cmdline.c
上传用户:andy_li
上传日期:2007-01-06
资源大小:1019k
文件大小:29k
源码类别:

压缩解压

开发平台:

MultiPlatform

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