From 2b878ef15ce2542687748f5db74619ee35b410e5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonathan=20Sch=C3=B6bel?= <jonathan@xn--schbel-yxa.info>
Date: Mon, 5 Jun 2023 22:35:58 +0200
Subject: [PATCH] NodeFragment: added attributes to html generation

The to_html method generates also the html for the attributes. Note,
that there is no escapeing of the quotes, the values are wrapped with. But
this is also somewhat consistent, as there is no syntax validation on
the tags either. (i.e. no '<' in side of a tag)
---
 sefht.geany                   |  6 +--
 src/lib/sefht/node_fragment.c | 46 +++++++++++++++++++
 tests/test_node_fragment.c    | 86 ++++++++++++++++++++++++++++++++---
 3 files changed, 129 insertions(+), 9 deletions(-)

diff --git a/sefht.geany b/sefht.geany
index bdd43c4..2c9723d 100644
--- a/sefht.geany
+++ b/sefht.geany
@@ -28,7 +28,7 @@ long_line_behaviour=1
 long_line_column=72
 
 [files]
-current_page=35
+current_page=34
 FILE_NAME_0=139;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2FREADME;0;8
 FILE_NAME_1=134;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2F.gitignore;0;8
 FILE_NAME_2=1751;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fconfigure.ac;0;8
@@ -43,7 +43,7 @@ FILE_NAME_10=1550;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fp
 FILE_NAME_11=1562;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment.h;0;8
 FILE_NAME_12=2022;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment_data.c;0;8
 FILE_NAME_13=2558;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment_class.c;0;8
-FILE_NAME_14=36155;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fnode_fragment.c;0;8
+FILE_NAME_14=20340;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fnode_fragment.c;0;8
 FILE_NAME_15=6811;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fnode_fragment.h;0;8
 FILE_NAME_16=4906;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fattr.c;0;8
 FILE_NAME_17=2956;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fattr.h;0;8
@@ -63,7 +63,7 @@ FILE_NAME_30=555;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2
 FILE_NAME_31=218;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Fno_test.sh.in;0;8
 FILE_NAME_32=1085;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_cms.c;0;8
 FILE_NAME_33=3283;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_data.c;0;8
-FILE_NAME_34=114262;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8
+FILE_NAME_34=110781;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8
 FILE_NAME_35=11319;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_attr.c;0;8
 FILE_NAME_36=11068;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text.c;0;8
 FILE_NAME_37=5744;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator.c;0;8
diff --git a/src/lib/sefht/node_fragment.c b/src/lib/sefht/node_fragment.c
index a6c5752..595db61 100644
--- a/src/lib/sefht/node_fragment.c
+++ b/src/lib/sefht/node_fragment.c
@@ -67,6 +67,11 @@ struct SH_NodeFragment
 #define CLOSE_TAG_BEGIN "</"
 #define CLOSE_TAG_END ">"
 
+#define ATTR_NAME_DELIMITER " "
+#define ATTR_VALUE_DELIMITER "="
+#define ATTR_VALUE_QUOTE_BEGIN "\""
+#define ATTR_VALUE_QUOTE_END "\""
+
 #define NEWLINE "\n"
 
 
@@ -1566,6 +1571,47 @@ SH_NodeFragment_to_html (const struct SH_NodeFragment * fragment,
 		goto fail_autoclean;
 	}
 
+	for (index = 0; index < fragment->attr_n; index++)
+	{
+	#define add(TEXT) SH_Text_append_string (html, (TEXT), status)
+	#define attr &(fragment->attrs[index])
+
+		if (!add (ATTR_NAME_DELIMITER))
+		{
+			goto fail_autoclean;
+		}
+
+		if (!add (Attr_get_name (attr)))
+		{
+			goto fail_autoclean;
+		}
+
+		if (Attr_has_value (attr))
+		{
+			if (!add (ATTR_VALUE_DELIMITER))
+			{
+				goto fail_autoclean;
+			}
+
+			if (!add (ATTR_VALUE_QUOTE_BEGIN))
+			{
+				goto fail_autoclean;
+			}
+
+			if (!add (Attr_get_value (attr)))
+			{
+				goto fail_autoclean;
+			}
+
+			if (!add (ATTR_VALUE_QUOTE_END))
+			{
+				goto fail_autoclean;
+			}
+		}
+	#undef attr
+	#undef add
+	}
+
 	if (!SH_Text_append_string (html, OPEN_TAG_END, status))
 	{
 		goto fail_autoclean;
diff --git a/tests/test_node_fragment.c b/tests/test_node_fragment.c
index be89c29..048ce6a 100644
--- a/tests/test_node_fragment.c
+++ b/tests/test_node_fragment.c
@@ -3655,9 +3655,26 @@ START_TEST(test_node_fragment_html_inline_no_status)
 	                                                    NULL);
 	ck_assert_ptr_ne (NULL, fragment);
 
+	result = SH_NodeFragment_append_attr_new (fragment,
+	                                          strdup ("lang"),
+	                                          strdup ("de"),
+	                                          NULL);
+	ck_assert_int_eq (TRUE, result);
+
 	child = SH_NodeFragment_new ("body", data, NULL);
 	ck_assert_ptr_ne (NULL, child);
 
+	result = SH_NodeFragment_append_attr_new ((SH_NodeFragment *)child,
+	                                          strdup ("id"),
+	                                          strdup ("body"),
+	                                          NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_attr_new ((SH_NodeFragment *)child,
+	                                          strdup ("attr"),
+	                                          NULL, NULL);
+	ck_assert_int_eq (TRUE, result);
+
 	result = SH_NodeFragment_append_child (fragment, child, NULL);
 	ck_assert_int_eq (TRUE, result);
 
@@ -3668,7 +3685,10 @@ START_TEST(test_node_fragment_html_inline_no_status)
 	ck_assert_ptr_ne (NULL, text);
 
 	string = SH_Text_get_string (text, 0, SIZE_MAX, &length, NULL);
-	ck_assert_str_eq (string, "<html><body></body></html>");
+	ck_assert_str_eq (string, "<html lang=\"de\">"
+	                          "<body id=\"body\" attr>"
+	                          "</body>"
+	                          "</html>");
 
 	/* cleanup */
 	free (string);
@@ -3697,9 +3717,26 @@ START_TEST(test_node_fragment_html_inline_with_status)
 	                                                    NULL);
 	ck_assert_ptr_ne (NULL, fragment);
 
+	result = SH_NodeFragment_append_attr_new (fragment,
+	                                          strdup ("lang"),
+	                                          strdup ("de"),
+	                                          NULL);
+	ck_assert_int_eq (TRUE, result);
+
 	child = SH_NodeFragment_new ("body", data, NULL);
 	ck_assert_ptr_ne (NULL, child);
 
+	result = SH_NodeFragment_append_attr_new ((SH_NodeFragment *)child,
+	                                          strdup ("id"),
+	                                          strdup ("body"),
+	                                          NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_attr_new ((SH_NodeFragment *)child,
+	                                          strdup ("attr"),
+	                                          NULL, NULL);
+	ck_assert_int_eq (TRUE, result);
+
 	result = SH_NodeFragment_append_child (fragment, child, NULL);
 	ck_assert_int_eq (TRUE, result);
 
@@ -3712,7 +3749,10 @@ START_TEST(test_node_fragment_html_inline_with_status)
 	ck_assert_int_eq (status.status, SUCCESS);
 
 	string = SH_Text_get_string (text, 0, SIZE_MAX, &length, NULL);
-	ck_assert_str_eq (string, "<html><body></body></html>");
+	ck_assert_str_eq (string, "<html lang=\"de\">"
+	                          "<body id=\"body\" attr>"
+	                          "</body>"
+	                          "</html>");
 
 	/* cleanup */
 	free (string);
@@ -3740,9 +3780,26 @@ START_TEST(test_node_fragment_html_wrap_no_status)
 	                                                    NULL);
 	ck_assert_ptr_ne (NULL, fragment);
 
+	result = SH_NodeFragment_append_attr_new (fragment,
+	                                          strdup ("lang"),
+	                                          strdup ("de"),
+	                                          NULL);
+	ck_assert_int_eq (TRUE, result);
+
 	child = SH_NodeFragment_new ("body", data, NULL);
 	ck_assert_ptr_ne (NULL, child);
 
+	result = SH_NodeFragment_append_attr_new ((SH_NodeFragment *)child,
+	                                          strdup ("id"),
+	                                          strdup ("body"),
+	                                          NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_attr_new ((SH_NodeFragment *)child,
+	                                          strdup ("attr"),
+	                                          NULL, NULL);
+	ck_assert_int_eq (TRUE, result);
+
 	result = SH_NodeFragment_append_child (fragment, child, NULL);
 	ck_assert_int_eq (TRUE, result);
 
@@ -3753,8 +3810,8 @@ START_TEST(test_node_fragment_html_wrap_no_status)
 	ck_assert_ptr_ne (NULL, text);
 
 	string = SH_Text_get_string (text, 0, SIZE_MAX, &length, NULL);
-	ck_assert_str_eq (string, "<html>\n"
-	                          "\t<body>\n"
+	ck_assert_str_eq (string, "<html lang=\"de\">\n"
+	                          "\t<body id=\"body\" attr>\n"
 	                          "\t</body>\n"
 	                          "</html>\n");
 
@@ -3785,9 +3842,26 @@ START_TEST(test_node_fragment_html_wrap_with_status)
 	                                                    NULL);
 	ck_assert_ptr_ne (NULL, fragment);
 
+	result = SH_NodeFragment_append_attr_new (fragment,
+	                                          strdup ("lang"),
+	                                          strdup ("de"),
+	                                          NULL);
+	ck_assert_int_eq (TRUE, result);
+
 	child = SH_NodeFragment_new ("body", data, NULL);
 	ck_assert_ptr_ne (NULL, child);
 
+	result = SH_NodeFragment_append_attr_new ((SH_NodeFragment *)child,
+	                                          strdup ("id"),
+	                                          strdup ("body"),
+	                                          NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_attr_new ((SH_NodeFragment *)child,
+	                                          strdup ("attr"),
+	                                          NULL, NULL);
+	ck_assert_int_eq (TRUE, result);
+
 	result = SH_NodeFragment_append_child (fragment, child, NULL);
 	ck_assert_int_eq (TRUE, result);
 
@@ -3800,8 +3874,8 @@ START_TEST(test_node_fragment_html_wrap_with_status)
 	ck_assert_int_eq (status.status, SUCCESS);
 
 	string = SH_Text_get_string (text, 0, SIZE_MAX, &length, NULL);
-	ck_assert_str_eq (string, "<html>\n"
-	                          "\t<body>\n"
+	ck_assert_str_eq (string, "<html lang=\"de\">\n"
+	                          "\t<body id=\"body\" attr>\n"
 	                          "\t</body>\n"
 	                          "</html>\n");
 
-- 
GitLab