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

  1.  
  2. /*        Manage different file formats            HTFormat.c
  3. **        =============================
  4. **
  5. ** Bugs:
  6. **    Not reentrant.
  7. **
  8. **    Assumes the incoming stream is ASCII, rather than a local file
  9. **    format, and so ALWAYS converts from ASCII on non-ASCII machines.
  10. **    Therefore, non-ASCII machines can't read local files.
  11. **
  12. */
  13.  
  14.  
  15. #include "HTUtils.h"
  16. #include "tcp.h"
  17.  
  18. /* Implements:
  19. */
  20. #include "HTFormat.h"
  21.  
  22. PUBLIC float HTMaxSecs = 1e10;        /* No effective limit */
  23. PUBLIC float HTMaxLength = 1e10;    /* No effective limit */
  24.  
  25. PUBLIC int loading_length= -1;
  26.  
  27. #ifdef unix
  28. #ifdef NeXT
  29. #define PRESENT_POSTSCRIPT "open %s; /bin/rm -f %s\n"
  30. #else
  31. #define PRESENT_POSTSCRIPT "(ghostview %s ; /bin/rm -f %s)&\n"    
  32.     /* Full pathname would be better! */
  33. #endif
  34. #endif
  35.  
  36.  
  37. #include "HTML.h"
  38. #include "HTMLDTD.h"
  39. #include "HText.h"
  40. #include "HTAlert.h"
  41. #include "HTList.h"
  42. #include "HTInit.h"
  43. /*    Streams and structured streams which we use:
  44. */
  45. #include "HTFWriter.h"
  46. #include "HTPlain.h"
  47. #include "SGML.h"
  48. #include "HTML.h"
  49. #include "HTMLGen.h"
  50.  
  51. #include "LYexit.h"
  52. #include "LYLeaks.h"
  53.  
  54. PUBLIC    BOOL HTOutputSource = NO;    /* Flag: shortcut parser to stdout */
  55. /* extern  BOOL interactive; LJM */
  56.  
  57. #ifdef ORIGINAL
  58. struct _HTStream {
  59.       CONST HTStreamClass*    isa;
  60.       /* ... */
  61. };
  62. #endif
  63.  
  64. /* this version used by the NetToText stream */
  65. struct _HTStream {
  66.     CONST HTStreamClass *        isa;
  67.     BOOL            had_cr;
  68.     HTStream *         sink;
  69. };
  70.  
  71.  
  72. /*    Presentation methods
  73. **    --------------------
  74. */
  75.  
  76. PUBLIC  HTList * HTPresentations = 0;
  77. PUBLIC  HTPresentation* default_presentation = 0;
  78.  
  79. /*
  80.  *    To free off the presentation list.
  81.  */
  82. static void free_presentations NOPARAMS;
  83.  
  84. /*    Define a presentation system command for a content-type
  85. **    -------------------------------------------------------
  86. */
  87. PUBLIC void HTSetPresentation ARGS5(
  88.     CONST char *, representation,
  89.     CONST char *, command,
  90.     float,    quality,
  91.     float,    secs, 
  92.     float,    secs_per_byte
  93. ){
  94.  
  95.     HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
  96.     if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
  97.     
  98.     pres->rep = HTAtom_for(representation);
  99.     pres->rep_out = WWW_PRESENT;        /* Fixed for now ... :-) */
  100.     pres->converter = HTSaveAndExecute;        /* Fixed for now ...     */
  101.     pres->quality = quality;
  102.     pres->secs = secs;
  103.     pres->secs_per_byte = secs_per_byte;
  104.     pres->rep = HTAtom_for(representation);
  105.     pres->command = 0;
  106.     StrAllocCopy(pres->command, command);
  107.    
  108.     /*
  109.      *    Memory leak fixed.
  110.      *  05-28-94 Lynx 2-3-1 Garrett Arch Blythe
  111.      */ 
  112.     if (!HTPresentations)    {
  113.     HTPresentations = HTList_new();
  114.     atexit(free_presentations);
  115.     }
  116.     
  117.     if (strcmp(representation, "*")==0) {
  118.         if (default_presentation) free(default_presentation);
  119.     default_presentation = pres;
  120.     } else {
  121.         HTList_addObject(HTPresentations, pres);
  122.     }
  123. }
  124.  
  125.  
  126. /*    Define a built-in function for a content-type
  127. **    ---------------------------------------------
  128. */
  129. PUBLIC void HTSetConversion ARGS6(
  130.     CONST char *, representation_in,
  131.     CONST char *, representation_out,
  132.     HTConverter*,    converter,
  133.     float,    quality,
  134.     float,    secs, 
  135.     float,    secs_per_byte
  136. ){
  137.  
  138.     HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
  139.     if (pres == NULL) outofmem(__FILE__, "HTSetConversion");
  140.     
  141.     pres->rep = HTAtom_for(representation_in);
  142.     pres->rep_out = HTAtom_for(representation_out);
  143.     pres->converter = converter;
  144.     pres->command = NULL;        /* Fixed */
  145.     pres->quality = quality;
  146.     pres->secs = secs;
  147.     pres->secs_per_byte = secs_per_byte;
  148.     pres->command = 0;
  149.    
  150.     /*
  151.      *    Memory Leak fixed.
  152.      *    05-28-94 Lynx 2-3-1 Garrett Arch Blythe
  153.      */ 
  154.     if (!HTPresentations)    {
  155.     HTPresentations = HTList_new();
  156.     atexit(free_presentations);
  157.     }
  158.     
  159.     HTList_addObject(HTPresentations, pres);
  160. }
  161.  
  162. static void free_presentations NOARGS    {
  163. /*
  164.  *    Purpose:    Free the presentation list.
  165.  *    Arguments:    void
  166.  *    Return Value:    void
  167.  *    Remarks/Portability/Dependencies/Restrictions:
  168.  *        Made to clean up Lynx's bad leakage.
  169.  *    Revision History:
  170.  *        05-28-94    created Lynx 2-3-1 Garrett Arch Blythe
  171.  */
  172.  
  173.     /*
  174.      *    Loop through the list.
  175.      */
  176.     while(!HTList_isEmpty(HTPresentations))    {
  177.         /*
  178.          *    Free off each item.
  179.          *    May also need to free off it's items, but not sure
  180.          *    as of yet.
  181.          */
  182.         free(HTList_removeLastObject(HTPresentations));
  183.     }
  184.     /*
  185.      *    Free the list itself.
  186.      */
  187.     HTList_delete(HTPresentations);
  188. }
  189.  
  190.  
  191. /*    File buffering
  192. **    --------------
  193. **
  194. **    The input file is read using the macro which can read from
  195. **    a socket or a file.
  196. **    The input buffer size, if large will give greater efficiency and
  197. **    release the server faster, and if small will save space on PCs etc.
  198. */
  199. #define INPUT_BUFFER_SIZE 4096        /* Tradeoff */
  200. PRIVATE char input_buffer[INPUT_BUFFER_SIZE];
  201. PRIVATE char * input_pointer;
  202. PRIVATE char * input_limit;
  203. PRIVATE int input_file_number;
  204.  
  205.  
  206. /*    Set up the buffering
  207. **
  208. **    These routines are public because they are in fact needed by
  209. **    many parsers, and on PCs and Macs we should not duplicate
  210. **    the static buffer area.
  211. */
  212. PUBLIC void HTInitInput ARGS1 (int,file_number)
  213. {
  214.     input_file_number = file_number;
  215.     input_pointer = input_limit = input_buffer;
  216. }
  217.  
  218. PUBLIC int interrupted_in_htgetcharacter = 0;
  219. PUBLIC char HTGetCharacter NOARGS
  220. {
  221.     char ch;
  222.     interrupted_in_htgetcharacter = 0;
  223.     do {
  224.     if (input_pointer >= input_limit) {
  225.         int status = NETREAD(
  226.             input_file_number, input_buffer, INPUT_BUFFER_SIZE);
  227.         if (status <= 0) {
  228.         if (status == 0) return (char)EOF;
  229.         if (status == HT_INTERRUPTED)
  230.                 {
  231.                   if (TRACE)
  232.                     fprintf (stderr, "HTFormat: Interrupted in HTGetCharacter\n"
  233. );
  234.                   interrupted_in_htgetcharacter = 1;
  235.                   return (char)EOF;
  236.                 }
  237.         if (TRACE) fprintf(stderr,
  238.             "HTFormat: File read error %d\n", status);
  239.         return (char)EOF; /* -1 is returned by UCX at end of HTTP link */
  240.         }
  241.         input_pointer = input_buffer;
  242.         input_limit = input_buffer + status;
  243.     }
  244.     ch = *input_pointer++;
  245.     } while (ch == (char) 13); /* Ignore ASCII carriage return */
  246.     
  247.     return FROMASCII(ch);
  248. }
  249.  
  250. /*    Stream the data to an ouput file as binary
  251. */
  252. PUBLIC int HTOutputBinary ARGS2( int,         input,
  253.                   FILE *,     output)
  254. {
  255.     do {
  256.         int status = NETREAD(
  257.             input, input_buffer, INPUT_BUFFER_SIZE);
  258.         if (status <= 0) {
  259.         if (status == 0) return 0;
  260.         if (TRACE) fprintf(stderr,
  261.             "HTFormat: File read error %d\n", status);
  262.         return 2;            /* Error */
  263.         }
  264.         fwrite(input_buffer, sizeof(char), status, output);
  265.     } while (YES);
  266. }
  267.  
  268. /* match maintype/* to  any MIME type starting with maintype
  269.  *  for example   image/gif should match image/*
  270.  */
  271. PRIVATE int half_match ARGS2(char *,trial_type, char *,target)
  272. {
  273.     char *cp=strchr(trial_type,'/');
  274.  
  275.     /* if no '/' or no '*' */
  276.     if(!cp || *(cp+1) != '*')
  277.     return 0;
  278.  
  279.     if(TRACE)
  280.     fprintf(stderr,"HTFormat: comparing %s and %s for half match\n",
  281.                               trial_type, target);
  282.  
  283.     /* main type matches */
  284.     if(!strncmp(trial_type, target, (cp-trial_type)-1)) 
  285.     return 1;
  286.  
  287.     return 0;
  288. }
  289.  
  290.  
  291. /*        Create a filter stack
  292. **        ---------------------
  293. **
  294. **    If a wildcard match is made, a temporary HTPresentation
  295. **    structure is made to hold the destination format while the
  296. **    new stack is generated. This is just to pass the out format to
  297. **    MIME so far.  Storing the format of a stream in the stream might
  298. **    be a lot neater.
  299. **
  300. */
  301. PUBLIC HTStream * HTStreamStack ARGS4(
  302.     HTFormat,        rep_in,
  303.     HTFormat,        rep_out,
  304.     HTStream*,        sink,
  305.     HTParentAnchor*,    anchor)
  306. {
  307.     HTAtom * wildcard = HTAtom_for("*");
  308.     HTFormat source = WWW_SOURCE;
  309.     if (TRACE) fprintf(stderr,
  310.         "HTFormat: Constructing stream stack for %s to %s\n",
  311.     HTAtom_name(rep_in),    
  312.     HTAtom_name(rep_out));
  313.         
  314.        /* don't return on WWW_SOURCE some people might like
  315.         * to make use of the source!!!!  LJM
  316.         */
  317.      /* if (rep_out == WWW_SOURCE ||
  318.                rep_out == rep_in) return sink;  LJM */
  319.  
  320.      if(rep_out == rep_in) return sink;
  321.  
  322.     /* don't do anymore do it in the Lynx code at startup LJM */
  323.     /* if (!HTPresentations) HTFormatInit(); */    /* set up the list */
  324.     
  325.     {
  326.     int n = HTList_count(HTPresentations);
  327.     int i;
  328.     HTPresentation * pres, *match,
  329.             *strong_wildcard_match=0,
  330.             *weak_wildcard_match=0,
  331.             *last_default_match=0,
  332.             *strong_subtype_wildcard_match=0;
  333.  
  334.     for(i=0; i<n; i++) {
  335.         pres = HTList_objectAt(HTPresentations, i);
  336.         if (pres->rep == rep_in) {
  337.             if (pres->rep_out == rep_out) {
  338.             if(TRACE)
  339.             fprintf(stderr,"StreamStack: found exact match: %s\n",HTAtom_name(pres->rep));
  340.                 return (*pres->converter)(pres, anchor, sink);
  341.  
  342.         } else if (pres->rep_out == wildcard) {
  343.             if(!strong_wildcard_match)
  344.                 strong_wildcard_match = pres;
  345.             /* otherwise use the first one */
  346.             if(TRACE)
  347.             fprintf(stderr,"StreamStack: found strong wildcard match: %s\n",HTAtom_name(pres->rep));
  348.         }
  349.  
  350.         } else if(half_match(HTAtom_name(pres->rep),
  351.                         HTAtom_name(rep_in))) {
  352.         
  353.             if (pres->rep_out == rep_out) {
  354.             if(!strong_subtype_wildcard_match)
  355.                strong_subtype_wildcard_match = pres;
  356.             /* otherwise use the first one */
  357.             if(TRACE)
  358.             fprintf(stderr,"StreamStack: found strong subtype wildcard match: %s\n",HTAtom_name(pres->rep));
  359.         }
  360.         }
  361.  
  362.         if (pres->rep == WWW_SOURCE) {
  363.         if(pres->rep_out == rep_out) {
  364.             if(!weak_wildcard_match)
  365.                 weak_wildcard_match = pres;
  366.             /* otherwise use the first one */
  367.             if(TRACE)
  368.             fprintf(stderr,"StreamStack: found weak wildcard match: %s\n",HTAtom_name(pres->rep_out));
  369.  
  370.         }
  371.         if(pres->rep_out == wildcard) {
  372.             if(!last_default_match)
  373.                 last_default_match = pres;
  374.             /* otherwise use the first one */
  375.         }
  376.         }
  377.     }
  378.     
  379.     match = strong_subtype_wildcard_match ? strong_subtype_wildcard_match :
  380.         strong_wildcard_match ?    strong_wildcard_match : 
  381.         weak_wildcard_match ? weak_wildcard_match : 
  382.         last_default_match;
  383.     
  384.     if (match) {
  385.         HTPresentation temp;
  386.         temp = *match;            /* Specific instance */
  387.         temp.rep = rep_in;        /* yuk */
  388.         temp.rep_out = rep_out;        /* yuk */
  389.         if(TRACE)
  390.             fprintf(stderr,"StreamStack: Using %s\n",HTAtom_name(temp.rep_out));
  391.         return (*match->converter)(&temp, anchor, sink);
  392.         }
  393.     }
  394.  
  395.     return NULL;
  396. }
  397.     
  398.  
  399. /*        Find the cost of a filter stack
  400. **        -------------------------------
  401. **
  402. **    Must return the cost of the same stack which StreamStack would set up.
  403. **
  404. ** On entry,
  405. **    length    The size of the data to be converted
  406. */
  407. PUBLIC float HTStackValue ARGS4(
  408.     HTFormat,        rep_in,
  409.     HTFormat,        rep_out,
  410.     float,            initial_value,
  411.     long int,        length)
  412. {
  413.     HTAtom * wildcard = HTAtom_for("*");
  414.  
  415.     if (TRACE) fprintf(stderr,
  416.         "HTFormat: Evaluating stream stack for %s worth %.3f to %s\n",
  417.     HTAtom_name(rep_in),    initial_value,
  418.     HTAtom_name(rep_out));
  419.         
  420.     if (rep_out == WWW_SOURCE ||
  421.         rep_out == rep_in) return 0.0;
  422.  
  423.     /* don't do anymore do it in the Lynx code at startup LJM */
  424.     /* if (!HTPresentations) HTFormatInit(); */    /* set up the list */
  425.     
  426.     {
  427.     int n = HTList_count(HTPresentations);
  428.     int i;
  429.     HTPresentation * pres;
  430.     for(i=0; i<n; i++) {
  431.         pres = HTList_objectAt(HTPresentations, i);
  432.         if (pres->rep == rep_in && (
  433.                 pres->rep_out == rep_out ||
  434.             pres->rep_out == wildcard)) {
  435.             float value = initial_value * pres->quality;
  436.         if (HTMaxSecs != 0.0)
  437.         value = value - (length*pres->secs_per_byte + pres->secs)
  438.                              /HTMaxSecs;
  439.         return value;
  440.         }
  441.     }
  442.     }
  443.     
  444.     return -1e30;        /* Really bad */
  445.  
  446. }
  447.     
  448.  
  449. /*    Push data from a socket down a stream
  450. **    -------------------------------------
  451. **
  452. **   This routine is responsible for creating and PRESENTING any
  453. **   graphic (or other) objects described by the file.
  454. **
  455. **   The file number given is assumed to be a TELNET stream ie containing
  456. **   CRLF at the end of lines which need to be stripped to LF for unix
  457. **   when the format is textual.
  458. **
  459. */
  460.  
  461. PUBLIC int HTCopy ARGS2(
  462.     int,            file_number,
  463.     HTStream*,        sink)
  464. {
  465.     HTStreamClass targetClass;    
  466.     char line[256];
  467.     int bytes=0;
  468.     int rv = 0;
  469.     char * msg;
  470.  
  471.     if (loading_length == -1)
  472.         msg = "Read %d bytes of data.";
  473.     else
  474.         /* We have a loading_length. */
  475.         msg = "Read %d of %d bytes of data.";
  476.  
  477.     
  478. /*    Push the data down the stream
  479. **
  480. */
  481.     targetClass = *(sink->isa);    /* Copy pointers to procedures */
  482.     
  483.     /*    Push binary from socket down sink
  484.     **
  485.     **        This operation could be put into a main event loop
  486.     */
  487.     for(;;) {
  488.         int status;
  489.     extern char LYCancelDownload;
  490.  
  491.     if (LYCancelDownload) {
  492.         LYCancelDownload = FALSE;
  493.         (*targetClass._abort)(sink, NULL);
  494.         rv = -1;
  495.         goto finished;
  496.     }
  497.  
  498.         if (HTCheckForInterrupt())
  499.           {
  500.             _HTProgress ("Data transfer interrupted.");
  501.             (*targetClass._abort)(sink, NULL);
  502.         if(bytes)
  503.                 rv = HT_INTERRUPTED;
  504.         else
  505.         rv = -1;
  506.         goto finished;
  507.           }
  508.  
  509.         status = NETREAD(file_number, input_buffer, INPUT_BUFFER_SIZE);
  510.  
  511.     if (status <= 0) {
  512.         if (status == 0) 
  513.           break;
  514.         else if (status == HT_INTERRUPTED)
  515.               {
  516.                 _HTProgress ("Data transfer interrupted.");
  517.                 (*targetClass._abort)(sink, NULL);
  518.             if(bytes)
  519.                     rv = HT_INTERRUPTED;
  520.             else
  521.             rv = -1;
  522.             goto finished;
  523.               }
  524.         else if (SOCKET_ERRNO == ENOTCONN || SOCKET_ERRNO == ECONNRESET 
  525.                            || SOCKET_ERRNO == EPIPE)
  526.               {
  527.                 /* Arrrrgh, HTTP 0/1 compability problem, maybe. */
  528.         rv = -2;
  529.             goto finished;
  530.               }
  531.             break;
  532.     }
  533.  
  534. #ifdef NOT_ASCII
  535.     {
  536.         char * p;
  537.         for(p = input_buffer; p < input_buffer+status; p++) {
  538.         *p = FROMASCII(*p);
  539.         }
  540.     }
  541. #endif
  542.  
  543.     (*targetClass.put_block)(sink, input_buffer, status);
  544.  
  545.     bytes += status;
  546.         sprintf(line, msg, bytes, loading_length);
  547.         HTProgress(line);
  548.  
  549.     } /* next bufferload */
  550.  
  551.     _HTProgress("Data transfer complete");
  552.     NETCLOSE(file_number);
  553.     rv = HT_LOADED;
  554.  
  555. finished:
  556.     loading_length = -1;
  557.     return(rv);
  558.     
  559. }
  560.  
  561.  
  562.  
  563. /*    Push data from a file pointer down a stream
  564. **    -------------------------------------
  565. **
  566. **   This routine is responsible for creating and PRESENTING any
  567. **   graphic (or other) objects described by the file.
  568. **
  569. **
  570. */
  571. PUBLIC void HTFileCopy ARGS2(
  572.     FILE *,            fp,
  573.     HTStream*,        sink)
  574. {
  575.     HTStreamClass targetClass;    
  576.     
  577. /*    Push the data down the stream
  578. **
  579. */
  580.     targetClass = *(sink->isa);    /* Copy pointers to procedures */
  581.     
  582.     /*    Push binary from socket down sink
  583.     */
  584.     for(;;) {
  585.     int status = fread(
  586.            input_buffer, 1, INPUT_BUFFER_SIZE, fp);
  587.     if (status == 0) { /* EOF or error */
  588.         if (ferror(fp) == 0) break;
  589.         if (TRACE) fprintf(stderr,
  590.         "HTFormat: Read error, read returns %d\n", ferror(fp));
  591.         break;
  592.     }
  593.     (*targetClass.put_block)(sink, input_buffer, status);
  594.     } /* next bufferload */
  595.     
  596. }
  597.  
  598.  
  599.  
  600.  
  601. /*    Push data from a socket down a stream STRIPPING CR
  602. **    --------------------------------------------------
  603. **
  604. **   This routine is responsible for creating and PRESENTING any
  605. **   graphic (or other) objects described by the socket.
  606. **
  607. **   The file number given is assumed to be a TELNET stream ie containing
  608. **   CRLF at the end of lines which need to be stripped to LF for unix
  609. **   when the format is textual.
  610. **
  611. */
  612. PUBLIC void HTCopyNoCR ARGS2(
  613.     int,            file_number,
  614.     HTStream*,        sink)
  615. {
  616.     HTStreamClass targetClass;    
  617.     
  618. /*    Push the data, ignoring CRLF, down the stream
  619. **
  620. */
  621.     targetClass = *(sink->isa);    /* Copy pointers to procedures */
  622.  
  623. /*    Push text from telnet socket down sink
  624. **
  625. **    @@@@@ To push strings could be faster? (especially is we
  626. **    cheat and don't ignore CR! :-}
  627. */  
  628.     HTInitInput(file_number);
  629.     for(;;) {
  630.     char character;
  631.     character = HTGetCharacter();
  632.     if (character == (char)EOF) break;
  633.     (*targetClass.put_character)(sink, character);           
  634.     }
  635. }
  636.  
  637.  
  638.  
  639. /*    Parse a socket given format and file number
  640. **
  641. **   This routine is responsible for creating and PRESENTING any
  642. **   graphic (or other) objects described by the file.
  643. **
  644. **   The file number given is assumed to be a TELNET stream ie containing
  645. **   CRLF at the end of lines which need to be stripped to LF for unix
  646. **   when the format is textual.
  647. **
  648. */
  649. PUBLIC int HTParseSocket ARGS5(
  650.     HTFormat,        rep_in,
  651.     HTFormat,        format_out,
  652.     HTParentAnchor *,    anchor,
  653.     int,            file_number,
  654.     HTStream*,        sink)
  655. {
  656.     HTStream * stream;
  657.     HTStreamClass targetClass;
  658.     int rv;
  659.     extern char LYCancelDownload;
  660.  
  661.     stream = HTStreamStack(rep_in,
  662.             format_out,
  663.              sink , anchor);
  664.     
  665.     if (!stream) {
  666.         char buffer[1024];    /* @@@@@@@@ */
  667.         if (LYCancelDownload) {
  668.         LYCancelDownload = FALSE;
  669.         return -1;
  670.     }
  671.     sprintf(buffer, "Sorry, can't convert from %s to %s.",
  672.             HTAtom_name(rep_in), HTAtom_name(format_out));
  673.     if (TRACE) fprintf(stderr, "HTFormat: %s\n", buffer);
  674.         return HTLoadError(sink, 501, buffer); /* returns -501 */
  675.     }
  676.     
  677. /*
  678. **    Push the data, don't worry about CRLF we can strip them later.
  679. */
  680.     targetClass = *(stream->isa);    /* Copy pointers to procedures */
  681.     rv = HTCopy(file_number, stream);
  682.     if (rv != -1 && rv != HT_INTERRUPTED) (*targetClass._free)(stream);
  683.     
  684.     return rv; /* full: HT_LOADED;  partial: HT_INTERRUPTED;  no bytes: -1 */
  685. }
  686.  
  687.  
  688.  
  689. /*    Parse a file given format and file pointer
  690. **
  691. **   This routine is responsible for creating and PRESENTING any
  692. **   graphic (or other) objects described by the file.
  693. **
  694. **   The file number given is assumed to be a TELNET stream ie containing
  695. **   CRLF at the end of lines which need to be stripped to \n for unix
  696. **   when the format is textual.
  697. **
  698. */
  699. PUBLIC int HTParseFile ARGS5(
  700.     HTFormat,        rep_in,
  701.     HTFormat,        format_out,
  702.     HTParentAnchor *,    anchor,
  703.     FILE *,            fp,
  704.     HTStream*,        sink)
  705. {
  706.     HTStream * stream;
  707.     HTStreamClass targetClass;    
  708.  
  709.     stream = HTStreamStack(rep_in,
  710.             format_out,
  711.              sink , anchor);
  712.     
  713.     if (!stream) {
  714.         char buffer[1024];    /* @@@@@@@@ */
  715.     extern char LYCancelDownload;
  716.         if (LYCancelDownload) {
  717.         LYCancelDownload = FALSE;
  718.         return -1;
  719.     }
  720.     sprintf(buffer, "Sorry, can't convert from %s to %s.",
  721.         HTAtom_name(rep_in), HTAtom_name(format_out));
  722.     if (TRACE) fprintf(stderr, "HTFormat(in HTParseFile): %s\n", buffer);
  723.         return HTLoadError(sink, 501, buffer);
  724.     }
  725.     
  726. /*    Push the data down the stream
  727. **
  728. **
  729. **   @@  Bug:  This decision ought to be made based on "encoding"
  730. **   rather than on content-type.  @@@  When we handle encoding.
  731. **   The current method smells anyway.
  732. */
  733.     targetClass = *(stream->isa);    /* Copy pointers to procedures */
  734.     HTFileCopy(fp, stream);
  735.     (*targetClass._free)(stream);
  736.     
  737.     return HT_LOADED;
  738. }
  739.  
  740.  
  741. /*    Converter stream: Network Telnet to internal character text
  742. **    -----------------------------------------------------------
  743. **
  744. **    The input is assumed to be in ASCII, with lines delimited
  745. **    by (13,10) pairs, These pairs are converted into (CR,LF)
  746. **    pairs in the local representation.  The (CR,LF) sequence
  747. **    when found is changed to a '\n' character, the internal
  748. **    C representation of a new line.
  749. */
  750.  
  751.  
  752. PRIVATE void NetToText_put_character ARGS2(HTStream *, me, char, net_char)
  753. {
  754.     char c = FROMASCII(net_char);
  755.     if (me->had_cr) {
  756.         if (c==LF) {
  757.         me->sink->isa->put_character(me->sink, '\n');    /* Newline */
  758.         me->had_cr = NO;
  759.         return;
  760.         } else {
  761.         me->sink->isa->put_character(me->sink, CR);    /* leftover */
  762.     }
  763.     }
  764.     me->had_cr = (c==CR);
  765.     if (!me->had_cr)
  766.     me->sink->isa->put_character(me->sink, c);        /* normal */
  767. }
  768.  
  769. PRIVATE void NetToText_put_string ARGS2(HTStream *, me, CONST char *, s)
  770. {
  771.     CONST char * p;
  772.     for(p=s; *p; p++) NetToText_put_character(me, *p);
  773. }
  774.  
  775. PRIVATE void NetToText_put_block ARGS3(HTStream *, me, CONST char*, s, int, l)
  776. {
  777.     CONST char * p;
  778.     for(p=s; p<(s+l); p++) NetToText_put_character(me, *p);
  779. }
  780.  
  781. PRIVATE void NetToText_free ARGS1(HTStream *, me)
  782. {
  783.     (me->sink->isa->_free)(me->sink);        /* Close rest of pipe */
  784.     free(me);
  785. }
  786.  
  787. PRIVATE void NetToText_abort ARGS2(HTStream *, me, HTError, e)
  788. {
  789.     me->sink->isa->_abort(me->sink,e);        /* Abort rest of pipe */
  790.     free(me);
  791. }
  792.  
  793. /*    The class structure
  794. */
  795. PRIVATE HTStreamClass NetToTextClass = {
  796.     "NetToText",
  797.     NetToText_free,
  798.     NetToText_abort,
  799.     NetToText_put_character,
  800.     NetToText_put_string,
  801.     NetToText_put_block
  802. };
  803.  
  804. /*    The creation method
  805. */
  806. PUBLIC HTStream * HTNetToText ARGS1(HTStream *, sink)
  807. {
  808.     HTStream* me = (HTStream*)malloc(sizeof(*me));
  809.     if (me == NULL) outofmem(__FILE__, "NetToText");
  810.     me->isa = &NetToTextClass;
  811.     
  812.     me->had_cr = NO;
  813.     me->sink = sink;
  814.     return me;
  815. }
  816.  
  817.  
  818.