New command line utility, lz4 (notice the missing final 'c'), with gzip-style argumen...
authoryann.collet.73@gmail.com <yann.collet.73@gmail.com@650e7d94-2a16-8b24-b05c-7c0b3f6821cd>
Mon, 9 Sep 2013 09:06:21 +0000 (09:06 +0000)
committeryann.collet.73@gmail.com <yann.collet.73@gmail.com@650e7d94-2a16-8b24-b05c-7c0b3f6821cd>
Mon, 9 Sep 2013 09:06:21 +0000 (09:06 +0000)
lz4c still there, supports additional gzip arguments, but also keep compatibility with legacy commands
lz4 (& lz4c) display version number
Fix : Sun Studio : compatible #pragma directive (issue 81)
Fix : compatible with Objective-C (iOS) (issue 79)
Fix : minor warnings using Visual Studio x64 (issue 80)
Changed : source file lz4c.c renamed lz4cli.c

git-svn-id: https://lz4.googlecode.com/svn/trunk@103 650e7d94-2a16-8b24-b05c-7c0b3f6821cd

Makefile
bench.c
cmake/CMakeLists.txt
cmake/pack/CMakeLists.txt
fullbench.c
lz4.c
lz4.h
lz4cli.c [moved from lz4c.c with 72% similarity]

index 995b387..e81ba77 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,38 @@
+# ################################################################
+# LZ4 Makefile
+# Copyright (C) Yann Collet 2011-2013
+# GPL v2 License
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# You can contact the author at :
+#  - LZ4 source repository : http://code.google.com/p/lz4/
+# ################################################################
+# lz4 : Command Line Utility, supporting gzip-like arguments
+# lz4c  : CLU, supporting also legacy lz4demo arguments
+# lz4c32: Same as lz4c, but forced to compile in 32-bits mode
+# fuzzer  : Test tool, to check lz4 integrity on target platform
+# fuzzer32: Same as fuzzer, but forced to compile in 32-bits mode
+# fullbench  : Precisely measure speed for each LZ4 function variant
+# fullbench32: Same as fullbench, but forced to compile in 32-bits mode
+# ################################################################
+
 CC=gcc
 CFLAGS=-I. -std=c99 -Wall -W -Wundef -Wno-implicit-function-declaration
 
+# Define *.exe as extension for Windows systems
 OS := $(shell uname)
 ifeq ($(OS),Linux)
 EXT =
@@ -10,20 +42,21 @@ endif
 
 default: lz4c
 
-all: lz4c lz4cs lz4c32 fuzzer fuzzer32 fullbench fullbench32
+all: lz4 lz4c lz4c32 fuzzer fuzzer32 fullbench fullbench32
 
-lz4c: lz4.c lz4hc.c bench.c xxhash.c lz4c.c
-       $(CC)      -O3 $(CFLAGS) $^ -o $@$(EXT)
+lz4: lz4.c lz4hc.c bench.c xxhash.c lz4cli.c
+       $(CC)      -O3 $(CFLAGS) -DDISABLE_LZ4C_LEGACY_OPTIONS $^ -o $@$(EXT)
 
-lz4cs: lz4.c lz4hc.c bench.c xxhash.c lz4c.c
-       $(CC)      -Os $(CFLAGS) $^ -o $@$(EXT)
+lz4c: lz4.c lz4hc.c bench.c xxhash.c lz4cli.c
+       $(CC)      -O3 $(CFLAGS) $^ -o $@$(EXT)
 
-lz4c32: lz4.c lz4hc.c bench.c xxhash.c lz4c.c
+lz4c32: lz4.c lz4hc.c bench.c xxhash.c lz4cli.c
        $(CC) -m32 -O3 $(CFLAGS) $^ -o $@$(EXT)
 
 fuzzer : lz4.c lz4hc.c fuzzer.c
+       @echo fuzzer is a test tool to check lz4 integrity on target platform
        $(CC)      -O3 $(CFLAGS) $^ -o $@$(EXT)
-       
+
 fuzzer32 : lz4.c lz4hc.c fuzzer.c
        $(CC) -m32 -O3 $(CFLAGS) $^ -o $@$(EXT)
 
@@ -34,4 +67,4 @@ fullbench32 : lz4.c lz4hc.c xxhash.c fullbench.c
        $(CC) -m32 -O3 $(CFLAGS) $^ -o $@$(EXT)
 
 clean:
-       rm -f core *.o lz4c$(EXT) lz4cs$(EXT) lz4c32$(EXT) fuzzer$(EXT) fullbench$(EXT) fullbench32$(EXT)
+       rm -f core *.o lz4$(EXT) lz4c$(EXT) lz4c32$(EXT) fuzzer$(EXT) fuzzer32$(EXT) fullbench$(EXT) fullbench32$(EXT)
diff --git a/bench.c b/bench.c
index 016a46e..7191c2a 100644 (file)
--- a/bench.c
+++ b/bench.c
@@ -143,11 +143,7 @@ static int chunkSize = DEFAULT_CHUNKSIZE;
 static int nbIterations = NBLOOPS;\r
 static int BMK_pause = 0;\r
 \r
-void BMK_SetBlocksize(int bsize)\r
-{\r
-    chunkSize = bsize;\r
-    DISPLAY("-Using Block Size of %i KB-\n", chunkSize>>10);\r
-}\r
+void BMK_SetBlocksize(int bsize) { chunkSize = bsize; }\r
 \r
 void BMK_SetNbIterations(int nbLoops)\r
 {\r
index 1afe650..496c076 100644 (file)
@@ -32,7 +32,7 @@ endif()
 \r
 set(SRC_DIR ../)\r
 set(LZ4_SRCS_LIB ${SRC_DIR}lz4.c ${SRC_DIR}lz4hc.c ${SRC_DIR}lz4.h )\r
-set(LZ4_SRCS ${SRC_DIR}xxhash.c ${SRC_DIR}bench.c ${SRC_DIR}lz4c.c)\r
+set(LZ4_SRCS ${SRC_DIR}xxhash.c ${SRC_DIR}bench.c ${SRC_DIR}lz4cli.c)\r
 \r
 if(NOT BUILD_SHARED_LIBS)\r
     set(LZ4_SRCS ${LZ4_SRCS} ${LZ4_SRCS_LIB})\r
index 8e59824..a9b0557 100644 (file)
@@ -42,7 +42,7 @@ INCLUDE_DIRECTORIES (${SRC_DIR})
 \r
 \r
 set(LZ4_SRCS_LIB ${SRC_DIR}lz4.c ${SRC_DIR}lz4hc.c ${SRC_DIR}lz4.h ${SRC_DIR}lz4_format_description.txt)\r
-set(LZ4_SRCS ${LZ4_SRCS_LIB} ${SRC_DIR}xxhash.c ${SRC_DIR}bench.c ${SRC_DIR}lz4c.c )\r
+set(LZ4_SRCS ${LZ4_SRCS_LIB} ${SRC_DIR}xxhash.c ${SRC_DIR}bench.c ${SRC_DIR}lz4cli.c )\r
 set(FUZZER_SRCS ${SRC_DIR}lz4.c ${SRC_DIR}lz4hc.c ${SRC_DIR}lz4.h ${SRC_DIR}fuzzer.c)\r
 \r
 # EXECUTABLES FOR 32 Bit and 64 versions\r
index abb4f92..cbb7483 100644 (file)
 //****************************\r
 // Constants\r
 //****************************\r
-#define COMPRESSOR_NAME "Full LZ4 speed analyzer"\r
+#define COMPRESSOR_NAME "LZ4 speed analyzer"\r
 #define COMPRESSOR_VERSION ""\r
 #define COMPILED __DATE__\r
 #define AUTHOR "Yann Collet"\r
-#define WELCOME_MESSAGE "*** %s %s, by %s (%s) ***\n", COMPRESSOR_NAME, COMPRESSOR_VERSION, AUTHOR, COMPILED\r
+#define WELCOME_MESSAGE "*** %s %s %i-bits, by %s (%s) ***\n", COMPRESSOR_NAME, COMPRESSOR_VERSION, (int)(sizeof(void*)*8), AUTHOR, COMPILED\r
 \r
 #define NBLOOPS    6\r
 #define TIMELOOP   2500\r
diff --git a/lz4.c b/lz4.c
index 73783ba..9852bbf 100644 (file)
--- a/lz4.c
+++ b/lz4.c
   typedef unsigned long long  U64;\r
 #endif\r
 \r
-typedef const BYTE* Ptr;\r
-\r
 #if defined(__GNUC__)  && !defined(LZ4_FORCE_UNALIGNED_ACCESS)\r
 #  define _PACKED __attribute__ ((packed))\r
 #else\r
@@ -186,7 +184,7 @@ typedef const BYTE* Ptr;
 #endif\r
 \r
 #if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__)\r
-#  ifdef __IBMC__\r
+#  if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)\r
 #    pragma pack(1)\r
 #  else\r
 #    pragma pack(push, 1)\r
@@ -199,7 +197,11 @@ typedef struct { U64 v; }  _PACKED U64_S;
 typedef struct {size_t v;} _PACKED size_t_S;\r
 \r
 #if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__)\r
-#  pragma pack(pop)\r
+#  if defined(__SUNPRO_C) || defined(__SUNPRO_CC)\r
+#    pragma pack(0)\r
+#  else\r
+#    pragma pack(pop)\r
+#  endif\r
 #endif\r
 \r
 #define A16(x)   (((U16_S *)(x))->v)\r
@@ -244,9 +246,9 @@ const int LZ4_minLength = (MFLIMIT+1);
 \r
 typedef struct {\r
     U32 hashTable[HASHNBCELLS4];\r
-    Ptr bufferStart;\r
-    Ptr base;\r
-    Ptr nextBlock;\r
+    const BYTE* bufferStart;\r
+    const BYTE* base;\r
+    const BYTE* nextBlock;\r
 } LZ4_Data_Structure;\r
 \r
 typedef enum { notLimited = 0, limited = 1 } limitedOutput_directive;\r
@@ -268,9 +270,9 @@ typedef enum { full = 0, partial = 1 } earlyEnd_directive;
 \r
 #if LZ4_ARCH64   // 64-bit\r
 #  define HTYPE                   U32\r
-#  define INITBASE(base)          Ptr const base = ip\r
+#  define INITBASE(base)          const BYTE* const base = ip\r
 #else            // 32-bit\r
-#  define HTYPE                   Ptr\r
+#  define HTYPE                   const BYTE*\r
 #  define INITBASE(base)          const int base = 0\r
 #endif\r
 \r
@@ -369,32 +371,32 @@ FORCE_INLINE int LZ4_hashSequence(U32 sequence, tableType_t tableType)
         return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));\r
 }\r
 \r
-FORCE_INLINE int LZ4_hashPosition(Ptr p, tableType_t tableType) { return LZ4_hashSequence(A32(p), tableType); }\r
+FORCE_INLINE int LZ4_hashPosition(const BYTE* p, tableType_t tableType) { return LZ4_hashSequence(A32(p), tableType); }\r
 \r
-FORCE_INLINE void LZ4_putPositionOnHash(Ptr p, U32 h, void* tableBase, tableType_t tableType, Ptr srcBase)\r
+FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase)\r
 {\r
     switch (tableType)\r
     {\r
-    case byPtr: { Ptr* hashTable = (Ptr*) tableBase; hashTable[h] = p; break; }\r
-    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = p-srcBase; break; }\r
+    case byPtr: { const BYTE** hashTable = (const BYTE**) tableBase; hashTable[h] = p; break; }\r
+    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); break; }\r
     case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); break; }\r
     }\r
 }\r
 \r
-FORCE_INLINE void LZ4_putPosition(Ptr p, void* tableBase, tableType_t tableType, Ptr srcBase)\r
+FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)\r
 {\r
     U32 h = LZ4_hashPosition(p, tableType);\r
     LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);\r
 }\r
 \r
-FORCE_INLINE Ptr LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, Ptr srcBase)\r
+FORCE_INLINE const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase)\r
 {\r
-    if (tableType == byPtr) { Ptr* hashTable = (Ptr*) tableBase; return hashTable[h]; }\r
+    if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; }\r
     if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; }\r
     { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; }   // default, to ensure a return\r
 }\r
 \r
-FORCE_INLINE Ptr LZ4_getPosition(Ptr p, void* tableBase, tableType_t tableType, Ptr srcBase)\r
+FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)\r
 {\r
     U32 h = LZ4_hashPosition(p, tableType);\r
     return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);\r
@@ -412,13 +414,13 @@ FORCE_INLINE int LZ4_compress_generic(
                  tableType_t tableType,\r
                  prefix64k_directive prefix)\r
 {\r
-    Ptr ip = (Ptr) source;\r
-    Ptr const base = (prefix==withPrefix) ? ((LZ4_Data_Structure*)ctx)->base : (Ptr) source;\r
-    Ptr const lowLimit = ((prefix==withPrefix) ? ((LZ4_Data_Structure*)ctx)->bufferStart : (Ptr)source);\r
-    Ptr anchor = (Ptr) source;\r
-    Ptr const iend = ip + inputSize;\r
-    Ptr const mflimit = iend - MFLIMIT;\r
-    Ptr const matchlimit = iend - LASTLITERALS;\r
+    const BYTE* ip = (const BYTE*) source;\r
+    const BYTE* const base = (prefix==withPrefix) ? ((LZ4_Data_Structure*)ctx)->base : (const BYTE*) source;\r
+    const BYTE* const lowLimit = ((prefix==withPrefix) ? ((LZ4_Data_Structure*)ctx)->bufferStart : (const BYTE*)source);\r
+    const BYTE* anchor = (const BYTE*) source;\r
+    const BYTE* const iend = ip + inputSize;\r
+    const BYTE* const mflimit = iend - MFLIMIT;\r
+    const BYTE* const matchlimit = iend - LASTLITERALS;\r
 \r
     BYTE* op = (BYTE*) dest;\r
     BYTE* const oend = op + maxOutputSize;\r
@@ -441,8 +443,8 @@ FORCE_INLINE int LZ4_compress_generic(
     for ( ; ; )\r
     {\r
         int findMatchAttempts = (1U << skipStrength) + 3;\r
-        Ptr forwardIp = ip;\r
-        Ptr ref;\r
+        const BYTE* forwardIp = ip;\r
+        const BYTE* ref;\r
         BYTE* token;\r
 \r
         // Find a match\r
@@ -599,7 +601,7 @@ int LZ4_compress_limitedOutput_continue (void* LZ4_Data, const char* source, cha
 // Stream functions\r
 //****************************\r
 \r
-FORCE_INLINE void LZ4_init(LZ4_Data_Structure* lz4ds, Ptr base)\r
+FORCE_INLINE void LZ4_init(LZ4_Data_Structure* lz4ds, const BYTE* base)\r
 {\r
     MEM_INIT(lz4ds->hashTable, 0, sizeof(lz4ds->hashTable));\r
     lz4ds->bufferStart = base;\r
@@ -611,7 +613,7 @@ FORCE_INLINE void LZ4_init(LZ4_Data_Structure* lz4ds, Ptr base)
 void* LZ4_create (const char* inputBuffer)\r
 {\r
     void* lz4ds = ALLOCATOR(1, sizeof(LZ4_Data_Structure));\r
-    LZ4_init ((LZ4_Data_Structure*)lz4ds, (Ptr)inputBuffer);\r
+    LZ4_init ((LZ4_Data_Structure*)lz4ds, (const BYTE*)inputBuffer);\r
     return lz4ds;\r
 }\r
 \r
@@ -636,7 +638,7 @@ char* LZ4_slideInputBuffer (void* LZ4_Data)
         for (nH=0; nH < HASHNBCELLS4; nH++)\r
         {\r
             if (lz4ds->hashTable[nH] < (U32)newBaseDelta) lz4ds->hashTable[nH] = 0;\r
-            else lz4ds->hashTable[nH] -= newBaseDelta;\r
+            else lz4ds->hashTable[nH] -= (U32)newBaseDelta;\r
         }\r
         lz4ds->base += newBaseDelta;\r
     }\r
@@ -660,7 +662,7 @@ FORCE_INLINE int LZ4_decompress_generic(
                  const char* source,\r
                  char* dest,\r
                  int inputSize,          //\r
-                 int outputSize,         // OutputSize must be != 0; if endOnInput==endOnInputSize, this value is the max size of Output Buffer.\r
+                 int outputSize,         // If endOnInput==endOnInputSize, this value is the max size of Output Buffer.\r
 \r
                  int endOnInput,         // endOnOutputSize, endOnInputSize\r
                  int prefix64k,          // noPrefix, withPrefix\r
@@ -669,19 +671,17 @@ FORCE_INLINE int LZ4_decompress_generic(
                  )\r
 {\r
     // Local Variables\r
-    Ptr restrict ip = (Ptr) source;\r
-    Ptr ref;\r
-    Ptr const iend = ip + inputSize;\r
+    const BYTE* restrict ip = (const BYTE*) source;\r
+    const BYTE* ref;\r
+    const BYTE* const iend = ip + inputSize;\r
 \r
     BYTE* op = (BYTE*) dest;\r
     BYTE* const oend = op + outputSize;\r
     BYTE* cpy;\r
     BYTE* oexit = op + targetOutputSize;\r
 \r
-    size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0};\r
-#if LZ4_ARCH64\r
-    size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};\r
-#endif\r
+    const size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0};   // static reduces speed for LZ4_decompress_safe() on GCC64\r
+    static const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};\r
 \r
 \r
     // Special cases\r
@@ -749,11 +749,7 @@ FORCE_INLINE int LZ4_decompress_generic(
         // copy repeated sequence\r
         if unlikely((op-ref)<(int)STEPSIZE)\r
         {\r
-#if LZ4_ARCH64\r
-            size_t dec64 = dec64table[op-ref];\r
-#else\r
-            const size_t dec64 = 0;\r
-#endif\r
+            const size_t dec64 = dec64table[(sizeof(void*)==4) ? 0 : op-ref];\r
             op[0] = ref[0];\r
             op[1] = ref[1];\r
             op[2] = ref[2];\r
@@ -803,6 +799,11 @@ int LZ4_decompress_safe_partial(const char* source, char* dest, int inputSize, i
     return LZ4_decompress_generic(source, dest, inputSize, maxOutputSize, endOnInputSize, noPrefix, partial, targetOutputSize);\r
 }\r
 \r
+int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int outputSize)\r
+{\r
+    return LZ4_decompress_generic(source, dest, 0, outputSize, endOnOutputSize, withPrefix, full, 0);\r
+}\r
+\r
 int LZ4_decompress_fast(const char* source, char* dest, int outputSize)\r
 {\r
 #ifdef _MSC_VER   // This version is faster with Visual\r
@@ -812,8 +813,3 @@ int LZ4_decompress_fast(const char* source, char* dest, int outputSize)
 #endif\r
 }\r
 \r
-int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int outputSize)\r
-{\r
-    return LZ4_decompress_generic(source, dest, 0, outputSize, endOnOutputSize, withPrefix, full, 0);\r
-}\r
-\r
diff --git a/lz4.h b/lz4.h
index 8f87908..a897bc3 100644 (file)
--- a/lz4.h
+++ b/lz4.h
@@ -83,7 +83,7 @@ LZ4_compressBound() :
     Provides the maximum size that LZ4 may output in a "worst case" scenario (input data not compressible)\r
     primarily useful for memory allocation of output buffer.\r
     inline function is recommended for the general case,\r
-    macro is also provided when result needs to be evaluated at compilation (such as table size allocation).\r
+    macro is also provided when result needs to be evaluated at compilation (such as stack memory allocation).\r
 \r
     isize  : is the input size. Max supported value is ~1.9GB\r
     return : maximum output size in a "worst case" scenario\r
@@ -130,23 +130,11 @@ LZ4_decompress_safe_partial() :
     return : the number of bytes decoded in the destination buffer (necessarily <= maxOutputSize)\r
        Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller.\r
              Always control how many bytes were decoded.\r
-             If the source stream is malformed, the function will stop decoding and return a negative result.\r
+             If the source stream is detected malformed, the function will stop decoding and return a negative result.\r
              This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets\r
 */\r
 \r
 \r
-int LZ4_decompress_safe_withPrefix64k (const char* source, char* dest, int inputSize, int maxOutputSize);\r
-int LZ4_decompress_fast_withPrefix64k (const char* source, char* dest, int outputSize);\r
-\r
-/*\r
-*_withPrefix64k() :\r
-    These decoding functions work the same as their "normal name" versions,\r
-    but will potentially use up to 64KB of data in front of 'char* dest'.\r
-    These functions are used for decoding inter-dependant blocks.\r
-*/\r
-\r
-\r
-\r
 //****************************\r
 // Stream Functions\r
 //****************************\r
@@ -187,6 +175,17 @@ When compression is completed, a call to LZ4_free() will release the memory used
 */\r
 \r
 \r
+int LZ4_decompress_safe_withPrefix64k (const char* source, char* dest, int inputSize, int maxOutputSize);\r
+int LZ4_decompress_fast_withPrefix64k (const char* source, char* dest, int outputSize);\r
+\r
+/*\r
+*_withPrefix64k() :\r
+    These decoding functions work the same as their "normal name" versions,\r
+    but can use up to 64KB of data in front of 'char* dest'.\r
+    These functions are necessary to decode inter-dependant blocks.\r
+*/\r
+\r
+\r
 //****************************\r
 // Obsolete Functions\r
 //****************************\r
diff --git a/lz4c.c b/lz4cli.c
similarity index 72%
rename from lz4c.c
rename to lz4cli.c
index 65a7ea2..faa1764 100644 (file)
--- a/lz4c.c
+++ b/lz4cli.c
@@ -1,5 +1,5 @@
 /*\r
-  LZ4c - LZ4 Compression CLI program \r
+  LZ4cli.c - LZ4 Command Line Interface\r
   Copyright (C) Yann Collet 2011-2013\r
   GPL v2 License\r
 \r
 */\r
 /*\r
   Note : this is stand-alone program.\r
-  It is not part of LZ4 compression library, it is a user program of LZ4 library.\r
+  It is not part of LZ4 compression library, it is a user program of the LZ4 library.\r
   The license of LZ4 library is BSD.\r
   The license of xxHash library is BSD.\r
   The license of this compression CLI program is GPLv2.\r
 */\r
 \r
 //**************************************\r
+// Tuning parameters\r
+//**************************************\r
+// DISABLE_LZ4C_LEGACY_OPTIONS :\r
+// Control the availability of -c0, -c1 and -hc legacy arguments\r
+// Default : Legacy options are enabled\r
+// #define DISABLE_LZ4C_LEGACY_OPTIONS\r
+\r
+\r
+//**************************************\r
 // Compiler Options\r
 //**************************************\r
 // Disable some Visual warning messages\r
 //****************************\r
 // Includes\r
 //****************************\r
-#include <stdio.h>    // fprintf, fopen, fread, _fileno(?)\r
+#include <stdio.h>    // fprintf, fopen, fread, _fileno, stdin, stdout\r
 #include <stdlib.h>   // malloc\r
 #include <string.h>   // strcmp\r
 #include <time.h>     // clock\r
-#ifdef _WIN32\r
-#include <io.h>       // _setmode\r
-#include <fcntl.h>    // _O_BINARY\r
-#endif\r
 #include "lz4.h"\r
 #include "lz4hc.h"\r
+#include "lz4stream.h"\r
 #include "bench.h"\r
 #include "xxhash.h"\r
 \r
 \r
+//****************************\r
+// OS-specific Includes\r
+//****************************\r
+#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)\r
+#  include <fcntl.h>    // _O_BINARY\r
+#  include <io.h>       // _setmode, _isatty\r
+#  define SET_BINARY_MODE(file) _setmode(_fileno(file), _O_BINARY)\r
+#  define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream))\r
+#else\r
+#  define SET_BINARY_MODE(file)\r
+#  define IS_CONSOLE(stdStream) isatty(fileno(stdStream))\r
+#endif\r
+\r
+\r
 //**************************************\r
 // Compiler-specific functions\r
 //**************************************\r
 // Constants\r
 //****************************\r
 #define COMPRESSOR_NAME "LZ4 Compression CLI"\r
-#define COMPRESSOR_VERSION ""\r
+#define COMPRESSOR_VERSION "1.0.3"\r
 #define COMPILED __DATE__\r
 #define AUTHOR "Yann Collet"\r
 #define EXTENSION ".lz4"\r
-#define WELCOME_MESSAGE "*** %s %s, by %s (%s) ***\n", COMPRESSOR_NAME, COMPRESSOR_VERSION, AUTHOR, COMPILED\r
-\r
-#define UNLZ4  "unlz4"\r
-#define LZ4CAT "lz4cat"\r
+#define WELCOME_MESSAGE "*** %s %s %i-bits, by %s (%s) ***\n", COMPRESSOR_NAME, COMPRESSOR_VERSION, (int)(sizeof(void*)*8), AUTHOR, COMPILED\r
 \r
 #define KB *(1U<<10)\r
 #define MB *(1U<<20)\r
@@ -130,7 +147,8 @@ static const int one = 1;
 //**************************************\r
 // Macros\r
 //**************************************\r
-#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)\r
+#define DISPLAY(...)         fprintf(stderr, __VA_ARGS__)\r
+#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }\r
 \r
 \r
 //**************************************\r
@@ -150,8 +168,7 @@ char nulmark[] = "/dev/null";
 // Local Parameters\r
 //**************************************\r
 static char* programName;\r
-static int silence = 0;\r
-static int verbose = 0;\r
+static int displayLevel = 2;   // 0 : no display  // 1: errors  // 2 : + result + interaction + warnings ;  // 3 : + progression;  // 4 : + information\r
 static int overwrite = 0;\r
 static int blockSizeId = LZ4S_BLOCKSIZEID_DEFAULT;\r
 static int blockChecksum = 0;\r
@@ -167,9 +184,9 @@ static int blockIndependence = 1;
 #define EXM_THROW(error, ...)                                             \\r
 {                                                                         \\r
     DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \\r
-    DISPLAY("Error %i : ", error);                                        \\r
-    DISPLAY(__VA_ARGS__);                                                 \\r
-    DISPLAY("\n");                                                        \\r
+    DISPLAYLEVEL(1, "Error %i : ", error);                                        \\r
+    DISPLAYLEVEL(1, __VA_ARGS__);                                                 \\r
+    DISPLAYLEVEL(1, "\n");                                                        \\r
     exit(error);                                                          \\r
 }\r
 \r
@@ -183,52 +200,101 @@ int usage()
     DISPLAY( "Usage :\n");\r
     DISPLAY( "      %s [arg] [input] [output]\n", programName);\r
     DISPLAY( "\n");\r
-    DISPLAY( "input   : a filename, or \n");\r
-    DISPLAY( "          '%s' or '-' for pipe mode (default if empty)\n", stdinmark);\r
+    DISPLAY( "input   : a filename\n");\r
+    DISPLAY( "          with no FILE, or when FILE is - or %s, read standard input\n", stdinmark);\r
     DISPLAY( "Arguments :\n");\r
-    DISPLAY( " -c0/-c : Fast compression (default) \n");\r
-    DISPLAY( " -c1/-hc: High compression \n");\r
+    DISPLAY( " -1     : Fast compression (default) \n");\r
+    DISPLAY( " -9     : High compression \n");\r
     DISPLAY( " -d     : decompression \n");\r
-    DISPLAY( " -y     : overwrite without prompting \n");\r
-    DISPLAY( " -h/-H  : Help (this text + advanced options)\n");\r
+    DISPLAY( " -f     : overwrite output without prompting \n");\r
+    DISPLAY( " -h/-H  : display help/long help and exit\n");\r
     return 0;\r
 }\r
 \r
 int usage_advanced()\r
 {\r
+    DISPLAY(WELCOME_MESSAGE);\r
     usage();\r
     DISPLAY( "\n");\r
-    DISPLAY( "Advanced options :\n");\r
-    DISPLAY( " -v     : be verbose \n");\r
-    DISPLAY( " -t     : test compressed file \n");\r
+    DISPLAY( "Advanced arguments :\n");\r
+    DISPLAY( " -V     : display Version number and exit\n");\r
+    DISPLAY( " -v     : verbose mode\n");\r
+    DISPLAY( " -q     : suppress warnings; specify twice to suppress errors too\n");\r
+    DISPLAY( " -c     : force write to standard output, even if it is the console\n");\r
+    DISPLAY( " -t     : test compressed file integrity\n");\r
+    DISPLAY( " -z     : force compression\n");\r
     DISPLAY( " -B#    : Block size [4-7](default : 7)\n");\r
     DISPLAY( " -BD    : Block dependency (improve compression ratio)\n");\r
     DISPLAY( " -BX    : enable block checksum (default:disabled)\n");\r
     DISPLAY( " -Sx    : disable stream checksum (default:enabled)\n");\r
-    DISPLAY( " -b#    : benchmark files, using # [0-1] compression level\n");\r
+    DISPLAY( "Benchmark arguments :\n");\r
+    DISPLAY( " -b     : benchmark file(s)\n");\r
     DISPLAY( " -i#    : iteration loops [1-9](default : 3), benchmark mode only\n");\r
+#if !defined(DISABLE_LZ4C_LEGACY_OPTIONS)\r
+    DISPLAY( "Legacy arguments :\n");\r
+    DISPLAY( " -c0    : fast compression\n");\r
+    DISPLAY( " -c1    : high compression\n");\r
+    DISPLAY( " -hc    : high compression\n");\r
+    DISPLAY( " -y     : overwrite output without prompting \n");\r
+    DISPLAY( " -s     : suppress warnings \n");\r
+#endif // DISABLE_LZ4C_LEGACY_OPTIONS\r
+    return 0;\r
+}\r
+\r
+int usage_longhelp()\r
+{\r
+    DISPLAY( "\n");\r
+    DISPLAY( "Which values can get [output] ? \n");\r
+    DISPLAY( "[output] : a filename\n");\r
+    DISPLAY( "          '%s', or '-' for standard output (pipe mode)\n", stdoutmark);\r
+    DISPLAY( "          '%s' to discard output (test mode)\n", NULL_OUTPUT);\r
+    DISPLAY( "[output] can be left empty. In this case, it receives the following value : \n");\r
+    DISPLAY( "          - if stdout is not the console, then [output] = stdout \n");\r
+    DISPLAY( "          - if stdout is console : \n");\r
+    DISPLAY( "               + if compression selected, output to filename%s \n", EXTENSION);\r
+    DISPLAY( "               + if decompression selected, output to filename without '%s'\n", EXTENSION);\r
+    DISPLAY( "                    > if input filename has no '%s' extension : error\n", EXTENSION);\r
     DISPLAY( "\n");\r
-    DISPLAY( "output  : a filename, or \n");\r
-    DISPLAY( "          '%s', or '-' for pipe mode\n", stdoutmark);\r
-    DISPLAY( "          or '%s'\n", NULL_OUTPUT);\r
-    DISPLAY( "          default if empty : stdout if input is stdin\n");\r
-    DISPLAY( "                             input.lz4 if compression selected\n");\r
-    DISPLAY( "                             input without '.lz4' if decompression\n");\r
+    DISPLAY( "Compression levels : \n");\r
+    DISPLAY( "There are technically 2 accessible compression levels.\n");\r
+    DISPLAY( "-0 ... -2 => Fast compression\n");\r
+    DISPLAY( "-3 ... -9 => High compression\n");\r
     DISPLAY( "\n");\r
-    DISPLAY( "Examples :\n");\r
-    DISPLAY( "1 : compress file 'filename', using default output name 'filename.lz4'\n");\r
+    DISPLAY( "stdin, stdout and the console : \n");\r
+    DISPLAY( "To protect the console from binary flooding (bad argument mistake)\n");\r
+    DISPLAY( "%s will refuse to read from console, or write to console \n", programName);\r
+    DISPLAY( "except if '-c' command is specified, to force output to console \n");\r
+    DISPLAY( "\n");\r
+    DISPLAY( "Simple example :\n");\r
+    DISPLAY( "1 : compress 'filename' fast, using default output name 'filename.lz4'\n");\r
     DISPLAY( "          %s filename\n", programName);\r
+    DISPLAY( "\n");\r
+    DISPLAY( "Arguments can be appended together, or provided independently. For example :\n");\r
     DISPLAY( "2 : compress 'filename' in high compression mode, overwrite output if exists\n");\r
-    DISPLAY( "          %s -hcy filename \n", programName);\r
+    DISPLAY( "          %s -f9 filename \n", programName);\r
+    DISPLAY( "    is equivalent to :\n");\r
+    DISPLAY( "          %s -f -9 filename \n", programName);\r
+    DISPLAY( "\n");\r
+    DISPLAY( "%s can be used in 'pure pipe mode', for example :\n", programName);\r
     DISPLAY( "3 : compress data stream from 'generator', send result to 'consumer'\n");\r
     DISPLAY( "          generator | %s | consumer \n", programName);\r
+#if !defined(DISABLE_LZ4C_LEGACY_OPTIONS)\r
+    DISPLAY( "\n");\r
+    DISPLAY( "Warning :\n");\r
+    DISPLAY( "Legacy arguments take precedence. Therefore : \n");\r
+    DISPLAY( "          %s -hc filename\n", programName);\r
+    DISPLAY( "means 'compress filename in high compression mode'\n");\r
+    DISPLAY( "It is not equivalent to :\n");\r
+    DISPLAY( "          %s -h -c filename\n", programName);\r
+    DISPLAY( "which would display help text and exit\n");\r
+#endif // DISABLE_LZ4C_LEGACY_OPTIONS\r
     return 0;\r
 }\r
 \r
 int badusage()\r
 {\r
-    DISPLAY("Wrong parameters\n");\r
-    usage();\r
+    DISPLAYLEVEL(1, "Incorrect parameters\n");\r
+    if (displayLevel >= 1) usage();\r
     exit(1);\r
 }\r
 \r
@@ -243,11 +309,9 @@ int get_fileHandle(char* input_filename, char* output_filename, FILE** pfinput,
 \r
     if (!strcmp (input_filename, stdinmark)) \r
     {\r
-        if (verbose) DISPLAY( "Using stdin for input\n");\r
+        DISPLAYLEVEL(4,"Using stdin for input\n");\r
         *pfinput = stdin;\r
-#ifdef _WIN32 // Need to set stdin/stdout to binary mode specifically for windows\r
-        _setmode( _fileno( stdin ), _O_BINARY );\r
-#endif\r
+        SET_BINARY_MODE(stdin);\r
     } \r
     else \r
     {\r
@@ -256,11 +320,9 @@ int get_fileHandle(char* input_filename, char* output_filename, FILE** pfinput,
 \r
     if (!strcmp (output_filename, stdoutmark)) \r
     {\r
-        if (verbose) DISPLAY( "Using stdout for output\n");\r
+        DISPLAYLEVEL(4,"Using stdout for output\n");\r
         *pfoutput = stdout;\r
-#ifdef _WIN32 // Need to set stdin/stdout to binary mode specifically for windows\r
-        _setmode( _fileno( stdout ), _O_BINARY );\r
-#endif\r
+        SET_BINARY_MODE(stdout);\r
     } \r
     else \r
     {\r
@@ -273,8 +335,9 @@ int get_fileHandle(char* input_filename, char* output_filename, FILE** pfinput,
             if (!overwrite)\r
             {\r
                 char ch;\r
-                DISPLAY( "Warning : %s already exists\n", output_filename); \r
-                DISPLAY( "Overwrite ? (Y/N) : ");\r
+                DISPLAYLEVEL(2, "Warning : %s already exists\n", output_filename); \r
+                DISPLAYLEVEL(2, "Overwrite ? (Y/N) : ");\r
+                if (displayLevel <= 1) EXM_THROW(11, "Operation aborted : %s already exists", output_filename);   // No interaction possible\r
                 ch = (char)getchar();\r
                 if ((ch!='Y') && (ch!='y')) EXM_THROW(11, "Operation aborted : %s already exists", output_filename);\r
             }\r
@@ -313,6 +376,7 @@ int legacy_compress_file(char* input_filename, char* output_filename, int compre
     }\r
     start = clock();\r
     get_fileHandle(input_filename, output_filename, &finput, &foutput);\r
+    if ((displayLevel==2) && (compressionlevel==1)) displayLevel=3;\r
 \r
     // Allocate Memory\r
     in_buff = (char*)malloc(LEGACY_BLOCKSIZE);\r
@@ -332,12 +396,12 @@ int legacy_compress_file(char* input_filename, char* output_filename, int compre
         int inSize = (int) fread(in_buff, (size_t)1, (size_t)LEGACY_BLOCKSIZE, finput);\r
         if( inSize<=0 ) break;\r
         filesize += inSize;\r
-        if (displayLevel) DISPLAY("Read : %i MB  \r", (int)(filesize>>20));\r
+        DISPLAYLEVEL(3, "Read : %i MB  \r", (int)(filesize>>20));\r
 \r
         // Compress Block\r
         outSize = compressionFunction(in_buff, out_buff+4, inSize);\r
         compressedfilesize += outSize+4;\r
-        if (displayLevel) DISPLAY("Read : %i MB  ==> %.2f%%\r", (int)(filesize>>20), (double)compressedfilesize/filesize*100);\r
+        DISPLAYLEVEL(3, "Read : %i MB  ==> %.2f%%\r", (int)(filesize>>20), (double)compressedfilesize/filesize*100);\r
 \r
         // Write Block\r
         * (unsigned int*) out_buff = LITTLE_ENDIAN_32(outSize);\r
@@ -347,11 +411,11 @@ int legacy_compress_file(char* input_filename, char* output_filename, int compre
 \r
     // Status\r
     end = clock();\r
-    if (!silence) DISPLAY( "Compressed %llu bytes into %llu bytes ==> %.2f%%\n",\r
+    DISPLAYLEVEL(2,"Compressed %llu bytes into %llu bytes ==> %.2f%%\n",\r
         (unsigned long long) filesize, (unsigned long long) compressedfilesize, (double)compressedfilesize/filesize*100);\r
     {\r
         double seconds = (double)(end - start)/CLOCKS_PER_SEC;\r
-        if (verbose) DISPLAY( "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);\r
+        DISPLAYLEVEL(4,"Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);\r
     }\r
 \r
     // Close & Free\r
@@ -378,7 +442,6 @@ int compress_file_blockDependency(char* input_filename, char* output_filename, i
     char* out_buff;\r
     FILE* finput;\r
     FILE* foutput;\r
-    int displayLevel = ((compressionlevel>0) && (!silence)) || (verbose);\r
     clock_t start, end;\r
     unsigned int blockSize, inputBufferSize;\r
     size_t sizeCheck, header_size;\r
@@ -387,6 +450,7 @@ int compress_file_blockDependency(char* input_filename, char* output_filename, i
 \r
     // Init\r
     start = clock();\r
+    if ((displayLevel==2) && (compressionlevel==1)) displayLevel=3;\r
     switch (compressionlevel)\r
     {\r
     case 0 :\r
@@ -440,14 +504,14 @@ int compress_file_blockDependency(char* input_filename, char* output_filename, i
         inSize = (unsigned int) fread(in_start, (size_t)1, (size_t)blockSize, finput);\r
         if( inSize==0 ) break;   // No more input : end of compression\r
         filesize += inSize;\r
-        if (displayLevel) DISPLAY("Read : %i MB  \r", (int)(filesize>>20));\r
+        DISPLAYLEVEL(3, "Read : %i MB  \r", (int)(filesize>>20));\r
         if (streamChecksum) XXH32_update(streamChecksumState, in_start, inSize);\r
 \r
         // Compress Block\r
         outSize = compressionFunction(ctx, in_start, out_buff+4, inSize, inSize-1);\r
         if (outSize > 0) compressedfilesize += outSize+4; else compressedfilesize += inSize+4;\r
         if (blockChecksum) compressedfilesize+=4;\r
-        if (displayLevel) DISPLAY("Read : %i MB  ==> %.2f%%\r", (int)(filesize>>20), (double)compressedfilesize/filesize*100);\r
+        DISPLAYLEVEL(3, "Read : %i MB  ==> %.2f%%\r", (int)(filesize>>20), (double)compressedfilesize/filesize*100);\r
 \r
         // Write Block\r
         if (outSize > 0)\r
@@ -498,11 +562,11 @@ int compress_file_blockDependency(char* input_filename, char* output_filename, i
 \r
     // Status\r
     end = clock();\r
-    if (!silence) DISPLAY( "Compressed %llu bytes into %llu bytes ==> %.2f%%\n",\r
+    DISPLAYLEVEL(2, "Compressed %llu bytes into %llu bytes ==> %.2f%%\n",\r
         (unsigned long long) filesize, (unsigned long long) compressedfilesize, (double)compressedfilesize/filesize*100);\r
     {\r
         double seconds = (double)(end - start)/CLOCKS_PER_SEC;\r
-        if (verbose) DISPLAY( "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);\r
+        DISPLAYLEVEL(4, "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);\r
     }\r
 \r
     // Close & Free\r
@@ -527,7 +591,6 @@ int compress_file(char* input_filename, char* output_filename, int compressionle
     char* headerBuffer;\r
     FILE* finput;\r
     FILE* foutput;\r
-    int displayLevel = ((compressionlevel>0) && (!silence)) || (verbose);\r
     clock_t start, end;\r
     int blockSize;\r
     size_t sizeCheck, header_size, readSize;\r
@@ -538,6 +601,7 @@ int compress_file(char* input_filename, char* output_filename, int compressionle
 \r
     // Init\r
     start = clock();\r
+    if ((displayLevel==2) && (compressionlevel==1)) displayLevel=3;\r
     switch (compressionlevel)\r
     {\r
     case 0 : compressionFunction = LZ4_compress_limitedOutput; break;\r
@@ -580,14 +644,14 @@ int compress_file(char* input_filename, char* output_filename, int compressionle
         unsigned int outSize;\r
 \r
         filesize += readSize;\r
-        if (displayLevel) DISPLAY("Read : %i MB  \r", (int)(filesize>>20));\r
+        DISPLAYLEVEL(3, "Read : %i MB  \r", (int)(filesize>>20));\r
         if (streamChecksum) XXH32_update(streamChecksumState, in_buff, (int)readSize);\r
 \r
         // Compress Block\r
         outSize = compressionFunction(in_buff, out_buff+4, (int)readSize, (int)readSize-1);\r
         if (outSize > 0) compressedfilesize += outSize+4; else compressedfilesize += readSize+4;\r
         if (blockChecksum) compressedfilesize+=4;\r
-        if (displayLevel) DISPLAY("Read : %i MB  ==> %.2f%%\r", (int)(filesize>>20), (double)compressedfilesize/filesize*100);\r
+        DISPLAYLEVEL(3, "Read : %i MB  ==> %.2f%%\r", (int)(filesize>>20), (double)compressedfilesize/filesize*100);\r
 \r
         // Write Block\r
         if (outSize > 0)\r
@@ -646,11 +710,11 @@ int compress_file(char* input_filename, char* output_filename, int compressionle
 \r
     // Final Status\r
     end = clock();\r
-    if (!silence) DISPLAY( "Compressed %llu bytes into %llu bytes ==> %.2f%%\n",\r
+    DISPLAYLEVEL(2, "Compressed %llu bytes into %llu bytes ==> %.2f%%\n",\r
         (unsigned long long) filesize, (unsigned long long) compressedfilesize, (double)compressedfilesize/filesize*100);\r
     {\r
         double seconds = (double)(end - start)/CLOCKS_PER_SEC;\r
-        if (verbose) DISPLAY( "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);\r
+        DISPLAYLEVEL(4, "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);\r
     }\r
 \r
     return 0;\r
@@ -887,9 +951,10 @@ unsigned long long selectDecoder( FILE* finput,  FILE* foutput)
     case LZ4S_MAGICNUMBER:\r
         return decodeLZ4S(finput, foutput);\r
     case LEGACY_MAGICNUMBER:\r
-        if (verbose) DISPLAY("Detected : Legacy format \n");\r
+        DISPLAYLEVEL(4, "Detected : Legacy format \n");\r
         return decodeLegacyStream(finput, foutput);\r
     case LZ4S_SKIPPABLE0:\r
+        DISPLAYLEVEL(4, "Skipping detected skippable area \n");\r
         nbReadBytes = fread(&size, 1, 4, finput);\r
         if (nbReadBytes != 4) EXM_THROW(42, "Stream error : skippable size unreadable");\r
         size = LITTLE_ENDIAN_32(size);     // Convert to Little Endian format\r
@@ -898,7 +963,7 @@ unsigned long long selectDecoder( FILE* finput,  FILE* foutput)
         return selectDecoder(finput, foutput);\r
     default:\r
         if (ftell(finput) == MAGICNUMBER_SIZE) EXM_THROW(44,"Unrecognized header : file cannot be decoded");   // Wrong magic number at the beginning of 1st stream\r
-        DISPLAY("Stream followed by unrecognized data\n");\r
+        DISPLAYLEVEL(2, "Stream followed by unrecognized data\n");\r
         return 0;\r
     }\r
 }\r
@@ -925,10 +990,10 @@ int decodeFile(char* input_filename, char* output_filename)
 \r
     // Final Status\r
     end = clock();\r
-    if (!silence) DISPLAY( "Successfully decoded %llu bytes \n", filesize);\r
+    DISPLAYLEVEL(2, "Successfully decoded %llu bytes \n", filesize);\r
     {\r
         double seconds = (double)(end - start)/CLOCKS_PER_SEC;\r
-        if (verbose) DISPLAY( "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);\r
+        DISPLAYLEVEL(4, "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);\r
     }\r
 \r
     // Close\r
@@ -947,16 +1012,15 @@ int main(int argc, char** argv)
         decode=0,\r
         bench=0,\r
         filenamesStart=2,\r
-        legacy_format=0;\r
+        legacy_format=0,\r
+        forceStdout=0;\r
     char* input_filename=0;\r
     char* output_filename=0;\r
     char nullOutput[] = NULL_OUTPUT;\r
     char extension[] = EXTENSION;\r
 \r
-    // Select behavior\r
+    // Init\r
     programName = argv[0];\r
-    if (strstr(programName, UNLZ4)) { decode=1; silence=1; }\r
-    else if (strstr(programName, LZ4CAT)) { decode=1; silence=1; output_filename=stdoutmark; }\r
 \r
     for(i=1; i<argc; i++)\r
     {\r
@@ -967,6 +1031,7 @@ int main(int argc, char** argv)
         // Decode command (note : aggregated commands are allowed)\r
         if (argument[0]=='-')\r
         {\r
+            // '-' means stdin/stdout\r
             if (argument[1]==0)\r
             {\r
                 if (!input_filename) input_filename=stdinmark;\r
@@ -977,14 +1042,38 @@ int main(int argc, char** argv)
             {\r
                 argument ++;\r
 \r
+#if !defined(DISABLE_LZ4C_LEGACY_OPTIONS)\r
+                // Legacy options (-c0, -c1, -hc, -y, -s, -b0, -b1)\r
+                if ((argument[0]=='c') && (argument[1]=='0')) { cLevel=0; argument++; continue; }          // -c0 (fast compression)\r
+                if ((argument[0]=='c') && (argument[1]=='1')) { cLevel=1; argument++; continue; }          // -c1 (high compression)\r
+                if ((argument[0]=='h') && (argument[1]=='c')) { cLevel=1; argument++; continue; }          // -hc (high compression)\r
+                if (*argument=='y') { overwrite=1; continue; }                                             // -y (answer 'yes' to overwrite permission)\r
+                if (*argument=='s') { displayLevel=1; continue; }                                          // -s (silent mode)\r
+                if ((argument[0]=='b') && (argument[1]=='0')) { bench=1; cLevel=0; argument++; continue; } // -b0 (fast bench)\r
+                if ((argument[0]=='b') && (argument[1]=='1')) { bench=1; cLevel=1; argument++; continue; } // -b1 (HC bench)\r
+#endif // DISABLE_LZ4C_LEGACY_OPTIONS\r
+\r
                 switch(argument[0])\r
                 {\r
-                    // Display help on usage\r
-                case 'H': usage_advanced(); return 0;\r
+                    // Display help\r
+                case 'V': DISPLAY(WELCOME_MESSAGE); return 0;   // Version\r
+                case 'h': usage_advanced(); return 0;\r
+                case 'H': usage_advanced(); usage_longhelp(); return 0;\r
 \r
                     // Compression (default)\r
-                case 'c': if ((argument[1] >='0') && (argument[1] <='1')) { cLevel=argument[1] - '0'; argument++; } break;\r
-                case 'h': if (argument[1]=='c') { cLevel=1; argument++; } else { usage_advanced(); return 0; } break;\r
+                case 'z': break;\r
+\r
+                    // Compression level\r
+                case '0': \r
+                case '1':\r
+                case '2': cLevel=0; break;\r
+                case '3':\r
+                case '4':\r
+                case '5':\r
+                case '6':\r
+                case '7':\r
+                case '8':\r
+                case '9': cLevel=1; break;\r
 \r
                     // Use Legacy format (hidden option)\r
                 case 'l': legacy_format=1; break;\r
@@ -992,40 +1081,56 @@ int main(int argc, char** argv)
                     // Decoding\r
                 case 'd': decode=1; break;\r
 \r
+                    // Force stdout, even if stdout==console\r
+                case 'c': forceStdout=1; output_filename=stdoutmark; displayLevel=1; break;\r
+\r
                     // Test\r
                 case 't': decode=1; output_filename=nulmark; break;\r
 \r
+                    // Overwrite\r
+                case 'f': overwrite=1; break;\r
+\r
+                    // Verbose mode\r
+                case 'v': displayLevel=4; break;\r
+\r
+                    // Quiet mode\r
+                case 'q': displayLevel--; break;\r
+\r
+                    // keep source file (default anyway, so useless) (for xz/lzma compatibility)\r
+                case 'k': break;\r
+\r
                     // Modify Block Properties\r
                 case 'B':\r
                     while (argument[1]!=0)\r
-                    switch(argument[1])\r
                     {\r
-                    case '4':\r
-                    case '5':\r
-                    case '6':\r
-                    case '7':\r
-                    { \r
-                        int B = argument[1] - '0'; \r
-                        int S = 1 << (8 + 2*B); \r
-                        BMK_SetBlocksize(S); \r
-                        blockSizeId = B;\r
-                        argument++;\r
-                        break;\r
-                    }\r
-                    case 'D': blockIndependence = 0, argument++; break;\r
-                    case 'X': blockChecksum = 1, argument ++; break;\r
-                    default : goto _exit_blockProperties;\r
+                        int exitBlockProperties=0;\r
+                        switch(argument[1])\r
+                        {\r
+                        case '4':\r
+                        case '5':\r
+                        case '6':\r
+                        case '7':\r
+                        { \r
+                            int B = argument[1] - '0'; \r
+                            int S = 1 << (8 + 2*B); \r
+                            BMK_SetBlocksize(S); \r
+                            blockSizeId = B;\r
+                            argument++;\r
+                            break;\r
+                        }\r
+                        case 'D': blockIndependence = 0, argument++; break;\r
+                        case 'X': blockChecksum = 1, argument ++; break;\r
+                        default : exitBlockProperties=1;\r
+                        }\r
+                        if (exitBlockProperties) break;\r
                     }\r
-_exit_blockProperties:\r
                     break;\r
 \r
                     // Modify Stream properties\r
                 case 'S': if (argument[1]=='x') { streamChecksum=0; argument++; break; } else { badusage(); }\r
 \r
-                    // Bench\r
-                case 'b': bench=1; \r
-                    if ((argument[1] >='0') && (argument[1] <='1')) { cLevel=argument[1] - '0'; argument++; } \r
-                    break;\r
+                    // Benchmark\r
+                case 'b': bench=1; break;\r
 \r
                     // Modify Nb Iterations (benchmark only)\r
                 case 'i': \r
@@ -1040,12 +1145,6 @@ _exit_blockProperties:
                     // Pause at the end (benchmark only) (hidden option)\r
                 case 'p': BMK_SetPause(); break;\r
 \r
-                    // Overwrite\r
-                case 'y': overwrite=1; break;\r
-\r
-                    // Verbose mode\r
-                case 'v': verbose=1; break;\r
-\r
                     // Unrecognised command\r
                 default : badusage();\r
                 }\r
@@ -1065,18 +1164,19 @@ _exit_blockProperties:
         }\r
     }\r
 \r
-    if (verbose) DISPLAY( WELCOME_MESSAGE);\r
+    DISPLAYLEVEL(4, WELCOME_MESSAGE);\r
+    DISPLAYLEVEL(4, "Blocks size : %i KB\n", (1 << ((blockSizeId*2)-2)));\r
 \r
     // No input filename ==> use stdin\r
     if(!input_filename) { input_filename=stdinmark; }\r
 \r
-    // Check if benchmark was required\r
+    // Check if benchmark is selected\r
     if (bench) return BMK_benchFile(argv+filenamesStart, argc-filenamesStart, cLevel);\r
 \r
     // No output filename ==> select one automatically (when possible)\r
     if (!output_filename) \r
     {\r
-        if (input_filename == stdinmark) { output_filename=stdoutmark; silence=1; }\r
+        if (!IS_CONSOLE(stdout)) { output_filename=stdoutmark; }\r
         else if (!decode)   // compression\r
         {\r
             int i=0, l=0;\r
@@ -1084,7 +1184,7 @@ _exit_blockProperties:
             output_filename = (char*)calloc(1,l+5);\r
             for (i=0;i<l;i++) output_filename[i] = input_filename[i];\r
             for (i=l;i<l+4;i++) output_filename[i] = extension[i-l];\r
-            if (!silence) DISPLAY("Compressed filename will be : %s \n", output_filename);\r
+            DISPLAYLEVEL(2, "Compressed filename will be : %s \n", output_filename);\r
         }\r
         else                // decompression (input file must respect format extension ".lz4")\r
         {\r
@@ -1094,29 +1194,25 @@ _exit_blockProperties:
             for (outl=0;outl<inl;outl++) output_filename[outl] = input_filename[outl];\r
             if (inl>4)\r
                 while ((outl >= inl-4) && (input_filename[outl] ==  extension[outl-inl+4])) output_filename[outl--]=0;\r
-            if (outl != inl-5) { DISPLAY("Cannot automatically decide an output filename\n"); badusage(); }\r
+            if (outl != inl-5) { DISPLAYLEVEL(1, "Cannot automatically decide an output filename\n"); badusage(); }\r
+            DISPLAYLEVEL(2, "Decoding file %s \n", output_filename);\r
         }\r
     }\r
 \r
-    if ((decode ? input_filename==stdinmark : output_filename==stdoutmark)\r
-        && !overwrite\r
-#ifdef _WIN32\r
-        && _isatty (_fileno ((decode ? stdin : stdout))))\r
-#else\r
-        &&  isatty ( fileno ((decode ? stdin : stdout))))\r
-#endif\r
-        badusage();\r
-\r
-    if ((input_filename == stdinmark) && (output_filename == stdoutmark)) silence=1;\r
+    // No warning message in pure pipe mode (stdin + stdout)\r
+    if (!strcmp(input_filename, stdinmark) && !strcmp(output_filename,stdoutmark) && (displayLevel>1)  && (displayLevel<4)) displayLevel=1;\r
 \r
-    if (verbose) silence=0;\r
+    // Check if input or output are defined as console; trigger an error in this case\r
+    if (!strcmp(input_filename, stdinmark)  && IS_CONSOLE(stdin)                 ) badusage();\r
+    if (!strcmp(output_filename,stdoutmark) && IS_CONSOLE(stdout) && !forceStdout) badusage();\r
 \r
+    // Decompress input if selected\r
     if (decode) return decodeFile(input_filename, output_filename);\r
 \r
     // compression is default action\r
     if (legacy_format)\r
     {\r
-        if (!silence) DISPLAY("! Generating compressed LZ4 using Legacy format (deprecated !) ! \n");\r
+        DISPLAYLEVEL(2, "! Generating compressed LZ4 using Legacy format (deprecated !) ! \n");\r
         return legacy_compress_file(input_filename, output_filename, cLevel);   \r
     }\r
     else\r