pkgsrc-Changes archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

CVS commit: pkgsrc/devel/mgdiff



Module Name:    pkgsrc
Committed By:   vins
Date:           Wed Mar  1 23:48:00 UTC 2023

Modified Files:
        pkgsrc/devel/mgdiff: DESCR Makefile PLIST distinfo
        pkgsrc/devel/mgdiff/patches: patch-Imakefile patch-mgdiff.c
            patch-rundiff.c
Added Files:
        pkgsrc/devel/mgdiff/files: README.pkgsrc cvsmgdiff cvsmgdiff.1
            mgdiff-48x48.xpm mgdiff.desktop rmgdiff rmgdiff.1 rmgdiff.awk
        pkgsrc/devel/mgdiff/patches: patch-Mgdiff.ad patch-externs.h
            patch-files.c patch-legend.c patch-manual.c patch-mgdiff.h
            patch-mgdiff.man patch-misc.c patch-modal.c patch-patchlevel.h
            patch-spawn.c

Log Message:
devel/mgdiff: update to mgdiff 1.0.1.

Update package using Debian's patches.

## Changes (local)

* Introduce a couple useful scripts based on mgdiff (also pulled from
  Debian):

  - rmgdiff allows the user to recursively diff two directories using
    any graphical diff viewer -- including mgdiff.

  - cvsmgdiff allows the user to compare a revision in a CVS archive
    with what is currently checked out.

* Switch to an internally managed install target.
* Make sure package links against libXpm.
* Add a mgdiff.desktop application file and a suitable pixmap.
* Address compiler warnings when building on Linux.
* Update DESCR.
* Add README.

## Changes (upstream)

* 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.
* Allow saving files with unselected blocks.
* 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.
* Update the man page to reflect the above changes.
* Fix Ctrl-U/Ctrl-P handling.
* Fix UTF8 handling.
* Replace all usage of sprintf() with snprintf().
* Fix a couple of missing includes.
* Fix building on SUN Solaris.
* Clean compiler warnings.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 pkgsrc/devel/mgdiff/DESCR \
    pkgsrc/devel/mgdiff/Makefile pkgsrc/devel/mgdiff/PLIST
cvs rdiff -u -r1.2 -r1.3 pkgsrc/devel/mgdiff/distinfo
cvs rdiff -u -r0 -r1.1 pkgsrc/devel/mgdiff/files/README.pkgsrc \
    pkgsrc/devel/mgdiff/files/cvsmgdiff pkgsrc/devel/mgdiff/files/cvsmgdiff.1 \
    pkgsrc/devel/mgdiff/files/mgdiff-48x48.xpm \
    pkgsrc/devel/mgdiff/files/mgdiff.desktop \
    pkgsrc/devel/mgdiff/files/rmgdiff pkgsrc/devel/mgdiff/files/rmgdiff.1 \
    pkgsrc/devel/mgdiff/files/rmgdiff.awk
cvs rdiff -u -r1.1 -r1.2 pkgsrc/devel/mgdiff/patches/patch-Imakefile \
    pkgsrc/devel/mgdiff/patches/patch-rundiff.c
cvs rdiff -u -r0 -r1.1 pkgsrc/devel/mgdiff/patches/patch-Mgdiff.ad \
    pkgsrc/devel/mgdiff/patches/patch-externs.h \
    pkgsrc/devel/mgdiff/patches/patch-files.c \
    pkgsrc/devel/mgdiff/patches/patch-legend.c \
    pkgsrc/devel/mgdiff/patches/patch-manual.c \
    pkgsrc/devel/mgdiff/patches/patch-mgdiff.h \
    pkgsrc/devel/mgdiff/patches/patch-mgdiff.man \
    pkgsrc/devel/mgdiff/patches/patch-misc.c \
    pkgsrc/devel/mgdiff/patches/patch-modal.c \
    pkgsrc/devel/mgdiff/patches/patch-patchlevel.h \
    pkgsrc/devel/mgdiff/patches/patch-spawn.c
cvs rdiff -u -r1.2 -r1.3 pkgsrc/devel/mgdiff/patches/patch-mgdiff.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: pkgsrc/devel/mgdiff/DESCR
diff -u pkgsrc/devel/mgdiff/DESCR:1.1 pkgsrc/devel/mgdiff/DESCR:1.2
--- pkgsrc/devel/mgdiff/DESCR:1.1       Mon Jan  2 22:43:52 2023
+++ pkgsrc/devel/mgdiff/DESCR   Wed Mar  1 23:48:00 2023
@@ -3,3 +3,7 @@ X11R[456] and the Motif widget set. It a
 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.
Index: pkgsrc/devel/mgdiff/Makefile
diff -u pkgsrc/devel/mgdiff/Makefile:1.1 pkgsrc/devel/mgdiff/Makefile:1.2
--- pkgsrc/devel/mgdiff/Makefile:1.1    Mon Jan  2 22:43:52 2023
+++ pkgsrc/devel/mgdiff/Makefile        Wed Mar  1 23:48:00 2023
@@ -1,7 +1,7 @@
-# $NetBSD: Makefile,v 1.1 2023/01/02 22:43:52 vins Exp $
+# $NetBSD: Makefile,v 1.2 2023/03/01 23:48:00 vins Exp $
 
 DISTNAME=      mgdiff
-PKGNAME=       ${DISTNAME}-1.0
+PKGNAME=       ${DISTNAME}-1.0.1
 CATEGORIES=    devel x11
 MASTER_SITES=  ${MASTER_SITE_XCONTRIB:=applications/}
 DIST_SUBDIR=   ${PKGNAME_NOREV}
@@ -12,23 +12,71 @@ COMMENT=    Graphical front end to Unix dif
 LICENSE=       mit
 
 USE_IMAKE=     yes
+USE_TOOLS+=    awk:run ksh:run
 
-LIBDIR=        lib/X11/${PKGBASE}
+REPLACE_KSH=   cvsmgdiff
+
+SUBST_CLASSES+=                prefix
+SUBST_STAGE.prefix=    pre-configure
+SUBST_FILES.prefix=    cvsmgdiff rmgdiff README.pkgsrc
+SUBST_VARS.prefix=     PREFIX
+SUBST_MESSAGE.prefix=  Replacing PREFIX placeholders.
+
+.include "../../mk/bsd.prefs.mk"
+
+.if ${OPSYS} == "Linux"
+SUBST_CLASSES+=                defs
+SUBST_STAGE.defs=      post-configure
+SUBST_FILES.defs+=     Makefile
+SUBST_SED.defs=                -e 's|-D_BSD_SOURCE[[:space:]]*-D_SVID_SOURCE|-D_DEFAULT_SOURCE|g'
+SUBST_MESSAGE.defs=    Replacing deprecated preprocessor-defined macros.
+.endif
 
 MAKE_FLAGS+=   CCOPTIONS=${CFLAGS:Q}
 MAKE_FLAGS+=   LOCAL_LDFLAGS=${LDFLAGS:Q}
+MAKE_FLAGS+=   XAPPLOADDIR=${PREFIX}/lib/X11/app-defaults
 
-INSTALLATION_DIRS+=    ${LIBDIR}
+INSTALLATION_DIRS+=    bin ${PKGMANDIR}/man1 libexec/${PKGBASE}
+INSTALLATION_DIRS+=    lib/X11/${PKGBASE} lib/X11/app-defaults
+INSTALLATION_DIRS+=    share/applications share/doc/${PKGBASE} share/pixmaps
+
+post-extract:
+.for f in *mgdiff README*
+       ${RUN}${CP} ${FILESDIR}/${f} ${WRKSRC}
+.endfor
+
+do-install:
+       ${INSTALL_PROGRAM} ${WRKSRC}/mgdiff ${DESTDIR}${PREFIX}/bin
+       ${INSTALL_MAN} ${WRKSRC}/mgdiff.man             \
+               ${DESTDIR}${PREFIX}/${PKGMANDIR}/man1/mgdiff.1
+.for i in cvsmgdiff rmgdiff
+       ${INSTALL_SCRIPT} ${WRKSRC}/${i} ${DESTDIR}${PREFIX}/bin
+       ${INSTALL_MAN} ${FILESDIR}/${i}.1               \
+               ${DESTDIR}${PREFIX}/${PKGMANDIR}/man1
+.endfor
+       ${INSTALL_DATA} ${WRKSRC}/Mgdiff.ad             \
+               ${DESTDIR}${PREFIX}/lib/X11/app-defaults/Mgdiff
+       ${INSTALL_DATA} ${WRKSRC}/mgdiff.x[bp]m         \
+               ${DESTDIR}${PREFIX}/lib/X11/${PKGBASE}
+       ${INSTALL_DATA} ${FILESDIR}/rmgdiff.awk         \
+               ${DESTDIR}${PREFIX}/libexec/${PKGBASE}
 
 post-install:
-       ${INSTALL_DATA} ${WRKSRC}/mgdiff.x[bp]m ${DESTDIR}${PREFIX}/${LIBDIR}
+       ${INSTALL_DATA} ${FILESDIR}/mgdiff-48x48.xpm    \
+               ${DESTDIR}${PREFIX}/share/pixmaps
+       ${INSTALL_DATA} ${FILESDIR}/mgdiff.desktop      \
+               ${DESTDIR}${PREFIX}/share/applications
+       ${INSTALL_DATA} ${WRKSRC}/README.pkgsrc         \
+               ${DESTDIR}${PREFIX}/share/doc/${PKGBASE}
 
+.include "../../sysutils/desktop-file-utils/desktopdb.mk"
 .include "../../x11/libXext/buildlink3.mk"
 .include "../../x11/libXmu/buildlink3.mk"
-.include "../../x11/libXt/buildlink3.mk"
-.include "../../x11/libSM/buildlink3.mk"
+.include "../../x11/libXpm/buildlink3.mk"
 .include "../../x11/libICE/buildlink3.mk"
 .include "../../x11/libXau/buildlink3.mk"
 .include "../../x11/libX11/buildlink3.mk"
+.include "../../x11/libXt/buildlink3.mk"
+.include "../../x11/libSM/buildlink3.mk"
 .include "../../mk/motif.buildlink3.mk"
 .include "../../mk/bsd.pkg.mk"
Index: pkgsrc/devel/mgdiff/PLIST
diff -u pkgsrc/devel/mgdiff/PLIST:1.1 pkgsrc/devel/mgdiff/PLIST:1.2
--- pkgsrc/devel/mgdiff/PLIST:1.1       Mon Jan  2 22:43:52 2023
+++ pkgsrc/devel/mgdiff/PLIST   Wed Mar  1 23:48:00 2023
@@ -1,6 +1,14 @@
-@comment $NetBSD: PLIST,v 1.1 2023/01/02 22:43:52 vins Exp $
+@comment $NetBSD: PLIST,v 1.2 2023/03/01 23:48:00 vins Exp $
+bin/cvsmgdiff
 bin/mgdiff
+bin/rmgdiff
 lib/X11/app-defaults/Mgdiff
 lib/X11/mgdiff/mgdiff.xbm
 lib/X11/mgdiff/mgdiff.xpm
+libexec/mgdiff/rmgdiff.awk
+man/man1/cvsmgdiff.1
 man/man1/mgdiff.1
+man/man1/rmgdiff.1
+share/applications/mgdiff.desktop
+share/doc/mgdiff/README.pkgsrc
+share/pixmaps/mgdiff-48x48.xpm

Index: pkgsrc/devel/mgdiff/distinfo
diff -u pkgsrc/devel/mgdiff/distinfo:1.2 pkgsrc/devel/mgdiff/distinfo:1.3
--- pkgsrc/devel/mgdiff/distinfo:1.2    Tue Jan  3 09:01:41 2023
+++ pkgsrc/devel/mgdiff/distinfo        Wed Mar  1 23:48:00 2023
@@ -1,8 +1,19 @@
-$NetBSD: distinfo,v 1.2 2023/01/03 09:01:41 vins Exp $
+$NetBSD: distinfo,v 1.3 2023/03/01 23:48:00 vins Exp $
 
-BLAKE2s (mgdiff-1.0/mgdiff.tar.gz) = 7c90e00f9646d41e5e822055340fa41440acaa5ec0352606ccec1e14b43188de
-SHA512 (mgdiff-1.0/mgdiff.tar.gz) = bf5ab4b2a9d42ff2edb73a6dda68a4d17d88f61c63f5ec8366cc49d372a56f3c6812d473a95d86bcb61680d1f91ce4ab7ad87a26748b45e2edd27b73044492a5
-Size (mgdiff-1.0/mgdiff.tar.gz) = 41187 bytes
-SHA1 (patch-Imakefile) = 6a29ed061ea0b54396269707acd7f53a9a5c32ce
-SHA1 (patch-mgdiff.c) = eba9d8ba00e15424093eaa8f65d58c7cb55625ce
-SHA1 (patch-rundiff.c) = 4ead16932bbf480d8da283b335a93418108926f2
+BLAKE2s (mgdiff-1.0.1/mgdiff.tar.gz) = 7c90e00f9646d41e5e822055340fa41440acaa5ec0352606ccec1e14b43188de
+SHA512 (mgdiff-1.0.1/mgdiff.tar.gz) = bf5ab4b2a9d42ff2edb73a6dda68a4d17d88f61c63f5ec8366cc49d372a56f3c6812d473a95d86bcb61680d1f91ce4ab7ad87a26748b45e2edd27b73044492a5
+Size (mgdiff-1.0.1/mgdiff.tar.gz) = 41187 bytes
+SHA1 (patch-Imakefile) = 7c95728d50c4d835ceb330124eccce166c9e2845
+SHA1 (patch-Mgdiff.ad) = 3be8cae459c84f355de65e37f679649472b38a16
+SHA1 (patch-externs.h) = 8e536067c9834b8ef26a0210aaf8ece31004f310
+SHA1 (patch-files.c) = fa06ab3916e0d0a95551bea5e3320c9e577b3d7a
+SHA1 (patch-legend.c) = 8933bc2938f94bc7c0c11009074517f017d4f8ee
+SHA1 (patch-manual.c) = 2f430240696d6eec22d5dd576c4577e5b7b4578d
+SHA1 (patch-mgdiff.c) = f2e2fb5cc4722ae38e00566ebbc5e87e00457807
+SHA1 (patch-mgdiff.h) = e7958ebd5ca1ccb17c7bcc7cf860d88e81f50cb4
+SHA1 (patch-mgdiff.man) = 6d3a2fbecb7ae1e8f8a2cc4f3c7ac15f44a8e01a
+SHA1 (patch-misc.c) = b6e1dd999f7fa5d013f3b6ad605f7c8c4cb4702e
+SHA1 (patch-modal.c) = 8c9e9e5c165c01f18ffb568367fa8c279a6913fc
+SHA1 (patch-patchlevel.h) = a9f3923649af2f99fdd4cce8148cc15ad6aaa626
+SHA1 (patch-rundiff.c) = 4c6360f13f1f9871b3a86afb476bfd041a290c58
+SHA1 (patch-spawn.c) = 3c9f8be777e47f485aef54511c2603adf4d26af3

Index: pkgsrc/devel/mgdiff/patches/patch-Imakefile
diff -u pkgsrc/devel/mgdiff/patches/patch-Imakefile:1.1 pkgsrc/devel/mgdiff/patches/patch-Imakefile:1.2
--- pkgsrc/devel/mgdiff/patches/patch-Imakefile:1.1     Mon Jan  2 22:43:53 2023
+++ pkgsrc/devel/mgdiff/patches/patch-Imakefile Wed Mar  1 23:48:00 2023
@@ -1,10 +1,10 @@
-$NetBSD: patch-Imakefile,v 1.1 2023/01/02 22:43:53 vins Exp $
+$NetBSD: patch-Imakefile,v 1.2 2023/03/01 23:48:00 vins Exp $
 
 Do not require libucb/SUNWscpu.
 
 --- Imakefile.orig     1994-05-19 02:01:00.000000000 +0000
 +++ Imakefile
-@@ -4,11 +4,10 @@
+@@ -4,16 +4,17 @@
  
  XCOMM Imakefile,v 2.0 1994/05/19 02:01:00 dan Exp
  
@@ -14,6 +14,14 @@ Do not require libucb/SUNWscpu.
  XCOMM for Dell SVR4
  XCOMM
 -EXTRA_LIBRARIES = -lc -lucb
++EXTRA_LIBRARIES = -lXpm
++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
+ 
+-LOCAL_LIBRARIES = $(XMLIB) $(XTOOLLIB) $(XMULIBONLY) $(XLIB)
++LOCAL_LIBRARIES = $(XMLIB) $(XTOOLLIB) $(XMULIBONLY) $(XLIB) $(XPLIB)
+ 
+ ComplexProgramTarget(mgdiff)
+ InstallAppDefaults(Mgdiff)
Index: pkgsrc/devel/mgdiff/patches/patch-rundiff.c
diff -u pkgsrc/devel/mgdiff/patches/patch-rundiff.c:1.1 pkgsrc/devel/mgdiff/patches/patch-rundiff.c:1.2
--- pkgsrc/devel/mgdiff/patches/patch-rundiff.c:1.1     Mon Jan  2 22:43:53 2023
+++ pkgsrc/devel/mgdiff/patches/patch-rundiff.c Wed Mar  1 23:48:00 2023
@@ -1,10 +1,36 @@
-$NetBSD: patch-rundiff.c,v 1.1 2023/01/02 22:43:53 vins Exp $
+$NetBSD: patch-rundiff.c,v 1.2 2023/03/01 23:48:00 vins Exp $
 
 Avoid conflicting getline() type definition.
+Pull patches from Debian.
 
 --- rundiff.c.orig     1994-05-19 02:01:22.000000000 +0000
 +++ rundiff.c
-@@ -63,7 +63,7 @@ typedef enum { ADD = 1, CHANGE, DELETE, 
+@@ -1,5 +1,5 @@
+-#ifndef lint
+-static char rcsid[] = "rundiff.c,v 2.0 1994/05/19 02:01:22 dan Exp";
++#if 0
++static char rcsid[] __attribute__((unused)) = "rundiff.c,v 2.0 1994/05/19 02:01:22 dan Exp";
+ #endif
+ 
+ /*
+@@ -44,6 +44,16 @@ static char rcsid[] = "rundiff.c,v 2.0 1
+ #include "mgdiff.h"
+ #include "externs.h"
+ 
++static inline void* xcalloc(size_t nmemb, size_t size)
++{
++    void *ret = calloc(nmemb, size);
++    if (!ret) {
++      perror("calloc");
++      exit (1);
++    }
++    return ret;
++}
++
+ /* 
+  * this is the maximum number of lines shown to the user if diff
+  * returns an error
+@@ -63,7 +73,7 @@ typedef enum { ADD = 1, CHANGE, DELETE,
  static char *duplicate (char *s, int *flag);
  static DiffType parse_diff_line (char *buf, int *f1n1, int *f1n2, int *f2n1, int *f2n2);
  static int eatline (FILE *f);
@@ -13,79 +39,328 @@ Avoid conflicting getline() type definit
  static void reset_blist (void);
  static Block *get_blist (void);
  static void add_blist (Block *b);
-@@ -271,7 +271,7 @@ DiffInfo *build_diff_info (char *prog, c
-               b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
-               b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short));
+@@ -170,22 +180,22 @@ DiffInfo *blank_diff_info (void)
+     Block *b;
+     DiffInfo *di;
+ 
+-    di = (DiffInfo *) calloc (1, sizeof (DiffInfo));
++    di = (DiffInfo *) xcalloc (1, sizeof (DiffInfo));
+     di->longline = "  ";
+     di->maxcols = strlen (di->longline);
+     di->status = 2;
+ 
+-    b = (Block *) calloc (1, sizeof (Block));
++    b = (Block *) xcalloc (1, sizeof (Block));
+     b->selected = NEITHER;
+     b->arr[LEFT].type = b->arr[RIGHT].type = SAME;
+     b->sline = 0;
+     b->ssize = 1;
+     b->arr[LEFT].fline = b->arr[RIGHT].fline = 0;
+     b->arr[LEFT].fsize = b->arr[RIGHT].fsize = 1;
+-    b->arr[LEFT].text = (char **) calloc (1, sizeof (char *));
+-    b->arr[LEFT].wtext = (char **) calloc (1, sizeof (char *));
+-    b->arr[LEFT].tlen = (short *) calloc (1, sizeof (short));
+-    b->arr[LEFT].text[0] = strdup ("  ");
++    b->arr[LEFT].text = (char **) xcalloc (1, sizeof (char *));
++    b->arr[LEFT].wtext = (char **) xcalloc (1, sizeof (char *));
++    b->arr[LEFT].tlen = (short *) xcalloc (1, sizeof (short));
++    b->arr[LEFT].text[0] = xstrdup ("  ");
+     b->arr[LEFT].tlen[0] = strlen (b->arr[LEFT].text[0]);
+ 
+     b->arr[RIGHT].text = NULL;
+@@ -209,7 +219,7 @@ DiffInfo *build_diff_info (char *prog, c
+     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;
+@@ -220,7 +230,7 @@ DiffInfo *build_diff_info (char *prog, c
+     file2 = fopen (path2, "r");
+     diff = spawn_diff (prog, args, path1, path2);
+ 
+-    di = (DiffInfo *) calloc (1, sizeof (DiffInfo));
++    di = (DiffInfo *) xcalloc (1, sizeof (DiffInfo));
+     di->longline = "";
+ 
+     XmUpdateDisplay (toplevel);
+@@ -244,21 +254,21 @@ DiffInfo *build_diff_info (char *prog, c
+           if (di->errors == 0) {
+               char cmdline[4096];
+ 
+-              di->etext = (char **) calloc (MAX_ERROR_LINES + 1, sizeof (char *));
+-              (void) sprintf (cmdline, "    \"%s %s %s %s\"", prog, args, path1, path2);
+-              di->etext[di->errors++] = strdup ("diff command line:");
+-              di->etext[di->errors++] = strdup ("");
+-              di->etext[di->errors++] = strdup (cmdline);
+-              di->etext[di->errors++] = strdup ("");
+-              di->etext[di->errors++] = strdup ("produced this output:");
+-              di->etext[di->errors++] = strdup ("");
++              di->etext = (char **) xcalloc (MAX_ERROR_LINES + 1, sizeof (char *));
++              (void) snprintf (cmdline, sizeof (cmdline), "    \"%s %s %s %s\"", prog, args, path1, path2);
++              di->etext[di->errors++] = xstrdup ("diff command line:");
++              di->etext[di->errors++] = xstrdup ("");
++              di->etext[di->errors++] = xstrdup (cmdline);
++              di->etext[di->errors++] = xstrdup ("");
++              di->etext[di->errors++] = xstrdup ("produced this output:");
++              di->etext[di->errors++] = xstrdup ("");
+           }
+           if (di->errors < MAX_ERROR_LINES)
+-              di->etext[di->errors++] = strdup (buffer);
++              di->etext[di->errors++] = xstrdup (buffer);
+           break;
+       case ADD:
+           if (f2n1 != fline2) {
+-              b = (Block *) calloc (1, sizeof (Block));
++              b = (Block *) xcalloc (1, sizeof (Block));
+               b->selected = NEITHER;
+               b->arr[LEFT].type = b->arr[RIGHT].type = SAME;
+               b->sline = sline;
+@@ -267,11 +277,11 @@ DiffInfo *build_diff_info (char *prog, c
+               b->arr[LEFT].fsize = b->arr[RIGHT].fsize = f2n1 - fline2;
+               b->ssize = f2n1 - fline2;
+               
+-              b->arr[LEFT].text = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
+-              b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
+-              b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short));
++              b->arr[LEFT].text = (char **) xcalloc (b->arr[LEFT].fsize, sizeof (char *));
++              b->arr[LEFT].wtext = (char **) xcalloc (b->arr[LEFT].fsize, sizeof (char *));
++              b->arr[LEFT].tlen = (short *) xcalloc (b->arr[LEFT].fsize, sizeof (short));
                for (i = 0; i < b->arr[LEFT].fsize; i++) {
 -                  getline (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]);
 +                  get_line (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]);
                    b->arr[LEFT].tlen[i] = strlen (b->arr[LEFT].text[i]);
                    if (di->maxcols < b->arr[LEFT].tlen[i]) {
                        di->maxcols = b->arr[LEFT].tlen[i];
-@@ -300,7 +300,7 @@ DiffInfo *build_diff_info (char *prog, c
-           b->arr[RIGHT].wtext = (char **) calloc (b->arr[RIGHT].fsize, sizeof (char *));
-           b->arr[RIGHT].tlen = (short *) calloc (b->arr[RIGHT].fsize, sizeof (short));
+@@ -285,7 +295,7 @@ DiffInfo *build_diff_info (char *prog, c
+               add_blist (b);
+           }
+ 
+-          b = (Block *) calloc (1, sizeof (Block));
++          b = (Block *) xcalloc (1, sizeof (Block));
+           b->selected = NEITHER;
+           b->arr[LEFT].type = BLANK;
+           b->arr[RIGHT].type = INSERT;
+@@ -296,11 +306,11 @@ DiffInfo *build_diff_info (char *prog, c
+           b->arr[RIGHT].fsize = f2n2 - f2n1 + 1;
+           b->ssize = max (b->arr[LEFT].fsize, b->arr[RIGHT].fsize);
+ 
+-          b->arr[RIGHT].text = (char **) calloc (b->arr[RIGHT].fsize, sizeof (char *));
+-          b->arr[RIGHT].wtext = (char **) calloc (b->arr[RIGHT].fsize, sizeof (char *));
+-          b->arr[RIGHT].tlen = (short *) calloc (b->arr[RIGHT].fsize, sizeof (short));
++          b->arr[RIGHT].text = (char **) xcalloc (b->arr[RIGHT].fsize, sizeof (char *));
++          b->arr[RIGHT].wtext = (char **) xcalloc (b->arr[RIGHT].fsize, sizeof (char *));
++          b->arr[RIGHT].tlen = (short *) xcalloc (b->arr[RIGHT].fsize, sizeof (short));
            for (i = 0; i < b->arr[RIGHT].fsize; i++) {
 -              getline (file2, &b->arr[RIGHT].text[i], &b->arr[RIGHT].wtext[i]);
 +              get_line (file2, &b->arr[RIGHT].text[i], &b->arr[RIGHT].wtext[i]);
                b->arr[RIGHT].tlen[i] = strlen (b->arr[RIGHT].text[i]);
                if (di->maxcols < b->arr[RIGHT].tlen[i]) {
                    di->maxcols = b->arr[RIGHT].tlen[i];
-@@ -331,7 +331,7 @@ DiffInfo *build_diff_info (char *prog, c
-               b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
-               b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short));
+@@ -318,7 +328,7 @@ DiffInfo *build_diff_info (char *prog, c
+           break;
+       case CHANGE:
+           if (f1n1 != fline1) {
+-              b = (Block *) calloc (1, sizeof (Block));
++              b = (Block *) xcalloc (1, sizeof (Block));
+               b->selected = NEITHER;
+               b->arr[LEFT].type = b->arr[RIGHT].type = SAME;
+               b->sline = sline;
+@@ -327,11 +337,11 @@ DiffInfo *build_diff_info (char *prog, c
+               b->arr[LEFT].fsize = b->arr[RIGHT].fsize = f1n1 - fline1;
+               b->ssize = f1n1 - fline1;
+               
+-              b->arr[LEFT].text = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
+-              b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
+-              b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short));
++              b->arr[LEFT].text = (char **) xcalloc (b->arr[LEFT].fsize, sizeof (char *));
++              b->arr[LEFT].wtext = (char **) xcalloc (b->arr[LEFT].fsize, sizeof (char *));
++              b->arr[LEFT].tlen = (short *) xcalloc (b->arr[LEFT].fsize, sizeof (short));
                for (i = 0; i < b->arr[LEFT].fsize; i++) {
 -                  getline (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]);
 +                  get_line (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]);
                    b->arr[LEFT].tlen[i] = strlen (b->arr[LEFT].text[i]);
                    if (di->maxcols < b->arr[LEFT].tlen[i]) {
                        di->maxcols = b->arr[LEFT].tlen[i];
-@@ -358,7 +358,7 @@ DiffInfo *build_diff_info (char *prog, c
-           b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
-           b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short));
+@@ -344,7 +354,7 @@ DiffInfo *build_diff_info (char *prog, c
+               sline += b->ssize;
+               add_blist (b);
+           }
+-          b = (Block *) calloc (1, sizeof (Block));
++          b = (Block *) xcalloc (1, sizeof (Block));
+           b->selected = NEITHER;
+           b->arr[LEFT].type = b->arr[RIGHT].type = DIFF;
+           b->sline = sline;
+@@ -354,11 +364,11 @@ DiffInfo *build_diff_info (char *prog, c
+           b->arr[RIGHT].fsize = f2n2 - f2n1 + 1;
+           b->ssize = max (b->arr[LEFT].fsize, b->arr[RIGHT].fsize);
+ 
+-          b->arr[LEFT].text = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
+-          b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
+-          b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short));
++          b->arr[LEFT].text = (char **) xcalloc (b->arr[LEFT].fsize, sizeof (char *));
++          b->arr[LEFT].wtext = (char **) xcalloc (b->arr[LEFT].fsize, sizeof (char *));
++          b->arr[LEFT].tlen = (short *) xcalloc (b->arr[LEFT].fsize, sizeof (short));
            for (i = 0; i < b->arr[LEFT].fsize; i++) {
 -              getline (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]);
 +              get_line (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]);
                b->arr[LEFT].tlen[i] = strlen (b->arr[LEFT].text[i]);
                if (di->maxcols < b->arr[LEFT].tlen[i]) {
                    di->maxcols = b->arr[LEFT].tlen[i];
-@@ -371,7 +371,7 @@ DiffInfo *build_diff_info (char *prog, c
-           b->arr[RIGHT].wtext = (char **) calloc (b->arr[RIGHT].fsize, sizeof (char *));
-           b->arr[RIGHT].tlen = (short *) calloc (b->arr[RIGHT].fsize, sizeof (short));
+@@ -367,11 +377,11 @@ DiffInfo *build_diff_info (char *prog, c
+           }
+           fline1 += b->arr[LEFT].fsize;
+ 
+-          b->arr[RIGHT].text = (char **) calloc (b->arr[RIGHT].fsize, sizeof (char *));
+-          b->arr[RIGHT].wtext = (char **) calloc (b->arr[RIGHT].fsize, sizeof (char *));
+-          b->arr[RIGHT].tlen = (short *) calloc (b->arr[RIGHT].fsize, sizeof (short));
++          b->arr[RIGHT].text = (char **) xcalloc (b->arr[RIGHT].fsize, sizeof (char *));
++          b->arr[RIGHT].wtext = (char **) xcalloc (b->arr[RIGHT].fsize, sizeof (char *));
++          b->arr[RIGHT].tlen = (short *) xcalloc (b->arr[RIGHT].fsize, sizeof (short));
            for (i = 0; i < b->arr[RIGHT].fsize; i++) {
 -              getline (file2, &b->arr[RIGHT].text[i], &b->arr[RIGHT].wtext[i]);
 +              get_line (file2, &b->arr[RIGHT].text[i], &b->arr[RIGHT].wtext[i]);
                b->arr[RIGHT].tlen[i] = strlen (b->arr[RIGHT].text[i]);
                if (di->maxcols < b->arr[RIGHT].tlen[i]) {
                    di->maxcols = b->arr[RIGHT].tlen[i];
-@@ -399,7 +399,7 @@ DiffInfo *build_diff_info (char *prog, c
-               b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
-               b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short));
+@@ -386,7 +396,7 @@ DiffInfo *build_diff_info (char *prog, c
+           break;
+       case DELETE:
+           if (f1n1 != fline1) {
+-              b = (Block *) calloc (1, sizeof (Block));
++              b = (Block *) xcalloc (1, sizeof (Block));
+               b->selected = NEITHER;
+               b->arr[LEFT].type = b->arr[RIGHT].type = SAME;
+               b->sline = sline;
+@@ -395,11 +405,11 @@ DiffInfo *build_diff_info (char *prog, c
+               b->arr[LEFT].fsize = b->arr[RIGHT].fsize = f1n1 - fline1;
+               b->ssize = f1n1 - fline1;
+               
+-              b->arr[LEFT].text = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
+-              b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
+-              b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short));
++              b->arr[LEFT].text = (char **) xcalloc (b->arr[LEFT].fsize, sizeof (char *));
++              b->arr[LEFT].wtext = (char **) xcalloc (b->arr[LEFT].fsize, sizeof (char *));
++              b->arr[LEFT].tlen = (short *) xcalloc (b->arr[LEFT].fsize, sizeof (short));
                for (i = 0; i < b->arr[LEFT].fsize; i++) {
 -                  getline (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]);
 +                  get_line (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]);
                    b->arr[LEFT].tlen[i] = strlen (b->arr[LEFT].text[i]);
                    if (di->maxcols < b->arr[LEFT].tlen[i]) {
                        di->maxcols = b->arr[LEFT].tlen[i];
-@@ -428,7 +428,7 @@ DiffInfo *build_diff_info (char *prog, c
-           b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
-           b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short));
+@@ -413,7 +423,7 @@ DiffInfo *build_diff_info (char *prog, c
+               add_blist (b);
+           }
+ 
+-          b = (Block *) calloc (1, sizeof (Block));
++          b = (Block *) xcalloc (1, sizeof (Block));
+           b->selected = NEITHER;
+           b->arr[LEFT].type = INSERT;
+           b->arr[RIGHT].type = BLANK;
+@@ -424,11 +434,11 @@ DiffInfo *build_diff_info (char *prog, c
+           b->arr[RIGHT].fsize = 0;
+           b->ssize = max (b->arr[LEFT].fsize, b->arr[RIGHT].fsize);
+ 
+-          b->arr[LEFT].text = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
+-          b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
+-          b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short));
++          b->arr[LEFT].text = (char **) xcalloc (b->arr[LEFT].fsize, sizeof (char *));
++          b->arr[LEFT].wtext = (char **) xcalloc (b->arr[LEFT].fsize, sizeof (char *));
++          b->arr[LEFT].tlen = (short *) xcalloc (b->arr[LEFT].fsize, sizeof (short));
            for (i = 0; i < b->arr[LEFT].fsize; i++) {
 -              getline (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]);
 +              get_line (file1, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]);
                b->arr[LEFT].tlen[i] = strlen (b->arr[LEFT].text[i]);
                if (di->maxcols < b->arr[LEFT].tlen[i]) {
                    di->maxcols = b->arr[LEFT].tlen[i];
-@@ -491,7 +491,7 @@ DiffInfo *build_diff_info (char *prog, c
-       b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
-       b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short));
+@@ -478,7 +488,7 @@ DiffInfo *build_diff_info (char *prog, c
+       ;
+ 
+     if (lines > 0) {
+-      b = (Block *) calloc (1, sizeof (Block));
++      b = (Block *) xcalloc (1, sizeof (Block));
+       b->selected = NEITHER;
+       b->arr[LEFT].type = b->arr[RIGHT].type = SAME;
+       b->sline = sline;
+@@ -487,11 +497,11 @@ DiffInfo *build_diff_info (char *prog, c
+       b->arr[LEFT].fsize = b->arr[RIGHT].fsize = lines;
+       b->ssize = lines;
+               
+-      b->arr[LEFT].text = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
+-      b->arr[LEFT].wtext = (char **) calloc (b->arr[LEFT].fsize, sizeof (char *));
+-      b->arr[LEFT].tlen = (short *) calloc (b->arr[LEFT].fsize, sizeof (short));
++      b->arr[LEFT].text = (char **) xcalloc (b->arr[LEFT].fsize, sizeof (char *));
++      b->arr[LEFT].wtext = (char **) xcalloc (b->arr[LEFT].fsize, sizeof (char *));
++      b->arr[LEFT].tlen = (short *) xcalloc (b->arr[LEFT].fsize, sizeof (short));
        for (i = 0; i < b->arr[LEFT].fsize; i++) {
 -          getline (file2, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]);
 +          get_line (file2, &b->arr[LEFT].text[i], &b->arr[LEFT].wtext[i]);
            b->arr[LEFT].tlen[i] = strlen (b->arr[LEFT].text[i]);
            if (di->maxcols < b->arr[LEFT].tlen[i]) {
                di->maxcols = b->arr[LEFT].tlen[i];
-@@ -663,7 +663,7 @@ static int eatline (FILE *f)
+@@ -522,21 +532,23 @@ DiffInfo *build_diff_info (char *prog, c
+  */
+ 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;
+           }
+@@ -550,17 +562,19 @@ static char *duplicate (char *s, int *fl
+     }
+ 
+     if (tabs || ctrls) {
+-      char *ret = (char *) calloc (1, len + 1);
+-      int j;
++      char *ret = (char *) xcalloc (1, len + 1);
++      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;
+               }
+@@ -585,7 +599,7 @@ static char *duplicate (char *s, int *fl
+     }
+     else {
+       *flag = False;
+-      return (strdup (s));
++      return (xstrdup (s));
+     }
+ }
+ 
+@@ -663,7 +677,7 @@ static int eatline (FILE *f)
   * printable) if necessary.  Silently truncate input lines at BUFSIZ
   * characters.
   */
@@ -94,3 +369,12 @@ Avoid conflicting getline() type definit
  {
      char buffer[BUFSIZ+1];
      char *s;
+@@ -685,7 +699,7 @@ static void getline (FILE *f, char **coo
+       while (getc (f) != '\n')
+           ;
+     *cooked = s;
+-    *raw = (flag) ? strdup (buffer) : NULL;
++    *raw = (flag) ? xstrdup (buffer) : NULL;
+ }
+ 
+ /* 

Index: pkgsrc/devel/mgdiff/patches/patch-mgdiff.c
diff -u pkgsrc/devel/mgdiff/patches/patch-mgdiff.c:1.2 pkgsrc/devel/mgdiff/patches/patch-mgdiff.c:1.3
--- pkgsrc/devel/mgdiff/patches/patch-mgdiff.c:1.2      Tue Jan  3 09:01:42 2023
+++ pkgsrc/devel/mgdiff/patches/patch-mgdiff.c  Wed Mar  1 23:48:00 2023
@@ -1,81 +1,873 @@
-$NetBSD: patch-mgdiff.c,v 1.2 2023/01/03 09:01:42 vins Exp $
+$NetBSD: patch-mgdiff.c,v 1.3 2023/03/01 23:48:00 vins Exp $
 
 Prevent unsafe use of tmpnam(). 
+Pull patches from Debian.
 
 --- mgdiff.c.orig      1994-09-29 01:56:53.000000000 +0000
 +++ mgdiff.c
-@@ -39,6 +39,7 @@ static char copyright[] = "Copyright (c)
+@@ -1,13 +1,14 @@
+-#ifndef lint
+-static char rcsid[] = "mgdiff.c,v 2.1 1994/09/29 01:56:53 dan Exp";
++#if 0
++static char rcsid[] __attribute__((unused)) = "mgdiff.c,v 2.1 1994/09/29 01:56:53 dan Exp";
+ #endif
+ 
+-#ifndef lint
+-static char copyright[] = "Copyright (c) 1994, Daniel Williams";
++#if 0
++static char copyright[] __attribute__((unused)) = "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,
+@@ -33,13 +34,17 @@ static char copyright[] = "Copyright (c)
+  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+  */
+ 
++#define _GNU_SOURCE
++
+ #include <X11/Xos.h>
+ 
+ #include <stdio.h>
  #include <stdlib.h>
  #include <assert.h>
  #include <errno.h>
 +#include <stdint.h>
  #include <sys/stat.h>
++#include <locale.h>
  
  #include <X11/Intrinsic.h>
-@@ -520,7 +521,7 @@ static void drawit (Widget w, XtPointer
+ #include <X11/StringDefs.h>
+@@ -79,7 +84,7 @@ static void update_pixmaps (void);
+ static void do_nothing (Widget widget, XEvent *event, String *params, Cardinal *num_params);
+ static void add_actions (XtAppContext app);
+ static int  x_error_handler (Display *dpy, XErrorEvent *event);
+-static void xt_error_handler (String message);
++static void xt_error_handler (String message) __attribute__ ((noreturn));
+ static void xt_warning_handler (String message);
+ static void redraw_partial_vert (Widget w);
+ static void redraw_partial_horz (Widget w);
+@@ -99,7 +104,7 @@ static void drag_diff (Widget w, XtPoint
+ 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 +114,16 @@ static void select_all (Side side);
+ static void unselect_all (void);
+ static Boolean all_selected (void);
+ static Dimension get_preferred_width (Widget w);
+-static char *basename (char *name);
++#if !(defined __GLIBC__ && __GLIBC__ >= 2)
++static char *mgdiff_basename (char *name);
++#endif
++
++enum {
++    WIDGET_LEFT        = 0x10000000,
++    WIDGET_RIGHT = 0x20000000
++} ;
+ 
+-#define APP_DEFAULTS_VERSION 1
++#define APP_DEFAULTS_VERSION 2
+ 
+ /* 
+  * treat failure to find the resources from the application defaults
+@@ -120,10 +132,16 @@ static char *basename (char *name);
+  */
+ 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 +155,7 @@ static Pixmap bitmap;
+ 
+ static struct screenstate {
+     Block *b;
++    Block *lastSelected;
+     int topline;
+     int leftcol;
+     int sindex, findex[2];
+@@ -170,7 +189,7 @@ static Widget form22, frame41, linenumr;
+ 
+ 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 +214,11 @@ static Boolean debug_flag;
+  * 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 +420,37 @@ static void drawit (Widget w, XtPointer
+     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 +459,10 @@ static void drawit (Widget w, XtPointer
+               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];
+           }
+@@ -520,7 +556,7 @@ static void drawit (Widget w, XtPointer
  /* ARGSUSED */
  static void file_cb (Widget w, XtPointer closure, XtPointer call_data)
  {
 -    switch ((int) closure) {
-+    switch ((uintptr_t) closure) {
++    switch ((intptr_t) closure) {
      case 0:                   /* open */
        toggle_open_sensitive (False);
        set_cursor (toplevel);
-@@ -560,7 +561,7 @@ static void file_cb (Widget w, XtPointer
+@@ -537,15 +573,32 @@ static void file_cb (Widget w, XtPointer
+       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:
+@@ -560,7 +613,7 @@ static void file_cb (Widget w, XtPointer
  /* ARGSUSED */
  static void view_cb (Widget w, XtPointer closure, XtPointer call_data)
  {
 -    switch ((int) closure) {
-+    switch ((uintptr_t) closure) {
++    switch ((intptr_t) closure) {
      case 0:                   /* previous */
        prev_diff (NULL, NULL, NULL);
        break;
-@@ -582,7 +583,7 @@ static void view_cb (Widget w, XtPointer
+@@ -582,7 +635,7 @@ static void view_cb (Widget w, XtPointer
  /* ARGSUSED */
  static void select_cb (Widget w, XtPointer closure, XtPointer call_data)
  {
 -    switch ((int) closure) {
-+    switch ((uintptr_t) closure) {
++    switch ((intptr_t) closure) {
      case 0:                   /* left */
        select_all (LEFT);
        break;
-@@ -604,7 +605,7 @@ static void select_cb (Widget w, XtPoint
+@@ -604,7 +657,7 @@ static void select_cb (Widget w, XtPoint
  /* ARGSUSED */
  static void options_cb (Widget w, XtPointer closure, XtPointer call_data)
  {
 -    switch ((int) closure) {
-+    switch ((uintptr_t) closure) {
++    switch ((intptr_t) closure) {
      case 0:                   /* toggle overview area */
        overview_flag = !overview_flag;
        if (overview_flag) {
-@@ -660,7 +661,7 @@ static void options_cb (Widget w, XtPoin
+@@ -660,7 +713,7 @@ static void options_cb (Widget w, XtPoin
  /* ARGSUSED */
  static void helpmenu_cb (Widget w, XtPointer closure, XtPointer call_data)
  {
 -    switch ((int) closure) {
-+    switch ((uintptr_t) closure) {
++    switch ((intptr_t) closure) {
      case 0:                   /* version */
        show_version (toplevel);
        break;
-@@ -1110,7 +1111,9 @@ int main (int argc, char *argv[])
+@@ -724,7 +777,6 @@ static void set_pixmaps (WidgetList chil
+       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 +807,7 @@ static void set_pixmaps (WidgetList chil
+       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 +815,7 @@ static void set_pixmaps (WidgetList chil
+       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 +958,7 @@ static void add_actions (XtAppContext ap
+      */
+     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 +1004,9 @@ static void add_actions (XtAppContext ap
+  */
+ static void cleanup_at_exit (void)
+ {
+-    if (tempfname != NULL)
++    if (strlen (tempfname) > 0)
+       (void) unlink (tempfname);
++    tempfname [0] = 0 ; 
+ }
+ 
+ /* 
+@@ -1017,8 +1071,11 @@ int main (int argc, char *argv[])
+     {"quitIfSame", "QuitIfSame", XtRBoolean, sizeof (Boolean), 0, XtRString, "false"},
+     {"debug", "Debug", XtRBoolean, sizeof (Boolean), 0, XtRString, "false"},
+     {"filename", "Filename", XtRString, sizeof (String), 0, XtRString, ""}};
+-    
++#if !(defined __GLIBC__ && __GLIBC__ >= 2)
++    progname = mgdiff_basename (argv[0]);
++#else
+     progname = basename (argv[0]);
++#endif
+ 
+     toplevel = XtVaAppInitialize (&app, "Mgdiff", option_table, XtNumber (option_table),
+ #if X11R5
+@@ -1027,6 +1084,10 @@ int main (int argc, char *argv[])
+                                 (unsigned int *) &argc,
+ #endif
+                                 argv, fallbacks, NULL);
++    setlocale (LC_ALL, "");
++    setlocale (LC_CTYPE, "POSIX");
++    XtSetLanguageProc (app, NULL, NULL);
++
+ 
+     XtVaGetValues (toplevel, XmNdepth, &depth, NULL);
+     if (depth == 1)
+@@ -1079,7 +1140,6 @@ int main (int argc, char *argv[])
+       };
+       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 +1147,10 @@ int main (int argc, char *argv[])
+     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 +1172,17 @@ int main (int argc, char *argv[])
+        * 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");
-+          char xxx[20];
-+          sprintf(tempfname, "mgdif.XXXXXXXX");
-+          close(mkstemp (tempfname));
-           str_fnamel = strdup (tempfname);
-           str_snamel = strdup (user_filename);
-           if (!copy_to_file (stdin, tempfname)) {
-@@ -1131,7 +1134,9 @@ int main (int argc, char *argv[])
+-          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 +1197,12 @@ int main (int argc, char *argv[])
        }
  
        if (strcmp (argv[2], "-") == 0) {
 -          tempfname = tempnam (NULL, "mgdif");
-+         char xxx[20];
-+            sprintf(tempfname, "mgdif.XXXXXXXX");
-+            close(mkstemp (tempfname));
-           str_fnamer = strdup (tempfname);
-           str_snamer = strdup (user_filename);
-           if (!copy_to_file (stdin, tempfname)) {
+-          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 +1239,7 @@ int main (int argc, char *argv[])
+     }
+ 
+     newss.b = di->first;
++    newss.lastSelected= NULL;
+     newss.topline = newss.sindex = newss.findex[LEFT] = newss.findex[RIGHT] = 0;
+ 
+     mainw = XtVaCreateManagedWidget ("mainw", xmMainWindowWidgetClass,
+@@ -1205,10 +1271,13 @@ int main (int argc, char *argv[])
+                                 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 +1560,7 @@ int main (int argc, char *argv[])
+ 
+     XtAppMainLoop (app);
+     /* NOTREACHED */
++    return 0;
+ }
+ 
+ static void redraw_partial_vert (Widget w)
+@@ -1622,9 +1692,9 @@ static void update_line_numbers (int l,
+ {
+     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);
+ }
+ 
+@@ -1860,19 +1930,20 @@ static void next_diff (Widget w, XtPoint
+ 
+           value = (b->sline >= lines_of_context) ? (b->sline - lines_of_context) : b->sline;
+           XtVaGetValues (sb, XmNmaximum, &maximum, XmNsliderSize, &slidersize, NULL);
+-          if (value > (maximum - slidersize))
+-              value = maximum - slidersize;
+ 
+           if ((w == sbl) || (w == sbr)) {
+               int side = (w == sbl) ? LEFT : RIGHT;
+ 
+-              if (newcbs.value > (maximum - slidersize)) {
+-                  newcbs.value = maximum - slidersize;
+-                  XtVaSetValues (w, XmNvalue, newcbs.value - b->sline + b->arr[side].fline, NULL);
++              if (value > (maximum - slidersize)) {
++                  value = maximum - slidersize;
++                  XtVaSetValues (w, XmNvalue, value - b->sline + b->arr[side].fline, NULL);
+                   return;
+               }
+           }
+ 
++          if (value > (maximum - slidersize))
++              value = maximum - slidersize;
++
+           newcbs.reason = XmCR_VALUE_CHANGED;
+           newcbs.event = NULL;
+           newcbs.value = value;
+@@ -1986,7 +2057,7 @@ static void show_version (Widget parent)
+                                             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@localhost)\nVersion: %s PL%s", VERSION, PATCHLEVEL);
++      (void) snprintf (buffer, sizeof (buffer), "mgdiff\n\nA graphical difference browser\n\nAuthors: Dan Williams (dan%sass.com@localhost)\nErik de Castro Lopo 
(erikd%mega-nerd.com@localhost)\n\nVersion: %s PL%s", VERSION, PATCHLEVEL);
+ 
+       XtVaSetValues (dialog,
+                      XmNautoUnmanage, True,
+@@ -2041,12 +2112,12 @@ void process_both_files (char *file1, ch
+     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 +2153,7 @@ void process_left_file (char *file1, cha
+     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 +2188,7 @@ void process_right_file (char *file2, ch
+     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 +2204,7 @@ void process_right_file (char *file2, ch
+     handle_diff_errors (di);
+ }
+ 
++
+ static void refresh (void)
+ {
+     newss.b = di->first;
+@@ -2182,9 +2254,11 @@ void toggle_open_sensitive (Boolean sens
+     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 +2270,263 @@ static void exit_cb (Widget w, XtPointer
+     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 +2566,14 @@ static void Scroll (Widget widget, XEven
+       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 +2650,8 @@ static Dimension get_preferred_width (Wi
+ /* 
+  * delete any prefix ending in '/' and return a copy
+  */
+-static char *basename (char *path)
++#if !(defined __GLIBC__ && __GLIBC__ >= 2)
++static char *mgdiff_basename (char *path)
+ {
+     if (path) {
+       char *p;
+@@ -2416,3 +2676,4 @@ static char *basename (char *path)
+     else
+       return (NULL);
+ }
++#endif

Added files:

Index: pkgsrc/devel/mgdiff/files/README.pkgsrc
diff -u /dev/null pkgsrc/devel/mgdiff/files/README.pkgsrc:1.1
--- /dev/null   Wed Mar  1 23:48:00 2023
+++ pkgsrc/devel/mgdiff/files/README.pkgsrc     Wed Mar  1 23:48:00 2023
@@ -0,0 +1,18 @@
+
+In order to read the default X resources and Motif widget settings,
+Mgdiff requires the XAPPLRESDIR environmental variable to be set to:
+
+       @PREFIX@/lib/X11/app-defaults
+
+-----------------------------------------------------------------------
+
+This distribution comes bundled with the following scripts:
+
+* rmgdiff allows the user to recursively diff two
+  directories using any graphical diff viewer -- including mgdiff.
+
+* cvsmgdiff allows the user to compare a revision in a  
+  CVS archive with what is currently checked out or to compare two
+  revision both of which are in the archive.
+
+See the relevant man pages for more information.
Index: pkgsrc/devel/mgdiff/files/cvsmgdiff
diff -u /dev/null pkgsrc/devel/mgdiff/files/cvsmgdiff:1.1
--- /dev/null   Wed Mar  1 23:48:00 2023
+++ pkgsrc/devel/mgdiff/files/cvsmgdiff Wed Mar  1 23:48:00 2023
@@ -0,0 +1,245 @@
+#!/usr/bin/env ksh
+
+#
+# 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:=@PREFIX@/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
Index: pkgsrc/devel/mgdiff/files/cvsmgdiff.1
diff -u /dev/null pkgsrc/devel/mgdiff/files/cvsmgdiff.1:1.1
--- /dev/null   Wed Mar  1 23:48:00 2023
+++ pkgsrc/devel/mgdiff/files/cvsmgdiff.1       Wed Mar  1 23:48:00 2023
@@ -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: \fImgdiff\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@localhost>
+for the Debian GNU/Linux project, but may
+be used by others.  It was written with the assistance  of
+\&\fIpod2man\fR\|(1).
Index: pkgsrc/devel/mgdiff/files/mgdiff-48x48.xpm
diff -u /dev/null pkgsrc/devel/mgdiff/files/mgdiff-48x48.xpm:1.1
--- /dev/null   Wed Mar  1 23:48:00 2023
+++ pkgsrc/devel/mgdiff/files/mgdiff-48x48.xpm  Wed Mar  1 23:48:00 2023
@@ -0,0 +1,561 @@
+/* XPM */
+static char * mgdiff_48x48_xpm[] = {
+"48 48 510 2",
+"      c None",
+".     c #F6F6F6",
+"+     c #F5F5F5",
+"@     c #F4F4F4",
+"#     c #F3F3F3",
+"$     c #F2F2F2",
+"%     c #F1F1F1",
+"&     c #F0F0F0",
+"*     c #EFEFEF",
+"=     c #EEEEEE",
+"-     c #EDEDED",
+";     c #DB4654",
+">     c #C01336",
+",     c #BC1036",
+"'     c #BB1037",
+")     c #B5133F",
+"!     c #A3215A",
+"~     c #90458C",
+"{     c #969ADD",
+"]     c #E5E7EF",
+"^     c #ECC7CB",
+"/     c #D31B30",
+"(     c #AD1546",
+"_     c #4C64DD",
+":     c #EDEEF1",
+"<     c #DA2B3C",
+"[     c #C50B2A",
+"}     c #2B4DDF",
+"|     c #E5828B",
+"1     c #CA1935",
+"2     c #BC0F36",
+"3     c #BE0F33",
+"4     c #6E3798",
+"5     c #A6B3ED",
+"6     c #D82637",
+"7     c #D50317",
+"8     c #B30C39",
+"9     c #6F3D9D",
+"0     c #A9B5EB",
+"a     c #ECC2C6",
+"b     c #C30829",
+"c     c #2E4ADA",
+"d     c #EDEEF2",
+"e     c #D50418",
+"f     c #163BDD",
+"g     c #E26B76",
+"h     c #6C2182",
+"i     c #90A0EA",
+"j     c #ECECEC",
+"k     c #D92839",
+"l     c #163ADC",
+"m     c #EFDADC",
+"n     c #D88697",
+"o     c #CA203C",
+"p     c #662389",
+"q     c #94A3E8",
+"r     c #ECC1C5",
+"s     c #C1082B",
+"t     c #2F4BDA",
+"u     c #D50519",
+"v     c #D30318",
+"w     c #3B31B6",
+"x     c #C9C7E6",
+"y     c #EBE3EB",
+"z     c #EAE2EA",
+"A     c #EBE2EA",
+"B     c #EBECF3",
+"C     c #E26C77",
+"D     c #8E175F",
+"E     c #6C7ADC",
+"F     c #EAE8EF",
+"G     c #F2F3F5",
+"H     c #D92939",
+"I     c #2237CF",
+"J     c #E0E3ED",
+"K     c #E58F98",
+"L     c #442DAC",
+"M     c #BDC6ED",
+"N     c #EEEFF3",
+"O     c #3433BD",
+"P     c #D1D6F0",
+"Q     c #8B1863",
+"R     c #6B82E6",
+"S     c #DFE2EC",
+"T     c #DB3D4C",
+"U     c #A81045",
+"V     c #4A65E1",
+"W     c #E36D78",
+"X     c #6C82E6",
+"Y     c #EBEBEB",
+"Z     c #EDD7D9",
+"`     c #C70624",
+" .    c #2746DB",
+"..    c #F0F0F2",
+"+.    c #3433BE",
+"@.    c #D1D6EF",
+"#.    c #8A1863",
+"$.    c #6C82E5",
+"%.    c #F1EEEE",
+"&.    c #D61124",
+"*.    c #1939D9",
+"=.    c #EEEFF2",
+"-.    c #E9EAEE",
+";.    c #65248A",
+">.    c #A56FA3",
+",.    c #B67DA6",
+"'.    c #B87EA7",
+").    c #B87FA7",
+"!.    c #B0A1D1",
+"~.    c #D5D9EC",
+"{.    c #E16B76",
+"].    c #A2114B",
+"^.    c #794AA3",
+"/.    c #B980A9",
+"(.    c #B97FA8",
+"_.    c #B789B4",
+":.    c #B9C1EB",
+"<.    c #E2E4EF",
+"[.    c #F0EEEE",
+"}.    c #D71D2F",
+"|.    c #2C34C5",
+"1.    c #D8DCEF",
+"2.    c #EBC0C4",
+"3.    c #2F4AD9",
+"4.    c #DCDDE0",
+"5.    c #CECECE",
+"6.    c #C2C2C2",
+"7.    c #D40519",
+"8.    c #63248C",
+"9.    c #8998DA",
+"0.    c #DEDEDE",
+"a.    c #E1E1E1",
+"b.    c #D9636E",
+"c.    c #2D4CDB",
+"d.    c #EEEEF0",
+"e.    c #F1EFEF",
+"f.    c #2E33C3",
+"g.    c #D5DAEF",
+"h.    c #EABFC3",
+"i.    c #2D48D7",
+"j.    c #C6C7CB",
+"k.    c #B7B7B7",
+"l.    c #ACACAC",
+"m.    c #D40418",
+"n.    c #D40317",
+"o.    c #761E78",
+"p.    c #833871",
+"q.    c #934675",
+"r.    c #984B7A",
+"s.    c #9B4E7D",
+"t.    c #9F5080",
+"u.    c #8C79B4",
+"v.    c #AFB5CE",
+"w.    c #CFCFCF",
+"x.    c #C7C7C7",
+"y.    c #D15A66",
+"z.    c #A90F44",
+"A.    c #7D3789",
+"B.    c #A85B8A",
+"C.    c #A95B8B",
+"D.    c #AC5F8E",
+"E.    c #AE6190",
+"F.    c #AA6B9E",
+"G.    c #A4AFE7",
+"H.    c #D82839",
+"I.    c #EFECEC",
+"J.    c #D61427",
+"K.    c #1B39D6",
+"L.    c #E8E9EE",
+"M.    c #E8E8E8",
+"N.    c #DDB2B7",
+"O.    c #2742D1",
+"P.    c #95969A",
+"Q.    c #868686",
+"R.    c #7A7A7A",
+"S.    c #3432BD",
+"T.    c #AAAFC8",
+"U.    c #DBDBDB",
+"V.    c #E2E2E2",
+"W.    c #EAEAEA",
+"X.    c #E9E9E9",
+"Y.    c #E7E7E7",
+"Z.    c #DE6772",
+"`.    c #657BDE",
+" +    c #DDDDDD",
+".+    c #DADADA",
+"++    c #DEE1EB",
+"@+    c #EDE0E1",
+"#+    c #CC0520",
+"$+    c #2141DA",
+"%+    c #CCCDCF",
+"&+    c #A97E82",
+"*+    c #213CCA",
+"=+    c #56575B",
+"-+    c #888888",
+";+    c #B2B2B2",
+">+    c #CDD3ED",
+",+    c #E26B77",
+"'+    c #6980E3",
+")+    c #DB5C68",
+"!+    c #AE0E3E",
+"~+    c #324FD1",
+"{+    c #79797A",
+"]+    c #5D5D5D",
+"^+    c #63393D",
+"/+    c #B7B7BB",
+"(+    c #D1D1D1",
+"_+    c #F7F7F7",
+":+    c #E36C78",
+"<+    c #DCDFEA",
+"[+    c #D0999E",
+"}+    c #582797",
+"|+    c #4D5A93",
+"1+    c #606060",
+"2+    c #515151",
+"3+    c #8A5F63",
+"4+    c #2E49D8",
+"5+    c #E5E5E9",
+"6+    c #D82738",
+"7+    c #E3E4E7",
+"8+    c #E6E6E6",
+"9+    c #E3E3E3",
+"0+    c #DDD6D6",
+"a+    c #CDA3AB",
+"b+    c #B2435D",
+"c+    c #8D1760",
+"d+    c #2D44A9",
+"e+    c #717171",
+"f+    c #898989",
+"g+    c #AFAFAF",
+"h+    c #D4A9AD",
+"i+    c #2F4BD9",
+"j+    c #EAEBEF",
+"k+    c #D0D6EF",
+"l+    c #E4E4E4",
+"m+    c #D72637",
+"n+    c #D20319",
+"o+    c #7A1D74",
+"p+    c #4053A8",
+"q+    c #9B9B9B",
+"r+    c #B3B3B3",
+"s+    c #E4B9BD",
+"t+    c #C2082A",
+"u+    c #D7D7D7",
+"v+    c #DCDCDC",
+"w+    c #D52B3B",
+"x+    c #CF051D",
+"y+    c #CE051D",
+"z+    c #CF041D",
+"A+    c #CD051E",
+"B+    c #C70724",
+"C+    c #B10D39",
+"D+    c #891758",
+"E+    c #562E7A",
+"F+    c #5C557E",
+"G+    c #999CA9",
+"H+    c #CCCCCC",
+"I+    c #E7BEC2",
+"J+    c #BC0A30",
+"K+    c #3450DB",
+"L+    c #E9EAED",
+"M+    c #D60E21",
+"N+    c #CD051F",
+"O+    c #3A38BE",
+"P+    c #CFD5ED",
+"Q+    c #E3707B",
+"R+    c #D2061B",
+"S+    c #891B66",
+"T+    c #6F85E6",
+"U+    c #CDCDCD",
+"V+    c #B8B8B8",
+"W+    c #919191",
+"X+    c #626262",
+"Y+    c #2E2E2E",
+"Z+    c #0C0C0C",
+"`+    c #242424",
+" @    c #A2A2A2",
+".@    c #CBCBCB",
+"+@    c #D8D8D8",
+"@@    c #E0E0E0",
+"#@    c #E5E5E5",
+"$@    c #BEBEBE",
+"%@    c #B6B6B6",
+"&@    c #9F9F9F",
+"*@    c #252525",
+"=@    c #070707",
+"-@    c #090909",
+";@    c #272727",
+">@    c #838383",
+",@    c #D5D5D5",
+"'@    c #DFDFDF",
+")@    c #848484",
+"!@    c #3D3D3D",
+"~@    c #0B0B0B",
+"{@    c #000000",
+"]@    c #1C1C1C",
+"^@    c #949494",
+"/@    c #D4D4D4",
+"(@    c #BABABA",
+"_@    c #C4C4C4",
+":@    c #D0D0D0",
+"<@    c #D3D3D3",
+"[@    c #616161",
+"}@    c #343434",
+"|@    c #0E0E0E",
+"1@    c #040404",
+"2@    c #121212",
+"3@    c #262626",
+"4@    c #CACACA",
+"5@    c #D9D9D9",
+"6@    c #BDBDBD",
+"7@    c #B5B5B5",
+"8@    c #ABABAB",
+"9@    c #AAAAAA",
+"0@    c #6A6A6A",
+"a@    c #969696",
+"b@    c #9E9E9E",
+"c@    c #999999",
+"d@    c #959595",
+"e@    c #464646",
+"f@    c #222222",
+"g@    c #282828",
+"h@    c #C9C9C9",
+"i@    c #BCBCBC",
+"j@    c #5C5C5C",
+"k@    c #6F6F6F",
+"l@    c #646464",
+"m@    c #181818",
+"n@    c #373737",
+"o@    c #393939",
+"p@    c #323232",
+"q@    c #1D1D1D",
+"r@    c #1E1E1E",
+"s@    c #131313",
+"t@    c #3B3B3B",
+"u@    c #353535",
+"v@    c #4D4D4D",
+"w@    c #5F5F5F",
+"x@    c #828282",
+"y@    c #575757",
+"z@    c #333333",
+"A@    c #3C3C3C",
+"B@    c #545454",
+"C@    c #989898",
+"D@    c #D6D6D6",
+"E@    c #C5C5C5",
+"F@    c #2D2D2D",
+"G@    c #161616",
+"H@    c #030303",
+"I@    c #020202",
+"J@    c #292929",
+"K@    c #2B2B2B",
+"L@    c #505050",
+"M@    c #313131",
+"N@    c #535353",
+"O@    c #878787",
+"P@    c #7F7F7F",
+"Q@    c #ADADAD",
+"R@    c #BFBFBF",
+"S@    c #7D7D7D",
+"T@    c #232323",
+"U@    c #0F0F0F",
+"V@    c #2A2A2A",
+"W@    c #5E5E5E",
+"X@    c #797979",
+"Y@    c #525252",
+"Z@    c #2C2C2C",
+"`@    c #9C9C9C",
+" #    c #A6A6A6",
+".#    c #C3C3C3",
+"+#    c #C0C0C0",
+"@#    c #363636",
+"##    c #080808",
+"$#    c #101010",
+"%#    c #0A0A0A",
+"&#    c #1F1F1F",
+"*#    c #444444",
+"=#    c #3E3E3E",
+"-#    c #727272",
+";#    c #565656",
+">#    c #808080",
+",#    c #3A3A3A",
+"'#    c #141414",
+")#    c #1B1B1B",
+"!#    c #4A4A4A",
+"~#    c #232224",
+"{#    c #414141",
+"]#    c #292729",
+"^#    c #383838",
+"/#    c #202020",
+"(#    c #050505",
+"_#    c #151515",
+":#    c #424242",
+"<#    c #6B6B6B",
+"[#    c #6E6E6E",
+"}#    c #858585",
+"|#    c #C6C6C6",
+"1#    c #303030",
+"2#    c #1E2720",
+"3#    c #19391B",
+"4#    c #1B3411",
+"5#    c #4E5A53",
+"6#    c #517A53",
+"7#    c #A6A5A6",
+"8#    c #C8C8C8",
+"9#    c #656565",
+"0#    c #484848",
+"a#    c #939393",
+"b#    c #D2D2D2",
+"c#    c #A7A7A7",
+"d#    c #8A8A8A",
+"e#    c #18421B",
+"f#    c #08630B",
+"g#    c #172B1F",
+"h#    c #242324",
+"i#    c #262526",
+"j#    c #37423D",
+"k#    c #3F853E",
+"l#    c #A2A1A2",
+"m#    c #5B5B5B",
+"n#    c #686868",
+"o#    c #3F3F3F",
+"p#    c #171717",
+"q#    c #0D0D0D",
+"r#    c #454545",
+"s#    c #555555",
+"t#    c #7E7E7E",
+"u#    c #A3A3A3",
+"v#    c #787878",
+"w#    c #111111",
+"x#    c #B4B4B4",
+"y#    c #2F2F2F",
+"z#    c #1C4426",
+"A#    c #11750F",
+"B#    c #1D4113",
+"C#    c #1F331C",
+"D#    c #2A2D2C",
+"E#    c #2B4A2E",
+"F#    c #178E17",
+"G#    c #248722",
+"H#    c #647466",
+"I#    c #6D6D6D",
+"J#    c #494949",
+"K#    c #060606",
+"L#    c #2F392E",
+"M#    c #278426",
+"N#    c #2CA72C",
+"O#    c #187C19",
+"P#    c #1C701E",
+"Q#    c #2B892B",
+"R#    c #23A223",
+"S#    c #2C822A",
+"T#    c #2F322F",
+"U#    c #C1C1C1",
+"V#    c #595959",
+"W#    c #B0B0B0",
+"X#    c #6C6C6C",
+"Y#    c #AEAEAE",
+"Z#    c #383738",
+"`#    c #4A674E",
+" $    c #2D9C2D",
+".$    c #2EA92F",
+"+$    c #3DB23D",
+"@$    c #2CA32C",
+"#$    c #3B9D39",
+"$$    c #5A6A5A",
+"%$    c #313031",
+"&$    c #191919",
+"*$    c #636363",
+"=$    c #A9A9A9",
+"-$    c #8D8D8D",
+";$    c #909090",
+">$    c #4B4C4B",
+",$    c #345D34",
+"'$    c #3A7E3B",
+")$    c #528052",
+"!$    c #657E65",
+"~$    c #576756",
+"{$    c #4F4F50",
+"]$    c #1A1A1A",
+"^$    c #434343",
+"/$    c #585858",
+"($    c #A5A5A5",
+"_$    c #A0A0A0",
+":$    c #545254",
+"<$    c #494649",
+"[$    c #535153",
+"}$    c #545354",
+"|$    c #404040",
+"1$    c #696969",
+"2$    c #8C8C8C",
+"3$    c #BBBBBB",
+"4$    c #A8A8A8",
+"5$    c #4C4C4C",
+"6$    c #474747",
+"7$    c #707070",
+"8$    c #818181",
+"9$    c #A4A4A4",
+"0$    c #5A5A5A",
+"a$    c #8B8B8B",
+"b$    c #8E8E8E",
+"c$    c #B9B9B9",
+"d$    c #4E4E4E",
+"e$    c #B1B1B1",
+"f$    c #777777",
+"g$    c #757575",
+"h$    c #666666",
+"i$    c #212121",
+"j$    c #979797",
+"k$    c #4B4B4B",
+". + + @ @ # $ $ $ % $ % & & % $ # @ @ @ + + + . . . . . . . . . . . . . . . . . . . . . . . . . ",
+"@ $ % & & * * = = * * * * * * * & % % % % # + + . . . . . . . . . . . . . . . . . . . . . . . . ",
+"% * = - - - - = = * * * * & % % % % % & * & # @ + + + + + + + + + + + + + + + + + + + + + . . . ",
+"= - ; > , , ' ) ! ~ { ] & $ $ $ $ $ ^ / ( _ : # @ < , , , , , , , [ } + + | 1 2 , , , , , 3 4 5 ",
+"- - 6 7 7 7 7 7 7 7 7 8 9 0 # # $ # a 7 b c d # @ e 7 7 7 7 7 7 7 7 f + + g 7 7 7 7 7 7 7 7 h i ",
+"j - k 7 l * & & m n o 7 7 p q # # # r 7 s t d # @ u v w x y z y y A B @ + C 7 D E y y z y z F G ",
+"j = H 7 I J * % % % & K 7 7 L M # # r 7 s t N # @ u v O P @ + + . + . + + C 7 Q R + . + @ @ @ . ",
+"j j k 7 I S * % % % % $ T 7 U V $ $ a 7 s t N @ # u v O P @ @ . + + + . + W 7 Q X . @ @ @ @ @ + ",
+"Y j k 7 I J & & $ & % $ Z 7 `  ...# a 7 s t d $ # u v +.@.@ + @ @ @ . . + C 7 #.$.@ @ @ # # $ @ ",
+"Y - k 7 I J = % % % % % %.&.7 *.=.$ r 7 s t -.= j u v ;.>.,.,.'.).!.~.& % {.7 ].^./.(./.(._.:.$ ",
+"j j k 7 I <.* & % % & % [.}.7 |.1.$ 2.7 s 3.4.5.6.7.7 7 7 7 7 7 7 8.9.0.a.b.7 7 7 7 7 7 7 s c.d.",
+"j j k 7 I J & % & % & & e.}.7 f.g.% h.7 s i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.7 z.A.B.C.D.E.F.G.* ",
+"j j H.7 I S * % * * * & I.J.7 K.L.M.N.7 s O.P.Q.R.m.v S.T.U.V.U.W.X.X.Y.Y Z.7 #.`. +.+.+a.X.= & ",
+"j - H.7 I ++= = * = = = @+7 #+$+%+k.&+7 s *+=+-+;+7.v O >+$ # + + + + . + ,+7 Q '+* = - Y Y - & ",
+"j j H.7 I ++- - - j j Y )+7 !+~+{+]+^+7 s O./+(+V.u v O P @ + . . + _+_+_+:+7 Q R @ + @ # $ % % ",
+"W.W.H.7 I <+Y W.X.M.V.[+7 7 }+|+1+2+3+7 s 4+5+= = u v O P @ + + . + + . . :+7 Q X _+. . + # # # ",
+"X.X.6+7 *.7+8+9+0+a+b+7 7 c+d+e+f+g+h+7 s i+j+% % u v O k+@ @ @ @ @ @ + + :+7 Q R . . . + + @ @ ",
+"l+l+m+7 7 7 7 7 7 7 7 n+o+p+q+r+(+ +s+7 t+3.j+% % u v O k+# # @ @ # @ @ @ C 7 Q R + + . @ + + + ",
+"u+v+w+x+y+z+A+B+C+D+E+F+G+H+.+V.M.X.I+7 J+K+L+= = M+N+O+P+$ $ $ # # $ # # Q+R+S+T++ . + + @ @ @ ",
+"U+U+x.V+W+X+Y+Z+`+]+ @.@+@@@9+#@Y.M.Y Y X.X.W.Y Y j * * * * & % % $ $ $ $ $ @ @ @ @ @ @ + @ @ @ ",
+"$@%@&@X+*@=@-@;@>@V+,@'@V.a.V.a.a.a.@@9+0..+V.l+#@8+M.M.W.j j - - * * % % $ $ @ # @ # # @ @ @ @ ",
+" @)@!@~@{@~@]@^@U+U.0.'@0.'@0./@5.w.(+U+(@_@:@:@<@/@:@(+'@@@@@l+Y.W.Y Y = = * % % $ $ # @ # # @ ",
+"[@}@|@1@2@3@-+4@U.@@@@a.'@5@:@6@;+7@8@9@0@a@b@q+c@^@d@8@l.(@x..@:@u+v+9+8+X.Y - * % % $ $ $ $ $ ",
+"e@3@Z+f@g@W+(+'@V.l+V.'@u+h@i@^@j@k@l@[@m@n@o@p@q@r@s@t@u@v@w@>@x@c@k.x.<@.+V.8+Y j - & % % % % ",
+"y@z@A@B@C@<@0.9+8+#@@@D@E@l.-+F@G@H@I@-@r@*@`+`+3@J@F@3@K@L@2+M@q@K@N@O@ @V+x.+@a.8+W.j = = * % ",
+"P@k@d@Q@<@ +9+Y.8+V.:@R@S@v@]@H@{@{@2@`+T@T@T@T@T@T@g@g@*@U@Z+V@W@X@Y@Z@!@1+`@ #.#<@ +l+M.Y Y j ",
+"k.+#x.<@0.a.l+Y.9+/@9@@#!@F@##H@I@$#T@T@T@T@T@T@f@T@T@T@`+m@%#&#n@*#=#-#;#3@!@1+>#r+x.(+U.l+Y.#@",
+",@w.D@U.@@9+#@V.U.;+=#,#T@'#)#Z@!#!@T@T@T@~#T@`+{#]#^#/#f@T@(#~@U@]@f@_#:#<#X+B@[#}#&@$@x.5@V.l+",
+".+5@ +@@l+l+9+0.|#1+1#s@##V@k@>@>@3@f@2#3#4#~#z@5#6#7#8#9#T@{#}@U@_#G@2@`+;@p@0#L@<#a#l.R@b#a.l+",
+"0.0.V.8+8+8+@@+@^@z@Z+##m@-#c#c#d#f@1#e#f#g#h#i#j#k#|#l#m#;@n#(@b@o#u@v@p###q#G@r#s#t#u#6.u+9+8+",
+"#@9+8+M.M.8+@@w.v#J@s@w#;#l.R@x#Q.y#y#z#A#B#C#D#E#F#G#H#o#3@k@:@u+x.X@I#J#Z+K#$#}@9#q+|#D@@@#@Y.",
+"W.M.W.W.W.Y.'@6.[@f@##g@&@.#|#$@q+o#K@L#M#N#O#P#Q#R#S#T#Z@g@a@.+'@U#!#*#V#e@J#e@X+`@6.+@l+8+X.W.",
+"j j j j Y Y.5@W#X#J@q#1+i@8#H+_@Y#[@3@Z#`# $.$+$@$#$$$%$`+o@_@9+'@k@=#T@&$!@*$x@=$x. +l+M.j * j ",
+"- = = - j Y.,@l.I#T@&$-$U#h@(+5.6@;$t@o#>$,$'$)$!$~${$^#V@f+@@9+X@]$^$J@!@/$m#($(+l+X.Y - * * = ",
+"- * * = - M..+r+}#o#m#_$+#U+<@<@5.(@>@B@X+:$<$[$}$;#|$}@1$.+a.)@^#!#*#J@=#2$3$.@l+Y - * & & $ * ",
+"- % % $ * X.'@_@ @n#d#4$3$|#(+D@/@w.(@2$X#5$N@6$V#5$@#7$.@,@8$*#[@;@r@/$R._$D@l+= * & & % % # & ",
+"* $ # $ & j @@.@Q@a#9$g+Y#k.x.<@/@/@5.E@4$R.0$2+[@>#($H+Q@x@M@W@|$)#^$W@`@/@V.= & % % # $ # # & ",
+"$ # # # % * 9+5.$@&@a$b$a$a#W#.#5.w.<@/@U+E@U#_@(+5.c$2$e+s#k@J#&#0#d$($/@M.% $ $ # $ # # # # % ",
+"# + + # $ & l+U+e$f$n@M@Y@B@f$q+W#6@_@h@h@_@|#c$c@;$a#7$g$6$o@l@t@7$g+u+8+& $ # # # # @ @ # # $ ",
+"# . + @ @ * l+/@W#X@5${#Y+^$Y@[@[@I#1+1$n#h$S@1+k@v#W@V#A@^#*#X+a#i@.+M.= % $ # # # # # $ # $ % ",
+"# . . @ @ * Y.D@%@a$W@o@M@/#i$]$`+*@&#V@V@{#@#K@y#0#Y+J#A@!#X@x#(+a.W.* % $ $ $ # @ # $ $ % % % ",
+"# . . + # % X.0.h@r+>#y@A@g@]@'#q#%#K#=@s@2@|@|@r@}@o#I#>#a#|#v+#@W.* % $ $ # # $ $ % % & % = & ",
+"# . + + % % - #@D@_@Q@j$X@W@k$:#^#F@f@p#f@/#'#r@F@y@7$b@x#(+.+Y.W.= % % $ $ # $ $ % % & & * - * ",
+"@ _++ @ % & = Y @@b#|#i@Q@9$_$j$W+b$x@9#O@S@f$>@_$7@U#5.U.9+8+X.- & & % $ # $ $ % % * * = - - = ",
+"@ . . @ $ * - W.Y. +,@U+4@.#U#+#U#R@k.g++#+#+#+#w.D@5@@@#@M.Y - = * & $ % % $ % % & * = * = = * ",
+"@ . + @ $ & = j Y #@ +D@b#(+(+(+(+b#:@H+<@b#b#D@+@v+'@9+M.Y j = * * % $ % % % $ & = & * * = = * ",
+"@ . + @ $ $ & - - X.9+0.5@u+D@u+u+u+u++@U.v+ +@@V.l+8+M.W.- = = * & & $ $ $ % & & * & & & & * % ",
+"+ + + @ # $ $ & = j j #@'@v+5@.+.+U.v+ +0.@@V.9+#@8+M.Y Y - = = = * & * $ & & & & & $ % % % & $ "};
Index: pkgsrc/devel/mgdiff/files/mgdiff.desktop
diff -u /dev/null pkgsrc/devel/mgdiff/files/mgdiff.desktop:1.1
--- /dev/null   Wed Mar  1 23:48:00 2023
+++ pkgsrc/devel/mgdiff/files/mgdiff.desktop    Wed Mar  1 23:48:00 2023
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Type=Application
+Name=Mgdiff
+GenericName=Diff/Patch Frontend
+Comment=Graphical front end to Unix diff
+Exec=mgdiff
+Terminal=false
+Icon=mgdiff-48x48
+StartupNotify=false
+MimeType=text/x-patch;text/x-diff;
+Categories=Application;Development;
Index: pkgsrc/devel/mgdiff/files/rmgdiff
diff -u /dev/null pkgsrc/devel/mgdiff/files/rmgdiff:1.1
--- /dev/null   Wed Mar  1 23:48:00 2023
+++ pkgsrc/devel/mgdiff/files/rmgdiff   Wed Mar  1 23:48:00 2023
@@ -0,0 +1,185 @@
+#!/bin/sh
+
+# Default value for the RMGDIFF_GUI environment variable.
+: ${RMGDIFF_GUI:=@PREFIX@/bin/mgdiff}
+
+#
+# You shouldn't need to edit beneath here.
+#
+
+SHOW_FILE_TYPES="TRUE"
+USE_CVS=""
+DEBUG=""
+USE_GUI="TRUE"
+RMGDIFF_VERSION=""
+LC_MESSAGES=POSIX
+export LC_MESSAGES
+
+
+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
+
+RMGDIFF_AWK=@PREFIX@/libexec/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
+
+LC_MESSAGES=C 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"
Index: pkgsrc/devel/mgdiff/files/rmgdiff.1
diff -u /dev/null pkgsrc/devel/mgdiff/files/rmgdiff.1:1.1
--- /dev/null   Wed Mar  1 23:48:00 2023
+++ pkgsrc/devel/mgdiff/files/rmgdiff.1 Wed Mar  1 23:48:00 2023
@@ -0,0 +1,98 @@
+.na
+.TH RMGDIFF 1
+.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@localhost)
Index: pkgsrc/devel/mgdiff/files/rmgdiff.awk
diff -u /dev/null pkgsrc/devel/mgdiff/files/rmgdiff.awk:1.1
--- /dev/null   Wed Mar  1 23:48:00 2023
+++ pkgsrc/devel/mgdiff/files/rmgdiff.awk       Wed Mar  1 23:48:00 2023
@@ -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 VCS 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|.bzr|.git|.svn)([ \/:]|$)/ )
+    {
+      if( debug )
+        print("Skipping VCS 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|.bzr|.git|.svn)([ \/:]|$)/ )
+    {
+      if( debug )
+        print("Skipping VCS 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 VCS entries.  Sort into two arrays for later printing.
+/^Only in / {
+  if( debug )
+    print("Start Only in");
+
+  if( !use_cvs && $0 ~ /[ \/](CVS|.bzr|.git|.svn)([ \/:]|$)/ )
+    {
+      if( debug )
+        print("Skipping VCS 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("");
+    }
+}

Index: pkgsrc/devel/mgdiff/patches/patch-Mgdiff.ad
diff -u /dev/null pkgsrc/devel/mgdiff/patches/patch-Mgdiff.ad:1.1
--- /dev/null   Wed Mar  1 23:48:01 2023
+++ pkgsrc/devel/mgdiff/patches/patch-Mgdiff.ad Wed Mar  1 23:48:00 2023
@@ -0,0 +1,58 @@
+$NetBSD: patch-Mgdiff.ad,v 1.1 2023/03/01 23:48:00 vins Exp $
+
+Pull patches from Debian.
+
+--- Mgdiff.ad.orig     1994-05-19 02:01:03.000000000 +0000
++++ Mgdiff.ad
+@@ -2,6 +2,8 @@
+ ! Mgdiff.ad,v 2.0 1994/05/19 02:01:03 dan Exp
+ !
+ 
++*XmScrollBar*width:       15
++
+ !
+ !                             widget hierarchy:
+ !
+@@ -112,7 +114,7 @@
+ !
+ ! this should only be defined in the site-wide file
+ !
+-?.AppDefaultsVersion:                 1
++?.AppDefaultsVersion:                 2
+ 
+ ?.Geometry:                           800x600
+ 
+@@ -169,9 +171,11 @@
+ !
+ ! the overview area
+ !
+-*sbl.width:                           16
+-*sbr.width:                           16
+-*dam.width:                           16
++*sbl.width:                           15
++*sbl.Background:                      lightgreen
++*sbr.width:                           15
++*sbr.Background:                      lightgreen
++*dam.width:                           30
+ *dam.Foreground:                      black
+ *dam.Background:                      cyan
+ 
+@@ -215,10 +219,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
Index: pkgsrc/devel/mgdiff/patches/patch-externs.h
diff -u /dev/null pkgsrc/devel/mgdiff/patches/patch-externs.h:1.1
--- /dev/null   Wed Mar  1 23:48:01 2023
+++ pkgsrc/devel/mgdiff/patches/patch-externs.h Wed Mar  1 23:48:00 2023
@@ -0,0 +1,33 @@
+$NetBSD: patch-externs.h,v 1.1 2023/03/01 23:48:00 vins Exp $
+
+Pull patches from Debian.
+
+--- externs.h.orig     1994-05-19 02:01:05.000000000 +0000
++++ externs.h
+@@ -28,8 +28,8 @@
+  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+  */
+ 
+-#ifndef lint
+-static char rcsid_externs_h[] = "externs.h,v 2.0 1994/05/19 02:01:05 dan Exp";
++#if 0
++static char rcsid_externs_h[] __attribute__((unused)) = "externs.h,v 2.0 1994/05/19 02:01:05 dan Exp";
+ #endif
+ 
+ extern int main (int argc, char *argv[]);
+@@ -43,7 +43,7 @@ extern DiffInfo *blank_diff_info (void);
+ extern DiffInfo *build_diff_info (char *prog, char *args, char *path1, char *path2);
+ extern int max (int i, int j);
+ extern int min (int i, int j);
+-extern int copy_to_file (FILE *fin, char *name);
++extern 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 add_editres (Widget shell);
+ 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
Index: pkgsrc/devel/mgdiff/patches/patch-files.c
diff -u /dev/null pkgsrc/devel/mgdiff/patches/patch-files.c:1.1
--- /dev/null   Wed Mar  1 23:48:01 2023
+++ pkgsrc/devel/mgdiff/patches/patch-files.c   Wed Mar  1 23:48:00 2023
@@ -0,0 +1,270 @@
+$NetBSD: patch-files.c,v 1.1 2023/03/01 23:48:00 vins Exp $
+
+Pull patches from Debian.
+
+--- files.c.orig       1994-05-19 02:01:06.000000000 +0000
++++ files.c
+@@ -1,9 +1,10 @@
+-#ifndef lint
+-static char rcsid[] = "files.c,v 2.0 1994/05/19 02:01:06 dan Exp";
++#if 0
++static char rcsid[] __attribute__((unused)) = "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 void popup_cb (Widget w, XtPointe
+  */
+ 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,12 +146,13 @@ void werror (Widget parent, char *title,
+     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);
+     dialog = XmCreateErrorDialog (parent, "werror", args, 2);
+-    XmStringFree (xms);
++    if (xms)
++      XmStringFree (xms);
+     XtVaSetValues (XtParent (dialog), XtNtitle, title, NULL);
+ 
+     XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON));
+@@ -174,8 +178,10 @@ void werror_long (Widget parent, char *t
+           xms1 = xms4;
+       else {
+           xms2 = XmStringConcat (xms1, xms4);
+-          XmStringFree (xms4);
+-          XmStringFree (xms1);
++          if (xms4)
++              XmStringFree (xms4);
++          if (xms1)
++              XmStringFree (xms1);
+           xms1 = xms2;
+       }
+ 
+@@ -183,16 +189,19 @@ void werror_long (Widget parent, char *t
+           XmString xms3;
+ 
+           xms3 = XmStringConcat (xms1, sep);
+-          XmStringFree (xms1);
++          if (xms1)
++              XmStringFree (xms1);
+           xms1 = xms3;
+       }
+     }
+-    XmStringFree (sep);
++    if (sep)
++      XmStringFree (sep);
+     
+     XtSetArg (args[0], XmNmessageString, xms1);
+     XtSetArg (args[1], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL);
+     dialog = XmCreateErrorDialog (parent, "werror", args, 2);
+-    XmStringFree (xms1);
++    if (xms1)
++      XmStringFree (xms1);
+     XtVaSetValues (XtParent (dialog), XtNtitle, title, NULL);
+     XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON));
+     XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON));
+@@ -318,7 +327,7 @@ void open_both_files (Widget parent, cha
+     Arg args[2];
+     int i;
+     char *dir;
+-    XmString xms;
++    XmString xms = (XmString)0;
+ 
+     shell = XtVaCreatePopupShell ("openfiles", xmDialogShellWidgetClass, parent,
+                                 XmNallowShellResize, True,
+@@ -349,7 +358,8 @@ void open_both_files (Widget parent, cha
+     fsb1 = XmCreateFileSelectionBox (frame1a, "files1", args, i);
+     if (dir) {
+       XtFree (dir);
+-      XmStringFree (xms);
++      if (xms)
++          XmStringFree (xms);
+     }
+ 
+     i = 0;
+@@ -360,7 +370,8 @@ void open_both_files (Widget parent, cha
+     fsb2 = XmCreateFileSelectionBox (frame2a, "files2", args, i);
+     if (dir) {
+       XtFree (dir);
+-      XmStringFree (xms);
++      if (xms)
++          XmStringFree (xms);
+     }
+ 
+     XtAddCallback (fsb1, XmNokCallback, filel_both_cb, shell);
+@@ -424,7 +435,7 @@ void open_left_file (Widget parent, char
+     Arg args[2];
+     int i;
+     char *dir;
+-    XmString xms;
++    XmString xms = (XmString)0;
+ 
+     i = 0;
+     XtSetArg (args[i], XmNdeleteResponse, XmDO_NOTHING); i++;
+@@ -435,7 +446,8 @@ void open_left_file (Widget parent, char
+     dialog = XmCreateFileSelectionDialog (parent, "openfile", args, i);
+     if (dir) {
+       XtFree (dir);
+-      XmStringFree (xms);
++      if (xms)
++          XmStringFree (xms);
+     }
+     XtAddCallback (XtParent (dialog), XmNpopupCallback, popup_cb, parent);
+     XtAddCallback (dialog, XmNokCallback, file_left_cb, dialog);
+@@ -477,7 +489,7 @@ void open_right_file (Widget parent, cha
+     Arg args[2];
+     int i;
+     char *dir;
+-    XmString xms;
++    XmString xms = (XmString)0;
+ 
+     i = 0;
+     XtSetArg (args[i], XmNdeleteResponse, XmDO_NOTHING); i++;
+@@ -488,7 +500,8 @@ void open_right_file (Widget parent, cha
+     dialog = XmCreateFileSelectionDialog (parent, "openfile", args, XtNumber (args));
+     if (dir) {
+       XtFree (dir);
+-      XmStringFree (xms);
++      if (xms)
++          XmStringFree (xms);
+     }
+ 
+     XtAddCallback (XtParent (dialog), XmNpopupCallback, popup_cb, parent);
+@@ -533,7 +546,7 @@ static void file_save_cb (Widget w, XtPo
+     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 +582,7 @@ void save_file (Widget parent, Block *b,
+     Arg args[3];
+     int i;
+     char *dir;
+-    XmString xms;
++    XmString xms = (XmString)0;
+ 
+     i = 0;
+     XtSetArg (args[i], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); i++;
+@@ -582,7 +595,8 @@ void save_file (Widget parent, Block *b,
+     dialog = XmCreateFileSelectionDialog (parent, "savefile", args, i);
+     if (dir) {
+       XtFree (dir);
+-      XmStringFree (xms);
++      if (xms)
++          XmStringFree (xms);
+     }
+ 
+     XtAddCallback (XtParent (dialog), XmNpopupCallback, popup_cb, parent);
+@@ -618,18 +632,32 @@ static int really_save_file (char *filen
+               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 +697,45 @@ static int write_chunk (FILE *file, Chun
+ 
+     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 */
Index: pkgsrc/devel/mgdiff/patches/patch-legend.c
diff -u /dev/null pkgsrc/devel/mgdiff/patches/patch-legend.c:1.1
--- /dev/null   Wed Mar  1 23:48:01 2023
+++ pkgsrc/devel/mgdiff/patches/patch-legend.c  Wed Mar  1 23:48:00 2023
@@ -0,0 +1,14 @@
+$NetBSD: patch-legend.c,v 1.1 2023/03/01 23:48:00 vins Exp $
+
+Pull patches from Debian.
+
+--- legend.c.orig      1994-05-19 02:01:08.000000000 +0000
++++ legend.c
+@@ -1,5 +1,5 @@
+-#ifndef lint
+-static char rcsid[] = "legend.c,v 2.0 1994/05/19 02:01:08 dan Exp";
++#if 0
++static char rcsid[] __attribute__((unused)) = "legend.c,v 2.0 1994/05/19 02:01:08 dan Exp";
+ #endif
+ 
+ /*
Index: pkgsrc/devel/mgdiff/patches/patch-manual.c
diff -u /dev/null pkgsrc/devel/mgdiff/patches/patch-manual.c:1.1
--- /dev/null   Wed Mar  1 23:48:01 2023
+++ pkgsrc/devel/mgdiff/patches/patch-manual.c  Wed Mar  1 23:48:00 2023
@@ -0,0 +1,40 @@
+$NetBSD: patch-manual.c,v 1.1 2023/03/01 23:48:00 vins Exp $
+
+Pull patches from Debian.
+
+--- manual.c.orig      1994-05-19 02:01:09.000000000 +0000
++++ manual.c
+@@ -1,5 +1,5 @@
+-#ifndef lint
+-static char rcsid[] = "manual.c,v 2.0 1994/05/19 02:01:09 dan Exp";
++#if 0
++static char rcsid[] __attribute__((unused)) = "manual.c,v 2.0 1994/05/19 02:01:09 dan Exp";
+ #endif
+ 
+ /*
+@@ -134,14 +134,14 @@ void show_manual_page (Widget parent)
+       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 @@ void show_manual_page (Widget parent)
+ 
+           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;
+       }
Index: pkgsrc/devel/mgdiff/patches/patch-mgdiff.h
diff -u /dev/null pkgsrc/devel/mgdiff/patches/patch-mgdiff.h:1.1
--- /dev/null   Wed Mar  1 23:48:01 2023
+++ pkgsrc/devel/mgdiff/patches/patch-mgdiff.h  Wed Mar  1 23:48:00 2023
@@ -0,0 +1,58 @@
+$NetBSD: patch-mgdiff.h,v 1.1 2023/03/01 23:48:00 vins Exp $
+
+Pull patches from Debian.
+
+--- mgdiff.h.orig      1994-05-19 02:01:15.000000000 +0000
++++ mgdiff.h
+@@ -1,8 +1,8 @@
+ #ifndef MXDIFF_H
+ #define MXDIFF_H
+ 
+-#ifndef lint
+-static char rcsid_mgdiff_h[] = "mgdiff.h,v 2.0 1994/05/19 02:01:15 dan Exp";
++#if 0
++static char rcsid_mgdiff_h[] __attribute__((unused)) = "mgdiff.h,v 2.0 1994/05/19 02:01:15 dan Exp";
+ #endif
+ 
+ /*
+@@ -52,7 +52,11 @@ typedef struct {
+     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,27 @@ typedef struct {
+  */
+ #define X11R5 (defined(XtSpecificationRelease) && (XtSpecificationRelease >= 5))
+ 
++#include <string.h>
++#include <stdlib.h>
++static inline char* xstrdup(const char *s)
++{
++    char *ret = strdup(s);
++    if (!ret) {
++        perror("strdup");
++        exit (1);
++    }
++    return ret;
++}
++
++/*
++ * According to IETF RFC 2279, byte values of 0xfe and 0xff are
++ * not legal utf-8, but all others bytes are legal.
++ */
++#if 1
++#define islatin(c)     (isprint((c)) || ((((unsigned char)(c)) <= 0xfd)))
++#define isallowed(c)  (isascii((c)) || islatin((c)))
++#else
++#define islatin(c)    ((isprint((c)) || ((((unsigned int)(c)) >= 160) && (((unsigned int)(c)) <= 255))))
++#define isallowed(c)  (isascii((c)) || islatin((c)))
++#endif
+ #endif
Index: pkgsrc/devel/mgdiff/patches/patch-mgdiff.man
diff -u /dev/null pkgsrc/devel/mgdiff/patches/patch-mgdiff.man:1.1
--- /dev/null   Wed Mar  1 23:48:01 2023
+++ pkgsrc/devel/mgdiff/patches/patch-mgdiff.man        Wed Mar  1 23:48:00 2023
@@ -0,0 +1,94 @@
+$NetBSD: patch-mgdiff.man,v 1.1 2023/03/01 23:48:00 vins Exp $
+
+Pull patches from Debian.
+
+--- mgdiff.man.orig    1994-05-19 02:01:16.000000000 +0000
++++ 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,
+@@ -82,6 +83,20 @@ track the lines being displayed in the t
+ .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 @@ specify an output file for writing the m
+ 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 @@ Mgdiff  mgdiff
+                                       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 @@ command assumes arguments are delimited
+ 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@localhost)
++.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.
Index: pkgsrc/devel/mgdiff/patches/patch-misc.c
diff -u /dev/null pkgsrc/devel/mgdiff/patches/patch-misc.c:1.1
--- /dev/null   Wed Mar  1 23:48:01 2023
+++ pkgsrc/devel/mgdiff/patches/patch-misc.c    Wed Mar  1 23:48:00 2023
@@ -0,0 +1,105 @@
+$NetBSD: patch-misc.c,v 1.1 2023/03/01 23:48:00 vins Exp $
+
+Pull patches from Debian.
+
+--- misc.c.orig        1994-05-19 02:01:19.000000000 +0000
++++ misc.c
+@@ -1,9 +1,10 @@
+-#ifndef lint
+-static char rcsid[] = "misc.c,v 2.0 1994/05/19 02:01:19 dan Exp";
++#if 0
++static char rcsid[] __attribute__((unused)) = "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 @@ static char rcsid[] = "misc.c,v 2.0 1994
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
+ 
+ #include <Xm/Xm.h>
+ #include <X11/cursorfont.h>
+@@ -40,6 +43,7 @@ static char rcsid[] = "misc.c,v 2.0 1994
+ #include <Xm/SashP.h>
+ 
+ #include "mgdiff.h"
++#include "externs.h"
+ 
+ int max (int i, int j)
+ {
+@@ -52,14 +56,49 @@ int min (int i, int j)
+ }
+ 
+ /* 
+- * 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;
+-
+-    if ((fout = fopen (name, "a")) == NULL)
+-      return (0);
++    FILE *fout ;
++    int fd ;
++#if !(defined __GLIBC__ && __GLIBC__ >= 2)
++    /*
++    **        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 ;
++    }
++#else
++    snprintf (name, name_len, "/tmp/mgdif-XXXXXX");
++    if ((fd = mkstemp(name)) < 0) {
++      perror("mkstemp");
++      exit(1);
++    }
++    if ((fout = fdopen (fd, "r+")) == NULL) {
++      close (fd);
++      perror("fdopen");
++      exit(1);
++    }
++#endif
+     while (!feof (fin)) {
+       char buffer[BUFSIZ];
+       int nitems;
+@@ -68,10 +107,12 @@ int copy_to_file (FILE *fin, char *name)
+       if (fwrite (buffer, 1, nitems, fout) != nitems)
+           break;
+     }
++
+     if (ferror (fin) || ferror (fout)) {
+       (void) fclose (fout);
+       return (1);
+     }
++
+     return ((fclose (fout) == 0));
+ }
+ 
Index: pkgsrc/devel/mgdiff/patches/patch-modal.c
diff -u /dev/null pkgsrc/devel/mgdiff/patches/patch-modal.c:1.1
--- /dev/null   Wed Mar  1 23:48:01 2023
+++ pkgsrc/devel/mgdiff/patches/patch-modal.c   Wed Mar  1 23:48:00 2023
@@ -0,0 +1,14 @@
+$NetBSD: patch-modal.c,v 1.1 2023/03/01 23:48:00 vins Exp $
+
+Pull patches from Debian.
+
+--- modal.c.orig       1994-05-19 02:01:20.000000000 +0000
++++ modal.c
+@@ -1,5 +1,5 @@
+-#ifndef lint
+-static char rcsid[] = "modal.c,v 2.0 1994/05/19 02:01:20 dan Exp";
++#if 0
++static char rcsid[] __attribute__((unused)) = "modal.c,v 2.0 1994/05/19 02:01:20 dan Exp";
+ #endif
+ 
+ /*
Index: pkgsrc/devel/mgdiff/patches/patch-patchlevel.h
diff -u /dev/null pkgsrc/devel/mgdiff/patches/patch-patchlevel.h:1.1
--- /dev/null   Wed Mar  1 23:48:01 2023
+++ pkgsrc/devel/mgdiff/patches/patch-patchlevel.h      Wed Mar  1 23:48:00 2023
@@ -0,0 +1,21 @@
+$NetBSD: patch-patchlevel.h,v 1.1 2023/03/01 23:48:00 vins Exp $
+
+Pull patches from Debian.
+
+--- patchlevel.h.orig  1994-05-19 02:01:21.000000000 +0000
++++ patchlevel.h
+@@ -28,11 +28,11 @@
+  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+  */
+ 
+-#ifndef lint
+-static char rcsid_patchlevel_h[] = "patchlevel.h,v 2.0 1994/05/19 02:01:21 dan Exp";
++#if 0
++static char rcsid_patchlevel_h[] __attribute__((unused)) = "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
Index: pkgsrc/devel/mgdiff/patches/patch-spawn.c
diff -u /dev/null pkgsrc/devel/mgdiff/patches/patch-spawn.c:1.1
--- /dev/null   Wed Mar  1 23:48:01 2023
+++ pkgsrc/devel/mgdiff/patches/patch-spawn.c   Wed Mar  1 23:48:00 2023
@@ -0,0 +1,84 @@
+$NetBSD: patch-spawn.c,v 1.1 2023/03/01 23:48:00 vins Exp $
+
+Pull patches from Debian.
+
+--- spawn.c.orig       1994-05-19 02:01:23.000000000 +0000
++++ spawn.c
+@@ -1,5 +1,5 @@
+-#ifndef lint
+-static char rcsid[] = "spawn.c,v 2.0 1994/05/19 02:01:23 dan Exp";
++#if 0
++static char rcsid[] __attribute__((unused)) = "spawn.c,v 2.0 1994/05/19 02:01:23 dan Exp";
+ #endif
+ 
+ /*
+@@ -35,8 +35,32 @@ static char rcsid[] = "spawn.c,v 2.0 199
+ #include <stdlib.h>
+ #include <errno.h>
+ 
++#include <X11/Intrinsic.h>
++
++#include "mgdiff.h"
++#include "externs.h"
++
+ #define BLOCKSIZE 10
+ 
++static inline void* xmalloc(size_t size)
++{
++    void *ret = malloc(size);
++    if (!ret) {
++      perror("malloc");
++      exit(1);
++    }
++    return ret;
++}
++static inline void* xrealloc(void *ptr, size_t size)
++{
++    void *ret = realloc(ptr, size);
++    if (!ret) {
++      perror("realloc");
++      exit(1);
++    }
++    return ret;
++}
++
+ /* 
+  * run a program with command line arguments and two pathname 
+  * arguments via fork/exec and return a pipe file descriptor into 
+@@ -86,26 +110,26 @@ FILE *spawn_diff (char *prog, char *args
+ 
+       argc = 0;
+       count = BLOCKSIZE;
+-      argv = (char **) malloc (sizeof (char *) * BLOCKSIZE);
++      argv = (char **) xmalloc (sizeof (char *) * BLOCKSIZE);
+       argv[argc++] = prog;
+ 
+       for (ptr = strtok (args, " \t"); ptr; ptr = strtok (NULL, " \t")) {
+           if (argc >= count) {
+-              argv = (char **) realloc (argv, sizeof (char *) * BLOCKSIZE);
++              argv = (char **) xrealloc (argv, sizeof (char *) * BLOCKSIZE);
+               count += BLOCKSIZE;
+           }
+           argv[argc++] = strdup (ptr);
+       }
+ 
+       if ((argc + 3) >= count)
+-          argv = (char **) realloc (argv, sizeof (char *) * 3);
++          argv = (char **) xrealloc (argv, sizeof (char *) * 3);
+ 
+       argv[argc++] = path1;
+       argv[argc++] = path2;
+       argv[argc++] = NULL;
+ 
+       if (execvp (prog, argv) == -1) {
+-          (void) sprintf (buffer, "%s: %s: %s", progname, "exec", prog);
++          (void) snprintf (buffer, sizeof (buffer), "%s: %s: %s", progname, "exec", prog);
+           perror (buffer);
+           exit (2);
+       }
+@@ -131,4 +155,5 @@ FILE *spawn_diff (char *prog, char *args
+       break;
+     }
+     /* NOTREACHED */
++    return NULL;
+ }



Home | Main Index | Thread Index | Old Index