diff options
Diffstat (limited to 'contrib/libucl/tests')
27 files changed, 585 insertions, 20 deletions
diff --git a/contrib/libucl/tests/Makefile.am b/contrib/libucl/tests/Makefile.am index 5b17e1fb252e..055eb8bd85b0 100644 --- a/contrib/libucl/tests/Makefile.am +++ b/contrib/libucl/tests/Makefile.am @@ -1,10 +1,12 @@ -EXTRA_DIST = $(TESTS) basic schema generate.res streamline.res rcl_test.json.xz +EXTRA_DIST = $(TESTS) basic schema generate.res \ + streamline.res rcl_test.json.xz TESTS = basic.test \ generate.test \ schema.test \ + msgpack.test \ speed.test \ - streamline.test + msgpack.test TESTS_ENVIRONMENT = $(SH) \ TEST_DIR=$(top_srcdir)/tests \ TEST_OUT_DIR=$(top_builddir)/tests \ @@ -35,4 +37,9 @@ test_streamline_SOURCES = test_streamline.c test_streamline_LDADD = $(common_test_ldadd) test_streamline_CFLAGS = $(common_test_cflags) -check_PROGRAMS = test_basic test_speed test_generate test_schema test_streamline
\ No newline at end of file +test_msgpack_SOURCES = test_msgpack.c +test_msgpack_LDADD = $(common_test_ldadd) +test_msgpack_CFLAGS = $(common_test_cflags) + +check_PROGRAMS = test_basic test_speed test_generate test_schema test_streamline \ + test_msgpack
\ No newline at end of file diff --git a/contrib/libucl/tests/basic/13.in b/contrib/libucl/tests/basic/13.in index 81f03a61d286..6e31e9c4b17f 100644 --- a/contrib/libucl/tests/basic/13.in +++ b/contrib/libucl/tests/basic/13.in @@ -1,7 +1,7 @@ key = value_orig; # test glob -.include(glob=true) "${CURDIR}/include_dir/test*.conf" +.include(glob=true,something="test") "${CURDIR}/include_dir/test*.conf" .include(priority=1) "${CURDIR}/include_dir/pri1.conf" .include(priority=2) "${CURDIR}/include_dir/pri2.conf" diff --git a/contrib/libucl/tests/basic/15.in b/contrib/libucl/tests/basic/15.in new file mode 100644 index 000000000000..1329b8c7c130 --- /dev/null +++ b/contrib/libucl/tests/basic/15.in @@ -0,0 +1,24 @@ +# In this test we test include override bug + +.include(priority = 1) "${CURDIR}/15.inc" + +section = { + value = "test"; +} + +overrided = { + value = "not-to-be-shown"; +} + +/* + BUGGED UCL: + overrided { + key = "overrided"; + } + !!! So overrided has actually rewritten the previous key + section { + value { + value = "not-to-be-shown"; + } + } +*/ diff --git a/contrib/libucl/tests/basic/15.inc b/contrib/libucl/tests/basic/15.inc new file mode 100644 index 000000000000..a9ab027351e6 --- /dev/null +++ b/contrib/libucl/tests/basic/15.inc @@ -0,0 +1,3 @@ +overrided { + key = "overrided"; +} diff --git a/contrib/libucl/tests/basic/15.res b/contrib/libucl/tests/basic/15.res new file mode 100644 index 000000000000..b6b4e2656d6d --- /dev/null +++ b/contrib/libucl/tests/basic/15.res @@ -0,0 +1,7 @@ +overrided { + key = "overrided"; +} +section { + value = "test"; +} + diff --git a/contrib/libucl/tests/basic/16.in b/contrib/libucl/tests/basic/16.in new file mode 100644 index 000000000000..07122528a32e --- /dev/null +++ b/contrib/libucl/tests/basic/16.in @@ -0,0 +1,12 @@ +.include(priority = 1) "${CURDIR}/16.inc" + +section = { + value = "test"; +} + +overrided = { + value = "not-to-be-shown"; +} +overrided = { + value2 = "implicit-array"; +} diff --git a/contrib/libucl/tests/basic/16.inc b/contrib/libucl/tests/basic/16.inc new file mode 100644 index 000000000000..34b6085c3fac --- /dev/null +++ b/contrib/libucl/tests/basic/16.inc @@ -0,0 +1,3 @@ +overrided { + key = "overrided"; +} diff --git a/contrib/libucl/tests/basic/16.res b/contrib/libucl/tests/basic/16.res new file mode 100644 index 000000000000..b6b4e2656d6d --- /dev/null +++ b/contrib/libucl/tests/basic/16.res @@ -0,0 +1,7 @@ +overrided { + key = "overrided"; +} +section { + value = "test"; +} + diff --git a/contrib/libucl/tests/basic/17.in b/contrib/libucl/tests/basic/17.in new file mode 100644 index 000000000000..bae66fb32eca --- /dev/null +++ b/contrib/libucl/tests/basic/17.in @@ -0,0 +1,2 @@ +# issue 74 +string that ends in slash\
\ No newline at end of file diff --git a/contrib/libucl/tests/basic/17.res b/contrib/libucl/tests/basic/17.res new file mode 100644 index 000000000000..9870b04035a9 --- /dev/null +++ b/contrib/libucl/tests/basic/17.res @@ -0,0 +1,2 @@ +string = "that ends in slash\\"; + diff --git a/contrib/libucl/tests/basic/18.in b/contrib/libucl/tests/basic/18.in new file mode 100644 index 000000000000..bd12c019859a --- /dev/null +++ b/contrib/libucl/tests/basic/18.in @@ -0,0 +1,10 @@ +defaults { + key = "val" + foo = "bar" + many = "values here" +} + +mything { + .inherit "defaults" + key = "newval" +} diff --git a/contrib/libucl/tests/basic/18.res b/contrib/libucl/tests/basic/18.res new file mode 100644 index 000000000000..a6272d508ac5 --- /dev/null +++ b/contrib/libucl/tests/basic/18.res @@ -0,0 +1,11 @@ +defaults { + key = "val"; + foo = "bar"; + many = "values here"; +} +mything { + key = "newval"; + foo = "bar"; + many = "values here"; +} + diff --git a/contrib/libucl/tests/basic/19-append.inc b/contrib/libucl/tests/basic/19-append.inc new file mode 100644 index 000000000000..909dfceb951c --- /dev/null +++ b/contrib/libucl/tests/basic/19-append.inc @@ -0,0 +1,8 @@ +okey_append = { + key = value1; + key1 = value2 +} + +akey_append = ["value3"]; + +skey_append = "value4"; diff --git a/contrib/libucl/tests/basic/19-merge.inc b/contrib/libucl/tests/basic/19-merge.inc new file mode 100644 index 000000000000..46deccbf7254 --- /dev/null +++ b/contrib/libucl/tests/basic/19-merge.inc @@ -0,0 +1,8 @@ +okey_merge = { + key = value1; + key1 = value2; +} + +akey_merge = ["value3"]; + +skey_merge = "value4"; diff --git a/contrib/libucl/tests/basic/19-rewrite.inc b/contrib/libucl/tests/basic/19-rewrite.inc new file mode 100644 index 000000000000..5a7094b0592d --- /dev/null +++ b/contrib/libucl/tests/basic/19-rewrite.inc @@ -0,0 +1,8 @@ +okey_rewrite = { + key = value1; + key1 = value2; +} + +akey_rewrite = ["value3"]; + +skey_rewrite = "value4"; diff --git a/contrib/libucl/tests/basic/19.in b/contrib/libucl/tests/basic/19.in new file mode 100644 index 000000000000..717aed819262 --- /dev/null +++ b/contrib/libucl/tests/basic/19.in @@ -0,0 +1,28 @@ +okey_append = { + key = value; +} + +akey_append = ["value"]; + +skey_append = "value"; + +okey_merge = { + key = value; + source = original; +} + +akey_merge = ["value"]; + +skey_merge = "value"; + +okey_rewrite = { + key = value; +} + +akey_rewrite = ["value"]; + +skey_rewrite = "value"; + +.include(duplicate="append") "${CURDIR}/19-append.inc" +.include(duplicate="merge") "${CURDIR}/19-merge.inc" +.include(duplicate="rewrite") "${CURDIR}/19-rewrite.inc" diff --git a/contrib/libucl/tests/basic/19.res b/contrib/libucl/tests/basic/19.res new file mode 100644 index 000000000000..ca7bc4106115 --- /dev/null +++ b/contrib/libucl/tests/basic/19.res @@ -0,0 +1,36 @@ +okey_append { + key = "value"; +} +okey_append { + key = "value1"; + key1 = "value2"; +} +akey_append [ + "value", +] +akey_append [ + "value3", +] +skey_append = "value"; +skey_append = "value4"; +okey_merge { + key = "value"; + key = "value1"; + source = "original"; + key1 = "value2"; +} +akey_merge [ + "value", + "value3", +] +skey_merge = "value"; +skey_merge = "value4"; +okey_rewrite { + key = "value1"; + key1 = "value2"; +} +akey_rewrite [ + "value3", +] +skey_rewrite = "value4"; + diff --git a/contrib/libucl/tests/basic/20.in b/contrib/libucl/tests/basic/20.in new file mode 100644 index 000000000000..f9d4088fc20c --- /dev/null +++ b/contrib/libucl/tests/basic/20.in @@ -0,0 +1,2 @@ +# issue 112 +[[0
\ No newline at end of file diff --git a/contrib/libucl/tests/basic/20.res b/contrib/libucl/tests/basic/20.res new file mode 100644 index 000000000000..abfbbf02cfe6 --- /dev/null +++ b/contrib/libucl/tests/basic/20.res @@ -0,0 +1,5 @@ +[ + [ + 0, + ] +] diff --git a/contrib/libucl/tests/basic/21.in b/contrib/libucl/tests/basic/21.in new file mode 100644 index 000000000000..8f4b328548bb --- /dev/null +++ b/contrib/libucl/tests/basic/21.in @@ -0,0 +1,2 @@ + [9 +{0 [[0
\ No newline at end of file diff --git a/contrib/libucl/tests/basic/21.res b/contrib/libucl/tests/basic/21.res new file mode 100644 index 000000000000..db091ce39354 --- /dev/null +++ b/contrib/libucl/tests/basic/21.res @@ -0,0 +1,10 @@ +[ + 9, + { + 0 [ + [ + 0, + ] + ] + } +] diff --git a/contrib/libucl/tests/basic/22.in b/contrib/libucl/tests/basic/22.in new file mode 100644 index 000000000000..244cea0b0c73 --- /dev/null +++ b/contrib/libucl/tests/basic/22.in @@ -0,0 +1,2 @@ +# issue 113 +ÿ=1
\ No newline at end of file diff --git a/contrib/libucl/tests/basic/22.res b/contrib/libucl/tests/basic/22.res new file mode 100644 index 000000000000..d4bf94d896a1 --- /dev/null +++ b/contrib/libucl/tests/basic/22.res @@ -0,0 +1,2 @@ +ÿ = 1; + diff --git a/contrib/libucl/tests/msgpack.test b/contrib/libucl/tests/msgpack.test new file mode 100755 index 000000000000..67a3c9359b1b --- /dev/null +++ b/contrib/libucl/tests/msgpack.test @@ -0,0 +1,3 @@ +#!/bin/sh + +${TEST_BINARY_DIR}/test_msgpack
\ No newline at end of file diff --git a/contrib/libucl/tests/test_basic.c b/contrib/libucl/tests/test_basic.c index 5859c0ba6eb7..45a9c8b2bc6a 100644 --- a/contrib/libucl/tests/test_basic.c +++ b/contrib/libucl/tests/test_basic.c @@ -27,13 +27,14 @@ int main (int argc, char **argv) { - char inbuf[8192], *test_in = NULL; + char *inbuf; struct ucl_parser *parser = NULL, *parser2 = NULL; ucl_object_t *obj; + ssize_t bufsize, r; FILE *in, *out; unsigned char *emitted = NULL; const char *fname_in = NULL, *fname_out = NULL; - int ret = 0, inlen, opt, json = 0, compact = 0, yaml = 0; + int ret = 0, opt, json = 0, compact = 0, yaml = 0; while ((opt = getopt(argc, argv, "jcy")) != -1) { switch (opt) { @@ -82,16 +83,28 @@ main (int argc, char **argv) ucl_parser_set_filevars (parser, fname_in, true); } - while (!feof (in)) { - memset (inbuf, 0, sizeof (inbuf)); - if (fread (inbuf, 1, sizeof (inbuf) - 1, in) == 0) { - break; + inbuf = malloc (BUFSIZ); + bufsize = BUFSIZ; + r = 0; + + while (!feof (in) && !ferror (in)) { + if (r == bufsize) { + inbuf = realloc (inbuf, bufsize * 2); + bufsize *= 2; + if (inbuf == NULL) { + perror ("realloc"); + exit (EXIT_FAILURE); + } } - inlen = strlen (inbuf); - test_in = malloc (inlen); - memcpy (test_in, inbuf, inlen); - ucl_parser_add_chunk (parser, (const unsigned char *)test_in, inlen); + r += fread (inbuf + r, 1, bufsize - r, in); + } + + if (ferror (in)) { + fprintf (stderr, "Failed to read the input file.\n"); + exit (EXIT_FAILURE); } + + ucl_parser_add_chunk (parser, (const unsigned char *)inbuf, r); fclose (in); if (fname_out != NULL) { @@ -103,12 +116,15 @@ main (int argc, char **argv) else { out = stdout; } + if (ucl_parser_get_error (parser) != NULL) { fprintf (out, "Error occurred: %s\n", ucl_parser_get_error(parser)); ret = 1; goto end; } + obj = ucl_parser_get_object (parser); + if (json) { if (compact) { emitted = ucl_object_emit (obj, UCL_EMIT_JSON_COMPACT); @@ -123,6 +139,7 @@ main (int argc, char **argv) else { emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG); } + ucl_parser_free (parser); ucl_object_unref (obj); parser2 = ucl_parser_new (UCL_PARSER_KEY_LOWERCASE); @@ -134,9 +151,11 @@ main (int argc, char **argv) ret = 1; goto end; } + if (emitted != NULL) { free (emitted); } + obj = ucl_parser_get_object (parser2); if (json) { if (compact) { @@ -163,8 +182,8 @@ end: if (parser2 != NULL) { ucl_parser_free (parser2); } - if (test_in != NULL) { - free (test_in); + if (inbuf != NULL) { + free (inbuf); } fclose (out); diff --git a/contrib/libucl/tests/test_msgpack.c b/contrib/libucl/tests/test_msgpack.c new file mode 100644 index 000000000000..dd5860e9828b --- /dev/null +++ b/contrib/libucl/tests/test_msgpack.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2015, Vsevolod Stakhov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ucl.h" +#include "ucl_internal.h" +#include <ctype.h> + +static const int niter = 1000; +static const int ntests = 100; +static const int nelt = 10; + +static int recursion = 0; + +typedef ucl_object_t* (*ucl_msgpack_test)(void); + +static ucl_object_t* ucl_test_integer (void); +static ucl_object_t* ucl_test_string (void); +static ucl_object_t* ucl_test_boolean (void); +static ucl_object_t* ucl_test_map (void); +static ucl_object_t* ucl_test_array (void); + +ucl_msgpack_test tests[] = { + ucl_test_integer, + ucl_test_string, + ucl_test_boolean, + ucl_test_map, + ucl_test_array, +}; + +#define NTESTS (sizeof(tests) / sizeof(tests[0])) + +typedef struct +{ + uint64_t state; + uint64_t inc; +} pcg32_random_t; + +pcg32_random_t rng; + +/* + * From http://www.pcg-random.org/ + */ +static uint32_t +pcg32_random (void) +{ + uint64_t oldstate = rng.state; + + rng.state = oldstate * 6364136223846793005ULL + (rng.inc | 1); + uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u; + uint32_t rot = oldstate >> 59u; + return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); +} + +static const char * +random_key (size_t *lenptr) +{ + static char keybuf[512]; + int keylen, i; + char c; + + keylen = pcg32_random () % (sizeof (keybuf) - 1) + 1; + + for (i = 0; i < keylen; i ++) { + do { + c = pcg32_random () & 0xFF; + } while (!isgraph (c)); + + keybuf[i] = c; + } + + *lenptr = keylen; + return keybuf; +} + +int +main (int argc, char **argv) +{ + int fd, i, j; + uint32_t sel; + ucl_object_t *obj, *elt; + struct ucl_parser *parser; + size_t klen, elen, elen2; + const char *key; + unsigned char *emitted, *emitted2; + FILE *out; + const char *fname_out = NULL; + + switch (argc) { + case 2: + fname_out = argv[1]; + break; + } + + /* Seed prng */ + fd = open ("/dev/urandom", O_RDONLY); + assert (fd != -1); + assert (read (fd, &rng, sizeof (rng)) == sizeof (rng)); + close (fd); + + for (i = 0; i < niter; i ++) { + if (fname_out != NULL) { + out = fopen (fname_out, "w"); + if (out == NULL) { + exit (-errno); + } + } + else { + out = NULL; + } + + /* Generate phase */ + obj = ucl_object_typed_new (UCL_OBJECT); + + for (j = 0; j < ntests; j ++) { + sel = pcg32_random () % NTESTS; + + key = random_key (&klen); + recursion = 0; + elt = tests[sel](); + assert (elt != NULL); + assert (klen != 0); + + ucl_object_insert_key (obj, elt, key, klen, true); + } + + emitted = ucl_object_emit_len (obj, UCL_EMIT_MSGPACK, &elen); + + assert (emitted != NULL); + + if (out) { + fprintf (out, "%*.s\n", (int)elen, emitted); + + fclose (out); + } + ucl_object_unref (obj); + + parser = ucl_parser_new (0); + + if (!ucl_parser_add_chunk_full (parser, emitted, elen, 0, + UCL_DUPLICATE_APPEND, UCL_PARSE_MSGPACK)) { + fprintf (stderr, "error parsing input: %s", + ucl_parser_get_error (parser)); + assert (0); + } + + obj = ucl_parser_get_object (parser); + assert (obj != NULL); + + emitted2 = ucl_object_emit_len (obj, UCL_EMIT_MSGPACK, &elen2); + + assert (emitted2 != NULL); + assert (elen2 == elen); + assert (memcmp (emitted, emitted2, elen) == 0); + + ucl_parser_free (parser); + ucl_object_unref (obj); + free (emitted); + free (emitted2); + } + + return 0; +} + + +static ucl_object_t* +ucl_test_integer (void) +{ + ucl_object_t *res; + int count, i; + uint64_t cur; + + res = ucl_object_typed_new (UCL_ARRAY); + count = pcg32_random () % nelt; + + for (i = 0; i < count; i ++) { + cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random (); + ucl_array_append (res, ucl_object_fromint (cur % 128)); + cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random (); + ucl_array_append (res, ucl_object_fromint (-cur % 128)); + cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random (); + ucl_array_append (res, ucl_object_fromint (cur % 65536)); + cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random (); + ucl_array_append (res, ucl_object_fromint (cur % INT32_MAX)); + cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random (); + ucl_array_append (res, ucl_object_fromint (cur)); + } + + return res; +} + +static ucl_object_t* +ucl_test_string (void) +{ + ucl_object_t *res, *elt; + int count, i; + uint32_t cur_len; + char *str; + + res = ucl_object_typed_new (UCL_ARRAY); + count = pcg32_random () % nelt; + + for (i = 0; i < count; i ++) { + while ((cur_len = pcg32_random ()) % 128 == 0); + + str = malloc (cur_len % 128); + ucl_array_append (res, ucl_object_fromstring_common (str, cur_len % 128, + UCL_STRING_RAW)); + free (str); + + while ((cur_len = pcg32_random ()) % 512 == 0); + str = malloc (cur_len % 512); + ucl_array_append (res, ucl_object_fromstring_common (str, cur_len % 512, + UCL_STRING_RAW)); + free (str); + + while ((cur_len = pcg32_random ()) % 128 == 0); + str = malloc (cur_len % 128); + elt = ucl_object_fromstring_common (str, cur_len % 128, + UCL_STRING_RAW); + elt->flags |= UCL_OBJECT_BINARY; + ucl_array_append (res, elt); + free (str); + + while ((cur_len = pcg32_random ()) % 512 == 0); + str = malloc (cur_len % 512); + elt = ucl_object_fromstring_common (str, cur_len % 512, + UCL_STRING_RAW); + elt->flags |= UCL_OBJECT_BINARY; + ucl_array_append (res, elt); + free (str); + } + + return res; +} + +static ucl_object_t* +ucl_test_boolean (void) +{ + ucl_object_t *res; + int count, i; + + res = ucl_object_typed_new (UCL_ARRAY); + count = pcg32_random () % nelt; + + for (i = 0; i < count; i ++) { + ucl_array_append (res, ucl_object_frombool (pcg32_random () % 2)); + } + + return res; +} + +static ucl_object_t* +ucl_test_map (void) +{ + ucl_object_t *res, *cur; + int count, i; + uint32_t cur_len, sel; + size_t klen; + const char *key; + + res = ucl_object_typed_new (UCL_OBJECT); + count = pcg32_random () % nelt; + + recursion ++; + + for (i = 0; i < count; i ++) { + + if (recursion > 10) { + sel = pcg32_random () % (NTESTS - 2); + } + else { + sel = pcg32_random () % NTESTS; + } + + key = random_key (&klen); + cur = tests[sel](); + assert (cur != NULL); + assert (klen != 0); + + ucl_object_insert_key (res, cur, key, klen, true); + + /* Multi value key */ + cur = tests[sel](); + assert (cur != NULL); + + ucl_object_insert_key (res, cur, key, klen, true); + } + + return res; +} + +static ucl_object_t* +ucl_test_array (void) +{ + ucl_object_t *res, *cur; + int count, i; + uint32_t cur_len, sel; + + res = ucl_object_typed_new (UCL_ARRAY); + count = pcg32_random () % nelt; + + recursion ++; + + for (i = 0; i < count; i ++) { + if (recursion > 10) { + sel = pcg32_random () % (NTESTS - 2); + } + else { + sel = pcg32_random () % NTESTS; + } + + cur = tests[sel](); + assert (cur != NULL); + + ucl_array_append (res, cur); + } + + return res; +} diff --git a/contrib/libucl/tests/test_schema.c b/contrib/libucl/tests/test_schema.c index 4f075dae8d68..39eb7f399125 100644 --- a/contrib/libucl/tests/test_schema.c +++ b/contrib/libucl/tests/test_schema.c @@ -40,20 +40,24 @@ read_stdin (char **buf) p = *buf; remain = size; - while ((ret = read (STDIN_FILENO, p, remain)) > 0) { + while ((ret = read (STDIN_FILENO, p, remain - 1)) > 0) { remain -= ret; p += ret; - if (remain == 0) { + + if (remain <= 1) { *buf = realloc (*buf, size * 2); if (*buf == NULL) { return -1; } - p = *buf + size; - remain = size; + + p = *buf + size - 1; + remain = size + 1; size *= 2; } } + *p = '\0'; + return ret; } |