1 /*
2   Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
3 
4   See the accompanying file LICENSE, version 2007-Mar-4 or later
5   (the contents of which are also included in zip.h) for terms of use.
6   If, for some reason, all these files are missing, the Info-ZIP license
7   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
8 */
9 
10 /*
11    Test procedure:
12 
13    Compile and link (in [.VMS] directory):
14 
15       define vms SYS$DISK:[]
16       set command /object ZIP_CLI.CLD
17       cc /define = (TEST, VMSCLI) /include = [-] CMDLINE
18       link link CMDLINE.OBJ, ZIP_CLI.OBJ
19 
20    Run:
21 
22       exec*ute == "$SYS$DISK:[]'"
23       exec cmdline [options ...]
24 
25 */
26 
27 /* 2004-12-13 SMS.
28  * Disabled the module name macro to accommodate old GNU C which didn't
29  * obey the directive, and thus confused MMS/MMK where the object
30  * library dependencies need to have the correct module name.
31  */
32 #if 0
33 # define module_name VMS_ZIP_CMDLINE
34 # define module_ident "02-006"
35 #endif /* 0 */
36 
37 /*
38 **
39 **  Facility:   ZIP
40 **
41 **  Module:     VMS_ZIP_CMDLINE
42 **
43 **  Author:     Hunter Goatley <goathunter@MadGoat.com>
44 **
45 **  Date:       July 30, 1993
46 **
47 **  Abstract:   Routines to handle a VMS CLI interface for Zip.  The CLI
48 **              command line is parsed and a new argc/argv are built and
49 **              returned to Zip.
50 **
51 **  Modified by:
52 **
53 **      02-007          Steven Schweda          09-FEB-2005
54 **              Added /PRESERVE_CASE.
55 **      02-006          Onno van der Linden,
56 **                      Christian Spieler       07-JUL-1998 23:03
57 **              Support GNU CC 2.8 on Alpha AXP (vers-num unchanged).
58 **      02-006          Johnny Lee              25-JUN-1998 07:40
59 **              Fixed typo (superfluous ';') (vers-num unchanged).
60 **      02-006          Christian Spieler       12-SEP-1997 23:17
61 **              Fixed bugs in /BEFORE and /SINCE handlers (vers-num unchanged).
62 **      02-006          Christian Spieler       12-JUL-1997 02:05
63 **              Complete revision of the argv strings construction.
64 **              Added handling of "-P pwd", "-R", "-i@file", "-x@file" options.
65 **      02-005          Patrick Ellis           09-MAY-1996 22:25
66 **              Show UNIX style help screen when UNIX style options are used.
67 **      02-004          Onno van der Linden,
68 **                      Christian Spieler       13-APR-1996 20:05
69 **              Removed /ENCRYPT=VERIFY ("-ee" option).
70 **      02-003          Christian Spieler       11-FEB-1996 23:05
71 **              Added handling of /EXTRAFIELDS qualifier ("-X" option).
72 **      02-002          Christian Spieler       09-JAN-1996 22:25
73 **              Added "#include crypt.h", corrected typo.
74 **      02-001          Christian Spieler       04-DEC-1995 16:00
75 **              Fixed compilation in DEC CC's ANSI mode.
76 **      02-000          Christian Spieler       10-OCT-1995 17:54
77 **              Modified for Zip v2.1, added several new options.
78 **      01-000          Hunter Goatley          30-JUL-1993 07:54
79 **              Original version (for Zip v1.9p1).
80 **
81 */
82 
83 
84 /* 2004-12-13 SMS.
85  * Disabled the module name macro to accommodate old GNU C which didn't
86  * obey the directive, and thus confused MMS/MMK where the object
87  * library dependencies need to have the correct module name.
88  */
89 #if 0
90 # if defined(__DECC) || defined(__GNUC__)
91 #  pragma module module_name module_ident
92 # else
93 #  module module_name module_ident
94 # endif
95 #endif /* 0 */
96 
97 /* Accomodation for /NAMES = AS_IS with old header files. */
98 
99 #define lib$establish LIB$ESTABLISH
100 #define lib$get_foreign LIB$GET_FOREIGN
101 #define lib$get_input LIB$GET_INPUT
102 #define lib$sig_to_ret LIB$SIG_TO_RET
103 #define ots$cvt_tu_l OTS$CVT_TU_L
104 #define str$concat STR$CONCAT
105 #define str$find_first_substring STR$FIND_FIRST_SUBSTRING
106 #define str$free1_dx STR$FREE1_DX
107 
108 #include "zip.h"
109 #ifndef TEST
110 #include "crypt.h"      /* for VMSCLI_help() */
111 #include "revision.h"   /* for VMSCLI_help() */
112 #endif /* !TEST */
113 
114 #include <ssdef.h>
115 #include <descrip.h>
116 #include <climsgdef.h>
117 #include <clidef.h>
118 #include <lib$routines.h>
119 #include <ots$routines.h>
120 #include <str$routines.h>
121 
122 #ifndef CLI$_COMMA
123 globalvalue CLI$_COMMA;
124 #endif
125 
126 /*
127 **  "Macro" to initialize a dynamic string descriptor.
128 */
129 #define init_dyndesc(dsc) {\
130         dsc.dsc$w_length = 0;\
131         dsc.dsc$b_dtype = DSC$K_DTYPE_T;\
132         dsc.dsc$b_class = DSC$K_CLASS_D;\
133         dsc.dsc$a_pointer = NULL;}
134 
135 /*
136 **  Memory allocation step for argv string buffer.
137 */
138 #define ARGBSIZE_UNIT 256
139 
140 /*
141 **  Memory reallocation macro for argv string buffer.
142 */
143 #define CHECK_BUFFER_ALLOCATION(buf, reserved, requested) { \
144     if ((requested) > (reserved)) { \
145         char *save_buf = (buf); \
146         (reserved) += ARGBSIZE_UNIT; \
147         if (((buf) = (char *) realloc((buf), (reserved))) == NULL) { \
148             if (save_buf != NULL) free(save_buf); \
149             return (SS$_INSFMEM); \
150         } \
151     } \
152 }
153 
154 /*
155 **  Define descriptors for all of the CLI parameters and qualifiers.
156 */
157 $DESCRIPTOR(cli_delete,         "DELETE");              /* -d */
158 $DESCRIPTOR(cli_freshen,        "FRESHEN");             /* -f */
159 $DESCRIPTOR(cli_move,           "MOVE");                /* -m */
160 $DESCRIPTOR(cli_update,         "UPDATE");              /* -u */
161 $DESCRIPTOR(cli_exclude,        "EXCLUDE");             /* -x */
162 $DESCRIPTOR(cli_include,        "INCLUDE");             /* -i */
163 $DESCRIPTOR(cli_exlist,         "EXLIST");              /* -x@ */
164 $DESCRIPTOR(cli_inlist,         "INLIST");              /* -i@ */
165 $DESCRIPTOR(cli_adjust,         "ADJUST_OFFSETS");      /* -A */
166 $DESCRIPTOR(cli_append,         "APPEND");              /* -g */
167 $DESCRIPTOR(cli_batch,          "BATCH");               /* -@ */
168 $DESCRIPTOR(cli_before,         "BEFORE");              /* -tt */
169 $DESCRIPTOR(cli_comments,       "COMMENTS");            /* -c,-z */
170 $DESCRIPTOR(cli_comment_archive,"COMMENTS.ARCHIVE");    /* -z */
171 $DESCRIPTOR(cli_comment_zipfile,"COMMENTS.ZIP_FILE");   /* -z */
172 $DESCRIPTOR(cli_comment_files,  "COMMENTS.FILES");      /* -c */
173 $DESCRIPTOR(cli_compression,    "COMPRESSION");         /* -Z */
174 $DESCRIPTOR(cli_compression_b,  "COMPRESSION.BZIP2");   /* -Zb */
175 $DESCRIPTOR(cli_compression_d,  "COMPRESSION.DEFLATE"); /* -Zd */
176 $DESCRIPTOR(cli_compression_s,  "COMPRESSION.STORE");   /* -Zs */
177 $DESCRIPTOR(cli_copy_entries,   "COPY_ENTRIES");        /* -U */
178 $DESCRIPTOR(cli_descriptors,    "DESCRIPTORS");         /* -fd */
179 $DESCRIPTOR(cli_difference,     "DIFFERENCE");          /* -DF */
180 $DESCRIPTOR(cli_dirnames,       "DIRNAMES");            /* -D */
181 $DESCRIPTOR(cli_display,        "DISPLAY");             /* -d? */
182 $DESCRIPTOR(cli_display_bytes,  "DISPLAY.BYTES");       /* -db */
183 $DESCRIPTOR(cli_display_counts, "DISPLAY.COUNTS");      /* -dc */
184 $DESCRIPTOR(cli_display_dots,   "DISPLAY.DOTS");        /* -dd,-ds */
185 $DESCRIPTOR(cli_display_globaldots, "DISPLAY.GLOBALDOTS"); /* -dg */
186 $DESCRIPTOR(cli_display_usize,  "DISPLAY.USIZE");       /* -du */
187 $DESCRIPTOR(cli_display_volume, "DISPLAY.VOLUME");      /* -dv */
188 $DESCRIPTOR(cli_dot_version,    "DOT_VERSION");         /* -ww */
189 $DESCRIPTOR(cli_encrypt,        "ENCRYPT");             /* -e,-P */
190 $DESCRIPTOR(cli_extra_fields,   "EXTRA_FIELDS");        /* -X [/NO] */
191 $DESCRIPTOR(cli_extra_fields_normal, "EXTRA_FIELDS.NORMAL"); /* no -X */
192 $DESCRIPTOR(cli_extra_fields_keep, "EXTRA_FIELDS.KEEP_EXISTING"); /* -X- */
193 $DESCRIPTOR(cli_filesync,       "FILESYNC");            /* -FS */
194 $DESCRIPTOR(cli_fix_archive,    "FIX_ARCHIVE");         /* -F[F] */
195 $DESCRIPTOR(cli_fix_normal,     "FIX_ARCHIVE.NORMAL");  /* -F */
196 $DESCRIPTOR(cli_fix_full,       "FIX_ARCHIVE.FULL");    /* -FF */
197 $DESCRIPTOR(cli_full_path,      "FULL_PATH");           /* -p */
198 $DESCRIPTOR(cli_grow,           "GROW");                /* -g */
199 $DESCRIPTOR(cli_help,           "HELP");                /* -h */
200 $DESCRIPTOR(cli_help_normal,    "HELP.NORMAL");         /* -h */
201 $DESCRIPTOR(cli_help_extended,  "HELP.EXTENDED");       /* -h2 */
202 $DESCRIPTOR(cli_junk,           "JUNK");                /* -j */
203 $DESCRIPTOR(cli_keep_version,   "KEEP_VERSION");        /* -w */
204 $DESCRIPTOR(cli_latest,         "LATEST");              /* -o */
205 $DESCRIPTOR(cli_level,          "LEVEL");               /* -[0-9] */
206 $DESCRIPTOR(cli_license,        "LICENSE");             /* -L */
207 $DESCRIPTOR(cli_log_file,       "LOG_FILE");            /* -la,-lf,-li */
208 $DESCRIPTOR(cli_log_file_append, "LOG_FILE.APPEND");    /* -la */
209 $DESCRIPTOR(cli_log_file_file,  "LOG_FILE.FILE");       /* -lf */
210 $DESCRIPTOR(cli_log_file_info,  "LOG_FILE.INFORMATIONAL"); /* -li */
211 $DESCRIPTOR(cli_must_match,     "MUST_MATCH");          /* -MM */
212 $DESCRIPTOR(cli_output,         "OUTPUT");              /* -O */
213 $DESCRIPTOR(cli_patt_case,      "PATTERN_CASE");        /* -ic[-] */
214 $DESCRIPTOR(cli_patt_case_blind, "PATTERN_CASE.BLIND"); /* -ic */
215 $DESCRIPTOR(cli_patt_case_sensitive, "PATTERN_CASE.SENSITIVE"); /* -ic- */
216 $DESCRIPTOR(cli_pkzip,          "PKZIP");               /* -k */
217 $DESCRIPTOR(cli_pres_case,      "PRESERVE_CASE");       /* -C */
218 $DESCRIPTOR(cli_pres_case_no2,  "PRESERVE_CASE.NOODS2");/* -C2- */
219 $DESCRIPTOR(cli_pres_case_no5,  "PRESERVE_CASE.NOODS5");/* -C5- */
220 $DESCRIPTOR(cli_pres_case_ods2, "PRESERVE_CASE.ODS2");  /* -C2 */
221 $DESCRIPTOR(cli_pres_case_ods5, "PRESERVE_CASE.ODS5");  /* -C5 */
222 $DESCRIPTOR(cli_quiet,          "QUIET");               /* -q */
223 $DESCRIPTOR(cli_recurse,        "RECURSE");             /* -r,-R */
224 $DESCRIPTOR(cli_recurse_path,   "RECURSE.PATH");        /* -r */
225 $DESCRIPTOR(cli_recurse_fnames, "RECURSE.FILENAMES");   /* -R */
226 $DESCRIPTOR(cli_show,           "SHOW");                /* -s? */
227 $DESCRIPTOR(cli_show_command,   "SHOW.COMMAND");        /* -sc */
228 $DESCRIPTOR(cli_show_debug,     "SHOW.DEBUG");          /* -sd */
229 $DESCRIPTOR(cli_show_files,     "SHOW.FILES");          /* -sf */
230 $DESCRIPTOR(cli_show_options,   "SHOW.OPTIONS");        /* -so */
231 $DESCRIPTOR(cli_since,          "SINCE");               /* -t */
232 $DESCRIPTOR(cli_split,          "SPLIT");               /* -s,-sb,-sp,-sv */
233 $DESCRIPTOR(cli_split_bell,     "SPLIT.BELL");          /* -sb */
234 $DESCRIPTOR(cli_split_pause,    "SPLIT.PAUSE");         /* -sp */
235 $DESCRIPTOR(cli_split_size,     "SPLIT.SIZE");          /* -s */
236 $DESCRIPTOR(cli_split_verbose,  "SPLIT.VERBOSE");       /* -sv */
237 $DESCRIPTOR(cli_store_types,    "STORE_TYPES");         /* -n */
238 $DESCRIPTOR(cli_sverbose,       "SVERBOSE");            /* -sv */
239 $DESCRIPTOR(cli_symlinks,       "SYMLINKS");            /* -y */
240 $DESCRIPTOR(cli_temp_path,      "TEMP_PATH");           /* -b */
241 $DESCRIPTOR(cli_test,           "TEST");                /* -T */
242 $DESCRIPTOR(cli_test_unzip,     "TEST.UNZIP");          /* -TT */
243 $DESCRIPTOR(cli_translate_eol,  "TRANSLATE_EOL");       /* -l[l] */
244 $DESCRIPTOR(cli_transl_eol_lf,  "TRANSLATE_EOL.LF");    /* -l */
245 $DESCRIPTOR(cli_transl_eol_crlf,"TRANSLATE_EOL.CRLF");  /* -ll */
246 $DESCRIPTOR(cli_unsfx,          "UNSFX");               /* -J */
247 $DESCRIPTOR(cli_verbose,        "VERBOSE");             /* -v (?) */
248 $DESCRIPTOR(cli_verbose_normal, "VERBOSE.NORMAL");      /* -v */
249 $DESCRIPTOR(cli_verbose_more,   "VERBOSE.MORE");        /* -vv */
250 $DESCRIPTOR(cli_verbose_debug,  "VERBOSE.DEBUG");       /* -vvv */
251 $DESCRIPTOR(cli_verbose_command,"VERBOSE.COMMAND");     /* (none) */
252 $DESCRIPTOR(cli_vms,            "VMS");                 /* -V */
253 $DESCRIPTOR(cli_vms_all,        "VMS.ALL");             /* -VV */
254 $DESCRIPTOR(cli_wildcard,       "WILDCARD");            /* -nw */
255 $DESCRIPTOR(cli_wildcard_nospan,"WILDCARD.NOSPAN");     /* -W */
256 
257 $DESCRIPTOR(cli_yyz,            "YYZ_ZIP");
258 
259 $DESCRIPTOR(cli_zip64,          "ZIP64");               /* -fz */
260 $DESCRIPTOR(cli_zipfile,        "ZIPFILE");
261 $DESCRIPTOR(cli_infile,         "INFILE");
262 $DESCRIPTOR(zip_command,        "zip ");
263 
264 static int show_VMSCLI_help;
265 
266 #if !defined(zip_clitable)
267 #  define zip_clitable ZIP_CLITABLE
268 #endif
269 #if defined(__DECC) || defined(__GNUC__)
270 extern void *zip_clitable;
271 #else
272 globalref void *zip_clitable;
273 #endif
274 
275 /* extern unsigned long LIB$GET_INPUT(void), LIB$SIG_TO_RET(void); */
276 
277 #ifndef __STARLET_LOADED
278 #ifndef sys$bintim
279 #  define sys$bintim SYS$BINTIM
280 #endif
281 #ifndef sys$numtim
282 #  define sys$numtim SYS$NUMTIM
283 #endif
284 extern int sys$bintim ();
285 extern int sys$numtim ();
286 #endif /* !__STARLET_LOADED */
287 #ifndef cli$dcl_parse
288 #  define cli$dcl_parse CLI$DCL_PARSE
289 #endif
290 #ifndef cli$present
291 #  define cli$present CLI$PRESENT
292 #endif
293 #ifndef cli$get_value
294 #  define cli$get_value CLI$GET_VALUE
295 #endif
296 extern unsigned long cli$dcl_parse ();
297 extern unsigned long cli$present ();
298 extern unsigned long cli$get_value ();
299 
300 unsigned long vms_zip_cmdline (int *, char ***);
301 static unsigned long get_list (struct dsc$descriptor_s *,
302                                struct dsc$descriptor_d *, int,
303                                char **, unsigned long *, unsigned long *);
304 static unsigned long get_time (struct dsc$descriptor_s *qual, char *timearg);
305 static unsigned long check_cli (struct dsc$descriptor_s *);
306 static int verbose_command = 0;
307 
308 
309 #ifdef TEST
310 
311 char errbuf[ FNMAX+ 81];        /* Error message buffer. */
312 
ziperr(int c,char * h)313 void ziperr( int c, char *h)    /* Error message display function. */
314 {
315 /* int c: error code from the ZE_ class */
316 /* char *h: message about how it happened */
317 
318 printf( "%d: %s\n", c, h);
319 }
320 
321 int
main(int argc,char ** argv)322 main(int argc, char **argv)     /* Main program. */
323 {
324     return (vms_zip_cmdline(&argc, &argv));
325 }
326 
327 #endif /* def TEST */
328 
329 
330 unsigned long
vms_zip_cmdline(int * argc_p,char *** argv_p)331 vms_zip_cmdline (int *argc_p, char ***argv_p)
332 {
333 /*
334 **  Routine:    vms_zip_cmdline
335 **
336 **  Function:
337 **
338 **      Parse the DCL command line and create a fake argv array to be
339 **      handed off to Zip.
340 **
341 **      NOTE: the argv[] is built as we go, so all the parameters are
342 **      checked in the appropriate order!!
343 **
344 **  Formal parameters:
345 **
346 **      argc_p          - Address of int to receive the new argc
347 **      argv_p          - Address of char ** to receive the argv address
348 **
349 **  Calling sequence:
350 **
351 **      status = vms_zip_cmdline (&argc, &argv);
352 **
353 **  Returns:
354 **
355 **      SS$_NORMAL      - Success.
356 **      SS$_INSFMEM     - A malloc() or realloc() failed
357 **      SS$_ABORT       - Bad time value
358 **
359 */
360     register unsigned long status;
361     char options[ 64];
362     char *the_cmd_line;                 /* buffer for argv strings */
363     unsigned long cmdl_size;            /* allocated size of buffer */
364     unsigned long cmdl_len;             /* used size of buffer */
365     char *ptr;
366     int  x, len;
367 
368     int new_argc;
369     char **new_argv;
370 
371     struct dsc$descriptor_d work_str;
372     struct dsc$descriptor_d foreign_cmdline;
373 
374     init_dyndesc(work_str);
375     init_dyndesc(foreign_cmdline);
376 
377     /*
378     **  See if the program was invoked by the CLI (SET COMMAND) or by
379     **  a foreign command definition.  Check for /YYZ_ZIP, which is a
380     **  valid default qualifier solely for this test.
381     */
382     show_VMSCLI_help = TRUE;
383     status = check_cli(&cli_yyz);
384     if (!(status & 1)) {
385         lib$get_foreign(&foreign_cmdline);
386         /*
387         **  If nothing was returned or the first character is a "-", then
388         **  assume it's a UNIX-style command and return.
389         */
390         if (foreign_cmdline.dsc$w_length == 0)
391             return (SS$_NORMAL);
392         if ((*(foreign_cmdline.dsc$a_pointer) == '-') ||
393             ((foreign_cmdline.dsc$w_length > 1) &&
394              (*(foreign_cmdline.dsc$a_pointer) == '"') &&
395              (*(foreign_cmdline.dsc$a_pointer + 1) == '-'))) {
396             show_VMSCLI_help = FALSE;
397             return (SS$_NORMAL);
398         }
399 
400         str$concat(&work_str, &zip_command, &foreign_cmdline);
401         status = cli$dcl_parse(&work_str, &zip_clitable, lib$get_input,
402                         lib$get_input, 0);
403         if (!(status & 1)) return (status);
404     }
405 
406     /*
407     **  There's always going to be a new_argv[] because of the image name.
408     */
409     if ((the_cmd_line = (char *) malloc(cmdl_size = ARGBSIZE_UNIT)) == NULL)
410         return (SS$_INSFMEM);
411 
412     strcpy(the_cmd_line, "zip");
413     cmdl_len = sizeof("zip");
414 
415     /*
416     **  First, check to see if any of the regular options were specified.
417     */
418 
419     options[0] = '-';
420     ptr = &options[1];          /* Point to temporary buffer */
421 
422     /*
423     **  Copy entries.
424     */
425     status = cli$present(&cli_copy_entries);
426     if (status & 1)
427         /* /COPY_ENTRIES */
428         *ptr++ = 'U';
429 
430     /*
431     **  Delete the specified files from the zip file?
432     */
433     status = cli$present(&cli_delete);
434     if (status & 1)
435         /* /DELETE */
436         *ptr++ = 'd';
437 
438     /*
439     **  Freshen (only changed files).
440     */
441     status = cli$present(&cli_freshen);
442     if (status & 1)
443         /* /FRESHEN */
444         *ptr++ = 'f';
445 
446     /*
447     **  Delete the files once they've been added to the zip file.
448     */
449     status = cli$present(&cli_move);
450     if (status & 1)
451         /* /MOVE */
452         *ptr++ = 'm';
453 
454     /*
455     **  Add changed and new files.
456     */
457     status = cli$present(&cli_update);
458     if (status & 1)
459         /* /UPDATE */
460         *ptr++ = 'u';
461 
462     /*
463     **  Check for the compression level (-0 through -9).
464     */
465     status = cli$present(&cli_level);
466     if (status & 1) {
467         /* /LEVEL = value */
468 
469         unsigned long binval;
470 
471         status = cli$get_value(&cli_level, &work_str);
472         status = ots$cvt_tu_l(&work_str, &binval);
473         if (!(status & 1) || (binval > 9)) {
474            return (SS$_ABORT);
475         }
476         *ptr++ = binval + '0';
477     }
478 
479     /*
480     **  Adjust offsets of zip archive entries.
481     */
482     status = cli$present(&cli_adjust);
483     if (status & 1)
484         /* /ADJUST_OFFSETS */
485         *ptr++ = 'A';
486 
487     /*
488     **  Add comments?
489     */
490     status = cli$present(&cli_comments);
491     if (status & 1)
492     {
493         int archive_or_zip_file = 0;
494 
495         if ((status = cli$present(&cli_comment_archive)) & 1)
496             /* /COMMENTS = ARCHIVE */
497             archive_or_zip_file = 1;
498         if ((status = cli$present(&cli_comment_zipfile)) & 1)
499             /* /COMMENTS = ZIP_FILE */
500             archive_or_zip_file = 1;
501         if (archive_or_zip_file != 0)
502             /* /COMMENTS = ARCHIVE */
503             *ptr++ = 'z';
504         if ((status = cli$present(&cli_comment_files)) & 1)
505             /* /COMMENTS = FILES */
506             *ptr++ = 'c';
507     }
508 
509     /*
510     **  Preserve case in file names.
511     */
512 #define OPT_C   "-C"            /* Preserve case all. */
513 #define OPT_CN  "-C-"           /* Down-case all. */
514 #define OPT_C2  "-C2"           /* Preserve case ODS2. */
515 #define OPT_C2N "-C2-"          /* Down-case ODS2. */
516 #define OPT_C5  "-C5"           /* Preserve case ODS5. */
517 #define OPT_C5N "-C5-"          /* Down-case ODS5. */
518 
519     status = cli$present( &cli_pres_case);
520     if ((status & 1) || (status == CLI$_NEGATED))
521     {
522         /* /[NO]PRESERVE_CASE */
523         char *opt;
524         int ods2 = 0;
525         int ods5 = 0;
526 
527         if (status == CLI$_NEGATED)
528         {
529             x = cmdl_len;
530             cmdl_len += strlen( OPT_CN)+ 1;
531             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
532             strcpy( &the_cmd_line[ x], OPT_CN);
533         }
534         else
535         {
536             if (cli$present( &cli_pres_case_no2) & 1)
537             {
538                 /* /PRESERVE_CASE = NOODS2 */
539                 ods2 = -1;
540             }
541             if (cli$present( &cli_pres_case_no5) & 1)
542             {
543                 /* /PRESERVE_CASE = NOODS5 */
544                 ods5 = -1;
545             }
546             if (cli$present( &cli_pres_case_ods2) & 1)
547             {
548                 /* /PRESERVE_CASE = ODS2 */
549                 ods2 = 1;
550             }
551             if (cli$present( &cli_pres_case_ods5) & 1)
552             {
553                 /* /PRESERVE_CASE = ODS5 */
554                 ods5 = 1;
555             }
556 
557             if (ods2 == ods5)
558             {
559                 /* Plain "-C[-]". */
560                 if (ods2 < 0)
561                     opt = OPT_CN;
562                 else
563                     opt = OPT_C;
564 
565                 x = cmdl_len;
566                 cmdl_len += strlen( opt)+ 1;
567                 CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
568                 strcpy( &the_cmd_line[ x], opt);
569             }
570             else
571             {
572                 if (ods2 != 0)
573                 {
574                     /* "-C2[-]". */
575                     if (ods2 < 0)
576                         opt = OPT_C2N;
577                     else
578                         opt = OPT_C2;
579 
580                     x = cmdl_len;
581                     cmdl_len += strlen( opt)+ 1;
582                     CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
583                     strcpy( &the_cmd_line[ x], opt);
584                 }
585 
586                 if (ods5 != 0)
587                 {
588                     /* "-C5[-]". */
589                     if (ods5 < 0)
590                         opt = OPT_C5N;
591                     else
592                         opt = OPT_C5;
593 
594                     x = cmdl_len;
595                     cmdl_len += strlen( opt)+ 1;
596                     CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
597                     strcpy( &the_cmd_line[ x], opt);
598                 }
599             }
600         }
601     }
602 
603     /*
604     **  Pattern case sensitivity.
605     */
606 #define OPT_IC  "-ic"           /* Case-insensitive pattern matching. */
607 #define OPT_ICN "-ic-"          /* Case-sensitive pattern matching. */
608 
609     status = cli$present( &cli_patt_case);
610     if (status & 1)
611     {
612         if (cli$present( &cli_patt_case_blind) & 1)
613         {
614             /* "-ic". */
615             x = cmdl_len;
616             cmdl_len += strlen( OPT_IC)+ 1;
617             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
618             strcpy( &the_cmd_line[ x], OPT_IC);
619         }
620         else if (cli$present( &cli_patt_case_sensitive) & 1)
621         {
622             /* "-ic-". */
623             x = cmdl_len;
624             cmdl_len += strlen( OPT_ICN)+ 1;
625             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
626             strcpy( &the_cmd_line[ x], OPT_ICN);
627         }
628     }
629 
630     /*
631     **  Data descriptors.
632     */
633 #define OPT_FD "-fd"
634 
635     status = cli$present( &cli_descriptors);
636     if (status & 1)
637     {
638         /* /DESCRIPTORS */
639         x = cmdl_len;
640         cmdl_len += strlen( OPT_FD)+ 1;
641         CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
642         strcpy( &the_cmd_line[ x], OPT_FD);
643     }
644 
645     /*
646     **  Difference archive.  Add only new or changed files.
647     */
648 #define OPT_DF   "-DF"          /* Difference archive. */
649 
650     if ((status = cli$present( &cli_difference)) & 1)
651     {
652         /* /DIFFERENCE */
653         x = cmdl_len;
654         cmdl_len += strlen( OPT_DF)+ 1;
655         CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
656         strcpy( &the_cmd_line[ x],  OPT_DF);
657     }
658 
659     /*
660     **  Do not add/modify directory entries.
661     */
662     status = cli$present(&cli_dirnames);
663     if (!(status & 1))
664         /* /DIRNAMES */
665         *ptr++ = 'D';
666 
667     /*
668     **  Encrypt?
669     */
670     status = cli$present(&cli_encrypt);
671     if (status & 1)
672         if ((status = cli$get_value(&cli_encrypt, &work_str)) & 1) {
673             /* /ENCRYPT = value */
674             x = cmdl_len;
675             cmdl_len += work_str.dsc$w_length + 4;
676             CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
677             strcpy(&the_cmd_line[x], "-P");
678             strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
679                     work_str.dsc$w_length);
680             the_cmd_line[cmdl_len-1] = '\0';
681         } else {
682             /* /ENCRYPT */
683             *ptr++ = 'e';
684         }
685 
686     /*
687     **  Fix the zip archive structure.
688     */
689     status = cli$present(&cli_fix_archive);
690     if (status & 1) {
691         *ptr++ = 'F';
692         /* /FIX_ARCHIVE = NORMAL */
693         if ((status = cli$present(&cli_fix_full)) & 1) {
694             /* /FIX_ARCHIVE = FULL */
695             *ptr++ = 'F';
696         }
697     }
698 
699     /*
700     **  Filesync.  Delete archive entry if no such file.
701     */
702 #define OPT_FS   "-FS"          /* Filesync. */
703 
704     if ((status = cli$present( &cli_filesync)) & 1)
705     {
706         /* /FILESYNC */
707         x = cmdl_len;
708         cmdl_len += strlen( OPT_FS)+ 1;
709         CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
710         strcpy( &the_cmd_line[ x],  OPT_FS);
711     }
712 
713     /*
714     **  Append (allow growing of existing zip file).
715     */
716     status = cli$present(&cli_append);
717     if (status & 1)
718         /* /APPEND */
719         *ptr++ = 'g';
720 
721     status = cli$present(&cli_grow);
722     if (status & 1)
723         /* /GROW */
724         *ptr++ = 'g';
725 
726     /*
727     **  Show the help.
728     */
729 #define OPT_H2 "-h2"
730 
731     status = cli$present(&cli_help);
732     if (status & 1)
733     {
734         status = cli$present( &cli_help_normal);
735         if (status & 1)
736         {
737             /* /HELP [= NORMAL] */
738             *ptr++ = 'h';
739         }
740         status = cli$present( &cli_help_extended);
741         if (status & 1)
742         {
743             /* /HELP = EXTENDED */
744             x = cmdl_len;
745             cmdl_len += strlen( OPT_H2)+ 1;
746             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
747             strcpy( &the_cmd_line[ x], OPT_H2);
748         }
749     }
750 
751     /*
752     **  Junk path names (directory specs).
753     */
754     status = cli$present(&cli_junk);
755     if (status & 1)
756         /* /JUNK */
757         *ptr++ = 'j';
758 
759     /*
760     **  Simulate zip file made by PKZIP.
761     */
762     status = cli$present(&cli_pkzip);
763     if (status & 1)
764         /* /KEEP_VERSION */
765         *ptr++ = 'k';
766 
767     /*
768     **  Translate end-of-line.
769     */
770     status = cli$present(&cli_translate_eol);
771     if (status & 1) {
772         /* /TRANSLATE_EOL [= LF]*/
773         *ptr++ = 'l';
774         if ((status = cli$present(&cli_transl_eol_crlf)) & 1) {
775             /* /TRANSLATE_EOL = CRLF */
776             *ptr++ = 'l';
777         }
778     }
779 
780     /*
781     **  Show the software license.
782     */
783     status = cli$present(&cli_license);
784     if (status & 1)
785         /* /LICENSE */
786         *ptr++ = 'L';
787 
788     /*
789     **  Set zip file time to time of latest file in it.
790     */
791     status = cli$present(&cli_latest);
792     if (status & 1)
793         /* /LATEST */
794         *ptr++ = 'o';
795 
796     /*
797     **  Store full path (default).
798     */
799     status = cli$present(&cli_full_path);
800     if (status == CLI$_PRESENT)
801         /* /FULL_PATH */
802         *ptr++ = 'p';
803     else if (status == CLI$_NEGATED)
804         /* /NOFULL_PATH */
805         *ptr++ = 'j';
806 
807     /*
808     **  Junk Zipfile prefix (SFX stub etc.).
809     */
810     status = cli$present(&cli_unsfx);
811     if (status & 1)
812         /* /UNSFX */
813         *ptr++ = 'J';
814 
815     /*
816     **  Recurse through subdirectories.
817     */
818     status = cli$present(&cli_recurse);
819     if (status & 1) {
820         if ((status = cli$present(&cli_recurse_fnames)) & 1)
821             /* /RECURSE [= PATH] */
822             *ptr++ = 'R';
823         else
824             /* /RECURSE [= FILENAMES] */
825             *ptr++ = 'r';
826     }
827 
828     /*
829     **  Test Zipfile.
830     */
831     status = cli$present(&cli_test);
832     if (status & 1) {
833         /* /TEST */
834         *ptr++ = 'T';
835     }
836 
837     /*
838     **  Be verbose.
839     */
840     status = cli$present(&cli_verbose);
841     if (status & 1) {
842         int i;
843         int verbo = 0;
844 
845         /* /VERBOSE */
846         if ((status = cli$present(&cli_verbose_command)) & 1)
847         {
848             /* /VERBOSE = COMMAND */
849             verbose_command = 1;
850         }
851 
852         /* Note that any or all of the following options may be
853            specified, and the maximum one is used.
854         */
855         if ((status = cli$present(&cli_verbose_normal)) & 1)
856             /* /VERBOSE [ = NORMAL ] */
857             verbo = 1;
858         if ((status = cli$present(&cli_verbose_more)) & 1)
859             /* /VERBOSE = MORE */
860             verbo = 2;
861         if ((status = cli$present(&cli_verbose_debug)) & 1) {
862             /* /VERBOSE = DEBUG */
863             verbo = 3;
864         }
865         for (i = 0; i < verbo; i++)
866             *ptr++ = 'v';
867     }
868 
869     /*
870     **  Quiet mode.
871     **  (Quiet mode is processed after verbose, because a "-v" modifier
872     **  resets "noisy" to 1.)
873     */
874     status = cli$present(&cli_quiet);
875     if (status & 1)
876         /* /QUIET */
877         *ptr++ = 'q';
878 
879     /*
880     **  Save the VMS file attributes (and all allocated blocks?).
881     */
882     status = cli$present(&cli_vms);
883     if (status & 1) {
884         /* /VMS */
885         *ptr++ = 'V';
886         if ((status = cli$present(&cli_vms_all)) & 1) {
887             /* /VMS = ALL */
888             *ptr++ = 'V';
889         }
890     }
891 
892     /*
893     **  Keep the VMS version number as part of the file name when stored.
894     */
895     status = cli$present(&cli_keep_version);
896     if (status & 1)
897         /* /KEEP_VERSION */
898         *ptr++ = 'w';
899 
900     /*
901     **  Store symlinks as symlinks.
902     */
903     status = cli$present(&cli_symlinks);
904     if (status & 1)
905         /* /SYMLINKS */
906         *ptr++ = 'y';
907 
908     /*
909     **  `Batch' processing: read filenames to archive from stdin
910     **  or the specified file.
911     */
912     status = cli$present(&cli_batch);
913     if (status & 1) {
914         /* /BATCH */
915         status = cli$get_value(&cli_batch, &work_str);
916         if (status & 1) {
917             /* /BATCH = value */
918             work_str.dsc$a_pointer[work_str.dsc$w_length] = '\0';
919             if ((stdin = freopen(work_str.dsc$a_pointer, "r", stdin)) == NULL)
920             {
921                 sprintf(errbuf, "could not open list file: %s",
922                         work_str.dsc$a_pointer);
923                 ziperr(ZE_PARMS, errbuf);
924             }
925         }
926         *ptr++ = '@';
927     }
928 
929     /*
930     **  Now copy the final options string to the_cmd_line.
931     */
932     len = ptr - &options[0];
933     if (len > 1) {
934         options[len] = '\0';
935         x = cmdl_len;
936         cmdl_len += len + 1;
937         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
938         strcpy(&the_cmd_line[x], options);
939     }
940 
941     /*
942     **
943     **  OK.  We've done all the regular options, so check for -b (temporary
944     **  file path), -n (special suffixes), -O (output atchive file),
945     **  -t (exclude before time), -Z (compression method), zipfile,
946     **  files to zip, and exclude list.
947     **
948     */
949     status = cli$present(&cli_temp_path);
950     if (status & 1) {
951         /* /TEMP_PATH = value */
952         status = cli$get_value(&cli_temp_path, &work_str);
953         x = cmdl_len;
954         cmdl_len += work_str.dsc$w_length + 4;
955         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
956         strcpy(&the_cmd_line[x], "-b");
957         strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
958                 work_str.dsc$w_length);
959         the_cmd_line[cmdl_len-1] = '\0';
960     }
961 
962     status = cli$present(&cli_output);
963     if (status & 1) {
964         /* /OUTPUT = value */
965         status = cli$get_value(&cli_output, &work_str);
966         x = cmdl_len;
967         cmdl_len += work_str.dsc$w_length + 4;
968         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
969         strcpy(&the_cmd_line[x], "-O");
970         strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
971                 work_str.dsc$w_length);
972         the_cmd_line[cmdl_len-1] = '\0';
973     }
974 
975     /*
976     **  Handle "-db", "-dc", "-dd", "-ds".
977     */
978 #define OPT_DB "-db"
979 #define OPT_DC "-dc"
980 #define OPT_DD "-dd"
981 #define OPT_DG "-dg"
982 #define OPT_DS "-ds="
983 #define OPT_DU "-du"
984 #define OPT_DV "-dv"
985 
986     status = cli$present( &cli_display);
987     if (status & 1)
988     {
989         if ((status = cli$present( &cli_display_bytes)) & 1)
990         {
991             /* /DISPLAY = BYTES */
992             x = cmdl_len;
993             cmdl_len += strlen( OPT_DB)+ 1;
994             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
995             strcpy( &the_cmd_line[ x], OPT_DB);
996         }
997 
998         if ((status = cli$present( &cli_display_counts)) & 1)
999         {
1000             /* /DISPLAY = COUNTS */
1001             x = cmdl_len;
1002             cmdl_len += strlen( OPT_DC)+ 1;
1003             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1004             strcpy( &the_cmd_line[ x],  OPT_DC);
1005         }
1006 
1007         if ((status = cli$present( &cli_display_dots)) & 1)
1008         {
1009             /* /DISPLAY = DOTS [= value] */
1010             status = cli$get_value( &cli_display_dots, &work_str);
1011 
1012             x = cmdl_len;
1013             cmdl_len += strlen( OPT_DD)+ 1;
1014             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1015             strcpy( &the_cmd_line[ x], OPT_DD);
1016 
1017             /* -dd[=value] now -dd -ds=value - 5/8/05 EG */
1018             if (work_str.dsc$w_length > 0) {
1019                 x = cmdl_len;
1020                 cmdl_len += strlen( OPT_DS);
1021                 CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1022                 strcpy( &the_cmd_line[ x], OPT_DS);
1023 
1024                 x = cmdl_len;
1025                 cmdl_len += work_str.dsc$w_length+ 1;
1026                 CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1027                 strncpy( &the_cmd_line[ x],
1028                  work_str.dsc$a_pointer, work_str.dsc$w_length);
1029             }
1030         }
1031 
1032         if ((status = cli$present( &cli_display_globaldots)) & 1)
1033         {
1034             /* /DISPLAY = GLOBALDOTS */
1035             x = cmdl_len;
1036             cmdl_len += strlen( OPT_DG)+ 1;
1037             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1038             strcpy( &the_cmd_line[ x],  OPT_DG);
1039         }
1040 
1041         if ((status = cli$present( &cli_display_usize)) & 1)
1042         {
1043             /* /DISPLAY = USIZE */
1044             x = cmdl_len;
1045             cmdl_len += strlen( OPT_DU)+ 1;
1046             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1047             strcpy( &the_cmd_line[ x],  OPT_DU);
1048         }
1049 
1050         if ((status = cli$present( &cli_display_volume)) & 1)
1051         {
1052             /* /DISPLAY = VOLUME */
1053             x = cmdl_len;
1054             cmdl_len += strlen( OPT_DV)+ 1;
1055             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1056             strcpy( &the_cmd_line[ x],  OPT_DV);
1057         }
1058     }
1059 
1060     /*
1061     **  Handle "-la", "-lf", "-li".
1062     */
1063 #define OPT_LA "-la"
1064 #define OPT_LF "-lf"
1065 #define OPT_LI "-li"
1066 
1067     status = cli$present( &cli_log_file);
1068     if (status & 1)
1069     {
1070         /* /SHOW */
1071         if ((status = cli$present( &cli_log_file_append)) & 1)
1072         {
1073             /* /LOG_FILE = APPEND */
1074             x = cmdl_len;
1075             cmdl_len += strlen( OPT_LA)+ 1;
1076             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1077             strcpy( &the_cmd_line[ x], OPT_LA);
1078         }
1079 
1080         status = cli$present(&cli_log_file_file);
1081         if (status & 1) {
1082             /* /LOG_FILE = FILE = file */
1083             status = cli$get_value(&cli_log_file_file, &work_str);
1084             x = cmdl_len;
1085             cmdl_len += strlen( OPT_LF)+ 2+ work_str.dsc$w_length;
1086             CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
1087             strcpy(&the_cmd_line[x], OPT_LF);
1088             strncpy(&the_cmd_line[x+strlen( OPT_LF)+ 1], work_str.dsc$a_pointer,
1089                 work_str.dsc$w_length);
1090             the_cmd_line[cmdl_len-1] = '\0';
1091         }
1092 
1093         if ((status = cli$present( &cli_log_file_info)) & 1)
1094         {
1095             /* /LOG = INFO */
1096             x = cmdl_len;
1097             cmdl_len += strlen( OPT_LI)+ 1;
1098             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1099             strcpy( &the_cmd_line[ x],  OPT_LI);
1100         }
1101     }
1102 
1103     /*
1104     **  Handle "-s", "-sb", "-sp", "-sv".
1105     */
1106 #define OPT_S "-s"
1107 #define OPT_SB "-sb"
1108 #define OPT_SP "-sp"
1109 #define OPT_SV "-sv"
1110 
1111     status = cli$present( &cli_split);
1112     if (status & 1)
1113     {
1114         status = cli$present( &cli_split_bell);
1115         if (status & 1)
1116         {
1117             /* /SPLIT = BELL */
1118             x = cmdl_len;
1119             cmdl_len += strlen( OPT_SB)+ 1;
1120             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1121             strcpy( &the_cmd_line[ x], OPT_SB);
1122         }
1123 
1124         status = cli$present( &cli_split_pause);
1125         if (status & 1)
1126         {
1127             /* /SPLIT = PAUSE */
1128             x = cmdl_len;
1129             cmdl_len += strlen( OPT_SP)+ 1;
1130             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1131             strcpy( &the_cmd_line[ x], OPT_SP);
1132         }
1133 
1134         status = cli$present( &cli_split_size);
1135         if (status & 1)
1136         {
1137             /* /SPLIT = SIZE = size */
1138             status = cli$get_value( &cli_split_size, &work_str);
1139 
1140             x = cmdl_len;
1141             cmdl_len += strlen( OPT_S)+ 1;
1142             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1143             strcpy( &the_cmd_line[ x], OPT_S);
1144 
1145             x = cmdl_len;
1146             cmdl_len += work_str.dsc$w_length+ 1;
1147             strncpy( &the_cmd_line[ x],
1148              work_str.dsc$a_pointer, work_str.dsc$w_length);
1149         }
1150 
1151         status = cli$present( &cli_split_verbose);
1152         if (status & 1)
1153         {
1154             /* /SPLIT = VERBOSE */
1155             x = cmdl_len;
1156             cmdl_len += strlen( OPT_SV)+ 1;
1157             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1158             strcpy( &the_cmd_line[ x], OPT_SV);
1159         }
1160     }
1161 
1162     /*
1163     **  Handle "-sc", "-sd", "-sf", "-so".
1164     */
1165 #define OPT_SC "-sc"
1166 #define OPT_SD "-sd"
1167 #define OPT_SF "-sf"
1168 #define OPT_SO "-so"
1169 
1170     status = cli$present( &cli_show);
1171     if (status & 1)
1172     {
1173         /* /SHOW */
1174         if ((status = cli$present( &cli_show_command)) & 1)
1175         {
1176             /* /SHOW = COMMAND */
1177             x = cmdl_len;
1178             cmdl_len += strlen( OPT_SC)+ 1;
1179             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1180             strcpy( &the_cmd_line[ x], OPT_SC);
1181         }
1182 
1183         if ((status = cli$present( &cli_show_debug)) & 1)
1184         {
1185             /* /SHOW = DEBUG */
1186             x = cmdl_len;
1187             cmdl_len += strlen( OPT_SD)+ 1;
1188             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1189             strcpy( &the_cmd_line[ x],  OPT_SD);
1190         }
1191 
1192         if ((status = cli$present( &cli_show_files)) & 1)
1193         {
1194             /* /SHOW = FILES */
1195             x = cmdl_len;
1196             cmdl_len += strlen( OPT_SF)+ 1;
1197             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1198             strcpy( &the_cmd_line[ x], OPT_SF);
1199         }
1200 
1201         if ((status = cli$present( &cli_show_options)) & 1)
1202         {
1203             /* /SHOW = OPTIONS */
1204             x = cmdl_len;
1205             cmdl_len += strlen( OPT_SO)+ 1;
1206             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1207             strcpy( &the_cmd_line[ x], OPT_SO);
1208         }
1209     }
1210 
1211     /*
1212     **  Handle "-fz".
1213     */
1214 #define OPT_FZ "-fz"
1215 
1216     status = cli$present( &cli_zip64);
1217     if (status & 1)
1218     {
1219         /* /ZIP64 */
1220         x = cmdl_len;
1221         cmdl_len += strlen( OPT_FZ)+ 1;
1222         CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1223         strcpy( &the_cmd_line[ x], OPT_FZ);
1224     }
1225 
1226     /*
1227     **  Handle "-nw" and "-W".
1228     */
1229 #define OPT_NW "-nw"
1230 #define OPT_W "-W"
1231 
1232     status = cli$present( &cli_wildcard);
1233     if (status & 1)
1234     {
1235         if ((status = cli$present( &cli_wildcard_nospan)) & 1)
1236         {
1237             /* /WILDCARD = NOSPAN */
1238             x = cmdl_len;
1239             cmdl_len += strlen( OPT_W)+ 1;
1240             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1241             strcpy( &the_cmd_line[ x], OPT_W);
1242         }
1243     }
1244     else if (status == CLI$_NEGATED)
1245     {
1246         /* /NOWILDCARD */
1247         x = cmdl_len;
1248         cmdl_len += strlen( OPT_NW)+ 1;
1249         CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1250         strcpy( &the_cmd_line[ x], OPT_NW);
1251     }
1252 
1253     /*
1254     **  Handle "-MM".
1255     */
1256 #define OPT_MM  "-MM"
1257 
1258     status = cli$present( &cli_must_match);
1259     if (status & 1)
1260     {
1261         /* /MUST_MATCH */
1262         x = cmdl_len;
1263         cmdl_len += strlen( OPT_MM)+ 1;
1264         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
1265         strcpy( &the_cmd_line[ x], OPT_MM);
1266     }
1267 
1268     /*
1269     **  UnZip command for archive test.
1270     */
1271 #define OPT_TT "-TT"
1272 
1273     status = cli$present(&cli_test);
1274     if (status & 1) {
1275         /* /TEST */
1276         status = cli$present(&cli_test_unzip);
1277         if (status & 1) {
1278             /* /TEST = UNZIP = value */
1279             status = cli$get_value(&cli_test_unzip, &work_str);
1280             x = cmdl_len;
1281             cmdl_len += strlen( OPT_TT)+ 2+ work_str.dsc$w_length;
1282             CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
1283             strcpy(&the_cmd_line[x], OPT_TT);
1284             strncpy(&the_cmd_line[x+strlen( OPT_TT)+ 1], work_str.dsc$a_pointer,
1285                 work_str.dsc$w_length);
1286             the_cmd_line[cmdl_len-1] = '\0';
1287         }
1288     }
1289 
1290     /*
1291     **  Handle "-Z".
1292     */
1293 #define OPT_ZB "-Zb"
1294 #define OPT_ZD "-Zd"
1295 #define OPT_ZS "-Zs"
1296 
1297     status = cli$present( &cli_compression);
1298     if (status & 1)
1299     {
1300         if ((status = cli$present( &cli_compression_b)) & 1)
1301         {
1302             /* /COMPRESSION = BZIP2 */
1303             x = cmdl_len;
1304             cmdl_len += strlen( OPT_ZB)+ 1;
1305             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1306             strcpy( &the_cmd_line[ x], OPT_ZB);
1307         }
1308 
1309         if ((status = cli$present( &cli_compression_d)) & 1)
1310         {
1311             /* /COMPRESSION = DEFLATE */
1312             x = cmdl_len;
1313             cmdl_len += strlen( OPT_ZD)+ 1;
1314             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1315             strcpy( &the_cmd_line[ x], OPT_ZD);
1316         }
1317 
1318         if ((status = cli$present( &cli_compression_s)) & 1)
1319         {
1320             /* /COMPRESSION = STORE */
1321             x = cmdl_len;
1322             cmdl_len += strlen( OPT_ZS)+ 1;
1323             CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
1324             strcpy( &the_cmd_line[ x], OPT_ZS);
1325         }
1326     }
1327 
1328     /*
1329     **  Handle "-t mmddyyyy".
1330     */
1331     status = cli$present(&cli_since);
1332     if (status & 1) {
1333         /* /SINCE = value */
1334         char since_time[9];
1335 
1336         status = get_time(&cli_since, &since_time[0]);
1337         if (!(status & 1)) return (status);
1338 
1339         /*
1340         **  Now let's add the option "-t mmddyyyy" to the new command line.
1341         */
1342         x = cmdl_len;
1343         cmdl_len += (3 + 9);
1344         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
1345         strcpy(&the_cmd_line[x], "-t");
1346         strcpy(&the_cmd_line[x+3], since_time);
1347     }
1348 
1349     /*
1350     **  Handle "-tt mmddyyyy".
1351     */
1352     status = cli$present(&cli_before);
1353     if (status & 1) {
1354         /* /BEFORE = value */
1355         char before_time[9];
1356 
1357         status = get_time(&cli_before, &before_time[0]);
1358         if (!(status & 1)) return (status);
1359 
1360         /*
1361         **  Now let's add the option "-tt mmddyyyy" to the new command line.
1362         */
1363         x = cmdl_len;
1364         cmdl_len += (4 + 9);
1365         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
1366         strcpy(&the_cmd_line[x], "-tt");
1367         strcpy(&the_cmd_line[x+4], before_time);
1368     }
1369 
1370     /*
1371     **  Handle "-n suffix:suffix:...".  (File types to store only.)
1372     */
1373     status = cli$present(&cli_store_types);
1374     if (status & 1) {
1375         /* /STORE_TYPES = value_list */
1376         x = cmdl_len;
1377         cmdl_len += 3;
1378         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
1379         strcpy(&the_cmd_line[x], "-n");
1380 
1381         status = get_list(&cli_store_types, &foreign_cmdline, ':',
1382                           &the_cmd_line, &cmdl_size, &cmdl_len);
1383         if (!(status & 1)) return (status);
1384     }
1385 
1386     /*
1387     **  Handle "-X", keep or strip extra fields.
1388     */
1389 #define OPT_X  "-X"
1390 #define OPT_XN  "-X-"
1391 
1392     status = cli$present(&cli_extra_fields);
1393     if (status & 1) {
1394         /* /EXTRA_FIELDS */
1395         if ((status = cli$present( &cli_extra_fields_keep)) & 1) {
1396             /* /EXTRA_FIELDS = KEEP_EXISTING */
1397             x = cmdl_len;
1398             cmdl_len += strlen( OPT_XN)+ 1;
1399             CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
1400             strcpy( &the_cmd_line[ x], OPT_XN);
1401         }
1402     }
1403     else if (status == CLI$_NEGATED) {
1404         /* /NOEXTRA_FIELDS */
1405         x = cmdl_len;
1406         cmdl_len += strlen( OPT_X)+ 1;
1407         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
1408         strcpy( &the_cmd_line[ x], OPT_X);
1409     }
1410 
1411     /*
1412     **  Now get the specified zip file name.
1413     */
1414     status = cli$present(&cli_zipfile);
1415     /* zipfile */
1416     if (status & 1) {
1417         status = cli$get_value(&cli_zipfile, &work_str);
1418 
1419         x = cmdl_len;
1420         cmdl_len += work_str.dsc$w_length + 1;
1421         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
1422         strncpy(&the_cmd_line[x], work_str.dsc$a_pointer,
1423                 work_str.dsc$w_length);
1424         the_cmd_line[cmdl_len-1] = '\0';
1425 
1426     }
1427 
1428     /*
1429     **  Run through the list of input files.
1430     */
1431     status = cli$present(&cli_infile);
1432     if (status & 1) {
1433         /* infile_list */
1434         status = get_list(&cli_infile, &foreign_cmdline, '\0',
1435                           &the_cmd_line, &cmdl_size, &cmdl_len);
1436         if (!(status & 1)) return (status);
1437     }
1438 
1439     /*
1440     **  List file containing exclude patterns present? ("-x@exclude.lst")
1441     */
1442     status = cli$present(&cli_exlist);
1443     if (status & 1) {
1444         /* /EXLIST = list */
1445         status = cli$get_value(&cli_exlist, &work_str);
1446         x = cmdl_len;
1447         cmdl_len += work_str.dsc$w_length + 4;
1448         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
1449         strncpy(&the_cmd_line[x], "-x@", 3);
1450         strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
1451                 work_str.dsc$w_length);
1452         the_cmd_line[cmdl_len-1] = '\0';
1453     }
1454 
1455     /*
1456     **  Any files to exclude? ("-x file file")
1457     */
1458     status = cli$present(&cli_exclude);
1459     if (status & 1) {
1460         /* /EXCLUDE = list */
1461         x = cmdl_len;
1462         cmdl_len += 3;
1463         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
1464         strcpy(&the_cmd_line[x], "-x");
1465 
1466         status = get_list(&cli_exclude, &foreign_cmdline, '\0',
1467                           &the_cmd_line, &cmdl_size, &cmdl_len);
1468         if (!(status & 1)) return (status);
1469     }
1470 
1471     /*
1472     **  List file containing include patterns present? ("-x@exclude.lst")
1473     */
1474     status = cli$present(&cli_inlist);
1475     if (status & 1) {
1476         /* /INLIST = list */
1477         status = cli$get_value(&cli_inlist, &work_str);
1478         x = cmdl_len;
1479         cmdl_len += work_str.dsc$w_length + 4;
1480         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
1481         strncpy(&the_cmd_line[x], "-i@", 3);
1482         strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
1483                 work_str.dsc$w_length);
1484         the_cmd_line[cmdl_len-1] = '\0';
1485     }
1486 
1487     /*
1488     **  Any files to include? ("-i file file")
1489     */
1490     status = cli$present(&cli_include);
1491     if (status & 1) {
1492         /* /INCLUDE = list */
1493         x = cmdl_len;
1494         cmdl_len += 3;
1495         CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
1496         strcpy(&the_cmd_line[x], "-i");
1497 
1498         status = get_list(&cli_exclude, &foreign_cmdline, '\0',
1499                           &the_cmd_line, &cmdl_size, &cmdl_len);
1500         if (!(status & 1)) return (status);
1501     }
1502 
1503 
1504     /*
1505     **  We have finished collecting the strings for the argv vector,
1506     **  release unused space.
1507     */
1508     if ((the_cmd_line = (char *) realloc(the_cmd_line, cmdl_len)) == NULL)
1509         return (SS$_INSFMEM);
1510 
1511     /*
1512     **  Now that we've built our new UNIX-like command line, count the
1513     **  number of args and build an argv array.
1514     */
1515     for (new_argc = 0, x = 0; x < cmdl_len; x++)
1516         if (the_cmd_line[x] == '\0')
1517             new_argc++;
1518 
1519     /*
1520     **  Allocate memory for the new argv[].  The last element of argv[]
1521     **  is supposed to be NULL, so allocate enough for new_argc+1.
1522     */
1523     if ((new_argv = (char **) calloc(new_argc+1, sizeof(char *))) == NULL)
1524         return (SS$_INSFMEM);
1525 
1526     /*
1527     **  For each option, store the address in new_argv[] and convert the
1528     **  separating blanks to nulls so each argv[] string is terminated.
1529     */
1530     for (ptr = the_cmd_line, x = 0; x < new_argc; x++) {
1531         new_argv[x] = ptr;
1532         ptr += strlen(ptr) + 1;
1533     }
1534     new_argv[new_argc] = NULL;
1535 
1536 #if defined(TEST) || defined(DEBUG)
1537     printf("new_argc    = %d\n", new_argc);
1538     for (x = 0; x < new_argc; x++)
1539         printf("new_argv[%d] = %s\n", x, new_argv[x]);
1540 #endif /* TEST || DEBUG */
1541 
1542     /* Show the complete UNIX command line, if requested. */
1543     if (verbose_command != 0)
1544     {
1545         printf( "   UNIX command line args (argc = %d):\n", new_argc);
1546         for (x = 0; x < new_argc; x++)
1547             printf( "%s\n", new_argv[ x]);
1548         printf( "\n");
1549     }
1550 
1551     /*
1552     **  All finished.  Return the new argc and argv[] addresses to Zip.
1553     */
1554     *argc_p = new_argc;
1555     *argv_p = new_argv;
1556 
1557     return (SS$_NORMAL);
1558 }
1559 
1560 
1561 
1562 static unsigned long
get_list(struct dsc$descriptor_s * qual,struct dsc$descriptor_d * rawtail,int delim,char ** p_str,unsigned long * p_size,unsigned long * p_end)1563 get_list (struct dsc$descriptor_s *qual, struct dsc$descriptor_d *rawtail,
1564           int delim, char **p_str, unsigned long *p_size, unsigned long *p_end)
1565 {
1566 /*
1567 **  Routine:    get_list
1568 **
1569 **  Function:   This routine runs through a comma-separated CLI list
1570 **              and copies the strings to the argv buffer.  The
1571 **              specified separation character is used to separate
1572 **              the strings in the argv buffer.
1573 **
1574 **              All unquoted strings are converted to lower-case.
1575 **
1576 **  Formal parameters:
1577 **
1578 **      qual    - Address of descriptor for the qualifier name
1579 **      rawtail - Address of descriptor for the full command line tail
1580 **      delim   - Character to use to separate the list items
1581 **      p_str   - Address of pointer pointing to output buffer (argv strings)
1582 **      p_size  - Address of number containing allocated size for output string
1583 **      p_end   - Address of number containing used length in output buf
1584 **
1585 */
1586 
1587     register unsigned long status;
1588     struct dsc$descriptor_d work_str;
1589 
1590     init_dyndesc(work_str);
1591 
1592     status = cli$present(qual);
1593     if (status & 1) {
1594 
1595         unsigned long len, old_len;
1596         long ind, sind;
1597         int keep_case;
1598         char *src, *dst; int x;
1599 
1600         /*
1601         **  Just in case the string doesn't exist yet, though it does.
1602         */
1603         if (*p_str == NULL) {
1604             *p_size = ARGBSIZE_UNIT;
1605             if ((*p_str = (char *) malloc(*p_size)) == NULL)
1606                 return (SS$_INSFMEM);
1607             len = 0;
1608         } else {
1609             len = *p_end;
1610         }
1611 
1612         while ((status = cli$get_value(qual, &work_str)) & 1) {
1613             old_len = len;
1614             len += work_str.dsc$w_length + 1;
1615             CHECK_BUFFER_ALLOCATION(*p_str, *p_size, len)
1616 
1617             /*
1618             **  Look for the filename in the original foreign command
1619             **  line to see if it was originally quoted.  If so, then
1620             **  don't convert it to lowercase.
1621             */
1622             keep_case = FALSE;
1623             str$find_first_substring(rawtail, &ind, &sind, &work_str);
1624             if ((ind > 1 && *(rawtail->dsc$a_pointer + ind - 2) == '"') ||
1625                 (ind == 0))
1626                 keep_case = TRUE;
1627 
1628             /*
1629             **  Copy the string to the buffer, converting to lowercase.
1630             */
1631             src = work_str.dsc$a_pointer;
1632             dst = *p_str+old_len;
1633             for (x = 0; x < work_str.dsc$w_length; x++) {
1634                 if (!keep_case && ((*src >= 'A') && (*src <= 'Z')))
1635                     *dst++ = *src++ + 32;
1636                 else
1637                     *dst++ = *src++;
1638             }
1639             if (status == CLI$_COMMA)
1640                 (*p_str)[len-1] = (char)delim;
1641             else
1642                 (*p_str)[len-1] = '\0';
1643         }
1644         *p_end = len;
1645     }
1646 
1647     return (SS$_NORMAL);
1648 
1649 }
1650 
1651 
1652 static unsigned long
get_time(struct dsc$descriptor_s * qual,char * timearg)1653 get_time (struct dsc$descriptor_s *qual, char *timearg)
1654 {
1655 /*
1656 **  Routine:    get_time
1657 **
1658 **  Function:   This routine reads the argument string of the qualifier
1659 **              "qual" that should be a VMS syntax date-time string.  The
1660 **              date-time string is converted into the standard format
1661 **              "mmddyyyy", specifying an absolute date.  The converted
1662 **              string is written into the 9 bytes wide buffer "timearg".
1663 **
1664 **  Formal parameters:
1665 **
1666 **      qual    - Address of descriptor for the qualifier name
1667 **      timearg - Address of a buffer carrying the 8-char time string returned
1668 **
1669 */
1670 
1671     register unsigned long status;
1672     struct dsc$descriptor_d time_str;
1673     struct quadword {
1674         long high;
1675         long low;
1676     } bintimbuf = {0,0};
1677 #ifdef __DECC
1678 #pragma member_alignment save
1679 #pragma nomember_alignment
1680 #endif  /* __DECC */
1681     struct tim {
1682         short year;
1683         short month;
1684         short day;
1685         short hour;
1686         short minute;
1687         short second;
1688         short hundred;
1689     } numtimbuf;
1690 #ifdef __DECC
1691 #pragma member_alignment restore
1692 #endif
1693 
1694     init_dyndesc(time_str);
1695 
1696     status = cli$get_value(qual, &time_str);
1697     /*
1698     **  If a date is given, convert it to 64-bit binary.
1699     */
1700     if (time_str.dsc$w_length) {
1701         status = sys$bintim(&time_str, &bintimbuf);
1702         if (!(status & 1)) return (status);
1703         str$free1_dx(&time_str);
1704     }
1705     /*
1706     **  Now call $NUMTIM to get the month, day, and year.
1707     */
1708     status = sys$numtim(&numtimbuf, (bintimbuf.low ? &bintimbuf : NULL));
1709     /*
1710     **  Write the "mmddyyyy" string to the return buffer.
1711     */
1712     if (!(status & 1)) {
1713         *timearg = '\0';
1714     } else {
1715         sprintf(timearg, "%02d%02d%04d", numtimbuf.month,
1716                 numtimbuf.day, numtimbuf.year);
1717     }
1718     return (status);
1719 }
1720 
1721 
1722 static unsigned long
check_cli(struct dsc$descriptor_s * qual)1723 check_cli (struct dsc$descriptor_s *qual)
1724 {
1725 /*
1726 **  Routine:    check_cli
1727 **
1728 **  Function:   Check to see if a CLD was used to invoke the program.
1729 **
1730 **  Formal parameters:
1731 **
1732 **      qual    - Address of descriptor for qualifier name to check.
1733 **
1734 */
1735     lib$establish(lib$sig_to_ret);      /* Establish condition handler */
1736     return (cli$present(qual));         /* Just see if something was given */
1737 }
1738 
1739 
1740 #ifndef TEST
1741 
VMSCLI_help(void)1742 void VMSCLI_help(void)  /* VMSCLI version */
1743 /* Print help (along with license info) to stdout. */
1744 {
1745   extent i;             /* counter for help array */
1746 
1747   /* help array */
1748   static char *text[] = {
1749 "Zip %s (%s). Usage: (zip :== $ dev:[dir]zip_cli.exe)",
1750 "zip archive[.zip] [list] [/EXCL=(xlist)] /options /modifiers",
1751 "  The default action is to add or replace archive entries from list, except",
1752 "  those in xlist. The include file list may contain the special name \"-\" to",
1753 "  compress standard input.  If both archive and list are omitted, Zip",
1754 "  compresses stdin to stdout.",
1755 "  Type zip -h for Unix-style flags.",
1756 "  Major options include:",
1757 "    /COPY, /DELETE, /DIFFERENCE, /FILESYNC, /FRESHEN, /GROW, /MOVE, /UPDATE,",
1758 "    /ADJUST_OFFSETS, /FIX_ARCHIVE[={NORMAL|FULL}], /TEST[=UNZIP=cmd], /UNSFX,",
1759 "  Modifiers include:",
1760 "    /BATCH[=list_file], /BEFORE=creation_time, /COMMENTS[={ARCHIVE|FILES}],",
1761 "    /EXCLUDE=(file_list), /EXLIST=file, /INCLUDE=(file_list), /INLIST=file,",
1762 "    /LATEST, /OUTPUT=out_archive, /SINCE=creation_time, /TEMP_PATH=directory,",
1763 "    /LOG_FILE=(FILE=log_file[,APPEND][,INFORMATIONAL]), /MUST_MATCH,",
1764 "    /PATTERN_CASE={BLIND|SENSITIVE}, /NORECURSE|/RECURSE[={PATH|FILENAMES}],",
1765 "    /STORE_TYPES=(type_list),",
1766 #if CRYPT
1767 "\
1768     /QUIET, /VERBOSE[={MORE|DEBUG}], /[NO]DIRNAMES, /JUNK, /ENCRYPT[=\"pwd\"],\
1769 ",
1770 #else /* !CRYPT */
1771 "    /QUIET, /VERBOSE[={MORE|DEBUG}], /[NO]DIRNAMES, /JUNK,",
1772 #endif /* ?CRYPT */
1773 "    /COMPRESSION = {BZIP2|DEFLATE|STORE}, /LEVEL=[0-9], /NOVMS|/VMS[=ALL],",
1774 "    /STORE_TYPES=(type_list), /[NO]PRESERVE_CASE[=([NO]ODS{2|5}[,...])],",
1775 "    /[NO]PKZIP, /[NO]KEEP_VERSION, /DOT_VERSION, /TRANSLATE_EOL[={LF|CRLF}],",
1776 "    /DISPLAY=([BYTES][,COUNTS][,DOTS=mb_per_dot][,GLOBALDOTS][,USIZE]",
1777 "    [,VOLUME]), /DESCRIPTORS, /[NO]EXTRA_FIELDS, /ZIP64,",
1778 #ifdef S_IFLNK
1779 "    /SPLIT = (SIZE=ssize [,BELL] [,PAUSE] [,VERBOSE]), /SYMLINKS"
1780 #else /* S_IFLNK */
1781 "    /SPLIT = (SIZE=ssize [,BELL] [,PAUSE] [,VERBOSE])"
1782 #endif /* S_IFLNK [else] */
1783   };
1784 
1785   if (!show_VMSCLI_help) {
1786      help();
1787      return;
1788   }
1789 
1790   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
1791   {
1792     printf(copyright[i], "zip");
1793     putchar('\n');
1794   }
1795   for (i = 0; i < sizeof(text)/sizeof(char *); i++)
1796   {
1797     printf(text[i], VERSION, REVDATE);
1798     putchar('\n');
1799   }
1800 } /* end function VMSCLI_help() */
1801 
1802 #endif /* !TEST */
1803