changeset 1188:aaae5eac20e1

Provded by James Jones
author boisy
date Fri, 30 May 2003 21:13:48 +0000
parents df263e490f85
children 93f0119d2c27
files 3rdparty/utils/viewgif/ReadMe 3rdparty/utils/viewgif/gifwin.c 3rdparty/utils/viewgif/setmap.c 3rdparty/utils/viewgif/viewgif.c 3rdparty/utils/viewgif/viewgif.h 3rdparty/utils/viewgif/viewvef.c
diffstat 6 files changed, 2383 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/3rdparty/utils/viewgif/ReadMe	Fri May 30 21:13:48 2003 +0000
@@ -0,0 +1,151 @@
+The following is some discussion of just what's going on in viewgif, so that
+future code maintainers and modifiers can have an easier time of it.
+
+Viewgif's main purpose is to decode GIF files and turn them into images that
+can be displayed on the CoCo.  The obstacles to such display are:
+
+1. GIF images can contain up to 256 colors, which are specified in RGB-888
+   form (i.e. eight bits of resolution along each axis of RGB space, a 3-D
+   space for colors whose basis consists of {red, green, blue}).  The CoCo
+   can display at most 16 colors out of the 64 colors that live in RGB-222.
+
+2. GIF images are compressed, using Lempel-Ziv compression (up to 12-bit
+   code length).
+
+The second part is no big deal; in fact, the method used in viewgif is that
+used in the early LZ compress program ported to OS-9/6809 a few years ago.
+The first part is the one of major interest here.
+
+Viewgif uses two methods to overcome the GIME's limitations:
+
+1. Representing each color c[i] in the GIF image with a sum of two colors
+   c1[i] and c2[i], where c1[i] + c2[i] is approximately equal to c[i].
+   The c1[i] are displayed on one window and the c2[i] on another, and
+   viewgif alternates rapidly between the two windows.  This gives us
+   additional resolution in RGB space.
+
+2. Dithering, adding random noise to the displayed image.  It may seem odd
+   that adding noise to an image should improve it, but in fact it does,
+   because it spreads out quantization error, and quantization error,
+   the error induced by going from a continuous quantity to a discrete
+   representation or, in our case, cutting down the resolution available,
+   is the big problem here.  The easiest way to see it is to use a non-
+   dithering CoCo GIF viewer on an image with lots of shading--portraits
+   are best, because you know what color people are.  (Starships could be
+   any color. :-)  It will look like someone painted the person brick red
+   or yellow, or like whoever does the *USA Today* weather maps body painted
+   the person.  Or maybe both!
+
+The real guts of viewgif is that portion which determines what "dithering
+factor" is the best for a given image.  (You get to specify whether you
+want one or two windows.)  This is done in the function newwind(), in the
+file viewgif.c, and the functions it calls (setmap() and approx1() and
+approx2() in setmap.c).  newwind() uses a binary search to find the largest
+dithering factor less than or equal to the one given on the command line
+(or the default, if you don't specify one) for which all the colors can
+successfully be mapped to those available on the one or two windows available.
+The dithering factor is "extended" in the negative direction by interpreting
+a negative dithering factor as increased sloppiness about what is considered
+"successful" mapping, so that this search always "succeeds."  Viewgif will
+show a positive "color tolerance" in this case.
+
+(If you look at the function approx2(), the function that approximates the
+the colors in the GIF CLUT (Color Look-Up Table) for the two-screen case,
+you'll note that not all pairs of colors are considered as possible sums;
+instead, only those pairs that are "near" one another are tried.  I can only
+guess at the reason behind this, but I think that it is done to prevent the
+change between windows from being excessively noticeable.  If you know
+of a reference that describes the algorithms used here, it would be nice
+to add that in the program comments.)
+
+Scattered throughout the original code were some numbers like 85, 42, and
+21.  These have to do with the conversion from RGB888 to RGB222.  The
+maximum value for a color component in RGB888 is 255, and in RGB222 is 3,
+so...to convert, one scales by a factor of 255 / 3 = 85.  (For two screens,
+this program uses 85 / 2, or 42.)  toler() and toler2(), the functions that
+determine how "close" two colors are, do their comparison in RGB888 space,
+but consider all colors that would map to the goal color in the CoCo display
+space equally close.  (The upper bound on the dithering factor is the
+"radius" of that neighborhood in RGB888 space.)
+
+For those who saw the original viewgif, here are the changes I've made:
+
+ 1. A header file, viewgif.h, has been added, with #defines that I hope will
+    give some idea where the magic values come from.  We've also anticipated
+    attempts to port to OS-9/68000, though of course the low-level routines
+    are quite CoCo-specific.
+
+ 2. The data have been restructured.  Most notably, the rgbcolor and
+    cocoscreen types are attempts to collect related data in an intelligible
+    fashion, to allow iteration over screens or color components, to let
+    the common outer loop in setmap() be actual common code, and to avoid
+    needless replication of code in the loop that tries to extend just
+    one CLUT in approx2().  We hope we are anticipating generalization to
+    three or more windows, though that way lies madness, more memory usage,
+    and a combinatorial explosion in the approx3() function that one would
+    have to add.
+
+ 3. Scalar global variables have been explicitly put on the direct page
+    for speed.  (This has been made conditional for possible porting.)
+    The assembly-language functions have been changed to reflect this
+    placement as well, since Vaughn Cato tried to pick time-critical
+    functions for conversion to assembly language.  Speaking of which,
+    we added comments showing addpixel() in C--not that it's tough to
+    figure out, but every little bit helps.
+
+ 4. Some judiciously-placed register declarations have been added, again
+    for speed.
+
+ 5. Subscripting has been turned into pointer arithmetic in various places.
+
+ 6. Some functions have been moved into what seems to me to be more
+    appropriate files, considering who calls them and the general purpose
+    of the functions in the file.  (Some more of this should be done; in
+    particular, functions not related to window manipulation should be
+    moved out of gifwin.c.)
+
+ 7. A bug in what was setmap2() but is now approx2() was corrected.  The
+    original was not toggling the "mode" variable, so that it would never
+    look at possible sums extending the larger CLUT.
+
+ 8. approx2() (formerly setmap2()) has added an array in which we recall
+    the results of the nearcolor() function, rather than calling it lots
+    of times.  (I think this is the big win for speeding up the analysis
+    phase.)
+
+ 9. We added a -? option.
+
+10. We added a -z option, that overwrites the global color map after
+    replacing unused colors with some color that is used.  CAUTION:
+    this overwrites the whole global color map, and said color map is
+    manipulated in other ways via the -g, -g2, and -b options.  You
+    can lose information if you combine -z with those options, and
+    perhaps we should prevent them from being used together.
+
+There is still more that can be done to speed things up.
+
+ 1. It should be possible to speed up the decompression.  Alas, the obvious
+    way, i.e. going with a hash table rather than a tree, may eat more memory
+    than we can afford; nevertheless, it is worth investigating.
+
+ 2. It may be worth trying putting two scan lines at a time instead of one,
+    to cut system call overhead.  One would have to allocate get/put buffers
+    for each window to do this.  It's not clear whether it would be a win
+    for interleaved images.
+
+ 3. This version of viewgif shares the problems of the program it is based
+    on.  (Indeed, it would be surprising if it didn't!)  Aside from smarter
+    mapping of colors, which I fear would require two passes over the GIF
+    file, the main one concerns smarter handling of aspect ratios.  Most
+    likely, since the current GIF specification doesn't say beans about
+    aspect ratio, one will have to let the user tweak the aspect ratio
+    on the command line.
+
+ 4. The VEF files generated may not be quite correct; vefprt seems to emit
+    a few lines of junk before putting out the rest of the image properly.
+    This behavior seems to be the same for the old and the new versions of
+    the program.
+
+ 5. The code that waits for the user to type a character could be changed
+    to use the SS_SSIG setstat along with an intercept() routine, to cut
+    system overhead.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/3rdparty/utils/viewgif/gifwin.c	Fri May 30 21:13:48 2003 +0000
@@ -0,0 +1,308 @@
+/*
+ * gifwin.c - window functions for ViewGIF 2.0
+ * by Vaughn Cato
+ */
+
+#include "viewgif.h"
+
+char           *mapgpb();
+extern int		errno;
+
+checksig()
+{
+	char            buf[6];
+
+	fread(buf, sizeof(*buf), 6, infile);
+	if (strncmp(buf, "GIF", 3) != 0)
+		fatal("file is not a GIF file");
+	if (strncmp(&buf[3], "87a", 3) != 0)
+		fatal("Unknown GIF version number");
+}
+
+perror(str)
+char           *str;
+{
+	fprintf(stderr, "%s: error\n", str);
+}
+
+error(str, errnum)
+char           *str;
+int             errnum;
+{
+	fprintf(stderr, "viewgif: %s\n", str);
+	exit(errnum);
+}
+
+sleep(ticks)
+int		ticks;
+{
+#asm
+ ldx 4,s
+ os9 F$Sleep
+#endasm
+}
+
+static char *ustext[] = {
+	"OS9 ViewGIF 2.0 by Vaughn Cato\n",
+	"usage: viewgif <filename> [-<option> ...]\n",
+	"       displays a gif picture\n",
+	"\n",
+	"  options:\n",
+	"       -d[[=]dfactor] Set dithering factor, default is 0\n",
+	"       -a Align to pixels\n",
+	"       -u[=]<filename> Create/use a color usage file\n",
+	"       -m[=]<magfact> Set magnification factor (1-64)\n",
+	"       -x[=]<start x> Set start x (0-64)\n",
+	"       -y[=]<start y> Set start y (0-64)\n",
+	"       -v[[=]<filename>] Generate vef format picture\n",
+	"       -g grey scale picture (average color brite)\n",
+	"       -g2 grey scale picture (max color brite)\n",
+	"       -g3 grey scale picture (NTSC color brite)\n",
+	"       -r Use random generator instead of table\n",
+	"       -s Silent.  No info printed\n",
+	"       -i Extended information\n",
+	"       -n No display\n",
+	"       -p[[=]seconds] Pause time (default 0)\n",
+	"       -c Use current screen\n",
+	"       -f Disable flicker\n",
+	"       -b[=]<britefact> Set brightness (1-16)\n",
+	"       -z Zap unused global color map entries\n",
+	NULL
+};
+
+usage()
+{
+	register char	**uscan;
+	
+	for (uscan = ustext; *uscan != NULL; uscan++)
+		fputs(*uscan, stderr);
+	exit(1);
+}
+
+initwin(firstscreen, oldpath)
+bool	firstscreen;
+int		oldpath;
+{
+	register bool	newwin;
+
+	newwin = (oldpath == -1);
+
+	if (newwin) {
+		if (!newscrn && firstscreen) {
+			/* just use stdout */
+			actwin = oldpath = 1;
+			dwend();
+		} else if ((actwin = oldpath = open("/w", 3)) == -1)
+			exit(errno);
+	} else {
+		actwin = oldpath;
+		dwend();
+	}
+
+	dwset(gmode ? 7 : 8, 0, 0, gmode ? 80 : 40, 24, 0, 0, 0);
+	curoff();
+	select();
+	flushwin();
+
+	if (newwin && firstscreen) {
+		groupnum = getpid();
+		bufnum = 1;
+		getblk(groupnum, bufnum, 0, 0, 640, 1);
+		flushwin();
+		if ((gpbufptr = mapgpb(actwin, groupnum, bufnum, 1)) == NULL)
+			exit(errno);
+	} 
+	
+	return actwin;
+}
+
+dwset(sty, cpx, cpy, szx, szy, prn1, prn2, prn3)
+int             sty, cpx, cpy, szx, szy, prn1, prn2, prn3;
+{
+	static char     outstr[] = {
+		0x1b, 0x20, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	int             size;
+
+	outstr[2] = sty;
+	outstr[3] = cpx;
+	outstr[4] = cpy;
+	outstr[5] = szx;
+	outstr[6] = szy;
+	if (sty > 0 && sty <= 8) {
+		outstr[7] = prn1;
+		outstr[8] = prn2;
+		outstr[9] = prn3;
+		size = sizeof(outstr);
+	} else
+		size = sizeof(outstr) - 3;
+	writemem(outstr, size);
+}
+
+dwend()
+{
+	static char     outstr[] = {0x1b, 0x24};
+
+	writemem(outstr, sizeof(outstr));
+}
+
+select()
+{
+	static char     outstr[] = {0x1b, 0x21};
+
+	writemem(outstr, sizeof(outstr));
+}
+
+bell()
+{
+	char            c = 7;
+	writemem(&c, 1);
+}
+
+palette(prn, ctn)
+{
+	static char     outstr[] = {0x1b, 0x31, 0, 0};
+
+	outstr[2] = prn;
+	outstr[3] = ctn;
+	writemem(outstr, sizeof(outstr));
+}
+
+point(x, y)
+int             x, y;
+{
+	static char     outstr[] = {0x1b, 0x42, 0, 0, 0, 0};
+
+	*(int *) &outstr[2] = x;
+	*(int *) &outstr[4] = y;
+	writemem(outstr, sizeof(outstr));
+}
+
+lineto(x, y)
+int             x, y;
+{
+	static char     outstr[] = {0x1b, 0x46, 0, 0, 0, 0};
+
+	*(int *) &outstr[2] = x;
+	*(int *) &outstr[4] = y;
+	writemem(outstr, sizeof(outstr));
+}
+
+fcolor(c)
+int             c;
+{
+	static char     outstr[] = {0x1b, 0x32, 0};
+
+	outstr[2] = c;
+	writemem(outstr, sizeof(outstr));
+}
+
+border(c)
+int             c;
+{
+	static char     outstr[] = {0x1b, 0x34, 0};
+
+	outstr[2] = c;
+	writemem(outstr, sizeof(outstr));
+}
+
+SetDPtr(x, y)
+int             x, y;
+{
+	static char     outstr[] = {0x1b, 0x40, 0, 0, 0, 0};
+
+	*(int *) &outstr[2] = x;
+	*(int *) &outstr[4] = y;
+	writemem(outstr, sizeof(outstr));
+}
+
+curoff()
+{
+	static char     outstr[] = {0x05, 0x20};
+
+	writemem(outstr, sizeof(outstr));
+}
+
+getblk(grp, bfn, cpx, cpy, szx, szy)
+int             grp, bfn, cpx, cpy, szx, szy;
+{
+	static char     outstr[] = {0x1b, 0x2c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+	outstr[2] = grp;
+	outstr[3] = bfn;
+	*(int *) (&outstr[4]) = cpx;
+	*(int *) (&outstr[6]) = cpy;
+	*(int *) (&outstr[8]) = szx;
+	*(int *) (&outstr[10]) = szy;
+	writemem(outstr, sizeof(outstr));
+}
+
+putblk(grp, bfn, cpx, cpy)
+int             grp, bfn, cpx, cpy;
+{
+	static char     outstr[] = {0x1b, 0x2d, 0, 0, 0, 0, 0, 0};
+
+	outstr[2] = grp;
+	outstr[3] = bfn;
+	*(int *) (&outstr[4]) = cpx;
+	*(int *) (&outstr[6]) = cpy;
+	writemem(outstr, sizeof(outstr));
+}
+
+killbuf(grp, bfn)
+int             grp, bfn;
+{
+	static char     outstr[] = {0x1b, 0x2a, 0, 0};
+
+	outstr[2] = grp;
+	outstr[3] = bfn;
+	writemem(outstr, sizeof(outstr));
+}
+
+char *
+mapgpb(path, grp, bfn, action)
+int             path, grp, bfn, action;
+{
+#asm
+ lda 7,s group
+ ldb 9,s buffer
+ tfr d,x ->X
+ lda 5,s path
+ ldb #$SS.MpGPB setstat code
+ pshs y
+ ldy 10+2,s action (1 => map, 0 => unmap)
+ os9 I$SetStt
+ puls y
+ bcc _mapgpb1
+ clra error--
+ std errno,y save error code,
+ ldx #0 return NULL pointer
+_mapgpb1: tfr x,d move pointer into position for return
+#endasm
+}
+
+static char			outbuf[256];
+static DIRECT char	*outptr = outbuf;
+static DIRECT int	bufleft = sizeof(outbuf);
+
+writemem(str, size)
+register char  *str;
+register int    size;
+{
+	while (size > bufleft) {
+		size -= bufleft;
+		while (--bufleft >= 0)
+			*outptr++ = *str++;
+		flushwin();
+	}
+	bufleft -= size;
+	while (--size >= 0)
+		*outptr++ = *str++;
+}
+
+flushwin()
+{
+	write(actwin, outbuf, outptr - outbuf);
+	outptr = outbuf;
+	bufleft = sizeof(outbuf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/3rdparty/utils/viewgif/setmap.c	Fri May 30 21:13:48 2003 +0000
@@ -0,0 +1,363 @@
+/*
+ * SetMap - Palette creator for ViewGIF 2.0
+ * These routines are the heart of the color analysis.  They take the
+ * global bitmap and, based on the dithering factor, produce a CoCo color
+ * palette.
+ */
+
+#include "viewgif.h"
+
+int		toler2(), exact();
+bool	nearcolor();
+
+/*
+ * setmap() -- determine whether, given the specified dithering factor,
+ * there are CLUTs for the screens we've been told to use that will let
+ * us come reasonably close to representing the colors in the GIF image.
+ * We change the semantics from the original version, returning FALSE
+ * if not all the CLUT etnries can be fit in, or TRUE if they all work.
+ *
+ * Method: look for approximations to each color in use in terms of colors
+ * already in the CLUTs.  If none is close enough, then add the color
+ * (or some decomposition thereof, in the multiple screen case) to the
+ * CLUTs.  If there's no room left to add the color, we return FALSE.
+ *
+ * Note: we're trying to trade space for speed in the innermost loop of
+ * doline() by always leaving an end marker, avoiding double testing in
+ * said loop.  We'll see how it works out.
+ */
+bool
+setmap()
+{
+	rgbcolor			next;
+	register int		add;
+	register rgbcolor	*gcscan;
+	register xlate		*trscan;
+	int         		numtrans, tolrnce, x, uplim, lowlim;
+
+	/* should be a loop if we really do change NSCREENS */
+	screen[0].clutsize = screen[1].clutsize = 0;
+
+	lowlim = low0;
+	uplim = up0;
+
+	if (dfactor > 0) {
+		tolrnce = 0;
+		lowlim -= dfactor;
+	} else
+		tolrnce = -dfactor;
+
+	if (dfactor > (int) flicker)
+		uplim += dfactor;
+
+	for (gcscan = globclut, x = 0; x < globcolors; gcscan++, x++) {
+		if (coloruse[x]) {
+			numtrans = 0;
+			trscan = &transtab[x][0];
+			for (add = lowlim; add < uplim; add = minadd(gcscan, add)) {
+				trscan->addval = add;
+				addoff(&next, gcscan, add);
+				if (!(*approx)(&next, trscan, tolrnce))
+					return FALSE;
+				if (++numtrans > 4)
+					fatal("BUG: numtrans>4");
+				trscan++;
+			}
+			/* mark end of transtab entries for this color */
+			trscan->addval = BOGUSDITH;
+		}
+	}
+	return TRUE;
+}
+
+addoff(color, color0, offset)
+register BYTE	*color, *color0;
+int				offset;
+{
+	register int	accum, x;
+
+	for (x = 3; --x >= 0; ) {
+		if ((accum = arith(*color0++) + offset) > 0xff)
+			accum = 0xff;
+		*color++ = accum;
+	}
+}
+
+/*
+ * approx1() -- the approximation seeker if there's only one screen
+ */
+bool
+approx1(goal, trans, toler)
+rgbcolor	*goal;
+xlate		*trans;
+int			toler;
+{
+	register rgbcolor	*cscan, *nearest;
+	int					x, mintoler, tv;
+
+	mintoler = toler + 1;
+	nearest = NULL;
+	for (cscan = screen[0].clut, x = screen[0].clutsize; --x >= 0; cscan++) {
+		if ((tv = tolerval(cscan, goal)) < mintoler) {
+			nearest = cscan;
+			if ((mintoler = tv) == 0)
+				break;
+		}
+	}
+
+	if (nearest == NULL) {
+		if (++screen[0].clutsize > MCCLUT)
+			return FALSE;
+		cscan->red   = arith(goal->red) / SCALE1;
+		cscan->green = arith(goal->green) / SCALE1;
+		cscan->blue  = arith(goal->blue) / SCALE1;
+		nearest = cscan;
+	}
+	trans->clutval[0] = nearest - screen[0].clut;
+	return TRUE;
+}
+
+/*
+ * approx2() -- a two-screen approximator
+ *
+ * The general idea here takes multiple passes:
+ * 1. Iterate over sums of pairs of colors taken one from each screen.
+ * 2. If that fails, then for each screen, try adding something that
+ *    should come close with each of the colors in the CLUT for the
+ *    other screen.  (Try it with the smallest CLUT first, to save space.)
+ * 3. If *that* fails, extend both CLUTs with the new color (at half
+ *    intensity).
+ *
+ * Since in step 1, which one would think eats the most time, viewgif was
+ * making repeated calls to nearcolor(), we've switched over to keeping
+ * a table remembering which colors in the palettes are near as determined
+ * by nearcolor().  (Donald Michie would be proud of us.)
+ */
+
+static bool	neartab[MCCLUT][MCCLUT];
+
+#define ROW		1
+#define COLUMN	2
+
+bool
+approx2(goal, trans, toler)
+rgbcolor	*goal;
+xlate		*trans;
+int			toler;
+{
+	register int		c1, c0;
+	rgbcolor			*scan0, *scan1, *near0, *near1;
+	cocoscreen			*extend, *exam, *temp;
+	int					(*tolfun)();
+	char				*near_row;
+	rgbcolor			scalergb;
+	int					mintoler, tv;
+	int					x;
+	bool				found;
+
+	scalergb.red   = arith(goal->red) / SCALE2;
+	scalergb.green = arith(goal->green) / SCALE2;
+	scalergb.blue  = arith(goal->blue) / SCALE2;
+
+	if (toler > 0)
+		tolfun = toler2;
+	else {
+		goal = &scalergb;
+		tolfun = exact;
+	}
+
+	found = FALSE;
+	mintoler = toler + 1;
+
+	for (scan0 = &screen[0].clut[c0 = screen[0].clutsize];
+		 scan0--, --c0 >= 0; )
+	{
+		near_row = neartab[c0];
+		for (c1 = screen[1].clutsize; --c1 >= 0; ) {
+			if (near_row[c1]) {
+				scan1 = &screen[1].clut[c1];
+				if ((tv = (*tolfun)(scan0, scan1, goal)) < mintoler) {
+					near0 = scan0;
+					near1 = scan1;
+					found = TRUE;
+					if ((mintoler = tv) == 0)
+						goto out;
+				}
+			}
+		}
+	}
+
+out:
+	if (!found) {
+		if (screen[1].clutsize < screen[0].clutsize) {
+			extend = &screen[1];
+			exam = &screen[0];
+		} else {
+			extend = &screen[0];
+			exam = &screen[1];
+		}
+		for (x = 2; --x >= 0; ) {
+			if (extend->clutsize < MCCLUT) {
+				near0 = &extend->clut[extend->clutsize];
+				for (scan1 = &exam->clut[c1 = exam->clutsize];
+					 scan1--, --c1 >= 0; )
+				{
+					forcenear(near0, scan1, &scalergb);
+					if ((tv = (*tolfun)(near0, scan1, goal)) < mintoler) {
+						near1 = scan1;
+						found = TRUE;
+						if ((mintoler = tv) == 0)
+							break;
+					}
+				}
+				if (found)
+					break;
+			}
+			temp = extend;
+			extend = exam;
+			exam = temp;
+		}
+	
+		if (found) {
+			if (mintoler > 0)
+				forcenear(near0, near1, &scalergb);
+			extend->clutsize++;
+			if (extend == &screen[0])
+				nearfill(ROW);
+			else {
+				temp = (cocoscreen *) near0;
+				near0 = near1;
+				near1 = (rgbcolor *) temp;
+				nearfill(COLUMN);
+			}
+		} else {
+			if (screen[0].clutsize >= MCCLUT ||
+				screen[1].clutsize >= MCCLUT)
+				return FALSE;
+			near0 = &screen[0].clut[screen[0].clutsize++];
+			near0->red   = arith(scalergb.red) / 2;
+			near0->green = arith(scalergb.green) / 2;
+			near0->blue  = arith(scalergb.blue) / 2;
+			near1 = &screen[1].clut[screen[1].clutsize++];
+			near1->red   = (arith(scalergb.red) + 1) / 2;
+			near1->green = (arith(scalergb.green) + 1) / 2;
+			near1->blue  = (arith(scalergb.blue) + 1) / 2;
+			nearfill(ROW | COLUMN);
+		}
+	}
+	trans->clutval[0] = near0 - screen[0].clut;
+	trans->clutval[1] = near1 - screen[1].clut;
+	return TRUE;
+}
+
+nearfill(section)
+int	section;
+{
+	register int	i, j;
+	rgbcolor		*newrgb;
+
+	if (section & ROW) {
+		newrgb = &screen[0].clut[j = screen[0].clutsize - 1];
+		for (i = screen[1].clutsize; --i >= 0; )
+			neartab[j][i] = nearcolor(newrgb, &screen[1].clut[i]);
+	}
+	if (section & COLUMN) {
+		newrgb = &screen[1].clut[j = screen[1].clutsize - 1];
+		for (i = screen[0].clutsize; --i >= 0; )
+			neartab[i][j] = nearcolor(&screen[0].clut[i], newrgb);
+	}
+}
+
+/*
+ * nearcolor() -- tell approx2() whether two colors are close enough
+ * to be considered for approximate summation to a color in the GIF CLUT.
+ */
+bool
+nearcolor(c1, c2)
+register rgbcolor	*c1, *c2;
+{
+	return abs(arith(c2->red)   - arith(c1->red))   < 2 &&
+		   abs(arith(c2->green) - arith(c1->green)) < 2 &&
+		   abs(arith(c2->blue)  - arith(c1->blue))  < 2;
+}
+
+/*
+ * forcenear() -- stuff a color into a CLUT that is guaranteed to
+ * pass the nearcolor test with the other fixed color (so we don't
+ * have to call nearcolor() explicitly), and should come close to
+ * adding to the fixed color (already in the other screen's CLUT)
+ * to give a specified goal color from the GIF CLUT.
+ */
+forcenear(vary, fixed, goal)
+register BYTE   vary[], fixed[], goal[];
+{
+	register int    d, x;
+
+	for (x = 3; --x >= 0; ) {
+		if ((d = arith(*vary = *goal++ - *fixed) - arith(*fixed)) < 0)
+			d = -1;
+		else if (d > 0)
+			d = 1;
+		*vary++ = *fixed++ + d;
+	}
+}
+
+int
+minadd(color, add)
+register BYTE	*color;
+int             add;
+{
+	int             maxval, tryadd, x;
+
+	maxval = 0;
+	for (x = 3; --x >= 0; ) {
+		if ((tryadd = (arith(*color++) + add) % minmod) > maxval)
+			maxval = tryadd;
+	}
+	return minmod - maxval + add;
+}
+
+int
+tolerval(ccolor, gcolor)
+register BYTE	*ccolor, *gcolor;
+{
+	int     x, v, mv;
+
+	mv = 0;
+	for (x = 3; --x >= 0; ) {
+		v = abs(SCALE1 * *ccolor++ + SCALE1 / 2 - arith(*gcolor++)) -
+			SCALE1 / 2;
+		if (v > mv)
+			mv = v;
+	}
+	return mv;
+}
+
+int
+toler2(ccolor1, ccolor2, gcolor)
+register BYTE	*ccolor1, *ccolor2, *gcolor;
+{
+	int     x, v, mv;
+
+	mv = 0;
+	for (x = 3; --x >= 0; ) {
+		v = abs(SCALE2 * (*ccolor1++ + *ccolor2++) + SCALE2 / 2 -
+				arith(*gcolor++)) - SCALE2 / 2;
+		if (v > mv)
+			mv = v;
+	}
+	return mv;
+}
+
+int
+exact(ccolor1, ccolor2, gcolor)
+register BYTE	*ccolor1, *ccolor2, *gcolor;
+{
+	if (arith(ccolor1[0]) + arith(ccolor2[0]) != arith(gcolor[0]))
+		return 2;
+	if (arith(ccolor1[1]) + arith(ccolor2[1]) != arith(gcolor[1]))
+		return 2;
+	if (arith(ccolor1[2]) + arith(ccolor2[2]) != arith(gcolor[2]))
+		return 2;
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/3rdparty/utils/viewgif/viewgif.c	Fri May 30 21:13:48 2003 +0000
@@ -0,0 +1,1024 @@
+/* OS-9 ViewGIF 2.0   Copyright (C) 1989 by Vaughn Cato */
+
+/*
+ * This program was specifically written for OS-9 on the Tandy Color
+ * Computer 3 as its graphics routines will only work on that system.
+ * The GIF decoding routines were originally taken from the Apollo
+ * workstation version of viewgif by Ben Samit.  As noted in the source
+ * code provided by Ben, most of his code was taken from a GIF to
+ * PostScript converter by Scott Hemphill.  Because of their consideration
+ * in providing the source code with their respective programs I am doing
+ * the same.
+ *
+ * I encourage you to send any enhancements in the Color Computer version
+ * you wish to be publicly distributed to me so that I may update the
+ * program and re-release it.  In this way, a standard version of the
+ * program can be maintained.
+ *
+ * My address is:
+ * Vaughn Cato
+ * 1244 E. Piedmont Rd. NE
+ * Marietta, Ga. 30062
+ */
+
+/*
+ * Any portion of this program may be freely used in any software provided
+ * the source for that program is made freely available to the public and
+ * credit is given to me, Ben Samit, and Scott Hemphill.
+ */
+
+#define EXTERN	/* force a defining instance of global variables */
+
+#include <string.h>
+#include "viewgif.h"
+
+void			showdata();
+char           *mapgpb();
+extern int		errno;
+
+DIRECT int      pauselen = -1;
+DIRECT bool     global;
+
+main(argc, argv)
+int             argc;
+char           *argv[];
+{
+	register char  *p;
+	register bool  *cscan;
+	char            opt;
+	bool            quit;
+	int             x, argnum;
+
+	dfactor  = D_DITHER;
+	magfact  = D_MAG;
+	britefac = D_BRITE;
+	infomode = D_INFO;
+	graytype = D_GRAY;
+	myheight = D_HEIGHT;
+
+	zapmap = aligned = realrand = vefon = FALSE;
+	flicker = newscrn = dispon = TRUE;
+
+	for (cscan = &coloruse[MGCLUT]; cscan > coloruse; )
+		*--cscan = TRUE;
+
+	screen[0].winpath = screen[1].winpath = -1;
+
+	for (argnum = 1; argnum < argc; ++argnum) {
+		if (argv[argnum][0] == '-') {
+			p = &argv[argnum][1];
+			while (opt = *p++) {
+				if (*p == '=')
+					++p;
+				switch (opt) {
+				case 'd':
+					if (*p == '\0')
+						dfactor = 0;
+					else {
+						dfactor = atoi(p);
+						if (dfactor < -MAXTOL1 || dfactor > MAXDITH1)
+							error("Invalid dithering factor", 1);
+					}
+					break;
+				case 'u':
+					usefname = p;
+					break;
+				case 'm':
+					magfact = atoi(p);
+					if (magfact < MINMAG || magfact > MAXMAG)
+						error("Invalid magnification", 1);
+					break;
+				case 'x':
+					startx = atoi(p);
+					if (startx < MINCOORD || startx > MAXCOORD)
+						error("Invalid start x coordinate", 1);
+					break;
+				case 'y':
+					starty = atoi(p);
+					if (starty < MINCOORD || starty > MAXCOORD)
+						error("Invalid start y coordinate", 1);
+					break;
+				case 'g':
+					switch (*p) {
+					case '2':
+						graytype = MAX_GRAY;
+						break;
+					case '3':
+						graytype = NTSC_GRAY;
+						break;
+					default:
+						graytype = AVG_GRAY;
+					}
+					break;
+				case 'a':
+					aligned = TRUE;
+					continue;
+				case 'z':
+					dispon = zapmap = TRUE;
+					continue;
+				case 'v':
+					dispon = vefon = TRUE;
+					if (*p != '\0')
+						vefname = p;
+					break;
+				case 'r':
+					realrand = TRUE;
+					continue;
+				case 's':
+					infomode = NO_INFO;
+					continue;
+				case 'i':
+					if (newscrn)
+						infomode = MUCH_INFO;
+					continue;
+				case 'n':
+					if (vefname == NULL)
+						dispon = FALSE;
+					continue;
+				case 'p':
+					pauselen = atoi(p);
+					break;
+				case 'c':
+					newscrn = FALSE;
+					infomode = NO_INFO;
+					continue;
+				case 'f':
+					flicker = FALSE;
+					continue;
+				case 'b':
+					britefac = atoi(p);
+					if (britefac < MINBRITE || britefac > MAXBRITE)
+						error("Invalid brightness factor", 1);
+					break;
+				case '?':
+					usage();
+				default:
+					fatal("Unknown option");
+				}
+				break;
+			}
+			for (x = argnum + 1; x < argc; ++x)
+				argv[x - 1] = argv[x];
+			--argc;
+			--argnum;
+		}
+	}
+
+	if (argc < 2)
+		usage();
+
+	if ((infile = fopen(argv[1], "r")) == NULL)
+		error("Cannot open input file", errno);
+
+	if (flicker) {
+		maxdith = MAXDITH2;
+		minmod = SCALE2;
+		approx = approx2;
+	} else {
+		maxdith = MAXDITH1;
+		minmod = SCALE1;
+		approx = approx1;
+	}
+	if (dfactor > maxdith)
+		dfactor = maxdith;
+	low0 = minmod / 2;
+	up0 = low0 + 1;
+
+	checksig();
+	readscrn();
+	if (!realrand)
+		makerand();
+
+
+	quit = FALSE;
+	framenum = 0;
+	do {
+		switch (getc(infile)) {
+		case '\0':
+			break;
+		case ',':
+			++framenum;
+			readimag();
+			waituser();
+			break;
+		case ';':
+			quit = TRUE;
+			break;
+		case '!':
+			readext();
+			break;
+		default:
+			quit = TRUE;
+			break;
+		}
+		if (!dispon && vefname == NULL && (usefname == NULL || !newuse))
+			break;
+	} while (!quit);
+
+	if (dispon) {
+		if (zapmap) {
+			if ((infile = freopen(argv[1], "r+", infile)) == NULL)
+				error("Cannot rewrite global map", errno);
+			else
+				zapglobmap();
+		}
+		killwind();
+	}
+
+	actwin = 1;
+	select();
+	flushwin();
+}
+
+makerand()
+{
+	register char	*rscan1, *rscan2;
+	int				x, f2;
+	char			temp;
+	bool			oddrow, oddrc;
+
+	f2 = maxdith / 2;
+
+	/* initialize */
+	x = 256;
+	for (rscan2 = &randtab[16][0]; (rscan2 -= 16) >= &randtab[0][0]; )
+		for (rscan1 = rscan2 + 16; rscan1 > rscan2; )
+			*--rscan1 = (--x * f2) >> 8;
+
+	/*
+	 * permute randomly (I don't think the original made all
+	 * permutations equally likely, alas)
+	 */
+	rscan1 = &randtab[0][0];
+	for (x = 256; x > 0; x--) {
+		rscan2 = rscan1 + (rand() % x);
+		temp = *rscan1;
+		*rscan1++ = *rscan2;
+		*rscan2 = temp;
+	}
+
+	oddrow = FALSE;
+	for (rscan2 = &randtab[16][0]; (rscan2 -= 16) >= &randtab[0][0]; ) {
+		oddrc = oddrow = !oddrow;
+		for (rscan1 = rscan2 + 16; --rscan1 >= rscan2; ) {
+			if (oddrc = !oddrc)
+				*rscan1 += maxdith;
+			if (oddrow)
+				*rscan1 += f2;
+		}
+	}
+}
+
+readuse()
+{
+	char            newname[64];
+	register char  *ep;
+	int             usefile;
+
+	getusename(newname);
+	if ((usefile = open(newname, 1)) == -1) {
+		for (ep = &coloruse[MGCLUT]; --ep >= coloruse; )
+			*ep = TRUE;
+		newuse = TRUE;
+	} else {
+		read(usefile, coloruse, MGCLUT * sizeof(bool));
+		close(usefile);
+		if (infomode != NO_INFO)
+			printf("Using usage file\n");
+		newuse = FALSE;
+	}
+}
+
+getusename(buffer)
+{
+	if (framenum > 1)
+		sprintf(buffer, "%s%d", usefname, framenum);
+	else
+		strcpy(buffer, usefname);
+}
+
+writeuse()
+{
+	register char  *cp, *gp;
+	int             usecount, usefile;
+	char            newname[64];
+
+	usecount = 0;
+	for (gp = &globuse[globcolors], cp = &coloruse[globcolors];
+		 --gp, --cp >= coloruse; )
+	{
+		if (*cp) {
+			*gp = TRUE;
+			++usecount;
+		}
+	}
+	if (infomode != NO_INFO)
+		printf("%d out of %d colors used.\n", usecount, globcolors);
+	if (usefname != NULL) {
+		getusename(newname);
+		if (newuse) {
+			if ((usefile = creat(newname, 3)) == -1)
+				error("Cannot create usage file", errno);
+			else
+				write(usefile, coloruse, globcolors);
+		}
+		close(usefile);
+	}
+}
+
+zapglobmap()
+{
+	register rgbcolor	*gp, *used;
+	register int		i;
+
+	for (i = 0; i < globcolors; i++) {
+		if (globuse[i]) {
+			used = &globclut[i];
+			for (gp = &globclut[i = globcolors]; --i, --gp >= globclut; )
+			{
+				if (!globuse[i]) {
+					gp->red   = used->red;
+					gp->green = used->green;
+					gp->blue  = used->blue;
+				}
+			}
+			fseek(infile, clutpos, 0);
+			fwrite(globclut, sizeof(rgbcolor), globcolors, infile);
+			return;
+		}
+	}
+}
+
+saveimag()
+{
+	register cocoscreen	*sscan;
+	char            	newname[64];
+	int             	file, x, scrnum, scrntype = 0;
+
+	for (scrnum = 0; scrnum <= flicker; ++scrnum) {
+		sscan = &screen[scrnum];
+		strcpy(newname, vefname);
+		if (framenum > 1)
+			sprintf(newname + strlen(newname), "%d", framenum);
+		if (scrnum == 1)
+			strcat(newname, ".2");
+		actwin = sscan->winpath;
+		select();
+		flushwin();
+		if ((file = creat(newname, 3)) == -1)
+			error("Cannot create vef file", errno);
+		else {
+			write(file, &scrntype, sizeof(scrntype));
+			write(file, sscan->pal, MCCLUT * sizeof(colorcode));
+			for (x = 0; x < 8; ++x)
+				write(file, gpbufptr, 160);
+			for (x = 0; x < MROWS; ++x) {
+				getblk(groupnum, bufnum, 0, x, MCOLS - 1, 1);
+				flushwin();
+				write(file, gpbufptr, 160);
+			}
+			close(file);
+		}
+	}
+}
+
+readext()
+{
+	char            buf[255];
+	int				count;
+
+	(void) getc(infile);
+	while (count = getc(infile))
+		fread(buf, 1, count, infile);
+}
+
+DIRECT int      real_x, real_y;
+DIRECT int      x_coord, y_coord;
+
+typedef struct {
+	int		ilv_r0;		/* starting row */
+	int		ilv_dr;		/* step size */
+}	ilvspec;
+
+static ilvspec	ilvdat[] = {
+	{1, 2}, /* .|.|.|.|.|.|.|.|. */
+	{2, 4}, /* ..|...|...|...|.. */
+	{4, 8}, /* ....|.......|.... */
+	{0, 8},	/* |.......|.......| */
+};
+
+readimag()
+{
+	BYTE				buf[9];
+	unsigned        	left, top, width, height;
+	bool            	local, intrlevd;
+	int             	lclbits;
+	int             	row, rowoffset;
+	register int		n;
+	int					lineread, hold, xpos, x;
+	register ilvspec   *ilvscan;
+
+	readuse();
+	newwind();
+
+	/* read header info */
+	fread(buf, sizeof(BYTE), sizeof(buf) / sizeof(BYTE), infile);
+	left = arith(buf[0]) | (buf[1] << 8);
+	top  = arith(buf[2]) | (buf[3] << 8);
+	imagwid  = width = arith(buf[4]) | (buf[5] << 8);
+	imaghigh = height = arith(buf[6]) | (buf[7] << 8);
+
+	if (infomode != NO_INFO)
+		printf("gif dimensions: %d x %d pixels\n", imagwid, imaghigh);
+
+	local = buf[8] & 0x80;
+	intrlevd = buf[8] & 0x40;
+
+	if (local) {
+		char            tempbuf[3];
+
+		lclbits = (buf[8] & 0x7) + 1;
+		for (x = 1 << lclbits; --x >= 0; )
+			fread(tempbuf, 3, 1, infile);
+	} else if (!global)
+		fatal("no CLUT present for image");
+
+	ilevtab[MROWS] = ILEVEND;
+	for (x = MROWS; --x >= 0; )
+		ilevtab[x] = ILEVMISS;
+
+	if (!aligned)
+		n = myheight;
+	else {
+		for (n = imaghigh; n > 200; n /= 2)
+			;
+	}
+	n *= magfact;
+
+	rowoffset = 3 * starty * magfact;
+	lineread = 0;
+	if (intrlevd) {
+		for (ilvscan = &ilvdat[elements(ilvdat)]; --ilvscan >= ilvdat; ) {
+			for (x = ilvscan->ilv_r0; x < imaghigh; x += ilvscan->ilv_dr) {
+				row = (long) x * n / imaghigh - rowoffset;
+				if (row >= 0 && row < MROWS)
+					ilevtab[row] = lineread;
+				++lineread;
+			}
+		}
+	} else {
+		for (x = 0; x < imaghigh; ++x) {
+			row = (long) x * n / imaghigh - rowoffset;
+			if (row >= 0 && row < MROWS)
+				ilevtab[row] = lineread;
+			++lineread;
+		}
+	}
+
+	x = startx * (imagwid / 64);
+	hold = xpos = 0;
+	while (xpos < mywidth) {
+		for (hold += mywidth * magfact; hold >= imagwid; hold -= imagwid)
+			xtab[xpos++] = x;
+		x++;
+	}
+
+	real_x = real_y = 0;
+	x_coord = y_coord = 0;
+
+	if (dispon || (usefname != NULL && newuse)) {
+		readrast(width, height);
+		writeuse();
+		if (vefname != NULL)
+			saveimag();
+	}
+}
+
+DIRECT int      datum;
+DIRECT int      bits;
+char            buf[255];
+
+readrast(width, height)
+unsigned        width, height;
+{
+	register char		   *ch;
+	register codetype	   *cscan;
+	int						count, code;
+
+	datasize = getc(infile);
+	codesize = datasize + 1;
+	codemask = (1 << codesize) - 1;
+	clear = 1 << datasize;
+	eoi = clear + 1;
+	bits = 16;
+
+	/* initialize code table */
+	for (cscan = &codetab[code = clear]; --cscan, --code >= 0; ) {
+		cscan->prefix = (codetype *) NULL;
+		cscan->first = cscan->suffix = code;
+	}
+
+	while ((count = getc(infile)) > 0) {
+		fread(buf, sizeof(*buf), count, infile);
+		for (ch = buf; --count >= 0; )
+			addbyte(*ch++);
+	}
+
+	datum >>= bits;
+	for (bits = 16 - bits; x_coord != 0 && bits >= codesize; bits -= codesize) {
+		process(datum & codemask);
+		datum >>= codesize;
+	}
+}
+
+addbyte(c)
+char            c;
+{
+	/*
+	 *	datum += (long)(*ch & 0xff) << bits;
+	 *	bits += 8;
+	 *	while (bits >= codesize) {
+	 *		code = datum & codemask;
+	 *		datum >>= codesize;
+	 *		bits -= codesize;
+	 *		if (code == eoi)
+	 *			goto exitloop;
+	 *		process(code);
+	 *	}
+	 */
+#asm
+ ldb 5,s
+ lda <bits+1
+ suba #7
+ bls _addb3
+ sta <bits+1
+ lda <datum
+ sta <datum+1
+ stb <datum
+ lda #1
+ bra _addb4
+_addb3
+ lda #8
+_addb1
+ lsrb
+ ror <datum
+ ror <datum+1
+_addb4
+ dec <bits+1
+ bne _addb2
+* pshs d
+ tfr d,u
+ ldd <codesize
+ std <bits
+ ldd <datum
+ anda <codemask
+ andb <codemask+1
+ pshs d
+ lbsr process
+ leas 2,s
+* puls d
+ tfr u,d
+_addb2
+ deca
+ bne _addb1
+#endasm
+}
+
+process(code)
+int             code;
+{
+	register codetype       *p, *cp;
+	static DIRECT int		avail;
+	static DIRECT codetype	*oldcp;
+
+	if (code == clear) {
+		/* clear table */
+		codesize = datasize + 1;
+		codemask = (1 << codesize) - 1;
+		avail = clear + 2;
+		oldcp = NULL;
+	} else if (code < avail) {
+		outcode(cp = &codetab[code]);	/* output the code */
+		if (oldcp != NULL) {
+			/* add new entry */
+			p = &codetab[avail++];
+			/* prefix is previous code, first is prefix's first */
+			p->first = (p->prefix = oldcp)->first;
+			p->suffix = cp->first;	/* suffix is first of current */
+			if ((avail & codemask) == 0 && avail < MCODE) {
+				/* increase code size */
+				codesize++;
+				codemask += avail;
+			}
+		}
+		oldcp = cp;
+	} else if (code == avail && oldcp != NULL) {
+		/* repeat of last code */
+		p = &codetab[avail++];
+		/* prefix is previous code, first is prefix's first */
+		p->first = (p->prefix = oldcp)->first;
+		p->suffix = p->first;		/* Suffix is first of last */
+		outcode(p);
+		if ((avail & codemask) == 0 && avail < MCODE) {
+			/* increase code size */
+			codesize++;
+			codemask += avail;
+		}
+		oldcp = &codetab[code];
+	} else
+		fatal("illegal code in raster data");
+}
+
+/*
+ * outcode() -- we finally get the data out of the LZ decompression, and
+ * fill a buffer until we get a line's worth of data.  The loop with x0
+ * and x is intended to take advantage of the mostly increasing nature
+ * of ilevtab[], replacing an O(n**2) loop that was there before.  Timing,
+ * however, shows that the change doesn't affect display time, so the
+ * performance bottleneck must be elsewhere.  Rats.
+ */
+outcode(p)
+codetype       *p;
+{
+	register BYTE		*sp = &codestk[0];
+	register int		x;
+	static DIRECT int	x0 = 0;
+
+	for (; p; p = p->prefix)
+		*sp++ = p->suffix;
+
+	while (--sp >= &codestk[0]) {
+		coloruse[arith(*sp)] = TRUE;
+		if (real_x == 0) {
+			y_coord = -1;
+			x = x0;
+			do {
+				if (++x >= myheight)
+					x = 0;
+				if (ilevtab[x] == real_y) {
+					x0 = y_coord = x;
+					break;
+				}
+			} while (x != x0);
+		}
+		if (y_coord >= 0) {
+			while (xtab[x_coord] == real_x)
+				linestor[x_coord++] = arith(*sp);
+		}
+		if (++real_x >= imagwid) {
+			if (y_coord >= 0 && dispon) {
+				do {
+					doline();
+				} while (ilevtab[++y_coord] == ILEVMISS);
+			}
+			real_x = x_coord = 0;
+			++real_y;
+		}
+	}
+}
+
+DIRECT int      bitcount, pixperbyte;
+DIRECT char    *byteptr;
+
+doline()
+{
+	register xlate	*p;
+	register char	*rrow;
+	register int	x, addval, scrnum;
+	cocoscreen		*sscan;
+
+	rrow = &randtab[y_coord & 15][0];
+
+	for (sscan = &screen[scrnum = (flicker ? 2 : 1)]; --sscan, --scrnum >= 0;)
+	{
+		actwin = sscan->winpath;
+		bitcount = pixperbyte;
+		byteptr = gpbufptr;
+		if (dfactor > 0) {
+			for (x = 0; x < mywidth; ++x) {
+				addval = (realrand) ? rand85(y_coord + x)
+									: rrow[x & 15];
+				for (p = &transtab[linestor[x]][1]; p->addval <= addval; )
+					p++;
+				--p;
+				addpixel(p->clutval[scrnum]);
+			}
+		} else {
+			for (x = 0; x < mywidth; ++x)
+				addpixel(transtab[linestor[x]][0].clutval[scrnum]);
+		}
+		if (flicker)
+			select();
+		putblk(groupnum, bufnum, 0, y_coord);
+		flushwin();
+	}
+}
+
+addpixel(c)
+{
+	/*
+	 *	*byteptr = (*byteptr << (gmode ? 2 : 4)) | c;
+	 *	if (--bitcount == 0) {
+	 *		byteptr++;
+	 *		bitcount = pixperbyte;
+	 *	}
+	 *
+	 * (The spelling discrepancy here is due to the 6809's chopping off
+	 * identifier lengths at a different point than the assembler appears to!)
+	 */
+#asm
+ ldx <byteptr
+ ldb ,x
+ lda <gmode+1
+ bne _addpix1
+ lslb
+ lslb
+_addpix1
+ lslb
+ lslb
+ orb 5,s
+ stb ,x
+ dec <bitcount+1
+ bne _addpix2
+ leax 1,x
+ stx <byteptr
+ lda <pixperby+1
+ sta <bitcount+1
+_addpix2
+#endasm
+}
+
+rand85(n)
+int             n;
+{
+	register unsigned	result;
+
+	result = rand() % maxdith;
+	if (n & 1)
+		result += maxdith + 1;
+	return result;
+}
+
+readscrn()
+{
+	char            	buf[7];
+	int             	x;
+	register rgbcolor	*rp;
+
+	fread(buf, sizeof(*buf), 7, infile);
+	imagwid = arith(buf[0]) | (buf[1] << 8);
+	imaghigh = arith(buf[2]) | (buf[3] << 8);
+	if (infomode != NO_INFO)
+		printf("%d x %d screen\n", imagwid, imaghigh);
+	global = (buf[4] & 0x80) != 0;
+	if (global) {
+		globbits = (buf[4] & 0x07) + 1;
+		globcolors = 1 << globbits;
+		if (infomode != NO_INFO)
+			printf("global bitmap: %d colors\n", globcolors);
+		clutpos = ftell(infile);
+		fread(globclut, 3, globcolors, infile);
+		if (infomode == MUCH_INFO) {
+			for (rp = globclut, x = 0; x < globcolors; rp++, x++) {
+				printf("color %d = %3d,%3d,%3d\n", x,
+				       arith(rp->red), arith(rp->green), arith(rp->blue));
+			}
+		}
+	} else
+		fatal("cannot handle non-global bitmaps");
+}
+
+/*
+ * newwind() -- the big banana; determine the CoCo CLUT(s) that will
+ * best display the GIF image given the GIF CLUT.
+ */
+
+newwind()
+{
+	register cocoscreen	*sscan;
+	register bool		*bscan;
+	register colorcode	*cscan;
+	rgbcolor			*rgbp;
+	bool				first;
+	char				blip;
+	int					x, hival, loval, midval;
+
+	fixgmap();
+
+	if (infomode != NO_INFO) {
+		printf("Analyzing..");
+		fflush(stdout);
+	}
+
+	loval = -MAXTOL1;
+	midval = hival = dfactor;
+
+	while (loval <= hival) {
+		dfactor = midval;
+		if (setmap()) {
+			loval = midval + 1;
+			blip = '+';
+		} else {
+			hival = midval - 1;
+			blip = '-';
+		}
+		if (infomode != NO_INFO) {
+			putchar(blip);
+			fflush(stdout);
+		}
+		midval = (loval + hival) / 2;
+	}
+
+	if (dfactor != hival) {
+		dfactor = hival;
+		setmap();
+	}
+
+	if (infomode != NO_INFO) {
+		putchar('\n');
+		showdata();
+	}
+
+	if (screen[0].clutsize <= 4 && !vefon) {
+		gmode = TRUE;
+		mywidth = 640;
+		pixperbyte = 4;
+	} else {
+		gmode = FALSE;
+		mywidth = 320;
+		pixperbyte = 2;
+	}
+
+	first = TRUE;
+	for (sscan = &screen[(flicker ? 2 : 1)]; --sscan >= screen; ) {
+		if (dispon)
+			sscan->winpath = initwin(first, sscan->winpath);
+		for (cscan = &sscan->pal[x = sscan->clutsize]; --cscan, --x >= 0; ) {
+			*cscan = colorval(&sscan->clut[x]);
+			if (dispon)
+				palette(x, *cscan);
+		}
+		if (dispon) {
+			border(0);
+			flushwin();
+		}
+		first = FALSE;
+	}
+	for (bscan = &coloruse[globcolors]; --bscan >= coloruse; )
+		*bscan = FALSE;
+}
+
+/* colorval() -- encode an RGB222 value the way the GIME likes it */
+
+colorval(color)
+register rgbcolor		*color;
+{
+	static char		cocode[] = {'\000', '\001', '\010', '\011'};
+
+	return  (((cocode[color->red & 3] << 1) |
+			   cocode[color->green & 3]) << 1) | cocode[color->blue & 3];
+}
+
+/*
+ * showdata() -- display a bunch of information on the CLUTs used
+ * if it's been asked for
+ */
+void
+showdata()
+{
+	register rgbcolor		*rscan;
+	register cocoscreen		*sscan;
+	int						x, y;
+
+	if (dfactor > 0)
+		printf("Dithering factor = %d\n", dfactor);
+	else
+		printf("Color tolerance = %d\n", -dfactor);
+	fputs("Resulting coco CLUT: ", stdout);
+	printf("%d colors", screen[0].clutsize);
+	if (flicker)
+		printf(" + %d colors\n", screen[1].clutsize);
+	else
+		putchar('\n');
+	if (infomode == MUCH_INFO) {
+		for (x = 0; x < (flicker ? 1 : 2); x++) {
+			sscan = &screen[x];
+			for (rscan = sscan->clut, y = 0; y < sscan->clutsize; y++) {
+				printf("%2d:%d,%d,%d=%d\n", y,
+					rscan->red, rscan->green, rscan->blue, colorval(rscan));
+				rscan++;
+			}
+			putchar('\n');
+		}
+		fputs("Translation table:\n", stdout);
+		for (x = 0; x < globcolors; ++x) {
+			if (coloruse[x]) {
+				printf("%3d:", x);
+				for (y = 0; y < 4 && transtab[x][y].addval != BOGUSDITH; ++y) {
+					printf(" %3d=%3d",
+						transtab[x][y].addval, transtab[x][y].clutval[0]);
+					if (flicker)
+						printf(",%3d", transtab[x][y].clutval[1]);
+				}
+				putchar('\n');
+			}
+		}
+	}
+}
+
+/*
+ * fixgmap() -- scale colors in the GIF image global CLUT in accordance
+ * with the brightness specification, and in passing, convert to gray
+ * if requested (either using the average of the components or their
+ * maximum).
+ */
+fixgmap()
+{
+	register rgbcolor	*rscan;
+	int             	x, r, g, b;
+
+	for (rscan = &globclut[x = globcolors]; --rscan, --x >= 0; ) {
+		if (coloruse[x]) {
+			r = arith(rscan->red);
+			g = arith(rscan->green);
+			b = arith(rscan->blue);
+			switch (graytype) {
+			case AVG_GRAY:
+				r = g = b = (r + g + b) / 3;
+				break;
+			case NTSC_GRAY:
+				r = g = b = (30 * r + 59 * g + 11 * b) / 100;
+				break;
+			case MAX_GRAY:
+				if (g > r)
+					r = g;
+				if (b > r)
+					r = b;
+				g = b = r;
+				break;
+			}
+			rscan->red   = (britefac * r) >> 4;
+			rscan->green = (britefac * g) >> 4;
+			rscan->blue  = (britefac * b) >> 4;
+		}
+	}
+}
+
+killwind()
+{
+	mapgpb(screen[flicker].winpath, groupnum, bufnum, 0);
+	killbuf(groupnum, bufnum);
+}
+
+waituser()
+{
+	char            	c;
+	int             	x;
+	register cocoscreen	*sscan;
+
+	if (dispon) {
+		if (pauselen < 0) {
+			for (x = 5; --x >= 0; )
+				bell();
+			flushwin();
+		}
+		if (flicker) {
+			pauselen *= 30;
+			do {
+				for (sscan = &screen[2]; --sscan >= screen; ) {
+					actwin = sscan->winpath;
+					select();
+					flushwin();
+					sleep(2);
+					if (ready(actwin)) {
+						read(actwin, &c, 1);
+						if (c == '\n')
+							return;
+					}
+				}
+			} while (pauselen < 0 || --pauselen >= 0);
+		} else if (pauselen > 0) {
+			sleep(60 * pauselen);
+		} else if (pauselen < 0) {
+			do {
+				read(screen[0].winpath, &c, 1);
+			} while (c != '\n');
+		}
+	}
+}
+
+ready(path)
+int             path;
+{
+#asm
+ lda 5,s
+ ldb #SS.Ready
+ os9 I$GetStt
+ bcc _ready1
+ ldd #0
+ bra _ready2
+_ready1
+ ldd #1
+_ready2
+#endasm
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/3rdparty/utils/viewgif/viewgif.h	Fri May 30 21:13:48 2003 +0000
@@ -0,0 +1,197 @@
+/*
+ * viewgif.h -- common header fodder for viewgif
+ */
+
+#include <stdio.h>
+
+#ifdef OSK
+/* the OS-9/68000 C compiler knows about void now! */
+#define DIRECT
+typedef unsigned char	BYTE;
+#define arith(byte)	(byte)
+#else
+typedef int		void;
+#define DIRECT direct
+typedef char			BYTE;
+#define arith(byte)	((byte) & 0xff)
+#endif
+
+/* the canonical dodge for being sure of exactly one defining declaration */
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef char	bool;		/* make up for a C deficiency */
+
+#define FALSE	(1 == 0)
+#define TRUE	(!FALSE)
+
+#define elements(array)	(sizeof(array) / sizeof(array[0]))
+#define maxnum(bits)	((1 << (bits)) - 1)
+
+/*
+ * typedef to let us look at RGB colors two ways--one, as an array of
+ * components; two, as a structure with nameable components.
+ */
+
+typedef union {
+	BYTE	rgbarr[3];
+	struct {
+		BYTE	rval, gval, bval;
+	}		rgbstr;
+}	rgbcolor;
+
+#define	red		rgbstr.rval
+#define green	rgbstr.gval
+#define blue	rgbstr.bval
+
+/* Values and variables related to the GIF spec */
+
+#define MGCLUT	 	256		/* maximum number of colors in a GIF picture */
+#define GBITS		8		/* # of bits in each component of a GIF color */
+#define MCODE		4096	/* number of 12-bit LZ codes */
+
+typedef struct cstruct {
+	struct cstruct	*prefix;
+	char			first, suffix;
+}		codetype;
+
+EXTERN bool				coloruse[MGCLUT];	/* flags colors in use */
+EXTERN bool				globuse[MGCLUT];	/* global usage flag */
+EXTERN rgbcolor			globclut[MGCLUT];	/* RGB colors in image */
+EXTERN DIRECT int		globbits;			/* # bits for global color map */
+EXTERN DIRECT int		globcolors;			/* # possible colors */
+EXTERN DIRECT unsigned	imagwid, imaghigh;	/* image width/height in pixels */
+
+EXTERN codetype			codetab[MCODE];		/* LZ code table */
+EXTERN BYTE				codestk[MCODE];		/* buffer for decoded bytes */
+EXTERN DIRECT int		codesize;			/* LZ code size in bits */
+EXTERN DIRECT int		codemask;			/* LZ code mask */
+EXTERN DIRECT int		clear;				/* code for code table clear */
+EXTERN DIRECT int		eoi;				/* code for end of image */
+EXTERN DIRECT int		datasize;			/* ??? */
+
+/* Now for CoCo-related stuff... */
+
+#define MCCLUT		 16		/* max size of Color Look-Up Table on CoCo 3 */
+#define CBITS		  2		/* # of bits in each component of a CoCo 3 color */
+#define MROWS		192		/* max number of rows we can display */
+#define MCOLS		640		/* max number of cols we can display */
+
+#define MSCREENS	  2		/* number of screens we may cycle among */
+
+/* type to hold the CoCo encoding of a color */
+
+typedef BYTE	colorcode;
+
+/*
+ * type to represent the screens that will collectively contain the
+ * GIF image for display--we add one to the sizes of the arrays for
+ * palettes to try to speed up the search for color mappings (see
+ * setmap.c functions)
+ */
+
+typedef struct {
+	int			winpath;			/* path # for window to display on */
+	int			clutsize;			/* colors actually used */
+	rgbcolor	clut[MCCLUT];		/* their RGB values */
+	colorcode	pal[MCCLUT];		/* their CoCo encodings */
+}	cocoscreen;
+
+typedef struct {
+	char		addval;
+	char		clutval[MSCREENS];
+}	xlate;
+
+EXTERN cocoscreen	screen[MSCREENS];		/* screens to be cycled among */
+EXTERN int			ilevtab[MROWS + 1];		/* interleave table */
+EXTERN int			xtab[MCOLS];			/* ??? */
+EXTERN int			linestor[MCOLS];		/* ??? */
+EXTERN xlate		transtab[MGCLUT][5];	/* translations of GIF colors */
+EXTERN char			randtab[16][16];		/* pseudo-random table */
+
+/* non-scan line values for ilevtab[] */
+#define ILEVMISS	(-1)					/* marks scan lines missed */
+											/* in readimag() scaling loops */
+#define ILEVEND		(-20)					/* end marker guaranteed not */
+											/* to match a valid scan line */
+											/* or ILEVMISS! */
+
+/* conversion between GIF's RGB space and the CoCo's RGB space */
+#define SCALE1		(maxnum(GBITS) / maxnum(CBITS))
+#define SCALE2		(SCALE1 / 2)
+
+/* limits */
+
+/* dithering factor */
+#define MAXDITH1	(SCALE1 / 2)
+#define MAXDITH2	(SCALE2 / 2)
+#define BOGUSDITH	127				/* end marker for addval */
+/* color tolerance (represented by negative "dithering factor") */
+#define MAXTOL1		SCALE1
+#define MAXTOL2		SCALE2
+/* magnification factor */
+#define MINMAG		  1
+#define MAXMAG		 64
+/* brightness */
+#define MINBRITE	  1
+#define MAXBRITE	 16
+/* starting coordinates (units: 64ths of the image size along the axis) */
+#define MINCOORD	  1
+#define MAXCOORD	 64
+
+/* some symbolic names for the values of some twistable knobs */
+
+#define NO_INFO		  0
+#define SOME_INFO	  1
+#define MUCH_INFO	  2
+
+#define NO_GRAY		  0
+#define AVG_GRAY	  1
+#define MAX_GRAY	  2
+#define NTSC_GRAY	  3
+
+/* default values */
+
+#define D_INFO		SOME_INFO
+#define D_GRAY		NO_GRAY
+#define D_BRITE		MAXBRITE
+#define D_DITHER	MAXDITH1
+#define D_MAG		MINMAG
+#define D_HEIGHT	MROWS
+
+EXTERN DIRECT FILE	*infile;			/* file containing GIF image */
+EXTERN DIRECT long	clutpos;			/* position of global CLUT in file */
+EXTERN DIRECT int	infomode;			/* control amount of commentary */
+EXTERN DIRECT int	graytype;			/* what kind of gray scale, if any */
+EXTERN DIRECT int	dfactor;			/* dithering factor */
+EXTERN DIRECT int	maxdith;			/* upper bound on random dither */
+EXTERN DIRECT int	magfact;			/* magnification factor */
+EXTERN DIRECT int	britefac;			/* brightness factor */
+EXTERN DIRECT int	startx, starty;		/* coord to map to top left corner */
+EXTERN DIRECT bool	realrand;			/* use random #s instead of table */
+EXTERN DIRECT bool	flicker;			/* cycle among screens */
+EXTERN DIRECT bool	dispon;				/* display the image */
+EXTERN DIRECT bool	zapmap;				/* overwrite unused map colors */
+EXTERN DIRECT bool	vefon;				/* save the image in VEF fmt */
+EXTERN DIRECT bool	aligned;			/* align to pixels */
+EXTERN DIRECT bool	newscrn;			/* switch to new window for display */
+EXTERN DIRECT char	*usefname;			/* to name of color usage file */
+EXTERN DIRECT char	*vefname;			/* to name of VEF output file */
+EXTERN DIRECT int	mywidth, myheight;	/* width, height we will display */
+EXTERN DIRECT int	actwin;				/* path for buffered gfx data */
+EXTERN DIRECT int	groupnum, bufnum;	/* get/put buffer information */
+EXTERN DIRECT int	framenum;			/* frame number--whatever that is */
+EXTERN DIRECT char	*gpbufptr;			/* pointer to get/put buffer */
+EXTERN DIRECT int	gmode;				/* graphics mode we're using */
+EXTERN DIRECT int	newuse;				/* ??? */
+EXTERN DIRECT bool	(*approx)();		/* to color approximation function */
+EXTERN DIRECT int	minmod;				/* modulus for minadd() */
+EXTERN DIRECT int	low0, up0;			/* default upper/lower limits for */
+										/* approximation searches */
+extern bool			approx1();			/* one-screen approximation */
+extern bool			approx2();			/* two-screen approximation */
+
+/* miscellanea for support routines */
+#define fatal(s)	error((s), 1)		/* fatal error (no natural errno) */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/3rdparty/utils/viewgif/viewvef.c	Fri May 30 21:13:48 2003 +0000
@@ -0,0 +1,340 @@
+/*
+ * ViewVEF 1.0 by Vaughn Cato
+ * For use in displaying flicker VEF files
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+int             actwin;
+char           *gpbufptr;
+char           *mapgpb();
+
+main(argc, argv)
+int             argc;
+char           *argv[];
+{
+	int             winfile1, winfile2;
+	int				x, groupnum, bufnum, flicker, file, scrnum, pauselen = -1;
+	char            c, newname[128];
+
+	if (argc < 2) {
+		printf("Usage: viewvef <vef file> [<pause length>]");
+		printf("       Displays normal or flicker VEF files\n");
+		exit(1);
+	}
+	if (argc == 3)
+		pauselen = atoi(argv[2]);
+	for (scrnum = 0; scrnum <= 1; ++scrnum) {
+		if (scrnum == 0) {
+			if ((file = open(argv[1], 1)) == -1) {
+				fprintf(stderr, "Cannot open %s\n", argv[scrnum + 1]);
+				exit(errno);
+			}
+			winfile1 = newwin();
+			groupnum = procid();
+			bufnum = 1;
+			getblk(groupnum, bufnum, 0, 0, 639, 1);
+			flushwin();
+			if ((gpbufptr = mapgpb(winfile1, groupnum, bufnum, 1)) == NULL)
+				exit(errno);
+		} else {
+			strcpy(newname, argv[1]);
+			strcat(newname, ".2");
+			if ((file = open(newname, 1)) == -1)
+				break;
+			flicker = 1;
+			winfile2 = newwin();
+		}
+		read(file, &c, 1);
+		read(file, &c, 1);
+		for (x = 0; x < 16; ++x) {
+			read(file, &c, 1);
+			palette(x, c);
+		}
+		for (x = 0; x < 8; ++x)
+			read(file, gpbufptr, 160);
+		for (x = 0; x < 192; ++x) {
+			read(file, gpbufptr, 160);
+			putblk(groupnum, bufnum, 0, x);
+			flushwin();
+		}
+	}
+	if (flicker) {
+		pauselen *= 30;
+		for (;;) {
+			actwin = winfile1;
+			select();
+			flushwin();
+			sleep(2);
+			if (ready(winfile1)) {
+				read(winfile1, &c, 1);
+				if (c == 13)
+					break;
+			}
+			actwin = winfile2;
+			select();
+			flushwin();
+			sleep(2);
+			if (ready(winfile2)) {
+				read(winfile2, &c, 1);
+				if (c == 13)
+					break;
+			}
+			if (pauselen == 0)
+				break;
+			if (pauselen > 0)
+				--pauselen;
+		}
+	} else {
+		if (pauselen >= 0) {
+			if (pauselen > 0)
+				sleep(60 * pauselen);
+		} else {
+			do {
+				read(winfile1, &c, 1);
+			} while (c != 13);
+		}
+	}
+	mapgpb(winfile1, groupnum, bufnum, 0);
+	actwin = 1;
+	select();
+	flushwin();
+	close(winfile1);
+	if (flicker)
+		close(winfile2);
+}
+
+sleep(ticks)
+int             ticks;
+{
+#asm
+ ldx 4,s
+ os9 $0a
+#endasm
+}
+
+newwin()
+{
+	int             winfile, windesc;
+
+	windesc = attach("w");
+	if ((winfile = open("/w", 3)) == -1)
+		exit(errno);
+	actwin = winfile;
+	dwset(8, 0, 0, 40, 24, 0, 0, 0);
+	curoff();
+	select();
+	flushwin();
+	detach(windesc);
+	return (winfile);
+}
+
+fcolor(c)
+	int             c;
+{
+	static char     outstr[] = {0x1b, 0x32, 0};
+
+	outstr[2] = c;
+	writemem(outstr, sizeof(outstr));
+}
+
+dwset(sty, cpx, cpy, szx, szy, prn1, prn2, prn3)
+	int             sty, cpx, cpy, szx, szy, prn1, prn2, prn3;
+{
+	static char     outstr[] = {0x1b, 0x20, 0, 0, 0, 0, 0, 0, 0, 0};
+	int             size;
+
+	outstr[2] = sty;
+	outstr[3] = cpx;
+	outstr[4] = cpy;
+	outstr[5] = szx;
+	outstr[6] = szy;
+	if (sty > 0 && sty <= 8) {
+		outstr[7] = prn1;
+		outstr[8] = prn2;
+		outstr[9] = prn3;
+		size = sizeof(outstr);
+	} else
+		size = sizeof(outstr) - 3;
+	writemem(outstr, size);
+}
+
+getblk(grp, bfn, cpx, cpy, szx, szy)
+	int             grp, bfn, cpx, cpy, szx, szy;
+{
+	static char     outstr[] = {0x1b, 0x2c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+	outstr[2] = grp;
+	outstr[3] = bfn;
+	*(int *) (&outstr[4]) = cpx;
+	*(int *) (&outstr[6]) = cpy;
+	*(int *) (&outstr[8]) = szx;
+	*(int *) (&outstr[10]) = szy;
+	writemem(outstr, sizeof(outstr));
+}
+
+putblk(grp, bfn, cpx, cpy)
+	int             grp, bfn, cpx, cpy;
+{
+	static char     outstr[] = {0x1b, 0x2d, 0, 0, 0, 0, 0, 0};
+
+	outstr[2] = grp;
+	outstr[3] = bfn;
+	*(int *) (&outstr[4]) = cpx;
+	*(int *) (&outstr[6]) = cpy;
+	writemem(outstr, sizeof(outstr));
+}
+
+dwend()
+{
+	static char     outstr[] = {0x1b, 0x24};
+
+	writemem(outstr, sizeof(outstr));
+}
+
+select()
+{
+	static char     outstr[] = {0x1b, 0x21};
+
+	writemem(outstr, sizeof(outstr));
+}
+
+bell()
+{
+	char            c = 7;
+	writemem(&c, 1);
+}
+
+palette(prn, ctn)
+{
+	static char     outstr[] = {0x1b, 0x31, 0, 0};
+
+	outstr[2] = prn;
+	outstr[3] = ctn;
+	writemem(outstr, sizeof(outstr));
+}
+
+curoff()
+{
+	static char     outstr[] = {0x05, 0x20};
+
+	writemem(outstr, sizeof(outstr));
+}
+
+writemem(str, size)
+	char           *str;
+	int             size;
+{
+	while (size-- > 0)
+		writechr(*str++);
+}
+
+writestr(file, str)
+	int             file;
+	char           *str;
+{
+	writeln(file, str, strlen(str));
+}
+
+char            outbuf[256];
+char           *outptr = outbuf;
+
+writechr(c)
+	char            c;
+{
+	if (outptr >= outbuf + sizeof(outbuf))
+		flushwin();
+	*outptr++ = c;
+}
+
+flushwin()
+{
+	write(actwin, outbuf, outptr - outbuf);
+	outptr = outbuf;
+}
+
+attach(str)
+	char           *str;
+{
+#asm
+ lda #3
+ ldx 4,s
+ os9 $80
+ bcs _atach1
+ tfr u,d
+ bra _atach2
+_atach1:
+ clra
+ std errno,y
+ ldd #-1
+_atach2:
+#endasm
+}
+
+detach(dte)
+int             dte;
+{
+#asm
+ ldu 4,s
+ os9 $81
+ bcs _detch1
+ ldd #0
+ bra _detch2
+_detch1:
+ clra
+ std errno,y
+ ldd #-1
+_detch2:
+#endasm
+}
+
+char           *
+mapgpb(path, grp, bfn, action)
+	int             path, grp, bfn, action;
+{
+#asm
+ lda 7,s
+ ldb 9,s
+ tfr d,x
+ lda 5,s
+ ldb #$84
+ pshs y
+ ldy 10+2,s
+ os9 $8e
+ puls y
+ bcc _mapgpb1
+ clra
+ std errno,y
+ ldx #0
+_mapgpb1:
+ tfr x,d
+#endasm
+}
+
+ready(path)
+	int             path;
+{
+#asm
+ lda 5,s
+ ldb #1
+ os9 $8d
+ bcc _ready1
+ ldd #0
+ bra _ready2
+_ready1:
+ ldd #1
+_ready2:
+#endasm
+}
+
+procid()
+{
+#asm
+ pshs y
+ os9 $0c
+ tfr a,b
+ puls y
+ clra
+#endasm
+}