mirror of
https://github.com/bdnugget/kcgi.git
synced 2026-11-07 21:47:27 +00:00
763 lines
20 KiB
C
763 lines
20 KiB
C
/* $Id$ */
|
|
/*
|
|
* Copyright (c) 2012, 2014, 2015 Kristaps Dzonsons <kristaps@bsd.lv>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <assert.h>
|
|
#include <inttypes.h>
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "kcgi.h"
|
|
#include "kcgihtml.h"
|
|
|
|
/*
|
|
* Maximum size of printing a signed 64-bit integer.
|
|
*/
|
|
#define INT_MAXSZ 22
|
|
|
|
/*
|
|
* A type of HTML5 element.
|
|
* Note: we don't list transitional elements, though I do note them in
|
|
* the tag array.
|
|
*/
|
|
enum htype {
|
|
TAG_FLOW, /* flow (block) element */
|
|
TAG_PHRASE,/* phrasing (inline) element */
|
|
TAG_VOID, /* auto-closing (e.g., INPUT) */
|
|
TAG_INSTRUCTION /* instruction */
|
|
};
|
|
|
|
/*
|
|
* A tag describes an HTML element and its properties.
|
|
*/
|
|
struct tag {
|
|
enum htype flags;
|
|
const char *name;
|
|
};
|
|
|
|
static const uint16_t entities[KENTITY__MAX] = {
|
|
198, /* KENTITY_AElig */
|
|
193, /* KENTITY_Aacute */
|
|
194, /* KENTITY_Acirc */
|
|
192, /* KENTITY_Agrave */
|
|
197, /* KENTITY_Aring */
|
|
195, /* KENTITY_Atilde */
|
|
196, /* KENTITY_Auml */
|
|
199, /* KENTITY_Ccedil */
|
|
8225, /* KENTITY_Dagger */
|
|
208, /* KENTITY_ETH */
|
|
201, /* KENTITY_Eacute */
|
|
202, /* KENTITY_Ecirc */
|
|
200, /* KENTITY_Egrave */
|
|
203, /* KENTITY_Euml */
|
|
205, /* KENTITY_Iacute */
|
|
206, /* KENTITY_Icirc */
|
|
204, /* KENTITY_Igrave */
|
|
207, /* KENTITY_Iuml */
|
|
209, /* KENTITY_Ntilde */
|
|
338, /* KENTITY_OElig */
|
|
211, /* KENTITY_Oacute */
|
|
212, /* KENTITY_Ocirc */
|
|
210, /* KENTITY_Ograve */
|
|
216, /* KENTITY_Oslash */
|
|
213, /* KENTITY_Otilde */
|
|
214, /* KENTITY_Ouml */
|
|
352, /* KENTITY_Scaron */
|
|
222, /* KENTITY_THORN */
|
|
218, /* KENTITY_Uacute */
|
|
219, /* KENTITY_Ucirc */
|
|
217, /* KENTITY_Ugrave */
|
|
220, /* KENTITY_Uuml */
|
|
221, /* KENTITY_Yacute */
|
|
376, /* KENTITY_Yuml */
|
|
225, /* KENTITY_aacute */
|
|
226, /* KENTITY_acirc */
|
|
180, /* KENTITY_acute */
|
|
230, /* KENTITY_aelig */
|
|
224, /* KENTITY_agrave */
|
|
38, /* KENTITY_amp */
|
|
39, /* KENTITY_apos */
|
|
229, /* KENTITY_aring */
|
|
227, /* KENTITY_atilde */
|
|
228, /* KENTITY_auml */
|
|
8222, /* KENTITY_bdquo */
|
|
166, /* KENTITY_brvbar */
|
|
231, /* KENTITY_ccedil */
|
|
184, /* KENTITY_cedil */
|
|
162, /* KENTITY_cent */
|
|
710, /* KENTITY_circ */
|
|
169, /* KENTITY_copy */
|
|
164, /* KENTITY_curren */
|
|
8224, /* KENTITY_dagger */
|
|
176, /* KENTITY_deg */
|
|
247, /* KENTITY_divide */
|
|
233, /* KENTITY_eacute */
|
|
234, /* KENTITY_ecirc */
|
|
232, /* KENTITY_egrave */
|
|
8195, /* KENTITY_emsp */
|
|
8194, /* KENTITY_ensp */
|
|
240, /* KENTITY_eth */
|
|
235, /* KENTITY_euml */
|
|
8364, /* KENTITY_euro */
|
|
189, /* KENTITY_frac12 */
|
|
188, /* KENTITY_frac14 */
|
|
190, /* KENTITY_frac34 */
|
|
62, /* KENTITY_gt */
|
|
8230, /* KENTITY_hellip */
|
|
237, /* KENTITY_iacute */
|
|
238, /* KENTITY_icirc */
|
|
161, /* KENTITY_iexcl */
|
|
236, /* KENTITY_igrave */
|
|
191, /* KENTITY_iquest */
|
|
239, /* KENTITY_iuml */
|
|
171, /* KENTITY_laquo */
|
|
8220, /* KENTITY_ldquo */
|
|
8206, /* KENTITY_lrm */
|
|
8249, /* KENTITY_lsaquo */
|
|
8216, /* KENTITY_lsquo */
|
|
60, /* KENTITY_lt */
|
|
175, /* KENTITY_macr */
|
|
8212, /* KENTITY_mdash */
|
|
181, /* KENTITY_micro */
|
|
183, /* KENTITY_middot */
|
|
160, /* KENTITY_nbsp */
|
|
8211, /* KENTITY_ndash */
|
|
172, /* KENTITY_not */
|
|
241, /* KENTITY_ntilde */
|
|
243, /* KENTITY_oacute */
|
|
244, /* KENTITY_ocirc */
|
|
339, /* KENTITY_oelig */
|
|
242, /* KENTITY_ograve */
|
|
170, /* KENTITY_ordf */
|
|
186, /* KENTITY_ordm */
|
|
248, /* KENTITY_oslash */
|
|
245, /* KENTITY_otilde */
|
|
246, /* KENTITY_ouml */
|
|
182, /* KENTITY_para */
|
|
8240, /* KENTITY_permil */
|
|
177, /* KENTITY_plusmn */
|
|
163, /* KENTITY_pound */
|
|
34, /* KENTITY_quot */
|
|
187, /* KENTITY_raquo */
|
|
8221, /* KENTITY_rdquo */
|
|
174, /* KENTITY_reg */
|
|
8207, /* KENTITY_rlm */
|
|
8250, /* KENTITY_rsaquo */
|
|
8217, /* KENTITY_rsquo */
|
|
8218, /* KENTITY_sbquo */
|
|
353, /* KENTITY_scaron */
|
|
167, /* KENTITY_sect */
|
|
173, /* KENTITY_shy */
|
|
185, /* KENTITY_sup1 */
|
|
178, /* KENTITY_sup2 */
|
|
179, /* KENTITY_sup3 */
|
|
223, /* KENTITY_szlig */
|
|
8201, /* KENTITY_thinsp */
|
|
254, /* KENTITY_thorn */
|
|
732, /* KENTITY_tilde */
|
|
215, /* KENTITY_times */
|
|
8482, /* KENTITY_trade */
|
|
250, /* KENTITY_uacute */
|
|
251, /* KENTITY_ucirc */
|
|
249, /* KENTITY_ugrave */
|
|
168, /* KENTITY_uml */
|
|
252, /* KENTITY_uuml */
|
|
253, /* KENTITY_yacute */
|
|
165, /* KENTITY_yen */
|
|
255, /* KENTITY_yuml */
|
|
8205, /* KENTITY_zwj */
|
|
8204, /* KENTITY_zwnj */
|
|
};
|
|
|
|
static const struct tag tags[KELEM__MAX] = {
|
|
{ TAG_PHRASE, "a" }, /* KELEM_A */ /* XXX: TRANS */
|
|
{ TAG_PHRASE, "abbr" }, /* KELEM_ABBR */
|
|
{ TAG_PHRASE, "address" }, /* KELEM_ADDRESS */
|
|
{ TAG_VOID, "area" }, /* KELEM_AREA */
|
|
{ TAG_FLOW, "article" }, /* KELEM_ARTICLE */
|
|
{ TAG_FLOW, "aside" }, /* KELEM_ASIDE */
|
|
{ TAG_FLOW, "audio" }, /* KELEM_AUDIO */ /* XXX: TRANS */
|
|
{ TAG_PHRASE, "b" }, /* KELEM_B */
|
|
{ TAG_VOID, "base" }, /* KELEM_BASE */
|
|
{ TAG_PHRASE, "bdi" }, /* KELEM_BDI */
|
|
{ TAG_PHRASE, "bdo" }, /* KELEM_BDO */
|
|
{ TAG_FLOW, "blockquote" }, /* KELEM_BLOCKQUOTE */
|
|
{ TAG_FLOW, "body" }, /* KELEM_BODY */
|
|
{ TAG_VOID, "br" }, /* KELEM_BR */
|
|
{ TAG_PHRASE, "button" }, /* KELEM_BUTTON */
|
|
{ TAG_FLOW, "canvas" }, /* KELEM_CANVAS */ /* XXX: TRANS */
|
|
{ TAG_FLOW, "caption" }, /* KELEM_CAPTION */
|
|
{ TAG_PHRASE, "cite" }, /* KELEM_CITE */
|
|
{ TAG_PHRASE, "code" }, /* KELEM_CODE */
|
|
{ TAG_VOID, "col" }, /* KELEM_COL */
|
|
{ TAG_PHRASE, "colgroup" }, /* KELEM_COLGROUP */
|
|
{ TAG_PHRASE, "datalist" }, /* KELEM_DATALIST */
|
|
{ TAG_FLOW, "dd" }, /* KELEM_DD */
|
|
{ TAG_PHRASE, "del" }, /* KELEM_DEL */ /* XXX: TRANS */
|
|
{ TAG_FLOW, "details" }, /* KELEM_DETAILS */
|
|
{ TAG_PHRASE, "dfn" }, /* KELEM_DFN */
|
|
{ TAG_FLOW, "div" }, /* KELEM_DIV */
|
|
{ TAG_FLOW, "dl" }, /* KELEM_DL */
|
|
{ TAG_INSTRUCTION, "!DOCTYPE html" }, /* KELEM_DOCTYPE */
|
|
{ TAG_FLOW, "dt" }, /* KELEM_DT */
|
|
{ TAG_PHRASE, "em" }, /* KELEM_EM */
|
|
{ TAG_VOID, "embed" }, /* KELEM_EMBED */
|
|
{ TAG_FLOW, "fieldset" }, /* KELEM_FIELDSET */
|
|
{ TAG_FLOW, "figcaption" }, /* KELEM_FIGCAPTION */
|
|
{ TAG_FLOW, "figure" }, /* KELEM_FIGURE */
|
|
{ TAG_FLOW, "footer" }, /* KELEM_FOOTER */
|
|
{ TAG_FLOW, "form" }, /* KELEM_FORM */
|
|
{ TAG_PHRASE, "h1" }, /* KELEM_H1 */
|
|
{ TAG_PHRASE, "h2" }, /* KELEM_H2 */
|
|
{ TAG_PHRASE, "h3" }, /* KELEM_H3 */
|
|
{ TAG_PHRASE, "h4" }, /* KELEM_H4 */
|
|
{ TAG_PHRASE, "h5" }, /* KELEM_H5 */
|
|
{ TAG_PHRASE, "h6" }, /* KELEM_H6 */
|
|
{ TAG_FLOW, "head" }, /* KELEM_HEAD */
|
|
{ TAG_FLOW, "header" }, /* KELEM_HEADER */
|
|
{ TAG_FLOW, "hgroup" }, /* KELEM_HGROUP */
|
|
{ TAG_VOID, "hr" }, /* KELEM_HR */
|
|
{ TAG_FLOW, "html" }, /* KELEM_HTML */
|
|
{ TAG_PHRASE, "i" }, /* KELEM_I */
|
|
{ TAG_PHRASE, "iframe" }, /* KELEM_IFRAME */
|
|
{ TAG_VOID, "img" }, /* KELEM_IMG */
|
|
{ TAG_VOID, "input" }, /* KELEM_INPUT */
|
|
{ TAG_PHRASE, "ins" }, /* KELEM_INS */ /* XXX: TRANS */
|
|
{ TAG_PHRASE, "kbd" }, /* KELEM_KBD */
|
|
{ TAG_VOID, "keygen" }, /* KELEM_KEYGEN */
|
|
{ TAG_PHRASE, "label" }, /* KELEM_LABEL */
|
|
{ TAG_PHRASE, "legend" }, /* KELEM_LEGEND */
|
|
{ TAG_FLOW, "li" }, /* KELEM_LI */
|
|
{ TAG_VOID, "link" }, /* KELEM_LINK */
|
|
{ TAG_FLOW, "map" }, /* KELEM_MAP */ /* XXX: TRANS */
|
|
{ TAG_PHRASE, "mark" }, /* KELEM_MARK */
|
|
{ TAG_FLOW, "menu" }, /* KELEM_MENU */
|
|
{ TAG_VOID, "meta" }, /* KELEM_META */
|
|
{ TAG_PHRASE, "meter" }, /* KELEM_METER */
|
|
{ TAG_FLOW, "nav" }, /* KELEM_NAV */
|
|
{ TAG_FLOW, "noscript" }, /* KELEM_NOSCRIPT */ /* XXX: TRANS */
|
|
{ TAG_FLOW, "object" }, /* KELEM_OBJECT */ /* XXX: TRANS */
|
|
{ TAG_FLOW, "ol" }, /* KELEM_OL */
|
|
{ TAG_FLOW, "optgroup" }, /* KELEM_OPTGROUP */
|
|
{ TAG_PHRASE, "option" }, /* KELEM_OPTION */
|
|
{ TAG_PHRASE, "output" }, /* KELEM_OUTPUT */
|
|
{ TAG_PHRASE, "p" }, /* KELEM_P */
|
|
{ TAG_VOID, "param" }, /* KELEM_PARAM */
|
|
{ TAG_PHRASE, "pre" }, /* KELEM_PRE */
|
|
{ TAG_PHRASE, "progress" }, /* KELEM_PROGRESS */
|
|
{ TAG_PHRASE, "q" }, /* KELEM_Q */
|
|
{ TAG_PHRASE, "rp" }, /* KELEM_RP */
|
|
{ TAG_PHRASE, "rt" }, /* KELEM_RT */
|
|
{ TAG_PHRASE, "ruby" }, /* KELEM_RUBY */
|
|
{ TAG_PHRASE, "s" }, /* KELEM_S */
|
|
{ TAG_PHRASE, "samp" }, /* KELEM_SAMP */
|
|
{ TAG_FLOW, "script" }, /* KELEM_SCRIPT */
|
|
{ TAG_FLOW, "section" }, /* KELEM_SECTION */
|
|
{ TAG_FLOW, "select" }, /* KELEM_SELECT */
|
|
{ TAG_PHRASE, "small" }, /* KELEM_SMALL */
|
|
{ TAG_VOID, "source" }, /* KELEM_SOURCE */
|
|
{ TAG_PHRASE, "span" }, /* KELEM_SPAN */
|
|
{ TAG_PHRASE, "strong" }, /* KELEM_STRONG */
|
|
{ TAG_FLOW, "style" }, /* KELEM_STYLE */
|
|
{ TAG_PHRASE, "sub" }, /* KELEM_SUB */
|
|
{ TAG_PHRASE, "summary" }, /* KELEM_SUMMARY */
|
|
{ TAG_PHRASE, "sup" }, /* KELEM_SUP */
|
|
{ TAG_FLOW, "table" }, /* KELEM_TABLE */
|
|
{ TAG_FLOW, "tbody" }, /* KELEM_TBODY */
|
|
{ TAG_FLOW, "td" }, /* KELEM_TD */
|
|
{ TAG_PHRASE, "textarea" }, /* KELEM_TEXTAREA */
|
|
{ TAG_FLOW, "tfoot" }, /* KELEM_TFOOT */
|
|
{ TAG_FLOW, "th" }, /* KELEM_TH */
|
|
{ TAG_FLOW, "thead" }, /* KELEM_THEAD */
|
|
{ TAG_PHRASE, "time" }, /* KELEM_TIME */
|
|
{ TAG_PHRASE, "title" }, /* KELEM_TITLE */
|
|
{ TAG_FLOW, "tr" }, /* KELEM_TR */
|
|
{ TAG_VOID, "track" }, /* KELEM_TRACK */
|
|
{ TAG_PHRASE, "u" }, /* KELEM_U */
|
|
{ TAG_FLOW, "ul" }, /* KELEM_UL */
|
|
{ TAG_PHRASE, "var" }, /* KELEM_VAR */
|
|
{ TAG_FLOW, "video" }, /* KELEM_VIDEO */ /* XXX: TRANS */
|
|
{ TAG_VOID, "wbr" }, /* KELEM_WBR */
|
|
};
|
|
|
|
static const char *const attrs[KATTR__MAX] = {
|
|
"accept-charset", /* KATTR_ACCEPT_CHARSET */
|
|
"accesskey", /* KATTR_ACCESSKEY */
|
|
"action", /* KATTR_ACTION */
|
|
"alt", /* KATTR_ALT */
|
|
"async", /* KATTR_ASYNC */
|
|
"autocomplete", /* KATTR_AUTOCOMPLETE */
|
|
"autofocus", /* KATTR_AUTOFOCUS */
|
|
"autoplay", /* KATTR_AUTOPLAY */
|
|
"border", /* KATTR_BORDER */
|
|
"challenge", /* KATTR_CHALLENGE */
|
|
"charset", /* KATTR_CHARSET */
|
|
"checked", /* KATTR_CHECKED */
|
|
"cite", /* KATTR_CITE */
|
|
"class", /* KATTR_CLASS */
|
|
"cols", /* KATTR_COLS */
|
|
"colspan", /* KATTR_COLSPAN */
|
|
"content", /* KATTR_CONTENT */
|
|
"contenteditable", /* KATTR_CONTENTEDITABLE */
|
|
"contextmenu", /* KATTR_CONTEXTMENU */
|
|
"controls", /* KATTR_CONTROLS */
|
|
"coords", /* KATTR_COORDS */
|
|
"datetime", /* KATTR_DATETIME */
|
|
"default", /* KATTR_DEFAULT */
|
|
"defer", /* KATTR_DEFER */
|
|
"dir", /* KATTR_DIR */
|
|
"dirname", /* KATTR_DIRNAME */
|
|
"disabled", /* KATTR_DISABLED */
|
|
"draggable", /* KATTR_DRAGGABLE */
|
|
"dropzone", /* KATTR_DROPZONE */
|
|
"enctype", /* KATTR_ENCTYPE */
|
|
"for", /* KATTR_FOR */
|
|
"form", /* KATTR_FORM */
|
|
"formaction", /* KATTR_FORMACTION */
|
|
"formenctype", /* KATTR_FORMENCTYPE */
|
|
"formmethod", /* KATTR_FORMMETHOD */
|
|
"formnovalidate", /* KATTR_FORMNOVALIDATE */
|
|
"formtarget", /* KATTR_FORMTARGET */
|
|
"header", /* KATTR_HEADER */
|
|
"height", /* KATTR_HEIGHT */
|
|
"hidden", /* KATTR_HIDDEN */
|
|
"high", /* KATTR_HIGH */
|
|
"href", /* KATTR_HREF */
|
|
"hreflang", /* KATTR_HREFLANG */
|
|
"http-equiv", /* KATTR_HTTP_EQUIV */
|
|
"icon", /* KATTR_ICON */
|
|
"id", /* KATTR_ID */
|
|
"ismap", /* KATTR_ISMAP */
|
|
"keytype", /* KATTR_KEYTYPE */
|
|
"kind", /* KATTR_KIND */
|
|
"label", /* KATTR_LABEL */
|
|
"lang", /* KATTR_LANG */
|
|
"language", /* KATTR_LANGUAGE */
|
|
"list", /* KATTR_LIST */
|
|
"loop", /* KATTR_LOOP */
|
|
"low", /* KATTR_LOW */
|
|
"manifest", /* KATTR_MANIFEST */
|
|
"max", /* KATTR_MAX */
|
|
"maxlength", /* KATTR_MAXLENGTH */
|
|
"media", /* KATTR_MEDIA */
|
|
"mediagroup", /* KATTR_MEDIAGROUP */
|
|
"method", /* KATTR_METHOD */
|
|
"min", /* KATTR_MIN */
|
|
"multiple", /* KATTR_MULTIPLE */
|
|
"muted", /* KATTR_MUTED */
|
|
"name", /* KATTR_NAME */
|
|
"novalidate", /* KATTR_NOVALIDATE */
|
|
"onabort", /* KATTR_ONABORT */
|
|
"onafterprint", /* KATTR_ONAFTERPRINT */
|
|
"onbeforeprint", /* KATTR_ONBEFOREPRINT */
|
|
"onbeforeunload", /* KATTR_ONBEFOREUNLOAD */
|
|
"onblur", /* KATTR_ONBLUR */
|
|
"oncanplay", /* KATTR_ONCANPLAY */
|
|
"oncanplaythrough", /* KATTR_ONCANPLAYTHROUGH */
|
|
"onchange", /* KATTR_ONCHANGE */
|
|
"onclick", /* KATTR_ONCLICK */
|
|
"oncontextmenu", /* KATTR_ONCONTEXTMENU */
|
|
"ondblclick", /* KATTR_ONDBLCLICK */
|
|
"ondrag", /* KATTR_ONDRAG */
|
|
"ondragend", /* KATTR_ONDRAGEND */
|
|
"ondragenter", /* KATTR_ONDRAGENTER */
|
|
"ondragleave", /* KATTR_ONDRAGLEAVE */
|
|
"ondragover", /* KATTR_ONDRAGOVER */
|
|
"ondragstart", /* KATTR_ONDRAGSTART */
|
|
"ondrop", /* KATTR_ONDROP */
|
|
"ondurationchange", /* KATTR_ONDURATIONCHANGE */
|
|
"onemptied", /* KATTR_ONEMPTIED */
|
|
"onended", /* KATTR_ONENDED */
|
|
"onerror", /* KATTR_ONERROR */
|
|
"onfocus", /* KATTR_ONFOCUS */
|
|
"onhashchange", /* KATTR_ONHASHCHANGE */
|
|
"oninput", /* KATTR_ONINPUT */
|
|
"oninvalid", /* KATTR_ONINVALID */
|
|
"onkeydown", /* KATTR_ONKEYDOWN */
|
|
"onkeypress", /* KATTR_ONKEYPRESS */
|
|
"onkeyup", /* KATTR_ONKEYUP */
|
|
"onload", /* KATTR_ONLOAD */
|
|
"onloadeddata", /* KATTR_ONLOADEDDATA */
|
|
"onloadedmetadata", /* KATTR_ONLOADEDMETADATA */
|
|
"onloadstart", /* KATTR_ONLOADSTART */
|
|
"onmessage", /* KATTR_ONMESSAGE */
|
|
"onmousedown", /* KATTR_ONMOUSEDOWN */
|
|
"onmousemove", /* KATTR_ONMOUSEMOVE */
|
|
"onmouseout", /* KATTR_ONMOUSEOUT */
|
|
"onmouseover", /* KATTR_ONMOUSEOVER */
|
|
"onmouseup", /* KATTR_ONMOUSEUP */
|
|
"onmousewheel", /* KATTR_ONMOUSEWHEEL */
|
|
"onoffline", /* KATTR_ONOFFLINE */
|
|
"ononline", /* KATTR_ONONLINE */
|
|
"onpagehide", /* KATTR_ONPAGEHIDE */
|
|
"onpageshow", /* KATTR_ONPAGESHOW */
|
|
"onpause", /* KATTR_ONPAUSE */
|
|
"onplay", /* KATTR_ONPLAY */
|
|
"onplaying", /* KATTR_ONPLAYING */
|
|
"onpopstate", /* KATTR_ONPOPSTATE */
|
|
"onprogress", /* KATTR_ONPROGRESS */
|
|
"onratechange", /* KATTR_ONRATECHANGE */
|
|
"onreadystatechange", /* KATTR_ONREADYSTATECHANGE */
|
|
"onreset", /* KATTR_ONRESET */
|
|
"onresize", /* KATTR_ONRESIZE */
|
|
"onscroll", /* KATTR_ONSCROLL */
|
|
"onseeked", /* KATTR_ONSEEKED */
|
|
"onseeking", /* KATTR_ONSEEKING */
|
|
"onselect", /* KATTR_ONSELECT */
|
|
"onshow", /* KATTR_ONSHOW */
|
|
"onstalled", /* KATTR_ONSTALLED */
|
|
"onstorage", /* KATTR_ONSTORAGE */
|
|
"onsubmit", /* KATTR_ONSUBMIT */
|
|
"onsuspend", /* KATTR_ONSUSPEND */
|
|
"ontimeupdate", /* KATTR_ONTIMEUPDATE */
|
|
"onunload", /* KATTR_ONUNLOAD */
|
|
"onvolumechange", /* KATTR_ONVOLUMECHANGE */
|
|
"onwaiting", /* KATTR_ONWAITING */
|
|
"open", /* KATTR_OPEN */
|
|
"optimum", /* KATTR_OPTIMUM */
|
|
"pattern", /* KATTR_PATTERN */
|
|
"placeholder", /* KATTR_PLACEHOLDER */
|
|
"poster", /* KATTR_POSTER */
|
|
"preload", /* KATTR_PRELOAD */
|
|
"radiogroup", /* KATTR_RADIOGROUP */
|
|
"readonly", /* KATTR_READONLY */
|
|
"rel", /* KATTR_REL */
|
|
"required", /* KATTR_REQUIRED */
|
|
"reversed", /* KATTR_REVERSED */
|
|
"rows", /* KATTR_ROWS */
|
|
"rowspan", /* KATTR_ROWSPAN */
|
|
"sandbox", /* KATTR_SANDBOX */
|
|
"scope", /* KATTR_SCOPE */
|
|
"seamless", /* KATTR_SEAMLESS */
|
|
"selected", /* KATTR_SELECTED */
|
|
"shape", /* KATTR_SHAPE */
|
|
"size", /* KATTR_SIZE */
|
|
"sizes", /* KATTR_SIZES */
|
|
"span", /* KATTR_SPAN */
|
|
"spellcheck", /* KATTR_SPELLCHECK */
|
|
"src", /* KATTR_SRC */
|
|
"srcdoc", /* KATTR_SRCDOC */
|
|
"srclang", /* KATTR_SRCLANG */
|
|
"start", /* KATTR_START */
|
|
"step", /* KATTR_STEP */
|
|
"style", /* KATTR_STYLE */
|
|
"tabindex", /* KATTR_TABINDEX */
|
|
"target", /* KATTR_TARGET */
|
|
"title", /* KATTR_TITLE */
|
|
"translate", /* KATTR_TRANSLATE */
|
|
"type", /* KATTR_TYPE */
|
|
"usemap", /* KATTR_USEMAP */
|
|
"value", /* KATTR_VALUE */
|
|
"width", /* KATTR_WIDTH */
|
|
"wrap", /* KATTR_WRAP */
|
|
};
|
|
|
|
size_t
|
|
khtml_elemat(struct khtmlreq *req)
|
|
{
|
|
|
|
return(req->elemsz);
|
|
}
|
|
|
|
void
|
|
khtml_elem(struct khtmlreq *req, enum kelem elem)
|
|
{
|
|
|
|
khtml_attr(req, elem, KATTR__MAX);
|
|
}
|
|
|
|
/*
|
|
* Open a tag.
|
|
* If we're a flow tag, emit a newline (unless already omitted).
|
|
* Then if we're at a newline regardless of tag type, indent properly to
|
|
* the point where we'll omit the tag name.
|
|
*/
|
|
static void
|
|
khtml_flow_open(struct khtmlreq *req, enum kelem elem)
|
|
{
|
|
size_t i;
|
|
|
|
if ( ! (KHTML_PRETTY & req->opts))
|
|
return;
|
|
|
|
if (TAG_FLOW == tags[elem].flags)
|
|
if ( ! req->newln) {
|
|
khttp_putc(req->req, '\n');
|
|
req->newln = 1;
|
|
}
|
|
|
|
if (req->newln)
|
|
for (i = 0; i < req->elemsz; i++)
|
|
khttp_puts(req->req, " ");
|
|
|
|
req->newln = 0;
|
|
}
|
|
|
|
/*
|
|
* If we're closing a flow or instruction tag, emit a newline.
|
|
* Otherwise do nothing.
|
|
*/
|
|
static void
|
|
khtml_flow_close(struct khtmlreq *req, enum kelem elem)
|
|
{
|
|
|
|
if ( ! (KHTML_PRETTY & req->opts))
|
|
return;
|
|
|
|
if (TAG_FLOW == tags[elem].flags ||
|
|
TAG_INSTRUCTION == tags[elem].flags) {
|
|
khttp_putc(req->req, '\n');
|
|
req->newln = 1;
|
|
} else
|
|
req->newln = 0;
|
|
}
|
|
|
|
void
|
|
khtml_attrx(struct khtmlreq *req, enum kelem elem, ...)
|
|
{
|
|
va_list ap;
|
|
enum kattr at;
|
|
|
|
khtml_flow_open(req, elem);
|
|
khttp_putc(req->req, '<');
|
|
khttp_puts(req->req, tags[elem].name);
|
|
|
|
va_start(ap, elem);
|
|
while (KATTR__MAX != (at = va_arg(ap, enum kattr))) {
|
|
khttp_putc(req->req, ' ');
|
|
khttp_puts(req->req, attrs[at]);
|
|
khttp_putc(req->req, '=');
|
|
khttp_putc(req->req, '"');
|
|
switch (va_arg(ap, enum kattrx)) {
|
|
case (KATTRX_STRING):
|
|
khtml_puts(req, va_arg(ap, char *));
|
|
break;
|
|
case (KATTRX_INT):
|
|
khtml_int(req, va_arg(ap, int64_t));
|
|
break;
|
|
case (KATTRX_DOUBLE):
|
|
khtml_double(req, va_arg(ap, double));
|
|
}
|
|
khttp_putc(req->req, '"');
|
|
}
|
|
va_end(ap);
|
|
|
|
if (TAG_VOID == tags[elem].flags)
|
|
khttp_putc(req->req, '/');
|
|
khttp_putc(req->req, '>');
|
|
khtml_flow_close(req, elem);
|
|
|
|
if (TAG_VOID != tags[elem].flags &&
|
|
TAG_INSTRUCTION != tags[elem].flags)
|
|
req->elems[req->elemsz++] = elem;
|
|
assert(req->elemsz < KDATA_MAXELEMSZ);
|
|
}
|
|
|
|
void
|
|
khtml_attr(struct khtmlreq *req, enum kelem elem, ...)
|
|
{
|
|
va_list ap;
|
|
enum kattr at;
|
|
const char *cp;
|
|
|
|
khtml_flow_open(req, elem);
|
|
khttp_putc(req->req, '<');
|
|
khttp_puts(req->req, tags[elem].name);
|
|
|
|
va_start(ap, elem);
|
|
while (KATTR__MAX != (at = va_arg(ap, enum kattr))) {
|
|
cp = va_arg(ap, char *);
|
|
assert(NULL != cp);
|
|
khttp_putc(req->req, ' ');
|
|
khttp_puts(req->req, attrs[at]);
|
|
khttp_putc(req->req, '=');
|
|
khttp_putc(req->req, '"');
|
|
khtml_puts(req, cp);
|
|
khttp_putc(req->req, '"');
|
|
|
|
}
|
|
va_end(ap);
|
|
|
|
if (TAG_VOID == tags[elem].flags)
|
|
khttp_putc(req->req, '/');
|
|
khttp_putc(req->req, '>');
|
|
khtml_flow_close(req, elem);
|
|
|
|
if (TAG_VOID != tags[elem].flags &&
|
|
TAG_INSTRUCTION != tags[elem].flags)
|
|
req->elems[req->elemsz++] = elem;
|
|
assert(req->elemsz < KDATA_MAXELEMSZ);
|
|
}
|
|
|
|
int
|
|
khtml_closeelem(struct khtmlreq *req, size_t sz)
|
|
{
|
|
size_t i;
|
|
|
|
if (0 == sz)
|
|
sz = req->elemsz;
|
|
|
|
for (i = 0; i < sz; i++) {
|
|
if (0 == req->elemsz)
|
|
return(0);
|
|
req->elemsz--;
|
|
khtml_flow_open(req, req->elems[req->elemsz]);
|
|
khttp_puts(req->req, "</");
|
|
khttp_puts(req->req, tags[req->elems[req->elemsz]].name);
|
|
khttp_putc(req->req, '>');
|
|
khtml_flow_close(req, req->elems[req->elemsz]);
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
int
|
|
khtml_closeto(struct khtmlreq *req, size_t pos)
|
|
{
|
|
|
|
if (pos > req->elemsz)
|
|
return(0);
|
|
return(khtml_closeelem(req, req->elemsz - pos));
|
|
}
|
|
|
|
void
|
|
khtml_entity(struct khtmlreq *req, enum kentity entity)
|
|
{
|
|
|
|
assert(entity < KENTITY__MAX);
|
|
khtml_ncr(req, entities[entity]);
|
|
}
|
|
|
|
void
|
|
khtml_ncr(struct khtmlreq *req, uint16_t ncr)
|
|
{
|
|
char buf[INT_MAXSZ];
|
|
|
|
(void)snprintf(buf, sizeof(buf), "%" PRIx16, ncr);
|
|
khttp_puts(req->req, "&#x");
|
|
khttp_puts(req->req, buf);
|
|
khttp_putc(req->req, ';');
|
|
}
|
|
|
|
void
|
|
khtml_double(struct khtmlreq *req, double val)
|
|
{
|
|
char buf[256];
|
|
|
|
(void)snprintf(buf, sizeof(buf), "%g", val);
|
|
khtml_puts(req, buf);
|
|
}
|
|
|
|
void
|
|
khtml_int(struct khtmlreq *req, int64_t val)
|
|
{
|
|
char buf[INT_MAXSZ];
|
|
|
|
(void)snprintf(buf, sizeof(buf), "%" PRId64, val);
|
|
khtml_puts(req, buf);
|
|
}
|
|
|
|
void
|
|
khtml_putc(struct khtmlreq *r, char c)
|
|
{
|
|
|
|
switch (c) {
|
|
case ('>'):
|
|
khtml_entity(r, KENTITY_gt);
|
|
break;
|
|
case ('&'):
|
|
khtml_entity(r, KENTITY_amp);
|
|
break;
|
|
case ('<'):
|
|
khtml_entity(r, KENTITY_lt);
|
|
break;
|
|
case ('"'):
|
|
khtml_entity(r, KENTITY_quot);
|
|
break;
|
|
case ('\''):
|
|
khtml_ncr(r, 39);
|
|
break;
|
|
default:
|
|
khttp_putc(r->req, c);
|
|
break;
|
|
}
|
|
}
|
|
|
|
int
|
|
khtml_write(const char *cp, size_t sz, void *arg)
|
|
{
|
|
struct khtmlreq *r = arg;
|
|
size_t i;
|
|
|
|
for (i = 0; i < sz; i++)
|
|
khtml_putc(r, cp[i]);
|
|
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
* Emit text in an HTML document.
|
|
* This means, minimally, that we need to escape the open and close
|
|
* delimiters for HTML tags.
|
|
*/
|
|
void
|
|
khtml_puts(struct khtmlreq *req, const char *cp)
|
|
{
|
|
|
|
req->newln = 0;
|
|
while ('\0' != *cp)
|
|
khtml_putc(req, *cp++);
|
|
}
|
|
|
|
|
|
/*
|
|
* Emit text in an HTML document.
|
|
* This means, minimally, that we need to escape the open and close
|
|
* delimiters for HTML tags.
|
|
*/
|
|
void
|
|
khtml_text(struct khtmlreq *req, const char *cp)
|
|
{
|
|
|
|
req->newln = 0;
|
|
while ('\0' != *cp)
|
|
khtml_putc(req, *cp++);
|
|
}
|
|
|
|
void
|
|
khtml_open(struct khtmlreq *r, struct kreq *req, int opts)
|
|
{
|
|
|
|
memset(r, 0, sizeof(struct khtmlreq));
|
|
r->req = req;
|
|
r->opts = opts;
|
|
}
|
|
|
|
int
|
|
khtml_close(struct khtmlreq *r)
|
|
{
|
|
int i;
|
|
|
|
i = r->elemsz;
|
|
khtml_closeelem(r, 0);
|
|
return(i);
|
|
}
|