about summary refs log tree commit diff
path: root/urt
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-19 03:12:28 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-19 03:12:28 +0000
commit1fd361a1ea06e44286c213ca1f814f49306fdc43 (patch)
tree64c8c96cf54d8718847339a403e5e67b922e8c3f /urt
downloadnetpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.gz
netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.xz
netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.zip
Create Subversion repository
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'urt')
-rw-r--r--urt/Makefile33
-rw-r--r--urt/README20
-rw-r--r--urt/Runput.c356
-rw-r--r--urt/Runput.h23
-rw-r--r--urt/cmd_name.c54
-rw-r--r--urt/rle.h492
-rw-r--r--urt/rle_addhist.c115
-rw-r--r--urt/rle_code.h70
-rw-r--r--urt/rle_config.h105
-rw-r--r--urt/rle_error.c118
-rw-r--r--urt/rle_getcom.c99
-rw-r--r--urt/rle_getrow.c562
-rw-r--r--urt/rle_getskip.c162
-rw-r--r--urt/rle_global.c85
-rw-r--r--urt/rle_hdr.c297
-rw-r--r--urt/rle_open_f.c310
-rw-r--r--urt/rle_put.h104
-rw-r--r--urt/rle_putcom.c169
-rw-r--r--urt/rle_putrow.c728
-rw-r--r--urt/rle_row_alc.c129
-rw-r--r--urt/scanargs.c948
-rw-r--r--urt/vaxshort.c50
-rw-r--r--urt/vaxshort.h5
23 files changed, 5034 insertions, 0 deletions
diff --git a/urt/Makefile b/urt/Makefile
new file mode 100644
index 00000000..04dd2913
--- /dev/null
+++ b/urt/Makefile
@@ -0,0 +1,33 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = urt
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/Makefile.config
+
+LIBOBJECTS = Runput.o cmd_name.o \
+	rle_addhist.o rle_error.o rle_getcom.o rle_getrow.o rle_getskip.o \
+	rle_global.o rle_hdr.o rle_open_f.o rle_putcom.o rle_putrow.o \
+        rle_row_alc.o \
+        scanargs.o vaxshort.o     
+
+MERGE_OBJECTS =
+
+all: librle.a
+
+librle.a: $(LIBOBJECTS)
+	rm -f $@
+	ar rc $@ $^
+	$(RANLIB) $@
+
+# Rule for objects.
+$(LIBOBJECTS): %.o: %.c importinc
+	$(CC) -c $(CFLAGS) -I importinc -o $@ $< $(CFLAGS_PERSONAL) $(CADD)
+
+BINARIES =
+SCRIPTS =
+
+OMIT_URT_RULE = 1
+include $(SRCDIR)/Makefile.common
diff --git a/urt/README b/urt/README
new file mode 100644
index 00000000..dc68889d
--- /dev/null
+++ b/urt/README
@@ -0,0 +1,20 @@
+This directory contains a subset of the Utah Raster Toolkit library.
+
+The source files are taken directly from that library, but only the ones
+Netpbm needs, so the resulting librle.a is smaller than the original.
+
+The files were extracted by Bryan Henderson on 2000.05.18, from a
+package taken from ftp.iastate.edu/pub/utah-raster/ called urt-3.1b on
+2000.04.13.
+
+A user who has the original library installed can use it instead of
+this stripped down version by configuring the make files
+appropriately.
+
+The source files have been modified slightly to quiet compiler warnings.
+
+In rle_global.c, the global data structure rle_dflt_hdr had "stdout"
+in its initializer in the original.  But GNU C Library Version 2
+defines stdout as a variable, so that wouldn't compile.  So I changed
+it to NULL and added a line to rle_hdr_init to set that field to
+'stdout' dynamically.  2000.06.02 BJH.
diff --git a/urt/Runput.c b/urt/Runput.c
new file mode 100644
index 00000000..3bc562ac
--- /dev/null
+++ b/urt/Runput.c
@@ -0,0 +1,356 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ *
+ *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
+ *  to have all "void" functions so declared.
+ */
+/* 
+ * Runput.c - General purpose Run Length Encoding.
+ * 
+ * Author:	Spencer W. Thomas
+ * 		Computer Science Dept.
+ * 		University of Utah
+ * Date:	Mon Aug  9 1982
+ * Copyright (c) 1982,1986 Spencer W. Thomas
+ * 
+ * $Id: Runput.c,v 3.0.1.1 1992/01/28 18:17:40 spencer Exp $
+ * 
+ * Modified by:	Todd W. Fuqua
+ * 	Date:	Jul 22 1984
+ * convert to new RLE format to make room for larger frame buffers
+ */
+
+/* THIS IS WAY OUT OF DATE.  See rle.5.
+ * The output file format is:
+ * 
+ * Word 0:	A "magic" number.  The top byte of the word contains
+ *		the letter 'R' or the letter 'W'.  'W' indicates that
+ *		only black and white information was saved.  The bottom
+ *		byte is one of the following:
+ *	' ':	Means a straight "box" save, -S flag was given.
+ *	'B':	Image saved with background color, clear screen to
+ *		background before restoring image.
+ *	'O':	Image saved in overlay mode.
+ * 
+ * Words 1-6:	The structure
+ * {     short   xpos,			Lower left corner
+ *             ypos,
+ *             xsize,			Size of saved box
+ *             ysize;
+ *     char    rgb[3];			Background color
+ *     char    map;			flag for map presence
+ * }
+ * 
+ * If the map flag is non-zero, then the color map will follow as 
+ * 3*256 16 bit words, first the red map, then the green map, and
+ * finally the blue map.
+ * 
+ * Following the setup information is the Run Length Encoded image.
+ * Each instruction consists of a 4-bit opcode, a 12-bit datum and
+ * possibly one or more following words (all words are 16 bits).  The
+ * instruction opcodes are:
+ * 
+ * SkipLines (1):   The bottom 10 bits are an unsigned number to be added to
+ *		    current Y position.
+ * 
+ * SetColor (2):    The datum indicates which color is to be loaded with
+ * 		    the data described by the following ByteData and
+ * 		    RunData instructions.  0->red, 1->green, 2->blue.  The
+ * 		    operation also resets the X position to the initial
+ * 		    X (i.e. a carriage return operation is performed).
+ * 
+ * SkipPixels (3):  The bottom 10 bits are an unsigned number to be
+ * 		    added to the current X position.
+ * 
+ * ByteData (5):    The datum is one less than the number of bytes of
+ * 		    color data following.  If the number of bytes is
+ * 		    odd, a filler byte will be appended to the end of
+ * 		    the byte string to make an integral number of 16-bit
+ * 		    words.  The bytes are in PDP-11 order.  The X
+ * 		    position is incremented to follow the last byte of
+ * 		    data.
+ * 
+ * RunData (6):	    The datum is one less than the run length.  The
+ * 		    following word contains (in its lower 8 bits) the
+ * 		    color of the run.  The X position is incremented to
+ * 		    follow the last byte in the run.
+ */
+
+#include    <string.h>
+#include	<stdio.h>
+
+#include	"rle_put.h"
+#include	"rle.h"
+#include	"rle_code.h"
+#include    "vaxshort.h"
+#include    "Runput.h"
+
+#define UPPER 255			/* anything bigger ain't a byte */
+
+/*
+ * Macros to make writing instructions with correct byte order easier.
+ */
+/* Write a two-byte value in little_endian order. */
+#define	put16(a)    (putc((a)&0xff,rle_fd),putc((char)(((a)>>8)&0xff),rle_fd))
+
+/* short instructions */
+#define mk_short_1(oper,a1)		/* one argument short */ \
+    putc(oper,rle_fd), putc((char)a1,rle_fd)
+
+#define mk_short_2(oper,a1,a2)		/* two argument short */ \
+    putc(oper,rle_fd), putc((char)a1,rle_fd), put16(a2)
+
+/* long instructions */
+#define mk_long_1(oper,a1)		/* one argument long */ \
+    putc((char)(LONG|oper),rle_fd), putc('\0', rle_fd), put16(a1)
+
+#define mk_long_2(oper,a1,a2)		/* two argument long */ \
+    putc((char)(LONG|oper),rle_fd), putc('\0', rle_fd), \
+    put16(a1), put16(a2)
+
+/* choose between long and short format instructions */
+/* NOTE: these macros can only be used where a STATEMENT is legal */
+
+#define mk_inst_1(oper,a1)		/* one argument inst */ \
+    if (a1>UPPER) (mk_long_1(oper,a1)); else (mk_short_1(oper,a1))
+
+#define mk_inst_2(oper,a1,a2)		/* two argument inst */ \
+    if (a1>UPPER) (mk_long_2(oper,a1,a2)); else (mk_short_2(oper,a1,a2))
+
+/* 
+ * Opcode definitions
+ */
+#define	    RSkipLines(n)   	    mk_inst_1(RSkipLinesOp,(n))
+
+#define	    RSetColor(c)	    mk_short_1(RSetColorOp,(c))
+				    /* has side effect of performing */
+				    /* "carriage return" action */
+
+#define	    RSkipPixels(n)	    mk_inst_1(RSkipPixelsOp,(n))
+
+#define	    RNewLine		    RSkipLines(1)
+
+#define	    RByteData(n)	    mk_inst_1(RByteDataOp,n)
+					/* followed by ((n+1)/2)*2 bytes */
+					/* of data.  If n is odd, last */
+					/* byte will be ignored */
+					/* "cursor" is left at pixel */
+					/* following last pixel written */
+
+#define	    RRunData(n,c)	    mk_inst_2(RRunDataOp,(n),(c))
+					/* next word contains color data */
+					/* "cursor" is left at pixel after */
+					/* end of run */
+
+#define     REOF		    mk_inst_1(REOFOp,0)
+					/* Really opcode only */
+
+/*****************************************************************
+ * TAG( RunSetup )
+ * Put out initial setup data for RLE files.
+ */
+void
+RunSetup(rle_hdr * the_hdr)
+{
+    struct XtndRsetup setup;
+    register FILE * rle_fd = the_hdr->rle_file;
+
+    put16( RLE_MAGIC );
+
+    if ( the_hdr->background == 2 )
+	setup.h_flags = H_CLEARFIRST;
+    else if ( the_hdr->background == 0 )
+	setup.h_flags = H_NO_BACKGROUND;
+    else
+	setup.h_flags = 0;
+    if ( the_hdr->alpha )
+	setup.h_flags |= H_ALPHA;
+    if ( the_hdr->comments != NULL && *the_hdr->comments != NULL )
+	setup.h_flags |= H_COMMENT;
+
+    setup.h_ncolors = the_hdr->ncolors;
+    setup.h_pixelbits = 8;		/* Grinnell dependent */
+    if ( the_hdr->ncmap > 0 && the_hdr->cmap == NULL )
+    {
+	fprintf( stderr,
+       "%s: Color map of size %d*%d specified, but not supplied, writing %s\n",
+		 the_hdr->cmd, the_hdr->ncmap, (1 << the_hdr->cmaplen),
+		 the_hdr->file_name );
+	the_hdr->ncmap = 0;
+    }
+    setup.h_cmaplen = the_hdr->cmaplen;	/* log2 of color map size */
+    setup.h_ncmap = the_hdr->ncmap;	/* no of color channels */
+    vax_pshort(setup.hc_xpos,the_hdr->xmin);
+    vax_pshort(setup.hc_ypos,the_hdr->ymin);
+    vax_pshort(setup.hc_xlen,the_hdr->xmax - the_hdr->xmin + 1);
+    vax_pshort(setup.hc_ylen,the_hdr->ymax - the_hdr->ymin + 1);
+    fwrite((char *)&setup, SETUPSIZE, 1, rle_fd);
+    if ( the_hdr->background != 0 )
+    {
+	register int i;
+	register rle_pixel *background =
+	    (rle_pixel *)malloc( (unsigned)(the_hdr->ncolors + 1) );
+	register int *bg_color;
+	/* 
+	 * If even number of bg color bytes, put out one more to get to 
+	 * 16 bit boundary.
+	 */
+	bg_color = the_hdr->bg_color;
+	for ( i = 0; i < the_hdr->ncolors; i++ )
+	    background[i] =  *bg_color++;
+	/* Extra byte, if written, should be 0. */
+	background[i] = 0;
+	fwrite((char *)background, (the_hdr->ncolors / 2) * 2 + 1, 1, rle_fd);
+	free( background );
+    }
+    else
+	putc( '\0', rle_fd );
+    if (the_hdr->ncmap > 0)
+    {
+	/* Big-endian machines are harder */
+	register int i, nmap = (1 << the_hdr->cmaplen) *
+			       the_hdr->ncmap;
+	register char *h_cmap = (char *)malloc( nmap * 2 );
+	if ( h_cmap == NULL )
+	{
+	    fprintf( stderr,
+	     "%s: Malloc failed for color map of size %d, writing %s\n",
+		     the_hdr->cmd, nmap, the_hdr->file_name );
+	    exit( 1 );
+	}
+	for ( i = 0; i < nmap; i++ )
+	    vax_pshort( &h_cmap[i*2], the_hdr->cmap[i] );
+
+	fwrite( h_cmap, nmap, 2, rle_fd );
+	free( h_cmap );
+    }
+
+    /* Now write out comments if given */
+    if ( setup.h_flags & H_COMMENT )
+    {
+	int comlen;
+	register CONST_DECL char ** com_p;
+
+	/* Get the total length of comments */
+	comlen = 0;
+	for ( com_p = the_hdr->comments; *com_p != NULL; com_p++ )
+	    comlen += 1 + strlen( *com_p );
+
+	put16( comlen );
+	for ( com_p = the_hdr->comments; *com_p != NULL; com_p++ )
+	    fwrite( *com_p, 1, strlen( *com_p ) + 1, rle_fd );
+
+	if ( comlen & 1 )	/* if odd length, round up */
+	    putc( '\0', rle_fd );
+    }
+}
+
+/*****************************************************************
+ * TAG( RunSkipBlankLines )
+ * Skip one or more blank lines in the RLE file.
+ */
+void
+RunSkipBlankLines(int nblank, rle_hdr * the_hdr)
+{
+    register FILE * rle_fd = the_hdr->rle_file;
+    RSkipLines(nblank);
+}
+
+/*****************************************************************
+ * TAG( RunSetColor )
+ * Select a color and do carriage return.
+ * color: 0 = Red, 1 = Green, 2 = Blue.
+ */
+void
+RunSetColor(int c, rle_hdr * the_hdr)
+{
+    register FILE * rle_fd = the_hdr->rle_file;
+    RSetColor(c);
+}
+
+/*****************************************************************
+ * TAG( RunSkipPixels )
+ * Skip a run of background.
+ */
+
+/* ARGSUSED */
+void
+RunSkipPixels(int nskip, int last, int wasrun, rle_hdr * the_hdr)
+{
+    register FILE * rle_fd = the_hdr->rle_file;
+    if (! last && nskip > 0)
+    {
+	RSkipPixels(nskip);
+    }
+}
+
+/*****************************************************************
+ * TAG( RunNewScanLine )
+ * Perform a newline action.  Since CR is implied by the Set Color
+ * operation, only generate code if the newline flag is true.
+ */
+void
+RunNewScanLine(int flag, rle_hdr * the_hdr)
+{
+    register FILE * rle_fd = the_hdr->rle_file;
+    if (flag)
+    {
+	RNewLine;
+    }
+}
+
+/*****************************************************************
+ * TAG( Runputdata )
+ * Put one or more pixels of byte data into the output file.
+ */
+void
+Runputdata(rle_pixel * buf, int n, rle_hdr * the_hdr)
+{
+    register FILE * rle_fd = the_hdr->rle_file;
+    if (n == 0)
+	return;
+
+    RByteData(n-1);
+    fwrite((char *)buf, n, 1, rle_fd);
+    if ( n & 1 )
+	putc( 0, rle_fd );
+}
+
+/*****************************************************************
+ * TAG( Runputrun )
+ * Output a single color run.
+ */
+
+/* ARGSUSED */
+void
+Runputrun(int color, int n, int last, rle_hdr * the_hdr)
+{
+    register FILE * rle_fd = the_hdr->rle_file;
+    RRunData(n-1,color);
+}
+
+
+/*****************************************************************
+ * TAG( RunputEof )
+ * Output an EOF opcode
+ */
+void
+RunputEof(rle_hdr * the_hdr)
+{
+    register FILE * rle_fd = the_hdr->rle_file;
+    REOF;
+}
diff --git a/urt/Runput.h b/urt/Runput.h
new file mode 100644
index 00000000..776e3ec5
--- /dev/null
+++ b/urt/Runput.h
@@ -0,0 +1,23 @@
+void 
+RunSetup(rle_hdr * the_hdr);
+
+void
+RunSkipBlankLines(int nblank, rle_hdr * the_hdr);
+
+void
+RunSetColor(int c, rle_hdr * the_hdr);
+
+void
+RunSkipPixels(int nskip, int last, int wasrun, rle_hdr * the_hdr);
+
+void
+RunNewScanLine(int flag, rle_hdr * the_hdr);
+
+void
+Runputdata(rle_pixel * buf, int n, rle_hdr * the_hdr);
+
+void
+Runputrun(int color, int n, int last, rle_hdr * the_hdr);
+
+void
+RunputEof(rle_hdr * the_hdr);
diff --git a/urt/cmd_name.c b/urt/cmd_name.c
new file mode 100644
index 00000000..1f8f0edf
--- /dev/null
+++ b/urt/cmd_name.c
@@ -0,0 +1,54 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ */
+/* 
+ * cmd_name.c - Extract command name from argv[0].
+ * 
+ * Author:	Spencer W. Thomas
+ * 		EECS Dept.
+ * 		University of Michigan
+ * Date:	Wed Jun 27 1990
+ * Copyright (c) 1990, University of Michigan
+ */
+
+#include "rle.h"
+static char no_name[] = "(no-name)";
+
+char *
+cmd_name( argv )
+char **argv;
+{
+    register char *cp, *a;
+
+    /* Be paranoid. */
+    if ( !argv || !(a = *argv) )
+	return no_name;
+
+    /* Find end of file name. */
+    for ( cp = a; *cp; cp++ )
+	;
+
+    /* Find last / or beginning of command name. */
+    for ( cp--; *cp != '/' && cp > a; cp-- )
+	;
+    
+    /* If it's a /, skip it. */
+    if ( *cp == '/' )
+	cp++;
+
+    return cp;
+}
diff --git a/urt/rle.h b/urt/rle.h
new file mode 100644
index 00000000..71f15d28
--- /dev/null
+++ b/urt/rle.h
@@ -0,0 +1,492 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ */
+/* 
+ * rle.h - Global declarations for Utah Raster Toolkit RLE programs.
+ * 
+ * Author:  Todd W. Fuqua
+ *      Computer Science Dept.
+ *      University of Utah
+ * Date:    Sun Jul 29 1984
+ * Copyright (c) 1984 Todd W. Fuqua
+ * 
+ * $Id: rle.h,v 3.0.1.5 1992/04/30 14:05:56 spencer Exp $
+ */
+
+#ifndef RLE_H
+#define RLE_H
+
+#include "rle_config.h"     /* Configuration parameters. */
+
+#include <stdio.h>      /* Declare FILE. */
+
+#ifdef c_plusplus
+#define USE_PROTOTYPES
+#endif
+
+enum rle_dispatch {
+    NO_DISPATCH = -1,
+    RUN_DISPATCH = 0
+};
+
+/* ****************************************************************
+ * TAG( rle_pixel rle_map )
+ *
+ * Typedef for 8-bit (or less) pixel data.
+ *
+ * Typedef for 16-bit color map data.
+ */
+typedef unsigned char rle_pixel;
+typedef unsigned short rle_map;
+
+/*
+ * Defines for traditional channel numbers.
+ */
+#define RLE_RED     0   /* Red channel traditionally here. */
+#define RLE_GREEN   1   /* Green channel traditionally here. */
+#define RLE_BLUE    2   /* Blue channel traditionally here. */
+#define RLE_ALPHA      -1   /* Alpha channel here. */
+
+/*
+ * Return values from rle_get_setup.
+ */
+#define RLE_SUCCESS  0
+#define RLE_NOT_RLE -1
+#define RLE_NO_SPACE    -2
+#define RLE_EMPTY   -3
+#define RLE_EOF     -4
+
+/*
+ * "Magic" value for is_init field.  Pi * 2^29.
+ */
+#define RLE_INIT_MAGIC  0x6487ED51L
+
+/*****************************************************************
+ * TAG( RLE_CHECK_ALLOC )
+ *
+ * Test for allocation failure, scream and die if so.
+ */
+#define RLE_CHECK_ALLOC( pgm, ptr, name )               \
+    ( !(ptr) ?  rle_alloc_error( pgm, name ) : 0 )
+
+/*
+ * TAG( rle_hdr )
+ *
+ * Definition of header structure used by RLE routines.
+ */
+
+#ifndef c_plusplus
+typedef
+#endif
+    struct rle_hdr {
+        enum rle_dispatch dispatch;  /* Type of file to create. */
+        int       ncolors;    /* Number of color channels. */
+        int *     bg_color;   /* Pointer to bg color vector. */
+        int       alpha;      /* If !0, save alpha channel. */
+        int       background; /* 0->just save all pixels, */
+        /* 1->overlay, 2->clear to bg first. */
+        int       xmin;       /* Lower X bound (left.) */
+        int       xmax;       /* Upper X bound (right.) */
+        int       ymin;       /* Lower Y bound (bottom.) */
+        int       ymax;       /* Upper Y bound (top.) */
+        int       ncmap;      /* Number of color channels in color map. */
+        /* Map only saved if != 0. */
+        int       cmaplen;    /* Log2 of color map length. */
+        rle_map * cmap;       /* Pointer to color map array. */
+        const char ** comments; /* Pointer to array of pointers to comments. */
+        FILE *    rle_file;   /* Input or output file. */
+        /* 
+         * Bit map of channels to read/save.  Indexed by (channel mod 256).
+         * Alpha channel sets bit 255.
+         * 
+         * Indexing (0 <= c <= 255):
+         *      bits[c/8] & (1 << (c%8))
+         */
+#define RLE_SET_BIT(glob,bit) \
+        ((glob).bits[((bit)&0xff)/8] |= (1<<((bit)&0x7)))
+#define RLE_CLR_BIT(glob,bit) \
+            ((glob).bits[((bit)&0xff)/8] &= ~(1<<((bit)&0x7)))
+#define RLE_BIT(glob,bit) \
+            ((glob).bits[((bit)&0xff)/8] & (1<<((bit)&0x7)))
+            char    bits[256/8];
+            /* Set to magic pattern if following fields are initialized. */
+            /* This gives a 2^(-32) chance of missing. */
+            long int is_init;   
+            /* Command, file name and image number for error messages. */
+            const char *cmd;
+            const char *file_name;
+            int img_num;
+            /* 
+             * Local storage for rle_getrow & rle_putrow.
+             * rle_getrow has
+             *      scan_y  int     current Y scanline.
+             *      vert_skip   int     number of lines to skip.
+             * rle_putrow has
+             *      nblank  int     number of blank lines.
+             *      brun    short(*)[2] Array of background runs.
+             *      fileptr long        Position in output file.
+             */
+            union {
+                struct {
+                    int scan_y,
+                        vert_skip;
+                    char is_eof,    /* Set when EOF or EofOp encountered. */
+                        is_seek;    /* If true, can seek input file. */
+                } get;
+                struct {
+                    int nblank;
+                    short (*brun)[2];
+                    long fileptr;
+                } put;
+            } priv;
+    }
+#ifndef c_plusplus
+rle_hdr             /* End of typedef. */
+#endif
+;
+
+/* 
+ * TAG( rle_dflt_hdr )
+ *
+ * Global variable with possibly useful default values.
+ */
+extern rle_hdr rle_dflt_hdr;
+
+
+/* Declare RLE library routines. */
+
+/* From rle_error.c. */
+/*****************************************************************
+ * TAG( rle_alloc_error )
+ * 
+ * Print memory allocation error message and exit.
+ */
+extern int rle_alloc_error( const char *pgm,
+                            const char *name );
+
+/*****************************************************************
+ * TAG( rle_get_error )
+ *
+ * Print an error message based on the error code returned by
+ * rle_get_setup.
+ */
+extern int rle_get_error( int code,
+                          const char *pgmname,
+                          const char *fname );
+              
+/* From rle_getrow.c */
+
+/*****************************************************************
+ * TAG( rle_debug )
+ * 
+ * Turn RLE debugging on or off.
+ */
+extern void rle_debug( int on_off );
+
+int
+rle_get_setup(rle_hdr * const the_hdr);
+
+/*****************************************************************
+ * TAG( rle_get_setup_ok )
+ *
+ * Call rle_get_setup.  If it returns an error code, call
+ * rle_get_error to print the error message, then exit with the error
+ * code. 
+ */
+extern void rle_get_setup_ok( rle_hdr *the_hdr,
+                              const char *prog_name,
+                              const char *file_name);
+
+/*****************************************************************
+ * TAG( rle_getrow )
+ *
+ * Read a scanline worth of data from an RLE file.
+ */
+extern int rle_getrow( rle_hdr * the_hdr, 
+                       rle_pixel * scanline[] );
+
+/* From rle_getskip.c */
+
+/*****************************************************************
+ * TAG( rle_getskip )
+ * Skip a scanline, return the number of the next one.
+ */
+extern unsigned int rle_getskip( rle_hdr *the_hdr );
+
+/* From rle_hdr.c. */
+
+/*****************************************************************
+ * TAG( rle_names )
+ *
+ * Load the command and file names into the rle_hdr.
+ */
+extern void rle_names( rle_hdr *the_hdr,
+                       const char *pgmname,
+                       const char *fname,
+                       int img_num );
+
+/*****************************************************************
+ * TAG( rle_hdr_cp )
+ * 
+ * Make a "safe" copy of a rle_hdr structure.
+ */
+extern rle_hdr * rle_hdr_cp( rle_hdr *from_hdr,
+                             rle_hdr *to_hdr );
+
+/*****************************************************************
+ * TAG( rle_hdr_init )
+ * 
+ * Initialize a rle_hdr structure.
+ */
+extern rle_hdr * rle_hdr_init( rle_hdr *the_hdr );
+
+/*****************************************************************
+ * TAG( rle_hdr_clear )
+ * 
+ */
+extern void rle_hdr_clear( rle_hdr *the_hdr );
+
+/* From rle_putrow.c. */
+
+/*****************************************************************
+ * TAG( rgb_to_bw )
+ *
+ * Converts RGB data to gray data via the NTSC Y transform.
+ */
+extern void rgb_to_bw( rle_pixel *red_row,
+                       rle_pixel *green_row,
+                       rle_pixel *blue_row,
+                       rle_pixel *bw_row,
+                       int rowlen );
+
+/*****************************************************************
+ * TAG( rle_puteof )
+ *
+ * Write an End-of-image opcode to the RLE file.
+ */
+extern void rle_puteof( rle_hdr *the_hdr );
+
+/*****************************************************************
+ * TAG( rle_putrow )
+ *
+ * Write a scanline of data to the RLE file.
+ */
+extern void rle_putrow( rle_pixel *rows[], int rowlen, rle_hdr *the_hdr );
+
+/*****************************************************************
+ * TAG( rle_put_init )
+ *
+ * Initialize header for output, but don't write it to the file.
+ */
+extern void rle_put_init( rle_hdr * the_hdr );
+
+/*****************************************************************
+ * TAG( rle_put_setup )
+ *
+ * Write header information to a new RLE image file.
+ */
+extern void rle_put_setup( rle_hdr * the_hdr );
+
+/*****************************************************************
+ * TAG( rle_skiprow )
+ *
+ * Skip nrow scanlines in the output file.
+ */
+extern void rle_skiprow( rle_hdr *the_hdr, int nrow );
+
+/* From rle_cp.c */
+/*****************************************************************
+ * TAG( rle_cp )
+ * Copy image data from input to output with minimal interpretation.
+ */
+extern void rle_cp( rle_hdr *in_hdr, rle_hdr *out_hdr );
+
+/* From rle_row_alc.c. */
+/*****************************************************************
+ * TAG( rle_row_alloc )
+ *
+ * Allocate scanline memory for use by rle_getrow.
+ */
+extern int rle_row_alloc( rle_hdr * the_hdr,
+                          rle_pixel *** scanp );
+
+/*****************************************************************
+     * TAG( rle_row_free )
+     *
+     * Free the above.
+     */
+extern void rle_row_free( rle_hdr *the_hdr, rle_pixel **scanp );
+
+/* From buildmap.c. */
+/* 
+ * buildmap - build a more usable colormap from data in the_hdr struct.
+     */
+extern rle_pixel **buildmap( rle_hdr *the_hdr,
+                             int minmap,
+                             double orig_gamma,
+                             double new_gamma );
+
+/* From rle_getcom.c. */
+/*****************************************************************
+ * TAG( rle_getcom )
+ *
+ * Get a specific comment from the image comments.
+ */
+const char *
+rle_getcom(const char * const name,
+           rle_hdr *    const the_hdr);
+
+/* From rle_putcom.c. */
+
+/* Delete a specific comment from the image comments. */
+const char *
+rle_delcom(const char * const name,
+           rle_hdr *    const the_hdr);
+
+/* Put (or replace) a comment into the image comments. */
+const char *
+rle_putcom(const char * const value,
+           rle_hdr *    const the_hdr);
+
+/* From dither.c. */
+/*****************************************************************
+ * TAG( bwdithermap )
+ * Create a color map for ordered dithering in grays.
+ */
+extern void bwdithermap( int levels, double gamma, int bwmap[],
+                         int divN[256], int modN[256], int magic[16][16] );
+/*****************************************************************
+ * TAG( ditherbw )
+ * Dither a gray-scale value.
+ */
+extern int ditherbw( int x, int y, int val, 
+                     int divN[256], int modN[256], int magic[16][16] );
+/*****************************************************************
+ * TAG( dithergb )
+ * Dither a color value.
+ */
+extern int dithergb( int x, int y, int r, int g, int b,
+                     int divN[256], int modN[256], int magic[16][16] );
+/*****************************************************************
+ * TAG( dithermap )
+ * Create a color map for ordered dithering in color.
+ */
+extern void dithermap( int levels, double gamma, int rgbmap[][3],
+                       int divN[256], int modN[256], int magic[16][16] );
+/*****************************************************************
+ * TAG( make_square )
+ * Make a 16x16 magic square for ordered dithering.
+ */
+extern void make_square( double N, int divN[256], int modN[256],
+                         int magic[16][16] );
+
+/* From float_to_exp.c. */
+/*****************************************************************
+ * TAG( float_to_exp )
+ * Convert a list of floating point numbers to "exp" format.
+ */
+extern void float_to_exp( int count, float * floats, rle_pixel * pixels );
+
+/* From rle_open_f.c. */
+/*****************************************************************
+ * TAG( rle_open_f )
+ *
+ * Open an input/output file with default.
+ */
+FILE *
+rle_open_f(const char * prog_name, const char * file_name, 
+           const char * mode);
+
+/*****************************************************************
+ * TAG( rle_open_f_noexit )
+ *
+ * Open an input/output file with default.
+ */
+FILE *
+rle_open_f_noexit(const char * const prog_name,
+                  const char * const file_name, 
+                  const char * const mode);
+
+/*****************************************************************
+ * TAG( rle_close_f )
+ * 
+ * Close a file opened by rle_open_f.  If the file is stdin or stdout,
+ * it will not be closed.
+ */
+extern void 
+rle_close_f( FILE *fd );
+
+/* From colorquant.c. */
+/*****************************************************************
+ * TAG( colorquant )
+ * Compute a colormap for quantizing an image to a limited set of colors.
+ */
+extern int colorquant( rle_pixel *red, rle_pixel *green, rle_pixel *blue,
+                       unsigned long pixels, rle_pixel *colormap[3],
+                       int colors, int bits,
+                       rle_pixel *rgbmap, int fast, int otherimages );
+
+/* From rle_addhist.c. */
+
+/* Append history information to the HISTORY comment. */
+void
+rle_addhist(char *          argv[],
+            rle_hdr * const in_hdr,
+            rle_hdr * const out_hdr);
+
+/* From cmd_name.c. */
+/*****************************************************************
+ * TAG( cmd_name )
+ * Extract command name from argv.
+ */
+extern char *cmd_name( char **argv );
+
+/* From scanargs.c. */
+/*****************************************************************
+ * TAG( scanargs )
+ * Scan command argument list and parse arguments.
+ */
+extern int scanargs( int argc,
+                     char **argv,
+                     const char *format,
+                     ... );
+
+/* From hilbert.c */
+/*****************************************************************
+ * TAG( hilbert_i2c )
+ * Convert an index into a Hilbert curve to a set of coordinates.
+ */
+extern void hilbert_c2i( int n, int m, int a[], long int *r );
+
+/*****************************************************************
+ * TAG( hilbert_c2i )
+ * Convert coordinates of a point on a Hilbert curve to its index.
+ */
+extern void hilbert_i2c( int n, int m, long int r, int a[] );
+
+/* From inv_cmap.c */
+/*****************************************************************
+ * TAG( inv_cmap )
+ * Compute an inverse colormap efficiently.
+ */
+extern void inv_cmap( int colors,
+                      unsigned char *colormap[3],
+                      int bits,
+                      unsigned long *dist_buf,
+                      unsigned char *rgbmap );
+
+#endif /* RLE_H */
diff --git a/urt/rle_addhist.c b/urt/rle_addhist.c
new file mode 100644
index 00000000..04e26206
--- /dev/null
+++ b/urt/rle_addhist.c
@@ -0,0 +1,115 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ */
+/* 
+ * rle_addhist.c - Add to the HISTORY comment in header
+ * 
+ * Author:  Andrew Marriott.
+ *      School of Computer Science 
+ *      Curtin University of Technology
+ * Date:    Mon Sept 10 1988
+ * Copyright (c) 1988, Curtin University of Technology
+ */
+
+#include "rle.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#ifdef  USE_TIME_H
+#include <time.h>
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#endif
+
+#include "mallocvar.h"
+
+/*****************************************************************
+ * TAG( rle_addhist )
+ * 
+ * Put a history comment into the header struct.
+ * Inputs:
+ *  argv:       Command line history to add to comments.
+ *  in_hdr:     Incoming header struct to use.
+ * Outputs:
+ *  out_hdr:    Outgoing header struct to add to.
+ * Assumptions:
+ *  If no incoming struct then value is NULL.
+ * Algorithm:
+ *  Calculate length of all comment strings, malloc and then set via
+ *  rle_putcom.
+ */
+
+void
+rle_addhist(char *          argv[],
+            rle_hdr * const in_hdr,
+            rle_hdr * const out_hdr) {
+
+    const char * const histoire = "HISTORY";
+    const char * const padding = "\t";
+
+    int length;
+    int i;
+    time_t  temp;
+    /* padding must give number of characters in histoire   */
+    /*     plus one for "="                 */
+    char * timedate;
+    const char * old;
+    static char * newc;
+
+    if (getenv("NO_ADD_RLE_HISTORY"))
+        return;
+    
+    length = 0;
+    for (i = 0; argv[i]; ++i)
+        length += strlen(argv[i]) +1;   /* length of each arg plus space. */
+
+    time(&temp);
+    timedate = ctime(&temp);
+    length += strlen(timedate);        /* length of date and time in ASCII. */
+
+    length += strlen(padding) + 3 + strlen(histoire) + 1;
+        /* length of padding, "on "  and length of history name plus "="*/
+    if (in_hdr) /* if we are interested in the old comments... */
+        old = rle_getcom(histoire, in_hdr);     /* get old comment. */
+    else
+        old = NULL;
+    
+    if (old && *old)
+        length += strlen(old);       /* add length if there. */
+
+    ++length;                               /*Cater for the null. */
+
+    MALLOCARRAY(newc, length);
+
+    if (newc == NULL)
+        return;
+
+    strcpy(newc,histoire);(void)strcat(newc,"=");
+    if (old && *old)
+        strcat(newc, old); /* add old string if there. */
+    for (i=0;argv[i];i++) {
+        strcat(newc, argv[i]);
+        strcat(newc, " ");
+    }
+    strcat(newc,"on ");
+    strcat(newc,timedate);         /* \n supplied by time. */
+    strcat(newc,padding);          /* to line up multiple histories.*/
+    
+    rle_putcom(newc, out_hdr);
+}
diff --git a/urt/rle_code.h b/urt/rle_code.h
new file mode 100644
index 00000000..955e7d42
--- /dev/null
+++ b/urt/rle_code.h
@@ -0,0 +1,70 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ */
+/* 
+ * rle_code.h - Definitions for Run Length Encoding.
+ * 
+ * Author:	Spencer W. Thomas
+ * 		Computer Science Dept.
+ * 		University of Utah
+ * Date:	Mon Aug  9 1982
+ * Copyright (c) 1982 Spencer W. Thomas
+ * 
+ * $Header: /usr/users/spencer/src/urt/include/RCS/rle_code.h,v 3.0 90/08/03 15:19:48 spencer Exp $
+ */
+
+#ifndef RLE_MAGIC
+
+/* 
+ * Opcode definitions
+ */
+
+#define     LONG                0x40
+#define	    RSkipLinesOp	1
+#define	    RSetColorOp		2
+#define	    RSkipPixelsOp	3
+#define	    RByteDataOp		5
+#define	    RRunDataOp		6
+#define	    REOFOp		7
+
+#define     H_CLEARFIRST        0x1	/* clear framebuffer flag */
+#define	    H_NO_BACKGROUND	0x2	/* if set, no bg color supplied */
+#define	    H_ALPHA		0x4   /* if set, alpha channel (-1) present */
+#define	    H_COMMENT		0x8	/* if set, comments present */
+
+struct XtndRsetup
+{
+    char    hc_xpos[2],
+            hc_ypos[2],
+            hc_xlen[2],
+            hc_ylen[2];
+    char    h_flags,
+            h_ncolors,
+	    h_pixelbits,
+	    h_ncmap,
+	    h_cmaplen;
+};
+#define	    SETUPSIZE	((4*2)+5)
+
+/* "Old" RLE format magic numbers */
+#define	    RMAGIC	('R' << 8)	/* top half of magic number */
+#define	    WMAGIC	('W' << 8)	/* black&white rle image */
+
+#define	    RLE_MAGIC	((short)0xcc52)	/* RLE file magic number */
+
+#endif /* RLE_MAGIC */
+
diff --git a/urt/rle_config.h b/urt/rle_config.h
new file mode 100644
index 00000000..f3fa5bbc
--- /dev/null
+++ b/urt/rle_config.h
@@ -0,0 +1,105 @@
+/* rle_config.h
+ * 
+ * Automatically generated by make-config-h script.
+ * DO NOT EDIT THIS FILE.
+ * Edit include/makefile.src and the configuration file instead.
+ */
+#if defined(WIN32) && !defined(__CYGWIN__)
+#define NO_OPEN_PIPES
+#endif
+
+#define ABEKASA60 ABEKASA60
+#define ABEKASA62 ABEKASA62
+#define ALIAS ALIAS
+#define CUBICOMP CUBICOMP
+#define GIF GIF
+#define GRAYFILES GRAYFILES
+#define MACPAINT MACPAINT
+#define POSTSCRIPT POSTSCRIPT
+#define TARGA TARGA
+#define TIFF2p4 TIFF2p4
+#define VICAR VICAR
+#define WASATCH WASATCH
+#define WAVEFRONT WAVEFRONT
+#define GCC GCC
+#define CONST_DECL CONST_DECL
+#define NO_MAKE_MAKEFILE NO_MAKE_MAKEFILE
+#define NO_TOOLS NO_TOOLS
+#define USE_TIME_H USE_TIME_H
+#define USE_PROTOTYPES USE_PROTOTYPES
+#define USE_RANDOM USE_RANDOM
+#define USE_STDARG USE_STDARG
+#define USE_STDLIB_H USE_STDLIB_H
+#define USE_UNISTD_H USE_UNISTD_H
+#define USE_STRING_H USE_STRING_H
+#define VOID_STAR VOID_STAR
+/* -*-C-*- */
+/***************** From rle_config.tlr *****************/
+
+/* CONST_DECL must be defined as 'const' or nothing. */
+#ifdef CONST_DECL
+#undef CONST_DECL
+#define CONST_DECL const
+
+#else
+#define CONST_DECL
+
+#endif
+
+/* A define for getx11. */
+#ifndef USE_XLIBINT_H
+#define XLIBINT_H_NOT_AVAILABLE
+#endif
+
+/* Typedef for void * so we can use it consistently. */
+#ifdef VOID_STAR
+typedef	void *void_star;
+#else
+typedef char *void_star;
+#endif
+
+#ifdef USE_STDLIB_H
+#include <stdlib.h>
+#else
+
+/* Some programs include files from other packages that also declare
+ * malloc.  Avoid double declaration by #define NO_DECLARE_MALLOC
+ * before including this file.
+ */
+#ifndef NO_DECLARE_MALLOC
+#ifdef USE_PROTOTYPES
+#   include <sys/types.h>	/* For size_t. */
+    extern void_star malloc( size_t );
+    extern void_star calloc( size_t, size_t );
+    extern void_star realloc( void_star, size_t );
+    extern void free( void_star );
+#else
+    extern void_star malloc();
+    extern void_star realloc();
+    extern void_star calloc();
+    extern void free();
+    extern void cfree();
+#endif /* USE_PROTOTYPES */
+#endif /* NO_DECLARE_MALLOC */
+
+#ifdef USE_PROTOTYPES
+extern char *getenv( CONST_DECL char *name );
+#else
+extern char *getenv();
+#endif
+
+#endif /* USE_STDLIB_H */
+
+#ifdef NEED_BSTRING
+    /* From bstring.c. */
+    /*****************************************************************
+     * TAG( bstring bzero )
+     * 'Byte string' functions.
+     */
+#   define bzero( _str, _n )		memset( _str, '\0', _n )
+#   define bcopy( _from, _to, _count )	memcpy( _to, _from, _count )
+#endif
+
+#ifdef NEED_SETLINEBUF
+#   define setlinebuf( _s )	setvbuf( (_s), NULL, _IOLBF, 0 )
+#endif
diff --git a/urt/rle_error.c b/urt/rle_error.c
new file mode 100644
index 00000000..acaca1a6
--- /dev/null
+++ b/urt/rle_error.c
@@ -0,0 +1,118 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ */
+/* 
+ * rle_error.c - Error message stuff for URT.
+ * 
+ * Author:	Spencer W. Thomas
+ * 		EECS Dept.
+ * 		University of Michigan
+ * Date:	Mon Mar  2 1992
+ * Copyright (c) 1992, University of Michigan
+ */
+
+#include <string.h>
+
+#include "rle.h"
+
+/*****************************************************************
+ * TAG( rle_alloc_error )
+ * 
+ * Print memory allocation error message and exit.
+ * Inputs:
+ * 	pgm:		Name of this program.
+ * 	name:		Name of memory trying to be allocated.
+ * Outputs:
+ * 	Prints message and exits.
+ *
+ * Returns int because it's used in a conditional expression.
+ */
+int
+rle_alloc_error( pgm, name )
+CONST_DECL char *pgm, *name;
+{
+    if ( name )
+	fprintf( stderr, "%s: memory allocation failed.\n", pgm );
+    else
+	fprintf( stderr, "%s: memory allocation failed (no space for %s).\n",
+		 pgm, name );
+
+    exit( RLE_NO_SPACE );
+
+    /* Will some compilers bitch about this because they know exit
+     * doesn't return??
+     */
+    return 0;
+}
+
+/*****************************************************************
+ * TAG( rle_get_error )
+ * 
+ * Print an error message for the return code from rle_get_setup
+ * Inputs:
+ * 	code:		The return code from rle_get_setup.
+ *	pgmname:	Name of this program (argv[0]).
+ *	fname:		Name of the input file.
+ * Outputs:
+ * 	Prints an error message on standard output.
+ *	Returns code.
+ */
+int
+rle_get_error( code, pgmname, fname )
+int code;
+CONST_DECL char *pgmname;
+CONST_DECL char *fname;
+{
+    if (! fname || strcmp( fname, "-" ) == 0 )
+	fname = "Standard Input";
+
+    switch( code )
+    {
+    case RLE_SUCCESS:		/* success */
+	break;
+
+    case RLE_NOT_RLE:		/* Not an RLE file */
+	fprintf( stderr, "%s: %s is not an RLE file\n",
+		 pgmname, fname );
+	break;
+
+    case RLE_NO_SPACE:			/* malloc failed */
+	fprintf( stderr,
+		 "%s: Malloc failed reading header of file %s\n",
+		 pgmname, fname );
+	break;
+
+    case RLE_EMPTY:
+	fprintf( stderr, "%s: %s is an empty file\n",
+		 pgmname, fname );
+	break;
+
+    case RLE_EOF:
+	fprintf( stderr,
+		 "%s: RLE header of %s is incomplete (premature EOF)\n",
+		 pgmname, fname );
+	break;
+
+    default:
+	fprintf( stderr, "%s: Error encountered reading header of %s\n",
+		 pgmname, fname );
+	break;
+    }
+    return code;
+}
+
+
diff --git a/urt/rle_getcom.c b/urt/rle_getcom.c
new file mode 100644
index 00000000..20da56a9
--- /dev/null
+++ b/urt/rle_getcom.c
@@ -0,0 +1,99 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ */
+/* 
+ * rle_getcom.c - Get specific comments from the_hdr structure.
+ * 
+ * Author:	Spencer W. Thomas
+ * 		Computer Science Dept.
+ * 		University of Utah
+ * Date:	Sun Jan 25 1987
+ * Copyright (c) 1987, University of Utah
+ */
+
+#include <stdio.h>
+#include "rle.h"
+
+/*****************************************************************
+ * TAG( match )
+ * 
+ * Match a name against a test string for "name=value" or "name".
+ * If it matches name=value, return pointer to value part, if just
+ * name, return pointer to NUL at end of string.  If no match, return NULL.
+ *
+ * Inputs:
+ * 	n:	Name to match.  May also be "name=value" to make it easier
+ *		to replace comments.
+ *	v:	Test string.
+ * Outputs:
+ * 	Returns pointer as above.
+ * Assumptions:
+ *	[None]
+ * Algorithm:
+ *	[None]
+ */
+static const char *
+match(const char * const nArg,
+      const char * const vArg) {
+
+    const char * n;
+    const char * v;
+
+    for (n = nArg, v = vArg; *n != '\0' && *n != '=' && *n == *v; n++, v++)
+        ;
+    if (*n == '\0' || *n == '=') {
+        if (*v == '\0')
+            return v;
+        else if (*v == '=')
+            return ++v;
+    }
+    return NULL;
+}
+
+
+
+/*****************************************************************
+ * TAG( rle_getcom )
+ * 
+ * Return a pointer to the value part of a name=value pair in the comments.
+ * Inputs:
+ * 	name:		Name part of the comment to search for.
+ *	the_hdr:	rle_dflt_hdr structure.
+ * Outputs:
+ * 	Returns pointer to value part of comment or NULL if no match.
+ * Assumptions:
+ *	[None]
+ * Algorithm:
+ *	[None]
+ */
+const char *
+rle_getcom(const char * const name,
+           rle_hdr *    const the_hdr) {
+
+    const char ** cp;
+
+    if (the_hdr->comments == NULL)
+        return NULL;
+
+    for (cp = the_hdr->comments; *cp; ++cp) {
+        const char * const v = match(name, *cp);
+        if (v != NULL )
+            return v;
+    }
+    return NULL;
+}
+
diff --git a/urt/rle_getrow.c b/urt/rle_getrow.c
new file mode 100644
index 00000000..fadf5441
--- /dev/null
+++ b/urt/rle_getrow.c
@@ -0,0 +1,562 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ *
+ *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
+ *  to have all "void" functions so declared.
+ */
+/* 
+ * rle_getrow.c - Read an RLE file in.
+ * 
+ * Author:  Spencer W. Thomas
+ *      Computer Science Dept.
+ *      University of Utah
+ * Date:    Wed Apr 10 1985
+ * Copyright (c) 1985 Spencer W. Thomas
+ * 
+ * $Id: rle_getrow.c,v 3.0.1.5 1992/03/04 19:33:08 spencer Exp spencer $
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "pm.h"
+#include "mallocvar.h"
+
+#include "rle.h"
+#include "rle_code.h"
+#include "vaxshort.h"
+
+/* Read a two-byte "short" that started in VAX (LITTLE_ENDIAN) order */
+#define VAXSHORT( var, fp )\
+    { var = fgetc(fp)&0xFF; var |= (fgetc(fp)) << 8; }
+  
+/* Instruction format -- first byte is opcode, second is datum. */
+
+#define OPCODE(inst) (inst[0] & ~LONG)
+#define LONGP(inst) (inst[0] & LONG)
+#define DATUM(inst) (inst[1] & 0xff)    /* Make sure it's unsigned. */
+
+static int     debug_f;     /* If non-zero, print debug info. */
+
+/*****************************************************************
+ * TAG( rle_get_setup )
+ * 
+ * Read the initialization information from an RLE file.
+ * Inputs:
+ *  the_hdr:    Contains pointer to the input file.
+ * Outputs:
+ *  the_hdr:    Initialized with information from the
+ *          input file.
+ *  Returns 0 on success, -1 if the file is not an RLE file,
+ *  -2 if malloc of the color map failed, -3 if an immediate EOF
+ *  is hit (empty input file), and -4 if an EOF is encountered reading
+ *  the setup information.
+ * Assumptions:
+ *  infile points to the "magic" number in an RLE file (usually
+ * byte 0 in the file).
+ * Algorithm:
+ *  Read in the setup info and fill in the_hdr.
+ */
+int
+rle_get_setup(rle_hdr * const the_hdr) {
+    struct XtndRsetup setup;
+    short magic;
+    FILE * infile = the_hdr->rle_file;
+    int i;
+    char * comment_buf;
+    
+    /* Clear old stuff out of the header. */
+    rle_hdr_clear( the_hdr );
+    if ( the_hdr->is_init != RLE_INIT_MAGIC )
+        rle_names( the_hdr, "Urt", "some file", 0 );
+    the_hdr->img_num++;     /* Count images. */
+
+    VAXSHORT( magic, infile );
+    if ( feof( infile ) )
+        return RLE_EMPTY;
+    if ( magic != RLE_MAGIC )
+        return RLE_NOT_RLE;
+    fread( &setup, 1, SETUPSIZE, infile );  /* assume VAX packing */
+    if ( feof( infile ) )
+        return RLE_EOF;
+
+    /* Extract information from setup */
+    the_hdr->ncolors = setup.h_ncolors;
+    for ( i = 0; i < the_hdr->ncolors; i++ )
+        RLE_SET_BIT( *the_hdr, i );
+
+    if ( !(setup.h_flags & H_NO_BACKGROUND) && setup.h_ncolors > 0 )
+    {
+        rle_pixel * bg_color;
+
+        MALLOCARRAY(the_hdr->bg_color, setup.h_ncolors);
+        MALLOCARRAY(bg_color, 1 + (setup.h_ncolors / 2) * 2);
+        RLE_CHECK_ALLOC( the_hdr->cmd, the_hdr->bg_color && bg_color,
+                         "background color" );
+        fread( (char *)bg_color, 1, 1 + (setup.h_ncolors / 2) * 2, infile );
+        for ( i = 0; i < setup.h_ncolors; i++ )
+            the_hdr->bg_color[i] = bg_color[i];
+        free( bg_color );
+    }
+    else
+    {
+        (void)getc( infile );   /* skip filler byte */
+        the_hdr->bg_color = NULL;
+    }
+
+    if ( setup.h_flags & H_NO_BACKGROUND )
+        the_hdr->background = 0;
+    else if ( setup.h_flags & H_CLEARFIRST )
+        the_hdr->background = 2;
+    else
+        the_hdr->background = 1;
+    if ( setup.h_flags & H_ALPHA )
+    {
+        the_hdr->alpha = 1;
+        RLE_SET_BIT( *the_hdr, RLE_ALPHA );
+    }
+    else
+        the_hdr->alpha = 0;
+
+    the_hdr->xmin = vax_gshort( setup.hc_xpos );
+    the_hdr->ymin = vax_gshort( setup.hc_ypos );
+    the_hdr->xmax = the_hdr->xmin + vax_gshort( setup.hc_xlen ) - 1;
+    the_hdr->ymax = the_hdr->ymin + vax_gshort( setup.hc_ylen ) - 1;
+
+    the_hdr->ncmap = setup.h_ncmap;
+    the_hdr->cmaplen = setup.h_cmaplen;
+    if ( the_hdr->ncmap > 0 )
+    {
+        int const maplen = the_hdr->ncmap * (1 << the_hdr->cmaplen);
+        int i;
+        char *maptemp;
+
+        MALLOCARRAY(the_hdr->cmap, maplen);
+        MALLOCARRAY(maptemp, 2 * maplen);
+        if ( the_hdr->cmap == NULL || maptemp == NULL )
+        {
+            pm_error("Malloc failed for color map of size %d*%d "
+                     "in rle_get_setup, reading '%s'",
+                     the_hdr->ncmap, (1 << the_hdr->cmaplen),
+                     the_hdr->file_name );
+            return RLE_NO_SPACE;
+        }
+        fread( maptemp, 2, maplen, infile );
+        for ( i = 0; i < maplen; i++ )
+            the_hdr->cmap[i] = vax_gshort( &maptemp[i * 2] );
+        free( maptemp );
+    }
+
+    /* Check for comments */
+    if ( setup.h_flags & H_COMMENT )
+    {
+        short comlen, evenlen;
+        register char * cp;
+
+        VAXSHORT( comlen, infile ); /* get comment length */
+        evenlen = (comlen + 1) & ~1;    /* make it even */
+        if ( evenlen )
+        {
+            MALLOCARRAY(comment_buf, evenlen);
+    
+            if ( comment_buf == NULL )
+            {
+                pm_error("Malloc failed for comment buffer of size %d "
+                         "in rle_get_setup, reading '%s'",
+                         comlen, the_hdr->file_name );
+                return RLE_NO_SPACE;
+            }
+            fread( comment_buf, 1, evenlen, infile );
+            /* Count the comments */
+            for ( i = 0, cp = comment_buf; cp < comment_buf + comlen; cp++ )
+                if ( *cp == 0 )
+                    i++;
+            i++;            /* extra for NULL pointer at end */
+            /* Get space to put pointers to comments */
+            MALLOCARRAY(the_hdr->comments, i);
+            if ( the_hdr->comments == NULL )
+            {
+                pm_error("Malloc failed for %d comment pointers "
+                         "in rle_get_setup, reading '%s'",
+                         i, the_hdr->file_name );
+                return RLE_NO_SPACE;
+            }
+            /* Get pointers to the comments */
+            *the_hdr->comments = comment_buf;
+            for ( i = 1, cp = comment_buf + 1;
+                  cp < comment_buf + comlen;
+                  cp++ )
+                if ( *(cp - 1) == 0 )
+                    the_hdr->comments[i++] = cp;
+            the_hdr->comments[i] = NULL;
+        }
+        else
+            the_hdr->comments = NULL;
+    }
+    else
+        the_hdr->comments = NULL;
+
+    /* Initialize state for rle_getrow */
+    the_hdr->priv.get.scan_y = the_hdr->ymin;
+    the_hdr->priv.get.vert_skip = 0;
+    the_hdr->priv.get.is_eof = 0;
+    the_hdr->priv.get.is_seek = ftell( infile ) > 0;
+    debug_f = 0;
+
+    if ( !feof( infile ) )
+        return RLE_SUCCESS; /* success! */
+    else
+    {
+        the_hdr->priv.get.is_eof = 1;
+        return RLE_EOF;
+    }
+}
+
+
+/*****************************************************************
+ * TAG( rle_get_setup_ok )
+ * 
+ * Read the initialization information from an RLE file.
+ * Inputs:
+ *  the_hdr:    Contains pointer to the input file.
+ *  prog_name:  Program name to be printed in the error message.
+ *      file_name:  File name to be printed in the error message.
+ *                  If NULL, the string "stdin" is generated.
+ * Outputs:
+ *  the_hdr:    Initialized with information from the
+ *          input file.
+ *      If reading the header fails, it prints an error message
+ *  and exits with the appropriate status code.
+ * Algorithm:
+ *  rle_get_setup does all the work.
+ */
+void
+rle_get_setup_ok( the_hdr, prog_name, file_name )
+rle_hdr * the_hdr;
+const char *prog_name;
+const char *file_name;
+{
+    int code;
+
+    /* Backwards compatibility: if is_init is not properly set, 
+     * initialize the header.
+     */
+    if ( the_hdr->is_init != RLE_INIT_MAGIC )
+    {
+    FILE *f = the_hdr->rle_file;
+    rle_hdr_init( the_hdr );
+    the_hdr->rle_file = f;
+    rle_names( the_hdr, prog_name, file_name, 0 );
+    }
+
+    code = rle_get_error( rle_get_setup( the_hdr ),
+              the_hdr->cmd, the_hdr->file_name );
+    if (code)
+    exit( code );
+}
+
+
+/*****************************************************************
+ * TAG( rle_debug )
+ * 
+ * Turn RLE debugging on or off.
+ * Inputs:
+ *  on_off:     if 0, stop debugging, else start.
+ * Outputs:
+ *  Sets internal debug flag.
+ * Assumptions:
+ *  [None]
+ * Algorithm:
+ *  [None]
+ */
+void
+rle_debug( on_off )
+int on_off;
+{
+    debug_f = on_off;
+
+    /* Set line buffering on stderr.  Character buffering is the default, and
+     * it is SLOOWWW for large amounts of output.
+     */
+    setvbuf( stderr, NULL, _IOLBF, 0);
+/*
+    setlinebuf( stderr );
+*/
+}
+
+
+/*****************************************************************
+ * TAG( rle_getrow )
+ * 
+ * Get a scanline from the input file.
+ * Inputs:
+ *  the_hdr:    Header structure containing information about 
+ *          the input file.
+ * Outputs:
+ *  scanline:   an array of pointers to the individual color
+ *          scanlines.  Scanline is assumed to have
+ *          the_hdr->ncolors pointers to arrays of rle_pixel,
+ *          each of which is at least the_hdr->xmax+1 long.
+ *  Returns the current scanline number.
+ * Assumptions:
+ *  rle_get_setup has already been called.
+ * Algorithm:
+ *  If a vertical skip is being executed, and clear-to-background is
+ *  specified (the_hdr->background is true), just set the
+ *  scanlines to the background color.  If clear-to-background is
+ *  not set, just increment the scanline number and return.
+ * 
+ *  Otherwise, read input until a vertical skip is encountered,
+ *  decoding the instructions into scanline data.
+ *
+ *  If ymax is reached (or, somehow, passed), continue reading and
+ *  discarding input until end of image.
+ */
+int
+rle_getrow( the_hdr, scanline )
+rle_hdr * the_hdr;
+rle_pixel *scanline[];
+{
+    register rle_pixel * scanc;
+    register int nc;
+    register FILE *infile = the_hdr->rle_file;
+    int scan_x = the_hdr->xmin, /* current X position */
+        max_x = the_hdr->xmax,  /* End of the scanline */
+       channel = 0;         /* current color channel */
+    int ns;         /* Number to skip */
+    short word, long_data;
+    char inst[2];
+
+    /* Clear to background if specified */
+    if ( the_hdr->background != 1 )
+    {
+    if ( the_hdr->alpha && RLE_BIT( *the_hdr, -1 ) )
+        memset( (char *)scanline[-1] + the_hdr->xmin, 0,
+           the_hdr->xmax - the_hdr->xmin + 1 );
+    for ( nc = 0; nc < the_hdr->ncolors; nc++ )
+        if ( RLE_BIT( *the_hdr, nc ) ) {
+        /* Unless bg color given explicitly, use 0. */
+        if ( the_hdr->background != 2 || the_hdr->bg_color[nc] == 0 )
+            memset( (char *)scanline[nc] + the_hdr->xmin, 0,
+               the_hdr->xmax - the_hdr->xmin + 1 );
+        else
+            memset((char *)scanline[nc] + the_hdr->xmin,
+                   the_hdr->bg_color[nc],
+                   the_hdr->xmax - the_hdr->xmin + 1);
+        }
+    }
+
+    /* If skipping, then just return */
+    if ( the_hdr->priv.get.vert_skip > 0 )
+    {
+    the_hdr->priv.get.vert_skip--;
+    the_hdr->priv.get.scan_y++;
+    if ( the_hdr->priv.get.vert_skip > 0 ) {
+        if ( the_hdr->priv.get.scan_y >= the_hdr->ymax )
+        {
+        int y = the_hdr->priv.get.scan_y;
+        while ( rle_getskip( the_hdr ) != 32768 )
+            ;
+        return y;
+        }
+        else
+        return the_hdr->priv.get.scan_y;
+    }
+    }
+
+    /* If EOF has been encountered, return also */
+    if ( the_hdr->priv.get.is_eof )
+    return ++the_hdr->priv.get.scan_y;
+
+    /* Otherwise, read and interpret instructions until a skipLines
+     * instruction is encountered.
+     */
+    if ( RLE_BIT( *the_hdr, channel ) )
+    scanc = scanline[channel] + scan_x;
+    else
+    scanc = NULL;
+    for (;;)
+    {
+    inst[0] = getc( infile );
+    inst[1] = getc( infile );
+    if ( feof(infile) )
+    {
+        the_hdr->priv.get.is_eof = 1;
+        break;      /* <--- one of the exits */
+    }
+
+    switch( OPCODE(inst) )
+    {
+    case RSkipLinesOp:
+        if ( LONGP(inst) )
+        {
+        VAXSHORT( the_hdr->priv.get.vert_skip, infile );
+        }
+        else
+        the_hdr->priv.get.vert_skip = DATUM(inst);
+        if (debug_f)
+        fprintf(stderr, "Skip %d Lines (to %d)\n",
+            the_hdr->priv.get.vert_skip,
+            the_hdr->priv.get.scan_y +
+                the_hdr->priv.get.vert_skip );
+
+        break;          /* need to break for() here, too */
+
+    case RSetColorOp:
+        channel = DATUM(inst);  /* select color channel */
+        if ( channel == 255 )
+        channel = -1;
+        scan_x = the_hdr->xmin;
+        if ( RLE_BIT( *the_hdr, channel ) )
+        scanc = scanline[channel]+scan_x;
+        if ( debug_f )
+        fprintf( stderr, "Set color to %d (reset x to %d)\n",
+             channel, scan_x );
+        break;
+
+    case RSkipPixelsOp:
+        if ( LONGP(inst) )
+        {
+        VAXSHORT( long_data, infile );
+        scan_x += long_data;
+        scanc += long_data;
+        if ( debug_f )
+            fprintf( stderr, "Skip %d pixels (to %d)\n",
+                long_data, scan_x );
+        }
+        else
+        {
+        scan_x += DATUM(inst);
+        scanc += DATUM(inst);
+        if ( debug_f )
+            fprintf( stderr, "Skip %d pixels (to %d)\n",
+                DATUM(inst), scan_x );
+        }
+        break;
+
+    case RByteDataOp:
+        if ( LONGP(inst) )
+        {
+        VAXSHORT( nc, infile );
+        }
+        else
+        nc = DATUM(inst);
+        nc++;
+        if ( debug_f ) {
+        if ( RLE_BIT( *the_hdr, channel ) )
+            fprintf( stderr, "Pixel data %d (to %d):", nc, scan_x+nc );
+        else
+            fprintf( stderr, "Pixel data %d (to %d)\n", nc, scan_x+nc);
+        }
+        if ( RLE_BIT( *the_hdr, channel ) )
+        {
+        /* Don't fill past end of scanline! */
+        if ( scan_x + nc > max_x )
+        {
+            ns = scan_x + nc - max_x - 1;
+            nc -= ns;
+        }
+        else
+            ns = 0;
+        fread( (char *)scanc, 1, nc, infile );
+        while ( ns-- > 0 )
+            (void)getc( infile );
+        if ( nc & 1 )
+            (void)getc( infile );   /* throw away odd byte */
+        }
+        else
+        if ( the_hdr->priv.get.is_seek )
+            fseek( infile, ((nc + 1) / 2) * 2, 1 );
+        else
+        {
+            register int ii;
+            for ( ii = ((nc + 1) / 2) * 2; ii > 0; ii-- )
+            (void) getc( infile );  /* discard it */
+        }
+
+        scanc += nc;
+        scan_x += nc;
+        if ( debug_f && RLE_BIT( *the_hdr, channel ) )
+        {
+        rle_pixel * cp = scanc - nc;
+        for ( ; nc > 0; nc-- )
+            fprintf( stderr, "%02x", *cp++ );
+        putc( '\n', stderr );
+        }
+        break;
+
+    case RRunDataOp:
+        if ( LONGP(inst) )
+        {
+        VAXSHORT( nc, infile );
+        }
+        else
+        nc = DATUM(inst);
+        nc++;
+        scan_x += nc;
+
+        VAXSHORT( word, infile );
+        if ( debug_f )
+        fprintf( stderr, "Run length %d (to %d), data %02x\n",
+                nc, scan_x, word );
+        if ( RLE_BIT( *the_hdr, channel ) )
+        {
+        if ( scan_x > max_x )
+        {
+            ns = scan_x - max_x - 1;
+            nc -= ns;
+        } 
+        else
+            ns = 0;
+        if ( nc >= 10 )     /* break point for 785, anyway */
+        {
+            memset((char *)scanc, word, nc);
+            scanc += nc;
+        }
+        else
+            for ( nc--; nc >= 0; nc--, scanc++ )
+            *scanc = word;
+        }
+        break;
+
+    case REOFOp:
+        the_hdr->priv.get.is_eof = 1;
+        if ( debug_f )
+        fprintf( stderr, "End of Image\n" );
+        break;
+
+    default:
+        fprintf( stderr,
+             "%s: rle_getrow: Unrecognized opcode: %d, reading %s\n",
+             the_hdr->cmd, inst[0], the_hdr->file_name );
+        exit(1);
+    }
+    if ( OPCODE(inst) == RSkipLinesOp || OPCODE(inst) == REOFOp )
+        break;          /* <--- the other loop exit */
+    }
+
+    /* If at end, skip the rest of a malformed image. */
+    if ( the_hdr->priv.get.scan_y >= the_hdr->ymax )
+    {
+    int y = the_hdr->priv.get.scan_y;
+    while ( rle_getskip( the_hdr ) != 32768 )
+        ;
+    return y;
+    }
+
+    return the_hdr->priv.get.scan_y;
+}
diff --git a/urt/rle_getskip.c b/urt/rle_getskip.c
new file mode 100644
index 00000000..f1c333e7
--- /dev/null
+++ b/urt/rle_getskip.c
@@ -0,0 +1,162 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ */
+/* 
+ * rle_getskip.c - Skip scanlines on input.
+ * 
+ * Author:	Spencer W. Thomas
+ * 		EECS Dept.
+ * 		University of Michigan
+ * Date:	Wed Jun 27 1990
+ * Copyright (c) 1990, University of Michigan
+ */
+
+#include "rle.h"
+#include "rle_code.h"
+
+/* Read a two-byte "short" that started in VAX (LITTLE_ENDIAN) order */
+#define VAXSHORT( var, fp )\
+	{ var = fgetc(fp)&0xFF; var |= (fgetc(fp)) << 8; }
+  
+/* Instruction format -- first byte is opcode, second is datum. */
+
+#define OPCODE(inst) (inst[0] & ~LONG)
+#define LONGP(inst) (inst[0] & LONG)
+#define DATUM(inst) (inst[1] & 0xff)	/* Make sure it's unsigned. */
+
+/*****************************************************************
+ * TAG( rle_getskip )
+ * 
+ * Skip the next scanline with data on it.
+ * Most useful for skipping to end-of-image.
+ * Inputs:
+ * 	the_hdr:	Describes input image.
+ * Outputs:
+ * 	Returns the number of the next scanline.  At EOF returns 32768.
+ * Assumptions:
+ * 	rle_get_setup has been called.
+ * Algorithm:
+ * 	Read input to the beginning of the next scanline, or to EOF or
+ * 	end of image.
+ */
+unsigned int
+rle_getskip( the_hdr )
+rle_hdr *the_hdr;
+{
+    unsigned char inst[2];
+    register FILE *infile = the_hdr->rle_file;
+    int nc;
+
+    /* Add in vertical skip from last scanline */
+    if ( the_hdr->priv.get.vert_skip > 0) 
+	the_hdr->priv.get.scan_y += the_hdr->priv.get.vert_skip;
+    the_hdr->priv.get.vert_skip = 0;
+
+    if ( the_hdr->priv.get.is_eof )
+	return 32768;		/* too big for 16 bits, signal EOF */
+    
+    /* Otherwise, read and interpret instructions until a skipLines
+     * instruction is encountered.
+     */
+    for (;;)
+    {
+        inst[0] = getc( infile );
+	inst[1] = getc( infile );
+	if ( feof(infile) )
+	{
+	    the_hdr->priv.get.is_eof = 1;
+	    break;		/* <--- one of the exits */
+	}
+
+	switch( OPCODE(inst) )
+	{
+	case RSkipLinesOp:
+	    if ( LONGP(inst) )
+	    {
+		VAXSHORT( the_hdr->priv.get.vert_skip, infile );
+	    }
+	    else
+		the_hdr->priv.get.vert_skip = DATUM(inst);
+	    break;			/* need to break for() here, too */
+
+	case RSetColorOp:
+	    /* No-op here. */
+	    break;
+
+	case RSkipPixelsOp:
+	    if ( LONGP(inst) )
+	    {
+		(void)getc( infile );
+		(void)getc( infile );
+	    }
+	    break;
+
+	case RByteDataOp:
+	    if ( LONGP(inst) )
+	    {
+	        VAXSHORT( nc, infile );
+	    }
+	    else
+		nc = DATUM(inst);
+	    nc++;
+	    if ( the_hdr->priv.get.is_seek )
+		fseek( infile, ((nc + 1) / 2) * 2, 1 );
+	    else
+	    {
+		register int ii;
+		for ( ii = ((nc + 1) / 2) * 2; ii > 0; ii-- )
+		    (void) getc( infile );	/* discard it */
+	    }
+
+	    break;
+
+	case RRunDataOp:
+	    if ( LONGP(inst) )
+	    {
+		(void)getc( infile );
+		(void)getc( infile );
+	    }
+	    (void)getc( infile );
+	    (void)getc( infile );
+	    break;
+
+	case REOFOp:
+	    the_hdr->priv.get.is_eof = 1;
+	    break;
+
+	default:
+	    fprintf( stderr,
+		     "%s: rle_getskip: Unrecognized opcode: %d, reading %s\n",
+		     the_hdr->cmd, OPCODE(inst), the_hdr->file_name );
+	    exit(1);
+	}
+	if ( OPCODE(inst) == REOFOp )
+	    break;			/* <--- the other loop exit */
+	if ( OPCODE(inst) == RSkipLinesOp )
+	    break;
+    }
+
+    /* Return the number of the NEXT scanline. */
+    the_hdr->priv.get.scan_y +=
+	the_hdr->priv.get.vert_skip;
+    the_hdr->priv.get.vert_skip = 0;
+
+    if ( the_hdr->priv.get.is_eof )
+	return 32768;		/* too big for 16 bits, signal EOF */
+    else
+	return the_hdr->priv.get.scan_y;
+}
diff --git a/urt/rle_global.c b/urt/rle_global.c
new file mode 100644
index 00000000..90d3f975
--- /dev/null
+++ b/urt/rle_global.c
@@ -0,0 +1,85 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ *
+ *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
+ *  to have all "void" functions so declared.
+ */
+/* 
+ * rle_global.c - Global variable initialization for rle routines.
+ * 
+ * Author:	Spencer W. Thomas
+ * 		Computer Science Dept.
+ * 		University of Utah
+ * Date:	Thu Apr 25 1985
+ * Copyright (c) 1985,1986 Spencer W. Thomas
+ * 
+ * $Id: rle_global.c,v 3.0.1.1 1992/01/28 18:23:03 spencer Exp $
+ */
+
+#include <stdio.h>
+#include "rle_put.h"
+#include "rle.h"
+#include "Runput.h"
+
+struct rle_dispatch_tab rle_DTable[] = {
+    {
+	" OB",
+	RunSetup,
+	RunSkipBlankLines,
+	RunSetColor,
+	RunSkipPixels,
+	RunNewScanLine,
+	Runputdata,
+	Runputrun,
+	DefaultBlockHook,
+	RunputEof
+    },
+};
+
+static int bg_color[3] = { 0, 0, 0 };
+
+rle_hdr rle_dflt_hdr = {
+    RUN_DISPATCH,		/* dispatch value */
+    3,				/* 3 colors */
+    bg_color,			/* background color */
+    0,				/* (alpha) if 1, save alpha channel */
+    2,				/* (background) 0->just save pixels, */
+				/* 1->overlay, 2->clear to bg first */
+    0, 511,			/* (xmin, xmax) X bounds to save */
+    0, 511,			/* (ymin, ymax) Y bounds to save */
+    0,				/* ncmap (if != 0, save color map) */
+    8,				/* cmaplen (log2 of length of color map) */
+    NULL,			/* pointer to color map */
+    NULL,			/* pointer to comment strings */
+    NULL,			/* output file -- must be set dynamically */
+    { 7 },			/* RGB channels only */
+    0L,				/* Can't free name and file fields. */
+    "Urt",			/* Default "program name". */
+    "no file",			/* No file name given. */
+    0				/* First image. */
+    /* Can't initialize the union */
+};
+
+#if 0
+/* ARGSUSED */
+void
+NullputEof(the_hdr)
+rle_hdr * the_hdr;
+{
+				/* do nothing */
+}
+#endif
diff --git a/urt/rle_hdr.c b/urt/rle_hdr.c
new file mode 100644
index 00000000..3cc0401d
--- /dev/null
+++ b/urt/rle_hdr.c
@@ -0,0 +1,297 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ */
+/* 
+ * rle_hdr.c - Functions to manipulate rle_hdr structures.
+ * 
+ * Author:	Spencer W. Thomas
+ * 		EECS Dept.
+ * 		University of Michigan
+ * Date:	Mon May 20 1991
+ * Copyright (c) 1991, University of Michigan
+ */
+
+#include "rle.h"
+
+#include <string.h>
+
+/*****************************************************************
+ * TAG( rle_names )
+ *
+ * Load program and file names into header.
+ * Inputs:
+ * 	the_hdr:	Header to modify.
+ * 	pgmname:	The program name.
+ * 	fname:		The file name.
+ * 	img_num:	Number of the image within the file.
+ * Outputs:
+ * 	the_hdr:	Modified header.
+ * Algorithm:
+ * 	If values previously filled in (by testing is_init field),
+ * 	free them.  Make copies of file name and program name,
+ * 	modifying file name for standard i/o.  Set is_init field.
+ */
+void
+rle_names( the_hdr, pgmname, fname, img_num )
+rle_hdr *the_hdr;
+CONST_DECL char *pgmname;
+CONST_DECL char *fname;
+int img_num;
+{
+#if 0
+    /* Can't do this because people do hdr1 = hdr2, which copies
+       the pointers. */
+
+    /* If filled in, free previous values. */
+    if ( the_hdr->is_init == RLE_INIT_MAGIC &&
+	 the_hdr->cmd != NULL && the_hdr->file_name != NULL )
+    {
+	if ( pgmname != the_hdr->cmd )
+	    free( the_hdr->cmd );
+	if ( fname != the_hdr->file_name )
+	    free( the_hdr->file_name );
+    }
+#endif
+
+    /* Mark as filled in. */
+    the_hdr->is_init = RLE_INIT_MAGIC;
+
+    /* Default file name for stdin/stdout. */
+    if ( fname == NULL || strcmp( fname, "-" ) == 0 || *fname == '\0' )
+	fname = "Standard I/O";
+    if ( pgmname == NULL )
+	pgmname = rle_dflt_hdr.cmd;
+
+    /* Fill in with copies of the strings. */
+    if ( the_hdr->cmd != pgmname )
+    {
+	char *tmp = (char *)malloc( strlen( pgmname ) + 1 );
+	RLE_CHECK_ALLOC( pgmname, tmp, 0 );
+	strcpy( tmp, pgmname );
+	the_hdr->cmd = tmp;
+    }
+
+    if ( the_hdr->file_name != fname )
+    {
+	char *tmp = (char *)malloc( strlen( fname ) + 1 );
+	RLE_CHECK_ALLOC( pgmname, tmp, 0 );
+	strcpy( tmp, fname );
+	the_hdr->file_name = tmp;
+    }
+
+    the_hdr->img_num = img_num;
+}
+
+
+/* Used by rle_hdr_cp and rle_hdr_init to avoid recursion loops. */
+static int no_recurse = 0;
+
+/*****************************************************************
+ * TAG( rle_hdr_cp )
+ * 
+ * Make a "safe" copy of a rle_hdr structure.
+ * Inputs:
+ * 	from_hdr:	Header to be copied.
+ * Outputs:
+ * 	to_hdr:		Copy of from_hdr, with all memory referred to
+ * 			by pointers copied.  Also returned as function
+ * 			value.  If NULL, a static header is used.
+ * Assumptions:
+ * 	It is safe to call rle_hdr_init on to_hdr.
+ * Algorithm:
+ * 	Initialize to_hdr, copy from_hdr to it, then copy the memory
+ * 	referred to by all non-null pointers.
+ */
+rle_hdr *
+rle_hdr_cp( from_hdr, to_hdr )
+rle_hdr *from_hdr, *to_hdr;
+{
+    static rle_hdr dflt_hdr;
+    CONST_DECL char *cmd, *file;
+    int num;
+
+    /* Save command, file name, and image number if already initialized. */
+    if ( to_hdr &&  to_hdr->is_init == RLE_INIT_MAGIC )
+    {
+	cmd = to_hdr->cmd;
+	file = to_hdr->file_name;
+	num = to_hdr->img_num;
+    }
+    else
+    {
+	cmd = file = NULL;
+	num = 0;
+    }
+
+    if ( !no_recurse )
+    {
+	no_recurse++;
+	rle_hdr_init( to_hdr );
+	no_recurse--;
+    }
+
+    if ( to_hdr == NULL )
+	to_hdr = &dflt_hdr;
+
+    *to_hdr = *from_hdr;
+
+    if ( to_hdr->bg_color )
+    {
+	int size = to_hdr->ncolors * sizeof(int);
+	to_hdr->bg_color = (int *)malloc( size );
+	RLE_CHECK_ALLOC( to_hdr->cmd, to_hdr->bg_color, "background color" );
+	memcpy( to_hdr->bg_color, from_hdr->bg_color, size );
+    }
+
+    if ( to_hdr->cmap )
+    {
+	int size = to_hdr->ncmap * (1 << to_hdr->cmaplen) * sizeof(rle_map);
+	to_hdr->cmap = (rle_map *)malloc( size );
+	RLE_CHECK_ALLOC( to_hdr->cmd, to_hdr->cmap, "color map" );
+	memcpy( to_hdr->cmap, from_hdr->cmap, size );
+    }
+
+    /* Only copy array of pointers, as the original comment memory
+     * never gets overwritten.
+     */
+    if ( to_hdr->comments )
+    {
+	int size = 0;
+	CONST_DECL char **cp;
+	for ( cp=to_hdr->comments; *cp; cp++ )
+	    size++;		/* Count the comments. */
+	/* Check if there are really any comments. */
+	if ( size )
+	{
+	    size++;		/* Copy the NULL pointer, too. */
+	    size *= sizeof(char *);
+	    to_hdr->comments = (CONST_DECL char **)malloc( size );
+	    RLE_CHECK_ALLOC( to_hdr->cmd, to_hdr->comments, "comments" );
+	    memcpy( to_hdr->comments, from_hdr->comments, size );
+	}
+	else
+	    to_hdr->comments = NULL;	/* Blow off empty comment list. */
+    }
+
+    /* Restore the names to their original values. */
+    to_hdr->cmd = cmd;
+    to_hdr->file_name = file;
+
+    /* Lines above mean nothing much happens if cmd and file are != NULL. */
+    rle_names( to_hdr, to_hdr->cmd, to_hdr->file_name, num );
+
+    return to_hdr;
+}
+
+/*****************************************************************
+ * TAG( rle_hdr_clear )
+ * 
+ * Clear out the allocated memory pieces of a header.
+ *
+ * This routine is intended to be used internally by the library, to
+ * clear a header before putting new data into it.  It clears all the
+ * fields that would be set by reading in a new image header.
+ * Therefore, it does not clear the program and file names.
+ * 
+ * Inputs:
+ * 	the_hdr:	To be cleared.
+ * Outputs:
+ * 	the_hdr:	After clearing.
+ * Assumptions:
+ * 	If is_init field is RLE_INIT_MAGIC, the header has been
+ * 	properly initialized.  This will fail every 2^(-32) times, on
+ * 	average.
+ * Algorithm:
+ * 	Free memory and set to zero all pointers, except program and
+ * 	file name.
+ */
+void
+rle_hdr_clear( the_hdr )
+rle_hdr *the_hdr;
+{
+    /* Try to free memory.  Assume if is_init is properly set that this
+     * header has been previously initialized, therefore it is safe to
+     * free memory.
+     */
+    if ( the_hdr && the_hdr->is_init == RLE_INIT_MAGIC )
+    {
+	if ( the_hdr->bg_color )
+	    free( the_hdr->bg_color );
+	the_hdr->bg_color = 0;
+	if ( the_hdr->cmap )
+	    free( the_hdr->cmap );
+	the_hdr->cmap = 0;
+	/* Unfortunately, we don't know how to free the comment memory. */
+	if ( the_hdr->comments )
+	    free( the_hdr->comments );
+	the_hdr->comments = 0;
+    }
+}
+
+
+
+/*****************************************************************
+ * TAG( rle_hdr_init )
+ * 
+ * Initialize a rle_hdr structure.
+ * Inputs:
+ * 	the_hdr:	Header to be initialized.
+ * Outputs:
+ * 	the_hdr:	Initialized header.
+ * Assumptions:
+ * 	If the_hdr->is_init is RLE_INIT_MAGIC, the header has been
+ * 	previously initialized.
+ * 	If the_hdr is a copy of another rle_hdr structure, the copy
+ * 	was made with rle_hdr_cp.
+ * Algorithm:
+ *  Fill in fields of rle_dflt_hdr that could not be set by the loader
+ *	If the_hdr is rle_dflt_hdr, do nothing else
+ *  Else:
+ *	  If the_hdr is NULL, return a copy of rle_dflt_hdr in static storage
+ * 	  If the_hdr->is_init is RLE_INIT_MAGIC, free all memory
+ * 	     pointed to by non-null pointers.
+ *    If this is a recursive call to rle_hdr_init, clear *the_hdr and
+ *      return the_hdr.
+ *    Else make a copy of rle_dflt_hdr and return its address.  Make the
+ *      copy in static storage if the_hdr is NULL, and in the_hdr otherwise.
+ */
+rle_hdr *
+rle_hdr_init( the_hdr )
+rle_hdr *the_hdr;
+{
+    rle_hdr *ret_hdr;
+
+    rle_dflt_hdr.rle_file = stdout;
+    /* The rest of rle_dflt_hdr is set by the loader's data initialization */
+
+    if ( the_hdr == &rle_dflt_hdr )
+	return the_hdr;
+
+    rle_hdr_clear( the_hdr );
+
+    /* Only call rle_hdr_cp if not called from there. */
+    if ( !no_recurse )
+    {
+	no_recurse++;
+	ret_hdr = rle_hdr_cp( &rle_dflt_hdr, the_hdr );
+	no_recurse--;
+    }
+    else
+	ret_hdr = the_hdr;
+
+    return ret_hdr;
+}
diff --git a/urt/rle_open_f.c b/urt/rle_open_f.c
new file mode 100644
index 00000000..d2575c11
--- /dev/null
+++ b/urt/rle_open_f.c
@@ -0,0 +1,310 @@
+/* 
+ * rle_open_f.c - Open a file with defaults.
+ * 
+ * Author : 	Jerry Winters 
+ * 		EECS Dept.
+ * 		University of Michigan
+ * Date:	11/14/89
+ * Copyright (c) 1990, University of Michigan
+ */
+
+#define _XOPEN_SOURCE  /* Make sure fdopen() is in stdio.h */
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifndef NO_OPEN_PIPES
+/* Need to have a SIGCLD signal catcher. */
+#include <signal.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#include "rle.h"
+
+/* Count outstanding children.  Assume no more than 100 possible. */
+#define MAX_CHILDREN 100
+static int catching_children = 0;
+static int pids[MAX_CHILDREN];
+
+
+
+static FILE *
+my_popen(const char * const cmd, 
+         const char * const mode, 
+         int  *       const pid) {
+
+    FILE *retfile;
+    int thepid = 0;
+    int pipefd[2];
+    int i;
+
+    /* Check args. */
+    if ( *mode != 'r' && *mode != 'w' )
+    {
+	errno = EINVAL;
+	return NULL;
+    }
+
+    if ( pipe(pipefd) < 0 )
+	return NULL;
+    
+    /* Flush known files. */
+    fflush(stdout);
+    fflush(stderr);
+    if ( (thepid = fork()) < 0 )
+    {
+	close(pipefd[0]);
+	close(pipefd[1]);
+	return NULL;
+    }
+    else if (thepid == 0) {
+	/* In child. */
+	/* Rearrange file descriptors. */
+	if ( *mode == 'r' )
+	{
+	    /* Parent reads from pipe, so reset stdout. */
+	    close(1);
+	    dup2(pipefd[1],1);
+	} else {
+	    /* Parent writing to pipe. */
+	    close(0);
+	    dup2(pipefd[0],0);
+	}
+	/* Close anything above fd 2. (64 is an arbitrary magic number). */
+	for ( i = 3; i < 64; i++ )
+	    close(i);
+
+	/* Finally, invoke the program. */
+	if ( execl("/bin/sh", "sh", "-c", cmd, NULL) < 0 )
+	    exit(127);
+	/* NOTREACHED */
+    }	
+
+    /* Close file descriptors, and gen up a FILE ptr */
+    if ( *mode == 'r' )
+    {
+	/* Parent reads from pipe. */
+	close(pipefd[1]);
+	retfile = fdopen( pipefd[0], mode );
+    } else {
+	/* Parent writing to pipe. */
+	close(pipefd[0]);
+	retfile = fdopen( pipefd[1], mode );
+    }
+
+    /* Return the PID. */
+    *pid = thepid;
+
+    return retfile;
+}
+#endif  /* !NO_OPEN_PIPES */
+
+/* 
+ *  Purpose : Open a file for input or ouput as controlled by the mode
+ *  parameter.  If no file name is specified (ie. file_name is null) then
+ *  a pointer to stdin or stdout will be returned.  The calling routine may
+ *  call this routine with a file name of "-".  For this case rle_open_f
+ *  will return a pointer to stdin or stdout depending on the mode.
+ *    If the user specifies a non-null file name and an I/O error occurs
+ *  when trying to open the file, rle_open_f will terminate execution with
+ *  an appropiate error message.
+ *
+ *  parameters
+ *   input:
+ *     prog_name: 	name of the calling program.
+ *     file_name : 	name of the file to open
+ *     mode : 		either "r" for read or input file or "w" for write or
+ *            		output file
+ *
+ *   output:
+ *     a file pointer
+ * 
+ */
+FILE *
+rle_open_f_noexit(const char * const prog_name, 
+                  const char * const file_name, 
+                  const char * const mode ) {
+
+    FILE *fp;
+    void perror();
+    CONST_DECL char *err_str;
+    const char *cp;
+    char *combuf;
+
+    if ( *mode == 'w' || *mode == 'a' )
+        fp = stdout;     /* Set the default value */
+    else
+        fp = stdin;
+    
+    if ( file_name != NULL && strcmp( file_name, "-" ) != 0 )
+    {
+#ifndef NO_OPEN_PIPES
+        /* Check for dead children. */
+        if ( catching_children > 0 )
+        {
+            int i, j;
+
+            /* Check all children to see if any are dead, reap them if so. */
+            for ( i = 0; i < catching_children; i++ )
+            {
+                /* The assumption here is that if it's dead, the kill
+                 * will fail, but, because we haven't waited for
+                 * it yet, it's a zombie.
+                 */
+                if (kill(pids[i], 0) < 0) {
+                    int opid = pids[i], pid = 0;
+                    /* Wait for processes & delete them from the list,
+                     * until we get the one we know is dead.
+                     * When removing one earlier in the list than
+                     * the one we found, decrement our loop index.
+                     */
+                    while (pid != opid) {
+                        pid = wait( NULL );
+                        for ( j = 0;
+                              j < catching_children && pids[j] != pid;
+                              j++ )
+                            ;
+                        if ( pid < 0 )
+                            break;
+                        if ( j < catching_children ) {
+                            if ( i >= j )
+                                i--;
+                            for ( j++; j < catching_children; j++ )
+                                pids[j-1] = pids[j];
+                            catching_children--;
+                        }
+                    }
+                }
+            }
+        }
+
+        /*  Real file, not stdin or stdout.  If name ends in ".Z",
+         *  pipe from/to un/compress (depending on r/w mode).
+         *  
+         *  If it starts with "|", popen that command.
+         */
+	    
+        cp = file_name + strlen( (char*) file_name ) - 2;
+        /* Pipe case. */
+        if ( *file_name == '|' )
+        {
+            int thepid;		/* PID from my_popen */
+            if ( (fp = my_popen( file_name + 1, mode, &thepid )) == NULL )
+            {
+                err_str = "%s: can't invoke <<%s>> for %s: ";
+                goto err;
+            }
+            /* One more child to catch, eventually. */
+            if (catching_children < MAX_CHILDREN) {
+                pids[catching_children++] = thepid;
+            }
+        }
+
+        /* Compress case. */
+        else if ( cp > file_name && *cp == '.' && *(cp + 1) == 'Z' )
+        {
+            int thepid;		/* PID from my_popen. */
+            combuf = (char *)malloc( 20 + strlen( file_name ) );
+            if ( combuf == NULL )
+            {
+                err_str = "%s: out of memory opening (compressed) %s for %s";
+                goto err;
+            }
+
+            if ( *mode == 'w' )
+                sprintf( combuf, "compress > %s", file_name );
+            else if ( *mode == 'a' )
+                sprintf( combuf, "compress >> %s", file_name );
+            else
+                sprintf( combuf, "compress -d < %s", file_name );
+
+            fp = my_popen( combuf, mode, &thepid );
+            free( combuf );
+
+            if ( fp == NULL )
+            {
+                err_str =
+                    "%s: can't invoke 'compress' program, "
+                    "trying to open %s for %s";
+                goto err;
+            }
+            /* One more child to catch, eventually. */
+            if (catching_children < MAX_CHILDREN) {
+                pids[catching_children++] = thepid;
+            }
+        }
+        else
+#endif /* !NO_OPEN_PIPES */
+        {
+            /* Ordinary, boring file case. */
+            /* In the original code, the code to add the "b" was
+               conditionally included only if the macro STDIO_NEEDS_BINARY was
+               defined.  But for Netpbm, there is no need make a distinction;
+               we always add the "b".  -BJH 2000.07.20.  
+            */
+            char mode_string[32];	/* Should be enough. */
+
+            /* Concatenate a 'b' onto the mode. */
+            mode_string[0] = mode[0];
+            mode_string[1] = 'b';
+            strcpy( mode_string + 2, mode + 1 );
+        
+            if ( (fp = fopen(file_name, mode_string)) == NULL )
+            {
+                err_str = "%s: can't open %s for %s: ";
+                goto err;
+            }
+        }
+    }
+
+    return fp;
+
+err:
+	fprintf( stderr, err_str,
+             prog_name, file_name,
+             (*mode == 'w') ? "output" :
+             (*mode == 'a') ? "append" :
+             "input" );
+	perror( "" );
+	return NULL;
+
+}
+
+FILE *
+rle_open_f(const char * prog_name, const char * file_name, const char * mode)
+{
+    FILE *fp;
+
+    if ( (fp = rle_open_f_noexit( prog_name, file_name, mode )) == NULL )
+	exit( -1 );
+
+    return fp;
+}
+
+
+/*****************************************************************
+ * TAG( rle_close_f )
+ * 
+ * Close a file opened by rle_open_f.  If the file is stdin or stdout,
+ * it will not be closed.
+ * Inputs:
+ * 	fd:	File to close.
+ * Outputs:
+ * 	None.
+ * Assumptions:
+ * 	fd is open.
+ * Algorithm:
+ * 	If fd is NULL, just return.
+ * 	If fd is stdin or stdout, don't close it.  Otherwise, call fclose.
+ */
+void
+rle_close_f( fd )
+FILE *fd;
+{
+    if ( fd == NULL || fd == stdin || fd == stdout )
+	return;
+    else
+	fclose( fd );
+}
diff --git a/urt/rle_put.h b/urt/rle_put.h
new file mode 100644
index 00000000..d611b438
--- /dev/null
+++ b/urt/rle_put.h
@@ -0,0 +1,104 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ */
+/* 
+ * rle_put.h - Definitions and a few global variables for rle_putrow/putraw.
+ * 
+ * Author:	Spencer W. Thomas
+ * 		Computer Science Dept.
+ * 		University of Utah
+ * Date:	Mon Aug  9 1982
+ * Copyright (c) 1982 Spencer W. Thomas
+ * 
+ * $Id: rle_put.h,v 3.0.1.2 1992/02/27 21:14:35 spencer Exp $
+ */
+
+#include "rle.h"
+
+/* ****************************************************************
+ * Dispatch table for different output types.
+ */
+#ifdef __cplusplus        /* Cfront 2.0  or g++ */
+#ifndef c_plusplus
+#define c_plusplus        
+#endif
+extern "C" {
+#endif
+
+
+#ifdef c_plusplus
+#define ARB_ARGS ...
+#else
+#define ARB_ARGS
+#endif
+
+typedef int rle_fn( ARB_ARGS );
+
+struct rle_dispatch_tab {
+    CONST_DECL char   *magic;   /* magic type flags */
+    void (*setup)(rle_hdr * the_hdr);          /* startup function */
+    void (*skipBlankLines)(int nblank, rle_hdr * the_hdr);
+    void(*setColor)(int c, rle_hdr * the_hdr);
+    void(*skipPixels)(int nskip, int last, int wasrun, rle_hdr * the_hdr);
+    void(*newScanLine)(int flag, rle_hdr * the_hdr);
+    void(*putdat)(rle_pixel * buf, int n, rle_hdr * the_hdr);
+        /* put a set of differing pixels */
+    void(*putrn)(int color, int n, int last, rle_hdr * the_hdr);
+        /* put a run all the same */
+    void (*blockHook)(rle_hdr * the_hdr);
+        /* hook called at start of new output block */
+    void(*putEof)(rle_hdr * the_hdr);     /* write EOF marker (if possible) */
+};
+
+extern struct rle_dispatch_tab rle_DTable[];
+
+/* 
+ * These definitions presume the existence of a variable called
+ * "fileptr", declared "long * fileptr".  *fileptr should be
+ * initialized to 0 before calling Setup().
+ * A pointer "the_hdr" declared "rle_hdr * the_hdr" is also
+ * presumed to exist.
+ */
+#define	    rle_magic		(rle_DTable[(int)the_hdr->dispatch].magic)
+#define	    Setup()		(*rle_DTable[(int)the_hdr->dispatch].setup)(the_hdr)
+#define	    SkipBlankLines(n)	(*rle_DTable[(int)the_hdr->dispatch].skipBlankLines)(n, the_hdr)
+#define	    SetColor(c)		(*rle_DTable[(int)the_hdr->dispatch].setColor)(c, the_hdr)
+#define	    SkipPixels(n, l, r)	(*rle_DTable[(int)the_hdr->dispatch].skipPixels)(n,l,r, the_hdr)
+#define	    NewScanLine(flag)	(*rle_DTable[(int)the_hdr->dispatch].newScanLine)(flag, the_hdr)
+#define	    putdata(buf, len)	(*rle_DTable[(int)the_hdr->dispatch].putdat)(buf, len, the_hdr)
+#define	    putrun(val, len, f)	(*rle_DTable[(int)the_hdr->dispatch].putrn)(val,len,f, the_hdr)
+#define	    BlockHook()		(*rle_DTable[(int)the_hdr->dispatch].blockHook)(the_hdr)
+#define	    PutEof()		(*rle_DTable[(int)the_hdr->dispatch].putEof)(the_hdr)
+
+void
+DefaultBlockHook(rle_hdr * the_hdr);
+/* 
+ * States for run detection
+ */
+#define	DATA	0
+#define	RUN1	1
+#define RUN2	2
+#define	RUN3	3
+#define RUN4	4
+#define RUN5	5
+#define RUN6	6
+#define RUN7	7
+#define	INRUN	-1
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/urt/rle_putcom.c b/urt/rle_putcom.c
new file mode 100644
index 00000000..b1215661
--- /dev/null
+++ b/urt/rle_putcom.c
@@ -0,0 +1,169 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ */
+/* 
+ * rle_putcom.c - Add a picture comment to the header struct.
+ * 
+ * Author:  Spencer W. Thomas
+ *      Computer Science Dept.
+ *      University of Utah
+ * Date:    Mon Feb  2 1987
+ * Copyright (c) 1987, University of Utah
+ */
+
+#include <stdio.h>
+
+#include "mallocvar.h"
+#include "pm.h"
+#include "rle.h"
+
+/*****************************************************************
+ * TAG( match )
+ * 
+ * Match a name against a test string for "name=value" or "name".
+ * If it matches name=value, return pointer to value part, if just
+ * name, return pointer to NUL at end of string.  If no match, return NULL.
+ *
+ * Inputs:
+ *  n:  Name to match.  May also be "name=value" to make it easier
+ *      to replace comments.
+ *  v:  Test string.
+ * Outputs:
+ *  Returns pointer as above.
+ * Assumptions:
+ *  [None]
+ * Algorithm:
+ *  [None]
+ */
+static const char *
+match(const char * const nArg,
+      const char * const vArg) {
+
+    const char * n;
+    const char * v;
+
+    for (n = nArg, v = vArg; *n != '\0' && *n != '=' && *n == *v; ++n, ++v)
+        ;
+    if (*n == '\0' || *n == '=') {
+        if (*v == '\0')
+            return v;
+        else if (*v == '=')
+            return ++v;
+    }
+
+    return NULL;
+}
+
+
+
+/*****************************************************************
+ * TAG( rle_putcom )
+ * 
+ * Put a comment into the header struct.
+ * Inputs:
+ *  value:      Value to add to comments.
+ *  the_hdr:    Header struct to add to.
+ * Outputs:
+ *  the_hdr:    Modified header struct.
+ *  Returns previous value;
+ * Assumptions:
+ *  value pointer can be used as is (data is NOT copied).
+ * Algorithm:
+ *  Find match if any, else add at end (realloc to make bigger).
+ */
+const char *
+rle_putcom(const char * const value,
+           rle_hdr *    const the_hdr) {
+
+    if ( the_hdr->comments == NULL) {
+        MALLOCARRAY_NOFAIL(the_hdr->comments, 2);
+        the_hdr->comments[0] = value;
+        the_hdr->comments[1] = NULL;
+    } else {
+        const char ** cp;
+        const char * v;
+        const char ** old_comments;
+        int i;
+        for (i = 2, cp = the_hdr->comments; *cp != NULL; ++i, ++cp)
+            if (match(value, *cp) != NULL) {
+                v = *cp;
+                *cp = value;
+                return v;
+            }
+        /* Not found */
+        /* Can't realloc because somebody else might be pointing to this
+         * comments block.  Of course, if this were true, then the
+         * assignment above would change the comments for two headers.
+         * But at least, that won't crash the program.  Realloc will.
+         * This would work a lot better in C++, where hdr1 = hdr2
+         * could copy the pointers, too.
+         */
+        old_comments = the_hdr->comments;
+        MALLOCARRAY(the_hdr->comments, i);
+        if (the_hdr->comments == NULL)
+            pm_error("Unable to allocate memory for comments");
+        the_hdr->comments[--i] = NULL;
+        the_hdr->comments[--i] = value;
+        for (--i; i >= 0; --i)
+            the_hdr->comments[i] = old_comments[i];
+    }
+
+    return NULL;
+}
+
+
+
+/*****************************************************************
+ * TAG( rle_delcom )
+ * 
+ * Delete a comment from header struct.
+ * Inputs:
+ *  name:       Name of comment to delete.
+ *  the_hdr:    Header to delete comment from.
+ * Outputs:
+ *  the_hdr:    Modified header struct.
+ *  Returns original comment value.
+ * Assumptions:
+ *  [None]
+ * Algorithm:
+ *  [None]
+ */
+const char *
+rle_delcom(const char * const name,
+           rle_hdr *    const the_hdr) {
+
+    const char * v = NULL;
+
+    if (the_hdr->comments == NULL)
+        v = NULL;
+    else {
+        const char ** cp;
+
+        for (cp = the_hdr->comments; *cp != NULL; ++cp)
+            if (match(name, *cp) != NULL) {
+                v = *cp;
+                for ( ; *cp != NULL; ++cp)
+                    *cp = cp[1];
+                break;
+            }
+        /* Not found */
+        if (*the_hdr->comments == NULL)
+            the_hdr->comments = NULL;
+    }
+
+    return v;
+}
diff --git a/urt/rle_putrow.c b/urt/rle_putrow.c
new file mode 100644
index 00000000..230720f8
--- /dev/null
+++ b/urt/rle_putrow.c
@@ -0,0 +1,728 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ *
+ *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
+ *  to have all "void" functions so declared.
+ */
+/* 
+ * rle_putrow.c - Save a row of the fb to a file.
+ * 
+ * Author:	Spencer W. Thomas
+ * 		Computer Science Dept.
+ * 		University of Utah
+ * Date:	1 April 1981
+ * Copyright (c) 1981,1986 Spencer W. Thomas
+ *
+ * $Id: rle_putrow.c,v 3.0.1.2 1992/01/28 18:29:22 spencer Exp $
+ */
+ 
+#include <stdio.h>
+#include "rle_put.h"
+#include "rle.h"
+
+
+#define FASTRUNS		/* Faster run finding */
+#ifdef vax
+#define LOCC			/* Use vax instructions for more speed */
+#endif
+
+#define	FALSE	0
+#define	TRUE	1
+
+/* Save some typing. */
+#define PBRUN the_hdr->priv.put.brun
+
+/*****************************************************************
+ * TAG( findruns )
+ * 
+ * Find runs not a given color in the row.
+ * Inputs:
+ * 	row:		Row of pixel values
+ *	rowlen:		Number of pixels in the row.
+ *	color:		Color to compare against.
+ *	nrun:		Number of runs already found (in different colors).
+ *	brun:		Runs found in other color channels already.
+ * Outputs:
+ * 	brun:		Modified to reflect merging of runs in this color.
+ *	Returns number of runs in brun.
+ * Assumptions:
+ *
+ * Algorithm:
+ * 	Search for occurences of pixels not of the given color outside
+ *	the runs already found.  When some are found, add a new run or
+ *	extend an existing one.  Adjacent runs with fewer than two
+ *	pixels intervening are merged.
+ */
+static int
+findruns(rle_pixel * const row, 
+         int         const rowlen, 
+         int         const color, 
+         int         const nrunAlready,
+         short    (* const brun)[2]) {
+
+    int i = 0, lower, upper;
+    int s, j;
+    int nrun;
+
+#ifdef DEBUG
+    fprintf( stderr, "findruns( " );
+    for ( s = 0; s < rowlen; s++ )
+        fprintf( stderr, "%2x.%s", row[s], (s % 20 == 19) ? "\n\t" : "" );
+    if ( s % 20 != 0 )
+        fprintf( stderr, "\n\t" );
+    fprintf( stderr, "%d, %d, %d, \n\t", rowlen, color, nrun );
+    for ( j = 0; j < nrun; j++ )
+        fprintf( stderr, "(%3d,%3d) %s", brun[j][0], brun[j][1],
+                 (j % 6 == 5) ? "\n\t" : "" );
+    fprintf( stderr, ")\n" );
+#endif
+
+    nrun = nrunAlready;
+
+    while ( i <= nrun )
+    {
+        /* Assert: 0 <= i <= rowlen
+         * brun[i] is the run following the "blank" space being
+         * searched.  If i == rowlen, search after brun[i-1].
+	 */
+
+	/* get lower and upper bounds of search */
+
+        if ( i == 0 )
+            lower = 0;
+        else
+            lower = brun[i-1][1] + 1;
+
+        if ( i == nrun )
+            upper = rowlen - 1;
+        else
+            upper = brun[i][0] - 1;
+
+#ifdef DEBUG
+        fprintf( stderr, "Searching before run %d from %d to %d\n",
+                 i, lower, upper );
+#endif
+        /* Search for beginning of run != color */
+#if  defined(LOCC)&defined(vax)
+        s = upper - skpc( (char *)row + lower, upper - lower + 1, color ) + 1;
+#else
+        for ( s = lower; s <= upper; s++ )
+            if ( row[s] != color )
+                break;
+#endif
+
+        if ( s <= upper )	/* found a new run? */
+        {
+            if ( s > lower + 1 || i == 0 ) /* disjoint from preceding run? */
+            {
+#ifdef DEBUG
+                fprintf( stderr, "Found new run starting at %d\n", s );
+#endif
+                /* Shift following runs up */
+                for ( j = nrun; j > i; j-- )
+                {
+                    brun[j][0] = brun[j-1][0];
+                    brun[j][1] = brun[j-1][1];
+                }
+                brun[i][0] = s;
+                nrun++;
+            }
+            else
+            {
+                i--;		/* just add to preceding run */
+#ifdef DEBUG
+                fprintf( stderr, "Adding to previous run\n" );
+#endif
+            }
+
+#if defined(LOCC)&defined(vax)
+            s = upper - locc( (char *)row + s, upper - s + 1, color ) + 1;
+#else
+            for ( ; s <= upper; s++ )
+                if ( row[s] == color )
+                    break;
+#endif
+            brun[i][1] = s - 1;
+
+#ifdef DEBUG
+            fprintf( stderr, "Ends at %d", s - 1 );
+#endif
+            if ( s >= upper && i < nrun - 1 ) /* merge with following run */
+            {
+                brun[i][1] = brun[i+1][1];
+                /* move following runs back down */
+                for ( j = i + 2; j < nrun; j++ )
+                {
+                    brun[j-1][0] = brun[j][0];
+                    brun[j-1][1] = brun[j][1];
+                }
+                nrun--;
+#ifdef DEBUG
+                fprintf( stderr, ", add to next run" );
+#endif
+            }
+#ifdef DEBUG
+            putc( '\n', stderr );
+#endif
+        }
+	
+        /* Search in next space */
+        i++;
+    }
+
+    return nrun;
+}
+
+
+
+/*****************************************************************
+ * TAG( rle_putrow )
+ * Write a scanline to the output file.
+ * 
+ * Inputs:
+ *	rows:		Pointer to vector of pointers to
+ *			rle_pixel arrays containing the pixel information.
+ *			If NULL, rowlen scanlines are skipped.
+ *	rowlen:		The number of pixels in the scanline, or the
+ *			number of scanlines to skip (see above).
+ * Outputs:
+ * 	Run length encoded information is written to the_hdr.rle_file.
+ * Assumptions:
+ * 	I'm sure there are lots of assumptions in here.
+ * Algorithm:
+ * 	There are two parts:
+ * 		1. Find all "sufficiently long" runs of background
+ * 		   color.  These will not be saved at all.
+ * 		2. For each run of non-background, for each color
+ * 		   channel, find runs of identical pixel values
+ * 		   between "data" segments (of differing pixel
+ * 		   values).
+ * 	For part 1, "sufficiently long" is 2 pixels, if the following
+ * 	data is less than 256 pixels long, otherwise it is 4 pixels.
+ * 	This is enforced by a post-process merge.
+ *
+ * 	Part 1 can be done in two different ways, depending on whether
+ * 	FASTRUNS is defined or not.  With FASTRUNS defined, it finds
+ * 	runs of the background pixel value in each channel
+ * 	independently, and then merges the results.  With FASTRUNS not
+ * 	defined, it scans all channels in parallel.
+ *
+ * 	Part 2 uses a state machine.  For each run of non-background
+ * 	data, it searches for sufficiently long sequences of a single
+ * 	value (in each channel independently).  Sufficiently long is 4
+ * 	pixels if the following data is < 256 pixels, 6 pixels
+ * 	otherwise.  This is because the startup cost for the run is 2
+ * 	bytes, and the startup cost for a data segment is 2 bytes if
+ * 	it is < 256 pixels long, 4 bytes otherwise.  Thus a run
+ * 	shorter than 4 or 6 pixels (respectively) would actually make
+ * 	the output longer.  An additional pixel is required if the
+ * 	preceding data is an odd number of pixels long (because a
+ * 	filler byte will be output at the end of it.)
+ */
+
+void
+rle_putrow(rows, rowlen, the_hdr)
+register rle_pixel *rows[];
+int rowlen;
+register rle_hdr * the_hdr;
+{
+    register int i, j;
+    int nrun;
+    register rle_pixel *row;
+    int mask;
+    char bits[256];
+    short   state,		/* State of run-finding state machine. */
+	    dstart,		/* Starting point for current data segment. */
+    	    dend,		/* Ending point of current data segment. */
+	    rstart = 0,		/* Starting point of current run. */
+	    runval = 0;		/* Data value for current run. */
+
+    if (rows == NULL)
+    {
+	the_hdr->priv.put.nblank += rowlen;
+	return;
+    }
+    /* 
+     * If not done already, allocate space to remember runs of
+     * non-background color.  A run of bg color must be at least 2
+     * bytes long to count, so there can be at most rowlen/3 of them.
+     */
+    if ( PBRUN == NULL )
+    {
+	PBRUN = (short (*)[2])malloc(
+	    (unsigned)((rowlen/3 + 1) * 2 * sizeof(short)) );
+	if ( PBRUN == NULL )
+	{
+	    fprintf( stderr, "%s: Malloc failed in rle_putrow, writing %s\n",
+		     the_hdr->cmd, the_hdr->file_name );
+	    exit(1);
+	}
+    }
+    /* Unpack bitmask in the_hdr struct */
+    for ( i=0; i < the_hdr->ncolors; i++ )
+	bits[i] = RLE_BIT( *the_hdr, i );
+    bits[255] = RLE_BIT( *the_hdr, -1 );
+
+    /* 
+     * If saving only non-background pixels, find runs of them.  Note
+     * that the alpha channel is considered to be background iff it is
+     * zero.
+     */
+#ifdef	FASTRUNS
+    if ( the_hdr->background )
+    {
+	/* 
+	 * Find runs in each color individually, merging them as we go.
+	 */
+	nrun = 0;		/* start out with no runs */
+	/* Alpha channel first */
+	if ( the_hdr->alpha )
+	    nrun = findruns( rows[-1], rowlen, 0, nrun, PBRUN );
+	/* Now the color channels */
+	for ( i = 0; i < the_hdr->ncolors; i++ )
+	    if ( bits[i] )
+		nrun = findruns( rows[i], rowlen, the_hdr->bg_color[i],
+				 nrun, PBRUN );
+    }
+    else
+    {
+	PBRUN[0][0] = 0;
+	PBRUN[0][1] = rowlen-1;
+	nrun = 1;
+    }
+#else				/* FASTRUNS */
+    if (the_hdr->background)	/* find non-background runs */
+    {
+	j = 0;
+	for (i=0; i<rowlen; i++)
+	    if (!same_color( i, rows, the_hdr->bg_color,
+			     the_hdr->ncolors, bits ) ||
+		(the_hdr->alpha && rows[-1][i] != 0))
+	    {
+		if (j > 0 && i - PBRUN[j-1][1] <= 2)
+		    j--;
+		else
+		    PBRUN[j][0] = i; /* start of run */
+		for ( i++;
+		      i < rowlen && 
+			( !same_color( i, rows, the_hdr->bg_color,
+					 the_hdr->ncolors, bits ) ||
+			  (the_hdr->alpha && rows[-1][i] != 0) );
+		      i++)
+		    ;			/* find the end of this run */
+		PBRUN[j][1] = i-1;    /* last in run */
+		j++;
+	    }
+	nrun = j;
+    }
+    else
+    {
+	PBRUN[0][0] = 0;
+	PBRUN[0][1] = rowlen-1;
+	nrun = 1;
+    }
+#endif				/* FASTRUNS */
+    /* One final pass merges runs with fewer than 4 intervening pixels
+     * if the second run is longer than 255 pixels.  This is because
+     * the startup cost for such a run is 4 bytes.
+     */
+    if ( nrun > 1 )
+    {
+	for ( i = nrun - 1; i > 0; i-- )
+	{
+	    if ( PBRUN[i][1] - PBRUN[i][0] > 255 &&
+		 PBRUN[i-1][1] + 4 > PBRUN[i][0] )
+	    {
+		PBRUN[i-1][1] = PBRUN[i][1];
+		for ( j = i; j < nrun - 1; j++ )
+		{
+		    PBRUN[j][0] = PBRUN[j+1][0];
+		    PBRUN[j][1] = PBRUN[j+1][1];
+		}
+		nrun--;
+	    }
+	}
+    }
+
+    if (nrun > 0)
+    {
+	if (the_hdr->priv.put.nblank > 0)
+	{
+	    SkipBlankLines(the_hdr->priv.put.nblank);
+	    the_hdr->priv.put.nblank = 0;
+	}
+	for ( mask = (the_hdr->alpha ? -1 : 0);
+	      mask < the_hdr->ncolors;
+	      mask++)			/* do all colors */
+	{
+	    if ( ! bits[mask & 0xff] )
+	    {
+		continue;
+	    }
+	    row = rows[mask];
+	    SetColor(mask);
+	    if (PBRUN[0][0] > 0)
+	    {
+		SkipPixels(PBRUN[0][0], FALSE, FALSE);
+	    }
+	    for (j=0; j<nrun; j++)
+	    {
+		state = DATA;
+		dstart = PBRUN[j][0];
+		dend = PBRUN[j][1];
+		for (i=dstart; i<=dend; i++)
+		{
+		    switch(state)
+		    {
+		    case DATA:
+			if (i > dstart && runval == row[i])
+			{
+			    /* 2 in a row may be a run. */
+			    /* If odd data length, start with RUN1 */
+			    if ( ((i - dstart) % 2) == 0)
+				state = RUN1;
+			    else
+				state = RUN2;
+			}
+			else
+			{
+			    runval = row[i];	/* maybe a run starts here? */
+			    rstart = i;
+			}
+			break;
+	    
+		    case RUN4:
+			if (runval == row[i])
+			{
+			    /* If the following data might be longer
+			     * than 255 pixels then look for 8 in a
+			     * row, otherwise, 6 in a row is
+			     * sufficient.  Fake this by skipping to
+			     * state RUN5.
+			     */
+			    if ( dend - i > 255 )
+				state  = RUN5;	/* Need some more. */
+			    else
+				state = RUN7;	/* Next one makes a run. */
+			    
+			}
+			else
+			{
+			    state = DATA;	/* Nope, back to data */
+			    runval = row[i];	/* but maybe a new run here? */
+			    rstart = i;
+			}
+			break;
+
+		    case RUN1:
+		    case RUN2:
+		    case RUN3:
+		    case RUN5:
+		    case RUN6:
+			if (runval == row[i])
+			{
+			    /* Move to the next state. */
+			    state++;
+			}
+			else
+			{
+			    state = DATA;	/* Nope, back to data */
+			    runval = row[i];	/* but maybe a new run here? */
+			    rstart = i;
+			}
+			break;
+
+
+		    case RUN7:
+			if (runval == row[i])	/* enough in a row for a run */
+			{
+			    state = INRUN;
+			    putdata(row + dstart, rstart - dstart);
+#ifdef FASTRUNS
+#ifdef LOCC
+			    /* Shortcut to find end of run! */
+			    i = dend - skpc( (char *)row + i, dend + 1 - i,
+					     runval );
+#else
+			    while ( row[++i] == runval && i <= dend)
+				; /* not quite so good, but not bad */
+			    i--;
+#endif /* LOCC */
+#endif /* FASTRUNS */
+			}
+			else
+			{
+			    state = DATA;		/* not a run, */
+			    runval = row[i];	/* but may this starts one */
+			    rstart = i;
+			}
+			break;
+	    
+		    case INRUN:
+			if (runval != row[i])	/* if run out */
+			{
+			    state = DATA;
+			    putrun(runval, i - rstart, FALSE);
+			    runval = row[i];	/* who knows, might be more */
+			    rstart = i;
+			    dstart = i;	/* starting a new 'data' run */
+			}
+			break;
+		    }
+		}
+		if (state == INRUN)
+		    putrun(runval, i - rstart, TRUE);	/* last bit */
+		else
+		    putdata(row + dstart, i - dstart);
+
+		if (j < nrun-1)
+		    SkipPixels(
+			    PBRUN[j+1][0] - dend - 1,
+			    FALSE, state == INRUN);
+		else
+		{
+		    if (rowlen - dend > 0)
+			SkipPixels(
+			    rowlen - dend - 1,
+			    TRUE, state == INRUN);
+		}
+	    }
+
+	    if ( mask != the_hdr->ncolors - 1 )
+		NewScanLine(FALSE);
+	}
+    }
+
+    /* Increment to next scanline */
+    the_hdr->priv.put.nblank++;
+
+    /* flush every scanline */
+    fflush( the_hdr->rle_file );
+}
+
+
+/*****************************************************************
+ * TAG( rle_skiprow )
+ * 
+ * Skip rows in RLE file.
+ * Inputs:
+ * 	the_hdr:    	Header struct for RLE output file.
+ *  	nrow:	    	Number of rows to skip.
+ * Outputs:
+ * 	Increments the nblank field in the the_hdr struct, so that a Skiplines
+ *  	code will be output the next time rle_putrow or rle_putraw is called.
+ * Assumptions:
+ * 	Only effective when called between rle_putrow or rle_putraw calls (or
+ *  	some other routine that follows the same conventions.
+ * Algorithm:
+ *	[None]
+ */
+void
+rle_skiprow( the_hdr, nrow )
+rle_hdr *the_hdr;
+int nrow;
+{
+    the_hdr->priv.put.nblank += nrow;
+}
+
+
+/*****************************************************************
+ * TAG( rle_put_init )
+ * 
+ * Initialize the header structure for writing scanlines. 
+ * Inputs:
+ *	[None]
+ * Outputs:
+ * 	the_hdr:	Private portions initialized for output.
+ * Assumptions:
+ *	[None]
+ * Algorithm:
+ *	[None]
+ */
+void
+rle_put_init( the_hdr )
+register rle_hdr *the_hdr;
+{
+    the_hdr->dispatch = RUN_DISPATCH;
+
+    if ( the_hdr->is_init != RLE_INIT_MAGIC )
+    {
+	the_hdr->cmd = "Urt";
+	the_hdr->file_name = "some file";
+    }
+    the_hdr->priv.put.nblank = 0;	/* Reinit static vars */
+    /* Would like to be able to free previously allocated storage,
+     * but can't count on a non-NULL value being a valid pointer.
+     */
+    PBRUN = NULL;
+    the_hdr->priv.put.fileptr = 0;
+
+    /* Only save alpha if alpha AND alpha channel bit are set. */
+    if ( the_hdr->alpha )
+	the_hdr->alpha = (RLE_BIT( *the_hdr, -1 ) != 0);
+    else
+	RLE_CLR_BIT( *the_hdr, -1 );
+}
+
+/*****************************************************************
+ * TAG( rle_put_setup )
+ * 
+ * Initialize for writing RLE, and write header to output file.
+ * Inputs:
+ * 	the_hdr:	Describes output image.
+ * Outputs:
+ * 	the_hdr:	Initialized.
+ * Assumptions:
+ *	Lots of them.
+ * Algorithm:
+ *	[None]
+ */
+void
+rle_put_setup( the_hdr )
+register rle_hdr * the_hdr;
+{
+    rle_put_init( the_hdr );
+    the_hdr->img_num++;		/* Count output images. */
+    Setup();
+}
+
+void
+DefaultBlockHook(rle_hdr * the_hdr)
+{
+    					/* Do nothing */
+}
+
+/*****************************************************************
+ * TAG( rle_puteof )
+ * Write an EOF code into the output file.
+ */
+void
+rle_puteof( the_hdr )
+register rle_hdr * the_hdr;
+{
+    /* Don't puteof twice. */
+    if ( the_hdr->dispatch == NO_DISPATCH )
+	return;
+    PutEof();
+    fflush( the_hdr->rle_file );
+    /* Free storage allocated by rle_put_init. */
+    if ( PBRUN != NULL )
+    {
+	free( PBRUN );
+	PBRUN = NULL;
+    }
+    /* Signal that puteof has been called. */
+    the_hdr->dispatch = NO_DISPATCH;
+}
+
+#ifndef FASTRUNS
+/*****************************************************************
+ * TAG( same_color )
+ * 
+ * Determine if the color at the given index position in the scan rows
+ * is the same as the background color.
+ * Inputs:
+ * 	index:	    Index to the pixel position in each row.
+ *	rows:	    array of pointers to the scanlines
+ *	bg_color:   the background color
+ *	ncolors:    number of color elements/pixel
+ * Outputs:
+ * 	TRUE if the color at row[*][i] is the same as bg_color[*].
+ * Assumptions:
+ *	[None]
+ * Algorithm:
+ *	[None]
+ */
+static int
+same_color( index, rows, bg_color, ncolors, bits )
+register rle_pixel *rows[];
+register int bg_color[];
+char *bits;
+{
+    register int i;
+
+    for ( i = 0; i < ncolors; i++, bits++ )
+	if ( *bits &&
+	     rows[i][index] != bg_color[i] )
+	    return 0;
+    return 1;				/* all the same */
+}
+#endif /* !FASTRUNS */
+
+/*****************************************************************
+ * TAG( rgb_to_bw )
+ * 
+ * Perform the NTSC Y transform on RGB data to get B&W data.
+ * Inputs:
+ * 	red_row, green_row, blue_row:	Given RGB pixel data.
+ *	rowlen:	    Number of pixels in the rows.
+ * Outputs:
+ * 	bw_row:	    Output B&W data.  May coincide with one of the
+ *		    inputs.
+ * Assumptions:
+ *	[None]
+ * Algorithm:
+ * 	BW = .30*R + .59*G + .11*B
+ */
+void
+rgb_to_bw( red_row, green_row, blue_row, bw_row, rowlen )
+rle_pixel *red_row;
+rle_pixel *green_row;
+rle_pixel *blue_row;
+rle_pixel *bw_row;
+int rowlen;
+{
+    register int x, bw;
+
+    for (x=0; x<rowlen; x++)
+    {
+	/* 68000 won't store float > 127 into byte? */
+	/* HP compiler blows it */
+	bw = 0.5 + .30*red_row[x] + .59*green_row[x] + .11*blue_row[x];
+	bw_row[x] = bw;
+    }
+}
+
+#ifdef LOCC
+/*ARGSUSED*/
+locc( p, l, c )
+register char *p;
+register int l;
+register int c;
+{
+    asm( "locc	r9,r10,(r11)" );
+#ifdef lint
+    c = (int) p;		/* why doesn't ARGSUSED work? */
+    l = c;
+    return l;			/* Needs return value, at least */
+#endif
+}
+
+/*ARGSUSED*/
+skpc( p, l, c )
+register char *p;
+register int l;
+register int c;
+{
+    asm( "skpc r9,r10,(r11)" );
+#ifdef lint
+    c = (int) p;		/* why doesn't ARGSUSED work? */
+    l = c;
+    return l;			/* Needs return value, at least */
+#endif
+}
+#endif
diff --git a/urt/rle_row_alc.c b/urt/rle_row_alc.c
new file mode 100644
index 00000000..0f29523e
--- /dev/null
+++ b/urt/rle_row_alc.c
@@ -0,0 +1,129 @@
+/*
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is 
+ * preserved on all copies.
+ * 
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the 
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ *
+ *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
+ *  to have all "void" functions so declared.
+ */
+/* 
+ * rle_row_alc.c - Allocate buffers for rle_getrow/rle_putrow.
+ * 
+ * Author:	Spencer W. Thomas
+ * 		Computer Science Dept.
+ * 		University of Utah
+ * Date:	Fri Nov 14 1986
+ * Copyright (c) 1986, Spencer W. Thomas
+ */
+
+#include <stdio.h>
+#include "rle.h"
+
+/*****************************************************************
+ * TAG( rle_row_alloc )
+ * 
+ * Allocate buffer space for use by rle_getrow and rle_putrow.
+ * Inputs:
+ * 	the_hdr:	Header structure for RLE file to be read or
+ *			written.
+ * Outputs:
+ *	scanp:		Pointer to pointer to created scanline buffer.
+ *			This pointer is adjusted for the alpha channel,
+ *			if present.
+ *	Returns 0 for success, -1 if malloc failed.
+ * Assumptions:
+ * 	No input scanline will extend beyond the declared xmax endpoint.
+ * Algorithm:
+ *	Count number of channels actually used (check bitmap).
+ * 	Allocate nchan*rowlength pixels, allocate a buffer
+ *	to hold ncolors+alpha pointers, and give each channel
+ *	rowlength pixels.  Rowlength is xmax + 1, to allow for rle_getrow
+ *	usage.
+ */
+int
+rle_row_alloc( the_hdr, scanp )
+rle_hdr *the_hdr;
+rle_pixel ***scanp;
+{
+    rle_pixel ** scanbuf, * pixbuf;
+    int rowlen, nchan = 0, i, ncol;
+
+    rowlen = the_hdr->xmax + 1;
+    if ( the_hdr->alpha && RLE_BIT( *the_hdr, RLE_ALPHA ) )
+	nchan++;
+    for ( i = 0; i < the_hdr->ncolors; i++ )
+	if ( RLE_BIT( *the_hdr, i ) )
+	     nchan++;
+
+    ncol = the_hdr->ncolors + the_hdr->alpha;
+
+    if ( (scanbuf = (rle_pixel **)malloc( ncol * sizeof(rle_pixel *) )) == 0 )
+	return -1;
+    if ( (pixbuf = (rle_pixel *)malloc( nchan * rowlen *
+				       sizeof(rle_pixel) )) == 0 )
+    {
+	free( scanbuf );
+	return -1;
+    }
+
+    if ( the_hdr->alpha )
+	scanbuf++;
+
+    for ( i = -the_hdr->alpha; i < the_hdr->ncolors; i++ )
+	if ( RLE_BIT( *the_hdr, i ) )
+	{
+	    scanbuf[i] = pixbuf;
+	    pixbuf += rowlen;
+	}
+	else
+	    scanbuf[i] = 0;
+    *scanp = scanbuf;
+
+    return 0;
+}
+
+
+/*****************************************************************
+ * TAG( rle_row_free )
+ * 
+ * Free storage allocated by rle_row_alloc().
+ * Inputs:
+ * 	the_hdr:	Header structure as above.
+ *	scanp:		Pointer to scanbuf above.
+ * Outputs:
+ * 	Frees storage referenced by scanp and nrawp.
+ * Assumptions:
+ * 	Storage was allocated by rle_row_alloc, or by use of same
+ *	algorithm, at least.
+ * Algorithm:
+ * 	free scanp[0] and scanp.
+ */
+void
+rle_row_free( the_hdr, scanp )
+rle_hdr *the_hdr;
+rle_pixel **scanp;
+{
+    int i;
+
+    if ( the_hdr->alpha )
+	scanp--;
+    for ( i = 0; i < the_hdr->ncolors + the_hdr->alpha; i++ )
+	if ( scanp[i] != 0 )
+	{
+	    free( (char *)scanp[i] );
+	    break;
+	}
+    free( (char *)scanp );
+}
diff --git a/urt/scanargs.c b/urt/scanargs.c
new file mode 100644
index 00000000..416f2380
--- /dev/null
+++ b/urt/scanargs.c
@@ -0,0 +1,948 @@
+/* 
+ * $Id: scanargs.c,v 3.0.1.3 1992/02/27 21:18:14 spencer Exp $
+ * 		Version 7 compatible
+ * 	Argument scanner, scans argv style argument list.
+ * 
+ * 	Some stuff is a kludge because sscanf screws up
+ * 
+ * 	Gary Newman - 10/4/1979 - Ampex Corp. 
+ * 
+ * 	Modified by Spencer W. Thomas, Univ. of Utah, 5/81 to
+ * 	add args introduced by 	a flag, add qscanargs call,
+ * 	allow empty flags.
+ * 
+ * 	If you make improvements we'd like to get them too.
+ * 	Jay Lepreau	lepreau@utah-20, decvax!harpo!utah-cs!lepreau
+ * 	Spencer Thomas	thomas@utah-20, decvax!harpo!utah-cs!thomas 
+ * 
+ *	(I know the code is ugly, but it just grew, you see ...)
+ * 
+ * Modified by:	Spencer W. Thomas
+ * 	Date:	Feb 25 1983
+ * 1. Fixed scanning of optional args.  Now args introduced by a flag
+ *    must follow the flag which introduces them and precede any other
+ *    flag argument.  It is still possible for a flag introduced
+ *    argument to be mistaken for a "bare" argument which occurs
+ *    earlier in the format string.  This implies that flags may not
+ *    be conditional upon other flags, and a message will be generated
+ *    if this is attempted.
+ * 
+ * 2. Usage message can be formatted by inserting newlines, tabs and
+ *    spaces into the format string.  This is especially useful for
+ *    long argument lists.
+ * 
+ * 3. Added n/N types for "numeric" args.  These args are scanned
+ *    using the C language conventions - a number starting 0x is
+ *    hexadecimal, a number starting with 0 is octal, otherwise it is
+ *    decimal.
+ *
+ *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
+ *  to have all "void" functions so declared.
+ */
+
+#include "rle.h"
+#include <stdio.h>
+#include <ctype.h>
+#ifndef USE_STDARG
+#include <varargs.h>
+#else
+#include <stdarg.h>
+#endif
+
+#include "nstring.h"
+
+typedef char bool;
+/* 
+ * An explicit assumption is made in this code that all pointers look
+ * alike, except possible char * pointers.
+ */
+typedef int *ptr;
+
+#define YES 1
+#define NO 0
+#define ERROR(msg)  {fprintf(stderr, "%s\n", msg); goto error; }
+
+/* 
+ * Storage allocation macros
+ */
+#define NEW( type, cnt )	(type *) malloc( (cnt) * sizeof( type ) )
+#define RENEW( type, ptr, cnt )	(type *) realloc( ptr, (cnt) * sizeof( type ) )
+
+#if defined(c_plusplus) && !defined(USE_PROTOTYPES)
+#define USE_PROTOTYPES
+#endif
+
+#ifndef USE_PROTOTYPES
+static char * prformat();
+static int isnum();
+static int	_do_scanargs();
+void		scan_usage();
+#else
+static CONST_DECL char * prformat( CONST_DECL char *, int );
+static int isnum( CONST_DECL char *, int, int );
+static int	_do_scanargs( int argc, char **argv, CONST_DECL char *format,
+			      va_list argl );
+void		scan_usage( char **, CONST_DECL char * );
+#endif
+
+/* 
+ * Argument list is (argc, argv, format, ... )
+ */
+int
+#ifndef USE_STDARG
+scanargs ( va_alist )
+va_dcl
+#else
+scanargs ( int argc, char **argv, CONST_DECL char *format, ... )
+#endif /* !USE_STDARG */
+{
+    va_list argl;
+    int retval;
+#ifndef USE_STDARG
+    int argc;
+    char ** argv;
+    CONST_DECL char *format;
+
+    va_start( argl );
+    argc = va_arg( argl, int );
+    argv = va_arg( argl, char ** );
+    format = va_arg( argl, CONST_DECL char * );
+#else
+    va_start( argl, format );
+#endif
+    retval = _do_scanargs( argc, argv, format, argl );
+    va_end( argl );
+    return retval;
+}
+    
+/* 
+ * This routine is necessary because of a pyramid compiler botch that
+ * uses parameter registers in a varargs routine.  The extra
+ * subroutine call isolates the args on the register stack so they
+ * don't get trashed.
+ */
+
+static int
+_do_scanargs( argc, argv, format, argl )
+int     argc;			/* Actual arguments */
+char  **argv;
+CONST_DECL char   *format;
+va_list argl;
+{
+
+    int    check;			/* check counter to be sure all argvs
+					   are processed */
+    register CONST_DECL char  *cp;
+    int    cnt;
+    int	    optarg = 0;			/* where optional args start */
+    int	    nopt = 0;
+    char    tmpflg,			/* temp flag */
+	    typchr;			/* type char from format string */
+    char    c;
+    bool  * arg_used;			/* array of flags */
+    ptr	    aptr = 0;			/* pointer to return loc */
+
+    bool    required;
+    int	    excnt;			/* which flag is set */
+    bool    exflag;			/* when set, one of a set of exclusive
+					   flags is set */
+
+    bool    list_of;			/* set if parsing off a list of args */
+    bool    comma_list;			/* set if AT&T style multiple args */
+    bool    no_usage;			/* If set, don't print usage msg. */
+    bool    help = NO;			/* If set, always print usage. */
+    int	  * cnt_arg = 0;		/* where to stuff list count */
+    int	    list_cnt;			/* how many in list */
+    /* These are used to build return lists */
+    char ** strlist = 0;
+    int   * intlist = 0;
+    long  * longlist = 0;
+    float * fltlist = 0;
+    double *dbllist = 0;
+    char  * argp;			/* Pointer to argument. */
+
+    CONST_DECL char   *ncp;		/* remember cp during flag scanning */
+    static char   cntrl[7] = "%  %1s";	/* control string for scanf's */
+    char    junk[2];			/* junk buffer for scanf's */
+
+    /* Set up for argument counting. */
+    arg_used = NEW( bool, argc );
+    if (arg_used == NULL)
+    {
+	fprintf(stderr, "malloc failed in scanargs, exiting\n");
+	exit(-1);
+    }
+    else
+    {
+	for (cnt=0; cnt<argc; cnt++)
+	    arg_used[cnt] = NO;
+    }
+    check = 0;
+
+    /* Scan for -help in arg list. */
+    for ( cnt=1; cnt<argc; cnt++ )
+	if ( strcmp( argv[cnt], "-help" ) == 0 )
+	{
+	    check += cnt;
+	    arg_used[cnt] = YES;
+	    if ( argc == 2 )
+	    {
+		scan_usage( argv, format );
+		return 0;
+	    }
+	    else
+		help = YES;
+	}
+
+    /* If format string ends in @, don't print a usage message. */
+    no_usage = *(format + strlen( format ) - 1) == '&';
+
+    cp = format;
+    /* 
+     * Skip program name
+     */
+    while ( *cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0' )
+	cp++;
+
+    while (*cp)
+    {
+	required = NO;			/* reset per-arg flags */
+	list_of = NO;
+	comma_list = NO;
+	list_cnt = 0;
+	switch (*(cp++))
+	{
+	    default: 			/* all other chars */
+		break;
+	    case ' ':			/* separators */
+	    case '\t':
+	    case '\n':
+		optarg = 0;		/* end of optional arg string */
+		break;
+
+	    case '(':			/* Surrounds a comment. */
+	    {
+		int depth = 1;		/* Count parenthesis depth. */
+		while ( *cp && depth > 0 )
+		    switch ( *(cp++) )
+		    {
+		    case '(':	depth++;		break;
+		    case ')':	depth--;		break;
+		    }
+		break;
+	    }
+
+	    case '!': 			/* required argument */
+		required = YES;
+	    case '%': 			/* not required argument */
+reswitch:				/* after finding '*' or ',' */
+		switch (typchr = *(cp++))
+		{
+		    case ',':		/* argument is AT&T list of things */
+			comma_list = YES;
+		    case '*':		/* argument is list of things */
+			list_of = YES;
+			list_cnt = 0;	/* none yet */
+			cnt_arg = va_arg( argl, int *);	/* item count * here */
+			goto reswitch;	/* try again */
+
+		    case '$':		/* "rest" of argument list */
+			while ( argc > 1 && !arg_used[argc-1] )
+			    argc--;	/* find last used argument */
+			*va_arg( argl, int * ) = argc;
+			break;
+
+		    case '&':		/* Return unused args. */
+			/* Count how many.  Always include argv[0]. */
+			for ( nopt = cnt = 1; cnt < argc; cnt++ )
+			    if ( !arg_used[cnt] )
+				nopt++;
+			if ( nopt == 1 )
+			    nopt = 0;	/* Special case for no args. */
+			if ( nopt > 0 )
+			{
+			    strlist = NEW( char *, nopt + 1 );
+			    /* Copy program name, for sure. */
+			    strlist[0] = argv[0];
+			    for ( nopt = cnt = 1; cnt < argc; cnt++ )
+				if ( !arg_used[cnt] )
+				{
+				    strlist[nopt++] = argv[cnt];
+				    check += cnt;
+				    arg_used[cnt] = 1;
+				}
+			    strlist[nopt] = NULL;
+			}
+			else
+			    strlist = NULL;	/* No args, return empty. */
+
+			/* Return count and arg list. */
+			*va_arg( argl, int * ) = nopt;
+			*va_arg( argl, char *** ) = strlist;
+			break;
+
+		    case '-': 		/* argument is flag */
+			if (optarg > 0)
+			    ERROR("Format error: flag conditional on flag not allowed");
+
+		    /* go back to label */
+			ncp = cp-1;	/* remember */
+			cp -= 3;
+			for (excnt = exflag = 0
+				; *cp != ' ' && !(*cp=='-' &&(cp[-1]=='!'||cp[-1]=='%'));
+				(--cp, excnt++))
+			{
+			    for (cnt = optarg+1; cnt < argc; cnt++)
+			    {
+			    /* flags all start with - */
+				if (*argv[cnt] == '-' && !arg_used[cnt] &&
+					!ISDIGIT(argv[cnt][1]))
+				    if (*(argv[cnt] + 1) == *cp)
+				    {
+					if (*(argv[cnt] + 2) != 0)
+					    ERROR ("extra flags ignored");
+					if (exflag)
+					    ERROR ("more than one exclusive flag chosen");
+					exflag++;
+					required = NO;
+					check += cnt;
+					arg_used[cnt] = 1;
+					nopt = cnt;
+					*va_arg( argl, int *) |= (1 << excnt);
+					break;
+				    }
+			    }
+			}
+			if (required)
+			    ERROR ("flag argument missing");
+			cp = ncp;
+			/* 
+			 * If none of these flags were found, skip any
+			 * optional arguments (in the varargs list, too).
+			 */
+			if (!exflag)
+			{
+			    (void)va_arg( argl, int * );/* skip the arg, too */
+			    while (*++cp && ! ISSPACE(*cp))
+				if (*cp == '!' || *cp == '%')
+				{
+				    if ( *++cp == '*' || *cp == ',' )
+				    {
+					cp++;
+					(void)va_arg( argl, int * );
+				    }
+				    /* 
+				     * Assume that char * might be a
+				     * different size, but that all
+				     * other pointers are same size.
+				     */
+				    if ( *cp == 's' )
+					(void)va_arg( argl, char * );
+				    else
+					(void)va_arg( argl, ptr );
+				}
+			}
+			else
+			{
+			    optarg = nopt;
+			    cp++;	/* skip over - */
+			}
+
+			break;
+
+		    case 's': 		/* char string */
+		    case 'd': 		/* decimal # */
+		    case 'o': 		/* octal # */
+		    case 'x': 		/* hexadecimal # */
+		    case 'n':		/* "number" in C syntax */
+		    case 'f': 		/* floating # */
+		    case 'D': 		/* long decimal # */
+		    case 'O': 		/* long octal # */
+		    case 'X': 		/* long hexadecimal # */
+		    case 'N':		/* long number in C syntax */
+		    case 'F': 		/* double precision floating # */
+#if defined(sgi) && !defined(mips)
+			/* Fix for broken SGI IRIS 2400/3000 floats */
+			if ( typchr == 'F' ) typchr = 'f';
+#endif /* sgi */
+			for (cnt = optarg+1; cnt < argc; cnt++)
+			{
+			    argp = argv[cnt];
+
+			    if ( isnum( argp, typchr, comma_list ) )
+			    {
+				;	/* it's ok, then */
+			    }
+			    else if ( *argp == '-' && argp[1] != '\0' )
+				if ( optarg > 0 ) /* end optional args? */
+				{
+				    /* Eat the arg, too, if necessary */
+				    if ( list_cnt == 0 ) {
+					if ( typchr == 's' )
+					    (void)va_arg( argl, char * );
+					else
+					    (void)va_arg( argl, ptr );
+                    }
+				    break;
+				}
+				else
+				    continue;
+			    else if ( typchr != 's' )
+				continue;	/* not number, keep looking */
+			    
+			    /* 
+			     * Otherwise usable argument may already
+			     * be used.  (Must check this after
+			     * checking for flag, though.)
+			     */
+			    if (arg_used[cnt]) continue;
+
+			    /* 
+			     * If it's a comma-and-or-space-separated
+			     * list then count how many, and separate
+			     * the list into an array of strings.
+			     */
+			    if ( comma_list )
+			    {
+				register char * s;
+				int pass;
+
+				/*
+				 * Copy the string so we remain nondestructive
+				 */
+				s = NEW( char, strlen(argp)+1 );
+				strcpy( s, argp );
+				argp = s;
+
+				/* 
+				 * On pass 0, just count them.  On
+				 * pass 1, null terminate each string 
+				 */
+				for ( pass = 0; pass <= 1; pass++ )
+				{
+				    for ( s = argp; *s != '\0'; )
+				    {
+					if ( pass )
+					    strlist[list_cnt] = s;
+					while ( (c = *s) != '\0' && c != ' ' &&
+						c != '\t' && c != ',' )
+					    s++;
+					if ( pass )
+					    *s = '\0';
+
+					list_cnt++;	/* count separators */
+					/* 
+					 * Two commas in a row give a null
+					 * string, but two spaces
+					 * don't.  Also skip spaces
+					 * after a comma.
+					 */
+					if ( c != '\0' )
+					    while ( *++s == ' ' || *s == '\t' )
+						;
+				    }
+				    if ( pass == 0 )
+				    {
+					strlist = NEW( char *, list_cnt );
+					list_cnt = 0;
+				    }
+				}
+			    }
+			    else if ( list_of )
+				list_cnt++;   /* getting them one at a time */
+			    /* 
+			     * If it's either type of list, then alloc
+			     * storage space for the returned values
+			     * (except that comma-separated string
+			     * lists already are done).
+			     */
+			    if ( list_of )
+			    {
+				if ( list_cnt == 1 || comma_list )
+				    switch( typchr )
+				    {
+					case 's':
+					    if ( !comma_list )
+						strlist = NEW( char *, 1 );
+					    aptr = (ptr) &strlist[0];
+					    break;
+					case 'n':
+					case 'd':
+					case 'o':
+					case 'x':
+					    intlist = NEW( int, list_cnt );
+					    aptr = (ptr) &intlist[0];
+					    break;
+					case 'N':
+					case 'D':
+					case 'O':
+					case 'X':
+					    longlist = NEW( long, list_cnt );
+					    aptr = (ptr) &longlist[0];
+					    break;
+					case 'f':
+					    fltlist = NEW( float, list_cnt );
+					    aptr = (ptr) &fltlist[0];
+					    break;
+					case 'F':
+					    dbllist = NEW( double, list_cnt );
+					    aptr = (ptr) &dbllist[0];
+					    break;
+				    }
+				else
+				    switch( typchr )
+				    {
+					case 's':
+					    strlist = RENEW( char *, strlist,
+							     list_cnt );
+					    aptr = (ptr) &strlist[list_cnt-1];
+					    break;
+					case 'n':
+					case 'd':
+					case 'o':
+					case 'x':
+					    intlist = RENEW( int, intlist,
+							     list_cnt );
+					    aptr = (ptr) &intlist[list_cnt-1];
+					    break;
+					case 'N':
+					case 'D':
+					case 'O':
+					case 'X':
+					    longlist = RENEW( long, longlist,
+							      list_cnt );
+					    aptr = (ptr) &longlist[list_cnt-1];
+					    break;
+					case 'f':
+					    fltlist = RENEW( float, fltlist,
+							     list_cnt );
+					    aptr = (ptr) &fltlist[list_cnt-1];
+					    break;
+					case 'F':
+					    dbllist = RENEW( double, dbllist,
+							     list_cnt );
+					    aptr = (ptr) &dbllist[list_cnt-1];
+					    break;
+				    }
+			    }
+			    else
+				aptr = va_arg( argl, ptr );
+
+			    if ( typchr == 's' )
+			    {
+				if ( ! comma_list )
+				    *(char **)aptr = argp;
+			    }
+			    else
+			    {
+				nopt = 0;
+				do {
+				    /* 
+				     * Need to update aptr if parsing
+				     * a comma list
+				     */
+				    if ( comma_list && nopt > 0 )
+				    {
+					argp = strlist[nopt];
+					switch( typchr )
+					{
+					    case 'n':
+					    case 'd':
+					    case 'o':
+					    case 'x':
+						aptr = (ptr) &intlist[nopt];
+						break;
+					    case 'N':
+					    case 'D':
+					    case 'O':
+					    case 'X':
+						aptr = (ptr) &longlist[nopt];
+						break;
+					    case 'f':
+						aptr = (ptr) &fltlist[nopt];
+						break;
+					    case 'F':
+						aptr = (ptr) &dbllist[nopt];
+						break;
+					}
+				    }
+				    /* 
+				     * Do conversion for n and N types
+				     */
+				    tmpflg = typchr;
+				    if (typchr == 'n' || typchr == 'N' ) {
+					if (*argp != '0')
+					    tmpflg = 'd';
+					else if (*(argp+1) == 'x' ||
+						 *(argp+1) == 'X')
+					{
+					    tmpflg = 'x';
+					    argp += 2;
+					}
+					else
+					    tmpflg = 'o';
+                    }
+				    if (typchr == 'N')
+					tmpflg = toupper( tmpflg );
+
+
+				    /* put in conversion */
+				    if ( isupper( tmpflg ) )
+				    {
+					cntrl[1] = 'l';
+					cntrl[2] = tolower( tmpflg );
+				    }
+				    else
+				    {
+					cntrl[1] = tmpflg;
+					cntrl[2] = ' ';
+				    }
+				    if (sscanf (argp, cntrl, aptr, junk) != 1)
+					ERROR ("Bad numeric argument");
+				} while ( comma_list && ++nopt < list_cnt );
+			    }
+			    check += cnt;
+			    arg_used[cnt] = 1;
+			    required = NO;
+			    /*
+			     * If not looking for multiple args,
+			     * then done, otherwise, keep looking.
+			     */
+			    if ( !( list_of && !comma_list ) )
+				break;
+			    else
+				continue;
+			}
+			if (required)
+			    switch (typchr)
+			    {
+				case 'x': 
+				case 'X': 
+				    ERROR ("missing hexadecimal argument");
+				case 's': 
+				    ERROR ("missing string argument");
+				case 'o': 
+				case 'O': 
+				    ERROR ("missing octal argument");
+				case 'd': 
+				case 'D': 
+				    ERROR ("missing decimal argument");
+				case 'f': 
+				case 'F': 
+				    ERROR ("missing floating argument");
+				case 'n':
+				case 'N':
+				    ERROR ("missing numeric argument");
+			    }
+			if ( list_cnt > 0 )
+			{
+			    *cnt_arg = list_cnt;
+			    switch ( typchr )
+			    {
+				case 's':
+				    *va_arg( argl, char *** ) = strlist;
+				    break;
+				case 'n':
+				case 'd':
+				case 'o':
+				case 'x':
+				    *va_arg( argl, int ** ) = intlist;
+				    break;
+				case 'N':
+				case 'D':
+				case 'O':
+				case 'X':
+				    *va_arg( argl, long ** ) = longlist;
+				    break;
+				case 'f':
+				    *va_arg( argl, float ** ) = fltlist;
+				    break;
+				case 'F':
+				    *va_arg( argl, double **) = dbllist;
+				    break;
+			    }
+			    if ( typchr != 's' && comma_list )
+				free( (char *) strlist );
+			}
+			else if ( cnt >= argc )
+			{
+			    /* Fell off end looking, so must eat the arg */
+			    if ( typchr == 's' )
+				(void)va_arg( argl, char * );
+			    else
+				(void)va_arg( argl, ptr );
+			}
+			break;
+		    default: 		/* error */
+			fprintf (stderr,
+				 "scanargs: Corrupt or invalid format spec\n");
+			return 0;
+		}
+	}
+    }
+
+    /*  Count up empty flags */
+    for (cnt=1; cnt<argc; cnt++)
+	if (argv[cnt][0] == '-' && argv[cnt][1] == '-' && argv[cnt][2] == 0
+	    && !arg_used[cnt] )
+	    check += cnt;
+
+    /* sum from 1 to N = n*(n+1)/2 used to count up checks */
+    if (check != (((argc - 1) * argc) / 2))
+	ERROR ("extra arguments not processed");
+
+    /* If -help, always print usage. */
+    if ( help )
+	scan_usage( argv, format );
+
+    free(arg_used);
+    return 1;
+
+error: 
+    if ( !no_usage )
+	scan_usage( argv, format );
+    free(arg_used);
+    return 0;
+}
+
+void
+scan_usage( argv, format )
+char ** argv;
+CONST_DECL char * format;
+{
+    register CONST_DECL char * cp;
+
+    fprintf (stderr, "usage : ");
+    if (*(cp = format) != ' ')
+    {
+	if ( *cp == '%' )
+	{
+	    /* 
+	     * This is bogus, but until everyone can agree on a name
+	     * for (rindex/strrchr) ....
+	     */
+	    for ( cp = argv[0]; *cp != '\0'; cp++ )
+		;			/* find the end of the string */
+	    for ( ; cp > argv[0] && *cp != '/'; cp-- )
+		;			/* find the last / */
+	    if ( *cp == '/' )
+		cp++;
+	    fprintf( stderr, "%s", cp );
+
+	    cp = format + 1;		/* reset to where it should be */
+	}
+	while (putc (*cp++, stderr) != ' ');
+    }
+    else
+	fprintf (stderr, "?? ");
+    while (*cp == ' ')
+	cp++;
+    (void)prformat (cp, NO);
+}
+
+static CONST_DECL char *
+prformat (format, recurse)
+CONST_DECL char   *format;
+int 	recurse;
+{
+    register CONST_DECL char  *cp;
+    bool    required, comma_list;
+    int    list_of, depth;
+
+    cp = format;
+    if (recurse)
+	putc (' ', stderr);
+
+    required = NO;
+    list_of = 0;
+    comma_list = NO;
+    while (*cp)
+    {
+	switch (*cp)
+	{
+	    default:
+	    	cp++;
+		break;
+	    case ' ':
+	    case '\n':
+	    case '\t':
+		/* allow annotations */
+		for ( ; format < cp; format++ )
+		    putc( *format, stderr );
+		putc(*cp, stderr);
+		format = ++cp;
+		break;
+
+	    case '(':
+		/* Parentheses surround an arbitrary (parenthesis
+		 * balanced) comment.
+		 */
+		for ( ; format < cp; format++ )
+		    putc( *format, stderr );
+		for ( cp++, depth = 1; *cp && depth > 0; )
+		{
+		    /* Don't print last close paren. */
+		    if ( *cp != ')' || depth > 1 )
+			putc( *cp, stderr );
+		    switch( *(cp++) )
+		    {
+		    case '(':	depth++;		break;
+		    case ')':	depth--;		break;
+		    }
+		}
+		format = cp;
+		break;
+
+	    case '!': 
+		required = YES;
+	    case '%': 
+reswitch:
+		switch (*++cp)
+		{
+		    case ',':
+			comma_list++;
+		    case '*':
+			list_of++;
+			goto reswitch;
+
+		    case '$':		/* "rest" of argument list */
+			if (!required)
+			    putc ('[', stderr);
+			for (; format < cp - 1 - list_of; format++)
+			    putc (*format, stderr);
+			fputs( " ...", stderr );
+			if ( !required )
+			    putc( ']', stderr );
+			break;
+
+		    case '-': 		/* flags */
+			if (!required)
+			    putc ('[', stderr);
+			putc ('-', stderr);
+
+			if (cp - format > 2 + list_of)
+			    putc ('{', stderr);
+			cp = format;
+			while (*cp != '%' && *cp != '!')
+			    putc (*cp++, stderr);
+			if (cp - format > 1 + list_of)
+			    putc ('}', stderr);
+			cp += 2;	/* skip !- or %- */
+			if (*cp && !ISSPACE(*cp))
+			    cp = prformat (cp, YES);
+					/* this is a recursive call */
+
+			cp--;	/* don't ignore next character */
+
+			if (!required)
+			    putc (']', stderr);
+			break;
+		    case 's': 		/* char string */
+		    case 'd': 		/* decimal # */
+		    case 'o': 		/* octal # */
+		    case 'x': 		/* hexadecimal # */
+		    case 'f': 		/* floating # */
+		    case 'D': 		/* long decimal # */
+		    case 'O': 		/* long octal # */
+		    case 'X': 		/* long hexadecimal # */
+		    case 'F': 		/* double precision floating # */
+		    case 'n':		/* numeric arg (C format) */
+		    case 'N':		/* long numeric arg */
+			if (!required)
+			    putc ('[', stderr);
+			for (; format < cp - 1 - list_of; format++)
+			    putc (*format, stderr);
+			if ( list_of != 0 )
+			{
+			    if ( comma_list )
+				putc( ',', stderr );
+			    else
+				putc( ' ', stderr );
+			    fputs( "...", stderr );
+			}
+			if (!required)
+			    putc (']', stderr);
+			break;
+		    default: 
+			break;
+		}
+		required = NO;
+		list_of = NO;
+		comma_list = NO;
+		if (*cp)		/* check for end of string */
+		    format = ++cp;
+		if (*cp && !ISSPACE(*cp))
+		    putc (' ', stderr);
+	}
+	if (recurse && ISSPACE(*cp))
+	    break;
+    }
+    if (!recurse)
+    {
+	for ( ; format < cp; format++ )
+	    putc( *format, stderr );
+	putc ('\n', stderr);
+    }
+    return (cp);
+}
+
+/* 
+ * isnum - determine whether a string MIGHT represent a number.
+ * typchr indicates the type of argument we are looking for, and
+ * determines the legal character set.  If comma_list is YES, then
+ * space and comma are also legal characters.
+ */
+static int
+isnum( str, typchr, comma_list )
+register CONST_DECL char * str;
+int typchr;
+int comma_list;
+{
+    register CONST_DECL char *allowed, *digits, *cp;
+    int hasdigit = NO;
+
+    switch( typchr )
+    {
+	case 'n':
+	case 'N':
+	    allowed = " \t,+-x0123456789abcdefABCDEF";
+	    break;
+	case 'd':
+	case 'D':
+	    allowed = " \t,+-0123456789";
+	    break;
+	case 'o':
+	case 'O':
+	    allowed = " \t,01234567";
+	    break;
+	case 'x':
+	case 'X':
+	    allowed = " \t,0123456789abcdefABCDEF";
+	    break;
+	case 'f':
+	case 'F':
+	    allowed = " \t,+-eE.0123456789";
+	    break;
+	case 's':			/* only throw out decimal numbers */
+	default:
+	    allowed = " \t,+-.0123456789";
+	    break;
+    }
+    digits = allowed;
+    while ( *digits != '0' )
+	digits++;
+    if ( ! comma_list )
+	allowed += 3;		      /* then don't allow space, tab, comma */
+
+    while ( *str != '\0' )
+    {
+    	for ( cp = allowed; *cp != '\0' && *cp != *str; cp++ )
+    	    ;
+    	if ( *cp == '\0' )
+	    return NO;		     /* if not in allowed chars, not number */
+	if ( cp - digits >= 0 )
+	    hasdigit = YES;
+	str++;
+    }
+    return hasdigit;
+}
diff --git a/urt/vaxshort.c b/urt/vaxshort.c
new file mode 100644
index 00000000..4b57b516
--- /dev/null
+++ b/urt/vaxshort.c
@@ -0,0 +1,50 @@
+/*
+ *			V A X S H O R T
+ *
+ *  Code to manipulate 16-bit integers in VAX order in a
+ *  machine independent manner.
+ *
+ *  (VAX is a trademark of Digital Equipment Corporation)
+ *
+ *  Author -
+ *	Michael John Muuss
+ *  
+ *  Source -
+ *	SECAD/VLD Computing Consortium, Bldg 394
+ *	The U. S. Army Ballistic Research Laboratory
+ *	Aberdeen Proving Ground, Maryland  21005-5066
+ *  
+ *  Distribution Status -
+ *	Public Domain, Distribution Unlimitied.
+ */
+
+#include "vaxshort.h"
+
+/*
+ *			V A X _ G S H O R T
+ *
+ *  Obtain a 16-bit signed integer from two adjacent characters,
+ *  stored in VAX order, regardless of word alignment.
+ */
+int
+vax_gshort(char *msgp)
+{
+	register unsigned char *p = (unsigned char *) msgp;
+	register int	i;
+
+	if( (i = (p[1] << 8) | p[0]) & 0x8000 )
+		return(i | ~0xFFFF);	/* Sign extend */
+	return(i);
+}
+
+/*
+ *			V A X _ P S H O R T
+ */
+char *
+vax_pshort(char *msgp, unsigned short s)
+{
+
+	msgp[0] = s & 0xFF;
+	msgp[1] = s >> 8;
+	return(msgp+2);
+}
diff --git a/urt/vaxshort.h b/urt/vaxshort.h
new file mode 100644
index 00000000..daeb856b
--- /dev/null
+++ b/urt/vaxshort.h
@@ -0,0 +1,5 @@
+int
+vax_gshort(char *msgp);
+
+char *
+vax_pshort(char *msgp, unsigned short s);