CGI program v C, který generuje XHTML pomocí libxml2
Tento kód jsem kdysi napsal pro generování HTML stránek v cgitu (alternativa GITWEBu napsaná v C). Je to wrapper kolem libxml2 API pro generování XHTML dokumentu. API libxml2 je poněkud zmatené a tak jsem vytvořil něco snáze použitelného.
/* header */ #include <glib.h> #include <libxml/tree.h> typedef struct _page page; struct _page { char* title_text; xmlDocPtr doc; xmlNodePtr head; xmlNodePtr body; xmlNodePtr title; xmlNodePtr content; }; extern page* page_new(const char* title); extern void page_emit(page* p); extern xmlNodePtr add_node(xmlNodePtr parent, const char* name, const char* cont, ...); extern void add_text(xmlNodePtr parent, const char* text); extern void set_attr(xmlNodePtr node, const char* name, const char* value); extern void page_add_meta(page* p, const char* name, const char* content); extern xmlNodePtr add_link(xmlNodePtr parent, const char* href, const char* text, const char* title); extern xmlNodePtr add_node_id(xmlNodePtr parent, const char* name, const char* id); extern xmlNodePtr add_node_class(xmlNodePtr parent, const char* name, const char* class); extern xmlNodePtr add_hidden_input(xmlNodePtr parent, const char* name, const char* data); extern void add_text_date(xmlNodePtr parent, time_t secs, char *format); extern void add_span_age(xmlNodePtr parent, time_t t, time_t max_relative, char *format); extern void add_html(xmlNodePtr parent, const char* html); /* code */ #include <string.h> static xmlChar* ensure_utf8(const char* str) { char* good_str; if (str == NULL) return NULL; // don't do anything with valid utf8 if (g_utf8_validate(str, -1, NULL)) return BAD_CAST str; // convert string to UTF-8, fixing invalid characters in the process good_str = g_convert_with_fallback(str, -1, "UTF-8", "UTF-8", "_", NULL, NULL, NULL); if (good_str == NULL) return BAD_CAST "[conversion failed]"; return BAD_CAST good_str; } xmlNodePtr add_node(xmlNodePtr parent, const char* name, const char* cont, ...) { xmlNodePtr node; va_list args; node = xmlNewNode(NULL, BAD_CAST ensure_utf8(name)); if (parent) xmlAddChild(parent, node); va_start(args, cont); while (1) { char *prop_name, *prop_value; prop_name = va_arg(args, char*); if (prop_name == 0) break; prop_value = va_arg(args, char*); if (prop_value == 0) continue; set_attr(node, prop_name, prop_value); } va_end(args); if (cont) add_text(node, cont); return node; } void add_text(xmlNodePtr parent, const char* text) { xmlAddChild(parent, xmlNewText(ensure_utf8(text))); } void set_attr(xmlNodePtr node, const char* name, const char* value) { xmlSetProp(node, ensure_utf8(name), ensure_utf8(value)); } void page_add_meta(page* p, const char* name, const char* content) { add_node(p->head, "meta", NULL, "name", name, "content", content, 0); } xmlNodePtr add_link(xmlNodePtr parent, const char* href, const char* text, const char* title) { return add_node(parent, "a", text, "href", href, "title", title, 0); } xmlNodePtr add_node_id(xmlNodePtr parent, const char* name, const char* id) { return add_node(parent, name, NULL, "id", id, 0); } xmlNodePtr add_node_class(xmlNodePtr parent, const char* name, const char* class) { return add_node(parent, name, NULL, "class", class, 0); } xmlNodePtr add_hidden_input(xmlNodePtr parent, const char* name, const char* data) { return add_node(parent, "input", NULL, "type", "hidden", "name", name, "value", data, 0); } void add_html(xmlNodePtr parent, const char* html) { int len = strlen(html)+8; char* buffer = malloc(len); snprintf(buffer, len, "<r>%s</r>", ensure_utf8(html)); xmlDocPtr doc = xmlReadMemory(buffer, len-1, 0, 0, XML_PARSE_NOWARNING|XML_PARSE_NOERROR|XML_PARSE_NONET); if (doc == 0) return; xmlNodePtr nl = xmlDocCopyNodeList(parent->doc, xmlDocGetRootElement(doc)->children); xmlAddChildList(parent, nl); xmlFreeDoc(doc); } page* page_new(const char* title) { xmlNodePtr root; page* p = malloc(sizeof(page)); p->doc = xmlNewDoc(BAD_CAST "1.0"); xmlCreateIntSubset(p->doc, BAD_CAST "html", BAD_CAST "-//W3C//DTD XHTML 1.0 Strict//EN", BAD_CAST "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"); root = add_node(NULL, "html", NULL, "lang", "en", 0); xmlDocSetRootElement(p->doc, root); p->head = add_node(root, "head", NULL, 0); p->title = add_node(p->head, "title", title, 0); p->body = add_node(root, "body", NULL, 0); page_add_meta(p, "generator", g_strdup_printf("cgit v%s", "1.0")); add_node(p->head, "link", 0, "rel", "stylesheet", "type", "text/css", "href", "style.css", 0); return p; } void page_emit(page* p) { char *buf, *out; int size; xmlDocDumpFormatMemoryEnc(p->doc, (xmlChar**)&buf, &size, "UTF-8", 1); /* remove <?xml ?> line to make IE happy */ out = strchr(buf, '\n'); if (out == NULL) return; out++; size -= (out - buf); /* send headers */ fprintf(stdout, "Content-Type: text/html; charset=UTF-8\r\n" "Content-Length: %d\r\n" "\r\n", size); fwrite(out, size, 1, stdout); fflush(stdout); } int main() { page* p = page_new("test"); add_node(p->body, "div", "Content text", NULL); page_emit(p); }
Kód si můžete také stáhnout a zkompilovat pomocí příkazu:
gcc -o cgi cgi.c `pkg-config --libs --cflags glib-2.0 libxml-2.0`
