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