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