Annotation of libwww/Library/src/HTML.c, revision 1.7
1.2 timbl 1: /* Structured stream to Rich hypertext converter
2: ** ============================================
1.1 timbl 3: **
1.2 timbl 4: ** This generates of a hypertext object. It converts from the
5: ** structured stream interface fro HTMl events into the style-
6: ** oriented iunterface of the HText.h interface. This module is
7: ** only used in clients and shouldnot be linked into servers.
1.1 timbl 8: **
1.6 timbl 9: ** Override this module if making a new GUI browser.
1.1 timbl 10: **
11: */
12: #include "HTML.h"
13:
1.6 timbl 14: /* #define CAREFUL Check nesting here notreally necessary */
1.2 timbl 15:
1.1 timbl 16: #include <ctype.h>
17: #include <stdio.h>
18:
19: #include "HTAtom.h"
20: #include "HTChunk.h"
21: #include "HText.h"
22: #include "HTStyle.h"
23:
1.3 timbl 24: #include "HTAlert.h"
1.4 timbl 25: #include "HTMLGen.h"
1.1 timbl 26:
27: extern HTStyleSheet * styleSheet; /* Application-wide */
28:
29: /* Module-wide style cache
30: */
31: PRIVATE int got_styles = 0;
1.2 timbl 32: PRIVATE HTStyle *styles[HTML_ELEMENTS];
33: PRIVATE HTStyle *default_style;
1.1 timbl 34:
35:
36: /* HTML Object
37: ** -----------
38: */
1.2 timbl 39: #define MAX_NESTING 20 /* Should be checked by parser */
40:
41: typedef struct _stack_element {
42: HTStyle * style;
43: int tag_number;
44: } stack_element;
45:
46: struct _HTStructured {
47: CONST HTStructuredClass * isa;
48: HTParentAnchor * node_anchor;
49: HText * text;
50:
51: HTStream* target; /* Output stream */
52: HTStreamClass targetClass; /* Output routines */
53:
54: HTChunk title; /* Grow by 128 */
55:
56: char * comment_start; /* for literate programming */
57: char * comment_end;
58:
59: HTTag * current_tag;
60: BOOL style_change;
61: HTStyle * new_style;
62: HTStyle * old_style;
63: BOOL in_word; /* Have just had a non-white char */
64: stack_element stack[MAX_NESTING];
65: stack_element *sp; /* Style stack pointer */
1.1 timbl 66: };
67:
1.2 timbl 68: struct _HTStream {
69: CONST HTStreamClass * isa;
70: /* .... */
71: };
1.1 timbl 72:
73: /* Forward declarations of routines
74: */
75: PRIVATE void get_styles NOPARAMS;
76:
77:
1.4 timbl 78: PRIVATE void actually_set_style PARAMS((HTStructured * me));
79: PRIVATE void change_style PARAMS((HTStructured * me, HTStyle * style));
1.1 timbl 80:
81: /* Style buffering avoids dummy paragraph begin/ends.
82: */
1.4 timbl 83: #define UPDATE_STYLE if (me->style_change) { actually_set_style(me); }
1.1 timbl 84:
85:
1.2 timbl 86: #ifdef OLD_CODE
1.1 timbl 87: /* The following accented characters are from peter Flynn, curia project */
88:
89: /* these ifdefs don't solve the problem of a simple terminal emulator
90: ** with a different character set to the client machine. But nothing does,
91: ** except looking at the TERM setting */
92:
1.2 timbl 93:
1.1 timbl 94: { "ocus" , "&" }, /* for CURIA */
95: #ifdef IBMPC
96: { "aacute" , "\240" }, /* For PC display */
97: { "eacute" , "\202" },
98: { "iacute" , "\241" },
99: { "oacute" , "\242" },
100: { "uacute" , "\243" },
101: { "Aacute" , "\101" },
102: { "Eacute" , "\220" },
103: { "Iacute" , "\111" },
104: { "Oacute" , "\117" },
105: { "Uacute" , "\125" },
106: #else
107: { "aacute" , "\341" }, /* Works for openwindows -- Peter Flynn */
108: { "eacute" , "\351" },
109: { "iacute" , "\355" },
110: { "oacute" , "\363" },
111: { "uacute" , "\372" },
112: { "Aacute" , "\301" },
113: { "Eacute" , "\310" },
114: { "Iacute" , "\315" },
115: { "Oacute" , "\323" },
116: { "Uacute" , "\332" },
117: #endif
118: { 0, 0 } /* Terminate list */
119: };
1.2 timbl 120: #endif
1.1 timbl 121:
122:
1.2 timbl 123: /* Entity values -- for ISO Latin 1 local representation
124: **
125: ** This MUST match exactly the table referred to in the DTD!
126: */
127: static char * ISO_Latin1[] = {
128: "\306", /* capital AE diphthong (ligature) */
129: "\301", /* capital A, acute accent */
130: "\302", /* capital A, circumflex accent */
131: "\300", /* capital A, grave accent */
132: "\305", /* capital A, ring */
133: "\303", /* capital A, tilde */
134: "\304", /* capital A, dieresis or umlaut mark */
135: "\307", /* capital C, cedilla */
136: "\320", /* capital Eth, Icelandic */
137: "\311", /* capital E, acute accent */
138: "\312", /* capital E, circumflex accent */
139: "\310", /* capital E, grave accent */
140: "\313", /* capital E, dieresis or umlaut mark */
141: "\315", /* capital I, acute accent */
142: "\316", /* capital I, circumflex accent */
143: "\314", /* capital I, grave accent */
144: "\317", /* capital I, dieresis or umlaut mark */
145: "\321", /* capital N, tilde */
146: "\323", /* capital O, acute accent */
147: "\324", /* capital O, circumflex accent */
148: "\322", /* capital O, grave accent */
149: "\330", /* capital O, slash */
150: "\325", /* capital O, tilde */
151: "\326", /* capital O, dieresis or umlaut mark */
152: "\336", /* capital THORN, Icelandic */
153: "\332", /* capital U, acute accent */
154: "\333", /* capital U, circumflex accent */
155: "\331", /* capital U, grave accent */
156: "\334", /* capital U, dieresis or umlaut mark */
157: "\335", /* capital Y, acute accent */
158: "\341", /* small a, acute accent */
159: "\342", /* small a, circumflex accent */
160: "\346", /* small ae diphthong (ligature) */
161: "\340", /* small a, grave accent */
162: "\046", /* ampersand */
163: "\345", /* small a, ring */
164: "\343", /* small a, tilde */
165: "\344", /* small a, dieresis or umlaut mark */
166: "\347", /* small c, cedilla */
167: "\351", /* small e, acute accent */
168: "\352", /* small e, circumflex accent */
169: "\350", /* small e, grave accent */
170: "\360", /* small eth, Icelandic */
171: "\353", /* small e, dieresis or umlaut mark */
172: "\076", /* greater than */
173: "\355", /* small i, acute accent */
174: "\356", /* small i, circumflex accent */
175: "\354", /* small i, grave accent */
176: "\357", /* small i, dieresis or umlaut mark */
177: "\074", /* less than */
178: "\361", /* small n, tilde */
179: "\363", /* small o, acute accent */
180: "\364", /* small o, circumflex accent */
181: "\362", /* small o, grave accent */
182: "\370", /* small o, slash */
183: "\365", /* small o, tilde */
184: "\366", /* small o, dieresis or umlaut mark */
185: "\337", /* small sharp s, German (sz ligature) */
186: "\376", /* small thorn, Icelandic */
187: "\372", /* small u, acute accent */
188: "\373", /* small u, circumflex accent */
189: "\371", /* small u, grave accent */
190: "\374", /* small u, dieresis or umlaut mark */
191: "\375", /* small y, acute accent */
192: "\377", /* small y, dieresis or umlaut mark */
1.1 timbl 193: };
194:
1.2 timbl 195:
196: /* Entity values -- for NeXT local representation
197: **
198: ** This MUST match exactly the table referred to in the DTD!
199: **
200: */
201: static char * NeXTCharacters[] = {
202: "\341", /* capital AE diphthong (ligature) */
203: "\202", /* capital A, acute accent */
204: "\203", /* capital A, circumflex accent */
205: "\201", /* capital A, grave accent */
206: "\206", /* capital A, ring */
207: "\204", /* capital A, tilde */
208: "\205", /* capital A, dieresis or umlaut mark */
209: "\207", /* capital C, cedilla */
210: "\220", /* capital Eth, Icelandic */
211: "\211", /* capital E, acute accent */
212: "\212", /* capital E, circumflex accent */
213: "\210", /* capital E, grave accent */
214: "\213", /* capital E, dieresis or umlaut mark */
215: "\215", /* capital I, acute accent */
216: "\216", /* capital I, circumflex accent these are */
217: "\214", /* capital I, grave accent ISO -100 hex */
218: "\217", /* capital I, dieresis or umlaut mark */
219: "\221", /* capital N, tilde */
220: "\223", /* capital O, acute accent */
221: "\224", /* capital O, circumflex accent */
222: "\222", /* capital O, grave accent */
223: "\351", /* capital O, slash 'cept this */
224: "\225", /* capital O, tilde */
225: "\226", /* capital O, dieresis or umlaut mark */
226: "\234", /* capital THORN, Icelandic */
227: "\230", /* capital U, acute accent */
228: "\231", /* capital U, circumflex accent */
229: "\227", /* capital U, grave accent */
230: "\232", /* capital U, dieresis or umlaut mark */
231: "\233", /* capital Y, acute accent */
232: "\326", /* small a, acute accent */
233: "\327", /* small a, circumflex accent */
234: "\361", /* small ae diphthong (ligature) */
235: "\325", /* small a, grave accent */
236: "\046", /* ampersand */
237: "\332", /* small a, ring */
238: "\330", /* small a, tilde */
239: "\331", /* small a, dieresis or umlaut mark */
240: "\333", /* small c, cedilla */
241: "\335", /* small e, acute accent */
242: "\336", /* small e, circumflex accent */
243: "\334", /* small e, grave accent */
244: "\346", /* small eth, Icelandic */
245: "\337", /* small e, dieresis or umlaut mark */
246: "\076", /* greater than */
247: "\342", /* small i, acute accent */
248: "\344", /* small i, circumflex accent */
249: "\340", /* small i, grave accent */
250: "\345", /* small i, dieresis or umlaut mark */
251: "\074", /* less than */
252: "\347", /* small n, tilde */
253: "\355", /* small o, acute accent */
254: "\356", /* small o, circumflex accent */
255: "\354", /* small o, grave accent */
256: "\371", /* small o, slash */
257: "\357", /* small o, tilde */
258: "\360", /* small o, dieresis or umlaut mark */
259: "\373", /* small sharp s, German (sz ligature) */
260: "\374", /* small thorn, Icelandic */
261: "\363", /* small u, acute accent */
262: "\364", /* small u, circumflex accent */
263: "\362", /* small u, grave accent */
264: "\366", /* small u, dieresis or umlaut mark */
265: "\367", /* small y, acute accent */
266: "\375", /* small y, dieresis or umlaut mark */
1.1 timbl 267: };
268:
1.2 timbl 269: /* Entity values -- for IBM/PC Code Page 850 (International)
270: **
271: ** This MUST match exactly the table referred to in the DTD!
272: **
273: */
274: /* @@@@@@@@@@@@@@@@@ TBD */
275:
276:
277:
278: /* Set character set
279: ** ----------------
280: */
281:
282: PRIVATE char** p_entity_values = ISO_Latin1; /* Pointer to translation */
1.1 timbl 283:
1.2 timbl 284: PUBLIC void HTMLUseCharacterSet ARGS1(HTMLCharacterSet, i)
285: {
286: p_entity_values = (i == HTML_NEXT_CHARS) ? NeXTCharacters
287: : ISO_Latin1;
288: }
1.1 timbl 289:
290:
291: /* Flattening the style structure
292: ** ------------------------------
293: **
294: On the NeXT, and on any read-only browser, it is simpler for the text to have
295: a sequence of styles, rather than a nested tree of styles. In this
296: case we have to flatten the structure as it arrives from SGML tags into
297: a sequence of styles.
298: */
299:
300: /* If style really needs to be set, call this
301: */
1.4 timbl 302: PRIVATE void actually_set_style ARGS1(HTStructured *, me)
1.1 timbl 303: {
1.4 timbl 304: if (!me->text) { /* First time through */
305: me->text = HText_new2(me->node_anchor, me->target);
306: HText_beginAppend(me->text);
307: HText_setStyle(me->text, me->new_style);
308: me->in_word = NO;
1.1 timbl 309: } else {
1.4 timbl 310: HText_setStyle(me->text, me->new_style);
1.1 timbl 311: }
1.4 timbl 312: me->old_style = me->new_style;
313: me->style_change = NO;
1.1 timbl 314: }
315:
316: /* If you THINK you need to change style, call this
317: */
318:
1.4 timbl 319: PRIVATE void change_style ARGS2(HTStructured *, me, HTStyle *,style)
1.1 timbl 320: {
1.4 timbl 321: if (me->new_style!=style) {
322: me->style_change = YES;
323: me->new_style = style;
1.1 timbl 324: }
325: }
326:
1.2 timbl 327: /*_________________________________________________________________________
328: **
329: ** A C T I O N R O U T I N E S
330: */
331:
332: /* Character handling
333: ** ------------------
1.1 timbl 334: */
1.4 timbl 335: PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c)
1.1 timbl 336: {
1.2 timbl 337:
1.4 timbl 338: switch (me->sp[0].tag_number) {
1.2 timbl 339: case HTML_COMMENT:
340: break; /* Do Nothing */
341:
342: case HTML_TITLE:
1.4 timbl 343: HTChunkPutc(&me->title, c);
1.2 timbl 344: break;
345:
346:
347: case HTML_LISTING: /* Litteral text */
348: case HTML_XMP:
349: case HTML_PLAINTEXT:
350: case HTML_PRE:
351: /* We guarrantee that the style is up-to-date in begin_litteral
352: */
1.4 timbl 353: HText_appendCharacter(me->text, c);
1.2 timbl 354: break;
355:
356: default: /* Free format text */
1.4 timbl 357: if (me->style_change) {
1.2 timbl 358: if ((c=='\n') || (c==' ')) return; /* Ignore it */
359: UPDATE_STYLE;
360: }
361: if (c=='\n') {
1.4 timbl 362: if (me->in_word) {
363: HText_appendCharacter(me->text, ' ');
364: me->in_word = NO;
1.2 timbl 365: }
366: } else {
1.4 timbl 367: HText_appendCharacter(me->text, c);
368: me->in_word = YES;
1.2 timbl 369: }
370: } /* end switch */
1.1 timbl 371: }
372:
1.2 timbl 373:
374:
375: /* String handling
376: ** ---------------
377: **
378: ** This is written separately from put_character becuase the loop can
379: ** in some cases be postponed to a lower level for speed.
380: */
1.4 timbl 381: PRIVATE void HTML_put_string ARGS2(HTStructured *, me, CONST char*, s)
1.1 timbl 382: {
1.2 timbl 383:
1.4 timbl 384: switch (me->sp[0].tag_number) {
1.2 timbl 385: case HTML_COMMENT:
386: break; /* Do Nothing */
387:
388: case HTML_TITLE:
1.4 timbl 389: HTChunkPuts(&me->title, s);
1.2 timbl 390: break;
391:
392:
393: case HTML_LISTING: /* Litteral text */
394: case HTML_XMP:
395: case HTML_PLAINTEXT:
396: case HTML_PRE:
397:
398: /* We guarrantee that the style is up-to-date in begin_litteral
399: */
1.4 timbl 400: HText_appendText(me->text, s);
1.2 timbl 401: break;
402:
403: default: /* Free format text */
404: {
405: CONST char *p = s;
1.4 timbl 406: if (me->style_change) {
1.2 timbl 407: for (; *p && ((*p=='\n') || (*p==' ')); p++) ; /* Ignore leaders */
408: if (!*p) return;
409: UPDATE_STYLE;
410: }
411: for(; *p; p++) {
1.4 timbl 412: if (me->style_change) {
1.2 timbl 413: if ((*p=='\n') || (*p==' ')) continue; /* Ignore it */
414: UPDATE_STYLE;
415: }
416: if (*p=='\n') {
1.4 timbl 417: if (me->in_word) {
418: HText_appendCharacter(me->text, ' ');
419: me->in_word = NO;
1.2 timbl 420: }
421: } else {
1.4 timbl 422: HText_appendCharacter(me->text, *p);
423: me->in_word = YES;
1.2 timbl 424: }
425: } /* for */
426: }
427: } /* end switch */
1.1 timbl 428: }
429:
430:
1.2 timbl 431: /* Buffer write
1.3 timbl 432: ** ------------
1.1 timbl 433: */
1.4 timbl 434: PRIVATE void HTML_write ARGS3(HTStructured *, me, CONST char*, s, int, l)
1.1 timbl 435: {
1.2 timbl 436: CONST char* p;
437: CONST char* e = s+l;
1.4 timbl 438: for (p=s; s<e; p++) HTML_put_character(me, *p);
1.1 timbl 439: }
1.2 timbl 440:
441:
442: /* Start Element
443: ** -------------
444: */
445: PRIVATE void HTML_start_element ARGS4(
1.4 timbl 446: HTStructured *, me,
1.2 timbl 447: int, element_number,
1.3 timbl 448: CONST BOOL*, present,
449: CONST char **, value)
1.2 timbl 450: {
451: switch (element_number) {
452: case HTML_A:
453: {
454: HTChildAnchor * source = HTAnchor_findChildAndLink(
1.4 timbl 455: me->node_anchor, /* parent */
1.2 timbl 456: present[HTML_A_NAME] ? value[HTML_A_NAME] : 0, /* Tag */
457: present[HTML_A_HREF] ? value[HTML_A_HREF] : 0, /* Addresss */
458: present[HTML_A_TYPE] && value[HTML_A_TYPE] ?
459: (HTLinkType*)HTAtom_for(value[HTML_A_TYPE])
460: : 0);
461:
462: if (present[HTML_A_TITLE] && value[HTML_A_TITLE]) {
463: HTParentAnchor * dest =
464: HTAnchor_parent(
465: HTAnchor_followMainLink((HTAnchor*)source)
466: );
467: if (!HTAnchor_title(dest))
468: HTAnchor_setTitle(dest, value[HTML_A_TITLE]);
469: }
470: UPDATE_STYLE;
1.4 timbl 471: HText_beginAnchor(me->text, source);
1.2 timbl 472: }
473: break;
474:
475: case HTML_TITLE:
1.4 timbl 476: HTChunkClear(&me->title);
1.2 timbl 477: break;
478:
479: case HTML_NEXTID:
480: /* if (present[NEXTID_N] && value[NEXTID_N])
1.4 timbl 481: HText_setNextId(me->text, atoi(value[NEXTID_N])); */
1.2 timbl 482: break;
483:
484: case HTML_ISINDEX:
1.4 timbl 485: HTAnchor_setIndex(me->node_anchor);
1.2 timbl 486: break;
487:
488: case HTML_P:
489: UPDATE_STYLE;
1.4 timbl 490: HText_appendParagraph(me->text);
491: me->in_word = NO;
1.2 timbl 492: break;
493:
494: case HTML_DL:
1.4 timbl 495: change_style(me, present && present[DL_COMPACT]
1.2 timbl 496: ? styles[HTML_DLC]
497: : styles[HTML_DL]);
1.4 timbl 498: me->in_word = NO;
1.2 timbl 499: break;
500:
501: case HTML_DT:
1.4 timbl 502: if (!me->style_change) {
503: HText_appendParagraph(me->text);
504: me->in_word = NO;
1.2 timbl 505: }
506: break;
507:
508: case HTML_DD:
509: UPDATE_STYLE;
1.4 timbl 510: HTML_put_character(me, '\t'); /* Just tab out one stop */
511: me->in_word = NO;
512: break;
1.2 timbl 513:
514: case HTML_UL:
515: case HTML_OL:
516: case HTML_MENU:
517: case HTML_DIR:
1.4 timbl 518: change_style(me, styles[element_number]);
519: me->in_word = NO;
1.2 timbl 520: break;
521:
522: case HTML_LI:
523: UPDATE_STYLE;
1.7 ! timbl 524: if (me->sp[0].tag_number != HTML_DIR)
1.4 timbl 525: HText_appendParagraph(me->text);
1.2 timbl 526: else
1.4 timbl 527: HText_appendCharacter(me->text, '\t'); /* Tab @@ nl for UL? */
528: me->in_word = NO;
1.2 timbl 529: break;
530:
531: case HTML_LISTING: /* Litteral text */
532: case HTML_XMP:
533: case HTML_PLAINTEXT:
534: case HTML_PRE:
1.4 timbl 535: change_style(me, styles[element_number]);
1.2 timbl 536: UPDATE_STYLE;
1.4 timbl 537: if (me->comment_end)
538: HText_appendText(me->text, me->comment_end);
1.2 timbl 539: break;
540:
541: default:
1.4 timbl 542: change_style(me, styles[element_number]); /* May be postponed */
1.2 timbl 543: break;
544:
545: } /* end switch */
546:
547: if (HTML_dtd.tags[element_number].contents!= SGML_EMPTY) {
1.4 timbl 548: --(me->sp);
549: me->sp[0].style = me->new_style; /* Stack new style */
550: me->sp[0].tag_number = element_number;
1.2 timbl 551: }
552:
1.1 timbl 553: }
1.2 timbl 554:
1.1 timbl 555: /* End Element
1.2 timbl 556: ** -----------
1.1 timbl 557: **
1.2 timbl 558: */
559: /* When we end an element, the style must be returned to that
1.1 timbl 560: ** in effect before that element. Note that anchors (etc?)
561: ** don't have an associated style, so that we must scan down the
562: ** stack for an element with a defined style. (In fact, the styles
563: ** should be linked to the whole stack not just the top one.)
564: ** TBL 921119
1.6 timbl 565: **
566: ** We don't turn on "CAREFUL" check because the parser produces
567: ** (internal code errors apart) good nesting. The parser checks
568: ** incoming code errors, not this module.
1.1 timbl 569: */
1.4 timbl 570: PRIVATE void HTML_end_element ARGS2(HTStructured *, me, int , element_number)
1.1 timbl 571: {
1.2 timbl 572: #ifdef CAREFUL /* parser assumed to produce good nesting */
1.4 timbl 573: if (element_number != me->sp[0].tag_number) {
1.2 timbl 574: fprintf(stderr, "HTMLText: end of element %s when expecting end of %s\n",
575: HTML_dtd.tags[element_number].name,
1.4 timbl 576: HTML_dtd.tags[me->sp->tag_number].name);
1.6 timbl 577: /* panic */
1.1 timbl 578: }
1.2 timbl 579: #endif
580:
1.4 timbl 581: me->sp++; /* Pop state off stack */
1.2 timbl 582:
583: switch(element_number) {
584:
585: case HTML_A:
586: UPDATE_STYLE;
1.4 timbl 587: HText_endAnchor(me->text);
1.2 timbl 588: break;
589:
590: case HTML_TITLE:
1.4 timbl 591: HTChunkTerminate(&me->title);
592: HTAnchor_setTitle(me->node_anchor, me->title.data);
1.2 timbl 593: break;
594:
595: case HTML_LISTING: /* Litteral text */
596: case HTML_XMP:
597: case HTML_PLAINTEXT:
598: case HTML_PRE:
1.4 timbl 599: if (me->comment_start)
600: HText_appendText(me->text, me->comment_start);
1.2 timbl 601: /* Fall through */
602:
603: default:
604:
1.4 timbl 605: change_style(me, me->sp->style); /* Often won't really change */
606: me->in_word = NO; /* Paragraph styles only @@ */
1.2 timbl 607: break;
608:
609: } /* switch */
1.1 timbl 610: }
611:
1.2 timbl 612:
613: /* Expanding entities
614: ** ------------------
615: */
616: /* (In fact, they all shrink!)
1.1 timbl 617: */
1.2 timbl 618:
1.4 timbl 619: PRIVATE void HTML_put_entity ARGS2(HTStructured *, me, int, entity_number)
1.1 timbl 620: {
1.4 timbl 621: HTML_put_string(me, ISO_Latin1[entity_number]); /* @@ Other representations */
1.1 timbl 622: }
623:
1.2 timbl 624:
625:
626: /* Free an HTML object
627: ** -------------------
628: **
1.4 timbl 629: ** If the document is empty, the text object will not yet exist.
630: So we could in fact abandon creating the document and return
631: an error code. In fact an empty document is an important type
632: of document, so we don't.
633: **
634: ** If non-interactive, everything is freed off. No: crashes -listrefs
1.2 timbl 635: ** Otherwise, the interactive object is left.
636: */
1.4 timbl 637: PUBLIC void HTML_free ARGS1(HTStructured *, me)
1.1 timbl 638: {
1.4 timbl 639: UPDATE_STYLE; /* Creates empty document here! */
640: if (me->comment_end)
641: HTML_put_string(me,me->comment_end);
642: HText_endAppend(me->text);
643:
644: if (me->target) {
645: (*me->targetClass.end_document)(me->target);
646: (*me->targetClass.free)(me->target);
647: /* HText_free(me->text); */ /* @@@@@@@@@@@@@@@ */
1.2 timbl 648: }
1.4 timbl 649: free(me);
1.1 timbl 650: }
651:
652:
1.4 timbl 653: PRIVATE void HTML_end_document ARGS1(HTStructured *, me)
1.1 timbl 654:
1.4 timbl 655: { /* Obsolete */
1.1 timbl 656: }
657:
1.2 timbl 658:
659: /* Get Styles from style sheet
660: ** ---------------------------
661: */
662: PRIVATE void get_styles NOARGS
1.1 timbl 663: {
1.2 timbl 664: got_styles = YES;
665:
666: default_style = HTStyleNamed(styleSheet, "Normal");
1.1 timbl 667:
1.2 timbl 668: styles[HTML_H1] = HTStyleNamed(styleSheet, "Heading1");
669: styles[HTML_H2] = HTStyleNamed(styleSheet, "Heading2");
670: styles[HTML_H3] = HTStyleNamed(styleSheet, "Heading3");
671: styles[HTML_H4] = HTStyleNamed(styleSheet, "Heading4");
672: styles[HTML_H5] = HTStyleNamed(styleSheet, "Heading5");
673: styles[HTML_H6] = HTStyleNamed(styleSheet, "Heading6");
674: styles[HTML_H7] = HTStyleNamed(styleSheet, "Heading7");
675:
676: styles[HTML_DL] = HTStyleNamed(styleSheet, "Glossary");
677: styles[HTML_UL] =
678: styles[HTML_OL] = HTStyleNamed(styleSheet, "List");
679: styles[HTML_MENU] = HTStyleNamed(styleSheet, "Menu");
680: styles[HTML_DIR] = HTStyleNamed(styleSheet, "Dir");
681: styles[HTML_DLC] = HTStyleNamed(styleSheet, "GlossaryCompact");
682: styles[HTML_ADDRESS]= HTStyleNamed(styleSheet, "Address");
683: styles[HTML_BLOCKQUOTE]= HTStyleNamed(styleSheet, "BlockQuote");
684: styles[HTML_PLAINTEXT] =
685: styles[HTML_XMP] = HTStyleNamed(styleSheet, "Example");
686: styles[HTML_PRE] = HTStyleNamed(styleSheet, "Preformatted");
687: styles[HTML_LISTING] = HTStyleNamed(styleSheet, "Listing");
688: }
689: /* P U B L I C
690: */
691:
692: /* Structured Object Class
693: ** -----------------------
694: */
695: PUBLIC CONST HTStructuredClass HTMLPresentation = /* As opposed to print etc */
696: {
697: "text/html",
698: HTML_free,
699: HTML_end_document,
700: HTML_put_character, HTML_put_string, HTML_write,
701: HTML_start_element, HTML_end_element,
702: HTML_put_entity
703: };
1.1 timbl 704:
1.4 timbl 705:
1.2 timbl 706: /* New Structured Text object
707: ** --------------------------
708: **
1.4 timbl 709: ** The strutcured stream can generate either presentation,
710: ** or plain text, or HTML.
1.1 timbl 711: */
1.4 timbl 712: PUBLIC HTStructured* HTML_new ARGS3(
1.2 timbl 713: HTParentAnchor *, anchor,
1.4 timbl 714: HTFormat, format_out,
1.2 timbl 715: HTStream*, stream)
1.1 timbl 716: {
717:
1.4 timbl 718: HTStructured * me;
719:
720: if (format_out != WWW_PLAINTEXT && format_out != WWW_PRESENT) {
1.6 timbl 721: HTStream * intermediate = HTStreamStack(WWW_HTML, format_out,
722: stream, anchor);
723: if (intermediate) return HTMLGenerator(intermediate);
1.4 timbl 724: fprintf(stderr, "** Internal error: can't parse HTML to %s\n",
725: HTAtom_name(format_out));
726: exit (-99);
727: }
728:
729: me = (HTStructured*) malloc(sizeof(*me));
730: if (me == NULL) outofmem(__FILE__, "HTML_new");
1.1 timbl 731:
732: if (!got_styles) get_styles();
733:
1.4 timbl 734: me->isa = &HTMLPresentation;
735: me->node_anchor = anchor;
736: me->title.size = 0;
737: me->title.growby = 128;
738: me->title.allocated = 0;
739: me->title.data = 0;
740: me->text = 0;
741: me->style_change = YES; /* Force check leading to text creation */
742: me->new_style = default_style;
743: me->old_style = 0;
744: me->sp = me->stack + MAX_NESTING - 1;
745: me->sp->tag_number = -1; /* INVALID */
746: me->sp->style = default_style; /* INVALID */
1.1 timbl 747:
1.4 timbl 748: me->comment_start = NULL;
749: me->comment_end = NULL;
750: me->target = stream;
751: if (stream) me->targetClass = *stream->isa; /* Copy pointers */
1.1 timbl 752:
1.4 timbl 753: return (HTStructured*) me;
1.1 timbl 754: }
755:
756:
1.2 timbl 757: /* HTConverter for HTML to plain text
758: ** ----------------------------------
1.1 timbl 759: **
1.2 timbl 760: ** This will convert from HTML to presentation or plain text.
1.1 timbl 761: */
1.2 timbl 762: PUBLIC HTStream* HTMLToPlain ARGS3(
763: HTPresentation *, pres,
764: HTParentAnchor *, anchor,
765: HTStream *, sink)
1.1 timbl 766: {
1.4 timbl 767: return SGML_new(&HTML_dtd, HTML_new(anchor, pres->rep_out, sink));
1.1 timbl 768: }
769:
770:
1.2 timbl 771: /* HTConverter for HTML to C code
772: ** ------------------------------
773: **
774: ** C copde is like plain text but all non-preformatted code
775: ** is commented out.
776: ** This will convert from HTML to presentation or plain text.
777: */
778: PUBLIC HTStream* HTMLToC ARGS3(
779: HTPresentation *, pres,
780: HTParentAnchor *, anchor,
781: HTStream *, sink)
1.1 timbl 782: {
1.4 timbl 783:
784: HTStructured * html;
785:
786: (*sink->isa->put_string)(sink, "/* "); /* Before even title */
787: html = HTML_new(anchor, WWW_PLAINTEXT, sink);
1.2 timbl 788: html->comment_start = "/* ";
789: html->comment_end = " */\n"; /* Must start in col 1 for cpp */
1.4 timbl 790: /* HTML_put_string(html,html->comment_start); */
1.2 timbl 791: return SGML_new(&HTML_dtd, html);
1.1 timbl 792: }
793:
794:
1.2 timbl 795: /* Presenter for HTML
796: ** ------------------
797: **
798: ** This will convert from HTML to presentation or plain text.
799: **
800: ** Override this if you have a windows version
1.1 timbl 801: */
1.2 timbl 802: #ifndef GUI
803: PUBLIC HTStream* HTMLPresent ARGS3(
804: HTPresentation *, pres,
805: HTParentAnchor *, anchor,
806: HTStream *, sink)
1.1 timbl 807: {
1.4 timbl 808: return SGML_new(&HTML_dtd, HTML_new(anchor, WWW_PRESENT, NULL));
1.1 timbl 809: }
1.2 timbl 810: #endif
1.1 timbl 811:
812:
1.2 timbl 813: /* Record error message as a hypertext object
814: ** ------------------------------------------
815: **
816: ** The error message should be marked as an error so that
817: ** it can be reloaded later.
818: ** This implementation just throws up an error message
819: ** and leaves the document unloaded.
1.1 timbl 820: **
1.2 timbl 821: ** On entry,
822: ** sink is a stream to the output device if any
823: ** number is the HTTP error number
824: ** message is the human readable message.
1.1 timbl 825: */
1.2 timbl 826:
827: PUBLIC int HTLoadError ARGS3(
828: HTStream *, sink,
829: int, number,
830: CONST char *, message)
831: {
832: HTAlert(message); /* @@@@@@@@@@@@@@@@@@@ */
833: return -number;
834: }
835:
Webmaster