home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / NETWORK / netpbm_src.lzh / NETPBM / PBM / libpbm1.c.orig < prev    next >
Text File  |  1996-11-18  |  36KB  |  1,552 lines

  1. /* libpbm1.c - pbm utility library part 1
  2. **
  3. ** Copyright (C) 1988 by Jef Poskanzer.
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. */
  12.  
  13. #include "pbm.h"
  14. #include "version.h"
  15. #include "compile.h"
  16. #include "libpbm.h"
  17. #if __STDC__
  18. #include <stdarg.h>
  19. #else /*__STDC__*/
  20. #include <varargs.h>
  21. #endif /*__STDC__*/
  22.  
  23.  
  24. /* Variable-sized arrays. */
  25.  
  26. char*
  27. pm_allocrow( cols, size )
  28.     int cols;
  29.     int size;
  30.     {
  31.     register char* itrow;
  32.  
  33.     itrow = (char*) malloc( cols * size );
  34.     if ( itrow == (char*) 0 )
  35.         pm_error( "out of memory allocating a row" );
  36.     return itrow;
  37.     }
  38.  
  39. void
  40. pm_freerow( itrow )
  41.     char* itrow;
  42.     {
  43.     free( itrow );
  44.     }
  45.  
  46.  
  47. #ifndef A_FRAGARRAY
  48. char**
  49. pm_allocarray( cols, rows, size )
  50.     int cols, rows;
  51.     int size;
  52.     {
  53.     char** its;
  54.     int i;
  55.  
  56.     its = (char**) malloc( rows * sizeof(char*) );
  57.     if ( its == (char**) 0 )
  58.         pm_error( "out of memory allocating an array" );
  59.     its[0] = (char*) malloc( rows * cols * size );
  60.     if ( its[0] == (char*) 0 )
  61.         pm_error( "out of memory allocating an array" );
  62.     for ( i = 1; i < rows; ++i )
  63.         its[i] = &(its[0][i * cols * size]);
  64.     return its;
  65.     }
  66.  
  67. void
  68. pm_freearray( its, rows )
  69.     char** its;
  70.     int rows;
  71.     {
  72.     free( its[0] );
  73.     free( its );
  74.     }
  75. #else /* A_FRAGARRAY */
  76. char**
  77. pm_allocarray( cols, rows, size )
  78.     int cols, rows;
  79.     int size;
  80.     {
  81.     char** its;
  82.     int i;
  83.     its = (char**) malloc( (rows + 1) * sizeof(char*) );
  84.     if ( its == (char**) 0 )
  85.         pm_error( "out of memory allocating an array" );
  86.     its[rows] = its[0] = (char*) malloc( rows * cols * size );
  87.     if ( its[0] != (char*) 0 )
  88.         for ( i = 1; i < rows; ++i )
  89.             its[i] = &(its[0][i * cols * size]);
  90.     else
  91.         for( i = 0; i < rows; ++i )
  92.             its[i] = pm_allocrow( cols, size );
  93.     return its;
  94.     }
  95. void
  96. pm_freearray( its, rows )
  97.     char** its;
  98.     int rows;
  99.     {
  100.     int i;
  101.     if( its[rows] != (char*) 0 )
  102.         free( its[rows] );
  103.     else
  104.         for( i = 0; i < rows; ++i )
  105.             pm_freerow( its[i] );
  106.     free( its );
  107.     }
  108. #endif /* A_FRAGARRAY */
  109.  
  110.  
  111. /* Case-insensitive keyword matcher. */
  112.  
  113. int
  114. pm_keymatch( str, keyword, minchars )
  115.     char* str;
  116.     char* keyword;
  117.     int minchars;
  118.     {
  119.     register int len;
  120.  
  121.     len = strlen( str );
  122.     if ( len < minchars )
  123.         return 0;
  124.     while ( --len >= 0 )
  125.         {
  126.         register char c1, c2;
  127.  
  128.         c1 = *str++;
  129.         c2 = *keyword++;
  130.         if ( c2 == '\0' )
  131.             return 0;
  132.         if ( isupper( c1 ) )
  133.             c1 = tolower( c1 );
  134.         if ( isupper( c2 ) )
  135.             c1 = tolower( c2 );
  136.         if ( c1 != c2 )
  137.             return 0;
  138.         }
  139.     return 1;
  140.     }
  141.  
  142.  
  143. /* Log base two hacks. */
  144.  
  145. int
  146. pm_maxvaltobits( maxval )
  147.     int maxval;
  148.     {
  149.     if ( maxval <= 1 )
  150.         return 1;
  151.     else if ( maxval <= 3 )
  152.         return 2;
  153.     else if ( maxval <= 7 )
  154.         return 3;
  155.     else if ( maxval <= 15 )
  156.         return 4;
  157.     else if ( maxval <= 31 )
  158.         return 5;
  159.     else if ( maxval <= 63 )
  160.         return 6;
  161.     else if ( maxval <= 127 )
  162.         return 7;
  163.     else if ( maxval <= 255 )
  164.         return 8;
  165.     else if ( maxval <= 511 )
  166.         return 9;
  167.     else if ( maxval <= 1023 )
  168.         return 10;
  169.     else if ( maxval <= 2047 )
  170.         return 11;
  171.     else if ( maxval <= 4095 )
  172.         return 12;
  173.     else if ( maxval <= 8191 )
  174.         return 13;
  175.     else if ( maxval <= 16383 )
  176.         return 14;
  177.     else if ( maxval <= 32767 )
  178.         return 15;
  179.     else if ( (long) maxval <= 65535L )
  180.         return 16;
  181.     else
  182.         pm_error( "maxval of %d is too large!", maxval );
  183.     }
  184.  
  185. int
  186. pm_bitstomaxval( bits )
  187.     int bits;
  188.     {
  189.     return ( 1 << bits ) - 1;
  190.     }
  191.  
  192.  
  193. /* Initialization. */
  194.  
  195. static char* progname;
  196. static int showmessages;
  197.  
  198. void
  199. pm_init( argcP, argv )
  200.     int* argcP;
  201.     char* argv[];
  202.     {
  203.     int argn, i;
  204. #ifdef A_RGBENV
  205.     char *rgbdef;
  206. #endif /* A_RGBENV */
  207.  
  208. #ifndef VMS
  209.     /* Extract program name. */
  210.     progname = rindex( argv[0], '/');
  211. #else
  212. {   char **temp_argv = argv;
  213.     int old_argc = *argcP;
  214.     int i;
  215.     getredirection( argcP, &temp_argv );
  216.     if (*argcP > old_argc) {
  217.         /* Number of command line arguments has increased */
  218.         fprintf( stderr, "Sorry!! getredirection() for VMS has changed the argument list!!!\n");
  219.         fprintf( stderr, "This is intolerable at the present time, so we must stop!!!\n");
  220.         exit(1);
  221.     }
  222.     for (i=0; i<*argcP; i++)
  223.         argv[i] = temp_argv[i];
  224.     }
  225.     if ( progname == NULL ) progname = rindex( argv[0], ']');
  226.     if ( progname == NULL ) progname = rindex( argv[0], '>');
  227. #endif
  228.     if ( progname == NULL )
  229.         progname = argv[0];
  230.     else
  231.         ++progname;
  232.  
  233.     /* Check for any global args. */
  234.     showmessages = 1;
  235.     for ( argn = 1; argn < *argcP; ++argn )
  236.         {
  237.         if ( pm_keymatch( argv[argn], "-quiet", 6 ) )
  238.             {
  239.             showmessages = 0;
  240.             }
  241.         else if ( pm_keymatch( argv[argn], "-version", 7 ) )
  242.             {
  243.             pm_message( "Version: %s", PBMPLUS_VERSION );
  244. #if defined(COMPILE_TIME) && defined(COMPILED_BY)
  245.         pm_message( "Compiled %s by user \"%s\"",
  246.                COMPILE_TIME, COMPILED_BY );
  247. #endif
  248. #ifdef BSD
  249.             pm_message( "BSD defined" );
  250. #endif /*BSD*/
  251. #ifdef SYSV
  252. #ifdef VMS
  253.         pm_message( "VMS & SYSV defined" );
  254. #else
  255.           pm_message( "SYSV defined" );
  256. #endif
  257. #endif /*SYSV*/
  258. #ifdef MSDOS
  259.             pm_message( "MSDOS defined" );
  260. #endif /*MSDOS*/
  261. #ifdef AMIGA
  262.             pm_message( "AMIGA defined" );
  263. #endif /* AMIGA */
  264. #ifdef PBMPLUS_RAWBITS
  265.             pm_message( "PBMPLUS_RAWBITS defined" );
  266. #endif /*PBMPLUS_RAWBITS*/
  267. #ifdef PBMPLUS_BROKENPUTC1
  268.             pm_message( "PBMPLUS_BROKENPUTC1 defined" );
  269. #endif /*PBMPLUS_BROKENPUTC1*/
  270. #ifdef PBMPLUS_BROKENPUTC2
  271.             pm_message( "PBMPLUS_BROKENPUTC2 defined" );
  272. #endif /*PBMPLUS_BROKENPUTC2*/
  273. #ifdef PGM_BIGGRAYS
  274.             pm_message( "PGM_BIGGRAYS defined" );
  275. #endif /*PGM_BIGGRAYS*/
  276. #ifdef PPM_PACKCOLORS
  277.             pm_message( "PPM_PACKCOLORS defined" );
  278. #endif /*PPM_PACKCOLORS*/
  279. #ifdef DEBUG
  280.             pm_message( "DEBUG defined" );
  281. #endif /*DEBUG*/
  282. #ifdef NEED_VFPRINTF1
  283.             pm_message( "NEED_VFPRINTF1 defined" );
  284. #endif /*NEED_VFPRINTF1*/
  285. #ifdef NEED_VFPRINTF2
  286.             pm_message( "NEED_VFPRINTF2 defined" );
  287. #endif /*NEED_VFPRINTF2*/
  288. #ifdef RGB_DB
  289. #ifndef A_RGBENV
  290.             pm_message( "RGB_DB=\"%s\"", RGB_DB );
  291. #else /* A_RGBENV */
  292.             if( rgbdef = getenv(RGB_DB) )
  293.                 pm_message( "RGB_DB= Env-var %s (set to \"%s\")", RGB_DB, rgbdef );
  294.             else
  295.                 pm_message( "RGB_DB= Env-var %s (unset)", RGB_DB );
  296. #endif /* A_RGBENV */
  297. #endif /*RGB_DB*/
  298. #ifdef LIBTIFF
  299.             pm_message( "LIBTIFF defined" );
  300. #endif /*LIBTIFF*/
  301.             exit( 0 );
  302.             }
  303.         else
  304.             continue;
  305.         for ( i = argn + 1; i <= *argcP; ++i )
  306.             argv[i - 1] = argv[i];
  307.         --(*argcP);
  308.         }
  309.     }
  310.  
  311. void
  312. pbm_init( argcP, argv )
  313.     int* argcP;
  314.     char* argv[];
  315.     {
  316.     pm_init( argcP, argv );
  317.     }
  318.  
  319.  
  320. /* Error handling. */
  321.  
  322. void
  323. pm_usage( usage )
  324.     char* usage;
  325.     {
  326.     fprintf( stderr, "usage:  %s %s\n", progname, usage );
  327.     exit( 1 );
  328.     }
  329.  
  330. void
  331. pm_perror( reason )
  332.     char* reason;
  333.     {
  334. #ifndef A_STRERROR
  335.     extern char* sys_errlist[];
  336. #endif /* A_STRERROR */
  337.     extern int errno;
  338.     char* e;
  339.  
  340. #ifdef A_STRERROR
  341.     e = strerror(errno);
  342. #else /* A_STRERROR */
  343.     e = sys_errlist[errno];
  344. #endif /* A_STRERROR */
  345.  
  346.     if ( reason != 0 && reason[0] != '\0' )
  347.         pm_error( "%s - %s", reason, e );
  348.     else
  349.         pm_error( "%s", e );
  350.     }
  351.  
  352. #if __STDC__
  353. void
  354. pm_message( char* format, ... )
  355.     {
  356.     va_list args;
  357.  
  358.     va_start( args, format );
  359. #else /*__STDC__*/
  360. /*VARARGS1*/
  361. void
  362. pm_message( va_alist )
  363.     va_dcl
  364.     { /*}*/
  365.     va_list args;
  366.     char* format;
  367.  
  368.     va_start( args );
  369.     format = va_arg( args, char* );
  370. #endif /*__STDC__*/
  371.  
  372.     if ( showmessages )
  373.         {
  374.         fprintf( stderr, "%s: ", progname );
  375.         (void) vfprintf( stderr, format, args );
  376.         fputc( '\n', stderr );
  377.         }
  378.     va_end( args );
  379.     }
  380.  
  381. #if __STDC__
  382. void
  383. pm_error( char* format, ... )
  384.     {
  385.     va_list args;
  386.  
  387.     va_start( args, format );
  388. #else /*__STDC__*/
  389. /*VARARGS1*/
  390. void
  391. pm_error( va_alist )
  392.     va_dcl
  393.     { /*}*/
  394.     va_list args;
  395.     char* format;
  396.  
  397.     va_start( args );
  398.     format = va_arg( args, char* );
  399. #endif /*__STDC__*/
  400.  
  401.     fprintf( stderr, "%s: ", progname );
  402.     (void) vfprintf( stderr, format, args );
  403.     fputc( '\n', stderr );
  404.     va_end( args );
  405.     exit( 1 );
  406.     }
  407.  
  408. #ifdef NEED_VFPRINTF1
  409.  
  410. /* Micro-vfprintf, for systems that don't have vfprintf but do have _doprnt.
  411. */
  412.  
  413. int
  414. vfprintf( stream, format, args )
  415.     FILE* stream;
  416.     char* format;
  417.     va_list args;
  418.     {
  419.     return _doprnt( format, args, stream );
  420.     }
  421. #endif /*NEED_VFPRINTF1*/
  422.  
  423. #ifdef NEED_VFPRINTF2
  424.  
  425. /* Portable mini-vfprintf, for systems that don't have either vfprintf or
  426. ** _doprnt.  This depends only on fprintf.  If you don't have fprintf,
  427. ** you might consider getting a new stdio library.
  428. */
  429.  
  430. int
  431. vfprintf( stream, format, args )
  432.     FILE* stream;
  433.     char* format;
  434.     va_list args;
  435.     {
  436.     int n;
  437.     char* ep;
  438.     char fchar;
  439.     char tformat[512];
  440.     int do_long;
  441.     int i;
  442.     long l;
  443.     unsigned u;
  444.     unsigned long ul;
  445.     char* s;
  446.     double d;
  447.  
  448.     n = 0;
  449.     while ( *format != '\0' )
  450.         {
  451.         if ( *format != '%' )
  452.             { /* Not special, just write out the char. */
  453.             (void) putc( *format, stream );
  454.             ++n;
  455.             ++format;
  456.             }
  457.         else
  458.             {
  459.             do_long = 0;
  460.             ep = format + 1;
  461.  
  462.             /* Skip over all the field width and precision junk. */
  463.             if ( *ep == '-' )
  464.                 ++ep;
  465.             if ( *ep == '0' )
  466.                 ++ep;
  467.             while ( isdigit( *ep ) )
  468.                 ++ep;
  469.             if ( *ep == '.' )
  470.                 {
  471.                 ++ep;
  472.                 while ( isdigit( *ep ) )
  473.                     ++ep;
  474.                 }
  475.             if ( *ep == '#' )
  476.                 ++ep;
  477.             if ( *ep == 'l' )
  478.                 {
  479.                 do_long = 1;
  480.                 ++ep;
  481.                 }
  482.  
  483.             /* Here's the field type.  Extract it, and copy this format
  484.             ** specifier to a temp string so we can add an end-of-string.
  485.             */
  486.             fchar = *ep;
  487.             (void) strncpy( tformat, format, ep - format + 1 );
  488.             tformat[ep - format + 1] = '\0';
  489.  
  490.             /* Now do a one-argument fprintf with the format string we have
  491.             ** isolated.
  492.             */
  493.             switch ( fchar )
  494.                 {
  495.                 case 'd':
  496.                 if ( do_long )
  497.                     {
  498.                     l = va_arg( args, long );
  499.                     n += fprintf( stream, tformat, l );
  500.                     }
  501.                 else
  502.                     {
  503.                     i = va_arg( args, int );
  504.                     n += fprintf( stream, tformat, i );
  505.                     }
  506.                 break;
  507.  
  508.                 case 'o':
  509.                 case 'x':
  510.                 case 'X':
  511.                 case 'u':
  512.                 if ( do_long )
  513.                     {
  514.                     ul = va_arg( args, unsigned long );
  515.                     n += fprintf( stream, tformat, ul );
  516.                     }
  517.                 else
  518.                     {
  519.                     u = va_arg( args, unsigned );
  520.                     n += fprintf( stream, tformat, u );
  521.                     }
  522.                 break;
  523.  
  524.                 case 'c':
  525.                 i = (char) va_arg( args, int );
  526.                 n += fprintf( stream, tformat, i );
  527.                 break;
  528.  
  529.                 case 's':
  530.                 s = va_arg( args, char* );
  531.                 n += fprintf( stream, tformat, s );
  532.                 break;
  533.  
  534.                 case 'e':
  535.                 case 'E':
  536.                 case 'f':
  537.                 case 'g':
  538.                 case 'G':
  539.                 d = va_arg( args, double );
  540.                 n += fprintf( stream, tformat, d );
  541.                 break;
  542.  
  543.                 case '%':
  544.                 (void) putc( '%', stream );
  545.                 ++n;
  546.                 break;
  547.  
  548.                 default:
  549.                 return -1;
  550.                 }
  551.  
  552.             /* Resume formatting on the next character. */
  553.             format = ep + 1;
  554.             }
  555.         }
  556.     return nc;
  557.     }
  558. #endif /*NEED_VFPRINTF2*/
  559.  
  560. #ifdef NEED_STRSTR
  561. /* for systems which do not provide strstr */
  562. char*
  563. strstr(s1, s2)
  564.     char *s1, *s2;
  565. {
  566.     int ls2 = strlen(s2);
  567.  
  568.     if (ls2 == 0)
  569.         return (s1);
  570.     while (strlen(s1) >= ls2) {
  571.         if (strncmp(s1, s2, ls2) == 0)
  572.             return (s1);
  573.         s1++;
  574.     }
  575.     return (0);
  576. }
  577.  
  578. #endif /*NEED_STRSTR*/
  579.  
  580.  
  581. /* File open/close that handles "-" as stdin and checks errors. */
  582.  
  583. FILE*
  584. pm_openr( name )
  585.     char* name;
  586.     {
  587.     FILE* f;
  588.  
  589.     if ( strcmp( name, "-" ) == 0 )
  590.         f = stdin;
  591.     else
  592.         {
  593. #ifdef MSDOS
  594.         f = fopen( name, "rb" );
  595. #else /*MSDOS*/
  596. #ifndef VMS
  597.       f = fopen( name, "r" );
  598. #else
  599.     f = fopen ( name, "r", "ctx=stm" );
  600. #endif
  601. #endif /*MSDOS*/
  602.         if ( f == NULL )
  603.             {
  604.             pm_perror( name );
  605.             exit( 1 );
  606.             }
  607.         }
  608.     return f;
  609.     }
  610.  
  611. FILE*
  612. pm_openw( name )
  613.     char* name;
  614.     {
  615.     FILE* f;
  616.  
  617. #ifdef MSDOS
  618.     f = fopen( name, "wb" );
  619. #else /*MSDOS*/
  620. #ifndef VMS
  621.     f = fopen( name, "w" );
  622. #else
  623.     f = fopen ( name, "w", "mbc=32", "mbf=2" );  /* set buffer factors */
  624. #endif
  625. #endif /*MSDOS*/
  626.     if ( f == NULL )
  627.         {
  628.         pm_perror( name );
  629.         exit( 1 );
  630.         }
  631.     return f;
  632.     }
  633.  
  634. void
  635. pm_close( f )
  636.     FILE* f;
  637.     {
  638.     fflush( f );
  639.     if ( ferror( f ) )
  640.         pm_message( "a file read or write error occurred at some point" );
  641.     if ( f != stdin )
  642.         if ( fclose( f ) != 0 )
  643.             pm_perror( "fclose" );
  644.     }
  645.  
  646. /* Endian I/O.
  647. */
  648.  
  649. int
  650. pm_readbigshort( in, sP )
  651.     FILE* in;
  652.     short* sP;
  653.     {
  654.     int c;
  655.  
  656.     if ( (c = getc( in )) == EOF )
  657.         return -1;
  658.     *sP = ( c & 0xff ) << 8;
  659.     if ( (c = getc( in )) == EOF )
  660.         return -1;
  661.     *sP |= c & 0xff;
  662.     return 0;
  663.     }
  664.  
  665. #if __STDC__
  666. int
  667. pm_writebigshort( FILE* out, short s )
  668. #else /*__STDC__*/
  669. int
  670. pm_writebigshort( out, s )
  671.     FILE* out;
  672.     short s;
  673. #endif /*__STDC__*/
  674.     {
  675.     (void) putc( ( s >> 8 ) & 0xff, out );
  676.     (void) putc( s & 0xff, out );
  677.     return 0;
  678.     }
  679.  
  680. int
  681. pm_readbiglong( in, lP )
  682.     FILE* in;
  683.     long* lP;
  684.     {
  685.     int c;
  686.  
  687.     if ( (c = getc( in )) == EOF )
  688.         return -1;
  689.     *lP = ( c & 0xff ) << 24;
  690.     if ( (c = getc( in )) == EOF )
  691.         return -1;
  692.     *lP |= ( c & 0xff ) << 16;
  693.     if ( (c = getc( in )) == EOF )
  694.         return -1;
  695.     *lP |= ( c & 0xff ) << 8;
  696.     if ( (c = getc( in )) == EOF )
  697.         return -1;
  698.     *lP |= c & 0xff;
  699.     return 0;
  700.     }
  701.  
  702. int
  703. pm_writebiglong( out, l )
  704.     FILE* out;
  705.     long l;
  706.     {
  707.     (void) putc( ( l >> 24 ) & 0xff, out );
  708.     (void) putc( ( l >> 16 ) & 0xff, out );
  709.     (void) putc( ( l >> 8 ) & 0xff, out );
  710.     (void) putc( l & 0xff, out );
  711.     return 0;
  712.     }
  713.  
  714. int
  715. pm_readlittleshort( in, sP )
  716.     FILE* in;
  717.     short* sP;
  718.     {
  719.     int c;
  720.  
  721.     if ( (c = getc( in )) == EOF )
  722.         return -1;
  723.     *sP = c & 0xff;
  724.     if ( (c = getc( in )) == EOF )
  725.         return -1;
  726.     *sP |= ( c & 0xff ) << 8;
  727.     return 0;
  728.     }
  729.  
  730. #if __STDC__
  731. int
  732. pm_writelittleshort( FILE* out, short s )
  733. #else /*__STDC__*/
  734. int
  735. pm_writelittleshort( out, s )
  736.     FILE* out;
  737.     short s;
  738. #endif /*__STDC__*/
  739.     {
  740.     (void) putc( s & 0xff, out );
  741.     (void) putc( ( s >> 8 ) & 0xff, out );
  742.     return 0;
  743.     }
  744.  
  745. int
  746. pm_readlittlelong( in, lP )
  747.     FILE* in;
  748.     long* lP;
  749.     {
  750.     int c;
  751.  
  752.     if ( (c = getc( in )) == EOF )
  753.         return -1;
  754.     *lP = c & 0xff;
  755.     if ( (c = getc( in )) == EOF )
  756.         return -1;
  757.     *lP |= ( c & 0xff ) << 8;
  758.     if ( (c = getc( in )) == EOF )
  759.         return -1;
  760.     *lP |= ( c & 0xff ) << 16;
  761.     if ( (c = getc( in )) == EOF )
  762.         return -1;
  763.     *lP |= ( c & 0xff ) << 24;
  764.     return 0;
  765.     }
  766.  
  767. int
  768. pm_writelittlelong( out, l )
  769.     FILE* out;
  770.     long l;
  771.     {
  772.     (void) putc( l & 0xff, out );
  773.     (void) putc( ( l >> 8 ) & 0xff, out );
  774.     (void) putc( ( l >> 16 ) & 0xff, out );
  775.     (void) putc( ( l >> 24 ) & 0xff, out );
  776.     return 0;
  777.     }
  778.  
  779.  
  780. /* Read a file of unknown size to a buffer. Return the number of bytes
  781.    read. Allocate more memory as we need it. The calling routine has
  782.    to free() the buffer.
  783.  
  784.    Oliver Trepte, oliver@fysik4.kth.se, 930613 */
  785.  
  786. #define PM_BUF_SIZE 16384      /* First try this size of the buffer, then
  787.                                    double this until we reach PM_MAX_BUF_INC */
  788. #define PM_MAX_BUF_INC 65536   /* Don't allocate more memory in larger blocks
  789.                                    than this. */
  790.  
  791. char *pm_read_unknown_size( file, nread )
  792.     FILE* file;
  793.     long* nread;
  794. {
  795.     long nalloc;
  796.     register int val;
  797.     char* buf;
  798.  
  799.     *nread = 0;
  800.     if ((buf=malloc(PM_BUF_SIZE)) == NULL)
  801.         pm_error("Cannot allocate memory");
  802.     nalloc = PM_BUF_SIZE;
  803.  
  804.     while(1) {
  805.         if (*nread >= nalloc) { /* We need a larger buffer */
  806.             if (nalloc > PM_MAX_BUF_INC)
  807.                 nalloc += PM_MAX_BUF_INC;
  808.             else
  809.                 nalloc += nalloc;
  810.             if ((buf=realloc(buf, nalloc)) == NULL)
  811.                 pm_error("Cannot allocate %d bytes of memory", nalloc);
  812.         }
  813.  
  814.         if ((val = getc(file)) == EOF)
  815.             return (buf);
  816.  
  817.         buf[(*nread)++] = val;
  818.     }
  819. }
  820.  
  821. /*****************************************************************************/
  822.  
  823. #ifdef VMS
  824. /*
  825.  * @(#)argproc.c 1.0 89/02/01        Mark Pizzolato (mark@infopiz.uucp)    
  826.  */
  827.  
  828. #ifndef lint
  829. char argproc_version[] = "@(#)argproc.c VMS uucp Version infopiz-1.0";
  830. #endif
  831.  
  832. #include "includes.h"        /* System include files, system dependent */
  833.  
  834.  
  835. /*
  836.  * getredirection() is intended to aid in porting C programs
  837.  * to VMS (Vax-11 C) which does not support '>' and '<'
  838.  * I/O redirection, along with a command line pipe mechanism
  839.  * using the '|' AND background command execution '&'.
  840.  * The piping mechanism will probably work with almost any 'filter' type
  841.  * of program.  With suitable modification, it may useful for other
  842.  * portability problems as well.
  843.  *
  844.  * Author:  Mark Pizzolato    mark@infopiz.UUCP
  845.  */
  846. struct list_item
  847.     {
  848.     struct list_item *next;
  849.     char *value;
  850.     };
  851.  
  852. int
  853. getredirection(ac, av)
  854. int        *ac;
  855. char        ***av;
  856. /*
  857.  * Process vms redirection arg's.  Exit if any error is seen.
  858.  * If getredirection() processes an argument, it is erased
  859.  * from the vector.  getredirection() returns a new argc and argv value.
  860.  * In the event that a background command is requested (by a trailing "&"),
  861.  * this routine creates a background subprocess, and simply exits the program.
  862.  *
  863.  * Warning: do not try to simplify the code for vms.  The code
  864.  * presupposes that getredirection() is called before any data is
  865.  * read from stdin or written to stdout.
  866.  *
  867.  * Normal usage is as follows:
  868.  *
  869.  *    main(argc, argv)
  870.  *    int        argc;
  871.  *        char        *argv[];
  872.  *    {
  873.  *        getredirection(&argc, &argv);
  874.  *    }
  875.  */
  876. {
  877.     int            argc = *ac;    /* Argument Count      */
  878.     char        **argv = *av;    /* Argument Vector      */
  879.     char        *ap;           /* Argument pointer      */
  880.     int                   j;        /* argv[] index          */
  881.     extern int        errno;        /* Last vms i/o error       */
  882.     int            item_count = 0;    /* Count of Items in List */
  883.     int            new_file;    /* flag, true if '>' used */
  884.     struct list_item     *list_head = 0;    /* First Item in List        */
  885.     struct list_item    *list_tail;    /* Last Item in List        */
  886.     char         *in = NULL;    /* Input File Name        */
  887.     char         *out = NULL;    /* Output File Name        */
  888.     char         *outmode = "w";    /* Mode to Open Output File */
  889.     int            cmargc = 0;        /* Piped Command Arg Count  */
  890.     char        **cmargv = NULL;/* Piped Command Arg Vector */
  891.     stat_t        statbuf;    /* fstat buffer            */
  892.  
  893.     /*
  894.      * First handle the case where the last thing on the line ends with
  895.      * a '&'.  This indicates the desire for the command to be run in a
  896.      * subprocess, so we satisfy that desire.
  897.      */
  898.     ap = argv[argc-1];
  899.     if (0 == strcmp("&", ap))
  900.     exit(background_process(--argc, argv));
  901.     if ('&' == ap[strlen(ap)-1])
  902.     {
  903.     ap[strlen(ap)-1] = '\0';
  904.     exit(background_process(argc, argv));
  905.     }
  906.     /*
  907.      * Now we handle the general redirection cases that involve '>', '>>',
  908.      * '<', and pipes '|'.
  909.      */
  910.     for (new_file = 0, j = 0; j < argc; ++j)
  911.     {
  912.     if (0 == strcmp("<", argv[j]))
  913.         {
  914.         if (j+1 >= argc)
  915.         {
  916.         errno = EINVAL;
  917.         perror("No input file");
  918.         exit(EXIT_ERR);
  919.         }
  920.         in = argv[++j];
  921.         continue;
  922.         }
  923.     if ('<' == *(ap = argv[j]))
  924.         {
  925.         in = 1 + ap;
  926.         continue;
  927.         }
  928.     if (0 == strcmp(">", ap))
  929.         {
  930.         if (j+1 >= argc)
  931.         {
  932.         errno = EINVAL;
  933.         perror("No output file");
  934.         exit(EXIT_ERR);
  935.         }
  936.         out = argv[++j];
  937.         new_file = 1;
  938.         continue;
  939.         }
  940.     if ('>' == *ap)
  941.         {
  942.         if ('>' == ap[1])
  943.         {
  944.         outmode = "a";
  945.         if ('\0' == ap[2])
  946.             out = argv[++j];
  947.         else
  948.             out = 2 + ap;
  949.         }
  950.         else
  951.         { out = 1 + ap;  new_file = 1; }
  952.         continue;
  953.         }
  954.     if (0 == strcmp("|", argv[j]))
  955.         {
  956.         if (j+1 >= argc)
  957.         {
  958.         errno = EPIPE;
  959.         perror("No command to Pipe to");
  960.         exit(EXIT_ERR);
  961.         }
  962.         cmargc = argc-(j+1);
  963.         cmargv = &argv[j+1];
  964.         argc = j;
  965.         outmode = "wb";    /* pipes are binary mode devices */
  966.         continue;
  967.         }
  968.     if ('|' == *(ap = argv[j]))
  969.         {
  970.         ++argv[j];
  971.         cmargc = argc-j;
  972.         cmargv = &argv[j];
  973.         argc = j;
  974.         outmode = "wb";    /* pipes are binary mode devices */
  975.         continue;
  976.         }
  977.     expand_wild_cards(ap, &list_head, &list_tail, &item_count);
  978.     }
  979.     /*
  980.      * Allocate and fill in the new argument vector, Some Unix's terminate
  981.      * the list with an extra null pointer.
  982.      */
  983.     argv = *av = calloc(item_count+1, sizeof(char *));
  984.     for (j = 0; j < item_count; ++j, list_head = list_head->next)
  985.     argv[j] = list_head->value;
  986.     *ac = item_count;
  987.     if (cmargv != NULL)
  988.     {
  989.     char subcmd[1024];
  990.     static char *pipe_and_fork();
  991.  
  992.     if (out != NULL)
  993.         {
  994.         errno = EINVAL;
  995.         perror("Invalid '|' and '>' specified");
  996.         exit(EXIT_ERR);
  997.         }
  998.     strcpy(subcmd, cmargv[0]);
  999.     for (j = 1; j < cmargc; ++j)
  1000.         {
  1001.         strcat(subcmd, " \"");
  1002.         strcat(subcmd, cmargv[j]);
  1003.         strcat(subcmd, "\"");
  1004.         }
  1005.     out = pipe_and_fork(subcmd);
  1006.     outmode = "wb";
  1007.     }
  1008.     
  1009.     /* Check for input from a pipe (mailbox) */
  1010.  
  1011.     if(fstat(0, &statbuf) == 0){
  1012.     if(strncmp(statbuf.st_dev, "MB", 2) == 0 || 
  1013.         strncmp(statbuf.st_dev, "_MB", 3) == 0){
  1014.  
  1015.         /* Input from a pipe, reopen it in binary mode to disable    */
  1016.         /* carriage control processing.                */
  1017.  
  1018.         if (in != NULL){
  1019.         errno = EINVAL;
  1020.         perror("Invalid '|' and '<' specified");
  1021.         exit(EXIT_ERR);
  1022.         }
  1023.         freopen(statbuf.st_dev, "rb", stdin);
  1024.         }
  1025.     }
  1026.     else {
  1027.     perror("fstat failed");
  1028.     exit(EXIT_ERR);
  1029.     }
  1030.  
  1031. #ifdef __ALPHA
  1032.         /*, "mbc=32", "mbf=2"))) blows up on the ALPHA cbm 11/08/92 */
  1033.     if ((in != NULL) && (NULL == freopen(in, "r", stdin)))
  1034.         {
  1035. #else
  1036.     if ((in != NULL) && (NULL == freopen(in, "r", stdin, "mbc=32", "mbf=2")))
  1037.     {
  1038. #endif
  1039.     perror(in);                   /* Can't find file        */
  1040.     exit(EXIT_ERR);        /* Is a fatal error        */
  1041.     }
  1042. #ifdef __ALPHA
  1043.     if ((out != NULL) && (NULL == freopen(out, outmode, stdout)))
  1044.         {
  1045. #else
  1046.     if ((out != NULL) && (NULL == freopen(out, outmode, stdout, "mbc=32", "mbf=2")))
  1047.     {    
  1048. #endif
  1049.     perror(ap);        /* Error, can't write or append    */
  1050.     exit(EXIT_ERR);        /* Is a fatal error        */
  1051.     }
  1052.  
  1053.      if ( new_file ) {
  1054.     /*
  1055.      * We are making an explicit output file, fstat the file and
  1056.          * declare exit handler to be able change the file to fixed length
  1057.      * records if necessary. 
  1058.      */
  1059.     char fname[256];
  1060.     static int outfile_rundown(), check_outfile_filetype();
  1061.     static stat_t ofile_stat;
  1062.     static struct exit_control_block {
  1063.             struct exit_control_block *flink;
  1064.             int    (*exit_routine)();
  1065.         int arg_count;
  1066.         int *status_address;    /* arg 1 */
  1067.         stat_t *stat;        /* arg 2 */
  1068.         int exit_status;
  1069.         int skew[128];
  1070.     } exit_block = 
  1071.         { 0, outfile_rundown, 2, &exit_block.exit_status, &ofile_stat, 0 };
  1072.  
  1073.     if ( fstat ( fileno(stdout), &ofile_stat ) == 0 )
  1074.          sys$dclexh ( &exit_block );
  1075.     else fprintf(stderr,"Error fstating stdout - %s\n",
  1076.         strerror(errno,vaxc$errno) );
  1077.  
  1078.     if ( fgetname ( stdout, fname, 0 ) ) check_outfile_filetype ( fname );
  1079.      }
  1080. #ifdef DEBUG
  1081.     fprintf(stderr, "Arglist:\n");
  1082.     for (j = 0; j < *ac;  ++j)
  1083.     fprintf(stderr, "argv[%d] = '%s'\n", j, argv[j]);
  1084. #endif
  1085. }
  1086.  
  1087. static int binary_outfile = 0;
  1088. void set_outfile_binary() { binary_outfile = 1; return; }
  1089.  
  1090. /*
  1091.  * Check if output file should be set to binary (fixed 512) on exit based
  1092.  * upon the filetype.
  1093.  */
  1094. static int check_outfile_filetype ( name )
  1095.     char *name;
  1096. {
  1097.     char *binary_filetypes, *ext, *p, *t;
  1098.     binary_filetypes = (char *) getenv ( "PBM_BINARY_FILETYPES" );
  1099.     if ( binary_filetypes == NULL ) return 0;
  1100.  
  1101.     ext = strchr ( name, '.' );  if ( ext == NULL ) return 0;
  1102.     ext++;
  1103.     t = strrchr ( name, '.' );   if ( t != NULL ) *t = '\0';
  1104.  
  1105.     for ( p = binary_filetypes; *p != '\0'; p++ ) {
  1106.     for ( t = p;
  1107.           (*p != '\0' ) && (strchr ( ",     ", *p ) == NULL); 
  1108.          p++ ) *p = toupper(*p);
  1109.     *p = '\0';
  1110.  
  1111.     if ( strcmp ( t, ext ) == 0 ) {
  1112.         binary_outfile = 1;
  1113.         break;
  1114.     }
  1115.     }
  1116.     return binary_outfile;
  1117. }
  1118.  
  1119.  
  1120. /*
  1121.  * Exit handler to set output file to binary on image exit.
  1122.  */
  1123. static int outfile_rundown ( reason, statbuf )
  1124.     int *reason;
  1125.     stat_t *statbuf;
  1126. {
  1127.     int code, channel, status, LIB$GETDVI(), sys$assign(), sys$qiow();
  1128.     long int fib_desc[2], devchar;
  1129.     short int iosb[4];
  1130.     $DESCRIPTOR(device, statbuf->st_dev);
  1131.     struct fibdef fib;        /* File information block (XQP) */
  1132.     struct atrdef atr[2];
  1133.     struct fat {
  1134.       unsigned char rtype, ratattrib;
  1135.       unsigned short int rsize, hiblk[2], efblk[2], ffbyte, maxrec, defext, gbc;
  1136.       unsigned short int reserved[4], versions;
  1137.     } rat;
  1138.  
  1139.     if ( !binary_outfile ) return 1;    /* leave file alone */
  1140.     /*
  1141.      * Assign channel to device listed in stat block and test if it is
  1142.      * a directory structured device, returning if not.
  1143.      */
  1144.     device.dsc$w_length = strlen ( statbuf->st_dev );
  1145.     status = sys$assign ( &device, &channel, 0, 0 );
  1146.     if ((status & 1) == 0) { fprintf(stderr, 
  1147.     "assign error to %s (%d)\n", device.dsc$a_pointer, status);
  1148.         return status; }
  1149.     code = DVI$_DEVCHAR;
  1150.     status = LIB$GETDVI ( &code, &channel, 0, &devchar );
  1151.     if ((status & 1) == 0) { fprintf(stderr, "getdvi error: %d\n", status);
  1152.         return status; }
  1153.     if ( (devchar & DEV$M_DIR) == 0 ) return 1;
  1154.     /*
  1155.      * Build File Information Block and Atrribute block.
  1156.      */
  1157. #ifdef __ALPHA
  1158.     fib.fib$w_fid[0] = statbuf->st_ino[0];
  1159.     fib.fib$w_fid[1] = statbuf->st_ino[1];
  1160.     fib.fib$w_fid[2] = statbuf->st_ino[2];
  1161. #else
  1162.     fib.fib$r_fid_overlay.fib$w_fid[0] = statbuf->st_ino[0];
  1163.     fib.fib$r_fid_overlay.fib$w_fid[1] = statbuf->st_ino[1];
  1164.     fib.fib$r_fid_overlay.fib$w_fid[2] = statbuf->st_ino[2];
  1165. #endif
  1166.  
  1167.     atr[0].atr$w_size = sizeof(rat);
  1168.     atr[0].atr$w_type = ATR$C_RECATTR;
  1169.     atr[0].atr$l_addr = &rat;
  1170.     atr[1].atr$w_size = 0; atr[1].atr$w_type = 0;
  1171.     /*
  1172.      * Perform access function with read_attributes sub-function.
  1173.      */
  1174.     freopen ( "SYS$OUTPUT:", "a", stdout );
  1175.     fib_desc[0] = 10; fib_desc[1] = (long int) &fib;
  1176. #ifdef __ALPHA
  1177.     fib.fib$l_acctl = FIB$M_WRITE;
  1178. #else
  1179.     fib.fib$r_acctl_overlay.fib$l_acctl = FIB$M_WRITE;
  1180. #endif
  1181.     status = sys$qiow ( 0, channel, IO$_ACCESS|IO$M_ACCESS,
  1182.          &iosb, 0, 0, &fib_desc, 0, 0, 0, &atr, 0 );
  1183.     /*
  1184.      * If status successful, update record byte and perform a MODIFY.
  1185.      */
  1186.     if ( (status&1) == 1 ) status = iosb[0];
  1187.     if ( (status&1) == 1 ) {
  1188.       rat.rtype = 1;        /* fixed length records */
  1189.       rat.rsize = 512;      /* 512 byte block recrods */
  1190.       rat.ratattrib = 0;        /* Record attributes: none */
  1191.  
  1192.      status = sys$qiow
  1193.     ( 0, channel, IO$_MODIFY, &iosb, 0, 0, &fib_desc, 0, 0, 0, &atr, 0 );
  1194.        if ( (status&1) == 1 ) status = iosb[0];
  1195.    }
  1196.    sys$dassgn ( channel );
  1197.    if ( (status & 1) == 0 ) fprintf ( stderr,
  1198.     "Failed to convert output file to binary format, status: %d\n", status);
  1199.    return status;
  1200. }
  1201.  
  1202.  
  1203. static add_item(head, tail, value, count)
  1204. struct list_item **head;
  1205. struct list_item **tail;
  1206. char *value;
  1207. int *count;
  1208. {
  1209.     if (*head == 0)
  1210.     {
  1211.     if (NULL == (*head = calloc(1, sizeof(**head))))
  1212.         {
  1213.         errno = ENOMEM;
  1214.         perror("");
  1215.         exit(EXIT_ERR);
  1216.         }
  1217.     *tail = *head;
  1218.     }
  1219.     else
  1220.     if (NULL == ((*tail)->next = calloc(1, sizeof(**head))))
  1221.         {
  1222.         errno = ENOMEM;
  1223.         perror("");
  1224.         exit(EXIT_ERR);
  1225.         }
  1226.     else
  1227.         *tail = (*tail)->next;
  1228.     (*tail)->value = value;
  1229.     ++(*count);
  1230. }
  1231.  
  1232. static expand_wild_cards(item, head, tail, count)
  1233. char *item;
  1234. struct ltem_list **head;
  1235. struct ltem_list **tail;
  1236. int *count;
  1237. {
  1238. int expcount = 0;
  1239. int context = 0;
  1240. int status;
  1241. int status_value;
  1242. int had_version;
  1243. $DESCRIPTOR(filespec, item);
  1244. $DESCRIPTOR(defaultspec, "SYS$DISK:[]*.*;");
  1245. $DESCRIPTOR(resultspec, "");
  1246.  
  1247.     if (strcspn(item, "*%") == strlen(item))
  1248.     {
  1249.     add_item(head, tail, item, count);
  1250.     return;
  1251.     }
  1252.     resultspec.dsc$b_dtype = DSC$K_DTYPE_T;
  1253.     resultspec.dsc$b_class = DSC$K_CLASS_D;
  1254.     resultspec.dsc$a_pointer = NULL;
  1255.     filespec.dsc$w_length = strlen(item);
  1256.     /*
  1257.      * Only return version specs, if the caller specified a version
  1258.      */
  1259.     had_version = strchr(item, ';');
  1260.     while (1 == (1&lib$find_file(&filespec, &resultspec, &context,
  1261.                      &defaultspec, 0, &status_value, &0)))
  1262.     {
  1263.     char *string;
  1264.     char *c;
  1265.  
  1266.     if (NULL == (string = calloc(1, resultspec.dsc$w_length+1)))
  1267.         {
  1268.         errno = ENOMEM;
  1269.         perror("");
  1270.         exit(EXIT_ERR);
  1271.         }
  1272.     strncpy(string, resultspec.dsc$a_pointer, resultspec.dsc$w_length);
  1273.     string[resultspec.dsc$w_length] = '\0';
  1274.     if (NULL == had_version)
  1275.         *((char *)strrchr(string, ';')) = '\0';
  1276.     /*
  1277.      * Be consistent with what the C RTL has already done to the rest of
  1278.      * the argv items and lowercase all of these names.
  1279.      */
  1280.     for (c = string; *c; ++c)
  1281.         if (isupper(*c))
  1282.         *c = tolower(*c);
  1283.     add_item(head, tail, string, count);
  1284.     ++expcount;
  1285.     }
  1286.     if (expcount == 0)
  1287.     add_item(head, tail, item, count);
  1288.     lib$sfree1_dd(&resultspec);
  1289.     lib$find_file_end(&context);
  1290. }
  1291.  
  1292. static int child_st[2];    /* Event Flag set when child process completes    */
  1293.  
  1294. static short child_chan;/* I/O Channel for Pipe Mailbox            */
  1295.  
  1296. static exit_handler(status)
  1297. int *status;
  1298. {
  1299. short iosb[4];
  1300.  
  1301.     if (0 == child_st[0])
  1302.     {
  1303. #ifdef DEBUG
  1304.     fprintf(stderr, "Waiting for Child Process to Finnish . . .\n");
  1305. #endif
  1306.     fflush(stdout);        /* Have to flush pipe for binary data to    */
  1307.                 /* terminate properly -- <tp@mccall.com>    */
  1308. #ifdef DEBUG
  1309.     fprintf(stderr, "    stdout flushed. . .\n");
  1310. #endif
  1311.     sys$qio(0, child_chan, IO$_WRITEOF, iosb, 0, 0, 0, 0, 0, 0, 0, 0);
  1312. #ifdef DEBUG
  1313.     fprintf(stderr, "    Pipe terminated. . .\n");
  1314. #endif
  1315.     fclose(stdout);
  1316. #ifdef DEBUG
  1317.     fprintf(stderr, "    stdout closed. . .\n");
  1318. #endif
  1319.     sys$synch(0, child_st);
  1320.     sys$dassgn(child_chan);
  1321.     }
  1322. #ifdef DEBUG
  1323.     fprintf(stderr, "    sync done. . .\n");
  1324. #endif
  1325. }
  1326.  
  1327. #include <syidef>        /* System Information Definitions    */
  1328.  
  1329. static sig_child(chan)
  1330. int chan;
  1331. {
  1332. #ifdef DEBUG
  1333.     fprintf(stderr, "Child Completion AST, st: %x\n", child_st[0] );
  1334. #endif
  1335.     if (child_st[0] == 0)
  1336.     { child_st[0] = 1; }
  1337.     sys$setef ( 0 );
  1338. }
  1339.  
  1340. static struct exit_control_block
  1341.     {
  1342.     struct exit_control_block *flink;
  1343.     int    (*exit_routine)();
  1344.     int arg_count;
  1345.     int *status_address;
  1346.     int exit_status;
  1347.     } exit_block =
  1348.     {
  1349.     0,
  1350.     exit_handler,
  1351.     1,
  1352.     &exit_block.exit_status,
  1353.     0
  1354.     };
  1355.  
  1356. static char *pipe_and_fork(cmd)
  1357. char *cmd;
  1358. {
  1359.     $DESCRIPTOR(cmddsc, cmd);
  1360.     static char mbxname[64], ef = 0;
  1361.     $DESCRIPTOR(mbxdsc, mbxname);
  1362.     short iosb[4];
  1363.     int status;
  1364.     int pid;
  1365.     struct
  1366.     {
  1367.     short dna_buflen;
  1368.     short dna_itmcod;
  1369.     char *dna_buffer;
  1370.     short *dna_retlen;
  1371.     int listend;
  1372.     } itmlst =
  1373.     {
  1374.     sizeof(mbxname),
  1375.     DVI$_DEVNAM,
  1376.     mbxname,
  1377.     &mbxdsc.dsc$w_length,
  1378.     0
  1379.     };
  1380.     int mbxsize;
  1381.     struct
  1382.     {
  1383.     short mbf_buflen;
  1384.     short mbf_itmcod;
  1385.     int *mbf_maxbuf;
  1386.     short *mbf_retlen;
  1387.     int listend;
  1388.     } syiitmlst =
  1389.     {
  1390.     sizeof(mbxsize),
  1391.     SYI$_MAXBUF,
  1392.     &mbxsize,
  1393.     0,
  1394.     0
  1395.     };
  1396.  
  1397.     cmddsc.dsc$w_length = strlen(cmd);
  1398.     /*
  1399.      * Get the SYSGEN parameter MAXBUF, and the smaller of it and 2048 as
  1400.      * the size of the 'pipe' mailbox.
  1401.      */
  1402.     if (1 == (1&(vaxc$errno = sys$getsyiw(0, 0, 0, &syiitmlst, iosb, 0, 0, 0))))
  1403.     vaxc$errno = iosb[0];
  1404.     if (0 == (1&vaxc$errno))
  1405.     {
  1406.      errno = EVMSERR;
  1407.     perror("Can't get SYSGEN parameter value for MAXBUF");
  1408.     exit(EXIT_ERR);
  1409.     }
  1410.     if (mbxsize > 2048)
  1411.     mbxsize = 2048;
  1412.     if (0 == (1&(vaxc$errno = sys$crembx(0, &child_chan, mbxsize, mbxsize, 0, 0, 0))))
  1413.     {
  1414.     errno = EVMSERR;
  1415.     perror("Can't create pipe mailbox");
  1416.     exit(EXIT_ERR);
  1417.     }
  1418.     if (1 == (1&(vaxc$errno = sys$getdviw(0, child_chan, 0, &itmlst, iosb,
  1419.                           0, 0, 0))))
  1420.     vaxc$errno = iosb[0];
  1421.     if (0 == (1&vaxc$errno))
  1422.     {
  1423.      errno = EVMSERR;
  1424.     perror("Can't get pipe mailbox device name");
  1425.     exit(EXIT_ERR);
  1426.     }
  1427.     mbxname[mbxdsc.dsc$w_length] = '\0';
  1428. #ifdef DEBUG
  1429.     fprintf(stderr, "Pipe Mailbox Name = '%s'\n", mbxname);
  1430. #endif
  1431.     if (0 == (1&(vaxc$errno = lib$spawn(&cmddsc, &mbxdsc, 0, &1,
  1432.                         0, &pid, child_st, &ef, sig_child,
  1433.                         &child_chan))))
  1434.     {
  1435.     errno = EVMSERR;
  1436.     perror("Can't spawn subprocess");
  1437.     exit(EXIT_ERR);
  1438.     }
  1439. #ifdef DEBUG
  1440.     fprintf(stderr, "Subprocess's Pid = %08X\n", pid);
  1441. #endif
  1442.     sys$dclexh(&exit_block);
  1443.     return(mbxname);
  1444. }
  1445.  
  1446. background_process(argc, argv)
  1447. int argc;
  1448. char **argv;
  1449. {
  1450. char command[2048] = "$";
  1451. $DESCRIPTOR(value, command);
  1452. $DESCRIPTOR(cmd, "BACKGROUND$COMMAND");
  1453. $DESCRIPTOR(null, "NLA0:");
  1454. int pid;
  1455.  
  1456.     strcat(command, argv[0]);
  1457.     while (--argc)
  1458.     {
  1459.     strcat(command, " \"");
  1460.     strcat(command, *(++argv));
  1461.     strcat(command, "\"");
  1462.     }
  1463.     value.dsc$w_length = strlen(command);
  1464.     if (0 == (1&(vaxc$errno = lib$set_symbol(&cmd, &value))))
  1465.     {
  1466.     errno = EVMSERR;
  1467.     perror("Can't create symbol for subprocess command");
  1468.     exit(EXIT_ERR);
  1469.     }
  1470.     if (0 == (1&(vaxc$errno = lib$spawn(&cmd, &null, 0, &17, 0, &pid))))
  1471.     {
  1472.     errno = EVMSERR;
  1473.     perror("Can't spawn subprocess");
  1474.     exit(EXIT_ERR);
  1475.     }
  1476. #ifdef DEBUG
  1477.     fprintf(stderr, "%s\n", command);
  1478. #endif
  1479.     fprintf(stderr, "%08X\n", pid);
  1480.     return(EXIT_OK);
  1481. }
  1482.  
  1483. /* got this off net.sources */
  1484.  
  1485. #ifdef    VMS
  1486. #define    index    strchr
  1487. #endif    /*VMS*/
  1488.  
  1489. /*
  1490.  * get option letter from argument vector
  1491.  */
  1492. int    opterr = 1,        /* useless, never set or used */
  1493.     optind = 1,        /* index into parent argv vector */
  1494.     optopt;            /* character checked for validity */
  1495. char    *optarg;        /* argument associated with option */
  1496.  
  1497. #define BADCH    (int)'?'
  1498. #define EMSG    ""
  1499. #define tell(s)    fputs(progname,stderr);fputs(s,stderr); \
  1500.         fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
  1501.  
  1502. getopt(nargc,nargv,ostr)
  1503. int    nargc;
  1504. char    **nargv,
  1505.     *ostr;
  1506. {
  1507.     static char    *place = EMSG;    /* option letter processing */
  1508.     register char    *oli;        /* option letter list index */
  1509.     char    *index();
  1510.     char *progname;
  1511.  
  1512.     if(!*place) {            /* update scanning pointer */
  1513.         if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
  1514.         if (*place == '-') {    /* found "--" */
  1515.             ++optind;
  1516.             return(EOF);
  1517.         }
  1518.     }                /* option letter okay? */
  1519.     if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
  1520.         if(!*place) ++optind;
  1521. #ifdef VMS
  1522.         progname = strrchr(nargv[0],']');
  1523. #else
  1524.         progname = rindex(nargv[0],'/');
  1525. #endif
  1526.         if (!progname) progname = nargv[0]; else progname++;
  1527.         tell(": illegal option -- ");
  1528.     }
  1529.     if (*++oli != ':') {        /* don't need argument */
  1530.         optarg = NULL;
  1531.         if (!*place) ++optind;
  1532.     }
  1533.     else {                /* need an argument */
  1534.         if (*place) optarg = place;    /* no white space */
  1535.         else if (nargc <= ++optind) {    /* no arg */
  1536.             place = EMSG;
  1537. #ifdef VMS
  1538.             progname = strrchr(nargv[0],']');
  1539. #else
  1540.             progname = rindex(nargv[0],'/');
  1541. #endif
  1542.             if (!progname) progname = nargv[0]; else progname++;
  1543.             tell(": option requires an argument -- ");
  1544.         }
  1545.          else optarg = nargv[optind];    /* white space */
  1546.         place = EMSG;
  1547.         ++optind;
  1548.     }
  1549.     return(optopt);            /* dump back option letter */
  1550. }
  1551. #endif /* VMS */
  1552.