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