| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,7 +17,7 @@ if (POLICY CMP0127) | |||
| 17 | 17 | cmake_policy(SET CMP0127 NEW) | |
| 18 | 18 | endif() | |
| 19 | 19 | ||
| 20 | - project(base64 LANGUAGES C VERSION 0.5.1) | ||
| 20 | + project(base64 LANGUAGES C VERSION 0.5.2) | ||
| 21 | 21 | ||
| 22 | 22 | include(GNUInstallDirs) | |
| 23 | 23 | include(CMakeDependentOption) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,4 @@ | |||
| 1 | - CFLAGS += -std=c99 -O3 -Wall -Wextra -pedantic | ||
| 1 | + CFLAGS += -std=c99 -O3 -Wall -Wextra -pedantic -DBASE64_STATIC_DEFINE | ||
| 2 | 2 | ||
| 3 | 3 | # Set OBJCOPY if not defined by environment: | |
| 4 | 4 | OBJCOPY ?= objcopy | |
@@ -56,6 +56,7 @@ ifdef OPENMP | |||
| 56 | 56 | CFLAGS += -fopenmp | |
| 57 | 57 | endif | |
| 58 | 58 | ||
| 59 | + TARGET := $(shell $(CC) -dumpmachine) | ||
| 59 | 60 | ||
| 60 | 61 | .PHONY: all analyze clean | |
| 61 | 62 | ||
@@ -64,9 +65,17 @@ all: bin/base64 lib/libbase64.o | |||
| 64 | 65 | bin/base64: bin/base64.o lib/libbase64.o | |
| 65 | 66 | $(CC) $(CFLAGS) -o $@ $^ | |
| 66 | 67 | ||
| 67 | - lib/libbase64.o: $(OBJS) | ||
| 68 | - $(LD) -r -o $@ $^ | ||
| 69 | - $(OBJCOPY) --keep-global-symbols=lib/exports.txt $@ | ||
| 68 | + # Workaround: mangle exported function names on MinGW32. | ||
| 69 | + lib/exports.build.txt: lib/exports.txt | ||
| 70 | + ifeq (i686-w64-mingw32, $(TARGET)) | ||
| 71 | + sed -e 's/^/_/' $< > $@ | ||
| 72 | + else | ||
| 73 | + cp -f $< $@ | ||
| 74 | + endif | ||
| 75 | + | ||
| 76 | + lib/libbase64.o: lib/exports.build.txt $(OBJS) | ||
| 77 | + $(LD) -r -o $@ $(OBJS) | ||
| 78 | + $(OBJCOPY) --keep-global-symbols=$< $@ | ||
| 70 | 79 | ||
| 71 | 80 | lib/config.h: | |
| 72 | 81 | @echo "#define HAVE_AVX512 $(HAVE_AVX512)" > $@ | |
@@ -97,4 +106,4 @@ analyze: clean | |||
| 97 | 106 | scan-build --use-analyzer=`which clang` --status-bugs make | |
| 98 | 107 | ||
| 99 | 108 | clean: | |
| 100 | - rm -f bin/base64 bin/base64.o lib/libbase64.o lib/config.h $(OBJS) | ||
| 109 | + rm -f bin/base64 bin/base64.o lib/libbase64.o lib/config.h lib/exports.build.txt $(OBJS) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,19 @@ | |||
| 1 | - #define _XOPEN_SOURCE // IOV_MAX | ||
| 1 | + // Test for MinGW. | ||
| 2 | + #if defined(__MINGW32__) || defined(__MINGW64__) | ||
| 3 | + # define MINGW | ||
| 4 | + #endif | ||
| 5 | + | ||
| 6 | + // Decide if the writev(2) system call needs to be emulated as a series of | ||
| 7 | + // write(2) calls. At least MinGW does not support writev(2). | ||
| 8 | + #ifdef MINGW | ||
| 9 | + # define EMULATE_WRITEV | ||
| 10 | + #endif | ||
| 11 | + | ||
| 12 | + // Include the necessary system header when using the system's writev(2). | ||
| 13 | + #ifndef EMULATE_WRITEV | ||
| 14 | + # define _XOPEN_SOURCE // Unlock IOV_MAX | ||
| 15 | + # include <sys/uio.h> | ||
| 16 | + #endif | ||
| 2 | 17 | ||
| 3 | 18 | #include <stdbool.h> | |
| 4 | 19 | #include <stdlib.h> | |
@@ -8,7 +23,7 @@ | |||
| 8 | 23 | #include <getopt.h> | |
| 9 | 24 | #include <errno.h> | |
| 10 | 25 | #include <limits.h> | |
| 11 | - #include <sys/uio.h> | ||
| 26 | + | ||
| 12 | 27 | #include "../include/libbase64.h" | |
| 13 | 28 | ||
| 14 | 29 | // Size of the buffer for the "raw" (not base64-encoded) data in bytes. | |
@@ -50,6 +65,59 @@ struct buffer { | |||
| 50 | 65 | char *enc; | |
| 51 | 66 | }; | |
| 52 | 67 | ||
| 68 | + // Optionally emulate writev(2) as a series of write calls. | ||
| 69 | + #ifdef EMULATE_WRITEV | ||
| 70 | + | ||
| 71 | + // Quick and dirty definition of IOV_MAX as it is probably not defined. | ||
| 72 | + #ifndef IOV_MAX | ||
| 73 | + # define IOV_MAX 1024 | ||
| 74 | + #endif | ||
| 75 | + | ||
| 76 | + // Quick and dirty definition of this system struct, for local use only. | ||
| 77 | + struct iovec { | ||
| 78 | + | ||
| 79 | + // Opaque data pointer. | ||
| 80 | + void *iov_base; | ||
| 81 | + | ||
| 82 | + // Length of the data in bytes. | ||
| 83 | + size_t iov_len; | ||
| 84 | + }; | ||
| 85 | + | ||
| 86 | + static ssize_t | ||
| 87 | + writev (const int fd, const struct iovec *iov, int iovcnt) | ||
| 88 | + { | ||
| 89 | + ssize_t r, nwrite = 0; | ||
| 90 | + | ||
| 91 | + // Reset the error marker. | ||
| 92 | + errno = 0; | ||
| 93 | + | ||
| 94 | + while (iovcnt-- > 0) { | ||
| 95 | + | ||
| 96 | + // Write the vector; propagate errors back to the caller. Note | ||
| 97 | + // that this loses information about how much vectors have been | ||
| 98 | + // successfully written, but that also seems to be the case | ||
| 99 | + // with the real function. The API is somewhat flawed. | ||
| 100 | + if ((r = write(fd, iov->iov_base, iov->iov_len)) < 0) { | ||
| 101 | + return r; | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + // Update the total write count. | ||
| 105 | + nwrite += r; | ||
| 106 | + | ||
| 107 | + // Return early after a partial write; the caller should retry. | ||
| 108 | + if ((size_t) r != iov->iov_len) { | ||
| 109 | + break; | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + // Move to the next vector. | ||
| 113 | + iov++; | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + return nwrite; | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + #endif // EMULATE_WRITEV | ||
| 120 | + | ||
| 53 | 121 | static bool | |
| 54 | 122 | buffer_alloc (const struct config *config, struct buffer *buf) | |
| 55 | 123 | { | |
@@ -272,29 +340,75 @@ encode (const struct config *config, struct buffer *buf) | |||
| 272 | 340 | return true; | |
| 273 | 341 | } | |
| 274 | 342 | ||
| 275 | - static int | ||
| 343 | + static inline size_t | ||
| 344 | + find_newline (const char *p, const size_t avail) | ||
| 345 | + { | ||
| 346 | + // This is very naive and can probably be improved by vectorization. | ||
| 347 | + for (size_t len = 0; len < avail; len++) { | ||
| 348 | + if (p[len] == '\n') { | ||
| 349 | + return len; | ||
| 350 | + } | ||
| 351 | + } | ||
| 352 | + | ||
| 353 | + return avail; | ||
| 354 | + } | ||
| 355 | + | ||
| 356 | + static bool | ||
| 276 | 357 | decode (const struct config *config, struct buffer *buf) | |
| 277 | 358 | { | |
| 278 | - size_t nread, nout; | ||
| 359 | + size_t avail; | ||
| 279 | 360 | struct base64_state state; | |
| 280 | 361 | ||
| 281 | 362 | // Initialize the decoder's state structure. | |
| 282 | 363 | base64_stream_decode_init(&state, 0); | |
| 283 | 364 | ||
| 284 | 365 | // Read encoded data into the buffer. Use the smallest buffer size to | |
| 285 | 366 | // be on the safe side: the decoded output will fit the raw buffer. | |
| 286 | - while ((nread = fread(buf->enc, 1, BUFFER_RAW_SIZE, config->fp)) > 0) { | ||
| 367 | + while ((avail = fread(buf->enc, 1, BUFFER_RAW_SIZE, config->fp)) > 0) { | ||
| 368 | + char *start = buf->enc; | ||
| 369 | + char *outbuf = buf->raw; | ||
| 370 | + size_t ototal = 0; | ||
| 371 | + | ||
| 372 | + // By popular demand, this utility tries to be bug-compatible | ||
| 373 | + // with GNU `base64'. That includes silently ignoring newlines | ||
| 374 | + // in the input. Tokenize the input on newline characters. | ||
| 375 | + while (avail > 0) { | ||
| 376 | + | ||
| 377 | + // Find the offset of the next newline character, which | ||
| 378 | + // is also the length of the next chunk. | ||
| 379 | + size_t outlen, len = find_newline(start, avail); | ||
| 380 | + | ||
| 381 | + // Ignore empty chunks. | ||
| 382 | + if (len == 0) { | ||
| 383 | + start++; | ||
| 384 | + avail--; | ||
| 385 | + continue; | ||
| 386 | + } | ||
| 287 | 387 | ||
| 288 | - // Decode the input into the raw buffer. | ||
| 289 | - if (base64_stream_decode(&state, buf->enc, nread, | ||
| 290 | - buf->raw, &nout) == 0) { | ||
| 291 | - fprintf(stderr, "%s: %s: decoding error\n", | ||
| 292 | - config->name, config->file); | ||
| 293 | - return false; | ||
| 388 | + // Decode the chunk into the raw buffer. | ||
| 389 | + if (base64_stream_decode(&state, start, len, | ||
| 390 | + outbuf, &outlen) == 0) { | ||
| 391 | + fprintf(stderr, "%s: %s: decoding error\n", | ||
| 392 | + config->name, config->file); | ||
| 393 | + return false; | ||
| 394 | + } | ||
| 395 | + | ||
| 396 | + // Update the output buffer pointer and total size. | ||
| 397 | + outbuf += outlen; | ||
| 398 | + ototal += outlen; | ||
| 399 | + | ||
| 400 | + // Bail out if the whole string has been consumed. | ||
| 401 | + if (len == avail) { | ||
| 402 | + break; | ||
| 403 | + } | ||
| 404 | + | ||
| 405 | + // Move the start pointer past the newline. | ||
| 406 | + start += len + 1; | ||
| 407 | + avail -= len + 1; | ||
| 294 | 408 | } | |
| 295 | 409 | ||
| 296 | 410 | // Append the raw data to the output stream. | |
| 297 | - if (write_stdout(config, buf->raw, nout) == false) { | ||
| 411 | + if (write_stdout(config, buf->raw, ototal) == false) { | ||
| 298 | 412 | return false; | |
| 299 | 413 | } | |
| 300 | 414 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,8 @@ | |||
| 1 | 1 | #ifndef BASE64_ENV_H | |
| 2 | 2 | #define BASE64_ENV_H | |
| 3 | 3 | ||
| 4 | + #include <stdint.h> | ||
| 5 | + | ||
| 4 | 6 | // This header file contains macro definitions that describe certain aspects of | |
| 5 | 7 | // the compile-time environment. Compatibility and portability macros go here. | |
| 6 | 8 | ||
@@ -46,12 +48,10 @@ | |||
| 46 | 48 | #if defined (__x86_64__) | |
| 47 | 49 | // This also works for the x32 ABI, which has a 64-bit word size. | |
| 48 | 50 | # define BASE64_WORDSIZE 64 | |
| 49 | - #elif defined (_INTEGRAL_MAX_BITS) | ||
| 50 | - # define BASE64_WORDSIZE _INTEGRAL_MAX_BITS | ||
| 51 | - #elif defined (__WORDSIZE) | ||
| 52 | - # define BASE64_WORDSIZE __WORDSIZE | ||
| 53 | - #elif defined (__SIZE_WIDTH__) | ||
| 54 | - # define BASE64_WORDSIZE __SIZE_WIDTH__ | ||
| 51 | + #elif SIZE_MAX == UINT32_MAX | ||
| 52 | + # define BASE64_WORDSIZE 32 | ||
| 53 | + #elif SIZE_MAX == UINT64_MAX | ||
| 54 | + # define BASE64_WORDSIZE 64 | ||
| 55 | 55 | #else | |
| 56 | 56 | # error BASE64_WORDSIZE_NOT_DEFINED | |
| 57 | 57 | #endif | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -32,12 +32,10 @@ add_base64_test(test_base64 | |||
| 32 | 32 | test_base64.c | |
| 33 | 33 | ) | |
| 34 | 34 | ||
| 35 | - if (NOT WIN32) | ||
| 36 | - add_base64_test(benchmark | ||
| 37 | - codec_supported.c | ||
| 38 | - benchmark.c | ||
| 39 | - ) | ||
| 40 | - endif() | ||
| 35 | + add_base64_test(benchmark | ||
| 36 | + codec_supported.c | ||
| 37 | + benchmark.c | ||
| 38 | + ) | ||
| 41 | 39 | ||
| 42 | 40 | if(CMAKE_SYSTEM_NAME STREQUAL "Linux") | |
| 43 | 41 | target_link_libraries(benchmark PRIVATE rt) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,11 +1,13 @@ | |||
| 1 | - CFLAGS += -std=c99 -O3 -Wall -Wextra -pedantic | ||
| 1 | + CFLAGS += -std=c99 -O3 -Wall -Wextra -pedantic -DBASE64_STATIC_DEFINE | ||
| 2 | 2 | ifdef OPENMP | |
| 3 | 3 | CFLAGS += -fopenmp | |
| 4 | 4 | endif | |
| 5 | 5 | ||
| 6 | 6 | TARGET := $(shell $(CC) -dumpmachine) | |
| 7 | 7 | ifneq (, $(findstring darwin, $(TARGET))) | |
| 8 | 8 | BENCH_LDFLAGS= | |
| 9 | + else ifneq (, $(findstring mingw, $(TARGET))) | ||
| 10 | + BENCH_LDFLAGS= | ||
| 9 | 11 | else | |
| 10 | 12 | # default to linux, -lrt needed | |
| 11 | 13 | BENCH_LDFLAGS=-lrt | |
| Back | FazBrowse Home | New Git URL |
0 commit comments