home *** CD-ROM | disk | FTP | other *** search
/ Collection of Internet / Collection of Internet.iso / msdos / lynx / source / www / library / implemen / htwsrc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-25  |  11.9 KB  |  537 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"capalloc.h"
  12. #include "HTWSRC.h"
  13. #include"capstdio.h"
  14.  
  15.  
  16. /* #include <sys/types.h>    already in tcp.h */
  17. /* #include <sys/stat.h>      this too         */
  18. #include <stdio.h>
  19. #include "HTML.h"
  20.  
  21. #include "HTUtils.h"
  22. #include "tcp.h"
  23. #include "HTParse.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. #define PAR_UNKNOWN 12
  66.     "unknown",
  67.     0,                /* Terminate list */
  68. #define PAR_COUNT 13
  69. } ;
  70.  
  71.  
  72. enum tokenstate { beginning, before_tag, colon, before_value,
  73.         value, bracketed_value, quoted_value, escape_in_quoted, done };
  74.  
  75.  
  76. /*        Stream Object
  77. **        ------------
  78. **
  79. **    The target is the structured stream down which the
  80. **    parsed results will go.
  81. **
  82. **    all the static stuff below should go in here to make it reentrant
  83. */
  84.  
  85. struct _HTStream {
  86.     CONST HTStreamClass *    isa;
  87.     HTStructured *        target;
  88.     char *            par_value[PAR_COUNT];
  89.     enum tokenstate     state;
  90.     char             param[BIG+1];
  91.     int            param_number;
  92.     int            param_count;
  93. };
  94.  
  95.  
  96.  
  97.  
  98. PUBLIC CONST char * hex = "0123456789ABCDEF";
  99.  
  100. /*    Decode one hex character
  101. */
  102.  
  103. PUBLIC char from_hex ARGS1(char, c)
  104. {
  105.     return           (c>='0')&&(c<='9') ? c-'0'
  106.             : (c>='A')&&(c<='F') ? c-'A'+10
  107.             : (c>='a')&&(c<='f') ? c-'a'+10
  108.             :               0;
  109. }
  110.  
  111.  
  112. /*            State machine
  113. **            -------------
  114. **
  115. ** On entry,
  116. **    me->state    is a valid state (see WSRC_init)
  117. **    c        is the next character
  118. ** On exit,
  119. **     returns    1    Done with file
  120. **        0    Continue. me->state is updated if necessary.
  121. **        -1    Syntax error error
  122. */
  123.  
  124.  
  125. /*        Treat One Character
  126. **        -------------------
  127. */
  128. PRIVATE void WSRCParser_put_character ARGS2(HTStream*, me, char, c)
  129. {
  130.     switch (me->state) {
  131.     case beginning:
  132.         if (c=='(') me->state = before_tag;
  133.     break;
  134.     
  135.     case before_tag:
  136.         if (c==')') {
  137.         me->state = done;
  138.         return;            /* Done with input file */
  139.     } else if (c==':') {
  140.         me->param_count = 0;
  141.         me->state = colon;
  142.     }                /* Ignore other text */
  143.     break;
  144.  
  145.     case colon:
  146.         if (WHITE(c)) {
  147.         me->param[me->param_count++] = 0;    /* Terminate */
  148.         for(me->param_number = 0; par_name[me->param_number]; me->param_number++) {
  149.         if (0==strcmp(par_name[me->param_number], me->param)) {
  150.             break;
  151.         }
  152.         }
  153.         if (!par_name[me->param_number]) {    /* Unknown field */
  154. #ifndef RELEASE
  155.         if (TRACE) fprintf(stderr,
  156.             "HTWSRC: Unknown field `%s' in source file\n",
  157.             me->param);
  158. #endif /* RELEASE */
  159.         me->param_number = PAR_UNKNOWN;
  160.         me->state = before_value;    /* Could be better ignore */
  161.         return;
  162.         }
  163.         me->state = before_value;
  164.     } else {
  165.         if (me->param_count < PARAM_MAX)  me->param[me->param_count++] = c;
  166.     }
  167.     break;
  168.     
  169.     case before_value:
  170.         if (c==')') {
  171.         me->state = done;
  172.         return;            /* Done with input file */
  173.     }
  174.     if (WHITE(c)) return;        /* Skip white space */
  175.     me->param_count = 0;
  176.     if (c=='"') {
  177.         me->state = quoted_value;
  178.         break;
  179.     }
  180.     me->state = (c=='"') ? quoted_value : 
  181.             (c=='(') ? bracketed_value : value;
  182.     me->param[me->param_count++] = c;    /* Don't miss first character */
  183.     break;
  184.  
  185.     case value:
  186.         if (WHITE(c)) {
  187.         me->param[me->param_count] = 0;
  188.         StrAllocCopy(me->par_value[me->param_number], me->param);
  189.         me->state = before_tag;
  190.     } else {
  191.         if (me->param_count < PARAM_MAX)  me->param[me->param_count++] = c;
  192.     }
  193.     break;
  194.  
  195.     case bracketed_value:
  196.         if (c==')') {
  197.         me->param[me->param_count] = 0;
  198.         StrAllocCopy(me->par_value[me->param_number], me->param);
  199.         me->state = before_tag;
  200.         break;
  201.     }
  202.         if (me->param_count < PARAM_MAX)  me->param[me->param_count++] = c;
  203.     break;
  204.     
  205.     case quoted_value:
  206.         if (c=='"') {
  207.         me->param[me->param_count] = 0;
  208.         StrAllocCopy(me->par_value[me->param_number], me->param);
  209.         me->state = before_tag;
  210.         break;
  211.     }
  212.     
  213.     if (c=='\\') {        /* Ignore escape but switch state */
  214.         me->state = escape_in_quoted;
  215.         break;
  216.     }
  217.     /* Fall through! */
  218.  
  219.     case escape_in_quoted:
  220.         if (me->param_count < PARAM_MAX)  me->param[me->param_count++] = c;
  221.     break;
  222.     
  223.     case done:                /* Ignore anything after EOF */
  224.     return;
  225.  
  226.     } /* switch me->state */
  227. }
  228.  
  229.  
  230. /*            Open Cache file
  231. **            ===============
  232. **
  233. **   Bugs: Maybe for filesystem-challenged platforms (MSDOS for example) we
  234. **   should make a hash code for the filename.
  235. */
  236.  
  237. #ifdef CACHE_FILE_PREFIX
  238. PRIVATE BOOL write_cache ARGS1(HTStream *, me)
  239. {
  240.     FILE * fp;
  241.     char cache_file_name[256];
  242.     char * www_database;
  243.     www_database = HTEscape(me->par_value[PAR_DATABASE_NAME], URL_XALPHAS);
  244.     sprintf(cache_file_name, "%sWSRC-%s:%s:%.100s.txt",
  245.         CACHE_FILE_PREFIX,
  246.     me->par_value[PAR_IP_NAME],
  247.     me->par_value[PAR_TCP_PORT] ? me->par_value[PAR_TCP_PORT] : "210",
  248.     www_database);
  249.     free(www_database);
  250.     fp = fopen(cache_file_name, "w");
  251.     if (!fp) return NO;
  252.     
  253.     if (me->par_value[PAR_DESCRIPTION])
  254.         fputs(me->par_value[PAR_DESCRIPTION], fp);
  255.     else 
  256.         fputs("Description not available\n", fp);
  257.     fclose(fp);
  258.     return YES;
  259. }
  260. #endif
  261.  
  262. /*            Output equivalent HTML
  263. **            ----------------------
  264. **
  265. */
  266.  
  267. void give_parameter ARGS2(HTStream *, me, int, p)
  268. {
  269.     PUTS(par_name[p]);
  270.     if (me->par_value[p]) {
  271.     PUTS(": ");
  272.     PUTS(me->par_value[p]);
  273.     PUTS("; ");
  274.     } else {
  275.         PUTS(" NOT GIVEN in source file; ");
  276.     }
  277. }
  278.  
  279.  
  280. /*            Generate Outout
  281. **            ===============
  282. */
  283. PRIVATE void WSRC_gen_html ARGS2(HTStream *, me, BOOL, source_file)
  284.  
  285. {
  286.     if (me->par_value[PAR_DATABASE_NAME]) {
  287.     char * shortname = 0;
  288.     int l;
  289.     StrAllocCopy(shortname, me->par_value[PAR_DATABASE_NAME]);
  290.     l = strlen(shortname);
  291.     if ( l > 4 && !strcasecomp(shortname + l -4, ".src")) {
  292.         shortname[l-4] = 0;    /* Chop of .src -- boring! */
  293.     }
  294.     
  295. #ifdef MSDOSMEM
  296.     {
  297.         extern void *vp_msdosmem;
  298.         extern void **vpp_msdosmem;
  299.         vp_msdosmem = NULL;
  300.         vpp_msdosmem = NULL;
  301.     }
  302. #endif /* MSDOSMEM */
  303.     START(HTML_TITLE);
  304.     PUTS(shortname);
  305.     PUTS(source_file ? " WAIS source file" : " index");
  306.     END(HTML_TITLE);
  307.     
  308. #ifdef MSDOSMEM
  309.     {
  310.         extern void *vp_msdosmem;
  311.         extern void **vpp_msdosmem;
  312.         vp_msdosmem = NULL;
  313.         vpp_msdosmem = NULL;
  314.     }
  315. #endif /* MSDOSMEM */
  316.     START(HTML_H1);
  317.     PUTS(shortname);
  318.     PUTS(source_file ? " description" : " index");
  319.     END(HTML_H1);
  320.     }
  321.     
  322. #ifdef MSDOSMEM
  323.     {
  324.         extern void *vp_msdosmem;
  325.         extern void **vpp_msdosmem;
  326.         vp_msdosmem = NULL;
  327.         vpp_msdosmem = NULL;
  328.     }
  329. #endif /* MSDOSMEM */
  330.     START(HTML_DL);        /* Definition list of details */
  331.     
  332.     if (source_file) {
  333. #ifdef MSDOSMEM
  334.     {
  335.         extern void *vp_msdosmem;
  336.         extern void **vpp_msdosmem;
  337.         vp_msdosmem = NULL;
  338.         vpp_msdosmem = NULL;
  339.     }
  340. #endif /* MSDOSMEM */
  341.     START(HTML_DT);
  342.     PUTS("Access links");
  343. #ifdef MSDOSMEM
  344.     {
  345.         extern void *vp_msdosmem;
  346.         extern void **vpp_msdosmem;
  347.         vp_msdosmem = NULL;
  348.         vpp_msdosmem = NULL;
  349.     }
  350. #endif /* MSDOSMEM */
  351.     START(HTML_DD);
  352.     if (me->par_value[PAR_IP_NAME] &&
  353.         me->par_value[PAR_DATABASE_NAME]) {
  354.     
  355.         char WSRC_address[256];
  356.         char * www_database;
  357.         www_database = HTEscape(me->par_value[PAR_DATABASE_NAME],
  358.             URL_XALPHAS);
  359.         sprintf(WSRC_address, "wais://%s:%s/%s",
  360.         me->par_value[PAR_IP_NAME],
  361.         me->par_value[PAR_TCP_PORT] ? me->par_value[PAR_TCP_PORT]
  362.             : "210",
  363.         www_database);
  364.     
  365.         HTStartAnchor(me->target, NULL, WSRC_address);
  366.         PUTS("Direct access");
  367.         END(HTML_A);
  368.         
  369.         PUTS(" or ");
  370.         
  371.         sprintf(WSRC_address, "http://info.cern.ch:8001/%s:%s/%s",
  372.         me->par_value[PAR_IP_NAME],
  373.         me->par_value[PAR_TCP_PORT] ? me->par_value[PAR_TCP_PORT]
  374.         : "210",
  375.         www_database);
  376.         HTStartAnchor(me->target, NULL, WSRC_address);
  377.         PUTS("through CERN gateway");
  378.         END(HTML_A);
  379.         
  380.         free(www_database);
  381.         
  382.     } else {
  383.         give_parameter(me, PAR_IP_NAME);
  384.         give_parameter(me, PAR_IP_NAME);
  385.     }
  386.     
  387.     } /* end if source_file */
  388.     
  389.     if (me->par_value[PAR_MAINTAINER]) {
  390. #ifdef MSDOSMEM
  391.     {
  392.         extern void *vp_msdosmem;
  393.         extern void **vpp_msdosmem;
  394.         vp_msdosmem = NULL;
  395.         vpp_msdosmem = NULL;
  396.     }
  397. #endif /* MSDOSMEM */
  398.     START(HTML_DT);
  399.     PUTS("Maintainer");
  400. #ifdef MSDOSMEM
  401.     {
  402.         extern void *vp_msdosmem;
  403.         extern void **vpp_msdosmem;
  404.         vp_msdosmem = NULL;
  405.         vpp_msdosmem = NULL;
  406.     }
  407. #endif /* MSDOSMEM */
  408.     START(HTML_DD);
  409.     PUTS(me->par_value[PAR_MAINTAINER]);
  410.     }
  411. #ifdef MSDOSMEM
  412.     {
  413.         extern void *vp_msdosmem;
  414.         extern void **vpp_msdosmem;
  415.         vp_msdosmem = NULL;
  416.         vpp_msdosmem = NULL;
  417.     }
  418. #endif /* MSDOSMEM */
  419.     START(HTML_DT);
  420.     PUTS("Host");
  421. #ifdef MSDOSMEM
  422.     {
  423.         extern void *vp_msdosmem;
  424.         extern void **vpp_msdosmem;
  425.         vp_msdosmem = NULL;
  426.         vpp_msdosmem = NULL;
  427.     }
  428. #endif /* MSDOSMEM */
  429.     START(HTML_DD);
  430.     PUTS(me->par_value[PAR_IP_NAME]);
  431.  
  432.     END(HTML_DL);
  433.  
  434.     if (me->par_value[PAR_DESCRIPTION]) {
  435. #ifdef MSDOSMEM
  436.     {
  437.         extern void *vp_msdosmem;
  438.         extern void **vpp_msdosmem;
  439.         vp_msdosmem = NULL;
  440.         vpp_msdosmem = NULL;
  441.     }
  442. #endif /* MSDOSMEM */
  443.     START(HTML_PRE);        /* Preformatted description */
  444.     PUTS(me->par_value[PAR_DESCRIPTION]);
  445.     END(HTML_PRE);
  446.     }
  447.     
  448.     (*me->target->isa->free)(me->target);
  449.     
  450.     return;
  451. } /* generate html */
  452.  
  453.  
  454. PRIVATE void WSRCParser_put_string ARGS2(HTStream *, context, CONST char*, str)
  455. {
  456.     CONST char *p;
  457.     for(p=str; *p; p++)
  458.         WSRCParser_put_character(context, *p);
  459. }
  460.  
  461.  
  462. PRIVATE void WSRCParser_write ARGS3(
  463.         HTStream *,     context,
  464.         CONST char*,     str,
  465.         int,         l)
  466. {
  467.     CONST char *p;
  468.     CONST char *e = str+l;
  469.     for(p=str; p<e; p++)
  470.         WSRCParser_put_character(context, *p);
  471. }
  472.  
  473.  
  474. PRIVATE void WSRCParser_free ARGS1(HTStream *, me)
  475. {
  476.     WSRC_gen_html(me, YES);
  477. #ifdef CACHE_FILE_PREFIX
  478.     write_cache(me);
  479. #endif
  480.     {
  481.     int p;
  482.     for(p=0; par_name[p]; p++) {    /* Clear out old values */
  483.         if (me->par_value[p]) {
  484.         free(me->par_value[p]);
  485.         }
  486.     }
  487.     }
  488.     free(me);
  489. }
  490.  
  491. PRIVATE void WSRCParser_abort ARGS1(HTStream *, me)
  492. {
  493.     WSRCParser_free(me);
  494. }
  495.  
  496.  
  497. /*        Stream subclass        -- method routines
  498. **        ---------------
  499. */
  500.  
  501. HTStreamClass WSRCParserClass = {
  502.     "WSRCParser",
  503.     WSRCParser_free,
  504.     WSRCParser_abort,
  505.     WSRCParser_put_character,
  506.      WSRCParser_put_string,
  507.     WSRCParser_write
  508.  
  509. };
  510.  
  511.  
  512. /*        Converter from WAIS Source to whatever
  513. **        --------------------------------------
  514. */
  515. PUBLIC HTStream* HTWSRCConvert ARGS3(
  516.     HTPresentation *,    pres,
  517.     HTParentAnchor *,    anchor,    
  518.     HTStream *,        sink)
  519. {
  520.     HTStream * me = (HTStream*) malloc(sizeof(*me));
  521.     if (!me) outofmem(__FILE__, "HTWSRCConvert");
  522.  
  523.     me->isa = &WSRCParserClass;
  524.     me->target = HTML_new(anchor, pres->rep_out, sink);
  525.  
  526.     {
  527.     int p;
  528.     for(p=0; p < PAR_COUNT; p++) {    /* Clear out parameter values */
  529.         me->par_value[p] = 0;
  530.     }
  531.     }
  532.     me->state = beginning;
  533.  
  534.     return me;
  535. }
  536.  
  537.