/* libpbm1.c - pbm utility library part 1 ** ** Copyright (C) 1988 by Jef Poskanzer. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #include "pbm.h" #include "version.h" #include "libpbm.h" #include #include /* Forward routines. */ #if defined(NEED_VFPRINTF1) || defined(NEED_VFPRINTF2) int vfprintf( FILE* stream, char* format, va_list args ); #endif /*NEED_VFPRINTF*/ /* Variable-sized arrays. */ char* pm_allocrow( int cols, int size ) { char* itrow; itrow = (char*) malloc( cols * size ); if ( itrow == (char*) 0 ) pm_error( "out of memory allocating a row" ); return itrow; } void pm_freerow( char* itrow ) { free( itrow ); } char** pm_allocarray( int cols, int rows, int size ) { char** its; int i; its = (char**) malloc( rows * sizeof(char*) ); if ( its == (char**) 0 ) pm_error( "out of memory allocating an array" ); its[0] = (char*) malloc( rows * cols * size ); if ( its[0] == (char*) 0 ) pm_error( "out of memory allocating an array" ); for ( i = 1; i < rows; ++i ) its[i] = &(its[0][i * cols * size]); return its; } void pm_freearray( char** its, int rows ) { free( its[0] ); free( its ); } /* Case-insensitive keyword matcher. */ int pm_keymatch( char* str, char* keyword, int minchars ) { int len; len = strlen( str ); if ( len < minchars ) return 0; while ( --len >= 0 ) { char c1, c2; c1 = *str++; c2 = *keyword++; if ( c2 == '\0' ) return 0; if ( isupper( c1 ) ) c1 = tolower( c1 ); if ( isupper( c2 ) ) c2 = tolower( c2 ); if ( c1 != c2 ) return 0; } return 1; } /* Log base two hacks. */ int pm_maxvaltobits( int maxval ) { if ( maxval <= 1 ) return 1; else if ( maxval <= 3 ) return 2; else if ( maxval <= 7 ) return 3; else if ( maxval <= 15 ) return 4; else if ( maxval <= 31 ) return 5; else if ( maxval <= 63 ) return 6; else if ( maxval <= 127 ) return 7; else if ( maxval <= 255 ) return 8; else if ( maxval <= 511 ) return 9; else if ( maxval <= 1023 ) return 10; else if ( maxval <= 2047 ) return 11; else if ( maxval <= 4095 ) return 12; else if ( maxval <= 8191 ) return 13; else if ( maxval <= 16383 ) return 14; else if ( maxval <= 32767 ) return 15; else if ( (long) maxval <= 65535L ) return 16; else pm_error( "maxval of %d is too large!", maxval ); } int pm_bitstomaxval( int bits ) { return ( 1 << bits ) - 1; } /* Initialization. */ static char* progname; static int showmessages; void pm_init( int* argcP, char* argv[] ) { int argn, i; /* Extract program name. */ progname = rindex( argv[0], '/'); if ( progname == NULL ) progname = argv[0]; else ++progname; /* Check for any global args. */ showmessages = 1; for ( argn = 1; argn < *argcP; ++argn ) { if ( pm_keymatch( argv[argn], "-quiet", 6 ) ) { showmessages = 0; } else if ( pm_keymatch( argv[argn], "-version", 7 ) ) { pm_message( "Version of %s", PBMPLUS_VERSION ); #ifdef BSD pm_message( "BSD defined" ); #endif /*BSD*/ #ifdef SYSV pm_message( "SYSV defined" ); #endif /*SYSV*/ #ifdef MSDOS pm_message( "MSDOS defined" ); #endif /*MSDOS*/ #ifdef PBMPLUS_BROKENPUTC1 pm_message( "PBMPLUS_BROKENPUTC1 defined" ); #endif /*PBMPLUS_BROKENPUTC1*/ #ifdef PBMPLUS_BROKENPUTC2 pm_message( "PBMPLUS_BROKENPUTC2 defined" ); #endif /*PBMPLUS_BROKENPUTC2*/ #ifdef PGM_BIGGRAYS pm_message( "PGM_BIGGRAYS defined" ); #endif /*PGM_BIGGRAYS*/ #ifdef DEBUG pm_message( "DEBUG defined" ); #endif /*DEBUG*/ #ifdef NEED_VFPRINTF1 pm_message( "NEED_VFPRINTF1 defined" ); #endif /*NEED_VFPRINTF1*/ #ifdef NEED_VFPRINTF2 pm_message( "NEED_VFPRINTF2 defined" ); #endif /*NEED_VFPRINTF2*/ #ifdef RGB_DB pm_message( "RGB_DB=\"%s\"", RGB_DB ); #endif /*RGB_DB*/ #ifdef LIBTIFF pm_message( "LIBTIFF defined" ); #endif /*LIBTIFF*/ exit( 0 ); } else continue; for ( i = argn + 1; i <= *argcP; ++i ) argv[i - 1] = argv[i]; --(*argcP); } } void pbm_init( int* argcP, char* argv[] ) { pm_init( argcP, argv ); } /* Error handling. */ void pm_usage( char* usage ) { fprintf( stderr, "usage: %s %s\n", progname, usage ); exit( 1 ); } void pm_perror( char* reason ) { const char* e; e = sys_errlist[errno]; if ( reason != 0 && reason[0] != '\0' ) pm_error( "%s - %s", reason, e ); else pm_error( "%s", e ); } void pm_message( char* format, ... ) { va_list args; va_start( args, format ); if ( showmessages ) { fprintf( stderr, "%s: ", progname ); (void) vfprintf( stderr, format, args ); fputc( '\n', stderr ); } va_end( args ); } void pm_error( char* format, ... ) { va_list args; va_start( args, format ); fprintf( stderr, "%s: ", progname ); (void) vfprintf( stderr, format, args ); fputc( '\n', stderr ); va_end( args ); exit( 1 ); } #ifdef NEED_VFPRINTF1 /* Micro-vfprintf, for systems that don't have vfprintf but do have _doprnt. */ int vfprintf( FILE* stream, char* format, va_list args ) { return _doprnt( format, args, stream ); } #endif /*NEED_VFPRINTF1*/ #ifdef NEED_VFPRINTF2 /* Portable mini-vfprintf, for systems that don't have either vfprintf or ** _doprnt. This depends only on fprintf. If you don't have fprintf, ** you might consider getting a new stdio library. */ int vfprintf( FILE* stream, char* format, va_list args ) { int n; char* ep; char fchar; char tformat[512]; int do_long; int i; long l; unsigned u; unsigned long ul; char* s; double d; n = 0; while ( *format != '\0' ) { if ( *format != '%' ) { /* Not special, just write out the char. */ (void) putc( *format, stream ); ++n; ++format; } else { do_long = 0; ep = format + 1; /* Skip over all the field width and precision junk. */ if ( *ep == '-' ) ++ep; if ( *ep == '0' ) ++ep; while ( isdigit( *ep ) ) ++ep; if ( *ep == '.' ) { ++ep; while ( isdigit( *ep ) ) ++ep; } if ( *ep == '#' ) ++ep; if ( *ep == 'l' ) { do_long = 1; ++ep; } /* Here's the field type. Extract it, and copy this format ** specifier to a temp string so we can add an end-of-string. */ fchar = *ep; (void) strncpy( tformat, format, ep - format + 1 ); tformat[ep - format + 1] = '\0'; /* Now do a one-argument fprintf with the format string we have ** isolated. */ switch ( fchar ) { case 'd': if ( do_long ) { l = va_arg( args, long ); n += fprintf( stream, tformat, l ); } else { i = va_arg( args, int ); n += fprintf( stream, tformat, i ); } break; case 'o': case 'x': case 'X': case 'u': if ( do_long ) { ul = va_arg( args, unsigned long ); n += fprintf( stream, tformat, ul ); } else { u = va_arg( args, unsigned ); n += fprintf( stream, tformat, u ); } break; case 'c': i = (char) va_arg( args, int ); n += fprintf( stream, tformat, i ); break; case 's': s = va_arg( args, char* ); n += fprintf( stream, tformat, s ); break; case 'e': case 'E': case 'f': case 'g': case 'G': d = va_arg( args, double ); n += fprintf( stream, tformat, d ); break; case '%': (void) putc( '%', stream ); ++n; break; default: return -1; } /* Resume formatting on the next character. */ format = ep + 1; } } return nc; } #endif /*NEED_VFPRINTF2*/ /* File open/close that handles "-" as stdin and checks errors. */ FILE* pm_openr( char* name ) { FILE* f; if ( strcmp( name, "-" ) == 0 ) f = stdin; else { #ifdef MSDOS f = fopen( name, "rb" ); #else /*MSDOS*/ f = fopen( name, "r" ); #endif /*MSDOS*/ if ( f == NULL ) pm_perror( name ); } return f; } FILE* pm_openw( char* name ) { FILE* f; #ifdef MSDOS f = fopen( name, "wb" ); #else /*MSDOS*/ f = fopen( name, "w" ); #endif /*MSDOS*/ if ( f == NULL ) pm_perror( name ); return f; } void pm_closer( FILE* f ) { if ( ferror( f ) ) pm_message( "a file read error occurred at some point" ); if ( f != stdin ) if ( fclose( f ) != 0 ) pm_perror( "fclose" ); } void pm_closew( FILE* f ) { fflush( f ); if ( ferror( f ) ) pm_message( "a file write error occurred at some point" ); if ( f != stdout ) if ( fclose( f ) != 0 ) pm_perror( "fclose" ); } /* Endian I/O. */ int pm_readbigshort( FILE* in, unsigned short* sP ) { int c; if ( (c = getc( in )) == EOF ) return -1; *sP = ( c & 0xff ) << 8; if ( (c = getc( in )) == EOF ) return -1; *sP |= c & 0xff; return 0; } int pm_writebigshort( FILE* out, unsigned short s ) { (void) putc( ( s >> 8 ) & 0xff, out ); (void) putc( s & 0xff, out ); return 0; } int pm_readbiglong( FILE* in, unsigned long* lP ) { int c; if ( (c = getc( in )) == EOF ) return -1; *lP = ( c & 0xff ) << 24; if ( (c = getc( in )) == EOF ) return -1; *lP |= ( c & 0xff ) << 16; if ( (c = getc( in )) == EOF ) return -1; *lP |= ( c & 0xff ) << 8; if ( (c = getc( in )) == EOF ) return -1; *lP |= c & 0xff; return 0; } int pm_writebiglong( FILE* out, unsigned long l ) { (void) putc( ( l >> 24 ) & 0xff, out ); (void) putc( ( l >> 16 ) & 0xff, out ); (void) putc( ( l >> 8 ) & 0xff, out ); (void) putc( l & 0xff, out ); return 0; } int pm_readlittleshort( FILE* in, unsigned short* sP ) { int c; if ( (c = getc( in )) == EOF ) return -1; *sP = c & 0xff; if ( (c = getc( in )) == EOF ) return -1; *sP |= ( c & 0xff ) << 8; return 0; } int pm_writelittleshort( FILE* out, unsigned short s ) { (void) putc( s & 0xff, out ); (void) putc( ( s >> 8 ) & 0xff, out ); return 0; } int pm_readlittlelong( FILE* in, unsigned long* lP ) { int c; if ( (c = getc( in )) == EOF ) return -1; *lP = c & 0xff; if ( (c = getc( in )) == EOF ) return -1; *lP |= ( c & 0xff ) << 8; if ( (c = getc( in )) == EOF ) return -1; *lP |= ( c & 0xff ) << 16; if ( (c = getc( in )) == EOF ) return -1; *lP |= ( c & 0xff ) << 24; return 0; } int pm_writelittlelong( FILE* out, unsigned long l ) { (void) putc( l & 0xff, out ); (void) putc( ( l >> 8 ) & 0xff, out ); (void) putc( ( l >> 16 ) & 0xff, out ); (void) putc( ( l >> 24 ) & 0xff, out ); return 0; } /* Convenience routine to read an entire file into a malloced area. */ char* pm_read_whole_file( FILE* in, long* sizeP ) { long maxsize, size; char* buf; int r; maxsize = 10000; /* arbitrary */ buf = malloc( maxsize ); if ( buf == (char*) 0 ) pm_error( "out of memory reading in a file" ); size = 0; for ( ; ; ) { r = fread( &buf[size], 1, maxsize - size, in ); if ( r < 0 ) pm_perror( "reading in a file" ); if ( r == 0 ) break; size += r; if ( size == maxsize ) { maxsize *= 2; buf = realloc( buf, maxsize ); if ( buf == (char*) 0 ) pm_error( "out of memory reading in a file" ); } } if ( sizeP != (long*) 0 ) *sizeP = size; return buf; }