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 X-Face decoder uses code from Compface, Copyright (c) 1990 James Ashton.\n");
162 static void print_modules(deark
*c
)
164 de_print_module_list(c
);
167 static void initialize_output_stream(struct cmdctx
*cc
)
170 int ansi_is_enabled
= 0;
173 if(cc
->msgs_to_stderr
) {
174 cc
->msgs_FILE
= stderr
;
177 cc
->msgs_FILE
= stdout
;
180 cc
->color_method
= CM_NOCOLOR
; // start with default
183 de_winconsole_init_handle(cc
->plctx
, cc
->msgs_to_stderr
? 2 : 1);
184 cc
->have_windows_console
= de_winconsole_is_console(cc
->plctx
);
186 // If appropriate, call _setmode so that Unicode output to the console
187 // works correctly (provided we use Unicode functions like fputws()).
188 if(cc
->have_windows_console
&& !cc
->to_ascii
&& !cc
->to_oem
) {
190 (void)_setmode(_fileno(cc
->msgs_FILE
), _O_U16TEXT
);
193 if(!cc
->have_windows_console
&& !cc
->to_ascii
&& !cc
->to_oem
&& !cc
->no_chcp
) {
194 // There are some situations in which it helps to declare the code page
195 // that our output uses.
196 de_winconsole_set_UTF8_CP(cc
->plctx
);
199 switch(cc
->color_method_req
) {
201 if(cc
->have_windows_console
) {
202 if(de_winconsole_try_enable_ansi24(cc
->plctx
)) {
203 cc
->color_method
= CM_ANSI24
;
207 cc
->color_method
= CM_WINCONSOLE
;
211 cc
->color_method
= CM_ANSI24
;
215 if(cc
->have_windows_console
) {
216 cc
->color_method
= CM_WINCONSOLE
;
220 cc
->color_method
= CM_ANSI
;
223 cc
->color_method
= CM_ANSI24
;
226 ; // leave at CM_NOCOLOR
229 if(cc
->color_method
==CM_WINCONSOLE
) {
230 de_winconsole_record_current_attributes(cc
->plctx
);
233 if((cc
->color_method
==CM_ANSI
|| cc
->color_method
==CM_ANSI24
) && !ansi_is_enabled
) {
234 de_winconsole_enable_ansi(cc
->plctx
);
238 switch(cc
->color_method_req
) {
241 cc
->color_method
= CM_NOCOLOR
;
244 cc
->color_method
= CM_ANSI
;
247 cc
->color_method
= CM_ANSI24
;
251 if(cc
->color_method
==CM_ANSI
|| cc
->color_method
==CM_ANSI24
) {
252 // If using ANSI codes, start by resetting all attributes
253 emit_sz(cc
, "\x1b[0m");
256 cc
->have_initialized_output_stream
= 1;
259 static void our_specialmsgfn(deark
*c
, unsigned int flags
, unsigned int code
,
264 cc
= de_get_userdata(c
);
265 if(cc
->color_method
==CM_NOCOLOR
) return;
267 if(!cc
->have_initialized_output_stream
) {
268 initialize_output_stream(cc
);
272 if(cc
->color_method
==CM_WINCONSOLE
) {
273 if(code
==DE_MSGCODE_HL
) {
274 de_winconsole_highlight(cc
->plctx
, 1);
276 else if(code
==DE_MSGCODE_UNHL
) {
277 de_winconsole_highlight(cc
->plctx
, 0);
279 else if(code
==DE_MSGCODE_RGBSAMPLE
) {
280 // There's no way to get 24-bit color using Windows console
281 // commands. Have to use ANSI24 instead.
288 // TODO: Maybe move the DE_COLOR_* macros to deark.h.
289 #define X_DE_COLOR_R(x) (unsigned int)(((x)>>16)&0xff)
290 #define X_DE_COLOR_G(x) (unsigned int)(((x)>>8)&0xff)
291 #define X_DE_COLOR_B(x) (unsigned int)((x)&0xff)
292 if(code
==DE_MSGCODE_HL
) {
293 emit_sz(cc
, "\x1b[7m");
295 else if(code
==DE_MSGCODE_UNHL
) {
296 emit_sz(cc
, "\x1b[27m");
298 else if(code
==DE_MSGCODE_RGBSAMPLE
&& cc
->color_method
==CM_ANSI24
) {
301 de_snprintf(buf
, sizeof(buf
), "\x1b[48;2;%u;%u;%um \x1b[0m",
302 X_DE_COLOR_R(param1
), X_DE_COLOR_G(param1
), X_DE_COLOR_B(param1
));
307 static void our_msgfn(deark
*c
, unsigned int flags
, const char *s1
)
312 cc
= de_get_userdata(c
);
314 if(!cc
->have_initialized_output_stream
) {
315 initialize_output_stream(cc
);
319 // Note - It doesn't seem quite right to have this functionality be separate
320 // from the library's *to_printable* functions, but they don't quite have
321 // the same purposes, and it would be tricky to combine them.
322 // This is really just a quick and dirty way to deal with systems that don't
323 // support Unicode, or don't support the Unicode characters we use.
325 // TODO: It's inconsistent that the de_utf8_to_ascii() and de_utf8_to_oem()
326 // code paths have a size limit, while the de_utf8_to_utf16_to_FILE() and
327 // fputs() paths do not.
328 de_utf8_to_ascii(s1
, cc
->msgbuf
, sizeof(cc
->msgbuf
), 0);
332 else if(cc
->to_oem
) {
333 de_utf8_to_oem(c
, s1
, cc
->msgbuf
, sizeof(cc
->msgbuf
));
344 static void our_fatalerrorfn(deark
*c
)
346 de_puts(c
, DE_MSGTYPE_MESSAGE
, "Exiting\n");
350 static void set_ext_option(deark
*c
, struct cmdctx
*cc
, const char *optionstring
)
355 tmp
= de_strdup(c
, optionstring
);
358 eqpos
= strchr(tmp
, '=');
361 de_set_ext_option(c
, tmp
, eqpos
+1);
365 de_set_ext_option(c
, tmp
, "");
370 static void set_encoding_option(deark
*c
, struct cmdctx
*cc
, const char *s
)
372 if(!strcmp(s
, "ascii")) {
375 else if(!strcmp(s
, "oem")) {
378 else if(!strcmp(s
, "utf8") || !strcmp(s
, "unicode")) {
383 de_puts(c
, DE_MSGTYPE_MESSAGE
, "Error: Unknown encoding\n");
389 DE_OPT_NULL
=0, DE_OPT_D
, DE_OPT_D2
, DE_OPT_D3
, DE_OPT_D4
, DE_OPT_L
,
390 DE_OPT_NOINFO
, DE_OPT_NOWARN
,
391 DE_OPT_NOBOM
, DE_OPT_NODENS
, DE_OPT_ASCIIHTML
, DE_OPT_NONAMES
,
393 DE_OPT_NOOVERWRITE
, DE_OPT_MODTIME
, DE_OPT_NOMODTIME
,
394 DE_OPT_Q
, DE_OPT_VERSION
, DE_OPT_HELP
, DE_OPT_LICENSE
, DE_OPT_ID
,
395 DE_OPT_MAINONLY
, DE_OPT_AUXONLY
, DE_OPT_EXTRACTALL
, DE_OPT_ZIP
, DE_OPT_TAR
,
396 DE_OPT_TOSTDOUT
, DE_OPT_MSGSTOSTDERR
, DE_OPT_FROMSTDIN
, DE_OPT_COLOR
,
397 DE_OPT_NOCHCP
, DE_OPT_ENCODING
,
398 DE_OPT_EXTOPT
, DE_OPT_FILE
, DE_OPT_FILE2
, DE_OPT_INENC
, DE_OPT_INTZ
,
399 DE_OPT_START
, DE_OPT_SIZE
, DE_OPT_M
, DE_OPT_MODCODES
, DE_OPT_O
, DE_OPT_OD
,
400 DE_OPT_K
, DE_OPT_K2
, DE_OPT_K3
, DE_OPT_KA
, DE_OPT_KA2
, DE_OPT_KA3
,
401 DE_OPT_T
, DE_OPT_ARCFN
, DE_OPT_GET
, DE_OPT_FIRSTFILE
, DE_OPT_MAXFILES
,
402 DE_OPT_MAXFILESIZE
, DE_OPT_MAXTOTALSIZE
, DE_OPT_MAXIMGDIM
,
403 DE_OPT_PRINTMODULES
, DE_OPT_DPREFIX
, DE_OPT_EXTRLIST
,
404 DE_OPT_ONLYMODS
, DE_OPT_DISABLEMODS
, DE_OPT_ONLYDETECT
, DE_OPT_NODETECT
,
414 struct opt_struct option_array
[] = {
415 { "d", DE_OPT_D
, 0 },
416 { "d2", DE_OPT_D2
, 0 },
417 { "d3", DE_OPT_D3
, 0 },
418 { "d4", DE_OPT_D4
, 0 },
419 { "l", DE_OPT_L
, 0 },
420 { "noinfo", DE_OPT_NOINFO
, 0 },
421 { "nowarn", DE_OPT_NOWARN
, 0 },
422 { "nobom", DE_OPT_NOBOM
, 0 },
423 { "nodens", DE_OPT_NODENS
, 0 },
424 { "asciihtml", DE_OPT_ASCIIHTML
, 0 },
425 { "nonames", DE_OPT_NONAMES
, 0 },
426 { "n", DE_OPT_NOOVERWRITE
, 0 },
427 { "modtime", DE_OPT_MODTIME
, 0 },
428 { "nomodtime", DE_OPT_NOMODTIME
, 0 },
429 { "padpix", DE_OPT_PADPIX
, 0 },
430 { "q", DE_OPT_Q
, 0 },
431 { "version", DE_OPT_VERSION
, 0 },
432 { "h", DE_OPT_HELP
, 0 },
433 { "help", DE_OPT_HELP
, 0 },
434 { "?", DE_OPT_HELP
, 0 },
435 { "modules", DE_OPT_PRINTMODULES
, 0 },
436 { "main", DE_OPT_MAINONLY
, 0 },
437 { "aux", DE_OPT_AUXONLY
, 0 },
438 { "a", DE_OPT_EXTRACTALL
, 0 },
439 { "extractall", DE_OPT_EXTRACTALL
, 0 },
440 { "zip", DE_OPT_ZIP
, 0 },
441 { "tar", DE_OPT_TAR
, 0 },
442 { "tostdout", DE_OPT_TOSTDOUT
, 0 },
443 { "msgstostderr", DE_OPT_MSGSTOSTDERR
, 0 },
444 { "fromstdin", DE_OPT_FROMSTDIN
, 0 },
445 { "color", DE_OPT_COLOR
, 0 },
446 { "k", DE_OPT_K
, 0 },
447 { "k2", DE_OPT_K2
, 0 },
448 { "k3", DE_OPT_K3
, 0 },
449 { "ka", DE_OPT_KA
, 0 },
450 { "ka2", DE_OPT_KA2
, 0 },
451 { "ka3", DE_OPT_KA3
, 0 },
452 { "license", DE_OPT_LICENSE
, 0 },
453 { "id", DE_OPT_ID
, 0 },
454 { "nochcp", DE_OPT_NOCHCP
, 0 },
455 { "enc", DE_OPT_ENCODING
, 1 },
456 { "opt", DE_OPT_EXTOPT
, 1 },
457 { "file", DE_OPT_FILE
, 1 },
458 { "file2", DE_OPT_FILE2
, 1 },
459 { "inenc", DE_OPT_INENC
, 1 },
460 { "intz", DE_OPT_INTZ
, 1 },
461 { "start", DE_OPT_START
, 1 },
462 { "size", DE_OPT_SIZE
, 1 },
463 { "m", DE_OPT_M
, 1 },
464 { "modcodes", DE_OPT_MODCODES
, 1 },
465 { "o", DE_OPT_O
, 1 },
466 { "basefn", DE_OPT_O
, 1 }, // Deprecated
467 { "od", DE_OPT_OD
, 1 },
468 { "t", DE_OPT_T
, 1 },
469 { "ta", DE_OPT_ARCFN
, 1 },
470 { "arcfn", DE_OPT_ARCFN
, 1 },
471 { "get", DE_OPT_GET
, 1 },
472 { "firstfile", DE_OPT_FIRSTFILE
, 1 },
473 { "maxfiles", DE_OPT_MAXFILES
, 1 },
474 { "maxfilesize", DE_OPT_MAXFILESIZE
, 1 },
475 { "maxtotalsize", DE_OPT_MAXTOTALSIZE
, 1 },
476 { "maxdim", DE_OPT_MAXIMGDIM
, 1 },
477 { "dprefix", DE_OPT_DPREFIX
, 1 },
478 { "extrlist", DE_OPT_EXTRLIST
, 1 },
479 { "onlymods", DE_OPT_ONLYMODS
, 1 },
480 { "disablemods", DE_OPT_DISABLEMODS
, 1 },
481 { "onlydetect", DE_OPT_ONLYDETECT
, 1 },
482 { "nodetect", DE_OPT_NODETECT
, 1 },
483 { "colormode", DE_OPT_COLORMODE
, 1 },
484 { NULL
, DE_OPT_NULL
, 0 }
487 static struct opt_struct
*opt_string_to_opt_struct(const char *s
)
491 for(k
=0; option_array
[k
].id
!=DE_OPT_NULL
; k
++) {
492 if(!strcmp(s
, option_array
[k
].string
)) {
493 return &option_array
[k
];
499 static void send_msgs_to_stderr(deark
*c
, struct cmdctx
*cc
)
501 cc
->msgs_to_stderr
= 1;
502 cc
->have_initialized_output_stream
= 0;
503 cc
->msgs_FILE
= NULL
;
505 cc
->have_windows_console
= 0;
509 static void colormode_opt(struct cmdctx
*cc
, const char *modestr
)
511 if(!strcmp(modestr
, "auto")) {
512 cc
->color_method_req
= CM_AUTOCOLOR
;
514 else if(!strcmp(modestr
, "ansi")) {
515 cc
->color_method_req
= CM_ANSI
;
517 else if(!strcmp(modestr
, "ansi24")) {
518 cc
->color_method_req
= CM_ANSI24
;
520 else if(!strcmp(modestr
, "winconsole")) {
521 cc
->color_method_req
= CM_WINCONSOLE
;
523 else if(!strcmp(modestr
, "none")) {
524 cc
->color_method_req
= CM_NOCOLOR
;
527 de_printf(cc
->c
, DE_MSGTYPE_MESSAGE
, "Invalid colormode: %s\n", modestr
);
533 static void set_output_basename(struct cmdctx
*cc
)
535 const char *outputbasefn
= cc
->base_output_filename
; // default, could be NULL
536 const char *outdirname
;
537 unsigned int flags
= 0;
539 if(cc
->option_k_level
&& cc
->input_filename
) {
540 if(cc
->option_k_level
==1) {
541 // Use base input filename in output filenames.
542 outputbasefn
= cc
->input_filename
;
545 else if(cc
->option_k_level
==2) {
546 // Use full input filename path, but not as an actual path.
547 outputbasefn
= cc
->input_filename
;
550 else if(cc
->option_k_level
==3) {
551 // Use full input filename path, as-is.
552 outputbasefn
= cc
->input_filename
;
556 if(cc
->to_zip
|| cc
->to_tar
) {
557 // In this case, -od refers to the archive filename, not to the base
558 // filename that we're dealing with here.
561 else if(cc
->to_stdout
) {
562 // -od is incompatible with -tostdout
566 outdirname
= cc
->output_dirname
;
569 de_set_output_filename_pattern(cc
->c
, outdirname
, outputbasefn
, flags
);
572 static void set_output_archive_name(struct cmdctx
*cc
)
574 const char *arcfn
= cc
->archive_filename
; // default, could be NULL
575 unsigned int flags
= 0;
577 if(!cc
->to_zip
&& !cc
->to_tar
) return;
578 if(cc
->to_stdout
) return;
580 if(cc
->option_ka_level
&& cc
->input_filename
)
582 if(cc
->option_ka_level
==1) {
583 // Use base input filename in output filenames.
584 arcfn
= cc
->input_filename
;
587 else if(cc
->option_ka_level
==2) {
588 // Use full input filename path, but not as an actual path.
589 arcfn
= cc
->input_filename
;
592 else if(cc
->option_ka_level
==3) {
593 // Use full input filename path, as-is.
594 arcfn
= cc
->input_filename
;
604 de_set_output_archive_filename(cc
->c
, cc
->output_dirname
, arcfn
, flags
);
607 static void handle_special_1st_filename(struct cmdctx
*cc
)
609 if(!cc
->output_special_1st_filename
) return;
610 de_set_output_special_1st_filename(cc
->c
,
611 ((cc
->to_zip
|| cc
->to_tar
|| cc
->to_stdout
) ? NULL
: cc
->output_dirname
),
612 cc
->output_special_1st_filename
);
613 if(!cc
->set_MAXFILES
) {
614 de_set_max_output_files(cc
->c
, 1);
618 static void parse_cmdline(deark
*c
, struct cmdctx
*cc
, int argc
, char **argv
)
623 const struct opt_struct
*opt
;
625 for(i
=1;i
<argc
;i
++) {
626 if(argv
[i
][0]=='-') {
627 if(argv
[i
][1]=='-') // Allow a superfluous second '-'
628 opt
= opt_string_to_opt_struct(argv
[i
]+2);
630 opt
= opt_string_to_opt_struct(argv
[i
]+1);
633 de_printf(c
, DE_MSGTYPE_MESSAGE
, "Unrecognized option: %s\n", argv
[i
]);
634 if(!strcmp(argv
[i
], "-")) {
635 // I don't want "-" to be an alias for "-fromstdin", because it
636 // would have different syntax rules than it does in most programs.
637 // (Question: Is "-" an *option*, or a kind of *filename*?)
638 de_printf(c
, DE_MSGTYPE_MESSAGE
,
639 "Note: To use stdin/stdout, use \"-fromstdin\"/\"-tostdout\".\n");
642 cc
->show_usage_message
= 1;
645 if(i
>=argc
-opt
->extra_args
) {
646 de_printf(c
, DE_MSGTYPE_MESSAGE
, "Option %s needs an argument\n", argv
[i
]);
648 cc
->show_usage_message
= 1;
654 de_set_std_option_int(c
, DE_STDOPT_DEBUG_LEVEL
, 1);
657 de_set_std_option_int(c
, DE_STDOPT_DEBUG_LEVEL
, 2);
660 de_set_std_option_int(c
, DE_STDOPT_DEBUG_LEVEL
, 3);
663 de_set_std_option_int(c
, DE_STDOPT_DEBUG_LEVEL
, 4);
666 de_set_std_option_int(c
, DE_STDOPT_LISTMODE
, 1);
669 de_set_std_option_int(c
, DE_STDOPT_INFOMESSAGES
, 0);
672 de_set_std_option_int(c
, DE_STDOPT_WARNINGS
, 0);
675 de_set_std_option_int(c
, DE_STDOPT_WRITE_BOM
, 0);
678 de_set_std_option_int(c
, DE_STDOPT_WRITE_DENSITY
, 0);
680 case DE_OPT_ASCIIHTML
:
681 de_set_std_option_int(c
, DE_STDOPT_ASCII_HTML
, 1);
684 de_set_std_option_int(c
, DE_STDOPT_FILENAMES_FROM_FILE
, 0);
687 de_set_std_option_int(c
, DE_STDOPT_PADPIX
, 1);
689 case DE_OPT_NOOVERWRITE
:
690 de_set_std_option_int(c
, DE_STDOPT_OVERWRITE_MODE
, DE_OVERWRITEMODE_NEVER
);
693 de_set_preserve_file_times(c
, 0, 1);
694 de_set_preserve_file_times(c
, 1, 1);
696 case DE_OPT_NOMODTIME
:
697 de_set_preserve_file_times(c
, 0, 0);
698 de_set_preserve_file_times(c
, 1, 0);
701 de_set_std_option_int(c
, DE_STDOPT_INFOMESSAGES
, 0);
702 de_set_std_option_int(c
, DE_STDOPT_WARNINGS
, 0);
705 cc
->special_command_flag
= 1;
706 cc
->special_command_code
= CMD_PRINTVERSION
;
708 case DE_OPT_PRINTMODULES
:
709 cc
->special_command_flag
= 1;
710 cc
->special_command_code
= CMD_PRINTMODULES
;
713 // At this point, we don't know whether this will be general help,
714 // or module-specific help. So just set a flag for later.
718 cc
->special_command_flag
= 1;
719 cc
->special_command_code
= CMD_PRINTLICENSE
;
722 de_set_std_option_int(c
, DE_STDOPT_ID_MODE
, 1);
727 case DE_OPT_MAINONLY
:
728 de_set_std_option_int(c
, DE_STDOPT_EXTRACT_POLICY
, DE_EXTRACTPOLICY_MAINONLY
);
731 de_set_std_option_int(c
, DE_STDOPT_EXTRACT_POLICY
, DE_EXTRACTPOLICY_AUXONLY
);
733 case DE_OPT_EXTRACTALL
:
734 de_set_std_option_int(c
, DE_STDOPT_EXTRACT_LEVEL
, 2);
737 de_set_output_style(c
, DE_OUTPUTSTYLE_ARCHIVE
, DE_ARCHIVEFMT_ZIP
);
741 de_set_output_style(c
, DE_OUTPUTSTYLE_ARCHIVE
, DE_ARCHIVEFMT_TAR
);
744 case DE_OPT_TOSTDOUT
:
745 send_msgs_to_stderr(c
, cc
);
748 case DE_OPT_MSGSTOSTDERR
:
749 send_msgs_to_stderr(c
, cc
);
751 case DE_OPT_FROMSTDIN
:
752 de_set_input_style(c
, DE_INPUTSTYLE_STDIN
);
756 colormode_opt(cc
, "auto");
759 cc
->option_k_level
= 1;
762 cc
->option_k_level
= 2;
765 cc
->option_k_level
= 3;
768 cc
->option_ka_level
= 1;
771 cc
->option_ka_level
= 2;
774 cc
->option_ka_level
= 3;
776 case DE_OPT_ENCODING
:
777 set_encoding_option(c
, cc
, argv
[i
+1]);
778 if(cc
->error_flag
) return;
781 set_ext_option(c
, cc
, argv
[i
+1]);
784 cc
->input_filename
= argv
[i
+1];
785 de_set_input_filename(c
, cc
->input_filename
);
788 de_set_ext_option(c
, "file2", argv
[i
+1]);
791 if(!de_set_input_encoding(c
, argv
[i
+1], 0)) {
792 de_printf(c
, DE_MSGTYPE_MESSAGE
,
793 "Error: Unknown input encoding: %s\n", argv
[i
+1]);
799 de_set_input_timezone(c
, (i64
)(3600.0*atof(argv
[i
+1])));
802 de_set_input_file_slice_start(c
, de_atoi64(argv
[i
+1]));
805 de_set_input_file_slice_size(c
, de_atoi64(argv
[i
+1]));
809 de_set_input_format(c
, argv
[i
+1]);
811 case DE_OPT_MODCODES
:
812 de_set_module_init_codes(c
, argv
[i
+1]);
815 cc
->base_output_filename
= argv
[i
+1];
818 cc
->output_dirname
= argv
[i
+1];
821 cc
->output_special_1st_filename
= argv
[i
+1];
824 // Relevant e.g. if the -zip option is used.
825 cc
->archive_filename
= argv
[i
+1];
828 de_set_first_output_file(c
, de_atoi(argv
[i
+1]));
829 de_set_max_output_files(c
, 1);
831 case DE_OPT_FIRSTFILE
:
832 de_set_first_output_file(c
, de_atoi(argv
[i
+1]));
834 case DE_OPT_MAXFILES
:
835 de_set_max_output_files(c
, de_atoi64(argv
[i
+1]));
836 cc
->set_MAXFILES
= 1;
838 case DE_OPT_MAXFILESIZE
:
839 de_set_max_output_file_size(c
, de_atoi64(argv
[i
+1]));
841 case DE_OPT_MAXTOTALSIZE
:
842 de_set_max_total_output_size(c
, de_atoi64(argv
[i
+1]));
844 case DE_OPT_MAXIMGDIM
:
845 de_set_max_image_dimension(c
, de_atoi64(argv
[i
+1]));
848 de_set_dprefix(c
, argv
[i
+1]);
850 case DE_OPT_EXTRLIST
:
851 de_set_extrlist_filename(c
, argv
[i
+1]);
853 case DE_OPT_ONLYMODS
:
854 de_set_disable_mods(c
, argv
[i
+1], 1);
856 case DE_OPT_DISABLEMODS
:
857 de_set_disable_mods(c
, argv
[i
+1], 0);
859 case DE_OPT_ONLYDETECT
:
860 de_set_disable_moddetect(c
, argv
[i
+1], 1);
862 case DE_OPT_NODETECT
:
863 de_set_disable_moddetect(c
, argv
[i
+1], 0);
865 case DE_OPT_COLORMODE
:
866 colormode_opt(cc
, argv
[i
+1]);
867 if(cc
->error_flag
) return;
870 de_printf(c
, DE_MSGTYPE_MESSAGE
, "Unrecognized option: %s\n", argv
[i
]);
872 cc
->show_usage_message
= 1;
876 i
+= opt
->extra_args
;
879 if(cc
->input_filename
) {
881 cc
->show_usage_message
= 1;
884 cc
->input_filename
= argv
[i
];
885 de_set_input_filename(c
, cc
->input_filename
);
890 if(module_flag
|| cc
->input_filename
|| cc
->from_stdin
) {
891 de_set_std_option_int(c
, DE_STDOPT_WANT_MODHELP
, 1);
894 cc
->special_command_flag
= 1;
895 cc
->special_command_code
= CMD_PRINTHELP
;
900 if(!cc
->input_filename
&& !cc
->special_command_flag
&& !cc
->from_stdin
) {
901 de_puts(c
, DE_MSGTYPE_MESSAGE
, "Error: Need an input filename\n");
903 cc
->show_usage_message
= 1;
908 if(cc
->to_zip
|| cc
->to_tar
) {
909 de_set_output_archive_filename(c
, NULL
, NULL
, 0x10);
912 de_set_output_style(c
, DE_OUTPUTSTYLE_STDOUT
, 0);
913 if(!cc
->set_MAXFILES
) {
914 de_set_max_output_files(c
, 1);
919 set_output_basename(cc
);
920 set_output_archive_name(cc
);
921 handle_special_1st_filename(cc
);
924 static int main2(int argc
, char **argv
)
927 struct cmdctx
*cc
= NULL
;
931 cc
= de_malloc(NULL
, sizeof(struct cmdctx
));
935 de_set_userdata(c
, (void*)cc
);
936 de_set_fatalerror_callback(c
, our_fatalerrorfn
);
937 de_set_messages_callback(c
, our_msgfn
);
938 de_set_special_messages_callback(c
, our_specialmsgfn
);
939 cc
->plctx
= de_platformdata_create();
941 if(argc
<2) { // Empty command line
946 parse_cmdline(c
, cc
, argc
, argv
);
949 if(cc
->show_usage_message
) {
950 print_usage_error(c
);
955 if(cc
->special_command_flag
) {
956 switch(cc
->special_command_code
) {
960 case CMD_PRINTVERSION
:
963 case CMD_PRINTLICENSE
:
966 case CMD_PRINTMODULES
:
977 (void)_setmode(_fileno(stdout
), _O_BINARY
);
980 (void)_setmode(_fileno(stdin
), _O_BINARY
);
991 de_platformdata_destroy(cc
->plctx
);
993 if(cc
->error_flag
) exit_status
= 1;
1000 // This prototype is to silence a possible -Wmissing-prototypes warning.
1001 int wmain(int argc
, wchar_t **argvW
);
1003 int wmain(int argc
, wchar_t **argvW
)
1008 argv
= de_convert_args_to_utf8(argc
, argvW
);
1009 exit_status
= main2(argc
, argv
);
1010 de_free_utf8_args(argc
, argv
);
1016 int main(int argc
, char **argv
)
1018 return main2(argc
, argv
);