home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip512.zip / vms / vms.c < prev    next >
C/C++ Source or Header  |  1994-08-23  |  66KB  |  2,618 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   vms.c                                        Igor Mandrichenko and others
  4.  
  5.   This file contains routines to extract VMS file attributes from a zipfile
  6.   extra field and create a file with these attributes.  The code was almost
  7.   entirely written by Igor, with a couple of routines by CN.
  8.  
  9.   ---------------------------------------------------------------------------
  10.  
  11.      Copyright (C) 1992-93 Igor Mandrichenko.
  12.      Permission is granted to any individual or institution to use, copy,
  13.      or redistribute this software so long as all of the original files
  14.      are included unmodified and that this copyright notice is retained.
  15.  
  16.   Revision history:
  17.  
  18.      1.x   [moved to History.510 for brevity]
  19.      2.0   Mandrichenko    7-apr-1993
  20.             Implement PKWARE style VMS file attributes
  21.      2.0-1 Mandrichenko    10-apr-1993
  22.             ACL handling code added.
  23.      2.1   Mandrichenko    24-aug-1993
  24.             Get both PKWARE and new INFO-ZIP signatures as equivalent
  25.             Use vmsmunch.h instead of fatdef.h
  26.      2.2   Cave Newt       3-oct-1993
  27.             Merged GRR 5.1e changes with latest Igor version:  open_outfile,
  28.             close_outfile, check_for_newer, UpdateCRC, flush, no ZIPINFO,
  29.             ctype.h, pInfo->textmode, etc.  Also merged new do_wild/mapname/
  30.             checkdir routines from Igor and moved VMSmunch.h into vms.h.
  31.      2.2-1 Mandrichenko    14-dec-1993
  32.             Bug fixes in mapname/checkdir stuff.
  33.             _flush_stream() rewritten to fix some bugs.
  34.      2.2-2 Goathunter      3 Jan 94
  35.             Fixes for Alpha-VMS.
  36.      2.2-3 Cave Newt       11 Jan 94
  37.             Disabled version-check by default; enable with CHECK_VERSIONS.
  38.             Installed Igor's ctrl-Z patch.
  39.      2.2-4 Mandrichenko    18 Jan 94
  40.             Fixed auto-appending of ".zip" and inability to create second
  41.             level of directory structure.
  42.      2.2-5 Cave Newt, Mike Freeman  28 Jan 94
  43.             Changed close_outfile() to return void for compatibility;
  44.             fixed declaration of second parameter to flush() (ulg size);
  45.             changed str[n]icmp() to STR[N]ICMP().
  46.      2.2-6 Christian Spieler  9 Apr 94
  47.             Numerous bug fixes/improvements.
  48.      2.2-7 Cave Newt       11 Apr 94
  49.             Fixed version-number/semicolon bug.
  50.      2.3   Cave Newt       21 Jun 94
  51.             Added prototype version() routine.
  52.      2.3-1 Cave Newt       1 Jul 94
  53.             *Really* fixed version-number/semicolon bug.
  54.      2.3-2 Rodney Brown    10 Jul 94
  55.             Added VMS status/severity level (define RETURN_SEVERITY)
  56.      2.3-3 Charles Bailey  10 Aug 94
  57.             Fixed severity levels.
  58.      2.3-4 CN, CS, IM, RB  16 Aug 94
  59.             Further severity tweaks; do_wild() bugfix (CS)
  60.      2.3-5 CS, CN, IM, GH  18 Aug 94
  61.             Further do_wild() modifications and fixes.
  62.      2.3-6 Christian Spieler  23 Aug 94
  63.             Added lots of typecasts and fixed some initializations for DEC C.
  64.  
  65.   ---------------------------------------------------------------------------*/
  66.  
  67. #ifdef VMS            /*      VMS only !      */
  68.  
  69. #include "unzip.h"
  70. #include "vms.h"        /* now includes VMSmunch.h */
  71.  
  72. #define BUFS512 8192*2        /* Must be a multiple of 512 */
  73.  
  74. #define    OK(s)    ((s)&1)        /* VMS success or warning status */
  75. #define    STRICMP(s1,s2)    STRNICMP(s1,s2,2147483647)
  76.  
  77. /*
  78. *   Local static storage
  79. */
  80. static struct FAB    fileblk;
  81. static struct XABDAT    dattim;
  82. static struct XABRDT    rdt;
  83. static struct RAB    rab;
  84. static struct NAM    nam;
  85.  
  86. static struct FAB *outfab = 0;
  87. static struct RAB *outrab = 0;
  88. static struct XABFHC *xabfhc = 0;
  89. static struct XABDAT *xabdat = 0;
  90. static struct XABRDT *xabrdt = 0;
  91. static struct XABPRO *xabpro = 0;
  92. static struct XABKEY *xabkey = 0;
  93. static struct XABALL *xaball = 0;
  94. struct XAB *first_xab = 0L, *last_xab = 0L;
  95.  
  96. static char query = 0;
  97. static int  text_output = 0,
  98.         raw_input,
  99.         hostnum;
  100.  
  101. static uch rfm;
  102.  
  103. static uch locbuf[BUFS512];
  104. static int loccnt = 0;
  105. static uch *locptr;
  106. static char got_eol = 0;
  107.  
  108. static int  _flush_blocks(),
  109.         _flush_stream(),
  110.         _flush_varlen(),
  111.         _flush_qio(),
  112.         _close_qio(),
  113.         _close_rms(),
  114.         WriteRecord(),
  115.         WriteBuffer(),
  116.         find_eol();
  117.  
  118. static int  (*_flush_routine)(),
  119.         (*_close_routine)();
  120.  
  121. static int get_vms_version();
  122. static int replace();
  123. static uch *extract_block();
  124. static void init_buf_ring();
  125. static void decompress_bits();
  126. static void UpdateCRC();
  127. static void message();
  128. static void free_up();
  129.  
  130. struct bufdsc
  131. {
  132.     struct bufdsc *next;
  133.     uch *buf;
  134.     int bufcnt;
  135. };
  136.  
  137. static struct bufdsc b1, b2, *curbuf;
  138. static uch buf1[BUFS512];
  139.  
  140. int check_format()
  141. {
  142.     int rtype;
  143.     struct FAB fab;
  144.  
  145.     fab = cc$rms_fab;
  146.     fab.fab$l_fna = zipfn;
  147.     fab.fab$b_fns = strlen(zipfn);
  148.  
  149.     sys$open(&fab);
  150.     rtype = fab.fab$b_rfm;
  151.     sys$close(&fab);
  152.  
  153.     if (rtype == FAB$C_VAR || rtype == FAB$C_VFC)
  154.     {
  155.     fprintf(stderr,
  156.         "\n     Error:  zipfile is in variable-length record format.  Please\n\
  157.      run \"bilf l %s\" to convert the zipfile to stream-LF\n\
  158.      record format.  (bilf.c and make_bilf.com are included in the\n\
  159.      VMS UnZip source distribution.)\n\n", zipfn);
  160.     return PK_ERR;
  161.     }
  162.  
  163.     return PK_COOL;
  164. }
  165.  
  166.  
  167.  
  168. #define PRINTABLE_FORMAT(x)    ( (x) == FAB$C_VAR         \
  169.                 || (x) == FAB$C_STMLF        \
  170.                 || (x) == FAB$C_STMCR        \
  171.                 || (x) == FAB$C_STM        )
  172.  
  173. /* VMS extra field types */
  174. #define    VAT_NONE    0
  175. #define    VAT_IZ        1    /* Old INFO-ZIP format */
  176. #define VAT_PK        2    /* PKWARE format */
  177.  
  178. static int  vet;
  179.  
  180. static int  create_default_output(),
  181.         create_rms_output(),
  182.         create_qio_output();
  183.  
  184. /*
  185.  *  open_outfile() assignments:
  186.  *
  187.  *  VMS attributes ?        create_xxx        _flush_xxx
  188.  *  ----------------        ----------        ----------
  189.  *  not found            'default'        text mode ?
  190.  *                        yes -> 'stream'
  191.  *                        no  -> 'block'
  192.  *
  193.  *  yes, in IZ format        'rms'        text mode ?
  194.  *                        yes -> switch(fab.rfm)
  195.  *                        VAR  -> 'varlen' 
  196.  *                        STM* -> 'stream'
  197.  *                            default -> 'block'
  198.  *                        no -> 'block'
  199.  *
  200.  *  yes, in PK format        'qio'        'qio'
  201.  *
  202.  *  "text mode" == pInfo -> text || cflag
  203.  */
  204.  
  205. int open_outfile()
  206. {
  207.     switch(vet = find_vms_attrs())
  208.     {    case VAT_NONE:
  209.     default:
  210.         return  create_default_output();
  211.     case VAT_IZ:
  212.         return  create_rms_output();
  213.     case VAT_PK:
  214.         return  create_qio_output();
  215.     }
  216. }
  217.  
  218. static void init_buf_ring()
  219. {
  220.     locptr = &locbuf[0];
  221.     loccnt = 0;
  222.  
  223.     b1.buf = &locbuf[0];
  224.     b1.bufcnt = 0;
  225.     b1.next = &b2;
  226.     b2.buf = &buf1[0];
  227.     b2.bufcnt = 0;
  228.     b2.next = &b1;
  229.     curbuf = &b1;
  230. }
  231.  
  232.  
  233.  
  234. static int create_default_output()
  235. {
  236.     int ierr, yr, mo, dy, hh, mm, ss;
  237.     char timbuf[24];        /* length = first entry in "stupid" + 1 */
  238.     int attr_given;        /* =1 if VMS attributes are present in
  239.                  *    extra_field */
  240.  
  241.     rab = cc$rms_rab;        /* fill FAB & RAB with default values */
  242.     fileblk = cc$rms_fab;
  243.  
  244.     text_output = pInfo->textmode || cflag;    /* extract the file in text
  245.                              * (variable-length) format */
  246.     hostnum = pInfo -> hostnum;
  247.  
  248.     outfab = &fileblk;
  249.     outfab->fab$l_xab = 0L;
  250.     rfm = FAB$C_STMLF;    /* Default, stream-LF format from VMS
  251.                 *   or UNIX */
  252.     if (text_output)
  253.     {   /* Default format for output text file */
  254.  
  255.     outfab->fab$b_rfm = FAB$C_VAR;    /* variable length records */
  256.     outfab->fab$b_rat = FAB$M_CR;    /* carriage-return carriage ctrl */
  257.     }
  258.     else
  259.     {   /* Default format for output binary file */
  260.  
  261.     outfab->fab$b_rfm = FAB$C_STMLF;    /* stream-LF record format */
  262.     outfab->fab$b_rat = FAB$M_CR;    /* carriage-return carriage ctrl */
  263.     }
  264.  
  265.     if (!cflag)    /* Redirect output */
  266.     outfab->fab$l_fna = filename;
  267.     else
  268.     outfab->fab$l_fna = "sys$output:";
  269.  
  270.     outfab->fab$b_fns = strlen(outfab->fab$l_fna);
  271.  
  272.     {
  273.     static char *month[] =
  274.         {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
  275.          "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
  276.  
  277.     /*  fixed-length string descriptor: */
  278.     struct dsc$descriptor stupid =
  279.         {23, DSC$K_DTYPE_T, DSC$K_CLASS_S, timbuf};
  280.  
  281.     yr = ((lrec.last_mod_file_date >> 9) & 0x7f) + 1980;
  282.     mo = ((lrec.last_mod_file_date >> 5) & 0x0f) - 1;
  283.     dy = (lrec.last_mod_file_date & 0x1f);
  284.     hh = (lrec.last_mod_file_time >> 11) & 0x1f;
  285.     mm = (lrec.last_mod_file_time >> 5) & 0x3f;
  286.     ss = (lrec.last_mod_file_time & 0x1f) * 2;
  287.  
  288.     dattim = cc$rms_xabdat;    /* fill XABs with default values */
  289.     rdt = cc$rms_xabrdt;
  290.     sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", dy, month[mo], yr,
  291.         hh, mm, ss);
  292.     sys$bintim(&stupid, &dattim.xab$q_cdt);
  293.     memcpy(&rdt.xab$q_rdt, &dattim.xab$q_cdt, sizeof(rdt.xab$q_rdt));
  294.  
  295.     dattim.xab$l_nxt = outfab->fab$l_xab;
  296.     outfab->fab$l_xab = (void *) &dattim;
  297.     }
  298.  
  299.     outfab->fab$w_ifi = 0;    /* Clear IFI. It may be nonzero after ZIP */
  300.  
  301.     ierr = sys$create(outfab);
  302.     if (ierr == RMS$_FEX)
  303.     ierr = replace();
  304.  
  305.     if (ierr == 0)        /* Canceled */
  306.     return free_up(), 1;
  307.  
  308.     if (ERR(ierr))
  309.     {
  310.     char buf[256];
  311.  
  312.     sprintf(buf, "[ Cannot create output file %s ]\n", filename);
  313.     message(buf, ierr);
  314.     message("", outfab->fab$l_stv);
  315.     free_up();
  316.     return PK_WARN;
  317.     }
  318.  
  319.     if (!text_output)    /* Do not reopen text files and stdout
  320.             *  Just open them in right mode         */
  321.     {
  322.     /*
  323.     *       Reopen file for Block I/O with no XABs.
  324.     */
  325.     if ((ierr = sys$close(outfab)) != RMS$_NORMAL)
  326.     {
  327. #ifdef DEBUG
  328.         message("[ create_output_file: sys$close failed ]\n", ierr);
  329.         message("", outfab->fab$l_stv);
  330. #endif
  331.         fprintf(stderr, "Can't create output file:  %s\n", filename);
  332.         free_up();
  333.         return PK_WARN;
  334.     }
  335.  
  336.  
  337.     outfab->fab$b_fac = FAB$M_BIO | FAB$M_PUT;    /* Get ready for block
  338.                              * output */
  339.     outfab->fab$l_xab = 0L;    /* Unlink all XABs */
  340.  
  341.     if ((ierr = sys$open(outfab)) != RMS$_NORMAL)
  342.     {
  343.         char buf[256];
  344.  
  345.         sprintf(buf, "[ Cannot open output file %s ]\n", filename);
  346.         message(buf, ierr);
  347.         message("", outfab->fab$l_stv);
  348.         free_up();
  349.         return PK_WARN;
  350.     }
  351.     }
  352.  
  353.     outrab = &rab;
  354.     rab.rab$l_fab = outfab;
  355.     if (!text_output)
  356.     {   rab.rab$l_rop |= RAB$M_BIO;
  357.         rab.rab$l_rop |= RAB$M_ASY;
  358.     }
  359.     rab.rab$b_rac = RAB$C_SEQ;
  360.  
  361.     if ((ierr = sys$connect(outrab)) != RMS$_NORMAL)
  362.     {
  363. #ifdef DEBUG
  364.     message("create_output_file: sys$connect failed.\n", ierr);
  365.     message("", outfab->fab$l_stv);
  366. #endif
  367.     fprintf(stderr, "Can't create output file:  %s\n", filename);
  368.     free_up();
  369.     return PK_WARN;
  370.     }
  371.  
  372.     init_buf_ring();
  373.  
  374.     _flush_routine = text_output? got_eol=0,_flush_stream : _flush_blocks;
  375.     _close_routine = _close_rms;
  376.     return PK_COOL;
  377. }
  378.  
  379.  
  380.  
  381. static int create_rms_output()
  382. {
  383.     int ierr, yr, mo, dy, hh, mm, ss;
  384.     char timbuf[24];        /* length = first entry in "stupid" + 1 */
  385.  
  386.     rab = cc$rms_rab;        /* fill FAB & RAB with default values */
  387.     fileblk = cc$rms_fab;
  388.  
  389.     text_output = cflag;    /* extract the file in text (variable-length)
  390.                  * format; ignore -a when attributes saved */
  391.     hostnum = pInfo -> hostnum;
  392.  
  393.     if (cflag)
  394.     {
  395.     if(!PRINTABLE_FORMAT(rfm=outfab->fab$b_rfm))
  396.     {    printf("[ File %s has illegal record format to put to screen ]\n",
  397.            filename);
  398.         free_up();
  399.         return PK_DISK;
  400.     }
  401.     }
  402.  
  403.     if (!cflag)    /* Redirect output */
  404.     outfab->fab$l_fna = filename;
  405.     else
  406.     outfab->fab$l_fna = "sys$output:";
  407.  
  408.     outfab->fab$b_fns = strlen(outfab->fab$l_fna);
  409.  
  410.     if (!(xabdat && xabrdt))    /* Use date/time info
  411.                  *  from zipfile if
  412.                  *  no attributes given
  413.                  */
  414.     {
  415.     static char *month[] =
  416.         {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
  417.          "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
  418.  
  419.     /*  fixed-length string descriptor: */
  420.     struct dsc$descriptor stupid =
  421.         {23, DSC$K_DTYPE_T, DSC$K_CLASS_S, timbuf};
  422.  
  423.     yr = ((lrec.last_mod_file_date >> 9) & 0x7f) + 1980;
  424.     mo = ((lrec.last_mod_file_date >> 5) & 0x0f) - 1;
  425.     dy = (lrec.last_mod_file_date & 0x1f);
  426.     hh = (lrec.last_mod_file_time >> 11) & 0x1f;
  427.     mm = (lrec.last_mod_file_time >> 5) & 0x3f;
  428.     ss = (lrec.last_mod_file_time & 0x1f) * 2;
  429.  
  430.     dattim = cc$rms_xabdat;    /* fill XABs with default values */
  431.     rdt = cc$rms_xabrdt;
  432.     sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", dy, month[mo], yr,
  433.         hh, mm, ss);
  434.     sys$bintim(&stupid, &dattim.xab$q_cdt);
  435.     memcpy(&rdt.xab$q_rdt, &dattim.xab$q_cdt, sizeof(rdt.xab$q_rdt));
  436.  
  437.     if (xabdat == 0L)
  438.     {
  439.         dattim.xab$l_nxt = outfab->fab$l_xab;
  440.         outfab->fab$l_xab = (void *) &dattim;
  441.     }
  442.     }
  443.  
  444.     outfab->fab$w_ifi = 0;    /* Clear IFI. It may be nonzero after ZIP */
  445.  
  446.     ierr = sys$create(outfab);
  447.     if (ierr == RMS$_FEX)
  448.     ierr = replace();
  449.  
  450.     if (ierr == 0)        /* Canceled */
  451.     return free_up(), 1;
  452.  
  453.     if (ERR(ierr))
  454.     {
  455.     char buf[256];
  456.  
  457.     sprintf(buf, "[ Cannot create output file %s ]\n", filename);
  458.     message(buf, ierr);
  459.     message("", outfab->fab$l_stv);
  460.     free_up();
  461.     return PK_WARN;
  462.     }
  463.  
  464.     if (!text_output)    /* Do not reopen text files and stdout
  465.             *  Just open them in right mode         */
  466.     {
  467.     /*
  468.     *       Reopen file for Block I/O with no XABs.
  469.     */
  470.     if ((ierr = sys$close(outfab)) != RMS$_NORMAL)
  471.     {
  472. #ifdef DEBUG
  473.         message("[ create_output_file: sys$close failed ]\n", ierr);
  474.         message("", outfab->fab$l_stv);
  475. #endif
  476.         fprintf(stderr, "Can't create output file:  %s\n", filename);
  477.         free_up();
  478.         return PK_WARN;
  479.     }
  480.  
  481.  
  482.     outfab->fab$b_fac = FAB$M_BIO | FAB$M_PUT;    /* Get ready for block
  483.                              * output */
  484.     outfab->fab$l_xab = 0L;    /* Unlink all XABs */
  485.  
  486.     if ((ierr = sys$open(outfab)) != RMS$_NORMAL)
  487.     {
  488.         char buf[256];
  489.  
  490.         sprintf(buf, "[ Cannot open output file %s ]\n", filename);
  491.         message(buf, ierr);
  492.         message("", outfab->fab$l_stv);
  493.         free_up();
  494.         return PK_WARN;
  495.     }
  496.     }
  497.  
  498.     outrab = &rab;
  499.     rab.rab$l_fab = outfab;
  500.     if (!text_output)
  501.     {   rab.rab$l_rop |= RAB$M_BIO;
  502.         rab.rab$l_rop |= RAB$M_ASY;
  503.     }
  504.     rab.rab$b_rac = RAB$C_SEQ;
  505.  
  506.     if ((ierr = sys$connect(outrab)) != RMS$_NORMAL)
  507.     {
  508. #ifdef DEBUG
  509.     message("create_output_file: sys$connect failed.\n", ierr);
  510.     message("", outfab->fab$l_stv);
  511. #endif
  512.     fprintf(stderr, "Can't create output file:  %s\n", filename);
  513.     free_up();
  514.     return PK_WARN;
  515.     }
  516.  
  517.     init_buf_ring();
  518.  
  519.     if( text_output )
  520.     switch(rfm)
  521.     {
  522.         case FAB$C_VAR:
  523.             _flush_routine = _flush_varlen;
  524.             break;
  525.         case FAB$C_STM:
  526.         case FAB$C_STMCR:
  527.         case FAB$C_STMLF:
  528.             _flush_routine = _flush_stream;
  529.             got_eol = 0;
  530.             break;
  531.         default:
  532.             _flush_routine = _flush_blocks;
  533.             break;
  534.     }
  535.     else
  536.     _flush_routine = _flush_blocks;
  537.     _close_routine = _close_rms;
  538.     return PK_COOL;
  539. }
  540.  
  541.  
  542.  
  543. static    int pka_devchn;
  544. static    int pka_vbn;
  545.  
  546. static struct
  547. {   short   status;
  548.     long    count;
  549.     short   dummy;
  550. } pka_io_sb;
  551.  
  552. static struct
  553. {   short   status;
  554.     short   dummy;
  555.     void    *addr;
  556. } pka_acp_sb;
  557.  
  558. static struct fibdef    pka_fib;
  559. static struct atrdef    pka_atr[VMS_MAX_ATRCNT];
  560. static int        pka_idx;
  561. static ulg        pka_uchar;
  562. static struct fatdef    pka_rattr;
  563.  
  564. static struct dsc$descriptor    pka_fibdsc =
  565. {   sizeof(pka_fib), DSC$K_DTYPE_Z, DSC$K_CLASS_S, (void *) &pka_fib    };
  566.  
  567. static struct dsc$descriptor_s    pka_devdsc =
  568. {   0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &nam.nam$t_dvi[1]    };
  569.  
  570. static struct dsc$descriptor_s pka_fnam =
  571. {   0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0    };
  572.  
  573.  
  574.  
  575. static int create_qio_output()
  576. {   int status;
  577.     static char exp_nam[NAM$C_MAXRSS];
  578.     static char res_nam[NAM$C_MAXRSS];
  579.     int    i;
  580.  
  581.     if( cflag )
  582.     {    fprintf(stderr,"[ Cannot put to screen ]\n");
  583.     return PK_DISK;
  584.     }
  585.  
  586.     fileblk = cc$rms_fab;
  587.     fileblk.fab$l_fna = filename;
  588.     fileblk.fab$b_fns = strlen(filename);
  589.  
  590.     nam = cc$rms_nam;
  591.     fileblk.fab$l_nam = &nam;
  592.     nam.nam$l_esa = exp_nam;
  593.     nam.nam$b_ess = sizeof(exp_nam);
  594.     nam.nam$l_rsa = res_nam;
  595.     nam.nam$b_rss = sizeof(res_nam);
  596.  
  597.     if( ERR(status = sys$parse(&fileblk)) )
  598.     {    message("create_output_file: sys$parse failed.\n", status);
  599.     return PK_DISK;
  600.     }       
  601.  
  602.     pka_devdsc.dsc$w_length = (unsigned short)nam.nam$t_dvi[0];
  603.  
  604.     if( ERR(status = sys$assign(&pka_devdsc,&pka_devchn,0,0)) )
  605.     {    message("sys$assign failed.\n",status);
  606.     return PK_DISK;
  607.     }
  608.  
  609.     pka_fnam.dsc$a_pointer = nam.nam$l_name;
  610.     pka_fnam.dsc$w_length  = nam.nam$b_name + nam.nam$b_type;
  611.     if( V_flag /* keep versions */ )
  612.     pka_fnam.dsc$w_length += nam.nam$b_ver;
  613.  
  614.     for (i=0;i<3;i++)
  615.     {    pka_fib.FIB$W_DID[i]=nam.nam$w_did[i];
  616.         pka_fib.FIB$W_FID[i]=0;
  617.     }
  618.  
  619.     pka_fib.FIB$L_ACCTL = FIB$M_WRITE;
  620.     /* Allocate space for the file */
  621.     pka_fib.FIB$W_EXCTL = FIB$M_EXTEND;
  622.     if( pka_uchar & FCH$M_CONTIG )
  623.     pka_fib.FIB$W_EXCTL |= FIB$M_ALCON | FIB$M_FILCON;
  624.     if( pka_uchar & FCH$M_CONTIGB )
  625.     pka_fib.FIB$W_EXCTL |= FIB$M_ALCONB;
  626.  
  627. #define SWAPW(x)    ( (((x)>>16)&0xFFFF) + ((x)<<16) )
  628.  
  629.     pka_fib.fib$l_exsz = SWAPW(pka_rattr.fat$r_hiblk_overlay.fat$l_hiblk);
  630.  
  631.     status = sys$qiow(0, pka_devchn, IO$_CREATE|IO$M_CREATE|IO$M_ACCESS,
  632.     &pka_acp_sb, 0, 0,
  633.     &pka_fibdsc, &pka_fnam, 0, 0, &pka_atr, 0);
  634.  
  635.     if( !ERR(status) )
  636.     status = pka_acp_sb.status;
  637.  
  638.     if( ERR(status) )
  639.     {    message("[ Create file QIO failed.\n",status);
  640.     return PK_DISK;
  641.     sys$dassgn(pka_devchn);
  642.     }
  643.  
  644.     pka_vbn = 1;
  645.     _flush_routine = _flush_qio;
  646.     _close_routine = _close_qio;
  647.     return PK_COOL;
  648. }
  649.  
  650.  
  651.  
  652. static int replace()
  653. {            /*
  654.             *    File exists. Inquire user about further action.
  655.             */
  656.     char answ[10];
  657.     struct NAM nam;
  658.     int ierr;
  659.  
  660.     if (query == 0)
  661.     {
  662.     do
  663.     {
  664.         fprintf(stderr,
  665.             "%s exists:  [o]verwrite, new [v]ersion or [n]o extract?\n\
  666.   (uppercase response [O,V,N] = do same for all files): ",
  667.             filename);
  668.         fflush(stderr);
  669.     } while (fgets(answ, 9, stderr) == NULL && !isalpha(answ[0])
  670.          && tolower(answ[0]) != 'o'
  671.          && tolower(answ[0]) != 'v'
  672.          && tolower(answ[0]) != 'n');
  673.  
  674.     if (isupper(answ[0]))
  675.         query = answ[0] = tolower(answ[0]);
  676.     }
  677.     else
  678.     answ[0] = query;
  679.  
  680.     switch (answ[0])
  681.     {
  682.     case 'n':
  683.         ierr = 0;
  684.         break;
  685.     case 'v':
  686.         nam = cc$rms_nam;
  687.         nam.nam$l_rsa = filename;
  688.         nam.nam$b_rss = FILNAMSIZ - 1;
  689.  
  690.         outfab->fab$l_fop |= FAB$M_MXV;
  691.         outfab->fab$l_nam = &nam;
  692.  
  693.         ierr = sys$create(outfab);
  694.         if (!ERR(ierr))
  695.         {
  696.         outfab->fab$l_nam = 0L;
  697.         filename[outfab->fab$b_fns = nam.nam$b_rsl] = 0;
  698.         }
  699.         break;
  700.     case 'o':
  701.         outfab->fab$l_fop |= FAB$M_SUP;
  702.         ierr = sys$create(outfab);
  703.         break;
  704.     }
  705.     return ierr;
  706. }
  707.  
  708.  
  709.  
  710. #define W(p)    (*(unsigned short*)(p))
  711. #define L(p)    (*(unsigned long*)(p))
  712. #define EQL_L(a,b)      ( L(a) == L(b) )
  713. #define EQL_W(a,b)      ( W(a) == W(b) )
  714.  
  715. /****************************************************************
  716.  * Function find_vms_attrs scans ZIP entry extra field if any   *
  717.  * and looks for VMS attribute records. Returns 0 if either no  *
  718.  * attributes found or no fab given.                            *
  719.  ****************************************************************/
  720. int find_vms_attrs()
  721. {
  722.     uch *scan = extra_field;
  723.     struct  EB_header *hdr;
  724.     int len;
  725.     int    type=VAT_NONE;
  726.  
  727.     outfab = NULL;
  728.     xabfhc = NULL;
  729.     xabdat = NULL;
  730.     xabrdt = NULL;
  731.     xabpro = NULL;
  732.     first_xab = last_xab = NULL;
  733.  
  734.     if (scan == NULL)
  735.     return PK_COOL;
  736.     len = lrec.extra_field_length;
  737.  
  738. #define LINK(p) {    /* Link xaballs and xabkeys into chain */    \
  739.                 if( first_xab == 0L )                   \
  740.                         first_xab = (void *) p;         \
  741.                 if( last_xab != 0L )                    \
  742.                         last_xab -> xab$l_nxt = (void *) p;             \
  743.                 last_xab = (void *) p;                  \
  744.                 p -> xab$l_nxt = 0;                     \
  745.         }
  746.     /* End of macro LINK */
  747.  
  748.     while (len > 0)
  749.     {
  750.     hdr = (struct EB_header *) scan;
  751.     if (EQL_W(&hdr->tag, IZ_SIGNATURE))
  752.     {
  753.         /*
  754.         *    INFO-ZIP style extra block decoding
  755.         */
  756.         struct IZ_block *blk;
  757.         uch *block_id;
  758.  
  759.         type = VAT_IZ;        
  760.  
  761.         blk = (struct IZ_block *)hdr;
  762.         block_id = (uch *) &blk->bid;
  763.         if (EQL_L(block_id, FABSIG))
  764.         {
  765.         outfab = (struct FAB *) extract_block(blk, 0,
  766.                               &cc$rms_fab, FABL);
  767.         }
  768.         else if (EQL_L(block_id, XALLSIG))
  769.         {
  770.         xaball = (struct XABALL *) extract_block(blk, 0,
  771.                              &cc$rms_xaball, XALLL);
  772.         LINK(xaball);
  773.         }
  774.         else if (EQL_L(block_id, XKEYSIG))
  775.         {
  776.         xabkey = (struct XABKEY *) extract_block(blk, 0,
  777.                              &cc$rms_xabkey, XKEYL);
  778.         LINK(xabkey);
  779.         }
  780.         else if (EQL_L(block_id, XFHCSIG))
  781.         {
  782.         xabfhc = (struct XABFHC *) extract_block(blk, 0,
  783.                              &cc$rms_xabfhc, XFHCL);
  784.         }
  785.         else if (EQL_L(block_id, XDATSIG))
  786.         {
  787.         xabdat = (struct XABDAT *) extract_block(blk, 0,
  788.                              &cc$rms_xabdat, XDATL);
  789.         }
  790.         else if (EQL_L(block_id, XRDTSIG))
  791.         {
  792.         xabrdt = (struct XABRDT *) extract_block(blk, 0,
  793.                              &cc$rms_xabrdt, XRDTL);
  794.         }
  795.         else if (EQL_L(block_id, XPROSIG))
  796.         {
  797.         xabpro = (struct XABPRO *) extract_block(blk, 0,
  798.                              &cc$rms_xabpro, XPROL);
  799.         }
  800.         else if (EQL_L(block_id, VERSIG))
  801.         {
  802. #ifdef CHECK_VERSIONS
  803.         char verbuf[80];
  804.         int verlen = 0;
  805.         uch *vers;
  806.         char *m;
  807.  
  808.         get_vms_version(verbuf, 80);
  809.         vers = extract_block(blk, &verlen, 0, 0);
  810.         if ((m = strrchr((char *) vers, '-')) != NULL)
  811.             *m = 0;    /* Cut out release number */
  812.         if (strcmp(verbuf, (char *) vers) && qflag < 2)
  813.         {
  814.             printf("[ Warning: VMS version mismatch.");
  815.  
  816.             printf("   This version %s --", verbuf);
  817.             strncpy(verbuf, (char *) vers, verlen);
  818.             verbuf[verlen] = 0;
  819.             printf(" version made by %s ]\n", verbuf);
  820.         }
  821.         free(vers);
  822. #endif
  823.         }
  824.         else
  825.         fprintf(stderr, "[ Warning: Unknown block signature %s ]\n",
  826.             block_id);
  827.     }
  828.     else if (hdr->tag == PK_SIGNATURE || hdr->tag == IZ_NEW_SIGNATURE)
  829.     {
  830.         /*
  831.         *    PKWARE style extra block decoding
  832.         */
  833.         struct  PK_header    *blk;
  834.         register byte   *scn;
  835.         register int    len;
  836.  
  837.         type = VAT_PK;        
  838.  
  839.         blk = (struct PK_header *)hdr;
  840.         len = blk -> size;
  841.         scn = (byte *)(&blk->data);
  842.         pka_idx = 0;
  843.         
  844.         while(len > PK_FLDHDR_SIZE)
  845.         {    register struct  PK_field    *fld;
  846.         int    skip=0;
  847.  
  848.         fld = (struct PK_field *)scn;
  849.         switch(fld->tag)
  850.         {   case ATR$C_UCHAR:
  851.             pka_uchar = L(&fld->value);
  852.             break;
  853.             case ATR$C_RECATTR:
  854.             pka_rattr = *(struct fatdef *)(&fld->value);
  855.             break;
  856.             case ATR$C_UIC:
  857.             case ATR$C_ADDACLENT:
  858.             skip = !secinf;
  859.             break;
  860.         }
  861.  
  862.         if( !skip )
  863.         {   pka_atr[pka_idx].atr$w_size = fld->size;
  864.             pka_atr[pka_idx].atr$w_type = fld->tag;
  865.             pka_atr[pka_idx].atr$l_addr = &fld->value;
  866.             ++pka_idx;
  867.         }
  868.         len -= fld->size + PK_FLDHDR_SIZE;
  869.         scn += fld->size + PK_FLDHDR_SIZE;
  870.         }
  871.         pka_atr[pka_idx].atr$w_size = 0;    /* End of list */
  872.         pka_atr[pka_idx].atr$w_type = 0;
  873.         pka_atr[pka_idx].atr$l_addr = 0L;
  874.     }
  875.     len -= hdr->size + 4;
  876.     scan += hdr->size + 4;
  877.     }
  878.  
  879.  
  880.     if( type == VAT_IZ )
  881.     {    if (outfab != 0)
  882.     {    /* Do not link XABPRO,XABRDT now. Leave them for sys$close() */
  883.  
  884.         outfab->fab$l_xab = 0L;
  885.         if (xabfhc != 0L)
  886.         {
  887.         xabfhc->xab$l_nxt = outfab->fab$l_xab;
  888.         outfab->fab$l_xab = (void *) xabfhc;
  889.         }
  890.         if (xabdat != 0L)
  891.         {
  892.         xabdat->xab$l_nxt = outfab->fab$l_xab;
  893.         outfab->fab$l_xab = (void *) xabdat;
  894.         }
  895.         if (first_xab != 0L)    /* Link xaball,xabkey subchain */
  896.         {
  897.         last_xab->xab$l_nxt = outfab->fab$l_xab;
  898.         outfab->fab$l_xab = (void *) first_xab;
  899.         }
  900.     }
  901.         else
  902.         type = VAT_NONE;
  903.     }
  904.     return type;
  905. }
  906.  
  907.  
  908.  
  909. static void free_up()
  910. {                /*
  911.                 *    Free up all allocated xabs
  912.                 */
  913.     if (xabdat != 0L) free(xabdat);
  914.     if (xabpro != 0L) free(xabpro);
  915.     if (xabrdt != 0L) free(xabrdt);
  916.     if (xabfhc != 0L) free(xabfhc);
  917.     while (first_xab != 0L)
  918.     {
  919.     struct XAB *x;
  920.  
  921.     x = (struct XAB *) first_xab->xab$l_nxt;
  922.     free(first_xab);
  923.     first_xab = x;
  924.     }
  925.     if (outfab != 0L && outfab != &fileblk)
  926.     free(outfab);
  927. }
  928.  
  929.  
  930.  
  931. #ifdef CHECK_VERSIONS
  932.  
  933. static int get_vms_version(verbuf, len)
  934.     char *verbuf;
  935.     int len;
  936. {
  937.     int i = SYI$_VERSION;
  938.     int verlen = 0;
  939.     struct dsc$descriptor version;
  940.     char *m;
  941.  
  942.     version.dsc$a_pointer = verbuf;
  943.     version.dsc$w_length = len - 1;
  944.     version.dsc$b_dtype = DSC$K_DTYPE_B;
  945.     version.dsc$b_class = DSC$K_CLASS_S;
  946.  
  947.     if (ERR(lib$getsyi(&i, 0, &version, &verlen, 0, 0)) || verlen == 0)
  948.     return 0;
  949.  
  950.     /* Cut out trailing spaces "V5.4-3   " -> "V5.4-3" */
  951.     for (m = verbuf + verlen, i = verlen - 1; i > 0 && verbuf[i] == ' '; --i)
  952.     --m;
  953.     *m = 0;
  954.  
  955.     /* Cut out release number "V5.4-3" -> "V5.4" */
  956.     if ((m = strrchr(verbuf, '-')) != NULL)
  957.     *m = 0;
  958.     return strlen(verbuf) + 1;    /* Transmit ending 0 too */
  959. }
  960.  
  961. #endif /* CHECK_VERSIONS */
  962.  
  963.  
  964.  
  965. /*
  966.  * Extracts block from p. If resulting length is less then needed, fill
  967.  * extra space with corresponding bytes from 'init'.
  968.  * Currently understands 3 formats of block compression:
  969.  * - Simple storing
  970.  * - Compression of zero bytes to zero bits
  971.  * - Deflation (see memextract() in extract.c)
  972.  */
  973. static uch *extract_block(p, retlen, init, needlen)
  974.     struct IZ_block *p;
  975.     int *retlen;
  976.     uch *init;
  977.     int needlen;
  978. {
  979.     uch *block;        /* Pointer to block allocated */
  980.     int cmptype;
  981.     int usiz, csiz, max;
  982.  
  983.     cmptype = p->flags & BC_MASK;
  984.     csiz = p->size - EXTBSL - RESL;
  985.     usiz = (cmptype == BC_STORED ? csiz : p->length);
  986.  
  987.     if (needlen == 0)
  988.     needlen = usiz;
  989.  
  990.     if (retlen)
  991.     *retlen = usiz;
  992.  
  993. #ifndef MAX
  994. #define MAX(a,b)    ( (a) > (b) ? (a) : (b) )
  995. #endif
  996.  
  997.     if ((block = (uch *) malloc(MAX(needlen, usiz))) == NULL)
  998.     return NULL;
  999.  
  1000.     if (init && (usiz < needlen))
  1001.     memcpy(block, init, needlen);
  1002.  
  1003.     switch (cmptype)
  1004.     {
  1005.     case BC_STORED:    /* The simplest case */
  1006.         memcpy(block, &(p->body[0]), usiz);
  1007.         break;
  1008.     case BC_00:
  1009.         decompress_bits(block, usiz, &(p->body[0]));
  1010.         break;
  1011.     case BC_DEFL:
  1012.         memextract(block, usiz, &(p->body[0]), csiz);
  1013.         break;
  1014.     default:
  1015.         free(block);
  1016.         block = NULL;
  1017.     }
  1018.     return block;
  1019. }
  1020.  
  1021.  
  1022.  
  1023. /*
  1024.  *  Simple uncompression routine. The compression uses bit stream.
  1025.  *  Compression scheme:
  1026.  *
  1027.  *  if(byte!=0)
  1028.  *      putbit(1),putbyte(byte)
  1029.  *  else
  1030.  *      putbit(0)
  1031.  */
  1032. static void decompress_bits(outptr, needlen, bitptr)
  1033.     uch *bitptr;    /* Pointer into compressed data */
  1034.     uch *outptr;    /* Pointer into output block */
  1035.     int needlen;    /* Size of uncompressed block */
  1036. {
  1037.     ulg bitbuf = 0;
  1038.     int bitcnt = 0;
  1039.  
  1040. #define _FILL   if(bitcnt+8 <= 32)                      \
  1041.                 {       bitbuf |= (*bitptr++) << bitcnt;\
  1042.                         bitcnt += 8;                    \
  1043.                 }
  1044.  
  1045.     while (needlen--)
  1046.     {
  1047.     if (bitcnt <= 0)
  1048.         _FILL;
  1049.  
  1050.     if (bitbuf & 1)
  1051.     {
  1052.         bitbuf >>= 1;
  1053.         if ((bitcnt -= 1) < 8)
  1054.         _FILL;
  1055.         *outptr++ = (uch) bitbuf;
  1056.         bitcnt -= 8;
  1057.         bitbuf >>= 8;
  1058.     }
  1059.     else
  1060.     {
  1061.         *outptr++ = 0;
  1062.         bitcnt -= 1;
  1063.         bitbuf >>= 1;
  1064.     }
  1065.     }
  1066. }
  1067.  
  1068.  
  1069.  
  1070. static void UpdateCRC(s, len)
  1071.     register uch *s;
  1072.     register int len;
  1073. {
  1074.     register ulg crcval = crc32val;
  1075.  
  1076.     /* update running CRC calculation with contents of a buffer */
  1077.     while (len--)
  1078.         crcval = crc_32_tab[((uch)crcval ^ (*s++)) & 0xff] ^ (crcval >> 8);
  1079.     crc32val = crcval;
  1080. }
  1081.  
  1082.  
  1083.  
  1084. /* flush contents of output buffer */
  1085. int flush(rawbuf, size, unshrink)    /* return PK-type error code */
  1086.     uch *rawbuf;
  1087.     ulg size;
  1088.     int unshrink;
  1089. {
  1090.     UpdateCRC(rawbuf, size);
  1091.     if (tflag)
  1092.     return PK_COOL;    /* Do not output. Update CRC only */
  1093.     else
  1094.     return (*_flush_routine)(rawbuf, size, 0);
  1095. }
  1096.  
  1097.  
  1098.  
  1099. static int _flush_blocks(rawbuf, size, final_flag)   /* Asynchronous version */
  1100.     uch *rawbuf;
  1101.     unsigned size;
  1102.     int final_flag;   /* 1 if this is the final flushout */
  1103. {
  1104.     int round;
  1105.     int rest;
  1106.     int off = 0;
  1107.     int status;
  1108.  
  1109.     while (size > 0)
  1110.     {
  1111.     if (curbuf->bufcnt < BUFS512)
  1112.     {
  1113.         int ncpy;
  1114.  
  1115.         ncpy = size > (BUFS512 - curbuf->bufcnt) ?
  1116.                 BUFS512 - curbuf->bufcnt :
  1117.                 size;
  1118.         memcpy(curbuf->buf + curbuf->bufcnt, rawbuf + off, ncpy);
  1119.         size -= ncpy;
  1120.         curbuf->bufcnt += ncpy;
  1121.         off += ncpy;
  1122.     }
  1123.     if (curbuf->bufcnt == BUFS512)
  1124.     {
  1125.         status = WriteBuffer(curbuf->buf, curbuf->bufcnt);
  1126.         if (status)
  1127.         return status;
  1128.         curbuf = curbuf->next;
  1129.         curbuf->bufcnt = 0;
  1130.     }
  1131.     }
  1132.  
  1133.     return (final_flag && (curbuf->bufcnt > 0)) ?
  1134.     WriteBuffer(curbuf->buf, curbuf->bufcnt) :
  1135.     PK_COOL;
  1136. }
  1137.  
  1138.  
  1139.  
  1140. static int _flush_qio(rawbuf, size, final_flag)
  1141.     uch *rawbuf;
  1142.     unsigned size;
  1143.     int final_flag;   /* 1 if this is the final flushout -- currently ignored */
  1144. {
  1145.     int status;
  1146.     uch    *out_ptr=rawbuf;
  1147.  
  1148.     if( final_flag )
  1149.     {    
  1150.     if( loccnt > 0 )
  1151.     {   status = sys$qiow(0, pka_devchn, IO$_WRITEVBLK, 
  1152.         &pka_io_sb, 0, 0,
  1153.         locbuf, ((loccnt+1)/2)*2,   /* Round to event byte count */
  1154.         pka_vbn,
  1155.         0, 0, 0);
  1156.         if(!ERR(status))        
  1157.         status = pka_io_sb.status;
  1158.         if(ERR(status))
  1159.         {   message("[ Write QIO failed ]\n",status);
  1160.         return PK_DISK;
  1161.         }
  1162.     }
  1163.     return PK_COOL;    
  1164.     }
  1165.  
  1166.     if( loccnt > 0 )
  1167.     {    /*
  1168.     *   Fill local buffer upto 512 bytes then put it out
  1169.     */
  1170.     int ncpy;
  1171.  
  1172.     ncpy = 512-loccnt;
  1173.     if( ncpy > size )
  1174.         ncpy = size;
  1175.  
  1176.     memcpy(locptr,rawbuf,ncpy);
  1177.     locptr += ncpy;
  1178.     loccnt += ncpy;
  1179.     size -= ncpy;
  1180.     out_ptr += ncpy;
  1181.     if( loccnt == 512 )
  1182.     {     
  1183.         status = sys$qiow(0, pka_devchn, IO$_WRITEVBLK, 
  1184.         &pka_io_sb, 0, 0,
  1185.         locbuf, loccnt, pka_vbn,
  1186.         0, 0, 0);
  1187.         if(!ERR(status))        
  1188.         status = pka_io_sb.status;
  1189.         if(ERR(status))
  1190.         {   message("[ Write QIO failed ]\n",status);
  1191.         return PK_DISK;
  1192.         }
  1193.  
  1194.         pka_vbn++;
  1195.         loccnt = 0;
  1196.         locptr = locbuf;
  1197.     }
  1198.     }
  1199.  
  1200.     if( size >= 512 )
  1201.     {    int nblk,put_cnt;
  1202.  
  1203.     /*
  1204.     *   Put rest of buffer as a single VB
  1205.     */
  1206.     put_cnt = (nblk = size>>9)<<9;
  1207.     status = sys$qiow(0, pka_devchn, IO$_WRITEVBLK, 
  1208.         &pka_io_sb, 0, 0,
  1209.         out_ptr, put_cnt, pka_vbn,
  1210.         0, 0, 0);
  1211.     if(!ERR(status))        
  1212.         status = pka_io_sb.status;
  1213.     if(ERR(status))
  1214.     {   message("[ Write QIO failed ]\n",status);
  1215.         return PK_DISK;
  1216.     }
  1217.  
  1218.     pka_vbn += nblk;
  1219.     out_ptr += put_cnt;
  1220.     size -= put_cnt;
  1221.     }
  1222.  
  1223.     if( size > 0 )
  1224.     {    memcpy(locptr,out_ptr,size);
  1225.     loccnt += size;
  1226.     locptr += size;
  1227.     }
  1228.  
  1229.  
  1230.     return PK_COOL;
  1231. }
  1232.  
  1233.  
  1234.  
  1235. static int _flush_varlen(rawbuf, size, final_flag)
  1236.     uch *rawbuf;
  1237.     unsigned size;
  1238.     int final_flag;
  1239. {
  1240.     ush nneed;
  1241.     ush reclen;
  1242.     uch *inptr=rawbuf;
  1243.  
  1244.     /*
  1245.     *    Flush local buffer
  1246.     */
  1247.  
  1248.     if( loccnt > 0 )
  1249.     {    reclen = *(ush*)locbuf;
  1250.         if( (nneed = reclen + 2 - loccnt) > 0 )
  1251.         {    if( nneed > size )
  1252.             {    if( size+loccnt > BUFS512 )
  1253.                 {    fprintf(stderr,"[ Record too long (%d bytes) ]\n",reclen );
  1254.                     return PK_DISK;
  1255.                 }
  1256.                 memcpy(locbuf+loccnt,rawbuf,size);
  1257.                 loccnt += size;
  1258.                 size = 0;
  1259.             }
  1260.             else
  1261.             {    memcpy(locbuf+loccnt,rawbuf,nneed);
  1262.                 loccnt += nneed;
  1263.                 size -= nneed;
  1264.                 inptr += nneed;
  1265.                 if( reclen & 1 )
  1266.                 {    size--;
  1267.                     inptr++;
  1268.                 }
  1269.                 if( WriteRecord(locbuf+2,reclen) )
  1270.                     return PK_DISK;
  1271.                 loccnt = 0;
  1272.             }
  1273.         }
  1274.         else
  1275.         {    if(WriteRecord(locbuf+2,reclen))
  1276.                 return PK_DISK;
  1277.             loccnt -= reclen+2;
  1278.         }
  1279.     }
  1280.     /*
  1281.     *    Flush incoming records
  1282.     */
  1283.     while(size > 0)
  1284.     {    reclen = *(ush*)inptr;
  1285.         if( reclen+2 <= size )
  1286.         {    if(WriteRecord(inptr+2,reclen))
  1287.                 return PK_DISK;
  1288.             size -= 2+reclen;
  1289.             inptr += 2+reclen;
  1290.             if( reclen & 1)
  1291.             {    --size;
  1292.                 ++inptr;
  1293.             }
  1294.         }
  1295.         else
  1296.         {    memcpy(locbuf,inptr,size);
  1297.             loccnt = size;
  1298.             size = 0;
  1299.         }
  1300.                     
  1301.     }
  1302.     /*
  1303.     *    Final flush rest of local buffer
  1304.     */
  1305.     if( final_flag && loccnt > 0 )
  1306.     {    fprintf(stderr,
  1307.             "[ Warning, incomplete record of length %d ]\n",
  1308.             *(ush*)locbuf);
  1309.         if( WriteRecord(locbuf+2,loccnt-2) )
  1310.             return PK_DISK;
  1311.     }
  1312.     return PK_COOL;
  1313. }
  1314.  
  1315.  
  1316.  
  1317. /*
  1318. *   Routine _flush_stream breaks decompressed stream into records
  1319. *   depending on format of the stream (fab->rfm, pInfo->textmode, etc.)
  1320. *   and puts out these records. It also handles CR LF sequences.
  1321. *   Should be used when extracting *text* files.
  1322. */
  1323.  
  1324. #define VT    0x0B
  1325. #define FF    0x0C
  1326.  
  1327. /* The file is from MSDOS/OS2/NT -> handle CRLF as record end, throw out ^Z */
  1328.  
  1329. /* GRR NOTES:  cannot depend on hostnum!  May have "flip'd" file or re-zipped
  1330.  * a Unix file, etc. */
  1331.  
  1332. #ifdef    USE_ORIG_DOS
  1333. # define ORG_DOS    (hostnum==FS_FAT_ || hostnum==FS_HPFS_ || hostnum==FS_NTFS_)
  1334. #else
  1335. # define ORG_DOS    1
  1336. #endif
  1337.  
  1338. /* Record delimiters */
  1339. #ifdef    undef
  1340. #define RECORD_END(c,f)                            \
  1341. (        ( ORG_DOS || pInfo->textmode ) && c==CTRLZ            \
  1342.     || ( f == FAB$C_STMLF && c==LF )                \
  1343.     || ( f == FAB$C_STMCR || ORG_DOS || pInfo->textmode ) && c==CR    \
  1344.     || ( f == FAB$C_STM && (c==CR || c==LF || c==FF || c==VT) )    \
  1345. )
  1346. #else
  1347. #   define  RECORD_END(c,f)   ((c) == LF || (c) == (CR))
  1348. #endif
  1349.  
  1350. static int  find_eol(p,n,l)
  1351. /*
  1352.  *  Find first CR,LF,CR-LF or LF-CR in string 'p' of length 'n'.
  1353.  *  Return offset of the sequence found or 'n' if not found.
  1354.  *  If found, return in '*l' length of the sequence (1 or 2) or
  1355.  *  zero if sequence end not seen, i.e. CR or LF is last char
  1356.  *  in the buffer.
  1357.  */
  1358. char    *p;
  1359. int    n;
  1360. int    *l;
  1361. {   int    off = n;
  1362.     char    *q;
  1363.  
  1364.     *l = 0;
  1365.  
  1366.     for(q=p ; n > 0 ; --n,++q)
  1367.     if( RECORD_END(*q,rfm) )
  1368.     {   off = q-p;
  1369.         break;
  1370.     }
  1371.  
  1372.     if( n > 1 )
  1373.     {
  1374.     *l = 1;
  1375.     if( ( q[0] == CR && q[1] == LF ) || ( q[0] == LF && q[1] == CR ) )
  1376.         *l = 2;
  1377.     }
  1378.  
  1379.     return off;
  1380. }
  1381.  
  1382. /* Record delimiters that must be put out */
  1383. #define PRINT_SPEC(c)    ( (c)==FF || (c)==VT )
  1384.  
  1385.  
  1386.  
  1387. static int _flush_stream(rawbuf, size, final_flag)
  1388.     uch *rawbuf;
  1389.     unsigned size;
  1390.     int final_flag; /* 1 if this is the final flushout */
  1391. {
  1392.     int rest;
  1393.     int end = 0, start = 0;
  1394.     int off = 0;
  1395.                  
  1396.     if (size == 0 && loccnt == 0)
  1397.     return PK_COOL;        /* Nothing to do ... */
  1398.  
  1399.     if( final_flag )
  1400.     {    int recsize;
  1401.  
  1402.     /*
  1403.      * This is flush only call. size must be zero now.
  1404.      * Just eject everything we have in locbuf.
  1405.      */
  1406.     recsize = loccnt - (got_eol ? 1:0);
  1407.     /*
  1408.      *  If the last char of file was ^Z ( end-of-file in MSDOS ),
  1409.      *  we will see it now.
  1410.      */
  1411.     if( recsize==1 && locbuf[0] == CTRLZ )
  1412.         return PK_COOL;
  1413.  
  1414.     return WriteRecord(locbuf, recsize) ? PK_DISK : PK_COOL;
  1415.     }
  1416.  
  1417.  
  1418.     if ( loccnt > 0 )
  1419.     {    /* Find end of record partialy saved in locbuf */
  1420.  
  1421.     int recsize;
  1422.     int complete=0;
  1423.  
  1424.     if( got_eol )
  1425.     {   recsize = loccnt - 1;
  1426.         complete = 1;
  1427.  
  1428.         if( (got_eol == CR && rawbuf[0] == LF) || (got_eol == LF && rawbuf[0] == CR) )
  1429.         end = 1;
  1430.  
  1431.         got_eol = 0;
  1432.     }
  1433.     else
  1434.     {   int    eol_len;
  1435.         int    eol_off;
  1436.  
  1437.         eol_off = find_eol(rawbuf,size,&eol_len);
  1438.  
  1439.         if( loccnt+eol_off > BUFS512 )
  1440.         {    /*
  1441.          *  No room in locbuf. Dump it and clear
  1442.          */
  1443.         recsize = loccnt;
  1444.         start = 0;
  1445.         fprintf(stderr, "[ Warning: Record too long (%d) ]\n",
  1446.             loccnt+eol_off);
  1447.         complete = 1;
  1448.         end = 0;
  1449.         }
  1450.         else
  1451.         {    if( eol_off >= size )
  1452.         {   end = size;
  1453.             complete = 0;
  1454.         }
  1455.         else if( eol_len == 0 )
  1456.         {   got_eol = rawbuf[eol_off];
  1457.             end = size;
  1458.             complete = 0;
  1459.         }
  1460.         else
  1461.         {   memcpy(locptr, rawbuf, eol_off);
  1462.             recsize = loccnt + eol_off;
  1463.             locptr += eol_off;
  1464.             loccnt += eol_off;
  1465.             end = eol_off + eol_len;
  1466.             complete = 1;
  1467.         }
  1468.         }
  1469.     }
  1470.  
  1471.     if( complete )
  1472.     {   if (WriteRecord(locbuf, recsize))
  1473.         return PK_DISK;
  1474.         loccnt = 0;
  1475.         locptr = locbuf;
  1476.     }
  1477.     }                /* end if( loccnt ) */
  1478.  
  1479.     for(start = end; start < size && end < size; )
  1480.     {    int eol_off,eol_len;
  1481.  
  1482.     got_eol = 0;
  1483.  
  1484. #ifdef undef
  1485.         if (cflag)
  1486.         /* skip CR's at the beginning of record */
  1487.             while (start < size && rawbuf[start] == CR)
  1488.                 ++start;
  1489. #endif
  1490.  
  1491.     if( start >= size )
  1492.         continue;
  1493.  
  1494.     /* Find record end */
  1495.     end = start+(eol_off = find_eol(rawbuf+start, size-start, &eol_len));
  1496.  
  1497.         if( end >= size )
  1498.         continue;
  1499.  
  1500.     if( eol_len > 0 )
  1501.     {   if( WriteRecord(rawbuf+start, end-start) )
  1502.         return PK_DISK;
  1503.         start = end + eol_len;
  1504.     }
  1505.     else
  1506.     {   got_eol = rawbuf[end];
  1507.         end = size;
  1508.         continue;
  1509.     }
  1510.     }
  1511.  
  1512.     rest = size - start;
  1513.  
  1514.     if (rest > 0)
  1515.     {    if( rest > BUFS512 )
  1516.     {   int    recsize;
  1517.  
  1518.         recsize = rest - (got_eol ? 1:0 );
  1519.         fprintf(stderr, "[ Warning: Record too long (%d) ]\n", recsize);
  1520.         got_eol = 0;
  1521.         return WriteRecord(rawbuf+start,recsize) ? PK_DISK : PK_COOL;
  1522.     }
  1523.     else
  1524.     {   memcpy(locptr, rawbuf + start, rest);
  1525.         locptr += rest;
  1526.         loccnt += rest;
  1527.     }
  1528.     }
  1529.     return PK_COOL;
  1530. }
  1531.  
  1532.  
  1533.  
  1534. static int WriteBuffer(buf, len)
  1535.     unsigned char *buf;
  1536.     int len;
  1537. {
  1538.     int status;
  1539.  
  1540.     status = sys$wait(outrab);
  1541.     if (ERR(status))
  1542.     {
  1543.     message("[ WriteBuffer failed ]\n", status);
  1544.     message("", outrab->rab$l_stv);
  1545.     }
  1546.     outrab->rab$w_rsz = len;
  1547.     outrab->rab$l_rbf = (char *) buf;
  1548.  
  1549.     if (ERR(status = sys$write(outrab)))
  1550.     {
  1551.     message("[ WriteBuffer failed ]\n", status);
  1552.     message("", outrab->rab$l_stv);
  1553.     return PK_DISK;
  1554.     }
  1555.     return PK_COOL;
  1556. }
  1557.  
  1558.  
  1559.  
  1560. static int WriteRecord(rec, len)
  1561.     unsigned char *rec;
  1562.     int len;
  1563. {
  1564.     int status;
  1565.  
  1566.     if (ERR(status = sys$wait(outrab)))
  1567.     {
  1568.     message("[ WriteRecord failed ]\n", status);
  1569.     message("", outrab->rab$l_stv);
  1570.     }
  1571.     outrab->rab$w_rsz = len;
  1572.     outrab->rab$l_rbf = (char *) rec;
  1573.  
  1574.     if (ERR(status = sys$put(outrab)))
  1575.     {
  1576.     message("[ WriteRecord failed ]\n", status);
  1577.     message("", outrab->rab$l_stv);
  1578.     return PK_DISK;
  1579.     }
  1580.     return PK_COOL;
  1581. }
  1582.  
  1583.  
  1584.  
  1585. void close_outfile()
  1586. {
  1587.     int status;
  1588.  
  1589.     status = (*_flush_routine)(0, 0, 1);     
  1590.     if (status)
  1591.         return /* PK_DISK */;
  1592.     if (cflag)
  1593.         return;         /* Don't close stdout */
  1594.     /* return */ (*_close_routine)();
  1595. }
  1596.  
  1597.  
  1598.  
  1599. static int _close_rms()
  1600. {
  1601.     int status;
  1602.     struct XABPRO pro;
  1603.  
  1604.     /* Link XABRDT,XABDAT and optionaly XABPRO */
  1605.     if (xabrdt != 0L)
  1606.     {
  1607.     xabrdt->xab$l_nxt = 0L;
  1608.     outfab->fab$l_xab = (void *) xabrdt;
  1609.     }
  1610.     else
  1611.     {
  1612.     rdt.xab$l_nxt = 0L;
  1613.     outfab->fab$l_xab = (void *) &rdt;
  1614.     }
  1615.     if (xabdat != 0L)
  1616.     {
  1617.     xabdat->xab$l_nxt = outfab->fab$l_xab;
  1618.     outfab->fab$l_xab = (void *)xabdat;
  1619.     }
  1620.  
  1621.     if( xabpro != 0L )
  1622.     {
  1623.     if( !secinf )
  1624.         xabpro->xab$l_uic = 0;    /* Use default (user's) uic */
  1625.     xabpro->xab$l_nxt = outfab->fab$l_xab;
  1626.     outfab->fab$l_xab = (void *) xabpro;
  1627.     }
  1628.     else
  1629.     {    pro = cc$rms_xabpro;
  1630.     pro.xab$w_pro = pInfo->file_attr;
  1631.     pro.xab$l_nxt = outfab->fab$l_xab;
  1632.     outfab->fab$l_xab = (void *) &pro;
  1633.     }
  1634.  
  1635.     sys$wait(outrab);
  1636.  
  1637.     status = sys$close(outfab);
  1638. #ifdef DEBUG
  1639.     if (ERR(status))
  1640.     {
  1641.     message("\r[ Warning: cannot set owner/protection/time attributes ]\n",
  1642.       status);
  1643.     message("", outfab->fab$l_stv);
  1644.     }
  1645. #endif
  1646.     free_up();
  1647.     return PK_COOL;
  1648. }
  1649.  
  1650.  
  1651.  
  1652. static int _close_qio()
  1653. {   int status;
  1654.  
  1655.     pka_fib.FIB$L_ACCTL =
  1656.     FIB$M_WRITE | FIB$M_NOTRUNC ;
  1657.     pka_fib.FIB$W_EXCTL = 0;
  1658.  
  1659.     pka_fib.FIB$W_FID[0] =
  1660.     pka_fib.FIB$W_FID[1] =
  1661.     pka_fib.FIB$W_FID[2] =
  1662.     pka_fib.FIB$W_DID[0] =
  1663.     pka_fib.FIB$W_DID[1] =
  1664.     pka_fib.FIB$W_DID[2] = 0;
  1665.  
  1666.     status = sys$qiow(0, pka_devchn, IO$_DEACCESS, &pka_acp_sb,
  1667.         0, 0,
  1668.         &pka_fibdsc, 0, 0, 0,
  1669.         &pka_atr, 0);
  1670.  
  1671.     sys$dassgn(pka_devchn);
  1672.     if( !ERR(status) )
  1673.     status = pka_acp_sb.status;
  1674.     if( ERR(status) )
  1675.     {    message("[ Deaccess QIO failed ]\n",status);
  1676.     return PK_DISK;
  1677.     }
  1678.     return PK_COOL;
  1679. }
  1680.  
  1681.  
  1682.  
  1683. #ifdef DEBUG
  1684. dump_rms_block(p)
  1685.     unsigned char *p;
  1686. {
  1687.     unsigned char bid, len;
  1688.     int err;
  1689.     char *type;
  1690.     char buf[132];
  1691.     int i;
  1692.  
  1693.     err = 0;
  1694.     bid = p[0];
  1695.     len = p[1];
  1696.     switch (bid)
  1697.     {
  1698.     case FAB$C_BID:
  1699.         type = "FAB";
  1700.         break;
  1701.     case XAB$C_ALL:
  1702.         type = "xabALL";
  1703.         break;
  1704.     case XAB$C_KEY:
  1705.         type = "xabKEY";
  1706.         break;
  1707.     case XAB$C_DAT:
  1708.         type = "xabDAT";
  1709.         break;
  1710.     case XAB$C_RDT:
  1711.         type = "xabRDT";
  1712.         break;
  1713.     case XAB$C_FHC:
  1714.         type = "xabFHC";
  1715.         break;
  1716.     case XAB$C_PRO:
  1717.         type = "xabPRO";
  1718.         break;
  1719.     default:
  1720.         type = "Unknown";
  1721.         err = 1;
  1722.         break;
  1723.     }
  1724.     printf("Block @%08X of type %s (%d).", p, type, bid);
  1725.     if (err)
  1726.     {
  1727.     printf("\n");
  1728.     return;
  1729.     }
  1730.     printf(" Size = %d\n", len);
  1731.     printf(" Offset - Hex - Dec\n");
  1732.     for (i = 0; i < len; i += 8)
  1733.     {
  1734.     int j;
  1735.  
  1736.     printf("%3d - ", i);
  1737.     for (j = 0; j < 8; j++)
  1738.         if (i + j < len)
  1739.         printf("%02X ", p[i + j]);
  1740.         else
  1741.         printf("   ");
  1742.     printf(" - ");
  1743.     for (j = 0; j < 8; j++)
  1744.         if (i + j < len)
  1745.         printf("%03d ", p[i + j]);
  1746.         else
  1747.         printf("    ");
  1748.     printf("\n");
  1749.     }
  1750. }
  1751.  
  1752. #endif                /* DEBUG */
  1753.  
  1754.  
  1755.  
  1756. static void message(string, status)
  1757.     int status;
  1758. char *string;
  1759. {
  1760.     char msgbuf[256];
  1761.  
  1762.     $DESCRIPTOR(msgd, msgbuf);
  1763.     int msglen = 0;
  1764.  
  1765.     if (ERR(lib$sys_getmsg(&status, &msglen, &msgd, 0, 0)))
  1766.     fprintf(stderr, "%s[ VMS status = %d ]\n", string, status);
  1767.     else
  1768.     {
  1769.     msgbuf[msglen] = 0;
  1770.     fprintf(stderr, "%s[ %s ]\n", string, msgbuf);
  1771.     }
  1772. }
  1773.  
  1774.  
  1775.  
  1776. #ifndef SFX
  1777.  
  1778. char *do_wild( wld )
  1779.     char *wld;
  1780. {
  1781.     int status;
  1782.  
  1783.     static char filename[256];
  1784.     static char efn[256];
  1785.     static char last_wild[256];
  1786.     static struct FAB fab;
  1787.     static struct NAM nam;
  1788.     static int first_call=1;
  1789.     static char deflt[] = "*.zip";
  1790.  
  1791.     if( first_call || strcmp(wld, last_wild) )
  1792.     {   /* (Re)Initialize everything */
  1793.  
  1794.         strcpy( last_wild, wld );
  1795.         first_call = 1;            /* New wild spec */
  1796.  
  1797.         fab = cc$rms_fab;
  1798.         fab.fab$l_fna = last_wild;
  1799.         fab.fab$b_fns = strlen(last_wild);
  1800.         fab.fab$l_dna = deflt;
  1801.         fab.fab$b_dns = strlen(deflt);
  1802.         fab.fab$l_nam = &nam;
  1803.         nam = cc$rms_nam;
  1804.         nam.nam$l_esa = efn;
  1805.         nam.nam$b_ess = sizeof(efn)-1;
  1806.         nam.nam$l_rsa = filename;
  1807.         nam.nam$b_rss = sizeof(filename)-1;
  1808.  
  1809.         if(!OK(sys$parse(&fab)))
  1810.             return (char *)NULL;     /* Initialization failed */
  1811.         first_call = 0;
  1812.         if( !OK(sys$search(&fab)) )
  1813.         {
  1814.             strcpy( filename, wld );
  1815.             return filename;
  1816.         }
  1817.     }
  1818.     else
  1819.     {
  1820.         if( !OK(sys$search(&fab)) )
  1821.         {
  1822.             first_call = 1;        /* Reinitialize next time */
  1823.             return (char *)NULL;
  1824.         }
  1825.     }
  1826.     filename[nam.nam$b_rsl] = 0;
  1827.     return filename;
  1828.  
  1829. } /* end function do_wild() */
  1830.  
  1831. #endif /* !SFX */
  1832.  
  1833.  
  1834.  
  1835. static ulg unix_to_vms[8]={ /* Map from UNIX rwx to VMS rwed */
  1836.                 /* Note that unix w bit is mapped to VMS wd bits */
  1837.     XAB$M_NOREAD | XAB$M_NOWRITE | XAB$M_NODEL | XAB$M_NOEXE,    /* --- no access*/
  1838.     XAB$M_NOREAD | XAB$M_NOWRITE | XAB$M_NODEL,                  /* --x */
  1839.     XAB$M_NOREAD |                               XAB$M_NOEXE,    /* -w- */
  1840.     XAB$M_NOREAD,                                                /* -wx */
  1841.                    XAB$M_NOWRITE | XAB$M_NODEL | XAB$M_NOEXE,    /* r-- */
  1842.                    XAB$M_NOWRITE | XAB$M_NODEL,                  /* r-x */
  1843.                                                  XAB$M_NOEXE,    /* rw- */
  1844.     0                                                            /* rwx full access*/
  1845. };
  1846.  
  1847. #define SETDFPROT   /* We are using undocumented VMS System Service    */
  1848.             /* SYS$SETDFPROT here. If your version of VMS does    */
  1849.             /* not have that service, undef SETDFPROT.        */
  1850.             /* IM: Maybe it's better to put this to Makefile    */
  1851.             /* and DESCRIP.MMS */
  1852.  
  1853.  
  1854.  
  1855. int mapattr()
  1856. {
  1857.     ulg  tmp=crec.external_file_attributes, theprot;
  1858.     static ulg  defprot = -1L,
  1859.         sysdef,owndef,grpdef,wlddef;  /* Default protection fields */
  1860.  
  1861.  
  1862.     /* IM: The only field of XABPRO we need to set here is */
  1863.     /*     file protection, so we need not to change type */
  1864.     /*     of pInfo->file_attr. WORD is quite enough. */
  1865.  
  1866.     if( defprot == -1L )
  1867.     {
  1868.     /*
  1869.     * First time here -- Get user default settings
  1870.     */
  1871.  
  1872. #ifdef SETDFPROT    /* Undef this if linker cat't resolve SYS$SETDFPROT */
  1873.     defprot = 0L;
  1874.     if( !ERR(SYS$SETDFPROT(0,&defprot)) )
  1875.     {
  1876.         sysdef = defprot & ( (1L<<XAB$S_SYS)-1 ) << XAB$V_SYS;
  1877.         owndef = defprot & ( (1L<<XAB$S_OWN)-1 ) << XAB$V_OWN;
  1878.         grpdef = defprot & ( (1L<<XAB$S_GRP)-1 ) << XAB$V_GRP;
  1879.         wlddef = defprot & ( (1L<<XAB$S_WLD)-1 ) << XAB$V_WLD;
  1880.     }
  1881.     else
  1882.     {
  1883. #endif /* ?SETDFPROT */
  1884.         umask(defprot = umask(0));
  1885.         defprot = ~defprot;
  1886.         wlddef = unix_to_vms[defprot & 07] << XAB$V_WLD;
  1887.         grpdef = unix_to_vms[(defprot>>3) & 07] << XAB$V_GRP;
  1888.         owndef = unix_to_vms[(defprot>>6) & 07] << XAB$V_OWN;
  1889.         sysdef = owndef << (XAB$V_SYS - XAB$V_OWN);
  1890.         defprot = sysdef | owndef | grpdef | wlddef;
  1891. #ifdef SETDFPROT
  1892.     }
  1893. #endif    /* ?SETDFPROT */
  1894.     }
  1895.  
  1896.     switch (pInfo->hostnum) {
  1897.         case UNIX_:
  1898.         case VMS_:  /*IM: ??? Does VMS Zip store protection in UNIX format ?*/
  1899.                     /* GRR:  Yup.  Bad decision on my part... */
  1900.             tmp = (unsigned)(tmp >> 16);  /* drwxrwxrwx */
  1901.         theprot  = (unix_to_vms[tmp & 07] << XAB$V_WLD)
  1902.                  | (unix_to_vms[(tmp>>3) & 07] << XAB$V_GRP)
  1903.                  | (unix_to_vms[(tmp>>6) & 07] << XAB$V_OWN);
  1904.  
  1905.         if( tmp & 0x4000 )
  1906.             /* Directory -- set D bits */
  1907.         theprot |= (XAB$M_NODEL << XAB$V_SYS)
  1908.             | (XAB$M_NODEL << XAB$V_OWN)
  1909.             | (XAB$M_NODEL << XAB$V_GRP)
  1910.             | (XAB$M_NODEL << XAB$V_WLD);
  1911.         pInfo->file_attr = theprot;
  1912.         break;
  1913.  
  1914.         case AMIGA_:
  1915.             tmp = (unsigned)(tmp>>16 & 0x0f);   /* Amiga RWED bits */
  1916.             pInfo->file_attr = (tmp << XAB$V_OWN) | grpdef | sysdef | wlddef;
  1917.             break;
  1918.  
  1919.         /* all remaining cases:  expand MSDOS read-only bit into write perms */
  1920.         case FS_FAT_:
  1921.         case FS_HPFS_:
  1922.         case FS_NTFS_:
  1923.         case MAC_:
  1924.         case ATARI_:             /* (used to set = 0666) */
  1925.         case TOPS20_:
  1926.         default:
  1927.         theprot = defprot;
  1928.         if( tmp & 1 )   /* Test read-only bit */
  1929.         {    /* Bit is set -- set bits in all fields */
  1930.         tmp = XAB$M_NOWRITE | XAB$M_NODEL;
  1931.         theprot |= (tmp << XAB$V_SYS) | (tmp << XAB$V_OWN) |
  1932.                (tmp << XAB$V_GRP) | (tmp << XAB$V_WLD);
  1933.         }
  1934.             pInfo->file_attr = theprot;
  1935.             break;
  1936.     } /* end switch (host-OS-created-by) */
  1937.  
  1938.     return 0;
  1939.  
  1940. } /* end function mapattr() */
  1941.  
  1942.  
  1943.  
  1944. #ifndef    EEXIST
  1945. #  include <errno.h>    /* For mkdir() status codes */
  1946. #endif
  1947.  
  1948. #include <fscndef.h> /* for filescan */
  1949.  
  1950. #   define FN_MASK   7
  1951. #   define USE_DEFAULT    (FN_MASK+1)
  1952.  
  1953. /*
  1954.  * Checkdir function codes:
  1955.  *    ROOT        -   set root path from unzip qq d:[dir]
  1956.  *    INIT        -   get ready for "filename"
  1957.  *    APPEND_DIR  -    append pathcomp
  1958.  *    APPEND_NAME -    append filename
  1959.  *    APPEND_NAME | USE_DEFAULT   -    expand filename using collected path
  1960.  *    GETPATH     -    return resulting filespec
  1961.  */
  1962.  
  1963. static    int created_dir;
  1964.  
  1965. int mapname(renamed)  /* return 0 if no error, 1 if caution (filename trunc),*/
  1966.     int renamed;      /* 2 if warning (skip file because dir doesn't exist), */
  1967. {                     /* 3 if error (skip file), 10 if no memory (skip file) */
  1968.     char pathcomp[FILNAMSIZ];   /* path-component buffer */
  1969.     char *pp, *cp=NULL;         /* character pointers */
  1970.     char *lastsemi = NULL;      /* pointer to last semi-colon in pathcomp */
  1971.     char *last_dot = NULL;      /* last dot not converted to underscore */
  1972.     int quote = FALSE;          /* flag:  next char is literal */
  1973.     int dotname = FALSE;        /* flag:  path component begins with dot */
  1974.     int error = 0;
  1975.     register unsigned workch;   /* hold the character being tested */
  1976.  
  1977.     if( renamed )
  1978.     {
  1979.             if( !(error = checkdir(pathcomp, APPEND_NAME | USE_DEFAULT)) )
  1980.             strcpy(filename, pathcomp);
  1981.         return error;
  1982.     }
  1983.         
  1984. /*---------------------------------------------------------------------------
  1985.     Initialize various pointers and counters and stuff.
  1986.   ---------------------------------------------------------------------------*/
  1987.  
  1988.     /* can create path as long as not just freshening, or if user told us */
  1989.     create_dirs = !fflag;
  1990.  
  1991.     created_dir = FALSE;        /* not yet */
  1992.  
  1993. /* GRR:  for VMS, convert to internal format now or later? or never? */
  1994.     if (checkdir(pathcomp, INIT) == 10)
  1995.         return 10;              /* initialize path buffer, unless no memory */
  1996.  
  1997.     *pathcomp = '\0';           /* initialize translation buffer */
  1998.     pp = pathcomp;              /* point to translation buffer */
  1999.     if (jflag)              /* junking directories */
  2000. /* GRR:  watch out for VMS version... */
  2001.         cp = (char *)strrchr(filename, '/');
  2002.     if (cp == NULL)             /* no '/' or not junking dirs */
  2003.         cp = filename;          /* point to internal zipfile-member pathname */
  2004.     else
  2005.         ++cp;                   /* point to start of last component of path */
  2006.  
  2007. /*---------------------------------------------------------------------------
  2008.     Begin main loop through characters in filename.
  2009.   ---------------------------------------------------------------------------*/
  2010.  
  2011.     while ((workch = (uch)*cp++) != 0) {
  2012.  
  2013.         if (quote) {              /* if character quoted, */
  2014.             *pp++ = (char)workch; /*  include it literally */
  2015.             quote = FALSE;
  2016.         } else
  2017.             switch (workch) {
  2018.             case '/':             /* can assume -j flag not given */
  2019.                 *pp = '\0';
  2020.                 if (last_dot) {   /* one dot in directory name is legal */
  2021.                     *last_dot = '.';
  2022.                     last_dot = NULL;
  2023.                 }
  2024.                 if ((error = checkdir(pathcomp, APPEND_DIR)) > 1)
  2025.                     return error;
  2026.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  2027.                 lastsemi = NULL;  /* leave directory semi-colons alone */
  2028.                 break;
  2029.  
  2030.             case ':':
  2031.                 *pp++ = '_';      /* drive names not stored in zipfile, */
  2032.                 break;            /*  so no colons allowed */
  2033.  
  2034.             case '.':
  2035.                 if (pp == pathcomp) {     /* nothing appended yet... */
  2036.                     if (*cp == '/') {     /* don't bother appending a "./" */
  2037.                         ++cp;             /*  component to the path:  skip */
  2038.                         break;            /*  to next char after the '/' */
  2039.                     } else if (*cp == '.' && cp[1] == '/') {   /* "../" */
  2040.                         *pp++ = '.';      /* add first dot, unchanged... */
  2041.                         ++cp;             /* skip second dot, since it will */
  2042.                     }                     /*  added next (as '_' for now) */
  2043.                 }
  2044.                 last_dot = pp;    /* point at last dot so far... */
  2045.                 *pp++ = '_';      /* convert dot to underscore for now */
  2046.                 break;
  2047.  
  2048.             case ';':             /* start of VMS version? */
  2049.                 if (lastsemi)
  2050.                     *lastsemi = '_';   /* convert previous one to underscore */
  2051.                 lastsemi = pp;
  2052.                 *pp++ = ';';      /* keep for now; remove VMS vers. later */
  2053.                 break;
  2054.  
  2055.             case ' ':
  2056.                 *pp++ = '_';
  2057.                 break;
  2058.  
  2059.             default:
  2060.                 if( isalpha(workch) || isdigit(workch) ||
  2061.                     workch=='$' || workch=='-' )
  2062.                     *pp++ = (char)workch;
  2063.                 else
  2064.                     *pp++ = '_';  /* convert everything else to underscore */
  2065.                 break;
  2066.             } /* end switch */
  2067.  
  2068.     } /* end while loop */
  2069.  
  2070.     *pp = '\0';                   /* done with pathcomp:  terminate it */
  2071.  
  2072.     /* if not saving them, remove VMS version numbers (appended "###") */
  2073.     if (lastsemi) {
  2074.         pp = lastsemi + 1;        /* expect all digits after semi-colon */
  2075.         while (isdigit((uch)(*pp)))
  2076.             ++pp;
  2077.         if (*pp)                  /* not version number:  convert ';' to '_' */
  2078.             *lastsemi = '_';
  2079.         else if (!V_flag)         /* only digits between ';' and end:  nuke */
  2080.             *lastsemi = '\0';
  2081.         /* else only digits and we're saving version number:  do nothing */
  2082.     }
  2083.  
  2084.     if (last_dot != NULL)         /* one dot is OK:  put it back in */
  2085.         *last_dot = '.';          /* (already done for directories) */
  2086.  
  2087. /*---------------------------------------------------------------------------
  2088.     Report if directory was created (and no file to create:  filename ended
  2089.     in '/'), check name to be sure it exists, and combine path and name be-
  2090.     fore exiting.
  2091.   ---------------------------------------------------------------------------*/
  2092.  
  2093.     if (filename[strlen(filename) - 1] == '/') {
  2094.         checkdir("", APPEND_NAME);   /* create directory, if not found */
  2095.         checkdir(filename, GETPATH);
  2096.         if (created_dir && QCOND2) {
  2097.             fprintf(stdout, "   creating: %s\n", filename);
  2098.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  2099.         }
  2100.         return 2;   /* dir existed already; don't look for data to extract */
  2101.     }
  2102.  
  2103.     if (*pathcomp == '\0') {
  2104.         fprintf(stderr, "mapname:  conversion of %s failed\n", filename);
  2105.         return 3;
  2106.     }
  2107.  
  2108.     checkdir(pathcomp, APPEND_NAME);   /* returns 1 if truncated:  care? */
  2109.     checkdir(filename, GETPATH);
  2110.  
  2111.     return error;
  2112.  
  2113. } /* end function mapname() */
  2114.  
  2115.  
  2116.  
  2117. int checkdir(pathcomp,fcn)
  2118. /*
  2119.  * returns:  1 - (on APPEND_NAME) truncated filename
  2120.  *           2 - path doesn't exist, not allowed to create
  2121.  *           3 - path doesn't exist, tried to create and failed; or
  2122.  *               path exists and is not a directory, but is supposed to be
  2123.  *           4 - path is too long
  2124.  *          10 - can't allocate memory for filename buffers
  2125.  */
  2126.     char *pathcomp;
  2127.     int fcn;
  2128. {
  2129.     int function=fcn & FN_MASK;
  2130.     static char pathbuf[FILNAMSIZ];
  2131.     static char lastdir[FILNAMSIZ]="\t"; /* directory created last time */
  2132.                          /* initially - impossible dir. spec. */
  2133.     static char *pathptr=pathbuf;        /* For debugger */
  2134.     static char *devptr, *dirptr, *namptr;
  2135.     static int  devlen, dirlen, namlen;
  2136.     static int  root_dirlen;
  2137.     static char *end;
  2138.     static int  first_comp,root_has_dir;
  2139.     static int  rootlen=0;
  2140.     static char *rootend;
  2141.     static int  mkdir_failed=0;
  2142.     int status;
  2143.  
  2144. /************
  2145.  *** ROOT ***
  2146.  ************/
  2147.  
  2148. #if (!defined(SFX) || defined(SFX_EXDIR))
  2149.     if(function==ROOT)
  2150.     {        /*  Assume VMS root spec */
  2151.         char  *p = pathcomp;
  2152.         char  *q;
  2153.  
  2154.         struct
  2155.         {   short  len;
  2156.             short  code;
  2157.             char   *addr;
  2158.         } itl [4] =
  2159.         {
  2160.             {  0,  FSCN$_DEVICE,    0  },
  2161.             {  0,  FSCN$_ROOT,      0  },
  2162.             {  0,  FSCN$_DIRECTORY, 0  },
  2163.             {  0,  0,               0  }   /* End of itemlist */
  2164.         };
  2165.         int fields = 0;
  2166.         struct dsc$descriptor  pthcmp;
  2167.  
  2168.         /*
  2169.          *  Initialize everything
  2170.          */
  2171.         end = devptr = dirptr = rootend = pathbuf;
  2172.         devlen = dirlen = rootlen = 0;
  2173.  
  2174.         pthcmp.dsc$a_pointer = pathcomp;
  2175.         if( (pthcmp.dsc$w_length = strlen(pathcomp)) > 255 )
  2176.             return 4;
  2177.  
  2178.         status = sys$filescan(&pthcmp, itl, &fields);
  2179.         if( !OK(status) )
  2180.             return 3;
  2181.  
  2182.         if( fields & FSCN$M_DEVICE )
  2183.         {   strncpy(devptr = end, itl[0].addr, itl[0].len);
  2184.             dirptr = (end += (devlen = itl[0].len));
  2185.         }
  2186.  
  2187.         root_has_dir = 0;
  2188.  
  2189.         if( fields & FSCN$M_ROOT )
  2190.         {   int   len;
  2191.  
  2192.             strncpy(dirptr = end, itl[1].addr,
  2193.                 len = itl[1].len - 1);        /* Cut out trailing ']' */
  2194.             end += len;
  2195.             root_has_dir = 1;
  2196.         }
  2197.  
  2198.         if( fields & FSCN$M_DIRECTORY )
  2199.         {   char  *ptr;
  2200.             int   len;
  2201.  
  2202.             len = itl[2].len-1;
  2203.             ptr = itl[2].addr;
  2204.  
  2205.             if( root_has_dir /* i.e. root specified */ )
  2206.             {   --len;                            /* Cut out leading dot */
  2207.                 ++ptr;                            /* ??? [a.b.c.][.d.e] */
  2208.             }
  2209.  
  2210.             strncpy(dirptr=end, ptr, len);  /* Replace trailing ']' */
  2211.             *(end+=len) = '.';                    /* ... with dot */
  2212.             ++end;
  2213.             root_has_dir = 1;
  2214.         }
  2215.  
  2216.         /* When user specified "[a.b.c.]" or "[qq...]", we have too many
  2217.         *  trailing dots. Let's cut them out. Now we surely have at least
  2218.         *  one trailing dot and "end" points just behind it. */
  2219.  
  2220.         dirlen = end - dirptr;
  2221.         while( dirlen > 1 && end[-2] == '.' )
  2222.             --dirlen,--end;
  2223.  
  2224.         first_comp = !root_has_dir;
  2225.         root_dirlen = end - dirptr;
  2226.         *(rootend = end) = 0;
  2227.         rootlen = rootend - devptr;
  2228.         return 0;
  2229.     }
  2230. #endif /* !SFX || SFX_EXDIR */
  2231.  
  2232.  
  2233. /************
  2234.  *** INIT ***
  2235.  ************/
  2236.  
  2237.     if( function == INIT )
  2238.     {
  2239.         if( strlen(filename) + rootlen + 13 > 255 )
  2240.             return 4;
  2241.  
  2242.     if( rootlen == 0 )    /* No root given, reset everything. */
  2243.     {   devptr = dirptr = rootend = pathbuf;
  2244.         devlen = dirlen = 0;
  2245.     }
  2246.         end = rootend;
  2247.         first_comp = !root_has_dir;
  2248.         if( dirlen = root_dirlen )
  2249.         end[-1] = '.';
  2250.     *end = 0;
  2251.         return        0;
  2252.     }
  2253.  
  2254.  
  2255. /******************
  2256.  *** APPEND_DIR ***
  2257.  ******************/
  2258.     if( function == APPEND_DIR )
  2259.     {        int cmplen;
  2260.  
  2261.     cmplen = strlen(pathcomp);
  2262.  
  2263.         if( first_comp )
  2264.         {   *end++ = '[';
  2265.         if( cmplen )
  2266.         *end++ = '.';    /*       "dir/..." --> "[.dir...]"    */
  2267.         /*                     else  "/dir..." --> "[dir...]"     */
  2268.         first_comp = 0;
  2269.     }        
  2270.  
  2271.     if( cmplen == 1 && *pathcomp == '.' )
  2272.             ; /* "..././..." -- ignore */
  2273.  
  2274.         else if( cmplen == 2 && pathcomp[0] == '.' && pathcomp[1] == '.' )
  2275.         {   /* ".../../..." -- convert to "...-..." */
  2276.             *end++ = '-';
  2277.             *end++ = '.';
  2278.         }
  2279.  
  2280.         else if( cmplen + (end-pathptr) > 255 )
  2281.             return 4;
  2282.  
  2283.         else
  2284.         {   strcpy(end, pathcomp);
  2285.             *(end+=cmplen) = '.';
  2286.             ++end;
  2287.         }
  2288.         dirlen = end - dirptr;
  2289.         *end = 0;
  2290.         return        0;
  2291.     }
  2292.  
  2293.  
  2294. /*******************
  2295.  *** APPEND_NAME ***
  2296.  *******************/
  2297.     if( function == APPEND_NAME )
  2298.     {        if( fcn & USE_DEFAULT )
  2299.         {   /* Expand renamed filename using collected path, return
  2300.             *  at pathcomp */
  2301.             struct        FAB fab;
  2302.             struct        NAM nam;
  2303.  
  2304.             fab = cc$rms_fab;
  2305.             fab.fab$l_fna = filename;
  2306.             fab.fab$b_fns = strlen(filename);
  2307.             fab.fab$l_dna = pathptr;
  2308.             fab.fab$b_dns = end-pathptr;
  2309.  
  2310.             fab.fab$l_nam = &nam;
  2311.             nam = cc$rms_nam;
  2312.             nam.nam$l_esa = pathcomp;
  2313.             nam.nam$b_ess = 255;            /* Assume large enaugh */
  2314.  
  2315.             if(!OK(status = sys$parse(&fab)) && status == RMS$_DNF )    /* Directory not found: */
  2316.             {   char    save;            /* ... try to create it */
  2317.                 char    *dirend;
  2318.                 int     mkdir_failed;
  2319.  
  2320.                 dirend = (char*)nam.nam$l_dir + nam.nam$b_dir;
  2321.                 save = *dirend;
  2322.                 *dirend = 0;
  2323.                 if( (mkdir_failed = mkdir(nam.nam$l_dev, 0)) && errno == EEXIST )
  2324.                     mkdir_failed = 0;
  2325.                 *dirend = save;
  2326.                 if( mkdir_failed )
  2327.                     return 3;
  2328.                 created_dir = TRUE;
  2329.             }                                /* if (sys$parse... */
  2330.             pathcomp[nam.nam$b_esl] = 0;
  2331.             return 0;
  2332.         }                                /* if (USE_DEFAULT) */
  2333.         else
  2334.         {
  2335.         *end = 0;
  2336.             if( dirlen )
  2337.             {    dirptr[dirlen-1] = ']'; /* Close directory */
  2338.  
  2339.         /*
  2340.          *    Try to create the target directory.
  2341.          *  Don't waste time creating directory that was created
  2342.          *    last time.
  2343.          */
  2344.         if( STRICMP(lastdir,pathbuf) )
  2345.         {
  2346.             mkdir_failed = 0;
  2347.             if( mkdir(pathbuf,0) )
  2348.             {   if( errno != EEXIST )
  2349.                 mkdir_failed = 1;   /* Mine for GETPATH */
  2350.             }
  2351.             else
  2352.             created_dir = TRUE;
  2353.             strcpy(lastdir,pathbuf);
  2354.         }
  2355.         }
  2356.         else
  2357.         {    /*
  2358.          * Target directory unspecified.
  2359.          * Try to create "sys$disk:[]"
  2360.          */
  2361.         if( strcmp(lastdir,"sys$disk:[]") )
  2362.         {   strcpy(lastdir,"sys$disk:[]");
  2363.             mkdir_failed = 0;
  2364.             if( mkdir(lastdir,0) && errno != EEXIST )
  2365.             mkdir_failed = 1;   /* Mine for GETPATH */
  2366.         }        
  2367.         }
  2368.             if( strlen(pathcomp) + (end-pathbuf) > 255 )
  2369.                 return 1;
  2370.             strcpy(end, pathcomp);
  2371.             end += strlen(pathcomp);
  2372.             return 0;
  2373.         }
  2374.     }
  2375.  
  2376.  
  2377. /***************
  2378.  *** GETPATH ***
  2379.  ***************/
  2380.     if( function == GETPATH )
  2381.     {
  2382.         if( mkdir_failed )
  2383.             return 3;
  2384.         *end = 0;                        /* To be safe */
  2385.         strcpy( pathcomp, pathbuf );
  2386.         return 0;
  2387.     }
  2388. }
  2389.  
  2390.  
  2391.  
  2392. int check_for_newer(filename)   /* return 1 if existing file newer or equal; */
  2393.     char *filename;             /*  0 if older; -1 if doesn't exist yet */
  2394. {
  2395.     unsigned short timbuf[7];
  2396.     int dy, mo, yr, hh, mm, ss, dy2, mo2, yr2, hh2, mm2, ss2;
  2397.     struct FAB fab;
  2398.     struct XABDAT xdat;
  2399.  
  2400.  
  2401.     if (stat(filename, &statbuf))
  2402.         return DOES_NOT_EXIST;
  2403.  
  2404.     fab  = cc$rms_fab;
  2405.     xdat = cc$rms_xabdat;
  2406.  
  2407.     fab.fab$l_xab = (char *) &xdat;
  2408.     fab.fab$l_fna = filename;
  2409.     fab.fab$b_fns = strlen(filename);
  2410.     fab.fab$l_fop = FAB$M_GET | FAB$M_UFO;
  2411.  
  2412.     if ((sys$open(&fab) & 1) == 0)       /* open failure:  report exists and */
  2413.         return EXISTS_AND_OLDER;         /*  older so new copy will be made  */
  2414.     sys$numtim(&timbuf,&xdat.xab$q_cdt);
  2415.     fab.fab$l_xab = 0L;
  2416.  
  2417.     sys$dassgn(fab.fab$l_stv);
  2418.     sys$close(&fab);   /* be sure file is closed and RMS knows about it */
  2419.  
  2420.     yr = timbuf[0];
  2421.     yr2 = ((lrec.last_mod_file_date >> 9) & 0x7f) + 1980;
  2422.     if (yr > yr2)
  2423.         return EXISTS_AND_NEWER;
  2424.     else if (yr < yr2)
  2425.         return EXISTS_AND_OLDER;
  2426.  
  2427.     mo = timbuf[1];
  2428.     mo2 = ((lrec.last_mod_file_date >> 5) & 0x0f);
  2429.     if (mo > mo2)
  2430.         return EXISTS_AND_NEWER;
  2431.     else if (mo < mo2)
  2432.         return EXISTS_AND_OLDER;
  2433.  
  2434.     dy = timbuf[2];
  2435.     dy2 = (lrec.last_mod_file_date & 0x1f);
  2436.     if (dy > dy2)
  2437.         return EXISTS_AND_NEWER;
  2438.     else if (dy < dy2)
  2439.         return EXISTS_AND_OLDER;
  2440.  
  2441.     hh = timbuf[3];
  2442.     hh2 = (lrec.last_mod_file_time >> 11) & 0x1f;
  2443.     if (hh > hh2)
  2444.         return EXISTS_AND_NEWER;
  2445.     else if (hh < hh2)
  2446.         return EXISTS_AND_OLDER;
  2447.  
  2448.     mm = timbuf[4];
  2449.     mm2 = (lrec.last_mod_file_time >> 5) & 0x3f;
  2450.     if (mm > mm2)
  2451.         return EXISTS_AND_NEWER;
  2452.     else if (mm < mm2)
  2453.         return EXISTS_AND_OLDER;
  2454.  
  2455.     /* round to nearest 2 secs--may become 60, but doesn't matter for compare */
  2456.     ss = (int)((float)timbuf[5] + (float)timbuf[6]*.01 + 1.) & -2;
  2457.     ss2 = (lrec.last_mod_file_time & 0x1f) * 2;
  2458.     if (ss >= ss2)
  2459.         return EXISTS_AND_NEWER;
  2460.  
  2461.     return EXISTS_AND_OLDER;
  2462. }
  2463.  
  2464.  
  2465.  
  2466. void return_VMS(ziperr)
  2467.     int ziperr;
  2468. {
  2469. #ifdef RETURN_CODES
  2470. /*---------------------------------------------------------------------------
  2471.     Do our own, explicit processing of error codes and print message, since
  2472.     VMS misinterprets return codes as rather obnoxious system errors ("access
  2473.     violation," for example).
  2474.   ---------------------------------------------------------------------------*/
  2475.  
  2476.     switch (ziperr) {
  2477.  
  2478.     case PK_COOL:
  2479.         break;   /* life is fine... */
  2480.     case PK_WARN:
  2481.         fprintf(stderr, "\n[return-code 1:  warning error \
  2482. (e.g., failed CRC or unknown compression method)]\n");
  2483.         break;
  2484.     case PK_ERR:
  2485.     case PK_BADERR:
  2486.         fprintf(stderr, "\n[return-code %d:  error in zipfile \
  2487. (e.g., can't find local file header sig)]\n", ziperr);
  2488.         break;
  2489.     case PK_MEM:
  2490.     case PK_MEM2:
  2491.     case PK_MEM3:
  2492.     case PK_MEM4:
  2493.     case PK_MEM5:
  2494.         fprintf(stderr, "\n[return-code %d:  insufficient memory]\n", ziperr);
  2495.         break;
  2496.     case PK_NOZIP:
  2497.         fprintf(stderr, "\n[return-code 9:  zipfile not found]\n");
  2498.         break;
  2499.     case PK_PARAM:   /* the one that gives "access violation," I think */
  2500.         fprintf(stderr, "\n[return-code 10:  bad or illegal parameters \
  2501. specified on command line]\n");
  2502.         break;
  2503.     case PK_FIND:
  2504.         fprintf(stderr,
  2505.           "\n[return-code 11:  no files found to extract/view/etc.]\n");
  2506.         break;
  2507.     case PK_DISK:
  2508.         fprintf(stderr,
  2509.   "\n[return-code 50:  disk full or other I/O error]\n");
  2510.         break;
  2511.     case PK_EOF:
  2512.         fprintf(stderr,
  2513.           "\n[return-code 51:  unexpected EOF in zipfile (i.e., truncated)]\n");
  2514.         break;
  2515.     default:
  2516.         fprintf(stderr, "\n[return-code %d:  unknown return-code (screw-up)]\n",
  2517.           ziperr);
  2518.         break;
  2519.     }
  2520. #endif /* RETURN_CODES */
  2521.  
  2522. /*---------------------------------------------------------------------------
  2523.     Return an intelligent status/severity level if RETURN_SEVERITY defined:
  2524.  
  2525.     $STATUS          $SEVERITY = $STATUS & 7
  2526.     31 .. 16 15 .. 3   2 1 0
  2527.                        -----
  2528.     VMS                0 0 0  0    Warning
  2529.     FACILITY           0 0 1  1    Success
  2530.     Number             0 1 0  2    Error
  2531.              MESSAGE   0 1 1  3    Information
  2532.              Number    1 0 0  4    Severe (fatal) error
  2533.  
  2534.     0x7FFF0000 was chosen (by experimentation) to be outside the range of
  2535.     VMS FACILITYs that have dedicated message numbers.  Hopefully this will
  2536.     always result in silent exits--it does on VMS 5.4.  Note that the C li-
  2537.     brary translates exit arguments of zero to a $STATUS value of 1 (i.e.,
  2538.     exit is both silent and has a $SEVERITY of "success").
  2539.   ---------------------------------------------------------------------------*/
  2540.  
  2541. #ifdef RETURN_SEVERITY
  2542.     {
  2543.     int severity = (ziperr == 2 || (ziperr >= 9 && ziperr <= 11))? 2 : 4;
  2544.  
  2545.     exit(                                          /* $SEVERITY:    */
  2546.          (ziperr == PK_COOL) ? 1 :                 /*   success        */
  2547.          (ziperr == PK_WARN) ? 0x7FFF0000 :        /*   warning        */
  2548.          (0x7FFF0000 | (ziperr << 4) | severity)   /*   error or fatal    */
  2549.         );
  2550.     }
  2551. #else
  2552.     exit(0);   /* everything okey-dokey as far as VMS concerned */
  2553. #endif
  2554.  
  2555. } /* end function return_VMS() */
  2556.  
  2557.  
  2558.  
  2559.  
  2560.  
  2561. #ifndef SFX
  2562.  
  2563. /************************/
  2564. /*  Function version()  */
  2565. /************************/
  2566.  
  2567. void version()
  2568. {
  2569.     extern char Far  CompiledWith[];
  2570. #ifdef VMS_VERSION
  2571.     char buf[40];
  2572. #endif
  2573.  
  2574.     printf(LoadFarString(CompiledWith),
  2575.  
  2576. #ifdef __GNUC__
  2577.       "gcc ", __VERSION__,
  2578. #else
  2579. #  if 0
  2580.       "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
  2581. #  else
  2582. #  if defined(DECC) || defined(__DECC) || defined (__DECC__)
  2583.       "DEC C", "",
  2584. #  else
  2585. #  ifdef VAXC
  2586.       "VAX C", "",
  2587. #  else
  2588.       "unknown compiler", "",
  2589. #  endif
  2590. #  endif
  2591. #  endif
  2592. #endif
  2593.  
  2594. #ifdef VMS_VERSION
  2595. #  if defined(__alpha)
  2596.       "OpenVMS",   /* version has trailing spaces ("V6.1   "), so truncate: */
  2597.       (sprintf(buf, " (%.4s for Alpha)", VMS_VERSION), buf),
  2598. #  else /* VAX */
  2599.       (VMS_VERSION[1] >= '6')? "OpenVMS" : "VMS",
  2600.       (sprintf(buf, " (%.4s for VAX)", VMS_VERSION), buf),
  2601. #  endif
  2602. #else
  2603.       "VMS",
  2604.       "",
  2605. #endif /* ?VMS_VERSION */
  2606.  
  2607. #ifdef __DATE__
  2608.       " on ", __DATE__
  2609. #else
  2610.       "", ""
  2611. #endif
  2612.       );
  2613.  
  2614. } /* end function version() */
  2615.  
  2616. #endif /* !SFX */
  2617. #endif /* VMS */
  2618.