home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / lynx-2.4 / WWW / Library / Implementation / HTWSRC.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-28  |  10.6 KB  |  480 lines

  1. /*            Parse WAIS Source file            HTWSRC.c
  2. **            ======================
  3. **
  4. **    This module parses a stream with WAIS source file
  5. **    format information on it and creates a structured stream.
  6. **    That structured stream is then converted into whatever.
  7. **
  8. **    3 June 93    Bug fix: Won't crash if no description
  9. */
  10.  
  11. #include "HTUtils.h"
  12. #include "tcp.h"
  13.  
  14. #include "HTWSRC.h"
  15.  
  16.  
  17. /* #include <sys/types.h>    already in tcp.h */
  18. /* #include <sys/stat.h>      this too         */
  19. /* #include <stdio.h> included in HTUtils.h -- FM */
  20. #include "HTML.h"
  21. #include "HTParse.h"
  22.  
  23. #include "LYLeaks.h"
  24.  
  25. #define BIG 10000        /* Arbitrary limit to value length */
  26. #define PARAM_MAX BIG
  27. #define CACHE_PERIOD (7*86400)    /* Time to keep .src file in seconds */
  28.  
  29. #define HEX_ESCAPE '%'
  30.  
  31. struct _HTStructured {
  32.     CONST HTStructuredClass *    isa;
  33.     /* ... */
  34. };
  35.  
  36. #define PUTC(c) (*me->target->isa->put_character)(me->target, c)
  37. #define PUTS(s) (*me->target->isa->put_string)(me->target, s)
  38. #define START(e) (*me->target->isa->start_element)(me->target, e, 0, 0)
  39. #define END(e) (*me->target->isa->end_element)(me->target, e)
  40.  
  41.  
  42. /*    Here are the parameters which can be specified in a  source file
  43. */
  44. PRIVATE CONST char* par_name[] = {
  45.     "version", 
  46.     "ip-address",
  47. #define PAR_IP_NAME 2
  48.     "ip-name", 
  49. #define PAR_TCP_PORT 3
  50.     "tcp-port", 
  51. #define PAR_DATABASE_NAME 4
  52.     "database-name",
  53. #define PAR_COST 5
  54.     "cost", 
  55. #define PAR_COST_UNIT 6
  56.     "cost-unit", 
  57. #define PAR_FREE 7
  58.     "free",    
  59. #define PAR_MAINTAINER 8
  60.     "maintainer",     
  61. #define PAR_DESCRIPTION 9
  62.     "description",
  63.     "keyword-list",     
  64.     "source",
  65.     "window-geometry",
  66.     "configuration",
  67.     "script",
  68.     "update-time",
  69.     "contact-at",
  70.     "last-contacted",
  71.     "confidence",
  72.     "num-docs-to-request",
  73.     "font",
  74.     "font-size",
  75. #define PAR_UNKNOWN 22
  76.     "unknown",
  77.     0,                /* Terminate list */
  78. #define PAR_COUNT 23
  79. } ;
  80.  
  81.  
  82. enum tokenstate { beginning, before_tag, colon, before_value,
  83.         value, bracketed_value, quoted_value, escape_in_quoted, done };
  84.  
  85.  
  86. /*        Stream Object
  87. **        ------------
  88. **
  89. **    The target is the structured stream down which the
  90. **    parsed results will go.
  91. **
  92. **    all the static stuff below should go in here to make it reentrant
  93. */
  94.  
  95. struct _HTStream {
  96.     CONST HTStreamClass *    isa;
  97.     HTStructured *        target;
  98.     char *            par_value[PAR_COUNT];
  99.     enum tokenstate     state;
  100.     char             param[BIG+1];
  101.     int            param_number;
  102.     int            param_count;
  103. };
  104.  
  105.  
  106.  
  107.  
  108. PUBLIC CONST char * hex = "0123456789ABCDEF";
  109.  
  110. /*    Decode one hex character
  111. */
  112.  
  113. PUBLIC char from_hex ARGS1(char, c)
  114. {
  115.     return           (c>='0')&&(c<='9') ? c-'0'
  116.             : (c>='A')&&(c<='F') ? c-'A'+10
  117.             : (c>='a')&&(c<='f') ? c-'a'+10
  118.             :               0;
  119. }
  120.  
  121.  
  122. /*            State machine
  123. **            -------------
  124. **
  125. ** On entry,
  126. **    me->state    is a valid state (see WSRC_init)
  127. **    c        is the next character
  128. ** On exit,
  129. **     returns    1    Done with file
  130. **        0    Continue. me->state is updated if necessary.
  131. **        -1    Syntax error error
  132. */
  133.  
  134.  
  135. /*        Treat One Character
  136. **        -------------------
  137. */
  138. PRIVATE void WSRCParser_put_character ARGS2(HTStream*, me, char, c)
  139. {
  140.     switch (me->state) {
  141.     case beginning:
  142.         if (c=='(') me->state = before_tag;
  143.     break;
  144.     
  145.     case before_tag:
  146.         if (c==')') {
  147.         me->state = done;
  148.         return;            /* Done with input file */
  149.     } else if (c==':') {
  150.         me->param_count = 0;
  151.         me->state = colon;
  152.     }                /* Ignore other text */
  153.     break;
  154.  
  155.     case colon:
  156.         if (WHITE(c)) {
  157.         me->param[me->param_count++] = 0;    /* Terminate */
  158.         for(me->param_number = 0; par_name[me->param_number]; me->param_number++) {
  159.         if (0==strcmp(par_name[me->param_number], me->param)) {
  160.             break;
  161.         }
  162.         }
  163.         if (!par_name[me->param_number]) {    /* Unknown field */
  164.             if (TRACE) fprintf(stderr,
  165.             "HTWSRC: Unknown field `%s' in source file\n",
  166.             me->param);
  167.         me->param_number = PAR_UNKNOWN;
  168.         me->state = before_value;    /* Could be better ignore */
  169.         return;
  170.         }
  171.         me->state = before_value;
  172.     } else {
  173.         if (me->param_count < PARAM_MAX)  me->param[me->param_count++] = c;
  174.     }
  175.     break;
  176.     
  177.     case before_value:
  178.         if (c==')') {
  179.         me->state = done;
  180.         return;            /* Done with input file */
  181.     }
  182.     if (WHITE(c)) return;        /* Skip white space */
  183.     me->param_count = 0;
  184.     if (c=='"') {
  185.         me->state = quoted_value;
  186.         break;
  187.     }
  188.     me->state = (c=='"') ? quoted_value : 
  189.             (c=='(') ? bracketed_value : value;
  190.     me->param[me->param_count++] = c;    /* Don't miss first character */
  191.     break;
  192.  
  193.     case value:
  194.         if (WHITE(c)) {
  195.         me->param[me->param_count] = 0;
  196.         StrAllocCopy(me->par_value[me->param_number], me->param);
  197.         me->state = before_tag;
  198.     } else {
  199.         if (me->param_count < PARAM_MAX)  me->param[me->param_count++] = c;
  200.     }
  201.     break;
  202.  
  203.     case bracketed_value:
  204.         if (c==')') {
  205.         me->param[me->param_count] = 0;
  206.         StrAllocCopy(me->par_value[me->param_number], me->param);
  207.         me->state = before_tag;
  208.         break;
  209.     }
  210.         if (me->param_count < PARAM_MAX)  me->param[me->param_count++] = c;
  211.     break;
  212.     
  213.     case quoted_value:
  214.         if (c=='"') {
  215.         me->param[me->param_count] = 0;
  216.         StrAllocCopy(me->par_value[me->param_number], me->param);
  217.         me->state = before_tag;
  218.         break;
  219.     }
  220.     
  221.     if (c=='\\') {        /* Ignore escape but switch state */
  222.         me->state = escape_in_quoted;
  223.         break;
  224.     }
  225.     /* Fall through! */
  226.  
  227.     case escape_in_quoted:
  228.         if (me->param_count < PARAM_MAX)  me->param[me->param_count++] = c;
  229.     me->state = quoted_value;
  230.     break;
  231.     
  232.     case done:                /* Ignore anything after EOF */
  233.     return;
  234.  
  235.     } /* switch me->state */
  236. }
  237.  
  238.  
  239. /*            Open Cache file
  240. **            ===============
  241. **
  242. **   Bugs: Maybe for filesystem-challenged platforms (MSDOS for example) we
  243. **   should make a hash code for the filename.
  244. */
  245.  
  246. #ifdef CACHE_FILE_PREFIX
  247. PRIVATE BOOL write_cache ARGS1(HTStream *, me)
  248. {
  249.     FILE * fp;
  250.     char cache_file_name[256];
  251.     char * www_database;
  252.     if (!me->par_value[PAR_DATABASE_NAME]
  253.         || !me->par_value[PAR_IP_NAME]
  254.     ) return NO;
  255.     
  256.     www_database = HTEscape(me->par_value[PAR_DATABASE_NAME], URL_XALPHAS);
  257.     sprintf(cache_file_name, "%sWSRC-%s:%s:%.100s.txt",
  258.         CACHE_FILE_PREFIX,
  259.     me->par_value[PAR_IP_NAME],
  260.     me->par_value[PAR_TCP_PORT] ? me->par_value[PAR_TCP_PORT] : "210",
  261.     www_database);
  262.     free(www_database);
  263.     fp = fopen(cache_file_name, "w");
  264.     if (!fp) return NO;
  265.     
  266.     if (me->par_value[PAR_DESCRIPTION])
  267.         fputs(me->par_value[PAR_DESCRIPTION], fp);
  268.     else 
  269.         fputs("Description not available\n", fp);
  270.     fclose(fp);
  271.     return YES;
  272. }
  273. #endif
  274.  
  275. /*            Output equivalent HTML
  276. **            ----------------------
  277. **
  278. */
  279.  
  280. void give_parameter ARGS2(HTStream *, me, int, p)
  281. {
  282.     PUTS(par_name[p]);
  283.     if (me->par_value[p]) {
  284.     PUTS(": ");
  285.     PUTS(me->par_value[p]);
  286.     PUTS("; ");
  287.     } else {
  288.         PUTS(" NOT GIVEN in source file; ");
  289.     }
  290. }
  291.  
  292.  
  293. /*            Generate Outout
  294. **            ===============
  295. */
  296. PRIVATE void WSRC_gen_html ARGS2(HTStream *, me, BOOL, source_file)
  297.  
  298. {
  299.     if (me->par_value[PAR_DATABASE_NAME]) {
  300.     char * shortname = 0;
  301.     int l;
  302.     StrAllocCopy(shortname, me->par_value[PAR_DATABASE_NAME]);
  303.     l = strlen(shortname);
  304.     if ( l > 4 && !strcasecomp(shortname + l -4, ".src")) {
  305.         shortname[l-4] = 0;    /* Chop of .src -- boring! */
  306.     }
  307.     
  308.     START(HTML_HEAD);
  309.     PUTS("\n");
  310.     START(HTML_TITLE);
  311.     PUTS(shortname);
  312.     PUTS(source_file ? " WAIS source file" : " index");
  313.     END(HTML_TITLE);
  314.     PUTS("\n");
  315.     END(HTML_HEAD);
  316.     
  317.     START(HTML_H1);
  318.     PUTS(shortname);
  319.     PUTS(source_file ? " description" : " index");
  320.     END(HTML_H1);
  321.     PUTS("\n");
  322.     if (shortname)
  323.         free(shortname);
  324.     }
  325.     
  326.     START(HTML_DL);        /* Definition list of details */
  327.     
  328.     if (source_file) {
  329.     START(HTML_DT);
  330.     PUTS("Access links");
  331.     START(HTML_DD);
  332.     if (me->par_value[PAR_IP_NAME] &&
  333.         me->par_value[PAR_DATABASE_NAME]) {
  334.     
  335.         char WSRC_address[256];
  336.         char * www_database;
  337.         www_database = HTEscape(me->par_value[PAR_DATABASE_NAME],
  338.             URL_XALPHAS);
  339.         sprintf(WSRC_address, "wais://%s%s%s/%s",
  340.         me->par_value[PAR_IP_NAME],
  341.         me->par_value[PAR_TCP_PORT] ? ":" : "",
  342.         me->par_value[PAR_TCP_PORT] ? me->par_value[PAR_TCP_PORT] :"",
  343.         www_database);
  344.     
  345.         HTStartAnchor(me->target, NULL, WSRC_address);
  346.         PUTS("Direct access");
  347.         END(HTML_A);
  348.         /** Proxy will be used if defined, so let user know that - FM **/
  349.         PUTS(" (or via proxy server, if defined), or");
  350.         START(HTML_BR);
  351.         /** Offer W3 Consortium gateway - FM **/
  352.         sprintf(WSRC_address, "http://www.w3.org:8001/%s%s%s/%s",
  353.         me->par_value[PAR_IP_NAME],
  354.         me->par_value[PAR_TCP_PORT] ? ":" : "",
  355.         me->par_value[PAR_TCP_PORT] ? me->par_value[PAR_TCP_PORT] :"",
  356.         www_database);
  357.         HTStartAnchor(me->target, NULL, WSRC_address);
  358.         PUTS("through W3 Consortium gateway");
  359.         END(HTML_A);
  360.  
  361.         free(www_database);
  362.         
  363.     } else {
  364.         give_parameter(me, PAR_IP_NAME);
  365.         give_parameter(me, PAR_DATABASE_NAME);
  366.     }
  367.     
  368.     } /* end if source_file */
  369.     
  370.     if (me->par_value[PAR_MAINTAINER]) {
  371.     START(HTML_DT);
  372.     PUTS("Maintainer");
  373.     START(HTML_DD);
  374.     PUTS(me->par_value[PAR_MAINTAINER]);
  375.     }
  376.     if (me->par_value[PAR_IP_NAME]) {
  377.         START(HTML_DT);
  378.         PUTS("Host");
  379.         START(HTML_DD);
  380.         PUTS(me->par_value[PAR_IP_NAME]);
  381.     }
  382.  
  383.     END(HTML_DL);
  384.  
  385.     if (me->par_value[PAR_DESCRIPTION]) {
  386.     START(HTML_PRE);        /* Preformatted description */
  387.     PUTS(me->par_value[PAR_DESCRIPTION]);
  388.     END(HTML_PRE);
  389.     }
  390.     
  391.     (*me->target->isa->_free)(me->target);
  392.     
  393.     return;
  394. } /* generate html */
  395.  
  396.  
  397. PRIVATE void WSRCParser_put_string ARGS2(HTStream *, context, CONST char*, str)
  398. {
  399.     CONST char *p;
  400.     for(p=str; *p; p++)
  401.         WSRCParser_put_character(context, *p);
  402. }
  403.  
  404.  
  405. PRIVATE void WSRCParser_write ARGS3(
  406.         HTStream *,     context,
  407.         CONST char*,     str,
  408.         int,         l)
  409. {
  410.     CONST char *p;
  411.     CONST char *e = str+l;
  412.     for(p=str; p<e; p++)
  413.         WSRCParser_put_character(context, *p);
  414. }
  415.  
  416.  
  417. PRIVATE void WSRCParser_free ARGS1(HTStream *, me)
  418. {
  419.     WSRC_gen_html(me, YES);
  420. #ifdef CACHE_FILE_PREFIX
  421.     write_cache(me);
  422. #endif
  423.     {
  424.     int p;
  425.     for(p=0; par_name[p]; p++) {    /* Clear out old values */
  426.         if (me->par_value[p]) {
  427.         free(me->par_value[p]);
  428.         }
  429.     }
  430.     }
  431.     free(me);
  432. }
  433.  
  434. PRIVATE void WSRCParser_abort ARGS2(HTStream *, me, HTError, e)
  435. {
  436.     WSRCParser_free(me);
  437. }
  438.  
  439.  
  440. /*        Stream subclass        -- method routines
  441. **        ---------------
  442. */
  443.  
  444. HTStreamClass WSRCParserClass = {
  445.     "WSRCParser",
  446.     WSRCParser_free,
  447.     WSRCParser_abort,
  448.     WSRCParser_put_character,
  449.      WSRCParser_put_string,
  450.     WSRCParser_write
  451.  
  452. };
  453.  
  454.  
  455. /*        Converter from WAIS Source to whatever
  456. **        --------------------------------------
  457. */
  458. PUBLIC HTStream* HTWSRCConvert ARGS3(
  459.     HTPresentation *,    pres,
  460.     HTParentAnchor *,    anchor,    
  461.     HTStream *,        sink)
  462. {
  463.     HTStream * me = (HTStream*) malloc(sizeof(*me));
  464.     if (!me) outofmem(__FILE__, "HTWSRCConvert");
  465.  
  466.     me->isa = &WSRCParserClass;
  467.     me->target = HTML_new(anchor, pres->rep_out, sink);
  468.  
  469.     {
  470.     int p;
  471.     for(p=0; p < PAR_COUNT; p++) {    /* Clear out parameter values */
  472.         me->par_value[p] = 0;
  473.     }
  474.     }
  475.     me->state = beginning;
  476.  
  477.     return me;
  478. }
  479.  
  480.