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