home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / zip22.zip / vms / cmdline.c < prev    next >
C/C++ Source or Header  |  1997-09-19  |  30KB  |  986 lines

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