diff :  xv-3.10a-jumbo-enh-patch-20050501.txt

This is a unified diff.  It should be applied (using Larry Wall's "patch"
program) to the XV 3.10a sources AFTER the jumbo-fixes patch has already
been applied.

diffs below:
   Imakefile
   Makefile
   Makefile.std
   README.jumbo
   README.pcd
   bggen.c
   bits/br_bzip2
   bits/br_mag
   bits/br_maki
   bits/br_mgcsfx
   bits/br_pcd
   bits/br_pi
   bits/br_pic
   bits/br_pic2
   bits/br_png
   bits/br_zx
   config.h
   tiff/Makefile
   vdcomp.c
   xcmap.c
   xv.c
   xv.h
   xv_mgcsfx.sample
   xvbmp.c
   xvbrowse.c
   xvctrl.c
   xvdial.c
   xvdir.c
   xvevent.c
   xvfits.c
   xvgam.c
   xvgif.c
   xvgrab.c
   xvhips.c
   xvhips.h
   xvimage.c
   xvinfo.c
   xvjpeg.c
   xvmag.c
   xvmaki.c
   xvmgcsfx.c
   xvmisc.c
   xvml.c
   xvml.h
   xvpbm.c
   xvpcd.c
   xvpds.c
   xvpi.c
   xvpic.c
   xvpic2.c
   xvpng.c
   xvpopup.c
   xvps.c
   xvrle.c
   xvroot.c
   xvsmooth.c
   xvtext.c
   xvtiff.c
   xvtiffwr.c
   xvvd.c
   xvwbmp.c
   xvxpm.c
   xvzx.c


diff -ruN xv-3.10a-bugfixes/Imakefile xv-3.10a-enhancements/Imakefile
--- xv-3.10a-bugfixes/Imakefile	1995-01-13 12:24:01.000000000 -0800
+++ xv-3.10a-enhancements/Imakefile	2005-04-17 14:04:22.000000000 -0700
@@ -104,6 +104,11 @@
 SGI = -Dsgi
 #endif
 
+/* install directory of xv_mgcsfx.sample. */
+MGCSFXDIR = $(LIBDIR)
+/* Directory of default configuration file. */
+MGCSFX = -DMGCSFXDIR=\"$(MGCSFXDIR)\"
+
 
 
 
@@ -137,6 +142,8 @@
 #if defined(SCOArchitecture)
 SCO= -Dsco -DPOSIX -DNO_RANDOM 
 SYS_LIBRARIES=        -lm -lc -lx 
+#elif defined(HPArchitecture)
+SYS_LIBRARIES=        -lm -lV3
 #else
 SYS_LIBRARIES=        -lm
 #endif
@@ -147,7 +154,7 @@
 
 DEFINES= $(SCO) $(UNIX) $(NODIRENT) $(VPRINTF) $(TIMERS) \
 	$(HPUX7) $(JPEG) $(TIFF) $(PDS) $(DXWM) $(RAND) \
-	$(BACKING_STORE) $(BSDTYPES) $(SGI)
+	$(BACKING_STORE) $(BSDTYPES) $(SGI) $(MGCSFX)
 
 INCLUDES = $(JPEGINCLUDE) $(TIFFINCLUDE)
 
@@ -157,7 +164,9 @@
 	xvdial.c xvgraf.c xvsunras.c xvjpeg.c xvps.c xvpopup.c xvdflt.c \
 	xvtiff.c xvtiffwr.c xvpds.c xvrle.c xviris.c xvgrab.c vprintf.c \
 	xvbrowse.c xvtext.c xvpcx.c xviff.c xvtarga.c xvxpm.c xvcut.c \
-	xvxwd.c xvfits.c
+	xvxwd.c xvfits.c xvpng.c xvzx.c xvwbmp.c xvpcd.c \
+	xvmag.c xvpic.c xvmaki.c xvpi.c xvpic2.c xvvd.c xvmgcsfx.c \
+	xvml.c
 
 OBJS1 =	xv.o xvevent.o xvroot.o xvmisc.o xvimage.o xvcolor.o xvsmooth.o \
 	xv24to8.o xvgif.o xvpm.o xvinfo.o xvctrl.o xvscrl.o xvalg.o \
@@ -165,7 +174,9 @@
 	xvdial.o xvgraf.o xvsunras.o xvjpeg.o xvps.o xvpopup.o xvdflt.o \
 	xvtiff.o xvtiffwr.o xvpds.o xvrle.o xviris.o xvgrab.o vprintf.o \
 	xvbrowse.o xvtext.o xvpcx.o xviff.o xvtarga.o xvxpm.o xvcut.o \
-	xvxwd.o xvfits.o
+	xvxwd.o xvfits.o xvpng.o xvzx.o xvwbmp.o xvpcd.o \
+	xvmag.o xvpic.o xvmaki.o xvpi.o xvpic2.o xvvd.o xvmgcsfx.o \
+	xvml.o
 
 SRCS2=	bggen.c
 OBJS2=	bggen.o
@@ -266,6 +277,8 @@
 InstallManPageLong(docs/xvp2p,$(MANDIR),xvpictoppm)
 InstallManPageLong(docs/vdcomp,$(MANDIR),vdcomp)
 
+InstallNonExecFile(xv_mgcsfx.sample,$(MGCSFXDIR))
+
 tar:
 	tar cf xv.tar Makefile* Imakefile *.c *.h bits docs \
 		 docs unsupt vms $(JPEGDIR) $(TIFFDIR) $(MISC)
diff -ruN xv-3.10a-bugfixes/Makefile xv-3.10a-enhancements/Makefile
--- xv-3.10a-bugfixes/Makefile	2005-04-06 08:17:13.000000000 -0700
+++ xv-3.10a-enhancements/Makefile	2005-05-01 10:23:32.000000000 -0700
@@ -41,10 +41,14 @@
 
 
 ### Installation locations
-BINDIR = /usr/local/bin
-MANDIR = /usr/local/man/man1
+PREFIX = /usr/local
+BINDIR = $(PREFIX)/bin
+MANDIR = $(PREFIX)/man/man1
 MANSUF = 1
-LIBDIR = /usr/local/lib
+DOCDIR = $(PREFIX)/doc/xv-3.10a
+LIBDIR = $(PREFIX)/lib/xv
+SYSCONFDIR = $(PREFIX)/etc
+DESTDIR =
 
 
 buildit: all
@@ -59,13 +63,59 @@
 ### on your machine, *COMMENT OUT* the following lines
 ###
 JPEG    = -DDOJPEG
-JPEGDIR = jpeg
-JPEGINC = -I$(JPEGDIR)
-JPEGLIB = $(JPEGDIR)/libjpeg.a
-$(JPEGDIR)/jconfig.h:
-	cd $(JPEGDIR) ; ./configure CC='$(CC)'
-$(JPEGLIB):  $(JPEGDIR)/jconfig.h
-	cd $(JPEGDIR) ; make
+#JPEGDIR = jpeg
+JPEGDIR = /usr
+#JPEGDIR = /usr/local
+#JPEGDIR = ../../libjpeg
+###
+JPEGINC = -I$(JPEGDIR)/include
+#JPEGINC = -I$(JPEGDIR)
+###
+JPEGLIB = -L$(JPEGDIR)/lib -ljpeg
+#JPEGLIB = -L$(JPEGDIR) -ljpeg
+#JPEGLIB = $(JPEGDIR)/libjpeg.a
+###
+### this is intended to build the ancient version (5a) that's included in the
+### "jpeg" subdir of XV, not an arbitrary copy of libjpeg:
+###
+#$(JPEGDIR)/jconfig.h:
+#	cd $(JPEGDIR) ; ./configure CC='$(CC)'
+#$(JPEGLIB):  $(JPEGDIR)/jconfig.h
+#	cd $(JPEGDIR) ; make
+
+
+###
+### if, for whatever reason, you're unable to get the PNG library to compile
+### on your machine, *COMMENT OUT* the following lines
+###
+PNG    = -DDOPNG
+PNGDIR = /usr
+#PNGDIR = /usr/local
+#PNGDIR = ../../libpng
+###
+PNGINC = -I$(PNGDIR)/include
+#PNGINC = -I$(PNGDIR)
+###
+PNGLIB = -L$(PNGDIR)/lib -lpng
+#PNGLIB = -L$(PNGDIR) -lpng
+#PNGLIB = $(PNGDIR)/libpng.a
+
+
+###
+### if, for whatever reason, you're unable to get both the PNG library and
+### (newer versions of) the TIFF library to compile on your machine, *COMMENT
+### OUT* the following lines
+###
+ZLIBDIR = /usr
+#ZLIBDIR = /usr/local
+#ZLIBDIR = ../../zlib
+###
+ZLIBINC = -I$(ZLIBDIR)/include
+#ZLIBINC = -I$(ZLIBDIR)
+###
+ZLIBLIB = -L$(ZLIBDIR)/lib -lz
+#ZLIBLIB = -L$(ZLIBDIR) -lz
+#ZLIBLIB = $(ZLIBDIR)/libz.a
 
 
 ###
@@ -80,17 +130,32 @@
 ###
 #TIFF    = -DDOTIFF
 TIFF    = -DDOTIFF -DUSE_TILED_TIFF_BOTLEFT_FIX
-TIFFDIR = tiff
-TIFFINC = -I$(TIFFDIR)
-TIFFLIB = $(TIFFDIR)/libtiff.a
-$(TIFFLIB):
-	( cd $(TIFFDIR) ; make CC='$(CC)' COPTS='$(CCOPTS) $(MCHN)' )
+#TIFFDIR = tiff
+TIFFDIR = /usr
+#TIFFDIR = /usr/local
+#TIFFDIR = ../../libtiff
+###
+TIFFINC = -I$(TIFFDIR)/include
+#TIFFINC = -I$(TIFFDIR)
+###
+### libtiff 3.5 and up may be compiled with zlib and libjpeg, but dependency
+### is properly handled in LIBS line ~143 lines below
+###
+TIFFLIB = -L$(TIFFDIR)/lib -ltiff
+#TIFFLIB = -L$(TIFFDIR) -ltiff
+#TIFFLIB = $(TIFFDIR)/libtiff.a
+###
+### this is intended to build the ancient version (3.3.016 beta) that's included
+### in the "tiff" subdir of XV, not an arbitrary copy of libtiff:
+###
+#$(TIFFLIB):
+#	( cd $(TIFFDIR) ; make CC='$(CC)' COPTS='$(CCOPTS) $(MCHN)' )
 
 
 ###
 ### if, for whatever reason, you're unable to get the PDS/VICAR support
 ### to compile (xvpds.c, and vdcomp.c), *COMMENT OUT* the following line,
-### and also remove 'vdcomp' from the 'all:' dependancy
+### and also remove 'vdcomp' from the 'all:' dependency
 ###
 PDS = -DDOPDS
 
@@ -98,8 +163,10 @@
 #----------System V----------
 
 # if you are running on a SysV-based machine, such as HP, Silicon Graphics,
-# Solaris, etc., uncomment the following line to get mostly there.
-#UNIX = -DSVR4
+# Solaris, etc.; uncomment one of the following lines to get you *most* of
+# the way there.  SYSV means System V R3.
+# UNIX = -DSVR4
+# UNIX = -DSYSV
 
 
 #----------Machine-Specific Configurations----------
@@ -121,12 +188,15 @@
 # To use old HP compilers (HPUX 7.0 or so), you may need
 #MCHN= -Dhpux -D_HPUX_SOURCE +Ns4000
 #
-# also, if you're using HP's compiler, add '-Aa' to whichever of those
+# Also, if you're using HP's compiler, add '-Aa' to whichever of those
 # two lines you're using, to turn on ANSI C mode.  Or so I'm told.
 #
-# note:  You may need to add '-I/usr/include/X11R5' (or R6, or whatever)
+# Note:  You may need to add '-I/usr/include/X11R5' (or R6, or whatever)
 # to whichever of those lines you used, as HP tends to store their X11
 # include files in a non-standard place...
+#
+# And you probably have to add '-lV3' to the end of the LIBS def when
+# using XV's AUTO_EXPAND option.
 
 
 ### for LINUX, uncomment the following line
@@ -205,6 +275,16 @@
 #VPRINTF = -DNEED_VPRINTF -DLONGINT -DNOSTDHDRS
 
 
+# if your X Window System compiled with -DX_LOCALE, 
+# uncomment the following line:
+# TVL10N = -DX_LOCALE
+
+# Install directory of xv_mgcsfx.sample.
+MGCSFXDIR = $(LIBDIR)
+# Directory of default configuration file.
+MGCSFX = -DMGCSFXDIR=\"$(MGCSFXDIR)\"
+
+
 
 
 ################ END OF CONFIGURATION OPTIONS #################
@@ -212,13 +292,14 @@
 
 
 
-CFLAGS = $(CCOPTS) $(JPEG) $(JPEGINC) $(TIFF) $(TIFFINC) $(PDS) \
-	$(NODIRENT) $(VPRINTF) $(TIMERS) $(UNIX) $(BSDTYPES) $(RAND) \
-	$(DXWM) $(MCHN)
+CFLAGS = $(CCOPTS) $(PNG) $(PNGINC) $(ZLIBINC) $(JPEG) $(JPEGINC) \
+	$(TIFF) $(TIFFINC) $(PDS) $(NODIRENT) $(VPRINTF) $(TIMERS) \
+	$(UNIX) $(BSDTYPES) $(RAND) $(DXWM) $(MCHN) $(TVL10N) $(MGCSFX) \
+	-DSYSCONFDIR=\"$(SYSCONFDIR)\" -DXVEXECPATH=\"$(LIBDIR)\"
 
 ### remove -lm for BeOS:
-LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) -lm
-#LIBS = -lX11 $(JPEGLIB) $(TIFFLIB)
+LIBS = $(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIBLIB) -L/usr/X11R6/lib -lX11 -lm
+#LIBS = $(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIBLIB) -lX11
 
 OBJS = 	xv.o xvevent.o xvroot.o xvmisc.o xvimage.o xvcolor.o xvsmooth.o \
 	xv24to8.o xvgif.o xvpm.o xvinfo.o xvctrl.o xvscrl.o xvalg.o \
@@ -226,7 +307,9 @@
 	xvdial.o xvgraf.o xvsunras.o xvjpeg.o xvps.o xvpopup.o xvdflt.o \
 	xvtiff.o xvtiffwr.o xvpds.o xvrle.o xviris.o xvgrab.o vprintf.o \
 	xvbrowse.o xvtext.o xvpcx.o xviff.o xvtarga.o xvxpm.o xvcut.o \
-	xvxwd.o xvfits.o
+	xvxwd.o xvfits.o xvpng.o xvzx.o xvwbmp.o xvpcd.o xvhips.o \
+	xvmag.o xvpic.o xvmaki.o xvpi.o xvpic2.o xvvd.o xvmgcsfx.o \
+	xvml.o
 
 MISC = README INSTALL CHANGELOG IDEAS
 
@@ -236,10 +319,12 @@
 
 
 
-all: $(JPEGLIB) $(TIFFLIB) xv bggen vdcomp xcmap xvpictoppm
+#all: $(JPEGLIB) $(TIFFLIB) xv bggen vdcomp xcmap xvpictoppm
+all: xv bggen vdcomp xcmap xvpictoppm
 
 
-xv: $(OBJS) $(JPEGLIB) $(TIFFLIB)
+#xv: $(OBJS) $(JPEGLIB) $(TIFFLIB)
+xv: $(OBJS)
 	$(CC) -o xv $(CFLAGS) $(OBJS) $(LIBS)
 
 bggen: bggen.c
@@ -268,13 +353,14 @@
 
 
 install: all
-	cp xv bggen vdcomp xcmap xvpictoppm $(BINDIR)
-	cp docs/xv.man     $(MANDIR)/xv.$(MANSUF)
-	cp docs/bggen.man  $(MANDIR)/bggen.$(MANSUF)
-	cp docs/xcmap.man  $(MANDIR)/xcmap.$(MANSUF)
-	cp docs/xvp2p.man  $(MANDIR)/xvpictoppm.$(MANSUF)
-	cp docs/vdcomp.man $(MANDIR)/vdcomp.$(MANSUF)
-	cp docs/xvdocs.ps* $(LIBDIR)
+	cp xv bggen vdcomp xcmap xvpictoppm $(DESTDIR)$(BINDIR)
+	cp docs/xv.man     $(DESTDIR)$(MANDIR)/xv.$(MANSUF)
+	cp docs/bggen.man  $(DESTDIR)$(MANDIR)/bggen.$(MANSUF)
+	cp docs/xcmap.man  $(DESTDIR)$(MANDIR)/xcmap.$(MANSUF)
+	cp docs/xvp2p.man  $(DESTDIR)$(MANDIR)/xvpictoppm.$(MANSUF)
+	cp docs/vdcomp.man $(DESTDIR)$(MANDIR)/vdcomp.$(MANSUF)
+	cp docs/xvdocs.ps* $(DESTDIR)$(LIBDIR) # or $(DESTDIR)$(DOCDIR)
+	#cp xv_mgcsfx.sample $(DESTDIR)$(SYSCONFDIR)/xv_mgcsfx
 
 tar:
 #	tar only local jpeg and tiff dirs, not user's or system's copies:
@@ -299,7 +385,7 @@
 xvbrowse.o:	bits/br_pcx bits/br_jfif bits/br_tiff bits/br_pds
 xvbrowse.o:	bits/br_ps bits/br_iff bits/br_targa bits/br_xpm
 xvbrowse.o:	bits/br_trash bits/fcurs bits/fccurs bits/fdcurs bits/fcursm
-xvbrowse.o:	bits/br_xwd
+xvbrowse.o:	bits/br_xwd bits/br_png bits/br_zx bits/br_pcd bits/br_bzip2
 
 xvbutt.o:	bits/cboard50 bits/rb_frame bits/rb_frame1 bits/rb_top
 xvbutt.o:	bits/rb_bot bits/rb_dtop bits/rb_dbot bits/rb_body
diff -ruN xv-3.10a-bugfixes/Makefile.std xv-3.10a-enhancements/Makefile.std
--- xv-3.10a-bugfixes/Makefile.std	2005-04-06 08:17:13.000000000 -0700
+++ xv-3.10a-enhancements/Makefile.std	2005-05-01 10:23:32.000000000 -0700
@@ -41,10 +41,14 @@
 
 
 ### Installation locations
-BINDIR = /usr/local/bin
-MANDIR = /usr/local/man/man1
+PREFIX = /usr/local
+BINDIR = $(PREFIX)/bin
+MANDIR = $(PREFIX)/man/man1
 MANSUF = 1
-LIBDIR = /usr/local/lib
+DOCDIR = $(PREFIX)/doc/xv-3.10a
+LIBDIR = $(PREFIX)/lib/xv
+SYSCONFDIR = $(PREFIX)/etc
+DESTDIR =
 
 
 buildit: all
@@ -59,13 +63,59 @@
 ### on your machine, *COMMENT OUT* the following lines
 ###
 JPEG    = -DDOJPEG
-JPEGDIR = jpeg
-JPEGINC = -I$(JPEGDIR)
-JPEGLIB = $(JPEGDIR)/libjpeg.a
-$(JPEGDIR)/jconfig.h:
-	cd $(JPEGDIR) ; ./configure CC='$(CC)'
-$(JPEGLIB):  $(JPEGDIR)/jconfig.h
-	cd $(JPEGDIR) ; make
+#JPEGDIR = jpeg
+JPEGDIR = /usr
+#JPEGDIR = /usr/local
+#JPEGDIR = ../../libjpeg
+###
+JPEGINC = -I$(JPEGDIR)/include
+#JPEGINC = -I$(JPEGDIR)
+###
+JPEGLIB = -L$(JPEGDIR)/lib -ljpeg
+#JPEGLIB = -L$(JPEGDIR) -ljpeg
+#JPEGLIB = $(JPEGDIR)/libjpeg.a
+###
+### this is intended to build the ancient version (5a) that's included in the
+### "jpeg" subdir of XV, not an arbitrary copy of libjpeg:
+###
+#$(JPEGDIR)/jconfig.h:
+#	cd $(JPEGDIR) ; ./configure CC='$(CC)'
+#$(JPEGLIB):  $(JPEGDIR)/jconfig.h
+#	cd $(JPEGDIR) ; make
+
+
+###
+### if, for whatever reason, you're unable to get the PNG library to compile
+### on your machine, *COMMENT OUT* the following lines
+###
+PNG    = -DDOPNG
+PNGDIR = /usr
+#PNGDIR = /usr/local
+#PNGDIR = ../../libpng
+###
+PNGINC = -I$(PNGDIR)/include
+#PNGINC = -I$(PNGDIR)
+###
+PNGLIB = -L$(PNGDIR)/lib -lpng
+#PNGLIB = -L$(PNGDIR) -lpng
+#PNGLIB = $(PNGDIR)/libpng.a
+
+
+###
+### if, for whatever reason, you're unable to get both the PNG library and
+### (newer versions of) the TIFF library to compile on your machine, *COMMENT
+### OUT* the following lines
+###
+ZLIBDIR = /usr
+#ZLIBDIR = /usr/local
+#ZLIBDIR = ../../zlib
+###
+ZLIBINC = -I$(ZLIBDIR)/include
+#ZLIBINC = -I$(ZLIBDIR)
+###
+ZLIBLIB = -L$(ZLIBDIR)/lib -lz
+#ZLIBLIB = -L$(ZLIBDIR) -lz
+#ZLIBLIB = $(ZLIBDIR)/libz.a
 
 
 ###
@@ -80,17 +130,32 @@
 ###
 #TIFF    = -DDOTIFF
 TIFF    = -DDOTIFF -DUSE_TILED_TIFF_BOTLEFT_FIX
-TIFFDIR = tiff
-TIFFINC = -I$(TIFFDIR)
-TIFFLIB = $(TIFFDIR)/libtiff.a
-$(TIFFLIB):
-	( cd $(TIFFDIR) ; make CC='$(CC)' COPTS='$(CCOPTS) $(MCHN)' )
+#TIFFDIR = tiff
+TIFFDIR = /usr
+#TIFFDIR = /usr/local
+#TIFFDIR = ../../libtiff
+###
+TIFFINC = -I$(TIFFDIR)/include
+#TIFFINC = -I$(TIFFDIR)
+###
+### libtiff 3.5 and up may be compiled with zlib and libjpeg, but dependency
+### is properly handled in LIBS line ~143 lines below
+###
+TIFFLIB = -L$(TIFFDIR)/lib -ltiff
+#TIFFLIB = -L$(TIFFDIR) -ltiff
+#TIFFLIB = $(TIFFDIR)/libtiff.a
+###
+### this is intended to build the ancient version (3.3.016 beta) that's included
+### in the "tiff" subdir of XV, not an arbitrary copy of libtiff:
+###
+#$(TIFFLIB):
+#	( cd $(TIFFDIR) ; make CC='$(CC)' COPTS='$(CCOPTS) $(MCHN)' )
 
 
 ###
 ### if, for whatever reason, you're unable to get the PDS/VICAR support
 ### to compile (xvpds.c, and vdcomp.c), *COMMENT OUT* the following line,
-### and also remove 'vdcomp' from the 'all:' dependancy
+### and also remove 'vdcomp' from the 'all:' dependency
 ###
 PDS = -DDOPDS
 
@@ -98,8 +163,10 @@
 #----------System V----------
 
 # if you are running on a SysV-based machine, such as HP, Silicon Graphics,
-# Solaris, etc., uncomment the following line to get mostly there.
-#UNIX = -DSVR4
+# Solaris, etc.; uncomment one of the following lines to get you *most* of
+# the way there.  SYSV means System V R3.
+# UNIX = -DSVR4
+# UNIX = -DSYSV
 
 
 #----------Machine-Specific Configurations----------
@@ -121,12 +188,15 @@
 # To use old HP compilers (HPUX 7.0 or so), you may need
 #MCHN= -Dhpux -D_HPUX_SOURCE +Ns4000
 #
-# also, if you're using HP's compiler, add '-Aa' to whichever of those
+# Also, if you're using HP's compiler, add '-Aa' to whichever of those
 # two lines you're using, to turn on ANSI C mode.  Or so I'm told.
 #
-# note:  You may need to add '-I/usr/include/X11R5' (or R6, or whatever)
+# Note:  You may need to add '-I/usr/include/X11R5' (or R6, or whatever)
 # to whichever of those lines you used, as HP tends to store their X11
 # include files in a non-standard place...
+#
+# And you probably have to add '-lV3' to the end of the LIBS def when
+# using XV's AUTO_EXPAND option.
 
 
 ### for LINUX, uncomment the following line
@@ -205,6 +275,16 @@
 #VPRINTF = -DNEED_VPRINTF -DLONGINT -DNOSTDHDRS
 
 
+# if your X Window System compiled with -DX_LOCALE, 
+# uncomment the following line:
+# TVL10N = -DX_LOCALE
+
+# Install directory of xv_mgcsfx.sample.
+MGCSFXDIR = $(LIBDIR)
+# Directory of default configuration file.
+MGCSFX = -DMGCSFXDIR=\"$(MGCSFXDIR)\"
+
+
 
 
 ################ END OF CONFIGURATION OPTIONS #################
@@ -212,13 +292,14 @@
 
 
 
-CFLAGS = $(CCOPTS) $(JPEG) $(JPEGINC) $(TIFF) $(TIFFINC) $(PDS) \
-	$(NODIRENT) $(VPRINTF) $(TIMERS) $(UNIX) $(BSDTYPES) $(RAND) \
-	$(DXWM) $(MCHN)
+CFLAGS = $(CCOPTS) $(PNG) $(PNGINC) $(ZLIBINC) $(JPEG) $(JPEGINC) \
+	$(TIFF) $(TIFFINC) $(PDS) $(NODIRENT) $(VPRINTF) $(TIMERS) \
+	$(UNIX) $(BSDTYPES) $(RAND) $(DXWM) $(MCHN) $(TVL10N) $(MGCSFX) \
+	-DSYSCONFDIR=\"$(SYSCONFDIR)\" -DXVEXECPATH=\"$(LIBDIR)\"
 
 ### remove -lm for BeOS:
-LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) -lm
-#LIBS = -lX11 $(JPEGLIB) $(TIFFLIB)
+LIBS = $(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIBLIB) -L/usr/X11R6/lib -lX11 -lm
+#LIBS = $(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIBLIB) -lX11
 
 OBJS = 	xv.o xvevent.o xvroot.o xvmisc.o xvimage.o xvcolor.o xvsmooth.o \
 	xv24to8.o xvgif.o xvpm.o xvinfo.o xvctrl.o xvscrl.o xvalg.o \
@@ -226,7 +307,9 @@
 	xvdial.o xvgraf.o xvsunras.o xvjpeg.o xvps.o xvpopup.o xvdflt.o \
 	xvtiff.o xvtiffwr.o xvpds.o xvrle.o xviris.o xvgrab.o vprintf.o \
 	xvbrowse.o xvtext.o xvpcx.o xviff.o xvtarga.o xvxpm.o xvcut.o \
-	xvxwd.o xvfits.o
+	xvxwd.o xvfits.o xvpng.o xvzx.o xvwbmp.o xvpcd.o xvhips.o \
+	xvmag.o xvpic.o xvmaki.o xvpi.o xvpic2.o xvvd.o xvmgcsfx.o \
+	xvml.o
 
 MISC = README INSTALL CHANGELOG IDEAS
 
@@ -236,10 +319,12 @@
 
 
 
-all: $(JPEGLIB) $(TIFFLIB) xv bggen vdcomp xcmap xvpictoppm
+#all: $(JPEGLIB) $(TIFFLIB) xv bggen vdcomp xcmap xvpictoppm
+all: xv bggen vdcomp xcmap xvpictoppm
 
 
-xv: $(OBJS) $(JPEGLIB) $(TIFFLIB)
+#xv: $(OBJS) $(JPEGLIB) $(TIFFLIB)
+xv: $(OBJS)
 	$(CC) -o xv $(CFLAGS) $(OBJS) $(LIBS)
 
 bggen: bggen.c
@@ -268,13 +353,14 @@
 
 
 install: all
-	cp xv bggen vdcomp xcmap xvpictoppm $(BINDIR)
-	cp docs/xv.man     $(MANDIR)/xv.$(MANSUF)
-	cp docs/bggen.man  $(MANDIR)/bggen.$(MANSUF)
-	cp docs/xcmap.man  $(MANDIR)/xcmap.$(MANSUF)
-	cp docs/xvp2p.man  $(MANDIR)/xvpictoppm.$(MANSUF)
-	cp docs/vdcomp.man $(MANDIR)/vdcomp.$(MANSUF)
-	cp docs/xvdocs.ps* $(LIBDIR)
+	cp xv bggen vdcomp xcmap xvpictoppm $(DESTDIR)$(BINDIR)
+	cp docs/xv.man     $(DESTDIR)$(MANDIR)/xv.$(MANSUF)
+	cp docs/bggen.man  $(DESTDIR)$(MANDIR)/bggen.$(MANSUF)
+	cp docs/xcmap.man  $(DESTDIR)$(MANDIR)/xcmap.$(MANSUF)
+	cp docs/xvp2p.man  $(DESTDIR)$(MANDIR)/xvpictoppm.$(MANSUF)
+	cp docs/vdcomp.man $(DESTDIR)$(MANDIR)/vdcomp.$(MANSUF)
+	cp docs/xvdocs.ps* $(DESTDIR)$(LIBDIR) # or $(DESTDIR)$(DOCDIR)
+	#cp xv_mgcsfx.sample $(DESTDIR)$(SYSCONFDIR)/xv_mgcsfx
 
 tar:
 #	tar only local jpeg and tiff dirs, not user's or system's copies:
@@ -299,7 +385,7 @@
 xvbrowse.o:	bits/br_pcx bits/br_jfif bits/br_tiff bits/br_pds
 xvbrowse.o:	bits/br_ps bits/br_iff bits/br_targa bits/br_xpm
 xvbrowse.o:	bits/br_trash bits/fcurs bits/fccurs bits/fdcurs bits/fcursm
-xvbrowse.o:	bits/br_xwd
+xvbrowse.o:	bits/br_xwd bits/br_png bits/br_zx bits/br_pcd bits/br_bzip2
 
 xvbutt.o:	bits/cboard50 bits/rb_frame bits/rb_frame1 bits/rb_top
 xvbutt.o:	bits/rb_bot bits/rb_dtop bits/rb_dbot bits/rb_body
diff -ruN xv-3.10a-bugfixes/README.jumbo xv-3.10a-enhancements/README.jumbo
--- xv-3.10a-bugfixes/README.jumbo	2005-04-10 19:55:23.000000000 -0700
+++ xv-3.10a-enhancements/README.jumbo	2005-05-01 13:45:58.000000000 -0700
@@ -14,10 +14,10 @@
 available from John's XV site (http://www.trilon.com/xv/downloads.html
 and ftp://ftp.trilon.com/pub/xv/patches/), plus a number of my own fixes
 and additions, plus quite a few from other people--though not all of the
-ones I'd intended to (sorry, SJT, AT, and JPD!) due to lack of time after
-dealing with the latest security issue (which I discovered, sigh).  They're
-still not fully complete, and it's possible they never will be, but I do
-plan to continue working on them whenever the mood strikes--and I may even
+ones I'd intended to, due to lack of time after dealing with the latest
+set of security issues (one of which I discovered, sigh).  They're still
+not fully complete, and it's possible they never will be, but I do plan
+to continue tinkering with them whenever the mood strikes--and I may even
 release them publicly on rare occasions.  (At the current rate, it looks
 like once a year may be the best we can hope for...we'll see.)
 
@@ -26,91 +26,86 @@
 
  - Landon Curt "chongo" Noll (http://www.isthe.com/chongo/)
    http://www.isthe.com/chongo/src/xv-patch/
- - Mark Ashley <mark@ibiblio.org>
+ - Mark Ashley <mark ibiblio.org>
    http://www.ibiblio.org/pub/packages/solaris/sparc/html/xv.3.10a.p19.html
- - Peter Jordan <pete@dc.seflin.org>
+ - Peter Jordan <pete dc.seflin.org>
    http://www.ibiblio.org/pub/Linux/apps/graphics/viewers/X/xv-3.10a.patch.*
  - Uwe F. Mayer (http://www.tux.org/~mayer/)
    http://www.tux.org/~mayer/linux/book/node311.html
- - Kurt Wall <kwall@kurtwerks.com>
+ - Kurt Wall <kwall kurtwerks.com>
    http://www.kurtwerks.com/software/xv.html
  - Chisato Yamauchi (http://phe.phyas.aichi-edu.ac.jp/~cyamauch/index_en.html)
    http://phe.phyas.aichi-edu.ac.jp/~cyamauch/xv.html
- - Daisuke Yabuki <dxy@optix.org>
+ - Daisuke Yabuki <dxy optix.org>
    http://www.optix.org/~dxy/solaris/xv/
  - Pekoe (http://pekoe.lair.net/)
    http://pekoe.lair.net/diary/xv.html
  - FreeBSD FreshPorts
    http://www.freshports.org/graphics/xv/
- - <sudakyo@fat.coara.or.jp>
+ - Kyoichiro Suda <sudakyo fat.coara.or.jp>
    http://www.coara.or.jp/~sudakyo/XV_jp.html
 
-I very much doubt that this is an exhaustive list.  So far, most of the other
-patch-sets appear not to be quite as extensive or as up-to-date as my own,
-although the last three or four do include the [large] Japanese extension
-patches that I omitted--not because they're unworthy, but simply because I
-didn't find them until collisions between the two sets of patches had become
-a large problem.  (Maybe for the next release...  I'd intended to try for
-this release, but the security issues ended up taking almost all of my
-available time.  And, to be honest, from my perspective, inclusion of the
-jp-extension patches is more for completeness' sake than personal interest,
-so their priority is fairly low.)
+I very much doubt that this is an exhaustive list.  So far, most of the
+other patch-sets appear not to be as extensive or as up-to-date as my own,
+particularly now that the (very large) "Japanese extension" patches are
+incorporated--big thanks to Werner Fink of SuSE for that!
 
 Below I summarize the component patches that are encompassed by my jumbo
 bugfixes and jumbo enhancements patches.  Unfortunately, some of my own
 additions never saw the light of day as standalone patches, but considering
 the number of overlaps (collisions) already implicit in this list, it would
-have been difficult to accomplish even if I'd had the time.  In any case,
-they're present in these jumbo patches but not chongo's, so those who _really_
-care can "subtract" the two sets of patches to see what I did.
+have been difficult to accomplish even if I'd had the time.
 
 Here's a quick guide to the "third-party" credits in the lists below:
 
   AAC = Andrey A. Chernov [ache]
         (http://cvsweb.freebsd.org/ports/graphics/xv/files/patch-ab)
-  AD  = Andreas Dilger (adilger@clusterfs.com)
-  AL  = Alexander Lehmann (lehmann@usa.net)
+  AD  = Andreas Dilger (adilger clusterfs.com)
+  AL  = Alexander Lehmann (lehmann usa.net)
   AT  = Anthony Thyssen (http://www.cit.gu.edu.au/~anthony/)
   DAC = David A. Clunie (http://www.dclunie.com/xv-pcd.html)
-  EK  = Egmont Koblinger (egmont@users.sourceforge.net)
+  EK  = Egmont Koblinger (egmont users.sourceforge.net)
   GRR = Greg Roelofs (http://pobox.com/~newt/)
   GV  = Guido Vollbeding (http://sylvana.net/guido/)
+  IM  = IKEMOTO Masahiro (ikeyan airlab.cs.ritsumei.ac.jp)
   JCE = John C. Elliott (http://www.seasip.demon.co.uk/ZX/zxdload.html)
   JHB = John H. Bradley, of course (http://www.trilon.com/xv/)
   JPD = Jean-Pierre Demailly (http://www-fourier.ujf-grenoble.fr/~demailly/)
   JR  = John Rochester (http://www.freebsd.org/cgi/query-pr.cgi?pr=2920)
         (also http://cvsweb.freebsd.org/ports/graphics/xv/files/patch-af, -ag)
   JZ  = Joe Zbiciak (http://spatula-city.org/~im14u2c/)
+  KS  = Kyoichiro Suda (http://www.coara.or.jp/~sudakyo/XV_jp.html)
   LCN = Landon Curt "chongo" Noll (http://www.isthe.com/chongo/)
+  LJ  = Larry Jones (lawrence.jones ugs.com)
   PBJ = Peter Jordan (http://www.ibiblio.org/pub/Linux/apps/graphics/viewers/X/)
   PSV = Pawel S. Veselov (http://manticore.2y.net/wbmp.html)
   SB  = Sean Borman (http://www.nd.edu/~sborman/software/xvwheelmouse.html)
-  SJT = TenThumbs (tenthumbs@cybernex.net)
+  SJT = TenThumbs (tenthumbs cybernex.net)
   TA  = Tim Adye (http://hepwww.rl.ac.uk/Adye/xv-psnewstyle.html)
+  TI  = Tetsuya INOUE (tin329 chino.it.okayama-u.ac.jp)
+  TO  = Tavis Ormandy (taviso gentoo.org)
+  WF  = Werner Fink (http://www.suse.de/~werner/)
 
 Other credits are as listed on the XV Downloads page or in the respective
 patches (e.g., the jp-extension patches or within the PNG patch).
 
 Finally, please note that these patches have not been blessed by John Bradley
-in any way (although I copied him on the May 2004 announcement--no response).
-Nor have I personally tested every change and feature!  (See the BIG SCARY
-WARNING below for further caveats.)  In other words, they're both completely
-unofficial and completely unguaranteed.  But they seem to work for me.  (And
-when they don't, I fix 'em.  Eventually, anyway... ;-) )
-
-One further "final" note:  this may well be the last release to include
-separate fix- and enhancements-patches.  It is too much of a timesink to
-maintain parallel trees--not to mention parallel makefiles (generic/public
-vs. local/personal, old vs. new libjpeg/libtiff) and xv.h (unregistered/
-public vs. registered/personal), particularly when some fixes come about
-while working on an enhancement.  Henceforth--assuming, of course, that
-there _is_ a "henceforth"--I expect to merge the patches into a single
-jumbo patch.  (Alternatively, I may simply freeze the current fix-patch
-and continue to evolve only the enhancements patch; in particular, new
-fixes would appear only in it.  Either approach would be simple enough;
-feedback as to which would be preferable is welcomed.)
+in any way (although I copied him on the May 2004 announcement--no response
+at that time).  Nor have I personally tested every change and feature!  (See
+the BIG SCARY WARNING below for further caveats.)  In other words, they're
+both completely unofficial and completely unguaranteed.  But they seem to
+work for me.  (And when they don't, I fix 'em.  Eventually, anyway... ;-) )
+
+One further "final" note:  as of this release, I am no longer updating the
+fixes patch; new stuff (including fixes) now appears only in the enhancements
+one.  It simply became too much of a timesink to maintain parallel trees--not
+to mention parallel makefiles (generic/public vs. local/personal, old vs.
+new libjpeg/libtiff) and xv.h (unregistered/public vs. registered/personal),
+particularly when some fixes came about while working on an enhancement and
+others were provided by third parties relative to the previous fix+enh state.
+Hence the mismatched "20050410" date on the fixes patch.
 
-GRR 20050410
+GRR 20050501
 
 
 How to build
@@ -158,8 +153,8 @@
 Assuming you have the prerequisites out of the way and aren't scared
 off by the Big Scary Warning, here's the build procedure:
 
-      bzip2 -dc xv-3.10a-jumbo-patches-20050410.tar.bz2 | tar xvf -
-      (or tar xvzf xv-3.10a-jumbo-patches-20050410.tar.gz) 
+      bzip2 -dc xv-3.10a-jumbo-patches-20050501.tar.bz2 | tar xvf -
+      (or tar xvzf xv-3.10a-jumbo-patches-20050501.tar.gz) 
 
       tar xvzf xv-3.10a.tar.gz 
 
@@ -167,7 +162,7 @@
 
       patch -p1 < ../xv-3.10a-jumbo-fix-patch-20050410.txt 
 
-      [optional] patch -p1 < ../xv-3.10a-jumbo-enh-patch-20050410.txt 
+      [optional] patch -p1 < ../xv-3.10a-jumbo-enh-patch-20050501.txt 
 
       edit Makefile and config.h as directed in INSTALL file (in particular,
       ensure paths to external libraries and header files are correct)
@@ -221,6 +216,8 @@
  - freebsd-vdcomp-newline.patch (AAC)
  - xv-3.10a.patch.linux (PBJ)	[/bin/sh versions of cleandir, RANLIB.sh only]
  - removed trailing white space (GRR)  [purely cosmetic]
+20040523:
+ - fixed compilation error in registered versions (GRR)
 20050410:
  - fix for YCbCr oversaturated-green bug(s) in TIFF decoder (GRR)
  - provisional fix for contiguous tiled TIFFs with bottom-* orientation (GRR)
@@ -265,12 +262,50 @@
  - boosted maximum number of files from 4096 to 32768 (GRR)
    (note that OS kernel limits may also apply; for example, in Linux see
    MAX_ARG_PAGES in linux-<version>/include/linux/binfmts.h)
- - xv-3.10a-bmp16.patch
-   (from http://www.coara.or.jp/~sudakyo/XV_jp.html)
+ - xv-3.10a-bmp16.patch (KS)
  - final-image delay (e.g., "-wait 0.2,3" : pause 3 secs on final image) (GRR)
  - xv-numpad.patch (EK)
  - xv-delete-is-not-backspace.patch (EK)
  - made browser window (schnauzer) and icons configurable (AT, GRR)
+20050501:
+ - xv-3.10a-bmpfix.patch (WF)		[*SECURITY*]
+ - xv310a-jp-extension-rev5.3.3.tar.gz (TI, IM, ..., WF)
+   (adds support for MAG, MAKI, Pi, PIC, and PIC2 formats[*]; "magic suffix"
+   detection/conversion; MacBinary prefixes; archives as virtual filesystems;
+   multilingual text viewer [though not Unicode]; etc.)
+ - xv-3.10a-yaos.dif (WF, TO)		[*SECURITY*]
+   (fixes a number of format-string issues and system() calls)
+ - xv-3.10a.dif (WF)			[*SECURITY*]
+   (fixes more format-string issues, mktemp() and open() calls, and compilation
+   warnings [mostly from jp-extension patch])
+ - xv-3.10a-jumbo-jpd_startgrab-patch-20050420.txt (JPD)
+ - PATCH.alwaysnever (LJ)
+ - PATCH.bsd (LJ)
+ - PATCH.linedraw (LJ)
+ - PATCH.multipage (LJ)
+ - PATCH.multipageGIF (LJ)
+ - PATCH.random (LJ)
+ - PATCH.stat (LJ)
+ - PATCH.thumbs (LJ)
+ - xv-startgrab-imake-hips.patch (JPD)
+   ("hips" portion only; adds support for HIPS image format[*])
+ - xv-3.10a-formatstr.patch (KS)
+ - xv-3.10a-shortsleep.patch (KS)
+ - xv-3.10a-locale-linux.patch (KS)
+ - xv-3.10a-printkey.patch (KS)
+ - xv-3.10a-sysconfdir.patch (KS)
+ - added PREFIX and DESTDIR support to Makefile (KS, GRR)
+ - xv-3.10a-xvexecpath.patch (but disabled pending fixes) (KS)
+ - xv-3.10a-zeroquit.patch (KS, GRR)
+
+
+[*] Note that all six of these formats may still suffer from exploitable heap
+    overflows [*SECURITY*] when decoding images with large (possibly invalid)
+    dimensions; as a result, they are DISABLED by default.  (Search for "GRR
+    POSSIBLE OVERFLOW / FIXME" comments in xvmag.c, xvmaki.c, xvpi.c, xvpic.c,
+    xvpic2.c, and xvhips.c, but keep in mind that these may not be exhaustive.)
+    Users who choose to overlook these security issues can enable any or all
+    of them by editing config.h.
 
 
 not (yet?) included:
@@ -284,31 +319,21 @@
 	-rw-r--r--     42397 Mar 11  2004 xv-3.10a-download-test2.patch
 	-rw-r--r--     47679 Mar 11  2004 xv-3.10a-download-test3.patch
 	-rw-r--r--     52745 Mar 11  2004 xv-3.10a-download-test4.patch
-	-rw-r--r--       415 Mar 11  2004 xv-3.10a-formatstr.patch
 	-rw-r--r--      3423 Apr 24  2004 xv-3.10a-keyzoom.patch
-	-rw-r--r--      1461 Mar 11  2004 xv-3.10a-locale-linux.patch
 	-rw-r--r--     12387 Mar 15  2004 xv-3.10a-menubutton.patch
 	-rw-r--r--      1178 Apr 24  2004 xv-3.10a-noblink.patch
-	-rw-r--r--       484 Mar 11  2004 xv-3.10a-printkey.patch
 	-rw-r--r--     57092 Jul  9  2004 xv-3.10a-resolution.patch
 	-rw-r--r--      4645 Apr 24  2004 xv-3.10a-selall.patch
-	-rw-r--r--       360 Mar 11  2004 xv-3.10a-shortsleep.patch
 	-rw-r--r--       702 Apr 24  2004 xv-3.10a-showlongname.patch
 	-rw-r--r--      1205 Apr 24  2004 xv-3.10a-staytoppdir.patch
-	-rw-r--r--      1591 Mar 15  2004 xv-3.10a-sysconfdir.patch
 	-rw-r--r--      4228 Apr 24  2004 xv-3.10a-wheelmouse.patch
 	-rw-r--r--       744 Apr 24  2004 xv-3.10a-xvbutt_wait.patch
-	-rw-r--r--       712 Mar 11  2004 xv-3.10a-xvexecpath.patch
 	-rw-r--r--      3757 Jul  9  2004 xv-3.10a-xvscrl_button2.patch
 	-rw-r--r--      1494 Jul  9  2004 xv-3.10a-xvscrl_wait.patch
 	-rw-r--r--     19352 Jul  9  2004 xv-3.10a-xvzoom.patch
-	-rw-r--r--      1827 Apr 24  2004 xv-3.10a-zeroquit.patch
 
- - xv310a-jp-extension-rev5.3.3.tar.gz		[extensive]
- - xv-3.10a-jp-extension-5.3.3-png-1.2d.patch	[PNG patch relative to jp-ext]
- - xv-3.10a+jp-extension-rev5.3.3+FLmask.v2.1+png+misc.patch	[??]
+ - xv-3.10a+jp-extension-rev5.3.3+FLmask.v2.1+png+misc.patch	["mask" support]
 
- - xv-grab-imake-hips.patch (JPD)		[HIPS format, -startgrab option]
  - xv-psnewstyle.patch (TA)			[coming later in 2005?]
  - xv-3.10a.patch.linux (PBJ)			[maybe use vdcomp.c changes?]
  - xvxpm-anthony-thyssen.c (AT)			["slate grey" bug already gone?]
@@ -332,8 +357,8 @@
 not finished (and/or even started ;-) ):
 
  - fix xvpng.c not to use direct struct access
- - fix for never-ending pile of SLOW popups when viewing TIFFs with unknown tags
-   (or truncated/corrupted images)
+ - (better) fix for never-ending pile of SLOW popups when viewing TIFFs with
+   unknown tags (or truncated/corrupted images)
  - fix for minor .Z inefficiency in xv.c ("FIXME")
  - fix for filename entry-field mouse/cursor bogosity
    (want at least positioning to work; preferably also select/cut/paste)
@@ -344,6 +369,7 @@
  - transparency support for TIFF, XPM and TGA images
  - support for tiled background image (with transparent foreground image)
  - MNG/JNG support
+ - SVG support
 
 
 ChangeLog
@@ -364,7 +390,7 @@
   20040531
     fixed undefined CLK_TCK with gcc -ansi (enh/USE_TICKS option); made
     libjpeg, libtiff, libpng and zlib sections of makefile more consistent
-    (enh);
+    (enh)
 
   20040606
     added freshmeat link, build instructions, and changelog to jumbo README
@@ -385,3 +411,32 @@
     sex bug in 24-bit FixPix display code (enh/USE_24BIT_ENDIAN_FIX option);
     fixed numerical-keypad NumLock behavior and delete-key behavior in file-
     load/save window (enh); made schnauzer window and icons configurable (enh)
+
+  20050417
+    incorporated "Japanese extension" patches, revision 5.3.3 (enh); fixed
+    additional *SECURITY* issues (format-string vulnerabilities, system()
+    and mktemp() calls, etc., but NOT heap overflows in new decoders) both
+    in existing code and in jp-extension additions (enh)
+
+  20050425
+    added support for -startgrab option (enh); added support for a "Never"
+    button to file-overwrite popups (enh); added NetBSD and BSDI to list of
+    mkstemp()-supporting systems (enh); improved line-drawing code to set the
+    correct pixels for lines of all slopes (enh); added "Page n of m" to Info
+    window for multipage images (enh); added support for multipage (animated)
+    GIFs (enh); fixed -random support so randomized file list can be traversed
+    normally in forward or backward direction (enh); added typecasts to stat()
+    printfs for portability (enh); fixed erroneous use of "creation" time and
+    forced unlink prior to overwrite in schnauzer thumbnail code (enh); added
+    HIPS support (enh/HAVE_HIPS option)
+
+  20050501
+    extended multipage keyboard support (PgUp/PgDn) to all windows except
+    control ("console") and directory (enh); fixed minor (non-security)
+    format-string issue in xv.c (enh); shortened delay on popup error windows
+    from 3 seconds to 1 second (enh); tweaked text-viewer localization support
+    (TV_L10N) for Linux (enh); added keyboard short cuts for Color and
+    Grayscale buttons in print dialog (enh); added support for separate "magic
+    suffix" (xv_mgcsfx) config dir (enh); added PREFIX and DESTDIR support to
+    Makefile (enh); fixed handling of zero-length files and other text-viewer
+    failures (enh)
diff -ruN xv-3.10a-bugfixes/README.pcd xv-3.10a-enhancements/README.pcd
--- xv-3.10a-bugfixes/README.pcd	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/README.pcd	2001-07-08 11:21:19.000000000 -0700
@@ -0,0 +1,159 @@
+Copyright 1993-2001 David Clunie.
+
+PCD patch for XV 3.10a Release Notes 2001/07/08.
+
+See also the progress notes at the end of this file. Thanks to all those
+contributors who have substantially improved this patch.
+
+These patches allow xv to read Kodak photocd files and choose which of the
+5 available resolutions one wants to view.
+
+When a photocd file is loaded, a dialog box asks which resolution you
+would like. The visual schnauzer builds thumbnails by reading the lowest
+resolution image. The selected resolution can be selected from the
+command line with the -pcd option:
+
+	[-pcd 0|1|2|3|4]
+
+where:
+
+	0=192*128,	base/16 resolution
+	1=384*256,	base/4 resolution
+	2=768*512,	base resolution
+	3=1536*1024,	4base resolution
+	4=3072*2048	16base resolution.
+
+Note that the Pro format is not supported.
+
+The command line option allows loops without the dialog box popping up, eg.:
+
+	xv -pcd 1 -wloop -wait 10 *.pcd
+
+The code is pretty crude and was written quickly for a specific purpose and
+has not really been cleaned up. It is poorly structured, full of debugging
+codes and verbose comments, and there is very little attempt at optimizing
+things. No profiling has been done.
+
+There is not yet support for overview files, nor is there a facility to
+use the higher resolution chroma planes from when viewing lower resolution
+images.
+
+It's only claim to fame is that it works and produces reasonable looking
+images.
+
+The outline of this is shamelessly derived from xvpbm.c to read the
+file, and xvtiffwr.c to handle the popup window and X stuff (X never
+has been my forte !), and the PhotoCD format information (though not
+the code) was found in Hadmut Danisch's (danisch@ira.uka.de) hpcdtoppm
+program in which he has reverse engineered the format by studying
+hex dumps of PhotoCDs ! The color stuff and Huffman decding were
+extensively revised by Matthew Francey.
+
+Feel free to send me comments or improvements, or even better, more
+information about the photo CD format ... hopefully someone who really
+knows what they are doing will tidy it up or do a neater job.
+
+david (dclunie@dclunie.com)
+
+---------
+
+The trace #define in xvpcd.c is now in the right place, and the ansi
+prototype for the magnify function has been fixed. Colin made me switch to
+xvbcopy() which seems like a good idea for System V victims.
+
+---------
+
+Date: Wed, 22 Dec 1993 16:09:52 --1000
+From: colinc@fitmail.fit.qut.edu.au (Colin Canfield )
+
+I have done some more work using your patch I thought you might be intested in.
+The major change was adding a size parameter to the LoadPCD; either -1 to mean
+the popup or else the size you desired. This allows batch mode processing,
+specifically xv -pcd <size> <filename>, and the visual schnauzer can work in 
+quick mode (ie. you don't have to select each image size when it is building 
+the icons)
+
+I have added an xbm file for the file type but haven't drawn an icon for it,
+this is in bitmaps/br_pcd.xbm. I will just send you the new files.
+
+---------
+
+From: andrew@andrew.triumf.ca (Andrew Daviel)
+Date: 16 Feb 1995 23:32:21 GMT
+
+This is David Clunie's patch for xv-3.00 tuned a bit to work
+on xv-3.10. The code's all the same except for replacing 
+"trace" with "fprintf" in xvpcd.c and adding an "unsigned" qualifier to 
+keep my compiler (gcc) happy. Oh yes, changed RFT_PCD to 20 as
+John Bradley has now used 15 through 19.
+
+---------
+
+From: dclunie@flash.us.com (David A. Clunie)
+Date: Thu Jun 15 14:43:46 GMT+0300 1995
+
+Andrew's patch didn't include Colin's browser changes, so I redid the
+xv-3.10 update from scratch ... it seems pretty much the same as
+Andrew's changes. I also edited the Imakefile and Makefiles in order
+to support the PCD changes, as well as make the install process a
+little more flexible, with options to strip and set modes and so on.
+Also made RFT_PCD 25 so as not to conflict with magpic patch from Japan
+by Ikemoto Masahiro <ikeyan@airlab.cs.ritsumei.ac.jp>, and used his
+bitmap icon for pcd files.
+
+Now there are two versions of the patch, one which should be applied
+to the xv-3.10 distribution.
+
+The other should be applied to xv-3.10 AFTER Ikemoto Masahiro's 
+Patch.magpic2.PhotoCD.XV319a, in order to add the browser features to
+the latter, as well as fixing a Makefile typo (was xcpcd.c not xvpcd.c)
+and including unistd.h for the SEEK_xxx constants in the magicpic
+stuff.
+
+---------
+
+Subject: Re: photo-cd patch for xv 
+From: Matthew Francey <mdf@angoss.com>
+Date: Mon, 26 Mar 2001 15:37:55 +0000
+
+Attached is a revised version of xvpcd.c;  the areas that I have
+re-written or changed are in a different coding style so you can tell
+what has changed.  The GNU 'indent' program can be run against the file
+to enforce a consistent style ..
+
+Here is what I've done though:
+
+a) huffman table reader re-written, because it would fail on some
+   photocd files with "unusual" huffman codes.
+
+b) the huffman-coded corrections are now properly applied
+
+c) the corrections can sometimes over or underflow;  clipping has been
+   introduced and effectively fixes the problem, but I suspect that
+   there is something deeper going on.
+
+d) the "official" YCC->sRGB transform is done.  a "beyond 100% white"
+   mapping table was snarfed from ImageMagick.  an option for using a
+   flat linear LUT was added -- this can make somewhat over-exposed images
+   look alot nicer.
+
+e) there were strange problems where the code wouldn't be able to find
+   the huffman tables and data for the 16base image (the bit-buffering
+   code was starting mid-sector, instead of at a sector boundary).  Looking
+   at a pcd file with a hex editor suggests to me that it is possible to
+   just skip directly to these huffman tables -- no special "+12" and such
+   constants necessary.  But I haven't tried this yet.
+
+The results:  I've been able to read about 50 or 60 .pcd files [scattered
+in age from 6 years old to scans done last week] with this code without
+incident.  Image quality at the high resolution is excellent.  Even the
+trivial amount of LUT control is useful when dealing with over-exposed
+images.
+
+If I get around to it:  finer LUT control to take advantage of the
+slightly extended dynamic range of PhotoCD scans, especially in regards to
+dark or somewhat underexposed scenes.
+
+
+
+
diff -ruN xv-3.10a-bugfixes/bggen.c xv-3.10a-enhancements/bggen.c
--- xv-3.10a-bugfixes/bggen.c	2004-05-16 17:50:52.000000000 -0700
+++ xv-3.10a-enhancements/bggen.c	2005-04-17 14:04:22.000000000 -0700
@@ -34,7 +34,7 @@
 #define MAXCOLS  128
 
 /* some VMS thing... */
-#ifdef vax11c
+#if defined(vax11c) || (defined(__sony_news) && (defined(bsd43) || defined(__bsd43) || defined(SYSTYPE_BSD) || defined(__SYSTYPE_BSD)))
 #include <ctype.h>
 #endif
 
diff -ruN xv-3.10a-bugfixes/bits/br_bzip2 xv-3.10a-enhancements/bits/br_bzip2
--- xv-3.10a-bugfixes/bits/br_bzip2	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/bits/br_bzip2	1998-04-12 19:23:39.000000000 -0700
@@ -0,0 +1,27 @@
+#define br_bzip2_width 48
+#define br_bzip2_height 48
+static unsigned char br_bzip2_bits[] = {
+   0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x7c, 0xbe, 0x3d, 0x0e, 0x02, 0x20, 0xfc, 0xbe, 0x7d, 0x1f, 0x02,
+   0x20, 0xcc, 0xb0, 0x6d, 0x1b, 0x02, 0x20, 0xcc, 0x98, 0x6d, 0x1b, 0x02,
+   0x20, 0xfc, 0x98, 0x6d, 0x18, 0x02, 0x20, 0x7c, 0x8c, 0x7d, 0x0c, 0x02,
+   0x20, 0xcc, 0x8c, 0x3d, 0x0e, 0x02, 0x20, 0xcc, 0x84, 0x0d, 0x06, 0x02,
+   0x20, 0xcc, 0x86, 0x0d, 0x03, 0x02, 0x20, 0xfc, 0xbe, 0x0d, 0x1f, 0x02,
+   0x20, 0x7c, 0xbe, 0x0d, 0x1f, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
diff -ruN xv-3.10a-bugfixes/bits/br_mag xv-3.10a-enhancements/bits/br_mag
--- xv-3.10a-bugfixes/bits/br_mag	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/bits/br_mag	2005-04-17 14:04:22.000000000 -0700
@@ -0,0 +1,27 @@
+#define br_mag_width 48
+#define br_mag_height 48
+static unsigned char br_mag_bits[] = {
+   0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x0c, 0x86, 0xc1, 0x0f, 0x02,
+   0x20, 0x0c, 0xc6, 0xe3, 0x1f, 0x02, 0x20, 0x1c, 0xe7, 0x67, 0x18, 0x02,
+   0x20, 0x1c, 0x77, 0x6e, 0x18, 0x02, 0x20, 0xbc, 0x37, 0x6c, 0x00, 0x02,
+   0x20, 0xbc, 0x37, 0x6c, 0x00, 0x02, 0x20, 0xec, 0x36, 0x6c, 0x1e, 0x02,
+   0x20, 0xec, 0xf6, 0x6f, 0x1e, 0x02, 0x20, 0x4c, 0xf6, 0x6f, 0x18, 0x02,
+   0x20, 0x4c, 0x36, 0x6c, 0x18, 0x02, 0x20, 0x0c, 0x36, 0x6c, 0x18, 0x02,
+   0x20, 0x0c, 0x36, 0xec, 0x1f, 0x02, 0x20, 0x0c, 0x36, 0xcc, 0x0f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
diff -ruN xv-3.10a-bugfixes/bits/br_maki xv-3.10a-enhancements/bits/br_maki
--- xv-3.10a-bugfixes/bits/br_maki	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/bits/br_maki	2005-04-17 14:04:22.000000000 -0700
@@ -0,0 +1,27 @@
+#define br_maki_width 48
+#define br_maki_height 48
+static unsigned char br_maki_bits[] = {
+   0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x83, 0x61, 0x18, 0x33, 0x02,
+   0x20, 0x83, 0xf1, 0x98, 0x33, 0x02, 0x20, 0xc7, 0xf9, 0x99, 0x31, 0x02,
+   0x20, 0xc7, 0x9d, 0xdb, 0x30, 0x02, 0x20, 0xef, 0x0d, 0xfb, 0x30, 0x02,
+   0x20, 0xef, 0x0d, 0x7b, 0x30, 0x02, 0x20, 0xbb, 0x0d, 0x7b, 0x30, 0x02,
+   0x20, 0xbb, 0xfd, 0xdb, 0x30, 0x02, 0x20, 0x93, 0xfd, 0xdb, 0x30, 0x02,
+   0x20, 0x93, 0x0d, 0x9b, 0x31, 0x02, 0x20, 0x83, 0x0d, 0x9b, 0x31, 0x02,
+   0x20, 0x83, 0x0d, 0x1b, 0x33, 0x02, 0x20, 0x83, 0x0d, 0x1b, 0x33, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
diff -ruN xv-3.10a-bugfixes/bits/br_mgcsfx xv-3.10a-enhancements/bits/br_mgcsfx
--- xv-3.10a-bugfixes/bits/br_mgcsfx	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/bits/br_mgcsfx	2005-04-17 14:04:22.000000000 -0700
@@ -0,0 +1,27 @@
+#define br_mgcsfx_width 48
+#define br_mgcsfx_height 48
+static unsigned char br_mgcsfx_bits[] = {
+   0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x3c, 0xcf, 0x71, 0x00, 0x02,
+   0x20, 0x6c, 0x61, 0xda, 0x00, 0x02, 0x20, 0x6c, 0x67, 0xd8, 0x1e, 0x02,
+   0x20, 0x3c, 0x61, 0xd8, 0x1e, 0x02, 0x20, 0x6c, 0x61, 0xda, 0x00, 0x02,
+   0x20, 0x6c, 0xcf, 0x71, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x4e, 0x7a, 0xef, 0x3d, 0x02, 0x20, 0xd3, 0x32, 0x68, 0x6c, 0x02,
+   0x20, 0xc3, 0x32, 0xe4, 0x6c, 0x02, 0x20, 0x5b, 0x33, 0x62, 0x6c, 0x02,
+   0x20, 0x53, 0x33, 0x61, 0x6c, 0x02, 0x20, 0x4e, 0x7a, 0xef, 0x3d, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
diff -ruN xv-3.10a-bugfixes/bits/br_pcd xv-3.10a-enhancements/bits/br_pcd
--- xv-3.10a-bugfixes/bits/br_pcd	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/bits/br_pcd	1995-06-15 21:31:53.000000000 -0700
@@ -0,0 +1,27 @@
+#define br_pcd_width 48
+#define br_pcd_height 48
+static unsigned char br_pcd_bits[] = {
+   0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x67, 0x00, 0xe0, 0x1c, 0x02,
+   0x20, 0x6f, 0x00, 0xf0, 0x3d, 0x02, 0x20, 0x6b, 0x00, 0xb0, 0x2d, 0x02,
+   0x20, 0x6b, 0x00, 0x33, 0x2c, 0x02, 0x20, 0x6b, 0x00, 0x33, 0x2c, 0x02,
+   0x20, 0xeb, 0x98, 0x37, 0x2c, 0x02, 0x20, 0xef, 0xbd, 0x37, 0x2c, 0x02,
+   0x20, 0x67, 0x2d, 0x33, 0x2c, 0x02, 0x20, 0x63, 0x2d, 0x33, 0x2c, 0x02,
+   0x20, 0x63, 0x2d, 0x33, 0x2c, 0x02, 0x20, 0x63, 0x2d, 0xb3, 0x2d, 0x02,
+   0x20, 0x63, 0x3d, 0xf7, 0x3d, 0x02, 0x20, 0x63, 0x19, 0xe6, 0x1c, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
diff -ruN xv-3.10a-bugfixes/bits/br_pi xv-3.10a-enhancements/bits/br_pi
--- xv-3.10a-bugfixes/bits/br_pi	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/bits/br_pi	2005-04-17 14:04:22.000000000 -0700
@@ -0,0 +1,27 @@
+#define br_pi_width 48
+#define br_pi_height 48
+static unsigned char br_pi_bits[] = {
+   0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x80, 0x1f, 0x7e, 0x00, 0x02,
+   0x20, 0x80, 0x3f, 0x7e, 0x00, 0x02, 0x20, 0x80, 0x31, 0x18, 0x00, 0x02,
+   0x20, 0x80, 0x31, 0x18, 0x00, 0x02, 0x20, 0x80, 0x31, 0x18, 0x00, 0x02,
+   0x20, 0x80, 0x39, 0x18, 0x00, 0x02, 0x20, 0x80, 0x1f, 0x18, 0x00, 0x02,
+   0x20, 0x80, 0x0f, 0x18, 0x00, 0x02, 0x20, 0x80, 0x01, 0x18, 0x00, 0x02,
+   0x20, 0x80, 0x01, 0x18, 0x00, 0x02, 0x20, 0x80, 0x01, 0x18, 0x00, 0x02,
+   0x20, 0x80, 0x01, 0x7e, 0x00, 0x02, 0x20, 0x80, 0x01, 0x7e, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
diff -ruN xv-3.10a-bugfixes/bits/br_pic xv-3.10a-enhancements/bits/br_pic
--- xv-3.10a-bugfixes/bits/br_pic	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/bits/br_pic	2005-04-17 14:04:22.000000000 -0700
@@ -0,0 +1,27 @@
+#define br_pic_width 48
+#define br_pic_height 48
+static unsigned char br_pic_bits[] = {
+   0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xf0, 0xf3, 0xf3, 0x01, 0x02,
+   0x20, 0xf0, 0xf7, 0xfb, 0x03, 0x02, 0x20, 0x30, 0xc6, 0x18, 0x03, 0x02,
+   0x20, 0x30, 0xc6, 0x18, 0x00, 0x02, 0x20, 0x30, 0xc6, 0x18, 0x00, 0x02,
+   0x20, 0x30, 0xc7, 0x18, 0x00, 0x02, 0x20, 0xf0, 0xc3, 0x18, 0x00, 0x02,
+   0x20, 0xf0, 0xc1, 0x18, 0x00, 0x02, 0x20, 0x30, 0xc0, 0x18, 0x00, 0x02,
+   0x20, 0x30, 0xc0, 0x18, 0x00, 0x02, 0x20, 0x30, 0xc0, 0x18, 0x03, 0x02,
+   0x20, 0x30, 0xf0, 0xfb, 0x03, 0x02, 0x20, 0x30, 0xf0, 0xf3, 0x01, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
diff -ruN xv-3.10a-bugfixes/bits/br_pic2 xv-3.10a-enhancements/bits/br_pic2
--- xv-3.10a-bugfixes/bits/br_pic2	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/bits/br_pic2	2005-04-17 14:04:22.000000000 -0700
@@ -0,0 +1,27 @@
+#define br_pic2_width 48
+#define br_pic2_height 48
+static unsigned char br_pic2_bits[] = {
+   0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x3f, 0x3f, 0x1f, 0x1f, 0x02,
+   0x20, 0x7f, 0xbf, 0xbf, 0x3f, 0x02, 0x20, 0x63, 0x8c, 0xb1, 0x31, 0x02,
+   0x20, 0x63, 0x8c, 0x01, 0x30, 0x02, 0x20, 0x63, 0x8c, 0x01, 0x30, 0x02,
+   0x20, 0x73, 0x8c, 0x01, 0x30, 0x02, 0x20, 0x3f, 0x8c, 0x01, 0x18, 0x02,
+   0x20, 0x1f, 0x8c, 0x01, 0x0c, 0x02, 0x20, 0x03, 0x8c, 0x01, 0x06, 0x02,
+   0x20, 0x03, 0x8c, 0x01, 0x03, 0x02, 0x20, 0x03, 0x8c, 0xb1, 0x01, 0x02,
+   0x20, 0x03, 0xbf, 0xbf, 0x3f, 0x02, 0x20, 0x03, 0x3f, 0x9f, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
diff -ruN xv-3.10a-bugfixes/bits/br_png xv-3.10a-enhancements/bits/br_png
--- xv-3.10a-bugfixes/bits/br_png	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/bits/br_png	1996-06-13 14:32:08.000000000 -0700
@@ -0,0 +1,28 @@
+#define br_png_width 48
+#define br_png_height 48
+static unsigned char br_png_bits[] = {
+  0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0xf8, 0x19, 0xc3, 0x07, 0x02, 0x20, 0x18, 0x3b, 0x63, 0x0c, 0x02,
+  0x20, 0x18, 0x3b, 0x33, 0x00, 0x02, 0x20, 0x18, 0x5b, 0x33, 0x00, 0x02,
+  0x20, 0xf8, 0x59, 0x33, 0x0f, 0x02, 0x20, 0x18, 0x98, 0x33, 0x0c, 0x02,
+  0x20, 0x18, 0x98, 0x33, 0x0c, 0x02, 0x20, 0x18, 0x18, 0x63, 0x0c, 0x02,
+  0x20, 0x18, 0x18, 0xc3, 0x0b, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03,
+  };
diff -ruN xv-3.10a-bugfixes/bits/br_zx xv-3.10a-enhancements/bits/br_zx
--- xv-3.10a-bugfixes/bits/br_zx	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/bits/br_zx	1998-08-06 13:00:03.000000000 -0700
@@ -0,0 +1,28 @@
+#define br_zx_width 48
+#define br_zx_height 48
+static unsigned char br_zx_bits[] = {
+  0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x7f, 0xce, 0x01, 0x0e, 0x02, 0x20, 0x61, 0x84, 0x00, 0x11, 0x02,
+  0x20, 0x30, 0x48, 0x00, 0x10, 0x02, 0x20, 0x18, 0x38, 0x10, 0x08, 0x02,
+  0x20, 0x0c, 0x30, 0x10, 0x0e, 0x02, 0x20, 0x06, 0x68, 0x7c, 0x10, 0x02,
+  0x20, 0x03, 0x48, 0x10, 0x10, 0x02, 0x20, 0x41, 0x84, 0x10, 0x11, 0x02,
+  0x20, 0x7f, 0xce, 0x01, 0x0e, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0xff, 0xff, 0xff, 0xff, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x40, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x10, 0x02, 0x20, 0x00, 0x00, 0x00, 0x08, 0x03,
+  0x20, 0x00, 0x00, 0x00, 0x84, 0x03, 0x20, 0x00, 0x00, 0x00, 0xc2, 0x03,
+  0x20, 0x00, 0x00, 0x00, 0xe1, 0x03, 0x20, 0x00, 0x00, 0x80, 0xf0, 0x02,
+  0x20, 0x00, 0x00, 0x40, 0x78, 0x02, 0x20, 0x00, 0x00, 0x20, 0x3c, 0x02,
+  0x20, 0x00, 0x00, 0x10, 0x1e, 0x02, 0x20, 0x00, 0x00, 0x08, 0x0f, 0x03,
+  0x20, 0x00, 0x00, 0x84, 0x87, 0x03, 0x20, 0x00, 0x00, 0xc2, 0xc3, 0x03,
+  0x20, 0x00, 0x00, 0xe1, 0xe1, 0x03, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03,
+  };
diff -ruN xv-3.10a-bugfixes/config.h xv-3.10a-enhancements/config.h
--- xv-3.10a-bugfixes/config.h	2005-03-21 23:21:31.000000000 -0800
+++ xv-3.10a-enhancements/config.h	2005-04-30 23:52:42.000000000 -0700
@@ -6,26 +6,46 @@
 /***************************************************************************
  * GZIP'd file support
  *
- * if you have the gnu uncompression utility 'gunzip', XV can use it to
- * automatically 'unzip' any gzip'd files.  To enable this feature,
- * change 'undef' to 'define' in the following line.  Needless to say, if
- * your gunzip is installed elsewhere on your machine, change the 'GUNZIP'
- * definition appropriately. (use 'which gunzip' to find if you have gunzip,
- * and where it lives)
+ * if you have the GNU uncompression utility 'gunzip' (or 'gzip' itself,
+ * which is just a link to gunzip), XV can use it to automatically 'unzip'
+ * any gzip'd files.  To enable this feature, change 'undef' to 'define' in
+ * the following line.  Needless to say, if your gunzip is installed elsewhere
+ * on your machine, change the 'GUNZIP' definition appropriately. (use
+ * 'which gunzip' to find if you have gunzip, and where it lives; ditto for
+ * gzip)
  */
-#undef USE_GUNZIP
+#define USE_GUNZIP
 
 #ifdef USE_GUNZIP
 #  ifdef VMS
 #    define GUNZIP "UNCOMPRESS"
 #  else
-/*   define GUNZIP "/usr/local/bin/gunzip -q"  */
-#    define GUNZIP "/usr/bin/gzip -dq"   /* more portable */
+#    if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__linux__)
+#      define GUNZIP "/usr/bin/gzip -dq"
+#    else
+#      define GUNZIP "/usr/local/bin/gzip -dq" /* is full path truly needed? */
+#    endif
 #  endif
 #endif
 
 
 /***************************************************************************
+ * BZIP2'd file support
+ *
+ * if you have the uncompression utility 'bunzip2' (or 'bzip2' itself, which
+ * is just a link to bunzip2), XV can use it to automatically 'unzip' any
+ * bzip2'd files.  To enable this feature, change 'undef' to 'define' in the
+ * following line (if not already done).  Use 'which bunzip2' or 'which bzip2'
+ * to find if you have bzip2/bunzip2, and where it lives.
+ */
+#define USE_BUNZIP2
+
+#ifdef USE_BUNZIP2
+#  define BUNZIP2 "bzip2 -d"  /* should this include the full path? */
+#endif
+
+
+/***************************************************************************
  * compress'd file support
  *
  * if you have GUNZIP defined above, just ignore this, as 'gunzip' can
@@ -38,7 +58,14 @@
  */
 #define UNCOMPRESS "/usr/ucb/uncompress"
 
-#if defined(hpux) || defined(SVR4) || defined(__386BSD__)
+#if defined(hpux) || defined(SVR4) || \
+    defined(__386BSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
+    defined(__linux__)
+    /*
+     I want to use BSD macro for checking if this OS is *BSD or not,
+     but the macro is defined in <sys/parm.h>, which I don't know all
+     machine has or not.
+     */
 #  undef  UNCOMPRESS
 #  define UNCOMPRESS "/usr/bin/uncompress"
 #endif
@@ -90,6 +117,7 @@
  */
 
 /* #define GS_PATH "/usr/local/bin/gs" */
+#define GS_PATH "/usr/bin/gs"
 /* #define GS_LIB  "."                 */
 /* #define GS_DEV  "ppmraw"            */
 
@@ -120,3 +148,201 @@
 
 #define BACKING_STORE
 
+
+/***************************************************************************
+ * PhotoCD/MAG/PIC/MAKI/Pi/PIC2/HIPS format Support:
+ *
+ * if, for whatever reason--say, security concerns--you don't want to
+ * include support for one or more of the PhotoCD, MAG/MAKI/Pi/PIC/PIC2
+ * (Japanese), or HIPS (astronomical) image formats, change the relevant
+ * 'define' to 'undef' in the following lines.  Conversely, if you *do*
+ * want them, change 'undef' to 'define' as appropriate.
+ */
+
+#define HAVE_PCD	/* believed to be reasonably safe */
+
+#undef HAVE_MAG		/* probable security issues */
+#undef HAVE_MAKI	/* probable security issues */
+#undef HAVE_PI		/* probable security issues */
+#undef HAVE_PIC		/* probable security issues */
+#undef HAVE_PIC2	/* probable security issues */
+
+#undef HAVE_HIPS	/* probable security issues */
+
+
+/***************************************************************************
+ * MacBinary file support:
+ *
+ * if you want XV to be able to handle ``MacBinary'' files (which have
+ * 128 byte info file header at the head), change 'undef' to 'define'
+ * in the following line.
+ */
+
+#undef MACBINARY
+
+
+/***************************************************************************
+ * Auto Expand support:
+ *
+ * if you want to extract archived file automatically and regard it as
+ * a directory, change 'undef' to 'define' in the AUTO_EXPAND line.
+ *
+ * Virtual Thumbdir support:
+ *
+ * if you want Virtual directory based Thumbdir(It means that XV
+ * doesn't forget builded Icons still be quited even if the directory
+ * is read-only), change 'undef' to 'define' the VIRTUAL_TD line.
+ */
+
+#undef AUTO_EXPAND
+#undef VIRTUAL_TD
+
+#if defined(VIRTUAL_TD) && !defined(AUTO_EXPAND)
+#  undef VIRTUAL_TD
+#endif
+
+
+/***************************************************************************
+ * Adjust the aspect ratio of Icons:
+ *
+ * if you want to adjust the aspect ratio of the icons in Visual
+ * Schnauzer, change 'undef' to 'define' in the following line.
+ */
+
+#undef VS_ADJUST
+
+
+/***************************************************************************
+ * Restore original colormap:
+ *
+ * if you want to restore original colormap when icons in Visual
+ * Shunauzer is double-clicked, change 'undef' to 'define' in the
+ * following line.
+ */
+
+#undef VS_RESCMAP
+
+
+/***************************************************************************
+ * TextViewer l10n support:
+ *
+ * if you want XV to show the text in Japanese on TextViewer, change
+ * 'undef' to 'define' in the following line.
+ */
+
+#undef TV_L10N
+
+#ifdef TV_L10N
+/*
+ * if you want to change the default code-set used in case that XV
+ * fails to select correct code-set, uncomment the '#define
+ * LOCALE_DEFAULT' line and change the 'LOCALE_DEFAULT' definition
+ * appropriately.
+ * (0:ASCII, 1:EUC-j, 2:JIS, 3:MS Kanji) */
+
+/* #  define LOCALE_DEFAULT 0 */
+
+/*
+ * Uncomment and edit the following lines, if your X Window System was
+ * not compiled with -DX_LOCALE and you failed to display the Japanese
+ * text in TextViewer.  You don't have to write locale name of JIS code-set
+ * and Microsoft code-set, if your system doesn't support those code-sets.
+ */
+
+/*
+#  define LOCALE_NAME_EUC     "ja_JP.EUC"
+#  define LOCALE_NAME_JIS     "ja_JP.JIS"
+#  define LOCALE_NAME_MSCODE  "ja_JP.SJIS"
+*/
+
+/*
+ * if your system doesn't have the Japanese fonts in the sizes,
+ * Uncomment and edit the following font size entries.
+ */
+
+/* #  define TV_FONTSIZE 14,16,24 */
+
+/*
+ * If you need, uncomment and modify the following font name.
+ */
+
+/* #  define TV_FONTSET "-*-fixed-medium-r-normal--%d-*" */
+#endif /* TV_L10N */
+
+
+/***************************************************************************
+ * User definable filter support:
+ *
+ * Use the filters as input and output method for load and save unsupported
+ * image format file. The filter command is recognized by definition of
+ * magic number or suffix in "~/.xv_mgcsfx" .
+ * To enable this feature, change 'undef' to 'define' in the following line.
+ */
+#undef HAVE_MGCSFX
+
+#ifdef HAVE_MGCSFX
+/*
+ * Support symbol 'auto' as <input image type> in startup file. This type
+ * cannot use pipe as input; it writes to a temporary file and recognizes
+ * the actual filetype by XV processing.
+ */
+#  define HAVE_MGCSFX_AUTO
+
+/*
+ * The startup file of definition for MgcSfx. 'MGCSFX_SITE_RC' is read
+ * first and '~/MGCSFX_RC' is second. So same definitions in both files
+ * are overridden by '~/MGCSFX_RC'
+ * To define startup file, see the sample of startup file 'xv_mgcsfx.sample'.
+ */
+#  define MGCSFX_SITE_RC  "xv_mgcsfx"
+#  define MGCSFX_RC       ".xv_mgcsfx"
+
+/*
+ * If you want startup file to pass preprocessor in reading time, then
+ * change 'undef' to 'define' in the following line.
+ *
+ * WARNING : If you decide to use preprocessor, you must not write
+ *           '# <comment>' style comment in startup file. Because,
+ *           preprocessor can't recognize.  */
+#  undef USE_MGCSFX_PREPROCESSOR
+
+#  ifdef USE_MGCSFX_PREPROCESSOR
+/*
+ * This is used like "system("MGCSFX_PREPROCESSOR MGCSFX_RC > tmp_name");",
+ * and read tmp_name instead of MGCSFX_RC.
+ */
+#    define MGCSFX_PREPROCESSOR "/usr/lib/cpp"
+/* #    define MGCSFX_PREPROCESSOR "cc -E" */
+
+#  endif /* USE_MGCSFX_PREPROCESSOR */
+
+/*
+ * Default string of command. If input command is required for undefined file,
+ * dialog is popuped with 'MGCSFX_DEFAULT_INPUT_COMMAND'. And, if output
+ * command is required in save dialog of MgcSfx, dialog is popuped with
+ * 'MGCSFX_DEFAULT_OUTPUT_COMMAND'.
+ *
+ * WARNING : Now, supported only 'PNM' image format, when command input is
+ *           required. You should define filter which use 'PNM' image format
+ *           as input or output.
+ */
+#  define MGCSFX_DEFAULT_INPUT_COMMAND  "tifftopnm"
+#  define MGCSFX_DEFAULT_OUTPUT_COMMAND "pnmtotiff"
+
+#endif /* HAVE_MGCSFX */
+
+
+/***************************************************************************
+ * Multi-Lingual TextViewer
+ *
+ * if you want XV to show the text in multi-lingual on TextViewer, change
+ * 'undef' to 'define' in the following line.
+ */
+
+#undef TV_MULTILINGUAL
+
+#define TV_DEFAULT_CODESET TV_EUC_JAPAN
+
+#ifdef TV_MULTILINGUAL
+#  undef TV_L10N
+#endif
diff -ruN xv-3.10a-bugfixes/tiff/Makefile xv-3.10a-enhancements/tiff/Makefile
--- xv-3.10a-bugfixes/tiff/Makefile	2004-05-16 18:49:11.000000000 -0700
+++ xv-3.10a-enhancements/tiff/Makefile	2005-04-17 14:45:28.000000000 -0700
@@ -38,7 +38,7 @@
 IPATH= -I.
 
 COPTS=	-O
-CFLAGS=	${COPTS} ${IPATH}
+CFLAGS=	${COPTS} ${IPATH} -D_BSD_SOURCE
 
 INCS=	tiff.h tiffio.h
 
diff -ruN xv-3.10a-bugfixes/vdcomp.c xv-3.10a-enhancements/vdcomp.c
--- xv-3.10a-bugfixes/vdcomp.c	2005-03-20 17:48:59.000000000 -0800
+++ xv-3.10a-enhancements/vdcomp.c	2005-04-17 22:59:39.000000000 -0700
@@ -106,6 +106,7 @@
      !defined(pyr)                       && \
      !defined(__UMAXV__)                 && \
      !defined(bsd43)                     && \
+     !defined(__bsd43)                   && \
      !defined(aux)                       && \
      !defined(__bsdi__)                  && \
      !defined(sequent)                   && \
@@ -115,7 +116,14 @@
 #  if defined(hp300) || defined(hp800) || defined(NeXT)
 #   include <sys/malloc.h>                /* it's in 'sys' on HPs and NeXT */
 #  else
-#   include <malloc.h>
+#   if !defined(__386BSD__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
+    /*
+     I want to use BSD macro for checking if this OS is *BSD or not,
+     but the macro is defined in <sys/parm.h>, which I don't know all
+     machine has or not.
+     */
+#     include <malloc.h>
+#   endif
 #  endif
 # endif
 #endif /* !VMS */
diff -ruN xv-3.10a-bugfixes/xcmap.c xv-3.10a-enhancements/xcmap.c
--- xv-3.10a-bugfixes/xcmap.c	2005-03-20 15:51:59.000000000 -0800
+++ xv-3.10a-enhancements/xcmap.c	2005-04-17 14:45:28.000000000 -0700
@@ -163,7 +163,7 @@
   XSetBackground(theDisp,theGC,bcol);
 
   CreateMainWindow(cmd,geom,argc,argv);
-  Resize(WIDE,HIGH);
+  Resize((int)WIDE,(int)HIGH);
 
   XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask
 	       | StructureNotifyMask | ButtonPressMask);
@@ -212,10 +212,10 @@
 
   case ConfigureNotify: {
     XConfigureEvent *conf_event = (XConfigureEvent *) event;
+    int w = conf_event->width, h = conf_event->height;
 
-    if (conf_event->window == mainW &&
-	(conf_event->width != WIDE || conf_event->height != HIGH))
-      Resize(conf_event->width, conf_event->height);
+    if (conf_event->window == mainW && (w != WIDE || h != HIGH))
+      Resize((int)(w ? w : WIDE), (int)(h ? h : HIGH));
   }
     break;
 
@@ -274,6 +274,8 @@
   WIDE = HIGH = 256;			/* default window size */
 
   x=y=w=h=1;
+  hints.flags = 0;
+
   i=XParseGeometry(geom,&x,&y,&w,&h);
   if (i&WidthValue)
   {
diff -ruN xv-3.10a-bugfixes/xv.c xv-3.10a-enhancements/xv.c
--- xv-3.10a-bugfixes/xv.c	2005-03-20 22:25:22.000000000 -0800
+++ xv-3.10a-enhancements/xv.c	2005-05-01 13:33:25.000000000 -0700
@@ -62,6 +62,19 @@
 
 static char   basefname[128];   /* just the current fname, no path */
 
+#ifdef TV_L10N
+#  ifndef TV_FONTSET
+#    define TV_FONTSET "-*-fixed-medium-r-normal--%d-*"
+#  endif
+#  ifndef TV_FONTSIZE
+#    define TV_FONTSIZE 14,16
+#  endif
+
+static int    mfontsize[] = { TV_FONTSIZE, 0 };
+static char   mfontset[256];
+#endif
+
+
 /* things to do upon successfully loading an image */
 static int    autoraw    = 0;   /* force raw if using stdcmap */
 static int    autodither = 0;   /* dither */
@@ -78,6 +91,12 @@
 
 static int    force8     = 0;   /* force 8-bit mode */
 static int    force24    = 0;   /* force 24-bit mode */
+#ifdef HAVE_PCD
+static int    PcdSize    = -1;  /* force dialog to ask */
+#endif
+
+static float  waitsec_nonfinal = -1;  /* "normal" waitsec value */
+static float  waitsec_final = -1;     /* final-image waitsec value */
 
 /* used in DeleteCmd() and Quit() */
 static char  **mainargv;
@@ -103,7 +122,6 @@
 static void openNextLoop             PARM((void));
 static void openPrevPic              PARM((void));
 static void openNamedPic             PARM((void));
-static int  findRandomPic            PARM((void));
 static void mainLoop                 PARM((void));
 static void createMainWindow         PARM((char *, char *));
 static void setWinIconNames          PARM((char *));
@@ -120,16 +138,17 @@
 int   imap, ctrlmap, gmap, browmap, cmtmap, clrroot, nopos, limit2x;
 char *display, *whitestr, *blackstr, *histr, *lostr,
      *infogeom, *fgstr, *bgstr, *ctrlgeom, *gamgeom, *browgeom, *tmpstr;
-char *rootfgstr, *rootbgstr, *visualstr, *textgeom, *cmtgeom;
+char *rootfgstr, *rootbgstr, *imagebgstr, *visualstr, *textgeom, *cmtgeom;
 char *monofontname, *flistName;
+#ifdef TV_L10N
+char **misscharset, *defstr;
+int nmisscharset;
+#endif
 int  curstype, stdinflag, browseMode, savenorm, preview, pscomp, preset,
      rmodeset, gamset, cgamset, perfect, owncmap, rwcolor, stdcmap;
 int  nodecor;
 double gamval, rgamval, ggamval, bgamval;
 
-
-
-
 /*******************************************/
 int main(argc, argv)
      int    argc;
@@ -137,6 +156,9 @@
 /*******************************************/
 {
   int    i;
+#ifdef TV_L10N
+  int    j;
+#endif
   XColor ecdef;
   Window rootReturn, parentReturn, *children;
   unsigned int numChildren, rootDEEP;
@@ -153,6 +175,13 @@
   /*** variable Initialization                       ***/
   /*****************************************************/
 
+#ifdef TV_L10N
+  /* setlocale(LC_ALL, localeList[LOCALE_EUCJ]); */
+  setlocale(LC_ALL, "");
+  xlocale = (int)XSupportsLocale();	/* assume that (Bool) is (int) */
+	/* if X doesn't support ja_JP.ujis text viewer l10n doesn't work. */
+#endif
+
   xv_getwd(initdir, sizeof(initdir));
   searchdir[0] = '\0';
   fullfname[0] = '\0';
@@ -162,7 +191,7 @@
 
   /* init internal variables */
   display = NULL;
-  fgstr = bgstr = rootfgstr = rootbgstr = NULL;
+  fgstr = bgstr = rootfgstr = rootbgstr = imagebgstr = NULL;
   histr = lostr = whitestr = blackstr = NULL;
   visualstr = monofontname = flistName = NULL;
   winTitle = NULL;
@@ -180,6 +209,7 @@
   autoclose = autoDelete = 0;
   cmapInGam = 0;
   grabDelay = 0;
+  startGrab = 0;
   showzoomcursor = 0;
   perfect = owncmap = stdcmap = rwcolor = 0;
 
@@ -228,6 +258,10 @@
     if (!tmpdir) FatalError("can't malloc 'tmpdir'\n");
     strcpy(tmpdir, tmpstr);
   }
+#ifdef AUTO_EXPAND
+  Vdinit();
+  vd_handler_setup();
+#endif
 
   /* init command-line options flags */
   infogeom = DEFINFOGEOM;  ctrlgeom = DEFCTRLGEOM;
@@ -238,7 +272,7 @@
   ninstall = 0;  fixedaspect = 0;  noFreeCols = nodecor = 0;
   DEBUG = 0;  bwidth = 2;
   nolimits = useroot = clrroot = noqcheck = 0;
-  waitsec = -1;  waitloop = 0;  automax = 0;
+  waitsec = waitsec_final = -1.0;  waitloop = 0;  automax = 0;
   rootMode = 0;  hsvmode = 0;
   rmodeset = gamset = cgamset = 0;
   nopos = limit2x = 0;
@@ -251,6 +285,10 @@
   preset = 0;
   viewonly = 0;
 
+#ifdef ENABLE_FIXPIX_SMOOTH
+  do_fixpix_smooth = 0;
+#endif
+
   /* init 'xormasks' array */
   xorMasks[0] = 0x01010101;
   xorMasks[1] = 0x02020203;
@@ -277,6 +315,24 @@
   tiffW = (Window) NULL;  tiffUp = 0;
 #endif
 
+#ifdef HAVE_PNG
+  pngW = (Window) NULL;  pngUp = 0;
+#endif
+
+  pcdW = (Window) NULL;  pcdUp = 0;
+
+#ifdef HAVE_PIC2
+  pic2W = (Window) NULL;  pic2Up = 0;
+#endif
+
+#ifdef HAVE_PCD
+  pcdW = (Window) NULL;  pcdUp = 0;
+#endif
+
+#ifdef HAVE_MGCSFX
+  mgcsfxW = (Window) NULL;  mgcsfxUp = 0;
+#endif
+
   imap = ctrlmap = gmap = browmap = cmtmap = 0;
 
   ch_offx = ch_offy = p_offx = p_offy = 0;
@@ -303,13 +359,35 @@
   verifyArgs();
 
 
+#if 0
+#ifdef XVEXECPATH
+  /* set up path to search for external executables */
+  {
+    char *systempath = getenv("PATH");
+    char *xvexecpath = getenv("XVPATH");
+    if (xvexecpath == NULL) xvexecpath = XVEXECPATH;
+    /* FIXME: can systempath == NULL? */
+    strcat(systempath, ":");		/* FIXME: writing to mem we don't own */
+    strcat(systempath, xvexecpath);	/* FIXME: writing to mem we don't own */
+    /* FIXME:  was there supposed to be a setenv() call in here? */
+    if (DEBUG)
+      fprintf(stderr, "DEBUG: executable search path: %s\n", systempath);
+  }
+#endif
+#endif
+
+
   /*****************************************************/
   /*** X Setup                                       ***/
   /*****************************************************/
 
   theScreen = DefaultScreen(theDisp);
   theCmap   = DefaultColormap(theDisp, theScreen);
-  rootW     = RootWindow(theDisp,theScreen);
+  if (spec_window) {
+	rootW = spec_window;
+  } else {
+  	rootW = RootWindow(theDisp,theScreen);
+  }
   theGC     = DefaultGC(theDisp,theScreen);
   theVisual = DefaultVisual(theDisp,theScreen);
   ncells    = DisplayCells(theDisp, theScreen);
@@ -320,7 +398,7 @@
 
   rootDEEP = dispDEEP;
 
-  /* things dependant on theVisual:
+  /* things dependent on theVisual:
    *    dispDEEP, theScreen, rootW, ncells, theCmap, theGC,
    *    vrWIDE, dispWIDE, vrHIGH, dispHIGH, maxWIDE, maxHIGH
    */
@@ -500,6 +578,7 @@
   arrow     = XCreateFontCursor(theDisp,(u_int) curstype);
   cross     = XCreateFontCursor(theDisp,XC_crosshair);
   tcross    = XCreateFontCursor(theDisp,XC_tcross);
+  tlcorner  = XCreateFontCursor(theDisp,XC_top_left_corner);
   zoom      = XCreateFontCursor(theDisp,XC_sizing);
 
   {
@@ -575,6 +654,18 @@
       xvAllocColor(theDisp, theCmap, &ecdef))  rootbg = ecdef.pixel;
 
 
+  /* GRR 19980308:  set up image bg color (for transparent images) */
+  have_imagebg = 0;
+  if (imagebgstr && XParseColor(theDisp, theCmap, imagebgstr, &ecdef) &&
+      xvAllocColor(theDisp, theCmap, &ecdef)) {
+    /* imagebg = ecdef.pixel; */
+    have_imagebg = 1;
+    imagebgR = ecdef.red;
+    imagebgG = ecdef.green;
+    imagebgB = ecdef.blue;
+  }
+
+
   /* set up hi/lo colors */
   i=0;
   if (dispDEEP > 1) {   /* only if we're on a reasonable display */
@@ -664,6 +755,61 @@
 
   monofont=monofinfo->fid;
 
+#ifdef TV_L10N
+  if (xlocale) {
+    i = 0;
+    while (mfontsize[i]) {
+      xlocale = 1;	/* True */
+
+      sprintf(mfontset, TV_FONTSET, mfontsize[i]);
+/*fprintf(stderr, "FontSet: %s\n", mfontset);*/
+
+      monofset = XCreateFontSet(theDisp, mfontset,
+				&misscharset, &nmisscharset, &defstr);
+#  if 0	/* not useful */
+      if (!monofset) {
+	/* the current locale is not supported */
+/*fprintf(stderr, "Current locale `%s' is not supported.\n", localeList[i]);*/
+	xlocale = 0;
+	break;
+      }
+#  endif
+/*fprintf(stderr, "# of misscharset in mfontsize[%d]: %d\n", i,nmisscharset);*/
+
+      for (j = 0; j < nmisscharset; j++) {
+	if (!strncmp(misscharset[j], "jisx0208", 8)) {
+	  /* font for JIS X 0208 is not found */
+	  xlocale = 0;
+	  break;
+	}
+      }
+
+      if (xlocale) {
+	monofsetinfo = XExtentsOfFontSet(monofset);
+	monofsetinfo->max_logical_extent.width = mfontsize[i];
+		/* correct size of TextViewer
+		   in case that JIS X 0208 is not found */
+	break;
+      }
+
+      i++;
+    } /* while (mfontsize[i]) */
+
+#  if 0
+    if (nmisscharset > 0) {
+      sprintf(str,"missing %d charset:\n", nmisscharset);
+      for (i = 0; i < nmisscharset; i++) {
+	sprintf(str, "%s\t%s\n", str, misscharset[i]);
+      }
+#    if 0
+      FatalError(str);
+#    else
+      fprintf(stderr, "%s", str);
+#    endif
+    }
+#  endif
+  }
+#endif	/* TV_L10N */
 
 
 
@@ -693,6 +839,18 @@
     }
     else namelist[0] = NULL;
   }
+  else if (randomShow) {
+    int i, j;
+    char *tmp;
+
+    srandom((int)time((time_t *)0));
+    for (i = numnames; i > 1; i--) {
+      j = random() % i;
+      tmp = namelist[i-1];
+      namelist[i-1] = namelist[j];
+      namelist[j] = tmp;
+    }
+  }
 
   if (numnames) makeDispNames();
 
@@ -796,6 +954,25 @@
   XSetTransientForHint(theDisp, tiffW, dirW);
 #endif
 
+#ifdef HAVE_PNG
+  CreatePNGW();
+  XSetTransientForHint(theDisp, pngW, dirW);
+#endif
+
+#ifdef HAVE_PCD
+  CreatePCDW();
+  XSetTransientForHint(theDisp, pcdW, dirW);
+#endif
+
+#ifdef HAVE_PIC2
+  CreatePIC2W();
+  XSetTransientForHint(theDisp, pic2W, dirW);
+#endif
+
+#ifdef HAVE_MGCSFX
+  CreateMGCSFXW();
+  XSetTransientForHint(theDisp, mgcsfxW, dirW);
+#endif
 
   LoadFishCursors();
   SetCursors(-1);
@@ -964,7 +1141,11 @@
 
   dispDEEP  = vinfo[best].depth;
   theScreen = vinfo[best].screen;
-  rootW     = RootWindow(theDisp, theScreen);
+  if (spec_window) {
+	rootW = spec_window;
+  } else {
+  	rootW = RootWindow(theDisp,theScreen);
+  }
   ncells    = vinfo[best].colormap_size;
   theCmap   = XCreateColormap(theDisp, rootW, theVisual, AllocNone);
 
@@ -1095,6 +1276,9 @@
 
   if (rd_str ("fileList"))       flistName   = def_str;
   if (rd_flag("fixed"))          fixedaspect = def_int;
+#ifdef ENABLE_FIXPIX_SMOOTH
+  if (rd_flag("fixpix"))         do_fixpix_smooth = def_int;
+#endif
   if (rd_flag("force8"))         force8      = def_int;
   if (rd_flag("force24"))        force24     = def_int;
   if (rd_str ("foreground"))     fgstr       = def_str;
@@ -1106,21 +1290,37 @@
   if (rd_str ("highlight"))      histr       = def_str;
   if (rd_str ("iconGeometry"))   icongeom    = def_str;
   if (rd_flag("iconic"))         startIconic = def_int;
+  if (rd_str ("imageBackground")) imagebgstr = def_str;
   if (rd_str ("infoGeometry"))   infogeom    = def_str;
   if (rd_flag("infoMap"))        imap        = def_int;
   if (rd_flag("loadBrowse"))     browseMode  = def_int;
   if (rd_str ("lowlight"))       lostr       = def_str;
+#ifdef MACBINARY
+  if (rd_flag("macbinary"))      handlemacb  = def_int;
+#endif
+#ifdef HAVE_MGCSFX
+  if (rd_flag("mgcsfx"))         mgcsfx      = def_int;
+#endif
   if (rd_flag("mono"))           mono        = def_int;
   if (rd_str ("monofont"))       monofontname = def_str;
   if (rd_int ("ncols"))          ncols       = def_int;
   if (rd_flag("ninstall"))       ninstall    = def_int;
   if (rd_flag("nodecor"))        nodecor     = def_int;
   if (rd_flag("nolimits"))       nolimits    = def_int;
+#ifdef HAVE_MGCSFX
+  if (rd_flag("nomgcsfx"))       nomgcsfx    = def_int;
+#endif
+#if defined(HAVE_PIC) || defined(HAVE_PIC2)
+  if (rd_flag("nopicadjust"))    nopicadjust = def_int;
+#endif
   if (rd_flag("nopos"))          nopos       = def_int;
   if (rd_flag("noqcheck"))       noqcheck    = def_int;
   if (rd_flag("nostat"))         nostat      = def_int;
   if (rd_flag("ownCmap"))        owncmap     = def_int;
   if (rd_flag("perfect"))        perfect     = def_int;
+#ifdef HAVE_PIC2
+  if (rd_flag("pic2split"))      pic2split   = def_int;
+#endif
   if (rd_flag("popupKludge"))    winCtrPosKludge = def_int;
   if (rd_str ("print"))          strncpy(printCmd, def_str,
 					 (size_t) PRINTCMDLEN);
@@ -1138,6 +1338,9 @@
   if (rd_str ("textviewGeometry")) textgeom  = def_str;
   if (rd_flag("useStdCmap"))     stdcmap     = def_int;
   if (rd_str ("visual"))         visualstr   = def_str;
+#ifdef VS_ADJUST
+  if (rd_flag("vsadjust"))       vsadjust    = def_int;
+#endif
   if (rd_flag("vsDisable"))      novbrowse   = def_int;
   if (rd_str ("vsGeometry"))     browgeom    = def_str;
   if (rd_flag("vsMap"))          browmap     = def_int;
@@ -1172,7 +1375,13 @@
       }
 
       if (numnames<MAXNAMES) {
+#ifdef AUTO_EXPAND
+	if(Isarchive(argv[i]) == 0){ /* Not archive file */
+	  namelist[numnames++] = argv[i];
+	}
+#else
 	namelist[numnames++] = argv[i];
+#endif
 	if (numnames==MAXNAMES) {
 	  fprintf(stderr,"%s: too many filenames.  Only using first %d.\n",
 		  cmd, MAXNAMES);
@@ -1198,6 +1407,14 @@
       }
     }
 
+    else if (!argcmp(argv[i],"-windowid",3,0,&pm)) {
+      if (++i<argc) {
+	if (sscanf(argv[i], "%ld", &spec_window) != 1) {
+		fprintf(stderr,"%s: bad argument to -windowid '%s'\n",cmd,argv[i]);
+        }
+      }
+    }
+
     else if (!argcmp(argv[i],"-best24",3,0,&pm))          /* -best */
       conv24 = CONV24_BEST;
 
@@ -1289,7 +1506,11 @@
     else if (!argcmp(argv[i],"-fg",3,0,&pm))              /* fg color */
       { if (++i<argc) fgstr = argv[i]; }
 
-    else if (!argcmp(argv[i],"-fixed",3,1,&fixedaspect)); /* fix asp. ratio */
+    else if (!argcmp(argv[i],"-fixed",5,1,&fixedaspect)); /* fix asp. ratio */
+
+#ifdef ENABLE_FIXPIX_SMOOTH
+    else if (!argcmp(argv[i],"-fixpix",5,1,&do_fixpix_smooth)); /* dithering */
+#endif
 
     else if (!argcmp(argv[i],"-flist",3,0,&pm))           /* file list */
       { if (++i<argc) flistName = argv[i]; }
@@ -1330,6 +1551,10 @@
       { if (++i<argc) infogeom = argv[i]; }
 
     else if (!argcmp(argv[i],"-imap",     3,1,&imap));        /* imap */
+
+    else if (!argcmp(argv[i],"-ibg",3,0,&pm)) /* GRR: image background color */
+      { if (++i<argc) imagebgstr = argv[i]; }
+
     else if (!argcmp(argv[i],"-lbrowse",  3,1,&browseMode));  /* browse mode */
 
     else if (!argcmp(argv[i],"-lo",3,0,&pm))	        /* lowlight */
@@ -1354,9 +1579,17 @@
     else if (!argcmp(argv[i],"-maxpect",5,1,&pm))       /* auto maximize */
       { automax=pm; fixedaspect=pm; }
 
+#ifdef MACBINARY
+    else if (!argcmp(argv[i],"-macbinary",3,1,&handlemacb)); /* macbinary */
+#endif
+
     else if (!argcmp(argv[i],"-mfn",3,0,&pm))           /* mono font name */
       { if (++i<argc) monofontname = argv[i]; }
 
+#ifdef HAVE_MGCSFX
+    else if (!argcmp(argv[i],"-mgcsfx", 4,1,&mgcsfx));  /* mgcsfx */
+#endif
+
     else if (!argcmp(argv[i],"-mono",3,1,&mono));	/* mono */
 
     else if (!argcmp(argv[i],"-name",3,0,&pm))          /* name */
@@ -1365,17 +1598,30 @@
     else if (!argcmp(argv[i],"-ncols",3,0,&pm))        /* ncols */
       { if (++i<argc) ncols=abs(atoi(argv[i])); }
 
-    else if (!argcmp(argv[i],"-ninstall",  3,1,&ninstall));   /* inst cmaps?*/
+    else if (!argcmp(argv[i],"-ninstall",  3,1,&ninstall));   /* inst cmaps? */
     else if (!argcmp(argv[i],"-nodecor",   4,1,&nodecor));
     else if (!argcmp(argv[i],"-nofreecols",4,1,&noFreeCols));
     else if (!argcmp(argv[i],"-nolimits",  4,1,&nolimits));   /* nolimits */
+#ifdef HAVE_MGCSFX
+    else if (!argcmp(argv[i],"-nomgcsfx", 4,1,&nomgcsfx));    /* nomgcsfx */
+#endif
+#if defined(HAVE_PIC) || defined(HAVE_PIC2)
+    else if (!argcmp(argv[i],"-nopicadjust", 4,1,&nopicadjust));/*nopicadjust*/
+#endif
     else if (!argcmp(argv[i],"-nopos",     4,1,&nopos));      /* nopos */
     else if (!argcmp(argv[i],"-noqcheck",  4,1,&noqcheck));   /* noqcheck */
-    else if (!argcmp(argv[i],"-noresetroot",5,1,&resetroot)); /* reset root*/
+    else if (!argcmp(argv[i],"-noresetroot",5,1,&resetroot)); /* reset root */
     else if (!argcmp(argv[i],"-norm",      5,1,&autonorm));   /* norm */
     else if (!argcmp(argv[i],"-nostat",    4,1,&nostat));     /* nostat */
     else if (!argcmp(argv[i],"-owncmap",   2,1,&owncmap));    /* own cmap */
+#ifdef HAVE_PCD
+    else if (!argcmp(argv[i],"-pcd",       4,0,&pm))         /* pcd with size */
+      { if (i+1<argc) PcdSize = atoi(argv[++i]); }
+#endif
     else if (!argcmp(argv[i],"-perfect",   3,1,&perfect));    /* -perfect */
+#ifdef HAVE_PIC2
+    else if (!argcmp(argv[i],"-pic2split", 3,1,&pic2split));  /* pic2split */
+#endif
     else if (!argcmp(argv[i],"-pkludge",   3,1,&winCtrPosKludge));
     else if (!argcmp(argv[i],"-poll",      3,1,&polling));    /* chk mod? */
 
@@ -1418,6 +1664,7 @@
       conv24 = CONV24_SLOW;
 
     else if (!argcmp(argv[i],"-smooth",3,1,&autosmooth));  /* autosmooth */
+    else if (!argcmp(argv[i],"-startgrab",3,1,&startGrab)); /* startGrab */
     else if (!argcmp(argv[i],"-stdcmap",3,1,&stdcmap));    /* use stdcmap */
 
     else if (!argcmp(argv[i],"-tgeometry",2,0,&pm))	   /* textview geom */
@@ -1429,6 +1676,10 @@
     else if (!argcmp(argv[i],"-visual",4,0,&pm))           /* visual */
       { if (++i<argc) visualstr = argv[i]; }
 
+#ifdef VS_ADJUST
+    else if (!argcmp(argv[i],"-vsadjust", 3,1,&vsadjust));  /* vsadjust */
+#endif
+
     else if (!argcmp(argv[i],"-vsdisable",4,1,&novbrowse)); /* disable sch? */
 
     else if (!argcmp(argv[i],"-vsgeometry",4,0,&pm))	/* visSchnauzer geom */
@@ -1440,8 +1691,9 @@
 
     else if (!argcmp(argv[i],"-wait",3,0,&pm)) {        /* secs betwn pics */
       if (++i<argc) {
-	waitsec = abs(atoi(argv[i]));
-	if (waitsec<0) waitsec = 0;
+	char *comma = strchr(argv[i], ',');
+	waitsec_nonfinal = fabs(atof(argv[i]));
+	waitsec_final = comma? fabs(atof(comma+1)) : waitsec_nonfinal;
       }
     }
 
@@ -1467,7 +1719,11 @@
   /* check options for validity */
 
   if (strlen(searchdir)) {  /* got a search directory */
+#ifdef AUTO_EXPAND
+    if (Chvdir(searchdir)) {
+#else
     if (chdir(searchdir)) {
+#endif
       fprintf(stderr,"xv: unable to cd to directory '%s'.\n",searchdir);
       fprintf(stderr,
        "    Ignoring '-dir' option and/or 'xv.searchDirectory' resource\n");
@@ -1514,7 +1770,7 @@
     preset = 0;
   }
 
-  if (waitsec < 0) noFreeCols = 0;   /* disallow nfc if not doing slideshow */
+  if (waitsec < 0.0) noFreeCols = 0;   /* disallow nfc if not doing slideshow */
   if (noFreeCols && perfect) { perfect = 0;  owncmap = 1; }
 
   /* decide what default color allocation stuff we've settled on */
@@ -1556,6 +1812,20 @@
 
 static void cmdSyntax()
 {
+  /* GRR 19980605:  added version info for most common libraries */
+  fprintf(stderr, "XV - %s.\n", REVDATE);
+#ifdef HAVE_JPEG
+  VersionInfoJPEG();
+#endif
+#ifdef HAVE_TIFF
+  VersionInfoTIFF();
+#endif
+#ifdef HAVE_PNG
+  VersionInfoPNG();
+#endif
+  /* pbm/pgm/ppm support is native, not via pbmplus/netpbm libraries */
+  fprintf(stderr, "\n");
+
   fprintf(stderr, "Usage:\n");
   printoption(cmd);
   printoption("[-]");
@@ -1595,6 +1865,9 @@
   printoption("[-expand exp | hexp:vexp]");
   printoption("[-fg color]");
   printoption("[-/+fixed]");
+#ifdef ENABLE_FIXPIX_SMOOTH
+  printoption("[-/+fixpix]");
+#endif
   printoption("[-flist fname]");
   printoption("[-gamma val]");
   printoption("[-geometry geom]");
@@ -1607,6 +1880,7 @@
   printoption("[-hi color]");
   printoption("[-/+hist]");
   printoption("[-/+hsv]");
+  printoption("[-ibg color]");  /* GRR 19980314 */
   printoption("[-icgeometry geom]");
   printoption("[-/+iconic]");
   printoption("[-igeometry geom]");
@@ -1614,9 +1888,15 @@
   printoption("[-/+lbrowse]");
   printoption("[-lo color]");
   printoption("[-/+loadclear]");
+#ifdef MACBINARY
+  printoption("[-/+macbinary]");
+#endif
   printoption("[-/+max]");
   printoption("[-/+maxpect]");
   printoption("[-mfn font]");
+#ifdef HAVE_MGCSFX
+  printoption("[-/+mgcsfx]");
+#endif
   printoption("[-/+mono]");
   printoption("[-name str]");
   printoption("[-ncols #]");
@@ -1624,13 +1904,25 @@
   printoption("[-/+nodecor]");
   printoption("[-/+nofreecols]");
   printoption("[-/+nolimits]");
+#ifdef HAVE_MGCSFX
+  printoption("[-/+nomgcsfx]");
+#endif
+#if defined(HAVE_PIC) || defined(HAVE_PIC2)
+  printoption("[-/+nopicadjust]");
+#endif
   printoption("[-/+nopos]");
   printoption("[-/+noqcheck]");
   printoption("[-/+noresetroot]");
   printoption("[-/+norm]");
   printoption("[-/+nostat]");
   printoption("[-/+owncmap]");
+#ifdef HAVE_PCD
+  printoption("[-pcd size(0=192*128,1,2,3,4=3072*2048)]");
+#endif
   printoption("[-/+perfect]");
+#ifdef HAVE_PIC2
+  printoption("[-/+pic2split]");
+#endif
   printoption("[-/+pkludge]");
   printoption("[-/+poll]");
   printoption("[-preset #]");
@@ -1649,17 +1941,22 @@
   printoption("[-/+rw]");
   printoption("[-slow24]");
   printoption("[-/+smooth]");
+  printoption("[-/+startgrab]");
   printoption("[-/+stdcmap]");
   printoption("[-tgeometry geom]");
   printoption("[-/+vflip]");
   printoption("[-/+viewonly]");
   printoption("[-visual type]");
+#ifdef VS_ADJUST
+  printoption("[-/+vsadjust]");
+#endif
   printoption("[-/+vsdisable]");
   printoption("[-vsgeometry geom]");
   printoption("[-/+vsmap]");
   printoption("[-/+vsperfect]");
-  printoption("[-wait seconds]");
+  printoption("[-wait secs[,final_secs]]");
   printoption("[-white color]");
+  printoption("[-windowid windowid]");
   printoption("[-/+wloop]");
   printoption("[filename ...]");
   fprintf(stderr,"\n\n");
@@ -1682,6 +1979,7 @@
   fprintf(stderr,"\t7: centered on a 'brick' background\n");
   fprintf(stderr,"\t8: symmetrical tiling\n");
   fprintf(stderr,"\t9: symmetrical mirrored tiling\n");
+  fprintf(stderr,"\t10: upper left corner\n");
   fprintf(stderr,"\n");
   Quit(1);
 }
@@ -1694,7 +1992,7 @@
      int *plusminus;
 {
   /* does a string compare between a1 and a2.  To return '0', a1 and a2
-     must match to the length of a2, and that length has to
+     must match to the length of a1, and that length has to
      be at least 'minlen'.  Otherwise, return non-zero.  plusminus set to '1'
      if '-option', '0' if '+option' */
 
@@ -1734,6 +2032,10 @@
   char *tmp;
   char *fullname,       /* full name of the original file */
         filename[512];  /* full name of file to load (could be /tmp/xxx)*/
+#ifdef MACBINARY
+  char origname[512];	/* file name of original file (NO processing) */
+  origname[0] = '\0';
+#endif
 
   xvbzero((char *) &pinfo, sizeof(PICINFO));
 
@@ -1866,8 +2168,22 @@
       frompipe = 1;
     }
   }
+#ifdef AUTO_EXPAND
+  else {
+    fullname = (char *) malloc(MAXPATHLEN+2);
+    strcpy(fullname, namelist[filenum]);
+    freename = 1;
+  }
+  tmp = (char *) rindex(fullname, '/');
+  if (tmp) {
+      *tmp = '\0';
+      Mkvdir(fullname);
+      *tmp = '/';
+  }
+  Dirtovd(fullname);
+#else
   else fullname = namelist[filenum];
-
+#endif
 
   strcpy(fullfname, fullname);
   tmp = BaseName(fullname);
@@ -1875,18 +2191,20 @@
 
 
   /* chop off trailing ".Z", ".z", or ".gz" from displayed basefname, if any */
-  if (strlen(basefname) > (size_t) 2     &&
-      strcmp(basefname+strlen(basefname)-2,".Z")==0)
+  if (strlen(basefname)>2 && strcmp(basefname+strlen(basefname)-2,".Z")==0)
     basefname[strlen(basefname)-2]='\0';
   else {
 #ifdef GUNZIP
-    if (strlen(basefname)>2 && strcmp(basefname+strlen(basefname)-2,".Z")==0)
+    if (strlen(basefname)>2 && strcmp(basefname+strlen(basefname)-2,".z")==0)
       basefname[strlen(basefname)-2]='\0';
-
-    else if (strlen(basefname)>3 &&
-	     strcmp(basefname+strlen(basefname)-3,".gz")==0)
+    else
+    if (strlen(basefname)>3 && strcmp(basefname+strlen(basefname)-3,".gz")==0)
       basefname[strlen(basefname)-3]='\0';
-#endif /* GUNZIP */
+#endif
+#ifdef BUNZIP2
+    if (strlen(basefname)>4 && strcmp(basefname+strlen(basefname)-4,".bz2")==0)
+      basefname[strlen(basefname)-4]='\0';
+#endif
   }
 
 
@@ -1973,6 +2291,9 @@
 
     if (strcmp(filename,STDINSTR)==0) {
       FILE *fp = NULL;
+#ifndef USE_MKSTEMP
+      int tmpfd;
+#endif
 
 #ifndef VMS
       sprintf(filename,"%s/xvXXXXXX",tmpdir);
@@ -1984,13 +2305,18 @@
       fp = fdopen(mkstemp(filename), "w");
 #else
       mktemp(filename);
-      fp = fopen(filename, "w");
+      tmpfd = open(filename,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR);
+      if (tmpfd < 0) FatalError("openPic(): can't create temporary file");
+      fp = fdopen(tmpfd,"w");
 #endif
       if (!fp) FatalError("openPic(): can't write temporary file");
 
       clearerr(stdin);
       while ( (i=getchar()) != EOF) putc(i,fp);
       fclose(fp);
+#ifndef USE_MKSTEMP
+      close(tmpfd);
+#endif
 
       /* and remove it from list, since we can never reload from stdin */
       if (strcmp(namelist[0], STDINSTR)==0) deleteFromList(0);
@@ -2005,15 +2331,21 @@
     (no pipes or stdin, though it could be compressed) to be loaded */
   filetype = ReadFileType(filename);
 
+#ifdef HAVE_MGCSFX
+  if (mgcsfx && filetype == RFT_UNKNOWN){ /* force use MgcSfx */
+    if(getInputCom() != 0) filetype = RFT_MGCSFX;
+  }
+#endif
 
-  if (filetype == RFT_COMPRESS) {   /* a compressed file.  uncompress it */
+  /* if it's a compressed file, uncompress it: */
+  if ((filetype == RFT_COMPRESS) || (filetype == RFT_BZIP2)) {
     char tmpname[128];
 
     if (
 #ifndef VMS
-	UncompressFile(filename, tmpname)
+	UncompressFile(filename, tmpname, filetype)
 #else
-	UncompressFile(basefname, tmpname)
+	UncompressFile(basefname, tmpname, filetype)
 #endif
 	) {
 
@@ -2029,6 +2361,57 @@
     WaitCursor();
   }
 
+#ifdef MACBINARY
+  if (handlemacb && macb_file == True) {
+    char tmpname[128];
+
+    if (RemoveMacbinary(filename, tmpname)) {
+      if (strcmp(fullname,filename)!=0) unlink(filename);
+      strcpy(origname, filename);
+      strcpy(filename, tmpname);
+    }
+    else filetype = RFT_ERROR;
+
+    WaitCursor();
+  }
+#endif
+
+#ifdef HAVE_MGCSFX_AUTO
+  if (filetype == RFT_MGCSFX) {
+      char tmpname[128], tmp[256];
+      char *icom;
+
+      if ((icom = mgcsfx_auto_input_com(filename)) != NULL) {
+	sprintf(tmpname, "%s/xvmsautoXXXXXX", tmpdir);
+#ifdef USE_MKSTEMP
+	close(mkstemp(tmpname));
+#else
+	mktemp(tmpname);
+#endif
+	SetISTR(ISTR_INFO, "Converting to known format by MgcSfx auto...");
+	sprintf(tmp,"%s >%s", icom, tmpname);
+      }
+      else goto ms_auto_no;
+
+#ifndef VMS
+      if (system(tmp))
+#else
+      if (!system(tmp))
+#endif
+      {
+	SetISTR(ISTR_INFO, "Unable to convert '%s' by MgcSfx auto.",
+	  BaseName(filename));
+	Warning();
+	filetype = RFT_ERROR;
+	goto ms_auto_no;
+      }
+
+      filetype = ReadFileType(tmpname);
+      if (strcmp(fullname,filename)!=0) unlink(filename);
+      strcpy(filename, tmpname);
+  }
+ms_auto_no:
+#endif /* HAVE_MGCSFX_AUTO */
 
   if (filetype == RFT_ERROR) {
     char  foostr[512];
@@ -2042,10 +2425,16 @@
 
   if (filetype == RFT_UNKNOWN) {
     /* view as a text/hex file */
-    TextView(filename);
+#ifdef MACBINARY
+    if (origname[0])
+      i = TextView(origname);
+    else
+#endif
+      i = TextView(filename);
     SetISTR(ISTR_INFO,"'%s' not in a recognized format.", basefname);
     /* Warning();  */
-    goto SHOWN_AS_TEXT;
+    if (i) goto SHOWN_AS_TEXT;
+    else   goto FAILED;
   }
 
   if (filetype < RFT_ERROR) {
@@ -2073,8 +2462,9 @@
   if (filetype == RFT_XBM && (!i || pinfo.w==0 || pinfo.h==0)) {
     /* probably just a '.h' file or something... */
     SetISTR(ISTR_INFO," ");
-    TextView(filename);
-    goto SHOWN_AS_TEXT;
+    i = TextView(filename);
+    if (i) goto SHOWN_AS_TEXT;
+    else   goto FAILED;
   }
 
   if (!i) {
@@ -2209,12 +2599,15 @@
   if (fullname && strcmp(fullname,filename)!=0) unlink(filename);
 
 
-  SetISTR(ISTR_INFO,formatStr);
+  SetISTR(ISTR_INFO, "%s", formatStr);
 
   SetInfoMode(INF_PART);
-  SetISTR(ISTR_FILENAME, "%s",
-	  (filenum==DFLTPIC || filenum==GRABBED || frompipe) ?
-	  "<none>" : basefname);
+  if (filenum==DFLTPIC || filenum==GRABBED || frompipe)
+    SetISTR(ISTR_FILENAME, "<none>");
+  else if (numPages > 1)
+    SetISTR(ISTR_FILENAME, "%s  Page %d of %d", basefname, curPage+1, numPages);
+  else
+    SetISTR(ISTR_FILENAME, "%s", basefname);
 
   SetISTR(ISTR_RES,"%d x %d",pWIDE,pHIGH);
   SetISTR(ISTR_COLOR, "");
@@ -2424,7 +2817,7 @@
     if (autodither && ncols>0) epicMode = EM_DITH;
 
     /* if in CM_STDCMAP mode, and *not* in '-wait 0', then autodither */
-    if (colorMapMode == CM_STDCMAP && waitsec != 0) epicMode = EM_DITH;
+    if (colorMapMode == CM_STDCMAP && waitsec != 0.0) epicMode = EM_DITH;
 
     /* if -smooth or image has been shrunk to fit screen */
     if (autosmooth || (pWIDE >maxWIDE || pHIGH>maxHIGH)
@@ -2510,7 +2903,11 @@
      to generate the correct exposes (particularly with 'BitGravity' turned
      on */
 
-  if (mainW && !useroot) GenExpose(mainW, 0, 0, (u_int) eWIDE, (u_int) eHIGH);
+  /*Brian T. Schellenberger: fix for X 4.2 refresh problem*/
+  if (mainW && !useroot) {
+    XSync(theDisp, False);
+    GenExpose(mainW, 0, 0, (u_int) eWIDE, (u_int) eHIGH);
+  }
 
   return 1;
 
@@ -2542,6 +2939,9 @@
 }
 
 
+extern byte ZXheader[128];	/* [JCE] Spectrum screen magic number is
+                                  defined in xvzx.c */
+
 
 /********************************/
 int ReadFileType(fname)
@@ -2554,76 +2954,105 @@
 
   FILE *fp;
   byte  magicno[30];    /* first 30 bytes of file */
-  int   rv, n;
+  int   rv=RFT_UNKNOWN, n;
+#ifdef MACBINARY
+  int macbin_alrchk = False;
+#endif
 
   if (!fname) return RFT_ERROR;   /* shouldn't happen */
 
   fp = xv_fopen(fname, "r");
   if (!fp) return RFT_ERROR;
 
+  if (strlen(fname) > 4 &&
+      strcasecmp(fname+strlen(fname)-5, ".wbmp")==0)          rv = RFT_WBMP;
+
   n = fread(magicno, (size_t) 1, (size_t) 30, fp);
   fclose(fp);
 
-  if (n<30) return RFT_UNKNOWN;    /* files less than 30 bytes long... */
+  if (n<30) return rv;    /* files less than 30 bytes long... */
 
-  rv = RFT_UNKNOWN;
+#ifdef MACBINARY
+  macb_file = False;
+  while (1) {
+#endif
 
-  if (strncmp((char *) magicno,"GIF87a", (size_t) 6)==0 ||
-      strncmp((char *) magicno,"GIF89a", (size_t) 6)==0)        rv = RFT_GIF;
+#ifdef HAVE_MGCSFX
+  if (is_mgcsfx(fname, magicno, 30) != 0) rv = RFT_MGCSFX;
+  else
+#endif
+       if (strncmp((char *) magicno,"GIF87a", (size_t) 6)==0 ||
+	   strncmp((char *) magicno,"GIF89a", (size_t) 6)==0) rv = RFT_GIF;
 
   else if (strncmp((char *) magicno,"VIEW", (size_t) 4)==0 ||
-	   strncmp((char *) magicno,"WEIV", (size_t) 4)==0)     rv = RFT_PM;
+	   strncmp((char *) magicno,"WEIV", (size_t) 4)==0)   rv = RFT_PM;
+
+#ifdef HAVE_PIC2
+  else if (magicno[0]=='P' && magicno[1]=='2' &&
+	   magicno[2]=='D' && magicno[3]=='T')                rv = RFT_PIC2;
+#endif
 
   else if (magicno[0] == 'P' && magicno[1]>='1' &&
-	   magicno[1]<='6')                             rv = RFT_PBM;
+	   (magicno[1]<='6' || magicno[1]=='8'))              rv = RFT_PBM;
 
   /* note: have to check XPM before XBM, as first 2 chars are the same */
   else if (strncmp((char *) magicno, "/* XPM */", (size_t) 9)==0) rv = RFT_XPM;
 
   else if (strncmp((char *) magicno,"#define", (size_t) 7)==0 ||
-	   (magicno[0] == '/' && magicno[1] == '*'))    rv = RFT_XBM;
+	   (magicno[0] == '/' && magicno[1] == '*'))          rv = RFT_XBM;
 
   else if (magicno[0]==0x59 && (magicno[1]&0x7f)==0x26 &&
-	   magicno[2]==0x6a && (magicno[3]&0x7f)==0x15) rv = RFT_SUNRAS;
+	   magicno[2]==0x6a && (magicno[3]&0x7f)==0x15)       rv = RFT_SUNRAS;
 
-  else if (magicno[0] == 'B' && magicno[1] == 'M')      rv = RFT_BMP;
+  else if (magicno[0] == 'B' && magicno[1] == 'M')            rv = RFT_BMP;
 
-  else if (magicno[0]==0x52 && magicno[1]==0xcc)        rv = RFT_UTAHRLE;
+  else if (magicno[0]==0x52 && magicno[1]==0xcc)              rv = RFT_UTAHRLE;
 
   else if ((magicno[0]==0x01 && magicno[1]==0xda) ||
-	   (magicno[0]==0xda && magicno[1]==0x01))      rv = RFT_IRIS;
+	   (magicno[0]==0xda && magicno[1]==0x01))            rv = RFT_IRIS;
 
-  else if (magicno[0]==0x1f && magicno[1]==0x9d)        rv = RFT_COMPRESS;
+  else if (magicno[0]==0x1f && magicno[1]==0x9d)              rv = RFT_COMPRESS;
 
 #ifdef GUNZIP
-  else if (magicno[0]==0x1f && magicno[1]==0x8b)        rv = RFT_COMPRESS;
+  else if (magicno[0]==0x1f && magicno[1]==0x8b)              rv = RFT_COMPRESS;
 #endif
 
-  else if (magicno[0]==0x0a && magicno[1] <= 5)         rv = RFT_PCX;
+#ifdef BUNZIP2
+  else if (magicno[0]==0x42 && magicno[1]==0x5a)              rv = RFT_BZIP2;
+#endif
+
+  else if (magicno[0]==0x0a && magicno[1] <= 5)               rv = RFT_PCX;
 
   else if (strncmp((char *) magicno,   "FORM", (size_t) 4)==0 &&
-	   strncmp((char *) magicno+8, "ILBM", (size_t) 4)==0)   rv = RFT_IFF;
+	   strncmp((char *) magicno+8, "ILBM", (size_t) 4)==0) rv = RFT_IFF;
 
   else if (magicno[0]==0 && magicno[1]==0 &&
 	   magicno[2]==2 && magicno[3]==0 &&
 	   magicno[4]==0 && magicno[5]==0 &&
-	   magicno[6]==0 && magicno[7]==0)              rv = RFT_TARGA;
+	   magicno[6]==0 && magicno[7]==0)                    rv = RFT_TARGA;
 
   else if (magicno[4]==0x00 && magicno[5]==0x00 &&
-	   magicno[6]==0x00 && magicno[7]==0x07)        rv = RFT_XWD;
+	   magicno[6]==0x00 && magicno[7]==0x07)              rv = RFT_XWD;
 
   else if (strncmp((char *) magicno,"SIMPLE  ", (size_t) 8)==0 &&
-	   magicno[29] == 'T')                          rv = RFT_FITS;
+	   magicno[29] == 'T')                                rv = RFT_FITS;
 
+  /* [JCE] Spectrum screen */
+  else if (memcmp(magicno, ZXheader, (size_t) 18)==0)         rv = RFT_ZX;
 
 #ifdef HAVE_JPEG
   else if (magicno[0]==0xff && magicno[1]==0xd8 &&
-	   magicno[2]==0xff)                            rv = RFT_JFIF;
+	   magicno[2]==0xff)                                  rv = RFT_JFIF;
 #endif
 
 #ifdef HAVE_TIFF
   else if ((magicno[0]=='M' && magicno[1]=='M') ||
-	   (magicno[0]=='I' && magicno[1]=='I'))        rv = RFT_TIFF;
+	   (magicno[0]=='I' && magicno[1]=='I'))              rv = RFT_TIFF;
+#endif
+
+#ifdef HAVE_PNG
+  else if (magicno[0]==0x89 && magicno[1]=='P' &&
+           magicno[2]=='N'  && magicno[3]=='G')               rv = RFT_PNG;
 #endif
 
 #ifdef HAVE_PDS
@@ -2635,11 +3064,59 @@
       rv = RFT_PDSVICAR;
 #endif
 
-#ifdef GS_PATH
+#ifdef GS_PATH   /* Ghostscript handles both PostScript and PDF */
   else if (strncmp((char *) magicno, "%!",     (size_t) 2)==0 ||
-	   strncmp((char *) magicno, "\004%!", (size_t) 3)==0)   rv = RFT_PS;
+	   strncmp((char *) magicno, "\004%!", (size_t) 3)==0 ||
+           strncmp((char *) magicno, "%PDF",   (size_t) 4)==0) rv = RFT_PS;
 #endif
 
+#ifdef HAVE_MAG
+  else if (strncmp((char *) magicno,"MAKI02  ", (size_t) 8)==0) rv = RFT_MAG;
+#endif
+
+#ifdef HAVE_MAKI
+  else if (strncmp((char *) magicno,"MAKI01A ", (size_t) 8)==0 ||
+	   strncmp((char *) magicno,"MAKI01B ", (size_t) 8)==0) rv = RFT_MAKI;
+#endif
+
+#ifdef HAVE_PIC
+  else if (magicno[0]=='P' && magicno[1]=='I'&&magicno[2]=='C') rv = RFT_PIC;
+#endif
+
+#ifdef HAVE_PI
+  else if (magicno[0]=='P' && magicno[1]=='i')                rv = RFT_PI;
+#endif
+
+#ifdef HAVE_HIPS
+  else if (strstr((char *) magicno, "./digest"))              rv = RFT_HIPS;
+#endif
+
+#ifdef HAVE_PCD
+  else if (magicno[0]==0xff && magicno[1]==0xff &&
+           magicno[2]==0xff && magicno[3]==0xff)              rv = RFT_PCD;
+#endif
+
+#ifdef MACBINARY
+    /* Now we try to handle MacBinary files, but the method is VERY dirty... */
+    if (macbin_alrchk == True) {
+      macb_file = True;
+      break;
+    }
+
+    if (rv != RFT_UNKNOWN)
+      break;
+
+    /* Skip MACBSIZE and recheck */
+    macbin_alrchk = True;
+    fp = xv_fopen(fname, "r");
+    if (!fp) return RFT_ERROR;
+    fseek(fp, MACBSIZE, SEEK_SET);
+    n = fread(magicno, (size_t) 1, (size_t) 30, fp);
+    fclose(fp);
+
+    if (n<30) return RFT_UNKNOWN;    /* files less than 30 bytes long... */
+  }
+#endif
   return rv;
 }
 
@@ -2652,9 +3129,10 @@
      PICINFO *pinfo;
 {
   /* if quick is set, we're being called to generate icons, or something
-     like that.  We should load the image as quickly as possible.  Currently,
-     this only affects the LoadPS routine, which, if quick is set, only
-     generates the page file for the first page of the document */
+     like that.  We should load the image as quickly as possible.  Previously,
+     this affected only the LoadPS routine, which, if quick is set, only
+     generates the page file for the first page of the document.  Now it
+     also affects PCD, which loads only a thumbnail. */
 
   int rv = 0;
 
@@ -2665,7 +3143,11 @@
   switch (ftype) {
   case RFT_GIF:     rv = LoadGIF   (fname, pinfo);         break;
   case RFT_PM:      rv = LoadPM    (fname, pinfo);         break;
+#ifdef HAVE_MGCSFX
+  case RFT_PBM:     rv = LoadPBM   (fname, pinfo, -1);     break;
+#else
   case RFT_PBM:     rv = LoadPBM   (fname, pinfo);         break;
+#endif
   case RFT_XBM:     rv = LoadXBM   (fname, pinfo);         break;
   case RFT_SUNRAS:  rv = LoadSunRas(fname, pinfo);         break;
   case RFT_BMP:     rv = LoadBMP   (fname, pinfo);         break;
@@ -2677,21 +3159,60 @@
   case RFT_XPM:     rv = LoadXPM   (fname, pinfo);         break;
   case RFT_XWD:     rv = LoadXWD   (fname, pinfo);         break;
   case RFT_FITS:    rv = LoadFITS  (fname, pinfo, quick);  break;
+  case RFT_ZX:      rv = LoadZX    (fname, pinfo);         break; /* [JCE] */
+  case RFT_WBMP:    rv = LoadWBMP  (fname, pinfo);         break;
+
+#ifdef HAVE_PCD
+  /* if quick is switched on, use the smallest image size; don't ask the user */
+  case RFT_PCD:     rv = LoadPCD   (fname, pinfo, quick ? 0 : PcdSize);  break;
+#endif
 
 #ifdef HAVE_JPEG
-  case RFT_JFIF:    rv = LoadJFIF  (fname, pinfo, quick);    break;
+  case RFT_JFIF:    rv = LoadJFIF  (fname, pinfo, quick);  break;
 #endif
 
 #ifdef HAVE_TIFF
-  case RFT_TIFF:    rv = LoadTIFF  (fname, pinfo, quick);    break;
+  case RFT_TIFF:    rv = LoadTIFF  (fname, pinfo, quick);  break;
+#endif
+
+#ifdef HAVE_PNG
+  case RFT_PNG:     rv = LoadPNG   (fname, pinfo);         break;
 #endif
 
 #ifdef HAVE_PDS
-  case RFT_PDSVICAR: rv = LoadPDS  (fname, pinfo);           break;
+  case RFT_PDSVICAR: rv = LoadPDS  (fname, pinfo);         break;
 #endif
 
 #ifdef GS_PATH
-  case RFT_PS:      rv = LoadPS    (fname, pinfo, quick);    break;
+  case RFT_PS:      rv = LoadPS    (fname, pinfo, quick);  break;
+#endif
+
+#ifdef HAVE_MAG
+  case RFT_MAG:     rv = LoadMAG   (fname, pinfo);         break;
+#endif
+
+#ifdef HAVE_MAKI
+  case RFT_MAKI:    rv = LoadMAKI  (fname, pinfo);         break;
+#endif
+
+#ifdef HAVE_PIC
+  case RFT_PIC:     rv = LoadPIC   (fname, pinfo);         break;
+#endif
+
+#ifdef HAVE_PI
+  case RFT_PI:      rv = LoadPi    (fname, pinfo);         break;
+#endif
+
+#ifdef HAVE_PIC2
+  case RFT_PIC2:    rv = LoadPIC2  (fname, pinfo, quick);  break;
+#endif
+
+#ifdef HAVE_HIPS
+  case RFT_HIPS:    rv = LoadHIPS  (fname, pinfo);         break;
+#endif
+
+#ifdef HAVE_MGCSFX
+  case RFT_MGCSFX:  rv = LoadMGCSFX (fname, pinfo);        break;
 #endif
 
   }
@@ -2700,13 +3221,17 @@
 
 
 /********************************/
-int UncompressFile(name, uncompname)
+int UncompressFile(name, uncompname, filetype)
      char *name, *uncompname;
+     int filetype;
 {
   /* returns '1' on success, with name of uncompressed file in uncompname
      returns '0' on failure */
 
   char namez[128], *fname, buf[512];
+#ifndef USE_MKSTEMP
+  int tmpfd;
+#endif
 
   fname = name;
   namez[0] = '\0';
@@ -2746,15 +3271,23 @@
   close(mkstemp(uncompname));
 #else
   mktemp(uncompname);
+  tmpfd = open(uncompname,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR);
+  if (tmpfd < 0) FatalError("UncompressFile(): can't create temporary file");
+  close(tmpfd);
 #endif
 
 #ifndef VMS
-  sprintf(buf,"%s -c %s >%s", UNCOMPRESS, fname, uncompname);
+  if (filetype == RFT_COMPRESS)
+    sprintf(buf,"%s -c '%s' > '%s'", UNCOMPRESS, fname, uncompname);
+# ifdef BUNZIP2
+  else if (filetype == RFT_BZIP2)
+    sprintf(buf,"%s -c '%s' > '%s'", BUNZIP2, fname, uncompname);
+# endif
 #else /* it IS VMS */
 # ifdef GUNZIP
-  sprintf(buf,"%s %s %s", UNCOMPRESS, fname, uncompname);
+  sprintf(buf,"%s '%s' '%s'", UNCOMPRESS, fname, uncompname);
 # else
-  sprintf(buf,"%s %s", UNCOMPRESS, fname);
+  sprintf(buf,"%s '%s'", UNCOMPRESS, fname);
 # endif
 #endif
 
@@ -2797,6 +3330,62 @@
 }
 
 
+#ifdef MACBINARY
+/********************************/
+int RemoveMacbinary(src, dst)
+     char *src, *dst;
+{
+  char buffer[8192]; /* XXX */
+  int n, eof;
+#ifndef USE_MKSTEMP
+  int tmpfd;
+#endif
+  FILE *sfp, *dfp;
+
+  sprintf(dst, "%s/xvmXXXXXX", tmpdir);
+#ifdef USE_MKSTEMP
+  close(mkstemp(dst));
+#else
+  mktemp(dst);
+  tmpfd = open(dst,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR);
+  if (tmpfd < 0) FatalError("RemoveMacbinary(): can't create temporary file");
+#endif
+
+  SetISTR(ISTR_INFO, "Removing MacBinary...");
+
+  sfp = xv_fopen(src, "r");
+#ifdef USE_MKSTEMP
+  dfp = xv_fopen(dst, "w");
+#else
+  dfp = fdopen(tmpfd, "w");
+#endif
+  if (!sfp || !dfp) {
+    SetISTR(ISTR_INFO, "Unable to remove a InfoFile header form '%s'.", src);
+    Warning();
+    return 0;
+  }
+  fseek(sfp, MACBSIZE, SEEK_SET);
+  while ((n = fread(buffer, 1, sizeof(buffer), sfp)) == 8192) /* XXX */
+    fwrite(buffer, 1, n, dfp);
+  if ((eof = feof(sfp)))
+    fwrite(buffer, 1, n, dfp);
+  fclose(sfp);
+  fflush(dfp);
+  fclose(dfp);
+#ifndef USE_MKSTEMP
+  close(tmpfd);
+#endif
+  if (!eof) {
+    SetISTR(ISTR_INFO, "Unable to remove a InfoFile header form '%s'.", src);
+    Warning();
+    return 0;
+  }
+
+  return 1;
+}
+#endif
+
+
 /********************************/
 void KillPageFiles(bname, numpages)
   char *bname;
@@ -2918,6 +3507,9 @@
 
   char fullcmd[512], tmpname[64], str[512];
   int i;
+#ifndef USE_MKSTEMP
+  int tmpfd;
+#endif
 
   if (!cmd || (strlen(cmd) < (size_t) 2)) return 1;
 
@@ -2926,6 +3518,9 @@
   close(mkstemp(tmpname));
 #else
   mktemp(tmpname);
+  tmpfd = open(tmpname,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR);
+  if (tmpfd < 0) FatalError("openPic(): can't create temporary file");
+  close(tmpfd);
 #endif
   if (tmpname[0] == '\0') {   /* mktemp() or mkstemp() blew up */
     sprintf(str,"Unable to create temporary filename.");
@@ -2966,26 +3561,21 @@
 {
   int i;
 
+  waitsec = (numnames <= 1)? waitsec_final : waitsec_nonfinal;
+
   if (!numnames) {  openPic(DFLTPIC);  return; }
 
   i = 0;
-  if (!randomShow) {
-    while (numnames>0) {
-      if (openPic(0)) return;  /* success */
-      else {
-	if (polling && !i)
-	  fprintf(stderr,"%s: POLLING: Waiting for file '%s' \n\tto %s\n",
-		  cmd, namelist[0], "be created, or whatever...");
-	i = 1;
-      }
+  while (numnames>0) {
+    if (openPic(0)) return;  /* success */
+    else {
+      if (polling && !i)
+	fprintf(stderr,"%s: POLLING: Waiting for file '%s' \n\tto %s\n",
+		cmd, namelist[0], "be created, or whatever...");
+      i = 1;
     }
   }
 
-  else {    /* pick random first picture */
-    for (i=findRandomPic();  i>=0;  i=findRandomPic())
-      if (openPic(i)) return;    /* success */
-  }
-
   if (numnames>1) FatalError("couldn't open any pictures");
   else Quit(-1);
 }
@@ -3014,19 +3604,15 @@
 {
   int i;
 
-  if (!randomShow) {
-    if (curname>=0) i = curname+1;
-    else if (nList.selected >= 0 && nList.selected < numnames)
-      i = nList.selected;
-    else i = 0;
+  if (curname>=0) i = curname+1;
+  else if (nList.selected >= 0 && nList.selected < numnames)
+    i = nList.selected;
+  else i = 0;
 
-    while (i<numnames && !openPic(i));
-    if (i<numnames) return;    /* success */
-  }
-  else {
-    for (i=findRandomPic(); i>=0; i=findRandomPic())
-      if (openPic(i)) return;
-  }
+  waitsec = (i == numnames-1)? waitsec_final : waitsec_nonfinal;
+
+  while (i<numnames && !openPic(i));
+  if (i<numnames) return;    /* success */
 
   Quit(0);
 }
@@ -3039,25 +3625,21 @@
 
   j = loop = 0;
   while (1) {
-    if (!randomShow) {
 
-      if (curname>=0) i = curname+1;
-      else if (nList.selected >= 0 && nList.selected < numnames)
-	i = nList.selected;
-      else i = 0;
+    if (curname>=0) i = curname+1;
+    else if (nList.selected >= 0 && nList.selected < numnames)
+      i = nList.selected;
+    else i = 0;
 
-      if (loop) {  i = 0;   loop = 0; }
+    if (loop) {  i = 0;   loop = 0; }
 
-      while (i<numnames && !openPic(i));
-      if (i<numnames) return;
-    }
-    else {
-      for (i=findRandomPic(); i>=0; i=findRandomPic())
-	if (openPic(i)) return;
-    }
+    waitsec = (i == numnames-1)? waitsec_final : waitsec_nonfinal;
+
+    while (i<numnames && !openPic(i));
+    if (i<numnames) return;
 
     loop = 1;        /* back to top of list */
-    if (j) break;                         /* we're in a 'failure loop' */
+    if (j) break;    /* we're in a 'failure loop' */
     j++;
   }
 
@@ -3090,47 +3672,6 @@
   openPic(LOADPIC);
 }
 
-
-
-
-/****************/
-static int findRandomPic()
-/****************/
-{
-  static byte *loadList;
-  static int   left_to_load, listLen = -1;
-  int          k;
-  time_t       t;
-
-  /* picks a random name out of the list, and returns it's index.  If there
-     are no more names to pick, it returns '-1' and resets itself */
-
-  if (!loadList || numnames!=listLen) {
-    if (loadList) free(loadList);
-    else {
-      time(&t);
-      srandom((unsigned int) t); /* seed the random */
-    }
-
-    left_to_load = listLen = numnames;
-    loadList = (byte *) malloc((size_t) listLen);
-    for (k=0; k<listLen; k++) loadList[k] = 0;
-  }
-
-  if (left_to_load <= 0) {   /* we've loaded all the pics */
-    for (k=0; k<listLen; k++) loadList[k] = 0;   /* clear flags */
-    left_to_load = listLen;
-    return -1;   /* 'done' return */
-  }
-
-  for (k=abs(random()) % listLen;  loadList[k];  k = (k+1) % listLen);
-
-  left_to_load--;
-  loadList[k] = TRUE;
-
-  return k;
-}
-
 /****************/
 static void mainLoop()
 {
@@ -3144,10 +3685,11 @@
      selected file (or the 0th file, if no selection either), and 'Prev' means
      view the one right before the selected file */
 
-  openFirstPic();   /* find first displayable picture, exit if none */
+  /* find first displayable picture, exit if none */
+  if (!startGrab) openFirstPic();
 
   if (!pic)  {  /* must've opened a text file...  display dflt pic */
-    openPic(DFLTPIC);
+    if (!startGrab) openPic(DFLTPIC);
     if (mainW && !useroot) RaiseTextWindows();
   }
 
@@ -3224,8 +3766,16 @@
   hints.flags = 0;
   if ((i&XValue || i&YValue)) hints.flags = USPosition;
 
-  if (i&XValue && i&XNegative) x = vrWIDE - eWIDE - abs(x);
-  if (i&YValue && i&YNegative) y = vrHIGH - eHIGH - abs(y);
+  hints.win_gravity = NorthWestGravity;
+  if (i&XValue && i&XNegative) {
+    hints.win_gravity = NorthEastGravity;
+    x = vrWIDE - (eWIDE + 2 * bwidth) - abs(x);
+  }
+  if (i&YValue && i&YNegative) {
+    hints.win_gravity = (hints.win_gravity == NorthWestGravity) ?
+      SouthWestGravity : SouthEastGravity;
+    y = vrHIGH - (eHIGH + 2 * bwidth) - abs(y);
+  }
 
   if (x+eWIDE > vrWIDE) x = vrWIDE - eWIDE;   /* keep on screen */
   if (y+eHIGH > vrHIGH) y = vrHIGH - eHIGH;
@@ -3245,7 +3795,7 @@
   hints.x = x;                  hints.y = y;
   hints.width = eWIDE;          hints.height = eHIGH;
   hints.max_width  = maxWIDE;   hints.max_height = maxHIGH;
-  hints.flags |= USSize | PMaxSize;
+  hints.flags |= USSize | PMaxSize | PWinGravity;
 
   xswa.bit_gravity = StaticGravity;
   xswa.background_pixel = bg;
@@ -3294,10 +3844,6 @@
     }
   }
 
-
-  XSetStandardProperties(theDisp,mainW,"","",None,NULL,0,&hints);
-  setWinIconNames(name);
-
   xwmh.input = True;
   xwmh.flags = InputHint;
 
@@ -3322,12 +3868,13 @@
       }
     }
   }
-  XSetWMHints(theDisp, mainW, &xwmh);
 
   classh.res_name = "xv";
   classh.res_class = "XVroot";
-  XSetClassHint(theDisp, mainW, &classh);
 
+  XmbSetWMProperties(theDisp, mainW, NULL, NULL, NULL, 0, &hints, &xwmh,
+                     &classh);
+  setWinIconNames(name);
 
   if (nodecor) {   /* turn of image window decorations (in MWM) */
     Atom mwm_wm_hints;
@@ -4070,16 +4617,30 @@
       unsigned long nitems, nleft;
       byte *data;
 
-      i = XGetWindowProperty(theDisp, RootWindow(theDisp, 0),
-			     resAtom, 0L, 1L, False,
-			     XA_STRING, &actType, &actFormat, &nitems, &nleft,
-			     (unsigned char **) &data);
+      if (spec_window) {
+        i = XGetWindowProperty(theDisp, spec_window,
+			       resAtom, 0L, 1L, False,
+			       XA_STRING, &actType, &actFormat, &nitems, &nleft,
+			       (unsigned char **) &data);
+      } else {
+        i = XGetWindowProperty(theDisp, RootWindow(theDisp, 0),
+			       resAtom, 0L, 1L, False,
+			       XA_STRING, &actType, &actFormat, &nitems, &nleft,
+			       (unsigned char **) &data);
+      }
       if (i==Success && actType==XA_STRING && actFormat==8) {
 	if (nitems>0 && data) XFree(data);
-	i = XGetWindowProperty(theDisp, RootWindow(theDisp, 0), resAtom, 0L,
-			       (long) ((nleft+4+3)/4),
-			       False, XA_STRING, &actType, &actFormat,
-			       &nitems, &nleft, (unsigned char **) &data);
+        if (spec_window) {
+	  i = XGetWindowProperty(theDisp, spec_window, resAtom, 0L,
+			         (long) ((nleft+4+3)/4),
+			         False, XA_STRING, &actType, &actFormat,
+			         &nitems, &nleft, (unsigned char **) &data);
+        } else {
+	  i = XGetWindowProperty(theDisp, RootWindow(theDisp, 0), resAtom, 0L,
+			         (long) ((nleft+4+3)/4),
+			         False, XA_STRING, &actType, &actFormat,
+			         &nitems, &nleft, (unsigned char **) &data);
+        }
 	if (i==Success && actType==XA_STRING && actFormat==8 && data) {
 	  def_resource = XrmGetStringDatabase((char *) data);
 	  XFree(data);
diff -ruN xv-3.10a-bugfixes/xv.h xv-3.10a-enhancements/xv.h
--- xv-3.10a-bugfixes/xv.h	2005-04-10 09:37:18.000000000 -0700
+++ xv-3.10a-enhancements/xv.h	2005-05-01 13:32:10.000000000 -0700
@@ -14,8 +14,9 @@
 /* GRR orig jumbo enhancements patch:	20000220 */
 /* GRR 1st public jumbo F+E patches:	20040531 */
 /* GRR 2nd public jumbo F+E patches:	20050410 */
-#define REVDATE   "version 3.10a-jumboFix of 20050410"
-#define VERSTR    "3.10a-20050410"
+/* GRR 3rd public jumbo F+E patches:	20050501 */
+#define REVDATE   "version 3.10a-jumboFix+Enh of 20050501"
+#define VERSTR    "3.10a-20050501"
 
 /*
  * uncomment the following, and modify for your site, but only if you've
@@ -49,6 +50,10 @@
 /* START OF MACHINE-DEPENDENT CONFIGURATION INFO */
 /*************************************************/
 
+
+#define ENABLE_FIXPIX_SMOOTH	/* GRR 19980607 */
+
+
 /* Things to make xv more likely to just build, without the user tweaking
    the makefile */
 
@@ -67,6 +72,14 @@
 #  define SVR4
 #endif
 
+#if defined(__sony_news) && defined(bsd43) && !defined(__bsd43)
+#  define __bsd43
+#elif defined(__sony_news) && (defined(SYSTYPE_BSD) || defined(__SYSTYPE_BSD)) && !defined(bsd43) && !defined(__bsd43)
+#  define bsd43
+#  define __bsd43
+#endif
+
+#include <signal.h>      /* for interrupt handling */
 
 /* at least on Linux, the following file (1) includes sys/types.h and
  * (2) defines __USE_BSD (which was not defined before here), so __linux__
@@ -78,7 +91,9 @@
 #  ifndef _LINUX_LIMITS_H
 #    include <linux/limits.h>
 #  endif
-#  define USLEEP
+#  ifndef USLEEP
+#    define USLEEP
+#  endif
    /* want only one or the other defined, not both: */
 #  if !defined(BSDTYPES) && !defined(__USE_BSD)
 #    define BSDTYPES
@@ -117,6 +132,16 @@
 #endif
 
 
+#if defined(__sony_news) && defined(__bsd43)
+#  include <unistd.h>
+#endif
+
+
+#if defined(__FreeBSD__)
+#  include <sys/param.h>
+#endif
+
+
 /* include files */
 #include <stdio.h>
 #include <math.h>
@@ -132,9 +157,11 @@
 
 #ifndef VMS
 #  include <errno.h>
-   extern int   errno;             /* SHOULD be in errno.h, but often isn't */
-#  if !defined(__NetBSD__) && !(defined(__linux__) && defined(__USE_BSD))
-     extern char *sys_errlist[];     /* this too... */
+#  ifndef __NetBSD__
+#    if !(defined __GLIBC__ && __GLIBC__ >= 2)
+       extern int   errno;         /* SHOULD be in errno.h, but often isn't */
+       extern char *sys_errlist[]; /* this too... */
+#    endif
 #  endif
 #endif
 
@@ -203,9 +230,10 @@
 #include <X11/Xatom.h>
 #include <X11/Xmd.h>
 
+#ifdef TV_L10N
+#  include <X11/Xlocale.h>
+#endif
 
-#undef SIGCHLD           /* defined in both Xos.h and signal.h */
-#include <signal.h>      /* for interrupt handling */
 
 #include <sys/types.h>
 
@@ -316,7 +344,9 @@
 #  endif
 #endif
 
-
+#ifndef S_IRWUSR
+#  define S_IRWUSR	(S_IRUSR|__S_IWRITE)
+#endif
 
 #ifndef MAXPATHLEN
 #  define MAXPATHLEN 256
@@ -343,13 +373,36 @@
 #endif
 
 
-/* GRR 20040430:  This is new and still only partially implemented.  No doubt
- *                there are many other systems that have mkstemp() (SUSv3),
- *                but let's start small...  */
-#if defined(__linux__) || defined(__OpenBSD__)
-#  define USE_MKSTEMP           /* use 'mkstemp()' instead of 'mktemp()' */
+/* GRR 20040430:  This is new and still not fully deployed.  No doubt there
+ *                are other systems that have mkstemp() (SUSv3); we can add
+ *                them later. */
+#ifndef VMS       /* VMS hates multi-line definitions */
+#  if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
+      defined(__bsdi__)
+#    ifndef USE_MKSTEMP
+#      define USE_MKSTEMP       /* use 'mkstemp()' instead of 'mktemp()' */
+#    endif                      /* >> SECURITY ISSUE << */
+#  endif
+#endif
+
+
+/* GRR 20040503:  This is new and so far tested only under Linux.  But it
+ *                allows -wait to work with subsecond values as long as
+ *                times() exists and clock_t is a long int (latter matters
+ *                only if/when clocks wrap, which for Linux is multiples of
+ *                497.11 days since the last reboot). */
+#if defined(__linux__)
+#  define USE_TICKS             /* use times()/Timer(), not time()/sleep() */
+#  include <limits.h>           /* LONG_MAX (really want CLOCK_T_MAX) */
+#  include <sys/times.h>        /* times() */
+#  ifndef CLK_TCK               /* can be undefined in strict-ANSI mode */
+#    define CLK_TCK CLOCKS_PER_SEC   /* claimed to be same thing in time.h */
+#  endif
 #endif
 
+#if (defined(SYSV) || defined(SVR4) || defined(linux)) && !defined(USE_GETCWD)
+#  define USE_GETCWD
+#endif
 
 /*****************************/
 /* END OF CONFIGURATION INFO */
@@ -363,17 +416,21 @@
 #  define HAVE_TIFF
 #endif
 
+#ifdef DOPNG
+#  define HAVE_PNG
+#endif
+
 #ifdef DOPDS
 #  define HAVE_PDS
 #endif
 
 
 
-#define PROGNAME  "xv"             /* used in resource database */
+#define PROGNAME   "xv"            /* used in resource database */
 
-#define MAXNAMES 4096              /* max # of files in ctrlW list */
+#define MAXNAMES   32768           /* max # of files in ctrlW list */
 
-#define MAXBRWIN   4               /* max # of vis browser windows */
+#define MAXBRWIN   16              /* max # of vis browser windows */
 
 /* strings in the INFOBOX (used in SetISTR and GetISTR) */
 #define NISTR         10    /* number of ISTRs */
@@ -494,24 +551,80 @@
 #define F_TIFINC  0
 #endif
 
+#ifdef HAVE_PNG
+#define F_PNGINC  1
+#else
+#define F_PNGINC  0
+#endif
+
+#ifdef HAVE_MAG
+#  define F_MAGINC  1
+#else
+#  define F_MAGINC  0
+#endif
+
+#ifdef HAVE_PIC
+#  define F_PICINC  1
+#else
+#  define F_PICINC  0
+#endif
+
+#ifdef HAVE_MAKI
+#  define F_MAKINC  1
+#else
+#  define F_MAKINC  0
+#endif
+
+#ifdef HAVE_PI
+#  define F_PAIINC  1
+#else
+#  define F_PAIINC  0
+#endif
+
+#ifdef HAVE_PIC2
+#  define F_PC2INC  1
+#else
+#  define F_PC2INC  0
+#endif
+
+#ifdef HAVE_MGCSFX
+#  define F_MGCSFXINC  1
+#else
+#  define F_MGCSFXINC  0
+#endif
+
+#ifdef MACBINARY
+#  define MACBSIZE 128
+#endif
 
 #define F_GIF         0
 #define F_JPEG      ( 0 + F_JPGINC)
 #define F_TIFF      ( 0 + F_JPGINC + F_TIFINC)
-#define F_PS        ( 1 + F_JPGINC + F_TIFINC)
-#define F_PBMRAW    ( 2 + F_JPGINC + F_TIFINC)
-#define F_PBMASCII  ( 3 + F_JPGINC + F_TIFINC)
-#define F_XBM       ( 4 + F_JPGINC + F_TIFINC)
-#define F_XPM       ( 5 + F_JPGINC + F_TIFINC)
-#define F_BMP       ( 6 + F_JPGINC + F_TIFINC)
-#define F_SUNRAS    ( 7 + F_JPGINC + F_TIFINC)
-#define F_IRIS      ( 8 + F_JPGINC + F_TIFINC)
-#define F_TARGA     ( 9 + F_JPGINC + F_TIFINC)
-#define F_FITS      (10 + F_JPGINC + F_TIFINC)
-#define F_PM        (11 + F_JPGINC + F_TIFINC)
-#define F_DELIM1    (12 + F_JPGINC + F_TIFINC)     /* ----- */
-#define F_FILELIST  (13 + F_JPGINC + F_TIFINC)
-#define F_MAXFMTS   (14 + F_JPGINC + F_TIFINC)     /* 15, normally */
+#define F_PNG       ( 0 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_PS        ( 1 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_PBMRAW    ( 2 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_PBMASCII  ( 3 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_XBM       ( 4 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_XPM       ( 5 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_BMP       ( 6 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_SUNRAS    ( 7 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_IRIS      ( 8 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_TARGA     ( 9 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_FITS      (10 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_PM        (11 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_ZX        (12 + F_JPGINC + F_TIFINC + F_PNGINC)   /* [JCE] */
+#define F_WBMP      (13 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define JP_EXT_F    (F_WBMP)
+#define F_MAG       (JP_EXT_F + F_MAGINC)
+#define F_PIC       (JP_EXT_F + F_MAGINC + F_PICINC)
+#define F_MAKI      (JP_EXT_F + F_MAGINC + F_PICINC + F_MAKINC)
+#define F_PI        (JP_EXT_F + F_MAGINC + F_PICINC + F_MAKINC + F_PAIINC)
+#define F_PIC2      (JP_EXT_F + F_MAGINC + F_PICINC + F_MAKINC + F_PAIINC + F_PC2INC)
+#define F_MGCSFX    (JP_EXT_F + F_MAGINC + F_PICINC + F_MAKINC + F_PAIINC + F_PC2INC + F_MGCSFXINC)
+#define JP_EXT_F_END (F_MGCSFX)
+#define F_DELIM1    (JP_EXT_F_END + 1)   /* ----- */
+#define F_FILELIST  (JP_EXT_F_END + 2)
+#define F_MAXFMTS   (JP_EXT_F_END + 3)   /* 23, normally */
 
 
 
@@ -541,6 +654,19 @@
 #define RFT_XPM      17
 #define RFT_XWD      18
 #define RFT_FITS     19
+#define RFT_PNG      20
+#define RFT_ZX       21    /* [JCE] */
+#define RFT_WBMP     22
+#define RFT_PCD      23
+#define RFT_HIPS     24
+#define RFT_BZIP2    25
+#define JP_EXT_RFT   (RFT_BZIP2)
+#define RFT_MAG      (JP_EXT_RFT + 1)
+#define RFT_MAKI     (JP_EXT_RFT + 2)
+#define RFT_PIC      (JP_EXT_RFT + 3)
+#define RFT_PI       (JP_EXT_RFT + 4)
+#define RFT_PIC2     (JP_EXT_RFT + 5)
+#define RFT_MGCSFX   (JP_EXT_RFT + 6)
 
 /* definitions for page up/down, arrow up/down list control */
 #define LS_PAGEUP   0
@@ -599,7 +725,8 @@
 #define RM_CBRICK  7     /* centered on a 'brick' bg */
 #define RM_ECENTER 8     /* symmetrical tiled */
 #define RM_ECMIRR  9     /* symmetrical mirror tiled */
-#define RM_MAX     RM_ECMIRR
+#define RM_UPLEFT 10     /* just in upper left corner */
+#define RM_MAX     RM_UPLEFT
 
 
 /* values of colorMapMode */
@@ -649,7 +776,8 @@
 #define RMB_CBRICK   8
 #define RMB_ECENTER  9
 #define RMB_ECMIRR   10
-#define RMB_MAX      11
+#define RMB_UPLEFT   11
+#define RMB_MAX      12
 
 
 /* indicies into conv24MB */
@@ -784,9 +912,9 @@
 		 int len;               /* length of major axis */
 		 int vert;              /* true if vertical, else horizontal */
 		 int active;            /* true if scroll bar can do anything*/
-		 int min,max;           /* min/max values 'pos' can take */
-		 int val;               /* 'value' of scrollbar */
-		 int page;              /* amt val change on pageup/pagedown */
+		 double min,max;        /* min/max values 'pos' can take */
+		 double val;            /* 'value' of scrollbar */
+		 double page;           /* amt val change on pageup/pagedown */
 		 int tpos;              /* thumb pos. (pixels from tmin) */
 		 int tmin,tmax;         /* min/max thumb offsets (from 0,0) */
 		 int tsize;             /* size of thumb (in pixels) */
@@ -801,9 +929,10 @@
 typedef struct { Window win;            /* window ID */
 		 int x,y,w,h;           /* window coords in parent */
 		 int active;            /* true if can do anything*/
-		 int min,max;           /* min/max values 'pos' can take */
-		 int val;               /* 'value' of dial */
-		 int page;              /* amt val change on pageup/pagedown */
+		 double min,max;        /* min/max values 'pos' can take */
+		 double val;            /* 'value' of dial */
+		 double inc;            /* amt val change on up/down */
+		 double page;           /* amt val change on pageup/pagedown */
 		 char *title;           /* title for this guage */
 		 char *units;           /* string appended to value */
 		 u_long fg,bg,hi,lo;    /* colors */
@@ -971,15 +1100,19 @@
 WHERE unsigned int  ncells, dispWIDE, dispHIGH, dispDEEP;
 WHERE unsigned int  vrWIDE, vrHIGH, maxWIDE, maxHIGH;
 WHERE Colormap      theCmap, LocalCmap;
-WHERE Window        rootW, mainW, vrootW;
+WHERE Window        spec_window, rootW, mainW, vrootW;
 WHERE GC            theGC;
 WHERE u_long        black, white, fg, bg, infofg, infobg;
 WHERE u_long        hicol, locol;
 WHERE u_long        blkRGB, whtRGB;
 WHERE Font          mfont, monofont;
 WHERE XFontStruct   *mfinfo, *monofinfo;
+#ifdef TV_L10N
+WHERE XFontSet      monofset;
+WHERE XFontSetExtents *monofsetinfo;
+#endif
 WHERE Visual        *theVisual;
-WHERE Cursor        arrow, cross, tcross, zoom, inviso;
+WHERE Cursor        arrow, cross, tcross, zoom, inviso, tlcorner;
 WHERE Pixmap        iconPix, iconmask;
 WHERE Pixmap        riconPix, riconmask;
 WHERE int           showzoomcursor;
@@ -996,6 +1129,10 @@
 WHERE int            picType;               /* CONV24_8BIT,CONV24_24BIT,etc.*/
 WHERE char          *picComments;           /* text comments on current pic */
 
+#ifdef TV_L10N
+WHERE int            xlocale;		    /* true if Xlib supports locale */
+#endif
+
 WHERE int            numPages, curPage;     /* for multi-page files */
 WHERE char           pageBaseName[64];      /* basename for multi-page files */
 
@@ -1029,6 +1166,23 @@
 WHERE unsigned long  cols[256];    /* maps pic pixel values to X pixel vals */
 WHERE int            fc2pcol[256]; /* maps freecols into pic pixel values */
 WHERE int            numcols;      /* # of desired colors in picture */
+#ifdef MACBINARY
+WHERE char           macb_file;    /* True if this file type is MacBinary */
+WHERE int            handlemacb;   /* True if we want to handle MacBinary */
+#endif
+#if defined(HAVE_PIC) || defined(HAVE_PIC2)
+WHERE int            nopicadjust;  /* True if we don't want to adjust aspect */
+#endif
+#ifdef HAVE_PIC2
+WHERE int            pic2split;    /* True if we want to split multiblocks */
+#endif
+#ifdef VS_ADJUST
+WHERE int            vsadjust; /* True if we want to adjust aspect of icons */
+#endif
+#ifdef HAVE_MGCSFX
+WHERE int            mgcsfx;    /* True if we want to force use MgcSfx */
+WHERE int            nomgcsfx;  /* True if we don't want to use MgcSfx */
+#endif
 
 /* Std Cmap stuff */
 WHERE byte           stdr[256], stdg[256], stdb[256];  /* std 3/3/2 cmap */
@@ -1083,42 +1237,47 @@
                     noFreeCols,    /* don't free colors when loading new pic */
                     autoquit,      /* quit in '-root' or when click on win */
                     xerrcode,      /* errorcode of last X error */
-                    grabDelay;     /* # of seconds to sleep at start of Grab */
+                    grabDelay,     /* # of seconds to sleep at start of Grab */
+                    startGrab;     /* start immediate grab ? */
 
 WHERE int           state824;      /* displays warning when going 8->24 */
 
 WHERE float         defaspect,     /* default aspect ratio to use */
                     normaspect;    /* normal aspect ratio of this picture */
 
-WHERE unsigned long rootbg, rootfg;   /* fg/bg for root border */
-WHERE int           waitsec;          /* secs btwn pics. -1=wait for event */
-WHERE int           waitloop;         /* loop at end of slide show? */
-WHERE int           automax;          /* maximize pic on open */
-WHERE int           rootMode;         /* mode used for -root images */
+WHERE u_long        rootbg, rootfg; /* fg/bg for root border */
+WHERE u_short       imagebgR;
+WHERE u_short       imagebgG;      /* GRR 19980308:  bg for transpar. images */
+WHERE u_short       imagebgB;
+WHERE int           have_imagebg;
+WHERE double        waitsec;       /* secs btwn pics. -1.0=wait for event */
+WHERE int           waitloop;      /* loop at end of slide show? */
+WHERE int           automax;       /* maximize pic on open */
+WHERE int           rootMode;      /* mode used for -root images */
 
-WHERE int           nostat;           /* if true, don't stat() in LdCurDir */
+WHERE int           nostat;        /* if true, don't stat() in LdCurDir */
 
-WHERE int           ctrlColor;        /* whether or not to use colored butts */
+WHERE int           ctrlColor;     /* whether or not to use colored butts */
 
-WHERE char         *def_str;          /* used by rd_*() routines */
+WHERE char         *def_str;       /* used by rd_*() routines */
 WHERE int           def_int;
-WHERE char         *tmpdir;           /* equal to "/tmp" or $TMPDIR env var */
-WHERE Pixmap        gray25Tile,       /* used for 3d effect on 1-bit disp's */
+WHERE char         *tmpdir;        /* equal to "/tmp" or $TMPDIR env var */
+WHERE Pixmap        gray25Tile,    /* used for 3d effect on 1-bit disp's */
                     gray50Tile;
-WHERE int           autoDelete;       /* delete cmd-line files on exit? */
+WHERE int           autoDelete;    /* delete cmd-line files on exit? */
 
 #define PRINTCMDLEN 256
 WHERE char          printCmd[PRINTCMDLEN];
 
 /* stuff used for 'info' box */
 WHERE Window        infoW;
-WHERE int           infoUp;       /* boolean:  whether infobox is visible */
+WHERE int           infoUp;        /* boolean:  whether infobox is visible */
 WHERE int           infoMode;
 
 
 /* stuff used for 'ctrl' box */
 WHERE Window        ctrlW;
-WHERE int           ctrlUp;       /* boolean:  whether ctrlbox is visible */
+WHERE int           ctrlUp;        /* boolean:  whether ctrlbox is visible */
 WHERE char         *namelist[MAXNAMES];  /* list of file names from argv */
 WHERE char         *origlist[MAXNAMES];  /* only names from argv (autoDelete)*/
 WHERE int           orignumnames;
@@ -1157,25 +1316,30 @@
 
 
 /* stuff used for 'browse' box */
-WHERE int           anyBrowUp;            /* whether *any* browser visible */
+WHERE int           anyBrowUp;              /* whether *any* browser visible */
 
 /* stuff used for textview windows */
-WHERE int           anyTextUp;            /* are any text windows visible? */
-WHERE int           commentUp;            /* comment window up? */
+WHERE int           anyTextUp;              /* are any text windows visible? */
+WHERE int           commentUp;              /* comment window up? */
 
 /* stuff used for xvcut.c */
-WHERE int           forceClipFile;        /* don't use property clipboard */
-WHERE int           clearR, clearG, clearB;  /* clear color in 24-bit mode */
+WHERE int           forceClipFile;          /* don't use property clipboard */
+WHERE int           clearR, clearG, clearB; /* clear color in 24-bit mode */
 
 
 /* stuff used for 'ps' box */
 WHERE Window        psW;
-WHERE int           psUp;       /* is psW mapped, or what? */
+WHERE int           psUp;         /* is psW mapped, or what? */
 WHERE CBUTT         encapsCB, pscompCB;
 WHERE char         *gsDev, *gsGeomStr;
 WHERE int           gsRes;
 
 
+/* stuff used for 'pcd' box */
+WHERE Window        pcdW;
+WHERE int           pcdUp;        /* is pcdW mapped, or what? */
+
+
 #ifdef HAVE_JPEG
 /* stuff used for 'jpeg' box */
 WHERE Window        jpegW;
@@ -1190,6 +1354,91 @@
 #endif
 
 
+#ifdef HAVE_PNG
+/* stuff used for 'png' box */
+WHERE Window        pngW;
+WHERE int           pngUp;        /* is pngW mapped, or what? */
+#endif
+
+
+#ifdef ENABLE_FIXPIX_SMOOTH
+WHERE int           do_fixpix_smooth;  /* GRR 19980607: runtime FS dithering */
+#endif
+
+#ifdef HAVE_PIC2
+/* stuff used for 'pic2' box */
+WHERE Window        pic2W;
+WHERE int           pic2Up;      /* is pic2W mapped, or what? */
+#endif /* HAVE_PIC2 */
+
+#ifdef HAVE_PCD
+/* stuff used for 'pcd' box */
+WHERE Window        pcdW;
+WHERE int           pcdUp;       /* is pcdW mapped, or what? */
+#endif /* HAVE_PCD */
+
+#ifdef HAVE_MGCSFX
+/* stuff used for 'mgcsfx' box */
+WHERE Window        mgcsfxW;
+WHERE Window        mgcsfxNameW;
+WHERE int           mgcsfxUp;      /* is mgcsfxW mapped, or what? */
+#endif /* HAVE_MGCSFX */
+
+#ifdef TV_L10N
+/* stuff used for TextViewer Japanization */
+#  define LOCALE_USASCII    0
+#  define LOCALE_EUCJ       1
+#  define LOCALE_JIS        2
+#  define LOCALE_MSCODE     3
+
+#  ifndef LOCALE_DEFAULT
+#    define LOCALE_DEFAULT  0
+#  endif /* !LOCALE_DEFAULT */
+
+#  ifndef MAIN
+     extern char *localeList[];
+#  else
+#    ifndef LOCALE_NAME_EUC
+#      ifndef X_LOCALE
+#        if defined(__FreeBSD__)
+	   char *localeList[] = {"", "ja_JP.EUC", "none", "none"};
+#        elif defined(__linux__)
+	   char *localeList[] = {"", "ja_JP.eucJP", "none", "ja_JP.SJIS"};
+#        elif defined(__sun) || defined(sun)
+	   char *localeList[] = {"", "ja", "none", "none"};
+#        elif defined(__sgi)	/* sgi, __sgi, __sgi__ (gcc) */
+	   char *localeList[] = {"", "ja_JP.EUC", "none", "none"};
+#        elif defined(sony_news)
+	   char *localeList[] = {"", "ja_JP.EUC", "none", "ja_JP.SJIS"};
+#        elif defined(nec)
+	   char *localeList[] = {"", "japan", "none", "none"};
+#        elif defined(__hpux)
+	   char *localeList[] = {"", "japanese.euc", "none", "japanese"};
+#        elif defined(__osf__)
+	   char *localeList[] = {"", "ja_JP.deckanji", "none", "ja_JP.SJIS"};
+#        elif defined(_AIX)
+	   char *localeList[] = {"", "ja_JP", "none", "Ja_JP" };
+#        elif defined(__bsdi)
+	   char *localeList[] = {"", "Japanese-EUC", "none", "none" };
+#        else
+	   char *localeList[] = {"", "ja_JP.EUC", "ja_JP.JIS", "ja_JP.SJIS"};
+#        endif
+#      else
+#        if (XlibSpecificationRelease > 5)
+           char *localeList[] = {"", "ja_JP.eucJP", "ja_JP.JIS7",
+				 "ja_JP.SJIS"};
+#        else
+           char *localeList[] = {"", "ja_JP.ujis", "ja_JP.jis7",
+				 "ja_JP.mscode"};
+#        endif
+#      endif /* X_LOCALE */
+#    else
+       char *localeList[] = {"", LOCALE_NAME_EUC,
+			     LOCALE_NAME_JIS, LOCALE_NAME_MSCODE};
+#    endif /* LOCALE_NAME_EUC */
+#  endif /* MAIN */
+#endif /* TV_L10N */
+
 #undef WHERE
 
 
@@ -1199,8 +1448,11 @@
 /****************************** XV.C ****************************/
 int   ReadFileType      PARM((char *));
 int   ReadPicFile       PARM((char *, int, PICINFO *, int));
-int   UncompressFile    PARM((char *, char *));
+int   UncompressFile    PARM((char *, char *, int));
 void  KillPageFiles     PARM((char *, int));
+#ifdef MACBINARY
+int   RemoveMacbinary   PARM((char *, char *));
+#endif
 
 void NewPicGetColors    PARM((int, int));
 void FixAspect          PARM((int, int *, int *));
@@ -1429,6 +1681,9 @@
 int  CheckPoll             PARM((int));
 void DIRDeletedFile        PARM((char *));
 void DIRCreatedFile        PARM((char *));
+FILE *pic2_OpenOutFile     PARM((char *, int *));
+void pic2_KillNullFile     PARM((FILE *));
+int  OpenOutFileDesc       PARM((char *));
 
 
 /*************************** XVBROWSE.C ************************/
@@ -1448,7 +1703,7 @@
 
 /*************************** XVTEXT.C ************************/
 void CreateTextWins        PARM((char *, char *));
-void TextView              PARM((char *));
+int  TextView              PARM((char *));
 void OpenTextView          PARM((char *, int, char *, int));
 
 void OpenCommentText       PARM((void));
@@ -1466,6 +1721,8 @@
 int  TextCheckEvent        PARM((XEvent *, int *, int *));
 int  TextDelWin            PARM((Window));
 
+int  CharsetCheckEvent     PARM((XEvent *));
+int  CharsetDelWin         PARM((Window));
 
 
 /**************************** XVGAM.C **************************/
@@ -1502,12 +1759,12 @@
 
 
 /*************************** XVDIAL.C ***************************/
-void DCreate               PARM((DIAL *, Window, int, int, int, int, int,
-				 int, int, int, u_long, u_long, u_long,
-				 u_long, char *, char *));
+void DCreate               PARM((DIAL *, Window, int, int, int, int, double,
+                                 double, double, double, double, u_long,
+                                 u_long, u_long, u_long, char *, char *));
 
-void DSetRange             PARM((DIAL *, int, int, int, int));
-void DSetVal               PARM((DIAL *, int));
+void DSetRange             PARM((DIAL *, double,double,double,double,double));
+void DSetVal               PARM((DIAL *, double));
 void DSetActive            PARM((DIAL *, int));
 void DRedraw               PARM((DIAL *));
 int  DTrack                PARM((DIAL *, int, int));
@@ -1585,7 +1842,11 @@
 				 byte *, byte *, int, int, char *));
 
 /**************************** XVPBM.C ***************************/
+#ifdef HAVE_MGCSFX
+int LoadPBM                PARM((char *, PICINFO *, int));
+#else
 int LoadPBM                PARM((char *, PICINFO *));
+#endif
 int WritePBM               PARM((FILE *, byte *, int, int, int, byte *,
 				 byte *, byte *, int, int, int, char *));
 
@@ -1604,6 +1865,11 @@
 int WriteBMP               PARM((FILE *, byte *, int, int, int, byte *,
 				 byte *, byte *, int, int));
 
+/**************************** XVWBMP.C ***************************/
+int LoadWBMP               PARM((char *, PICINFO *));
+int WriteWBMP              PARM((FILE *, byte *, int, int, int, byte *,
+				 byte *, byte *, int, int));
+
 /**************************** XVRLE.C ***************************/
 int LoadRLE                PARM((char *, PICINFO *));
 
@@ -1642,6 +1908,7 @@
 void JPEGDialog            PARM((int));
 int  JPEGCheckEvent        PARM((XEvent *));
 void JPEGSaveParams        PARM((char *, int));
+void VersionInfoJPEG       PARM((void));		/* GRR 19980605 */
 
 /**************************** XVTIFF.C ***************************/
 int   LoadTIFF             PARM((char *, PICINFO *, int));
@@ -1649,6 +1916,15 @@
 void  TIFFDialog           PARM((int));
 int   TIFFCheckEvent       PARM((XEvent *));
 void  TIFFSaveParams       PARM((char *, int));
+void  VersionInfoTIFF      PARM((void));		/* GRR 19980605 */
+
+/**************************** XVPNG.C ***************************/
+int  LoadPNG               PARM((char *, PICINFO *));
+void CreatePNGW            PARM((void));
+void PNGDialog             PARM((int));
+int  PNGCheckEvent         PARM((XEvent *));
+void PNGSaveParams         PARM((char *, int));
+void VersionInfoPNG        PARM((void));		/* GRR 19980605 */
 
 /**************************** XVPDS.C ***************************/
 int LoadPDS                PARM((char *, PICINFO *));
@@ -1661,6 +1937,87 @@
 void  PSResize             PARM((void));
 int   LoadPS               PARM((char *, PICINFO *, int));
 
+/************************ [JCE] XVZX.C ***************************/
+
+int LoadZX                 PARM((char *, PICINFO *));
+int WriteZX                PARM((FILE *, byte *, int, int, int, byte *,
+				 byte *, byte *, int, int, char *));
+
+/**************************** XVPCD.C ***************************/
+int   LoadPCD              PARM((char *, PICINFO *, int));
+void  CreatePCDW           PARM((void));
+void  PCDDialog            PARM((int));
+int   PCDCheckEvent        PARM((XEvent *));
+void  PCDSetParamOptions   PARM((char *));
+
+/*************************** XVMAG.C ***************************/
+int   LoadMAG              PARM((char *, PICINFO *));
+int   WriteMAG             PARM((FILE *, byte *, int, int, int,
+				 byte *, byte *, byte *, int, int, char *));
+
+/*************************** XVMAKI.C ***************************/
+int   LoadMAKI             PARM((char *, PICINFO *));
+int   WriteMAKI            PARM((FILE *, byte *, int, int, int,
+				 byte *, byte *, byte *, int, int));
+
+/*************************** XVPIC.C ***************************/
+int   LoadPIC              PARM((char *, PICINFO *));
+int   WritePIC             PARM((FILE *, byte *, int, int, int,
+				 byte *, byte *, byte *, int, int, char *));
+
+/*************************** XVPI.C ***************************/
+int   LoadPi               PARM((char *, PICINFO *));
+int   WritePi              PARM((FILE *, byte *, int, int, int,
+				 byte *, byte *, byte *, int, int, char *));
+
+/*************************** XVPIC2.C ***************************/
+int   LoadPIC2             PARM((char *, PICINFO *, int));
+void  CreatePIC2W          PARM((void));
+void  PIC2Dialog           PARM((int));
+int   PIC2CheckEvent       PARM((XEvent *));
+int   PIC2SetParamOptions  PARM((char *));
+
+/**************************** XVPCD.C ***************************/
+int   LoadPCD              PARM((char *, PICINFO *,int));
+void  CreatePCDW           PARM((void));
+void  PCDDialog            PARM((int));
+int   PCDCheckEvent        PARM((XEvent *));
+void  PCDSetParamOptions   PARM((char *));
+
+/**************************** XVHIPS.C ***************************/
+int   LoadHIPS             PARM((char *, PICINFO *));
+
+/*************************** XVMGCSFX.C ***************************/
+int   is_mgcsfx             PARM((char *, unsigned char *, int));
+char *mgcsfx_auto_input_com PARM((char *));
+int   LoadMGCSFX            PARM((char *, PICINFO *));
+void  CreateMGCSFXW         PARM((void));
+void  MGCSFXDialog          PARM((int));
+int   MGCSFXCheckEvent      PARM((XEvent *));
+int   MGCSFXSaveParams      PARM((char *, int));
+
+int getInputCom             PARM((void));
+int getOutputCom            PARM((void));
+
+/**************************** XVVD.C ****************************/
+void  Vdinit               PARM((void));
+void  Vdsettle             PARM((void));
+int   Chvdir               PARM((char *));
+void  Dirtovd              PARM((char *));
+void  Vdtodir              PARM((char *));
+void  Dirtosubst           PARM((char *));
+int   Mkvdir               PARM((char *));
+void  Mkvdir_force         PARM((char *));
+int   Rmvdir               PARM((char *));
+int   Movevdir             PARM((char *, char *));
+int   Isarchive            PARM((char *));
+int   Isvdir               PARM((char *));
+void  vd_HUPhandler        PARM((void));
+void  vd_handler           PARM((int));
+int   vd_Xhandler          PARM((Display *, XErrorEvent *));
+int   vd_XIOhandler        PARM((Display *));
+void  vd_handler_setup     PARM((void));
+
 /*************************** XVPOPUP.C ***************************/
 void  CenterMapWindow      PARM((Window, int, int, int, int));
 int   PopUp                PARM((char *, char **, int));
@@ -1714,3 +2071,13 @@
 void CoordP2E              PARM((int, int, int *, int *));
 void CoordE2P              PARM((int, int, int *, int *));
 
+#if defined(__mips) && defined(__SYSTYPE_BSD43)
+#  define strstr(A,B) pds_strstr((A),(B))
+#  undef S_IFIFO
+#endif /* !mips_bsd */
+
+#ifndef SEEK_SET
+#  define SEEK_SET 0
+#  define SEEK_CUR 1
+#  define SEEK_END 2
+#endif
diff -ruN xv-3.10a-bugfixes/xv_mgcsfx.sample xv-3.10a-enhancements/xv_mgcsfx.sample
--- xv-3.10a-bugfixes/xv_mgcsfx.sample	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xv_mgcsfx.sample	2005-04-17 14:04:22.000000000 -0700
@@ -0,0 +1,125 @@
+#/*
+# Configuration file for XV with recognition of 'Magic and Suffix'
+#
+#
+# $Id: xv_mgcsfx.sample,v 1.11 95/10/03 17:00:05 tin329 Exp Locker: tin329 $
+#
+# Author: Tetsuya INOUE  <tin329@chino.it.okayama-u.ac.jp>
+#
+#
+# MgcSfx definition should write in one line.
+#  Format:
+#      <desc>:<ms type>:<ofs>:<magic>:<suffix>:<in it>:<in c>:<out it>:<out c>
+#  If you decide to not use preprocessor, comment style is allowed.
+#      # <comment>
+#
+#   <desc>            Description of your recognized image format.
+#   <ms type>         Type ID for recognition. (You should use 'magic'.)
+#                        * magic        Data of string style.
+#                                        `\' escape for special characters:
+#                                           \b \f \n \r \t \v \\ \' \" \a \?
+#                                           \0  ...\377   octal value
+#                                           \x0 ...\xff   hexadecimal value
+#                        * suffix       Suffix of file name.
+#                                         This type check <suffix> instead
+#                                         of <magic>.
+#                        * [b|l]eint16  2 byte integer of [big|little] endian.
+#                        * [b|l]eint32  4 byte integer of [big|little] endian.
+#   <ofs>             Offset of magic number in the target image file.
+#   <magic>           Data(magic number) of <ms type> to match at <ofs>.
+#   <suffix>          Suffix of filename with '.'start.
+#
+#   <in it>           Input image format type (output from <in c>).
+#                        * PNM       (PPM, PGM, PBM)
+#                        * AUTO      Recognized by xv management, and load.
+#                                    This is different from others, because
+#                                    this write file to temporary.
+#   <out it>          Output image format type (input to <out c>).
+#                        * PNM_RAW   (PPM_RAW, PGM_RAW, PBM_RAW)
+#                        * PNM_ASCII (PPM_ASCII, PGM_ASCII, PBM_ASCII)
+#
+#   <in c>            Command to get the input image.
+#                        * Command mast read stdin or file(specified by
+#                          argument), and write to stdout.
+#                        * Use %s to represent the file name. Without %s,
+#                          get file on stdin.
+#   <out c>           Command to put the output image.
+#                        * Command mast read stdin and write to stdout.
+#
+#   <comment>         Any message.
+#*/
+
+#/*############################################################################
+#
+# definition of the rule with Magic and Suffix
+#
+#*/
+
+# /* Canon View Station Image Format */
+ViewStation(std):magic:0:VsStdImf V0.2:.vs:PNM:VStopnm %s:PNM_RAW:pnmtoVS
+ViewStation(obj):magic:0:VsObjFormat V1.0:.vs:PNM:VSobjtopnm -:PNM_RAW:pnmtoVSobj
+
+# /* CERN httpd cache */
+# /* unchc skip header of CERN httpd cache file, and write data to stdout. */
+CERN httpd cache:magic:0:HTTP/1.0::AUTO:unchc %s::
+
+# /* XLD4(Q4) image format */
+XLD(Q4):magic:11:MAJYO:.q4:PNM:q4toppm::
+
+# /* ML1 image format */
+ML1:magic:0:\1\0\0\x1a:.ml1:PNM:ml1toppm %s::
+
+# /* Pict image format, 256 color only */
+PICT:suffix:::.pict:PNM:picttoppm:PNM_RAW:ppmquant 256 | ppmtopict 
+PICT(gzip):suffix:::.pict.gz:PNM:gzip -dc | picttoppm:PNM_RAW:ppmquant 256 | ppmtopict | gzip
+PICT(compress):suffix:::.pict.Z:PNM:compress -dc | picttoppm:PNM_RAW:ppmquant 256 | ppmtopict | compress
+
+# /* Tim image format(used by SONY PlayStation) */
+TIM:magic:0:\x10\x00\x00\x00:.tim:PNM:timtoppm::
+
+# /* Cam image format(used by CASIO QV-10) */
+# /* CAM:magic:0:\x07\x20\x4d\x4d:.cam:AUTO:camtoppm -j:PNM_RAW */
+CAM:magic:0:\x07\x20\x4d\x4d:.cam:PNM:camtoppm::
+
+# /* Portable Network Graphics (PNG) format : magic is "0x89 PNG" */
+PNG:magic:0:\x89\x50\x4e\x47:.png:PNM:pngtopnm %s:PNM_RAW:pnmtopng
+# /* PNG(interlace):magic:0:\x89\x50\x4e\x47:.png:PNM:pngtopnm %s:PNM_RAW:pnmtopng -interlace */
+
+# /* DB-Z, SAURUS Freehand Memo, PV-F1 Action Board, Wiz Quick Memo format */
+# /* Use xbm2free-1.10 or later. Old version is NOT a filter. */
+# /* To show version of xbm2free, type "xbm2free" (with no argument). */
+ZAURUS:magic:19:IMG1:.zau:PBM_ASCII:free2pbm:PBM:pbmtoxbm|xbm2free -s -
+DBZ:magic:19:IMG1:.dbz:::PBM:pbmtoxbm|xbm2free -d -
+PVF1:magic:12:IMG1:.pvf1:PBM_ASCII:free2pbm:PBM:pbmtoxbm|xbm2free -v -
+# /* WIZ:magic:19:IMG1:.wiz:::PBM:pbmtoxbm|xbm2free -w - */
+
+
+
+# /* Compress:magic:0:\037\235:.Z:AUTO:uncompress %s:: */
+# /* Gzip:magic:0:\037\213:.gz:AUTO:gunzip %s:: */
+# /* Gzip(old):magic:0:\037\236:.z:AUTO:gunzip %s:: */
+
+# /* MAKI:magic:0:MAKI01A\040:.mki:::: */
+# /* MAKI:magic:0:MAKI01B\040:.mki:::: */
+# /* MAG:magic:0:MAKI02\040\040:.mag:::: */
+# /* Pi:magic:0:Pi:.pi:::: */
+# /* PIC:magic:0:PIC:.pic:::: */
+# /* PIC2:magic:0:P2DT:.p2:::: */
+# /* PhotoCD:magic:0:\xff\xff\xff\xff:.pcd:::: */
+
+# /* PBM(ascii):magic:0:P1:.pbm:::: */
+# /* PGM(ascii):magic:0:P2:.pgm:::: */
+# /* PPM(ascii):magic:0:P3:.ppm:::: */
+# /* PBM(raw):magic:0:P4:.pbm:::: */
+# /* PGM(raw):magic:0:P5:.pgm:::: */
+# /* PPM(raw):magic:0:P6:.ppm:::: */
+
+# /* Sun raster:magic:0:\131\246\152\225:.sun:::: */
+# /* JFIF(JPEG):magic:0:\xff\xd8\xff:.jpg:::: */
+# /* TIFF big-endian:magic:0:\115\115:.tif:::: */
+# /* TIFF little-endian:magic:0:\111\111:.tif:::: */
+# /* GIF(87):magic:0:GIF87a:.gif:::: */
+# /* GIF(89):magic:0:GIF89a:.gif:::: */
+# /* SGI(1):magic:0:\x01\xda:.rgb:::: */
+# /* SGI(2):magic:0:\xda\x01:.rgb:::: */
+# /* XWD:magic:0:\0\0\0\7: :::: */
diff -ruN xv-3.10a-bugfixes/xvbmp.c xv-3.10a-enhancements/xvbmp.c
--- xv-3.10a-bugfixes/xvbmp.c	2005-03-27 18:12:17.000000000 -0800
+++ xv-3.10a-enhancements/xvbmp.c	2005-04-17 13:56:31.000000000 -0700
@@ -1,5 +1,5 @@
 /*
- * xvbmp.c - i/o routines for .BMP files (MS Windows 3.x)
+ * xvbmp.c - I/O routines for .BMP files (MS Windows 3.x and later; OS/2)
  *
  * LoadBMP(fname, numcols)
  * WriteBMP(fp, pic, ptype, w, h, r, g, b, numcols, style);
@@ -9,30 +9,39 @@
 
 #include "xv.h"
 
-/* comments on error handling:
-   a truncated file is not considered a Major Error.  The file is loaded, the
-   rest of the pic is filled with 0's.
-
-   a file with garbage characters in it is an unloadable file.  All allocated
-   stuff is tossed, and LoadBMP returns non-zero
-
-   not being able to malloc is a Fatal Error.  The program is aborted. */
-
-
-#define BI_RGB  0
-#define BI_RLE8 1
-#define BI_RLE4 2
+/* Comments on error-handling:
+   A truncated file is not considered a Major Error.  The file is loaded,
+   and the rest of the pic is filled with 0's.
+
+   A file with garbage characters in it is an unloadable file.  All allocated
+   stuff is tossed, and LoadBMP returns non-zero.
+
+   Not being able to malloc is a Fatal Error.  The program is aborted. */
+
+
+#define BI_RGB       0   /* a.k.a. uncompressed */
+#define BI_RLE8      1
+#define BI_RLE4      2
+#define BI_BITFIELDS 3   /* BMP version 4 */
+#define BI_JPEG      4   /* BMP version 5 (not yet supported) */
+#define BI_PNG       5   /* BMP version 5 (not yet supported) */
 
 #define WIN_OS2_OLD 12
 #define WIN_NEW     40
 #define OS2_NEW     64
 
+#if (defined(UINT_MAX) && UINT_MAX != 0xffffffffU)
+#  error XV's BMP code requires 32-bit unsigned integer type, but u_int isn't
+#endif
+
 static long filesize;
 
 static int   loadBMP1   PARM((FILE *, byte *, u_int, u_int));
 static int   loadBMP4   PARM((FILE *, byte *, u_int, u_int, u_int));
 static int   loadBMP8   PARM((FILE *, byte *, u_int, u_int, u_int));
-static int   loadBMP24  PARM((FILE *, byte *, u_int, u_int));
+static int   loadBMP16  PARM((FILE *, byte *, u_int, u_int, u_int *));
+static int   loadBMP24  PARM((FILE *, byte *, u_int, u_int, u_int));
+static int   loadBMP32  PARM((FILE *, byte *, u_int, u_int, u_int *));
 static u_int getshort   PARM((FILE *));
 static u_int getint     PARM((FILE *));
 static void  putshort   PARM((FILE *, int));
@@ -52,15 +61,14 @@
      PICINFO *pinfo;
 /*******************************************/
 {
-  FILE         *fp;
-  int          i, c, c1, rv;
-  u_int        bfSize, bfOffBits, biSize, biWidth, biHeight, biPlanes;
-  u_int        biBitCount, biCompression, biSizeImage, biXPelsPerMeter;
-  u_int        biYPelsPerMeter, biClrUsed, biClrImportant;
-  int bPad;
-  char         *cmpstr;
-  byte         *pic24, *pic8;
-  char          buf[512], *bname;
+  FILE    *fp;
+  int     i, c, c1, rv, bPad;
+  u_int   bfSize, bfOffBits, biSize, biWidth, biHeight, biPlanes;
+  u_int   biBitCount, biCompression, biSizeImage, biXPelsPerMeter;
+  u_int   biYPelsPerMeter, biClrUsed, biClrImportant;
+  u_int   colormask[3];
+  char    buf[512], *bname, *cmpstr, rgb_bits[16];
+  byte    *pic24, *pic8;
 
   /* returns '1' on success */
 
@@ -98,14 +106,13 @@
     biClrUsed       = getint(fp);
     biClrImportant  = getint(fp);
   }
-
   else {    /* old bitmap format */
     biWidth         = getshort(fp);          /* Types have changed ! */
     biHeight        = getshort(fp);
     biPlanes        = getshort(fp);
     biBitCount      = getshort(fp);
 
-    /* Not in old versions so have to compute them*/
+    /* not in old versions, so have to compute them */
     biSizeImage = (((biPlanes * biBitCount*biWidth)+31)/32)*4*biHeight;
 
     biCompression   = BI_RGB;
@@ -126,25 +133,39 @@
   if (FERROR(fp)) { bmpError(bname,"EOF reached in file header"); goto ERROR; }
 
 
-  /* error checking */
-  if ((biBitCount!=1 && biBitCount!=4 && biBitCount!=8 && biBitCount!=24) ||
-      biPlanes!=1 || biCompression>BI_RLE4 ||
+  /* error-checking */
+  if ((biBitCount!=1 && biBitCount!=4 && biBitCount!=8 &&
+       biBitCount!=16 && biBitCount!=24 && biBitCount!=32) ||
+      biPlanes!=1 || biCompression>BI_PNG ||
       biWidth<=0 || biHeight<=0 ||
       (biClrUsed && biClrUsed > (1 << biBitCount))) {
 
     sprintf(buf,
-	    "Bogus BMP File!  (%dx%d, Bits=%d, Colors=%d, Planes=%d, Compr=%d)",
+	    "Unsupported BMP type (%dx%d, Bits=%d, Colors=%d, Planes=%d, "
+	    "Compr=%d)",
 	    biWidth, biHeight, biBitCount, biClrUsed, biPlanes, biCompression);
 
     bmpError(bname, buf);
     goto ERROR;
   }
 
+  if (biCompression>BI_BITFIELDS) {
+    sprintf(buf, "Unsupported BMP compression method (%s)",
+	    biCompression == BI_JPEG? "JPEG" :
+	    biCompression == BI_PNG? "PNG" :
+	    "unknown/newer than v5");
+
+    bmpError(bname, buf);
+    goto ERROR;
+  }
+
   if (((biBitCount==1 || biBitCount==24) && biCompression != BI_RGB) ||
-      (biBitCount==4 && biCompression==BI_RLE8) ||
-      (biBitCount==8 && biCompression==BI_RLE4)) {
+      (biBitCount==4 && biCompression!=BI_RGB && biCompression!=BI_RLE4) ||
+      (biBitCount==8 && biCompression!=BI_RGB && biCompression!=BI_RLE8) ||
+      ((biBitCount==16 || biBitCount==32) &&
+       biCompression!=BI_RGB && biCompression!=BI_BITFIELDS)) {
 
-    sprintf(buf,"Bogus BMP File!  (bitCount=%d, Compression=%d)",
+    sprintf(buf,"Unsupported BMP type (bitCount=%d, Compression=%d)",
 	    biBitCount, biCompression);
 
     bmpError(bname, buf);
@@ -156,20 +177,23 @@
   if (biSize != WIN_OS2_OLD) {
     /* skip ahead to colormap, using biSize */
     c = biSize - 40;    /* 40 bytes read from biSize to biClrImportant */
-    for (i=0; i<c; i++) getc(fp);
-
+    for (i=0; i<c; i++)
+      getc(fp);
     bPad = bfOffBits - (biSize + 14);
   }
 
+  /* 16-bit or 32-bit color mask */
+  if (biCompression==BI_BITFIELDS) {
+    colormask[0] = getint(fp);
+    colormask[1] = getint(fp);
+    colormask[2] = getint(fp);
+    bPad -= 12;
+  }
+
   /* load up colormap, if any */
-  if (biBitCount!=24) {
+  if (biBitCount == 1 || biBitCount == 4 || biBitCount == 8) {
     int i, cmaplen;
 
-/* this is superfluous; see identical test in "error checking" block above
-  if (biClrUsed > (1 << biBitCount))
-    biClrUsed = (1 << biBitCount);
- */
-
     cmaplen = (biClrUsed) ? biClrUsed : 1 << biBitCount;
     for (i=0; i<cmaplen; i++) {
       pinfo->b[i] = getc(fp);
@@ -205,7 +229,7 @@
 
   /* create pic8 or pic24 */
 
-  if (biBitCount==24) {
+  if (biBitCount==16 || biBitCount==24 || biBitCount==32) {
     u_int npixels = biWidth * biHeight;
     u_int count = 3 * npixels;
 
@@ -227,19 +251,35 @@
   WaitCursor();
 
   /* load up the image */
-  if      (biBitCount == 1) rv = loadBMP1(fp,pic8,biWidth,biHeight);
-  else if (biBitCount == 4) rv = loadBMP4(fp,pic8,biWidth,biHeight,
-					  biCompression);
-  else if (biBitCount == 8) rv = loadBMP8(fp,pic8,biWidth,biHeight,
-					  biCompression);
-  else                      rv = loadBMP24(fp,pic24,biWidth,biHeight);
+  switch (biBitCount) {
+  case 1:
+    rv = loadBMP1(fp, pic8, biWidth, biHeight);
+    break;
+  case 4:
+    rv = loadBMP4(fp, pic8, biWidth, biHeight, biCompression);
+    break;
+  case 8:
+    rv = loadBMP8(fp, pic8, biWidth, biHeight, biCompression);
+    break;
+  case 16:
+    rv = loadBMP16(fp, pic24, biWidth, biHeight,           /*  v-- BI_RGB */
+                   biCompression == BI_BITFIELDS? colormask : NULL);
+    break;
+  default:
+    if (biBitCount == 32 && biCompression == BI_BITFIELDS)
+      rv = loadBMP32(fp, pic24, biWidth, biHeight, colormask);
+    else /* 24 or (32 and BI_RGB) */
+      rv = loadBMP24(fp, pic24, biWidth, biHeight, biBitCount);
+    break;
+  }
 
   if (rv) bmpError(bname, "File appears truncated.  Winging it.");
 
+
   fclose(fp);
 
 
-  if (biBitCount == 24) {
+  if (biBitCount > 8) {
     pinfo->pic  = pic24;
     pinfo->type = PIC24;
   }
@@ -251,6 +291,22 @@
   cmpstr = "";
   if      (biCompression == BI_RLE4) cmpstr = ", RLE4 compressed";
   else if (biCompression == BI_RLE8) cmpstr = ", RLE8 compressed";
+  else if (biCompression == BI_BITFIELDS) {
+    int    bit, c[3], i;
+    u_int  mask;
+
+    for (i = 0; i < 3; ++i) {
+      mask = colormask[i];
+      c[i] = 0;
+      for (bit = 0; bit < 32; ++bit) {
+        if (mask & 1)
+          ++c[i];
+        mask >>= 1;
+      }
+    }
+    sprintf(rgb_bits, ", RGB%d%d%d", c[0], c[1], c[2]);
+    cmpstr = rgb_bits;
+  }
 
   pinfo->w = biWidth;  pinfo->h = biHeight;
   pinfo->normw = pinfo->w;   pinfo->normh = pinfo->h;
@@ -282,12 +338,13 @@
      u_int  w,h;
 {
   int   i,j,c,bitnum,padw;
-  byte *pp;
+  byte *pp = pic8 + ((h - 1) * w);
+  size_t l = w*h;
 
   c = 0;
   padw = ((w + 31)/32) * 32;  /* 'w', padded to be a multiple of 32 */
 
-  for (i=h-1; i>=0; i--) {
+  for (i=h-1; i>=0 && (pp - pic8 <= l); i--) {
     pp = pic8 + (i * w);
     if ((i&0x3f)==0) WaitCursor();
     for (j=bitnum=0; j<padw; j++,bitnum++) {
@@ -316,8 +373,8 @@
      u_int  w,h,comp;
 {
   int   i,j,c,c1,x,y,nybnum,padw,rv;
-  byte *pp;
-
+  byte *pp = pic8 + ((h - 1) * w);
+  size_t l = w*h;
 
   rv = 0;
   c = c1 = 0;
@@ -325,7 +382,7 @@
   if (comp == BI_RGB) {   /* read uncompressed data */
     padw = ((w + 7)/8) * 8; /* 'w' padded to a multiple of 8pix (32 bits) */
 
-    for (i=h-1; i>=0; i--) {
+    for (i=h-1; i>=0 && (pp - pic8 <= l); i--) {
       pp = pic8 + (i * w);
       if ((i&0x3f)==0) WaitCursor();
 
@@ -353,7 +410,7 @@
 
       if (c) {                                   /* encoded mode */
 	c1 = getc(fp);
-	for (i=0; i<c; i++,x++,pp++)
+	for (i=0; i<c && (pp - pic8 <= l); i++,x++,pp++)
 	  *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f);
       }
 
@@ -373,7 +430,7 @@
 	}
 
 	else {                                   /* absolute mode */
-	  for (i=0; i<c; i++, x++, pp++) {
+	  for (i=0; i<c && (pp - pic8 <= l); i++, x++, pp++) {
 	    if ((i&1) == 0) c1 = getc(fp);
 	    *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f);
 	  }
@@ -402,14 +459,18 @@
      u_int  w,h,comp;
 {
   int   i,j,c,c1,padw,x,y,rv;
-  byte *pp;
+  byte *pp = pic8 + ((h - 1) * w);
+  size_t l = w*h;
+  byte *pend;
 
   rv = 0;
 
+  pend = pic8 + w * h;
+
   if (comp == BI_RGB) {   /* read uncompressed data */
     padw = ((w + 3)/4) * 4; /* 'w' padded to a multiple of 4pix (32 bits) */
 
-    for (i=h-1; i>=0; i--) {
+    for (i=h-1; i>=0 && (pp - pic8 <= l); i--) {
       pp = pic8 + (i * w);
       if ((i&0x3f)==0) WaitCursor();
 
@@ -425,12 +486,12 @@
     x = y = 0;
     pp = pic8 + x + (h-y-1)*w;
 
-    while (y<h) {
+    while (y<h && pp<=pend) {
       c = getc(fp);  if (c == EOF) { rv = 1;  break; }
 
       if (c) {                                   /* encoded mode */
 	c1 = getc(fp);
-	for (i=0; i<c; i++,x++,pp++) *pp = c1;
+	for (i=0; i<c && pp<=pend; i++,x++,pp++) *pp = c1;
       }
 
       else {    /* c==0x00  :  escape codes */
@@ -449,7 +510,7 @@
 	}
 
 	else {                                   /* absolute mode */
-	  for (i=0; i<c; i++, x++, pp++) {
+	  for (i=0; i<c && pp<=pend; i++, x++, pp++) {
 	    c1 = getc(fp);
 	    *pp = c1;
 	  }
@@ -472,26 +533,133 @@
 
 
 /*******************************************/
-static int loadBMP24(fp, pic24, w, h)
+static int loadBMP16(fp, pic24, w, h, mask)
+     FILE  *fp;
+     byte  *pic24;
+     u_int w, h, *mask;
+{
+  int	 x, y;
+  byte	*pp = pic24 + ((h - 1) * w * 3);
+  size_t l = w*h*3;
+  u_int	 buf, colormask[6];
+  int	 i, bit, bitshift[6], colorbits[6], bitshift2[6];
+
+  if (mask == NULL) {  /* RGB555 */
+    colormask[0] = 0x00007c00;
+    colormask[1] = 0x000003e0;
+    colormask[2] = 0x0000001f;
+    colormask[3] = 0x7c000000;
+    colormask[4] = 0x03e00000;
+    colormask[5] = 0x001f0000;
+    bitshift[0] =  7;	bitshift2[0] = 0;
+    bitshift[1] =  2;	bitshift2[1] = 0;
+    bitshift[2] =  0;	bitshift2[2] = 3;
+    bitshift[3] = 23;	bitshift2[3] = 0;
+    bitshift[4] = 18;	bitshift2[4] = 0;
+    bitshift[5] = 13;	bitshift2[5] = 0;
+  } else {
+    colormask[0] = mask[0];
+    colormask[1] = mask[1];
+    colormask[2] = mask[2];
+    colormask[3] = (mask[0] & 0xffff) << 16;
+    colormask[4] = (mask[1] & 0xffff) << 16;
+    colormask[5] = (mask[2] & 0xffff) << 16;
+
+    for (i = 0; i < 3; ++i) {
+      buf = colormask[i];
+
+      bitshift[i] = 0;
+      for (bit = 0; bit < 32; ++bit) {
+	if (buf & 1)
+	  break;
+	else
+	  ++bitshift[i];
+	buf >>= 1;
+      }
+      bitshift[i+3] = bitshift[i] + 16;
+
+      colorbits[i] = 0;
+      for (; bit < 32; ++bit) {
+	if (buf & 1)
+	  ++colorbits[i];
+	else
+	  break;
+	buf >>= 1;
+      }
+      if (colorbits[i] > 8) { /* over 8-bit depth */
+	bitshift[i] += (colorbits[i] - 8);
+	bitshift[i+3] = bitshift[i] + 16;
+	bitshift2[i] = bitshift2[i+3] = 0;
+      } else
+	bitshift2[i] = bitshift2[i+3] = 8 - colorbits[i];
+    }
+  }
+
+  if (DEBUG > 1)
+    fprintf(stderr, "loadBMP16: bitfields\n"
+	    "\tR: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
+	    "\t             (mask = %08x, shift >>%2d, <<%2d)\n"
+	    "\tG: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
+	    "\t             (mask = %08x, shift >>%2d, <<%2d)\n"
+	    "\tB: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
+	    "\t             (mask = %08x, shift >>%2d, <<%2d)\n",
+	    colorbits[0], colormask[0], bitshift[0], bitshift2[0],
+	    colormask[3], bitshift[3], bitshift2[3],
+	    colorbits[1], colormask[1], bitshift[1], bitshift2[1],
+	    colormask[4], bitshift[4], bitshift2[4],
+	    colorbits[2], colormask[2], bitshift[2], bitshift2[2],
+	    colormask[5], bitshift[5], bitshift2[5]);
+
+  for (y = h-1; y >= 0 && (pp - pic24 <= l); y--) {
+    pp = pic24 + (3 * w * y);
+    if ((y&0x3f)==0) WaitCursor();
+
+    for (x = w; x > 1; x -= 2) {
+      buf = getint(fp);
+      *(pp++) = (buf & colormask[0]) >> bitshift[0] << bitshift2[0];
+      *(pp++) = (buf & colormask[1]) >> bitshift[1] << bitshift2[1];
+      *(pp++) = (buf & colormask[2]) >> bitshift[2] << bitshift2[2];
+      *(pp++) = (buf & colormask[3]) >> bitshift[3] << bitshift2[3];
+      *(pp++) = (buf & colormask[4]) >> bitshift[4] << bitshift2[4];
+      *(pp++) = (buf & colormask[5]) >> bitshift[5] << bitshift2[5];
+    }
+    if (w & 1) { /* padded to 2 pix */
+      buf = getint(fp);
+      *(pp++) = (buf & colormask[0]) >> bitshift[0];
+      *(pp++) = (buf & colormask[1]) >> bitshift[1];
+      *(pp++) = (buf & colormask[2]) >> bitshift[2];
+    }
+  }
+
+  return FERROR(fp)? 1 : 0;
+}
+
+
+
+/*******************************************/
+static int loadBMP24(fp, pic24, w, h, bits)   /* also handles 32-bit BI_RGB */
      FILE *fp;
      byte *pic24;
-     u_int  w,h;
+     u_int  w,h, bits;
 {
   int   i,j,padb,rv;
-  byte *pp;
+  byte *pp = pic24 + ((h - 1) * w * 3);
+  size_t l = w*h*3;
 
   rv = 0;
 
   padb = (4 - ((w*3) % 4)) & 0x03;  /* # of pad bytes to read at EOscanline */
+  if (bits==32) padb = 0;
 
   for (i=h-1; i>=0; i--) {
     pp = pic24 + (i * w * 3);
     if ((i&0x3f)==0) WaitCursor();
 
-    for (j=0; j<w; j++) {
+    for (j=0; j<w && (pp - pic24 <= l); j++) {
       pp[2] = getc(fp);   /* blue */
       pp[1] = getc(fp);   /* green */
       pp[0] = getc(fp);   /* red */
+      if (bits==32) getc(fp);
       pp += 3;
     }
 
@@ -507,6 +675,70 @@
 
 
 /*******************************************/
+static int loadBMP32(fp, pic24, w, h, colormask) /* 32-bit BI_BITFIELDS only */
+     FILE  *fp;
+     byte  *pic24;
+     u_int w, h, *colormask;
+{
+  int	 x, y;
+  byte	*pp;
+  u_int	 buf;
+  int	 i, bit, bitshift[3], colorbits[3], bitshift2[3];
+
+  for (i = 0; i < 3; ++i) {
+    buf = colormask[i];
+
+    bitshift[i] = 0;
+    for (bit = 0; bit < 32; ++bit) {
+      if (buf & 1)
+	break;
+      else
+	++bitshift[i];
+      buf >>= 1;
+    }
+
+    colorbits[i] = 0;
+    for (; bit < 32; ++bit) {
+      if (buf & 1)
+	++colorbits[i];
+      else
+	break;
+      buf >>= 1;
+    }
+    if (colorbits[i] > 8) {  /* over 8-bit depth */
+      bitshift[i] += (colorbits[i] - 8);
+      bitshift2[i] = 0;
+    } else
+      bitshift2[i] = 8 - colorbits[i];
+  }
+
+  if (DEBUG > 1)
+    fprintf(stderr, "loadBMP32: bitfields\n"
+	    "\tR: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
+	    "\tG: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
+	    "\tB: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n",
+	    colorbits[0], colormask[0], bitshift[0], bitshift2[0],
+	    colorbits[1], colormask[1], bitshift[1], bitshift2[1],
+	    colorbits[2], colormask[2], bitshift[2], bitshift2[2]);
+
+  for (y = h-1; y >= 0; y--) {
+    pp = pic24 + (3 * w * y);
+    if ((y&0x3f)==0) WaitCursor();
+
+    for(x = w; x > 0; x --) {
+      buf = getint(fp);
+      *(pp++) = (buf & colormask[0]) >> bitshift[0] << bitshift2[0];
+      *(pp++) = (buf & colormask[1]) >> bitshift[1] << bitshift2[1];
+      *(pp++) = (buf & colormask[2]) >> bitshift[2] << bitshift2[2];
+    }
+  }
+
+  return FERROR(fp)? 1 : 0;
+}
+
+
+
+/*******************************************/
 static u_int getshort(fp)
      FILE *fp;
 {
@@ -523,7 +755,7 @@
   int c, c1, c2, c3;
   c = getc(fp);  c1 = getc(fp);  c2 = getc(fp);  c3 = getc(fp);
   return  ((u_int) c) +
-         (((u_int) c1) << 8) +
+	 (((u_int) c1) << 8) +
 	 (((u_int) c2) << 16) +
 	 (((u_int) c3) << 24);
 }
diff -ruN xv-3.10a-bugfixes/xvbrowse.c xv-3.10a-enhancements/xvbrowse.c
--- xv-3.10a-bugfixes/xvbrowse.c	2004-05-16 18:01:25.000000000 -0700
+++ xv-3.10a-enhancements/xvbrowse.c	2005-04-25 23:30:27.000000000 -0700
@@ -24,6 +24,10 @@
 typedef unsigned int mode_t;  /* file mode bits */
 #endif
 
+#ifndef MAX
+#  define MAX(a,b) (((a)>(b))?(a):(b))   /* used only for wheelmouse support */
+#endif
+
 
 /* load up built-in icons */
 #include "bits/br_file"
@@ -36,6 +40,7 @@
 #include "bits/br_error"
 /* #include "bits/br_unknown"	commented out (near line 492) */
 #include "bits/br_cmpres"
+#include "bits/br_bzip2"
 
 #include "bits/br_gif"
 #include "bits/br_pm"
@@ -50,11 +55,20 @@
 #include "bits/br_tiff"
 #include "bits/br_pds"
 #include "bits/br_ps"
+#include "bits/br_pcd"
 #include "bits/br_iff"
 #include "bits/br_targa"
 #include "bits/br_xpm"
 #include "bits/br_xwd"
 #include "bits/br_fits"
+#include "bits/br_png"
+#include "bits/br_zx"	/* [JCE] The Spectrum+3 icon */
+#include "bits/br_mag"
+#include "bits/br_maki"
+#include "bits/br_pic"
+#include "bits/br_pi"
+#include "bits/br_pic2"
+#include "bits/br_mgcsfx"
 
 #include "bits/br_trash"
 #include "bits/fcurs"
@@ -94,14 +108,23 @@
 #define BF_XPM      25
 #define BF_XWD      26
 #define BF_FITS     27
-#define BF_MAX      28    /* # of built-in icons */
+#define BF_PNG      28
+#define BF_ZX       29    /* [JCE] Spectrum SCREEN$ */
+#define BF_PCD      30
+#define BF_BZIP2    31
+#define JP_EXT_BF   (BF_BZIP2)
+#define BF_MAG      (JP_EXT_BF + 1)
+#define BF_MAKI     (JP_EXT_BF + 2)
+#define BF_PIC      (JP_EXT_BF + 3)
+#define BF_PI       (JP_EXT_BF + 4)
+#define BF_PIC2     (JP_EXT_BF + 5)
+#define BF_MGCSFX   (JP_EXT_BF + 6)
+#define JP_EXT_BF_END  (BF_MGCSFX)
+#define BF_MAX      (JP_EXT_BF_END + 1)    /* # of built-in icons */
 
 #define ISLOADABLE(ftyp) (ftyp!=BF_DIR  && ftyp!=BF_CHR && ftyp!=BF_BLK && \
 			  ftyp!=BF_SOCK && ftyp!=BF_FIFO)
 
-#define DEF_BROWWIDE 615   /* default size of window */
-#define DEF_BROWHIGH 356
-
 #define SCROLLVERT  8      /* height of scroll region at top/bottom of iconw */
 #define PAGEVERT    40     /* during rect drag, if further than this, page */
 
@@ -113,16 +136,35 @@
 #define BOTMARGIN 58       /* room for a row of buttons and a line of text */
 #define LRMARGINS 5        /* left and right margins */
 
-#define ISIZE_WIDE   80    /* maximum size of an icon */
-#define ISIZE_HIGH   60
+/* some people like bigger icons; 4:3 aspect ratio is recommended
+ * (NOTE:  standard XV binaries will not be able to read larger icons!) */
+#ifndef ISIZE_WIDE
+#  define ISIZE_WIDE 80    /* maximum size of an icon */
+#endif
+#ifndef ISIZE_HIGH
+#  define ISIZE_HIGH 60
+#endif
 
-#define ISPACE_WIDE (ISIZE_WIDE+16)   /* icon spacing */
+#ifndef ISIZE_WPAD
+#  define ISIZE_WPAD 16    /* extra horizontal padding between icons */
+#endif
+
+#ifndef INUM_WIDE
+#  define INUM_WIDE 6      /* size initial window to hold this many icons */
+#endif
+#ifndef INUM_HIGH
+#  define INUM_HIGH 3
+#endif
+
+#define ISPACE_WIDE (ISIZE_WIDE+ISIZE_WPAD)   /* icon spacing */
 #define ISPACE_TOP  4                 /* dist btwn top of ISPACE and ISIZE */
 #define ISPACE_TTOP 4                 /* dist btwn bot of icon and title */
 #define ISPACE_HIGH (ISIZE_HIGH+ISPACE_TOP+ISPACE_TTOP+16+4)
 
 #define DBLCLICKTIME 300  /* milliseconds */
 
+#define COUNT(x) (sizeof (x) / sizeof (x)[0])
+
 /* button/menu indicies */
 #define BR_CHDIR    0
 #define BR_DELETE   1
@@ -140,12 +182,23 @@
 #define BR_NBUTTS   13   /* # of command buttons */
 #define BR_SEP1     13   /* separator */
 #define BR_HIDDEN   14
+#ifdef AUTO_EXPAND
+#define BR_CLEARVD  15
+#define BR_SELFILES 16
+#define BR_NCMDS    17   /* # of menu commands */
+#else
 #define BR_SELFILES 15
 #define BR_NCMDS    16   /* # of menu commands */
+#endif
 
 #define BUTTW 80
 #define BUTTH 24
 
+/* original size of window was 615 x 356 (for 80x60 thumbnails in 6x3 array) */
+#define DEF_BROWWIDE  (ISPACE_WIDE * INUM_WIDE + LRMARGINS * 2 + 29)
+#define DEF_BROWHIGH  (ISPACE_HIGH * INUM_HIGH + BUTTH * 2 + 16 + 28)
+/* last number is a fudge--e.g., extra spaces, borders, etc. -----^  */
+
 static char *showHstr = "Show hidden files";
 static char *hideHstr = "Hide 'hidden' files";
 
@@ -164,6 +217,9 @@
 			    "Close window\t^c",
 			    MBSEP,
 			    "Show hidden files",     /* no equiv */
+#ifdef AUTO_EXPAND
+			    "Clear virtual directory",
+#endif
 			    "Select files...\t^f"
 			    };
 
@@ -209,6 +265,13 @@
 		} BROWINFO;
 
 
+/* keep track of last icon visible in each path */
+typedef struct IVIS IVIS;
+    struct IVIS { IVIS   *next;
+                  char   *name;
+                  int    icon;
+                };
+
 static Cursor   movecurs, copycurs, delcurs;
 static BROWINFO binfo[MAXBRWIN];
 static Pixmap   bfIcons[BF_MAX], trashPix;
@@ -294,10 +357,16 @@
 static void cp_special       PARM((struct stat *, int));
 static void cp_fifo          PARM((struct stat *, int));
 
+#ifdef AUTO_EXPAND
+static int  stat2bf          PARM((u_int, char *));
+#else
 static int  stat2bf          PARM((u_int));
+#endif
 
 static int  selmatch         PARM((char *, char *));
 static int  selmatch1        PARM((char *, char *));
+static void recIconVisible   PARM((char *, int));
+static void restIconVisible  PARM((BROWINFO *));
 
 
 
@@ -511,9 +580,10 @@
   bfIcons[BF_JFIF]=MakePix1(br->win,br_jfif_bits,br_jfif_width,br_jfif_height);
   bfIcons[BF_TIFF]=MakePix1(br->win,br_tiff_bits,br_tiff_width,br_tiff_height);
   bfIcons[BF_PDS] =MakePix1(br->win,br_pds_bits, br_pds_width, br_pds_height);
-
-  bfIcons[BF_COMPRESS]= MakePix1(br->win, br_cmpres_bits,
-				 br_cmpres_width, br_cmpres_height);
+  bfIcons[BF_COMPRESS] = MakePix1(br->win, br_cmpres_bits,
+				  br_cmpres_width, br_cmpres_height);
+  bfIcons[BF_BZIP2] = MakePix1(br->win, br_bzip2_bits,
+			       br_bzip2_width, br_bzip2_height);
 
   bfIcons[BF_PS]  =MakePix1(br->win,br_ps_bits,  br_ps_width,  br_ps_height);
   bfIcons[BF_IFF] =MakePix1(br->win,br_iff_bits, br_iff_width, br_iff_height);
@@ -524,6 +594,16 @@
   bfIcons[BF_XPM] =MakePix1(br->win,br_xpm_bits, br_xpm_width, br_xpm_height);
   bfIcons[BF_XWD] =MakePix1(br->win,br_xwd_bits, br_xwd_width, br_xwd_height);
   bfIcons[BF_FITS]=MakePix1(br->win,br_fits_bits,br_fits_width,br_fits_height);
+  bfIcons[BF_PNG] =MakePix1(br->win,br_png_bits, br_png_width, br_png_height);
+  bfIcons[BF_ZX]  =MakePix1(br->win,br_zx_bits,  br_zx_width,  br_zx_height);
+  bfIcons[BF_PCD] =MakePix1(br->win,br_pcd_bits, br_pcd_width, br_pcd_height);
+  bfIcons[BF_MAG] =MakePix1(br->win,br_mag_bits, br_mag_width, br_mag_height);
+  bfIcons[BF_MAKI]=MakePix1(br->win,br_maki_bits,br_maki_width,br_maki_height);
+  bfIcons[BF_PIC] =MakePix1(br->win,br_pic_bits, br_pic_width, br_pic_height);
+  bfIcons[BF_PI]  =MakePix1(br->win,br_pi_bits,  br_pi_width,  br_pi_height);
+  bfIcons[BF_PIC2]=MakePix1(br->win,br_pic2_bits,br_pic2_width,br_pic2_height);
+  bfIcons[BF_MGCSFX] = MakePix1(br->win,br_mgcsfx_bits,
+                             br_mgcsfx_width,br_mgcsfx_height);
 
 
   /* check that they all got built */
@@ -698,6 +778,9 @@
   }
 }
 
+#ifdef VS_RESCMAP
+static int _IfTempOut=0;
+#endif
 
 /***************************************************************/
 void KillBrowseWindows()
@@ -730,7 +813,6 @@
   return 0;
 }
 
-
 /***************************************************************/
 static int brChkEvent(br, xev)
      BROWINFO *br;
@@ -745,15 +827,32 @@
 
   if (!hasBeenSized) return 0;  /* ignore evrythng until we get 1st Resize */
 
+
+#ifdef VS_RESCMAP
+  /* force change color map if have LocalCmap */
+  if (browPerfect && browCmap && (_IfTempOut==2)) {
+    int i;
+    XSetWindowAttributes xswa;
+
+    xswa.colormap = LocalCmap? LocalCmap : theCmap;
+    for (i=0; i<MAXBRWIN; ++i)
+      XChangeWindowAttributes(theDisp, binfo[i].win, CWColormap, &xswa);
+    XFlush(theDisp);
+    _IfTempOut=1;
+  }
+#endif
+
   if (xev->type == Expose) {
     int x,y,w,h;
     XExposeEvent *e = (XExposeEvent *) xev;
     x = e->x;  y = e->y;  w = e->width;  h = e->height;
 
     /* throw away excess redraws for 'dumb' windows */
-    if (e->count > 0 && (e->window == br->scrl.win)) {}
+    if (e->count > 0 && (e->window == br->scrl.win))
+      ;
 
-    else if (e->window == br->scrl.win) SCRedraw(&(br->scrl));
+    else if (e->window == br->scrl.win)
+      SCRedraw(&(br->scrl));
 
     else if (e->window == br->win || e->window == br->iconW) { /* smart wins */
       /* group individual expose rects into a single expose region */
@@ -806,13 +905,57 @@
     int i,x,y;
     x = e->x;  y = e->y;
 
-    if (e->button == Button1) {
+#ifdef VS_RESCMAP
+    if (browCmap && browPerfect && (_IfTempOut!=0))
+      {
+	  XSetWindowAttributes  xswa;
+	  _IfTempOut--;
+	  xswa.colormap = browCmap;
+	  for(i=0;i<MAXBRWIN;i++)
+	    XChangeWindowAttributes(theDisp, binfo[i].win, CWColormap, &xswa);
+	  XFlush(theDisp);
+      }
+
+#endif
+
+  if (e->button == Button1) {
       if      (e->window == br->win)      clickBrow(br,x,y);
       else if (e->window == br->scrl.win) SCTrack(&(br->scrl),x,y);
       else if (e->window == br->iconW) {
 	i = clickIconWin(br, x,y,(unsigned long) e->time,
 			 (e->state&ControlMask) || (e->state&ShiftMask));
-
+      }
+      else rv = 0;
+    }
+    else if (e->button == Button4) {   /* note min vs. max, + vs. - */
+      /* scroll regardless of where we are in the browser window */
+      if (e->window == br->win ||
+	  e->window == br->scrl.win ||
+	  e->window == br->iconW)
+      {
+	SCRL *sp=&(br->scrl);
+	int  halfpage=MAX(1,sp->page/2); /* user resize to 1 line? */
+
+	if (sp->val > sp->min+halfpage)
+	  SCSetVal(sp,sp->val-halfpage);
+	else
+	  SCSetVal(sp,sp->min);
+      }
+      else rv = 0;
+    }
+    else if (e->button == Button5) {   /* note max vs. min, - vs. + */
+      /* scroll regardless of where we are in the browser window */
+      if (e->window == br->win ||
+	  e->window == br->scrl.win ||
+	  e->window == br->iconW)
+      {
+	SCRL *sp=&(br->scrl);
+	int  halfpage=MAX(1,sp->page/2); /* user resize to 1 line? */
+
+	if (sp->val < sp->max-halfpage)
+	  SCSetVal(sp,sp->val+halfpage);
+	else
+	  SCSetVal(sp,sp->max);
       }
       else rv = 0;
     }
@@ -1101,6 +1244,10 @@
   case BR_SELFILES: doSelFilesCmd(br);   break;
 
   case BR_RECURSUP: doRecurseCmd(br);    break;
+
+#ifdef AUTO_EXPAND
+  case BR_CLEARVD:  Vdsettle();          break;
+#endif
   }
 }
 
@@ -1250,6 +1397,18 @@
   int i, allowtext;
 
   if (!nostr) setSelInfoStr(br, sel);
+#ifdef AUTO_EXPAND
+  if (Isvdir(br->path)) {
+    BTSetActive(&br->but[BR_DELETE],  0);
+    br->cmdMB.dim[BR_DELETE] = 1;
+
+    BTSetActive(&br->but[BR_RENAME],  0);
+    br->cmdMB.dim[BR_RENAME] = 1;
+
+    BTSetActive(&br->but[BR_MKDIR],  0);
+    br->cmdMB.dim[BR_MKDIR] = 1;
+  } else {
+#endif
   BTSetActive(&br->but[BR_DELETE],  br->numlit>0);
   br->cmdMB.dim[BR_DELETE] = !(br->numlit>0);
 
@@ -1258,6 +1417,11 @@
 
   BTSetActive(&br->but[BR_GENICON], br->numlit>0);
   br->cmdMB.dim[BR_GENICON] = !(br->numlit>0);
+#ifdef AUTO_EXPAND
+  BTSetActive(&br->but[BR_MKDIR],  1);
+  br->cmdMB.dim[BR_MKDIR] = 0;
+  }
+#endif
 
   /* turn on 'text view' cmd if exactly one non-dir is lit */
   allowtext = 0;
@@ -1318,8 +1482,11 @@
 	  struct stat st;
 
 	  sprintf(buf, "%s%s", br->path, bf->name);  /* build filename */
+#ifdef AUTO_EXPAND
+	  Dirtovd(buf);
+#endif
 	  if (stat(buf, &st) == 0) {
-	    sprintf(buf, "%s:  %ld bytes", bf->name, st.st_size);
+	    sprintf(buf, "%s:  %ld bytes", bf->name, (long)st.st_size);
 	    strcat(buf, buf1);
 	  }
 	}
@@ -1598,6 +1765,10 @@
 {
   int sval, first, numvis;
 
+  /* if we know what path we have, remember last visible icon for this path */
+  if (br->path)
+    recIconVisible(br->path, num);
+
   /* if icon #i isn't visible, adjust scrollbar so it *is* */
 
   sval = br->scrl.val;
@@ -1649,29 +1820,14 @@
   return;
 }
 
-
 /***************************************************************/
-static int clickIconWin(br, mx, my, mtime, multi)
-     BROWINFO *br;
-     int mx,my,multi;
-     unsigned long mtime;
+static int updateSel(br, sel, multi, mtime)
+  BROWINFO *br;
+  int sel, multi;
+  unsigned long mtime;
 {
-  /* returns '-1' normally, returns an index into bfList[] if the user
-     double-clicks an icon */
-
-  int       i,j, rv, sel, cpymode, dodel;
-  BROWINFO *destBr;
-  BFIL     *bf;
-  char      buf[256], *destFolderName;
-
-  rv = -1;     /* default return value */
-  if (!br->bfList || !br->bfLen) return rv;
-
-  destBr = br;  destFolderName = ".";
-
-  sel = mouseInWhichIcon(br, mx, my);
-
-  dodel = 0;
+  int i;
+  BFIL *bf;
 
   if (sel == -1) {  /* clicked on nothing */
     if (!multi) {   /* deselect all */
@@ -1728,11 +1884,12 @@
 
 
     /* see if we've double-clicked something */
-    if (sel==br->lastIconClicked && mtime-br->lastClickTime < DBLCLICKTIME) {
+    if (mtime &&
+        sel==br->lastIconClicked && mtime-br->lastClickTime < DBLCLICKTIME) {
       br->lastIconClicked = -1;    /* YES */
 
       doubleClick(br, sel);
-      return rv;
+      return -1;
     }
 
     else {
@@ -1741,9 +1898,36 @@
     }
   }
 
-
   changedNumLit(br, -1, 0);
+  return 0;
+}
+
 
+/***************************************************************/
+static int clickIconWin(br, mx, my, mtime, multi)
+     BROWINFO *br;
+     int mx,my,multi;
+     unsigned long mtime;
+{
+  /* returns '-1' normally, returns an index into bfList[] if the user
+     double-clicks an icon */
+
+  int       i,j, sel, cpymode, dodel;
+  BROWINFO *destBr;
+  BFIL     *bf;
+  char      buf[256], *destFolderName;
+
+  if (!br->bfList || !br->bfLen) return -1;
+
+  destBr = br;  destFolderName = ".";
+
+  sel = mouseInWhichIcon(br, mx, my);
+  dodel = 0;
+
+  recIconVisible(br->path, sel);
+
+  if (updateSel(br, sel, multi, mtime))
+    return -1;
 
 
   {    /* track mouse until button1 is released */
@@ -2098,7 +2282,7 @@
     }
   }      /* end of 'tracking' sub-function */
 
-  return rv;
+  return -1;
 }
 
 /*******************************************/
@@ -2164,15 +2348,35 @@
     else sprintf(buf, "%s%s", br->path, br->bfList[sel].name);
 #endif
 
+#ifdef AUTO_EXPAND
+    if (Chvdir(buf)) {
+#else
     if (chdir(buf)) {
+#endif
       char str[512];
       sprintf(str,"Unable to cd to '%s'\n", br->bfList[sel].name);
       setBrowStr(br, str);
       XBell(theDisp, 50);
     }
     else {
+#ifdef AUTO_EXPAND
+      if (Isvdir(buf)) {
+	BTSetActive(&br->but[BR_DELETE],  0);
+	br->cmdMB.dim[BR_DELETE] = 1;
+
+	BTSetActive(&br->but[BR_RENAME],  0);
+	br->cmdMB.dim[BR_RENAME] = 1;
+
+	BTSetActive(&br->but[BR_MKDIR],  0);
+	br->cmdMB.dim[BR_MKDIR] = 1;
+      } else {
+	BTSetActive(&br->but[BR_MKDIR],  1);
+	br->cmdMB.dim[BR_MKDIR] = 0;
+      }
+#endif
       scanDir(br);
       SCSetVal(&(br->scrl), 0);  /* reset to top on a chdir */
+      restIconVisible(br);
     }
   }
 
@@ -2193,6 +2397,28 @@
     }
     else { *event_retP = LOADPIC;  SetDirFName(buf);  }
 
+#ifdef VS_RESCMAP
+    /* Change Colormap for browser */
+    if (browPerfect && browCmap)
+      {
+	  int i;
+	  XSetWindowAttributes  xswa;
+	  if(LocalCmap)
+	    {
+		xswa.colormap = LocalCmap;
+		_IfTempOut=2;
+	    }
+	  else
+	    {
+		xswa.colormap = theCmap;
+		_IfTempOut=2;
+	    }
+	  for(i=0;i<MAXBRWIN;i++)
+	    XChangeWindowAttributes(theDisp, binfo[i].win, CWColormap, &xswa);
+	  XFlush(theDisp);
+      }
+#endif
+
     *event_doneP = 1;     /* make MainLoop load image */
   }
 }
@@ -2347,6 +2573,9 @@
 
 	  /* try to open this file */
 	  sprintf(foo, "%s%s", br->path, br->bfList[i].name);
+#ifdef AUTO_EXPAND
+	Dirtovd(foo);
+#endif
 	  for (j=0; j<numnames && strcmp(namelist[j],foo); j++);
 	  if (j<numnames) {
 	    curname = nList.selected = j;
@@ -2362,6 +2591,9 @@
       else {          /* not SPACE, or SPACE and lit=1 and not shift */
 	for (i=0; i<br->bfLen && !br->bfList[i].lit; i++);  /* find lit one */
 	sprintf(fname, "%s%s", br->path, br->bfList[i].name);
+#ifdef AUTO_EXPAND
+	Dirtovd(fname);
+#endif
 	viewsel = !(strcmp(fname, fullfname));
 
 	if (viewsel) {
@@ -2553,7 +2785,11 @@
     }
 #endif
 
+#ifdef AUTO_EXPAND
+    if (Chvdir(tmppath)) {
+#else
     if (chdir(tmppath)) {
+#endif
       char str[512];
       sprintf(str,"Unable to cd to '%s'\n", tmppath);
       MBRedraw(&(br->dirMB));
@@ -2561,8 +2797,24 @@
       XBell(theDisp, 50);
     }
     else {
+#ifdef AUTO_EXPAND
+      if (Isvdir(tmppath)) {
+	BTSetActive(&br->but[BR_DELETE],  0);
+	br->cmdMB.dim[BR_DELETE] = 1;
+
+	BTSetActive(&br->but[BR_RENAME],  0);
+	br->cmdMB.dim[BR_RENAME] = 1;
+
+	BTSetActive(&br->but[BR_MKDIR],  0);
+	br->cmdMB.dim[BR_MKDIR] = 1;
+      } else {
+	BTSetActive(&br->but[BR_MKDIR],  1);
+	br->cmdMB.dim[BR_MKDIR] = 0;
+      }
+#endif
       scanDir(br);
       SCSetVal(&br->scrl, 0);  /* reset to top of window on a chdir */
+      restIconVisible(br);
     }
   }
 }
@@ -2581,7 +2833,11 @@
   if ((strlen(br->path) > (size_t) 2) && br->path[strlen(br->path)-1] == '/')
     br->path[strlen(br->path)-1] = '\0';
 
+#ifdef AUTO_EXPAND
+  rv = Chvdir(br->path);
+#else
   rv = chdir(br->path);
+#endif
   if (rv) {
     char str[512];
     sprintf(str, "Unable to cd to '%s'\n", br->path);
@@ -2589,6 +2845,23 @@
     XBell(theDisp, 50);
   }
 
+#ifdef AUTO_EXPAND
+  if (Isvdir(br->path)) {
+    BTSetActive(&br->but[BR_DELETE],  0);
+    br->cmdMB.dim[BR_DELETE] = 1;
+
+    BTSetActive(&br->but[BR_RENAME],  0);
+    br->cmdMB.dim[BR_RENAME] = 1;
+
+    BTSetActive(&br->but[BR_MKDIR],  0);
+    br->cmdMB.dim[BR_MKDIR] = 1;
+  } else {
+    BTSetActive(&br->but[BR_MKDIR],  1);
+    br->cmdMB.dim[BR_MKDIR] = 0;
+  }
+#endif
+
+  restIconVisible(br);
   strcat(br->path, "/");   /* put trailing '/' back on */
   return rv;
 }
@@ -2615,8 +2888,13 @@
     strcpy(dstbr->mblist[i], srcbr->mblist[i]);
   }
 
-  dstbr->dirMB.list  = srcbr->mblist;
+#if 0
+  dstbr->dirMB.list  = srcbr->mblist;  /* original bug..? */
   dstbr->dirMB.nlist = srcbr->ndirs;
+#else
+  dstbr->dirMB.list  = dstbr->mblist;  /* fixed by        */
+  dstbr->dirMB.nlist = dstbr->ndirs;   /*   jp-extension. */
+#endif
 
   XClearArea(theDisp, dstbr->dirMB.win, dstbr->dirMB.x, dstbr->dirMB.y,
 	     dstbr->dirMB.w+3, dstbr->dirMB.h+3, False);
@@ -2974,7 +3252,11 @@
 
 
   if (stat(bf->name, &st)==0) {
+#ifdef AUTO_EXPAND
+    bf->ftype = stat2bf((u_int) st.st_mode , bf->name);
+#else
     bf->ftype = stat2bf((u_int) st.st_mode);
+#endif
     if (bf->ftype == BF_FILE && (st.st_mode & 0111)) bf->ftype = BF_EXE;
 
     switch (bf->ftype) {
@@ -3006,6 +3288,7 @@
     case RFT_XBM:      bf->ftype = BF_XBM;      break;
     case RFT_SUNRAS:   bf->ftype = BF_SUNRAS;   break;
     case RFT_BMP:      bf->ftype = BF_BMP;      break;
+    case RFT_WBMP:     bf->ftype = BF_BMP;      break;
     case RFT_UTAHRLE:  bf->ftype = BF_UTAHRLE;  break;
     case RFT_IRIS:     bf->ftype = BF_IRIS;     break;
     case RFT_PCX:      bf->ftype = BF_PCX;      break;
@@ -3013,12 +3296,22 @@
     case RFT_TIFF:     bf->ftype = BF_TIFF;     break;
     case RFT_PDSVICAR: bf->ftype = BF_PDS;      break;
     case RFT_COMPRESS: bf->ftype = BF_COMPRESS; break;
+    case RFT_BZIP2:    bf->ftype = BF_BZIP2;    break;
     case RFT_PS:       bf->ftype = BF_PS;       break;
     case RFT_IFF:      bf->ftype = BF_IFF;      break;
     case RFT_TARGA:    bf->ftype = BF_TARGA;    break;
     case RFT_XPM:      bf->ftype = BF_XPM;      break;
     case RFT_XWD:      bf->ftype = BF_XWD;      break;
     case RFT_FITS:     bf->ftype = BF_FITS;     break;
+    case RFT_PNG:      bf->ftype = BF_PNG;      break;
+    case RFT_ZX:       bf->ftype = BF_ZX;       break;	/* [JCE] */
+    case RFT_PCD:      bf->ftype = BF_PCD;      break;
+    case RFT_MAG:      bf->ftype = BF_MAG;      break;
+    case RFT_MAKI:     bf->ftype = BF_MAKI;     break;
+    case RFT_PIC:      bf->ftype = BF_PIC;      break;
+    case RFT_PI:       bf->ftype = BF_PI;       break;
+    case RFT_PIC2:     bf->ftype = BF_PIC2;     break;
+    case RFT_MGCSFX:   bf->ftype = BF_MGCSFX;   break;
     }
   }
 }
@@ -3405,7 +3698,7 @@
   double  wexpand,hexpand;
   int     iwide, ihigh;
   byte   *icon24, *icon8;
-  char    str[256], str1[256], *readname, uncompname[128];
+  char    str[256], str1[256], readname[128], uncompname[128];
   char    basefname[128], *uncName;
 
 
@@ -3414,7 +3707,7 @@
   basefname[0] = '\0';
   pinfo.pic = (byte *) NULL;
   pinfo.comment = (char *) NULL;
-  readname = bf->name;
+  strncpy(readname, bf->name, sizeof(readname) - 1);
 
   /* free any old info in 'bf' */
   if (bf->imginfo) free          (bf->imginfo);
@@ -3431,7 +3724,7 @@
 
   filetype = ReadFileType(bf->name);
 
-  if (filetype == RFT_COMPRESS) {
+  if ((filetype == RFT_COMPRESS) || (filetype == RFT_BZIP2)) {
 #if (defined(VMS) && !defined(GUNZIP))
     /* VMS decompress doesn't like the file to have a trailing .Z in fname
        however, GUnZip is OK with it, which we are calling UnCompress */
@@ -3442,9 +3735,9 @@
     uncName = bf->name;
 #endif
 
-    if (UncompressFile(uncName, uncompname)) {
+    if (UncompressFile(uncName, uncompname, filetype)) {
       filetype = ReadFileType(uncompname);
-      readname = uncompname;
+      strncpy(readname, uncompname, sizeof(readname) - 1);
     }
     else {
       sprintf(str, "Couldn't uncompress file '%s'", bf->name);
@@ -3453,6 +3746,56 @@
     }
   }
 
+#ifdef MACBINARY
+  if (handlemacb && macb_file == True && bf->ftype != BF_ERROR) {
+    if (RemoveMacbinary(readname, uncompname)) {
+      if (strcmp(readname, bf->name)!=0) unlink(readname);
+      strncpy(readname, uncompname, sizeof(readname) - 1);
+    }
+    else {
+      sprintf(str, "Unable to remove a InfoFile header form '%s'.", bf->name);
+      setBrowStr(br, str);
+      bf->ftype = BF_ERROR;
+    }
+  }
+#endif
+
+#ifdef HAVE_MGCSFX_AUTO
+  if (bf->ftype != BF_ERROR) {
+    if(filetype == RFT_MGCSFX){
+      char tmpname[128];
+      char *icom;
+
+      if((icom = mgcsfx_auto_input_com(bf->name)) != NULL){
+	sprintf(tmpname, "%s/xvmsautoXXXXXX", tmpdir);
+#ifdef USE_MKSTEMP
+	close(mkstemp(tmpname));
+#else
+	mktemp(tmpname);
+#endif
+	SetISTR(ISTR_INFO, "Converting to known format by MgcSfx auto...");
+	sprintf(str,"%s >%s", icom, tmpname);
+      }else goto ms_auto_no;
+
+#ifndef VMS
+      if (system(str))
+#else
+      if (!system(str))
+#endif
+      {
+        sprintf(str, "Unable to convert '%s' by MgcSfx auto.", bf->name);
+        setBrowStr(br, str);
+        bf->ftype = BF_ERROR;
+      } else {
+        filetype = ReadFileType(tmpname);
+        if (strcmp(readname, bf->name)!=0) unlink(readname);
+        strncpy(readname, tmpname, sizeof(readname) - 1);
+      }
+    }
+  }
+ms_auto_no:
+#endif /* HAVE_MGCSFX_AUTO */
+
   /* get rid of comments.  don't need 'em */
   if (pinfo.comment) free(pinfo.comment);  pinfo.comment = (char *) NULL;
 
@@ -3470,6 +3813,9 @@
   else {
     /* otherwise it's a known filetype... do the *hard* part now... */
 
+#ifdef VS_ADJUST
+    normaspect = defaspect;
+#endif
     i = ReadPicFile(readname, filetype, &pinfo, 1);
     KillPageFiles(pinfo.pagebname, pinfo.numpages);
 
@@ -3489,7 +3835,7 @@
   }
 
   /* if we made an uncompressed file, we can rm it now */
-  if (readname != bf->name) unlink(readname);
+  if (strcmp(readname, bf->name)!=0) unlink(readname);
 
 
   /* at this point either BF_ERROR, BF_UNKNOWN, BF_EXE or pic */
@@ -3507,16 +3853,30 @@
 
   /* compute size of icon  (iwide,ihigh) */
 
+#ifdef VS_ADJUST
+  if (!vsadjust) normaspect = 1;
+
+  wexpand = (double) (pinfo.w * normaspect) / (double) ISIZE_WIDE;
+#else
   wexpand = (double) pinfo.w / (double) ISIZE_WIDE;
+#endif /* VS_ADJUST */
   hexpand = (double) pinfo.h / (double) ISIZE_HIGH;
 
   if (wexpand >= 1.0 || hexpand >= 1.0) {   /* don't expand small icons */
     if (wexpand>hexpand) {
+#ifdef VS_ADJUST
+      iwide = (int) ((pinfo.w * normaspect) / wexpand + 0.5);
+#else
       iwide = (int) (pinfo.w / wexpand + 0.5);
+#endif
       ihigh = (int) (pinfo.h / wexpand + 0.5);
     }
     else {
+#ifdef VS_ADJUST
+      iwide = (int) ((pinfo.w * normaspect) / hexpand + 0.5);
+#else
       iwide = (int) (pinfo.w / hexpand + 0.5);
+#endif
       ihigh = (int) (pinfo.h / hexpand + 0.5);
     }
   }
@@ -3566,6 +3926,15 @@
   case RFT_XPM:      strcat(str,"XPM file");              break;
   case RFT_XWD:      strcat(str,"XWD file");              break;
   case RFT_FITS:     strcat(str,"FITS file");             break;
+  case RFT_PNG:      strcat(str,"PNG file");              break;
+  case RFT_ZX:       strcat(str,"Spectrum SCREEN$");      break; /* [JCE] */
+  case RFT_PCD:      strcat(str,"PhotoCD file");          break;
+  case RFT_MAG:      strcat(str,"MAG file");              break;
+  case RFT_MAKI:     strcat(str,"MAKI file");             break;
+  case RFT_PIC:      strcat(str,"PIC file");              break;
+  case RFT_PI:       strcat(str,"PI file");               break;
+  case RFT_PIC2:     strcat(str,"PIC2 file");             break;
+  case RFT_MGCSFX:   strcat(str,"Magic Suffix file");     break;
   default:           strcat(str,"file of unknown type");  break;
   }
 
@@ -3669,6 +4038,10 @@
 
   sprintf(thFname, "%s%s/%s", br->path, THUMBDIR, bf->name);
 
+#ifdef AUTO_EXPAND
+  Dirtovd(thFname);
+#endif
+
   fp = fopen(thFname, "r");
   if (!fp) return;            /* nope, it doesn't have one */
 
@@ -3784,6 +4157,11 @@
 
   sprintf(thFname, "%s%s/%s", br->path, THUMBDIR, bf->name);
 
+#ifdef AUTO_EXPAND
+  Dirtovd(thFname);
+#endif
+
+  unlink(thFname);  /* just in case there's already an unwritable one */
   fp = fopen(thFname, "w");
   if (!fp) {
     sprintf(buf, "Can't create thumbnail file '%s':  %s", thFname,
@@ -3848,15 +4226,30 @@
 
   sprintf(thFname, "%s%s", br->path, THUMBDIRNAME);
 
+#ifdef AUTO_EXPAND
+  Dirtovd(thFname);
+#endif
+
   i = stat(thFname, &st);
   if (i) {                      /* failed, let's create it */
     sprintf(thFname, "%s.", br->path);
+#ifdef AUTO_EXPAND
+  Dirtovd(thFname);
+#endif
     i = stat(thFname, &st);     /* get permissions of parent dir */
     if (!i) perm = st.st_mode & 07777;
        else perm = 0755;
 
     sprintf(thFname, "%s%s", br->path, THUMBDIRNAME);
+#ifdef AUTO_EXPAND
+    Dirtovd(thFname);
+#  ifdef VIRTUAL_TD
+    if (mkdir(thFname, (mode_t) perm) < 0)
+      Mkvdir_force(thFname);
+#  else
     mkdir(thFname, (mode_t) perm);
+#  endif
+#endif
   }
 }
 
@@ -3898,7 +4291,7 @@
   for (i=0, bf=br->bfList; i<br->bfLen; i++, bf++) {
     if (bf->ftype <= BF_FILE || bf->ftype >= BF_ERROR || bf->ftype==BF_EXE) {
 
-      /* ie, not a 'special' file */
+      /* i.e., not a 'special' file */
 
       int  s1, s2;
       char thfname[256];
@@ -3912,10 +4305,9 @@
       sprintf(thfname, "%s/%s", THUMBDIR, bf->name);
       s2 = stat(thfname, &thumbst);
 
-      if (s1 || s2 || filest.st_mtime > thumbst.st_mtime ||
-	              filest.st_ctime > thumbst.st_ctime) {
+      if (s1 || s2 || filest.st_mtime > thumbst.st_mtime) {
 	/* either stat'ing the file or the thumbfile failed, or
-	   both stat's succeeded and the file has a newer mod or creation
+	   both stat's succeeded and the file has a newer mod
 	   time than the thumbnail file */
 
 	makeIconVisible(br, i);
@@ -3927,8 +4319,12 @@
 	  iconsBuilt++;
 	  if (DEBUG)
 	    fprintf(stderr,"icon made:fname='%s' thfname='%s' %d,%d,%ld,%ld\n",
-		    bf->name, thfname, s1,s2,filest.st_mtime,thumbst.st_mtime);
+		    bf->name, thfname, s1, s2,
+		    (long)filest.st_mtime, (long)thumbst.st_mtime);
 	}
+      } else if (filest.st_ctime > thumbst.st_ctime) {
+        /* update protections */
+        chmod(thfname, (mode_t) (filest.st_mode & 07777));
       }
     }
     statcount++;
@@ -3963,7 +4359,11 @@
       sprintf(thfname, "%s/%s", THUMBDIR, dp->d_name);
       if (stat(thfname, &thumbst)==0) {  /* success */
 	int tmp;
+#ifdef AUTO_EXPAND
+	tmp  = stat2bf((u_int) thumbst.st_mode , thfname);
+#else
 	tmp  = stat2bf((u_int) thumbst.st_mode);
+#endif
 
 	if (tmp == BF_FILE) {  /* a plain file */
 	  /* see if this thumbfile has an associated pic file */
@@ -4042,6 +4442,15 @@
   static char *labels[] = { "\nOk", "\033Cancel" };
   struct stat st;
 
+#ifdef AUTO_EXPAND
+  if (Isvdir(br->path)) {
+    sprintf(buf,"Sorry, you can't rename file in the virtual directory, '%s'",
+	    br->path);
+    ErrPopUp(buf, "\nBummer!");
+    return;
+  }
+#endif
+
   if (cdBrow(br)) return;
 
   /* find the selected file */
@@ -4129,6 +4538,15 @@
   static char *labels[] = { "\nOk", "\033Cancel" };
   struct stat  st;
 
+#ifdef AUTO_EXPAND
+  if (Isvdir(br->path)) {
+    sprintf(buf,"Sorry, you can't mkdir in the virtual directory, '%s'",
+	    br->path);
+    ErrPopUp(buf, "\nBummer!");
+    return;
+  }
+#endif
+
   if (cdBrow(br)) return;
 
   buf[0] = '\0';
@@ -4197,14 +4615,34 @@
     if (cdBrow(br)) return;     /* prints its own error message */
   }
 
+#ifdef AUTO_EXPAND
+  if (Chvdir(buf)) {
+#else
   if (chdir(buf)) {
+#endif
     sprintf(str,"Unable to cd to '%s'\n", buf);
     setBrowStr(br, str);
     XBell(theDisp, 50);
   }
   else {
+#ifdef AUTO_EXPAND
+      if (Isvdir(buf)) {
+	BTSetActive(&br->but[BR_DELETE],  0);
+	br->cmdMB.dim[BR_DELETE] = 1;
+
+	BTSetActive(&br->but[BR_RENAME],  0);
+	br->cmdMB.dim[BR_RENAME] = 1;
+
+	BTSetActive(&br->but[BR_MKDIR],  0);
+	br->cmdMB.dim[BR_MKDIR] = 1;
+      } else {
+	BTSetActive(&br->but[BR_MKDIR],  1);
+	br->cmdMB.dim[BR_MKDIR] = 0;
+      }
+#endif
     scanDir(br);
     SCSetVal(&(br->scrl), 0);	/* reset to top on a chdir */
+    restIconVisible(br);
   }
 }
 
@@ -4229,6 +4667,15 @@
   char   buf[512];
   static char *yesno[]  = { "\004Delete", "\033Cancel" };
 
+#ifdef AUTO_EXPAND
+  if (Isvdir(br->path)) {
+    sprintf(buf,"Sorry, you can't delete file at the virtual directory, '%s'",
+	    br->path);
+    ErrPopUp(buf, "\nBummer!");
+    return;
+  }
+#endif
+
   if (!br->bfLen || !br->bfList || !br->numlit) return;
 
   if (cdBrow(br)) return;     /* can't cd to this directory.  screw it! */
@@ -4251,7 +4698,11 @@
   for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) {
     if (bf->lit) {
       if (firstdel == -1) firstdel = i;
-      if (bf->ftype == BF_DIR) numdirs++;
+      if (bf->ftype == BF_DIR
+#ifdef AUTO_EXPAND
+	  && (!Isarchive(bf->name))
+#endif
+			     ) numdirs++;
       else numfiles++;
     }
   }
@@ -4265,7 +4716,12 @@
     slen = strlen(buf);
 
     for (i=0, bf=br->bfList;  i<br->bfLen;  i++,bf++) {
+#ifdef AUTO_EXPAND
+      if (bf->lit && (bf->ftype != BF_DIR || Isarchive(bf->name))) {
+#else
       if (bf->lit && bf->ftype != BF_DIR) {
+#endif
+
 	if ( (slen + strlen(bf->name) + 1) > 256) {
 	  strcat(buf,"...");
 	  break;
@@ -4277,7 +4733,7 @@
       }
     }
 
-    i = PopUp(buf, yesno, 2);
+    i = PopUp(buf, yesno, COUNT(yesno));
     if (i) return;              /* cancelled */
   }
 
@@ -4290,7 +4746,11 @@
     slen = strlen(buf);
 
     for (i=0, bf=br->bfList;  i<br->bfLen;  i++,bf++) {
+#ifdef AUTO_EXPAND
+      if (bf->lit && (bf->ftype == BF_DIR || !Isarchive(bf->name))) {
+#else
       if (bf->lit && bf->ftype == BF_DIR) {
+#endif
 	if ( (slen + strlen(bf->name) + 1) > 256) {
 	  strcat(buf,"...");
 	  break;
@@ -4302,7 +4762,7 @@
       }
     }
 
-    i = PopUp(buf, yesno, 2);
+    i = PopUp(buf, yesno, COUNT(yesno));
     if (i) return;              /* cancelled */
   }
 
@@ -4311,7 +4771,11 @@
 
   for (i=0, bf=br->bfList;  i<br->bfLen;  i++,bf++) {
     if (bf->lit) {
-      if (bf->ftype == BF_DIR) rm_dir (br, bf->name);
+      if (bf->ftype == BF_DIR
+#ifdef AUTO_EXPAND
+	  && !Isarchive(bf->name)
+#endif
+			     ) rm_dir (br, bf->name);
                           else rm_file(br, bf->name);
     }
   }
@@ -4440,7 +4904,11 @@
   xv_getwd(orgDir, sizeof(orgDir));
 
   sprintf(curDir, "%s%s", br->path, subdir);
+#ifdef AUTO_EXPAND
+  if (Chvdir(curDir)) {
+#else
   if (chdir(curDir)) {
+#endif
     char str[512];
     sprintf(str, "Unable to cd to '%s'\n", curDir);
     setBrowStr(br, str);
@@ -4452,14 +4920,24 @@
   /* have we looped? */
   for (i=0; i<dirStackLen && strcmp(curDir, dirStack[i]); i++);
   if (i<dirStackLen) {   /* YES */
+#ifdef AUTO_EXPAND
+    Chvdir(orgDir);
+#else
     chdir(orgDir);
+#endif
+    restIconVisible(br);
     return;
   }
 
   sp = (char *) malloc((size_t) strlen(curDir) + 1);
   if (!sp) {
     setBrowStr(br, "malloc() error in recurseUpdate()\n");
+#ifdef AUTO_EXPAND
+    Chvdir(orgDir);
+#else
     chdir(orgDir);
+#endif
+    restIconVisible(br);
     return;
   }
 
@@ -4494,7 +4972,12 @@
 
   xv_getwd(curDir, sizeof(curDir));
   if (strcmp(orgDir, curDir)) {   /* change back to orgdir */
+#ifdef AUTO_EXPAND
+    Chvdir(orgDir);
+#else
     chdir(orgDir);
+#endif
+    restIconVisible(br);
     scanDir(br);
   }
 }
@@ -4518,6 +5001,13 @@
     setBrowStr(br, buf);
   }
 
+#ifdef AUTO_EXPAND
+  if (Rmvdir(name)) {
+    sprintf(buf, "fail to remove virturl directory: %s", name);
+    setBrowStr(br, buf);
+  }
+#endif
+
   /* try to delete a thumbnail file, as well.  ignore errors */
   strcpy(buf1, name);          /* tmp1 = leading path of name */
   tmp = (char *) rindex(buf1, '/');
@@ -4586,7 +5076,14 @@
 	goto done;
       }
 
-      if (stat2bf((u_int) st.st_mode) == BF_DIR) {  /* skip, for now */
+#ifdef AUTO_EXPAND
+      if ((stat2bf((u_int) st.st_mode , rmdirPath) == BF_DIR)
+	  && !Isarchive(rmdirPath))                /* skip, for now */
+#else
+
+      if (stat2bf((u_int) st.st_mode) == BF_DIR)   /* skip, for now */
+#endif
+      {
 	rmdirPath[oldpathlen] = '\0';
 	continue;   /* don't remove from list */
       }
@@ -4639,9 +5136,9 @@
 
 static int overwrite;
 #define OWRT_ASK    0
-#define OWRT_NOASK  1
-#define OWRT_CANCEL 2
-
+#define OWRT_ALWAYS 1
+#define OWRT_NEVER  2
+#define OWRT_CANCEL 3
 
 /*******************************************/
 static void dragFiles(srcBr, dstBr, srcpath, dstpath, dstdir,
@@ -4676,11 +5173,26 @@
   }
   else if (strcmp(dstdir,".")!=0) sprintf(dstp, "%s%s/", dstpath, dstdir);
 
+#ifdef AUTO_EXPAND
+  if (Isvdir(dstp)) {
+    sprintf(buf,"Sorry, you can't %s to the virtual directory, '%s'",
+	    cpymode ? "copy" : "move", dstp);
+    ErrPopUp(buf, "\nBummer!");
+    SetCursors(-1);
+    return;
+  }
+  if (Isvdir(srcpath))
+      cpymode = 1;
+#endif
+
 
 
   /* if there is a thumbnail directory in 'srcpath', make one for dstpath */
   sprintf(src,"%s%s", srcpath, THUMBDIR);
   dothumbs = 0;
+#ifdef AUTO_EXPAND
+  Dirtovd(src);
+#endif
   if (stat(src, &st)==0) {
     sprintf(dst,"%s%s", dstp, THUMBDIR);
     mkdir(dst, st.st_mode & 07777);
@@ -4711,6 +5223,14 @@
     if (overwrite == OWRT_CANCEL) break;         /* abort move */
     if (j==1) fail++;
 
+#ifdef AUTO_EXPAND
+    if (!cpymode && j==0)
+      if (Movevdir(src,dst)) {
+	sprintf(buf, "fail to move virturl directory: %s", names[i]);
+	setBrowStr(srcBr, buf);
+      }
+#endif
+
     if (dothumbs && j==0) {
       sprintf(src,"%s%s/%s", srcpath, THUMBDIR, names[i]);
       sprintf(dst,"%s%s/%s", dstp,    THUMBDIR, names[i]);
@@ -4748,6 +5268,15 @@
   }
 
 
+  if (!cpymode) {
+    /* clear all lit files in the source folder (as they've been moved)
+       note:  this won't be the optimal behavior if any files failed to
+       move, but screw it, that's not going to happen too often... */
+    for (i=0; i<srcBr->bfLen; i++) srcBr->bfList[i].lit = 0;
+    srcBr->numlit = 0;
+  }
+
+
   /* clear all files in the destination folder */
   for (i=0; i<dstBr->bfLen; i++) {
     dstBr->bfList[i].lit = 0;
@@ -4793,7 +5322,51 @@
   SetCursors(-1);
 }
 
+static int recursive_remove(dir)
+     char *dir;
+{
+  DIR *dp = NULL;
+  struct dirent *di;
+  char name[MAXPATHLEN+1];
+
+  strncpy(name, dir, MAXPATHLEN);
+  name[MAXPATHLEN] = 0;
+
+  if (name[strlen(name) - 1] == '/')
+    name[strlen(name) - 1] = 0;
 
+  if ((dp = opendir(name)) == NULL)
+    goto err;
+
+  while ((di = readdir(dp)) != NULL) {
+    char buf[MAXPATHLEN+1];
+    struct stat st;
+
+    if (!strcmp(di->d_name, ".") || !strcmp(di->d_name, ".."))
+      continue;
+
+    snprintf(buf, MAXPATHLEN, "%s/%s", name, di->d_name);
+
+    if (stat(buf, &st) < 0)
+      continue;
+
+    if (S_ISDIR(st.st_mode)) {
+      if (recursive_remove(buf) < 0)
+	goto err;
+    } else
+      unlink(buf);
+  }
+
+  if (rmdir(name) < 0)
+    goto err;
+
+  closedir(dp);
+  return 0;
+
+err:
+  if (dp) closedir(dp);
+  return -1;
+}
 
 /*************************************************/
 static int moveFile(src,dst)
@@ -4811,31 +5384,45 @@
   int         i, srcdir, dstdir;
   struct stat st;
   char        buf[512];
-  static char  *owbuts[4]  = { "\nOk", "dDon't ask", "nNo", "\033Cancel" };
+  static char  *owbuts[]  = { "\nOk", "aAlways", "nNo", "NNever", "\033Cancel" };
 
   if (DEBUG) fprintf(stderr,"moveFile %s %s\n", src, dst);
 
+#ifdef AUTO_EXPAND
+  Dirtosubst(src);
+#endif
+
   if (stat(src, &st)) return 0;    /* src doesn't exist, it would seem */
+#ifdef AUTO_EXPAND
+  srcdir = (stat2bf((u_int) st.st_mode , src) == BF_DIR);
+#else
   srcdir = (stat2bf((u_int) st.st_mode) == BF_DIR);
+#endif
 
   /* see if destination exists */
+
   if (stat(dst, &st)==0) {
+    if (overwrite==OWRT_NEVER) return -1;
+#ifdef AUTO_EXPAND
+    dstdir = (stat2bf((u_int) st.st_mode , dst) == BF_DIR);
+#else
     dstdir = (stat2bf((u_int) st.st_mode) == BF_DIR);
+#endif
 
     if (overwrite==OWRT_ASK) {
-      sprintf(buf, "%s '%s' exists.\n\nOverwrite?",
+      snprintf(buf, sizeof(buf), "%s '%s' exists.\n\nOverwrite?",
 	      dstdir ? "Directory" : "File", dst);
-      i = PopUp(buf, owbuts, 4);
-
-      if      (i==1) overwrite = OWRT_NOASK;
-      else if (i==2) return -1;
-      else if (i==3) { overwrite = OWRT_CANCEL;  return 1; }
+      switch (PopUp(buf, owbuts, COUNT(owbuts))) {
+	case 1: overwrite = OWRT_ALWAYS; break;
+	case 2: return -1;
+	case 3: overwrite = OWRT_NEVER; return -1;
+	case 4: overwrite = OWRT_CANCEL;  return 1;
+      }
     }
 
     if (dstdir) {
 #ifndef VMS  /* we don't delete directories in VMS */
-      sprintf(buf, "rm -rf %s", dst);
-      if (system(buf)) {     /* okay, so it's cheating... */
+      if (recursive_remove(dst)) {   /* okay, so it's cheating... */
 	SetISTR(ISTR_WARNING, "Unable to remove directory %s", dst);
 	return 1;
       }
@@ -4858,9 +5445,8 @@
   if (i == 0) {    /* copied okay, kill the original */
     if (srcdir) {
 #ifndef VMS   /* we don't delete directories in VMS */
-      sprintf(buf, "rm -rf %s", src);
-      if (system(buf)) {     /* okay, so it's cheating... */
-	SetISTR(ISTR_WARNING, "Unable to remove directory %s", dst);
+      if (recursive_remove(src)) {   /* okay, so it's cheating... */
+	SetISTR(ISTR_WARNING, "Unable to remove directory %s", src);
 	return 1;
       }
 #endif /* VMS */
@@ -4906,38 +5492,51 @@
 	   fall through:  if dest doesn't exist, copy the directory, recurs */
 
 
-  int         i, dstExists, srcdir, dstdir;
+  int         dstExists, srcdir, dstdir;
   struct stat srcSt, dstSt;
   char        buf[1024];
-  static char *owdiff[3] = { "\nOk", "nNo", "\033Cancel" };
-  static char *owsame[4] = { "\nOk", "dDon't Ask", "nNo", "\033Cancel" };
+  static char *owdiff[] = { "\nOk", "nNo", "\033Cancel" };
+  static char *owsame[] = { "\nOk", "aAlways", "nNo", "NNever", "\033Cancel" };
 
   if (DEBUG) fprintf(stderr,"copyFile %s %s\n", src, dst);
 
+#ifdef AUTO_EXPAND
+  Dirtosubst(src);
+#endif
+
   if (stat(src,&srcSt)) return 0;  /* source doesn't exist, it would seem */
 
   dstExists = (stat(dst, &dstSt)==0);
 
   if (dstExists) {   /* ask about overwriting... */
-    srcdir = (stat2bf((u_int) srcSt.st_mode) == BF_DIR);
-    dstdir = (stat2bf((u_int) dstSt.st_mode) == BF_DIR);
+#ifdef AUTO_EXPAND
+  srcdir = (stat2bf((u_int) srcSt.st_mode , src) == BF_DIR);
+  dstdir = (stat2bf((u_int) dstSt.st_mode , dst) == BF_DIR);
+#else
+  srcdir = (stat2bf((u_int) srcSt.st_mode) == BF_DIR);
+  dstdir = (stat2bf((u_int) dstSt.st_mode) == BF_DIR);
+#endif
 
     sprintf(buf, "%s '%s' already exists.  Replace it with %s '%s'?",
 	    (dstdir) ? "Directory" : "File", dst,
 	    (srcdir) ? "contents of directory" : "file", src);
 
     if (srcdir == dstdir) {
+      if (overwrite==OWRT_NEVER) return -1;
       if (overwrite==OWRT_ASK) {
-	i = PopUp(buf, owsame, 4);
-	if (i==1) overwrite = OWRT_NOASK;
-	if (i==2) return -1;
-	else if (i==3) { overwrite = OWRT_CANCEL;  return 1; }
+	switch (PopUp(buf, owsame, COUNT(owsame))) {
+	  case 1: overwrite = OWRT_ALWAYS; break;
+	  case 2: return -1;
+	  case 3: overwrite = OWRT_NEVER; return -1;
+	  case 4: overwrite = OWRT_CANCEL;  return 1;
+	}
       }
     }
     else {     /* one's a dir, the other's a file.  *ALWAYS* ask! */
-      i = PopUp(buf, owdiff, 3);
-      if (i==1) return -1;
-      else if (i==2) { overwrite = OWRT_CANCEL;  return 1; }
+      switch (PopUp(buf, owdiff, COUNT(owdiff))) {
+        case 1: return -1;
+        case 2: overwrite = OWRT_CANCEL;  return 1;
+      }
     }
 
 
@@ -5035,8 +5634,11 @@
     havedst = 1;
   }
 
-
+#ifdef AUTO_EXPAND
+  switch(stat2bf((u_int) srcSt.st_mode , cpDstPath)) {
+#else
   switch(stat2bf((u_int) srcSt.st_mode)) {
+#endif
     /* determine how to copy, by filetype */
 
     /* NOTE:  There is no S_IFLNK case here, since we're using 'stat()' and
@@ -5052,7 +5654,11 @@
     }
   }
   else {
+#ifdef AUTO_EXPAND
+    if (stat2bf((u_int) dstSt.st_mode , cpDstPath) != BF_DIR) {
+#else
     if (stat2bf((u_int) dstSt.st_mode) != BF_DIR) {
+#endif
       SetISTR(ISTR_WARNING,"%s: not a directory", cpDstPath);
       copyerr++;
       return;
@@ -5130,7 +5736,12 @@
       goto done;
     }
 
-    if (stat2bf((u_int) srcSt.st_mode) == BF_DIR) {
+#ifdef AUTO_EXPAND
+    if (stat2bf((u_int) srcSt.st_mode , cpSrcPath) == BF_DIR)
+#else
+    if (stat2bf((u_int) srcSt.st_mode) == BF_DIR)
+#endif
+    {
       cpSrcPath[oldsrclen] = '\0';
       continue;                     /* don't remove from list, just skip */
     }
@@ -5189,9 +5800,9 @@
      int exists;
 /*****************************/
 {
-  register int srcFd, dstFd, rcount, wcount, i;
+  register int srcFd, dstFd, rcount, wcount;
   char         buf[8192];
-  static char  *owbuts[4] = { "\nOk", "dDon't Ask", "nNo", "\033Cancel" };
+  static char  *owbuts[] = { "\nOk", "aAlways", "nNo", "NNever", "\033Cancel" };
 
   if (DEBUG) fprintf(stderr,"cp_file:  src='%s',  dst='%s'\n",
 		     cpSrcPath, cpDstPath);
@@ -5203,13 +5814,15 @@
   }
 
   if (exists) {
+    if (overwrite==OWRT_NEVER) return;
     if (overwrite==OWRT_ASK) {
       sprintf(buf, "File '%s' exists.\n\nOverwrite?", cpDstPath);
-      i = PopUp(buf, owbuts, 4);
-
-      if      (i==1) overwrite = OWRT_NOASK;
-      else if (i==2) return;
-      else if (i==3) { overwrite = OWRT_CANCEL;  return; }
+      switch (PopUp(buf, owbuts, 4)) {
+        case 1: overwrite = OWRT_ALWAYS; break;
+        case 2: return;
+        case 3: overwrite = OWRT_NEVER; return;
+        case 4: overwrite = OWRT_CANCEL;  return;
+      }
     }
     dstFd = open(cpDstPath, O_WRONLY|O_TRUNC, 0);
   }
@@ -5303,8 +5916,14 @@
 
 
 /*********************************/
+#ifdef AUTO_EXPAND
+static int stat2bf(uistmode, path)
+     u_int uistmode;
+     char *path;
+#else
 static int stat2bf(uistmode)
      u_int uistmode;
+#endif
 {
   /* given the 'st.st_mode' field from a successful stat(), returns
      BF_FILE, BF_DIR, BF_BLK, BF_CHR, BF_FIFO, or BF_SOCK.  Does *NOT*
@@ -5318,6 +5937,9 @@
   else if (S_ISBLK(stmode))  rv = BF_BLK;
   else if (S_ISFIFO(stmode)) rv = BF_FIFO;
   else if (S_ISSOCK(stmode)) rv = BF_SOCK;
+#ifdef AUTO_EXPAND
+  else if (Isarchive(path))  rv = BF_DIR;
+#endif
   else                       rv = BF_FILE;
 
   return rv;
@@ -5418,4 +6040,56 @@
 }
 
 
+static IVIS *icon_vis_list = NULL;
+
+/***************************************************************/
+static void recIconVisible(name, icon)
+  char *name;
+  int   icon;
+{
+  IVIS *ptr, *prev = NULL;
+
+  for (ptr = icon_vis_list; ptr; prev = ptr, ptr = ptr->next) {
+    if (!strcmp(ptr->name, name)) {
+      ptr->icon = icon;
+      return;
+    }
+  }
+
+  ptr = calloc(sizeof(IVIS), 1);
+  if (!ptr)
+    return;
+
+  ptr->name = strdup(name);
 
+  if (!ptr->name) {
+    free(ptr);
+    return;
+  }
+
+  if (!prev) {
+    icon_vis_list = ptr;
+  } else {
+    prev->next = ptr;
+  }
+
+  ptr->next = NULL;
+  ptr->icon = icon;
+}
+
+/***************************************************************/
+static void restIconVisible(br)
+  BROWINFO *br;
+{
+  IVIS *ptr;
+
+  for (ptr = icon_vis_list; ptr; ptr = ptr->next) {
+    if (!strcmp(ptr->name, br->path)) {
+      if (ptr->icon >= 0) {
+        makeIconVisible(br, ptr->icon);
+        updateSel(br, ptr->icon, 0, 0);
+      }
+      return;
+    }
+  }
+}
diff -ruN xv-3.10a-bugfixes/xvctrl.c xv-3.10a-enhancements/xvctrl.c
--- xv-3.10a-bugfixes/xvctrl.c	2004-05-23 11:56:37.000000000 -0700
+++ xv-3.10a-enhancements/xvctrl.c	2004-05-23 12:15:18.000000000 -0700
@@ -104,7 +104,8 @@
 			     "Root: centered, warp",
 			     "Root: centered, brick",
     		             "Root: symmetrical tiled",
-			     "Root: symmetrical mirrored" };
+			     "Root: symmetrical mirrored",
+			     "Root: upper left corner" };
 
 static char *conv24MList[] = { "8-bit mode\t\2448",
 			       "24-bit mode\t\2448",
diff -ruN xv-3.10a-bugfixes/xvdial.c xv-3.10a-enhancements/xvdial.c
--- xv-3.10a-bugfixes/xvdial.c	2004-05-16 18:01:57.000000000 -0700
+++ xv-3.10a-enhancements/xvdial.c	2004-05-16 18:06:38.000000000 -0700
@@ -41,20 +41,21 @@
 
 
 /* local functions */
-static int  whereInDial     PARM((DIAL *, int, int));
-static void drawArrow       PARM((DIAL *));
-static void drawValStr      PARM((DIAL *));
-static void drawButt        PARM((DIAL *, int, int));
-static int  computeDialVal  PARM((DIAL *, int, int));
-static void dimDial         PARM((DIAL *));
+static int    whereInDial     PARM((DIAL *, int, int));
+static void   drawArrow       PARM((DIAL *));
+static void   drawValStr      PARM((DIAL *));
+static void   drawButt        PARM((DIAL *, int, int));
+static double computeDialVal  PARM((DIAL *, int, int));
+static void   dimDial         PARM((DIAL *));
 
 
 /***************************************************/
-void DCreate(dp, parent, x, y, w, h, minv, maxv, curv, page,
+void DCreate(dp, parent, x, y, w, h, minv, maxv, curv, inc, page,
 	          fg, bg, hi, lo, title, units)
 DIAL         *dp;
 Window        parent;
-int           x,y,w,h,minv,maxv,curv,page;
+int           x,y,w,h;
+double        minv,maxv,curv,inc,page;
 unsigned long fg,bg,hi,lo;
 char         *title, *units;
 {
@@ -98,18 +99,18 @@
 				1,fg,bg);
   if (!dp->win) FatalError("can't create dial window");
 
-  DSetRange(dp, minv, maxv, curv, page);
+  DSetRange(dp, minv, maxv, curv, inc, page);
   XSelectInput(theDisp, dp->win, ExposureMask | ButtonPressMask);
 }
 
 
 /***************************************************/
-void DSetRange(dp, minv, maxv, curv, page)
-DIAL *dp;
-int   minv, maxv, curv, page;
+void DSetRange(dp, minv, maxv, curv, inc, page)
+DIAL   *dp;
+double  minv, maxv, curv, inc, page;
 {
   if (maxv<minv) maxv=minv;
-  dp->min = minv;    dp->max = maxv;    dp->page = page;
+  dp->min = minv; dp->max = maxv; dp->inc = inc; dp->page = page;
   dp->active =  (minv < maxv);
 
   DSetVal(dp, curv);
@@ -118,8 +119,8 @@
 
 /***************************************************/
 void DSetVal(dp, curv)
-DIAL *dp;
-int   curv;
+DIAL  *dp;
+double curv;
 {
   RANGE(curv, dp->min, dp->max);   /* make sure curv is in-range */
 
@@ -129,7 +130,7 @@
   XSetForeground(theDisp, theGC, dp->bg);
   drawArrow(dp);
 
-  dp->val = curv;
+  dp->val = (double)((int)(curv / dp->inc + (curv > 0 ? 0.5 : -0.5))) * dp->inc;
 
   /* draw new arrow and string */
   XSetForeground(theDisp, theGC, dp->fg);
@@ -202,7 +203,8 @@
 int mx,my;
 {
   Window       rW,cW;
-  int          rx,ry, x,y, ipos, pos, lit, i, origval;
+  int          rx, ry, x, y, ipos, pos, lit;
+  double       origval;
   unsigned int mask;
 
   lit = 0;
@@ -224,9 +226,9 @@
   if (ipos != INDIAL) {
     drawButt(dp, ipos, 1);
     switch (ipos) {
-    case INCW1:  if (dp->val < dp->max) DSetVal(dp, dp->val+1); break;
+    case INCW1:  if (dp->val < dp->max) DSetVal(dp, dp->val+dp->inc);  break;
     case INCW2:  if (dp->val < dp->max) DSetVal(dp, dp->val+dp->page); break;
-    case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-1); break;
+    case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->inc);  break;
     case INCCW2: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->page); break;
     }
     if (dp->drawobj != NULL) (dp->drawobj)();
@@ -235,8 +237,9 @@
   }
 
   else {
-    i = computeDialVal(dp, mx, my);
-    DSetVal(dp, i);
+    double v;
+    v = computeDialVal(dp, mx, my);
+    DSetVal(dp, v);
     if (dp->drawobj != NULL) (dp->drawobj)();
   }
 
@@ -246,11 +249,11 @@
     if (!(mask & Button1Mask)) break;    /* button released */
 
     if (ipos == INDIAL) {
-      int j;
-      i = computeDialVal(dp, x, y);
-      j = dp->val;
-      DSetVal(dp, i);
-      if (j != dp->val) {
+      double v, w;
+      v = computeDialVal(dp, x, y);
+      w = dp->val;
+      DSetVal(dp, v);
+      if (w != dp->val) {
 	/* track whatever dial controls */
 	if (dp->drawobj != NULL) (dp->drawobj)();
       }
@@ -266,11 +269,11 @@
 
       if (lit) {
 	switch (ipos) {
-	case INCW1:  if (dp->val < dp->max) DSetVal(dp, dp->val+1);
+	case INCW1:  if (dp->val < dp->max) DSetVal(dp, dp->val+dp->inc);
 	             break;
 	case INCW2:  if (dp->val < dp->max) DSetVal(dp, dp->val+dp->page);
                      break;
-	case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-1);
+	case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->inc);
                      break;
 	case INCCW2: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->page);
                      break;
@@ -320,19 +323,20 @@
 static void drawArrow(dp)
 DIAL *dp;
 {
-  int i, rad, cx, cy;
+  int rad, cx, cy;
+  double v;
   XPoint arrow[4];
 
   rad = dp->rad;  cx = dp->cx;  cy = dp->cy;
 
   /* map pos (range minv..maxv) into degrees (range 240..-60) */
-  i = 240 + (-300 * (dp->val - dp->min)) / (dp->max - dp->min);
-  arrow[0].x = cx + (int) ((double) rad * .80 * cos(i * DEG2RAD));
-  arrow[0].y = cy - (int) ((double) rad * .80 * sin(i * DEG2RAD));
-  arrow[1].x = cx + (int) ((double) rad * .33 * cos((i+160) * DEG2RAD));
-  arrow[1].y = cy - (int) ((double) rad * .33 * sin((i+160) * DEG2RAD));
-  arrow[2].x = cx + (int) ((double) rad * .33 * cos((i-160) * DEG2RAD));
-  arrow[2].y = cy - (int) ((double) rad * .33 * sin((i-160) * DEG2RAD));
+  v = 240 + (-300 * (dp->val - dp->min)) / (dp->max - dp->min);
+  arrow[0].x = cx + (int) ((double) rad * .80 * cos(v * DEG2RAD));
+  arrow[0].y = cy - (int) ((double) rad * .80 * sin(v * DEG2RAD));
+  arrow[1].x = cx + (int) ((double) rad * .33 * cos((v+160) * DEG2RAD));
+  arrow[1].y = cy - (int) ((double) rad * .33 * sin((v+160) * DEG2RAD));
+  arrow[2].x = cx + (int) ((double) rad * .33 * cos((v-160) * DEG2RAD));
+  arrow[2].y = cy - (int) ((double) rad * .33 * sin((v-160) * DEG2RAD));
   arrow[3].x = arrow[0].x;
   arrow[3].y = arrow[0].y;
   XDrawLines(theDisp, dp->win, theGC, arrow, 4, CoordModeOrigin);
@@ -343,23 +347,37 @@
 static void drawValStr(dp)
 DIAL *dp;
 {
-  int  i, x1, x2;
+  int  tot, i, x1, x2;
   char foo[60], foo1[60];
 
   /* compute longest string necessary so we can right-align this thing */
-  sprintf(foo,"%d",dp->min);    x1 = strlen(foo);
-  sprintf(foo,"%d",dp->max);    x2 = strlen(foo);
+  sprintf(foo,"%d",(int)dp->min);    x1 = strlen(foo);
+  sprintf(foo,"%d",(int)dp->max);    x2 = strlen(foo);
   if (dp->min < 0 && dp->max > 0) x2++;   /* put '+' at beginning */
   i = x1;  if (x2>x1) i = x2;
   if (dp->units) i += strlen(dp->units);
 
-  if (dp->min < 0 && dp->max > 0) sprintf(foo,"%+d", dp->val);
-  else sprintf(foo,"%d", dp->val);
+  sprintf(foo,"%g",dp->inc);   /* space for decimal values */
+  tot = i + strlen(foo) - 1;   /* Take away the 0 from the beginning */
+
+  if (dp->min < 0.0 && dp->max > 0.0) sprintf(foo,"%+g", dp->val);
+  else sprintf(foo,"%g", dp->val);
+
+  if (dp->inc < 1.0)
+  {
+    int j;
+
+    if (dp->val == (double)((int)dp->val))
+      strcat(foo,".");
+
+    for (j = strlen(foo); j < tot; j++)
+      strcat(foo,"0");
+  }
 
   if (dp->units) strcat(foo,dp->units);
   foo1[0] = '\0';
   if (strlen(foo) < (size_t) i) {
-    for (i = i - strlen(foo); i>0; i--) strcat(foo1," ");
+    for (i-=strlen(foo);i>0;i--) strcat(foo1," ");
   }
   strcat(foo1, foo);
 
@@ -411,12 +429,13 @@
 
 
 /***************************************************/
-static int computeDialVal(dp, x, y)
+static double computeDialVal(dp, x, y)
 DIAL *dp;
 int x, y;
 {
-  int dx, dy, val;
-  double angle;
+  int dx, dy;
+
+  double angle, val;
 
   /* compute dx, dy (distance from cx, cy).  Note: +dy is *up* */
   dx = x - dp->cx;  dy = dp->cy - y;
@@ -436,8 +455,10 @@
   if (angle > 270.0) angle -= 360.0;
   if (angle < -90.0) angle += 360.0;
 
-  val = (int) ((dp->max - dp->min) * (240.0 - angle) / 300.0) + dp->min;
+  val = ((dp->max - dp->min) * (240.0 - angle) / 300.0) + dp->min;
 
+  /* round value to be an even multiple of dp->inc */
+  val = (double)((int)(val / dp->inc + 0.5)) * dp->inc;
   return val;
 }
 
diff -ruN xv-3.10a-bugfixes/xvdir.c xv-3.10a-enhancements/xvdir.c
--- xv-3.10a-bugfixes/xvdir.c	2005-03-20 18:38:30.000000000 -0800
+++ xv-3.10a-enhancements/xvdir.c	2005-04-25 22:24:28.000000000 -0700
@@ -62,6 +62,9 @@
 #ifdef HAVE_TIFF
 			       "TIFF",
 #endif
+#ifdef HAVE_PNG
+			       "PNG",
+#endif
 			       "PostScript",
 			       "PBM/PGM/PPM (raw)",
 			       "PBM/PGM/PPM (ascii)",
@@ -73,9 +76,32 @@
 			       "Targa (24-bit)",
 			       "FITS",
 			       "PM",
+			       "Spectrum SCREEN$",	/* [JCE] */
+			       "WBMP",
+#ifdef HAVE_MAG
+			       "MAG",
+#endif
+#ifdef HAVE_PIC
+			       "PIC",
+#endif
+#ifdef HAVE_MAKI
+			       "MAKI (640x400 only)",
+#endif
+#ifdef HAVE_PI
+			       "PI",
+#endif
+#ifdef HAVE_PIC2
+			       "PIC2",
+#endif
+#ifdef HAVE_MGCSFX
+			       "MgcSfx",
+#endif
 			       MBSEP,
 			       "Filename List"};
 
+#ifdef HAVE_PIC2
+extern int PIC2SaveParams    PARM((char *, int));
+#endif
 
 static void arrangeButts     PARM((int));
 static void RedrawDList      PARM((int, SCRL *));
@@ -570,7 +596,11 @@
     }
 #endif
 
+#ifdef AUTO_EXPAND
+    if (Chvdir(tmppath)) {
+#else
     if (chdir(tmppath)) {
+#endif
       char str[512];
       sprintf(str,"Unable to cd to '%s'\n", tmppath);
       *trunc_point = '/';  /* restore the path */
@@ -635,7 +665,11 @@
   xv_getwd(path, sizeof(path));
 #endif
 
+#ifdef AUTO_EXPAND
+  if (Chvdir(path)) {
+#else
   if (chdir(path)) {
+#endif
     ErrPopUp("Current load/save directory seems to have gone away!",
 	     "\nYikes!");
 #ifdef apollo
@@ -643,7 +677,11 @@
 #else
     strcpy(path,"/");
 #endif
+#ifdef AUTO_EXPAND
+    Chvdir(path);
+#else
     chdir(path);
+#endif
   }
 
   changedDir = strcmp(path, oldpath);
@@ -748,6 +786,9 @@
 	else if (S_ISFIFO(ftype)) fnames[i][0] = C_FIFO;
 	else if (S_ISSOCK(ftype)) fnames[i][0] = C_SOCK;
         else if (fnames[i][0] == C_REG && (mode&0111)) fnames[i][0] = C_EXE;
+#ifdef AUTO_EXPAND
+	else if (Isarchive(fnames[i]+1)) fnames[i][0] = C_DIR;
+#endif
       }
       else {
 	/* fprintf(stderr,"problems 'stat-ing' files\n");*/
@@ -847,7 +888,7 @@
     scrollToFileName();
   }
 
-  else if (c=='\010' || c=='\177') {    /* BS or DEL */
+  else if (c=='\010') {                 /* BS */
     if (curPos==0) return(-1);          /* at beginning of str */
     xvbcopy(&filename[curPos], &filename[curPos-1], (size_t) (len-curPos+1));
     curPos--;
@@ -872,7 +913,7 @@
     curPos = len;
   }
 
-  else if (c=='\004') {                 /* ^D: delete character at curPos */
+  else if (c=='\004' || c=='\177') {    /* ^D or DEL: delete character at curPos */
     if (curPos==len) return(-1);
     xvbcopy(&filename[curPos+1], &filename[curPos], (size_t) (len-curPos));
   }
@@ -1055,6 +1096,25 @@
 
   fullname = GetDirFullName();
 
+#ifdef AUTO_EXPAND
+  {
+      char path[MAXPATHLEN];
+
+      GetDirPath(path);
+      Mkvdir(path);
+      if ((i = Isvdir(fullname)) & 01) {
+	  char buf[128];
+	  sprintf(buf,
+		  "Sorry, you can't save file in the virtual directory, '%s'",
+		  path);
+	  ErrPopUp(buf, "\nBummer!");
+	  return -1;
+      }
+      if (i & 06)
+	  Rmvdir(fullname);
+  }
+#endif
+
   fmt = MBWhich(&fmtMB);
   col = MBWhich(&colMB);
 
@@ -1116,7 +1176,34 @@
   }
 #endif
 
+#ifdef HAVE_PNG
+  else if (fmt == F_PNG) {   /* PNG */
+    PNGSaveParams(fullname, col);
+    PNGDialog(1);                   /* open PNG Dialog box */
+    dbut[S_BOK].lit = 0;  BTRedraw(&dbut[S_BOK]);
+    return 0;                      /* always 'succeeds' */
+  }
+#endif
+
+#ifdef HAVE_PIC2
+  else if (fmt == F_PIC2) {   /* PIC2 */
+    if (PIC2SaveParams(fullname, col) < 0)
+	return 0;
+    PIC2Dialog(1);                   /* open PIC2 Dialog box */
+    dbut[S_BOK].lit = 0;  BTRedraw(&dbut[S_BOK]);
+    return 0;                      /* always 'succeeds' */
+  }
+#endif /* HAVE_PIC2 */
 
+#ifdef HAVE_MGCSFX
+  else if (fmt == F_MGCSFX) {   /* MGCSFX */
+    if (MGCSFXSaveParams(fullname, col) < 0)
+	return 0;
+    MGCSFXDialog(1);                   /* open MGCSFX Dialog box */
+    dbut[S_BOK].lit = 0;  BTRedraw(&dbut[S_BOK]);
+    return 0;                      /* always 'succeeds' */
+  }
+#endif /* HAVE_MGCSFX */
 
 
   WaitCursor();
@@ -1164,6 +1251,10 @@
     rv = WriteBMP   (fp, thepic, ptype, w, h, rp, gp, bp, nc, col);
     break;
 
+  case F_WBMP:
+    rv = WriteWBMP  (fp, thepic, ptype, w, h, rp, gp, bp, nc, col);
+    break;
+
   case F_IRIS:
     rv = WriteIRIS  (fp, thepic, ptype, w, h, rp, gp, bp, nc, col);
     break;
@@ -1181,6 +1272,35 @@
     rv = WriteFITS  (fp, thepic, ptype, w, h, rp, gp, bp, nc, col,
 		     picComments);
     break;
+
+  case F_ZX:		/* [JCE] Spectrum SCREEN$ */
+    rv = WriteZX    (fp, thepic, ptype, w, h, rp, gp, bp, nc, col,
+		     picComments);
+    break;
+#ifdef HAVE_MAG
+  case F_MAG:
+    rv = WriteMAG   (fp, thepic, ptype, w, h, rp, gp, bp, nc, col,
+		     picComments);
+    break;
+#endif /* HAVE_MAG */
+#ifdef HAVE_PIC
+  case F_PIC:
+    rv = WritePIC   (fp, thepic, ptype, w, h, rp, gp, bp, nc, col,
+		     picComments);
+    break;
+#endif /* HAVE_PIC */
+#ifdef HAVE_MAKI
+  case F_MAKI:
+    rv = WriteMAKI  (fp, thepic, ptype, w, h, rp, gp, bp, nc, col);
+    break;
+#endif /* HAVE_MAKI */
+
+#ifdef HAVE_PI
+  case F_PI:
+    rv = WritePi    (fp, thepic, ptype, w, h, rp, gp, bp, nc, col,
+		     picComments);
+    break;
+#endif /* HAVE_PI */
   }
 
 
@@ -1310,7 +1430,8 @@
 
   else if (group == F_FORMAT) {
     MBSelect(&fmtMB, bnum);
-    if (MBWhich(&fmtMB) == F_XBM) { /* turn off all but B/W */
+    if (MBWhich(&fmtMB) == F_XBM ||
+	MBWhich(&fmtMB) == F_WBMP) { /* turn off all but B/W */
       colMB.dim[F_FULLCOLOR] = 1;
       colMB.dim[F_GREYSCALE] = 1;
       colMB.dim[F_BWDITHER]  = 0;
@@ -1389,14 +1510,29 @@
       (strcmp(lowsuf,"eps" )==0) ||
       (strcmp(lowsuf,"rgb" )==0) ||
       (strcmp(lowsuf,"tga" )==0) ||
-      (strcmp(lowsuf,"xpm" )==0) ||
       (strcmp(lowsuf,"fits")==0) ||
       (strcmp(lowsuf,"fts" )==0) ||
+#ifdef HAVE_JPEG
       (strcmp(lowsuf,"jpg" )==0) ||
       (strcmp(lowsuf,"jpeg")==0) ||
       (strcmp(lowsuf,"jfif")==0) ||
+#endif
+#ifdef HAVE_TIFF
       (strcmp(lowsuf,"tif" )==0) ||
-      (strcmp(lowsuf,"tiff")==0)) {
+      (strcmp(lowsuf,"tiff")==0) ||
+#endif
+#ifdef HAVE_PNG
+      (strcmp(lowsuf,"png" )==0) ||
+#endif
+      (strcmp(lowsuf,"wbmp")==0) ||
+      (strcmp(lowsuf,"xpm" )==0) ||
+      (strcmp(lowsuf,"tiff")==0) ||
+      (strcmp(lowsuf,"mag" )==0) ||
+      (strcmp(lowsuf,"pic" )==0) ||
+      (strcmp(lowsuf,"mki" )==0) ||
+      (strcmp(lowsuf,"pi"  )==0) ||
+      (strcmp(lowsuf,"p2"  )==0) ||
+      (strcmp(lowsuf,"pcd" )==0)) {
 
     /* found one.  set lowsuf = to the new suffix, and tack on to filename */
 
@@ -1419,6 +1555,7 @@
     case F_XBM:      strcpy(lowsuf,"xbm");  break;
     case F_SUNRAS:   strcpy(lowsuf,"ras");  break;
     case F_BMP:      strcpy(lowsuf,"bmp");  break;
+    case F_WBMP:     strcpy(lowsuf,"wbmp"); break;
     case F_PS:       strcpy(lowsuf,"ps");   break;
     case F_IRIS:     strcpy(lowsuf,"rgb");  break;
     case F_TARGA:    strcpy(lowsuf,"tga");  break;
@@ -1432,8 +1569,33 @@
 #ifdef HAVE_TIFF
     case F_TIFF:     strcpy(lowsuf,"tif");  break;
 #endif
+
+#ifdef HAVE_PNG
+    case F_PNG:      strcpy(lowsuf,"png");  break;
+#endif
+
+#ifdef HAVE_MAG
+    case F_MAG:      strcpy(lowsuf,"mag");  break;
+#endif
+
+#ifdef HAVE_PIC
+    case F_PIC:      strcpy(lowsuf,"pic");  break;
+#endif
+
+#ifdef HAVE_MAKI
+    case F_MAKI:     strcpy(lowsuf,"mki");  break;
+#endif
+
+#ifdef HAVE_PI
+    case F_PI:       strcpy(lowsuf,"pi");   break;
+#endif
+
+#ifdef HAVE_PIC2
+    case F_PIC2:     strcpy(lowsuf,"p2");   break;
+#endif
     }
 
+
     if (allcaps) {  /* upper-caseify lowsuf */
       for (sp=lowsuf; *sp; sp++)
 	*sp = (islower(*sp)) ? toupper(*sp) : *sp;
@@ -1499,6 +1661,11 @@
   }
 #endif
 
+#ifdef AUTO_EXPAND
+  Mkvdir(newpath);
+  Dirtovd(newpath);
+#endif
+
   if (stat(newpath, &st)==0) {
     int isdir;
 
@@ -1596,7 +1763,11 @@
   dopipe = 0;
 
   /* make sure we're in the correct directory */
+#ifdef AUTO_EXPAND
+  if (strlen(path)) Chvdir(path);
+#else
   if (strlen(path)) chdir(path);
+#endif
 
   if (ISPIPE(filename[0])) {   /* do piping */
     /* make up some bogus temp file to put this in */
@@ -2002,7 +2173,7 @@
     if (stat(namelist[curname], &origStat)==0) {
       haveStat = 1;
       if (DEBUG) fprintf(stderr," origStat.size=%ld,  origStat.mtime=%ld\n",
-			 origStat.st_size, origStat.st_mtime);
+			 (long)origStat.st_size, (long)origStat.st_mtime);
     }
   }
 }
@@ -2027,7 +2198,7 @@
 
     if (stat(namelist[curname], &st)==0) {
       if (DEBUG) fprintf(stderr," st.size=%ld,  st.mtime=%ld\n",
-			 st.st_size, st.st_mtime);
+			 (long)st.st_size, (long)st.st_mtime);
 
       if ((st.st_size  == origStat.st_size) &&
 	  (st.st_mtime == origStat.st_mtime)) return 0;  /* no change */
@@ -2080,3 +2251,164 @@
 }
 
 
+#ifdef HAVE_PIC2
+/**** Stuff for PIC2Dialog box ****/
+FILE *pic2_OpenOutFile(filename, append)
+char *filename;
+int *append;
+{
+    /* opens file for output.  does various error handling bits.  Returns
+       an open file pointer if success, NULL if failure */
+
+    FILE *fp = NULL;
+    struct stat st;
+
+    if (!filename || filename[0] == '\0')
+	return (NULL);
+    strcpy(outFName, filename);
+    dopipe = 0;
+
+    /* make sure we're in the correct directory */
+#ifdef AUTO_EXPAND
+    if (strlen(path)) Chvdir(path);
+#else
+    if (strlen(path)) chdir(path);
+#endif
+
+    if (ISPIPE(filename[0])) {   /* do piping */
+	/* make up some bogus temp file to put this in */
+#ifndef VMS
+	sprintf(outFName, "%s/xvXXXXXX", tmpdir);
+#else
+	strcpy(outFName, "[]xvXXXXXX.lis");
+#endif
+#ifdef USE_MKSTEMP
+	fp = fdopen(mkstemp(outFName), "w");
+#else
+	mktemp(outFName);
+#endif
+	dopipe = 1;
+    }
+
+
+    /* see if file exists (i.e., we're overwriting) */
+    *append = 0;
+#ifdef USE_MKSTEMP
+    if (!dopipe)
+#endif
+    if (stat(outFName, &st)==0) {    /* stat succeeded, file must exist */
+	if (ReadFileType(outFName) != RFT_PIC2) {
+	    static char *foo[] = { "\nOk", "\033Cancel" };
+	    char str[512];
+
+	    sprintf(str,"Overwrite existing file '%s'?", outFName);
+	    if (PopUp(str, foo, 2))
+		return (NULL);
+	} else {
+	    static char *foo[] = { "\nOk", "\033Cancel" };
+	    char str[512];
+
+	    sprintf(str,"Append to existing file '%s'?", outFName);
+	    if (PopUp(str, foo, 2)) {
+		sprintf(str,"Overwrite existing file '%s'?", outFName);
+		if (PopUp(str, foo, 2))
+		    return (NULL);
+	    } else
+		*append = 1;
+	}
+    }
+
+    /* Open file */
+#ifdef USE_MKSTEMP
+    if (!dopipe)
+#endif
+    fp = *append ? fopen(outFName, "r+") : fopen(outFName, "w");
+    if (!fp) {
+	char  str[512];
+	sprintf(str,"Can't write file '%s'\n\n  %s.",outFName, ERRSTR(errno));
+	ErrPopUp(str, "\nBummer");
+	return (NULL);
+    }
+
+    return (fp);
+}
+
+
+/***************************************/
+void pic2_KillNullFile(fp)
+FILE *fp;
+{
+    fseek(fp, (size_t) 0, SEEK_END);
+    if (ftell(fp) > 0) {
+	fclose(fp);
+	return;
+    } else {
+	fclose(fp);
+	unlink(outFName);
+	return;
+    }
+}
+#endif /* HAVE_PIC2 */
+
+
+#ifdef HAVE_MGCSFX
+/**** Stuff for MGCSFX Dialog box ****/
+/***************************************/
+int OpenOutFileDesc(filename)
+     char *filename;
+{
+  /* opens file for output.  does various error handling bits.  Returns
+     an open file pointer if success, NULL if failure */
+
+  int         fd;
+  struct stat st;
+
+  if (!filename || filename[0] == '\0') return -1;
+  strcpy(outFName, filename);
+  dopipe = 0;
+
+  /* make sure we're in the correct directory */
+#ifdef AUTO_EXPAND
+  if (strlen(path)) Chvdir(path);
+#else
+  if (strlen(path)) chdir(path);
+#endif
+
+  if (ISPIPE(filename[0])) {   /* do piping */
+    /* make up some bogus temp file to put this in */
+#ifndef VMS
+    sprintf(outFName, "%s/xvXXXXXX", tmpdir);
+#else
+    strcpy(outFName, "[]xvXXXXXX.lis");
+#endif
+#ifdef USE_MKSTEMP
+    close(mkstemp(outFName));
+#else
+    mktemp(outFName);
+#endif
+    dopipe = 1;
+  }
+
+
+  /* if didn't just create it, see if file exists (i.e., we're overwriting) */
+  if (!dopipe && stat(outFName, &st)==0) {   /* stat succeeded, file exists */
+    static char *foo[] = { "\nOk", "\033Cancel" };
+    char str[512];
+
+    sprintf(str,"Overwrite existing file '%s'?", outFName);
+    if (PopUp(str, foo, 2)) return -1;
+  }
+
+
+  /* Open file */
+  fd = open(outFName, O_WRONLY | O_CREAT | O_TRUNC, (0644));
+  if (fd < 0) {
+    char  str[512];
+    sprintf(str,"Can't write file '%s'\n\n  %s.", outFName, ERRSTR(errno));
+    ErrPopUp(str, "\nBummer");
+    return -1;
+  }
+
+  return fd;
+}
+#endif /* HAVE_MGCSFX */
diff -ruN xv-3.10a-bugfixes/xvevent.c xv-3.10a-enhancements/xvevent.c
--- xv-3.10a-bugfixes/xvevent.c	2004-05-16 18:02:03.000000000 -0700
+++ xv-3.10a-enhancements/xvevent.c	2005-05-01 09:33:38.000000000 -0700
@@ -64,6 +64,8 @@
 
 static void   annotatePic      PARM((void));
 
+static int    debkludge_offx;
+static int    debkludge_offy;
 
 /****************/
 int EventLoop()
@@ -71,13 +73,25 @@
 {
   XEvent event;
   int    retval,done,waiting;
-  time_t orgtime, curtime;
+#ifdef USE_TICKS
+  clock_t waitsec_ticks=0L, orgtime_ticks=0L, curtime_ticks;
+  clock_t elapsed_ticks=0L, remaining_interval;
+#else
+  time_t orgtime=0L, curtime;
+#endif
 
 
 #ifndef NOSIGNAL
   signal(SIGQUIT, onInterrupt);
 #endif
 
+  if (startGrab == 1) {
+     startGrab = 2;
+     FakeButtonPress(&but[BGRAB]);
+     FakeKeyPress(ctrlW, XK_Return);
+     return(1);
+  }
+
   /* note: there's no special event handling if we're using the root window.
      if we're using the root window, we will recieve NO events for mainW */
 
@@ -100,18 +114,24 @@
 
   while (!done) {
 
-    if (waitsec > -1 && canstartwait && !waiting && XPending(theDisp)==0) {
+    if (waitsec >= 0.0 && canstartwait && !waiting && XPending(theDisp)==0) {
       /* we wanna wait, we can wait, we haven't started waiting yet, and
 	 all pending events (ie, drawing the image the first time)
 	 have been dealt with:  START WAITING */
-      time((time_t *) &orgtime);
+#ifdef USE_TICKS
+      waitsec_ticks = (clock_t)(waitsec * CLK_TCK);
+      orgtime_ticks = times(NULL);  /* unclear if NULL valid, but OK on Linux */
+#else
+      orgtime = time(NULL);
+#endif
       waiting = 1;
     }
 
 
     /* if there's an XEvent pending *or* we're not doing anything
        in real-time (polling, flashing the selection, etc.) get next event */
-    if ((waitsec==-1 && !polling && !HaveSelection()) || XPending(theDisp)>0) {
+    if ((waitsec<0.0 && !polling && !HaveSelection()) || XPending(theDisp)>0)
+    {
       XNextEvent(theDisp, &event);
       retval = HandleEvent(&event,&done);
     }
@@ -121,7 +141,7 @@
 	DrawSelection(0);
 	DrawSelection(1);
 	XFlush(theDisp);
-	Timer(200);
+	Timer(200);             /* milliseconds */
       }
 
       if (polling) {
@@ -129,13 +149,32 @@
 	else if (!XPending(theDisp)) sleep(1);
       }
 
-      if (waitsec>-1 && waiting) {
-	time((time_t *) &curtime);
-	if (curtime - orgtime < waitsec) sleep(1);
-	else {
-	  if (waitloop) return NEXTLOOP;
-	  else return NEXTQUIT;
-	}
+      if (waitsec>=0.0 && waiting) {
+#ifdef USE_TICKS
+        curtime_ticks = times(NULL);   /* value in ticks */
+        if (curtime_ticks < orgtime_ticks) {
+          /* clock ticks rolled over:  need to correct for that (i.e.,
+           *  curtime_ticks is presumably quite small, while orgtime_ticks
+           *  should be close to LONG_MAX, so do math accordingly--any way
+           *  to check whether clock_t is *not* a signed long?) */
+          elapsed_ticks = curtime_ticks + (LONG_MAX - orgtime_ticks);
+        } else
+          elapsed_ticks = curtime_ticks - orgtime_ticks;
+        remaining_interval = waitsec_ticks - elapsed_ticks;
+        if (remaining_interval >= (clock_t)(1 * CLK_TCK))
+          sleep(1);
+        else {
+          /* less than one second remaining:  do delay in msec, then return */
+          Timer((remaining_interval * 1000L) / CLK_TCK);  /* can't overflow */
+          return waitloop? NEXTLOOP : NEXTQUIT;
+        }
+#else
+        curtime = time(NULL);          /* value in seconds */
+	if (curtime - orgtime < (time_t)waitsec)
+          sleep(1);
+	else
+          return waitloop? NEXTLOOP : NEXTQUIT;
+#endif
       }
     }
   }  /* while (!done) */
@@ -154,7 +193,24 @@
      int    *donep;
 {
   static int wasInfoUp=0, wasCtrlUp=0, wasDirUp=0, wasGamUp=0, wasPsUp=0;
-  static int wasJpegUp=0, wasTiffUp=0;
+#ifdef HAVE_JPEG
+  static int wasJpegUp=0;
+#endif
+#ifdef HAVE_TIFF
+  static int wasTiffUp=0;
+#endif
+#ifdef HAVE_PNG
+  static int wasPngUp=0;
+#endif
+#ifdef HAVE_PCD
+  static int wasPcdUp=0;
+#endif
+#ifdef HAVE_PIC2
+  static int wasPic2Up=0;
+#endif
+#ifdef HAVE_MGCSFX
+  static int wasMgcSfxUp=0;
+#endif
 
   static int mainWKludge=0;  /* force first mainW expose after a mainW config
 				to redraw all of mainW */
@@ -233,6 +289,28 @@
     if (TIFFCheckEvent(event)) break;   /* event has been processed */
 #endif
 
+#ifdef HAVE_PNG
+    if (PNGCheckEvent (event)) break;   /* event has been processed */
+#endif
+
+    if (PCDCheckEvent(event)) break;    /* event has been processed */
+
+#ifdef HAVE_PIC2
+    if (PIC2CheckEvent(event)) break;   /* event has been processed */
+#endif
+
+#ifdef HAVE_PCD
+    if (PCDCheckEvent (event)) break;   /* event has been processed */
+#endif
+
+#ifdef HAVE_MGCSFX
+    if (MGCSFXCheckEvent(event)) break; /* event has been processed */
+#endif
+
+#ifdef TV_MULTILINGUAL
+    if (CharsetCheckEvent(event)) break; /* event has been processed */
+#endif
+
     if (GamCheckEvent (event)) break;   /* event has been processed */
     if (BrowseCheckEvent (event, &retval, &done)) break;   /* event eaten */
     if (TextCheckEvent   (event, &retval, &done)) break;   /* event eaten */
@@ -344,6 +422,9 @@
 
       if (BrowseDelWin(client_event->window)) break;
       if (TextDelWin(client_event->window)) break;
+#ifdef TV_MULTILINGUAL
+      if (CharsetDelWin(client_event->window)) break;
+#endif
 
       if      (client_event->window == infoW) InfoBox(0);
       else if (client_event->window == gamW)  GamBox(0);
@@ -359,6 +440,24 @@
       else if (client_event->window == tiffW) TIFFDialog(0);
 #endif
 
+#ifdef HAVE_PNG
+      else if (client_event->window == pngW)  PNGDialog(0);
+#endif
+
+      else if (client_event->window == pcdW)  PCDDialog(0);
+
+#ifdef HAVE_PIC2
+      else if (client_event->window == pic2W) PIC2Dialog(0);
+#endif
+
+#ifdef HAVE_PCD
+      else if (client_event->window == pcdW)  PCDDialog(0);
+#endif
+
+#ifdef HAVE_MGCSFX
+      else if (client_event->window == mgcsfxW) MGCSFXDialog(0);
+#endif
+
       else if (client_event->window == mainW) Quit(0);
     }
   }
@@ -534,10 +633,21 @@
 #ifdef HAVE_JPEG
 	if (wasJpegUp) { JPEGDialog(wasJpegUp);  wasJpegUp=0; }
 #endif
-
 #ifdef HAVE_TIFF
 	if (wasTiffUp) { TIFFDialog(wasTiffUp);  wasTiffUp=0; }
 #endif
+#ifdef HAVE_PNG
+	if (wasPngUp)  { PNGDialog(wasJpegUp);   wasPngUp=0; }
+#endif
+#ifdef HAVE_PCD
+	if (wasPcdUp)  { PCDDialog(wasPcdUp);    wasPcdUp=0; }
+#endif
+#ifdef HAVE_PIC2
+	if (wasPic2Up) { PIC2Dialog(wasPic2Up);  wasPic2Up=0; }
+#endif
+#ifdef HAVE_MGCSFX
+	if (wasMgcSfxUp) { MGCSFXDialog(wasMgcSfxUp);  wasMgcSfxUp=0; }
+#endif
       }
     }
   }
@@ -572,10 +682,21 @@
 #ifdef HAVE_JPEG
 	  if (jpegUp) { wasJpegUp = jpegUp;  JPEGDialog(0); }
 #endif
-
 #ifdef HAVE_TIFF
 	  if (tiffUp) { wasTiffUp = tiffUp;  TIFFDialog(0); }
 #endif
+#ifdef HAVE_PNG
+	  if (pngUp)  { wasPngUp  = pngUp;   PNGDialog(0); }
+#endif
+#ifdef HAVE_PCD
+	  if (pcdUp)  { wasPcdUp = pcdUp;    PCDDialog(0); }
+#endif
+#ifdef HAVE_PIC2
+	  if (pic2Up) { wasPic2Up = pic2Up;  PIC2Dialog(0); }
+#endif
+#ifdef HAVE_MGCSFX
+	  if (mgcsfxUp) { wasMgcSfxUp = mgcsfxUp;  MGCSFXDialog(0); }
+#endif
 	}
       }
     }
@@ -641,6 +762,30 @@
 	p_offy = xwa.y;
       }
 
+      /* Gather info to keep right border inside */
+      {
+	Window current;
+	Window root_r;
+	Window parent_r;
+	Window *children_r;
+	int nchildren_r;
+	XWindowAttributes xwa;
+
+	parent_r=mainW;
+	current=mainW;
+	do {
+	  current=parent_r;
+	  XQueryTree(theDisp, current, &root_r, &parent_r,
+		     &children_r, &nchildren_r);
+	  if (children_r!=NULL) {
+	    XFree(children_r);
+	  }
+	} while(parent_r!=root_r);
+	XGetWindowAttributes(theDisp, current, &xwa);
+	debkludge_offx=eWIDE-xwa.width+p_offx;
+	debkludge_offy=eHIGH-xwa.height+p_offy;
+      }
+
 
       /* move window around a bit... */
       {
@@ -997,7 +1142,8 @@
 
   int          i;
   char         txt[512], str[PRINTCMDLEN + 10];
-  static char *labels[] = { " Color", " Grayscale", " B/W", "\033Cancel" };
+  static char *labels[] = { "\03Color", "\07Grayscale", " B/W", "\033Cancel" };
+                          /* ^B ("\02") already used for moving cursor back */
 
   strcpy(txt, "Print:  Enter a command that will read a PostScript file ");
   strcat(txt, "from stdin and print it to the desired printer.\n\n");
@@ -1147,6 +1293,26 @@
     if (TIFFCheckEvent(event)) break;
 #endif
 
+#ifdef HAVE_PNG
+    if (PNGCheckEvent (event)) break;
+#endif
+
+#ifdef HAVE_PCD
+    if (PCDCheckEvent (event)) break;	/* event has been processed */
+#endif
+
+#ifdef HAVE_PIC2
+    if (PIC2CheckEvent(event)) break;
+#endif
+
+#ifdef HAVE_MGCSFX
+    if (MGCSFXCheckEvent(event)) break;
+#endif
+
+#ifdef TV_MULTILINGUAL
+    if (CharsetCheckEvent(event)) break;
+#endif
+
     if (GamCheckEvent (event)) break;
     if (BrowseCheckEvent (event, &retval, &done)) break;
     if (TextCheckEvent   (event, &retval, &done)) break;
@@ -1276,6 +1442,48 @@
       else if (shift) BlurPaint();
       break;
 
+    case Button4:   /* note min vs. max, + vs. - */
+      if (win == ctrlW || win == nList.win || win == nList.scrl.win) {
+	SCRL *sp=&nList.scrl;
+	int  halfpage=sp->page/2;
+
+	if (sp->val > sp->min+halfpage)
+	  SCSetVal(sp,sp->val-halfpage);
+	else
+	  SCSetVal(sp,sp->min);
+      }
+      else if (win ==  dirW || win == dList.win || win == dList.scrl.win) {
+	SCRL *sp=&dList.scrl;
+	int  halfpage=sp->page/2;
+
+	if (sp->val > sp->min+halfpage)
+	  SCSetVal(sp,sp->val-halfpage);
+	else
+	  SCSetVal(sp,sp->min);
+      }
+      break;
+
+    case Button5:   /* note max vs. min, - vs. + */
+      if (win == ctrlW || win == nList.win || win == nList.scrl.win) {
+	SCRL *sp=&nList.scrl;
+	int  halfpage=sp->page/2;
+
+	if (sp->val < sp->max-halfpage)
+	  SCSetVal(sp,sp->val+halfpage);
+	else
+	  SCSetVal(sp,sp->max);
+      }
+      else if (win ==  dirW || win == dList.win || win == dList.scrl.win) {
+	SCRL *sp=&dList.scrl;
+	int  halfpage=sp->page/2;
+
+	if (sp->val < sp->max-halfpage)
+	  SCSetVal(sp,sp->val+halfpage);
+	else
+	  SCSetVal(sp,sp->max);
+      }
+      break;
+
     default:       break;
     }
   }
@@ -1364,16 +1572,35 @@
     if (TIFFCheckEvent(event)) break;
 #endif
 
+#ifdef HAVE_PNG
+    if (PNGCheckEvent (event)) break;
+#endif
+
+    if (PCDCheckEvent (event)) break;
+
+#ifdef HAVE_PIC2
+    if (PIC2CheckEvent(event)) break;
+#endif
+
+#ifdef HAVE_PCD
+    if (PCDCheckEvent (event)) break;
+#endif
+
+#ifdef HAVE_MGCSFX
+    if (MGCSFXCheckEvent(event)) break;
+#endif
+
     if (GamCheckEvent (event)) break;
     if (BrowseCheckEvent (event, &retval, &done)) break;
     if (TextCheckEvent   (event, &retval, &done)) break;
 
 
-    /* check for pageup/pagedown, 'p' in main window
-       (you can use shift-up or shift-down if no crop rectangle drawn)
-       (for viewing multipage docs) */
+    /* Support for multi-image files ("multipage docs").  Check for PgUp/PgDn
+       or 'p' in any window but control or directory; PgUp/PgDn are already
+       used to page through the file list in those windows.  If no cropping
+       rectangle is active, shift-Up and shift-Down also work. */
 
-    if (key_event->window == mainW) {
+    if (key_event->window != ctrlW && key_event->window != dirW) {
       dealt = 1;
 
       ck = CursorKey(ks, shift, 0);
@@ -1578,13 +1805,13 @@
 	}
 	break;
 
-      case '\010':
-      case '\177': FakeButtonPress(&but[BPREV]);    break;
+      case '\010': FakeButtonPress(&but[BPREV]);    break;
 
 
       case '\014': FakeButtonPress(&but[BLOAD]);    break;  /* ^L */
       case '\023': FakeButtonPress(&but[BSAVE]);    break;  /* ^S */
       case '\020': FakeButtonPress(&but[BPRINT]);   break;  /* ^P */
+      case '\177':
       case '\004': FakeButtonPress(&but[BDELETE]);  break;  /* ^D */
 
 	/* BCOPY, BCUT, BPASTE, BCLEAR handled in 'meta' case */
@@ -2025,6 +2252,16 @@
   if (xwa->width  < dispWIDE && xwc.x < p_offx) xwc.x = p_offx;
   if (xwa->height < dispHIGH && xwc.y < p_offy) xwc.y = p_offy;
 
+  /* Try to keep bottom right decorations inside */
+  if (xwc.x+eWIDE-debkludge_offx>dispWIDE) {
+    xwc.x=dispWIDE-eWIDE+debkludge_offx;
+    if (xwc.x<0) xwc.x=0;
+  }
+  if (xwc.y+eHIGH-debkludge_offy>dispHIGH) {
+    xwc.y=dispHIGH-eHIGH+debkludge_offy;
+    if (xwc.y<0) xwc.y=0;
+  }
+
   xwc.width  = xwa->width;
   xwc.height = xwa->height;
 
@@ -2370,6 +2607,24 @@
   if (tiffUp) TIFFDialog(0);  /* close tiff window */
 #endif
 
+#ifdef HAVE_PNG
+  if (pngUp) PNGDialog(0);    /* close png window */
+#endif
+
+  if (pcdUp) PCDDialog(0);    /* close pcd window */
+
+#ifdef HAVE_PIC2
+  if (pic2Up) PIC2Dialog(0);  /* close pic2 window */
+#endif
+
+#ifdef HAVE_PCD
+  if (pcdUp)  PCDDialog(0);   /* close pcd window */
+#endif
+
+#ifdef HAVE_MGCSFX
+  if (mgcsfxUp) MGCSFXDialog(0);  /* close mgcsfx window */
+#endif
+
   ClosePopUp();
 
   /* make the interrupt signal look like a '\n' keypress in ctrlW */
@@ -2574,26 +2829,43 @@
 static void paintLine(x,y,x1,y1)
   int x,y,x1,y1;
 {
-  int dx,dy,i,lx,ly,adx,ady;
+  int t,dx,dy,d,dd;
 
-  dx = x1-x;  dy = y1-y;
-  adx = abs(dx);  ady = abs(dy);
+  dx = abs(x1-x);  dy = abs(y1-y);
 
-  if (dx == 0 && dy == 0) paintPixel(x,y);
-
-  else if (adx > ady) {           /* X is major axis */
-    for (i=0; i<=adx; i++) {
-      lx = x + (i * dx + (adx/2)) / abs(dx);
-      ly = y + (i * dy + (adx/2)) / abs(dx);
-      paintPixel(lx,ly);
+  if (dx >= dy) {                       /* X is major axis */
+    if (x > x1) {
+       t = x; x = x1; x1 = t;
+       t = y; y = y1; y1 = t;
+     }
+    d = dy + dy - dx;
+    dd = y < y1 ? 1 : -1;
+    while (x <= x1) {
+      paintPixel(x,y);
+      if (d > 0) {
+        y += dd;
+        d -= dx + dx;
+      }
+      ++x;
+      d += dy + dy;
     }
   }
 
   else {                                /* Y is major axis */
-    for (i=0; i<=ady; i++) {
-      lx = x + (i * dx + (ady/2)) / ady;
-      ly = y + (i * dy + (ady/2)) / ady;
-      paintPixel(lx,ly);
+    if (y > y1) {
+       t = x; x = x1; x1 = t;
+       t = y; y = y1; y1 = t;
+     }
+    d = dx + dx - dy;
+    dd = x < x1 ? 1 : -1;
+    while (y <= y1) {
+      paintPixel(x,y);
+      if (d > 0) {
+        x += dd;
+        d -= dy + dy;
+      }
+      ++y;
+      d += dx + dx;
     }
   }
 
diff -ruN xv-3.10a-bugfixes/xvfits.c xv-3.10a-enhancements/xvfits.c
--- xv-3.10a-bugfixes/xvfits.c	2005-04-02 21:08:45.000000000 -0800
+++ xv-3.10a-enhancements/xvfits.c	2005-04-17 14:45:28.000000000 -0700
@@ -14,7 +14,7 @@
  * provided "as is" without express or implied warranty.
  */
 
-
+#define  NEEDSDIR /* for S_IRUSR|S_IWUSR */
 #include "xv.h"
 
 #define NCARDS    (36)
@@ -228,7 +228,7 @@
    * If there was a problem writing files, then a error message will be set.
    */
 
-  int   i, npixels=nx * ny, nwrt;
+  int   i, npixels=nx * ny, nwrt, tmpfd;
   FILE *fp;
   char *error;
   char  filename[70];
@@ -254,7 +254,12 @@
 
   for (i=0; i < nz && !error; i++) {
     sprintf(filename, "%s%d", basename, i+1);
-    fp = xv_fopen(filename, "w");
+    tmpfd = open(filename,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR);
+    if (tmpfd < 0) {
+      error = "Unable to open temporary file";
+      break;
+    }
+    fp = fdopen(tmpfd, "w");
     if (!fp) {
       error = "Unable to open temporary file";
       break;
@@ -262,13 +267,17 @@
 
     if (wrheader(fp, nx, ny, comment)) {
       error = "I/O error writing temporary file";
+      fflush(fp);
       fclose(fp);
       unlink(filename);
+      close(tmpfd);
       break;
     }
 
     nwrt = fwrite(image+i*npixels, sizeof(byte), (size_t) npixels, fp);
+    fflush(fp);
     fclose(fp);
+    close(tmpfd);
 
     if (nwrt == 0) {  /* failed to write any data */
       error = "I/O error writing temporary file";
diff -ruN xv-3.10a-bugfixes/xvgam.c xv-3.10a-enhancements/xvgam.c
--- xv-3.10a-bugfixes/xvgam.c	2004-05-16 18:02:11.000000000 -0700
+++ xv-3.10a-enhancements/xvgam.c	2004-05-16 18:06:48.000000000 -0700
@@ -265,11 +265,11 @@
   BTCreate(&gbut[G_BRNDCOL], cmapF,  5 + 66 + 67 + 2, 189, 66, BUTTH,
 	   "Random", infofg, infobg, hicol, locol);
 
-  DCreate(&rhDial, cmapF, 5, 215, 66, 100,   0,360,180, 5,
+  DCreate(&rhDial, cmapF, 5, 215, 66, 100,   0.0, 360.0, 180.0, 1.0, 5.0,
 	  infofg, infobg, hicol, locol, "Hue", NULL);
-  DCreate(&gsDial, cmapF, 72, 215, 66, 100,  0,360,180, 5,
+  DCreate(&gsDial, cmapF, 72, 215, 66, 100,  0.0, 360.0, 180.0, 1.0, 5.0,
 	  infofg, infobg, hicol, locol, "Sat.", NULL);
-  DCreate(&bvDial, cmapF, 139, 215, 66, 100,   0,360,180, 5,
+  DCreate(&bvDial, cmapF, 139, 215, 66, 100, 0.0, 360.0, 180.0, 1.0, 5.0,
 	  infofg, infobg, hicol, locol, "Value", NULL);
 
   rhDial.drawobj = gsDial.drawobj = bvDial.drawobj = dragEditColor;
@@ -359,7 +359,7 @@
 
   srcHD.drawobj = dstHD.drawobj = whtHD.drawobj = dragHueDial;
 
-  DCreate(&satDial, hsvF, 100, 199, 100, 121, -100, 100, 0, 5,
+  DCreate(&satDial, hsvF, 100, 199, 100, 121, -100.0, 100.0, 0.0, 1.0, 5.0,
 	   infofg, infobg,hicol,locol, "Saturation", "%");
 
   hueRB = RBCreate(NULL, hsvF,  7, 153, "1",
@@ -722,7 +722,7 @@
 
   if (whtHD.enabCB.val && whtHD.satval) hsvnonlinear++;
 
-  if (satDial.val != 0) hsvnonlinear++;
+  if (satDial.val != 0.0) hsvnonlinear++;
 
   /* check intensity graf */
   for (i=0; i<256 && intGraf.func[i]==i; i++);
@@ -1291,14 +1291,14 @@
     rgb2hsv(rcmap[editColor], gcmap[editColor], bcmap[editColor], &h, &s, &v);
     if (h<0) h = 0;
 
-    DSetVal(&rhDial, (int) h);
-    DSetVal(&gsDial, (int) (s*100));
-    DSetVal(&bvDial, (int) (v*100));
+    DSetVal(&rhDial, h);
+    DSetVal(&gsDial, s*100);
+    DSetVal(&bvDial, v*100);
   }
   else {
-    DSetVal(&rhDial, rcmap[editColor]);
-    DSetVal(&gsDial, gcmap[editColor]);
-    DSetVal(&bvDial, bcmap[editColor]);
+    DSetVal(&rhDial, (double)rcmap[editColor]);
+    DSetVal(&gsDial, (double)gcmap[editColor]);
+    DSetVal(&bvDial, (double)bcmap[editColor]);
   }
 }
 
@@ -1310,16 +1310,15 @@
 
   if (hsvmode) {
     int rv, gv, bv;
-    hsv2rgb((double) rhDial.val, ((double) gsDial.val) / 100.0,
-	    ((double) bvDial.val) / 100.0, &rv, &gv, &bv);
+    hsv2rgb(rhDial.val, gsDial.val / 100.0, bvDial.val / 100.0, &rv, &gv, &bv);
     rcmap[editColor] = rv;
     gcmap[editColor] = gv;
     bcmap[editColor] = bv;
   }
   else {
-    rcmap[editColor] = rhDial.val;
-    gcmap[editColor] = gsDial.val;
-    bcmap[editColor] = bvDial.val;
+    rcmap[editColor] = (int)rhDial.val;
+    gcmap[editColor] = (int)gsDial.val;
+    bcmap[editColor] = (int)bvDial.val;
   }
 }
 
@@ -1561,9 +1560,9 @@
     gsDial.title = "Green";
     bvDial.title = "Blue";
 
-    DSetRange(&rhDial, 0, 255, rcmap[editColor], 16);
-    DSetRange(&gsDial, 0, 255, gcmap[editColor], 16);
-    DSetRange(&bvDial, 0, 255, bcmap[editColor], 16);
+    DSetRange(&rhDial, 0.0, 255.0, (double)rcmap[editColor], 1.0, 16.0);
+    DSetRange(&gsDial, 0.0, 255.0, (double)gcmap[editColor], 1.0, 16.0);
+    DSetRange(&bvDial, 0.0, 255.0, (double)bcmap[editColor], 1.0, 16.0);
 
     XClearWindow(theDisp, rhDial.win);    DRedraw(&rhDial);
     XClearWindow(theDisp, gsDial.win);    DRedraw(&gsDial);
@@ -1581,9 +1580,9 @@
 	    &h, &s, &v);
 
     if (h<0.0) h = 0.0;
-    DSetRange(&rhDial, 0, 360, (int) h, 5);
-    DSetRange(&gsDial, 0, 100, (int) (s*100), 5);
-    DSetRange(&bvDial, 0, 100, (int) (v*100), 5);
+    DSetRange(&rhDial, 0.0, 360.0,     h, 1.0, 5.0);
+    DSetRange(&gsDial, 0.0, 100.0, s*100, 1.0, 5.0);
+    DSetRange(&bvDial, 0.0, 100.0, v*100, 1.0, 5.0);
 
     XClearWindow(theDisp, rhDial.win);    DRedraw(&rhDial);
     XClearWindow(theDisp, gsDial.win);    DRedraw(&gsDial);
@@ -1891,7 +1890,7 @@
     }
 
     /* apply satDial value to s */
-    s = s + ((double) satDial.val) / 100.0;
+    s = s + satDial.val / 100.0;
     if (s<0.0) s = 0.0;
     if (s>1.0) s = 1.0;
 
@@ -2007,7 +2006,7 @@
 
   gs->hueRBnum = RBWhich(hueRB);
 
-  gs->satval = satDial.val;
+  gs->satval = (int)satDial.val;
   GetGrafState(&intGraf,&gs->istate);
   GetGrafState(&rGraf,  &gs->rstate);
   GetGrafState(&gGraf,  &gs->gstate);
@@ -2064,8 +2063,8 @@
     changed++;
   }
 
-  if (gs->satval != satDial.val) {
-    DSetVal(&satDial,gs->satval);
+  if (gs->satval != (int)satDial.val) {
+    DSetVal(&satDial,(double)gs->satval);
     changed++;
   }
 
@@ -3200,7 +3199,7 @@
 
   if (whtHD.enabCB.val && whtHD.satval) hsvmod++;
 
-  if (satDial.val != 0) hsvmod++;
+  if (satDial.val != 0.0) hsvmod++;
 
   /* check intensity graf */
   for (i=0; i<256; i++) {
@@ -3284,7 +3283,7 @@
       }
 
       /* apply satDial value to s */
-      s = s + satDial.val;
+      s = s + (int)satDial.val;
       if (s<  0) s =   0;
       if (s>100) s = 100;
 
diff -ruN xv-3.10a-bugfixes/xvgif.c xv-3.10a-enhancements/xvgif.c
--- xv-3.10a-bugfixes/xvgif.c	2005-04-03 11:53:13.000000000 -0700
+++ xv-3.10a-enhancements/xvgif.c	2005-04-30 21:47:44.000000000 -0700
@@ -50,6 +50,7 @@
     BytesPerScanline,		/* bytes per scanline in output raster */
     ColorMapSize,		/* number of colors */
     Background,			/* background color */
+    Transparent,		/* transparent color (GRR 19980314) */
     CodeSize,			/* Code size, read from GIF header */
     InitCodeSize,		/* Starting code size, used during Clear */
     Code,			/* Value returned by ReadCode */
@@ -111,16 +112,20 @@
 
   register byte  ch, *origptr;
   register int   i, block;
-  int            aspect, gotimage;
+  int            aspect;
+  char tmpname[256];
+  byte r[256], g[256], b[256];
 
   /* initialize variables */
-  BitOffset = XC = YC = OutCount = gotimage = 0;
+  BitOffset = XC = YC = OutCount = 0;
   Pass = -1;
   RawGIF = Raster = pic8 = NULL;
   gif89 = 0;
+  Transparent = -1;
 
   pinfo->pic     = (byte *) NULL;
   pinfo->comment = (char *) NULL;
+  pinfo->numpages= 0;
 
   bname = BaseName(fname);
   fp = xv_fopen(fname,"r");
@@ -145,7 +150,7 @@
 
   if (fread(dataptr, (size_t) filesize, (size_t) 1, fp) != 1)
     return( gifError(pinfo, "GIF data read failed") );
-
+  fclose(fp);
 
   origptr = dataptr;
 
@@ -161,6 +166,7 @@
   RWidth = ch + 0x100 * NEXTBYTE;	/* screen dimensions... not used. */
   ch = NEXTBYTE;
   RHeight = ch + 0x100 * NEXTBYTE;
+  if (DEBUG) fprintf(stderr,"GIF89 logical screen = %d x %d\n",RWidth,RHeight);
 
   ch = NEXTBYTE;
   HasColormap = ((ch & COLORMAPMASK) ? True : False);
@@ -176,6 +182,8 @@
     if (!gif89) return(gifError(pinfo,"corrupt GIF file (screen descriptor)"));
     else normaspect = (float) (aspect + 15) / 64.0;   /* gif89 aspect ratio */
     if (DEBUG) fprintf(stderr,"GIF89 aspect = %f\n", normaspect);
+    /* FIXME:  apparently this _should_ apply to all frames in a multi-image
+     *         GIF (i.e., PgUp/PgDn), but it doesn't */
   }
 
 
@@ -183,20 +191,23 @@
 
   if (HasColormap)
     for (i=0; i<ColorMapSize; i++) {
-      pinfo->r[i] = NEXTBYTE;
-      pinfo->g[i] = NEXTBYTE;
-      pinfo->b[i] = NEXTBYTE;
+      r[i] = NEXTBYTE;
+      g[i] = NEXTBYTE;
+      b[i] = NEXTBYTE;
     }
   else {  /* no colormap in GIF file */
     /* put std EGA palette (repeated 16 times) into colormap, for lack of
        anything better to do */
 
     for (i=0; i<256; i++) {
-      pinfo->r[i] = EGApalette[i&15][0];
-      pinfo->g[i] = EGApalette[i&15][1];
-      pinfo->b[i] = EGApalette[i&15][2];
+      r[i] = EGApalette[i&15][0];
+      g[i] = EGApalette[i&15][1];
+      b[i] = EGApalette[i&15][2];
     }
   }
+  memcpy(pinfo->r, r, sizeof r);
+  memcpy(pinfo->g, g, sizeof g);
+  memcpy(pinfo->b, b, sizeof b);
 
   /* possible things at this point are:
    *   an application extension block
@@ -334,12 +345,28 @@
 	if (DEBUG) fprintf(stderr,"Graphic Control extension\n\n");
 
 	SetISTR(ISTR_INFO, "%s:  %s", bname,
-		"Graphic Control Extension in GIF file.  Ignored.");
+		"Graphic Control Extension ignored.");
 
-	/* read (and ignore) data sub-blocks */
+	/* read (and ignore) data sub-blocks, unless compositing with
+         * user-defined background */
 	do {
-	  j = 0; sbsize = NEXTBYTE;
-	  while (j<sbsize) { SKIPBYTE;  j++; }
+	  j = 0;
+	  sbsize = NEXTBYTE;
+	  /* GRR 19980314:  get transparent index out of block */
+	  if (have_imagebg && sbsize == 4 && Transparent < 0) {
+	    byte packed_fields = NEXTBYTE;
+
+	    j++;
+	    SKIPBYTE;  j++;
+	    SKIPBYTE;  j++;
+	    if (packed_fields & 1) {
+	      Transparent = NEXTBYTE;
+	      j++;
+	    }
+	  }
+	  while (j<sbsize) {
+	    SKIPBYTE;  j++;
+	  }
 	} while (sbsize);
       }
 
@@ -376,36 +403,42 @@
 
 
     else if (block == IMAGESEP) {
-      if (DEBUG) fprintf(stderr,"imagesep (got=%d)  ",gotimage);
+      if (DEBUG) fprintf(stderr,"imagesep (page=%d)  ",pinfo->numpages+1);
       if (DEBUG) fprintf(stderr,"  at start: offset=0x%x\n",dataptr-RawGIF);
 
-      if (gotimage) {   /* just skip over remaining images */
-	int i,misc,ch,ch1;
+      BitOffset = XC = YC = Pass = OutCount = 0;
 
-	/* skip image header */
-	SKIPBYTE;  SKIPBYTE;  /* left position */
-	SKIPBYTE;  SKIPBYTE;  /* top position */
-	SKIPBYTE;  SKIPBYTE;  /* width */
-	SKIPBYTE;  SKIPBYTE;  /* height */
-	misc = NEXTBYTE;      /* misc. bits */
-
-	if (misc & 0x80) {    /* image has local colormap.  skip it */
-	  for (i=0; i< 1 << ((misc&7)+1);  i++) {
-	    SKIPBYTE;  SKIPBYTE;  SKIPBYTE;
+      if (pinfo->numpages > 0) {   /* do multipage stuff */
+	if (pinfo->numpages == 1) {    /* first time only... */
+	  xv_mktemp(pinfo->pagebname, "xvpgXXXXXX");
+	  if (pinfo->pagebname[0] == '\0') {
+	    ErrPopUp("LoadGIF: Unable to create temporary filename???",
+			"\nHow unlikely!");
+	    return 0;
 	  }
 	}
-
-	SKIPBYTE;       /* minimum code size */
-
-	/* skip image data sub-blocks */
-	do {
-	  ch = ch1 = NEXTBYTE;
-	  while (ch--) SKIPBYTE;
-	  if ((dataptr - RawGIF) > filesize) break;      /* EOF */
-	} while(ch1);
+	sprintf(tmpname, "%s%d", pinfo->pagebname, pinfo->numpages);
+	fp = xv_fopen(tmpname, "w");
+	if (!fp) {
+	  ErrPopUp("LoadGIF: Unable to open temp file", "\nDang!");
+	  return 0;
+	}
+	if (WriteGIF(fp, pinfo->pic, pinfo->type, pinfo->w, pinfo->h, pinfo->r,
+		 pinfo->g, pinfo->b, numcols, pinfo->colType, NULL)) {
+	  fclose(fp);
+	  ErrPopUp("LoadGIF: Error writing temp file", "\nBummer!");
+	  return 0;
+	}
+	fclose(fp);
+	free(pinfo->pic);
+	pinfo->pic = (byte *) NULL;
+	if (HasColormap) {
+	  memcpy(pinfo->r, r, sizeof r);
+	  memcpy(pinfo->g, g, sizeof g);
+	  memcpy(pinfo->b, b, sizeof b);
+	}
       }
-
-      else if (readImage(pinfo)) gotimage = 1;
+      if (readImage(pinfo)) pinfo->numpages++;
       if (DEBUG) fprintf(stderr,"  at end:   dataptr=0x%x\n",dataptr-RawGIF);
     }
 
@@ -425,7 +458,7 @@
 	sprintf(str, "Unknown block type (0x%02x) at offset 0x%x",
 		block, (dataptr - origptr) - 1);
 
-	if (!gotimage) return gifError(pinfo, str);
+	if (!pinfo->numpages) return gifError(pinfo, str);
 	else gifWarning(str);
       }
 
@@ -438,8 +471,34 @@
   free(RawGIF);	 RawGIF = NULL;
   free(Raster);  Raster = NULL;
 
-  if (!gotimage)
+  if (!pinfo->numpages)
      return( gifError(pinfo, "no image data found in GIF file") );
+  if (pinfo->numpages > 1) {
+    /* write the last page temp file */
+    int numpages = pinfo->numpages;
+    char *comment = pinfo->comment;
+    sprintf(tmpname, "%s%d", pinfo->pagebname, pinfo->numpages);
+    fp = xv_fopen(tmpname, "w");
+    if (!fp) {
+      ErrPopUp("LoadGIF: Unable to open temp file", "\nDang!");
+      return 0;
+    }
+    if (WriteGIF(fp, pinfo->pic, pinfo->type, pinfo->w, pinfo->h, pinfo->r,
+		 pinfo->g, pinfo->b, numcols, pinfo->colType, NULL)) {
+      fclose(fp);
+      ErrPopUp("LoadGIF: Error writing temp file", "\nBummer!");
+      return 0;
+    }
+    fclose(fp);
+    free(pinfo->pic);
+    pinfo->pic = (byte *) NULL;
+
+    /* load the first page temp file */
+    sprintf(tmpname, "%s%d", pinfo->pagebname, 1);
+    i = LoadGIF(tmpname, pinfo);
+    pinfo->numpages = numpages;
+    pinfo->comment = comment;
+  }
 
   return 1;
 }
@@ -484,6 +543,17 @@
   }
 
 
+  /* GRR 19980314 */
+  /* need not worry about size of EGA palette:  full 256 colors */
+  if (have_imagebg && Transparent >= 0 &&
+      Transparent < ((Misc&0x80)? (1 << ((Misc&7)+1)) : ColorMapSize) )
+  {
+    pinfo->r[Transparent] = (imagebgR >> 8);
+    pinfo->g[Transparent] = (imagebgG >> 8);
+    pinfo->b[Transparent] = (imagebgB >> 8);
+  }
+
+
 
   /* Start reading the raster data. First we get the intial code size
    * and compute decompressor constant values, based on this code size.
@@ -540,7 +610,7 @@
     return( gifError(pinfo, "image dimensions out of range") );
   picptr = pic8 = (byte *) malloc((size_t) maxpixels);
   if (!pic8) FatalError("LoadGIF: couldn't malloc 'pic8'");
-	        
+
 
 
   /* Decompress the file, continuing until you see the GIF EOF code.
@@ -642,11 +712,10 @@
     SetISTR(ISTR_WARNING,"%s:  %s", bname,
 	    "This GIF file seems to be truncated.  Winging it.");
     if (!Interlace)  /* clear->EOBuffer */
-      xvbzero((char *) pic8+npixels, (size_t) (maxpixels-npixels));
+      xvbzero((char *) pic8+npixels,
+	      (size_t) (maxpixels-npixels<0 ? 0 : maxpixels-npixels));
   }
 
-  fclose(fp);
-
   /* fill in the PICINFO structure */
 
   pinfo->pic     = pic8;
diff -ruN xv-3.10a-bugfixes/xvgrab.c xv-3.10a-enhancements/xvgrab.c
--- xv-3.10a-bugfixes/xvgrab.c	2004-05-16 18:03:30.000000000 -0700
+++ xv-3.10a-enhancements/xvgrab.c	2005-04-25 23:39:32.000000000 -0700
@@ -14,6 +14,13 @@
 #define NEEDSTIME
 #include "xv.h"
 
+/* Allow flexibility in use of buttons JPD */
+#define WINDOWGRABMASK Button1Mask  /* JPD prefers Button2Mask */
+#define RECTGTRACKMASK Button2Mask  /* JPD prefers Button1Mask*/
+#define CANCELGRABMASK Button3Mask
+
+#define DO_GRABFLASH  /* JPD prefers not to do that; just a loss of time ... */
+
 
 union swapun {
   CARD32 l;
@@ -69,12 +76,15 @@
      0 if cancelled */
 
   int          i, x, y, x1, y1, x2, y2, ix, iy, iw, ih, rv;
-  int          rx, ry, pretendGotB1, autograb;
+  int          rx, ry, GotButton, autograb;
+  int          cancelled = 0;
   Window       rW, cW, clickWin;
   unsigned int mask;
+#ifdef RECOLOR_GRAB_CURSOR
   XColor       fc, bc;
+#endif
 
-  pretendGotB1 = 0;
+  GotButton = 0;
 
   if (grabInProgress) return 0;      /* avoid recursive grabs during delay */
 
@@ -122,15 +132,23 @@
     free(grabPic);  grabPic = (byte *) NULL;
   }
 
-
+  /* recolor cursor to indicate that grabbing is active? */
+  /* Instead, change cursor JPD */
+#ifdef RECOLOR_GRAB_CURSOR
   fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
   fc.red = fc.green = fc.blue = 0xffff;
   bc.red = bc.green = bc.blue = 0x0000;
   XRecolorCursor(theDisp, tcross, &fc, &bc);
+#endif
 
 
   XBell(theDisp, 0);		/* beep once at start of grab */
 
+  /* Change cursor to top_left_corner JPD */
+  XGrabPointer(theDisp, rootW, False,
+     PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
+     GrabModeAsync, GrabModeAsync, None, tlcorner, CurrentTime);
+
   if (!autograb) XGrabButton(theDisp, (u_int) AnyButton, 0, rootW, False, 0,
 			     GrabModeAsync, GrabModeSync, None, tcross);
 
@@ -142,7 +160,7 @@
       rv = 0;
       goto exit;
     }
-    else { pretendGotB1 = 1;  mask = Button1Mask; }
+    else { GotButton = 1;  mask = WINDOWGRABMASK; }
   }
 
   else {   /* !autograb */
@@ -170,16 +188,20 @@
     }
   }
 
+  XUngrabPointer(theDisp, CurrentTime);
+  /* Reset cursor to XC_tcross JPD */
+  XGrabPointer(theDisp, rootW, False,
+     PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
+     GrabModeAsync, GrabModeAsync, None, tcross, CurrentTime);
 
   /***
    ***  got button click (or pretending we did, if autograb)
    ***/
 
-
-  if (mask & Button3Mask || rW!=rootW) {        /* Button3: CANCEL GRAB */
+  if (mask & CANCELGRABMASK || rW!=rootW) {        /* CANCEL GRAB */
     while (1) {      /* wait for button to be released */
       if (XQueryPointer(theDisp,rootW,&rW,&cW,&rx,&ry,&x1,&y1,&mask)) {
-	if (!(mask & Button3Mask)) break;
+	if (!(mask & CANCELGRABMASK)) break;
       }
     }
 
@@ -187,19 +209,21 @@
     XBell(theDisp, 0);
     XBell(theDisp, 0);
     rv = 0;
+    cancelled = 1;
     goto exit;
   }
 
 
-
-  if (mask & Button1Mask) {  /* Button1:  GRAB WINDOW (& FRAME, maybe)     */
-    while (!pretendGotB1) {  /* wait for button to be released, if clicked */
+  if (mask & WINDOWGRABMASK) {  /* GRAB WINDOW (& FRAME, maybe)     */
+    while (!GotButton) {  /* wait for button to be released, if clicked */
       int rx,ry,x1,y1;  Window rW, cW;
       if (XQueryPointer(theDisp,rootW,&rW,&cW,&rx,&ry,&x1,&y1,&mask)) {
-	if (!(mask & Button1Mask)) break;
+	if (!(mask & WINDOWGRABMASK)) break;
       }
     }
 
+  grabwin:
+
     clickWin = (cW) ? cW : rootW;
 
     if (clickWin == rootW) {   /* grab entire screen */
@@ -223,7 +247,6 @@
       }
     }
 
-
     /* range checking:  keep rectangle fully on-screen */
     if (ix<0) { iw += ix;  ix = 0; }
     if (iy<0) { ih += iy;  iy = 0; }
@@ -244,8 +267,7 @@
     endflash();
   }
 
-
-  else {  /* Button2:  TRACK A RECTANGLE */
+  else {  /* TRACK A RECTANGLE */
     int    origrx, origry;
 
     clickWin = rootW;
@@ -259,7 +281,7 @@
     /* Wait for button release while tracking rectangle on screen */
     while (1) {
       if (XQueryPointer(theDisp,rootW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
-	if (!(mask & Button2Mask)) break;
+	if (!(mask & RECTGTRACKMASK)) break;
       }
 
       flashrect(ix, iy, iw, ih, 0);                /* turn off rect */
@@ -276,6 +298,7 @@
 
     flashrect(ix, iy, iw, ih, 0);                  /* turn off rect */
 
+#ifdef DO_GRABFLASH
     /* flash the rectangle a bit... */
     for (i=0; i<5; i++) {
       flashrect(ix, iy, iw, ih, 1);
@@ -283,13 +306,26 @@
       flashrect(ix, iy, iw, ih, 0);
       XFlush(theDisp);  Timer(100);
     }
+#endif
+
     endflash();
 
+    /* if rectangle has zero width or height, search for child window JPD */
+    if (iw==0 && ih==0) {
+       int xr, yr;
+       Window childW = 0;
+       if (rW && cW)
+          XTranslateCoordinates(theDisp, rW, cW, rx, ry, &xr, &yr, &childW);
+       if (childW)
+          cW = childW;
+       goto grabwin;
+    }
+
     XUngrabServer(theDisp);
   }
 
-
   /***
+   ***  now that clickWin,ix,iy,iw,ih are known, try to grab the bits :
    ***  grab screen area (ix,iy,iw,ih)
    ***/
 
@@ -303,9 +339,16 @@
 
   SetCursors(-1);
 
-
  exit:
 
+  XUngrabPointer(theDisp, CurrentTime);
+  XUngrabServer(theDisp);
+
+  if (startGrab) {
+    startGrab = 0;
+    if (cancelled) Quit(0);
+  }
+
   if (hidewins) {                   /* remap XV windows */
     autoclose += 2;                 /* force it on once */
     if (mainW && dispMode == RMB_WINDOW) {
@@ -1217,7 +1260,3 @@
 
   return 1;
 }
-
-
-
-
diff -ruN xv-3.10a-bugfixes/xvhips.c xv-3.10a-enhancements/xvhips.c
--- xv-3.10a-bugfixes/xvhips.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvhips.c	2005-04-30 23:49:14.000000000 -0700
@@ -0,0 +1,406 @@
+/*
+ * xvhips.c - load routine for 'HIPS' format pictures
+ *
+ * LoadHIPS(fname, numcols)
+ */
+
+/*
+ * Copyright 1989, 1990 by the University of Pennsylvania
+ *
+ * Permission to use, copy, and distribute for non-commercial purposes,
+ * is hereby granted without fee, providing that the above copyright
+ * notice appear in all copies and that both the copyright notice and this
+ * permission notice appear in supporting documentation.
+ *
+ * The software may be modified for your own purposes, but modified versions
+ * may not be distributed.
+ *
+ * This software is provided "as is" without any express or implied warranty.
+ */
+
+#include "xv.h"
+
+#ifdef HAVE_HIPS
+
+#define Boolean FREDDIE
+#include "xvhips.h"
+#undef Boolean
+
+#include <alloca.h>
+
+#define LINES 100
+#define LINELENGTH 132
+
+static int   fread_header(int fd, struct header *hd);
+static char  *getline(int fd, char **s, int *l);
+static int   dfscanf(int fd);
+static void  make_grayscale(char *r, char *g, char *b);
+static float hls_value (float n1, float n2, float hue);
+static void  hls_to_rgb(float h, float l, float s,
+                        float *r, float *g, float *b);
+static void  make_huescale(char *r, char *g, char *b);
+static void  make_heatscale(char *r, char *g, char *b);
+static int   load_colourmap(char *filestem, int max_colours,
+                            char *r, char *g, char *b);
+
+/************************************************************************
+ *
+ * Read Header routines
+ *
+ ************************************************************************/
+
+static char *ssave[LINES];
+static int slmax[LINES];
+static int lalloc = 0;
+//extern char *calloc();
+
+
+
+static int fread_header(fd, hd)
+  int fd;
+  struct header *hd;
+{
+  int lineno, len, i;
+  char *s;
+
+/*fprintf(stderr,"fread_header: entered\n");*/
+  if(lalloc<1) {
+    ssave[0] = calloc(LINELENGTH, sizeof (char));
+    slmax[0] = LINELENGTH;
+    lalloc = 1;
+  }
+/*fprintf(stderr,"fread_header: ssave allocated\n");*/
+  getline(fd,&ssave[0],&slmax[0]);
+  hd->orig_name = calloc(strlen(ssave[0])+1, sizeof (char));
+  strcpy(hd->orig_name,ssave[0]);
+  getline(fd,&ssave[0],&slmax[0]);
+  hd->seq_name = calloc(strlen(ssave[0])+1, sizeof (char));
+  strcpy(hd->seq_name,ssave[0]);
+  hd->num_frame = dfscanf(fd);
+  getline(fd,&ssave[0],&slmax[0]);
+  hd->orig_date = calloc(strlen(ssave[0])+1, sizeof (char));
+  strcpy(hd->orig_date,ssave[0]);
+  hd->rows = dfscanf(fd);
+  hd->cols = dfscanf(fd);
+  hd->bits_per_pixel = dfscanf(fd);
+  hd->bit_packing = dfscanf(fd);
+  hd->pixel_format = dfscanf(fd);
+  lineno = 0;
+  len = 1;
+  getline(fd,&ssave[0],&slmax[0]);
+  s = ssave[0];
+  while(*(s += strlen(s)-3) == '|') {
+    len += strlen(ssave[lineno]);
+    lineno++;
+    if (lineno >= LINES)
+      fprintf(stderr, "Too many lines in header history");
+    if(lineno >= lalloc) {
+      ssave[lineno] = calloc(LINELENGTH, sizeof (char));
+      slmax[lineno] = LINELENGTH;
+      lalloc++;
+    }
+    getline(fd,&ssave[lineno],&slmax[lineno]);
+    s = ssave[lineno];
+  }
+  len += strlen(ssave[lineno]);
+  hd->seq_history = calloc(len, sizeof (char));
+  hd->seq_history[0] = '\0';
+  for (i=0;i<=lineno;i++)
+    strcat(hd->seq_history,ssave[i]);
+  lineno = 0;
+  len = 1;
+  while(strcmp(getline(fd,&ssave[lineno],&slmax[lineno]),".\n")) {
+    len += strlen(ssave[lineno]);
+    lineno++;
+    if (lineno >= LINES)
+      fprintf(stderr, "Too many lines in header desc.");
+    if(lineno >= lalloc) {
+      ssave[lineno] = calloc(LINELENGTH, sizeof (char));
+      slmax[lineno] = LINELENGTH;
+      lalloc++;
+    }
+  }
+  hd->seq_desc = calloc(len, sizeof (char));
+  *hd->seq_desc = '\0';
+  for (i=0;i<lineno;i++)
+    strcat(hd->seq_desc,ssave[i]);
+/*fprintf(stderr,"fread_header: exiting\n");*/
+  return 0;
+}
+
+
+
+static char *getline(fd,s,l)
+  int fd;
+  char **s;
+  int *l;
+{
+  int i,m;
+  char c,*s1,*s2;
+
+  i = 0;
+  s1 = *s;
+  m = *l;
+  while(read(fd,&c,1) == 1 && c != '\n') {
+    if (m-- <= 2) {
+      s2 = calloc(LINELENGTH+*l,sizeof (char));
+      strcpy(s2,*s);
+      *s = s2;
+      *l += LINELENGTH;
+      m = LINELENGTH;
+      s1 = s2 + strlen(s2);
+    }
+    *s1++ = c;
+  }
+  if (c == '\n') {
+    *s1++ = '\n';
+    *s1 = '\0';
+    return *s;
+  }
+  fprintf(stderr, "Unexpected EOF while reading header.");
+  return NULL;
+}
+
+
+
+static int dfscanf(fd)
+  int fd;
+{
+  int i;
+
+  getline(fd,&ssave[0],&slmax[0]);
+  sscanf(ssave[0],"%d",&i);
+  return(i);
+}
+
+
+
+/*******************************************/
+int LoadHIPS(fname,pinfo)
+     char *fname;
+     PICINFO * pinfo;
+/*******************************************/
+{
+  FILE  *fp;
+  struct header h;
+  char * pic;
+
+  /* open the stream, if necesary */
+  fp=fopen(fname,"r");
+  if (!fp) return 0;
+
+  if (!fread_header(fileno(fp), &h)) {
+    SetISTR(ISTR_WARNING,"Can't read HIPS header");
+    return 0;
+  }
+
+  pinfo->w = h.cols;
+  pinfo->h = h.rows;
+  pic = pinfo->pic = (byte *) malloc(h.rows * h.cols);   // GRR POSSIBLE OVERFLOW / FIXME
+  if (!pic) FatalError("couldn't malloc HIPS file");
+
+  if (!fread(pic, 1, h.cols*h.rows, fp)) {
+    SetISTR(ISTR_WARNING,"Error reading HIPS data.\n");
+    return 0;
+  }
+  fclose (fp);
+
+  pinfo->frmType = F_SUNRAS;
+  pinfo->colType = F_FULLCOLOR;
+  sprintf(pinfo->fullInfo, "HIPS file (%d bytes)", h.cols*h.rows);
+  sprintf(pinfo->shrtInfo, "HIPS file.");
+  pinfo->comment = (char *) NULL;
+
+  {
+    char cmapname[256];
+    /* Check header for colormap spec */
+    char * s = h.seq_desc - 1;
+    char * cmaptag = "+COLORMAP";
+    int sl = strlen(cmaptag);
+    cmapname[0] = 0;
+    while (*++s)
+      if (*s == '+')
+	if (strncmp(s, cmaptag, sl) == 0) {
+	  char * p = s + sl;
+	  while (*p && (*p == ' ' || *p == '\n' || *p == '\t')) p++;
+	  sscanf(p, "%s", cmapname);
+	  SetISTR(ISTR_INFO, cmapname);
+	  fprintf(stderr, "Colormap = [%s]\n", cmapname);
+	}
+
+    if (strcmp(cmapname, "gray") == 0 || strcmp(cmapname, "grey") == 0)
+      make_grayscale(pinfo->r, pinfo->g, pinfo->b);
+    else if (strcmp(cmapname, "heat") == 0)
+      make_heatscale(pinfo->r, pinfo->g, pinfo->b);
+    else if (strcmp(cmapname, "hues") == 0)
+      make_huescale(pinfo->r, pinfo->g, pinfo->b);
+    else if (!cmapname[0] || !load_colourmap(cmapname, 256, pinfo->r, pinfo->g, pinfo->b))
+      make_grayscale(pinfo->r, pinfo->g, pinfo->b);
+    sprintf(pinfo->fullInfo, "HIPS file (%d x %d), Colormap = [%s]", h.cols, h.rows, cmapname);
+  }
+
+  return 1;
+}
+
+
+
+static void make_grayscale(char * r, char * g, char * b)
+{
+  int i;
+  /* default grayscale colors */
+  r[0] = 40; g[0] = 150; b[0] = 100; /* "green4" background */
+  for(i = 1; i < 256; i++)
+    r[i] = g[i] = b[i] = i;
+}
+
+
+
+static float hls_value (n1, n2, hue)
+  float n1,n2,hue;
+{
+	if (hue>360.0)
+	  hue-=360.0 ;
+	else if (hue<0.0)
+	  hue+=360.0 ;
+
+	if (hue<60.0)
+	  return( n1+(n2-n1)*hue/60.0 ) ;
+	else if (hue<180.0)
+	  return ( n2 ) ;
+	else if (hue<240.0)
+	  return ( n1+(n2-n1)*(240.0-hue)/60.0 ) ;
+	else
+	  return (n1) ;
+}
+
+
+
+static void hls_to_rgb(h,l,s,  r,g,b)
+  float h, l, s;
+  float *r, *g, *b;
+{
+	static float m1, m2 ;
+
+	if (l<=0.5)
+		m2=l*(1+s) ;
+	else
+		m2=l+s-l*s ;
+	m1=2.0*l-m2 ;
+	if (s==0.0) *r=*g=*b=l ;
+	else {
+		*r=hls_value(m1,m2,h+120.0) ;
+		*g=hls_value(m1,m2,h) ;
+		*b=hls_value(m1,m2,h-120.0) ;
+	}
+
+}
+
+
+
+static void make_huescale(char * r, char * g, char * b)
+{
+  int j;
+  r[0] = g[0] = b[0] = 0;
+  for (j = 1; j<256; j++)
+    {
+      float fr, fg, fb;
+      hls_to_rgb((double)(256.0-j)*360.0/256.0, 0.5, 1.0, &fr, &fg, &fb);
+      r[j] = rint(255*fr);
+      g[j] = rint(255*fg);
+      b[j] = rint(255*fb);
+    }
+}
+
+
+
+static void make_heatscale(char * r, char * g, char * b)
+{
+  int j;
+  r[0] = g[0] = b[0] = 0;
+  for (j = 1; j<256; j++)
+    {
+      if(j<255/2)
+	r[j] = j*255/(255/2-1);
+      else
+	r[j]=255;
+      if (j>=255/2+255/3)
+	g[j] = 255;
+      else if (j>255/3)
+	g[j] = (j-255/3)*255/(255/2-1);
+      else
+	g[j] = 0;
+      if (j>255/2)
+	b[j] = (j-255/2)*255/(255-255/2-1);
+      else
+	b[j] = 0;
+    }
+}
+
+
+
+static int load_colourmap(char *filestem, int max_colours,
+                          char *r, char *g, char *b)
+{
+  FILE * fp;
+  int numread=0;
+  char * filename;
+  char str[200];
+  int num_colors;
+  /*
+   * Look for palette file in local directory
+   */
+
+  filename = (char*)alloca(strlen(filestem) + 5);
+  strcpy(filename, filestem);
+  strcat(filename, ".PAL"); /* Add the PAL suffix to the name specified */
+  fp = fopen(filename,"r");
+  if (!fp) {
+    /*
+     * If not found, try in $IM2HOME/etc/palettes
+     */
+    char * im2home = (char*)getenv("IM2HOME");
+    char * palette_subdirectory = "etc/palettes";
+    char * fullfilename;
+    if (!im2home)
+      {
+	im2home = "/home/jewel/imagine2";
+	fprintf(stderr,"IM2HOME environment variable not set -- using [%s]\n",im2home);
+      }
+    fullfilename = alloca(strlen(im2home)+strlen(palette_subdirectory)+strlen(filename)+5);
+    sprintf(fullfilename, "%s/%s/%s",im2home,palette_subdirectory,filename);
+    fp = fopen(fullfilename,"r");
+    if (!fp)
+      {
+	fprintf(stderr,"Couldn't find any palette file -- looked for [%s] and [%s].\n",
+		filename,fullfilename);
+	perror("Last system error message was");
+	return 0;
+      }
+  }
+
+  strcpy(str,"(null)");
+  if (!fscanf(fp,"%s\n",str) || strncmp(str,"Palette",7) != 0) {
+    fprintf(stderr,"error: First line of palette file should be `Palette', not [%s]\n", str);
+    return 0;
+  }
+
+  fscanf(fp,"%[^\n]",str) ; /* Scan to end of line */
+  fscanf (fp,"%d",&num_colors);/* Read the number of colours in the file */
+  fgets(str,120,fp) ; /* Skip the text description, and general info lines */
+  fgets(str,120,fp) ;
+
+  while ((numread<max_colours)&&(numread<num_colors)) {
+    int rc, gc, bc;
+    fscanf (fp,"%d %d %d -", &rc, &gc, &bc) ; /* Get the (r,g,b) tuples */
+    r[numread] = rc;
+    g[numread] = gc;
+    b[numread] = bc;
+    numread++;
+    fgets(str,120,fp) ; /* Skip the description, if present */
+  }
+
+  SetISTR(ISTR_INFO,"Read %d colors from palette file [%s]", numread, filename);
+  return (numread) ; /* Return the number of colours ACTUALLY READ */
+}
+
+#endif /* HAVE_HIPS */
diff -ruN xv-3.10a-bugfixes/xvhips.h xv-3.10a-enhancements/xvhips.h
--- xv-3.10a-bugfixes/xvhips.h	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvhips.h	2005-04-25 08:34:14.000000000 -0700
@@ -0,0 +1,154 @@
+/*
+ * HIPL Picture Header Format Standard
+ *
+ * Michael Landy - 2/1/82
+ */
+
+#define XHEADER
+#ifdef XHEADER
+struct extended {
+	char *name;
+	char *vals;
+	};
+#endif
+
+struct header {
+	char	*orig_name;	/* The originator of this sequence */
+	char	*seq_name;	/* The name of this sequence */
+	int	num_frame;	/* The number of frames in this sequence */
+	char	*orig_date;	/* The date the sequence was originated */
+	int	rows;		/* The number of rows in each image */
+	int	cols;		/* The number of columns in each image */
+	int	bits_per_pixel;	/* The number of significant bits per pixel */
+	int	bit_packing;	/* Nonzero if bits were packed contiguously */
+	int	pixel_format;	/* The format of each pixel, see below */
+	char	*seq_history;	/* The sequence's history of transformations */
+	char	*seq_desc;	/* Descriptive information */
+#ifdef XHEADER
+	struct extended *xheader;
+#endif
+};
+
+/*
+ * Pixel Format Codes
+ */
+
+#define	PFBYTE	0		/* Bytes interpreted as integers (8 bits) */
+#define PFSHORT	1		/* Short integers (2 bytes) */
+#define PFINT	2		/* Integers (4 bytes) */
+#define	PFFLOAT	3		/* Float's (4 bytes)*/
+#define	PFCOMPLEX 4		/* 2 Float's interpreted as (real,imaginary) */
+#define PFASCII	5		/* ASCII rep, with linefeeds after each row */
+#define	PFDOUBLE 6		/* Double's (8 byte floats) */
+#define	PFDBLCOM 7		/* Double complex's (2 Double's) */
+#define PFQUAD	10		/* quad-tree encoding (Mimaging) */
+#define PFQUAD1	11		/* quad-tree encoding */
+#define PFBHIST	12		/* histogram of byte image (using ints) */
+#define PFSPAN	13		/* spanning tree format */
+#define PLOT3D	24		/* plot-3d format */
+#define PFINTPYR 50		/* integer pyramid */
+#define PFFLOATPYR 51		/* float pyramid */
+#define PFPOLYLINE 100		/* 2D points */
+#define PFCOLVEC 101		/* Set of RGB triplets defining colours */
+#define PFUKOOA 102		/* Data in standard UKOOA format */
+#define PFTRAINING 104		/* Set of colour vector training examples */
+#define PFTOSPACE 105		/* TOspace world model data structure */
+#define PFSTEREO 106		/* Stereo sequence (l, r, l, r, ...) */
+#define PFRGPLINE 107		/* 2D points with regions */
+#define PFRGISPLINE 108		/* 2D points with regions and interfaces */
+#define PFCHAIN	200		/* Chain code encoding (Mimaging) */
+#define PFLUT	300		/* LUT format (uses Ints) (Mimaging) */
+#define PFAHC	400		/* adaptive hierarchical encoding */
+#define PFOCT	401		/* oct-tree encoding */
+#define	PFBT	402		/* binary tree encoding */
+#define PFAHC3	403		/* 3-d adaptive hierarchical encoding */
+#define PFBQ	404		/* binquad encoding */
+#define PFRLED	500		/* run-length encoding */
+#define PFRLEB	501		/* run-length encoding, line begins black */
+#define PFRLEW	502		/* run-length encoding, line begins white */
+#define PFPOLAR	600		/* rho-theta format (Mimaging) */
+
+/*
+ * Bit packing formats
+ */
+
+#define	MSBFIRST 1		/* bit packing - most significant bit first */
+#define	LSBFIRST 2		/* bit packing - least significant bit first */
+
+#define FBUFLIMIT 30000		/* increase this if you use large PLOT3D
+					files */
+
+/*
+ * For general readability
+ */
+
+#ifndef TRUE
+# define	TRUE	1
+#endif
+
+#ifndef FALSE
+# define	FALSE	0
+#endif
+
+typedef	long	Boolean;
+extern char *strsave(), *memalloc();
+
+/*
+ * image and pyramid type declarations for the pyramid routines.
+ *
+ * The pyramid utilities are derived from code originally written by
+ * Raj Hingorani at SRI/David Sarnoff Research Institute.  The original
+ * Gaussian and Laplacian pyramid algorithms were designed by Peter Burt (also
+ * currently at SRI/DSRC).  See:  Computer Graphics and Image Processing,
+ * Volume 16, pp. 20-51, 1981, and IEEE Transactions on Communications,
+ * Volume COM-31, pp. 532-540, 1983.
+ */
+
+#define MAXLEV 12
+
+
+typedef struct {
+   float **ptr;
+   int nr;
+   int nc;
+} FIMAGE;
+
+typedef struct {
+   int **ptr;
+   int nr;
+   int nc;
+} IIMAGE;
+
+typedef FIMAGE FPYR[MAXLEV];
+typedef IIMAGE IPYR[MAXLEV];
+
+typedef struct {
+   float *k;
+   int taps2;		/* the number of taps from the center rightward,
+				total number is 2*taps2-1 */
+} FILTER;
+
+/* function definitions */
+
+float		**_read_fimgstr();
+int		**_read_iimgstr();
+float		**_alloc_fimage();
+int		**_alloc_iimage();
+
+/* image macros */
+
+#ifndef MAX
+# define MAX(A,B)  ((A) > (B) ? (A) : (B))
+#endif /* MAX */
+#ifndef MIN
+# define MIN(A,B)  ((A) < (B) ? (A) : (B))
+#endif /* MIN */
+#ifndef ABS
+# define ABS(A)    ((A) > 0 ? (A) : (-(A)))
+#endif /* ABS */
+#ifndef BETWEEN
+# define BETWEEN(A,B,C) (((A) < (B)) ? (B) : (((A) > (C)) ? (C) : (A)))
+#endif /* BETWEEN */
+#ifndef SIGN
+# define SIGN(A,B) (((B) > 0) ? (A) : (-(A)))
+#endif /* SIGN */
diff -ruN xv-3.10a-bugfixes/xvimage.c xv-3.10a-enhancements/xvimage.c
--- xv-3.10a-bugfixes/xvimage.c	2005-03-31 07:23:39.000000000 -0800
+++ xv-3.10a-enhancements/xvimage.c	2005-04-17 23:00:10.000000000 -0700
@@ -21,6 +21,16 @@
  *            int  LoadPad(pinfo, fname);
  */
 
+/* The following switch should better be provided at runtime for
+ * comparison purposes.
+ * At the moment it's only compile time, unfortunately.
+ * Who can make adaptions for use as a runtime switch by a menu option?
+ * [GRR 19980607:  now via do_fixpix_smooth global; macro renamed to ENABLE_]
+ * [see http://sylvana.net/fixpix/ for home page, further info]
+ */
+/* #define ENABLE_FIXPIX_SMOOTH */   /* GRR 19980607:  moved into xv.h */
+
+#define  NEEDSDIR             /* for S_IRUSR|S_IWUSR */
 #include "copyright.h"
 
 #include "xv.h"
@@ -36,7 +46,9 @@
 static int  doAutoCrop24      PARM((void));
 static void floydDitherize1   PARM((XImage *, byte *, int, int, int,
 				    byte *, byte *,byte *));
+#if 0 /* NOTUSED */
 static int  highbit           PARM((unsigned long));
+#endif
 
 static int  doPadSolid        PARM((char *, int, int, int, int));
 static int  doPadBggen        PARM((char *, int, int, int, int));
@@ -46,6 +58,267 @@
 static int  ReadImageFile1    PARM((char *, PICINFO *));
 
 
+/* The following array represents the pixel values for each shade
+ * of the primary color components.
+ * If 'p' is a pointer to a source image rgb-byte-triplet, we can
+ * construct the output pixel value simply by 'oring' together
+ * the corresponding components:
+ *
+ *	unsigned char *p;
+ *	unsigned long pixval;
+ *
+ *	pixval  = screen_rgb[0][*p++];
+ *	pixval |= screen_rgb[1][*p++];
+ *	pixval |= screen_rgb[2][*p++];
+ *
+ * This is both efficient and generic, since the only assumption
+ * is that the primary color components have separate bits.
+ * The order and distribution of bits does not matter, and we
+ * don't need additional variables and shifting/masking code.
+ * The array size is 3 KBytes total and thus very reasonable.
+ */
+
+static unsigned long screen_rgb[3][256];
+
+/* The following array holds the exact color representations
+ * reported by the system.
+ * This is useful for less than 24 bit deep displays as a base
+ * for additional dithering to get smoother output.
+ */
+
+static byte screen_set[3][256];
+
+/* The following routine initializes the screen_rgb and screen_set
+ * arrays.
+ * Since it is executed only once per program run, it does not need
+ * to be super-efficient.
+ *
+ * The method is to draw points in a pixmap with the specified shades
+ * of primary colors and then get the corresponding XImage pixel
+ * representation.
+ * Thus we can get away with any Bit-order/Byte-order dependencies.
+ *
+ * The routine uses some global X variables: theDisp, theScreen,
+ * and dispDEEP. Adapt these to your application as necessary.
+ * I've not passed them in as parameters, since for other platforms
+ * than X these may be different (see vfixpix.c), and so the
+ * screen_init() interface is unique.
+ *
+ * BUG: I've read in the "Xlib Programming Manual" from O'Reilly &
+ * Associates, that the DefaultColormap in TrueColor might not
+ * provide the full shade representation in XAllocColor.
+ * In this case one had to provide a 'best' colormap instead.
+ * However, my tests with Xaccel on a Linux-Box with a Mach64
+ * card were fully successful, so I leave that potential problem
+ * to you at the moment and would appreciate any suggestions...
+ */
+
+static void screen_init()
+{
+  static int init_flag; /* assume auto-init as 0 */
+  Pixmap check_map;
+  GC check_gc;
+  XColor check_col;
+  XImage *check_image;
+  int ci, i;
+
+  if (init_flag) return;
+  init_flag = 1;
+
+  check_map = XCreatePixmap(theDisp, RootWindow(theDisp,theScreen),
+			    1, 1, dispDEEP);
+  check_gc = XCreateGC(theDisp, check_map, 0, NULL);
+  for (ci = 0; ci < 3; ci++) {
+    for (i = 0; i < 256; i++) {
+      check_col.red = 0;
+      check_col.green = 0;
+      check_col.blue = 0;
+      /* Do proper upscaling from unsigned 8 bit (image data values)
+	 to unsigned 16 bit (X color representation). */
+      ((unsigned short *)&check_col.red)[ci] = (unsigned short)((i << 8) | i);
+      if (theVisual->class == TrueColor)
+	XAllocColor(theDisp, theCmap, &check_col);
+      else
+	xvAllocColor(theDisp, theCmap, &check_col);
+      screen_set[ci][i] =
+	(((unsigned short *)&check_col.red)[ci] >> 8) & 0xff;
+      XSetForeground(theDisp, check_gc, check_col.pixel);
+      XDrawPoint(theDisp, check_map, check_gc, 0, 0);
+      check_image = XGetImage(theDisp, check_map, 0, 0, 1, 1,
+			      AllPlanes, ZPixmap);
+      if (check_image) {
+	switch (check_image->bits_per_pixel) {
+	case 8:
+	  screen_rgb[ci][i] = *(CARD8 *)check_image->data;
+	  break;
+	case 16:
+	  screen_rgb[ci][i] = *(CARD16 *)check_image->data;
+	  break;
+	case 24:
+	  screen_rgb[ci][i] =
+	    ((unsigned long)*(CARD8 *)check_image->data << 16) |
+	    ((unsigned long)*(CARD8 *)(check_image->data + 1) << 8) |
+	    (unsigned long)*(CARD8 *)(check_image->data + 2);
+	  break;
+	case 32:
+	  screen_rgb[ci][i] = *(CARD32 *)check_image->data;
+	  break;
+	}
+	XDestroyImage(check_image);
+      }
+    }
+  }
+  XFreeGC(theDisp, check_gc);
+  XFreePixmap(theDisp, check_map);
+}
+
+
+#ifdef ENABLE_FIXPIX_SMOOTH
+
+/* The following code is based in part on:
+ *
+ * jquant1.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains 1-pass color quantization (color mapping) routines.
+ * These routines provide mapping to a fixed color map using equally spaced
+ * color values.  Optional Floyd-Steinberg or ordered dithering is available.
+ */
+
+/* Declarations for Floyd-Steinberg dithering.
+ *
+ * Errors are accumulated into the array fserrors[], at a resolution of
+ * 1/16th of a pixel count.  The error at a given pixel is propagated
+ * to its not-yet-processed neighbors using the standard F-S fractions,
+ *		...	(here)	7/16
+ *		3/16	5/16	1/16
+ * We work left-to-right on even rows, right-to-left on odd rows.
+ *
+ * We can get away with a single array (holding one row's worth of errors)
+ * by using it to store the current row's errors at pixel columns not yet
+ * processed, but the next row's errors at columns already processed.  We
+ * need only a few extra variables to hold the errors immediately around the
+ * current column.  (If we are lucky, those variables are in registers, but
+ * even if not, they're probably cheaper to access than array elements are.)
+ *
+ * We provide (#columns + 2) entries per component; the extra entry at each
+ * end saves us from special-casing the first and last pixels.
+ */
+
+typedef INT16 FSERROR;		/* 16 bits should be enough */
+typedef int LOCFSERROR;		/* use 'int' for calculation temps */
+
+typedef struct { byte    *colorset;
+		 FSERROR *fserrors;
+	       } FSBUF;
+
+/* Floyd-Steinberg initialization function.
+ *
+ * It is called 'fs2_init' since it's specialized for our purpose and
+ * could be embedded in a more general FS-package.
+ *
+ * Returns a malloced FSBUF pointer which has to be passed as first
+ * parameter to subsequent 'fs2_dither' calls.
+ * The FSBUF structure does not need to be referenced by the calling
+ * application, it can be treated from the app like a void pointer.
+ *
+ * The current implementation does only require to free() this returned
+ * pointer after processing.
+ *
+ * Returns NULL if malloc fails.
+ *
+ * NOTE: The FSBUF structure is designed to allow the 'fs2_dither'
+ * function to work with an *arbitrary* number of color components
+ * at runtime! This is an enhancement over the IJG code base :-).
+ * Only fs2_init() specifies the (maximum) number of components.
+ */
+
+static FSBUF *fs2_init(width)
+int width;
+{
+  FSBUF *fs;
+  FSERROR *p;
+
+  fs = (FSBUF *)
+    malloc(sizeof(FSBUF) * 3 + ((size_t)width + 2) * sizeof(FSERROR) * 3);
+  if (fs == 0) return fs;
+
+  fs[0].colorset = screen_set[0];
+  fs[1].colorset = screen_set[1];
+  fs[2].colorset = screen_set[2];
+
+  p = (FSERROR *)(fs + 3);
+  memset(p, 0, ((size_t)width + 2) * sizeof(FSERROR) * 3);
+
+  fs[0].fserrors = p;
+  fs[1].fserrors = p + 1;
+  fs[2].fserrors = p + 2;
+
+  return fs;
+}
+
+/* Floyd-Steinberg dithering function.
+ *
+ * NOTE:
+ * (1) The image data referenced by 'ptr' is *overwritten* (input *and*
+ *     output) to allow more efficient implementation.
+ * (2) Alternate FS dithering is provided by the sign of 'nc'. Pass in
+ *     a negative value for right-to-left processing. The return value
+ *     provides the right-signed value for subsequent calls!
+ * (3) This particular implementation assumes *no* padding between lines!
+ *     Adapt this if necessary.
+ */
+
+static int fs2_dither(fs, ptr, nc, num_rows, num_cols)
+FSBUF *fs;
+byte *ptr;
+int nc, num_rows, num_cols;
+{
+  int abs_nc, ci, row, col;
+  LOCFSERROR delta, cur, belowerr, bpreverr;
+  byte *dataptr, *colsetptr;
+  FSERROR *errorptr;
+
+  if ((abs_nc = nc) < 0) abs_nc = -abs_nc;
+  for (row = 0; row < num_rows; row++) {
+    for (ci = 0; ci < abs_nc; ci++, ptr++) {
+      dataptr = ptr;
+      colsetptr = fs[ci].colorset;
+      errorptr = fs[ci].fserrors;
+      if (nc < 0) {
+	dataptr += (num_cols - 1) * abs_nc;
+	errorptr += (num_cols + 1) * abs_nc;
+      }
+      cur = belowerr = bpreverr = 0;
+      for (col = 0; col < num_cols; col++) {
+	cur += errorptr[nc];
+	cur += 8; cur >>= 4;
+	if ((cur += *dataptr) < 0) cur = 0;
+	else if (cur > 255) cur = 255;
+	*dataptr = cur & 0xff;
+	cur -= colsetptr[cur];
+	delta = cur << 1; cur += delta;
+	bpreverr += cur; cur += delta;
+	belowerr += cur; cur += delta;
+	errorptr[0] = (FSERROR)bpreverr;
+	bpreverr = belowerr;
+	belowerr = delta >> 1;
+	dataptr += nc;
+	errorptr += nc;
+      }
+      errorptr[0] = (FSERROR)bpreverr;
+    }
+    ptr += (num_cols - 1) * abs_nc;
+    nc = -nc;
+  }
+  return nc;
+}
+
+#endif /* ENABLE_FIXPIX_SMOOTH */
+
 
 #define DO_CROP 0
 #define DO_ZOOM 1
@@ -1348,7 +1621,7 @@
     SetISTR(ISTR_WARNING, "Invalid image dimensions for dithering");
     return (byte *)NULL;
   }
-  
+
   outpic = (byte *) malloc((size_t) npixels);
   if (!outpic) return outpic;
 
@@ -1838,7 +2111,7 @@
      unsigned int   wide, high;
 {
   /*
-   * this has to do the none-to-simple bit of converting the data in 'pic24'
+   * This has to do the none-too-simple bit of converting the data in 'pic24'
    * into something usable by X.
    *
    * There are two major approaches:  if we're displaying on a TrueColor
@@ -1852,7 +2125,7 @@
    * mode.  (In that by this point, a 3/3/2 standard colormap has been
    * created for our use (though all 256 colors may not be unique...), and
    * we're just going to display the 24-bit picture by dithering with those
-   * colors
+   * colors.)
    *
    */
 
@@ -1890,33 +2163,17 @@
     /* Non-ColorMapped Visuals:  TrueColor, DirectColor                     */
     /************************************************************************/
 
-    unsigned long r, g, b, rmask, gmask, bmask, xcol;
-    int           rshift, gshift, bshift, bperpix, bperline, border, cshift;
-    int           maplen;
+    unsigned long xcol;
+    int           bperpix, bperline;
     byte         *imagedata, *lip, *ip, *pp;
 
 
-    /* compute various shifting constants that we'll need... */
-
-    rmask = theVisual->red_mask;
-    gmask = theVisual->green_mask;
-    bmask = theVisual->blue_mask;
-
-    rshift = 7 - highbit(rmask);
-    gshift = 7 - highbit(gmask);
-    bshift = 7 - highbit(bmask);
-
-    maplen = theVisual->map_entries;
-    if (maplen>256) maplen=256;
-    cshift = 7 - highbit((u_long) (maplen-1));
-
     xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL,
 		        wide,  high, 32, 0);
     if (!xim) FatalError("couldn't create X image!");
 
     bperline = xim->bytes_per_line;
     bperpix  = xim->bits_per_pixel;
-    border   = xim->byte_order;
 
     imagedata = (byte *) malloc((size_t) (high * bperline));
     if (!imagedata) FatalError("couldn't malloc imagedata");
@@ -1930,85 +2187,141 @@
       FatalError(buf);
     }
 
+    screen_init();
 
-    lip = imagedata;  pp = pic24;
-    for (i=0; i<high; i++, lip+=bperline) {
-      for (j=0, ip=lip; j<wide; j++) {
-	r = *pp++;  g = *pp++;  b = *pp++;
-
-	/* shift r,g,b so that high bit of 8-bit color specification is
-	 * aligned with high bit of r,g,b-mask in visual,
-	 * AND each component with its mask,
-	 * and OR the three components together
-	 */
-
-	if (theVisual->class == DirectColor) {
-	  r = (u_long) directConv[(r>>cshift) & 0xff] << cshift;
-	  g = (u_long) directConv[(g>>cshift) & 0xff] << cshift;
-	  b = (u_long) directConv[(b>>cshift) & 0xff] << cshift;
-	}
-
-
-	/* shift the bits around */
-	if (rshift<0) r = r << (-rshift);
-	         else r = r >> rshift;
-
-	if (gshift<0) g = g << (-gshift);
-	         else g = g >> gshift;
-
-	if (bshift<0) b = b << (-bshift);
-	         else b = b >> bshift;
-
-	r = r & rmask;
-	g = g & gmask;
-	b = b & bmask;
-
-	xcol = r | g | b;
-
-	if (bperpix == 32) {
-	  if (border == MSBFirst) {
-	    *ip++ = (xcol>>24) & 0xff;
-	    *ip++ = (xcol>>16) & 0xff;
-	    *ip++ = (xcol>>8)  & 0xff;
-	    *ip++ =  xcol      & 0xff;
-	  }
-	  else {  /* LSBFirst */
-	    *ip++ =  xcol      & 0xff;
-	    *ip++ = (xcol>>8)  & 0xff;
-	    *ip++ = (xcol>>16) & 0xff;
-	    *ip++ = (xcol>>24) & 0xff;
-	  }
-	}
-
-	else if (bperpix == 24) {
-	  if (border == MSBFirst) {
-	    *ip++ = (xcol>>16) & 0xff;
-	    *ip++ = (xcol>>8)  & 0xff;
-	    *ip++ =  xcol      & 0xff;
-	  }
-	  else {  /* LSBFirst */
-	    *ip++ =  xcol      & 0xff;
-	    *ip++ = (xcol>>8)  & 0xff;
-	    *ip++ = (xcol>>16) & 0xff;
-	  }
-	}
+#ifdef ENABLE_FIXPIX_SMOOTH
+    if (do_fixpix_smooth) {
+#if 0
+      /* If we wouldn't have to save the original pic24 image data,
+       * the following code would do the dither job by overwriting
+       * the image data, and the normal render code would then work
+       * without any change on that data.
+       * Unfortunately, this approach would hurt the xv assumptions...
+       */
+      if (bperpix < 24) {
+        FSBUF *fs = fs2_init(wide);
+        if (fs) {
+	  fs2_dither(fs, pic24, 3, high, wide);
+	  free(fs);
+        }
+      }
+#else
+      /* ...so we have to take a different approach with linewise
+       * dithering/rendering in a loop using a temporary line buffer.
+       */
+      if (bperpix < 24) {
+        FSBUF *fs = fs2_init(wide);
+        if (fs) {
+	  byte *row_buf = malloc((size_t)wide * 3);
+	  if (row_buf) {
+	    int nc = 3;
+	    byte *picp = pic24;  lip = imagedata;
+
+	    switch (bperpix) {
+	      case 8:
+	        for (i=0; i<high; i++, lip+=bperline, picp+=(size_t)wide*3) {
+	          memcpy(row_buf, picp, (size_t)wide * 3);
+	          nc = fs2_dither(fs, row_buf, nc, 1, wide);
+	          for (j=0, ip=lip, pp=row_buf; j<wide; j++) {
+	            xcol  = screen_rgb[0][*pp++];
+	            xcol |= screen_rgb[1][*pp++];
+	            xcol |= screen_rgb[2][*pp++];
+		    *ip++ = xcol & 0xff;
+	          }
+	        }
+		break;
+
+	      case 16:
+	        for (i=0; i<high; i++, lip+=bperline, picp+=(size_t)wide*3) {
+	          CARD16 *ip16 = (CARD16 *)lip;
+	          memcpy(row_buf, picp, (size_t)wide * 3);
+	          nc = fs2_dither(fs, row_buf, nc, 1, wide);
+	          for (j=0, pp=row_buf; j<wide; j++) {
+	            xcol  = screen_rgb[0][*pp++];
+	            xcol |= screen_rgb[1][*pp++];
+	            xcol |= screen_rgb[2][*pp++];
+		    *ip16++ = (CARD16)xcol;
+	          }
+	        }
+		break;
+	    } /* end switch */
+
+	    free(row_buf);
+	    free(fs);
 
-	else if (bperpix == 16) {
-	  if (border == MSBFirst) {
-	    *ip++ = (xcol>>8)  & 0xff;
-	    *ip++ =  xcol      & 0xff;
-	  }
-	  else {  /* LSBFirst */
-	    *ip++ =  xcol      & 0xff;
-	    *ip++ = (xcol>>8)  & 0xff;
+	    return xim;
 	  }
-	}
-
-	else if (bperpix == 8) {
-	  *ip++ =  xcol      & 0xff;
-	}
+	  free(fs);
+        }
       }
+#endif /* 0? */
     }
+#endif /* ENABLE_FIXPIX_SMOOTH */
+
+    lip = imagedata;  pp = pic24;
+
+    switch (bperpix) {
+      case 8:
+        for (i=0; i<high; i++, lip+=bperline) {
+          for (j=0, ip=lip; j<wide; j++) {
+	    xcol  = screen_rgb[0][*pp++];
+	    xcol |= screen_rgb[1][*pp++];
+	    xcol |= screen_rgb[2][*pp++];
+	    *ip++ = xcol & 0xff;
+          }
+        }
+        break;
+
+      case 16:
+        for (i=0; i<high; i++, lip+=bperline) {
+          CARD16 *ip16 = (CARD16 *)lip;
+          for (j=0; j<wide; j++) {
+	    xcol  = screen_rgb[0][*pp++];
+	    xcol |= screen_rgb[1][*pp++];
+	    xcol |= screen_rgb[2][*pp++];
+	    *ip16++ = (CARD16)xcol;
+          }
+        }
+        break;
+
+      case 24:
+        for (i=0; i<high; i++, lip+=bperline) {
+          for (j=0, ip=lip; j<wide; j++) {
+	    xcol  = screen_rgb[0][*pp++];
+	    xcol |= screen_rgb[1][*pp++];
+	    xcol |= screen_rgb[2][*pp++];
+#ifdef USE_24BIT_ENDIAN_FIX
+	    if (border == MSBFirst) {
+	      *ip++ = (xcol>>16) & 0xff;
+	      *ip++ = (xcol>>8)  & 0xff;
+	      *ip++ =  xcol      & 0xff;
+	    }
+	    else {  /* LSBFirst */
+	      *ip++ =  xcol      & 0xff;
+	      *ip++ = (xcol>>8)  & 0xff;
+	      *ip++ = (xcol>>16) & 0xff;
+	    }
+#else /* GRR:  this came with the FixPix patch, but I don't think it's right */
+	    *ip++ = (xcol >> 16) & 0xff;    /* (no way to test, however, so  */
+	    *ip++ = (xcol >> 8)  & 0xff;    /* it's left enabled by default) */
+	    *ip++ =  xcol        & 0xff;
+#endif
+          }
+        }
+        break;
+
+      case 32:
+        for (i=0; i<high; i++, lip+=bperline) {
+          CARD32 *ip32 = (CARD32 *)lip;
+          for (j=0; j<wide; j++) {
+	    xcol  = screen_rgb[0][*pp++];
+	    xcol |= screen_rgb[1][*pp++];
+	    xcol |= screen_rgb[2][*pp++];
+	    *ip32++ = (CARD32)xcol;
+          }
+        }
+        break;
+    } /* end switch */
   }
 
   else {
@@ -2458,6 +2771,7 @@
 
 
 /***********************/
+#if 0 /* NOTUSED */
 static int highbit(ul)
 unsigned long ul;
 {
@@ -2470,6 +2784,7 @@
   for (i=31; ((ul & hb) == 0) && i>=0;  i--, ul<<=1);
   return i;
 }
+#endif /* 0 - NOTUSED */
 
 
 
@@ -2680,6 +2995,9 @@
      char *str;
      int   wide, high, opaque,omode;
 {
+#ifndef USE_MKSTEMP
+  int tmpfd;
+#endif
   int i;
   byte *bgpic24;
   char syscmd[512], fname[128], errstr[512];
@@ -2705,6 +3023,13 @@
   close(mkstemp(fname));
 #else
   mktemp(fname);
+  tmpfd = open(fname, O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR);
+  if (tmpfd < 0) {
+    sprintf(errstr, "Error: can't create temporary file %s", fname);
+    ErrPopUp(errstr, "\nDoh!");
+    return 0;
+  }
+  close(tmpfd);
 #endif
 
   /* run bggen to generate the background */
@@ -2978,7 +3303,7 @@
 
   ftype = ReadFileType(name);
 
-  if (ftype == RFT_COMPRESS) {    /* handle compressed/gzipped files */
+  if ((ftype == RFT_COMPRESS) || (ftype == RFT_BZIP2)) {  /* handle .Z,gz,bz2 */
 #ifdef VMS
     basefname[0] = '\0';
     strcpy(basefname, name);     /* remove trailing .Z */
@@ -2988,7 +3313,7 @@
     uncName = name;
 #endif
 
-    if (UncompressFile(uncName, uncompname)) {
+    if (UncompressFile(uncName, uncompname, ftype)) {
       ftype = ReadFileType(uncompname);
       readname = uncompname;
     }
@@ -3029,9 +3354,3 @@
 
   return 1;
 }
-
-
-
-
-
-
diff -ruN xv-3.10a-bugfixes/xvinfo.c xv-3.10a-enhancements/xvinfo.c
--- xv-3.10a-bugfixes/xvinfo.c	2004-05-16 18:03:43.000000000 -0700
+++ xv-3.10a-enhancements/xvinfo.c	2005-05-01 00:05:53.000000000 -0700
@@ -265,7 +265,7 @@
   if (stnum == ISTR_WARNING && !ctrlUp && !infoUp && !anyBrowUp &&
       strlen(istrs[stnum])) {
     OpenAlert(istrs[stnum]);
-    sleep(3);
+    sleep(1);  /* was 3, but _really_ slow for TIFFs with unknown tags... */
     CloseAlert();
   }
 }
diff -ruN xv-3.10a-bugfixes/xvjpeg.c xv-3.10a-enhancements/xvjpeg.c
--- xv-3.10a-bugfixes/xvjpeg.c	2005-03-27 16:23:06.000000000 -0800
+++ xv-3.10a-enhancements/xvjpeg.c	2005-04-17 14:45:28.000000000 -0700
@@ -51,11 +51,21 @@
 static    void         clickJD            PARM((int, int));
 static    void         doCmd              PARM((int));
 static    void         writeJPEG          PARM((void));
+#if JPEG_LIB_VERSION > 60
+METHODDEF(void)        xv_error_exit      PARM((j_common_ptr));
+METHODDEF(void)        xv_error_output    PARM((j_common_ptr));
+METHODDEF(void)        xv_prog_meter      PARM((j_common_ptr));
+#else
 METHODDEF void         xv_error_exit      PARM((j_common_ptr));
 METHODDEF void         xv_error_output    PARM((j_common_ptr));
 METHODDEF void         xv_prog_meter      PARM((j_common_ptr));
+#endif
 static    unsigned int j_getc             PARM((j_decompress_ptr));
+#if JPEG_LIB_VERSION > 60
+METHODDEF(boolean)     xv_process_comment PARM((j_decompress_ptr));
+#else
 METHODDEF boolean      xv_process_comment PARM((j_decompress_ptr));
+#endif
 static    int          writeJFIF          PARM((FILE *, byte *, int,int,int));
 
 
@@ -85,10 +95,10 @@
 
   XSelectInput(theDisp, jpegW, ExposureMask | ButtonPressMask | KeyPressMask);
 
-  DCreate(&qDial, jpegW, 10, 10, 80, 100, 1, 100, 75, 5,
+  DCreate(&qDial, jpegW, 10, 10, 80, 100, 1.0, 100.0, 75.0, 1.0, 5.0,
 	  infofg, infobg, hicol, locol, "Quality", "%");
 
-  DCreate(&smDial, jpegW, 120, 10, 80, 100, 0, 100, 0, 5,
+  DCreate(&smDial, jpegW, 120, 10, 80, 100, 0.0, 100.0, 0.0, 1.0, 5.0,
 	  infofg, infobg, hicol, locol, "Smoothing", "%");
 
   BTCreate(&jbut[J_BOK], jpegW, JWIDE-180-1, JHIGH-10-BUTTH-1, 80, BUTTH,
@@ -415,7 +425,11 @@
 
 
 /**************************************************/
-METHODDEF void xv_error_exit(cinfo)
+#if JPEG_LIB_VERSION > 60
+METHODDEF(void) xv_error_exit(cinfo)
+#else
+METHODDEF void  xv_error_exit(cinfo)
+#endif
      j_common_ptr cinfo;
 {
   my_error_ptr myerr;
@@ -427,7 +441,11 @@
 
 
 /**************************************************/
-METHODDEF void xv_error_output(cinfo)
+#if JPEG_LIB_VERSION > 60
+METHODDEF(void) xv_error_output(cinfo)
+#else
+METHODDEF void  xv_error_output(cinfo)
+#endif
      j_common_ptr cinfo;
 {
   my_error_ptr myerr;
@@ -441,7 +459,11 @@
 
 
 /**************************************************/
-METHODDEF void xv_prog_meter(cinfo)
+#if JPEG_LIB_VERSION > 60
+METHODDEF(void) xv_prog_meter(cinfo)
+#else
+METHODDEF void  xv_prog_meter(cinfo)
+#endif
      j_common_ptr cinfo;
 {
   struct jpeg_progress_mgr *prog;
@@ -706,7 +728,11 @@
 
 
 /**************************************************/
-METHODDEF boolean xv_process_comment(cinfo)
+#if JPEG_LIB_VERSION > 60
+METHODDEF(boolean) xv_process_comment(cinfo)
+#else
+METHODDEF boolean  xv_process_comment(cinfo)
+#endif
      j_decompress_ptr cinfo;
 {
   int          length, hasnull;
@@ -794,8 +820,8 @@
 
 
   jpeg_set_defaults(&cinfo);
-  jpeg_set_quality(&cinfo, qDial.val, TRUE);
-  cinfo.smoothing_factor = smDial.val;
+  jpeg_set_quality(&cinfo, (int)qDial.val, TRUE);
+  cinfo.smoothing_factor = (int)smDial.val;
 
 
   jpeg_start_compress(&cinfo, TRUE);
@@ -804,7 +830,7 @@
   /*** COMMENT HANDLING ***/
 
   sprintf(xvcmt, "%sXV %s  Quality = %d, Smoothing = %d\n",
-	  CREATOR_STR, REVDATE, qDial.val, smDial.val);
+	  CREATOR_STR, REVDATE, (int)qDial.val, (int)smDial.val);
 
   if (picComments) {   /* append XV comment */
     char *sp, *sp1;  int done;
@@ -866,4 +892,27 @@
 
 
 
+
+/*******************************************/
+void
+VersionInfoJPEG()	/* GRR 19980605, 19980607 */
+{
+  int major = JPEG_LIB_VERSION / 10;
+  int minor = JPEG_LIB_VERSION % 10;
+  char minoralpha[2];
+
+  if (minor) {
+    minoralpha[0] = (char)(minor - 1 + 'a');
+    minoralpha[1] = '\0';
+  } else
+    minoralpha[0] = '\0';
+
+/* fprintf(stderr, "   Compiled with libjpeg %d.%d.\n", major, minor); */
+  fprintf(stderr, "   Compiled with libjpeg %d%s.\n", major, minoralpha);
+}
+
+
+
+
+
 #endif  /* HAVE_JPEG */
diff -ruN xv-3.10a-bugfixes/xvmag.c xv-3.10a-enhancements/xvmag.c
--- xv-3.10a-bugfixes/xvmag.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvmag.c	2005-04-17 22:56:58.000000000 -0700
@@ -0,0 +1,866 @@
+/*
+ *  xvmag.c - load routine for `MAG' format pictures.
+ *
+ *  The `MAG' format is used by many Japanese personal computer users.
+ *  This program is based on MAGBIBLE.DOC which is the specification
+ *  for `MAG' format written by Woody RINN.  It is written in Japanese,
+ *  and exists in some anon-ftp sites.
+ */
+
+#include "xv.h"
+#include <setjmp.h>
+
+#ifdef HAVE_MAG
+
+typedef unsigned short data16;
+
+struct mag {
+    jmp_buf jmp;
+    FILE *fp;
+    long fsize;
+    int m_256, m_dig, m_8, m_200;
+    int x1, y1, x2, y2, left_pad, right_pad;
+    int p_width, p_height, width, height;
+    long h_off, a_off, a_size, b_off, b_size, p_off, p_size;
+    byte *a, *b, *p;
+};
+
+static void mag_open_file       PARM((struct mag*, char*));
+static void mag_read_check_data PARM((struct mag*));
+static void mag_read_comment    PARM((struct mag*, char**));
+static void mag_read_header     PARM((struct mag*));
+static void mag_read_palette    PARM((struct mag*, byte*, byte*, byte*));
+static void mag_read_flags      PARM((struct mag*));
+static void mag_read_pixel_data PARM((struct mag*));
+static void mag_expand_body     PARM((struct mag*, byte**));
+
+static void mag_compress_data    PARM((struct mag*, byte*));
+static void mag_write_check_data PARM((struct mag*));
+static void mag_write_comment    PARM((struct mag*, char *));
+static void mag_write_palette    PARM((struct mag*, int,
+				       byte*, byte*, byte*, int));
+static void mag_write_flags      PARM((struct mag*));
+static void mag_write_pixel_data PARM((struct mag*));
+static void mag_write_header     PARM((struct mag*));
+static void mag_set_double_word  PARM((long, byte *));
+
+static void mag_init_info        PARM((struct mag*));
+static void mag_cleanup_mag_info PARM((struct mag*, int));
+static void mag_cleanup_pinfo    PARM((PICINFO*));
+static void mag_memory_error     PARM((char*, char*));
+static void mag_error            PARM((struct mag*, int));
+static void mag_file_error       PARM((struct mag*, int));
+static void mag_file_warning     PARM((struct mag*, int));
+static void mag_show_struct      PARM((struct mag*));
+static void *mag_malloc          PARM((size_t, char*));
+static void *mag_realloc         PARM((void*, size_t, char*));
+
+
+static char *mag_id = "MAKI02  ";
+static struct{
+    int dx, dy;
+}points[16] = {
+    { 0,  0}, { 1,  0}, { 2,  0}, { 4,  0},
+    { 0,  1}, { 1,  1},
+    { 0,  2}, { 1,  2}, { 2,  2},
+    { 0,  4}, { 1,  4}, { 2,  4},
+    { 0,  8}, { 1,  8}, { 2,  8},
+    { 0, 16},
+};
+static int try[15] = {1, 4, 5, 6, 7, 9, 10, 2, 8, 11, 12, 13, 14, 3, 15};
+
+static char *mag_msgs[] = {
+    NULL,
+#define MAG_OPEN 1
+    "can't open file",
+#define MAG_CORRUPT 2
+    "file currupted.",
+#define MAG_FORMAT 3
+    "not MAG format.",
+#define MAG_WRITE 4
+    "write failed.",
+};
+
+
+#define H4(x) (((int) (x) >> 4) & 0x0f)	/* operates on a byte */
+#define L4(x) ((x) & 0x0f)
+#define H8(x) (((x) >> 8) & 0xff)	/* operates on a data16 */
+#define L8(x) ((x) & 0xff)
+
+#define error(msgnum) longjmp(mi->jmp, msgnum)
+
+
+/* The main routine to load a MAG file. */
+int LoadMAG(fname, pinfo)
+    char *fname;
+    PICINFO *pinfo;
+{
+    struct mag mag;
+    int e;
+
+    if(DEBUG) fputs("LoadMAG:\n", stderr);
+
+    pinfo->comment = NULL;
+    mag_init_info(&mag);
+    if((e = setjmp(mag.jmp)) != 0){
+	/* When an error occurs, comes here. */
+	mag_cleanup_mag_info(&mag, 0);
+	mag_cleanup_pinfo(pinfo);
+	return 0;
+    }
+
+    mag_open_file(&mag, fname);
+    mag_read_check_data(&mag);
+    mag_read_comment(&mag, &pinfo->comment);
+    mag_read_header(&mag);
+    mag_read_palette(&mag, pinfo->r, pinfo->g, pinfo->b);
+    mag_read_flags(&mag);
+    mag_read_pixel_data(&mag);
+    mag_expand_body(&mag, &pinfo->pic);
+
+    pinfo->w = pinfo->normw = mag.width;
+    pinfo->h = pinfo->normh = mag.height;
+    pinfo->type = PIC8;
+    pinfo->frmType = F_MAG;
+    pinfo->colType = F_FULLCOLOR;
+    sprintf(pinfo->fullInfo, "MAG, %d colors%s (%ld bytes)",
+	    mag.m_256 ? 256 : (mag.m_8 ? 8 : 16),
+	    mag.m_200 ? ", aspect 0.5" : "", mag.fsize);
+    sprintf(pinfo->shrtInfo, "%dx%d MAG", mag.width, mag.height);
+    if(mag.m_200)
+	normaspect = 0.5;
+
+    mag_cleanup_mag_info(&mag, 0);
+    return 1;
+}
+
+static void mag_open_file(mi, fname)
+    struct mag *mi;
+    char *fname;
+{
+    if((mi->fp = fopen(fname, "rb")) == NULL)
+	mag_file_error(mi, MAG_OPEN);
+    fseek(mi->fp, (size_t) 0, SEEK_END);
+    mi->fsize = ftell(mi->fp);
+    fseek(mi->fp, (size_t) 0, SEEK_SET);
+}
+
+static void mag_read_check_data(mi)
+    struct mag *mi;
+{
+    char buffer[8];
+
+    if(fread(buffer, (size_t) 8, (size_t) 1, mi->fp) != 1)
+	mag_file_error(mi, MAG_CORRUPT);
+    if(strncmp(buffer, mag_id, (size_t) 8) != 0)
+	mag_error(mi, MAG_FORMAT);
+}
+
+static void mag_read_comment(mi, p)
+    struct mag *mi;
+    char **p;
+{
+    int max = -1, i = 0;
+    int c;
+
+    while((c = fgetc(mi->fp)) != EOF){
+	if(c == 0x1a)
+	    break;
+	if(max < i){
+	    max += 16;
+	    *p = mag_realloc(*p, (size_t) max + 1, "mag_read_comment#1");
+	}
+	(*p)[i++] = c;
+    }
+
+    if(c == EOF)
+	mag_file_error(mi, MAG_CORRUPT);
+
+    if(max < i){
+	*p = mag_realloc(*p, (size_t) max + 2, "mag_read_comment#2");
+    }
+    if(i > 24){
+	(*p)[i] = '\0';
+	strcpy(*p, &(*p)[24]);
+    }else{
+	(*p)[0] = '\0';
+    }
+}
+
+static void mag_read_header(mi)
+    struct mag *mi;
+{
+    byte buf[32];
+
+    mi->h_off = ftell(mi->fp);
+
+    if(fread(buf, (size_t) 32, (size_t) 1, mi->fp) != 1)
+	mag_file_error(mi, MAG_CORRUPT);
+
+    mi->m_256 = buf[3] & 0x80;
+    mi->m_dig = buf[3] & 0x04;
+    mi->m_8   = buf[3] & 0x02;
+    mi->m_200 = buf[3] & 0x01;
+
+    mi->x1 = buf[ 4] + buf[ 5] * 256;
+    mi->y1 = buf[ 6] + buf[ 7] * 256;
+    mi->x2 = buf[ 8] + buf[ 9] * 256;
+    mi->y2 = buf[10] + buf[11] * 256;
+
+#define get_dword(a, b, c, d) \
+    ((long)(a) << 24 | (long)(b) << 16 | (long)(c) << 8 | (long)(d))
+
+    mi->a_off  = get_dword(buf[15], buf[14], buf[13], buf[12]);
+    mi->b_off  = get_dword(buf[19], buf[18], buf[17], buf[16]);
+    mi->b_size = get_dword(buf[23], buf[22], buf[21], buf[20]);
+    mi->p_off  = get_dword(buf[27], buf[26], buf[25], buf[24]);
+    mi->p_size = get_dword(buf[31], buf[30], buf[29], buf[28]);
+#undef get_dword
+
+    mi->a_size = mi->b_off - mi->a_off;
+    mi->a_off += mi->h_off;
+    mi->b_off += mi->h_off;
+    mi->p_off += mi->h_off;
+
+    mi->width     = mi->x2 - mi->x1 + 1;
+    mi->height    = mi->y2 - mi->y1 + 1;
+    mi->left_pad  =       mi->x1 & 07;
+    mi->right_pad = 07 - (mi->x2 & 07);
+    mi->x1       -= mi->left_pad;		/* x1 = 8m   */
+    mi->x2       += mi->right_pad;		/* x2 = 8n+7 */
+    mi->p_width   = ((mi->x2 + 1) - mi->x1) / (mi->m_256 ? 2 : 4);
+    mi->p_height  =  (mi->y2 + 1) - mi->y1;
+
+    if(DEBUG) mag_show_struct(mi);
+}
+
+static void mag_read_palette(mi, r, g, b)
+    struct mag *mi;
+    byte *r, *g, *b;
+{
+    int num_palettes;
+    byte *buf;
+
+    if(mi->m_256)
+	num_palettes = 256;
+    else
+	num_palettes = 16;
+
+    buf = mag_malloc((size_t)num_palettes * 3, "mag_read_palette");
+
+    if(fread(buf, (size_t) 3, (size_t) num_palettes, mi->fp) != num_palettes){
+	free(buf);
+	mag_file_error(mi, MAG_CORRUPT);
+    }
+
+    for(num_palettes--; num_palettes >= 0; num_palettes--){
+	g[num_palettes] = buf[num_palettes * 3    ];
+	r[num_palettes] = buf[num_palettes * 3 + 1];
+	b[num_palettes] = buf[num_palettes * 3 + 2];
+    }
+
+    free(buf);
+}
+
+static void mag_read_flags(mi)
+     struct mag *mi;
+{
+    mi->a = mag_malloc((size_t) mi->a_size, "mag_read_flags#1");
+    mi->b = mag_malloc((size_t) mi->b_size, "mag_read_flags#2");
+
+    fseek(mi->fp, mi->a_off, SEEK_SET);
+    if(fread(mi->a, (size_t) mi->a_size, (size_t) 1, mi->fp) != 1)
+	mag_file_warning(mi, MAG_CORRUPT);
+    if(fread(mi->b, (size_t) mi->b_size, (size_t) 1, mi->fp) != 1)
+	mag_file_warning(mi, MAG_CORRUPT);
+}
+
+static void mag_read_pixel_data(mi)
+    struct mag *mi;
+{
+    mi->p = mag_malloc((size_t) mi->p_size, "mag_read_pixel_data");
+
+    fseek(mi->fp, mi->p_off, SEEK_SET);
+    if(fread(mi->p, (size_t) mi->p_size, (size_t) 1, mi->fp) != 1)
+	mag_file_warning(mi, MAG_CORRUPT);
+}
+
+/* MAG expanding routine */
+static void mag_expand_body(mi, pic0)
+    struct mag *mi;
+    byte **pic0;
+{
+    int ai, bi, fi, pi;
+    int px, py, x, y;
+    byte *flag;
+    byte mask;
+    data16 *pixel0;
+
+    flag   = mag_malloc((size_t) mi->p_width / 2, "mag_expand_body#1");
+    *pic0  = mag_malloc((size_t) mi->width * mi->height, "mag_expand_body#2");  // GRR POSSIBLE OVERFLOW / FIXME
+    pixel0 = mag_malloc((size_t) 2 * mi->p_width * 17, "mag_expand_body#3");  // GRR POSSIBLE OVERFLOW / FIXME
+
+#define pixel(x, y) pixel0[(y) % 17 * mi->p_width + (x)]
+
+    ai = bi = pi = 0;
+    mask = 0x80;
+    for(y = py = 0; py < mi->p_height; py++){
+	for(fi = 0; fi < mi->p_width / 2; fi++){
+	    if(py == 0){
+		if(mi->a[ai] & mask)
+		    flag[fi] = mi->b[bi++];
+		else
+		    flag[fi] = 0;
+	    }else{
+		if(mi->a[ai] & mask)
+		    flag[fi] ^= mi->b[bi++];
+	    }
+	    if((mask >>= 1) == 0){
+		mask = 0x80;
+		ai++;
+	    }
+	}
+
+	for(px = fi = 0; fi < mi->p_width / 2; fi++){
+	    int f = H4(flag[fi]);
+	    if(f == 0){
+		pixel(px, py) = mi->p[pi] + mi->p[pi + 1] * 256;
+		px++;
+		pi+=2;
+	    }else{
+		int dx = points[f].dx, dy = points[f].dy;
+		pixel(px, py) = pixel(px - dx, py - dy);
+		px++;
+	    }
+
+	    f = L4(flag[fi]);
+	    if(f == 0){
+		pixel(px, py) = mi->p[pi] + mi->p[pi + 1] * 256;
+		px++;
+		pi+=2;
+	    }else{
+		int dx = points[f].dx, dy = points[f].dy;
+		pixel(px, py) = pixel(px - dx, py - dy);
+		px++;
+	    }
+	}
+
+#define inside(x) ((unsigned int)(x) < mi->width)
+#define  pic(x, y) (*pic0)[(y) * mi->width + (x)]
+	for(x = -mi->left_pad, px = 0; px < mi->p_width; px++){
+	    data16 p = pixel(px, py);
+	    if(mi->m_256){
+		if(inside(x))
+		    pic(x, y) = L8(p);
+		x++;
+		if(inside(x))
+		    pic(x, y) = H8(p);
+		x++;
+	    }else{
+		if(inside(x))
+		    pic(x, y) = H4(L8(p));
+		x++;
+		if(inside(x))
+		    pic(x, y) = L4(L8(p));
+		x++;
+		if(inside(x))
+		    pic(x, y) = H4(H8(p));
+		x++;
+		if(inside(x))
+		    pic(x, y) = L4(H8(p));
+		x++;
+	    }
+	}
+	y++;
+    }
+#undef pic
+#undef inside
+#undef pixel
+
+    free(flag);
+    free(pixel0);
+}
+
+
+/* The main routine to write a MAG file. */
+int WriteMAG(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle,
+	      comment)
+    FILE *fp;
+    byte *pic;
+    int ptype, w, h;
+    byte *rmap, *gmap, *bmap;
+    int numcols, colorstyle;
+    char *comment;
+{
+    byte rtemp[256], gtemp[256], btemp[256];
+    struct mag mag;
+    int e;
+
+    if(DEBUG) fputs("WriteMag\n", stderr);
+
+    mag_init_info(&mag);
+    mag.fp = fp;
+
+    if(ptype == PIC24){
+	if(!(pic = Conv24to8(pic, w, h, 256, rtemp, gtemp, btemp)))
+	    mag_memory_error("Conv24to8", "WriteMAG");
+	rmap = rtemp;
+	gmap = gtemp;
+	bmap = btemp;
+	numcols = 256;
+	mag.m_256 = 1;
+    }else{
+	if(numcols > 16)
+	    mag.m_256 = 1;
+    }
+
+    if((e = setjmp(mag.jmp)) != 0){
+	/* When an error occurs, comes here. */
+	mag_cleanup_mag_info(&mag, 1);
+	return -1;
+    }
+
+    mag.x2 = w - 1;
+    mag.y2 = h - 1;
+    mag.right_pad = 07 - (mag.x2 & 07);
+    mag.p_width = (w + mag.right_pad) / (mag.m_256 ? 2 : 4);
+    mag.p_height = h;
+    mag.width = w;
+    mag.height = h;
+    mag.a_size = (mag.p_width * mag.p_height + 15) / 16;	/* x/2/8 */   // GRR POSSIBLE OVERFLOW / FIXME
+    if(mag.a_size % 2)
+	mag.a_size++;
+
+    mag_compress_data(&mag, pic);
+    mag_write_check_data(&mag);
+    mag_write_comment(&mag, comment);
+
+    mag.h_off = ftell(mag.fp);
+
+    mag_write_palette(&mag, numcols, rmap, gmap, bmap,
+		      colorstyle == F_GREYSCALE);
+    mag_write_flags(&mag);
+    mag_write_pixel_data(&mag);
+    mag_write_header(&mag);
+
+    mag_cleanup_mag_info(&mag, 1);
+    return 0;
+}
+
+/* MAG compressing routine */
+static void mag_compress_data(mi, pic0)
+    struct mag *mi;
+    byte *pic0;
+{
+    int ai, bi, pi, i;
+    int bmax, pmax;
+    byte mask;
+    byte *flag0;
+    data16 *pixel0;
+    int px, py, x, y;
+
+    pixel0 = mag_malloc((size_t) 2 * mi->p_width * mi->p_height,  // GRR POSSIBLE OVERFLOW / FIXME
+			"mag_compress_data#1");
+    flag0 = mag_malloc((size_t) mi->p_width * mi->p_height,  // GRR POSSIBLE OVERFLOW / FIXME
+		       "mag_compress_data#2");
+
+#define pic(x, y) pic0[(y) * mi->width + (x)]
+    /* convert dots to pixels */
+    i = 0;
+    for(y = py = 0; py < mi->p_height; py++){
+	for(x = px = 0; px < mi->p_width; px++){
+	    data16 p = 0;
+	    if(mi->m_256){
+		if(x < mi->width)
+		    p += pic(x, y);
+		x++;
+		if(x < mi->width)
+		    p += pic(x, y) * 256;
+		x++;
+	    }else{
+		if(x < mi->width)
+		    p += pic(x, y) * 16;
+		x++;
+		if(x < mi->width)
+		    p += pic(x, y);
+		x++;
+		if(x < mi->width)
+		    p += pic(x, y) * 4096;
+		x++;
+		if(x < mi->width)
+		    p += pic(x, y) * 256;
+		x++;
+	    }
+	    pixel0[i++] = p;
+	}
+	y++;
+    }
+#undef pic
+
+#define pixel(x, y) pixel0[(y) * mi->p_width + (x)]
+#define  flag(x, y)  flag0[(y) * mi->p_width + (x)]
+    /* get flags */
+    pmax = pi = 0;
+    for(py = 0; py < mi->p_height; py++){
+	for(px = 0; px < mi->p_width; px++){
+	    int t;
+	    for(t = 0; t < 15; t++){
+		int dx = points[try[t]].dx, dy = points[try[t]].dy;
+		if(dx <= px && dy <= py){
+		    if(pixel(px - dx, py - dy) == pixel(px, py))
+			break;
+		}
+	    }
+	    if(t < 15){
+		flag(px, py) = try[t];
+	    }else{
+		flag(px, py) = 0;
+		if(pmax <= pi + 1){
+		    pmax += 128;
+		    mi->p = mag_realloc(mi->p, (size_t) pmax,
+					"mag_compress_data#3");
+		}
+		mi->p[pi++] = L8(pixel(px, py));
+		mi->p[pi++] = H8(pixel(px, py));
+	    }
+	}
+    }
+#undef flag
+#undef pixel
+
+    /* pack 2 flags into 1 byte */
+    for(i = 0; i < mi->p_width / 2 * mi->p_height; i++)
+	flag0[i] = flag0[i * 2] * 16 + flag0[i * 2 + 1];
+
+#define flag(x, y)  flag0[(y) * mi->p_width / 2 + (x)]
+    for(py = mi->p_height - 1; py >= 1; py--){
+	for(px = 0; px < mi->p_width / 2; px++)
+	    flag(px, py) ^= flag(px, py - 1);
+    }
+#undef flag
+
+    mask = 0x80;
+    ai = bi = bmax = 0;
+    mi->a = mag_malloc((size_t) mi->a_size, "mag_compress_data#4");   // GRR POSSIBLE OVERFLOW / FIXME
+    for(i = 0; i < mi->p_width / 2 * mi->p_height; i++){
+	if(flag0[i] == 0){
+	    mi->a[ai] &= ~mask;
+	}else{
+	    if(bmax == bi){
+		bmax += 128;
+		mi->b = mag_realloc(mi->b, (size_t) bmax,
+				    "mag_compress_data#4");
+	    }
+	    mi->b[bi++] = flag0[i];
+	    mi->a[ai] |= mask;
+	}
+
+	if((mask >>= 1) == 0){
+	    mask = 0x80;
+	    ai++;
+	}
+    }
+
+    if(bi % 2)
+	bi++;
+    mi->b_size = bi;
+
+    mi->p_size = pi;
+
+    free(pixel0);
+    free(flag0);
+}
+
+static void mag_write_check_data(mi)
+    struct mag *mi;
+{
+    if(fwrite(mag_id, (size_t) 8, (size_t) 1, mi->fp) != 1)
+	mag_file_error(mi, MAG_WRITE);
+}
+
+static void mag_write_comment(mi, comment)
+    struct mag *mi;
+    char *comment;
+{
+    char *p;
+    int i;
+
+    if(fputs("XV   ", mi->fp) == EOF)
+	mag_file_error(mi, MAG_WRITE);
+
+    if((p = (char *) getenv("USER")) == NULL)
+	p = "????????";
+    for(i = 5; i < 24; i++){
+	if(*p == '\0')
+	    break;
+	if(fputc(*p++, mi->fp) == EOF)
+	    mag_file_error(mi, MAG_WRITE);
+    }
+    for( ; i < 24; i++){
+	if(fputc(' ', mi->fp) == EOF)
+	    mag_file_error(mi, MAG_WRITE);
+    }
+
+    if(comment){
+	int l = strlen(comment);
+	if(l > 0){
+	    int i;
+	    for(i = 0; i < l; i++){
+		if(comment[i] == 0x1a)
+		    comment[i] = ' ';
+	    }
+	    if(fwrite(comment, (size_t) l, (size_t) 1, mi->fp) != 1)
+		mag_file_error(mi, MAG_WRITE);
+	}
+    }
+
+    if(fputc(0x1a, mi->fp) == EOF)
+	mag_file_error(mi, MAG_WRITE);
+}
+
+static void mag_write_palette(mi, num, r, g, b, grey)
+    struct mag *mi;
+    int num;
+    byte *r, *g, *b;
+    int grey;
+{
+    int i, left;
+    char buf[3];
+
+    fseek(mi->fp, 32L, SEEK_CUR);	/* skip header area */
+    for(i = 0; i < num; i++){
+	buf[0] = *g++;
+	buf[1] = *r++;
+	buf[2] = *b++;
+	if(grey)
+	    buf[0] = buf[1] = buf[2] = MONO(buf[1], buf[0], buf[2]);
+	if(fwrite(buf, (size_t) 3, (size_t) 1, mi->fp) != 1)
+	    mag_file_error(mi, MAG_WRITE);
+    }
+    if(num < 16){
+	left = 16 - num;
+    }else if(num == 16){
+	left = 0;
+    }else if(num < 256){
+	left = 256 - num;
+    }else if(num == 256){
+	left = 0;
+    }else
+	left = 0;	/* shouldn't happen */
+
+    if(left > 0){
+	for(i = 0; i < left; i++){
+	    if(fwrite(buf, (size_t) 3, (size_t) 1, mi->fp) != 1)
+		mag_file_error(mi, MAG_WRITE);
+	}
+    }
+}
+
+static void mag_write_flags(mi)
+    struct mag *mi;
+{
+    int i;
+
+    mi->a_off = ftell(mi->fp);
+    for(i = 0; i < mi->a_size; i++){
+	if(fputc(mi->a[i], mi->fp) == EOF)
+	    mag_file_error(mi, MAG_WRITE);
+    }
+
+    mi->b_off = ftell(mi->fp);
+    for(i = 0; i < mi->b_size; i++){
+	if(fputc(mi->b[i], mi->fp) == EOF)
+	    mag_file_error(mi, MAG_WRITE);
+    }
+}
+
+static void mag_write_pixel_data(mi)
+    struct mag *mi;
+{
+    int i;
+
+    mi->p_off = ftell(mi->fp);
+    for(i = 0; i < mi->p_size; i++){
+	if(fputc(mi->p[i], mi->fp) == EOF)
+	    mag_file_error(mi, MAG_WRITE);
+    }
+}
+
+static void mag_write_header(mi)
+    struct mag *mi;
+{
+    byte buf[32];
+
+    if(DEBUG) mag_show_struct(mi);
+
+    mi->a_off -= mi->h_off;
+    mi->b_off -= mi->h_off;
+    mi->p_off -= mi->h_off;
+
+    buf[ 0] = buf[1] = buf[2] = 0;
+    buf[ 3] = (mi->m_256 ? 0x80 : 0);
+    buf[ 4] = buf[5] = 0;
+    buf[ 6] = buf[7] = 0;
+    buf[ 8] = L8(mi->x2);
+    buf[ 9] = H8(mi->x2);
+    buf[10] = L8(mi->y2);
+    buf[11] = H8(mi->y2);
+    mag_set_double_word(mi->a_off,  &buf[12]);
+    mag_set_double_word(mi->b_off,  &buf[16]);
+    mag_set_double_word(mi->b_size, &buf[20]);
+    mag_set_double_word(mi->p_off,  &buf[24]);
+    mag_set_double_word(mi->p_size, &buf[28]);
+
+    fseek(mi->fp, mi->h_off, SEEK_SET);
+    if(fwrite(buf, (size_t) 32, (size_t) 1, mi->fp) != 1)
+	mag_file_error(mi, MAG_WRITE);
+}
+
+static void mag_set_double_word(n, p)
+    long n;
+    byte *p;
+{
+    p[0] = n % 256;	/* ugly...anything wrong with shift/mask operations? */
+    p[1] = n / 256 % 256;		/* (n >> 8) & 0xff */
+    p[2] = n / 256 / 256 % 256;	/* (n >> 16) & 0xff */
+    p[3] = n / 256 / 256 / 256 % 256;	/* (n >> 24) & 0xff */
+}
+
+/*
+ * The routines to initialize or clean up.
+ * mag_init_info:
+ *	initializes a mag structure.
+ * mag_cleanup_mag_info:
+ *	cleans up a mag structure.
+ * mag_cleanup_pinfo:
+ *	cleans up a PICINFO structure.
+ */
+static void mag_init_info(mi)
+    struct mag *mi;
+{
+    mi->fp = NULL;
+    mi->fsize = 0;
+    mi->m_256 = mi->m_dig = mi->m_8 = mi->m_200 = 0;
+    mi->x1 = mi->y1 = mi->x2 = mi->y2 = 0;
+    mi->left_pad = mi->right_pad = 0;
+    mi->p_width = mi->p_height = mi->width = mi->height = 0;
+    mi->h_off = mi->p_off = mi->p_size = 0;
+    mi->a_off = mi->a_size = mi->b_off = mi->b_size = 0;
+    mi->a = NULL;
+    mi->b = NULL;
+    mi->p = NULL;
+}
+
+static void mag_cleanup_mag_info(mi, writing)
+    struct mag *mi;
+    int writing;
+{
+    if(mi->fp && !writing)
+	fclose(mi->fp);
+    if(mi->a)
+	free(mi->a);
+    if(mi->b)
+	free(mi->b);
+    if(mi->p)
+	free(mi->p);
+}
+
+static void mag_cleanup_pinfo(pinfo)
+    PICINFO *pinfo;
+{
+    if(pinfo->comment){
+	free(pinfo->comment);
+	pinfo->comment = NULL;
+    }
+    if(pinfo->pic){
+	free(pinfo->pic);
+	pinfo->pic = NULL;
+    }
+}
+
+/*
+ * Error handler.
+ * mag_memory_error:
+ *	shows an error message, and terminates.
+ * mag_error:
+ *	shows an non-file error message, and jumps to the entry for errors.
+ * mag_file_error:
+ *	shows an file error message, and jumps to the entry for errors.
+ * mag_file_warning:
+ *	shows an file warning message.
+ */
+static void mag_memory_error(scm, fn)
+    char *scm, *fn;
+{
+    char buf[128];
+    sprintf(buf, "%s: can't allocate memory. (%s)", scm, fn);
+    FatalError(buf);
+}
+
+static void mag_error(mi, mn)
+    struct mag *mi;
+    int mn;
+{
+    SetISTR(ISTR_WARNING, "%s", mag_msgs[mn]);
+    longjmp(mi->jmp, 1);
+}
+
+static void mag_file_error(mi, mn)
+    struct mag *mi;
+    int mn;
+{
+    if(feof(mi->fp))
+	SetISTR(ISTR_WARNING, "%s (end of file)", mag_msgs[mn]);
+    else
+	SetISTR(ISTR_WARNING, "%s (%s)", mag_msgs[mn], ERRSTR(errno));
+    longjmp(mi->jmp, 1);
+}
+
+static void mag_file_warning(mi, mn)
+    struct mag *mi;
+    int mn;
+{
+    if(feof(mi->fp))
+	SetISTR(ISTR_WARNING, "%s (end of file)", mag_msgs[mn]);
+    else
+	SetISTR(ISTR_WARNING, "%s (%s)", mag_msgs[mn], ERRSTR(errno));
+}
+
+static void mag_show_struct (mi)
+    struct mag *mi;
+{
+    fprintf(stderr, "  256 colors: %s\n", mi->m_256 ? "true" : "false");
+    fprintf(stderr, "  8 colors: %s\n", mi->m_8 ? "true" : "false");
+    fprintf(stderr, "  digital colors: %s\n", mi->m_dig ? "true" : "false");
+    fprintf(stderr, "  aspect ratio: %f\n", mi->m_200 ? 0.5 : 1.0);
+    fprintf(stderr, "  image size: %dx%d\n", mi->width, mi->height);
+    fprintf(stderr, "  left pad: %d\n", mi->left_pad);
+    fprintf(stderr, "  right pad: %d\n", mi->right_pad);
+    fprintf(stderr, "  h_off: %ld\n", mi->h_off);
+    fprintf(stderr, "  A: off:%ld, size:%ld\n", mi->a_off, mi->a_size);
+    fprintf(stderr, "  B: off:%ld, size:%ld\n", mi->b_off, mi->b_size);
+    fprintf(stderr, "  P: off:%ld, size:%ld\n", mi->p_off, mi->p_size);
+}
+
+/* Memory related routines. */
+static void *mag_malloc(n, fn)
+    size_t n;
+    char *fn;
+{
+    void *r = (void *) malloc(n);
+    if(r == NULL)
+	mag_memory_error("malloc", fn);
+    return r;
+}
+
+static void *mag_realloc(p, n, fn)
+    void *p;
+    size_t n;
+    char *fn;
+{
+    void *r = (p == NULL) ? (void *) malloc(n) : (void *) realloc(p, n);
+    if(r == NULL)
+	mag_memory_error("realloc", fn);
+    return r;
+}
+#endif /* HAVE_MAG */
diff -ruN xv-3.10a-bugfixes/xvmaki.c xv-3.10a-enhancements/xvmaki.c
--- xv-3.10a-bugfixes/xvmaki.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvmaki.c	2005-04-17 22:57:01.000000000 -0700
@@ -0,0 +1,794 @@
+/*
+ * xvmaki.c - load routine for `MAKI' format pictures.
+ *
+ * The `MAKI' format was used by some Japanese personal computer users.
+ */
+
+#include "xv.h"
+#include <setjmp.h>
+
+#ifdef HAVE_MAKI
+
+typedef unsigned short data16;
+typedef unsigned int data32;
+
+struct maki_info {
+    jmp_buf jmp;
+    FILE *fp;
+    long fsize;
+    int x0, y0, x1, y1;
+    int width, height;
+    float aspect;
+    long fb_size;
+    long pa_size, pb_size;
+    int m_maki01b, m_200, m_dig8;
+    data16 ext_flag;
+    byte *fa, *fb, *pa, *pb;
+    byte *vs;
+    int numcols;
+    byte *forma, *formb;
+};
+
+
+static void maki_open_file             PARM((struct maki_info*, char*));
+static void maki_check_id              PARM((struct maki_info*));
+static void maki_skip_comment          PARM((struct maki_info*));
+static void maki_read_header           PARM((struct maki_info*));
+static void maki_read_palette          PARM((struct maki_info*,
+					     byte*, byte*, byte*));
+static void maki_read_flags            PARM((struct maki_info*));
+static void maki_read_pixel_data       PARM((struct maki_info*));
+static void maki_expand_virtual_screen PARM((struct maki_info*));
+static void maki_expand_pixel_data     PARM((struct maki_info*, byte**));
+static void maki_init_info             PARM((struct maki_info*));
+
+static void maki_make_pixel_data       PARM((struct maki_info*, byte*));
+static void maki_make_virtual_screen   PARM((struct maki_info*));
+static void maki_make_flags            PARM((struct maki_info*));
+static void maki_write_check_id        PARM((struct maki_info*));
+static void maki_write_comment         PARM((struct maki_info*));
+static void maki_write_header          PARM((struct maki_info*));
+static void maki_write_palette         PARM((struct maki_info*,
+					     byte*, byte*, byte*, int));
+static void maki_write_flags           PARM((struct maki_info*));
+static void maki_write_pixel_data      PARM((struct maki_info*));
+
+static void maki_cleanup_maki_info     PARM((struct maki_info*, int));
+static void maki_cleanup_pinfo         PARM((PICINFO*));
+static void maki_memory_error          PARM((char*, char*));
+static void maki_error                 PARM((struct maki_info*, int));
+static void maki_file_error            PARM((struct maki_info*, int));
+static void maki_file_warning          PARM((struct maki_info*, int));
+static void maki_show_maki_info        PARM((struct maki_info*));
+static void *maki_malloc               PARM((size_t, char*));
+static void *maki_realloc              PARM((void *, size_t, char*));
+
+static char maki_id_a[] = "MAKI01A ";
+static char maki_id_b[] = "MAKI01B ";
+
+static char *maki_msgs[] = {
+    NULL,
+#define MAKI_OPEN 1
+    "can't open file.",
+#define MAKI_CORRUPT 2
+    "file corrupted.",
+#define MAKI_FORMAT 3
+    "not MAKI format.",
+#define MAKI_BAD_DATA 4
+    "bad data.",
+#define MAKI_COMMENT 5
+    "no '^Z' after comment.",
+#define MAKI_SIZE 6
+    "bad size.",
+#define MAKI_WRITE 7
+    "write failed.",
+};
+
+#define H4(b) ((b) >> 4 & 0xf)
+#define L4(b) ((b)      & 0xf)
+#define error(msg_num) longjmp(mi->jmp, msg_num)
+
+int LoadMAKI(fname, pinfo)
+    char *fname;
+    PICINFO *pinfo;
+{
+    struct maki_info maki;
+    int e;
+
+    if(DEBUG) fputs("LoadMAKI:\n", stderr);
+
+    pinfo->comment = NULL;
+    maki_init_info(&maki);
+    if((e = setjmp(maki.jmp)) != 0){
+	/* When an error occurs, comes here. */
+	maki_cleanup_maki_info(&maki, 0);
+	maki_cleanup_pinfo(pinfo);
+	return 0;
+    }
+
+    maki_open_file(&maki, fname);
+    maki_check_id(&maki);
+    maki_skip_comment(&maki);
+    maki_read_header(&maki);
+    maki_read_palette(&maki, pinfo->r, pinfo->g, pinfo->b);
+    maki_read_flags(&maki);
+    maki_read_pixel_data(&maki);
+    maki_expand_virtual_screen(&maki);
+    maki_expand_pixel_data(&maki, &pinfo->pic);
+
+    pinfo->w = pinfo->normw = maki.width;
+    pinfo->h = pinfo->normh = maki.height;
+    pinfo->type = PIC8;
+    pinfo->frmType = F_MAKI;
+    pinfo->colType = F_FULLCOLOR;
+    sprintf(pinfo->fullInfo, "MAKI, 16 colors (%ld bytes)", maki.fsize);
+    sprintf(pinfo->shrtInfo, "%dx%d MAKI", maki.width, maki.height);
+    normaspect = maki.aspect;
+
+    maki_cleanup_maki_info(&maki, 0);
+    return 1;
+}
+
+static void maki_open_file(mi, fname)
+    struct maki_info *mi;
+    char *fname;
+{
+    if((mi->fp = fopen(fname, "rb")) == NULL)
+	maki_file_error(mi, MAKI_OPEN);
+    fseek(mi->fp, (size_t) 0, SEEK_END);
+    mi->fsize = ftell(mi->fp);
+    fseek(mi->fp, (size_t) 0, SEEK_SET);
+}
+
+static void maki_check_id(mi)
+    struct maki_info *mi;
+{
+    char buf[8];
+    if(fread(buf, (size_t) 8, (size_t) 1, mi->fp) != 1)
+	maki_file_error(mi, MAKI_CORRUPT);
+    if(strncmp(buf, maki_id_a, (size_t) 8) != 0 &&
+       strncmp(buf, maki_id_b, (size_t) 8) != 0)
+	maki_error(mi, MAKI_FORMAT);
+    mi->m_maki01b = (buf[6] == 'B');
+}
+
+static void maki_skip_comment(mi)
+    struct maki_info *mi;
+{
+    int i;
+    int c;
+
+    for(i = 0; i < 24; i++){
+	if((c = fgetc(mi->fp)) == EOF)
+	    maki_file_error(mi, MAKI_CORRUPT);
+	if(c == '\032')	/* ^Z, 0x1a */
+	    break;
+    }
+    if(c != '\032')
+	maki_file_error(mi, MAKI_COMMENT);
+
+    fseek(mi->fp, 32L, SEEK_SET);
+}
+
+static void maki_read_header(mi)
+    struct maki_info *mi;
+{
+    byte buf[16];
+
+    if(fread(buf, (size_t) 16, (size_t) 1, mi->fp) != 1)
+	maki_file_error(mi, MAKI_CORRUPT);
+
+    mi->fb_size  = (long)buf[ 0] << 8 | (long)buf[ 1];
+    mi->pa_size  = (long)buf[ 2] << 8 | (long)buf[ 3];
+    mi->pb_size  = (long)buf[ 4] << 8 | (long)buf[ 5];
+    mi->ext_flag = (long)buf[ 6] << 8 | (long)buf[ 7];
+    mi->x0       = (long)buf[ 8] << 8 | (long)buf[ 9];
+    mi->y0       = (long)buf[10] << 8 | (long)buf[11];
+    mi->x1       = (long)buf[12] << 8 | (long)buf[13];
+    mi->y1       = (long)buf[14] << 8 | (long)buf[15];
+
+    mi->width  = mi->x1-- - mi->x0;
+    mi->height = mi->y1-- - mi->y0;
+    mi->m_200  = mi->ext_flag & 1;
+    mi->m_dig8 = mi->ext_flag & 2;
+    mi->aspect = mi->m_200 ? 0.5 : 1.0;
+
+    if(DEBUG) maki_show_maki_info(mi);
+}
+
+static void maki_read_palette(mi, r, g, b)
+    struct maki_info *mi;
+    byte *r, *g, *b;
+{
+    byte buf[48], *p;
+
+    if(fread(buf, (size_t) 48, (size_t) 1, mi->fp) != 1)
+	maki_file_error(mi, MAKI_CORRUPT);
+
+    for(p = buf; p < &buf[48]; ){
+	*g++ = *p++;
+	*r++ = *p++;
+	*b++ = *p++;
+    }
+}
+
+static void maki_read_flags(mi)
+    struct maki_info *mi;
+{
+    mi->fa = maki_malloc((size_t) 1000       , "maki_read_flags#1");
+    mi->fb = maki_malloc((size_t) mi->fb_size, "maki_read_flags#2");
+
+    if(fread(mi->fa, (size_t) 1000, (size_t) 1, mi->fp) != 1)
+	maki_file_warning(mi, MAKI_CORRUPT);
+    if(fread(mi->fb, (size_t) mi->fb_size, (size_t) 1, mi->fp) != 1)
+	maki_file_warning(mi, MAKI_CORRUPT);
+}
+
+static void maki_read_pixel_data(mi)
+    struct maki_info *mi;
+{
+    mi->pa = maki_malloc((size_t) mi->pa_size, "maki_read_pixel_data#1");
+    mi->pb = maki_malloc((size_t) mi->pb_size, "maki_read_pixel_data#2");
+
+    if(fread(mi->pa, (size_t) mi->pa_size, (size_t) 1, mi->fp) != 1)
+	maki_file_warning(mi, MAKI_CORRUPT);
+    if(fread(mi->pb, (size_t) mi->pb_size, (size_t) 1, mi->fp) != 1)
+	maki_file_warning(mi, MAKI_CORRUPT);
+}
+
+static void maki_expand_virtual_screen(mi)
+    struct maki_info *mi;
+{
+    int x, y, fai, fbi;
+    int bpl = mi->width / 2 / 8;		/* bytes per line */
+    byte mask;
+    mi->vs = maki_malloc((size_t) bpl * mi->height,  // GRR POSSIBLE OVERFLOW / FIXME
+			 "maki_expand_virtual_screen");
+
+    fai = fbi = 0;
+    mask = 0x80;
+    for(y = 0; y < mi->height; y += 4){
+	for(x = 0; x < mi->width / 2; x += 4){
+	    if(mi->fa[fai] & mask){
+		byte bh, bl;
+		bh = mi->fb[fbi++];
+		bl = mi->fb[fbi++];
+		if(x % 8 == 0){
+		    mi->vs[ y      * bpl + x / 8] = H4(bh) << 4;
+		    mi->vs[(y + 1) * bpl + x / 8] = L4(bh) << 4;
+		    mi->vs[(y + 2) * bpl + x / 8] = H4(bl) << 4;
+		    mi->vs[(y + 3) * bpl + x / 8] = L4(bl) << 4;
+		}else{
+		    mi->vs[ y      * bpl + x / 8] |= H4(bh);
+		    mi->vs[(y + 1) * bpl + x / 8] |= L4(bh);
+		    mi->vs[(y + 2) * bpl + x / 8] |= H4(bl);
+		    mi->vs[(y + 3) * bpl + x / 8] |= L4(bl);
+		}
+	    }else{
+		if(x % 8 == 0){
+		    mi->vs[ y      * bpl + x / 8] = 0;
+		    mi->vs[(y + 1) * bpl + x / 8] = 0;
+		    mi->vs[(y + 2) * bpl + x / 8] = 0;
+		    mi->vs[(y + 3) * bpl + x / 8] = 0;
+		}else{
+/*		    mi->vs[ y      * bpl + x / 8] |= 0;
+		    mi->vs[(y + 1) * bpl + x / 8] |= 0;
+		    mi->vs[(y + 2) * bpl + x / 8] |= 0;
+		    mi->vs[(y + 3) * bpl + x / 8] |= 0; */
+		}
+	    }
+
+	    if((mask >>= 1) == 0){
+		mask = 0x80;
+		fai++;
+	    }
+	}
+    }
+}
+
+static void maki_expand_pixel_data(mi, pic)
+    struct maki_info *mi;
+    byte **pic;
+{
+    int x, y;
+    int vsi, pi, max_pi;
+    byte *p;
+    byte mask;
+    int gap;
+    *pic = maki_malloc((size_t) mi->width * mi->height,  // GRR POSSIBLE OVERFLOW / FIXME
+		       "maki_expand_pixel_data");
+
+    vsi = pi = 0;
+    p = mi->pa;
+    max_pi = mi->pa_size - 1;
+    mask = 0x80;
+    for(y = 0; y < mi->height; y++){
+	for(x = 0; x < mi->width; x += 2){
+	    if(mi->vs[vsi] & mask){
+		if(pi > max_pi){
+		    if(p == mi->pb)
+			maki_error(mi, MAKI_BAD_DATA);
+		    pi = 0;
+		    p = mi->pb;
+		    max_pi = mi->pb_size - 1;
+		}
+		(*pic)[y * mi->width + x    ] = H4(p[pi]);
+		(*pic)[y * mi->width + x + 1] = L4(p[pi]);
+		pi++;
+	    }else{
+		(*pic)[y * mi->width + x    ] = 0;
+		(*pic)[y * mi->width + x + 1] = 0;
+	    }
+
+	    if((mask >>= 1) == 0){
+		mask = 0x80;
+		vsi++;
+	    }
+	}
+    }
+
+    gap = mi->m_maki01b ? 4 : 2;
+
+    for(y = gap; y < mi->height; y++){
+	for(x = 0; x < mi->width; x++)
+	    (*pic)[y * mi->width + x] ^= (*pic)[(y - gap) * mi->width + x];
+    }
+}
+
+
+int WriteMAKI(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle)
+    FILE *fp;
+    byte *pic;
+    int ptype, w, h;
+    byte *rmap, *gmap, *bmap;
+    int numcols, colorstyle;
+{
+    byte rtemp[256], gtemp[256], btemp[256];
+    struct maki_info maki, *mi = &maki;
+    int e;
+
+    if(DEBUG) fputs("WriteMAKI:\n", stderr);
+
+    maki_init_info(&maki);
+    if((e = setjmp(maki.jmp)) != 0){
+	/* An error occurs */
+	maki_cleanup_maki_info(&maki, 1);
+	return -1;
+    }
+
+    if(w != 640 || h != 400) {
+        char  str[512];
+        sprintf(str,"MAKI: %s Should be 640x400", maki_msgs[MAKI_SIZE]);
+	ErrPopUp(str, "\nBummer!");
+	maki_error(mi, MAKI_SIZE);
+    }
+
+    maki.fp = fp;
+    maki.width = w;
+    maki.height = h;
+    maki.x1 = w - 1;
+    maki.y1 = h - 1;
+
+    if(ptype == PIC24){
+	if(!(pic = Conv24to8(pic, w, h, 16, rtemp, gtemp, btemp)))
+	    maki_memory_error("Conv24to8#1", "WriteMAKI");
+	rmap = rtemp;
+	gmap = gtemp;
+	bmap = btemp;
+    }else if(numcols > 16){
+	if(!(pic = Conv8to24(pic, w, h, rmap, gmap, bmap)))
+	    maki_memory_error("Conv8to24", "WriteMAKI");
+	if(!(pic = Conv24to8(pic, w, h, 16, rtemp, gtemp, btemp)))
+	    maki_memory_error("Conv24to8#2", "WriteMAKI");
+	rmap = rtemp;
+	gmap = gtemp;
+	bmap = btemp;
+    }else
+	maki.numcols = numcols;
+
+    maki_make_pixel_data(&maki, pic);
+    maki_make_virtual_screen(&maki);
+    maki_make_flags(&maki);
+    maki_write_check_id(&maki);
+    maki_write_comment(&maki);
+    maki_write_header(&maki);
+    maki_write_palette(&maki, rmap, gmap, bmap, colorstyle == F_GREYSCALE);
+    maki_write_flags(&maki);
+    maki_write_pixel_data(&maki);
+
+    maki_cleanup_maki_info(&maki, 1);
+    return 0;
+}
+
+static void maki_make_pixel_data(mi, pic)
+    struct maki_info *mi;
+    byte *pic;
+{
+    int x, y, i;
+    int nza, nzb;
+
+    mi->forma = maki_malloc((size_t) mi->width / 2 * mi->height,  // GRR POSSIBLE OVERFLOW / FIXME
+			    "maki_make_pixel_data#1");
+    mi->formb = maki_malloc((size_t) mi->width / 2 * mi->height,  // GRR POSSIBLE OVERFLOW / FIXME
+			    "maki_make_pixel_data#2");
+
+    for(y = 0; y < mi->height; y++){
+	for(x = 0; x < mi->width; x += 2){
+	    byte b;
+	    b = pic[y * mi->width + x] << 4 | pic[y * mi->width + x + 1];
+	    mi->forma[y * mi->width / 2 + x / 2] = b;
+	    mi->formb[y * mi->width / 2 + x / 2] = b;
+	}
+    }
+
+    for(y = mi->height - 1; y >= 2; y--){
+	for(x = 0; x < mi->width / 2; x++){
+	    mi->forma[y * mi->width / 2 + x] ^=
+		mi->forma[(y - 2) * mi->width / 2 + x];
+	}
+    }
+
+    for(y = mi->height - 1; y >= 4; y--){
+	for(x = 0; x < mi->width / 2; x++){
+	    mi->formb[y * mi->width / 2 + x] ^=
+		mi->formb[(y - 4) * mi->width / 2 + x];
+	}
+    }
+
+    nza = nzb = 0;
+    for(i = 0; i < mi->width / 2 * mi->height; i++){
+	if(mi->forma[i] != 0)
+	    nza++;
+	if(mi->formb[i] != 0)
+	    nzb++;
+    }
+    if(nza > nzb){
+	mi->m_maki01b = 1;
+	free(mi->forma);
+	mi->forma = NULL;
+    }else{
+	mi->m_maki01b = 0;
+	free(mi->formb);
+	mi->formb = NULL;
+    }
+}
+
+static void maki_make_virtual_screen(mi)
+    struct maki_info *mi;
+{
+    int bpl = mi->width / 2 / 8;
+    int vsi, pai, pbi, max_pai, max_pbi;
+    byte mask;
+    byte *pixels;
+    int x, y;
+
+    mi->vs = maki_malloc((size_t) bpl * mi->height,  // GRR POSSIBLE OVERFLOW / FIXME
+			 "maki_make_virtual_screen#1");
+
+    if(mi->m_maki01b)
+	pixels = mi->formb;
+    else
+	pixels = mi->forma;
+
+    vsi = pai = pbi = 0;
+    max_pai = max_pbi = -1;
+    mask = 0x80;
+    for(y = 0; y < mi->height; y++){
+	for(x = 0; x < mi->width / 2; x++){
+	    if(pixels[y * mi->width / 2 + x] == 0){
+		mi->vs[vsi] &= ~mask;
+	    }else{
+		mi->vs[vsi] |= mask;
+		if(y < 200){
+		    if(pai > max_pai){
+			max_pai += 1024;
+			mi->pa = maki_realloc(mi->pa, (size_t) max_pai + 1,
+					      "maki_make_virtual_screen#2");
+		    }
+		    mi->pa[pai++] = pixels[y * mi->width / 2 + x];
+		}else{
+		    if(pbi > max_pbi){
+			max_pbi += 1024;
+			mi->pb = maki_realloc(mi->pb, (size_t) max_pbi + 2,
+					      "maki_make_virtual_screen#3");
+		    }
+		    mi->pb[pbi++] = pixels[y * mi->width / 2 + x];
+		}
+	    }
+
+	    if((mask >>= 1) == 0){
+		mask = 0x80;
+		vsi++;
+	    }
+	}
+    }
+
+    mi->pa_size = pai;
+    mi->pb_size = pbi;
+}
+
+static void maki_make_flags(mi)
+    struct maki_info *mi;
+{
+    int bpl = mi->width / 2 / 8;
+    int fbi, max_fbi;
+    int fai;
+    int x, y;
+    byte mask;
+
+    mi->fa = maki_malloc((size_t) bpl * mi->height, "maki_make_flags#1");  // GRR POSSIBLE OVERFLOW / FIXME
+
+    fbi = fai = 0;
+    max_fbi = -1;
+    mask = 0x80;
+    for(y = 0; y < mi->height; y += 4){
+	for(x = 0; x < mi->width / 2; x += 4){
+	    if(x % 8 == 0){
+		if(H4(mi->vs[ y      * bpl + x / 8]) == 0 &&
+		   H4(mi->vs[(y + 1) * bpl + x / 8]) == 0 &&
+		   H4(mi->vs[(y + 2) * bpl + x / 8]) == 0 &&
+		   H4(mi->vs[(y + 3) * bpl + x / 8]) == 0){
+		    mi->fa[fai] &= ~mask;
+		}else{
+		    mi->fa[fai] |= mask;
+		    if(fbi + 1 > max_fbi){
+			max_fbi += 1024;
+			mi->fb = maki_realloc(mi->fb, (size_t) max_fbi + 1,
+					      "maki_make_flags#2");
+		    }
+		    mi->fb[fbi++] = H4(mi->vs[ y      * bpl + x / 8]) << 4
+				  | H4(mi->vs[(y + 1) * bpl + x / 8]);
+		    mi->fb[fbi++] = H4(mi->vs[(y + 2) * bpl + x / 8]) << 4
+				  | H4(mi->vs[(y + 3) * bpl + x / 8]);
+		}
+	    }else{
+		if(L4(mi->vs[ y      * bpl + x / 8]) == 0 &&
+		   L4(mi->vs[(y + 1) * bpl + x / 8]) == 0 &&
+		   L4(mi->vs[(y + 2) * bpl + x / 8]) == 0 &&
+		   L4(mi->vs[(y + 3) * bpl + x / 8]) == 0){
+		    mi->fa[fai] &= ~mask;
+		}else{
+		    mi->fa[fai] |= mask;
+		    if(fbi + 1 > max_fbi){
+			max_fbi += 1024;
+			mi->fb = maki_realloc(mi->fb, (size_t) max_fbi + 1,
+					      "maki_make_flags#3");
+		    }
+		    mi->fb[fbi++] = L4(mi->vs[ y      * bpl + x / 8]) << 4
+				  | L4(mi->vs[(y + 1) * bpl + x / 8]);
+		    mi->fb[fbi++] = L4(mi->vs[(y + 2) * bpl + x / 8]) << 4
+				  | L4(mi->vs[(y + 3) * bpl + x / 8]);
+		}
+	    }
+
+	    if((mask >>= 1) == 0){
+		mask = 0x80;
+		fai++;
+	    }
+	}
+    }
+
+    mi->fb_size = fbi;
+}
+
+static void maki_write_check_id(mi)
+    struct maki_info *mi;
+{
+    char *id = mi->m_maki01b ? maki_id_b : maki_id_a;
+    if(fwrite(id, (size_t) 8, (size_t) 1, mi->fp) != 1)
+	maki_file_error(mi, MAKI_WRITE);
+}
+
+static void maki_write_comment(mi)
+    struct maki_info *mi;
+{
+    char buf[24];
+    char *p;
+    int i = 0;
+
+    strcpy(buf, "XV   ");
+
+    if((p = (char *) getenv("USER")) == NULL)
+	p = "????????";
+    for(i = 5; i < 23; i++){
+	if(*p == '\0')
+	    break;
+	buf[i] = *p++;
+    }
+    for( ; i < 23; i++)
+	buf[i] = ' ';
+
+    buf[i] = '\032';	/* ^Z, 0x1a */
+
+    if(fwrite(buf, (size_t) 24, (size_t) 1, mi->fp) != 1)
+	maki_file_error(mi, MAKI_WRITE);
+}
+
+static void maki_write_header(mi)
+    struct maki_info *mi;
+{
+    byte buf[16];
+
+    if(DEBUG) maki_show_maki_info(mi);
+
+#define set_word(i, v) {buf[i]=(v)>>8&0xff;buf[i+1]=(v)&0xff;}
+    set_word(0, mi->fb_size);
+    set_word(2, mi->pa_size);
+    set_word(4, mi->pb_size);
+    set_word(6, mi->ext_flag);
+    set_word(8, mi->x0);
+    set_word(10, mi->y0);
+    set_word(12, mi->x1 + 1);
+    set_word(14, mi->y1 + 1);
+#undef set_word
+
+    if(fwrite(buf, (size_t) 16, (size_t) 1, mi->fp) != 1)
+	maki_file_error(mi, MAKI_WRITE);
+}
+
+static void maki_write_palette(mi, r, g, b, grey)
+    struct maki_info *mi;
+    byte *r, *g, *b;
+    int grey;
+{
+    int i;
+    char buf[3];
+    for(i = 0; i < mi->numcols; i++){
+	buf[0] = *g++;
+	buf[1] = *r++;
+	buf[2] = *b++;
+	if(grey)
+	    buf[0] = buf[1] = buf[2] = MONO(buf[1], buf[0], buf[2]);
+	if(fwrite(buf, (size_t) 3, (size_t) 1, mi->fp) != 1)
+	    maki_file_error(mi, MAKI_WRITE);
+    }
+    for( ; i < 16; i++){
+	if(fwrite(buf, (size_t) 3, (size_t) 1, mi->fp) != 1)
+	    maki_file_error(mi, MAKI_WRITE);
+    }
+}
+
+static void maki_write_flags(mi)
+    struct maki_info *mi;
+{
+    int bpl = mi->width / 2 / 8;
+    if(fwrite(mi->fa, (size_t) bpl * mi->height / 16, (size_t) 1, mi->fp) != 1)
+	maki_file_error(mi, MAKI_WRITE);
+
+    if(fwrite(mi->fb, (size_t) mi->fb_size, (size_t) 1, mi->fp) != 1)
+	maki_file_error(mi, MAKI_WRITE);
+}
+
+static void maki_write_pixel_data(mi)
+    struct maki_info *mi;
+{
+    if(fwrite(mi->pa, (size_t) mi->pa_size, (size_t) 1, mi->fp) != 1)
+	maki_file_error(mi, MAKI_WRITE);
+
+    if(fwrite(mi->pb, (size_t) mi->pb_size, (size_t) 1, mi->fp) != 1)
+	maki_file_error(mi, MAKI_WRITE);
+}
+
+
+
+static void maki_init_info(mi)
+    struct maki_info *mi;
+{
+    xvbzero((char *)mi, sizeof(struct maki_info));
+    mi->fp = NULL;
+    mi->fsize = 0;
+    mi->x0 = mi->y0 = mi->x1 = mi->y1 = 0;
+    mi->width = mi->height = 0;
+    mi->aspect = 1.0;
+    mi->fb_size = mi->pa_size = mi->pb_size = 0;
+    mi->m_maki01b = mi->m_200 = mi->m_dig8 = 0;
+    mi->ext_flag = 0;
+    mi->fa = mi->fb = mi->pa = mi->pb = NULL;
+    mi->vs = NULL;
+    mi->numcols = 16;
+    mi->forma = mi->formb = NULL;
+}
+
+static void maki_cleanup_maki_info(mi, writing)
+    struct maki_info *mi;
+    int writing;
+{
+    if(mi->fp && !writing)
+	fclose(mi->fp);
+    if(mi->fa)
+	free(mi->fa);
+    if(mi->fb)
+	free(mi->fb);
+    if(mi->pa)
+	free(mi->pa);
+    if(mi->pb)
+	free(mi->pb);
+    if(mi->vs)
+	free(mi->vs);
+    if(mi->forma)
+	free(mi->forma);
+    if(mi->formb)
+	free(mi->formb);
+}
+
+static void maki_cleanup_pinfo(pi)
+    PICINFO *pi;
+{
+    if(pi->pic){
+	free(pi->pic);
+	pi->pic = NULL;
+    }
+}
+
+static void maki_memory_error(scm, fn)
+    char *scm, *fn;
+{
+    char buf[128];
+    sprintf(buf, "%s: coulndn't allocate memory. (%s)", scm, fn);
+    FatalError(buf);
+}
+
+static void maki_error(mi, mn)
+    struct maki_info *mi;
+    int mn;
+{
+    SetISTR(ISTR_WARNING, "%s", maki_msgs[mn]);
+    longjmp(mi->jmp, 1);
+}
+
+static void maki_file_error(mi, mn)
+    struct maki_info *mi;
+    int mn;
+{
+    if(feof(mi->fp))
+	SetISTR(ISTR_WARNING, "%s (end of file)", maki_msgs[mn]);
+    else
+	SetISTR(ISTR_WARNING, "%s (%s)", maki_msgs[mn], ERRSTR(errno));
+    longjmp(mi->jmp, 1);
+}
+
+static void maki_file_warning(mi, mn)
+    struct maki_info *mi;
+    int mn;
+{
+    if(feof(mi->fp))
+	SetISTR(ISTR_WARNING, "%s (end of file)", maki_msgs[mn]);
+    else
+	SetISTR(ISTR_WARNING, "%s (%s)", maki_msgs[mn], ERRSTR(errno));
+}
+
+static void maki_show_maki_info(mi)
+    struct maki_info *mi;
+{
+    fprintf(stderr, "  file size: %ld.\n", mi->fsize);
+    fprintf(stderr, "  image size: %dx%d.\n", mi->width, mi->height);
+    fprintf(stderr, "  aspect: %f.\n", mi->aspect);
+    fprintf(stderr, "  flag B size: %ld.\n", mi->fb_size);
+    fprintf(stderr, "  pixel data size: A:%ld, B:%ld.\n",
+	    mi->pa_size, mi->pb_size);
+    fprintf(stderr, "  MAKI01B: %s.\n", mi->m_maki01b ? "true" : "false");
+    fprintf(stderr, "  200 line mode: %s.\n", mi->m_200 ? "true" : "false");
+    fprintf(stderr, "  digital 8 colors: %s.\n", mi->m_dig8 ? "true" : "false");
+}
+
+static void *maki_malloc(n, fn)
+    size_t n;
+    char *fn;
+{
+    void *r = (void *) malloc(n);
+    if(r == NULL)
+	maki_memory_error("malloc", fn);
+    return r;
+}
+
+static void *maki_realloc(p, n, fn)
+    void *p;
+    size_t n;
+    char *fn;
+{
+    void *r = (p == NULL) ? (void *) malloc(n) : (void *) realloc(p, n);
+    if(r == NULL)
+	maki_memory_error("realloc", fn);
+    return r;
+}
+#endif /* HAVE_MAKI */
diff -ruN xv-3.10a-bugfixes/xvmgcsfx.c xv-3.10a-enhancements/xvmgcsfx.c
--- xv-3.10a-bugfixes/xvmgcsfx.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvmgcsfx.c	2005-05-01 10:20:12.000000000 -0700
@@ -0,0 +1,2276 @@
+/*
+ * $Id: xvmgcsfx.c,v 1.23 95/11/27 19:03:36 tin329 Exp Locker: tin329 $
+ * xvmgcsfx.c - Use the filters as input and output method.
+ *
+ * Features
+ * ========
+ * Use the filters as input and output method for load and save unsupported
+ * image format file. The filter command is recognized by definition of
+ * magic number or suffix in "~/.xv_mgcsfx" .
+ *
+ * Bugs
+ * ====
+ * There are many bugs.
+ * Let's go hunting for insects with an insect net. (it's all joke.)
+ *
+ * Author
+ * ======
+ * Tetsuya INOUE  <tin329@chino.it.okayama-u.ac.jp>
+ */
+
+/*
+ * Known Bugs and Todo  /  あれこれ気になること
+ *
+ *  ~/.xv_mgcsfx 内
+ *    ・定義が不完全だとエラー (':'の数)。
+ *    ・デリミタとして ':' を使うので、スタートアップファイル内で
+ *      ':' を用いて定義はできない。'\:'でもダメ。
+ *    ・ magic タイプで、８進数は３桁分０〜７を調べ、１６進数は
+ *       isxdigit が真を返す間中処理される。しかし、１ｂｙｔｅと
+ *       してしか評価されない。
+ *    ・プリプロセッサを使うときは、コメントの書き方に注意しなければな
+ *        らない。プリプロセッサによってはコメントがエラーになる。
+ *    ・パイプへの入出力のフォーマットの種類が PNM のみ
+ *        入力
+ *            ファイルポインタを seek してはいけない
+ *            ファイルサイズを用いてはいけない
+ *        出力
+ *            ファイルポインタを seek してはいけない
+ *            exec できなくて終了したプロセスに書き込み不可
+ *    ・サフィックスとマジックナンバーの使い分けをどうするか。
+ *        マジックナンバーが同じで、サフィックスが異なる場合を認めるか？
+ *    ・compress(gzip)のファイルはテンポラリでは xvtmp??? という名前な
+ *      ので suffix では識別できない。
+ *
+ *  認識する時に MACBINARY には負ける(in xv.c)。
+ *
+ *  多重に pipe を通すことができない。(pipe が seek できないから)
+ *    ・socketpair で、recv に MSG_PEEK フラグをつかって空読みする。
+ *    ・これをやるとファイルの認識がめちゃめちゃ遅くなる。
+ *
+ *  リソースで設定
+ *    ・リソースで設定する方が面倒くさい
+ *
+ *  マジックナンバーの設定に正規表現
+ *
+ *  セーブ用プロセスが失敗する場合の対策が今一つ
+ *
+ *  DEC OSF/1 V3.0 では、パイプにデータがまだない時に読み込もうとすると、
+ *  read が不完全になる。(in xvpbm.c)
+ *  同様に書き込み時にも問題が生じるかもしれない。
+ */
+
+#define  NEEDSDIR               /* for stat() */
+#include "xv.h"
+
+
+#ifdef HAVE_MGCSFX
+
+
+#ifdef __osf__
+#  ifdef __alpha
+#    define ARCHITECTURE64 1
+#  endif /* __alpha */
+#endif /* __osf__ */
+
+#ifdef ARCHITECTURE64
+typedef short int16;
+typedef int   int32;
+typedef long  int64;
+#else
+typedef short int16;
+typedef long  int32;
+#endif /* ARCHITECTURE64 */
+
+#ifdef sgi
+#  define vfork fork
+#endif
+
+#define USE_SIGCHLD
+#if 0
+#  undef  USE_SIGCHLD
+#endif
+
+#ifdef USE_SIGCHLD
+#  include <sys/wait.h>
+#endif
+
+typedef struct _mgcsfxtab
+{
+  struct _mgcsfxtab *next;
+  char              *description;
+  int                mgcsfx_type;
+  int                offset;
+  union{
+    int16            int16_data;
+    int32            int32_data;
+    char            *string_data;
+  }                  dt;
+  int                string_len;
+  char              *suffix;
+  int                input_image_type;
+  char              *input_command;
+  int                output_image_type;
+  char              *output_command;
+} mgcsfxtab;
+
+
+#ifndef MGCSFXDIR
+#  define MGCSFXDIR       "/usr/local/lib"
+#endif
+#ifndef SYSCONFDIR
+#  define SYSCONFDIR      MGCSFXDIR
+#endif
+#ifndef MGCSFX_SITE_RC
+#  define MGCSFX_SITE_RC  "xv_mgcsfx"
+#endif
+#ifndef MGCSFX_RC
+#  define MGCSFX_RC       ".xv_mgcsfx"
+#endif
+
+#ifdef USE_MGCSFX_PREPROCESSOR
+#  ifndef MGCSFX_PREPROCESSOR
+#    define MGCSFX_PREPROCESSOR "/usr/lib/cpp"
+#  endif
+#endif
+
+
+/* Check type for Magic number and Suffix */
+enum {T_UNKNOWN,
+      T_MAGIC, T_SUFFIX,
+      T_BEINT16, T_BEINT32, T_BEINT64,
+      T_LEINT16, T_LEINT32, T_LEINT64};
+
+/* Image Type for input and output format */
+enum {IT_UNKNOWN,
+#ifdef HAVE_MGCSFX_AUTO
+      IT_AUTO,
+#endif /* HAVE_MGCSFX_AUTO */
+      IT_PNM, IT_PPM, IT_PGM, IT_PBM,
+      IT_PNM_RAW, IT_PPM_RAW, IT_PGM_RAW, IT_PBM_RAW,
+      IT_PNM_ASCII, IT_PPM_ASCII, IT_PGM_ASCII, IT_PBM_ASCII,
+      IT_GIF, IT_JPEG, IT_TIFF, IT_JFIF, /* IT_PS, IT_COMPRESS,*/
+      IT_XBM, IT_XPM, IT_BMP, IT_SUNRAS, IT_IRIS, IT_XWD,
+      /* IT_TARGA, IT_FITS, IT_PM, IT_UTAHRLE, IT_PCX, IT_PDSVICAR, IT_IFF, */
+      IT_MAG, IT_MAKI, IT_PI, IT_PIC, IT_PIC2 /* , IT_PCD */};
+
+
+/*--------------------------------------------------------------------------*/
+void  mgcsfx_handler        PARM((int));
+void  mgcsfx_handler_setup  PARM((void));
+
+#ifdef USE_MGCSFX_PREPROCESSOR
+static char      *get_tmp_fname          PARM((void));
+static char      *make_preprocessed_file PARM((char *));
+#endif /* USE_MGCSFX_PREPROCESSOR */
+
+int   is_mgcsfx             PARM((char *, unsigned char *, int));
+
+char *mgcsfx_auto_input_com PARM((char *));
+
+
+static mgcsfxtab *free_mgcsfx PARM((mgcsfxtab *));
+static char      *fgettoken   PARM((FILE*, int));
+static int        string_fin  PARM((char *));
+static int        type_mgcsfx PARM((char *));
+static int        type_image  PARM((char *));
+
+static void       read_mgcsfx PARM((mgcsfxtab **, char *));
+static void       init_mgcsfx PARM((void));
+static mgcsfxtab *find_mgcsfx PARM((char *, unsigned char *, int));
+
+int   LoadMGCSFX            PARM((char *, PICINFO *));
+
+#ifdef SVR4
+typedef void Sigfunc(int);
+static Sigfunc   *xv_signal   PARM((int , Sigfunc *));
+#endif
+
+/*--------------------------------------------------------------------------*/
+mgcsfxtab *mgcsfx_table = NULL;
+int       mgcsfx_setup_flag = 0;
+
+int       nitem_mgcsfx = 0;
+int       desc_width = 0;
+
+int       max_offset_mgcsfx = 0;
+int       max_length_mgcsfx = 0;
+int       need_buf_size = 0;
+
+static char input_command_ex[1024];
+static int  input_command_ex_flag = 0;
+
+#ifdef USE_SIGCHLD
+static int  w_p_fail=0;
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+/***************************************************/
+void mgcsfx_handler(sig)
+     int sig;
+{
+#ifdef USE_SIGCHLD
+  int pid, pst;
+#endif
+
+#if defined(SYSV) || defined(SVR4)
+  sighold(sig);
+#else
+  sigblock(sigmask(sig));
+#endif
+
+#ifdef USE_SIGCHLD
+  if(w_p_fail == 1){
+    /*
+     * At this point, process write to broken pipe.
+     * Probably external command was can't exec.
+     */
+    w_p_fail = 2;
+    pid = wait(&pst);
+  }
+#endif
+
+  return;
+
+  /* Quit(1); */ /*exit(1);*/
+}
+
+void mgcsfx_handler_setup()
+{
+#ifdef SVR4
+  xv_signal(SIGPIPE, (void (*)PARM((int))) mgcsfx_handler);
+  xv_signal(SIGCHLD, (void (*)PARM((int))) mgcsfx_handler);
+#else
+# ifdef SYSV
+  sigset(SIGPIPE, (void (*)PARM((int))) mgcsfx_handler);
+  sigset(SIGCHLD, (void (*)PARM((int))) mgcsfx_handler);
+# else
+  signal(SIGPIPE, (void (*)PARM((int))) mgcsfx_handler);
+  signal(SIGCHLD, (void (*)PARM((int))) mgcsfx_handler);
+# endif
+#endif
+}
+
+/***************************************************/
+#ifdef USE_MGCSFX_PREPROCESSOR
+static char *get_tmp_fname()
+{
+  static char tmp[MAXPATHLEN+1];
+
+#ifndef VMS
+  sprintf(tmp, "%s/xvmgcsfxXXXXXX",tmpdir);
+#else
+  /* sprintf(tmp, "Sys$Scratch:xvmgcsfxXXXXXX"); */
+  strcpy(tmp, "[]xvmgcsfxXXXXXX");
+#endif /* VMS */
+
+#ifdef USE_MKSTEMP
+  close(mkstemp(tmp));
+#else
+  mktemp(tmp);
+#endif
+
+  return tmp;
+}
+
+static char *make_preprocessed_file(fname)
+     char *fname;
+{
+  char buf[512];
+  char *tmp_name;
+
+  tmp_name = get_tmp_fname();
+
+#ifndef VMS
+  sprintf(buf,"%s %s > %s", MGCSFX_PREPROCESSOR, fname, tmp_name);
+#else
+  sprintf(buf,"%s %s > %s", MGCSFX_PREPROCESSOR, fname, tmp_name); /* really OK? */
+#endif
+
+  SetISTR(ISTR_INFO, "Preprocessing '%s'...", BaseName(fname));
+#ifndef VMS
+  if (system(buf))
+#else
+  if (!system(buf))
+#endif
+  {
+    SetISTR(ISTR_INFO, "Unable to preprocess '%s'.", BaseName(fname));
+    Warning();
+    return NULL;
+  }
+
+  return tmp_name;
+}
+#endif /* USE_MGCSFX_PREPROCESSOR */
+
+/***************************************************/
+/* 認識できるファイルかどうか調べる */
+int is_mgcsfx(fname,buffer,size)
+     char          *fname;
+     unsigned char *buffer;
+     int            size;
+{
+  mgcsfxtab          *magic;
+  FILE               *fp;
+  unsigned char      *buf;
+  int                 s;
+
+  if(nomgcsfx){
+    return 0;
+  }else{
+    if(size < need_buf_size){
+      if((buf = (unsigned char *)calloc(need_buf_size, sizeof(char)))==NULL){
+	fprintf(stderr,"Can't allocate memory\n");
+	return 0;
+      }
+      if((fp = xv_fopen(fname, "r"))==NULL){
+	fprintf(stderr,"Can't open file %s\n", fname);
+	free(buf);
+	return 0;
+      }
+      s = fread(buf, 1, need_buf_size, fp);
+      if((magic = find_mgcsfx(fname, buf, s))!=NULL &&
+	magic->input_command != NULL){
+	free(buf);
+	fclose(fp);
+	return 1;
+      }else{
+	free(buf);
+	fclose(fp);
+	return 0;
+      }
+    }else{
+      if((magic = find_mgcsfx(fname, buffer, size))!=NULL &&
+	magic->input_command != NULL){
+	return 1;
+      }else{
+	return 0;
+      }
+    }
+  }
+}
+
+#ifdef HAVE_MGCSFX_AUTO
+char *mgcsfx_auto_input_com(fname)
+char *fname;
+{
+  static char command[1024];
+  mgcsfxtab       *magic;
+  char *ptr;
+
+  FILE *fp;
+  unsigned char *buf;
+  int                 s;
+
+  if((buf = (unsigned char *)calloc(need_buf_size, sizeof(char)))==NULL){
+    fprintf(stderr,"Can't allocate memory\n");
+    return NULL;
+  }
+  if((fp = xv_fopen(fname, "r"))==NULL){
+    fprintf(stderr,"Can't open file %s\n", fname);
+    free(buf);
+    return NULL;
+  }
+  s = fread(buf, 1, need_buf_size, fp);
+  if((magic = find_mgcsfx(fname, buf, s))!=NULL &&
+     magic->input_command != NULL && magic->input_image_type == IT_AUTO){
+    if ((ptr = strstr(magic->input_command, "%s"))){
+      sprintf(command, magic->input_command, fname);
+    }else{
+      sprintf(command, "%s < %s", magic->input_command, fname);
+    }
+    free(buf);
+    fclose(fp);
+    return command;
+  }else{
+    free(buf);
+    fclose(fp);
+    return NULL;
+  }
+}
+#endif /* HAVE_MGCSFX_AUTO */
+
+/***************************************************/
+static mgcsfxtab *free_mgcsfx(m)
+     mgcsfxtab *m;
+{
+  mgcsfxtab *next;
+  if(m == NULL) return NULL;
+  next = m->next;
+  if(m->description != NULL) free(m->description);
+  if(m->mgcsfx_type == T_MAGIC && m->dt.string_data != NULL)
+    free(m->dt.string_data);
+  if(m->suffix != NULL) free(m->suffix);
+  if(m->input_command != NULL) free(m->input_command);
+  if(m->output_command != NULL) free(m->output_command);
+  free(m);
+  return next;
+}
+
+
+
+/***************************************************/
+/* char c または '\n' で区切られた文字列を取り出す
+ *  ファイルの最後まで読んだら NULL を返す
+ *  改行なら改行を返す(改行で区切られた場合は '\n' をストリームに戻す)
+ */
+#define CBUF_SIZE 1024
+static char *fgettoken(fp, c)
+     FILE *fp;
+     int   c; /* Real mean is char */
+{
+  char *buf;
+  char *buf2;
+  int   i;
+  int   n=0;
+  int   max=0;
+  int   count = 1;
+
+  char *ss;
+  char *se;
+
+  if((buf = (char *)calloc(CBUF_SIZE, sizeof(char))) == NULL){
+    fprintf(stderr,"Can't allocate memory\n");
+    exit(1);
+  }
+  max = CBUF_SIZE;
+  count = 2;
+
+  do{
+    if((i = getc(fp))==EOF || i == '\n' || i == c) break;
+
+    buf[n] = (char)i;
+
+    if(i != c && n == max-1){
+      buf[max] = '\0';
+      if((buf2 = (char *)calloc(CBUF_SIZE * count, sizeof(char))) == NULL){
+	fprintf(stderr,"Can't allocate memory\n");
+	exit(1);
+      }
+      strcpy(buf2, buf);
+      free(buf);
+      buf = buf2;
+      buf2 = NULL;
+      max = CBUF_SIZE * count;
+      count++;
+    }
+
+    n++;
+  }while(i != c);
+
+  buf[n] = '\0';
+
+  /* 最初と最後の空白文字を切り詰める */
+  ss = buf + strspn(buf, " \t\b\r\n"); /* find the first non-white space */
+  se = buf + strlen(buf);              /* find the end of the string */
+
+  /* strip from the end first */
+  while ((--se >= ss) && strchr(" \t\b\r\n", *se));
+  *(++se) = '\0';
+
+  if(i == EOF && strlen(ss)==0){        /* EOF なら NULL を返す */
+    free(buf);
+    return NULL;
+  }else if(i == '\n' && strlen(ss)==0){ /* 改行のみの場合 */
+    static char cr[2] = {'\n','\0'};
+    buf2 = strdup(cr);
+    free(buf);
+    return buf2;
+  }else{                                /* 通常 */
+    if(i == '\n' && strlen(ss)>0) ungetc(i,fp);
+    buf2 = strdup(ss);
+    free(buf);
+    return buf2;
+  }
+}
+
+
+
+/***************************************************/
+/* 文字列中の特殊記号(\)を正しいものにする
+ */
+static int string_fin(string_data)
+     char *string_data;
+{
+  char *cptr;
+  char *ptr;
+  int   length;
+
+  /* Change all the \xx sequences into a single character */
+  cptr = string_data;
+
+  for (ptr = cptr; *ptr; ++ptr){
+    if (*ptr != '\\'){
+      *cptr = *ptr;
+    }else{
+      switch (*(++ptr)){
+#if defined(__STDC__)
+      case 'a': /* Audible alert (terminal bell) */
+	*cptr = '\007';
+	break;
+      case '?': /* Question mark */
+	*cptr = '\?';
+	break;
+#endif
+      case 'b': /* Backspace */
+	*cptr = '\b';
+	break;
+      case 'f': /* Form feed */
+	*cptr = '\f';
+	break;
+      case 'n': /* Line feed */
+	*cptr = '\n';
+	break;
+      case 'r': /* Carriage return */
+	*cptr = '\r';
+	break;
+      case 't': /* Horizontal tab */
+	*cptr = '\t';
+	break;
+      case 'v': /* Vertical tab */
+	*cptr = '\v';
+	break;
+      case '\\': /* Backslash */
+	*cptr = '\\';
+	break;
+      case '\'': /* Single quote */
+	*cptr = '\'';
+	break;
+      case '"': /* Double quote */
+	*cptr = '\"';
+	break;
+      case '0': /* Octal constant  \0 ... \377 */
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+	if ((ptr[1] >= '0') && (ptr[1] <= '7')){
+	  if ((ptr[2] >= '0') && (ptr[2] <= '7')){ /* \000 ...\377 */
+	    *cptr = ((*ptr - '0') * 64) +((ptr[1] - '0') * 8) +(ptr[1] - '0');
+	    ptr += 2;
+	  }else{ /* \00 ...\77 */
+	    *cptr = ((*ptr - '0') * 8) + (ptr[1] - '0');
+	    ++ptr;
+	  }
+	}else{ /* \0 ...\7 */
+	  *cptr = *ptr - '0';
+	}
+	break;
+      case 'x': /* Hexadecimal constant  \x0 .. \xff */
+	if (isxdigit (ptr[1])){
+	  *cptr = 0;
+	  while (isxdigit (*(++ptr)))
+	    *cptr = (*cptr * 16) +
+	      (*ptr > '9' ? tolower (*ptr) - ('a' - 10) : *ptr - '0');
+	  --ptr;
+	  break;
+	}
+      default:
+	/*  *(cptr++) = '\\';  No use for treat '\z' as 'z' */
+	*cptr = *ptr;
+	break;
+      }
+    }
+    ++cptr;
+  }
+  *cptr = '\0';
+  length = cptr - string_data;
+  return length;
+}
+
+/***************************************************/
+static int type_mgcsfx(str)
+     char *str;
+{
+  if(str == NULL){
+    return T_UNKNOWN;
+  }else if(!strcmp(str, "magic")   || !strcmp(str, "MAGIC")){
+    return T_MAGIC;
+  }else if(!strcmp(str, "string")  || !strcmp(str, "STRING")){
+    return T_MAGIC;
+  }else if(!strcmp(str, "suffix")  || !strcmp(str, "SUFFIX")){
+    return T_SUFFIX;
+  }else if(!strcmp(str, "beint16") || !strcmp(str, "BEINT16")){
+    return T_BEINT16;
+  }else if(!strcmp(str, "leint16") || !strcmp(str, "LEINT16")){
+    return T_LEINT16;
+  }else if(!strcmp(str, "beint32") || !strcmp(str, "BEINT32")){
+    return T_BEINT32;
+  }else if(!strcmp(str, "leint32") || !strcmp(str, "LEINT32")){
+    return T_LEINT32;
+  }else{
+    return T_UNKNOWN;
+  }
+}
+
+/***************************************************/
+static int type_image(str)
+     char *str;
+{
+  if(str == NULL){
+    return IT_UNKNOWN;
+#ifdef HAVE_MGCSFX_AUTO
+  }else if(!strcmp(str, "auto") || !strcmp(str, "AUTO")){
+    return IT_AUTO;
+#endif /* HAVE_MGCSFX_AUTO */
+  }else if(!strcmp(str, "pnm") || !strcmp(str, "PNM")){
+    return IT_PNM;
+  }else if(!strcmp(str, "ppm") || !strcmp(str, "PPM")){
+    return IT_PPM;
+  }else if(!strcmp(str, "pgm") || !strcmp(str, "PGM")){
+    return IT_PGM;
+  }else if(!strcmp(str, "pbm") || !strcmp(str, "PBM")){
+    return IT_PBM;
+  }else if(!strcmp(str, "pnm_raw") || !strcmp(str, "PNM_RAW")){
+    return IT_PNM_RAW;
+  }else if(!strcmp(str, "ppm_raw") || !strcmp(str, "PPM_RAW")){
+    return IT_PPM_RAW;
+  }else if(!strcmp(str, "pgm_raw") || !strcmp(str, "PGM_RAW")){
+    return IT_PGM_RAW;
+  }else if(!strcmp(str, "pbm_raw") || !strcmp(str, "PBM_RAW")){
+    return IT_PBM_RAW;
+  }else if(!strcmp(str, "pnm_ascii") || !strcmp(str, "PNM_ASCII")){
+    return IT_PNM_ASCII;
+  }else if(!strcmp(str, "ppm_ascii") || !strcmp(str, "PPM_ASCII")){
+    return IT_PPM_ASCII;
+  }else if(!strcmp(str, "pgm_ascii") || !strcmp(str, "PGM_ASCII")){
+    return IT_PGM_ASCII;
+  }else if(!strcmp(str, "pbm_ascii") || !strcmp(str, "PBM_ASCII")){
+    return IT_PBM_ASCII;
+
+  }else if(!strcmp(str, "gif")  || !strcmp(str, "GIF")){
+    return IT_GIF;
+  }else if(!strcmp(str, "jpeg") || !strcmp(str, "JPEG")){
+    return IT_JPEG;
+  }else if(!strcmp(str, "tiff") || !strcmp(str, "TIFF")){
+    return IT_TIFF;
+  }else if(!strcmp(str, "jfif") || !strcmp(str, "JFIF")){
+    return IT_JFIF;
+
+  }else if(!strcmp(str, "xbm") || !strcmp(str, "XBM")){
+    return IT_XBM;
+  }else if(!strcmp(str, "xpm") || !strcmp(str, "XPM")){
+    return IT_XPM;
+  }else if(!strcmp(str, "bmp") || !strcmp(str, "BMP")){
+    return IT_BMP;
+  }else if(!strcmp(str, "sunras") || !strcmp(str, "SUNRAS")){
+    return IT_SUNRAS;
+  }else if(!strcmp(str, "iris") || !strcmp(str, "IRIS")){
+    return IT_IRIS;
+  }else if(!strcmp(str, "xwd") || !strcmp(str, "XWD")){
+    return IT_XWD;
+
+  }else if(!strcmp(str, "mag") || !strcmp(str, "MAG")){
+    return IT_MAG;
+  }else if(!strcmp(str, "maki") || !strcmp(str, "MAKI")){
+    return IT_MAKI;
+  }else if(!strcmp(str, "pi") || !strcmp(str, "PI")){
+    return IT_PI;
+  }else if(!strcmp(str, "pic") || !strcmp(str, "PIC")){
+    return IT_PIC;
+  }else if(!strcmp(str, "pic2") || !strcmp(str, "PIC2")){
+    return IT_PIC2;
+
+  }else{
+    return IT_UNKNOWN;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+#define mgcsfx_read_error(FILENAME, LINENUM, AFTERFIELD) \
+fprintf (stderr,\
+"%s: line %d: missing fields of %s field\n",\
+FILENAME, LINENUM, AFTERFIELD);
+
+#define magic_type_error(FILENAME, LINENUM, MAGICNUMBER) \
+fprintf (stderr,\
+"%s: line %d: invalid <magic type> field '%s'\n",\
+FILENAME, LINENUM, MAGICNUMBER);
+/*--------------------------------------------------------------------------*/
+
+/***************************************************/
+static void read_mgcsfx(mgcsfx_table, fname)
+     mgcsfxtab **mgcsfx_table;
+     char       *fname;
+{
+  FILE *fp;
+  char *s;
+  int   line_number = 0;
+  int   str_len;
+  int   reach_end;
+  int   def_err;
+
+  char *description;
+  char *mgcsfx_type;
+  char *offset;
+  char *magic;
+  char *suffix;
+  char *i_img;
+  char *i_com;
+  char *o_img;
+  char *o_com;
+
+  mgcsfxtab  *ent;
+  mgcsfxtab **entry;
+
+
+  if((fp=fopen(fname, "r"))==NULL){
+    /* fprintf(stderr, "Can't open %s\n",fname); */
+    return;
+  }
+
+  while(1){
+retry:
+    line_number++;
+    def_err = 0;
+
+    s= NULL;
+    description = mgcsfx_type = offset = magic = suffix
+      = i_img = i_com = o_img = o_com = NULL;
+    reach_end = 0;
+
+    if((s = fgettoken(fp, ':'))==NULL) break; /* EOF なら終り */
+    if(*s == '#'){/* 先頭が '#' なら読みとばす */
+      while((s = fgettoken(fp, '\n'))!=NULL){
+	if(*s == '\n'){
+	  free(s);
+	  goto retry;
+	}
+	free(s);
+      }
+      if(s == NULL) break;
+    }else if(*s == '\n'){/* 空行は無視 */
+      free(s);
+      goto retry;
+    }
+    if(strlen(s) > 0) description = s;
+    else free(s);
+
+    if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* 何もないなら設定ミス */
+      if(s != NULL) free(s);
+      mgcsfx_read_error(fname, line_number, "data type");
+      goto next;
+    }
+    if(strlen(s) > 0) mgcsfx_type = s;
+    else free(s);
+
+    if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* 何もないなら設定ミス */
+      if(s != NULL) free(s);
+      mgcsfx_read_error(fname, line_number, "byte offset");
+      goto next;
+    }
+    if(strlen(s) > 0) offset = s;
+    else free(s);
+
+    if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* 何もないなら設定ミス */
+      if(s != NULL) free(s);
+      mgcsfx_read_error(fname, line_number, "magic number");
+      goto next;
+    }
+    if(strlen(s) > 0) magic = s;
+    else free(s);
+
+    if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* 何もないなら設定ミス */
+      if(s != NULL) free(s);
+      mgcsfx_read_error(fname, line_number, "suffix");
+      goto next;
+    }
+    if(strlen(s) > 0) suffix = s;
+    else free(s);
+
+    if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* 何もないなら設定ミス */
+      if(s != NULL) free(s);
+      mgcsfx_read_error(fname, line_number, "input image type");
+      goto next;
+    }
+    if(strlen(s) > 0) i_img = s;
+    else free(s);
+
+    if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* 何もないなら設定ミス */
+      if(s != NULL) free(s);
+      mgcsfx_read_error(fname, line_number, "input command");
+      goto next;
+    }
+    if(strlen(s) > 0) i_com = s;
+    else free(s);
+
+    if((s = fgettoken(fp, ':'))==NULL || *s == '\n'){/* 何もないなら設定ミス */
+      if(s != NULL) free(s);
+      mgcsfx_read_error(fname, line_number, "output image type");
+      goto next;
+    }
+    if(strlen(s) > 0) o_img = s;
+    else free(s);
+
+    if((s = fgettoken(fp, '#'))==NULL || *s == '\n'){/* 何もないなら設定ミス */
+    /*
+      free(s);
+      mgcsfx_read_error(fname, line_number, "output command");
+      goto next;
+     */
+      if(s != NULL){
+	*s = '\0';
+	reach_end = 1;
+      }
+    }
+    if(s != NULL){
+      if(strlen(s) > 0) o_com = s;
+      else free(s);
+    }
+
+    if(reach_end == 0){
+      while((s = fgettoken(fp, '\n'))!=NULL){/* 行末のゴミを捨てる */
+	if(*s == '\n'){
+	  free(s);
+	  break; /* goto next; */
+	}
+	free(s);
+      }
+    }else{
+      reach_end = 0;
+    }
+
+
+
+    /* --------------------------------------------------------------------- */
+next:;
+
+    if(DEBUG){
+      fprintf(stderr,"Read:  file %s:  line %d.\n", fname, line_number);
+      fprintf(stderr,"Description : %s\n",
+	      description ? description : "-- error --");
+      fprintf(stderr,"Type        : %s\n",
+	      mgcsfx_type ? mgcsfx_type : "-- error --");
+      fprintf(stderr,"Offset      : %s\n", offset ? offset : "--+--");
+      fprintf(stderr,"Magic       : %s\n", magic ? magic : "--+--");
+      fprintf(stderr,"Suffix      : %s\n", suffix ? suffix : "--+--");
+      fprintf(stderr,"i Image     : %s\n", i_img ? i_img : "--+--");
+      fprintf(stderr,"i Command   : %s\n", i_com ? i_com : "--+--");
+      fprintf(stderr,"o Image     : %s\n", o_img ? o_img : "--+--");
+      fprintf(stderr,"o Command   : %s\n", o_com ? o_com : "--+--");
+      fprintf(stderr,"\n");
+    }
+
+    /* create mgcsfxtab */
+    if((ent = (mgcsfxtab *) malloc (sizeof (mgcsfxtab)))==NULL){
+      fprintf(stderr,"Can't allocate memory\n");
+      exit(1);
+    }
+    ent->next              = NULL;
+    ent->description       = NULL;
+    ent->mgcsfx_type       = T_UNKNOWN;
+    ent->offset            = 0;
+    ent->string_len        = 0;
+    ent->suffix            = NULL;
+    ent->input_image_type  = IT_UNKNOWN;
+    ent->input_command     = NULL;
+    ent->output_image_type = IT_UNKNOWN;
+    ent->output_command    = NULL;
+
+    if(description != NULL){
+      ent->description = description;
+      description = NULL;
+    }else{
+      fprintf (stderr,"%s: line %d: undefined <description> field.\n",
+	       fname, line_number);
+      def_err ++;
+      goto next2;
+    }
+
+    if(mgcsfx_type == NULL){
+      fprintf (stderr,"%s: line %d: undefined <mgcsfx type> field.\n",
+	       fname, line_number);
+      def_err ++;
+      goto next2;
+    }
+    ent->mgcsfx_type = type_mgcsfx(mgcsfx_type);
+    switch(ent->mgcsfx_type){
+    case T_SUFFIX:
+      if(suffix == NULL){
+	fprintf (stderr,
+              "%s: line %d: conflict definition : undefined <suffix> field.\n",
+		 fname, line_number);
+	def_err ++;
+	goto next2;
+      }
+      break;
+    case T_BEINT16:
+      if (sscanf(magic, "%hi", &(ent->dt.int16_data)) != 1){
+	magic_type_error(fname, line_number, magic);
+	def_err ++;
+	goto next2;
+      }
+      break;
+    case T_LEINT16:
+      if (sscanf(magic, "%hi", &(ent->dt.int16_data)) != 1){
+	magic_type_error(fname, line_number, magic);
+	def_err ++;
+	goto next2;
+      }
+      break;
+#ifdef ARCHITECTURE64
+    case T_BEINT32:
+      if (sscanf(magic, "%i", &(ent->dt.int32_data)) != 1){
+	magic_type_error(fname, line_number, magic);
+	def_err ++;
+	goto next2;
+      }
+      break;
+    case T_LEINT32:
+      if (sscanf(magic, "%i", &(ent->dt.int32_data)) != 1){
+	magic_type_error(fname, line_number, magic);
+	def_err ++;
+	goto next2;
+      }
+      break;
+#else
+    case T_BEINT32:
+      if (sscanf(magic, "%li", &(ent->dt.int32_data)) != 1){
+	magic_type_error(fname, line_number, magic);
+	def_err ++;
+	goto next2;
+      }
+      break;
+    case T_LEINT32:
+      if (sscanf(magic, "%li", &(ent->dt.int32_data)) != 1){
+	magic_type_error(fname, line_number, magic);
+	def_err ++;
+	goto next2;
+      }
+      break;
+#endif /* ARCHITECTURE64 */
+    case T_MAGIC:
+      if(magic == NULL){
+	fprintf (stderr,"%s: line %d: undefined <magic> field.\n",
+		 fname, line_number);
+	def_err ++;
+	goto next2;
+      }
+      if((str_len = string_fin(magic))<=0){
+	fprintf (stderr,"%s: line %d: invalid <magic> field.\n",
+		 fname, line_number);
+	def_err ++;
+	goto next2;
+      }
+
+      ent->string_len = str_len;
+      if((ent->dt.string_data = (char *)malloc(str_len + 1))==NULL){
+	fprintf(stderr,"Can't allocate memory\n");
+	exit(1);
+      }
+      memcpy(ent->dt.string_data, magic, str_len + 1);
+      break;
+    case T_UNKNOWN:
+    default:
+      fprintf (stderr,"%s: line %d: invalid <mgcsfx type> field.\n",
+	       fname, line_number);
+      def_err ++;
+      goto next2;
+      break;
+    };
+
+
+    if(offset == NULL){
+      if(ent->mgcsfx_type == T_MAGIC ||
+	 ent->mgcsfx_type == T_BEINT16 ||
+	 ent->mgcsfx_type == T_LEINT16 ||
+	 ent->mgcsfx_type == T_BEINT32 ||
+	 ent->mgcsfx_type == T_LEINT32){
+	fprintf (stderr,
+	      "%s: line %d: conflict definition : undefined <offset> field.\n",
+		 fname, line_number);
+	def_err ++;
+	goto next2;
+      }
+    }else{
+      if(ent->mgcsfx_type != T_SUFFIX) sscanf(offset, "%i", &(ent->offset));
+    }
+
+    if(suffix != NULL){
+      ent->suffix = suffix;
+      suffix = NULL;
+    }
+
+    if((i_img == NULL && i_com == NULL) && (o_img == NULL || o_com == NULL)){
+      fprintf (stderr,"%s: line %d: invalid definition.\n",
+	       fname, line_number);
+      def_err ++;
+      goto next2;
+    }
+    if((o_img == NULL && o_com == NULL) && (i_img == NULL || i_com == NULL)){
+      fprintf (stderr,"%s: line %d: invalid definition.\n",
+	       fname, line_number);
+      def_err ++;
+      goto next2;
+    }
+
+    if(i_img != NULL && i_com != NULL){
+      ent->input_image_type  = type_image(i_img);
+      ent->input_command = i_com;
+      i_com = NULL;
+    }else{
+      ent->input_image_type  = IT_UNKNOWN;
+      ent->input_command = NULL;
+    }
+
+    if(o_img != NULL && o_com != NULL){
+      ent->output_image_type = type_image(o_img);
+      ent->output_command = o_com;
+      o_com = NULL;
+    }else{
+      ent->output_image_type = IT_UNKNOWN;
+      ent->output_command = NULL;
+    }
+    /* end of create mgcsfxtab */
+
+
+next2:;
+
+    if(def_err != 0 || DEBUG){
+      fprintf(stderr,"Description : %s \t -> %s\n",
+	      description ? description : "--+--",
+	      ent->description ? ent->description : "-- error --");
+      fprintf(stderr,"Type        : %s \t -> %d\n",
+	      mgcsfx_type ? mgcsfx_type : "--+--",
+	      ent->mgcsfx_type);
+      fprintf(stderr,"Offset      : %s \t -> %d\n",
+	      offset ? offset : "--+--",
+	      ent->offset);
+
+      fprintf(stderr,"Magic       : %s", magic ? magic : "--+--");
+      switch(ent->mgcsfx_type){
+      case T_BEINT16:
+      case T_LEINT16:
+	fprintf(stderr," \t -> %d\n",ent->dt.int16_data);
+	break;
+      case T_BEINT32:
+      case T_LEINT32:
+	fprintf(stderr," \t -> %ld\n",ent->dt.int32_data);
+	break;
+      case T_MAGIC:
+	fprintf(stderr," \t -> %s\n",ent->dt.string_data);
+	break;
+      default:
+	fprintf(stderr,"\n");
+	break;
+      };
+
+      fprintf(stderr,"Suffix      : %s \t -> %s\n",
+	      suffix ? suffix : "--+--",
+	      ent->suffix ? ent->suffix : "--+--");
+      fprintf(stderr,"i Image     : %s \t -> %d\n",
+	      i_img ? i_img : "--+--",
+	      ent->input_image_type);
+      fprintf(stderr,"i Command   : %s \t -> %s\n",
+	      i_com ? i_com : "--+--",
+	      ent->input_command ? ent->input_command : "--+--");
+      fprintf(stderr,"o Image     : %s \t -> %d\n",
+	      o_img ? o_img : "--+--",
+	      ent->output_image_type);
+      fprintf(stderr,"o Command   : %s \t -> %s\n",
+	      o_com ? o_com : "--+--",
+	      ent->output_command ? ent->output_command : "--+--");
+      fprintf(stderr,"\n");
+    }
+
+    if(description != NULL) free(description);
+    if(mgcsfx_type != NULL) free(mgcsfx_type);
+    if(offset      != NULL) free(offset);
+    if(magic       != NULL) free(magic);
+    if(suffix      != NULL) free(suffix);
+    if(i_img       != NULL) free(i_img);
+    if(i_com       != NULL) free(i_com);
+    if(o_img       != NULL) free(o_img);
+    if(o_com       != NULL) free(o_com);
+
+
+    if(def_err != 0) goto next3;
+
+    /* Override any existing entry for this magic number/file type */
+    for(entry = mgcsfx_table; *entry; entry = &((*entry)->next)){
+      if((ent->mgcsfx_type == (*entry)->mgcsfx_type) &&
+	 (
+	   ((ent->offset == (*entry)->offset) &&
+	    (((ent->mgcsfx_type == T_BEINT16) &&
+	      (ent->dt.int16_data == (*entry)->dt.int16_data)) ||
+	     ((ent->mgcsfx_type == T_BEINT32) &&
+	      (ent->dt.int32_data == (*entry)->dt.int32_data)) ||
+	     ((ent->mgcsfx_type == T_LEINT16) &&
+	      (ent->dt.int16_data == (*entry)->dt.int16_data)) ||
+	     ((ent->mgcsfx_type == T_LEINT32) &&
+	      (ent->dt.int32_data == (*entry)->dt.int32_data)) ||
+
+	     ((ent->mgcsfx_type == T_MAGIC) &&
+	      !memcmp(ent->dt.string_data, (*entry)->dt.string_data,
+		      ent->string_len))
+	      )) ||
+	  ((ent->mgcsfx_type == T_SUFFIX) &&
+	   !strcmp(ent->suffix, (*entry)->suffix))
+	 )
+	){
+
+	free ((*entry)->description);
+	(*entry)->description = ent->description;
+	ent->description = NULL;
+
+	(*entry)->input_image_type = ent->input_image_type;
+	if ((*entry)->input_command) free ((*entry)->input_command);
+	(*entry)->input_command = ent->input_command;
+	ent->input_command = NULL;
+
+	(*entry)->output_image_type = ent->output_image_type;
+	if ((*entry)->output_command) free ((*entry)->output_command);
+	(*entry)->output_command = ent->output_command;
+	ent->output_command = NULL;
+
+	free_mgcsfx(ent);
+	break;
+      }
+    }
+    if (!*entry){
+      ent->next = NULL;
+      *entry = ent;
+    }
+
+    /* if(s == NULL) break; */
+next3:;
+    if(def_err != 0) free_mgcsfx(ent);
+  } /* end of while(1) */
+}
+
+
+/***************************************************/
+/* マジックナンバー定義ファイル名を得て、読み込ませる */
+static void init_mgcsfx ()
+{
+  extern char *getenv ();
+
+  char      *home_dir;
+  char       fname[1024];
+  mgcsfxtab *entry;
+  int        len;
+  struct stat st;
+
+#ifdef USE_MGCSFX_PREPROCESSOR
+  char      *pp_fname;
+#endif /* USE_MGCSFX_PREPROCESSOR */
+
+  mgcsfx_table = NULL;
+
+  mgcsfx_handler_setup();
+
+  if(nomgcsfx){
+    mgcsfx_setup_flag = 1;
+    nitem_mgcsfx = 0;
+    desc_width = 0;
+  }else{
+    sprintf (fname, "%s/%s", SYSCONFDIR, MGCSFX_SITE_RC);
+    if(stat(fname, &st) == 0 && S_ISREG(st.st_mode)){
+      /* Read the site MagicSuffix table into a linked list */
+#ifdef USE_MGCSFX_PREPROCESSOR
+      if((pp_fname = make_preprocessed_file(fname)) != NULL){
+	read_mgcsfx (&mgcsfx_table, pp_fname);
+      }
+      unlink(pp_fname);
+#else
+      read_mgcsfx (&mgcsfx_table, fname);
+#endif /* USE_MGCSFX_PREPROCESSOR */
+    }
+
+    /* Read the personal MgcSfx table into the list overriding site entries */
+    if ((home_dir = getenv ("HOME"))){
+      sprintf (fname, "%s/%s", home_dir, MGCSFX_RC);
+      if(stat(fname, &st) == 0 && S_ISREG(st.st_mode)){
+#ifdef USE_MGCSFX_PREPROCESSOR
+	if((pp_fname = make_preprocessed_file(fname)) != NULL){
+	  read_mgcsfx (&mgcsfx_table, pp_fname);
+	}
+	unlink(pp_fname);
+#else
+	read_mgcsfx (&mgcsfx_table, fname);
+#endif /* USE_MGCSFX_PREPROCESSOR */
+      }
+    }
+
+    mgcsfx_setup_flag = 1;
+
+    nitem_mgcsfx = 0;
+    desc_width = 0;
+    for (entry = mgcsfx_table; entry; entry = entry->next){
+      nitem_mgcsfx ++;
+      len = strlen(entry->description);
+      if(len > desc_width) desc_width = len;
+      if(max_offset_mgcsfx < entry->offset) max_offset_mgcsfx = entry->offset;
+      if(entry->mgcsfx_type == T_MAGIC &&
+	 max_length_mgcsfx < entry->string_len)
+	max_length_mgcsfx = entry->string_len;
+    }
+    if(max_length_mgcsfx == 0) max_length_mgcsfx = sizeof(int32);
+    need_buf_size = max_offset_mgcsfx + max_length_mgcsfx + 1;/* 1 is safety */
+  }
+}
+
+/***************************************************/
+/* マジックナンバーを調べて、定義しているテーブルを検索する
+   マジックナンバーのテーブルを読み込んでいないなら読み込む */
+static mgcsfxtab *find_mgcsfx (fname, buffer, buffer_size)
+     char           *fname;
+     unsigned char  *buffer;
+     int             buffer_size;
+{
+  mgcsfxtab *entry;
+  int16      buf16;
+  int32      buf32;
+  char      *suf;
+
+  if (mgcsfx_setup_flag == 0) init_mgcsfx ();
+
+  for (entry = mgcsfx_table; entry; entry = entry->next){
+    switch (entry->mgcsfx_type){
+    case T_BEINT16:
+      if ((buffer_size > 0) &&
+	  ((entry->offset + sizeof (int16)) <= buffer_size)){
+	buf16 = ((char)*(buffer + entry->offset) << 8) |
+	  ((char)*(buffer + entry->offset +1));
+	if(entry->dt.int16_data == buf16) return entry;
+      }
+      break;
+    case T_LEINT16:
+      if ((buffer_size > 0) &&
+	  ((entry->offset + sizeof (int16)) <= buffer_size)){
+	buf16 = ((char)*(buffer + entry->offset +1) << 8) |
+	  ((char)*(buffer + entry->offset));
+	if(entry->dt.int16_data == buf16) return entry;
+      }
+      break;
+    case T_BEINT32:
+      if ((buffer_size > 0) &&
+	  ((entry->offset + sizeof (int32)) <= buffer_size)){
+	buf32 = ((char)*(buffer + entry->offset) << 24) |
+	  ((char)*(buffer + entry->offset +1) << 16) |
+	  ((char)*(buffer + entry->offset +2) << 8) |
+	  ((char)*(buffer + entry->offset +3));
+	if(entry->dt.int32_data == buf32) return entry;
+      }
+      break;
+    case T_LEINT32:
+      if ((buffer_size > 0) &&
+	  ((entry->offset + sizeof (int32)) <= buffer_size)){
+	buf32 = ((char)*(buffer + entry->offset +3) << 24) |
+	  ((char)*(buffer + entry->offset +2) << 16) |
+	  ((char)*(buffer + entry->offset +1) << 8) |
+	  ((char)*(buffer + entry->offset));
+	if(entry->dt.int32_data == buf32) return entry;
+      }
+      break;
+    case T_MAGIC:
+      if ((buffer_size > 0) &&
+	  ((entry->offset + entry->string_len)
+	   <= buffer_size) &&
+	  !memcmp (entry->dt.string_data, buffer + entry->offset,
+		   entry->string_len ))
+	return entry;
+      break;
+    case T_SUFFIX:
+      if(fname != NULL && entry->suffix != NULL){
+	if(strlen(fname) - strlen(entry->suffix) > 0){
+	  suf = fname + (strlen(fname) - strlen(entry->suffix));
+	  if(!strcmp(suf, entry->suffix)) return entry;
+	}
+      }
+      break;
+    case T_UNKNOWN:
+    default:
+      return NULL;
+      break;
+    }
+  }
+  return NULL;
+}
+
+
+
+
+
+/***************************************************/
+/* マジックナンバーの定義を調べて、それにあわせたコマンドを実行する */
+/* if OK return 1, else if ERROR return 0 */
+int
+LoadMGCSFX(file_name, pinfo)
+     char    *file_name;
+     PICINFO *pinfo;
+{
+  unsigned char *buffer;
+  int            size;
+  mgcsfxtab     *magic;
+  mgcsfxtab     *magic_cur;
+  char          *ptr;
+  char           command[1024];
+  int            fd[2];
+  int            pid = -2;
+  int            file;
+  char          *fname;
+  int            rv;
+  int            pst;
+
+  int            i_it;
+  char          *i_com;
+
+  WaitCursor();
+
+  fname = file_name;
+  if((file = open (fname, O_RDONLY))<0){
+    SetISTR(ISTR_WARNING, "Can't open %s",fname);
+    return 0;
+  }
+
+  if((buffer = (unsigned char *)calloc(need_buf_size, sizeof(char))) == NULL){
+    SetISTR(ISTR_WARNING, "Can't allocate memory");
+    return 0;
+  }
+
+  magic_cur = NULL;
+
+/*  do{ */
+    size = read (file, buffer, need_buf_size);
+
+    if (lseek (file, 0L, 0) < 0){ /* can't seek pipe !! */
+      fprintf (stderr, "Can't lseek %s\n", file_name);
+      close(file);
+      return 0;
+    }
+
+    magic = find_mgcsfx (fname, buffer, size);
+
+    if ((magic != NULL && magic->input_command) ||
+        (magic == NULL && mgcsfx && input_command_ex_flag)){
+
+      if(magic == NULL){
+	if (fname != NULL && (ptr = strstr(input_command_ex, "%s"))){
+	  sprintf (command, input_command_ex, fname);
+	}else{
+	  strcpy (command, input_command_ex);
+	  fname=NULL;
+	}
+      }else{
+	/* Use stdin or give file name */
+	if (fname != NULL && (ptr = strstr(magic->input_command, "%s"))){
+	  sprintf (command, magic->input_command, fname);
+	}else{
+	  strcpy (command, magic->input_command);
+	  fname=NULL;
+	}
+      }
+
+      /* Do the pipe/fork/exec here */
+      if (pipe (fd) < 0){
+	fprintf (stderr, "Can't pipe : %s\n", file_name);
+	close(file);
+	return 0;
+      }
+
+      if ((pid = vfork ()) < 0){
+	fprintf (stderr, "Can't vfork : %s\n", file_name);
+	close (fd[0]);
+	close (fd[1]);
+	close(file);
+	return 0;
+      }
+
+      if (!pid){
+	 close(0);
+	if (fname == NULL || (open ("/dev/null", O_RDONLY) < 0)){
+	   dup(file);
+	}
+	 close(file);
+	 close(1);
+	 dup(fd[1]);
+	 close(2);
+	 open("/dev/null", O_WRONLY);
+	 close(fd[0]);
+	 execl("/bin/sh", "/bin/sh", "-c", command, 0);
+	_exit(127);
+      }
+
+      close (fd[1]);
+      dup2(fd[0], file);
+      close (fd[0]);
+      fname = NULL;
+      magic_cur = magic;
+    }
+/*  } while(magic != NULL); */
+
+  free(buffer);
+
+  if(magic_cur == NULL && mgcsfx && input_command_ex_flag){
+    i_it  = IT_PNM;
+    i_com = input_command_ex;
+  }else{
+    i_it  = magic_cur->input_image_type;
+    i_com = magic_cur->input_command;
+  }
+
+  if((magic_cur != NULL && i_com) ||
+    (magic_cur == NULL && mgcsfx && input_command_ex_flag)){
+    switch(i_it){
+    case IT_PNM:
+    case IT_PPM:
+    case IT_PGM:
+    case IT_PBM:
+    case IT_PNM_RAW:
+    case IT_PPM_RAW:
+    case IT_PGM_RAW:
+    case IT_PBM_RAW:
+    case IT_PNM_ASCII:
+    case IT_PPM_ASCII:
+    case IT_PGM_ASCII:
+    case IT_PBM_ASCII:
+      rv = LoadPBM(file_name, pinfo, file);
+      break;
+    case IT_GIF:
+    case IT_JPEG:
+    case IT_TIFF:
+    case IT_JFIF:
+    case IT_XBM:
+    case IT_XPM:
+    case IT_BMP:
+    case IT_SUNRAS:
+    case IT_IRIS:
+    case IT_XWD:
+    case IT_MAG:
+    case IT_MAKI:
+    case IT_PI:
+    case IT_PIC:
+    case IT_PIC2:
+      SetISTR(ISTR_WARNING, "Yet supported input image type (from filter output)");
+      rv = 0;
+      break;
+    case IT_UNKNOWN:
+      SetISTR(ISTR_WARNING, "Unknown input image type (from filter output)");
+      rv = 0;
+      break;
+#ifdef HAVE_MGCSFX_AUTO
+    case IT_AUTO:
+#endif
+    default:
+      SetISTR(ISTR_WARNING, "Error in input image type (from filter output)");
+      rv = 0;
+      break;
+    }
+  }else{
+    rv = 0;
+  }
+
+  /* fail if pid still == -2? */
+  while(wait(&pst) != pid);  /* FIXME?  pid isn't necessarily initialized... */
+  if( *((char *)&pst) != 0 ) rv = 0;
+
+  input_command_ex_flag = 0;
+
+  return rv;
+
+  /* fclose(fp);  close in Load??? */
+  /* return 0; error */
+  /* return 1; ok */
+}
+
+
+
+
+
+/*--------------------------------------------------------------------------*/
+#ifndef MGCSFX_DEFAULT_INPUT_COMMAND
+#  define MGCSFX_DEFAULT_INPUT_COMMAND  "tifftopnm"
+#endif
+#ifndef MGCSFX_DEFAULT_OUTPUT_COMMAND
+#  define MGCSFX_DEFAULT_OUTPUT_COMMAND "pnmtotiff"
+#endif
+
+int MSWIDE  =  0;
+int MSHIGH  =  0;
+
+#define MS_NBUTTS 2
+#define MS_BOK    0
+#define MS_BCANC  1
+#define BUTTW    60  /* width of buttons (OK or Cancel) */
+#define BUTTH    24  /* height of buttons (OK or Cancel) */
+#define RBSIZE   15  /* width and height of RB button (select, ON or OFF)*/
+#define CWIDE    8   /* width of character */
+/* #define CHIGH        height of character      defined in xv.h */
+#define MARGIN    3  /* margin of button and label     SPACING */
+
+#define MSD_TITLE       "Save file with external command..."
+#define MSD_RBTITLE     "Type of Magic and Suffix"
+#define MSD_IC_TITLE    "input command"
+
+static BUTT  msbut[MS_NBUTTS];
+static RBUTT *typeRB;
+
+static char output_command_ex[1024];
+static int  output_command_ex_flag = 0;
+
+static int   colorType;
+
+static int   w_pid;
+static int   w_pstatus;
+
+#define MSNAMWIDE 252               /* width of 'file name' entry window */
+#define MAXFNLEN 256               /* max len of filename being entered */
+static char   DialogFileName[MAXFNLEN+100];   /* filename being entered */
+static int    curPos, stPos, enPos;     /* filename textedit stuff */
+
+
+static mgcsfxtab *get_mgcsfx PARM((int));
+static void changeSuffix PARM((int));
+
+static int WriteMGCSFX  PARM((FILE**,byte*,int,int,int,
+			    byte*,byte*,byte*,int,int,char*,
+			    int, int, char*));
+void  CreateMGCSFXW         PARM((void));
+void  MGCSFXDialog          PARM((int));
+int   MGCSFXCheckEvent      PARM((XEvent *));
+int   MGCSFXSaveParams      PARM((char *, int));
+
+static void drawMSD     PARM((int,int,int,int));
+static void clickMSD    PARM((int,int));
+static void doCmd       PARM((int));
+static int writeMGCSFX  PARM((void));
+
+static void changeSuffix   PARM((int));
+static void redrawNamMSD   PARM((void));
+static void showFNamMSD    PARM((void));
+static int keyinMSD        PARM((int));
+
+int getInputCom  PARM((void));
+int getOutputCom PARM((void));
+/*--------------------------------------------------------------------------*/
+
+/***************************************************/
+/* どれを選んだか調べる。０はコマンドを入力するものとする */
+static mgcsfxtab *get_mgcsfx(ms_type)
+     int ms_type;
+{
+  mgcsfxtab *magic;
+  int        i;
+
+  magic = NULL;
+  if(ms_type != 0){
+    i = 1;
+    for(magic = mgcsfx_table; (magic && i<ms_type); magic = magic->next){i++;}
+  }
+  return magic;
+}
+
+/***************************************************/
+/* 外部コマンドを実行して、それに出力する */
+/* if OK return 0, else if ERROR return -1 */
+static
+int WriteMGCSFX(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,file_name,
+		ms_type, file, comment)
+     FILE **fp;
+     byte  *pic;
+     int    ptype, w,h;
+     byte  *rmap, *gmap, *bmap;
+     int    numcols, colorstyle;
+     char  *file_name;
+     int    ms_type;
+     int    file; /* file descriptor */
+     char  *comment;
+{
+  mgcsfxtab *magic;
+
+  int        fd[2];
+  int        pid;
+  int        rv;
+
+  WaitCursor();
+
+#ifdef USE_SIGCHLD
+  w_p_fail = 1;
+#endif
+
+  magic = get_mgcsfx(ms_type);
+  if(ms_type != 0 && magic == NULL) return -1;
+
+  if ((ms_type == 0 && output_command_ex_flag) ||
+      (ms_type !=0 && magic != NULL && magic->output_command)){
+
+    /* Do the pipe/fork/exec here */
+    if (pipe (fd) < 0){
+      fprintf (stderr, "Can't pipe : %s\n", file_name);
+      return -1;
+    }
+
+    if ((pid = vfork ()) < 0){
+      fprintf (stderr, "Can't vfork : %s\n", file_name);
+      close (fd[0]);
+      close (fd[1]);
+      return -1;
+    }
+
+    if (!pid){
+      close(1);
+      dup(file);
+      close(file);
+      close(0);
+      dup(fd[0]);
+      close(2);
+      open("/dev/null", O_WRONLY);
+      close(fd[1]);
+      if(ms_type == 0){
+	execl("/bin/sh", "/bin/sh", "-c", output_command_ex, 0);
+      }else{
+	execl("/bin/sh", "/bin/sh", "-c", magic->output_command, 0);
+      }
+      _exit(127);
+    }
+
+    close (fd[0]);
+    dup2(fd[1], file);
+    close (fd[1]);
+
+  }else{
+    return -1;
+  }
+
+
+  *fp = fdopen(file, "w");
+
+  /* sleep(1); Best way is wait for checking SIGCHLD, but it's feel waist.*/
+
+#ifdef USE_SIGCHLD
+  if(w_p_fail != 2){
+#endif
+    if(ms_type == 0){
+      rv = WritePBM(*fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,
+		    1, comment);
+    }else{
+      switch(magic -> output_image_type){
+      case IT_PNM:
+      case IT_PPM:
+      case IT_PGM:
+      case IT_PBM:
+      case IT_PNM_RAW:
+      case IT_PPM_RAW:
+      case IT_PGM_RAW:
+      case IT_PBM_RAW:
+	rv = WritePBM(*fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,
+		      1, comment);
+	break;
+      case IT_PNM_ASCII:
+      case IT_PPM_ASCII:
+      case IT_PGM_ASCII:
+      case IT_PBM_ASCII:
+	rv = WritePBM(*fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,
+		      0, comment);
+	break;
+      case IT_GIF:
+      case IT_JPEG:
+      case IT_TIFF:
+      case IT_JFIF:
+      case IT_XBM:
+      case IT_XPM:
+      case IT_BMP:
+      case IT_SUNRAS:
+      case IT_IRIS:
+      case IT_XWD:
+      case IT_MAG:
+      case IT_MAKI:
+      case IT_PI:
+      case IT_PIC:
+      case IT_PIC2:
+	SetISTR(ISTR_WARNING, "Yet supported output image type (to filter input)");
+	rv = -1;
+	break;
+      case IT_UNKNOWN:
+	SetISTR(ISTR_WARNING, "Unknown output image type (to filter input)");
+	rv = -1;
+	break;
+#ifdef HAVE_MGCSFX_AUTO
+      case IT_AUTO:
+#endif
+      default:
+	SetISTR(ISTR_WARNING, "Error in output image type (to filter input)");
+	rv = -1;
+	break;
+      }
+    }
+#ifdef USE_SIGCHLD
+  }else{
+    rv = -1;
+  }
+#endif
+
+#ifdef USE_SIGCHLD
+  if(w_p_fail != 2){
+#endif
+    w_pid = pid;
+#ifdef USE_SIGCHLD
+    w_p_fail = 0;
+  }else{
+    rv = -1;
+  }
+#endif
+
+  output_command_ex_flag = 0;
+
+  return rv;
+
+  /* fclose(*fp);   close in CloseOutFile in writeMGCSFX */
+  /* return  0; ok */
+  /* return -1; error */
+}
+
+/***************************************************/
+void CreateMGCSFXW()
+{
+  int	     y;
+  int        type_num;
+  mgcsfxtab *entry;
+
+  if (mgcsfx_setup_flag == 0) init_mgcsfx ();
+
+  if(desc_width < strlen(MSD_IC_TITLE))  desc_width = strlen(MSD_IC_TITLE);
+  nitem_mgcsfx ++;
+
+  MSWIDE = desc_width * CWIDE + RBSIZE + 36; /* 36 is start of RB button */
+  MSHIGH = nitem_mgcsfx * (RBSIZE + MARGIN);
+
+  if(MSWIDE < strlen(MSD_TITLE) + 20) MSWIDE = strlen(MSD_TITLE) + 20;
+  if(MSWIDE < strlen(MSD_RBTITLE) + 16) MSWIDE = strlen(MSD_RBTITLE) + 16;
+  if(MSWIDE < MSNAMWIDE + 10) MSWIDE = MSNAMWIDE + 10;
+  if(MSWIDE <  BUTTW * 2 + 10) MSWIDE = BUTTW * 2 + 10;
+
+  MSHIGH += 55 + LINEHIGH + 10 + BUTTH + 10;
+
+  MSWIDE += 20; /* right side margin */
+  MSHIGH += 10; /* RB buttun down side margin */
+
+
+  mgcsfxW = CreateWindow("xv mgcsfx", "XVmgcsfx", NULL,
+			 MSWIDE, MSHIGH, infofg, infobg, 0);
+  if (!mgcsfxW) FatalError("can't create mgcsfx window!");
+
+  XSelectInput(theDisp, mgcsfxW,
+	       ExposureMask | ButtonPressMask | KeyPressMask);
+
+  mgcsfxNameW = XCreateSimpleWindow(theDisp, mgcsfxW,
+				    10,  MSHIGH-LINEHIGH-10-BUTTH-10-1,
+				    (u_int) MSNAMWIDE+6, (u_int) LINEHIGH+5,
+				    1, infofg, infobg);
+  if (!mgcsfxNameW) FatalError("can't create mgcsfx name window");
+  XSelectInput(theDisp, mgcsfxNameW, ExposureMask);
+
+  /* Ok ボタン */
+  BTCreate(&msbut[MS_BOK], mgcsfxW,
+	   MSWIDE-BUTTW-10-BUTTW-10-1, MSHIGH-BUTTH-10-1,
+	   BUTTW, BUTTH,
+	   "Ok", infofg, infobg, hicol, locol);
+  /* Cancel ボタン*/
+  BTCreate(&msbut[MS_BCANC], mgcsfxW,
+	   MSWIDE-BUTTW-10-1, MSHIGH-BUTTH-10-1,
+	   BUTTW, BUTTH,
+	   "Cancel", infofg, infobg, hicol, locol);
+
+  y = 55;
+  /* User should input command to exec external command */
+  typeRB = RBCreate(NULL, mgcsfxW, 36, y,          MSD_IC_TITLE,
+		    infofg, infobg,hicol,locol);
+  y += (RBSIZE + MARGIN); /* 18 */
+
+  type_num = 1;
+  for (entry = mgcsfx_table; entry; entry = entry->next){
+    RBCreate(typeRB, mgcsfxW, 36, y,            entry->description,
+	     infofg, infobg,hicol,locol);
+    y += (RBSIZE + MARGIN); /* 18 */
+    if(entry->output_command == NULL){
+      RBSetActive(typeRB, type_num, 0); /* if no command, off */
+    }
+    type_num++;
+  }
+
+  XMapSubwindows(theDisp, mgcsfxW);
+}
+
+
+/***************************************************/
+void MGCSFXDialog(vis)
+     int vis;
+{
+  if (vis) {
+    CenterMapWindow(mgcsfxW, msbut[MS_BOK].x + msbut[MS_BOK].w/2,
+		    msbut[MS_BOK].y + msbut[MS_BOK].h/2, MSWIDE, MSHIGH);
+  }
+  else     XUnmapWindow(theDisp, mgcsfxW);
+  mgcsfxUp = vis;
+}
+
+
+/***************************************************/
+int MGCSFXCheckEvent(xev)
+     XEvent *xev;
+{
+  /* check event to see if it's for one of our subwindows.  If it is,
+     deal accordingly, and return '1'.  Otherwise, return '0' */
+
+  int rv;
+  rv = 1;
+
+  if (!mgcsfxUp) return (0);
+
+  if (xev->type == Expose) {
+    int x,y,w,h;
+    XExposeEvent *e = (XExposeEvent *) xev;
+    x = e->x;  y = e->y;  w = e->width;  h = e->height;
+
+    if (e->window == mgcsfxW)       drawMSD(x, y, w, h);
+    else rv = 0;
+  }
+
+  else if (xev->type == ButtonPress) {
+    XButtonEvent *e = (XButtonEvent *) xev;
+    int x,y;
+    x = e->x;  y = e->y;
+
+    if (e->button == Button1) {
+      if      (e->window == mgcsfxW)     clickMSD(x,y);
+      else rv = 0;
+    }  /* button1 */
+    else rv = 0;
+  }  /* button press */
+
+  else if (xev->type == KeyPress) {
+    XKeyEvent *e = (XKeyEvent *) xev;
+    char buf[128];  KeySym ks;  XComposeStatus status;
+    int stlen;
+
+    stlen = XLookupString(e,buf,128,&ks,&status);
+    buf[stlen] = '\0';
+
+    if (e->window == mgcsfxW) {
+      if (stlen) {
+	keyinMSD(buf[0]);
+      }
+    }
+    else rv = 0;
+  }
+  else rv = 0;
+
+  if (rv == 0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
+    XBell(theDisp, 50);
+    rv = 1;   /* eat it */
+  }
+
+  return (rv);
+}
+
+
+/***************************************************/
+int MGCSFXSaveParams(fname, col)
+     char *fname;
+     int col;
+{
+  colorType = col;
+  strcpy(DialogFileName, GetDirFName());
+  return (0);
+}
+
+/***************************************************/
+/* ダイアログを表示するときの処理 */
+static void drawMSD(x,y,w,h)
+     int x,y,w,h;
+{
+  int        i;
+  XRectangle xr;
+
+  xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
+  XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
+
+  XSetForeground(theDisp, theGC, infofg);
+  XSetBackground(theDisp, theGC, infobg);
+
+  for (i = 0; i < MS_NBUTTS; i++) BTRedraw(&msbut[i]);
+
+  ULineString(mgcsfxW, typeRB->x-16, typeRB->y-3-DESCENT,
+	      MSD_RBTITLE);
+  RBRedraw(typeRB, -1);
+
+  DrawString(mgcsfxW, 20, 29, MSD_TITLE);
+
+  XSetClipMask(theDisp, theGC, None);
+
+  showFNamMSD();
+}
+
+/***************************************************/
+/* ダイアログをクリックしたときの処理 */
+static void clickMSD(x,y)
+     int x,y;
+{
+  int   i;
+  BUTT *bp;
+
+  /* check BUTTs */
+
+  /* check the RBUTTS first, since they don't DO anything */
+  if ((i = RBClick(typeRB, x,y)) >= 0) { /* 選択(type)ボタンの処理 */
+    (void) RBTrack(typeRB, i);  /* 選択(type)ボタンを押したとき */
+    changeSuffix(i);
+    return;
+  }
+
+  for (i = 0; i < MS_NBUTTS; i++) { /* Ok,Cancel ボタンの処理 */
+    bp = &msbut[i];
+    if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h))
+      break;
+  }
+  if (i < MS_NBUTTS)  /* found one */ /* Ok,Cancel ボタンを押したとき */
+    if (BTTrack(bp)) doCmd(i);
+}
+
+/***************************************************/
+/* ボタン(Ok, Cancel) の処理 */
+static void doCmd(cmd)
+     int cmd;
+{
+  int rv;
+
+  switch (cmd) {
+  case MS_BOK: /* Ok button */ {
+    char *fullname;
+
+    rv = writeMGCSFX(); /* Save with filter(MGCSFX) */
+    MGCSFXDialog(0);
+
+    fullname = GetDirFullName();
+    if (!ISPIPE(fullname[0])) {
+      XVCreatedFile(fullname);
+      if(!rv) StickInCtrlList(0);
+    }
+  }
+    break;
+  case MS_BCANC: /* Cancel button */
+    DialogFileName[0] = '\0';
+    curPos = stPos = enPos = 0;
+    MGCSFXDialog(0);
+    break;
+  default:
+    break;
+  }
+}
+
+/*******************************************/
+static int writeMGCSFX()
+{
+  int   rv, type;
+  int   ptype, w, h, pfree, nc;
+  byte *inpix, *rmap, *gmap, *bmap;
+
+  FILE *fp = NULL;
+  int   file;
+  char *fullname;
+
+  rv = -1;
+  type = RBWhich(typeRB);
+
+  SetDirFName(DialogFileName); /* change filename in dir dialog */
+  fullname = GetDirFullName();
+
+  if(type == 0){
+    if(getOutputCom() == 0) return rv;
+  }
+
+  file = OpenOutFileDesc(fullname);
+  if(file < 0) return rv;
+
+  WaitCursor();
+  inpix = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rmap, &gmap, &bmap);
+
+  rv = WriteMGCSFX(&fp, inpix, ptype, w, h,
+		   rmap, gmap, bmap, nc, colorType, fullname,
+		   type, file, picComments);
+
+  SetCursors(-1);
+
+  if (CloseOutFile(fp, fullname, rv) == 0) DirBox(0);
+
+  WaitCursor();
+#ifdef USE_SIGCHLD
+  if(w_p_fail == 0){
+#endif
+    while(wait(&w_pstatus) != w_pid);  /* if( *((char *)&w_pstatus) != 0 ) ; */
+#ifdef USE_SIGCHLD
+  }else{
+    w_p_fail = 0;
+  }
+#endif
+  w_pid = 0;
+  w_pstatus = 0;
+
+  if (pfree) free(inpix);
+  return rv;
+}
+
+
+/***************************************/
+static void changeSuffix(ms_type)
+     int ms_type;
+{
+  /* see if there's a common suffix at the end of the DialogFileName.
+     if there is, remember what case it was (all caps or all lower), lop
+     it off, and replace it with a new appropriate suffix, in the
+     same case */
+
+  int allcaps;
+  char *suffix, *sp, *dp, lowsuf[512];
+  mgcsfxtab *magic;
+
+  /* find the last '.' in the DialogFileName */
+  suffix = (char *) rindex(DialogFileName, '.');
+  if (!suffix) return;
+  suffix++;  /* point to first letter of the suffix */
+
+  /* check for all-caposity */
+  for (sp = suffix, allcaps=1; *sp; sp++)
+    if (islower(*sp)) allcaps = 0;
+
+  /* copy the suffix into an all-lower-case buffer */
+  for (sp=suffix, dp=lowsuf; *sp; sp++, dp++) {
+    *dp = (isupper(*sp)) ? tolower(*sp) : *sp;
+  }
+  *dp = '\0';
+
+
+  magic = get_mgcsfx(ms_type);
+  if(magic != NULL && magic->suffix != NULL){
+    strcpy(lowsuf,(magic->suffix)+1);
+
+    if (allcaps) {  /* upper-caseify lowsuf */
+      for (sp=lowsuf; *sp; sp++)
+	*sp = (islower(*sp)) ? toupper(*sp) : *sp;
+    }
+
+    /* one other case:  if the original suffix started with a single
+       capital letter, make the new suffix start with a single cap */
+    if (isupper(suffix[0])) lowsuf[0] = toupper(lowsuf[0]);
+
+    strcpy(suffix, lowsuf);   /* tack onto DialogFileName */
+    showFNamMSD();
+  }
+}
+
+/***************************************************/
+/* ダイアログ内にファイルネームを表示するときの処理 (下請け)*/
+static void redrawNamMSD()
+{
+  int cpos;
+
+  /* draw substring DialogFileName[stPos:enPos] and cursor */
+
+  Draw3dRect(mgcsfxNameW, 0, 0, (u_int) MSNAMWIDE+5, (u_int) LINEHIGH+4, R3D_IN, 2,
+	     hicol, locol, infobg);
+
+  XSetForeground(theDisp, theGC, infofg);
+
+  if (stPos>0) {  /* draw a "there's more over here" doowah */
+    XDrawLine(theDisp, mgcsfxNameW, theGC, 0,0,0,LINEHIGH+5);
+    XDrawLine(theDisp, mgcsfxNameW, theGC, 1,0,1,LINEHIGH+5);
+    XDrawLine(theDisp, mgcsfxNameW, theGC, 2,0,2,LINEHIGH+5);
+  }
+
+  if ((size_t) enPos < strlen(DialogFileName)) {
+    /* draw a "there's more over here" doowah */
+    XDrawLine(theDisp, mgcsfxNameW, theGC, MSNAMWIDE+5,0,MSNAMWIDE+5,LINEHIGH+5);
+    XDrawLine(theDisp, mgcsfxNameW, theGC, MSNAMWIDE+4,0,MSNAMWIDE+4,LINEHIGH+5);
+    XDrawLine(theDisp, mgcsfxNameW, theGC, MSNAMWIDE+3,0,MSNAMWIDE+3,LINEHIGH+5);
+  }
+
+  XDrawString(theDisp, mgcsfxNameW, theGC,3,ASCENT+3,DialogFileName+stPos, enPos-stPos);
+
+  cpos = XTextWidth(mfinfo, &DialogFileName[stPos], curPos-stPos);
+  XDrawLine(theDisp, mgcsfxNameW, theGC, 3+cpos, 2, 3+cpos, 2+CHIGH+1);
+  XDrawLine(theDisp, mgcsfxNameW, theGC, 3+cpos, 2+CHIGH+1, 5+cpos, 2+CHIGH+3);
+  XDrawLine(theDisp, mgcsfxNameW, theGC, 3+cpos, 2+CHIGH+1, 1+cpos, 2+CHIGH+3);
+}
+
+/***************************************************/
+/* ダイアログ内にファイルネームを表示する */
+static void showFNamMSD()
+{
+  int len;
+
+  len = strlen(DialogFileName);
+
+  if (curPos<stPos) stPos = curPos;
+  if (curPos>enPos) enPos = curPos;
+
+  if (stPos>len) stPos = (len>0) ? len-1 : 0;
+  if (enPos>len) enPos = (len>0) ? len-1 : 0;
+
+  /* while substring is shorter than window, inc enPos */
+
+  while (XTextWidth(mfinfo, &DialogFileName[stPos], enPos-stPos) < MSNAMWIDE
+	 && enPos<len) { enPos++; }
+
+  /* while substring is longer than window, dec enpos, unless enpos==curpos,
+     in which case, inc stpos */
+
+  while (XTextWidth(mfinfo, &DialogFileName[stPos], enPos-stPos) > MSNAMWIDE) {
+    if (enPos != curPos) enPos--;
+    else stPos++;
+  }
+
+
+  if (ctrlColor) XClearArea(theDisp, mgcsfxNameW, 2,2, (u_int) MSNAMWIDE+5-3,
+			    (u_int) LINEHIGH+4-3, False);
+  else XClearWindow(theDisp, mgcsfxNameW);
+
+  redrawNamMSD();
+  BTSetActive(&msbut[MS_BOK], strlen(DialogFileName)!=0);
+}
+
+/***************************************************/
+/* キー入力したときの処理 */
+static int keyinMSD(c)
+     int c;
+{
+  /* got keypress in dirW.  stick on end of DialogFileName */
+  int len;
+
+  len = strlen(DialogFileName);
+
+  if (c>=' ' && c<'\177') {             /* printable characters */
+    /* note: only allow 'piped commands' in savemode... */
+
+    /* only allow spaces in 'piped commands', not filenames */
+    if (c==' ' && (!ISPIPE(DialogFileName[0]) || curPos==0)) return (-1);
+
+    /* only allow vertbars in 'piped commands', not filenames */
+    if (c=='|' && curPos!=0 && !ISPIPE(DialogFileName[0])) return(-1);
+
+    if (len >= MAXFNLEN-1) return(-1);  /* max length of string */
+    xvbcopy(&DialogFileName[curPos], &DialogFileName[curPos+1], (size_t) (len-curPos+1));
+    DialogFileName[curPos]=c;  curPos++;
+  }
+
+  else if (c=='\010' || c=='\177') {    /* BS or DEL */
+    if (curPos==0) return(-1);          /* at beginning of str */
+    xvbcopy(&DialogFileName[curPos], &DialogFileName[curPos-1], (size_t) (len-curPos+1));
+    curPos--;
+  }
+
+  else if (c=='\025') {                 /* ^U: clear entire line */
+    DialogFileName[0] = '\0';
+    curPos = 0;
+  }
+
+  else if (c=='\013') {                 /* ^K: clear to end of line */
+    DialogFileName[curPos] = '\0';
+  }
+
+  else if (c=='\001') {                 /* ^A: move to beginning */
+    curPos = 0;
+  }
+
+  else if (c=='\005') {                 /* ^E: move to end */
+    curPos = len;
+  }
+
+  else if (c=='\004') {                 /* ^D: delete character at curPos */
+    if (curPos==len) return(-1);
+    xvbcopy(&DialogFileName[curPos+1], &DialogFileName[curPos], (size_t) (len-curPos));
+  }
+
+  else if (c=='\002') {                 /* ^B: move backwards char */
+    if (curPos==0) return(-1);
+    curPos--;
+  }
+
+  else if (c=='\006') {                 /* ^F: move forwards char */
+    if (curPos==len) return(-1);
+    curPos++;
+  }
+
+  else if (c=='\012' || c=='\015') {    /* CR(\r) or LF(\n) */
+    FakeButtonPress(&msbut[MS_BOK]);
+  }
+
+  else if (c=='\033') {                  /* ESC = Cancel */
+    FakeButtonPress(&msbut[MS_BCANC]);
+  }
+
+  else if (c=='\011') {                  /* tab = filename expansion */
+    if (1 /* !autoComplete() */) XBell(theDisp, 0);
+    else {
+      curPos = strlen(DialogFileName);
+    }
+  }
+
+  else return(-1);                      /* unhandled character */
+
+  showFNamMSD();
+
+  return(0);
+}
+
+
+/*******************************************/
+int getInputCom()
+{
+  static char *labels[] = { "\nOk", "\033Cancel" };
+  int i;
+
+  strcpy(input_command_ex, MGCSFX_DEFAULT_INPUT_COMMAND);
+  i = GetStrPopUp("Input External Command (Input is PNM):", labels, 2,
+		  input_command_ex, 1024, "",0);
+  if (i == 0 && strlen(input_command_ex) != 0){
+    input_command_ex_flag = 1;
+    return 1;
+  }else{
+    input_command_ex_flag = 0;
+    return 0;
+  }
+}
+
+int getOutputCom()
+{
+  static char *labels[] = { "\nOk", "\033Cancel" };
+  int i;
+
+  strcpy(output_command_ex, MGCSFX_DEFAULT_OUTPUT_COMMAND);
+  i = GetStrPopUp("Input External Command (Output is PNM_RAW):", labels, 2,
+		  output_command_ex, 1024, "",0);
+  if (i == 0 && strlen(output_command_ex) != 0){
+    output_command_ex_flag = 1;
+    return 1;
+  }else{
+    output_command_ex_flag = 0;
+    return 0;
+  }
+}
+
+#ifdef SVR4
+Sigfunc *
+xv_signal(signo, func)
+     int signo;
+     Sigfunc *func;
+{
+  struct sigaction act, oact;
+
+  act.sa_handler = func;
+  sigemptyset(&act.sa_mask);
+  act.sa_flags = 0;
+  act.sa_flags |= SA_RESTART;
+
+  if (sigaction(signo, &act, &oact) < 0)
+    return SIG_ERR;
+
+  return oact.sa_handler;
+}
+#endif
+
+#endif /* HAVE_MGCSFX */
diff -ruN xv-3.10a-bugfixes/xvmisc.c xv-3.10a-enhancements/xvmisc.c
--- xv-3.10a-bugfixes/xvmisc.c	2005-03-20 22:47:06.000000000 -0800
+++ xv-3.10a-enhancements/xvmisc.c	2005-04-17 14:45:28.000000000 -0700
@@ -103,10 +103,18 @@
   if (!usesize || !(i&WidthValue))  w = defw;
   if (!usesize || !(i&HeightValue)) h = defh;
 
-  hints.flags |= USSize;
+  hints.flags |= USSize | PWinGravity;
 
-  if (i&XValue && i&XNegative) x = dispWIDE - w - abs(x);
-  if (i&YValue && i&YNegative) y = dispHIGH - h - abs(y);
+  hints.win_gravity = NorthWestGravity;
+  if (i&XValue && i&XNegative) {
+    hints.win_gravity = NorthEastGravity;
+    x = dispWIDE - (w + 2 * bwidth) - abs(x);
+  }
+  if (i&YValue && i&YNegative) {
+    hints.win_gravity = (hints.win_gravity == NorthWestGravity) ?
+      SouthWestGravity : SouthEastGravity;
+    y = dispHIGH - (h + 2 * bwidth) - abs(y);
+  }
 
 
 #define VROOT_TRANS
@@ -142,20 +150,19 @@
   if (!win) return(win);   /* leave immediately if couldn't create */
 
 
-  XSetStandardProperties(theDisp, win, name, name, None, NULL, 0, &hints);
-
   xwmh.input = True;
   xwmh.flags = InputHint;
   if (iconPix) { xwmh.icon_pixmap = iconPix;  xwmh.flags |= IconPixmapHint; }
-  XSetWMHints(theDisp, win, &xwmh);
 
   if (clname && strlen(clname)) {
     classh.res_name = "xv";
     classh.res_class = clname;
-    XSetClassHint(theDisp, win, &classh);
     StoreDeleteWindowProp(win);
   }
 
+  XmbSetWMProperties(theDisp, win, name, name, NULL, 0, &hints, &xwmh,
+      clname ? &classh : NULL);
+
   return(win);
 }
 
@@ -232,28 +239,28 @@
   int  i = CK_NONE;
 
   if      (ks==XK_Up    || ks==XK_KP_Up    ||
-	   ks==XK_KP_8  || ks==XK_F28)             i=CK_UP;
+			   ks==XK_F28)             i=CK_UP;
 
   else if (ks==XK_Down  || ks==XK_KP_Down  ||
-	   ks==XK_KP_2  || ks==XK_F34)             i=CK_DOWN;
+			   ks==XK_F34)             i=CK_DOWN;
 
   else if (ks==XK_Left  || ks==XK_KP_Left  ||
-	   ks==XK_KP_4  || ks==XK_F30)             i=CK_LEFT;
+			   ks==XK_F30)             i=CK_LEFT;
 
   else if (ks==XK_Right || ks==XK_KP_Right ||
-	   ks==XK_KP_6  || ks==XK_F32)             i=CK_RIGHT;
+			   ks==XK_F32)             i=CK_RIGHT;
 
   else if (ks==XK_Prior || ks==XK_KP_Prior ||
-	   ks==XK_KP_9  || ks==XK_F29)             i=CK_PAGEUP;
+			   ks==XK_F29)             i=CK_PAGEUP;
 
   else if (ks==XK_Next  || ks==XK_KP_Next  ||
-	   ks==XK_KP_3  || ks==XK_F35)             i=CK_PAGEDOWN;
+			   ks==XK_F35)             i=CK_PAGEDOWN;
 
   else if (ks==XK_Home  || ks==XK_KP_Home  ||
-	   ks==XK_KP_7  || ks==XK_F27)             i=CK_HOME;
+			   ks==XK_F27)             i=CK_HOME;
 
   else if (ks==XK_End   || ks==XK_KP_End   ||
-	   ks==XK_KP_1  || ks==XK_F33)             i=CK_END;
+			   ks==XK_F33)             i=CK_END;
 
   else i = CK_NONE;
 
@@ -503,6 +510,11 @@
      as we have to keep the alloc'd colors around, but we don't want anything
      else to stay */
 
+#ifdef AUTO_EXPAND
+  chdir(initdir);
+  Vdsettle();
+#endif
+
   if (!theDisp) exit(i);   /* called before connection opened */
 
   if (useroot && i==0) {   /* save the root info */
@@ -526,6 +538,26 @@
     if (tiffW) XDestroyWindow(theDisp, tiffW);
 #endif
 
+#ifdef HAVE_PNG
+    if (pngW)  XDestroyWindow(theDisp, pngW);
+#endif
+
+#ifdef HAVE_PCD
+    if (pcdW)  XDestroyWindow(theDisp, pcdW);
+#endif
+
+#ifdef HAVE_PIC2
+    if (pic2W) XDestroyWindow(theDisp, pic2W);
+#endif
+
+#ifdef HAVE_MGCSFX
+    if (mgcsfxW) XDestroyWindow(theDisp, mgcsfxW);
+#endif
+
+#ifdef HAVE_PNG
+    if (pngW)  XDestroyWindow(theDisp, pngW);
+#endif
+
     /* if NOT using stdcmap for images, free stdcmap */
     if (colorMapMode != CM_STDCMAP) {
       int j;
@@ -722,6 +754,26 @@
 #ifdef HAVE_TIFF
   if (tiffW) XDefineCursor(theDisp, tiffW, otherc);
 #endif
+
+#ifdef HAVE_PNG
+  if (pngW)  XDefineCursor(theDisp, pngW, otherc);
+#endif
+
+#ifdef HAVE_PNG
+  if (pngW)  XDefineCursor(theDisp, pngW, otherc);
+#endif
+
+#ifdef HAVE_PCD
+  if (pcdW)  XDefineCursor(theDisp, pcdW, otherc);
+#endif
+
+#ifdef HAVE_PIC2
+  if (pic2W) XDefineCursor(theDisp, pic2W, otherc);
+#endif
+
+#ifdef HAVE_MGCSFX
+  if (mgcsfxW) XDefineCursor(theDisp, mgcsfxW, otherc);
+#endif
 }
 
 
@@ -921,7 +973,7 @@
 void XVCreatedFile(fullname)
      char *fullname;
 {
-  /* called whenever a file has been deleted.  Updates browser & dir windows,
+  /* called whenever a file has been created.  Updates browser & dir windows,
      if necessary */
 
   BRCreatedFile(fullname);
@@ -1006,6 +1058,9 @@
 	((rv=(char *) getenv("cwd"))==NULL)) rv = "./";
     strcpy(buf, rv);
   }
+#ifdef AUTO_EXPAND
+  Vdtodir(buf);
+#endif
 }
 
 
diff -ruN xv-3.10a-bugfixes/xvml.c xv-3.10a-enhancements/xvml.c
--- xv-3.10a-bugfixes/xvml.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvml.c	2005-04-17 22:57:34.000000000 -0700
@@ -0,0 +1,989 @@
+/*
+ * xvml.c  -  makes text item structure for multi-lingual textviewer.
+ *
+ * Entry Points:
+ *  struct ml_text *ml_draw_text()
+ *  struct context *ml_create_context()
+ *  int ml_set_charsets()
+ *  void get_monofont_size()
+ */
+
+#include "xv.h"
+#include <X11/Xresource.h>
+
+#ifdef TV_MULTILINGUAL	/* whole this file. */
+
+#include "xvml.h"
+#define HAVE_STRDUP 1
+#define USE_MULE_EXTENSION
+
+#ifndef __STDC__
+#define CHAR char
+#else
+#define CHAR int
+#endif
+
+#define CODE_SI  0x0e	/* LS0 */
+#define CODE_SO  0x0f	/* LS1 */
+#define CODE_SS2 ((unsigned char) 0x8e)
+#define CODE_SS3 ((unsigned char) 0x8f)
+
+int ml_tab_width = 64;	/* dots */
+
+struct charset {
+    int bpc;		/* bytes per char */
+    int noc;		/* number of chars */
+    char designator;
+    char *registry;
+    int bit7;
+
+    int loaded;
+    char *fontname;
+
+    XFontStruct *fs;
+} charset[] = {
+    { 1, 94, 'B', "iso8859-1",       0, 0, NULL, NULL},
+    { 1, 96, 'A', "iso8859-1",       1, 0, NULL, NULL},
+    { 1, 94, '0', "omron_udc_zh-0",  0, 0, NULL, NULL},
+    { 1, 94, '2', "mulearabic-0",    0, 0, NULL, NULL},
+    { 1, 94, '3', "mulearabic-1",    0, 0, NULL, NULL},
+    { 1, 94, '4', "mulearabic-2",    0, 0, NULL, NULL},
+    { 1, 94, 'J', "jisx0201.1976-0", 0, 0, NULL, NULL},
+    { 1, 96, '0', "muleipa-1",       1, 0, NULL, NULL},
+    { 1, 96, '1', "viscii1.1-1",     1, 0, NULL, NULL},
+    { 1, 96, '2', "viscii1.1-1",     1, 0, NULL, NULL},
+    { 1, 96, 'B', "iso8859-2",       1, 0, NULL, NULL},
+    { 1, 96, 'C', "iso8859-3",       1, 0, NULL, NULL},
+    { 1, 96, 'D', "iso8859-4",       1, 0, NULL, NULL},
+    { 1, 96, 'T', "tis620.1986-0",   1, 0, NULL, NULL},
+    { 1, 96, 'F', "iso8859-7",       1, 0, NULL, NULL},
+    { 1, 96, 'G', "iso8859-6",       1, 0, NULL, NULL},
+    { 1, 96, 'H', "iso8859-8",       1, 0, NULL, NULL},
+    { 1, 94, 'I', "jisx0201.1976-0", 1, 0, NULL, NULL},
+    { 1, 96, 'L', "iso8859-5",       1, 0, NULL, NULL},
+    { 1, 96, 'M', "iso8859-9",       1, 0, NULL, NULL},
+    { 2, 94, '2', "ethio-0",         0, 0, NULL, NULL},
+    { 2, 94, '@', "jisx0208.1978",   0, 0, NULL, NULL},
+    { 2, 94, 'A', "gb2312.1980-0",   0, 0, NULL, NULL},
+    { 2, 94, 'B', "jisx0208.1983-0", 0, 0, NULL, NULL},
+    { 2, 94, 'C', "ksc5601.1987-0",  0, 0, NULL, NULL},
+    { 2, 94, 'D', "jisx0212.1990-0", 0, 0, NULL, NULL},
+    { 2, 94, '0', "big5.eten-0",     0, 0, NULL, NULL},
+    { 2, 94, '1', "big5.hku-0",      0, 0, NULL, NULL},
+    /* End Mark */
+    { 0,  0,   0,        NULL,       0, 0, NULL, NULL},
+};
+#define NR_CHARSETS ((int) (sizeof charset / sizeof charset[0]))
+
+static struct charset *ascii = NULL;
+
+struct context {
+    struct charset *g[4];
+    struct charset **gl, **gr;
+    struct charset **ss;
+    int eol;		/* 0: \n,  1: \r\n,  2: \r,  3: any */
+    int valid[4];	/* g[i] is valid? */
+    int short_form;	/* allow shortened designator sequence? */
+    int lock_shift;	/* allow locking shift? */
+
+    unsigned char *cbuf, *cbp;
+    struct ml_text text;
+    int line;
+    int delta;
+    int toolong;
+
+    Display *dpy;
+    Screen *scr;
+    Window root_win;
+};
+#define DPY (context->dpy)
+#define SCR (context->scr)
+#define ROOT_WIN (context->root_win)
+
+static unsigned char *escape_sequence		PARM((unsigned char *));
+static unsigned char *designator_sequence	PARM((unsigned char *));
+static void locking_shift			PARM((unsigned CHAR));
+static void single_shift			PARM((unsigned CHAR));
+static void put_unknown_char			PARM((unsigned CHAR));
+static struct charset *search_charset		PARM((int, int, int));
+static void pack_string				PARM((struct charset *,
+						      unsigned char *, int));
+static void init_xrm				PARM((void));
+static void init_xrm_fonts			PARM((void));
+static void init_xrm_tab			PARM((void));
+#ifndef HAVE_STRDUP
+static char *strdup				PARM((char *));
+#endif
+
+static char *default_fonts[] = {		/* default for xrm_fonts */
+    "-sony-fixed-medium-r-normal--16-*-*-*-*-*-iso8859-1",
+    "-jis-fixed-medium-r-normal--16-*-*-*-*-*-jisx0208.1983-0",
+};
+static int xrm_nfonts;
+static char **xrm_fonts;
+
+static struct context *context;	/* current context */
+
+struct ml_text *ml_draw_text(ctx, string, len)
+    struct context *ctx;
+    char *string;
+    int len;
+{
+    unsigned char *str = (unsigned char *) string;
+    unsigned char *estr = str + len;
+
+    context = ctx;
+
+    if(ascii == NULL){
+	fputs("ml_draw_text: call ml_set_charsets, first.\n", stderr);
+	return NULL;
+    }
+
+    if(!str)
+	return &context->text;
+
+    WaitCursor();
+
+    if (context->text.maxlines != 0) {
+	struct ml_text *tp = &context->text;
+	struct ml_line *lp;
+	int i;
+	for (i = tp->nlines, lp = tp->lines; i > 0; i--, lp++) {
+	    if (lp->maxitems != 0)
+		free((char *) lp->items);
+	}
+	free((char *) tp->lines);
+	tp->maxlines = tp->nlines = 0;
+    }
+    if (context->cbuf != NULL)
+	free((char *) context->cbuf);
+    context->cbp = (unsigned char *) malloc((size_t) len * 8);/* all \xxx */
+    context->cbuf = context->cbp;
+    context->line = 0;
+    context->delta = 0;
+    context->ss = NULL;
+
+    while(str < estr){
+	if((*str & 0x80) == 0){				/* left half */
+	    struct charset *cs = context->ss ? *context->ss : *context->gl;
+	    unsigned char min_char, max_char;
+	    if (cs != NULL) {
+		if(cs->noc == 94){
+		    min_char = 0x21;
+		    max_char = 0x7e;
+		}else{
+		    min_char = 0x20;
+		    max_char = 0x7f;
+		}
+	    }
+
+	    if (cs == NULL)
+		put_unknown_char(*str++);
+	    else if(*str < min_char || *str > max_char){	/* C1 */
+		switch(*str){
+		case ' ':
+		    {
+			unsigned char *p = str + 1;
+			while (*p == ' ' && p < estr)
+			    p++;
+			pack_string(ascii, str, (int) (p - str));
+			str = p;
+		    }
+		    break;
+
+		case '\t':
+		    pack_string(ascii, str++, 0);
+		    break;
+
+		case '\n':
+		    switch (context->eol) {
+		    case 0:				/* unix type eol */
+			pack_string(ascii, str, 0);
+			WaitCursor();
+			str++;
+			break;
+		    case 1:				/* dos type eol */
+		    case 2:				/* mac type eol */
+			put_unknown_char('\n');
+			str++;
+			break;
+		    case 3:				/* any type eol */
+			pack_string(ascii, str++, 0);
+			while (*str == '\n' || *str == '\r')
+			    str++;
+			WaitCursor();
+			break;
+		    }
+		    break;
+
+		case '\r':
+		    switch (context->eol) {
+		    case 0:
+			put_unknown_char('\r');
+			str++;
+			break;
+		    case 1:
+			str++;
+			if (*str == '\n')
+			    pack_string(ascii, str++, 0);
+			else
+			    put_unknown_char('\r');
+			break;
+		    case 2:
+			pack_string(ascii, str, 0);
+			WaitCursor();
+			str++;
+			break;
+		    case 3:
+			pack_string(ascii, str++, 0);
+			while (*str == '\n' || *str == '\r')
+			    str++;
+			WaitCursor();
+			break;
+		    }
+		    break;
+
+		case '\033':
+		    {
+			unsigned char *p;
+			str++;
+			if((p = escape_sequence(str)) == str)
+			    put_unknown_char('\033');
+			else
+			    str = p;
+		    }
+		    break;
+
+		case CODE_SI:
+		case CODE_SO:
+		    if (!context->lock_shift)
+			put_unknown_char((unsigned int) *str++);
+		    else
+			locking_shift((unsigned int) *str++);
+		    break;
+
+		default:
+		    put_unknown_char((unsigned int) *str++);
+		}
+	    }else{					/* GL */
+		if (context->ss != NULL) {
+		    pack_string(cs, str, 1);
+		    str += cs->bpc;
+		    context->ss = NULL;
+		} else {
+		    int n;
+
+		    if (cs->bpc == 1) {
+			unsigned char *p = str;
+			for (n = 0; p < estr; n++) {
+			    if (*p < min_char || *p > max_char)
+				break;
+			    p++;
+			}
+			pack_string(cs, str, n);
+			str = p;
+		    } else {
+			unsigned char *p = str;
+			for (n = 0; p < estr - 1; n++) {
+			    if (*p < min_char || *p > max_char ||
+				    *(p + 1) < min_char || *(p + 1) > max_char)
+				break;
+			    p += 2;
+			}
+			if (n > 0)
+			    pack_string(cs, str, n);
+			else
+			    put_unknown_char(*p++);
+			str = p;
+		    }
+		}
+	    }
+	}else{						/* right half */
+	    struct charset *cs = context->ss ? *context->ss : *context->gr;
+	    unsigned char min_char, max_char;
+	    if (cs != NULL) {
+		if(cs->noc == 94){
+		    min_char = 0xa1;
+		    max_char = 0xfe;
+		}else{
+		    min_char = 0xa0;
+		    max_char = 0xff;
+		}
+	    }
+
+	    if (cs == NULL)
+		put_unknown_char(*str++);
+	    else if(*str < min_char || *str > max_char){	/* C2 */
+		unsigned char c = *str++;
+		switch(c){
+		case CODE_SS2:
+		case CODE_SS3:
+		    single_shift((unsigned CHAR) c);
+		    break;
+		default:
+		    put_unknown_char(c);
+		}
+	    }else{					/* GR */
+		if (context->ss != NULL) {
+		    pack_string(cs, str, 1);
+		    str += cs->bpc;
+		    context->ss = NULL;
+		} else {
+		    int n;
+
+		    if (cs->bpc == 1) {
+			unsigned char *p = str;
+			for (n = 0; p < estr; n++) {
+			    if (*p < min_char || *p > max_char)
+				break;
+			    p++;
+			}
+			pack_string(cs, str, n);
+			str = p;
+		    } else {
+			unsigned char *p = str;
+			for (n = 0; p < estr - 1; n++) {
+			    if (*p < min_char || *p > max_char ||
+				    *(p + 1) < min_char || *(p + 1) > max_char)
+				break;
+			    p += 2;
+			}
+			if (n > 0)
+			    pack_string(cs, str, n);
+			else
+			    put_unknown_char(*p++);
+			str = p;
+		    }
+		}
+	    }
+	}
+    }
+
+    {
+	struct ml_text *tp = &context->text;
+	struct ml_line *lp;
+	int i;
+
+	tp->width = 0;
+	tp->height = 0;
+	for (lp = tp->lines, i = tp->nlines; i > 0; lp++, i--) {
+	    if (lp->nitems == 0) {
+		lp->ascent  = ascii->fs->ascent;
+		lp->descent = ascii->fs->descent;
+	    }
+	    if (tp->width < lp->width)
+		tp->width = lp->width;
+	    tp->height += lp->ascent + lp->descent;
+	}
+    }
+
+    SetCursors(-1);
+    return &context->text;
+}
+
+static unsigned char *escape_sequence(str)
+    unsigned char *str;
+{
+    unsigned char *p;
+    switch(*str){
+    case '$':
+    case '(': case ')': case '*': case '+':
+    case '-': case '.': case '/': case ',':
+	if((p = designator_sequence(str)) == NULL)
+	    return str;
+	return p;
+    case 'n': case 'o': case '~': case '}': case '|':
+	if (!context->lock_shift)
+	    return str;
+	locking_shift(*str);
+	return str + 1;
+    case 'N': case 'O':
+	single_shift(*str);
+	return str + 1;
+    }
+    return str;
+
+}
+
+static unsigned char *designator_sequence(str)
+    unsigned char *str;
+{
+    unsigned char *p = str;
+    int noc, bpc, n_g, shortened;
+    unsigned char des;
+    struct charset *cs;
+
+    if(*p == '$'){
+	bpc = 2;
+	p++;
+    }else
+	bpc = 1;
+
+    switch(*p++){
+    case '(':	noc = 94; n_g = 0; des = *p++; shortened = 0; break;
+    case ')':	noc = 94; n_g = 1; des = *p++; shortened = 0; break;
+    case '*':	noc = 94; n_g = 2; des = *p++; shortened = 0; break;
+    case '+':	noc = 94; n_g = 3; des = *p++; shortened = 0; break;
+#ifdef USE_MULE_EXTENSION
+    case ',':	noc = 96; n_g = 0; des = *p++; shortened = 0; break;
+#endif
+    case '-':	noc = 96; n_g = 1; des = *p++; shortened = 0; break;
+    case '.':	noc = 96; n_g = 2; des = *p++; shortened = 0; break;
+    case '/':	noc = 96; n_g = 3; des = *p++; shortened = 0; break;
+    case '@':	noc = 94; n_g = 0; des = 'B';  shortened = 0; break;
+    case 'A':	noc = 94; n_g = 0; des = 'A';  shortened = 1; break;
+    case 'B':	noc = 94; n_g = 0; des = 'B';  shortened = 1; break;
+    default:	return NULL;
+    }
+    if (!context->short_form && shortened)
+	return NULL;
+
+    if((cs = search_charset(bpc, noc, des)) == NULL){
+	if(DEBUG){
+	    fprintf(stderr, "designator_sequence: (%d,%d,%c) not found.\n",
+		    bpc, noc, des);
+	}
+	return NULL;
+    }
+    if (!context->valid[n_g])
+	return NULL;
+    context->g[n_g] = cs;
+    if(DEBUG){
+	fprintf(stderr,
+		"designator_sequence: G%d is `%s'.\n", n_g, cs->registry);
+    }
+    return p;
+}
+
+static void locking_shift(c)
+    unsigned CHAR c;
+{
+    switch((unsigned char) c){
+    case CODE_SI:	context->gl = &context->g[0]; break;
+    case CODE_SO:	context->gl = &context->g[1]; break;
+    case 'n':		context->gl = &context->g[2]; break;
+    case 'o':		context->gl = &context->g[3]; break;
+    case '~':		context->gr = &context->g[1]; break;
+    case '}':		context->gr = &context->g[2]; break;
+    case '|':		context->gr = &context->g[3]; break;
+    }
+    if(DEBUG){
+	fprintf(stderr, "locking_shift: (%d,%d).\n",
+		(int)(context->gl - context->g),
+		(int)(context->gr - context->g));
+    }
+}
+
+static void single_shift(c)
+    unsigned CHAR c;
+{
+    switch((unsigned char) c){
+    case CODE_SS2:	context->ss = &context->g[2]; break;
+    case CODE_SS3:	context->ss = &context->g[3]; break;
+    }
+}
+
+
+static void put_unknown_char(chr)
+    unsigned CHAR chr;
+{
+    unsigned char c = chr;
+
+    if(c < 0x20){
+	unsigned char buf[2];
+	buf[0] = '^';
+	buf[1] = c + 0x40;
+	pack_string(ascii, buf, 2);
+    }else{
+	unsigned char buf[4];
+	buf[0] = '\\';
+	buf[1] =  ((c >> 6) & 07) + '0';
+	buf[2] =  ((c >> 3) & 07) + '0';
+	buf[3] =  ((c     ) & 07) + '0';
+	pack_string(ascii, buf, 4);
+    }
+}
+
+struct context *ml_create_context(s)
+    Screen *s;
+{
+    context = (struct context *) malloc(sizeof *context);
+
+    context->g[0] = NULL;
+    context->g[1] = NULL;
+    context->g[2] = NULL;
+    context->g[3] = NULL;
+    context->gl = NULL;
+    context->gr = NULL;
+    context->ss = NULL;
+
+    context->cbuf = NULL;
+    context->text.maxlines = context->text.nlines = 0;
+    context->line = 0;
+    context->delta = 0;
+    context->toolong = 0;
+
+    DPY = DisplayOfScreen(s);
+    SCR = s;
+    ROOT_WIN = RootWindowOfScreen(s);
+
+    return context;
+}
+
+
+int ml_set_charsets(ctx, sys)
+    struct context *ctx;
+    struct coding_system *sys;
+{
+    int retval = 0;
+    int i;
+
+    context = ctx;
+
+    if(ascii == NULL){
+	init_xrm();
+	if((ascii = search_charset(1, 94, 'B')) == NULL){
+	    fputs("ml_set_charsets: ascii charset not found.\n", stderr);
+	    Quit(1);
+	}
+	if (ascii->fs == NULL) {
+	    fputs("ml_set_charsets: iso8859-1 font not found.\n", stderr);
+	    Quit(1);
+	}
+    }
+    for(i = 0; i < 4; i++){
+	switch(sys->design[i].bpc){
+	case -1:	/* make G[i] invalid */
+	    context->valid[i] = 0;
+	    break;
+
+	case 0:		/* don't change */
+	    break;
+
+	case 1: case 2:	/* change it */
+	    if((context->g[i] = search_charset(sys->design[i].bpc,
+					       sys->design[i].noc,
+					       sys->design[i].des)) == NULL){
+		fputs("ml_set_charsets: ", stderr);
+		fprintf(stderr, "(%d,%d,%c) is specified as G%d, ",
+			sys->design[i].bpc, sys->design[i].noc,
+			sys->design[i].des, i);
+		fputs("but not found. using `iso8859-1'.\n", stderr);
+		context->g[i] = ascii;
+		retval++;
+	    }
+	    context->valid[i] = 1;
+	    break;
+
+	default:	/* error */
+	    fprintf(stderr,"ml_set_charsets: bad arguments of G%d. ", i);
+	    fputs("using `iso8859-1'.\n", stderr);
+	    context->g[i] = ascii;
+	    retval++;
+	}
+    }
+    if((unsigned int) sys->gl < 4)
+	context->gl = &context->g[sys->gl];
+    else{
+	fprintf(stderr, "ml_set_charsets: bad number as GL. using G0.\n");
+	context->gl = &context->g[0];
+    }
+    if((unsigned int) sys->gr < 4)
+	context->gr = &context->g[sys->gr];
+    else{
+	fprintf(stderr, "ml_set_charsets: bad number as GR. using G0.\n");
+	context->gr = &context->g[0];
+    }
+    context->eol = sys->eol;
+    context->short_form = sys->short_form;
+    context->lock_shift = sys->lock_shift;
+    return retval;
+}
+
+static struct charset *search_charset(bpc, noc, des)
+    int bpc, noc;
+    int des;
+{
+    struct charset *cset;
+    for(cset = charset; cset->bpc != 0; cset++){
+	if(cset->bpc == bpc &&
+	   cset->noc == noc &&
+	   cset->designator == (char) des){
+	    if(!cset->loaded){
+#if 0
+		int i, l;
+		l = strlen(cset->registry);
+		for (i = 0; i < xrm_nfonts; i++) {
+		    int li = strlen(xrm_fonts[i]);
+		    if (li > l) {
+			if (xrm_fonts[i][li - l - 1] == '-' &&
+				strcmp(xrm_fonts[i] + li - l,
+				       cset->registry) == 0) {
+			    if ((cset->fs = XLoadQueryFont(DPY, xrm_fonts[i]))
+				    != NULL) {
+				if (DEBUG) {
+				    fprintf(stderr, "%s for %s\n",
+					    xrm_fonts[i], cset->registry);
+				}
+				cset->fontname = xrm_fonts[i];
+				break;
+			    } else
+				SetISTR(ISTR_WARNING,
+					"%s: font not found.", xrm_fonts[i]);
+			}
+		    }
+		}
+#else
+		int i, l;
+		l = strlen(cset->registry);
+		for (i = 0; i < xrm_nfonts && cset->fs == NULL; i++) {
+		    int j, nfnts = 0;
+		    char **fnts = XListFonts(DPY, xrm_fonts[i],
+					     65535, &nfnts);
+		    for (j = 0 ; j < nfnts; j++) {
+			int ll = strlen(fnts[j]);
+			if (*(fnts[j] + ll - l - 1) == '-' &&
+			    strcmp(fnts[j] + ll - l, cset->registry)== 0) {
+			    if ((cset->fs = XLoadQueryFont(DPY, fnts[j]))
+				!= NULL) {
+				if (DEBUG) {
+				    fprintf(stderr, "%s for %s\n",
+					    fnts[j], cset->registry);
+				}
+				cset->fontname = strdup(fnts[j]);
+				break;
+			    } else
+				SetISTR(ISTR_WARNING,
+					"%s: font not found", fnts[j]);
+			}
+		    }
+		    if (fnts != NULL)
+			XFreeFontNames(fnts);
+		}
+#endif
+		if(cset->fs == NULL){
+		    SetISTR(ISTR_WARNING,
+			    "font for %s not found.\nusing ascii font.",
+			    cset->registry);
+		    if (ascii != NULL)
+			cset->fs = ascii->fs;
+		}
+
+		cset->loaded = 1;
+	    }
+	    return cset;
+	}
+    }
+    return NULL;
+}
+
+static void pack_string(cs, str, len)
+    struct charset *cs;
+    unsigned char *str;
+    int len;	/* number of chars(not bytes) */
+{
+    struct ml_text *mt = &context->text;
+    struct ml_line *lp;
+    XTextItem16 *ip;
+
+    if (context->line == mt->maxlines) {
+	int oldmax = mt->maxlines;
+	if (mt->maxlines < 1)
+	    mt->maxlines = 1;
+	else
+	    mt->maxlines = 2 * mt->maxlines;
+	if (oldmax == 0)
+	    mt->lines = (struct ml_line *)
+				malloc(sizeof(struct ml_line) * mt->maxlines);
+	else {
+	    mt->lines = (struct ml_line *)
+				realloc(mt->lines,
+					sizeof(struct ml_line) * mt->maxlines);
+	}
+    }
+    lp = &mt->lines[context->line];
+    if (mt->nlines == context->line) {
+	mt->nlines++;
+	lp->maxitems = 0;
+	lp->nitems = 0;
+	lp->width = 0;
+	lp->ascent = lp->descent = 0;
+    }
+
+    if (len == 0) {
+	switch (*str) {
+	case '\n':
+	    context->line++;
+	    context->delta = 0;
+	    context->toolong = 0;
+	    break;
+	case '\t':
+	    {
+		int nx, x = lp->width + context->delta;
+		nx = (x + ml_tab_width) / ml_tab_width * ml_tab_width;
+		context->delta += nx - x;
+	    }
+	    break;
+	}
+	return;
+    }
+
+    if (context->toolong)
+	return;
+    if (lp->width > 30000) {
+	context->toolong = 1;
+	cs = ascii;
+	str = (unsigned char *) "...";
+	len = 3;
+    }
+
+    if (lp->nitems == lp->maxitems) {
+	int oldmax = lp->maxitems;
+	if (lp->maxitems < 1)
+	    lp->maxitems = 1;
+	else
+	    lp->maxitems = 2 * lp->maxitems;
+	if (oldmax == 0)
+	    lp->items = (XTextItem16 *)
+				malloc(sizeof(XTextItem16) * lp->maxitems);
+	else
+	    lp->items = (XTextItem16 *)
+				realloc(lp->items,
+					sizeof(XTextItem16) * lp->maxitems);
+    }
+    ip = &lp->items[lp->nitems++];
+    ip->chars = (XChar2b *) context->cbp;
+    ip->nchars = len;
+    ip->delta = context->delta;
+    ip->font = cs->fs->fid;
+    context->cbp += 2 * len;
+    context->delta = 0;
+
+    if (cs->bpc == 1) {
+	XChar2b *p;
+	unsigned char b7 = cs->bit7 ? 0x80 : 0;
+	int i;
+	for (i = len, p = ip->chars; i > 0; i--, p++) {
+	    p->byte1 = '\0';
+	    p->byte2 = (*str++ & 0x7f) | b7;
+	}
+    } else {
+	XChar2b *p;
+	unsigned char b7 = cs->bit7 ? 0x80 : 0;
+	int i;
+	for (i = len, p = ip->chars; i > 0; i--, p++) {
+	    p->byte1 = (*str++ & 0x7f) | b7;
+	    p->byte2 = (*str++ & 0x7f) | b7;
+	}
+    }
+
+    lp->width += XTextWidth16(cs->fs, ip->chars, ip->nchars);
+    if (lp->ascent < cs->fs->ascent)
+	lp->ascent = cs->fs->ascent;
+    if (lp->descent < cs->fs->descent)
+	lp->descent = cs->fs->descent;
+}
+
+void get_monofont_size(wide, high)
+    int *wide, *high;
+{
+    if (ascii == NULL) {
+	fputs("ml_draw_text: call ml_set_charsets, first.\n", stderr);
+	return;
+    }
+    *wide = ascii->fs->max_bounds.width;
+    *high = ascii->fs->ascent + ascii->fs->descent;
+}
+
+static void init_xrm()
+{
+    init_xrm_fonts();
+    init_xrm_tab();
+}
+
+static void init_xrm_fonts()
+{
+    char *p, *fns = XGetDefault(theDisp, "xv", "fontSet");
+    int n;
+    if (fns == NULL) {
+	xrm_fonts = default_fonts;
+	xrm_nfonts = sizeof default_fonts / sizeof *default_fonts;
+	return;
+    }
+    while(*fns == ' ' || *fns == '\t')
+	fns++;
+    if (*fns == '\0') {
+	xrm_fonts = default_fonts;
+	xrm_nfonts = sizeof default_fonts / sizeof *default_fonts;
+	return;
+    }
+    fns = strdup(fns);
+
+    n = 1;
+    for (p = fns; *p != '\0'; p++) {
+	if (*p == ',')
+	    n++;
+    }
+    xrm_nfonts = n;
+    xrm_fonts = (char **) malloc(sizeof (char *) * xrm_nfonts);
+    for (n = 0, p = fns; n < xrm_nfonts && *p != '\0'; ) {
+	while (*p == ' ' || *p == '\t')
+	    p++;
+	xrm_fonts[n++] = p;
+	while (1) {
+	    char *q;
+	    while (*p != ' ' && *p != '\t' && *p != ',' && *p != '\0')
+		p++;
+	    q = p;
+	    while (*q == ' ' || *q == '\t')
+		q++;
+	    if (*q == ',' || *q == '\0') {
+		*p = '\0';
+		p = q + 1;
+		break;
+	    } else
+		p = q;
+	}
+    }
+    for ( ; n < xrm_nfonts; n++)
+	xrm_fonts[n] = "";
+}
+
+static void init_xrm_tab()
+{
+    char *ts = XGetDefault(theDisp, "xv", "tabWidth");
+    unsigned short tab;
+    if (ts == NULL)
+	tab = 64;
+    else {
+	char *ep;
+	long t;
+	int bad = 0;
+	t = strtol(ts, &ep, 0);
+	tab = (unsigned short) t;
+	if (ep != NULL) {
+	    while (*ep == ' ' && *ep == '\t')
+		ep++;
+	    if (*ep != '\0')
+		bad = 1;
+	}
+	if (tab != (long) (unsigned long) t)
+	    bad = 1;
+	if (bad) {
+	    SetISTR(ISTR_WARNING, "bad tab width.");
+	    tab = 64;
+	}
+    }
+    ml_tab_width = tab;
+}
+
+
+#ifndef HAVE_STRDUP
+static char *strdup(str)
+    char *str;
+{
+    return strcpy(malloc(strlen(str) + 1), str);
+}
+#endif
+
+char *lookup_registry(d, b7)
+    struct design d;
+    int *b7;
+{
+    int i;
+    for (i = 0; i < NR_CHARSETS; i++) {
+	if (charset[i].bpc == d.bpc && charset[i].noc == d.noc &&
+	    charset[i].designator == d.des) {
+	    *b7 = charset[i].bit7;
+	    return charset[i].registry;
+	}
+    }
+    return NULL;
+}
+
+struct design lookup_design(registry, b7)
+    char *registry;
+    int b7;
+{
+    struct design d;
+    int i;
+    d.bpc = 0;
+    d.noc = 0;
+    d.des = '\0';
+    for (i = 0; i < NR_CHARSETS; i++) {
+	if (strcmp(charset[i].registry, registry) == 0 &&
+		charset[i].bit7 == b7) {
+	    d.bpc = charset[i].bpc;
+	    d.noc = charset[i].noc;
+	    d.des = charset[i].designator;
+	    break;
+	}
+    }
+    return d;
+}
+
+char *sjis_to_jis(orig, len, newlen)
+    char *orig;
+    int len, *newlen;
+{
+    unsigned char *new;
+    unsigned char *p, *q, *endp;
+    if (len == 0) {
+	*newlen = 0;
+	return (char *) malloc((size_t) 1);
+    }
+    new = (unsigned char *) malloc((size_t) len * 4);	/* big enough */
+    for (p = (unsigned char *) orig, endp = p + len, q = new; p < endp; ) {
+	if ((*p & 0x80) == 0)			/* 1 byte char */
+	    *q++ = *p++;
+	else if (*p >= 0x81 && *p <= 0x9f) {	/* kanji 1st byte */
+	    unsigned char c1 = *p++;
+	    unsigned char c2 = *p++;
+	    if (c2 < 0x40 || c2 > 0xfc) {		/* bad 2nd byte */
+		*q++ = CODE_SS2;
+		*q++ = c1;
+		*q++ = CODE_SS2;
+		*q++ = c2;
+	    } else {					/* right 2nd byte */
+		if (c2 <= 0x9e) {
+		    if (c2 > 0x7f)
+			c2--;
+		    c1 = (c1 - 0x81) * 2 + 1 + 0xa0;
+		    c2 = (c2 - 0x40)     + 1 + 0xa0;
+		} else {
+		    c1 = (c1 - 0x81) * 2 + 2 + 0xa0;
+		    c2 = (c2 - 0x9f)     + 1 + 0xa0;
+		}
+		*q++ = c1;
+		*q++ = c2;
+	    }
+	} else if (*p >= 0xe0 && *p <= 0xef) {	/* kanji 1st byte */
+	    unsigned char c1 = *p++;
+	    unsigned char c2 = *p++;
+	    if (c2 < 0x40 || c2 > 0xfc) {		/* bad 2nd byte */
+		*q++ = CODE_SS2;
+		*q++ = c1;
+		*q++ = CODE_SS2;
+		*q++ = c2;
+	    } else {					/* right 2nd byte */
+		if (c2 <= 0x9e) {
+		    c1 = (c1 - 0xe0) * 2 + 63 + 0xa0;
+		    c2 = (c2 - 0x40)     +  1 + 0xa0;
+		} else {
+		    c1 = (c1 - 0xe0) * 2 + 64 + 0xa0;
+		    c2 = (c2 - 0x9f)     +  1 + 0xa0;
+		}
+		*q++ = c1;
+		*q++ = c2;
+	    }
+	} else {				/* katakana or something */
+	    *q++ = CODE_SS2;
+	    *q++ = *p++;
+	}
+    }
+    *newlen = q - new;
+
+    return (char *) realloc(new, (size_t) *newlen);
+}
+
+#endif /* TV_MULTILINGUAL */
diff -ruN xv-3.10a-bugfixes/xvml.h xv-3.10a-enhancements/xvml.h
--- xv-3.10a-bugfixes/xvml.h	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvml.h	2005-04-17 22:57:45.000000000 -0700
@@ -0,0 +1,96 @@
+#ifndef MLVIEW_H
+#define MLVIEW_H
+
+/*
+ * What is this?
+ *
+ *  It is a package to show multi-lingual text.
+ *
+ * How to use?
+ *
+ *  1. Call ml_set_screen(Screen *scr);
+ *	Tell this package the screen you use.
+ *
+ *  2. Call ml_set_charsets(struct char_spec spec[4], int gl, int gr);
+ *	Tell this package the initial charsets.
+ *	Gn is set to the charset specified by spec[n], respectively.
+ *	GL and GR are set to G[gl] and G[gr], respectively.
+ *	If first call, iso8859-1 font is loaded.
+ *
+ *  3. Call ml_draw_text(char *string);
+ *	It Creates a bitmap, and returns it to you.
+ *	If something goes wrong, it returns None.
+ *	DON'T free the returned pixmaps!!
+ *
+ * BUGS:
+ *  - Amharic and Tigrigna characters are strange.
+ *  - Big5 is not supported.
+ *  - Reverse direction is not supported.
+ *  - Composing is not supported.
+ *  - Cantonese can't be shown.
+ *  - Texts which have many lines are buggy.
+ *
+ * NOTE:
+ *  - Shifted JIS and Shifted GB must be converted to iso2022 in advance.
+ *
+ * Example of parameters to ml_set_charsets:
+ *  - EUC-Japan
+ *	spec = { {1, 94, 'B'},		G0 is US-ASCII
+ *		 {2, 94, 'B'},		G1 is JIS X0208
+ *		 {1, 94, 'J'},		G2 is (right-half of)JIS X0201
+ *		 {2, 94, 'D'} };	G3 is JIS X0212
+ *	gl = 0;				GL is G0
+ *	gr = 1;				GR is G1
+ *
+ *  - Compound Text
+ *	spec = { {1, 94, 'B'},		G0 is US-ASCII
+ *		 {1, 96, 'A'},		G1 is Latin-1
+ *		 {1, 94, 'B'},		G2 is US-ASCII (maybe unused)
+ *		 {1, 94, 'B'} };	G3 is US-ASCII (maybe unused)
+ *	gl = 0;				GL is G0
+ *	gr = 1;				GR is G1
+ *
+ *  - Korean Mail
+ *	spec = { {1, 94, 'B'},		G0 is US-ASCII
+ *		 {2, 94, 'C'},		G1 is KSC5601
+ *		 {1, 94, 'B'},		G2 is US-ASCII (maybe unused)
+ *		 {1, 94, 'B'} };	G3 is US-ASCII (maybe unused)
+ *	gl = 0;				GL is G0
+ *	gl = 1;				GR is G1
+ */
+
+struct coding_system {
+    struct design {
+	int bpc;	/* byte per char if 1 or 2,
+			   don't touch if 0, or
+			   don't use if -1.*/
+	int noc;	/* number of chars (94 or 96) */
+	char des;	/* designator ('A', 'B', ...) */
+    } design[4];
+    int gl, gr;
+    int eol;
+    int short_form;
+    int lock_shift;
+};
+
+struct ml_text {
+    int maxlines, nlines;
+    struct ml_line {
+	int maxitems, nitems;
+	int width, ascent, descent;
+	XTextItem16 *items;
+    } *lines;
+    int width, height;
+};
+
+struct context;
+struct ml_text *ml_draw_text		PARM((struct context *, char *, int));
+struct context *ml_create_context	PARM((Screen *));
+int ml_set_charsets			PARM((struct context *,
+					      struct coding_system *));
+void get_monofont_size			PARM((int *, int *));
+char *sjis_to_jis			PARM((char *, int, int *));
+char *lookup_registry			PARM((struct design, int *));
+struct design lookup_design		PARM((char *, int));
+
+#endif
diff -ruN xv-3.10a-bugfixes/xvpbm.c xv-3.10a-enhancements/xvpbm.c
--- xv-3.10a-bugfixes/xvpbm.c	2005-04-03 14:25:28.000000000 -0700
+++ xv-3.10a-enhancements/xvpbm.c	2005-04-17 14:04:22.000000000 -0700
@@ -23,6 +23,15 @@
  */
 
 
+typedef unsigned short  ush;
+typedef unsigned char   uch;
+
+#define alpha_composite(composite, fg, alpha, bg) {               \
+    ush temp = ((ush)(fg)*(ush)(alpha) +                          \
+                (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128);  \
+    (composite) = (uch)((temp + (temp >> 8)) >> 8);               \
+}
+
 #define TRUNCSTR "File appears to be truncated."
 
 static int garbage;
@@ -31,6 +40,7 @@
 static int loadpbm  PARM((FILE *, PICINFO *, int));
 static int loadpgm  PARM((FILE *, PICINFO *, int, int));
 static int loadppm  PARM((FILE *, PICINFO *, int, int));
+static int loadpam  PARM((FILE *, PICINFO *, int, int));
 static int getint   PARM((FILE *, PICINFO *));
 static int getbit   PARM((FILE *, PICINFO *));
 static int getshort PARM((FILE *));
@@ -38,10 +48,83 @@
 
 static char *bname;
 
+
+#ifdef HAVE_MGCSFX
+/*
+ * When file read or file write is fail, probably it's caused by
+ * reading from pipe which has no data yet, or writing to pipe
+ * which is not ready yet.
+ * Then we can use system call select() on descriptor of pipe and wait.
+ * If you want, change 'undef' to 'define' in the following line.
+ * This feature is performance-killer.
+ */
+#undef FIX_PIPE_ERROR
+
+#ifdef __osf__
+#  ifdef __alpha
+#    define FIX_PIPE_ERROR
+#  endif
+#endif
+
+#endif /* HAVE_MGCSFX */
+
+
+#ifdef FIX_PIPE_ERROR
+
+int pipefdr;
+
+struct timeval timeout;
+int    width;
+fd_set fds;
+
+static void ready_read()
+{
+  if(pipefdr < 0) return; /* if file descriptor is not pipe, OK */
+  WaitCursor();
+
+reselect:
+  /* setting of timeout */
+  timeout.tv_sec = 1;  /* 1 sec */
+  timeout.tv_usec = 0; /* 0 usec */
+
+  FD_ZERO(&fds);     /* clear bits */
+  FD_SET(pipefdr, &fds); /* set bit of fd in fds */
+
+  /* number of file descriptor to want check (0 〜 width-1) */
+  width = pipefdr + 1;
+
+  /* select returns number of file descriptors */
+  if (select(width, &fds, NULL, NULL, &timeout) < 0){
+    if(DEBUG){
+      fprintf(stderr, "No file descriptors can't selected, waiting...\n");
+    }
+    goto reselect;
+  }
+
+  if (FD_ISSET(pipefdr, &fds)){
+    /* Now, descriptor of pipe is ready to read */
+    return;
+  }else{
+    if(DEBUG){
+      fprintf(stderr, "Can't read from pipe yet, waiting...\n");
+    }
+    goto reselect;
+  }
+
+}
+#endif /* FIX_PIPE_ERROR */
+
 /*******************************************/
+#ifdef HAVE_MGCSFX
+int LoadPBM(fname, pinfo, fd)
+     char    *fname;
+     PICINFO *pinfo;
+     int      fd;
+#else
 int LoadPBM(fname, pinfo)
      char    *fname;
      PICINFO *pinfo;
+#endif /* HAVE_MGCSFX */
 /*******************************************/
 {
   /* returns '1' on success */
@@ -50,6 +133,10 @@
   int    c, c1;
   int    maxv, rv;
 
+#ifdef FIX_PIPE_ERROR
+  pipefdr = fd;
+#endif
+
   garbage = maxv = rv = 0;
   bname = BaseName(fname);
 
@@ -57,6 +144,22 @@
   pinfo->comment = (char *) NULL;
 
 
+#ifdef HAVE_MGCSFX
+  if(fd < 0){
+    /* open the file */
+    fp = xv_fopen(fname,"r");
+    if (!fp) return (pbmError(bname, "can't open file"));
+
+    /* compute file length */
+    fseek(fp, 0L, 2);
+    filesize = ftell(fp);
+    fseek(fp, 0L, 0);
+  }else{
+    fp = fdopen(fd, "r");
+    if (!fp) return (pbmError(bname, "can't open file"));
+    filesize = 0; /* dummy */
+  }
+#else
   /* open the file */
   fp = xv_fopen(fname,"r");
   if (!fp) return (pbmError(bname, "can't open file"));
@@ -65,6 +168,7 @@
   fseek(fp, 0L, 2);
   filesize = ftell(fp);
   fseek(fp, 0L, 0);
+#endif /* HAVE_MGCSFX */
 
 
   /* read the first two bytes of the file to determine which format
@@ -73,7 +177,8 @@
      "P6" = raw pixmap */
 
   c = getc(fp);  c1 = getc(fp);
-  if (c!='P' || c1<'1' || c1>'6') return(pbmError(bname, "unknown format"));
+  if (c!='P' || c1<'1' || (c1>'6' && c1!='8'))	/* GRR alpha */
+    return(pbmError(bname, "unknown format"));
 
   /* read in header information */
   pinfo->w = getint(fp, pinfo);  pinfo->h = getint(fp, pinfo);
@@ -104,6 +209,7 @@
   if      (c1=='1' || c1=='4') rv = loadpbm(fp, pinfo, c1=='4' ? 1 : 0);
   else if (c1=='2' || c1=='5') rv = loadpgm(fp, pinfo, c1=='5' ? 1 : 0, maxv);
   else if (c1=='3' || c1=='6') rv = loadppm(fp, pinfo, c1=='6' ? 1 : 0, maxv);
+  else if            (c1=='8') rv = loadpam(fp, pinfo,           1    , maxv);
 
   fclose(fp);
 
@@ -248,7 +354,20 @@
       }
     }
     else {
+#ifdef FIX_PIPE_ERROR
+  reread:
+      numgot += fread(pic8 + numgot, (size_t) 1, (size_t) w*h - numgot, fp); /* read raw data */
+      if(errno == EINTR){
+        if(DEBUG){
+	  fprintf(stderr,
+	  "Can't read all data from pipe, call select and waiting...\n");
+	}
+	ready_read();
+	goto reread;
+      }
+#else
       numgot = fread(pic8, (size_t)1, (size_t)npixels, fp);  /* read raw data */
+#endif
     }
   }
 
@@ -315,7 +434,20 @@
       }
     }
     else {
+#ifdef FIX_PIPE_ERROR
+  reread:
+      numgot += fread(pic24 + numgot, (size_t) 1, (size_t) w*h*3 - numgot, fp);  /* read data */
+      if(errno == EINTR){
+        if(DEBUG){
+	  fprintf(stderr,
+	  "Can't read all data from pipe, call select and waiting...\n");
+	}
+	ready_read();
+	goto reread;
+      }
+#else
       numgot = fread(pic24, (size_t) 1, (size_t) bufsize, fp);  /* read data */
+#endif
     }
   }
 
@@ -341,6 +473,122 @@
 }
 
 
+/*******************************************/
+static int loadpam(fp, pinfo, raw, maxv)	/* unofficial RGBA extension */
+     FILE    *fp;
+     PICINFO *pinfo;
+     int      raw, maxv;
+{
+  byte *p, *pix, *pic24, *linebuf, scale[256], bgR, bgG, bgB, r, g, b, a;
+  int   i, j, bitshift, w, h, npixels, bufsize, linebufsize, holdmaxv;
+
+  w = pinfo->w;
+  h = pinfo->h;
+
+  npixels = w * h;
+  bufsize = 3*npixels;
+  linebufsize = 4*w;
+  if (w <= 0 || h <= 0 || npixels/w != h || bufsize/3 != npixels ||
+      linebufsize/4 != w)
+    return pbmError(bname, "image dimensions too large");
+
+  /* allocate 24-bit image */
+  pic24 = (byte *) calloc((size_t) bufsize, (size_t) 1);
+  if (!pic24) FatalError("couldn't malloc 'pic24' for PAM");
+
+  /* allocate line buffer for pre-composited RGBA data */
+  linebuf = (byte *) malloc((size_t) linebufsize);
+  if (!linebuf) {
+    free(pic24);
+    FatalError("couldn't malloc 'linebuf' for PAM");
+  }
+
+  pinfo->pic  = pic24;
+  pinfo->type = PIC24;
+  sprintf(pinfo->fullInfo, "PAM, %s format.  (%ld bytes)",
+	  (raw) ? "raw" : "ascii", filesize);
+  sprintf(pinfo->shrtInfo, "%dx%d PAM.", w, h);
+  pinfo->colType = F_FULLCOLOR;
+
+
+  /* if maxv>255, keep dropping bits until it's reasonable */
+  holdmaxv = maxv;
+  bitshift = 0;
+  while (maxv>255) { maxv = maxv>>1;  bitshift++; }
+
+
+  numgot = 0;
+
+  if (!raw) {					/* GRR:  not alpha-ready */
+    return pbmError(bname, "can't handle non-raw PAM image");
+/*
+    for (i=0, pix=pic24; i<h; i++) {
+      if ((i&0x3f)==0) WaitCursor();
+      for (j=0; j<w*3; j++, pix++)
+	*pix = (byte) (getint(fp, pinfo) >> bitshift);
+    }
+ */
+  }
+  else { /* raw */
+    if (holdmaxv>255) {				/* GRR:  not alpha-ready */
+      return pbmError(bname, "can't handle PAM image with maxval > 255");
+/*
+      for (i=0, pix=pic24; i<h; i++) {
+	if ((i&0x3f)==0) WaitCursor();
+	for (j=0; j<w*3; j++,pix++)
+	  *pix = (byte) (getshort(fp) >> bitshift);
+      }
+ */
+    }
+    else {
+      if (have_imagebg) {			/* GRR:  alpha-ready */
+        bgR = (imagebgR >> 8);
+        bgG = (imagebgG >> 8);
+        bgB = (imagebgB >> 8);
+      } else {
+        bgR = bgG = bgB = 0;
+      }
+      for (i=0, pix=pic24; i<h; i++) {
+        numgot += fread(linebuf, (size_t) 1, (size_t) linebufsize, fp);  /* read data */
+	if ((i&0x3f)==0) WaitCursor();
+	for (j=0, p=linebuf; j<w; j++) {
+          r = *p++;
+          g = *p++;
+          b = *p++;
+          a = *p++;
+          alpha_composite(*pix++, r, a, bgR)
+          alpha_composite(*pix++, g, a, bgG)
+          alpha_composite(*pix++, b, a, bgB)
+	}
+      }
+    }
+  }
+
+  free(linebuf);
+
+  /* in principle this could overflow, but not critical */
+  if (numgot != w*h*4) pbmError(bname, TRUNCSTR);
+
+  if (garbage)
+    return(pbmError(bname, "Garbage characters in image data."));
+
+
+  /* have to scale up all RGB values (Conv24to8 expects RGB values to
+     range from 0-255) */
+
+  if (maxv<255) {
+    for (i=0; i<=maxv; i++) scale[i] = (i * 255) / maxv;
+
+    for (i=0, pix=pic24; i<h; i++) {
+      if ((i&0x3f)==0) WaitCursor();
+      for (j=0; j<w*3; j++, pix++) *pix = scale[*pix];
+    }
+  }
+
+  return 1;
+}
+
+
 
 /*******************************************/
 static int getint(fp, pinfo)
diff -ruN xv-3.10a-bugfixes/xvpcd.c xv-3.10a-enhancements/xvpcd.c
--- xv-3.10a-bugfixes/xvpcd.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvpcd.c	2005-04-26 00:25:13.000000000 -0700
@@ -0,0 +1,1307 @@
+/*
+ * xvpcd.c - load routine for 'PhotoCD' format pictures
+ *
+ * LoadPCD(fname, pinfo, size)  -  loads a PhotoCD file
+ *
+ * This routine will popup a choice of which of the 5 available resolutions
+ * the user wants to choose, then load it as a 24 bit image.
+ *
+ * Copyright 1993 David Clunie, Melbourne, Australia.
+ *
+ * The outline of this is shamelessly derived from xvpbm.c to read the
+ * file, and xvtiffwr.c to handle the popup window and X stuff (X never
+ * has been my forte !), and the PhotoCD format information (though not
+ * the code) was found in Hadmut Danisch's (danisch@ira.uka.de) hpcdtoppm
+ * program in which he has reverse engineered the format by studying
+ * hex dumps of PhotoCDs ! After all who can afford the Kodak developer's
+ * kit, which none of us have seen yet ? Am I even allowed to mention these
+ * words (Kodak, PhotoCD) ? I presume they are registered trade marks.
+ *
+ * PS. I have no idea how Halmut worked out the YCC <-> RGB conversion
+ * factors, but I have calculated them from his tables and the results
+ * look good enough to me.
+ *
+ * Added size parameter to allow the schnautzer to create thumnails
+ * without requesting the size every time.
+ */
+
+#include "xv.h"
+#include <memory.h>
+
+#ifdef HAVE_PCD
+
+#define	TRACE	0
+#if TRACE
+#  define trace(x) fprintf x
+#else
+#  define trace(x)
+#endif
+
+/* Comments on error-handling:
+   A truncated file is not considered a Major Error.  The file is loaded,
+   and the rest of the pic is filled with 0's.
+
+   Not being able to malloc is a Fatal Error.  The program is aborted. */
+
+
+#ifdef __STDC__
+static void magnify(int, int, int, int, int, byte *);
+static int pcdError(char *, char *);
+static int gethuffdata(byte *, byte *, byte *, int, int);
+#else
+static void magnify();
+static int pcdError();
+static int gethuffdata();
+#endif
+
+#define wcurfactor 16	/* Call WaitCursor() every n rows */
+
+static int	size;	  /* Set by window routines */
+static int	leaveitup;/* Cleared by docmd() when OK or CANCEL pressed */
+static int	goforit;  /* Set to 1 if OK or 0 if CANCEL */
+static FILE	*fp;
+static CBUTT  lutCB;
+
+/*
+ * This "beyond 100%" table is taken from ImageMagick (gamma 2.2).
+ * Why there are 351 entries and not 346 as per Kodak documentation
+ * is a mystery.
+ */
+static	double	rscale = 1.00,
+		gscale = 1.00,
+		bscale = 1.00;
+
+static	byte	Y[351] = {
+	  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
+	 10,  11,  12,  13,  14,  15,  16,  17,  18,  19,
+	 20,  21,  22,  23,  24,  25,  26,  27,  28,  29,
+	 30,  32,  33,  34,  35,  36,  37,  38,  39,  40,
+	 41,  42,  43,  45,  46,  47,  48,  49,  50,  51,
+	 52,  53,  54,  56,  57,  58,  59,  60,  61,  62,
+	 63,  64,  66,  67,  68,  69,  70,  71,  72,  73,
+	 74,  76,  77,  78,  79,  80,  81,  82,  83,  84,
+	 86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
+	 97,  98,  99, 100, 101, 102, 103, 104, 105, 106,
+	107, 108, 110, 111, 112, 113, 114, 115, 116, 117,
+	118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+	129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
+	139, 140, 141, 142, 143, 144, 145, 146, 147, 148,
+	149, 150, 151, 152, 153, 154, 155, 156, 157, 158,
+	159, 160, 161, 162, 163, 164, 165, 166, 167, 168,
+	169, 170, 171, 172, 173, 174, 175, 176, 176, 177,
+	178, 179, 180, 181, 182, 183, 184, 185, 186, 187,
+	188, 189, 190, 191, 192, 193, 193, 194, 195, 196,
+	197, 198, 199, 200, 201, 201, 202, 203, 204, 205,
+	206, 207, 207, 208, 209, 210, 211, 211, 212, 213,
+	214, 215, 215, 216, 217, 218, 218, 219, 220, 221,
+	221, 222, 223, 224, 224, 225, 226, 226, 227, 228,
+	228, 229, 230, 230, 231, 232, 232, 233, 234, 234,
+	235, 236, 236, 237, 237, 238, 238, 239, 240, 240,
+	241, 241, 242, 242, 243, 243, 244, 244, 245, 245,
+	245, 246, 246, 247, 247, 247, 248, 248, 248, 249,
+	249, 249, 249, 250, 250, 250, 250, 251, 251, 251,
+	251, 251, 252, 252, 252, 252, 252, 253, 253, 253,
+	253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
+	254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
+	254, 254, 254, 254, 254, 254, 254, 254, 254, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255
+};
+
+/*******************************************/
+/* The size should be -1 for the popup to ask otherwise fast is assumed */
+/* returns '1' on success */
+/*******************************************/
+int
+LoadPCD(char *fname, PICINFO *pinfo, int theSize)
+{
+  long   offset;
+  int    mag;
+  int	 rotate;
+  byte	 header[3*0x800];
+  byte	*pic24, *luma, *chroma1, *chroma2, *ptr, *lptr, *c1ptr, *c2ptr;
+  int   w, h, npixels, bufsize;
+  int   row, col;
+	int	huffplanes;
+	char	*bname;
+
+	bname		= BaseName(fname);
+	pinfo->pic	= NULL;
+	pinfo->comment	= NULL;
+
+
+	/*
+	 *  open the file
+	 */
+	if((fp=fopen(fname,"r")) == NULL)
+		return pcdError(bname, "can't open file");
+
+	/*
+	 * inspect the header
+	 */
+	if(fread(&header[0], 1, sizeof(header), fp) != sizeof(header))
+		return pcdError(bname, "could not load PCD header");
+	if(strncmp(&header[0x800], "PCD_", 4) != 0)
+		return pcdError(bname, "not a PCD file");
+	rotate = header[0x0E02] & 0x03;
+
+/* base/16
+	- plain data starts at sector 1+2+1=4
+	  (numbered from 0, ie. the 5th sector)
+	- luma 192*128 = 24576 bytes (12 sectors)
+	  + chroma1 96*64 = 6144 bytes (3 sectors)
+	  + chroma2 96*64 = 6144 bytes (3 sectors)
+	  = total 18 sectors
+
+	- NB. "Plain" data is interleaved - 2 luma rows 192 wide,
+	  then 1 of each of the chroma rows 96 wide !
+
+   base/4
+	- plain data starts at sector 1+2+1+18+1=23
+	- luma 384*256 = 98304 bytes (48 sectors)
+	  + chroma1 192*128 = 24576 bytes (12 sectors)
+	  + chroma2 192*128 = 24576 bytes (12 sectors)
+	  = total 72 sectors
+
+	- NB. "Plain" data is interleaved - 2 luma rows 384 wide,
+	  then 1 of each of the chroma rows 192 wide !
+
+   base
+	- plain data starts at sector 1+2+1+18+1+72+1=96
+
+	- luma 768*512 = 393216 bytes (192 sectors)
+	  + chroma1 384*256 = 98304 bytes (48 sectors)
+	  + chroma2 384*256 = 98304 bytes (48 sectors)
+	  = total 288 sectors
+
+	- NB. "Plain" data is interleaved - 2 luma rows 768 wide,
+	  then 1 of each of the chroma rows 384 wide !
+
+   4base
+	- plain data for base is read
+	- luma data interpolated *2
+	- chroma data interpolated *4
+
+	- cd_offset is 1+2+1+18+1+72+1+288=384
+	- at cd_offset+4 (388) is huffman table
+	- at cd_offset+5 (389) is 4base luma plane
+
+	(the sector at cd_offset+3 seems to contain 256 words each of
+	which is an offset presumably to the sector containing certain
+	rows ? rows/4 given 1024 possible rows. The rest of this sector
+	is filled with zeroes)
+
+
+   16base
+	- plain data for base is read
+	- luma data interpolated *2
+	- chroma data interpolated *4
+
+	- cd_offset is 1+2+1+18+1+72+1+288=384
+	- at cd_offset+4 (388) is huffman table for 4 base
+	- at cd_offset+5 (389) is 4base luma plane
+	- luma plane interpolated *2
+
+	- cd_offset is set to current position (should be start of sector)
+	- at cd_offset+12 is huffman table for 16 base
+	- at cd_offset+14 is 16 base luma & 2 chroma planes which are read
+          (note that the luma plane comes first, with a sync pattern
+           announcing each row from 0 to 2047, then the two chroma planes
+           are interleaved by row, the row # being even from 0 to 2046, with
+           each row containing 1536 values, the chroma1 row coming first,
+           finally followed by a sync pattern with a row of 2048 announcing
+           the end (its plane seems to be set to 3, ie. chroma2)
+	- chroma planes interpolated *2
+
+	(the sector at cd_offset+10 & 11 seem to contain 1024 pairs of words
+        the first for luma and the second for chroma, each of
+	which is an offset presumably to the sector containing certain
+	rows ? rows/2 given 2048 possible rows)
+
+Not yet implemented:
+
+In order to do overskip for base and 4base, one has to reach the chroma
+data for 16 base:
+
+	- for 4base, after reading the 4base luma plane (and presumably
+	  skipping the chroma planes) one sets cd_offset to the start of
+	  the "current" sector
+
+	- for base, one has to skip the 4base data first:
+	- cd_offset is set to 384
+	- at (cd_offset+3 sectors)[510] is a 16 bit word high byte 1st
+	  containing an offset to the beginning of the 16base stuff
+	  though there is then a loop until >30 0xff's start a sector !
+
+	- being now positioned after the end of the 4base stuff,
+	- at (cd_offset+10 sectors)[2] is a 16 bit word high byte 1st
+	  containing an offset to the chroma planes.
+	- at cd_offset+12 is the set of huffman tables
+
+	- for base, the 16base chroma planes are then halved
+*/
+
+  PCDSetParamOptions(bname);
+  if (theSize == -1)
+  {
+    PCDDialog(1);                   /* Open PCD Dialog box */
+    SetCursors(-1);                 /* Somebody has already set it to wait :( */
+    leaveitup=1;
+    goforit=0;
+	size = 1;
+    /* block until the popup window gets closed */
+    while (leaveitup) {
+      int i;
+      XEvent event;
+      XNextEvent(theDisp, &event);
+      HandleEvent(&event, &i);
+    }
+    /* At this point goforit and size will have been set */
+    if (!goforit) {
+      /* nothing allocated so nothing needs freeing */
+      return 0;
+    }
+    WaitCursor();
+  }
+  else
+  {
+    size = theSize;
+    goforit = 1;
+  }
+
+	if(lutCB.val)
+		rscale = gscale = bscale = 255.0/346.0;
+	else
+		rscale = gscale = bscale = 1.0;
+
+	switch (size) {
+	case 0:
+		pinfo->w = 192;
+		pinfo->h = 128;
+		offset=4*0x800;
+		mag=1;
+		huffplanes=0;
+		sprintf(pinfo->fullInfo, "PhotoCD, base/16 resolution");
+		break;
+
+	case 1:
+		pinfo->w = 384;
+		pinfo->h = 256;
+		offset=23*0x800;
+		mag=1;
+		huffplanes=0;
+		sprintf(pinfo->fullInfo, "PhotoCD, base/4 resolution");
+		break;
+
+	case 2:
+	default:
+		pinfo->w = 768;
+		pinfo->h = 512;
+		offset=96*0x800;
+		mag=1;
+		huffplanes=0;
+		sprintf(pinfo->fullInfo, "PhotoCD, base resolution");
+		break;
+
+	case 3:
+		pinfo->w = 1536;
+		pinfo->h = 1024;
+		offset=96*0x800;
+		mag=2;
+		huffplanes=1;
+		sprintf(pinfo->fullInfo, "PhotoCD, 4base resolution");
+		break;
+
+	case 4:
+		pinfo->w=3072;
+		pinfo->h=2048;
+		offset=96*0x800;
+		mag=4;
+		huffplanes=2;
+		sprintf(pinfo->fullInfo, "PhotoCD, 16base resolution");
+		break;
+	}
+
+	/*
+	 * rotate?
+	 */
+	w = pinfo->w;
+	h = pinfo->h;
+	switch(rotate) {
+	case	0:
+		break;
+
+	case	1:
+	case	3:
+		pinfo->w = h;
+		pinfo->h = w;
+		break;
+
+	default:
+		fprintf(stderr, "unknown image rotate %d; assuming none\n",
+			rotate);
+		rotate = 0;
+	}
+
+	/*
+	 * allocate 24-bit image
+	 */
+	npixels = pinfo->w * pinfo->h;
+	bufsize = 3 * npixels;
+	if (pinfo->w <= 0 || pinfo->h <= 0 || npixels/pinfo->w != pinfo->h ||
+	    bufsize/3 != npixels)
+		FatalError("image dimensions out of range");
+
+	pinfo->pic = (byte *)malloc((size_t) bufsize);
+	if(!pinfo->pic)
+		FatalError("couldn't malloc '24-bit RGB plane'");
+
+	pinfo->type = PIC24;
+	sprintf(pinfo->shrtInfo, "%dx%d PhotoCD.", pinfo->w, pinfo->h);
+	pinfo->colType = F_FULLCOLOR;
+	pinfo->frmType = -1;
+
+	if(fseek(fp, offset, SEEK_SET) == -1) {
+		free(pinfo->pic);
+		return pcdError(bname,"Can't find start of data.");
+	}
+
+	pic24 = pinfo->pic;
+
+	luma=(byte *)calloc(npixels,1);
+	if(!luma) {
+		free(pinfo->pic);
+		FatalError("couldn't malloc 'luma plane'");
+	}
+
+	chroma1=(byte *)calloc(npixels/4,1);
+	if(!chroma1) {
+		free(pinfo->pic);
+		free(luma);
+		FatalError("couldn't malloc 'chroma1 plane'");
+	}
+
+	chroma2=(byte *)calloc(npixels/4,1);
+	if(!chroma2) {
+		free(pinfo->pic);
+		free(luma);
+		free(chroma1);
+		FatalError("couldn't malloc 'chroma2 plane'");
+	}
+
+	/* Read 2 luma rows length w, then one of each chroma rows w/2 */
+	/* If a mag factor is active, the small image is read into the */
+	/* top right hand corner of the larger allocated image */
+
+	trace((stderr, "base image: start @ 0x%08lx (sector %ld.%ld)\n",
+				ftell(fp), ftell(fp)/0x800, ftell(fp) % 0x800));
+	for(row=0,lptr=luma,c1ptr=chroma1,c2ptr=chroma2; row <h/mag;
+				row+=2,lptr+=w*2,c1ptr+=w/2,c2ptr+=w/2) {
+		if(fread(lptr, 1, w/mag, fp) != w/mag) {
+			pcdError(bname, "Luma plane too short.");
+			break;
+		}
+		if(fread(lptr+w, 1, w/mag, fp) != w/mag) {
+			pcdError(bname, "Luma plane too short.");
+			break;
+		}
+		if(fread(c1ptr, 1, w/2/mag, fp) != w/2/mag) {
+			pcdError(bname, "Chroma1 plane too short.");
+			break;
+		}
+		if(fread(c2ptr, 1, w/2/mag, fp) != w/2/mag) {
+			pcdError(bname, "Chroma2 plane too short.");
+			break;
+		}
+		if(row%wcurfactor == 0)
+			WaitCursor();
+	}
+	trace((stderr, "base image: done @ 0x%08lx (sector %ld.%ld)\n",
+				ftell(fp), ftell(fp)/0x800, ftell(fp) % 0x800));
+
+	if(huffplanes) {
+		if(fseek(fp, 388*0x800, SEEK_SET) == -1)
+			return pcdError(bname,
+					"Can't find start of huffman tables.");
+
+		magnify(2, h/mag, w/mag, h, w, luma);
+		magnify(2, h/2/mag, w/2/mag, h/2, w/2, chroma1);
+		magnify(2, h/2/mag, w/2/mag, h/2, w/2, chroma2);
+
+		/*
+		 * doesn't really touch the chroma planes which aren't
+		 * present in 4base
+		 */
+		gethuffdata(luma, chroma1, chroma2, w, h/mag*2);
+
+		/*
+		 * if only doing 4base should probably fetch 16bases
+		 * chroma planes here
+		 */
+		if(huffplanes == 2) {
+			/*
+			 * This depends on gethuffdata() having grabbed
+			 * things in 0x800 sectors AND still being
+			 * positioned in the "last" sector of the data
+			 * (cf. Hadmut's code which is positioned at start
+			 * of the next sector)
+			 */
+			long	offset = ftell(fp)/0x800+12;
+
+			if(fseek(fp, offset*0x800, SEEK_SET) == 0) {
+				magnify(2,h/2,w/2,h,w,luma);
+				magnify(2,h/4,w/4,h/2,w/2,chroma1);
+				magnify(2,h/4,w/4,h/2,w/2,chroma2);
+				gethuffdata(luma,chroma1,chroma2,w,h);
+			} else
+				fprintf(stderr, "can't seek to 2nd huffman tables\n");
+		}
+	}
+	fclose(fp);
+
+	/*
+	 * YCC -> R'G'B' and image rotate
+	 */
+	ptr=pic24;
+	lptr=luma; c1ptr=chroma1; c2ptr=chroma2;
+	for(row = 0; row < h; ++row) {
+		byte	*rowc1ptr = c1ptr,
+			*rowc2ptr = c2ptr;
+		int	k = 0;
+
+		switch(rotate) {
+		case	1:
+			ptr = &pic24[row*3 + (w - 1)*h*3];
+			  k = -3*(h + 1);
+			break;
+
+		case	3:
+			ptr = &pic24[(h - 1 - row)*3];
+			  k =  3*(h - 1);
+			break;
+
+		default:
+			ptr = &pic24[row*w*3];
+			  k = 0;
+			break;
+		}
+		for(col = 0; col < w; ++col) {
+			double	L	= 1.3584*(double) *lptr++,
+				C1	= 2.2179*(double) (*c1ptr - 156),
+				C2	= 1.8215*(double) (*c2ptr - 137);
+			int	r	= rscale*(L + C2),
+				g	= gscale*(L - 0.194*C1 - 0.509*C2),
+				b	= bscale*(L + C1);
+
+			if(lutCB.val) {
+				if(r < 0) r = 0; else if(r >= 255) r = 255;
+				if(g < 0) g = 0; else if(g >= 255) g = 255;
+				if(b < 0) b = 0; else if(b >= 255) b = 255;
+			} else {
+				if(r < 0) r = 0; else if(r >= 351) r = 350;
+				if(g < 0) g = 0; else if(g >= 351) g = 350;
+				if(b < 0) b = 0; else if(b >= 351) b = 350;
+				r = Y[r]; g = Y[g]; b = Y[b];
+			}
+			*ptr++ = r;
+			*ptr++ = g;
+			*ptr++ = b;
+			ptr   += k;
+			if(col & 1) {
+				++c1ptr;
+				++c2ptr;
+			}
+		}
+		if((row & 1) == 0) {
+			c1ptr = rowc1ptr;
+			c2ptr = rowc2ptr;
+		}
+		if(row%wcurfactor == 0)
+			WaitCursor();
+	}
+	free(luma); free(chroma1); free(chroma2);
+	return 1;
+}
+
+/*
+ * derived from Hadmut Danisch's interpolate()
+ */
+static void
+magnify(int mag,	/* power of 2 by which to magnify in place */
+	int h, int w,	/* the "start" unmag'd dimensions of the array */
+	int mh, int mw,	/* the real (maximum) dimensions of the array */
+	byte *p)	/* pointer to the data */
+{
+  int x,y,yi;
+  byte *optr,*nptr,*uptr;  /* MUST be unsigned, else averaging fails */
+
+  while (mag > 1) {
+
+    /* create every 2nd new row from 0 */
+    /*  even pixels being equal to the old, odd ones averaged with successor */
+    /*  special case being the last column which is just set equal to the */
+    /*  second last) ... */
+
+    for(y=0;y<h;y++) {
+      yi=h-1-y;
+      optr=p+  yi*mw + (w-1);	          /* last pixel of an old row */
+      nptr=p+2*yi*mw + (2*w - 2);         /* last pixel of a new row */
+
+      nptr[0]=nptr[1]=optr[0];            /* special cases */
+
+      for(x=1;x<w;x++) {
+        optr--; nptr-=2;                  /* next lower pixel(s) */
+        nptr[0]=optr[0];                  /* even pixels duped */
+        nptr[1]=(((int)optr[0])+
+                 ((int)optr[1])+1)>>1;    /* odd averaged */
+      }
+    }
+
+    /* Fill in odd rows, as average of prior & succeeding rows, with */
+    /* even pixels average of one column, odd pixels average of two */
+
+    for(y=0;y<h-1;y++) {                  /* all but the last old row */
+      optr=p + 2*y*mw;                    /* start of the new "even" rows */
+      nptr=optr+mw;                       /* start of the next empty row */
+      uptr=nptr+mw;                       /* start of the next again (even) */
+
+      for(x=0;x<w-1;x++) {                /* for all cols except the last */
+        nptr[0]=(((int)optr[0])+
+                 ((int)uptr[0])+1)>>1;    /* even pixels */
+        nptr[1]=(((int)optr[0])+
+                 ((int)optr[2])+
+                 ((int)uptr[0])+
+                 ((int)uptr[2])+2)>>2;    /* odd pixels */
+        nptr+=2; optr+=2; uptr+=2;
+      }
+      *(nptr++)=(((int)*(optr++))+
+                 ((int)*(uptr++))+1)>>1;  /* 2nd last pixel */
+      *(nptr++)=(((int)*(optr++))+
+                 ((int)*(uptr++))+1)>>1;  /* last pixel */
+    }
+
+    xvbcopy(p + (2*h-2)*mw,                 /* 2nd last row */
+          p + (2*h-1)*mw,                 /* the last row */
+          2*w);                           /* length of a new row */
+
+    h*=2; w*=2;
+    mag>>=1;	/* Obviously mag must be a power of 2 ! */
+  }
+}
+
+/*******************************************/
+static int
+pcdError(char *fname, char *st)
+{
+  SetISTR(ISTR_WARNING,"%s:  %s", fname, st);
+  return 0;
+}
+
+
+/**** Stuff for PCDDialog box ****/
+
+#define TWIDE 380
+#define THIGH 160
+#define T_NBUTTS 2
+#define T_BOK    0
+#define T_BCANC  1
+#define BUTTH    24
+
+static void drawTD    PARM((int, int, int, int));
+static void clickTD   PARM((int, int));
+static void doCmd     PARM((int));
+static void PCDSetParams PARM((void));
+
+/* local variables */
+static BUTT  tbut[T_NBUTTS];
+static RBUTT *resnRB;
+
+
+
+/***************************************************/
+void CreatePCDW()
+{
+  int	     y;
+
+  pcdW = CreateWindow("xv pcd", "XVpcd", NULL,
+		       TWIDE, THIGH, infofg, infobg, 0);
+  if (!pcdW) FatalError("can't create pcd window!");
+
+  XSelectInput(theDisp, pcdW, ExposureMask | ButtonPressMask | KeyPressMask);
+
+  BTCreate(&tbut[T_BOK], pcdW, TWIDE-140-1, THIGH-10-BUTTH-1, 60, BUTTH,
+	   "Ok", infofg, infobg, hicol, locol);
+
+  BTCreate(&tbut[T_BCANC], pcdW, TWIDE-70-1, THIGH-10-BUTTH-1, 60, BUTTH,
+	   "Cancel", infofg, infobg, hicol, locol);
+
+  y = 55;
+  resnRB = RBCreate(NULL, pcdW, 36, y,   "192*128   Base/16",
+           infofg, infobg,hicol,locol);
+  RBCreate(resnRB, pcdW, 36, y+18,       "384*256   Base/4",
+           infofg, infobg,hicol,locol);
+  RBCreate(resnRB, pcdW, 36, y+36,       "768*512   Base",
+           infofg, infobg, hicol, locol);
+  RBCreate(resnRB, pcdW, TWIDE/2, y,     "1536*1024 4Base",
+           infofg, infobg, hicol, locol);
+  RBCreate(resnRB, pcdW, TWIDE/2, y+18,  "3072*2048 16Base",
+           infofg, infobg, hicol, locol);
+
+  CBCreate(&lutCB, pcdW, TWIDE/2, y+36,  "Linear LUT",
+           infofg, infobg, hicol, locol);
+
+  RBSelect(resnRB, 2);
+
+  XMapSubwindows(theDisp, pcdW);
+}
+
+
+/***************************************************/
+void PCDDialog(vis)
+int vis;
+{
+  if (vis) {
+    CenterMapWindow(pcdW, tbut[T_BOK].x + tbut[T_BOK].w/2,
+		    tbut[T_BOK].y + tbut[T_BOK].h/2, TWIDE, THIGH);
+  }
+  else     XUnmapWindow(theDisp, pcdW);
+  pcdUp = vis;
+}
+
+
+/***************************************************/
+int PCDCheckEvent(xev)
+XEvent *xev;
+{
+  /* check event to see if it's for one of our subwindows.  If it is,
+     deal accordingly, and return '1'.  Otherwise, return '0' */
+
+  int rv;
+  rv = 1;
+
+  if (!pcdUp) return 0;
+
+  if (xev->type == Expose) {
+    int x,y,w,h;
+    XExposeEvent *e = (XExposeEvent *) xev;
+    x = e->x;  y = e->y;  w = e->width;  h = e->height;
+
+    if (e->window == pcdW)       drawTD(x, y, w, h);
+    else rv = 0;
+  }
+
+  else if (xev->type == ButtonPress) {
+    XButtonEvent *e = (XButtonEvent *) xev;
+    int x,y;
+    x = e->x;  y = e->y;
+
+    if (e->button == Button1) {
+      if      (e->window == pcdW)     clickTD(x,y);
+      else rv = 0;
+    }  /* button1 */
+    else rv = 0;
+  }  /* button press */
+
+
+  else if (xev->type == KeyPress) {
+    XKeyEvent *e = (XKeyEvent *) xev;
+    char buf[128];  KeySym ks;  XComposeStatus status;
+    int stlen;
+
+    stlen = XLookupString(e,buf,128,&ks,&status);
+    buf[stlen] = '\0';
+
+    RemapKeyCheck(ks, buf, &stlen);
+
+    if (e->window == pcdW) {
+      if (stlen) {
+	if (buf[0] == '\r' || buf[0] == '\n') { /* enter */
+	  FakeButtonPress(&tbut[T_BOK]);
+	}
+	else if (buf[0] == '\033') {            /* ESC */
+	  FakeButtonPress(&tbut[T_BCANC]);
+	}
+      }
+    }
+    else rv = 0;
+  }
+  else rv = 0;
+
+  if (rv==0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
+    XBell(theDisp, 50);
+    rv = 1;   /* eat it */
+  }
+
+  return rv;
+}
+
+
+/***************************************************/
+void
+PCDSetParamOptions(char *fname)
+{
+  int cur;
+  cur = RBWhich(resnRB);
+
+  RBSetActive(resnRB,0,1);
+  RBSetActive(resnRB,1,1);
+  RBSetActive(resnRB,2,1);
+  RBSetActive(resnRB,3,1);
+  RBSetActive(resnRB,4,1);
+  CBSetActive(&lutCB,1);
+}
+
+
+/***************************************************/
+static void
+drawTD(int x, int y, int w, int h)
+{
+  char *title  = "Load PhotoCD file...";
+  int  i;
+  XRectangle xr;
+
+  xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
+  XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
+
+  XSetForeground(theDisp, theGC, infofg);
+  XSetBackground(theDisp, theGC, infobg);
+
+  for (i=0; i<T_NBUTTS; i++) BTRedraw(&tbut[i]);
+
+  ULineString(pcdW, resnRB->x-16, resnRB->y-10-DESCENT, "Resolution");
+  RBRedraw(resnRB, -1);
+  CBRedraw(&lutCB);
+
+  XDrawString(theDisp, pcdW, theGC, 20, 19, title, strlen(title));
+
+  XSetClipMask(theDisp, theGC, None);
+}
+
+
+/***************************************************/
+static void clickTD(x,y)
+int x,y;
+{
+  int i;
+  BUTT *bp;
+
+  /* check BUTTs */
+
+  /* check the RBUTTS first, since they don't DO anything */
+  if ( (i=RBClick(resnRB, x,y)) >= 0) {
+    (void) RBTrack(resnRB, i);
+    return;
+  }
+
+  if(CBClick(&lutCB, x, y)) {
+    (void) CBTrack(&lutCB);
+    return;
+  }
+
+  for (i=0; i<T_NBUTTS; i++) {
+    bp = &tbut[i];
+    if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
+  }
+
+  if (i<T_NBUTTS) {  /* found one */
+    if (BTTrack(bp)) doCmd(i);
+  }
+}
+
+
+
+/***************************************************/
+static void doCmd(cmd)
+int cmd;
+{
+  leaveitup=0;
+  goforit=0;
+  switch (cmd) {
+  case T_BOK:  	PCDSetParams();
+                goforit=1;
+  case T_BCANC:	PCDDialog(0);
+                break;
+
+  default:	break;
+  }
+}
+
+
+/*******************************************/
+static void PCDSetParams()
+{
+  switch (RBWhich(resnRB)) {
+  case 0: size = 0;      break;
+  case 1: size = 1;      break;
+  case 2: size = 2;      break;
+  case 3: size = 3;      break;
+  case 4: size = 4;      break;
+  case 5: size = 0;      break;
+  default: size = 0;     break;
+  }
+}
+
+/*
+ * Read the Huffman tables which consist of an unsigned byte # of entries
+ * (less 1) followed by up to 256 entries, each of which is a series of 4
+ * unsigned bytes - length, highseq, lowseq, and key.
+ *
+ * Store the huffman table into tree type structure:
+ *
+ * 	int int[n of entries*2]
+ *
+ * Each entry consists of two words (the 1st for zero and the 2nd for one).
+ *
+ * If the word is negative, then subtract it from the current pointer to
+ * get the next entry (ie. it is the negative offset from the current
+ * position*2 in order to skip entries not words) with which to
+ * make a decision.
+ *
+ * If the word is not negative, then the low 8 bits contain the value (which
+ * is supposed to be a signed char) and the rest of the word is zero.
+ */
+static void
+dumphufftab(int n, const byte *h, int m, const int *t)
+{
+	int	j;
+
+	for(j = 0; j < n || j < m; ++j) {
+		if(j < m)
+			fprintf(stderr, "%04x %04x ::", 0xffff & t[2*j + 0],
+							 0xffff & t[2*j + 1]);
+		else
+			fprintf(stderr, "%s %s ::", "    ", "    ");
+		if(j < n) {
+			int	 k;
+			unsigned l = (h[4*j + 1] << 8) | h[4*j + 2];
+
+			fprintf(stderr, " %02x %2d ", h[4*j + 3], h[4*j + 0]);
+			for(k = 0; k <= h[4*j + 0]; ++k, l *= 2)
+				fprintf(stderr, "%c", '0'+((l & 0x8000) != 0));
+		}
+		fprintf(stderr, "\n");
+	}
+}
+
+static int *
+gethufftable(void)
+{
+	int	*hufftab, *h, i, j, N, num, bufsize, huffptr, hufftop;
+	byte	*huf;
+
+	/*
+	 * absorb the entirety of the table in one chunk (for better
+	 * dumps in case of error)
+	 */
+	trace((stderr, "hufftab 0x%08lx ", ftell(fp)));
+	num = 1 + fgetc(fp);   /* 256 max */
+	huf = (byte *)alloca(4*num*sizeof(byte));
+	if((i = fread(huf, 1, 4*num, fp)) != 4*num) {
+		fprintf(stderr, "unexpected EOF: got %d bytes, wanted %d\n",
+								i, 4*num);
+		return NULL;
+	}
+
+	/*
+	 * guess an initial size and prepare the initial entry
+	 */
+	trace((stderr, "length %u\n", num));
+	N = 2*num;   /* 512 max */
+	bufsize = N * sizeof(int);
+/*	this case can't happen, but added for symmetry with loop below
+	if (N/2 != num || bufsize/N != sizeof(int)) {
+		SetISTR(ISTR_WARNING, "Huffman table size out of range");
+		return NULL;
+	}
+ */
+	if((hufftab = (int *)malloc(bufsize)) == NULL)
+		FatalError("couldn't malloc initial Huffman table");
+	hufftab[0] = hufftab[1] = 0;
+
+	/*
+	 * we check the table for reasonableness;  there is a lack of detailed
+	 * documentation on this format.  in particular, for the base16,
+	 * the position of the huffman tables is uncertain to within one
+	 * "sector", and we have to detect his before trying to read
+	 * bogusness.
+	 */
+	hufftop = 0;
+	for(i = 0; i < num; ++i) {
+		unsigned length   =  huf[4*i + 0],
+			 codeword = (huf[4*i + 1] << 8) | huf[4*i + 2];
+
+		/*
+		 * some sanity checks
+		 */
+		if(length >= 16) {
+			fprintf(stderr,
+				"gethufftable: improbable length @ %d/%d\n",
+					i, num);
+			dumphufftab(num, huf, hufftop/2, hufftab);
+			free(hufftab);
+			return NULL;
+		}
+
+		/*
+		 * walk the whole set of codes
+		 */
+		huffptr = 0;
+		for(j = 0; j < 16; ++j, codeword *= 2) {
+			/*
+			 * choose the child node
+			 */
+			if(codeword & 0x8000)
+				++huffptr;
+
+			/*
+			 * store value at end-of-code
+			 */
+			if(j == length) {
+				/*
+				 * more sanity
+				 */
+				if((codeword *= 2) & 0xffff) {
+					fprintf(stderr,
+						"gethufftable: "
+						":probable invalid code @ %d\n",
+							i);
+					dumphufftab(num, huf,
+							hufftop/2, hufftab);
+					free(hufftab);
+					return NULL;
+				}
+				hufftab[huffptr] = 1 + (int) huf[4*i + 3];
+				break;
+			}
+
+			/*
+			 * otherwise, follow the tree to date
+			 */
+			if(hufftab[huffptr] < 0) {
+				huffptr -= hufftab[huffptr];
+				continue;
+			} else if(hufftab[huffptr] > 0) {
+				fprintf(stderr, "duplicate code %d %d/%d\n",
+					huffptr, i, num);
+				dumphufftab(num, huf, hufftop/2, hufftab);
+				free(hufftab);
+				return NULL;
+			}
+
+			/*
+			 * and if necessary, make the tree bigger
+			 */
+			if((hufftop += 2) >= N) {
+				int oldN = N;
+#if TRACE
+				dumphufftab(num, huf, hufftop/2, hufftab);
+#endif
+				N *= 2;
+				bufsize = N*sizeof(int);
+				if (N/2 != oldN || bufsize/N != sizeof(int)) {
+					SetISTR(ISTR_WARNING,
+					  "new Huffman table is too large");
+					free(hufftab);
+					return NULL;
+				}
+				h = (int *)realloc(hufftab, bufsize);
+				if(h == NULL) {
+					fprintf(stderr,
+						"Table overflow %d/%d\n",
+								 i, num);
+					dumphufftab(num, huf,
+							hufftop/2, hufftab);
+					free(hufftab);
+					FatalError(
+					  "couldn't realloc Huffman table");
+				}
+				hufftab = h;
+			}
+
+			/*
+			 * then add new ptr
+			 */
+			hufftab[huffptr] = huffptr - hufftop;
+			huffptr = hufftop;
+			hufftab[huffptr + 0] =
+			hufftab[huffptr + 1] = 0;
+		}
+	}
+	return hufftab;
+}
+
+/* WORDTYPE & char buffer must be unsigned else */
+/* fills with sign bit not 0 on right shifts */
+typedef unsigned int WORDTYPE;
+typedef int SWORDTYPE;
+#define WORDSIZE sizeof(WORDTYPE)
+#define NBYTESINBUF 0x800
+
+static byte buffer[NBYTESINBUF];
+static int bitsleft=0;
+static int bytesleft=0;
+static byte *bufptr;
+static WORDTYPE word;
+
+#if 0
+static void
+dumpbuffer(void)
+{
+  int i,left;
+  byte *ptr=buffer;
+
+  fprintf(stderr,"dumpbuffer: bytesleft=%d bitsleft= %d word=0x%08lx\n",
+    bytesleft,bitsleft,(unsigned long)word);
+  for (left=NBYTESINBUF; left>0; left-=16) {
+    fprintf(stderr,"%05d  ",left);
+    for (i=0; i<8; i++) {
+      fprintf(stderr,"%02x",*ptr++);
+      fprintf(stderr,"%02x ",*ptr++);
+    }
+    fprintf(stderr,"\n");
+  }
+}
+#endif /* 0 */
+
+static void
+loadbuffer(void)
+{
+  if ((bytesleft=fread(buffer,1,NBYTESINBUF,fp)) == 0) {
+    fprintf(stderr,"Truncation error\n");
+    exit(1);
+  }
+  bufptr=buffer;
+  /* dumpbuffer(); */
+}
+
+static void
+loadbyte(void)
+{
+  if (bytesleft <= 0) loadbuffer();
+  --bytesleft;
+  word|=(WORDTYPE)(*bufptr++)<<(sizeof(WORDTYPE)*8-8-bitsleft);
+  bitsleft+=8;
+}
+
+static int
+getbit(void)
+{
+  int bit;
+
+  while (bitsleft <= 0) loadbyte();
+  --bitsleft;
+  bit=(SWORDTYPE)(word)<0;  /* assumes word is signed */
+  /* bit=word>>(sizeof(WORDTYPE)*8-1); */
+  word<<=1;
+  return bit;
+}
+
+static WORDTYPE
+getnn(int nn)
+{
+  WORDTYPE value;
+
+  while (bitsleft <= nn) loadbyte();
+  bitsleft-=nn;
+  value=word>>(sizeof(WORDTYPE)*8-nn);
+  word<<=nn;
+  return value;
+}
+
+static WORDTYPE
+isnn(int nn)
+{
+  WORDTYPE value;
+
+  while (bitsleft <= nn) loadbyte();
+  value=word>>(sizeof(WORDTYPE)*8-nn);
+  return value;
+}
+
+static void
+skipnn(int nn)
+{
+  while (bitsleft <= nn) loadbyte();
+  bitsleft-=nn;
+  word<<=nn;
+}
+
+#define get1()    (getbit())
+#define get2()    (getnn(2))
+#define get8()    (getnn(8))
+#define get13()    (getnn(13))
+#define get16()    (getnn(16))
+#define get24()    (getnn(24))
+
+#define is24()    (isnn(24))
+
+#define skip1()    (skipnn(1))
+#define skip24()  (skipnn(24))
+
+static int
+gethuffdata(	byte *luma,
+		byte *chroma1,
+		byte *chroma2,
+		int realrowwidth,
+		int maxrownumber)
+{
+static	byte	clip[3*256];
+	int	*hufftable[3], *huffstart = NULL, *huffptr = NULL;
+	int	row, col, plane, i, result = 1;
+#if TRACE
+	int	uflow = 0, oflow = 0;
+#endif
+	byte	*pixelptr = NULL;
+
+	trace((stderr,"gethuffdata: start @ 0x%08lx (sector %ld.%ld)\n",
+			ftell(fp), ftell(fp)/0x800, ftell(fp) % 0x800));
+
+	/*
+	 * correction clipping
+	 */
+	if(clip[256+255] == 0) {
+		for(i = 0; i < 256; ++i)
+			clip[i +   0] = 0x00,
+			clip[i + 256] = (byte) i,
+			clip[i + 512] = 0xff;
+	}
+
+	/*
+	 * should really only look for luma plane for 4base, but the
+	 * there are zeroes in the rest of the sector that give both
+	 * chroma tables 0 length
+	 */
+	for(i = 0; i < 3; ++i)
+		hufftable[i] = NULL;
+	for(i = 0; i < 3; ++i) {
+		if((hufftable[i] = gethufftable()) == NULL) {
+			result = 0;
+			break;
+		}
+	}
+	if(result == 0)
+		goto oops;
+
+	/*
+	 * skip remainder of current sector
+	 */
+	i = (ftell(fp) | 0x7ff) + 1;
+	if(fseek(fp, i, SEEK_SET) < 0) {
+		fprintf(stderr, "gethuffdata: sector skip failed\n");
+		return 0;
+	}
+
+	/*
+	 * skip remainder of "sector"
+	 */
+	i = 0;
+	while (is24() != 0xfffffe) {
+		(void)get24();
+		if(++i == 1)
+			trace((stderr,"gethuffdata: skipping for sync ..."));
+	}
+	if(i != 0)
+		trace((stderr, " %d times\n", i));
+
+	while(result) {
+		if(is24() == 0xfffffe) {
+			skip24();
+			plane = get2();
+			row = get13(); col = 0;
+			skip1();
+			if(row >= maxrownumber) {
+				trace((stderr,
+					"gethuffdata: stopping at row %d\n",
+								row));
+				break;
+			}
+			switch (plane) {
+			case	0:
+				huffstart = hufftable[0];
+				pixelptr  = luma + row*realrowwidth;
+				break;
+
+			case	2:
+				huffstart = hufftable[1];
+				pixelptr  = chroma1 + row/2*realrowwidth/2;
+				break;
+
+			case	3:
+				huffstart = hufftable[2];
+				pixelptr  = chroma2 + row/2*realrowwidth/2;
+				break;
+
+			default:
+				fprintf(stderr, "gethuffdata: bad plane %d\n",
+									plane);
+				result = 0;
+				break;
+			}
+			WaitCursor();
+			continue;
+		}
+
+		/*
+		 * locate correction in huffman tree
+		 */
+		for(huffptr = huffstart;;) {
+			huffptr += get1();
+			if(*huffptr < 0) {
+				huffptr -= *huffptr;
+			} else if(*huffptr == 0) {
+				fprintf(stderr,
+					"gethuffdata: invalid code: "
+						"image quality reduced\n");
+				result = 0;
+				break;
+			} else
+				break;
+		}
+		if(!result)
+			break;
+
+		/*
+		 * apply correction to the pixel
+		 *
+		 * eeeek!!  the corrections can sometimes over or underflow!
+		 * this strongly suggested that the 'magnify' method was in
+		 * some way wrong.  however, experiments showed that the
+		 * over/under flows even occured for the pixels that are
+		 * copied through magnify without change (ie, the even
+		 * row/even column case).  curiously, though, the odd
+		 * column and odd row cases were about 3x more likely to have
+		 * the over/underflow, and the odd row/odd column case was
+		 * about 5x higher, so maybe the use of a bi-linear
+		 * interpolation is not correct -- just *close*?
+		 *
+		 * the other clue in this area is that the overflows are
+		 * by far most frequenct along edges of very bright
+		 * areas -- rarely in the interior of such regions.
+		 */
+		i = (int) *pixelptr + (signed char) (*huffptr - 1);
+#if TRACE
+		if(i > 255)
+			++oflow;
+/*			trace((stderr,
+			  "gethuffdata: oflow %d %d %d\n", row, col, i));*/
+		else if(i < 0)
+			++uflow;
+/*			trace((stderr,
+			  "gethuffdata: uflow %d %d %d\n", row, col, i));*/
+		++col;
+#endif
+		*pixelptr++ = clip[i + 256];
+	}
+
+oops:
+	for(i = 0; i < 3; ++i)
+		free(hufftable[i]);
+	trace((stderr, "gethuffdata: uflow=%d oflow=%d\n", uflow, oflow));
+	trace((stderr, "gethuffdata: done @ 0x%08lx (sector %ld.%d)\n",
+				ftell(fp), ftell(fp)/0x800, 0x800 - bytesleft));
+	return result;
+}
+
+#endif /* HAVE_PCD */
diff -ruN xv-3.10a-bugfixes/xvpds.c xv-3.10a-enhancements/xvpds.c
--- xv-3.10a-bugfixes/xvpds.c	2005-04-03 11:31:30.000000000 -0700
+++ xv-3.10a-enhancements/xvpds.c	2005-04-17 21:40:40.000000000 -0700
@@ -77,8 +77,7 @@
  * Huffman-encoded, and the encoding histogram follows the ASCII headers.
  * To decode these, we use a slightly modified version of "vdcomp.c" from the
  * NASA Viking CD-ROMS.  For xv to work, you need to have vdcomp compiled
- * and in your search path.  vdcomp.c should be included with this
-distribution.
+ * and in your search path.  vdcomp.c should be included with this distribution.
  *
  * I've heard that newer discs have FITS images on them.  If they do, support
  * for them will be added when I get one.  Until then, you can use fitstopgm.
@@ -102,7 +101,7 @@
  * This software is provided "as is" without any express or implied warranty.
  */
 
-
+#define  NEEDSDIR       /* for S_IRUSR|S_IWUSR */
 #include "xv.h"
 
 #ifdef HAVE_PDS
@@ -129,27 +128,32 @@
 
 /* This is arbitrary.  Everything I've seen so far fits in 50 chars */
 #define COMMENTSIZE	50
+#define INOTESIZE	1000
 
 
 static int	lastwasinote = FALSE;
-static char	scanbuff         [MAX_SIZE],
-                rtbuff         [RTBUFFSIZE],
-		inote	   [20*COMMENTSIZE],
-                infobuff      [COMMENTSIZE],
-		spacecraft    [COMMENTSIZE],
-		target        [COMMENTSIZE],
-		filtname      [COMMENTSIZE],
-		gainmode      [COMMENTSIZE],
-		editmode      [COMMENTSIZE],
-		scanmode      [COMMENTSIZE],
-		exposure      [COMMENTSIZE],
-		shuttermode   [COMMENTSIZE],
-		mphase        [COMMENTSIZE],
-		iname         [COMMENTSIZE],
-		itime         [COMMENTSIZE],
-                garbage       [1020],
+static char	scanbuff         [MAX_SIZE+1],
+                rtbuff         [RTBUFFSIZE+1],
+		inote	        [INOTESIZE+1],
+                infobuff      [COMMENTSIZE+1],
+		spacecraft    [COMMENTSIZE+1],
+		target        [COMMENTSIZE+1],
+		filtname      [COMMENTSIZE+1],
+		gainmode      [COMMENTSIZE+1],
+		editmode      [COMMENTSIZE+1],
+		scanmode      [COMMENTSIZE+1],
+		exposure      [COMMENTSIZE+1],
+		shuttermode   [COMMENTSIZE+1],
+		mphase        [COMMENTSIZE+1],
+		iname         [COMMENTSIZE+1],
+		itime         [COMMENTSIZE+1],
+                garbage       [1024],
 		*tmptmp,
 		pdsuncompfname[FNAMESIZE];
+
+#define SSTR(l)			"%" #l "s"
+#define S(l)			SSTR(l)
+
 byte *image;
 static int elaphe;
 
@@ -251,6 +255,9 @@
   /* returns '1' on success, '0' on failure */
 
   int tempnum, bytewidth, bufsize;
+#ifndef USE_MKSTEMP
+  int tmpfd;
+#endif
   FILE	*zf;
   static int isfixed,teco,i,j,itype,vaxbyte,
              recsize,hrecsize,irecsize,isimage,labelrecs,labelsofar,
@@ -397,7 +404,7 @@
 
       if (strcmp(scanbuff,"END") == 0) {
 	break;
-      } else if (sscanf(scanbuff," RECORD_TYPE = %s",rtbuff) == 1) {
+      } else if (sscanf(scanbuff, " RECORD_TYPE = " S(RTBUFFSIZE), rtbuff) == 1) {
 	if (strncmp(rtbuff,"VARIABLE_LENGTH", (size_t) 15) == 0) {
 	  /*		itype=PDSVARIABLE; */
 	} else if (strncmp(rtbuff,"FIXED_LENGTH", (size_t) 12) == 0) {
@@ -416,7 +423,7 @@
 	    if (irecsize == 0) irecsize=recsize;
 	lastwasinote=FALSE;
 	continue;
-      } else if (sscanf(scanbuff," FILE_TYPE = %s", rtbuff) != 0) {
+      } else if (sscanf(scanbuff, " FILE_TYPE = " S(RTBUFFSIZE), rtbuff) != 0) {
 	lastwasinote=FALSE;
 	if (strncmp(rtbuff,"IMAGE", (size_t) 5) == 0) {
 	  isimage=TRUE;
@@ -445,74 +452,74 @@
 	lastwasinote=FALSE; continue;
       } else if (sscanf(scanbuff," SAMPLE_BITS = %d", &samplesize) == 1) {
 	lastwasinote=FALSE; continue;
-      } else if (sscanf(scanbuff," SAMPLE_TYPE = %s", sampletype) == 1) {
+      } else if (sscanf(scanbuff, " SAMPLE_TYPE = " S(64), sampletype) == 1) {
 	lastwasinote=FALSE; continue;
-      } else if (sscanf(scanbuff," SPACECRAFT_NAME = %s %s",
+      } else if (sscanf(scanbuff," SPACECRAFT_NAME = " S(COMMENTSIZE) " " S(1023),
 			spacecraft,garbage) == 2 ) {
-	strcat(spacecraft,xv_strstr(scanbuff, spacecraft)+strlen(spacecraft));
+	const char *tmp = xv_strstr(scanbuff, spacecraft) + strlen(spacecraft);
+	strncat(spacecraft, tmp, COMMENTSIZE - strlen(spacecraft));
 	lastwasinote=FALSE;  continue;
-      } else if (sscanf(scanbuff," SPACECRAFT_NAME = %s", spacecraft) == 1) {
+      } else if (sscanf(scanbuff, " SPACECRAFT_NAME = " S(COMMENTSIZE), spacecraft) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," TARGET_NAME = %s", target) == 1) {
+      } else if (sscanf(scanbuff, " TARGET_NAME = " S(COMMENTSIZE), target) == 1) {
 	lastwasinote=FALSE; continue;
-      } else if (sscanf(scanbuff," TARGET_BODY = %s", target) == 1) {
+      } else if (sscanf(scanbuff, " TARGET_BODY = " S(COMMENTSIZE), target) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," MISSION_PHASE_NAME = %s", mphase) == 1) {
+      } else if (sscanf(scanbuff, " MISSION_PHASE_NAME = " S(COMMENTSIZE), mphase) == 1) {
 	lastwasinote=FALSE; continue;
-      } else if (sscanf(scanbuff," MISSION_PHASE = %s", mphase) == 1) {
+      } else if (sscanf(scanbuff, " MISSION_PHASE = " S(COMMENTSIZE), mphase) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," INSTRUMENT_NAME = %s", iname) == 1) {
+      } else if (sscanf(scanbuff, " INSTRUMENT_NAME = " S(COMMENTSIZE), iname) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," GAIN_MODE_ID = %s", gainmode) == 1) {
+      } else if (sscanf(scanbuff, " GAIN_MODE_ID = " S(COMMENTSIZE), gainmode) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," INSTRUMENT_GAIN_STATE = %s",gainmode)==1) {
+      } else if (sscanf(scanbuff, " INSTRUMENT_GAIN_STATE = " S(COMMENTSIZE), gainmode) ==1 ) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," EDIT_MODE_ID = %s", editmode) == 1) {
+      } else if (sscanf(scanbuff, " EDIT_MODE_ID = " S(COMMENTSIZE), editmode) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," INSTRUMENT_EDIT_MODE = %s", editmode)==1) {
+      } else if (sscanf(scanbuff, " INSTRUMENT_EDIT_MODE = " S(COMMENTSIZE), editmode) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," SCAN_MODE_ID = %s", scanmode) == 1) {
+      } else if (sscanf(scanbuff, " SCAN_MODE_ID = " S(COMMENTSIZE), scanmode) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," INSTRUMENT_SCAN_RATE = %s", scanmode)==1) {
+      } else if (sscanf(scanbuff, " INSTRUMENT_SCAN_RATE = " S(COMMENTSIZE), scanmode) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," SHUTTER_MODE_ID = %s", shuttermode) == 1) {
+      } else if (sscanf(scanbuff, " SHUTTER_MODE_ID = " S(COMMENTSIZE), shuttermode) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," INSTRUMENT_SHUTTER_MODE = %s",
-			shuttermode) == 1) {
+      } else if (sscanf(scanbuff, " INSTRUMENT_SHUTTER_MODE = " S(COMMENTSIZE), shuttermode) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," SCAN_MODE_ID = %s", scanmode) == 1) {
+      } else if (sscanf(scanbuff, " SCAN_MODE_ID = " S(COMMENTSIZE), scanmode) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," INSTRUMENT_SCAN_RATE = %s", scanmode)==1) {
+      } else if (sscanf(scanbuff, " INSTRUMENT_SCAN_RATE = " S(COMMENTSIZE), scanmode) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," SPACECRAFT_EVENT_TIME = %s", itime) == 1) {
+      } else if (sscanf(scanbuff, " SPACECRAFT_EVENT_TIME = " S(COMMENTSIZE), itime) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," IMAGE_TIME = %s", itime) == 1) {
+      } else if (sscanf(scanbuff, " IMAGE_TIME = " S(COMMENTSIZE), itime) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," FILTER_NAME = %s", filtname) == 1) {
+      } else if (sscanf(scanbuff, " FILTER_NAME = " S(COMMENTSIZE), filtname) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff," INSTRUMENT_FILTER_NAME = %s",filtname)==1) {
+      } else if (sscanf(scanbuff, " INSTRUMENT_FILTER_NAME = " S(COMMENTSIZE), filtname) == 1) {
 	lastwasinote=FALSE; continue;
 
-      } else if ((sscanf(scanbuff," EXPOSURE_DURATION = %s", exposure) == 1)
-	      || (sscanf(scanbuff," INSTRUMENT_EXPOSURE_DURATION = %s",
-			 exposure) == 1)) {
+      } else if ((sscanf(scanbuff, " EXPOSURE_DURATION = " S(COMMENTSIZE), exposure) == 1)
+	      || (sscanf(scanbuff, " INSTRUMENT_EXPOSURE_DURATION = " S(COMMENTSIZE),
+			 exposure)) == 1) {
 	tmptmp = (char *) index(scanbuff,'=');
 	tmptmp++;
 	while((*tmptmp) == ' ')
@@ -520,10 +527,10 @@
 	strcpy(exposure,tmptmp);
 	lastwasinote=FALSE; continue;
 
-      } else if (sscanf(scanbuff, "NOTE = %s", inote) == 1) {
+      } else if (sscanf(scanbuff, "NOTE = " S(INOTESIZE), inote) == 1) {
 	tmptmp = (char *) index(scanbuff,'='); tmptmp++;
 	while (((*tmptmp) == ' ') || ((*tmptmp)  == '"')) tmptmp++;
-	strcpy(inote,tmptmp);
+	strncpy(inote, tmptmp, INOTESIZE - 1);
 	strcat(inote," ");
 
 	/*   evil and somewhat risky:  A "note" (really, any textual
@@ -548,7 +555,7 @@
       } else if (lastwasinote) {
 	tmptmp=scanbuff;
 	while (((*tmptmp) == ' ') || ((*tmptmp)  == '"')) tmptmp++;
-	strcat(inote,tmptmp);
+	strncat(inote, tmptmp, INOTESIZE - strlen(inote) - 1);
 	strcat(inote," ");
 	if (index(tmptmp,'"') != NULL)
 	    lastwasinote=FALSE;
@@ -647,27 +654,27 @@
 
   *infobuff='\0';
   if (*spacecraft) {
-    strcat(infobuff,spacecraft);
+    strncat(infobuff, spacecraft, sizeof(infobuff) - 1);
   }
 
   if (*target) {
-    strcat(infobuff,", ");
-    strcat(infobuff,target);
+    strncat(infobuff, ", ", sizeof(infobuff) - strlen(infobuff) - 1);
+    strncat(infobuff, target, sizeof(infobuff) - strlen(infobuff) - 1);
   }
 
   if (*filtname) {
-    strcat(infobuff,", ");
-    strcat(infobuff,filtname);
+    strncat(infobuff, ", ", sizeof(infobuff) - strlen(infobuff) - 1);
+    strncat(infobuff, filtname, sizeof(infobuff) - strlen(infobuff) - 1);
   }
 
   if (*itime) {
-    strcat(infobuff,", ");
-    strcat(infobuff,itime);
+    strncat(infobuff, ", ", sizeof(infobuff) - strlen(infobuff) - 1);
+    strncat(infobuff, itime, sizeof(infobuff) - strlen(infobuff) - 1);
   }
 
-  SetISTR(ISTR_WARNING,infobuff);
+  SetISTR(ISTR_WARNING, "%s", infobuff);
 
-  strcpy(pdsuncompfname,fname);
+  strncpy(pdsuncompfname,fname,sizeof(pdsuncompfname) - 1);
   ftypstr = "";
 
   switch (itype) {
@@ -695,7 +702,7 @@
     fclose(zf);
 
 #ifndef VMS
-    sprintf(pdsuncompfname,"%s/xvhuffXXXXXX", tmpdir);
+    snprintf(pdsuncompfname, sizeof(pdsuncompfname) - 1, "%s/xvhuffXXXXXX", tmpdir);
 #else
     strcpy(pdsuncompfname,"sys$disk:[]xvhuffXXXXXX");
 #endif
@@ -704,10 +711,16 @@
     close(mkstemp(pdsuncompfname));
 #else
     mktemp(pdsuncompfname);
+    tmpfd = open(pdsuncompfname,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR);
+    if (tmpfd < 0) {
+      SetISTR(ISTR_WARNING,"Unable to create temporary file.");
+      return 0;
+    }
+    close(tmpfd);
 #endif
 
 #ifndef VMS
-    sprintf(scanbuff,"%s %s - 4 >%s",PDSUNCOMP,fname,pdsuncompfname);
+    sprintf(scanbuff,"%s '%s' - 4 > %s", PDSUNCOMP, fname, pdsuncompfname);
 #else
     sprintf(scanbuff,"%s %s %s 4",PDSUNCOMP,fname,pdsuncompfname);
 #endif
@@ -823,26 +836,26 @@
     char tmp[256];
     *(pinfo->comment) = '\0';
 
-    sprintf(tmp, "Spacecraft: %-28sTarget: %-32s\n", spacecraft, target);
-    strcat(pinfo->comment, tmp);
+    sprintf(tmp, "Spacecraft: %-28.28sTarget: %-32.32s\n", spacecraft, target);
+    strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1);
 
-    sprintf(tmp, "Filter: %-32sMission phase: %-24s\n", filtname, mphase);
-    strcat(pinfo->comment, tmp);
+    sprintf(tmp, "Filter: %-32.32sMission phase: %-24.24s\n", filtname, mphase);
+    strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1);
 
-    sprintf(tmp, "Image time: %-28sGain mode: %-29s\n", itime, gainmode);
-    strcat(pinfo->comment, tmp);
+    sprintf(tmp, "Image time: %-28.28sGain mode: %-29.29s\n", itime, gainmode);
+    strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1);
 
-    sprintf(tmp, "Edit mode: %-29sScan mode: %-29s\n", editmode, scanmode);
-    strcat(pinfo->comment, tmp);
+    sprintf(tmp, "Edit mode: %-29.29sScan mode: %-29.29s\n", editmode, scanmode);
+    strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1);
 
-    sprintf(tmp, "Exposure: %-30sShutter mode: %-25s\n", exposure,shuttermode);
-    strcat(pinfo->comment, tmp);
+    sprintf(tmp, "Exposure: %-30.30sShutter mode: %-25.25s\n", exposure,shuttermode);
+    strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1);
 
-    sprintf(tmp, "Instrument: %-28sImage time: %-28s\n", iname, itime);
-    strcat(pinfo->comment, tmp);
+    sprintf(tmp, "Instrument: %-28.28sImage time: %-28.28s\n", iname, itime);
+    strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1);
 
-    sprintf(tmp, "Image Note: %-28s", inote);
-    strcat(pinfo->comment, tmp);
+    sprintf(tmp, "Image Note: %-28.28s", inote);
+    strncat(pinfo->comment, tmp, 2000 - strlen(pinfo->comment) - 1);
   }
 
   if (LoadPDSPalette(fname, pinfo))  return 1;
diff -ruN xv-3.10a-bugfixes/xvpi.c xv-3.10a-enhancements/xvpi.c
--- xv-3.10a-bugfixes/xvpi.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvpi.c	2005-04-17 22:57:04.000000000 -0700
@@ -0,0 +1,1060 @@
+/*
+ * xvpi.c - load routine for `Pi' format pictures.
+ *
+ * The `Pi' format is made by Yanagisawa.
+ * It is common among many Japanese personal computer users.
+ *
+ */
+
+#include "xv.h"
+#include <setjmp.h>
+
+#ifdef HAVE_PI
+
+typedef unsigned short data16;
+typedef unsigned int data32;
+
+struct pi_info {
+    jmp_buf jmp;
+    FILE *fp;
+    struct {
+	int rest;
+	byte cur;
+    }bs;
+    long fsize;
+    byte mode;
+    int width, height;
+    float aspect;
+    int cbits;
+    int numcols;
+    byte *cmap;
+    struct ct_t{
+	struct elt_t *top;
+	struct elt_t{
+	    struct elt_t *old, *recent;
+	    byte val;
+	} *elt;
+    }*ct;
+    int defcmap;
+    int writing_grey;
+};
+
+static void pi_open_file         PARM((struct pi_info*, char*));
+static void pi_read_header       PARM((struct pi_info*, char**));
+static void pi_check_id          PARM((struct pi_info*));
+static void pi_read_comment      PARM((struct pi_info*, char**));
+static void pi_read_palette      PARM((struct pi_info*));
+static void pi_expand            PARM((struct pi_info*, byte**));
+static byte pi_read_color        PARM((struct pi_info*, int));
+static int pi_read_position      PARM((struct pi_info*));
+static data32 pi_read_length     PARM((struct pi_info*));
+static int pi_copy_pixels        PARM((struct pi_info*,
+				     byte*, int, int, data32));
+
+static void pi_write_header      PARM((struct pi_info*,
+				       char*, byte*, byte*, byte*));
+static void pi_write_id          PARM((struct pi_info*));
+static void pi_write_comment     PARM((struct pi_info*, char*));
+static void pi_write_palette     PARM((struct pi_info*, byte*, byte*, byte*));
+static void pi_compress          PARM((struct pi_info*, byte*));
+static void pi_write_gabage      PARM((struct pi_info*));
+static void pi_write_color       PARM((struct pi_info*, int, int));
+static int pi_test_matching      PARM((struct pi_info*,
+				       byte*, int, int, data32*));
+static void pi_write_position    PARM((struct pi_info*, int));
+static void pi_write_length      PARM((struct pi_info*, data32));
+
+static void pi_table_create      PARM((struct pi_info*));
+static byte pi_table_get_value   PARM((struct pi_info*, int, int));
+static int pi_table_lookup_value PARM((struct pi_info*, int, int));
+static data32 pi_read_bits       PARM((struct pi_info*, int));
+static void pi_write_bits        PARM((struct pi_info*, data32, int));
+static void pi_init_pi_info      PARM((struct pi_info*));
+static void pi_cleanup_pi_info   PARM((struct pi_info*, int));
+static void pi_cleanup_pinfo     PARM((PICINFO*));
+static void pi_memory_error      PARM((char*, char*));
+static void pi_error             PARM((struct pi_info*, int));
+static void pi_file_error        PARM((struct pi_info*, int));
+static void pi_file_warning      PARM((struct pi_info*, int));
+static void pi_show_pi_info      PARM((struct pi_info*));
+static void *pi_malloc           PARM((size_t, char*));
+static void *pi_realloc          PARM((void*, size_t, char*));
+
+
+static char *pi_id = "Pi";
+static char *pi_msgs[] = {
+    NULL,
+#define PI_OPEN 1
+    "couldn't open.",
+#define PI_CORRUPT 2
+    "file corrupted.",
+#define PI_FORMAT 3
+    "not PI format.",
+#define PI_PLANES 4
+    "bad number of planes.",
+#define PI_WRITE 5
+    "write failed.",
+};
+
+
+/* The main routine of `Pi' loader. */
+int LoadPi(fname, pinfo)
+    char *fname;
+    PICINFO *pinfo;
+{
+    struct pi_info pi;
+    int e;
+    int i;
+    if(DEBUG) fputs("LoadPi:\n", stderr);
+
+    pinfo->comment = NULL;
+    pi_init_pi_info(&pi);
+    if((e = setjmp(pi.jmp)) != 0){
+	/* When an error occurs, comes here. */
+	pi_cleanup_pi_info(&pi, 0);
+	pi_cleanup_pinfo(pinfo);
+	if(DEBUG) fputs("\n", stderr);
+	return 0;
+    }
+
+    pi_open_file(&pi, fname);
+    pi_read_header(&pi, &pinfo->comment);
+    pi_expand(&pi, &pinfo->pic);
+
+    pinfo->normw = pinfo->w = pi.width;
+    pinfo->normh = pinfo->h = pi.height;
+    pinfo->type = PIC8;
+    if(pi.numcols > 256)	/* shouldn't happen. */
+	pi.numcols = 256;
+    for(i = 0; i < pi.numcols; i++){
+	pinfo->r[i] = pi.cmap[i * 3    ];
+	pinfo->g[i] = pi.cmap[i * 3 + 1];
+	pinfo->b[i] = pi.cmap[i * 3 + 2];
+    }
+    pinfo->frmType = F_PI;
+    pinfo->colType = F_FULLCOLOR;
+    sprintf(pinfo->fullInfo, "Pi, %d colors (%ld bytes)",
+	    pi.numcols, pi.fsize);
+    sprintf(pinfo->shrtInfo, "%dx%d Pi.", pi.width, pi.height);
+    normaspect = pi.aspect;
+
+    pi_cleanup_pi_info(&pi, 0);
+    if(DEBUG) fputs("\n", stderr);
+    return 1;
+}
+
+static void pi_open_file(pi, fname)
+    struct pi_info *pi;
+    char *fname;
+{
+    if((pi->fp = fopen(fname, "rb")) == NULL)
+	pi_file_error(pi, PI_OPEN);
+    fseek(pi->fp, (size_t) 0, SEEK_END);
+    pi->fsize = ftell(pi->fp);
+    fseek(pi->fp, (size_t) 0, SEEK_SET);
+}
+
+static void pi_read_header(pi, comm)
+    struct pi_info *pi;
+    char **comm;
+{
+    byte buf[10];
+    int mda;
+    int i;
+
+    pi_check_id(pi);
+    pi_read_comment(pi, comm);
+
+    if(fread(buf, (size_t) 10, (size_t) 1, pi->fp) != 1)
+	pi_file_error(pi, PI_CORRUPT);
+
+    pi->mode = buf[0];
+    pi->defcmap = pi->mode & 0x80;
+    if(buf[1] != 0 && buf[2] != 0)
+	pi->aspect = (float) buf[2] / (int) buf[1];
+    pi->cbits = buf[3];
+    pi->numcols = 1 << pi->cbits;
+
+    if(pi->cbits != 4 && pi->cbits != 8)
+	pi_error(pi, PI_PLANES);
+
+    mda = (int) buf[8] << 8 | (int) buf[9];
+    for(i = 0; i < mda; i++){
+	if(fgetc(pi->fp) == EOF)
+	    pi_file_error(pi, PI_CORRUPT);
+    }
+
+    if(fread(buf, (size_t) 4, (size_t) 1, pi->fp) != 1)
+	pi_file_error(pi, PI_CORRUPT);
+    pi->width  = (int) buf[0] << 8 | (int) buf[1];
+    pi->height = (int) buf[2] << 8 | (int) buf[3];
+
+    pi_read_palette(pi);
+
+    if(DEBUG) pi_show_pi_info(pi);
+}
+
+static void pi_check_id(pi)
+    struct pi_info *pi;
+{
+    char buf[2];
+
+    if(fread(buf, (size_t) 2, (size_t) 1, pi->fp) != 1)
+	pi_file_error(pi, PI_CORRUPT);
+    if(strncmp(buf, pi_id, (size_t) 2) != 0)
+	pi_error(pi, PI_FORMAT);
+}
+
+static void pi_read_comment(pi, comm)
+    struct pi_info *pi;
+    char **comm;
+{
+/*
+ * The comment format is like:
+ *   comment string `^Z' dummy string `\0'
+ */
+    int max = -1, i = 0;
+    int c;
+
+    while(1){
+	if((c = fgetc(pi->fp)) == EOF)
+	    pi_file_error(pi, PI_CORRUPT);
+	if(c == '\032')		/* 0x1a, '^Z' */
+	    break;
+	if(max < i){
+	    max += 32;
+	    *comm = pi_realloc(*comm, (size_t) max + 1, "pi_read_comment(1)");
+	}
+	(*comm)[i++] = c;
+    }
+    if(max < i){
+	max++;
+	*comm = pi_realloc(*comm, (size_t) max + 1, "pi_read_comment(2)");
+    }
+    (*comm)[i] = '\0';
+
+    while((c = fgetc(pi->fp)) != '\0'){		/* skip the dummy area */
+	if(c == EOF)
+	    pi_file_error(pi, PI_CORRUPT);
+    }
+}
+
+static void pi_read_palette(pi)
+    struct pi_info *pi;
+{
+    pi->cmap = pi_malloc((size_t) pi->numcols * 3, "pi_read_palette");
+    if(pi->mode & 0x80){
+	if(pi->numcols == 16){
+	    int i;
+	    byte on;
+
+	    on = 0x77;
+	    for(i = 0; i < 8; i++){
+		pi->cmap[i * 3    ] = i & 2 ? on : 0;
+		pi->cmap[i * 3 + 1] = i & 4 ? on : 0;
+		pi->cmap[i * 3 + 2] = i & 1 ? on : 0;
+	    }
+	    on = 0xff;
+	    for(; i < 16; i++){
+		pi->cmap[i * 3    ] = i & 2 ? on : 0;
+		pi->cmap[i * 3 + 1] = i & 4 ? on : 0;
+		pi->cmap[i * 3 + 2] = i & 1 ? on : 0;
+	    }
+	}else{	/* pi->numcols == 256 */
+	    int i;
+	    byte r, g, b;
+	    r = g = b = 0;
+	    for(i = 0; i < 256; i++){
+		pi->cmap[i * 3    ] = r;
+		pi->cmap[i * 3 + 1] = g;
+		pi->cmap[i * 3 + 2] = b;
+		if((b += 0x40) == 0){
+		    if((r += 0x20) == 0)
+			g += 0x20;
+		}
+	    }
+	}
+    }else{
+	if(fread(pi->cmap, (size_t) pi->numcols * 3, (size_t) 1, pi->fp) != 1)
+	    pi_file_error(pi, PI_CORRUPT);
+    }
+}
+
+/* The main routine to expand `Pi' file. */
+static void pi_expand(pi, pic)
+    struct pi_info *pi;
+    byte **pic;
+{
+    byte prev_col = 0;
+    int prev_pos = -1;
+    int cnt = 0, max_cnt = pi->width * pi->height;
+
+    *pic = pi_malloc((size_t) max_cnt, "pi_expand");   // GRR POSSIBLE OVERFLOW / FIXME
+
+    pi_table_create(pi);
+
+    if(pi->width > 2){
+	(*pic)[0] = pi_read_color(pi, 0);
+	(*pic)[1] = pi_read_color(pi, (*pic)[0]);
+
+	while(cnt < max_cnt){
+	    int pos = pi_read_position(pi);
+	    if(pos != prev_pos){
+		data32 len = pi_read_length(pi);
+		cnt = pi_copy_pixels(pi, *pic, cnt, pos, len);
+		prev_col = (*pic)[cnt - 1];
+		prev_pos = pos;
+	    }else{
+		do{
+		    prev_col = pi_read_color(pi, (int) prev_col);
+		    (*pic)[cnt++] = prev_col;
+		    prev_col = pi_read_color(pi, (int) prev_col);
+		    (*pic)[cnt++] = prev_col;
+		}while(pi_read_bits(pi, 1) == 1);
+
+		prev_pos = -1;
+	    }
+	}
+    }else{
+	while(cnt < max_cnt){
+	    prev_col = pi_read_color(pi, (int) prev_col);
+	    (*pic)[cnt++] = prev_col;
+	}
+    }
+}
+
+static byte pi_read_color(pi, prev)
+    struct pi_info *pi;
+    int prev;
+{
+    byte n;
+    if(pi->cbits == 4){
+	if(pi_read_bits(pi, 1) == 1)
+	    n = pi_read_bits(pi, 1);			/* 1x */
+	else{
+	    if(pi_read_bits(pi, 1) == 0)
+		n = pi_read_bits(pi, 1) + 2;		/* 00x */
+	    else{
+		if(pi_read_bits(pi, 1) == 0)
+		    n = pi_read_bits(pi, 2) + 4;	/* 010xx */
+		else
+		    n = pi_read_bits(pi, 3) + 8;	/* 011xxx */
+	    }
+	}
+    }else{	/* cbits == 8 */
+	if(pi_read_bits(pi, 1) == 1)
+	    n = pi_read_bits(pi, 1);
+	else{
+	    int bits = 0;
+	    byte base = 2;
+	    while(bits < 6){
+		if(pi_read_bits(pi, 1) == 0)
+		    break;
+		bits++;
+		base <<= 1;
+	    }
+	    n = pi_read_bits(pi, bits + 1) + base;
+	}
+    }
+
+    return pi_table_get_value(pi, prev, (int) n);
+}
+
+static int pi_read_position(pi)
+    struct pi_info *pi;
+{
+    byte r;
+    if((r = pi_read_bits(pi, 2)) != 3)
+	return (int) r;
+    else
+	return (int) pi_read_bits(pi, 1) + 3;
+}
+
+static data32 pi_read_length(pi)
+    struct pi_info *pi;
+{
+    data32 r = 1;
+    int bits = 0;
+    while(pi_read_bits(pi, 1) == 1){
+	r <<= 1;
+	bits++;
+    }
+    if(bits > 0)
+	return r + pi_read_bits(pi, bits);
+    return 1;
+}
+
+static int pi_copy_pixels(pi, pic, cnt, pos, len)
+    struct pi_info *pi;
+    byte *pic;
+    int cnt, pos;
+    data32 len;
+{
+    int s = 0, d = cnt;
+    int max = pi->width * pi->height;
+    switch(pos){
+    case 0:
+	if(cnt < 2){
+	    if(pic[0] == pic[1])
+		s = cnt - 2;
+	    else
+		s = cnt - 4;
+	}else{
+	    if(pic[cnt - 2] == pic[cnt - 1])
+		s = cnt - 2;
+	    else
+		s = cnt - 4;
+	}
+	break;
+    case 1:
+	s = cnt - pi->width;
+	break;
+    case 2:
+	s = cnt - pi->width * 2;
+	break;
+    case 3:
+	s = cnt - pi->width + 1;
+	break;
+    case 4:
+	s = cnt - pi->width - 1;
+    }
+
+    len *= 2;
+    while(s < 0 && len != 0 && d < max){
+	pic[d++] = pic[-(s++) % 2];
+	len--;
+    }
+    while(len != 0 && d < max){
+	pic[d++] = pic[s++];
+	len--;
+    }
+    return d;
+}
+
+/* The main routine of `Pi' saver. */
+int WritePi(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle,
+	    comment)
+    FILE *fp;
+    byte *pic;
+    int ptype, w, h;
+    byte *rmap, *gmap, *bmap;
+    int numcols, colorstyle;
+    char *comment;
+{
+    byte rtemp[256], gtemp[256], btemp[256];
+    struct pi_info pi;
+    int e;
+
+    if(DEBUG) fputs("WritePi\n", stderr);
+    pi_init_pi_info(&pi);
+    pi.fp = fp;
+    pi.width  = w;
+    pi.height = h;
+    pi.writing_grey = (colorstyle == F_GREYSCALE);
+    if(ptype == PIC24){
+	if(!(pic = Conv24to8(pic, w, h, 256, rtemp, gtemp, btemp)))
+	    pi_memory_error("Conv24to8", "WritePi");
+	rmap = rtemp;
+	gmap = gtemp;
+	bmap = btemp;
+	numcols = 256;
+    }
+
+    if((e = setjmp(pi.jmp)) != 0){
+	/* When an error occurs, comes here. */
+	pi_cleanup_pi_info(&pi, 1);
+	if(DEBUG) fputs("\n", stderr);
+	return -1;
+    }
+
+    pi.numcols = numcols;
+    pi_write_header(&pi, comment,  rmap, gmap, bmap);
+    pi_compress(&pi, pic);
+    pi_write_gabage(&pi);
+
+    pi_cleanup_pi_info(&pi, 1);
+    if(DEBUG) fputs("\n", stderr);
+    return 0;
+}
+
+static void pi_write_header(pi, comm, r, g, b)
+    struct pi_info *pi;
+    char *comm;
+    byte *r, *g, *b;
+{
+    byte buf[14];
+
+    if(DEBUG) pi_show_pi_info(pi);
+
+    pi_write_id(pi);
+    pi_write_comment(pi, comm);
+
+    buf[0] = buf[1] = buf[2] = 0;
+    buf[3] = pi->cbits = pi->numcols > 16 ? 8 : 4;
+    buf[4] = 'X';
+    buf[5] = 'V';
+    buf[6] = ' ';
+    buf[7] = ' ';
+    buf[8] = buf[9] = 0;
+    buf[10] = pi->width >> 8;
+    buf[11] = pi->width;
+    buf[12] = pi->height >> 8;
+    buf[13] = pi->height;
+    if(fwrite(buf, (size_t) 14, (size_t) 1, pi->fp) != 1)
+	pi_file_error(pi, PI_WRITE);
+
+    pi_write_palette(pi, r, g, b);
+}
+
+static void pi_write_id(pi)
+    struct pi_info *pi;
+{
+    if(fwrite(pi_id, (size_t) 2, (size_t) 1, pi->fp) != 1)
+	pi_file_error(pi, PI_WRITE);
+}
+
+static void pi_write_comment(pi, comm)
+    struct pi_info *pi;
+    char *comm;
+{
+    if(comm){
+	int i;
+	for(i = 0; comm[i]; i++){
+	    if(comm[i] == '\032')	/* 0x1a, '^Z' */
+		comm[i] = ' ';
+	}
+	if(i > 0){
+	    if(fwrite(comm, (size_t) i, (size_t) 1, pi->fp) != 1)
+		pi_file_error(pi, PI_WRITE);
+	}
+    }
+
+    if(fwrite("\032\0", (size_t) 2, (size_t) 1, pi->fp) != 1)
+	pi_file_error(pi, PI_WRITE);
+}
+
+static void pi_write_palette(pi, r, g, b)
+    struct pi_info *pi;
+    byte *r, *g, *b;
+{
+    int i;
+    int pinum = 1 << pi->cbits;
+    char buf[3];
+
+    for(i = 0; i < pi->numcols; i++){
+	buf[0] = *r++;
+	buf[1] = *g++;
+	buf[2] = *b++;
+	if(pi->writing_grey)
+	    buf[0] = buf[1] = buf[2] = MONO(buf[0], buf[1], buf[2]);
+	if(fwrite(buf, (size_t) 3, (size_t) 1, pi->fp) != 1)
+	    pi_file_error(pi, PI_WRITE);
+    }
+    for( ; i < pinum; i++){
+	if(fwrite(buf, (size_t) 3, (size_t) 1, pi->fp) != 1)
+	    pi_file_error(pi, PI_WRITE);
+    }
+    pi->numcols = pinum;
+}
+
+/* The main routine to compress `Pi' format. */
+static void pi_compress(pi, pic)
+    struct pi_info *pi;
+    byte *pic;
+{
+    byte prev_col = 0;
+    int prev_pos = -1;
+    int cnt = 0, max_cnt = pi->width * pi->height;
+    pi_table_create(pi);
+
+    if(pi->width > 2){
+	int pos;
+	data32 len;
+
+	pi_write_color(pi, 0,      pic[0]);
+	pi_write_color(pi, pic[0], pic[1]);
+	pos = pi_test_matching(pi, pic, prev_pos, cnt, &len);
+	while(cnt < max_cnt){
+	    if(pos >= 0){
+		pi_write_position(pi, pos);
+		pi_write_length(pi, len);
+		if((cnt += len * 2) >= max_cnt)
+		    break;
+		prev_col = pic[cnt - 1];
+		prev_pos = pos;
+		pos = pi_test_matching(pi, pic, prev_pos, cnt, &len);
+	    }else{
+		pi_write_position(pi, prev_pos);
+		prev_pos = -1;
+		while(pos < 0){
+		    pi_write_color(pi, (int) prev_col, pic[cnt]);
+		    prev_col = pic[cnt];
+		    if(++cnt >= max_cnt)
+			break;
+		    pi_write_color(pi, (int) prev_col, pic[cnt]);
+		    prev_col = pic[cnt];
+		    if(++cnt >= max_cnt)
+			break;
+		    pos = pi_test_matching(pi, pic, -1, cnt, &len);
+		    if(pos < 0)
+			pi_write_bits(pi, 1, 1);
+		    else
+			pi_write_bits(pi, 0, 1);
+		}
+	    }
+	}
+    }else{
+	while(cnt < max_cnt){
+	    pi_write_color(pi, (int) prev_col, pic[cnt]);
+	    prev_col = pic[cnt++];
+	}
+    }
+}
+
+static void pi_write_gabage(pi)
+    struct pi_info *pi;
+{
+    pi_write_bits(pi, 0, 32);
+}
+
+static void pi_write_color(pi, prev, col)
+    struct pi_info *pi;
+    int prev, col;
+{
+    int n = pi_table_lookup_value(pi, prev, col);
+
+    if(pi->cbits == 4){
+	if(n < 2)
+	    pi_write_bits(pi, (data32) n | 2, 2);
+	else if(n < 4)
+	    pi_write_bits(pi, (data32) n - 2, 3);
+	else if(n < 8)
+	    pi_write_bits(pi, (data32) (n - 4) | 8, 5);
+	else
+	    pi_write_bits(pi, (data32) (n - 8) | 24, 6);
+    }else{	/* cbits == 8 */
+	if(n < 2){
+	    pi_write_bits(pi, (data32) n | 2, 2);
+	}else{
+	    int bits = 0;
+	    byte base = 2;
+	    while(bits < 6){
+		if(n < (int) base * 2)
+		    break;
+		bits++;
+		base <<= 1;
+	    }
+	    pi_write_bits(pi, 0, 1);
+	    if(bits > 0)
+		pi_write_bits(pi, 0xffffffff, bits);
+	    if(bits < 6)
+		pi_write_bits(pi, 0, 1);
+	    pi_write_bits(pi, (data32) n - base, bits + 1);
+	}
+    }
+}
+
+static int pi_test_matching(pi, pic, prev, cnt, len)
+    struct pi_info *pi;
+    byte *pic;
+    int prev, cnt;
+    data32 *len;
+{
+    data32 lens[5];
+    int pos, p;
+    int s, d = 0;
+    int max = pi->width * pi->height;
+
+    for(pos = 0; pos < 5; pos++){
+	switch(pos){
+	case 0:
+	    if(cnt < 2){
+		if(pic[0] == pic[1])
+		    d = cnt - 2;
+		else
+		    d = cnt - 4;
+	    }else{
+		if(pic[cnt - 2] == pic[cnt - 1])
+		    d = cnt - 2;
+		else
+		    d = cnt - 4;
+	    }
+	    break;
+	case 1:
+	    d = cnt - pi->width;
+	    break;
+	case 2:
+	    d = cnt - pi->width * 2;
+	    break;
+	case 3:
+	    d = cnt - pi->width + 1;
+	    break;
+	case 4:
+	    d = cnt - pi->width - 1;
+	}
+	s = cnt;
+	lens[pos] = 0;
+
+	if(prev == 0 && pos == 0)
+	    continue;
+
+	while(d < max){
+	    if(pic[(d < 0) ? (-d) % 2 : d] != pic[s])
+		break;
+	    lens[pos]++;
+	    d++;
+	    s++;
+	}
+
+    }
+
+    for(pos = 0, p = 1; p < 5; p++){
+	if(lens[p] >= lens[pos])
+	    pos = p;
+    }
+
+    if(lens[pos] / 2 == 0)
+	return -1;
+    *len = lens[pos] / 2;
+    return pos;
+}
+
+static void pi_write_position(pi, pos)
+    struct pi_info *pi;
+    int pos;
+{
+    switch(pos){
+    case 0:
+	pi_write_bits(pi, 0, 2);
+	break;
+    case 1:
+	pi_write_bits(pi, 1, 2);
+	break;
+    case 2:
+	pi_write_bits(pi, 2, 2);
+	break;
+    case 3:
+	pi_write_bits(pi, 6, 3);
+	break;
+    case 4:
+	pi_write_bits(pi, 7, 3);
+	break;
+    }
+}
+
+static void pi_write_length(pi, len)
+    struct pi_info *pi;
+    data32 len;
+{
+    int bits = 0;
+    data32 base = 1;
+
+    while(len >= base * 2){
+	bits++;
+	base <<= 1;
+    }
+    if(bits > 0){
+	pi_write_bits(pi, 0xffffffff, bits);
+	pi_write_bits(pi, 0, 1);
+	pi_write_bits(pi, len - base, bits);
+    }else
+	pi_write_bits(pi, 0, 1);
+}
+
+/*
+ * These pi_table_* functions manipulate the color table.
+ * pi_table_create:
+ *	allocates and initializes a color table.
+ * pi_table_get_value:
+ *	get the specified value, and move it to the top of the list.
+ * pi_table_lookup_value:
+ *	look up the specified value, and move it to the top of the list.
+ */
+static void pi_table_create(pi)
+    struct pi_info *pi;
+{
+    struct ct_t *t;
+    int i;
+    byte mask = pi->numcols - 1;
+    pi->ct = pi_malloc(sizeof *pi->ct * pi->numcols, "pi_table_create(1)");
+    for(i = 0, t = pi->ct; i < pi->numcols; i++, t++){
+	int j;
+	byte v = i;
+	t->elt = pi_malloc(sizeof *t->elt * pi->numcols, "pi_table_create(2)");
+	t->top = &t->elt[pi->numcols - 1];
+	for(j = 0; j < pi->numcols; j++){
+	    v = (v + 1) & mask;
+	    if(j > 0)
+		t->elt[j].old    = &t->elt[j - 1];
+	    else
+		t->elt[0].old    = t->top;
+	    if(j < pi->numcols - 1)
+		t->elt[j].recent = &t->elt[j + 1];
+	    else
+		t->elt[j].recent = &t->elt[0];
+	    t->elt[j].val    = v;
+	}
+	t->elt[0].old = t->top;
+	t->top->recent = &t->elt[0];
+    }
+}
+
+static byte pi_table_get_value(pi, left, num)
+    struct pi_info *pi;
+    int left, num;
+{
+    struct ct_t *t = &pi->ct[left];
+    struct elt_t *e = t->top;
+    if(left >= pi->numcols || num >= pi->numcols)
+	abort();
+    if(num != 0){
+	do {
+	    e = e->old;
+	}while(--num != 0);
+
+	e->old->recent = e->recent;
+	e->recent->old = e->old;
+
+	e->recent = t->top->recent;
+	e->recent->old = e;
+	e->old = t->top;
+	t->top->recent = e;
+
+	t->top = e;
+    }
+    return e->val;
+}
+
+static int pi_table_lookup_value(pi, left, v)
+    struct pi_info *pi;
+    int left, v;
+{
+    struct ct_t *t = &pi->ct[left];
+    struct elt_t *e = t->top;
+    int num = 0;
+
+    if(left >= pi->numcols || v >= pi->numcols)
+	abort();
+
+    while(e->val != v){
+	e = e->old;
+	num++;
+    }
+
+    if(num != 0){
+	e->old->recent = e->recent;
+	e->recent->old = e->old;
+
+	e->recent = t->top->recent;
+	e->recent->old = e;
+	e->old = t->top;
+	t->top->recent = e;
+
+	t->top = e;
+    }
+
+    return num;
+}
+
+/*
+ * These 2 functions read or write to a bit stream.
+ * pi_read_bits:
+ *	reads a specified-bit data from the bit stream.
+ * pi_write_bits:
+ *	writes a specified-bit data to the bit stream.
+ */
+static data32 pi_read_bits(pi, numbits)
+    struct pi_info *pi;
+    int numbits;
+{
+    data32 r = 0;
+
+    while(numbits > 0){
+	while(pi->bs.rest > 0 && numbits > 0){
+	    r = (r << 1) | (pi->bs.cur & 0x80 ? 1 : 0);
+	    pi->bs.cur <<= 1;
+	    pi->bs.rest--;
+	    numbits--;
+	}
+	if(numbits > 0){
+	    int c;
+	    if((c = fgetc(pi->fp)) == EOF)
+		pi_file_warning(pi, PI_CORRUPT);
+	    pi->bs.cur  = c;
+	    pi->bs.rest = 8;
+	}
+    }
+
+    return r;
+}
+
+static void pi_write_bits(pi, dat, bits)
+    struct pi_info *pi;
+    data32 dat;
+    int bits;
+{
+    data32 dat_mask = 1 << (bits - 1);
+    while(bits > 0){
+	while(pi->bs.rest < 8 && bits > 0){
+	    pi->bs.cur <<= 1;
+	    if(dat & dat_mask)
+		pi->bs.cur |= 1;
+	    pi->bs.rest++;
+	    bits--;
+	    dat_mask >>= 1;
+	}
+	if(pi->bs.rest >= 8){
+	    if(fputc((int)pi->bs.cur, pi->fp) == EOF)
+		pi_file_error(pi, PI_WRITE);
+	    pi->bs.cur  = 0;
+	    pi->bs.rest = 0;
+	}
+    }
+}
+
+/*
+ * The routines to initialize or clean up.
+ * pi_inif_pi_info:
+ *	initializes a pi_info structure.
+ * pi_cleanup_pi_info:
+ *	cleanup pi_info structure. It frees allocated memories.
+ * pi_cleanup_pinfo:
+ *	cleanup PICINFO structure when an error occurs.
+ */
+static void pi_init_pi_info(pi)
+    struct pi_info *pi;
+{
+    pi->fp = NULL;
+    pi->bs.rest = 0;
+    pi->bs.cur = 0;
+    pi->fsize = 0;
+    pi->mode = 0;
+    pi->width = pi->mode = 0;
+    pi->aspect = 1.0;
+    pi->cbits = 0;
+    pi->numcols = 0;
+    pi->cmap = NULL;
+    pi->ct = NULL;
+    pi->defcmap = 0;
+    pi->writing_grey = 0;
+}
+
+static void pi_cleanup_pi_info(pi, writing)
+    struct pi_info *pi;
+    int writing;
+{
+    if(pi->fp && !writing){
+	fclose(pi->fp);
+	pi->fp = NULL;
+    }
+    if(pi->cmap){
+	free(pi->cmap);
+	pi->cmap = NULL;
+    }
+    if(pi->ct){
+	int i;
+	for(i = 0; i < pi->numcols; i++)
+	    free(pi->ct[i].elt);
+	free(pi->ct);
+	pi->ct = NULL;
+    }
+}
+
+static void pi_cleanup_pinfo(pinfo)
+    PICINFO *pinfo;
+{
+    if(pinfo->pic){
+	free(pinfo->pic);
+	pinfo->pic = NULL;
+    }
+    if(pinfo->comment){
+	free(pinfo->comment);
+	pinfo->comment = NULL;
+    }
+}
+
+/*
+ * Error handling routins.
+ * pi_memory_error:
+ *	shows a error message, and terminates.
+ * pi_error:
+ *	shows a non-file error message.
+ * pi_file_error:
+ *	shows a file error message.
+ */
+static void pi_memory_error(scm, fn)
+    char *scm, *fn;
+{
+    char buf[128];
+    sprintf(buf, "%s: couldn't allocate memory. (%s)", scm ,fn);
+    FatalError(buf);
+}
+
+static void pi_error(pi, mn)
+    struct pi_info *pi;
+    int mn;
+{
+    SetISTR(ISTR_WARNING, "%s", pi_msgs[mn]);
+    longjmp(pi->jmp, 1);
+}
+
+static void pi_file_error(pi, mn)
+    struct pi_info *pi;
+    int mn;
+{
+    if(feof(pi->fp))
+	SetISTR(ISTR_WARNING, "%s (end of file)", pi_msgs[mn]);
+    else
+	SetISTR(ISTR_WARNING, "%s (%s)", pi_msgs[mn], ERRSTR(errno));
+    longjmp(pi->jmp, 1);
+}
+
+static void pi_file_warning(pi, mn)
+    struct pi_info *pi;
+    int mn;
+{
+    if(feof(pi->fp))
+	SetISTR(ISTR_WARNING, "%s (end of file)", pi_msgs[mn]);
+    else
+	SetISTR(ISTR_WARNING, "%s (%s)", pi_msgs[mn], ERRSTR(errno));
+}
+
+static void pi_show_pi_info(pi)
+    struct pi_info *pi;
+{
+    fprintf(stderr, "  file size: %ld.\n", pi->fsize);
+    fprintf(stderr, "  mode: 0x%02x.\n", pi->mode);
+    fprintf(stderr, "  image size: %dx%d.\n", pi->width, pi->height);
+    fprintf(stderr, "  aspect: %f.\n", pi->aspect);
+    fprintf(stderr, "  number of color bits: %d.\n", pi->cbits);
+    fprintf(stderr, "  number of colors: %d.\n", pi->numcols);
+    fprintf(stderr, "  using default colormap: %s.\n",
+	    pi->defcmap ? "true" : "false");
+    fprintf(stderr, "  writing greyscale image: %s.\n",
+	    pi->writing_grey ? "true" : "false");
+}
+
+/*
+ * Memory related routines.  If failed, they calls pi_memory_error.
+ */
+static void *pi_malloc(n, fn)
+    size_t n;
+    char *fn;
+{
+    void *r = (void *) malloc(n);
+    if(r == NULL)
+	pi_memory_error("malloc", fn);
+    return r;
+}
+
+static void *pi_realloc(p, n, fn)
+    void *p;
+    size_t n;
+    char *fn;
+{
+    void *r = (p == NULL) ? (void *) malloc(n) : (void *) realloc(p, n);
+    if(r == NULL)
+	pi_memory_error("realloc", fn);
+    return r;
+}
+#endif /* HAVE_PI */
diff -ruN xv-3.10a-bugfixes/xvpic.c xv-3.10a-enhancements/xvpic.c
--- xv-3.10a-bugfixes/xvpic.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvpic.c	2005-04-17 22:57:08.000000000 -0700
@@ -0,0 +1,1285 @@
+/*
+ * xvpic.c - load routine for `PIC' format pictures.
+ *
+ * The `PIC' format is used by many Japanese personal computer users.
+ */
+
+#include "xv.h"
+#include <setjmp.h>
+
+#ifdef HAVE_PIC
+
+typedef unsigned short data16;
+typedef unsigned int data32;
+
+struct pic_info {
+    jmp_buf jmp;
+    FILE *fp;
+    struct {
+	int rest;
+	byte cur;
+    }bs;
+    long fsize;
+    int type, mode;
+    int width, height;
+    float aspect;
+    int cbits;
+    int cmapped;
+    byte *cmap;
+    int cached;
+    struct cache_t {
+	int newest;
+	struct cachenode_t {
+	    data32 dat;
+	    int newer, older;
+	} *node;
+    } cache;
+    int g_bits, r_bits, b_bits, i_bits;
+    int inv_gr;
+    int tiled256;
+    int numcols;
+    int writing_grey;
+    data32 *data;
+};
+
+static void pic_open_file              PARM((struct pic_info*,char*));
+static void pic_check_id               PARM((struct pic_info*));
+static void pic_read_comment           PARM((struct pic_info*, char**));
+static void pic_read_header            PARM((struct pic_info*));
+static void pic_expand_data            PARM((struct pic_info*));
+static int pic_expanding_read_len      PARM((struct pic_info*));
+static data32 pic_expanding_read_color PARM((struct pic_info*));
+static void pic_expanding_read_chain
+			PARM((struct pic_info*, int, int, data32));
+static void pic_make_xvpic
+			PARM((struct pic_info*, byte**, byte*, byte*, byte*));
+
+static void pic_write_id               PARM((struct pic_info*));
+static void pic_write_comment          PARM((struct pic_info*, char*));
+static void pic_write_header           PARM((struct pic_info*));
+static void pic_write_palette
+			PARM((struct pic_info*, byte*, byte*, byte*));
+static void pic_make_sparse_data       PARM((struct pic_info*, byte*));
+static void pic_write_data             PARM((struct pic_info*));
+static void pic_write_length           PARM((struct pic_info*, data32));
+static void pic_write_color            PARM((struct pic_info*, data32));
+static void pic_write_chain
+			PARM((struct pic_info*, int, int, data32));
+
+static data32 pic_read_rgb             PARM((struct pic_info*));
+static data32 pic_read_color_code      PARM((struct pic_info*));
+static void pic_write_rgb              PARM((struct pic_info*, data32));
+static void pic_write_color_code       PARM((struct pic_info*, data32));
+
+static void pic_cache_init             PARM((struct pic_info*));
+static data32 pic_cache_get_value      PARM((struct pic_info*, int));
+static void pic_cache_add_value        PARM((struct pic_info*, data32));
+static int pic_cache_lookup            PARM((struct pic_info*, data32));
+
+static data32 pic_read_bits            PARM((struct pic_info*, int));
+static void pic_write_bits             PARM((struct pic_info*, data32, int));
+static byte pic_pad_bit                PARM((int, data32));
+
+static void pic_init_info              PARM((struct pic_info*));
+static void pic_cleanup_pic_info       PARM((struct pic_info*, int));
+static void pic_cleanup_pinfo          PARM((PICINFO*));
+static void pic_memory_error           PARM((char*, char*));
+static void pic_error                  PARM((struct pic_info*, int));
+static void pic_file_error             PARM((struct pic_info*, int));
+static void pic_file_warning           PARM((struct pic_info*, int));
+static void pic_show_pic_info          PARM((struct pic_info*));
+static void *pic_malloc                PARM((size_t, char*));
+static void *pic_realloc               PARM((void*, size_t, char*));
+
+
+static char *pic_id = "PIC";
+
+/* Error Messages */
+static char *pic_msgs[] = {
+    NULL,
+#define PIC_OPEN 1
+    "can't open file.",
+#define PIC_CORRUPT 2
+    "file corrupted.",
+#define PIC_FORMAT 3
+    "not PIC format.",
+#define PIC_SUPPORT 4
+    "unsupported type.",
+#define PIC_COMMENT 5
+    "can't read comment.",
+#define PIC_TYPE 6
+    "bad machine type.",
+#define PIC_MODE 7
+    "bad machine-dependent mode.",
+#define PIC_NUM_COLORS 8
+    "bad number of colors.",
+#define PIC_SIZE 9
+    "bad size.",
+#define PIC_ASPECT 10
+    "bad aspect.",
+#define PIC_WRITE 11
+    "write failed.",
+};
+
+#define H4(b) (((b) >> 4) & 0x0f)
+#define L4(b) ( (b)       & 0x0f)
+
+
+/* The main routine to load a PIC file. */
+int LoadPIC(fname, pinfo)
+    char *fname;
+    PICINFO *pinfo;
+{
+    int e;
+    struct pic_info pic;
+    char buf[128];
+
+    if(DEBUG) fputs("LoadPIC:\n", stderr);
+
+    pic_init_info(&pic);
+
+    pinfo->comment = NULL;
+    if((e = setjmp(pic.jmp)) != 0){
+	/* When an error occurs, comes here. */
+	pic_cleanup_pic_info(&pic, 0);
+	pic_cleanup_pinfo(pinfo);
+	if(DEBUG) fputs("\n", stderr);
+	return 0;
+    }
+
+    pic_open_file(&pic, fname);
+    pic_check_id(&pic);
+    pic_read_comment(&pic, &pinfo->comment);
+    pic_read_header(&pic);
+    pic_expand_data(&pic);
+    pic_make_xvpic(&pic, &pinfo->pic, pinfo->r, pinfo->g, pinfo->b);
+
+    pinfo->w = pic.width;
+    if(pic.tiled256)
+	pinfo->h = pic.height * 2;
+    else
+	pinfo->h = pic.height;
+    pinfo->normw = pinfo->w;
+    pinfo->normh = pinfo->h;
+    pinfo->type = pic.cmapped ? PIC8 : PIC24;
+    pinfo->frmType = F_PIC;
+    pinfo->colType = F_FULLCOLOR;
+    strcpy(pinfo->fullInfo, "PIC");
+    switch(pic.type){
+    case 0x0:
+	strcat(pinfo->fullInfo, ", X68k");
+	break;
+    case 0x1:
+	strcat(pinfo->fullInfo, ", PC-88VA");
+	if(pic.mode & 1)
+	    strcat(pinfo->fullInfo, ", HR");
+	if(pic.mode & 2)
+	    strcat(pinfo->fullInfo, ", tiled 256");
+	break;
+    case 0x2:
+	strcat(pinfo->fullInfo, ", FM-TOWNS");
+	if(pic.mode == 0x5){
+	    strcat(pinfo->fullInfo, ", low-resolution");
+	}else{
+	    strcat(pinfo->fullInfo, ", high-resolution");
+	}
+	break;
+    case 0x3:
+	strcat(pinfo->fullInfo, ", Macintosh");
+	break;
+    case 0xf:
+	;
+    }
+    sprintf(buf, " (%ld bytes)", pic.fsize);
+    strcat(pinfo->fullInfo, buf);
+    sprintf(pinfo->shrtInfo, "%dx%d(aspect %4.2f) PIC.",
+	    pinfo->w, pinfo->h, pic.aspect);
+    if (!nopicadjust)
+	normaspect = pic.aspect;
+
+    pic_cleanup_pic_info(&pic, 0);
+    if(DEBUG) fputs("\n", stderr);
+    return 1;
+}
+
+static void pic_open_file(pi, fname)
+    struct pic_info *pi;
+    char *fname;
+{
+    if((pi->fp = fopen(fname, "rb")) == NULL)
+	pic_file_error(pi, PIC_OPEN);
+    fseek(pi->fp, (size_t) 0, SEEK_END);
+    pi->fsize = ftell(pi->fp);
+    fseek(pi->fp, (size_t) 0, SEEK_SET);
+}
+
+static void pic_check_id(pi)
+    struct pic_info *pi;
+{
+    char buf[3];
+    if(fread(buf, (size_t) 3, (size_t) 1, pi->fp) != 1)
+	pic_file_error(pi, PIC_CORRUPT);
+    if(strncmp(buf, pic_id, (size_t) 3) != 0)
+	pic_error(pi, PIC_FORMAT);
+}
+
+static void pic_read_comment(pi, comm)
+    struct pic_info *pi;
+    char **comm;
+{
+    /* The comment field is like:
+     * comment-string ^Z dummy \0 \0
+     */
+    int max = -1, i = 0;
+    int c;
+
+    while(1){
+	if((c = fgetc(pi->fp)) == EOF)
+	    pic_file_error(pi, PIC_CORRUPT);
+	if(c == '\032')			/* 0x1a, '^Z' */
+	    break;
+	if(max < i){
+	    max += 32;
+	    *comm = pic_realloc(*comm, (size_t) max + 1, "pic_read_comment#1");
+	}
+	(*comm)[i++] = c;
+    }
+
+    if(max < i){
+	max++;
+	*comm = pic_realloc(*comm, (size_t) max + 1, "pic_read_comment#2");
+    }
+    (*comm)[i] = '\0';
+
+    while((c = fgetc(pi->fp)) != '\0'){	/* skip the dummy area */
+	if(c == EOF)
+	    pic_file_error(pi, PIC_CORRUPT);
+    }
+
+    if(fgetc(pi->fp) != '\0')		/* check the reserved byte */
+	pic_error(pi, PIC_SUPPORT);
+}
+
+static void pic_read_header(pi)
+    struct pic_info *pi;
+{
+    pi->mode   = pic_read_bits(pi, 4);
+    pi->type   = pic_read_bits(pi, 4);
+    pi->cbits  = pic_read_bits(pi, 16);
+    pi->width  = pic_read_bits(pi, 16);
+    pi->height = pic_read_bits(pi, 16);
+
+    /* machine-dependent setup. */
+    switch(pi->type){
+    case 0x0:				/* X68K */
+	if(pi->mode != 0)
+	    pic_error(pi, PIC_MODE);
+	switch(pi->cbits){
+	case 4:
+	    pi->aspect = 1.0;
+	    pi->g_bits = pi->r_bits = pi->b_bits = 5;
+	    pi->i_bits = 1;
+	    pi->cmapped = 1;
+	    break;
+
+	case 8:
+	    pi->aspect = 4.0 / 3.0;
+	    pi->g_bits = pi->r_bits = pi->b_bits = 5;
+	    pi->i_bits = 1;
+	    pi->cmapped = 1;
+	    break;
+
+	case 15:
+	    pi->aspect = 4.0 / 3.0;
+	    pi->g_bits = pi->r_bits = pi->b_bits = 5;
+	    pi->cached = 1;
+	    break;
+
+	case 16:
+	    pi->aspect = 4.0 / 3.0;
+	    pi->g_bits = pi->r_bits = pi->b_bits = 5;
+	    pi->i_bits = 1;
+	    pi->cached = 1;
+	    break;
+
+	default:
+	    pic_error(pi, PIC_NUM_COLORS);
+	}
+	break;
+
+    case 0x1:				/* PC-88VA */
+	if(pi->height > 1000)
+	    pic_error(pi, PIC_SIZE);
+	switch(pi->width * 1000 + pi->height){
+	case 640400:
+	case 640204:
+	case 640200:
+	case 320408:
+	case 320400:
+	case 320200:
+	    break;
+	default:
+	    pic_error(pi, PIC_SIZE);
+	}
+	pi->aspect = 400.0 / pi->height;
+	pi->aspect *= pi->width / 640.0;
+	if(pi->mode & 0x1)		/* HR mode */
+	    pi->aspect *= 2.0;
+	if(pi->mode & 0x2){		/* tiled 256 format */
+	    if(pi->cbits != 16)
+		pic_error(pi, PIC_NUM_COLORS);
+	    pi->tiled256 = 1;
+	}
+	switch(pi->cbits){
+	case 8:
+	    pi->g_bits = pi->r_bits = 3;
+	    pi->b_bits = 2;
+	    break;
+
+	case 12:
+	    pi->g_bits = pi->r_bits = pi->b_bits = 4;
+	    pi->cached = 1;
+	    break;
+
+	case 16:
+	    pi->g_bits = 6;
+	    pi->r_bits = pi->b_bits = 5;
+	    pi->cached = 1;
+	    break;
+
+	default:
+	    pic_error(pi, PIC_NUM_COLORS);
+	}
+	break;
+
+    case 0x2:				/* FM-TOWNS */
+	if(pi->cbits != 15)
+	    pic_error(pi, PIC_NUM_COLORS);
+	switch(pi->mode){
+	case 0x5:
+	case 0xc:
+	    break;
+	default:
+	    pic_error(pi, PIC_MODE);
+	}
+	pi->g_bits = pi->r_bits = pi->b_bits = 5;
+	pi->cached = 1;
+	break;
+
+    case 0x3:				/* MAC */
+	if(pi->cbits != 15)
+	    pic_error(pi, PIC_NUM_COLORS);
+	pi->r_bits = pi->g_bits = pi->b_bits = 5;
+	pi->inv_gr = 1;
+	break;
+
+    case 0xf:				/* misc */
+	{
+	    byte ah, al;
+
+	    switch(pi->mode){
+	    case 0x0:
+		break;
+	    case 0x1:
+		pi->aspect = 4.0 / 3.0;
+		break;
+	    case 0xf:
+		break;
+	    default:
+		pic_error(pi, PIC_MODE);
+	    }
+	    pic_read_bits(pi, 16);	/* x */
+	    pic_read_bits(pi, 16);	/* y */
+	    ah = pic_read_bits(pi, 8);
+	    al = pic_read_bits(pi, 8);
+	    if(ah > 0 && al > 0)
+		pi->aspect = (float) al / (int) ah;
+	    else if(pi->mode == 0xf)
+		pic_error(pi, PIC_ASPECT);
+	    switch(pi->cbits){
+	    case 4:
+	    case 8:
+		pi->g_bits = pi->r_bits = pi->b_bits = pic_read_bits(pi, 8);
+		pi->cmapped = 1;
+		break;
+
+	    case 12:
+		pi->g_bits = pi->r_bits = pi->b_bits = 4;
+		pi->cached = 1;
+		break;
+
+	    case 15:
+		pi->g_bits = pi->r_bits = pi->b_bits = 5;
+		pi->cached = 1;
+		break;
+
+	    case 16:
+		pi->g_bits = pi->r_bits = pi->b_bits = 5;
+		pi->i_bits = 1;
+		pi->cached = 1;
+		break;
+
+	    case 24:
+		pi->g_bits = pi->r_bits = pi->b_bits = 8;
+		pi->cached = 1;
+		break;
+
+	    case 32:
+		pic_error(pi, PIC_SUPPORT);
+		break;
+
+	    default:
+		pic_error(pi, PIC_NUM_COLORS);
+	    }
+	}
+	break;
+
+    default:
+	pic_error(pi, PIC_TYPE);
+    }
+
+    pi->numcols = 1 << pi->cbits;
+
+    /* read palette data */
+    if(pi->cmapped){
+	int i;
+	pi->cmap = pic_malloc((size_t) 3 * pi->numcols, "pic_read_header#1");
+	for(i = 0; i < pi->numcols; i++){
+	    data32 c = pic_read_rgb(pi);
+	    pi->cmap[i * 3    ] = c >> 16 & 0xff;
+	    pi->cmap[i * 3 + 1] = c >>  8 & 0xff;
+	    pi->cmap[i * 3 + 2] = c       & 0xff;
+	}
+    }
+
+    /* setup color code cache */
+    if(pi->cached)
+	pic_cache_init(pi);
+
+
+    pi->data = pic_malloc(sizeof(data32) * pi->width * pi->height,   // GRR POSSIBLE OVERFLOW / FIXME
+			  "pic_read_header#2");
+    {
+	int i;
+	for(i = 0; i < pi->width * pi->height; i++)
+	    pi->data[i] = 0xffffffff;
+    }
+
+    if(DEBUG)
+	pic_show_pic_info(pi);
+}
+
+/* The main routine to expand a PIC file. */
+static void pic_expand_data(pi)
+    struct pic_info *pi;
+{
+    int cnt;
+    data32 c;
+    pi->data[0] = c = 0;
+    for(cnt = -1; cnt < pi->width * pi->height; ){
+	int len = pic_expanding_read_len(pi);
+	cnt += len;
+	if(cnt < pi->width * pi->height){
+	    int x = cnt % pi->width;
+	    int y = cnt / pi->width;
+	    data32 c = pic_expanding_read_color(pi);
+	    pic_expanding_read_chain(pi, x, y, c);
+	}
+    }
+}
+
+static int pic_expanding_read_len(pi)
+    struct pic_info *pi;
+{
+    int len;
+    byte bits;
+    for(len = 2, bits = 1; pic_read_bits(pi, 1) == 1; bits++)
+	len <<= 1;
+    return len - 1 + pic_read_bits(pi, bits);
+}
+
+static data32 pic_expanding_read_color(pi)
+    struct pic_info *pi;
+{
+    if(pi->cached){
+	byte b = pic_read_bits(pi, 1);
+	if(b){
+	    return pic_cache_get_value(pi, (int) pic_read_bits(pi, 7));
+	}else{
+	    data32 c = pic_read_color_code(pi);
+	    pic_cache_add_value(pi, c);
+	    return c;
+	}
+    }
+    return pic_read_color_code(pi);
+}
+
+static void pic_expanding_read_chain(pi, x, y, c)
+    struct pic_info *pi;
+    int x, y;
+    data32 c;
+{
+    pi->data[y * pi->width + x] = c;
+    if(pic_read_bits(pi, 1) == 1){
+	int fin = 0;
+	while(!fin){
+	    switch(pic_read_bits(pi, 2)){
+	    case 1:	/* left */
+		pi->data[(++y) * pi->width + (--x)] = c;
+		break;
+	    case 2:	/* middle */
+		pi->data[(++y) * pi->width +    x ] = c;
+		break;
+	    case 3:	/* right */
+		pi->data[(++y) * pi->width + (++x)] = c;
+		break;
+	    case 0:	/* far or nothing */
+		if(pic_read_bits(pi, 1) == 0)
+		    fin = 1;
+		else{
+		    if(pic_read_bits(pi, 1) == 0)
+			pi->data[(++y) * pi->width + (x -= 2)] = c;
+		    else
+			pi->data[(++y) * pi->width + (x += 2)] = c;
+		}
+	    }
+	}
+    }
+}
+
+/*
+ * Make a picture from the expanded data.
+ */
+static void pic_make_xvpic(pi, xp, rp, gp, bp)
+    struct pic_info *pi;
+    byte **xp, *rp, *gp, *bp;
+{
+    if(pi->cmapped){
+	if(pi->tiled256)
+	    *xp = pic_malloc((size_t) pi->width * pi->height * 2,   // GRR POSSIBLE OVERFLOW / FIXME
+			     "pic_make_xvpic#1");
+	else
+	    *xp = pic_malloc((size_t) pi->width * pi->height,   // GRR POSSIBLE OVERFLOW / FIXME
+			     "pic_make_xvpic#2");
+    }else
+	*xp = pic_malloc((size_t) pi->width * pi->height * 3,   // GRR POSSIBLE OVERFLOW / FIXME
+			 "pic_make_xvpic#3");
+
+    if(pi->cmapped){
+	int i;
+
+	for(i = 0; i < pi->numcols; i++){
+	    rp[i] = pi->cmap[i * 3    ];
+	    gp[i] = pi->cmap[i * 3 + 1];
+	    bp[i] = pi->cmap[i * 3 + 2];
+	}
+
+	if(pi->tiled256){
+	    int pic_idx = 0, dat_idx;
+	    data16 col = 0;
+	    for(dat_idx = 0; dat_idx < pi->width * pi->height; dat_idx++){
+		if(pi->data[dat_idx] != 0xffffffff)
+		    col = pi->data[dat_idx];
+		(*xp)[pic_idx++] = col      & 0xff;
+		(*xp)[pic_idx++] = col >> 8 & 0xff;
+		dat_idx++;
+	    }
+	}else{
+	    int pic_idx = 0, dat_idx;
+	    byte col = 0;
+	    for(dat_idx = 0; dat_idx < pi->width * pi->height; dat_idx++){
+		if(pi->data[dat_idx] != 0xffffffff)
+		    col = pi->data[dat_idx];
+		(*xp)[pic_idx++] = col;
+	    }
+	}
+    }else{
+	int pic_idx = 0, dat_idx;
+	byte r = 0, g = 0, b = 0;
+	for(dat_idx = 0; dat_idx < pi->width * pi->height; dat_idx++){
+	    if(pi->data[dat_idx] != 0xffffffff){
+		data32 col = pi->data[dat_idx];
+		r = col >> 16 & 0xff;
+		g = col >>  8 & 0xff;
+		b = col       & 0xff;
+	    }
+	    (*xp)[pic_idx++] = r;
+	    (*xp)[pic_idx++] = g;
+	    (*xp)[pic_idx++] = b;
+	}
+    }
+}
+
+
+/* The main routine to write PIC file. */
+int WritePIC(fp, pic0, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle,
+	     comment)
+    FILE *fp;
+    byte *pic0;
+    int ptype, w, h;
+    byte *rmap, *gmap, *bmap;
+    int numcols, colorstyle;
+    char *comment;
+{
+    struct pic_info pic;
+    int e;
+
+    if(DEBUG) fputs("WritePIC:\n", stderr);
+
+    pic_init_info(&pic);
+    pic.fp = fp;
+    pic.width  = w;
+    pic.height = h;
+    pic.writing_grey = (colorstyle == F_GREYSCALE);
+    if(ptype != PIC24){		/* PIC8  */
+	pic.cmapped = 1;
+	pic.cached  = 0;
+	pic.cbits   = 8;
+	pic.g_bits  =
+	pic.r_bits  =
+	pic.b_bits  = 8;
+	pic.i_bits  = 0;
+	pic.numcols = numcols;
+    }else{			/* PIC24 */
+	pic.cmapped = 0;
+	pic.cached  = 1;
+	pic.cbits   = 24;
+	pic.g_bits  =
+	pic.r_bits  =
+	pic.b_bits  = 8;
+	pic.i_bits  = 0;
+	pic.numcols = 1 << 24;
+	pic_cache_init(&pic);
+    }
+
+    if((e = setjmp(pic.jmp)) != 0){
+	/* When an error occurs while writing, comes here. */
+	pic_cleanup_pic_info(&pic, 1);
+	if(DEBUG) fputs("\n", stderr);
+	return -1;
+    }
+
+    pic_write_id(&pic);
+    pic_write_comment(&pic, comment);
+    pic_write_header(&pic);
+    if(pic.cmapped)
+	pic_write_palette(&pic, rmap, gmap, bmap);
+    pic_make_sparse_data(&pic, pic0);
+    pic_write_data(&pic);
+    pic_write_bits(&pic, 0, 8);
+
+    pic_cleanup_pic_info(&pic, 1);
+    if(DEBUG) fputs("\n", stderr);
+    return 0;
+}
+
+static void pic_write_id(pi)
+    struct pic_info *pi;
+{
+    if(fwrite("PIC", (size_t) 3, (size_t) 1, pi->fp) != 1)
+	pic_file_error(pi, PIC_WRITE);
+}
+
+static void pic_write_comment(pi, comm)
+    struct pic_info *pi;
+    char *comm;
+{
+    if(comm){
+	while(*comm){
+	    int c = *comm;
+	    if(c == '\032')
+		c = ' ';
+	    if(fputc(*comm, pi->fp) == EOF)
+		pic_file_error(pi, PIC_WRITE);
+	    comm++;
+	}
+    }
+    /* write ^Z, 0, and reserved. */
+    if(fwrite("\032\0\0", (size_t)3, (size_t) 1, pi->fp) != 1)
+	pic_file_error(pi, PIC_WRITE);
+}
+
+static void pic_write_header(pi)
+    struct pic_info *pi;
+{
+    if(DEBUG) pic_show_pic_info(pi);
+    pic_write_bits(pi, (data32) 0, 4);			/* mode:  1:1 */
+    pic_write_bits(pi, (data32) 0xf, 4);		/* type: misc */
+    pic_write_bits(pi, (data32) pi->cbits, 16);		/* bits */
+    pic_write_bits(pi, (data32) pi->width, 16);		/* width */
+    pic_write_bits(pi, (data32) pi->height, 16);	/* height */
+    pic_write_bits(pi, (data32) 0xffff, 16);		/* x: unused */
+    pic_write_bits(pi, (data32) 0xffff, 16);		/* y: unused */
+    pic_write_bits(pi, (data32) 0x0101, 16);		/* real aspect */
+}
+
+static void pic_write_palette(pi, r, g, b)
+    struct pic_info *pi;
+    byte *r, *g, *b;
+{
+    int i;
+    data32 rgb = 0;
+    pic_write_bits(pi, (data32) pi->g_bits, 8);
+    for(i = 0; i < pi->numcols; i++){
+	rgb = (data32) *r++ << 16 | (data32) *g++ << 8 | (data32) *b++;
+	pic_write_rgb(pi, rgb);
+    }
+    for( ; i < 256; i++)
+	pic_write_rgb(pi, rgb);
+}
+
+static void pic_make_sparse_data(pi, dat)
+    struct pic_info *pi;
+    byte *dat;
+{
+    int i;
+    data32 c;
+
+    pi->data = pic_malloc(sizeof(data32) * pi->width * pi->height,   // GRR POSSIBLE OVERFLOW / FIXME
+			  "pic_make_sparse_data");
+
+    if(pi->cmapped){
+	c = 0;
+	for(i = 0; i < pi->width * pi->height; i++){
+	    if(c != dat[i])
+		c = pi->data[i] = dat[i];
+	    else
+		pi->data[i] = 0xffffffff;
+	}
+    }else{
+	int j = 0;
+	c = 0;
+	for(i = 0; i < pi->width * pi->height; i++){
+	    data32 r, g, b, t;
+	    r = dat[j++];
+	    g = dat[j++];
+	    b = dat[j++];
+	    t = r << 16 | g << 8 | b;
+	    if(c != t)
+		c = pi->data[i] = t;
+	    else
+		pi->data[i] = 0xffffffff;
+	}
+    }
+}
+
+static void pic_write_data(pi)
+    struct pic_info *pi;
+{
+    int i;
+    int max = pi->width * pi->height;
+    data32 c = 0;
+
+    i = -1;
+    while(i < max){
+	int j;
+	for(j = i + 1; j < max; j++){
+	    if(pi->data[j] != 0xffffffff)
+		break;
+	}
+	pic_write_length(pi, (data32) j - i);
+	i = j;
+	if(i < max){
+	    pic_write_color(pi, c = pi->data[i]);
+	    pic_write_chain(pi, i % pi->width, i / pi->width, c);
+	}
+    }
+}
+
+static void pic_write_length(pi, len)
+    struct pic_info *pi;
+    data32 len;
+{
+    int bits = 0;	/* leading 1's */
+    int max = 2;
+
+    while(len > max){
+	max = (max + 1) * 2;
+	bits++;
+    }
+    pic_write_bits(pi, 0xffffffff, bits);
+    pic_write_bits(pi, 0, 1);
+    pic_write_bits(pi, len - max / 2, bits + 1);
+}
+
+static void pic_write_color(pi, c)
+    struct pic_info *pi;
+    data32 c;
+{
+    if(pi->cached){
+	int idx = pic_cache_lookup(pi, c);
+	if(idx < 0){	/* not found */
+	    pic_write_bits(pi, 0, 1);
+	    pic_write_color_code(pi, c);
+	    pic_cache_add_value(pi, c);
+	}else{		/* found */
+	    pic_write_bits(pi, (data32) 0xffffffff, 1);
+	    pic_write_bits(pi, (data32) idx, 7);
+	}
+    }else
+	pic_write_color_code(pi, c);
+}
+
+static void pic_write_chain(pi, x, y, c)
+    struct pic_info *pi;
+    int x, y;
+    data32 c;
+{
+    int ctr = (y + 1) * pi->width + x;
+
+    if(y < pi->height - 1 &&
+       (                      pi->data[ctr    ] == c  ||
+	(x > 0             && pi->data[ctr - 1] == c) ||
+	(x < pi->width - 1 && pi->data[ctr + 1] == c) ||
+	(x > 1             && pi->data[ctr - 2] == c) ||
+	(x < pi->width - 2 && pi->data[ctr + 2] == c))){
+	pic_write_bits(pi, 1, 1);
+	while(++y < pi->height){
+	    if(pi->data[ctr] == c){				  /* center */
+		pic_write_bits(pi, 2, 2);
+		pi->data[ctr] = 0xffffffff;
+		ctr += pi->width;
+	    }else if(x > 0 && pi->data[ctr - 1] == c){		  /* left */
+		pic_write_bits(pi, 1, 2);
+		pi->data[ctr - 1] = 0xffffffff;
+		ctr += pi->width - 1;
+	    }else if(x < pi->width - 1 && pi->data[ctr + 1] == c){/* right */
+		pic_write_bits(pi, 3, 2);
+		pi->data[ctr + 1] = 0xffffffff;
+		ctr += pi->width + 1;
+	    }else if(x > 1 && pi->data[ctr - 2] == c){		  /* 2-left */
+		pic_write_bits(pi, 2, 4);
+		pi->data[ctr - 2] = 0xffffffff;
+		ctr += pi->width - 2;
+	    }else if(x < pi->width - 2 && pi->data[ctr + 2] == c){/* 2-right */
+		pic_write_bits(pi, 3, 4);
+		pi->data[ctr + 2] = 0xffffffff;
+		ctr += pi->width + 2;
+	    }else						  /* nothing */
+		break;
+	}
+	pic_write_bits(pi, 0, 3);
+    }else
+	pic_write_bits(pi, 0, 1);
+}
+
+
+/*
+ * These 4 functions read or write a color.
+ *
+ * pic_read_rgb:
+ *	reads an RGB. Each bit length is [rgb]_bits, but
+ *	it is expanded to 8bits when returned.
+ *
+ * pic_read_color_code:
+ *	reads a color code, whose length is cbits.
+ *	It is the index to the colormap or RGB itself.
+ *
+ * pic_write_rgb:
+ *	writes an RGB value.
+ *
+ * pic_write_color_code:
+ *	writes a color code.
+ */
+static data32 pic_read_rgb(pi)
+    struct pic_info *pi;
+{
+    int rb = pi->r_bits, gb = pi->g_bits, bb = pi->b_bits;
+    byte r, g, b;
+    if(pi->inv_gr){
+	r = pic_read_bits(pi, rb);
+	g = pic_read_bits(pi, gb);
+    }else{
+	g = pic_read_bits(pi, gb);
+	r = pic_read_bits(pi, rb);
+    }
+    b = pic_read_bits(pi, bb);
+    if(pi->i_bits){
+	byte i;
+	i = pic_read_bits(pi, pi->i_bits);
+	r = r << pi->i_bits | i;
+	g = g << pi->i_bits | i;
+	b = b << pi->i_bits | i;
+	rb += pi->i_bits;
+	gb += pi->i_bits;
+	bb += pi->i_bits;
+    }
+    r = pic_pad_bit(rb, r);
+    g = pic_pad_bit(gb, g);
+    b = pic_pad_bit(bb, b);
+
+    return (data32) r << 16 | (data32) g << 8 | (data32) b;
+}
+
+static data32 pic_read_color_code(pi)
+    struct pic_info *pi;
+{
+    if(pi->cmapped)
+	return pic_read_bits(pi, pi->cbits);
+    return pic_read_rgb(pi);
+}
+
+static void pic_write_rgb(pi, rgb)
+    struct pic_info *pi;
+    data32 rgb;
+{
+    byte r = rgb >> 16;
+    byte g = rgb >> 8;
+    byte b = rgb;
+    if(pi->writing_grey)
+	r = g = b = MONO(r, g, b);
+    pic_write_bits(pi, g, pi->g_bits);
+    pic_write_bits(pi, r, pi->r_bits);
+    pic_write_bits(pi, b, pi->b_bits);
+}
+
+static void pic_write_color_code(pi, code)
+    struct pic_info *pi;
+    data32 code;
+{
+    if(pi->cmapped){
+	pic_write_bits(pi, code, pi->cbits);
+    }else{
+	pic_write_rgb(pi, code);
+    }
+}
+
+
+/*
+ * These pic_cache_* functions are an implementation of the color cache.
+ *
+ * pic_cache_init:
+ *	initializes the cache.
+ *
+ * pic_cache_get_value:
+ *	gets a color indexed by the argument `idx'.
+ *	It updates the `most recently used' time.
+ *
+ * pic_cache_add_value:
+ *	adds a color to the top of the cache list.
+ */
+static void pic_cache_init(pi)
+    struct pic_info *pi;
+{
+    int i;
+    pi->cache.node = pic_malloc(sizeof(struct cachenode_t) * 128,
+				"pic_cache_init");
+    for(i = 0; i < 128; i++){
+	pi->cache.node[i].newer = i + 1;
+	pi->cache.node[i].older = i - 1;
+	pi->cache.node[i].dat = 0;
+    }
+    pi->cache.node[  0].older = 127;
+    pi->cache.node[127].newer = 0;
+    pi->cache.newest = 0;
+}
+
+static data32 pic_cache_get_value(pi, idx)
+    struct pic_info *pi;
+    int idx;
+{
+    struct cachenode_t *p = pi->cache.node;
+    int n = pi->cache.newest;
+    if(n != idx){
+	p[p[idx].newer].older = p[idx].older;
+	p[p[idx].older].newer = p[idx].newer;
+
+	p[p[n].newer].older = idx;
+	p[idx].newer = p[n].newer;
+	p[n].newer = idx;
+	p[idx].older = n;
+
+	pi->cache.newest = idx;
+    }
+    return pi->cache.node[idx].dat;
+}
+
+static void pic_cache_add_value(pi, dat)
+    struct pic_info *pi;
+    data32 dat;
+{
+    pi->cache.newest = pi->cache.node[pi->cache.newest].newer;
+    pi->cache.node[pi->cache.newest].dat = dat;
+}
+
+static int pic_cache_lookup(pi, dat)
+    struct pic_info *pi;
+    data32 dat;
+{
+    int i;
+    for(i = 0; i < 128; i++){
+	if(pi->cache.node[i].dat == dat){
+	    pic_cache_get_value(pi, i);
+	    return i;
+	}
+    }
+    return -1;
+}
+
+
+/*
+ * These pic_{read,write}_bits functions access the bit stream.
+ * pic_read_bits:
+ *	reads the specified bits from the file.
+ *
+ * pic_write_bits:
+ *	writes the specified bits to the file.
+ */
+static data32 pic_read_bits(pi, bits)
+    struct pic_info *pi;
+    int bits;
+{
+    data32 r = 0;
+
+    while(bits > 0){
+	while(pi->bs.rest > 0 && bits > 0){
+	    r = (r << 1) | (pi->bs.cur & 0x80 ? 1 : 0);
+	    pi->bs.cur <<= 1;
+	    pi->bs.rest--;
+	    bits--;
+	}
+	if(bits > 0){
+	    int c;
+	    if((c = fgetc(pi->fp)) == EOF){
+		pic_file_warning(pi, PIC_CORRUPT);
+		c = 0;
+	    }
+	    pi->bs.cur  = c;
+	    pi->bs.rest = 8;
+	}
+    }
+
+    return r;
+}
+
+static void pic_write_bits(pi, dat, bits)
+    struct pic_info *pi;
+    data32 dat;
+    int bits;
+{
+    data32 dat_mask = 1 << (bits - 1);
+    while(bits > 0){
+	while(pi->bs.rest < 8 && bits > 0){
+	    pi->bs.cur <<= 1;
+	    if(dat & dat_mask)
+		pi->bs.cur |= 1;
+	    pi->bs.rest++;
+	    bits--;
+	    dat_mask >>= 1;
+	}
+	if(pi->bs.rest >= 8){
+	    if(fputc((int)pi->bs.cur, pi->fp) == EOF)
+		pic_error(pi, PIC_WRITE);
+	    pi->bs.cur  = 0;
+	    pi->bs.rest = 0;
+	}
+    }
+}
+
+
+/*
+ * This function extends sub-8-bit data to 8-bit data using bit-replication.
+ */
+static byte pic_pad_bit(bits, dat)
+    int bits;
+    data32 dat;
+{
+    switch(bits){
+    case 1:
+	if(dat & 1)
+	    dat = 0xff;
+	else
+	    dat = 0;
+	break;
+    case 2:
+	dat = dat << 6 | dat << 4 | dat << 2 | dat;
+	break;
+    case 3:
+	dat = dat << 5 | dat << 2 | dat >> 1;
+	break;
+    case 4:
+	dat = dat << 4 | dat;
+	break;
+    case 5:
+	dat = dat << 3 | dat >> 2;
+	break;
+    case 6:
+	dat = dat << 2 | dat >> 4;
+	break;
+    case 7:
+	dat = dat << 1 | dat >> 6;
+    }
+
+    return dat;
+}
+
+/*
+ * These functions initialize or clean up structures.
+ * pic_init_info:
+ *	initializes a pic_info structure.
+ * pic_cleanup_pic_info:
+ *	cleans up a pic_info structure.
+ * pic_cleanup_pinfo:
+ *	cleans up a PICINFO structure.
+ */
+static void pic_init_info(pi)
+    struct pic_info *pi;
+{
+    pi->fp = NULL;
+    pi->bs.rest = 0;
+    pi->bs.cur = '\0';
+    pi->type = pi->mode = 0;
+    pi->width = pi->height = 0;
+    pi->aspect = 1.0;
+    pi->cbits = 0;
+    pi->cmapped = pi->cached = 0;
+    pi->cache.node = NULL;
+    pi->cmap = NULL;
+    pi->g_bits = pi->r_bits = pi->b_bits = pi->i_bits = 0;
+    pi->inv_gr = 0;
+    pi->tiled256 = 0;
+    pi->numcols = 0;
+    pi->writing_grey = 0;
+}
+
+static void pic_cleanup_pic_info(pi, writing)
+    struct pic_info *pi;
+    int writing;
+{
+    if(!writing && pi->fp)
+	fclose(pi->fp);
+    if(pi->cmap)
+	free(pi->cmap);
+    if(pi->cache.node)
+	free(pi->cache.node);
+    if(pi->data)
+	free(pi->data);
+    pi->fp = NULL;
+    pi->cmap = NULL;
+    pi->cache.node = NULL;
+    pi->data = NULL;
+}
+
+static void pic_cleanup_pinfo(pinfo)
+    PICINFO *pinfo;
+{
+    if(pinfo->pic){
+	free(pinfo->pic);
+	pinfo->pic = NULL;
+    }
+    if(pinfo->comment){
+	free(pinfo->comment);
+	pinfo->comment = NULL;
+    }
+}
+
+/*
+ * Error Handlers.
+ * pic_memory_error:
+ *	shows an error message and terminates.
+ * pic_error:
+ *	shows a non-file error message and jumps to the entry for errors.
+ * pic_file_error:
+ *	shows a file error message and jumps to the entry for errors.
+ * pic_file_warning:
+ *	shows a file warning message.
+ */
+static void pic_memory_error(scm, fn)
+    char *scm, *fn;
+{
+    char buf[128];
+    sprintf(buf, "%s: can't allocate memory. (%s)", scm, fn);
+    FatalError(buf);
+}
+
+static void pic_error(pi, mn)
+    struct pic_info *pi;
+    int mn;
+{
+    SetISTR(ISTR_WARNING, "%s", pic_msgs[mn]);
+    longjmp(pi->jmp, 1);
+}
+
+static void pic_file_error(pi, mn)
+    struct pic_info *pi;
+    int mn;
+{
+    if(feof(pi->fp))
+	SetISTR(ISTR_WARNING, "%s (end of file)", pic_msgs[mn]);
+    else
+	SetISTR(ISTR_WARNING, "%s (%s)", pic_msgs[mn], ERRSTR(errno));
+    longjmp(pi->jmp, 1);
+}
+
+static void pic_file_warning(pi, mn)
+    struct pic_info *pi;
+    int mn;
+{
+    if(feof(pi->fp))
+	SetISTR(ISTR_WARNING, "%s (end of file)", pic_msgs[mn]);
+    else
+	SetISTR(ISTR_WARNING, "%s (%s)", pic_msgs[mn], ERRSTR(errno));
+}
+
+static void pic_show_pic_info(pi)
+    struct pic_info *pi;
+{
+    fprintf(stderr, "  file size: %ld.\n", pi->fsize);
+
+    fputs("  machine: ", stderr);
+    switch(pi->type){
+    case 0x0:
+	fputs("X68k", stderr);
+	break;
+    case 0x1:
+	fputs("PC-88VA", stderr);
+	if(pi->mode & 1)
+	    fputs(",HR", stderr);
+	if(pi->mode & 2)
+	    fputs(",tiled256", stderr);
+	break;
+    case 0x2:
+	fprintf(stderr,
+		"FM-TOWNS,%s-resolution", pi->mode == 5 ? "low" : "high");
+	break;
+    case 0x3:
+	fputs("Macintosh", stderr);
+	break;
+    case 0xf:
+	fputs("misc", stderr);
+    }
+    fputs("\n", stderr);
+
+    fprintf(stderr, "  image size: %dx%d\n", pi->width, pi->height);
+    fprintf(stderr, "  aspect: %f\n", pi->aspect);
+    fprintf(stderr, "  cache: %s\n", pi->cached ? "on" : "off");
+    fprintf(stderr, "  colormap: %s\n", pi->cmapped ? "on" : "off");
+    fprintf(stderr, "  number of color bits: %d\n", pi->cbits);
+    fprintf(stderr, "  number of RGB bits: R%d,G%d,B%d,I%d\n",
+	   pi->r_bits, pi->g_bits, pi->b_bits, pi->i_bits);
+    fprintf(stderr, "  inverted G&R: %s\n", pi->inv_gr ? "true" : "false");
+    fprintf(stderr, "  number of colors: %d\n", pi->numcols);
+}
+
+/* Memory related routines. */
+static void *pic_malloc(n, fn)
+    size_t n;
+    char *fn;
+{
+    void *r = (void *) malloc(n);
+    if(r == NULL)
+	pic_memory_error("malloc", fn);
+    return r;
+}
+
+static void *pic_realloc(p, n, fn)
+    void *p;
+    size_t n;
+    char *fn;
+{
+    void *r = (p == NULL) ? (void *) malloc(n) : (void *) realloc(p, n);
+    if(r == NULL)
+	pic_memory_error("realloc", fn);
+    return r;
+}
+#endif /* HAVE_PIC */
diff -ruN xv-3.10a-bugfixes/xvpic2.c xv-3.10a-enhancements/xvpic2.c
--- xv-3.10a-bugfixes/xvpic2.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvpic2.c	2005-04-17 22:56:07.000000000 -0700
@@ -0,0 +1,3608 @@
+/*
+ * $Id: xvpic2.c,v 2.9.1.14 1995/04/24 15:34:15 ikeyan Exp $
+ * xvpic2.c - load and save routines for `PIC2' format pictures.
+ *
+ *
+ * Outline
+ * =======
+ * xvpic2.c supports the PIC2 format image file. It is used some
+ * Japanese personal computer users.
+ *
+ * The PIC2 format is designed by A.Yanagisawa. It is an excellent
+ * format except for its encode/decode speed. ;-)
+ *
+ * The features of the PIC2 format:
+ * - Powerful header information (included author, filename, title,
+ *   saver, product number, created date and comment).
+ * - Reversible compression, and very high compression ratio (in many
+ *   cases, a higher compression ratio than the JPEG compression;
+ *   because of its compression method, PIC2 is especially good at
+ *   pictures like cell animation).
+ * - Can handle full-color (24 bits) image.
+ * - Can include multi image blocks into one PIC2 file.
+ * - Have four different block format (P2SS, P2SF, P2BM and
+ *   P2BI). P2SS format uses arithmetic compression for storing
+ *   data. P2SF uses normal run-length compression. P2BM and P2BI is
+ *   raw image format. Select any one according to the situation.
+ *
+ * Explanation of the PIC2 compression:
+
+ * - In the first place, try to record pixel color, uses color caches
+ *   which keep some recent colors, and formed according to color's
+ *   frequency.  PIC2 has some color cache spaces that are switched by
+ *   upper pixel value of current pixel.  If cache is hit, record
+ *   that.
+ * - Unfortunately, in the case of color cache didn't hit, record the
+ *   difference from the value estimated with the value of upper and
+ *   left pixel of current pixel (similar to PNG's AVG predictor).
+ * - And extract image's color chain if exist, and record that (it
+ *   results in image's outline).
+ * - In all cases, arithmetic compression is used in the final stage
+ *   before writing the file, which in theory produces the ideal
+ *   compression ratio (P2SS).
+ *
+ * Features
+ * ========
+ * - Support 3,6,9,12,15,18,21,24bit PIC2 format (Load/Save).
+ * - Support all image block formats of PIC2 (Load/Save).
+ * - Support multi block PIC2 file (Load/Save).
+ *
+ *
+ * Bugs
+ * ====
+ * - Unsupport 8bit PIC2 image file.
+ *
+ * If you find other bugs (surely exist :-)), send me bug-report.
+ *
+ *
+ * Author
+ * ======
+ * IKEMOTO Masahiro <ikeyan@airlab.cs.ritsumei.ac.jp>
+ */
+
+#define PIC2_IGNORE_UNUSED_FUNCTIONS
+#define NEEDSDIR
+
+#include "xv.h"
+#include <setjmp.h>
+
+#ifdef HAVE_PIC2
+
+typedef unsigned long pixel;
+
+#define pic2_cextoshort(addr) ( \
+    (((short) (((byte *) addr)[0])) <<  8) | \
+    ( (short) (((byte *) addr)[1])) \
+)
+#define pic2_cextolong(addr) ( \
+    (((long)  (((byte *) addr)[0])) << 24) | \
+    (((long)  (((byte *) addr)[1])) << 16) | \
+    (((long)  (((byte *) addr)[2])) <<  8) | \
+    ( (long)  (((byte *) addr)[3])) \
+)
+#define pic2_shorttocex(addr, n) { \
+    ((byte *) addr)[0] = (((unsigned short) (n) >>  8) & 0xff); \
+    ((byte *) addr)[1] = ( (unsigned short) (n)        & 0xff); \
+}
+#define pic2_longtocex(addr, n) { \
+    ((byte *) addr)[0] = (((unsigned long)  (n) >> 24) & 0xff); \
+    ((byte *) addr)[1] = (((unsigned long)  (n) >> 16) & 0xff); \
+    ((byte *) addr)[2] = (((unsigned long)  (n) >>  8) & 0xff); \
+    ((byte *) addr)[3] = ( (unsigned long)  (n)        & 0xff); \
+}
+#define pic2_shift_bits(b, n) (((n) > 0) ? ((b) << (n)) : ((b) >> -(n)))
+
+#define PIC2_READ_MODE		0
+#define PIC2_WRITE_MODE		1
+
+#define PIC2_ARITH_CACHE	32
+#define PIC2_ARITH_CONTEXT	128
+#define PIC2_FAST_CACHE		64
+
+#define PIC2_HEADER_SIZE	124
+#define PIC2_BLOCK_HEADER_SIZE	26
+
+struct pic2_header {
+    char magic[4];
+    char name[18];
+    char subtitle[8];
+    char crlf0[2];
+    char title[30];
+    char crlf1[2];
+    char saver[30];
+    char crlf2[2];
+    char eof[1];
+    char reserve0[1];
+    short flag;
+    short no;
+    long time;
+    long size;
+    short depth;
+    short x_aspect;
+    short y_aspect;
+    short x_max;
+    short y_max;
+    long reserve1;
+};
+
+struct pic2_block {
+    char id[4];
+    long size;
+    short flag;
+    short x_wid;
+    short y_wid;
+    short x_offset;
+    short y_offset;
+    long opaque;
+    long reserve;
+};
+
+struct pic2_info {
+    jmp_buf jmp;
+    FILE *fp;
+    struct {
+	int rest;
+	byte cur;
+	int bits;
+	char zero;
+    }bs;
+    long fsize;
+    struct pic2_header *header;
+    struct pic2_block *block;
+    int n_pal;
+    int pal_bits;
+    byte pal[256][3];
+    char *comment;
+    char mode;
+    long next_pos;
+    long block_pos;
+    short x_max;
+    short y_max;
+    int ynow;
+    byte *buf;
+    pixel *vram_prev;
+    pixel *vram_now;
+    pixel *vram_next;
+    short *flag_now;
+    short *flag_next;
+    short *flag2_now;
+    short *flag2_next;
+    short *flag2_next2;
+    pixel (*cache)[PIC2_ARITH_CACHE];
+    unsigned short *cache_pos;
+    unsigned short *mulu_tab;
+    long aa;
+    long cc;
+    long dd;
+    char cache_hit_c;
+    int (*next_line) PARM((struct pic2_info *, pixel **));
+    char writing_grey;
+    char pagebname[64];
+    int pnum;
+};
+
+static void pic2_open_file             PARM((struct pic2_info*,char*));
+static void pic2_read_header           PARM((struct pic2_info*));
+static void pic2_read_block_header1    PARM((struct pic2_info*));
+static void pic2_read_block_header2    PARM((struct pic2_info*));
+static short pic2_arith_decode_bit     PARM((struct pic2_info*,int));
+static short pic2_arith_decode_nn      PARM((struct pic2_info*,int));
+static void pic2_arith_expand_chain    PARM((struct pic2_info*,int,int,pixel));
+static short pic2_arith_get_number     PARM((struct pic2_info*,int,int));
+static pixel pic2_arith_read_color     PARM((struct pic2_info*,int));
+static int pic2_arith_expand_line      PARM((struct pic2_info*,pixel**));
+static int pic2_arith_loader_init      PARM((struct pic2_info*));
+static int pic2_fast_read_length       PARM((struct pic2_info*));
+static void pic2_fast_expand_chain     PARM((struct pic2_info*,int,pixel));
+static pixel pic2_fast_read_color      PARM((struct pic2_info*,pixel));
+static int pic2_fast_expand_line       PARM((struct pic2_info*,pixel**));
+static int pic2_fast_loader_init       PARM((struct pic2_info*));
+static int pic2_beta_expand_line       PARM((struct pic2_info*,pixel**));
+static int pic2_beta_loader_init       PARM((struct pic2_info*));
+static void pic2_make_xvpic            PARM((struct pic2_info*,byte**,
+					     byte*,byte*,byte*));
+static void pic2_make_pagefile         PARM((struct pic2_info*,char*,int));
+static void pic2_setup_pic2_info       PARM((struct pic2_info*,
+					     char*,char*,char*,char*,
+					     int,int,int,int,int,int,char *));
+static void pic2_append                PARM((struct pic2_info*));
+static void pic2_write_header1         PARM((struct pic2_info*));
+static void pic2_write_header2         PARM((struct pic2_info*));
+static void pic2_write_block_header    PARM((struct pic2_info*));
+static void pic2_arith_write_zero_bit  PARM((struct pic2_info*));
+static void pic2_arith_flush_bit_buf   PARM((struct pic2_info*));
+static void pic2_arith_carry_bit       PARM((struct pic2_info*));
+static void pic2_arith_encode_bit      PARM((struct pic2_info*,int,int));
+static void pic2_arith_encode_nbyte    PARM((struct pic2_info*,int,int,int));
+static void pic2_arith_encode_nn       PARM((struct pic2_info*,int,int));
+static void pic2_arith_press_chain     PARM((struct pic2_info*,int));
+static void pic2_arith_put_number      PARM((struct pic2_info*,int,int,int));
+static void pic2_arith_write_color     PARM((struct pic2_info*,int));
+static void pic2_arith_press_line2     PARM((struct pic2_info*));
+static int pic2_arith_press_line       PARM((struct pic2_info*,pixel**));
+static int pic2_arith_saver_init       PARM((struct pic2_info*,pixel**));
+static void pic2_fast_write_length     PARM((struct pic2_info*,int));
+static void pic2_fast_press_chain      PARM((struct pic2_info*,int));
+static void pic2_fast_press_chain2     PARM((struct pic2_info*,int));
+static void pic2_fast_flush_chain      PARM((struct pic2_info*));
+static void pic2_fast_write_color      PARM((struct pic2_info*,int));
+static void pic2_fast_press_line2      PARM((struct pic2_info*));
+static int pic2_fast_press_line        PARM((struct pic2_info*,pixel**));
+static int pic2_fast_saver_init        PARM((struct pic2_info*,pixel**));
+static int pic2_beta_press_line        PARM((struct pic2_info*,pixel**));
+static int pic2_beta_saver_init        PARM((struct pic2_info*,pixel**));
+static void pic2_write_data            PARM((struct pic2_info*,byte*,
+					     int,int,int,int,int,
+					     byte*,byte*,byte*,int,int));
+static int pic2_next_line              PARM((struct pic2_info*,pixel**));
+static int pic2_next_block             PARM((struct pic2_info*));
+static int pic2_find_block             PARM((struct pic2_info*));
+static int pic2_load_block             PARM((struct pic2_info*));
+static int pic2_save_block             PARM((struct pic2_info*,pixel**,
+					     int,int,int,int,char*,pixel));
+#ifndef PIC2_IGNORE_UNUSED_FUNCTIONS
+static void pic2_read_palette          PARM((struct pic2_info*,
+					     byte*,byte*,byte*));
+static void pic2_write_palette         PARM((struct pic2_info*,int,int,
+					     byte*,byte*,byte*));
+#endif /* !PIC2_IGNORE_UNUSED_FUNCTIONS */
+static byte pic2_convert_color_bits    PARM((int,int,int));
+static byte pic2_pad_color_bits        PARM((int,int,int));
+static byte pic2_reduce_color_bits     PARM((int,int,int));
+static pixel pic2_exchange_rg          PARM((pixel,int));
+static void pic2_handle_para           PARM((struct pic2_info*,int));
+static int pic2_alloc_buffer           PARM((struct pic2_info*));
+static void pic2_free_buffer           PARM((struct pic2_info*));
+static long pic2_seek_file             PARM((struct pic2_info*,long,int));
+static long pic2_tell_file             PARM((struct pic2_info*));
+static int pic2_read_file              PARM((struct pic2_info*,void*,size_t));
+static long pic2_read_long             PARM((struct pic2_info*));
+static short pic2_read_short           PARM((struct pic2_info*));
+static char pic2_read_char             PARM((struct pic2_info*));
+static int pic2_write_file             PARM((struct pic2_info*,void*,size_t));
+static int pic2_write_long             PARM((struct pic2_info*,long));
+static int pic2_write_short            PARM((struct pic2_info*,int));
+static int pic2_write_char             PARM((struct pic2_info*,int));
+static unsigned long pic2_read_bits    PARM((struct pic2_info*,int));
+static void pic2_write_bits            PARM((struct pic2_info*,
+					     unsigned long,int));
+static void pic2_flush_bits            PARM((struct pic2_info*));
+static void pic2_memory_error          PARM((char*,char*));
+static void pic2_error                 PARM((struct pic2_info*,int));
+static void pic2_file_error            PARM((struct pic2_info*,int));
+static void pic2_init_info             PARM((struct pic2_info*));
+static void pic2_cleanup_pic2_info     PARM((struct pic2_info*,int));
+static void pic2_cleanup_pinfo         PARM((PICINFO*));
+static void pic2_show_pic2_info        PARM((struct pic2_info*));
+static char *pic2_strncpy              PARM((char*,char*,size_t));
+static void *pic2_malloc               PARM((size_t,char*));
+static void *pic2_new                  PARM((size_t,char*));
+
+static int WritePIC2                   PARM((FILE*,byte*,int,int,int,
+					     byte*,byte*,byte*,int,int,char*,
+					     int,int,int,int,int,char*));
+
+static char *pic2_id = "P2DT";
+
+/* Error Messages */
+static char *pic2_msgs[] = {
+    NULL,
+#define PIC2_OPEN 1
+    "can't open file.",
+#define PIC2_CORRUPT 2
+    "file corrupted.",
+#define PIC2_FORMAT 3
+    "not PIC2 format.",
+#define PIC2_DEPTH 4
+    "bit depths not divisible by 3 are unsupported.",
+#define PIC2_TMPFILE 5
+    "unable to create temporary filename???",
+#define PIC2_PAGE 6
+    "couldn't load the page.",
+#define PIC2_APPEND 7
+    "cannot append.",
+#define PIC2_WRITE 8
+    "write failed.",
+};
+
+struct _form_tab {
+    char *id;
+    int (*loader_init) PARM((struct pic2_info *));
+    int (*saver_init) PARM((struct pic2_info *, pixel **));
+} form_tab[] = {
+	{ "P2SS", pic2_arith_loader_init, pic2_arith_saver_init},
+	{ "P2SF", pic2_fast_loader_init, pic2_fast_saver_init},
+	{ "P2BM", pic2_beta_loader_init, pic2_beta_saver_init},
+	{ "P2BI", pic2_beta_loader_init, pic2_beta_saver_init},
+};
+#define	n_form_tab (sizeof(form_tab) / sizeof(struct _form_tab))
+#define P2SS 0
+#define P2SF 1
+#define P2BM 2
+#define P2BI 3
+
+/* The main routine to load a PIC2 file. */
+int LoadPIC2(fname, pinfo, quick)
+char *fname;
+PICINFO *pinfo;
+int quick;
+{
+    int e, i, block;
+    struct pic2_info pic2;
+
+    if (DEBUG)
+	fputs("LoadPIC2:\n", stderr);
+
+    pic2_init_info(&pic2);
+
+    if ((e = setjmp(pic2.jmp)) != 0){
+	/* When an error occurs, comes here. */
+	pic2_free_buffer(&pic2);
+	pic2_cleanup_pic2_info(&pic2, 0);
+	pic2_cleanup_pinfo(pinfo);
+	if (pic2split)
+	    KillPageFiles(pic2.pagebname, pic2.pnum);
+	SetCursors(-1);
+	if (DEBUG)
+	    fputs("\n", stderr);
+	return (0);
+    }
+    pic2_open_file(&pic2, fname);
+    pic2_read_header(&pic2);
+
+    if ((i = pic2_find_block(&pic2)) == 0)
+	pic2_file_error(&pic2, PIC2_CORRUPT);
+
+    block = 1;
+    while(i == 2) {
+	SetISTR(ISTR_WARNING, "unknown or invalid block #%d.", block);
+	i = pic2_next_block(&pic2);
+	block++;
+    }
+
+    if (pic2split && !quick) {
+	char firstpage[512];
+	struct stat st;
+#ifndef USE_MKSTEMP
+	int tmpfd;
+#endif
+
+#ifndef VMS
+	sprintf(pic2.pagebname, "%s/xvpic2XXXXXX", tmpdir);
+#else
+	sprintf(pic2.pagebname, "Sys$Scratch:xvpic2XXXXXX");
+#endif
+#ifdef USE_MKSTEMP
+	close(mkstemp(pic2.pagebname));
+#else
+	mktemp(pic2.pagebname);
+	tmpfd = open(pic2.pagebname, O_WRONLY|O_CREAT|O_EXCL, S_IRWUSR);
+	if (tmpfd < 0) FatalError("LoadPIC2(): can't create temporary file");
+	close(tmpfd);
+#endif
+	if (pic2.pagebname[0] == '\0')
+	    pic2_error(&pic2, PIC2_TMPFILE);
+	strcat(pic2.pagebname, ".");
+
+	sprintf(firstpage, "%s%d", pic2.pagebname, 1);
+	if (stat(firstpage, &st)) {
+	    for (pic2.pnum = 1; i >= 1; pic2.pnum++) {
+		pic2_load_block(&pic2);
+		pic2_make_pagefile(&pic2, pic2.pagebname, pic2.pnum);
+		while(block++, (i = pic2_next_block(&pic2)) == 2)
+		    SetISTR(ISTR_WARNING,
+			    "unknown or invalid block #%d.", block);
+	    }
+            pinfo->numpages = --pic2.pnum;
+            if (!LoadPIC2(firstpage, pinfo, 1))
+		pic2_error(&pic2, PIC2_PAGE);
+	    if (pic2.pnum == 1)
+		unlink(firstpage);
+	    else
+		strcpy(pinfo->pagebname, pic2.pagebname);
+	} else
+            if (!LoadPIC2(fname, pinfo, 1))
+		pic2_error(&pic2, PIC2_PAGE);
+    } else {
+	char buf[128], format[64];
+	int j;
+
+	pinfo->w = pic2.x_max;
+	pinfo->h = pic2.y_max;
+	pinfo->normw = pinfo->w;
+	pinfo->normh = pinfo->h;
+	pinfo->type = PIC24;
+	for (j = 0; j < n_form_tab; j++) {
+	    if (xvbcmp(pic2.block->id, form_tab[j].id, (size_t) 4) == 0)
+		break;
+	}
+	pinfo->frmType = F_PIC2;
+	pinfo->colType = F_FULLCOLOR;
+	pinfo->comment = pic2.comment;
+
+	if (pic2split) {
+	    pic2_make_xvpic(&pic2, &pinfo->pic, pinfo->r, pinfo->g, pinfo->b);
+	    strcpy(format, form_tab[j].id);
+	} else {
+	    for (pic2.pnum = 1; i >= 1; pic2.pnum++) {
+		SetISTR(ISTR_INFO, "composing block #%d", block);
+		pic2_make_xvpic(&pic2, &pinfo->pic,
+				pinfo->r, pinfo->g, pinfo->b);
+		while(block++, (i = pic2_next_block(&pic2)) == 2)
+		    SetISTR(ISTR_WARNING,
+			    "unknown or invalid block #%d.", block);
+	    }
+	    if (--block > 1)
+		if (block != --pic2.pnum)
+		    sprintf(format, "MultiBlock[%d/%d]", block, pic2.pnum);
+		else
+		    sprintf(format, "MultiBlock[%d]", block);
+	    else
+		strcpy(format, form_tab[j].id);
+	}
+	sprintf(buf, "PIC2(%s). %d colors (%ld bytes)", format,
+		(int) 1 << pic2.header->depth, pic2.fsize);
+	strcat(pinfo->fullInfo, buf);
+	sprintf(pinfo->shrtInfo, "%dx%d(aspect %4.2f) PIC2(%s).",
+		pinfo->w, pinfo->h,
+		(float) pic2.header->x_aspect / (float) pic2.header->y_aspect,
+		format);
+	if (!nopicadjust)
+	    normaspect = (float) pic2.header->x_aspect
+			 / (float) pic2.header->y_aspect;
+    }
+    pic2_cleanup_pic2_info(&pic2, 0);
+    SetCursors(-1);
+    if (DEBUG)
+	fputs("\n", stderr);
+    return (1);
+}
+
+/*
+ * This function opens the file, and set its size.
+ */
+static void pic2_open_file(pi, fname)
+    struct pic2_info *pi;
+    char *fname;
+{
+    if ((pi->fp = fopen(fname, "rb")) == NULL)
+	pic2_file_error(pi, PIC2_OPEN);
+    fseek(pi->fp, (size_t) 0, SEEK_END);
+    pi->fsize = ftell(pi->fp);
+    fseek(pi->fp, (size_t) 0, SEEK_SET);
+}
+
+/*
+ * These functions read the PIC2 header informations.
+ * pic2_read_header:
+ *	reads the PIC2 header.
+ * pic2_read_block_header1:
+ *	reads the id number of block header and the size of block.
+ * pic2_read_block_header2:
+ *	reads the rest of block header.
+ */
+static void pic2_read_header(pi)
+struct pic2_info *pi;
+{
+    long s_comment;
+
+    pi->mode = PIC2_READ_MODE;
+
+    /* read header image */
+    pic2_read_file(pi, pi->header->magic, 4);
+    pic2_read_file(pi, pi->header->name, 18);
+    pic2_read_file(pi, pi->header->subtitle, 8);
+    pic2_read_file(pi, pi->header->crlf0, 2);
+    pic2_read_file(pi, pi->header->title, 30);
+    pic2_read_file(pi, pi->header->crlf1, 2);
+    pic2_read_file(pi, pi->header->saver, 30);
+    pic2_read_file(pi, pi->header->crlf2, 2);
+    pic2_read_file(pi, pi->header->eof, 1);
+    pic2_read_file(pi, pi->header->reserve0, 1);
+    pi->header->flag = pic2_read_short(pi);
+    pi->header->no = pic2_read_short(pi);
+    pi->header->time = pic2_read_long(pi);
+    pi->header->size = pic2_read_long(pi);
+    pi->header->depth = pic2_read_short(pi);
+    pi->header->x_aspect = pic2_read_short(pi);
+    pi->header->y_aspect = pic2_read_short(pi);
+    pi->header->x_max = pic2_read_short(pi);
+    pi->header->y_max = pic2_read_short(pi);
+    pi->header->reserve1 = pic2_read_long(pi);
+
+    /* check magic number */
+    if (strncmp(pi->header->magic, pic2_id, (size_t) 4) != 0)
+        pic2_error(pi, PIC2_FORMAT);
+
+    /* read palette data, if exists */
+    if (pi->header->flag & 1) {
+	pi->pal_bits = pic2_read_char(pi);
+	pi->n_pal = pic2_read_short(pi);
+	pic2_read_file(pi, pi->pal, (size_t) (pi->n_pal * 3));
+    }
+
+    /* read comments */
+    s_comment = pi->header->size - pic2_tell_file(pi);
+    pi->comment = pic2_new(s_comment + 1, "pic2_read_header");
+    pic2_read_file(pi, pi->comment, (size_t) s_comment);
+    pi->comment[s_comment] = '\0';
+
+    pi->x_max = pi->header->x_max;
+    pi->y_max = pi->header->y_max;
+
+    /* set initial block point */
+    pi->next_pos = pic2_tell_file(pi);
+}
+
+static void pic2_read_block_header1(pi)
+struct pic2_info *pi;
+{
+    pic2_read_file(pi, pi->block->id, 4);
+    pi->block->size = pic2_read_long(pi);
+}
+
+static void pic2_read_block_header2(pi)
+struct pic2_info *pi;
+{
+    pi->block->flag = pic2_read_short(pi);
+    pi->block->x_wid = pic2_read_short(pi);
+    pi->block->y_wid = pic2_read_short(pi);
+    pi->block->x_offset = pic2_read_short(pi);
+    pi->block->y_offset = pic2_read_short(pi);
+    pi->block->opaque = pic2_read_long(pi);
+    pi->block->reserve = pic2_read_long(pi);
+}
+
+/*
+ * These functions are arithmetic pic2 format extractor.
+ */
+static short pic2_arith_decode_bit(pi, c)
+struct pic2_info *pi;
+int c;
+{
+    unsigned short pp;
+
+    pp = pi->mulu_tab[(pi->aa & 0x7f00) / 2 + c];
+    if (pi->dd >= (int) pp) {
+	pi->dd -= pp;
+	pi->aa -= pp;
+
+	while ((short) pi->aa >= 0) {
+	    pi->dd *= 2;
+	    if (pic2_read_bits(pi, 1))
+		pi->dd++;
+	    pi->aa *= 2;
+	}
+	return (1);
+    } else {
+	pi->aa = pp;
+
+	while ((short) pi->aa >= 0) {
+	    pi->dd *= 2;
+	    if (pic2_read_bits(pi, 1))
+		pi->dd++;
+	    pi->aa *= 2;
+	}
+	return (0);
+    }
+}
+
+static short pic2_arith_decode_nn(pi, c)
+struct pic2_info *pi;
+int c;
+{
+    int n;
+
+    if (pic2_arith_decode_bit(pi, c)) {
+	/* n < 1 */
+	n = 0;
+    } else if (pic2_arith_decode_bit(pi, c + 1)) {
+	/* n < 1 + 2 */
+	n = 1;
+	if (pic2_arith_decode_bit(pi, c + 8))
+	    n += 1;
+    } else if (pic2_arith_decode_bit(pi, c + 2)) {
+	/* n < 1 + 2 + 4 */
+	n = 1 + 2;
+	if (pic2_arith_decode_bit(pi,  c + 8))
+	    n += 1;
+	if (pic2_arith_decode_bit(pi,  c + 9))
+	    n += 2;
+    } else if (pic2_arith_decode_bit(pi, c + 3)) {
+	/* n < 1 + 2 + 4 + 8 */
+	n = 1 + 2 + 4;
+	if (pic2_arith_decode_bit(pi, c + 8))
+	    n += 1;
+	if (pic2_arith_decode_bit(pi, c + 9))
+	    n += 2;
+	if (pic2_arith_decode_bit(pi, c + 10))
+	    n += 4;
+    } else if (pic2_arith_decode_bit(pi, c + 4)) {
+	/* n < 1 + 2 + 4 + 8 + 16 */
+	n = 1 + 2 + 4 + 8;
+	if (pic2_arith_decode_bit(pi, c + 8))
+	    n += 1;
+	if (pic2_arith_decode_bit(pi, c + 9))
+	    n += 2;
+	if (pic2_arith_decode_bit(pi, c + 10))
+	    n += 4;
+	if (pic2_arith_decode_bit(pi, c + 11))
+	    n += 8;
+    } else if (pic2_arith_decode_bit(pi,  c + 5)) {
+	/* n < 1 + 2 + 4 + 8 + 16 + 32 */
+	n = 1 + 2 + 4 + 8 + 16;
+	if (pic2_arith_decode_bit(pi, c + 8))
+	    n += 1;
+	if (pic2_arith_decode_bit(pi, c + 9))
+	    n += 2;
+	if (pic2_arith_decode_bit(pi, c + 10))
+	    n += 4;
+	if (pic2_arith_decode_bit(pi, c + 11))
+	    n += 8;
+	if (pic2_arith_decode_bit(pi, c + 12))
+	    n += 16;
+
+    } else if (pic2_arith_decode_bit(pi, c + 6)) {
+	/* n < 1 + 2 + 4 + 8 + 16 + 32 + 64 */
+	n = 1 + 2 + 4 + 8 + 16 + 32;
+	if (pic2_arith_decode_bit(pi, c + 8))
+	    n += 1;
+	if (pic2_arith_decode_bit(pi, c + 9))
+	    n += 2;
+	if (pic2_arith_decode_bit(pi, c + 10))
+	    n += 4;
+	if (pic2_arith_decode_bit(pi, c + 11))
+	    n += 8;
+	if (pic2_arith_decode_bit(pi, c + 12))
+	    n += 16;
+	if (pic2_arith_decode_bit(pi, c + 13))
+	    n += 32;
+
+    } else if (pic2_arith_decode_bit(pi, c + 7)) {
+	/* n < 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 */
+	n = 1 + 2 + 4 + 8 + 16 + 32 + 64;
+	if (pic2_arith_decode_bit(pi, c + 8))
+	    n += 1;
+	if (pic2_arith_decode_bit(pi, c + 9))
+	    n += 2;
+	if (pic2_arith_decode_bit(pi, c + 10))
+	    n += 4;
+	if (pic2_arith_decode_bit(pi, c + 11))
+	    n += 8;
+	if (pic2_arith_decode_bit(pi, c + 12))
+	    n += 16;
+	if (pic2_arith_decode_bit(pi, c + 13))
+	    n += 32;
+	if (pic2_arith_decode_bit(pi, c + 14))
+	    n += 64;
+
+    } else {
+	n = 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128;
+    }
+    return (n);
+}
+
+static void pic2_arith_expand_chain(pi, x, y, cc)
+struct pic2_info *pi;
+int x, y;
+pixel cc;
+{
+    static const unsigned short c_tab[] = {
+	80 + 6 * 5,	/* -5 */
+	80 + 6 * 4,
+	80 + 6 * 3,
+	80 + 6 * 2,
+	80 + 6 * 1,
+	80 + 6 * 0,	/* 0  */
+	80 + 6 * 0,	/* 1  */
+    };
+    unsigned short b;
+
+    b = c_tab[pi->flag_now[x] + 5];
+    if (!pic2_arith_decode_bit(pi, b++)) {
+	if (pic2_arith_decode_bit(pi, b++))      {	/* down */
+	    pi->vram_next[x    ] = cc;
+	    pi->flag_next[x    ] = -1;
+	} else if (pic2_arith_decode_bit(pi, b++)) {	/* left */
+	    pi->vram_next[x - 1] = cc;
+	    pi->flag_next[x - 1] = -2;
+	} else if (pic2_arith_decode_bit(pi, b++)) {	/* right */
+	    pi->vram_next[x + 1] = cc;
+	    pi->flag_next[x + 1] = -3;
+	} else if (pic2_arith_decode_bit(pi, b++)) {	/* left2 */
+	    pi->vram_next[x - 2] = cc;
+	    pi->flag_next[x - 2] = -4;
+	} else {					/* right2 */
+	    pi->vram_next[x + 2] = cc;
+	    pi->flag_next[x + 2] = -5;
+	}
+    }
+}
+
+static short pic2_arith_get_number(pi, c, bef)
+struct pic2_info *pi;
+int c, bef;
+{
+    unsigned short n;
+    byte maxcol;
+
+    maxcol = 0xff >> (8 - pi->header->depth / 3);
+
+    n = pic2_arith_decode_nn(pi, c);
+    if (bef > ((int) maxcol >> 1)) {
+	if (n > ((int) maxcol - bef) * 2)
+	    n = maxcol - n;
+	else if (n & 1)
+	    n = n / 2 + bef + 1;
+	else
+	    n = bef - n / 2;
+    } else {
+	if ((int) n > (bef * 2))
+	    n = n;
+	else if (n & 1)
+	    n = n / 2 + bef + 1;
+	else
+	    n = bef - n / 2;
+    }
+    return (n);
+}
+
+static pixel pic2_arith_read_color(pi, x)
+struct pic2_info *pi;
+int x;
+{
+    pixel c1, c2, cc;
+    unsigned short i, j, k, m;
+    short r, g, b, r0, g0, b0;
+    short colbits;
+    pixel rmask, gmask, bmask;
+    byte maxcol;
+
+    colbits = pi->header->depth / 3;
+    rmask = (0xff >> (8 - colbits)) << (colbits * 2);
+    gmask = (0xff >> (8 - colbits)) <<  colbits;
+    bmask = (0xff >> (8 - colbits));
+    maxcol = (byte) bmask;
+
+    c1 = pi->vram_prev[x];
+    k = ((c1 >> ((colbits - 3) * 3)) & 0x1c0)
+      | ((c1 >> ((colbits - 3) * 2)) & 0x038)
+      | ((c1 >>  (colbits - 3)     ) & 0x007);
+    if (colbits == 5)
+	k = pic2_exchange_rg(k, 3);
+
+    if (pic2_arith_decode_bit(pi, pi->cache_hit_c)) {	/* ouch */
+	pi->cache_hit_c = 16;
+
+        c2 = pi->vram_now[x - 1];
+	r = ((c1 & rmask) + (c2 & rmask)) >> (colbits * 2 + 1);
+	g = ((c1 & gmask) + (c2 & gmask)) >> (colbits     + 1);
+	b = ((c1 & bmask) + (c2 & bmask)) >> (              1);
+
+	g0 = pic2_arith_get_number(pi, 32, g);
+        r = r + g0 - g;
+	if (r > (short) maxcol)
+	    r = maxcol;
+	else if (r < 0)
+	    r = 0;
+
+        b = b + g0 - g;
+	if (b > (short) maxcol)
+	    b = maxcol;
+	else if (b < 0)
+	    b = 0;
+
+	r0 = pic2_arith_get_number(pi, 48, r);
+	b0 = pic2_arith_get_number(pi, 64, b);
+
+	pi->cache_pos[k] = j = (pi->cache_pos[k] - 1) & (PIC2_ARITH_CACHE - 1);
+	pi->cache[k][j] = cc = (r0 << (colbits * 2)) | (g0 << colbits) | b0;
+    } else {
+	pi->cache_hit_c = 15;
+
+	j = pic2_arith_decode_nn(pi, 17);
+	m = pi->cache_pos[k];
+	i = (m + j / 2) & (PIC2_ARITH_CACHE - 1);
+	j = (m + j) & (PIC2_ARITH_CACHE - 1);
+
+	cc = pi->cache[k][j];
+	pi->cache[k][j] = pi->cache[k][i];
+	pi->cache[k][i] = pi->cache[k][m];
+	pi->cache[k][m] = cc;
+    }
+    return (cc);
+}
+
+static int pic2_arith_expand_line(pi, line)
+struct pic2_info *pi;
+pixel **line;
+{
+    int ymax;
+    int x, xw;
+    pixel cc;
+
+    pic2_handle_para(pi, 0);
+
+    xw = pi->block->x_wid;
+    ymax = pi->block->y_wid - 1;
+
+    if (pi->ynow > ymax)
+	return (-2);					/* end */
+
+    /* set right end of previous line before left end of current line. */
+    if (pi->ynow == 0) {
+	cc = 0;
+    } else
+	cc = pi->vram_prev[xw - 1];
+    pi->vram_now[-1] = cc;
+
+    /* clear flag for change point */
+    xvbzero((char *) pi->flag_next, xw * sizeof(pi->flag_next[0]));
+
+    /* clear flag for position probability space */
+    xvbzero((char *) pi->flag2_next2, xw * sizeof(pi->flag2_next2[0]));
+
+    for (x = 0; x < xw; x++) {
+	if (pi->flag_now[x] < 0) {
+	    cc = pi->vram_now[x];
+	    if (pi->ynow < ymax)
+		pic2_arith_expand_chain(pi, x, pi->ynow, cc);
+	} else if (pic2_arith_decode_bit(pi, pi->flag2_now[x])) {
+	    /* ajust probability space around of change point */
+	    pi->flag2_now  [x + 1]++;
+	    pi->flag2_now  [x + 2]++;
+	    pi->flag2_next [x - 1]++;
+	    pi->flag2_next [x    ]++;
+	    pi->flag2_next [x + 1]++;
+	    pi->flag2_next2[x - 1]++;
+	    pi->flag2_next2[x    ]++;
+	    pi->flag2_next2[x + 1]++;
+
+	    pi->vram_now[x] = cc = pic2_arith_read_color(pi, x);
+	    if (pi->ynow < ymax)
+		pic2_arith_expand_chain(pi, x, pi->ynow, cc);
+	} else
+	    pi->vram_now[x] = cc;
+    }
+    if (line != NULL)
+	*line = pi->vram_now;
+    pi->ynow++;
+
+    pic2_handle_para(pi, 1);
+
+    return (pi->ynow - 1);
+}
+
+static int pic2_arith_loader_init(pi)
+struct pic2_info *pi;
+{
+    unsigned short p2b[256];
+    int i, xw;
+
+    pi->ynow = 0;
+
+    /* check the color depth */
+    if (pi->header->depth % 3)
+	pic2_error(pi, PIC2_DEPTH);
+
+    /* set function for extract next line */
+    pi->next_line = pic2_arith_expand_line;
+
+    /* clear cache and flags */
+    xw = pi->block->x_wid;
+    xvbzero((char *) pi->cache, 8 * 8 * 8 * sizeof(pi->cache[0]));
+    xvbzero((char *) pi->cache_pos, 8 * 8 * 8 * sizeof(pi->cache_pos[0]));
+
+    xvbzero((char *) pi->flag_now, xw * sizeof(pi->flag_now[0]));
+    xvbzero((char *) pi->flag2_now, 8 + xw * sizeof(pi->flag2_now[0]));
+    xvbzero((char *) pi->flag2_next, 8 + xw * sizeof(pi->flag2_next[0]));
+
+    /* go to picture data field */
+    pic2_seek_file(pi, pi->block_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET);
+
+    /* clear bit field marker */
+    pi->bs.rest = 0;
+    pi->bs.cur = 0;
+
+    /* read probability table */
+    for (i = 0; i < PIC2_ARITH_CONTEXT; i++)
+	p2b[i] = pic2_read_short(pi);
+
+    /* make multiplication table */
+    for (i = 0; i < 16384; i++) {
+	pi->mulu_tab[i] = (long) (i / 128 + 128) * (int) p2b[i & 127] / 256;
+	if (pi->mulu_tab[i] == 0) pi->mulu_tab[i] = 1;
+    }
+    /* initialize some valuables */
+    pi->aa = 0xffff;
+    pi->dd = 0;
+    for (i = 0; i < 16; i++) {
+	pi->dd *= 2;
+	if (pic2_read_bits(pi, 1))
+	    pi->dd |= 1;
+    }
+    pi->cache_hit_c = 16;
+
+    return (0);
+}
+
+/*
+ * These functions are fast pic2 compression extractor.
+ */
+static int pic2_fast_read_length(pi)
+struct pic2_info *pi;
+{
+    int a;
+
+    a = 0;
+    while (pic2_read_bits(pi, 1)) {
+	a++;
+    }
+    if (a == 0)
+	return (0);
+    return (pic2_read_bits(pi, a) + (1 << a) - 1);
+}
+
+static void pic2_fast_expand_chain(pi, x, cc)
+struct pic2_info *pi;
+int x;
+pixel cc;
+{
+    if (pic2_read_bits(pi, 1) != 0) {
+	if (pic2_read_bits(pi, 1) != 0) {		/* down */
+	    pi->vram_next[x] = cc;
+	    pi->flag_next[x] = -1;
+	} else if (pic2_read_bits(pi, 1) != 0) {
+	    if (pic2_read_bits(pi, 1) == 0) {		/* left2down */
+		pi->vram_next[x - 2] = cc;
+		pi->flag_next[x - 2] = -1;
+	    } else {					/* left1down */
+		pi->vram_next[x - 1] = cc;
+		pi->flag_next[x - 1] = -1;
+	    }
+	} else {
+	    if (pic2_read_bits(pi, 1) == 0) {		/* right2down */
+		pi->vram_next[x + 2] = cc;
+		pi->flag_next[x + 2] = -1;
+	    } else {					/* left1down */
+		pi->vram_next[x + 1] = cc;
+		pi->flag_next[x + 1] = -1;
+	    }
+	}
+    }
+}
+
+static pixel pic2_fast_read_color(pi, bc)
+struct pic2_info *pi;
+pixel bc;
+{
+    pixel cc;
+    unsigned short j, k, m;
+    short depth, colbits;
+    pixel (*cache)[PIC2_FAST_CACHE];
+
+    depth = pi->header->depth;
+    colbits = depth / 3;
+    cache = (pixel (*)[PIC2_FAST_CACHE]) pi->cache;
+
+    bc = pic2_exchange_rg(bc, colbits);
+    k = pic2_shift_bits(bc, 8 - depth);
+    if (pic2_read_bits(pi, 1) == 0) {
+	pi->cache_pos[k] = m = (pi->cache_pos[k] - 1) & (PIC2_FAST_CACHE - 1);
+	cc = pic2_read_bits(pi, depth);
+	cc = pic2_exchange_rg(cc, colbits);
+	cache[k][m] = cc;
+    } else {
+	j = pic2_read_bits(pi, 6);		/* 6= log2(PIC2_FAST_CACHE) */
+	m = pi->cache_pos[k];
+	cc = cache[k][(m + j) & (PIC2_FAST_CACHE - 1)];
+    }
+    return (cc);
+}
+
+static int pic2_fast_expand_line(pi, line)
+struct pic2_info *pi;
+pixel **line;
+{
+    int ymax;
+    int x, xw;
+    pixel cc;
+
+    pic2_handle_para(pi, 0);
+
+    xw = pi->block->x_wid;
+    ymax = pi->block->y_wid - 1;
+
+    if (pi->ynow > ymax)
+	return (-2);
+
+    if (pi->ynow == 0) {
+	pi->dd = 0;
+	pi->aa = pic2_fast_read_length(pi);
+	if (pi->aa == 1023)
+	    pi->dd = 1023;
+	else if (pi->aa > 1023)
+	    pi->aa--;
+	cc = 0;
+    } else
+	cc = pi->vram_prev[xw - 1];
+
+    xvbzero((char *) pi->flag_next, xw * sizeof(pi->flag_next[0]));
+
+    for (x = 0; x < xw; x++) {
+	if (pi->dd > 0) {
+	    if (pi->flag_now[x] < 0) {			/* on chain ? */
+		cc = pi->vram_now[x];
+		pic2_fast_expand_chain(pi, x, cc);
+		if (--pi->dd == 0) {
+		    pi->aa = pic2_fast_read_length(pi);
+		    if (pi->aa == 1023)
+			pi->dd = 1023;
+		    else if (pi->aa > 1023)
+			pi->aa--;
+		}
+	    } else
+		pi->vram_now[x] = cc;
+	} else {
+	    if (pi->flag_now[x] < 0) {			/* on chain ? */
+		cc = pi->vram_now[x];
+		pic2_fast_expand_chain(pi, x, cc);
+	    } else if (--pi->aa < 0) {
+		cc = pi->vram_now[x] = pic2_fast_read_color(pi, cc);
+		pic2_fast_expand_chain(pi, x, cc);
+		pi->aa = pic2_fast_read_length(pi);
+		if (pi->aa == 1023)
+		    pi->dd = 1023;
+		else if (pi->aa > 1023)
+		    pi->aa--;
+	    } else
+		pi->vram_now[x] = cc;
+	}
+    }
+    if (line != NULL)
+	*line = pi->vram_now;
+    pi->ynow++;
+
+    pic2_handle_para(pi, 1);
+
+    return (pi->ynow - 1);
+}
+
+static int pic2_fast_loader_init(pi)
+struct pic2_info *pi;
+{
+    int xw;
+
+    pi->ynow = 0;
+
+    /* check the color depth */
+    if (pi->header->depth % 3)
+	pic2_error(pi, PIC2_DEPTH);
+
+    /* set function for extract next line */
+    pi->next_line = pic2_fast_expand_line;
+
+    /* clear cache and flags */
+    xw = pi->block->x_wid;
+    xvbzero((char *) pi->cache, sizeof(pi->cache[0]) * 256);
+    xvbzero((char *) pi->cache_pos, sizeof(pi->cache_pos[0]) * 8 * 8 * 8);
+    xvbzero((char *) pi->flag_now, (xw + 8) * sizeof(pi->flag_now[0]));
+    xvbzero((char *) pi->flag_next, (xw + 8) * sizeof(pi->flag_next[0]));
+
+    /* go to picture data field */
+    pic2_seek_file(pi, pi->block_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET);
+
+    /* clear bit field marker */
+    pi->bs.rest = 0;
+    pi->bs.cur = 0;
+
+    return (0);
+}
+
+/*
+ * These functions are beta pic2 format extractor.
+ */
+static int pic2_beta_expand_line(pi, line)
+struct pic2_info *pi;
+pixel **line;
+{
+    int i, xw, ymax;
+    byte a, b, c, *p;
+    pixel *pc;
+    short depth, pixbyte, colbits;
+
+    depth = pi->header->depth;
+    pixbyte = depth / 8 + ((depth % 8) > 0);
+    colbits = depth / 3;
+
+    xw = pi->block->x_wid;
+    ymax = pi->block->y_wid - 1;
+
+    if (pi->ynow > ymax)
+	return (-2);					/* end */
+
+    pc = pi->vram_now;
+    p = (byte *) pi->vram_prev;
+    if (pixbyte == 3) {
+	pic2_read_file(pi, pi->vram_prev, (size_t) (xw * pixbyte));
+	for (i = 0; i < xw; i++, pc++) {
+	    a = *p++;
+	    b = *p++;
+	    c = *p++;
+	    *pc = ((pixel) a << 16) | ((pixel) b << 8) | (pixel) c;
+	}
+    } else if (pixbyte == 2) {
+	pic2_read_file(pi, pi->vram_prev, (size_t) (xw * 2));
+	if (strncmp(pi->block->id, "P2BM", 4) == 0) {
+	    for (i = 0; i < xw; i++, pc++) {
+		a = *p++;
+		b = *p++;
+		*pc = ((pixel) a << 8) | (pixel) b;
+		if (colbits == 5) {
+		    *pc >>= 1;
+		    *pc = pic2_exchange_rg(*pc, colbits);
+		}
+	    }
+	} else {
+	    for (i = 0; i < xw; i++, pc++) {
+		a = *p++;
+		b = *p++;
+		*pc = ((pixel) b << 8) | (pixel) a;
+		if (colbits == 5) {
+		    *pc >>= 1;
+		    *pc = pic2_exchange_rg(*pc, colbits);
+		}
+	    }
+	}
+    } else {
+	pic2_read_file(pi, pi->vram_prev, (size_t) xw);
+	for (i = 0; i < xw; i++)
+	    *pc++ = *p++;
+    }
+    if (line != NULL)
+	*line = pi->vram_now;
+
+    pc = pi->vram_prev;
+    pi->vram_prev = pi->vram_now;
+    pi->vram_now = pi->vram_next;
+    pi->vram_next = pc;
+
+    pi->ynow++;
+    return (pi->ynow - 1);
+}
+
+static int pic2_beta_loader_init(pi)
+struct pic2_info *pi;
+{
+    pi->ynow = 0;
+    pi->next_line = pic2_beta_expand_line;
+    pic2_seek_file(pi, pi->block_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET);
+    return (0);
+}
+
+/*
+ * Make a picture from the expanded data.
+ */
+static void pic2_make_xvpic(pi, xp, rp, gp, bp)
+struct pic2_info *pi;
+byte **xp, *rp, *gp, *bp;
+{
+    int line, i;
+    pixel *linep, opaque;
+    short colbits;
+    byte colmask;
+
+    if (*xp == NULL)
+	*xp = pic2_new((size_t) pi->x_max * pi->y_max * 3, "pic2_make_xvpic");   // GRR POSSIBLE OVERFLOW / FIXME
+
+    if (pi->block->flag & 1)
+	opaque = pi->block->opaque;
+    else
+	opaque = 0xffffffff;
+
+    colbits = pi->header->depth / 3;
+    colmask = 0xff >> (8 - colbits);
+
+    line = pic2_load_block(pi);
+    for (;;) {
+	int pic_idx;
+
+	line = pic2_next_line(pi, &linep);
+	if (line < 0)
+	    break;
+	pic_idx = ((line + pi->block->y_offset) * pi->x_max
+		   + pi->block->x_offset) * 3;
+
+	for (i = 0; i < pi->block->x_wid; i++, linep++) {
+	    byte r, g, b;
+
+	    if (*linep != opaque) {
+		r = ((*linep >> (colbits * 2)) & colmask);
+		r = pic2_convert_color_bits(r, colbits, 8);
+		g = ((*linep >>  colbits     ) & colmask);
+		g = pic2_convert_color_bits(g, colbits, 8);
+		b = ( *linep                   & colmask);
+		b = pic2_convert_color_bits(b, colbits, 8);
+		(*xp)[pic_idx++] = r;
+		(*xp)[pic_idx++] = g;
+		(*xp)[pic_idx++] = b;
+	    } else
+	        pic_idx += 3;
+
+	    WaitCursor();
+	}
+    }
+}
+
+/*
+ * This function splits a multiblock PIC2 file into several pages.
+ */
+static void pic2_make_pagefile(pi, pagebname, pnum)
+struct pic2_info *pi;
+char *pagebname;
+int pnum;
+{
+    struct pic2_info pic2;
+    FILE *fp;
+    char pagefile[64], *buf;
+    size_t imagesize;
+
+    sprintf(pagefile, "%s%d", pagebname, pnum);
+    if ((fp = fopen(pagefile, "wb")) == NULL)
+	pic2_error(pi, PIC2_WRITE);
+
+    xvbcopy((char *) pi, (char *) &pic2, sizeof(struct pic2_info));
+    pic2.fp = fp;
+
+    pic2_write_header1(&pic2);
+
+    pic2_write_block_header(&pic2);
+
+    imagesize = pi->block->size - PIC2_BLOCK_HEADER_SIZE;
+    buf = (char *) pic2_malloc(imagesize, "pic2_make_pagefile");
+
+    pic2_seek_file(pi, pi->block_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET);
+    if (fread(buf, (size_t) 1, imagesize, pi->fp) < imagesize) {
+	free(buf);
+	pic2_file_error(pi, PIC2_CORRUPT);
+    }
+    if (fwrite(buf, (size_t) 1, imagesize, fp) < imagesize) {
+	free(buf);
+	pic2_error(pi, PIC2_WRITE);
+    }
+    free(buf);
+
+    pic2.next_pos = pic2_tell_file(&pic2);
+    pic2_write_header2(&pic2);
+
+    fclose(fp);
+}
+
+/* The main routine to save a PIC2 file. */
+static int WritePIC2(fp, pic0, ptype, w, h, rmap, gmap, bmap, numcols,
+		     colorstyle, fname, type, depth, x_offset, y_offset,
+		     append, comment)
+FILE *fp;
+byte *pic0;
+int ptype, w, h;
+byte *rmap, *gmap, *bmap;
+int numcols, colorstyle;
+char *fname;
+int type, depth;
+int x_offset, y_offset;
+int append;
+char *comment;
+{
+    struct pic2_info pic2;
+    char creator[256], title[256], saver[256];
+    int e;
+
+    if (DEBUG)
+	fputs("WritePIC2:\n", stderr);
+
+    pic2_init_info(&pic2);
+    pic2.fp = fp;
+    pic2.writing_grey = (colorstyle == F_GREYSCALE);
+
+    if ((e = setjmp(pic2.jmp)) != 0){
+	/* When an error occurs while writing, comes here. */
+	pic2_free_buffer(&pic2);
+	pic2_cleanup_pic2_info(&pic2, 1);
+	SetCursors(-1);
+	if (DEBUG)
+	    fputs("\n", stderr);
+	return (-1);
+    }
+    sprintf(creator, "XV Version %s", VERSTR);
+    pic2_strncpy(title, comment, 30);
+    sprintf(saver, "XV %s/UNIX/Bradley", VERSTR);
+
+    if (!append) {
+	pic2_setup_pic2_info(&pic2, creator, fname, title, saver,
+			     0, depth, 1, 1, w, h, comment);
+	pic2_write_header1(&pic2);
+    } else {
+	pic2_read_header(&pic2);
+	pic2_append(&pic2);
+	free(pic2.comment);
+	pic2_setup_pic2_info(&pic2, creator, fname, title, saver,
+			     0, depth, 1, 1, w, h, comment);
+    }
+
+    pic2_write_data(&pic2, pic0, ptype, x_offset, y_offset, w, h,
+		    rmap, gmap, bmap, type, depth);
+    pic2_write_header2(&pic2);
+
+    pic2_cleanup_pic2_info(&pic2, 1);
+    SetCursors(-1);
+    if (DEBUG)
+	fputs("\n", stderr);
+    return (0);
+}
+
+/*
+ * This function initializes pic2_info.
+ */
+static void pic2_setup_pic2_info(pi, name, fname, title, saver, no, depth,
+			      x_aspect, y_aspect, x_max, y_max, comment)
+struct pic2_info *pi;
+char *name, *fname, *title, *saver;
+int no, depth;
+int x_aspect, y_aspect;
+int x_max, y_max;
+char *comment;
+{
+    char basename[256], *suffix;
+
+    pi->mode = PIC2_WRITE_MODE;
+
+    /* set magic number */
+    strncpy(pi->header->magic, pic2_id, 4);
+
+    /* set creator's name */
+    pic2_strncpy(pi->header->name, (char *) name, 18);
+
+    /* set title and subtitle */
+    pic2_strncpy(pi->header->title, (char *) title, 30);
+    strcpy(basename, BaseName(fname));
+    suffix = (char *) rindex(basename, '.');
+    if (suffix) {
+	suffix++;
+	if (!strcmp(suffix, "p2") || !strcmp(suffix, "P2"))
+	    *(suffix - 1) = '\0';
+    }
+    pic2_strncpy(pi->header->subtitle, basename, 8);
+
+    /* set saver */
+    pic2_strncpy(pi->header->saver, saver, 30);
+
+    /* set picture number */
+    pi->header->no = no;
+
+    /* import comment */
+    pi->comment = comment;
+
+    /* set some picture's info */
+    pi->header->depth = depth;
+    pi->header->x_aspect = x_aspect;
+    pi->header->y_aspect = y_aspect;
+    pi->header->x_max = x_max;
+    pi->header->y_max = y_max;
+
+    /* set some gaps */
+    pi->header->crlf0[0] = pi->header->crlf1[0] = pi->header->crlf2[0] = 0x0d;
+    pi->header->crlf0[1] = pi->header->crlf1[1] = pi->header->crlf2[1] = 0x0a;
+
+    pi->header->eof[0] = 0x1a;
+    pi->header->reserve0[0] = 0;
+    pi->header->reserve1 = 0;
+
+    /* set palettes */
+    if (pi->n_pal > 0)
+	pi->header->flag = 1;
+    else
+	pi->header->flag = 0;
+}
+
+/*
+ * This function appends to existing pic2 file.
+ */
+static void pic2_append(pi)
+struct pic2_info *pi;
+{
+    int block;
+
+    block = pic2_find_block(pi);
+    while (block > 0)
+	block = pic2_next_block(pi);
+
+    if (block != 0)
+	pic2_error(pi, PIC2_APPEND);
+}
+
+/*
+ * These functions write the PIC2 header.
+ * pic2_write_header1:
+ *	write palette data and comment.
+ * pic2_write_header2:
+ *	write the terminate block and rest header.
+ * pic2_write_block_header:
+ *	write the block header.
+ */
+static void pic2_write_header1(pi)
+struct pic2_info *pi;
+{
+    char *comment;
+
+    /* seek to block start position */
+    pic2_seek_file(pi, PIC2_HEADER_SIZE, SEEK_SET);
+
+    /* write palette */
+    if (pi->n_pal > 0) {
+	pic2_write_char(pi, pi->pal_bits);
+	pic2_write_short(pi, pi->n_pal);
+	pic2_write_file(pi, pi->pal, (size_t) (pi->n_pal * 3));
+    }
+    /* save comment */
+    comment = pi->comment;
+    if (pi->comment != NULL) {
+	for (comment = pi->comment; *comment; comment++) {
+	    if (*comment == '\n') {
+		pic2_write_char(pi, '\r');
+		pic2_write_char(pi, '\n');
+	    } else if (*comment != '\r')
+		pic2_write_char(pi, *comment);
+	}
+	pic2_write_char(pi, 0);
+    }
+    /* set the next block position */
+    pi->next_pos = pic2_tell_file(pi);
+    pi->header->size = pi->next_pos;
+}
+
+static void pic2_write_header2(pi)
+struct pic2_info *pi;
+{
+    pic2_seek_file(pi, pi->next_pos, SEEK_SET);
+
+    /* write terminate block */
+    pic2_write_long(pi, 0);
+    pic2_write_long(pi, 0);
+
+    /* set some header information */
+    if (pi->header->x_max < pi->x_max)
+	pi->header->x_max = pi->x_max;
+    if (pi->header->y_max < pi->x_max)
+	pi->header->y_max = pi->y_max;
+
+    pi->header->time = time(NULL);
+    pic2_seek_file(pi, 0, SEEK_SET);
+
+    /* write header image */
+    pic2_write_file(pi, pi->header->magic, 4);
+    pic2_write_file(pi, pi->header->name, 18);
+    pic2_write_file(pi, pi->header->subtitle, 8);
+    pic2_write_file(pi, pi->header->crlf0, 2);
+    pic2_write_file(pi, pi->header->title, 30);
+    pic2_write_file(pi, pi->header->crlf1, 2);
+    pic2_write_file(pi, pi->header->saver, 30);
+    pic2_write_file(pi, pi->header->crlf2, 2);
+    pic2_write_file(pi, pi->header->eof, 1);
+    pic2_write_file(pi, pi->header->reserve0, 1);
+    pic2_write_short(pi, pi->header->flag);
+    pic2_write_short(pi, pi->header->no);
+    pic2_write_long(pi, pi->header->time);
+    pic2_write_long(pi, pi->header->size);
+    pic2_write_short(pi, pi->header->depth);
+    pic2_write_short(pi, pi->header->x_aspect);
+    pic2_write_short(pi, pi->header->y_aspect);
+    pic2_write_short(pi, pi->header->x_max);
+    pic2_write_short(pi, pi->header->y_max);
+    pic2_write_long(pi, pi->header->reserve1);
+}
+
+static void pic2_write_block_header(pi)
+struct pic2_info *pi;
+{
+    pic2_write_file(pi, pi->block->id, 4);
+    pic2_write_long(pi, pi->block->size);
+    pic2_write_short(pi, pi->block->flag);
+    pic2_write_short(pi, pi->block->x_wid);
+    pic2_write_short(pi, pi->block->y_wid);
+    pic2_write_short(pi, pi->block->x_offset);
+    pic2_write_short(pi, pi->block->y_offset);
+    pic2_write_long(pi, pi->block->opaque);
+    pic2_write_long(pi, pi->block->reserve);
+}
+
+/*
+ * These functions implement the arithmetic-format compressor.
+ */
+#define	pic2_arith_write_one_bit(pi)	(pi->bs.bits++)
+
+static void pic2_arith_write_zero_bit(pi)
+struct pic2_info *pi;
+{
+    if (pi->bs.zero)
+	pic2_write_bits(pi, 0, 1);
+
+    while (pi->bs.bits--)
+	pic2_write_bits(pi, 1, 1);
+
+    pi->bs.bits = 0;
+    pi->bs.zero = 1;
+}
+
+static void pic2_arith_flush_bit_buf(pi)
+struct pic2_info *pi;
+{
+    int	i;
+
+    for (i = 0; i < 16; i++) {
+	if (pi->cc & 0x8000)
+	    pic2_arith_write_one_bit(pi);
+	else
+	    pic2_arith_write_zero_bit(pi);
+	pi->cc <<= 1;
+    }
+    pic2_arith_write_zero_bit(pi);
+    pic2_flush_bits(pi);
+}
+
+static void pic2_arith_carry_bit(pi)
+struct pic2_info *pi;
+{
+    pic2_write_bits(pi, 1, 1);
+
+    if (pi->bs.bits == 0) {
+	pi->bs.zero = 0;
+    } else {
+	while (--pi->bs.bits)
+	    pic2_write_bits(pi, 0, 1);
+	pi->bs.zero = 1;
+    }
+}
+
+static void pic2_arith_encode_bit(pi, n, c)
+struct pic2_info *pi;
+int n, c;
+{
+    int	pp;
+    long *c_sum, *c_0_sum;
+
+    c_sum = (long *) pi->mulu_tab;
+    c_0_sum = c_sum + PIC2_ARITH_CONTEXT + 1;
+
+    if (pi->dd  == 0) {
+	c_sum[c]++;
+	if (n == 0)
+	    c_0_sum[c]++;
+	return;
+    }
+    pp = pi->mulu_tab[(pi->aa & 0x7f00) / 2 + c];
+    if (n != 0) {
+	pi->cc = pi->cc + pp;
+	if (pi->cc > 0xffff) {
+	    pic2_arith_carry_bit(pi);
+	    pi->cc = pi->cc & 0xffff;
+	}
+	pi->aa = pi->aa - pp;
+	while (pi->aa < 0x8000) {
+	    if (pi->cc & 0x8000)
+		pic2_arith_write_one_bit(pi);
+	    else
+		pic2_arith_write_zero_bit(pi);
+	    pi->cc = (pi->cc * 2) & 0xffff;
+	    pi->aa = pi->aa * 2;
+	}
+    } else {
+	pi->aa = pp;
+
+	while (pi->aa < 0x8000) {
+	    if (pi->cc & 0x8000)
+		pic2_arith_write_one_bit(pi);
+	    else
+		pic2_arith_write_zero_bit(pi);
+	    pi->cc = (pi->cc * 2) & 0xffff;
+	    pi->aa = pi->aa * 2;
+	}
+    }
+}
+
+static void pic2_arith_encode_nbyte(pi, n, c, max)
+struct pic2_info *pi;
+int n, c, max;
+{
+    short i;
+
+    for (i = 0; i < n; i++) {
+	pic2_arith_encode_bit(pi, 0, c + i);
+    }
+    if (n < max)
+	pic2_arith_encode_bit(pi, 1, c + n);
+}
+
+static void pic2_arith_encode_nn(pi, n, c)
+struct pic2_info *pi;
+int n, c;
+{
+    if (n < 1) {
+	pic2_arith_encode_bit(pi, 1, c);
+    } else if (n < 1 + 2) {
+	pic2_arith_encode_bit(pi, 0, c);
+	pic2_arith_encode_bit(pi, 1, c + 1);
+	n -= 1;
+	pic2_arith_encode_bit(pi, n & 1, c + 8);
+    } else if (n < 1 + 2 + 4) {
+	pic2_arith_encode_bit(pi, 0, c);
+	pic2_arith_encode_bit(pi, 0, c + 1);
+	pic2_arith_encode_bit(pi, 1, c + 2);
+	n -= 1 + 2;
+	pic2_arith_encode_bit(pi, n & 1, c + 8);
+	pic2_arith_encode_bit(pi, n & 2, c + 9);
+    } else if (n < 1 + 2 + 4 + 8) {
+	pic2_arith_encode_bit(pi, 0, c);
+	pic2_arith_encode_bit(pi, 0, c + 1);
+	pic2_arith_encode_bit(pi, 0, c + 2);
+	pic2_arith_encode_bit(pi, 1, c + 3);
+	n -= 1 + 2 + 4;
+	pic2_arith_encode_bit(pi, n & 1, c + 8);
+	pic2_arith_encode_bit(pi, n & 2, c + 9);
+	pic2_arith_encode_bit(pi, n & 4, c + 10);
+    } else if (n < 1 + 2 + 4 + 8 + 16) {
+	pic2_arith_encode_bit(pi, 0, c);
+	pic2_arith_encode_bit(pi, 0, c + 1);
+	pic2_arith_encode_bit(pi, 0, c + 2);
+	pic2_arith_encode_bit(pi, 0, c + 3);
+	pic2_arith_encode_bit(pi, 1, c + 4);
+	n -= 1 + 2 + 4 + 8;
+	pic2_arith_encode_bit(pi, n & 1, c + 8);
+	pic2_arith_encode_bit(pi, n & 2, c + 9);
+	pic2_arith_encode_bit(pi, n & 4, c + 10);
+	pic2_arith_encode_bit(pi, n & 8, c + 11);
+    } else if (n < 1 + 2 + 4 + 8 + 16 + 32) {
+	pic2_arith_encode_bit(pi, 0, c);
+	pic2_arith_encode_bit(pi, 0, c + 1);
+	pic2_arith_encode_bit(pi, 0, c + 2);
+	pic2_arith_encode_bit(pi, 0, c + 3);
+	pic2_arith_encode_bit(pi, 0, c + 4);
+	pic2_arith_encode_bit(pi, 1, c + 5);
+	n -= 1 + 2 + 4 + 8 + 16;
+	pic2_arith_encode_bit(pi, n & 1, c + 8);
+	pic2_arith_encode_bit(pi, n & 2, c + 9);
+	pic2_arith_encode_bit(pi, n & 4, c + 10);
+	pic2_arith_encode_bit(pi, n & 8, c + 11);
+	pic2_arith_encode_bit(pi, n & 16, c + 12);
+    } else if (n < 1 + 2 + 4 + 8 + 16 + 32 + 64) {
+	pic2_arith_encode_bit(pi, 0, c);
+	pic2_arith_encode_bit(pi, 0, c + 1);
+	pic2_arith_encode_bit(pi, 0, c + 2);
+	pic2_arith_encode_bit(pi, 0, c + 3);
+	pic2_arith_encode_bit(pi, 0, c + 4);
+	pic2_arith_encode_bit(pi, 0, c + 5);
+	pic2_arith_encode_bit(pi, 1, c + 6);
+	n -= 1 + 2 + 4 + 8 + 16 + 32;
+	pic2_arith_encode_bit(pi, n & 1, c + 8);
+	pic2_arith_encode_bit(pi, n & 2, c + 9);
+	pic2_arith_encode_bit(pi, n & 4, c + 10);
+	pic2_arith_encode_bit(pi, n & 8, c + 11);
+	pic2_arith_encode_bit(pi, n & 16, c + 12);
+	pic2_arith_encode_bit(pi, n & 32, c + 13);
+    } else if (n < 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128) {
+	pic2_arith_encode_bit(pi, 0, c);
+	pic2_arith_encode_bit(pi, 0, c + 1);
+	pic2_arith_encode_bit(pi, 0, c + 2);
+	pic2_arith_encode_bit(pi, 0, c + 3);
+	pic2_arith_encode_bit(pi, 0, c + 4);
+	pic2_arith_encode_bit(pi, 0, c + 5);
+	pic2_arith_encode_bit(pi, 0, c + 6);
+	pic2_arith_encode_bit(pi, 1, c + 7);
+	n -= 1 + 2 + 4 + 8 + 16 + 32 + 64;
+	pic2_arith_encode_bit(pi, n & 1, c + 8);
+	pic2_arith_encode_bit(pi, n & 2, c + 9);
+	pic2_arith_encode_bit(pi, n & 4, c + 10);
+	pic2_arith_encode_bit(pi, n & 8, c + 11);
+	pic2_arith_encode_bit(pi, n & 16, c + 12);
+	pic2_arith_encode_bit(pi, n & 32, c + 13);
+	pic2_arith_encode_bit(pi, n & 64, c + 14);
+    } else {
+	pic2_arith_encode_bit(pi, 0, c);
+	pic2_arith_encode_bit(pi, 0, c + 1);
+	pic2_arith_encode_bit(pi, 0, c + 2);
+	pic2_arith_encode_bit(pi, 0, c + 3);
+	pic2_arith_encode_bit(pi, 0, c + 4);
+	pic2_arith_encode_bit(pi, 0, c + 5);
+	pic2_arith_encode_bit(pi, 0, c + 6);
+	pic2_arith_encode_bit(pi, 0, c + 7);
+    }
+}
+
+static void pic2_arith_press_chain(pi, x)
+struct pic2_info *pi;
+int x;
+{
+    int b, d;
+    pixel c;
+
+    b = -(pi->flag_now[x]);
+    c = pi->vram_now[x];
+    d = 0;
+
+    if (b < 0)
+	b = 0;
+
+    if (pi->flag_next[x] == 1 && pi->vram_next[x] == c) {
+	d = 1;
+	pi->flag_next[x] = -1;
+    } else if (pi->flag_next[x - 1] == 1 && pi->vram_next[x - 1] == c) {
+	d = 2;
+	pi->flag_next[x - 1] = -2;
+    } else if (pi->flag_next[x + 1] == 1 && pi->vram_next[x + 1] == c) {
+	d = 3;
+	pi->flag_next[x + 1] = -3;
+    } else if (pi->flag_next[x - 2] == 1 && pi->vram_next[x - 2] == c) {
+	d = 4;
+	pi->flag_next[x - 2] = -4;
+    } else if (pi->flag_next[x + 2] == 1 && pi->vram_next[x + 2] == c) {
+	if ((pi->flag_now[x + 2] != 0 && pi->vram_now[x + 2] == c)
+	    || (pi->flag_now[x + 1] != 0 && pi->vram_now[x + 1] == c)
+	    || (pi->flag_now[x + 3] != 0 && pi->vram_now[x + 3] == c)) {
+	    pic2_arith_encode_nbyte(pi, 0, 80 + 6 * b, 5);
+	    return;
+	}
+	d = 5;
+	pi->flag_next[x + 2] = -5;
+    }
+    pic2_arith_encode_nbyte(pi, d, 80 + 6 * b, 5);
+}
+
+static void pic2_arith_put_number(pi, xn, xa, xb)
+struct pic2_info *pi;
+int xn, xa, xb;
+{
+    short n;
+    byte maxcol;
+
+    maxcol = 0xff >> (8 - pi->header->depth / 3);
+
+    if (xa > ((int) maxcol >> 1)) {
+	if (xb > xa)
+	    n = (xb - xa) * 2 - 1;
+	else if (xa - ((int) maxcol - xa)  > xb)
+	    n = maxcol - xb;
+	else
+	    n = (xa - xb) * 2;
+    } else {
+	if (xb <= xa)
+	    n = (xa - xb) * 2;
+	else if (2 * xa < xb)
+	    n = xb;
+ 	else
+	    n = (xb - xa) * 2 - 1;
+    }
+    pic2_arith_encode_nn(pi, n, xn);
+}
+
+static void pic2_arith_write_color(pi, x)
+struct pic2_info *pi;
+int x;
+{
+    pixel c1, c2, cc;
+    short g0, r0, b0, r, g, b;
+    int i, j;
+    unsigned short k;
+    pixel *p, *pp;
+    short colbits;
+    pixel rmask, gmask, bmask;
+    byte maxcol;
+
+    colbits = pi->header->depth / 3;
+    rmask = (0xff >> (8 - colbits)) << (colbits * 2);
+    gmask = (0xff >> (8 - colbits)) <<  colbits;
+    bmask = (0xff >> (8 - colbits));
+    maxcol = (byte) bmask;
+
+    cc = pi->vram_now[x];
+    c1 = pi->vram_prev[x];
+    k = ((c1 >> ((colbits - 3) * 3)) & 0x1c0)
+      | ((c1 >> ((colbits - 3) * 2)) & 0x038)
+      | ((c1 >>  (colbits - 3)     ) & 0x007);
+    if (colbits == 5)
+	k = pic2_exchange_rg(k, 3);
+
+    p = pi->cache[k];
+    for (i = 0; i < (PIC2_ARITH_CACHE - 1); i++) {
+	if (cc == *p++)
+	    break;
+    }
+    if (i == (PIC2_ARITH_CACHE - 1)) {
+	pp = p - 1;
+	for (j = i; j > 0; j--) {
+	    *--p = *--pp;
+	}
+	pi->cache[k][0] = cc;
+	pic2_arith_encode_bit(pi, 1, pi->cache_hit_c);
+	pi->cache_hit_c = 16;
+
+	c2 = pi->vram_now[x - 1];
+	r = ((c1 & rmask) + (c2 & rmask)) >> (colbits * 2 + 1);
+	g = ((c1 & gmask) + (c2 & gmask)) >> (colbits     + 1);
+	b = ((c1 & bmask) + (c2 & bmask)) >> (              1);
+
+	r0 = (cc >> (colbits * 2)) & maxcol;
+	g0 = (cc >>  colbits     ) & maxcol;
+	b0 =  cc                   & maxcol;
+
+	r = r + g0 - g;
+	if (r < 0)
+	    r = 0;
+	else if (r > (short) maxcol)
+	    r = maxcol;
+
+	b = b + g0 - g;
+	if (b < 0)
+	    b = 0;
+	else if (b > (short) maxcol)
+	    b = maxcol;
+
+	pic2_arith_put_number(pi, 32, g, g0);
+	pic2_arith_put_number(pi, 48, r, r0);
+	pic2_arith_put_number(pi, 64, b, b0);
+    } else {
+	*--p = pi->cache[k][i / 2];
+	pi->cache[k][i / 2] = pi->cache[k][0];
+	pi->cache[k][0] = cc;
+
+	pic2_arith_encode_bit(pi, 0, pi->cache_hit_c);
+	pi->cache_hit_c = 15;
+	pic2_arith_encode_nn(pi, i, 17);
+    }
+}
+
+static void pic2_arith_press_line2(pi)
+struct pic2_info *pi;
+{
+    int x, xw, ymax;
+    pixel cc;
+
+    xw = pi->block->x_wid;
+    ymax = pi->block->y_wid -1;
+    cc = pi->vram_now[xw - 1];			/* last color */
+    pi->vram_next[-1] = cc;
+
+    /* mark change point */
+    for (x = 0; x < xw; x++)
+	if (cc != pi->vram_next[x]) {
+	    pi->flag_next[x] = 1;
+	    cc = pi->vram_next[x];
+	} else
+	    pi->flag_next[x] = 0;
+
+    for (x = 0; x < xw; x++) {
+	if (pi->flag_now[x] == 1) {			/* change point */
+	    pi->flag2_now  [x + 1]++;
+	    pi->flag2_now  [x + 2]++;
+	    pi->flag2_next [x - 1]++;
+	    pi->flag2_next [x    ]++;
+	    pi->flag2_next [x + 1]++;
+	    pi->flag2_next2[x - 1]++;
+	    pi->flag2_next2[x    ]++;
+	    pi->flag2_next2[x + 1]++;
+
+	    /* write change point */
+	    pic2_arith_encode_bit(pi, 1, pi->flag2_now[x]);
+
+	    /* write color */
+	    pic2_arith_write_color(pi, x);
+
+	    /* if not last line, write chain */
+	    if (pi->ynow - 1 < ymax)
+		pic2_arith_press_chain(pi, x);
+	} else if (pi->flag_now[x] == 0)		/* not on chain */
+	    /* write change point */
+	    pic2_arith_encode_bit(pi, 0, pi->flag2_now[x]);
+	else				/* on chain */
+	     /* if not on last line, write next chain */
+	     if (pi->ynow - 1 < ymax)
+		 pic2_arith_press_chain(pi, x);
+    }
+}
+
+static int pic2_arith_press_line(pi, line)
+struct pic2_info *pi;
+pixel **line;
+{
+    int i, xw, ymax;
+    long *c_sum, *c_0_sum;
+
+    xw = pi->block->x_wid;
+    ymax = pi->block->y_wid -1;
+    c_sum = (long *) pi->mulu_tab;
+    c_0_sum = c_sum + PIC2_ARITH_CONTEXT +1;
+
+    pic2_handle_para(pi, 0);
+
+    xvbzero((char *) pi->flag2_next2 - 4,
+	    (8 + xw) * sizeof(pi->flag2_next2[0]));
+
+    if (pi->ynow == 0) {			/* first line */
+	int x;
+	pixel cc = 0;
+
+	if (pi->dd != 0) {			/* compress pass */
+	    unsigned short c_tab[PIC2_ARITH_CONTEXT];
+
+	    for (i = 0; i < PIC2_ARITH_CONTEXT; i++) {
+		unsigned long a, b;
+		a = c_0_sum[i];
+		b = c_sum[i];
+		while (a > 32767) {
+		    a /= 2;
+		    b /= 2;
+		}
+		if (a == b)
+		    c_tab[i] = 0xffff;		/* b==0 here, too */
+		else
+		    c_tab[i] = (65536 * a) / b; /* a < b, so less 65536 */
+	    }
+	    for (i = 0; i < 16384; i++) {
+		pi->mulu_tab[i] = (long) (i / 128 + 128) * (int) c_tab[i & 127] / 256;
+		if (pi->mulu_tab[i] == 0)
+		    pi->mulu_tab[i] = 1;	/* 0 is wrong */
+	    }
+	    for (i = 0; i < PIC2_ARITH_CONTEXT; i++)
+		pic2_write_short(pi, c_tab[i]);
+
+	    xvbzero((char *) pi->vram_now, xw * sizeof(pi->vram_now[0]));
+	} else {				/* statistical pass */
+	    xvbzero((char *) c_0_sum, PIC2_ARITH_CONTEXT * sizeof(c_0_sum[0]));
+	    xvbzero((char *) c_sum, PIC2_ARITH_CONTEXT * sizeof(c_sum[0]));
+	}
+
+	/* initialize flags */
+	xvbzero((char *) pi->cache, 8 * 8 * 8 * sizeof(pi->cache[0]));
+	xvbzero((char *) pi->cache_pos, 8 * 8 * 8 * sizeof(pi->cache_pos[0]));
+
+	xvbzero((char *) pi->flag2_next - 4,
+		(8 + xw) * sizeof(pi->flag2_next[0]));
+	xvbzero((char *) pi->flag2_next2 - 4,
+		(8 + xw) * sizeof(pi->flag2_next2[0]));
+
+	pi->vram_next[-1] = cc;
+	for (x = 0; x < xw; x++)
+	    if (cc != pi->vram_next[x]) {
+		pi->flag_next[x] = 1;
+		cc = pi->vram_next[x];
+	    } else
+		pi->flag_next[x] = 0;
+
+	pi->aa = 0xffff;
+	cc = 0;
+	pi->cache_hit_c = 16;
+    } else					/* after second line */
+	pic2_arith_press_line2(pi);
+
+    if (pi->ynow ==  ymax) {
+	pi->ynow++;
+	pic2_handle_para(pi, 1);
+	pic2_handle_para(pi, 0);
+	pic2_arith_press_line2(pi);
+    }
+    /* line buffer for next data */
+    if (line != NULL)
+	*line = pi->vram_prev;
+
+    pi->ynow++;
+
+    if (pi->ynow - 1 < ymax) {
+	pic2_handle_para(pi, 1);
+	return (pi->ynow);
+    } else {					/* end */
+	if (pi->dd == 0) {			/* statistical pass */
+	    pi->dd = 1;
+	    pi->ynow = 0;
+	    pic2_handle_para(pi, 1);
+	    return (0);
+	} else {
+	    pic2_handle_para(pi, 1);
+	    pic2_arith_flush_bit_buf(pi);
+	    return (-2);			/* end */
+	}
+    }
+}
+
+static int pic2_arith_saver_init(pi, line)
+struct pic2_info *pi;
+pixel **line;
+{
+    pi->ynow = 0;
+
+    /* check the color depth */
+    if (pi->header->depth % 3)
+	pic2_error(pi, PIC2_DEPTH);
+
+    /* set next line function */
+    pi->next_line = pic2_arith_press_line;
+
+    if (line != NULL)
+	*line = pi->vram_next + 4;
+
+    pic2_seek_file(pi, pi->next_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET);
+
+    /* clear bit field marker */
+    pi->bs.rest = 0;
+    pi->bs.cur = 0;
+    pi->bs.zero = 0;
+    pi->bs.bits = 0;
+
+    return (0);
+}
+
+/*
+ * These functions are fast pic2 format compressor.
+ */
+static void pic2_fast_write_length(pi, n)
+struct pic2_info *pi;
+int n;
+{
+    int	a, b;
+    static const unsigned short len_data[8][2] = {
+	{1, 0},
+	{1, 0},
+	{3, 4},
+	{3, 5},
+	{5, 24},
+	{5, 25},
+	{5, 26},
+	{5, 27},
+    };
+
+    n++;
+    if (n < 8)
+	pic2_write_bits(pi, len_data[n][1], len_data[n][0]);
+    else {
+	a = 0;
+	b = 2;
+	while (n > b - 1) {
+	    a = a + 1;
+	    b = b * 2;
+	}
+	pic2_write_bits(pi, 0xfffffffe, a + 1);
+	if (a > 0)
+	    pic2_write_bits(pi, n - b / 2, a);
+    }
+}
+
+static void pic2_fast_press_chain(pi, x)
+struct pic2_info *pi;
+int x;
+{
+    int ymax;
+    pixel cc;
+
+    ymax = pi->block->y_wid -1;
+    cc = pi->vram_now[x];
+
+    if (pi->ynow - 1 == ymax) {
+	pic2_write_bits(pi, 0, 1);
+	return;
+    }
+    if (pi->flag_next[x] == 1 && pi->vram_next[x] == cc) {
+	pi->flag_next[x] = -1;
+	pic2_write_bits(pi, 3, 2);
+    } else if (pi->flag_next[x - 1] == 1 && pi->vram_next[x - 1] == cc) {
+	pi->flag_next[x - 1] = -1;
+	pic2_write_bits(pi, 11, 4);
+    } else if (pi->flag_next[x + 1] == 1 && pi->vram_next[x + 1] == cc) {
+	pi->flag_next[x + 1] = -1;
+	pic2_write_bits(pi, 9, 4);
+    } else if (pi->flag_next[x - 2] == 1 && pi->vram_next[x - 2] == cc) {
+	pi->flag_next[x - 2] = -1;
+	pic2_write_bits(pi, 10, 4);
+    } else if ((pi->flag_next[x + 2] == 1 && pi->vram_next[x + 2] == cc)
+		&& !(pi->flag_now[x + 2] != 0 && pi->vram_now[x + 2] == cc)) {
+	pi->flag_next[x + 2] = -1;
+	pic2_write_bits(pi, 8, 4);
+    } else
+	pic2_write_bits(pi, 0, 1);
+}
+
+static void pic2_fast_press_chain2(pi, x)
+struct pic2_info *pi;
+int x;
+{
+    int ymax;
+    pixel cc;
+    char *chain_buff;
+
+    ymax = pi->block->y_wid -1;
+    chain_buff = (char *) pi->mulu_tab;
+    cc = pi->vram_now[x];
+
+    if (pi->ynow - 1 == ymax) {
+	chain_buff[pi->cc++] = 0;
+	return;
+    }
+    if (pi->flag_next[x] == 1 && pi->vram_next[x] == cc) {
+	pi->flag_next[x] = -1;
+	chain_buff[pi->cc++] = 1;
+    } else if (pi->flag_next[x - 1] == 1 && pi->vram_next[x - 1] == cc) {
+	pi->flag_next[x - 1] = -1;
+	chain_buff[pi->cc++] = 2;
+    } else if (pi->flag_next[x + 1] == 1 && pi->vram_next[x + 1] == cc) {
+	pi->flag_next[x + 1] = -1;
+	chain_buff[pi->cc++] = 3;
+    } else if (pi->flag_next[x - 2] == 1 && pi->vram_next[x - 2] == cc) {
+	pi->flag_next[x - 2] = -1;
+	chain_buff[pi->cc++] = 4;
+    } else if ((pi->flag_next[x + 2] == 1 && pi->vram_next[x + 2] == cc)
+	       && !(pi->flag_now[x + 2] != 0 && pi->vram_now[x + 2] == cc)) {
+	pi->flag_next[x + 2] = -1;
+	chain_buff[pi->cc++] = 5;
+    } else
+	chain_buff[pi->cc++] = 0;
+}
+
+static void pic2_fast_flush_chain(pi)
+struct pic2_info *pi;
+{
+    int i;
+    char *chain_buf;
+
+    chain_buf = (char *) pi->mulu_tab;
+    for (i = 0; i < pi->cc; i++){
+	switch (chain_buf[i]) {
+	case 0:
+	    pic2_write_bits(pi, 0, 1);
+	    break;
+	case 1:
+	    pic2_write_bits(pi, 3, 2);
+	    break;
+	case 2:
+	    pic2_write_bits(pi, 11, 4);
+	    break;
+	case 3:
+	    pic2_write_bits(pi, 9, 4);
+	    break;
+	case 4:
+	    pic2_write_bits(pi, 10, 4);
+	    break;
+	case 5:
+	    pic2_write_bits(pi, 8, 4);
+	    break;
+	}
+    }
+    pi->cc = 0;
+}
+
+static void pic2_fast_write_color(pi, x)
+struct pic2_info *pi;
+int x;
+{
+    pixel cc, bc;
+    unsigned short j, k, m;
+    short depth, colbits;
+    pixel (*cache)[PIC2_FAST_CACHE];
+
+    depth = pi->header->depth;
+    colbits = depth / 3;
+    cache = (pixel (*)[PIC2_FAST_CACHE]) pi->cache;
+
+    bc = pi->vram_now[x - 1];
+    bc = pic2_exchange_rg(bc, colbits);
+    k = pic2_shift_bits(bc, 8 - depth);
+    cc = pi->vram_now[x];
+    m = pi->cache_pos[k];
+
+    for (j = 0; j < PIC2_FAST_CACHE; j++)
+	if (cache[k][(m + j) & (PIC2_FAST_CACHE - 1)] == cc)
+	    break;
+
+    if (j == PIC2_FAST_CACHE) {
+	m = (m - 1) & (PIC2_FAST_CACHE - 1);
+	pi->cache_pos[k] = m;
+	cache[k][m] = cc;
+
+	cc = pic2_exchange_rg(cc, colbits);
+	pic2_write_bits(pi, 0, 1);
+	pic2_write_bits(pi, cc, depth);
+    } else {
+	pic2_write_bits(pi, 1, 1);
+	pic2_write_bits(pi, j, 6);
+    }
+}
+
+static void pic2_fast_press_line2(pi)
+struct pic2_info *pi;
+{
+    int x, xw;
+    pixel cc;
+
+    xw = pi->block->x_wid;
+    cc = pi->vram_now[xw - 1];			/* last color */
+    pi->vram_next[-1] = cc;
+
+    /* mark change point */
+    for (x = 0; x < xw; x++)
+	if (cc != pi->vram_next[x]) {
+	    pi->flag_next[x] = 1;
+	    cc = pi->vram_next[x];
+	} else
+	    pi->flag_next[x] = 0;
+
+    for (x = 0; x < xw; x++)
+	if (pi->flag_now[x] == 1) {			/* change point */
+	    if (pi->aa >= 1023)
+		pi->aa++;
+	    pic2_fast_write_length(pi, pi->aa);
+	    pic2_fast_flush_chain(pi);
+	    pi->aa = 0;
+	    pic2_fast_write_color(pi, x);
+	    pic2_fast_press_chain(pi, x);
+	} else if (pi->flag_now[x] == 0) {
+	    pi->aa++;
+	} else {
+	    pic2_fast_press_chain2(pi, x);
+	    if (pi->cc == 1023) {
+		pic2_fast_write_length(pi, 1023);
+		pic2_fast_flush_chain(pi);
+		pi->aa = 0;
+	    }
+	}
+}
+
+static int pic2_fast_press_line(pi, line)
+struct pic2_info *pi;
+pixel **line;
+{
+    int xw, ymax;
+
+    xw = pi->block->x_wid;
+    ymax = pi->block->y_wid -1;
+
+    pic2_handle_para(pi, 0);
+
+    if (pi->ynow == 0) {			/* first line */
+	int x;
+	pixel cc = 0;
+
+	/* initialize flags */
+	xvbzero((char *) pi->cache, 256 * sizeof(pi->cache[0]));
+	xvbzero((char *) pi->cache_pos,
+		PIC2_FAST_CACHE * sizeof(pi->cache_pos[0]));
+
+	/* mark change point */
+	pi->vram_next[-1] = cc;
+	for (x = 0; x < xw; x++)
+	    if (cc != pi->vram_next[x]) {
+		pi->flag_next[x] = 1;
+		cc = pi->vram_next[x];
+	    } else
+		pi->flag_next[x] = 0;
+
+	pi->cc = 0;
+	pi->aa = 0;
+    } else					/* after second line */
+	pic2_fast_press_line2(pi);
+
+    if (pi->ynow ==  ymax) {
+	pi->ynow++;
+	pic2_handle_para(pi, 1);
+	pic2_handle_para(pi, 0);
+	pic2_fast_press_line2(pi);
+    }
+    /* line buffer for next data */
+    if (line != NULL)
+	*line = pi->vram_prev;
+
+    pi->ynow++;
+
+    if (pi->ynow - 1 < ymax) {
+	pic2_handle_para(pi, 1);
+	return (pi->ynow);
+    } else {					/* end */
+	pic2_handle_para(pi, 1);
+	if (pi->aa >= 1023)
+	    pi->aa++;
+	pic2_fast_write_length(pi, pi->aa);
+	pic2_fast_flush_chain(pi);
+	return (-2);				/* end */
+    }
+}
+
+static int pic2_fast_saver_init(pi, line)
+struct pic2_info *pi;
+pixel **line;
+{
+    pi->ynow = 0;
+
+    /* check the color depth */
+    if (pi->header->depth % 3)
+	pic2_error(pi, PIC2_DEPTH);
+
+    /* set next line function */
+    pi->next_line = pic2_fast_press_line;
+    if (line != NULL)
+	*line = pi->vram_next + 4;
+
+    pic2_seek_file(pi, pi->next_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET);
+
+    /* clear bit field marker */
+    pi->bs.rest = 0;
+    pi->bs.cur = 0;
+
+    return (0);
+}
+
+/*
+ * These functions are beta pic2 format compressor.
+ */
+static int pic2_beta_press_line(pi, line)
+struct pic2_info *pi;
+pixel **line;
+{
+    int i, xw, ymax;
+    byte *p;
+    pixel *pc;
+    short depth, pixbyte, colbits;
+
+    depth = pi->header->depth;
+    pixbyte = depth / 8 + ((depth % 8) > 0);
+    colbits = depth / 3;
+
+    xw = pi->block->x_wid;
+    ymax = pi->block->y_wid - 1;
+
+    pc = pi->vram_now;
+    p = (byte *) pi->vram_prev;
+    if (pixbyte == 3) {
+	for (i = 0; i < xw; i++, pc++) {
+	    *p++ = *pc >> 16;
+	    *p++ = *pc >>  8;
+	    *p++ = *pc;
+	}
+	pic2_write_file(pi, pi->vram_prev, (size_t) (xw * 3));
+    } else if (pixbyte == 2) {
+	if (strncmp(pi->block->id, "P2BM", 4) == 0)
+	    for (i = 0; i < xw; i++, pc++) {
+		if (colbits == 5) {
+		    *pc = pic2_exchange_rg(*pc, colbits);
+		    *pc <<= 1;
+		}
+		*p++ = *pc >> 8;
+		*p++ = *pc;
+	    }
+	else
+	    for (i = 0; i < xw; i++, pc++) {
+		if (colbits == 5) {
+		    *pc = pic2_exchange_rg(*pc, colbits);
+		    *pc <<= 1;
+		}
+		*p++ = *pc;
+		*p++ = *pc >> 8;
+	    }
+	pic2_write_file(pi, pi->vram_prev, (size_t) (xw * 2));
+    } else {
+	for (i = 0; i < xw; i++, pc++)
+	    *p++ = *pc;
+	pic2_write_file(pi, pi->vram_prev, (size_t) xw);
+    }
+    if (line != NULL)
+	*line = pi->vram_now;
+
+    pi->ynow++;
+    if (pi->ynow > ymax)
+	return (-2);
+    return (pi->ynow);
+}
+
+static int pic2_beta_saver_init(pi, line)
+struct pic2_info *pi;
+pixel **line;
+{
+    pi->ynow = 0;
+
+    *line = pi->vram_now;
+    pi->next_line = pic2_beta_press_line;
+    pic2_seek_file(pi, pi->next_pos + PIC2_BLOCK_HEADER_SIZE, SEEK_SET);
+    return (0);
+}
+
+/*
+ * This function saves compressed data.
+ */
+static void pic2_write_data(pi, data, ptype, x_offset, y_offset, w, h,
+			    rmap, gmap, bmap, type, depth)
+struct pic2_info *pi;
+byte *data;
+int ptype;
+int x_offset, y_offset;
+int w, h;
+byte *rmap, *gmap, *bmap;
+int type, depth;
+{
+    int i, line;
+    pixel *linep;
+    short colbits;
+
+    colbits = pi->header->depth / 3;
+
+    line = pic2_save_block(pi, &linep, x_offset, y_offset, w, h,
+			   form_tab[type].id, 0xffffffff);
+    while (line >= 0) {
+	byte r, g, b;
+	int pic_idx;
+
+	pic_idx = line * w * ((ptype == PIC24) ? 3 : 1);
+
+	for (i = 0; i < w; i++) {
+	    if (ptype != PIC24) {
+		r = rmap[data[pic_idx]];
+		g = gmap[data[pic_idx]];
+		b = bmap[data[pic_idx]];
+		pic_idx++;
+	    } else {
+		r = data[pic_idx++];
+		g = data[pic_idx++];
+		b = data[pic_idx++];
+	    }
+	    if (pi->writing_grey)
+		r = g = b = MONO(r, g, b);
+
+	    r = pic2_convert_color_bits(r, 8, colbits);
+	    g = pic2_convert_color_bits(g, 8, colbits);
+	    b = pic2_convert_color_bits(b, 8, colbits);
+
+	    linep[i] = ((pixel) r << (colbits * 2))
+		     | ((pixel) g <<  colbits     )
+		     | ((pixel) b                 );
+	}
+	line = pic2_next_line(pi, &linep);
+	WaitCursor();
+    }
+}
+
+/*
+ * This function compresses/extracts one line buffer.
+ */
+static int pic2_next_line(pi, line)
+struct pic2_info *pi;
+pixel **line;
+{
+    int res;
+
+    res = pi->next_line(pi, line);
+    if (res == -2) {
+	if (pi->mode == PIC2_WRITE_MODE) {
+	    long new_pos;
+
+	    new_pos = pic2_tell_file(pi);
+	    pi->block->size = new_pos - pi->next_pos;
+	    pic2_seek_file(pi, pi->next_pos, SEEK_SET);
+	    pic2_write_block_header(pi);
+	    pi->next_pos = new_pos;
+	    if (DEBUG)
+		pic2_show_pic2_info(pi);
+	}
+	pic2_free_buffer(pi);
+    }
+    return (res);
+}
+
+/*
+ * These functions find the pic2 image block.
+ * pic2_next_block:
+ *	moves the file pointer to the next image block.
+ * pic2_find_block:
+ *	finds the first image block and moves the file pointer there.
+ */
+static int pic2_next_block(pi)
+struct pic2_info *pi;
+{
+    int i;
+
+    if (pi->mode != PIC2_READ_MODE)
+	return (-1);
+
+    /* go to block for read */
+    pic2_seek_file(pi, pi->next_pos, SEEK_SET);
+
+    /* read the head of block header */
+    pic2_read_block_header1(pi);
+
+    /* end block ? */
+    if (pi->block->id[0] == 0)
+	return (0);
+
+    /* set current block */
+    pi->block_pos = pi->next_pos;
+
+    /* set next block */
+    pi->next_pos += pi->block->size;
+
+   /* check block id */
+    for (i = 0; i < n_form_tab; i++) {
+	if (xvbcmp(pi->block->id, form_tab[i].id, (size_t) 4) == 0)
+	    break;
+    }
+    if (i == n_form_tab)
+	return (2);
+
+    /* read the rest of block header */
+    pic2_read_block_header2(pi);
+
+    if (pi->block->x_offset + pi->block->x_wid > pi->x_max)
+	pi->x_max = pi->block->x_offset + pi->block->x_wid;
+
+    if (pi->block->y_offset + pi->block->y_wid > pi->y_max)
+	pi->y_max = pi->block->y_offset + pi->block->y_wid;
+
+    if (DEBUG)
+	pic2_show_pic2_info(pi);
+    return (1);
+}
+
+static int pic2_find_block(pi)
+struct pic2_info *pi;
+{
+    if (pi->mode != PIC2_READ_MODE)
+	return (-1);
+
+    pi->next_pos = pi->header->size;
+    return (pic2_next_block(pi));
+}
+
+/*
+ * These functions load/save the pic2 image block.
+ * pic2_load_block:
+ *	initializes loader information with current block information.
+ * pic2_save_block:
+ *	initializes saver information.
+ */
+static int pic2_load_block(pi)
+struct pic2_info *pi;
+{
+    int i;
+
+    for (i = 0; i < n_form_tab; i++) {
+	if (xvbcmp(pi->block->id, form_tab[i].id, (size_t) 4) == 0)
+	    break;
+    }
+    if (i == n_form_tab)
+	return (2);
+
+    pic2_alloc_buffer(pi);
+    return (form_tab[i].loader_init(pi));
+}
+
+static int pic2_save_block(pi, line, x, y, xw, yw, id, opaque)
+struct pic2_info *pi;
+pixel **line;
+int x, y, xw, yw;
+char *id;
+pixel opaque;
+{
+    int i;
+
+    for (i = 0; i < n_form_tab; i++) {
+	if (xvbcmp(id, form_tab[i].id, (size_t) 4) == 0)
+	    break;
+    }
+    if (i == n_form_tab)
+	return (2);
+
+    strncpy(pi->block->id, id, 4);
+    pi->block->x_wid = xw;
+    pi->block->y_wid = yw;
+    pi->block->x_offset = x;
+    pi->block->y_offset = y;
+    pi->block->reserve = 0;
+
+    if (x < 0)
+	x = 0;
+    if (y < 0)
+	y = 0;
+    if (x + xw > pi->x_max)
+	pi->x_max = x + xw;
+    if (y + yw > pi->y_max)
+	pi->y_max = y + yw;
+
+    if (opaque != 0xffffffff) {
+	pi->block->flag = 1;
+	pi->block->opaque = opaque;
+    } else {
+	pi->block->flag = 0;
+	pi->block->opaque = 0;
+    }
+    pic2_alloc_buffer(pi);
+
+    return (form_tab[i].saver_init(pi, line));
+}
+
+/*
+ * These functions set/get palettes.
+ * pic2_read_palette:
+ *	copy the palettes from pic2_info to PICINFO.
+ * pic2_write_palette:
+ *	copy the palettes from PICINFO to pic2_info.
+ */
+#ifndef PIC2_IGNORE_UNUSED_FUNCTIONS
+static void pic2_read_palette(pi, r, g, b)
+struct pic2_info *pi;
+byte *r, *g, *b;
+{
+    int i;
+
+    if (pi->n_pal > 256)
+	pi->n_pal = 256;
+
+    if (pi->pal_bits > 8)
+	pi->pal_bits = 8;
+
+    for (i = 0; i < pi->n_pal; i++) {
+	*r++ =pic2_convert_color_bits(pi->pal[i][0] >> (8 - pi->pal_bits),
+				      pi->pal_bits, 8);
+	*g++ =pic2_convert_color_bits(pi->pal[i][1] >> (8 - pi->pal_bits),
+				      pi->pal_bits, 8);
+	*b++ =pic2_convert_color_bits(pi->pal[i][2] >> (8 - pi->pal_bits),
+				      pi->pal_bits, 8);
+    }
+}
+
+static void pic2_write_palette(pi, n_pal, pal_bits, r, g, b)
+struct pic2_info *pi;
+int n_pal, pal_bits;
+byte *r, *g, *b;
+{
+    int i;
+
+    if (n_pal > 256)
+	pi->n_pal = 256;
+    else
+	pi->n_pal = n_pal;
+
+    if (pal_bits > 8)
+	pi->pal_bits = 8;
+    else
+	pi->pal_bits = pal_bits;
+
+    for (i = 0; i < n_pal; i++) {
+	pi->pal[i][0] = pic2_convert_color_bits(*r++, 8, pal_bits)
+	    << (8 - pal_bits);
+	pi->pal[i][1] = pic2_convert_color_bits(*g++, 8, pal_bits)
+	    << (8 - pal_bits);
+	pi->pal[i][2] = pic2_convert_color_bits(*b++, 8, pal_bits)
+	    << (8 - pal_bits);
+    }
+}
+#endif /* PIC2_IGNORE_UNUSED_FUNCTIONS */
+
+/*
+ * These functions handle color bits.
+ * pic2_convert_color_bits:
+ *	converts color bits.
+ * pic2_pad_color_bits:
+ *	pads color bits.
+ * pic2_reduce_color_bits:
+ *	reduces color bits.
+ * pic2_exchange_rg:
+ *      exchanges red and green values.
+ */
+static byte pic2_convert_color_bits(c, from, to)
+int c, from, to;
+{
+    if (from == to)
+	return ((byte) c);
+    else if (from < to)
+	return (pic2_pad_color_bits(c, from, to));
+    else
+	return (pic2_reduce_color_bits(c, from, to));
+}
+
+static byte pic2_pad_color_bits(c, from, to)
+int c, from, to;
+{
+    byte p = 0;
+
+    do {
+	to -= from;
+	p |= pic2_shift_bits(c, to);
+    } while (to >= 0);
+    return (p);
+}
+
+static byte pic2_reduce_color_bits(c, from, to)
+int c, from, to;
+{
+    return ((byte) (c >> (from - to)));
+}
+
+static pixel pic2_exchange_rg(p, colbits)
+pixel p;
+int colbits;
+{
+    pixel rmask, gmask, bmask;
+
+    rmask = (0xff >> (8 - colbits)) << (colbits * 2);
+    gmask = (0xff >> (8 - colbits)) <<  colbits;
+    bmask = (0xff >> (8 - colbits));
+
+    p = ((p << colbits) & rmask)
+      | ((p >> colbits) & gmask)
+      | ( p             & bmask);
+    return (p);
+}
+
+/*
+ * This function handles work memory buffer.
+ */
+static void pic2_handle_para(pi, mode)
+struct pic2_info *pi;
+int mode;
+{
+    static pixel *vram_prev, *vram_now, *vram_next;
+    static short *flag_now, *flag_next;
+    static short *flag2_now, *flag2_next, *flag2_next2;
+
+    switch (mode) {
+    case 0:
+	vram_prev = pi->vram_prev;
+	vram_now = pi->vram_now;
+	vram_next = pi->vram_next;
+	flag_now = pi->flag_now;
+	flag_next = pi->flag_next;
+	flag2_now = pi->flag2_now;
+	flag2_next = pi->flag2_next;
+	flag2_next2 = pi->flag2_next2;
+	pi->vram_prev += 4;
+	pi->vram_now += 4;
+	pi->vram_next += 4;
+	pi->flag_now += 4;
+	pi->flag_next += 4;
+	pi->flag2_now += 4;
+	pi->flag2_next += 4;
+	pi->flag2_next2 += 4;
+	break;
+    case 1:
+	pi->vram_prev = vram_now;
+	pi->vram_now = vram_next;
+	pi->vram_next = vram_prev;
+	pi->flag_now = flag_next;
+	pi->flag_next = flag_now;
+	pi->flag2_now = flag2_next;
+	pi->flag2_next = flag2_next2;
+	pi->flag2_next2 = flag2_now;
+	break;
+    }
+}
+
+/*
+ * These functions alloc/free work memory.
+ * pic2_alloc_buffer:
+ *	alloc work memory buffer.
+ * pic2_free_buffer:
+ *	free work memory buffer.
+ */
+static int pic2_alloc_buffer(pi)
+struct pic2_info *pi;
+{
+    int wid;
+    byte *p;
+
+    if (pi->buf != NULL)
+	return (-1);
+
+    wid = pi->block->x_wid;
+
+    p = pi->buf = (byte *) pic2_new((wid + 8) * sizeof(pixel) * 3   // GRR POSSIBLE OVERFLOW / FIXME
+				    + sizeof(pi->cache[0]) * 8 * 8 * 8
+				    + sizeof(pi->cache_pos[0]) * 8 * 8 * 8
+				    + sizeof(pi->mulu_tab[0]) * 16384
+				    + sizeof(pi->flag_now[0]) * ((wid+8) * 5),
+				    "pic2_alloc_buffer");
+
+    pi->vram_prev = (pixel *) p;
+    p += (wid + 8) * sizeof(pixel);
+    pi->vram_now = (pixel *) p;
+    p += (wid + 8) * sizeof(pixel);
+    pi->vram_next = (pixel *) p;
+    p += (wid + 8) * sizeof(pixel);
+    pi->cache = (pixel (*)[PIC2_ARITH_CACHE]) p;
+    p += sizeof(pi->cache[0]) * 8 * 8 * 8;
+    pi->cache_pos = (unsigned short *) p;
+    p += sizeof(pi->cache_pos[0]) * 8 * 8 * 8;
+    pi->mulu_tab = (unsigned short *) p;
+    p += sizeof(pi->mulu_tab[0]) * 16384;
+    pi->flag_now = (short *) p;
+    p += sizeof(pi->flag_now[0]) * (wid + 8);
+    pi->flag_next = (short *) p;
+    p += sizeof(pi->flag_next[0]) * (wid + 8);
+    pi->flag2_now = (short *) p;
+    p += sizeof(pi->flag2_now[0]) * (wid + 8);
+    pi->flag2_next = (short *) p;
+    p += sizeof(pi->flag2_next[0]) * (wid + 8);
+    pi->flag2_next2 = (short *) p;
+    p += sizeof(pi->flag2_next2[0]) * (wid + 8);
+    return (0);
+}
+
+static void pic2_free_buffer(pi)
+struct pic2_info *pi;
+{
+    free(pi->buf);
+    pi->buf = NULL;
+}
+
+/*
+ * These functions handle the file pointer.
+ * pic2_seek_file:
+ *	moves the file pointer.
+ * pic2_tell_file:
+ *	tells the location of the file pointer.
+ */
+static long pic2_seek_file(pi, offset, whence)
+struct pic2_info *pi;
+long offset;
+int whence;
+{
+    long n;
+
+    n = fseek(pi->fp, offset, whence);
+    if (n < 0)
+	pic2_file_error(pi, PIC2_CORRUPT);
+
+    return (n);
+}
+
+static long pic2_tell_file(pi)
+struct pic2_info *pi;
+{
+    return (ftell(pi->fp));
+}
+
+/*
+ * These functions handle file.
+ * pic2_read_file:
+ *	reads data from the file.
+ * pic2_read_long:
+ *	reads long word data from the file and converts to internal expression.
+ * pic2_read_short:
+ *	reads word data from the file and converts to internal expression.
+ * pic2_read_char:
+ *	reads byte data from the file.
+ * pic2_write_file:
+ *	writes data to the file.
+ * pic2_write_long:
+ *	converts long word data to common expression and writes to the file.
+ * pic2_write_short:
+ *	converts word data to common expression and writes to the file.
+ * pic2_write_char:
+ *	writes byte data to the file.
+ */
+static int pic2_read_file(pi, buf, size)
+struct pic2_info *pi;
+void *buf;
+size_t size;
+{
+    if (fread(buf, (size_t) 1, size, pi->fp) < size)
+	pic2_file_error(pi, PIC2_CORRUPT);
+    return (0);
+}
+
+static long pic2_read_long(pi)
+struct pic2_info *pi;
+{
+    byte buf[4];
+
+    if (fread(buf, (size_t) 4, (size_t) 1, pi->fp) < 1)
+	pic2_file_error(pi, PIC2_CORRUPT);
+    return (pic2_cextolong(buf));
+}
+
+static short pic2_read_short(pi)
+struct pic2_info *pi;
+{
+    byte buf[2];
+
+    if (fread(buf, (size_t) 2, (size_t) 1, pi->fp) < 1)
+	pic2_file_error(pi, PIC2_CORRUPT);
+    return (pic2_cextoshort(buf));
+}
+
+static char pic2_read_char(pi)
+struct pic2_info *pi;
+{
+    int c;
+
+    if ((c = fgetc(pi->fp)) == EOF)
+	pic2_file_error(pi, PIC2_CORRUPT);
+    return ((char) c);
+}
+
+static int pic2_write_file(pi, buf, size)
+struct pic2_info *pi;
+void *buf;
+size_t size;
+{
+    if (fwrite(buf, (size_t) 1, size, pi->fp) < size)
+	pic2_error(pi, PIC2_WRITE);
+    return (0);
+}
+
+static int pic2_write_long(pi, n)
+struct pic2_info *pi;
+long n;
+{
+    byte buf[4];
+
+    pic2_longtocex(buf, n);
+    if (fwrite(buf, (size_t) 4, (size_t) 1, pi->fp) < 1)
+	pic2_error(pi, PIC2_WRITE);
+    return (0);
+}
+
+static int pic2_write_short(pi, n)
+struct pic2_info *pi;
+int n;
+{
+    byte buf[2];
+
+    pic2_shorttocex(buf, n);
+    if (fwrite(buf, (size_t) 2, (size_t) 1, pi->fp) < 1)
+	pic2_error(pi, PIC2_WRITE);
+    return (0);
+}
+
+static int pic2_write_char(pi, c)
+struct pic2_info *pi;
+int c;
+{
+    if (fputc(c, pi->fp) == EOF)
+	pic2_error(pi, PIC2_WRITE);
+    return (0);
+}
+
+/*
+ * These functions access the bit stream.
+ * pic2_read_bits:
+ *	reads the specified bits from the file.
+ * pic2_write_bits:
+ *	writes the specified bits to the file.
+ * pic2_flush_bits:
+ *	flushes bit buffer to the file.
+ */
+static unsigned long pic2_read_bits(pi, bits)
+struct pic2_info *pi;
+int bits;
+{
+    unsigned long r = 0;
+
+    while (bits > 0) {
+	while (pi->bs.rest > 0 && bits > 0) {
+	    r = (r << 1) | (pi->bs.cur & 0x80 ? 1 : 0);
+	    pi->bs.cur <<= 1;
+	    pi->bs.rest--;
+	    bits--;
+	}
+	if (bits > 0) {
+	    int c;
+	    if ((c = fgetc(pi->fp)) == EOF)
+		pic2_file_error(pi, PIC2_CORRUPT);
+	    pi->bs.cur  = (byte) c;
+	    pi->bs.rest = 8;
+	}
+    }
+    return r;
+}
+
+static void pic2_write_bits(pi, dat, bits)
+struct pic2_info *pi;
+unsigned long dat;
+int bits;
+{
+    unsigned long dat_mask = 1 << (bits - 1);
+
+    while (bits > 0) {
+	while (pi->bs.rest < 8 && bits > 0) {
+	    pi->bs.cur <<= 1;
+	    if (dat & dat_mask)
+		pi->bs.cur |= 1;
+	    pi->bs.rest++;
+	    bits--;
+	    dat_mask >>= 1;
+	}
+	if (pi->bs.rest >= 8) {
+	    if ((fputc((int) pi->bs.cur, pi->fp)) == EOF)
+		pic2_error(pi, PIC2_WRITE);
+	    pi->bs.cur  = 0;
+	    pi->bs.rest = 0;
+	}
+    }
+}
+
+static void pic2_flush_bits(pi)
+struct pic2_info *pi;
+{
+    if (pi->bs.rest < 8) {
+	pi->bs.cur <<= 8 - pi->bs.rest;
+	if (fputc((int) pi->bs.cur, pi->fp) == EOF)
+		pic2_error(pi, PIC2_WRITE);
+	pi->bs.cur  = 0;
+	pi->bs.rest = 0;
+    }
+}
+
+/*
+ * These functions initialize or clean up structures.
+ * pic2_init_info:
+ *	initializes a pic2_info structure.
+ * pic2_cleanup_pic2_info:
+ *	cleans up a pic_info structure.
+ * pic2_cleanup_pinfo:
+ *	cleans up a PICINFO structure.
+ */
+static void pic2_init_info(pi)
+struct pic2_info *pi;
+{
+    xvbzero((char *) pi, sizeof(struct pic2_info));
+    pi->header = pic2_new(sizeof(struct pic2_header), "pic2_init_info#1");
+    pi->block = pic2_new(sizeof(struct pic2_block), "pic2_init_info#2");
+}
+
+static void pic2_cleanup_pic2_info(pi, writing)
+struct pic2_info *pi;
+int writing;
+{
+    if (!writing && pi->fp)
+	fclose(pi->fp);
+    if (pi->header)
+	free(pi->header);
+    if (pi->block)
+	free(pi->block);
+    pi->fp = NULL;
+    pi->header = NULL;
+    pi->block = NULL;
+    pi->comment = NULL;
+}
+
+static void pic2_cleanup_pinfo(pinfo)
+PICINFO *pinfo;
+{
+    if (pinfo->pic){
+	free(pinfo->pic);
+	pinfo->pic = NULL;
+    }
+    if (pinfo->comment){
+	free(pinfo->comment);
+	pinfo->comment = NULL;
+    }
+}
+
+/*
+ * Error Handlers.
+ * pic2_memory_error:
+ *	shows an error message and terminates.
+ * pic2_error:
+ *	shows a non-file error message and jumps to the entry for errors.
+ * pic2_file_error:
+ *	shows a file error message and jumps to the entry for errors.
+ */
+static void pic2_memory_error(scm, fn)
+char *scm, *fn;
+{
+    char buf[128];
+    sprintf(buf, "%s: can't allocate memory. (%s)", scm, fn);
+    FatalError(buf);
+}
+
+static void pic2_error(pi, mn)
+struct pic2_info *pi;
+int mn;
+{
+    SetISTR(ISTR_WARNING, "%s", pic2_msgs[mn]);
+    longjmp(pi->jmp, 1);
+}
+
+static void pic2_file_error(pi, mn)
+    struct pic2_info *pi;
+    int mn;
+{
+    if (feof(pi->fp))
+	SetISTR(ISTR_WARNING, "%s (end of file)", pic2_msgs[mn]);
+    else
+	SetISTR(ISTR_WARNING, "%s (%s)", pic2_msgs[mn], ERRSTR(errno));
+    longjmp(pi->jmp, 1);
+}
+
+static void pic2_show_pic2_info(pi)
+    struct pic2_info *pi;
+{
+    fprintf(stderr, "file size: %ld.\n", pi->fsize);
+    fprintf(stderr, "full image size: %dx%d\n", pi->x_max, pi->y_max);
+    fprintf(stderr, "number of palettes: %d\n", pi->n_pal);
+    fprintf(stderr, "depth of palettes: %d\n", pi->pal_bits);
+    fprintf(stderr, "current block position: %ld\n", pi->block_pos);
+    fprintf(stderr, "next block position: %ld\n\n", pi->next_pos);
+
+    fprintf(stderr, "header flag: %x\n", pi->header->flag);
+    fprintf(stderr, "header size: %ld\n", pi->header->size);
+    fprintf(stderr, "x_aspect: %d, y_aspect: %d\n",
+	    pi->header->x_aspect, pi->header->y_aspect);
+    fprintf(stderr, "number of color bits: %d\n\n", pi->header->depth);
+
+    fprintf(stderr, "image block id: %s\n", pi->block->id);
+    fprintf(stderr, "image block size: %ld\n", pi->block->size);
+    fprintf(stderr, "block flag: %x\n", pi->block->flag);
+
+    fprintf(stderr, "block image size: %dx%d\n",
+	    pi->block->x_wid, pi->block->y_wid);
+    fprintf(stderr, "x_offset: %d\n", pi->block->x_offset);
+    fprintf(stderr, "y_offset: %d\n", pi->block->y_offset);
+    fprintf(stderr, "opaque color: %lx\n\n", pi->block->opaque);
+}
+
+/*
+ * This function is similar to strncpy.
+ * But this pads with whitespace after the null character.
+ */
+static char *pic2_strncpy(dest, src, n)
+char *dest, *src;
+size_t n;
+{
+    char *r;
+
+    r = dest;
+    while (n--)
+	if ((src != NULL) && (*src != '\r') && (*src != '\n') && *src)
+	    *dest++ = *src++;
+	else
+	    *dest++ = ' ';
+    return (r);
+}
+
+/*
+ * These functions create a memory block.
+ */
+static void *pic2_malloc(size, fn)
+size_t size;
+char *fn;
+{
+    void *p;
+
+    p = (void *) malloc(size);
+    if (p == NULL)
+	pic2_memory_error("malloc", fn);
+    return (p);
+}
+
+static void *pic2_new(size, fn)
+size_t size;
+char *fn;
+{
+    void *p;
+
+    p = (void *) pic2_malloc(size, fn);
+    xvbzero((char *) p, size);
+    return (p);
+}
+
+
+
+
+/**** Stuff for PIC2Dialog box ****/
+
+#define TWIDE    320
+#define THIGH	 178
+#define T_NBUTTS 2
+#define T_BOK    0
+#define T_BCANC  1
+#define BUTTH    24
+
+static void drawTD    PARM((int,int,int,int));
+static void clickTD   PARM((int,int));
+static void doCmd     PARM((int));
+static void writePIC2 PARM((void));
+
+/* local variables */
+static FILE  *fp;
+static char  *filename;
+static int   colorType;
+static int   append;
+static int   x_offset;
+static int   y_offset;
+static BUTT  tbut[T_NBUTTS];
+static RBUTT *typeRB;
+static RBUTT *depthRB;
+
+
+
+/***************************************************/
+void CreatePIC2W()
+{
+    int	     y;
+
+    pic2W = CreateWindow("xv pic2", "XVpic2", NULL,
+			TWIDE, THIGH, infofg, infobg, 0);
+    if (!pic2W)
+	FatalError("can't create pic2 window!");
+
+    XSelectInput(theDisp, pic2W,
+		 ExposureMask | ButtonPressMask | KeyPressMask);
+
+    BTCreate(&tbut[T_BOK], pic2W, TWIDE-140-1, THIGH-10-BUTTH-1, 60, BUTTH,
+	     "Ok", infofg, infobg, hicol, locol);
+
+    BTCreate(&tbut[T_BCANC], pic2W, TWIDE-70-1, THIGH-10-BUTTH-1, 60, BUTTH,
+	     "Cancel", infofg, infobg, hicol, locol);
+
+    y = 55;
+    typeRB = RBCreate(NULL, pic2W, 36, y,          "P2SS",
+		      infofg, infobg,hicol,locol);
+    RBCreate(typeRB, pic2W, 36, y+18,              "P2SF",
+	     infofg, infobg,hicol,locol);
+    RBCreate(typeRB, pic2W, 36, y+36,              "P2BM",
+	     infofg, infobg, hicol, locol);
+    RBCreate(typeRB, pic2W, 36, y+54,              "P2BI",
+	     infofg, infobg, hicol, locol);
+
+    depthRB = RBCreate(NULL, pic2W, TWIDE/2-16, y, "  3bit",
+		       infofg, infobg,hicol,locol);
+    RBCreate(depthRB, pic2W, TWIDE/2-16, y+18,     "  6bit",
+	     infofg, infobg,hicol,locol);
+    RBCreate(depthRB, pic2W, TWIDE/2-16, y+36,     "  9bit",
+	     infofg, infobg, hicol, locol);
+    RBCreate(depthRB, pic2W, TWIDE/2-16, y+54,     "12bit",
+	     infofg, infobg, hicol, locol);
+    RBCreate(depthRB, pic2W, TWIDE/4*3-16, y,      "15bit",
+	     infofg, infobg, hicol, locol);
+    RBCreate(depthRB, pic2W, TWIDE/4*3-16, y+18,   "18bit",
+	     infofg, infobg, hicol, locol);
+    RBCreate(depthRB, pic2W, TWIDE/4*3-16, y+36,   "21bit",
+	     infofg, infobg, hicol, locol);
+    RBCreate(depthRB, pic2W, TWIDE/4*3-16, y+54,   "24bit",
+	     infofg, infobg, hicol, locol);
+
+    XMapSubwindows(theDisp, pic2W);
+}
+
+
+/***************************************************/
+void PIC2Dialog(vis)
+int vis;
+{
+    if (vis) {
+	CenterMapWindow(pic2W, tbut[T_BOK].x + tbut[T_BOK].w/2,
+			tbut[T_BOK].y + tbut[T_BOK].h/2, TWIDE, THIGH);
+    }
+    else     XUnmapWindow(theDisp, pic2W);
+    pic2Up = vis;
+}
+
+
+/***************************************************/
+int PIC2CheckEvent(xev)
+XEvent *xev;
+{
+    /* check event to see if it's for one of our subwindows.  If it is,
+       deal accordingly and return '1'.  Otherwise, return '0'. */
+
+    int rv;
+    rv = 1;
+
+    if (!pic2Up)
+	return (0);
+
+    if (xev->type == Expose) {
+	int x,y,w,h;
+	XExposeEvent *e = (XExposeEvent *) xev;
+	x = e->x;  y = e->y;  w = e->width;  h = e->height;
+
+	if (e->window == pic2W)       drawTD(x, y, w, h);
+	else rv = 0;
+    }
+
+    else if (xev->type == ButtonPress) {
+	XButtonEvent *e = (XButtonEvent *) xev;
+	int x,y;
+	x = e->x;  y = e->y;
+
+	if (e->button == Button1) {
+	    if      (e->window == pic2W)     clickTD(x,y);
+	    else rv = 0;
+	}  /* button1 */
+	else rv = 0;
+    }  /* button press */
+
+
+    else if (xev->type == KeyPress) {
+	XKeyEvent *e = (XKeyEvent *) xev;
+	char buf[128];  KeySym ks;  XComposeStatus status;
+	int stlen;
+
+	stlen = XLookupString(e,buf,128,&ks,&status);
+	buf[stlen] = '\0';
+
+	if (e->window == pic2W) {
+	    if (stlen) {
+		if (buf[0] == '\r' || buf[0] == '\n') { /* enter */
+		    FakeButtonPress(&tbut[T_BOK]);
+		}
+		else if (buf[0] == '\033') {            /* ESC */
+		    FakeButtonPress(&tbut[T_BCANC]);
+		}
+	    }
+	}
+	else rv = 0;
+    }
+    else rv = 0;
+
+    if (rv == 0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
+	XBell(theDisp, 50);
+	rv = 1;   /* eat it */
+    }
+
+    return (rv);
+}
+
+
+/***************************************************/
+int PIC2SaveParams(fname, col)
+char *fname;
+int col;
+{
+    filename = fname;
+    colorType = col;
+
+    /* see if we can open the output file before proceeding */
+    fp = pic2_OpenOutFile(filename, &append);
+    if (!fp)
+	return (-1);
+
+    RBSetActive(typeRB,0,1);
+    RBSetActive(typeRB,1,1);
+    RBSetActive(typeRB,2,1);
+    RBSetActive(typeRB,3,1);
+    RBSelect(typeRB,0);
+
+
+    if (append) {
+	struct pic2_info pic2;
+
+	pic2_init_info(&pic2);
+	pic2.fp = fp;
+	pic2_read_header(&pic2);
+
+	RBSetActive(depthRB,0,0);
+	RBSetActive(depthRB,1,0);
+	RBSetActive(depthRB,2,0);
+	RBSetActive(depthRB,3,0);
+	RBSetActive(depthRB,4,0);
+	RBSetActive(depthRB,5,0);
+	RBSetActive(depthRB,6,0);
+	RBSetActive(depthRB,7,0);
+
+	switch (pic2.header->depth) {
+	case  3:
+	    RBSetActive(depthRB,0,1);
+	    RBSelect(depthRB,0);
+	    RBSetActive(typeRB,3,0);
+	    break;
+	case  6:
+	    RBSetActive(depthRB,1,1);
+	    RBSelect(depthRB,1);
+	    RBSetActive(typeRB,3,0);
+	    break;
+	case  9:
+	    RBSetActive(depthRB,2,1);
+	    RBSelect(depthRB,2);
+	    break;
+	case 12:
+	    RBSetActive(depthRB,3,1);
+	    RBSelect(depthRB,3);
+	    break;
+	case 15:
+	    RBSetActive(depthRB,4,1);
+	    RBSelect(depthRB,4);
+	    break;
+	case 18:
+	    RBSetActive(depthRB,5,1);
+	    RBSelect(depthRB,5);
+	    RBSetActive(typeRB,3,0);
+	    break;
+	case 21:
+	    RBSetActive(depthRB,6,1);
+	    RBSelect(depthRB,6);
+	    RBSetActive(typeRB,3,0);
+	    break;
+	case 24:
+	    RBSetActive(depthRB,7,1);
+	    RBSelect(depthRB,7);
+	    RBSetActive(typeRB,3,0);
+	    break;
+	default: {
+	    char str[512];
+	    sprintf(str, "unsupported PIC2 file '%s'.", filename);
+	    ErrPopUp(str, "\nBummer");
+	    CloseOutFile(fp, filename, 0);
+	    fp = OpenOutFile(fname);
+	    if (!fp)
+		return (-1);
+	    break;
+	}
+	}
+	pic2_seek_file(&pic2, 0, SEEK_SET);
+	pic2_cleanup_pic2_info(&pic2, 1);
+    } else {
+	RBSetActive(depthRB,0,1);
+	RBSetActive(depthRB,1,1);
+	RBSetActive(depthRB,2,1);
+	RBSetActive(depthRB,3,1);
+	RBSetActive(depthRB,4,1);
+	RBSetActive(depthRB,5,1);
+	RBSetActive(depthRB,6,1);
+	RBSetActive(depthRB,7,1);
+	RBSelect(depthRB,7);
+	RBSetActive(typeRB,3,0);
+    }
+    return (0);
+}
+
+
+/***************************************************/
+static void drawTD(x,y,w,h)
+int x,y,w,h;
+{
+    char *title  = "Save PIC2 file...";
+    int  i;
+    XRectangle xr;
+
+    xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
+    XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
+
+    XSetForeground(theDisp, theGC, infofg);
+    XSetBackground(theDisp, theGC, infobg);
+
+    for (i = 0; i < T_NBUTTS; i++)
+	BTRedraw(&tbut[i]);
+
+    ULineString(pic2W, typeRB->x-16, typeRB->y-3-DESCENT,   "FormatType");
+    ULineString(pic2W, depthRB->x-16, depthRB->y-3-DESCENT, "ColorDepth");
+    RBRedraw(typeRB, -1);
+    RBRedraw(depthRB, -1);
+
+    DrawString(pic2W, 20, 29, title);
+
+    XSetClipMask(theDisp, theGC, None);
+}
+
+static void clickTD(x,y)
+int x,y;
+{
+    int i;
+    BUTT *bp;
+
+    /* check BUTTs */
+
+    /* check the RBUTTS first, since they don't DO anything */
+    if ((i = RBClick(typeRB, x,y)) >= 0) {
+	(void) RBTrack(typeRB, i);
+	return;
+    } else if ((i = RBClick(depthRB, x,y)) >= 0) {
+	(void) RBTrack(depthRB, i);
+	if ((2 <= i) && (i <= 4))
+	    RBSetActive(typeRB,3,1);
+	else {
+	    RBSetActive(typeRB,3,0);
+	    if (RBWhich(typeRB) == 3)
+		RBSelect(typeRB,0);
+	return;
+	}
+    }
+    for (i = 0; i < T_NBUTTS; i++) {
+	bp = &tbut[i];
+	if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h))
+	    break;
+    }
+    if (i < T_NBUTTS)  /* found one */
+	if (BTTrack(bp))
+	    doCmd(i);
+}
+
+
+
+/***************************************************/
+static void doCmd(cmd)
+int cmd;
+{
+    switch (cmd) {
+    case T_BOK: {
+	char *fullname;
+	char buf[64], *x_offsetp, *y_offsetp;
+	static char *labels[] = { "\nOk", "\033Cancel" };
+        XEvent event;
+	int i;
+
+	strcpy(buf, "0,0");
+	i = GetStrPopUp("Enter offset (x,y):", labels, 2, buf, 64,
+			"01234567890,", 1);
+
+	if (i)
+	    return;
+	if (strlen(buf)==0)
+	    return;
+
+	x_offsetp = buf;
+	y_offsetp = index(buf, ',');
+	if (!y_offsetp)
+	    return;
+	*(y_offsetp++) = '\0';
+	if ((*x_offsetp == '\0') || (*y_offsetp == '\0'))
+	    return;
+	x_offset = atoi(x_offsetp);
+	y_offset = atoi(y_offsetp);
+
+        XNextEvent(theDisp, &event);
+	HandleEvent(&event, &i);
+
+	writePIC2();
+	PIC2Dialog(0);
+
+	fullname = GetDirFullName();
+	if (!ISPIPE(fullname[0])) {
+	    XVCreatedFile(fullname);
+	    StickInCtrlList(0);
+	}
+    }
+	break;
+    case T_BCANC:
+	pic2_KillNullFile(fp);
+	PIC2Dialog(0);
+	break;
+    default:
+	break;
+    }
+}
+
+
+/*******************************************/
+static void writePIC2()
+{
+    int   w, h, nc, rv, type, depth, ptype, pfree;
+    byte *inpix, *rmap, *gmap, *bmap;
+
+
+    WaitCursor();
+    inpix = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rmap, &gmap, &bmap);
+
+    if (colorType == F_REDUCED)
+	colorType = F_FULLCOLOR;
+
+    switch (RBWhich(typeRB)) {
+    case 0: type = P2SS;  break;
+    case 1: type = P2SF;  break;
+    case 2: type = P2BM;  break;
+    case 3: type = P2BI;  break;
+    default: type = P2SS; break;
+    }
+    switch (RBWhich(depthRB)) {
+    case 0: depth =  3;  break;
+    case 1: depth =  6;  break;
+    case 2: depth =  9;  break;
+    case 3: depth = 12;  break;
+    case 4: depth = 15;  break;
+    case 5: depth = 18;  break;
+    case 6: depth = 21;  break;
+    case 7: depth = 24;  break;
+    default: depth = 24; break;
+    }
+    rv = WritePIC2(fp, inpix, ptype, w, h,
+		   rmap, gmap, bmap, nc, colorType, filename,
+		   type, depth, x_offset, y_offset, append, picComments);
+
+    if (CloseOutFile(fp, filename, rv) == 0)
+	DirBox(0);
+
+    if (pfree)
+	free(inpix);
+}
+#endif /* HAVE_PIC2 */
diff -ruN xv-3.10a-bugfixes/xvpng.c xv-3.10a-enhancements/xvpng.c
--- xv-3.10a-bugfixes/xvpng.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvpng.c	2005-04-17 15:00:08.000000000 -0700
@@ -0,0 +1,1081 @@
+/*
+ * xvpng.c - load and write routines for 'PNG' format pictures
+ *
+ * callable functions
+ *
+ *    CreatePNGW()
+ *    PNGDialog(vis)
+ *    PNGCheckEvent(xev)
+ *    PNGSaveParams(fname, col)
+ *    LoadPNG(fname, pinfo)
+ *    VersionInfoPNG()
+ */
+
+/*#include "copyright.h"*/
+/* (c) 1995 by Alexander Lehmann <lehmann@mathematik.th-darmstadt.de>
+ *   This file is a suplement to xv and is supplied under the same copying
+ *   conditions (except the shareware part).
+ * Modified by Andreas Dilger <adilger@enel.ucalgary.ca> to fix
+ *   error handling for bad PNGs, add dialogs for interlacing and
+ *   compression selection, and upgrade to libpng-0.89.
+ * Modified by Greg Roelofs, TenThumbs and others to fix bugs and add
+ *   features.
+ * The copyright will be passed on to JB at some future point if he
+ * so desires.
+ */
+
+#include "xv.h"
+
+#ifdef HAVE_PNG
+
+#include "png.h"
+
+/*** Stuff for PNG Dialog box ***/
+#define PWIDE 318
+#define PHIGH 215
+
+#define DISPLAY_GAMMA 2.20  /* default display gamma */
+#define COMPRESSION   6     /* default zlib compression level, not max
+                               (Z_BEST_COMPRESSION) */
+
+#define HAVE_tRNS     (info_ptr->valid & PNG_INFO_tRNS)
+
+#define DWIDE     86
+#define DHIGH    104
+#define PFX PWIDE-93
+#define PFY       44
+#define PFH       20
+
+#define P_BOK    0
+#define P_BCANC  1
+#define P_NBUTTS 2
+
+#define BUTTH    24
+
+#define LF       10   /* a.k.a. '\n' on ASCII machines */
+#define CR       13   /* a.k.a. '\r' on ASCII machines */
+
+/*** local functions ***/
+static    void drawPD         PARM((int, int, int, int));
+static    void clickPD        PARM((int, int));
+static    void doCmd          PARM((int));
+static    void writePNG       PARM((void));
+static    int  WritePNG       PARM((FILE *, byte *, int, int, int,
+                                    byte *, byte *, byte *, int));
+
+static    void png_xv_error   PARM((png_structp png_ptr,
+                                    png_const_charp message));
+static    void png_xv_warning PARM((png_structp png_ptr,
+                                    png_const_charp message));
+
+/*** local variables ***/
+static char *filename;
+static char *fbasename;
+static int   colorType;
+static int   read_anything;
+static double Display_Gamma = DISPLAY_GAMMA;
+
+static DIAL  cDial, gDial;
+static BUTT  pbut[P_NBUTTS];
+static CBUTT interCB;
+static CBUTT FdefCB, FnoneCB, FsubCB, FupCB, FavgCB, FPaethCB;
+
+/**************************************************************************/
+/* PNG SAVE DIALOG ROUTINES ***********************************************/
+/**************************************************************************/
+
+
+/*******************************************/
+void CreatePNGW()
+{
+  pngW = CreateWindow("xv png", "XVPNG", NULL,
+                      PWIDE, PHIGH, infofg, infobg, 0);
+  if (!pngW) FatalError("can't create PNG window!");
+
+  XSelectInput(theDisp, pngW, ExposureMask | ButtonPressMask | KeyPressMask);
+
+  DCreate(&cDial, pngW,  12, 25, DWIDE, DHIGH, (double)Z_NO_COMPRESSION,
+          (double)Z_BEST_COMPRESSION, COMPRESSION, 1.0, 3.0,
+          infofg, infobg, hicol, locol, "Compression", NULL);
+
+  DCreate(&gDial, pngW, DWIDE+27, 25, DWIDE, DHIGH, 1.0, 3.5,DISPLAY_GAMMA,0.01,0.2,
+          infofg, infobg, hicol, locol, "Disp. Gamma", NULL);
+
+  CBCreate(&interCB, pngW,  DWIDE+30, DHIGH+3*LINEHIGH+2, "interlace",
+           infofg, infobg, hicol, locol);
+
+  CBCreate(&FdefCB,   pngW, PFX, PFY, "Default",
+           infofg, infobg, hicol, locol);
+  FdefCB.val = 1;
+
+  CBCreate(&FnoneCB,  pngW, PFX, FdefCB.y + PFH + 4, "none",
+           infofg, infobg, hicol, locol);
+  CBCreate(&FsubCB,   pngW, PFX, FnoneCB.y + PFH, "sub",
+           infofg, infobg, hicol, locol);
+  CBCreate(&FupCB,    pngW, PFX, FsubCB.y  + PFH, "up",
+           infofg, infobg, hicol, locol);
+  CBCreate(&FavgCB,   pngW, PFX, FupCB.y   + PFH, "average",
+           infofg, infobg, hicol, locol);
+  CBCreate(&FPaethCB, pngW, PFX, FavgCB.y  + PFH, "Paeth",
+           infofg, infobg, hicol, locol);
+
+  FnoneCB.val = FsubCB.val = FupCB.val = FavgCB.val = FPaethCB.val = 1;
+  CBSetActive(&FnoneCB, !FdefCB.val);
+  CBSetActive(&FsubCB, !FdefCB.val);
+  CBSetActive(&FupCB, !FdefCB.val);
+  CBSetActive(&FavgCB, !FdefCB.val);
+  CBSetActive(&FPaethCB, !FdefCB.val);
+
+  BTCreate(&pbut[P_BOK], pngW, PWIDE-180-1, PHIGH-10-BUTTH-1, 80, BUTTH,
+          "Ok", infofg, infobg, hicol, locol);
+  BTCreate(&pbut[P_BCANC], pngW, PWIDE-90-1, PHIGH-10-BUTTH-1, 80, BUTTH,
+          "Cancel", infofg, infobg, hicol, locol);
+
+  XMapSubwindows(theDisp, pngW);
+}
+
+
+/*******************************************/
+void PNGDialog(vis)
+     int vis;
+{
+  if (vis) {
+    CenterMapWindow(pngW, pbut[P_BOK].x + (int) pbut[P_BOK].w/2,
+                          pbut[P_BOK].y + (int) pbut[P_BOK].h/2,
+                    PWIDE, PHIGH);
+  }
+  else XUnmapWindow(theDisp, pngW);
+  pngUp = vis;
+}
+
+
+/*******************************************/
+int PNGCheckEvent(xev)
+     XEvent *xev;
+{
+  /* check event to see if it's for one of our subwindows.  If it is,
+     deal accordingly, and return '1'.  Otherwise, return '0' */
+
+  int rv;
+  rv = 1;
+
+  if (!pngUp) return 0;
+
+  if (xev->type == Expose) {
+    int x,y,w,h;
+    XExposeEvent *e = (XExposeEvent *) xev;
+    x = e->x; y = e->y; w = e->width; h = e->height;
+
+    /* throw away excess expose events for 'dumb' windows */
+    if (e->count > 0 && (e->window == cDial.win)) {}
+
+    else if (e->window == pngW)        drawPD(x, y, w, h);
+    else if (e->window == cDial.win)   DRedraw(&cDial);
+    else if (e->window == gDial.win)   DRedraw(&gDial);
+    else rv = 0;
+  }
+
+  else if (xev->type == ButtonPress) {
+    XButtonEvent *e = (XButtonEvent *) xev;
+    int x,y;
+    x = e->x;  y = e->y;
+
+    if (e->button == Button1) {
+      if      (e->window == pngW)       clickPD(x,y);
+      else if (e->window == cDial.win)  DTrack(&cDial,x,y);
+      else if (e->window == gDial.win)  DTrack(&gDial,x,y);
+      else rv = 0;
+    }  /* button1 */
+    else rv = 0;
+  }  /* button press */
+
+  else if (xev->type == KeyPress) {
+    XKeyEvent *e = (XKeyEvent *) xev;
+    char buf[128];  KeySym ks;
+    int stlen;
+
+    stlen = XLookupString(e,buf,128,&ks,(XComposeStatus *) NULL);
+    buf[stlen] = '\0';
+
+    RemapKeyCheck(ks, buf, &stlen);
+
+    if (e->window == pngW) {
+      if (stlen) {
+        if (buf[0] == '\r' || buf[0] == '\n') { /* enter */
+          FakeButtonPress(&pbut[P_BOK]);
+        }
+        else if (buf[0] == '\033') {            /* ESC */
+          FakeButtonPress(&pbut[P_BCANC]);
+        }
+      }
+    }
+    else rv = 0;
+  }
+  else rv = 0;
+
+  if (rv==0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
+    XBell(theDisp, 50);
+    rv = 1;   /* eat it */
+  }
+
+  return rv;
+}
+
+
+/*******************************************/
+void PNGSaveParams(fname, col)
+     char *fname;
+     int col;
+{
+  filename = fname;
+  colorType = col;
+}
+
+
+/*******************************************/
+static void drawPD(x, y, w, h)
+     int x, y, w, h;
+{
+  char *title   = "Save PNG file...";
+
+  char ctitle1[20];
+  char *ctitle2 = "Useful range";
+  char *ctitle3 = "is 2 - 7.";
+  char *ctitle4 = "Uncompressed = 0";
+
+  char *ftitle  = "Row Filters:";
+
+  char gtitle[20];
+
+  int i;
+  XRectangle xr;
+
+  xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
+  XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
+
+  XSetForeground(theDisp, theGC, infofg);
+  XSetBackground(theDisp, theGC, infobg);
+
+  for (i=0; i<P_NBUTTS; i++) BTRedraw(&pbut[i]);
+
+  DrawString(pngW,       15,  6+ASCENT,                          title);
+
+  sprintf(ctitle1, "Default = %d", COMPRESSION);
+  DrawString(pngW,       18,  6+DHIGH+cDial.y+ASCENT,            ctitle1);
+  DrawString(pngW,       17,  6+DHIGH+cDial.y+ASCENT+LINEHIGH,   ctitle2);
+  DrawString(pngW,       17,  6+DHIGH+cDial.y+ASCENT+2*LINEHIGH, ctitle3);
+  DrawString(pngW,       17,  6+DHIGH+cDial.y+ASCENT+3*LINEHIGH, ctitle4);
+
+  sprintf(gtitle, "Default = %g", DISPLAY_GAMMA);
+  DrawString(pngW, DWIDE+30,  6+DHIGH+gDial.y+ASCENT,            gtitle);
+
+  ULineString(pngW, FdefCB.x, FdefCB.y-3-DESCENT, ftitle);
+  XDrawRectangle(theDisp, pngW, theGC, FdefCB.x-11, FdefCB.y-LINEHIGH-3,
+                                       93, 8*LINEHIGH+15);
+  CBRedraw(&FdefCB);
+  XDrawLine(theDisp, pngW, theGC, FdefCB.x-11, FdefCB.y+LINEHIGH+4,
+                                  FdefCB.x+82, FdefCB.y+LINEHIGH+4);
+
+  CBRedraw(&FnoneCB);
+  CBRedraw(&FupCB);
+  CBRedraw(&FsubCB);
+  CBRedraw(&FavgCB);
+  CBRedraw(&FPaethCB);
+
+  CBRedraw(&interCB);
+
+  XSetClipMask(theDisp, theGC, None);
+}
+
+
+/*******************************************/
+static void clickPD(x,y)
+     int x,y;
+{
+  int i;
+  BUTT *bp;
+
+  /* check BUTTs */
+
+  for (i=0; i<P_NBUTTS; i++) {
+    bp = &pbut[i];
+    if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
+  }
+
+  if (i<P_NBUTTS) {  /* found one */
+    if (BTTrack(bp)) doCmd(i);
+  }
+
+  /* check CBUTTs */
+
+  else if (CBClick(&FdefCB,x,y)) {
+    int oldval = FdefCB.val;
+
+    CBTrack(&FdefCB);
+
+    if (oldval != FdefCB.val)
+    {
+      CBSetActive(&FnoneCB, !FdefCB.val);
+      CBSetActive(&FsubCB, !FdefCB.val);
+      CBSetActive(&FupCB, !FdefCB.val);
+      CBSetActive(&FavgCB, !FdefCB.val);
+      CBSetActive(&FPaethCB, !FdefCB.val);
+
+      CBRedraw(&FnoneCB);
+      CBRedraw(&FupCB);
+      CBRedraw(&FsubCB);
+      CBRedraw(&FavgCB);
+      CBRedraw(&FPaethCB);
+    }
+  }
+  else if (CBClick(&FnoneCB,x,y))  CBTrack(&FnoneCB);
+  else if (CBClick(&FsubCB,x,y))   CBTrack(&FsubCB);
+  else if (CBClick(&FupCB,x,y))    CBTrack(&FupCB);
+  else if (CBClick(&FavgCB,x,y))   CBTrack(&FavgCB);
+  else if (CBClick(&FPaethCB,x,y)) CBTrack(&FPaethCB);
+  else if (CBClick(&interCB,x,y))  CBTrack(&interCB);
+}
+
+
+/*******************************************/
+static void doCmd(cmd)
+     int cmd;
+{
+  switch (cmd) {
+    case P_BOK:
+      {
+        char *fullname;
+
+        writePNG();
+        PNGDialog(0);
+
+        fullname = GetDirFullName();
+        if (!ISPIPE(fullname[0])) {
+          XVCreatedFile(fullname);
+          StickInCtrlList(0);
+        }
+      }
+      break;
+
+    case P_BCANC:
+      PNGDialog(0);
+      break;
+
+    default:
+      break;
+  }
+}
+
+
+/*******************************************/
+static void writePNG()
+{
+  FILE       *fp;
+  int         w, h, nc, rv, ptype, pfree;
+  byte       *inpix, *rmap, *gmap, *bmap;
+
+  fp = OpenOutFile(filename);
+  if (!fp) return;
+
+  fbasename = BaseName(filename);
+
+  WaitCursor();
+  inpix = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rmap, &gmap, &bmap);
+
+  rv = WritePNG(fp, inpix, ptype, w, h, rmap, gmap, bmap, nc);
+
+  SetCursors(-1);
+
+  if (CloseOutFile(fp, filename, rv) == 0) DirBox(0);
+
+  if (pfree) free(inpix);
+}
+
+
+/*******************************************/
+int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols)
+     FILE *fp;
+     byte *pic;
+     int   ptype, w, h;
+     byte *rmap, *gmap, *bmap;
+     int   numcols;
+{
+  png_struct *png_ptr;
+  png_info   *info_ptr;
+  png_color   palette[256];
+  png_textp   text;
+  byte        remap[256];
+  int         i, filter, linesize, pass;
+  byte       *p, *png_line;
+  char        software[256];
+  char       *savecmnt;
+
+  if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
+       png_xv_error, png_xv_warning)) == NULL) {
+    sprintf(software, "png_create_write_struct() failure in WritePNG (ver. %s)",
+      PNG_LIBPNG_VER_STRING);
+    FatalError(software);
+  }
+
+  if ((info_ptr = png_create_info_struct(png_ptr)) == NULL)
+  {
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    sprintf(software, "png_create_info_struct() failure in WritePNG");
+    FatalError(software);
+  }
+
+  if (setjmp(png_ptr->jmpbuf)) {
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    return -1;
+  }
+
+  png_init_io(png_ptr, fp);
+
+  png_set_compression_level(png_ptr, (int)cDial.val);
+
+  /* Don't bother filtering if we aren't compressing the image */
+  if (FdefCB.val)
+  {
+    if ((int)cDial.val == 0)
+      png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
+  }
+  else
+  {
+    filter  = FnoneCB.val  ? PNG_FILTER_NONE  : 0;
+    filter |= FsubCB.val   ? PNG_FILTER_SUB   : 0;
+    filter |= FupCB.val    ? PNG_FILTER_UP    : 0;
+    filter |= FavgCB.val   ? PNG_FILTER_AVG   : 0;
+    filter |= FPaethCB.val ? PNG_FILTER_PAETH : 0;
+
+    png_set_filter(png_ptr, 0, filter);
+  }
+
+  info_ptr->width = w;
+  info_ptr->height = h;
+  if (w <= 0 || h <= 0) {
+    SetISTR(ISTR_WARNING, "%s:  image dimensions out of range (%dx%d)",
+      fbasename, w, h);
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    return -1;
+  }
+
+  info_ptr->interlace_type = interCB.val ? 1 : 0;
+
+  linesize = 0;   /* quiet a compiler warning */
+
+  if (colorType == F_FULLCOLOR || colorType == F_REDUCED) {
+    if(ptype == PIC24) {
+      linesize = 3*w;
+      if (linesize/3 < w) {
+        SetISTR(ISTR_WARNING, "%s:  image dimensions too large (%dx%d)",
+          fbasename, w, h);
+        png_destroy_write_struct(&png_ptr, &info_ptr);
+        return -1;
+      }
+      info_ptr->color_type = PNG_COLOR_TYPE_RGB;
+      info_ptr->bit_depth = 8;
+    } else {
+      linesize = w;
+      info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
+      if(numcols <= 2)
+        info_ptr->bit_depth = 1;
+      else
+      if(numcols <= 4)
+        info_ptr->bit_depth = 2;
+      else
+      if(numcols <= 16)
+        info_ptr->bit_depth = 4;
+      else
+        info_ptr->bit_depth = 8;
+
+      for(i = 0; i < numcols; i++) {
+        palette[i].red   = rmap[i];
+        palette[i].green = gmap[i];
+        palette[i].blue  = bmap[i];
+      }
+      info_ptr->num_palette = numcols;
+      info_ptr->palette = palette;
+      info_ptr->valid |= PNG_INFO_PLTE;
+    }
+  }
+
+  else if(colorType == F_GREYSCALE || colorType == F_BWDITHER) {
+    info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
+    if(colorType == F_BWDITHER) {
+      /* shouldn't happen */
+      if (ptype == PIC24) FatalError("PIC24 and B/W Stipple in WritePNG()");
+
+      info_ptr->bit_depth = 1;
+      if(MONO(rmap[0], gmap[0], bmap[0]) > MONO(rmap[1], gmap[1], bmap[1])) {
+        remap[0] = 1;
+        remap[1] = 0;
+      }
+      else {
+        remap[0] = 0;
+        remap[1] = 1;
+      }
+      linesize = w;
+    }
+    else {
+      if(ptype == PIC24) {
+        linesize = 3*w;
+        if (linesize/3 < w) {
+          SetISTR(ISTR_WARNING, "%s:  image dimensions too large (%dx%d)",
+            fbasename, w, h);
+          png_destroy_write_struct(&png_ptr, &info_ptr);
+          return -1;
+        }
+        info_ptr->bit_depth = 8;
+      }
+      else {
+        int low_precision;
+
+        linesize = w;
+
+        for(i = 0; i < numcols; i++)
+          remap[i] = MONO(rmap[i], gmap[i], bmap[i]);
+
+        for(; i < 256; i++)
+          remap[i]=0;
+
+        info_ptr->bit_depth = 8;
+
+        /* Note that this fails most of the time because of gamma */
+        /* try to adjust to 4-bit precision grayscale */
+
+        low_precision=1;
+
+        for(i = 0; i < numcols; i++) {
+          if((remap[i] & 0x0f) * 0x11 != remap[i]) {
+            low_precision = 0;
+            break;
+          }
+        }
+
+        if(low_precision) {
+          for(i = 0; i < numcols; i++) {
+            remap[i] &= 0xf;
+          }
+          info_ptr->bit_depth = 4;
+
+          /* try to adjust to 2-bit precision grayscale */
+
+          for(i = 0; i < numcols; i++) {
+            if((remap[i] & 0x03) * 0x05 != remap[i]) {
+              low_precision = 0;
+              break;
+            }
+          }
+        }
+
+        if(low_precision) {
+          for(i = 0; i < numcols; i++) {
+            remap[i] &= 3;
+          }
+          info_ptr->bit_depth = 2;
+
+          /* try to adjust to 1-bit precision grayscale */
+
+          for(i = 0; i < numcols; i++) {
+            if((remap[i] & 0x01) * 0x03 != remap[i]) {
+              low_precision = 0;
+              break;
+            }
+          }
+        }
+
+        if(low_precision) {
+          for(i = 0; i < numcols; i++) {
+            remap[i] &= 1;
+          }
+          info_ptr->bit_depth = 1;
+        }
+      }
+    }
+  }
+
+  else
+    png_error(png_ptr, "Unknown colorstyle in WritePNG");
+
+  if ((text = (png_textp)malloc(sizeof(png_text)))) {
+    sprintf(software, "XV %s", REVDATE);
+
+    text->compression = -1;
+    text->key = "Software";
+    text->text = software;
+    text->text_length = strlen(text->text);
+
+    info_ptr->max_text = 1;
+    info_ptr->num_text = 1;
+    info_ptr->text = text;
+  }
+
+  Display_Gamma = gDial.val;  /* Save the current gamma for loading */
+
+  info_ptr->gamma = 1.0/gDial.val;
+  info_ptr->valid |= PNG_INFO_gAMA;
+
+  png_write_info(png_ptr, info_ptr);
+
+  if(info_ptr->bit_depth < 8)
+    png_set_packing(png_ptr);
+
+  pass=png_set_interlace_handling(png_ptr);
+
+  if((png_line = malloc(linesize)) == NULL)
+    png_error(png_ptr, "cannot allocate temp image line");
+
+  for(i = 0; i < pass; i++) {
+    int j;
+    p = pic;
+    for(j = 0; j < h; j++) {
+      if(info_ptr->color_type == PNG_COLOR_TYPE_GRAY) {
+        int k;
+        for(k = 0; k < w; k++)
+          png_line[k] = ptype==PIC24 ? MONO(p[k*3], p[k*3+1], p[k*3+2]) :
+                                       remap[p[k]];
+        png_write_row(png_ptr, png_line);
+      } else  /* RGB or palette */
+        png_write_row(png_ptr, p);
+      if((j & 0x1f) == 0) WaitCursor();
+      p += linesize;
+    }
+  }
+
+  free(png_line);
+
+  savecmnt = NULL;   /* quiet a compiler warning */
+
+  if (text)
+  {
+    if (picComments && strlen(picComments) &&
+        (savecmnt = (char *)malloc((strlen(picComments) + 1)*sizeof(char)))) {
+      png_textp tp;
+      char *comment, *key;
+
+      strcpy(savecmnt, picComments);
+      key = savecmnt;
+      tp = text;
+      info_ptr->num_text = 0;
+
+      comment = strchr(key, ':');
+
+      do  {
+        /* Allocate a larger structure for comments if necessary */
+        if (info_ptr->num_text >= info_ptr->max_text)
+        {
+          if ((tp =
+              realloc(text, (info_ptr->num_text + 2)*sizeof(png_text))) == NULL)
+          {
+            break;
+          }
+          else
+          {
+            text = tp;
+            tp = &text[info_ptr->num_text];
+            info_ptr->max_text += 2;
+          }
+        }
+
+        /* See if it looks like a PNG keyword from LoadPNG */
+        /* GRR: should test for strictly < 80, right? (key = 1-79 chars only) */
+        if(comment && comment[1] == ':' && comment - key <= 80) {
+          *(comment++) = '\0';
+          *(comment++) = '\0';
+
+          /* If the comment is the 'Software' chunk XV writes, we remove it,
+             since we have already stored one */
+          if (strcmp(key, "Software") == 0 && strncmp(comment, "XV", 2) == 0) {
+            key = strchr(comment, '\n');
+            if(key)
+              key++; /* skip \n */
+            comment = strchr(key, ':');
+          }
+          /* We have another keyword and/or comment to write out */
+          else {
+            tp->key = key;
+            tp->text = comment;
+
+            /* We have to find the end of this comment, and the next keyword
+               if there is one */
+            for (; NULL != (key = comment = strchr(comment, ':')); comment++)
+              if (key[1] == ':')
+                break;
+
+            /* It looks like another keyword, go backward to the beginning */
+            if (key) {
+              while(key > tp->text && *key != '\n')
+                key--;
+
+              if (key > tp->text && comment - key <= 80) {
+                *key = '\0';
+                key++;
+              }
+            }
+
+            tp->text_length = strlen(tp->text);
+
+            /* We don't have another keyword, so remove the last newline */
+            if (!key && tp->text[tp->text_length - 1] == '\n')
+            {
+              tp->text[tp->text_length] = '\0';
+              tp->text_length--;
+            }
+
+            tp->compression = tp->text_length > 640 ? 0 : -1;
+            info_ptr->num_text++;
+            tp++;
+          }
+        }
+        /* Just a generic comment:  make sure line-endings are valid for PNG */
+        else {
+          char *p=key, *q=key;     /* only deleting chars, not adding any */
+
+          while (*p) {
+            if (*p == CR) {        /* lone CR or CR/LF:  EOL either way */
+              *q++ = LF;           /* LF is the only allowed PNG line-ending */
+              if (p[1] == LF)      /* get rid of any original LF */
+                ++p;
+            } else if (*p == LF)   /* lone LF */
+              *q++ = LF;
+            else
+              *q++ = *p;
+            ++p;
+          }
+          *q = '\0';               /* unnecessary...but what the heck */
+          tp->key = "Comment";
+          tp->text = key;
+          tp->text_length = q - key;
+          tp->compression = tp->text_length > 750 ? 0 : -1;
+          info_ptr->num_text++;
+          key = NULL;
+        }
+      } while (key && *key);
+    }
+    else
+    {
+      info_ptr->num_text = 0;
+    }
+  }
+  info_ptr->text = text;
+
+  png_convert_from_time_t(&(info_ptr->mod_time), time(NULL));
+  info_ptr->valid |= PNG_INFO_tIME;
+
+  png_write_end(png_ptr, info_ptr);
+  fflush(fp);   /* just in case we core-dump before finishing... */
+
+  if (text)
+  {
+    free(text);
+    /* must do this or png_destroy_write_struct() 0.97+ will free text again: */
+    info_ptr->text = (png_textp)NULL;
+    if (savecmnt)
+    {
+      free(savecmnt);
+      savecmnt = (char *)NULL;
+    }
+  }
+
+  png_destroy_write_struct(&png_ptr, &info_ptr);
+
+  return 0;
+}
+
+
+/*******************************************/
+int LoadPNG(fname, pinfo)
+     char    *fname;
+     PICINFO *pinfo;
+/*******************************************/
+{
+  /* returns '1' on success */
+
+  FILE  *fp;
+  png_struct *png_ptr;
+  png_info *info_ptr;
+  png_color_16 my_background;
+  int i,j;
+  int linesize, bufsize;
+  int filesize;
+  int pass;
+  int gray_to_rgb;
+  size_t commentsize;
+
+  fbasename = BaseName(fname);
+
+  pinfo->pic     = (byte *) NULL;
+  pinfo->comment = (char *) NULL;
+
+  read_anything=0;
+
+  /* open the file */
+  fp = xv_fopen(fname,"r");
+  if (!fp) {
+    SetISTR(ISTR_WARNING,"%s:  can't open file", fname);
+    return 0;
+  }
+
+  /* find the size of the file */
+  fseek(fp, 0L, 2);
+  filesize = ftell(fp);
+  fseek(fp, 0L, 0);
+
+  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
+                                   png_xv_error, png_xv_warning);
+  if(!png_ptr) {
+    fclose(fp);
+    FatalError("malloc failure in LoadPNG");
+  }
+
+  info_ptr = png_create_info_struct(png_ptr);
+
+  if(!info_ptr) {
+    fclose(fp);
+    png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+    FatalError("malloc failure in LoadPNG");
+  }
+
+  if(setjmp(png_ptr->jmpbuf)) {
+    fclose(fp);
+    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+    if(!read_anything) {
+      if(pinfo->pic) {
+        free(pinfo->pic);
+        pinfo->pic = NULL;
+      }
+      if(pinfo->comment) {
+        free(pinfo->comment);
+        pinfo->comment = NULL;
+      }
+    }
+    return read_anything;
+  }
+
+  png_init_io(png_ptr, fp);
+  png_read_info(png_ptr, info_ptr);
+
+  pinfo->w = pinfo->normw = info_ptr->width;
+  pinfo->h = pinfo->normh = info_ptr->height;
+  if (pinfo->w <= 0 || pinfo->h <= 0) {
+    SetISTR(ISTR_WARNING, "%s:  image dimensions out of range (%dx%d)",
+      fbasename, pinfo->w, pinfo->h);
+    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+    return read_anything;
+  }
+
+  pinfo->frmType = F_PNG;
+
+  sprintf(pinfo->fullInfo, "PNG, %d bit ",
+          info_ptr->bit_depth * info_ptr->channels);
+
+  switch(info_ptr->color_type) {
+    case PNG_COLOR_TYPE_PALETTE:
+      strcat(pinfo->fullInfo, "palette color");
+      break;
+
+    case PNG_COLOR_TYPE_GRAY:
+      strcat(pinfo->fullInfo, "grayscale");
+      break;
+
+    case PNG_COLOR_TYPE_GRAY_ALPHA:
+      strcat(pinfo->fullInfo, "grayscale+alpha");
+      break;
+
+    case PNG_COLOR_TYPE_RGB:
+      strcat(pinfo->fullInfo, "truecolor");
+      break;
+
+    case PNG_COLOR_TYPE_RGB_ALPHA:
+      strcat(pinfo->fullInfo, "truecolor+alpha");
+      break;
+  }
+
+  sprintf(pinfo->fullInfo + strlen(pinfo->fullInfo),
+	  ", %sinterlaced. (%d bytes)",
+	  info_ptr->interlace_type ? "" : "non-", filesize);
+
+  sprintf(pinfo->shrtInfo, "%lux%lu PNG", info_ptr->width, info_ptr->height);
+
+  if (info_ptr->bit_depth < 8)
+      png_set_packing(png_ptr);
+
+  if (info_ptr->valid & PNG_INFO_gAMA)
+    png_set_gamma(png_ptr, Display_Gamma, info_ptr->gamma);
+  else
+    png_set_gamma(png_ptr, Display_Gamma, 0.45);
+
+  gray_to_rgb = 0;   /* quiet a compiler warning */
+
+  if (have_imagebg) {
+    if (info_ptr->bit_depth == 16) {
+      my_background.red   = imagebgR;
+      my_background.green = imagebgG;
+      my_background.blue  = imagebgB;
+      my_background.gray = imagebgG;   /* only used if all three equal... */
+    } else {
+      my_background.red   = (imagebgR >> 8);
+      my_background.green = (imagebgG >> 8);
+      my_background.blue  = (imagebgB >> 8);
+      my_background.gray = my_background.green;
+    }
+    png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN,
+                       0, Display_Gamma);
+    if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
+         (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && HAVE_tRNS)) &&
+        (imagebgR != imagebgG || imagebgR != imagebgB))  /* i.e., colored bg */
+    {
+      png_set_gray_to_rgb(png_ptr);
+      png_set_expand(png_ptr);
+      gray_to_rgb = 1;
+    }
+  } else {
+    if (info_ptr->valid & PNG_INFO_bKGD) {
+      png_set_background(png_ptr, &info_ptr->background,
+                         PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+    } else {
+      my_background.red = my_background.green = my_background.blue =
+        my_background.gray = 0;
+      png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN,
+                         0, Display_Gamma);
+    }
+  }
+
+  if (info_ptr->bit_depth == 16)
+    png_set_strip_16(png_ptr);
+
+  if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
+      info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+  {
+    if (info_ptr->bit_depth == 1)
+      pinfo->colType = F_BWDITHER;
+    else
+      pinfo->colType = F_GREYSCALE;
+    png_set_expand(png_ptr);
+  }
+
+  pass=png_set_interlace_handling(png_ptr);
+
+  png_read_update_info(png_ptr, info_ptr);
+
+  if(info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
+     info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || gray_to_rgb)
+  {
+    linesize = 3 * pinfo->w;
+    if (linesize/3 < pinfo->w) {   /* know pinfo->w > 0 (see above) */
+      SetISTR(ISTR_WARNING, "%s:  image dimensions too large (%dx%d)",
+        fbasename, pinfo->w, pinfo->h);
+      png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+      return read_anything;
+    }
+    pinfo->colType = F_FULLCOLOR;
+    pinfo->type = PIC24;
+  } else {
+    linesize = pinfo->w;
+    pinfo->type = PIC8;
+    if(info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
+       info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+      for(i = 0; i < 256; i++)
+        pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i;
+    } else {
+      pinfo->colType = F_FULLCOLOR;
+      for(i = 0; i < info_ptr->num_palette; i++) {
+        pinfo->r[i] = info_ptr->palette[i].red;
+        pinfo->g[i] = info_ptr->palette[i].green;
+        pinfo->b[i] = info_ptr->palette[i].blue;
+      }
+    }
+  }
+
+  bufsize = linesize * pinfo->h;
+  if (bufsize/linesize < pinfo->h) {  /* know linesize, pinfo->h > 0 (above) */
+    SetISTR(ISTR_WARNING, "%s:  image dimensions too large (%dx%d)",
+      fbasename, pinfo->w, pinfo->h);
+    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+    return read_anything;
+  }
+  pinfo->pic = calloc((size_t)bufsize, (size_t)1);
+
+  if(!pinfo->pic) {
+    png_error(png_ptr, "can't allocate space for PNG image");
+  }
+
+  png_start_read_image(png_ptr);
+
+  for(i = 0; i < pass; i++) {
+    byte *p = pinfo->pic;
+    for(j = 0; j < pinfo->h; j++) {
+      png_read_row(png_ptr, p, NULL);
+      read_anything = 1;
+      if((j & 0x1f) == 0) WaitCursor();
+      p += linesize;
+    }
+  }
+
+  png_read_end(png_ptr, info_ptr);
+
+  if(info_ptr->num_text > 0) {
+    commentsize = 1;
+
+    for(i = 0; i < info_ptr->num_text; i++)
+      commentsize += strlen(info_ptr->text[i].key) + 1 +
+                     info_ptr->text[i].text_length + 2;
+
+    if((pinfo->comment = malloc(commentsize)) == NULL) {
+      png_warning(png_ptr,"can't allocate comment string");
+    }
+    else {
+      pinfo->comment[0] = '\0';
+      for(i = 0; i < info_ptr->num_text; i++) {
+        strcat(pinfo->comment, info_ptr->text[i].key);
+        strcat(pinfo->comment, "::");
+        strcat(pinfo->comment, info_ptr->text[i].text);
+        strcat(pinfo->comment, "\n");
+      }
+    }
+  }
+
+  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+
+  fclose(fp);
+
+  return 1;
+}
+
+
+/*******************************************/
+static void
+png_xv_error(png_ptr, message)
+     png_structp png_ptr;
+     png_const_charp message;
+{
+  SetISTR(ISTR_WARNING,"%s:  libpng error: %s", fbasename, message);
+
+  longjmp(png_ptr->jmpbuf, 1);
+}
+
+
+/*******************************************/
+static void
+png_xv_warning(png_ptr, message)
+     png_structp png_ptr;
+     png_const_charp message;
+{
+  if (!png_ptr)
+    return;
+
+  SetISTR(ISTR_WARNING,"%s:  libpng warning: %s", fbasename, message);
+}
+
+
+/*******************************************/
+void
+VersionInfoPNG()	/* GRR 19980605 */
+{
+  fprintf(stderr, "   Compiled with libpng %s; using libpng %s.\n",
+    PNG_LIBPNG_VER_STRING, png_libpng_ver);
+  fprintf(stderr, "   Compiled with zlib %s; using zlib %s.\n",
+    ZLIB_VERSION, zlib_version);
+}
+
+#endif /* HAVE_PNG */
diff -ruN xv-3.10a-bugfixes/xvpopup.c xv-3.10a-enhancements/xvpopup.c
--- xv-3.10a-bugfixes/xvpopup.c	2004-05-16 18:04:13.000000000 -0700
+++ xv-3.10a-enhancements/xvpopup.c	2005-04-25 08:21:34.000000000 -0700
@@ -23,7 +23,7 @@
 #define OMIT_ICON_BITS
 #include "bits/icon"   /* icon_bits[] not used, but icon_width/height are */
 
-#define PUWIDE 400
+#define PUWIDE 480
 #define PUHIGH 170
 
 #define PAD_PUWIDE 480
@@ -201,14 +201,14 @@
 
     if (!padHaveDooDads) {
       DCreate(&padWDial, popW, 16,      puhigh-16-100-1,75,100,
-	      1, 2048, pWIDE, 10,
+	      1.0, 2048.0, (double)pWIDE, 1.0, 10.0,
 	      infofg, infobg, hicol, locol, "Width", NULL);
       DCreate(&padHDial, popW, 16+1+75, puhigh-16-100-1,75,100,
-	      1, 2048, pHIGH, 10,
+	      1.0, 2048.0, (double)pHIGH, 1.0, 10.0,
 	      infofg, infobg, hicol, locol, "Height", NULL);
 
       DCreate(&padODial, popW, 16+1+75+75+9, puhigh-16-100-1,75,100,
-	      0, 100, 100, 10,
+	      0.0, 100.0, 100.0, 1.0, 10.0,
 	      infofg, infobg, hicol, locol, "Opaque", NULL);
 
       MBCreate(&padMthdMB, popW, 100-2+44, 10, 140, 19, NULL,
@@ -259,9 +259,9 @@
   else if (poptyp == ISPAD) {
     BTSetActive(&bts[0], (int) strlen(gsBuf));
     i = pWIDE * 3;  RANGE(i,2048,9999);
-    DSetRange(&padWDial, 1, i, padWDial.val, 10);
+    DSetRange(&padWDial, 1.0, (double)i, padWDial.val, 1.0, 10.0);
     i = pHIGH * 3;  RANGE(i,2048,9999);
-    DSetRange(&padHDial, 1, i, padHDial.val, 10);
+    DSetRange(&padHDial, 1.0, (double)i, padHDial.val, 1.0, 10.0);
 
     DSetActive(&padWDial, (padMode!=PAD_LOAD));  /* DSetRange activates dial */
     DSetActive(&padHDial, (padMode!=PAD_LOAD));
@@ -287,15 +287,19 @@
   /* center first button in window around mouse position, with constraint that
      window be fully on the screen */
 
-  CenterMapWindow(popW, 40 + bts[0].x, BUTTH/2 + bts[0].y, puwide, puhigh);
   popUp = poptyp;
+  if (startGrab == 2)
+    startGrab = 4;
+  else {
+    CenterMapWindow(popW, 40 + bts[0].x, BUTTH/2 + bts[0].y, puwide, puhigh);
 
-  /* MUST wait for VisibilityNotify event to come in, else we run the risk
-     of UnMapping the window *before* the Map request completed.  This
-     appears to be bad, (It leaves an empty window frame up.) though it
-     generally only happens on slow servers.  Better safe than screwed... */
+    /* MUST wait for VisibilityNotify event to come in, else we run the risk
+       of UnMapping the window *before* the Map request completed.  This
+       appears to be bad, (It leaves an empty window frame up.) though it
+       generally only happens on slow servers.  Better safe than screwed... */
 
-  XWindowEvent(theDisp, popW, VisibilityChangeMask, &event);
+    XWindowEvent(theDisp, popW, VisibilityChangeMask, &event);
+  }
 
   /* block until this window gets closed */
   while (popUp) {
@@ -466,9 +470,9 @@
   changedGSBuf();      /* careful!  popW doesn't exist yet! */
 
   if (padHaveDooDads) {
-    oldW = padWDial.val;
-    oldH = padHDial.val;
-    oldO = padODial.val;
+    oldW = (int)padWDial.val;
+    oldH = (int)padHDial.val;
+    oldO = (int)padODial.val;
   }
   else { oldW = pWIDE;  oldH = pHIGH;  oldO = 100; }
 
@@ -487,9 +491,9 @@
   }
 
   if (rv == 1) {   /* cancelled:  restore normal values */
-    DSetVal(&padWDial, oldW);
-    DSetVal(&padHDial, oldH);
-    DSetVal(&padODial, oldO);
+    DSetVal(&padWDial, (double)oldW);
+    DSetVal(&padHDial, (double)oldH);
+    DSetVal(&padODial, (double)oldO);
   }
 
   XUnmapWindow(theDisp, padWDial.win);
@@ -499,9 +503,9 @@
   /* load up return values */
   *pMode   = padMode;
   *pStr    = padBuf;
-  *pWide   = padWDial.val;
-  *pHigh   = padHDial.val;
-  *pOpaque = padODial.val;
+  *pWide   = (int)padWDial.val;
+  *pHigh   = (int)padHDial.val;
+  *pOpaque = (int)padODial.val;
   *pOmode  = padOMode;
 
   return rv;
@@ -956,14 +960,14 @@
      int x,y;
 {
   int i;
-  BUTT *bp;
+  BUTT *bp = NULL;
 
   for (i=0; i<nbts; i++) {
     bp = &bts[i];
     if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
   }
 
-  if (i<nbts && BTTrack(bp)) {
+  if (i<nbts && bp && BTTrack(bp)) {
     popUp = 0;  selected = i;  return;
   }
 
@@ -972,8 +976,8 @@
   else if (popUp == ISPAD) {
     if (PTINRECT(x, y, padDButt.x, padDButt.y, padDButt.w, padDButt.h)) {
       if (BTTrack(&padDButt)) {
-	DSetVal(&padWDial, pWIDE);
-	DSetVal(&padHDial, pHIGH);
+	DSetVal(&padWDial, (double)pWIDE);
+	DSetVal(&padHDial, (double)pHIGH);
       }
     }
 
@@ -1105,7 +1109,7 @@
   }
 
 
-  else if (c=='\010' || c=='\177') {    /* BS or DEL */
+  else if (c=='\010') {                 /* BS */
     if (gsCurPos==0) return 1;                     /* at beginning of str */
     xvbcopy(&gsBuf[gsCurPos], &gsBuf[gsCurPos-1], (size_t) len-gsCurPos+1);
     gsCurPos--;
@@ -1128,7 +1132,7 @@
     gsCurPos = len;
   }
 
-  else if (c=='\004') {                 /* ^D: delete character at gsCurPos */
+  else if (c=='\004' || c=='\177') {    /* ^D or DEL: delete character at gsCurPos */
     if (gsCurPos==len) return 1;
     xvbcopy(&gsBuf[gsCurPos+1], &gsBuf[gsCurPos], (size_t) len-gsCurPos);
   }
diff -ruN xv-3.10a-bugfixes/xvps.c xv-3.10a-enhancements/xvps.c
--- xv-3.10a-bugfixes/xvps.c	2005-03-30 08:18:17.000000000 -0800
+++ xv-3.10a-enhancements/xvps.c	2005-04-17 14:45:28.000000000 -0700
@@ -142,9 +142,9 @@
   CBCreate(&encapsCB, psW, 240, 7, "preview", infofg, infobg, hicol, locol);
   CBCreate(&pscompCB, psW, 331, 7, "compress", infofg, infobg, hicol, locol);
 
-  DCreate(&xsDial, psW, 240, 30, 80, 100, 10, 800, 100, 5,
+  DCreate(&xsDial, psW, 240, 30, 80, 100, 10.0, 800.0, 100.0, 0.5, 5.0,
 	  infofg, infobg, hicol, locol, "Width", "%");
-  DCreate(&ysDial, psW, 331, 30, 80, 100, 10, 800, 100, 5,
+  DCreate(&ysDial, psW, 331, 30, 80, 100, 10.0, 800.0, 100.0, 0.5, 5.0,
 	  infofg, infobg, hicol, locol, "Height", "%");
   xsDial.drawobj = changedScale;
   ysDial.drawobj = changedScale;
@@ -239,10 +239,10 @@
 
   if (rd_int("psres")) {             /* xv.psres:  default paper resolution */
     if (def_int >= 10 && def_int <= 720) {
-      int i = (int) ((PIX2INCH * 100) / def_int);
+      double v = (PIX2INCH * 100) / def_int;
 
-      DSetVal(&xsDial, i);
-      DSetVal(&ysDial, i);
+      DSetVal(&xsDial, v);
+      DSetVal(&ysDial, v);
     }
   }
 
@@ -839,7 +839,7 @@
   if (scx < scy) { sz_iny = h * scx; }
             else { sz_inx = w * scy; }
 
-  DSetVal(&xsDial, (int) ((100 * (sz_inx * PIX2INCH) / w) + .5));
+  DSetVal(&xsDial, 100 * (sz_inx * PIX2INCH) / w);
   DSetVal(&ysDial, xsDial.val);
 
   sz_inx = (double) w / PIX2INCH * (xsDial.val / 100.0);
@@ -1561,9 +1561,9 @@
      the first one is loaded (but not deleted) */
 
 #ifdef GS_PATH
-  char tmp[512], gscmd[512], cmdstr[512], tmpname[64];
+  #define CMDSIZE	1024
+  char tmp[512], gscmd[512], cmdstr[CMDSIZE], tmpname[64];
   int  gsresult, nump, i, filetype, doalert, epsf;
-  char *rld;
 #endif
 
   pinfo->pic     = (byte *) NULL;
@@ -1596,7 +1596,7 @@
   /* build 'gscmd' string */
 
 #ifndef VMS  /* VMS needs quotes around mixed case command lines */
-  sprintf(gscmd, "%s -sDEVICE=%s -r%d -q -dNOPAUSE -sOutputFile=%s%%d ",
+  sprintf(gscmd, "%s -sDEVICE=%s -r%d -q -dSAFER -dNOPAUSE -sOutputFile=%s%%d ",
 	  GS_PATH, gsDev, gsRes, tmpname);
 #else
   sprintf(gscmd,
@@ -1734,32 +1734,48 @@
 
 /******************************************************************/
 #ifdef GS_PATH
-void buildCmdStr(str, gscmd, fname, quick, epsf)
-     char *str, *gscmd, *fname;
+void buildCmdStr(str, gscmd, xname, quick, epsf)
+     char *str, *gscmd, *xname;
      int   quick, epsf;
 {
   /* note 'epsf' set only on files that don't have a showpage cmd */
+  char *x, *y, *fname;
+
+  x = (char *) malloc((5 * strlen(xname))+3);
+  if (!x)
+	FatalError("malloc failure in xvps.c buildCmdStr");
+  fname = x;
+  *x++ = 0x27;
+
+  for (y = xname; *y; ++y) {
+     if (0x27 == *y) {
+       strcpy(x, "'\"'\"'");
+       x += strlen(x);
+     } else *x++ = *y;
+  }
+  strcpy (x, "'");
 
 #ifndef VMS
 
-  if      (epsf)  sprintf(str, "echo '\n showpage ' | cat '%s' - | %s -",
+  if      (epsf)  snprintf(str, CMDSIZE, "echo '\n showpage ' | cat %s - | %s -",
 			  fname, gscmd);
 
-  else if (quick) sprintf(str, "echo '%s' | cat - '%s' | %s -",
+  else if (quick) snprintf(str, CMDSIZE, "echo %s | cat - %s | %s -",
 			  "/showpage { showpage quit } bind def",
 			  fname,  gscmd);
 
-  else            sprintf(str, "%s -- %s", gscmd, fname);
+  else            snprintf(str, CMDSIZE, "%s -- %s", gscmd, fname);
 
 #else /* VMS */
   /* VMS doesn't have pipes or an 'echo' command and GS doesn't like
-     Unix-style file names as input files in the VMS version */
+     Unix-style filenames as input files in the VMS version */
   strcat(tmp, " -- ");
   rld = strrchr(fname, '/');     /* Pointer to last '/' */
   if (rld) rld++;                /* Pointer to filename */
   else rld = fname;              /* No path - use original string */
   strcat(tmp, rld);
 #endif  /* VMS */
+  free(fname);
 }
 #endif  /* GS_PATH */
 
diff -ruN xv-3.10a-bugfixes/xvrle.c xv-3.10a-enhancements/xvrle.c
--- xv-3.10a-bugfixes/xvrle.c	2005-03-29 23:29:14.000000000 -0800
+++ xv-3.10a-enhancements/xvrle.c	2004-05-16 18:07:46.000000000 -0700
@@ -43,7 +43,7 @@
   byte   bgcol[256];
   byte   maps[3][256];
   int    xpos, ypos, w, h, flags, ncolors, pixelbits, ncmap, cmaplen;
-  int    cmtlen, npixels, bufsize=0;
+  int    cmtlen;
   byte  *img;
   long filesize;
   char  *bname, *errstr;
@@ -176,44 +176,32 @@
 
   errstr = NULL;
   if (ncolors == 0 || ncolors == 2)
-    errstr = "Unsupported number of channels in RLE file";
+    errstr = "Unsupt. # of channels in RLE file.\n";
 
   if (pixelbits != 8)
-    errstr = "Only 8-bit pixels supported in RLE files";
+    errstr = "Only 8-bit pixels supported in RLE files.\n";
 
   if (ncmap==0 || ncmap==1 || ncmap == 3 || ncmap == ncolors) { /* ok */ }
-  else errstr = "Invalid number of colormap channels in RLE file";
+  else errstr = "Invalid # of colormap channels in RLE file.\n";
 
-  npixels = w * h;
-  if (w <= 0 || h <= 0 || npixels/w != h)
-    errstr = "RLE image dimensions out of range";
+  if (w<1 || h<1)
+    errstr = "Bogus size in RLE header.\n";
 
 
   if (errstr) {
     fclose(fp);
-    if (pinfo->comment)
-      free(pinfo->comment);
-    pinfo->comment = (char *) NULL;
+    if (pinfo->comment) free(pinfo->comment);  pinfo->comment = (char *) NULL;
     return rleError(bname, errstr);
   }
 
 
   /* allocate image memory */
-  if (ncolors == 1)
-    img = (byte *) calloc((size_t) npixels, (size_t) 1);
-  else {
-    bufsize = 3*npixels;
-    if (bufsize/3 != npixels)
-      return rleError(bname, "RLE image dimensions out of range");
-    img = (byte *) calloc((size_t) bufsize, (size_t) 1);
-  }
-
+  if (ncolors == 1) img = (byte *) calloc((size_t) w * h,     (size_t) 1);
+               else img = (byte *) calloc((size_t) w * h * 3, (size_t) 1);
   if (!img) {
     fclose(fp);
-    if (pinfo->comment)
-      free(pinfo->comment);
-    pinfo->comment = (char *) NULL;
-    return rleError(bname, "Unable to allocate RLE image data");
+    if (pinfo->comment) free(pinfo->comment);  pinfo->comment = (char *) NULL;
+    return rleError(bname, "unable to allocate image data.\n");
   }
 
 
@@ -221,10 +209,10 @@
   if ((flags & H_CLEARFIRST) && !(flags & H_NO_BACKGROUND)) {
     byte *ip;
     if (ncolors == 1) {
-      for (i=0, ip=img; i<npixels; i++, ip++) *ip = bgcol[0];
+      for (i=0, ip=img; i<w*h; i++, ip++) *ip = bgcol[0];
     }
     else {
-      for (i=0, ip=img; i<npixels; i++)
+      for (i=0, ip=img; i<w*h; i++)
 	for (j=0; j<3; j++, ip++) *ip = bgcol[j];
     }
   }
@@ -242,7 +230,7 @@
   if (ncmap) {
     byte *ip;
     int   imagelen, cmask;
-    imagelen = (ncolors==1) ? npixels : bufsize;
+    imagelen = (ncolors==1) ? w*h : w*h*3;
     cmask = (cmaplen-1);
 
     if (ncmap == 1) {   /* single gamma curve */
@@ -250,7 +238,7 @@
     }
 
     else if (ncmap >= 3 && ncolors >=3) {   /* one curve per band */
-      for (i=0, ip=img; i<npixels; i++) {
+      for (i=0, ip=img; i<w*h; i++) {
 	*ip = maps[0][*ip & cmask];   ip++;
 	*ip = maps[1][*ip & cmask];   ip++;
 	*ip = maps[2][*ip & cmask];   ip++;
diff -ruN xv-3.10a-bugfixes/xvroot.c xv-3.10a-enhancements/xvroot.c
--- xv-3.10a-bugfixes/xvroot.c	2004-05-16 18:04:21.000000000 -0700
+++ xv-3.10a-enhancements/xvroot.c	2004-05-16 18:07:52.000000000 -0700
@@ -44,6 +44,7 @@
   case RM_MIRROR:
   case RM_IMIRROR: rpixw = 2*eWIDE;  rpixh = 2*eHIGH;  break;
   case RM_CSOLID:
+  case RM_UPLEFT:
   case RM_CWARP:
   case RM_CBRICK:  rpixw = dispWIDE; rpixh = dispHIGH; break;
 
@@ -101,7 +102,7 @@
 
 
   else if (rmode == RM_CENTER || rmode == RM_CENTILE || rmode == RM_CSOLID ||
-	   rmode == RM_CWARP || rmode == RM_CBRICK) {
+	   rmode == RM_CWARP || rmode == RM_CBRICK || rmode == RM_UPLEFT) {
     /* do some stuff to set up the border around the picture */
 
     if (rmode != RM_CENTILE) {
@@ -138,6 +139,12 @@
 
     else if (rmode == RM_CSOLID) { }
 
+    else if (rmode == RM_UPLEFT) {
+
+      XPutImage(theDisp, tmpPix, theGC, theImage, 0,0, 0,0,
+		(u_int) eWIDE, (u_int) eHIGH);
+    }
+
     else if (rmode == RM_CWARP) {          /* warp effect */
       XSetForeground(theDisp, theGC, rootfg);
       for (i=0; i<=dispWIDE; i+=8)
@@ -157,7 +164,7 @@
 
 
     /* draw the image centered on top of the background */
-    if (rmode != RM_CENTILE)
+    if ((rmode != RM_CENTILE) && (rmode != RM_UPLEFT))
       XPutImage(theDisp, tmpPix, theGC, theImage, 0,0,
 		((int) dispWIDE-eWIDE)/2, ((int) dispHIGH-eHIGH)/2,
 		(u_int) eWIDE, (u_int) eHIGH);
diff -ruN xv-3.10a-bugfixes/xvsmooth.c xv-3.10a-enhancements/xvsmooth.c
--- xv-3.10a-bugfixes/xvsmooth.c	2004-05-16 18:04:28.000000000 -0700
+++ xv-3.10a-enhancements/xvsmooth.c	2004-05-16 18:07:59.000000000 -0700
@@ -105,7 +105,7 @@
     /* we can save a lot of time by precomputing cxtab[] and pxtab[], both
        dwide arrays of ints that contain values for the equations:
          cx = (ex * swide) / dwide;
-         px = ((ex * swide * 100) / dwide) - (cx * 100) - 50; */
+         px = ((ex * swide * 128) / dwide) - (cx * 128) - 64; */
 
     cxtab = (int *) malloc(dwide * sizeof(int));
     if (!cxtab) { free(pic24);  return NULL; }
@@ -115,8 +115,8 @@
 
     for (ex=0; ex<dwide; ex++) {
       cxtab[ex] = (ex * swide) / dwide;
-      pxtab[ex] = (((ex * swide)* 100) / dwide)
-	           - (cxtab[ex] * 100) - 50;
+      pxtab[ex] = (((ex * swide)* 128) / dwide)
+	           - (cxtab[ex] * 128) - 64;
     }
 
     for (ey=0; ey<dhigh; ey++) {
@@ -125,7 +125,7 @@
       ProgressMeter(0, (dhigh)-1, ey, "Smooth");
 
       cy = (ey * shigh) / dhigh;
-      py = (((ey * shigh) * 100) / dhigh) - (cy * 100) - 50;
+      py = (((ey * shigh) * 128) / dhigh) - (cy * 128) - 64;
       if (py<0) { y1 = cy-1;  if (y1<0) y1=0; }
            else { y1 = cy+1;  if (y1>shigh-1) y1=shigh-1; }
 
@@ -172,30 +172,30 @@
 	else {
 	  /* compute weighting factors */
 	  apx = abs(px);  apy = abs(py);
-	  pA = (apx * apy) / 100;
-	  pB = (apy * (100 - apx)) / 100;
-	  pC = (apx * (100 - apy)) / 100;
-	  pD = 100 - (pA + pB + pC);
+	  pA = (apx * apy) >> 7; /* div 128 */
+	  pB = (apy * (128 - apx)) >> 7; /* div 128 */
+	  pC = (apx * (128 - apy)) >> 7; /* div 128 */
+	  pD = 128 - (pA + pB + pC);
 
 	  if (is24) {
-	    *pp++ = ((int) (pA * rA))/100 + ((int) (pB * rB))/100 +
-	            ((int) (pC * rC))/100 + ((int) (pD * rD))/100;
+	    *pp++ = (((int) (pA * rA))>>7) + (((int) (pB * rB))>>7) +
+	            (((int) (pC * rC))>>7) + (((int) (pD * rD))>>7);
 
-	    *pp++ = ((int) (pA * gA))/100 + ((int) (pB * gB))/100 +
-	            ((int) (pC * gC))/100 + ((int) (pD * gD))/100;
+	    *pp++ = (((int) (pA * gA))>>7) + (((int) (pB * gB))>>7) +
+	            (((int) (pC * gC))>>7) + (((int) (pD * gD))>>7);
 
-	    *pp++ = ((int) (pA * bA))/100 + ((int) (pB * bB))/100 +
-	            ((int) (pC * bC))/100 + ((int) (pD * bD))/100;
+	    *pp++ = (((int) (pA * bA))>>7) + (((int) (pB * bB))>>7) +
+	            (((int) (pC * bC))>>7) + (((int) (pD * bD))>>7);
 	  }
 	  else {  /* 8-bit pic */
-	    *pp++ = ((int) (pA * rmap[cA]))/100 + ((int)(pB * rmap[cB]))/100 +
-	            ((int) (pC * rmap[cC]))/100 + ((int)(pD * rmap[cD]))/100;
+	    *pp++ = (((int)(pA * rmap[cA]))>>7) + (((int)(pB * rmap[cB]))>>7) +
+	            (((int)(pC * rmap[cC]))>>7) + (((int)(pD * rmap[cD]))>>7);
 
-	    *pp++ = ((int) (pA * gmap[cA]))/100 + ((int)(pB * gmap[cB]))/100 +
-	            ((int) (pC * gmap[cC]))/100 + ((int)(pD * gmap[cD]))/100;
+	    *pp++ = (((int)(pA * gmap[cA]))>>7) + (((int)(pB * gmap[cB]))>>7) +
+	            (((int)(pC * gmap[cC]))>>7) + (((int)(pD * gmap[cD]))>>7);
 
-	    *pp++ = ((int)(pA * bmap[cA]))/100 + ((int)(pB * bmap[cB]))/100 +
-  	            ((int)(pC * bmap[cC]))/100 + ((int)(pD * bmap[cD]))/100;
+	    *pp++ = (((int)(pA * bmap[cA]))>>7) + (((int)(pB * bmap[cB]))>>7) +
+  	            (((int)(pC * bmap[cC]))>>7) + (((int)(pD * bmap[cD]))>>7);
 	  }
 	}
       }
diff -ruN xv-3.10a-bugfixes/xvtext.c xv-3.10a-enhancements/xvtext.c
--- xv-3.10a-bugfixes/xvtext.c	2004-05-16 18:04:38.000000000 -0700
+++ xv-3.10a-enhancements/xvtext.c	2005-05-01 13:04:23.000000000 -0700
@@ -19,9 +19,13 @@
 #include "copyright.h"
 
 #include "xv.h"
+#ifdef TV_MULTILINGUAL
+#include "xvml.h"
+#endif
 
-
-#define BUTTW 80
+#define BUTTW1 80
+#define BUTTW2 60
+#define BUTTW3 110
 #define BUTTH 24
 
 #define TOPMARGIN 30       /* from top of window to top of text window */
@@ -36,11 +40,28 @@
 #define TV_ASCII    0
 #define TV_HEX      1
 #define TV_CLOSE    2
-#define TV_NBUTTS   3
 
+#define TV_E_NBUTTS 3
+
+#ifdef TV_L10N
+#  define TV_RESCAN   3
+#  define TV_USASCII  4
+#  define TV_JIS      5
+#  define TV_EUCJ     6
+#  define TV_MSCODE   7
+
+#  define TV_J_NBUTTS 8
+#endif
 
 #define TITLELEN 128
 
+#ifdef TV_MULTILINGUAL
+struct coding_spec {
+    struct coding_system coding_system;
+    char *(*converter)PARM((char *, int, int *));
+};
+#endif
+
 /* data needed per text window */
 typedef struct {  Window win, textW;
 		  int    vis, wasvis;
@@ -57,16 +78,89 @@
 		  int    chwide, chhigh;   /* size of textW, in chars */
 		  int    hexmode;          /* true if disp Hex, else Ascii */
 		  SCRL   vscrl, hscrl;
-		  BUTT   but[TV_NBUTTS], nopBut;
+#ifdef TV_L10N
+		  int    code;         /* current character code */
+		  BUTT   but[TV_J_NBUTTS], nopBut;
+#else
+		  BUTT   but[TV_E_NBUTTS], nopBut;
+#endif
+#ifdef TV_MULTILINGUAL
+/*		  int    codeset; */
+		  struct coding_spec ccs;	/* current coding_spec */
+		  BUTT   csbut;
+		  char *cv_text;
+		  int cv_len;
+		  struct context *ctx;
+		  struct ml_text *txt;
+		  struct csinfo_t *cs;
+#endif
 		} TVINFO;
 
 
 static TVINFO   tinfo[MAXTVWIN];
 static int      hasBeenSized = 0;
 static int      haveWindows  = 0;
+static int      nbutts;		/* # of buttons */
 static int      mfwide, mfhigh, mfascent;   /* size of chars in mono font */
 static int     *event_retP, *event_doneP;   /* used in tvChkEvent() */
-
+#ifdef TV_MULTILINGUAL
+# define TV_PLAIN          0
+# define TV_ISO_8859_1     1
+# define TV_ISO_2022_JP    2
+# define TV_EUC_JAPAN      3
+# define TV_ISO_2022_INT_1 4
+# define TV_ISO_2022_KR    5
+# define TV_EUC_KOREA      6
+# define TV_ISO_2022_SS2_8 7
+# define TV_ISO_2022_SS2_7 8
+# define TV_SHIFT_JIS      9
+# define TV_NCSS          10
+static char *codeSetNames[TV_NCSS] = {
+    "plain",
+    "iso-8859-1",
+    "iso-2022-jp",
+    "euc-japan",
+    "iso-2022-int-1",
+    "iso-2022-kr",
+    "euc-korea",
+    "iso-2022-ss2-8",
+    "iso-2022-ss2-7",
+    "Shift JIS",
+};
+static struct coding_spec coding_spec[TV_NCSS] = {
+    /* --- G0 ---   --- G1 ---   --- G2 ---   --- G3 ---  GL GR EOL SF LS */
+    /* plain */
+    {{{{ 1,94,'B'}, { 1,94,'B'}, { 1,94,'B'}, { 1,94,'B'}}, 0, 0,  0, 1, 1},
+     NULL},
+    /* iso-8859-1 */
+    {{{{ 1,94,'B'}, { 1,96,'A'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 1,  0, 0, 0},
+     NULL},
+    /* iso-2022-jp */
+    {{{{ 1,94,'B'}, {-1,94,'B'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 0,  0, 1, 0},
+     NULL},
+    /* euc-japan */
+    {{{{ 1,94,'B'}, { 2,94,'B'}, { 1,94,'J'}, { 2,94,'D'}}, 0, 1,  0, 1, 0},
+     NULL},
+    /* iso-2022-int-1 */
+    {{{{ 1,94,'B'}, { 2,94,'C'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 1,  0, 1, 1},
+     NULL},
+    /* iso-2022-kr */
+    {{{{ 1,94,'B'}, { 2,94,'C'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 1,  0, 0, 1},
+     NULL},
+    /* euc-korea */
+    {{{{ 1,94,'B'}, { 2,94,'C'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 1,  0, 0, 0},
+     NULL},
+    /* iso-2022-ss2-8 */
+    {{{{ 1,94,'B'}, {-1,94,'C'}, { 0,94,'B'}, {-1,94,'B'}}, 0, 1,  0, 0, 0},
+     NULL},
+    /* iso-2022-ss2-7 */
+    {{{{ 1,94,'B'}, {-1,94,'C'}, { 0,94,'B'}, {-1,94,'B'}}, 0, 1,  0, 1, 0},
+     NULL},
+    /* shift jis */
+    {{{{ 1,94,'B'}, { 2,94,'B'}, { 1,94,'J'}, { 2,94,'D'}}, 0, 1,  1, 1, 0},
+     sjis_to_jis},
+};
+#endif
 
 static void closeText       PARM((TVINFO *));
 static int  tvChkEvent      PARM((TVINFO *, XEvent *));
@@ -82,7 +176,15 @@
 static void textKey         PARM((TVINFO *, int));
 static void doHexAsciiCmd   PARM((TVINFO *, int));
 static void computeText     PARM((TVINFO *));
-
+#ifdef TV_L10N
+static int  selectCodeset         PARM((TVINFO *));
+#endif
+#ifdef TV_MULTILINGUAL
+static void setCodingSpec   PARM((TVINFO *, struct coding_spec *));
+static void createCsWins    PARM((char *));
+static void openCsWin       PARM((TVINFO *));
+static void closeCsWin      PARM((TVINFO *));
+#endif
 
 /* HEXMODE output looks like this:
 0x00000000: 00 11 22 33 44 55 66 77 - 88 99 aa bb cc dd ee ff  0123456789abcdef
@@ -98,12 +200,51 @@
   XSizeHints            hints;
   XSetWindowAttributes  xswa;
   TVINFO               *tv;
+#ifdef TV_MULTILINGUAL
+  int			default_codeset;
+#endif
 
+#ifdef TV_L10N
+  if (!xlocale) {
+#endif
+      mfwide = monofinfo->max_bounds.width;
+      mfhigh = monofinfo->ascent + monofinfo->descent;
+      mfascent = monofinfo->ascent;
 
-  mfwide = monofinfo->max_bounds.width;
-  mfhigh = monofinfo->ascent + monofinfo->descent;
-  mfascent = monofinfo->ascent;
+      nbutts = TV_E_NBUTTS;	/* # of buttons */
+#ifdef TV_L10N
+  }
+  else {
+      mfwide = monofsetinfo->max_logical_extent.width / 2;	/* shit! */
+      mfhigh = monofsetinfo->max_logical_extent.height + 1;
+      mfascent = mfhigh;
+
+      nbutts = TV_J_NBUTTS;	/* # of buttons */
+  }
+#endif
 
+#ifdef TV_MULTILINGUAL
+  {
+    char *dc = XGetDefault(theDisp, "xv", "codeSet");
+    if (dc == NULL)
+      default_codeset = TV_DEFAULT_CODESET;
+    else {
+      for (i = 0; i < TV_NCSS; i++) {
+	if (strcmp(dc, codeSetNames[i]) == 0)
+	  break;
+      }
+      if (i >= TV_NCSS) {
+        if (strcmp(dc, "iso-2022") == 0)
+	  default_codeset = TV_PLAIN;
+	else {
+	  SetISTR(ISTR_WARNING, "%s: unknown codeset.", dc);
+	  default_codeset = TV_PLAIN;
+	}
+      } else
+	default_codeset = i;
+    }
+  }
+#endif
   /* compute default size of textview windows.  should be big enough to
      hold an 80x24 text window */
 
@@ -118,6 +259,14 @@
   for (i=0; i<MAXTVWIN; i++) {
     tv = &tinfo[i];
 
+#ifdef TV_MULTILINGUAL
+    tv->ctx = ml_create_context(ScreenOfDisplay(theDisp, theScreen));
+    tv->txt = NULL;
+    tv->cv_text = NULL;
+    tv->cv_len = 0;
+    ml_set_charsets(tv->ctx, &coding_spec[TV_PLAIN].coding_system);
+#endif
+
     tv->win = CreateWindow((i<CMTWIN) ? "xv text viewer" : "xv image comments",
 			   "XVtextview",
 			   (i<CMTWIN) ? geom : cmtgeom,
@@ -162,24 +311,56 @@
     XSelectInput(theDisp, tv->textW, ExposureMask | ButtonPressMask);
 
 
-    BTCreate(&(tv->but[TV_ASCII]), tv->win, 0,0,BUTTW,BUTTH,
+    BTCreate(&(tv->but[TV_ASCII]), tv->win, 0,0,BUTTW1,BUTTH,
 	     "Ascii",infofg,infobg,hicol,locol);
-    BTCreate(&(tv->but[TV_HEX]), tv->win, 0,0,BUTTW,BUTTH,
+    BTCreate(&(tv->but[TV_HEX]), tv->win, 0,0,BUTTW1,BUTTH,
 	     "Hex",infofg,infobg,hicol,locol);
-    BTCreate(&(tv->but[TV_CLOSE]), tv->win, 0,0,BUTTW,BUTTH,
+    BTCreate(&(tv->but[TV_CLOSE]), tv->win, 0,0,BUTTW1,BUTTH,
 	     "Close",infofg,infobg,hicol,locol);
 
+#ifdef TV_L10N
+    if (xlocale) {
+	BTCreate(&(tv->but[TV_RESCAN]), tv->win, 0,0,BUTTW2,BUTTH,
+		 "RESCAN",infofg,infobg,hicol,locol);
+	BTCreate(&(tv->but[TV_USASCII]), tv->win, 0,0,BUTTW2,BUTTH,
+		 "ASCII",infofg,infobg,hicol,locol);
+	BTCreate(&(tv->but[TV_JIS]), tv->win, 0,0,BUTTW2,BUTTH,
+		 "JIS",infofg,infobg,hicol,locol);
+	BTCreate(&(tv->but[TV_EUCJ]), tv->win, 0,0,BUTTW2,BUTTH,
+		 "EUC-j",infofg,infobg,hicol,locol);
+	BTCreate(&(tv->but[TV_MSCODE]), tv->win, 0,0,BUTTW2,BUTTH,
+		 "MS Kanji",infofg,infobg,hicol,locol);
+    }
+#endif
+
     BTCreate(&(tv->nopBut), tv->win, 0,0, (u_int) tv->vscrl.tsize+1,
 	     (u_int) tv->vscrl.tsize+1, "", infofg, infobg, hicol, locol);
     tv->nopBut.active = 0;
 
     XMapSubwindows(theDisp, tv->win);
 
+#ifdef TV_MULTILINGUAL
+    BTCreate(&tv->csbut, tv->win, 0, 0, BUTTW1, BUTTH, "Code Sets",
+	     infofg, infobg, hicol, locol);
+#endif
+
     tv->text = (char *) NULL;
     tv->textlen = 0;
     tv->title[0] = '\0';
+#ifdef TV_L10N
+    tv->code = (xlocale ? LOCALE_DEFAULT : 0);
+#endif
+#ifdef TV_MULTILINGUAL
+    tv->ccs = coding_spec[default_codeset];
+#endif
   }
-
+#ifdef TV_MULTILINGUAL
+  get_monofont_size(&mfwide, &mfhigh);
+  /* recalculate sizes. */
+  defwide = 80 * mfwide + 2*LRMARGINS + 8 + 20;   /* -ish */
+  defhigh = 24 * mfhigh + TOPMARGIN + BOTMARGIN + 8 + 20;   /* ish */
+  cmthigh = 6  * mfhigh + TOPMARGIN + BOTMARGIN + 8 + 20;   /* ish */
+#endif
 
   for (i=0; i<MAXTVWIN; i++) {
     resizeText(&tinfo[i], defwide, (i<CMTWIN) ? defhigh : cmthigh);
@@ -190,44 +371,54 @@
 
   hasBeenSized = 1;  /* we can now start looking at textview events */
 
+#ifdef TV_MULTILINGUAL
+  createCsWins("+100+100");
+#endif
 }
 
 
 /***************************************************************/
-void TextView(fname)
+int TextView(fname)
      char *fname;
 {
   /* given a filename, attempts to read in the file and open a textview win */
 
+  int   filetype;
   long  textlen;
   char *text, buf[512], title[128], rfname[MAXPATHLEN+1];
   char *basefname[128];  /* just current fname, no path */
   FILE *fp;
+  char filename[MAXPATHLEN+1];
+
+  strncpy(filename, fname, sizeof(filename) - 1);
+#ifdef AUTO_EXPAND
+  Mkvdir(filename);
+  Dirtovd(filename);
+#endif
 
   basefname[0] = '\0';
-  strcpy(rfname, fname);
+  strncpy(rfname, filename, sizeof(rfname) - 1);
 
   /* see if this file is compressed.  if it is, uncompress it, and view
      the uncompressed version */
 
-  if (ReadFileType(fname) == RFT_COMPRESS) {
+  filetype = ReadFileType(filename);
+  if ((filetype == RFT_COMPRESS) || (filetype == RFT_BZIP2)) {
 #ifndef VMS
-    if (!UncompressFile(fname, rfname)) return;    /* failed to uncompress */
+    if (!UncompressFile(filename, rfname, filetype)) return FALSE;
 #else
     /* chop off trailing '.Z' from friendly displayed basefname, if any */
-    strcpy (basefname, fname);
+    strncpy (basefname, filename, 128 - 1);
     *rindex (basefname, '.') = '\0';
-    if (!UncompressFile(basefname, rfname)) return;/* failed to uncompress */
+    if (!UncompressFile(basefname, rfname, filetype)) return FALSE;
 #endif
   }
 
-
-
   fp = fopen(rfname, "r");
   if (!fp) {
     sprintf(buf,"Couldn't open '%s':  %s", rfname, ERRSTR(errno));
     ErrPopUp(buf,"\nOh well");
-    return;
+    return FALSE;
   }
 
 
@@ -239,16 +430,16 @@
     sprintf(buf, "File '%s' contains no data.  (Zero length file.)", rfname);
     ErrPopUp(buf, "\nOk");
     fclose(fp);
-    return;
+    return FALSE;
   }
 
-  text = (char *) malloc((size_t) textlen);
+  text = (char *) malloc((size_t) textlen + 1);
   if (!text) {
     sprintf(buf, "Couldn't malloc %ld bytes to read file '%s'",
 	    textlen, rfname);
     ErrPopUp(buf, "\nSo what!");
     fclose(fp);
-    return;
+    return FALSE;
   }
 
   if (fread(text, (size_t) 1, (size_t) textlen, fp) != textlen) {
@@ -256,6 +447,9 @@
 	    rfname);
     ErrPopUp(buf, "\nHmm...");
   }
+#ifdef TV_MULTILINGUAL
+  text[textlen] = '\0';
+#endif
 
   fclose(fp);
 
@@ -263,6 +457,7 @@
   OpenTextView(text, (int) textlen, title, 1);
 
   /* note:  text gets freed when window gets closed */
+  return TRUE;
 }
 
 
@@ -504,6 +699,10 @@
   tv->text  = (char *) NULL;
   tv->lines = (char **) NULL;
   tv->numlines = tv->textlen = tv->hexmode = 0;
+
+#ifdef TV_MULTILINGUAL
+  closeCsWin(tv);
+#endif
 }
 
 
@@ -591,6 +790,40 @@
       else if (e->window == tv->textW) { }
       else rv = 0;
     }
+    else if (e->button == Button4) {   /* note min vs. max, + vs. - */
+      /* scroll regardless of where we are in the text window */
+      if (e->window == tv->win ||
+	 e->window == tv->vscrl.win ||
+	 e->window == tv->hscrl.win ||
+	 e->window == tv->textW)
+      {
+	SCRL *sp=&(tv->vscrl);
+	int  halfpage=sp->page/2;
+
+	if (sp->val > sp->min+halfpage)
+	  SCSetVal(sp,sp->val-halfpage);
+	else
+	  SCSetVal(sp,sp->min);
+      }
+      else rv = 0;
+    }
+    else if (e->button == Button5) {   /* note max vs. min, - vs. + */
+      /* scroll regardless of where we are in the text window */
+      if (e->window == tv->win ||
+	 e->window == tv->vscrl.win ||
+	 e->window == tv->hscrl.win ||
+	 e->window == tv->textW)
+      {
+	SCRL *sp=&(tv->vscrl);
+	int  halfpage=sp->page/2;
+
+	if (sp->val < sp->max-halfpage)
+	  SCSetVal(sp,sp->val+halfpage);
+	else
+	  SCSetVal(sp,sp->max);
+      }
+      else rv = 0;
+    }
     else rv = 0;
   }
 
@@ -633,7 +866,9 @@
   int        i, maxw, maxh;
   XSizeHints hints;
 
+#ifndef TV_MULTILINGUAL
   if (tv->wide == w && tv->high == h) return;  /* no change in size */
+#endif
 
   if (XGetNormalHints(theDisp, tv->win, &hints)) {
     hints.width  = w;
@@ -657,10 +892,23 @@
   XMoveResizeWindow(theDisp, tv->textW, LRMARGINS, TOPMARGIN,
 		    (u_int) tv->twWide, (u_int) tv->twHigh);
 
-  for (i=0; i<TV_NBUTTS; i++) {
-    tv->but[i].x = tv->wide - (TV_NBUTTS-i) * (BUTTW+5);
+  for (i=0; i<TV_E_NBUTTS; i++) {
+    tv->but[i].x = tv->wide - (TV_E_NBUTTS-i) * (BUTTW1+5);
     tv->but[i].y = tv->high - BUTTH - 5;
   }
+#ifdef TV_MULTILINGUAL
+  tv->csbut.x = 5;
+  tv->csbut.y = tv->high - BUTTH - 5;
+#endif
+
+#ifdef TV_L10N
+  if (xlocale) {
+    for (; i<TV_J_NBUTTS; i++) {
+      tv->but[i].x = 5 + (i-TV_E_NBUTTS) * (BUTTW2+5);
+      tv->but[i].y = tv->high - BUTTH - 5;
+    }
+  }
+#endif
 
   computeScrlVals(tv);
 
@@ -711,6 +959,29 @@
   case TV_CLOSE:   if (tv == &tinfo[CMTWIN]) CloseCommentText();
                    else closeText(tv);
                    break;
+
+#ifdef TV_L10N
+  case TV_RESCAN:
+    tv->code = selectCodeset(tv);
+    drawTextW(0, &tv->vscrl);
+    break;
+  case TV_USASCII:
+    tv->code = LOCALE_USASCII;
+    drawTextW(0, &tv->vscrl);
+    break;
+  case TV_JIS:
+    tv->code = LOCALE_JIS;
+    drawTextW(0, &tv->vscrl);
+    break;
+  case TV_EUCJ:
+    tv->code = LOCALE_EUCJ;
+    drawTextW(0, &tv->vscrl);
+    break;
+  case TV_MSCODE:
+    tv->code = LOCALE_MSCODE;
+    drawTextW(0, &tv->vscrl);
+    break;
+#endif	/* TV_L10N */
   }
 }
 
@@ -745,8 +1016,10 @@
   drawNumLines(tv);
 
   /* draw the buttons */
-  for (i=0; i<TV_NBUTTS; i++) BTRedraw(&(tv->but[i]));
-
+  for (i=0; i<nbutts; i++) BTRedraw(&(tv->but[i]));
+#ifdef TV_MULTILINGUAL
+  BTRedraw(&tv->csbut);
+#endif
   BTRedraw(&tv->nopBut);
 }
 
@@ -816,7 +1089,14 @@
      int   delta;
      SCRL *sptr;
 {
-  int     i, j, lnum, hpos, cpos, extrach, lwide;
+  int     i, j, lnum, hpos, vpos, cpos, lwide;
+#ifndef TV_MULTILINGUAL
+  int     extrach;
+#endif
+#ifdef TV_L10N
+  int     desig_stat;	/* for ISO 2022-JP */
+	      /* 0: ASCII,  1: JIS X 0208,  2: GL is JIS X 0201 kana */
+#endif
   TVINFO *tv;
   char    linestr[512];
   u_char  *sp, *ep, *lp;
@@ -839,12 +1119,38 @@
   XSetFont(theDisp, theGC, monofont);
 
   hpos = tv->hscrl.val;
+  vpos = tv->vscrl.val;
   lwide = (tv->chwide < 500) ? tv->chwide : 500;
 
   /* draw text */
   if (!tv->hexmode) {     /* ASCII mode */
+#ifdef TV_MULTILINGUAL
+    XClearArea(theDisp, tv->textW, 0, 0,
+	       (u_int) tv->twWide, (u_int) tv->twHigh, False);
+    if(tv->txt == NULL)
+      return;
+    else {
+	int i;
+	int y;
+	struct ml_text *tp = tv->txt;
+	struct ml_line *lp;
+
+	XSetFunction(theDisp, theGC, GXcopy);
+	XSetClipMask(theDisp, theGC, None);
+	y = 3;
+	for (lp = &tp->lines[vpos], i = tp->nlines - vpos;
+		i > 0; lp++, i--) {
+	    XDrawText16(theDisp, tv->textW, theGC,
+			-mfwide * hpos + 3, y + lp->ascent,
+			lp->items, lp->nitems);
+	    y += lp->ascent + lp->descent;
+	    if (y > tv->twHigh)
+		break;
+	}
+    }
+#else
     for (i=0; i<tv->chhigh; i++) {    /* draw each line */
-      lnum = i + tv->vscrl.val;
+      lnum = i + vpos;
       if (lnum < tv->numlines-1) {
 
 	/* find start of displayed portion of line.  This is *wildly*
@@ -865,7 +1171,13 @@
 	      cpos--;  sp++;
 	    }
 	    else if (*sp < 32) extrach = 1;
+
+#ifdef TV_L10N
+	    else if (!tv->code && *sp > 127) extrach = 3;
+#else
 	    else if (*sp > 127) extrach = 3;
+#endif
+
 	    else sp++;
 	  }
 	  else {
@@ -881,6 +1193,10 @@
 
 	/* build up the linestr buffer, which is the current line, padded
 	   with blanks to a width of exactly tv->chwide chars */
+#ifdef TV_L10N
+	desig_stat = 0;		/* for ISO 2022-JP */
+	      /* 0: ASCII,  1: JIS X 0208,  2: GL is JIS X 0201 kana */
+#endif
 	for (cpos=0, lp=(byte *) linestr; cpos<lwide; cpos++, lp++) {
 	  if (sp>=ep) *lp = ' ';
 	  else {
@@ -894,13 +1210,117 @@
 	      cpos--;  lp--;  sp++;
 	    }
 
+#ifdef TV_L10N
+	    else if (*sp < 32 && !(tv->code == LOCALE_JIS && *sp == 0x1b)) {
+#else
 	    else if (*sp < 32) {
+#endif
 	      if (!extrach) extrach = 2;
 	      if      (extrach == 2) *lp = '^';
 	      else if (extrach == 1) *lp = *sp + 64;
 	    }
 
+#ifdef TV_L10N
+	    /* convert to EUC-Japan */
+	    else if (tv->code == LOCALE_JIS) {
+	      if (*sp == 0x1b) {	/* ESC */
+		if (*(sp+1) == '$') {
+		  if (*(sp+2) == 'B' || *(sp+2) == 'A' || *(sp+2) == '@') {
+		    /* ESC $ B,  ESC $ A,  ESC $ @ */
+		    desig_stat = 1;
+		    sp += 3;  cpos--;  lp--;
+		  }
+		  else if (*(sp+2) == '(' && *(sp+3) == 'B') {
+		    /* ESC $ ( B */
+		    desig_stat = 1;
+		    sp += 4;  cpos--;  lp--;
+		  }
+		}
+		else if (*(sp+1) == '(') {
+		  if (*(sp+2) == 'B' || *(sp+2) == 'J' || *(sp+2) == 'H') {
+		    /* ESC ( B,  ESC ( J,  ESC ( H */
+		    desig_stat = 0;
+		    sp += 3;  cpos--;  lp--;
+		  }
+		  else if (*(sp+2) == 'I') {
+		    /* ESC ( I */
+		    desig_stat = 2;
+		    sp += 3;  cpos--;  lp--;
+		  }
+		}
+		else if (*(sp+1) == ')' && *(sp+2) == 'I') {
+		  /* ESC ) I */
+		  desig_stat = 2;
+		  sp += 3;  cpos--;  lp--;
+		}
+		else {	/* error */
+		  *lp = ' ';  sp++;
+		}
+	      }
+
+	      else {
+		switch (desig_stat) {
+		case 0:		/* ASCII */
+		  *lp = *sp++;
+		  break;
+		case 1:		/* JIS X 0208 */
+		  *lp++ = *sp++ | 0x80;
+		  *lp   = *sp++ | 0x80;
+		  cpos++;
+		  break;
+		case 2:		/* JIS X 0201 kana */
+#if defined(__osf__) && !defined(X_LOCALE)
+		  *lp   = '=';  sp++;
+#else
+		  *lp++ = 0x8e;	/* ^N | 0x80 */
+		  *lp   = *sp++ | 0x80;
+#endif
+		  break;
+		default:	/* error */
+		  *lp = *sp++;
+		  break;
+		}
+	      }
+	    }
+
+	    else if (tv->code == LOCALE_MSCODE) {
+	      if ((*sp >= 0x81 && *sp <= 0x9f)
+			 || (*sp >= 0xe0 && *sp <= 0xef)) {
+		static u_char c1, c2;
+
+/*fprintf(stderr, "(%x,%x)->", *sp, *(sp+1));*/
+		c1 = ((*sp - ((*sp>=0xe0) ? 0xb0 : 0x70)) << 1)
+			- ((*(sp+1)<=0x9e) ? 1 : 0);
+		c2 = *(sp+1);
+		if      (c2 >= 0x9f)  c2 -= 0x7e;	/* 0x9F - 0xFC */
+		else if (c2 >= 0x80)  c2 -= 0x20;	/* 0x80 - 0x9E */
+		else		      c2 -= 0x1f;	/* 0x40 - 0x7E */
+
+		*lp++ = c1 | 0x80;
+		*lp   = c2 | 0x80;
+		sp += 2;
+/*fprintf(stderr, "(%x %x) ", c1 | 0x80, c2 | 0x80);*/
+		cpos++;
+	      }
+
+	      else if (*sp >= 0xa1 && *sp <= 0xdf) {	/* JIS X 0201 kana */
+#if defined(__osf__) && !defined(X_LOCALE)
+		*lp   = '=';  sp++;
+#else
+		*lp++ = 0x8e;	/* ^N | 0x80 */
+		*lp   = *sp++;
+#endif
+	      }
+
+	      else *lp = *sp++;
+	    }
+#endif	/* TV_L10N */
+
+#ifdef TV_L10N
+	    else if (!tv->code && *sp > 127) {
+#else
 	    else if (*sp > 127) {
+#endif
 	      if (!extrach) extrach = 4;
 	      if      (extrach == 4) *lp = '\\';
 	      else if (extrach == 3) *lp = ((u_char)(*sp & 0700) >> 6) + '0';
@@ -916,6 +1336,9 @@
 	    }
 	  }
 	}
+#ifdef TV_L10N
+	*lp = '\0';	/* terminate linestr */
+#endif
       }
 
       else {  /* below bottom of file.  Just build a blank str */
@@ -923,15 +1346,22 @@
       }
 
       /* draw the line */
-      XDrawImageString(theDisp, tv->textW, theGC,
-		       3, i*mfhigh + 3 + mfascent, linestr, lwide);
+#ifdef TV_L10N
+      if (xlocale)
+	XmbDrawImageString(theDisp, tv->textW, monofset, theGC,
+		3, i*mfhigh + 1 + mfascent, linestr, strlen(linestr));
+      else
+#endif
+	XDrawImageString(theDisp, tv->textW, theGC,
+		3, i*mfhigh + 3 + mfascent, linestr, lwide);
     }  /* for i ... */
+#endif /* TV_MULTILINGUAL */
   }  /* if hexmode */
 
 
   else { /* HEX MODE */
     for (i=0; i<tv->chhigh; i++) {    /* draw each line */
-      lnum = i + tv->vscrl.val;
+      lnum = i + vpos;
       if (lnum < tv->hexlines) {
 
 	char hexstr[80], tmpstr[16];
@@ -957,7 +1387,11 @@
 
 	for (j=0; j<16; j++) {
 	  if (sp+j < ep) {
+#ifdef TV_L10N
+	    if (sp[j] >= 32 && (sp[j] <= 127 || tv->code)) *lp++ = sp[j];
+#else
 	    if (sp[j] >= 32 && sp[j] <= 127) *lp++ = sp[j];
+#endif
 	    else *lp++ = '.';
 	  }
 	  else *lp++ = ' ';
@@ -1005,14 +1439,21 @@
   int   i;
   BUTT *bp;
 
-  for (i=0, bp=tv->but; i<TV_NBUTTS; i++, bp++) {
+  for (i=0, bp=tv->but; i<nbutts; i++, bp++) {
     if (PTINRECT(x,y,bp->x,bp->y,bp->w,bp->h)) break;
   }
 
-  if (i<TV_NBUTTS) {
+  if (i<nbutts) {
     if (BTTrack(bp)) doCmd(tv, i);
     return;
   }
+
+#ifdef TV_MULTILINGUAL
+  if (PTINRECT(x, y, tv->csbut.x, tv->csbut.y, tv->csbut.w, tv->csbut.h)) {
+    if (BTTrack(&tv->csbut))
+      openCsWin(tv);
+  }
+#endif
 }
 
 
@@ -1042,13 +1483,38 @@
 
   /* keyboard equivalents */
   switch (buf[0]) {
-  case '\001': doCmd(tv, TV_ASCII);   break;      /* ^A = Ascii */
-  case '\010': doCmd(tv, TV_HEX);     break;      /* ^H = Hex   */
-
-  case '\033': doCmd(tv, TV_CLOSE);   break;      /* ESC = Close window */
+  case '\001':  case 'a':  case 'A':
+    doCmd(tv, TV_ASCII);   break;      /* ^A = Ascii */
+  case '\010':  case 'h':  case 'H':
+    doCmd(tv, TV_HEX);     break;      /* ^H = Hex   */
+
+  case '\021':  case 'q':  case 'Q':
+  case '\003':  case 'c':  case 'C':
+  case '\033':
+    doCmd(tv, TV_CLOSE);   break;      /* ESC = Close window */
 
   default:     break;
   }
+
+#ifdef TV_L10N
+  if (xlocale) {
+    switch (buf[0]) {
+    case '\022':  case 'r':  case 'R':
+      doCmd(tv, TV_RESCAN);   break;
+    case '\012':  case 'j':  case 'J':
+      doCmd(tv, TV_JIS);      break;
+    case '\005':  case 'e':  case 'E':
+    case '\025':  case 'u':  case 'U':
+      doCmd(tv, TV_EUCJ);     break;
+    case '\015':  case 'm':  case 'M':
+    case '\023':  case 's':  case 'S':
+      doCmd(tv, TV_MSCODE);  break;
+
+    default:  break;
+    }
+  }
+#endif	/* TV_L10N */
+
 }
 
 
@@ -1109,7 +1575,20 @@
     if (i<tv->numlines-1) SCSetVal(&tv->vscrl, i);
   }
 
+#ifdef TV_L10N
+  /* redraw text */
+  if (xlocale) {
+    XClearArea(theDisp, tv->textW, 0, 0,
+	       (u_int) tv->twWide, (u_int) tv->twHigh, False);
+
+    drawTextW(0, &tv->vscrl);
+  }
+#endif
+#ifdef TV_MULTILINGUAL
+  XClearArea(theDisp, tv->textW, 0, 0,
+	     (u_int) tv->twWide, (u_int) tv->twHigh, False);
   drawTextW(0, &tv->vscrl);
+#endif
 }
 
 
@@ -1122,9 +1601,22 @@
   int   i,j,wide,maxwide,space;
   byte *sp;
 
+#ifdef TV_L10N
+  /* select code-set */
+  if (xlocale)
+    tv->code = selectCodeset(tv);
+#endif	/* TV_L10N */
+
   if (!tv->text) {
     tv->numlines = tv->hexlines = 0;
     tv->lines = (char **) NULL;
+#ifdef TV_MULTILINGUAL
+    if (tv->cv_text != NULL) {
+	free(tv->cv_text);
+	tv->cv_text = NULL;
+    }
+    tv->txt = NULL;
+#endif
     return;
   }
 
@@ -1172,17 +1664,129 @@
 	wide += space;
       }
       else if (*sp <  32) wide += 2;
+#ifdef TV_L10N
+      else if (*sp > 127 && !tv->code) wide += 4;
+#else
       else if (*sp > 127) wide += 4;
+#endif
       else wide++;
     }
     if (wide > maxwide) maxwide = wide;
   }
   tv->maxwide = maxwide;
 
+#ifdef TV_MULTILINGUAL
+  ml_set_charsets(tv->ctx, &tv->ccs.coding_system);
+  if (tv->cv_text != NULL) {
+      free(tv->cv_text);
+      tv->cv_text = NULL;
+  }
+  if (tv->ccs.converter == NULL) {
+      tv->txt = ml_draw_text(tv->ctx, tv->text, tv->textlen);
+  } else {
+      tv->cv_text = (*tv->ccs.converter)(tv->text, tv->textlen, &tv->cv_len);
+      tv->txt = ml_draw_text(tv->ctx, tv->cv_text, tv->cv_len);
+  }
+  tv->maxwide = tv->txt->width / mfwide;
+  tv->numlines = tv->txt->height / mfhigh + 1;
+#endif
+
   tv->hexlines = (tv->textlen + 15) / 16;
 }
 
 
+/***************************************************/
+#ifdef TV_L10N
+static int selectCodeset(tv)
+     TVINFO *tv;
+{
+  u_char *sp;
+  int i, len;
+  int code = LOCALE_USASCII;	/* == 0 */
+
+
+  len = tv->textlen;
+
+  /* select code-set */
+  if (xlocale) {
+    sp = (u_char *) tv->text;  i = 0;
+    while (i < len - 1) {
+      if (*sp == 0x1b &&
+	  (*(sp+1) == '$' || *(sp+1) == '(' || *(sp+1) == ')')) {
+	code = LOCALE_JIS;
+	break;
+      }
+
+      else if (*sp >= 0xa1 && *sp <= 0xdf) {
+	if (*(sp+1) >= 0xf0 && *(sp+1) <= 0xfe) {
+	  code = LOCALE_EUCJ;
+	  break;
+	}
+#  if (LOCALE_DEFAULT == LOCALE_EUCJ)
+	else {
+	  sp++;  i++;
+	}
+#  endif
+      }
+
+      else if ((*sp >= 0x81 && *sp <= 0x9f) || (*sp >= 0xe0 && *sp <= 0xef)) {
+	if ((*(sp+1) >= 0x40 && *(sp+1) <= 0x7e) || *(sp+1) == 0x80) {
+	  code = LOCALE_MSCODE;
+	  break;
+	}
+	else if (*(sp+1) == 0xfd || *(sp+1) == 0xfe) {
+	  code = LOCALE_EUCJ;
+	  break;
+	}
+	else {
+	  sp++;  i++;
+	}
+      }
+
+      else if (*sp >= 0xf0 && *sp <= 0xfe) {
+	code = LOCALE_EUCJ;
+	break;
+      }
+
+      sp++;  i++;
+    }
+    if (!code)  code = LOCALE_DEFAULT;
+  }
+
+  return code;
+}
+#endif	/* TV_L10N */
+
+#ifdef TV_MULTILINGUAL
+static void setCodingSpec(tv, cs)
+    TVINFO *tv;
+    struct coding_spec *cs;
+{
+  if (xvbcmp((char *) &tv->ccs, (char *) cs, sizeof *cs) == 0)
+    return;
+
+  tv->ccs = *cs;
+#if 0
+  ml_set_charsets(tv->ctx, &tv->ccs.coding_system);
+  if (tv->cv_text != NULL) {
+      free(tv->cv_text);
+      tv->cv_text = NULL;
+  }
+  if (tv->ccs.converter == NULL) {
+      tv->txt = ml_draw_text(tv->ctx, tv->text, tv->textlen);
+  } else {
+      tv->cv_text = (*tv->ccs.converter)(tv->text, tv->textlen, &tv->cv_len);
+      tv->txt = ml_draw_text(tv->ctx, tv->cv_text, tv->cv_len);
+  }
+#else
+  computeText(tv);
+  computeScrlVals(tv);
+#endif
+  /* drawTextW(0, &tv->vscrl); */
+}
+#endif
+
+
 /**********************************************************************/
 /* BUILT-IN TEXT FILES ************************************************/
 /**********************************************************************/
@@ -1555,8 +2159,509 @@
   OpenTextView(keyhelp, (int) strlen(keyhelp), "XV Help", 0);
 }
 
+#ifdef TV_MULTILINGUAL
+
+#define TV_ML_ACCEPT TV_NCSS
+#define TV_ML_CLOSE  (TV_ML_ACCEPT + 1)
+#define TV_ML_NBUTTS (TV_ML_CLOSE + 1)
+
+#define TV_ML_RETCODE	0
+#	define TV_ML_RET_LF	0
+#	define TV_ML_RET_CRLF	1
+#	define TV_ML_RET_CR	2
+#	define TV_ML_RET_ANY	3
+#define TV_ML_GL	1
+#define TV_ML_GR	2
+#define TV_ML_CVTR	3
+#define TV_ML_NRBUTTS	4
+
+#define TV_ML_SHORT	0
+#define TV_ML_LOCK	1
+#define TV_ML_NCBUTTS	2
+
+#define TV_ML_NLISTS	4
+
+#define CSWIDE (BUTTW3 * 5 + 5 * 6)
+#define CSHIGH 450
+
+typedef struct csinfo_t {
+    TVINFO *tv;
+    RBUTT *rbt[TV_ML_NRBUTTS];
+    CBUTT cbt[TV_ML_NCBUTTS];
+    LIST ls[TV_ML_NLISTS];
+    BUTT bt[TV_ML_NBUTTS];
+    int up;
+    Window win;
+    struct coding_spec tcs;	/* temporary coding_spec */
+} CSINFO;
+CSINFO csinfo[MAXTVWIN];
+static char **regs;
+static int nregs;
+
+static int  csCheckEvent           PARM((CSINFO *, XEvent *));
+static void csReflect              PARM((CSINFO *));
+static void csRedraw               PARM((CSINFO *));
+static void csListRedraw           PARM((LIST *));
+static void csLsRedraw             PARM((int, SCRL *));
+static void create_registry_list   PARM((void));
+
+static char *(*cvtrtab[])PARM((char *, int, int *)) = {
+    NULL,
+    sjis_to_jis,
+};
+
+static void createCsWins(geom)
+    char *geom;
+{
+    XSetWindowAttributes xswa;
+    int i, j;
+
+    create_registry_list();
+
+    xswa.backing_store = WhenMapped;
+    for (i = 0; i < MAXTVWIN; i++) {
+	char nam[8];
+	TVINFO *tv = &tinfo[i];
+	CSINFO *cs = &csinfo[i];
+	tv->cs = cs;
+	cs->tv = tv;
+	sprintf(nam, "XVcs%d", i);
+	cs->win = CreateWindow("xv codeset", nam, geom,
+			       CSWIDE, CSHIGH, infofg, infobg, 0);
+	if (!cs->win) FatalError("couldn't create 'charset' window!");
+#ifdef BACKING_STORE
+	XChangeWindowAttributes(theDisp, cs->win, CWBackingStore, &xswa);
+#endif
+	XSelectInput(theDisp, cs->win, ExposureMask | ButtonPressMask);
+
+	DrawString(cs->win, 5, 5 + ASCENT, "Initial States");
+	for (i = 0; i < TV_ML_NLISTS; i++) {
+	    int x, y;
+	    char buf[80];
+
+	    if (i / 2 == 0)
+		x = 15;
+	    else
+		x = 280;
+	    if (i % 2 == 0)
+		y = 5 + LINEHIGH * 1;
+	    else
+		y = 5 + LINEHIGH * 7 + SPACING * 3;
+
+	    sprintf(buf, "Designation for G%d:", i + 1);
+	    DrawString(cs->win, x, y + ASCENT, buf);
+
+	    LSCreate(&cs->ls[i], cs->win, x + 15, y + LINEHIGH,
+			200, LINEHIGH * 5, 5,
+			regs, nregs + 2,
+			infofg, infobg, hicol, locol, csLsRedraw, 0, 0);
+	    cs->ls[i].selected = 0;
+	}
+
+	for (i = 0; i < 2; i++) {
+	    char *p;
+	    int n;
+	    int x, y;
+
+	    if ((p = (char *) malloc(3 * 4)) == NULL)
+		FatalError("out of memory in createCsWins().");
+	    strcpy(p, "G1 G2 G3 G4");
+	    p[2] = p[5] = p[8] = '\0';
+	    n = (i == 0 ? TV_ML_GL : TV_ML_GR);
+	    x = (i == 0 ? 15 : 280);
+	    y = 235;
+	    DrawString(cs->win, x, y + ASCENT, "Assignment for GL:");
+	    x += 15;
+	    y += LINEHIGH;
+	    cs->rbt[n] = RBCreate(NULL, cs->win,
+				  x, y, p, infofg, infobg, hicol, locol);
+	    for (j = 1; j < 4; j++) {
+		p += 3;
+		x += 50;
+		RBCreate(cs->rbt[n], cs->win,
+			 x, y, p, infofg, infobg, hicol, locol);
+	    }
+	}
+
+	DrawString(cs->win, 5, 280 + ASCENT, "Ret Code:");
+	cs->rbt[TV_ML_RETCODE] =
+	    RBCreate(NULL, cs->win, 20, 300, "LF", infofg,infobg, hicol,locol);
+	RBCreate(cs->rbt[TV_ML_RETCODE], cs->win, 20, 300 + 20, "CR+LF",
+		 infofg, infobg, hicol, locol);
+	RBCreate(cs->rbt[TV_ML_RETCODE], cs->win, 90, 300, "CR",
+		 infofg, infobg, hicol, locol);
+	RBCreate(cs->rbt[TV_ML_RETCODE], cs->win, 90, 300 + 20, "Any",
+		 infofg, infobg, hicol, locol);
+
+	DrawString(cs->win, 350, 280 + ASCENT, "Converter:");
+	cs->rbt[TV_ML_CVTR] =
+	    RBCreate(NULL, cs->win, 365, 300, "Nothing",
+		     infofg, infobg, hicol, locol);
+	RBCreate(cs->rbt[TV_ML_CVTR], cs->win, 365, 300 + 20, "Shift JIS",
+		 infofg, infobg, hicol, locol);
+
+	CBCreate(&cs->cbt[TV_ML_SHORT], cs->win, 200, 300, "Short Form",
+		 infofg, infobg, hicol, locol);
+	CBCreate(&cs->cbt[TV_ML_LOCK], cs->win, 200, 320, "Locking Shift",
+		 infofg, infobg, hicol, locol);
+
+	for (j = 0; j < TV_NCSS; j++) {
+	    BTCreate(&cs->bt[j], cs->win,
+		     5 + (BUTTW3 + 5) * (j % 5),
+		     350 + 5 + (BUTTH + 5) * (j / 5),
+		     BUTTW3, BUTTH, codeSetNames[j],
+		     infofg, infobg, hicol, locol);
+	}
+	BTCreate(&cs->bt[TV_ML_ACCEPT], cs->win,
+		 CSWIDE - 10 - BUTTW3 * 2, CSHIGH - 5 - BUTTH, BUTTW3, BUTTH,
+		 "Accept", infofg, infobg, hicol, locol);
+	BTCreate(&cs->bt[TV_ML_CLOSE], cs->win,
+		 CSWIDE - 5 - BUTTW3, CSHIGH - 5 - BUTTH, BUTTW3, BUTTH,
+		 "Close", infofg, infobg, hicol, locol);
 
+	XMapSubwindows(theDisp, cs->win);
+	cs->up = 0;
+    }
+}
 
+static void openCsWin(tv)
+    TVINFO *tv;
+{
+    CSINFO *cs = tv->cs;
+    if (cs->up)
+	return;
 
+    XMapRaised(theDisp, cs->win);
+    cs->up = 1;
+    cs->tcs = cs->tv->ccs;
+    csReflect(cs);
+}
 
+static void closeCsWin(tv)
+    TVINFO *tv;
+{
+    CSINFO *cs = tv->cs;
+    if (!cs->up)
+	return;
+    cs->up = 0;
+    XUnmapWindow(theDisp, cs->win);
+}
+
+int CharsetCheckEvent(xev)
+    XEvent *xev;
+{
+    int i;
+    CSINFO *cs;
+
+    for (cs = csinfo, i = 0; i < MAXTVWIN; cs++, i++) {
+	if (!cs->up)
+	    continue;
+	if (csCheckEvent(cs, xev))
+	    break;
+    }
+    if (i < MAXTVWIN)
+	return 1;
+    return 0;
+}
+
+static int csCheckEvent(cs, xev)
+    CSINFO *cs;
+    XEvent *xev;
+{
+    RBUTT **rbp;
+    CBUTT *cbp;
+    LIST *ls;
+    BUTT *bp;
+    int i, n;
+
+    if (xev->type == Expose) {
+	int x, y, w, h;
+	XExposeEvent *e = (XExposeEvent *) xev;
+	x = e->x; y = e->y; w = e->width; h = e->height;
+
+	if (cs->win == e->window){
+	    csRedraw(cs);
+	    return 1;
+	} else {
+	    for (i = 0; i < TV_ML_NLISTS; i++) {
+		if (cs->ls[i].win == e->window) {
+		    LSRedraw(&cs->ls[i], 0);
+		    return 1;
+		}
+	    }
+	   for (i = 0; i < TV_ML_NLISTS; i++) {
+		if (cs->ls[i].scrl.win == e->window) {
+		    SCRedraw(&cs->ls[i].scrl);
+		    return 1;
+		}
+	   }
+	}
+    } else if (xev->type == ButtonPress) {
+	int x, y;
+	XButtonEvent *e = (XButtonEvent *) xev;
+	x = e->x; y = e->y;
+	if (cs->win == e->window) {
+	    for (bp = cs->bt, i = 0; i < TV_ML_NBUTTS; bp++, i++) {
+		if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h))
+		    break;
+	    }
+	    if (i < TV_ML_NBUTTS) {
+		if (BTTrack(bp)) {
+		    if (i < TV_NCSS) {
+			cs->tcs = coding_spec[i];
+			csReflect(cs);
+		    } else {
+			switch (i) {
+			case TV_ML_ACCEPT:
+			    setCodingSpec(cs->tv, &cs->tcs);
+			    break;
+			case TV_ML_CLOSE:
+			    closeCsWin(cs->tv);
+			    break;
+			}
+		    }
+		}
+		return 1;
+	    }
+	    for (cbp = cs->cbt, i = 0; i < TV_ML_NCBUTTS; cbp++, i++) {
+		if (CBClick(cbp, x, y) && CBTrack(cbp))
+		    break;
+	    }
+	    if (i < TV_ML_NCBUTTS) {
+		switch (i) {
+		case TV_ML_SHORT:
+		    cs->tcs.coding_system.short_form = cbp->val;
+		    break;
+		case TV_ML_LOCK:
+		    cs->tcs.coding_system.lock_shift = cbp->val;
+		    break;
+		}
+		return 1;
+	    }
+	    for (rbp = cs->rbt, i = 0; i < TV_ML_NRBUTTS; rbp++, i++) {
+		if ((n = RBClick(*rbp, x, y)) >= 0 && RBTrack(*rbp, n)) {
+		    break;
+		}
+	    }
+	    if (i < TV_ML_NRBUTTS) {
+		switch (i) {
+		case TV_ML_RETCODE:
+		    cs->tcs.coding_system.eol = n;
+		    break;
+		case TV_ML_GL:
+		    cs->tcs.coding_system.gl = n;
+		    break;
+		case TV_ML_GR:
+		    cs->tcs.coding_system.gr = n;
+		    break;
+		case TV_ML_CVTR:
+		    cs->tcs.converter = cvtrtab[n];
+		    break;
+		}
+		return 1;
+	    }
+	} else {
+	    for (ls = cs->ls, i = 0; i < TV_ML_NLISTS; ls++, i++) {
+		if (ls->win == e->window) {
+		    LSClick(ls, e);
+		    n = ls->selected;
+		    if (n < nregs) {
+			char r[32], *p = r;
+			int b7;
+			strcpy(r, regs[n]);
+			if ((p = strrchr(r, '/')) != NULL) {
+			    *p = '\0';
+			    b7 = (*(p + 1) == 'R' ? 1 : 0);
+			} else
+			    b7 = 0;	/* shouldn't occur */
+			cs->tcs.coding_system.design[i] = lookup_design(r, b7);
+		    } else if (n == nregs)    /* initially none is designed. */
+			cs->tcs.coding_system.design[i].bpc = 0;
+		    else
+			cs->tcs.coding_system.design[i].bpc = -1;
+		    return 1;
+		}
+	    }
+	    for (ls = cs->ls, i = 0; i < TV_ML_NLISTS; ls++, i++) {
+		if (ls->scrl.win == e->window) {
+		    SCTrack(&ls->scrl, x, y);
+		    return 1;
+		}
+	    }
+	}
+    }
+    return 0;
+}
+
+static void csReflect(cs)
+    CSINFO *cs;
+{
+    int i;
+
+    RBSelect(cs->rbt[TV_ML_RETCODE], cs->tcs.coding_system.eol);
+    RBSelect(cs->rbt[TV_ML_GL], cs->tcs.coding_system.gl);
+    RBSelect(cs->rbt[TV_ML_GR], cs->tcs.coding_system.gr);
+    for (i = 0; i < sizeof cvtrtab / sizeof cvtrtab[0]; i++) {
+	if (cs->tcs.converter == cvtrtab[i])
+	    break;
+    }
+    if (i >= sizeof cvtrtab / sizeof cvtrtab[0])
+	FatalError("program error in csReflect().");
+    RBSelect(cs->rbt[TV_ML_CVTR], i);
+
+    cs->cbt[TV_ML_SHORT].val = cs->tcs.coding_system.short_form;
+    cs->cbt[TV_ML_LOCK].val = cs->tcs.coding_system.lock_shift;
+    for (i = 0; i < TV_ML_NLISTS; i++) {
+	struct design design = cs->tcs.coding_system.design[i];
+	char *reg, r[32];
+	int b7;
+	int n = 0;
+	switch (design.bpc) {
+	case -1:
+	    n = nregs + 1;
+	    break;
+	case 0:
+	    n = nregs;
+	    break;
+	case 1:
+	case 2:
+	    if ((reg = lookup_registry(design, &b7)) == NULL)
+		FatalError("internal error in csReflect.");
+	    sprintf(r, "%s/%s", reg, b7 ? "Right" : "Left");
+	    for (n = 0; n < nregs; n++) {
+		if (strcmp(regs[n], r) == 0)
+		    break;
+	    }
+	}
+	cs->ls[i].selected = n;
+	ScrollToCurrent(&cs->ls[i]);
+    }
+    csRedraw(cs);
+    for (i = 0; i < TV_ML_NLISTS; i++)
+	csListRedraw(&cs->ls[i]);
+}
+
+static void csRedraw(cs)
+    CSINFO *cs;
+{
+    int i;
+
+    XSetForeground(theDisp, theGC, infofg);
+    DrawString(cs->win,  5,5 + ASCENT, "Initial States");
+    for (i = 0; i < TV_ML_NLISTS; i++) {
+	int x, y;
+	char buf[80];
+
+	if (i / 2 == 0)
+	    x = 15;
+	else
+	    x = 280;
+	if (i % 2 == 0)
+	    y = 5 + LINEHIGH * 1;
+	else
+	    y = 5 + LINEHIGH * 7 + SPACING * 3;
+
+	sprintf(buf, "Designation for G%d:", i);
+	DrawString(cs->win, x, y + ASCENT, buf);
+    }
+
+    DrawString(cs->win,  15, 235 + ASCENT, "Invocation for GL:");
+    DrawString(cs->win, 280, 235 + ASCENT, "Invocation for GR:");
+    DrawString(cs->win,   5, 280 + ASCENT, "Ret Code:");
+    DrawString(cs->win, 350, 280 + ASCENT, "Converter:");
+
+    for (i = 0; i < TV_ML_NBUTTS; i++)
+	BTRedraw(&cs->bt[i]);
+    for (i = 0; i < TV_ML_NCBUTTS; i++)
+	CBRedraw(&cs->cbt[i]);
+    for (i = 0; i < TV_ML_NRBUTTS; i++)
+	RBRedraw(cs->rbt[i], -1);
+}
+
+static void csListRedraw(ls)
+    LIST *ls;
+{
+    int i;
+    for (i = 0; i < TV_ML_NLISTS; i++) {
+	LSRedraw(ls, 0);
+	SCRedraw(&ls->scrl);
+    }
+}
+
+static void csLsRedraw(delta, sptr)
+    int delta;
+    SCRL *sptr;
+{
+    int i, j;
+    for (i = 0; i < MAXTVWIN; i++) {
+	for (j = 0; j < TV_ML_NLISTS; j++) {
+	    if (sptr == &csinfo[i].ls[j].scrl) {
+		LSRedraw(&csinfo[i].ls[j], delta);
+		return;
+	    }
+	}
+    }
+}
+
+int CharsetDelWin(win)
+    Window win;
+{
+    CSINFO *cs;
+    int i;
+
+    for (cs = csinfo, i = 0; i < TV_NCSS; cs++, i++) {
+	if (cs->win == win) {
+	    if (cs->up) {
+		XUnmapWindow(theDisp, cs->win);
+		cs->up = 0;
+	    }
+	    return 1;
+	}
+    }
+    return 0;
+}
+
+static int reg_comp PARM((const void *, const void *));
+static void create_registry_list()
+{
+    struct design d;
+    char *names, *p;
+    int i;
+
+    if ((p = names = (char *) malloc(32 * 0x80 * 2 * 2)) == NULL)
+	FatalError("out of memory in create_name_list#1.");
+    nregs = 0;
+    for (d.bpc = 1; d.bpc <=2; d.bpc++) {
+	for (d.noc = 94; d.noc <= 96; d.noc += 2) {
+	    for (d.des = ' '; (unsigned char) d.des < 0x80; d.des++) {
+		int b7;
+		char *r;
+		if ((r = lookup_registry(d, &b7)) != NULL) {
+		    sprintf(p, "%s/%s", r, b7 ? "Right" : "Left");
+		    p += strlen(p) + 1;
+		    nregs++;
+		}
+	    }
+	}
+    }
+    if ((names = (char *) realloc(names, (size_t) (p - names))) == NULL)
+	FatalError("out of memory in create_name_list#2.");
+    if ((regs = (char **) malloc(sizeof(char *) * (nregs + 3))) == NULL)
+	FatalError("out of memory in create_name_list#3.");
+    p = names;
+    for (i = 0; i < nregs; i++) {
+	regs[i] = p;
+	p += strlen(p) + 1;
+    }
+    qsort(regs, (size_t) nregs, sizeof(char *), reg_comp);
+    regs[i++] = "nothing";
+    regs[i++] = "unused";
+    regs[i++] = NULL;
+}
+static int reg_comp(dst, src)
+    const void *dst, *src;
+{
+    return strcmp(*(char **) dst, *(char **) src);
+}
 
+#endif /* TV_MULTILINGUAL */
diff -ruN xv-3.10a-bugfixes/xvtiff.c xv-3.10a-enhancements/xvtiff.c
--- xv-3.10a-bugfixes/xvtiff.c	2005-03-27 17:25:31.000000000 -0800
+++ xv-3.10a-enhancements/xvtiff.c	2005-04-17 14:11:55.000000000 -0700
@@ -512,7 +512,7 @@
   vsprintf(cp, fmt, ap);
   strcat(cp, ".");
 
-  SetISTR(ISTR_WARNING,buf);
+  SetISTR(ISTR_WARNING, "%s", buf);
 
   error_occurred = 1;
 }
@@ -536,7 +536,7 @@
   vsprintf(cp, fmt, ap);
   strcat(cp, ".");
 
-  SetISTR(ISTR_WARNING,buf);
+  SetISTR(ISTR_WARNING, "%s", buf);
 }
 
 
@@ -564,6 +564,10 @@
 static	byte **BWmap;
 static	byte **PALmap;
 
+/* XXXX Work around some collisions with the new library. */
+#define tileContigRoutine _tileContigRoutine
+#define tileSeparateRoutine _tileSeparateRoutine
+
 typedef void (*tileContigRoutine)   PARM((byte*, u_char*, RGBvalue*,
 					  uint32, uint32, int, int));
 
@@ -603,7 +607,7 @@
 					     uint32, uint32, int, int));
 static void   put4bitbwtile            PARM((byte *, u_char *, RGBvalue *,
 					     uint32, uint32, int, int));
-static void   put16bitbwtile           PARM((byte *, u_char *, RGBvalue *,
+static void   put16bitbwtile           PARM((byte *, u_short *, RGBvalue *,
 					     uint32, uint32, int, int));
 
 static void   putRGBcontig8bittile     PARM((byte *, u_char *, RGBvalue *,
@@ -653,7 +657,7 @@
 
   default:
     TIFFError(TIFFFileName(tif),
-	      "Sorry, can not handle %d-bit pictures", bitspersample);
+	      "Sorry, cannot handle %d-bit pictures", bitspersample);
     return (0);
   }
 
@@ -666,7 +670,7 @@
 
   default:
     TIFFError(TIFFFileName(tif),
-	      "Sorry, can not handle %d-channel images", samplesperpixel);
+	      "Sorry, cannot handle %d-channel images", samplesperpixel);
     return (0);
   }
 
@@ -1157,7 +1161,7 @@
   b = g + stripsize;
   put = pickTileSeparateCase(Map);
   if (put == 0) {
-    TIFFError(filename, "Can not handle format");
+    TIFFError(filename, "Cannot handle format");
     return (0);
   }
   y = setorientation(tif, h);
@@ -1197,7 +1201,7 @@
 /*
  * Greyscale images with less than 8 bits/sample are handled
  * with a table to avoid lots of shifts and masks.  The table
- * is setup so that put*bwtile (below) can retrieve 8/bitspersample
+ * is set up so that put*bwtile (below) can retrieve 8/bitspersample
  * pixel values simply by indexing into the table with one
  * number.
  */
@@ -1249,11 +1253,11 @@
 
 
 /*
- * Palette images with <= 8 bits/sample are handled
- * with a table to avoid lots of shifts and masks.  The table
- * is setup so that put*cmaptile (below) can retrieve 8/bitspersample
- * pixel values simply by indexing into the table with one
- * number.
+ * Palette images with <= 8 bits/sample are handled with
+ * a table to avoid lots of shifts and masks.  The table
+ * is set up so that put*cmaptile (below) can retrieve
+ * (8/bitspersample) pixel-values simply by indexing into
+ * the table with one number.
  */
 static int makecmap()
 {
@@ -1305,7 +1309,7 @@
 /*
  * The following routines move decoded data returned
  * from the TIFF library into rasters filled with packed
- * ABGR pixels (i.e. suitable for passing to lrecwrite.)
+ * ABGR pixels (i.e., suitable for passing to lrecwrite.)
  *
  * The routines have been created according to the most
  * important cases and optimized.  pickTileContigCase and
@@ -1376,7 +1380,7 @@
      int fromskew, toskew;
 {
   while (h-- > 0) {
-    UNROLL8(w, , *cp++ = PALmap[*pp++][0])
+    UNROLL8(w, , *cp++ = PALmap[*pp++][0]);
     cp += toskew;
     pp += fromskew;
   }
@@ -1529,7 +1533,7 @@
  */
 static void put16bitbwtile(cp, pp, Map, w, h, fromskew, toskew)
      byte  *cp;
-     u_char *pp;
+     u_short *pp;
      RGBvalue *Map;
      uint32 w, h;
      int fromskew, toskew;
@@ -1538,8 +1542,7 @@
 
   while (h-- > 0) {
     for (x=w; x>0; x--) {
-      *cp++ = Map[(pp[0] << 8) + pp[1]];
-      pp += 2;
+      *cp++ = Map[*pp++];
     }
     cp += toskew;
     pp += fromskew;
@@ -1577,7 +1580,7 @@
 	      *cp++ = pp[0];
 	      *cp++ = pp[1];
 	      *cp++ = pp[2];
-	      pp += samplesperpixel)
+	      pp += samplesperpixel);
       cp += toskew;
       pp += fromskew;
     }
@@ -1650,7 +1653,7 @@
 	      *cp++ = *r++;
 	      *cp++ = *g++;
 	      *cp++ = *b++;
-	      )
+	      );
       SKEW(r, g, b, fromskew);
       cp += toskew;
     }
@@ -1857,7 +1860,7 @@
   case PHOTOMETRIC_MINISWHITE:
   case PHOTOMETRIC_MINISBLACK:
     switch (bitspersample) {
-    case 16: put = put16bitbwtile; break;
+    case 16: put = (tileContigRoutine) put16bitbwtile; break;
     case 8:  put = putgreytile;    break;
     case 4:  put = put4bitbwtile;  break;
     case 2:  put = put2bitbwtile;  break;
@@ -1872,7 +1875,7 @@
     break;
   }
 
-  if (put==0) TIFFError(filename, "Can not handle format");
+  if (put==0) TIFFError(filename, "Cannot handle format");
   return (put);
 }
 
@@ -1880,8 +1883,8 @@
 /*
  * Select the appropriate conversion routine for unpacked data.
  *
- * NB: we assume that unpacked single channel data is directed
- *	 to the "packed routines.
+ * NB: we assume that unpacked single-channel data is directed
+ *	 to the "packed" routines.
  */
 static tileSeparateRoutine pickTileSeparateCase(Map)
      RGBvalue* Map;
@@ -1897,10 +1900,32 @@
     break;
   }
 
-  if (put==0) TIFFError(filename, "Can not handle format");
+  if (put==0) TIFFError(filename, "Cannot handle format");
   return (put);
 }
 
 
 
+/*******************************************/
+void
+VersionInfoTIFF()      /* GRR 19980605 */
+{
+  char temp[1024], *p, *q;
+
+  strcpy(temp, TIFFGetVersion());
+  p = temp;
+  while (!isdigit(*p))
+    ++p;
+  if ((q = strchr(p, '\n')) != NULL)
+    *q = '\0';
+
+  fprintf(stderr, "   Compiled with libtiff %s", p);
+#ifdef TIFFLIB_VERSION
+  fprintf(stderr, " of %d", TIFFLIB_VERSION);    /* e.g., 19960307 */
+#endif
+  fprintf(stderr, ".\n");
+}
+
+
+
 #endif /* HAVE_TIFF */
diff -ruN xv-3.10a-bugfixes/xvtiffwr.c xv-3.10a-enhancements/xvtiffwr.c
--- xv-3.10a-bugfixes/xvtiffwr.c	2005-03-28 08:39:52.000000000 -0800
+++ xv-3.10a-enhancements/xvtiffwr.c	2005-04-17 14:45:28.000000000 -0700
@@ -86,6 +86,9 @@
       TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS,
 	  GROUP3OPT_2DENCODING+GROUP3OPT_FILLBITS);
 
+  if (comp == COMPRESSION_LZW)
+      TIFFSetField(tif, TIFFTAG_PREDICTOR, 2);
+
   TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
   TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
   TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
diff -ruN xv-3.10a-bugfixes/xvvd.c xv-3.10a-enhancements/xvvd.c
--- xv-3.10a-bugfixes/xvvd.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvvd.c	2005-04-17 22:56:02.000000000 -0700
@@ -0,0 +1,1101 @@
+
+/*
+ * xvvd.c - extract archived file automatically and regard it as a
+ *          (virtual) directory.
+ */
+
+#define NEEDSDIR
+
+#include "xv.h"
+
+#ifdef AUTO_EXPAND
+
+static void  vd_Dirtovd    		PARM((char *));
+static void  vd_Vdtodir    		PARM((char *));
+static int   vd_Mkvdir    		PARM((char *));
+static int   vd_Rmvdir     		PARM((char *));
+static int   vd_Movevdir  		PARM((char *, char *));
+static void  vd_addvdtable		PARM((char *));
+static void  vd_packvdtable		PARM((void));
+static int   vd_recursive_mkdir		PARM((char *));
+static int   vd_recursive_rmdir		PARM((char *));
+static void  vd_optimize_path		PARM((char *));
+static int   vd_ftype			PARM((char *));
+static int   vd_compp			PARM((char *, char *));
+static int   vd_UncompressFile		PARM((char *, char *));
+static int   vd_tarc			PARM((char *));
+static u_int vd_tar_sumchk		PARM((char *));
+
+#define VD_VDTABLESIZE	100
+
+#define VD_ERR -2
+#define VD_UKN -1
+
+static char *ext_command[] = {
+/* KEEP 0 */
+    NULL,
+#define VD_ARC 1
+    "arc xo %s",
+#define VD_ARJ 2
+    "unarj x %s",
+#define VD_LZH 3
+    "lha -xf %s",
+#define VD_TAR 4
+    "tar xvf %s",
+#define VD_ZIP 5
+    "unzip -xo %s",
+#define VD_ZOO 6
+    "zoo xOS %s",
+};
+
+int vdcount = 0;
+
+static char vdroot[MAXPATHLEN+1];
+static char *vdtable[VD_VDTABLESIZE];
+
+/*
+ * These functions initialize and settle virtual directory system.
+ * Vdinit:
+ *	creates root of virtual directory.
+ * Vdsettle:
+ *	sweeps virtual directories.
+ */
+void Vdinit()
+{
+#ifndef VMS
+    char tmp[MAXPATHLEN+1];
+
+    xv_getwd(tmp, MAXPATHLEN+1);
+    if (chdir(tmpdir)) {
+	fprintf(stderr, "Warning: cannot chdir to tmpdir = '%s'.\n", tmpdir);
+	fprintf(stderr,
+		"         I will use current directory '%s' instead of tmpdir.\n",
+		tmp);
+    }
+    xv_getwd(vdroot, MAXPATHLEN+1);
+    strcat(vdroot, "/.xvvdXXXXXX");
+    chdir(tmp);
+#else
+    sprintf(vdroot, "Sys$Scratch:xvvdXXXXXX");
+#endif /* VMS */
+#ifdef USE_MKSTEMP
+    close(mkstemp(vdroot));
+#else
+    mktemp(vdroot);
+#endif
+
+    if (!vd_recursive_mkdir(vdroot))
+	tmpdir = vdroot;
+}
+
+void Vdsettle()
+{
+    int i;
+
+    for (i = 0; i < vdcount; i++)
+	free(vdtable[i]);
+
+    vdcount = 0;
+
+    vd_recursive_rmdir(vdroot);
+}
+
+/*
+ * This function chdir to virtual directory, if specified path is in
+ * virtual directlry.
+ */
+int Chvdir(dir)
+char *dir;
+{
+    char buf[MAXPATHLEN+1];
+
+    if (Mkvdir(dir) == VD_ERR)
+	return -1;
+
+    strcpy(buf, dir);
+    Dirtovd(buf);
+
+    return (chdir(buf));
+}
+
+/*
+ * These functions convert directory <-> virtual directory.
+ * Dirtovd:
+ *	front interface of vd_Dirtovd.
+ * vd_Dirtovd:
+ *	converts directory to virtual directory.
+ * Vdtodir:
+ *	front interface of vd_Vdtodir.
+ * vd_Vdtodir:
+ *	converts virtual directory to normal directory.
+ * Dirtosubst:
+ *	converts directory to substance of archive.
+ */
+void Dirtovd(dir)
+char *dir;
+{
+    vd_optimize_path(dir);
+
+    vd_Dirtovd(dir);
+}
+
+static void vd_Dirtovd(dir)
+char *dir;
+{
+    int i;
+
+    for (i = 0; i < vdcount; i++)
+	if (!strncmp(dir, vdtable[i], strlen(vdtable[i]))) {
+	    char tmp[MAXPATHLEN+1];
+
+	    sprintf(tmp, "%s%s", vdroot, dir);
+	    strcpy(dir, tmp);
+	    Dirtovd(dir);
+	}
+}
+
+void Vdtodir(dir)
+char *dir;
+{
+    vd_optimize_path(dir);
+
+    vd_Vdtodir(dir);
+}
+
+static void vd_Vdtodir(vd)
+char *vd;
+{
+    int i;
+    char tmp[MAXPATHLEN+1];
+
+    for (i = vdcount-1; i >= 0; i--) {
+	sprintf(tmp, "%s%s", vdroot, vdtable[i]);
+	if(!strncmp(vd, tmp, strlen(tmp))) {
+	    strcpy(tmp, vd+strlen(vdroot));
+	    strcpy(vd, tmp);
+	    Vdtodir(vd);
+	}
+    }
+}
+
+void Dirtosubst(dir)
+char *dir;
+{
+    char tmp[MAXPATHLEN+1];
+
+    Dirtovd(dir);
+
+    strcpy(tmp, dir+strlen(vdroot));
+
+    if (Isarchive(tmp))
+	strcpy(dir, tmp);
+}
+
+/*
+ * These functions make virtual directory and extracts archive, if
+ * specified path is archive.
+ * Mkvdir:
+ *	front interface of vd_Mkvdir.
+ * vd_Mkvdir:
+ *	does real work.
+ * Mkvdir_force: (used by makeThumbDir(in xvbrowse.c) only)
+ *	make virtual directory by force.
+ */
+int Mkvdir(dir)
+char *dir;
+{
+    char dir1[MAXPATHLEN+1], dir2[MAXPATHLEN+1];
+    char *d1, *d2;
+    int rv;
+
+#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
+    sighold(SIGHUP);
+    sighold(SIGCHLD);
+#else
+    int mask;
+    mask = sigblock(sigmask(SIGHUP)|sigmask(SIGCHLD));
+#endif
+
+    strcpy(dir1, dir);
+    vd_optimize_path(dir1);
+
+    if ((rv = vd_Mkvdir(dir1)) != VD_ERR)
+	goto MKVDIR_END;
+
+    strcpy(dir2, dir1);
+    d2 = dir2 + strlen(dir2);
+    while (rv == VD_ERR) {
+	d2--;
+	while (*d2 != '/')
+	    d2--;
+	*d2 = '\0';
+	rv = vd_Mkvdir(dir2);
+    }
+    d1 = dir1 + strlen(dir2);
+    while ((rv != VD_ERR) && (*d1 != '\0')) {
+	*d2++ = *d1++;
+	while ((*d1 != '/') && (*d1 != '\0'))
+	    *d2++ = *d1++;
+	*d2 = '\0';
+	rv = vd_Mkvdir(dir2);
+    }
+
+MKVDIR_END:
+#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
+    sigrelse(SIGHUP);
+    sigrelse(SIGCHLD);
+#else
+    sigsetmask(mask);
+#endif
+
+    return rv;
+}
+
+static int vd_Mkvdir(dir)
+char *dir;
+{
+    char dir1[MAXPATHLEN+1], dir2[MAXPATHLEN+1], tmp[MAXPATHLEN+1];
+    int ftype, i;
+    struct stat st;
+    FILE *pfp;
+
+    strcpy(dir1, dir);
+    Dirtovd(dir1);
+    strcpy(dir2, dir1);
+
+    WaitCursor();
+
+    if ((ftype = vd_ftype(dir1)) < 0) {
+	SetCursors(-1);
+	return ftype;
+    }
+    if (ftype == RFT_COMPRESS) {
+	if (!(ftype = vd_compp(dir1, tmp))) {
+	    SetCursors(-1);
+	    return ftype;
+	}
+	strcpy(dir1, tmp);
+    }
+
+    if (!stat(dir1, &st)) {
+	for(i = 0; i < vdcount; i++)
+	    if (!strcmp(vdtable[i], dir2)) {
+		SetCursors(-1);
+		return 0;
+	    }
+
+	if (!S_ISDIR(st.st_mode)) {
+	    char origdir[MAXPATHLEN+1], buf[MAXPATHLEN+10], buf1[100];
+
+	    if (vdcount >= VD_VDTABLESIZE) {
+		ErrPopUp("Sorry, you can't make virtual directory any more.",
+			 "\nBummer!");
+		goto VD_MKVDIR_ERR;
+	    }
+
+	    WaitCursor();
+
+	    xv_getwd(origdir, MAXPATHLEN+1);
+
+	    sprintf(tmp, "%s%s", vdroot, dir2);
+	    if (vd_recursive_mkdir(tmp) || chdir(tmp)) {
+		SetISTR(ISTR_INFO, "fail to make virtual directory.");
+		Warning();
+		goto VD_MKVDIR_ERR;
+	    }
+	    sprintf(buf, ext_command[ftype], dir1);
+
+	    WaitCursor();
+
+	    if((pfp = popen(buf, "r")) == NULL) {
+		SetISTR(ISTR_INFO, "fail to extract archive '%s'.",
+			BaseName(dir2));
+		Warning();
+		goto VD_MKVDIR_ERR;
+	    }
+	    while (1) {
+		if (fread(buf1, 1, sizeof(buf1), pfp) < sizeof(buf1))
+		    break;
+		WaitCursor();
+	    }
+	    if (!feof(pfp)) {
+		SetISTR(ISTR_INFO, "Pipe was broken.");
+		Warning();
+		pclose(pfp);
+		goto VD_MKVDIR_ERR;
+	    }
+	    pclose(pfp);
+
+	    if (strcmp(dir1, dir2))
+		unlink(dir1);
+
+	    vd_addvdtable(dir2);
+	    Dirtovd(origdir);
+	    chdir(origdir);
+	    SetCursors(-1);
+	    return 0;
+
+VD_MKVDIR_ERR:
+	    if (strcmp(dir1, dir2))
+		unlink(dir1);
+	    SetCursors(-1);
+	    return VD_ERR;
+	}
+    }
+    SetCursors(-1);
+    return VD_ERR;
+}
+
+#ifdef VIRTUAL_TD
+void Mkvdir_force(dir)
+char *dir;
+{
+    char tmp[MAXPATHLEN+1];
+
+    if (vdcount >= VD_VDTABLESIZE) {
+      ErrPopUp("Sorry, you can't make virtual directory any more.",
+	       "\nBummer!");
+      return;
+    }
+
+    sprintf(tmp, "%s%s", vdroot, dir);
+    if (vd_recursive_mkdir(tmp)) {
+      SetISTR(ISTR_INFO, "Failed to make virtual directory.");
+      Warning();
+      return;
+    }
+
+    vd_addvdtable(dir);
+}
+#endif /* VIRTUAL_TD */
+
+/*
+ * These functions remove virtual directory, if exists.
+ * Rmvdir:
+ *	front interface of vd_Rmvdir.
+ * vd_Rmvdir:
+ *	remove virtual directory function.
+ */
+int Rmvdir(dir)
+char *dir;
+{
+    int rv;
+    char buf[MAXPATHLEN+1];
+
+    strcpy(buf, dir);
+    vd_optimize_path(buf);
+
+    rv = vd_Rmvdir(buf);
+    vd_packvdtable();
+    return rv;
+}
+
+static int vd_Rmvdir(dir)
+char *dir;
+{
+    int i;
+    char tmp[MAXPATHLEN+1];
+
+    for(i = 0; i < vdcount; i++)
+	if (!strncmp(dir, vdtable[i], strlen(dir))) {
+	    sprintf(tmp, "%s%s", vdroot, vdtable[i]);
+	    if (vd_Rmvdir(tmp))
+		return 1;
+	    if (vd_recursive_rmdir(tmp))
+		return 1;
+	    vdtable[i][0] = '\0';
+	}
+    return 0;
+}
+
+/*
+ * These functions move virtual directory, if exists.
+ * Movevdir:
+ *	front interface of move virtual directory function.
+ * vd_Movevdir:
+ *	does real work.
+ */
+int Movevdir(src, dst)
+char *src, *dst;
+{
+/*
+    char sbuf[MAXPATHLEN+1], dbuf[MAXPATHLEN+1];
+
+    strcpy(sbuf, src);
+    vd_optimize_path(sbuf);
+
+    strcpy(dbuf, dst);
+    vd_optimize_path(dbuf);
+
+    return (vd_Movevdir(sbuf, dbuf));
+*/
+    return (vd_Movevdir(src, dst));
+}
+
+static int vd_Movevdir(src, dst)
+char *src, *dst;
+{
+    int i;
+    char *p, *pp;
+    char tmp[MAXPATHLEN+1], tmps[MAXPATHLEN+1], tmpd[MAXPATHLEN+1];
+
+    for (i = 0; i < vdcount; i++)
+	if (!strncmp(src, vdtable[i], strlen(src))) {
+	    sprintf(tmps, "%s%s", vdroot, vdtable[i]);
+	    sprintf(tmp, "%s%s", dst, vdtable[i]+strlen(src));
+	    sprintf(tmpd, "%s%s", vdroot, tmp);
+
+	    if (vd_Movevdir(tmps, tmpd))
+		return 1;
+
+	    pp = vdtable[i];
+	    p = (char *) malloc(strlen(tmp)+1);
+	    strcpy(p, tmp);
+	    vdtable[i] = p;
+
+	    strcpy(tmp, tmpd);
+	    for (p = tmp+strlen(tmp); *p != '/'; p--)
+		;
+	    *p = '\0';
+
+	    if (vd_recursive_mkdir(tmp))
+		goto VD_MOVEVDIR_ERR;
+
+	    if (rename(tmps, tmpd) < 0)
+		goto VD_MOVEVDIR_ERR;
+
+	    free(pp);
+	}
+    return 0;
+
+VD_MOVEVDIR_ERR:
+    free(vdtable[i]);
+    vdtable[i] = pp;
+    return 1;
+}
+
+/*
+ * These functions handle table of virtual directories.
+ * vd_addvdtable:
+ *	adds virtual directory to table.
+ * vd_packvdtable:
+ *	removes disused virtual directories from table.
+ */
+static void vd_addvdtable(vd)
+char *vd;
+{
+    char *p;
+    p = (char *) malloc(strlen(vd)+1);
+    strcpy(p, vd);
+    vdtable[vdcount] = p;
+    vdcount++;
+}
+
+static void vd_packvdtable()
+{
+    int i, j;
+
+    for (i = j = 0; i < vdcount; i++)
+	if (vdtable[i][0] != '\0')
+	    vdtable[j++] = vdtable[i];
+	else
+	    free(vdtable[i]);
+
+    vdcount = j;
+}
+
+/*
+ * These are utility functions.
+ * vd_recursive_mkdir:
+ *	makes directories recursively.
+ * vd_recursive_rmdir
+ *	removes directories recursively.
+ */
+static int vd_recursive_mkdir(dir)
+char *dir;
+{
+    char buf[MAXPATHLEN+1], *p;
+    struct stat st;
+
+    strcpy(buf, dir);
+
+    if (buf[strlen(buf) - 1] == '/')
+	buf[strlen(buf) - 1] = '\0';
+
+    p = rindex(buf, '/');
+    *p = '\0';
+
+    if (stat(buf, &st) < 0)
+	if (vd_recursive_mkdir(buf) < 0)
+	    return (-1);
+
+    *p = '/';
+    if (mkdir(buf, 0700) < 0)
+	return (-1);
+
+    return (0);
+}
+
+static int vd_recursive_rmdir(dir)
+char *dir;
+{
+    char buf[MAXPATHLEN+1], buf2[MAXPATHLEN+1];
+    DIR *dp;
+    struct dirent *di;
+
+    strcpy(buf, dir);
+
+    if (buf[strlen(buf) - 1] == '/')
+	buf[strlen(buf) - 1] = '\0';
+
+    if ((dp = opendir(buf)) == NULL)
+	return (-1);
+
+    while ((di = readdir(dp)) != NULL) {
+	struct stat st;
+
+	if (!strcmp(di->d_name, ".") || !strcmp(di->d_name, ".."))
+	    continue;
+
+	sprintf(buf2, "%s/%s", dir, di->d_name);
+
+	stat(buf2, &st);
+	if (S_ISDIR(st.st_mode)) {
+	    if (vd_recursive_rmdir(buf2) < 0)
+		goto VD_RECURSIVE_RMDIR_ERR;
+	} else
+	    unlink(buf2);
+    }
+    if (rmdir(buf) < 0)
+	goto VD_RECURSIVE_RMDIR_ERR;
+
+    closedir(dp);
+    return (0);
+
+VD_RECURSIVE_RMDIR_ERR:
+    closedir(dp);
+    return (-1);
+}
+
+/*
+ * These functions test specified path.
+ * Isarchive:
+ *	tests whether it's an archive?
+ * Isvdir:
+ *	tests whether it's in the virtual directory?
+ */
+int Isarchive(path)
+char *path;
+{
+    int ftype;
+
+    if ((ftype = vd_ftype(path)) < 0)
+	return 0;
+
+    if (ftype == RFT_COMPRESS)
+	if (!(ftype = vd_compp(path, NULL)))
+	    return 0;
+
+    return ftype;
+}
+
+int Isvdir(path)
+char *path;
+{
+    int rv = 0;
+    char tmp1[MAXPATHLEN+1], tmp2[MAXPATHLEN+1];
+    int archive1, archive2;
+
+    strcpy(tmp1, path);
+    strcpy(tmp2, path);
+
+    vd_optimize_path(tmp1);
+    Dirtovd(tmp2);
+
+    archive1 = Isarchive(tmp1);
+    archive2 = Isarchive(tmp2);
+
+    if (strcmp(tmp1, tmp2)) {
+	char tmp3[MAXPATHLEN+1], tmp4[MAXPATHLEN+1];
+	int archive3, archive4;
+
+	sprintf(tmp3, "%s%s", vdroot, tmp1);
+	strcpy(tmp4, tmp2+strlen(vdroot));
+
+	archive3 = Isarchive(tmp3);
+	archive4 = Isarchive(tmp4);
+
+	if (archive4 && !strcmp(tmp1, tmp4)) {
+	    rv |= 06;
+	    return rv;
+	}
+	rv |= 01;
+	if (archive2)
+	    rv |= 02;
+	else if (archive4)
+	    rv |= 06;
+	return rv;
+    }
+    if (archive1)
+	rv |= 02;
+
+    return rv;
+}
+
+/*
+ * This function optimizes given path.
+ * Expand '~' to home directory and removes '.', and treat '..'.
+ */
+static void vd_optimize_path(path)
+char *path;
+{
+    char *tmp, *reserve;
+
+    if (!strcmp(path, STDINSTR))
+	return;
+
+    if (*path == '\0') {
+	xv_getwd(path, MAXPATHLEN+1);
+	return;
+    }
+    if (*path == '~')
+	Globify(path);
+    if (*path != '/') {
+	char tmp[MAXPATHLEN+1];
+
+	strcpy(tmp, path);
+	xv_getwd(path, MAXPATHLEN+1);
+	strcat(path, "/");
+	strcat(path, tmp);
+    }
+
+    reserve = tmp = path;
+    while(*path != '\0') {
+	if (*path == '/') {
+	    *tmp++ = *path;
+	    while (*++path == '/')
+		;
+	    continue;
+	}
+	if ((*path == '.') && (*(path-1) == '/')) {
+	    if (*(path+1) == '/') {
+		tmp--;
+		path++;
+		continue;
+	    } else if (*(path+1) == '\0') {
+		tmp--;
+		break;
+	    } else if (*(path+1) == '.') {
+		if (*(path+2) == '/') {
+		    if ((tmp - reserve) > 1)
+			for (tmp-=2; (*tmp != '/'); tmp--)
+			    ;
+		    else
+			tmp = reserve;
+		    path+=2;
+		    continue;
+		} else if (*(path+2) == '\0') {
+		    if ((tmp - reserve) > 1)
+			for (tmp-=2; (*tmp != '/'); tmp--)
+			    ;
+		    else
+			tmp = reserve+1;
+		    break;
+		}
+	    }
+	}
+	*tmp++ = *path++;
+    }
+    if (((tmp - reserve) > 1) && *(tmp-1) == '/')
+	tmp--;
+    if (tmp == reserve)
+	*tmp++ = '/';
+
+    *tmp = '\0';
+}
+
+/*
+ * These functions detect file type.
+ */
+static int vd_ftype(fname)
+char *fname;
+{
+    /* check archive type */
+
+    FILE *fp;
+    byte  magicno[30];    /* first 30 bytes of file */
+    int   rv, n;
+    struct stat st;
+
+    if (!fname) return VD_ERR;   /* shouldn't happen */
+
+    if ((!stat(fname, &st)) && (st.st_mode & S_IFMT) == S_IFDIR)
+	return VD_UKN;
+    fp = xv_fopen(fname, "r");
+    if (!fp) return VD_ERR;
+
+    n = fread(magicno, (size_t) 1, (size_t) 30, fp);
+    fclose(fp);
+
+    if (n<30) return VD_UKN;    /* files less than 30 bytes long... */
+
+    rv = VD_UKN;
+
+    if (magicno[0] == 0x60 && magicno[1]==0xea) rv = VD_ARJ;
+
+    else if (magicno[2] == '-' && magicno[3] == 'l' &&
+	     magicno[4] == 'h') rv = VD_LZH;
+
+    else if (strncmp((char *) magicno,"PK", (size_t) 2)==0) rv = VD_ZIP;
+
+    else if (magicno[20]==0xdc && magicno[21]==0xa7 &&
+	     magicno[22]==0xc4 && magicno[23]==0xfd) rv = VD_ZOO;
+
+    else if (vd_tarc(fname)) rv = VD_TAR;
+
+    else if (magicno[0]==0x1f && magicno[1]==0x9d) rv = RFT_COMPRESS;
+
+    else if (!strncmp((char *) &magicno[11], "MAJYO", (size_t) 5))
+	     rv = VD_UKN; /* XXX */
+
+    else if (magicno[0] == 26) rv = VD_ARC;
+
+#ifdef GUNZIP
+    else if (magicno[0]==0x1f && magicno[1]==0x8b) rv = RFT_COMPRESS;/* gzip */
+    else if (magicno[0]==0x1f && magicno[1]==0x9e) rv = RFT_COMPRESS;/*  old */
+    else if (magicno[0]==0x1f && magicno[1]==0x1e) rv = RFT_COMPRESS;/* pack */
+#endif
+
+    return rv;
+}
+
+static int vd_compp(path, newpath)
+char *path, *newpath;
+{
+    /*
+     * uncompress and check archive type.
+     *
+     * If newpath is NULL, uncompress only 512 byte of 'path' and
+     * check archive type, so it is for SPEED-UP strategy.
+     * In this case, caller this function does not have to unlink
+     * tempoary file.
+     * Unfortunately it does not work in VMS system.
+     */
+
+    int file_type, r;
+    char uncompname[128], basename[128];
+    int comptype;
+
+    if (newpath) *newpath = '\0';
+    strncpy(basename, path, 127);
+    comptype = ReadFileType(path);
+#if (defined(VMS) && !defined(GUNZIP))
+    /* VMS decompress doesn't like the file to have a trailing .Z in fname
+    however, GUnZip is OK with it, which we are calling UnCompress */
+    *rindex (basename, '.') = '\0';
+#endif
+#ifdef VMS
+    if (UncompressFile(basename, uncompname)) {
+#else
+    if (newpath == NULL)
+	r = vd_UncompressFile(basename, uncompname);
+    else
+	r = UncompressFile(basename, uncompname, comptype);
+    if (r) {
+#endif
+	if ((file_type = vd_ftype(uncompname)) < 0) {
+	    unlink(uncompname);
+	    return 0;
+	}
+	if (newpath) strcpy(newpath, uncompname);
+	else unlink(uncompname);
+    } else {
+	return 0;
+    }
+    return file_type;
+}
+
+#define HEADERSIZE 512
+
+static void  vd_Dirtovd    		PARM((char *));
+static int   stderr_on			PARM((void));
+static int   stderr_off			PARM((void));
+static FILE  *popen_nul			PARM((char *, char *));
+
+static int vd_UncompressFile(name, uncompname)
+char *name, *uncompname;
+{
+    /* Yap, I`m nearly same as original `UncompnameFile' function, but,
+       1) I extract `name' file ONLY first 512 byte.
+       2) I'm called only from UNIX and UNIX like OS, *NOT* VMS */
+    /* returns '1' on success, with name of uncompressed file in uncompname
+       returns '0' on failure */
+
+    char namez[128], *fname, buf[512], tmp[HEADERSIZE];
+    int n, tmpfd;
+    FILE *pfp, *tfp;
+
+    fname = name;
+    namez[0] = '\0';
+
+
+#ifndef GUNZIP
+    /* see if compressed file name ends with '.Z'.  If it *doesn't*, we need
+       to temporarily rename it so it *does*, uncompress it, and rename it
+       *back* to what it was.  necessary because uncompress doesn't handle
+       files that don't end with '.Z' */
+
+    if (strlen(name) >= (size_t) 2            &&
+	strcmp(name + strlen(name)-2,".Z")!=0 &&
+	strcmp(name + strlen(name)-2,".z")!=0) {
+	strcpy(namez, name);
+	strcat(namez,".Z");
+
+	if (rename(name, namez) < 0) {
+	    sprintf(buf, "Error renaming '%s' to '%s':  %s",
+		    name, namez, ERRSTR(errno));
+	    ErrPopUp(buf, "\nBummer!");
+	    return 0;
+	}
+
+	fname = namez;
+    }
+#endif   /* not GUNZIP */
+
+    sprintf(uncompname, "%s/xvuXXXXXX", tmpdir);
+#ifdef USE_MKSTEMP
+    tmpfd = mkstemp(uncompname);
+#else
+    mktemp(uncompname);
+#endif
+
+    sprintf(buf,"%s -c %s", UNCOMPRESS, fname);
+    SetISTR(ISTR_INFO, "Uncompressing Header '%s'...", BaseName(fname));
+    if ((pfp = popen_nul(buf, "r")) == NULL) {
+	SetISTR(ISTR_INFO, "Cannot extract for archive '%s'.",
+		BaseName(fname));
+	Warning();
+#ifdef USE_MKSTEMP
+	if (tmpfd >= 0)
+	    close(tmpfd);
+#endif
+	return 0;
+    }
+#ifdef USE_MKSTEMP
+    if (tmpfd < 0)
+#else
+    if ((tmpfd = open(uncompname,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR)) < 0)
+#endif
+    {
+	SetISTR(ISTR_INFO, "Unable to create temporary file.",
+		BaseName(uncompname));
+	Warning();
+	pclose(pfp);
+    }
+    if ((tfp = fdopen(tmpfd, "w")) == NULL) {
+	SetISTR(ISTR_INFO, "Unable to create temporary file.",
+		BaseName(uncompname));
+	Warning();
+	close(tmpfd);
+	pclose(pfp);
+	return 0;
+    }
+    if ((n = fread(tmp, 1, sizeof(tmp), pfp)) != HEADERSIZE) {
+	SetISTR(ISTR_INFO, "Unable to read '%s'.",
+		BaseName(fname));
+	Warning();
+	pclose(pfp);
+	fflush(tfp);
+	fclose(tfp);
+	close(tmpfd);
+	return 0;
+    }
+    fwrite(tmp, 1, n, tfp);
+    fflush(tfp);
+    fclose(tfp);
+    close(tmpfd);
+    pclose(pfp);
+
+    /* if we renamed the file to end with a .Z for the sake of 'uncompress',
+       rename it back to what it once was... */
+
+    if (strlen(namez)) {
+	if (rename(namez, name) < 0) {
+	    sprintf(buf, "Error renaming '%s' to '%s':  %s",
+		    namez, name, ERRSTR(errno));
+	    ErrPopUp(buf, "\nBummer!");
+	}
+    }
+
+    return 1;
+}
+
+#define TARBLOCK 512
+#define CKSTART 148 /* XXX */
+#define CKSIZE 8
+
+/*
+ * Tar file: 1, other: 0
+ */
+static int vd_tarc(fname)
+char *fname;
+{
+    FILE *fp;
+    unsigned int sum;
+    char *ckp, buf[TARBLOCK];
+
+    if ((fp = fopen(fname, "r")) == NULL)
+	return 0;
+
+    fread(buf, TARBLOCK, 1, fp);
+    fclose(fp);
+
+    for (sum = 0, ckp = buf + CKSTART;
+	 (ckp < buf + CKSTART + CKSIZE) && *ckp != '\0';
+	 ckp++) {
+	sum *= 8;
+	if (*ckp == ' ')
+	    continue;
+	if (*ckp < '0' || '7' < *ckp)
+	    return 0;
+	sum += *ckp - '0';
+    }
+    if (sum != vd_tar_sumchk(buf))
+	return 0;
+
+    return 1;
+}
+
+static unsigned int vd_tar_sumchk(buf)
+char *buf;
+{
+    int i;
+    unsigned int sum = 0;
+
+    for (i = 0; i < CKSTART; i++) {
+	sum += *(buf + i);
+    }
+    sum += ' ' * 8;
+    for (i += 8; i < TARBLOCK; i++) {
+	sum += *(buf + i);
+    }
+    return sum;
+}
+
+
+static int stde = -1;        /*  fd of stderr    */
+static int nul = -1;         /*  fd of /dev/null */
+
+/*
+ * switch off the output to stderr(bypass to /dev/null).
+ */
+static int stderr_off()
+{
+    if (nul < 0)
+      nul = open("/dev/null", O_RDONLY);
+    if (nul < 0) {
+	fprintf(stderr, "/dev/null open failure\n");
+	return -1;
+    }
+    if (stde < 0)
+	stde = dup(2);
+    if (stde < 0) {
+	fprintf(stderr, "duplicate stderr failure\n");
+	return -1;
+    }
+    close(2);
+    dup(nul);
+    return 0;
+}
+
+/*
+ * turn on stderr output.
+ */
+static int stderr_on()
+{
+    if ((stde < 0) || (nul < 0)) {
+	fprintf(stderr, "stderr_on should call after stderr_off\n");
+	return -1;
+    }
+    close(2);
+    dup(stde);
+    return 0;
+}
+
+/*
+ * popen with no output to stderr.
+ */
+static FILE *popen_nul(prog, mode)
+char *prog, *mode;
+{
+    FILE *fp;
+
+    stderr_off();
+    fp = popen(prog, mode);
+    stderr_on();
+    return fp;
+}
+
+/*
+ * These functions are for SIGNAL.
+ * If XV end by C-c, there are dust of directory which name is .xvvd???,
+ * made by xvvd. Then, I handle SIGINT, and add good finish.
+ */
+void vd_HUPhandler()
+{
+#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
+    sighold(SIGHUP);
+#else
+    int mask;
+    mask = sigblock(sigmask(SIGHUP));
+#endif
+
+  Vdsettle();
+
+#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
+    sigrelse(SIGHUP);
+    signal(SIGHUP, (void (*)PARM((int))) vd_HUPhandler);
+#else
+    sigsetmask(mask);
+#endif
+}
+
+void vd_handler(sig)
+int sig;
+{
+#if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
+    sighold(sig);
+#else
+    sigblock(sigmask(sig));
+#endif
+
+    Quit(1); /*exit(1);*/
+}
+
+int vd_Xhandler(disp,event)
+Display *disp;
+XErrorEvent *event;
+{
+    Quit(1); /*exit(1);*/
+    return (1); /* Not reached */
+}
+
+int vd_XIOhandler(disp)
+Display *disp;
+{
+    fprintf(stderr, "XIO  fatal IO error ? (?) on X server\n");
+    fprintf(stderr, "You must exit normally in xv usage.\n");
+    Quit(1); /*exit(1);*/
+    return (1); /* Not reached */
+}
+
+void vd_handler_setup()
+{
+    signal(SIGHUP, (void (*)PARM((int))) vd_HUPhandler);
+    signal(SIGINT, (void (*)PARM((int))) vd_handler);
+    signal(SIGTERM,(void (*)PARM((int))) vd_handler);
+
+    (void)XSetErrorHandler(vd_Xhandler);
+    (void)XSetIOErrorHandler(vd_XIOhandler);
+}
+#endif /* AUTO_EXPAND */
diff -ruN xv-3.10a-bugfixes/xvwbmp.c xv-3.10a-enhancements/xvwbmp.c
--- xv-3.10a-bugfixes/xvwbmp.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvwbmp.c	2005-04-03 14:02:18.000000000 -0700
@@ -0,0 +1,323 @@
+/*
+ * xvwbmp.c - i/o routings for WBMP files
+ * defined by OMA (http://www.openmobilealliance.com)
+ * as a standard for images for micro devices.
+ *
+ * exports :
+ *
+ * LoadWBMP(fname, numcols);
+ * WriteWBMP(fp, pic, ptype, w, h, r, g, b, numcols, style);
+ *
+ * author: Pawel S. Veselov <vps@manticore.2y.net>
+ *	      http://manticore.2y.net/
+ *
+ */
+
+#include "xv.h"
+
+typedef	short int16;
+typedef unsigned char uint8;
+typedef	unsigned short uint16;	/* sizeof (uint16) must == 2 */
+#if defined(__alpha) || _MIPS_SZLONG == 64
+typedef	int int32;
+typedef	unsigned int uint32;	/* sizeof (uint32) must == 4 */
+#else
+typedef	long int32;
+typedef	unsigned long uint32;	/* sizeof (uint32) must == 4 */
+#endif
+
+#define MUST(a)	            if (!(a)) {\
+				return fail(st_fname, st_err);\
+				close(fd); \
+			    }
+#define READU8(fd,u)	    if ((read(fd, &u, 1)<1)) {\
+				myfree(); \
+				close(fd); \
+				return fail(st_fname, err_ueof); }
+#define SREADU8(fd, u)	    if ((read(fd, &u, 1,)<1)) {\
+				{ st_err = err_ueof; return 0; }
+
+#define SREADC(fd, str, l)  {	\
+    str = (char*)mymalloc(l);	\
+    if (!str) {			\
+	myfree();		\
+	FatalError("LoadWBMP: can't malloc extension buffer");	\
+    }				\
+    if (read(fd, str, l)<l) {	\
+	st_err = err_ueof;	\
+	return 0;		\
+    }
+
+static char * err_ueof = "Unexpected EOF";
+static char * err_unst = "Unsupported image type";
+static char * err_extf = "Extensions are forbidden";
+static char * err_inmb = "Invalid multibyte integer";
+
+static char * st_fname;
+static char * st_err;
+
+static int fail	    PARM((char *, char *));
+static int read_mb  PARM((int *, int));
+static void write_mb PARM((uint32, FILE *));
+static int read_ext PARM((int, uint8));
+static void * mymalloc PARM((int));
+static void myfree   PARM((void));
+static uint8 * render1 PARM((uint8 *, int, int));
+
+void ** mymem = NULL;
+int mymems = 0;
+
+int LoadWBMP(char * fname, PICINFO * pinfo)
+{
+    int fd;
+    int im_type;	/* image type (only type 0 supported) */
+    uint8 fix_header;	/* fixed header field */
+    int width, height;
+    int npixels, raw_size, aux;
+    uint8 * raw;
+
+    st_fname = fname;
+
+    fd = open(fname, O_RDONLY);
+    if (fd < 0) {
+	return fail(fname, "Couldn't open the file");
+    }
+
+    MUST(read_mb(&im_type, fd));
+    if (im_type) {
+	return fail(fname, err_unst);
+    }
+
+    READU8(fd, fix_header);
+
+    MUST(read_ext(fd, fix_header));
+
+    MUST(read_mb(&width, fd));
+    MUST(read_mb(&height, fd));
+
+    npixels = width * height;
+    raw_size = (npixels+7) / 8;
+    if (width <= 0 || height <= 0 || npixels/width != height ||
+        npixels+7 < npixels)
+    {
+	return fail(fname, "image dimensions out of range");
+    }
+
+    raw = mymalloc(raw_size);
+    if (!raw) {
+	myfree();
+	FatalError("LoadWBMP: can't malloc image buffer");
+    }
+
+    aux = read(fd, raw, raw_size);
+    if (aux < raw_size) {
+	fail(fname, "Image size shrank");
+	raw_size = aux;
+    }
+
+    pinfo->r[0] = 0;
+    pinfo->g[0] = 0;
+    pinfo->b[0] = 0;
+    pinfo->r[1] = 255;
+    pinfo->g[1] = 255;
+    pinfo->b[1] = 255;
+
+    pinfo->pic = render1(raw, raw_size, npixels);
+    pinfo->type = PIC8;
+
+    pinfo->w = pinfo->normw = width;
+    pinfo->h = pinfo->normh = height;
+    pinfo->frmType = F_BWDITHER;
+
+    sprintf(pinfo->fullInfo, "WBMP, 1 bit per pixel, %d bytes", raw_size);
+    sprintf(pinfo->shrtInfo, "%dx%d WBMP (WAP/OMA).", width, height);
+    pinfo->comment = (char*)NULL;
+
+    close(fd);
+
+    myfree();
+    return 1;
+}
+
+int WriteWBMP(FILE * fp, byte * pic, int ptype, int w, int h,
+	byte * rmap, byte *gmap, byte *bmap,
+	int numcols, int colorstyle)
+{
+    int count = 0;
+    uint8 bit = 0;
+    int i;
+
+    write_mb(0, fp);	/* type : always 0 */
+    putc(0, fp);	/* fixed header : always 0 for type 0 */
+    write_mb((uint32)w, fp);
+    write_mb((uint32)h, fp);
+
+    /* ready to write data */
+
+    for (i=0; i<w*h; i++) {
+	bit |= (((pic[i]&1)<<(7-(count++))));
+	if (count == 8) {
+	    putc(bit, fp);
+	    count = 0;
+	}
+    }
+
+    if (!count) {
+	putc(bit, fp);
+    }
+
+    return 0;
+}
+
+int fail(char * name, char * msg)
+{
+    SetISTR(ISTR_WARNING, "%s : %s", name, msg);
+    return 0;
+}
+
+void write_mb(uint32 data, FILE * f)
+{
+    int i = 32;
+    uint32 aux = data;
+    int no;
+
+    if (!aux) {
+	i = 1;
+    } else {
+	while (!(aux & 0x80000000)) {
+	    aux <<= 1;
+	    i--;
+	}
+    }
+
+    /* i tells us how many bits are left to encode */
+
+    no = (i / 7 + ((i % 7)?1:0))-1;
+
+    /*
+    fprintf(stderr, "writing %x, bits to write=%d, passes=%d\n",
+	    data, i, no);
+    */
+
+    do {
+	uint8 value = no?0x80:0x0;
+	value |= ((data >> (no*7)) & 0x7f);
+	putc(value, f);
+    } while ((no--)>0);
+
+}
+
+int read_mb(int * dst, int fd)
+{
+    int ac = 0;
+    int ct = 0;
+
+    while (1) {
+	uint8 bt;
+	if ((ct++)==6) {
+	    st_err = err_inmb;
+	    return 0;
+	}
+
+	if ((read(fd, &bt, 1)) < 1) {
+	    st_err = err_ueof;
+	    return 0;
+	}
+	ac = (ac << 7) | (bt & 0x7f);   /* accumulates up to 42 bits?? FIXME */
+	if (!(bt & 0x80))
+	    break;
+    }
+    *dst = ac;
+    return 1;
+}
+
+int read_ext(int fd, uint8 fixed)
+{
+    if (!(fixed&0x7f)) {    /* no extensions */
+	return 1;
+    }
+
+    /*
+     * The only described type is WBMP 0, that must not
+     * have extensions.
+     */
+
+    st_err = err_extf;
+    return 0;
+
+    /*
+
+    fixed = (fixed >> 5)&0x3;
+
+    switch (fixed) {
+    case 0:
+	while (true) {
+	    SREADU8(fd, fixed);
+	    if (!(fixed & 0x7f)) { break; }
+	}
+	break;
+    case 0x3:
+	{
+	    char * par;
+	    char * val;
+	    SREADU8(fd, fixed);
+	    SREADC(fd, par, (fixed>>4)&0x6);
+	    SREADC(fd, val, fixed&0xf);
+	}
+	break;
+    }
+    */
+}
+
+void * mymalloc(int l)
+{
+    mymem = (void**)realloc(mymem, mymems+1);
+    if (!mymem)
+	FatalError("LoadWBMP: can't realloc buffer");
+    return (mymem[mymems++] = malloc(l));
+}
+
+void myfree()
+{
+    int i;
+
+    if (mymem) {
+	for (i=0; i<mymems; i++) {
+	    if (mymem[i])
+	        free(mymem[i]);
+	}
+	free(mymem);
+    }
+    mymem = (void**)NULL;
+    mymems = 0;
+}
+
+uint8 * render1(uint8 * data, int size, int npixels)
+{
+    byte * pic;
+    int i;
+    int cnt = 0;
+    uint8 cb = *data;
+
+    pic = calloc(npixels,1);   /* checked for overflow by caller */
+    if (!pic) {
+	myfree();
+	FatalError("LoadWBMP: can't allocate 'pic' buffer");
+    }
+
+    /* expand bits into bytes */
+    /* memset(pic, 0, npixels); */
+
+    for (i=0; i<npixels; i++) {
+
+	pic[i] = (cb>>7)&1;
+
+	if ((++cnt)==8) {
+	    cb = *(++data);
+	    cnt = 0;
+	} else {
+	    cb <<=1;
+	}
+    }
+    return pic;
+}
diff -ruN xv-3.10a-bugfixes/xvxpm.c xv-3.10a-enhancements/xvxpm.c
--- xv-3.10a-bugfixes/xvxpm.c	2005-03-28 22:22:50.000000000 -0800
+++ xv-3.10a-enhancements/xvxpm.c	2005-04-17 14:45:28.000000000 -0700
@@ -175,7 +175,15 @@
 
     do {
       char  key[3];
-      char  color[40];	/* Need to figure a good size for this... */
+      char  color[80];	/* Need to figure a good size for this... */
+
+/*
+ *  Problem with spaces in color names
+ *
+ *    X s Color Name m Other Name c Last Name
+ *
+ *  ... this parser doesn't find `Any Name'
+ */
 
       for (j=0; j<2 && (c != ' ') && (c != '\t') && (c != EOF); j++) {
 	key[j] = c;
@@ -187,7 +195,7 @@
       if (c == EOF)	/* The failure condition of getc() */
 	return (XpmLoadError(bname, "Error parsing colormap line"));
 
-      for (j=0; j<39 && (c!=' ') && (c!='\t') && (c!='"') && c!=EOF; j++) {
+      for (j=0; j<79 && (c!=' ') && (c!='\t') && (c!='"') && c!=EOF; j++) {
 	color[j] = c;
 	c = XpmGetc(fp);
       }
@@ -248,7 +256,7 @@
       else {      /* 'None' or unrecognized color spec */
 	int rgb;
 
-	if (strcmp(color, "None") == 0) rgb = 0xb2c0dc;  /* infobg */
+	if (strcasecmp(color, "None") == 0) rgb = 0xb2c0dc;  /* infobg */
 	else {
 	  SetISTR(ISTR_INFO, "%s:  unknown color spec '%s'", bname, color);
 	  Timer(1000);
@@ -321,7 +329,8 @@
 	*i_sptr++ = mapentry->cv_rgb[2];
       }
     }  /* for ( j < w ) */
-    (void)XpmGetc(fp);		/* Throw away the close " */
+    while (((c = XpmGetc(fp))!=EOF) &&		/* Throw away the close " and */
+	(c != '"'));				/* erase all remaining pixels */
 
     if (!(i%7)) WaitCursor();
   }  /* for ( i < h ) */
diff -ruN xv-3.10a-bugfixes/xvzx.c xv-3.10a-enhancements/xvzx.c
--- xv-3.10a-bugfixes/xvzx.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvzx.c	2004-05-16 18:08:33.000000000 -0700
@@ -0,0 +1,349 @@
+/*
+ * xvzx.c - load routine for Spectrum screen$
+ *
+ * John Elliott, 7 August 1998
+ *
+ * LoadZX(fname, pinfo)  -  load file
+ * WriteZX(fp,pic,ptype,w,h,r,g,b,numcols,style,cmt,comment) - convert to
+ *                          256x192 SCREEN$ and save.
+ */
+
+#include "copyright.h"
+
+#include "xv.h"
+
+
+
+/*
+ * comments on error handling:
+ * a file with a bad header checksum is a warning error.
+ *
+ * not being able to malloc is a Fatal Error.  The program is aborted.
+ */
+
+
+#define TRUNCSTR "File appears to be truncated."
+
+static int zxError PARM((char *, char *));
+
+static char *bname;
+
+/*******************************************/
+int LoadZX(fname, pinfo)
+     char    *fname;
+     PICINFO *pinfo;
+/*******************************************/
+{
+  /* returns '1' on success */
+
+  FILE  *fp;
+  unsigned int    c, c1;
+  int   x,y, trunc;
+  byte  *zxfile;
+
+  bname = BaseName(fname);
+
+  pinfo->pic     = (byte *) NULL;
+  pinfo->comment = (char *) NULL;
+
+  /* Allocate memory for a 256x192x8bit image */
+
+  pinfo->pic     = (byte *)malloc(256*192);
+  if (!pinfo->pic) FatalError("malloc failure in xvzx.c LoadZX");
+
+  /* Allocate 1B80h bytes and slurp the whole file into memory */
+
+  zxfile         = (byte *)malloc(7040);
+  if (!zxfile)     FatalError("malloc failure in xvzx.c LoadZX");
+
+  /* open the file */
+  fp = xv_fopen(fname,"r");
+  if (!fp) return (zxError(bname, "can't open file"));
+
+  /* Load it in en bloc */
+  memset(zxfile, 0, 7040);
+  if (fread(zxfile, 1, 7040, fp) < 7040) trunc = 1;
+
+  /* Transform to 8-bit */
+
+  for (y = 0; y < 192; y++) for (x = 0; x < 256; x++)
+  {
+     /* Spectrum screen layout: three 2k segments at y=0, y=64, y=128 */
+     /* In each segment: Scan lines 0,8,16,...,56,1,9,...,57 etc.  Each
+        scanline is 32 bytes, so line 1 is 256 bytes after line 0
+
+        So address of line start is ((y>>6) * 2048) + ((y & 7) * 256)
+        + ((y & 0x38) * 4)
+
+       The colour byte for a cell is at screen + 6k + (y >> 3)*32 + (x>>3)
+
+       */
+
+     int offset;
+     byte *dst  = pinfo->pic + 256*y + x;
+     byte attr, pt, mask;
+
+     offset  = (y >> 6)   * 2048;
+     offset += (y & 7)    * 256;
+     offset += (y & 0x38) * 4;
+     offset += (x >> 3);
+
+     pt = zxfile[offset + 128];	/* Ink/paper map */
+
+     offset = 0x1880;
+     offset += (y >> 3) * 32;
+     offset += (x >> 3);
+
+     attr = zxfile[offset]; 	/* Colours for cell */
+
+     mask = 0x80;
+
+     if (x & 7) mask >>= (x & 7);
+
+     if (pt & mask)  *dst = attr & 7;        /* Ink */
+     else            *dst = (attr >> 3) & 7; /* Paper */
+
+     if (attr & 0x40) *dst |= 8; /* High intensity */
+  }
+
+  /* Picture bytes converted; now build the colour maps */
+
+  pinfo->normw = pinfo->w = 256;
+  pinfo->normh = pinfo->h = 192;
+  pinfo->type = PIC8;
+
+  for (c = 0; c < 16; c++)
+  {
+    if (c < 8) c1 = 192; else c1 = 255;	/* low-intensity colours use 192 */
+					/* high-intensity colours use 255 */
+    pinfo->b[c] = (c & 1 ? c1 : 0);
+    pinfo->r[c] = (c & 2 ? c1 : 0);
+    pinfo->g[c] = (c & 4 ? c1 : 0);
+  }
+
+  pinfo->colType = F_FULLCOLOR;
+  pinfo->frmType = F_ZX;		/* Save as SCREEN$ */
+  sprintf(pinfo->fullInfo, "Spectrum SCREEN$, load address %04x",
+                                 zxfile[16]+256*zxfile[17]);
+  strcpy(pinfo->shrtInfo, "Spectrum SCREEN$.");
+
+  /* Almost as an afterthought, check that the +3DOS header is valid.
+
+     If it isn't, then odds are that the file isn't a graphic. But it
+     had the right magic number, so it might be. Let them see it anyway.
+
+     The check is: Byte 127 of the header should be the 8-bit sum of bytes
+                   0-126 of the header. The header should also have the
+                   +3DOS magic number, but we know it does or we wouldn't
+                   have got this far.
+  */
+
+  c1 = 0;
+  for (c1 = c = 0; c < 127; c++) c1 = ((c1 + zxfile[c]) & 0xFF);
+  if (c1 != zxfile[127]) zxError(bname, "Bad header checksum.");
+
+  fclose(fp);
+  free(zxfile);
+  return 1;
+}
+
+
+
+
+
+/*******************************************/
+static int zxError(fname, st)
+     char *fname, *st;
+{
+  SetISTR(ISTR_WARNING,"%s:  %s", fname, st);
+  return 0;
+}
+
+
+/* Spectrum screen file header. The first 18 bytes are used in the magic
+   number test */
+
+byte ZXheader[128] =
+{
+        'P', 'L', 'U', 'S', '3', 'D', 'O', 'S', 26,  /* Spectrum +3DOS file */
+	  1,   0, 				     /* Header type 1.0 */
+	128,  27,  0,   0,			     /* 7040 bytes */
+	  3,	                                     /* Binary format */
+          0, 27,   				     /* 6912 data bytes */
+	  0, 64					     /* load address 0x4000 */
+};
+
+
+
+/* Get the Spectrum colour/bright byte (0-15) from a pixel */
+
+static int PointZX(pic, w, h, rmap, gmap, bmap, x, y)
+	byte *pic;
+	int w,h;
+	byte *rmap, *gmap, *bmap;
+	int x,y;
+{
+	int index, r, g, b, zxc;
+
+	/* If the picture is smaller than the screen, pad out the edges
+           with "bright black" - a colour not otherwise returned */
+
+	if (x >= w || y >= h) return 8;
+
+	/* Get colour index */
+
+	index = pic[y*w + x];
+
+	/* Convert to rgb */
+
+	r = rmap[index];
+	g = gmap[index];
+	b = bmap[index];
+	zxc = 0;
+
+	/* Work out Spectrum colour by a simplistic "nearest colour" method */
+
+	if (b >= 160) zxc |= 1;	/* Blue */
+	if (r >= 160) zxc |= 2;	/* Red */
+	if (g >= 160) zxc |= 4;	/* Green */
+	if (r > 208 || g >= 208 || b >= 208) zxc |= 8; /* High intensity */
+
+	return zxc;
+}
+
+
+/* Work out what colours should be used in a cell */
+
+static void CellZX(pic, w, h, rmap, gmap, bmap, cx, cy, zxfile)
+        byte *pic;
+        int w,h;
+        byte *rmap, *gmap, *bmap;
+        int cx,cy;
+	byte *zxfile;
+{
+	byte counts[16];	/* Count of no. of colours */
+	int offset, ink, paper, n, m, x, y, x0, y0, di, dp;
+
+	x0 = cx * 8;		/* Convert from cell to pixel coords */
+	y0 = cy * 8;
+
+	for (n = 0; n < 16; n++) counts[n] = 0;	 /* Reset all counts */
+
+	/* Count no. of pixels of various colours */
+
+	for (y = y0; y < y0+8; y++) for (x = x0; x < x0+8; x++)
+	{
+		m = PointZX(pic, w, h, rmap, gmap, bmap, x, y);
+
+		counts[m]++;
+	}
+	counts[8] = 0;	/* Discard Bright Black (pixels not in the picture area)
+                         */
+
+	/* Assign the most popular colour as ink */
+	for (n = m = ink = 0; n < 16; n++) if (counts[n] > m)
+	{
+		ink = n;
+		m   = counts[n];
+	}
+	counts[ink] = 0;
+
+	/* Assign the next most popular colour as paper */
+	for (n = m = paper = 0; n < 16; n++) if (counts[n] > m)
+	{
+		paper = n;
+		m     = counts[n];
+	}
+	/* We have ink and paper. Set cell's attributes */
+
+	offset = cy*32 + cx + 0x1880;
+
+	/* Set the high-intensity bit if ink is high-intensity */
+	if (ink & 8) zxfile[offset] = 0x40; else zxfile[offset] = 0;
+	zxfile[offset] |= ((paper & 7) << 3);
+	zxfile[offset] |=  (ink & 7);
+
+	/* Plot the points */
+	for (y = y0; y < y0+8; y++)
+	{
+	     byte mask = 0x80;
+
+	     offset  = (y >> 6)   * 2048;
+	     offset += (y & 7)    * 256;
+	     offset += (y & 0x38) * 4;
+	     offset += (x0 >> 3);
+
+	     for (x = x0; x < x0+8; x++)
+	     {
+		/* Work out whether the point should be plotted as ink or
+                   paper */
+		m = PointZX(pic, w, h, rmap, gmap, bmap, x, y);
+
+		di = (ink & 7)   - (m & 7);	/* "Difference" from ink */
+		dp = (paper & 7) - (m & 7);	/* "Difference" from paper */
+
+		if (di < 0) di = -di;
+		if (dp < 0) dp = -dp;
+
+		if (di < dp)	/* Point is more like ink */
+			zxfile[offset+128] |= mask;
+
+		mask = (mask >> 1);
+             }
+	}
+
+}
+
+
+
+/*******************************************/
+int WriteZX(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,comment)
+     FILE *fp;
+     byte *pic;
+     int   ptype, w,h;
+     byte *rmap, *gmap, *bmap;
+     int   numcols, colorstyle;
+     char *comment;
+{
+	int rv, x, y;
+	byte *zxfile;
+	byte *pic8;
+	byte  rtemp[256],gtemp[256],btemp[256];
+
+	/* To simplify matters, reduce 24-bit to 8-bit. Since the Spectrum
+           screen is 3.5-bit anyway, it doesn't make much difference */
+
+	if (ptype == PIC24)
+	{
+		pic8 = Conv24to8(pic, w, h, 256, rtemp,gtemp,btemp);
+		if (!pic8) FatalError("Unable to malloc in WriteZX()");
+		rmap = rtemp;  gmap = gtemp;  bmap = btemp;  numcols=256;
+  	}
+	else pic8 = pic;
+
+	ZXheader[127] = 0x71;	/* The correct checksum. */
+
+	/* Create a memory image of the SCREEN$ */
+
+	zxfile         = (byte *)malloc(7040);
+	if (!zxfile)     FatalError("malloc failure in xvzx.c WriteZX");
+
+	memset(zxfile, 0, 7040);	/* Reset all points to black */
+	memcpy(zxfile, ZXheader, 128);	/* Create +3DOS header */
+
+        /* Convert the image, character cell by character cell */
+        for (y = 0; y < 24; y++) for (x = 0; x < 32; x++)
+        {
+                CellZX(pic8, w, h, rmap, gmap, bmap, x, y, zxfile);
+        }
+	rv = 0;
+	if (fwrite(zxfile, 1, 7040, fp) < 7040) rv = -1;
+
+	if (ptype == PIC24) free(pic8);
+	free(zxfile);
+
+	if (ferror(fp)) rv = -1;
+
+	return rv;
+}
+
