File mgdiff-1.0.1.diff of Package mgdiff

--- mgdiff.c
+++ mgdiff.c
@@ -1,13 +1,14 @@
-#ifndef lint
+#if 0
 static char rcsid[] = "mgdiff.c,v 2.1 1994/09/29 01:56:53 dan Exp";
 #endif
 
-#ifndef lint
+#if 0
 static char copyright[] = "Copyright (c) 1994, Daniel Williams";
 #endif
 
 /*
  * Copyright (c) 1994    Daniel Williams
+ * Copyright (c) 2003    Erik de Castro Lopo
  * 
  * The X Consortium, and any party obtaining a copy of these files from
  * the X Consortium, directly or indirectly, is granted, free of charge,
@@ -40,6 +41,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <sys/stat.h>
+#include <locale.h>
 
 #include <X11/Intrinsic.h>
 #include <X11/StringDefs.h>
@@ -99,7 +101,7 @@
 static void show_version (Widget parent);
 static void update_overall (void);
 static void refresh (void);
-static void toggle_saveas_sensitive (Boolean sensitive);
+static void toggle_saveas_sensitive (Boolean saveas, Boolean save_left, Boolean save_right);
 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);
@@ -109,9 +111,14 @@
 static void unselect_all (void);
 static Boolean all_selected (void);
 static Dimension get_preferred_width (Widget w);
-static char *basename (char *name);
+static char *mgdiff_basename (char *name);
 
-#define APP_DEFAULTS_VERSION 1
+enum {
+    WIDGET_LEFT	 = 0x10000000,
+    WIDGET_RIGHT = 0x20000000
+} ;
+
+#define APP_DEFAULTS_VERSION 2
 
 /* 
  * treat failure to find the resources from the application defaults
@@ -120,10 +127,16 @@
  */
 static String fallbacks[] = {
     "*menubar.button_0.XmString: File",
-    "*file_menu*button_4.XmString: Exit",
+    "*file_menu*button_6.XmString: Exit",
     NULL
 };
 
+static char unselected_text_msg [] =
+    "Unselected blocks remain.\n\n"
+    "Press Cancel to go back to correct this.\n"
+    "Pressing OK will save the merged data with all unselected\n"
+    "blocks absent from the output file." ;
+
 static XrmOptionDescRec option_table[] = {
     {"-quit", "quitIfSame", XrmoptionNoArg, "true"},
     {"-args", "diffArgs", XrmoptionSepArg, NULL},
@@ -137,6 +150,7 @@
 
 static struct screenstate {
     Block *b;
+    Block *lastSelected;
     int topline;
     int leftcol;
     int sindex, findex[2];
@@ -170,7 +184,7 @@
 
 static char *str_fnamel, *str_fnamer;
 static char *str_snamel, *str_snamer;
-static char *tempfname;
+static char tempfname [512] = "" ;
 static char *user_filename;
 char *progname;
 
@@ -195,8 +209,11 @@
  * anyway) and less complex than turning on and correctly processing
  * GraphicsExpose events.
  */
-static int statel = VisibilityFullyObscured;
-static int stater = VisibilityFullyObscured;
+
+/* Make the initial state unobscured. */
+static int statel = VisibilityUnobscured;
+static int stater = VisibilityUnobscured;
+
 
 /* ARGSUSED1 */
 static void Visible (Widget widget, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch)
@@ -398,23 +415,37 @@
     Region region;
     Block *b;
     GC fore, back;
-    int columns;
-
+    int columns, widget_side;
+	
+    Side x_selection = NEITHER;
+    Block *curr_x_block = newss.lastSelected;
+	
+    if (curr_x_block) {
+	x_selection = curr_x_block->selected;
+    }
+	
     XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL);
     XtAddExposureToRegion (cbs->event, region = XCreateRegion ());
 
     columns = (int) width / font_width + 1;
 
+    if (w == textl)
+	widget_side = WIDGET_LEFT;
+    else if (w == textr)
+	widget_side = WIDGET_RIGHT;
+    else
+	assert (False);
+
     itemp = newss.sindex;
     ypos = 0;
     for (b = newss.b; b != NULL; b = b->next) {
 	int j;
 	Chunk *ths, *oth;
 
-	if (w == textl) {
+	if (widget_side == WIDGET_LEFT) {
 	    ths = &b->arr[LEFT];
 	    oth = &b->arr[RIGHT];
-	    if (b->selected == LEFT) {
+	    if (b->selected == LEFT || b->selected == BOTH) {
 		fore = gcfore[4];
 		back = gcback[4];
 	    }
@@ -423,10 +454,10 @@
 		back = gcback[ths->type];
 	    }
 	}
-	else if (w == textr) {
+	else if (widget_side == WIDGET_RIGHT) {
 	    ths = &b->arr[RIGHT];
 	    oth = &b->arr[LEFT];
-	    if (b->selected == RIGHT) {
+	    if (b->selected == RIGHT || b->selected == BOTH) {
 		fore = gcfore[4];
 		back = gcback[4];
 	    }
@@ -537,15 +568,32 @@
 	open_right_file (toplevel, str_fnamer);
 	break;
     case 3:			/* save as */
-	if (all_selected ()) {
-	    set_cursor (toplevel);
-	    save_file (toplevel, di->first, str_fnamel);
+	if (all_selected () == False) {
+	    if (modal_question (toplevel, "Mgdiff Save", unselected_text_msg) == False)
+		break;
 	}
-	else {
-	    werror (toplevel, "Save Error", "Save", "there are unselected text blocks");
+	save_file (toplevel, di->first, str_fnamel);
+	break;
+	case 4:			/* save as left */
+	if (all_selected () == False) {
+	    if (modal_question (toplevel, "Mgdiff Save", unselected_text_msg) == False)
+		break;
 	}
+	    set_cursor (toplevel);
+	    save_as_filename (toplevel, di->first, str_fnamel);
+	    reset_cursor (toplevel);
+	break;
+	case 5:			/* save as right */
+	if (all_selected () == False) {
+	    if (modal_question (toplevel, "Mgdiff Save", unselected_text_msg) == False)
+		break;
+	}
+	    set_cursor (toplevel);
+	    save_as_filename (toplevel, di->first, str_fnamer);
+	    reset_cursor (toplevel);
+
 	break;
-    case 4:			/* exit */
+    case 6:			/* exit */
 	exit_cb (w, NULL, NULL);
 	break;
     default:
@@ -724,7 +772,6 @@
 	dagcb = XtGetGC (children[1], GCForeground|GCBackground, &gc_values);
 	been_here = 1;
     }
-
     for (i = 0; i < 3; i++) {
 	XtVaGetValues (children[i],
 		       XmNwidth, &width[i],
@@ -755,7 +802,7 @@
 	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;
+	back = (b->selected == LEFT || b->selected == BOTH) ? 4 : b->arr[LEFT].type;
 	XFillRectangle (XtDisplay (children[0]), p[0], gcback[back],
 			0, y, width[0], h);
 
@@ -763,7 +810,7 @@
 	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;
+	back = (b->selected == RIGHT || b->selected == BOTH) ? 4 : b->arr[RIGHT].type;
 	XFillRectangle (XtDisplay (children[2]), p[2], gcback[back],
 			0, y, width[2], h);
 
@@ -906,6 +953,7 @@
      */
     static char *foo3 = "\
 	<Btn1Down>: Select() \n\
+	<Btn2Down>: Select() \n\
 	~Ctrl <Key>osfPageDown: Scroll(PageDown) \n\
 	~Ctrl <Key>osfPageUp: Scroll(PageUp) \n\
 	<Key>osfLeft: Scroll(Left) \n\
@@ -951,8 +999,9 @@
  */
 static void cleanup_at_exit (void)
 {
-    if (tempfname != NULL)
+    if (strlen (tempfname) > 0)
 	(void) unlink (tempfname);
+    tempfname [0] = 0 ; 
 }
 
 /* 
@@ -1018,8 +1067,11 @@
     {"debug", "Debug", XtRBoolean, sizeof (Boolean), 0, XtRString, "false"},
     {"filename", "Filename", XtRString, sizeof (String), 0, XtRString, ""}};
     
-    progname = basename (argv[0]);
+    progname = mgdiff_basename (argv[0]);
 
+    XtSetLanguageProc (NULL, NULL, NULL);
+    setlocale (LC_ALL, "");
+    setlocale (LC_CTYPE, "en");
     toplevel = XtVaAppInitialize (&app, "Mgdiff", option_table, XtNumber (option_table),
 #if X11R5
 				  &argc,
@@ -1079,7 +1131,6 @@
 	};
 	werror_long (toplevel, "Wrong Application Defaults", array, sizeof (array) / sizeof (array[0]));
     }
-
     if (debug_flag) {
 	XSetErrorHandler (x_error_handler);
 	XtAppSetErrorHandler (app, xt_error_handler);
@@ -1087,7 +1138,10 @@
     else
 	XtAppSetWarningHandler (app, xt_warning_handler);
 
-#if sun
+#if 0
+    /* May possibly be required on some old versions of SunOS.
+    ** Definitely not required on Solaris.
+    */
     (void) on_exit (cleanup_at_exit, NULL);
 #else
     (void) atexit (cleanup_at_exit);
@@ -1109,14 +1163,17 @@
 	 * two filenames on command line; process them
 	 */
     case 3:
+	if (strcmp (argv[1], "-") == 0 && strcmp (argv[2], "-") == 0) {
+		(void) fprintf (stderr, "Cannot use stdin for both file input\n");
+		exit (2);
+	}
 	if (strcmp (argv[1], "-") == 0) {
-	    tempfname = tempnam (NULL, "mgdif");
-	    str_fnamel = strdup (tempfname);
-	    str_snamel = strdup (user_filename);
-	    if (!copy_to_file (stdin, tempfname)) {
+	    if (!copy_to_tempfile (stdin, tempfname, sizeof (tempfname))) {
 		(void) fprintf (stderr, "Error copying stdin to temp file \"%s\"\n", tempfname);
 		exit (2);
 	    }
+	    str_fnamel = strdup (tempfname);
+	    str_snamel = strdup (user_filename);
 	}
 	else if (!file_tests (toplevel, argv[1])) {
 	    no_files_flag = True;
@@ -1131,13 +1188,12 @@
 	}
 
 	if (strcmp (argv[2], "-") == 0) {
-	    tempfname = tempnam (NULL, "mgdif");
-	    str_fnamer = strdup (tempfname);
-	    str_snamer = strdup (user_filename);
-	    if (!copy_to_file (stdin, tempfname)) {
+	    if (!copy_to_tempfile (stdin, tempfname, sizeof (tempfname))) {
 		(void) fprintf (stderr, "Error copying stdin to temp file \"%s\"\n", tempfname);
 		exit (2);
 	    }
+	    str_fnamer = strdup (tempfname);
+	    str_snamer = strdup (user_filename);
 	}
 	else if (!file_tests (toplevel, argv[2])) {
 	    no_files_flag = True;
@@ -1174,6 +1230,7 @@
     }
 
     newss.b = di->first;
+    newss.lastSelected= NULL;
     newss.topline = newss.sindex = newss.findex[LEFT] = newss.findex[RIGHT] = 0;
 
     mainw = XtVaCreateManagedWidget ("mainw", xmMainWindowWidgetClass,
@@ -1205,10 +1262,13 @@
 				  XmVaPUSHBUTTON, NULL, NULL, NULL, NULL,
 				  XmVaSEPARATOR,
 				  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);
+	toggle_saveas_sensitive (False, False, False);
     }
     XmVaCreateSimplePulldownMenu (menubar, "view_menu", 1, view_cb,
 				  XmVaPUSHBUTTON, NULL, NULL, NULL, NULL,
@@ -1491,6 +1551,7 @@
 
     XtAppMainLoop (app);
     /* NOTREACHED */
+    return 0;
 }
 
 static void redraw_partial_vert (Widget w)
@@ -1622,9 +1683,9 @@
 {
     char buffer[16];
 
-    (void) sprintf (buffer, "%*d", linenum_columns, l);
+    (void) snprintf (buffer, sizeof (buffer), "%*d", linenum_columns, l);
     XmTextFieldSetString (linenuml, buffer);
-    (void) sprintf (buffer, "%*d", linenum_columns, r);
+    (void) snprintf (buffer, sizeof (buffer), "%*d", linenum_columns, r);
     XmTextFieldSetString (linenumr, buffer);
 }
 
@@ -1986,7 +2047,7 @@
 					      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);
+	(void) snprintf (buffer, sizeof (buffer), "mgdiff\n\nA graphical difference browser\n\nAuthors: Dan Williams (dan@sass.com)\nErik de Castro Lopo (erikd@mega-nerd.com)\n\nVersion: %s PL%s", VERSION, PATCHLEVEL);
 
 	XtVaSetValues (dialog,
 		       XmNautoUnmanage, True,
@@ -2041,12 +2102,12 @@
     if (di->status != 2) {
 	no_files_flag = False;
 	toggle_openlr_sensitive (True);
-	toggle_saveas_sensitive (True);
+	toggle_saveas_sensitive (True, True, True);
     }
     else {
 	no_files_flag = True;
 	toggle_openlr_sensitive (False);
-	toggle_saveas_sensitive (False);
+	toggle_saveas_sensitive (False, False, False);
 	free (str_fnamel);
 	free (str_snamel);
 	free (str_fnamer);
@@ -2082,7 +2143,7 @@
     if (di->status == 2) {
 	no_files_flag = True;
 	toggle_openlr_sensitive (False);
-	toggle_saveas_sensitive (False);
+	toggle_saveas_sensitive (False, False, False);
 	free (str_fnamel);
 	free (str_snamel);
 	free (str_fnamer);
@@ -2117,7 +2178,7 @@
     if (di->status == 2) {
 	no_files_flag = True;
 	toggle_openlr_sensitive (False);
-	toggle_saveas_sensitive (False);
+	toggle_saveas_sensitive (False, False, False);
 	free (str_fnamel);
 	free (str_snamel);
 	free (str_fnamer);
@@ -2133,6 +2194,7 @@
     handle_diff_errors (di);
 }
 
+
 static void refresh (void)
 {
     newss.b = di->first;
@@ -2182,9 +2244,11 @@
     toggle_openlr_sensitive (sensitive);
 }
 
-static void toggle_saveas_sensitive (Boolean sensitive)
+static void toggle_saveas_sensitive (Boolean saveas, Boolean save_left, Boolean save_right)
 {
-    XtSetSensitive (XtNameToWidget (file_menu, "button_3"), sensitive);
+    XtSetSensitive (XtNameToWidget (file_menu, "button_3"), saveas);
+    XtSetSensitive (XtNameToWidget (file_menu, "button_4"), save_left);
+    XtSetSensitive (XtNameToWidget (file_menu, "button_5"), save_right);
 }
 
 /* 
@@ -2196,78 +2260,263 @@
     exit ((di != NULL) ? di->status : 2);
 }
 
+static void lost_selection ( Widget  widget, Atom* selection) { 
+	
+	if (debug_flag) {
+		fprintf(stderr,"selection lost on widget %p\n",widget);
+	}
+//	newss.lastSelected=NULL;
+}
+
+static Boolean do_selection(Widget widget, Atom*  selection, Atom*  target ,
+                            Atom*  type, XtPointer*  value, 
+			    unsigned long* length,int* format) {
+
+    Atom targets = XInternAtom(XtDisplay(widget), "TARGETS", False);
+    Atom *array;
+    char* result;
+    char* line;
+    int i,j;
+    Block *b= newss.lastSelected;
+    Chunk *chunk =NULL;
+    
+    if (debug_flag) {
+		fprintf(stderr,"selection request on widget %p\n",widget);
+    }
+
+   if (!b) return False;
+   
+   chunk = &(b->arr[b->selected]);
+   
+    if (*target == targets)
+    {
+	if (debug_flag) {
+		fprintf(stderr,"clipboards targets requested on widget %p\n",widget);
+        }	
+	/*
+	 * Handle request for data types
+	 */
+
+	if ((array = (Atom *)XtMalloc((unsigned)(sizeof(Atom) * 1))) == NULL)
+	    return False;
+	*value = (XtPointer)array;
+	array[0] = XA_STRING;
+	*type = XA_ATOM;
+	*format = sizeof(Atom) * 8;
+	*length = 5;
+	return True;
+    }
+    
+    if (*target == XA_STRING) {
+    	/*
+	 * request for string data !.
+	 */
+	if (debug_flag) {
+		fprintf(stderr,"string target requested on widget %p\n",widget);
+	}
+    	
+	/*
+	 * Iterate through the lines in the text block
+	 * summing the lengths
+	 */
+	*length=0;
+	for (i = 0; i < chunk->fsize; i++) {
+	   if ((chunk->wtext != NULL) && (chunk->wtext[i] != NULL)) {
+	       *length += (strlen(chunk->wtext[i])+1);
+	   } else {
+	       *length += (strlen(chunk->text[i])+1);
+	   }
+         }
+        *format = 8;	    /* 8 bits per char */
+	*type  = XA_STRING;
+	if (debug_flag) {
+		fprintf(stderr,"string length= %li\n",*length);
+	}
+
+    	*value = XtMalloc(*length);
+        result = (char*)(*value);
+ 	/*
+	 * Iterate through the lines in the text block
+	 * moving the data into the clipboard memblock
+	 */
+	for (i = 0; i < chunk->fsize; i++) {
+	   if ((chunk->wtext != NULL) && (chunk->wtext[i] != NULL)) {
+	      line = chunk->wtext[i] ;
+	   } else {
+	       line = chunk->text[i];
+	   }
+	   j =strlen(line);
+	   memcpy(result,line,j);
+	   result+=j;
+	   *(result++)= '\n';
+         }
+ 	
+	
+	if (debug_flag) {
+		fprintf(stderr,"all done string at= %p\n",*value);
+	}
+	if (!(*value)) {
+		return False;
+    	}
+	return True;
+    }
+    /* 
+     * Haven't found data type we know about!
+     */
+    return False;	
+}
+
+
+
+
 /* ARGSUSED2 */
 static void Select (Widget widget, XEvent *event, String *params, Cardinal *num_params)
 {
-    if (event->xany.type == ButtonPress) {
+    /*
+    ** The original version of this function was rather confusing. It was
+    ** rewritten to make it easier to follow so that more selection features
+    ** could then be added (ie select both left and right).
+    ** The function itself and the main for loop are written so that evaluation
+    ** of current state occurs at the top and processing at the bottom. For
+    ** instance, the first test to see if the XEvent is a ButtonPress returns
+    ** from the function rather than making the whole function one huge if
+    ** statement. Similarly, continue statements are used in the for loop to
+    ** bypass the lower part of the loop.
+    */
 	Block *b;
 	Dimension ypos, height;
-	int itemp, rect_height;
+    int itemp, rect_height, widget_side;
+ 	Side x_selection = NEITHER;
+        Block *curr_x_block = newss.lastSelected;
+
+    if (event->xany.type != ButtonPress)
+	return;
+
+    if (widget == textl)
+	widget_side = WIDGET_LEFT;
+    else if (widget == textr)
+	widget_side = WIDGET_RIGHT;
+    else
+	assert (False);
+
+ 	
+ 	if (curr_x_block) {
+		x_selection = curr_x_block->selected;
+ 	}
 
 	XtVaGetValues (widget, XmNheight, &height, NULL);
 
 	itemp = newss.sindex;
 	ypos = 0;
+ 	//Find selected chunk!.
 	for (b = newss.b; b != NULL; b = b->next) {
+	/* If the current ypos is > height of window, we're done, so just return. */
+	    if (ypos > height)
+	    	return;
+
 	    if ((rect_height = font_height * (b->ssize - itemp)) > (int) height)
 		rect_height = height;
+	itemp = 0;
 
-	    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 ();
+	if (event->xbutton.y < (unsigned int) ypos) {
+	    ypos += rect_height;
+	    continue;
 		    }
-		    else if (widget == textr) {
-			b->selected = RIGHT;
-			redraw_partial (textl, ypos, rect_height);
-			redraw_partial (textr, ypos, rect_height);
-			update_pixmaps ();
+
+	if (event->xbutton.y >= (unsigned int) (ypos + rect_height)) {
+	    ypos += rect_height;
+	    continue;
 		    }
-		    else
-			assert (False);
-		    break;
-		case RIGHT:
-		    if (widget == textl) {
+
+	/*
+	** Have now found the selected block.
+	** If the LH and RH sides of the selected block are the same, then
+	** there is nothing to do, so just return.
+	*/
+	if (b->arr[LEFT].type == SAME)
+	    return;
+
+	/*
+	** This state machine has been rewritten as a true state machine. The
+	** original had three cases (LEFT< RIGHT, NEITHER) and an if statement
+	** in each case. Since the original simplification, more states have
+	** been added (ie select BOTH state).
+	*/
+	switch (widget_side | (event->xbutton.button << 4) | b->selected) {
+	    case WIDGET_LEFT  | (1<<4) | NEITHER:
+	    case WIDGET_LEFT  | (1<<4) | RIGHT:
+	    case WIDGET_LEFT  | (1<<4) | BOTH:
 			b->selected = LEFT;
-			redraw_partial (textl, ypos, rect_height);
-			redraw_partial (textr, ypos, rect_height);
-			update_pixmaps ();
-		    }
-		    else if (widget == textr) {
+		break;
+	    case WIDGET_LEFT  | (1<<4) | LEFT:
+	    case WIDGET_RIGHT | (2<<4) | BOTH:
 			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 ();
+
+	    case WIDGET_RIGHT | (1<<4) | NEITHER:
+	    case WIDGET_RIGHT | (1<<4) | LEFT:
+	    case WIDGET_RIGHT | (1<<4) | BOTH:
+		b->selected = RIGHT;
+		break;
+	    case WIDGET_RIGHT | (1<<4) | RIGHT:
+	    case WIDGET_LEFT  | (2<<4) | BOTH:
+		b->selected = NEITHER;
 		    break;
-		default:
-		    assert (False);
+
+	    case WIDGET_LEFT  | (2<<4) | NEITHER:
+	    case WIDGET_LEFT  | (2<<4) | LEFT:
+	    case WIDGET_LEFT  | (2<<4) | RIGHT:
+	    	if (b->arr[LEFT].type == DIFF) {
+		    b->selected = BOTH;
 		    break;
 		}
-		return;
-	    }
+		if (b->arr[LEFT].wtext != NULL)
+		    b->selected = (b->selected == LEFT) ? NEITHER : LEFT;
+	    	break ;
+
+	    case WIDGET_RIGHT | (2<<4) | NEITHER:
+	    case WIDGET_RIGHT | (2<<4) | LEFT:
+	    case WIDGET_RIGHT | (2<<4) | RIGHT:
+	    	if (b->arr[LEFT].type == DIFF) {
+		    b->selected = BOTH;
+		    break;
+		}
+	    	if (b->arr[RIGHT].wtext != NULL)
+		    b->selected = (b->selected == RIGHT) ? NEITHER : RIGHT;
+	    	break ;
 
-	    ypos += rect_height;
 
-	    itemp = 0;
-	    if (ypos > height)
-		return;
+		default:
+		printf ("Button:%d    widget:%s    sel:%d\n", event->xbutton.button, 
+			widget_side == WIDGET_LEFT ? "LEFT" : "RIGHT", b->selected) ;
+		    assert (False);
+		    break;
+		}
+	redraw_partial (textl, ypos, rect_height);
+	redraw_partial (textr, ypos, rect_height);
+	update_pixmaps ();
+      
+	if (  b->selected == NEITHER ) {
+		if (b == newss.lastSelected)
+ 			newss.lastSelected=NULL;
+	} else {
+		newss.lastSelected=b;
 	}
-    }
+	
+	if ( !newss.lastSelected 
+	      || (x_selection != newss.lastSelected->selected)
+  //	     || (newss.lastSelected != curr_x_block ) 
+ 	    )
+	{
+ 		XtDisownSelection(widget,XA_PRIMARY, CurrentTime);
+	}
+	
+ 	if (newss.lastSelected) {
+ 	   XtOwnSelection(widget,XA_PRIMARY, CurrentTime,&do_selection,&lost_selection,NULL);
+  	}
+
+	return;
+	    }
 }
 
 /* 
@@ -2307,14 +2556,14 @@
 	else {
 	    char buffer[1024];
 	    
-	    (void) sprintf (buffer, "Illegal argument to action proc Scroll (\"%s\")", params[0]);
+	    (void) snprintf (buffer, sizeof (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);
+	(void) snprintf (buffer, sizeof (buffer), "Illegal number of arguments to action proc Scroll (\"%d\")", *num_params);
 	XtAppWarning (XtWidgetToApplicationContext (widget), buffer);
     }
 }
@@ -2391,7 +2640,7 @@
 /* 
  * delete any prefix ending in '/' and return a copy
  */
-static char *basename (char *path)
+static char *mgdiff_basename (char *path)
 {
     if (path) {
 	char *p;
--- mgdiff.h
+++ mgdiff.h
@@ -1,7 +1,7 @@
 #ifndef MXDIFF_H
 #define MXDIFF_H
 
-#ifndef lint
+#if 0
 static char rcsid_mgdiff_h[] = "mgdiff.h,v 2.0 1994/05/19 02:01:15 dan Exp";
 #endif
 
@@ -52,7 +52,11 @@
     short *tlen;		/* the lengths of each line */
 } Chunk;
 
-typedef enum {LEFT = 0, RIGHT, NEITHER} Side;
+/*
+** LEFT and RIGHT must be 0 and 1 respectively as they are used 
+** to index as array.
+*/
+typedef enum {LEFT = 0, RIGHT, NEITHER, BOTH} Side;
 
 /* 
  * a block is an element of a doubly linked list containing a left chunk 
@@ -86,4 +90,11 @@
  */
 #define X11R5 (defined(XtSpecificationRelease) && (XtSpecificationRelease >= 5))
 
+/*
+ * According to IETF RFC 2279, byte values of 0xfe and 0xff are
+ * not legal utf-8, but all others bytes are legal.
+ */
+#define islatin(c)     (isprint((c)) || ((((unsigned char)(c)) <= 0xfd)))
+
+#define isallowed(c)	(isascii((c)) || islatin((c)))
 #endif
--- Imakefile
+++ Imakefile
@@ -8,7 +8,8 @@
 XCOMM
 XCOMM for Dell SVR4
 XCOMM
-EXTRA_LIBRARIES = -lc -lucb
+#EXTRA_LIBRARIES = -lc -lucb
+EXTRA_DEFINES = -Wall -Wstrict-prototypes -Wmissing-prototypes
 
 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
--- legend.c
+++ legend.c
@@ -1,4 +1,4 @@
-#ifndef lint
+#if 0
 static char rcsid[] = "legend.c,v 2.0 1994/05/19 02:01:08 dan Exp";
 #endif
 
--- Mgdiff.ad
+++ Mgdiff.ad
@@ -112,7 +112,7 @@
 !
 ! this should only be defined in the site-wide file
 !
-?.AppDefaultsVersion:			1
+?.AppDefaultsVersion:			2
 
 ?.Geometry:				800x600
 
@@ -215,10 +215,14 @@
 *file_menu*button_3.Accelerator:	Ctrl<Key>s
 *file_menu*button_3.AcceleratorText:	Ctrl+S
 
-*file_menu*button_4.XmString:		Exit
-*file_menu*button_4.Mnemonic:		E
-*file_menu*button_4.Accelerator:	Ctrl<Key>c
-*file_menu*button_4.AcceleratorText:	Ctrl+C
+*file_menu*button_4.XmString:		Save As Left...
+*file_menu*button_5.XmString:		Save As Right...
+
+*file_menu*button_6.XmString:		Exit
+*file_menu*button_6.Mnemonic:		E
+*file_menu*button_6.Accelerator:	Ctrl<Key>c
+*file_menu*button_6.AcceleratorText:	Ctrl+C
+
 !
 !
 *view_menu*button_0.XmString:		Previous
--- spawn.c
+++ spawn.c
@@ -1,4 +1,4 @@
-#ifndef lint
+#if 0
 static char rcsid[] = "spawn.c,v 2.0 1994/05/19 02:01:23 dan Exp";
 #endif
 
@@ -35,6 +35,11 @@
 #include <stdlib.h>
 #include <errno.h>
 
+#include <X11/Intrinsic.h>
+
+#include "mgdiff.h"
+#include "externs.h"
+
 #define BLOCKSIZE 10
 
 /* 
@@ -105,7 +110,7 @@
 	argv[argc++] = NULL;
 
 	if (execvp (prog, argv) == -1) {
-	    (void) sprintf (buffer, "%s: %s: %s", progname, "exec", prog);
+	    (void) snprintf (buffer, sizeof (buffer), "%s: %s: %s", progname, "exec", prog);
 	    perror (buffer);
 	    exit (2);
 	}
@@ -131,4 +136,5 @@
 	break;
     }
     /* NOTREACHED */
+    return NULL;
 }
--- files.c
+++ files.c
@@ -1,9 +1,10 @@
-#ifndef lint
+#if 0
 static char rcsid[] = "files.c,v 2.0 1994/05/19 02:01:06 dan Exp";
 #endif
 
 /*
  * Copyright (c) 1994    Daniel Williams
+ * Copyright (c) 2003    Erik de Castro Lopo
  * 
  * The X Consortium, and any party obtaining a copy of these files from
  * the X Consortium, directly or indirectly, is granted, free of charge,
@@ -83,16 +84,18 @@
  */
 static int is_ascii_text (char *filename)
 {
-    int fd, bytes, i;
+    int fd, bytes, i, ch;
     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]))
+    for (i = 0; i < bytes; i++) {
+	ch = buffer [i];
+	if (!isallowed(ch))
 	    return (0);
+    }
     return (1);
 }
 
@@ -143,7 +146,7 @@
     XmString xms;
     Arg args[2];
 
-    (void) sprintf (buffer, "%s: %s", msg1, msg2);
+    (void) snprintf (buffer, sizeof (buffer), "%s: %s", msg1, msg2);
     xms = XmStringCreateLtoR (buffer, XmSTRING_DEFAULT_CHARSET);
     XtSetArg (args[0], XmNmessageString, xms);
     XtSetArg (args[1], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL);
@@ -318,7 +321,7 @@
     Arg args[2];
     int i;
     char *dir;
-    XmString xms;
+    XmString xms = NULL ;
 
     shell = XtVaCreatePopupShell ("openfiles", xmDialogShellWidgetClass, parent,
 				  XmNallowShellResize, True,
@@ -424,7 +427,7 @@
     Arg args[2];
     int i;
     char *dir;
-    XmString xms;
+    XmString xms = NULL ;
 
     i = 0;
     XtSetArg (args[i], XmNdeleteResponse, XmDO_NOTHING); i++;
@@ -477,7 +480,7 @@
     Arg args[2];
     int i;
     char *dir;
-    XmString xms;
+    XmString xms = NULL ;
 
     i = 0;
     XtSetArg (args[i], XmNdeleteResponse, XmDO_NOTHING); i++;
@@ -533,7 +536,7 @@
     if (access (filename, W_OK) == 0) {	/* file exists and can be written */
 	char buffer[1024];
 
-	(void) sprintf (buffer, "Overwrite \"%s\"?", filename);
+	(void) snprintf (buffer, sizeof (buffer), "Overwrite \"%s\"?", filename);
 	if (modal_question (w, "Mgdiff Save Question", buffer)) {
 	    set_cursor (shell);
 	    if ((status = really_save_file (filename, (Block *) closure)) != 0) {
@@ -569,7 +572,7 @@
     Arg args[3];
     int i;
     char *dir;
-    XmString xms;
+    XmString xms = NULL ;
 
     i = 0;
     XtSetArg (args[i], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); i++;
@@ -618,18 +621,32 @@
 		return (status);
 	}
 	else if ((b->arr[LEFT].type == DIFF) && (b->arr[RIGHT].type == DIFF)) {
-	    assert (b->selected != NEITHER);
+	    switch (b->selected) {
+		case BOTH:
+		    fprintf (file, "<<<<<<< diff from left file\n");
+		    if ((status = write_chunk (file, &b->arr[LEFT])) != 0)
+			return (status);
+		    fprintf (file, "========\n");
+		    if ((status = write_chunk (file, &b->arr[RIGHT])) != 0)
+			return (status);
+		    fprintf (file, ">>>>>>> diff from right file\n");
+		    break;
+		case LEFT:
+		case RIGHT:
 	    if ((status = write_chunk (file, &b->arr[b->selected])) != 0)
 		return (status);
+		    break;
+		case NEITHER:
+		    break;
+		default : assert (False);
+	    }
 	}
 	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);
@@ -669,3 +686,45 @@
 
     return (0);
 }
+
+void save_as_filename (Widget parent, Block *closure, char *filename)
+{	
+    char *title = "Mgdiff Save Error";
+    int status;
+    Widget shell = get_top_shell (parent);
+
+    if (access (filename, W_OK) == 0) {
+	/* file exists and can be written */
+	char buffer[1024];
+
+	(void) snprintf (buffer, sizeof (buffer), "Overwrite \"%s\"?", filename);
+	if (modal_question (parent, "Mgdiff Save Question", buffer)) {
+	    set_cursor (shell);
+	    if ((status = really_save_file (filename, (Block *) closure)) != 0) {
+		reset_cursor (shell);
+		werror (parent, 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 (parent, title, filename, strerror (status));
+		return;
+	    }
+	    reset_cursor (shell);
+	}
+	else {
+	    /* for some other reason */
+	    werror (parent, title, filename, strerror (errno));
+	    return;
+	}
+    }
+
+} /* save_as_filename */
--- manual.c
+++ manual.c
@@ -1,4 +1,4 @@
-#ifndef lint
+#if 0
 static char rcsid[] = "manual.c,v 2.0 1994/05/19 02:01:09 dan Exp";
 #endif
 
@@ -134,14 +134,14 @@
 	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);
+	    (void) snprintf (buffer, sizeof (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);
+	    (void) snprintf (buffer, sizeof (buffer), "Shell command (resource \"manCommand\"):\n\n\"%s\"\n\nproduced no output", cmd);
 	    xms = XmStringCreateLtoR (buffer, XmSTRING_DEFAULT_CHARSET);
 	    iserror = 1;
 	}
@@ -151,7 +151,7 @@
 
 	    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);
+	    (void) snprintf (buffer, sizeof (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;
 	}
--- debian/README.debian
+++ debian/README.debian
@@ -0,0 +1,39 @@
+mgdiff for DEBIAN
+----------------------
+
+I've added an awk script called "rmgdiff" that allows you to use
+mgdiff (or tkdiff etc.) to graphically and recursively diff two
+directories.
+
+Paul Serice <ugs@debian.org>, Tue, 25 Aug 1998 23:05:16 -0500
+
+               -----------------------------
+
+I've applied lots of patches from Erik de Castro Lopo <erikd AT
+mega-nerd DOT com>. Main new features for the user are:
+
+  - Save As Left... / Save As Right... in File menu
+  - saving without having selected all textblocks is possible
+  - click-middle-button selects both sides, the resulting file gets
+    markers like CVS uses
+  - changes documented in manpage
+
+See the changelog entry of 1.0-20 for a complete list of changes and
+the manpage for more explanations of the new features. Thanks Erik,
+great work!
+
+Edelhard Becker <edelhard@debian.org>, Sat, 07 Jun 2003 16:02:26 +0200
+
+               -----------------------------
+
+I've got another useful patch from Roger Gammans <roger@computer-
+surgery.co.uk> which add two features (see his "Patch Viewer" page
+http://www.sandman.uklinux.net/patchv/default.html for more info):
+
+  - X Paste of the most recently selected diff hunk. 
+  - A wrapper to view patches, by appliy them to a temporary file first 
+
+The latter is installed as /usr/share/doc/mgdiff/viewpatch, thanks
+Roger!
+
+Edelhard Becker <edelhard@debian.org>, Thu, 08 Apr 2004 00:42:30 +0200
--- debian/control
+++ debian/control
@@ -0,0 +1,15 @@
+Source: mgdiff
+Section: text
+Priority: optional
+Maintainer: Edelhard Becker <edelhard@debian.org>
+Build-Depends: xutils, lesstif2-dev, debhelper (>= 4)
+Standards-Version: 3.6.1
+
+Package: mgdiff
+Architecture: any
+Depends: ${shlibs:Depends}, debianutils (>=1.7), file, mawk
+Description: xdiff clone
+ mgdiff is modeled after xdiff and provides a nice graphical interface
+ for comparing the contents of two text files.  rmgdiff recurses down
+ two directories collating difference information and invoking mgdiff
+ whenever two text files differ.
--- debian/prerm
+++ debian/prerm
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+#DEBHELPER#
+
+if [ -L /usr/doc/mgdiff ]; then
+	rm -f /usr/doc/mgdiff
+fi
--- debian/rules
+++ debian/rules
@@ -0,0 +1,66 @@
+#!/usr/bin/make -f
+# Made with the aid of debmake, by Christoph Lameter,
+# based on the sample debian/rules file for GNU hello by Ian Jackson.
+
+export DH_COMPAT=4
+package=mgdiff
+
+build:
+	dh_testdir
+	xmkmf
+	make depend XMULIBONLY=""
+	make XMULIBONLY=""
+	touch build
+
+clean:
+	dh_testdir
+	-rm -f build
+	-make clean
+	-rm -f `find . -name "*~"`
+	-rm -rf debian/mgdiff debian/files* core debian/substvars
+
+binary-indep: build
+	dh_testdir
+	dh_testroot
+# There are no architecture-independent files to be uploaded
+# generated by this package.  If there were any they would be
+# made here.
+
+binary-arch: build
+	dh_testdir
+	dh_testroot
+	-rm -rf debian/mgdiff
+	install -d debian/mgdiff debian/mgdiff/usr/bin debian/mgdiff/usr/share/man/man1 debian/mgdiff/usr/share/doc/mgdiff
+	make install BINDIR=`pwd`/debian/mgdiff/usr/bin \
+		XAPPLOADDIR=`pwd`/debian/mgdiff/etc/X11/app-defaults \
+		XMULIBONLY=""
+	make install.man MANDIR=`pwd`/debian/mgdiff/usr/share/man/man1 XMULIBONLY=""
+	mkdir -p debian/mgdiff/usr/lib/rmgdiff
+	install -m 755 debian/rmgdiff debian/mgdiff/usr/lib/rmgdiff
+	install -m 644 debian/rmgdiff.awk debian/mgdiff/usr/lib/rmgdiff
+	ln -s ../lib/rmgdiff/rmgdiff debian/mgdiff/usr/bin
+	install -m 755 debian/cvsmgdiff debian/mgdiff/usr/bin
+	install -m 644 debian/cvsmgdiff.1 debian/mgdiff/usr/share/man/man1
+	install -m 644 debian/rmgdiff.1x debian/mgdiff/usr/share/man/man1
+	install -m 644 debian/mgdiff.README debian/mgdiff/usr/share/doc/mgdiff
+	install -m 755 debian/viewpatch debian/mgdiff/usr/share/doc/mgdiff
+	chmod u+w debian/mgdiff/usr/share/man/man1/mgdiff.1x
+	chmod u+w debian/mgdiff/etc/X11/app-defaults/Mgdiff
+	dh_testdir
+	dh_installdirs
+	dh_installdocs
+	dh_installman
+	dh_installchangelogs 
+	dh_link
+	dh_strip
+	dh_compress
+	dh_fixperms
+	dh_installdeb
+	dh_shlibdeps
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+binary: binary-indep binary-arch
+
+.PHONY: binary binary-arch binary-indep clean
--- debian/rmgdiff
+++ debian/rmgdiff
@@ -0,0 +1,183 @@
+#!/bin/sh
+
+# Default value for the RMGDIFF_GUI environment variable.
+: ${RMGDIFF_GUI:=/usr/bin/mgdiff}
+
+#
+# You shouldn't need to edit beneath here.
+#
+
+SHOW_FILE_TYPES="TRUE"
+USE_CVS=""
+DEBUG=""
+USE_GUI="TRUE"
+RMGDIFF_VERSION=""
+
+
+
+Usage() {
+cat <<-EOF
+
+Usage: `basename "$0"` [-b] [-c] [-d] [-g <gui>] [-n] [-v] <dir1> <dir2>
+
+    -b: basic reporting (no file type info will be printed)
+    -c: cvs files will be included in diff
+    -d: print debugging information
+    -g: which gui to use
+    -n: no gui will pop up
+    -v: version
+
+EOF
+}
+
+verify_exec () {
+    type "$1" 1>/dev/null 2>&1
+    if [ $? -ne 0 ] ; then
+        echo "$progname: Error: Unable to find executable for \"$1\"." >&2
+        exit 1
+    fi
+}
+
+# Some machines don't have a "readlink" command.
+read_link_via_ls() {
+    if [ $# -ne 1 ] ; then
+        echo "$progname: Internal Error: Invalid args for" \
+             "readlink_via_ls: $@" >&2
+        exit 1
+    fi
+
+    \ls -l "$1" | sed -e 's|.*-> ||'
+}
+
+
+# Some machines don't have a "realpath" command.  follow_link_via_ls
+# does not pretend to be "realpath" because it will leave all sorts of
+# cruft in the path string, but it should eventuall reach a regular
+# file.
+follow_link_via_ls() {
+
+    if [ $# -ne 1 ] ; then
+        echo "$progname: Internal Error: Invalid args for" \
+             "follow_link_via_ls: $@" >&2
+        exit 1
+    fi
+
+    local_iteration_count=0
+    local_iteration_max=1024
+
+    # Prime the pump.
+    local_tmp=
+    local_rv="$1"
+
+    while [ $local_iteration_count -lt $local_iteration_max ] ; do
+
+        if [ ! -h "$local_rv" ] ; then
+            break
+        fi
+
+        local_tmp=`read_link_via_ls "$local_rv"`
+
+        # The "read_link_via_ls" above could result in an absolute
+        # path or a relative one.  The Solaris /bin/sh does not
+        # support "${PSTREE_AWK_SCRIPT#/}".  So, use grep instead.
+        echo "$local_tmp" | grep '^/' >/dev/null 2>&1
+        if [ $? -ne 0 ] ; then
+            # The path given by readlink was relative.  So, we have a
+            # little more work to do because we need to prepend the
+            # same path used to reach the original symlink.
+            local_tmp=`dirname "$local_rv"`/"$local_tmp"
+        fi
+
+        local_rv="$local_tmp"
+
+        local_iteration_count=`expr $local_iteration_count + 1`
+
+    done
+
+    if [ $local_iteration_count -ge $local_iteration_max ] ; then
+        echo "$progname: Error: Symbolic link nesting is too deep when" \
+             "following \"$1\"." >&2
+        exit 1
+    fi 
+
+    echo "$local_rv"
+
+}
+
+
+#
+# Script starts here.
+#
+
+progname="rmgdiff"
+verify_exec "basename"
+progname=`basename "$0"`
+
+verify_exec "awk"
+verify_exec "diff"
+verify_exec "dirname"
+verify_exec "expr"
+verify_exec "file"
+verify_exec "grep"
+verify_exec "ls"
+verify_exec "$RMGDIFF_GUI"
+verify_exec "sed"
+
+while getopts "bcdg:nv" OPT ; do
+    case "$OPT" in
+        b)  SHOW_FILE_TYPES=""
+            ;;
+        c)  USE_CVS="TRUE"
+            ;;
+        d)  DEBUG="TRUE"
+            ;;
+        g)  RMGDIFF_GUI="$OPTARG"
+            ;;
+        n)  USE_GUI=""
+            ;;
+        v)  RMGDIFF_VERSION="TRUE"
+            ;;
+        \?) Usage
+            exit 1
+            ;;
+    esac
+done
+shift `expr $OPTIND - 1`
+
+#
+# Find the rmgdiff awk script.  It is located in the same directory as
+# this shell script after following all the symlinks.
+#
+lib_dir=`follow_link_via_ls "$0"`
+RMGDIFF_AWK=`dirname "$lib_dir"`/rmgdiff.awk
+
+
+# If the user just wants the version ...
+if [ -n "$RMGDIFF_VERSION" ] ; then
+    exec awk -v version="$RMGDIFF_VERSION" -f "$RMGDIFF_AWK"
+fi
+
+if [ $# -lt 2 ] || [ $# -gt 2 ] ; then
+    Usage
+    exit 1
+fi
+
+if [ ! -d "$1" ] ; then
+    echo "$progname: dir1=\"$1\" is not a directory." 1>&2
+    exit 1
+fi
+
+if [ ! -d "$2" ] ; then
+    echo "$progname: dir2=\"$2\" is not a directory." 1>&2
+    exit 1
+fi
+
+exec diff -rq "$1" "$2" | awk -v debug="$DEBUG" \
+                              -v dir1="$1" \
+                              -v dir2="$2" \
+                              -v rmgdiff_gui="$RMGDIFF_GUI" \
+                              -v show_file_types="$SHOW_FILE_TYPES" \
+                              -v use_cvs="$USE_CVS" \
+                              -v use_gui="$USE_GUI" \
+                              -v version="$RMGDIFF_VERSION" \
+                              -f "$RMGDIFF_AWK"
--- debian/changelog
+++ debian/changelog
@@ -0,0 +1,264 @@
+mgdiff (1.0-28) unstable; urgency=low
+
+  * bug fixes by Javier Fernández-Sanguino Peña <jfs@debian.org>
+    - Insecure /tmp usage in viewpatch example script (Closes: #335188)
+    - mgdiff: Allows user to set both input as '-' (Closes: #335191)
+    Thanks Javier!
+
+ -- Edelhard Becker <edelhard@debian.org>  Tue, 25 Oct 2005 22:48:37 +0200
+
+mgdiff (1.0-27) unstable; urgency=low
+
+  * updated Paul Serices rmgdiff shell and awk scripts to 1.8.1, available
+    from his rmgdiff page (see copyright file); this should fix problems with
+    filenames and dirs with spaces and gawk compatibility, thanks Paul!
+
+ -- Edelhard Becker <edelhard@debian.org>  Thu, 23 Jun 2005 22:14:26 +0200
+
+mgdiff (1.0-26) unstable; urgency=low
+
+  * fixed rmgdiff.1x typo, thanks A Costa (Closes: #310343)
+
+ -- Edelhard Becker <edelhard@debian.org>  Fri, 27 May 2005 17:37:17 +0200
+
+mgdiff (1.0-25) unstable; urgency=low
+
+  * switched to lesstif2, get rid of lesstif1
+  * switched to debhelper, get rid of debmake
+  * made debhelper version lintian-clean
+
+ -- Edelhard Becker <edelhard@debian.org>  Sat, 12 Mar 2005 22:33:35 +0100
+
+mgdiff (1.0-24) unstable; urgency=low
+
+  * bug fixes by Erik de Castro Lopo <erikd AT mega-nerd DOT com>:
+    - clean compiler warnigs (Closes: #271623)
+    - fix Ctrl-U/Ctrl-P handling (Closes: #271624)
+    - fix UTF8 handling (Closes: #135854)
+    Thanks Erik!
+
+ -- Edelhard Becker <edelhard@debian.org>  Thu,  7 Oct 2004 00:50:16 +0200
+
+mgdiff (1.0-23) unstable; urgency=low
+
+  * Removes Xmu references from the build process (Closes: Bug#256419, must
+    been there for ages, thanks Daniel).
+  * corrected manpage sections to 1x
+
+ -- Edelhard Becker <edelhard@debian.org>  Sun, 27 Jun 2004 14:50:55 +0200
+
+mgdiff (1.0-22) unstable; urgency=low
+
+  * included Roger Gammans <rgammans@computer-surgery.co.uk> "Patch Viewer"
+    plus necessary mgdiff patch
+  * Bumped to standards version 3.6.1
+
+ -- Edelhard Becker <edelhard@debian.org>  Thu,  8 Apr 2004 00:33:53 +0200
+
+mgdiff (1.0-21) unstable; urgency=low
+
+  * scrambled Eriks e-mail in the manpage also
+  * typo in man-page fixed (thx Erik pointing this out)
+
+ -- Edelhard Becker <edelhard@debian.org>  Wed,  9 Jul 2003 16:33:07 +0200
+
+mgdiff (1.0-20) unstable; urgency=low
+
+  * applied lots of patches from Erik de Castro Lopo <erikd AT mega-nerd DOT
+    com> (explanations from his e-mail to me):
+    - mgdiff-includes.diff: Fix a couple of missing includes.
+    - mgdiff-islatin.diff: Fix a warning message.
+    - mgdiff-sun-fix.diff: A fix for SUN Solaris.
+    - mgdiff-tempfile.diff: Replace use of tempnam() with something more
+      secure.
+    - mgdiff-warnings.diff: Remove compiler warnings when using CFLAGS equal
+      to -g -O2 -Wall -Wstrict-prototypes -Wmissing-prototypes [eb: added the
+      flags to the Imakefile].
+    - mgdiff-snprintf.diff: Replace all usage of sprintf() with snprintf().
+    - mgdiff-save-left-right.diff: Add file menu entries for "Save as Left..."
+      and "Save as Right...". Includes increment of APP_DEFAULTS_VERSION
+      number, mods to Mgdiff.ad and checks for correct app-default value.
+    - mgdiff-save-unselected.diff: Allow saving files with unselected blocks.
+    - mgdiff-select-both.diff: Add ability to select both sides by clicking
+      with the middle button. When both sides are selected the two blocks are
+      written to the output file using markings similar to the markings CVS
+      palces in a file when a merge goes wrong.
+    - mgdiff-man.diff: Update the man page to reflect the above changes. Also
+      added my own copyright to a couple of files where I made anything more
+      than minor changes. I'm quite happy to have my changes under the same
+      license as the original code.
+  * changed maintainer address to debian account
+  * Bumped to standards version 3.5.10
+  * updated README
+
+ -- Edelhard Becker <edelhard@debian.org>  Sat,  7 Jun 2003 16:07:42 +0200
+
+mgdiff (1.0-19) unstable; urgency=low
+
+  * Added NAME section to cvsmgdiff man page (closes: #141670).
+  * Bumped to standards version 3.5.8.0.
+  * New maintainer. Closes: #169554.
+
+ -- Edelhard Becker <becker@edelhard.de>  Wed, 26 Feb 2003 19:01:20 +0100
+
+mgdiff (1.0-18) unstable; urgency=low
+
+  * Change source maintainer to myself (closes: #71915).
+  * Make cvsmgdiff a bash script (bash should handle anything pdksh does).
+  * Write a manpage for cvsmgdiff.
+  * Add dh_strip to rules (fixes lintian warning).  
+  * Add debhelper to Build-Depends.
+
+ -- Ian Zimmerman <itz@speakeasy.org>  Fri, 15 Feb 2002 12:38:38 -0800
+
+mgdiff (1.0-17) unstable; urgency=low
+
+  * Fixed not being able to specify the cvsmgdiff gui from the command
+    line.  There is now a -g flag.
+  * Also fixed a problem with where mgdiff was not comming up when
+    the -r option was used exactly once on the command line.
+
+ -- Paul Serice <paul@serice.net>  Tue,  5 Feb 2002 13:09:08 -0600
+
+mgdiff (1.0-16) unstable; urgency=low
+
+  * Better dependencies in the Debian "control" file.
+  * Introduced the "cvsmgdiff" script for comparing a revision in your
+    CVS archive with what is currently checked out or for comparing
+    two revision both of which are in the archive.  It works with
+    "mgdiff" (of course), xdiff, xxdiff, and tkdiff (not that tkdiff
+    needs this script).
+  * Portable way to move rmgdiff.awk out of /usr/bin and into
+    /usr/lib/rmgdiff where it should have been in the first place.
+
+ -- Paul Serice <paul@serice.net>  Sat, 26 Jan 2002 23:06:47 -0600
+
+mgdiff (1.0-15) unstable; urgency=low
+
+  * Debian QA Upload.
+  * New version built by Paul Serice <paul@serice.net>
+    Fri, 26 Oct 2001 03:19:15 -0500; Thank you for your contribution:
+    - This is getting embarrassing. Previous version introduced a bug
+      that caused the "only in" sanity check to be triggered (yes,
+      again) when a file was only in one directory but had a minimum
+      depth of 2.
+
+ -- Peter Palfrader <weasel@debian.org>  Sun, 28 Oct 2001 01:55:22 +0200
+
+mgdiff (1.0-14) unstable; urgency=low
+
+  * Debian QA Upload.
+  * New version built by Paul Serice <paul@serice.net>
+    Thu, 27 Sep 2001 20:33:15 -0500; Thanks Paul:
+    - Fatal bug in rmgdiff caused by working on two directories the last
+      one was a superstring of the first one is fixed.
+  * Removed emacs mode commands from debian/changelog.
+  * /etc/X11/app-defaults/Mgdiff tagged as conffile.
+
+ -- Peter Palfrader <weasel@debian.org>  Sat, 29 Sep 2001 23:24:31 +0200
+
+mgdiff (1.0-13) unstable; urgency=low
+
+  * Debian QA Upload.
+  * Changed maintainer email address from debian-qa@lists.debian.org
+    to packages@qa.debian.org.
+  * New version built by Paul Serice <paul@serice.net>
+    Fri, 21 Sep 2001 01:29:06 -0500; Thanks Paul:
+    - Merged patch from Polish(ed) distribution, closes: #96085
+      (mgdiff has wrong heuristics for determining whether a file is
+      text or not).
+    - rmgdiff failed to escape meta-characters in directory names causing
+      directories like "c++_src" to trigger a sanity check.
+
+ -- Peter Palfrader <weasel@debian.org>  Sat, 22 Sep 2001 15:42:00 +0200
+
+mgdiff (1.0-12) unstable; urgency=low
+
+  * Fixed RMGDIFF_GUI variable in /usr/bin/rmgdiff.
+  * Added license and author of rmgdiff to copyright file.
+  * Thanks Paul, closes: #87929.
+
+ -- Peter Palfrader <weasel@debian.org>  Wed, 28 Feb 2001 03:40:31 +0000
+
+mgdiff (1.0-11) unstable; urgency=low
+
+  * Made Build-Depends: xutils, lesstif-dev, debmake (closes: #83848).
+  * Some app-defaults bugs have not been closed by last changelog:
+    (closes: #81421, #81383)
+  * Added support for DEB_BUILD_OPTIONS.
+  * Removed diff from Depends. diff is essential.
+  * Changed man path from usr/X11R6/man to /usr/share/man.
+  * Install binaries in usr/bin instead of usr/X11R6/bin.
+  * Moved doc from /usr/doc to /usr/share/doc and create symlink.
+  * Calling dpkg-gencontrol with -isp now, so Section and Priority fields
+    are in the pacakge.
+
+ -- Peter Palfrader <weasel@debian.org>  Sat, 24 Feb 2001 17:39:49 +0000
+
+mgdiff (1.0-10) unstable; urgency=low
+
+  * Rebuilt to move app-defaults file to /etc/X11, Closes: #86278
+
+ -- Joey Hess <joeyh@debian.org>  Fri, 16 Feb 2001 19:50:21 -0800
+
+mgdiff (1.0-9) unstable; urgency=low
+
+  * Paul orphaned the package a while back. Maintainer set to QA.
+
+ -- Joey Hess <joeyh@debian.org>  Fri, 29 Dec 2000 18:47:27 -0800
+
+mgdiff (1.0-8) unstable; urgency=low
+
+  * Fixed error in man page for rmgdiff.
+
+ -- Paul Serice <ugs@debian.org>  Sat, 13 Nov 1999 05:37:36 -0600
+
+mgdiff (1.0-7) unstable; urgency=low
+
+  * Added dependency on mawk.
+  * Fixed usage for rmgdiff:  -m should be -g.
+
+ -- Paul Serice <ugs@debian.org>  Tue, 26 Oct 1999 21:09:52 -0500
+
+mgdiff (1.0-6) unstable; urgency=low
+
+  * Linked against lesstif1.  Closes bug #48167.
+
+ -- Paul Serice <ugs@debian.org>  Sun, 24 Oct 1999 21:23:31 -0500
+
+mgdiff (1.0-5) unstable; urgency=low
+
+  * Added needed dependency on "file".
+
+ -- Paul Serice <ugs@debian.org>  Sat,  8 May 1999 15:30:37 -0500
+
+mgdiff (1.0-4) unstable; urgency=low
+
+  * I wrote "rmgdiff" to allow the user to recursively diff two
+    directories using any graphical diff viewer -- including
+    mgdiff.
+  * Compiled using libc6 with new naming convention.
+  * mgdiff man page was not in the correct directory.
+  * Added "mgdiff.README".
+  * Now using original source in tarball.
+
+ -- Paul Serice <ugs@debian.org>  Sun, 17 Jan 1999 23:05:44 -0600
+
+mgdiff (1.0-3) unstable; urgency=low
+
+  * Updated description to reflect Lesstif improvements.
+  * Changed architecture to 'any'.
+
+ -- Paul Serice <ugs@debian.org>  Mon, 26 Oct 1998 01:16:45 -0600
+
+mgdiff (1.0-2) unstable; urgency=low
+
+  * Changed architecture to all.
+
+ -- Paul Serice <ugs@debian.org>  Sat, 24 Oct 1998 23:08:56 -0500
+
+mgdiff (1.0-1) unstable; urgency=low
+
+  * Initial Release.
+
+ -- Paul Serice <ugs@debian.org>  Tue, 25 Aug 1998 23:05:16 -0500
--- debian/cvsmgdiff.1
+++ debian/cvsmgdiff.1
@@ -0,0 +1,182 @@
+.\" Automatically generated by Pod::Man version 1.16
+.\" Fri Feb 15 12:01:43 2002
+.\"
+.\" Standard preamble:
+.\" ======================================================================
+.de Sh \" Subsection heading
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Ip \" List item
+.br
+.ie \\n(.$>=3 .ne \\$3
+.el .ne 3
+.IP "\\$1" \\$2
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+
+.fi
+..
+.\" Set up some character translations and predefined strings.  \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote.  | will give a
+.\" real vertical bar.  \*(C+ will give a nicer C++.  Capital omega is used
+.\" to do unbreakable dashes and therefore won't be available.  \*(C` and
+.\" \*(C' expand to `' in nroff, nothing in troff, for use with C<>
+.tr \(*W-|\(bv\*(Tr
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+.    ds -- \(*W-
+.    ds PI pi
+.    if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.    if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\"  diablo 12 pitch
+.    ds L" ""
+.    ds R" ""
+.    ds C` ""
+.    ds C' ""
+'br\}
+.el\{\
+.    ds -- \|\(em\|
+.    ds PI \(*p
+.    ds L" ``
+.    ds R" ''
+'br\}
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr
+.\" for titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and
+.\" index entries marked with X<> in POD.  Of course, you'll have to process
+.\" the output yourself in some meaningful fashion.
+.if \nF \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
+..
+.    nr % 0
+.    rr F
+.\}
+.\"
+.\" For nroff, turn off justification.  Always turn off hyphenation; it
+.\" makes way too many mistakes in technical documents.
+.hy 0
+.if n .na
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear.  Run.  Save yourself.  No user-serviceable parts.
+.bd B 3
+.    \" fudge factors for nroff and troff
+.if n \{\
+.    ds #H 0
+.    ds #V .8m
+.    ds #F .3m
+.    ds #[ \f1
+.    ds #] \fP
+.\}
+.if t \{\
+.    ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+.    ds #V .6m
+.    ds #F 0
+.    ds #[ \&
+.    ds #] \&
+.\}
+.    \" simple accents for nroff and troff
+.if n \{\
+.    ds ' \&
+.    ds ` \&
+.    ds ^ \&
+.    ds , \&
+.    ds ~ ~
+.    ds /
+.\}
+.if t \{\
+.    ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+.    ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+.    ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+.    ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+.    ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+.    ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+.    \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+.    \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+.    \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+.    ds : e
+.    ds 8 ss
+.    ds o a
+.    ds d- d\h'-1'\(ga
+.    ds D- D\h'-1'\(hy
+.    ds th \o'bp'
+.    ds Th \o'LP'
+.    ds ae ae
+.    ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ======================================================================
+.\"
+.IX Title "CVSMGDIFF 1"
+.TH CVSMGDIFF 1 "Utility Scripts" "2002-02-15" "Utility Scripts"
+.SH NAME
+cvsmgdiff \- uses mgdiff to display differences between any two cvs revisions.
+.UC
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+\&\fBcvsmgdiff\fR [\fB\-v\fR|\fB\-h\fR|\fB\-g\fR \fIgui\fR|\fB\-r\fR \fIrev1\fR [\fB\-r\fR \fIrev2\fR]] \fIfile\fR ...
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+This manual page documents briefly  the cvsmgdiff program.
+This manual page was written for the Debian GNU/Linux distribution
+(but may be used by others), because the  original
+program does not have a manual page.
+.PP
+This script lets you recursively diff the \s-1CVS\s0 directories you have
+checked out.  To use, just pass in an optional revision levels and
+an optional file directory name.  This script then will show you the
+differences you're interested in.
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+.Ip "\fB\-v\fR" 4
+.IX Item "-v"
+Print version information successfully
+.Ip "\fB\-h\fR" 4
+.IX Item "-h"
+Print help information
+.Ip "\fB\-g\fR \fIgui\fR" 4
+.IX Item "-g gui"
+Use the program \fIgui\fR as the user interface (default: \fI/usr/bin/mgdiff\fR)
+.Ip "\fB\-r\fR \fIrevision\fR" 4
+.IX Item "-r revision"
+Specify the \s-1CVS\s0 revision to view.  If just one \fB\-r\fR option is given, view
+differences between that revision and the current file in the \s-1CVS\s0 working
+directory.  If two \fB\-r\fR options are given, compare those two revisions
+with each other.
+.SH "AUTHOR"
+.IX Header "AUTHOR"
+cvsmgdiff appears to have been written by Paul Serice.
+This manual page was written  by  Ian Zimmerman <itz@speakeasy.org>
+for the Debian GNU/Linux project, but may
+be used by others.  It was written with the assistance  of
+\&\fIpod2man\fR\|(1).
--- debian/mgdiff.README
+++ debian/mgdiff.README
@@ -0,0 +1,44 @@
+Mon May 16 21:52:32 EDT 1994
+
+This is mgdiff, a graphical front end to the Unix diff command based
+upon X11R[456] and the Motif widget set.  It allows the user to select
+two files for comparison, runs the diff command, parses the output and
+presents the results graphically.  This presentation can also be used
+to generate a user-specified merge of the two files into a third file.
+
+This program's appearance is based upon a program called gdiff, which
+runs only on Silicon Graphics workstations and for which source code
+is not provided.
+
+The program has been developed and tested in the following
+environment:
+
+	- Dell SVR4 Issue 2.2 
+	- cc and gcc 2.3.3
+	- X11R4 and X11R5
+	- Motif 1.1.4
+
+It has received some testing using SGI IRIX 5.2 with cc, X11R5 and
+Motif 1.2.3.
+
+It should build fairly painlessly with the Imakefile provided.  You
+may need to point the Imakefile at your Motif libraries.
+
+You will need to install the application defaults file correctly for
+the program to run at all.
+
+An XPM icon file is provided if your window manager can use it.
+
+A preformatted manual page is also provided for those who don't have
+DWB or it's equivalent.
+
+Please send your comments, bug reports, bug fixes etc. to:
+
+	mgdiff@sass.com
+
+Enjoy,
+Dan
+--
+Daniel Williams, Consultant | Systems & Scientific Software
+Internet: dan@sass.com      | 263 Forrest Avenue
+Voice: (215) 885-1573       | Elkins Park, PA  19027
--- debian/cvsmgdiff
+++ debian/cvsmgdiff
@@ -0,0 +1,245 @@
+#! /bin/bash
+
+#
+# This script lets you recursively diff the CVS directories you have
+# checked out.  To use, just pass in an optional revision levels and
+# an optional file directory name.  This script then will show you the
+# differences you're interested in.
+#
+#                                             -- Paul Serice
+#
+
+CVSMGDIFF_VERSION=1.1
+
+: ${MGDIFF:=/usr/bin/mgdiff}
+: ${TMP:=/tmp}
+
+function usage {
+    if [ $# -ne 1 ] ; then
+        echo "progname: Error: Invalid args for usage: \"$@\"" >&2
+        exit 1
+    fi
+    cmd=
+    cmd="$cmd echo >&2 ;"
+    cmd="$cmd echo \"Usage: $progname [-h] [-v]"
+    cmd="$cmd [-g <gui>] [[-r <rev1>] [-r <rev2>]] file\" >&$1 ;"
+    cmd="$cmd echo >&2"
+    eval "$cmd"
+    if [ $1 -eq 1 ] ; then
+        exit 0
+    fi
+    exit 1
+}
+
+function verify_exec {
+    if [ $# -ne 1 ] ; then
+        echo "$progname: Error: Invalid args for verify_exec: \"$@\"" >&2
+        exit 1
+    fi
+    if ! type "$1" >/dev/null 2>&1 ; then
+        echo "$progname: Error: Unable to find executable for \"$1\"." >&2
+        exit 1
+    fi
+}
+
+tmp_base="cvsmgdiff-$$."
+function clean_up {
+    # These signal handlers are rough.  It is, as far as I can tell,
+    # impossible to pass in the name of the currently active temporary
+    # files.  A reasonable alternative is to scan $TMP for files that
+    # match the pattern we use being careful not to allow a malicious
+    # user to trick us into deleting some other file.
+    find "$TMP" -maxdepth 1 \
+                -type f \
+                -links 1 \
+                -uid `id -u` \
+                -name "$tmp_base"'*' \
+                -print0 \
+    | xargs -r0 rm -f
+    exit 0
+}
+
+#
+# getunique() -- Finds two unique temporary file names.
+#
+getunique()
+{
+    old_umask=`umask`
+    umask 077
+    if ! tmp_file_1=$(mktemp -q "$TMP/${tmp_base}XXXXXX") ; then
+        echo "Error: Unable to allocate a necessary temporary file." >&2
+        exit 1
+    fi
+    
+    if ! tmp_file_2=$(mktemp -q "$TMP/${tmp_base}XXXXXX") ; then
+        echo "Error: Unable to allocate a necessary temporary file." >&2
+        exit 1
+    fi
+    umask $old_umask
+}
+
+#
+# Script Starts Here !!!
+#
+
+progname="cvsmgdiff.sh"
+verify_exec "basename"
+progname=`basename $0`
+
+# Signal Trap handler to clean up temporary files in "$TMP".
+if ! trap 'clean_up' HUP INT QUIT TERM ; then
+    echo "$progname: Unable to register signal handler." >&2
+    exit 1
+fi
+
+# Get cvs revision(s) to use.
+cnt=0
+while getopts "g:hr:v" OPT ; do
+    case "$OPT" in
+        g)  MGDIFF="$OPTARG"
+            ;;
+        h)  usage 1
+            ;;
+        r)  rev[$cnt]="-r$OPTARG"
+            cnt=`expr $cnt + 1`
+            ;;
+        v)  echo "$progname: ${CVSMGDIFF_VERSION}"
+            exit 0
+            ;;
+        \?) usage 2
+            ;;
+    esac
+done
+shift `expr $OPTIND - 1`
+
+verify_exec "cut"
+verify_exec "cvs"
+verify_exec "echo"
+verify_exec "expr"
+verify_exec "find"
+verify_exec "grep"
+verify_exec "$MGDIFF"
+verify_exec "mktemp"
+verify_exec "sleep"
+verify_exec "xargs"
+
+mgdiff_basename=`basename "$MGDIFF"`
+
+# Portability issues.
+if [ "$mgdiff_basename" = "mgdiff" ] ; then
+    QUIET_OPT="-quit"
+    FNAME_OPT="-file"
+elif [ "$mgdiff_basename" = "xdiff" ] ; then
+    QUIET_OPT="-D"
+    FNAME_OPT="-N"
+elif [ "$mgdiff_basename" = "xxdiff" ] ; then
+    QUIET_OPT="-D"
+    FNAME_OPT="-N"
+    TITLE_1_OPT="--title1"
+    TITLE_2_OPT="--title2"
+fi
+
+if [ $cnt -gt 2 ] ; then
+    echo
+    echo "Error: Too many revisions."
+    echo
+    exit 1
+fi
+
+if [ ! -d `pwd`"/CVS" ] && [ ! -d `pwd`"/$1/CVS" ] ; then
+    echo
+    echo "Warning: \"$1\" does not appear to be a CVS directory." 1>&2
+    echo "Trying to diff \"$1\" with CVS repository anyway."
+    echo
+    sleep 5
+fi
+
+# Run CVS recursively on the entire directory.
+cvs diff "${rev[@]}" "$@" 2>/dev/null \
+| grep '^Index:' \
+| cut -d ' ' -f 2 \
+| while read fname ; do
+
+      echo -n "Processing $fname . . . "
+
+      # tkdiff CVS access built-in.
+      if [ "$mgdiff_basename" = "tkdiff" ] ; then
+
+          "$MGDIFF" ${rev[0]+"${rev[@]}"} "$fname"
+
+      # The others require a little bit of scripting.
+      elif [ $cnt -eq 2 ] ; then
+
+          getunique
+
+          \cvs update -p "${rev[0]}" "$fname" > "$tmp_file_1" 2> /dev/null
+          \cvs update -p "${rev[1]}" "$fname" > "$tmp_file_2" 2> /dev/null
+
+          "$MGDIFF" ${QUIET_OPT+"$QUIET_OPT"} \
+                    ${TITLE_1_OPT+"$TITLE_1_OPT" "$fname (rev ${rev[0]#-r})"} \
+                    ${TITLE_2_OPT+"$TITLE_2_OPT" "$fname (rev ${rev[1]#-r})"} \
+                    "$tmp_file_1" "$tmp_file_2"
+
+          \rm -f "$tmp_file_1" > /dev/null 2>&1
+          \rm -f "$tmp_file_2" > /dev/null 2>&1
+          
+      elif [ $cnt -le 1 ] ; then
+
+         if [ $cnt -eq 1 ] ; then
+             title_rev="${rev[0]#-r}"
+         else
+             title_rev=`cvs status "$fname" \
+                        | grep 'Working revision:' \
+                        | awk '{print $3;}'`
+         fi
+              
+          # For some reason, xxdiff does not like to work with pipes
+          # despite its saying otherwise.
+          if [ "$TITLE_1_OPT" ] ; then
+
+              getunique
+
+              # The convention that "diff" uses is that the old file is on
+              # the left and the new file is on the right.  We use this to
+              # display the files for all but "mgdiff" which has a
+              # "File->Save As..." menu option that works better the other
+              # way around.
+              file_first="$tmp_file_1"
+              file_second="$fname"
+              if [ "$mgdiff_basename" = "mgdiff" ] ; then
+                  file_first="$fname"
+                  file_second="$tmp_file_1"
+              fi
+
+              cvs update -p ${rev[0]+"${rev[0]}"} "$fname" \
+                     > "$tmp_file_1" 2>/dev/null
+              
+              "$MGDIFF" ${QUIET_OPT+"$QUIET_OPT"} \
+                        ${TITLE_1_OPT+"$TITLE_1_OPT" "$fname (rev $title_rev)"}\
+                        "$file_first" "$file_second"
+              
+              \rm -f "$tmp_file_1" > /dev/null 2>&1
+              \rm -f "$tmp_file_2" > /dev/null 2>&1
+
+          else
+
+              # See comment above.
+              file_first="-"
+              file_second="$fname"
+              if [ "$mgdiff_basename" = "mgdiff" ] ; then
+                  file_first="$fname"
+                  file_second="-"
+              fi
+
+              cvs update -p ${rev[0]+"${rev[0]}"} "$fname" 2>/dev/null \
+              | "$MGDIFF" ${QUIET_OPT+"$QUIET_OPT"} \
+                          ${FNAME_OPT+"$FNAME_OPT" "$fname (rev $title_rev)"} \
+                          "$file_first" "$file_second"
+
+          fi
+          
+      fi
+
+      echo "Done."
+
+  done
--- debian/viewpatch
+++ debian/viewpatch
@@ -0,0 +1,33 @@
+#!/bin/sh
+##
+#
+# (C) Roger Gammans 2001 (rgammans@computer-surgery.co.uk).
+#
+# Please distribute under the GPL.
+#
+# It's probably better to rely on the $PATH
+# to find the various external bits as they more likey
+# to be in it somewhere than one particluar location
+# over many unices.
+#
+
+FNAME=`tempfile` || { echo "$0: Cannot create temporary file" >&2; exit 1;  }
+trap " [ -f \"$FNAME\" ] && /bin/rm -f -- \"$FNAME\"" 0 1 2 3 13 15
+
+ORIG=$1
+PATCH=$2
+
+shift 2
+
+if [ -z "$ORIG" ] ||  [ ! -e "$ORIG" ] ; then
+	echo "$0: original file '$ORIG' does not exist"
+fi
+if [ -z "$PATCH" ] ||  [ ! -e "$PATCH" ] ; then
+	echo "$0: original file '$ORIG' does not exist"
+fi
+
+
+cp $ORIG $FNAME;
+if patch $* $FNAME  < $PATCH; then mgdiff $ORIG $FNAME; fi
+
+exit 0
--- debian/rmgdiff.1x
+++ debian/rmgdiff.1x
@@ -0,0 +1,98 @@
+.na
+.TH RMGDIFF 1x
+.SH NAME
+rmgdiff \- use almost any graphical file difference browser to recursively
+view the differences between two directories.
+.SH SYNOPSIS
+rmgdiff [-b] [-d] [-g gui] [-n] dir1 dir2
+.SH DESCRIPTION
+.LP
+.I rmgdiff
+is an awk script that works in conjunction with almost any graphical file
+difference browser.  It is known to work with 
+.IR mgdiff ,
+.IR tkdiff ,
+and
+.IR xdiff .
+.LP
+Unless I am mistaken, most of the GUI difference viewers (except for emacs)
+do not have built-in support for recursing down two directories, but
+.I diff
+does.  Based on
+.IR diff 's
+output, 
+.I rmgdiff
+decides when to invoke the graphical difference viewer.
+.LP
+In addition,
+.I rmgdiff
+also collates
+.IR diff 's
+output.  As soon as a new difference is encountered in a text file,
+.I rmgdiff
+will print to standard output the name of the file that both directories have
+in common.  It will then start the GUI and block until the user exits.
+As more text files with differences are found, the GUI will be started up
+again.
+.LP
+In the interim,
+.I rmgdiff
+will keep track of differences in binary (non-text) files.  It organizes
+the binary files as executables, shared libraries, static libraries, object
+files, and other.  Only after all the text files have been displayed will
+.I rmgdiff
+report the binary differences.
+.LP
+It also keeps track of files and directories that
+.I diff
+reports as being only in one directory or another.  
+.I rmgdiff
+organizes these entries by directory.  Thus, files in one directory
+will be reported in one block, and files that are in the other directory
+will be reported in a different block.
+.LP
+In addition to printing the name of the files that are different,
+.I rmgdiff
+defaults to printing the relevant portion of the output from the
+.I file
+command.  This has the unfortunate side-effect of slowing things down;
+however, I find this information to be invaluable.  If you're just looking
+for a fast way to collate 
+.IR diff 's
+output, try piping it into
+.I sort
+instead.
+
+.SH COMMAND LINE OPTIONS
+.TP 8
+.B \-b
+Sets the basic reporting mode.  In basic mode, rmgdiff reports only
+file names.  It does not report the file types involved.
+.TP 8
+.B \-c
+By default, files relating to
+.I CVS
+are ignored by
+.IR rmgdiff .
+If you want to include CVS files, use this option.
+.TP 8
+.B \-d
+Sets
+.I rmgdiff
+to print way too much debugging information.
+.TP 8
+\fB\-g\fP \fIgui\fP
+Tells
+.I rmgdiff
+which gui you would like to use for viewing differences.  By default,
+.I mgdiff
+is used.  You can also set $RMGDIFF_GUI in your environment, but it can
+be overridden with this option.
+.TP 8
+.B \-n
+.I rmgdiff
+will not invoke the gui.  This is useful, if you only want to view the 
+collated output.
+
+.SH AUTHOR
+Paul Serice (paul@serice.net)
--- debian/mgdiff.substvars
+++ debian/mgdiff.substvars
@@ -0,0 +1 @@
+shlibs:Depends=lesstif2, libc6 (>= 2.3.5-1), libice6 | xlibs (>> 4.1.0), libsm6 | xlibs (>> 4.1.0), libx11-6 | xlibs (>> 4.1.0), libxext6 | xlibs (>> 4.1.0), libxt6 | xlibs (>> 4.1.0)
--- debian/copyright
+++ debian/copyright
@@ -0,0 +1,42 @@
+This package was debianized by Paul Serice <ugs@debian.org> on
+Tue, 25 Aug 1998 23:05:16 -0500.
+
+It was downloaded from ftp://ftp.x.org/contrib/applications/mgdiff.tar.gz .
+
+Please note that rmgdiff is not a part of the mgdiff distribution.  Instead,
+it was written by your humble Debian maintainer.  rmgdiff is GNU
+copyrighted.
+
+The copyright for mgdiff as found in mgdiff.c of the source distribution
+is as follows:
+
+/*
+ * 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.
+ */
+
+
+rmgdiff was written by Paul Serice <paul@serice.net>. It has its homepage
+at http://www.serice.net/rmgdiff/ and is in public domain.
--- debian/rmgdiff.awk
+++ debian/rmgdiff.awk
@@ -0,0 +1,776 @@
+#
+# rmgdiff.awk
+#             -- awk script to that reads standard input for the output
+#                of "diff -rq <dir1> <dir2>".  It then takes diff's
+#                output and calls mgdiff once for each pair of text
+#                files that differ.  It prints out a message to this
+#                effect.  It then prints out a list of binary files
+#                that have differences followed by a list of files
+#                that appear only in the first directory followed by a
+#                list of files that appear only in the second
+#                directory.
+#
+#                It expects you to pass in <dir1> and <dir2> on the
+#                command line using awk's "-v" option.  You should
+#                find the shell script I use to call this file near
+#                where you found this file.
+#
+#                                            -- Paul Serice
+#
+
+#
+# Changes:
+#
+#  v1.8.1   Minor clean up.
+#
+#  v1.8.0   Testing revealed problems handling white space.
+#
+#  v1.7     Fixed a problem with the regular expression that
+#           escapes meta-characters in the escape_dir() function.
+#           Now, both gawk and mawk should be able to interpret this
+#           script.
+#
+#  v1.6     Changed the "rmgdiff" shell script wrapper so that this
+#           awk script does not have to be in the same directory.
+#           You can now place both "rmgdiff" and "rmgdiff.awk" in
+#           any directory and place a symbolic link in a "bin"
+#           directory that points to the "rmgdiff" shell script.
+#           The shell script will then follow the symbolic links
+#           in order to find the "rmgdiff.awk" script.  One way to
+#           set this up is as follows:
+#
+#                 /usr/local/lib/rmgdiff/rmgdiff
+#                 /usr/local/lib/rmgdiff/rmgdiff.awk
+#                 /usr/local/bin/rmgdiff -> ../lib/rmgdiff/rmgdiff
+#
+#  v1.5     I've said it before, and here I go again.  This time
+#           it's fixed.  v1.4 introduced a new bug related to the same
+#           section of code that v1.3 and v1.4 was trying to fix.
+#           This new bug manifested itself when a subdirectory was
+#           only in one directory and had a minimum depth of at least
+#           2.  Everything that was originally a bug and everything I
+#           subsequently broke now appears to work.
+#  v1.4     Was finally able to reproduce the bug that was causing
+#           reported directories to appear to have been split
+#           incorrectly.  Problem solved.
+#  v1.3     Forgot to escape the accidental meta-characters in the
+#           directory names.  Also, I am explicitly putting both the
+#           "rmgdiff" shell script and this "rmgdiff.awk" awk script
+#           in the public domain.  (It has always been in the public
+#           domain.  This just makes it official.  Use at your own
+#           risk.)
+#  v1.2     Changed the way the "rmgdiff" shell script initialized the
+#           RMGDIFF_GUI variable.
+#  v1.1     Fixed bug in "/^Binary file /" rule that used "$4" and "$6"
+#           instead of "$3" and "$5".
+#  v1.0     Initial release
+# 
+
+#
+# trim_dir(dir) -- A user can enter a directory such as "dir", "dir/", 
+#                  "dir//", etc.  trim_dirr() will reduce all of these
+#                  to "dir" by removing all trailing slashes.
+#
+function trim_dir( dir  ,  pos ) {
+  if( !dir )
+    return "";
+
+  pos = length(dir);
+  while( pos > 0 )
+    {
+      if( substr(dir, pos, 1) != "/" )
+        break;
+      pos--;
+    }
+
+  # If you made it back to the beginning, then "dir" was all slashes
+  # which is a synonym for the root dir.
+  if( pos <= 0 )
+    return "/";
+  else
+    return substr(dir, 1, pos);
+}
+
+
+#
+# escape_dir(dir) -- Escape the characters in the directory name that
+#                    are coincidentally meta characters.
+#
+function escape_dir(dir) {
+    gsub(/[[\]{}()^$. +|*?]/, "\\\\&", dir);
+    return dir;
+}
+
+
+#
+# relative_path(full_path, upper_dir)
+#
+#         This function strips off the upper most directory.  This
+#         lets you report a difference just by reporting the relative
+#         path.  Thus, "dir1/abcd/efgh" and "dir2/abcd/efgh" can be
+#         reported as being different by referring to "a difference in
+#         the abcd/efgh files that reside in both directories."
+#
+function relative_path( full_path, upper_dir  ,  pos ) {
+  if( index(full_path, upper_dir) != 1 )
+    {
+      print("***");
+      print("*** rmgdiff.awk: Internal error. ");
+      print("***              " upper_dir );
+      print("***              can't possibly be the base directory of ");
+      print("***              " full_path ".");
+      print("***");
+      exit_flag = 1;
+      exit(1);
+    }
+
+  pos = length(upper_dir) + 1;
+  full_path_len = length(full_path);
+
+  while( pos <= full_path_len )
+    {
+      if( substr(full_path, pos, 1) != "/")
+        break;
+      pos++;
+    }
+  
+  # If "pos" makes it all the way to the end of "full_path", then the
+  # user passed in the name of a single directory instead of a path.
+  if( pos == length )
+    return "";
+  else
+    return substr(full_path, pos);
+}
+
+
+#
+# get_file_type() -- Returns the relevant part of the description returned
+#                    by "file".  Unlike for Linux, the "file" command for
+#                    SGI will have in indeterminate number of spaces before
+#                    the relevant partion.  Hence the iterative solution.
+#                    Perhaps it would be better to use 'FS= ' (?).
+#
+function get_file_type( file_name, \
+                        cmd, pos, file_type, file_type_len, next_ch) {
+  cmd = file_cmd " \"" file_name "\"";
+  if( (cmd | getline file_type) == -1)
+    {
+      print("");
+      print("rmgdiff.awk:  Unable to determine file type of " $2 ".");
+      print("              This usually occurs because you don't have any " \
+                           "available");
+      print("              file descriptors or \"file\" is not in your path.");
+      print("");
+      exit_flag = 1;
+      exit(1);
+    }
+  close(cmd);
+
+  # Start right after the colon that always follows the file name.
+  pos = length(file_name) + 2;
+  file_type_len = length(file_type);
+
+  # Iterate until you find the first non-space and non-tab.  I did it
+  # like this because different versions of Unix have different spacing.
+  while( pos <= file_type_len )
+    {
+      next_ch = substr(file_type, pos, 1);
+      if( (next_ch != " ") && (next_ch != "\t") )
+        break;
+      pos++;
+    }
+  
+  if( pos > file_type_len )
+    {
+      print("***");
+      print("*** rmgdiff.awk: Internal error.  Missed a file type for");
+      print("***              "  file_name);
+      print("***");
+      exit_flag = 1;
+      exit(1);
+    }
+  
+  return substr(file_type, pos);
+}
+
+
+#
+# add_only_in(dir, str3, str4) -- routine to convert $3 and $4 of the
+#                                 output of diff when the file is only
+#                                 in one directory into something we can
+#                                 later print.
+#
+function add_only_in(dir, str3, str4  ,  middle, fullpath, file_type) {
+
+  middle = relative_path(str3, dir);
+  
+  if( middle == "" )
+    fullpath = dir "/" str4;
+  else
+    fullpath = dir "/" middle "/" str4;
+  
+  file_type = get_file_type(fullpath);
+  
+  if( debug )
+    print("file_type = " file_type);
+  
+  if( dir == dir1 )
+    {
+      if( debug )
+        print("Adding " fullpath " to only_in_dir1[" only_in_dir1_cnt "].");
+
+      if( show_file_types )
+        only_in_dir1[only_in_dir1_cnt++] = fullpath "  (" file_type ")";
+      else
+        only_in_dir1[only_in_dir1_cnt++] = fullpath;
+    }
+  else if( dir == dir2 )
+    {
+      if( debug )
+        print("Adding " fullpath " to only_in_dir2[" only_in_dir2_cnt "].");
+
+      if( show_file_types )
+        only_in_dir2[only_in_dir2_cnt++] = fullpath "  (" file_type ")";
+      else
+        only_in_dir2[only_in_dir2_cnt++] = fullpath;
+    }
+  else
+    {
+      print("***");
+      print("*** rmgdiff.awk: Internal error.  Can't figure out " \
+            "\"only in\" directory.");
+      print("***");
+      exit_flag = 1;
+      exit(1);
+    }
+}
+
+
+
+#
+# add_binary(full_name_1, full_name_2)
+#          -- Determines what type of binary a file is and adds it
+#             to the appropriate list for reporting later.  Make
+#             sure "full_name_1" is the full_name associated with
+#             "dir1" (which is a global variable).
+#
+
+function add_binary(full_name_1, full_name_2  ,  file_type_1, file_type_2) {
+  file_type_1 = get_file_type(full_name_1);
+  file_type_2 = get_file_type(full_name_2);
+  
+  if( debug )
+    {
+      print("full_name_1 = " full_name_1);
+      print("full_name_2 = " full_name_2);
+      print("file_type_1 = " file_type_1);
+      print("file_type_2 = " file_type_2);
+    }
+
+  if( file_type_1 ~ /executable/ && file_type_2 ~ /executable/ )
+    {
+      if( debug )
+        print("Adding " relative_path(full_name_1, dir1) \
+              " to executable_files[" executable_files_cnt "].");
+
+      if( show_file_types )
+        executable_files[executable_files_cnt++] \
+          = relative_path(full_name_1, dir1) "  (" file_type_1 ")";
+      else
+        executable_files[executable_files_cnt++] \
+          = relative_path(full_name_1, dir1);
+    }
+  else if( file_type_1 ~ /shared object/ && file_type_2 ~ /shared object/ )
+    {
+      if( debug )
+        print("Adding " relative_path(full_name_1, dir1) " to shared_libs[" \
+              shared_libs_cnt "].");
+
+      if( show_file_types )
+        shared_libs[shared_libs_cnt++] \
+          = relative_path(full_name_1, dir1) "  (" file_type_1 ")";
+      else
+        shared_libs[shared_libs_cnt++] \
+          = relative_path(full_name_1, dir1);
+    }
+  else if( file_type_1 ~ /ar archive/ && file_type_2 ~ /ar archive/ )
+    {
+      if( debug )
+        print("Adding " relative_path(full_name_1, dir1) " to static_libs[" \
+              static_libs_cnt "].");
+
+      if( show_file_types )
+        static_libs[static_libs_cnt++] \
+          = relative_path(full_name_1, dir1) "  (" file_type_1 ")";
+      else
+        static_libs[static_libs_cnt++] \
+          = relative_path(full_name_1, dir1);
+    }
+  else if( file_type_1 ~ /relocatable/ && file_type_2 ~ /relocatable/ )
+    {
+      if( debug )
+        print("Adding " relative_path(full_name_1, dir1) " to object_files[" \
+              object_files_cnt "].");
+
+      if( show_file_types )
+        object_files[object_files_cnt++] \
+          = relative_path(full_name_1, dir1) "  (" file_type_1 ")";
+      else
+        object_files[object_files_cnt++] \
+          = relative_path(full_name_1, dir1);
+    }
+  # gzip files report a date which is causing them to appear
+  # to be mismatched.  Avoid a mismatch with this rule.
+  else if ( file_type_1 ~ /gzip compressed data/ &&
+            file_type_2 ~ /gzip compressed data/ )
+    {
+      if( debug )
+        {
+	  print("Matched a gzipped file.  I'll be making up a type!!!");
+          print("Adding " relative_path(full_name_1, dir1) \
+                " to other_bin_files[" other_bin_files_cnt "].");
+        }
+
+      if( show_file_types )
+        other_bin_files[other_bin_files_cnt++] \
+          = relative_path(full_name_1, dir1) "  (gzip compressed data)";
+      else
+        other_bin_files[other_bin_files_cnt++] \
+          = relative_path(full_name_1, dir1);
+    }
+  # Mismatched types.
+  else if ( file_type_1 !~ file_type_2 )  
+    {
+      if( debug )
+        {
+          print("Adding " relative_path(full_name_1, dir1) \
+                " to mismatched_files[" mismatched_files_cnt "].");
+          print("File types differ!");
+        }
+      
+      mismatched_files[mismatched_files_cnt++] \
+        = relative_path(full_name_1, dir1) \
+          "  (Types differ.  See next two lines.)\n" \
+          "       " dir1 ":  (" file_type_1 ")\n" \
+          "       " dir2 ":  (" file_type_2 ")";
+    }
+  else
+    {
+      if( debug )
+        print("Adding " relative_path(full_name_1, dir1) \
+              " to other_bin_files[" other_bin_files_cnt "].");
+
+      if( show_file_types )
+        other_bin_files[other_bin_files_cnt++] \
+          = relative_path(full_name_1, dir1) "  (" file_type_1 ")";
+      else
+        other_bin_files[other_bin_files_cnt++] \
+          = relative_path(full_name_1, dir1);
+    }
+}
+
+
+#
+# add_text(full_name_1, full_name_2, file_type_1, file_type2)
+#          -- We don't really need to "add" an entry to note that
+#             we have found a text file.  Instead, we go ahead and
+#             print out the file's name and start up the GUI.
+#
+function add_text(full_name_1, full_name_2, file_type_1, file_type_2) {
+  if( debug )
+    {
+      print("full_name_1 = " full_name_1);
+      print("full_name_2 = " full_name_2);
+      print("file_type_1 = " file_type_1);
+      print("file_type_2 = " file_type_2);
+    }
+  
+  if( first_diff )
+    {
+      printf("\n*** DIFFERENT TEXT FILES ***\n\n");
+      first_diff = 0;
+    }
+  
+  if( file_type_1 == file_type_2 )
+    if( show_file_types )
+      print(relative_path(full_name_1, dir1) "  (" file_type_1 ")");
+    else
+      print(relative_path(full_name_1, dir1));
+  else
+    {
+      print("=====");
+      print(relative_path(full_name_1, dir1) "  (Types differ.  " \
+            "See next two lines)");
+      print("       " dir1 ":  (" file_type_1 ")");
+      print("       " dir2 ":  (" file_type_2 ")");
+      print("=====");
+    }
+  
+  if(use_gui)
+    system(rmgdiff_gui " \"" full_name_1 "\" \"" full_name_2 "\"");
+}
+
+
+#
+# add_text_or_binary(full_name_1, full_name_2)
+#              -- Used to detect whether we have text files that differ
+#                 or something else.  It sure would be nice if we could
+#                 pass these strings by reference.
+#
+function add_text_or_binary(full_name_1, full_name_2 , file_type_1, file_type_2)
+{
+  file_type_1 = get_file_type(full_name_1);
+  file_type_2 = get_file_type(full_name_2);
+  
+  if( (file_type_1 ~ /text/ || file_type_1 ~ /^empty$/) &&
+      (file_type_2 ~ /text/ || file_type_2 ~ /^empty$/) )
+    {
+      add_text(full_name_1, full_name_2, file_type_1, file_type_2);
+    }
+  else
+    {
+      add_binary(full_name_1, full_name_2);
+    }
+}
+
+
+
+function check_exec(exec  ,  cmd) {
+  cmd="type \"" exec "\" 1>/dev/null 2>&1";
+  if( system(cmd) != 0 )
+    {
+      printf("\nrmgdiff.awk: " exec " isn't executable.\n\n");
+      exit_flag = 1;
+      exit(1);
+    }
+}
+
+
+function check_dir(dir  ,  cmd) {
+  cmd = "[ -d \"" dir "\" ]";
+  if( system(cmd) != 0 )
+    {
+      printf("\nrmgdiff.awk: \"" dir "\" isn't a directory.\n\n");
+      exit_flag = 1;
+      exit(1);
+    }
+}
+
+
+function check_external_executables() {
+  # You only need a gui if debug is off.  Default to "mgdiff" if
+  # the user does not pass in a value.
+  if(use_gui && !rmgdiff_gui)
+    {
+      rmgdiff_gui = "mgdiff";
+    }
+  check_exec(rmgdiff_gui);
+
+  if(!file_cmd)
+    {
+      file_cmd = "file";
+    }
+  check_exec(file_cmd);
+
+  check_dir(dir1);
+  check_dir(dir2);
+}
+
+#
+# get_full_names(raw_diff_line, dir1, dir2, full_names)
+#     -- This function takes the raw output of "diff -rq" for lines of
+#        the form "... <file1> and <file2> differ" and returns <file1>
+#        and <file2> in "full_names[1]" and "full_names[2]" respectively.
+#        A special function is needed in order to account for those
+#        cases where the file names have embedded spaces.
+#
+function get_full_names(raw_diff_line, dir1, dir2, full_names  ,  regex) {
+  #
+  # full_names[2] -- The first call to gsub() strips off the trailing
+  # "differ".  The second call to gsub() strips from the beginning of
+  # the string to the "and" that precedes <file2>.  In case you missed
+  # it, we are calculating full_names[2] [sic] first.
+  #
+  full_names[2] = raw_diff_line;
+  gsub(/ differ$/, "", full_names[2]);
+  gsub("^.* and (" dir2 ")", dir2, full_names[2]);
+
+  #
+  # full_names[1] -- The first call to gsub() strips off the trailing
+  # "and <file2> differ".  The second call to gsub() strips from the
+  # beginning of the string up to <file1>.
+  #
+  full_names[1] = raw_diff_line;
+  sub(" and " full_names[2] " differ$", "", full_names[1]);
+  sub("^.* " dir1, dir1, full_names[1]);
+
+  if( debug ) {
+      print("full_names[1] = " full_names[1]);
+      print("full_names[2] = " full_names[2]);
+  }
+}
+
+
+
+BEGIN {
+  if( debug )
+    print("Start BEGIN");
+
+  if( version )
+    {
+      printf("\nrmgdiff.awk: v1.8.1\n\n");
+      exit_flag = 1;
+      exit 1;
+    }
+
+  first_diff = 1;            # Flag.
+
+  check_external_executables();
+
+  if( debug )
+    {
+      print("dir1 = " dir1);
+      print("dir2 = " dir2);
+    }
+
+  dir1 = trim_dir(dir1);
+  dir2 = trim_dir(dir2);
+
+  if( debug )
+    {
+      print("Trimmed dir1 to " dir1);
+      print("Trimmed dir2 to " dir2);
+      print("");
+    }
+
+  # When you want to match regular expressions, you need to escape any
+  # meta characters.  For example, if your directory where "c++_src",
+  # and you try to do the match in the /^Only in/ that checks the
+  # following:
+  # 
+  #       if( "c++_src" ~ "^" "c++_src" )
+  #
+  # it will fail because the "++" in the last term are meta characters
+  # that aren't matched.
+  dir1_escaped = escape_dir(dir1);
+  dir2_escaped = escape_dir(dir2);
+
+  if( debug )
+    {
+      print("dir1 escaped to " dir1_escaped);
+      print("dir2 escaped to " dir2_escaped);
+    }
+
+  if( length(dir1_escaped) >= length(dir2_escaped) ) {
+    longer_dir = dir1;
+    longer_dir_escaped = dir1_escaped;
+    shorter_dir = dir2;
+    shorter_dir_escaped = dir2_escaped;
+  } else {
+    longer_dir = dir2;
+    longer_dir_escaped = dir2_escaped;
+    shorter_dir = dir1;
+    shorter_dir_escaped = dir1_escaped;
+  }
+
+  if( debug )
+    {
+      print("longer_dir = " longer_dir);
+      print("longer_dir_escaped = " longer_dir_escaped);
+      print("shorter_dir = " shorter_dir);
+      print("shorter_dir_escaped = " shorter_dir_escaped);
+    }
+
+}
+
+
+{
+  # Show the current line.
+  if( debug )
+    print("Current line:  " $0);
+}
+
+
+
+# Find the files that differ.  Filter out the CVS entries.  Call mgdiff
+# if the file is a text file.  If the file is a binary, save it for later.
+/^Files / {
+  if( debug )
+    print("Start Text and Binary files");
+
+  if( !use_cvs && $0 ~ /[ \/]CVS([ \/:]|$)/ )
+    {
+      if( debug )
+        print("Skipping CVS file.\n");
+      next;
+    }
+
+  full_names[1] = "";
+  full_names[2] = "";
+  get_full_names($0, dir1, dir2, full_names);
+
+  add_text_or_binary(full_names[1], full_names[2]);
+}
+
+
+# This is here for compatibility with the older version of GNU diff
+# that reported binary and text file differences separately.
+/^Binary files / {
+  if( debug )
+    print("Start Binary files only");
+
+  if( !use_cvs && $0 ~ /[ \/]CVS([ \/:]|$)/ )
+    {
+      if( debug )
+        print("Skipping CVS file.\n");
+      next;
+    }
+
+  full_names[1] = "";
+  full_names[2] = "";
+  get_full_names($0, dir1, dir2, full_names);
+
+  add_binary(full_names[1], full_names[2]);
+}
+
+# Find the files that are only in one of the directories.  Filter out
+# the CVS entries.  Sort into two arrays for later printing.
+/^Only in / {
+  if( debug )
+    print("Start Only in");
+
+  if( !use_cvs && $0 ~ /[ \/]CVS([ \/:]|$)/ )
+    {
+      if( debug )
+        print("Skipping CVS file.\n");
+      next;
+    }
+
+  # Find the directory.
+  only_in_dir = substr($0, length("Only in ") + 1);
+  gsub(/: .*$/, "", only_in_dir);
+
+  # Find the file that is only in "only_in_dir".
+  only_file = $0;
+  gsub(/^.*: /, "", only_file);
+
+  if( debug )
+    {
+      print("only_in_dir = " only_in_dir);
+      print("only_file = " only_file);
+    }
+
+  #
+  # A space means to concatenate the strings.  So,
+  #
+  #        only_in_dir ~ "^" longer_dir_escaped
+  #
+  #
+  # means you have a match if only_in_dir begins with longer_dir_escaped.
+  #
+  # You have to NOT anchor the end of the string to match.  The reason
+  # is that you could easily get the situation where a file or
+  # directory is only in one of the directories you are recursively
+  # diffing, and it has a depth of 2 or more.  (Note, "depth" here is
+  # the same concept as the "find" command's "-maxdepth" parameter.)
+  # This means you don't know what is going to be at the end of only_in_dir.
+  #
+  # You have to test the longer directory first because you might be
+  # diffing two directories named something like "my_dir" and
+  # "my_dir-v1.0".  If you tested the shorter directory first, you
+  # would always get a match because when only_in_dir is the longer directory,
+  # it too matches the shorter directory.
+  #
+
+  if( only_in_dir ~ "^" longer_dir_escaped ) {
+      add_only_in(longer_dir, only_in_dir, only_file);
+  }
+  else if( only_in_dir ~ "^" shorter_dir_escaped ) {
+      add_only_in(shorter_dir, only_in_dir, only_file);
+  } else {
+      print("***");
+      print("*** rmgdiff.awk: Internal error.  Missed an \"only in\".");
+      print("***    only_in_dir = " only_in_dir);
+      print("***");
+      exit_flag = 1;
+      exit(1);
+    }
+
+}
+
+
+# Just print a line to separate output for each pass.
+{
+  if( debug )
+    print("");
+}
+
+
+# Print out the entries you earlier saved to an array.
+END {
+  if( !exit_flag )
+    {
+
+      # I decided to not create a separate function for printing
+      # reports because you can't pass these potentially large
+      # arrays by reference.
+
+      if( executable_files_cnt )
+        {
+          printf("\n*** DIFFERENT EXECUTABLES ***\n\n");
+          for( i = 0 ; i < executable_files_cnt ; i++ )
+            print(executable_files[i]);
+        }
+
+      if( shared_libs_cnt )
+        {
+          printf("\n*** DIFFERENT SHARED LIBRARIES ***\n\n");
+          for( i = 0 ; i < shared_libs_cnt ; i++ )
+            print(shared_libs[i]);
+        }
+
+      if( static_libs_cnt )
+        {
+          printf("\n*** DIFFERENT STATIC LIBRARIES ***\n\n");
+          for( i = 0 ; i < static_libs_cnt ; i++ )
+            print(static_libs[i]);
+        }
+
+      if( object_files_cnt )
+        {
+          printf("\n*** DIFFERENT OBJECT FILES ***\n\n");
+          for( i = 0 ; i < object_files_cnt ; i++ )
+            print(object_files[i]);
+        }
+
+      if( other_bin_files_cnt )
+        {
+          printf("\n*** OTHER DIFFERENT BINARY FILES ***\n\n");
+          for( i = 0 ; i < other_bin_files_cnt ; i++ )
+            print(other_bin_files[i]);
+        }
+      
+      if( only_in_dir1_cnt )
+        {
+          printf("\n*** FILES ONLY IN %s ***\n\n", dir1);
+          for( i = 0 ; i < only_in_dir1_cnt ; i++ )
+            print(only_in_dir1[i]);
+        }
+      
+      if( only_in_dir2_cnt )
+        {
+          printf("\n*** FILES ONLY IN %s ***\n\n", dir2);
+          for( i = 0 ; i < only_in_dir2_cnt ; i++ )
+            print(only_in_dir2[i]);
+        }
+
+      if( mismatched_files_cnt )
+        {
+          printf("\n*** WARNING: MISMATCHED FILES ***\n\n");
+          for( i = 0 ; i < mismatched_files_cnt ; i++ )
+            print(mismatched_files[i]);
+        }
+
+      print("");
+    }
+}
--- modal.c
+++ modal.c
@@ -1,4 +1,4 @@
-#ifndef lint
+#if 0
 static char rcsid[] = "modal.c,v 2.0 1994/05/19 02:01:20 dan Exp";
 #endif
 
--- rundiff.c
+++ rundiff.c
@@ -1,4 +1,4 @@
-#ifndef lint
+#if 0
 static char rcsid[] = "rundiff.c,v 2.0 1994/05/19 02:01:22 dan Exp";
 #endif
 
@@ -209,7 +209,7 @@
     FILE *diff, *file1, *file2;
     char buffer[BUFSIZ+1];
     int sline, fline1, fline2;
-    Block *b;
+    Block *b = NULL;
     int i, lines, counter;
     int stat_loc;
     DiffInfo *di;
@@ -245,7 +245,7 @@
 		char cmdline[4096];
 
 		di->etext = (char **) calloc (MAX_ERROR_LINES + 1, sizeof (char *));
-		(void) sprintf (cmdline, "    \"%s %s %s %s\"", prog, args, path1, path2);
+		(void) snprintf (cmdline, sizeof (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);
@@ -522,21 +522,23 @@
  */
 static char *duplicate (char *s, int *flag)
 {
-    int len, i, tabs, ctrls;
+    int len, i, tabs, ctrls, latin, ch;
 
     /* 
      * 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])) {
+    ch = s [i];
+	latin = islatin(ch);
+	if ((isascii(ch) || latin)) {
 	    if (s[i] == '\t') {
 		tabs++;
 		len += 8;
 		len /= 8;
 		len *= 8;
 	    }
-	    else if (iscntrl (s[i])) {
+	    else if (!latin && iscntrl (s[i])) {
 		ctrls++;
 		len += 2;
 	    }
@@ -551,16 +553,18 @@
 
     if (tabs || ctrls) {
 	char *ret = (char *) calloc (1, len + 1);
-	int j;
+	int j, ch;
 
 	for (i = 0, j = 0; s[i] != '\0'; i++) {
-	    if (isascii (s[i])) {
+	    ch = s[i];
+	    latin = islatin(ch);
+	    if ((isascii(ch) || latin)) {
 		if (s[i] == '\t') {
 		    ret[j++] = ' ';
 		    while ((j % 8) != 0)
 			ret[j++] = ' ';
 		}
-		else if (iscntrl (s[i])) {
+		else if (!latin && iscntrl (s[i])) {
 		    ret[j++] = '^';
 		    ret[j++] = (s[i] + '@') & 0x7f;
 		}
--- misc.c
+++ misc.c
@@ -1,9 +1,10 @@
-#ifndef lint
+#if 0
 static char rcsid[] = "misc.c,v 2.0 1994/05/19 02:01:19 dan Exp";
 #endif
 
 /*
  * Copyright (c) 1994    Daniel Williams
+ * Copyright (c) 2003    Erik de Castro Lopo
  * 
  * The X Consortium, and any party obtaining a copy of these files from
  * the X Consortium, directly or indirectly, is granted, free of charge,
@@ -33,6 +34,8 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
 
 #include <Xm/Xm.h>
 #include <X11/cursorfont.h>
@@ -40,6 +43,7 @@
 #include <Xm/SashP.h>
 
 #include "mgdiff.h"
+#include "externs.h"
 
 int max (int i, int j)
 {
@@ -52,14 +56,38 @@
 }
 
 /* 
- * copy a stream up to the EOF to a file
+ * Create a temporary file and write all text from the input stream (up to 
+ * the EOF) to the file.
+ * The name of the temp file is returned to the user in *name.
  */
-int copy_to_file (FILE *fin, char *name)
+int copy_to_tempfile (FILE *fin, char *name, size_t name_len)
 {
-    FILE *fout;
+    FILE *fout ;
+    int fd ;
+	
+    /*
+    **	Seed the random() generator. This does not need to be super
+    **	randomised as the while loop below will be run until a file
+    **	is opened.
+    */
+    srandom (getpid () + getppid () + time (NULL)) ;
+
+    while (1) {
+	snprintf (name, name_len, "/tmp/mgdiff-%#lx", random()) ;
+	if ((fd = open (name, O_CREAT | O_EXCL | O_RDWR, 0600)) < 0) {
+	    if (errno == EEXIST)
+		continue ;
+	    return 1 ;
+	}
+
+	if ((fout = fdopen (fd, "r+")) == NULL) {
+	    close (fd) ;
+	    return 1 ;
+	}
+	
+	break ;
+    }
 
-    if ((fout = fopen (name, "a")) == NULL)
-	return (0);
     while (!feof (fin)) {
 	char buffer[BUFSIZ];
 	int nitems;
@@ -68,10 +96,12 @@
 	if (fwrite (buffer, 1, nitems, fout) != nitems)
 	    break;
     }
+
     if (ferror (fin) || ferror (fout)) {
 	(void) fclose (fout);
 	return (1);
     }
+
     return ((fclose (fout) == 0));
 }
 
--- patchlevel.h
+++ patchlevel.h
@@ -28,11 +28,11 @@
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#ifndef lint
+#if 0
 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"
+#define PATCHLEVEL "1"
 
 #endif
--- externs.h
+++ externs.h
@@ -28,7 +28,7 @@
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#ifndef lint
+#if 0
 static char rcsid_externs_h[] = "externs.h,v 2.0 1994/05/19 02:01:05 dan Exp";
 #endif
 
@@ -43,7 +43,7 @@
 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 int copy_to_tempfile (FILE *fin, char *name, size_t name_len);
 extern void set_cursor (Widget w);
 extern void reset_cursor (Widget w);
 extern Widget get_top_shell (Widget w);
@@ -61,5 +61,6 @@
 extern void turn_off_sash_traversal (Widget pane);
 extern void show_legend (Widget parent);
 extern void show_context (Widget parent);
+extern void save_as_filename (Widget parent, Block *b, char *name);
 
 #endif
--- mgdiff.man
+++ mgdiff.man
@@ -1,6 +1,7 @@
 .\" mgdiff.man,v 2.0 1994/05/19 02:01:16 dan Exp
 .\"
 .\" Copyright (c) 1994    Daniel Williams
+.\" Copyright (c) 2003    Erik de Castro Lopo
 .\" 
 .\" The X Consortium, and any party obtaining a copy of these files from
 .\" the X Consortium, directly or indirectly, is granted, free of charge,
@@ -26,7 +27,7 @@
 .\" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 .\"
 .na
-.TH MGDIFF 1
+.TH MGDIFF 1x
 .SH NAME
 mgdiff \- Motif-based graphical file difference browser
 .SH SYNOPSIS
@@ -82,6 +83,20 @@
 .LP
 At the top of the display is a Motif menu bar; those functions are
 discussed in the MENUS section of this manual page.
+.LP
+Earlier versions of this program (pre 2003) only allowed the selection
+of the left hand side difference or the right hand side difference.  It
+also would not allow a file to be saved with unselected blocks.  The
+current version allows the user to select both sides of a difference
+by selecting blocks using the middle mouse button.  When both sides of a 
+difference are selected both blocks will be saved to the merged file and 
+marked in a similar manner to the way 
+.I CVS
+marks merges that require manual resolution of conflicting changes.  In
+addition, the current version also allows saving of a merged file with
+unselected blocks.  In this case, the merged file will contain 
+neither the left hand side nor the right hand side of the unselected
+blocks.
 
 .SH COMMAND LINE OPTIONS
 .TP 8
@@ -170,8 +185,27 @@
 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.
+areas of difference between the two files the user is asked whether
+they want to continue or cancel the operation.  If the user continues,
+the output file will contain none of the unselected blocks.
+.IP "\fBSave As Left...\fP" \n(XYP
+.LP
+Saves the merged file to the location given by the left hand side
+file location. The user will be asked if they are sure they wish the
+existing file to be overwritten. As with the "Save As", if there are 
+any unselected areas of difference between the two files the user 
+asked whether they want to continue or cancel the operation.  If the
+user continues, the output file will contain none of the data in the
+unselected blocks.
+.IP "\fBSave As Right...\fP" \n(XYP
+.LP
+Saves the merged file to the location given by the right hand side
+file location. The user will be asked if they are sure they wish the
+existing file to be overwritten. As with the "Save As", if there are 
+any unselected areas of difference between the two files the user 
+asked whether they want to continue or cancel the operation.  If the
+user continues, the output file will contain none of the data in the
+unselected blocks.
 .IP "\fBExit\fP" \n(XYP
 .B Ctrl+C
 .LP
@@ -332,6 +366,9 @@
 					XmPushButtonGadget  button_3
 					XmSeparatorGadget  separator_0
 					XmPushButtonGadget  button_4
+					XmPushButtonGadget  button_5
+					XmSeparatorGadget  separator_1
+					XmPushButtonGadget  button_6
 				XmRowColumn  options_menu
 					XmToggleButtonGadget  button_0
 					XmToggleButtonGadget  button_1
@@ -543,12 +580,17 @@
 any quote processing.
 .SH COPYRIGHT
 Copyright (c) 1994, Daniel Williams
+.br 
+Copyright (c) 2003, Erik de Castro Lopo
 .br
 See
 .B X (1)
 for a full statement of rights and permissions.
-.SH AUTHOR
+.SH AUTHORS
 Daniel Williams (dan@sass.com)
+.br
+Erik de Castro Lopo (erikd AT mega-nerd DOT com) added "\fBSave as Left/Right\fP"
+and saving both and neither sides.
 .SH ACKNOWLEDGEMENTS
 To Andrew C. Myers for writing
 .I gdiff.
openSUSE Build Service is sponsored by