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