mgdiff-1.0.orig/ 40755 1751 1751 0 6650540661 11361 5ustar ugsugsmgdiff-1.0.orig/externs.h100644 1751 1751 6107 5566544141 13325 0ustar ugsugs#ifndef EXTERNS_H #define EXTERNS_H /* * Copyright (c) 1994 Daniel Williams * * The X Consortium, and any party obtaining a copy of these files from * the X Consortium, directly or indirectly, is granted, free of charge, * a full and unrestricted irrevocable, world-wide, paid up, * royalty-free, nonexclusive right and license to deal in this software * and documentation files (the "Software"), including without limitation * the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons * who receive copies from any such party to do so. This license * includes without limitation a license to do the foregoing actions * under any patents of the party supplying this software to the X * Consortium. The following conditions apply: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL DANIEL WILLIAMS OR SYSTEMS & SCIENTIFIC SOFTWARE BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef lint static char rcsid_externs_h[] = "externs.h,v 2.0 1994/05/19 02:01:05 dan Exp"; #endif extern int main (int argc, char *argv[]); extern void process_both_files (char *file1, char *name1, char *file2, char *name2); extern void process_left_file (char *file1, char *name1); extern void process_right_file (char *file2, char *name2); extern void toggle_open_sensitive (Boolean sensitive); extern void toggle_openlr_sensitive (Boolean sensitive); extern void free_diff_info (DiffInfo *di); extern DiffInfo *blank_diff_info (void); extern DiffInfo *build_diff_info (char *prog, char *args, char *path1, char *path2); extern int max (int i, int j); extern int min (int i, int j); extern int copy_to_file (FILE *fin, char *name); extern void set_cursor (Widget w); extern void reset_cursor (Widget w); extern Widget get_top_shell (Widget w); extern int file_tests (Widget w, char *filename); extern void werror (Widget parent, char *title, char *msg1, char *msg2); extern void werror_long (Widget parent, char *title, char **lines, int numlines); extern void open_both_files (Widget parent, char *namel, char *namer); extern void open_left_file (Widget parent, char *name); extern void open_right_file (Widget parent, char *name); extern void save_file (Widget parent, Block *b, char *name); extern FILE *spawn_diff (char *prog, char *args, char *path1, char *path2); extern void show_manual_page (Widget parent); extern int modal_question (Widget parent, char *title, char *question); extern void add_editres (Widget shell); extern void turn_off_sash_traversal (Widget pane); extern void show_legend (Widget parent); extern void show_context (Widget parent); #endif mgdiff-1.0.orig/files.c100644 1751 1751 45230 5566544142 12753 0ustar ugsugs#ifndef lint static char rcsid[] = "files.c,v 2.0 1994/05/19 02:01:06 dan Exp"; #endif /* * Copyright (c) 1994 Daniel Williams * * The X Consortium, and any party obtaining a copy of these files from * the X Consortium, directly or indirectly, is granted, free of charge, * a full and unrestricted irrevocable, world-wide, paid up, * royalty-free, nonexclusive right and license to deal in this software * and documentation files (the "Software"), including without limitation * the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons * who receive copies from any such party to do so. This license * includes without limitation a license to do the foregoing actions * under any patents of the party supplying this software to the X * Consortium. The following conditions apply: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL DANIEL WILLIAMS OR SYSTEMS & SCIENTIFIC SOFTWARE BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mgdiff.h" #include "externs.h" static void popup_cb (Widget w, XtPointer closure, XtPointer call_data); static int is_ascii_text (char *filename); static void filel_both_cb (Widget w, XtPointer closure, XtPointer call_data); static void filer_both_cb (Widget w, XtPointer closure, XtPointer call_data); static void cancel_both_cb (Widget w, XtPointer closure, XtPointer call_data); static void do_before (Widget w); static void do_after (void); static void cancel_cb (Widget w, XtPointer closure, XtPointer call_data); static void file_left_cb (Widget w, XtPointer closure, XtPointer call_data); static void file_right_cb (Widget w, XtPointer closure, XtPointer call_data); static void cancel_save_cb (Widget w, XtPointer closure, XtPointer call_data); static void file_save_cb (Widget w, XtPointer closure, XtPointer call_data); static int really_save_file (char *filename, Block *bl); static int write_chunk (FILE *file, Chunk *chunk); static char *filel_name; static char *filer_name; static char *left_label = "Left Selection"; static char *right_label = "Right Selection"; extern Widget toplevel; /* ARGSUSED */ static void popup_cb (Widget w, XtPointer closure, XtPointer call_data) { reset_cursor ((Widget) closure); } /* * quick heuristic to test whether a file's contents are ascii text */ static int is_ascii_text (char *filename) { int fd, bytes, i; char buffer[1024]; fd = open (filename, O_RDONLY); bytes = read (fd, (void *) buffer, 1024); (void) close (fd); for (i = 0; i < bytes; i++) if (!isascii (buffer[i])) return (0); return (1); } /* * conduct some tests to determine if the input file is suitable for * processing by our program */ int file_tests (Widget w, char *filename) { struct stat buf; char *title = "Mgdiff Error"; if (access (filename, R_OK) != 0) { werror (w, title, filename, strerror (errno)); return (0); } if (stat (filename, &buf) != 0) { werror (w, title, filename, strerror (errno)); return (0); } if (!S_ISREG (buf.st_mode)) { werror (w, title, filename, "not an ordinary file"); return (0); } if (buf.st_size == 0) { werror (w, title, filename, "file is empty"); return (0); } if (!is_ascii_text (filename)) { werror (w, title, filename, "file is not a text file"); return (0); } return (1); } /* * popup a simple error dialog */ void werror (Widget parent, char *title, char *msg1, char *msg2) { Widget dialog; char buffer[4096]; XmString xms; Arg args[2]; (void) sprintf (buffer, "%s: %s", msg1, msg2); xms = XmStringCreateLtoR (buffer, XmSTRING_DEFAULT_CHARSET); XtSetArg (args[0], XmNmessageString, xms); XtSetArg (args[1], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); dialog = XmCreateErrorDialog (parent, "werror", args, 2); XmStringFree (xms); XtVaSetValues (XtParent (dialog), XtNtitle, title, NULL); XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON)); XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON)); XtManageChild (dialog); } /* * popup a longer error dialog */ void werror_long (Widget parent, char *title, char **lines, int numlines) { Widget dialog; Arg args[2]; XmString xms1, xms2, xms4, sep; int i; sep = XmStringSeparatorCreate (); xms1 = NULL; for (i = 0; i < numlines; i++) { xms4 = XmStringCreateSimple (lines[i]); if (xms1 == NULL) xms1 = xms4; else { xms2 = XmStringConcat (xms1, xms4); XmStringFree (xms4); XmStringFree (xms1); xms1 = xms2; } if (i < (numlines - 1)) { XmString xms3; xms3 = XmStringConcat (xms1, sep); XmStringFree (xms1); xms1 = xms3; } } XmStringFree (sep); XtSetArg (args[0], XmNmessageString, xms1); XtSetArg (args[1], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); dialog = XmCreateErrorDialog (parent, "werror", args, 2); XmStringFree (xms1); XtVaSetValues (XtParent (dialog), XtNtitle, title, NULL); XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON)); XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON)); XtManageChild (dialog); } /* ARGSUSED */ static void filel_both_cb (Widget w, XtPointer closure, XtPointer call_data) { XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *) call_data; char *filename; if (!XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &filename)) return; if (file_tests ((Widget) closure, filename)) { if (filel_name != NULL) XtFree (filel_name); filel_name = filename; if (filer_name != NULL) { do_before ((Widget) closure); XmUpdateDisplay (toplevel); process_both_files (filel_name, filel_name, filer_name, filer_name); do_after (); } } } /* ARGSUSED */ static void filer_both_cb (Widget w, XtPointer closure, XtPointer call_data) { XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *) call_data; char *filename; if (!XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &filename)) return; if (file_tests ((Widget) closure, filename)) { if (filer_name != NULL) XtFree (filer_name); filer_name = filename; if (filel_name != NULL) { do_before ((Widget) closure); XmUpdateDisplay (toplevel); process_both_files (filel_name, filel_name, filer_name, filer_name); do_after (); } } } /* ARGSUSED */ static void cancel_both_cb (Widget w, XtPointer closure, XtPointer call_data) { toggle_open_sensitive (True); toggle_openlr_sensitive (True); XFlush (XtDisplay (w)); XtPopdown ((Widget) closure); XtDestroyWidget ((Widget) closure); do_after (); } static void do_before (Widget w) { Display *display = XtDisplay (w); XtPopdown (w); XtDestroyWidget (w); toggle_open_sensitive (True); XFlush (display); } static void do_after (void) { if (filel_name != NULL) { XtFree (filel_name); filel_name = NULL; } if (filer_name != NULL) { XtFree (filer_name); filer_name = NULL; } } /* * dirname delivers all but the last level of the path name in string */ static char *dirname (char *path) { char *end, *val; if (!path) return (NULL); val = strdup (path); for (end = val; *end; end++) ; for (; end != val; end--) { if (*end == '/') { if (end == val) { free (val); return (strdup ("/")); } else { *end = '\0'; return (val); } } } free (val); return (NULL); } void open_both_files (Widget parent, char *namel, char *namer) { Widget shell; Widget fsb1, fsb2; Widget form2b; Widget frame1a, frame2a; Arg args[2]; int i; char *dir; XmString xms; shell = XtVaCreatePopupShell ("openfiles", xmDialogShellWidgetClass, parent, XmNallowShellResize, True, XmNdeleteResponse, XmDO_NOTHING, NULL); XtAddCallback (shell, XmNpopupCallback, popup_cb, parent); form2b = XtVaCreateWidget ("form2b", xmFormWidgetClass, shell, NULL); frame1a = XtVaCreateManagedWidget ("frame1a", xmFrameWidgetClass, form2b, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_WIDGET, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); frame2a = XtVaCreateManagedWidget ("frame2a", xmFrameWidgetClass, form2b, XmNleftAttachment, XmATTACH_POSITION, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNleftPosition, 50, NULL); i = 0; if ((dir = dirname (namel))) { xms = XmStringCreateSimple (dir); XtSetArg (args[i], XmNdirectory, xms); i++; } fsb1 = XmCreateFileSelectionBox (frame1a, "files1", args, i); if (dir) { XtFree (dir); XmStringFree (xms); } i = 0; if ((dir = dirname (namer))) { xms = XmStringCreateSimple (dir); XtSetArg (args[i], XmNdirectory, xms); i++; } fsb2 = XmCreateFileSelectionBox (frame2a, "files2", args, i); if (dir) { XtFree (dir); XmStringFree (xms); } XtAddCallback (fsb1, XmNokCallback, filel_both_cb, shell); XtAddCallback (fsb2, XmNokCallback, filer_both_cb, shell); XtAddCallback (fsb1, XmNcancelCallback, cancel_both_cb, shell); XtAddCallback (fsb2, XmNcancelCallback, cancel_both_cb, shell); XtVaSetValues (XmFileSelectionBoxGetChild (fsb1, XmDIALOG_HELP_BUTTON), XmNsensitive, False, NULL); XtVaSetValues (XmFileSelectionBoxGetChild (fsb2, XmDIALOG_HELP_BUTTON), XmNsensitive, False, NULL); XtVaSetValues (XmFileSelectionBoxGetChild (fsb1, XmDIALOG_SELECTION_LABEL), XtVaTypedArg, XmNlabelString, XmRString, left_label, strlen (left_label) + 1, NULL); XtVaSetValues (XmFileSelectionBoxGetChild (fsb2, XmDIALOG_SELECTION_LABEL), XtVaTypedArg, XmNlabelString, XmRString, right_label, strlen (right_label) + 1, NULL); XtVaSetValues (frame1a, XmNrightWidget, frame2a, NULL); XtManageChild (fsb1); XtManageChild (fsb2); XtManageChild (form2b); XmAddWMProtocolCallback (shell, XmInternAtom (XtDisplay (parent), "WM_DELETE_WINDOW", False), cancel_both_cb, (caddr_t) shell); XtVaSetValues (shell, XmNallowShellResize, False, NULL); XtPopup (shell, XtGrabNone); } /* ARGSUSED */ static void cancel_cb (Widget w, XtPointer closure, XtPointer call_data) { XtDestroyWidget ((Widget) closure); toggle_open_sensitive (True); } /* ARGSUSED */ static void file_left_cb (Widget w, XtPointer closure, XtPointer call_data) { XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *) call_data; char *filename; if (!XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &filename)) return; if (file_tests ((Widget) closure, filename)) { process_left_file (filename, filename); cancel_cb (NULL, closure, NULL); } XtFree (filename); } void open_left_file (Widget parent, char *name) { Widget dialog; Arg args[2]; int i; char *dir; XmString xms; i = 0; XtSetArg (args[i], XmNdeleteResponse, XmDO_NOTHING); i++; if ((dir = dirname (name))) { xms = XmStringCreateSimple (dir); XtSetArg (args[i], XmNdirectory, xms); i++; } dialog = XmCreateFileSelectionDialog (parent, "openfile", args, i); if (dir) { XtFree (dir); XmStringFree (xms); } XtAddCallback (XtParent (dialog), XmNpopupCallback, popup_cb, parent); XtAddCallback (dialog, XmNokCallback, file_left_cb, dialog); XtAddCallback (dialog, XmNcancelCallback, cancel_cb, dialog); XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON), XmNsensitive, False, NULL); XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL), XtVaTypedArg, XmNlabelString, XmRString, left_label, strlen (left_label) + 1, NULL); XmAddWMProtocolCallback (XtParent (dialog), XmInternAtom (XtDisplay (parent), "WM_DELETE_WINDOW", False), cancel_cb, (caddr_t) XtParent (dialog)); XtManageChild (dialog); } /* ARGSUSED */ static void file_right_cb (Widget w, XtPointer closure, XtPointer call_data) { XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *) call_data; char *filename; if (!XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &filename)) return; if (file_tests ((Widget) closure, filename)) { process_right_file (filename, filename); cancel_cb (NULL, closure, NULL); } XtFree (filename); } void open_right_file (Widget parent, char *name) { Widget dialog; Arg args[2]; int i; char *dir; XmString xms; i = 0; XtSetArg (args[i], XmNdeleteResponse, XmDO_NOTHING); i++; if ((dir = dirname (name))) { xms = XmStringCreateSimple (dir); XtSetArg (args[i], XmNdirectory, xms); i++; } dialog = XmCreateFileSelectionDialog (parent, "openfile", args, XtNumber (args)); if (dir) { XtFree (dir); XmStringFree (xms); } XtAddCallback (XtParent (dialog), XmNpopupCallback, popup_cb, parent); XtAddCallback (dialog, XmNokCallback, file_right_cb, dialog); XtAddCallback (dialog, XmNcancelCallback, cancel_cb, dialog); XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON), XmNsensitive, False, NULL); XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL), XtVaTypedArg, XmNlabelString, XmRString, right_label, strlen (right_label) + 1, NULL); XmAddWMProtocolCallback (XtParent (dialog), XmInternAtom (XtDisplay (parent), "WM_DELETE_WINDOW", False), cancel_cb, (caddr_t) XtParent (dialog)); XtManageChild (dialog); } /* ARGSUSED */ static void cancel_save_cb (Widget w, XtPointer closure, XtPointer call_data) { XtDestroyWidget (get_top_shell (w)); } /* * this callback does the work of saving the merged file differences * and is attached as the "OK" callback to the FileSelectionDialog */ static void file_save_cb (Widget w, XtPointer closure, XtPointer call_data) { XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *) call_data; char *title = "Mgdiff Save Error"; char *filename; int status; Widget shell = get_top_shell (w); if (!XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &filename)) return; if (access (filename, W_OK) == 0) { /* file exists and can be written */ char buffer[1024]; (void) sprintf (buffer, "Overwrite \"%s\"?", filename); if (modal_question (w, "Mgdiff Save Question", buffer)) { set_cursor (shell); if ((status = really_save_file (filename, (Block *) closure)) != 0) { reset_cursor (shell); werror (w, title, filename, strerror (status)); return; } reset_cursor (shell); } } else { /* file can't be written to */ if (errno == ENOENT) { /* because it doesn't exist */ set_cursor (shell); if ((status = really_save_file (filename, (Block *) closure)) != 0) { reset_cursor (shell); werror (w, title, filename, strerror (status)); return; } reset_cursor (shell); } else { /* for some other reason */ werror (w, title, filename, strerror (errno)); return; } } XtDestroyWidget (shell); } void save_file (Widget parent, Block *b, char *name) { Widget dialog; Arg args[3]; int i; char *dir; XmString xms; i = 0; XtSetArg (args[i], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); i++; XtSetArg (args[i], XmNdeleteResponse, XmDO_NOTHING); i++; if ((dir = dirname (name))) { xms = XmStringCreateSimple (dir); XtSetArg (args[i], XmNdirectory, xms); i++; } dialog = XmCreateFileSelectionDialog (parent, "savefile", args, i); if (dir) { XtFree (dir); XmStringFree (xms); } XtAddCallback (XtParent (dialog), XmNpopupCallback, popup_cb, parent); XtAddCallback (dialog, XmNokCallback, file_save_cb, (XtPointer) b); XtAddCallback (dialog, XmNcancelCallback, cancel_save_cb, NULL); XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON), XmNsensitive, False, NULL); XmAddWMProtocolCallback (XtParent (dialog), XmInternAtom (XtDisplay (parent), "WM_DELETE_WINDOW", False), cancel_save_cb, (caddr_t) NULL); XtManageChild (dialog); } /* * write the merged file differences out to a file and return 0 for * success and an errno for failure */ static int really_save_file (char *filename, Block *bl) { FILE *file; Block *b; int status; if ((file = fopen (filename, "w")) == NULL) return (errno); for (b = bl; b != NULL; b = b->next) { if ((b->arr[LEFT].type == SAME) && (b->arr[RIGHT].type == SAME)) { if ((status = write_chunk (file, &b->arr[LEFT])) != 0) return (status); } else if ((b->arr[LEFT].type == DIFF) && (b->arr[RIGHT].type == DIFF)) { assert (b->selected != NEITHER); if ((status = write_chunk (file, &b->arr[b->selected])) != 0) return (status); } else if ((b->arr[LEFT].type == INSERT) && (b->arr[RIGHT].type == BLANK)) { assert (b->selected != NEITHER); if (b->selected == LEFT) if ((status = write_chunk (file, &b->arr[LEFT])) != 0) return (status); } else if ((b->arr[LEFT].type == BLANK) && (b->arr[RIGHT].type == INSERT)) { assert (b->selected != NEITHER); if (b->selected == RIGHT) if ((status = write_chunk (file, &b->arr[RIGHT])) != 0) return (status); } else assert (False); } if (fclose (file) != 0) return (errno); return (0); } /* * write out a chunk of text to a file and return 0 if successful or * the errno if unsuccessful */ static int write_chunk (FILE *file, Chunk *chunk) { int i; for (i = 0; i < chunk->fsize; i++) { if ((chunk->wtext != NULL) && (chunk->wtext[i] != NULL)) { if (fputs (chunk->wtext[i], file) == EOF) return (errno); if (fputs ("\n", file) == EOF) return (errno); } else { if (fputs (chunk->text[i], file) == EOF) return (errno); if (fputs ("\n", file) == EOF) return (errno); } } return (0); } mgdiff-1.0.orig/Imakefile100644 1751 1751 660 5566544134 13255 0ustar ugsugs#ifndef XCOMM #define XCOMM # #endif XCOMM Imakefile,v 2.0 1994/05/19 02:01:00 dan Exp XMLIB = -lXm XCOMM XCOMM for Dell SVR4 XCOMM EXTRA_LIBRARIES = -lc -lucb SRCS = mgdiff.c rundiff.c misc.c files.c spawn.c manual.c modal.c legend.c OBJS = mgdiff.o rundiff.o misc.o files.o spawn.o manual.o modal.o legend.o LOCAL_LIBRARIES = $(XMLIB) $(XTOOLLIB) $(XMULIBONLY) $(XLIB) ComplexProgramTarget(mgdiff) InstallAppDefaults(Mgdiff) mgdiff-1.0.orig/legend.c100644 1751 1751 12143 5566544144 13106 0ustar ugsugs#ifndef lint static char rcsid[] = "legend.c,v 2.0 1994/05/19 02:01:08 dan Exp"; #endif /* * Copyright (c) 1994 Daniel Williams * * The X Consortium, and any party obtaining a copy of these files from * the X Consortium, directly or indirectly, is granted, free of charge, * a full and unrestricted irrevocable, world-wide, paid up, * royalty-free, nonexclusive right and license to deal in this software * and documentation files (the "Software"), including without limitation * the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons * who receive copies from any such party to do so. This license * includes without limitation a license to do the foregoing actions * under any patents of the party supplying this software to the X * Consortium. The following conditions apply: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL DANIEL WILLIAMS OR SYSTEMS & SCIENTIFIC SOFTWARE BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include "mgdiff.h" #include "externs.h" /* ARGSUSED */ static void popdown_shell (Widget w, XtPointer closure, XtPointer call_data) { XtPopdown ((Widget) closure); } /* ARGSUSED */ static void popup_cb (Widget w, XtPointer closure, XtPointer call_data) { reset_cursor ((Widget) closure); } /* ARGSUSED */ static void destroy_cb (Widget w, XtPointer closure, XtPointer call_data) { *((Widget *) closure) = NULL; } /* * display a dialog that shows how different text blocks are * color-coded */ void show_legend (Widget parent) { static Widget shell; if (shell == NULL) { Widget form2a, pane, widget, rc, formd; XGCValues gc_values; extern GC gcfore[5]; set_cursor (parent); formd = XmCreateFormDialog (parent, "legend", NULL, 0); shell = XtParent (formd); XtVaSetValues (shell, XmNdeleteResponse, XmDESTROY, NULL); add_editres (shell); XtAddCallback (shell, XmNpopupCallback, popup_cb, parent); XtAddCallback (shell, XmNdestroyCallback, destroy_cb, &shell); pane = XtVaCreateWidget ("pane", xmPanedWindowWidgetClass, formd, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNsashWidth, 1, XmNsashHeight, 1, NULL); rc = XtVaCreateManagedWidget ("rc", xmRowColumnWidgetClass, pane, NULL); XGetGCValues (XtDisplay (parent), gcfore[0], GCForeground|GCBackground, &gc_values); (void) XtVaCreateManagedWidget ("label1", xmLabelWidgetClass, rc, XmNforeground, gc_values.foreground, XmNbackground, gc_values.background, NULL); XGetGCValues (XtDisplay (parent), gcfore[1], GCForeground|GCBackground, &gc_values); (void) XtVaCreateManagedWidget ("label2", xmLabelWidgetClass, rc, XmNforeground, gc_values.foreground, XmNbackground, gc_values.background, NULL); XGetGCValues (XtDisplay (parent), gcfore[2], GCForeground|GCBackground, &gc_values); (void) XtVaCreateManagedWidget ("label3", xmLabelWidgetClass, rc, XmNforeground, gc_values.foreground, XmNbackground, gc_values.background, NULL); XGetGCValues (XtDisplay (parent), gcfore[3], GCForeground|GCBackground, &gc_values); (void) XtVaCreateManagedWidget ("label4", xmLabelWidgetClass, rc, XmNforeground, gc_values.foreground, XmNbackground, gc_values.background, NULL); XGetGCValues (XtDisplay (parent), gcfore[4], GCForeground|GCBackground, &gc_values); (void) XtVaCreateManagedWidget ("label5", xmLabelWidgetClass, rc, XmNforeground, gc_values.foreground, XmNbackground, gc_values.background, NULL); form2a = XtVaCreateManagedWidget("form2a", xmFormWidgetClass, pane, XmNfractionBase, 5, NULL); turn_off_sash_traversal (pane); widget = XtVaCreateManagedWidget ("OK", xmPushButtonWidgetClass, form2a, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNshowAsDefault, True, XmNdefaultButtonShadowThickness, 1, NULL); XtAddCallback(widget, XmNactivateCallback, popdown_shell, shell); { Dimension w, h; XtVaGetValues (widget, XmNwidth, &w, XmNheight, &h, NULL); XtVaSetValues (form2a, XmNpaneMaximum, h, XmNpaneMinimum, h, NULL); } XtManageChild (pane); XtManageChild (formd); } XtPopup (shell, XtGrabNone); } mgdiff-1.0.orig/Makefile.ini100644 1751 1751 2515 5610125600 13662 0ustar ugsugs# # Makefile.ini,v 2.1 1994/07/11 02:16:32 dan Exp # # # flags for Dell SVR4 # INCS = -I/usr/X5/include LIBS = -L/usr/X5/lib -lXm -lXt -lXmu -lXext -lX11 -lsocket -lnsl -lc -lucb DEFS = -DDELL -DSVR4 -DSYSV386 -Di386 -DSVR4_0 -DFUNCPROTO -DEDITRES # # flags for SGI Irix 5.2 # #LIBS = -lXm -lXt -lX11 #DEFS = -xansi -D__STDC__=1 -DXML -DSYSV -DSVR4 -DFUNCPROTO=7 -DNARROWPROTO OPTS = -g CFLAGS = $(OPTS) $(DEFS) $(INCS) SRCS = mgdiff.c rundiff.c misc.c files.c spawn.c manual.c modal.c legend.c OBJS = mgdiff.o rundiff.o misc.o files.o spawn.o manual.o modal.o legend.o HDRS = externs.h mgdiff.h MISC = Makefile Imakefile mgdiff.xbm Mgdiff.ad FILES = $(SRCS) $(HDRS) $(MISC) # # this for using GNU compiler # GCC = gcc -fno-builtin #CC = $(GCC) mgdiff : $(OBJS) $(CC) $(CFLAGS) $(OBJS) -o $@ $(LIBS) TAGS : $(SRCS) $(HDRS) etags -t $(SRCS) $(HDRS) clean : rm -f $(OBJS) clobber : rm -f mgdiff $(OBJS) # # check all source files with lint # lint : lint -shux $(DEFS) $(INCS) $(SRCS) depend : $(SRCS) $(GCC) $(CFLAGS) -MM $(SRCS) mgdiff.o : mgdiff.c mgdiff.h externs.h patchlevel.h mgdiff.xbm rundiff.o : rundiff.c mgdiff.h externs.h misc.o : misc.c mgdiff.h files.o : files.c mgdiff.h externs.h spawn.o : spawn.c manual.o : manual.c mgdiff.h externs.h modal.o : modal.c mgdiff.h externs.h legend.o : legend.c mgdiff.h externs.h mgdiff-1.0.orig/manual.c100644 1751 1751 16316 5566544145 13134 0ustar ugsugs#ifndef lint static char rcsid[] = "manual.c,v 2.0 1994/05/19 02:01:09 dan Exp"; #endif /* * Copyright (c) 1994 Daniel Williams * * The X Consortium, and any party obtaining a copy of these files from * the X Consortium, directly or indirectly, is granted, free of charge, * a full and unrestricted irrevocable, world-wide, paid up, * royalty-free, nonexclusive right and license to deal in this software * and documentation files (the "Software"), including without limitation * the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons * who receive copies from any such party to do so. This license * includes without limitation a license to do the foregoing actions * under any patents of the party supplying this software to the X * Consortium. The following conditions apply: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL DANIEL WILLIAMS OR SYSTEMS & SCIENTIFIC SOFTWARE BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include "mgdiff.h" #include "externs.h" static char *get_manual_text (char *command); static void popdown_shell (Widget w, XtPointer closure, XtPointer call_data); static void popup_cb (Widget w, XtPointer closure, XtPointer call_data); /* * run the as a shell command and return the output in * dynamically allocated space. returns NULL if something really bad * goes wrong with the popen. */ static char *get_manual_text (char *command) { FILE *f; char *retval; int size, bytes; char buffer[BUFSIZ]; if ((f = popen (command, "r")) == NULL) return (NULL); for (size = 0, retval = NULL; !feof (f); ) { if ((bytes = fread ((void *) buffer, 1, BUFSIZ, f)) != 0) { if (size) retval = (char *) realloc ((void *) retval, size + bytes + 1); else retval = (char *) malloc (bytes + 1); (void) memcpy ((void *) &retval[size], (void *) buffer, bytes); retval[size + bytes] = '\0'; size += bytes; } } /* * this return value (the exit status of the command) is not that * useful because it's the status of the last command in what is * usually a pipeline. previous commands in the pipeline can fail * and we would never know it from this value. */ (void) pclose (f); return (retval); } /* ARGSUSED */ static void popdown_shell (Widget w, XtPointer closure, XtPointer call_data) { XtPopdown ((Widget) closure); } /* ARGSUSED */ static void popup_cb (Widget w, XtPointer closure, XtPointer call_data) { reset_cursor ((Widget) closure); } /* * create and display a shell containing a ScrolledText widget * with the manual page for the application */ void show_manual_page (Widget parent) { static Widget shell; if (shell == NULL) { int i; Widget form2a, pane, text_w, widget, formd; Arg args[10]; char *value; int iserror = 0; XmString xms; char *cmd; static XtResource resources[] = { {"manCommand", "ManCommand", XtRString, sizeof (String), 0, XtRString, #if defined(SYSV) || defined(SVR4) "(man mgdiff | col -bx) 2>&1" #else "(man mgdiff | col -b) 2>&1" #endif }}; set_cursor (parent); XtGetApplicationResources (parent, &cmd, resources, XtNumber (resources), NULL, 0); value = get_manual_text (cmd); if (value == NULL) { /* system calls in popen failed */ char buffer[1024]; (void) sprintf (buffer, "System routine \"popen\" failed executing\nthis command (resource \"manCommand\"):\n\n\"%s\"", cmd); xms = XmStringCreateLtoR (buffer, XmSTRING_DEFAULT_CHARSET); iserror = 1; } else if (value[0] == '\0') { /* command produced no output */ char buffer[1024]; (void) sprintf (buffer, "Shell command (resource \"manCommand\"):\n\n\"%s\"\n\nproduced no output", cmd); xms = XmStringCreateLtoR (buffer, XmSTRING_DEFAULT_CHARSET); iserror = 1; } else if (strlen (value) < (unsigned int) 80) { /* command produced insufficient output */ char buffer[1024]; char *tmp; if ((tmp = strrchr (value, '\n')) != NULL) *tmp = '\0'; (void) sprintf (buffer, "Shell command (resource \"manCommand\"):\n\n \"%s\"\n\nproduced this output: \n\n \"%s\"", cmd, value); xms = XmStringCreateLtoR (buffer, XmSTRING_DEFAULT_CHARSET); iserror = 1; } if (iserror) { Widget dialog; XtSetArg (args[0], XmNmessageString, xms); dialog = XmCreateErrorDialog (parent, "manualerr", args, 1); XmStringFree (xms); XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON)); XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON)); XtManageChild (dialog); reset_cursor (parent); return; } formd = XmCreateFormDialog (parent, "manualpage", NULL, 0); shell = XtParent (formd); XtVaSetValues (shell, XmNdeleteResponse, XmUNMAP, NULL); add_editres (shell); XtAddCallback (shell, XmNpopupCallback, popup_cb, parent); pane = XtVaCreateManagedWidget ("pane", xmPanedWindowWidgetClass, formd, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNsashWidth, 1, XmNsashHeight, 1, NULL); i = 0; XtSetArg (args[i], XmNscrollVertical, True); i++; XtSetArg (args[i], XmNscrollHorizontal, False); i++; XtSetArg (args[i], XmNeditMode, XmMULTI_LINE_EDIT); i++; XtSetArg (args[i], XmNeditable, False); i++; XtSetArg (args[i], XmNcursorPositionVisible, False); i++; XtSetArg (args[i], XmNwordWrap, False); i++; XtSetArg (args[i], XmNvalue, value); i++; XtSetArg (args[i], XmNtraversalOn, False); i++; text_w = XmCreateScrolledText (pane, "help_text", args, i); if (value) free (value); XtManageChild (text_w); form2a = XtVaCreateManagedWidget ("form2a", xmFormWidgetClass, pane, XmNfractionBase, 7, NULL); turn_off_sash_traversal (pane); widget = XtVaCreateManagedWidget ("OK", xmPushButtonWidgetClass, form2a, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNshowAsDefault, True, XmNdefaultButtonShadowThickness, 1, NULL); XtAddCallback (widget, XmNactivateCallback, popdown_shell, shell); { Dimension w, h; XtVaGetValues (widget, XmNwidth, &w, XmNheight, &h, NULL); XtVaSetValues (form2a, XmNpaneMaximum, h, XmNpaneMinimum, h, NULL); } XtManageChild (formd); } XtPopup (shell, XtGrabNone); } mgdiff-1.0.orig/Mgdiff.ad100644 1751 1751 17774 5566544137 13227 0ustar ugsugs! ! Mgdiff.ad,v 2.0 1994/05/19 02:01:03 dan Exp ! ! ! widget hierarchy: ! !Mgdiff mgdiff ! XmMainWindow mainw ! XmSeparatorGadget MainWinSep1 ! XmSeparatorGadget MainWinSep2 ! XmSeparatorGadget MainWinSep3 ! XmRowColumn menubar ! XmCascadeButtonGadget button_0 ! XmCascadeButtonGadget button_1 ! XmCascadeButtonGadget button_2 ! XmCascadeButtonGadget button_3 ! XmCascadeButtonGadget button_4 ! XmMenuShell popup_file_menu ! XmRowColumn select_menu ! XmPushButtonGadget button_0 ! XmPushButtonGadget button_1 ! XmSeparatorGadget separator_0 ! XmPushButtonGadget button_2 ! XmRowColumn file_menu ! XmPushButtonGadget button_0 ! XmPushButtonGadget button_1 ! XmPushButtonGadget button_2 ! XmPushButtonGadget button_3 ! XmSeparatorGadget separator_0 ! XmPushButtonGadget button_4 ! XmRowColumn options_menu ! XmToggleButtonGadget button_0 ! XmToggleButtonGadget button_1 ! XmToggleButtonGadget button_2 ! XmRowColumn help_menu ! XmPushButtonGadget button_0 ! XmPushButtonGadget button_1 ! XmPushButtonGadget button_2 ! XmRowColumn view_menu ! XmPushButtonGadget button_0 ! XmPushButtonGadget button_1 ! XmPushButtonGadget button_2 ! XmForm form1 ! XmFrame frame1 ! XmForm form3 ! XmScrollBar sbl ! XmDrawingArea dam ! XmScrollBar sbr ! XmFrame frame2 ! XmForm form4 ! XmForm form2 ! XmScrollBar sb ! XmForm form21 ! XmFrame frame3 ! XmLabel fnamel ! XmFrame frame31 ! XmTextField linenuml ! XmForm form22 ! XmFrame frame4 ! XmLabel fnamer ! XmFrame frame41 ! XmTextField linenumr ! XmDrawingArea textl ! XmDrawingArea textr ! XmScrollBar sbh ! XmDialogShell version_popup ! XmMessageBox version ! XmLabelGadget symbol ! XmLabelGadget ! XmSeparatorGadget separator ! XmPushButtonGadget OK ! XmPushButtonGadget Cancel ! XmPushButtonGadget Help ! XmDialogShell manualpage_popup ! XmForm manualpage ! XmPanedWindow pane ! XmScrolledWindow help_textSW ! XmScrollBar vbar ! XmText help_text ! XmForm form2a ! XmPushButton OK ! XmSash sash ! XmSeparatorGadget separator ! XmSash sash ! XmSeparatorGadget separator ! XmDialogShell legend_popup ! XmForm legend ! XmPanedWindow pane ! XmRowColumn rc ! XmLabel label1 ! XmLabel label2 ! XmLabel label3 ! XmLabel label4 ! XmLabel label5 ! XmForm form2a ! XmPushButton OK ! XmSash sash ! XmSeparatorGadget separator ! XmSash sash ! XmSeparatorGadget separator ! XmDialogShell werror_popup ! XmMessageBox werror ! XmLabelGadget symbol ! XmLabelGadget ! XmSeparatorGadget separator ! XmPushButtonGadget OK ! XmPushButtonGadget Cancel ! XmPushButtonGadget Help ! ! ! this should only be defined in the site-wide file ! ?.AppDefaultsVersion: 1 ?.Geometry: 800x600 ! ! Use these values on color displays ! *DiffForeground: black *DiffBackground: yellow *SameForeground: black *SameBackground: grey *InsertForeground: black *InsertBackground: orange *BlankForeground: black *BlankBackground: grey66 *SelectForeground: black *SelectBackground: light slate blue ! ! Use these values on gray-scale displays ! !*DiffForeground: black !*DiffBackground: white !*SameForeground: black !*SameBackground: grey !*InsertForeground: black !*InsertBackground: #888 !*BlankForeground: black !*BlankBackground: grey66 !*SelectForeground: white !*SelectBackground: #444 *Font: 7x13bold *DragScroll: true *Overview: true *QuitIfSame: false *Filename: (stdin) *HorzScrollbar: true *LinesOfContext: 3 *ManCommand: (man mgdiff | col -bx) 2>&1 ! ! GNU diff can be much faster, especially for large files ! *DiffCommand: diff *DiffArgs: *Background: cadet blue *FontList: variable *text.Foreground: black *text.Background: grey ! ! the overview area ! *sbl.width: 16 *sbr.width: 16 *dam.width: 16 *dam.Foreground: black *dam.Background: cyan *version_popup.Title: Version Information *openfiles.Title: Open Files *openfile_popup.Title: Open File *savefile_popup.Title: Save File *legend_popup.Title: Mgdiff Legend *manualerr_popup.Title: Mgdiff Error *manualpage*XmText*FontList: 7x13bold *manualpage*XmText*Rows: 40 *manualpage*XmText*Columns: 80 *manualpage_popup.Title: Mgdiff Manual Page *legend*XmLabel*FontList: 7x13bold *label1.XmString: this color indicates blocks which differ between files *label2.XmString: this color indicates blocks which are identical between files *label3.XmString: this color indicates blocks which have been inserted in one file *label4.XmString: this color indicates blocks which are for display purposes *label5.XmString: this color indicates blocks which have been selected by the user ! ! *file_menu*button_0.XmString: Open... *file_menu*button_0.Mnemonic: O *file_menu*button_0.Accelerator: Ctrlo *file_menu*button_0.AcceleratorText: Ctrl+O *file_menu*button_1.XmString: Open Left... *file_menu*button_1.Mnemonic: L *file_menu*button_1.Accelerator: Ctrll *file_menu*button_1.AcceleratorText: Ctrl+L *file_menu*button_2.XmString: Open Right... *file_menu*button_2.Mnemonic: R *file_menu*button_2.Accelerator: Ctrlr *file_menu*button_2.AcceleratorText: Ctrl+R *file_menu*button_3.XmString: Save As... *file_menu*button_3.Mnemonic: S *file_menu*button_3.Accelerator: Ctrls *file_menu*button_3.AcceleratorText: Ctrl+S *file_menu*button_4.XmString: Exit *file_menu*button_4.Mnemonic: E *file_menu*button_4.Accelerator: Ctrlc *file_menu*button_4.AcceleratorText: Ctrl+C ! ! *view_menu*button_0.XmString: Previous *view_menu*button_0.Mnemonic: P *view_menu*button_0.Accelerator: Ctrlp *view_menu*button_0.AcceleratorText: Ctrl+P *view_menu*button_1.XmString: Next *view_menu*button_1.Mnemonic: N *view_menu*button_1.Accelerator: Ctrln *view_menu*button_1.AcceleratorText: Ctrl+N *view_menu*button_2.XmString: Next Unselected *view_menu*button_2.Mnemonic: U *view_menu*button_2.Accelerator: Ctrlu *view_menu*button_2.AcceleratorText: Ctrl+U ! ! *select_menu*button_0.XmString: Left All *select_menu*button_0.Mnemonic: L !*select_menu*button_0.Accelerator: !*select_menu*button_0.AcceleratorText: *select_menu*button_1.XmString: Right All *select_menu*button_1.Mnemonic: R !*select_menu*button_1.Accelerator: !*select_menu*button_1.AcceleratorText: *select_menu*button_2.XmString: Unselect All *select_menu*button_2.Mnemonic: U !*select_menu*button_2.Accelerator: !*select_menu*button_2.AcceleratorText: ! ! *options_menu*button_0.XmString: Overview *options_menu*button_0.Mnemonic: O *options_menu*button_0.Accelerator: Ctrlw *options_menu*button_0.AcceleratorText: Ctrl+W *options_menu*button_1.XmString: Horizontal Scrollbar *options_menu*button_1.Mnemonic: H *options_menu*button_1.Accelerator: Ctrlh *options_menu*button_1.AcceleratorText: Ctrl+H *options_menu*button_2.XmString: Drag Scroll *options_menu*button_2.Mnemonic: D *options_menu*button_2.Accelerator: Ctrld *options_menu*button_2.AcceleratorText: Ctrl+D ! ! *help_menu*button_0.XmString: Version... *help_menu*button_0.Mnemonic: V *help_menu*button_0.Accelerator: Ctrlv *help_menu*button_0.AcceleratorText: Ctrl+V *help_menu*button_1.XmString: Manual Page... *help_menu*button_1.Mnemonic: M *help_menu*button_1.Accelerator: Ctrlm *help_menu*button_1.AcceleratorText: Ctrl+M *help_menu*button_2.XmString: Color Legend... *help_menu*button_2.Mnemonic: G *help_menu*button_2.Accelerator: Ctrlg *help_menu*button_2.AcceleratorText: Ctrl+G ! ! *menubar.button_0.XmString: File *menubar.button_0.Mnemonic: F *menubar.button_1.XmString: View *menubar.button_1.Mnemonic: V *menubar.button_2.XmString: Select *menubar.button_2.Mnemonic: S *menubar.button_3.XmString: Options *menubar.button_3.Mnemonic: O *menubar.button_4.XmString: Help *menubar.button_5.Mnemonic: H *XmDialogShell*OK.XmString: OK mgdiff-1.0.orig/mgdiff.c100644 1751 1751 215035 5642417345 13126 0ustar ugsugs#ifndef lint static char rcsid[] = "mgdiff.c,v 2.1 1994/09/29 01:56:53 dan Exp"; #endif #ifndef lint static char copyright[] = "Copyright (c) 1994, Daniel Williams"; #endif /* * Copyright (c) 1994 Daniel Williams * * The X Consortium, and any party obtaining a copy of these files from * the X Consortium, directly or indirectly, is granted, free of charge, * a full and unrestricted irrevocable, world-wide, paid up, * royalty-free, nonexclusive right and license to deal in this software * and documentation files (the "Software"), including without limitation * the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons * who receive copies from any such party to do so. This license * includes without limitation a license to do the foregoing actions * under any patents of the party supplying this software to the X * Consortium. The following conditions apply: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL DANIEL WILLIAMS OR SYSTEMS & SCIENTIFIC SOFTWARE BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mgdiff.h" #include "externs.h" #include "patchlevel.h" #include "mgdiff.xbm" static void Visible (Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch); static Region RegionFromRect (int x, int y, int w, int h); static void resize_cb (Widget w, XtPointer closure, XtPointer call_data); static void drawit (Widget w, XtPointer closure, XtPointer call_data); static void file_cb (Widget w, XtPointer closure, XtPointer call_data); static void view_cb (Widget w, XtPointer closure, XtPointer call_data); static void select_cb (Widget w, XtPointer closure, XtPointer call_data); static void options_cb (Widget w, XtPointer closure, XtPointer call_data); static void helpmenu_cb (Widget w, XtPointer closure, XtPointer call_data); static void resize_em (WidgetList children); static void set_pixmaps (WidgetList children); static void create_gcs (void); static void configure_rowcol (Widget widget, XEvent *event, String *params, Cardinal *num_params); static void update_pixmaps (void); static void do_nothing (Widget widget, XEvent *event, String *params, Cardinal *num_params); static void add_actions (XtAppContext app); static int x_error_handler (Display *dpy, XErrorEvent *event); static void xt_error_handler (String message); static void xt_warning_handler (String message); static void redraw_partial_vert (Widget w); static void redraw_partial_horz (Widget w); static void sbh_moved (Widget w, XtPointer closure, XtPointer call_data); static void fake_adjust_label (Widget w); static void update_line_numbers (int l, int r); static void sb_moved (Widget w, XtPointer closure, XtPointer call_data); static void redraw_full (Widget w); static void redraw_partial (Widget w, Dimension ypos, Dimension height); static void update_screenstate (int reason, int topline); static void redraw_both_vert (void); static void redraw_both_horz (void); static void next_diff (Widget w, XtPointer closure, XtPointer call_data); static void next_diff_unselected (void); static void prev_diff (Widget w, XtPointer closure, XtPointer call_data); static void drag_diff (Widget w, XtPointer closure, XtPointer call_data); static void show_version (Widget parent); static void update_overall (void); static void refresh (void); static void toggle_saveas_sensitive (Boolean sensitive); static void exit_cb (Widget w, XtPointer closure, XtPointer call_data); static void Select (Widget widget, XEvent *event, String *params, Cardinal *num_params); static void Scroll (Widget widget, XEvent *event, String *params, Cardinal *num_params); static int ilog10 (int lines); static void handle_diff_errors (DiffInfo *d); static void select_all (Side side); static void unselect_all (void); static Boolean all_selected (void); static Dimension get_preferred_width (Widget w); static char *basename (char *name); #define APP_DEFAULTS_VERSION 1 /* * treat failure to find the resources from the application defaults * file as a unrecoverable error; specify just enough fallback * resources to allow the user to exit the program. */ static String fallbacks[] = { "*menubar.button_0.XmString: File", "*file_menu*button_4.XmString: Exit", NULL }; static XrmOptionDescRec option_table[] = { {"-quit", "quitIfSame", XrmoptionNoArg, "true"}, {"-args", "diffArgs", XrmoptionSepArg, NULL}, {"-file", "filename", XrmoptionSepArg, NULL}, {"-debug", "debug", XrmoptionNoArg, "true"} }; static int lines_of_context; static Pixmap bitmap; static struct screenstate { Block *b; int topline; int leftcol; int sindex, findex[2]; } oldss, newss; static DiffInfo *di; static char *diffcmd; static char *diffargs; static int font_height = 10; static int font_width; static int font_descent; static int font_mono; static int font_widestline; static GC gc; GC gcfore[5]; static GC gcback[5]; static XtAppContext app; Widget toplevel; static Widget file_menu; static Widget textl, textr, sb; static Widget form1, form2, frame1, frame2, form3, form4; static Widget fnamel, fnamer; static Widget frame3, frame4; static Widget sbl, dam, sbr, sbh; static Widget form21, frame31, linenuml; static Widget form22, frame41, linenumr; static char *str_fnamel, *str_fnamer; static char *str_snamel, *str_snamer; static char *tempfname; static char *user_filename; char *progname; static int linenum_columns; static XtTranslations text_trans; static Boolean overview_flag; static Boolean horz_scrollbar; static Boolean drag_scroll; static int app_defaults_version; static Boolean no_files_flag; static Boolean quit_flag; static Boolean debug_flag; /* * these track the visibility status of the two DrawingArea widgets * into which the text is drawn. If it's fully obscured, I don't * bother doing any drawing. If it's unobscured, I use a fast * method of redrawing. If it's partially obscured, I use a slow (but * sure) method of redrawing. This turns out to be faster (on my server, * anyway) and less complex than turning on and correctly processing * GraphicsExpose events. */ static int statel = VisibilityFullyObscured; static int stater = VisibilityFullyObscured; /* ARGSUSED1 */ static void Visible (Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch) { XVisibilityEvent *e = (XVisibilityEvent *) event; if (widget == textl) statel = e->state; else if (widget == textr) stater = e->state; else /* CONSTCOND */ assert (False); } /* * if the labels that display the filenames are large enough, center * the filename; if not, show the end of it (likely to be the most * interesting part) */ /* ARGSUSED1 */ static void adjust_label (Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch) { if (event->type == Expose) { XtRemoveEventHandler (widget, ExposureMask, False, adjust_label, NULL); fake_adjust_label (widget); } else if (event->type == ConfigureNotify) { Dimension margin_width, string_width; unsigned char alignment; XmString label_string; XmFontList font_list; XtVaGetValues (widget, XmNmarginWidth, &margin_width, XmNalignment, &alignment, XmNlabelString, &label_string, XmNfontList, &font_list, NULL); string_width = XmStringWidth (font_list, label_string); XmStringFree (label_string); if ((int) (string_width + 2 * margin_width) > event->xconfigure.width) { if (alignment != XmALIGNMENT_END) XtVaSetValues (widget, XmNalignment, XmALIGNMENT_END, NULL); } else if (alignment != XmALIGNMENT_CENTER) XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL); } } /* * fake up a call to the above event handler to adjust the filename labels */ static void fake_adjust_label (Widget w) { Dimension width; XConfigureEvent e; e.type = ConfigureNotify; XtVaGetValues (w, XmNwidth, &width, NULL); e.width = width; adjust_label (w, NULL, (XEvent *) &e, NULL); } /* * given the position and size of a rectangle create a * Region structure */ static Region RegionFromRect (int x, int y, int w, int h) { XPoint points[4]; points[0].x = (short) x; points[0].y = (short) y; points[1].x = (short) x; points[1].y = (short) y + h; points[2].x = (short) x + w; points[2].y = (short) y + h; points[3].x = (short) x + w; points[3].y = (short) y; return (XPolygonRegion (points, 4, EvenOddRule)); } /* * handle the resizeCallbacks from the drawing areas that are used * to render the text panels by adjusting the scrollbars */ /* ARGSUSED1 */ static void resize_cb (Widget w, XtPointer closure, XtPointer call_data) { Dimension width, height; int lines, columns, value; XmScrollBarCallbackStruct cbs; static int been_here; /* * if graphics contexts not created yet, create them */ if (!been_here) { XGCValues gc_values; XFontStruct *xfs; static XtResource resources[] = { {XtNfont, XtCFont, XtRFont, sizeof (Font), XtOffset (XGCValues *, font), XtRString, "7x13bold"}}; XtGetApplicationResources (toplevel, &gc_values, resources, XtNumber (resources), NULL, 0); xfs = XQueryFont (XtDisplay (w), gc_values.font); font_descent = xfs->descent; font_height = xfs->ascent + xfs->descent; font_width = xfs->max_bounds.width; font_mono = ((xfs->per_char == NULL) || (xfs->min_bounds.width == xfs->max_bounds.width)); font_widestline = XTextWidth (xfs, di->longline, strlen (di->longline)); XFreeFontInfo (NULL, xfs, 1); XtVaGetValues (w, XmNbackground, &gc_values.background, NULL); gc_values.graphics_exposures = False; gc_values.foreground = None; gc = XtGetGC (w, GCForeground|GCBackground|GCGraphicsExposures, &gc_values); been_here = 1; } XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL); lines = (int) height / font_height; if (font_mono) { int maximum, minimum; XtVaGetValues (sbh, XmNmaximum, &maximum, XmNminimum, &minimum, NULL); columns = min ((int) width / font_width, maximum - minimum); XtVaSetValues (sbh, XmNsliderSize, columns, XmNpageIncrement, columns, NULL); } else { XtVaSetValues (sbh, XmNmaximum, font_widestline, XmNincrement, font_width, XmNsliderSize, width, XmNpageIncrement, width, NULL); } if (di->lines <= lines) { XtVaSetValues (sb, XmNmaximum, di->lines, XmNvalue, 0, XmNsliderSize, di->lines, XmNpageIncrement, di->lines, NULL); newss.topline = 0; } else { int maximum; XtVaGetValues (sb, XmNmaximum, &maximum, XmNvalue, &value, NULL); if ((maximum - lines) < value) { XtVaSetValues (sb, XmNvalue, (maximum - lines), XmNsliderSize, lines, XmNpageIncrement, lines, NULL); } else { XtVaSetValues (sb, XmNsliderSize, lines, XmNpageIncrement, lines, NULL); } } XtVaGetValues (sb, XmNvalue, &value, NULL); cbs.reason = XmCR_DRAG; cbs.value = value; sb_moved (sb, NULL, (XtPointer) &cbs); } /* * this is the main drawing function, called as the exposeCallback of * each of the text drawing areas. */ /* ARGSUSED1 */ static void drawit (Widget w, XtPointer closure, XtPointer call_data) { XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct *) call_data; Dimension ypos; int stemp, itemp, rect_height; Dimension width, height; Region region; Block *b; GC fore, back; int columns; XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL); XtAddExposureToRegion (cbs->event, region = XCreateRegion ()); columns = (int) width / font_width + 1; itemp = newss.sindex; ypos = 0; for (b = newss.b; b != NULL; b = b->next) { int j; Chunk *ths, *oth; if (w == textl) { ths = &b->arr[LEFT]; oth = &b->arr[RIGHT]; if (b->selected == LEFT) { fore = gcfore[4]; back = gcback[4]; } else { fore = gcfore[ths->type]; back = gcback[ths->type]; } } else if (w == textr) { ths = &b->arr[RIGHT]; oth = &b->arr[LEFT]; if (b->selected == RIGHT) { fore = gcfore[4]; back = gcback[4]; } else { fore = gcfore[ths->type]; back = gcback[ths->type]; } } else /* CONSTCOND */ assert (False); if ((rect_height = font_height * (b->ssize - itemp)) > (int) height) rect_height = height; if (XRectInRegion (region, 0, ypos, width, rect_height) != RectangleOut) { XRectangle rect; Region r1, r2; r1 = RegionFromRect (0, ypos, width, rect_height); XIntersectRegion (region, r1, r2 = XCreateRegion ()); XClipBox (r2, &rect); XFillRectangles (XtDisplay (w), XtWindow (w), back, &rect, 1); XDestroyRegion (r1); XDestroyRegion (r2); } stemp = ypos; assert (stemp >= 0); for (j = itemp; j < ths->fsize; j++) { stemp += font_height; assert (stemp >= 0); if (ths->text != NULL) { if (XRectInRegion (region, 0, stemp - font_height, width, font_height) != RectangleOut) { if (font_mono) { XDrawString (XtDisplay (w), XtWindow (w), fore, 0, stemp - font_descent, &ths->text[j][newss.leftcol], min (ths->tlen[j] - newss.leftcol, columns)); } else { XDrawString (XtDisplay (w), XtWindow (w), fore, -newss.leftcol, stemp - font_descent, ths->text[j], ths->tlen[j]); } } } else if (oth->text != NULL) { if (XRectInRegion (region, 0, stemp - font_height, width, font_height) != RectangleOut) { if (font_mono) { XDrawString (XtDisplay (w), XtWindow (w), fore, 0, stemp - font_descent, &oth->text[j][newss.leftcol], min (oth->tlen[j] - newss.leftcol, columns)); } else { XDrawString (XtDisplay (w), XtWindow (w), fore, -newss.leftcol, stemp - font_descent, oth->text[j], oth->tlen[j]); } } } else /* CONSTCOND */ assert (False); } ypos += rect_height; itemp = 0; if (ypos > height) { XDestroyRegion (region); return; } } /* * if we get here, it means that we're at the end of the display * and have to clear the last fractional line (or more, if the displayed * text is shorter than the height of the drawing area.) */ XClearArea (XtDisplay (w), XtWindow (w), 0, ypos, width, height - ypos, 0); XDestroyRegion (region); } /* * called by the entries in the 'File' menu */ /* ARGSUSED */ static void file_cb (Widget w, XtPointer closure, XtPointer call_data) { switch ((int) closure) { case 0: /* open */ toggle_open_sensitive (False); set_cursor (toplevel); open_both_files (toplevel, str_fnamel, str_fnamer); break; case 1: /* open left */ toggle_open_sensitive (False); set_cursor (toplevel); open_left_file (toplevel, str_fnamel); break; case 2: /* open right */ toggle_open_sensitive (False); set_cursor (toplevel); open_right_file (toplevel, str_fnamer); break; case 3: /* save as */ if (all_selected ()) { set_cursor (toplevel); save_file (toplevel, di->first, str_fnamel); } else { werror (toplevel, "Save Error", "Save", "there are unselected text blocks"); } break; case 4: /* exit */ exit_cb (w, NULL, NULL); break; default: assert (False); break; } } /* * called by the entries in the 'View' menu */ /* ARGSUSED */ static void view_cb (Widget w, XtPointer closure, XtPointer call_data) { switch ((int) closure) { case 0: /* previous */ prev_diff (NULL, NULL, NULL); break; case 1: /* next */ next_diff (NULL, NULL, NULL); break; case 2: /* next unselected */ next_diff_unselected (); break; default: assert (False); break; } } /* * called by the entries in the 'Select' menu */ /* ARGSUSED */ static void select_cb (Widget w, XtPointer closure, XtPointer call_data) { switch ((int) closure) { case 0: /* left */ select_all (LEFT); break; case 1: /* right */ select_all (RIGHT); break; case 2: /* unselect */ unselect_all (); break; default: assert (False); break; } } /* * called by the entries in the 'Options' menu */ /* ARGSUSED */ static void options_cb (Widget w, XtPointer closure, XtPointer call_data) { switch ((int) closure) { case 0: /* toggle overview area */ overview_flag = !overview_flag; if (overview_flag) { XtManageChild (frame1); XtVaSetValues (frame2, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, frame1, NULL); } else { XtVaSetValues (frame2, XmNrightAttachment, XmATTACH_FORM, NULL); XtUnmanageChild (frame1); } break; case 1: /* toggle horizontal scrollbar */ horz_scrollbar = !horz_scrollbar; if (horz_scrollbar) { XtManageChild (sbh); XtVaSetValues (form2, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, sbh, NULL); } else { XtVaSetValues (form2, XmNbottomAttachment, XmATTACH_FORM, NULL); XtUnmanageChild (sbh); } break; case 2: /* toggle drag scrolling */ drag_scroll = !drag_scroll; if (drag_scroll) { XtAddCallback (sbl, XmNdragCallback, drag_diff, NULL); XtAddCallback (sbr, XmNdragCallback, drag_diff, NULL); XtAddCallback (sbh, XmNdragCallback, sbh_moved, NULL); XtAddCallback (sb, XmNdragCallback, sb_moved, NULL); } else { XtRemoveCallback (sbl, XmNdragCallback, drag_diff, NULL); XtRemoveCallback (sbr, XmNdragCallback, drag_diff, NULL); XtRemoveCallback (sbh, XmNdragCallback, sbh_moved, NULL); XtRemoveCallback (sb, XmNdragCallback, sb_moved, NULL); } break; default: assert (False); break; } } /* * called by the entries in the 'Help' menu */ /* ARGSUSED */ static void helpmenu_cb (Widget w, XtPointer closure, XtPointer call_data) { switch ((int) closure) { case 0: /* version */ show_version (toplevel); break; case 1: /* manual page */ show_manual_page (toplevel); break; case 2: /* legend */ show_legend (toplevel); break; default: assert (False); break; } } /* * set sizes of scrollbars in overview area */ static void resize_em (WidgetList children) { Dimension height, left, right; XtVaGetValues (children[1], XmNheight, &height, NULL); left = (int) height * di->flines[LEFT] / max (di->flines[LEFT], di->flines[RIGHT]); right = (int) height * di->flines[RIGHT] / max (di->flines[LEFT], di->flines[RIGHT]); XtVaSetValues (children[0], XmNheight, left, NULL); XtVaSetValues (children[2], XmNheight, right, NULL); } /* * the program uses two scrollbars and a drawing area to create the * overview display; they are drawn on by drawing into some pixmaps * and then setting the backgroundPixmap of those widgets to those * pixmaps. */ static void set_pixmaps (WidgetList children) { Pixmap p[3]; Dimension width[3], height[3]; int depth[3]; Block *b; int yfpos[2]; int i; static int been_here; static GC dagcf, dagcb; if (!been_here) { XGCValues gc_values; XtVaGetValues (children[1], XmNforeground, &gc_values.foreground, XmNbackground, &gc_values.background, NULL); dagcf = XtGetGC (children[1], GCForeground|GCBackground, &gc_values); XtVaGetValues (children[1], XmNforeground, &gc_values.background, XmNbackground, &gc_values.foreground, NULL); dagcb = XtGetGC (children[1], GCForeground|GCBackground, &gc_values); been_here = 1; } for (i = 0; i < 3; i++) { XtVaGetValues (children[i], XmNwidth, &width[i], XmNheight, &height[i], XmNdepth, &depth[i], XmNbackgroundPixmap, &p[i], NULL); if (p[i] != XmUNSPECIFIED_PIXMAP) XFreePixmap (XtDisplay (children[i]), p[i]); p[i] = XCreatePixmap (XtDisplay (children[i]), XtWindow (children[i]), width[i], height[i], depth[i]); } for (i = 0; i < 5; i++) { XSetClipMask (XtDisplay (toplevel), gcfore[i], None); XSetClipMask (XtDisplay (toplevel), gcback[i], None); } XFillRectangle (XtDisplay (children[1]), p[1], dagcb, 0, 0, width[1], height[1]); yfpos[LEFT] = yfpos[RIGHT] = 0; for (b = di->first; b != NULL; b = b->next) { int y, h; int y1, y2, y3, y4; int back; y1 = y = (int) height[0] * yfpos[LEFT] / max (di->flines[LEFT], 1); yfpos[LEFT] += b->arr[LEFT].fsize; h = ((int) height[0] * yfpos[LEFT] / max (di->flines[LEFT], 1)) - y; y3 = ((h == 0) ? y1 : (y1 + h - 1)); back = (b->selected == LEFT) ? 4 : b->arr[LEFT].type; XFillRectangle (XtDisplay (children[0]), p[0], gcback[back], 0, y, width[0], h); y2 = y = (int) height[2] * yfpos[RIGHT] / max (di->flines[RIGHT], 1); yfpos[RIGHT] += b->arr[RIGHT].fsize; h = ((int) height[2] * yfpos[RIGHT] / max (di->flines[RIGHT], 1)) - y; y4 = ((h == 0) ? y2 : (y2 + h - 1)); back = (b->selected == RIGHT) ? 4 : b->arr[RIGHT].type; XFillRectangle (XtDisplay (children[2]), p[2], gcback[back], 0, y, width[2], h); if (b->arr[LEFT].type != SAME) { XDrawLine (XtDisplay (children[1]), p[1], dagcf, 0, y1, width[1] - 1, y2); XDrawLine (XtDisplay (children[1]), p[1], dagcf, 0, y3, width[1] - 1, y4); } } XDrawLine (XtDisplay (children[1]), p[1], dagcf, 0, 0, 0, height[1]); XDrawLine (XtDisplay (children[1]), p[1], dagcf, width[1] - 1, 0, width[1] - 1, height[1]); for (i = 0; i < 3; i++) XtVaSetValues (children[i], XmNbackgroundPixmap, p[i], NULL); } /* * create a bunch of the GCs that are needed */ static void create_gcs (void) { static XtResource resources[][4] = { {{XtNfont, XtCFont, XtRFont, sizeof (Font), XtOffset (XGCValues *, font), XtRString, "7x13bold"}, {"diffForeground", "DiffForeground", XtRPixel, sizeof (Pixel), XtOffset (XGCValues *, foreground), XtRString, "black"}, {"diffBackground", "DiffBackground", XtRPixel, sizeof (Pixel), XtOffset (XGCValues *, background), XtRString, "yellow"}}, {{XtNfont, XtCFont, XtRFont, sizeof (Font), XtOffset (XGCValues *, font), XtRString, "7x13bold"}, {"sameForeground", "SameForeground", XtRPixel, sizeof (Pixel), XtOffset (XGCValues *, foreground), XtRString, "black"}, {"sameBackground", "SameBackground", XtRPixel, sizeof (Pixel), XtOffset (XGCValues *, background), XtRString, "grey"}}, {{XtNfont, XtCFont, XtRFont, sizeof (Font), XtOffset (XGCValues *, font), XtRString, "7x13bold"}, {"insertForeground", "InsertForeground", XtRPixel, sizeof (Pixel), XtOffset (XGCValues *, foreground), XtRString, "black"}, {"insertBackground", "InsertBackground", XtRPixel, sizeof (Pixel), XtOffset (XGCValues *, background), XtRString, "orange"}}, {{XtNfont, XtCFont, XtRFont, sizeof (Font), XtOffset (XGCValues *, font), XtRString, "7x13bold"}, {"blankForeground", "BlankForeground", XtRPixel, sizeof (Pixel), XtOffset (XGCValues *, foreground), XtRString, "black"}, {"blankBackground", "BlankBackground", XtRPixel, sizeof (Pixel), XtOffset (XGCValues *, background), XtRString, "grey66"}}, {{XtNfont, XtCFont, XtRFont, sizeof (Font), XtOffset (XGCValues *, font), XtRString, "7x13bold"}, {"selectForeground", "SelectForeground", XtRPixel, sizeof (Pixel), XtOffset (XGCValues *, foreground), XtRString, "black"}, {"selectBackground", "SelectBackground", XtRPixel, sizeof (Pixel), XtOffset (XGCValues *, background), XtRString, "light slate blue"}}}; static int been_here; if (!been_here) { int i; for (i = 0; i < 5; i++) { XGCValues gc_values; XtGetApplicationResources (toplevel, &gc_values, resources[i], XtNumber (resources[i]), NULL, 0); gcfore[i] = XtGetGC (toplevel, GCForeground|GCBackground|GCFont, &gc_values); gc_values.foreground = gc_values.background; gcback[i] = XtGetGC (toplevel, GCForeground|GCBackground|GCFont, &gc_values); } been_here = 1; } } /* * this action routine is called when the overview area has been resized */ /* ARGSUSED1 */ static void configure_rowcol (Widget widget, XEvent *event, String *params, Cardinal *num_params) { WidgetList children; create_gcs (); XtVaGetValues (widget, XmNchildren, &children, NULL); resize_em (children); set_pixmaps (children); } /* * this function is called when the overview area information has * changed and needs to be updated */ static void update_pixmaps (void) { WidgetList children; XtVaGetValues (form3, XmNchildren, &children, NULL); set_pixmaps (children); } /* ARGSUSED */ static void do_nothing (Widget widget, XEvent *event, String *params, Cardinal *num_params) { } /* * add actions and change the translation tables of several widgets */ static void add_actions (XtAppContext app) { XtActionsRec action[2]; XtTranslations temp; /* * remove much of the input behavior of the scrollbar widgets * used in the overview display */ static char *foo1 = "\ ~Shift Ctrl ~Meta ~Alt : DoNothing() \n\ ~Shift Ctrl ~Meta ~Alt : DoNothing() \n\ ~Shift ~Ctrl ~Meta ~Alt : DoNothing() \n\ ~Shift ~Ctrl ~Meta ~Alt : DoNothing() \n\ ~Shift ~Ctrl ~Meta ~Alt Button1: DoNothing() \n\ osfBeginLine: DoNothing() \n\ osfEndLine: DoNothing() \n\ osfPageUp: DoNothing() \n\ osfPageDown: DoNothing() \n\ ~Shift ~Ctrl osfUp: DoNothing() \n\ ~Shift ~Ctrl osfDown: DoNothing() \n\ ~Shift ~Ctrl osfLeft: DoNothing() \n\ ~Shift ~Ctrl osfRight: DoNothing()"; /* * catch changes in the size of the overview display */ static char *foo2 = "\ : configure_rowcol() \n\ : configure_rowcol()"; /* * add selecting and scrolling actions to the drawing areas * that are used to render text */ static char *foo3 = "\ : Select() \n\ ~Ctrl osfPageDown: Scroll(PageDown) \n\ ~Ctrl osfPageUp: Scroll(PageUp) \n\ osfLeft: Scroll(Left) \n\ osfRight: Scroll(Right) \n\ osfDown: Scroll(Down) \n\ osfUp: Scroll(Up) \n\ Ctrl osfBeginLine: Scroll(BeginData) \n\ osfBeginLine: Scroll(BeginLine) \n\ Ctrl osfEndLine: Scroll(EndData) \n\ osfEndLine: Scroll(EndLine) \n\ Ctrl osfPageUp: Scroll(PageLeft) \n\ Ctrl osfPageDown: Scroll(PageRight) \n\ osfBeginData: Scroll(Home) \n\ osfEndData: Scroll(End)"; /* * these last two are not always in the XKeysymDB as they should be, * giving rise to runtime warnings from Xt */ action[0].string = "DoNothing"; action[0].proc = do_nothing; XtAppAddActions (app, action, 1); temp = XtParseTranslationTable (foo1); XtOverrideTranslations (sbl, temp); XtOverrideTranslations (sbr, temp); action[0].string = "configure_rowcol"; action[0].proc = configure_rowcol; XtAppAddActions (app, action, 1); temp = XtParseTranslationTable (foo2); XtOverrideTranslations (form3, temp); action[0].string = "Scroll"; action[0].proc = Scroll; action[1].string = "Select"; action[1].proc = Select; XtAppAddActions (app, action, 2); text_trans = XtParseTranslationTable (foo3); } /* * cleanup temporary file at program exit */ static void cleanup_at_exit (void) { if (tempfname != NULL) (void) unlink (tempfname); } /* * provide our own error handlers that print out and then * abort, causing a core dump for debugging purposes. this * only happens when the '-debug' flag is used. */ static int x_error_handler (Display *dpy, XErrorEvent *event) { char etext[BUFSIZ]; XGetErrorText (dpy, event->error_code, etext, BUFSIZ); (void) fprintf (stderr, "X Error: %s\n", etext); abort (); /* NOTREACHED */ } static void xt_error_handler (String message) { (void) fprintf (stderr, "Xt Error: %s\n", message); abort (); /* NOTREACHED */ } /* * filter out Xt warnings that are expected and are not the * result of real problems */ static void xt_warning_handler (String message) { static char *matchtable[] = { "linenuml", /* Traversal_on must always be true. */ "linenumr", /* Traversal_on must always be true. */ "osfBeginData", /* sometimes unknown as a keysym */ "osfEndData", /* sometimes unknown as a keysym */ "specified slider size", "scrollbar page increment" }; int i; for (i = 0; i < XtNumber (matchtable); i++) if (strstr (message, matchtable[i])) return; (void) fprintf (stderr, "Xt Warning: %s\n", message); } int main (int argc, char *argv[]) { Widget mainw, menubar, widget; int minimum_width, minimum_height; int depth; /* depth of top level shell */ static XtResource resources[] = { {"diffCommand", "DiffCommand", XtRString, sizeof (String), 0, XtRString, "diff"}, {"diffArgs", "DiffArgs", XtRString, sizeof (String), 0, XtRString, ""}, {"dragScroll", "DragScroll", XtRBoolean, sizeof (Boolean), 0, XtRString, "true"}, {"horzScrollbar", "HorzScrollbar", XtRBoolean, sizeof (Boolean), 0, XtRString, "true"}, {"linesOfContext", "LinesOfContext", XtRInt, sizeof (int), 0, XtRString, "3"}, {"overview", "Overview", XtRBoolean, sizeof (Boolean), 0, XtRString, "true"}, {"appDefaultsVersion", "AppDefaultsVersion", XtRInt, sizeof (int), 0, XtRString, "0"}, {"quitIfSame", "QuitIfSame", XtRBoolean, sizeof (Boolean), 0, XtRString, "false"}, {"debug", "Debug", XtRBoolean, sizeof (Boolean), 0, XtRString, "false"}, {"filename", "Filename", XtRString, sizeof (String), 0, XtRString, ""}}; progname = basename (argv[0]); toplevel = XtVaAppInitialize (&app, "Mgdiff", option_table, XtNumber (option_table), #if X11R5 &argc, #else (unsigned int *) &argc, #endif argv, fallbacks, NULL); XtVaGetValues (toplevel, XmNdepth, &depth, NULL); if (depth == 1) XtAppError (app, "monochrome displays are not supported"); add_editres (toplevel); XmAddWMProtocolCallback (toplevel, XmInternAtom (XtDisplay (toplevel), "WM_DELETE_WINDOW", False), exit_cb, NULL); bitmap = XCreatePixmapFromBitmapData (XtDisplay (toplevel), RootWindowOfScreen (XtScreen (toplevel)), (char *) mgdiff_bits, mgdiff_width, mgdiff_height, BlackPixelOfScreen (XtScreen (toplevel)), WhitePixelOfScreen (XtScreen (toplevel)), 1); XtVaSetValues (toplevel, XmNiconPixmap, bitmap, NULL); XtGetApplicationResources (toplevel, &diffcmd, &resources[0], 1, NULL, 0); XtGetApplicationResources (toplevel, &diffargs, &resources[1], 1, NULL, 0); XtGetApplicationResources (toplevel, &drag_scroll, &resources[2], 1, NULL, 0); XtGetApplicationResources (toplevel, &horz_scrollbar, &resources[3], 1, NULL, 0); XtGetApplicationResources (toplevel, &lines_of_context, &resources[4], 1, NULL, 0); if (lines_of_context < 0) { lines_of_context = 0; /* print out warning */ XtAppWarning (app, "Illegal value specified for \"linesOfContext\" resource"); } XtGetApplicationResources (toplevel, &overview_flag, &resources[5], 1, NULL, 0); XtGetApplicationResources (toplevel, &app_defaults_version, &resources[6], 1, NULL, 0); XtGetApplicationResources (toplevel, &quit_flag, &resources[7], 1, NULL, 0); XtGetApplicationResources (toplevel, &debug_flag, &resources[8], 1, NULL, 0); XtGetApplicationResources (toplevel, &user_filename, &resources[9], 1, NULL, 0); if (app_defaults_version == 0) { static String array[] = { "The application defaults file for mgdiff (named \"Mgdiff\")", "was not found and so the program will not work correctly.", "Exit the program and see the RESOURCES section of the", "X(1) manual page for information on how to install it." }; werror_long (toplevel, "No Application Defaults", array, sizeof (array) / sizeof (array[0])); } else if (app_defaults_version != APP_DEFAULTS_VERSION) { static String array[] = { "The application defaults file for mgdiff (named \"Mgdiff\") is", "the wrong version and so the program may not work correctly.", }; werror_long (toplevel, "Wrong Application Defaults", array, sizeof (array) / sizeof (array[0])); } if (debug_flag) { XSetErrorHandler (x_error_handler); XtAppSetErrorHandler (app, xt_error_handler); } else XtAppSetWarningHandler (app, xt_warning_handler); #if sun (void) on_exit (cleanup_at_exit, NULL); #else (void) atexit (cleanup_at_exit); #endif switch (argc) { /* * no filenames on command line; start up empty */ case 1: no_files_flag = True; di = blank_diff_info (); str_snamel = strdup ("(no file)"); str_snamer = strdup ("(no file)"); break; /* * two filenames on command line; process them */ case 3: if (strcmp (argv[1], "-") == 0) { tempfname = tempnam (NULL, "mgdif"); str_fnamel = strdup (tempfname); str_snamel = strdup (user_filename); if (!copy_to_file (stdin, tempfname)) { (void) fprintf (stderr, "Error copying stdin to temp file \"%s\"\n", tempfname); exit (2); } } else if (!file_tests (toplevel, argv[1])) { no_files_flag = True; di = blank_diff_info (); str_snamel = strdup ("(no file)"); str_snamer = strdup ("(no file)"); break; } else { str_snamel = strdup (argv[1]); str_fnamel = strdup (argv[1]); } if (strcmp (argv[2], "-") == 0) { tempfname = tempnam (NULL, "mgdif"); str_fnamer = strdup (tempfname); str_snamer = strdup (user_filename); if (!copy_to_file (stdin, tempfname)) { (void) fprintf (stderr, "Error copying stdin to temp file \"%s\"\n", tempfname); exit (2); } } else if (!file_tests (toplevel, argv[2])) { no_files_flag = True; di = blank_diff_info (); str_snamel = strdup ("(no file)"); str_snamer = strdup ("(no file)"); break; } else { str_snamer = strdup (argv[2]); str_fnamer = strdup (argv[2]); } di = build_diff_info (diffcmd, diffargs, str_fnamel, str_fnamer); handle_diff_errors (di); if ((di->status == 0) && quit_flag) { exit (0); } else if (di->status == 2) { str_fnamel = str_fnamer = NULL; str_snamel = strdup ("(no file)"); str_snamer = strdup ("(no file)"); } break; /* * anything else is a usage error */ default: (void) fprintf (stderr, "Usage: %s [-toolkitoption ...] [-quit] [-file name] [-args diffargs] [file1 file2]\n", progname); exit (2); break; } newss.b = di->first; newss.topline = newss.sindex = newss.findex[LEFT] = newss.findex[RIGHT] = 0; mainw = XtVaCreateManagedWidget ("mainw", xmMainWindowWidgetClass, toplevel, NULL); /* * create menu bar */ menubar = XmVaCreateSimpleMenuBar (mainw, "menubar", XmVaCASCADEBUTTON, NULL, NULL, XmVaCASCADEBUTTON, NULL, NULL, XmVaCASCADEBUTTON, NULL, NULL, XmVaCASCADEBUTTON, NULL, NULL, XmVaCASCADEBUTTON, NULL, NULL, NULL); /* * make the minimum permissible width of the window equal to the * minimum width of the menubar */ minimum_width = (int) get_preferred_width (menubar); minimum_height = (minimum_width * 3) / 4; file_menu = XmVaCreateSimplePulldownMenu (menubar, "file_menu", 0, file_cb, XmVaPUSHBUTTON, NULL, NULL, NULL, NULL, XmVaPUSHBUTTON, NULL, NULL, NULL, NULL, XmVaPUSHBUTTON, NULL, NULL, NULL, NULL, XmVaPUSHBUTTON, NULL, NULL, NULL, NULL, XmVaSEPARATOR, XmVaPUSHBUTTON, NULL, NULL, NULL, NULL, NULL); if (no_files_flag || (di->status == 2)) { toggle_openlr_sensitive (False); toggle_saveas_sensitive (False); } XmVaCreateSimplePulldownMenu (menubar, "view_menu", 1, view_cb, XmVaPUSHBUTTON, NULL, NULL, NULL, NULL, XmVaPUSHBUTTON, NULL, NULL, NULL, NULL, XmVaPUSHBUTTON, NULL, NULL, NULL, NULL, NULL); XmVaCreateSimplePulldownMenu (menubar, "select_menu", 2, select_cb, XmVaPUSHBUTTON, NULL, NULL, NULL, NULL, XmVaPUSHBUTTON, NULL, NULL, NULL, NULL, XmVaSEPARATOR, XmVaPUSHBUTTON, NULL, NULL, NULL, NULL, NULL); widget = XmVaCreateSimplePulldownMenu (menubar, "options_menu", 3, options_cb, XmVaTOGGLEBUTTON, NULL, NULL, NULL, NULL, XmVaTOGGLEBUTTON, NULL, NULL, NULL, NULL, XmVaTOGGLEBUTTON, NULL, NULL, NULL, NULL, NULL); XmVaCreateSimplePulldownMenu (menubar, "help_menu", 4, helpmenu_cb, XmVaPUSHBUTTON, NULL, NULL, NULL, NULL, XmVaPUSHBUTTON, NULL, NULL, NULL, NULL, XmVaPUSHBUTTON, NULL, NULL, NULL, NULL, NULL); XtVaSetValues (menubar, XmNmenuHelpWidget, XtNameToWidget (menubar, "button_4"), NULL); XmToggleButtonSetState (XtNameToWidget (widget, "button_0"), overview_flag, False); XmToggleButtonSetState (XtNameToWidget (widget, "button_1"), horz_scrollbar, False); XmToggleButtonSetState (XtNameToWidget (widget, "button_2"), drag_scroll, False); XtManageChild (menubar); form1 = XtVaCreateManagedWidget ("form1", xmFormWidgetClass, mainw, XmNhorizontalSpacing, 1, XmNverticalSpacing, 1, NULL); XtVaSetValues (mainw, XmNmenuBar, menubar, XmNworkWindow, form1, NULL); frame1 = XtVaCreateWidget ("frame1", xmFrameWidgetClass, form1, XmNleftAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); if (overview_flag) XtManageChild (frame1); form3 = XtVaCreateManagedWidget ("form3", xmFormWidgetClass, frame1, XmNhorizontalSpacing, 0, NULL); sbl = XtVaCreateManagedWidget ("sbl", xmScrollBarWidgetClass, form3, XmNmaximum, max (1, di->flines[LEFT]), XmNpageIncrement, 1, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_WIDGET, XmNbottomAttachment, XmATTACH_NONE, XmNtopAttachment, XmATTACH_FORM, XmNshowArrows, False, XmNsliderSize, 1, XmNshadowThickness, 0, NULL); XtAddCallback (sbl, XmNpageIncrementCallback, next_diff, NULL); XtAddCallback (sbl, XmNpageDecrementCallback, prev_diff, NULL); XtAddCallback (sbl, XmNvalueChangedCallback, drag_diff, NULL); if (drag_scroll) XtAddCallback (sbl, XmNdragCallback, drag_diff, NULL); dam = XtVaCreateManagedWidget ("dam", xmDrawingAreaWidgetClass, form3, XmNtraversalOn, False, XmNleftAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_WIDGET, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); sbr = XtVaCreateManagedWidget ("sbr", xmScrollBarWidgetClass, form3, XmNmaximum, max (1, di->flines[RIGHT]), XmNpageIncrement, 1, XmNleftAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNtopAttachment, XmATTACH_FORM, XmNshowArrows, False, XmNsliderSize, 1, XmNshadowThickness, 0, NULL); add_actions (app); XtAddCallback (sbr, XmNpageIncrementCallback, next_diff, NULL); XtAddCallback (sbr, XmNpageDecrementCallback, prev_diff, NULL); XtAddCallback (sbr, XmNvalueChangedCallback, drag_diff, NULL); if (drag_scroll) XtAddCallback (sbr, XmNdragCallback, drag_diff, NULL); frame2 = XtVaCreateManagedWidget ("frame2", xmFrameWidgetClass, form1, XmNleftAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); form4 = XtVaCreateManagedWidget ("form4", xmFormWidgetClass, frame2, NULL); form2 = XtVaCreateManagedWidget ("form2", xmFormWidgetClass, form4, XmNhorizontalSpacing, 1, XmNverticalSpacing, 1, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); sbh = XtVaCreateWidget ("sbh", xmScrollBarWidgetClass, form4, XmNmaximum, di->maxcols, XmNsliderSize, 1, XmNorientation, XmHORIZONTAL, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_NONE, XmNheight, 20, NULL); XtAddCallback (sbh, XmNvalueChangedCallback, sbh_moved, NULL); if (drag_scroll) XtAddCallback (sbh, XmNdragCallback, sbh_moved, NULL); if (horz_scrollbar) XtManageChild (sbh); sb = XtVaCreateManagedWidget ("sb", xmScrollBarWidgetClass, form2, XmNmaximum, di->lines, XmNleftAttachment, XmATTACH_POSITION, XmNleftOffset, -10, /* -1/2 of width */ XmNrightAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNleftPosition, 50, XmNwidth, 20, NULL); if (drag_scroll) XtAddCallback (sb, XmNdragCallback, sb_moved, NULL); XtAddCallback (sb, XmNvalueChangedCallback, sb_moved, NULL); XtAddCallback (sb, XmNincrementCallback, sb_moved, NULL); XtAddCallback (sb, XmNdecrementCallback, sb_moved, NULL); XtAddCallback (sb, XmNpageIncrementCallback, sb_moved, NULL); XtAddCallback (sb, XmNpageDecrementCallback, sb_moved, NULL); XtAddCallback (sb, XmNtoTopCallback, sb_moved, NULL); XtAddCallback (sb, XmNtoBottomCallback, sb_moved, NULL); form21 = XtVaCreateManagedWidget ("form21", xmFormWidgetClass, form2, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_WIDGET, XmNbottomAttachment, XmATTACH_NONE, XmNtopAttachment, XmATTACH_FORM, NULL); frame3 = XtVaCreateManagedWidget ("frame3", xmFrameWidgetClass, form21, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_WIDGET, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); fnamel = XtVaCreateManagedWidget ("fnamel", xmLabelWidgetClass, frame3, XmNlabelString, XmStringCreateSimple (str_snamel), NULL); linenum_columns = ilog10 (max (di->flines[LEFT], di->flines[RIGHT])); frame31 = XtVaCreateManagedWidget ("frame31", xmFrameWidgetClass, form21, XmNleftAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); linenuml = XtVaCreateManagedWidget ("linenuml", xmTextFieldWidgetClass, frame31, XmNcolumns, linenum_columns, XmNsensitive, True, XmNtraversalOn, False, XmNeditable, False, XmNhighlightThickness, 0, XmNmarginHeight, 2, XmNshadowThickness, 0, XmNcursorPositionVisible, False, NULL); XtVaSetValues (frame3, XmNrightWidget, frame31, NULL); form22 = XtVaCreateManagedWidget ("form22", xmFormWidgetClass, form2, XmNleftAttachment, XmATTACH_WIDGET, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNtopAttachment, XmATTACH_FORM, NULL); frame4 = XtVaCreateManagedWidget ("frame4", xmFrameWidgetClass, form22, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_WIDGET, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); fnamer = XtVaCreateManagedWidget ("fnamer", xmLabelWidgetClass, frame4, XmNlabelString, XmStringCreateSimple (str_snamer), NULL); frame41 = XtVaCreateManagedWidget ("frame41", xmFrameWidgetClass, form22, XmNleftAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); linenumr = XtVaCreateManagedWidget ("linenumr", xmTextFieldWidgetClass, frame41, XmNcolumns, linenum_columns, XmNsensitive, True, XmNeditable, False, XmNtraversalOn, False, XmNhighlightThickness, 0, XmNmarginHeight, 2, XmNshadowThickness, 0, XmNcursorPositionVisible, False, NULL); XtVaSetValues (frame4, XmNrightWidget, frame41, NULL); update_line_numbers (1, 1); textl = XtVaCreateManagedWidget ("text", xmDrawingAreaWidgetClass, form2, XmNtraversalOn, False, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_WIDGET, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_WIDGET, NULL); XtOverrideTranslations (textl, text_trans); XtAddCallback (textl, XmNexposeCallback, drawit, NULL); textr = XtVaCreateManagedWidget ("text", xmDrawingAreaWidgetClass, form2, XmNtraversalOn, False, XmNleftAttachment, XmATTACH_WIDGET, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_WIDGET, NULL); XtOverrideTranslations (textr, text_trans); XtAddCallback (textr, XmNexposeCallback, drawit, NULL); XtAddCallback (textr, XmNresizeCallback, resize_cb, NULL); XtVaSetValues (sbl, XmNrightWidget, dam, NULL); XtVaSetValues (dam, XmNrightWidget, sbr, NULL); XtVaSetValues (form21, XmNrightWidget, sb, NULL); if (overview_flag) XtVaSetValues (frame2, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, frame1, NULL); else XtVaSetValues (frame2, XmNrightAttachment, XmATTACH_FORM, NULL); XtVaSetValues (form22, XmNleftWidget, sb, NULL); XtVaSetValues (textl, XmNtopWidget, form21, XmNrightWidget, sb, NULL); XtVaSetValues (textr, XmNtopWidget, form22, XmNleftWidget, sb, NULL); if (horz_scrollbar) XtVaSetValues (form2, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, sbh, NULL); else XtVaSetValues (form2, XmNbottomAttachment, XmATTACH_FORM, NULL); XtRealizeWidget (toplevel); XtVaSetValues (toplevel, XmNminWidth, minimum_width, XmNminHeight, minimum_height, NULL); XtAddEventHandler (textl, VisibilityChangeMask, False, Visible, NULL); XtAddEventHandler (textr, VisibilityChangeMask, False, Visible, NULL); XtAddEventHandler (fnamel, StructureNotifyMask, False, adjust_label, NULL); XtAddEventHandler (fnamer, StructureNotifyMask, False, adjust_label, NULL); XtAddEventHandler (fnamel, ExposureMask, False, adjust_label, NULL); XtAddEventHandler (fnamer, ExposureMask, False, adjust_label, NULL); XtAppMainLoop (app); /* NOTREACHED */ } static void redraw_partial_vert (Widget w) { Dimension xsrc, ysrc, xdest, ydest; Dimension width, height; XExposeEvent e; XmDrawingAreaCallbackStruct dacbs; XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL); dacbs.event = (XEvent *) &e; e.type = Expose; e.send_event = False; e.display = XtDisplay (w); e.window = XtWindow (w); e.count = 0; e.x = 0; e.width = width; xsrc = xdest = 0; if (newss.topline < oldss.topline) { /* scrolling down */ ysrc = 0; ydest = (oldss.topline - newss.topline) * font_height; e.y = 0; if (ydest < height) { XCopyArea (XtDisplay (w), XtWindow (w), XtWindow (w), gc, xsrc, ysrc, width, height - ysrc, xdest, ydest); e.height = ydest; } else { e.height = height; } } else { /* scrolling up */ ydest = 0; ysrc = (newss.topline - oldss.topline) * font_height; if (ysrc < height) { XCopyArea (XtDisplay (w), XtWindow (w), XtWindow (w), gc, xsrc, ysrc, width, height - ysrc, xdest, ydest); e.y = height - ysrc; e.height = ysrc; } else { e.y = 0; e.height = height; } } XtCallCallbacks (w, XmNexposeCallback, &dacbs); } static void redraw_partial_horz (Widget w) { Dimension xsrc, ysrc, xdest, ydest; Dimension width, height; XExposeEvent e; XmDrawingAreaCallbackStruct dacbs; XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL); dacbs.event = (XEvent *) &e; e.type = Expose; e.send_event = False; e.display = XtDisplay (w); e.window = XtWindow (w); e.count = 0; e.y = 0; e.height = height; ysrc = ydest = 0; if (newss.leftcol < oldss.leftcol) { /* scrolling right */ xsrc = 0; xdest = (oldss.leftcol - newss.leftcol) * (font_mono ? font_width : 1); e.x = 0; if (xdest < width) { XCopyArea (XtDisplay (w), XtWindow (w), XtWindow (w), gc, xsrc, ysrc, width - xsrc, height, xdest, ydest); e.width = xdest; } else { e.width = width; } } else { /* scrolling left */ xdest = 0; xsrc = (newss.leftcol - oldss.leftcol) * (font_mono ? font_width : 1); if (xsrc < width) { XCopyArea (XtDisplay (w), XtWindow (w), XtWindow (w), gc, xsrc, ysrc, width - xsrc, height, xdest, ydest); e.x = width - xsrc; e.width = xsrc; } else { e.x = 0; e.width = width; } } XtCallCallbacks (w, XmNexposeCallback, &dacbs); } /* ARGSUSED */ static void sbh_moved (Widget w, XtPointer closure, XtPointer call_data) { XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *) call_data; if (cbs->value != newss.leftcol) { oldss = newss; newss.leftcol = cbs->value; redraw_both_horz (); } } /* * the XmTextFieldSetString calls may leak memory according to Purify */ static void update_line_numbers (int l, int r) { char buffer[16]; (void) sprintf (buffer, "%*d", linenum_columns, l); XmTextFieldSetString (linenuml, buffer); (void) sprintf (buffer, "%*d", linenum_columns, r); XmTextFieldSetString (linenumr, buffer); } /* ARGSUSED */ static void sb_moved (Widget w, XtPointer closure, XtPointer call_data) { XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *) call_data; switch (cbs->reason) { case XmCR_INCREMENT: case XmCR_DECREMENT: case XmCR_PAGE_INCREMENT: case XmCR_PAGE_DECREMENT: case XmCR_TO_TOP: case XmCR_TO_BOTTOM: update_screenstate (cbs->reason, cbs->value); break; case XmCR_VALUE_CHANGED: if (cbs->value < newss.topline) update_screenstate (XmCR_PAGE_DECREMENT, cbs->value); else if (cbs->value > newss.topline) update_screenstate (XmCR_PAGE_INCREMENT, cbs->value); else { update_line_numbers (newss.findex[LEFT] + 1, newss.findex[RIGHT] + 1); return; } break; case XmCR_DRAG: if (cbs->value < newss.topline) update_screenstate (XmCR_PAGE_DECREMENT, cbs->value); else if (cbs->value > newss.topline) update_screenstate (XmCR_PAGE_INCREMENT, cbs->value); else return; break; default: /* CONSTCOND */ assert (False); break; } update_overall (); update_line_numbers (newss.findex[LEFT] + 1, newss.findex[RIGHT] + 1); redraw_both_vert (); } /* * redraw an entire DrawingArea widget by synthesizing an Expose event * and invoking the widget's expose callbacks */ static void redraw_full (Widget w) { Dimension width, height; XExposeEvent e; XmDrawingAreaCallbackStruct dacbs; XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL); dacbs.event = (XEvent *) &e; e.type = Expose; e.send_event = False; e.display = XtDisplay (w); e.count = e.x = e.y = 0; e.width = width; e.height = height; e.window = XtWindow (w); XtCallCallbacks (w, XmNexposeCallback, &dacbs); } /* * redraw part of a DrawingArea widget by synthesizing an Expose event * and invoking the widget's expose callbacks */ static void redraw_partial (Widget w, Dimension ypos, Dimension height) { Dimension width; XExposeEvent e; XmDrawingAreaCallbackStruct dacbs; XtVaGetValues (w, XmNwidth, &width, NULL); dacbs.event = (XEvent *) &e; e.type = Expose; e.send_event = False; e.display = XtDisplay (w); e.count = e.x = 0; e.y = ypos; e.width = width; e.height = height; e.window = XtWindow (w); XtCallCallbacks (w, XmNexposeCallback, &dacbs); } static void update_screenstate (int reason, int topline) { Block *b; if (topline == newss.topline) return; switch (reason) { case XmCR_INCREMENT: oldss = newss; newss.topline += 1; if (newss.sindex >= (newss.b->ssize - 1)) { newss.b = newss.b->next; newss.sindex = 0; } else newss.sindex += 1; break; case XmCR_DECREMENT: oldss = newss; newss.topline -= 1; if (newss.sindex == 0) { newss.b = newss.b->prev; newss.sindex = newss.b->ssize - 1; } else newss.sindex -= 1; break; case XmCR_PAGE_INCREMENT: oldss = newss; newss.topline = topline; for (b = newss.b; b->next != NULL; b = b->next) { if ((newss.topline >= b->sline) && (newss.topline < (b->sline + b->ssize))) break; } newss.b = b; newss.sindex = newss.topline - newss.b->sline; break; case XmCR_PAGE_DECREMENT: oldss = newss; newss.topline = topline; for (b = newss.b; b->prev != NULL; b = b->prev) { if ((newss.topline >= b->sline) && (newss.topline < (b->sline + b->ssize))) break; } newss.b = b; newss.sindex = newss.topline - newss.b->sline; break; case XmCR_TO_TOP: oldss = newss; newss.b = di->first; newss.topline = 0; newss.sindex = 0; break; case XmCR_TO_BOTTOM: oldss = newss; newss.topline = topline; for (b = di->last; b->prev != NULL; b = b->prev) { if ((newss.topline >= b->sline) && (newss.topline < (b->sline + b->ssize))) break; } newss.b = b; newss.sindex = newss.topline - newss.b->sline; break; default: assert (False); break; } } static void redraw_both_vert (void) { switch (statel) { case VisibilityUnobscured: redraw_partial_vert (textl); break; case VisibilityPartiallyObscured: redraw_full (textl); break; case VisibilityFullyObscured: break; default: assert (False); break; } switch (stater) { case VisibilityUnobscured: redraw_partial_vert (textr); break; case VisibilityPartiallyObscured: redraw_full (textr); break; case VisibilityFullyObscured: break; default: assert (False); break; } } static void redraw_both_horz (void) { switch (statel) { case VisibilityUnobscured: redraw_partial_horz (textl); break; case VisibilityPartiallyObscured: redraw_full (textl); break; case VisibilityFullyObscured: break; default: assert (False); break; } switch (stater) { case VisibilityUnobscured: redraw_partial_horz (textr); break; case VisibilityPartiallyObscured: redraw_full (textr); break; case VisibilityFullyObscured: break; } } /* ARGSUSED */ static void next_diff (Widget w, XtPointer closure, XtPointer call_data) { Block *b; for (b = newss.b->next; b != NULL; b = b->next) if ((b->arr[LEFT].type != SAME) && ((newss.topline + lines_of_context) < b->sline)) { int value, maximum, slidersize; XmScrollBarCallbackStruct newcbs; value = (b->sline >= lines_of_context) ? (b->sline - lines_of_context) : b->sline; XtVaGetValues (sb, XmNmaximum, &maximum, XmNsliderSize, &slidersize, NULL); if (value > (maximum - slidersize)) value = maximum - slidersize; if ((w == sbl) || (w == sbr)) { int side = (w == sbl) ? LEFT : RIGHT; if (newcbs.value > (maximum - slidersize)) { newcbs.value = maximum - slidersize; XtVaSetValues (w, XmNvalue, newcbs.value - b->sline + b->arr[side].fline, NULL); return; } } newcbs.reason = XmCR_VALUE_CHANGED; newcbs.event = NULL; newcbs.value = value; XtVaSetValues (sb, XmNvalue, value, NULL); XtCallCallbacks (sb, XmNvalueChangedCallback, &newcbs); return; } } static void next_diff_unselected (void) { Block *b; for (b = newss.b->next; b != NULL; b = b->next) if ((b->selected == NEITHER) && (b->arr[LEFT].type != SAME) && ((newss.topline + lines_of_context) < b->sline)) { int value, maximum, slidersize; XmScrollBarCallbackStruct newcbs; value = (b->sline >= lines_of_context) ? (b->sline - lines_of_context) : b->sline; XtVaGetValues (sb, XmNmaximum, &maximum, XmNsliderSize, &slidersize, NULL); if (value > (maximum - slidersize)) value = maximum - slidersize; newcbs.reason = XmCR_VALUE_CHANGED; newcbs.event = NULL; newcbs.value = value; XtVaSetValues (sb, XmNvalue, value, NULL); XtCallCallbacks (sb, XmNvalueChangedCallback, &newcbs); return; } } /* ARGSUSED */ static void prev_diff (Widget w, XtPointer closure, XtPointer call_data) { Block *b; for (b = newss.b->prev; b != NULL; b = b->prev) if ((b->arr[LEFT].type != SAME) && ((newss.topline + lines_of_context) >= b->sline)) { int value; XmScrollBarCallbackStruct newcbs; value = (b->sline >= lines_of_context) ? (b->sline - lines_of_context) : 0; newcbs.reason = XmCR_VALUE_CHANGED; newcbs.event = NULL; newcbs.value = value; XtVaSetValues (sb, XmNvalue, value, NULL); XtCallCallbacks (sb, XmNvalueChangedCallback, &newcbs); return; } } /* ARGSUSED */ static void drag_diff (Widget w, XtPointer closure, XtPointer call_data) { XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *) call_data; Block *b; XmScrollBarCallbackStruct newcbs; int side = (w == sbl) ? LEFT : RIGHT; int maximum, slidersize; if (cbs->value < newss.findex[side]) { /* towards the start */ for (b = newss.b; b != NULL; b = b->prev) { if (cbs->value < (b->arr[side].fline + b->arr[side].fsize)) { newcbs.reason = XmCR_VALUE_CHANGED; newcbs.event = NULL; newcbs.value = b->sline + (cbs->value - b->arr[side].fline); XtVaSetValues (sb, XmNvalue, newcbs.value, NULL); XtCallCallbacks (sb, XmNvalueChangedCallback, &newcbs); return; } } } else { /* towards the end */ for (b = newss.b; b != NULL; b = b->next) { if (cbs->value < (b->arr[side].fline + b->arr[side].fsize)) { newcbs.reason = XmCR_VALUE_CHANGED; newcbs.event = NULL; newcbs.value = b->sline + (cbs->value - b->arr[side].fline); XtVaGetValues (sb, XmNmaximum, &maximum, XmNsliderSize, &slidersize, NULL); if (newcbs.value > (maximum - slidersize)) { newcbs.value = maximum - slidersize; XtVaSetValues (w, XmNvalue, newcbs.value - b->sline + b->arr[side].fline, NULL); return; } XtVaSetValues (sb, XmNvalue, newcbs.value, NULL); XtCallCallbacks (sb, XmNvalueChangedCallback, &newcbs); return; } } } } static void show_version (Widget parent) { static Widget dialog; char buffer[512]; if (dialog == NULL) { Pixel fg, bg; Display *dpy = XtDisplay (parent); Pixmap bitmap; dialog = XmCreateInformationDialog (parent, "version", NULL, 0); XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON)); XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON)); XtVaGetValues (dialog, XmNforeground, &fg, XmNbackground, &bg, NULL); bitmap = XCreatePixmapFromBitmapData (dpy, XtWindow (parent), (char *) mgdiff_bits, mgdiff_width, mgdiff_height, fg, bg, DefaultDepth (dpy, DefaultScreen (dpy))); (void) sprintf (buffer, "mgdiff\n\nA graphical difference browser\n\nAuthor: Dan Williams (dan@sass.com)\nVersion: %s PL%s", VERSION, PATCHLEVEL); XtVaSetValues (dialog, XmNautoUnmanage, True, XmNsymbolPixmap, bitmap, XtVaTypedArg, XmNmessageString, XmRString, buffer, strlen (buffer)+1, NULL); } XtManageChild (dialog); } static void update_overall (void) { int value; value = newss.b->arr[LEFT].fline; if (newss.sindex < newss.b->arr[LEFT].fsize) value += newss.sindex; else value += newss.b->arr[LEFT].fsize; if (value < di->flines[LEFT]) XtVaSetValues (sbl, XmNvalue, value, NULL); newss.findex[LEFT] = value; value = newss.b->arr[RIGHT].fline; if (newss.sindex < newss.b->arr[RIGHT].fsize) value += newss.sindex; else value += newss.b->arr[RIGHT].fsize; if (value < di->flines[RIGHT]) XtVaSetValues (sbr, XmNvalue, value, NULL); newss.findex[RIGHT] = value; } void process_both_files (char *file1, char *name1, char *file2, char *name2) { DiffInfo *newdi; str_fnamel = strdup (file1); str_snamel = strdup (name1); str_fnamer = strdup (file2); str_snamer = strdup (name2); set_cursor (toplevel); newdi = build_diff_info (diffcmd, diffargs, str_fnamel, str_fnamer); /* * can't put this before build_diff_info (where it would get to * reuse the freed memory) because build_diff_info processes * exposure events which need the information. */ free_diff_info (di); di = newdi; if (di->status != 2) { no_files_flag = False; toggle_openlr_sensitive (True); toggle_saveas_sensitive (True); } else { no_files_flag = True; toggle_openlr_sensitive (False); toggle_saveas_sensitive (False); free (str_fnamel); free (str_snamel); free (str_fnamer); free (str_snamer); str_snamel = strdup ("(no file)"); str_snamer = strdup ("(no file)"); str_fnamel = str_fnamer = NULL; } refresh (); fake_adjust_label (fnamel); fake_adjust_label (fnamer); reset_cursor (toplevel); handle_diff_errors (di); } void process_left_file (char *file1, char *name1) { DiffInfo *newdi; str_fnamel = strdup (file1); str_snamel = strdup (name1); set_cursor (toplevel); newdi = build_diff_info (diffcmd, diffargs, str_fnamel, str_fnamer); /* * can't put this before build_diff_info (where it would get to * reuse the freed memory) because build_diff_info processes * exposure events which need the information. */ free_diff_info (di); di = newdi; if (di->status == 2) { no_files_flag = True; toggle_openlr_sensitive (False); toggle_saveas_sensitive (False); free (str_fnamel); free (str_snamel); free (str_fnamer); free (str_snamer); str_snamel = strdup ("(no file)"); str_snamer = strdup ("(no file)"); str_fnamel = str_fnamer = NULL; } refresh (); fake_adjust_label (fnamel); reset_cursor (toplevel); handle_diff_errors (di); } void process_right_file (char *file2, char *name2) { DiffInfo *newdi; str_fnamer = strdup (file2); str_snamer = strdup (name2); set_cursor (toplevel); newdi = build_diff_info (diffcmd, diffargs, str_fnamel, str_fnamer); /* * can't put this before build_diff_info (where it would get to * reuse the freed memory) because build_diff_info processes * exposure events which need the information. */ free_diff_info (di); di = newdi; if (di->status == 2) { no_files_flag = True; toggle_openlr_sensitive (False); toggle_saveas_sensitive (False); free (str_fnamel); free (str_snamel); free (str_fnamer); free (str_snamer); str_snamel = strdup ("(no file)"); str_snamer = strdup ("(no file)"); str_fnamel = str_fnamer = NULL; } refresh (); fake_adjust_label (fnamer); reset_cursor (toplevel); handle_diff_errors (di); } static void refresh (void) { newss.b = di->first; newss.topline = newss.sindex = newss.findex[LEFT] = newss.findex[RIGHT] = 0; XtVaSetValues (sbl, XmNmaximum, di->flines[LEFT], XmNpageIncrement, 1, XmNvalue, 0, NULL); XtVaSetValues (sbr, XmNmaximum, di->flines[RIGHT], XmNpageIncrement, 1, XmNvalue, 0, NULL); XtVaSetValues (sbh, XmNsliderSize, 1, XmNmaximum, di->maxcols, XmNvalue, 0, NULL); XtVaSetValues (sb, XmNsliderSize, 1, XmNmaximum, di->lines, XmNvalue, 0, NULL); XtVaSetValues (fnamel, XtVaTypedArg, XmNlabelString, XmRString, str_snamel, strlen (str_snamel) + 1, NULL); XtVaSetValues (fnamer, XtVaTypedArg, XmNlabelString, XmRString, str_snamer, strlen (str_snamer) + 1, NULL); linenum_columns = ilog10 (max (di->flines[LEFT], di->flines[RIGHT])); XtVaSetValues (linenuml, XmNcolumns, linenum_columns, NULL); XtVaSetValues (linenumr, XmNcolumns, linenum_columns, NULL); update_line_numbers (newss.findex[LEFT] + 1, newss.findex[RIGHT] + 1); resize_cb (textl, NULL, NULL); resize_cb (textr, NULL, NULL); redraw_full (textl); redraw_full (textr); configure_rowcol (form3, NULL, NULL, NULL); } void toggle_openlr_sensitive (Boolean sensitive) { if (!no_files_flag || !sensitive) { XtSetSensitive (XtNameToWidget (file_menu, "button_1"), sensitive); XtSetSensitive (XtNameToWidget (file_menu, "button_2"), sensitive); } } void toggle_open_sensitive (Boolean sensitive) { XtSetSensitive (XtNameToWidget (file_menu, "button_0"), sensitive); toggle_openlr_sensitive (sensitive); } static void toggle_saveas_sensitive (Boolean sensitive) { XtSetSensitive (XtNameToWidget (file_menu, "button_3"), sensitive); } /* * return the status of the diff command as the status of this program */ /* ARGSUSED */ static void exit_cb (Widget w, XtPointer closure, XtPointer call_data) { exit ((di != NULL) ? di->status : 2); } /* ARGSUSED2 */ static void Select (Widget widget, XEvent *event, String *params, Cardinal *num_params) { if (event->xany.type == ButtonPress) { Block *b; Dimension ypos, height; int itemp, rect_height; XtVaGetValues (widget, XmNheight, &height, NULL); itemp = newss.sindex; ypos = 0; for (b = newss.b; b != NULL; b = b->next) { if ((rect_height = font_height * (b->ssize - itemp)) > (int) height) rect_height = height; if ((event->xbutton.y >= (unsigned int) ypos) && (event->xbutton.y < (unsigned int) (ypos + rect_height)) && (b->arr[LEFT].type != SAME)) { switch (b->selected) { case LEFT: if (widget == textl) { b->selected = NEITHER; redraw_partial (textl, ypos, rect_height); redraw_partial (textr, ypos, rect_height); update_pixmaps (); } else if (widget == textr) { b->selected = RIGHT; redraw_partial (textl, ypos, rect_height); redraw_partial (textr, ypos, rect_height); update_pixmaps (); } else assert (False); break; case RIGHT: if (widget == textl) { b->selected = LEFT; redraw_partial (textl, ypos, rect_height); redraw_partial (textr, ypos, rect_height); update_pixmaps (); } else if (widget == textr) { b->selected = NEITHER; redraw_partial (textl, ypos, rect_height); redraw_partial (textr, ypos, rect_height); update_pixmaps (); } else assert (False); break; case NEITHER: b->selected = (widget == textl) ? LEFT : RIGHT; redraw_partial (textl, ypos, rect_height); redraw_partial (textr, ypos, rect_height); update_pixmaps (); break; default: assert (False); break; } return; } ypos += rect_height; itemp = 0; if (ypos > height) return; } } } /* * action routine for the text drawing areas: implements the Scrolled * Region recommendations of Section 2.3.4 of the OSF/Motif Style Guide */ static void Scroll (Widget widget, XEvent *event, String *params, Cardinal *num_params) { static char *zero = "0"; static char *one = "1"; if (*num_params == 1) { if (strcmp (params[0], "PageDown") == 0) XtCallActionProc (sb, "PageDownOrRight", event, &zero, (Cardinal) 1); else if (strcmp (params[0], "PageUp") == 0) XtCallActionProc (sb, "PageUpOrLeft", event, &zero, (Cardinal) 1); else if (strcmp (params[0], "Left") == 0) XtCallActionProc (sbh, "IncrementUpOrLeft", event, &one, (Cardinal) 1); else if (strcmp (params[0], "Right") == 0) XtCallActionProc (sbh, "IncrementDownOrRight", event, &one, (Cardinal) 1); else if (strcmp (params[0], "Down") == 0) XtCallActionProc (sb, "IncrementDownOrRight", event, &zero, (Cardinal) 1); else if (strcmp (params[0], "Up") == 0) XtCallActionProc (sb, "IncrementUpOrLeft", event, &zero, (Cardinal) 1); else if (strcmp (params[0], "PageRight") == 0) XtCallActionProc (sbh, "PageDownOrRight", event, &one, (Cardinal) 1); else if (strcmp (params[0], "PageLeft") == 0) XtCallActionProc (sbh, "PageUpOrLeft", event, &one, (Cardinal) 1); else if (strcmp (params[0], "BeginLine") == 0) XtCallActionProc (sbh, "TopOrBottom", event, NULL, (Cardinal) 0); else if (strcmp (params[0], "EndLine") == 0) XtCallActionProc (sbh, "TopOrBottom", event, NULL, (Cardinal) 0); else if (strcmp (params[0], "BeginData") == 0) XtCallActionProc (sb, "TopOrBottom", event, NULL, (Cardinal) 0); else if (strcmp (params[0], "EndData") == 0) XtCallActionProc (sb, "TopOrBottom", event, NULL, (Cardinal) 0); else { char buffer[1024]; (void) sprintf (buffer, "Illegal argument to action proc Scroll (\"%s\")", params[0]); XtAppWarning (XtWidgetToApplicationContext (widget), buffer); } } else { char buffer[1024]; (void) sprintf (buffer, "Illegal number of arguments to action proc Scroll (\"%d\")", *num_params); XtAppWarning (XtWidgetToApplicationContext (widget), buffer); } } /* * return the integer base 10 logarithm of the input, also useful as * the number of decimal digits needed to represent the value */ static int ilog10 (int lines) { int i; for (i = 1; lines >= 10; i++) lines /= 10; return (i); } static void handle_diff_errors (DiffInfo *d) { switch (d->errors) { case 0: break; case 1: werror_long (toplevel, "Diff Error", d->etext, d->errors); break; default: werror_long (toplevel, "Diff Errors", d->etext, d->errors); break; } } static void select_all (Side side) { Block *b; for (b = di->first; b != NULL; b = b->next) if (b->arr[LEFT].type != SAME) b->selected = side; redraw_full (textl); redraw_full (textr); update_pixmaps (); } static void unselect_all (void) { Block *b; for (b = di->first; b != NULL; b = b->next) if (b->arr[LEFT].type != SAME) b->selected = NEITHER; redraw_full (textl); redraw_full (textr); update_pixmaps (); } /* * return True if all blocks have been selected, False otherwise */ static Boolean all_selected (void) { Block *b; for (b = di->first; b != NULL; b = b->next) if ((b->arr[LEFT].type != SAME) && (b->selected == NEITHER)) return (False); return (True); } static Dimension get_preferred_width (Widget w) { XtWidgetGeometry size; size.request_mode = CWWidth; (void) XtQueryGeometry (w, NULL, &size); return (size.width); } /* * delete any prefix ending in '/' and return a copy */ static char *basename (char *path) { if (path) { char *p; /* * find the end of the string */ for (p = path; *p != '\0'; p++) ; /* * search backwards for a '/' or the beginning of the string */ for (; ((*p != '/') && (p > path)); p--) ; /* * return a copy of the piece */ return (strdup ((*p == '/') ? ++p : p)); } else return (NULL); } mgdiff-1.0.orig/mgdiff.cat100644 1751 1751 56373 5566544151 13444 0ustar ugsugs MGDIFF(1) MGDIFF(1) NNAAMMEE mgdiff - Motif-based graphical file difference browser SSYYNNOOPPSSIISS mgdiff [-toolkitoption ...] [-quit] [-file _n_a_m_e] [-args _d_i_f_f_a_r_g_s] [file1 file2] DDEESSCCRRIIPPTTIIOONN _M_g_d_i_f_f is a graphical front end to the _d_i_f_f command. It permits the user to view the differences between two ASCII files in context and, optionally, to write out a third file which is the user-defined merging of those two files. It is inspired by a similar program, called _g_d_i_f_f_, which runs only on Silicon Graphics workstations and for which source code is not provided. The program takes as arguments various flags (described in the next section) and the names of two files to compare. Either filename (but not both) may be given as '-' to use standard input instead. The resulting display consists mostly of two panes of text; the one on the left is the first file specified and the one on the right is the second file specified. Between and below the text panes are scrollbars that per- mit changing the visible portions of the two files being compared. In addition, the program implements the Scrolled Region recommendations of Section 2.3.4 of the OSF/Motif Style Guide (release 1.1), meaning that the arrow and paging keys will work to scroll as well. Above each text pane is the name of the file in that text pane and the line number in the file which is being displayed. The text in each of the text panes is divided into blocks of lines which are color-coded with one of five different colors. This indicates that the block: differs between the two files is identical between the two files has been inserted in one file or the other is for display purposes (to match an inserted block in the other file) has been selected by the user (for writing to a merged file) These colors can be modified by the user via X resources; see the RESOURCES section of this manual page. A legend display of the colors and their meanings is available using the Help menu. 1 MGDIFF(1) MGDIFF(1) On the right-hand side of the display is an overview area; this shows the files in their entirety. The sliders in the overview area track the lines being displayed in the text panes. At the top of the display is a Motif menu bar; those func- tions are discussed in the MENUS section of this manual page. CCOOMMMMAANNDD LLIINNEE OOPPTTIIOONNSS --ttoooollkkiittooppttiioonn These are the standard options accepted by all applications that use the X Toolkit Intrinsics. See the OPTIONS section in the XX(1) manual page. --qquuiitt This option sets the resource _M_g_d_i_f_f_._q_u_i_t_I_f_S_a_m_e to "true". This will cause the program to exit imme- diately without bringing up a window if the two files have no differences (as determined by the _d_i_f_f command). --aarrggss _d_i_f_f_a_r_g_s This option sets the resource _M_g_d_i_f_f_._d_i_f_f_A_r_g_s to the value of the _d_i_f_f_a_r_g_s argument. These flags are passed to the _d_i_f_f command that actually com- putes the differences between the two files. Since any argument can be passed, it is possible to specify flags that cause the _d_i_f_f command to fail or to generate output in a different format that will cause _m_g_d_i_f_f to fail. For most versions of _d_i_f_f_, only three flags make any sense. The first is '-b'; this causes _d_i_f_f to ignore trailing blanks (spaces and tabs) and to treat all other strings of blanks as equivalent. The second flag is '-w'; this ignores blanks and treats strings of blanks as equivalent. The last flag is '-i'; this ignores case when comparing letters. --ffiillee _n_a_m_e This command sets the resource _M_g_d_i_f_f_._f_i_l_e_n_a_m_e to the value of the _n_a_m_e argument. _m_g_d_i_f_f uses this string to display over a file read from standard input. MMEENNUUSS The menubar contains the following menu topics as Cascade- Buttons: FFiillee, VViieeww, SSeelleecctt, OOppttiioonnss and HHeellpp. The rest of this section discusses each menu entry, showing it's name and accelerator, if any. FFiillee 2 MGDIFF(1) MGDIFF(1) This pulldown menu controls file access: OOppeenn...... CCttrrll++OO Brings up the "Open Files" FileSelectionDialog to allow the user to open two files for comparison. OOppeenn LLeefftt...... CCttrrll++LL Brings up the "Open File" FileSelectionDialog to allow the user to specify a file to open and com- pare with the already opened right-hand file. OOppeenn RRiigghhtt...... CCttrrll++RR Brings up the "Open File" FileSelectionDialog to allow the user to specify a file to open and com- pare with the already opened left-hand file. SSaavvee AAss...... CCttrrll++SS Brings up the "Save File" FileSelectionDialog to allow the user to specify an output file for writ- ing the merged file; this is an application modal dialog. The program will allow the user to over- write an existing file but pops up a QuestionDialog to allow the user to cancel the operation if desired. If there are any unselected areas of dif- ference between the two files the user is notified via an ErrorDialog and the save operation is can- celed. EExxiitt CCttrrll++CC Exits the program immediately. VViieeww This pulldown menu contains commands for moving through the files. PPrreevviioouuss CCttrrll++PP Scrolls both file views so that the previous area of difference is _M_g_d_i_f_f_._l_i_n_e_s_O_f_C_o_n_t_e_x_t lines from the top of the application window. NNeexxtt CCttrrll++NN Scrolls both file views so that the next area of difference is _M_g_d_i_f_f_._l_i_n_e_s_O_f_C_o_n_t_e_x_t lines from the top of the application window. 3 MGDIFF(1) MGDIFF(1) NNeexxtt UUnnsseelleecctteedd CCttrrll++UU Scrolls both file views so that the next unselected area of difference is _M_g_d_i_f_f_._l_i_n_e_s_O_f_C_o_n_t_e_x_t lines from the top of the application window. SSeelleecctt The two files being compared can be optionally merged into one file. To do this, the user must select for each area of difference between the two files which version should be written to the merged file. The menu entries in this pulldown menu allow the user to select or unselect differ- ences in groups rather than individually. LLeefftt AAllll For all areas of difference between the two files select the left-hand file version. RRiigghhtt AAllll For all areas of difference between the two files select the right-hand file version. UUnnsseelleecctt AAllll Unselects all areas of difference in both files. OOppttiioonnss This pulldown menu controls miscellaneous appearance and/or behavior options. OOvveerrvviieeww CCttrrll++WW This menu entry toggles the presence of the overview area on the right-hand side of the appli- cation window. The default value for this toggle is controlled by a resource, _M_g_d_i_f_f_._o_v_e_r_v_i_e_w, which is described in the RESOURCES section. HHoorriizzoonnttaall SSccrroollllbbaarr CCttrrll++HH This menu entry toggles the presence of the hori- zontal scrollbar at the bottom of the application window. The default value for this toggle is con- trolled by a resource, _M_g_d_i_f_f_._h_o_r_z_S_c_r_o_l_l_b_a_r, which is described in the RESOURCES section. DDrraagg SSccrroollll CCttrrll++DD 4 MGDIFF(1) MGDIFF(1) This menu entry toggles the behaviour of the scrollbars in the application window. When set, dragging the slider of a scrollbar results in a immediate change in the view of the text being com- pared. When unset, the view is only changed at the end of a slider drag (when the mouse button is released.) This setting might be preferred on a slower X server. The default value for this toggle is controlled by a resource, _M_g_d_i_f_f_._d_r_a_g_S_c_r_o_l_l, which is described in the RESOURCES section. HHeellpp This pulldown menu displays commands for obtaining help on or information about _m_g_d_i_f_f. VVeerrssiioonn...... CCttrrll++VV Brings up an InformationDialog with author and ver- sion information. MMaannuuaall PPaaggee...... CCttrrll++MM Brings up a DialogShell with a ScrolledText widget containing this manual page. The command for gen- erating this is customizable via a resource, _M_g_d_i_f_f_._m_a_n_C_o_m_m_a_n_d, which is described in the RESOURCES section. CCoolloorr LLeeggeenndd...... CCttrrll++GG Brings up a DialogShell which summarizes the use of color in encoding the types of differences between the two files being compared. OOTTHHEERR DDIISSPPLLAAYYSS//CCOONNTTRROOLLSS You can move directly to a particular spot in the two files by using BBDDrraagg in the overview area. The program uses what the OSF/Motif Style Guide calls "multiple selection" to select individual blocks for writ- ing to a merged file. Clicking BBSSeelleecctt on an unselected block adds it to the list of selected blocks. Clicking BBSSeelleecctt on a selected block removes it from the list of selected blocks. In addition, Clicking BBSSeelleecctt on an uns- elected block which is opposite a selected block (in the other text panes) removes the selected block from the list of selected blocks. The numbers in the small boxes next to the file names are the line numbers of the lines at the top of the text panes. 5 MGDIFF(1) MGDIFF(1) WWIIDDGGEETTSS What follows is the hierarchy of Motif widgets, as gener- ated by eeddiittrreess(1). The hierarchical structure of the widget tree is reflected in the indentation. Each line consists of the widget class name followed by the widget instance name. This information might be useful if you wish to customize the appearance of the program via resource settings. Mgdiff mgdiff XmMainWindow mainw XmSeparatorGadget MainWinSep1 XmSeparatorGadget MainWinSep2 XmSeparatorGadget MainWinSep3 XmRowColumn menubar XmCascadeButtonGadget button_0 XmCascadeButtonGadget button_1 XmCascadeButtonGadget button_2 XmCascadeButtonGadget button_3 XmCascadeButtonGadget button_4 XmMenuShell popup_file_menu XmRowColumn select_menu XmPushButtonGadget button_0 XmPushButtonGadget button_1 XmSeparatorGadget separator_0 XmPushButtonGadget button_2 XmRowColumn file_menu XmPushButtonGadget button_0 XmPushButtonGadget button_1 XmPushButtonGadget button_2 XmPushButtonGadget button_3 XmSeparatorGadget separator_0 XmPushButtonGadget button_4 XmRowColumn options_menu XmToggleButtonGadget button_0 XmToggleButtonGadget button_1 XmToggleButtonGadget button_2 XmRowColumn help_menu XmPushButtonGadget button_0 XmPushButtonGadget button_1 XmPushButtonGadget button_2 XmRowColumn view_menu XmPushButtonGadget button_0 XmPushButtonGadget button_1 XmPushButtonGadget button_2 XmForm form1 XmFrame frame1 XmForm form3 XmScrollBar sbl XmDrawingArea dam XmScrollBar sbr XmFrame frame2 XmForm form4 XmForm form2 6 MGDIFF(1) MGDIFF(1) XmScrollBar sb XmForm form21 XmFrame frame3 XmLabel fnamel XmFrame frame31 XmTextField linenuml XmForm form22 XmFrame frame4 XmLabel fnamer XmFrame frame41 XmTextField linenumr XmDrawingArea textl XmDrawingArea textr XmScrollBar sbh XmDialogShell version_popup XmMessageBox version XmLabelGadget symbol XmLabelGadget XmSeparatorGadget separator XmPushButtonGadget OK XmPushButtonGadget Cancel XmPushButtonGadget Help XmDialogShell manualpage_popup XmForm manualpage XmPanedWindow pane XmScrolledWindow help_textSW XmScrollBar vbar XmText help_text XmForm form2a XmPushButton OK XmSash sash XmSeparatorGadget separator XmSash sash XmSeparatorGadget separator XmDialogShell legend_popup XmForm legend XmPanedWindow pane XmRowColumn rc XmLabel label1 XmLabel label2 XmLabel label3 XmLabel label4 XmLabel label5 XmForm form2a XmPushButton OK XmSash sash XmSeparatorGadget separator XmSash sash XmSeparatorGadget separator XmDialogShell werror_popup XmMessageBox werror XmLabelGadget symbol XmLabelGadget XmSeparatorGadget separator 7 MGDIFF(1) MGDIFF(1) XmPushButtonGadget OK XmPushButtonGadget Cancel XmPushButtonGadget Help XX RREESSOOUURRCCEESS MMggddiiffff..ddiiffffFFoorreeggrroouunndd:: bbllaacckk MMggddiiffff..ddiiffffBBaacckkggrroouunndd:: yyeellllooww These colors are for blocks which differ between files. MMggddiiffff..ssaammeeFFoorreeggrroouunndd:: bbllaacckk MMggddiiffff..ssaammeeBBaacckkggrroouunndd:: ggrreeyy These colors are for blocks which are identical between files. MMggddiiffff..iinnsseerrttFFoorreeggrroouunndd:: bbllaacckk MMggddiiffff..iinnsseerrttBBaacckkggrroouunndd:: oorraannggee These colors are for blocks which have been inserted in one file. MMggddiiffff..bbllaannkkFFoorreeggrroouunndd:: bbllaacckk MMggddiiffff..bbllaannkkBBaacckkggrroouunndd:: ggrreeyy6666 These colors are for blocks which are for display pur- poses. MMggddiiffff..sseelleeccttFFoorreeggrroouunndd:: bbllaacckk MMggddiiffff..sseelleeccttBBaacckkggrroouunndd:: lliigghhtt ssllaattee bblluuee These colors are for blocks which have been selected by the user. MMggddiiffff..ffoonntt:: 77xx1133bboolldd Font for displaying text blocks. MMggddiiffff..ddrraaggSSccrroollll:: ttrruuee Set to true if scrollbar dragging should cause immediate changes in the viewed text, and false if the view should 8 MGDIFF(1) MGDIFF(1) only change after the scrollbar has been moved. MMggddiiffff..oovveerrvviieeww:: ttrruuee Set to true if the file overview section should appear. MMggddiiffff..hhoorrzzSSccrroollllbbaarr:: ttrruuee Set to true if the horizontal scrollbar should appear. MMggddiiffff..lliinneessOOffCCoonntteexxtt:: 33 Number of lines that should appear above a difference block gotten to using the Previous or Next commands. Should be greater or equal to zero. MMggddiiffff..mmaannCCoommmmaanndd:: ((mmaann mmggddiiffff || ccooll --bb)) 22>>&&11 The command (or pipeline) used to produce a formatted man- ual page without escape codes. MMggddiiffff..ddiiffffCCoommmmaanndd:: ddiiffff The ddiiffff(1) compatible command to use for calculating dif- ferences between text files. MMggddiiffff..ddiiffffAArrggss:: The arguments to be provided to the _d_i_f_f command. This resource can also be set via the _-_a_r_g_s command line option. MMggddiiffff..qquuiittIIffSSaammee:: ffaallssee If the two files have no differences (as determined by the _d_i_f_f command) then exit immediately without bringing up a window. This resource can also be set to "true" via the _-_q_u_i_t command line option. MMggddiiffff..ffiilleennaammee:: ((ssttddiinn)) _m_g_d_i_f_f uses this string to display over a file read from standard input. This resource can also be set via the _-_f_i_l_e command line option. 9 MGDIFF(1) MGDIFF(1) DDIIAAGGNNOOSSTTIICCSS Returns the exit status generated by the _d_i_f_f command. This is usually 0 for no differences, 1 for some differ- ences and 2 for errors. SSEEEE AALLSSOO ddiiffff(1), XX(1) RREESSTTRRIICCTTIIOONNSS Using BBDDrraagg in the overview area doesn't work well when drag scrolling is turned off. Doesn't support monochrome displays. Input lines longer than BUFSIZ (see /usr/include/stdio.h) are silently truncated. The code for parsing and passing arguments to the _d_i_f_f command assumes arguments are delimited by white space and does not do any quote processing. CCOOPPYYRRIIGGHHTT Copyright (c) 1994, Daniel Williams See XX ((11)) for a full statement of rights and permissions. AAUUTTHHOORR Daniel Williams (dan@sass.com) AACCKKNNOOWWLLEEDDGGEEMMEENNTTSS To Andrew C. Myers for writing _g_d_i_f_f_. 10 mgdiff-1.0.orig/mgdiff.h100644 1751 1751 6531 5566544153 13075 0ustar ugsugs#ifndef MXDIFF_H #define MXDIFF_H #ifndef lint static char rcsid_mgdiff_h[] = "mgdiff.h,v 2.0 1994/05/19 02:01:15 dan Exp"; #endif /* * Copyright (c) 1994 Daniel Williams * * The X Consortium, and any party obtaining a copy of these files from * the X Consortium, directly or indirectly, is granted, free of charge, * a full and unrestricted irrevocable, world-wide, paid up, * royalty-free, nonexclusive right and license to deal in this software * and documentation files (the "Software"), including without limitation * the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons * who receive copies from any such party to do so. This license * includes without limitation a license to do the foregoing actions * under any patents of the party supplying this software to the X * Consortium. The following conditions apply: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL DANIEL WILLIAMS OR SYSTEMS & SCIENTIFIC SOFTWARE BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * these are the types of each chunk as identified by the difference * algorithm and map to different colors for display purposes. */ typedef enum {DIFF = 0, SAME, INSERT, BLANK} ChunkType; /* * each file compared is broken up into a list of chunks, which are * the smallest set of contiguous lines identified by the difference * algorithm. */ typedef struct { ChunkType type; /* what kind of chunk is this? */ int fline; /* file address (linenumber) */ int fsize; /* number of lines in file */ char **text; /* the text to display */ char **wtext; /* the text to write */ short *tlen; /* the lengths of each line */ } Chunk; typedef enum {LEFT = 0, RIGHT, NEITHER} Side; /* * a block is an element of a doubly linked list containing a left chunk * and a right chunk */ typedef struct block { struct block *prev, *next; Side selected; /* which chunk of the Block is selected */ int sline; /* screen address (linenumber) */ int ssize; /* number of lines on screen */ Chunk arr[2]; /* left and right Chunks */ } Block; /* * the results of a file comparison */ typedef struct { int status; /* return value from diff */ char **etext; /* any error text from diff */ int errors; /* number of lines of error text */ int lines; /* total number of screen lines */ int maxcols; /* maximum length of any text line */ char *longline; /* longest string of characters to be rendered */ int flines[2]; /* total number of file lines for each file */ Block *first; /* the first block in the block list */ Block *last; /* the last block in the block list */ } DiffInfo; /* * True if we are compiling under Release 5 or above of the Intrinsics */ #define X11R5 (defined(XtSpecificationRelease) && (XtSpecificationRelease >= 5)) #endif mgdiff-1.0.orig/mgdiff.man100644 1751 1751 41373 5566544154 13445 0ustar ugsugs.\" mgdiff.man,v 2.0 1994/05/19 02:01:16 dan Exp .\" .\" Copyright (c) 1994 Daniel Williams .\" .\" The X Consortium, and any party obtaining a copy of these files from .\" the X Consortium, directly or indirectly, is granted, free of charge, .\" a full and unrestricted irrevocable, world-wide, paid up, .\" royalty-free, nonexclusive right and license to deal in this software .\" and documentation files (the "Software"), including without limitation .\" the rights to use, copy, modify, merge, publish, distribute, .\" sublicense, and/or sell copies of the Software, and to permit persons .\" who receive copies from any such party to do so. This license .\" includes without limitation a license to do the foregoing actions .\" under any patents of the party supplying this software to the X .\" Consortium. The following conditions apply: .\" .\" The above copyright notice and this permission notice shall be .\" included in all copies or substantial portions of the Software. .\" .\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, .\" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF .\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. .\" IN NO EVENT SHALL DANIEL WILLIAMS OR SYSTEMS & SCIENTIFIC SOFTWARE BE .\" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION .\" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION .\" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .\" .na .TH MGDIFF 1 .SH NAME mgdiff \- Motif-based graphical file difference browser .SH SYNOPSIS mgdiff [\-toolkitoption ...] [\-quit] [\-file \fIname\fP] [\-args \fIdiffargs\fP] [file1 file2] .SH DESCRIPTION .LP .I Mgdiff is a graphical front end to the .I diff command. It permits the user to view the differences between two ASCII files in context and, optionally, to write out a third file which is the user-defined merging of those two files. It is inspired by a similar program, called .I gdiff, which runs only on Silicon Graphics workstations and for which source code is not provided. .LP The program takes as arguments various flags (described in the next section) and the names of two files to compare. Either filename (but not both) may be given as '-' to use standard input instead. .LP The resulting display consists mostly of two panes of text; the one on the left is the first file specified and the one on the right is the second file specified. Between and below the text panes are scrollbars that permit changing the visible portions of the two files being compared. In addition, the program implements the Scrolled Region recommendations of Section 2.3.4 of the OSF/Motif Style Guide (release 1.1), meaning that the arrow and paging keys will work to scroll as well. Above each text pane is the name of the file in that text pane and the line number in the file which is being displayed. .LP The text in each of the text panes is divided into blocks of lines which are color\-coded with one of five different colors. This indicates that the block: .IP differs between the two files .IP is identical between the two files .IP has been inserted in one file or the other .IP is for display purposes (to match an inserted block in the other file) .IP has been selected by the user (for writing to a merged file) .LP These colors can be modified by the user via X resources; see the RESOURCES section of this manual page. A legend display of the colors and their meanings is available using the Help menu. .LP On the right\-hand side of the display is an overview area; this shows the files in their entirety. The sliders in the overview area track the lines being displayed in the text panes. .LP At the top of the display is a Motif menu bar; those functions are discussed in the MENUS section of this manual page. .SH COMMAND LINE OPTIONS .TP 8 .B \-toolkitoption These are the standard options accepted by all applications that use the X Toolkit Intrinsics. See the OPTIONS section in the .BR X (1) manual page. .TP 8 .B \-quit This option sets the resource .I Mgdiff.quitIfSame to "true". This will cause the program to exit immediately without bringing up a window if the two files have no differences (as determined by the .I diff command). .TP 8 \fB\-args\fP \fIdiffargs\fP This option sets the resource .I Mgdiff.diffArgs to the value of the .IR diffargs argument. These flags are passed to the .I diff command that actually computes the differences between the two files. Since any argument can be passed, it is possible to specify flags that cause the .I diff command to fail or to generate output in a different format that will cause .I mgdiff to fail. For most versions of .I diff, only three flags make any sense. The first is '\-b'; this causes .I diff to ignore trailing blanks (spaces and tabs) and to treat all other strings of blanks as equivalent. The second flag is '\-w'; this ignores blanks and treats strings of blanks as equivalent. The last flag is '\-i'; this ignores case when comparing letters. .TP 8 \fB\-file\fP \fIname\fP This command sets the resource .I Mgdiff.filename to the value of the .IR name argument. .I mgdiff uses this string to display over a file read from standard input. .nr XX 4 .nr XY 18 .SH MENUS The menubar contains the following menu topics as CascadeButtons: \fBFile\fP, \fBView\fP, \fBSelect\fP, \fBOptions\fP and \fBHelp\fP. The rest of this section discusses each menu entry, showing it's name and accelerator, if any. .IP "\fBFile\fP" .LP This pulldown menu controls file access: .RS \n(XXP .IP "\fBOpen...\fP" \n(XYP .B Ctrl+O .LP Brings up the "Open Files" FileSelectionDialog to allow the user to open two files for comparison. .IP "\fBOpen Left...\fP" \n(XYP .B Ctrl+L .LP Brings up the "Open File" FileSelectionDialog to allow the user to specify a file to open and compare with the already opened right\-hand file. .IP "\fBOpen Right...\fP" \n(XYP .B Ctrl+R .LP Brings up the "Open File" FileSelectionDialog to allow the user to specify a file to open and compare with the already opened left\-hand file. .IP "\fBSave As...\fP" \n(XYP .B Ctrl+S .LP Brings up the "Save File" FileSelectionDialog to allow the user to specify an output file for writing the merged file; this is an application modal dialog. The program will allow the user to overwrite an existing file but pops up a QuestionDialog to allow the user to cancel the operation if desired. If there are any unselected areas of difference between the two files the user is notified via an ErrorDialog and the save operation is canceled. .IP "\fBExit\fP" \n(XYP .B Ctrl+C .LP Exits the program immediately. .RE .IP "\fBView\fP" .LP This pulldown menu contains commands for moving through the files. .RS \n(XXP .IP "\fBPrevious\fP" \n(XYP .B Ctrl+P .LP Scrolls both file views so that the previous area of difference is .I Mgdiff.linesOfContext lines from the top of the application window. .IP "\fBNext\fP" \n(XYP .B Ctrl+N .LP Scrolls both file views so that the next area of difference is .I Mgdiff.linesOfContext lines from the top of the application window. .IP "\fBNext Unselected\fP" \n(XYP .B Ctrl+U .LP Scrolls both file views so that the next unselected area of difference is .I Mgdiff.linesOfContext lines from the top of the application window. .RE .IP "\fBSelect\fP" .LP The two files being compared can be optionally merged into one file. To do this, the user must select for each area of difference between the two files which version should be written to the merged file. The menu entries in this pulldown menu allow the user to select or unselect differences in groups rather than individually. .RS \n(XXP .IP "\fBLeft All\fP" \n(XYP .LP For all areas of difference between the two files select the left\-hand file version. .IP "\fBRight All\fP" \n(XYP .LP For all areas of difference between the two files select the right\-hand file version. .IP "\fBUnselect All\fP" \n(XYP .LP Unselects all areas of difference in both files. .RE .IP "\fBOptions\fP" .LP This pulldown menu controls miscellaneous appearance and/or behavior options. .RS \n(XXP .IP "\fBOverview\fP" \n(XYP .B Ctrl+W .LP This menu entry toggles the presence of the overview area on the right\-hand side of the application window. The default value for this toggle is controlled by a resource, .IR Mgdiff.overview , which is described in the RESOURCES section. .IP "\fBHorizontal Scrollbar\fP" \n(XYP .B Ctrl+H .LP This menu entry toggles the presence of the horizontal scrollbar at the bottom of the application window. The default value for this toggle is controlled by a resource, .IR Mgdiff.horzScrollbar , which is described in the RESOURCES section. .IP "\fBDrag Scroll\fP" \n(XYP .B Ctrl+D .LP This menu entry toggles the behaviour of the scrollbars in the application window. When set, dragging the slider of a scrollbar results in a immediate change in the view of the text being compared. When unset, the view is only changed at the end of a slider drag (when the mouse button is released.) This setting might be preferred on a slower X server. The default value for this toggle is controlled by a resource, .IR Mgdiff.dragScroll , which is described in the RESOURCES section. .RE .IP "\fBHelp\fP" .LP This pulldown menu displays commands for obtaining help on or information about .IR mgdiff . .RS \n(XXP .IP "\fBVersion...\fP" \n(XYP .B Ctrl+V .LP Brings up an InformationDialog with author and version information. .IP "\fBManual Page...\fP" \n(XYP .B Ctrl+M .LP Brings up a DialogShell with a ScrolledText widget containing this manual page. The command for generating this is customizable via a resource, .IR Mgdiff.manCommand , which is described in the RESOURCES section. .IP "\fBColor Legend...\fP" \n(XYP .B Ctrl+G .LP Brings up a DialogShell which summarizes the use of color in encoding the types of differences between the two files being compared. .RE .SH OTHER DISPLAYS/CONTROLS .LP You can move directly to a particular spot in the two files by using \fBBDrag\fP in the overview area. .LP The program uses what the OSF/Motif Style Guide calls "multiple selection" to select individual blocks for writing to a merged file. Clicking \fBBSelect\fP on an unselected block adds it to the list of selected blocks. Clicking \fBBSelect\fP on a selected block removes it from the list of selected blocks. In addition, Clicking \fBBSelect\fP on an unselected block which is opposite a selected block (in the other text panes) removes the selected block from the list of selected blocks. .LP The numbers in the small boxes next to the file names are the line numbers of the lines at the top of the text panes. .SH WIDGETS What follows is the hierarchy of Motif widgets, as generated by .BR editres (1). The hierarchical structure of the widget tree is reflected in the indentation. Each line consists of the widget class name followed by the widget instance name. This information might be useful if you wish to customize the appearance of the program via resource settings. .nf .DT Mgdiff mgdiff XmMainWindow mainw XmSeparatorGadget MainWinSep1 XmSeparatorGadget MainWinSep2 XmSeparatorGadget MainWinSep3 XmRowColumn menubar XmCascadeButtonGadget button_0 XmCascadeButtonGadget button_1 XmCascadeButtonGadget button_2 XmCascadeButtonGadget button_3 XmCascadeButtonGadget button_4 XmMenuShell popup_file_menu XmRowColumn select_menu XmPushButtonGadget button_0 XmPushButtonGadget button_1 XmSeparatorGadget separator_0 XmPushButtonGadget button_2 XmRowColumn file_menu XmPushButtonGadget button_0 XmPushButtonGadget button_1 XmPushButtonGadget button_2 XmPushButtonGadget button_3 XmSeparatorGadget separator_0 XmPushButtonGadget button_4 XmRowColumn options_menu XmToggleButtonGadget button_0 XmToggleButtonGadget button_1 XmToggleButtonGadget button_2 XmRowColumn help_menu XmPushButtonGadget button_0 XmPushButtonGadget button_1 XmPushButtonGadget button_2 XmRowColumn view_menu XmPushButtonGadget button_0 XmPushButtonGadget button_1 XmPushButtonGadget button_2 XmForm form1 XmFrame frame1 XmForm form3 XmScrollBar sbl XmDrawingArea dam XmScrollBar sbr XmFrame frame2 XmForm form4 XmForm form2 XmScrollBar sb XmForm form21 XmFrame frame3 XmLabel fnamel XmFrame frame31 XmTextField linenuml XmForm form22 XmFrame frame4 XmLabel fnamer XmFrame frame41 XmTextField linenumr XmDrawingArea textl XmDrawingArea textr XmScrollBar sbh XmDialogShell version_popup XmMessageBox version XmLabelGadget symbol XmLabelGadget XmSeparatorGadget separator XmPushButtonGadget OK XmPushButtonGadget Cancel XmPushButtonGadget Help XmDialogShell manualpage_popup XmForm manualpage XmPanedWindow pane XmScrolledWindow help_textSW XmScrollBar vbar XmText help_text XmForm form2a XmPushButton OK XmSash sash XmSeparatorGadget separator XmSash sash XmSeparatorGadget separator XmDialogShell legend_popup XmForm legend XmPanedWindow pane XmRowColumn rc XmLabel label1 XmLabel label2 XmLabel label3 XmLabel label4 XmLabel label5 XmForm form2a XmPushButton OK XmSash sash XmSeparatorGadget separator XmSash sash XmSeparatorGadget separator XmDialogShell werror_popup XmMessageBox werror XmLabelGadget symbol XmLabelGadget XmSeparatorGadget separator XmPushButtonGadget OK XmPushButtonGadget Cancel XmPushButtonGadget Help .fi .nr XY 15 .SH X RESOURCES .IP "\fBMgdiff.diffForeground:\fP" \n(XYP .B black .IP "\fBMgdiff.diffBackground:\fP" \n(XYP .B yellow .LP These colors are for blocks which differ between files. .IP "\fBMgdiff.sameForeground:\fP" \n(XYP .B black .IP "\fBMgdiff.sameBackground:\fP" \n(XYP .B grey .LP These colors are for blocks which are identical between files. .IP "\fBMgdiff.insertForeground:\fP" \n(XYP .B black .IP "\fBMgdiff.insertBackground:\fP" \n(XYP .B orange .LP These colors are for blocks which have been inserted in one file. .IP "\fBMgdiff.blankForeground:\fP" \n(XYP .B black .IP "\fBMgdiff.blankBackground:\fP" \n(XYP .B grey66 .LP These colors are for blocks which are for display purposes. .IP "\fBMgdiff.selectForeground:\fP" \n(XYP .B black .IP "\fBMgdiff.selectBackground:\fP" \n(XYP .B light slate blue .LP These colors are for blocks which have been selected by the user. .IP "\fBMgdiff.font:\fP" \n(XYP .B 7x13bold .LP Font for displaying text blocks. .IP "\fBMgdiff.dragScroll:\fP" \n(XYP .B true .LP Set to true if scrollbar dragging should cause immediate changes in the viewed text, and false if the view should only change after the scrollbar has been moved. .IP "\fBMgdiff.overview:\fP" \n(XYP .B true .LP Set to true if the file overview section should appear. .IP "\fBMgdiff.horzScrollbar:\fP" \n(XYP .B true .LP Set to true if the horizontal scrollbar should appear. .IP "\fBMgdiff.linesOfContext:\fP" \n(XYP .B 3 .LP Number of lines that should appear above a difference block gotten to using the Previous or Next commands. Should be greater or equal to zero. .IP "\fBMgdiff.manCommand:\fP" \n(XYP .B (man mgdiff | col -b) 2>&1 .LP The command (or pipeline) used to produce a formatted manual page without escape codes. .IP "\fBMgdiff.diffCommand:\fP" \n(XYP .B diff .LP The .BR diff (1) compatible command to use for calculating differences between text files. .IP "\fBMgdiff.diffArgs:\fP" \n(XYP .B "" .LP The arguments to be provided to the .I diff command. This resource can also be set via the .I \-args command line option. .IP "\fBMgdiff.quitIfSame:\fP" \n(XYP .B false .LP If the two files have no differences (as determined by the .I diff command) then exit immediately without bringing up a window. This resource can also be set to "true" via the .I \-quit command line option. .IP "\fBMgdiff.filename:\fP" \n(XYP .B (stdin) .LP .I mgdiff uses this string to display over a file read from standard input. This resource can also be set via the .I \-file command line option. .SH DIAGNOSTICS Returns the exit status generated by the .I diff command. This is usually 0 for no differences, 1 for some differences and 2 for errors. .SH SEE ALSO .BR diff (1), .BR X (1) .SH RESTRICTIONS .LP Using \fBBDrag\fP in the overview area doesn't work well when drag scrolling is turned off. .LP Doesn't support monochrome displays. .LP Input lines longer than BUFSIZ (see /usr/include/stdio.h) are silently truncated. .LP The code for parsing and passing arguments to the .I diff command assumes arguments are delimited by white space and does not do any quote processing. .SH COPYRIGHT Copyright (c) 1994, Daniel Williams .br See .B X (1) for a full statement of rights and permissions. .SH AUTHOR Daniel Williams (dan@sass.com) .SH ACKNOWLEDGEMENTS To Andrew C. Myers for writing .I gdiff. mgdiff-1.0.orig/mgdiff.xbm100644 1751 1751 4347 5566544155 13441 0ustar ugsugs#define mgdiff_width 50 #define mgdiff_height 50 static unsigned char mgdiff_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x18, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x18, 0x0c, 0x04, 0x00, 0x37, 0x00, 0x00, 0xc6, 0x83, 0x87, 0xff, 0x19, 0x07, 0x00, 0x20, 0x78, 0xfc, 0x60, 0xff, 0x01, 0x00, 0x18, 0xcf, 0x03, 0x90, 0xd9, 0x79, 0x00, 0x8c, 0x31, 0xf8, 0xff, 0x0f, 0x0f, 0x00, 0x66, 0x0c, 0xfe, 0xff, 0xdf, 0x07, 0x00, 0x32, 0xc7, 0xff, 0xff, 0x7f, 0x18, 0x00, 0xd9, 0xf1, 0xff, 0xff, 0xff, 0x10, 0x00, 0x64, 0xf8, 0x7f, 0xbf, 0xf6, 0x60, 0x00, 0x10, 0xfe, 0xd7, 0x55, 0xc5, 0x41, 0x00, 0x08, 0x7f, 0xb6, 0xaf, 0xaa, 0x03, 0x00, 0x84, 0x87, 0xea, 0x5f, 0x3d, 0x0f, 0x00, 0xc2, 0x29, 0xbe, 0xbf, 0xca, 0x1f, 0x00, 0xe2, 0xa2, 0xd6, 0x7f, 0x2d, 0x3e, 0x00, 0x7f, 0x08, 0xba, 0xbf, 0xda, 0x7d, 0x00, 0x3f, 0x81, 0x5a, 0x1f, 0x0d, 0xe2, 0x03, 0x3f, 0x2c, 0xbe, 0x4e, 0xca, 0xb9, 0x03, 0x9f, 0x82, 0x54, 0x65, 0x05, 0xe9, 0x00, 0x34, 0x2a, 0xac, 0xaa, 0x86, 0x6c, 0x03, 0xb4, 0x40, 0x59, 0x55, 0x03, 0xae, 0x00, 0x5c, 0x2c, 0xb4, 0xaa, 0x01, 0x53, 0x00, 0xf8, 0x51, 0x61, 0xd5, 0x80, 0x3d, 0x00, 0x50, 0x0f, 0x94, 0x3f, 0x80, 0x68, 0x00, 0x60, 0x9d, 0x15, 0x00, 0x60, 0x8c, 0x00, 0xc0, 0xf2, 0x01, 0x00, 0xbc, 0x87, 0x00, 0x00, 0xaf, 0xff, 0xff, 0x03, 0x0e, 0x00, 0x00, 0x7c, 0x01, 0x00, 0xf0, 0x19, 0x00, 0x00, 0xc0, 0x03, 0x00, 0xfc, 0x30, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x97, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x44, 0x48, 0x24, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x80, 0x67, 0x08, 0x04, 0x00, 0x00, 0x00, 0x40, 0x44, 0x3c, 0x1e, 0x00, 0x00, 0x00, 0x40, 0x44, 0x08, 0x04, 0x00, 0x00, 0x00, 0x40, 0x44, 0x08, 0x04, 0x00, 0x00, 0x00, 0x40, 0x44, 0x08, 0x04, 0x00, 0x00, 0x00, 0x80, 0xe7, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; mgdiff-1.0.orig/mgdiff.xpm100644 1751 1751 5360 5566544156 13454 0ustar ugsugs/* XPM */ static char * mgdiff_xpm[] = { "50 50 3 1", " s None c None", ". c black", "X c white", " ", " ", " ", " ", " .. .. ", " ............ .. ", " .. .. ... ", " .. .. . ... .. ", " .. .... .... .......... .. ... ", " . .... ...... .. ......... ", " .. .... .... . .. .. ... .... ", " .. .. .. ................. .... ", " .. .. .. .................... ..... ", " . .. ... ......................... .. ", ". ..X... ............................ . ", " . .. ............X......X.X..X.... .. ", " . ..........X.X...X.X.X.X.X.XXX... . ", " . .......XX..X..X.....X.X.X.X.X.X... ", " . ....XXXX.X.X.X........X.X.X....XX.... ", " . ...XX.X.XXX.....X.......X.X.X.XX....... ", " . ...X.XXX.X.X..X.X.........X.X..X.XXX..... ", ".......XXXX.XXXXX.X...X.......X.X.X..X...X..... ", "......XX.XXXXXX.X.X..X.X.....XXX.X..XXXXX.XXX.....", "......XXXX..X.XXX.....X.X...XX.XX.X.XX...XX...X...", ".....XX.X.XXXXX.XX.X.X.X.X.XX..X.X.XXXXX.XX.X...XX", " .X..XXX.X.X.XXXX..X.X.X.X.X.X.X..XXXX.XX..X..X..", " .X..X.XXXXXX.X.XX..X.X.X.X.X.X..XXXXXXX...X.X. ", " ...X.XXX..X.XXXX.X..X.X.X.X.X..XXXXXXX..XX.X. ", " ......XXX.X.X.XXXX..X.X.X.X..XXXXXXX..X.... ", " .X.X....XXXXXX.X.XX.......XXXXXXXXX.XXX. .. ", " ..X.X...XX..X.X.XXXXXXXXXXXXXXXX..XXX.. . ", " ..X.XX.....XXXXXXXXXXXXXXXXX....X.... . ", " ....X.X...................XXXXXXX... ", " .....X.XXXXXXXXXXXXXXXXXXX..... .. ", " ....XXXXXXXXXXXXXXXX...... .. ", " ....XXXXXXXXXXX... . .. ", " ............ . .. ", " .. ", " . ", " . .. .. ", " . . . . . . ", " . . . ", " .... .. . . ", " . . . .... .... ", " . . . . . ", " . . . . . ", " . . . . . ", " .... ... . . ", " ", " "}; mgdiff-1.0.orig/misc.c100644 1751 1751 7136 5566544157 12575 0ustar ugsugs#ifndef lint static char rcsid[] = "misc.c,v 2.0 1994/05/19 02:01:19 dan Exp"; #endif /* * Copyright (c) 1994 Daniel Williams * * The X Consortium, and any party obtaining a copy of these files from * the X Consortium, directly or indirectly, is granted, free of charge, * a full and unrestricted irrevocable, world-wide, paid up, * royalty-free, nonexclusive right and license to deal in this software * and documentation files (the "Software"), including without limitation * the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons * who receive copies from any such party to do so. This license * includes without limitation a license to do the foregoing actions * under any patents of the party supplying this software to the X * Consortium. The following conditions apply: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL DANIEL WILLIAMS OR SYSTEMS & SCIENTIFIC SOFTWARE BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include "mgdiff.h" int max (int i, int j) { return ((i > j) ? i : j); } int min (int i, int j) { return ((i < j) ? i : j); } /* * copy a stream up to the EOF to a file */ int copy_to_file (FILE *fin, char *name) { FILE *fout; if ((fout = fopen (name, "a")) == NULL) return (0); while (!feof (fin)) { char buffer[BUFSIZ]; int nitems; nitems = fread (buffer, 1, BUFSIZ, fin); if (fwrite (buffer, 1, nitems, fout) != nitems) break; } if (ferror (fin) || ferror (fout)) { (void) fclose (fout); return (1); } return ((fclose (fout) == 0)); } void set_cursor (Widget w) { static Cursor watch = 0; if (!watch) watch = XCreateFontCursor (XtDisplay (w), XC_watch); XDefineCursor (XtDisplay (w), XtWindow (w), watch); XmUpdateDisplay (w); } void reset_cursor (Widget w) { XUndefineCursor (XtDisplay (w), XtWindow (w)); XmUpdateDisplay (w); } /* * traverse up to the top shell */ Widget get_top_shell (Widget w) { while (w && !XtIsWMShell (w)) w = XtParent (w); return (w); } #if sun char *strerror (int errnum) { extern int sys_nerr; extern char *sys_errlist[]; if ((0 < errnum) && (errnum < sys_nerr)) return (sys_errlist[errnum]); else return (""); } #endif void add_editres (Widget shell) { #if EDITRES && X11R5 extern void _XEditResCheckMessages (Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch); XtAddEventHandler (shell, (EventMask) 0, True, _XEditResCheckMessages, NULL); #endif } /* * from Heller's Motif Programming Manual; eliminate the ability to * traverse to a PanedWindow's sashes. */ void turn_off_sash_traversal (Widget pane) { WidgetList children; int num_children; XtVaGetValues (pane, XmNchildren, &children, XmNnumChildren, &num_children, NULL); while (num_children-- > 0) if (XmIsSash (children[num_children])) XtVaSetValues (children[num_children], XmNtraversalOn, False, NULL); } mgdiff-1.0.orig/modal.c100644 1751 1751 6625 5566544160 12732 0ustar ugsugs#ifndef lint static char rcsid[] = "modal.c,v 2.0 1994/05/19 02:01:20 dan Exp"; #endif /* * Copyright (c) 1994 Daniel Williams * * The X Consortium, and any party obtaining a copy of these files from * the X Consortium, directly or indirectly, is granted, free of charge, * a full and unrestricted irrevocable, world-wide, paid up, * royalty-free, nonexclusive right and license to deal in this software * and documentation files (the "Software"), including without limitation * the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons * who receive copies from any such party to do so. This license * includes without limitation a license to do the foregoing actions * under any patents of the party supplying this software to the X * Consortium. The following conditions apply: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL DANIEL WILLIAMS OR SYSTEMS & SCIENTIFIC SOFTWARE BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * this module is derived from code in "Motif Programming Manual" * which bears the following notice: * * Written by Dan Heller. Copyright 1991, O'Reilly & Associates. * This program is freely distributable without licensing fees and * is provided without guarantee or warrantee expressed or implied. * This program is -not- in the public domain. */ #include #include #include "mgdiff.h" #include "externs.h" static void ok_cb (Widget w, XtPointer closure, XtPointer call_data); static void cancel_cb (Widget w, XtPointer closure, XtPointer call_data); typedef enum { Busy, Ok, Cancel } State; /* ARGSUSED */ static void ok_cb (Widget w, XtPointer closure, XtPointer call_data) { *((State *) closure) = Ok; XtDestroyWidget (get_top_shell (w)); } /* ARGSUSED */ static void cancel_cb (Widget w, XtPointer closure, XtPointer call_data) { *((State *) closure) = Cancel; XtDestroyWidget (get_top_shell (w)); } /* * pop up a modal QuestionDialog and return True for user's choice of * "OK" and False for "Cancel" */ int modal_question (Widget parent, char *title, char *question) { static Arg args[] = {{XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL}}; XtAppContext app = XtWidgetToApplicationContext (parent); State answer = Busy; Widget dialog; dialog = XmCreateQuestionDialog (parent, "question", args, XtNumber (args)); XtAddCallback (dialog, XmNokCallback, ok_cb, &answer); XtAddCallback (dialog, XmNcancelCallback, cancel_cb, &answer); XtVaSetValues (dialog, XtVaTypedArg, XmNmessageString, XmRString, question, strlen (question)+1, XtVaTypedArg, XmNdialogTitle, XmRString, title, strlen (title)+1, NULL); XtSetSensitive (XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON), False); XtManageChild (dialog); while ((answer == Busy) || XtAppPending (app)) XtAppProcessEvent (app, XtIMAll); return (answer == Ok); } mgdiff-1.0.orig/patchlevel.h100644 1751 1751 3145 5566544161 13765 0ustar ugsugs#ifndef PATCHLEVEL_H #define PATCHLEVEL_H /* * Copyright (c) 1994 Daniel Williams * * The X Consortium, and any party obtaining a copy of these files from * the X Consortium, directly or indirectly, is granted, free of charge, * a full and unrestricted irrevocable, world-wide, paid up, * royalty-free, nonexclusive right and license to deal in this software * and documentation files (the "Software"), including without limitation * the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons * who receive copies from any such party to do so. This license * includes without limitation a license to do the foregoing actions * under any patents of the party supplying this software to the X * Consortium. The following conditions apply: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL DANIEL WILLIAMS OR SYSTEMS & SCIENTIFIC SOFTWARE BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef lint static char rcsid_patchlevel_h[] = "patchlevel.h,v 2.0 1994/05/19 02:01:21 dan Exp"; #endif #define VERSION "1.0" #define PATCHLEVEL "0" #endif mgdiff-1.0.orig/rundiff.c100644 1751 1751 51563 5566544162 13316 0ustar ugsugs#ifndef lint static char rcsid[] = "rundiff.c,v 2.0 1994/05/19 02:01:22 dan Exp"; #endif /* * Copyright (c) 1994 Daniel Williams * * The X Consortium, and any party obtaining a copy of these files from * the X Consortium, directly or indirectly, is granted, free of charge, * a full and unrestricted irrevocable, world-wide, paid up, * royalty-free, nonexclusive right and license to deal in this software * and documentation files (the "Software"), including without limitation * the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons * who receive copies from any such party to do so. This license * includes without limitation a license to do the foregoing actions * under any patents of the party supplying this software to the X * Consortium. The following conditions apply: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL DANIEL WILLIAMS OR SYSTEMS & SCIENTIFIC SOFTWARE BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include "mgdiff.h" #include "externs.h" /* * this is the maximum number of lines shown to the user if diff * returns an error */ #define MAX_ERROR_LINES 25 /* * pick this parameter to strike a balance between keeping the display * refreshed and processing the diff command rapidly. The program will * process at least this many lines from the input files before checking * to see if any X Events need to be handled. */ #define UPDATE_GRANULARITY 500 typedef enum { ADD = 1, CHANGE, DELETE, IGNORE, ERROR} DiffType; static char *duplicate (char *s, int *flag); static DiffType parse_diff_line (char *buf, int *f1n1, int *f1n2, int *f2n1, int *f2n2); static int eatline (FILE *f); static void getline (FILE *f, char **cooked, char **raw); static void reset_blist (void); static Block *get_blist (void); static void add_blist (Block *b); /* * release all storage used by the DiffInfo structure and its * constituent data structures */ void free_diff_info (DiffInfo *di) { Block *b, *bold; int i; /* * free the error text, if any */ if (di->etext != NULL) { char **p; for (p = di->etext; *p != NULL; p++) free ((void *) *p); free ((void *) di->etext); } /* * free all text information */ for (b = di->first; b != NULL; /* increment done in the loop */) { /* * if the blocks are identical the text is stored only on the * left hand data structures */ if ((b->arr[LEFT].type == SAME) && (b->arr[RIGHT].type == SAME)) { for (i = 0; i < b->arr[LEFT].fsize; i++) { free ((void *) b->arr[LEFT].text[i]); if ((b->arr[LEFT].wtext != NULL) && (b->arr[LEFT].wtext[i] != NULL)) free ((void *) b->arr[LEFT].wtext[i]); } free ((void *) b->arr[LEFT].text); if (b->arr[LEFT].wtext != NULL) free ((void *) b->arr[LEFT].wtext); free ((void *) b->arr[LEFT].tlen); } else if ((b->arr[LEFT].type == DIFF) && (b->arr[RIGHT].type == DIFF)) { for (i = 0; i < b->arr[LEFT].fsize; i++) { free ((void *) b->arr[LEFT].text[i]); if ((b->arr[LEFT].wtext != NULL) && (b->arr[LEFT].wtext[i] != NULL)) free ((void *) b->arr[LEFT].wtext[i]); } for (i = 0; i < b->arr[RIGHT].fsize; i++) { free ((void *) b->arr[RIGHT].text[i]); if ((b->arr[RIGHT].wtext != NULL) && (b->arr[RIGHT].wtext[i] != NULL)) free ((void *) b->arr[RIGHT].wtext[i]); } free ((void *) b->arr[LEFT].text); if (b->arr[LEFT].wtext != NULL) free ((void *) b->arr[LEFT].wtext); free ((void *) b->arr[LEFT].tlen); free ((void *) b->arr[RIGHT].text); if (b->arr[RIGHT].wtext != NULL) free ((void *) b->arr[RIGHT].wtext); free ((void *) b->arr[RIGHT].tlen); } else if ((b->arr[LEFT].type == INSERT) && (b->arr[RIGHT].type == BLANK)) { for (i = 0; i < b->arr[LEFT].fsize; i++) { free ((void *) b->arr[LEFT].text[i]); if ((b->arr[LEFT].wtext != NULL) && (b->arr[LEFT].wtext[i] != NULL)) free ((void *) b->arr[LEFT].wtext[i]); } free ((void *) b->arr[LEFT].text); if (b->arr[LEFT].wtext != NULL) free ((void *) b->arr[LEFT].wtext); free ((void *) b->arr[LEFT].tlen); } else if ((b->arr[LEFT].type == BLANK) && (b->arr[RIGHT].type == INSERT)) { for (i = 0; i < b->arr[RIGHT].fsize; i++) { free ((void *) b->arr[RIGHT].text[i]); if ((b->arr[RIGHT].wtext != NULL) && (b->arr[RIGHT].wtext[i] != NULL)) free ((void *) b->arr[RIGHT].wtext[i]); } free ((void *) b->arr[RIGHT].text); if (b->arr[RIGHT].wtext != NULL) free ((void *) b->arr[RIGHT].wtext); free ((void *) b->arr[RIGHT].tlen); } else /* CONSTCOND */ assert (False); bold = b; b = b->next; free ((void *) bold); } free ((void *) di); } /* * build just enough of a DiffInfo structure so that routines that use * the data won't be shocked. this is used to show a blank display * (no files loaded). */ DiffInfo *blank_diff_info (void) { Block *b; DiffInfo *di; di = (DiffInfo *) calloc (1, sizeof (DiffInfo)); di->longline = " "; di->maxcols = strlen (di->longline); di->status = 2; b = (Block *) calloc (1, sizeof (Block)); b->selected = NEITHER; b->arr[LEFT].type = b->arr[RIGHT].type = SAME; b->sline = 0; b->ssize = 1; b->arr[LEFT].fline = b->arr[RIGHT].fline = 0; b->arr[LEFT].fsize = b->arr[RIGHT].fsize = 1; b->arr[LEFT].text = (char **) calloc (1, sizeof (char *)); b->arr[LEFT].wtext = (char **) calloc (1, sizeof (char *)); b->arr[LEFT].tlen = (short *) calloc (1, sizeof (short)); b->arr[LEFT].text[0] = strdup (" "); b->arr[LEFT].tlen[0] = strlen (b->arr[LEFT].text[0]); b->arr[RIGHT].text = NULL; b->arr[RIGHT].wtext = NULL; b->arr[RIGHT].tlen = NULL; di->first = di->last = b; di->lines = b->sline + b->ssize; di->flines[LEFT] = b->arr[LEFT].fline + b->arr[LEFT].fsize; di->flines[RIGHT] = b->arr[RIGHT].fline + b->arr[RIGHT].fsize; return (di); } /* * run the diff command on two files with optional arguments and * return a data structure that captures the differences between * them in a way that can be displayed. */ DiffInfo *build_diff_info (char *prog, char *args, char *path1, char *path2) { FILE *diff, *file1, *file2; char buffer[BUFSIZ+1]; int sline, fline1, fline2; Block *b; int i, lines, counter; int stat_loc; DiffInfo *di; extern Widget toplevel; extern char *progname; file1 = fopen (path1, "r"); file2 = fopen (path2, "r"); diff = spawn_diff (prog, args, path1, path2); di = (DiffInfo *) calloc (1, sizeof (DiffInfo)); di->longline = ""; XmUpdateDisplay (toplevel); counter = 0; reset_blist (); sline = 0; fline1 = fline2 = 1; while (fgets (buffer, BUFSIZ, diff) != NULL) { int f1n1, f1n2, f2n1, f2n2; if ((sline - counter) > UPDATE_GRANULARITY) { counter = sline; XmUpdateDisplay (toplevel); } switch (parse_diff_line (buffer, &f1n1, &f1n2, &f2n1, &f2n2)) { case IGNORE: break; case ERROR: if (di->errors == 0) { char cmdline[4096]; di->etext = (char **) calloc (MAX_ERROR_LINES + 1, sizeof (char *)); (void) sprintf (cmdline, " \"%s %s %s %s\"", prog, args, path1, path2); di->etext[di->errors++] = strdup ("diff command line:"); di->etext[di->errors++] = strdup (""); di->etext[di->errors++] = strdup (cmdline); di->etext[di->errors++] = strdup (""); di->etext[di->errors++] = strdup ("produced this output:"); di->etext[di->errors++] = strdup (""); } if (di->errors < MAX_ERROR_LINES) di->etext[di->errors++] = strdup (buffer); break; case ADD: if (f2n1 != fline2) { b = (Block *) calloc (1, sizeof (Block)); b->selected = NEITHER; b->arr[LEFT].type = b->arr[RIGHT].type = SAME; b->sline = sline; b->arr[LEFT].fline = fline1 - 1; b->arr[RIGHT].fline = fline2 - 1; b->arr[LEFT].fsize = b->arr[RIGHT].fsize = f2n1 - fline2; b->ssize = f2n1 - fline2; b->arr[LEFT].text = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *)); b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *)); b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short)); for (i = 0; i < b->arr[LEFT].fsize; i++) { getline (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]); b->arr[LEFT].tlen[i] = strlen (b->arr[LEFT].text[i]); if (di->maxcols < b->arr[LEFT].tlen[i]) { di->maxcols = b->arr[LEFT].tlen[i]; di->longline = b->arr[LEFT].text[i]; } (void) eatline (file2); } fline1 += b->arr[LEFT].fsize; fline2 += b->arr[RIGHT].fsize; sline += b->ssize; add_blist (b); } b = (Block *) calloc (1, sizeof (Block)); b->selected = NEITHER; b->arr[LEFT].type = BLANK; b->arr[RIGHT].type = INSERT; b->sline = sline; b->arr[LEFT].fline = fline1 - 1; b->arr[RIGHT].fline = fline2 - 1; b->arr[LEFT].fsize = 0; b->arr[RIGHT].fsize = f2n2 - f2n1 + 1; b->ssize = max (b->arr[LEFT].fsize, b->arr[RIGHT].fsize); b->arr[RIGHT].text = (char **) calloc (b->arr[RIGHT].fsize, sizeof (char *)); b->arr[RIGHT].wtext = (char **) calloc (b->arr[RIGHT].fsize, sizeof (char *)); b->arr[RIGHT].tlen = (short *) calloc (b->arr[RIGHT].fsize, sizeof (short)); for (i = 0; i < b->arr[RIGHT].fsize; i++) { getline (file2, &b->arr[RIGHT].text[i], &b->arr[RIGHT].wtext[i]); b->arr[RIGHT].tlen[i] = strlen (b->arr[RIGHT].text[i]); if (di->maxcols < b->arr[RIGHT].tlen[i]) { di->maxcols = b->arr[RIGHT].tlen[i]; di->longline = b->arr[RIGHT].text[i]; } } fline2 += b->arr[RIGHT].fsize; b->arr[LEFT].text = NULL; b->arr[LEFT].tlen = NULL; sline += b->ssize; add_blist (b); break; case CHANGE: if (f1n1 != fline1) { b = (Block *) calloc (1, sizeof (Block)); b->selected = NEITHER; b->arr[LEFT].type = b->arr[RIGHT].type = SAME; b->sline = sline; b->arr[LEFT].fline = fline1 - 1; b->arr[RIGHT].fline = fline2 - 1; b->arr[LEFT].fsize = b->arr[RIGHT].fsize = f1n1 - fline1; b->ssize = f1n1 - fline1; b->arr[LEFT].text = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *)); b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *)); b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short)); for (i = 0; i < b->arr[LEFT].fsize; i++) { getline (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]); b->arr[LEFT].tlen[i] = strlen (b->arr[LEFT].text[i]); if (di->maxcols < b->arr[LEFT].tlen[i]) { di->maxcols = b->arr[LEFT].tlen[i]; di->longline = b->arr[LEFT].text[i]; } (void) eatline (file2); } fline1 += b->arr[LEFT].fsize; fline2 += b->arr[RIGHT].fsize; sline += b->ssize; add_blist (b); } b = (Block *) calloc (1, sizeof (Block)); b->selected = NEITHER; b->arr[LEFT].type = b->arr[RIGHT].type = DIFF; b->sline = sline; b->arr[LEFT].fline = fline1 - 1; b->arr[RIGHT].fline = fline2 - 1; b->arr[LEFT].fsize = f1n2 - f1n1 + 1; b->arr[RIGHT].fsize = f2n2 - f2n1 + 1; b->ssize = max (b->arr[LEFT].fsize, b->arr[RIGHT].fsize); b->arr[LEFT].text = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *)); b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *)); b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short)); for (i = 0; i < b->arr[LEFT].fsize; i++) { getline (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]); b->arr[LEFT].tlen[i] = strlen (b->arr[LEFT].text[i]); if (di->maxcols < b->arr[LEFT].tlen[i]) { di->maxcols = b->arr[LEFT].tlen[i]; di->longline = b->arr[LEFT].text[i]; } } fline1 += b->arr[LEFT].fsize; b->arr[RIGHT].text = (char **) calloc (b->arr[RIGHT].fsize, sizeof (char *)); b->arr[RIGHT].wtext = (char **) calloc (b->arr[RIGHT].fsize, sizeof (char *)); b->arr[RIGHT].tlen = (short *) calloc (b->arr[RIGHT].fsize, sizeof (short)); for (i = 0; i < b->arr[RIGHT].fsize; i++) { getline (file2, &b->arr[RIGHT].text[i], &b->arr[RIGHT].wtext[i]); b->arr[RIGHT].tlen[i] = strlen (b->arr[RIGHT].text[i]); if (di->maxcols < b->arr[RIGHT].tlen[i]) { di->maxcols = b->arr[RIGHT].tlen[i]; di->longline = b->arr[RIGHT].text[i]; } } fline2 += b->arr[RIGHT].fsize; sline += b->ssize; add_blist (b); break; case DELETE: if (f1n1 != fline1) { b = (Block *) calloc (1, sizeof (Block)); b->selected = NEITHER; b->arr[LEFT].type = b->arr[RIGHT].type = SAME; b->sline = sline; b->arr[LEFT].fline = fline1 - 1; b->arr[RIGHT].fline = fline2 - 1; b->arr[LEFT].fsize = b->arr[RIGHT].fsize = f1n1 - fline1; b->ssize = f1n1 - fline1; b->arr[LEFT].text = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *)); b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *)); b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short)); for (i = 0; i < b->arr[LEFT].fsize; i++) { getline (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]); b->arr[LEFT].tlen[i] = strlen (b->arr[LEFT].text[i]); if (di->maxcols < b->arr[LEFT].tlen[i]) { di->maxcols = b->arr[LEFT].tlen[i]; di->longline = b->arr[LEFT].text[i]; } (void) eatline (file2); } fline1 += b->arr[LEFT].fsize; fline2 += b->arr[RIGHT].fsize; sline += b->ssize; add_blist (b); } b = (Block *) calloc (1, sizeof (Block)); b->selected = NEITHER; b->arr[LEFT].type = INSERT; b->arr[RIGHT].type = BLANK; b->sline = sline; b->arr[LEFT].fline = fline1 - 1; b->arr[RIGHT].fline = fline2 - 1; b->arr[LEFT].fsize = f1n2 - f1n1 + 1; b->arr[RIGHT].fsize = 0; b->ssize = max (b->arr[LEFT].fsize, b->arr[RIGHT].fsize); b->arr[LEFT].text = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *)); b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *)); b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short)); for (i = 0; i < b->arr[LEFT].fsize; i++) { getline (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]); b->arr[LEFT].tlen[i] = strlen (b->arr[LEFT].text[i]); if (di->maxcols < b->arr[LEFT].tlen[i]) { di->maxcols = b->arr[LEFT].tlen[i]; di->longline = b->arr[LEFT].text[i]; } } fline1 += b->arr[LEFT].fsize; b->arr[RIGHT].text = NULL; b->arr[RIGHT].tlen = NULL; sline += b->ssize; add_blist (b); break; default: /* CONSTCOND */ assert (False); break; } } /* * if we've read no lines and there are diff errors then blow off */ if ((fline1 == 1) && (fline2 == 1) && (di->errors > 0)) { DiffInfo *newdi = blank_diff_info (); if (wait (&stat_loc) == -1) { (void) fprintf (stderr, "%s: system call ", progname); perror ("wait"); exit (2); } newdi->errors = di->errors; newdi->etext = di->etext; newdi->status = (WIFEXITED (stat_loc)) ? (WEXITSTATUS (stat_loc)) : 2; return (newdi); } /* * we've parsed all the diff commands but the possibility exists * that the rest of the two files are identical */ /* get a line count from the first file */ for (lines = 0; eatline (file1); lines++) ; if (lines > 0) { b = (Block *) calloc (1, sizeof (Block)); b->selected = NEITHER; b->arr[LEFT].type = b->arr[RIGHT].type = SAME; b->sline = sline; b->arr[LEFT].fline = fline1 - 1; b->arr[RIGHT].fline = fline2 - 1; b->arr[LEFT].fsize = b->arr[RIGHT].fsize = lines; b->ssize = lines; b->arr[LEFT].text = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *)); b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *)); b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short)); for (i = 0; i < b->arr[LEFT].fsize; i++) { getline (file2, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]); b->arr[LEFT].tlen[i] = strlen (b->arr[LEFT].text[i]); if (di->maxcols < b->arr[LEFT].tlen[i]) { di->maxcols = b->arr[LEFT].tlen[i]; di->longline = b->arr[LEFT].text[i]; } } add_blist (b); } di->first = get_blist (); di->last = b; di->lines = b->sline + b->ssize; di->flines[LEFT] = b->arr[LEFT].fline + b->arr[LEFT].fsize; di->flines[RIGHT] = b->arr[RIGHT].fline + b->arr[RIGHT].fsize; if (wait (&stat_loc) == -1) { (void) fprintf (stderr, "%s: system call ", progname); perror ("wait"); exit (2); } di->status = (WIFEXITED (stat_loc)) ? (WEXITSTATUS (stat_loc)) : 2; return (di); } /* * make a copy of a string, converting tabs to spaces and control characters * to printable form if needed. */ static char *duplicate (char *s, int *flag) { int len, i, tabs, ctrls; /* * compute length of new string, taking tabs and control * characters into account */ for (i = 0, len = 0, ctrls = tabs = 0; s[i] != '\0'; i++) { if (isascii (s[i])) { if (s[i] == '\t') { tabs++; len += 8; len /= 8; len *= 8; } else if (iscntrl (s[i])) { ctrls++; len += 2; } else len++; } else { ctrls++; len += 4; } } if (tabs || ctrls) { char *ret = (char *) calloc (1, len + 1); int j; for (i = 0, j = 0; s[i] != '\0'; i++) { if (isascii (s[i])) { if (s[i] == '\t') { ret[j++] = ' '; while ((j % 8) != 0) ret[j++] = ' '; } else if (iscntrl (s[i])) { ret[j++] = '^'; ret[j++] = (s[i] + '@') & 0x7f; } else ret[j++] = s[i]; } else { unsigned char c = s[i]; /* * create octal escape */ ret[j++] = '\\'; ret[j+2] = (c % 8) + '0'; c /= 8; ret[j+1] = (c % 8) + '0'; c /= 8; ret[j+0] = (c % 8) + '0'; j += 3; } } *flag = True; return (ret); } else { *flag = False; return (strdup (s)); } } /* * this code taken from "ediff.c" by David MacKenzie, a published, * uncopyrighted program to translate diff output into plain English */ static DiffType parse_diff_line (char *buf, int *f1n1, int *f1n2, int *f2n1, int *f2n2) { if ((buf[0] == '<') || (buf[0] == '>') || (buf[0] == '-')) { return (IGNORE); } else if (sscanf (buf, "%d,%dc%d,%d\n", f1n1, f1n2, f2n1, f2n2) == 4) { return (CHANGE); } else if (sscanf (buf, "%d,%dc%d\n", f1n1, f1n2, f2n1) == 3) { *f2n2 = *f2n1; return (CHANGE); } else if (sscanf (buf, "%dc%d,%d\n", f1n1, f2n1, f2n2) == 3) { *f1n2 = *f1n1; return (CHANGE); } else if (sscanf (buf, "%dc%d\n", f1n1, f2n1) == 2) { *f2n2 = *f2n1; *f1n2 = *f1n1; return (CHANGE); } else if (sscanf (buf, "%d,%dd%d\n", f1n1, f1n2, f2n1) == 3) { *f2n2 = *f2n1; return (DELETE); } else if (sscanf (buf, "%dd%d\n", f1n1, f2n1) == 2) { *f2n2 = *f2n1; *f1n2 = *f1n1; return (DELETE); } else if (sscanf (buf, "%da%d,%d\n", f1n1, f2n1, f2n2) == 3) { *f1n2 = *f1n1; return (ADD); } else if (sscanf (buf, "%da%d\n", f1n1, f2n1) == 2) { *f1n2 = *f1n1; *f2n2 = *f2n1; return (ADD); } else return (ERROR); } /* * read a line and throw it away */ static int eatline (FILE *f) { for (;;) { int c; c = getc (f); if (c == '\n') return (1); /* * EOF (aka 0xff, 0377) is valid byte that might appear in our * input; for this reason, we cannot compare against EOF. */ if (feof (f) || ferror (f)) return (0); } /* NOTREACHED */ } /* * read a single line from a stream and return both raw (as read) * and cooked (tabs converted to spaces and control characters made * printable) if necessary. Silently truncate input lines at BUFSIZ * characters. */ static void getline (FILE *f, char **cooked, char **raw) { char buffer[BUFSIZ+1]; char *s; int j, flag; for (j = 0; j < BUFSIZ; j++) { buffer[j] = getc (f); /* see comment above about EOF */ if ((buffer[j] == '\n') || feof (f) || ferror (f)) break; } /* see comment above about EOF */ if ((j == 0) && (feof (f) || ferror (f))) *cooked = *raw = NULL; buffer[j] = '\0'; s = duplicate (buffer, &flag); /* the line was too long; toss the rest */ if (j >= BUFSIZ) while (getc (f) != '\n') ; *cooked = s; *raw = (flag) ? strdup (buffer) : NULL; } /* * minimal doubly-linked list functions */ static Block *blist, *last; static void reset_blist (void) { blist = last = NULL; } static Block *get_blist (void) { return (blist); } static void add_blist (Block *b) { if (blist == NULL) blist = last = b; else { last->next = b; b->prev = last; last = last->next; } } mgdiff-1.0.orig/spawn.c100644 1751 1751 7666 5566544163 12777 0ustar ugsugs#ifndef lint static char rcsid[] = "spawn.c,v 2.0 1994/05/19 02:01:23 dan Exp"; #endif /* * Copyright (c) 1994 Daniel Williams * * The X Consortium, and any party obtaining a copy of these files from * the X Consortium, directly or indirectly, is granted, free of charge, * a full and unrestricted irrevocable, world-wide, paid up, * royalty-free, nonexclusive right and license to deal in this software * and documentation files (the "Software"), including without limitation * the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons * who receive copies from any such party to do so. This license * includes without limitation a license to do the foregoing actions * under any patents of the party supplying this software to the X * Consortium. The following conditions apply: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL DANIEL WILLIAMS OR SYSTEMS & SCIENTIFIC SOFTWARE BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #define BLOCKSIZE 10 /* * run a program with command line arguments and two pathname * arguments via fork/exec and return a pipe file descriptor into * which standard output and standard error have been redirected */ FILE *spawn_diff (char *prog, char *args, char *path1, char *path2) { int pipe_fds[2]; char buffer[1024]; extern char *progname; char **argv; char *ptr; int argc, count; if (pipe (pipe_fds) == -1) { (void) fprintf (stderr, "%s: system call ", progname); perror ("pipe"); exit (2); } switch (fork ()) { case 0: /* the child */ /* * redirect standard output and standard error into the pipe */ (void) close (fileno (stdout)); if (dup (pipe_fds[1]) == -1) { (void) fprintf (stderr, "%s: system call ", progname); perror ("dup"); exit (2); } (void) close (fileno (stderr)); if (dup (pipe_fds[1]) == -1) { (void) fprintf (stderr, "%s: system call ", progname); perror ("dup"); exit (2); } (void) close (pipe_fds[0]); /* * split up args passed in into an argument vector for the execvp * system call. this works for an unlimited number of arguments, * but fails to do any quote processing. arguments with embedded * spaces will break this. */ argc = 0; count = BLOCKSIZE; argv = (char **) malloc (sizeof (char *) * BLOCKSIZE); argv[argc++] = prog; for (ptr = strtok (args, " \t"); ptr; ptr = strtok (NULL, " \t")) { if (argc >= count) { argv = (char **) realloc (argv, sizeof (char *) * BLOCKSIZE); count += BLOCKSIZE; } argv[argc++] = strdup (ptr); } if ((argc + 3) >= count) argv = (char **) realloc (argv, sizeof (char *) * 3); argv[argc++] = path1; argv[argc++] = path2; argv[argc++] = NULL; if (execvp (prog, argv) == -1) { (void) sprintf (buffer, "%s: %s: %s", progname, "exec", prog); perror (buffer); exit (2); } break; case -1: /* fork error */ (void) fprintf (stderr, "%s: system call ", progname); perror ("fork"); exit (2); break; default: /* the parent */ /* * we must close this in the parent or else the close of the * writer end of the pipe in the child will not cause an EOF * condition for the reader */ (void) close (pipe_fds[1]); /* * return the reader side of the pipe as a stdio stream */ return (fdopen (pipe_fds[0], "r")); /* NOTREACHED */ break; } /* NOTREACHED */ }