Article 12819 of alt.sources:
Newsgroups: alt.sources
Path: nntpd.lkg.dec.com!pa.dec.com!news2.digital.com!news1.digital.com!uunet!in2.uu.net!EU.net!Germany.EU.net!Dortmund.Germany.EU.net!ping.de!cliwe.ping.de!fdc
From: fdc@cliwe.ping.de (Frank D. Cringle)
Subject: viewfax - an X-window fax viewer, V2.2, Part02/03
Message-ID: <vt20tjte9h.fsf_-_@cliwe.ping.de>
Followup-To: alt.sources.d
Lines: 2188
Sender: fdc@cliwe.ping.de
Organization: No foundation. 
X-Newsreader: Gnus v5.0.1
References: <vt4tyfteiu.fsf@cliwe.ping.de>
Date: Thu, 14 Sep 1995 22:58:18 GMT

Submitted-by: fdc@cliwe.ping.de
Archive-name: viewfax-2.2/part02

---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is part 02 of viewfax-2.2
# ============= viewfax-2.2/faxinput.c ==============
if test ! -d 'viewfax-2.2'; then
    echo 'x - creating directory viewfax-2.2'
    mkdir 'viewfax-2.2'
fi
if test -f 'viewfax-2.2/faxinput.c' -a X"$1" != X"-c"; then
	echo 'x - skipping viewfax-2.2/faxinput.c (File already exists)'
else
echo 'x - extracting viewfax-2.2/faxinput.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'viewfax-2.2/faxinput.c' &&
/* Fax file input processing
X   Copyright (C) 1990, 1995  Frank D. Cringle.
X
This file is part of viewfax - g3/g4 fax processing software.
X     
viewfax is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
X     
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.
X     
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
X
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include "faxexpand.h"
X
#define	FAXMAGIC	"\000PC Research, Inc\000\000\000\000\000\000"
X
/* Enter an argument in the linked list of pages */
struct pagenode *
notefile(char *name)
{
X    struct pagenode *new = (struct pagenode *) xmalloc(sizeof *new);
X
X    *new = defaultpage;
X    if (firstpage == NULL)
X	firstpage = new;
X    new->prev = lastpage;
X    new->next = NULL;
X    if (lastpage != NULL)
X	lastpage->next = new;
X    lastpage = new;
X    new->pathname = name;
X    if ((new->name = strrchr(new->pathname, '/')) != NULL)
X	new->name++;
X    else
X	new->name = new->pathname;
X
X    if (new->width == 0)
X	new->width = 1728;
X    if (new->vres < 0)
X	new->vres = !(new->name[0] == 'f' && new->name[1] == 'n');
X    new->extra = NULL;
X    return new;
}
X
static t32bits
get4(unsigned char *p, int endian)
{
X    return endian ? (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3] :
X	p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
}
X
static int
get2(unsigned char *p, int endian)
{
X    return endian ? (p[0]<<8)|p[1] : p[0]|(p[1]<<8);
}
X
/* generate pagenodes for the images in a tiff file */
int
notetiff(char *name)
{
X    FILE *tf;
X    unsigned char header[8];
X    static const char littleTIFF[4] = "\x49\x49\x2a\x00";
X    static const char bigTIFF[4] = "\x4d\x4d\x00\x2a";
X    int endian;
X    t32bits IFDoff;
X    struct pagenode *pn = NULL;
X
X    if ((tf = fopen(name, "r")) == NULL) {
X	perror(name);
X	return 0;
X    }
X
X    if (fread(header, 8, 1, tf) == 0) {
X    nottiff:
X	fclose(tf);
X	(void) notefile(name);
X	return 0;
X    }
X    if (memcmp(header, &littleTIFF, 4) == 0)
X	endian = 0;
X    else if (memcmp(header, &bigTIFF, 4) == 0)
X	endian = 1;
X    else
X	goto nottiff;
X    IFDoff = get4(header+4, endian);
X    if (IFDoff & 1)
X	goto nottiff;
X    do {			/* for each page */
X	unsigned char buf[12];
X	int ndirent;
X	pixnum iwidth = defaultpage.width ? defaultpage.width : 1728;
X	pixnum iheight = defaultpage.height ? defaultpage.height : 2339;
X	int inverse = defaultpage.inverse;
X	int lsbfirst = 0;
X	int t4opt = 0, comp = 0;
X	int orient = defaultpage.orient;
X	off_t here;
X	size_t bytecount = 0;
X	double yres = defaultpage.vres ? 196.0 : 98.0;
X	struct strip *strips = NULL, *laststrip;
X
X	if (fseek(tf, IFDoff, SEEK_SET) < 0) {
X	bad:
X	    while (strips) {
X		struct strip *s = strips->next;
X		free(strips);
X		strips = s;
X	    }
X	    /* have we recorded any valid pages yet? */
X	    if (pn == NULL)
X		goto nottiff;
X	    else {
X		fprintf(stderr, "%s:%s: invalid tiff file\n", ProgName, name);
X		fclose(tf);
X		return 1;
X	    }
X	}
X	if (fread(buf, 2, 1, tf) == 0)
X	    goto bad;
X	ndirent = get2(buf, endian);
X	while (ndirent--) {	/* for each directory entry */
X	    int tag, ftype;
X	    t32bits count, value = 0;
X	    if (fread(buf, 12, 1, tf) == 0)
X		goto bad;
X	    tag = get2(buf, endian);
X	    ftype = get2(buf+2, endian);
X	    count = get4(buf+4, endian);
X	    switch(ftype) {	/* value is offset to list if count*size > 4 */
X	    case 3:		/* short */
X		value = get2(buf+8, endian);
X		break;
X	    case 4:		/* long */
X		value = get4(buf+8, endian);
X		break;
X	    case 5:		/* offset to rational */
X		value = get4(buf+8, endian);
X		break;
X	    }
X	    switch(tag) {
X	    case 256:		/* ImageWidth */
X		iwidth = value;
X		break;
X	    case 257:		/* ImageLength */
X		iheight = value;
X		break;
X	    case 259:		/* Compression */
X		comp = value;
X		break;
X	    case 262:		/* PhotometricInterpretation */
X		inverse ^= (value == 1);
X		break;
X	    case 266:		/* FillOrder */
X		lsbfirst = (value == 2);
X		break;
X	    case 273:		/* StripOffsets */
X		if (count == 1 || (count == 2 && ftype == 3)) {
X		    strips = (struct strip *) xmalloc(sizeof *strips);
X		    strips->offset = value;
X		    strips->next = NULL;
X		    if (count == 2) {
X			strips->next =
X			    (struct strip *) xmalloc(sizeof *strips);
X			strips->next->offset = get2(buf+10, endian);
X			strips->next->next = NULL;
X		    }
X		    break;
X		}
X		here = ftell(tf);
X		if (fseek(tf, value, SEEK_SET) < 0)
X		    goto bad;
X		while (count--) {
X		    if (strips == NULL)
X			strips = laststrip =
X			    (struct strip *) xmalloc(sizeof *strips);
X		    else {
X			laststrip->next =
X			    (struct strip *) xmalloc(sizeof *strips);
X			laststrip = laststrip->next;
X		    }
X		    if (fread(buf, (ftype == 3) ? 2 : 4, 1, tf) == 0)
X			goto bad;
X		    laststrip->offset = (ftype == 3) ?
X			get2(buf, endian) : get4(buf, endian);
X		    laststrip->next = NULL;
X		}
X		if (fseek(tf, here, SEEK_SET) < 0)
X		    goto bad;
X		break;
X	    case 274:		/* Orientation */
X		switch(value) {
X		default:	/* row0 at top,    col0 at left   */
X		    orient = 0;
X		    break;
X		case 2:		/* row0 at top,    col0 at right  */
X		    orient = TURN_M;
X		    break;
X		case 3:		/* row0 at bottom, col0 at right  */
X		    orient = TURN_U;
X		    break;
X		case 4:		/* row0 at bottom, col0 at left   */
X		    orient = TURN_U|TURN_M;
X		    break;
X		case 5:		/* row0 at left,   col0 at top    */
X		    orient = TURN_M|TURN_L;
X		    break;
X		case 6:		/* row0 at right,  col0 at top    */
X		    orient = TURN_U|TURN_L;
X		    break;
X		case 7:		/* row0 at right,  col0 at bottom */
X		    orient = TURN_U|TURN_M|TURN_L;
X		    break;
X		case 8:		/* row0 at left,   col0 at bottom */
X		    orient = TURN_L;
X		    break;
X		}
X		break;
X	    case 279:		/* StripByteCounts */
X		if (count == 1 || (count == 2 && ftype == 3)) {
X		    strips->size = bytecount = value;
X		    if (count == 2) {
X			strips->next->size = get2(buf+10, endian);
X			bytecount += strips->next->size;
X		    }
X		    break;
X		}
X		here = ftell(tf);
X		if (fseek(tf, value, SEEK_SET) < 0)
X		    goto bad;
X		laststrip = strips;
X		while (count--) {
X		    if (laststrip == NULL) {
X			fprintf(stderr, "%s:%s: too many strip bytecounts\n",
X				ProgName, name);
X			goto bad;
X		    }
X		    if (fread(buf, (ftype == 3) ? 2 : 4, 1, tf) == 0)
X			goto bad;
X		    laststrip->size = (ftype == 3) ?
X			get2(buf, endian) : get4(buf, endian);
X		    bytecount += laststrip->size;
X		    laststrip = laststrip->next;
X		}
X		if (laststrip != NULL) {
X		    fprintf(stderr, "%s:%s: too few strip bytecounts\n",
X			    ProgName, name);
X		    goto bad;
X		}
X		if (fseek(tf, here, SEEK_SET) < 0)
X		    goto bad;
X		break;
X	    case 283:		/* YResolution */
X		here = ftell(tf);
X		if (fseek(tf, value, SEEK_SET) < 0 ||
X		    fread(buf, 8, 1, tf) == 0)
X		    goto bad;
X		yres = get4(buf, endian) / get4(buf+4, endian);
X		if (fseek(tf, here, SEEK_SET) < 0)
X		    goto bad;		
X		break;
X	    case 292:		/* T4Options */
X		t4opt = value;
X		break;
X	    case 293:		/* T6Options */
X		/* later */
X		break;
X	    case 296:		/* ResolutionUnit */
X		if (value == 3)
X		    yres *= 2.54;
X		break;
X	    }
X	}
X	if (comp != 3 && comp != 4) {
X	    fprintf(stderr, "%s:%s: this version only handles fax files\n",
X		ProgName, name);
X	    goto bad;
X	}
X	pn = notefile(name);
X	pn->strips = strips;
X	pn->length = bytecount;
X	pn->width = iwidth;
X	pn->height = iheight;
X	pn->inverse = inverse;
X	pn->lsbfirst = lsbfirst;
X	pn->orient = orient;
X	pn->vres = (yres > 150); /* arbitrary threshold for fine resolution */
X	if (comp == 3)
X	    pn->expander = (t4opt & 1) ? g32expand : g31expand;
X	else
X	    pn->expander = g4expand;
X	if (fread(buf, 4, 1, tf) == 0)
X	    goto bad;
X	IFDoff = get4(buf, endian);
X    } while (IFDoff);
X    fclose(tf);
X    return 1;
}
X
/* report error and remove bad file from the list */
static void
badfile(struct pagenode *pn)
{
X    struct pagenode *p;
X
X    if (errno)
X	perror(pn->pathname);
X    if (pn == firstpage) {
X	if (pn->next == NULL)
X	    exit(1);
X	firstpage = thispage = firstpage->next;
X	firstpage->prev = NULL;
X    }
X    else
X	for (p = firstpage; p; p = p->next)
X	    if (p->next == pn) {
X		thispage = p;
X		p->next = pn->next;
X		if (pn->next)
X		    pn->next->prev = p;
X		break;
X	    }
X    if (pn) free(pn);
}
X
/* rearrange input bits into t16bits lsb-first chunks */
static void
normalize(struct pagenode *pn, int revbits, int swapbytes, size_t length)
{
X    t32bits *p = (t32bits *) pn->data;
X
X    switch ((revbits<<1)|swapbytes) {
X    case 0:
X	break;
X    case 1:
X	for ( ; length; length -= 4) {
X	    t32bits t = *p;
X	    *p++ = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8);
X	}
X	break;
X    case 2:
X	for ( ; length; length -= 4) {
X	    t32bits t = *p;
X	    t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4);
X	    t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2);
X	    *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1);
X	}
X	break;
X    case 3:
X	for ( ; length; length -= 4) {
X	    t32bits t = *p;
X	    t = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8);
X	    t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4);
X	    t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2);
X	    *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1);
X	}
X    }
}
X
X
/* get compressed data into memory */
unsigned char *
getpage(struct pagenode *pn)
{
X    int fd;
X    size_t roundup;
X    struct stat sbuf;
X    unsigned char *Data;
X    union { t16bits s; unsigned char b[2]; } so;
#define ShortOrder	so.b[1]
X
X    so.s = 1;
X    if ((fd = open(pn->pathname, O_RDONLY, 0)) < 0) {
X	badfile(pn);
X	return NULL;
X    }
X
X    if (pn->strips == NULL) {
X	if (fstat(fd, &sbuf) != 0) {
X	    close(fd);
X	    badfile(pn);
X	    return NULL;
X	}
X	pn->length = sbuf.st_size;
X    }
X
X    /* round size to full boundary plus t32bits */
X    roundup = (pn->length + 7) & ~3;
X
X    Data = (unsigned char *) xmalloc(roundup);
X    /* clear the last 2 t32bits, to force the expander to terminate
X       even if the file ends in the middle of a fax line  */
X    *((t32bits *) Data + roundup/4 - 8) = 0;
X    *((t32bits *) Data + roundup/4 - 4) = 0;
X    if (pn->strips == NULL) {
X	/* we expect to get it in one gulp... */
X	if (read(fd, (char *)Data, (unsigned)pn->length) != (int)pn->length) {
X	    badfile(pn);
X	    free(Data);
X	    close(fd);
X	    return NULL;
X	}
X    }
X    else {
X	struct strip *s = pn->strips;
X	unsigned char *p = Data;
X	while (s) {
X	    if ((lseek(fd, s->offset, SEEK_SET) < 0) ||
X		(read(fd, (char *)p, s->size) != s->size)) {
X		badfile(pn);
X		free(Data);
X		close(fd);
X		return NULL;
X	    }
X	    p += s->size;
X	    s = s->next;
X	}
X    }
X    close(fd);
X
X    pn->data = (t16bits *) Data;
X    if (pn->strips == NULL && memcmp(Data, FAXMAGIC, sizeof(FAXMAGIC)) == 0) {
X	/* handle ghostscript / PC Research fax file */
X	if (Data[24] != 1 || Data[25] != 0)
X	    printf("%s: only first page of multipage file %s will be shown\n",
X		   ProgName, pn->pathname);
X	pn->length -= 64;
X	pn->vres = Data[29];
X	pn->data += 32;
X	roundup -= 64;
X    }
X
X    normalize(pn, !pn->lsbfirst, ShortOrder, roundup);
X    if (pn->height == 0)
X	pn->height = G3count(pn, pn->expander == g32expand);
X    if (pn->height == 0) {
X	fprintf(stderr, "%s: no fax found in file %s\n", ProgName,
X		pn->pathname);
X	errno = 0;
X	badfile(pn);
X	free(Data);
X	return NULL;
X    }
X    if (verbose)
X	printf("%s:\n\twidth = %d\n\theight = %d\n\tresolution = %s\n",
X	       pn->name, pn->width, pn->height, pn->vres ?
X	       "fine" : "normal");
X    return Data;
}
SHAR_EOF
chmod 0664 viewfax-2.2/faxinput.c ||
echo 'restore of viewfax-2.2/faxinput.c failed'
Wc_c="`wc -c < 'viewfax-2.2/faxinput.c'`"
test 11869 -eq "$Wc_c" ||
	echo 'viewfax-2.2/faxinput.c: original size 11869, current size' "$Wc_c"
fi
# ============= viewfax-2.2/faxinit.c ==============
if test -f 'viewfax-2.2/faxinit.c' -a X"$1" != X"-c"; then
	echo 'x - skipping viewfax-2.2/faxinit.c (File already exists)'
else
echo 'x - extracting viewfax-2.2/faxinit.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'viewfax-2.2/faxinit.c' &&
/* Initialise fax decoder tables
X   Copyright (C) 1990, 1995  Frank D. Cringle.
X
This file is part of viewfax - g3/g4 fax processing software.
X     
viewfax is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
X     
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.
X     
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
X
#include <sys/types.h>
#include "faxexpand.h"
X
struct tabent MainTable[128];
struct tabent WhiteTable[4096];
struct tabent BlackTable[8192];
X
struct proto {
X    t16bits code;		/* right justified, lsb-first, zero filled */
X    t16bits val;		/* (pixel count)<<4 + code width  */
};
X
static struct proto Pass[] = {
{ 0x0008, 4 },
{ 0, 0 }
};
X
static struct proto Horiz[]  = {
{ 0x0004, 3 },
{ 0, 0 }
};
X
static struct proto V0[]  = {
{ 0x0001, 1 },
{ 0, 0 }
};
X
static struct proto VR[]  = {
{ 0x0006, (1<<4)+3 },
{ 0x0030, (2<<4)+6 },
{ 0x0060, (3<<4)+7 },
{ 0, 0 }
};
X
static struct proto VL[]  = {
{ 0x0002, (1<<4)+3 },
{ 0x0010, (2<<4)+6 },
{ 0x0020, (3<<4)+7 },
{ 0, 0 }
};
X
static struct proto Ext[]  = {
{ 0x0040, 7 },
{ 0, 0 }
};
X
static struct proto EOLV[]  = {
{ 0x0000, 7 },
{ 0, 0 }
};
X
static struct proto MakeUpW[] = {
{ 0x001b, 1029 },
{ 0x0009, 2053 },
{ 0x003a, 3078 },
{ 0x0076, 4103 },
{ 0x006c, 5128 },
{ 0x00ec, 6152 },
{ 0x0026, 7176 },
{ 0x00a6, 8200 },
{ 0x0016, 9224 },
{ 0x00e6, 10248 },
{ 0x0066, 11273 },
{ 0x0166, 12297 },
{ 0x0096, 13321 },
{ 0x0196, 14345 },
{ 0x0056, 15369 },
{ 0x0156, 16393 },
{ 0x00d6, 17417 },
{ 0x01d6, 18441 },
{ 0x0036, 19465 },
{ 0x0136, 20489 },
{ 0x00b6, 21513 },
{ 0x01b6, 22537 },
{ 0x0032, 23561 },
{ 0x0132, 24585 },
{ 0x00b2, 25609 },
{ 0x0006, 26630 },
{ 0x01b2, 27657 },
{ 0, 0 }
};
X
static struct proto MakeUpB[] = {
{ 0x03c0, 1034 },
{ 0x0130, 2060 },
{ 0x0930, 3084 },
{ 0x0da0, 4108 },
{ 0x0cc0, 5132 },
{ 0x02c0, 6156 },
{ 0x0ac0, 7180 },
{ 0x06c0, 8205 },
{ 0x16c0, 9229 },
{ 0x0a40, 10253 },
{ 0x1a40, 11277 },
{ 0x0640, 12301 },
{ 0x1640, 13325 },
{ 0x09c0, 14349 },
{ 0x19c0, 15373 },
{ 0x05c0, 16397 },
{ 0x15c0, 17421 },
{ 0x0dc0, 18445 },
{ 0x1dc0, 19469 },
{ 0x0940, 20493 },
{ 0x1940, 21517 },
{ 0x0540, 22541 },
{ 0x1540, 23565 },
{ 0x0b40, 24589 },
{ 0x1b40, 25613 },
{ 0x04c0, 26637 },
{ 0x14c0, 27661 },
{ 0, 0 }
};
X
static struct proto MakeUp[] = {
{ 0x0080, 28683 },
{ 0x0180, 29707 },
{ 0x0580, 30731 },
{ 0x0480, 31756 },
{ 0x0c80, 32780 },
{ 0x0280, 33804 },
{ 0x0a80, 34828 },
{ 0x0680, 35852 },
{ 0x0e80, 36876 },
{ 0x0380, 37900 },
{ 0x0b80, 38924 },
{ 0x0780, 39948 },
{ 0x0f80, 40972 },
{ 0, 0 }
};
X
static struct proto TermW[] = {
{ 0x00ac, 8 },
{ 0x0038, 22 },
{ 0x000e, 36 },
{ 0x0001, 52 },
{ 0x000d, 68 },
{ 0x0003, 84 },
{ 0x0007, 100 },
{ 0x000f, 116 },
{ 0x0019, 133 },
{ 0x0005, 149 },
{ 0x001c, 165 },
{ 0x0002, 181 },
{ 0x0004, 198 },
{ 0x0030, 214 },
{ 0x000b, 230 },
{ 0x002b, 246 },
{ 0x0015, 262 },
{ 0x0035, 278 },
{ 0x0072, 295 },
{ 0x0018, 311 },
{ 0x0008, 327 },
{ 0x0074, 343 },
{ 0x0060, 359 },
{ 0x0010, 375 },
{ 0x000a, 391 },
{ 0x006a, 407 },
{ 0x0064, 423 },
{ 0x0012, 439 },
{ 0x000c, 455 },
{ 0x0040, 472 },
{ 0x00c0, 488 },
{ 0x0058, 504 },
{ 0x00d8, 520 },
{ 0x0048, 536 },
{ 0x00c8, 552 },
{ 0x0028, 568 },
{ 0x00a8, 584 },
{ 0x0068, 600 },
{ 0x00e8, 616 },
{ 0x0014, 632 },
{ 0x0094, 648 },
{ 0x0054, 664 },
{ 0x00d4, 680 },
{ 0x0034, 696 },
{ 0x00b4, 712 },
{ 0x0020, 728 },
{ 0x00a0, 744 },
{ 0x0050, 760 },
{ 0x00d0, 776 },
{ 0x004a, 792 },
{ 0x00ca, 808 },
{ 0x002a, 824 },
{ 0x00aa, 840 },
{ 0x0024, 856 },
{ 0x00a4, 872 },
{ 0x001a, 888 },
{ 0x009a, 904 },
{ 0x005a, 920 },
{ 0x00da, 936 },
{ 0x0052, 952 },
{ 0x00d2, 968 },
{ 0x004c, 984 },
{ 0x00cc, 1000 },
{ 0x002c, 1016 },
{ 0, 0 }
};
X
static struct proto TermB[] = {
{ 0x03b0, 10 },
{ 0x0002, 19 },
{ 0x0003, 34 },
{ 0x0001, 50 },
{ 0x0006, 67 },
{ 0x000c, 84 },
{ 0x0004, 100 },
{ 0x0018, 117 },
{ 0x0028, 134 },
{ 0x0008, 150 },
{ 0x0010, 167 },
{ 0x0050, 183 },
{ 0x0070, 199 },
{ 0x0020, 216 },
{ 0x00e0, 232 },
{ 0x0030, 249 },
{ 0x03a0, 266 },
{ 0x0060, 282 },
{ 0x0040, 298 },
{ 0x0730, 315 },
{ 0x00b0, 331 },
{ 0x01b0, 347 },
{ 0x0760, 363 },
{ 0x00a0, 379 },
{ 0x0740, 395 },
{ 0x00c0, 411 },
{ 0x0530, 428 },
{ 0x0d30, 444 },
{ 0x0330, 460 },
{ 0x0b30, 476 },
{ 0x0160, 492 },
{ 0x0960, 508 },
{ 0x0560, 524 },
{ 0x0d60, 540 },
{ 0x04b0, 556 },
{ 0x0cb0, 572 },
{ 0x02b0, 588 },
{ 0x0ab0, 604 },
{ 0x06b0, 620 },
{ 0x0eb0, 636 },
{ 0x0360, 652 },
{ 0x0b60, 668 },
{ 0x05b0, 684 },
{ 0x0db0, 700 },
{ 0x02a0, 716 },
{ 0x0aa0, 732 },
{ 0x06a0, 748 },
{ 0x0ea0, 764 },
{ 0x0260, 780 },
{ 0x0a60, 796 },
{ 0x04a0, 812 },
{ 0x0ca0, 828 },
{ 0x0240, 844 },
{ 0x0ec0, 860 },
{ 0x01c0, 876 },
{ 0x0e40, 892 },
{ 0x0140, 908 },
{ 0x01a0, 924 },
{ 0x09a0, 940 },
{ 0x0d40, 956 },
{ 0x0340, 972 },
{ 0x05a0, 988 },
{ 0x0660, 1004 },
{ 0x0e60, 1020 },
{ 0, 0 }
};
X
static struct proto EOLH[] = {
{ 0x0000, 11 },
{ 0, 0 }
};
X
static void
FillTable(struct tabent *T, int Size, struct proto *P, int State)
{
X    int limit = 1 << Size;
X
X    while (P->val) {
X	int width = P->val & 15;
X	int param = P->val >> 4;
X	int incr = 1 << width;
X	int code;
X	for (code = P->code; code < limit; code += incr) {
X	    struct tabent *E = T+code;
X	    E->State = State;
X	    E->Width = width;
X	    E->Param = param;
X	}
X	P++;
X    }
}
X
/* initialise the huffman code tables */
void
faxinit(void)
{
X    FillTable(MainTable, 7, Pass, S_Pass);
X    FillTable(MainTable, 7, Horiz, S_Horiz);
X    FillTable(MainTable, 7, V0, S_V0);
X    FillTable(MainTable, 7, VR, S_VR);
X    FillTable(MainTable, 7, VL, S_VL);
X    FillTable(MainTable, 7, Ext, S_Ext);
X    FillTable(MainTable, 7, EOLV, S_EOL);
X    FillTable(WhiteTable, 12, MakeUpW, S_MakeUpW);
X    FillTable(WhiteTable, 12, MakeUp, S_MakeUp);
X    FillTable(WhiteTable, 12, TermW, S_TermW);
X    FillTable(WhiteTable, 12, EOLH, S_EOL);
X    FillTable(BlackTable, 13, MakeUpB, S_MakeUpB);
X    FillTable(BlackTable, 13, MakeUp, S_MakeUp);
X    FillTable(BlackTable, 13, TermB, S_TermB);
X    FillTable(BlackTable, 13, EOLH, S_EOL);
}
SHAR_EOF
chmod 0664 viewfax-2.2/faxinit.c ||
echo 'restore of viewfax-2.2/faxinit.c failed'
Wc_c="`wc -c < 'viewfax-2.2/faxinit.c'`"
test 6464 -eq "$Wc_c" ||
	echo 'viewfax-2.2/faxinit.c: original size 6464, current size' "$Wc_c"
fi
# ============= viewfax-2.2/viewfax.c ==============
if test -f 'viewfax-2.2/viewfax.c' -a X"$1" != X"-c"; then
	echo 'x - skipping viewfax-2.2/viewfax.c (File already exists)'
else
echo 'x - extracting viewfax-2.2/viewfax.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'viewfax-2.2/viewfax.c' &&
/* Program to view fax files on an X-window screen
X   Copyright (C) 1990, 1995  Frank D. Cringle.
X
This file is part of viewfax - g3/g4 fax processing software.
X     
viewfax is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
X     
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.
X     
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
X
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
/* NewImage() needs to fiddle with the Display structure */
#define XLIB_ILLEGAL_ACCESS
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <X11/keysymdef.h>
#include <X11/cursorfont.h>
#include "faxexpand.h"
X
#define VERSION "2.2"
X
/* If moving the image around with the middle mouse button is jerky or
X   slow, try defining USE_MOTIONHINT.  It may help (it may also make
X   things worse - it depends on the server implementation) */
#undef USE_MOTIONHINT
X
struct pagenode *firstpage, *lastpage, *thispage, *helppage;
struct pagenode defaultpage;
X
/* access the 'extra' field in a pagenode */
#define Pimage(p)	((XImage *)(p)->extra)
X
/* getopt declarations */
extern int getopt();
extern char *optarg;
extern int optind, opterr, optopt;
X
/* forward declarations */
static XImage *FlipImage(XImage *xi);
static XImage *MirrorImage(XImage *xi);
static XImage *NewImage(int w, int h, char *data, int bit_order);
static XImage *RotImage(XImage *Image);
static XImage *ZoomImage(XImage *Big);
static void FreeImage(XImage *Image);
static int GetImage(struct pagenode *pn);
static void SetupDisplay(int argc, char **argv);
static void ShowLoop(void);
static int release(int quit);
static char *suffix(char *opt, char *str);
X
/* X variables */
static char *DispName = NULL;
static char *Geometry = NULL;
static Display *Disp;
static Window Root;
static Window Win;
static int Default_Screen;
static GC PaintGC;
static Cursor WorkCursor;
static Cursor ReadyCursor;
static Cursor MoveCursor;
static Cursor LRCursor;
static Cursor UDCursor;
X
char *ProgName;
int verbose = 0;
X
static int abell = 0;			/* audio bell */
static int vbell = 1;			/* visual bell */
static int zfactor = 0;			/* zoom factor */
X
static size_t Memused = 0;		/* image memory usage */
static size_t Memlimit = 4*1024*1024;	/* try not to exceed */
X
#undef min
#undef max
#define min(a,b)	((a)<(b)?(a):(b))
#define max(a,b)	((a)>(b)?(a):(b))
X
/* OK, OK - this is a dreadful hack.  But it adequately distinguishes
X   modern big- and little- endian hosts.  We only need this to set the
X   byte order in XImage structures */
static union { t32bits i; unsigned char b[4]; } bo;
#define ByteOrder	bo.b[3]
X
static char Banner[] =
"\nviewfax version " VERSION ", Copyright (C) 1990, 1995 Frank D. Cringle.\n"
"viewfax comes with ABSOLUTELY NO WARRANTY; for details see the\n"
"file \"COPYING\" in the distribution directory.\n\n";
X
static char Usage[] =
"usage: %s <flags> file ...\n"
"\t-f\tfine resolution (default unless filename begins with 'fn')\n"
"\t-n\tnormal resolution\n"
"\t-h\theight (number of fax lines)\n"
"\t-w\twidth (dots per fax line)\n"
"\t-l\tturn image 90 degrees (landscape mode)\n"
"\t-u\tturn image upside down\n"
"\t-i\tinvert (black/white)\n"
"\t-d\t(or -display) use an alternate X display\n"
"\t-g\t(or -geometry) size and position of window\n"
"\t-b\tuse audio (-ba) or visual (-bv) warning bell\n"
"\t-m\tmemory usage limit\n"
"\t-r\tfax data is packed ls-bit first in input bytes\n"
"\t-v\tverbose messages\n"
"\t-z\tinitial zoom factor\n"
"\t-2\traw files are g3-2d\n"
"\t-4\traw files are g4\n";
X
int
main(int argc, char **argv)
{
X    int c;
X    int err = 0;
X
X    bo.i = 1;
X    defaultpage.vres = -1;
X    defaultpage.expander = g31expand;
X    opterr = 0;			/* suppress getopt error message */
X
X    if ((ProgName = strrchr(argv[0], '/')) == NULL)
X	ProgName = argv[0];
X    else
X	ProgName++;
X    while ((c = getopt(argc, argv, "b:d:fg:h:ilm:nruvw:z:24")) != -1)
X	switch(c) {
X	case 'b':
X	    abell = vbell = 0;
X	    while (*optarg) {
X		abell |= (*optarg == 'a');
X		vbell |= (*optarg == 'v');
X		optarg++;
X	    }
X	    break;
X	case 'd':		/* display name */
X	    if (*(DispName = suffix(optarg, "isplay")) == 0)
X		DispName = argv[optind++];
X	    break;
X	case 'f':		/* fine resolution */
X	    defaultpage.vres = 1;
X	    break;
X	case 'g':		/* geometry */
X	    if (*(Geometry = suffix(optarg, "eometry")) == 0)
X		Geometry = argv[optind++];
X	    break;
X	case 'h':		/* user thinks this is the height */
X	    defaultpage.height = atoi(optarg);
X	    break;
X	case 'i':		/* invert black/white */
X	    defaultpage.inverse = 1;
X	    break;
X	case 'l':		/* landscape */
X	    defaultpage.orient |= TURN_L;
X	    break;
X	case 'm':		/* memory usage limit */
X	    Memlimit = atoi(optarg);
X	    switch(optarg[strlen(optarg)-1]) {
X	    case 'M':
X	    case 'm':
X		Memlimit *= 1024;
X	    case 'K':
X	    case 'k':
X		Memlimit *= 1024;
X	    }
X	    break;
X	case 'n':		/* normal resolution */
X	    defaultpage.vres = 0;
X	    break;
X	case 'r':		/* reverse input bits */
X	    defaultpage.lsbfirst = 1;
X	    break;
X	case 'u':		/* upside down */
X	    defaultpage.orient |= TURN_U;
X	    break;
X	case 'v':		/* verbose messages */
X	    verbose = 1;
X	    break;
X	case 'w':		/* user thinks this is the width */
X	    defaultpage.width = atoi(optarg);
X	    break;
X	case 'z':		/* zoom factor */
X	    c = atoi(optarg);
X	    if (c <= 0)
X		c = 1;
X	    for (zfactor = 1; c > 1; c >>= 1)
X		zfactor <<= 1;	/* constrain to a power of 2 */
X	    break;
X	case '2':
X	    defaultpage.expander = g32expand;
X	    break;
X	case '4':
X	    defaultpage.expander = g4expand;
X	    break;
X	default:
X	    err++;
X	    break;
X	}
X
X    if (defaultpage.expander == g4expand && defaultpage.height == 0) {
X	fputs("-h value is required to interpret raw g4 faxes\n", stderr);
X	err++;
X    }
X
X    if (verbose)
X	fputs(Banner, stdout);
X
X    firstpage = lastpage = thispage = helppage = NULL;
X    for (; optind < argc; optind++)
X	(void) notetiff(argv[optind]);
X
X    if (err || firstpage == NULL) {
X	if (!verbose)
X	    fprintf(stderr, Banner);
X	fprintf(stderr, Usage, ProgName);
X	exit(1);
X    }
X
X    if ((Disp = XOpenDisplay(DispName)) == NULL) {
X	fprintf(stderr, "%s: can't open display %s\n", ProgName,
X		DispName ? DispName : XDisplayName((char *) NULL));
X	exit(1);
X    }
X    Default_Screen = XDefaultScreen(Disp);
X    faxinit();
X    thispage = firstpage;
X    while (!GetImage(firstpage))
X	/* try again */;
X    SetupDisplay(argc, argv);
X    ShowLoop();
X    return 0;
}
X
/* return mismatching suffix of option name*/
static char *
suffix(char *opt, char *prefix)
{
X    while (*opt && *opt == *prefix) {
X	opt++; prefix++;
X    }
X    return opt;
}
X
static void
drawline(pixnum *run, int LineNum, struct pagenode *pn)
{
X    t32bits *p, *p1;		/* p - current line, p1 - low-res duplicate */
X    pixnum *r;			/* pointer to run-lengths */
X    t32bits pix;		/* current pixel value */
X    t32bits acc;		/* pixel accumulator */
X    int nacc;			/* number of valid bits in acc */
X    int tot;			/* total pixels in line */
X    int n;
X
X    p = (t32bits *) (Pimage(pn)->data + LineNum*(2-pn->vres)*Pimage(pn)->bytes_per_line);
X    p1 = pn->vres ? NULL : p + Pimage(pn)->bytes_per_line/sizeof(*p);
X    r = run;
X    acc = 0;
X    nacc = 0;
X    pix = pn->inverse ? ~0 : 0;
X    tot = 0;
X    while (tot < pn->width) {
X	n = *r++;
X	tot += n;
X	if (pix)
X	    acc |= (~(t32bits)0 >> nacc);
X	else if (nacc)
X	    acc &= (~(t32bits)0 << (32 - nacc));
X	else
X	    acc = 0;
X	if (nacc + n < 32) {
X	    nacc += n;
X	    pix = ~pix;
X	    continue;
X	}
X	*p++ = acc;
X	if (p1)
X	    *p1++ = acc;
X	n -= 32 - nacc;
X	while (n >= 32) {
X	    n -= 32;
X	    *p++ = pix;
X	    if (p1)
X		*p1++ = pix;
X	}
X	acc = pix;
X	nacc = n;
X	pix = ~pix;
X    }
X    if (nacc) {
X	*p++ = acc;
X	if (p1)
X	    *p1++ = acc;
X    }
}
X
static int
GetImage(struct pagenode *pn)
{
X    unsigned char *Data = getpage(pn);
X
X    if (Data == NULL)
X	return 0;
X    pn->extra = NewImage(pn->width, pn->vres ?
X			 pn->height : 2*pn->height, NULL, 1);
X    (*pn->expander)(pn, drawline);
X    if (pn->orient & TURN_U)
X	pn->extra = FlipImage(Pimage(pn));
X    if (pn->orient & TURN_M)
X	pn->extra = MirrorImage(Pimage(pn));
X    if (pn->orient & TURN_L)
X	pn->extra = RotImage(Pimage(pn));
X    if (verbose) printf("\tmemused = %d\n", Memused);
X    free(Data);
X    return 1;
}
X
#ifndef _HAVE_USLEEP
static int
usleep(unsigned usecs)
{
X    struct timeval t;
X
X    t.tv_sec = usecs/10000000;
X    t.tv_usec = usecs%1000000;
X    (void) select(1, NULL, NULL, NULL, &t);
X    return 0;
}
#endif
X
#ifndef REAL_ROOT
/* Function Name: GetVRoot
X * Description: Gets the root window, even if it's a virtual root
X * Arguments: the display and the screen
X * Returns: the root window for the client
X *
X * by David Elliott, taken from the x-faq
X */
static Window
GetVRoot(Display *dpy, int scr)
{
X    Window rootReturn, parentReturn, *children;
X    unsigned int numChildren;
X    Window root = RootWindow(dpy, scr);
X    Atom __SWM_VROOT = None;
X    int i;
X 
X    __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False);
X    XQueryTree(dpy, root, &rootReturn, &parentReturn, &children,
X	       &numChildren);
X    for (i = 0; i < numChildren; i++) {
X        Atom actual_type;
X        int actual_format;
X        unsigned long nitems, bytesafter;
X        Window *newRoot = NULL;
X 
X        if (XGetWindowProperty(dpy, children[i], __SWM_VROOT, 0, 1,
X			       False, XA_WINDOW, &actual_type,
X			       &actual_format, &nitems, &bytesafter,
X			       (unsigned char **) &newRoot)
X					== Success && newRoot) {
X	    if (children) XFree(children);
X	    return *newRoot;
X	}
X    }
X    return root;
}
#endif
X
static Atom wm_delete_window;
X
/* Area the user would like us to use, derived from -geometry */
static struct {
X    int v, x, y;
X    unsigned int w, h;
} Area = {0, 0, 0};
X
/* nominal border width */
#define BW 4
X
/* Figure out the zoom factor needed to fit the fax on the available display */
static void
SetupDisplay(int argc, char **argv)
{
X    int Width, Height, i;
X    XSetWindowAttributes Attr;
X    XSizeHints size_hints;
X    Atom wm_protocols;
X    int faxh = Pimage(thispage)->height;
X    int faxw = Pimage(thispage)->width;
X
#ifdef REAL_ROOT
X    Root = RootWindow(Disp, Default_Screen);
X    Width = Area.w = DisplayWidth(Disp, Default_Screen);
X    Height = Area.h = DisplayHeight(Disp, Default_Screen);
#elif TVTWM_BIGWINDOW
X    XWindowAttributes RootWA;
X    Root = GetVRoot(Disp, Default_Screen);
X    XGetWindowAttributes(Disp, Root, &RootWA);
X    Width = Area.w = RootWA.width;
X    Height = Area.h = RootWA.height;
#else
X    Root = GetVRoot(Disp, Default_Screen);
X    Width = Area.w = DisplayWidth(Disp, Default_Screen);
X    Height = Area.h = DisplayHeight(Disp, Default_Screen);
#endif
X    if (Geometry)
X	Area.v = XParseGeometry(Geometry, &Area.x, &Area.y,
X				&Area.w, &Area.h);
X    Area.w = max(64, Area.w);
X    Area.h = max(64, Area.h);
X
X    if (zfactor == 0)
X	for (zfactor = 1;
X	     faxw / zfactor > Area.w ||
X	     faxh / zfactor > Area.h;
X	     zfactor *= 2)
X	    ;
X    Attr.background_pixel = WhitePixel(Disp, Default_Screen);
X    Attr.border_pixel = BlackPixel(Disp, Default_Screen);
X
X    for (size_hints.width = faxw, i = 1; i < zfactor; i *= 2)
X	size_hints.width = (size_hints.width + 1) /2;
X    for (size_hints.height = faxh, i = 1; i < zfactor; i *= 2)
X	size_hints.height = (size_hints.height + 1) /2;
X
X    switch (Area.v & (XValue|XNegative)) {
X    case XValue:
X	size_hints.x = Area.x + BW;
X	break;
X    case XValue|XNegative:
X	Area.x = Width + Area.x - 2*BW - Area.w;
X	size_hints.x = Area.x + Area.w - size_hints.width;
X	break;
X    default:
X	size_hints.x = Area.x + (Area.w - size_hints.width)/2;
X    }
X    switch (Area.v & (YValue|YNegative)) {
X    case YValue:
X	size_hints.y = Area.y + BW;
X	break;
X    case YValue|YNegative:
X	Area.y = Height + Area.y - 2*BW - Area.h;
X	size_hints.y = Area.y + Area.h - size_hints.height;
X	break;
X    default:
X	size_hints.y = Area.y + (Area.h - size_hints.height)/2;
X    }
X
X    size_hints.max_width = size_hints.width;
X    size_hints.max_height = size_hints.height;
X    size_hints.flags = PSize|PMaxSize;
X    if (Area.v & (XValue|YValue)) size_hints.flags |= USPosition;
X    if (Area.v & (HeightValue|WidthValue)) size_hints.flags |= USSize;
X	
X    Win = XCreateWindow(Disp, Root, size_hints.x, size_hints.y,
X			size_hints.width, size_hints.height,
X			BW, 0, InputOutput, CopyFromParent,
X			CWBackPixel|CWBorderPixel, &Attr);
#ifdef PWinGravity
{
X    XWMHints wm_hints;
X    XClassHint class_hints;
X    XTextProperty windowName, iconName;
X
X    if (!XStringListToTextProperty(&thispage->name, 1, &windowName) ||
X	!XStringListToTextProperty(&ProgName, 1, &iconName)) {
X	fprintf(stderr, "%s: can't make window/icon name\n", ProgName);
X	exit(1);
X    }
X    wm_hints.initial_state = NormalState;
X    wm_hints.input = True;
X    wm_hints.flags = StateHint|InputHint;
X    class_hints.res_name = ProgName;
X    class_hints.res_class = "Faxview";
X    XSetWMProperties(Disp, Win, &windowName, &iconName, argv, argc,
X		     &size_hints, &wm_hints, &class_hints);
}
#else
X    XSetStandardProperties(Disp, Win, thispage->name, ProgName,
X			   None, argv, argc, &size_hints);
#endif
X
X    PaintGC = XCreateGC(Disp, Win, 0L, (XGCValues *) NULL);
X    XSetForeground(Disp, PaintGC, BlackPixel(Disp, Default_Screen));
X    XSetBackground(Disp, PaintGC, WhitePixel(Disp, Default_Screen));
X    XSetFunction(Disp, PaintGC, GXcopy);
X    WorkCursor = XCreateFontCursor(Disp, XC_watch);
X    ReadyCursor = XCreateFontCursor(Disp, XC_plus);
X    MoveCursor = XCreateFontCursor(Disp, XC_fleur);
X    LRCursor = XCreateFontCursor(Disp, XC_sb_h_double_arrow);
X    UDCursor = XCreateFontCursor(Disp, XC_sb_v_double_arrow);
X    XSelectInput(Disp, Win, Button2MotionMask | ButtonPressMask |
X		 ButtonReleaseMask | ExposureMask | KeyPressMask |
X		 SubstructureNotifyMask | OwnerGrabButtonMask |
#ifdef USE_MOTIONHINT
X		 PointerMotionHintMask |
#endif
X		 StructureNotifyMask);
X    wm_protocols = XInternAtom(Disp, "WM_PROTOCOLS", False);
X    wm_delete_window = XInternAtom(Disp, "WM_DELETE_WINDOW", False);
X    XChangeProperty(Disp, Win, wm_protocols, XA_ATOM, 32,
X                    PropModeAppend, (unsigned char * ) &wm_delete_window, 1);
X    XMapRaised(Disp, Win);
}
X
#define MAXZOOM	10
X
/* After requesting a window size change, we throw away key and button presses
X   until we get the notification that the size has changed.  If for some
X   reason the notification does not come, we resume processing as normal after
X   PATIENCE milliseconds */
#define PATIENCE 10000
X
static void
ShowLoop(void)
{
X    XEvent Event;
X
X    /* centre of image within window */
X    int x = 0, ox = 0, offx = 0, nx;	/* x, old x, offset x, new x */
X    int y = 0, oy = 0, offy = 0, ny;	/* y, old y, offset y, new y */
X
X    int oz, Resize = 0, Refresh = 0;	/* old zoom, window size changed,
X					   needs updating */
X    int PaneWidth, PaneHeight;		/* current size of our window */
X    int AbsX, AbsY;		/* absolute position of centre of window */
X    int FrameWidth, FrameHeight, FrameX, FrameY;/* size/offset of decoration */
X    int Oversize = 0;		/* window manager insists on oversize window */
X    int Reparented = 0;
X    int i;
X    XImage *Image, *Images[MAXZOOM];
X    struct pagenode *viewpage = NULL;	/* page viewed when help requested */
X    XSizeHints size_hints;
X    Time Lasttime = 0;		/* time of last accepted key/button press */
X    int ExpectConfNotify = 1;
X
X    XDefineCursor(Disp, Win, WorkCursor);
X    XFlush(Disp);
X    for (oz = 0; oz < MAXZOOM; oz++)
X	Images[oz] = NULL;
X    Image = Images[0] = Pimage(thispage);
X    for (oz = 0; oz < MAXZOOM && zfactor > (1 << oz); oz++)
X	Images[oz+1] = ZoomImage(Images[oz]);
X    Image = Images[oz];
X
X    /* some reasonable values,
X       just in case we do not get a configurenotify first */
X    AbsX = Area.w/2;
X    AbsY = Area.h/2;
X    FrameWidth = FrameHeight = FrameX = FrameY = 0;
X    PaneWidth = Image->width;
X    PaneHeight = Image->height;
X
X    XDefineCursor(Disp, Win, ReadyCursor);
X
X    for (;;) {
X	XNextEvent(Disp, &Event);
X	do {
X	    switch(Event.type) {
X	    case MappingNotify:
X		XRefreshKeyboardMapping((XMappingEvent *)(&Event));
X		break;
X	    case ClientMessage:
X		if (Event.xclient.data.l[0] == wm_delete_window) {
X		    XCloseDisplay(Disp);
X		    exit(1);
X		}
X		break;
X	    case Expose:
X	    {
X		XExposeEvent *p = (XExposeEvent *) &Event;
X		XPutImage(Disp, Win, PaintGC, Image,
X			  p->x + x - PaneWidth/2,
X			  p->y + y - PaneHeight/2,
X			  p->x, p->y,
X			  p->width, p->height);
X	    }
X		break;
X	    case ReparentNotify:
X	    {
X		Window Myroot = Root;
X		Window Parent = Event.xreparent.parent;
X		Window Frame = Parent;	/* I should be so lucky! */
X		Window *Mykids;
X		unsigned int Nkids;
X		XWindowAttributes MyWA, FrameWA;
X
X		if (Parent != Root)
X		    do {
X			Frame = Parent;
X			while (!XQueryTree(Disp, Frame, &Myroot,
X					   &Parent, &Mykids, &Nkids))
X			    release(1);
X			if (Mykids) XFree(Mykids);
X		    } while (Parent != Root);
X		while (!XGetWindowAttributes(Disp, Win, &MyWA))
X		    release(1);
X		while (!XGetWindowAttributes(Disp, Frame, &FrameWA))
X		    release(1);
X		/* if area is partly constrained, stay where the WM put you */
X		if ((Area.v & (XValue|WidthValue)) == WidthValue) {
X		    Area.v |= XValue;
X		    Area.x = FrameWA.x;
X		}
X		if ((Area.v & (YValue|HeightValue)) == HeightValue) {
X		    Area.v |= YValue;
X		    Area.y = FrameWA.y;
X		}
X		XTranslateCoordinates(Disp, Win, Frame, 0, 0,
X				      &FrameX, &FrameY, &Parent);
X		FrameWidth = FrameWA.width - MyWA.width;
X		FrameHeight = FrameWA.height - MyWA.height;
X		Reparented = ExpectConfNotify = 1;
X	    }
X		break;
X	    case ConfigureNotify:
X	    {
X		XConfigureEvent *p = (XConfigureEvent *) &Event;
X		int NewX = AbsX;
X		int NewY = AbsY;
#ifdef REAL_ROOT
X		if (p->send_event || !Reparented) {
X		    NewX = p->x + p->width/2;
X		    NewY = p->y + p->height/2;
X		}
#else
X		/* support tvtwm */
X		if (!Reparented) {
X		    NewX = p->x + p->border_width + p->width/2;
X		    NewY = p->y + p->border_width + p->height/2;
X		}
X		else if (p->send_event) {
X		    /* the event info is viewport-relative, we need absolute */
X		    Window w;
X		    XTranslateCoordinates(Disp, Win, Root, 0, 0,
X					  &NewX, &NewY, &w);
X		    NewX += p->width/2;
X		    NewY += p->height/2;
X		}
#endif
X		if (!ExpectConfNotify) {
X		    /* user intervention */
X		    if (PaneWidth != p->width)
X			Area.w = p->width + FrameWidth;
X		    if (PaneHeight != p->height)
X			Area.h = p->height + FrameHeight;
X		    if (NewX != AbsX || NewY != AbsY) {
X			Area.x = NewX - p->width/2 - FrameX;
X			Area.y = NewY - p->height/2 - FrameY;
X		    }
X		}
X		AbsX = NewX; AbsY = NewY;
X		PaneWidth = p->width;
X		PaneHeight = p->height;
X		Oversize = PaneWidth > Image->width ||
X		    PaneHeight > Image->height;
X		ExpectConfNotify = 0;
X	    }
X		break;
X	    case KeyPress:
X		if (ExpectConfNotify &&
X		    (Event.xkey.time < (Lasttime + PATIENCE)))
X		    break;
X		Lasttime = Event.xkey.time;
X		ExpectConfNotify = 0;
X		switch(XKeycodeToKeysym(Disp, Event.xkey.keycode, 0)) {
X		case XK_Help:
X		case XK_h:
X		    if (helppage == NULL) {
X			if (!notetiff(HELPFILE))
X			    goto nopage;
X			else {
X			    helppage = lastpage;
X			    lastpage = helppage->prev;
X			    lastpage->next = helppage->prev = NULL;
X			}
X		    }
X		    viewpage = thispage;
X		    thispage = helppage;
X		    goto newpage;
X		    break;
X		case XK_m:
X		    XDefineCursor(Disp, Win, WorkCursor);
X		    XFlush(Disp);
X		    thispage->extra = Images[0] = MirrorImage(Images[0]);
X		    thispage->orient ^= TURN_M;
X		    for (i = 1; Images[i]; i++) {
X			FreeImage(Images[i]);
X			Images[i] = ZoomImage(Images[i-1]);
X		    }
X		    Image = Images[oz];
X		    XPutImage(Disp, Win, PaintGC, Image,
X			      x-PaneWidth/2, y-PaneHeight/2,
X			      0, 0, PaneWidth, PaneHeight);
X		    XDefineCursor(Disp, Win, ReadyCursor);
X		    break;
X		case XK_z:
X		    if (Event.xkey.state & ShiftMask)
X			goto Zoomout;
X		    else
X			goto Zoomin;
X		case XK_Up:
X		    y -= PaneHeight / 2;
X		    break;
X		case XK_Down:
X		    y += PaneHeight / 2;
X		    break;
X		case XK_Left:
X		    x -= PaneWidth / 2;
X		    break;
X		case XK_Right:
X		    x += PaneWidth / 2;
X		    break;
X		case XK_Home:
X		case XK_R7:		/* sun4 keyboard */
X		    if (Event.xkey.state & ShiftMask) {
X			thispage = firstpage;
X			goto newpage;
X		    }
X		    x = 0;
X		    y = 0;
X		    break;
X		case XK_End:
X		case XK_R13:
X		    if (Event.xkey.state & ShiftMask) {
X			thispage = lastpage;
X			goto newpage;
X		    }
X		    x = Image->width;
X		    y = Image->height;
X		    break;
X		case XK_l:
X		    XDefineCursor(Disp, Win, WorkCursor);
X		    XFlush(Disp);
X		    thispage->extra = Image = RotImage(Images[0]);
X		    thispage->orient ^= TURN_L;
X		    for (i = 1; Images[i]; i++) {
X			FreeImage(Images[i]);
X			Images[i] = NULL;
X		    }
X		    Images[0] = Image;
X		    for (i = 1; i <= oz; i++)
X			Images[i] = ZoomImage(Images[i-1]);
X		    Image = Images[oz];
X		{ int t = x; x = y; y = t; }
X		    Refresh = Resize = 1;
X		    XDefineCursor(Disp, Win, ReadyCursor);
X		    break;
X		case XK_p:
X		case XK_minus:
X		case XK_Prior:
X		case XK_R9:
X		case XK_BackSpace:
X		    if (thispage->prev == NULL)
X			goto nopage;
X		    thispage = thispage->prev;
X		    goto newpage;
X		case XK_n:
X		case XK_plus:
X		case XK_space:
X		case XK_Next:
X		case XK_R15:
X		    if (thispage->next == NULL) {
X		    nopage:
X			if (abell) {
X			    putchar('\a');
X			    fflush(stdout);
X			}
X			if (vbell) {
X			    XAddPixel(Image, 1);
X			    XPutImage(Disp, Win, PaintGC, Image,
X				      x-PaneWidth/2, y-PaneHeight/2,
X				      0, 0, PaneWidth, PaneHeight);
X			    XSync(Disp, 0);
X			    (void) usleep(200000);
X			    XAddPixel(Image, 1);
X			    XPutImage(Disp, Win, PaintGC, Image,
X				      x-PaneWidth/2, y-PaneHeight/2,
X				      0, 0, PaneWidth, PaneHeight);
X			}
X			break;
X		    }
X		    thispage = thispage->next;
X		newpage:
X		    XDefineCursor(Disp, Win, WorkCursor);
X		    XFlush(Disp);
X		    /* if old image was not resized by the user, fit new one */
X		    Resize = ((PaneWidth == Image->width ||
X			       PaneWidth == Area.w - FrameWidth) &&
X			      (PaneHeight == Image->height ||
X			       PaneHeight == Area.h - FrameHeight));
X		    for (i = 1; Images[i]; i++) {
X			FreeImage(Images[i]);
X			Images[i] = NULL;
X		    }
X		    if (Pimage(thispage) == NULL)
X			while (!GetImage(thispage))
X			    /* try again */;
X		    Images[0] = Pimage(thispage);
X		    XStoreName(Disp, Win, thispage->name);
X		    for (i = 1; i <= oz; i++)
X			Images[i] = ZoomImage(Images[i-1]);
X		    Image = Images[oz];
X		    Refresh = 1;
X		    XDefineCursor(Disp, Win, ReadyCursor);
X		    break;
X		case XK_u:
X		    XDefineCursor(Disp, Win, WorkCursor);
X		    XFlush(Disp);
X		    thispage->extra = Images[0] = FlipImage(Images[0]);
X		    thispage->orient ^= TURN_U;
X		    for (i = 1; Images[i]; i++) {
X			FreeImage(Images[i]);
X			Images[i] = ZoomImage(Images[i-1]);
X		    }
X		    Image = Images[oz];
X		    XPutImage(Disp, Win, PaintGC, Image,
X			      x-PaneWidth/2, y-PaneHeight/2,
X			      0, 0, PaneWidth, PaneHeight);
X		    XDefineCursor(Disp, Win, ReadyCursor);
X		    break;
X		case XK_q:
X		    if (viewpage) {
X			thispage = viewpage;
X			viewpage = NULL;
X			goto newpage;
X		    }
X		    XCloseDisplay(Disp);
#ifdef xmalloc
X		    malloc_shutdown();
#endif
X		    exit(0);
X		}
X		break;
X	    case ButtonPress:
X		if (ExpectConfNotify &&
X		    (Event.xbutton.time < (Lasttime + PATIENCE)))
X		    break;
X		Lasttime = Event.xbutton.time;
X		ExpectConfNotify = 0;
X		switch (Event.xbutton.button) {
X		case Button1:
X		Zoomout:
X		    if (oz > 0) {
X			Image = Images[--oz];
X			zfactor >>= 1;
X			x *= 2;
X			y *= 2;
X			Resize = Refresh = 1;
X		    }
X		    break;
X		case Button2:
X		    switch (((Image->width > PaneWidth)<<1) |
X			    (Image->height > PaneHeight)) {
X		    case 0:
X			break;
X		    case 1:
X			XDefineCursor(Disp, Win, UDCursor);
X			break;
X		    case 2:
X			XDefineCursor(Disp, Win, LRCursor);
X			break;
X		    case 3:
X			XDefineCursor(Disp, Win, MoveCursor);
X		    }
X		    XFlush(Disp);
X		    offx = Event.xbutton.x;
X		    offy = Event.xbutton.y;
X		    break;
X		case Button3:
X		Zoomin:
X		    if (oz < MAXZOOM && Image->width >= 64 && zfactor < 32) {
X			Image = Images[++oz];
X			zfactor <<= 1;
X			x /= 2;
X			y /= 2;
X			Resize = Refresh = 1;
X		    }
X		    break;
X		}
X		if (Image == NULL) {
X		    for (i = oz; i && (Images[i] == NULL); i--)
X			;
X		    for (; i != oz; i++)
X			Images[i+1] = ZoomImage(Images[i]);
X		    Image = Images[oz];
X		}
X		break;
X	    case MotionNotify:
#ifdef USE_MOTIONHINT
X	    {
X		unsigned int Junk;
X		Window JunkW;
X		XQueryPointer(Disp, Event.xmotion.window, &JunkW, &JunkW,
X			      &Junk, &Junk, &nx, &ny, &Junk);
X	    }
#else
X		do {
X		    nx = Event.xmotion.x;
X		    ny = Event.xmotion.y;
X		} while (XCheckTypedEvent(Disp, MotionNotify, &Event));
#endif
X		x += offx - nx;
X		y += offy - ny;
X		offx = nx;
X		offy = ny;
X		break;
X	    case ButtonRelease:
X		if (Event.xbutton.button == Button2) {
X		    XDefineCursor(Disp, Win, ReadyCursor);
X		    XFlush(Disp);
X		}
X	    }
X	} while (XCheckWindowEvent(Disp, Win,
X				   KeyPressMask|ButtonPressMask, &Event));
X
X	/* if someone thinks we should resize the window and it is not
X	   already the right size, or if the window is too big and we
X	   have not already tried to make it smaller ... */
X	if ((Resize && !(Image->width == PaneWidth &&
X			 Image->height == PaneHeight)) ||
X	    (!Oversize && (Image->width < PaneWidth ||
X			   Image->height < PaneHeight))) {
X	    int PosX = AbsX - PaneWidth/2 - FrameX;
X	    int PosY = AbsY - PaneHeight/2 - FrameY;
X	    XWindowChanges New;
X	    int ChangeMask = 0;
X
X	    New.width = min(Area.w - FrameWidth, Image->width);
X	    New.height = min(Area.h - FrameHeight, Image->height);
X	    /* expect an expose if size must change */
X	    Refresh &= (New.width == PaneWidth && New.height == PaneHeight);
X	    New.x = max(Area.x, AbsX-New.width/2-FrameX);
X	    New.x = min(New.x, Area.w-(New.width+FrameWidth)+Area.x);
X	    New.y = max(Area.y, AbsY-New.height/2-FrameY);
X	    New.y = min(New.y, Area.h-(New.height+FrameHeight)+Area.y);
X
X	    /* mwm takes max_size very seriously! */
X	    size_hints.flags = 0;
X	    XSetNormalHints(Disp, Win, &size_hints);
X
X	    size_hints.flags = PMaxSize;
X	    size_hints.x = PosX;
X	    size_hints.y = PosY;
X	    size_hints.width = PaneWidth;
X	    size_hints.height = PaneHeight;
X	    /* only move a coordinate if the ideal new value is different
X	       from the current value and either the other dimension has
X	       changed or the current value is out of area */
X	    if (PosX != New.x &&
X		(New.height != PaneHeight || PosX < Area.x || 
X		 PosX > Area.w-New.width-FrameWidth-Area.x)) {
X		ChangeMask |= CWX;
X		size_hints.x = New.x;
X		size_hints.flags |= PPosition;
X	    }
X	    if (PosY != New.y &&
X		(New.width != PaneWidth || PosY < Area.y ||
X		 PosY > Area.h-New.height-FrameHeight-Area.y)) {
X		ChangeMask |= CWY;
X		size_hints.y = New.y;
X		size_hints.flags |= PPosition;
X	    }
X	    if (New.width != PaneWidth) {
X		ChangeMask |= CWWidth;
X		size_hints.width = New.width;
X		size_hints.flags |= PSize;
X		ExpectConfNotify = Reparented;
X	    }
X	    if (New.height != PaneHeight) {
X		ChangeMask |= CWHeight;
X		size_hints.height = New.height;
X		size_hints.flags |= PSize;
X		ExpectConfNotify = Reparented;
X	    }
X	    New.border_width = 1;	/* ICCCM 4.1.5 */
X	    ChangeMask |= CWBorderWidth;
X	    XConfigureWindow(Disp, Win, ChangeMask, &New);
X	    size_hints.max_width = Image->width;
X	    size_hints.max_height = Image->height;
X	    XSetNormalHints(Disp, Win, &size_hints);
X	}
X	x = max(x, PaneWidth/2);
X	x = min(x, Image->width-PaneWidth/2);
X	y = max(y, PaneHeight/2);
X	y = min(y, Image->height-PaneHeight/2);
X	if (x != ox || y != oy || Refresh)
X	    XPutImage(Disp, Win, PaintGC, Image,
X		      x-PaneWidth/2, y-PaneHeight/2,
X		      0, 0, PaneWidth, PaneHeight);
X	ox = x;
X	oy = y;
X	Resize = Refresh = 0;
X    }
}
X
/* run this region through perl to generate the zoom table:
$lim = 1;
@c = ("0", "1", "1", "2");
print "static unsigned char Z[] = {\n";
for ($i = 0; $i < 16; $i++) {
X    for ($j = 0; $j < 16; $j++) {
X	$b1 = ($c[$j&3]+$c[$i&3]) > $lim;
X	$b2 = ($c[($j>>2)&3]+$c[($i>>2)&3]) > $lim;
X	printf " %X,", ($b2 << 1) | $b1;
X    }
X    print "\n";
}
print "};\n";
*/
static unsigned char Z[] = {
X 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 3,
X 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, 3, 3,
X 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, 3, 3,
X 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3,
X 0, 0, 0, 1, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3,
X 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
X 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
X 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
X 0, 0, 0, 1, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3,
X 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
X 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
X 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
X 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3,
X 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
X 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
X 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
};
X
#define nib(n,w)	(((w)>>((n)<<2))&15)
#define zak(a,b)	Z[(a<<4)|b]
X
/* 2 -> 1 zoom, 4 pixels -> 1 pixel
X   if #pixels <= $lim (see above), new pixel is white,
X   else black.
*/
static XImage *
ZoomImage(XImage *Big)
{
X    XImage *Small;
X    int w, h;
X    int i, j;
X
X    XDefineCursor(Disp, Win, WorkCursor);
X    XFlush(Disp);
X    w = (Big->width+1) / 2;
X    h = (Big->height+1) / 2;
X    Small = NewImage(w, h, NULL, Big->bitmap_bit_order);
X    Small->xoffset = (Big->xoffset+1)/2;
X    for (i = 0; i < Big->height; i += 2) {
X	t32bits *pb0 = (t32bits *) (Big->data + i * Big->bytes_per_line);
X	t32bits *pb1 = pb0 + ((i == Big->height-1) ? 0 : Big->bytes_per_line/4);
X	t32bits *ps = (t32bits *) (Small->data + i * Small->bytes_per_line / 2);
X	for (j = 0; j < Big->bytes_per_line/8; j++) {
X	    t32bits r1, r2;
X	    t32bits t0 = *pb0++;
X	    t32bits t1 = *pb1++;
X	    r1 = (zak(nib(7,t0),nib(7,t1))<<14) |
X		 (zak(nib(6,t0),nib(6,t1))<<12) |
X		 (zak(nib(5,t0),nib(5,t1))<<10) |
X		 (zak(nib(4,t0),nib(4,t1))<<8) |
X		 (zak(nib(3,t0),nib(3,t1))<<6) |
X		 (zak(nib(2,t0),nib(2,t1))<<4) |
X		 (zak(nib(1,t0),nib(1,t1))<<2) |
X		 (zak(nib(0,t0),nib(0,t1)));
X	    t0 = *pb0++;
X	    t1 = *pb1++;
X	    r2 = (zak(nib(7,t0),nib(7,t1))<<14) |
X		 (zak(nib(6,t0),nib(6,t1))<<12) |
X		 (zak(nib(5,t0),nib(5,t1))<<10) |
X		 (zak(nib(4,t0),nib(4,t1))<<8) |
X		 (zak(nib(3,t0),nib(3,t1))<<6) |
X		 (zak(nib(2,t0),nib(2,t1))<<4) |
X		 (zak(nib(1,t0),nib(1,t1))<<2) |
X		 (zak(nib(0,t0),nib(0,t1)));
X	    *ps++ = (Big->bitmap_bit_order) ?
X		(r1<<16)|r2 : (r2<<16)|r1;
X	}
X	for ( ; j < Small->bytes_per_line/4; j++) {
X	    t32bits r1;
X	    t32bits t0 = *pb0++;
X	    t32bits t1 = *pb1++;
X	    r1 = (zak(nib(7,t0),nib(7,t1))<<14) |
X		 (zak(nib(6,t0),nib(6,t1))<<12) |
X		 (zak(nib(5,t0),nib(5,t1))<<10) |
X		 (zak(nib(4,t0),nib(4,t1))<<8) |
X		 (zak(nib(3,t0),nib(3,t1))<<6) |
X		 (zak(nib(2,t0),nib(2,t1))<<4) |
X		 (zak(nib(1,t0),nib(1,t1))<<2) |
X		 (zak(nib(0,t0),nib(0,t1)));
X	    *ps++ = (Big->bitmap_bit_order) ?
X		(r1<<16) : r1;
X	}
X    }
X    XDefineCursor(Disp, Win, ReadyCursor);
X    return Small;
}
X
static XImage *
FlipImage(XImage *Image)
{
X    XImage *New = NewImage(Image->width, Image->height,
X			   Image->data, !Image->bitmap_bit_order);
X    t32bits *p1 = (t32bits *) Image->data;
X    t32bits *p2 = (t32bits *) (Image->data + Image->height *
X			     Image->bytes_per_line - 4);
X
X    /* the first shall be last ... */
X    while (p1 < p2) {
X	t32bits t = *p1;
X	*p1++ = *p2;
X	*p2-- = t;
X    }
X
X    /* let Xlib twiddle the bits */
X    New->xoffset = 32 - (Image->width & 31) - Image->xoffset;
X    New->xoffset &= 31;
X
X    Image->data = NULL;
X    FreeImage(Image);
X    return New;
}
X
static XImage *
MirrorImage(XImage *Image)
{
X    int i;
X    XImage *New = NewImage(Image->width, Image->height,
X			   Image->data, !Image->bitmap_bit_order);
X
X    /* reverse order of 32-bit words in each line */
X    for (i = 0; i < Image->height; i++) {
X	t32bits *p1 = (t32bits *) (Image->data + Image->bytes_per_line * i);
X	t32bits *p2 = p1 + Image->bytes_per_line/4 - 1;
X	while (p1 < p2) {
X	    t32bits t = *p1;
X	    *p1++ = *p2;
X	    *p2-- = t;
X	}
X    }
X
X    /* let Xlib twiddle the bits */
X    New->xoffset = 32 - (Image->width & 31) - Image->xoffset;
X    New->xoffset &= 31;
X
X    Image->data = NULL;
X    FreeImage(Image);
X    return New;
}
X
static XImage *
RotImage(XImage *Image)
{
X    XImage *New;
X    int w = Image->height;
X    int h = Image->width;
X    int i, j, k, shift;
X    int order = Image->bitmap_bit_order;
X    int offs = h+Image->xoffset-1;
X
X    New = NewImage(w, h, NULL, 1);
X
X    k = (32 - Image->xoffset) & 3;
X    for (i = h - 1; i && k; i--, k--) {
X	t32bits *sp = (t32bits *) Image->data + (offs-i)/32;
X	t32bits *dp = (t32bits *) (New->data+i*New->bytes_per_line);
X	t32bits d0;
X	shift = (offs-i)&31;
X	if (order) shift = 31-shift;
X	for (j = 0; j < w; j++) {
X	    t32bits t = *sp;
X	    sp += Image->bytes_per_line/4;
X	    d0 |= ((t >> shift) & 1);
X	    if ((j & 31) == 31)
X		*dp++ = d0;
X	    d0 <<= 1;;
X	}
X	if (j & 31)
X	    *dp++ = d0<<(31-j);
X    }
X    for ( ; i >= 3; i-=4) {
X	t32bits *sp = (t32bits *) Image->data + (offs-i)/32;
X	t32bits *dp0 = (t32bits *) (New->data+i*New->bytes_per_line);
X	t32bits *dp1 = dp0 - New->bytes_per_line/4;
X	t32bits *dp2 = dp1 - New->bytes_per_line/4;
X	t32bits *dp3 = dp2 - New->bytes_per_line/4;
X	t32bits d0, d1, d2, d3;
X	shift = (offs-i)&31;
X	if (order) shift = 28-shift;
X	for (j = 0; j < w; j++) {
X	    t32bits t = *sp >> shift;
X	    sp += Image->bytes_per_line/4;
X	    d0 |= t & 1; t >>= 1;
X	    d1 |= t & 1; t >>= 1;
X	    d2 |= t & 1; t >>= 1;
X	    d3 |= t & 1; t >>= 1;
X	    if ((j & 31) == 31) {
X		if (order) {
X		    *dp0++ = d3;
X		    *dp1++ = d2;
X		    *dp2++ = d1;
X		    *dp3++ = d0;
X		}
X		else {
X		    *dp0++ = d0;
X		    *dp1++ = d1;
X		    *dp2++ = d2;
X		    *dp3++ = d3;
X		}
X	    }
X	    d0 <<= 1; d1 <<= 1; d2 <<= 1; d3 <<= 1;
X	}
X	if (j & 31) {
X	    if (order) {
X		*dp0++ = d3<<(31-j);
X		*dp1++ = d2<<(31-j);
X		*dp2++ = d1<<(31-j);
X		*dp3++ = d0<<(31-j);
X	    }
X	    else {
X		*dp0++ = d0<<(31-j);
X		*dp1++ = d1<<(31-j);
X		*dp2++ = d2<<(31-j);
X		*dp3++ = d3<<(31-j);
X	    }
X	}
X    }
X    for (; i >= 0; i--) {
X	t32bits *sp = (t32bits *) Image->data + (offs-i)/32;
X	t32bits *dp = (t32bits *) (New->data+i*New->bytes_per_line);
X	t32bits d0;
X	shift = (offs-i)&31;
X	if (order) shift = 31-shift;
X	for (j = 0; j < w; j++) {
X	    t32bits t = *sp;
X	    sp += Image->bytes_per_line/4;
X	    d0 |= ((t >> shift) & 1);
X	    if ((j & 31) == 31)
X		*dp++ = d0;
X	    d0 <<= 1;;
X	}
X	if (j & 31)
X	    *dp++ = d0<<(31-j);
X    }
X    FreeImage(Image);
X    return New;
}
X
/* release some non-essential memory or abort */
#define Try(n)								\
X    if (n && n != thispage && n->extra) {				\
X	FreeImage(n->extra);						\
X	n->extra = NULL;						\
X	return 1;							\
X    }
X
static int
release(int quit)
{
X    struct pagenode *pn;
X
X    if (thispage) {
X	/* first consider "uninteresting" pages */
X	for (pn = firstpage->next; pn; pn = pn->next)
X	    if (pn->extra && pn != thispage && pn != thispage->prev &&
X		pn != thispage->next && pn != lastpage) {
X		FreeImage(Pimage(pn));
X		pn->extra = NULL;
X		return 1;
X	    }
X	Try(lastpage);
X	Try(firstpage);
X	Try(thispage->prev);
X	Try(thispage->next);
X    }
X    if (!quit)
X	return 0;
X    fprintf(stderr, "%s(release): insufficient memory\n", ProgName);
X    exit(1);
}
X
static XImage *
NewImage(int w, int h, char *data, int bit_order)
{
X    XImage *new;
X    /* This idea is taken from xwud/xpr.  Use a fake display with the
X       desired bit/byte order to get the image routines initialised
X       correctly */
X    Display fake = *Disp;
X
X    if (data == NULL)
X	data = xmalloc(((w + 31) & ~31) * h / 8);
X    fake.byte_order = ByteOrder;
X    fake.bitmap_bit_order = bit_order;
X
X    while ((new = XCreateImage(&fake, DefaultVisual(Disp, Default_Screen),
X			       1, XYBitmap, 0, data, w, h, 32, 0)) == NULL)
X	(void) release(1);
X    Memused += new->bytes_per_line * new->height;
X    return new;
}
X
static void
FreeImage(XImage *Image)
{
X    if (Image->data)
X	Memused -= Image->bytes_per_line * Image->height;
X    XDestroyImage(Image);
}
X
#ifndef xmalloc
char *
xmalloc(unsigned int size)
{
X    char *p;
X
X    while (Memused + size > Memlimit && release(0))
X	;
X    while ((p = malloc(size)) == NULL)
X	(void) release(1);
X    return p;
}
#endif
SHAR_EOF
chmod 0664 viewfax-2.2/viewfax.c ||
echo 'restore of viewfax-2.2/viewfax.c failed'
Wc_c="`wc -c < 'viewfax-2.2/viewfax.c'`"
test 36678 -eq "$Wc_c" ||
	echo 'viewfax-2.2/viewfax.c: original size 36678, current size' "$Wc_c"
fi
true || echo 'restore of viewfax-2.2/viewfax.man failed'
echo End of part 2, continue with part 3
exit 0

-- 
Frank Cringle                      | fdc@cliwe.ping.de
voice + fax                        | +49 2304 467101


