int main(int argc, char** argv) { int i, bench=0, decode=0, forceStdout=0, main_pause=0, rangeBench = 1; unsigned fileNameStart = 0; unsigned nbFiles = 0; unsigned cLevel = 1; const char* programName = argv[0]; const char* inFileName = NULL; const char* outFileName = NULL; char* dynNameSpace = NULL; char extension[] = ZSTD_EXTENSION; displayOut = stderr; /* Pick out basename component. Don't rely on stdlib because of conflicting behavior. */ for (i = (int)strlen(programName); i > 0; i--) { if (programName[i] == '/') { i++; break; } } programName += i; /* zstdcat preset behavior */ if (!strcmp(programName, ZSTD_CAT)) { decode=1; forceStdout=1; displayLevel=1; outFileName=stdoutmark; } /* unzstd preset behavior */ if (!strcmp(programName, ZSTD_UNZSTD)) decode=1; /* command switches */ for(i=1; i<argc; i++) { char* argument = argv[i]; if(!argument) continue; /* Protection if argument empty */ /* long commands (--long-word) */ if (!strcmp(argument, "--version")) { displayOut=stdout; DISPLAY(WELCOME_MESSAGE); return 0; } if (!strcmp(argument, "--help")) { displayOut=stdout; return usage_advanced(programName); } if (!strcmp(argument, "--verbose")) { displayLevel=4; continue; } /* Decode commands (note : aggregated commands are allowed) */ if (argument[0]=='-') { /* '-' means stdin/stdout */ if (argument[1]==0) { if (!inFileName) inFileName=stdinmark; else outFileName=stdoutmark; continue; } argument++; while (argument[0]!=0) { /* compression Level */ if ((*argument>='0') && (*argument<='9')) { cLevel = 0; while ((*argument >= '0') && (*argument <= '9')) { cLevel *= 10; cLevel += *argument - '0'; argument++; } continue; } switch(argument[0]) { /* Display help */ case 'V': displayOut=stdout; DISPLAY(WELCOME_MESSAGE); return 0; /* Version Only */ case 'H': case 'h': displayOut=stdout; return usage_advanced(programName); /* Compression (default) */ //case 'z': forceCompress = 1; break; /* Decoding */ case 'd': decode=1; argument++; break; /* Force stdout, even if stdout==console */ case 'c': forceStdout=1; outFileName=stdoutmark; displayLevel=1; argument++; break; // Test //case 't': decode=1; LZ4IO_setOverwrite(1); output_filename=nulmark; break; /* Overwrite */ case 'f': FIO_overwriteMode(); argument++; break; /* Verbose mode */ case 'v': displayLevel=4; argument++; break; /* Quiet mode */ case 'q': displayLevel--; argument++; break; /* keep source file (default anyway, so useless; only for xz/lzma compatibility) */ case 'k': argument++; break; /* Benchmark */ case 'b': bench=1; argument++; break; /* Modify Nb Iterations (benchmark only) */ case 'i': { int iters= 0; argument++; while ((*argument >='0') && (*argument <='9')) iters *= 10, iters += *argument++ - '0'; BMK_SetNbIterations(iters); } break; /* cut input into blocks (benchmark only) */ case 'B': { size_t bSize = 0; argument++; while ((*argument >='0') && (*argument <='9')) bSize *= 10, bSize += *argument++ - '0'; if (*argument=='K') bSize<<=10, argument++; /* allows using KB notation */ if (*argument=='M') bSize<<=20, argument++; if (*argument=='B') argument++; BMK_SetBlockSize(bSize); } break; /* range bench (benchmark only) */ case 'r': rangeBench = -1; argument++; break; /* Pause at the end (hidden option) */ case 'p': main_pause=1; argument++; break; /* unknown command */ default : return badusage(programName); } } continue; } /* first provided filename is input */ if (!inFileName) { inFileName = argument; fileNameStart = i; nbFiles = argc-i; continue; } /* second provided filename is output */ if (!outFileName) { outFileName = argument; if (!strcmp (outFileName, nullString)) outFileName = nulmark; continue; } } /* Welcome message (if verbose) */ DISPLAYLEVEL(3, WELCOME_MESSAGE); /* No input filename ==> use stdin */ if(!inFileName) { inFileName=stdinmark; } /* Check if input defined as console; trigger an error in this case */ if (!strcmp(inFileName, stdinmark) && IS_CONSOLE(stdin) ) return badusage(programName); /* Check if benchmark is selected */ if (bench) { BMK_benchFiles(argv+fileNameStart, nbFiles, cLevel*rangeBench); goto _end; } /* No output filename ==> try to select one automatically (when possible) */ while (!outFileName) { if (!IS_CONSOLE(stdout)) { outFileName=stdoutmark; break; } /* Default to stdout whenever possible (i.e. not a console) */ if (!decode) /* compression to file */ { size_t l = strlen(inFileName); dynNameSpace = (char*)calloc(1,l+5); if (dynNameSpace==NULL) { DISPLAY("not enough memory\n"); exit(1); } strcpy(dynNameSpace, inFileName); strcpy(dynNameSpace+l, ZSTD_EXTENSION); outFileName = dynNameSpace; DISPLAYLEVEL(2, "Compressed filename will be : %s \n", outFileName); break; } /* decompression to file (automatic name will work only if input filename has correct format extension) */ { size_t outl; size_t inl = strlen(inFileName); dynNameSpace = (char*)calloc(1,inl+1); if (dynNameSpace==NULL) { DISPLAY("not enough memory\n"); exit(1); } outFileName = dynNameSpace; strcpy(dynNameSpace, inFileName); outl = inl; if (inl>4) while ((outl >= inl-4) && (inFileName[outl] == extension[outl-inl+4])) dynNameSpace[outl--]=0; if (outl != inl-5) { DISPLAYLEVEL(1, "Cannot determine an output filename\n"); return badusage(programName); } DISPLAYLEVEL(2, "Decoding file %s \n", outFileName); } } /* Check if output is defined as console; trigger an error in this case */ if (!strcmp(outFileName,stdoutmark) && IS_CONSOLE(stdout) && !forceStdout) return badusage(programName); /* No warning message in pure pipe mode (stdin + stdout) */ if (!strcmp(inFileName, stdinmark) && !strcmp(outFileName,stdoutmark) && (displayLevel==2)) displayLevel=1; /* IO Stream/File */ FIO_setNotificationLevel(displayLevel); if (decode) FIO_decompressFilename(outFileName, inFileName); else FIO_compressFilename(outFileName, inFileName, cLevel); _end: if (main_pause) waitEnter(); free(dynNameSpace); return 0; }
int main(int argCount, const char** argv) { int argNb, bench=0, decode=0, testmode=0, forceStdout=0, main_pause=0, nextEntryIsDictionary=0, operationResult=0, dictBuild=0, nextArgumentIsOutFileName=0, nextArgumentIsMaxDict=0, nextArgumentIsDictID=0, nextArgumentIsFile=0; int cLevel = ZSTDCLI_CLEVEL_DEFAULT; int cLevelLast = 1; unsigned recursive = 0; const char** filenameTable = (const char**)malloc(argCount * sizeof(const char*)); /* argCount >= 1 */ unsigned filenameIdx = 0; const char* programName = argv[0]; const char* outFileName = NULL; const char* dictFileName = NULL; char* dynNameSpace = NULL; unsigned maxDictSize = g_defaultMaxDictSize; unsigned dictID = 0; int dictCLevel = g_defaultDictCLevel; unsigned dictSelect = g_defaultSelectivityLevel; #ifdef UTIL_HAS_CREATEFILELIST const char** fileNamesTable = NULL; char* fileNamesBuf = NULL; unsigned fileNamesNb; #endif /* init */ (void)recursive; (void)cLevelLast; /* not used when ZSTD_NOBENCH set */ (void)dictCLevel; (void)dictSelect; (void)dictID; /* not used when ZSTD_NODICT set */ (void)decode; (void)cLevel; /* not used when ZSTD_NOCOMPRESS set */ if (filenameTable==NULL) { DISPLAY("zstd: %s \n", strerror(errno)); exit(1); } filenameTable[0] = stdinmark; displayOut = stderr; /* Pick out program name from path. Don't rely on stdlib because of conflicting behavior */ { size_t pos; for (pos = (int)strlen(programName); pos > 0; pos--) { if (programName[pos] == '/') { pos++; break; } } programName += pos; } /* preset behaviors */ if (!strcmp(programName, ZSTD_UNZSTD)) decode=1; if (!strcmp(programName, ZSTD_CAT)) { decode=1; forceStdout=1; displayLevel=1; outFileName=stdoutmark; } /* command switches */ for(argNb=1; argNb<argCount; argNb++) { const char* argument = argv[argNb]; if(!argument) continue; /* Protection if argument empty */ if (nextArgumentIsFile==0) { /* long commands (--long-word) */ if (!strcmp(argument, "--")) { nextArgumentIsFile=1; continue; } if (!strcmp(argument, "--decompress")) { decode=1; continue; } if (!strcmp(argument, "--force")) { FIO_overwriteMode(); continue; } if (!strcmp(argument, "--version")) { displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); } if (!strcmp(argument, "--help")) { displayOut=stdout; CLEAN_RETURN(usage_advanced(programName)); } if (!strcmp(argument, "--verbose")) { displayLevel++; continue; } if (!strcmp(argument, "--quiet")) { displayLevel--; continue; } if (!strcmp(argument, "--stdout")) { forceStdout=1; outFileName=stdoutmark; displayLevel-=(displayLevel==2); continue; } if (!strcmp(argument, "--ultra")) { FIO_setMaxWLog(0); continue; } if (!strcmp(argument, "--check")) { FIO_setChecksumFlag(2); continue; } if (!strcmp(argument, "--no-check")) { FIO_setChecksumFlag(0); continue; } if (!strcmp(argument, "--no-dictID")) { FIO_setDictIDFlag(0); continue; } if (!strcmp(argument, "--sparse")) { FIO_setSparseWrite(2); continue; } if (!strcmp(argument, "--no-sparse")) { FIO_setSparseWrite(0); continue; } if (!strcmp(argument, "--test")) { testmode=1; decode=1; continue; } if (!strcmp(argument, "--train")) { dictBuild=1; outFileName=g_defaultDictName; continue; } if (!strcmp(argument, "--maxdict")) { nextArgumentIsMaxDict=1; continue; } if (!strcmp(argument, "--dictID")) { nextArgumentIsDictID=1; continue; } if (!strcmp(argument, "--keep")) { FIO_setRemoveSrcFile(0); continue; } if (!strcmp(argument, "--rm")) { FIO_setRemoveSrcFile(1); continue; } /* '-' means stdin/stdout */ if (!strcmp(argument, "-")){ if (!filenameIdx) { filenameIdx=1, filenameTable[0]=stdinmark; outFileName=stdoutmark; displayLevel-=(displayLevel==2); continue; } } /* Decode commands (note : aggregated commands are allowed) */ if (argument[0]=='-') { argument++; while (argument[0]!=0) { #ifndef ZSTD_NOCOMPRESS /* compression Level */ if ((*argument>='0') && (*argument<='9')) { cLevel = readU32FromChar(&argument); dictCLevel = cLevel; if (dictCLevel > ZSTD_maxCLevel()) CLEAN_RETURN(badusage(programName)); continue; } #endif switch(argument[0]) { /* Display help */ case 'V': displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); /* Version Only */ case 'H': case 'h': displayOut=stdout; CLEAN_RETURN(usage_advanced(programName)); /* Decoding */ case 'd': decode=1; argument++; break; /* Force stdout, even if stdout==console */ case 'c': forceStdout=1; outFileName=stdoutmark; displayLevel-=(displayLevel==2); argument++; break; /* Use file content as dictionary */ case 'D': nextEntryIsDictionary = 1; argument++; break; /* Overwrite */ case 'f': FIO_overwriteMode(); forceStdout=1; argument++; break; /* Verbose mode */ case 'v': displayLevel++; argument++; break; /* Quiet mode */ case 'q': displayLevel--; argument++; break; /* keep source file (default); for gzip/xz compatibility */ case 'k': FIO_setRemoveSrcFile(0); argument++; break; /* Checksum */ case 'C': argument++; FIO_setChecksumFlag(2); break; /* test compressed file */ case 't': testmode=1; decode=1; argument++; break; /* destination file name */ case 'o': nextArgumentIsOutFileName=1; argument++; break; /* recursive */ case 'r': recursive=1; argument++; break; #ifndef ZSTD_NOBENCH /* Benchmark */ case 'b': bench=1; argument++; break; /* range bench (benchmark only) */ case 'e': /* compression Level */ argument++; cLevelLast = readU32FromChar(&argument); break; /* Modify Nb Iterations (benchmark only) */ case 'i': argument++; { U32 const iters = readU32FromChar(&argument); BMK_setNotificationLevel(displayLevel); BMK_SetNbIterations(iters); } break; /* cut input into blocks (benchmark only) */ case 'B': argument++; { size_t bSize = readU32FromChar(&argument); if (toupper(*argument)=='K') bSize<<=10, argument++; /* allows using KB notation */ if (toupper(*argument)=='M') bSize<<=20, argument++; if (toupper(*argument)=='B') argument++; BMK_setNotificationLevel(displayLevel); BMK_SetBlockSize(bSize); } break; #endif /* ZSTD_NOBENCH */ /* Dictionary Selection level */ case 's': argument++; dictSelect = readU32FromChar(&argument); break; /* Pause at the end (-p) or set an additional param (-p#) (hidden option) */ case 'p': argument++; #ifndef ZSTD_NOBENCH if ((*argument>='0') && (*argument<='9')) { BMK_setAdditionalParam(readU32FromChar(&argument)); } else #endif main_pause=1; break; /* unknown command */ default : CLEAN_RETURN(badusage(programName)); } } continue; } /* if (argument[0]=='-') */ if (nextArgumentIsMaxDict) { nextArgumentIsMaxDict = 0; maxDictSize = readU32FromChar(&argument); if (toupper(*argument)=='K') maxDictSize <<= 10; if (toupper(*argument)=='M') maxDictSize <<= 20; continue; } if (nextArgumentIsDictID) { nextArgumentIsDictID = 0; dictID = readU32FromChar(&argument); continue; } } /* if (nextArgumentIsAFile==0) */ if (nextEntryIsDictionary) { nextEntryIsDictionary = 0; dictFileName = argument; continue; } if (nextArgumentIsOutFileName) { nextArgumentIsOutFileName = 0; outFileName = argument; if (!strcmp(outFileName, "-")) outFileName = stdoutmark; continue; } /* add filename to list */ filenameTable[filenameIdx++] = argument; } /* Welcome message (if verbose) */ DISPLAYLEVEL(3, WELCOME_MESSAGE); #ifdef UTIL_HAS_CREATEFILELIST if (recursive) { fileNamesTable = UTIL_createFileList(filenameTable, filenameIdx, &fileNamesBuf, &fileNamesNb); if (fileNamesTable) { unsigned i; for (i=0; i<fileNamesNb; i++) DISPLAYLEVEL(4, "%d %s\n", i, fileNamesTable[i]); free((void*)filenameTable); filenameTable = fileNamesTable; filenameIdx = fileNamesNb; } } #endif /* Check if benchmark is selected */ if (bench) { #ifndef ZSTD_NOBENCH BMK_setNotificationLevel(displayLevel); BMK_benchFiles(filenameTable, filenameIdx, dictFileName, cLevel, cLevelLast); #endif goto _end; } /* Check if dictionary builder is selected */ if (dictBuild) { #ifndef ZSTD_NODICT ZDICT_params_t dictParams; memset(&dictParams, 0, sizeof(dictParams)); dictParams.compressionLevel = dictCLevel; dictParams.selectivityLevel = dictSelect; dictParams.notificationLevel = displayLevel; dictParams.dictID = dictID; DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, dictParams); #endif goto _end; } /* No input filename ==> use stdin and stdout */ filenameIdx += !filenameIdx; /*< default input is stdin */ if (!strcmp(filenameTable[0], stdinmark) && !outFileName) outFileName = stdoutmark; /*< when input is stdin, default output is stdout */ /* Check if input/output defined as console; trigger an error in this case */ if (!strcmp(filenameTable[0], stdinmark) && IS_CONSOLE(stdin) ) CLEAN_RETURN(badusage(programName)); if (outFileName && !strcmp(outFileName, stdoutmark) && IS_CONSOLE(stdout) && !(forceStdout && decode)) CLEAN_RETURN(badusage(programName)); /* user-selected output filename, only possible with a single file */ if (outFileName && strcmp(outFileName,stdoutmark) && strcmp(outFileName,nulmark) && (filenameIdx>1)) { DISPLAY("Too many files (%u) on the command line. \n", filenameIdx); CLEAN_RETURN(filenameIdx); } /* No warning message in pipe mode (stdin + stdout) or multiple mode */ if (!strcmp(filenameTable[0], stdinmark) && outFileName && !strcmp(outFileName,stdoutmark) && (displayLevel==2)) displayLevel=1; if ((filenameIdx>1) & (displayLevel==2)) displayLevel=1; /* IO Stream/File */ FIO_setNotificationLevel(displayLevel); #ifndef ZSTD_NOCOMPRESS if (!decode) { if (filenameIdx==1 && outFileName) operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel); else operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, outFileName ? outFileName : ZSTD_EXTENSION, dictFileName, cLevel); } else #endif { /* decompression */ #ifndef ZSTD_NODECOMPRESS if (testmode) { outFileName=nulmark; FIO_setRemoveSrcFile(0); } /* test mode */ if (filenameIdx==1 && outFileName) operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName); else operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, outFileName ? outFileName : ZSTD_EXTENSION, dictFileName); #else DISPLAY("Decompression not supported\n"); #endif } _end: if (main_pause) waitEnter(); free(dynNameSpace); #ifdef UTIL_HAS_CREATEFILELIST if (fileNamesTable) UTIL_freeFileList(fileNamesTable, fileNamesBuf); else #endif free((void*)filenameTable); return operationResult; }