[comp.sources.x] v10i088: xv - display and manipulate images, Part10/10

bradley@halibut.cis.upenn.edu (John Bradley) (11/28/90)

Submitted-by: bradley@halibut.cis.upenn.edu (John Bradley)
Posting-number: Volume 10, Issue 88
Archive-name: xv/part10

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./README`
then
echo "writting ./README"
cat > ./README << '\BARFOO\'
Installation
------------
If you don't plan to use Imake, copy 'Makefile.std' (a regular old-style
minimalist makefile, not one created by Imake) to 'Makefile'.

Check the Makefile for the configuration option(s).  There are unfortunately
quite a few these days, to support a number of different machines.  The
program builds just fine on Suns running SunOS 4.0, VAXes running Ultrix, 
and DECstations running UWS, without any options whatsoever.  If you're
on a SYSV-based machine, you'll probably need '-DSYSV' and '-DDIRENT'.
Read the file for more specific info.

Otherwise, check the Imakefile, and make the program however you normally 
would.  Be sure to 'make depend' before building the program.

Caveats
-------

XV has been developed on a Sun4/280 running SunOS 4.0, using both the normal
'cc' and gcc-1.37 compilers.  There shouldn't be anything grotesque enough
in the code to break any other compilers.  

The viewing environment has mainly been an IBM RT with an 8-bit color display.
The window managers of choice have been TWM (recently) and UWM (in the past).

It has been compiled and tested on the following systems:  Sun 4 running SunOS 
4.0, VAXstation 3500 running Ultrix 3.0, MicroVax II running Ultrix 2.0, 
DecStation 3100 running UWS 2.0, IBM RISC System/6000 running AIX 3.0.

It has displayed on the following systems:  IBM RT (8-bit color), Sun 3 
(1-bit B/W), Sun 3 (8-bit grayscale), Sun 4 (1-bit B/W), MicroVax II (8-bit
color), MicroVax II (4-bit grayscale), a variety of HPs (4-bit color, 6-bit 
color, 8-bit color, and 24-bit color), and Visual, NCD, Tektronix, and
HDS X terminals (1-bit B/W abd 8-bit color).

Provided you don't have some odd-ball 5-bit StaticColor display, it should
work for you.

'vsprintf.c' has been included for the benefit of those on machines that
don't have it.  (IBM RT AOS 4.3 and BSD 4.3 on VAX)


Bizarrities
-----------

There are problems with using XV under 'dxwm', DEC's window manager.  You'll
have to specify '-dxwm' to enable a couple of kludges, and even then XV is
unable to MOVE its window AT ALL.  (This was with dxwm controlling my X11R4
IBM RT display.  Your mileage (dxwm controlling a DEC server, ferinstance)
may vary.

XV would appear to exercise a pair of bugs in TWM, the version from the X11R4 
tape.  Perhaps they've been fixed by now.

Colormap Installation:  under twm, if you have multiple XVs running, and each
has their own colormap, sometimes the colormap doesn't get properly installed 
if you move the mouse directly from one XV to the other, quickly, so that it 
doesn't see the mouse go into the root window, or any other window.  If you 
move the mouse outside the window and move it back in, it SHOULD install the
colormap correctly.

Colormap Installation: Note, if an alternate colormap is installed, it will
ONLY be installed when the mouse is inside the IMAGE window.  It will not be
installed when the mouse is in any other XV windows.  This is because I can't
guarantee that the other windows will still have contrasting
foreground/background colors when the alternate colormap is installed.  It is
assumed that if you put the mouse in a window, you will want to use that
window, so you'd better be able to READ that window...

There's a bug in my version of TWM that creeps up if you have titlebars 
turned off.  Essentially, XV tells the window manager to make the window a
certain size.  TWM (wrongly) adds enough room at the top to put its title bar 
there, but doesn't draw it, since titlebars are turned off.  XV gets back a
ConfigureNotify event on the window with the new size, which is large by 20-odd
pixels in height.  There's no way to detect this behavior that I know of.
Workaround:  wait for a fixed version of TWM, until then, run (at least XV) 
with titlebars on.



Modifying XV
------------

ADDING A NEW FILE FORMAT TO XV

This category is split up into two sections, reading a new file format, and 
writing a new file format, because it's perfectly conceivable that you'd want 
to do one but not the other.  In some cases, it's even possible that you could
only (realistically, read "easily") do one or the other.  (Example:  you want
to be able to write an Encapsulated PostScript image, but you'd never be able
to read PostScript files without writing a complete postscript interpreter, 
something that's thankfully outside the context of this program.)

Alternately, you might also want to be able to directly display the output of
some Mutant Ray Tracer (or whatever) without going through a conversion
program, yet you'd NEVER want to create more Mutant-Ray-Tracer-format pictures
with xv...

Whatever.  The following instructions are being written as I add PBM/PGM/PPM 
capability to the program, so A) it's likely to be fairly accurate, and B) for
example purposes, I'll be talking about the PBM/PGM/PPM code specifically.

READING A NEW FILE FORMAT

-------
NOTE:  Despite the wide variety of displays and file formats XV deals with,
internally it only manipulates 8-bit colormapped images.  If you're loading
an 8-bit colormapped image, such as a GIF image, no prob.  If you're loading
an 8-or-less-bits format that doesn't have a colormap (such as an 8-bit 
greyscale image, or a 1-bit B/W bitmap) your Load() routine will have to 
generate an appropriate colormap.  And if you're loading up a 24 bit RGB file,
you'll have to compress it down to 8 bits by calling Conf24to8()...
-------

Make a copy of xvpm.c, calling it something appropriate.  I'm adding PBM 
capabilities, so I think xvpbm.c is a fine file name.

Edit the Makefile so that your new module will be compiled.  Add 'xvpbm.o' 
(or whatever)

Edit the new module.

You'll need to #include "xv.h", of course.

The module should have one externally callable function that does the work of
loading up the file.  The function is called with two arguments, a filename
and the number of colors available on this display, like so:

/*******************************************/
int LoadPBM(fname,nc)
    char *fname;   int nc;
/*******************************************/

The file name will be the complete file name (absolute, not relative to any 
directory).  Note:  if xv is reading from <stdin>, don't worry about it.
stdin is automatically copied to a /tmp/xv****** file to make life considerably
simpler (and some times possible at all)

The number of colors argument is going to be (2 << # of bit planes) (or 'ncols'
if specified on the command line).  Either way, this only comes into play if 
you have to do a 24-to-8 bit conversion.  More on that later.

The function returns '0' on success, non-zero on failure.

The function is expected to load up the following global variables:
	byte *pic;	this is a wide*high array of bytes, one byte per pixel,
			starting at the top-left corner, and proceeding in 
			scan-line order.  There is no padding of any sort at 
			the end of a scan line.  The code is expected to 
			malloc() the memory for this image.

	int pWIDE, pHIGH;
			these variables specify the size of the image that
			has been loaded, in pixels.

	byte r[256], g[256], b[256];
			the desired colormap.  As specified above, 'pic' is
			an 8-bits per pixel image.  A given pixel value in pic
			maps to an RGB color through these arrays.  In each
			array, a value of 0 means 'off', and a value of 255
			means 'fully on'.  Note:  the arrays do not have to
			be completely set.  Only RGB entries for pixels that
			actually exist in the 'pic' need to be set.  For 
			example, if the pic is known to be a B/W bitmap with
			pixel values of 0 and 1, you'd only have to set
			{r,g,b}[0] and {r,g,b}[1].

The function should also call 'SetISTR(ISTR_FORMAT, fmt, args)' to set the
"Format:" string in the Info box.  It should call the function as soon as
possible (ie, once it knows the format of the picture, but before it's tried
to load/parse all of the image data...)


Diagnostics:

Non-fatal errors in your Load() routine should be handled by calling
SetISTR(ISTR_WARNING, fmt, args...).  This will print the string in the info
box and in the ctrl box.

Non-fatal errors would be things like 'can't open file'...

Fatal errors should be handled by calling 'FatalError(error_string)'.  
This function prints the string to stderr, and exits the program with an error
code.  The classic fatal error is 'unable to malloc...'.


Handling 24-bit RGB pictures:

If (as in the case of PPM files) you're file format has 24 bits of information
per pixel, you'll have to get it down to 8 bits and a colormap for XV to make
any use of it.  A function 'Conv25to8(pic24, w, h, nc)' is provided, so
don't worry about it.

To use it, you'll have to load your picture into a WIDE*HIGH*3 array of bytes.
(You'll be expected to malloc() this array.)  This array begins at the top left
corner, and proceeds in scan-line order.  The first byte of the array is the
red component of pixel0, followed by the green component of pixel0, followed by
the blue component of pixel0, followed by the red component of pixel1, etc...
There is no padding of any kind.

Once you've got this image built, call 'Conv24to8()' with a pointer to the
24bit image, the width and height of the image, and the number of colors to
'shoot for' in the resulting 8-bit picture.  This is the same parameter that
was passed to your Load() routine, so just pass it along.

If successful, Conv24to8() will return '0'.  It will have generated 'pic', and
filled in values in all the global variables that your Load() routine is
expected to set.  You should now free() the memory associated with the 24-bit
version of your image and leave your Load() function.

Read the source in xvpbm.c for further info on writing the Load() routine.

----------

Once you have a working Load() routine, you'll want to do some other crap...

Edit xv.h and add two function prototypes for any global functions you've
written (presumably just LoadPBM() (in this case)).  You'll need to add a full
function prototype (with parameter types) in the #ifdef __STDC__ section (near
the bottom), and a function reference (just the return type) in the #else /*
non-ANSI */ section at the bottom.



Edit xv.c:


***  Add a filetype #define near the top.  Find the section:

> /* file types that can be read */
> #define UNKNOWN 0
> #define GIF     1
> #define PM      2

And add one more to the list, in this case: "#define PBM 3"

Note: I only added one filetype to this list, despite the fact that
I'm really adding three (or six, really) different file formats to the
program.  This is because all of these file formats are related, and
are handled by the same Load...() function.



*** now tell the openPic() routine about your Load...() routine

find the following (in openPic()):

>    filetype = UNKNOWN;
>    if (strncmp(magicno,"GIF87",5)==0) filetype = GIF;
>    else if (strncmp(magicno,"VIEW",4)==0 ||
>             strncmp(magicno,"WEIV",4)==0) filetype = PM;

Add another 'else' case that will set filetype if it's your format:

>    else if (magicno[0] == 'P' && magicno[1]>='1' &&
>             magicno[1]<='6') filetype = PBM;


And add another case to the switch statement (a few lines further down)

>  switch (filetype) {
>  case GIF: i = LoadGIF(filename);      break;
>  case PM:  i = LoadPM(filename,ncols); break;
>  }

add:

>  case PBM: i = LoadPBM(filename,ncols); break;


That should do it.  Consult the file xvpm.c or xvpbm.c for further information.
Remember: do as I mean, not as I say.

-----------------------------------------------------------------------------




WRITING A NEW FILE FORMAT

-------
NOTE:  Despite the wide variety of displays and file formats XV deals with,
internally it only manipulates 8-bit colormapped images.  As a result, writing
out 24bit RGB images is a horrible waste, and is to be avoided if your file
format can handle colortable images...
-------

If you haven't already done so (if/when you created the Load...() function):
  Make a copy of xvpm.c, calling it something appropriate.  I'm adding PBM 
  capabilities, so I think xvpbm.c is a fine file name.

  Edit the Makefile so that your new module will be compiled.  Add 'xvpbm.o' 
  (or whatever)

  Edit the new module.

  You'll need to #include "xv.h", of course.


The module should have one externally callable function that does the work of
writing the file.  The function is called with a vitual plethora of arguments.
At a minimum, you'll be given a FILE * to an already open-for-writing stream,
a pointer to an 8-bits per pixel image, the width and height of that image, 
pointers to 256-entry red, green, and blue colormaps, the number of colors
actually used in the colormaps, and the 'color style' from the 'Save' dialog 
box.

You may pass more parameters, since you're going to be adding the call to this
function later on.  For example, in my PBM code, I pass one more parameter,
'raw' (whether to save the file as RAW or ASCII) to handle two very similar
formats.  (Rather than haveing WritePBMRaw() and WritePBMAscii()...)

Your function definition should look something like this:

/*******************************************/
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;
/*******************************************/

Write the function as you deem appropriate.

Some Notes:
  *  your function should return '0' if successful, non-zero if not
  *  don't close 'fp'
  *  pic is a w*h byte array, starting at top-left, and proceeding in normal
	scan-line order

  *  colorstyle can (currently) take on three values:
	0=FULL COLOR.  This could mean either 24-bit RGB, or an 8-bit colormap
	  or any other color format.  r[pix],g[pix],b[pix] specifies the color
	  of pixel 'pix'.  

	1=GREYSCALE, preferably 8 bits.  Two caveats:  you MUST use the 
	  colormap to determine what grey value to write.  For all you know,
	  pixel value '0' in pic could map to white, '1' could map to black, 
	  and '2' could map to a half-intensity grey.  

	  The other note:  unless the original picture was a greyscale, (which
	  SHOULDN'T be tested for), the colormap is going to have actual 
	  colors in it.  You'll want to map RGB colors into greyscale values
	  using 'the standard formula'  (roughly .33R + .5G +.17B).  The
	  following code shows how to quickly write a raw greyscale image:

	  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);
	  }

	2=B/W STIPPLE:  The stippling algorithm will have already been 
	  preformed by the time your function is called.  'pic' will be an
	  image consisting of the pixel values '1' and '0'.  (pic will STILL
	  be organized the same way (ie, one byte per pixel))

	  1 = WHITE, 0 = BLACK


	* for FULL COLOR or GREYSCALE images, you will be guaranteed that all
	  pixel values in pic are in the range [0 - numcols-1] (inclusive).


That done, edit 'xv.h' and add a pair of function declarations for your new
function.  (one full ANSI-style prototype, and one that just declares the
return type).  (Copy the declarations for 'WritePM()'.)

Edit 'xvdir.c'.  This is the module that controls the 'Save' dialog box.

Add another 'format' type to the 'formatRB' button list:
In the function 'CreateDirW()', find the block that (starts like):

>  formatRB = RBCreate(NULL, dirW, 26, y, "GIF", infofg, infobg);
>  RBCreate(formatRB, dirW, 26, y+18, "PM", infofg, infobg);

copy the last 'RBCreate' call in the list, add '18' to the 'y+**' argument,
and stick in an appropriate format type name.  In this case, I'm adding
two formats (PBM raw and PBM ascii) so I'll add these two lines:

>  RBCreate(formatRB, dirW, 26, y+36, "PBM/PGM/PPM raw", infofg, infobg);
>  RBCreate(formatRB, dirW, 26, y+54, "PBM/PGM/PPM ascii", infofg, infobg);

Depending how many formats you've added, you may have to move the 
'Normal Size' & 'At Current Expansion' buttons down.  Right above the RBCreate
calls that have that string in them is a 'y = y + **' assignment.  Add 18 to
the constant for each 'format' line that you added above.


In the function DoSave(), find the following block:
>  i = RBWhich(formatRB);
>  switch (i) {
>  case 0:  rv = WriteGIF(fp,thepic,w, h, r, g, b,numcols,RBWhich(colorRB));
>           break;
>  case 1:  rv = WritePM (fp,thepic,w, h, r, g, b,numcols,RBWhich(colorRB));
>           break;
>  }

and add cases for your function(s), like so:

>  case 2:  rv = WritePBM(fp,thepic,w, h, r, g, b,numcols,RBWhich(colorRB),1);
>           break;
>  case 3:  rv = WritePBM(fp,thepic,w, h, r, g, b,numcols,RBWhich(colorRB),0);
>           break;


\BARFOO\
else
  echo "will not over write ./README"
fi
if `test ! -s ./PATCHLEVEL`
then
echo "writting ./PATCHLEVEL"
cat > ./PATCHLEVEL << '\BARFOO\'
Current patchlevel:  2

Rev: 10/9/90    (patchlevel 0  -  initial release)

Rev: 10/17/90   (patchlevel 1)
------------------------------
Imakefile added			(David Elliot    (dce@smsc.sony.com))
System V release 4 mods		(David Elliot    (dce@smsc.sony.com))
Bug in 'quick check' fixed	(Arthur Olson    (ado@elsie.nci.nih.gov))
Mods for Convex machines	(Anthony Datri   (datri@convex.com))
'vprintf' module added 		(Jonathan Kamens (jik@pit-manager.mit.edu))
window creation bug fixed
added icon
fixed 'Input Focus' probs
added '-w' flag to bggen
various cleanups to shut up 'noisy' compilers


Rev: 11/26/90  (patchlevel 2)
-----------------------------
added workaround for 'X Protocol Errors' on broken servers (XFreeColors())
	(see the '-bfc' option)
fixed core dump when cropping on certain displays
misc. #ifdefs for HPs
fixed problem with fish cursor remaining around too long
more SVR4 #ifdefs			(David Elliott,  dce@smsc.sony.com)
fixed bug in tracking pixel values	(Bob Finch,      bob@gli.com)
misc #ifdefs for ISC 386/ix 2.0.2	(Mark Snitily    mark@zok.uucp)
misc #ifdefs for AT&T machines	 	(Eric Raymond   eric@snark.thyrsus.com)
misc #ifdefs for Silicon Graphics       (Paul Close     pdc@lunch.wpd.sgi.com)
Added POSIX signal handling		(Mike Patnode   (mikep@sco.com))
Port to SCO UNIX/ODT			(Mike Patnode   (mikep@sco.com))

fixed problem with using '-max' and '-fixed' at same time
			(Greg Spencer   greg@longs.lance.colostate.edu)

modification to work with Virtual Root Windows (ala swm and tvtwm)
			(Bill Kucharski  kucharsk@solbourne.com)

the 'save-as' filename is now set to the 'current' filename

Also, if you double click on 'plain' files in the directory box,
	it will set the 'save-as' filename accordingly.

Added ability to view images centered on the root window, without
	any tiling.  Added associated options ('-center', '-rfg', '-rbg',
	and '-rpat')

Workaround for twm 'No title bars' bug  
			 (Steve Swales  steve@bat.lle.rochester.edu)

Bidirectional Rotate commands added

Maxpect command added:  (Maximum size, but preserve aspect ratio)

AutoCrop command added:  (Crops out solid borders.)

Potential support for 32-bit displays.  (Hasn't been tested.  Don't have one.)
\BARFOO\
else
  echo "will not over write ./PATCHLEVEL"
fi
if `test ! -s ./Makefile`
then
echo "writting ./Makefile"
cat > ./Makefile << '\BARFOO\'
# Makefile for xv
#

# your C compiler of choice
CC = cc

################ CONFIGURATION OPTIONS #################

# if you are running on a SysV-based machine, such as HP, Silicon Graphics,
# etc, uncomment the following line to get you most of the way there.  
#
#UNIX = -DSVR4

# If you are running on a POSIX-compatible machine, such as an
# IBM RS6000, you MAY need to uncomment the 'NEED_DIRENT' line.
# To determine if such 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
#
#NEED_DIRENT = -DDIRENT


# If, when 'Applying' colors, or when loading new pictures, you get an
# X Protocol Error on the XFreeColors() call, your X Server is Wrong.
# Several workarounds:  You can specify '-bfc' on the command line, or
# set the 'xv.brokeFreeCols' resource to 'true'.  Alternately, you can
# uncomment the BROKECOLS line below to compile in the workarounds
# permanently.  If you do this, '-bfc' will toggle OFF the workarounds.
# Noteworthy Offenders:  AIX 3.1 on IBM 6000, and OLW on Suns
#
#BROKECOLS = -DBROKEFREECOLS


# IF YOUR MACHINE DOESN'T HAVE 'vprintf()' OR 'vsprintf()'
#
# Vax BSD and IBM AOS don't have vprintf or vsprintf.
# Note that our local library versions of sprintf have been updated
# to return int, the number of characters in the formatted string,
# whereas the versions in stock 4.3BSD do not so return.  You may
# have to remove the "-DINTSPRINTF" below if you're compiling for
# stock 4.3BSD or for some other Vax or RT library package where
# sprintf returns char *.
#
# Also, I define NOVOID on the Vax because I'm using pcc to compile.
# If you use gcc or some other better compiler, this should not be
# necessary.  I define NOSTDHDRS on the RT because we don't have
# standard ANSI header files installed for the RT, even though the RT
# compiler claims to be ANSI-compliant.
#
#  (for BSD 4.3 VAX, uncomment the following line)
#VPRINTF = -DNEED_VPRINTF -DINTSPRINTF -DLONGINT -DNOVOID
#  (for (stock) IBM RT AOS 4.3, uncomment the following line)
#VPRINTF = -DNEED_VPRINTF -DLONGINT -DNOSTDHDRS


# If your machine does not have the 'setitimer()' call, but does
# have the 'usleep()' call, uncomment the following line:
#
#TIMERS = -DUSLEEP
#
# alternately, if your machine does not have EITHER the 'setitimer()' or
# the 'usleep()' call, uncomment the following line:
#
#TIMERS = -DNOTIMER


# If you are using an AT&T machine, uncomment the following line
# If you have ptoblems compiling xv.c and xvdir.c because of the DIR
# reference in dirent.h, append '-DATT' to the following line:
#
#ATT = -DSYSV -DDIRENT -DUSLEEP -DATT


# For SCO and ODT machines, uncomment the following:
#
#SCO = -Dsco -DPOSIX -DNOTIMER
#
# Itimers will be in 3.2v3 (yeah!) but that won't be out in the public's
# hands for a while.  Hey, it's just the fish anyways.
#
# Also, you'll want to change LIBS to
#
#  -lX11 -lm -lsocket -lmalloc -lc -lx
#
# -lx must be after -lc so you get the right directory routines.
#


CFLAGS = -O2 $(NEED_DIRENT) $(BROKECOLS) $(VPRINTF) $(TIMERS) $(ATT) $(SCO) \
	$(UNIX)

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 \
	  bitmaps/icon

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 \
	vprintf.o

MISC = README PATCHLEVEL

.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* Imakefile *.c *.h bitmaps docs $(MISC)

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

$(OBJS):   xv.h
xv.o:      bitmaps.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 ./Makefile.std`
then
echo "writting ./Makefile.std"
cat > ./Makefile.std << '\BARFOO\'
# Makefile for xv
#

# your C compiler of choice
CC = cc

################ CONFIGURATION OPTIONS #################

# if you are running on a SysV-based machine, such as HP, Silicon Graphics,
# etc, uncomment the following line to get you most of the way there.  
#
#UNIX = -DSVR4

# If you are running on a POSIX-compatible machine, such as an
# IBM RS6000, you MAY need to uncomment the 'NEED_DIRENT' line.
# To determine if such 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
#
#NEED_DIRENT = -DDIRENT


# If, when 'Applying' colors, or when loading new pictures, you get an
# X Protocol Error on the XFreeColors() call, your X Server is Wrong.
# Several workarounds:  You can specify '-bfc' on the command line, or
# set the 'xv.brokeFreeCols' resource to 'true'.  Alternately, you can
# uncomment the BROKECOLS line below to compile in the workarounds
# permanently.  If you do this, '-bfc' will toggle OFF the workarounds.
# Noteworthy Offenders:  AIX 3.1 on IBM 6000, and OLW on Suns
#
#BROKECOLS = -DBROKEFREECOLS


# IF YOUR MACHINE DOESN'T HAVE 'vprintf()' OR 'vsprintf()'
#
# Vax BSD and IBM AOS don't have vprintf or vsprintf.
# Note that our local library versions of sprintf have been updated
# to return int, the number of characters in the formatted string,
# whereas the versions in stock 4.3BSD do not so return.  You may
# have to remove the "-DINTSPRINTF" below if you're compiling for
# stock 4.3BSD or for some other Vax or RT library package where
# sprintf returns char *.
#
# Also, I define NOVOID on the Vax because I'm using pcc to compile.
# If you use gcc or some other better compiler, this should not be
# necessary.  I define NOSTDHDRS on the RT because we don't have
# standard ANSI header files installed for the RT, even though the RT
# compiler claims to be ANSI-compliant.
#
#  (for BSD 4.3 VAX, uncomment the following line)
#VPRINTF = -DNEED_VPRINTF -DINTSPRINTF -DLONGINT -DNOVOID
#  (for (stock) IBM RT AOS 4.3, uncomment the following line)
#VPRINTF = -DNEED_VPRINTF -DLONGINT -DNOSTDHDRS


# If your machine does not have the 'setitimer()' call, but does
# have the 'usleep()' call, uncomment the following line:
#
#TIMERS = -DUSLEEP
#
# alternately, if your machine does not have EITHER the 'setitimer()' or
# the 'usleep()' call, uncomment the following line:
#
#TIMERS = -DNOTIMER


# If you are using an AT&T machine, uncomment the following line
# If you have ptoblems compiling xv.c and xvdir.c because of the DIR
# reference in dirent.h, append '-DATT' to the following line:
#
#ATT = -DSYSV -DDIRENT -DUSLEEP -DATT


# For SCO and ODT machines, uncomment the following:
#
#SCO = -Dsco -DPOSIX -DNOTIMER
#
# Itimers will be in 3.2v3 (yeah!) but that won't be out in the public's
# hands for a while.  Hey, it's just the fish anyways.
#
# Also, you'll want to change LIBS to
#
#  -lX11 -lm -lsocket -lmalloc -lc -lx
#
# -lx must be after -lc so you get the right directory routines.
#


CFLAGS = -O $(NEED_DIRENT) $(BROKECOLS) $(VPRINTF) $(TIMERS) $(ATT) $(SCO) \
	$(UNIX)

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 \
	  bitmaps/icon

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 \
	vprintf.o

MISC = README PATCHLEVEL

.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* Imakefile *.c *.h bitmaps docs $(MISC)

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

$(OBJS):   xv.h
xv.o:      bitmaps.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.std"
fi
if `test ! -s ./Imakefile`
then
echo "writting ./Imakefile"
cat > ./Imakefile << '\BARFOO\'
/*
 * if you are running on a SysV-based machine, such as HP, Silicon Graphics,
 * etc, uncomment the following line to get you *most* of the way there.
 */
/* UNIX = -DSVR4 */

/*
 * If you are running on a POSIX-compatible machine, such as an
 * IBM RS6000, you MAY need uncomment the 'NEED_DIRENT' line.
 * To determine if such 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
 */
/* NEED_DIRENT = -DDIRENT */


/* If, when 'Applying' colors, or when loading new pictures, you get an
 * X Protocol Error on the XFreeColors() call, your X Server is Wrong.
 * Several workarounds:  You can specify '-bfc' on the command line, or
 * set the 'xv.brokeFreeCols' resource to 'true'.  Alternately, you can
 * uncomment the BROKECOLS line below to compile in the workarounds
 * permanently.  If you do this, '-bfc' will toggle OFF the workarounds.
 *
 * Noteworthy Offenders:  AIX 3.1 on IBM 6000, and OLW on Suns
 */
/* BROKECOLS = -DBROKEFREECOLS */


/* IF YOUR MACHINE DOESN'T HAVE 'vprintf()' OR 'vsprintf()'
 *
 * Vax BSD and IBM AOS don't have vprintf or vsprintf.
 * Note that our local library versions of sprintf have been updated
 * to return int, the number of characters in the formatted string,
 * whereas the versions in stock 4.3BSD do not so return.  You may
 * have to remove the "-DINTSPRINTF" below if you're compiling for
 * stock 4.3BSD or for some other Vax or RT library package where
 * sprintf returns char *.
 *
 * Also, I define NOVOID on the Vax because I'm using pcc to compile.
 * If you use gcc or some other better compiler, this should not be
 * necessary.  I define NOSTDHDRS on the RT because we don't have
 * standard ANSI header files installed for the RT, even though the RT
 * compiler claims to be ANSI-compliant.
 */
#if defined(VaxArchitecture) && !defined(UltrixArchitecture)
VPRINTF=	-DNEED_VPRINTF -DINTSPRINTF -DLONGINT -DNOVOID
#else 
#  if defined(RtArchitecture) && !defined(AIXArchitecture)
VPRINTF=	-DNEED_VPRINTF -DINTSPRINTF -DLONGINT -DNOSTDHDRS
#  endif
#endif


/* If your machine does not have the 'setitimer()' call, but does
 * have the 'usleep()' call, uncomment the following line:
 */
/* TIMERS = -DUSLEEP */
/*
 * alternately, if your machine does not have EITHER the 'setitimer()' or
 * the 'usleep()' call, uncomment the following line:
 */
/* TIMERS = -DNOTIMER */


/* If you are using an AT&T machine, uncomment the following line
 * If you have ptoblems compiling xv.c and xvdir.c because of the DIR
 * reference in dirent.h, append '-DATT' to the following line:
 */
/* ATT = -DSYSV -DDIRENT -DUSLEEP -DATT */


#if defined(SCOArchitecture)
DEFINES= -DPOSIX -DNOITIMER
SYS_LIBRARIES=        $(XLIB) -lm -lc -lx
#else
SYS_LIBRARIES=        $(XLIB) -lm
#endif

CCOPTIONS= $(UNIX) $(NEED_DIRENT) $(BROKECOLS) $(VPRINTF) $(TIMERS) $(ATT)

SYS_LIBRARIES=	-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 \
	  bitmaps/icon

SRCS1 =	xv.c xv24to8.c xvbutt.c xvctrl.c xvdir.c xvfish.c xvgam.c\
	xvgif.c xvgifwr.c xvinfo.c xvmisc.c xvpbm.c xvpm.c xvscrl.c\
	xvxbm.c vprintf.c

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

SRCS2=	bggen.c
OBJS2=	bggen.o

PROGRAMS= xv bggen

ComplexProgramTarget_1(xv,,)
ComplexProgramTarget_2(bggen,,)

InstallNonExec(docs/xv.man,$(MANDIR)/xv.ManSuffix)
InstallNonExec(docs/bggen.man,$(MANDIR)/bggen.ManSuffix)

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

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

depend:: bitmaps.h

\BARFOO\
else
  echo "will not over write ./Imakefile"
fi
if `test ! -s ./bggen.c`
then
echo "writting ./bggen.c"
cat > ./bggen.c << '\BARFOO\'
/*
 * bggen.c  -  a program that generates backgrounds for use with XV
 *
 * by John Bradley, University of Pennsylvania
 *   (bradley@cis.upenn.edu)
 *
 *      Rev: 8/31/90
 *      Rev: 10/17/90  -  added '-w' option
 */

/*
 * 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 <stdio.h>

#define DEFSIZE 1024
#define MAXCOLS  128

struct color { int r,g,b; int y; } cols[MAXCOLS], *cur, *nex;

int bmask[8] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };


main(argc,argv)
int    argc;
char **argv;
{
  int i,j,cnt,numcols;
  int high = DEFSIZE;
  int wide = 1;
  int bits = 8;
  int r, g, b;

  cnt = 0;  numcols = 0;
  for (i=1; i<argc; i++) {
    if (!strcmp(argv[i],"-s")) high = atoi(argv[++i]);

    else if (!strcmp(argv[i],"-w")) wide = atoi(argv[++i]);

    else if (!strcmp(argv[i],"-b")) bits = atoi(argv[++i]);

    else if (argv[i][0]=='-') break;     /* any other '-' option is unknown */

    else {
      switch (cnt) {
      case 0:  cols[numcols].r = atoi(argv[i]);  break;
      case 1:  cols[numcols].g = atoi(argv[i]);  break;
      case 2:  cols[numcols].b = atoi(argv[i]);  break;
      }
      cnt++;

      if (cnt==3) {
	if (numcols<MAXCOLS) numcols++;
	cnt = 0;
      }
    }
  }


  if (cnt || numcols==0 || high<1 || bits<1 || bits>8) {
    fprintf(stderr,"usage:  %s [-s size] [-w width] [-b bits] %s\n\n",
	    argv[0], "r1 g1 b1 [r2 g2 b2 ...]");
    fprintf(stderr,"\tThis will generate a WIDTHxSIZE vertical color band.\n");
    fprintf(stderr,"\t(Default: 1x%d)  To set your background\n",DEFSIZE);
    fprintf(stderr,"\t'bits' is the number of significant bits in the\n");
    fprintf(stderr,"\tcolor specifications.  (1-8)\n");
    fprintf(stderr,"\tpipe the resulting output into this cmd:\n");
    fprintf(stderr,"\t\t'xv -root -quit -slow24'\n\n");
    exit(1);
  }

  printf("P3 %d %d 255\n",wide,high);

  /* special case code for numcols==1 */

  if (numcols==1) {
    for (i=0; i<high; i++) 
      for (j=0; j<wide; j++)
	printf("%d %d %d\n",cols[0].r,cols[0].g,cols[0].b);
  }
  else {

    /* fill in 'y' field of cols[] */
    for (i=0; i<numcols; i++)
      cols[i].y = ((high-1) * i) / (numcols-1);

    cur = &cols[0];  nex = cur+1;

    for (i=0; i<high; i++) {
      /* advance to next pair of colors if we're outside region */
      while (nex->y < i) { cur++; nex++; }

      r = cur->r + ((nex->r - cur->r) * (i - cur->y)) / (nex->y - cur->y);
      g = cur->g + ((nex->g - cur->g) * (i - cur->y)) / (nex->y - cur->y);
      b = cur->b + ((nex->b - cur->b) * (i - cur->y)) / (nex->y - cur->y);

      r = r & bmask[bits-1];
      g = g & bmask[bits-1];
      b = b & bmask[bits-1];

      for (j=0; j<wide; j++)
	printf("%d %d %d\n",r,g,b);
    }
  }
}




\BARFOO\
else
  echo "will not over write ./bggen.c"
fi
if `test ! -s ./vprintf.c`
then
echo "writting ./vprintf.c"
cat > ./vprintf.c << '\BARFOO\'
#ifdef NEED_VPRINTF

#include <stdio.h>

/* Portable vsprintf  by Robert A. Larson <blarson@skat.usc.edu> */
/* Portable vfprintf  by Robert A. Larson <blarson@skat.usc.edu> */

/* Copyright 1989 Robert A. Larson.
 * Distribution in any form is allowed as long as the author
 * retains credit, changes are noted by their author and the
 * copyright message remains intact.  This program comes as-is
 * with no warentee of fitness for any purpouse.
 *
 * Thanks to Doug Gwen, Chris Torek, and others who helped clarify
 * the ansi printf specs.
 *
 * Please send any bug fixes and improvments to blarson@skat.usc.edu .
 * The use of goto is NOT a bug.
 */

/* Feb	7, 1989		blarson		First usenet release */

/* This code implements the vsprintf function, without relying on
 * the existance of _doprint or other system specific code.
 *
 * Define NOVOID if void * is not a supported type.
 *
 * Two compile options are available for efficency:
 *	INTSPRINTF	should be defined if sprintf is int and returns
 *			the number of chacters formated.
 *	LONGINT		should be defined if sizeof(long) == sizeof(int)
 *
 *	They only make the code smaller and faster, they need not be
 *	defined.
 *
 * UNSIGNEDSPECIAL should be defined if unsigned is treated differently
 * than int in argument passing.  If this is definded, and LONGINT is not,
 * the compiler must support the type unsingned long.
 *
 * Most quirks and bugs of the available sprintf fuction are duplicated,
 * however * in the width and precision fields will work correctly
 * even if sprintf does not support this, as will the n format.
 *
 * Bad format strings, or those with very long width and precision
 * fields (including expanded * fields) will cause undesired results.
 */

#ifdef OSK		/* os9/68k can take advantage of both */
#define LONGINT
#define INTSPRINTF
#endif

/* This must be a typedef not a #define! */
#ifdef NOVOID
typedef char *pointer;
#else
typedef void *pointer;
#endif

#ifdef	INTSPRINTF
#define Sprintf(string,format,arg)	(sprintf((string),(format),(arg)))
#else
#define Sprintf(string,format,arg)	(\
	sprintf((string),(format),(arg)),\
	strlen(string)\
)
#endif

#if defined(__STDC__) && !defined(NOSTDHDRS)
#include <stdarg.h>
#else
#include <varargs.h>
#endif

typedef int *intp;

int vsprintf(dest, format, args)
char *dest;
register char *format;
va_list args;
{
    register char *dp = dest;
    register char c;
    register char *tp;
    char tempfmt[64];
#ifndef LONGINT
    int longflag;
#endif

    tempfmt[0] = '%';
    while( (c = *format++) != 0) {
	if(c=='%') {
	    tp = &tempfmt[1];
#ifndef LONGINT
	    longflag = 0;
#endif
continue_format:
	    switch(c = *format++) {
		case 's':
		    *tp++ = c;
		    *tp = '\0';
		    dp += Sprintf(dp, tempfmt, va_arg(args, char *));
		    break;
		case 'u':
		case 'x':
		case 'o':
		case 'X':
#ifdef UNSIGNEDSPECIAL
		    *tp++ = c;
		    *tp = '\0';
#ifndef LONGINT
		    if(longflag)
			dp += Sprintf(dp, tempfmt, va_arg(args, unsigned long));
		    else
#endif
			dp += Sprintf(dp, tempfmt, va_arg(args, unsigned));
		    break;
#endif
		case 'd':
		case 'c':
		case 'i':
		    *tp++ = c;
		    *tp = '\0';
#ifndef LONGINT
		    if(longflag)
			dp += Sprintf(dp, tempfmt, va_arg(args, long));
		    else
#endif
			dp += Sprintf(dp, tempfmt, va_arg(args, int));
		    break;
		case 'f':
		case 'e':
		case 'E':
		case 'g':
		case 'G':
		    *tp++ = c;
		    *tp = '\0';
		    dp += Sprintf(dp, tempfmt, va_arg(args, double));
		    break;
		case 'p':
		    *tp++ = c;
		    *tp = '\0';
		    dp += Sprintf(dp, tempfmt, va_arg(args, pointer));
		    break;
		case '-':
		case '+':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case '.':
		case ' ':
		case '#':
		case 'h':
		    *tp++ = c;
		    goto continue_format;
		case 'l':
#ifndef LONGINT
		    longflag = 1;
		    *tp++ = c;
#endif
		    goto continue_format;
		case '*':
		    tp += Sprintf(tp, "%d", va_arg(args, int));
		    goto continue_format;
		case 'n':
		    *va_arg(args, intp) = dp - dest;
		    break;
		case '%':
		default:
		    *dp++ = c;
		    break;
	    }
	} else *dp++ = c;
    }
    *dp = '\0';
    return dp - dest;
}


int vfprintf(dest, format, args)
FILE *dest;
register char *format;
va_list args;
{
    register char c;
    register char *tp;
    register int count = 0;
    char tempfmt[64];
#ifndef LONGINT
    int longflag;
#endif

    tempfmt[0] = '%';
    while(c = *format++) {
	if(c=='%') {
	    tp = &tempfmt[1];
#ifndef LONGINT
	    longflag = 0;
#endif
continue_format:
	    switch(c = *format++) {
		case 's':
		    *tp++ = c;
		    *tp = '\0';
		    count += fprintf(dest, tempfmt, va_arg(args, char *));
		    break;
		case 'u':
		case 'x':
		case 'o':
		case 'X':
#ifdef UNSIGNEDSPECIAL
		    *tp++ = c;
		    *tp = '\0';
#ifndef LONGINT
		    if(longflag)
			count += fprintf(dest, tempfmt, va_arg(args, unsigned long));
		    else
#endif
			count += fprintf(dest, tempfmt, va_arg(args, unsigned));
		    break;
#endif
		case 'd':
		case 'c':
		case 'i':
		    *tp++ = c;
		    *tp = '\0';
#ifndef LONGINT
		    if(longflag)
			count += fprintf(dest, tempfmt, va_arg(args, long));
		    else
#endif
			count += fprintf(dest, tempfmt, va_arg(args, int));
		    break;
		case 'f':
		case 'e':
		case 'E':
		case 'g':
		case 'G':
		    *tp++ = c;
		    *tp = '\0';
		    count += fprintf(dest, tempfmt, va_arg(args, double));
		    break;
		case 'p':
		    *tp++ = c;
		    *tp = '\0';
		    count += fprintf(dest, tempfmt, va_arg(args, pointer));
		    break;
		case '-':
		case '+':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case '.':
		case ' ':
		case '#':
		case 'h':
		    *tp++ = c;
		    goto continue_format;
		case 'l':
#ifndef LONGINT
		    longflag = 1;
		    *tp++ = c;
#endif
		    goto continue_format;
		case '*':
		    tp += Sprintf(tp, "%d", va_arg(args, int));
		    goto continue_format;
		case 'n':
		    *va_arg(args, intp) = count;
		    break;
		case '%':
		default:
		    putc(c, dest);
		    count++;
		    break;
	    }
	} else {
	    putc(c, dest);
	    count++;
	}
    }
    return count;
}

vprintf(format, args)
char *format;
va_list args;
{
    return vfprintf(stdout, format, args);
}

#endif
\BARFOO\
else
  echo "will not over write ./vprintf.c"
fi
echo "Finished archive 10 of 10"
exit

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