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