cmdline.c 36 KB

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