blob: 1e5536134df22e5703e4f81bc970eaae0ab03c85 [file] [log] [blame]
Yann Colletfcf20872016-05-29 05:16:05 +02001/*
2 zstdcli - Command Line Interface (cli) for zstd
3 Copyright (C) Yann Collet 2014-2016
4
5 GPL v2 License
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 You can contact the author at :
22 - zstd homepage : http://www.zstd.net/
23*/
24/*
25 Note : this is a user program, not part of libzstd.
26 The license of libzstd is BSD.
27 The license of this command line program is GPLv2.
28*/
29
30
31/*-************************************
Yann Collet2cac5b32016-07-13 14:15:08 +020032* Tuning parameters
33**************************************/
Yann Collet2b1a3632016-07-13 15:16:00 +020034#ifndef ZSTDCLI_CLEVEL_DEFAULT
35# define ZSTDCLI_CLEVEL_DEFAULT 3
Yann Collet2cac5b32016-07-13 14:15:08 +020036#endif
37
38
39/*-************************************
Yann Colletfcf20872016-05-29 05:16:05 +020040* Includes
41**************************************/
Yann Collet92c986b2016-07-04 01:37:30 +020042#include "util.h" /* Compiler options, UTIL_HAS_CREATEFILELIST */
Yann Colletfcf20872016-05-29 05:16:05 +020043#include <string.h> /* strcmp, strlen */
44#include <ctype.h> /* toupper */
Yann Colletf9cac7a2016-07-04 18:16:16 +020045#include <errno.h> /* errno */
Yann Colletfcf20872016-05-29 05:16:05 +020046#include "fileio.h"
47#ifndef ZSTD_NOBENCH
48# include "bench.h" /* BMK_benchFiles, BMK_SetNbIterations */
49#endif
Yann Colletfcf20872016-05-29 05:16:05 +020050#ifndef ZSTD_NODICT
51# include "dibio.h"
52#endif
Yann Colletd3b7f8d2016-06-04 19:47:02 +020053#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_maxCLevel */
54#include "zstd.h" /* ZSTD_VERSION_STRING */
Yann Colletfcf20872016-05-29 05:16:05 +020055
56
Yann Colletfcf20872016-05-29 05:16:05 +020057/*-************************************
58* OS-specific Includes
59**************************************/
60#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
61# include <io.h> /* _isatty */
62# define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream))
63#else
Yann Colletd916c902016-07-04 00:42:58 +020064# if defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)
65# include <unistd.h> /* isatty */
66# define IS_CONSOLE(stdStream) isatty(fileno(stdStream))
67# else
68# define IS_CONSOLE(stdStream) 0
69# endif
Yann Colletfcf20872016-05-29 05:16:05 +020070#endif
71
72
73/*-************************************
74* Constants
75**************************************/
76#define COMPRESSOR_NAME "zstd command line interface"
77#ifndef ZSTD_VERSION
78# define ZSTD_VERSION "v" ZSTD_VERSION_STRING
79#endif
80#define AUTHOR "Yann Collet"
81#define WELCOME_MESSAGE "*** %s %i-bits %s, by %s ***\n", COMPRESSOR_NAME, (int)(sizeof(size_t)*8), ZSTD_VERSION, AUTHOR
82
83#define ZSTD_EXTENSION ".zst"
84#define ZSTD_CAT "zstdcat"
85#define ZSTD_UNZSTD "unzstd"
86
87#define KB *(1 <<10)
88#define MB *(1 <<20)
89#define GB *(1U<<30)
90
91static const char* g_defaultDictName = "dictionary";
92static const unsigned g_defaultMaxDictSize = 110 KB;
Yann Collet41105342016-07-27 15:09:11 +020093static const int g_defaultDictCLevel = 5;
Yann Colletfcf20872016-05-29 05:16:05 +020094static const unsigned g_defaultSelectivityLevel = 9;
95
96
97/*-************************************
98* Display Macros
99**************************************/
100#define DISPLAY(...) fprintf(displayOut, __VA_ARGS__)
101#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
102static FILE* displayOut;
103static unsigned displayLevel = 2; /* 0 : no display, 1: errors, 2 : + result + interaction + warnings, 3 : + progression, 4 : + information */
104
105
106/*-************************************
107* Command Line
108**************************************/
109static int usage(const char* programName)
110{
111 DISPLAY( "Usage :\n");
112 DISPLAY( " %s [args] [FILE(s)] [-o file]\n", programName);
113 DISPLAY( "\n");
114 DISPLAY( "FILE : a filename\n");
115 DISPLAY( " with no FILE, or when FILE is - , read standard input\n");
116 DISPLAY( "Arguments :\n");
117#ifndef ZSTD_NOCOMPRESS
Yann Collet10b9c132016-07-24 01:21:53 +0200118 DISPLAY( " -# : # compression level (1-%u, default:%u) \n", ZSTD_maxCLevel(), ZSTDCLI_CLEVEL_DEFAULT);
Yann Colletfcf20872016-05-29 05:16:05 +0200119#endif
120#ifndef ZSTD_NODECOMPRESS
121 DISPLAY( " -d : decompression \n");
122#endif
123 DISPLAY( " -D file: use `file` as Dictionary \n");
124 DISPLAY( " -o file: result stored into `file` (only if 1 input file) \n");
125 DISPLAY( " -f : overwrite output without prompting \n");
Yann Colleta7a5d772016-07-02 00:37:32 +0200126 DISPLAY( "--rm : remove source file(s) after successful de/compression \n");
Yann Colletd916c902016-07-04 00:42:58 +0200127 DISPLAY( " -k : preserve source file(s) (default) \n");
Yann Colletfcf20872016-05-29 05:16:05 +0200128 DISPLAY( " -h/-H : display help/long help and exit\n");
129 return 0;
130}
131
132static int usage_advanced(const char* programName)
133{
134 DISPLAY(WELCOME_MESSAGE);
135 usage(programName);
136 DISPLAY( "\n");
137 DISPLAY( "Advanced arguments :\n");
138 DISPLAY( " -V : display Version number and exit\n");
Yann Colletfcf20872016-05-29 05:16:05 +0200139 DISPLAY( " -v : verbose mode\n");
140 DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n");
141 DISPLAY( " -c : force write to standard output, even if it is the console\n");
142#ifdef UTIL_HAS_CREATEFILELIST
143 DISPLAY( " -r : operate recursively on directories\n");
144#endif
145#ifndef ZSTD_NOCOMPRESS
146 DISPLAY( "--ultra : enable ultra modes (requires more memory to decompress)\n");
Yann Colletb09b12c2016-06-09 22:59:51 +0200147 DISPLAY( "--no-dictID : don't write dictID into header (dictionary compression)\n");
Yann Colletc98f8e72016-06-20 16:31:24 +0200148 DISPLAY( "--[no-]check : integrity check (default:enabled)\n");
Yann Colletfcf20872016-05-29 05:16:05 +0200149#endif
Yann Collet6381e992016-05-31 02:29:45 +0200150#ifndef ZSTD_NODECOMPRESS
Yann Collet2c4acda2016-06-02 17:05:50 +0200151 DISPLAY( "--test : test compressed file integrity \n");
Yann Colletb09b12c2016-06-09 22:59:51 +0200152 DISPLAY( "--[no-]sparse : sparse mode (default:enabled on file, disabled on stdout)\n");
Yann Collet6381e992016-05-31 02:29:45 +0200153#endif
Yann Colletfcf20872016-05-29 05:16:05 +0200154#ifndef ZSTD_NODICT
155 DISPLAY( "\n");
156 DISPLAY( "Dictionary builder :\n");
Yann Colletb09b12c2016-06-09 22:59:51 +0200157 DISPLAY( "--train ## : create a dictionary from a training set of files \n");
158 DISPLAY( " -o file : `file` is dictionary name (default: %s) \n", g_defaultDictName);
159 DISPLAY( "--maxdict ## : limit dictionary to specified size (default : %u) \n", g_defaultMaxDictSize);
Yann Colletfcf20872016-05-29 05:16:05 +0200160 DISPLAY( " -s# : dictionary selectivity level (default: %u)\n", g_defaultSelectivityLevel);
Yann Colletb09b12c2016-06-09 22:59:51 +0200161 DISPLAY( "--dictID ## : force dictionary ID to specified value (default: random)\n");
Yann Colletfcf20872016-05-29 05:16:05 +0200162#endif
163#ifndef ZSTD_NOBENCH
164 DISPLAY( "\n");
165 DISPLAY( "Benchmark arguments :\n");
166 DISPLAY( " -b# : benchmark file(s), using # compression level (default : 1) \n");
167 DISPLAY( " -e# : test all compression levels from -bX to # (default: 1)\n");
Yann Colleta9febe82016-08-01 13:37:17 +0200168 DISPLAY( " -i# : minimum evaluation time in seconds (default : 3s)\n");
Yann Colletfcf20872016-05-29 05:16:05 +0200169 DISPLAY( " -B# : cut file into independent blocks of size # (default: no block)\n");
170#endif
171 return 0;
172}
173
174static int badusage(const char* programName)
175{
176 DISPLAYLEVEL(1, "Incorrect parameters\n");
177 if (displayLevel >= 1) usage(programName);
178 return 1;
179}
180
Yann Colletfcf20872016-05-29 05:16:05 +0200181static void waitEnter(void)
182{
183 int unused;
184 DISPLAY("Press enter to continue...\n");
185 unused = getchar();
186 (void)unused;
187}
188
Yann Collet1dd79612016-06-03 15:14:09 +0200189/*! readU32FromChar() :
190 @return : unsigned integer value reach from input in `char` format
191 Will also modify `*stringPtr`, advancing it to position where it stopped reading.
Yann Colleta7a5d772016-07-02 00:37:32 +0200192 Note : this function can overflow if result > MAX_UINT */
Yann Collet1dd79612016-06-03 15:14:09 +0200193static unsigned readU32FromChar(const char** stringPtr)
194{
195 unsigned result = 0;
196 while ((**stringPtr >='0') && (**stringPtr <='9'))
197 result *= 10, result += **stringPtr - '0', (*stringPtr)++ ;
198 return result;
199}
200
Yann Colletfcf20872016-05-29 05:16:05 +0200201
202#define CLEAN_RETURN(i) { operationResult = (i); goto _end; }
203
204int main(int argCount, const char** argv)
205{
206 int argNb,
207 bench=0,
208 decode=0,
Yann Colletb4024902016-07-26 00:49:47 +0200209 testmode=0,
Yann Colletfcf20872016-05-29 05:16:05 +0200210 forceStdout=0,
211 main_pause=0,
212 nextEntryIsDictionary=0,
213 operationResult=0,
214 dictBuild=0,
215 nextArgumentIsOutFileName=0,
Yann Collet290aaa72016-05-30 21:18:52 +0200216 nextArgumentIsMaxDict=0,
Yann Colletf9cac7a2016-07-04 18:16:16 +0200217 nextArgumentIsDictID=0,
218 nextArgumentIsFile=0;
Yann Collet41105342016-07-27 15:09:11 +0200219 int cLevel = ZSTDCLI_CLEVEL_DEFAULT;
220 int cLevelLast = 1;
Yann Colletfcf20872016-05-29 05:16:05 +0200221 unsigned recursive = 0;
222 const char** filenameTable = (const char**)malloc(argCount * sizeof(const char*)); /* argCount >= 1 */
223 unsigned filenameIdx = 0;
224 const char* programName = argv[0];
225 const char* outFileName = NULL;
226 const char* dictFileName = NULL;
227 char* dynNameSpace = NULL;
228 unsigned maxDictSize = g_defaultMaxDictSize;
Yann Collet290aaa72016-05-30 21:18:52 +0200229 unsigned dictID = 0;
Yann Collet41105342016-07-27 15:09:11 +0200230 int dictCLevel = g_defaultDictCLevel;
Yann Colletfcf20872016-05-29 05:16:05 +0200231 unsigned dictSelect = g_defaultSelectivityLevel;
232#ifdef UTIL_HAS_CREATEFILELIST
233 const char** fileNamesTable = NULL;
234 char* fileNamesBuf = NULL;
235 unsigned fileNamesNb;
236#endif
237
238 /* init */
Yann Colletf3a1a842016-06-05 01:05:01 +0200239 (void)recursive; (void)cLevelLast; /* not used when ZSTD_NOBENCH set */
240 (void)dictCLevel; (void)dictSelect; (void)dictID; /* not used when ZSTD_NODICT set */
Yann Colletfcf20872016-05-29 05:16:05 +0200241 (void)decode; (void)cLevel; /* not used when ZSTD_NOCOMPRESS set */
Yann Colletd916c902016-07-04 00:42:58 +0200242 if (filenameTable==NULL) { DISPLAY("zstd: %s \n", strerror(errno)); exit(1); }
Yann Colletfcf20872016-05-29 05:16:05 +0200243 filenameTable[0] = stdinmark;
244 displayOut = stderr;
245 /* Pick out program name from path. Don't rely on stdlib because of conflicting behavior */
246 { size_t pos;
247 for (pos = (int)strlen(programName); pos > 0; pos--) { if (programName[pos] == '/') { pos++; break; } }
248 programName += pos;
249 }
250
251 /* preset behaviors */
252 if (!strcmp(programName, ZSTD_UNZSTD)) decode=1;
253 if (!strcmp(programName, ZSTD_CAT)) { decode=1; forceStdout=1; displayLevel=1; outFileName=stdoutmark; }
254
255 /* command switches */
256 for(argNb=1; argNb<argCount; argNb++) {
257 const char* argument = argv[argNb];
258 if(!argument) continue; /* Protection if argument empty */
259
Yann Colletf9cac7a2016-07-04 18:16:16 +0200260 if (nextArgumentIsFile==0) {
Yann Colletfcf20872016-05-29 05:16:05 +0200261
Yann Colletf9cac7a2016-07-04 18:16:16 +0200262 /* long commands (--long-word) */
263 if (!strcmp(argument, "--")) { nextArgumentIsFile=1; continue; }
264 if (!strcmp(argument, "--decompress")) { decode=1; continue; }
265 if (!strcmp(argument, "--force")) { FIO_overwriteMode(); continue; }
266 if (!strcmp(argument, "--version")) { displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); }
267 if (!strcmp(argument, "--help")) { displayOut=stdout; CLEAN_RETURN(usage_advanced(programName)); }
Yann Collet988bcf32016-07-15 19:43:30 +0200268 if (!strcmp(argument, "--verbose")) { displayLevel++; continue; }
Yann Colletf9cac7a2016-07-04 18:16:16 +0200269 if (!strcmp(argument, "--quiet")) { displayLevel--; continue; }
270 if (!strcmp(argument, "--stdout")) { forceStdout=1; outFileName=stdoutmark; displayLevel-=(displayLevel==2); continue; }
271 if (!strcmp(argument, "--ultra")) { FIO_setMaxWLog(0); continue; }
272 if (!strcmp(argument, "--check")) { FIO_setChecksumFlag(2); continue; }
273 if (!strcmp(argument, "--no-check")) { FIO_setChecksumFlag(0); continue; }
274 if (!strcmp(argument, "--no-dictID")) { FIO_setDictIDFlag(0); continue; }
275 if (!strcmp(argument, "--sparse")) { FIO_setSparseWrite(2); continue; }
276 if (!strcmp(argument, "--no-sparse")) { FIO_setSparseWrite(0); continue; }
Yann Colletb4024902016-07-26 00:49:47 +0200277 if (!strcmp(argument, "--test")) { testmode=1; decode=1; continue; }
Yann Colletf9cac7a2016-07-04 18:16:16 +0200278 if (!strcmp(argument, "--train")) { dictBuild=1; outFileName=g_defaultDictName; continue; }
279 if (!strcmp(argument, "--maxdict")) { nextArgumentIsMaxDict=1; continue; }
280 if (!strcmp(argument, "--dictID")) { nextArgumentIsDictID=1; continue; }
281 if (!strcmp(argument, "--keep")) { FIO_setRemoveSrcFile(0); continue; }
282 if (!strcmp(argument, "--rm")) { FIO_setRemoveSrcFile(1); continue; }
Yann Colletfcf20872016-05-29 05:16:05 +0200283
Yann Colletf9cac7a2016-07-04 18:16:16 +0200284 /* '-' means stdin/stdout */
285 if (!strcmp(argument, "-")){
286 if (!filenameIdx) {
287 filenameIdx=1, filenameTable[0]=stdinmark;
288 outFileName=stdoutmark;
289 displayLevel-=(displayLevel==2);
Yann Colletfcf20872016-05-29 05:16:05 +0200290 continue;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200291 } }
Yann Colletfcf20872016-05-29 05:16:05 +0200292
Yann Colletf9cac7a2016-07-04 18:16:16 +0200293 /* Decode commands (note : aggregated commands are allowed) */
294 if (argument[0]=='-') {
295 argument++;
Yann Colletfcf20872016-05-29 05:16:05 +0200296
Yann Colletf9cac7a2016-07-04 18:16:16 +0200297 while (argument[0]!=0) {
298 #ifndef ZSTD_NOCOMPRESS
299 /* compression Level */
300 if ((*argument>='0') && (*argument<='9')) {
301 cLevel = readU32FromChar(&argument);
302 dictCLevel = cLevel;
303 if (dictCLevel > ZSTD_maxCLevel())
304 CLEAN_RETURN(badusage(programName));
305 continue;
306 }
307 #endif
Yann Colletfcf20872016-05-29 05:16:05 +0200308
Yann Colletf9cac7a2016-07-04 18:16:16 +0200309 switch(argument[0])
310 {
311 /* Display help */
312 case 'V': displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); /* Version Only */
313 case 'H':
314 case 'h': displayOut=stdout; CLEAN_RETURN(usage_advanced(programName));
Yann Colletfcf20872016-05-29 05:16:05 +0200315
Yann Colletf9cac7a2016-07-04 18:16:16 +0200316 /* Decoding */
317 case 'd': decode=1; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200318
Yann Colletf9cac7a2016-07-04 18:16:16 +0200319 /* Force stdout, even if stdout==console */
320 case 'c': forceStdout=1; outFileName=stdoutmark; displayLevel-=(displayLevel==2); argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200321
Yann Colletf9cac7a2016-07-04 18:16:16 +0200322 /* Use file content as dictionary */
323 case 'D': nextEntryIsDictionary = 1; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200324
Yann Colletf9cac7a2016-07-04 18:16:16 +0200325 /* Overwrite */
326 case 'f': FIO_overwriteMode(); forceStdout=1; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200327
Yann Colletf9cac7a2016-07-04 18:16:16 +0200328 /* Verbose mode */
Yann Collet988bcf32016-07-15 19:43:30 +0200329 case 'v': displayLevel++; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200330
Yann Colletf9cac7a2016-07-04 18:16:16 +0200331 /* Quiet mode */
332 case 'q': displayLevel--; argument++; break;
Yann Collet2c4acda2016-06-02 17:05:50 +0200333
Yann Colletf9cac7a2016-07-04 18:16:16 +0200334 /* keep source file (default); for gzip/xz compatibility */
335 case 'k': FIO_setRemoveSrcFile(0); argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200336
Yann Colletf9cac7a2016-07-04 18:16:16 +0200337 /* Checksum */
338 case 'C': argument++; FIO_setChecksumFlag(2); break;
Yann Colletfcf20872016-05-29 05:16:05 +0200339
Yann Colletf9cac7a2016-07-04 18:16:16 +0200340 /* test compressed file */
Yann Colletb4024902016-07-26 00:49:47 +0200341 case 't': testmode=1; decode=1; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200342
Yann Collet2cac5b32016-07-13 14:15:08 +0200343 /* destination file name */
Yann Colletf9cac7a2016-07-04 18:16:16 +0200344 case 'o': nextArgumentIsOutFileName=1; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200345
Yann Colletf9cac7a2016-07-04 18:16:16 +0200346 /* recursive */
347 case 'r': recursive=1; argument++; break;
348
349 #ifndef ZSTD_NOBENCH
350 /* Benchmark */
351 case 'b': bench=1; argument++; break;
352
353 /* range bench (benchmark only) */
354 case 'e':
355 /* compression Level */
356 argument++;
357 cLevelLast = readU32FromChar(&argument);
358 break;
359
360 /* Modify Nb Iterations (benchmark only) */
361 case 'i':
Yann Colletfcf20872016-05-29 05:16:05 +0200362 argument++;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200363 { U32 const iters = readU32FromChar(&argument);
364 BMK_setNotificationLevel(displayLevel);
365 BMK_SetNbIterations(iters);
366 }
Yann Colletfcf20872016-05-29 05:16:05 +0200367 break;
368
Yann Colletf9cac7a2016-07-04 18:16:16 +0200369 /* cut input into blocks (benchmark only) */
370 case 'B':
371 argument++;
372 { size_t bSize = readU32FromChar(&argument);
373 if (toupper(*argument)=='K') bSize<<=10, argument++; /* allows using KB notation */
374 if (toupper(*argument)=='M') bSize<<=20, argument++;
375 if (toupper(*argument)=='B') argument++;
376 BMK_setNotificationLevel(displayLevel);
377 BMK_SetBlockSize(bSize);
378 }
379 break;
380 #endif /* ZSTD_NOBENCH */
381
382 /* Dictionary Selection level */
383 case 's':
384 argument++;
385 dictSelect = readU32FromChar(&argument);
386 break;
387
388 /* Pause at the end (-p) or set an additional param (-p#) (hidden option) */
389 case 'p': argument++;
390 #ifndef ZSTD_NOBENCH
391 if ((*argument>='0') && (*argument<='9')) {
392 BMK_setAdditionalParam(readU32FromChar(&argument));
393 } else
394 #endif
395 main_pause=1;
396 break;
397 /* unknown command */
398 default : CLEAN_RETURN(badusage(programName));
Yann Colletfcf20872016-05-29 05:16:05 +0200399 }
Yann Colletfcf20872016-05-29 05:16:05 +0200400 }
Yann Colletf9cac7a2016-07-04 18:16:16 +0200401 continue;
402 } /* if (argument[0]=='-') */
403
404 if (nextArgumentIsMaxDict) {
405 nextArgumentIsMaxDict = 0;
406 maxDictSize = readU32FromChar(&argument);
407 if (toupper(*argument)=='K') maxDictSize <<= 10;
408 if (toupper(*argument)=='M') maxDictSize <<= 20;
409 continue;
Yann Colletfcf20872016-05-29 05:16:05 +0200410 }
Yann Colletf9cac7a2016-07-04 18:16:16 +0200411
412 if (nextArgumentIsDictID) {
413 nextArgumentIsDictID = 0;
414 dictID = readU32FromChar(&argument);
415 continue;
416 }
417
418 } /* if (nextArgumentIsAFile==0) */
Yann Colletfcf20872016-05-29 05:16:05 +0200419
420 if (nextEntryIsDictionary) {
421 nextEntryIsDictionary = 0;
422 dictFileName = argument;
423 continue;
424 }
425
426 if (nextArgumentIsOutFileName) {
427 nextArgumentIsOutFileName = 0;
428 outFileName = argument;
429 if (!strcmp(outFileName, "-")) outFileName = stdoutmark;
430 continue;
431 }
432
Yann Colletfcf20872016-05-29 05:16:05 +0200433 /* add filename to list */
434 filenameTable[filenameIdx++] = argument;
435 }
436
437 /* Welcome message (if verbose) */
438 DISPLAYLEVEL(3, WELCOME_MESSAGE);
439
440#ifdef UTIL_HAS_CREATEFILELIST
441 if (recursive) {
442 fileNamesTable = UTIL_createFileList(filenameTable, filenameIdx, &fileNamesBuf, &fileNamesNb);
443 if (fileNamesTable) {
444 unsigned i;
Yann Collet06dd7412016-07-18 04:06:43 +0200445 for (i=0; i<fileNamesNb; i++) DISPLAYLEVEL(4, "%d %s\n", i, fileNamesTable[i]);
Yann Colletfcf20872016-05-29 05:16:05 +0200446 free((void*)filenameTable);
447 filenameTable = fileNamesTable;
448 filenameIdx = fileNamesNb;
449 }
450 }
451#endif
452
453 /* Check if benchmark is selected */
454 if (bench) {
455#ifndef ZSTD_NOBENCH
456 BMK_setNotificationLevel(displayLevel);
457 BMK_benchFiles(filenameTable, filenameIdx, dictFileName, cLevel, cLevelLast);
458#endif
459 goto _end;
460 }
461
462 /* Check if dictionary builder is selected */
463 if (dictBuild) {
464#ifndef ZSTD_NODICT
465 ZDICT_params_t dictParams;
Yann Collet5e80dd32016-07-13 17:38:39 +0200466 memset(&dictParams, 0, sizeof(dictParams));
Yann Colletfcf20872016-05-29 05:16:05 +0200467 dictParams.compressionLevel = dictCLevel;
468 dictParams.selectivityLevel = dictSelect;
469 dictParams.notificationLevel = displayLevel;
Yann Collet290aaa72016-05-30 21:18:52 +0200470 dictParams.dictID = dictID;
Yann Colletfcf20872016-05-29 05:16:05 +0200471 DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, dictParams);
472#endif
473 goto _end;
474 }
475
476 /* No input filename ==> use stdin and stdout */
477 filenameIdx += !filenameIdx; /*< default input is stdin */
Yann Collet06dd7412016-07-18 04:06:43 +0200478 if (!strcmp(filenameTable[0], stdinmark) && !outFileName) outFileName = stdoutmark; /*< when input is stdin, default output is stdout */
Yann Colletfcf20872016-05-29 05:16:05 +0200479
480 /* Check if input/output defined as console; trigger an error in this case */
481 if (!strcmp(filenameTable[0], stdinmark) && IS_CONSOLE(stdin) ) CLEAN_RETURN(badusage(programName));
482 if (outFileName && !strcmp(outFileName, stdoutmark) && IS_CONSOLE(stdout) && !(forceStdout && decode))
483 CLEAN_RETURN(badusage(programName));
484
485 /* user-selected output filename, only possible with a single file */
486 if (outFileName && strcmp(outFileName,stdoutmark) && strcmp(outFileName,nulmark) && (filenameIdx>1)) {
487 DISPLAY("Too many files (%u) on the command line. \n", filenameIdx);
488 CLEAN_RETURN(filenameIdx);
489 }
490
491 /* No warning message in pipe mode (stdin + stdout) or multiple mode */
492 if (!strcmp(filenameTable[0], stdinmark) && outFileName && !strcmp(outFileName,stdoutmark) && (displayLevel==2)) displayLevel=1;
Yann Collet06dd7412016-07-18 04:06:43 +0200493 if ((filenameIdx>1) & (displayLevel==2)) displayLevel=1;
Yann Colletfcf20872016-05-29 05:16:05 +0200494
495 /* IO Stream/File */
496 FIO_setNotificationLevel(displayLevel);
497#ifndef ZSTD_NOCOMPRESS
498 if (!decode) {
499 if (filenameIdx==1 && outFileName)
500 operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel);
501 else
502 operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, outFileName ? outFileName : ZSTD_EXTENSION, dictFileName, cLevel);
503 } else
504#endif
505 { /* decompression */
506#ifndef ZSTD_NODECOMPRESS
Yann Colletb4024902016-07-26 00:49:47 +0200507 if (testmode) { outFileName=nulmark; FIO_setRemoveSrcFile(0); } /* test mode */
Yann Colletfcf20872016-05-29 05:16:05 +0200508 if (filenameIdx==1 && outFileName)
509 operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName);
510 else
511 operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, outFileName ? outFileName : ZSTD_EXTENSION, dictFileName);
512#else
513 DISPLAY("Decompression not supported\n");
514#endif
515 }
516
517_end:
518 if (main_pause) waitEnter();
519 free(dynNameSpace);
520#ifdef UTIL_HAS_CREATEFILELIST
521 if (fileNamesTable)
522 UTIL_freeFileList(fileNamesTable, fileNamesBuf);
523 else
524#endif
525 free((void*)filenameTable);
526 return operationResult;
527}