ksgi

Форк
0
/
kcgihtml.c 
896 строк · 24.2 Кб
1
/*	$Id$ */
2
/*
3
 * Copyright (c) 2012--2021 Kristaps Dzonsons <kristaps@bsd.lv>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
#include "config.h"
18

19
#include <assert.h>
20
#include <inttypes.h>
21
#include <stdarg.h>
22
#include <stdint.h>
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26

27
#include "kcgi.h"
28
#include "kcgihtml.h"
29

30
/*
31
 * Maximum size of printing a signed 64-bit integer.
32
 */
33
#define	INT_MAXSZ	 22
34

35
/*
36
 * A type of HTML5 element.
37
 * Note: we don't list transitional elements, though I do note them in
38
 * the tag array.
39
 */
40
enum	htype {
41
	TAG_FLOW, /* flow (block) element */
42
	TAG_PHRASE,/* phrasing (inline) element */
43
	TAG_VOID, /* auto-closing (e.g., INPUT) */
44
	TAG_INSTRUCTION /* instruction */
45
};
46

47
/*
48
 * A tag describes an HTML element and its properties.
49
 */
50
struct	tag {
51
	enum htype	 flags; 
52
	const char	*name;
53
};
54

55
static	const uint16_t entities[KENTITY__MAX] = {
56
	198, /* KENTITY_AElig */
57
	193, /* KENTITY_Aacute */
58
	194, /* KENTITY_Acirc */
59
	192, /* KENTITY_Agrave */
60
	197, /* KENTITY_Aring */
61
	195, /* KENTITY_Atilde */
62
	196, /* KENTITY_Auml */
63
	199, /* KENTITY_Ccedil */
64
	8225, /* KENTITY_Dagger */
65
	208, /* KENTITY_ETH */
66
	201, /* KENTITY_Eacute */
67
	202, /* KENTITY_Ecirc */
68
	200, /* KENTITY_Egrave */
69
	203, /* KENTITY_Euml */
70
	205, /* KENTITY_Iacute */
71
	206, /* KENTITY_Icirc */
72
	204, /* KENTITY_Igrave */
73
	207, /* KENTITY_Iuml */
74
	209, /* KENTITY_Ntilde */
75
	338, /* KENTITY_OElig */
76
	211, /* KENTITY_Oacute */
77
	212, /* KENTITY_Ocirc */
78
	210, /* KENTITY_Ograve */
79
	216, /* KENTITY_Oslash */
80
	213, /* KENTITY_Otilde */
81
	214, /* KENTITY_Ouml */
82
	352, /* KENTITY_Scaron */
83
	222, /* KENTITY_THORN */
84
	218, /* KENTITY_Uacute */
85
	219, /* KENTITY_Ucirc */
86
	217, /* KENTITY_Ugrave */
87
	220, /* KENTITY_Uuml */
88
	221, /* KENTITY_Yacute */
89
	376, /* KENTITY_Yuml */
90
	225, /* KENTITY_aacute */
91
	226, /* KENTITY_acirc */
92
	180, /* KENTITY_acute */
93
	230, /* KENTITY_aelig */
94
	224, /* KENTITY_agrave */
95
	38, /* KENTITY_amp */
96
	39, /* KENTITY_apos */
97
	229, /* KENTITY_aring */
98
	227, /* KENTITY_atilde */
99
	228, /* KENTITY_auml */
100
	8222, /* KENTITY_bdquo */
101
	166, /* KENTITY_brvbar */
102
	231, /* KENTITY_ccedil */
103
	184, /* KENTITY_cedil */
104
	162, /* KENTITY_cent */
105
	710, /* KENTITY_circ */
106
	169, /* KENTITY_copy */
107
	164, /* KENTITY_curren */
108
	8224, /* KENTITY_dagger */
109
	176, /* KENTITY_deg */
110
	247, /* KENTITY_divide */
111
	233, /* KENTITY_eacute */
112
	234, /* KENTITY_ecirc */
113
	232, /* KENTITY_egrave */
114
	8195, /* KENTITY_emsp */
115
	8194, /* KENTITY_ensp */
116
	240, /* KENTITY_eth */
117
	235, /* KENTITY_euml */
118
	8364, /* KENTITY_euro */
119
	189, /* KENTITY_frac12 */
120
	188, /* KENTITY_frac14 */
121
	190, /* KENTITY_frac34 */
122
	62, /* KENTITY_gt */
123
	8230, /* KENTITY_hellip */
124
	237, /* KENTITY_iacute */
125
	238, /* KENTITY_icirc */
126
	161, /* KENTITY_iexcl */
127
	236, /* KENTITY_igrave */
128
	191, /* KENTITY_iquest */
129
	239, /* KENTITY_iuml */
130
	171, /* KENTITY_laquo */
131
	8220, /* KENTITY_ldquo */
132
	8206, /* KENTITY_lrm */
133
	8249, /* KENTITY_lsaquo */
134
	8216, /* KENTITY_lsquo */
135
	60, /* KENTITY_lt */
136
	175, /* KENTITY_macr */
137
	8212, /* KENTITY_mdash */
138
	181, /* KENTITY_micro */
139
	183, /* KENTITY_middot */
140
	160, /* KENTITY_nbsp */
141
	8211, /* KENTITY_ndash */
142
	172, /* KENTITY_not */
143
	241, /* KENTITY_ntilde */
144
	243, /* KENTITY_oacute */
145
	244, /* KENTITY_ocirc */
146
	339, /* KENTITY_oelig */
147
	242, /* KENTITY_ograve */
148
	170, /* KENTITY_ordf */
149
	186, /* KENTITY_ordm */
150
	248, /* KENTITY_oslash */
151
	245, /* KENTITY_otilde */
152
	246, /* KENTITY_ouml */
153
	182, /* KENTITY_para */
154
	8240, /* KENTITY_permil */
155
	177, /* KENTITY_plusmn */
156
	163, /* KENTITY_pound */
157
	34, /* KENTITY_quot */
158
	187, /* KENTITY_raquo */
159
	8221, /* KENTITY_rdquo */
160
	174, /* KENTITY_reg */
161
	8207, /* KENTITY_rlm */
162
	8250, /* KENTITY_rsaquo */
163
	8217, /* KENTITY_rsquo */
164
	8218, /* KENTITY_sbquo */
165
	353, /* KENTITY_scaron */
166
	167, /* KENTITY_sect */
167
	173, /* KENTITY_shy */
168
	185, /* KENTITY_sup1 */
169
	178, /* KENTITY_sup2 */
170
	179, /* KENTITY_sup3 */
171
	223, /* KENTITY_szlig */
172
	8201, /* KENTITY_thinsp */
173
	254, /* KENTITY_thorn */
174
	732, /* KENTITY_tilde */
175
	215, /* KENTITY_times */
176
	8482, /* KENTITY_trade */
177
	250, /* KENTITY_uacute */
178
	251, /* KENTITY_ucirc */
179
	249, /* KENTITY_ugrave */
180
	168, /* KENTITY_uml */
181
	252, /* KENTITY_uuml */
182
	253, /* KENTITY_yacute */
183
	165, /* KENTITY_yen */
184
	255, /* KENTITY_yuml */
185
	8205, /* KENTITY_zwj */
186
	8204, /* KENTITY_zwnj */
187
};
188

189
static	const struct tag tags[KELEM__MAX] = {
190
	{ TAG_PHRASE, "a" }, /* KELEM_A */ /* XXX: TRANS */
191
	{ TAG_PHRASE, "abbr" }, /* KELEM_ABBR */
192
	{ TAG_PHRASE, "address" }, /* KELEM_ADDRESS */
193
	{ TAG_VOID, "area" }, /* KELEM_AREA */
194
	{ TAG_FLOW, "article" }, /* KELEM_ARTICLE */
195
	{ TAG_FLOW, "aside" }, /* KELEM_ASIDE */
196
	{ TAG_FLOW, "audio" }, /* KELEM_AUDIO */ /* XXX: TRANS */
197
	{ TAG_PHRASE, "b" }, /* KELEM_B */
198
	{ TAG_VOID, "base" }, /* KELEM_BASE */
199
	{ TAG_PHRASE, "bdi" }, /* KELEM_BDI */
200
	{ TAG_PHRASE, "bdo" }, /* KELEM_BDO */
201
	{ TAG_FLOW, "blockquote" }, /* KELEM_BLOCKQUOTE */
202
	{ TAG_FLOW, "body" }, /* KELEM_BODY */
203
	{ TAG_VOID, "br" }, /* KELEM_BR */
204
	{ TAG_PHRASE, "button" }, /* KELEM_BUTTON */
205
	{ TAG_FLOW, "canvas" }, /* KELEM_CANVAS */ /* XXX: TRANS */
206
	{ TAG_FLOW, "caption" }, /* KELEM_CAPTION */
207
	{ TAG_PHRASE, "cite" }, /* KELEM_CITE */
208
	{ TAG_PHRASE, "code" }, /* KELEM_CODE */
209
	{ TAG_VOID, "col" }, /* KELEM_COL */
210
	{ TAG_PHRASE, "colgroup" }, /* KELEM_COLGROUP */
211
	{ TAG_PHRASE, "data" }, /* KELEM_DATA*/
212
	{ TAG_PHRASE, "datalist" }, /* KELEM_DATALIST */
213
	{ TAG_FLOW, "dd" }, /* KELEM_DD */
214
	{ TAG_PHRASE, "del" }, /* KELEM_DEL */ /* XXX: TRANS */
215
	{ TAG_FLOW, "details" }, /* KELEM_DETAILS */
216
	{ TAG_PHRASE, "dfn" }, /* KELEM_DFN */
217
	{ TAG_FLOW, "dialog" }, /* KELEM_DIALOG */
218
	{ TAG_FLOW, "div" }, /* KELEM_DIV */
219
	{ TAG_FLOW, "dl" }, /* KELEM_DL */
220
	{ TAG_INSTRUCTION, "!DOCTYPE html" }, /* KELEM_DOCTYPE */
221
	{ TAG_FLOW, "dt" }, /* KELEM_DT */
222
	{ TAG_PHRASE, "em" }, /* KELEM_EM */
223
	{ TAG_VOID, "embed" }, /* KELEM_EMBED */
224
	{ TAG_FLOW, "fieldset" }, /* KELEM_FIELDSET */
225
	{ TAG_FLOW, "figcaption" }, /* KELEM_FIGCAPTION */
226
	{ TAG_FLOW, "figure" }, /* KELEM_FIGURE */
227
	{ TAG_FLOW, "footer" }, /* KELEM_FOOTER */
228
	{ TAG_FLOW, "form" }, /* KELEM_FORM */
229
	{ TAG_PHRASE, "h1" }, /* KELEM_H1 */
230
	{ TAG_PHRASE, "h2" }, /* KELEM_H2 */
231
	{ TAG_PHRASE, "h3" }, /* KELEM_H3 */
232
	{ TAG_PHRASE, "h4" }, /* KELEM_H4 */
233
	{ TAG_PHRASE, "h5" }, /* KELEM_H5 */
234
	{ TAG_PHRASE, "h6" }, /* KELEM_H6 */
235
	{ TAG_FLOW, "head" }, /* KELEM_HEAD */
236
	{ TAG_FLOW, "header" }, /* KELEM_HEADER */
237
	{ TAG_FLOW, "hgroup" }, /* KELEM_HGROUP */
238
	{ TAG_VOID, "hr" }, /* KELEM_HR */
239
	{ TAG_FLOW, "html" }, /* KELEM_HTML */
240
	{ TAG_PHRASE, "i" }, /* KELEM_I */
241
	{ TAG_PHRASE, "iframe" }, /* KELEM_IFRAME */
242
	{ TAG_VOID, "img" }, /* KELEM_IMG */
243
	{ TAG_VOID, "input" }, /* KELEM_INPUT */
244
	{ TAG_PHRASE, "ins" }, /* KELEM_INS */ /* XXX: TRANS */
245
	{ TAG_PHRASE, "kbd" }, /* KELEM_KBD */
246
	{ TAG_VOID, "keygen" }, /* KELEM_KEYGEN */
247
	{ TAG_PHRASE, "label" }, /* KELEM_LABEL */
248
	{ TAG_PHRASE, "legend" }, /* KELEM_LEGEND */
249
	{ TAG_FLOW, "li" }, /* KELEM_LI */
250
	{ TAG_VOID, "link" }, /* KELEM_LINK */
251
	{ TAG_FLOW, "main" }, /* KELEM_MAIN */
252
	{ TAG_FLOW, "map" }, /* KELEM_MAP */ /* XXX: TRANS */
253
	{ TAG_PHRASE, "mark" }, /* KELEM_MARK */
254
	{ TAG_FLOW, "menu" }, /* KELEM_MENU */
255
	{ TAG_VOID, "meta" }, /* KELEM_META */
256
	{ TAG_PHRASE, "meter" }, /* KELEM_METER */
257
	{ TAG_FLOW, "nav" }, /* KELEM_NAV */
258
	{ TAG_FLOW, "noscript" }, /* KELEM_NOSCRIPT */ /* XXX: TRANS */
259
	{ TAG_FLOW, "object" }, /* KELEM_OBJECT */ /* XXX: TRANS */
260
	{ TAG_FLOW, "ol" }, /* KELEM_OL */
261
	{ TAG_FLOW, "optgroup" }, /* KELEM_OPTGROUP */
262
	{ TAG_PHRASE, "option" }, /* KELEM_OPTION */
263
	{ TAG_PHRASE, "output" }, /* KELEM_OUTPUT */
264
	{ TAG_PHRASE, "p" }, /* KELEM_P */
265
	{ TAG_VOID, "param" }, /* KELEM_PARAM */
266
	{ TAG_PHRASE, "picture" }, /* KELEM_PICTURE */ /* XXX: TRANS */
267
	{ TAG_PHRASE, "pre" }, /* KELEM_PRE */
268
	{ TAG_PHRASE, "progress" }, /* KELEM_PROGRESS */
269
	{ TAG_PHRASE, "q" }, /* KELEM_Q */
270
	{ TAG_PHRASE, "rb" }, /* KELEM_RB */
271
	{ TAG_PHRASE, "rp" }, /* KELEM_RP */
272
	{ TAG_PHRASE, "rt" }, /* KELEM_RT */
273
	{ TAG_PHRASE, "rtc" }, /* KELEM_RTC */
274
	{ TAG_PHRASE, "ruby" }, /* KELEM_RUBY */
275
	{ TAG_PHRASE, "s" }, /* KELEM_S */
276
	{ TAG_PHRASE, "samp" }, /* KELEM_SAMP */
277
	{ TAG_FLOW, "script" }, /* KELEM_SCRIPT */
278
	{ TAG_FLOW, "section" }, /* KELEM_SECTION */
279
	{ TAG_FLOW, "select" }, /* KELEM_SELECT */
280
	{ TAG_PHRASE, "small" }, /* KELEM_SMALL */
281
	{ TAG_VOID, "source" }, /* KELEM_SOURCE */
282
	{ TAG_PHRASE, "span" }, /* KELEM_SPAN */
283
	{ TAG_PHRASE, "strong" }, /* KELEM_STRONG */
284
	{ TAG_FLOW, "style" }, /* KELEM_STYLE */
285
	{ TAG_PHRASE, "sub" }, /* KELEM_SUB */
286
	{ TAG_PHRASE, "summary" }, /* KELEM_SUMMARY */
287
	{ TAG_PHRASE, "sup" }, /* KELEM_SUP */
288
	{ TAG_FLOW, "table" }, /* KELEM_TABLE */
289
	{ TAG_FLOW, "tbody" }, /* KELEM_TBODY */
290
	{ TAG_FLOW, "td" }, /* KELEM_TD */
291
	{ TAG_PHRASE, "textarea" }, /* KELEM_TEXTAREA */
292
	{ TAG_FLOW, "tfoot" }, /* KELEM_TFOOT */
293
	{ TAG_FLOW, "th" }, /* KELEM_TH */
294
	{ TAG_FLOW, "thead" }, /* KELEM_THEAD */
295
	{ TAG_PHRASE, "time" }, /* KELEM_TIME */
296
	{ TAG_PHRASE, "title" }, /* KELEM_TITLE */
297
	{ TAG_FLOW, "tr" }, /* KELEM_TR */
298
	{ TAG_VOID, "track" }, /* KELEM_TRACK */
299
	{ TAG_PHRASE, "u" }, /* KELEM_U */
300
	{ TAG_FLOW, "ul" }, /* KELEM_UL */
301
	{ TAG_PHRASE, "var" }, /* KELEM_VAR */
302
	{ TAG_FLOW, "video" }, /* KELEM_VIDEO */ /* XXX: TRANS */
303
	{ TAG_VOID, "wbr" }, /* KELEM_WBR */
304
};
305

306
static	const char *const attrs[KATTR__MAX] = {
307
	"accept-charset", /* KATTR_ACCEPT_CHARSET */
308
	"accesskey", /* KATTR_ACCESSKEY */
309
	"action", /* KATTR_ACTION */
310
	"allowfullscreen", /* KATTR_ALLOWFULLSCREEN */
311
	"allowpaymentrequest", /* KATTR_ALLOWPAYMENTREQUEST */
312
	"alt", /* KATTR_ALT */
313
	"async", /* KATTR_ASYNC */
314
	"autocomplete", /* KATTR_AUTOCOMPLETE */
315
	"autofocus", /* KATTR_AUTOFOCUS */
316
	"autoplay", /* KATTR_AUTOPLAY */
317
	"border", /* KATTR_BORDER */
318
	"challenge", /* KATTR_CHALLENGE */
319
	"charset", /* KATTR_CHARSET */
320
	"checked", /* KATTR_CHECKED */
321
	"cite", /* KATTR_CITE */
322
	"class", /* KATTR_CLASS */
323
	"cols", /* KATTR_COLS */
324
	"colspan", /* KATTR_COLSPAN */
325
	"content", /* KATTR_CONTENT */
326
	"contenteditable", /* KATTR_CONTENTEDITABLE */
327
	"contextmenu", /* KATTR_CONTEXTMENU */
328
	"controls", /* KATTR_CONTROLS */
329
	"coords", /* KATTR_COORDS */
330
	"crossorigin", /* KATTR_CROSSORIGIN */
331
	"data", /* KATTR_DATA */
332
	"datetime", /* KATTR_DATETIME */
333
	"default", /* KATTR_DEFAULT */
334
	"defer", /* KATTR_DEFER */
335
	"dir", /* KATTR_DIR */
336
	"dirname", /* KATTR_DIRNAME */
337
	"disabled", /* KATTR_DISABLED */
338
	"download", /* KATTR_DOWNLOAD */
339
	"draggable", /* KATTR_DRAGGABLE */
340
	"dropzone", /* KATTR_DROPZONE */
341
	"enctype", /* KATTR_ENCTYPE */
342
	"for", /* KATTR_FOR */
343
	"form", /* KATTR_FORM */
344
	"formaction", /* KATTR_FORMACTION */
345
	"formenctype", /* KATTR_FORMENCTYPE */
346
	"formmethod", /* KATTR_FORMMETHOD */
347
	"formnovalidate", /* KATTR_FORMNOVALIDATE */
348
	"formtarget", /* KATTR_FORMTARGET */
349
	"header", /* KATTR_HEADER */
350
	"headers", /* KATTR_HEADERS */
351
	"height", /* KATTR_HEIGHT */
352
	"hidden", /* KATTR_HIDDEN */
353
	"high", /* KATTR_HIGH */
354
	"href", /* KATTR_HREF */
355
	"hreflang", /* KATTR_HREFLANG */
356
	"http-equiv", /* KATTR_HTTP_EQUIV */
357
	"icon", /* KATTR_ICON */
358
	"id", /* KATTR_ID */
359
	"ismap", /* KATTR_ISMAP */
360
	"keytype", /* KATTR_KEYTYPE */
361
	"kind", /* KATTR_KIND */
362
	"label", /* KATTR_LABEL */
363
	"lang", /* KATTR_LANG */
364
	"language", /* KATTR_LANGUAGE */
365
	"list", /* KATTR_LIST */
366
	"longdesc", /* KATTR_LONGDESC */
367
	"loop", /* KATTR_LOOP */
368
	"low", /* KATTR_LOW */
369
	"manifest", /* KATTR_MANIFEST */
370
	"max", /* KATTR_MAX */
371
	"maxlength", /* KATTR_MAXLENGTH */
372
	"media", /* KATTR_MEDIA */
373
	"mediagroup", /* KATTR_MEDIAGROUP */
374
	"method", /* KATTR_METHOD */
375
	"min", /* KATTR_MIN */
376
	"minlength", /* KATTR_MINLENGTH */
377
	"multiple", /* KATTR_MULTIPLE */
378
	"muted", /* KATTR_MUTED */
379
	"name", /* KATTR_NAME */
380
	"nonce", /* KATTR_NONCE */
381
	"novalidate", /* KATTR_NOVALIDATE */
382
	"onabort", /* KATTR_ONABORT */
383
	"onafterprint", /* KATTR_ONAFTERPRINT */
384
	"onauxclick", /* KATTR_ONAUXCLICK */
385
	"onbeforeprint", /* KATTR_ONBEFOREPRINT */
386
	"onbeforeunload", /* KATTR_ONBEFOREUNLOAD */
387
	"onblur", /* KATTR_ONBLUR */
388
	"oncancel", /* KATTR_ONCANCEL */
389
	"oncanplay", /* KATTR_ONCANPLAY */
390
	"oncanplaythrough", /* KATTR_ONCANPLAYTHROUGH */
391
	"onchange", /* KATTR_ONCHANGE */
392
	"onclick", /* KATTR_ONCLICK */
393
	"onclose", /* KATTR_ONCLOSE */
394
	"oncontextmenu", /* KATTR_ONCONTEXTMENU */
395
	"oncuechange", /* KATTR_ONCUECHANGE */
396
	"oncut", /* KATTR_ONCUT */
397
	"ondblclick", /* KATTR_ONDBLCLICK */
398
	"ondrag", /* KATTR_ONDRAG */
399
	"ondragend", /* KATTR_ONDRAGEND */
400
	"ondragenter", /* KATTR_ONDRAGENTER */
401
	"ondragexit", /* KATTR_ONDRAGEXIT */
402
	"ondragleave", /* KATTR_ONDRAGLEAVE */
403
	"ondragover", /* KATTR_ONDRAGOVER */
404
	"ondragstart", /* KATTR_ONDRAGSTART */
405
	"ondrop", /* KATTR_ONDROP */
406
	"ondurationchange", /* KATTR_ONDURATIONCHANGE */
407
	"onemptied", /* KATTR_ONEMPTIED */
408
	"onended", /* KATTR_ONENDED */
409
	"onerror", /* KATTR_ONERROR */
410
	"onfocus", /* KATTR_ONFOCUS */
411
	"onhashchange", /* KATTR_ONHASHCHANGE */
412
	"oninput", /* KATTR_ONINPUT */
413
	"oninvalid", /* KATTR_ONINVALID */
414
	"onkeydown", /* KATTR_ONKEYDOWN */
415
	"onkeypress", /* KATTR_ONKEYPRESS */
416
	"onkeyup", /* KATTR_ONKEYUP */
417
	"onload", /* KATTR_ONLOAD */
418
	"onloadeddata", /* KATTR_ONLOADEDDATA */
419
	"onloadedmetadata", /* KATTR_ONLOADEDMETADATA */
420
	"onloadstart", /* KATTR_ONLOADSTART */
421
	"onmessage", /* KATTR_ONMESSAGE */
422
	"onmousedown", /* KATTR_ONMOUSEDOWN */
423
	"onmouseenter", /* KATTR_ONMOUSEENTER */
424
	"onmouseleave", /* KATTR_ONMOUSELEAVE */
425
	"onmousemove", /* KATTR_ONMOUSEMOVE */
426
	"onmouseout", /* KATTR_ONMOUSEOUT */
427
	"onmouseover", /* KATTR_ONMOUSEOVER */
428
	"onmouseup", /* KATTR_ONMOUSEUP */
429
	"onmousewheel", /* KATTR_ONMOUSEWHEEL */
430
	"onoffline", /* KATTR_ONOFFLINE */
431
	"ononline", /* KATTR_ONONLINE */
432
	"onpagehide", /* KATTR_ONPAGEHIDE */
433
	"onpageshow", /* KATTR_ONPAGESHOW */
434
	"onpaste", /* KATTR_ONPASTE */
435
	"onpause", /* KATTR_ONPAUSE */
436
	"onplay", /* KATTR_ONPLAY */
437
	"onplaying", /* KATTR_ONPLAYING */
438
	"onpopstate", /* KATTR_ONPOPSTATE */
439
	"onprogress", /* KATTR_ONPROGRESS */
440
	"onratechange", /* KATTR_ONRATECHANGE */
441
	"onreadystatechange", /* KATTR_ONREADYSTATECHANGE */
442
	"onreset", /* KATTR_ONRESET */
443
	"onresize", /* KATTR_ONRESIZE */
444
	"onscroll", /* KATTR_ONSCROLL */
445
	"onseeked", /* KATTR_ONSEEKED */
446
	"onseeking", /* KATTR_ONSEEKING */
447
	"onselect", /* KATTR_ONSELECT */
448
	"onshow", /* KATTR_ONSHOW */
449
	"onstalled", /* KATTR_ONSTALLED */
450
	"onstorage", /* KATTR_ONSTORAGE */
451
	"onsubmit", /* KATTR_ONSUBMIT */
452
	"onsuspend", /* KATTR_ONSUSPEND */
453
	"ontimeupdate", /* KATTR_ONTIMEUPDATE */
454
	"ontoggle", /* KATTR_ONTOGGLE */
455
	"onunload", /* KATTR_ONUNLOAD */
456
	"onvolumechange", /* KATTR_ONVOLUMECHANGE */
457
	"onwaiting", /* KATTR_ONWAITING */
458
	"onwheel", /* KATTR_ONWHEEL */
459
	"open", /* KATTR_OPEN */
460
	"optimum", /* KATTR_OPTIMUM */
461
	"pattern", /* KATTR_PATTERN */
462
	"placeholder", /* KATTR_PLACEHOLDER */
463
	"poster", /* KATTR_POSTER */
464
	"preload", /* KATTR_PRELOAD */
465
	"radiogroup", /* KATTR_RADIOGROUP */
466
	"readonly", /* KATTR_READONLY */
467
	"referrerpolicy", /* KATTR_REFERRERPOLICY */
468
	"rel", /* KATTR_REL */
469
	"required", /* KATTR_REQUIRED */
470
	"rev", /* KATTR_REV */
471
	"reversed", /* KATTR_REVERSED */
472
	"role", /* KATTR_ROLE */
473
	"rows", /* KATTR_ROWS */
474
	"rowspan", /* KATTR_ROWSPAN */
475
	"sandbox", /* KATTR_SANDBOX */
476
	"scope", /* KATTR_SCOPE */
477
	"seamless", /* KATTR_SEAMLESS */
478
	"selected", /* KATTR_SELECTED */
479
	"shape", /* KATTR_SHAPE */
480
	"size", /* KATTR_SIZE */
481
	"sizes", /* KATTR_SIZES */
482
	"span", /* KATTR_SPAN */
483
	"spellcheck", /* KATTR_SPELLCHECK */
484
	"src", /* KATTR_SRC */
485
	"srcdoc", /* KATTR_SRCDOC */
486
	"srclang", /* KATTR_SRCLANG */
487
	"srcset", /* KATTR_SRCSET */
488
	"start", /* KATTR_START */
489
	"step", /* KATTR_STEP */
490
	"style", /* KATTR_STYLE */
491
	"tabindex", /* KATTR_TABINDEX */
492
	"target", /* KATTR_TARGET */
493
	"title", /* KATTR_TITLE */
494
	"translate", /* KATTR_TRANSLATE */
495
	"type", /* KATTR_TYPE */
496
	"typemustmatch", /* KATTR_TYPEMUSTMATCH */
497
	"usemap", /* KATTR_USEMAP */
498
	"value", /* KATTR_VALUE */
499
	"width", /* KATTR_WIDTH */
500
	"wrap", /* KATTR_WRAP */
501
};
502

503
size_t
504
khtml_elemat(const struct khtmlreq *req)
505
{
506

507
	return req->elemsz;
508
}
509

510
enum kcgi_err
511
khtml_elem(struct khtmlreq *req, enum kelem elem)
512
{
513

514
	return khtml_attr(req, elem, KATTR__MAX);
515
}
516

517
/*
518
 * Open a tag---only used when pretty-printing and a noop otherwise.
519
 * If we're a flow tag, emit a newline (unless already omitted). 
520
 * Then if we're at a newline regardless of tag type, indent properly to
521
 * the point where we'll omit the tag name.
522
 */
523
static enum kcgi_err
524
khtml_flow_open(struct khtmlreq *req, enum kelem elem)
525
{
526
	size_t		 i;
527
	enum kcgi_err	 er;
528

529
	if ( ! (KHTML_PRETTY & req->opts))
530
		return(KCGI_OK);
531

532
	if (TAG_FLOW == tags[elem].flags && ! req->newln) {
533
		if (KCGI_OK != (er = kcgi_writer_putc(req->arg, '\n')))
534
			return(er);
535
		req->newln = 1;
536
	}
537

538
	if (req->newln)
539
		for (i = 0; i < req->elemsz; i++) 
540
			if (KCGI_OK != (er = 
541
			    kcgi_writer_puts(req->arg, "  ")))
542
				return(er);
543

544
	req->newln = 0;
545
	return(KCGI_OK);
546
}
547

548
/*
549
 * If we're pretty-printing and closing a flow or instruction tag, emit
550
 * a newline.
551
 * Otherwise do nothing.
552
 * Returns the usual write error code.
553
 */
554
static enum kcgi_err
555
khtml_flow_close(struct khtmlreq *req, enum kelem elem)
556
{
557
	enum kcgi_err	 er;
558

559
	if ( ! (KHTML_PRETTY & req->opts))
560
		return(KCGI_OK);
561

562
	if (TAG_FLOW == tags[elem].flags ||
563
	    TAG_INSTRUCTION == tags[elem].flags) {
564
		if (KCGI_OK != (er = kcgi_writer_putc(req->arg, '\n')))
565
			return(er);
566
		req->newln = 1;
567
	} else
568
		req->newln = 0;
569

570
	return(KCGI_OK);
571
}
572

573
enum kcgi_err
574
khtml_attrx(struct khtmlreq *req, enum kelem elem, ...)
575
{
576
	va_list		 ap;
577
	enum kattr	 at;
578
	enum kcgi_err	 er = KCGI_OK;
579

580
	if (tags[elem].flags != TAG_VOID &&
581
	    tags[elem].flags != TAG_INSTRUCTION &&
582
	    req->elemsz >= KHTML_STACK_MAX) {
583
		kutil_warnx(NULL, NULL, 
584
			"maximum html stack size exceeded");
585
		return KCGI_ENOMEM;
586
	}
587

588
	if ((er = khtml_flow_open(req, elem)) != KCGI_OK)
589
		return er;
590
	if ((er = kcgi_writer_putc(req->arg, '<')) != KCGI_OK)
591
		return er;
592
	if ((er = kcgi_writer_puts(req->arg, tags[elem].name)) != KCGI_OK)
593
		return er;
594

595
	va_start(ap, elem);
596
	while ((at = va_arg(ap, enum kattr)) != KATTR__MAX) {
597
		if ((er = kcgi_writer_putc(req->arg, ' ')) != KCGI_OK)
598
			goto out;
599
		if ((er = kcgi_writer_puts(req->arg, attrs[at])) != KCGI_OK)
600
			goto out;
601
		if ((er = kcgi_writer_puts(req->arg, "=\"")) != KCGI_OK)
602
			goto out;
603

604
		switch (va_arg(ap, enum kattrx)) {
605
		case KATTRX_STRING:
606
			er = khtml_puts(req, va_arg(ap, char *));
607
			break;
608
		case KATTRX_INT:
609
			er = khtml_int(req, va_arg(ap, int64_t));
610
			break;
611
		case KATTRX_DOUBLE:
612
			er = khtml_double(req, va_arg(ap, double));
613
			break;
614
		}
615
		if (er != KCGI_OK)
616
			goto out;
617
		if ((er = kcgi_writer_putc(req->arg, '"')) != KCGI_OK)
618
			goto out;
619
	}
620
	va_end(ap);
621

622
	if (tags[elem].flags == TAG_VOID &&
623
	    (er = kcgi_writer_putc(req->arg, '/')) != KCGI_OK)
624
		return er;
625
	if ((er = kcgi_writer_putc(req->arg, '>')) != KCGI_OK)
626
		return er;
627
	if ((er = khtml_flow_close(req, elem)) != KCGI_OK)
628
		return er;
629

630
	if (tags[elem].flags != TAG_VOID &&
631
	    tags[elem].flags != TAG_INSTRUCTION)
632
		req->elems[req->elemsz++] = elem;
633

634
	return KCGI_OK;
635
out:
636
	va_end(ap);
637
	return er;
638
}
639

640
enum kcgi_err
641
khtml_attr(struct khtmlreq *req, enum kelem elem, ...)
642
{
643
	va_list		 ap;
644
	enum kattr	 at;
645
	const char	*cp;
646
	enum kcgi_err	 er;
647

648
	if (tags[elem].flags != TAG_VOID &&
649
	    tags[elem].flags != TAG_INSTRUCTION &&
650
	    req->elemsz >= KHTML_STACK_MAX) {
651
		kutil_warnx(NULL, NULL, 
652
			"maximum html stack size exceeded");
653
		return KCGI_ENOMEM;
654
	}
655

656
	if ((er = khtml_flow_open(req, elem)) != KCGI_OK)
657
		return er;
658
	if ((er = kcgi_writer_putc(req->arg, '<')) != KCGI_OK)
659
		return er;
660
	if ((er = kcgi_writer_puts(req->arg, tags[elem].name)) != KCGI_OK)
661
		return er;
662

663
	va_start(ap, elem);
664
	while ((at = va_arg(ap, enum kattr)) != KATTR__MAX) {
665
		cp = va_arg(ap, char *);
666

667
		/*
668
		 * FIXME: shouldn't we allow situations where there's no
669
		 * value, like <option selected>?
670
		 * I don't know if this is valid XML.
671
		 * Meanwhile, don't let it happen.
672
		 */
673

674
		assert(cp != NULL);
675
		if ((er = kcgi_writer_putc(req->arg, ' ')) != KCGI_OK)
676
			goto out;
677
		if ((er = kcgi_writer_puts(req->arg, attrs[at])) != KCGI_OK)
678
			goto out;
679
		if ((er = kcgi_writer_puts(req->arg, "=\"")) != KCGI_OK)
680
			goto out;
681
		if ((er = khtml_puts(req, cp)) != KCGI_OK)
682
			goto out;
683
		if ((er = kcgi_writer_putc(req->arg, '"')) != KCGI_OK)
684
			goto out;
685

686
	}
687
	va_end(ap);
688

689
	if (tags[elem].flags == TAG_VOID &&
690
	    (er = kcgi_writer_putc(req->arg, '/')) != KCGI_OK)
691
		return er;
692
	if ((er = kcgi_writer_putc(req->arg, '>')) != KCGI_OK)
693
		return er;
694
	if ((er = khtml_flow_close(req, elem)) != KCGI_OK)
695
		return er;
696

697
	if (tags[elem].flags != TAG_VOID &&
698
	    tags[elem].flags != TAG_INSTRUCTION)
699
		req->elems[req->elemsz++] = elem;
700

701
	return KCGI_OK;
702
out:
703
	va_end(ap);
704
	return er;
705
}
706

707
enum kcgi_err
708
khtml_closeelem(struct khtmlreq *req, size_t sz)
709
{
710
	size_t		 i;
711
	enum kcgi_err	 er;
712

713
	if (sz == 0)
714
		sz = req->elemsz;
715
	if (sz > req->elemsz)
716
		sz = req->elemsz;
717

718
	for (i = 0; i < sz; i++) {
719
		assert(req->elemsz);
720
		req->elemsz--;
721
		er = khtml_flow_open(req, req->elems[req->elemsz]);
722
		if (er != KCGI_OK)
723
			return er;
724
		er = kcgi_writer_puts(req->arg, "</");
725
		if (er != KCGI_OK)
726
			return er;
727
		er = kcgi_writer_puts(req->arg,
728
			tags[req->elems[req->elemsz]].name);
729
		if (er != KCGI_OK)
730
			return er;
731
		er = kcgi_writer_putc(req->arg, '>');
732
		if (er != KCGI_OK)
733
			return er;
734
		er = khtml_flow_close(req, req->elems[req->elemsz]);
735
		if (er != KCGI_OK)
736
			return er;
737
	}
738

739
	return KCGI_OK;
740
}
741

742
enum kcgi_err
743
khtml_closeto(struct khtmlreq *req, size_t pos)
744
{
745

746
	if (pos >= req->elemsz)
747
		return KCGI_OK;
748
	return khtml_closeelem(req, req->elemsz - pos);
749
}
750

751
enum kcgi_err
752
khtml_entity(struct khtmlreq *req, enum kentity entity)
753
{
754

755
	assert(entity < KENTITY__MAX);
756
	return khtml_ncr(req, entities[entity]);
757
}
758

759
enum kcgi_err
760
khtml_ncr(struct khtmlreq *req, uint32_t ncr)
761
{
762
	char	 	 buf[INT_MAXSZ];
763
	enum kcgi_err	 er;
764

765
	/* 
766
	 * Don't check whether ncr is a valid unicode entity.
767
	 * Right now these only go up to 150 000 or so.
768
	 */
769

770
	snprintf(buf, sizeof(buf), "%" PRIx32, ncr);
771
	if ((er = kcgi_writer_puts(req->arg, "&#x")) != KCGI_OK)
772
		return er;
773
	if ((er = kcgi_writer_puts(req->arg, buf)) != KCGI_OK)
774
		return er;
775
	return kcgi_writer_putc(req->arg, ';');
776
}
777

778
enum kcgi_err
779
khtml_double(struct khtmlreq *req, double val)
780
{
781
	char	 buf[256];
782

783
	(void)snprintf(buf, sizeof(buf), "%g", val);
784
	return(khtml_puts(req, buf));
785
}
786

787
enum kcgi_err
788
khtml_int(struct khtmlreq *req, int64_t val)
789
{
790
	char	 buf[INT_MAXSZ];
791

792
	(void)snprintf(buf, sizeof(buf), "%" PRId64, val);
793
	return(khtml_puts(req, buf));
794
}
795

796
enum kcgi_err
797
khtml_putc(struct khtmlreq *r, char c)
798
{
799
	enum kcgi_err	 er;
800

801
	switch (c) {
802
	case ('>'):
803
		er = khtml_entity(r, KENTITY_gt);
804
		break;
805
	case ('&'):
806
		er = khtml_entity(r, KENTITY_amp);
807
		break;
808
	case ('<'):
809
		er = khtml_entity(r, KENTITY_lt);
810
		break;
811
	case ('"'):
812
		er = khtml_entity(r, KENTITY_quot);
813
		break;
814
	case ('\''):
815
		er = khtml_ncr(r, 39);
816
		break;
817
	default:
818
		er = kcgi_writer_putc(r->arg, c);
819
		break;
820
	}
821

822
	return(er);
823
}
824

825
enum kcgi_err
826
khtml_write(const char *cp, size_t sz, void *arg)
827
{
828
	struct khtmlreq	*r = arg;
829
	size_t		 i;
830
	enum kcgi_err	 er;
831

832
	if (cp == NULL || sz == 0)
833
		return KCGI_OK;
834

835
	for (i = 0; i < sz; i++) 
836
		if ((er = khtml_putc(r, cp[i])) != KCGI_OK)
837
			return er;
838

839
	return KCGI_OK;
840
}
841

842
enum kcgi_err
843
khtml_printf(struct khtmlreq *req, const char *fmt, ...)
844
{
845
	char		*buf;
846
	int		 len;
847
	va_list		 ap;
848
	enum kcgi_err	 er;
849

850
	if (fmt == NULL)
851
		return KCGI_OK;
852

853
	va_start(ap, fmt);
854
	len = vasprintf(&buf, fmt, ap);
855
	va_end(ap);
856

857
	if (len < 0)
858
		return KCGI_ENOMEM;
859

860
	er = khtml_write(buf, (size_t)len, req);
861
	free(buf);
862
	return er;
863
}
864

865
enum kcgi_err
866
khtml_puts(struct khtmlreq *req, const char *cp)
867
{
868

869
	if (cp == NULL)
870
		return KCGI_OK;
871
	return khtml_write(cp, strlen(cp), req);
872
}
873

874

875
enum kcgi_err
876
khtml_open(struct khtmlreq *r, struct kreq *req, int opts)
877
{
878

879
	memset(r, 0, sizeof(struct khtmlreq));
880
	if ((r->arg = kcgi_writer_get(req, 0)) == NULL)
881
		return KCGI_ENOMEM;
882

883
	r->opts = opts;
884
	return KCGI_OK;
885
}
886

887
enum kcgi_err
888
khtml_close(struct khtmlreq *r)
889
{
890
	enum kcgi_err	 er;
891

892
	er = khtml_closeelem(r, 0);
893
	kcgi_writer_free(r->arg);
894
	r->arg = NULL;
895
	return er;
896
}
897

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.