/* HTMLwriter.c -- HTML output for WWW nodes * $Id: SGMLmain.c,v 1.3 93/01/06 18:40:27 connolly Exp Locker: connolly $ */ /* implements ... */ #include "HTMLwriter.h" /* uses ... */ #include "HTMLdtd.h" #include "SGML.h" #include #include "object.h" /* prototypes for private functions... */ static HMWriterProc htmlwriter_new; static HMDeleteProc htmlwriter_dt; static HMStartTagProc start_tag; static HMEndTagProc end_tag; static HMDataProc data; HMDoc_Class HTMLwriter = {0, htmlwriter_new, htmlwriter_dt, start_tag, end_tag, data, html_entity_text}; typedef struct{ HMStream out; HMWriteProc *write; enum {start, html, head, body} state; }STR; #define STR_puts(s, chars) ((s)->write)((s)->out, (chars), strlen(chars)); static HMDoc* htmlwriter_new(out, write) HMStream out; HMWriteProc* write; { STR* s = NEW(STR, 1); s->out = out; s->write = write; s->state = start; return (HMDoc*)s; } static VOID htmlwriter_dt(this) HMDoc* this; { FREE(this); } static VOID data(document, chars, nchars) HMDoc* document; CONST char* chars; int nchars; { STR* s = (STR*)document; char* out; if(nchars>0){ int len; /* fake tag minimization. * This is a non-conforming error handling mechanism. * But it's expedient. */ switch(s->state){ case start: start_tag(document, "HTML", 0, 0); case html: start_tag(document, "BODY", 0, 0); break; case head: return; /* data in HEAD tag is an error */ } len = SGML_replen(chars, "<>&"); out = NEW(char, len + 1); SGML_repcpy(out, chars, "<>&"); (s->write)(s->out, (VOIDPTR)out, (unsigned)len); FREE(out); } } static VOID end_tag(document, gi) HMDoc* document; CONST char* gi; { STR* s = (STR*)document; /* * This is a non-conforming error handling mechanism. * But it's expedient.@@ */ if(!strcmp(gi, "HEAD") || !strcmp(gi, "BODY")) s->state = html; else if (!strcmp(gi, "HTML")) s->state = start; (s->write)(s->out, "\nwrite)(s->out, ">", 1); } static int start_tag(document, gi, attributes, nattrs) HMDoc* document; CONST char* gi; CONST HMBinding attributes[]; int nattrs; { STR* s = (STR*)document; int i, len; char literal[SGML_LITLEN*6]; int content = HTML_content(gi); /* @@ fake tag minimization */ if(!strcmp(gi, "HTML")) s->state = html; if(!strcmp(gi, "HEAD")) s->state = head; else if (!strcmp(gi, "BODY")) s->state = body; (s->write)(s->out, "<", 1); STR_puts(s, gi); for(i = 0; iwrite)(s->out, " ", 1); STR_puts(s, name); (s->write)(s->out, "=\"", 2); STR_puts(s, literal); (s->write)(s->out, "\"", 1); } /* only write out newline for non-empty elements */ (s->write)(s->out, ">\n", content == SGML_EMPTY ? 1 : 2); return content; } /********************* * Data routines *********************/ int SGML_replen(data, specials) CONST char* data; CONST char* specials; { CONST unsigned char* p = (CONST unsigned char*)data; int ret = strlen(data); while(*p){ if(strchr(specials, *p)) ret += (*p>9 ? (*p>99 ? 5 : 4) : 3); /* extra &#ddd; */ *p++; } return ret; } char* SGML_repcpy(markup, data, specials) char* markup; CONST char* data; CONST char* specials; { char* dst = markup; CONST unsigned char* p = (CONST unsigned char*)data; char digit; while(*p){ if(strchr(specials, *p)){ *dst++ = '&'; /* @@ non-ascii compilers! */ *dst++ = '#'; if(*p > 99) *dst++ = (*p / 100) + '0'; if(*p > 9) *dst++ = ((*p % 100) / 10) + '0'; *dst++ = (*p % 10) + '0'; *dst++ = ';'; p++; }else *dst++ = *p++; } *dst = 0; return markup; }