libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit ee3f32220038303ebf1bfcf1494c9badf6d3adc4
parent 237aebfade9f51cfb3c0071b71b8875fb9eba335
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Mon,  7 Jun 2021 19:46:46 +0300

Added internal functions for printing decimal and hex numbers

Diffstat:
Msrc/microhttpd/.gitignore | 1+
Msrc/microhttpd/Makefile.am | 4++++
Msrc/microhttpd/mhd_str.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/microhttpd/mhd_str.h | 30++++++++++++++++++++++++++++++
Msrc/microhttpd/test_str.c | 310+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 413 insertions(+), 0 deletions(-)

diff --git a/src/microhttpd/.gitignore b/src/microhttpd/.gitignore @@ -48,6 +48,7 @@ test_http_reasons /test_shutdown_select_ignore /test_str_compare /test_str_to_value +/test_str_from_value /test_upgrade /test_upgrade_ssl /test_options diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am @@ -157,6 +157,7 @@ endif check_PROGRAMS = \ test_str_compare \ test_str_to_value \ + test_str_from_value \ test_str_token \ test_str_token_remove \ test_str_tokens_remove \ @@ -358,6 +359,9 @@ test_str_compare_SOURCES = \ test_str_to_value_SOURCES = \ test_str.c test_helpers.h mhd_str.c mhd_str.h +test_str_from_value_SOURCES = \ + test_str.c test_helpers.h mhd_str.c mhd_str.h + test_str_token_SOURCES = \ test_str_token.c mhd_str.c mhd_str.h diff --git a/src/microhttpd/mhd_str.c b/src/microhttpd/mhd_str.c @@ -32,6 +32,7 @@ #include "mhd_assert.h" #include "mhd_limits.h" +#include "mhd_assert.h" #ifdef MHD_FAVOR_SMALL_CODE #ifdef _MHD_static_inline @@ -1184,3 +1185,70 @@ MHD_str_to_uvalue_n_ (const char *str, #endif /* MHD_FAVOR_SMALL_CODE */ + + +size_t +MHD_uint32_to_strx (uint32_t val, + char *buf, + size_t buf_size) +{ + char *chr; /**< pointer to the current printed digit */ + int digit_pos = 7; /** zero-based, digit position in @a 'val' */ + int digit; + + chr = buf; + digit = (int) (((val) >> (4 * digit_pos)) & 0xf); + + /* Skip leading zeros */ + while ((0 == digit) && (0 != digit_pos)) + digit = (int) (((val) >> (4 * --digit_pos)) & 0xf); + + while (0 != buf_size) + { + *chr = (digit <= 9) ? ('0' + (char) digit) : ('A' + (char) digit - 10); + chr++; + buf_size--; + if (0 == digit_pos) + return (size_t) (chr - buf); + digit = (int) (((val) >> (4 * --digit_pos)) & 0xf); + } + return 0; /* The buffer is too small */ +} + + +size_t +MHD_uint16_to_str (uint16_t val, + char *buf, + size_t buf_size) +{ + char *chr; /**< pointer to the current printed digit */ + /* The biggest printable number is 65535 */ + uint16_t divisor = UINT16_C (10000); + int digit; + + chr = buf; + digit = (int) (val / divisor); + mhd_assert (digit < 10); + + /* Do not print leading zeros */ + while ((0 == digit) && (1 < divisor)) + { + divisor /= 10; + digit = (int) (val / divisor); + mhd_assert (digit < 10); + } + + while (0 != buf_size) + { + *chr = (char) digit + '0'; + chr++; + buf_size--; + if (1 == divisor) + return (size_t) (chr - buf); + val %= divisor; + divisor /= 10; + digit = (int) (val / divisor); + mhd_assert (digit < 10); + } + return 0; /* The buffer is too small */ +} diff --git a/src/microhttpd/mhd_str.h b/src/microhttpd/mhd_str.h @@ -361,4 +361,34 @@ MHD_str_to_uvalue_n_ (const char *str, #endif /* MHD_FAVOR_SMALL_CODE */ + +/** + * Convert uint32_t value to hexdecimal US-ASCII string. + * @note: result is NOT zero-terminated. + * @param val the value to convert + * @param buf the buffer to result to + * @param buf_size size of the @a buffer + * @return number of charters has been put to the @a buf, + * zero if buffer is too small (buffer may be modified). + */ +size_t +MHD_uint32_to_strx (uint32_t val, + char *buf, + size_t buf_size); + + +/** + * Convert uint16_t value to decimal US-ASCII string. + * @note: result is NOT zero-terminated. + * @param val the value to convert + * @param buf the buffer to result to + * @param buf_size size of the @a buffer + * @return number of charters has been put to the @a buf, + * zero if buffer is too small (buffer may be modified). + */ +size_t +MHD_uint16_to_str (uint16_t val, + char *buf, + size_t buf_size); + #endif /* MHD_STR_H */ diff --git a/src/microhttpd/test_str.c b/src/microhttpd/test_str.c @@ -3315,6 +3315,313 @@ run_str_to_X_tests (void) int +check_str_from_uint16 (void) +{ + size_t t_failed = 0; + size_t i, j; + char buf[70]; + const char *erase = + "-@=sd#+&(pdiren456qwe#@C3S!DAS45AOIPUQWESAdFzxcv1s*()&#$%34`" + "32452d098poiden45SADFFDA3S4D3SDFdfgsdfgsSADFzxdvs$*()&#2342`" + "adsf##$$@&*^%*^&56qwe#3C@S!DAScFAOIP$#%#$Ad1zs3v1$*()&#1228`"; + static const size_t n_checks = sizeof(dstrs_w_values) + / sizeof(dstrs_w_values[0]); + int c_failed[n_checks]; + + memset (c_failed, 0, sizeof(c_failed)); + + for (j = 0; j < locale_name_count; j++) + { + set_test_locale (j); /* setlocale() can be slow! */ + for (i = 0; i < n_checks; i++) + { + const struct str_with_value *const t = dstrs_w_values + i; + size_t b_size; + size_t rs; + + if (c_failed[i]) + continue; /* skip already failed checks */ + + if (t->str.len < t->num_of_digt) + { + fprintf (stderr, + "ERROR: dstrs_w_values[%u] has wrong num_of_digt (%u): num_of_digt is expected" + " to be less or equal to str.len (%u).\n", + (unsigned int) i, (unsigned int) t->num_of_digt, (unsigned + int) t->str. + len); + return -1; + } + if ('0' == t->str.str[0]) + continue; /* Skip strings prefixed with zeros */ + if (t->num_of_digt != t->str.len) + continue; /* Skip strings with suffixes */ + if (UINT16_MAX < t->val) + continue; /* Too large value to convert */ + if (sizeof(buf) < t->str.len + 1) + { + fprintf (stderr, + "ERROR: dstrs_w_values[%u] has too long (%u) string, " + "size of 'buf' should be increased.\n", + (unsigned int) i, (unsigned int) t->str.len); + return -1; + } + for (b_size = 0; b_size <= t->str.len + 1; ++b_size) + { + /* fill buffer with pseudo-random values */ + memcpy (buf, erase, sizeof(buf)); + + rs = MHD_uint16_to_str (t->val, buf, b_size); + + if (t->num_of_digt > b_size) + { + /* Must fail, buffer is too small for result */ + if (0 != rs) + { + if (0 == c_failed[i]) + t_failed++; + c_failed[i] = ! 0; + fprintf (stderr, + "FAILED: MHD_uint16_to_str(%" PRIu64 ", -> buf," + " %d) returned %" PRIuPTR + ", while expecting 0." + " Locale: %s\n", t->val, (int) b_size, (intptr_t) rs, + get_current_locale_str ()); + } + } + else + { + if (t->num_of_digt != rs) + { + if (0 == c_failed[i]) + t_failed++; + c_failed[i] = ! 0; + fprintf (stderr, + "FAILED: MHD_uint16_to_str(%" PRIu64 ", -> buf," + " %d) returned %" PRIuPTR + ", while expecting %d." + " Locale: %s\n", t->val, (int) b_size, (intptr_t) rs, + (int) t->num_of_digt, get_current_locale_str ()); + } + else if (0 != memcmp (buf, t->str.str, t->num_of_digt)) + { + if (0 == c_failed[i]) + t_failed++; + c_failed[i] = ! 0; + fprintf (stderr, + "FAILED: MHD_uint16_to_str(%" PRIu64 ", -> \"%.*s\"," + " %d) returned %" PRIuPTR "." + " Locale: %s\n", t->val, (int) rs, buf, (int) b_size, + (intptr_t) rs, get_current_locale_str ()); + } + else if (0 != memcmp (buf + rs, erase + rs, sizeof(buf) - rs)) + { + if (0 == c_failed[i]) + t_failed++; + c_failed[i] = ! 0; + fprintf (stderr, + "FAILED: MHD_uint16_to_str(%" PRIu64 ", -> \"%.*s\"," + " %d) returned %" PRIuPTR + " and touched data after the resulting string." + " Locale: %s\n", t->val, (int) rs, buf, (int) b_size, + (intptr_t) rs, get_current_locale_str ()); + } + } + } + if ((verbose > 1) && (j == locale_name_count - 1) && ! c_failed[i]) + printf ("PASSED: MHD_uint16_to_str(%" PRIu64 ", -> \"%.*s\", %d) " + "== %" PRIuPTR "\n", + t->val, (int) rs, buf, (int) b_size - 1, (intptr_t) rs); + } + } + return t_failed; +} + + +int +check_strx_from_uint32 (void) +{ + size_t t_failed = 0; + size_t i, j; + char buf[70]; + const char *erase = + "jrlkjssfhjfvrjntJHLJ$@%$#adsfdkj;k$##$%#$%FGDF%$#^FDFG%$#$D`" + ";skjdhjflsdkjhdjfalskdjhdfalkjdhf$%##%$$#%FSDGFSDDGDFSSDSDF`" + "#5#$%#$#$DFSFDDFSGSDFSDF354FDDSGFDFfdssfddfswqemn,.zxih,.sx`"; + static const size_t n_checks = sizeof(xdstrs_w_values) + / sizeof(xdstrs_w_values[0]); + int c_failed[n_checks]; + + memset (c_failed, 0, sizeof(c_failed)); + + for (j = 0; j < locale_name_count; j++) + { + set_test_locale (j); /* setlocale() can be slow! */ + for (i = 0; i < n_checks; i++) + { + const struct str_with_value *const t = xdstrs_w_values + i; + size_t b_size; + size_t rs; + + if (c_failed[i]) + continue; /* skip already failed checks */ + + if (t->str.len < t->num_of_digt) + { + fprintf (stderr, + "ERROR: dstrs_w_values[%u] has wrong num_of_digt (%u): num_of_digt is expected" + " to be less or equal to str.len (%u).\n", + (unsigned int) i, (unsigned int) t->num_of_digt, (unsigned + int) t->str. + len); + return -1; + } + if ('0' == t->str.str[0]) + continue; /* Skip strings prefixed with zeros */ + if (t->num_of_digt != t->str.len) + continue; /* Skip strings with suffixes */ + if (UINT32_MAX < t->val) + continue; /* Too large value to convert */ + if (sizeof(buf) < t->str.len + 1) + { + fprintf (stderr, + "ERROR: dstrs_w_values[%u] has too long (%u) string, " + "size of 'buf' should be increased.\n", + (unsigned int) i, (unsigned int) t->str.len); + return -1; + } + for (b_size = 0; b_size <= t->str.len + 1; ++b_size) + { + /* fill buffer with pseudo-random values */ + memcpy (buf, erase, sizeof(buf)); + + rs = MHD_uint32_to_strx (t->val, buf, b_size); + + if (t->num_of_digt > b_size) + { + /* Must fail, buffer is too small for result */ + if (0 != rs) + { + if (0 == c_failed[i]) + t_failed++; + c_failed[i] = ! 0; + fprintf (stderr, + "FAILED: MHD_uint32_to_strx(0x%" PRIXPTR ", -> buf," + " %d) returned %" PRIuPTR + ", while expecting 0." + " Locale: %s\n", t->val, (int) b_size, (intptr_t) rs, + get_current_locale_str ()); + } + } + else + { + if (t->num_of_digt != rs) + { + if (0 == c_failed[i]) + t_failed++; + c_failed[i] = ! 0; + fprintf (stderr, + "FAILED: MHD_uint32_to_strx(0x%" PRIXPTR ", -> buf," + " %d) returned %" PRIuPTR + ", while expecting %d." + " Locale: %s\n", t->val, (int) b_size, (intptr_t) rs, + (int) t->num_of_digt, get_current_locale_str ()); + } + else if (0 == MHD_str_equal_caseless_bin_n_ (buf, t->str.str, + t->num_of_digt)) + { + if (0 == c_failed[i]) + t_failed++; + c_failed[i] = ! 0; + fprintf (stderr, + "FAILED: MHD_uint32_to_strx(0x%" PRIXPTR ", -> \"%.*s\"," + " %d) returned %" PRIuPTR "." + " Locale: %s\n", t->val, (int) rs, buf, (int) b_size, + (intptr_t) rs, get_current_locale_str ()); + } + else if (0 != memcmp (buf + rs, erase + rs, sizeof(buf) - rs)) + { + if (0 == c_failed[i]) + t_failed++; + c_failed[i] = ! 0; + fprintf (stderr, + "FAILED: MHD_uint32_to_strx(0x%" PRIXPTR ", -> \"%.*s\"," + " %d) returned %" PRIuPTR + " and touched data after the resulting string." + " Locale: %s\n", t->val, (int) rs, buf, (int) b_size, + (intptr_t) rs, get_current_locale_str ()); + } + } + } + if ((verbose > 1) && (j == locale_name_count - 1) && ! c_failed[i]) + printf ("PASSED: MHD_uint32_to_strx(0x%" PRIXPTR ", -> \"%.*s\", %d) " + "== %" PRIuPTR "\n", + t->val, (int) rs, buf, (int) b_size - 1, (intptr_t) rs); + } + } + return t_failed; +} + + +int +run_str_from_X_tests (void) +{ + int str_from_uint16; + int strx_from_uint32; + int failures; + + failures = 0; + + str_from_uint16 = check_str_from_uint16 (); + if (str_from_uint16 != 0) + { + if (str_from_uint16 < 0) + { + fprintf (stderr, + "ERROR: test internal error in check_str_from_uint16().\n"); + return 99; + } + fprintf (stderr, + "FAILED: testcase check_str_from_uint16() failed.\n\n"); + failures += str_from_uint16; + } + else if (verbose > 1) + printf ( + "PASSED: testcase check_str_from_uint16() successfully passed.\n\n"); + + strx_from_uint32 = check_strx_from_uint32 (); + if (strx_from_uint32 != 0) + { + if (strx_from_uint32 < 0) + { + fprintf (stderr, + "ERROR: test internal error in check_strx_from_uint32().\n"); + return 99; + } + fprintf (stderr, + "FAILED: testcase check_strx_from_uint32() failed.\n\n"); + failures += strx_from_uint32; + } + else if (verbose > 1) + printf ( + "PASSED: testcase check_strx_from_uint32() successfully passed.\n\n"); + + if (failures) + { + if (verbose > 0) + printf ("At least one test failed.\n"); + + return 1; + } + + if (verbose > 0) + printf ("All tests passed successfully.\n"); + + return 0; +} + + +int main (int argc, char *argv[]) { if (has_param (argc, argv, "-v") || has_param (argc, argv, "--verbose") || @@ -3328,5 +3635,8 @@ main (int argc, char *argv[]) if (has_in_name (argv[0], "_to_value")) return run_str_to_X_tests (); + if (has_in_name (argv[0], "_from_value")) + return run_str_from_X_tests (); + return run_eq_neq_str_tests (); }