10c16b537SWarner Losh /* 20c16b537SWarner Losh * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. 30c16b537SWarner Losh * All rights reserved. 40c16b537SWarner Losh * 50c16b537SWarner Losh * This source code is licensed under both the BSD-style license (found in the 60c16b537SWarner Losh * LICENSE file in the root directory of this source tree) and the GPLv2 (found 70c16b537SWarner Losh * in the COPYING file in the root directory of this source tree). 80c16b537SWarner Losh * You may select, at your option, one of the above-listed licenses. 90c16b537SWarner Losh */ 100c16b537SWarner Losh 110c16b537SWarner Losh 120c16b537SWarner Losh /*-************************************ 130c16b537SWarner Losh * Tuning parameters 140c16b537SWarner Losh **************************************/ 150c16b537SWarner Losh #ifndef ZSTDCLI_CLEVEL_DEFAULT 160c16b537SWarner Losh # define ZSTDCLI_CLEVEL_DEFAULT 3 170c16b537SWarner Losh #endif 180c16b537SWarner Losh 190c16b537SWarner Losh #ifndef ZSTDCLI_CLEVEL_MAX 200c16b537SWarner Losh # define ZSTDCLI_CLEVEL_MAX 19 /* without using --ultra */ 210c16b537SWarner Losh #endif 220c16b537SWarner Losh 230c16b537SWarner Losh 240c16b537SWarner Losh 250c16b537SWarner Losh /*-************************************ 260c16b537SWarner Losh * Dependencies 270c16b537SWarner Losh **************************************/ 280c16b537SWarner Losh #include "platform.h" /* IS_CONSOLE, PLATFORM_POSIX_VERSION */ 290c16b537SWarner Losh #include "util.h" /* UTIL_HAS_CREATEFILELIST, UTIL_createFileList */ 300c16b537SWarner Losh #include <stdio.h> /* fprintf(), stdin, stdout, stderr */ 310c16b537SWarner Losh #include <string.h> /* strcmp, strlen */ 320c16b537SWarner Losh #include <errno.h> /* errno */ 330c16b537SWarner Losh #include "fileio.h" /* stdinmark, stdoutmark, ZSTD_EXTENSION */ 340c16b537SWarner Losh #ifndef ZSTD_NOBENCH 350c16b537SWarner Losh # include "bench.h" /* BMK_benchFiles, BMK_SetNbSeconds */ 360c16b537SWarner Losh #endif 370c16b537SWarner Losh #ifndef ZSTD_NODICT 380c16b537SWarner Losh # include "dibio.h" /* ZDICT_cover_params_t, DiB_trainFromFiles() */ 390c16b537SWarner Losh #endif 400c16b537SWarner Losh #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_maxCLevel */ 410c16b537SWarner Losh #include "zstd.h" /* ZSTD_VERSION_STRING */ 420c16b537SWarner Losh 430c16b537SWarner Losh 440c16b537SWarner Losh /*-************************************ 450c16b537SWarner Losh * Constants 460c16b537SWarner Losh **************************************/ 470c16b537SWarner Losh #define COMPRESSOR_NAME "zstd command line interface" 480c16b537SWarner Losh #ifndef ZSTD_VERSION 490c16b537SWarner Losh # define ZSTD_VERSION "v" ZSTD_VERSION_STRING 500c16b537SWarner Losh #endif 510c16b537SWarner Losh #define AUTHOR "Yann Collet" 520c16b537SWarner Losh #define WELCOME_MESSAGE "*** %s %i-bits %s, by %s ***\n", COMPRESSOR_NAME, (int)(sizeof(size_t)*8), ZSTD_VERSION, AUTHOR 530c16b537SWarner Losh 540c16b537SWarner Losh #define ZSTD_ZSTDMT "zstdmt" 550c16b537SWarner Losh #define ZSTD_UNZSTD "unzstd" 560c16b537SWarner Losh #define ZSTD_CAT "zstdcat" 570c16b537SWarner Losh #define ZSTD_GZ "gzip" 580c16b537SWarner Losh #define ZSTD_GUNZIP "gunzip" 590c16b537SWarner Losh #define ZSTD_GZCAT "gzcat" 600c16b537SWarner Losh #define ZSTD_LZMA "lzma" 610c16b537SWarner Losh #define ZSTD_UNLZMA "unlzma" 620c16b537SWarner Losh #define ZSTD_XZ "xz" 630c16b537SWarner Losh #define ZSTD_UNXZ "unxz" 640c16b537SWarner Losh #define ZSTD_LZ4 "lz4" 650c16b537SWarner Losh #define ZSTD_UNLZ4 "unlz4" 660c16b537SWarner Losh 670c16b537SWarner Losh #define KB *(1 <<10) 680c16b537SWarner Losh #define MB *(1 <<20) 690c16b537SWarner Losh #define GB *(1U<<30) 700c16b537SWarner Losh 711ad8ac7aSBaptiste Daroussin #define DISPLAY_LEVEL_DEFAULT 2 720c16b537SWarner Losh 730c16b537SWarner Losh static const char* g_defaultDictName = "dictionary"; 740c16b537SWarner Losh static const unsigned g_defaultMaxDictSize = 110 KB; 750c16b537SWarner Losh static const int g_defaultDictCLevel = 3; 760c16b537SWarner Losh static const unsigned g_defaultSelectivityLevel = 9; 770c16b537SWarner Losh static const unsigned g_defaultMaxWindowLog = 27; 780c16b537SWarner Losh #define OVERLAP_LOG_DEFAULT 9999 790c16b537SWarner Losh #define LDM_PARAM_DEFAULT 9999 /* Default for parameters where 0 is valid */ 800c16b537SWarner Losh static U32 g_overlapLog = OVERLAP_LOG_DEFAULT; 810c16b537SWarner Losh static U32 g_ldmHashLog = 0; 820c16b537SWarner Losh static U32 g_ldmMinMatch = 0; 830c16b537SWarner Losh static U32 g_ldmHashEveryLog = LDM_PARAM_DEFAULT; 840c16b537SWarner Losh static U32 g_ldmBucketSizeLog = LDM_PARAM_DEFAULT; 850c16b537SWarner Losh 860c16b537SWarner Losh 870c16b537SWarner Losh /*-************************************ 880c16b537SWarner Losh * Display Macros 890c16b537SWarner Losh **************************************/ 900c16b537SWarner Losh #define DISPLAY(...) fprintf(g_displayOut, __VA_ARGS__) 910c16b537SWarner Losh #define DISPLAYLEVEL(l, ...) { if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } } 920c16b537SWarner Losh static int g_displayLevel = DISPLAY_LEVEL_DEFAULT; /* 0 : no display, 1: errors, 2 : + result + interaction + warnings, 3 : + progression, 4 : + information */ 930c16b537SWarner Losh static FILE* g_displayOut; 940c16b537SWarner Losh 950c16b537SWarner Losh 960c16b537SWarner Losh /*-************************************ 970c16b537SWarner Losh * Command Line 980c16b537SWarner Losh **************************************/ 990c16b537SWarner Losh static int usage(const char* programName) 1000c16b537SWarner Losh { 1010c16b537SWarner Losh DISPLAY( "Usage : \n"); 1020c16b537SWarner Losh DISPLAY( " %s [args] [FILE(s)] [-o file] \n", programName); 1030c16b537SWarner Losh DISPLAY( "\n"); 1040c16b537SWarner Losh DISPLAY( "FILE : a filename \n"); 1050c16b537SWarner Losh DISPLAY( " with no FILE, or when FILE is - , read standard input\n"); 1060c16b537SWarner Losh DISPLAY( "Arguments : \n"); 1070c16b537SWarner Losh #ifndef ZSTD_NOCOMPRESS 1080c16b537SWarner Losh DISPLAY( " -# : # compression level (1-%d, default:%d) \n", ZSTDCLI_CLEVEL_MAX, ZSTDCLI_CLEVEL_DEFAULT); 1090c16b537SWarner Losh #endif 1100c16b537SWarner Losh #ifndef ZSTD_NODECOMPRESS 1110c16b537SWarner Losh DISPLAY( " -d : decompression \n"); 1120c16b537SWarner Losh #endif 1130c16b537SWarner Losh DISPLAY( " -D file: use `file` as Dictionary \n"); 1140c16b537SWarner Losh DISPLAY( " -o file: result stored into `file` (only if 1 input file) \n"); 1150c16b537SWarner Losh DISPLAY( " -f : overwrite output without prompting and (de)compress links \n"); 1160c16b537SWarner Losh DISPLAY( "--rm : remove source file(s) after successful de/compression \n"); 1170c16b537SWarner Losh DISPLAY( " -k : preserve source file(s) (default) \n"); 1180c16b537SWarner Losh DISPLAY( " -h/-H : display help/long help and exit \n"); 1190c16b537SWarner Losh return 0; 1200c16b537SWarner Losh } 1210c16b537SWarner Losh 1220c16b537SWarner Losh static int usage_advanced(const char* programName) 1230c16b537SWarner Losh { 1240c16b537SWarner Losh DISPLAY(WELCOME_MESSAGE); 1250c16b537SWarner Losh usage(programName); 1260c16b537SWarner Losh DISPLAY( "\n"); 1270c16b537SWarner Losh DISPLAY( "Advanced arguments : \n"); 1280c16b537SWarner Losh DISPLAY( " -V : display Version number and exit \n"); 1290c16b537SWarner Losh DISPLAY( " -v : verbose mode; specify multiple times to increase verbosity\n"); 1300c16b537SWarner Losh DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n"); 1310c16b537SWarner Losh DISPLAY( " -c : force write to standard output, even if it is the console\n"); 1320c16b537SWarner Losh DISPLAY( " -l : print information about zstd compressed files \n"); 1330c16b537SWarner Losh #ifndef ZSTD_NOCOMPRESS 1340c16b537SWarner Losh DISPLAY( "--ultra : enable levels beyond %i, up to %i (requires more memory)\n", ZSTDCLI_CLEVEL_MAX, ZSTD_maxCLevel()); 1350c16b537SWarner Losh DISPLAY( "--long[=#] : enable long distance matching with given window log (default : %u)\n", g_defaultMaxWindowLog); 1360c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 1370c16b537SWarner Losh DISPLAY( " -T# : use # threads for compression (default:1) \n"); 1380c16b537SWarner Losh DISPLAY( " -B# : select size of each job (default:0==automatic) \n"); 1390c16b537SWarner Losh #endif 1400c16b537SWarner Losh DISPLAY( "--no-dictID : don't write dictID into header (dictionary compression)\n"); 1410c16b537SWarner Losh DISPLAY( "--[no-]check : integrity check (default:enabled) \n"); 1420c16b537SWarner Losh #endif 1430c16b537SWarner Losh #ifdef UTIL_HAS_CREATEFILELIST 1440c16b537SWarner Losh DISPLAY( " -r : operate recursively on directories \n"); 1450c16b537SWarner Losh #endif 1460c16b537SWarner Losh #ifdef ZSTD_GZCOMPRESS 1470c16b537SWarner Losh DISPLAY( "--format=gzip : compress files to the .gz format \n"); 1480c16b537SWarner Losh #endif 1490c16b537SWarner Losh #ifdef ZSTD_LZMACOMPRESS 1500c16b537SWarner Losh DISPLAY( "--format=xz : compress files to the .xz format \n"); 1510c16b537SWarner Losh DISPLAY( "--format=lzma : compress files to the .lzma format \n"); 1520c16b537SWarner Losh #endif 1530c16b537SWarner Losh #ifdef ZSTD_LZ4COMPRESS 1540c16b537SWarner Losh DISPLAY( "--format=lz4 : compress files to the .lz4 format \n"); 1550c16b537SWarner Losh #endif 1560c16b537SWarner Losh #ifndef ZSTD_NODECOMPRESS 1570c16b537SWarner Losh DISPLAY( "--test : test compressed file integrity \n"); 1580c16b537SWarner Losh #if ZSTD_SPARSE_DEFAULT 1590c16b537SWarner Losh DISPLAY( "--[no-]sparse : sparse mode (default:enabled on file, disabled on stdout)\n"); 1600c16b537SWarner Losh #else 1610c16b537SWarner Losh DISPLAY( "--[no-]sparse : sparse mode (default:disabled)\n"); 1620c16b537SWarner Losh #endif 1630c16b537SWarner Losh #endif 1640c16b537SWarner Losh DISPLAY( " -M# : Set a memory usage limit for decompression \n"); 1650c16b537SWarner Losh DISPLAY( "-- : All arguments after \"--\" are treated as files \n"); 1660c16b537SWarner Losh #ifndef ZSTD_NODICT 1670c16b537SWarner Losh DISPLAY( "\n"); 1680c16b537SWarner Losh DISPLAY( "Dictionary builder : \n"); 1690c16b537SWarner Losh DISPLAY( "--train ## : create a dictionary from a training set of files \n"); 1700c16b537SWarner Losh DISPLAY( "--train-cover[=k=#,d=#,steps=#] : use the cover algorithm with optional args\n"); 1710c16b537SWarner Losh DISPLAY( "--train-legacy[=s=#] : use the legacy algorithm with selectivity (default: %u)\n", g_defaultSelectivityLevel); 1720c16b537SWarner Losh DISPLAY( " -o file : `file` is dictionary name (default: %s) \n", g_defaultDictName); 1730c16b537SWarner Losh DISPLAY( "--maxdict=# : limit dictionary to specified size (default : %u) \n", g_defaultMaxDictSize); 1740c16b537SWarner Losh DISPLAY( "--dictID=# : force dictionary ID to specified value (default: random)\n"); 1750c16b537SWarner Losh #endif 1760c16b537SWarner Losh #ifndef ZSTD_NOBENCH 1770c16b537SWarner Losh DISPLAY( "\n"); 1780c16b537SWarner Losh DISPLAY( "Benchmark arguments : \n"); 1790c16b537SWarner Losh DISPLAY( " -b# : benchmark file(s), using # compression level (default : 1) \n"); 1800c16b537SWarner Losh DISPLAY( " -e# : test all compression levels from -bX to # (default: 1)\n"); 1810c16b537SWarner Losh DISPLAY( " -i# : minimum evaluation time in seconds (default : 3s) \n"); 1820c16b537SWarner Losh DISPLAY( " -B# : cut file into independent blocks of size # (default: no block)\n"); 1830c16b537SWarner Losh DISPLAY( "--priority=rt : set process priority to real-time \n"); 1840c16b537SWarner Losh #endif 1850c16b537SWarner Losh return 0; 1860c16b537SWarner Losh } 1870c16b537SWarner Losh 1880c16b537SWarner Losh static int badusage(const char* programName) 1890c16b537SWarner Losh { 1900c16b537SWarner Losh DISPLAYLEVEL(1, "Incorrect parameters\n"); 1910c16b537SWarner Losh if (g_displayLevel >= 2) usage(programName); 1920c16b537SWarner Losh return 1; 1930c16b537SWarner Losh } 1940c16b537SWarner Losh 1950c16b537SWarner Losh static void waitEnter(void) 1960c16b537SWarner Losh { 1970c16b537SWarner Losh int unused; 1980c16b537SWarner Losh DISPLAY("Press enter to continue...\n"); 1990c16b537SWarner Losh unused = getchar(); 2000c16b537SWarner Losh (void)unused; 2010c16b537SWarner Losh } 2020c16b537SWarner Losh 2030c16b537SWarner Losh static const char* lastNameFromPath(const char* path) 2040c16b537SWarner Losh { 2050c16b537SWarner Losh const char* name = path; 2060c16b537SWarner Losh if (strrchr(name, '/')) name = strrchr(name, '/') + 1; 2070c16b537SWarner Losh if (strrchr(name, '\\')) name = strrchr(name, '\\') + 1; /* windows */ 2080c16b537SWarner Losh return name; 2090c16b537SWarner Losh } 2100c16b537SWarner Losh 2110c16b537SWarner Losh /*! exeNameMatch() : 2120c16b537SWarner Losh @return : a non-zero value if exeName matches test, excluding the extension 2130c16b537SWarner Losh */ 2140c16b537SWarner Losh static int exeNameMatch(const char* exeName, const char* test) 2150c16b537SWarner Losh { 2160c16b537SWarner Losh return !strncmp(exeName, test, strlen(test)) && 2170c16b537SWarner Losh (exeName[strlen(test)] == '\0' || exeName[strlen(test)] == '.'); 2180c16b537SWarner Losh } 2190c16b537SWarner Losh 2200c16b537SWarner Losh /*! readU32FromChar() : 2210c16b537SWarner Losh @return : unsigned integer value read from input in `char` format 2220c16b537SWarner Losh allows and interprets K, KB, KiB, M, MB and MiB suffix. 2230c16b537SWarner Losh Will also modify `*stringPtr`, advancing it to position where it stopped reading. 2240c16b537SWarner Losh Note : function result can overflow if digit string > MAX_UINT */ 2250c16b537SWarner Losh static unsigned readU32FromChar(const char** stringPtr) 2260c16b537SWarner Losh { 2270c16b537SWarner Losh unsigned result = 0; 2280c16b537SWarner Losh while ((**stringPtr >='0') && (**stringPtr <='9')) 2290c16b537SWarner Losh result *= 10, result += **stringPtr - '0', (*stringPtr)++ ; 2300c16b537SWarner Losh if ((**stringPtr=='K') || (**stringPtr=='M')) { 2310c16b537SWarner Losh result <<= 10; 2320c16b537SWarner Losh if (**stringPtr=='M') result <<= 10; 2330c16b537SWarner Losh (*stringPtr)++ ; 2340c16b537SWarner Losh if (**stringPtr=='i') (*stringPtr)++; 2350c16b537SWarner Losh if (**stringPtr=='B') (*stringPtr)++; 2360c16b537SWarner Losh } 2370c16b537SWarner Losh return result; 2380c16b537SWarner Losh } 2390c16b537SWarner Losh 2400c16b537SWarner Losh /** longCommandWArg() : 2410c16b537SWarner Losh * check if *stringPtr is the same as longCommand. 2420c16b537SWarner Losh * If yes, @return 1 and advances *stringPtr to the position which immediately follows longCommand. 2430c16b537SWarner Losh * @return 0 and doesn't modify *stringPtr otherwise. 2440c16b537SWarner Losh */ 2450c16b537SWarner Losh static unsigned longCommandWArg(const char** stringPtr, const char* longCommand) 2460c16b537SWarner Losh { 2470c16b537SWarner Losh size_t const comSize = strlen(longCommand); 2480c16b537SWarner Losh int const result = !strncmp(*stringPtr, longCommand, comSize); 2490c16b537SWarner Losh if (result) *stringPtr += comSize; 2500c16b537SWarner Losh return result; 2510c16b537SWarner Losh } 2520c16b537SWarner Losh 2530c16b537SWarner Losh 2540c16b537SWarner Losh #ifndef ZSTD_NODICT 2550c16b537SWarner Losh /** 2560c16b537SWarner Losh * parseCoverParameters() : 2570c16b537SWarner Losh * reads cover parameters from *stringPtr (e.g. "--train-cover=k=48,d=8,steps=32") into *params 2580c16b537SWarner Losh * @return 1 means that cover parameters were correct 2590c16b537SWarner Losh * @return 0 in case of malformed parameters 2600c16b537SWarner Losh */ 2610c16b537SWarner Losh static unsigned parseCoverParameters(const char* stringPtr, ZDICT_cover_params_t* params) 2620c16b537SWarner Losh { 2630c16b537SWarner Losh memset(params, 0, sizeof(*params)); 2640c16b537SWarner Losh for (; ;) { 2650c16b537SWarner Losh if (longCommandWArg(&stringPtr, "k=")) { params->k = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 2660c16b537SWarner Losh if (longCommandWArg(&stringPtr, "d=")) { params->d = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 2670c16b537SWarner Losh if (longCommandWArg(&stringPtr, "steps=")) { params->steps = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 2680c16b537SWarner Losh return 0; 2690c16b537SWarner Losh } 2700c16b537SWarner Losh if (stringPtr[0] != 0) return 0; 2710c16b537SWarner Losh DISPLAYLEVEL(4, "cover: k=%u\nd=%u\nsteps=%u\n", params->k, params->d, params->steps); 2720c16b537SWarner Losh return 1; 2730c16b537SWarner Losh } 2740c16b537SWarner Losh 2750c16b537SWarner Losh /** 2760c16b537SWarner Losh * parseLegacyParameters() : 2770c16b537SWarner Losh * reads legacy dictioanry builter parameters from *stringPtr (e.g. "--train-legacy=selectivity=8") into *selectivity 2780c16b537SWarner Losh * @return 1 means that legacy dictionary builder parameters were correct 2790c16b537SWarner Losh * @return 0 in case of malformed parameters 2800c16b537SWarner Losh */ 2810c16b537SWarner Losh static unsigned parseLegacyParameters(const char* stringPtr, unsigned* selectivity) 2820c16b537SWarner Losh { 2830c16b537SWarner Losh if (!longCommandWArg(&stringPtr, "s=") && !longCommandWArg(&stringPtr, "selectivity=")) { return 0; } 2840c16b537SWarner Losh *selectivity = readU32FromChar(&stringPtr); 2850c16b537SWarner Losh if (stringPtr[0] != 0) return 0; 2860c16b537SWarner Losh DISPLAYLEVEL(4, "legacy: selectivity=%u\n", *selectivity); 2870c16b537SWarner Losh return 1; 2880c16b537SWarner Losh } 2890c16b537SWarner Losh 2900c16b537SWarner Losh static ZDICT_cover_params_t defaultCoverParams(void) 2910c16b537SWarner Losh { 2920c16b537SWarner Losh ZDICT_cover_params_t params; 2930c16b537SWarner Losh memset(¶ms, 0, sizeof(params)); 2940c16b537SWarner Losh params.d = 8; 2950c16b537SWarner Losh params.steps = 4; 2960c16b537SWarner Losh return params; 2970c16b537SWarner Losh } 2980c16b537SWarner Losh #endif 2990c16b537SWarner Losh 3000c16b537SWarner Losh 3010c16b537SWarner Losh /** parseCompressionParameters() : 3020c16b537SWarner Losh * reads compression parameters from *stringPtr (e.g. "--zstd=wlog=23,clog=23,hlog=22,slog=6,slen=3,tlen=48,strat=6") into *params 3030c16b537SWarner Losh * @return 1 means that compression parameters were correct 3040c16b537SWarner Losh * @return 0 in case of malformed parameters 3050c16b537SWarner Losh */ 3060c16b537SWarner Losh static unsigned parseCompressionParameters(const char* stringPtr, ZSTD_compressionParameters* params) 3070c16b537SWarner Losh { 3080c16b537SWarner Losh for ( ; ;) { 3090c16b537SWarner Losh if (longCommandWArg(&stringPtr, "windowLog=") || longCommandWArg(&stringPtr, "wlog=")) { params->windowLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 3100c16b537SWarner Losh if (longCommandWArg(&stringPtr, "chainLog=") || longCommandWArg(&stringPtr, "clog=")) { params->chainLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 3110c16b537SWarner Losh if (longCommandWArg(&stringPtr, "hashLog=") || longCommandWArg(&stringPtr, "hlog=")) { params->hashLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 3120c16b537SWarner Losh if (longCommandWArg(&stringPtr, "searchLog=") || longCommandWArg(&stringPtr, "slog=")) { params->searchLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 3130c16b537SWarner Losh if (longCommandWArg(&stringPtr, "searchLength=") || longCommandWArg(&stringPtr, "slen=")) { params->searchLength = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 3140c16b537SWarner Losh if (longCommandWArg(&stringPtr, "targetLength=") || longCommandWArg(&stringPtr, "tlen=")) { params->targetLength = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 3150c16b537SWarner Losh if (longCommandWArg(&stringPtr, "strategy=") || longCommandWArg(&stringPtr, "strat=")) { params->strategy = (ZSTD_strategy)(readU32FromChar(&stringPtr)); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 3160c16b537SWarner Losh if (longCommandWArg(&stringPtr, "overlapLog=") || longCommandWArg(&stringPtr, "ovlog=")) { g_overlapLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 3170c16b537SWarner Losh if (longCommandWArg(&stringPtr, "ldmHashLog=") || longCommandWArg(&stringPtr, "ldmhlog=")) { g_ldmHashLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 3180c16b537SWarner Losh if (longCommandWArg(&stringPtr, "ldmSearchLength=") || longCommandWArg(&stringPtr, "ldmslen=")) { g_ldmMinMatch = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 3190c16b537SWarner Losh if (longCommandWArg(&stringPtr, "ldmBucketSizeLog=") || longCommandWArg(&stringPtr, "ldmblog=")) { g_ldmBucketSizeLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 3200c16b537SWarner Losh if (longCommandWArg(&stringPtr, "ldmHashEveryLog=") || longCommandWArg(&stringPtr, "ldmhevery=")) { g_ldmHashEveryLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } 3210c16b537SWarner Losh return 0; 3220c16b537SWarner Losh } 3230c16b537SWarner Losh 3240c16b537SWarner Losh if (stringPtr[0] != 0) return 0; /* check the end of string */ 3250c16b537SWarner Losh DISPLAYLEVEL(4, "windowLog=%d\nchainLog=%d\nhashLog=%d\nsearchLog=%d\n", params->windowLog, params->chainLog, params->hashLog, params->searchLog); 3260c16b537SWarner Losh DISPLAYLEVEL(4, "searchLength=%d\ntargetLength=%d\nstrategy=%d\n", params->searchLength, params->targetLength, params->strategy); 3270c16b537SWarner Losh return 1; 3280c16b537SWarner Losh } 3290c16b537SWarner Losh 3300c16b537SWarner Losh static void printVersion(void) 3310c16b537SWarner Losh { 3320c16b537SWarner Losh DISPLAY(WELCOME_MESSAGE); 3330c16b537SWarner Losh /* format support */ 3340c16b537SWarner Losh DISPLAYLEVEL(3, "*** supports: zstd"); 3350c16b537SWarner Losh #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>0) && (ZSTD_LEGACY_SUPPORT<8) 3360c16b537SWarner Losh DISPLAYLEVEL(3, ", zstd legacy v0.%d+", ZSTD_LEGACY_SUPPORT); 3370c16b537SWarner Losh #endif 3380c16b537SWarner Losh #ifdef ZSTD_GZCOMPRESS 3390c16b537SWarner Losh DISPLAYLEVEL(3, ", gzip"); 3400c16b537SWarner Losh #endif 3410c16b537SWarner Losh #ifdef ZSTD_LZ4COMPRESS 3420c16b537SWarner Losh DISPLAYLEVEL(3, ", lz4"); 3430c16b537SWarner Losh #endif 3440c16b537SWarner Losh #ifdef ZSTD_LZMACOMPRESS 3450c16b537SWarner Losh DISPLAYLEVEL(3, ", lzma, xz "); 3460c16b537SWarner Losh #endif 3470c16b537SWarner Losh DISPLAYLEVEL(3, "\n"); 3480c16b537SWarner Losh /* posix support */ 3490c16b537SWarner Losh #ifdef _POSIX_C_SOURCE 3500c16b537SWarner Losh DISPLAYLEVEL(4, "_POSIX_C_SOURCE defined: %ldL\n", (long) _POSIX_C_SOURCE); 3510c16b537SWarner Losh #endif 3520c16b537SWarner Losh #ifdef _POSIX_VERSION 3530c16b537SWarner Losh DISPLAYLEVEL(4, "_POSIX_VERSION defined: %ldL \n", (long) _POSIX_VERSION); 3540c16b537SWarner Losh #endif 3550c16b537SWarner Losh #ifdef PLATFORM_POSIX_VERSION 3560c16b537SWarner Losh DISPLAYLEVEL(4, "PLATFORM_POSIX_VERSION defined: %ldL\n", (long) PLATFORM_POSIX_VERSION); 3570c16b537SWarner Losh #endif 3580c16b537SWarner Losh } 3590c16b537SWarner Losh 3600c16b537SWarner Losh typedef enum { zom_compress, zom_decompress, zom_test, zom_bench, zom_train, zom_list } zstd_operation_mode; 3610c16b537SWarner Losh 3620c16b537SWarner Losh #define CLEAN_RETURN(i) { operationResult = (i); goto _end; } 3630c16b537SWarner Losh 3640c16b537SWarner Losh int main(int argCount, const char* argv[]) 3650c16b537SWarner Losh { 3660c16b537SWarner Losh int argNb, 3670c16b537SWarner Losh forceStdout=0, 3680c16b537SWarner Losh followLinks=0, 3690c16b537SWarner Losh main_pause=0, 3700c16b537SWarner Losh nextEntryIsDictionary=0, 3710c16b537SWarner Losh operationResult=0, 3720c16b537SWarner Losh nextArgumentIsOutFileName=0, 3730c16b537SWarner Losh nextArgumentIsMaxDict=0, 3740c16b537SWarner Losh nextArgumentIsDictID=0, 3750c16b537SWarner Losh nextArgumentsAreFiles=0, 3760c16b537SWarner Losh ultra=0, 3770c16b537SWarner Losh lastCommand = 0, 3780c16b537SWarner Losh nbThreads = 1, 3790c16b537SWarner Losh setRealTimePrio = 0, 380*052d3c12SConrad Meyer separateFiles = 0, 3810c16b537SWarner Losh ldmFlag = 0; 3820c16b537SWarner Losh unsigned bench_nbSeconds = 3; /* would be better if this value was synchronized from bench */ 3830c16b537SWarner Losh size_t blockSize = 0; 3840c16b537SWarner Losh zstd_operation_mode operation = zom_compress; 3850c16b537SWarner Losh ZSTD_compressionParameters compressionParams; 3860c16b537SWarner Losh int cLevel = ZSTDCLI_CLEVEL_DEFAULT; 3870c16b537SWarner Losh int cLevelLast = 1; 3880c16b537SWarner Losh unsigned recursive = 0; 3890c16b537SWarner Losh unsigned memLimit = 0; 3900c16b537SWarner Losh const char** filenameTable = (const char**)malloc(argCount * sizeof(const char*)); /* argCount >= 1 */ 3910c16b537SWarner Losh unsigned filenameIdx = 0; 3920c16b537SWarner Losh const char* programName = argv[0]; 3930c16b537SWarner Losh const char* outFileName = NULL; 3940c16b537SWarner Losh const char* dictFileName = NULL; 3950c16b537SWarner Losh const char* suffix = ZSTD_EXTENSION; 3960c16b537SWarner Losh unsigned maxDictSize = g_defaultMaxDictSize; 3970c16b537SWarner Losh unsigned dictID = 0; 3980c16b537SWarner Losh int dictCLevel = g_defaultDictCLevel; 3990c16b537SWarner Losh unsigned dictSelect = g_defaultSelectivityLevel; 4000c16b537SWarner Losh #ifdef UTIL_HAS_CREATEFILELIST 4010c16b537SWarner Losh const char** extendedFileList = NULL; 4020c16b537SWarner Losh char* fileNamesBuf = NULL; 4030c16b537SWarner Losh unsigned fileNamesNb; 4040c16b537SWarner Losh #endif 4050c16b537SWarner Losh #ifndef ZSTD_NODICT 4060c16b537SWarner Losh ZDICT_cover_params_t coverParams = defaultCoverParams(); 4070c16b537SWarner Losh int cover = 1; 4080c16b537SWarner Losh #endif 4090c16b537SWarner Losh 4100c16b537SWarner Losh 4110c16b537SWarner Losh /* init */ 4120c16b537SWarner Losh (void)recursive; (void)cLevelLast; /* not used when ZSTD_NOBENCH set */ 4130c16b537SWarner Losh (void)dictCLevel; (void)dictSelect; (void)dictID; (void)maxDictSize; /* not used when ZSTD_NODICT set */ 4140c16b537SWarner Losh (void)ultra; (void)cLevel; (void)ldmFlag; /* not used when ZSTD_NOCOMPRESS set */ 4150c16b537SWarner Losh (void)memLimit; /* not used when ZSTD_NODECOMPRESS set */ 4160c16b537SWarner Losh if (filenameTable==NULL) { DISPLAY("zstd: %s \n", strerror(errno)); exit(1); } 4170c16b537SWarner Losh filenameTable[0] = stdinmark; 4180c16b537SWarner Losh g_displayOut = stderr; 4190c16b537SWarner Losh 4200c16b537SWarner Losh programName = lastNameFromPath(programName); 4210c16b537SWarner Losh 4220c16b537SWarner Losh /* preset behaviors */ 4230c16b537SWarner Losh if (exeNameMatch(programName, ZSTD_ZSTDMT)) nbThreads=0; 4240c16b537SWarner Losh if (exeNameMatch(programName, ZSTD_UNZSTD)) operation=zom_decompress; 4251ad8ac7aSBaptiste Daroussin if (exeNameMatch(programName, ZSTD_CAT)) { operation=zom_decompress; forceStdout=1; FIO_overwriteMode(); outFileName=stdoutmark; g_displayLevel=1; } 4260c16b537SWarner Losh if (exeNameMatch(programName, ZSTD_GZ)) { suffix = GZ_EXTENSION; FIO_setCompressionType(FIO_gzipCompression); FIO_setRemoveSrcFile(1); } /* behave like gzip */ 4270c16b537SWarner Losh if (exeNameMatch(programName, ZSTD_GUNZIP)) { operation=zom_decompress; FIO_setRemoveSrcFile(1); } /* behave like gunzip */ 4280c16b537SWarner Losh if (exeNameMatch(programName, ZSTD_GZCAT)) { operation=zom_decompress; forceStdout=1; FIO_overwriteMode(); outFileName=stdoutmark; g_displayLevel=1; } /* behave like gzcat */ 4290c16b537SWarner Losh if (exeNameMatch(programName, ZSTD_LZMA)) { suffix = LZMA_EXTENSION; FIO_setCompressionType(FIO_lzmaCompression); FIO_setRemoveSrcFile(1); } /* behave like lzma */ 4300c16b537SWarner Losh if (exeNameMatch(programName, ZSTD_UNLZMA)) { operation=zom_decompress; FIO_setCompressionType(FIO_lzmaCompression); FIO_setRemoveSrcFile(1); } /* behave like unlzma */ 4310c16b537SWarner Losh if (exeNameMatch(programName, ZSTD_XZ)) { suffix = XZ_EXTENSION; FIO_setCompressionType(FIO_xzCompression); FIO_setRemoveSrcFile(1); } /* behave like xz */ 4320c16b537SWarner Losh if (exeNameMatch(programName, ZSTD_UNXZ)) { operation=zom_decompress; FIO_setCompressionType(FIO_xzCompression); FIO_setRemoveSrcFile(1); } /* behave like unxz */ 4330c16b537SWarner Losh if (exeNameMatch(programName, ZSTD_LZ4)) { suffix = LZ4_EXTENSION; FIO_setCompressionType(FIO_lz4Compression); FIO_setRemoveSrcFile(1); } /* behave like xz */ 4340c16b537SWarner Losh if (exeNameMatch(programName, ZSTD_UNLZ4)) { operation=zom_decompress; FIO_setCompressionType(FIO_lz4Compression); FIO_setRemoveSrcFile(1); } /* behave like unxz */ 4350c16b537SWarner Losh memset(&compressionParams, 0, sizeof(compressionParams)); 4360c16b537SWarner Losh 4370c16b537SWarner Losh /* command switches */ 4380c16b537SWarner Losh for (argNb=1; argNb<argCount; argNb++) { 4390c16b537SWarner Losh const char* argument = argv[argNb]; 4400c16b537SWarner Losh if(!argument) continue; /* Protection if argument empty */ 4410c16b537SWarner Losh 4420c16b537SWarner Losh if (nextArgumentsAreFiles==0) { 4430c16b537SWarner Losh /* "-" means stdin/stdout */ 4440c16b537SWarner Losh if (!strcmp(argument, "-")){ 4450c16b537SWarner Losh if (!filenameIdx) { 4460c16b537SWarner Losh filenameIdx=1, filenameTable[0]=stdinmark; 4470c16b537SWarner Losh outFileName=stdoutmark; 4480c16b537SWarner Losh g_displayLevel-=(g_displayLevel==2); 4490c16b537SWarner Losh continue; 4500c16b537SWarner Losh } } 4510c16b537SWarner Losh 4520c16b537SWarner Losh /* Decode commands (note : aggregated commands are allowed) */ 4530c16b537SWarner Losh if (argument[0]=='-') { 4540c16b537SWarner Losh 4550c16b537SWarner Losh if (argument[1]=='-') { 4560c16b537SWarner Losh /* long commands (--long-word) */ 4570c16b537SWarner Losh if (!strcmp(argument, "--")) { nextArgumentsAreFiles=1; continue; } /* only file names allowed from now on */ 4580c16b537SWarner Losh if (!strcmp(argument, "--list")) { operation=zom_list; continue; } 4590c16b537SWarner Losh if (!strcmp(argument, "--compress")) { operation=zom_compress; continue; } 4600c16b537SWarner Losh if (!strcmp(argument, "--decompress")) { operation=zom_decompress; continue; } 4610c16b537SWarner Losh if (!strcmp(argument, "--uncompress")) { operation=zom_decompress; continue; } 4620c16b537SWarner Losh if (!strcmp(argument, "--force")) { FIO_overwriteMode(); forceStdout=1; followLinks=1; continue; } 4630c16b537SWarner Losh if (!strcmp(argument, "--version")) { g_displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); } 4640c16b537SWarner Losh if (!strcmp(argument, "--help")) { g_displayOut=stdout; CLEAN_RETURN(usage_advanced(programName)); } 4650c16b537SWarner Losh if (!strcmp(argument, "--verbose")) { g_displayLevel++; continue; } 4660c16b537SWarner Losh if (!strcmp(argument, "--quiet")) { g_displayLevel--; continue; } 4670c16b537SWarner Losh if (!strcmp(argument, "--stdout")) { forceStdout=1; outFileName=stdoutmark; g_displayLevel-=(g_displayLevel==2); continue; } 4680c16b537SWarner Losh if (!strcmp(argument, "--ultra")) { ultra=1; continue; } 4690c16b537SWarner Losh if (!strcmp(argument, "--check")) { FIO_setChecksumFlag(2); continue; } 4700c16b537SWarner Losh if (!strcmp(argument, "--no-check")) { FIO_setChecksumFlag(0); continue; } 4710c16b537SWarner Losh if (!strcmp(argument, "--sparse")) { FIO_setSparseWrite(2); continue; } 4720c16b537SWarner Losh if (!strcmp(argument, "--no-sparse")) { FIO_setSparseWrite(0); continue; } 4730c16b537SWarner Losh if (!strcmp(argument, "--test")) { operation=zom_test; continue; } 4740c16b537SWarner Losh if (!strcmp(argument, "--train")) { operation=zom_train; outFileName=g_defaultDictName; continue; } 4750c16b537SWarner Losh if (!strcmp(argument, "--maxdict")) { nextArgumentIsMaxDict=1; lastCommand=1; continue; } /* kept available for compatibility with old syntax ; will be removed one day */ 4760c16b537SWarner Losh if (!strcmp(argument, "--dictID")) { nextArgumentIsDictID=1; lastCommand=1; continue; } /* kept available for compatibility with old syntax ; will be removed one day */ 4770c16b537SWarner Losh if (!strcmp(argument, "--no-dictID")) { FIO_setDictIDFlag(0); continue; } 4780c16b537SWarner Losh if (!strcmp(argument, "--keep")) { FIO_setRemoveSrcFile(0); continue; } 4790c16b537SWarner Losh if (!strcmp(argument, "--rm")) { FIO_setRemoveSrcFile(1); continue; } 4800c16b537SWarner Losh if (!strcmp(argument, "--priority=rt")) { setRealTimePrio = 1; continue; } 4810c16b537SWarner Losh #ifdef ZSTD_GZCOMPRESS 4820c16b537SWarner Losh if (!strcmp(argument, "--format=gzip")) { suffix = GZ_EXTENSION; FIO_setCompressionType(FIO_gzipCompression); continue; } 4830c16b537SWarner Losh #endif 4840c16b537SWarner Losh #ifdef ZSTD_LZMACOMPRESS 4850c16b537SWarner Losh if (!strcmp(argument, "--format=lzma")) { suffix = LZMA_EXTENSION; FIO_setCompressionType(FIO_lzmaCompression); continue; } 4860c16b537SWarner Losh if (!strcmp(argument, "--format=xz")) { suffix = XZ_EXTENSION; FIO_setCompressionType(FIO_xzCompression); continue; } 4870c16b537SWarner Losh #endif 4880c16b537SWarner Losh #ifdef ZSTD_LZ4COMPRESS 4890c16b537SWarner Losh if (!strcmp(argument, "--format=lz4")) { suffix = LZ4_EXTENSION; FIO_setCompressionType(FIO_lz4Compression); continue; } 4900c16b537SWarner Losh #endif 4910c16b537SWarner Losh 4920c16b537SWarner Losh /* long commands with arguments */ 4930c16b537SWarner Losh #ifndef ZSTD_NODICT 4940c16b537SWarner Losh if (longCommandWArg(&argument, "--train-cover")) { 4950c16b537SWarner Losh operation = zom_train; 4960c16b537SWarner Losh outFileName = g_defaultDictName; 4970c16b537SWarner Losh cover = 1; 4980c16b537SWarner Losh /* Allow optional arguments following an = */ 4990c16b537SWarner Losh if (*argument == 0) { memset(&coverParams, 0, sizeof(coverParams)); } 5000c16b537SWarner Losh else if (*argument++ != '=') { CLEAN_RETURN(badusage(programName)); } 5010c16b537SWarner Losh else if (!parseCoverParameters(argument, &coverParams)) { CLEAN_RETURN(badusage(programName)); } 5020c16b537SWarner Losh continue; 5030c16b537SWarner Losh } 5040c16b537SWarner Losh if (longCommandWArg(&argument, "--train-legacy")) { 5050c16b537SWarner Losh operation = zom_train; 5060c16b537SWarner Losh outFileName = g_defaultDictName; 5070c16b537SWarner Losh cover = 0; 5080c16b537SWarner Losh /* Allow optional arguments following an = */ 5090c16b537SWarner Losh if (*argument == 0) { continue; } 5100c16b537SWarner Losh else if (*argument++ != '=') { CLEAN_RETURN(badusage(programName)); } 5110c16b537SWarner Losh else if (!parseLegacyParameters(argument, &dictSelect)) { CLEAN_RETURN(badusage(programName)); } 5120c16b537SWarner Losh continue; 5130c16b537SWarner Losh } 5140c16b537SWarner Losh #endif 5150c16b537SWarner Losh if (longCommandWArg(&argument, "--threads=")) { nbThreads = readU32FromChar(&argument); continue; } 5160c16b537SWarner Losh if (longCommandWArg(&argument, "--memlimit=")) { memLimit = readU32FromChar(&argument); continue; } 5170c16b537SWarner Losh if (longCommandWArg(&argument, "--memory=")) { memLimit = readU32FromChar(&argument); continue; } 5180c16b537SWarner Losh if (longCommandWArg(&argument, "--memlimit-decompress=")) { memLimit = readU32FromChar(&argument); continue; } 5190c16b537SWarner Losh if (longCommandWArg(&argument, "--block-size=")) { blockSize = readU32FromChar(&argument); continue; } 5200c16b537SWarner Losh if (longCommandWArg(&argument, "--maxdict=")) { maxDictSize = readU32FromChar(&argument); continue; } 5210c16b537SWarner Losh if (longCommandWArg(&argument, "--dictID=")) { dictID = readU32FromChar(&argument); continue; } 5220c16b537SWarner Losh if (longCommandWArg(&argument, "--zstd=")) { if (!parseCompressionParameters(argument, &compressionParams)) CLEAN_RETURN(badusage(programName)); continue; } 5230c16b537SWarner Losh if (longCommandWArg(&argument, "--long")) { 5240c16b537SWarner Losh unsigned ldmWindowLog = 0; 5250c16b537SWarner Losh ldmFlag = 1; 5260c16b537SWarner Losh /* Parse optional window log */ 5270c16b537SWarner Losh if (*argument == '=') { 5280c16b537SWarner Losh ++argument; 5290c16b537SWarner Losh ldmWindowLog = readU32FromChar(&argument); 5300c16b537SWarner Losh } else if (*argument != 0) { 5310c16b537SWarner Losh /* Invalid character following --long */ 5320c16b537SWarner Losh CLEAN_RETURN(badusage(programName)); 5330c16b537SWarner Losh } 5340c16b537SWarner Losh /* Only set windowLog if not already set by --zstd */ 5350c16b537SWarner Losh if (compressionParams.windowLog == 0) 5360c16b537SWarner Losh compressionParams.windowLog = ldmWindowLog; 5370c16b537SWarner Losh continue; 5380c16b537SWarner Losh } 5390c16b537SWarner Losh /* fall-through, will trigger bad_usage() later on */ 5400c16b537SWarner Losh } 5410c16b537SWarner Losh 5420c16b537SWarner Losh argument++; 5430c16b537SWarner Losh while (argument[0]!=0) { 5440c16b537SWarner Losh if (lastCommand) { 5450c16b537SWarner Losh DISPLAY("error : command must be followed by argument \n"); 5460c16b537SWarner Losh CLEAN_RETURN(1); 5470c16b537SWarner Losh } 5480c16b537SWarner Losh #ifndef ZSTD_NOCOMPRESS 5490c16b537SWarner Losh /* compression Level */ 5500c16b537SWarner Losh if ((*argument>='0') && (*argument<='9')) { 5510c16b537SWarner Losh dictCLevel = cLevel = readU32FromChar(&argument); 5520c16b537SWarner Losh continue; 5530c16b537SWarner Losh } 5540c16b537SWarner Losh #endif 5550c16b537SWarner Losh 5560c16b537SWarner Losh switch(argument[0]) 5570c16b537SWarner Losh { 5580c16b537SWarner Losh /* Display help */ 5590c16b537SWarner Losh case 'V': g_displayOut=stdout; printVersion(); CLEAN_RETURN(0); /* Version Only */ 5600c16b537SWarner Losh case 'H': 5610c16b537SWarner Losh case 'h': g_displayOut=stdout; CLEAN_RETURN(usage_advanced(programName)); 5620c16b537SWarner Losh 5630c16b537SWarner Losh /* Compress */ 5640c16b537SWarner Losh case 'z': operation=zom_compress; argument++; break; 5650c16b537SWarner Losh 5660c16b537SWarner Losh /* Decoding */ 5670c16b537SWarner Losh case 'd': 5680c16b537SWarner Losh #ifndef ZSTD_NOBENCH 5690c16b537SWarner Losh if (operation==zom_bench) { BMK_setDecodeOnlyMode(1); argument++; break; } /* benchmark decode (hidden option) */ 5700c16b537SWarner Losh #endif 5710c16b537SWarner Losh operation=zom_decompress; argument++; break; 5720c16b537SWarner Losh 5730c16b537SWarner Losh /* Force stdout, even if stdout==console */ 5740c16b537SWarner Losh case 'c': forceStdout=1; outFileName=stdoutmark; argument++; break; 5750c16b537SWarner Losh 5760c16b537SWarner Losh /* Use file content as dictionary */ 5770c16b537SWarner Losh case 'D': nextEntryIsDictionary = 1; lastCommand = 1; argument++; break; 5780c16b537SWarner Losh 5790c16b537SWarner Losh /* Overwrite */ 5800c16b537SWarner Losh case 'f': FIO_overwriteMode(); forceStdout=1; followLinks=1; argument++; break; 5810c16b537SWarner Losh 5820c16b537SWarner Losh /* Verbose mode */ 5830c16b537SWarner Losh case 'v': g_displayLevel++; argument++; break; 5840c16b537SWarner Losh 5850c16b537SWarner Losh /* Quiet mode */ 5860c16b537SWarner Losh case 'q': g_displayLevel--; argument++; break; 5870c16b537SWarner Losh 5880c16b537SWarner Losh /* keep source file (default) */ 5890c16b537SWarner Losh case 'k': FIO_setRemoveSrcFile(0); argument++; break; 5900c16b537SWarner Losh 5910c16b537SWarner Losh /* Checksum */ 5920c16b537SWarner Losh case 'C': FIO_setChecksumFlag(2); argument++; break; 5930c16b537SWarner Losh 5940c16b537SWarner Losh /* test compressed file */ 5950c16b537SWarner Losh case 't': operation=zom_test; argument++; break; 5960c16b537SWarner Losh 5970c16b537SWarner Losh /* destination file name */ 5980c16b537SWarner Losh case 'o': nextArgumentIsOutFileName=1; lastCommand=1; argument++; break; 5990c16b537SWarner Losh 6000c16b537SWarner Losh /* limit decompression memory */ 6010c16b537SWarner Losh case 'M': 6020c16b537SWarner Losh argument++; 6030c16b537SWarner Losh memLimit = readU32FromChar(&argument); 6040c16b537SWarner Losh break; 6050c16b537SWarner Losh case 'l': operation=zom_list; argument++; break; 6060c16b537SWarner Losh #ifdef UTIL_HAS_CREATEFILELIST 6070c16b537SWarner Losh /* recursive */ 6080c16b537SWarner Losh case 'r': recursive=1; argument++; break; 6090c16b537SWarner Losh #endif 6100c16b537SWarner Losh 6110c16b537SWarner Losh #ifndef ZSTD_NOBENCH 6120c16b537SWarner Losh /* Benchmark */ 6130c16b537SWarner Losh case 'b': 6140c16b537SWarner Losh operation=zom_bench; 6150c16b537SWarner Losh argument++; 6160c16b537SWarner Losh break; 6170c16b537SWarner Losh 6180c16b537SWarner Losh /* range bench (benchmark only) */ 6190c16b537SWarner Losh case 'e': 6200c16b537SWarner Losh /* compression Level */ 6210c16b537SWarner Losh argument++; 6220c16b537SWarner Losh cLevelLast = readU32FromChar(&argument); 6230c16b537SWarner Losh break; 6240c16b537SWarner Losh 6250c16b537SWarner Losh /* Modify Nb Iterations (benchmark only) */ 6260c16b537SWarner Losh case 'i': 6270c16b537SWarner Losh argument++; 6280c16b537SWarner Losh bench_nbSeconds = readU32FromChar(&argument); 6290c16b537SWarner Losh break; 6300c16b537SWarner Losh 6310c16b537SWarner Losh /* cut input into blocks (benchmark only) */ 6320c16b537SWarner Losh case 'B': 6330c16b537SWarner Losh argument++; 6340c16b537SWarner Losh blockSize = readU32FromChar(&argument); 6350c16b537SWarner Losh break; 6360c16b537SWarner Losh 637*052d3c12SConrad Meyer /* benchmark files separately (hidden option) */ 638*052d3c12SConrad Meyer case 'S': 639*052d3c12SConrad Meyer argument++; 640*052d3c12SConrad Meyer separateFiles = 1; 641*052d3c12SConrad Meyer break; 642*052d3c12SConrad Meyer 6430c16b537SWarner Losh #endif /* ZSTD_NOBENCH */ 6440c16b537SWarner Losh 6450c16b537SWarner Losh /* nb of threads (hidden option) */ 6460c16b537SWarner Losh case 'T': 6470c16b537SWarner Losh argument++; 6480c16b537SWarner Losh nbThreads = readU32FromChar(&argument); 6490c16b537SWarner Losh break; 6500c16b537SWarner Losh 6510c16b537SWarner Losh /* Dictionary Selection level */ 6520c16b537SWarner Losh case 's': 6530c16b537SWarner Losh argument++; 6540c16b537SWarner Losh dictSelect = readU32FromChar(&argument); 6550c16b537SWarner Losh break; 6560c16b537SWarner Losh 6570c16b537SWarner Losh /* Pause at the end (-p) or set an additional param (-p#) (hidden option) */ 6580c16b537SWarner Losh case 'p': argument++; 6590c16b537SWarner Losh #ifndef ZSTD_NOBENCH 6600c16b537SWarner Losh if ((*argument>='0') && (*argument<='9')) { 6610c16b537SWarner Losh BMK_setAdditionalParam(readU32FromChar(&argument)); 6620c16b537SWarner Losh } else 6630c16b537SWarner Losh #endif 6640c16b537SWarner Losh main_pause=1; 6650c16b537SWarner Losh break; 6660c16b537SWarner Losh /* unknown command */ 6670c16b537SWarner Losh default : CLEAN_RETURN(badusage(programName)); 6680c16b537SWarner Losh } 6690c16b537SWarner Losh } 6700c16b537SWarner Losh continue; 6710c16b537SWarner Losh } /* if (argument[0]=='-') */ 6720c16b537SWarner Losh 6730c16b537SWarner Losh if (nextArgumentIsMaxDict) { /* kept available for compatibility with old syntax ; will be removed one day */ 6740c16b537SWarner Losh nextArgumentIsMaxDict = 0; 6750c16b537SWarner Losh lastCommand = 0; 6760c16b537SWarner Losh maxDictSize = readU32FromChar(&argument); 6770c16b537SWarner Losh continue; 6780c16b537SWarner Losh } 6790c16b537SWarner Losh 6800c16b537SWarner Losh if (nextArgumentIsDictID) { /* kept available for compatibility with old syntax ; will be removed one day */ 6810c16b537SWarner Losh nextArgumentIsDictID = 0; 6820c16b537SWarner Losh lastCommand = 0; 6830c16b537SWarner Losh dictID = readU32FromChar(&argument); 6840c16b537SWarner Losh continue; 6850c16b537SWarner Losh } 6860c16b537SWarner Losh 6870c16b537SWarner Losh } /* if (nextArgumentIsAFile==0) */ 6880c16b537SWarner Losh 6890c16b537SWarner Losh if (nextEntryIsDictionary) { 6900c16b537SWarner Losh nextEntryIsDictionary = 0; 6910c16b537SWarner Losh lastCommand = 0; 6920c16b537SWarner Losh dictFileName = argument; 6930c16b537SWarner Losh continue; 6940c16b537SWarner Losh } 6950c16b537SWarner Losh 6960c16b537SWarner Losh if (nextArgumentIsOutFileName) { 6970c16b537SWarner Losh nextArgumentIsOutFileName = 0; 6980c16b537SWarner Losh lastCommand = 0; 6990c16b537SWarner Losh outFileName = argument; 7000c16b537SWarner Losh if (!strcmp(outFileName, "-")) outFileName = stdoutmark; 7010c16b537SWarner Losh continue; 7020c16b537SWarner Losh } 7030c16b537SWarner Losh 7040c16b537SWarner Losh /* add filename to list */ 7050c16b537SWarner Losh filenameTable[filenameIdx++] = argument; 7060c16b537SWarner Losh } 7070c16b537SWarner Losh 7080c16b537SWarner Losh if (lastCommand) { /* forgotten argument */ 7090c16b537SWarner Losh DISPLAY("error : command must be followed by argument \n"); 7100c16b537SWarner Losh CLEAN_RETURN(1); 7110c16b537SWarner Losh } 7120c16b537SWarner Losh 7130c16b537SWarner Losh /* Welcome message (if verbose) */ 7140c16b537SWarner Losh DISPLAYLEVEL(3, WELCOME_MESSAGE); 7150c16b537SWarner Losh 7160c16b537SWarner Losh if (nbThreads == 0) { 7170c16b537SWarner Losh /* try to guess */ 7180c16b537SWarner Losh nbThreads = UTIL_countPhysicalCores(); 7190c16b537SWarner Losh DISPLAYLEVEL(3, "Note: %d physical core(s) detected \n", nbThreads); 7200c16b537SWarner Losh } 7210c16b537SWarner Losh 7220c16b537SWarner Losh g_utilDisplayLevel = g_displayLevel; 7230c16b537SWarner Losh if (!followLinks) { 7240c16b537SWarner Losh unsigned u; 7250c16b537SWarner Losh for (u=0, fileNamesNb=0; u<filenameIdx; u++) { 7260c16b537SWarner Losh if (UTIL_isLink(filenameTable[u])) { 7270c16b537SWarner Losh DISPLAYLEVEL(2, "Warning : %s is a symbolic link, ignoring\n", filenameTable[u]); 7280c16b537SWarner Losh } else { 7290c16b537SWarner Losh filenameTable[fileNamesNb++] = filenameTable[u]; 7300c16b537SWarner Losh } 7310c16b537SWarner Losh } 7320c16b537SWarner Losh filenameIdx = fileNamesNb; 7330c16b537SWarner Losh } 7340c16b537SWarner Losh #ifdef UTIL_HAS_CREATEFILELIST 7350c16b537SWarner Losh if (recursive) { /* at this stage, filenameTable is a list of paths, which can contain both files and directories */ 7360c16b537SWarner Losh extendedFileList = UTIL_createFileList(filenameTable, filenameIdx, &fileNamesBuf, &fileNamesNb, followLinks); 7370c16b537SWarner Losh if (extendedFileList) { 7380c16b537SWarner Losh unsigned u; 7390c16b537SWarner Losh for (u=0; u<fileNamesNb; u++) DISPLAYLEVEL(4, "%u %s\n", u, extendedFileList[u]); 7400c16b537SWarner Losh free((void*)filenameTable); 7410c16b537SWarner Losh filenameTable = extendedFileList; 7420c16b537SWarner Losh filenameIdx = fileNamesNb; 7430c16b537SWarner Losh } 7440c16b537SWarner Losh } 7450c16b537SWarner Losh #endif 7460c16b537SWarner Losh 7470c16b537SWarner Losh if (operation == zom_list) { 7480c16b537SWarner Losh #ifndef ZSTD_NODECOMPRESS 7490c16b537SWarner Losh int const ret = FIO_listMultipleFiles(filenameIdx, filenameTable, g_displayLevel); 7500c16b537SWarner Losh CLEAN_RETURN(ret); 7510c16b537SWarner Losh #else 7520c16b537SWarner Losh DISPLAY("file information is not supported \n"); 7530c16b537SWarner Losh CLEAN_RETURN(1); 7540c16b537SWarner Losh #endif 7550c16b537SWarner Losh } 7560c16b537SWarner Losh 7570c16b537SWarner Losh /* Check if benchmark is selected */ 7580c16b537SWarner Losh if (operation==zom_bench) { 7590c16b537SWarner Losh #ifndef ZSTD_NOBENCH 7600c16b537SWarner Losh BMK_setNotificationLevel(g_displayLevel); 761*052d3c12SConrad Meyer BMK_setSeparateFiles(separateFiles); 7620c16b537SWarner Losh BMK_setBlockSize(blockSize); 7630c16b537SWarner Losh BMK_setNbThreads(nbThreads); 764*052d3c12SConrad Meyer BMK_setRealTime(setRealTimePrio); 7650c16b537SWarner Losh BMK_setNbSeconds(bench_nbSeconds); 7660c16b537SWarner Losh BMK_setLdmFlag(ldmFlag); 7670c16b537SWarner Losh BMK_setLdmMinMatch(g_ldmMinMatch); 7680c16b537SWarner Losh BMK_setLdmHashLog(g_ldmHashLog); 7690c16b537SWarner Losh if (g_ldmBucketSizeLog != LDM_PARAM_DEFAULT) { 7700c16b537SWarner Losh BMK_setLdmBucketSizeLog(g_ldmBucketSizeLog); 7710c16b537SWarner Losh } 7720c16b537SWarner Losh if (g_ldmHashEveryLog != LDM_PARAM_DEFAULT) { 7730c16b537SWarner Losh BMK_setLdmHashEveryLog(g_ldmHashEveryLog); 7740c16b537SWarner Losh } 775*052d3c12SConrad Meyer BMK_benchFiles(filenameTable, filenameIdx, dictFileName, cLevel, cLevelLast, &compressionParams); 776*052d3c12SConrad Meyer #else 777*052d3c12SConrad Meyer (void)bench_nbSeconds; (void)blockSize; (void)setRealTimePrio; (void)separateFiles; 7780c16b537SWarner Losh #endif 7790c16b537SWarner Losh goto _end; 7800c16b537SWarner Losh } 7810c16b537SWarner Losh 7820c16b537SWarner Losh /* Check if dictionary builder is selected */ 7830c16b537SWarner Losh if (operation==zom_train) { 7840c16b537SWarner Losh #ifndef ZSTD_NODICT 7850c16b537SWarner Losh ZDICT_params_t zParams; 7860c16b537SWarner Losh zParams.compressionLevel = dictCLevel; 7870c16b537SWarner Losh zParams.notificationLevel = g_displayLevel; 7880c16b537SWarner Losh zParams.dictID = dictID; 7890c16b537SWarner Losh if (cover) { 7900c16b537SWarner Losh int const optimize = !coverParams.k || !coverParams.d; 7910c16b537SWarner Losh coverParams.nbThreads = nbThreads; 7920c16b537SWarner Losh coverParams.zParams = zParams; 7930c16b537SWarner Losh operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, blockSize, NULL, &coverParams, optimize); 7940c16b537SWarner Losh } else { 7950c16b537SWarner Losh ZDICT_legacy_params_t dictParams; 7960c16b537SWarner Losh memset(&dictParams, 0, sizeof(dictParams)); 7970c16b537SWarner Losh dictParams.selectivityLevel = dictSelect; 7980c16b537SWarner Losh dictParams.zParams = zParams; 7990c16b537SWarner Losh operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, blockSize, &dictParams, NULL, 0); 8000c16b537SWarner Losh } 8010c16b537SWarner Losh #endif 8020c16b537SWarner Losh goto _end; 8030c16b537SWarner Losh } 8040c16b537SWarner Losh 8050c16b537SWarner Losh #ifndef ZSTD_NODECOMPRESS 8060c16b537SWarner Losh if (operation==zom_test) { outFileName=nulmark; FIO_setRemoveSrcFile(0); } /* test mode */ 8070c16b537SWarner Losh #endif 8080c16b537SWarner Losh 8090c16b537SWarner Losh /* No input filename ==> use stdin and stdout */ 8100c16b537SWarner Losh filenameIdx += !filenameIdx; /* filenameTable[0] is stdin by default */ 8110c16b537SWarner Losh if (!strcmp(filenameTable[0], stdinmark) && !outFileName) outFileName = stdoutmark; /* when input is stdin, default output is stdout */ 8120c16b537SWarner Losh 8130c16b537SWarner Losh /* Check if input/output defined as console; trigger an error in this case */ 8140c16b537SWarner Losh if (!strcmp(filenameTable[0], stdinmark) && IS_CONSOLE(stdin) ) CLEAN_RETURN(badusage(programName)); 8150c16b537SWarner Losh if (outFileName && !strcmp(outFileName, stdoutmark) && IS_CONSOLE(stdout) && !strcmp(filenameTable[0], stdinmark) && !forceStdout && operation!=zom_decompress) 8160c16b537SWarner Losh CLEAN_RETURN(badusage(programName)); 8170c16b537SWarner Losh 8180c16b537SWarner Losh #ifndef ZSTD_NOCOMPRESS 8190c16b537SWarner Losh /* check compression level limits */ 8200c16b537SWarner Losh { int const maxCLevel = ultra ? ZSTD_maxCLevel() : ZSTDCLI_CLEVEL_MAX; 8210c16b537SWarner Losh if (cLevel > maxCLevel) { 8220c16b537SWarner Losh DISPLAYLEVEL(2, "Warning : compression level higher than max, reduced to %i \n", maxCLevel); 8230c16b537SWarner Losh cLevel = maxCLevel; 8240c16b537SWarner Losh } } 8250c16b537SWarner Losh #endif 8260c16b537SWarner Losh 8270c16b537SWarner Losh /* No status message in pipe mode (stdin - stdout) or multi-files mode */ 8280c16b537SWarner Losh if (!strcmp(filenameTable[0], stdinmark) && outFileName && !strcmp(outFileName,stdoutmark) && (g_displayLevel==2)) g_displayLevel=1; 8290c16b537SWarner Losh if ((filenameIdx>1) & (g_displayLevel==2)) g_displayLevel=1; 8300c16b537SWarner Losh 8310c16b537SWarner Losh /* IO Stream/File */ 8320c16b537SWarner Losh FIO_setNotificationLevel(g_displayLevel); 8330c16b537SWarner Losh if (operation==zom_compress) { 8340c16b537SWarner Losh #ifndef ZSTD_NOCOMPRESS 8350c16b537SWarner Losh FIO_setNbThreads(nbThreads); 8360c16b537SWarner Losh FIO_setBlockSize((U32)blockSize); 8370c16b537SWarner Losh FIO_setLdmFlag(ldmFlag); 8380c16b537SWarner Losh FIO_setLdmHashLog(g_ldmHashLog); 8390c16b537SWarner Losh FIO_setLdmMinMatch(g_ldmMinMatch); 8400c16b537SWarner Losh if (g_ldmBucketSizeLog != LDM_PARAM_DEFAULT) { 8410c16b537SWarner Losh FIO_setLdmBucketSizeLog(g_ldmBucketSizeLog); 8420c16b537SWarner Losh } 8430c16b537SWarner Losh if (g_ldmHashEveryLog != LDM_PARAM_DEFAULT) { 8440c16b537SWarner Losh FIO_setLdmHashEveryLog(g_ldmHashEveryLog); 8450c16b537SWarner Losh } 8460c16b537SWarner Losh 8470c16b537SWarner Losh if (g_overlapLog!=OVERLAP_LOG_DEFAULT) FIO_setOverlapLog(g_overlapLog); 8480c16b537SWarner Losh if ((filenameIdx==1) && outFileName) 8490c16b537SWarner Losh operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel, &compressionParams); 8500c16b537SWarner Losh else 851*052d3c12SConrad Meyer operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, outFileName, suffix, dictFileName, cLevel, &compressionParams); 8520c16b537SWarner Losh #else 8530c16b537SWarner Losh (void)suffix; 8540c16b537SWarner Losh DISPLAY("Compression not supported\n"); 8550c16b537SWarner Losh #endif 8560c16b537SWarner Losh } else { /* decompression or test */ 8570c16b537SWarner Losh #ifndef ZSTD_NODECOMPRESS 8580c16b537SWarner Losh if (memLimit == 0) { 8590c16b537SWarner Losh if (compressionParams.windowLog == 0) 8600c16b537SWarner Losh memLimit = (U32)1 << g_defaultMaxWindowLog; 8610c16b537SWarner Losh else { 8620c16b537SWarner Losh memLimit = (U32)1 << (compressionParams.windowLog & 31); 8630c16b537SWarner Losh } 8640c16b537SWarner Losh } 8650c16b537SWarner Losh FIO_setMemLimit(memLimit); 8660c16b537SWarner Losh if (filenameIdx==1 && outFileName) 8670c16b537SWarner Losh operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName); 8680c16b537SWarner Losh else 869*052d3c12SConrad Meyer operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, outFileName, dictFileName); 8700c16b537SWarner Losh #else 8710c16b537SWarner Losh DISPLAY("Decompression not supported\n"); 8720c16b537SWarner Losh #endif 8730c16b537SWarner Losh } 8740c16b537SWarner Losh 8750c16b537SWarner Losh _end: 8760c16b537SWarner Losh if (main_pause) waitEnter(); 8770c16b537SWarner Losh #ifdef UTIL_HAS_CREATEFILELIST 8780c16b537SWarner Losh if (extendedFileList) 8790c16b537SWarner Losh UTIL_freeFileList(extendedFileList, fileNamesBuf); 8800c16b537SWarner Losh else 8810c16b537SWarner Losh #endif 8820c16b537SWarner Losh free((void*)filenameTable); 8830c16b537SWarner Losh return operationResult; 8840c16b537SWarner Losh } 885