mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Add function for creating hex string literals
This commit is contained in:
parent
aeeb851422
commit
1f766a332f
14 changed files with 250 additions and 112 deletions
|
@ -39,15 +39,17 @@
|
|||
* @param l is byte length of `s`
|
||||
* @return bytes appended (always `l`) or -1 if `ENOMEM`
|
||||
* @see appendz(b).i to get buffer length
|
||||
* @note 20% faster than appends()
|
||||
*/
|
||||
ssize_t appendd(char **b, const void *s, size_t l) {
|
||||
char *p;
|
||||
size_t n;
|
||||
struct appendz z;
|
||||
assert(b);
|
||||
z = appendz((p = *b));
|
||||
if (ROUNDUP(z.i + l + 1, 8) + W > z.n) {
|
||||
n = ROUNDUP(z.i + l + 1, 8) + W;
|
||||
if (n > z.n) {
|
||||
if (!z.n) z.n = W * 2;
|
||||
while (ROUNDUP(z.i + l + 1, 8) + W > z.n) z.n += z.n >> 1;
|
||||
while (n > z.n) z.n += z.n >> 1;
|
||||
z.n = ROUNDUP(z.n, W);
|
||||
if ((p = realloc(p, z.n))) {
|
||||
z.n = malloc_usable_size(p);
|
||||
|
@ -59,9 +61,7 @@ ssize_t appendd(char **b, const void *s, size_t l) {
|
|||
}
|
||||
*(char *)mempcpy(p + z.i, s, l) = 0;
|
||||
z.i += l;
|
||||
if (!IsTiny() && W == 8) {
|
||||
z.i |= (size_t)APPEND_COOKIE << 48;
|
||||
}
|
||||
if (!IsTiny() && W == 8) z.i |= (size_t)APPEND_COOKIE << 48;
|
||||
*(size_t *)(p + z.n - W) = z.i;
|
||||
return l;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
*
|
||||
* @return bytes appended or -1 if `ENOMEM`
|
||||
* @see appendz(b).i to get buffer length
|
||||
* @note O(1) amortized buffer growth
|
||||
*/
|
||||
ssize_t(appendf)(char **b, const char *fmt, ...) {
|
||||
int n;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
|
@ -37,35 +38,39 @@
|
|||
* free(b);
|
||||
*
|
||||
* If `i` is greater than the current length then the extra bytes are
|
||||
* filled with NUL characters.
|
||||
* filled with NUL characters. If `i` is less than the current length
|
||||
* then memory is released to the system.
|
||||
*
|
||||
* The resulting buffer is guarranteed to be NUL-terminated, i.e.
|
||||
* `!b[appendz(b).i]` will be the case.
|
||||
* `!b[appendz(b).i]` will be the case even if both params are 0.
|
||||
*
|
||||
* @return `i` or -1 if `ENOMEM`
|
||||
* @see appendz(b).i to get buffer length
|
||||
*/
|
||||
ssize_t appendr(char **b, size_t i) {
|
||||
char *p;
|
||||
size_t n;
|
||||
struct appendz z;
|
||||
assert(b);
|
||||
z = appendz((p = *b));
|
||||
z.n = ROUNDUP(i + 1, 8) + W;
|
||||
if ((p = realloc(p, z.n))) {
|
||||
z.n = malloc_usable_size(p);
|
||||
assert(!(z.n & (W - 1)));
|
||||
*b = p;
|
||||
} else {
|
||||
return -1;
|
||||
if (i != z.i || !p) {
|
||||
n = ROUNDUP(i + 1, 8) + W;
|
||||
if (n > z.n || bsrl(n) < bsrl(z.n)) {
|
||||
if ((p = realloc(p, n))) {
|
||||
n = malloc_usable_size(p);
|
||||
assert(!(n & (W - 1)));
|
||||
*b = p;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (i > z.i) {
|
||||
memset(p + z.i, 0, i - z.i + 1);
|
||||
} else {
|
||||
p[i] = 0;
|
||||
}
|
||||
*(size_t *)(p + n - W) =
|
||||
i | (!IsTiny() && W == 8 ? (size_t)APPEND_COOKIE << 48 : 0);
|
||||
}
|
||||
if (i > z.i) {
|
||||
memset(p, z.i, i - z.i);
|
||||
}
|
||||
z.i = i;
|
||||
p[z.i] = 0;
|
||||
if (!IsTiny() && W == 8) {
|
||||
z.i |= (size_t)APPEND_COOKIE << 48;
|
||||
}
|
||||
*(size_t *)(p + z.n - W) = z.i;
|
||||
return i;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
*
|
||||
* @return bytes appended (always `strlen(s)`) or -1 if `ENOMEM`
|
||||
* @see appendz(b).i to get buffer length
|
||||
* @note 2x faster than appendf()
|
||||
*/
|
||||
ssize_t appends(char **b, const char *s) {
|
||||
return appendd(b, s, strlen(s));
|
||||
|
|
|
@ -16,18 +16,23 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
|
||||
#define W sizeof(size_t)
|
||||
|
||||
/**
|
||||
* Appends character or word-encoded string to buffer.
|
||||
*
|
||||
* Up to eight characters can be appended. For example:
|
||||
*
|
||||
* appendw(&s, 'h'|'i'<<8);
|
||||
* appendw(&s, READ64LE("hi\0\0\0\0\0"));
|
||||
*
|
||||
* Is equivalent to:
|
||||
* Are equivalent to:
|
||||
*
|
||||
* appends(&s, "hi");
|
||||
*
|
||||
|
@ -37,15 +42,40 @@
|
|||
*
|
||||
* Will append a single NUL character.
|
||||
*
|
||||
* This function is slightly faster than appendd() and appends(). Its
|
||||
* main advantage is it improves code size in functions that call it.
|
||||
*
|
||||
* The resulting buffer is guaranteed to be NUL-terminated, i.e.
|
||||
* `!b[appendz(b).i]` will be the case.
|
||||
*
|
||||
* @return bytes appended or -1 if `ENOMEM`
|
||||
* @see appendz(b).i to get buffer length
|
||||
*/
|
||||
ssize_t appendw(char **b, uint64_t w) {
|
||||
char t[8];
|
||||
unsigned n = 1;
|
||||
WRITE64LE(t, w);
|
||||
if (w) n += bsrl(w) >> 3;
|
||||
return appendd(b, t, n);
|
||||
size_t n;
|
||||
unsigned l;
|
||||
char *p, *q;
|
||||
struct appendz z;
|
||||
z = appendz((p = *b));
|
||||
l = w ? (bsrl(w) >> 3) + 1 : 1;
|
||||
n = ROUNDUP(z.i + 8 + 1, 8) + W;
|
||||
if (n > z.n) {
|
||||
if (!z.n) z.n = W * 2;
|
||||
while (n > z.n) z.n += z.n >> 1;
|
||||
z.n = ROUNDUP(z.n, W);
|
||||
if ((p = realloc(p, z.n))) {
|
||||
z.n = malloc_usable_size(p);
|
||||
assert(!(z.n & (W - 1)));
|
||||
*b = p;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
q = p + z.i;
|
||||
WRITE64LE(q, w);
|
||||
q[8] = 0;
|
||||
z.i += l;
|
||||
if (!IsTiny() && W == 8) z.i |= (size_t)APPEND_COOKIE << 48;
|
||||
*(size_t *)(p + z.n - W) = z.i;
|
||||
return l;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
/**
|
||||
* Returns size of append buffer.
|
||||
*
|
||||
* @param p must be 0 or have been allocated by an append*() function
|
||||
* @return i is number of bytes stored in buffer
|
||||
* @return n is number of bytes in allocation
|
||||
*/
|
||||
|
@ -36,6 +37,12 @@ struct appendz appendz(char *p) {
|
|||
assert(z.n >= W * 2 && !(z.n & (W - 1)));
|
||||
z.i = *(size_t *)(p + z.n - W);
|
||||
if (!IsTiny() && W == 8) {
|
||||
/*
|
||||
* This check should fail if an append*() function was passed a
|
||||
* pointer that was allocated manually by malloc(). Append ptrs
|
||||
* can be free()'d safely, but they need to be allocated by the
|
||||
* append library, because we write a special value to the end.
|
||||
*/
|
||||
assert((z.i >> 48) == APPEND_COOKIE);
|
||||
z.i &= 0x0000ffffffffffff;
|
||||
}
|
||||
|
|
52
libc/stdio/dumphexc.c
Normal file
52
libc/stdio/dumphexc.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/stdio/hex.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Turns data into "\x00..." string literal.
|
||||
*/
|
||||
char *DumpHexc(const char *p, size_t n, size_t *z) {
|
||||
long o;
|
||||
int i, m;
|
||||
char A[128], *q, *s = 0;
|
||||
if (n == -1) n = p ? strlen(p) : 0;
|
||||
appendw(&s, '"' | '\\' << 8 | '\n' << 16);
|
||||
for (o = 0; (m = MIN(16, n)); p += m, n -= m) {
|
||||
q = A;
|
||||
for (i = 0; i < m; ++i) {
|
||||
*q++ = '\\';
|
||||
*q++ = 'x';
|
||||
*q++ = "0123456789abcdef"[(p[i] & 0xF0) >> 4];
|
||||
*q++ = "0123456789abcdef"[(p[i] & 0x0F) >> 0];
|
||||
}
|
||||
if (o) appendw(&s, '\\' | '\n' << 8);
|
||||
appendd(&s, A, q - A);
|
||||
o += m;
|
||||
}
|
||||
if (appendw(&s, '"') != -1) {
|
||||
if (z) *z = appendz(s).i;
|
||||
return s;
|
||||
} else {
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
}
|
11
libc/stdio/hex.internal.h
Normal file
11
libc/stdio/hex.internal.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_STDIO_HEX_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_STDIO_HEX_INTERNAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
char *DumpHex(const char *, size_t, size_t *);
|
||||
char *DumpHexc(const char *, size_t, size_t *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_STDIO_HEX_INTERNAL_H_ */
|
|
@ -57,7 +57,7 @@ o/$(MODE)/libc/stdio/fputc.o: \
|
|||
|
||||
o//libc/stdio/appendw.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-O2
|
||||
-Os
|
||||
|
||||
LIBC_STDIO_LIBS = $(foreach x,$(LIBC_STDIO_ARTIFACTS),$($(x)))
|
||||
LIBC_STDIO_SRCS = $(foreach x,$(LIBC_STDIO_ARTIFACTS),$($(x)_SRCS))
|
||||
|
|
|
@ -30,14 +30,16 @@
|
|||
ssize_t(vappendf)(char **b, const char *f, va_list v) {
|
||||
char *p;
|
||||
int r, s;
|
||||
size_t n;
|
||||
va_list w;
|
||||
struct appendz z;
|
||||
z = appendz((p = *b));
|
||||
va_copy(w, v);
|
||||
if ((r = (vsnprintf)(p + z.i, z.n ? z.n - W - z.i : 0, f, v)) >= 0) {
|
||||
if (ROUNDUP(z.i + r + 1, 8) + W > z.n) {
|
||||
n = ROUNDUP(z.i + r + 1, 8) + W;
|
||||
if (n > z.n) {
|
||||
if (!z.n) z.n = W * 2;
|
||||
while (ROUNDUP(z.i + r + 1, 8) + W > z.n) z.n += z.n >> 1;
|
||||
while (n > z.n) z.n += z.n >> 1;
|
||||
z.n = ROUNDUP(z.n, W);
|
||||
if ((p = realloc(p, z.n))) {
|
||||
z.n = malloc_usable_size(p);
|
||||
|
|
|
@ -1,27 +1,28 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BENCH_H_
|
||||
#define COSMOPOLITAN_LIBC_BENCH_H_
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/nexgen32e/bench.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview Microbenchmarking tools.
|
||||
* @fileoverview Microbenchmarking Toolz.
|
||||
*/
|
||||
|
||||
#ifndef BENCHLOOP
|
||||
#define BENCHLOOP(START, STOP, N, INIT, EXPR) \
|
||||
({ \
|
||||
unsigned long Iter, Count; \
|
||||
double Average, Sample, Time1, Time2; \
|
||||
for (Average = 1, Iter = 1, Count = (N); Iter < Count; ++Iter) { \
|
||||
INIT; \
|
||||
Time1 = START(); \
|
||||
EXPR; \
|
||||
Time2 = STOP(); \
|
||||
Sample = Time2 - Time1; \
|
||||
Average += 1. / Iter * (Sample - Average); \
|
||||
} \
|
||||
Average; \
|
||||
#define BENCHLOOP(START, STOP, N, INIT, EXPR) \
|
||||
({ \
|
||||
unsigned long Iter, Count; \
|
||||
uint64_t Time1, Time2; \
|
||||
double Average; \
|
||||
for (Average = 1, Iter = 1, Count = (N); Iter < Count; ++Iter) { \
|
||||
INIT; \
|
||||
Time1 = START(); \
|
||||
EXPR; \
|
||||
Time2 = STOP(); \
|
||||
Average += 1. / Iter * (unsignedsubtract(Time2, Time1) - Average); \
|
||||
} \
|
||||
Average; \
|
||||
})
|
||||
#endif /* BENCHLOOP */
|
||||
|
||||
|
|
34
test/libc/stdio/dumphexc_test.c
Normal file
34
test/libc/stdio/dumphexc_test.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/hex.internal.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
TEST(DumpHexc, test) {
|
||||
EXPECT_STREQ("\"\\\n\
|
||||
\\x68\\x65\\x6c\\x6c\\x6f\\xe2\\x86\\x92\\x0a\\x01\\x02\\x74\\x68\\x65\\x65\\x72\\\n\
|
||||
\\x68\\x75\\x72\\x63\\x65\\x6f\\x61\\x68\\x72\\x63\\x75\\x6f\\x65\\x61\\x75\\x68\\\n\
|
||||
\\x63\\x72\"",
|
||||
DumpHexc("hello→\n\1\2theerhurceoahrcuoeauhcr", -1, 0));
|
||||
}
|
||||
|
||||
BENCH(DumpHexc, bench) {
|
||||
EZBENCH2("dumphexc", donothing, free(DumpHexc(kHyperion, kHyperionSize, 0)));
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
@ -87,8 +88,7 @@ TEST(appendw, test) {
|
|||
EXPECT_EQ(0, b[0]);
|
||||
EXPECT_EQ('h', b[1]);
|
||||
EXPECT_EQ(0, b[2]);
|
||||
ASSERT_NE(-1, appendw(&b, 'e' | 'l' << 8 | 'l' << 16 | 'o' << 24 |
|
||||
(uint64_t)'!' << 32));
|
||||
ASSERT_NE(-1, appendw(&b, READ64LE("ello!\0\0")));
|
||||
EXPECT_EQ(7, appendz(b).i);
|
||||
EXPECT_EQ(0, b[0]);
|
||||
EXPECT_EQ('h', b[1]);
|
||||
|
@ -101,7 +101,7 @@ TEST(appendw, test) {
|
|||
free(b);
|
||||
}
|
||||
|
||||
TEST(appendr, test) {
|
||||
TEST(appendr, testShrink_nulTerminates) {
|
||||
char *b = 0;
|
||||
ASSERT_NE(-1, appends(&b, "hello"));
|
||||
EXPECT_EQ(5, appendz(b).i);
|
||||
|
@ -121,15 +121,54 @@ TEST(appendr, test) {
|
|||
free(b);
|
||||
}
|
||||
|
||||
TEST(appendr, testExtend_zeroFills) {
|
||||
char *b = 0;
|
||||
ASSERT_NE(-1, appends(&b, "hello"));
|
||||
EXPECT_EQ(5, appendz(b).i);
|
||||
ASSERT_NE(-1, appendr(&b, 20));
|
||||
EXPECT_EQ(20, appendz(b).i);
|
||||
ASSERT_BINEQ(u"hello ", b);
|
||||
ASSERT_NE(-1, appendr(&b, 20));
|
||||
EXPECT_EQ(20, appendz(b).i);
|
||||
ASSERT_BINEQ(u"hello ", b);
|
||||
free(b);
|
||||
}
|
||||
|
||||
TEST(appendr, testAbsent_allocatesNul) {
|
||||
char *b = 0;
|
||||
ASSERT_NE(-1, appendr(&b, 0));
|
||||
EXPECT_EQ(0, appendz(b).i);
|
||||
ASSERT_BINEQ(u" ", b);
|
||||
free(b);
|
||||
}
|
||||
|
||||
TEST(appendd, testMemFail_doesntInitializePointer) {
|
||||
char *b = 0;
|
||||
ASSERT_EQ(-1, appendd(&b, 0, -1ull >> 8));
|
||||
EXPECT_EQ(0, b);
|
||||
}
|
||||
|
||||
TEST(appendd, testMemFail_doesntFreeExistingAllocation) {
|
||||
char *b = 0;
|
||||
ASSERT_NE(-1, appends(&b, "hello"));
|
||||
EXPECT_STREQ("hello", b);
|
||||
ASSERT_EQ(-1, appendd(&b, 0, -1ull >> 8));
|
||||
EXPECT_STREQ("hello", b);
|
||||
free(b);
|
||||
}
|
||||
|
||||
BENCH(vappendf, bench) {
|
||||
const char t[] = {0};
|
||||
char *b = 0;
|
||||
EZBENCH2("appendf", donothing, appendf(&b, "1"));
|
||||
EZBENCH2("appendf", donothing, appendf(&b, "hello"));
|
||||
free(b), b = 0;
|
||||
EZBENCH2("appends", donothing, appends(&b, "1"));
|
||||
EZBENCH2("appends", donothing, appends(&b, "hello"));
|
||||
free(b), b = 0;
|
||||
EZBENCH2("appendw", donothing, appendw(&b, 'B'));
|
||||
EZBENCH2("appendw", donothing,
|
||||
appendw(&b, 'h' | 'e' << 8 | 'l' << 16 | 'l' << 24 |
|
||||
(uint64_t)'o' << 32));
|
||||
free(b), b = 0;
|
||||
EZBENCH2("appendd", donothing, appendd(&b, t, 1));
|
||||
EZBENCH2("appendd", donothing, appendd(&b, "hello", 5));
|
||||
EZBENCH2("appendr", donothing, appendr(&b, 0));
|
||||
free(b), b = 0;
|
||||
}
|
||||
|
|
|
@ -18,75 +18,30 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/stdio/hex.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
struct Append {
|
||||
size_t i, n;
|
||||
char *p;
|
||||
};
|
||||
|
||||
int AppendFmt(struct Append *b, const char *fmt, ...) {
|
||||
int n;
|
||||
char *p;
|
||||
va_list va, vb;
|
||||
va_start(va, fmt);
|
||||
va_copy(vb, va);
|
||||
n = vsnprintf(b->p + b->i, b->n - b->i, fmt, va);
|
||||
if (n >= b->n - b->i) {
|
||||
do {
|
||||
if (b->n) {
|
||||
b->n += b->n >> 1; /* this is the important line */
|
||||
} else {
|
||||
b->n = 16;
|
||||
}
|
||||
} while (b->i + n + 1 > b->n);
|
||||
b->p = realloc(b->p, b->n);
|
||||
vsnprintf(b->p + b->i, b->n - b->i, fmt, vb);
|
||||
}
|
||||
va_end(vb);
|
||||
va_end(va);
|
||||
b->i += n;
|
||||
return n;
|
||||
}
|
||||
|
||||
char *DumpHexc(const char *data, size_t size, size_t *z) {
|
||||
long o;
|
||||
int b, i, n;
|
||||
char A[128], *p;
|
||||
struct Append buf;
|
||||
if (size == -1) size = data ? strlen(data) : 0;
|
||||
buf.i = 0;
|
||||
buf.n = 256;
|
||||
buf.p = calloc(1, 256);
|
||||
AppendFmt(&buf, "\"\\\n");
|
||||
for (b = o = 0; (n = MIN(16, size)); data += n, size -= n) {
|
||||
p = A;
|
||||
for (i = 0; i < n; ++i) {
|
||||
*p++ = '\\';
|
||||
*p++ = 'x';
|
||||
*p++ = "0123456789abcdef"[(data[i] & 0xF0) >> 4];
|
||||
*p++ = "0123456789abcdef"[(data[i] & 0x0F) >> 0];
|
||||
}
|
||||
if (o) AppendFmt(&buf, "\\\n");
|
||||
AppendFmt(&buf, "%.*s", p - A, A);
|
||||
o += n;
|
||||
}
|
||||
AppendFmt(&buf, "\"");
|
||||
if (z) *z = buf.i;
|
||||
return buf.p;
|
||||
}
|
||||
/**
|
||||
* @fileoverview Hex String Literal Converter, e.g.
|
||||
*
|
||||
* $ echo hello | o/tool/viz/dumphexc.com
|
||||
* "\
|
||||
* \x68\x65\x6c\x6c\x6f\x0a"
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char *p;
|
||||
size_t n, g;
|
||||
char *b = 0;
|
||||
char buf[512];
|
||||
struct Append b = {0};
|
||||
while ((g = fread(buf, 1, sizeof(buf), stdin))) {
|
||||
AppendFmt(&b, "%.*s", g, buf);
|
||||
appendd(&b, buf, g);
|
||||
}
|
||||
if (!ferror(stdin)) {
|
||||
p = DumpHexc(b.p, b.i, &n);
|
||||
p = DumpHexc(b, appendz(b).i, &n);
|
||||
fwrite(p, 1, n, stdout);
|
||||
free(p);
|
||||
}
|
||||
printf("\n");
|
||||
return ferror(stdin) || ferror(stdout) ? 1 : 0;
|
||||
|
|
Loading…
Reference in a new issue