From 7662dc5ce75ba032099279a7cde71c761f335685 Mon Sep 17 00:00:00 2001 From: Daniel Markstedt Date: Thu, 5 Mar 2026 19:05:22 +0100 Subject: [PATCH] port bSGMLEncode function from bstrlib the bSGMLEncode function converts the input string to something that is escaped for literal representation in HTML, XML, etc. code ported from bstrlib by Paul Hsieh with modifications; the unit test is written from scratch --- bstring/bstraux.c | 19 +++++++++++++++++++ bstring/bstraux.h | 10 ++++++++++ tests/testaux.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/bstring/bstraux.c b/bstring/bstraux.c index 18d33c9..92d57fe 100644 --- a/bstring/bstraux.c +++ b/bstring/bstraux.c @@ -909,6 +909,25 @@ bYDecode(const bstring src) return out; } +/* int bSGMLEncode (bstring b) + * + * Change the string into a version that is quotable in SGML (HTML, XML). + */ +int +bSGMLEncode(bstring b) +{ +static struct tagbstring fr[4][2] = { + { bsStatic("&"), bsStatic("&") }, + { bsStatic("\""), bsStatic(""") }, + { bsStatic("<"), bsStatic("<") }, + { bsStatic(">"), bsStatic(">") } }; + for (int i = 0; i < 4; i++) { + int ret = bfindreplace(b, &fr[i][0], &fr[i][1], 0); + if (0 > ret) return ret; + } + return 0; +} + bstring bStrfTime(const char * fmt, const struct tm * timeptr) { diff --git a/bstring/bstraux.h b/bstring/bstraux.h index 12e6125..ac9a2ba 100644 --- a/bstring/bstraux.h +++ b/bstring/bstraux.h @@ -322,6 +322,16 @@ bYEncode(const bstring src); BSTR_PUBLIC bstring bYDecode(const bstring src); +/** + * Change the string into a version that is quotable in SGML (HTML, XML). + * Replaces &, ", <, > with their SGML entity equivalents. + * + * @param b the bstring to encode in-place + * @return BSTR_OK on success, BSTR_ERR on error + */ +BSTR_PUBLIC int +bSGMLEncode(bstring b); + /* Writable stream */ typedef int (*bNwrite)(const void *buf, size_t elsize, size_t nelem, void *parm); diff --git a/tests/testaux.c b/tests/testaux.c index 6cc6983..ff80d96 100644 --- a/tests/testaux.c +++ b/tests/testaux.c @@ -483,6 +483,33 @@ START_TEST(core_013) } END_TEST +START_TEST(core_014) +{ + bstring b; + + /* All four entities: &, ", <, > */ + b = bfromcstr("<\"Hello, you, me, & world\">"); + ck_assert_int_eq(bSGMLEncode(b), BSTR_OK); + ck_assert_int_eq(biseqcstr(b, "<"Hello, you, me, & world">"), 1); + bdestroy(b); + + /* No special characters — string should be unchanged */ + b = bfromcstr("Hello, world"); + ck_assert_int_eq(bSGMLEncode(b), BSTR_OK); + ck_assert_int_eq(biseqcstr(b, "Hello, world"), 1); + bdestroy(b); + + /* Empty string */ + b = bfromcstr(""); + ck_assert_int_eq(bSGMLEncode(b), BSTR_OK); + ck_assert_int_eq(biseqcstr(b, ""), 1); + bdestroy(b); + + /* NULL input */ + ck_assert_int_eq(bSGMLEncode(NULL), BSTR_ERR); +} +END_TEST + int main(void) { @@ -504,6 +531,7 @@ main(void) tcase_add_test(core, core_011); tcase_add_test(core, core_012); tcase_add_test(core, core_013); + tcase_add_test(core, core_014); suite_add_tcase(suite, core); /* Run tests */ SRunner *runner = srunner_create(suite);