Support for Microsoft C / Visual Studio

This commit is contained in:
Eric Biggers 2016-01-30 15:13:29 -06:00
parent 051d55919b
commit fb1de37c0e
23 changed files with 478 additions and 306 deletions

View File

@ -53,19 +53,19 @@ ifneq ($(findstring -mingw,$(CC)),)
AR := $(patsubst %-gcc,%-ar,$(CC)) AR := $(patsubst %-gcc,%-ar,$(CC))
endif endif
WINDOWS := yes WINDOWS := yes
LIB_SUFFIX := .a LIB_SUFFIX := .lib
SHLIB_SUFFIX := .dll SHLIB_SUFFIX := .dll
PROG_SUFFIX := .exe PROG_SUFFIX := .exe
PROG_CFLAGS := -static PROG_SRC := tools/wgetopt.c
GZIP_CFLAGS := -municode PROG_CFLAGS := -static -municode
SHLIB_IS_PIC := no SHLIB_IS_PIC := no
else else
WINDOWS := no WINDOWS := no
LIB_SUFFIX := .a LIB_SUFFIX := .a
SHLIB_SUFFIX := .so SHLIB_SUFFIX := .so
PROG_SUFFIX := PROG_SUFFIX :=
PROG_SRC :=
PROG_CFLAGS := PROG_CFLAGS :=
GZIP_CFLAGS :=
SHLIB_IS_PIC := yes SHLIB_IS_PIC := yes
endif endif
@ -102,6 +102,9 @@ ifneq ($(RUNTIME_CPU_DETECTION),yes)
override CFLAGS += -DRUNTIME_CPU_DETECTION=0 override CFLAGS += -DRUNTIME_CPU_DETECTION=0
endif endif
PROG_CFLAGS += $(CFLAGS)
PROG_SRC += libdeflate$(LIB_SUFFIX)
SRC := src/aligned_malloc.c SRC := src/aligned_malloc.c
ifeq ($(SUPPORT_COMPRESSION),yes) ifeq ($(SUPPORT_COMPRESSION),yes)
SRC += src/deflate_compress.c SRC += src/deflate_compress.c
@ -151,15 +154,15 @@ libdeflate$(SHLIB_SUFFIX):$(SHLIB_OBJ)
libdeflate$(LIB_SUFFIX):$(OBJ) libdeflate$(LIB_SUFFIX):$(OBJ)
$(AR) cr $@ $+ $(AR) cr $@ $+
benchmark$(PROG_SUFFIX):tools/benchmark.c libdeflate$(LIB_SUFFIX) benchmark$(PROG_SUFFIX):tools/benchmark.c $(PROG_SRC)
$(CC) -o $@ $(CFLAGS) -L. $+ libdeflate$(LIB_SUFFIX) -lz $(CC) -o $@ $(PROG_CFLAGS) $+ -lz
gzip$(PROG_SUFFIX):tools/gzip.c libdeflate$(LIB_SUFFIX) gzip$(PROG_SUFFIX):tools/gzip.c $(PROG_SRC)
$(CC) -o $@ $(CFLAGS) $(GZIP_CFLAGS) $(PROG_CFLAGS) -L. $+ libdeflate$(LIB_SUFFIX) $(CC) -o $@ $(PROG_CFLAGS) $+
ifeq ($(WINDOWS),yes) ifeq ($(WINDOWS),yes)
gunzip$(PROG_SUFFIX):tools/gzip.c libdeflate$(LIB_SUFFIX) gunzip$(PROG_SUFFIX):tools/gzip.c $(PROG_SRC)
$(CC) -o $@ $(CFLAGS) $(GZIP_CFLAGS) $(PROG_CFLAGS) -L. $+ libdeflate$(LIB_SUFFIX) $(CC) -o $@ $(PROG_CFLAGS) $+
else else
gunzip$(PROG_SUFFIX):gzip$(PROG_SUFFIX) gunzip$(PROG_SUFFIX):gzip$(PROG_SUFFIX)
ln -f gzip$(PROG_SUFFIX) $@ ln -f gzip$(PROG_SUFFIX) $@
@ -187,10 +190,8 @@ endif
all:$(TARGETS) all:$(TARGETS)
clean: clean:
rm -f libdeflate.a libdeflate.so libdeflate.dll src/*.o \ rm -f libdeflate.a libdeflate.so libdeflate.dll src/*.o src/*.obj \
benchmark benchmark.exe \ benchmark gzip gunzip *.exe *.lib *.obj *.exp
gzip gzip.exe \
gunzip gunzip.exe
.PHONY: all clean .PHONY: all clean

48
Makefile.msc Normal file
View File

@ -0,0 +1,48 @@
#
# Makefile for the Microsoft toolchain. It builds a static library and a shared
# library (DLL) and its corresponding import library.
#
# Usage:
# nmake /f Makefile.msc
#
CC = cl
LD = link
AR = lib
CFLAGS = /MD /O2 -I.
STATICLIB = libdeflatestatic.lib
SHAREDLIB = libdeflate.dll
IMPLIB = libdeflate.lib
OBJS = src/adler32.obj \
src/aligned_malloc.obj \
src/crc32.obj \
src/deflate_compress.obj \
src/deflate_decompress.obj \
src/gzip_compress.obj \
src/gzip_decompress.obj \
src/x86_cpu_features.obj \
src/zlib_compress.obj \
src/zlib_decompress.obj
all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB)
$(STATICLIB): $(OBJS)
$(AR) $(ARFLAGS) -out:$@ $(OBJS)
$(IMPLIB): $(SHAREDLIB)
$(SHAREDLIB): $(OBJS)
$(LD) $(LDFLAGS) -out:$@ -dll -implib:$(IMPLIB) $(OBJS)
.c.obj:
$(CC) -c /Fo:$@ $(CFLAGS) $<
clean:
-del *.lib
-del *.dll
-del *.exe
-del *.exp
-del *.obj
-del src\*.obj

View File

@ -21,19 +21,18 @@ on it, and anyone is free to use it for any reason.
Building Building
======== ========
Currently, the build system is very bare-bones. On a UNIX-like system, just run On a UNIX-like system, just run `make`. You need GNU Make and either GCC or
`make`. You need GNU Make and either GCC or Clang. Clang. There is no `make install` yet; just copy the file(s) to where you want.
There are various options which can be set on the `make` command line; see the There are various options which can be set on the `make` command line; see the
Makefile for details. As an example, you can run `make SUPPORT_COMPRESSION=no` Makefile for details. As an example, you can run `make SUPPORT_COMPRESSION=no`
to build a decompression-only library. to build a decompression-only library.
There is no `make install` yet; just copy the file(s) to where you want. On Windows, a separate Makefile, `Makefile.msc`, is provided for the tools that
come with Visual Studio. However, using MinGW (GCC) instead is recommended
It's possible to build Windows binaries using MinGW with a command like this: because it is a superior compiler that produces better-performing binaries. You
can build Windows binaries using MinGW with a command like this:
$ make CC=x86_64-w64-mingw32-gcc BUILD_PROGRAMS=yes
$ make CC=x86_64-w64-mingw32-gcc
API API
=== ===

View File

@ -11,6 +11,19 @@ extern "C" {
#include <stddef.h> #include <stddef.h>
/* Microsoft C / Visual Studio garbage. If you want to link to the DLL version
* of libdeflate, then #define LIBDEFLATE_DLL. */
#ifdef _MSC_VER
# ifdef BUILDING_LIBDEFLATE
# define LIBDEFLATEAPI __declspec(dllexport)
# elif defined(LIBDEFLATE_DLL)
# define LIBDEFLATEAPI __declspec(dllimport)
# endif
#endif
#ifndef LIBDEFLATEAPI
# define LIBDEFLATEAPI
#endif
/* ========================================================================== */ /* ========================================================================== */
/* Compression */ /* Compression */
/* ========================================================================== */ /* ========================================================================== */
@ -28,7 +41,7 @@ struct deflate_compressor;
* to 32768, the largest size permissible in the DEFLATE format. It cannot be * to 32768, the largest size permissible in the DEFLATE format. It cannot be
* changed at runtime. * changed at runtime.
*/ */
extern struct deflate_compressor * LIBDEFLATEAPI struct deflate_compressor *
deflate_alloc_compressor(unsigned int compression_level); deflate_alloc_compressor(unsigned int compression_level);
/* /*
@ -38,7 +51,7 @@ deflate_alloc_compressor(unsigned int compression_level);
* The return value is the compressed size in bytes, or 0 if the data could not * The return value is the compressed size in bytes, or 0 if the data could not
* be compressed to 'out_nbytes_avail' bytes or fewer. * be compressed to 'out_nbytes_avail' bytes or fewer.
*/ */
extern size_t LIBDEFLATEAPI size_t
deflate_compress(struct deflate_compressor *compressor, deflate_compress(struct deflate_compressor *compressor,
const void *in, size_t in_nbytes, const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail); void *out, size_t out_nbytes_avail);
@ -62,13 +75,13 @@ deflate_compress(struct deflate_compressor *compressor,
* and store the data uncompressed if deflate_compress() returns 0, indicating * and store the data uncompressed if deflate_compress() returns 0, indicating
* that the compressed data did not fit into the provided output buffer. * that the compressed data did not fit into the provided output buffer.
*/ */
extern size_t LIBDEFLATEAPI size_t
deflate_compress_bound(struct deflate_compressor *compressor, size_t in_nbytes); deflate_compress_bound(struct deflate_compressor *compressor, size_t in_nbytes);
/* /*
* Like deflate_compress(), but stores the data in the zlib wrapper format. * Like deflate_compress(), but stores the data in the zlib wrapper format.
*/ */
extern size_t LIBDEFLATEAPI size_t
zlib_compress(struct deflate_compressor *compressor, zlib_compress(struct deflate_compressor *compressor,
const void *in, size_t in_nbytes, const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail); void *out, size_t out_nbytes_avail);
@ -77,13 +90,13 @@ zlib_compress(struct deflate_compressor *compressor,
* Like deflate_compress_bound(), but assumes the data will be compressed with * Like deflate_compress_bound(), but assumes the data will be compressed with
* zlib_compress() rather than with deflate_compress(). * zlib_compress() rather than with deflate_compress().
*/ */
extern size_t LIBDEFLATEAPI size_t
zlib_compress_bound(struct deflate_compressor *compressor, size_t in_nbytes); zlib_compress_bound(struct deflate_compressor *compressor, size_t in_nbytes);
/* /*
* Like deflate_compress(), but stores the data in the gzip wrapper format. * Like deflate_compress(), but stores the data in the gzip wrapper format.
*/ */
extern size_t LIBDEFLATEAPI size_t
gzip_compress(struct deflate_compressor *compressor, gzip_compress(struct deflate_compressor *compressor,
const void *in, size_t in_nbytes, const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail); void *out, size_t out_nbytes_avail);
@ -92,7 +105,7 @@ gzip_compress(struct deflate_compressor *compressor,
* Like deflate_compress_bound(), but assumes the data will be compressed with * Like deflate_compress_bound(), but assumes the data will be compressed with
* gzip_compress() rather than with deflate_compress(). * gzip_compress() rather than with deflate_compress().
*/ */
extern size_t LIBDEFLATEAPI size_t
gzip_compress_bound(struct deflate_compressor *compressor, size_t in_nbytes); gzip_compress_bound(struct deflate_compressor *compressor, size_t in_nbytes);
/* /*
@ -100,7 +113,7 @@ gzip_compress_bound(struct deflate_compressor *compressor, size_t in_nbytes);
* deflate_alloc_compressor(). If a NULL pointer is passed in, no action is * deflate_alloc_compressor(). If a NULL pointer is passed in, no action is
* taken. * taken.
*/ */
extern void LIBDEFLATEAPI void
deflate_free_compressor(struct deflate_compressor *compressor); deflate_free_compressor(struct deflate_compressor *compressor);
/* ========================================================================== */ /* ========================================================================== */
@ -120,7 +133,7 @@ struct deflate_decompressor;
* DEFLATE, zlib, or gzip); however, the appropriate decompression function must * DEFLATE, zlib, or gzip); however, the appropriate decompression function must
* be called. * be called.
*/ */
extern struct deflate_decompressor * LIBDEFLATEAPI struct deflate_decompressor *
deflate_alloc_decompressor(void); deflate_alloc_decompressor(void);
/* /*
@ -172,7 +185,7 @@ enum decompress_result {
* but no other problems were encountered, or another nonzero result code if * but no other problems were encountered, or another nonzero result code if
* decompression failed for another reason. * decompression failed for another reason.
*/ */
extern enum decompress_result LIBDEFLATEAPI enum decompress_result
deflate_decompress(struct deflate_decompressor *decompressor, deflate_decompress(struct deflate_decompressor *decompressor,
const void *in, size_t in_nbytes, const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail, void *out, size_t out_nbytes_avail,
@ -182,7 +195,7 @@ deflate_decompress(struct deflate_decompressor *decompressor,
* Like deflate_decompress(), but assumes the zlib wrapper format instead of raw * Like deflate_decompress(), but assumes the zlib wrapper format instead of raw
* DEFLATE. * DEFLATE.
*/ */
extern enum decompress_result LIBDEFLATEAPI enum decompress_result
zlib_decompress(struct deflate_decompressor *decompressor, zlib_decompress(struct deflate_decompressor *decompressor,
const void *in, size_t in_nbytes, const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail, void *out, size_t out_nbytes_avail,
@ -192,7 +205,7 @@ zlib_decompress(struct deflate_decompressor *decompressor,
* Like deflate_decompress(), but assumes the gzip wrapper format instead of raw * Like deflate_decompress(), but assumes the gzip wrapper format instead of raw
* DEFLATE. * DEFLATE.
*/ */
extern enum decompress_result LIBDEFLATEAPI enum decompress_result
gzip_decompress(struct deflate_decompressor *decompressor, gzip_decompress(struct deflate_decompressor *decompressor,
const void *in, size_t in_nbytes, const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail, void *out, size_t out_nbytes_avail,
@ -203,7 +216,7 @@ gzip_decompress(struct deflate_decompressor *decompressor,
* with deflate_alloc_decompressor(). If a NULL pointer is passed in, no action * with deflate_alloc_decompressor(). If a NULL pointer is passed in, no action
* is taken. * is taken.
*/ */
extern void LIBDEFLATEAPI void
deflate_free_decompressor(struct deflate_decompressor *decompressor); deflate_free_decompressor(struct deflate_decompressor *decompressor);

View File

@ -126,7 +126,7 @@ bt_matchfinder_advance_one_byte(struct bt_matchfinder * const restrict mf,
const u32 max_len, const u32 max_len,
const u32 nice_len, const u32 nice_len,
const u32 max_search_depth, const u32 max_search_depth,
u32 next_hashes[const restrict static 2], u32 next_hashes[restrict 2],
u32 * const restrict best_len_ret, u32 * const restrict best_len_ret,
struct lz_match * restrict lz_matchptr, struct lz_match * restrict lz_matchptr,
const bool record_matches) const bool record_matches)
@ -294,7 +294,7 @@ bt_matchfinder_get_matches(struct bt_matchfinder *mf,
u32 max_len, u32 max_len,
u32 nice_len, u32 nice_len,
u32 max_search_depth, u32 max_search_depth,
u32 next_hashes[static 2], u32 next_hashes[2],
u32 *best_len_ret, u32 *best_len_ret,
struct lz_match *lz_matchptr) struct lz_match *lz_matchptr)
{ {
@ -323,7 +323,7 @@ bt_matchfinder_skip_position(struct bt_matchfinder *mf,
u32 max_len, u32 max_len,
u32 nice_len, u32 nice_len,
u32 max_search_depth, u32 max_search_depth,
u32 next_hashes[static 2]) u32 next_hashes[2])
{ {
u32 best_len; u32 best_len;
bt_matchfinder_advance_one_byte(mf, bt_matchfinder_advance_one_byte(mf,

View File

@ -2,9 +2,7 @@
* compiler-gcc.h - definitions for the GNU C compiler (and for clang) * compiler-gcc.h - definitions for the GNU C compiler (and for clang)
*/ */
#pragma once #ifdef _WIN32
#ifdef __WIN32__
# define LIBEXPORT __declspec(dllexport) # define LIBEXPORT __declspec(dllexport)
#else #else
# define LIBEXPORT __attribute__((visibility("default"))) # define LIBEXPORT __attribute__((visibility("default")))

56
src/compiler-msc.h Normal file
View File

@ -0,0 +1,56 @@
/*
* compiler-msc.h - definitions for the Microsoft C Compiler
*/
#include <inttypes.h>
#include <stdlib.h>
#define BUILDING_LIBDEFLATE
/* MSC __restrict has nonstandard behavior. Don't use it. */
#define restrict
#define LIBEXPORT __declspec(dllexport)
#define forceinline __forceinline
/* Assume a little endian architecture with fast unaligned access. */
#define CPU_IS_LITTLE_ENDIAN() 1
#define UNALIGNED_ACCESS_IS_FAST 1
#define compiler_bswap16 _byteswap_ushort
#define compiler_bswap32 _byteswap_ulong
#define compiler_bswap64 _byteswap_uint64
static forceinline unsigned
compiler_fls32(uint32_t n)
{
_BitScanReverse(&n, n);
return n;
}
#define compiler_fls32 compiler_fls32
static forceinline unsigned
compiler_ffs32(uint32_t n)
{
_BitScanForward(&n, n);
return n;
}
#define compiler_ffs32 compiler_ffs32
#ifdef _M_X64
static forceinline unsigned
compiler_fls64(uint64_t n)
{
_BitScanReverse64(&n, n);
return n;
}
#define compiler_fls64 compiler_fls64
static forceinline unsigned
compiler_ffs64(uint64_t n)
{
_BitScanForward64(&n, n);
return n;
}
#define compiler_ffs64 compiler_ffs64
#endif /* _M_X64 */

View File

@ -8,8 +8,10 @@
* define as many of them as possible. */ * define as many of them as possible. */
#ifdef __GNUC__ #ifdef __GNUC__
# include "compiler-gcc.h" # include "compiler-gcc.h"
#elif defined(_MSC_VER)
# include "compiler-msc.h"
#else #else
# warning "Unrecognized compiler. Please add a header file for your compiler. Compilation will proceed, but performance may suffer!" # pragma message("Unrecognized compiler. Please add a header file for your compiler. Compilation will proceed, but performance may suffer!")
#endif #endif
/* forceinline - force a function to be inlined */ /* forceinline - force a function to be inlined */

View File

@ -26,6 +26,8 @@ FUNCNAME(struct deflate_decompressor * restrict d,
u16 nlen; u16 nlen;
unsigned num_litlen_syms; unsigned num_litlen_syms;
unsigned num_offset_syms; unsigned num_offset_syms;
u16 tmp16;
u32 tmp32;
next_block: next_block:
/* Starting to read the next block. */ /* Starting to read the next block. */

View File

@ -11,13 +11,13 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "libdeflate.h"
#include "aligned_malloc.h" #include "aligned_malloc.h"
#include "deflate_compress.h" #include "deflate_compress.h"
#include "deflate_constants.h" #include "deflate_constants.h"
#include "unaligned.h" #include "unaligned.h"
#include "libdeflate.h"
/* /*
* Note: when compiling this file, SUPPORT_NEAR_OPTIMAL_PARSING should be * Note: when compiling this file, SUPPORT_NEAR_OPTIMAL_PARSING should be
* defined to either 0 or 1. When defined to 1, the near-optimal parsing * defined to either 0 or 1. When defined to 1, the near-optimal parsing
@ -1565,7 +1565,7 @@ deflate_compress_greedy(struct deflate_compressor * restrict c,
struct deflate_sequence *next_seq = c->sequences; struct deflate_sequence *next_seq = c->sequences;
u32 litrunlen = 0; u32 litrunlen = 0;
u32 items_remaining = MAX_ITEMS_PER_BLOCK; u32 items_remaining = MAX_ITEMS_PER_BLOCK;
u32 next_hashes[2] = {}; u32 next_hashes[2] = {0, 0};
deflate_init_output(&os, out, out_nbytes_avail); deflate_init_output(&os, out, out_nbytes_avail);
deflate_reset_symbol_frequencies(c); deflate_reset_symbol_frequencies(c);
@ -1662,7 +1662,7 @@ deflate_compress_lazy(struct deflate_compressor * restrict c,
struct deflate_sequence *next_seq = c->sequences; struct deflate_sequence *next_seq = c->sequences;
u32 litrunlen = 0; u32 litrunlen = 0;
u32 items_remaining = MAX_ITEMS_PER_BLOCK; u32 items_remaining = MAX_ITEMS_PER_BLOCK;
u32 next_hashes[2] = {}; u32 next_hashes[2] = {0, 0};
deflate_init_output(&os, out, out_nbytes_avail); deflate_init_output(&os, out, out_nbytes_avail);
deflate_reset_symbol_frequencies(c); deflate_reset_symbol_frequencies(c);
@ -2171,7 +2171,7 @@ deflate_compress_near_optimal(struct deflate_compressor * restrict c,
struct lz_match *cache_end; struct lz_match *cache_end;
const u8 *in_block_begin; const u8 *in_block_begin;
const u8 *in_block_end; const u8 *in_block_end;
u32 next_hashes[2] = {}; u32 next_hashes[2] = {0, 0};
deflate_init_output(&os, out, out_nbytes_avail); deflate_init_output(&os, out, out_nbytes_avail);
deflate_reset_symbol_frequencies(c); deflate_reset_symbol_frequencies(c);

View File

@ -9,10 +9,10 @@
* *
* --------------------------------------------------------------------------- * ---------------------------------------------------------------------------
* *
* This is a highly optimized DEFLATE decompressor. On x86_64 it decompresses * This is a highly optimized DEFLATE decompressor. When compiled with gcc on
* data in about 52% of the time of zlib (48% if BMI2 instructions are * x86_64, it decompresses data in about 52% of the time of zlib (48% if BMI2
* available). On other architectures it should still be significantly faster * instructions are available). On other architectures it should still be
* than zlib, but the difference may be smaller. * significantly faster than zlib, but the difference may be smaller.
* *
* Why this is faster than zlib's implementation: * Why this is faster than zlib's implementation:
* *
@ -30,19 +30,19 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "libdeflate.h"
#include "deflate_constants.h" #include "deflate_constants.h"
#include "unaligned.h" #include "unaligned.h"
#include "x86_cpu_features.h" #include "x86_cpu_features.h"
#include "libdeflate.h"
/* By default, if the expression passed to SAFETY_CHECK() evaluates to false, /* By default, if the expression passed to SAFETY_CHECK() evaluates to false,
* then deflate_decompress() immediately returns DECOMPRESS_BAD_DATA as the * then deflate_decompress() immediately returns DECOMPRESS_BAD_DATA as the
* compressed data is invalid. But if unsafe decompression is enabled, then the * compressed data is invalid. But if unsafe decompression is enabled, then the
* value of the expression is ignored, allowing the compiler to optimize out * value of the expression is ignored, allowing the compiler to optimize out
* some code. */ * some code. */
#if UNSAFE_DECOMPRESSION #if UNSAFE_DECOMPRESSION
# warning "UNSAFE DECOMPRESSION IS ENABLED. THIS MUST ONLY BE USED IF THE DECOMPRESSOR INPUT WILL ALWAYS BE TRUSTED!" # pragma message("UNSAFE DECOMPRESSION IS ENABLED. THIS MUST ONLY BE USED IF THE DECOMPRESSOR INPUT WILL ALWAYS BE TRUSTED!")
# define SAFETY_CHECK(expr) (void)(expr) # define SAFETY_CHECK(expr) (void)(expr)
#else #else
# define SAFETY_CHECK(expr) if (unlikely(!(expr))) return DECOMPRESS_BAD_DATA # define SAFETY_CHECK(expr) if (unlikely(!(expr))) return DECOMPRESS_BAD_DATA
@ -195,15 +195,13 @@ typedef machine_word_t bitbuf_t;
* checksum against the uncompressed data if they wish to detect corruptions. * checksum against the uncompressed data if they wish to detect corruptions.
*/ */
#define FILL_BITS_BYTEWISE() \ #define FILL_BITS_BYTEWISE() \
({ \
do { \ do { \
if (likely(in_next != in_end)) \ if (likely(in_next != in_end)) \
bitbuf |= (bitbuf_t)*in_next++ << bitsleft; \ bitbuf |= (bitbuf_t)*in_next++ << bitsleft; \
else \ else \
overrun_count++; \ overrun_count++; \
bitsleft += 8; \ bitsleft += 8; \
} while (bitsleft <= BITBUF_NBITS - 8); \ } while (bitsleft <= BITBUF_NBITS - 8)
})
/* /*
* Fill the bitbuffer variable by reading the next word from the input buffer. * Fill the bitbuffer variable by reading the next word from the input buffer.
@ -214,11 +212,11 @@ typedef machine_word_t bitbuf_t;
* access, such as x86 and x86_64. * access, such as x86 and x86_64.
*/ */
#define FILL_BITS_WORDWISE() \ #define FILL_BITS_WORDWISE() \
({ \ do { \
bitbuf |= get_unaligned_leword(in_next) << bitsleft; \ bitbuf |= get_unaligned_leword(in_next) << bitsleft; \
in_next += (BITBUF_NBITS - bitsleft) >> 3; \ in_next += (BITBUF_NBITS - bitsleft) >> 3; \
bitsleft += (BITBUF_NBITS - bitsleft) & ~7; \ bitsleft += (BITBUF_NBITS - bitsleft) & ~7; \
}) } while (0)
/* /*
* Does the bitbuffer variable currently contain at least 'n' bits? * Does the bitbuffer variable currently contain at least 'n' bits?
@ -226,56 +224,34 @@ typedef machine_word_t bitbuf_t;
#define HAVE_BITS(n) (bitsleft >= (n)) #define HAVE_BITS(n) (bitsleft >= (n))
/* /*
* Raw form of ENSURE_BITS(): the bitbuffer variable must not already contain * Load more bits from the input buffer until the specified number of bits is
* the requested number of bits. * present in the bitbuffer variable. 'n' cannot be too large; see MAX_ENSURE
* and CAN_ENSURE().
*/ */
#define DO_ENSURE_BITS(n) \ #define ENSURE_BITS(n) \
({ \ if (!HAVE_BITS(n)) { \
if (CPU_IS_LITTLE_ENDIAN() && \ if (CPU_IS_LITTLE_ENDIAN() && \
UNALIGNED_ACCESS_IS_FAST && \ UNALIGNED_ACCESS_IS_FAST && \
likely(in_end - in_next >= sizeof(bitbuf_t))) \ likely(in_end - in_next >= sizeof(bitbuf_t))) \
FILL_BITS_WORDWISE(); \ FILL_BITS_WORDWISE(); \
else \ else \
FILL_BITS_BYTEWISE(); \ FILL_BITS_BYTEWISE(); \
}) }
/*
* Load more bits from the input buffer until the specified number of bits is
* present in the bitbuffer variable. 'n' cannot be too large; see MAX_ENSURE
* and CAN_ENSURE().
*/
#define ENSURE_BITS(n) \
({ \
if (!HAVE_BITS(n)) \
DO_ENSURE_BITS(n); \
})
/* /*
* Return the next 'n' bits from the bitbuffer variable without removing them. * Return the next 'n' bits from the bitbuffer variable without removing them.
*/ */
#define BITS(n) \ #define BITS(n) ((u32)bitbuf & (((u32)1 << (n)) - 1))
({ \
(u32)bitbuf & (((u32)1 << (n)) - 1); \
})
/* /*
* Remove the next 'n' bits from the bitbuffer variable. * Remove the next 'n' bits from the bitbuffer variable.
*/ */
#define REMOVE_BITS(n) \ #define REMOVE_BITS(n) (bitbuf >>= (n), bitsleft -= (n))
({ \
bitbuf >>= (n); \
bitsleft -= (n); \
})
/* /*
* Remove and return the next 'n' bits from the bitbuffer variable. * Remove and return the next 'n' bits from the bitbuffer variable.
*/ */
#define POP_BITS(n) \ #define POP_BITS(n) (tmp32 = BITS(n), REMOVE_BITS(n), tmp32)
({ \
u32 bits = BITS(n); \
REMOVE_BITS(n); \
bits; \
})
/* /*
* Align the input to the next byte boundary, discarding any remaining bits in * Align the input to the next byte boundary, discarding any remaining bits in
@ -287,24 +263,17 @@ typedef machine_word_t bitbuf_t;
* be actually discarded. * be actually discarded.
*/ */
#define ALIGN_INPUT() \ #define ALIGN_INPUT() \
({ \ do { \
in_next -= (bitsleft >> 3) - MIN(overrun_count, bitsleft >> 3); \ in_next -= (bitsleft >> 3) - MIN(overrun_count, bitsleft >> 3); \
bitbuf = 0; \ bitbuf = 0; \
bitsleft = 0; \ bitsleft = 0; \
}) } while(0)
/* /*
* Read a 16-bit value from the input. This must have been preceded by a call * Read a 16-bit value from the input. This must have been preceded by a call
* to ALIGN_INPUT(), and the caller must have already checked for overrun. * to ALIGN_INPUT(), and the caller must have already checked for overrun.
*/ */
#define READ_U16() \ #define READ_U16() (tmp16 = get_unaligned_le16(in_next), in_next += 2, tmp16)
({ \
u16 v; \
\
v = get_unaligned_le16(in_next); \
in_next += 2; \
v; \
})
/***************************************************************************** /*****************************************************************************
* Huffman decoding * * Huffman decoding *

View File

@ -8,13 +8,13 @@
* You can do whatever you want with this file. * You can do whatever you want with this file.
*/ */
#include "libdeflate.h"
#include "crc32.h" #include "crc32.h"
#include "deflate_compress.h" #include "deflate_compress.h"
#include "gzip_constants.h" #include "gzip_constants.h"
#include "unaligned.h" #include "unaligned.h"
#include "libdeflate.h"
LIBEXPORT size_t LIBEXPORT size_t
gzip_compress(struct deflate_compressor *c, const void *in, size_t in_size, gzip_compress(struct deflate_compressor *c, const void *in, size_t in_size,
void *out, size_t out_nbytes_avail) void *out, size_t out_nbytes_avail)

View File

@ -8,12 +8,12 @@
* You can do whatever you want with this file. * You can do whatever you want with this file.
*/ */
#include "libdeflate.h"
#include "crc32.h" #include "crc32.h"
#include "gzip_constants.h" #include "gzip_constants.h"
#include "unaligned.h" #include "unaligned.h"
#include "libdeflate.h"
LIBEXPORT enum decompress_result LIBEXPORT enum decompress_result
gzip_decompress(struct deflate_decompressor *d, gzip_decompress(struct deflate_decompressor *d,
const void *in, size_t in_nbytes, const void *in, size_t in_nbytes,

View File

@ -167,12 +167,12 @@ hc_matchfinder_longest_match(struct hc_matchfinder * const restrict mf,
const u32 max_len, const u32 max_len,
const u32 nice_len, const u32 nice_len,
const u32 max_search_depth, const u32 max_search_depth,
u32 next_hashes[const restrict static 2], u32 next_hashes[restrict 2],
u32 * const restrict offset_ret) u32 * const restrict offset_ret)
{ {
const u8 *in_next = in_base + cur_pos; const u8 *in_next = in_base + cur_pos;
u32 depth_remaining = max_search_depth; u32 depth_remaining = max_search_depth;
const u8 *best_matchptr = best_matchptr; /* uninitialized */ const u8 *best_matchptr = in_next;
const mf_pos_t cutoff = cur_pos - MATCHFINDER_WINDOW_SIZE; const mf_pos_t cutoff = cur_pos - MATCHFINDER_WINDOW_SIZE;
mf_pos_t cur_node3, cur_node4; mf_pos_t cur_node3, cur_node4;
u32 hash3, hash4; u32 hash3, hash4;
@ -335,7 +335,7 @@ hc_matchfinder_skip_positions(struct hc_matchfinder * const restrict mf,
const ptrdiff_t cur_pos, const ptrdiff_t cur_pos,
const ptrdiff_t end_pos, const ptrdiff_t end_pos,
const u32 count, const u32 count,
u32 next_hashes[const restrict static 2]) u32 next_hashes[restrict 2])
{ {
const u8 *in_next = in_base + cur_pos; const u8 *in_next = in_base + cur_pos;
const u8 * const stop_ptr = in_next + count; const u8 * const stop_ptr = in_next + count;

View File

@ -8,13 +8,13 @@
* You can do whatever you want with this file. * You can do whatever you want with this file.
*/ */
#include "libdeflate.h"
#include "adler32.h" #include "adler32.h"
#include "deflate_compress.h" #include "deflate_compress.h"
#include "unaligned.h" #include "unaligned.h"
#include "zlib_constants.h" #include "zlib_constants.h"
#include "libdeflate.h"
LIBEXPORT size_t LIBEXPORT size_t
zlib_compress(struct deflate_compressor *c, const void *in, size_t in_size, zlib_compress(struct deflate_compressor *c, const void *in, size_t in_size,
void *out, size_t out_nbytes_avail) void *out, size_t out_nbytes_avail)

View File

@ -8,12 +8,12 @@
* You can do whatever you want with this file. * You can do whatever you want with this file.
*/ */
#include "libdeflate.h"
#include "adler32.h" #include "adler32.h"
#include "unaligned.h" #include "unaligned.h"
#include "zlib_constants.h" #include "zlib_constants.h"
#include "libdeflate.h"
LIBEXPORT enum decompress_result LIBEXPORT enum decompress_result
zlib_decompress(struct deflate_decompressor *d, zlib_decompress(struct deflate_decompressor *d,
const void *in, size_t in_nbytes, const void *in, size_t in_nbytes,

View File

@ -8,70 +8,37 @@
* You can do whatever you want with this file. * You can do whatever you want with this file.
*/ */
#define _FILE_OFFSET_BITS 64
#undef _ANSI_SOURCE
#define _POSIX_C_SOURCE 199309L
#include <stdbool.h> #include "util.h"
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <libdeflate.h>
#include <zlib.h> #include <zlib.h>
static const tchar *const optstring = T("s:l:123456789zgYZh");
static void static void
usage(FILE *fp) usage(FILE *fp)
{ {
static const char * const str = static const char * const str =
"Usage: benchmark [FILE...]\n" "Usage: benchmark [OPTION]... [FILE]...\n"
"\n" "\n"
"A compression and decompression benchmark and testing program.\n" "A compression and decompression benchmark and testing program.\n"
"Benchmarks are run on each FILE specified, or stdin if no file is specified.\n" "Benchmarks are run on each FILE specified, or stdin if no file is specified.\n"
"\n" "\n"
"Options:\n" "Options:\n"
" -s, --chunk-size=SIZE chunk size\n" " -s SIZE chunk size\n"
" -l, --level=LEVEL compression level [1-12]\n" " -l LEVEL compression level [1-12]\n"
" -1 fastest\n" " -1 fastest\n"
" -9 slow\n" " -9 slow\n"
" -z, --zlib use zlib wrapper\n" " -z use zlib wrapper\n"
" -g, --gzip use gzip wrapper\n" " -g use gzip wrapper\n"
" -Y, --compress-with-libz compress with libz, not libdeflate\n" " -Y compress with libz, not libdeflate\n"
" -Z, --decompress-with-libz decompress with libz, not libdeflate\n" " -Z decompress with libz, not libdeflate\n"
" -h, --help print this help\n" " -h print this help\n"
; ;
fputs(str, fp); fputs(str, fp);
} }
static void
fatal_error(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
fprintf(stderr, "ERROR: ");
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");
va_end(va);
exit(1);
}
#define ASSERT(expr, fmt, ...) \
{ \
if (!(expr)) \
fatal_error((fmt), ## __VA_ARGS__); \
}
enum wrapper { enum wrapper {
NO_WRAPPER, NO_WRAPPER,
ZLIB_WRAPPER, ZLIB_WRAPPER,
@ -293,15 +260,6 @@ decompressor_destroy(struct decompressor *d)
(*d->free_private)(d->private); (*d->free_private)(d->private);
} }
#define TIME_UNIT_PER_MS 1000000
static uint64_t
current_time(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ((uint64_t)1000000000 * ts.tv_sec) + ts.tv_nsec;
}
static void static void
do_benchmark(int fd, char *ubuf1, char *ubuf2, do_benchmark(int fd, char *ubuf1, char *ubuf2,
char *cbuf, uint32_t max_chunk_size, char *cbuf, uint32_t max_chunk_size,
@ -312,13 +270,9 @@ do_benchmark(int fd, char *ubuf1, char *ubuf2,
uint64_t compress_time_total = 0; uint64_t compress_time_total = 0;
uint64_t decompress_time_total = 0; uint64_t decompress_time_total = 0;
#ifdef __WIN32__
_setmode(fd, O_BINARY);
#endif
for (;;) { for (;;) {
char *p = ubuf1; char *p = ubuf1;
ssize_t bytes_read; int32_t bytes_read;
size_t usize; size_t usize;
size_t csize; size_t csize;
uint64_t start_time; uint64_t start_time;
@ -381,27 +335,15 @@ do_benchmark(int fd, char *ubuf1, char *ubuf2,
(unsigned int)(csize_total * 100 / usize_total), (unsigned int)(csize_total * 100 / usize_total),
(unsigned int)(csize_total * 100000 / usize_total % 1000)); (unsigned int)(csize_total * 100000 / usize_total % 1000));
printf("\tCompression time: %"PRIu64" ms (%"PRIu64" MB/s)\n", printf("\tCompression time: %"PRIu64" ms (%"PRIu64" MB/s)\n",
compress_time_total / TIME_UNIT_PER_MS, compress_time_total / 1000000,
1000 * usize_total / compress_time_total); 1000 * usize_total / compress_time_total);
printf("\tDecompression time: %"PRIu64" ms (%"PRIu64" MB/s)\n", printf("\tDecompression time: %"PRIu64" ms (%"PRIu64" MB/s)\n",
decompress_time_total / TIME_UNIT_PER_MS, decompress_time_total / 1000000,
1000 * usize_total / decompress_time_total); 1000 * usize_total / decompress_time_total);
} }
static const char *const optstring = "s:l:0123456789gzYZh";
static const struct option longopts[] = {
{"chunk-size", required_argument, NULL, 's'},
{"level", required_argument, NULL, 'l'},
{"zlib", no_argument, NULL, 'z'},
{"gzip", no_argument, NULL, 'g'},
{"compress-with-libz", no_argument, NULL, 'Y'},
{"decompress-with-libz", no_argument, NULL, 'Z'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0},
};
int int
main(int argc, char **argv) main(int argc, tchar *argv[])
{ {
uint32_t chunk_size = 32768; uint32_t chunk_size = 32768;
int level = 6; int level = 6;
@ -415,17 +357,23 @@ main(int argc, char **argv)
struct decompressor d; struct decompressor d;
int opt_char; int opt_char;
while ((opt_char = while ((opt_char = tgetopt(argc, argv, optstring)) != -1) {
getopt_long(argc, argv, optstring, longopts, NULL)) != -1)
{
switch (opt_char) { switch (opt_char) {
case 's': case 's':
chunk_size = strtoul(optarg, NULL, 10); chunk_size = tstrtoul(toptarg, NULL, 10);
break; break;
case 'l': case 'l':
level = strtoul(optarg, NULL, 10); level = tstrtoul(toptarg, NULL, 10);
break; break;
case '1' ... '9': case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
level = opt_char - '0'; level = opt_char - '0';
break; break;
case 'z': case 'z':
@ -449,8 +397,8 @@ main(int argc, char **argv)
} }
} }
argc -= optind; argc -= toptind;
argv += optind; argv += toptind;
printf("Benchmarking DEFLATE compression:\n"); printf("Benchmarking DEFLATE compression:\n");
printf("\tCompression level: %d\n", level); printf("\tCompression level: %d\n", level);
@ -475,14 +423,15 @@ main(int argc, char **argv)
if (argc == 0) { if (argc == 0) {
printf("Reading from stdin...\n"); printf("Reading from stdin...\n");
set_binary_mode(STDIN_FILENO);
do_benchmark(STDIN_FILENO, ubuf1, ubuf2, do_benchmark(STDIN_FILENO, ubuf1, ubuf2,
cbuf, chunk_size, &c, &d); cbuf, chunk_size, &c, &d);
} else { } else {
for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
printf("Processing \"%s\"...\n", argv[i]); printf("Processing \"%"TS"\"...\n", argv[i]);
int fd = open(argv[i], O_RDONLY); int fd = topen(argv[i], O_RDONLY | O_BINARY);
ASSERT(fd >= 0, ASSERT(fd >= 0,
"Can't open \"%s\" for reading: %s\n", "Can't open \"%"TS"\" for reading: %s\n",
argv[i], strerror(errno)); argv[i], strerror(errno));
do_benchmark(fd, ubuf1, ubuf2, cbuf, chunk_size, &c, &d); do_benchmark(fd, ubuf1, ubuf2, cbuf, chunk_size, &c, &d);
close(fd); close(fd);

View File

@ -8,76 +8,7 @@
* You can do whatever you want with this file. * You can do whatever you want with this file.
*/ */
#define _FILE_OFFSET_BITS 64 #include "util.h"
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef __WIN32__
# include <wchar.h>
# include <windows.h>
#else
# include <sys/mman.h>
#endif
#include "libdeflate.h"
#ifdef __WIN32__
# define main wmain
# define tchar wchar_t
# define _T(text) L##text
# define T(text) _T(text)
# define TS "ls"
# define tstrcmp wcscmp
# define tstrlen wcslen
# define tmemcpy wmemcpy
# define tstrrchr wcsrchr
# define tstrtol wcstol
# define topen _wopen
# define topen _wopen
# define tstat _wstati64
# define tunlink _wunlink
#else
# define main main
# define tchar char
# define T(text) text
# define TS "s"
# define tstrcmp strcmp
# define tstrlen strlen
# define tmemcpy memcpy
# define tstrrchr strrchr
# define tstrtol strtol
# define topen open
# define tstat stat
# define tunlink unlink
#endif
#ifndef O_BINARY
# define O_BINARY 0
#endif
static const tchar *
basename(const tchar *argv0)
{
const tchar *p = tstrrchr(argv0, '/');
#ifdef __WIN32__
const tchar *p2 = tstrrchr(argv0, '\\');
if (p2 && (!p || p2 > p))
p = p2;
#endif
if (p)
return p + 1;
return argv0;
}
static bool static bool
is_gunzip(const tchar *argv0) is_gunzip(const tchar *argv0)
@ -86,7 +17,7 @@ is_gunzip(const tchar *argv0)
if (!tstrcmp(name, T("gunzip"))) if (!tstrcmp(name, T("gunzip")))
return true; return true;
#ifdef __WIN32__ #ifdef _WIN32
if (!tstrcmp(name, T("gunzip.exe"))) if (!tstrcmp(name, T("gunzip.exe")))
return true; return true;
#endif #endif
@ -104,26 +35,6 @@ usage(void)
exit(1); exit(1);
} }
static void
fatal_error(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
fprintf(stderr, "ERROR: ");
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");
va_end(va);
exit(1);
}
#define ASSERT(expr, fmt, ...) \
{ \
if (!(expr)) \
fatal_error((fmt), ## __VA_ARGS__); \
}
static void * static void *
map_file_contents(const tchar *path, size_t *size_ret, void **token_ret) map_file_contents(const tchar *path, size_t *size_ret, void **token_ret)
{ {
@ -148,8 +59,8 @@ map_file_contents(const tchar *path, size_t *size_ret, void **token_ret)
"File \"%"TS"\" cannot be processed by " "File \"%"TS"\" cannot be processed by "
"this program because it is too large.", path); "this program because it is too large.", path);
#ifdef __WIN32__ #ifdef _WIN32
HANDLE h = CreateFileMapping((HANDLE)_get_osfhandle(fd), HANDLE h = CreateFileMapping((HANDLE)(intptr_t)_get_osfhandle(fd),
NULL, PAGE_READONLY, 0, 0, NULL); NULL, PAGE_READONLY, 0, 0, NULL);
ASSERT(h != NULL, "Unable create file mapping for \"%"TS"\": " ASSERT(h != NULL, "Unable create file mapping for \"%"TS"\": "
"Windows error %u", path, (unsigned int )GetLastError()); "Windows error %u", path, (unsigned int )GetLastError());
@ -178,7 +89,7 @@ map_file_contents(const tchar *path, size_t *size_ret, void **token_ret)
static void static void
unmap_file_contents(void *token, void *map, size_t size) unmap_file_contents(void *token, void *map, size_t size)
{ {
#ifdef __WIN32__ #ifdef _WIN32
UnmapViewOfFile(map); UnmapViewOfFile(map);
CloseHandle((HANDLE)token); CloseHandle((HANDLE)token);
#else #else
@ -207,7 +118,7 @@ write_file(const tchar *path, const void *contents, size_t size)
ASSERT(ret > 0, "Error writing data to \"%"TS"\": %s", ASSERT(ret > 0, "Error writing data to \"%"TS"\": %s",
path, strerror(errno)); path, strerror(errno));
size -= ret; size -= ret;
contents += ret; contents = (const uint8_t *)contents + ret;
} }
ASSERT(!close(fd), "Error writing data to \"%"TS"\"", ASSERT(!close(fd), "Error writing data to \"%"TS"\"",
@ -253,7 +164,7 @@ decompress_file(struct deflate_decompressor *d, const tchar *path, bool force)
ASSERT(compressed_size >= sizeof(uint32_t), ASSERT(compressed_size >= sizeof(uint32_t),
"File \"%"TS"\" is not a gzip file.", path); "File \"%"TS"\" is not a gzip file.", path);
uncompressed_size = load_u32_gzip(compressed_data + uncompressed_size = load_u32_gzip((const uint8_t *)compressed_data +
(compressed_size - sizeof(uint32_t))); (compressed_size - sizeof(uint32_t)));
uncompressed_data = malloc(uncompressed_size); uncompressed_data = malloc(uncompressed_size);
ASSERT(uncompressed_data != NULL, ASSERT(uncompressed_data != NULL,

23
tools/msc_test.bat Executable file
View File

@ -0,0 +1,23 @@
call d:\VS2015\vc\vcvarsall
nmake /f Makefile.msc clean
nmake /f Makefile.msc
cl /MD /O2 /Fe:benchmark.exe -I. -Itools -I..\zlib-msc tools\benchmark.c tools\wgetopt.c libdeflatestatic.lib ..\zlib-msc\zlib.lib
cl /MD /O2 /Fe:gzip.exe -I. -Itools tools\gzip.c tools\wgetopt.c libdeflatestatic.lib
del j:\exe\gzip.exe 2> nul
del j:\exe\gunzip.exe 2> nul
copy gzip.exe j:\exe\gzip.exe
copy gzip.exe j:\exe\gunzip.exe
del j:\exe\benchmark.exe 2> nul
copy benchmark.exe j:\exe\benchmark.exe
call d:\VS2015\vc\vcvarsall x86_amd64
nmake /f Makefile.msc clean
nmake /f Makefile.msc
cl /MD /O2 /Fe:benchmark.exe -I. -Itools -I..\zlib-msc64 tools\benchmark.c tools\wgetopt.c libdeflatestatic.lib ..\zlib-msc64\zlib.lib
cl /MD /O2 /Fe:gzip.exe -I. -Itools tools\gzip.c tools\wgetopt.c libdeflatestatic.lib
del j:\exe64\gzip.exe 2> nul
del j:\exe64\gunzip.exe 2> nul
copy gzip.exe j:\exe64\gzip.exe
copy gzip.exe j:\exe64\gunzip.exe
del j:\exe64\benchmark.exe 2> nul
copy benchmark.exe j:\exe64\benchmark.exe

135
tools/util.h Normal file
View File

@ -0,0 +1,135 @@
#define _FILE_OFFSET_BITS 64
#undef _ANSI_SOURCE
#define _POSIX_C_SOURCE 199309L
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#ifdef _WIN32
# include <wchar.h>
# include <windows.h>
# include "wgetopt.h"
#else
# include <sys/mman.h>
# include <sys/time.h>
# include <unistd.h>
# include <getopt.h>
#endif
#include <libdeflate.h>
#ifdef _WIN32
# define main wmain
# define tchar wchar_t
# define _T(text) L##text
# define T(text) _T(text)
# define TS "ls"
# define tgetopt wgetopt
# define toptarg woptarg
# define toptind woptind
# define tstrcmp wcscmp
# define tstrlen wcslen
# define tmemcpy wmemcpy
# define tstrrchr wcsrchr
# define tstrtol wcstol
# define tstrtoul wcstoul
# define topen _wopen
# define tunlink _wunlink
# ifdef _MSC_VER
# define fstat _fstat64
# define stat _stat64
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
# endif
# define tstat _wstati64
#else
# define main main
# define tchar char
# define T(text) text
# define TS "s"
# define tgetopt getopt
# define toptarg optarg
# define toptind optind
# define tstrcmp strcmp
# define tstrlen strlen
# define tmemcpy memcpy
# define tstrrchr strrchr
# define tstrtol strtol
# define tstrtoul strtoul
# define topen open
# define tunlink unlink
# define tstat stat
#endif
#ifndef O_BINARY
# define O_BINARY 0
#endif
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
static void
fatal_error(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
fprintf(stderr, "ERROR: ");
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");
va_end(va);
exit(1);
}
#define ASSERT(expr, fmt, ...) \
{ \
if (!(expr)) \
fatal_error((fmt), ## __VA_ARGS__); \
}
static inline const tchar *
basename(const tchar *argv0)
{
const tchar *p = tstrrchr(argv0, '/');
#ifdef _WIN32
const tchar *p2 = tstrrchr(argv0, '\\');
if (p2 && (!p || p2 > p))
p = p2;
#endif
if (p)
return p + 1;
return argv0;
}
static inline void
set_binary_mode(int fd)
{
#ifdef _WIN32
_setmode(fd, O_BINARY);
#endif
}
static inline uint64_t
current_time(void)
{
#ifdef _WIN32
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
return 100 * (((uint64_t)ft.dwHighDateTime << 32) | ft.dwLowDateTime);
#else
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ((uint64_t)1000000000 * ts.tv_sec) + ts.tv_nsec;
#endif
}

62
tools/wgetopt.c Normal file
View File

@ -0,0 +1,62 @@
/*
* wide-character getopt for Windows
*
* Public domain
*/
#include <stdio.h>
#include <wchar.h>
#include "wgetopt.h"
wchar_t *woptarg; /* Global argument pointer */
int woptind = 0; /* Global argv index */
static wchar_t *scan = NULL; /* Private scan pointer */
int wgetopt(int argc, wchar_t * const argv[], const wchar_t *optstring)
{
wchar_t c;
wchar_t *place;
woptarg = NULL;
if (!scan || *scan == '\0') {
if (woptind == 0)
woptind++;
if (woptind >= argc || argv[woptind][0] != '-'
|| argv[woptind][1] == '\0')
return EOF;
if (argv[woptind][1] == '-' && argv[woptind][2] == '\0') {
woptind++;
return EOF;
}
scan = argv[woptind] + 1;
woptind++;
}
c = *scan++;
place = wcschr(optstring, c);
if (!place || c == ':') {
fprintf(stderr, "%ls: unknown option -%lc\n", argv[0], c);
return '?';
}
place++;
if (*place == ':') {
if (*scan != '\0') {
woptarg = scan;
scan = NULL;
} else if (woptind < argc) {
woptarg = argv[woptind];
woptind++;
} else {
fprintf(stderr, "%ls: option requires argument -%lc\n",
argv[0], c);
return ':';
}
}
return c;
}

4
tools/wgetopt.h Normal file
View File

@ -0,0 +1,4 @@
extern wchar_t *woptarg;
extern int woptind;
int wgetopt(int argc, wchar_t * const argv[], const wchar_t *optstring);

View File

@ -4,10 +4,10 @@ set -e
make clean make clean
make -j4 CC=i686-w64-mingw32-gcc BUILD_PROGRAMS=yes make -j4 CC=i686-w64-mingw32-gcc BUILD_PROGRAMS=yes
cp *.exe /j/exe cp -vf *.exe /j/exe/
make clean make clean
make -j4 CC=x86_64-w64-mingw32-gcc BUILD_PROGRAMS=yes make -j4 CC=x86_64-w64-mingw32-gcc BUILD_PROGRAMS=yes
cp *.exe /j/exe64 cp -vf *.exe /j/exe64/
sudo systemctl restart smbd sudo systemctl restart smbd