/*
 *   Copyright (C) 1993, 1994 Konrad Schroder.
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 1, or (at your option)
 *   any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "tex2asc.h"

extern struct Option option;
extern int input_line;
extern char *begin_latin, *end_latin;
extern char *begin_italics, *end_italics;
extern char *begin_bold, *end_bold;
extern char *begin_underline, *end_underline;
extern char *begin_greek, *end_greek;
extern char *begin_document, *end_document;
extern char *begin_teletype, *end_teletype;
extern char *end_par, *parindent;
extern char bold_space, italic_space, underline_space;
extern char footfile[ML];
extern char peek_ahead_char;
extern int footnote_c;
extern char *everypar;
extern char infile[];

struct hash hash_table[NONE_SUCH+2] = {
    { "_",          D__,           "_"           ,0    },
    { "aa",         D_aa,          "a"           ,0	},
    { "AA",         D_AA,          "A"           ,0	},
    { "ae",         D_ae,          "ae"          ,0	},
    { "AE",         D_AE,          "AE"          ,0	},
    { "backslash",  D_backslash,   "\\"          ,0	},
    { "beginsection", D_beginsection, ""         ,0	},
    { "bf",         D_bf,          ""            ,0	},
    { "bigskip",    D_bigskip,     "\006\n"      ,0	}, /* DISC_NL, nl */
    { "bye",        D_bye,         ""            ,0	},
    { "centerline", D_centerline,  ""            ,0	},
    { "cr",         D_cr,          "\006"        ,0    }, /* DISC_NL */
    { "dag",        D_dag,         "+"           ,0	}, /* dagger */
    { "ddag",       D_ddag,        "#"           ,0	}, /* double dagger */
    { "end",        D_end,         ""            ,0	},
    { "footnote",   D_footnote,    ""            ,0	},
    { "halign",     D_halign,      ""            ,0     },
    { "hsize",      D_hsize,       ""            ,1   },
    { "hskip",      D_hskip,       ""            ,1   },
    { "i",          D_i,           "i"           ,0	},
    { "input",      D_input,       ""            ,0	},
    { "it",         D_it,          ""            ,0	},
    { "j",          D_j,           "j"           ,0	},
    { "kern",       D_kern,        ""            ,1   },
    { "l",          D_l,           "l"           ,0	},
    { "L",          D_L,           "L"           ,0	},
    { "langle",     D_langle,      "<"           ,0	},
    { "ldots",      D_ldots,       "..."         ,0	},
    { "leftline",   D_leftline,    ""            ,0	},
    { "medskip",    D_medskip,     "\006\n"      ,0	}, /* DISC_NL,nl */
    { "noindent",   D_noindent,    "\003"        ,0	}, /* NOINDENT */
    { "o",          D_o,           "o"           ,0	},
    { "O",          D_O,           "O"           ,0	},
    { "obeylines",  D_obeylines,   ""            ,0	},
    { "oe",         D_oe,          "oe"          ,0	},
    { "OE",         D_OE,          "OE"          ,0	},
    { "P",          D_P,           "[P]"         ,0	},
    { "parindent",  D_parindent,   ""            ,1   },
    { "parskip",    D_parskip,     ""            ,1   },
    { "qquad",      D_qquad,       "        "    ,0	},
    { "quad",       D_quad,        "    "        ,0	},
    { "rangle",     D_rangle,      ">"           ,0	},
    { "rightline",  D_rightline,   ""            ,0	},
    { "rm",         D_rm,          ""            ,0	},
    { "S",          D_S,           "sec. "       ,0	},
    { "settabs",    D_settabs,     ""            ,0    },
    { "sl",         D_sl,          ""            ,0	},
    { "ss",         D_ss,          "ss"          ,0	},
    { "TeX",        D_TeX,         "TeX"         ,0	},
    { "tt",         D_tt,          ""            ,0    },
    { "underbar",   D_underbar,    ""            ,0	},
    { "vfill",      D_vfill,       "\014"        ,0	},
    { "vsize",      D_vsize,       ""            ,1    },
    { "vskip",      D_vskip,       ""            ,1    },
    { "alpha",      D_alpha,       "<alpha>"     ,0	},
    { "beta",       D_beta,        "<beta>"      ,0	},
    { "gamma",      D_gamma,       "<gamma>"     ,0	},
    { "delta",      D_delta,       "<delta>"     ,0	},
    { "epsilon",    D_epsilon,     "<epsilon>"   ,0	},
    { "zeta",       D_zeta,        "<zeta>"      ,0	},
    { "eta",        D_eta,         "<eta>"       ,0	},
    { "theta",      D_theta,       "<theta>"     ,0	},
    { "iota",       D_iota,        "<iota>"      ,0	},
    { "kappa",      D_kappa,       "<kappa>"     ,0	},
    { "lambda",     D_lambda,      "<lambda>"    ,0	},
    { "mu",         D_mu,          "<mu>"        ,0	},
    { "nu",         D_nu,          "<nu>"        ,0	},
    { "xi",         D_xi,          "<xi>"        ,0	},
    { "omicron",    D_omicron,     "<omicron>"   ,0	},
    { "pi",         D_pi,          "<pi>"        ,0	},
    { "rho",        D_rho,         "<rho>"       ,0	},
    { "sigma",      D_sigma,       "<sigma>"     ,0	},
    { "tau",        D_tau,         "<tau>"       ,0	},
    { "upsilon",    D_upsilon,     "<upsilon>"   ,0	},
    { "phi",        D_phi,         "<phi>"       ,0	},
    { "chi",        D_chi,         "<chi>"       ,0	},
    { "psi",        D_psi,         "<psi>"       ,0	},
    { "omega",      D_omega,       "<omega>"     ,0	},
    { "Gamma",      D_Gamma,       "<Gamma>"     ,0	},
    { "Delta",      D_Delta,       "<Delta>"     ,0	},
    { "Theta",      D_Theta,       "<Theta>"     ,0	},
    { "Lambda",     D_Lambda,      "<Lambda>"    ,0	},
    { "Xi",         D_Xi,          "<Xi>"        ,0	},
    { "Pi",         D_Pi,          "<Pi>"        ,0	},
    { "Sigma",      D_Sigma,       "<Sigma>"     ,0	},
    { "Upsilon",    D_Upsilon,     "<Upsilon>"   ,0	},
    { "Phi",        D_Phi,         "<Phi>"       ,0	},
    { "Psi",        D_Psi,         "<Psi>"       ,0	},
    { "Omega",      D_Omega,       "<Omega>"     ,0	},

    { "chap",       S_chap,        ""            ,0	},
    { "docversion", S_docversion,  ""            ,1   },
    { "eg",         S_eg,          ""            ,0    },
    { "emdash",     S_emdash,      "---"         ,0    },
    { "endash",     S_endash,      "--"          ,0    },
    { "fnote",      S_fnote,       ""            ,0	},
    { "grbf",       S_grbf,        ""            ,0	},
    { "greek",      S_greek,       ""            ,0	},
    { "head",       S_head,        ""            ,0    },
    { "introsec",   S_introsec,    ""            ,0    },
    { "isec",       S_isec,        ""            ,0    },
    { "lbf",        S_lbf,         ""            ,0    },
    { "linesbyfive", S_linesbyfive, ""           ,0	},
    { "lit",        S_lit,         ""            ,0    },
    { "lrm",        S_lrm,         ""            ,0    },
    { "note",       S_note,        ""            ,0    },
    { "personae",   S_personae,    ""            ,0    },
    { "poetrysize", S_poetrysize,  ""            ,0	},
    { "pounds",     S_pounds,      "L"           ,0	},
    { "sec",        S_sec,         "sec."        ,0	}, /* section symbol */
    { "section",    S_section,     ""            ,0    },
    { "subsec",     S_subsec,      ""            ,0    },
    { "subhead",    S_subhead,     ""            ,0    },
    { "superhead",  S_superhead,   ""            ,0    },
    { "xref",       S_xref,        ""            ,0    },

    { "",           0,             ""            ,0    }
};

void init_chars(void)
{
    switch(option.character_set)
    {
      case 0:                   /* straight ASCII */
        strcpy(hash_table[D_ddag].replace_word,"#");
        strcpy(hash_table[D_dag].replace_word,"%");
        strcpy(hash_table[D_S].replace_word,"sec.");
        strcpy(hash_table[D_P].replace_word,"[P]");

        strcpy(hash_table[D_oe].replace_word,"oe");
        strcpy(hash_table[D_ae].replace_word,"ae");
        strcpy(hash_table[D_OE].replace_word,"OE");
        strcpy(hash_table[D_AE].replace_word,"AE");
        strcpy(hash_table[D_aa].replace_word,"a");
        strcpy(hash_table[D_AA].replace_word,"A");
        strcpy(hash_table[D_o].replace_word,"o");
        strcpy(hash_table[D_O].replace_word,"O"); /* `0' might be better */
        strcpy(hash_table[D_l].replace_word,"l");
        strcpy(hash_table[D_L].replace_word,"L");
        strcpy(hash_table[D_ss].replace_word,"ss");
        break;

      case ibm_pc_chars:
        strcpy(hash_table[D_ddag].replace_word,"\022");
        strcpy(hash_table[D_dag].replace_word,"\030");
        strcpy(hash_table[D_S].replace_word,"\025");
        strcpy(hash_table[D_P].replace_word,"\024");

        strcpy(hash_table[D_oe].replace_word,"oe");
        strcpy(hash_table[D_ae].replace_word,"\221");
        strcpy(hash_table[D_OE].replace_word,"OE");
        strcpy(hash_table[D_AE].replace_word,"\222");
        strcpy(hash_table[D_aa].replace_word,"\206");
        strcpy(hash_table[D_AA].replace_word,"\217");
        strcpy(hash_table[D_o].replace_word,"\355");
        strcpy(hash_table[D_O].replace_word,"0");
        strcpy(hash_table[D_l].replace_word,"l");
        strcpy(hash_table[D_L].replace_word,"L");
        strcpy(hash_table[D_ss].replace_word,"ss");
        strcpy(hash_table[S_pounds].replace_word,"\234");
        break;

      case mac_chars:
        strcpy(hash_table[D_ddag].replace_word,"#");
        strcpy(hash_table[D_dag].replace_word,"\240");
        strcpy(hash_table[D_S].replace_word,"\244");
        strcpy(hash_table[D_P].replace_word,"\246");

        strcpy(hash_table[D_oe].replace_word,"\317");
        strcpy(hash_table[D_ae].replace_word,"\276");
        strcpy(hash_table[D_OE].replace_word,"\316");
        strcpy(hash_table[D_AE].replace_word,"\256");
        strcpy(hash_table[D_aa].replace_word,"\214");
        strcpy(hash_table[D_AA].replace_word,"\201");
        strcpy(hash_table[D_o].replace_word,"\277");
        strcpy(hash_table[D_O].replace_word,"\257");
        strcpy(hash_table[D_l].replace_word,"l");
        strcpy(hash_table[D_L].replace_word,"L");
        strcpy(hash_table[D_ss].replace_word,"\247");
        strcpy(hash_table[S_pounds].replace_word,"\243");
        break;

      case latin1_chars:
        strcpy(hash_table[D_ddag].replace_word,"\244"); /* act. currency   */
        strcpy(hash_table[D_dag].replace_word,"\240"); /* but what hey... */
        strcpy(hash_table[D_S].replace_word,"\247");
        strcpy(hash_table[D_P].replace_word,"\266");

        strcpy(hash_table[D_oe].replace_word,"oe");
        strcpy(hash_table[D_ae].replace_word,"\346");
        strcpy(hash_table[D_OE].replace_word,"OE");
        strcpy(hash_table[D_AE].replace_word,"\306");
        strcpy(hash_table[D_aa].replace_word,"\345");
        strcpy(hash_table[D_AA].replace_word,"\305");
        strcpy(hash_table[D_o].replace_word,"\370");
        strcpy(hash_table[D_O].replace_word,"\330");
        strcpy(hash_table[D_l].replace_word,"l");
        strcpy(hash_table[D_L].replace_word,"L");
        strcpy(hash_table[D_ss].replace_word,"\337");
        strcpy(hash_table[S_pounds].replace_word,"\243");
        break;

      case html_chars:
        strcpy(hash_table[D_ddag].replace_word,"&#164;");
        if(option.apply_codes==html_plus_codes)
        {
            strcpy(hash_table[D_dag].replace_word,"&#165;");
            strcpy(hash_table[D_S].replace_word,"&#167;");
        }
        strcpy(hash_table[D_P].replace_word,"&para;");

        strcpy(hash_table[D_langle].replace_word,"&lt;");
        strcpy(hash_table[D_rangle].replace_word,"&gt;");
        strcpy(hash_table[D_oe].replace_word,"oe");
        strcpy(hash_table[D_ae].replace_word,"ae");
        strcpy(hash_table[D_OE].replace_word,"OE");
        strcpy(hash_table[D_AE].replace_word,"AE");
        strcpy(hash_table[D_aa].replace_word,"&aring;");
        strcpy(hash_table[D_AA].replace_word,"&Aring;");
        strcpy(hash_table[D_o].replace_word,"&oslash;");
        strcpy(hash_table[D_O].replace_word,"&Oslash");
        strcpy(hash_table[D_l].replace_word,"l");
        strcpy(hash_table[D_L].replace_word,"L");
        strcpy(hash_table[D_ss].replace_word,"&szlig;");
        strcpy(hash_table[S_emdash].replace_word," - ");
        strcpy(hash_table[S_endash].replace_word," - ");

        break;
    }
    return;
}

void init_codes(void)
{
    parindent="    ";
    end_par="\n";
    switch(option.apply_codes)
    {
      case strip_codes:
        begin_latin=end_latin=begin_italics=end_italics=begin_bold=end_bold="";
        begin_teletype=end_teletype=begin_underline=end_underline="";
        begin_document=end_document="";
        break;
      case ansi_codes:
        begin_italics="\033[3m";
        begin_bold=begin_teletype="\033[1m";
        begin_latin=begin_underline="\033[4m";
        end_latin=end_bold=end_italics=end_underline=end_teletype="\033[m";
        begin_document=end_document=end_italics;
        break;
      case ascii_codes:
        begin_italics=end_italics="*";
        begin_bold=end_bold="=";
        begin_underline=end_underline="_";
        begin_latin=end_latin=begin_teletype=end_teletype="|";
        bold_space = *begin_bold;
        italic_space = *begin_italics;
        underline_space = *begin_underline;
        begin_document=end_document="";
        break;
      case ibm_ansi_codes:
        begin_italics="\033[1m";
        begin_teletype=begin_bold="\033[7m";
        begin_latin=begin_underline="\033[5m"; /* change back to 4 */
        end_latin=end_teletype=end_bold=end_italics=end_underline="\033[m";
        begin_document=end_document=end_italics;
        break;
      case rtf_codes:
        begin_bold="{\\b ";
        begin_italics="{\\i ";
        begin_underline="{\\ul ";
        begin_teletype="{\\f6 ";
        begin_latin="";
        if(option.character_set==mac_chars) /* Mac */
            begin_document="{\\rtf1\\mac\\deff5{\\fonttbl{\\f0\\froman \
New York;}{\\f5\\froman Times;}{\\f6\\froman Courier;}{\\f8\\fnil AttikaPlus}}\\f5";
        else                    /* IBM; don't know of a Latin1 MSW */
            begin_document="{\\rtf1\\ansi\\deff5{\\fonttbl{\\f0\\froman \
New York;}{\\f5\\froman Times;}{\\f6\\froman Courier;}{\\f8\\fnil Greek}}\\f5";
        parindent="\\tab ";
        end_par="\\par\n";
        end_teletype=end_bold=end_italics=end_underline=end_document="}";
        end_latin="";
        break;
      case html_codes:
      case html_plus_codes:
        begin_bold="<B>";
        begin_italics="<I>";
        begin_latin="<FONT COLOR=\"#500000\">";
        begin_underline="<U>";
        begin_teletype="<TT>";
        begin_document="";
        parindent="<P>";
        end_par="\n";
        end_bold="</B>";
        end_italics="</I>";
        end_latin="</FONT>";
        end_underline="</U>";
        end_teletype="</TT>";
        end_document="";
        break;
    }

    if(option.gutenberg)
        parindent="\012\015";

    switch(option.greek)
    {
      case ascii_greek:
        begin_greek=end_greek="";
        break;
      case greek_keys: case win_greek:
        begin_greek="{\\f8 ";
        end_greek="}";
        break;
    }
    return;
}

int get_hash_no(char *s)
{
    int ret_val=0;
    char *t;

    for(t=s;*t!='\0';t++)
        ret_val += (int)(*t);

    return ret_val;
}

void init_hash(void)
{
    int i;

    if(hash_table[NONE_SUCH].word[0])
        printf("warning: NONE_SUCH has value %s\n",
               hash_table[NONE_SUCH].word);
    for(i=0; hash_table[i].word[0]!='\0'; i++)
        hash_table[i].val = get_hash_no(hash_table[i].word);
    return;
}

int hash_lookup(char *s)
{
    int i, hash_no;

    hash_no = get_hash_no(s);

    for(i=0;hash_table[i].word[0]!='\0';i++)
        if(hash_no == hash_table[i].val && streq(s,hash_table[i].word))
            return i;
    return -1;
}

void swallow_dimen(char c)
{
    if(strchr("=+-0123456789.,\'\"",c)==NULL)
        return;
    if(c=='=')
    {
        while(isspace(peek_ahead_char))
            get_next_char();
        if(strchr("+-0123456789.,\'\"",peek_ahead_char)==NULL)
        {
            fprintf(stderr,"malformed dimension on line %d of input\n",
                    input_line);
            return;
        }
        c=peek_ahead_char;
    }
    if(c=='+' || c=='-')
    {
        while(isspace(peek_ahead_char))
            get_next_char();
        c=peek_ahead_char;
    }

    if(c=='\'')
        while(isdigit(peek_ahead_char) && peek_ahead_char != '8' &&
              peek_ahead_char != '9')
            get_next_char();
    else if(c=='\"')
        while(strchr("0123456789ABCDEF",peek_ahead_char))
            get_next_char();
    else
    {
        while(isdigit(peek_ahead_char))
            get_next_char();
        if(peek_ahead_char=='.')
        {
            get_next_char();
            while(isdigit(peek_ahead_char))
                get_next_char();
        }
    }
    while(isspace(peek_ahead_char))
        get_next_char();
    get_next_char();
    get_next_char();
    return;
}

char *get_prefix(char *file)
{
    char *foo;

    if(getenv("HTML_PREFIX"))
        return getenv("HTML_PREFIX");
    else
    {
        foo = (char *)malloc(sizeof(char)*(strlen(file)+1));
        strcpy(foo,file);
        if(strchr(foo,'.'))
            *(strchr(foo,'.')+1)='\0';
        return foo;
    }
}

char *get_suffix(char *file)
{
    if(getenv("HTML_SUFFIX"))
        return getenv("HTML_SUFFIX");
    else
        return ".html";
}

struct direc_and_last  *read_directive(MODE *mode, int level)
{
    struct direc_and_last *ret_val;
    char accent_char, *cp;
    unsigned char *t;
    char direc[ML], temp[ML];
    FILE *fp;
    MODE tempmode;
    int i, j, ind;
    int c;

    unsigned char *read_frame(MODE *,int,char);

    ret_val = (struct direc_and_last *)malloc(sizeof(*ret_val));
    ret_val->c = '\0';
    k_zero(&(ret_val->direc));

    memset(direc,'\0',ML);

    if(isalnum(c=get_next_char()))
    {
        i=1;
        direc[0]=c;
        while((c=get_next_char())!=EOF && isalnum(c))
            direc[i++]=c;
        direc[i]='\0';
        if(isspace(ret_val->c = c))
            while((c=get_next_char())!=EOF && isspace(c))
                ;
        ret_val->c = c;
    }
    else if(strchr("#$%&{}_",c))
    {
        if(option.apply_codes==rtf_codes && (c=='{' || c=='}'))
            add_char(&(ret_val->direc),'\\');
        if(is_html() && c=='&')
            add_str(&(ret_val->direc),"&amp;");
        else
            add_char(&(ret_val->direc),c);
        return ret_val;
    }
    else if(strchr("\'`\"^~=.",c))
    {
        accent_char = c;
        if((c = get_next_char())=='\\')
            c=get_next_char();  /* for dotless i, j */
        else if(c=='{')
        {
            ret_val->c=c;
            return ret_val;     /* don't even try to interpret /"{} */
        }
	cp = accent(c, accent_char);
	if (cp)
        	add_str(&(ret_val->direc), cp);
	else
		add_char(&(ret_val->direc), c);
        return ret_val;
    }
    else if(strchr(" ,!",c))
    {
        add_char(&(ret_val->direc),' ');
        return ret_val;
    }
    else if(strchr("/-",c))     /* ignore these characters */
    {
        k_zero(&(ret_val->direc));
        return ret_val;
    }
#if 0
    else if(c=='+')
    {
        char line[ML];
        int i=0;

        if(is_html())
            add_str(&ret_val->direc,"<PRE>");
        for(i=0;i<ML;i++)
        {
            line[i]=' ';
        }
        line[ML-1]='\0';
        mode->tab_mode++;
        i=0;
        while(mode->tab_mode)
        {
            t = read_frame(mode,level+1,'&');
            strncpy(line+mode->tabs[i],t,strlen(t)); /* don't copy the NUL */
            free(t);
        }
        for(i=ML-1;i && (line[i]=='\0' || line[i]==' '); i--)
            ;
        if(i>0)
        {
            line[i]='\n';
            line[i+1]='\0';
        }
        add_str(&ret_val->direc,line);
        if(is_html())
            add_str(&ret_val->direc,"</PRE>");
    }
#endif
    else
    {
        printf("tex2asc: line %d: unknown control sequence \\%c\n",
               input_line, c);
        exit(1);
    }

    if((ind=hash_lookup(direc))<0)
    {
#ifdef DEBUG
        printf("tex2asc: unknown control sequence %s.\n",direc);
#endif
        return ret_val;         /* unknown sequence */
    }

    if(hash_table[ind].has_params)
    {
        swallow_dimen(ret_val->c);
        while(isspace(peek_ahead_char))
            get_next_char();
        ret_val->c='\0';
    }

    switch(ind)
    {
      case D_halign:
        t = read_frame(mode,level+1,'}');
        while(isspace(ret_val->c=get_next_char()))
            ;
        /* read the format string */
        for(i=0;t[i] && t[i]!=TEX_CR;i++)
            ;
        /*
         * now for each piece of the rest, format it into a nice
         * table-like thing for output.  Basically we only do
         * anything really interesting for HTML+.
         */
        if(option.apply_codes==html_plus_codes)
            add_str(&(ret_val->direc),"<TABLE>");
        while(t[i])
        {
            if(t[i]==TEX_CR && t[i+1]=='\0')
                break;
            if(is_html())
            {
                if(option.apply_codes==html_plus_codes)
                    add_str(&(ret_val->direc),"<TR><TD>");
                else
                    add_str(&(ret_val->direc),"<BR>");
            }
            else
                add_char(&(ret_val->direc),DISC_NL);
            for(j=0;t[j] && t[j]!=TEX_CR;j++)
            {
                if(t[j]=='\t')
                {
                    if(option.apply_codes==html_plus_codes)
                        add_str(&(ret_val->direc),"<TD>");
                    else
                        add_char(&(ret_val->direc),'\t');
                }
                else if(t[j]==TEX_HASH)
                {
                    for(i++; t[i] && t[i]!='\t' && t[i]!=TEX_CR; i++)
                        add_char(&(ret_val->direc),t[i]);
                }
                else
                    add_char(&(ret_val->direc),t[j]);
            }
            for(;t[i]&&t[i]!=TEX_CR;i++)
                ;
        }
        if(option.apply_codes==html_plus_codes)
            add_str(&(ret_val->direc),"</TABLE>");
        else if(is_html())
            add_str(&(ret_val->direc),"<BR>");
        break;
      case D_cr:
        add_char(&(ret_val->direc),TEX_CR);
        break;
      case D_input:
        ret_val->c='\0';
        while((c=get_next_char())!= EOF && c!='\n')
            ;
        break;
      case S_fnote:
        footnote_c++;
        if(option.apply_codes==rtf_codes)
        {
            sprintf(temp,"%d",footnote_c);
            add_str(&(ret_val->direc),"{\\up6 ");
            add_str(&(ret_val->direc),temp);
            add_str(&(ret_val->direc),"{\\footnote {\\up6 ");
            add_str(&(ret_val->direc),temp);
            add_char(&(ret_val->direc),'}');
        }
	else if(is_html())
        {
            sprintf(temp,"[%d]",footnote_c);
            add_str(&(ret_val->direc),temp);
        }
        else
        {
            sprintf(temp,"<%d>",footnote_c);
            add_str(&(ret_val->direc),temp);
        }
        t=read_frame(mode,level+1,'}');
        if(option.apply_codes==rtf_codes)
        {
            add_str(&(ret_val->direc),t);
            add_char(&(ret_val->direc),'}');
        }
        else if(is_html())
        {
            add_str(&(ret_val->direc),"[");
            add_str(&(ret_val->direc),t);
            add_str(&(ret_val->direc),"]");
        }
        else if(option.footnote==leave_notes)
        {
            add_str(&(ret_val->direc),"<[");
            add_str(&(ret_val->direc),t);
            add_str(&(ret_val->direc),"]>");
        }
        else if(option.footnote)
        {
            add_str(&(ret_val->direc),t);
            add_char(&(ret_val->direc),'\n');
            fp = fopen(footfile,"a");
            output(ret_val->direc.str,fp);
            fclose(fp);
            k_zero(&(ret_val->direc));
            add_str(&(ret_val->direc),temp);
        }
        free(t);
        break;
      case D_footnote:
        footnote_c++;
        t=read_frame(mode, level+1,'}');
        if(option.apply_codes==rtf_codes)
        {
            add_str(&(ret_val->direc),"{\\up6 ");
            add_str(&(ret_val->direc),t);
            add_str(&(ret_val->direc),"{\\footnote {\\up6 ");
            add_str(&(ret_val->direc),t);
            add_char(&(ret_val->direc),'}');
        }
        else if(is_html())
        {
            sprintf(temp,"[%s]",t);
            add_str(&(ret_val->direc),temp);
        }
        else
        {
            sprintf(temp,"<%s>",t);
            add_str(&(ret_val->direc),temp);
        }
        while(get_next_char()!='{')
            ;
        ret_val->c='\0';
        t=read_frame(mode,level+1,'}');
        if(option.apply_codes==rtf_codes)
        {
            add_str(&(ret_val->direc),t);
            add_char(&(ret_val->direc),'}');
        }
        else if(is_html())
        {
            add_str(&(ret_val->direc),"[");
            add_str(&(ret_val->direc),t);
            free(t);
            add_str(&(ret_val->direc),"]");
        }
        else if(option.footnote==leave_notes)
        {
            add_str(&(ret_val->direc),"<[");
            add_str(&(ret_val->direc),t);
            free(t);
            add_str(&(ret_val->direc),"]>");
        }
        else if(option.footnote)
        {
            add_str(&(ret_val->direc),t);
            add_char(&(ret_val->direc),'\n');
            fp = fopen(footfile,"a");
            output(ret_val->direc.str,fp);
            fclose(fp);
            k_zero(&(ret_val->direc));
            add_str(&(ret_val->direc),temp);
        }
        break;
      case D_centerline:
      case D_leftline:
      case D_rightline:
        add_char(&(ret_val->direc),DISC_NL); /* Discretionary newline */
        add_char(&(ret_val->direc),NOINDENT);
        t=read_frame(mode,level+1,'}');
        while(isspace(ret_val->c=get_next_char()))
            ;
        if(streq(direc,"leftline"))
        {
            if(option.apply_codes==rtf_codes)
                add_str(&(ret_val->direc),"{\\ql\\phpg\\posxl ");
            else if (is_html())
                add_str(&(ret_val->direc),"<P>");
            add_str(&(ret_val->direc),t);
        }
        else if(streq(direc,"rightline"))
        {
            if(option.apply_codes==rtf_codes)
                add_str(&(ret_val->direc),"{\\qr\\phpg\\posxr ");
            else if(is_html())
                add_str(&(ret_val->direc),"<P align=right>");
            else
                for(i=0;i<mode->margin-(strlen(t)+5);i++)
                    add_char(&(ret_val->direc),TIE);
            add_str(&(ret_val->direc),t);
        }
        else if(streq(direc,"centerline"))
        {
            if(option.apply_codes==rtf_codes)
                add_str(&(ret_val->direc),"{\\qc\\phpg\\posxc ");
            else if(is_html())
                add_str(&(ret_val->direc),"<center><P>");
            else
                for(i=0;i<(mode->margin-(strlen(t)+3))/2;i++)
                    add_char(&(ret_val->direc),TIE);
            add_str(&(ret_val->direc),t);
        }
        add_char(&(ret_val->direc),SP_PAR);
        if(option.apply_codes==rtf_codes)
        {
            add_char(&(ret_val->direc),NOINDENT);
            add_char(&(ret_val->direc),'}');
            add_char(&(ret_val->direc),NOPRINT);
        }
        else if(is_html() && streq(direc,"centerline"))
            add_str(&(ret_val->direc),"</center>");
        break;
      case D_obeylines:
        mode->obeylines++;
        add_char(&(ret_val->direc),SP_PAR); /* kludge */
        break;
      case S_linesbyfive:
        mode->countlines++;
        mode->linecount=1;
        if(is_html())
            add_str(&(ret_val->direc),"<OL><LI>");
        break;
      case D_rm:
        if(mode->font & UNDERLINE)
            add_str(&(ret_val->direc),end_underline);
        if(mode->font & TELETYPE)
            add_str(&(ret_val->direc),end_teletype);
        if(mode->font & LATIN)
            add_str(&(ret_val->direc),end_latin);
        if(mode->font & GREEK)
            add_str(&(ret_val->direc),end_greek);
        if(mode->font & ITALICS)
            add_str(&(ret_val->direc),end_italics);
        if(mode->font & BOLD)
            add_str(&(ret_val->direc),end_bold);
        mode->font=ROMAN;
        break;
      case S_lrm:
        if(mode->font & UNDERLINE)
            add_str(&(ret_val->direc),end_underline);
        if(mode->font & TELETYPE)
            add_str(&(ret_val->direc),end_teletype);
        if(mode->font & ITALICS)
            add_str(&(ret_val->direc),end_italics);
        if(mode->font & GREEK)
            add_str(&(ret_val->direc),end_greek);
        if(mode->font & BOLD)
            add_str(&(ret_val->direc),end_bold);
        if((mode->font & LATIN)==0)
            add_str(&(ret_val->direc),begin_latin);
        mode->font=LATIN;
        break;
      case D_it: case D_sl:
        if(mode->font & UNDERLINE)
            add_str(&(ret_val->direc),end_underline);
        if(mode->font & TELETYPE)
            add_str(&(ret_val->direc),end_teletype);
        if(mode->font & LATIN)
            add_str(&(ret_val->direc),end_latin);
        if(mode->font & GREEK)
            add_str(&(ret_val->direc),end_greek);
        if(mode->font & BOLD)
            add_str(&(ret_val->direc),end_bold);
        if((mode->font & ITALICS) == 0)
            add_str(&(ret_val->direc),begin_italics);
        mode->font = ITALICS;
        break;
      case S_lit:
        if(mode->font & UNDERLINE)
            add_str(&(ret_val->direc),end_underline);
        if(mode->font & TELETYPE)
            add_str(&(ret_val->direc),end_teletype);
        if(mode->font & GREEK)
            add_str(&(ret_val->direc),end_greek);
        if(mode->font & BOLD)
            add_str(&(ret_val->direc),end_bold);
        if((mode->font & ITALICS) == 0)
            add_str(&(ret_val->direc),begin_italics);
        if((mode->font & LATIN)==0)
            add_str(&(ret_val->direc),begin_latin);
        mode->font = LATIN|ITALICS;
        break;
      case D_tt:
        if(mode->font & UNDERLINE)
            add_str(&(ret_val->direc),end_underline);
        if(mode->font & LATIN)
            add_str(&(ret_val->direc),end_latin);
        if(mode->font & ITALICS)
            add_str(&(ret_val->direc),end_italics);
        if(mode->font & GREEK)
            add_str(&(ret_val->direc),end_greek);
        if(mode->font & BOLD)
            add_str(&(ret_val->direc),end_bold);
        if((mode->font & TELETYPE) == 0)
            add_str(&(ret_val->direc),begin_teletype);
        mode->font = TELETYPE;
        break;
      case D_bf:
        if(mode->font & TELETYPE)
            add_str(&(ret_val->direc),end_teletype);
        if(mode->font & UNDERLINE)
            add_str(&(ret_val->direc),end_underline);
        if(mode->font & LATIN)
            add_str(&(ret_val->direc),end_latin);
        if(mode->font & ITALICS)
            add_str(&(ret_val->direc),end_italics);
        if(mode->font & GREEK)
            add_str(&(ret_val->direc),end_greek);
        if((mode->font & BOLD) == 0)
            add_str(&(ret_val->direc),begin_bold);
        mode->font = BOLD;
        break;
      case S_lbf:
        if(mode->font & UNDERLINE)
            add_str(&(ret_val->direc),end_underline);
        if(mode->font & TELETYPE)
            add_str(&(ret_val->direc),end_teletype);
        if(mode->font & ITALICS)
            add_str(&(ret_val->direc),end_italics);
        if(mode->font & GREEK)
            add_str(&(ret_val->direc),end_greek);
        if((mode->font & BOLD) == 0)
            add_str(&(ret_val->direc),begin_bold);
        if((mode->font & LATIN)==0)
            add_str(&(ret_val->direc),begin_latin);
        mode->font = BOLD|LATIN;
        break;
      case D_beginsection:
        tempmode = *mode;
        tempmode.font |= BOLD;

        /* this isn't actually right. */
        t=read_frame(&tempmode,level+1,'\n'); 

        if(option.apply_codes==rtf_codes)
            add_str(&(ret_val->direc),"\\par{\\b");
        else
        {
            add_char(&(ret_val->direc),DISC_NL);
            add_char(&(ret_val->direc),'\n');
            add_char(&(ret_val->direc),NOINDENT);
            if((mode->font  & BOLD)==0)
                add_str(&(ret_val->direc),begin_bold);
        }
        if(ret_val->c!='\0')
            add_char(&(ret_val->direc),ret_val->c);
        add_str(&(ret_val->direc),t);
        if(option.apply_codes==rtf_codes)
            add_str(&(ret_val->direc),"}\\par ");
        else
        {
            if((mode->font  & BOLD)==0)
                add_str(&(ret_val->direc),end_bold);
            add_char(&(ret_val->direc),'\n');
            add_char(&(ret_val->direc),NOINDENT);
        }
        free(t);
        while(isspace(peek_ahead_char))
            get_next_char();
        ret_val->c='\0';
        break;
      case D_underbar:
        tempmode = *mode;
        add_str(&(ret_val->direc),begin_underline);
        tempmode.font |= UNDERLINE;
        t=read_frame(&tempmode,level+1,'}');
        add_str(&(ret_val->direc),t);
        free(t);
        add_str(&(ret_val->direc),end_underline);
        break;
      case S_greek:
        if(mode->font & ITALICS)
            add_str(&(ret_val->direc),end_italics);
        if(mode->font & BOLD)
            add_str(&(ret_val->direc),end_bold);
        if(!(mode->font & GREEK))
            add_str(&(ret_val->direc),begin_greek);
        mode->font=GREEK;
        break;
      case S_grbf:
        if(mode->font & ITALICS)
            add_str(&(ret_val->direc),end_italics);
        if((mode->font & BOLD) == 0)
            add_str(&(ret_val->direc),begin_bold);
        if(!(mode->font & GREEK))
            add_str(&(ret_val->direc),begin_greek);
        mode->font = GREEK|BOLD;
        break;
      case S_chap:
        add_str(&(ret_val->direc),chapter(mode));
        break;
      case S_sec:
        add_str(&(ret_val->direc),section(mode));
        break;
      case S_isec:
        add_str(&(ret_val->direc),independent_section(mode));
        break;
      case S_poetrysize:
        mode->margin = 60;
        break;
      case S_introsec:
      case S_section:
        {
            char *ss;

            ss = read_frame(mode,level+1,'.');
            if(is_html())
            {
                add_str(&(ret_val->direc),"<H4 ID=\"");
                add_char(&(ret_val->direc),ret_val->c);
                add_str(&(ret_val->direc),ss);
                add_str(&(ret_val->direc),"\">");
            }
            add_char(&(ret_val->direc),ret_val->c);
            ret_val->c='\0';
            add_str(&(ret_val->direc),ss);
            if(is_html())
                add_str(&(ret_val->direc),".</H4>");
            free(ss);
        }
        break;
      case S_subsec:
        {
            char *ss;

            ss=read_frame(mode,level+1,'.');
            if(is_html())
            {
                add_str(&(ret_val->direc),"<A NAME=");
                add_char(&(ret_val->direc),c);
                add_str(&(ret_val->direc),ss);
                add_str(&(ret_val->direc),"><I><B>"); /* <H5> */
            }
            add_char(&(ret_val->direc),ret_val->c);
            add_str(&(ret_val->direc),ss);
            ret_val->c='\0';
            if(is_html())
                add_str(&(ret_val->direc),".</A></B></I>"); /* </H5> */
            free(ss);
            break;
        }
      case S_head:
        if(is_html())
            add_str(&(ret_val->direc),"<H2>");
        ret_val->c='\0';
        add_str(&(ret_val->direc),read_frame(mode,level+1,'}'));
        if(is_html())
            add_str(&(ret_val->direc),".</H2>");
        break;
      case S_subhead:
        if(is_html())
            add_str(&(ret_val->direc),"<H3>");
        ret_val->c='\0';
        add_str(&(ret_val->direc),read_frame(mode,level+1,'}'));
        if(is_html())
            add_str(&(ret_val->direc),".</H3>");
        break;
      case S_superhead:
        if(is_html())
            add_str(&(ret_val->direc),"<H1>");
        ret_val->c='\0';
        add_str(&(ret_val->direc),read_frame(mode,level+1,'}'));
        if(is_html())
            add_str(&(ret_val->direc),".</H1>");
        break;
      case S_xref:
        {
            char *ss, *t;
            char ss_html[ML];

            ss = read_frame(mode,level+1,'}');
            if(is_html())
            {
                strcpy(ss_html,ss);
                if((t=strchr(ss_html,'.'))!=NULL)
                {
                    *t++ = '\0';
                    t++;
                }
                add_str(&(ret_val->direc),"<A HREF=\"");
                add_str(&(ret_val->direc),get_prefix(infile));
                add_str(&(ret_val->direc),ss_html);
                add_str(&(ret_val->direc),get_suffix(infile));
                if(t)
                {
                    add_char(&(ret_val->direc),'#');
                    add_str(&(ret_val->direc),t);
                }
                add_str(&(ret_val->direc),"\">");
            }
            add_str(&(ret_val->direc),ss);
            if(is_html())
                add_str(&(ret_val->direc),"</A>");
            free(ss);
            ret_val->c='\0';
            break;
        }
      case S_note:
        {
            char *ss;

            if(ret_val->c!='{')
                fprintf(stderr,"malformed note? c==%c\n",ret_val->c);
            ss=read_frame(mode,level+1,'}');
            if(is_html())
            {
                /* add_str(&(ret_val->direc),"<NOTE ROLE=\"NOTE "); */
                add_str(&(ret_val->direc),"<B>NOTE"); /* <H6> */
            }
            if(atoi(ss) || ss[0]!='0')
            {
                add_char(&(ret_val->direc),' ');
                add_str(&(ret_val->direc),ss);
            }
            add_str(&(ret_val->direc),":  ");
            if(is_html())
            {
                /* add_str(&(ret_val->direc),"\">"); */
                add_str(&(ret_val->direc),"</B>"); /* </H6> */
            }
            while((c=get_next_char())!='{' && c>0)
                fprintf(stderr,"ignoring character %c\n",c);
            add_str(&(ret_val->direc),read_frame(mode,level+1,'}'));
            /*
               if(is_html())
               add_str(&(ret_val->direc),".</NOTE>");
               */
            while(ret_val->c > 0 && !isspace(ret_val->c))
                ret_val->c=get_next_char();
            free(ss);
            break;
        }
      case S_personae:
        if(is_html())
        {
            everypar="\003<LI>";
            add_str(&(ret_val->direc),"<UL><LI>");
        }
        add_str(&(ret_val->direc),read_frame(mode,level+1,'}'));
        if(is_html())
        {
            add_str(&(ret_val->direc),"</UL>");
            everypar=NULL;
        }
        ret_val->c='\0';
        break;
      case S_eg:
        if(is_html())
        {
            everypar="\003<LI>";
            add_str(&(ret_val->direc),"<UL><LI>");
        }
        add_str(&(ret_val->direc),read_frame(mode,level+1,'}'));
        if(is_html())
        {
            add_str(&(ret_val->direc),"</UL>");
            everypar=NULL;
        }
        ret_val->c='\0';
        break;
      default:
        add_str(&(ret_val->direc),hash_table[ind].replace_word);
        break;
    }
    return ret_val;
}
