Subversion Repositories pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

  1. /* tex2doc.c */
  2. /*****************************************************************************/
  3. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
  4. /*                                                                           */
  5. /* AS-Portierung                                                             */
  6. /*                                                                           */
  7. /* Konverter TeX-->ASCII-DOC                                                 */
  8. /*                                                                           */
  9. /*****************************************************************************/
  10.  
  11. #include "stdinc.h"
  12. #include "asmitree.h"
  13. #include "chardefs.h"
  14. #include <ctype.h>
  15. #include <string.h>
  16. #include "strutil.h"
  17.  
  18. #include "findhyphen.h"
  19. #ifndef __MSDOS__
  20. #include "ushyph.h"
  21. #include "grhyph.h"
  22. #endif
  23.  
  24. #include "chardefs.h"
  25. #include "texutil.h"
  26. #include "texrefs.h"
  27. #include "textoc.h"
  28. #include "texfonts.h"
  29. #include "nls.h"
  30.  
  31. /*--------------------------------------------------------------------------*/
  32.  
  33. #define TOKLEN 250
  34.  
  35. static char *TableName,
  36.             *BiblioName,
  37.             *ContentsName,
  38. #define ErrorEntryCnt 3
  39.             *ErrorEntryNames[ErrorEntryCnt];
  40.  
  41. typedef enum
  42. {
  43.   EnvNone, EnvDocument, EnvItemize, EnvEnumerate, EnvDescription, EnvTable,
  44.   EnvTabular, EnvRaggedLeft, EnvRaggedRight, EnvCenter, EnvVerbatim,
  45.   EnvQuote, EnvTabbing, EnvBiblio, EnvMarginPar, EnvCaption, EnvHeading, EnvCount
  46. } EnvType;
  47.  
  48. typedef enum
  49. {
  50.   AlignNone, AlignCenter, AlignLeft, AlignRight
  51. } TAlignment;
  52.  
  53. typedef struct sEnvSave
  54. {
  55.   struct sEnvSave *Next;
  56.   EnvType SaveEnv;
  57.   int ListDepth, ActLeftMargin, LeftMargin, RightMargin;
  58.   int EnumCounter, FontNest;
  59.   TAlignment Alignment;
  60. } TEnvSave, *PEnvSave;
  61.  
  62. typedef enum
  63. {
  64.   ColLeft, ColRight, ColCenter, ColBar
  65. } TColumn;
  66.  
  67. #define MAXCOLS 30
  68. #define MAXROWS 500
  69. typedef char *TableLine[MAXCOLS];
  70. typedef struct
  71. {
  72.   int ColumnCount, TColumnCount;
  73.   TColumn ColTypes[MAXCOLS];
  74.   int ColLens[MAXCOLS];
  75.   int LineCnt;
  76.   TableLine Lines[MAXROWS];
  77.   Boolean LineFlags[MAXROWS];
  78.   Boolean MultiFlags[MAXROWS];
  79. } TTable;
  80.  
  81. static char *EnvNames[EnvCount] =
  82. {
  83.   "___NONE___", "document", "itemize", "enumerate", "description", "table", "tabular",
  84.   "raggedleft", "raggedright", "center", "verbatim", "quote", "tabbing",
  85.   "thebibliography", "___MARGINPAR___", "___CAPTION___", "___HEADING___"
  86. };
  87.  
  88. static int IncludeNest;
  89. static FILE *infiles[50], *outfile;
  90. static char TocName[200];
  91. static char SrcDir[TOKLEN + 1], asname[TOKLEN];
  92.  
  93. #define CHAPMAX 6
  94. static int Chapters[CHAPMAX];
  95. static int TableNum, ErrState, FracState, BibIndent, BibCounter;
  96. #define TABMAX 100
  97. static int TabStops[TABMAX], TabStopCnt, CurrTabStop;
  98. static Boolean InAppendix, InMathMode;
  99. static TTable *pThisTable;
  100. static int CurrRow, CurrCol;
  101. static Boolean GermanMode;
  102.  
  103. static EnvType CurrEnv;
  104. static int CurrPass;
  105. static int CurrListDepth;
  106. static int EnumCounter;
  107. static int ActLeftMargin, LeftMargin, RightMargin;
  108. static TAlignment Alignment;
  109. static PEnvSave EnvStack;
  110.  
  111. static PInstTable TeXTable;
  112.  
  113. static tCodepage Codepage;
  114. static const tNLSCharacterTab *pCharacterTab;
  115. static Boolean enable_hyphenation;
  116.  
  117. /*--------------------------------------------------------------------------*/
  118.  
  119. void ChkStack(void)
  120. {
  121. }
  122.  
  123. static void SetSrcDir(const char *pSrcFile)
  124. {
  125.   const char *pSep;
  126.  
  127.   pSep = strchr(pSrcFile, PATHSEP);
  128.   if (!pSep)
  129.     pSep = strchr(pSrcFile, '/');
  130.  
  131.   if (!pSep)
  132.     *SrcDir = '\0';
  133.   else
  134.   {
  135.     size_t l = pSep + 1 - pSrcFile;
  136.  
  137.     if (l >= sizeof(SrcDir))
  138.     {
  139.       fprintf(stderr, "%s: path too long\n", pSrcFile);
  140.       exit(3);
  141.     }
  142.     memcpy(SrcDir, pSrcFile, l);
  143.     SrcDir[l] = '\0';
  144.   }
  145. }
  146.  
  147. static void error(char *Msg)
  148. {
  149.   int z;
  150.  
  151.   fprintf(stderr, "%s:%d.%d: %s\n", pInFileName, CurrLine, CurrColumn, Msg);
  152.   for (z = 0; z < IncludeNest; fclose(infiles[z++]));
  153.   fclose(outfile);
  154.   exit(2);
  155. }
  156.  
  157. static void SetLang(Boolean IsGerman)
  158. {
  159.   char **pp;
  160.  
  161.   if (GermanMode == IsGerman)
  162.     return;
  163.  
  164.   DestroyTree();
  165.   GermanMode = IsGerman;
  166.   if (GermanMode)
  167.   {
  168.     TableName = "Tabelle";
  169.     BiblioName = "Literaturverzeichnis";
  170.     ContentsName = "Inhalt";
  171.     ErrorEntryNames[0] = "Typ";
  172.     ErrorEntryNames[1] = "Ursache";
  173.     ErrorEntryNames[2] = "Argument";
  174. #ifndef __MSDOS__
  175.     BuildTree(GRHyphens);
  176. #endif
  177.   }
  178.   else
  179.   {
  180.     TableName = "Table";
  181.     BiblioName = "Bibliography";
  182.     ContentsName = "Contents";
  183.     ErrorEntryNames[0] = "Type";
  184.     ErrorEntryNames[1] = "Reason";
  185.     ErrorEntryNames[2] = "Argument";
  186. #ifndef __MSDOS__
  187.     BuildTree(USHyphens);
  188.     for (pp = USExceptions; *pp != NULL; pp++)
  189.       AddException(*pp);
  190. #endif
  191.   }
  192. }
  193.  
  194. /*------------------------------------------------------------------------------*/
  195.  
  196. static void GetNext(char *Src, char *Dest)
  197. {
  198.   char *c = strchr(Src, ' ');
  199.  
  200.   if (!c)
  201.   {
  202.     strcpy(Dest, Src);
  203.     *Src = '\0';
  204.   }
  205.   else
  206.   {
  207.     *c = '\0';
  208.     strcpy(Dest, Src);
  209.     for (c++; *c == ' '; c++);
  210.     strmov(Src, c);
  211.   }
  212. }
  213.  
  214. static void ReadAuxFile(char *Name)
  215. {
  216.   FILE *file = fopen(Name, "r");
  217.   char Line[300], Cmd[300], Nam[300], Val[300];
  218.  
  219.   if (!file)
  220.     return;
  221.  
  222.   while (!feof(file))
  223.   {
  224.     if (!fgets(Line, 299, file))
  225.       break;
  226.     if ((*Line) && (Line[strlen(Line) - 1] == '\n'))
  227.       Line[strlen(Line) - 1] = '\0';
  228.     GetNext(Line, Cmd);
  229.     if (!strcmp(Cmd, "Label"))
  230.     {
  231.       GetNext(Line, Nam);
  232.       GetNext(Line, Val);
  233.       AddLabel(Nam, Val);
  234.     }
  235.     else if (!strcmp(Cmd, "Citation"))
  236.     {
  237.       GetNext(Line, Nam);
  238.       GetNext(Line, Val);
  239.       AddCite(Nam, Val);
  240.     }
  241.   }
  242.  
  243.   fclose(file);
  244. }
  245.  
  246. /*--------------------------------------------------------------------------*/
  247.  
  248. static Boolean issep(char inp)
  249. {
  250.   return ((inp == ' ') || (inp == '\t') || (inp == '\n'));
  251. }
  252.  
  253. static Boolean isalphanum(char inp)
  254. {
  255.   return ((inp >= 'A') && (inp <= 'Z'))
  256.       || ((inp >= 'a') && (inp <= 'z'))
  257.       || ((inp >= '0') && (inp <= '9'))
  258.       || (inp == '.');
  259. }
  260.  
  261. static char LastChar = '\0';
  262. static char SaveSep = '\0', SepString[TOKLEN] = "";
  263. static Boolean DidEOF;
  264. static char BufferLine[TOKLEN] = "", *BufferPtr = BufferLine;
  265. typedef struct
  266. {
  267.   char Token[TOKLEN], Sep[TOKLEN];
  268. } PushedToken;
  269. static int PushedTokenCnt = 0;
  270. static PushedToken PushedTokens[16];
  271.  
  272. static int GetChar(void)
  273. {
  274.   Boolean Comment;
  275.   static Boolean DidPar = False;
  276.   char *Result;
  277.  
  278.   if (*BufferPtr == '\0')
  279.   {
  280.     do
  281.     {
  282.       if (IncludeNest <= 0)
  283.         return EOF;
  284.       do
  285.       {
  286.         Result = fgets(BufferLine, TOKLEN, infiles[IncludeNest - 1]);
  287.         if (Result)
  288.           break;
  289.         fclose(infiles[--IncludeNest]);
  290.         if (IncludeNest <= 0)
  291.           return EOF;
  292.       }
  293.       while (True);
  294.       CurrLine++;
  295.       BufferPtr = BufferLine;
  296.       Comment = (strlen(BufferLine) >= 2) && (!strncmp(BufferLine, "%%", 2));
  297.       if ((*BufferLine == '\0') || (*BufferLine == '\n'))
  298.       {
  299.         if ((CurrEnv == EnvDocument) && (!DidPar))
  300.         {
  301.           strcpy(BufferLine, "\\par\n");
  302.           DidPar = True;
  303.           Comment = False;
  304.         }
  305.       }
  306.       else if (!Comment)
  307.         DidPar = False;
  308.     }
  309.     while (Comment);
  310.   }
  311.   return *(BufferPtr++);
  312. }
  313.  
  314. static Boolean ReadToken(char *Dest)
  315. {
  316.   int ch, z;
  317.   Boolean Good;
  318.   char *run;
  319.  
  320.   if (PushedTokenCnt > 0)
  321.   {
  322.     strcpy(Dest, PushedTokens[0].Token);
  323.     strcpy(SepString, PushedTokens[0].Sep);
  324.     for (z = 0; z < PushedTokenCnt - 1; z++)
  325.       PushedTokens[z] = PushedTokens[z + 1];
  326.     PushedTokenCnt--;
  327.     return True;
  328.   }
  329.  
  330.   if (DidEOF)
  331.     return FALSE;
  332.  
  333.   CurrColumn = BufferPtr - BufferLine + 1;
  334.  
  335.   /* falls kein Zeichen gespeichert, fuehrende Blanks ueberspringen */
  336.  
  337.   *Dest = '\0';
  338.   *SepString = SaveSep;
  339.   run = SepString + ((SaveSep == '\0') ? 0 : 1);
  340.   if (LastChar == '\0')
  341.   {
  342.     do
  343.     {
  344.       ch = GetChar();
  345.       if (ch == '\r')
  346.         ch = GetChar();
  347.       if (issep(ch))
  348.         *(run++) = ' ';
  349.     }
  350.     while ((issep(ch)) && (ch != EOF));
  351.     *run = '\0';
  352.     if (ch == EOF)
  353.     {
  354.       DidEOF = TRUE;
  355.       return FALSE;
  356.     }
  357.   }
  358.   else
  359.   {
  360.     ch = LastChar;
  361.     LastChar = '\0';
  362.   }
  363.  
  364.   /* jetzt Zeichen kopieren, bis Leerzeichen */
  365.  
  366.   run = Dest;
  367.   SaveSep = '\0';
  368.   if (isalphanum(*(run++) = ch))
  369.   {
  370.     do
  371.     {
  372.       ch = GetChar();
  373.       Good = (!issep(ch)) && (isalphanum(ch)) && (ch != EOF);
  374.       if (Good)
  375.         *(run++) = ch;
  376.     }
  377.     while (Good);
  378.  
  379.     /* Dateiende ? */
  380.  
  381.     if (ch == EOF)
  382.       DidEOF = TRUE;
  383.  
  384.     /* Zeichen speichern ? */
  385.  
  386.     else if ((!issep(ch)) && (!isalphanum(ch)))
  387.       LastChar = ch;
  388.  
  389.     /* Separator speichern ? */
  390.  
  391.     else if (issep(ch))
  392.       SaveSep = ' ';
  393.   }
  394.  
  395.   /* Ende */
  396.  
  397.   *run = '\0';
  398.   return True;
  399. }
  400.  
  401. static void BackToken(char *Token)
  402. {
  403.   if (PushedTokenCnt >= 16)
  404.     return;
  405.   strcpy(PushedTokens[PushedTokenCnt].Token, Token);
  406.   strcpy(PushedTokens[PushedTokenCnt].Sep, SepString);
  407.   PushedTokenCnt++;
  408. }
  409.  
  410. /*--------------------------------------------------------------------------*/
  411.  
  412. static void assert_token(char *ref)
  413. {
  414.   char token[TOKLEN];
  415.  
  416.   ReadToken(token);
  417.   if (strcmp(ref, token))
  418.   {
  419.     as_snprintf(token, sizeof(token), "\"%s\" expected", ref);
  420.     error(token);
  421.   }
  422. }
  423.  
  424. static void collect_token(char *dest, char *term)
  425. {
  426.   char Comp[TOKLEN];
  427.   Boolean first = TRUE, done;
  428.  
  429.   *dest = '\0';
  430.   do
  431.   {
  432.     ReadToken(Comp);
  433.     done = !strcmp(Comp, term);
  434.     if (!done)
  435.     {
  436.       if (!first)
  437.         strcat(dest, SepString);
  438.       strcat(dest, Comp);
  439.     }
  440.     first = False;
  441.   }
  442.   while (!done);
  443. }
  444.  
  445. /*--------------------------------------------------------------------------*/
  446.  
  447. static const char CHR_ae[3] = HYPHEN_CHR_ae,
  448.                   CHR_oe[3] = HYPHEN_CHR_oe,
  449.                   CHR_ue[3] = HYPHEN_CHR_ue,
  450.                   CHR_AE[3] = HYPHEN_CHR_AE,
  451.                   CHR_OE[3] = HYPHEN_CHR_OE,
  452.                   CHR_UE[3] = HYPHEN_CHR_UE,
  453.                   CHR_sz[3] = HYPHEN_CHR_sz;
  454.  
  455. static int visible_clen(char ch)
  456. {
  457.   if (Codepage != eCodepageASCII)
  458.     return 1;
  459.   else if (ch == *CHR_ae)
  460.     return CharTab_GetLength(pCharacterTab, eCH_ae);
  461.   else if (ch == *CHR_oe)
  462.     return CharTab_GetLength(pCharacterTab, eCH_oe);
  463.   else if (ch == *CHR_ue)
  464.     return CharTab_GetLength(pCharacterTab, eCH_ue);
  465.   else if (ch == *CHR_AE)
  466.     return CharTab_GetLength(pCharacterTab, eCH_Ae);
  467.   else if (ch == *CHR_OE)
  468.     return CharTab_GetLength(pCharacterTab, eCH_Oe);
  469.   else if (ch == *CHR_UE)
  470.     return CharTab_GetLength(pCharacterTab, eCH_Ue);
  471.   else if (ch == *CHR_sz)
  472.     return CharTab_GetLength(pCharacterTab, eCH_sz);
  473.   else
  474.     return 1;
  475. }
  476.  
  477. static int visible_strlen(const char *pStr)
  478. {
  479.   int res = 0;
  480.  
  481.   while (*pStr)
  482.     res += visible_clen(*pStr++);
  483.   return res;
  484. }
  485.  
  486. static int visible_strnlen(const char *pStr, int MaxLen)
  487. {
  488.   int res = 0;
  489.  
  490.   while (*pStr && MaxLen)
  491.   {
  492.     res += visible_clen(*pStr++);
  493.     MaxLen--;
  494.   }
  495.   return res;
  496. }
  497.  
  498. static void outc(char ch)
  499. {
  500.   char Buf[3];
  501.  
  502.   if (ch == *CHR_ae)
  503.     fputs(CharTab_GetNULTermString(pCharacterTab, eCH_ae, Buf), outfile);
  504.   else if (ch == *CHR_oe)
  505.     fputs(CharTab_GetNULTermString(pCharacterTab, eCH_oe, Buf), outfile);
  506.   else if (ch == *CHR_ue)
  507.     fputs(CharTab_GetNULTermString(pCharacterTab, eCH_ue, Buf), outfile);
  508.   else if (ch == *CHR_AE)
  509.     fputs(CharTab_GetNULTermString(pCharacterTab, eCH_Ae, Buf), outfile);
  510.   else if (ch == *CHR_OE)
  511.     fputs(CharTab_GetNULTermString(pCharacterTab, eCH_Oe, Buf), outfile);
  512.   else if (ch == *CHR_UE)
  513.     fputs(CharTab_GetNULTermString(pCharacterTab, eCH_Ue, Buf), outfile);
  514.   else if (ch == *CHR_sz)
  515.     fputs(CharTab_GetNULTermString(pCharacterTab, eCH_sz, Buf), outfile);
  516.   else
  517.     fputc(ch, outfile);
  518. }
  519.  
  520. static void outs(const char *pStr)
  521. {
  522.   while (*pStr)
  523.     outc(*pStr++);
  524. }
  525.  
  526. static char OutLineBuffer[TOKLEN] = "", SideMargin[TOKLEN];
  527.  
  528. static void PutLine(Boolean DoBlock)
  529. {
  530.   int ll = RightMargin - LeftMargin + 1;
  531.   int l, n, ptrcnt, diff, div, mod, divmod;
  532.   char *chz, *ptrs[50];
  533.   Boolean SkipFirst, IsFirst;
  534.  
  535.   outs(Blanks(LeftMargin - 1));
  536.   if ((Alignment != AlignNone) || (!DoBlock))
  537.   {
  538.     l = visible_strlen(OutLineBuffer);
  539.     diff = ll - l;
  540.     switch (Alignment)
  541.     {
  542.       case AlignRight:
  543.         outs(Blanks(diff));
  544.         l = ll;
  545.         break;
  546.       case AlignCenter:
  547.         outs(Blanks(diff >> 1));
  548.         l += diff >> 1;
  549.         break;
  550.       default:
  551.         break;
  552.     }
  553.     outs(OutLineBuffer);
  554.   }
  555.   else
  556.   {
  557.     SkipFirst = ((CurrEnv == EnvItemize) || (CurrEnv == EnvEnumerate) || (CurrEnv == EnvDescription) || (CurrEnv == EnvBiblio));
  558.     if (LeftMargin == ActLeftMargin)
  559.       SkipFirst = False;
  560.     l = ptrcnt = 0;
  561.     IsFirst = SkipFirst;
  562.     for (chz = OutLineBuffer; *chz != '\0'; chz++)
  563.     {
  564.       if ((chz > OutLineBuffer) && (*(chz - 1) != ' ') && (*chz == ' '))
  565.       {
  566.         if (!IsFirst)
  567.           ptrs[ptrcnt++] = chz;
  568.         IsFirst = False;
  569.       }
  570.       l += visible_clen(*chz);
  571.     }
  572.     (void)ptrs;
  573.     diff = ll + 1 - l;
  574.     div = (ptrcnt > 0) ? diff / ptrcnt : 0;
  575.     mod = diff - (ptrcnt*div);
  576.     divmod = (mod > 0) ? ptrcnt / mod : ptrcnt + 1;
  577.     IsFirst = SkipFirst;
  578.     ptrcnt = 0;
  579.     for (chz = OutLineBuffer; *chz != '\0'; chz++)
  580.     {
  581.       outc(*chz);
  582.       if ((chz > OutLineBuffer) && (*(chz - 1) != ' ') && (*chz == ' '))
  583.       {
  584.         if (!IsFirst)
  585.         {
  586.           n = div;
  587.           if ((mod > 0) && (!(ptrcnt % divmod)))
  588.           {
  589.             mod--;
  590.             n++;
  591.           }
  592.           if (n > 0)
  593.             outs(Blanks(n));
  594.           ptrcnt++;
  595.         }
  596.         IsFirst = False;
  597.       }
  598.     }
  599.     l = RightMargin - LeftMargin + 1;
  600.   }
  601.   if (*SideMargin != '\0')
  602.   {
  603.     outs(Blanks(ll + 3 - l));
  604.     outs(SideMargin);
  605.     *SideMargin = '\0';
  606.   }
  607.   outc('\n');
  608.   LeftMargin = ActLeftMargin;
  609. }
  610.  
  611. static void AddLine(const char *Part, char *Sep)
  612. {
  613.   int mlen = RightMargin - LeftMargin + 1, *hyppos, hypcnt, z, hlen, vlen;
  614.   char *search, save, *lastalpha;
  615.  
  616.   if (strlen(Sep) > 1)
  617.     Sep[1] = '\0';
  618.   if (*OutLineBuffer != '\0')
  619.     strcat(OutLineBuffer, Sep);
  620.   strcat(OutLineBuffer, Part);
  621.   vlen = visible_strlen(OutLineBuffer);
  622.   if (vlen >= mlen)
  623.   {
  624.     search = OutLineBuffer + mlen;
  625.     while (search >= OutLineBuffer)
  626.     {
  627.       if (*search == ' ')
  628.         break;
  629.       if (search > OutLineBuffer)
  630.       {
  631.         if (*(search - 1) == '-')
  632.           break;
  633.         else if (*(search - 1) == '/')
  634.           break;
  635.         else if (*(search - 1) == ';')
  636.           break;
  637.         else if (*(search - 1) == ';')
  638.           break;
  639.       }
  640.       search--;
  641.     }
  642.     if (search <= OutLineBuffer)
  643.     {
  644.       PutLine(True);
  645.       *OutLineBuffer = '\0';
  646.     }
  647.     else
  648.     {
  649.       if (*search == ' ')
  650.       {
  651.         for (lastalpha = search + 1; *lastalpha != '\0'; lastalpha++)
  652.           if ((as_tolower(*lastalpha) < 'a') || (as_tolower(*lastalpha) > 'z'))
  653.             break;
  654.         if (lastalpha - search > 3)
  655.         {
  656.           save = (*lastalpha);
  657.           *lastalpha = '\0';
  658.           if (enable_hyphenation)
  659.             DoHyphens(search + 1, &hyppos, &hypcnt);
  660.           else
  661.             hypcnt = 0;
  662.           *lastalpha = save;
  663.           hlen = -1;
  664.           for (z = 0; z < hypcnt; z++)
  665.             if (visible_strnlen(OutLineBuffer, search - OutLineBuffer) + hyppos[z] + 1 < mlen)
  666.               hlen = hyppos[z];
  667.           if (hlen > 0)
  668.           {
  669.             memmove(search + hlen + 2, search + hlen + 1, strlen(search + hlen + 1) + 1);
  670.             search[hlen + 1] = '-';
  671.             search += hlen + 2;
  672.           }
  673.           if (hypcnt > 0)
  674.             free(hyppos);
  675.         }
  676.       }
  677.       save = (*search);
  678.       *search = '\0';
  679.       PutLine(True);
  680.       *search = save;
  681.       for (; *search == ' '; search++);
  682.       strcpy(OutLineBuffer, search);
  683.     }
  684.   }
  685. }
  686.  
  687. static void AddSideMargin(const char *Part, char *Sep)
  688. {
  689.   if (strlen(Sep) > 1)
  690.     Sep[1] = '\0';
  691.   if (*Sep != '\0')
  692.     if ((*SideMargin != '\0') || (!issep(*Sep)))
  693.       strcat(SideMargin, Sep);
  694.   strcat(SideMargin, Part);
  695. }
  696.  
  697. static void FlushLine(void)
  698. {
  699.   if (*OutLineBuffer != '\0')
  700.   {
  701.     PutLine(False);
  702.     *OutLineBuffer = '\0';
  703.   }
  704. }
  705.  
  706. static void ResetLine(void)
  707. {
  708.   *OutLineBuffer = '\0';
  709. }
  710.  
  711. /*--------------------------------------------------------------------------*/
  712.  
  713. void PrFontDiff(int OldFlags, int NewFlags)
  714. {
  715.   (void)OldFlags;
  716.   (void)NewFlags;
  717. }
  718.  
  719. void PrFontSize(tFontSize Type, Boolean On)
  720. {
  721.   (void)Type;
  722.   (void)On;
  723. }
  724.  
  725. static void SaveEnv(EnvType NewEnv)
  726. {
  727.   PEnvSave NewSave;
  728.  
  729.   NewSave = (PEnvSave) malloc(sizeof(TEnvSave));
  730.   NewSave->Next = EnvStack;
  731.   NewSave->ListDepth = CurrListDepth;
  732.   NewSave->LeftMargin = LeftMargin;
  733.   NewSave->Alignment = Alignment;
  734.   NewSave->ActLeftMargin = ActLeftMargin;
  735.   NewSave->RightMargin = RightMargin;
  736.   NewSave->EnumCounter = EnumCounter;
  737.   NewSave->SaveEnv = CurrEnv;
  738.   NewSave->FontNest = FontNest;
  739.   EnvStack = NewSave;
  740.   CurrEnv = NewEnv;
  741.   FontNest = 0;
  742. }
  743.  
  744. static void RestoreEnv(void)
  745. {
  746.   PEnvSave OldSave;
  747.  
  748.   OldSave = EnvStack;
  749.   EnvStack = OldSave->Next;
  750.   CurrListDepth = OldSave->ListDepth;
  751.   LeftMargin = OldSave->LeftMargin;
  752.   ActLeftMargin = OldSave->ActLeftMargin;
  753.   RightMargin = OldSave->RightMargin;
  754.   Alignment = OldSave->Alignment;
  755.   EnumCounter = OldSave->EnumCounter;
  756.   FontNest = OldSave->FontNest;
  757.   CurrEnv = OldSave->SaveEnv;
  758.   free(OldSave);
  759. }
  760.  
  761. static void InitTableRow(int Index)
  762. {
  763.   int z;
  764.  
  765.   for (z = 0; z < pThisTable->TColumnCount; pThisTable->Lines[Index][z++] = NULL);
  766.   pThisTable->MultiFlags[Index] = False;
  767.   pThisTable->LineFlags[Index] = False;
  768. }
  769.  
  770. static void NextTableColumn(void)
  771. {
  772.   if (CurrEnv != EnvTabular)
  773.     error("table separation char not within tabular environment");
  774.  
  775.   if ((pThisTable->MultiFlags[CurrRow])
  776.    || (CurrCol >= pThisTable->TColumnCount))
  777.     error("too many columns within row");
  778.  
  779.   CurrCol++;
  780. }
  781.  
  782. static void AddTableEntry(const char *Part, char *Sep)
  783. {
  784.   char *Ptr = pThisTable->Lines[CurrRow][CurrCol];
  785.   int nlen = Ptr ? strlen(Ptr) : 0;
  786.   Boolean UseSep = (nlen > 0);
  787.  
  788.   if (strlen(Sep) > 1)
  789.     Sep[1] = '\0';
  790.   if (UseSep)
  791.     nlen += strlen(Sep);
  792.   nlen += strlen(Part);
  793.   if (!Ptr)
  794.   {
  795.     Ptr = (char *) malloc(nlen + 1);
  796.     *Ptr = '\0';
  797.   }
  798.   else
  799.   {
  800.     char *NewPtr = (char *) realloc(Ptr, nlen + 1);
  801.     if (NewPtr)
  802.       Ptr = NewPtr;
  803.   }
  804.   if (UseSep)
  805.     strcat(Ptr, Sep);
  806.   strcat(Ptr, Part);
  807.   pThisTable->Lines[CurrRow][CurrCol] = Ptr;
  808. }
  809.  
  810. static void DoPrnt(char *Ptr, TColumn Align, int len)
  811. {
  812.   int l = (!Ptr) ? 0 : visible_strlen(Ptr), diff;
  813.  
  814.   len -= 2;
  815.   diff = len - l;
  816.   outc(' ');
  817.   switch (Align)
  818.   {
  819.     case ColRight:
  820.       outs(Blanks(diff));
  821.       break;
  822.     case ColCenter:
  823.       outs(Blanks((diff + 1) / 2));
  824.       break;
  825.     default:
  826.       break;
  827.   }
  828.   if (Ptr)
  829.   {
  830.     outs(Ptr);
  831.     free(Ptr);
  832.   }
  833.   switch (Align)
  834.   {
  835.     case ColLeft:
  836.       outs(Blanks(diff));
  837.       break;
  838.     case ColCenter:
  839.       outs(Blanks(diff / 2));
  840.       break;
  841.     default:
  842.       break;
  843.   }
  844.   outc(' ');
  845. }
  846.  
  847. static void DumpTable(void)
  848. {
  849.   int RowCnt, rowz, colz, colptr, ml, l, diff, sumlen, firsttext, indent;
  850.  
  851.   /* compute widths of individual rows */
  852.   /* get index of first text column */
  853.  
  854.   RowCnt = (pThisTable->Lines[CurrRow][0]) ? CurrRow + 1 : CurrRow;
  855.   firsttext = -1;
  856.   for (colz = colptr = 0; colz < pThisTable->ColumnCount; colz++)
  857.     if (pThisTable->ColTypes[colz] == ColBar)
  858.       pThisTable->ColLens[colz] = 1;
  859.     else
  860.     {
  861.       ml = 0;
  862.       for (rowz = 0; rowz < RowCnt; rowz++)
  863.         if ((!pThisTable->LineFlags[rowz]) && (!pThisTable->MultiFlags[rowz]))
  864.         {
  865.           l = (!pThisTable->Lines[rowz][colptr]) ? 0 : visible_strlen(pThisTable->Lines[rowz][colptr]);
  866.           if (ml < l)
  867.             ml = l;
  868.         }
  869.       pThisTable->ColLens[colz] = ml + 2;
  870.       colptr++;
  871.       if (firsttext < 0)
  872.         firsttext = colz;
  873.     }
  874.  
  875.   /* get total width */
  876.  
  877.   for (colz = sumlen = 0; colz < pThisTable->ColumnCount; sumlen += pThisTable->ColLens[colz++]);
  878.   indent = (RightMargin - LeftMargin + 1 - sumlen) / 2;
  879.   if (indent < 0)
  880.     indent = 0;
  881.  
  882.   /* search for multicolumns and extend first field if table is too lean */
  883.  
  884.   ml = 0;
  885.   for (rowz = 0; rowz < RowCnt; rowz++)
  886.     if ((!pThisTable->LineFlags[rowz]) && (pThisTable->MultiFlags[rowz]))
  887.     {
  888.       l = pThisTable->Lines[rowz][0] ? strlen(pThisTable->Lines[rowz][0]) : 0;
  889.       if (ml < l)
  890.         ml = l;
  891.     }
  892.   if (ml + 4 > sumlen)
  893.   {
  894.     diff = ml + 4 - sumlen;
  895.     pThisTable->ColLens[firsttext] += diff;
  896.   }
  897.  
  898.   /* print rows */
  899.  
  900.   for (rowz = 0; rowz < RowCnt; rowz++)
  901.   {
  902.     outs(Blanks(LeftMargin - 1 + indent));
  903.     if (pThisTable->MultiFlags[rowz])
  904.     {
  905.       l = sumlen;
  906.       if (pThisTable->ColTypes[0] == ColBar)
  907.       {
  908.         l--;
  909.         outc('|');
  910.       }
  911.       if (pThisTable->ColTypes[pThisTable->ColumnCount - 1] == ColBar)
  912.         l--;
  913.       for (colz = 0; colz < pThisTable->ColumnCount; colz++)
  914.       {
  915.         if (!colz)
  916.           DoPrnt(pThisTable->Lines[rowz][colz], pThisTable->ColTypes[firsttext], l);
  917.         else if (pThisTable->Lines[rowz][colz])
  918.         {
  919.           free(pThisTable->Lines[rowz][colz]);
  920.           pThisTable->Lines[rowz][colz] = NULL;
  921.         }
  922.         pThisTable->Lines[rowz][0] = NULL;
  923.       }
  924.       if (pThisTable->ColTypes[pThisTable->ColumnCount - 1] == ColBar)
  925.         outc('|');
  926.     }
  927.     else
  928.     {
  929.       for (colz = colptr = 0; colz < pThisTable->ColumnCount; colz++)
  930.         if (pThisTable->LineFlags[rowz])
  931.         {
  932.           if (pThisTable->ColTypes[colz] == ColBar)
  933.             outc('+');
  934.           else
  935.             for (l = 0; l < pThisTable->ColLens[colz]; l++)
  936.               outc('-');
  937.         }
  938.         else
  939.           if (pThisTable->ColTypes[colz] == ColBar)
  940.             outc('|');
  941.           else
  942.           {
  943.             DoPrnt(pThisTable->Lines[rowz][colptr], pThisTable->ColTypes[colz], pThisTable->ColLens[colz]);
  944.             pThisTable->Lines[rowz][colptr] = NULL;
  945.             colptr++;
  946.           }
  947.     }
  948.     outc('\n');
  949.   }
  950. }
  951.  
  952. static void DoAddNormal(const char *Part, char *Sep)
  953. {
  954.   switch (CurrEnv)
  955.   {
  956.     case EnvMarginPar:
  957.       AddSideMargin(Part, Sep);
  958.       break;
  959.     case EnvTabular:
  960.       AddTableEntry(Part, Sep);
  961.       break;
  962.     default:
  963.       AddLine(Part, Sep);
  964.   }
  965. }
  966.  
  967. static void GetTableName(char *Dest, size_t DestSize)
  968. {
  969.   int ThisTableNum = (CurrEnv == EnvTabular) ? TableNum + 1 : TableNum;
  970.  
  971.   if (InAppendix)
  972.     as_snprintf(Dest, DestSize, "%c.%d", Chapters[0] + 'A', ThisTableNum);
  973.   else
  974.     as_snprintf(Dest, DestSize, "%d.%d", Chapters[0], ThisTableNum);
  975. }
  976.  
  977. static void GetSectionName(char *Dest, size_t DestSize)
  978. {
  979.   int z;
  980.  
  981.   *Dest = '\0';
  982.   for (z = 0; z <= 2; z++)
  983.   {
  984.     if ((z > 0) && (Chapters[z] == 0))
  985.       break;
  986.     if ((InAppendix) && (z == 0))
  987.       as_snprcatf(Dest, DestSize, "%c.", Chapters[z] + 'A');
  988.     else
  989.       as_snprcatf(Dest, DestSize, "%d.", Chapters[z]);
  990.   }
  991. }
  992.  
  993. /*--------------------------------------------------------------------------*/
  994.  
  995. static char BackSepString[TOKLEN];
  996.  
  997. static void TeXFlushLine(Word Index)
  998. {
  999.   UNUSED(Index);
  1000.  
  1001.   if (CurrEnv == EnvTabular)
  1002.   {
  1003.     for (CurrCol++; CurrCol < pThisTable->TColumnCount; pThisTable->Lines[CurrRow][CurrCol++] = as_strdup(""));
  1004.     CurrRow++;
  1005.     if (CurrRow == MAXROWS)
  1006.       error("too many rows in table");
  1007.     InitTableRow(CurrRow);
  1008.     CurrCol = 0;
  1009.   }
  1010.   else
  1011.   {
  1012.     if (*OutLineBuffer == '\0')
  1013.       strcpy(OutLineBuffer, " ");
  1014.     FlushLine();
  1015.   }
  1016.   if (CurrEnv == EnvTabbing)
  1017.     CurrTabStop = 0;
  1018. }
  1019.  
  1020. static void TeXKillLine(Word Index)
  1021. {
  1022.   UNUSED(Index);
  1023.  
  1024.   ResetLine();
  1025. }
  1026.  
  1027. static void TeXDummy(Word Index)
  1028. {
  1029.   UNUSED(Index);
  1030. }
  1031.  
  1032. static void TeXDummyNoBrack(Word Index)
  1033. {
  1034.   char Token[TOKLEN];
  1035.   UNUSED(Index);
  1036.  
  1037.   ReadToken(Token);
  1038. }
  1039.  
  1040. static void TeXDummyEqual(Word Index)
  1041. {
  1042.   char Token[TOKLEN];
  1043.   UNUSED(Index);
  1044.  
  1045.   assert_token("=");
  1046.   ReadToken(Token);
  1047. }
  1048.  
  1049. static void TeXDummyInCurl(Word Index)
  1050. {
  1051.   char Token[TOKLEN];
  1052.   UNUSED(Index);
  1053.  
  1054.   assert_token("{");
  1055.   ReadToken(Token);
  1056.   assert_token("}");
  1057. }
  1058.  
  1059. static void TeXNewCommand(Word Index)
  1060. {
  1061.   char token[TOKLEN], command[TOKLEN], sum_token[TOKLEN], arg_cnt[TOKLEN];
  1062.   int level;
  1063.   UNUSED(Index);
  1064.  
  1065.   assert_token("{");
  1066.   assert_token("\\");
  1067.   ReadToken(command);
  1068.   assert_token("}");
  1069.   ReadToken(token);
  1070.  
  1071.   if (!strcmp(token, "["))
  1072.   {
  1073.     ReadToken(arg_cnt);
  1074.     assert_token("]");
  1075.     ReadToken(token);
  1076.   }
  1077.   if (strcmp(token, "{"))
  1078.     error("\"{\" expected");
  1079.  
  1080.   level = 1;
  1081.   *sum_token = '\0';
  1082.   do
  1083.   {
  1084.     ReadToken(token);
  1085.     if (!strcmp(token, "{"))
  1086.       level++;
  1087.     else if (!strcmp(token, "}"))
  1088.       level--;
  1089.     if (level != 0)
  1090.       strmaxcat(sum_token, token, sizeof(sum_token));
  1091.   }
  1092.   while (level != 0);
  1093.   if (!strcmp(command, "asname"))
  1094.     strmaxcpy(asname, sum_token, sizeof(asname));
  1095. }
  1096.  
  1097. static void TeXDef(Word Index)
  1098. {
  1099.   char Token[TOKLEN];
  1100.   int level;
  1101.   UNUSED(Index);
  1102.  
  1103.   assert_token("\\");
  1104.   ReadToken(Token);
  1105.   assert_token("{");
  1106.   level = 1;
  1107.   do
  1108.   {
  1109.     ReadToken(Token);
  1110.     if (!strcmp(Token, "{"))
  1111.       level++;
  1112.     else if (!strcmp(Token, "}"))
  1113.       level--;
  1114.   }
  1115.   while (level != 0);
  1116. }
  1117.  
  1118. static void TeXFont(Word Index)
  1119. {
  1120.   char Token[TOKLEN];
  1121.   UNUSED(Index);
  1122.  
  1123.   assert_token("\\");
  1124.   ReadToken(Token);
  1125.   assert_token("=");
  1126.   ReadToken(Token);
  1127.   ReadToken(Token);
  1128.   assert_token("\\");
  1129.   ReadToken(Token);
  1130. }
  1131.  
  1132. static void TeXAppendix(Word Index)
  1133. {
  1134.   int z;
  1135.   UNUSED(Index);
  1136.  
  1137.   InAppendix = True;
  1138.   *Chapters = -1;
  1139.   for (z = 1; z < CHAPMAX; Chapters[z++] = 0);
  1140. }
  1141.  
  1142. static int LastLevel;
  1143.  
  1144. static void TeXNewSection(Word Level)
  1145. {
  1146.   int z;
  1147.  
  1148.   if (Level >= CHAPMAX)
  1149.     return;
  1150.  
  1151.   FlushLine();
  1152.   outc('\n');
  1153.  
  1154.   assert_token("{");
  1155.   LastLevel = Level;
  1156.   SaveEnv(EnvHeading);
  1157.   RightMargin = 200;
  1158.  
  1159.   Chapters[Level]++;
  1160.   for (z = Level + 1; z < CHAPMAX; Chapters[z++] = 0);
  1161.   if (Level == 0)
  1162.     TableNum = 0;
  1163. }
  1164.  
  1165. static void EndSectionHeading(void)
  1166. {
  1167.   int Level = LastLevel, z;
  1168.   char Line[TOKLEN], Title[TOKLEN];
  1169.  
  1170.   strcpy(Title, OutLineBuffer);
  1171.   *OutLineBuffer = '\0';
  1172.  
  1173.   *Line = '\0';
  1174.   if (Level < 3)
  1175.   {
  1176.     GetSectionName(Line, sizeof(Line));
  1177.     as_snprcatf(Line, sizeof(Line), " ");
  1178.     if ((Level == 2) && (((strlen(Line) + strlen(Title))&1) == 0))
  1179.       as_snprcatf(Line, sizeof(Line), " ");
  1180.   }
  1181.   as_snprcatf(Line, sizeof(Line), "%s", Title);
  1182.  
  1183.   outs("        ");
  1184.   outs(Line);
  1185.   outs("\n        ");
  1186.   for (z = 0; z < (int)strlen(Line); z++)
  1187.     switch(Level)
  1188.     {
  1189.       case 0:
  1190.         outc('=');
  1191.         break;
  1192.       case 1:
  1193.         outc('-');
  1194.         break;
  1195.       case 2:
  1196.         outc(((z&1) == 0) ? '-' : ' ');
  1197.         break;
  1198.       case 3:
  1199.         outc('.');
  1200.         break;
  1201.     }
  1202.   outc('\n');
  1203.  
  1204.   if (Level < 3)
  1205.   {
  1206.     GetSectionName(Line, sizeof(Line));
  1207.     as_snprcatf(Line, sizeof(Line), " %s", Title);
  1208.     AddToc(Line, 5 + Level);
  1209.   }
  1210. }
  1211.  
  1212. static EnvType GetEnvType(char *Name)
  1213. {
  1214.   EnvType z;
  1215.  
  1216.   if (!strcmp(Name, "longtable"))
  1217.     return EnvTabular;
  1218.   for (z = EnvNone + 1; z < EnvCount; z++)
  1219.     if (!strcmp(Name, EnvNames[z]))
  1220.       return z;
  1221.  
  1222.   error("unknown environment");
  1223.   return EnvNone;
  1224. }
  1225.  
  1226. static void TeXBeginEnv(Word Index)
  1227. {
  1228.   char EnvName[TOKLEN], Add[TOKLEN];
  1229.   EnvType NEnv;
  1230.   Boolean done;
  1231.   TColumn NCol;
  1232.   int z;
  1233.   UNUSED(Index);
  1234.  
  1235.   assert_token("{");
  1236.   ReadToken(EnvName);
  1237.   if ((NEnv = GetEnvType(EnvName)) == EnvTable)
  1238.   {
  1239.     ReadToken(Add);
  1240.     if (!strcmp(Add, "*"))
  1241.       assert_token("}");
  1242.     else if (strcmp(Add, "}"))
  1243.       error("unknown table environment");
  1244.   }
  1245.   else
  1246.     assert_token("}");
  1247.  
  1248.   if (NEnv != EnvVerbatim)
  1249.     SaveEnv(NEnv);
  1250.  
  1251.   switch (NEnv)
  1252.   {
  1253.     case EnvItemize:
  1254.     case EnvEnumerate:
  1255.     case EnvDescription:
  1256.       FlushLine();
  1257.       if (CurrListDepth == 0)
  1258.         outc('\n');
  1259.       ++CurrListDepth;
  1260.       ActLeftMargin = LeftMargin = (CurrListDepth * 4) + 1;
  1261.       RightMargin = 70;
  1262.       EnumCounter = 0;
  1263.       break;
  1264.     case EnvBiblio:
  1265.       FlushLine(); outc('\n');
  1266.       outs("        ");
  1267.       outs(BiblioName);
  1268.       outs("\n        ");
  1269.       for (z = 0; z < (int)strlen(BiblioName); z++)
  1270.         outc('=');
  1271.       outc('\n');
  1272.       assert_token("{");
  1273.       ReadToken(Add);
  1274.       assert_token("}");
  1275.       ActLeftMargin = LeftMargin = 4 + (BibIndent = strlen(Add));
  1276.       break;
  1277.     case EnvVerbatim:
  1278.       FlushLine();
  1279.       if ((*BufferLine != '\0') && (*BufferPtr != '\0'))
  1280.       {
  1281.         outs(BufferPtr);
  1282.         *BufferLine = '\0';
  1283.         BufferPtr = BufferLine;
  1284.       }
  1285.       do
  1286.       {
  1287.         if (!fgets(Add, TOKLEN-1, infiles[IncludeNest - 1]))
  1288.           break;
  1289.         CurrLine++;
  1290.         done = strstr(Add, "\\end{verbatim}") != NULL;
  1291.         if (!done)
  1292.           outs(Add);
  1293.       }
  1294.       while (!done);
  1295.       outc('\n');
  1296.       break;
  1297.     case EnvQuote:
  1298.       FlushLine();
  1299.       outc('\n');
  1300.       ActLeftMargin = LeftMargin = 5;
  1301.       RightMargin = 70;
  1302.       break;
  1303.     case EnvTabbing:
  1304.       FlushLine();
  1305.       outc('\n');
  1306.       TabStopCnt = 0;
  1307.       CurrTabStop = 0;
  1308.       break;
  1309.     case EnvTable:
  1310.       ReadToken(Add);
  1311.       if (strcmp(Add, "["))
  1312.         BackToken(Add);
  1313.       else
  1314.         do
  1315.         {
  1316.           ReadToken(Add);
  1317.         }
  1318.         while (strcmp(Add, "]"));
  1319.       FlushLine();
  1320.       outc('\n');
  1321.       ++TableNum;
  1322.       break;
  1323.     case EnvCenter:
  1324.       FlushLine();
  1325.       Alignment = AlignCenter;
  1326.       break;
  1327.     case EnvRaggedRight:
  1328.       FlushLine();
  1329.       Alignment = AlignLeft;
  1330.       break;
  1331.     case EnvRaggedLeft:
  1332.       FlushLine();
  1333.       Alignment = AlignRight;
  1334.       break;
  1335.     case EnvTabular:
  1336.       FlushLine();
  1337.       assert_token("{");
  1338.       pThisTable->ColumnCount = pThisTable->TColumnCount = 0;
  1339.       do
  1340.       {
  1341.         ReadToken(Add);
  1342.         done = !strcmp(Add, "}");
  1343.         if (!done)
  1344.         {
  1345.           if (pThisTable->ColumnCount >= MAXCOLS)
  1346.             error("too many columns in table");
  1347.           if (!strcmp(Add, "|"))
  1348.             NCol = ColBar;
  1349.           else if (!strcmp(Add, "l"))
  1350.             NCol = ColLeft;
  1351.           else if (!strcmp(Add, "r"))
  1352.             NCol = ColRight;
  1353.           else if (!strcmp(Add, "c"))
  1354.             NCol = ColCenter;
  1355.           else
  1356.           {
  1357.             NCol = ColBar;
  1358.             error("unknown table column descriptor");
  1359.           }
  1360.           if ((pThisTable->ColTypes[pThisTable->ColumnCount++] = NCol) != ColBar)
  1361.            pThisTable->TColumnCount++;
  1362.         }
  1363.       }
  1364.       while (!done);
  1365.       InitTableRow(CurrRow = 0);
  1366.       CurrCol = 0;
  1367.       break;
  1368.     default:
  1369.       break;
  1370.   }
  1371. }
  1372.  
  1373. static void TeXEndEnv(Word Index)
  1374. {
  1375.   char EnvName[TOKLEN], Add[TOKLEN];
  1376.   EnvType NEnv;
  1377.   UNUSED(Index);
  1378.  
  1379.   assert_token("{");
  1380.   ReadToken(EnvName);
  1381.   if ((NEnv = GetEnvType(EnvName)) == EnvTable)
  1382.   {
  1383.     ReadToken(Add);
  1384.     if (!strcmp(Add, "*"))
  1385.       assert_token("}");
  1386.     else if (strcmp(Add, "}"))
  1387.       error("unknown table environment");
  1388.   }
  1389.   else
  1390.     assert_token("}");
  1391.  
  1392.   if (!EnvStack)
  1393.     error("end without begin");
  1394.   if (CurrEnv != NEnv)
  1395.   {
  1396.     char Str[100];
  1397.  
  1398.     as_snprintf(Str, sizeof(Str), "begin (%s) and end (%s) of environment do not match",
  1399.                 EnvNames[CurrEnv], EnvNames[NEnv]);
  1400.     error(Str);
  1401.   }
  1402.  
  1403.   switch (CurrEnv)
  1404.   {
  1405.     case EnvItemize:
  1406.     case EnvEnumerate:
  1407.     case EnvDescription:
  1408.       FlushLine();
  1409.       if (CurrListDepth == 1)
  1410.         outc('\n');
  1411.       break;
  1412.     case EnvBiblio:
  1413.     case EnvQuote:
  1414.     case EnvTabbing:
  1415.       FlushLine();
  1416.       outc('\n');
  1417.       break;
  1418.     case EnvCenter:
  1419.     case EnvRaggedRight:
  1420.     case EnvRaggedLeft:
  1421.       FlushLine();
  1422.       break;
  1423.     case EnvTabular:
  1424.       DumpTable();
  1425.       break;
  1426.     case EnvTable:
  1427.       FlushLine();
  1428.       outc('\n');
  1429.       break;
  1430.     default:
  1431.       break;
  1432.   }
  1433.  
  1434.   RestoreEnv();
  1435. }
  1436.  
  1437. static void TeXItem(Word Index)
  1438. {
  1439.   char NumString[20], Token[TOKLEN], Acc[TOKLEN];
  1440.   UNUSED(Index);
  1441.  
  1442.   FlushLine();
  1443.   switch(CurrEnv)
  1444.   {
  1445.     case EnvItemize:
  1446.       LeftMargin = ActLeftMargin - 3;
  1447.       AddLine(" - ", "");
  1448.       break;
  1449.     case EnvEnumerate:
  1450.       LeftMargin = ActLeftMargin - 4;
  1451.       as_snprintf(NumString, sizeof(NumString), "%3d ", ++EnumCounter);
  1452.       AddLine(NumString, "");
  1453.       break;
  1454.     case EnvDescription:
  1455.       ReadToken(Token);
  1456.       if (strcmp(Token, "[")) BackToken(Token);
  1457.       else
  1458.       {
  1459.         collect_token(Acc, "]");
  1460.         LeftMargin = ActLeftMargin - 4;
  1461.         as_snprintf(NumString, sizeof(NumString), "%3s ", Acc);
  1462.         AddLine(NumString, "");
  1463.       }
  1464.       break;
  1465.     default:
  1466.       error("\\item not in a list environment");
  1467.   }
  1468. }
  1469.  
  1470. static void TeXBibItem(Word Index)
  1471. {
  1472.   char NumString[20], Token[TOKLEN], Name[TOKLEN], Format[10];
  1473.   UNUSED(Index);
  1474.  
  1475.   if (CurrEnv != EnvBiblio)
  1476.     error("\\bibitem not in bibliography environment");
  1477.  
  1478.   assert_token("{");
  1479.   collect_token(Name, "}");
  1480.  
  1481.   FlushLine();
  1482.   outc('\n');
  1483.   ++BibCounter;
  1484.  
  1485.   LeftMargin = ActLeftMargin - BibIndent - 3;
  1486.   as_snprintf(Format, sizeof(Format), "[%%%dd] ", BibIndent);
  1487.   as_snprintf(NumString, sizeof(NumString), Format, BibCounter);
  1488.   AddLine(NumString, "");
  1489.   as_snprintf(NumString, sizeof(NumString), "%d", BibCounter);
  1490.   AddCite(Name, NumString);
  1491.   ReadToken(Token);
  1492.   *SepString = '\0';
  1493.   BackToken(Token);
  1494. }
  1495.  
  1496. static void TeXAddDollar(Word Index)
  1497. {
  1498.   UNUSED(Index);
  1499.  
  1500.   DoAddNormal("$", BackSepString);
  1501. }
  1502.  
  1503. static void TeXAddUnderbar(Word Index)
  1504. {
  1505.   UNUSED(Index);
  1506.  
  1507.   DoAddNormal("_", BackSepString);
  1508. }
  1509.  
  1510. #if 0
  1511. static void TeXAddPot(Word Index)
  1512. {
  1513.   UNUSED(Index);
  1514.  
  1515.   DoAddNormal("^", BackSepString);
  1516. }
  1517. #endif
  1518.  
  1519. static void TeXAddAmpersand(Word Index)
  1520. {
  1521.   UNUSED(Index);
  1522.  
  1523.   DoAddNormal("&", BackSepString);
  1524. }
  1525.  
  1526. static void TeXAddAt(Word Index)
  1527. {
  1528.   UNUSED(Index);
  1529.  
  1530.   DoAddNormal("@", BackSepString);
  1531. }
  1532.  
  1533. static void TeXAddImm(Word Index)
  1534. {
  1535.   UNUSED(Index);
  1536.  
  1537.   DoAddNormal("#", BackSepString);
  1538. }
  1539.  
  1540. static void TeXAddPercent(Word Index)
  1541. {
  1542.   UNUSED(Index);
  1543.  
  1544.   DoAddNormal("%", BackSepString);
  1545. }
  1546.  
  1547. static void TeXAddSSharp(Word Index)
  1548. {
  1549.   UNUSED(Index);
  1550.  
  1551.   DoAddNormal(HYPHEN_CHR_sz, BackSepString);
  1552. }
  1553.  
  1554. static void TeXAddIn(Word Index)
  1555. {
  1556.   UNUSED(Index);
  1557.  
  1558.   DoAddNormal("in", BackSepString);
  1559. }
  1560.  
  1561. static void TeXAddReal(Word Index)
  1562. {
  1563.   UNUSED(Index);
  1564.  
  1565.   DoAddNormal("R", BackSepString);
  1566. }
  1567.  
  1568. static void TeXAddGreekMu(Word Index)
  1569. {
  1570.   char Buf[3];
  1571.  
  1572.   UNUSED(Index);
  1573.  
  1574.   DoAddNormal(CharTab_GetNULTermString(pCharacterTab, eCH_mu, Buf), BackSepString);
  1575. }
  1576.  
  1577. static void TeXAddGreekPi(Word Index)
  1578. {
  1579.   UNUSED(Index);
  1580.  
  1581.   DoAddNormal("Pi", BackSepString);
  1582. }
  1583.  
  1584. static void TeXAddLessEq(Word Index)
  1585. {
  1586.   UNUSED(Index);
  1587.  
  1588.   DoAddNormal("<=", BackSepString);
  1589. }
  1590.  
  1591. static void TeXAddGreaterEq(Word Index)
  1592. {
  1593.   UNUSED(Index);
  1594.  
  1595.   DoAddNormal(">=", BackSepString);
  1596. }
  1597.  
  1598. static void TeXAddNotEq(Word Index)
  1599. {
  1600.   UNUSED(Index);
  1601.  
  1602.   DoAddNormal("!=", BackSepString);
  1603. }
  1604.  
  1605. static void TeXAddLAnd(Word Index)
  1606. {
  1607.   UNUSED(Index);
  1608.  
  1609.   DoAddNormal("&", BackSepString);
  1610. }
  1611.  
  1612. static void TeXAddLOr(Word Index)
  1613. {
  1614.   UNUSED(Index);
  1615.  
  1616.   DoAddNormal("|", BackSepString);
  1617. }
  1618.  
  1619. static void TeXAddOPlus(Word Index)
  1620. {
  1621.   UNUSED(Index);
  1622.  
  1623.   DoAddNormal("^", BackSepString);
  1624. }
  1625.  
  1626. static void TeXAddMid(Word Index)
  1627. {
  1628.   UNUSED(Index);
  1629.  
  1630.   DoAddNormal("|", BackSepString);
  1631. }
  1632.  
  1633. static void TeXASName(Word Index)
  1634. {
  1635.   char arg[TOKLEN];
  1636.  
  1637.   UNUSED(Index);
  1638.  
  1639.   assert_token("{");
  1640.   collect_token(arg, "}");
  1641.   DoAddNormal(asname, BackSepString);
  1642. }
  1643.  
  1644. static void TeXAddRightArrow(Word Index)
  1645. {
  1646.   UNUSED(Index);
  1647.  
  1648.   DoAddNormal("->", BackSepString);
  1649. }
  1650.  
  1651. static void TeXAddLongRightArrow(Word Index)
  1652. {
  1653.   UNUSED(Index);
  1654.  
  1655.   DoAddNormal("-->", BackSepString);
  1656. }
  1657.  
  1658. static void TeXAddLongLeftArrow(Word Index)
  1659. {
  1660.   UNUSED(Index);
  1661.  
  1662.   DoAddNormal("<--", BackSepString);
  1663. }
  1664.  
  1665. static void TeXAddLeftArrow(Word Index)
  1666. {
  1667.   UNUSED(Index);
  1668.  
  1669.   DoAddNormal("<-", BackSepString);
  1670. }
  1671.  
  1672. static void TeXAddGets(Word Index)
  1673. {
  1674.   UNUSED(Index);
  1675.  
  1676.   DoAddNormal("<-", BackSepString);
  1677. }
  1678.  
  1679. static void TeXAddLeftRightArrow(Word Index)
  1680. {
  1681.   UNUSED(Index);
  1682.  
  1683.   DoAddNormal("<->", BackSepString);
  1684. }
  1685.  
  1686. static void TeXDoFrac(Word Index)
  1687. {
  1688.   UNUSED(Index);
  1689.  
  1690.   assert_token("{");
  1691.   *SepString = '\0';
  1692.   BackToken("(");
  1693.   FracState = 0;
  1694. }
  1695.  
  1696. static void NextFracState(void)
  1697. {
  1698.   if (FracState == 0)
  1699.   {
  1700.     assert_token("{");
  1701.     *SepString = '\0';
  1702.     BackToken(")");
  1703.     BackToken("/");
  1704.     BackToken("(");
  1705.   }
  1706.   else if (FracState == 1)
  1707.   {
  1708.     *SepString = '\0';
  1709.     BackToken(")");
  1710.   }
  1711.   if ((++FracState) == 2)
  1712.     FracState = -1;
  1713. }
  1714.  
  1715. static void TeXNewFontType(Word Index)
  1716. {
  1717.   CurrFontType = (tFontType) Index;
  1718. }
  1719.  
  1720. static void TeXEnvNewFontType(Word Index)
  1721. {
  1722.   char NToken[TOKLEN];
  1723.  
  1724.   SaveFont();
  1725.   CurrFontType = (tFontType) Index;
  1726.   assert_token("{");
  1727.   ReadToken(NToken);
  1728.   strcpy(SepString, BackSepString);
  1729.   BackToken(NToken);
  1730. }
  1731.  
  1732. static void TeXNewFontSize(Word Index)
  1733. {
  1734.   CurrFontSize = (tFontSize) Index;
  1735. }
  1736.  
  1737. static void TeXEnvNewFontSize(Word Index)
  1738. {
  1739.   char NToken[TOKLEN];
  1740.  
  1741.   SaveFont();
  1742.   CurrFontSize = (tFontSize) Index;
  1743.   assert_token("{");
  1744.   ReadToken(NToken);
  1745.   strcpy(SepString, BackSepString);
  1746.   BackToken(NToken);
  1747. }
  1748.  
  1749. static void TeXAddMarginPar(Word Index)
  1750. {
  1751.   UNUSED(Index);
  1752.  
  1753.   assert_token("{");
  1754.   SaveEnv(EnvMarginPar);
  1755. }
  1756.  
  1757. static void TeXAddCaption(Word Index)
  1758. {
  1759.   char tmp[100];
  1760.   int cnt;
  1761.   UNUSED(Index);
  1762.  
  1763.   assert_token("{");
  1764.   if ((CurrEnv != EnvTable) && (CurrEnv != EnvTabular))
  1765.     error("caption outside of a table");
  1766.   FlushLine();
  1767.   outc('\n');
  1768.   GetTableName(tmp, sizeof(tmp));
  1769.   SaveEnv(EnvCaption);
  1770.   AddLine(TableName, "");
  1771.   cnt = strlen(TableName);
  1772.   strcat(tmp, ": ");
  1773.   AddLine(tmp, " ");
  1774.   cnt += 1 + strlen(tmp);
  1775.   LeftMargin = 1;
  1776.   ActLeftMargin = cnt + 1;
  1777.   RightMargin = 70;
  1778. }
  1779.  
  1780. static void TeXEndHead(Word Index)
  1781. {
  1782.   UNUSED(Index);
  1783. }
  1784.  
  1785. static void TeXHorLine(Word Index)
  1786. {
  1787.   UNUSED(Index);
  1788.  
  1789.   if (CurrEnv != EnvTabular)
  1790.     error("\\hline outside of a table");
  1791.  
  1792.   if (pThisTable->Lines[CurrRow][0])
  1793.     InitTableRow(++CurrRow);
  1794.   pThisTable->LineFlags[CurrRow] = True;
  1795.   InitTableRow(++CurrRow);
  1796. }
  1797.  
  1798. static void TeXMultiColumn(Word Index)
  1799. {
  1800.   char Token[TOKLEN], *endptr;
  1801.   int cnt;
  1802.   UNUSED(Index);
  1803.  
  1804.   if (CurrEnv != EnvTabular) error("\\multicolumn outside of a table");
  1805.   if (CurrCol != 0) error("\\multicolumn must be in first column");
  1806.  
  1807.   assert_token("{");
  1808.   ReadToken(Token);
  1809.   assert_token("}");
  1810.   cnt = strtol(Token, &endptr, 10);
  1811.   if (*endptr != '\0')
  1812.     error("invalid numeric format to \\multicolumn");
  1813.   if (cnt != pThisTable->TColumnCount)
  1814.     error("\\multicolumn must span entire table");
  1815.   assert_token("{");
  1816.   do
  1817.   {
  1818.     ReadToken(Token);
  1819.   }
  1820.   while (strcmp(Token, "}"));
  1821.   pThisTable->MultiFlags[CurrRow] = True;
  1822. }
  1823.  
  1824. static void TeXIndex(Word Index)
  1825. {
  1826.   char Token[TOKLEN];
  1827.   UNUSED(Index);
  1828.  
  1829.   assert_token("{");
  1830.   do
  1831.   {
  1832.     ReadToken(Token);
  1833.   }
  1834.   while (strcmp(Token, "}"));
  1835. }
  1836.  
  1837. static int GetDim(Double *Factors)
  1838. {
  1839.   char Acc[TOKLEN];
  1840.   static char *UnitNames[] = {"cm", "mm", ""}, **run, *endptr;
  1841.   Double Value;
  1842.  
  1843.   assert_token("{");
  1844.   collect_token(Acc, "}");
  1845.   for (run = UnitNames; **run != '\0'; run++)
  1846.     if (!strcmp(*run, Acc + strlen(Acc) - strlen(*run)))
  1847.       break;
  1848.   if (**run == '\0')
  1849.     error("unknown unit for dimension");
  1850.   Acc[strlen(Acc) - strlen(*run)] = '\0';
  1851.   Value = strtod(Acc, &endptr);
  1852.   if (*endptr != '\0')
  1853.     error("invalid numeric format for dimension");
  1854.   return (int)(Value*Factors[run - UnitNames]);
  1855. }
  1856.  
  1857. static Double HFactors[] = { 4.666666, 0.4666666, 0 };
  1858. static Double VFactors[] = { 3.111111, 0.3111111, 0 };
  1859.  
  1860. static void TeXHSpace(Word Index)
  1861. {
  1862.   UNUSED(Index);
  1863.  
  1864.   DoAddNormal(Blanks(GetDim(HFactors)), "");
  1865. }
  1866.  
  1867. static void TeXVSpace(Word Index)
  1868. {
  1869.   int z, erg;
  1870.   UNUSED(Index);
  1871.  
  1872.   erg = GetDim(VFactors);
  1873.   FlushLine();
  1874.   for (z = 0; z < erg; z++)
  1875.     outc('\n');
  1876. }
  1877.  
  1878. static void TeXRule(Word Index)
  1879. {
  1880.   int h = GetDim(HFactors), v = GetDim(VFactors);
  1881.   char Rule[200];
  1882.   UNUSED(Index);
  1883.  
  1884.   for (v = 0; v < h; Rule[v++] = '-');
  1885.   Rule[v] = '\0';
  1886.   DoAddNormal(Rule, BackSepString);
  1887. }
  1888.  
  1889. static void TeXAddTabStop(Word Index)
  1890. {
  1891.   int z, n, p;
  1892.   UNUSED(Index);
  1893.  
  1894.   if (CurrEnv != EnvTabbing)
  1895.     error("tab marker outside of tabbing environment");
  1896.   if (TabStopCnt >= TABMAX)
  1897.     error("too many tab stops");
  1898.  
  1899.   n = strlen(OutLineBuffer);
  1900.   for (p = 0; p < TabStopCnt; p++)
  1901.     if (TabStops[p] > n)
  1902.       break;
  1903.   for (z = TabStopCnt - 1; z >= p; z--)
  1904.     TabStops[z + 1] = TabStops[z];
  1905.   TabStops[p] = n;
  1906.   TabStopCnt++;
  1907. }
  1908.  
  1909. static void TeXJmpTabStop(Word Index)
  1910. {
  1911.   int diff;
  1912.   UNUSED(Index);
  1913.  
  1914.   if (CurrEnv != EnvTabbing)
  1915.     error("tab trigger outside of tabbing environment");
  1916.   if (CurrTabStop >= TabStopCnt)
  1917.     error("not enough tab stops");
  1918.  
  1919.   diff = TabStops[CurrTabStop] - strlen(OutLineBuffer);
  1920.   if (diff > 0)
  1921.     DoAddNormal(Blanks(diff), "");
  1922.   CurrTabStop++;
  1923. }
  1924.  
  1925. static void TeXDoVerb(Word Index)
  1926. {
  1927.   char Token[TOKLEN], *pos, Marker;
  1928.   UNUSED(Index);
  1929.  
  1930.   ReadToken(Token);
  1931.   if (*SepString != '\0')
  1932.     error("invalid control character for \\verb");
  1933.   Marker = (*Token);
  1934.   strmov(Token, Token + 1);
  1935.   strcpy(SepString, BackSepString);
  1936.   do
  1937.   {
  1938.     DoAddNormal(SepString, "");
  1939.     pos = strchr(Token, Marker);
  1940.     if (pos)
  1941.     {
  1942.       *pos = '\0';
  1943.       DoAddNormal(Token, "");
  1944.       *SepString = '\0';
  1945.       BackToken(pos + 1);
  1946.       break;
  1947.     }
  1948.     else
  1949.     {
  1950.       DoAddNormal(Token, "");
  1951.       ReadToken(Token);
  1952.     }
  1953.   }
  1954.   while (True);
  1955. }
  1956.  
  1957. static void TeXErrEntry(Word Index)
  1958. {
  1959.   char Token[TOKLEN];
  1960.   UNUSED(Index);
  1961.  
  1962.   assert_token("{");
  1963.   ReadToken(Token);
  1964.   assert_token("}");
  1965.   assert_token("{");
  1966.   *SepString = '\0';
  1967.   BackToken("\\");
  1968.   BackToken("item");
  1969.   BackToken("[");
  1970.   BackToken(Token);
  1971.   BackToken("]");
  1972.   ErrState = 0;
  1973. }
  1974.  
  1975. static void NextErrState(void)
  1976. {
  1977.   if (ErrState < 3)
  1978.     assert_token("{");
  1979.   if (ErrState == 0)
  1980.   {
  1981.     *SepString = '\0';
  1982.     BackToken("\\");
  1983.     BackToken("begin");
  1984.     BackToken("{");
  1985.     BackToken("description");
  1986.     BackToken("}");
  1987.   }
  1988.   if ((ErrState >= 0) && (ErrState <= 2))
  1989.   {
  1990.     *SepString = '\0';
  1991.     BackToken("\\");
  1992.     BackToken("item");
  1993.     BackToken("[");
  1994.     BackToken(ErrorEntryNames[ErrState]);
  1995.     BackToken(":");
  1996.     BackToken("]");
  1997.     BackToken("\\");
  1998.     BackToken("\\");
  1999.   }
  2000.   if (ErrState == 3)
  2001.   {
  2002.     *SepString = '\0';
  2003.     BackToken("\\");
  2004.     BackToken("\\");
  2005.     BackToken(" ");
  2006.     BackToken("\\");
  2007.     BackToken("end");
  2008.     BackToken("{");
  2009.     BackToken("description");
  2010.     BackToken("}");
  2011.     ErrState = -1;
  2012.   }
  2013.   else
  2014.     ErrState++;
  2015. }
  2016.  
  2017. static void TeXWriteLabel(Word Index)
  2018. {
  2019.   char Name[TOKLEN], Value[TOKLEN];
  2020.   UNUSED(Index);
  2021.  
  2022.   assert_token("{");
  2023.   collect_token(Name, "}");
  2024.  
  2025.   if ((CurrEnv == EnvCaption) || (CurrEnv == EnvTabular))
  2026.     GetTableName(Value, sizeof(Value));
  2027.   else
  2028.   {
  2029.     GetSectionName(Value, sizeof(Value));
  2030.     if ((*Value) && (Value[strlen(Value) - 1] == '.'))
  2031.       Value[strlen(Value) - 1] = '\0';
  2032.   }
  2033.  
  2034.   AddLabel(Name, Value);
  2035. }
  2036.  
  2037. static void TeXWriteRef(Word Index)
  2038. {
  2039.   char Name[TOKLEN], Value[TOKLEN];
  2040.   UNUSED(Index);
  2041.  
  2042.   assert_token("{");
  2043.   collect_token(Name, "}");
  2044.   GetLabel(Name, Value);
  2045.   DoAddNormal(Value, BackSepString);
  2046. }
  2047.  
  2048. static void TeXWriteCitation(Word Index)
  2049. {
  2050.   char Name[TOKLEN], Value[TOKLEN];
  2051.   UNUSED(Index);
  2052.  
  2053.   assert_token("{");
  2054.   collect_token(Name, "}");
  2055.   GetCite(Name, Value);
  2056.   as_snprintf(Name, sizeof(Name), "[%s]", Value);
  2057.   DoAddNormal(Name, BackSepString);
  2058. }
  2059.  
  2060. static void TeXNewParagraph(Word Index)
  2061. {
  2062.   UNUSED(Index);
  2063.  
  2064.   FlushLine();
  2065.   outc('\n');
  2066. }
  2067.  
  2068. static void TeXContents(Word Index)
  2069. {
  2070.   FILE *file = fopen(TocName, "r");
  2071.   char Line[200];
  2072.   UNUSED(Index);
  2073.  
  2074.   if (!file)
  2075.   {
  2076.     Warning("contents file not found.");
  2077.     DoRepass = True;
  2078.     return;
  2079.   }
  2080.  
  2081.   FlushLine();
  2082.   outs("        ");
  2083.   outs(ContentsName);
  2084.   outs("\n\n");
  2085.   while (!feof(file))
  2086.   {
  2087.     if (!fgets(Line, 199, file))
  2088.       break;
  2089.     outs(Line);
  2090.   }
  2091.  
  2092.   fclose(file);
  2093. }
  2094.  
  2095. static void TeXParSkip(Word Index)
  2096. {
  2097.   char Token[TOKLEN];
  2098.   UNUSED(Index);
  2099.  
  2100.   ReadToken(Token);
  2101.   do
  2102.   {
  2103.     ReadToken(Token);
  2104.     if ((!strncmp(Token, "plus", 4)) || (!strncmp(Token, "minus", 5)))
  2105.     {
  2106.     }
  2107.     else
  2108.     {
  2109.       BackToken(Token);
  2110.       return;
  2111.     }
  2112.   }
  2113.   while (1);
  2114. }
  2115.  
  2116. static void TeXNLS(Word Index)
  2117. {
  2118.   char Token[TOKLEN], Buf[3];
  2119.   const char *Repl = NULL;
  2120.   UNUSED(Index);
  2121.  
  2122.   /* NOTE: For characters relevant to hyphenation, insert the
  2123.            (codepage-independent) hyphen characters at this place.
  2124.            Transformation to codepage-dependent character takes
  2125.            place @ output: */
  2126.  
  2127.   *Token = '\0';
  2128.   ReadToken(Token);
  2129.   if (*SepString == '\0')
  2130.     switch (*Token)
  2131.     {
  2132.       case 'a':
  2133.         Repl = HYPHEN_CHR_ae;
  2134.         break;
  2135.       case 'e':
  2136.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_ee, Buf);
  2137.         break;
  2138.       case 'i':
  2139.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_ie, Buf);
  2140.         break;
  2141.       case 'o':
  2142.         Repl = HYPHEN_CHR_oe;
  2143.         break;
  2144.       case 'u':
  2145.         Repl = HYPHEN_CHR_ue;
  2146.         break;
  2147.       case 'A':
  2148.         Repl = HYPHEN_CHR_AE;
  2149.         break;
  2150.       case 'E':
  2151.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Ee, Buf);
  2152.         break;
  2153.       case 'I':
  2154.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Ie, Buf);
  2155.         break;
  2156.       case 'O':
  2157.         Repl = HYPHEN_CHR_OE;
  2158.         break;
  2159.       case 'U':
  2160.         Repl = HYPHEN_CHR_UE;
  2161.         break;
  2162.       case 's':
  2163.         Repl = HYPHEN_CHR_sz;
  2164.         break;
  2165.       default :
  2166.         break;
  2167.     }
  2168.  
  2169.   if (Repl)
  2170.   {
  2171.     if (strlen(Repl) > 1)
  2172.       memmove(Token + strlen(Repl), Token + 1, strlen(Token));
  2173.     memcpy(Token, Repl, strlen(Repl));
  2174.     strcpy(SepString, BackSepString);
  2175.   }
  2176.   else
  2177.     DoAddNormal("\"", BackSepString);
  2178.  
  2179.   BackToken(Token);
  2180. }
  2181.  
  2182. static void TeXNLSGrave(Word Index)
  2183. {
  2184.   char Token[TOKLEN], Buf[3];
  2185.   const char *Repl = NULL;
  2186.   UNUSED(Index);
  2187.  
  2188.   *Token = '\0';
  2189.   ReadToken(Token);
  2190.   if (*SepString == '\0')
  2191.     switch (*Token)
  2192.     {
  2193.       case 'a':
  2194.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_agrave, Buf);
  2195.         break;
  2196.       case 'A':
  2197.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Agrave, Buf);
  2198.         break;
  2199.       case 'e':
  2200.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_egrave, Buf);
  2201.         break;
  2202.       case 'E':
  2203.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Egrave, Buf);
  2204.         break;
  2205.       case 'i':
  2206.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_igrave, Buf);
  2207.         break;
  2208.       case 'I':
  2209.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Igrave, Buf);
  2210.         break;
  2211.       case 'o':
  2212.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_ograve, Buf);
  2213.         break;
  2214.       case 'O':
  2215.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Ograve, Buf);
  2216.         break;
  2217.       case 'u':
  2218.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_ugrave, Buf);
  2219.         break;
  2220.       case 'U':
  2221.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Ugrave, Buf);
  2222.         break;
  2223.       default:
  2224.         break;
  2225.     }
  2226.  
  2227.   if (Repl)
  2228.   {
  2229.     if (strlen(Repl) > 1)
  2230.       memmove(Token + strlen(Repl), Token + 1, strlen(Token));
  2231.     memcpy(Token, Repl, strlen(Repl));
  2232.     strcpy(SepString, BackSepString);
  2233.   }
  2234.   else
  2235.     DoAddNormal("\"", BackSepString);
  2236.  
  2237.   BackToken(Token);
  2238. }
  2239.  
  2240. static void TeXNLSAcute(Word Index)
  2241. {
  2242.   char Token[TOKLEN], Buf[3];
  2243.   const char *Repl = NULL;
  2244.   UNUSED(Index);
  2245.  
  2246.   *Token = '\0';
  2247.   ReadToken(Token);
  2248.   if (*SepString == '\0')
  2249.     switch (*Token)
  2250.     {
  2251.       case 'a':
  2252.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_aacute, Buf);
  2253.         break;
  2254.       case 'A':
  2255.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Aacute, Buf);
  2256.         break;
  2257.       case 'e':
  2258.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_eacute, Buf);
  2259.         break;
  2260.       case 'E':
  2261.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Eacute, Buf);
  2262.         break;
  2263.       case 'i':
  2264.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_iacute, Buf);
  2265.         break;
  2266.       case 'I':
  2267.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Iacute, Buf);
  2268.         break;
  2269.       case 'o':
  2270.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_oacute, Buf);
  2271.         break;
  2272.       case 'O':
  2273.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Oacute, Buf);
  2274.         break;
  2275.       case 'u':
  2276.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_uacute, Buf);
  2277.         break;
  2278.       case 'U':
  2279.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Uacute, Buf);
  2280.         break;
  2281.       default:
  2282.         break;
  2283.     }
  2284.  
  2285.   if (Repl)
  2286.   {
  2287.     if (strlen(Repl) > 1)
  2288.       memmove(Token + strlen(Repl), Token + 1, strlen(Token));
  2289.     memcpy(Token, Repl, strlen(Repl));
  2290.     strcpy(SepString, BackSepString);
  2291.   }
  2292.   else
  2293.     DoAddNormal("\"", BackSepString);
  2294.  
  2295.   BackToken(Token);
  2296. }
  2297.  
  2298. static void TeXNLSCirc(Word Index)
  2299. {
  2300.   char Token[TOKLEN], Buf[3];
  2301.   const char *Repl = "";
  2302.   UNUSED(Index);
  2303.  
  2304.   *Token = '\0';
  2305.   ReadToken(Token);
  2306.   if (*SepString == '\0')
  2307.     switch (*Token)
  2308.     {
  2309.       case 'a':
  2310.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_acirc, Buf);
  2311.         break;
  2312.       case 'A':
  2313.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Acirc, Buf);
  2314.         break;
  2315.       case 'e':
  2316.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_ecirc, Buf);
  2317.         break;
  2318.       case 'E':
  2319.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Ecirc, Buf);
  2320.         break;
  2321.       case 'i':
  2322.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_icirc, Buf);
  2323.         break;
  2324.       case 'I':
  2325.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Icirc, Buf);
  2326.         break;
  2327.       case 'o':
  2328.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_ocirc, Buf);
  2329.         break;
  2330.       case 'O':
  2331.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Ocirc, Buf);
  2332.         break;
  2333.       case 'u':
  2334.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_ucirc, Buf);
  2335.         break;
  2336.       case 'U':
  2337.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Ucirc, Buf);
  2338.         break;
  2339.       default:
  2340.         break;
  2341.     }
  2342.  
  2343.   if (Repl)
  2344.   {
  2345.     if (strlen(Repl) > 1)
  2346.       memmove(Token + strlen(Repl), Token + 1, strlen(Token));
  2347.     memcpy(Token, Repl, strlen(Repl));
  2348.     strcpy(SepString, BackSepString);
  2349.   }
  2350.   else
  2351.     DoAddNormal("\"", BackSepString);
  2352.  
  2353.   BackToken(Token);
  2354. }
  2355.  
  2356. static void TeXNLSTilde(Word Index)
  2357. {
  2358.   char Token[TOKLEN], Buf[3];
  2359.   const char *Repl = "";
  2360.   UNUSED(Index);
  2361.  
  2362.   *Token = '\0';
  2363.   ReadToken(Token);
  2364.   if (*SepString == '\0')
  2365.     switch (*Token)
  2366.     {
  2367.       case 'n':
  2368.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_ntilde, Buf);
  2369.         break;
  2370.       case 'N':
  2371.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Ntilde, Buf);
  2372.         break;
  2373.     }
  2374.  
  2375.   if (Repl)
  2376.   {
  2377.     if (strlen(Repl) > 1)
  2378.       memmove(Token + strlen(Repl), Token + 1, strlen(Token));
  2379.     memcpy(Token, Repl, strlen(Repl));
  2380.     strcpy(SepString, BackSepString);
  2381.   }
  2382.   else
  2383.     DoAddNormal("\"", BackSepString);
  2384.  
  2385.   BackToken(Token);
  2386. }
  2387.  
  2388. static void TeXCedilla(Word Index)
  2389. {
  2390.   char Token[TOKLEN], Buf[3];
  2391.   UNUSED(Index);
  2392.  
  2393.   assert_token("{");
  2394.   collect_token(Token, "}");
  2395.   if (!strcmp(Token, "c"))
  2396.     strcpy(Token, CharTab_GetNULTermString(pCharacterTab, eCH_ccedil, Buf));
  2397.   if (!strcmp(Token, "C"))
  2398.     strcpy(Token, CharTab_GetNULTermString(pCharacterTab, eCH_Ccedil, Buf));
  2399.  
  2400.   DoAddNormal(Token, BackSepString);
  2401. }
  2402.  
  2403. static void TeXAsterisk(Word Index)
  2404. {
  2405.   (void)Index;
  2406.   DoAddNormal("*", BackSepString);
  2407. }
  2408.  
  2409. static Boolean TeXNLSSpec(char *Line)
  2410. {
  2411.   Boolean Found = True;
  2412.   char Buf[3];
  2413.   const char *Repl = NULL;
  2414.   int cnt = 0;
  2415.  
  2416.   if (*SepString == '\0')
  2417.     switch (*Line)
  2418.     {
  2419.       case 'o':
  2420.         cnt = 1;
  2421.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_oslash, Buf);
  2422.         break;
  2423.       case 'O':
  2424.         cnt = 1;
  2425.         Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Oslash, Buf);
  2426.         break;
  2427.       case 'a':
  2428.         switch (Line[1])
  2429.         {
  2430.           case 'a':
  2431.             cnt = 2;
  2432.             Repl = CharTab_GetNULTermString(pCharacterTab, eCH_aring, Buf);
  2433.             break;
  2434.           case 'e':
  2435.             cnt = 2;
  2436.             Repl = CharTab_GetNULTermString(pCharacterTab, eCH_aelig, Buf);
  2437.             break;
  2438.           default:
  2439.             Found = False;
  2440.         }
  2441.         break;
  2442.       case 'A':
  2443.         switch (Line[1])
  2444.         {
  2445.           case 'A':
  2446.             cnt = 2;
  2447.             Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Aring, Buf);
  2448.             break;
  2449.           case 'E':
  2450.             cnt = 2;
  2451.             Repl = CharTab_GetNULTermString(pCharacterTab, eCH_Aelig, Buf);
  2452.             break;
  2453.           default:
  2454.             Found = False;
  2455.         }
  2456.         break;
  2457.       default:
  2458.         Found = False;
  2459.     }
  2460.  
  2461.   if (Found)
  2462.   {
  2463.     if ((int)strlen(Repl) != cnt)
  2464.       memmove(Line + strlen(Repl), Line + cnt, strlen(Line) - cnt + 1);
  2465.     memcpy(Line, Repl, strlen(Repl));
  2466.     strcpy(SepString, BackSepString);
  2467.   }
  2468.   else
  2469.     DoAddNormal("\"", BackSepString);
  2470.  
  2471.   BackToken(Line);
  2472.   return Found;
  2473. }
  2474.  
  2475. static void TeXHyphenation(Word Index)
  2476. {
  2477.   char Token[TOKLEN];
  2478.   UNUSED(Index);
  2479.  
  2480.   assert_token("{");
  2481.   collect_token(Token, "}");
  2482.   AddException(Token);
  2483. }
  2484.  
  2485. static void TeXDoPot(void)
  2486. {
  2487.   char Token[TOKLEN];
  2488.  
  2489.   ReadToken(Token);
  2490.   if (*Token == '2')
  2491.   {
  2492.     char Buf[3];
  2493.     const char *pRepl = CharTab_GetNULTermString(pCharacterTab, eCH_e2, Buf);
  2494.  
  2495.     if (strlen(pRepl) > 1)
  2496.       memmove(Token + strlen(pRepl), Token + 1, strlen(Token));
  2497.     memcpy(Token, pRepl, strlen(pRepl));
  2498.   }
  2499.   else
  2500.     DoAddNormal("^", BackSepString);
  2501.  
  2502.   BackToken(Token);
  2503. }
  2504.  
  2505. static void TeXDoSpec(void)
  2506. {
  2507.   strcpy(BackSepString, SepString);
  2508.   TeXNLS(0);
  2509. }
  2510.  
  2511. static void TeXInclude(Word Index)
  2512. {
  2513.   char Token[2 * TOKLEN + 1], Msg[2 * TOKLEN + 1];
  2514.   UNUSED(Index);
  2515.  
  2516.   assert_token("{");
  2517.   strcpy(Token, SrcDir);
  2518.   collect_token(Token + strlen(Token), "}");
  2519.   infiles[IncludeNest] = fopen(Token, "r");
  2520.   if (!infiles[IncludeNest])
  2521.   {
  2522.     as_snprintf(Msg, sizeof(Msg), "file %s not found", Token);
  2523.     error(Msg);
  2524.   }
  2525.   else
  2526.     IncludeNest++;
  2527. }
  2528.  
  2529. static void TeXDocumentStyle(Word Index)
  2530. {
  2531.   char Token[TOKLEN];
  2532.   UNUSED(Index);
  2533.  
  2534.   ReadToken(Token);
  2535.   if (!strcmp(Token, "["))
  2536.   {
  2537.     do
  2538.     {
  2539.       ReadToken(Token);
  2540.       if (!strcmp(Token, "german"))
  2541.         SetLang(True);
  2542.     }
  2543.     while (strcmp(Token, "]"));
  2544.     assert_token("{");
  2545.     ReadToken(Token);
  2546.     if (CurrPass <= 1)
  2547.     {
  2548.       if (!as_strcasecmp(Token,  "article"))
  2549.       {
  2550.         AddInstTable(TeXTable, "section", 0, TeXNewSection);
  2551.         AddInstTable(TeXTable, "subsection", 1, TeXNewSection);
  2552.         AddInstTable(TeXTable, "subsubsection", 3, TeXNewSection);
  2553.       }
  2554.       else
  2555.       {
  2556.         AddInstTable(TeXTable, "chapter", 0, TeXNewSection);
  2557.         AddInstTable(TeXTable, "section", 1, TeXNewSection);
  2558.         AddInstTable(TeXTable, "subsection", 2, TeXNewSection);
  2559.         AddInstTable(TeXTable, "subsubsection", 3, TeXNewSection);
  2560.       }
  2561.     }
  2562.     assert_token("}");
  2563.   }
  2564. }
  2565.  
  2566. /*!------------------------------------------------------------------------
  2567.  * \fn     TeXUsePackage(Word Index)
  2568.  * \brief  parse \usepackage command
  2569.  * ------------------------------------------------------------------------ */
  2570.  
  2571. static void TeXUsePackage(Word Index)
  2572. {
  2573.   char Token[TOKLEN], Msg[2 * TOKLEN + 1];
  2574.   Boolean read_german_opt = False;
  2575.  
  2576.   UNUSED(Index);
  2577.  
  2578.   while (True)
  2579.   {
  2580.     ReadToken(Token);
  2581.     if (!strcmp(Token, "["))
  2582.     {
  2583.       do
  2584.       {
  2585.         ReadToken(Token);
  2586.         if (!strcmp(Token, "german"))
  2587.           read_german_opt = True;
  2588.       }
  2589.       while (strcmp(Token, "]"));
  2590.     }
  2591.     else if (!strcmp(Token, "{"))
  2592.     {
  2593.       ReadToken(Token);
  2594.       if (!as_strcasecmp(Token, "german"))
  2595.         SetLang(True);
  2596.       else if (!as_strcasecmp(Token, "babel"))
  2597.         SetLang(read_german_opt);
  2598.       else if (!as_strcasecmp(Token, "makeidx"));
  2599.       else if (!as_strcasecmp(Token, "hyperref"));
  2600.       else if (!as_strcasecmp(Token, "longtable"));
  2601.       else
  2602.       {
  2603.         as_snprintf(Msg, sizeof(Msg), "unknown package '%s'", Token);
  2604.         error(Msg);
  2605.       }
  2606.       assert_token("}");
  2607.       break;
  2608.     }
  2609.     else
  2610.     {
  2611.       as_snprintf(Msg, sizeof(Msg), "expecting [ or { after \\usepackage");
  2612.       error(Msg);
  2613.     }
  2614.   }
  2615. }
  2616.  
  2617. /*--------------------------------------------------------------------------*/
  2618.  
  2619. int main(int argc, char **argv)
  2620. {
  2621.   char Line[TOKLEN], Comp[TOKLEN], *p, AuxFile[200];
  2622.   int z, NumPassesLeft;
  2623.  
  2624.   if (argc < 3)
  2625.   {
  2626.     fprintf(stderr, "calling convention: %s <input file> <output file>\n", *argv);
  2627.     exit(1);
  2628.   }
  2629.  
  2630.   nls_init();
  2631.   if (!NLS_Initialize(&argc, argv))
  2632.     exit(3);
  2633.  
  2634.   enable_hyphenation = True;
  2635.   if (argc)
  2636.   {
  2637.     int z, dest;
  2638.  
  2639.     z = dest = 1;
  2640.     while (z < argc)
  2641.       if (!as_strcasecmp(argv[z], "-nohyphen"))
  2642.       {
  2643.         enable_hyphenation = False;
  2644.         z++;
  2645.       }
  2646.       else
  2647.         argv[dest++] = argv[z++];
  2648.     argc = dest;
  2649.   }
  2650.  
  2651.   Codepage = NLS_GetCodepage();
  2652.   pCharacterTab = GetCharacterTab(Codepage);
  2653.   pThisTable = (TTable*)calloc(1, sizeof(*pThisTable));
  2654.  
  2655.   TeXTable = CreateInstTable(301);
  2656.   AddInstTable(TeXTable, "\\", 0, TeXFlushLine);
  2657.   AddInstTable(TeXTable, "par", 0, TeXNewParagraph);
  2658.   AddInstTable(TeXTable, "-", 0, TeXDummy);
  2659.   AddInstTable(TeXTable, "hyphenation", 0, TeXHyphenation);
  2660.   AddInstTable(TeXTable, "kill", 0, TeXKillLine);
  2661.   AddInstTable(TeXTable, "/", 0, TeXDummy);
  2662.   AddInstTable(TeXTable, "pagestyle", 0, TeXDummyInCurl);
  2663.   AddInstTable(TeXTable, "thispagestyle", 0, TeXDummyInCurl);
  2664.   AddInstTable(TeXTable, "sloppy", 0, TeXDummy);
  2665.   AddInstTable(TeXTable, "clearpage", 0, TeXDummy);
  2666.   AddInstTable(TeXTable, "cleardoublepage", 0, TeXDummy);
  2667.   AddInstTable(TeXTable, "topsep", 0, TeXDummyNoBrack);
  2668.   AddInstTable(TeXTable, "parskip", 0, TeXParSkip);
  2669.   AddInstTable(TeXTable, "parindent", 0, TeXDummyNoBrack);
  2670.   AddInstTable(TeXTable, "textwidth", 0, TeXDummyNoBrack);
  2671.   AddInstTable(TeXTable, "evensidemargin", 0, TeXDummyNoBrack);
  2672.   AddInstTable(TeXTable, "oddsidemargin", 0, TeXDummyNoBrack);
  2673.   AddInstTable(TeXTable, "hfuzz", 0, TeXDummyEqual);
  2674.   AddInstTable(TeXTable, "newcommand", 0, TeXNewCommand);
  2675.   AddInstTable(TeXTable, "def", 0, TeXDef);
  2676.   AddInstTable(TeXTable, "font", 0, TeXFont);
  2677.   AddInstTable(TeXTable, "documentstyle", 0, TeXDocumentStyle);
  2678.   AddInstTable(TeXTable, "documentclass", 0, TeXDocumentStyle);
  2679.   AddInstTable(TeXTable, "usepackage", 0, TeXUsePackage);
  2680.   AddInstTable(TeXTable, "appendix", 0, TeXAppendix);
  2681.   AddInstTable(TeXTable, "makeindex", 0, TeXDummy);
  2682.   AddInstTable(TeXTable, "begin", 0, TeXBeginEnv);
  2683.   AddInstTable(TeXTable, "end", 0, TeXEndEnv);
  2684.   AddInstTable(TeXTable, "item", 0, TeXItem);
  2685.   AddInstTable(TeXTable, "bibitem", 0, TeXBibItem);
  2686.   AddInstTable(TeXTable, "errentry", 0, TeXErrEntry);
  2687.   AddInstTable(TeXTable, "$", 0, TeXAddDollar);
  2688.   AddInstTable(TeXTable, "_", 0, TeXAddUnderbar);
  2689.   AddInstTable(TeXTable, "&", 0, TeXAddAmpersand);
  2690.   AddInstTable(TeXTable, "@", 0, TeXAddAt);
  2691.   AddInstTable(TeXTable, "#", 0, TeXAddImm);
  2692.   AddInstTable(TeXTable, "%", 0, TeXAddPercent);
  2693.   AddInstTable(TeXTable, "ss", 0, TeXAddSSharp);
  2694.   AddInstTable(TeXTable, "in", 0, TeXAddIn);
  2695.   AddInstTable(TeXTable, "rz", 0, TeXAddReal);
  2696.   AddInstTable(TeXTable, "mu", 0, TeXAddGreekMu);
  2697.   AddInstTable(TeXTable, "pi", 0, TeXAddGreekPi);
  2698.   AddInstTable(TeXTable, "leq", 0, TeXAddLessEq);
  2699.   AddInstTable(TeXTable, "geq", 0, TeXAddGreaterEq);
  2700.   AddInstTable(TeXTable, "neq", 0, TeXAddNotEq);
  2701.   AddInstTable(TeXTable, "land", 0, TeXAddLAnd);
  2702.   AddInstTable(TeXTable, "lor", 0, TeXAddLOr);
  2703.   AddInstTable(TeXTable, "oplus", 0, TeXAddOPlus);
  2704.   AddInstTable(TeXTable, "mid", 0, TeXAddMid);
  2705.   AddInstTable(TeXTable, "asname", 0, TeXASName);
  2706.   AddInstTable(TeXTable, "frac", 0, TeXDoFrac);
  2707.   AddInstTable(TeXTable, "rm", FontStandard, TeXNewFontType);
  2708.   AddInstTable(TeXTable, "em", FontEmphasized, TeXNewFontType);
  2709.   AddInstTable(TeXTable, "bf", FontBold, TeXNewFontType);
  2710.   AddInstTable(TeXTable, "tt", FontTeletype, TeXNewFontType);
  2711.   AddInstTable(TeXTable, "it", FontItalic, TeXNewFontType);
  2712.   AddInstTable(TeXTable, "bb", FontBold, TeXEnvNewFontType);
  2713.   AddInstTable(TeXTable, "tty", FontTeletype, TeXEnvNewFontType);
  2714.   AddInstTable(TeXTable, "ii", FontItalic, TeXEnvNewFontType);
  2715.   AddInstTable(TeXTable, "tiny", FontTiny, TeXNewFontSize);
  2716.   AddInstTable(TeXTable, "small", FontSmall, TeXNewFontSize);
  2717.   AddInstTable(TeXTable, "normalsize", FontNormalSize, TeXNewFontSize);
  2718.   AddInstTable(TeXTable, "large", FontLarge, TeXNewFontSize);
  2719.   AddInstTable(TeXTable, "huge", FontHuge, TeXNewFontSize);
  2720.   AddInstTable(TeXTable, "tin", FontTiny, TeXEnvNewFontSize);
  2721.   AddInstTable(TeXTable, "rightarrow", 0, TeXAddRightArrow);
  2722.   AddInstTable(TeXTable, "longrightarrow", 0, TeXAddLongRightArrow);
  2723.   AddInstTable(TeXTable, "leftarrow", 0, TeXAddLeftArrow);
  2724.   AddInstTable(TeXTable, "gets", 0, TeXAddGets);
  2725.   AddInstTable(TeXTable, "longleftarrow", 0, TeXAddLongLeftArrow);
  2726.   AddInstTable(TeXTable, "leftrightarrow", 0, TeXAddLeftRightArrow);
  2727.   AddInstTable(TeXTable, "marginpar", 0, TeXAddMarginPar);
  2728.   AddInstTable(TeXTable, "caption", 0, TeXAddCaption);
  2729.   AddInstTable(TeXTable, "endhead", 0, TeXEndHead);
  2730.   AddInstTable(TeXTable, "label", 0, TeXWriteLabel);
  2731.   AddInstTable(TeXTable, "ref", 0, TeXWriteRef);
  2732.   AddInstTable(TeXTable, "cite", 0, TeXWriteCitation);
  2733.   AddInstTable(TeXTable, "hline", 0, TeXHorLine);
  2734.   AddInstTable(TeXTable, "multicolumn", 0, TeXMultiColumn);
  2735.   AddInstTable(TeXTable, "ttindex", 0, TeXIndex);
  2736.   AddInstTable(TeXTable, "hspace", 0, TeXHSpace);
  2737.   AddInstTable(TeXTable, "vspace", 0, TeXVSpace);
  2738.   AddInstTable(TeXTable, "=", 0, TeXAddTabStop);
  2739.   AddInstTable(TeXTable, ">", 0, TeXJmpTabStop);
  2740.   AddInstTable(TeXTable, "verb", 0, TeXDoVerb);
  2741.   AddInstTable(TeXTable, "printindex", 0, TeXDummy);
  2742.   AddInstTable(TeXTable, "tableofcontents", 0, TeXContents);
  2743.   AddInstTable(TeXTable, "rule", 0, TeXRule);
  2744.   AddInstTable(TeXTable, "\"", 0, TeXNLS);
  2745.   AddInstTable(TeXTable, "`", 0, TeXNLSGrave);
  2746.   AddInstTable(TeXTable, "'", 0, TeXNLSAcute);
  2747.   AddInstTable(TeXTable, "^", 0, TeXNLSCirc);
  2748.   AddInstTable(TeXTable, "~", 0, TeXNLSTilde);
  2749.   AddInstTable(TeXTable, "c", 0, TeXCedilla);
  2750.   AddInstTable(TeXTable, "*", 0, TeXAsterisk);
  2751.   AddInstTable(TeXTable, "newif", 0, TeXDummy);
  2752.   AddInstTable(TeXTable, "fi", 0, TeXDummy);
  2753.   AddInstTable(TeXTable, "ifelektor", 0, TeXDummy);
  2754.   AddInstTable(TeXTable, "elektortrue", 0, TeXDummy);
  2755.   AddInstTable(TeXTable, "elektorfalse", 0, TeXDummy);
  2756.   AddInstTable(TeXTable, "input", 0, TeXInclude);
  2757.  
  2758.   CurrPass = 0;
  2759.   NumPassesLeft = 3;
  2760.   do
  2761.   {
  2762.     CurrPass++;
  2763.  
  2764.     DidEOF = False;
  2765.     IncludeNest = 0;
  2766.     pInFileName = argv[1];
  2767.     *infiles = fopen(pInFileName, "r");
  2768.     if (!*infiles)
  2769.     {
  2770.       perror(pInFileName);
  2771.       exit(3);
  2772.     }
  2773.     else
  2774.       IncludeNest++;
  2775.     SetSrcDir(pInFileName);
  2776.     if (!strcmp(argv[2], "-"))
  2777.       outfile = stdout;
  2778.     else
  2779.     {
  2780.       outfile = fopen(argv[2], "w");
  2781.       if (!outfile)
  2782.       {
  2783.         perror(argv[2]);
  2784.         exit(3);
  2785.       }
  2786.     }
  2787.  
  2788.     for (z = 0; z < CHAPMAX; Chapters[z++] = 0);
  2789.     TableNum = 0;
  2790.     TabStopCnt = 0;
  2791.     CurrTabStop = 0;
  2792.     ErrState = FracState = -1;
  2793.     InAppendix = False;
  2794.     EnvStack = NULL;
  2795.     CurrEnv = EnvNone;
  2796.     CurrListDepth = 0;
  2797.     ActLeftMargin = LeftMargin = 1;
  2798.     RightMargin = 70;
  2799.     Alignment = AlignNone;
  2800.     EnumCounter = 0;
  2801.     InitFont();
  2802.     CurrLine = 0;
  2803.     InitLabels();
  2804.     InitCites();
  2805.     InitToc();
  2806.     *SideMargin = '\0';
  2807.     DoRepass = False;
  2808.     BibIndent = BibCounter = 0;
  2809.     GermanMode = True;
  2810.     SetLang(False);
  2811.  
  2812.     strcpy(TocName, pInFileName);
  2813.     p = strrchr(TocName, '.');
  2814.     if (p)
  2815.       *p = '\0';
  2816.     strcat(TocName, ".dtoc");
  2817.  
  2818.     strcpy(AuxFile, pInFileName);
  2819.     p = strrchr(AuxFile, '.');
  2820.     if (p)
  2821.       *p = '\0';
  2822.     strcat(AuxFile, ".daux");
  2823.     ReadAuxFile(AuxFile);
  2824.  
  2825.     while (1)
  2826.     {
  2827.       if (!ReadToken(Line))
  2828.         break;
  2829.       if (!strcmp(Line, "\\"))
  2830.       {
  2831.         strcpy(BackSepString, SepString);
  2832.         if (!ReadToken(Line))
  2833.           error("unexpected end of file");
  2834.         if (*SepString != '\0')
  2835.           BackToken(Line);
  2836.         else if (!LookupInstTable(TeXTable, Line))
  2837.           if (!TeXNLSSpec(Line))
  2838.           {
  2839.             as_snprintf(Comp, sizeof(Comp), "unknown TeX command %s", Line);
  2840.             Warning(Comp);
  2841.           }
  2842.       }
  2843.       else if (!strcmp(Line, "$"))
  2844.       {
  2845.         InMathMode = !InMathMode;
  2846.         if (InMathMode)
  2847.         {
  2848.           strcpy(BackSepString, SepString);
  2849.           ReadToken(Line);
  2850.           strcpy(SepString, BackSepString);
  2851.           BackToken(Line);
  2852.         }
  2853.       }
  2854.       else if (!strcmp(Line, "&"))
  2855.         NextTableColumn();
  2856.       else if ((!strcmp(Line, "^")) && (InMathMode))
  2857.         TeXDoPot();
  2858.       else if ((!strcmp(Line, "\"")) && (GermanMode))
  2859.         TeXDoSpec();
  2860.       else if (!strcmp(Line, "{"))
  2861.         SaveFont();
  2862.       else if (!strcmp(Line, "}"))
  2863.       {
  2864.         if (FontNest > 0)
  2865.           RestoreFont();
  2866.         else if (ErrState >= 0)
  2867.           NextErrState();
  2868.         else if (FracState >= 0)
  2869.           NextFracState();
  2870.         else switch (CurrEnv)
  2871.         {
  2872.           case EnvMarginPar:
  2873.             RestoreEnv();
  2874.             break;
  2875.           case EnvCaption:
  2876.             FlushLine();
  2877.             RestoreEnv();
  2878.             break;
  2879.           case EnvHeading:
  2880.             EndSectionHeading();
  2881.             RestoreEnv();
  2882.             break;
  2883.           default:
  2884.             RestoreFont();
  2885.         }
  2886.       }
  2887.       else
  2888.         DoAddNormal(Line, SepString);
  2889.     }
  2890.     FlushLine();
  2891.  
  2892.     for (z = 0; z < IncludeNest; fclose(infiles[z++]));
  2893.     fclose(outfile);
  2894.  
  2895.     unlink(AuxFile);
  2896.     PrintLabels(AuxFile);
  2897.     PrintCites(AuxFile);
  2898.     PrintToc(TocName);
  2899.  
  2900.     FreeLabels();
  2901.     FreeCites();
  2902.     DestroyTree();
  2903.     FreeToc();
  2904.     FreeFontStack();
  2905.  
  2906.     NumPassesLeft--;
  2907.     if (DoRepass)
  2908.       fprintf(stderr, "additional pass needed\n");
  2909.   }
  2910.   while (DoRepass && NumPassesLeft);
  2911.  
  2912.   DestroyInstTable(TeXTable);
  2913.  
  2914.   if (DoRepass)
  2915.   {
  2916.     fprintf(stderr, "additional passes needed but cowardly not done\n");
  2917.     return 3;
  2918.   }
  2919.   else
  2920.   {
  2921.     fprintf(stderr, "%d pass(es) needed\n", CurrPass);
  2922.     return 0;
  2923.   }
  2924. }
  2925.  
  2926. #ifdef CKMALLOC
  2927. #undef malloc
  2928. #undef realloc
  2929.  
  2930. void *ckmalloc(size_t s)
  2931. {
  2932.   void *tmp = malloc(s);
  2933.   if (!tmp)
  2934.   {
  2935.     fprintf(stderr, "allocation error(malloc): out of memory");
  2936.     exit(255);
  2937.   }
  2938.   return tmp;
  2939. }
  2940.  
  2941. void *ckrealloc(void *p, size_t s)
  2942. {
  2943.   void *tmp = realloc(p, s);
  2944.   if (!tmp)
  2945.   {
  2946.     fprintf(stderr, "allocation error(realloc): out of memory");
  2947.     exit(255);
  2948.   }
  2949.   return tmp;
  2950. }
  2951. #endif
  2952.  
  2953.