Annotation of libwww/Library/src/HTMLGen.c, revision 2.7
2.1 timbl 1: /* HTML Generator
2: ** ==============
3: **
4: ** This version of the HTML object sends HTML markup to the output stream.
5: **
6: ** Bugs: Line wrapping is not done at all.
7: ** All data handled as PCDATA.
8: ** Should convert old XMP, LISTING and PLAINTEXT to PRE.
9: **
10: ** It is not obvious to me right now whether the HEAD should be generated
2.7 ! timbl 11: ** from the incomming data or the anchor. Currently it is from the former
2.1 timbl 12: ** which is cleanest.
13: */
14:
2.7 ! timbl 15: #define BUFFER_SIZE 80 /* Line buffer attempts to make neat breaks */
! 16:
2.1 timbl 17: /* Implements:
18: */
19: #include "HTMLGen.h"
20:
21: #include <stdio.h>
22: #include "HTMLDTD.h"
23: #include "HTStream.h"
24: #include "SGML.h"
25: #include "HTFormat.h"
26:
2.3 timbl 27: #define PUTC(c) (*me->targetClass.put_character)(me->target, c)
2.7 ! timbl 28: /* #define PUTS(s) (*me->targetClass.put_string)(me->target, s) */
2.4 timbl 29: #define PUTB(s,l) (*me->targetClass.put_block)(me->target, s, l)
2.1 timbl 30:
31: /* HTML Object
32: ** -----------
33: */
34:
35: struct _HTStream {
36: CONST HTStreamClass * isa;
37: HTStream * target;
38: HTStreamClass targetClass; /* COPY for speed */
39: };
40:
41: struct _HTStructured {
42: CONST HTStructuredClass * isa;
43: HTStream * target;
44: HTStreamClass targetClass; /* COPY for speed */
2.7 ! timbl 45:
! 46: char buffer[BUFFER_SIZE];
! 47: char * write_pointer;
! 48: char * line_break;
! 49: int cleanness;
! 50: BOOL preformatted;
2.1 timbl 51: };
52:
53:
2.7 ! timbl 54: /* Flush Buffer
! 55: ** ------------
! 56: */
! 57: PRIVATE void HTMLGen_flush ARGS1(HTStructured *, me)
! 58: {
! 59: (*me->targetClass.put_block)(me->target,
! 60: me->buffer,
! 61: me->write_pointer - me->buffer);
! 62: me->write_pointer = me->buffer;
! 63: me->line_break = me->buffer;
! 64: me->cleanness = 0;
! 65: }
! 66:
! 67:
2.1 timbl 68: /* Character handling
69: ** ------------------
70: */
2.3 timbl 71: PRIVATE void HTMLGen_put_character ARGS2(HTStructured *, me, char, c)
2.1 timbl 72: {
2.7 ! timbl 73:
! 74: *me->write_pointer++ = c;
! 75:
! 76: if (c=='\n') {
! 77: HTMLGen_flush(me);
! 78: return;
! 79: }
! 80:
! 81: if ((!me->preformatted && c==' ')) {
! 82: me->line_break = me->write_pointer;
! 83: me->cleanness = 1;
! 84: }
! 85:
! 86: /* Flush buffer out when full */
! 87: if (me->write_pointer == me->buffer + BUFFER_SIZE) {
! 88: if (me->cleanness) {
! 89: me->line_break[-1] = '\n';
! 90: (*me->targetClass.put_block)(me->target,
! 91: me->buffer,
! 92: me->line_break - me->buffer);
! 93: { /* move next line in */
! 94: char * p,*q;
! 95: for(q=me->buffer, p=me->line_break; p < me->write_pointer; )
! 96: *q++ = *p++;
! 97: }
! 98: me->cleanness = 0;
! 99: } else {
! 100: (*me->targetClass.put_block)(me->target,
! 101: me->buffer,
! 102: BUFFER_SIZE);
! 103: }
! 104: me->write_pointer = me->buffer;
! 105: me->line_break = me->buffer;
! 106: }
2.1 timbl 107: }
108:
109:
110:
111: /* String handling
112: ** ---------------
113: */
2.3 timbl 114: PRIVATE void HTMLGen_put_string ARGS2(HTStructured *, me, CONST char*, s)
2.1 timbl 115: {
2.7 ! timbl 116: CONST char * p;
! 117: for(p=s; *p; p++) HTMLGen_put_character(me, *p);
2.1 timbl 118: }
119:
2.3 timbl 120: PRIVATE void HTMLGen_write ARGS3(HTStructured *, me, CONST char*, s, int, l)
2.1 timbl 121: {
2.7 ! timbl 122: CONST char * p;
! 123: for(p=s; p<s+l; p++) HTMLGen_put_character(me, *p);
2.1 timbl 124: }
125:
126:
127: /* Start Element
128: ** -------------
2.7 ! timbl 129: **
! 130: ** Within the opening tag, there may be spaces
! 131: ** and the line may be broken at these spaces.
2.1 timbl 132: */
133: PRIVATE void HTMLGen_start_element ARGS4(
2.3 timbl 134: HTStructured *, me,
2.2 timbl 135: int, element_number,
136: CONST BOOL*, present,
137: CONST char **, value)
2.1 timbl 138: {
139: int i;
2.7 ! timbl 140:
! 141: BOOL was_preformatted = me->preformatted;
! 142: HTTag * tag = &HTML_dtd.tags[element_number];
2.1 timbl 143:
2.7 ! timbl 144: me->preformatted = NO;
! 145: HTMLGen_put_character(me, '<');
! 146: HTMLGen_put_string(me, tag->name);
2.1 timbl 147: if (present) for (i=0; i< tag->number_of_attributes; i++) {
148: if (present[i]) {
2.7 ! timbl 149: HTMLGen_put_character(me, ' ');
! 150: HTMLGen_put_string(me, tag->attributes[i].name);
2.1 timbl 151: if (value[i]) {
2.7 ! timbl 152: HTMLGen_put_string(me, "=\"");
! 153: HTMLGen_put_string(me, value[i]);
! 154: HTMLGen_put_character(me, '"');
2.1 timbl 155: }
156: }
157: }
2.7 ! timbl 158: HTMLGen_put_string(me, ">\n");
! 159:
! 160: /* Make very specific HTML assumption that PRE can't be
! 161: nested! */
! 162:
! 163: me->preformatted = (element_number == HTML_PRE) ? YES : was_preformatted;
2.1 timbl 164: }
165:
166:
167: /* End Element
168: ** -----------
169: **
170: */
171: /* When we end an element, the style must be returned to that
172: ** in effect before that element. Note that anchors (etc?)
173: ** don't have an associated style, so that we must scan down the
174: ** stack for an element with a defined style. (In fact, the styles
175: ** should be linked to the whole stack not just the top one.)
176: ** TBL 921119
177: */
2.3 timbl 178: PRIVATE void HTMLGen_end_element ARGS2(HTStructured *, me,
2.1 timbl 179: int , element_number)
180: {
2.7 ! timbl 181: HTMLGen_put_string(me, "</");
! 182: HTMLGen_put_string(me, HTML_dtd.tags[element_number].name);
! 183: HTMLGen_put_character(me, '>');
! 184: if (element_number == HTML_PRE) me->preformatted = NO;
2.1 timbl 185: }
186:
187:
188: /* Expanding entities
189: ** ------------------
190: **
191: */
192:
2.3 timbl 193: PRIVATE void HTMLGen_put_entity ARGS2(HTStructured *, me, int, entity_number)
2.1 timbl 194: {
2.7 ! timbl 195: HTMLGen_put_character(me, '&');
! 196: HTMLGen_put_string(me, HTML_dtd.entity_names[entity_number]);
! 197: HTMLGen_put_character(me, ';');
2.1 timbl 198: }
199:
200:
201:
202: /* Free an HTML object
203: ** -------------------
204: **
205: */
2.3 timbl 206: PRIVATE void HTMLGen_free ARGS1(HTStructured *, me)
2.1 timbl 207: {
2.7 ! timbl 208: (*me->targetClass.put_character)(me->target, '\n');
! 209: HTMLGen_flush(me);
2.3 timbl 210: (*me->targetClass.free)(me->target); /* ripple through */
211: free(me);
2.1 timbl 212: }
213:
214:
2.7 ! timbl 215: PRIVATE void PlainToHTML_free ARGS1(HTStructured *, me)
! 216: {
! 217: HTMLGen_end_element(me, HTML_PRE);
! 218: HTMLGen_end_element(me, HTML_BODY);
! 219: HTMLGen_end_element(me, HTML_HTML);
! 220: HTMLGen_free(me);
! 221: }
! 222:
! 223:
2.1 timbl 224:
2.6 timbl 225: PRIVATE void HTMLGen_abort ARGS2(HTStructured *, me, HTError, e)
2.1 timbl 226: {
2.6 timbl 227: HTMLGen_free(me);
2.1 timbl 228: }
229:
230:
2.6 timbl 231: PRIVATE void PlainToHTML_abort ARGS2(HTStructured *, me, HTError, e)
2.1 timbl 232: {
2.7 ! timbl 233: PlainToHTML_free(me);
2.1 timbl 234: }
235:
236:
237:
238: /* Structured Object Class
239: ** -----------------------
240: */
2.5 timbl 241: PRIVATE CONST HTStructuredClass HTMLGeneration = /* As opposed to print etc */
2.1 timbl 242: {
243: "text/html",
244: HTMLGen_free,
2.6 timbl 245: HTMLGen_abort,
2.1 timbl 246: HTMLGen_put_character, HTMLGen_put_string, HTMLGen_write,
247: HTMLGen_start_element, HTMLGen_end_element,
248: HTMLGen_put_entity
249: };
250:
251:
252: /* Subclass-specific Methods
253: ** -------------------------
254: */
255:
256: PUBLIC HTStructured * HTMLGenerator ARGS1(HTStream *, output)
257: {
2.3 timbl 258: HTStructured* me = (HTStructured*)malloc(sizeof(*me));
259: if (me == NULL) outofmem(__FILE__, "HTMLGenerator");
260: me->isa = &HTMLGeneration;
2.1 timbl 261:
2.3 timbl 262: me->target = output;
263: me->targetClass = *me->target->isa; /* Copy pointers to routines for speed*/
2.7 ! timbl 264:
! 265: me->write_pointer = me->buffer;
! 266: me->line_break = me->buffer;
! 267: me->cleanness = 0;
! 268: me->preformatted = NO;
2.3 timbl 269: return me;
2.1 timbl 270: }
271:
272: /* Stream Object Class
273: ** -------------------
274: **
2.2 timbl 275: ** This object just converts a plain text stream into HTML
276: ** It is officially a structured strem but only the stream bits exist.
277: ** This is just the easiest way of typecasting all the routines.
2.1 timbl 278: */
2.2 timbl 279: PRIVATE CONST HTStructuredClass PlainToHTMLConversion =
2.1 timbl 280: {
281: "plaintexttoHTML",
282: HTMLGen_free,
2.6 timbl 283: PlainToHTML_abort,
2.1 timbl 284: HTMLGen_put_character,
285: HTMLGen_put_string,
286: HTMLGen_write,
2.2 timbl 287: NULL, /* Structured stuff */
288: NULL,
289: NULL
2.1 timbl 290: };
291:
292:
293: /* HTConverter from plain text to HTML Stream
294: ** ------------------------------------------
295: */
296:
297: PUBLIC HTStream* HTPlainToHTML ARGS3(
298: HTPresentation *, pres,
299: HTParentAnchor *, anchor,
300: HTStream *, sink)
301: {
2.7 ! timbl 302: HTStructured* me = (HTStructured*)malloc(sizeof(*me));
2.3 timbl 303: if (me == NULL) outofmem(__FILE__, "PlainToHTML");
2.7 ! timbl 304: me->isa = (HTStructuredClass*) &PlainToHTMLConversion;
2.1 timbl 305:
2.3 timbl 306: me->target = sink;
307: me->targetClass = *me->target->isa;
2.1 timbl 308: /* Copy pointers to routines for speed*/
309:
2.7 ! timbl 310: HTMLGen_put_string(me, "<HTML>\n<BODY>\n<PRE>\n");
! 311: me->preformatted = YES;
! 312: return (HTStream*) me;
2.1 timbl 313: }
314:
315:
Webmaster