static void test_sc_string_append_char__normal() { char buf[16]; size_t len; sc_string_init(buf, sizeof buf); len = sc_string_append_char(buf, sizeof buf, 'h'); g_assert_cmpstr(buf, ==, "h"); g_assert_cmpint(len, ==, 1); len = sc_string_append_char(buf, sizeof buf, 'e'); g_assert_cmpstr(buf, ==, "he"); g_assert_cmpint(len, ==, 2); len = sc_string_append_char(buf, sizeof buf, 'l'); g_assert_cmpstr(buf, ==, "hel"); g_assert_cmpint(len, ==, 3); len = sc_string_append_char(buf, sizeof buf, 'l'); g_assert_cmpstr(buf, ==, "hell"); g_assert_cmpint(len, ==, 4); len = sc_string_append_char(buf, sizeof buf, 'o'); g_assert_cmpstr(buf, ==, "hello"); g_assert_cmpint(len, ==, 5); }
static void test_sc_string_append_char__NULL_buf() { if (g_test_subprocess()) { sc_string_append_char(NULL, 2, 'a'); g_test_message("expected sc_string_append_char not to return"); g_test_fail(); return; } g_test_trap_subprocess(NULL, 0, 0); g_test_trap_assert_failed(); g_test_trap_assert_stderr("cannot append character: buffer is NULL\n"); }
static void test_sc_string_append_char__invalid_zero() { if (g_test_subprocess()) { char buf[2] = { 0 }; sc_string_append_char(buf, sizeof buf, '\0'); g_test_message("expected sc_string_append_char not to return"); g_test_fail(); return; } g_test_trap_subprocess(NULL, 0, 0); g_test_trap_assert_failed(); g_test_trap_assert_stderr ("cannot append character: cannot append string terminator\n"); }
static void test_sc_string_append_char__overflow() { if (g_test_subprocess()) { char buf[1] = { 0 }; sc_string_append_char(buf, sizeof buf, 'a'); g_test_message("expected sc_string_append_char not to return"); g_test_fail(); return; } g_test_trap_subprocess(NULL, 0, 0); g_test_trap_assert_failed(); g_test_trap_assert_stderr ("cannot append character: not enough space\n"); }
static void test_sc_string_append_char__uninitialized_buf() { if (g_test_subprocess()) { char buf[2] = { 0xFF, 0xFF }; sc_string_append_char(buf, sizeof buf, 'a'); g_test_message("expected sc_string_append_char not to return"); g_test_fail(); return; } g_test_trap_subprocess(NULL, 0, 0); g_test_trap_assert_failed(); g_test_trap_assert_stderr ("cannot append character: dst is unterminated\n"); }
void sc_string_quote(char *buf, size_t buf_size, const char *str) { if (str == NULL) { die("cannot quote string: string is NULL"); } const char *hex = "0123456789abcdef"; // NOTE: this also checks buf/buf_size sanity so that we don't have to. sc_string_init(buf, buf_size); sc_string_append_char(buf, buf_size, '"'); for (unsigned char c; (c = *str) != 0; ++str) { switch (c) { // Pass ASCII letters and digits unmodified. case '0' ... '9': case 'A' ... 'Z': case 'a' ... 'z': // Pass most of the punctuation unmodified. case ' ': case '!': case '#': case '$': case '%': case '&': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case '[': case '\'': case ']': case '^': case '_': case '`': case '{': case '|': case '}': case '~': sc_string_append_char(buf, buf_size, c); break; // Escape special whitespace characters. case '\n': sc_string_append_char_pair(buf, buf_size, '\\', 'n'); break; case '\r': sc_string_append_char_pair(buf, buf_size, '\\', 'r'); break; case '\t': sc_string_append_char_pair(buf, buf_size, '\\', 't'); break; case '\v': sc_string_append_char_pair(buf, buf_size, '\\', 'v'); break; // Escape the escape character. case '\\': sc_string_append_char_pair(buf, buf_size, '\\', '\\'); break; // Escape double quote character. case '"': sc_string_append_char_pair(buf, buf_size, '\\', '"'); break; // Escape everything else as a generic hexadecimal escape string. default: sc_string_append_char_pair(buf, buf_size, '\\', 'x'); sc_string_append_char_pair(buf, buf_size, hex[c >> 4], hex[c & 15]); break; } } sc_string_append_char(buf, buf_size, '"'); }