Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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