home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip540.zip / vms / cmdline.c < prev    next >
C/C++ Source or Header  |  1998-07-02  |  29KB  |  949 lines

  1. #define module_name VMS_UNZIP_CMDLINE
  2. #define module_ident "02-007"
  3. /*
  4. **
  5. **  Facility:   UNZIP
  6. **
  7. **  Module:     VMS_UNZIP_CMDLINE
  8. **
  9. **  Author:     Hunter Goatley <goathunter@MadGoat.com>
  10. **
  11. **  Date:       25 Apr 97 (orig. Zip version, 30 Jul 93)
  12. **
  13. **  Abstract:   Routines to handle a VMS CLI interface for UnZip.  The CLI
  14. **              command line is parsed and a new argc/argv are built and
  15. **              returned to UnZip.
  16. **
  17. **  Modified by:
  18. **
  19. **      02-007          Onno van der Linden     02-Jul-1998 19:07
  20. **              Modified to support GNU CC 2.8 on Alpha; version unchanged.
  21. **      02-007          Johnny Lee              25-Jun-1998 07:38
  22. **              Fixed typo (superfluous ';'); no version num change.
  23. **      02-007          Hunter Goatley          11-NOV-1997 10:38
  24. **              Fixed "zip" vs. "unzip" typo; no version num change.
  25. **      02-007          Christian Spieler       14-SEP-1997 22:43
  26. **              Cosmetic mods to stay in sync with Zip; no version num change.
  27. **      02-007          Christian Spieler       12-JUL-1997 02:05
  28. **              Revised argv vector construction for better handling of quoted
  29. **              arguments (e.g.: embedded white space); no version num change.
  30. **      02-007          Christian Spieler       04-MAR-1997 22:25
  31. **              Made /CASE_INSENSITIVE common to UnZip and ZipInfo mode;
  32. **              added support for /PASSWORD="decryption_key" argument.
  33. **      02-006          Christian Spieler       11-MAY-1996 22:40
  34. **              Added SFX version of VMSCLI_usage().
  35. **      02-005          Patrick Ellis           09-MAY-1996 22:25
  36. **              Show UNIX style usage screen when UNIX style options are used.
  37. **      02-004          Christian Spieler       06-FEB-1996 02:20
  38. **              Added /HELP qualifier.
  39. **      02-003          Christian Spieler       23-DEC-1995 17:20
  40. **              Adapted to UnZip 5.2.
  41. **      02-002          Hunter Goatley          16-JUL-1994 10:20
  42. **              Fixed some typos.
  43. **      02-001          Cave Newt               14-JUL-1994 15:18
  44. **              Removed obsolete /EXTRACT option; fixed /*TEXT options;
  45. **              wrote VMSCLI usage() function
  46. **      02-000          Hunter Goatley          12-JUL-1994 00:00
  47. **              Original UnZip version (v5.11).
  48. **      01-000          Hunter Goatley          30-JUL-1993 07:54
  49. **              Original version (for Zip v1.9p1).
  50. **
  51. */
  52.  
  53.  
  54. #if defined(__DECC) || defined(__GNUC__)
  55. #pragma module module_name module_ident
  56. #else
  57. #module module_name module_ident
  58. #endif
  59.  
  60. #define UNZIP_INTERNAL
  61. #include "unzip.h"
  62. #ifndef TEST
  63. #  include "version.h"  /* for VMSCLI_usage() */
  64. #endif /* !TEST */
  65.  
  66. #include <ssdef.h>
  67. #include <descrip.h>
  68. #include <climsgdef.h>
  69. #include <clidef.h>
  70. #include <lib$routines.h>
  71. #include <str$routines.h>
  72.  
  73. #ifndef CLI$_COMMA
  74. globalvalue CLI$_COMMA;
  75. #endif
  76.  
  77. /*
  78. **  "Macro" to initialize a dynamic string descriptor.
  79. */
  80. #define init_dyndesc(dsc) {\
  81.         dsc.dsc$w_length = 0;\
  82.         dsc.dsc$b_dtype = DSC$K_DTYPE_T;\
  83.         dsc.dsc$b_class = DSC$K_CLASS_D;\
  84.         dsc.dsc$a_pointer = NULL;}
  85.  
  86. /*
  87. **  Memory allocation step for argv string buffer.
  88. */
  89. #define ARGBSIZE_UNIT 256
  90.  
  91. /*
  92. **  Memory reallocation macro for argv string buffer.
  93. */
  94. #define CHECK_BUFFER_ALLOCATION(buf, reserved, requested) { \
  95.     if ((requested) > (reserved)) { \
  96.         char *save_buf = (buf); \
  97.         (reserved) += ARGBSIZE_UNIT; \
  98.         if (((buf) = (char *) realloc((buf), (reserved))) == NULL) { \
  99.             if (save_buf != NULL) free(save_buf); \
  100.             return (SS$_INSFMEM); \
  101.         } \
  102.     } \
  103. }
  104.  
  105. /*
  106. **  Define descriptors for all of the CLI parameters and qualifiers.
  107. */
  108. #if 0
  109. $DESCRIPTOR(cli_extract,        "EXTRACT");             /* obsolete */
  110. #endif
  111. $DESCRIPTOR(cli_text,           "TEXT");                /* -a[a] */
  112. $DESCRIPTOR(cli_text_auto,      "TEXT.AUTO");           /* -a */
  113. $DESCRIPTOR(cli_text_all,       "TEXT.ALL");            /* -aa */
  114. $DESCRIPTOR(cli_text_none,      "TEXT.NONE");           /* ---a */
  115. $DESCRIPTOR(cli_binary,         "BINARY");              /* -b[b] */
  116. $DESCRIPTOR(cli_binary_auto,    "BINARY.AUTO");         /* -b */
  117. $DESCRIPTOR(cli_binary_all,     "BINARY.ALL");          /* -bb */
  118. $DESCRIPTOR(cli_binary_none,    "BINARY.NONE");         /* ---b */
  119. $DESCRIPTOR(cli_case_insensitive,"CASE_INSENSITIVE");   /* -C */
  120. $DESCRIPTOR(cli_screen,         "SCREEN");              /* -c */
  121. $DESCRIPTOR(cli_directory,      "DIRECTORY");           /* -d */
  122. $DESCRIPTOR(cli_freshen,        "FRESHEN");             /* -f */
  123. $DESCRIPTOR(cli_help,           "HELP");                /* -h */
  124. $DESCRIPTOR(cli_junk,           "JUNK");                /* -j */
  125. $DESCRIPTOR(cli_lowercase,      "LOWERCASE");           /* -L */
  126. $DESCRIPTOR(cli_list,           "LIST");                /* -l */
  127. $DESCRIPTOR(cli_brief,          "BRIEF");               /* -l */
  128. $DESCRIPTOR(cli_full,           "FULL");                /* -v */
  129. $DESCRIPTOR(cli_overwrite,      "OVERWRITE");           /* -o, -n */
  130. $DESCRIPTOR(cli_quiet,          "QUIET");               /* -q */
  131. $DESCRIPTOR(cli_super_quiet,    "QUIET.SUPER");         /* -qq */
  132. $DESCRIPTOR(cli_test,           "TEST");                /* -t */
  133. $DESCRIPTOR(cli_type,           "TYPE");                /* -c */
  134. $DESCRIPTOR(cli_pipe,           "PIPE");                /* -p */
  135. $DESCRIPTOR(cli_password,       "PASSWORD");            /* -P */
  136. $DESCRIPTOR(cli_uppercase,      "UPPERCASE");           /* -U */
  137. $DESCRIPTOR(cli_update,         "UPDATE");              /* -u */
  138. $DESCRIPTOR(cli_version,        "VERSION");             /* -V */
  139. $DESCRIPTOR(cli_restore,        "RESTORE");             /* -X */
  140. $DESCRIPTOR(cli_comment,        "COMMENT");             /* -z */
  141. $DESCRIPTOR(cli_exclude,        "EXCLUDE");             /* -x */
  142.  
  143. $DESCRIPTOR(cli_information,    "ZIPINFO");             /* -Z */
  144. $DESCRIPTOR(cli_short,          "SHORT");               /* -Zs */
  145. $DESCRIPTOR(cli_medium,         "MEDIUM");              /* -Zm */
  146. $DESCRIPTOR(cli_long,           "LONG");                /* -Zl */
  147. $DESCRIPTOR(cli_verbose,        "VERBOSE");             /* -Zv */
  148. $DESCRIPTOR(cli_header,         "HEADER");              /* -Zh */
  149. $DESCRIPTOR(cli_totals,         "TOTALS");              /* -Zt */
  150. $DESCRIPTOR(cli_times,          "TIMES");               /* -ZT */
  151. $DESCRIPTOR(cli_one_line,       "ONE_LINE");            /* -Z2 */
  152.  
  153. $DESCRIPTOR(cli_page,           "PAGE");                /* -M , -ZM */
  154.  
  155. $DESCRIPTOR(cli_yyz,            "YYZ_UNZIP");
  156.  
  157. $DESCRIPTOR(cli_zipfile,        "ZIPFILE");
  158. $DESCRIPTOR(cli_infile,         "INFILE");
  159. $DESCRIPTOR(unzip_command,      "unzip ");
  160.  
  161. static int show_VMSCLI_usage;
  162.  
  163. #if defined(__DECC) || defined(__GNUC__)
  164. extern void *vms_unzip_cld;
  165. #else
  166. globalref void *vms_unzip_cld;
  167. #endif
  168.  
  169. /* extern unsigned long LIB$GET_INPUT(void), LIB$SIG_TO_RET(void); */
  170.  
  171. extern unsigned long cli$dcl_parse ();
  172. extern unsigned long cli$present ();
  173. extern unsigned long cli$get_value ();
  174.  
  175. unsigned long vms_unzip_cmdline (int *, char ***);
  176. static unsigned long get_list (struct dsc$descriptor_s *,
  177.                                struct dsc$descriptor_d *, int,
  178.                                char **, unsigned long *, unsigned long *);
  179. static unsigned long check_cli (struct dsc$descriptor_s *);
  180.  
  181.  
  182. #ifdef TEST
  183. int
  184. main(int argc, char **argv)
  185. {
  186.     return (vms_unzip_cmdline(&argc, &argv));
  187. }
  188. #endif /* TEST */
  189.  
  190.  
  191. unsigned long
  192. vms_unzip_cmdline (int *argc_p, char ***argv_p)
  193. {
  194. /*
  195. **  Routine:    vms_unzip_cmdline
  196. **
  197. **  Function:
  198. **
  199. **      Parse the DCL command line and create a fake argv array to be
  200. **      handed off to Zip.
  201. **
  202. **      NOTE: the argv[] is built as we go, so all the parameters are
  203. **      checked in the appropriate order!!
  204. **
  205. **  Formal parameters:
  206. **
  207. **      argc_p          - Address of int to receive the new argc
  208. **      argv_p          - Address of char ** to receive the argv address
  209. **
  210. **  Calling sequence:
  211. **
  212. **      status = vms_unzip_cmdline (&argc, &argv);
  213. **
  214. **  Returns:
  215. **
  216. **      SS$_NORMAL      - Success.
  217. **      SS$_INSFMEM     - A malloc() or realloc() failed
  218. **      SS$_ABORT       - Bad time value
  219. **
  220. */
  221.     register unsigned long status;
  222.     char options[256];
  223.     char *the_cmd_line;                 /* buffer for argv strings */
  224.     unsigned long cmdl_size;            /* allocated size of buffer */
  225.     unsigned long cmdl_len;             /* used size of buffer */
  226.     char *ptr;
  227.     int  x, len, zipinfo, exclude_list;
  228.  
  229.     int new_argc;
  230.     char **new_argv;
  231.  
  232.     struct dsc$descriptor_d work_str;
  233.     struct dsc$descriptor_d foreign_cmdline;
  234.     struct dsc$descriptor_d output_directory;
  235.     struct dsc$descriptor_d password_arg;
  236.  
  237.     init_dyndesc(work_str);
  238.     init_dyndesc(foreign_cmdline);
  239.     init_dyndesc(output_directory);
  240.     init_dyndesc(password_arg);
  241.  
  242.     /*
  243.     **  See if the program was invoked by the CLI (SET COMMAND) or by
  244.     **  a foreign command definition.  Check for /YYZ_UNZIP, which is a
  245.     **  valid default qualifier solely for this test.
  246.     */
  247.     show_VMSCLI_usage = TRUE;
  248.     status = check_cli(&cli_yyz);
  249.     if (!(status & 1)) {
  250.         lib$get_foreign(&foreign_cmdline);
  251.         /*
  252.         **  If nothing was returned or the first character is a "-", then
  253.         **  assume it's a UNIX-style command and return.
  254.         */
  255.         if (foreign_cmdline.dsc$w_length == 0)
  256.             return (SS$_NORMAL);
  257.         if ((*(foreign_cmdline.dsc$a_pointer) == '-') ||
  258.             ((foreign_cmdline.dsc$w_length > 1) &&
  259.              (*(foreign_cmdline.dsc$a_pointer) == '"') &&
  260.              (*(foreign_cmdline.dsc$a_pointer + 1) == '-'))) {
  261.             show_VMSCLI_usage = FALSE;
  262.             return (SS$_NORMAL);
  263.         }
  264.  
  265.         str$concat(&work_str, &unzip_command, &foreign_cmdline);
  266.         status = cli$dcl_parse(&work_str, &vms_unzip_cld, lib$get_input,
  267.                         lib$get_input, 0);
  268.         if (!(status & 1)) return (status);
  269.     }
  270.  
  271.     /*
  272.     **  There's always going to be a new_argv[] because of the image name.
  273.     */
  274.     if ((the_cmd_line = (char *) malloc(cmdl_size = ARGBSIZE_UNIT)) == NULL)
  275.         return (SS$_INSFMEM);
  276.  
  277.     strcpy(the_cmd_line, "unzip");
  278.     cmdl_len = sizeof("unzip");
  279.  
  280.     /*
  281.     **  First, check to see if any of the regular options were specified.
  282.     */
  283.  
  284.     options[0] = '-';
  285.     ptr = &options[1];          /* Point to temporary buffer */
  286.  
  287.     /*
  288.     **  Is it ZipInfo??
  289.     */
  290.     zipinfo = 0;
  291.     status = cli$present(&cli_information);
  292.     if (status & 1) {
  293.  
  294.         zipinfo = 1;
  295.  
  296.         *ptr++ = 'Z';
  297.  
  298.         if (cli$present(&cli_one_line) & 1)
  299.             *ptr++ = '2';
  300.         if (cli$present(&cli_short) & 1)
  301.             *ptr++ = 's';
  302.         if (cli$present(&cli_medium) & 1)
  303.             *ptr++ = 'm';
  304.         if (cli$present(&cli_long) & 1)
  305.             *ptr++ = 'l';
  306.         if (cli$present(&cli_verbose) & 1)
  307.             *ptr++ = 'v';
  308.         if (cli$present(&cli_header) & 1)
  309.             *ptr++ = 'h';
  310.         if (cli$present(&cli_comment) & 1)
  311.             *ptr++ = 'c';
  312.         if (cli$present(&cli_totals) & 1)
  313.             *ptr++ = 't';
  314.         if (cli$present(&cli_times) & 1)
  315.             *ptr++ = 'T';
  316.  
  317.     }
  318.     else {
  319.  
  320. #if 0
  321.     /*
  322.     **  Extract files?
  323.     */
  324.     status = cli$present(&cli_extract);
  325.     if (status == CLI$_NEGATED)
  326.         *ptr++ = '-';
  327.     if (status != CLI$_ABSENT)
  328.         *ptr++ = 'x';
  329. #endif
  330.  
  331.     /*
  332.     **  Write binary files in VMS binary (fixed-length, 512-byte records,
  333.     **  record attributes: none) format
  334.     **  (auto-convert, or force to convert all files)
  335.     */
  336.     status = cli$present(&cli_binary);
  337.     if (status != CLI$_ABSENT) {
  338.         *ptr++ = '-';
  339.         *ptr++ = '-';
  340.         *ptr++ = 'b';
  341.         if ((status & 1) &&
  342.             !((status = cli$present(&cli_binary_none)) & 1)) {
  343.             *ptr++ = 'b';
  344.             if ((status = cli$present(&cli_binary_all)) & 1)
  345.                 *ptr++ = 'b';
  346.         }
  347.     }
  348.  
  349.     /*
  350.     **  Convert files as text (CR LF -> LF, etc.)
  351.     **  (auto-convert, or force to convert all files)
  352.     */
  353.     status = cli$present(&cli_text);
  354.     if (status != CLI$_ABSENT) {
  355.         *ptr++ = '-';
  356.         *ptr++ = '-';
  357.         *ptr++ = 'a';
  358.         if ((status & 1) &&
  359.             !((status = cli$present(&cli_text_none)) & 1)) {
  360.             *ptr++ = 'a';
  361.             if ((status = cli$present(&cli_text_all)) & 1)
  362.                 *ptr++ = 'a';
  363.         }
  364.     }
  365.  
  366.     /*
  367.     **  Extract files to screen?
  368.     */
  369.     status = cli$present(&cli_screen);
  370.     if (status == CLI$_NEGATED)
  371.         *ptr++ = '-';
  372.     if (status != CLI$_ABSENT)
  373.         *ptr++ = 'c';
  374.  
  375.     /*
  376.     **  Re-create directory structure?  (default)
  377.     */
  378.     status = cli$present(&cli_directory);
  379.     if (status == CLI$_PRESENT) {
  380.         status = cli$get_value(&cli_directory, &output_directory);
  381.     }
  382.  
  383.     /*
  384.     **  Freshen existing files, create none
  385.     */
  386.     status = cli$present(&cli_freshen);
  387.     if (status == CLI$_NEGATED)
  388.         *ptr++ = '-';
  389.     if (status != CLI$_ABSENT)
  390.         *ptr++ = 'f';
  391.  
  392.     /*
  393.     **  Show the help.
  394.     */
  395.     status = cli$present(&cli_help);
  396.     if (status & 1)
  397.         *ptr++ = 'h';
  398.  
  399.     /*
  400.     **  Junk stored directory names on unzip
  401.     */
  402.     status = cli$present(&cli_junk);
  403.     if (status == CLI$_NEGATED)
  404.         *ptr++ = '-';
  405.     if (status != CLI$_ABSENT)
  406.         *ptr++ = 'j';
  407.  
  408.     /*
  409.     **  List contents (/BRIEF or /FULL (default))
  410.     */
  411.     status = cli$present(&cli_list);
  412.     if (status & 1) {
  413.         if (cli$present(&cli_full) & 1)
  414.            *ptr++ = 'v';
  415.         else
  416.            *ptr++ = 'l';
  417.     }
  418.  
  419.     /*
  420.     **  Overwrite files?
  421.     */
  422.     status = cli$present(&cli_overwrite);
  423.     if (status == CLI$_NEGATED)
  424.         *ptr++ = 'n';
  425.     else if (status != CLI$_ABSENT)
  426.         *ptr++ = 'o';
  427.  
  428.     /*
  429.     **  Decryption password from command line?
  430.     */
  431.     status = cli$present(&cli_password);
  432.     if (status == CLI$_PRESENT) {
  433.         status = cli$get_value(&cli_password, &password_arg);
  434.     }
  435.  
  436.     /*
  437.     **  Pipe files to SYS$OUTPUT with no informationals?
  438.     */
  439.     status = cli$present(&cli_pipe);
  440.     if (status != CLI$_ABSENT)
  441.         *ptr++ = 'p';
  442.  
  443.     /*
  444.     **  Quiet
  445.     */
  446.     status = cli$present(&cli_quiet);
  447.     if (status & 1) {
  448.         *ptr++ = 'q';
  449.         if ((status = cli$present(&cli_super_quiet)) & 1)
  450.             *ptr++ = 'q';
  451.     }
  452.  
  453.     /*
  454.     **  Test archive integrity
  455.     */
  456.     status = cli$present(&cli_test);
  457.     if (status == CLI$_NEGATED)
  458.         *ptr++ = '-';
  459.     if (status != CLI$_ABSENT)
  460.         *ptr++ = 't';
  461.  
  462.     /*
  463.     **  Make (some) names lowercase
  464.     */
  465.     status = cli$present(&cli_lowercase);
  466.     if (status == CLI$_NEGATED)
  467.         *ptr++ = '-';
  468.     if (status != CLI$_ABSENT)
  469.         *ptr++ = 'L';
  470.  
  471.     /*
  472.     **  Uppercase (don't convert to lower)
  473.     */
  474.     status = cli$present(&cli_uppercase);
  475.     if (status == CLI$_NEGATED)
  476.         *ptr++ = '-';
  477.     if (status != CLI$_ABSENT)
  478.         *ptr++ = 'U';
  479.  
  480.     /*
  481.     **  Update (extract only new and newer files)
  482.     */
  483.     status = cli$present(&cli_update);
  484.     if (status == CLI$_NEGATED)
  485.         *ptr++ = '-';
  486.     if (status != CLI$_ABSENT)
  487.         *ptr++ = 'u';
  488.  
  489.     /*
  490.     **  Version (retain VMS/DEC-20 file versions)
  491.     */
  492.     status = cli$present(&cli_version);
  493.     if (status == CLI$_NEGATED)
  494.         *ptr++ = '-';
  495.     if (status != CLI$_ABSENT)
  496.         *ptr++ = 'V';
  497.  
  498.     /*
  499.     **  Restore owner/protection info
  500.     */
  501.     status = cli$present(&cli_restore);
  502.     if (status == CLI$_NEGATED)
  503.         *ptr++ = '-';
  504.     if (status != CLI$_ABSENT)
  505.         *ptr++ = 'X';
  506.  
  507.     /*
  508.     **  Display only the archive comment
  509.     */
  510.     status = cli$present(&cli_comment);
  511.     if (status == CLI$_NEGATED)
  512.         *ptr++ = '-';
  513.     if (status != CLI$_ABSENT)
  514.         *ptr++ = 'z';
  515.  
  516.     }   /* ZipInfo check way up there.... */
  517.  
  518.     /* The following options are common to both UnZip and ZipInfo mode. */
  519.  
  520.     /*
  521.     **  Match filenames case-insensitively (-C)
  522.     */
  523.     status = cli$present(&cli_case_insensitive);
  524.     if (status == CLI$_NEGATED)
  525.         *ptr++ = '-';
  526.     if (status != CLI$_ABSENT)
  527.         *ptr++ = 'C';
  528.  
  529.     /*
  530.     **  Use builtin pager for all screen output
  531.     */
  532.     status = cli$present(&cli_page);
  533.     if (status == CLI$_NEGATED)
  534.         *ptr++ = '-';
  535.     if (status != CLI$_ABSENT)
  536.         *ptr++ = 'M';
  537.  
  538.     /*
  539.     **  Check existence of a list of files to exclude, fetch is done later.
  540.     */
  541.     status = cli$present(&cli_exclude);
  542.     exclude_list = ((status & 1) != 0);
  543.  
  544.     /*
  545.     **  If the user didn't give any DCL qualifier, assume he wants the
  546.     **  Un*x interface.
  547.     if ( (ptr == &options[1]) &&
  548.          (output_directory.dsc$w_length == 0) &&
  549.          (password_arg.dsc$w_length == 0) &&
  550.          (!exclude_list)  ) {
  551.         free(the_cmd_line);
  552.         return (SS$_NORMAL);
  553.     }
  554.     */
  555.  
  556.     /*
  557.     **  Now copy the final options string to the_cmd_line.
  558.     */
  559.     len = ptr - &options[0];
  560.     if (len > 1) {
  561.         options[len] = '\0';
  562.         x = cmdl_len;
  563.         cmdl_len += len + 1;
  564.         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
  565.         strcpy(&the_cmd_line[x], options);
  566.     }
  567.  
  568.     /*
  569.     **  If specified, add the decryption password argument.
  570.     **/
  571.     if (password_arg.dsc$w_length != 0) {
  572.         x = cmdl_len;
  573.         cmdl_len += password_arg.dsc$w_length + 4;
  574.         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
  575.         strcpy(&the_cmd_line[x], "-P");
  576.         strncpy(&the_cmd_line[x+3], password_arg.dsc$a_pointer,
  577.                 password_arg.dsc$w_length);
  578.         the_cmd_line[cmdl_len-1] = '\0';
  579.     }
  580.  
  581.     /*
  582.     **  Now get the specified zip file name.
  583.     */
  584.     status = cli$present(&cli_zipfile);
  585.     if (status & 1) {
  586.         status = cli$get_value(&cli_zipfile, &work_str);
  587.  
  588.         x = cmdl_len;
  589.         cmdl_len += work_str.dsc$w_length + 1;
  590.         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
  591.         strncpy(&the_cmd_line[x], work_str.dsc$a_pointer,
  592.                 work_str.dsc$w_length);
  593.         the_cmd_line[cmdl_len-1] = '\0';
  594.  
  595.     }
  596.  
  597.     /*
  598.     **  Get the output directory, for UnZip.
  599.     **/
  600.     if (output_directory.dsc$w_length != 0) {
  601.         x = cmdl_len;
  602.         cmdl_len += output_directory.dsc$w_length + 4;
  603.         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
  604.         strcpy(&the_cmd_line[x], "-d");
  605.         strncpy(&the_cmd_line[x+3], output_directory.dsc$a_pointer,
  606.                 output_directory.dsc$w_length);
  607.         the_cmd_line[cmdl_len-1] = '\0';
  608.     }
  609.  
  610.     /*
  611.     **  Run through the list of files to unzip.
  612.     */
  613.     status = cli$present(&cli_infile);
  614.     if (status & 1) {
  615.         status = get_list(&cli_infile, &foreign_cmdline, '\0',
  616.                           &the_cmd_line, &cmdl_size, &cmdl_len);
  617.         if (!(status & 1)) return (status);
  618.     }
  619.  
  620.     /*
  621.     **  Get the list of files to exclude, if there are any.
  622.     */
  623.     if (exclude_list) {
  624.         x = cmdl_len;
  625.         cmdl_len += 3;
  626.         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
  627.         strcpy(&the_cmd_line[x], "-x");
  628.  
  629.         status = get_list(&cli_exclude, &foreign_cmdline, '\0',
  630.                           &the_cmd_line, &cmdl_size, &cmdl_len);
  631.         if (!(status & 1)) return (status);
  632.     }
  633.  
  634.     /*
  635.     **  We have finished collecting the strings for the argv vector,
  636.     **  release unused space.
  637.     */
  638.     if ((the_cmd_line = (char *) realloc(the_cmd_line, cmdl_len)) == NULL)
  639.         return (SS$_INSFMEM);
  640.  
  641.     /*
  642.     **  Now that we've built our new UNIX-like command line, count the
  643.     **  number of args and build an argv array.
  644.     */
  645.     for (new_argc = 0, x = 0; x < cmdl_len; x++)
  646.         if (the_cmd_line[x] == '\0')
  647.             new_argc++;
  648.  
  649.     /*
  650.     **  Allocate memory for the new argv[].  The last element of argv[]
  651.     **  is supposed to be NULL, so allocate enough for new_argc+1.
  652.     */
  653.     if ((new_argv = (char **) calloc(new_argc+1, sizeof(char *))) == NULL)
  654.         return (SS$_INSFMEM);
  655.  
  656.     /*
  657.     **  For each option, store the address in new_argv[] and convert the
  658.     **  separating blanks to nulls so each argv[] string is terminated.
  659.     */
  660.     for (ptr = the_cmd_line, x = 0; x < new_argc; x++) {
  661.         new_argv[x] = ptr;
  662.         ptr += strlen(ptr) + 1;
  663.     }
  664.     new_argv[new_argc] = NULL;
  665.  
  666. #if defined(TEST) || defined(DEBUG)
  667.     printf("new_argc    = %d\n", new_argc);
  668.     for (x = 0; x < new_argc; x++)
  669.         printf("new_argv[%d] = %s\n", x, new_argv[x]);
  670. #endif /* TEST || DEBUG */
  671.  
  672.     /*
  673.     **  All finished.  Return the new argc and argv[] addresses to Zip.
  674.     */
  675.     *argc_p = new_argc;
  676.     *argv_p = new_argv;
  677.  
  678.     return (SS$_NORMAL);
  679. }
  680.  
  681.  
  682.  
  683. static unsigned long
  684. get_list (struct dsc$descriptor_s *qual, struct dsc$descriptor_d *rawtail,
  685.           int delim, char **p_str, unsigned long *p_size, unsigned long *p_end)
  686. {
  687. /*
  688. **  Routine:    get_list
  689. **
  690. **  Function:   This routine runs through a comma-separated CLI list
  691. **              and copies the strings to the argv buffer.  The
  692. **              specified separation character is used to separate
  693. **              the strings in the argv buffer.
  694. **
  695. **              All unquoted strings are converted to lower-case.
  696. **
  697. **  Formal parameters:
  698. **
  699. **      qual    - Address of descriptor for the qualifier name
  700. **      rawtail - Address of descriptor for the full command line tail
  701. **      delim   - Character to use to separate the list items
  702. **      p_str   - Address of pointer pointing to output buffer (argv strings)
  703. **      p_size  - Address of number containing allocated size for output string
  704. **      p_end   - Address of number containing used length in output buf
  705. **
  706. */
  707.  
  708.     register unsigned long status;
  709.     struct dsc$descriptor_d work_str;
  710.  
  711.     init_dyndesc(work_str);
  712.  
  713.     status = cli$present(qual);
  714.     if (status & 1) {
  715.  
  716.         unsigned long len, old_len;
  717.         long ind, sind;
  718.         int keep_case;
  719.         char *src, *dst; int x;
  720.  
  721.         /*
  722.         **  Just in case the string doesn't exist yet, though it does.
  723.         */
  724.         if (*p_str == NULL) {
  725.             *p_size = ARGBSIZE_UNIT;
  726.             if ((*p_str = (char *) malloc(*p_size)) == NULL)
  727.                 return (SS$_INSFMEM);
  728.             len = 0;
  729.         } else {
  730.             len = *p_end;
  731.         }
  732.  
  733.         while ((status = cli$get_value(qual, &work_str)) & 1) {
  734.             old_len = len;
  735.             len += work_str.dsc$w_length + 1;
  736.             CHECK_BUFFER_ALLOCATION(*p_str, *p_size, len)
  737.  
  738.             /*
  739.             **  Look for the filename in the original foreign command
  740.             **  line to see if it was originally quoted.  If so, then
  741.             **  don't convert it to lowercase.
  742.             */
  743.             keep_case = FALSE;
  744.             str$find_first_substring(rawtail, &ind, &sind, &work_str);
  745.             if ((ind > 1 && *(rawtail->dsc$a_pointer + ind - 2) == '"') ||
  746.                 (ind == 0))
  747.                 keep_case = TRUE;
  748.  
  749.             /*
  750.             **  Copy the string to the buffer, converting to lowercase.
  751.             */
  752.             src = work_str.dsc$a_pointer;
  753.             dst = *p_str+old_len;
  754.             for (x = 0; x < work_str.dsc$w_length; x++) {
  755.                 if (!keep_case && ((*src >= 'A') && (*src <= 'Z')))
  756.                     *dst++ = *src++ + 32;
  757.                 else
  758.                     *dst++ = *src++;
  759.             }
  760.             if (status == CLI$_COMMA)
  761.                 (*p_str)[len-1] = (char)delim;
  762.             else
  763.                 (*p_str)[len-1] = '\0';
  764.         }
  765.         *p_end = len;
  766.     }
  767.  
  768.     return (SS$_NORMAL);
  769.  
  770. }
  771.  
  772.  
  773. static unsigned long
  774. check_cli (struct dsc$descriptor_s *qual)
  775. {
  776. /*
  777. **  Routine:    check_cli
  778. **
  779. **  Function:   Check to see if a CLD was used to invoke the program.
  780. **
  781. **  Formal parameters:
  782. **
  783. **      qual    - Address of descriptor for qualifier name to check.
  784. **
  785. */
  786.     lib$establish(lib$sig_to_ret);      /* Establish condition handler */
  787.     return (cli$present(qual));         /* Just see if something was given */
  788. }
  789.  
  790.  
  791. #ifndef TEST
  792. #ifdef SFX
  793.  
  794. #ifdef SFX_EXDIR
  795. #  define SFXOPT_EXDIR "\n                   and /DIRECTORY=exdir-spec"
  796. #else
  797. #  define SFXOPT_EXDIR ""
  798. #endif
  799.  
  800. #ifdef MORE
  801. #  define SFXOPT1 "/PAGE, "
  802. #else
  803. #  define SFXOPT1 ""
  804. #endif
  805.  
  806. int VMSCLI_usage(__GPRO__ int error)    /* returns PK-type error code */
  807. {
  808.     extern char UnzipSFXBanner[];
  809. #ifdef BETA
  810.     extern char BetaVersion[];
  811. #endif
  812.     int flag;
  813.  
  814.     if (!show_VMSCLI_usage)
  815.        return usage(__G__ error);
  816.  
  817.     flag = (error? 1 : 0);
  818.  
  819.     Info(slide, flag, ((char *)slide, UnzipSFXBanner,
  820.       UZ_MAJORVER, UZ_MINORVER, PATCHLEVEL, BETALEVEL, VERSION_DATE));
  821.     Info(slide, flag, ((char *)slide, "\
  822. Valid main options are /TEST, /FRESHEN, /UPDATE, /PIPE, /SCREEN, /COMMENT%s.\n",
  823.       SFXOPT_EXDIR));
  824.     Info(slide, flag, ((char *)slide, "\
  825. Modifying options are /TEXT, /BINARY, /JUNK, /[NO]OVERWRITE, /QUIET,\n\
  826.                       /CASE_INSENSITIVE, /LOWERCASE, %s/VERSION, /RESTORE.\n",
  827.       SFXOPT1));
  828. #ifdef BETA
  829.     Info(slide, flag, ((char *)slide, BetaVersion, "\n", "SFX"));
  830. #endif
  831.  
  832.     if (error)
  833.         return PK_PARAM;
  834.     else
  835.         return PK_COOL;     /* just wanted usage screen: no error */
  836.  
  837. } /* end function usage() */
  838.  
  839.  
  840. #else /* !SFX */
  841.  
  842. int VMSCLI_usage(__GPRO__ int error)    /* returns PK-type error code */
  843. {
  844.     extern char UnzipUsageLine1[];
  845. #ifdef BETA
  846.     extern char BetaVersion[];
  847. #endif
  848.     int flag;
  849.  
  850.     if (!show_VMSCLI_usage)
  851.        return usage(__G__ error);
  852.  
  853. /*---------------------------------------------------------------------------
  854.     If user requested usage, send it to stdout; else send to stderr.
  855.   ---------------------------------------------------------------------------*/
  856.  
  857.     flag = (error? 1 : 0);
  858.  
  859.  
  860. /*---------------------------------------------------------------------------
  861.     Print either ZipInfo usage or UnZip usage, depending on incantation.
  862.   ---------------------------------------------------------------------------*/
  863.  
  864.     if (uO.zipinfo_mode) {
  865.  
  866. #ifndef NO_ZIPINFO
  867.  
  868.         Info(slide, flag, ((char *)slide, "\
  869. ZipInfo %d.%d%d%s %s, by Newtware and the fine folks at Info-ZIP.\n\n\
  870. List name, date/time, attribute, size, compression method, etc., about files\n\
  871. in list (excluding those in xlist) contained in the specified .zip archive(s).\
  872. \n\"file[.zip]\" may be a wildcard name containing * or % (e.g., \"*font-%.zip\
  873. \").\n", ZI_MAJORVER, ZI_MINORVER, PATCHLEVEL, BETALEVEL, VERSION_DATE));
  874.  
  875.         Info(slide, flag, ((char *)slide, "\
  876.    usage:  zipinfo file[.zip] [list] [/EXCL=(xlist)] [/DIR=exdir] /options\n\
  877.    or:  unzip /ZIPINFO file[.zip] [list] [/EXCL=(xlist)] [/DIR=exdir] /options\
  878. \n\nmain\
  879.  listing-format options:              /SHORT   short \"ls -l\" format (def.)\n\
  880.   /ONE_LINE  just filenames, one/line     /MEDIUM  medium Unix \"ls -l\" format\n\
  881.   /VERBOSE   verbose, multi-page format   /LONG    long Unix \"ls -l\" format\n\
  882. "));
  883.  
  884.         Info(slide, flag, ((char *)slide, "\
  885. miscellaneous options:\n  \
  886. /HEADER   print header line       /TOTALS  totals for listed files or for all\n\
  887.   /COMMENT  print zipfile comment   /TIMES   times in sortable decimal format\n\
  888.   /[NO]CASE_INSENSITIVE  match filenames case-insensitively\n\
  889.   /[NO]PAGE page output through built-in \"more\"\n\
  890.   /EXCLUDE=(file-spec1,etc.)  exclude file-specs from listing\n"));
  891.  
  892.         Info(slide, flag, ((char *)slide, "\n\
  893. Type unzip \"-Z\" for Unix style flags\n\
  894. Remember that non-lowercase filespecs must be\
  895.  quoted in VMS (e.g., \"Makefile\").\n"));
  896.  
  897. #endif /* !NO_ZIPINFO */
  898.  
  899.     } else {   /* UnZip mode */
  900.  
  901.         Info(slide, flag, ((char *)slide, UnzipUsageLine1,
  902.           UZ_MAJORVER, UZ_MINORVER, PATCHLEVEL, BETALEVEL, VERSION_DATE));
  903.  
  904. #ifdef BETA
  905.         Info(slide, flag, ((char *)slide, BetaVersion, "", ""));
  906. #endif
  907.  
  908.         Info(slide, flag, ((char *)slide, "\
  909. Usage: unzip file[.zip] [list] [/EXCL=(xlist)] [/DIR=exdir] /options /modifiers\
  910. \n  Default action is to extract files in list, except those in xlist, to exdir\
  911. ;\n  file[.zip] may be a wildcard.  %s\n\n",
  912. #ifdef NO_ZIPINFO
  913.           "(ZipInfo mode is disabled in this version.)"
  914. #else
  915.           "Type \"unzip /ZIPINFO\" for ZipInfo-mode usage."
  916. #endif
  917.           ));
  918.  
  919.         Info(slide, flag, ((char *)slide, "\
  920. Major options include (type unzip -h for Unix style flags):\n\
  921.    /[NO]TEST, /LIST, /[NO]SCREEN, /PIPE, /[NO]FRESHEN, /[NO]UPDATE,\n\
  922.    /[NO]COMMENT, /DIRECTORY=directory-spec, /EXCLUDE=(file-spec1,etc.)\n\n\
  923. Modifiers include:\n\
  924.    /BRIEF, /FULL, /[NO]TEXT[=NONE|AUTO|ALL], /[NO]BINARY[=NONE|AUTO|ALL],\n\
  925.    /[NO]OVERWRITE, /[NO]JUNK, /QUIET, /QUIET[=SUPER], /[NO]PAGE,\n\
  926.    /[NO]CASE_INSENSITIVE, /[NO]LOWERCASE, /[NO]VERSION, /[NO]RESTORE\n\n"));
  927.  
  928.         Info(slide, flag, ((char *)slide, "\
  929. Examples (see unzip.doc or \"HELP UNZIP\" for more info):\n   \
  930. unzip edit1 /EXCL=joe.jou /CASE_INSENSITIVE    => extract all files except\n   \
  931.    joe.jou (or JOE.JOU, or any combination of case) from zipfile edit1.zip\n   \
  932. unzip zip201 \"Makefile.VMS\" vms/*.[ch]         => extract VMS Makefile and\n\
  933.       *.c and *.h files; must quote uppercase names if /CASE_INSENS not used\n\
  934.    unzip foo /DIR=tmp:[.test] /JUNK /TEXT /OVER   => extract all files to temp.\
  935. \n      directory without paths, auto-converting text files and overwriting\
  936. \n"));
  937.  
  938.     } /* end if (zipinfo_mode) */
  939.  
  940.     if (error)
  941.         return PK_PARAM;
  942.     else
  943.         return PK_COOL;     /* just wanted usage screen: no error */
  944.  
  945. } /* end function VMSCLI_usage() */
  946.  
  947. #endif /* ?SFX */
  948. #endif /* !TEST */
  949.