/* 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, "\n", 3);
STR_puts(s, gi);
(s->write)(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;
}