cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
builder.c
Go to the documentation of this file.
4#include <cjson/cJSON.h>
5#include <stdlib.h>
6#include <string.h>
7#include <stdio.h>
8
21 if (!el) return NULL;
22
24 cwist_sstring_assign(el->tag, tag ? tag : "");
25 el->attributes = cJSON_CreateObject();
26 el->children = NULL;
27 el->child_count = 0;
28 el->inner_text = NULL;
29
30 return el;
31}
32
38 if (!el) return;
39
40 if (el->tag) cwist_sstring_destroy(el->tag);
41 if (el->attributes) cJSON_Delete(el->attributes);
42
43 if (el->children) {
44 for (int i = 0; i < el->child_count; i++) {
46 }
48 }
49
51
52 cwist_free(el);
53}
54
61void cwist_html_element_add_attr(cwist_html_element_t *el, const char *key, const char *value) {
62 if (!el || !key || !value || !el->attributes) return;
63
64 if (cJSON_HasObjectItem(el->attributes, key)) {
65 cJSON_ReplaceItemInObject(el->attributes, key, cJSON_CreateString(value));
66 } else {
67 cJSON_AddStringToObject(el->attributes, key, value);
68 }
69}
70
77 cwist_html_element_add_attr(el, "id", id);
78}
79
85void cwist_html_element_add_class(cwist_html_element_t *el, const char *class_name) {
86 if (!el || !class_name || !el->attributes) return;
87
88 cJSON *cls = cJSON_GetObjectItem(el->attributes, "class");
89 if (cls && cls->valuestring && *cls->valuestring) {
90 // Append to existing class
92 cwist_sstring_assign(s, cls->valuestring);
94 cwist_sstring_append(s, class_name);
95 cJSON_ReplaceItemInObject(el->attributes, "class",
96 cJSON_CreateString(s->data ? s->data : ""));
98 } else {
99 cwist_html_element_add_attr(el, "class", class_name);
100 }
101}
102
109 if (!el) return;
110 const char *actual_text = text ? text : "";
111 if (el->inner_text) {
112 cwist_sstring_assign(el->inner_text, actual_text);
113 } else {
115 cwist_sstring_assign(el->inner_text, actual_text);
116 }
117}
118
125 if (!el || !child) return;
126
127 el->child_count++;
129 el->children, sizeof(cwist_html_element_t *) * el->child_count);
130 if (!new_children) {
131 el->child_count--;
132 return;
133 }
134 el->children = new_children;
135 el->children[el->child_count - 1] = child;
136}
137
142static bool is_void_element(const char *tag) {
143 static const char *const void_tags[] = {"area", "base", "br", "col", "embed", "hr", "img",
144 "input", "link", "meta", "source", "track", "wbr"};
145 for (size_t i = 0; i < sizeof(void_tags) / sizeof(void_tags[0]); i++) {
146 const char *a = tag, *b = void_tags[i];
147 while (*a && (*a | 0x20) == *b) {
148 a++;
149 b++;
150 }
151 if (*a == '\0' && *b == '\0') return true;
152 }
153 return false;
154}
155
161static void render_element(cwist_html_element_t *el, cwist_sstring *out) {
162 if (!el || !out) return;
163
164 if (el->tag && el->tag->data && *el->tag->data) {
165 cwist_sstring_append(out, "<");
166 cwist_sstring_append(out, el->tag->data);
167 cJSON *attr = NULL;
168 cJSON_ArrayForEach(attr, el->attributes) {
169 if (!attr || !attr->string) continue;
170 if (cJSON_IsString(attr) && attr->valuestring) {
171 cwist_sstring_append(out, " ");
172 cwist_sstring_append(out, attr->string);
173 cwist_sstring_append(out, "=\"");
174 cwist_sstring_append_escaped(out, attr->valuestring);
175 cwist_sstring_append(out, "\"");
176 } else if (cJSON_IsTrue(attr)) {
177 cwist_sstring_append(out, " ");
178 cwist_sstring_append(out, attr->string);
179 } else if (cJSON_IsNumber(attr)) {
180 char num_buf[64];
181 snprintf(num_buf, sizeof(num_buf), "%g", attr->valuedouble);
182 cwist_sstring_append(out, " ");
183 cwist_sstring_append(out, attr->string);
184 cwist_sstring_append(out, "=\"");
185 cwist_sstring_append(out, num_buf);
186 cwist_sstring_append(out, "\"");
187 }
188 }
189 cwist_sstring_append(out, ">");
190
191 /* A void element cannot have content; an end tag like </br> would be
192 * parsed by browsers as a second element. */
193 if (is_void_element(el->tag->data)) return;
194
195 if (el->inner_text && el->inner_text->data) {
197 }
198
199 if (el->children) {
200 for (int i = 0; i < el->child_count; i++) {
201 render_element(el->children[i], out);
202 }
203 }
204
205 cwist_sstring_append(out, "</");
206 cwist_sstring_append(out, el->tag->data);
207 cwist_sstring_append(out, ">");
208 } else if (el->inner_text && el->inner_text->data) {
209 // If no tag, just render the text (escaped)
211 }
212}
213
220 if (!el) return NULL;
222 cwist_sstring_assign(out, "");
223 render_element(el, out);
224 return out;
225}
Memory allocation wrappers backed by libttak.
void cwist_free(void *ptr)
Free memory obtained via cwist_alloc/cwist_strdup/etc.
Definition alloc.c:52
void * cwist_realloc(void *ptr, size_t new_size)
Resize an existing allocation (libttak tracked).
Definition alloc.c:27
void * cwist_alloc(size_t size)
Allocate zeroed memory tracked by libttak.
Definition alloc.c:17
void cwist_html_element_add_child(cwist_html_element_t *el, cwist_html_element_t *child)
Append a child node to an element's ordered children list.
Definition builder.c:124
void cwist_html_element_add_attr(cwist_html_element_t *el, const char *key, const char *value)
Insert or replace an HTML attribute on an element.
Definition builder.c:61
void cwist_html_element_set_id(cwist_html_element_t *el, const char *id)
Set the DOM id attribute for an element.
Definition builder.c:76
void cwist_html_element_destroy(cwist_html_element_t *el)
Recursively destroy an element and every descendant it owns.
Definition builder.c:37
void cwist_html_element_add_class(cwist_html_element_t *el, const char *class_name)
Append a CSS class token to an element.
Definition builder.c:85
cwist_sstring * cwist_html_render(cwist_html_element_t *el)
Render an HTML tree to a freshly allocated string buffer.
Definition builder.c:219
cwist_html_element_t * cwist_html_element_create(const char *tag)
Allocate a new HTML element node for the supplied tag name.
Definition builder.c:19
void cwist_html_element_set_text(cwist_html_element_t *el, const char *text)
Replace the element's inner text payload.
Definition builder.c:108
HTML element builder and renderer.
Safe string type with helper methods.
cwist_sstring * cwist_sstring_create(void)
Create a new sstring instance.
Definition sstring.c:802
cwist_error_t cwist_sstring_append(cwist_sstring *str, const char *data)
Append a C string.
Definition sstring.c:559
cwist_error_t cwist_sstring_assign(cwist_sstring *str, const char *data)
Assign a C string.
Definition sstring.c:504
void cwist_sstring_destroy(cwist_sstring *str)
Destroy an sstring instance.
Definition sstring.c:823
cwist_error_t cwist_sstring_append_escaped(cwist_sstring *str, const char *data)
Append an escaped C string.
Definition sstring.c:616
cJSON * attributes
Definition builder.h:14
cwist_sstring * inner_text
Definition builder.h:17
struct cwist_html_element ** children
Definition builder.h:15
cwist_sstring * tag
Definition builder.h:13
char * data
Access directly only when raw handling is necessary.
Definition sstring.h:15