home *** CD-ROM | disk | FTP | other *** search
/ Collection of Internet / Collection of Internet.iso / msdos / lynx / source / www / library / implemen / htmlgen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-25  |  9.4 KB  |  363 lines

  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
  11. **    from the incomming data or the anchor.  Currently it is from the former
  12. **    which is cleanest.
  13. */
  14.  
  15. #define BUFFER_SIZE    80    /* Line buffer attempts to make neat breaks */
  16.  
  17. /* Implements:
  18. */
  19. #include"capalloc.h"
  20. #include "HTMLGen.h"
  21.  
  22. #include"capstdio.h"
  23. #include <stdio.h>
  24. #include "HTMLDTD.h"
  25. #include "HTStream.h"
  26. #include "SGML.h"
  27. #include "HTFormat.h"
  28. #include "tcp.h"
  29.  
  30. #define PUTC(c) (*me->targetClass.put_character)(me->target, c)
  31. /* #define PUTS(s) (*me->targetClass.put_string)(me->target, s) */
  32. #define PUTB(s,l) (*me->targetClass.put_block)(me->target, s, l)
  33.  
  34. /*        HTML Object
  35. **        -----------
  36. */
  37.  
  38. struct _HTStream {
  39.     CONST HTStreamClass *        isa;    
  40.     HTStream *             target;
  41.     HTStreamClass            targetClass;    /* COPY for speed */
  42. };
  43.  
  44. struct _HTStructured {
  45.     CONST HTStructuredClass *    isa;
  46.     HTStream *             target;
  47.     HTStreamClass            targetClass;    /* COPY for speed */
  48.     
  49.     char                buffer[BUFFER_SIZE+1]; /* 1for NL */
  50.     char *                write_pointer;
  51.     char *                line_break;
  52.     int                cleanness;
  53.     BOOL                delete_line_break_char;
  54.     BOOL                preformatted;
  55. };
  56.  
  57.  
  58. /*    Flush Buffer
  59. **    ------------
  60. */
  61. PRIVATE void HTMLGen_flush ARGS1(HTStructured *, me)
  62. {
  63.     (*me->targetClass.put_block)(me->target, 
  64.                     me->buffer,
  65.                 me->write_pointer - me->buffer);
  66.     me->write_pointer = me->buffer;
  67.     me->line_break = me->buffer;
  68.     me->cleanness = 0;
  69.     me->delete_line_break_char = NO;
  70. }
  71.  
  72.  
  73. /*    Character handling
  74. **    ------------------
  75. **
  76. **    The tricky bits are the line break handling.  This attempts
  77. **    to synchrononise line breaks on sentence or phrase ends. This
  78. **    is important if one stores SGML files in a line-oriented code
  79. **    repository, so that if a small change is made, line ends don't
  80. **    shift in a ripple-through to apparently change a large part of the
  81. **    file. We give extra "cleanness" to spaces appearing directly
  82. **    after periods (full stops), [semi]colons and commas.
  83. **       This should make the source files easier to read and modify
  84. **    by hand, too, though this is not a primary design consideration.
  85. */
  86. PRIVATE void HTMLGen_put_character ARGS2(HTStructured *, me, char, c)
  87. {
  88.  
  89.     *me->write_pointer++ = c;
  90.     
  91.     if (c=='\n') {
  92.         HTMLGen_flush(me);
  93.     return;
  94.     }
  95.     
  96.     if ((!me->preformatted  && c==' ')) {
  97.         int new_cleanness = 1;
  98.     if (me->write_pointer > (me->buffer + 1)) {
  99.         char delims[5];
  100.         char * p;
  101.         strcpy(delims, ",;:.");        /* @@ english bias */
  102.         p = strchr(delims, me->write_pointer[-2]);
  103.         if (p) new_cleanness = p - delims + 2;
  104.     }
  105.     if (new_cleanness >= me->cleanness) {
  106.         me->line_break = me->write_pointer - 1;  /* Point to space */
  107.         me->cleanness = new_cleanness;
  108.         me->delete_line_break_char = YES;
  109.     }
  110.     }
  111.     
  112.     /* Flush buffer out when full */
  113.     if (me->write_pointer == me->buffer + BUFFER_SIZE) {
  114.         if (me->cleanness) {
  115.         char line_break_char = me->line_break[0];
  116.         char * saved = me->line_break;
  117.         
  118.         if (me->delete_line_break_char) saved++; 
  119.         me->line_break[0] = '\n';
  120.         (*me->targetClass.put_block)(me->target,
  121.                         me->buffer,
  122.                     me->line_break - me->buffer + 1);
  123.         me->line_break[0] = line_break_char;
  124.         {  /* move next line in */
  125.             char * p=saved;
  126.         char *q;
  127.         for(q=me->buffer; p < me->write_pointer; )
  128.             *q++ = *p++;
  129.         }
  130.         me->cleanness = 0;
  131.         me->delete_line_break_char = 0;
  132.         me->write_pointer = me->write_pointer - (saved-me->buffer);
  133.  
  134.     } else {
  135.         (*me->targetClass.put_block)(me->target,
  136.             me->buffer,
  137.         BUFFER_SIZE);
  138.         me->write_pointer = me->buffer;
  139.     }
  140.     me->line_break = me->buffer;
  141.     }
  142. }
  143.  
  144.  
  145.  
  146. /*    String handling
  147. **    ---------------
  148. */
  149. PRIVATE void HTMLGen_put_string ARGS2(HTStructured *, me, CONST char*, s)
  150. {
  151.     CONST char * p;
  152.     for(p=s; *p; p++) HTMLGen_put_character(me, *p);
  153. }
  154.  
  155. PRIVATE void HTMLGen_write ARGS3(HTStructured *, me, CONST char*, s, int, l)
  156. {
  157.     CONST char * p;
  158.     for(p=s; p<s+l; p++) HTMLGen_put_character(me, *p);
  159. }
  160.  
  161.  
  162. /*    Start Element
  163. **    -------------
  164. **
  165. **    Within the opening tag, there may be spaces
  166. **    and the line may be broken at these spaces.
  167. */
  168. PRIVATE void HTMLGen_start_element ARGS4(
  169.     HTStructured *,     me,
  170.     int,            element_number,
  171.     CONST BOOL*,         present,
  172.     CONST char **,        value)
  173. {
  174.     int i;
  175.     
  176.     BOOL was_preformatted = me->preformatted;
  177.     HTTag * tag = &HTML_dtd.tags[element_number];
  178.  
  179.     me->preformatted = NO;    /* free text within tags */
  180.     HTMLGen_put_character(me, '<');
  181.     HTMLGen_put_string(me, tag->name);
  182.     if (present) for (i=0; i< tag->number_of_attributes; i++) {
  183.         if (present[i]) {
  184.         HTMLGen_put_character(me, ' ');
  185.         HTMLGen_put_string(me, tag->attributes[i].name);
  186.         if (value[i]) {
  187.          HTMLGen_put_string(me, "=\"");
  188.         HTMLGen_put_string(me, value[i]);
  189.         HTMLGen_put_character(me, '"');
  190.         }
  191.     }
  192.     }
  193.     HTMLGen_put_string(me, ">\n");
  194.     
  195.     if (tag->contents != SGML_EMPTY) {  /* can break after element start */ 
  196.         me->line_break = me->write_pointer;    /* Don't you hate SGML?  */
  197.     me->cleanness = 1;
  198.     me->delete_line_break_char = NO;
  199.     }
  200.     /* Make very specific HTML assumption that PRE can't be
  201.        nested! */
  202.        
  203.     me->preformatted = (element_number == HTML_PRE)  ? YES : was_preformatted;
  204. }
  205.  
  206.  
  207. /*        End Element
  208. **        -----------
  209. **
  210. */
  211. /*    When we end an element, the style must be returned to that
  212. **    in effect before that element.  Note that anchors (etc?)
  213. **    don't have an associated style, so that we must scan down the
  214. **    stack for an element with a defined style. (In fact, the styles
  215. **    should be linked to the whole stack not just the top one.)
  216. **    TBL 921119
  217. */
  218. PRIVATE void HTMLGen_end_element ARGS2(HTStructured *, me,
  219.             int , element_number)
  220. {
  221.     if (HTML_dtd.tags[element_number].contents != SGML_EMPTY) {
  222.                     /* can break before element end */ 
  223.         me->line_break = me->write_pointer;    /* Don't you hate SGML?  */
  224.     me->cleanness = 1;
  225.     me->delete_line_break_char = NO;
  226.     }
  227.     HTMLGen_put_string(me, "</");
  228.     HTMLGen_put_string(me, HTML_dtd.tags[element_number].name);
  229.     HTMLGen_put_character(me, '>');
  230.     if (element_number == HTML_PRE) me->preformatted = NO;
  231. }
  232.  
  233.  
  234. /*        Expanding entities
  235. **        ------------------
  236. **
  237. */
  238.  
  239. PRIVATE void HTMLGen_put_entity ARGS2(HTStructured *, me, int, entity_number)
  240. {
  241.     HTMLGen_put_character(me, '&');
  242.     HTMLGen_put_string(me, HTML_dtd.entity_names[entity_number]);
  243.     HTMLGen_put_character(me, ';');
  244. }
  245.  
  246.  
  247.  
  248. /*    Free an HTML object
  249. **    -------------------
  250. **
  251. */
  252. PRIVATE void HTMLGen_free ARGS1(HTStructured *, me)
  253. {
  254.     (*me->targetClass.put_character)(me->target, '\n');
  255.     HTMLGen_flush(me);
  256.     (*me->targetClass.free)(me->target);    /* ripple through */
  257.     free(me);
  258. }
  259.  
  260.  
  261. PRIVATE void PlainToHTML_free ARGS1(HTStructured *, me)
  262. {
  263.     HTMLGen_end_element(me, HTML_PRE);
  264.     HTMLGen_end_element(me, HTML_BODY);
  265.     HTMLGen_end_element(me, HTML_HTML);
  266.     HTMLGen_free(me);
  267. }
  268.  
  269.  
  270.  
  271. PRIVATE void HTMLGen_abort ARGS2(HTStructured *, me, HTError, e)
  272. {
  273.     HTMLGen_free(me);
  274. }
  275.  
  276.  
  277. PRIVATE void PlainToHTML_abort ARGS2(HTStructured *, me, HTError, e)
  278. {
  279.     PlainToHTML_free(me);
  280. }
  281.  
  282.  
  283.  
  284. /*    Structured Object Class
  285. **    -----------------------
  286. */
  287. PRIVATE CONST HTStructuredClass HTMLGeneration = /* As opposed to print etc */
  288. {        
  289.     "text/html",
  290.     HTMLGen_free,
  291.     HTMLGen_abort,
  292.     HTMLGen_put_character,     HTMLGen_put_string, HTMLGen_write,
  293.     HTMLGen_start_element,     HTMLGen_end_element,
  294.     HTMLGen_put_entity
  295. }; 
  296.  
  297.  
  298. /*    Subclass-specific Methods
  299. **    -------------------------
  300. */
  301.  
  302. PUBLIC HTStructured * HTMLGenerator ARGS1(HTStream *, output)
  303. {
  304.     HTStructured* me = (HTStructured*)malloc(sizeof(*me));
  305.     if (me == NULL) outofmem(__FILE__, "HTMLGenerator");
  306.     me->isa = &HTMLGeneration;       
  307.  
  308.     me->target = output;
  309.     me->targetClass = *me->target->isa; /* Copy pointers to routines for speed*/
  310.     
  311.     me->write_pointer = me->buffer;
  312.     me->line_break =     me->buffer;
  313.     me->cleanness =     0;
  314.     me->delete_line_break_char = NO;
  315.     me->preformatted =     NO;
  316.     return me;
  317. }
  318.  
  319. /*    Stream Object Class
  320. **    -------------------
  321. **
  322. **    This object just converts a plain text stream into HTML
  323. **    It is officially a structured strem but only the stream bits exist.
  324. **    This is just the easiest way of typecasting all the routines.
  325. */
  326. PRIVATE CONST HTStructuredClass PlainToHTMLConversion =
  327. {        
  328.     "plaintexttoHTML",
  329.     HTMLGen_free,    
  330.     PlainToHTML_abort,    
  331.     HTMLGen_put_character,
  332.     HTMLGen_put_string,
  333.     HTMLGen_write,
  334.     NULL,        /* Structured stuff */
  335.     NULL,
  336.     NULL
  337. }; 
  338.  
  339.  
  340. /*    HTConverter from plain text to HTML Stream
  341. **    ------------------------------------------
  342. */
  343.  
  344. PUBLIC HTStream* HTPlainToHTML ARGS3(
  345.     HTPresentation *,    pres,
  346.     HTParentAnchor *,    anchor,    
  347.     HTStream *,        sink)
  348. {
  349.     HTStructured* me = (HTStructured*)malloc(sizeof(*me));
  350.     if (me == NULL) outofmem(__FILE__, "PlainToHTML");
  351.     me->isa = (HTStructuredClass*) &PlainToHTMLConversion;       
  352.  
  353.     me->target = sink;
  354.     me->targetClass = *me->target->isa;
  355.         /* Copy pointers to routines for speed*/
  356.     
  357.     HTMLGen_put_string(me, "<HTML>\n<BODY>\n<PRE>\n");
  358.     me->preformatted = YES;
  359.     return (HTStream*) me;
  360. }
  361.  
  362.  
  363.