1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // Command-line interface
7 #define DE_NOT_IN_MODULE
8 #include "deark-config.h"
9 #include "deark-user.h"
10 #include "deark-version.h"
14 #include <io.h> // for _setmode
17 enum color_method_enum
{
25 enum special_command_code_enum
{
26 CMD_NONE
= 0, CMD_PRINTHELP
, CMD_PRINTVERSION
, CMD_PRINTLICENSE
,
32 struct de_platform_data
*plctx
;
33 const char *input_filename
;
35 int show_usage_message
;
36 int special_command_flag
;
37 enum special_command_code_enum special_command_code
;
40 // Have we set msgs_FILE and have_windows_console, and called _setmode if needed?
41 int have_initialized_output_stream
;
43 FILE *msgs_FILE
; // Where to print (error, etc.) messages
45 int have_windows_console
; // Is msgs_FILE a console?
49 const char *output_dirname
;
50 const char *base_output_filename
;
51 const char *output_special_1st_filename
;
52 const char *archive_filename
;
53 int option_k_level
; // Use input filename in output filenames
54 int option_ka_level
; // Use input filename in output archive filenames
64 enum color_method_enum color_method_req
;
65 enum color_method_enum color_method
;
69 // Low-level print function
70 static void emit_sz(struct cmdctx
*cc
, const char *sz
)
74 de_utf8_to_utf16_to_FILE(cc
->c
, sz
, cc
->msgs_FILE
);
78 fputs(sz
, cc
->msgs_FILE
);
81 static void print_version(deark
*c
, int verbose
)
85 de_printf(c
, DE_MSGTYPE_MESSAGE
, "Deark version: %s\n",
86 de_get_version_string(vbuf
, sizeof(vbuf
)));
88 de_printf(c
, DE_MSGTYPE_MESSAGE
, "platform API: %s\n",
95 de_printf(c
, DE_MSGTYPE_MESSAGE
, "platform bits: %u\n",
96 (unsigned int)(8*sizeof(void*)));
98 de_printf(c
, DE_MSGTYPE_MESSAGE
, "build type: debug\n");
102 static void print_usage_oneline(deark
*c
) {
103 de_puts(c
, DE_MSGTYPE_MESSAGE
, "Usage: deark [options] <input-file> [options]\n");
106 static void print_usage_error(deark
*c
)
108 print_usage_oneline(c
);
109 de_puts(c
, DE_MSGTYPE_MESSAGE
, "\"deark -h\" for help.\n");
112 static void print_help(deark
*c
)
115 de_puts(c
, DE_MSGTYPE_MESSAGE
,
116 "A utility for extracting data from various file formats\n\n");
117 print_usage_oneline(c
);
118 de_puts(c
, DE_MSGTYPE_MESSAGE
,
119 "\nCommonly used options:\n"
120 " -l: Instead of extracting, list the files that would be extracted.\n"
121 " -k, -ka: Start output (-k) or .zip (-ka) filenames with the input filename.\n"
122 " -o <base-filename>: Start output filenames with this string.\n"
123 " -od <directory>: Write files to this directory.\n"
124 " -zip: Write files to a .zip file (output.zip by default).\n"
125 " -a, -main: Extract more (-a) or less (-main) data than usual.\n"
126 " -get <n>: Extract only file number <n>.\n"
127 " -maxfiles <n>: Extract at most <n> files.\n"
128 " -d, -d2, -d3: Print additional information about the file.\n"
129 " -q, -noinfo, -nowarn: Print fewer messages than usual.\n"
130 " -color: Allow color in printed messages.\n"
131 " -m <module>: Assume input file is this format, instead of autodetecting.\n"
132 " -modules: Print the names of all available modules.\n"
133 " -h, -version, -license: Print this message / version info / terms of use.\n"
137 static void print_license(deark
*c
)
139 de_puts(c
, DE_MSGTYPE_MESSAGE
, "Deark\n"
140 "Copyright (C) 2016-"DE_COPYRIGHT_YEAR_STRING
" Jason Summers\n\n"
141 "Permission is hereby granted, free of charge, to any person obtaining a copy\n"
142 "of this software and associated documentation files (the \"Software\"), to deal\n"
143 "in the Software without restriction, including without limitation the rights\n"
144 "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n"
145 "copies of the Software, and to permit persons to whom the Software is\n"
146 "furnished to do so, subject to the following conditions:\n\n"
147 "The above copyright notice and this permission notice shall be included in\n"
148 "all copies or substantial portions of the Software.\n\n"
149 "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n"
150 "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n"
151 "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n"
152 "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n"
153 "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n"
154 "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n"
157 "The zlib and Deflate encoder and decoder use MIT-licensed code from miniz,\n"
158 "(c) Rich Geldreich, Tenacious Software, RAD Game Tools, Valve Software.\n\n"
159 "The LoadDskF module uses public domain code from the dskdcmps utility, by an\n"
160 "unknown author.\n\n"
161 "The X-Face decoder uses code from Compface, Copyright (c) 1990 James Ashton.\n");
164 static void print_modules(deark
*c
)
166 de_print_module_list(c
);
169 static void initialize_output_stream(struct cmdctx
*cc
)
172 int ansi_is_enabled
= 0;
175 if(cc
->msgs_to_stderr
) {
176 cc
->msgs_FILE
= stderr
;
179 cc
->msgs_FILE
= stdout
;
182 cc
->color_method
= CM_NOCOLOR
; // start with default
185 de_winconsole_init_handle(cc
->plctx
, cc
->msgs_to_stderr
? 2 : 1);
186 cc
->have_windows_console
= de_winconsole_is_console(cc
->plctx
);
188 // If appropriate, call _setmode so that Unicode output to the console
189 // works correctly (provided we use Unicode functions like fputws()).
190 if(cc
->have_windows_console
&& !cc
->to_ascii
&& !cc
->to_oem
) {
192 (void)_setmode(_fileno(cc
->msgs_FILE
), _O_U16TEXT
);
195 if(!cc
->have_windows_console
&& !cc
->to_ascii
&& !cc
->to_oem
&& !cc
->no_chcp
) {
196 // There are some situations in which it helps to declare the code page
197 // that our output uses.
198 de_winconsole_set_UTF8_CP(cc
->plctx
);
201 switch(cc
->color_method_req
) {
203 if(cc
->have_windows_console
) {
204 if(de_winconsole_try_enable_ansi24(cc
->plctx
)) {
205 cc
->color_method
= CM_ANSI24
;
209 cc
->color_method
= CM_WINCONSOLE
;
213 cc
->color_method
= CM_ANSI24
;
217 if(cc
->have_windows_console
) {
218 cc
->color_method
= CM_WINCONSOLE
;
222 cc
->color_method
= CM_ANSI
;
225 cc
->color_method
= CM_ANSI24
;
228 ; // leave at CM_NOCOLOR
231 if(cc
->color_method
==CM_WINCONSOLE
) {
232 de_winconsole_record_current_attributes(cc
->plctx
);
235 if((cc
->color_method
==CM_ANSI
|| cc
->color_method
==CM_ANSI24
) && !ansi_is_enabled
) {
236 de_winconsole_enable_ansi(cc
->plctx
);
240 switch(cc
->color_method_req
) {
243 cc
->color_method
= CM_NOCOLOR
;
246 cc
->color_method
= CM_ANSI
;
249 cc
->color_method
= CM_ANSI24
;
253 if(cc
->color_method
==CM_ANSI
|| cc
->color_method
==CM_ANSI24
) {
254 // If using ANSI codes, start by resetting all attributes
255 emit_sz(cc
, "\x1b[0m");
258 cc
->have_initialized_output_stream
= 1;
261 static void our_specialmsgfn(deark
*c
, unsigned int flags
, unsigned int code
,
266 cc
= de_get_userdata(c
);
267 if(cc
->color_method
==CM_NOCOLOR
) return;
269 if(!cc
->have_initialized_output_stream
) {
270 initialize_output_stream(cc
);
274 if(cc
->color_method
==CM_WINCONSOLE
) {
275 if(code
==DE_MSGCODE_HL
) {
276 de_winconsole_highlight(cc
->plctx
, 1);
278 else if(code
==DE_MSGCODE_UNHL
) {
279 de_winconsole_highlight(cc
->plctx
, 0);
281 else if(code
==DE_MSGCODE_RGBSAMPLE
) {
282 // There's no way to get 24-bit color using Windows console
283 // commands. Have to use ANSI24 instead.
290 // TODO: Maybe move the DE_COLOR_* macros to deark.h.
291 #define X_DE_COLOR_R(x) (unsigned int)(((x)>>16)&0xff)
292 #define X_DE_COLOR_G(x) (unsigned int)(((x)>>8)&0xff)
293 #define X_DE_COLOR_B(x) (unsigned int)((x)&0xff)
294 if(code
==DE_MSGCODE_HL
) {
295 emit_sz(cc
, "\x1b[7m");
297 else if(code
==DE_MSGCODE_UNHL
) {
298 emit_sz(cc
, "\x1b[27m");
300 else if(code
==DE_MSGCODE_RGBSAMPLE
&& cc
->color_method
==CM_ANSI24
) {
303 de_snprintf(buf
, sizeof(buf
), "\x1b[48;2;%u;%u;%um \x1b[0m",
304 X_DE_COLOR_R(param1
), X_DE_COLOR_G(param1
), X_DE_COLOR_B(param1
));
309 static void our_msgfn(deark
*c
, unsigned int flags
, const char *s1
)
314 cc
= de_get_userdata(c
);
316 if(!cc
->have_initialized_output_stream
) {
317 initialize_output_stream(cc
);
321 // Note - It doesn't seem quite right to have this functionality be separate
322 // from the library's *to_printable* functions, but they don't quite have
323 // the same purposes, and it would be tricky to combine them.
324 // This is really just a quick and dirty way to deal with systems that don't
325 // support Unicode, or don't support the Unicode characters we use.
327 // TODO: It's inconsistent that the de_utf8_to_ascii() and de_utf8_to_oem()
328 // code paths have a size limit, while the de_utf8_to_utf16_to_FILE() and
329 // fputs() paths do not.
330 de_utf8_to_ascii(s1
, cc
->msgbuf
, sizeof(cc
->msgbuf
), 0);
334 else if(cc
->to_oem
) {
335 de_utf8_to_oem(c
, s1
, cc
->msgbuf
, sizeof(cc
->msgbuf
));
346 static void our_fatalerrorfn(deark
*c
)
348 de_puts(c
, DE_MSGTYPE_MESSAGE
, "Exiting\n");
352 static void set_ext_option(deark
*c
, struct cmdctx
*cc
, const char *optionstring
)
357 tmp
= de_strdup(c
, optionstring
);
360 eqpos
= strchr(tmp
, '=');
363 de_set_ext_option(c
, tmp
, eqpos
+1);
367 de_set_ext_option(c
, tmp
, "");
372 static void set_encoding_option(deark
*c
, struct cmdctx
*cc
, const char *s
)
374 if(!strcmp(s
, "ascii")) {
377 else if(!strcmp(s
, "oem")) {
380 else if(!strcmp(s
, "utf8") || !strcmp(s
, "unicode")) {
385 de_puts(c
, DE_MSGTYPE_MESSAGE
, "Error: Unknown encoding\n");
391 DE_OPT_NULL
=0, DE_OPT_D
, DE_OPT_D2
, DE_OPT_D3
, DE_OPT_D4
, DE_OPT_L
,
392 DE_OPT_NOINFO
, DE_OPT_NOWARN
,
393 DE_OPT_NOBOM
, DE_OPT_NODENS
, DE_OPT_ASCIIHTML
, DE_OPT_NONAMES
,
395 DE_OPT_NOOVERWRITE
, DE_OPT_MODTIME
, DE_OPT_NOMODTIME
,
396 DE_OPT_Q
, DE_OPT_VERSION
, DE_OPT_HELP
, DE_OPT_LICENSE
, DE_OPT_ID
,
397 DE_OPT_MAINONLY
, DE_OPT_AUXONLY
, DE_OPT_EXTRACTALL
, DE_OPT_ZIP
, DE_OPT_TAR
,
398 DE_OPT_TOSTDOUT
, DE_OPT_MSGSTOSTDERR
, DE_OPT_FROMSTDIN
, DE_OPT_COLOR
,
399 DE_OPT_NOCHCP
, DE_OPT_ENCODING
,
400 DE_OPT_EXTOPT
, DE_OPT_FILE
, DE_OPT_FILE2
, DE_OPT_INENC
, DE_OPT_INTZ
,
401 DE_OPT_START
, DE_OPT_SIZE
, DE_OPT_M
, DE_OPT_MODCODES
, DE_OPT_O
, DE_OPT_OD
,
402 DE_OPT_K
, DE_OPT_K2
, DE_OPT_K3
, DE_OPT_KA
, DE_OPT_KA2
, DE_OPT_KA3
,
403 DE_OPT_T
, DE_OPT_ARCFN
, DE_OPT_GET
, DE_OPT_FIRSTFILE
, DE_OPT_MAXFILES
,
404 DE_OPT_MAXFILESIZE
, DE_OPT_MAXTOTALSIZE
, DE_OPT_MAXIMGDIM
,
405 DE_OPT_PRINTMODULES
, DE_OPT_DPREFIX
, DE_OPT_EXTRLIST
,
406 DE_OPT_ONLYMODS
, DE_OPT_DISABLEMODS
, DE_OPT_ONLYDETECT
, DE_OPT_NODETECT
,
416 struct opt_struct option_array
[] = {
417 { "d", DE_OPT_D
, 0 },
418 { "d2", DE_OPT_D2
, 0 },
419 { "d3", DE_OPT_D3
, 0 },
420 { "d4", DE_OPT_D4
, 0 },
421 { "l", DE_OPT_L
, 0 },
422 { "noinfo", DE_OPT_NOINFO
, 0 },
423 { "nowarn", DE_OPT_NOWARN
, 0 },
424 { "nobom", DE_OPT_NOBOM
, 0 },
425 { "nodens", DE_OPT_NODENS
, 0 },
426 { "asciihtml", DE_OPT_ASCIIHTML
, 0 },
427 { "nonames", DE_OPT_NONAMES
, 0 },
428 { "n", DE_OPT_NOOVERWRITE
, 0 },
429 { "modtime", DE_OPT_MODTIME
, 0 },
430 { "nomodtime", DE_OPT_NOMODTIME
, 0 },
431 { "padpix", DE_OPT_PADPIX
, 0 },
432 { "q", DE_OPT_Q
, 0 },
433 { "version", DE_OPT_VERSION
, 0 },
434 { "h", DE_OPT_HELP
, 0 },
435 { "help", DE_OPT_HELP
, 0 },
436 { "?", DE_OPT_HELP
, 0 },
437 { "modules", DE_OPT_PRINTMODULES
, 0 },
438 { "main", DE_OPT_MAINONLY
, 0 },
439 { "aux", DE_OPT_AUXONLY
, 0 },
440 { "a", DE_OPT_EXTRACTALL
, 0 },
441 { "extractall", DE_OPT_EXTRACTALL
, 0 },
442 { "zip", DE_OPT_ZIP
, 0 },
443 { "tar", DE_OPT_TAR
, 0 },
444 { "tostdout", DE_OPT_TOSTDOUT
, 0 },
445 { "msgstostderr", DE_OPT_MSGSTOSTDERR
, 0 },
446 { "fromstdin", DE_OPT_FROMSTDIN
, 0 },
447 { "color", DE_OPT_COLOR
, 0 },
448 { "k", DE_OPT_K
, 0 },
449 { "k2", DE_OPT_K2
, 0 },
450 { "k3", DE_OPT_K3
, 0 },
451 { "ka", DE_OPT_KA
, 0 },
452 { "ka2", DE_OPT_KA2
, 0 },
453 { "ka3", DE_OPT_KA3
, 0 },
454 { "license", DE_OPT_LICENSE
, 0 },
455 { "id", DE_OPT_ID
, 0 },
456 { "nochcp", DE_OPT_NOCHCP
, 0 },
457 { "enc", DE_OPT_ENCODING
, 1 },
458 { "opt", DE_OPT_EXTOPT
, 1 },
459 { "file", DE_OPT_FILE
, 1 },
460 { "file2", DE_OPT_FILE2
, 1 },
461 { "inenc", DE_OPT_INENC
, 1 },
462 { "intz", DE_OPT_INTZ
, 1 },
463 { "start", DE_OPT_START
, 1 },
464 { "size", DE_OPT_SIZE
, 1 },
465 { "m", DE_OPT_M
, 1 },
466 { "modcodes", DE_OPT_MODCODES
, 1 },
467 { "o", DE_OPT_O
, 1 },
468 { "basefn", DE_OPT_O
, 1 }, // Deprecated
469 { "od", DE_OPT_OD
, 1 },
470 { "t", DE_OPT_T
, 1 },
471 { "ta", DE_OPT_ARCFN
, 1 },
472 { "arcfn", DE_OPT_ARCFN
, 1 },
473 { "get", DE_OPT_GET
, 1 },
474 { "firstfile", DE_OPT_FIRSTFILE
, 1 },
475 { "maxfiles", DE_OPT_MAXFILES
, 1 },
476 { "maxfilesize", DE_OPT_MAXFILESIZE
, 1 },
477 { "maxtotalsize", DE_OPT_MAXTOTALSIZE
, 1 },
478 { "maxdim", DE_OPT_MAXIMGDIM
, 1 },
479 { "dprefix", DE_OPT_DPREFIX
, 1 },
480 { "extrlist", DE_OPT_EXTRLIST
, 1 },
481 { "onlymods", DE_OPT_ONLYMODS
, 1 },
482 { "disablemods", DE_OPT_DISABLEMODS
, 1 },
483 { "onlydetect", DE_OPT_ONLYDETECT
, 1 },
484 { "nodetect", DE_OPT_NODETECT
, 1 },
485 { "colormode", DE_OPT_COLORMODE
, 1 },
486 { NULL
, DE_OPT_NULL
, 0 }
489 static struct opt_struct
*opt_string_to_opt_struct(const char *s
)
493 for(k
=0; option_array
[k
].id
!=DE_OPT_NULL
; k
++) {
494 if(!strcmp(s
, option_array
[k
].string
)) {
495 return &option_array
[k
];
501 static void send_msgs_to_stderr(deark
*c
, struct cmdctx
*cc
)
503 cc
->msgs_to_stderr
= 1;
504 cc
->have_initialized_output_stream
= 0;
505 cc
->msgs_FILE
= NULL
;
507 cc
->have_windows_console
= 0;
511 static void colormode_opt(struct cmdctx
*cc
, const char *modestr
)
513 if(!strcmp(modestr
, "auto")) {
514 cc
->color_method_req
= CM_AUTOCOLOR
;
516 else if(!strcmp(modestr
, "ansi")) {
517 cc
->color_method_req
= CM_ANSI
;
519 else if(!strcmp(modestr
, "ansi24")) {
520 cc
->color_method_req
= CM_ANSI24
;
522 else if(!strcmp(modestr
, "winconsole")) {
523 cc
->color_method_req
= CM_WINCONSOLE
;
525 else if(!strcmp(modestr
, "none")) {
526 cc
->color_method_req
= CM_NOCOLOR
;
529 de_printf(cc
->c
, DE_MSGTYPE_MESSAGE
, "Invalid colormode: %s\n", modestr
);
535 static void set_output_basename(struct cmdctx
*cc
)
537 const char *outputbasefn
= cc
->base_output_filename
; // default, could be NULL
538 const char *outdirname
;
539 unsigned int flags
= 0;
541 if(cc
->option_k_level
&& cc
->input_filename
) {
542 if(cc
->option_k_level
==1) {
543 // Use base input filename in output filenames.
544 outputbasefn
= cc
->input_filename
;
547 else if(cc
->option_k_level
==2) {
548 // Use full input filename path, but not as an actual path.
549 outputbasefn
= cc
->input_filename
;
552 else if(cc
->option_k_level
==3) {
553 // Use full input filename path, as-is.
554 outputbasefn
= cc
->input_filename
;
558 if(cc
->to_zip
|| cc
->to_tar
) {
559 // In this case, -od refers to the archive filename, not to the base
560 // filename that we're dealing with here.
563 else if(cc
->to_stdout
) {
564 // -od is incompatible with -tostdout
568 outdirname
= cc
->output_dirname
;
571 de_set_output_filename_pattern(cc
->c
, outdirname
, outputbasefn
, flags
);
574 static void set_output_archive_name(struct cmdctx
*cc
)
576 const char *arcfn
= cc
->archive_filename
; // default, could be NULL
577 unsigned int flags
= 0;
579 if(!cc
->to_zip
&& !cc
->to_tar
) return;
580 if(cc
->to_stdout
) return;
582 if(cc
->option_ka_level
&& cc
->input_filename
)
584 if(cc
->option_ka_level
==1) {
585 // Use base input filename in output filenames.
586 arcfn
= cc
->input_filename
;
589 else if(cc
->option_ka_level
==2) {
590 // Use full input filename path, but not as an actual path.
591 arcfn
= cc
->input_filename
;
594 else if(cc
->option_ka_level
==3) {
595 // Use full input filename path, as-is.
596 arcfn
= cc
->input_filename
;
606 de_set_output_archive_filename(cc
->c
, cc
->output_dirname
, arcfn
, flags
);
609 static void handle_special_1st_filename(struct cmdctx
*cc
)
611 if(!cc
->output_special_1st_filename
) return;
612 de_set_output_special_1st_filename(cc
->c
,
613 ((cc
->to_zip
|| cc
->to_tar
|| cc
->to_stdout
) ? NULL
: cc
->output_dirname
),
614 cc
->output_special_1st_filename
);
615 if(!cc
->set_MAXFILES
) {
616 de_set_max_output_files(cc
->c
, 1);
620 static void parse_cmdline(deark
*c
, struct cmdctx
*cc
, int argc
, char **argv
)
625 const struct opt_struct
*opt
;
627 for(i
=1;i
<argc
;i
++) {
628 if(argv
[i
][0]=='-') {
629 if(argv
[i
][1]=='-') // Allow a superfluous second '-'
630 opt
= opt_string_to_opt_struct(argv
[i
]+2);
632 opt
= opt_string_to_opt_struct(argv
[i
]+1);
635 de_printf(c
, DE_MSGTYPE_MESSAGE
, "Unrecognized option: %s\n", argv
[i
]);
636 if(!strcmp(argv
[i
], "-")) {
637 // I don't want "-" to be an alias for "-fromstdin", because it
638 // would have different syntax rules than it does in most programs.
639 // (Question: Is "-" an *option*, or a kind of *filename*?)
640 de_printf(c
, DE_MSGTYPE_MESSAGE
,
641 "Note: To use stdin/stdout, use \"-fromstdin\"/\"-tostdout\".\n");
644 cc
->show_usage_message
= 1;
647 if(i
>=argc
-opt
->extra_args
) {
648 de_printf(c
, DE_MSGTYPE_MESSAGE
, "Option %s needs an argument\n", argv
[i
]);
650 cc
->show_usage_message
= 1;
656 de_set_std_option_int(c
, DE_STDOPT_DEBUG_LEVEL
, 1);
659 de_set_std_option_int(c
, DE_STDOPT_DEBUG_LEVEL
, 2);
662 de_set_std_option_int(c
, DE_STDOPT_DEBUG_LEVEL
, 3);
665 de_set_std_option_int(c
, DE_STDOPT_DEBUG_LEVEL
, 4);
668 de_set_std_option_int(c
, DE_STDOPT_LISTMODE
, 1);
671 de_set_std_option_int(c
, DE_STDOPT_INFOMESSAGES
, 0);
674 de_set_std_option_int(c
, DE_STDOPT_WARNINGS
, 0);
677 de_set_std_option_int(c
, DE_STDOPT_WRITE_BOM
, 0);
680 de_set_std_option_int(c
, DE_STDOPT_WRITE_DENSITY
, 0);
682 case DE_OPT_ASCIIHTML
:
683 de_set_std_option_int(c
, DE_STDOPT_ASCII_HTML
, 1);
686 de_set_std_option_int(c
, DE_STDOPT_FILENAMES_FROM_FILE
, 0);
689 de_set_std_option_int(c
, DE_STDOPT_PADPIX
, 1);
691 case DE_OPT_NOOVERWRITE
:
692 de_set_std_option_int(c
, DE_STDOPT_OVERWRITE_MODE
, DE_OVERWRITEMODE_NEVER
);
695 de_set_preserve_file_times(c
, 0, 1);
696 de_set_preserve_file_times(c
, 1, 1);
698 case DE_OPT_NOMODTIME
:
699 de_set_preserve_file_times(c
, 0, 0);
700 de_set_preserve_file_times(c
, 1, 0);
703 de_set_std_option_int(c
, DE_STDOPT_INFOMESSAGES
, 0);
704 de_set_std_option_int(c
, DE_STDOPT_WARNINGS
, 0);
707 cc
->special_command_flag
= 1;
708 cc
->special_command_code
= CMD_PRINTVERSION
;
710 case DE_OPT_PRINTMODULES
:
711 cc
->special_command_flag
= 1;
712 cc
->special_command_code
= CMD_PRINTMODULES
;
715 // At this point, we don't know whether this will be general help,
716 // or module-specific help. So just set a flag for later.
720 cc
->special_command_flag
= 1;
721 cc
->special_command_code
= CMD_PRINTLICENSE
;
724 de_set_std_option_int(c
, DE_STDOPT_ID_MODE
, 1);
729 case DE_OPT_MAINONLY
:
730 de_set_std_option_int(c
, DE_STDOPT_EXTRACT_POLICY
, DE_EXTRACTPOLICY_MAINONLY
);
733 de_set_std_option_int(c
, DE_STDOPT_EXTRACT_POLICY
, DE_EXTRACTPOLICY_AUXONLY
);
735 case DE_OPT_EXTRACTALL
:
736 de_set_std_option_int(c
, DE_STDOPT_EXTRACT_LEVEL
, 2);
739 de_set_output_style(c
, DE_OUTPUTSTYLE_ARCHIVE
, DE_ARCHIVEFMT_ZIP
);
743 de_set_output_style(c
, DE_OUTPUTSTYLE_ARCHIVE
, DE_ARCHIVEFMT_TAR
);
746 case DE_OPT_TOSTDOUT
:
747 send_msgs_to_stderr(c
, cc
);
750 case DE_OPT_MSGSTOSTDERR
:
751 send_msgs_to_stderr(c
, cc
);
753 case DE_OPT_FROMSTDIN
:
754 de_set_input_style(c
, DE_INPUTSTYLE_STDIN
);
758 colormode_opt(cc
, "auto");
761 cc
->option_k_level
= 1;
764 cc
->option_k_level
= 2;
767 cc
->option_k_level
= 3;
770 cc
->option_ka_level
= 1;
773 cc
->option_ka_level
= 2;
776 cc
->option_ka_level
= 3;
778 case DE_OPT_ENCODING
:
779 set_encoding_option(c
, cc
, argv
[i
+1]);
780 if(cc
->error_flag
) return;
783 set_ext_option(c
, cc
, argv
[i
+1]);
786 cc
->input_filename
= argv
[i
+1];
787 de_set_input_filename(c
, cc
->input_filename
);
790 de_set_ext_option(c
, "file2", argv
[i
+1]);
793 if(!de_set_input_encoding(c
, argv
[i
+1], 0)) {
794 de_printf(c
, DE_MSGTYPE_MESSAGE
,
795 "Error: Unknown input encoding: %s\n", argv
[i
+1]);
801 de_set_input_timezone(c
, (i64
)(3600.0*atof(argv
[i
+1])));
804 de_set_input_file_slice_start(c
, de_atoi64(argv
[i
+1]));
807 de_set_input_file_slice_size(c
, de_atoi64(argv
[i
+1]));
811 de_set_input_format(c
, argv
[i
+1]);
813 case DE_OPT_MODCODES
:
814 de_set_module_init_codes(c
, argv
[i
+1]);
817 cc
->base_output_filename
= argv
[i
+1];
820 cc
->output_dirname
= argv
[i
+1];
823 cc
->output_special_1st_filename
= argv
[i
+1];
826 // Relevant e.g. if the -zip option is used.
827 cc
->archive_filename
= argv
[i
+1];
830 de_set_first_output_file(c
, de_atoi(argv
[i
+1]));
831 de_set_max_output_files(c
, 1);
833 case DE_OPT_FIRSTFILE
:
834 de_set_first_output_file(c
, de_atoi(argv
[i
+1]));
836 case DE_OPT_MAXFILES
:
837 de_set_max_output_files(c
, de_atoi64(argv
[i
+1]));
838 cc
->set_MAXFILES
= 1;
840 case DE_OPT_MAXFILESIZE
:
841 de_set_max_output_file_size(c
, de_atoi64(argv
[i
+1]));
843 case DE_OPT_MAXTOTALSIZE
:
844 de_set_max_total_output_size(c
, de_atoi64(argv
[i
+1]));
846 case DE_OPT_MAXIMGDIM
:
847 de_set_max_image_dimension(c
, de_atoi64(argv
[i
+1]));
850 de_set_dprefix(c
, argv
[i
+1]);
852 case DE_OPT_EXTRLIST
:
853 de_set_extrlist_filename(c
, argv
[i
+1]);
855 case DE_OPT_ONLYMODS
:
856 de_set_disable_mods(c
, argv
[i
+1], 1);
858 case DE_OPT_DISABLEMODS
:
859 de_set_disable_mods(c
, argv
[i
+1], 0);
861 case DE_OPT_ONLYDETECT
:
862 de_set_disable_moddetect(c
, argv
[i
+1], 1);
864 case DE_OPT_NODETECT
:
865 de_set_disable_moddetect(c
, argv
[i
+1], 0);
867 case DE_OPT_COLORMODE
:
868 colormode_opt(cc
, argv
[i
+1]);
869 if(cc
->error_flag
) return;
872 de_printf(c
, DE_MSGTYPE_MESSAGE
, "Unrecognized option: %s\n", argv
[i
]);
874 cc
->show_usage_message
= 1;
878 i
+= opt
->extra_args
;
881 if(cc
->input_filename
) {
883 cc
->show_usage_message
= 1;
886 cc
->input_filename
= argv
[i
];
887 de_set_input_filename(c
, cc
->input_filename
);
892 if(module_flag
|| cc
->input_filename
|| cc
->from_stdin
) {
893 de_set_std_option_int(c
, DE_STDOPT_WANT_MODHELP
, 1);
896 cc
->special_command_flag
= 1;
897 cc
->special_command_code
= CMD_PRINTHELP
;
902 if(!cc
->input_filename
&& !cc
->special_command_flag
&& !cc
->from_stdin
) {
903 de_puts(c
, DE_MSGTYPE_MESSAGE
, "Error: Need an input filename\n");
905 cc
->show_usage_message
= 1;
910 if(cc
->to_zip
|| cc
->to_tar
) {
911 de_set_output_archive_filename(c
, NULL
, NULL
, 0x10);
914 de_set_output_style(c
, DE_OUTPUTSTYLE_STDOUT
, 0);
915 if(!cc
->set_MAXFILES
) {
916 de_set_max_output_files(c
, 1);
921 set_output_basename(cc
);
922 set_output_archive_name(cc
);
923 handle_special_1st_filename(cc
);
926 static int main2(int argc
, char **argv
)
929 struct cmdctx
*cc
= NULL
;
933 cc
= de_malloc(NULL
, sizeof(struct cmdctx
));
937 de_set_userdata(c
, (void*)cc
);
938 de_set_fatalerror_callback(c
, our_fatalerrorfn
);
939 de_set_messages_callback(c
, our_msgfn
);
940 de_set_special_messages_callback(c
, our_specialmsgfn
);
941 cc
->plctx
= de_platformdata_create();
943 if(argc
<2) { // Empty command line
948 parse_cmdline(c
, cc
, argc
, argv
);
951 if(cc
->show_usage_message
) {
952 print_usage_error(c
);
957 if(cc
->special_command_flag
) {
958 switch(cc
->special_command_code
) {
962 case CMD_PRINTVERSION
:
965 case CMD_PRINTLICENSE
:
968 case CMD_PRINTMODULES
:
979 (void)_setmode(_fileno(stdout
), _O_BINARY
);
982 (void)_setmode(_fileno(stdin
), _O_BINARY
);
993 de_platformdata_destroy(cc
->plctx
);
995 if(cc
->error_flag
) exit_status
= 1;
1002 // This prototype is to silence a possible -Wmissing-prototypes warning.
1003 int wmain(int argc
, wchar_t **argvW
);
1005 int wmain(int argc
, wchar_t **argvW
)
1010 argv
= de_convert_args_to_utf8(argc
, argvW
);
1011 exit_status
= main2(argc
, argv
);
1012 de_free_utf8_args(argc
, argv
);
1018 int main(int argc
, char **argv
)
1020 return main2(argc
, argv
);