blob: c71e80bdd38b785bcd96a1631ce256ea032c5fea [file] [log] [blame]
Yann Collet4ded9e52016-08-30 10:04:33 -07001/**
2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 */
Yann Collet5f53b032016-08-28 10:00:49 -07009
Yann Colletfcf20872016-05-29 05:16:05 +020010
Yann Colletfcf20872016-05-29 05:16:05 +020011/*-************************************
Yann Collet2cac5b32016-07-13 14:15:08 +020012* Tuning parameters
13**************************************/
Yann Collet2b1a3632016-07-13 15:16:00 +020014#ifndef ZSTDCLI_CLEVEL_DEFAULT
15# define ZSTDCLI_CLEVEL_DEFAULT 3
Yann Collet2cac5b32016-07-13 14:15:08 +020016#endif
17
Yann Colletfe0590f2016-08-12 18:04:15 +020018#ifndef ZSTDCLI_CLEVEL_MAX
Yann Collet0977f7e2016-09-21 12:24:43 +020019# define ZSTDCLI_CLEVEL_MAX 19 /* when not using --ultra */
Yann Colletfe0590f2016-08-12 18:04:15 +020020#endif
21
Yann Collet2cac5b32016-07-13 14:15:08 +020022
Yann Collet8dafb1a2017-01-25 17:01:13 -080023
Yann Collet2cac5b32016-07-13 14:15:08 +020024/*-************************************
Yann Collet52afb392016-11-16 08:50:54 -080025* Dependencies
Yann Colletfcf20872016-05-29 05:16:05 +020026**************************************/
Przemyslaw Skibinski7a8a03c2016-12-21 15:08:44 +010027#include "platform.h" /* IS_CONSOLE, PLATFORM_POSIX_VERSION */
28#include "util.h" /* UTIL_HAS_CREATEFILELIST, UTIL_createFileList */
Yann Colletfcf20872016-05-29 05:16:05 +020029#include <string.h> /* strcmp, strlen */
Yann Colletf9cac7a2016-07-04 18:16:16 +020030#include <errno.h> /* errno */
Yann Colletfcf20872016-05-29 05:16:05 +020031#include "fileio.h"
32#ifndef ZSTD_NOBENCH
Przemyslaw Skibinski26306fc2016-11-03 11:38:01 +010033# include "bench.h" /* BMK_benchFiles, BMK_SetNbSeconds */
Yann Colletfcf20872016-05-29 05:16:05 +020034#endif
Yann Colletfcf20872016-05-29 05:16:05 +020035#ifndef ZSTD_NODICT
36# include "dibio.h"
37#endif
Yann Colletd3b7f8d2016-06-04 19:47:02 +020038#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_maxCLevel */
39#include "zstd.h" /* ZSTD_VERSION_STRING */
Yann Colletfcf20872016-05-29 05:16:05 +020040
41
Yann Colletfcf20872016-05-29 05:16:05 +020042/*-************************************
Yann Colletfcf20872016-05-29 05:16:05 +020043* Constants
44**************************************/
45#define COMPRESSOR_NAME "zstd command line interface"
46#ifndef ZSTD_VERSION
47# define ZSTD_VERSION "v" ZSTD_VERSION_STRING
48#endif
49#define AUTHOR "Yann Collet"
50#define WELCOME_MESSAGE "*** %s %i-bits %s, by %s ***\n", COMPRESSOR_NAME, (int)(sizeof(size_t)*8), ZSTD_VERSION, AUTHOR
51
Sean Purcell5a61f362017-04-14 11:33:04 -070052#define ZSTD_ZSTDMT "zstdmt"
Yann Colletfcf20872016-05-29 05:16:05 +020053#define ZSTD_UNZSTD "unzstd"
Yann Colletc09d16b2017-02-14 10:45:19 -080054#define ZSTD_CAT "zstdcat"
55#define ZSTD_GZ "gzip"
56#define ZSTD_GUNZIP "gunzip"
57#define ZSTD_GZCAT "gzcat"
Nick Terrellaa8bcf32017-03-13 18:11:07 -070058#define ZSTD_LZMA "lzma"
59#define ZSTD_XZ "xz"
Yann Colletfcf20872016-05-29 05:16:05 +020060
61#define KB *(1 <<10)
62#define MB *(1 <<20)
63#define GB *(1U<<30)
64
David Lamac43e952016-08-12 14:49:05 -070065#define DEFAULT_DISPLAY_LEVEL 2
66
Yann Colletfcf20872016-05-29 05:16:05 +020067static const char* g_defaultDictName = "dictionary";
68static const unsigned g_defaultMaxDictSize = 110 KB;
Yann Colletc8431422016-09-01 15:05:57 -070069static const int g_defaultDictCLevel = 3;
Yann Colletfcf20872016-05-29 05:16:05 +020070static const unsigned g_defaultSelectivityLevel = 9;
Yann Collet8d8513f2017-01-30 14:37:08 -080071#define OVERLAP_LOG_DEFAULT 9999
72static U32 g_overlapLog = OVERLAP_LOG_DEFAULT;
Yann Colletfcf20872016-05-29 05:16:05 +020073
74
75/*-************************************
76* Display Macros
77**************************************/
Sean Purcell042ba122017-03-23 11:13:52 -070078#define DISPLAY(...) fprintf(g_displayOut, __VA_ARGS__)
79#define DISPLAYLEVEL(l, ...) { if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } }
80static int g_displayLevel = DEFAULT_DISPLAY_LEVEL; /* 0 : no display, 1: errors, 2 : + result + interaction + warnings, 3 : + progression, 4 : + information */
81static FILE* g_displayOut;
Yann Colletfcf20872016-05-29 05:16:05 +020082
83
84/*-************************************
85* Command Line
86**************************************/
87static int usage(const char* programName)
88{
89 DISPLAY( "Usage :\n");
90 DISPLAY( " %s [args] [FILE(s)] [-o file]\n", programName);
91 DISPLAY( "\n");
92 DISPLAY( "FILE : a filename\n");
93 DISPLAY( " with no FILE, or when FILE is - , read standard input\n");
94 DISPLAY( "Arguments :\n");
95#ifndef ZSTD_NOCOMPRESS
inikep5a548702016-08-18 09:00:25 +020096 DISPLAY( " -# : # compression level (1-%d, default:%d) \n", ZSTDCLI_CLEVEL_MAX, ZSTDCLI_CLEVEL_DEFAULT);
Yann Colletfcf20872016-05-29 05:16:05 +020097#endif
98#ifndef ZSTD_NODECOMPRESS
99 DISPLAY( " -d : decompression \n");
100#endif
101 DISPLAY( " -D file: use `file` as Dictionary \n");
102 DISPLAY( " -o file: result stored into `file` (only if 1 input file) \n");
Sean Purcell680e4e02017-03-23 11:52:09 -0700103 DISPLAY( " -f : overwrite output without prompting and (de)compress links \n");
Yann Colleta7a5d772016-07-02 00:37:32 +0200104 DISPLAY( "--rm : remove source file(s) after successful de/compression \n");
Yann Colletd916c902016-07-04 00:42:58 +0200105 DISPLAY( " -k : preserve source file(s) (default) \n");
Yann Colletfcf20872016-05-29 05:16:05 +0200106 DISPLAY( " -h/-H : display help/long help and exit\n");
107 return 0;
108}
109
110static int usage_advanced(const char* programName)
111{
112 DISPLAY(WELCOME_MESSAGE);
113 usage(programName);
114 DISPLAY( "\n");
115 DISPLAY( "Advanced arguments :\n");
116 DISPLAY( " -V : display Version number and exit\n");
Yann Collet805c5a32017-04-01 00:36:31 -0700117 DISPLAY( " -v : verbose mode; specify multiple times to increase verbosity\n");
Yann Colletfcf20872016-05-29 05:16:05 +0200118 DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n");
119 DISPLAY( " -c : force write to standard output, even if it is the console\n");
Paul Cruz901435e2017-06-05 14:45:31 -0700120 DISPLAY( " -l : print information about zstd compressed files.\n");
Yann Colletfcf20872016-05-29 05:16:05 +0200121#ifndef ZSTD_NOCOMPRESS
Yann Colletfe0590f2016-08-12 18:04:15 +0200122 DISPLAY( "--ultra : enable levels beyond %i, up to %i (requires more memory)\n", ZSTDCLI_CLEVEL_MAX, ZSTD_maxCLevel());
Yann Collet500014a2017-01-19 16:59:56 -0800123#ifdef ZSTD_MULTITHREAD
124 DISPLAY( " -T# : use # threads for compression (default:1) \n");
Yann Collet805c5a32017-04-01 00:36:31 -0700125 DISPLAY( " -B# : select size of each job (default:0==automatic) \n");
126#endif
127 DISPLAY( "--no-dictID : don't write dictID into header (dictionary compression)\n");
128 DISPLAY( "--[no-]check : integrity check (default:enabled) \n");
129#endif
130#ifdef UTIL_HAS_CREATEFILELIST
131 DISPLAY( " -r : operate recursively on directories \n");
Yann Collet500014a2017-01-19 16:59:56 -0800132#endif
Przemyslaw Skibinskicfd4dc22017-02-08 15:17:55 +0100133#ifdef ZSTD_GZCOMPRESS
Przemyslaw Skibinski4f9eaa72017-02-08 18:08:09 +0100134 DISPLAY( "--format=gzip : compress files to the .gz format \n");
Przemyslaw Skibinskicfd4dc22017-02-08 15:17:55 +0100135#endif
Nick Terrellaa8bcf32017-03-13 18:11:07 -0700136#ifdef ZSTD_LZMACOMPRESS
137 DISPLAY( "--format=xz : compress files to the .xz format \n");
138 DISPLAY( "--format=lzma : compress files to the .lzma format \n");
139#endif
Sean Purcell4de86322017-04-24 16:48:25 -0700140#ifdef ZSTD_LZ4COMPRESS
141 DISPLAY( "--format=lz4 : compress files to the .lz4 format \n");
142#endif
Yann Collet6381e992016-05-31 02:29:45 +0200143#ifndef ZSTD_NODECOMPRESS
Yann Collet2c4acda2016-06-02 17:05:50 +0200144 DISPLAY( "--test : test compressed file integrity \n");
Nick Terrell96fe5452017-03-31 15:16:43 -0700145#if ZSTD_SPARSE_DEFAULT
Yann Colletb09b12c2016-06-09 22:59:51 +0200146 DISPLAY( "--[no-]sparse : sparse mode (default:enabled on file, disabled on stdout)\n");
Nick Terrell96fe5452017-03-31 15:16:43 -0700147#else
148 DISPLAY( "--[no-]sparse : sparse mode (default:disabled)\n");
149#endif
Yann Collet6381e992016-05-31 02:29:45 +0200150#endif
Yann Colletd4cda272016-10-14 13:13:13 -0700151 DISPLAY( " -M# : Set a memory usage limit for decompression \n");
Paul Cruz9437cc72017-06-15 15:07:54 -0700152 DISPLAY( "--list : list information about a zstd compressed file \n");
Yann Collet60038942016-09-16 18:52:52 +0200153 DISPLAY( "-- : All arguments after \"--\" are treated as files \n");
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");
Nick Terrellf376d472017-05-01 23:40:20 -0700158 DISPLAY( "--train-cover[=k=#,d=#,steps=#] : use the cover algorithm with optional args\n");
159 DISPLAY( "--train-legacy[=s=#] : use the legacy algorithm with selectivity (default: %u)\n", g_defaultSelectivityLevel);
Yann Colletb09b12c2016-06-09 22:59:51 +0200160 DISPLAY( " -o file : `file` is dictionary name (default: %s) \n", g_defaultDictName);
Yann Collet96aa3012017-03-24 16:04:29 -0700161 DISPLAY( "--maxdict=# : limit dictionary to specified size (default : %u) \n", g_defaultMaxDictSize);
Yann Collet96aa3012017-03-24 16:04:29 -0700162 DISPLAY( "--dictID=# : force dictionary ID to specified value (default: random)\n");
Yann Colletfcf20872016-05-29 05:16:05 +0200163#endif
164#ifndef ZSTD_NOBENCH
165 DISPLAY( "\n");
166 DISPLAY( "Benchmark arguments :\n");
167 DISPLAY( " -b# : benchmark file(s), using # compression level (default : 1) \n");
168 DISPLAY( " -e# : test all compression levels from -bX to # (default: 1)\n");
Yann Colleta9febe82016-08-01 13:37:17 +0200169 DISPLAY( " -i# : minimum evaluation time in seconds (default : 3s)\n");
Yann Colletfcf20872016-05-29 05:16:05 +0200170 DISPLAY( " -B# : cut file into independent blocks of size # (default: no block)\n");
Przemyslaw Skibinski40580ff2017-02-08 13:49:06 +0100171 DISPLAY( "--priority=rt : set process priority to real-time\n");
Yann Colletfcf20872016-05-29 05:16:05 +0200172#endif
173 return 0;
174}
175
176static int badusage(const char* programName)
177{
178 DISPLAYLEVEL(1, "Incorrect parameters\n");
Sean Purcell042ba122017-03-23 11:13:52 -0700179 if (g_displayLevel >= 2) usage(programName);
Yann Colletfcf20872016-05-29 05:16:05 +0200180 return 1;
181}
182
Yann Colletfcf20872016-05-29 05:16:05 +0200183static void waitEnter(void)
184{
185 int unused;
186 DISPLAY("Press enter to continue...\n");
187 unused = getchar();
188 (void)unused;
189}
190
Sean Purcellef30af82017-03-24 17:06:09 -0700191static const char* lastNameFromPath(const char* path)
192{
193 const char* name = path;
194 if (strrchr(name, '/')) name = strrchr(name, '/') + 1;
195 if (strrchr(name, '\\')) name = strrchr(name, '\\') + 1; /* windows */
196 return name;
197}
198
199/*! exeNameMatch() :
200 @return : a non-zero value if exeName matches test, excluding the extension
201 */
202static int exeNameMatch(const char* exeName, const char* test)
203{
204 return !strncmp(exeName, test, strlen(test)) &&
205 (exeName[strlen(test)] == '\0' || exeName[strlen(test)] == '.');
206}
207
Yann Collet1dd79612016-06-03 15:14:09 +0200208/*! readU32FromChar() :
Yann Colletd4cda272016-10-14 13:13:13 -0700209 @return : unsigned integer value read from input in `char` format
210 allows and interprets K, KB, KiB, M, MB and MiB suffix.
Yann Collet1dd79612016-06-03 15:14:09 +0200211 Will also modify `*stringPtr`, advancing it to position where it stopped reading.
Yann Colletd4cda272016-10-14 13:13:13 -0700212 Note : function result can overflow if digit string > MAX_UINT */
Yann Collet1dd79612016-06-03 15:14:09 +0200213static unsigned readU32FromChar(const char** stringPtr)
214{
215 unsigned result = 0;
216 while ((**stringPtr >='0') && (**stringPtr <='9'))
217 result *= 10, result += **stringPtr - '0', (*stringPtr)++ ;
Yann Collet33fdd092016-10-17 17:48:48 -0700218 if ((**stringPtr=='K') || (**stringPtr=='M')) {
219 result <<= 10;
220 if (**stringPtr=='M') result <<= 10;
221 (*stringPtr)++ ;
222 if (**stringPtr=='i') (*stringPtr)++;
223 if (**stringPtr=='B') (*stringPtr)++;
224 }
Yann Collet1dd79612016-06-03 15:14:09 +0200225 return result;
226}
227
Yann Collet743b33f2016-12-02 15:18:57 -0800228/** longCommandWArg() :
Yann Collet6ccd37c2017-01-30 13:07:24 -0800229 * check if *stringPtr is the same as longCommand.
Yann Collet743b33f2016-12-02 15:18:57 -0800230 * If yes, @return 1 and advances *stringPtr to the position which immediately follows longCommand.
231 * @return 0 and doesn't modify *stringPtr otherwise.
232 */
Yann Collet70077bc2016-10-14 14:41:17 -0700233static unsigned longCommandWArg(const char** stringPtr, const char* longCommand)
234{
235 size_t const comSize = strlen(longCommand);
Yann Collet743b33f2016-12-02 15:18:57 -0800236 int const result = !strncmp(*stringPtr, longCommand, comSize);
Yann Collet70077bc2016-10-14 14:41:17 -0700237 if (result) *stringPtr += comSize;
238 return result;
239}
240
Przemyslaw Skibinski671f28d2016-12-13 12:18:07 +0100241
Nick Terrelldf8415c2016-12-31 21:08:24 -0800242#ifndef ZSTD_NODICT
243/**
244 * parseCoverParameters() :
Nick Terrellf376d472017-05-01 23:40:20 -0700245 * reads cover parameters from *stringPtr (e.g. "--train-cover=k=48,d=8,steps=32") into *params
Nick Terrelldf8415c2016-12-31 21:08:24 -0800246 * @return 1 means that cover parameters were correct
247 * @return 0 in case of malformed parameters
248 */
Nick Terrellf376d472017-05-01 23:40:20 -0700249static unsigned parseCoverParameters(const char* stringPtr, COVER_params_t* params)
Nick Terrelldf8415c2016-12-31 21:08:24 -0800250{
251 memset(params, 0, sizeof(*params));
252 for (; ;) {
Nick Terrell3a1fefc2017-01-02 12:40:43 -0800253 if (longCommandWArg(&stringPtr, "k=")) { params->k = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
Nick Terrelldf8415c2016-12-31 21:08:24 -0800254 if (longCommandWArg(&stringPtr, "d=")) { params->d = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
Nick Terrell3a1fefc2017-01-02 12:40:43 -0800255 if (longCommandWArg(&stringPtr, "steps=")) { params->steps = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
Nick Terrelldf8415c2016-12-31 21:08:24 -0800256 return 0;
257 }
258 if (stringPtr[0] != 0) return 0;
Nick Terrellf376d472017-05-01 23:40:20 -0700259 DISPLAYLEVEL(4, "cover: k=%u\nd=%u\nsteps=%u\n", params->k, params->d, params->steps);
Nick Terrelldf8415c2016-12-31 21:08:24 -0800260 return 1;
261}
Nick Terrellf376d472017-05-01 23:40:20 -0700262
263/**
264 * parseLegacyParameters() :
265 * reads legacy dictioanry builter parameters from *stringPtr (e.g. "--train-legacy=selectivity=8") into *selectivity
266 * @return 1 means that legacy dictionary builder parameters were correct
267 * @return 0 in case of malformed parameters
268 */
269static unsigned parseLegacyParameters(const char* stringPtr, unsigned* selectivity)
270{
271 if (!longCommandWArg(&stringPtr, "s=") && !longCommandWArg(&stringPtr, "selectivity=")) { return 0; }
272 *selectivity = readU32FromChar(&stringPtr);
273 if (stringPtr[0] != 0) return 0;
274 DISPLAYLEVEL(4, "legacy: selectivity=%u\n", *selectivity);
275 return 1;
276}
277
278static COVER_params_t defaultCoverParams(void)
279{
280 COVER_params_t params;
281 memset(&params, 0, sizeof(params));
282 params.d = 8;
283 params.steps = 4;
284 return params;
285}
Nick Terrelldf8415c2016-12-31 21:08:24 -0800286#endif
Yann Collet6ccd37c2017-01-30 13:07:24 -0800287
288
Przemyslaw Skibinski671f28d2016-12-13 12:18:07 +0100289/** parseCompressionParameters() :
290 * reads compression parameters from *stringPtr (e.g. "--zstd=wlog=23,clog=23,hlog=22,slog=6,slen=3,tlen=48,strat=6") into *params
291 * @return 1 means that compression parameters were correct
292 * @return 0 in case of malformed parameters
293 */
294static unsigned parseCompressionParameters(const char* stringPtr, ZSTD_compressionParameters* params)
295{
296 for ( ; ;) {
Przemyslaw Skibinski671f28d2016-12-13 12:18:07 +0100297 if (longCommandWArg(&stringPtr, "windowLog=") || longCommandWArg(&stringPtr, "wlog=")) { params->windowLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
298 if (longCommandWArg(&stringPtr, "chainLog=") || longCommandWArg(&stringPtr, "clog=")) { params->chainLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
299 if (longCommandWArg(&stringPtr, "hashLog=") || longCommandWArg(&stringPtr, "hlog=")) { params->hashLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
300 if (longCommandWArg(&stringPtr, "searchLog=") || longCommandWArg(&stringPtr, "slog=")) { params->searchLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
301 if (longCommandWArg(&stringPtr, "searchLength=") || longCommandWArg(&stringPtr, "slen=")) { params->searchLength = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
302 if (longCommandWArg(&stringPtr, "targetLength=") || longCommandWArg(&stringPtr, "tlen=")) { params->targetLength = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
Przemyslaw Skibinskic71e5522016-12-13 20:04:32 +0100303 if (longCommandWArg(&stringPtr, "strategy=") || longCommandWArg(&stringPtr, "strat=")) { params->strategy = (ZSTD_strategy)(1 + readU32FromChar(&stringPtr)); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
Yann Collet6ccd37c2017-01-30 13:07:24 -0800304 if (longCommandWArg(&stringPtr, "overlapLog=") || longCommandWArg(&stringPtr, "ovlog=")) { g_overlapLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; }
Przemyslaw Skibinski671f28d2016-12-13 12:18:07 +0100305 return 0;
306 }
307
308 if (stringPtr[0] != 0) return 0; /* check the end of string */
Przemyslaw Skibinski897b8bb2016-12-13 13:03:41 +0100309 DISPLAYLEVEL(4, "windowLog=%d\nchainLog=%d\nhashLog=%d\nsearchLog=%d\n", params->windowLog, params->chainLog, params->hashLog, params->searchLog);
310 DISPLAYLEVEL(4, "searchLength=%d\ntargetLength=%d\nstrategy=%d\n", params->searchLength, params->targetLength, params->strategy);
Przemyslaw Skibinski671f28d2016-12-13 12:18:07 +0100311 return 1;
312}
313
314
Paul Cruz901435e2017-06-05 14:45:31 -0700315typedef enum { zom_compress, zom_decompress, zom_test, zom_bench, zom_train, zom_list } zstd_operation_mode;
Yann Colletfcf20872016-05-29 05:16:05 +0200316
317#define CLEAN_RETURN(i) { operationResult = (i); goto _end; }
318
Yann Collet0977f7e2016-09-21 12:24:43 +0200319int main(int argCount, const char* argv[])
Yann Colletfcf20872016-05-29 05:16:05 +0200320{
321 int argNb,
Yann Colletfcf20872016-05-29 05:16:05 +0200322 forceStdout=0,
Sean Purcell680e4e02017-03-23 11:52:09 -0700323 followLinks=0,
Yann Colletfcf20872016-05-29 05:16:05 +0200324 main_pause=0,
325 nextEntryIsDictionary=0,
326 operationResult=0,
Yann Colletfcf20872016-05-29 05:16:05 +0200327 nextArgumentIsOutFileName=0,
Yann Collet290aaa72016-05-30 21:18:52 +0200328 nextArgumentIsMaxDict=0,
Yann Colletf9cac7a2016-07-04 18:16:16 +0200329 nextArgumentIsDictID=0,
Yann Collet743b33f2016-12-02 15:18:57 -0800330 nextArgumentsAreFiles=0,
Yann Collet27b5ac62016-09-21 14:20:56 +0200331 ultra=0,
Yann Collet500014a2017-01-19 16:59:56 -0800332 lastCommand = 0,
Przemyslaw Skibinskid05014c2017-02-07 16:48:01 +0100333 nbThreads = 1,
334 setRealTimePrio = 0;
Yann Collet500014a2017-01-19 16:59:56 -0800335 unsigned bench_nbSeconds = 3; /* would be better if this value was synchronized from bench */
336 size_t blockSize = 0;
Yann Collet22de81e2016-10-28 13:58:31 -0700337 zstd_operation_mode operation = zom_compress;
Przemyslaw Skibinski671f28d2016-12-13 12:18:07 +0100338 ZSTD_compressionParameters compressionParams;
Yann Collet41105342016-07-27 15:09:11 +0200339 int cLevel = ZSTDCLI_CLEVEL_DEFAULT;
340 int cLevelLast = 1;
Yann Colletfcf20872016-05-29 05:16:05 +0200341 unsigned recursive = 0;
Yann Colletd4cda272016-10-14 13:13:13 -0700342 unsigned memLimit = 0;
Yann Colletfcf20872016-05-29 05:16:05 +0200343 const char** filenameTable = (const char**)malloc(argCount * sizeof(const char*)); /* argCount >= 1 */
344 unsigned filenameIdx = 0;
345 const char* programName = argv[0];
346 const char* outFileName = NULL;
347 const char* dictFileName = NULL;
Przemyslaw Skibinskicb563062017-02-08 17:37:14 +0100348 const char* suffix = ZSTD_EXTENSION;
Yann Colletfcf20872016-05-29 05:16:05 +0200349 unsigned maxDictSize = g_defaultMaxDictSize;
Yann Collet290aaa72016-05-30 21:18:52 +0200350 unsigned dictID = 0;
Yann Collet41105342016-07-27 15:09:11 +0200351 int dictCLevel = g_defaultDictCLevel;
Yann Colletfcf20872016-05-29 05:16:05 +0200352 unsigned dictSelect = g_defaultSelectivityLevel;
353#ifdef UTIL_HAS_CREATEFILELIST
Yann Collet0977f7e2016-09-21 12:24:43 +0200354 const char** extendedFileList = NULL;
Yann Colletfcf20872016-05-29 05:16:05 +0200355 char* fileNamesBuf = NULL;
356 unsigned fileNamesNb;
357#endif
Nick Terrelldf8415c2016-12-31 21:08:24 -0800358#ifndef ZSTD_NODICT
Nick Terrellf376d472017-05-01 23:40:20 -0700359 COVER_params_t coverParams = defaultCoverParams();
360 int cover = 1;
Nick Terrelldf8415c2016-12-31 21:08:24 -0800361#endif
Yann Colletfcf20872016-05-29 05:16:05 +0200362
363 /* init */
Yann Colletf3a1a842016-06-05 01:05:01 +0200364 (void)recursive; (void)cLevelLast; /* not used when ZSTD_NOBENCH set */
Yann Collet407a11f2016-11-03 15:52:01 -0700365 (void)dictCLevel; (void)dictSelect; (void)dictID; (void)maxDictSize; /* not used when ZSTD_NODICT set */
366 (void)ultra; (void)cLevel; /* not used when ZSTD_NOCOMPRESS set */
367 (void)memLimit; /* not used when ZSTD_NODECOMPRESS set */
Yann Colletd916c902016-07-04 00:42:58 +0200368 if (filenameTable==NULL) { DISPLAY("zstd: %s \n", strerror(errno)); exit(1); }
Yann Colletfcf20872016-05-29 05:16:05 +0200369 filenameTable[0] = stdinmark;
Sean Purcell042ba122017-03-23 11:13:52 -0700370 g_displayOut = stderr;
Sean Purcellef30af82017-03-24 17:06:09 -0700371
372 programName = lastNameFromPath(programName);
Yann Colletfcf20872016-05-29 05:16:05 +0200373
374 /* preset behaviors */
Sean Purcell5a61f362017-04-14 11:33:04 -0700375 if (exeNameMatch(programName, ZSTD_ZSTDMT)) nbThreads=0;
Sean Purcellef30af82017-03-24 17:06:09 -0700376 if (exeNameMatch(programName, ZSTD_UNZSTD)) operation=zom_decompress;
377 if (exeNameMatch(programName, ZSTD_CAT)) { operation=zom_decompress; forceStdout=1; FIO_overwriteMode(); outFileName=stdoutmark; g_displayLevel=1; }
378 if (exeNameMatch(programName, ZSTD_GZ)) { suffix = GZ_EXTENSION; FIO_setCompressionType(FIO_gzipCompression); FIO_setRemoveSrcFile(1); } /* behave like gzip */
379 if (exeNameMatch(programName, ZSTD_GUNZIP)) { operation=zom_decompress; FIO_setRemoveSrcFile(1); } /* behave like gunzip */
380 if (exeNameMatch(programName, ZSTD_GZCAT)) { operation=zom_decompress; forceStdout=1; FIO_overwriteMode(); outFileName=stdoutmark; g_displayLevel=1; } /* behave like gzcat */
381 if (exeNameMatch(programName, ZSTD_LZMA)) { suffix = LZMA_EXTENSION; FIO_setCompressionType(FIO_lzmaCompression); FIO_setRemoveSrcFile(1); } /* behave like lzma */
382 if (exeNameMatch(programName, ZSTD_XZ)) { suffix = XZ_EXTENSION; FIO_setCompressionType(FIO_xzCompression); FIO_setRemoveSrcFile(1); } /* behave like xz */
Przemyslaw Skibinski671f28d2016-12-13 12:18:07 +0100383 memset(&compressionParams, 0, sizeof(compressionParams));
Yann Colletfcf20872016-05-29 05:16:05 +0200384
385 /* command switches */
Yann Collet11223492016-10-14 14:07:11 -0700386 for (argNb=1; argNb<argCount; argNb++) {
Yann Colletfcf20872016-05-29 05:16:05 +0200387 const char* argument = argv[argNb];
388 if(!argument) continue; /* Protection if argument empty */
389
Yann Collet743b33f2016-12-02 15:18:57 -0800390 if (nextArgumentsAreFiles==0) {
391 /* "-" means stdin/stdout */
Yann Colletf9cac7a2016-07-04 18:16:16 +0200392 if (!strcmp(argument, "-")){
393 if (!filenameIdx) {
394 filenameIdx=1, filenameTable[0]=stdinmark;
395 outFileName=stdoutmark;
Sean Purcell042ba122017-03-23 11:13:52 -0700396 g_displayLevel-=(g_displayLevel==2);
Yann Colletfcf20872016-05-29 05:16:05 +0200397 continue;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200398 } }
Yann Colletfcf20872016-05-29 05:16:05 +0200399
Yann Colletf9cac7a2016-07-04 18:16:16 +0200400 /* Decode commands (note : aggregated commands are allowed) */
401 if (argument[0]=='-') {
Yann Colletfcf20872016-05-29 05:16:05 +0200402
Yann Collet743b33f2016-12-02 15:18:57 -0800403 if (argument[1]=='-') {
404 /* long commands (--long-word) */
405 if (!strcmp(argument, "--")) { nextArgumentsAreFiles=1; continue; } /* only file names allowed from now on */
Paul Cruz9437cc72017-06-15 15:07:54 -0700406 if (!strcmp(argument, "--list")) { operation=zom_list; continue; }
Yann Collet743b33f2016-12-02 15:18:57 -0800407 if (!strcmp(argument, "--compress")) { operation=zom_compress; continue; }
408 if (!strcmp(argument, "--decompress")) { operation=zom_decompress; continue; }
409 if (!strcmp(argument, "--uncompress")) { operation=zom_decompress; continue; }
Sean Purcell680e4e02017-03-23 11:52:09 -0700410 if (!strcmp(argument, "--force")) { FIO_overwriteMode(); forceStdout=1; followLinks=1; continue; }
Sean Purcell042ba122017-03-23 11:13:52 -0700411 if (!strcmp(argument, "--version")) { g_displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); }
412 if (!strcmp(argument, "--help")) { g_displayOut=stdout; CLEAN_RETURN(usage_advanced(programName)); }
413 if (!strcmp(argument, "--verbose")) { g_displayLevel++; continue; }
414 if (!strcmp(argument, "--quiet")) { g_displayLevel--; continue; }
415 if (!strcmp(argument, "--stdout")) { forceStdout=1; outFileName=stdoutmark; g_displayLevel-=(g_displayLevel==2); continue; }
Yann Collet743b33f2016-12-02 15:18:57 -0800416 if (!strcmp(argument, "--ultra")) { ultra=1; continue; }
417 if (!strcmp(argument, "--check")) { FIO_setChecksumFlag(2); continue; }
418 if (!strcmp(argument, "--no-check")) { FIO_setChecksumFlag(0); continue; }
419 if (!strcmp(argument, "--sparse")) { FIO_setSparseWrite(2); continue; }
420 if (!strcmp(argument, "--no-sparse")) { FIO_setSparseWrite(0); continue; }
421 if (!strcmp(argument, "--test")) { operation=zom_test; continue; }
422 if (!strcmp(argument, "--train")) { operation=zom_train; outFileName=g_defaultDictName; continue; }
Yann Collet96aa3012017-03-24 16:04:29 -0700423 if (!strcmp(argument, "--maxdict")) { nextArgumentIsMaxDict=1; lastCommand=1; continue; } /* kept available for compatibility with old syntax ; will be removed one day */
424 if (!strcmp(argument, "--dictID")) { nextArgumentIsDictID=1; lastCommand=1; continue; } /* kept available for compatibility with old syntax ; will be removed one day */
Yann Collet743b33f2016-12-02 15:18:57 -0800425 if (!strcmp(argument, "--no-dictID")) { FIO_setDictIDFlag(0); continue; }
426 if (!strcmp(argument, "--keep")) { FIO_setRemoveSrcFile(0); continue; }
427 if (!strcmp(argument, "--rm")) { FIO_setRemoveSrcFile(1); continue; }
Przemyslaw Skibinski0665a352017-02-07 20:12:59 +0100428 if (!strcmp(argument, "--priority=rt")) { setRealTimePrio = 1; continue; }
Yann Colletc1c040e2017-03-01 16:49:20 -0800429#ifdef ZSTD_GZCOMPRESS
Przemyslaw Skibinski97041952017-02-14 09:47:29 +0100430 if (!strcmp(argument, "--format=gzip")) { suffix = GZ_EXTENSION; FIO_setCompressionType(FIO_gzipCompression); continue; }
Yann Colletc1c040e2017-03-01 16:49:20 -0800431#endif
Nick Terrellaa8bcf32017-03-13 18:11:07 -0700432#ifdef ZSTD_LZMACOMPRESS
433 if (!strcmp(argument, "--format=lzma")) { suffix = LZMA_EXTENSION; FIO_setCompressionType(FIO_lzmaCompression); continue; }
434 if (!strcmp(argument, "--format=xz")) { suffix = XZ_EXTENSION; FIO_setCompressionType(FIO_xzCompression); continue; }
435#endif
Sean Purcell4de86322017-04-24 16:48:25 -0700436#ifdef ZSTD_LZ4COMPRESS
437 if (!strcmp(argument, "--format=lz4")) { suffix = LZ4_EXTENSION; FIO_setCompressionType(FIO_lz4Compression); continue; }
438#endif
Yann Collet743b33f2016-12-02 15:18:57 -0800439
440 /* long commands with arguments */
Yann Colletc1c040e2017-03-01 16:49:20 -0800441#ifndef ZSTD_NODICT
Nick Terrellf376d472017-05-01 23:40:20 -0700442 if (longCommandWArg(&argument, "--train-cover")) {
443 operation = zom_train;
444 outFileName = g_defaultDictName;
445 cover = 1;
Nick Terrelldf8415c2016-12-31 21:08:24 -0800446 /* Allow optional arguments following an = */
447 if (*argument == 0) { memset(&coverParams, 0, sizeof(coverParams)); }
448 else if (*argument++ != '=') { CLEAN_RETURN(badusage(programName)); }
449 else if (!parseCoverParameters(argument, &coverParams)) { CLEAN_RETURN(badusage(programName)); }
450 continue;
451 }
Nick Terrellf376d472017-05-01 23:40:20 -0700452 if (longCommandWArg(&argument, "--train-legacy")) {
453 operation = zom_train;
454 outFileName = g_defaultDictName;
455 cover = 0;
456 /* Allow optional arguments following an = */
457 if (*argument == 0) { continue; }
458 else if (*argument++ != '=') { CLEAN_RETURN(badusage(programName)); }
459 else if (!parseLegacyParameters(argument, &dictSelect)) { CLEAN_RETURN(badusage(programName)); }
460 continue;
461 }
Nick Terrelldf8415c2016-12-31 21:08:24 -0800462#endif
Yann Collet230d7ac2017-04-21 11:38:13 -0700463 if (longCommandWArg(&argument, "--threads=")) { nbThreads = readU32FromChar(&argument); continue; }
Yann Collet743b33f2016-12-02 15:18:57 -0800464 if (longCommandWArg(&argument, "--memlimit=")) { memLimit = readU32FromChar(&argument); continue; }
465 if (longCommandWArg(&argument, "--memory=")) { memLimit = readU32FromChar(&argument); continue; }
466 if (longCommandWArg(&argument, "--memlimit-decompress=")) { memLimit = readU32FromChar(&argument); continue; }
Yann Collet6be23372017-01-30 11:17:26 -0800467 if (longCommandWArg(&argument, "--block-size=")) { blockSize = readU32FromChar(&argument); continue; }
Yann Collet96aa3012017-03-24 16:04:29 -0700468 if (longCommandWArg(&argument, "--maxdict=")) { maxDictSize = readU32FromChar(&argument); continue; }
469 if (longCommandWArg(&argument, "--dictID=")) { dictID = readU32FromChar(&argument); continue; }
Przemyslaw Skibinski671f28d2016-12-13 12:18:07 +0100470 if (longCommandWArg(&argument, "--zstd=")) { if (!parseCompressionParameters(argument, &compressionParams)) CLEAN_RETURN(badusage(programName)); continue; }
Yann Collet743b33f2016-12-02 15:18:57 -0800471 /* fall-through, will trigger bad_usage() later on */
472 }
473
474 argument++;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200475 while (argument[0]!=0) {
Yann Collet27b5ac62016-09-21 14:20:56 +0200476 if (lastCommand) {
477 DISPLAY("error : command must be followed by argument \n");
Przemyslaw Skibinski684858e2017-02-21 18:17:24 +0100478 CLEAN_RETURN(1);
Yann Collet27b5ac62016-09-21 14:20:56 +0200479 }
Yann Colletc8431422016-09-01 15:05:57 -0700480#ifndef ZSTD_NOCOMPRESS
Yann Colletf9cac7a2016-07-04 18:16:16 +0200481 /* compression Level */
482 if ((*argument>='0') && (*argument<='9')) {
Yann Colletfe0590f2016-08-12 18:04:15 +0200483 dictCLevel = cLevel = readU32FromChar(&argument);
Yann Colletf9cac7a2016-07-04 18:16:16 +0200484 continue;
485 }
Yann Colletc8431422016-09-01 15:05:57 -0700486#endif
Yann Colletfcf20872016-05-29 05:16:05 +0200487
Yann Colletf9cac7a2016-07-04 18:16:16 +0200488 switch(argument[0])
489 {
490 /* Display help */
Sean Purcell042ba122017-03-23 11:13:52 -0700491 case 'V': g_displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); /* Version Only */
Yann Colletf9cac7a2016-07-04 18:16:16 +0200492 case 'H':
Sean Purcell042ba122017-03-23 11:13:52 -0700493 case 'h': g_displayOut=stdout; CLEAN_RETURN(usage_advanced(programName));
Yann Colletfcf20872016-05-29 05:16:05 +0200494
Yann Collet22de81e2016-10-28 13:58:31 -0700495 /* Compress */
496 case 'z': operation=zom_compress; argument++; break;
497
Yann Colletf9cac7a2016-07-04 18:16:16 +0200498 /* Decoding */
Yann Collet2a826e52016-12-06 17:56:20 -0800499 case 'd':
500#ifndef ZSTD_NOBENCH
Yann Colletab7a5792016-12-28 16:11:09 +0100501 if (operation==zom_bench) { BMK_setDecodeOnlyMode(1); argument++; break; } /* benchmark decode (hidden option) */
Yann Collet2a826e52016-12-06 17:56:20 -0800502#endif
Yann Colletd9465012016-12-06 16:49:23 -0800503 operation=zom_decompress; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200504
Yann Colletf9cac7a2016-07-04 18:16:16 +0200505 /* Force stdout, even if stdout==console */
Yann Colletfe0590f2016-08-12 18:04:15 +0200506 case 'c': forceStdout=1; outFileName=stdoutmark; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200507
Yann Colletf9cac7a2016-07-04 18:16:16 +0200508 /* Use file content as dictionary */
Yann Collet27b5ac62016-09-21 14:20:56 +0200509 case 'D': nextEntryIsDictionary = 1; lastCommand = 1; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200510
Yann Colletf9cac7a2016-07-04 18:16:16 +0200511 /* Overwrite */
Sean Purcell680e4e02017-03-23 11:52:09 -0700512 case 'f': FIO_overwriteMode(); forceStdout=1; followLinks=1; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200513
Yann Colletf9cac7a2016-07-04 18:16:16 +0200514 /* Verbose mode */
Sean Purcell042ba122017-03-23 11:13:52 -0700515 case 'v': g_displayLevel++; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200516
Yann Colletf9cac7a2016-07-04 18:16:16 +0200517 /* Quiet mode */
Sean Purcell042ba122017-03-23 11:13:52 -0700518 case 'q': g_displayLevel--; argument++; break;
Yann Collet2c4acda2016-06-02 17:05:50 +0200519
Yann Collet2e63a872017-05-02 15:40:42 -0700520 /* keep source file (default) */
Yann Colletf9cac7a2016-07-04 18:16:16 +0200521 case 'k': FIO_setRemoveSrcFile(0); argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200522
Yann Colletf9cac7a2016-07-04 18:16:16 +0200523 /* Checksum */
Yann Collet2e63a872017-05-02 15:40:42 -0700524 case 'C': FIO_setChecksumFlag(2); argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200525
Yann Colletf9cac7a2016-07-04 18:16:16 +0200526 /* test compressed file */
Yann Collet22de81e2016-10-28 13:58:31 -0700527 case 't': operation=zom_test; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200528
Yann Collet2cac5b32016-07-13 14:15:08 +0200529 /* destination file name */
Yann Collet27b5ac62016-09-21 14:20:56 +0200530 case 'o': nextArgumentIsOutFileName=1; lastCommand=1; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200531
Yann Colletd4cda272016-10-14 13:13:13 -0700532 /* limit decompression memory */
533 case 'M':
534 argument++;
535 memLimit = readU32FromChar(&argument);
536 break;
Paul Cruz901435e2017-06-05 14:45:31 -0700537 case 'l': operation=zom_list; argument++; break;
Yann Colletc4cc9bf2016-09-13 17:50:08 +0200538#ifdef UTIL_HAS_CREATEFILELIST
Yann Colletf9cac7a2016-07-04 18:16:16 +0200539 /* recursive */
540 case 'r': recursive=1; argument++; break;
Yann Colletc4cc9bf2016-09-13 17:50:08 +0200541#endif
Yann Colletf9cac7a2016-07-04 18:16:16 +0200542
Yann Colletc8431422016-09-01 15:05:57 -0700543#ifndef ZSTD_NOBENCH
Yann Colletf9cac7a2016-07-04 18:16:16 +0200544 /* Benchmark */
Yann Collet500014a2017-01-19 16:59:56 -0800545 case 'b':
546 operation=zom_bench;
547 argument++;
548 break;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200549
550 /* range bench (benchmark only) */
551 case 'e':
Yann Collet500014a2017-01-19 16:59:56 -0800552 /* compression Level */
553 argument++;
554 cLevelLast = readU32FromChar(&argument);
555 break;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200556
557 /* Modify Nb Iterations (benchmark only) */
558 case 'i':
Yann Colletfcf20872016-05-29 05:16:05 +0200559 argument++;
Yann Collet500014a2017-01-19 16:59:56 -0800560 bench_nbSeconds = readU32FromChar(&argument);
Yann Colletfcf20872016-05-29 05:16:05 +0200561 break;
562
Yann Colletf9cac7a2016-07-04 18:16:16 +0200563 /* cut input into blocks (benchmark only) */
564 case 'B':
565 argument++;
Yann Collet500014a2017-01-19 16:59:56 -0800566 blockSize = readU32FromChar(&argument);
Yann Colletf9cac7a2016-07-04 18:16:16 +0200567 break;
Yann Collet74745262017-01-02 02:05:45 +0100568
Yann Collet500014a2017-01-19 16:59:56 -0800569#endif /* ZSTD_NOBENCH */
570
Yann Collet74745262017-01-02 02:05:45 +0100571 /* nb of threads (hidden option) */
572 case 'T':
573 argument++;
Yann Collet500014a2017-01-19 16:59:56 -0800574 nbThreads = readU32FromChar(&argument);
Yann Collet74745262017-01-02 02:05:45 +0100575 break;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200576
577 /* Dictionary Selection level */
578 case 's':
579 argument++;
580 dictSelect = readU32FromChar(&argument);
581 break;
582
583 /* Pause at the end (-p) or set an additional param (-p#) (hidden option) */
584 case 'p': argument++;
Yann Colletc8431422016-09-01 15:05:57 -0700585#ifndef ZSTD_NOBENCH
Yann Colletf9cac7a2016-07-04 18:16:16 +0200586 if ((*argument>='0') && (*argument<='9')) {
587 BMK_setAdditionalParam(readU32FromChar(&argument));
588 } else
Yann Colletc8431422016-09-01 15:05:57 -0700589#endif
Yann Colletf9cac7a2016-07-04 18:16:16 +0200590 main_pause=1;
591 break;
592 /* unknown command */
593 default : CLEAN_RETURN(badusage(programName));
Yann Colletfcf20872016-05-29 05:16:05 +0200594 }
Yann Colletfcf20872016-05-29 05:16:05 +0200595 }
Yann Colletf9cac7a2016-07-04 18:16:16 +0200596 continue;
597 } /* if (argument[0]=='-') */
598
Yann Collet96aa3012017-03-24 16:04:29 -0700599 if (nextArgumentIsMaxDict) { /* kept available for compatibility with old syntax ; will be removed one day */
Yann Colletf9cac7a2016-07-04 18:16:16 +0200600 nextArgumentIsMaxDict = 0;
Yann Collet27b5ac62016-09-21 14:20:56 +0200601 lastCommand = 0;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200602 maxDictSize = readU32FromChar(&argument);
Yann Colletf9cac7a2016-07-04 18:16:16 +0200603 continue;
Yann Colletfcf20872016-05-29 05:16:05 +0200604 }
Yann Colletf9cac7a2016-07-04 18:16:16 +0200605
Yann Collet96aa3012017-03-24 16:04:29 -0700606 if (nextArgumentIsDictID) { /* kept available for compatibility with old syntax ; will be removed one day */
Yann Colletf9cac7a2016-07-04 18:16:16 +0200607 nextArgumentIsDictID = 0;
Yann Collet27b5ac62016-09-21 14:20:56 +0200608 lastCommand = 0;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200609 dictID = readU32FromChar(&argument);
610 continue;
611 }
612
613 } /* if (nextArgumentIsAFile==0) */
Yann Colletfcf20872016-05-29 05:16:05 +0200614
615 if (nextEntryIsDictionary) {
616 nextEntryIsDictionary = 0;
Yann Collet27b5ac62016-09-21 14:20:56 +0200617 lastCommand = 0;
Yann Colletfcf20872016-05-29 05:16:05 +0200618 dictFileName = argument;
619 continue;
620 }
621
622 if (nextArgumentIsOutFileName) {
623 nextArgumentIsOutFileName = 0;
Yann Collet27b5ac62016-09-21 14:20:56 +0200624 lastCommand = 0;
Yann Colletfcf20872016-05-29 05:16:05 +0200625 outFileName = argument;
626 if (!strcmp(outFileName, "-")) outFileName = stdoutmark;
627 continue;
628 }
629
Yann Colletfcf20872016-05-29 05:16:05 +0200630 /* add filename to list */
631 filenameTable[filenameIdx++] = argument;
632 }
633
Przemyslaw Skibinski684858e2017-02-21 18:17:24 +0100634 if (lastCommand) { DISPLAY("error : command must be followed by argument \n"); CLEAN_RETURN(1); } /* forgotten argument */
Yann Collet714464f2016-09-21 16:05:03 +0200635
Yann Colletfcf20872016-05-29 05:16:05 +0200636 /* Welcome message (if verbose) */
637 DISPLAYLEVEL(3, WELCOME_MESSAGE);
Przemyslaw Skibinskib0f36632016-12-16 15:41:18 +0100638#ifdef _POSIX_C_SOURCE
639 DISPLAYLEVEL(4, "_POSIX_C_SOURCE defined: %ldL\n", (long) _POSIX_C_SOURCE);
640#endif
641#ifdef _POSIX_VERSION
642 DISPLAYLEVEL(4, "_POSIX_VERSION defined: %ldL\n", (long) _POSIX_VERSION);
643#endif
644#ifdef PLATFORM_POSIX_VERSION
645 DISPLAYLEVEL(4, "PLATFORM_POSIX_VERSION defined: %ldL\n", (long) PLATFORM_POSIX_VERSION);
646#endif
Yann Colletfcf20872016-05-29 05:16:05 +0200647
Sean Purcellafa48512017-04-13 12:28:28 -0700648 if (nbThreads == 0) {
649 /* try to guess */
650 nbThreads = UTIL_countPhysicalCores();
651 DISPLAYLEVEL(3, "Note: %d physical core(s) detected\n", nbThreads);
652 }
Sean Purcell680e4e02017-03-23 11:52:09 -0700653
Sean Purcelldee08ca2017-03-23 12:09:35 -0700654 g_utilDisplayLevel = g_displayLevel;
Sean Purcell680e4e02017-03-23 11:52:09 -0700655 if (!followLinks) {
656 unsigned u;
657 for (u=0, fileNamesNb=0; u<filenameIdx; u++) {
658 if (UTIL_isLink(filenameTable[u])) {
659 DISPLAYLEVEL(2, "Warning : %s is a symbolic link, ignoring\n", filenameTable[u]);
660 } else {
661 filenameTable[fileNamesNb++] = filenameTable[u];
662 }
663 }
664 filenameIdx = fileNamesNb;
665 }
Yann Colletfcf20872016-05-29 05:16:05 +0200666#ifdef UTIL_HAS_CREATEFILELIST
Yann Collet0977f7e2016-09-21 12:24:43 +0200667 if (recursive) { /* at this stage, filenameTable is a list of paths, which can contain both files and directories */
Sean Purcell680e4e02017-03-23 11:52:09 -0700668 extendedFileList = UTIL_createFileList(filenameTable, filenameIdx, &fileNamesBuf, &fileNamesNb, followLinks);
Yann Collet0977f7e2016-09-21 12:24:43 +0200669 if (extendedFileList) {
Yann Collet415251c2016-08-01 14:26:49 +0200670 unsigned u;
Yann Collet0977f7e2016-09-21 12:24:43 +0200671 for (u=0; u<fileNamesNb; u++) DISPLAYLEVEL(4, "%u %s\n", u, extendedFileList[u]);
Yann Colletfcf20872016-05-29 05:16:05 +0200672 free((void*)filenameTable);
Yann Collet0977f7e2016-09-21 12:24:43 +0200673 filenameTable = extendedFileList;
Yann Colletfcf20872016-05-29 05:16:05 +0200674 filenameIdx = fileNamesNb;
675 }
676 }
677#endif
Paul Cruz901435e2017-06-05 14:45:31 -0700678 if(operation==zom_list){
Paul Cruze2089922017-06-15 12:27:32 -0700679 g_displayOut = stdout;
Paul Cruz607ee9f2017-06-14 13:23:36 -0700680 if(filenameIdx==0){
681 DISPLAY("No files given\n");
682 CLEAN_RETURN(0);
683 }
Paul Cruz618a7b62017-06-12 16:53:50 -0700684 DISPLAY("===========================================\n");
685 DISPLAY("Printing information about compressed files\n");
686 DISPLAY("===========================================\n");
Paul Cruz901435e2017-06-05 14:45:31 -0700687 DISPLAY("Number of files listed: %d\n", filenameIdx);
Paul Cruz607ee9f2017-06-14 13:23:36 -0700688 {
689 unsigned u;
690 for(u=0; u<filenameIdx;u++){
691 FIO_listFile(filenameTable[u],g_displayLevel);
692 }
Paul Cruz901435e2017-06-05 14:45:31 -0700693 }
694 CLEAN_RETURN(0);
695 }
Yann Colletfcf20872016-05-29 05:16:05 +0200696 /* Check if benchmark is selected */
Yann Collet22de81e2016-10-28 13:58:31 -0700697 if (operation==zom_bench) {
Yann Colletfcf20872016-05-29 05:16:05 +0200698#ifndef ZSTD_NOBENCH
Sean Purcell042ba122017-03-23 11:13:52 -0700699 BMK_setNotificationLevel(g_displayLevel);
Yann Collet500014a2017-01-19 16:59:56 -0800700 BMK_setBlockSize(blockSize);
701 BMK_setNbThreads(nbThreads);
702 BMK_setNbSeconds(bench_nbSeconds);
Przemyslaw Skibinskid05014c2017-02-07 16:48:01 +0100703 BMK_benchFiles(filenameTable, filenameIdx, dictFileName, cLevel, cLevelLast, &compressionParams, setRealTimePrio);
Yann Colletfcf20872016-05-29 05:16:05 +0200704#endif
Yann Collet3dc85ba2017-02-02 16:19:09 -0800705 (void)bench_nbSeconds;
Yann Colletfcf20872016-05-29 05:16:05 +0200706 goto _end;
707 }
708
709 /* Check if dictionary builder is selected */
Yann Collet22de81e2016-10-28 13:58:31 -0700710 if (operation==zom_train) {
Yann Colletfcf20872016-05-29 05:16:05 +0200711#ifndef ZSTD_NODICT
Nick Terrelldf8415c2016-12-31 21:08:24 -0800712 if (cover) {
Nick Terrellf376d472017-05-01 23:40:20 -0700713 int const optimize = !coverParams.k || !coverParams.d;
Nick Terrell2fe91262017-01-27 11:56:02 -0800714 coverParams.nbThreads = nbThreads;
Nick Terrelldf8415c2016-12-31 21:08:24 -0800715 coverParams.compressionLevel = dictCLevel;
Sean Purcell042ba122017-03-23 11:13:52 -0700716 coverParams.notificationLevel = g_displayLevel;
Nick Terrelldf8415c2016-12-31 21:08:24 -0800717 coverParams.dictID = dictID;
Nick Terrellf376d472017-05-01 23:40:20 -0700718 operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, NULL, &coverParams, optimize);
Nick Terrelldf8415c2016-12-31 21:08:24 -0800719 } else {
720 ZDICT_params_t dictParams;
721 memset(&dictParams, 0, sizeof(dictParams));
722 dictParams.compressionLevel = dictCLevel;
723 dictParams.selectivityLevel = dictSelect;
Sean Purcell042ba122017-03-23 11:13:52 -0700724 dictParams.notificationLevel = g_displayLevel;
Nick Terrelldf8415c2016-12-31 21:08:24 -0800725 dictParams.dictID = dictID;
Yann Colletf332ece2017-03-23 16:24:02 -0700726 operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, &dictParams, NULL, 0);
Nick Terrelldf8415c2016-12-31 21:08:24 -0800727 }
Yann Colletfcf20872016-05-29 05:16:05 +0200728#endif
729 goto _end;
730 }
731
732 /* No input filename ==> use stdin and stdout */
Yann Collet87c18b22016-08-26 01:43:47 +0200733 filenameIdx += !filenameIdx; /* filenameTable[0] is stdin by default */
734 if (!strcmp(filenameTable[0], stdinmark) && !outFileName) outFileName = stdoutmark; /* when input is stdin, default output is stdout */
Yann Colletfcf20872016-05-29 05:16:05 +0200735
736 /* Check if input/output defined as console; trigger an error in this case */
737 if (!strcmp(filenameTable[0], stdinmark) && IS_CONSOLE(stdin) ) CLEAN_RETURN(badusage(programName));
Sean Purcellb8e52d32017-03-16 16:06:03 -0700738 if (outFileName && !strcmp(outFileName, stdoutmark) && IS_CONSOLE(stdout) && !strcmp(filenameTable[0], stdinmark) && !forceStdout && operation!=zom_decompress)
Yann Colletfcf20872016-05-29 05:16:05 +0200739 CLEAN_RETURN(badusage(programName));
740
741 /* user-selected output filename, only possible with a single file */
742 if (outFileName && strcmp(outFileName,stdoutmark) && strcmp(outFileName,nulmark) && (filenameIdx>1)) {
743 DISPLAY("Too many files (%u) on the command line. \n", filenameIdx);
744 CLEAN_RETURN(filenameIdx);
745 }
746
inikep23cec872016-10-05 11:56:22 +0200747#ifndef ZSTD_NOCOMPRESS
Yann Colletfe0590f2016-08-12 18:04:15 +0200748 /* check compression level limits */
749 { int const maxCLevel = ultra ? ZSTD_maxCLevel() : ZSTDCLI_CLEVEL_MAX;
750 if (cLevel > maxCLevel) {
751 DISPLAYLEVEL(2, "Warning : compression level higher than max, reduced to %i \n", maxCLevel);
752 cLevel = maxCLevel;
753 } }
inikep23cec872016-10-05 11:56:22 +0200754#endif
Yann Colletfe0590f2016-08-12 18:04:15 +0200755
Yann Colletf22adae2017-01-19 13:46:30 -0800756 /* No status message in pipe mode (stdin - stdout) or multi-files mode */
Sean Purcell042ba122017-03-23 11:13:52 -0700757 if (!strcmp(filenameTable[0], stdinmark) && outFileName && !strcmp(outFileName,stdoutmark) && (g_displayLevel==2)) g_displayLevel=1;
758 if ((filenameIdx>1) & (g_displayLevel==2)) g_displayLevel=1;
Yann Colletfcf20872016-05-29 05:16:05 +0200759
760 /* IO Stream/File */
Sean Purcell042ba122017-03-23 11:13:52 -0700761 FIO_setNotificationLevel(g_displayLevel);
Yann Collet22de81e2016-10-28 13:58:31 -0700762 if (operation==zom_compress) {
Yann Collet0977f7e2016-09-21 12:24:43 +0200763#ifndef ZSTD_NOCOMPRESS
Yann Collet500014a2017-01-19 16:59:56 -0800764 FIO_setNbThreads(nbThreads);
Yann Collet512cbe82017-01-24 17:02:26 -0800765 FIO_setBlockSize((U32)blockSize);
Yann Collet8d8513f2017-01-30 14:37:08 -0800766 if (g_overlapLog!=OVERLAP_LOG_DEFAULT) FIO_setOverlapLog(g_overlapLog);
Yann Collet993060e2016-09-21 16:46:08 +0200767 if ((filenameIdx==1) && outFileName)
Przemyslaw Skibinski8349d672016-12-13 13:24:59 +0100768 operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel, &compressionParams);
Yann Colletfcf20872016-05-29 05:16:05 +0200769 else
Przemyslaw Skibinskicb563062017-02-08 17:37:14 +0100770 operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, outFileName ? outFileName : suffix, dictFileName, cLevel, &compressionParams);
Yann Collet0977f7e2016-09-21 12:24:43 +0200771#else
772 DISPLAY("Compression not supported\n");
Yann Colletfcf20872016-05-29 05:16:05 +0200773#endif
Yann Collet22de81e2016-10-28 13:58:31 -0700774 } else { /* decompression or test */
Yann Colletfcf20872016-05-29 05:16:05 +0200775#ifndef ZSTD_NODECOMPRESS
Yann Collet22de81e2016-10-28 13:58:31 -0700776 if (operation==zom_test) { outFileName=nulmark; FIO_setRemoveSrcFile(0); } /* test mode */
Yann Colletd4cda272016-10-14 13:13:13 -0700777 FIO_setMemLimit(memLimit);
Yann Colletfcf20872016-05-29 05:16:05 +0200778 if (filenameIdx==1 && outFileName)
779 operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName);
780 else
781 operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, outFileName ? outFileName : ZSTD_EXTENSION, dictFileName);
782#else
783 DISPLAY("Decompression not supported\n");
784#endif
785 }
786
787_end:
788 if (main_pause) waitEnter();
Yann Colletfcf20872016-05-29 05:16:05 +0200789#ifdef UTIL_HAS_CREATEFILELIST
Yann Collet0977f7e2016-09-21 12:24:43 +0200790 if (extendedFileList)
791 UTIL_freeFileList(extendedFileList, fileNamesBuf);
Yann Colletfcf20872016-05-29 05:16:05 +0200792 else
793#endif
794 free((void*)filenameTable);
795 return operationResult;
796}