/* arclynx - simple version of Lynx for Acorn machines
 * (c) 1996 Andrew Wood
 *
 * Routines contained in this file (a_parse.c):
 *   lynx_parse()          - last modified 96/07/23
 *   lynx_read_type()      - last modified 96/07/17
 *   lynx_store_line()     - last modified 96/07/17
 *   lynx_parse_text()     - last modified 96/07/18
 *   lynx_html_addchar()   - last modified 96/07/18
 *   lynx_parse_html()     - last modified 96/07/18
 *   lynx_html_str()       - last modified 96/07/17
 *   lynx_getchar()        - last modified 96/07/18
 *   lynx_html_addstring() - last modified 96/07/18
 */

#include "arclynx.h"
#include <string.h>
#include <roslib.h>


typedef struct {                                    /* document parsing data */
 char bold,italic,heading,a_name,a_href,preformatted,centred;/* format flags */
 int left_margin,right_margin;        /* current left and right margin sizes */
 long last_space_pos;                          /* position of previous space */
 int p;                                        /* current position in string */
 int width;                                               /* width of screen */
 int charsleft;                              /* characters left on this line */
 int written;                                /* writeable characters written */
} Parse;


enum {                                       /* tags that can be understood: */
 HTML_A,
 HTML_ALIGN,
 HTML_ALT,
 HTML_B,
 HTML_BLOCKQUOTE,
 HTML_BR,
 HTML_CENTER,
 HTML_CENTRE,
 HTML_DD,
 HTML_DL,
 HTML_DT,
 HTML_EM,
 HTML_H1,
 HTML_H2,
 HTML_H3,
 HTML_H4,
 HTML_H5,
 HTML_H6,
 HTML_HR,
 HTML_HREF,
 HTML_I,
 HTML_IMG,
 HTML_LI,
 HTML_NAME,
 HTML_OL,
 HTML_P,
 HTML_PRE,
 HTML_STRONG,
 HTML_TITLE,
 HTML_UL,
 NUM_HTML_TAGS
};
enum {                                                     /* types of list: */
 LIST_UL,
 LIST_DL,
 LIST_OL,
 NUM_LIST_TYPES
};


int lynx_read_type(Status *);     /* return 0 for text file, 1 for HTML file */
void lynx_store_line(Status *,char *);               /* write line to memory */
void lynx_parse_text(Status *);                           /* parse text file */
void lynx_html_addchar(Status *,Parse *,int);       /* add character to line */
void lynx_parse_html(Status *);                           /* parse HTML file */
char *lynx_html_str(char *);                   /* extract string from quotes */
int lynx_getchar(Status *,char);                 /* read byte from open file */
void lynx_html_addstring(Status *,Parse *,char *);     /* add string to line */


/******************************************************************************
 * lynx_parse(status) - parse currently open file for displaying
 *
 * NB this routine uses status->temp
 */
void lynx_parse(Status *status) {
 lynx_clear_document(&(status->build));           /* clear previous document */
 lynx_getchar(status,0);
 if (lynx_read_type(status)==0) {
  lynx_parse_text(status);
 } else {
  lynx_parse_html(status);
 }
 fclose(status->build.fptr); status->build.fptr=NULL;          /* close file */
}


/******************************************************************************
 * lynx_read_type(status) - return 0 if file is a text file, 1 if it is HTML
 */
int lynx_read_type(Status *status) {
 static os_regset r;
 r.r[0]=17;
 r.r[1]=status->build.filename;
 os_swi(0x08,&r);
 if (((r.r[2]>>8)&(0xFFF))==0xFAF) return(1);
 return(0);
}


/******************************************************************************
 * lynx_store_line(status,temp) - add line in temp to document in memory
 */
void lynx_store_line(Status *status,char *temp) {
 static int size;                                          /* size of string */
 size=0; while(temp[size]!=0) {                       /* find string length: */
  switch(temp[size]) {
   case LYNX_A_HREF_CODE:
   case LYNX_A_NAME_CODE:size++; size++; break;
   case LYNX_SPACES_CODE:size++; break;
   default:break;
  }
  size++;
 }
 status->build.line[status->build.lines]=(char *)malloc(size+1); /* allocate */
 if (status->build.line[status->build.lines]==NULL) {     /* abort if failed */
  status->temp[0]=0; return;                              /**/
 }
 memcpy(status->build.line[status->build.lines],temp,size+1); /* copy string */
 status->build.lines++;                               /* line has been added */
 temp[0]=0;                                   /* blank temporary line string */
}


/******************************************************************************
 * lynx_getchar(status,flag) - return next character from open file
 */
int lynx_getchar(Status *status,char flag) {
 static char buffer[256];
 static long file_size;
 static long file_pos;
 static int buf_pos;
 static long transfer;
 static int c;
 if (flag==0) {
  fseek(status->build.fptr,0,SEEK_END); file_size=ftell(status->build.fptr);
  fseek(status->build.fptr,0,SEEK_SET); file_pos=0;
  transfer=file_size-file_pos; if (transfer>256) transfer=256;
  fread(buffer,1,transfer,status->build.fptr);
  buf_pos=0; return(0);
 }
 c=buffer[buf_pos]; buf_pos++;
 if (buf_pos>=transfer) {
  file_pos+=transfer; buf_pos=0;
  transfer=file_size-file_pos; if (transfer>256) transfer=256;
  if (transfer<=0) {
   fseek(status->build.fptr,0,SEEK_END);                     /* cause an EOF */
   fgetc(status->build.fptr);                                /**/
   return(c);
  }
  fseek(status->build.fptr,file_pos,SEEK_SET);
  fread(buffer,1,transfer,status->build.fptr);
 }
 fseek(status->build.fptr,file_pos+buf_pos,SEEK_SET);
 return(c);
}


/******************************************************************************
 * lynx_parse_text(status) - parse currently open file as text file
 *
 * NB this routine uses status->temp
 */
void lynx_parse_text(Status *status) {
 static long size,curpos;                     /* file size, current position */
 static int p;                                         /* percent last shown */
 static int c;                            /* character read from file stream */
 static int a;                                             /* misc. variable */
 static char temp[256];                           /* line creation workspace */
 Screen *screen;                                       /* screen information */
 screen=awterm_workspace();                                   /* get pointer */
 strncpy(status->build.title,status->build.url,60);                 /* title */
 p=-1;                              /* no percentage indicator displayed yet */
 fseek(status->build.fptr,0,SEEK_END); size=ftell(status->build.fptr); /*size*/
 if (size==0) size=1;
 fseek(status->build.fptr,0,SEEK_SET);            /* return to start of file */
 temp[0]=0;                                                    /* blank line */
 while (!feof(status->build.fptr)) {
  curpos=ftell(status->build.fptr);
  if ((100*curpos/size)>=(p+1)) {
   p+=1;
   sprintf(status->temp,"Reading text file: %d%% done",p);
   awterm_status(status->temp);
  }
  c=lynx_getchar(status,1);
  a=strlen(temp);
  switch(c) {
   case 9:do {strcat(temp," ");} while((strlen(temp)%8)!=0); break;
   case 10:lynx_store_line(status,temp); break;
   case 13:break;
   default:
    if (c>31) {
     temp[a]=c; a++; temp[a]=0;
     if (a>=screen->width) lynx_store_line(status,temp);
    }
    break;
  }
 }
 lynx_store_line(status,temp);
}


/******************************************************************************
 * lynx_html_addstring(status,parse,string) - add 'string' to line
 */
void lynx_html_addstring(Status *status,Parse *parse,char *string) {
 static int i;
 for(i=0; i<strlen(string); i++) {lynx_html_addchar(status,parse,string[i]);}
}


/******************************************************************************
 * lynx_html_addchar(status,parse,c) - add character to line, formatting text
 *                                     if necessary
 */
void lynx_html_addchar(Status *status,Parse *parse,int c) {
 static char temp[256];
 static char bold=0,italic=0,heading=0,a_href=0,a_name=0;
 int a;
 if (parse->p<0) {
  parse->p=0;
  temp[parse->p]=LYNX_SPACES_CODE; parse->p++;
  temp[parse->p]=parse->left_margin; parse->p++;
  temp[parse->p]=0;
  parse->charsleft=parse->width-parse->left_margin-parse->right_margin;
  parse->last_space_pos=0; parse->written=0;
  bold=0; italic=0; heading=0; a_href=0; a_name=0;
 }
 if (c>256) {
  c-=256;
  switch(c) {
   case LYNX_BOLD_CODE:
   case LYNX_ITALIC_CODE:
   case LYNX_HEADING_CODE:
   case LYNX_A_HREF_END:
   case LYNX_A_NAME_END:temp[parse->p]=c; parse->p++; temp[parse->p]=0; break;
   case LYNX_A_HREF_CODE:
    temp[parse->p]=c; parse->p++;
    temp[parse->p]=(status->build.anchor_hrefs % 256); parse->p++;
    temp[parse->p]=(status->build.anchor_hrefs >> 8); parse->p++;
    temp[parse->p]=0; break;
   case LYNX_A_NAME_CODE:
    temp[parse->p]=c; parse->p++;
    temp[parse->p]=(status->build.anchor_names % 256); parse->p++;
    temp[parse->p]=(status->build.anchor_names >> 8); parse->p++;
    temp[parse->p]=0; break;
   default:break;
  }
  return;
 }
 if (c==-3) {if (status->build.lines>0) c=-1;}
 if (c==-2) {if (parse->written>0) c=-1;}
 if (c==-1) {
  if (parse->centred) {
   temp[1]+=(parse->width-(temp[1]+string_length(temp)))/2;
  }
  lynx_store_line(status,temp); parse->p=-1; return;
 }
 if (c<-100) {
  c+=1000;
  if (c==LIST_UL) {
   temp[1]=parse->left_margin-2;
   lynx_html_addchar(status,parse,'+');
   lynx_html_addchar(status,parse,' ');
   return;
  }
  if (c>=LIST_OL) {
   temp[1]=parse->left_margin-2;
   sprintf(temp+parse->p,"%d. ",(c-LIST_OL)+1);
   parse->p+=strlen(temp+parse->p);
   return;
  }
 }
 if (c<=0) return;
 if (parse->bold!=bold) {
  bold=parse->bold;
  lynx_html_addchar(status,parse,256+LYNX_BOLD_CODE);
 }
 if (parse->italic!=italic) {
  italic=parse->italic;
  lynx_html_addchar(status,parse,256+LYNX_ITALIC_CODE);
 }
 if (parse->heading!=heading) {
  heading=parse->heading;
  lynx_html_addchar(status,parse,256+LYNX_HEADING_CODE);
 }
 if (parse->a_href!=a_href) {
  a_href=parse->a_href;
  if (a_href) {
   lynx_html_addchar(status,parse,256+LYNX_A_HREF_CODE);
  } else {
   lynx_html_addchar(status,parse,256+LYNX_A_HREF_END);
  }
 }
 if (parse->a_name!=a_name) {
  a_name=parse->a_name;
  if (a_name) {
   lynx_html_addchar(status,parse,256+LYNX_A_NAME_CODE);
  } else {
   lynx_html_addchar(status,parse,256+LYNX_A_NAME_END);
  }
 }
 if (parse->preformatted) {
  if (c==10) {lynx_store_line(status,temp); parse->p=-1; return;}
  if (c<32) c=32;
  temp[parse->p]=c; parse->p++; temp[parse->p]=0;
  if (parse->p>=parse->width) {
   lynx_store_line(status,temp); parse->p=-1; return;
  }
  return;
 }
 if (c<32) c=32;
 if ((c==32) & (parse->written==0)) return;    /* no spaces at start of line */
 if ((c==32) & (parse->last_space_pos==parse->p-1)) return; /* no 2 in a row */
 if (c==32) parse->last_space_pos=parse->p;
 temp[parse->p]=c; parse->p++; temp[parse->p]=0;
 parse->charsleft--; parse->written++;
 if (parse->charsleft<=0) {                         /* reached end of a line */
  if ((c==32) | (parse->last_space_pos<=0)) {             /* need word wrap? */
   lynx_store_line(status,temp); parse->p=-1;                          /* no */
  } else {
   a=parse->last_space_pos; temp[a]=0; a++; /* yes - terminate at last space */
   lynx_store_line(status,temp); parse->p=-1;       /* ...and store the line */
   bold=0; italic=0; heading=0; a_href=0; a_name=0;
   while(temp[a]!=0) {
    switch(temp[a]) {
     case LYNX_BOLD_CODE:bold=1-bold; break;
     case LYNX_ITALIC_CODE:italic=1-italic; break;
     case LYNX_HEADING_CODE:heading=1-heading; break;
     case LYNX_A_HREF_CODE:a_href=1; a+=2; break;
     case LYNX_A_HREF_END:a_href=0; break;
     case LYNX_A_NAME_CODE:a_name=1; a+=2; break;
     case LYNX_A_NAME_END:a_name=0; break;
     default:lynx_html_addchar(status,parse,temp[a]); break;
    }
    a++;
   }
  }
 }
}


/******************************************************************************
 * lynx_html_str(string) - returns string containing the string enclosed in
 *                         quotes or spaces in 'string'
 */
char *lynx_html_str(char *string) {
 static char temp[256];
 static int i,c;
 static char quotes;
 temp[0]=0; quotes=0;
 while((string[0]=='\"') | (string[0]==' ') | 
       (string[0]==10) | (string[0]==13)) {
  if (string[0]=='\"') quotes=1;
  string++;
 }
 strcpy(temp,string);
 if (quotes) {c='\"';} else {c=' ';}
 for(i=0; i<strlen(temp); i++) {if (temp[i]==c) temp[i]=0;}
 return(temp);
}


/******************************************************************************
 * lynx_parse_html(status) - parse currently open file as HTML file
 *
 * NB this routine uses status->temp
 */
void lynx_parse_html(Status *status) {
 static long size,curpos;                     /* file size, current position */
 static int p;                                         /* percent last shown */
 static int c;                            /* character read from file stream */
 static int a,b,i,tag;                                  /* general variables */
 static char *t;                                        /* temporary pointer */
 static char title;                                  /* "writing title" flag */
 static Parse parse;                                  /* parsing information */
 static Screen *screen;                                /* screen information */
 static char yes;          /* flag; if set, tag turning on, else turning off */
 static char quit;                                              /* quit flag */
 static int list_depth;                             /* depth of list nesting */
 static int href;                          /* 1 if anchor is href, 0 if name */
 static char list[MAX_LIST_DEPTH];                             /* list stack */
 static char *tags[]={                                     /* HTML tag list: */
 "a",
 "align",
 "alt",
 "b",
 "blockquote",
 "br",
 "center",
 "centre",
 "dd",
 "dl",
 "dt",
 "em",
 "h1",
 "h2",
 "h3",
 "h4",
 "h5",
 "h6",
 "hr",
 "href",
 "i",
 "img",
 "li",
 "name",
 "ol",
 "p",
 "pre",
 "strong",
 "title",
 "ul",
 "END"};
 screen=awterm_workspace();                              /* get info pointer */
 strncpy(status->build.title,status->build.url,60);         /* initial title */
 p=-1;                              /* no percentage indicator displayed yet */
 fseek(status->build.fptr,0,SEEK_END); size=ftell(status->build.fptr); /*size*/
 if (size==0) size=1;
 fseek(status->build.fptr,0,SEEK_SET);            /* return to start of file */
 parse.bold=0; parse.italic=0; parse.heading=0;
 parse.a_name=0; parse.a_href=0;
 parse.preformatted=0; parse.centred=0;
 parse.left_margin=3; parse.right_margin=3;
 parse.last_space_pos=0;
 parse.width=screen->width;
 parse.p=-1;
 parse.charsleft=0;
 parse.written=0;
 title=0;
 list_depth=0;
 quit=0;
 while ((!feof(status->build.fptr)) & (!quit)) {
  curpos=ftell(status->build.fptr);
  if ((100*curpos/size)>=(p+1)) {
   p+=1;
   sprintf(status->temp,"Parsing document: %d%% done",p);
   awterm_status(status->temp);
   c=awterm_readkey(); if ((c>='A') & (c<='Z')) c+=32;
   if (c=='q') quit=1;
  }
  c=lynx_getchar(status,1);
  switch(c) {
   case 13:break;
   case '>':break;
   case '<':
    a=0; status->temp[a]=0; c=lynx_getchar(status,1);
    while ((!feof(status->build.fptr)) & (c!='>')) {
     if (c<32) c=32;
     status->temp[a]=c; a++; status->temp[a]=0; status->temp[a+1]=0;
     if (a<(LYNX_TEMP_WORKSPACE-2)) {
      c=lynx_getchar(status,1);
     } else {c='>';}
    }
    t=status->temp;
    if (t[0]=='/') {yes=0; t++;} else {yes=1;}
    tag=-1; for(i=0; i<NUM_HTML_TAGS; i++) {
     if (strcmp(tags[i],word_lterm(t))==0) {tag=i; i=NUM_HTML_TAGS;}
    }
    t+=strlen(word_lterm(t)); t++;
    switch(tag) {
     case HTML_A:
      if (yes) {
       href=-1;
       while ((t[0]!=0) & (href==-1)) {
        if (strcmp(tags[HTML_HREF],word_lterm(t))==0) href=1;
        if (strcmp(tags[HTML_NAME],word_lterm(t))==0) href=0;
        t+=strlen(word_lterm(t)); t++;
       }
       if (href==1) {
        a=status->build.anchor_hrefs;
        status->build.anchor_href[a] =
         (char *)malloc(strlen(lynx_html_str(t))+1);
        if (status->build.anchor_href[a]!=NULL) {
         strcpy(status->build.anchor_href[a],lynx_html_str(t));
         parse.a_href=1;
        } else {href=-1;}
       }
       if (href==0) {
        a=status->build.anchor_names;
        status->build.anchor_name[a] =
         (char *)malloc(strlen(lynx_html_str(t))+1);
        if (status->build.anchor_name[a]!=NULL) {
         strcpy(status->build.anchor_name[a],lynx_html_str(t));
         parse.a_name=1;
        } else {href=-1;}
       }
      } else {
       if (href==1) {
        parse.a_href=0; status->build.anchor_hrefs++;
       }
       if (href==0) {
        parse.a_name=0; status->build.anchor_names++;
       }
      }
      break;
     case HTML_STRONG:
     case HTML_B:parse.bold=yes; break;
     case HTML_BLOCKQUOTE:
      if (yes) {
       parse.left_margin+=3; parse.right_margin+=3;
      } else {
       parse.left_margin-=3; parse.right_margin-=3;
      }
      lynx_html_addchar(status,&parse,-1);
      break;
     case HTML_BR:lynx_html_addchar(status,&parse,-1); break;
     case HTML_CENTER:
     case HTML_CENTRE:parse.centred=yes; break;
     case HTML_DD:
      if (yes) {
       parse.left_margin=list_depth*3+3;
       lynx_html_addchar(status,&parse,-2);
      } else {
       parse.left_margin=list_depth*3+0;
      }
      break;
     case HTML_DL:
      if (yes) {
       parse.left_margin=list_depth*3+3;
       list[list_depth]=LIST_DL; list_depth++;
       lynx_html_addchar(status,&parse,-1);
      } else {
       parse.left_margin=list_depth*3+0;
       list_depth--; if (list_depth<0) list_depth=0;
       lynx_html_addchar(status,&parse,-1);
      }
      break;
     case HTML_DT:
      if (yes) {
       parse.left_margin=list_depth*3+0;
       lynx_html_addchar(status,&parse,-2);
      } else {
       parse.left_margin=list_depth*3+3;
      }
      break;
     case HTML_H1:
     case HTML_H2:
     case HTML_H3:
     case HTML_H4:
     case HTML_H5:
     case HTML_H6:
      lynx_html_addchar(status,&parse,-3);
      parse.bold=0; parse.italic=0; parse.heading=yes;
      parse.a_name=0; parse.a_href=0; parse.centred=0;
      if (yes) {
       while (t[0]!=0) {
        if (strcmp(tags[HTML_ALIGN],word_lterm(t))==0) {
         t+=strlen(word_lterm(t)); t++;
         if (strcmp(tags[HTML_CENTER],word_lterm(t))==0) parse.centred=1;
         if (strcmp(tags[HTML_CENTRE],word_lterm(t))==0) parse.centred=1;
        }
        t+=strlen(word_lterm(t)); t++;
       }
      }
      if (yes) {lynx_html_addchar(status,&parse,-1);}
      else {lynx_html_addchar(status,&parse,-2);}
      break;
     case HTML_HR:
      lynx_html_addchar(status,&parse,-2);
      a=parse.centred; parse.centred=1;
      for(b=0; b<40; b++) lynx_html_addchar(status,&parse,152);
      lynx_html_addchar(status,&parse,-2);
      parse.centred=a;
      break;
     case HTML_EM:
     case HTML_I:parse.italic=yes; break;
     case HTML_IMG:
      if (yes) {
       a=0;
       while (t[0]!=0) {
        if (strcmp(tags[HTML_ALT],word_lterm(t))==0) {
         t+=strlen(word_lterm(t)); t++; a=1;
         if (strlen(lynx_html_str(t))>0) {
          lynx_html_addchar(status,&parse,'[');
          lynx_html_addstring(status,&parse,lynx_html_str(t));
          lynx_html_addchar(status,&parse,']');
         }
        }
        t+=strlen(word_lterm(t)); t++;
       }
       if (!a) lynx_html_addstring(status,&parse,"[IMAGE]");
      }
      break;
     case HTML_LI:
      if (yes) {
       lynx_html_addchar(status,&parse,-1);
       lynx_html_addchar(status,&parse,-1000+list[list_depth-1]);
       if (list[list_depth-1]>=LIST_OL) list[list_depth-1]++;
      }
      break;
     case HTML_OL:
      lynx_html_addchar(status,&parse,-2);
      if (yes) {
       parse.left_margin+=3;
       list[list_depth]=LIST_OL; list_depth++;
      } else {
       parse.left_margin-=3;
       list_depth--; if (list_depth<0) list_depth=0;
      }
      break;
     case HTML_P:
      lynx_html_addchar(status,&parse,-2);
      parse.bold=0; parse.italic=0; parse.heading=0;
      parse.a_name=0; parse.a_href=0; parse.centred=0;
      if (yes) {
       while (t[0]!=0) {
        if (strcmp(tags[HTML_ALIGN],word_lterm(t))==0) {
         t+=strlen(word_lterm(t)); t++;
         if (strcmp(tags[HTML_CENTER],word_lterm(t))==0) parse.centred=1;
         if (strcmp(tags[HTML_CENTRE],word_lterm(t))==0) parse.centred=1;
        }
        t+=strlen(word_lterm(t)); t++;
       }
      }
      lynx_html_addchar(status,&parse,-1);
      break;
     case HTML_PRE:parse.preformatted=yes; break;
     case HTML_TITLE:
      if (yes) {status->build.title[0]=0; title=1;} else {title=0;}
      break;
     case HTML_UL:
      lynx_html_addchar(status,&parse,-2);
      if (yes) {
       parse.left_margin+=3;
       list[list_depth]=LIST_UL; list_depth++;
      } else {
       parse.left_margin-=3;
       list_depth--; if (list_depth<0) list_depth=0;
      }
      break;
     default:break;
    }
    break;
   case '&':
    status->temp[0]=0; a=0;
    do {
     c=lynx_getchar(status,1);
     status->temp[a]=c; a++; status->temp[a]=0;
    } while ((!feof(status->build.fptr)) & (c!=';') & (c!=' '));
    c=0;
    if (strcmp(status->temp," ")==0) c='&';
    if (strcmp(status->temp,"lt;")==0) c='<';
    if (strcmp(status->temp,"gt;")==0) c='>';
    if (strcmp(status->temp,"amp;")==0) c='&';
    if (strcmp(status->temp,"quot;")==0) c='\"';
    if (strcmp(status->temp,"nbsp;")==0) c=160;
    if (strcmp(status->temp,"iexcl;")==0) c=161;
    if (strcmp(status->temp,"cent;")==0) c=162;
    if (strcmp(status->temp,"pound;")==0) c=163;
    if (strcmp(status->temp,"curren;")==0) c=164;
    if (strcmp(status->temp,"yen;")==0) c=165;
    if (strcmp(status->temp,"brvbar;")==0) c=166;
    if (strcmp(status->temp,"sect;")==0) c=167;
    if (strcmp(status->temp,"uml;")==0) c=168;
    if (strcmp(status->temp,"copy;")==0) c=169;
    if (strcmp(status->temp,"ordf;")==0) c=170;
    if (strcmp(status->temp,"laquo;")==0) c=171;
    if (strcmp(status->temp,"not;")==0) c=172;
    if (strcmp(status->temp,"shy;")==0) c=173;
    if (strcmp(status->temp,"reg;")==0) c=174;
    if (strcmp(status->temp,"macr;")==0) c=175;
    if (strcmp(status->temp,"deg;")==0) c=176;
    if (strcmp(status->temp,"plusmn;")==0) c=177;
    if (strcmp(status->temp,"sup2;")==0) c=178;
    if (strcmp(status->temp,"sup3;")==0) c=179;
    if (strcmp(status->temp,"acute;")==0) c=180;
    if (strcmp(status->temp,"micro;")==0) c=181;
    if (strcmp(status->temp,"para;")==0) c=182;
    if (strcmp(status->temp,"middot;")==0) c=183;
    if (strcmp(status->temp,"cedil;")==0) c=184;
    if (strcmp(status->temp,"sup1;")==0) c=185;
    if (strcmp(status->temp,"ordm;")==0) c=186;
    if (strcmp(status->temp,"raquo;")==0) c=187;
    if (strcmp(status->temp,"frac14;")==0) c=188;
    if (strcmp(status->temp,"frac12;")==0) c=189;
    if (strcmp(status->temp,"frac34;")==0) c=190;
    if (strcmp(status->temp,"iquest;")==0) c=191;
    if (strcmp(status->temp,"times;")==0) c=215;
    if (strcmp(status->temp,"divide;")==0) c=247;
    if (status->temp[0]=='#') sscanf(status->temp+1,"%d",&c);
    if (c>256) c=0;
    if ((c>31) | (c==13) | (c==10)) lynx_html_addchar(status,&parse,c);
    if (c==0) {
     lynx_html_addchar(status,&parse,'&');
     lynx_html_addstring(status,&parse,status->temp);
    }
    break;
   default:
    if (title) {
     if (strlen(status->build.title)<(MAX_TITLE_LENGTH-1)) {
      a=strlen(status->build.title);
      if (c>31) {status->build.title[a]=c; a++; status->build.title[a]=0;}
     }
    } else {
     lynx_html_addchar(status,&parse,c);
    }
    break;
  }
 }
 lynx_html_addchar(status,&parse,-1);
}
