blob: 29bcc776359f0906f81c9eaf60352c3031eb78df [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
23/*-************************************
Yann Collet52afb392016-11-16 08:50:54 -080024* Dependencies
Yann Colletfcf20872016-05-29 05:16:05 +020025**************************************/
Yann Collet92c986b2016-07-04 01:37:30 +020026#include "util.h" /* Compiler options, UTIL_HAS_CREATEFILELIST */
Yann Colletfcf20872016-05-29 05:16:05 +020027#include <string.h> /* strcmp, strlen */
Yann Colletf9cac7a2016-07-04 18:16:16 +020028#include <errno.h> /* errno */
Yann Colletfcf20872016-05-29 05:16:05 +020029#include "fileio.h"
30#ifndef ZSTD_NOBENCH
Przemyslaw Skibinski26306fc2016-11-03 11:38:01 +010031# include "bench.h" /* BMK_benchFiles, BMK_SetNbSeconds */
Yann Colletfcf20872016-05-29 05:16:05 +020032#endif
Yann Colletfcf20872016-05-29 05:16:05 +020033#ifndef ZSTD_NODICT
34# include "dibio.h"
35#endif
Yann Colletd3b7f8d2016-06-04 19:47:02 +020036#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_maxCLevel */
37#include "zstd.h" /* ZSTD_VERSION_STRING */
Yann Colletfcf20872016-05-29 05:16:05 +020038
39
Yann Colletfcf20872016-05-29 05:16:05 +020040/*-************************************
41* OS-specific Includes
42**************************************/
43#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
44# include <io.h> /* _isatty */
45# define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream))
Yann Collet0977f7e2016-09-21 12:24:43 +020046#elif defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE) || (defined(__APPLE__) && defined(__MACH__)) /* https://sourceforge.net/p/predef/wiki/OperatingSystems/ */
47# include <unistd.h> /* isatty */
48# define IS_CONSOLE(stdStream) isatty(fileno(stdStream))
Yann Colletfcf20872016-05-29 05:16:05 +020049#else
Yann Collet0977f7e2016-09-21 12:24:43 +020050# define IS_CONSOLE(stdStream) 0
Yann Colletfcf20872016-05-29 05:16:05 +020051#endif
52
53
54/*-************************************
55* Constants
56**************************************/
57#define COMPRESSOR_NAME "zstd command line interface"
58#ifndef ZSTD_VERSION
59# define ZSTD_VERSION "v" ZSTD_VERSION_STRING
60#endif
61#define AUTHOR "Yann Collet"
62#define WELCOME_MESSAGE "*** %s %i-bits %s, by %s ***\n", COMPRESSOR_NAME, (int)(sizeof(size_t)*8), ZSTD_VERSION, AUTHOR
63
64#define ZSTD_EXTENSION ".zst"
65#define ZSTD_CAT "zstdcat"
66#define ZSTD_UNZSTD "unzstd"
67
68#define KB *(1 <<10)
69#define MB *(1 <<20)
70#define GB *(1U<<30)
71
David Lamac43e952016-08-12 14:49:05 -070072#define DEFAULT_DISPLAY_LEVEL 2
73
Yann Colletfcf20872016-05-29 05:16:05 +020074static const char* g_defaultDictName = "dictionary";
75static const unsigned g_defaultMaxDictSize = 110 KB;
Yann Colletc8431422016-09-01 15:05:57 -070076static const int g_defaultDictCLevel = 3;
Yann Colletfcf20872016-05-29 05:16:05 +020077static const unsigned g_defaultSelectivityLevel = 9;
78
79
80/*-************************************
81* Display Macros
82**************************************/
83#define DISPLAY(...) fprintf(displayOut, __VA_ARGS__)
84#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
85static FILE* displayOut;
David Lamac43e952016-08-12 14:49:05 -070086static unsigned displayLevel = DEFAULT_DISPLAY_LEVEL; /* 0 : no display, 1: errors, 2 : + result + interaction + warnings, 3 : + progression, 4 : + information */
Yann Colletfcf20872016-05-29 05:16:05 +020087
88
89/*-************************************
90* Command Line
91**************************************/
92static int usage(const char* programName)
93{
94 DISPLAY( "Usage :\n");
95 DISPLAY( " %s [args] [FILE(s)] [-o file]\n", programName);
96 DISPLAY( "\n");
97 DISPLAY( "FILE : a filename\n");
98 DISPLAY( " with no FILE, or when FILE is - , read standard input\n");
99 DISPLAY( "Arguments :\n");
100#ifndef ZSTD_NOCOMPRESS
inikep5a548702016-08-18 09:00:25 +0200101 DISPLAY( " -# : # compression level (1-%d, default:%d) \n", ZSTDCLI_CLEVEL_MAX, ZSTDCLI_CLEVEL_DEFAULT);
Yann Colletfcf20872016-05-29 05:16:05 +0200102#endif
103#ifndef ZSTD_NODECOMPRESS
104 DISPLAY( " -d : decompression \n");
105#endif
106 DISPLAY( " -D file: use `file` as Dictionary \n");
107 DISPLAY( " -o file: result stored into `file` (only if 1 input file) \n");
108 DISPLAY( " -f : overwrite output without prompting \n");
Yann Colleta7a5d772016-07-02 00:37:32 +0200109 DISPLAY( "--rm : remove source file(s) after successful de/compression \n");
Yann Colletd916c902016-07-04 00:42:58 +0200110 DISPLAY( " -k : preserve source file(s) (default) \n");
Yann Colletfcf20872016-05-29 05:16:05 +0200111 DISPLAY( " -h/-H : display help/long help and exit\n");
112 return 0;
113}
114
115static int usage_advanced(const char* programName)
116{
117 DISPLAY(WELCOME_MESSAGE);
118 usage(programName);
119 DISPLAY( "\n");
120 DISPLAY( "Advanced arguments :\n");
121 DISPLAY( " -V : display Version number and exit\n");
David Lamac43e952016-08-12 14:49:05 -0700122 DISPLAY( " -v : verbose mode; specify multiple times to increase log level (default:%d)\n", DEFAULT_DISPLAY_LEVEL);
Yann Colletfcf20872016-05-29 05:16:05 +0200123 DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n");
124 DISPLAY( " -c : force write to standard output, even if it is the console\n");
125#ifdef UTIL_HAS_CREATEFILELIST
126 DISPLAY( " -r : operate recursively on directories\n");
127#endif
128#ifndef ZSTD_NOCOMPRESS
Yann Colletfe0590f2016-08-12 18:04:15 +0200129 DISPLAY( "--ultra : enable levels beyond %i, up to %i (requires more memory)\n", ZSTDCLI_CLEVEL_MAX, ZSTD_maxCLevel());
Yann Colletb09b12c2016-06-09 22:59:51 +0200130 DISPLAY( "--no-dictID : don't write dictID into header (dictionary compression)\n");
Yann Colletc98f8e72016-06-20 16:31:24 +0200131 DISPLAY( "--[no-]check : integrity check (default:enabled)\n");
Yann Colletfcf20872016-05-29 05:16:05 +0200132#endif
Yann Collet6381e992016-05-31 02:29:45 +0200133#ifndef ZSTD_NODECOMPRESS
Yann Collet2c4acda2016-06-02 17:05:50 +0200134 DISPLAY( "--test : test compressed file integrity \n");
Yann Colletb09b12c2016-06-09 22:59:51 +0200135 DISPLAY( "--[no-]sparse : sparse mode (default:enabled on file, disabled on stdout)\n");
Yann Collet6381e992016-05-31 02:29:45 +0200136#endif
Yann Colletd4cda272016-10-14 13:13:13 -0700137 DISPLAY( " -M# : Set a memory usage limit for decompression \n");
Yann Collet60038942016-09-16 18:52:52 +0200138 DISPLAY( "-- : All arguments after \"--\" are treated as files \n");
Yann Colletfcf20872016-05-29 05:16:05 +0200139#ifndef ZSTD_NODICT
140 DISPLAY( "\n");
141 DISPLAY( "Dictionary builder :\n");
Yann Colletb09b12c2016-06-09 22:59:51 +0200142 DISPLAY( "--train ## : create a dictionary from a training set of files \n");
143 DISPLAY( " -o file : `file` is dictionary name (default: %s) \n", g_defaultDictName);
144 DISPLAY( "--maxdict ## : limit dictionary to specified size (default : %u) \n", g_defaultMaxDictSize);
Yann Colletfcf20872016-05-29 05:16:05 +0200145 DISPLAY( " -s# : dictionary selectivity level (default: %u)\n", g_defaultSelectivityLevel);
Yann Colletb09b12c2016-06-09 22:59:51 +0200146 DISPLAY( "--dictID ## : force dictionary ID to specified value (default: random)\n");
Yann Colletfcf20872016-05-29 05:16:05 +0200147#endif
148#ifndef ZSTD_NOBENCH
149 DISPLAY( "\n");
150 DISPLAY( "Benchmark arguments :\n");
151 DISPLAY( " -b# : benchmark file(s), using # compression level (default : 1) \n");
152 DISPLAY( " -e# : test all compression levels from -bX to # (default: 1)\n");
Yann Colleta9febe82016-08-01 13:37:17 +0200153 DISPLAY( " -i# : minimum evaluation time in seconds (default : 3s)\n");
Yann Colletfcf20872016-05-29 05:16:05 +0200154 DISPLAY( " -B# : cut file into independent blocks of size # (default: no block)\n");
155#endif
156 return 0;
157}
158
159static int badusage(const char* programName)
160{
161 DISPLAYLEVEL(1, "Incorrect parameters\n");
162 if (displayLevel >= 1) usage(programName);
163 return 1;
164}
165
Yann Colletfcf20872016-05-29 05:16:05 +0200166static void waitEnter(void)
167{
168 int unused;
169 DISPLAY("Press enter to continue...\n");
170 unused = getchar();
171 (void)unused;
172}
173
Yann Collet1dd79612016-06-03 15:14:09 +0200174/*! readU32FromChar() :
Yann Colletd4cda272016-10-14 13:13:13 -0700175 @return : unsigned integer value read from input in `char` format
176 allows and interprets K, KB, KiB, M, MB and MiB suffix.
Yann Collet1dd79612016-06-03 15:14:09 +0200177 Will also modify `*stringPtr`, advancing it to position where it stopped reading.
Yann Colletd4cda272016-10-14 13:13:13 -0700178 Note : function result can overflow if digit string > MAX_UINT */
Yann Collet1dd79612016-06-03 15:14:09 +0200179static unsigned readU32FromChar(const char** stringPtr)
180{
181 unsigned result = 0;
182 while ((**stringPtr >='0') && (**stringPtr <='9'))
183 result *= 10, result += **stringPtr - '0', (*stringPtr)++ ;
Yann Collet33fdd092016-10-17 17:48:48 -0700184 if ((**stringPtr=='K') || (**stringPtr=='M')) {
185 result <<= 10;
186 if (**stringPtr=='M') result <<= 10;
187 (*stringPtr)++ ;
188 if (**stringPtr=='i') (*stringPtr)++;
189 if (**stringPtr=='B') (*stringPtr)++;
190 }
Yann Collet1dd79612016-06-03 15:14:09 +0200191 return result;
192}
193
Yann Collet743b33f2016-12-02 15:18:57 -0800194/** longCommandWArg() :
195 * check is *stringPtr is the same as longCommand.
196 * If yes, @return 1 and advances *stringPtr to the position which immediately follows longCommand.
197 * @return 0 and doesn't modify *stringPtr otherwise.
198 */
Yann Collet70077bc2016-10-14 14:41:17 -0700199static unsigned longCommandWArg(const char** stringPtr, const char* longCommand)
200{
201 size_t const comSize = strlen(longCommand);
Yann Collet743b33f2016-12-02 15:18:57 -0800202 int const result = !strncmp(*stringPtr, longCommand, comSize);
Yann Collet70077bc2016-10-14 14:41:17 -0700203 if (result) *stringPtr += comSize;
204 return result;
205}
206
Yann Collet22de81e2016-10-28 13:58:31 -0700207typedef enum { zom_compress, zom_decompress, zom_test, zom_bench, zom_train } zstd_operation_mode;
Yann Colletfcf20872016-05-29 05:16:05 +0200208
209#define CLEAN_RETURN(i) { operationResult = (i); goto _end; }
210
Yann Collet0977f7e2016-09-21 12:24:43 +0200211int main(int argCount, const char* argv[])
Yann Colletfcf20872016-05-29 05:16:05 +0200212{
213 int argNb,
Yann Colletfcf20872016-05-29 05:16:05 +0200214 forceStdout=0,
215 main_pause=0,
216 nextEntryIsDictionary=0,
217 operationResult=0,
Yann Colletfcf20872016-05-29 05:16:05 +0200218 nextArgumentIsOutFileName=0,
Yann Collet290aaa72016-05-30 21:18:52 +0200219 nextArgumentIsMaxDict=0,
Yann Colletf9cac7a2016-07-04 18:16:16 +0200220 nextArgumentIsDictID=0,
Yann Collet743b33f2016-12-02 15:18:57 -0800221 nextArgumentsAreFiles=0,
Yann Collet27b5ac62016-09-21 14:20:56 +0200222 ultra=0,
223 lastCommand = 0;
Yann Collet22de81e2016-10-28 13:58:31 -0700224 zstd_operation_mode operation = zom_compress;
Yann Collet41105342016-07-27 15:09:11 +0200225 int cLevel = ZSTDCLI_CLEVEL_DEFAULT;
226 int cLevelLast = 1;
Yann Colletfcf20872016-05-29 05:16:05 +0200227 unsigned recursive = 0;
Yann Colletd4cda272016-10-14 13:13:13 -0700228 unsigned memLimit = 0;
Yann Colletfcf20872016-05-29 05:16:05 +0200229 const char** filenameTable = (const char**)malloc(argCount * sizeof(const char*)); /* argCount >= 1 */
230 unsigned filenameIdx = 0;
231 const char* programName = argv[0];
232 const char* outFileName = NULL;
233 const char* dictFileName = NULL;
Yann Colletfcf20872016-05-29 05:16:05 +0200234 unsigned maxDictSize = g_defaultMaxDictSize;
Yann Collet290aaa72016-05-30 21:18:52 +0200235 unsigned dictID = 0;
Yann Collet41105342016-07-27 15:09:11 +0200236 int dictCLevel = g_defaultDictCLevel;
Yann Colletfcf20872016-05-29 05:16:05 +0200237 unsigned dictSelect = g_defaultSelectivityLevel;
238#ifdef UTIL_HAS_CREATEFILELIST
Yann Collet0977f7e2016-09-21 12:24:43 +0200239 const char** extendedFileList = NULL;
Yann Colletfcf20872016-05-29 05:16:05 +0200240 char* fileNamesBuf = NULL;
241 unsigned fileNamesNb;
242#endif
243
244 /* init */
Yann Colletf3a1a842016-06-05 01:05:01 +0200245 (void)recursive; (void)cLevelLast; /* not used when ZSTD_NOBENCH set */
Yann Collet407a11f2016-11-03 15:52:01 -0700246 (void)dictCLevel; (void)dictSelect; (void)dictID; (void)maxDictSize; /* not used when ZSTD_NODICT set */
247 (void)ultra; (void)cLevel; /* not used when ZSTD_NOCOMPRESS set */
248 (void)memLimit; /* not used when ZSTD_NODECOMPRESS set */
Yann Colletd916c902016-07-04 00:42:58 +0200249 if (filenameTable==NULL) { DISPLAY("zstd: %s \n", strerror(errno)); exit(1); }
Yann Colletfcf20872016-05-29 05:16:05 +0200250 filenameTable[0] = stdinmark;
251 displayOut = stderr;
252 /* Pick out program name from path. Don't rely on stdlib because of conflicting behavior */
253 { size_t pos;
254 for (pos = (int)strlen(programName); pos > 0; pos--) { if (programName[pos] == '/') { pos++; break; } }
255 programName += pos;
256 }
257
258 /* preset behaviors */
Yann Collet22de81e2016-10-28 13:58:31 -0700259 if (!strcmp(programName, ZSTD_UNZSTD)) operation=zom_decompress;
Yann Collet743b33f2016-12-02 15:18:57 -0800260 if (!strcmp(programName, ZSTD_CAT)) { operation=zom_decompress; forceStdout=1; FIO_overwriteMode(); outFileName=stdoutmark; displayLevel=1; }
Yann Colletfcf20872016-05-29 05:16:05 +0200261
262 /* command switches */
Yann Collet11223492016-10-14 14:07:11 -0700263 for (argNb=1; argNb<argCount; argNb++) {
Yann Colletfcf20872016-05-29 05:16:05 +0200264 const char* argument = argv[argNb];
265 if(!argument) continue; /* Protection if argument empty */
266
Yann Collet743b33f2016-12-02 15:18:57 -0800267 if (nextArgumentsAreFiles==0) {
268 /* "-" means stdin/stdout */
Yann Colletf9cac7a2016-07-04 18:16:16 +0200269 if (!strcmp(argument, "-")){
270 if (!filenameIdx) {
271 filenameIdx=1, filenameTable[0]=stdinmark;
272 outFileName=stdoutmark;
273 displayLevel-=(displayLevel==2);
Yann Colletfcf20872016-05-29 05:16:05 +0200274 continue;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200275 } }
Yann Colletfcf20872016-05-29 05:16:05 +0200276
Yann Colletf9cac7a2016-07-04 18:16:16 +0200277 /* Decode commands (note : aggregated commands are allowed) */
278 if (argument[0]=='-') {
Yann Colletfcf20872016-05-29 05:16:05 +0200279
Yann Collet743b33f2016-12-02 15:18:57 -0800280 if (argument[1]=='-') {
281 /* long commands (--long-word) */
282 if (!strcmp(argument, "--")) { nextArgumentsAreFiles=1; continue; } /* only file names allowed from now on */
283 if (!strcmp(argument, "--compress")) { operation=zom_compress; continue; }
284 if (!strcmp(argument, "--decompress")) { operation=zom_decompress; continue; }
285 if (!strcmp(argument, "--uncompress")) { operation=zom_decompress; continue; }
286 if (!strcmp(argument, "--force")) { FIO_overwriteMode(); continue; }
287 if (!strcmp(argument, "--version")) { displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); }
288 if (!strcmp(argument, "--help")) { displayOut=stdout; CLEAN_RETURN(usage_advanced(programName)); }
289 if (!strcmp(argument, "--verbose")) { displayLevel++; continue; }
290 if (!strcmp(argument, "--quiet")) { displayLevel--; continue; }
291 if (!strcmp(argument, "--stdout")) { forceStdout=1; outFileName=stdoutmark; displayLevel-=(displayLevel==2); continue; }
292 if (!strcmp(argument, "--ultra")) { ultra=1; continue; }
293 if (!strcmp(argument, "--check")) { FIO_setChecksumFlag(2); continue; }
294 if (!strcmp(argument, "--no-check")) { FIO_setChecksumFlag(0); continue; }
295 if (!strcmp(argument, "--sparse")) { FIO_setSparseWrite(2); continue; }
296 if (!strcmp(argument, "--no-sparse")) { FIO_setSparseWrite(0); continue; }
297 if (!strcmp(argument, "--test")) { operation=zom_test; continue; }
298 if (!strcmp(argument, "--train")) { operation=zom_train; outFileName=g_defaultDictName; continue; }
299 if (!strcmp(argument, "--maxdict")) { nextArgumentIsMaxDict=1; lastCommand=1; continue; }
300 if (!strcmp(argument, "--dictID")) { nextArgumentIsDictID=1; lastCommand=1; continue; }
301 if (!strcmp(argument, "--no-dictID")) { FIO_setDictIDFlag(0); continue; }
302 if (!strcmp(argument, "--keep")) { FIO_setRemoveSrcFile(0); continue; }
303 if (!strcmp(argument, "--rm")) { FIO_setRemoveSrcFile(1); continue; }
304
305 /* long commands with arguments */
306 if (longCommandWArg(&argument, "--memlimit=")) { memLimit = readU32FromChar(&argument); continue; }
307 if (longCommandWArg(&argument, "--memory=")) { memLimit = readU32FromChar(&argument); continue; }
308 if (longCommandWArg(&argument, "--memlimit-decompress=")) { memLimit = readU32FromChar(&argument); continue; }
309 /* fall-through, will trigger bad_usage() later on */
310 }
311
312 argument++;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200313 while (argument[0]!=0) {
Yann Collet27b5ac62016-09-21 14:20:56 +0200314 if (lastCommand) {
315 DISPLAY("error : command must be followed by argument \n");
316 return 1;
317 }
Yann Colletc8431422016-09-01 15:05:57 -0700318#ifndef ZSTD_NOCOMPRESS
Yann Colletf9cac7a2016-07-04 18:16:16 +0200319 /* compression Level */
320 if ((*argument>='0') && (*argument<='9')) {
Yann Colletfe0590f2016-08-12 18:04:15 +0200321 dictCLevel = cLevel = readU32FromChar(&argument);
Yann Colletf9cac7a2016-07-04 18:16:16 +0200322 continue;
323 }
Yann Colletc8431422016-09-01 15:05:57 -0700324#endif
Yann Colletfcf20872016-05-29 05:16:05 +0200325
Yann Colletf9cac7a2016-07-04 18:16:16 +0200326 switch(argument[0])
327 {
328 /* Display help */
329 case 'V': displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); /* Version Only */
330 case 'H':
331 case 'h': displayOut=stdout; CLEAN_RETURN(usage_advanced(programName));
Yann Colletfcf20872016-05-29 05:16:05 +0200332
Yann Collet22de81e2016-10-28 13:58:31 -0700333 /* Compress */
334 case 'z': operation=zom_compress; argument++; break;
335
Yann Colletf9cac7a2016-07-04 18:16:16 +0200336 /* Decoding */
Yann Colletd9465012016-12-06 16:49:23 -0800337 case 'd': if (operation==zom_bench) {
338 BMK_setDecodeOnly(1); argument++; break; /* benchmark decode (hidden option) */
339 } else {
340 operation=zom_decompress; argument++; break;
341 }
Yann Colletfcf20872016-05-29 05:16:05 +0200342
Yann Colletf9cac7a2016-07-04 18:16:16 +0200343 /* Force stdout, even if stdout==console */
Yann Colletfe0590f2016-08-12 18:04:15 +0200344 case 'c': forceStdout=1; outFileName=stdoutmark; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200345
Yann Colletf9cac7a2016-07-04 18:16:16 +0200346 /* Use file content as dictionary */
Yann Collet27b5ac62016-09-21 14:20:56 +0200347 case 'D': nextEntryIsDictionary = 1; lastCommand = 1; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200348
Yann Colletf9cac7a2016-07-04 18:16:16 +0200349 /* Overwrite */
350 case 'f': FIO_overwriteMode(); forceStdout=1; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200351
Yann Colletf9cac7a2016-07-04 18:16:16 +0200352 /* Verbose mode */
Yann Collet988bcf32016-07-15 19:43:30 +0200353 case 'v': displayLevel++; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200354
Yann Colletf9cac7a2016-07-04 18:16:16 +0200355 /* Quiet mode */
356 case 'q': displayLevel--; argument++; break;
Yann Collet2c4acda2016-06-02 17:05:50 +0200357
Yann Colletf9cac7a2016-07-04 18:16:16 +0200358 /* keep source file (default); for gzip/xz compatibility */
359 case 'k': FIO_setRemoveSrcFile(0); argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200360
Yann Colletf9cac7a2016-07-04 18:16:16 +0200361 /* Checksum */
362 case 'C': argument++; FIO_setChecksumFlag(2); break;
Yann Colletfcf20872016-05-29 05:16:05 +0200363
Yann Colletf9cac7a2016-07-04 18:16:16 +0200364 /* test compressed file */
Yann Collet22de81e2016-10-28 13:58:31 -0700365 case 't': operation=zom_test; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200366
Yann Collet2cac5b32016-07-13 14:15:08 +0200367 /* destination file name */
Yann Collet27b5ac62016-09-21 14:20:56 +0200368 case 'o': nextArgumentIsOutFileName=1; lastCommand=1; argument++; break;
Yann Colletfcf20872016-05-29 05:16:05 +0200369
Yann Colletd4cda272016-10-14 13:13:13 -0700370 /* limit decompression memory */
371 case 'M':
372 argument++;
373 memLimit = readU32FromChar(&argument);
374 break;
375
Yann Colletc4cc9bf2016-09-13 17:50:08 +0200376#ifdef UTIL_HAS_CREATEFILELIST
Yann Colletf9cac7a2016-07-04 18:16:16 +0200377 /* recursive */
378 case 'r': recursive=1; argument++; break;
Yann Colletc4cc9bf2016-09-13 17:50:08 +0200379#endif
Yann Colletf9cac7a2016-07-04 18:16:16 +0200380
Yann Colletc8431422016-09-01 15:05:57 -0700381#ifndef ZSTD_NOBENCH
Yann Colletf9cac7a2016-07-04 18:16:16 +0200382 /* Benchmark */
Yann Colletb9550d62016-10-28 14:43:24 -0700383 case 'b': operation=zom_bench; argument++; break;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200384
385 /* range bench (benchmark only) */
386 case 'e':
387 /* compression Level */
388 argument++;
389 cLevelLast = readU32FromChar(&argument);
390 break;
391
392 /* Modify Nb Iterations (benchmark only) */
393 case 'i':
Yann Colletfcf20872016-05-29 05:16:05 +0200394 argument++;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200395 { U32 const iters = readU32FromChar(&argument);
396 BMK_setNotificationLevel(displayLevel);
Przemyslaw Skibinski26306fc2016-11-03 11:38:01 +0100397 BMK_SetNbSeconds(iters);
Yann Colletf9cac7a2016-07-04 18:16:16 +0200398 }
Yann Colletfcf20872016-05-29 05:16:05 +0200399 break;
400
Yann Colletf9cac7a2016-07-04 18:16:16 +0200401 /* cut input into blocks (benchmark only) */
402 case 'B':
403 argument++;
Yann Colletd4cda272016-10-14 13:13:13 -0700404 { size_t const bSize = readU32FromChar(&argument);
Yann Colletf9cac7a2016-07-04 18:16:16 +0200405 BMK_setNotificationLevel(displayLevel);
406 BMK_SetBlockSize(bSize);
407 }
408 break;
Yann Colletc8431422016-09-01 15:05:57 -0700409#endif /* ZSTD_NOBENCH */
Yann Colletf9cac7a2016-07-04 18:16:16 +0200410
411 /* Dictionary Selection level */
412 case 's':
413 argument++;
414 dictSelect = readU32FromChar(&argument);
415 break;
416
417 /* Pause at the end (-p) or set an additional param (-p#) (hidden option) */
418 case 'p': argument++;
Yann Colletc8431422016-09-01 15:05:57 -0700419#ifndef ZSTD_NOBENCH
Yann Colletf9cac7a2016-07-04 18:16:16 +0200420 if ((*argument>='0') && (*argument<='9')) {
421 BMK_setAdditionalParam(readU32FromChar(&argument));
422 } else
Yann Colletc8431422016-09-01 15:05:57 -0700423#endif
Yann Colletf9cac7a2016-07-04 18:16:16 +0200424 main_pause=1;
425 break;
426 /* unknown command */
427 default : CLEAN_RETURN(badusage(programName));
Yann Colletfcf20872016-05-29 05:16:05 +0200428 }
Yann Colletfcf20872016-05-29 05:16:05 +0200429 }
Yann Colletf9cac7a2016-07-04 18:16:16 +0200430 continue;
431 } /* if (argument[0]=='-') */
432
433 if (nextArgumentIsMaxDict) {
434 nextArgumentIsMaxDict = 0;
Yann Collet27b5ac62016-09-21 14:20:56 +0200435 lastCommand = 0;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200436 maxDictSize = readU32FromChar(&argument);
Yann Colletf9cac7a2016-07-04 18:16:16 +0200437 continue;
Yann Colletfcf20872016-05-29 05:16:05 +0200438 }
Yann Colletf9cac7a2016-07-04 18:16:16 +0200439
440 if (nextArgumentIsDictID) {
441 nextArgumentIsDictID = 0;
Yann Collet27b5ac62016-09-21 14:20:56 +0200442 lastCommand = 0;
Yann Colletf9cac7a2016-07-04 18:16:16 +0200443 dictID = readU32FromChar(&argument);
444 continue;
445 }
446
447 } /* if (nextArgumentIsAFile==0) */
Yann Colletfcf20872016-05-29 05:16:05 +0200448
449 if (nextEntryIsDictionary) {
450 nextEntryIsDictionary = 0;
Yann Collet27b5ac62016-09-21 14:20:56 +0200451 lastCommand = 0;
Yann Colletfcf20872016-05-29 05:16:05 +0200452 dictFileName = argument;
453 continue;
454 }
455
456 if (nextArgumentIsOutFileName) {
457 nextArgumentIsOutFileName = 0;
Yann Collet27b5ac62016-09-21 14:20:56 +0200458 lastCommand = 0;
Yann Colletfcf20872016-05-29 05:16:05 +0200459 outFileName = argument;
460 if (!strcmp(outFileName, "-")) outFileName = stdoutmark;
461 continue;
462 }
463
Yann Colletfcf20872016-05-29 05:16:05 +0200464 /* add filename to list */
465 filenameTable[filenameIdx++] = argument;
466 }
467
Yann Collet714464f2016-09-21 16:05:03 +0200468 if (lastCommand) { DISPLAY("error : command must be followed by argument \n"); return 1; } /* forgotten argument */
469
Yann Colletfcf20872016-05-29 05:16:05 +0200470 /* Welcome message (if verbose) */
471 DISPLAYLEVEL(3, WELCOME_MESSAGE);
472
473#ifdef UTIL_HAS_CREATEFILELIST
Yann Collet0977f7e2016-09-21 12:24:43 +0200474 if (recursive) { /* at this stage, filenameTable is a list of paths, which can contain both files and directories */
475 extendedFileList = UTIL_createFileList(filenameTable, filenameIdx, &fileNamesBuf, &fileNamesNb);
476 if (extendedFileList) {
Yann Collet415251c2016-08-01 14:26:49 +0200477 unsigned u;
Yann Collet0977f7e2016-09-21 12:24:43 +0200478 for (u=0; u<fileNamesNb; u++) DISPLAYLEVEL(4, "%u %s\n", u, extendedFileList[u]);
Yann Colletfcf20872016-05-29 05:16:05 +0200479 free((void*)filenameTable);
Yann Collet0977f7e2016-09-21 12:24:43 +0200480 filenameTable = extendedFileList;
Yann Colletfcf20872016-05-29 05:16:05 +0200481 filenameIdx = fileNamesNb;
482 }
483 }
484#endif
485
486 /* Check if benchmark is selected */
Yann Collet22de81e2016-10-28 13:58:31 -0700487 if (operation==zom_bench) {
Yann Colletfcf20872016-05-29 05:16:05 +0200488#ifndef ZSTD_NOBENCH
489 BMK_setNotificationLevel(displayLevel);
490 BMK_benchFiles(filenameTable, filenameIdx, dictFileName, cLevel, cLevelLast);
491#endif
492 goto _end;
493 }
494
495 /* Check if dictionary builder is selected */
Yann Collet22de81e2016-10-28 13:58:31 -0700496 if (operation==zom_train) {
Yann Colletfcf20872016-05-29 05:16:05 +0200497#ifndef ZSTD_NODICT
498 ZDICT_params_t dictParams;
Yann Collet5e80dd32016-07-13 17:38:39 +0200499 memset(&dictParams, 0, sizeof(dictParams));
Yann Colletfcf20872016-05-29 05:16:05 +0200500 dictParams.compressionLevel = dictCLevel;
501 dictParams.selectivityLevel = dictSelect;
502 dictParams.notificationLevel = displayLevel;
Yann Collet290aaa72016-05-30 21:18:52 +0200503 dictParams.dictID = dictID;
Yann Colletfcf20872016-05-29 05:16:05 +0200504 DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, dictParams);
505#endif
506 goto _end;
507 }
508
509 /* No input filename ==> use stdin and stdout */
Yann Collet87c18b22016-08-26 01:43:47 +0200510 filenameIdx += !filenameIdx; /* filenameTable[0] is stdin by default */
511 if (!strcmp(filenameTable[0], stdinmark) && !outFileName) outFileName = stdoutmark; /* when input is stdin, default output is stdout */
Yann Colletfcf20872016-05-29 05:16:05 +0200512
513 /* Check if input/output defined as console; trigger an error in this case */
514 if (!strcmp(filenameTable[0], stdinmark) && IS_CONSOLE(stdin) ) CLEAN_RETURN(badusage(programName));
Yann Collet22de81e2016-10-28 13:58:31 -0700515 if (outFileName && !strcmp(outFileName, stdoutmark) && IS_CONSOLE(stdout) && strcmp(filenameTable[0], stdinmark) && !(forceStdout && (operation==zom_decompress)))
Yann Colletfcf20872016-05-29 05:16:05 +0200516 CLEAN_RETURN(badusage(programName));
517
518 /* user-selected output filename, only possible with a single file */
519 if (outFileName && strcmp(outFileName,stdoutmark) && strcmp(outFileName,nulmark) && (filenameIdx>1)) {
520 DISPLAY("Too many files (%u) on the command line. \n", filenameIdx);
521 CLEAN_RETURN(filenameIdx);
522 }
523
inikep23cec872016-10-05 11:56:22 +0200524#ifndef ZSTD_NOCOMPRESS
Yann Colletfe0590f2016-08-12 18:04:15 +0200525 /* check compression level limits */
526 { int const maxCLevel = ultra ? ZSTD_maxCLevel() : ZSTDCLI_CLEVEL_MAX;
527 if (cLevel > maxCLevel) {
528 DISPLAYLEVEL(2, "Warning : compression level higher than max, reduced to %i \n", maxCLevel);
529 cLevel = maxCLevel;
530 } }
inikep23cec872016-10-05 11:56:22 +0200531#endif
Yann Colletfe0590f2016-08-12 18:04:15 +0200532
533 /* No warning message in pipe mode (stdin + stdout) or multi-files mode */
Yann Colletfcf20872016-05-29 05:16:05 +0200534 if (!strcmp(filenameTable[0], stdinmark) && outFileName && !strcmp(outFileName,stdoutmark) && (displayLevel==2)) displayLevel=1;
Yann Collet06dd7412016-07-18 04:06:43 +0200535 if ((filenameIdx>1) & (displayLevel==2)) displayLevel=1;
Yann Colletfcf20872016-05-29 05:16:05 +0200536
537 /* IO Stream/File */
538 FIO_setNotificationLevel(displayLevel);
Yann Collet22de81e2016-10-28 13:58:31 -0700539 if (operation==zom_compress) {
Yann Collet0977f7e2016-09-21 12:24:43 +0200540#ifndef ZSTD_NOCOMPRESS
Yann Collet993060e2016-09-21 16:46:08 +0200541 if ((filenameIdx==1) && outFileName)
Yann Colletfcf20872016-05-29 05:16:05 +0200542 operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel);
543 else
544 operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, outFileName ? outFileName : ZSTD_EXTENSION, dictFileName, cLevel);
Yann Collet0977f7e2016-09-21 12:24:43 +0200545#else
546 DISPLAY("Compression not supported\n");
Yann Colletfcf20872016-05-29 05:16:05 +0200547#endif
Yann Collet22de81e2016-10-28 13:58:31 -0700548 } else { /* decompression or test */
Yann Colletfcf20872016-05-29 05:16:05 +0200549#ifndef ZSTD_NODECOMPRESS
Yann Collet22de81e2016-10-28 13:58:31 -0700550 if (operation==zom_test) { outFileName=nulmark; FIO_setRemoveSrcFile(0); } /* test mode */
Yann Colletd4cda272016-10-14 13:13:13 -0700551 FIO_setMemLimit(memLimit);
Yann Colletfcf20872016-05-29 05:16:05 +0200552 if (filenameIdx==1 && outFileName)
553 operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName);
554 else
555 operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, outFileName ? outFileName : ZSTD_EXTENSION, dictFileName);
556#else
557 DISPLAY("Decompression not supported\n");
558#endif
559 }
560
561_end:
562 if (main_pause) waitEnter();
Yann Colletfcf20872016-05-29 05:16:05 +0200563#ifdef UTIL_HAS_CREATEFILELIST
Yann Collet0977f7e2016-09-21 12:24:43 +0200564 if (extendedFileList)
565 UTIL_freeFileList(extendedFileList, fileNamesBuf);
Yann Colletfcf20872016-05-29 05:16:05 +0200566 else
567#endif
568 free((void*)filenameTable);
569 return operationResult;
570}