[comp.sources.x] REPOST: v09i076: XV -- successor to XGIF, Part01/01

bradley@grip.cis.upenn.edu (John Bradley) (10/11/90)

Submitted-by: bradley@grip.cis.upenn.edu (John Bradley)
Posting-number: Volume 9, Issue 76
Archive-name: xv/part01

**  SORRY!!!! I seriously screwed up this submission!  It's being
**  reposted.  Extended apologies to archive sites!!!
**  --dan heller

XV is a direct successor to XGIF.  

New features include:
  * more graphic formats supported (GIF, PBM/PGM/PPM, and X11 bitmap)

  * works on most X displays (1-, 4-, 6-, 8-, and 24-bit displays are
    supported)

  * arbitrary scaling, cropping, rotation (in 90-degree steps)

  * can write files in all formats listed above

  * arbitrary gamma correction curve for brightness/contrast control
    and interesting effects

  * cool-whizo user interface

  * better color allocation code, including the ability to install its own
    colormap if necessary

  * more robust error handling

  * and more bug fixes than we'd care to discuss...


Full Description:
-----------------
XV is a program that displays image files in GIF, PBM/PGM/PPM, and X11 Bitmap
formats.  It is a direct sequel to XGIF, and fixes most (if not all) of the
shortcomings of that program.  XV runs on nearly ALL X displays, 1-bit,
4-bit, 6-bit, 8-bit, and 24-bit, color, grayscale, and black/white.  

XV displays one image at a time in an output window.  You can arbitrarily
stretch or compress the window, and the picture will be rescaled to fit.  
You can rotate the picture in 90-degree steps.  You can repeatedly 'crop'
a picture (define a rectangular 'region-of-interest' and 'throw away' the
rest).  You can magnify any portion of the picture by any amount, up to the 
maximum size of your screen.  

XV allows you click on the picture to determine pixel RGB values and x,y 
coordinates.  You can perform arbitrary 'gamma correction' on the picture
both in RGB space and HSV space.  You can specify the maximum number of colors
that XV should use, for some interesting visual effects.  You can have
the program produce a stippled version of the picture using black and white,
or any other pair of colors.  

XV can write images in a variety of formats, with many of the modifications 
you may have made to the picture saved as well.  You can use XV to do format 
conversion.  XV will also automatically uncompress compress-ed files, as well 
as read files from stdin.


John Bradley                    University of Pennsylvania  -  GRASP Lab
     bradley@cis.upenn.edu

     October 9, 1990

----------------------(cut here)--------------------
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./xvpbm.c`
then
echo "writting ./xvpbm.c"
cat > ./xvpbm.c << '\BARFOO\'
/*
 * xvpbm.c - load routine for 'pm' format pictures
 *
 * LoadPBM(fname, numcols)  -  loads a PBM, PGM, or PPM file
 * WritePBM(fp,pic,w,h,r,g,b,numcols,style,raw,cmt)
 */

/*
 * Copyright 1989, 1990 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any express or implied warranty.
 */


#include "xv.h"



/* comments on error handling:
   a truncated file is not considered a Major Error.  The file is loaded, the
   rest of the pic is filled with 0's.

   a file with garbage characters in it is an unloadable file.  All allocated
   stuff is tossed, and LoadPBM returns non-zero

   not being able to malloc is a Fatal Error.  The program is aborted. */


#define TRUNCSTR "File appears to be truncated."

static int garbage;
static long numgot, filesize;


static int loadpbm(), loadpgm(), loadppm();
static int getint(),  getbit(),  PBMerr();


/*******************************************/
int LoadPBM(fname,nc)
     char *fname;
     int   nc;
/*******************************************/
{
  FILE  *fp;
  int    c, c1;
  int    w, h, maxv, rv;

  garbage = 0;

  /* open the stream, if necesary */
  fp=fopen(fname,"r");
  if (!fp) return 1;
  
  /* figure out the file size (for Informational Purposes Only) */
  fseek(fp, 0L, 2);
  filesize = ftell(fp);
  fseek(fp, 0L, 0);

  /* read the first two bytes of the file to determine which format
     this file is.  "P1" = ascii bitmap, "P2" = ascii greymap,
     "P3" = ascii pixmap, "P4" = raw bitmap, "P5" = raw greymap,
     "P6" = raw pixmap */

  c = getc(fp);  c1 = getc(fp);
  if (c!='P' || c1<'1' || c1>'6') return(PBMerr("unknown format"));

  /* read in header information */
  w = getint(fp);  h = getint(fp);

  /* if we're not reading a bitmap, read the 'max value' */
  if ( !(c1=='1' || c1=='4')) {
    maxv = getint(fp);
    if (maxv < 1) garbage=1;    /* to avoid 'div by zero' probs */
  }


  if (garbage) {
    if (fp!=stdin) fclose(fp);
    return (PBMerr("Garbage characters in header."));
  }

  rv = 0;

  /* call the appropriate subroutine to handle format-specific stuff */
  if      (c1=='1' || c1=='4') rv = loadpbm(fp,w,h,       c1=='4' ? 1 : 0);
  else if (c1=='2' || c1=='5') rv = loadpgm(fp,w,h, maxv, c1=='5' ? 1 : 0);
  else if (c1=='3' || c1=='6') rv = loadppm(fp,w,h, maxv, c1=='6' ? 1 : 0, nc);

  if (fp!=stdin) fclose(fp);
  return(rv);
}  



/*******************************************/
static int loadpbm(fp, w, h, raw)
FILE *fp;
int   w,h,raw;
{
  byte *pix;
  int   i,j,k,bit;


  SetISTR(ISTR_FORMAT,"PBM, %s format.  (%ld bytes)", 
	  (raw) ? "raw" : "ascii", filesize);

  /* load up the XV global variables */
  pic = (byte *) calloc(w*h,1);
  if (!pic) FatalError("couldn't malloc 'pic'");

  pWIDE = w;  pHIGH = h;

  /* B/W bitmaps have a two entry colormap */
  r[0] = g[0] = b[0] = 255;   /* 0 = white */
  r[1] = g[1] = b[1] = 0;     /* 1 = black */

  if (!raw) {
    numgot = 0;
    for (i=0, pix=pic; i<h; i++)
      for (j=0; j<w; j++, pix++)
	*pix = getbit(fp);

    if (numgot != w*h) PBMerr(TRUNCSTR);
    if (garbage) {
      free(pic);
      return(PBMerr("Garbage characters in image data."));
    }
  }


  else {   /* read raw bits */
    int trunc = 0;

    for (i=0, pix=pic; i<h; i++)
      for (j=0,bit=0; j<w; j++, pix++, bit++) {

	bit &= 7;
	if (!bit) {
	  k = getc(fp);
	  if (k==EOF) { trunc=1; k=0; }
	}

	*pix = (k&0x80) ? 1 : 0;
	k = k << 1;
      }

    if (trunc) PBMerr(TRUNCSTR);
  }

  return 0;
}


/*******************************************/
static int loadpgm(fp, w, h, maxv, raw)
FILE *fp;
int   w,h,maxv,raw;
{
  byte *pix;
  int   i,j,bitshift;

  SetISTR(ISTR_FORMAT,"PGM, %s format.  (%ld bytes)", 
	  (raw) ? "raw" : "ascii", filesize);

  /* load up the XV global variables */
  pic = (byte *) calloc(w*h,1);
  if (!pic) FatalError("couldn't malloc 'pic'");

  pWIDE = w;  pHIGH = h;

  /* if maxv>255, keep dropping bits until it's reasonable */
  bitshift = 0;
  while (maxv>255) { maxv = maxv>>1;  bitshift++; }

  /* fill in a greyscale colormap where maxv maps to 255 */
  for (i=0; i<=maxv; i++)
    r[i] = g[i] = b[i] = (i*255)/maxv;

  if (!raw) {
    numgot = 0;
    for (i=0, pix=pic; i<h; i++)
      for (j=0; j<w; j++, pix++)
	*pix = (getint(fp) >> bitshift);
  }

  else numgot = fread(pic, 1, w*h, fp);   /* read raw data */

  if (numgot != w*h) PBMerr(TRUNCSTR);

  if (garbage) {
    free(pic);
    return (PBMerr("Garbage characters in image data."));
  }

  return 0;
}


/*******************************************/
static int loadppm(fp, w, h, maxv, raw, nc)
FILE *fp;
int   w,h,maxv,raw,nc;
{
  byte *pix, *pic24, scale[256];
  int   i,j,bitshift;

  SetISTR(ISTR_FORMAT,"PPM, %s format.  (%ld bytes)", 
	  (raw) ? "raw" : "ascii", filesize);

  /* allocate 24-bit image */
  pic24 = (byte *) calloc(w*h*3,1);
  if (!pic24) FatalError("couldn't malloc 'pic24'");

  /* if maxv>255, keep dropping bits until it's reasonable */
  bitshift = 0;
  while (maxv>255) { maxv = maxv>>1;  bitshift++; }

  if (!raw) {
    numgot = 0;
    for (i=0, pix=pic24; i<h; i++)
      for (j=0; j<w*3; j++, pix++)
	*pix = (getint(fp) >> bitshift);
  }

  else numgot = fread(pic24, 1, w*h*3, fp);    /* read raw data */

  if (numgot != w*h*3) PBMerr(TRUNCSTR);

  if (garbage) {
    free(pic24);
    return(PBMerr("Garbage characters in image data."));
  }

  /* have to scale all RGB values up (Conv24to8 expects RGB values to
     range from 0-255 */

  if (maxv<255) { 
    for (i=0; i<=maxv; i++) scale[i] = (i * 255) / maxv;

    for (i=0, pix=pic24; i<h; i++) 
      for (j=0; j<w*3; j++, pix++) 
	*pix = scale[*pix];
  }

  i = Conv24to8(pic24,w,h,nc);
  free(pic24);
  return i;
}



/*******************************************/
static int getint(fp)
FILE *fp;
{
  int c, i;

  /* skip forward to start of next number */
  c = getc(fp);
  while (1) {
    /* eat comments */
    if (c=='#') {   /* if we're at a comment, read to end of line */
      while (c != '\n' && c != EOF) c=getc(fp);
    }

    if (c==EOF) return 0;
    if (c>='0' && c<='9') break;   /* we've found what we were looking for */

    /* see if we are getting garbage (non-whitespace) */
    if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=',') garbage=1;

    c = getc(fp);
  }


  /* we're at the start of a number, continue until we hit a non-number */
  i = 0;
  while (1) {
    i = (i*10) + (c - '0');
    c = getc(fp);
    if (c==EOF) return i;
    if (c<'0' || c>'9') break;
  }

  numgot++;
  return i;
}



/*******************************************/
static int getbit(fp)
FILE *fp;
{
  int c;

  /* skip forward to start of next number */
  c = getc(fp);
  while (1) {
    /* eat comments */
    if (c=='#') {   /* if we're at a comment, read to end of line */
      while (c != '\n' && c != EOF) c=getc(fp);
    }

    if (c==EOF) return 0;
    if (c=='0' || c=='1') break;   /* we've found what we were looking for */

    /* see if we are getting garbage (non-whitespace) */
    if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=',') garbage=1;

    c = getc(fp);
  }


  numgot++;
  return(c-'0');
}


/*******************************************/
static int PBMerr(st)
char *st;
{
  SetISTR(ISTR_WARNING,st);
  return 1;
}





/*******************************************/
int WritePBM(fp,pic,w,h,rmap,gmap,bmap,numcols,colorstyle,raw)
FILE *fp;
byte *pic;
int   w,h;
byte *rmap, *gmap, *bmap;
int   numcols, colorstyle, raw;
{
  /* writes a PBM/PGM/PPM file to the already open stream
     if (raw), writes as RAW bytes, otherwise writes as ASCII 
     'colorstyle' single-handedly determines the type of file written
     if colorstyle==0, (Full Color) a PPM file is written
     if colorstyle==1, (Greyscale)  a PGM file is written
     if colorstyle==2, (B/W stipple) a PBM file is written */

  int   magic;
  byte *pix;
  int   i,j,len;

  /* calc the appropriate magic number for this file type */
  magic = 0;
  if      (colorstyle==0) magic = 3;
  else if (colorstyle==1) magic = 2;
  else if (colorstyle==2) magic = 1;

  if (raw && magic) magic+=3;

  if (!magic) return(PBMerr("WritePBM: unknown file format"));

  /* write the header info */
  fprintf(fp,"P%d\n",magic);
  fprintf(fp,"# created by 'xv %s'\n", namelist[curname]);
  fprintf(fp,"%d %d\n",w,h);
  if (colorstyle!=2) fprintf(fp,"255\n");

  if (ferror(fp)) return -1;

  /* write the image data */

  if (colorstyle==0) {                  /* 24bit RGB, 3 bytes per pixel */
    for (i=0, pix=pic, len=0; i<h; i++)
      for (j=0; j<w; j++,pix++) {
	if (raw) {
	  putc(r[*pix],fp);  
	  putc(g[*pix],fp);  
	  putc(b[*pix],fp);
	}
	else {
	  fprintf(fp,"%3d %3d %3d ",r[*pix], g[*pix], b[*pix]);
	  len+=12;
	  if (len>58) { fprintf(fp,"\n");  len=0; }
	}
      }
  }

  else if (colorstyle==1) {             /* 8-bit greyscale */
    byte rgb[256];
    for (i=0; i<numcols; i++) rgb[i] = MONO(rmap[i],gmap[i],bmap[i]);
    for (i=0, pix=pic, len=0; i<w*h; i++,pix++) {
      if (raw) putc(rgb[*pix],fp);
      else {
	fprintf(fp,"%3d ",rgb[*pix]);
	len += 4;
	if (len>66) { fprintf(fp,"\n");  len=0; }
      }
    }
  }

  else if (colorstyle==2) {             /* 1-bit B/W stipple */
    int bit,k;
    for (i=0, pix=pic, len=0; i<h; i++) {
      for (j=0, bit=0, k=0; j<w; j++, pix++) {
	if (raw) {
	  k = (k << 1) | *pix;
	  bit++;
	  if (bit==8) {
	    fputc(~k,fp);
	    bit = k = 0;
	  }
	}
	else {
	  if (*pix) fprintf(fp,"0 ");
	       else fprintf(fp,"1 ");
	  len+=2;
	  if (len>68) { fprintf(fp,"\n"); len=0; }
	}
      } /* j */
      if (raw && bit) {
	k = k << (8-bit);
	fputc(~k,fp);
      }
    }
  }

  if (ferror(fp)) return -1;

  return 0;
}


	  
	  



\BARFOO\
else
  echo "will not over write ./xvpbm.c"
fi
if `test ! -s ./xvpm.c`
then
echo "writting ./xvpm.c"
cat > ./xvpm.c << '\BARFOO\'
/*
 * xvpm.c - load routine for 'pm' format pictures
 *
 * LoadPM(fname, numcols)  -  loads a PM pic, does 24to8 code if nec.
 * WritePM(fp, pic, w, h, r,g,b, numcols, style)
 * WriteRaw(fp, pic, w, h, r,g,b, numcols, style)
 */

/*
 * Copyright 1989, 1990 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any express or implied warranty.
 */


#include "xv.h"
#include "pm.h"

pmpic  thePic;

static int PMError();
static void flipl();

/*******************************************/
int LoadPM(fname,nc)
     char *fname;
     int   nc;
/*******************************************/
{
  FILE  *fp;
  int    isize,i,flipit,w,h,rv;

  rv = 0;
  thePic.pm_image = NULL;

  /* read in the PM picture */
  fp=fopen(fname,"r");
  if (!fp) return( PMError("unable to open file") );
  
  flipit = 0;
  fread(&thePic,PM_IOHDR_SIZE,1,fp);
  if (thePic.pm_id != PM_MAGICNO) {
    flipl( (byte *) &thePic.pm_id);
    if (thePic.pm_id == PM_MAGICNO) flipit = 1;
    else flipl( (byte *) &thePic.pm_id);
  }
  if (thePic.pm_id != PM_MAGICNO) return( PMError("not a PM file") );

  if (flipit) {
    flipl((byte *) &thePic.pm_np);      flipl((byte *) &thePic.pm_nrow);
    flipl((byte *) &thePic.pm_ncol);    flipl((byte *) &thePic.pm_nband);
    flipl((byte *) &thePic.pm_form);    flipl((byte *) &thePic.pm_cmtsize);
    }
          
  /* make sure that the input picture can be dealt with */
  if ( thePic.pm_nband!=1 || 
      (thePic.pm_form!=PM_I && thePic.pm_form!=PM_C) ||
      (thePic.pm_form==PM_I && thePic.pm_np>1) ||
      (thePic.pm_form==PM_C && (thePic.pm_np==2 || thePic.pm_np>4)) ) {
    fprintf(stderr,"PM picture not in a displayable format.\n");
    fprintf(stderr,"(ie, 1-plane PM_I, or 1-, 3-, or 4-plane PM_C)\n");
    return 1;
    }	

  w = thePic.pm_ncol;  h = thePic.pm_nrow;

  isize = pm_isize(&thePic);

  if (DEBUG) 
    fprintf(stderr,"%s: LoadPM() - loading a %dx%d %s pic, %d planes\n",
	    cmd, w, h, (thePic.pm_form==PM_I) ? "PM_I" : "PM_C", 
	    thePic.pm_np);

  SetISTR(ISTR_FORMAT,"PM, %s.  (%d plane %s)  (%d bytes)",
	  (thePic.pm_form==PM_I || thePic.pm_np>1) ? 
	     "24-bit color" : "8-bit greyscale",
	  thePic.pm_np, (thePic.pm_form==PM_I) ? "PM_I" : "PM_C",
	  isize + PM_IOHDR_SIZE + thePic.pm_cmtsize);

  /* allocate memory for picture and read it in */
  thePic.pm_image = (char *) malloc(isize);
  if (thePic.pm_image == NULL) 
    return( PMError("unable to malloc PM picture") );

  if (fread(thePic.pm_image, (unsigned) isize, 1, fp) != 1) 
    return( PMError("file read error") );
  if (fp!=stdin) fclose(fp);

  if (DEBUG) fprintf(stderr,"loadpm 1\n");

  /* convert PM picture to 'pic' (8 bit) format */
  if (thePic.pm_form == PM_I) {
    int  *intptr;
    byte *pic24, *picptr;

    if ((pic24 = (byte *) malloc(w*h*3))==NULL) 
      return( PMError("unable to malloc 24-bit picture") );
      
    intptr = (int *) thePic.pm_image;
    picptr = pic24;

    if (flipit) {    /* if flipit, integer is RRGGBBAA instead of AABBGGRR */
      for (i=w*h; i>0; i--, intptr++) {
	*picptr++ = (*intptr>>24) & 0xff;
	*picptr++ = (*intptr>>16) & 0xff;
	*picptr++ = (*intptr>>8)  & 0xff;
      }
    }
    else {
      for (i=w*h; i>0; i--, intptr++) {
	*picptr++ = (*intptr)     & 0xff;
	*picptr++ = (*intptr>>8)  & 0xff;
	*picptr++ = (*intptr>>16) & 0xff;
      }
    }

    if (DEBUG) fprintf(stderr,"loadpm 2\n");

    free(thePic.pm_image);
    rv=Conv24to8(pic24,w,h,nc);
    free(pic24);
  }


  else if (thePic.pm_form == PM_C && thePic.pm_np>1) {
    byte *pic24, *picptr, *rptr, *gptr, *bptr;

    if ((pic24 = (byte *) malloc(w*h*3))==NULL) 
      return( PMError("unable to malloc 24-bit picture") );

    rptr = (byte *) thePic.pm_image;
    gptr = rptr + w*h;
    bptr = rptr + w*h*2;
    picptr = pic24;
    for (i=w*h; i>0; i--) {
      *picptr++ = *rptr++;
      *picptr++ = *gptr++;
      *picptr++ = *bptr++;
    }
    free(thePic.pm_image);
    rv=Conv24to8(pic24,w,h,nc);
    free(pic24);
  }
  
  else if (thePic.pm_form == PM_C && thePic.pm_np==1) {
    /* don't have to convert, just point pic at thePic.pm_image */
    pic = (byte *) thePic.pm_image;
    pWIDE = w;  pHIGH = h;  
    for (i=0; i<256; i++) r[i]=g[i]=b[i]=i;  /* and build mono colortable */
    rv = 0;
  }

  return rv;
}


/*******************************************/
int WritePM(fp, pic, w, h, rmap, gmap, bmap, numcols, colorstyle)
FILE *fp;
byte *pic;
int   w,h;
byte *rmap, *gmap, *bmap;
int   numcols, colorstyle;
{
  /* writes a PM file to the already open stream
     'colorstyle' single-handedly determines the type of PM pic written
     if colorstyle==0, (Full Color) a 3-plane PM_C pic is written
     if colorstyle==1, (Greyscal) a 1-plane PM_C pic is written
     if colorstyle==0, (B/W stipple) a 1-plane PM_C pic is written */

  char  foo[256];
  int   i;
  byte *p;

  /* create 'comment' field */
  sprintf(foo,"created by 'xv %s'\n", namelist[curname]);

  /* fill in fields of a pmheader */
  thePic.pm_id = PM_MAGICNO;
  thePic.pm_np = (colorstyle==0) ? 3 : 1;
  thePic.pm_ncol = w;
  thePic.pm_nrow = h;
  thePic.pm_nband = 1;
  thePic.pm_form  = PM_C;
  thePic.pm_cmtsize = strlen(foo);

  if (fwrite(&thePic, PM_IOHDR_SIZE, 1, fp) != 1) return -1;

  /* write the picture data */
  if (colorstyle == 0) {         /* 24bit RGB, organized as 3 8bit planes */
    for (i=0,p=pic; i<w*h; i++, p++)
      putc(rmap[*p], fp);
    for (i=0,p=pic; i<w*h; i++, p++)
      putc(gmap[*p], fp);
    for (i=0,p=pic; i<w*h; i++, p++)
      putc(bmap[*p], fp);
  }

  else if (colorstyle == 1) {    /* GreyScale: 8 bits per pixel */
    byte rgb[256];
    for (i=0; i<numcols; i++) rgb[i] = MONO(rmap[i],gmap[i],bmap[i]);
    for (i=0, p=pic; i<w*h; i++, p++)
      putc(rgb[*p],fp);
  }

  else /* (colorstyle == 2) */ { /* B/W stipple.  pic is 1's and 0's */
    for (i=0, p=pic; i<w*h; i++, p++)
      putc(*p ? 255 : 0,fp);
  }

  if (fputs(foo,fp)==EOF) return -1;

  return 0;
}


/*****************************/
static int PMError(st)
char *st;
{
  SetISTR(ISTR_WARNING,"LoadPM() - %s",cmd,st);
  Warning();
  if (thePic.pm_image != NULL) free(thePic.pm_image);
  return -1;
}


/*****************************/
static void flipl(p)
     byte *p;
{
  byte t; 
  t = p[0];  p[0]=p[3];  p[3] = t;
  t = p[1];  p[1]=p[2];  p[2] = t;
}



\BARFOO\
else
  echo "will not over write ./xvpm.c"
fi
if `test ! -s ./xvscrl.c`
then
echo "writting ./xvscrl.c"
cat > ./xvscrl.c << '\BARFOO\'
/* 
 * xvscrl.c - Scroll Bar handling functions
 *
 * callable functions:
 *
 *   SCCreate()   -  creates the Scroll Bar window.
 *   SCSetRange() -  sets min/max/current values of control
 *   SCSetVal()   -  sets value of control 
 *   SCRedraw()   -  redraws scroll bar
 *   SCTrack()    -  called when clicked.  Operates control 'til mouseup
 */

/*
 * Copyright 1989, 1990 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any express or implied warranty.
 */


#include "xv.h"
#include "bitmaps.h"


static Pixmap upPix,  downPix;   /* up/down arrows */
static Pixmap up1Pix, down1Pix;  /* up/down arrows (lit up) */
static Pixmap sgray;             /* gray stipple for lit scrollbar */
static int    pixmaps_built=0;   /* true if pixmaps created already */


/* scroll regions */
#define UPLINE 0
#define UPPAGE 1
#define DNLINE 2
#define DNPAGE 3
#define THUMB  4

#define SCRLWAIT 150   /* milliseconds to wait between scrolls */

/* local functions */
#ifdef __STDC__
static int  whereInScrl(SCRL *, int, int);
static void drawArrow(SCRL *, int);
#else
static int  whereInScrl();
static void drawArrow();
#endif


/***************************************************/
void SCCreate(sp, parent, x, y, vert, len, minv, maxv, curv, page, 
	          fg, bg, func)
SCRL         *sp;
Window        parent;
int           x,y,vert,len,minv,maxv,curv,page;
unsigned long fg,bg;
void          (*func)();
{


  if (!pixmaps_built) {
    upPix    = XCreatePixmapFromBitmapData(theDisp, parent, 
		up_bits, up_width, up_height, fg, bg, dispDEEP);
    downPix  = XCreatePixmapFromBitmapData(theDisp, parent, 
	        down_bits, down_width, down_height, fg, bg, dispDEEP);
    up1Pix   = XCreatePixmapFromBitmapData(theDisp, parent, 
                up1_bits, up1_width, up1_height, fg, bg, dispDEEP);
    down1Pix = XCreatePixmapFromBitmapData(theDisp, parent, 
	        down1_bits, down1_width, down1_height,fg,bg,dispDEEP);
    sgray    = XCreatePixmapFromBitmapData(theDisp, parent,
	        scrlgray_bits, scrlgray_width, scrlgray_height,fg,bg,dispDEEP);
  }

  sp->vert = vert;
  sp->len  = len;
  sp->fg   = fg;
  sp->bg   = bg;
  sp->uplit = sp->dnlit = 0;

  if (vert) 
    sp->win = XCreateSimpleWindow(theDisp, parent,x,y,up_width-2,len,1,fg,bg);
  else FatalError("don't know HOW to make horizontal scrollbar");

  if (!sp->win) FatalError("can't create scrollbar window");

  sp->tsize  =  up_width-2;      /* really only if vertical */
  sp->tmin   =  up_height-1;
  sp->tmax   =  len - (up_height-1) - sp->tsize;
  sp->drawobj = func;

  SCSetRange(sp, minv, maxv, curv, page);
  XSelectInput(theDisp, sp->win, ExposureMask | ButtonPressMask);
}


/***************************************************/
void SCSetRange(sp, minv, maxv, curv, page)
SCRL *sp;
int   minv, maxv, curv, page;
{
  if (maxv<minv) maxv=minv;
  sp->min = minv;    sp->max = maxv;    sp->page = page;
  sp->active =  (minv < maxv);

  /* adjust scroll bar background */
  if (sp->active) XSetWindowBackgroundPixmap(theDisp, sp->win, sgray);
             else XSetWindowBackground(theDisp, sp->win, sp->bg);

  SCSetVal(sp, curv);
}


/***************************************************/
void SCSetVal(sp, curv)
SCRL *sp;
int   curv;
{
  RANGE(curv, sp->min, sp->max);   /* make sure curv is in-range */
  sp->val = curv;

  if (sp->active) 
    sp->tpos = sp->tmin + ((sp->tmax - sp->tmin)*(curv - sp->min))
                        / (sp->max - sp->min);
  SCRedraw(sp);
  (sp->drawobj)();     /* redraw whatever the scrollbar controls */
  XFlush(theDisp);
}


/***************************************************/
void SCRedraw(sp)
SCRL *sp;
{
  XSetForeground(theDisp, theGC, sp->fg);
  XSetBackground(theDisp, theGC, sp->bg);

  XClearWindow(theDisp, sp->win);
  
  if (sp->vert) {    /* draw up/down arrows */
    drawArrow(sp,UPLINE);
    drawArrow(sp,DNLINE);

    if (sp->active) {   /* a thumb is necessary */
      XSetForeground(theDisp, theGC, sp->bg);
      XFillRectangle(theDisp, sp->win, theGC,
		     1, sp->tpos+1, sp->tsize-2, sp->tsize-2);
      XSetForeground(theDisp, theGC, sp->fg);
      XDrawRectangle(theDisp, sp->win, theGC,
		     0, sp->tpos, sp->tsize-1, sp->tsize-1);
    }
  }
}



/***************************************************/
static int whereInScrl(sp,x,y)
SCRL *sp;
int x,y;
{
  int v;

  /* returns region # that x,y is in.  Returns '-1' if none */

  v=0;
  if (sp->vert) {
    if (x<0 || x>up_width-2 || y<0 || y>sp->len) return -1;
    v = y;
  }

  /* once we know it's in scroll bar, only have to check 'v' versus len */
  if (v < sp->tmin)               return UPLINE;
  if (sp->active) {
    if (v <  sp->tpos)             return UPPAGE;
    if (v <  sp->tpos + sp->tsize) return THUMB;
    if (v <= sp->tmax + sp->tsize) return DNPAGE;
  }
  if (v > sp->tmax+sp->tsize)    return DNLINE;

  return -1;
}


/***************************************************/
static void drawArrow(sp,arr)
SCRL *sp;
int arr;
{
  /* only if vertical */
  if (arr == UPLINE) {
    if (sp->uplit) 
      XCopyArea(theDisp, up1Pix,  sp->win,theGC,0,0,up_width,up_height,-1,-1);
    else
      XCopyArea(theDisp, upPix,   sp->win,theGC,0,0,up_width,up_height,-1,-1);
  }

  else if (arr == DNLINE) {
    if (sp->dnlit) 
      XCopyArea(theDisp, down1Pix,sp->win,theGC,0,0,up_width,up_height,
		-1, sp->len-(up_height-1));
    else
      XCopyArea(theDisp, downPix, sp->win,theGC,0,0,up_width,up_height,
		-1, sp->len-(up_height-1));
  }

  XFlush(theDisp);
}


/***************************************************/
void SCTrack(sp,mx,my)
SCRL *sp;
int mx,my;
{
  Window       rW,cW;
  int          rx,ry, x,y, ipos, pos, lit, ty, tyoff, ty1;
  unsigned int mask;

  /* determine in which of the five regions of the scroll bar the mouse
     was clicked (upline, downline, uppage, downpage, thumb) */

  ty = tyoff = 0;

  XSetForeground(theDisp, theGC, sp->fg);
  XSetBackground(theDisp, theGC, sp->bg);

  /* light up appropriate bit of scroll bar */
  ipos = whereInScrl(sp,mx,my);
  lit = 1;

  switch (ipos) {
  case UPLINE:  sp->uplit = 1;
                if (sp->val > sp->min) SCSetVal(sp,sp->val-1);                
                Timer(SCRLWAIT);
                break;

  case DNLINE:  sp->dnlit = 1;
                if (sp->val < sp->max) SCSetVal(sp,sp->val+1);
                Timer(SCRLWAIT);
                break;

  case UPPAGE:  SCSetVal(sp,sp->val - sp->page);  break;
  case DNPAGE:  SCSetVal(sp,sp->val + sp->page);  break;
  case THUMB:   tyoff = sp->tpos - my;
                ty = sp->tpos;
                XSetState(theDisp, theGC, sp->fg, sp->bg, GXinvert, 
			  sp->fg ^ sp->bg);
                XDrawRectangle(theDisp,sp->win,theGC,
			       0, sp->tpos, sp->tsize-1, sp->tsize-1);
                break;
  }

  /* VERTICAL CODE ONLY */
  while (XQueryPointer(theDisp,sp->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
    if (!(mask & Button1Mask)) break;    /* button released */

    switch (ipos) {

    case THUMB:
      /* do thumb tracking */
      if (x<-16 || x>16+sp->tsize) {   /* outside tracking range */
	if (lit) {
	  lit = 0;
	  XDrawRectangle(theDisp,sp->win,theGC,0,ty,sp->tsize-1,sp->tsize-1);
	}
      }

      else {                           /* inside tracking range */
	if (!lit) {  /* not lit, just turn on */
	  lit = 1;
	  ty = y + tyoff;
	  RANGE(ty, sp->tmin, sp->tmax);
	  XDrawRectangle(theDisp,sp->win,theGC,0,ty,sp->tsize-1,sp->tsize-1);
	}
	else { /* already lit, more the thumb */
	  ty1 = y+tyoff;
	  RANGE(ty1, sp->tmin, sp->tmax);
	  if (ty != ty1) {    /* but only if mouse has moved */
	    XDrawRectangle(theDisp, sp->win, theGC, 
			   0,ty,sp->tsize-1,sp->tsize-1);
	    ty = ty1;
	    XDrawRectangle(theDisp, sp->win, theGC, 
			   0,ty,sp->tsize-1,sp->tsize-1);
	  }
	}
      }
      break;


    case UPLINE:
    case DNLINE:                     /* arrows */
      pos = whereInScrl(sp,x,y);
      if (pos == ipos) {
	if (!lit) { 
	  lit = 1; 
	  if (ipos == UPLINE) { sp->uplit = 1;  drawArrow(sp,UPLINE); }
	                 else { sp->dnlit = 1;  drawArrow(sp,DNLINE); }
	}

	else {
	  if (sp->val > sp->min && pos==UPLINE) {
	    SCSetVal(sp, sp->val-1);
	    Timer(SCRLWAIT);
	  }
	  else if (sp->val < sp->max && pos==DNLINE) {
	    SCSetVal(sp, sp->val+1);
	    Timer(SCRLWAIT);
	  }
	}
      }
      
      else {
	if (lit) { 
	  lit = 0; 
	  if (ipos == UPLINE) { sp->uplit = 0;  drawArrow(sp,UPLINE); }
	                 else { sp->dnlit = 0;  drawArrow(sp,DNLINE); }
	}
      }
      break;
      
    }
  }


  if (ipos == THUMB) {
    if (lit)    /* turn off */
      XDrawRectangle(theDisp,sp->win,theGC,0,ty,sp->tsize-1,sp->tsize-1);

    XSetState(theDisp, theGC, sp->fg, sp->bg, GXcopy, AllPlanes);

    if (lit && ty != sp->tpos) {    /* if thumb was moved, ROUND to new val */
      int dt, dv;
      dt = sp->tmax - sp->tmin;
      dv = sp->max  - sp->min;
      SCSetVal(sp, sp->min + (dv*(ty - sp->tmin)+dt/2) / dt);
    }
  }

  if (lit && ipos == UPLINE) { sp->uplit = 0; drawArrow(sp, UPLINE); }
  if (lit && ipos == DNLINE) { sp->dnlit = 0; drawArrow(sp, DNLINE); }
}




\BARFOO\
else
  echo "will not over write ./xvscrl.c"
fi
if `test ! -s ./xvxbm.c`
then
echo "writting ./xvxbm.c"
cat > ./xvxbm.c << '\BARFOO\'
/*
 * xvxbm.c - load routine for X11 Bitmap format pictures
 *
 * LoadXBM(fname)  -  loads an X11 Bitmap file\
 * WriteXBM(fp, pic, w, h)
 */

/*
 * Copyright 1989, 1990 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any express or implied warranty.
 */


#include "xv.h"



/*
 * File Format:
 *   (format identifier:  "#define" as first couple chars in file)
 *
 * looks for first line beginning with '#define'
 *   reads "#define identifier width"  (identifier is ignored)
 * looks for next line beginning with '#define'
 *   reads "#define identifier height" (identifier is ignored)
 * looks for next occurence of characters '0x'
 *   read next two chars as two hex digits
 *   move forward to next occurence of '0x'
 *   repeat
 */
 

static int XBMError();


/*******************************************/
int LoadXBM(fname,nc)
     char *fname;
     int   nc;
/*******************************************/
{
  FILE  *fp;
  int    c, c1;
  int    i, j, k, bit, w, h;
  byte  *pix;
  long   filesize;
  char   line[256];
  byte   hex[256];


  fp=fopen(fname,"r");
  if (!fp) return 1;

  /* figure out the file size (for Informational Purposes Only) */
  fseek(fp, 0L, 2);
  filesize = ftell(fp);
  fseek(fp, 0L, 0);


  /* read width:  skip lines until we hit a #define */
  while (1) {
    if (!fgets(line,256,fp)) 
      return(XBMError("EOF reached in header info."));

    if (strncmp(line,"#define",7)==0) {
      if (sscanf(line,"#define %*s %d", &w) != 1) 
	return(XBMError("Unable to read 'width'"));
      else break;
    }
  }


  /* read height:  skip lines until we hit another #define */
  while (1) {
    if (!fgets(line,256,fp)) 
      return(XBMError("EOF reached in header info."));

    if (strncmp(line,"#define",7)==0) {
      if (sscanf(line,"#define %*s %d", &h) != 1) 
	return(XBMError("Unable to read 'height'"));
      else break;
    }
  }



  /* scan forward until we see the first '0x' */
  c = getc(fp);  c1 = getc(fp);
  while (c1!=EOF && !(c=='0' && c1=='x') ) { c = c1;  c1 = getc(fp); }

  if (c1==EOF) 
    return(XBMError("No bitmap data found"));


  /* load up the stuff XV expects us to load up */

  SetISTR(ISTR_FORMAT,"X11 Bitmap  (%ld bytes)", filesize);

  pic = (byte *) calloc(w*h,1);
  if (!pic) FatalError("couldn't malloc 'pic'");

  pWIDE = w;  pHIGH = h;

  /* B/W bitmaps have a two entry colormap */
  r[0] = g[0] = b[0] = 255;     /* 0 = white */
  r[1] = g[1] = b[1] = 0;       /* 1 = black */


  /* initialize the 'hex' array for zippy ASCII-hex -> int conversion */

  for (i=0; i<256; i++) hex[i]=0;
  for (i='0'; i<='9'; i++) hex[i] = i - '0';
  for (i='a'; i<='f'; i++) hex[i] = i + 10 - 'a';
  for (i='A'; i<='F'; i++) hex[i] = i + 10 - 'A';

  /* read/convert the image data */

  for (i=0, pix=pic; i<h; i++)
    for (j=0,bit=0; j<w; j++, pix++, bit = ++bit&7) {

      if (!bit) {
	/* get next byte from file.  we're already positioned at it */
	c = getc(fp);  c1 = getc(fp);
	if (c<0 || c1<0) { 
	  /* EOF: break out of loop */	  
	  c=c1='0'; i=h; j=w;
	  XBMError("The file would appear to be truncated.");
	}

	k = (hex[c] << 4) + hex[c1];

	/* advance to next '0x' */
	c = getc(fp);  c1 = getc(fp);
	while (c1!=EOF && !(c=='0' && c1=='x') ) { c = c1;  c1 = getc(fp); }
      }

      *pix = (k&1) ? 1 : 0;
      k = k >> 1;
    }

  fclose(fp);

  return 0;
}  



/*******************************************/
static int XBMError(st)
char *st;
{
  SetISTR(ISTR_WARNING,st);
  return 1;
}


/*******************************************/
int WriteXBM(fp, pic, w, h, fname)
FILE *fp;
byte *pic;
int   w,h;
char *fname;
{
  /* pic is expected to be an array of w*h bytes.  '0' is considered 'black'
     non-zero is considered white.  Some sort of stippling algorithm should've
     been called already to produce pic, otherwise the output won't be at all
     useful */

  int   i,j,k,bit,len,nbytes;
  byte *pix;
  char name[256], *foo;

  /* figure out a reasonable basename */
  strcpy(name,fname);
  foo = strchr(name,'.');
  if (foo) *foo='\0';                 /* truncated name at first '.' */

  fprintf(fp,"#define %s_width %d\n",name,w);  
  fprintf(fp,"#define %s_height %d\n",name,h);
  fprintf(fp,"static char %s_bits[] = {\n",name);

  fprintf(fp," ");

  nbytes = h * ((w+7)/8);   /* # of bytes to write */

  for (i=0, len=1, pix=pic; i<h; i++) {
    for (j=bit=k=0; j<w; j++,pix++) {
      k = (k>>1);
      if (*pix) k |= 0x80;
      bit++;
      if (bit==8) {
	fprintf(fp,"0x%02x",(byte) ~k);
	nbytes--;  len += 4;
	if (nbytes) { fprintf(fp,",");  len++; }
	if (len>72) { fprintf(fp,"\n ");  len=1; }
	bit = k = 0;
      }
    }

    if (bit) {
      k = k >> (8-bit);
      fprintf(fp,"0x%02x",(byte) ~k);
      nbytes--;  len += 4;
      if (nbytes) { fprintf(fp,",");  len++; }
      if (len>72) { fprintf(fp,"\n ");  len=1; }
    }
  }

  fprintf(fp,"};\n");

  if (ferror(fp)) return -1;
  return 0;
}
\BARFOO\
else
  echo "will not over write ./xvxbm.c"
fi
if `test ! -s ./Makefile`
then
echo "writting ./Makefile"
cat > ./Makefile << '\BARFOO\'
# Makefile for xv
#

# your C compiler of choice
CC = cc

# optimization/debugging options for your C compiler
# Note:  If you are running on a POSIX-compatible machine, such as an
#        IBM RS6000, you MAY need to add '-DDIRENT' to CFLAGS.  To determine
#        if this is the case, do a 'man readdir' on your machine.  If
#        readdir() returns a pointer to 'struct direct', you will not have
#        to change anything.  If, however, readdir() returns a pointer to
#        'struct dirent', you will have to add the '-DDIRENT' to CFLAGS
CFLAGS = -O


LIBS = -lX11 -lm

BITMAPS = bitmaps/grasp bitmaps/penn bitmaps/down bitmaps/down1 \
	  bitmaps/up bitmaps/up1 bitmaps/scrlgray bitmaps/gray50 \
	  bitmaps/gray25 bitmaps/i_fifo bitmaps/i_chr bitmaps/i_dir \
	  bitmaps/i_blk bitmaps/i_lnk bitmaps/i_sock bitmaps/i_reg \
	  bitmaps/rb_off bitmaps/rb_on bitmaps/rb_off1 bitmaps/rb_on1 \
	  bitmaps/fc_left bitmaps/fc_leftm bitmaps/fc_mid bitmaps/fc_midm \
	  bitmaps/fc_right bitmaps/fc_rightm bitmaps/fc_left1 \
	  bitmaps/fc_left1m bitmaps/fc_right1 bitmaps/fc_right1m

OBJS = 	xv.o xvmisc.o xv24to8.o xvgif.o xvpm.o xvinfo.o xvctrl.o xvscrl.o \
	xvgifwr.o xvdir.o xvbutt.o xvpbm.o xvxbm.o xvgam.o xvfish.o

MISC = README

.c.o:	; $(CC) -c $(CFLAGS) -o $@ $*.c

all: xv bggen

xv: $(OBJS)
	$(CC) $(CFLAGS) -o xv $(OBJS) $(LIBS)

bggen: bggen.c
	$(CC) $(CFLAGS) -o bggen bggen.c
	
clean:
	rm -f $(OBJS)

tar:
	tar cf xv.tar Makefile *.c *.h bitmaps docs $(MISC)

xv.3100: bitmaps.h
	cc -O3 *.c -o xv $(XLIB)

$(OBJS):   xv.h
xvmisc.o:  bitmaps.h
xvinfo.o:  bitmaps.h
xvctrl.o:  bitmaps.h
xvscrl.o:  bitmaps.h
xvbutt.o:  bitmaps.h

bitmaps.h: $(BITMAPS)
	cat $(BITMAPS) > bitmaps.h





\BARFOO\
else
  echo "will not over write ./Makefile"
fi
if `test ! -s ./xv.h`
then
echo "writting ./xv.h"
cat > ./xv.h << '\BARFOO\'
/*
 *  xv.h  -  header file for xv, but you probably guessed as much
 */

/*
 * Copyright 1989, 1990 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any express or implied warranty.
 */

#define REVDATE   "Rev: 10/9/90"


/* include files */
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <string.h>
#include <memory.h>             /* for 'memset()' prototype */
extern int   errno;             /* this SHOULD be in errno.h */
extern char *sys_errlist[];     /* this SHOULD be in errno.h */


#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>

#ifndef ibm032			/* IBM RT 4.3 doesn't have malloc.h */
#include <malloc.h>
#endif

#ifdef NEEDSTIME
#include <sys/types.h>
#include <sys/timeb.h>
#include <signal.h>
#ifndef  sigmask
#define  sigmask(m)      (1 << ((m)-1))
#endif
#endif

#ifdef NEEDSDIR
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/param.h>
#include <sys/stat.h>
#ifdef DIRENT
#include <dirent.h>
#endif
#endif

#ifdef NEEDSVARARGS
#include <varargs.h>
#endif


#define UNCOMPRESS "/usr/ucb/uncompress"   /* for uncompressing .Z files */

#define PROGNAME  "xv"             /* used in resource database */

#define DEFINFOGEOM "-10+10"       /* default position of info window */
#define DEFDIRGEOM  "-10-10"       /* default position of directory window */
#define DEFCTRLGEOM "+400+400"     /* default position of ctrl window */
#define DEFGAMGEOM  "+10-10"       /* default position of gamma window */

#define INFOWIDE 500               /* (fixed) size of info window */
#define INFOHIGH 250

#define CTRLWIDE 440               /* (fixed) size of control window */
#define CTRLHIGH 265

#define DIRWIDE  300               /* (fixed) size of directory window */
#define DIRHIGH  420

#define GAMWIDE  366               /* (fixed) size of Gamma window */
#define GAMHIGH  356

#define MAXNAMES 1024   /* max # of files (more than this?  Get REAL!)

/* strings in the INFOBOX (used in SetISTR and GetISTR) */
#define NISTR         9    /* number of ISTRs */
#define ISTR_INFO     0
#define ISTR_WARNING  1
#define ISTR_FILENAME 2
#define ISTR_FORMAT   3
#define ISTR_RES      4
#define ISTR_CROP     5
#define ISTR_EXPAND   6
#define ISTR_COLOR    7
#define ISTR_COLOR2   8

/* potential values of 'infomode', used in info box drawing routines */
#define INF_NONE 0    /* empty box */
#define INF_STR  1    /* just ISTR_INFO */
#define INF_PART 2    /* filename, format, size and infostr */
#define INF_FULL 3    /* INF_PART + clipping, expansion, colorinfo */


/* buttons in the ctrl window */
#define NBUTTS  17
#define BNEXT   0
#define BPREV   1
#define BCROP   2
#define BUNCROP 3
#define BNORM   4
#define BMAX    5
#define BUP2    6
#define BDN2    7
#define BUP10   8
#define BDN10   9
#define BQUIT   10
#define B4BY3   11
#define BSAVE   12
#define BROTATE 13
#define BINFO   14
#define BGAMMA  15
#define BASPECT 16


/* buttons in the 'save' window */
#define S_NBUTTS 4
#define S_BOPEN  0
#define S_BSAVE  1
#define S_BCANC  2
#define S_BQUIT  3


/* buttons in the 'gamma' window */
#define G_NBUTTS  17
#define G_BAPPLY  0
#define G_BNOGAM  1
#define G_BRESET  2
#define G_BDEF    3
#define G_BGTYPE  4
#define G_BCLOSE  5
#define G_BUP_BR  6
#define G_BDN_BR  7
#define G_BUP_CN  8
#define G_BDN_CN  9
#define G_BHSVRGB 10
#define G_B1      11
#define G_B2      12
#define G_B3      13
#define G_B4      14
#define G_BSET    15
#define G_BUNDO   16


/* definitions of first char of dirnames[i] (filetype) */
#define C_FIFO  'f'    /* FIFO special file */
#define C_CHR   'c'    /* character special file */
#define C_DIR   'd'    /* directory */
#define C_BLK   'b'    /* block special file */
#define C_LNK   'l'    /* symbolic link */
#define C_SOCK  's'    /* socket */
#define C_REG   ' '    /* regular file */


/* random string-placing definitions */
#define SPACING 3      /* vertical space between strings */
#define ASCENT   (mfinfo->ascent)
#define DESCENT  (mfinfo->descent)
#define CHIGH    (ASCENT + DESCENT)
#define LINEHIGH (CHIGH + SPACING)


#define STDINSTR "<stdin>"


#ifndef MAIN
#define WHERE extern
#else
#define WHERE
#endif

typedef unsigned char byte;

typedef struct { Window win;            /* window ID */
		 int len;               /* length of major axis */
		 int vert;              /* true if vertical, else horizontal */
		 int active;            /* true if scroll bar can do anything*/
		 int min,max;           /* min/max values 'pos' can take */
		 int val;               /* 'value' of scrollbar */
		 int page;              /* amt val change on pageup/pagedown */
		 int tpos;              /* thumb pos. (pixels from tmin) */
		 int tmin,tmax;         /* min/max thumb offsets (from 0,0) */
		 int tsize;             /* size of thumb (in pixels) */
		 unsigned long fg,bg;   /* colors */
		 void (*drawobj)();     /* redraws obj controlled by scrl*/
		 int uplit, dnlit;      /* true if up&down arrows are lit */
	       } SCRL;

typedef struct { Window win;            /* parent window */
		 int x,y,w,h;           /* size of button rectangle */
		 int lit;               /* if true, invert colors */
		 int active;            /* if false, stipple gray */
		 int toggle;            /* if true, clicking toggles state */
		 unsigned long fg,bg;   /* colors */
		 char *str;             /* string in button */
	       } BUTT;


typedef struct { Window win;            /* window */
		 int x,y,w,h;           /* size of window */
		 unsigned long fg,bg;   /* colors */
		 char **str;            /* ptr to list of strings */
		 int   nstr;            /* number of strings */
		 int   selected;        /* number of 'selected' string */
		 int   nlines;          /* number of lines shown at once */
		 SCRL  scrl;            /* scrollbar that controls list */
		 int   filetypes;       /* true if filetype icons to be drawn*/
		 int   dirsonly;        /* if true, only dirs selectable */
	       } LIST;


typedef struct rbutt { Window        win;      /* parent window */
		       int           x,y;      /* position in parent */
		       char         *str;      /* the message string */
		       int           selected; /* selected or not */
		       int           active;   /* selectable? */
		       struct rbutt *next;     /* pointer to next in group */
		       unsigned long fg,bg;    /* colors */
		     } RBUTT;

/* MACROS */
#define CENTERX(f,x,str) ((x)-XTextWidth(f,str,strlen(str))/2)
#define CENTERY(f,y) ((y)-((f->ascent+f->descent)/2)+f->ascent)

/* RANGE forces a to be in the range b..c (inclusive) */
#define RANGE(a,b,c) { if (a<b) a=b;  if (a>c) a=c; }

/* PTINRECT returns '1' if x,y is in rect (inclusive) */
#define PTINRECT(x,y,rx,ry,rw,rh) \
           ((x)>=(rx) && (y)>=(ry) && (x)<=(rx)+(rw) && (y)<=(ry)+(rh))

/* MONO returns total intensity of r,g,b components */
#define MONO(rd,gn,bl) (((rd)*11 + (gn)*16 + (bl)*5) >> 5)  /*.33R+ .5G+ .17B*/



/* X stuff */
WHERE Display       *theDisp;
WHERE int           theScreen;
WHERE unsigned int  ncells, dispWIDE, dispHIGH, dispDEEP;
WHERE Colormap      theCmap, LocalCmap;
WHERE Window        rootW, mainW;
WHERE GC            theGC;
WHERE unsigned long black, white, fg, bg, infofg, infobg;
WHERE Font          mfont, monofont;
WHERE XFontStruct   *mfinfo, *monofinfo;
WHERE Visual        *theVisual;
WHERE Cursor        arrow, cross;

/* global vars used by LOAD routines */
WHERE byte          *pic;                   /* ptr to loaded picture */
WHERE unsigned int   pWIDE,pHIGH;           /* size of 'pic' */
WHERE byte           r[256],g[256],b[256];  /* colormap */
WHERE char          *cmd;                   /* program name for printf's */
WHERE int            DEBUG;                 /* print debugging info */
WHERE int            mono;                  /* true if displaying grayscale */


/* more global variables, used by xv and xvmisc */
WHERE byte          *cpic;         /* cropped version of pic */
WHERE unsigned int  cWIDE, cHIGH,  /* size of cropped region */
                    cXOFF, cYOFF;  /* offset of region from 0,0 of pic */

WHERE byte          *epic;         /* expanded version of cpic */
                                   /* points to pic when at 1:1 expansion */
                                   /* this is converted to 'theImage' */
WHERE unsigned int  eWIDE, eHIGH;  /* size of epic */
WHERE unsigned int  normFact;      /* factor to shrink picture by for 'norm' */

WHERE byte           rorg[256],gorg[256],borg[256];  /* ORIGINAL colormap */
WHERE byte           gamcr[256];   /* gamma correction curve */
WHERE byte           fsgamcr[256]; /* gamma correction curve (for FS dither) */


WHERE XImage        *theImage;     /* X version of epic */


WHERE unsigned long freecols[256]; /* list of pixel values to free */
WHERE int           nfcols;        /* number of colors to free */
WHERE unsigned long cols[256];     /* maps pic pixel values to X pixel vals */
WHERE int           fc2pcol[256];  /* maps freecols into pic pixel values */
WHERE int           numcols;       /* # of desired colors in picture */
WHERE int           ncols;         /* max # of (different) colors to alloc */

WHERE char          str[128];      /* dummy string used for error messages */

WHERE int           expand,        /* expansion amount */
                    bwidth,        /* border width of created windows */
                    noglob,        /* force to only use colors it alloced */
                    revvideo,      /* reverse video */
                    perfect,       /* perfect color.  install own colormap */
                    fixedaspect,   /* fixed aspect ratio */
                    slow24,        /* use slow 24to8 algorithm */
                    ninstall,      /* true if using icccm-complaint WM
				      (a WM that will does install CMaps */
                    useroot,       /* true if we should draw in rootW */
                    noqcheck,      /* true if we should NOT do QuickCheck */
                    rwcolor,       /* true if we should use R/W color cells */
                    rwthistime,    /* true if we DID use R/W color cells */
                    fish,          /* turn on annoying fish */
                    fishrunning;   /* true if fish are in operation */

WHERE float         defaspect,     /* default aspect ratio to use */
                    normaspect;    /* normal aspect ratio of this picture */

WHERE int           crx1, cry1,    /* dimensions of cropping rectangle */
                    crx2, cry2;



/* stuff used for 'info' box */
WHERE Window        infoW;
WHERE int           infoUp;       /* boolean:  whether infobox is visible */
WHERE int           infoMode;


/* stuff used for 'ctrl' box */
WHERE Window        ctrlW;
WHERE int           ctrlUp;       /* boolean:  whether ctrlbox is visible */
WHERE char         *namelist[MAXNAMES];  /* list of file names from argv */
WHERE char         *dispnames[MAXNAMES]; /* truncated names shown in listbox */
WHERE int           numnames, curname;
WHERE LIST          nList;
WHERE BUTT          but[NBUTTS];         /* command buttons in ctrl window */
WHERE Pixmap        grayTile, grayStip;  /* for drawing dim things */

/* stuff used for 'directory' box */
WHERE Window        dirW, ddirW, dnamW;
WHERE int           dirUp;       /* is dirW mapped or not */
WHERE LIST          dList;       /* list of filenames in current directory */
WHERE BUTT          dbut[S_NBUTTS];

/* stuff used for 'gamma' box */
#define NUMHANDS 4
WHERE Window        gamW,graphW;
WHERE int           gamUp;       /* is gamW mapped or not */
WHERE BUTT          gbut[G_NBUTTS];
WHERE XPoint        ghand[NUMHANDS];

#undef WHERE





/* function declarations for externally-callable functions */

#ifdef __STDC__ 
/****************************** XV.C ****************************/
void DrawWindow(int, int, int, int);
void WCrop(int, int);
void WUnCrop(void);
void WResize(int, int);
void WRotate(void);
void InvCropRect(void);
void MakeRootPic(void);

/*************************** XVMISC.C ***************************/
Window CreateWindow(char *, char *, unsigned int, unsigned int, 
		    unsigned long, unsigned long);
void Resize(int, int);
void Rotate(void);
void SortColormap(void);
void AllocColors(void);
void AllocRWColors(void);
void DoMonoAndRV(void);
void DoCrop(void);
void UnCrop(void);
void FSDither(byte *, int, int, byte *);
void CreateXImage(void);
void CenterString(Window, char *, int, int);
void ULineString(Window, char *, int, int);
int  StringWidth(char *);
void FakeButtonPress(BUTT *);
void SetCropString(void);
void Warning(void);
void FatalError(char *);
void LoadFishCursors(void);
void SetCursors(int);
void WaitCursor(void);
void Quit(int);
void Timer(int);

/*************************** XV24TO8.C **************************/
int  Conv24to8(byte *, int, int, int);
void InitFSDTables(void);

/**************************** XVCTRL.C **************************/
void CreateCtrl(char *);
void CtrlBox(int);
void RedrawCtrl(int, int, int, int);
int  ClickCtrl(int, int);
void DrawCtrlStr(void);
void ScrollToCurrent(void);

void LSCreate(LIST *, Window, int, int, int, int, int, char **, int, 
	      unsigned long, unsigned long, void (*)(void), int, int);
void LSRedraw(LIST *);
int  LSClick (LIST *, XButtonEvent *);
void LSNewData(LIST *, char **, int);


/*************************** XVINFO.C ***************************/
void  CreateInfo(char *);
void  InfoBox(int);
void  RedrawInfo(int, int, int, int);
void  SetInfoMode(int);
void  SetISTR(int, ...);
char *GetISTR(int);

/**************************** XVDIR.C ***************************/
void CreateDirW(char *);
void DirBox(int);
void RedrawDirW(int,int,int,int);
int  ClickDirW(int, int);
void LoadCurrentDirectory(void);
void RedrawDDirW(void);
void RedrawDNamW(void);
void SelectDir(int);
void DirOpenActive(void);
void TrackDDirW(int,int);
int  DirKey(int);
int  DoSave(void);


/**************************** XVGAM.C **************************/
void CreateGam(char *);
void GamBox(int);
void RedrawGam(int, int, int, int);
void RedrawGraph(int, int, int, int);
void ClickGam(int, int);
void TrackGraph(int, int);
void GenerateGamma(void);
void GenerateFSGamma(void);
void GammifyColors(void);
void SetGPreset(int, int, int, int, int, int, int);

/*************************** XVSCRL.C ***************************/
void SCCreate  (SCRL *, Window, int, int, int, int, int, int, int, int, 
                      unsigned long, unsigned long, void (*)(void));
void SCSetRange(SCRL *, int, int, int, int);
void SCSetVal  (SCRL *, int);
void SCRedraw  (SCRL *);
void SCTrack   (SCRL *, int, int);


/**************************** XVBUTT.C ***************************/

void BTCreate(BUTT *, Window, int, int, int, int, char *, 
	      unsigned long, unsigned long);
void BTSetActive(BUTT *, int);
void BTRedraw(BUTT *);
int  BTTrack (BUTT *);


RBUTT *RBCreate(RBUTT *, Window, int, int, char*, 
		unsigned long, unsigned long);
void   RBRedraw(RBUTT *, int);
void   RBSelect(RBUTT *, int);
int    RBWhich(RBUTT *);
int    RBCount(RBUTT *);
void   RBSetActive(RBUTT *, int, int);
int    RBClick(RBUTT *, int, int);
void   RBTrack(RBUTT *, int);


/**************************** XVGIF.C ***************************/
int LoadGIF(char *, int);

/*************************** XVGIFWR.C **************************/
int WriteGIF(FILE *, byte *, int, int, byte *, byte *, byte *, int, int);

/**************************** XVPM.C ****************************/
int LoadPM(char *, int);
int WritePM(FILE *, byte *, int, int, byte *, byte *, byte *, int, int);

/**************************** XVPBM.C ***************************/
int LoadPBM(char *, int);
int WritePBM(FILE *, byte *, int, int, byte *, byte *, byte *, int, int, int);

/**************************** XVXBM.C ***************************/
int LoadXBM(char *, int);
int WriteXBM(FILE *, byte *, int, int, char *);





#else     /* using non-ANSI cc.  Function defs, but no params */




/****************************** XV.C ****************************/
void DrawWindow(), WCrop(), WUnCrop(), WResize(), WRotate(), InvCropRect();
void MakeRootPic();

/*************************** XVMISC.C ***************************/
Window CreateWindow();
void   Resize(), Rotate(), SortColormap(), AllocColors(), DoCrop(), UnCrop();
void   DoMonoAndRV();
void   AllocRWColors(), FSDither(), CenterString(), ULineString();
int    StringWidth();
void   FakeButtonPress(), SetCropString(), Warning(), FatalError(), Quit();
void   Timer(), CreateXImage(), LoadFishCursors(), SetCursors(), WaitCursor();

/*************************** XV24TO8.C **************************/
int  Conv24to8();
void InitFSDTables();

/**************************** XVCTRL.C **************************/
void CreateCtrl(), CtrlBox(), RedrawCtrl(), DrawCtrlStr(), ScrollToCurrent();
int  ClickCtrl();

void LSCreate(), LSRedraw(), LSNewData();
int  LSClick();

/*************************** XVINFO.C ***************************/
void  CreateInfo(), InfoBox(), RedrawInfo(), SetInfoMode(), SetISTR();
char *GetISTR();

/**************************** XVDIR.C ***************************/
void CreateDirW(), DirBox(), RedrawDirW(), LoadCurrentDirectory();
int  ClickDirW(), DoSave(), DirKey();
void RedrawDDirW(), RedrawDNamW(), SelectDir(), DirOpenActive(), TrackDDirW();

/**************************** XVGAM.C **************************/
void CreateGam(), GamBox(), RedrawGam(), RedrawGraph(), ClickGam();
void TrackGraph(), GenerateGamma(), GenerateFSGamma(), GammifyColors();
void SetGPreset();

/*************************** XVSCRL.C ***************************/
void SCCreate(), SCSetRange(), SCSetVal(), SCRedraw(), SCTrack();

/**************************** XVBUTT.C ***************************/
void BTCreate(), BTSetActive(), BTRedraw();
int  BTTrack();

RBUTT *RBCreate();
void   RBRedraw(), RBSelect(), RBSetActive(), RBTrack();
int    RBWhich(), RBCount(), RBClick();

/**************************** XVGIF.C ***************************/
int LoadGIF();

/*************************** XVGIFWR.C **************************/
int WriteGIF();

/**************************** XVPM.C ****************************/
int LoadPM(), WritePM();

/**************************** XVPBM.C ***************************/
int LoadPBM(), WritePBM();

/**************************** XVXBM.C ***************************/
int LoadXBM(), WriteXBM();


#endif
\BARFOO\
else
  echo "will not over write ./xv.h"
fi
if `test ! -s ./pm.h`
then
echo "writting ./pm.h"
cat > ./pm.h << '\BARFOO\'
/* include file defining constants/macros for PM files.  Used by xvpm.c 
 */

/*
 * Copyright 1989, 1990 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any express or implied warranty.
 */

#define	PM_MAGICNO	0x56494557		/* Hex for VIEW */
#define PM_MAXNELM	1024
#define PM_MAXNBAND	1024
#define PM_NOSHIFT	0
#define PM_SHIFT	1

#define	PM_A		0x8000
#define	PM_C		0x8001
#define	PM_S		0x8002
#define	PM_I		0x8004
#define PM_F		0xc004

#define PM_RED 0xff
#define PM_GREEN 0xff00
#define PM_BLUE 0xff0000
#define PM_ALPHA 0xff000000
#define PM_BW 0

#define	PM_CMAX		0xff
#define PM_SMAX		0x7fff
#define	PM_IMAX		0x7fffffff
#define PM_FMAX		1.7E38

#define PM_IOHDR_SIZE	(sizeof(pmpic)-(2*sizeof(char*)))

#define	pm_max(pm)	((pm)->pm_form == PM_C ? PM_CMAX :		  \
				(pm)->pm_form == PM_S ? PM_SMAX :	  \
					(pm)->pm_form == PM_I ? PM_IMAX : \
						 PM_FMAX)

#define pm_index(fm)	(((fm)&0xff)-(((fm)>>14)&01))
#define	pm_sel(fm,fn)	(*((fn)[pm_index(fm)]))
#define pm_iindex(a,nc,cr,cc)	((a)+((cr)*(nc))+(cc))
 
#define pm_nelm(p)	((p)->pm_ncol * (p)->pm_nrow)
#define pm_nbelm(p)	(pm_nelm(p) * (p)->pm_nband)
#define pm_psize(p)	(pm_nbelm(p) * (((p)->pm_form)&0xff))
#define pm_isize(p)	((p)->pm_np * pm_psize(p))
#define pm_npix(p)      (pm_nbelm(p) * (p)->pm_np)

#include <sys/types.h>

typedef struct {
	int	pm_id;		/* Magic number for pm format files.	*/
	int	pm_np;		/* Number of planes. Normally 1.	*/
	int	pm_nrow;	/* Number of rows. 1 - MAXNELM.		*/
	int	pm_ncol;	/* Number of columns. 1 - MAXNELM.	*/
	int	pm_nband;	/* Number of bands.			*/
	int	pm_form;	/* Pixel format.			*/
	int	pm_cmtsize;	/* Number comment bytes. Includes NULL. */
	char	*pm_image;	/* The image itself.			*/
	char	*pm_cmt;	/* Transforms performed.		*/
} pmpic;

typedef	struct {
	int	pm_x;		/* X Position. */
	int	pm_y;		/* Y Position. */
	int	pm_z;		/* Z Position. */
	float	pm_ux;		/* Uncertainty in x. */
	float	pm_uy;		/* Uncertainty in y. */
	float	pm_uz;		/* Uncertainty in z. */
} pmxyz;

#define	PM_EBASE	100
#define PM_EMALLOC	101
#define PM_EBADPARAM	102
#define PM_EBADPIC	103
#define PM_EBADFORM	104
#define PM_EBADMAGIC	105
#define PM_ENULLPIC	106    /* picture given was NULL */
#define PM_EBADPLANES   107  /* invalid # of planes chosen for format */
#define PM_EBADBANDS 	108 /* invalid # of bands chosen for format */
#define PM_EBADSIZE 	109 /* # of rows/cols and x offsets, y offsets
			   too big for ikonas */
#define PM_EBADCOLORS 	110 /* invalid number of colors chosen for format */
#define PM_EBADCOLORPLANE 111 /* invalid color plane entered */


#define PM_NERROR	12
#define PM_ERROR(e)	(((e) < PM_EBASE || (e) > (PM_EBASE + PM_NERROR)) ? \
				0 : (e) - PM_EBASE)
extern char	*pm_errmsg[];

pmpic	*pm_add();
pmpic	*pm_addcmt();
pmpic	*pm_alloc();
pmpic	*pm_and();
pmpic	*pm_bthresh();
pmpic	*pm_cast();
char	*pm_cmt();
pmpic	*pm_conv();
pmpic	*pm_ebadform();
int	pm_getcmt();
pmpic	*pm_ikrd();
pmpic	*pm_ikwr();
pmpic	*pm_neg();
pmpic	*pm_or();
pmpic	*pm_prep();
pmpic	*pm_rdhdr();
pmpic	*pm_read();
pmpic	*pm_scale();
pmpic	*pm_sub();
pmpic	*pm_thresh();
pmpic	*pm_write();

pmxyz	*pm_centroid();

\BARFOO\
else
  echo "will not over write ./pm.h"
fi
echo "Finished archive 1 of 8"
exit



dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.