home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / zip21.zip / vms / cmdline.c < prev    next >
C/C++ Source or Header  |  1996-04-14  |  25KB  |  833 lines

  1. /*
  2.  
  3.  Copyright (C) 1990-1996 Mark Adler, Richard B. Wales, Jean-loup Gailly,
  4.  Kai Uwe Rommel, Christian Spieler, Onno van der Linden and Igor Mandrichenko.
  5.  Permission is granted to any individual or institution to use, copy, or
  6.  redistribute this software so long as all of the original files are included,
  7.  that it is not sold for profit, and that this copyright notice is retained.
  8.  
  9. */
  10.  
  11. #define module_name VMS_ZIP_CMDLINE
  12. #define module_ident "02-004"
  13. /*
  14. **
  15. **  Facility:   ZIP
  16. **
  17. **  Module:     VMS_ZIP_CMDLINE
  18. **
  19. **  Author:     Hunter Goatley <goathunter@WKUVX1.WKU.EDU>
  20. **
  21. **  Date:       July 30, 1993
  22. **
  23. **  Abstract:   Routines to handle a VMS CLI interface for Zip.  The CLI
  24. **              command line is parsed and a new argc/argv are built and
  25. **              returned to zip.
  26. **
  27. **  Modified by:
  28. **
  29. **      02-004          Onno van der Linden,
  30. **                      Christian Spieler       13-APR-1996 20:05
  31. **              Removed /ENCRYPT=VERIFY ("-ee" option).
  32. **      02-003          Christian Spieler       11-FEB-1996 23:05
  33. **              Added handling of /EXTRAFIELDS qualifier ("-X" option).
  34. **      02-002          Christian Spieler       09-JAN-1996 22:25
  35. **              Added "#include crypt.h", corrected typo.
  36. **      02-001          Christian Spieler       04-DEC-1995 16:00
  37. **              Fixed compilation in DEC CC's ANSI mode.
  38. **      02-000          Christian Spieler       10-OCT-1995 17:54
  39. **              Modified for Zip v2.1, added several new options.
  40. **      01-000          Hunter Goatley          30-JUL-1993 07:54
  41. **              Original version (for Zip v1.9p1).
  42. **
  43. */
  44.  
  45.  
  46. #ifdef __DECC
  47. #pragma module module_name module_ident
  48. #else
  49. #module module_name module_ident
  50. #endif
  51.  
  52. #include "zip.h"
  53. #include "crypt.h"
  54. #ifndef NOCPYRT
  55. # define NOCPYRT
  56. #endif
  57. #include "revision.h"   /* for help() */
  58.  
  59. #include <ssdef.h>
  60. #include <descrip.h>
  61. #include <climsgdef.h>
  62. #include <clidef.h>
  63. #include <lib$routines.h>
  64. #include <ots$routines.h>
  65. #include <str$routines.h>
  66.  
  67. #ifndef CLI$_COMMA
  68. globalvalue CLI$_COMMA;
  69. #endif
  70.  
  71. /*
  72. **  "Macro" to initialize a dynamic string descriptor.
  73. */
  74. #define init_dyndesc(dsc) {\
  75.         dsc.dsc$w_length = 0;\
  76.         dsc.dsc$b_dtype = DSC$K_DTYPE_T;\
  77.         dsc.dsc$b_class = DSC$K_CLASS_D;\
  78.         dsc.dsc$a_pointer = NULL;}
  79.  
  80. /*
  81. **  Define descriptors for all of the CLI parameters and qualifiers.
  82. */
  83. $DESCRIPTOR(cli_delete,         "DELETE");              /* -d */
  84. $DESCRIPTOR(cli_freshen,        "FRESHEN");             /* -f */
  85. $DESCRIPTOR(cli_move,           "MOVE");                /* -m */
  86. $DESCRIPTOR(cli_update,         "UPDATE");              /* -u */
  87. $DESCRIPTOR(cli_exclude,        "EXCLUDE");             /* -x */
  88. $DESCRIPTOR(cli_include,        "INCLUDE");             /* -i */
  89. $DESCRIPTOR(cli_adjust,         "ADJUST_OFFSETS");      /* -A */
  90. $DESCRIPTOR(cli_append,         "APPEND");              /* -g */
  91. $DESCRIPTOR(cli_batch,          "BATCH");               /* -@ */
  92. $DESCRIPTOR(cli_comments,       "COMMENTS");            /* -c,-z */
  93. $DESCRIPTOR(cli_comment_zipfile,"COMMENTS.ZIP_FILE");   /* -z */
  94. $DESCRIPTOR(cli_comment_files,  "COMMENTS.FILES");      /* -c */
  95. $DESCRIPTOR(cli_dirnames,       "DIRNAMES");            /* -D */
  96. #ifdef CRYPT
  97. $DESCRIPTOR(cli_encrypt,        "ENCRYPT");             /* -e */
  98. #endif /* CRYPT */
  99. $DESCRIPTOR(cli_extra_fields,   "EXTRA_FIELDS");        /* -X */
  100. $DESCRIPTOR(cli_fix_archive,    "FIX_ARCHIVE");         /* -F[F] */
  101. $DESCRIPTOR(cli_fix_normal,     "FIX_ARCHIVE.NORMAL");  /* -F */
  102. $DESCRIPTOR(cli_fix_full,       "FIX_ARCHIVE.FULL");    /* -FF */
  103. $DESCRIPTOR(cli_full_path,      "FULL_PATH");           /* -p */
  104. $DESCRIPTOR(cli_help,           "HELP");                /* -h */
  105. $DESCRIPTOR(cli_junk,           "JUNK");                /* -j */
  106. $DESCRIPTOR(cli_keep_version,   "KEEP_VERSION");        /* -w */
  107. $DESCRIPTOR(cli_latest,         "LATEST");              /* -o */
  108. $DESCRIPTOR(cli_level,          "LEVEL");               /* -[0-9] */
  109. $DESCRIPTOR(cli_license,        "LICENSE");             /* -L */
  110. $DESCRIPTOR(cli_pkzip,          "PKZIP");               /* -k */
  111. $DESCRIPTOR(cli_quiet,          "QUIET");               /* -q */
  112. $DESCRIPTOR(cli_recurse,        "RECURSE");             /* -r */
  113. $DESCRIPTOR(cli_since,          "SINCE");               /* -t */
  114. $DESCRIPTOR(cli_store_types,    "STORE_TYPES");         /* -n */
  115. $DESCRIPTOR(cli_temp_path,      "TEMP_PATH");           /* -b */
  116. $DESCRIPTOR(cli_test,           "TEST");                /* -T */
  117. $DESCRIPTOR(cli_translate_eol,  "TRANSLATE_EOL");       /* -l[l] */
  118. $DESCRIPTOR(cli_transl_eol_lf,  "TRANSLATE_EOL.LF");    /* -l */
  119. $DESCRIPTOR(cli_transl_eol_crlf,"TRANSLATE_EOL.CRLF");  /* -ll */
  120. $DESCRIPTOR(cli_unsfx,          "UNSFX");               /* -J */
  121. $DESCRIPTOR(cli_verbose,        "VERBOSE");             /* -v */
  122. $DESCRIPTOR(cli_verbose_more,   "VERBOSE.MORE");        /* -vv */
  123. $DESCRIPTOR(cli_verbose_debug,  "VERBOSE.DEBUG");       /* -vvv */
  124. $DESCRIPTOR(cli_vms,            "VMS");                 /* -V */
  125.  
  126. $DESCRIPTOR(cli_yyz,            "YYZ_ZIP");
  127.  
  128. $DESCRIPTOR(cli_zipfile,        "ZIPFILE");
  129. $DESCRIPTOR(cli_infile,         "INFILE");
  130. $DESCRIPTOR(zip_command,        "zip ");
  131.  
  132. #ifdef __DECC
  133. extern void *zip_clitable;
  134. #else
  135. globalref void *zip_clitable;
  136. #endif
  137.  
  138. /* extern unsigned long LIB$GET_INPUT(void), LIB$SIG_TO_RET(void); */
  139.  
  140. #ifndef __STARLET_LOADED
  141. extern int sys$bintim ();
  142. extern int sys$numtim ();
  143. #endif
  144. extern unsigned long cli$dcl_parse ();
  145. extern unsigned long cli$present ();
  146. extern unsigned long cli$get_value ();
  147.  
  148. unsigned long vms_zip_cmdline (int *, char ***);
  149. unsigned long get_list (struct dsc$descriptor_s *, char **,
  150.                         struct dsc$descriptor_d *, char);
  151. unsigned long check_cli (struct dsc$descriptor_s *);
  152.  
  153.  
  154. #ifdef TEST
  155. unsigned long
  156. main(int argc, char **argv)
  157. {
  158.     register status;
  159.     return (vms_zip_cmdline(&argc, &argv));
  160. }
  161. #endif /* TEST */
  162.  
  163.  
  164. unsigned long
  165. vms_zip_cmdline (int *argc_p, char ***argv_p)
  166. {
  167. /*
  168. **  Routine:    vms_zip_cmdline
  169. **
  170. **  Function:
  171. **
  172. **      Parse the DCL command line and create a fake argv array to be
  173. **      handed off to Zip.
  174. **
  175. **      NOTE: the argv[] is built as we go, so all the parameters are
  176. **      checked in the appropriate order!!
  177. **
  178. **  Formal parameters:
  179. **
  180. **      argc_p          - Address of int to receive the new argc
  181. **      argv_p          - Address of char ** to receive the argv address
  182. **
  183. **  Calling sequence:
  184. **
  185. **      status = vms_zip_cmdline (&argc, &argv);
  186. **
  187. **  Returns:
  188. **
  189. **      SS$_NORMAL      - Success.
  190. **      SS$_INSFMEM     - A malloc() or realloc() failed
  191. **      SS$_ABORT       - Bad time value
  192. **
  193. */
  194.     register status;
  195.     char options[48];
  196.     char *the_cmd_line;
  197.     char *ptr;
  198.     int  x, len;
  199.  
  200.     int new_argc;
  201.     char **new_argv;
  202.  
  203.     struct dsc$descriptor_d work_str;
  204.     struct dsc$descriptor_d foreign_cmdline;
  205.  
  206.     init_dyndesc (work_str);
  207.     init_dyndesc (foreign_cmdline);
  208.  
  209.     /*
  210.     **  See if the program was invoked by the CLI (SET COMMAND) or by
  211.     **  a foreign command definition.  Check for /YYZ_ZIP, which is a
  212.     **  valid default qualifier solely for this test.
  213.     */
  214.     status = check_cli (&cli_yyz);
  215.     if (!(status & 1)) {
  216.         lib$get_foreign (&foreign_cmdline);
  217.         /*
  218.         **  If nothing was returned or the first character is a "-", then
  219.         **  assume it's a UNIX-style command and return.
  220.         */
  221.         if ((foreign_cmdline.dsc$w_length == 0) ||
  222.             (*(foreign_cmdline.dsc$a_pointer) == '-'))
  223.             return(SS$_NORMAL);
  224.  
  225.         str$concat (&work_str, &zip_command, &foreign_cmdline);
  226.         status = cli$dcl_parse(&work_str, &zip_clitable, lib$get_input,
  227.                         lib$get_input, 0);
  228.         if (!(status & 1)) return(status);
  229.     }
  230.  
  231.     /*
  232.     **  There's always going to be a new_argv[] because of the image name.
  233.     */
  234.     if ((the_cmd_line = (char *) malloc (sizeof("zip")+1)) == NULL)
  235.         return(SS$_INSFMEM);
  236.  
  237.     strcpy (the_cmd_line, "zip");
  238.  
  239.     /*
  240.     **  First, check to see if any of the regular options were specified.
  241.     */
  242.  
  243.     options[0] = '-';
  244.     ptr = &options[1];          /* Point to temporary buffer */
  245.  
  246.     /*
  247.     **  Delete the specified files from the zip file?
  248.     */
  249.     status = cli$present (&cli_delete);
  250.     if (status & 1)
  251.         *ptr++ = 'd';
  252.  
  253.     /*
  254.     **  Freshen (only changed files).
  255.     */
  256.     status = cli$present (&cli_freshen);
  257.     if (status & 1)
  258.         *ptr++ = 'f';
  259.  
  260.     /*
  261.     **  Delete the files once they've been added to the zip file.
  262.     */
  263.     status = cli$present (&cli_move);
  264.     if (status & 1)
  265.         *ptr++ = 'm';
  266.  
  267.     /*
  268.     **  Add changed and new files.
  269.     */
  270.     status = cli$present (&cli_update);
  271.     if (status & 1)
  272.         *ptr++ = 'u';
  273.  
  274.     /*
  275.     **  Check for the compression level (-0 through -9).
  276.     */
  277.     status = cli$present(&cli_level);
  278.     if (status & 1) {
  279.  
  280.         unsigned long binval;
  281.  
  282.         status = cli$get_value (&cli_level, &work_str);
  283.         status = ots$cvt_tu_l (&work_str, &binval);
  284.         if (!(status & 1) || (binval > 9)) {
  285.            return(SS$_ABORT);
  286.         }
  287.         *ptr++ = binval + '0';
  288.     }
  289.  
  290.     /*
  291.     **  Adjust offsets of zip archive entries.
  292.     */
  293.     status = cli$present(&cli_adjust);
  294.     if (status & 1)
  295.         *ptr++ = 'A';
  296.  
  297.     /*
  298.     **  Add comments?
  299.     */
  300.     status = cli$present (&cli_comments);
  301.     if (status & 1) {
  302. /*        while ((status = cli$get_value (&cli_comments, &work_str)) & 1) {
  303.             if (strncmp(work_str.dsc$a_pointer,"ZIP",3) == 0)
  304.                 *ptr++ = 'z';
  305.             if (strncmp(work_str.dsc$a_pointer,"FIL",3) == 0)
  306.                 *ptr++ = 'c';
  307.         } */
  308.         if ((status = cli$present (&cli_comment_zipfile)) & 1)
  309.             *ptr++ = 'z';
  310.         if ((status = cli$present (&cli_comment_files)) & 1)
  311.             *ptr++ = 'c';
  312.     }
  313.  
  314.     /*
  315.     **  Do not add/modify directory entries.
  316.     */
  317.     status = cli$present(&cli_dirnames);
  318.     if (!(status & 1))
  319.         *ptr++ = 'D';
  320.  
  321. #ifdef CRYPT
  322.     /*
  323.     **  Encrypt?
  324.     */
  325.     status = cli$present (&cli_encrypt);
  326.     if (status & 1)
  327.         *ptr++ = 'e';
  328. #endif /* CRYPT */
  329.  
  330.     /*
  331.     **  Fix the zip archive structure.
  332.     */
  333.     status = cli$present (&cli_fix_archive);
  334.     if (status & 1) {
  335.         *ptr++ = 'F';
  336.         if ((status = cli$present (&cli_fix_full)) & 1) {
  337.             *ptr++ = 'F';
  338.         }
  339.     }
  340.  
  341.     /*
  342.     **  Append (allow growing of existing zip file).
  343.     */
  344.     status = cli$present (&cli_append);
  345.     if (status & 1)
  346.         *ptr++ = 'g';
  347.  
  348.     /*
  349.     **  Show the help.
  350.     */
  351.     status = cli$present (&cli_help);
  352.     if (status & 1)
  353.         *ptr++ = 'h';
  354.  
  355.     /*
  356.     **  Junk path names (directory specs).
  357.     */
  358.     status = cli$present (&cli_junk);
  359.     if (status & 1)
  360.         *ptr++ = 'j';
  361.  
  362.     /*
  363.     **  Simulate zip file made by PKZIP.
  364.     */
  365.     status = cli$present (&cli_pkzip);
  366.     if (status & 1)
  367.         *ptr++ = 'k';
  368.  
  369.     /*
  370.     **  Translage end-of-line.
  371.     */
  372.     status = cli$present (&cli_translate_eol);
  373.     if (status & 1) {
  374.         *ptr++ = 'l';
  375.         if ((status = cli$present (&cli_transl_eol_crlf)) & 1) {
  376.             *ptr++ = 'l';
  377.         }
  378.     }
  379.  
  380.     /*
  381.     **  Show the software license.
  382.     */
  383.     status = cli$present (&cli_license);
  384.     if (status & 1)
  385.         *ptr++ = 'L';
  386.  
  387.     /*
  388.     **  Set zip file time to time of latest file in it.
  389.     */
  390.     status = cli$present (&cli_latest);
  391.     if (status & 1)
  392.         *ptr++ = 'o';
  393.  
  394.     /*
  395.     **  Store full path (default).
  396.     */
  397.     status = cli$present (&cli_full_path);
  398.     if (status == CLI$_PRESENT)
  399.         *ptr++ = 'p';
  400.     else if (status == CLI$_NEGATED)
  401.         *ptr++ = 'j';
  402.  
  403.     /*
  404.     **  Junk Zipfile prefix (SFX stub etc.).
  405.     */
  406.     status = cli$present (&cli_unsfx);
  407.     if (status & 1)
  408.         *ptr++ = 'J';
  409.  
  410.     /*
  411.     **  Recurse through subdirectories.
  412.     */
  413.     status = cli$present (&cli_recurse);
  414.     if (status & 1)
  415.         *ptr++ = 'r';
  416.  
  417.     /*
  418.     **  Be verbose.
  419.     */
  420.     status = cli$present (&cli_verbose);
  421.     if (status & 1) {
  422.         *ptr++ = 'v';
  423.         if ((status = cli$present (&cli_verbose_more)) & 1)
  424.             *ptr++ = 'v';
  425.         if ((status = cli$present (&cli_verbose_debug)) & 1) {
  426.             *ptr++ = 'v';
  427.             *ptr++ = 'v';
  428.         }
  429.     }
  430.  
  431.     /*
  432.     **  Quiet mode.
  433.     **  (Quiet mode is processed after verbose, because a "-v" modifier
  434.     **  resets "noisy" to 1.)
  435.     */
  436.     status = cli$present (&cli_quiet);
  437.     if (status & 1)
  438.         *ptr++ = 'q';
  439.  
  440.     /*
  441.     **  Suppress creation of any extra field.
  442.     */
  443.     status = cli$present (&cli_extra_fields);
  444.     if (!(status & 1))
  445.         *ptr++ = 'X';
  446.  
  447.     /*
  448.     **  Save the VMS file attributes.
  449.     */
  450.     status = cli$present (&cli_vms);
  451.     if (status & 1)
  452.         *ptr++ = 'V';
  453.  
  454.     /*
  455.     **  Keep the VMS version number as part of the file name when stored.
  456.     */
  457.     status = cli$present (&cli_keep_version);
  458.     if (status & 1)
  459.         *ptr++ = 'w';
  460.  
  461.     /*
  462.     **  `Batch' processing: read filenames to archive from stdin
  463.     **  or the specified file.
  464.     */
  465.     status = cli$present (&cli_batch);
  466.     if (status & 1) {
  467.                status = cli$get_value (&cli_batch, &work_str);
  468.         if (status & 1) {
  469.             work_str.dsc$a_pointer[work_str.dsc$w_length] = '\0';
  470.             if ((stdin = freopen(work_str.dsc$a_pointer, "r", stdin)) == NULL)
  471.             {
  472.                 sprintf(errbuf, "could not open list file: %s",
  473.                         work_str.dsc$a_pointer);
  474.                 ziperr(ZE_PARMS, errbuf);
  475.             }
  476.         }
  477.         *ptr++ = '@';
  478.     }
  479.  
  480.     /*
  481.     **  Now copy the final options string to the_cmd_line.
  482.     */
  483.     x = ptr - &options[0];
  484.     if (x > 1) {
  485.         options[x] = '\0';
  486.         len = strlen(the_cmd_line) + x + 2;
  487.         if ((the_cmd_line = (char *) realloc (the_cmd_line, len)) == NULL)
  488.             return(SS$_INSFMEM);
  489.         strcat (the_cmd_line, " ");
  490.         strcat (the_cmd_line, options);
  491.     }
  492.  
  493.     /*
  494.     **
  495.     **  OK.  We've done all the regular options, so check for -b (temporary
  496.     **  file path), -n (special suffixes), zipfile, files to zip, and exclude
  497.     **  list.
  498.     **
  499.     */
  500.     status = cli$present (&cli_temp_path);
  501.     if (status & 1) {
  502.         status = cli$get_value (&cli_temp_path, &work_str);
  503.         len = strlen(the_cmd_line) + work_str.dsc$w_length + 4 + 1;
  504.         if ((the_cmd_line = (char *) realloc (the_cmd_line, len)) == NULL)
  505.             return(SS$_INSFMEM);
  506.         strcat (the_cmd_line, " -b ");
  507.         x = strlen(the_cmd_line);
  508.         strncpy(&the_cmd_line[x], work_str.dsc$a_pointer,
  509.                 work_str.dsc$w_length);
  510.         the_cmd_line[len] = '\0';
  511.     }
  512.  
  513.     /*
  514.     **  Handle "-t mmddyy".
  515.     */
  516.     status = cli$present (&cli_since);
  517.     if (status & 1) {
  518. #ifdef __DECC
  519. #pragma member_alignment save
  520. #pragma nomember_alignment
  521. #endif  /* __DECC */
  522.  
  523.         struct tim {
  524.             short year;
  525.             short month;
  526.             short day;
  527.             short hour;
  528.             short minute;
  529.             short second;
  530.             short hundred;
  531.         } numtimbuf;
  532.         struct quadword {
  533.             long high;
  534.             long low;
  535.         } bintimbuf = {0,0};
  536.         struct dsc$descriptor_d since_time;
  537. #ifdef __DECC
  538. #pragma member_alignment restore
  539. #endif
  540.         init_dyndesc(since_time);
  541.         status = cli$get_value (&cli_since, &since_time);
  542.         /*
  543.         **  If a date is given, convert it to 64-bit binary.
  544.         */
  545.         if (since_time.dsc$w_length) {
  546.             status = sys$bintim (&since_time, &bintimbuf);
  547.             if (!(status & 1)) return(status);
  548.             str$free1_dx (&since_time);
  549.         }
  550.         /*
  551.         **  Now call $NUMTIM to get the month, day, and year.
  552.         */
  553.         status = sys$numtim (&numtimbuf, (bintimbuf.low ? &bintimbuf : NULL));
  554.         if (!(status & 1)) return(status);
  555.  
  556.         /*
  557.         **  Now let's add the option "-t mmddyy" to the new command line.
  558.         */
  559.         len = strlen(the_cmd_line) + 4 + 6 + 1;
  560.         if ((the_cmd_line = (char *) realloc (the_cmd_line, len)) == NULL)
  561.             return(SS$_INSFMEM);
  562.         strcat (the_cmd_line, " -t ");
  563.         x = strlen(the_cmd_line);
  564.         sprintf(&the_cmd_line[x], "%02d%02d%02d", numtimbuf.month,
  565.                 numtimbuf.day,
  566.                 ((numtimbuf.year < 2000) ? numtimbuf.year - 1900 :
  567.                         numtimbuf.year - 2000));
  568.     }
  569.  
  570.     /*
  571.     **  Handle "-n suffix:suffix:...".  (File types to store only.)
  572.     */
  573.     status = cli$present (&cli_store_types);
  574.     if (status & 1) {
  575.         len = strlen(the_cmd_line) + 4 + 1;
  576.         if ((the_cmd_line = (char *) realloc (the_cmd_line, len)) == NULL)
  577.             return(SS$_INSFMEM);
  578.         strcat (the_cmd_line, " -n ");
  579.  
  580.         status = get_list (&cli_store_types, &the_cmd_line,
  581.                            &foreign_cmdline, ':');
  582.         if (!(status & 1)) return (status);
  583.     }
  584.  
  585.     /*
  586.     **  Now get the specified zip file name.
  587.     */
  588.     status = cli$present (&cli_zipfile);
  589.     if (status & 1) {
  590.         status = cli$get_value (&cli_zipfile, &work_str);
  591.  
  592.         len = strlen(the_cmd_line) + work_str.dsc$w_length + 2;
  593.         if ((the_cmd_line = (char *) realloc (the_cmd_line, len)) == NULL)
  594.             return(SS$_INSFMEM);
  595.         strcat (the_cmd_line, " ");
  596.         x = strlen(the_cmd_line);
  597.         strncpy(&the_cmd_line[x], work_str.dsc$a_pointer,
  598.                 work_str.dsc$w_length);
  599.         the_cmd_line[len] = '\0';
  600.  
  601.     }
  602.  
  603.     /*
  604.     **  Run through the list of input files.
  605.     */
  606.     status = cli$present (&cli_infile);
  607.     if (status & 1) {
  608.         len = strlen(the_cmd_line) + 2;
  609.         if ((the_cmd_line = (char *) realloc (the_cmd_line, len)) == NULL)
  610.             return(SS$_INSFMEM);
  611.         strcat (the_cmd_line, " ");
  612.         status = get_list (&cli_infile, &the_cmd_line, &foreign_cmdline, ' ');
  613.         if (!(status & 1)) return (status);
  614.     }
  615.  
  616.     /*
  617.     **  Any files to exclude? ("-x file file")
  618.     */
  619.     status = cli$present (&cli_exclude);
  620.     if (status & 1) {
  621.         len = strlen(the_cmd_line) + work_str.dsc$w_length + 4 + 1;
  622.         if ((the_cmd_line = (char *) realloc (the_cmd_line, len)) == NULL)
  623.             return(SS$_INSFMEM);
  624.         strcat (the_cmd_line, " -x ");
  625.         status = get_list (&cli_exclude, &the_cmd_line, &foreign_cmdline, ' ');
  626.         if (!(status & 1)) return (status);
  627.     }
  628.  
  629.     /*
  630.     **  Any files to include? ("-i file file")
  631.     */
  632.     status = cli$present (&cli_include);
  633.     if (status & 1) {
  634.         len = strlen(the_cmd_line) + work_str.dsc$w_length + 4 + 1;
  635.         if ((the_cmd_line = (char *) realloc (the_cmd_line, len)) == NULL)
  636.             return(SS$_INSFMEM);
  637.         strcat (the_cmd_line, " -i ");
  638.         status = get_list (&cli_include, &the_cmd_line, &foreign_cmdline, ' ');
  639.         if (!(status & 1)) return (status);
  640.     }
  641.  
  642.  
  643.     /*
  644.     **  Now that we've built our new UNIX-like command line, count the
  645.     **  number of args and build an argv array.
  646.     */
  647.  
  648. #if defined(TEST) || defined(DEBUG)
  649.     printf("%s\n",the_cmd_line);
  650. #endif /* TEST || DEBUG */
  651.  
  652.     new_argc = 1;
  653.     for (ptr = the_cmd_line;
  654.          (ptr = strchr(ptr,' ')) != NULL;
  655.          ptr++, new_argc++);
  656.  
  657.     /*
  658.     **  Allocate memory for the new argv[].  The last element of argv[]
  659.     **  is supposed to be NULL, so allocate enough for new_argc+1.
  660.     */
  661.     if ((new_argv = (char **) calloc (new_argc+1, sizeof(char *))) == NULL)
  662.         return(SS$_INSFMEM);
  663.  
  664.     /*
  665.     **  For each option, store the address in new_argv[] and convert the
  666.     **  separating blanks to nulls so each argv[] string is terminated.
  667.     */
  668.     for (ptr = the_cmd_line, x = 0; x < new_argc; x++) {
  669.         new_argv[x] = ptr;
  670.         if ((ptr = strchr (ptr, ' ')) != NULL)
  671.             *ptr++ = '\0';
  672.     }
  673.     new_argv[new_argc] = NULL;
  674.  
  675. #if defined(TEST) || defined(DEBUG)
  676.     printf("new_argc    = %d\n", new_argc);
  677.     for (x = 0; x < new_argc; x++)
  678.         printf("new_argv[%d] = %s\n", x, new_argv[x]);
  679. #endif /* TEST || DEBUG */
  680.  
  681.     /*
  682.     **  All finished.  Return the new argc and argv[] addresses to Zip.
  683.     */
  684.     *argc_p = new_argc;
  685.     *argv_p = new_argv;
  686.  
  687.     return(SS$_NORMAL);
  688. }
  689.  
  690.  
  691.  
  692. unsigned long
  693. get_list (struct dsc$descriptor_s *qual, char **str,
  694.           struct dsc$descriptor_d *cmdline, char c)
  695. {
  696. /*
  697. **  Routine:    get_list
  698. **
  699. **  Function:   This routine runs through a comma-separated CLI list
  700. **              and copies the strings to the command line.  The
  701. **              specified separation character is used to separate
  702. **              the strings on the command line.
  703. **
  704. **              All unquoted strings are converted to lower-case.
  705. **
  706. **  Formal parameters:
  707. **
  708. **      qual    - Address of descriptor for the qualifier name
  709. **      str     - Address of pointer pointing to string (command line)
  710. **      cmdline - Address of descriptor for the full command line tail
  711. **      c       - Character to use to separate the list items
  712. **
  713. */
  714.  
  715.     register status;
  716.     struct dsc$descriptor_d work_str;
  717.  
  718.     init_dyndesc(work_str);
  719.  
  720.     status = cli$present (qual);
  721.     if (status & 1) {
  722.  
  723.         unsigned long len, old_len, lower_it, ind, sind;
  724.  
  725.         len = strlen(*str);
  726.         while ((status = cli$get_value (qual, &work_str)) & 1) {
  727.             /*
  728.             **  Just in case the string doesn't exist yet, though it does.
  729.             */
  730.             if (*str == NULL) {
  731.                 len = work_str.dsc$w_length + 1;
  732.                 if ((*str = (char *) malloc (work_str.dsc$w_length)) == NULL)
  733.                     return(SS$_INSFMEM);
  734.                 strncpy(*str,work_str.dsc$a_pointer,len);
  735.             } else {
  736.                 char *src, *dst; int x;
  737.                 old_len = len;
  738.                 len += work_str.dsc$w_length + 1;
  739.                 if ((*str = (char *) realloc (*str, len)) == NULL)
  740.                     return(SS$_INSFMEM);
  741.  
  742.                 /*
  743.                 **  Look for the filename in the original foreign command
  744.                 **  line to see if it was originally quoted.  If so, then
  745.                 **  don't convert it to lowercase.
  746.                 */
  747.                 lower_it = 0;
  748.                 str$find_first_substring (cmdline, &ind, &sind, &work_str);
  749.                 if (*(cmdline->dsc$a_pointer + ind - 2) == '"')
  750.                     lower_it = 1;
  751.  
  752.                 /*
  753.                 **  Copy the string to the buffer, converting to lowercase.
  754.                 */
  755.                 src = work_str.dsc$a_pointer;
  756.                 dst = *str+old_len;
  757.                 for (x = 0; x < work_str.dsc$w_length; x++) {
  758.                     if (!lower_it && ((*src >= 'A') && (*src <= 'Z')))
  759.                         *dst++ = *src++ + 32;
  760.                     else
  761.                         *dst++ = *src++;
  762.                 }
  763.             }
  764.             if (status == CLI$_COMMA)
  765.                 (*str)[len-1] = c;
  766.             else
  767.                 (*str)[len-1] = '\0';
  768.         }
  769.     }
  770.  
  771.     return (SS$_NORMAL);
  772.  
  773. }
  774.  
  775.  
  776. unsigned long
  777. check_cli (struct dsc$descriptor_s *qual)
  778. {
  779. /*
  780. **  Routine:    check_cli
  781. **
  782. **  Function:   Check to see if a CLD was used to invoke the program.
  783. **
  784. **  Formal parameters:
  785. **
  786. **      qual    - Address of descriptor for qualifier name to check.
  787. **
  788. */
  789.     lib$establish(lib$sig_to_ret);      /* Establish condition handler */
  790.     return (cli$present(qual));         /* Just see if something was given */
  791. }
  792.  
  793.  
  794. void help()  /* VMSCLI version */
  795. /* Print help (along with license info) to stdout. */
  796. {
  797.   extent i;             /* counter for help array */
  798.  
  799.   /* help array */
  800.   static char *text[] = {
  801. "Zip %s (%s). Usage: zip==\"$disk:[dir]zip.exe\"",
  802. "zip zipfile[.zip] [list] [/EXCL=(xlist)] /options /modifiers",
  803. "  The default action is to add or replace zipfile entries from list, except",
  804. "  those in xlist. The include file list may contain the special name - to",
  805. "  compress standard input.  If both zipfile and list are omitted, zip",
  806. "  compresses stdin to stdout.",
  807. "  Major options include:",
  808. "    /FRESHEN, /UPDATE, /DELETE, /[NO]MOVE, /COMMENTS[={ZIP_FILE|FILES}],",
  809. "    /LATEST, /TEST, /ADJUST_OFFSETS, /FIX_ARCHIVE[=FULL], /UNSFX",
  810. "  Modifiers include:",
  811. "    /EXCLUDE=(file list), /INCLUDE=(file list), /SINCE=\"creation time\",",
  812. #ifdef CRYPT
  813. "\
  814.     /QUIET,/VERBOSE[=MORE],/[NO]RECURSE,/[NO]DIRNAMES,/JUNK,/ENCRYPT[=VERIFY],",
  815. #else /* !CRYPT */
  816. "    /QUIET, /VERBOSE[=MORE], /[NO]RECURSE, /[NO]DIRNAMES, /JUNK,",
  817. #endif /* ?CRYPT */
  818. "    /[NO]KEEP_VERSION, /[NO]VMS, /[NO]PKZIP, /TRANSLATE_EOL[={LF|CRLF}],",
  819. "    /[NO]EXTRA_FIELDS /LEVEL=[0-9], /TEMP_PATH=directory, /BATCH[=list file]"
  820.   };
  821.  
  822.   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
  823.   {
  824.     printf(copyright[i], "zip");
  825.     putchar('\n');
  826.   }
  827.   for (i = 0; i < sizeof(text)/sizeof(char *); i++)
  828.   {
  829.     printf(text[i], VERSION, REVDATE);
  830.     putchar('\n');
  831.   }
  832. } /* end function help() */
  833.