38#ifndef XML_STATUS_ERROR
39#define XML_STATUS_ERROR 0
71 agerrorf(
"Unknown HTML element <%s> on line %lu \n", name,
76static int icmp(
const void *name,
const void *
item) {
77 const char *
const *
const j =
item;
78 return strcasecmp(name, *j);
81static int bgcolorfn(
htmldata_t *p,
const char *v) {
86static int pencolorfn(
htmldata_t *p,
const char *v) {
91static int hreffn(
htmldata_t *p,
const char *v) {
96static int sidesfn(
htmldata_t *p,
const char *v) {
97 unsigned short flags = 0;
115 agwarningf(
"Unrecognized character '%c' (%d) in sides attribute\n", c, c);
124static int titlefn(
htmldata_t *p,
const char *v) {
125 p->
title = strdup(v);
129static int portfn(
htmldata_t *p,
const char *v) {
136static int stylefn(
htmldata_t *p,
const char *v) {
155 agwarningf(
"Illegal value %.*s for STYLE - ignored\n", (
int)tk.
size,
163static int targetfn(
htmldata_t *p,
const char *v) {
168static int idfn(
htmldata_t *p,
const char *v) {
179static int doInt(
const char *v,
char *
s,
int min,
int max,
long *ul) {
182 long b = strtol(v, &ep, 10);
185 agwarningf(
"Improper %s value %s - ignored",
s, v);
187 }
else if (b > max) {
188 agwarningf(
"%s value %s > %d - too large - ignored",
s, v, max);
190 }
else if (b < min) {
191 agwarningf(
"%s value %s < %d - too small - ignored",
s, v, min);
198static int gradientanglefn(
htmldata_t *p,
const char *v) {
201 if (doInt(v,
"GRADIENTANGLE", 0, 360, &u))
207static int borderfn(
htmldata_t *p,
const char *v) {
210 if (doInt(v,
"BORDER", 0, UCHAR_MAX, &u))
212 p->
border = (
unsigned char)u;
217static int cellpaddingfn(
htmldata_t *p,
const char *v) {
220 if (doInt(v,
"CELLPADDING", 0, UCHAR_MAX, &u))
222 p->
pad = (
unsigned char)u;
227static int cellspacingfn(
htmldata_t *p,
const char *v) {
230 if (doInt(v,
"CELLSPACING", SCHAR_MIN, SCHAR_MAX, &u))
232 p->
space = (
signed char)u;
237static int cellborderfn(
htmldata_t *data,
const char *v) {
242 if (doInt(v,
"CELLBORDER", 0,
INT8_MAX, &u))
248static int columnsfn(
htmldata_t *data,
const char *v) {
252 agwarningf(
"Unknown value %s for COLUMNS - ignored\n", v);
259static int rowsfn(
htmldata_t *data,
const char *v) {
263 agwarningf(
"Unknown value %s for ROWS - ignored\n", v);
270static int fixedsizefn(
htmldata_t *p,
const char *v) {
272 if (!strcasecmp(v,
"TRUE"))
274 else if (strcasecmp(v,
"FALSE")) {
275 agwarningf(
"Illegal value %s for FIXEDSIZE - ignored\n", v);
281static int valignfn(
htmldata_t *p,
const char *v) {
283 if (!strcasecmp(v,
"BOTTOM"))
285 else if (!strcasecmp(v,
"TOP"))
287 else if (strcasecmp(v,
"MIDDLE")) {
288 agwarningf(
"Illegal value %s for VALIGN - ignored\n", v);
294static int halignfn(
htmldata_t *p,
const char *v) {
296 if (!strcasecmp(v,
"LEFT"))
298 else if (!strcasecmp(v,
"RIGHT"))
300 else if (strcasecmp(v,
"CENTER")) {
301 agwarningf(
"Illegal value %s for ALIGN - ignored\n", v);
307static int cell_halignfn(
htmldata_t *p,
const char *v) {
309 if (!strcasecmp(v,
"LEFT"))
311 else if (!strcasecmp(v,
"RIGHT"))
313 else if (!strcasecmp(v,
"TEXT"))
315 else if (strcasecmp(v,
"CENTER"))
318 agwarningf(
"Illegal value %s for ALIGN in TD - ignored\n", v);
322static int balignfn(
htmldata_t *p,
const char *v) {
324 if (!strcasecmp(v,
"LEFT"))
326 else if (!strcasecmp(v,
"RIGHT"))
328 else if (strcasecmp(v,
"CENTER"))
331 agwarningf(
"Illegal value %s for BALIGN in TD - ignored\n", v);
335static int heightfn(
htmldata_t *p,
const char *v) {
338 if (doInt(v,
"HEIGHT", 0, USHRT_MAX, &u))
340 p->
height = (
unsigned short)u;
344static int widthfn(
htmldata_t *p,
const char *v) {
347 if (doInt(v,
"WIDTH", 0, USHRT_MAX, &u))
349 p->
width = (
unsigned short)u;
353static int rowspanfn(
htmldata_t *data,
const char *v) {
361 agwarningf(
"ROWSPAN value cannot be 0 - ignored\n");
368static int colspanfn(
htmldata_t *data,
const char *v) {
376 agwarningf(
"COLSPAN value cannot be 0 - ignored\n");
383static int fontcolorfn(
textfont_t *p,
const char *v) {
385 p->
color = (
char *)v;
389static int facefn(
textfont_t *p,
const char *v) {
395static int ptsizefn(
textfont_t *p,
const char *v) {
398 if (doInt(v,
"POINT-SIZE", 0, UCHAR_MAX, &u))
404static int srcfn(
htmlimg_t *p,
const char *v) {
409static int scalefn(
htmlimg_t *p,
const char *v) {
410 p->
scale = strdup(v);
414static int alignfn(
int *p,
const char *v) {
416 if (!strcasecmp(v,
"RIGHT"))
418 else if (!strcasecmp(v,
"LEFT"))
420 else if (!strcasecmp(v,
"CENTER"))
423 agwarningf(
"Illegal value %s for ALIGN - ignored\n", v);
436static const html_item_t tbl_items[] = {
438 {
"bgcolor", bgcolorfn},
439 {
"border", borderfn},
440 {
"cellborder", cellborderfn},
441 {
"cellpadding", cellpaddingfn},
442 {
"cellspacing", cellspacingfn},
443 {
"color", pencolorfn},
444 {
"columns", columnsfn},
445 {
"fixedsize", fixedsizefn},
446 {
"gradientangle", gradientanglefn},
447 {
"height", heightfn},
454 {
"target", targetfn},
456 {
"tooltip", titlefn},
457 {
"valign", valignfn},
461static const html_item_t cell_items[] = {
462 {
"align", cell_halignfn},
463 {
"balign", balignfn},
464 {
"bgcolor", bgcolorfn},
465 {
"border", borderfn},
466 {
"cellpadding", cellpaddingfn},
467 {
"cellspacing", cellspacingfn},
468 {
"color", pencolorfn},
469 {
"colspan", colspanfn},
470 {
"fixedsize", fixedsizefn},
471 {
"gradientangle", gradientanglefn},
472 {
"height", heightfn},
476 {
"rowspan", rowspanfn},
479 {
"target", targetfn},
481 {
"tooltip", titlefn},
482 {
"valign", valignfn},
492static const font_item_t font_items[] = {
493 {
"color", fontcolorfn},
495 {
"point-size", ptsizefn},
504static const img_item_t img_items[] = {
511 int (*action)(
int *,
const char *);
514static const br_item_t br_items[] = {
522#define CALL_ACTION(list, elem, tp, val) \
524 const html_item_t *: (const html_item_t *)(elem), \
525 const font_item_t *: (const font_item_t *)(elem), \
526 const img_item_t *: (const img_item_t *)(elem), \
527 const br_item_t *: (const br_item_t *)(elem)) \
528 ->action((tp), (val)))
538#define doAttrs(ctx, tp, items, nel, atts, s) \
542 while ((name = *(atts)++) != NULL) { \
543 const char *val = *(atts)++; \
545 bsearch(name, (items), (nel), sizeof((items)[0]), icmp); \
547 (ctx)->warn |= CALL_ACTION((items), ip, (tp), val); \
549 agwarningf("Illegal attribute %s in %s - ignored\n", name, (s)); \
557 doAttrs(ctx, &ctx->
htmllval->
i, br_items,
558 sizeof(br_items) /
sizeof(br_items[0]), atts,
"<BR>");
564 doAttrs(ctx, img, img_items,
sizeof(img_items) /
sizeof(img_items[0]), atts,
571 unsigned char flags) {
576 assert(
flags <= FLAGS_MAX);
577 tf.
flags = (
unsigned char)(
flags & FLAGS_MAX);
579 doAttrs(ctx, &tf, font_items,
sizeof(font_items) /
sizeof(font_items[0]),
590 doAttrs(ctx, &
cell->data, cell_items,
591 sizeof(cell_items) /
sizeof(cell_items[0]), atts,
"<TD>");
602 doAttrs(ctx, &tbl->
data, tbl_items,
sizeof(tbl_items) /
sizeof(tbl_items[0]),
608static void startElement(
void *user,
const char *name,
const char **atts) {
611 if (strcasecmp(name,
"TABLE") == 0) {
615 }
else if (strcasecmp(name,
"TR") == 0 || strcasecmp(name,
"TH") == 0) {
618 }
else if (strcasecmp(name,
"TD") == 0) {
622 }
else if (strcasecmp(name,
"FONT") == 0) {
625 }
else if (strcasecmp(name,
"B") == 0) {
628 }
else if (strcasecmp(name,
"S") == 0) {
631 }
else if (strcasecmp(name,
"U") == 0) {
634 }
else if (strcasecmp(name,
"O") == 0) {
637 }
else if (strcasecmp(name,
"I") == 0) {
640 }
else if (strcasecmp(name,
"SUP") == 0) {
643 }
else if (strcasecmp(name,
"SUB") == 0) {
646 }
else if (strcasecmp(name,
"BR") == 0) {
649 }
else if (strcasecmp(name,
"HR") == 0) {
651 }
else if (strcasecmp(name,
"VR") == 0) {
653 }
else if (strcasecmp(name,
"IMG") == 0) {
656 }
else if (strcasecmp(name,
"HTML") == 0) {
663static void endElement(
void *user,
const char *name) {
666 if (strcasecmp(name,
"TABLE") == 0) {
669 }
else if (strcasecmp(name,
"TR") == 0 || strcasecmp(name,
"TH") == 0) {
671 }
else if (strcasecmp(name,
"TD") == 0) {
674 }
else if (strcasecmp(name,
"HTML") == 0) {
676 }
else if (strcasecmp(name,
"FONT") == 0) {
678 }
else if (strcasecmp(name,
"B") == 0) {
680 }
else if (strcasecmp(name,
"U") == 0) {
682 }
else if (strcasecmp(name,
"O") == 0) {
684 }
else if (strcasecmp(name,
"I") == 0) {
686 }
else if (strcasecmp(name,
"SUP") == 0) {
688 }
else if (strcasecmp(name,
"SUB") == 0) {
690 }
else if (strcasecmp(name,
"S") == 0) {
692 }
else if (strcasecmp(name,
"BR") == 0) {
697 }
else if (strcasecmp(name,
"HR") == 0) {
702 }
else if (strcasecmp(name,
"VR") == 0) {
707 }
else if (strcasecmp(name,
"IMG") == 0) {
724static void characterData(
void *user,
const char *
s,
int length) {
731 for (i =
length; i; i--) {
759 XML_SetUserData(ctx->parser, ctx);
760 XML_SetElementHandler(ctx->parser, startElement, endElement);
761 XML_SetCharacterDataHandler(ctx->parser, characterData);
769 static atomic_flag first;
770 if (!atomic_flag_test_and_set(&first)) {
771 agwarningf(
"Not built with libexpat. Table formatting is not available.\n");
781 XML_ParserFree(ctx->parser);
812 while (depth && (c = *
s++)) {
839 t = eatComment(ctx, t + 3);
841 while (*t && *t !=
'>')
844 agwarningf(
"Label closed before end of HTML element\n");
850 while ((c = *t) && c !=
'<') {
851 if (c ==
'&' && *(t + 1) !=
'#') {
878static void protect_rsqb(
agxbuf *xb) {
887 size_t size = strlen(data);
889 if (data[size - 1] !=
']') {
895 data[size - 1] =
'\0';
909 return XML_GetCurrentLineNumber(ctx->parser);
1040 const char *token_text =
agxbuse(ctx->
xb);
1041 fprintf(stderr,
"%s \"%s\"\n",
s, token_text);
1044 fprintf(stderr,
"%s\n",
s);
1051 static char *begin_html =
"<HTML>";
1052 static char *end_html =
"</HTML>";
1065 if (ctx->
mode == 0) {
1077 endp = findNext(ctx,
s, &ctx->
lb);
1078 len = (size_t)(endp -
s);
1082 protect_rsqb(&ctx->
lb);
1087 assert(llen <= INT_MAX &&
"XML token too long for expat API");
1088 rv = XML_Parse(ctx->parser,
agxbuse(&ctx->
lb), (
int)llen, 0);
1090 assert(
len <= INT_MAX &&
"XML token too long for expat API");
1091 rv = XML_Parse(ctx->parser,
s, (
int)
len,
len ? 0 : 1);
1096 XML_ErrorString(XML_GetErrorCode(ctx->parser)),
1105 }
while (ctx->
tok == 0);
1107 printTok(ctx, ctx->
tok);
static void agxbfree(agxbuf *xb)
free any malloced resources
static WUR char * agxbuse(agxbuf *xb)
static size_t agxblen(const agxbuf *xb)
return number of characters currently stored
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Memory allocation wrappers that exit on failure.
static char * gv_strdup(const char *original)
static void * gv_alloc(size_t size)
char * scanEntity(char *t, agxbuf *xb)
static Extype_t length(Exid_t *rhs, Exdisc_t *disc)
static double len(glCompPoint p)
static int cnt(Dict_t *d, Dtlink_t **set)
void agwarningf(const char *fmt,...)
void agerrorf(const char *fmt,...)
int agerr(agerrlevel_t level, const char *fmt,...)
replacements for ctype.h functions
static char gv_tolower(int c)
int htmllex(union HTMLSTYPE *htmllval, htmlscan_t *scanner)
static UNUSED void agxbput_move(agxbuf *dst, const char *src)
agxbput, but assume that source and destination may overlap
unsigned long htmllineno(htmlscan_t *scanner)
static void error_context(htmllexstate_t *ctx)
int clearHTMLlexer(htmlscan_t *scanner)
int initHTMLlexer(htmlscan_t *scanner, char *src, agxbuf *xb, htmlenv_t *env)
void htmlerror(htmlscan_t *scanner, const char *msg)
static unsigned long htmllineno_ctx(htmllexstate_t *ctx)
static void free_ritem(row_t *p)
Free row. This closes and frees row’s list, then the item itself is freed.
static bool startswith(const char *s, const char *prefix)
does the string s begin with the string prefix?
platform abstraction for case-insensitive string functions
result of partitioning available space, part of maze
size_t row_count
number of rows
bool hrule
horizontal rule
a non-owning string reference
const char * data
start of the pointed to string
size_t size
extent of the string in bytes
state for an in-progress string tokenization
Non-owning string references.
static bool strview_case_str_eq(strview_t a, const char *b)
compare a string reference to a string for case insensitive equality
#define GV_TEXTFONT_FLAGS_WIDTH
static strview_t tok_get(const tok_t *t)
get the current token
static tok_t tok(const char *input, const char *separators)
begin tokenization of a new string
static bool tok_end(const tok_t *t)
is this tokenizer exhausted?
static void tok_next(tok_t *t)
advance to the next token in the string being scanned
abstraction for squashing compiler warnings for unused symbols