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