1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
2 #include <stdio.h>
3 #include <ctype.h>
4 #include <unistd.h> /* for unlink */
5 #include "sowing.h"
6 #include "search.h"
7 #include "tex.h"
8
9 #define OUTFILE_SIZE 512
10 /* #define DBGMSG(a) if (DebugCommands) { fprintf( stdout, ... what goes here .. ); } */
11
12 extern LINK *GetNextLink ( LINK * );
13 /*
14 This is a simple program to translate mostly ASCII text code from
15 a latexinfo file into another format. Different formats can be
16 generated by providing different versions of the file tex2....c
17 For example,
18 tex2win generates Windows help output.
19 tex2html generates HTML (WWW) output
20
21 */
22
23 /*
24 Outstanding problems:
25
26 InOutputBody isn't set except within "sections" (after WriteBeginPage).
27 Some TeX code doesn't use section/chapter/part.
28
29 InOutputBody is used to suppress random TeX code from generating output.
30 We need another way to indicate InOutputBody.
31 -> many commands could set when they are called, indicating that we are
32 doing output. ???
33
34 In general, this code needs to be entirely re-written. The model should be
35 a string of filters that recognize various constructions and replace them.
36 replaced code is contained in (nested?) begin-tok/end-tok pairs.
37 */
38
39
40 /*
41 I'd like to push a token in every routine, but the PC version seems to
42 run out of stack space (very, very tiny stacks!)
43
44 What I should do is just allocate and deallocate. This is more expensive,
45 but TeX is recursive and I've had problems with things like TeX commands
46 in \subsection....
47 */
48
49 /*
50 Still need code to handle
51 \font\manual=manfnt at 12pt
52 (also, how to handle in generating output? Should it produce a
53 bitmap?)
54 */
55 /* static char gtoken[MAX_TOKEN]; */
56
57 /* These are used to hold a stack of tokens so that (a) we don't have to
58 allocated them all the time and (b) we don't require the ability to
59 allocate them off of the stack (a problem for PC's) */
60 char *tokbuf, *curtok;
61 int toknum;
62
63 /*
64 void TeXProcessCommand();
65 extern void TXem(), TXtt(), TXbf(), TXsf(), TXrm(),
66 TXmath(), TXmathend(), TXinlinemath(),
67 TXinlinemathend(), TXbitmap(), TXbw2(), TXbw(), TXbbrace(),
68 TXebrace(), TXoutbullet(), TXbgroup(), TXegroup();
69 extern int TXWriteStartNewline(), TeXoutNewline();
70
71 extern void TXbitemize(), TXeitemize(),
72 TXbenumerate(), TXeenumberate(),
73 TXbdescription(), TXedescription(),
74 TXbmenu(), TXemenu(), TXdimen(), TXnumber(), TXDef(), TeXtabular(),
75 TXbibitem(), TXDoNewenvironment(), TXDoNewtheorem(),
76 TXcounter(), TXadvance(),
77 TXDoBibliography(), TXcaption();
78 extern int LookupEnv();
79
80 extern void SCSetAtLetter();
81 extern char SCGetCommentChar();
82
83 */
84 /* Forward refs */
85 /*
86 void TeXskipEnv(), TXoutactiveToken();
87 */
88 void PrintLastSectionName( FILE * );
89
90 FILE *ferr = 0; /* We'd like this to be stderr, but ANSI/ISO C broke this */
91 SRList *topicctx = 0;
92
93 int InDocument = 0;
94 int InOutputBody = 0;
95
96 static int AmSkipping = 0; /* Set to one when skipping a tex environment */
97 int InArg = 0; /* Set to one when in an argument */
98 char *ArgBuffer = 0; /* Used to hold temporary text */
99 static int InVerbatim = 0; /* Verbatim has special processing */
100 static int DebugArgs = 0; /* Set to one to dump arg processing */
101 int DebugCommands = 0; /* Set to one to dump command processing */
102 int DebugOutput = 0; /* Set to one to dump output processing */
103 int DebugFile = 0; /* Debug file related commands */
104 int DebugFont = 0; /* Debug font related commands */
105 int warnRedefinition = 0; /* Warn on redefinition of commands */
106 static int UseIfTex = 0; /* Set to use begin{iftex} ... instead of
107 begin{ifinfo} code */
108
109 static int ProcessManPageTokens = 0;
110 /* Check EVERY token for a reference to a
111 known man page. WARNING: this may make
112 the file rather link-heavy */
113
114 /* These control whether we generate GIF files for what we don't understand */
115 int LatexUnknownEnvs = 0;
116 /* Latex Tables? */
117 int LatexTables = 0;
118 /* Latex Math? */
119 int LatexMath = 0;
120 /* Simple Math (math mode with no TeX commands done in italics */
121 int SimpleMath = 0;
122 /* Number of the generated image file */
123 int imageno = 0;
124 /* Set LatexAgain to 0 if you want to use the old img files */
125 int LatexAgain = 1;
126
127 /* Set to 1 to generate HTML for tabular environments */
128 int HandleAlign = 0;
129
130 int TableNumber = 0, FigureNumber = 0, EquationNumber = 0;
131 int NumberedEnvironmentType = ENV_NONE;
132 char *envjumpname = 0;
133 int envJumpNum = 0;
134
135 int IncludeSectionNumbers = 0;
136 /* MinSectionKind allows us to handle documents with Chapters and Sections
137 better (a bibliography is the same kind of item as the largest
138 section (Chapter == 0, Section == 1)
139 */
140 int MinSectionKind = 1;
141
142 int IgnoreCatcode = 1;
143
144 /* This is for debugging the LaTeX file; it is important to ensure that all
145 braces are closed */
146 int LineNo[10] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
147 char *(InFName[10]) = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
148 int BraceCount = 0;
149 char CmdName[65];
150
151 /* These hold the current section being processed, so that LABELS to this
152 section may be entered into the label table (and hence to the aux file for
153 the section pass). */
154 static int CurSeqnum = 0;
155 static char CurNodename[256];
156
157 /* Citation characters. The default is [ and ] */
158 char *CitePrefix = 0;
159 char *CiteSuffix = 0;
160
161
162 int UsingLatexinfo = 0;
163 int DestIsHtml = 1;
164 int HTMLv3 = 1;
165
166 #if defined(WIN32) || defined(__MSDOS__)
167 char HTML_Suffix[5] = "htm";
168 char DirSep = '\\';
169 char DirSepString[2] = "\\";
170 #else
171 char HTML_Suffix[5] = "html";
172 char DirSep = '/';
173 char DirSepString[2] = "/";
174 #endif
175 /*
176 TeX processing:
177 We need to manage things like \section{name}, \begin{tex}, \c (comment)
178
179 Multiple blank lines must generate a \par in the rtf file.
180 More specifically, a completely blank line must be changed into a par.
181 */
182 /* The tex stack */
183 typedef struct {
184 int fonttype; /* Current font */
185 /* Other parameters as required */
186 int fontsize; /* Not used yet; should be delta? */
187 } TeXStack;
188
189 /* The section stack */
190 typedef struct {
191 int level; /* Section level */
192 int count; /* Current count of sections at this level */
193 /* entries for parent, children, siblings?? */
194 } SectionStack;
195
196 /* The list of known functions */
197 SRList *TeXlist = 0;
198
199 /* Stack of input files */
200 int curfile = 0;
201 FILE *(fpin[10]) = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
202 FILE *fpout = 0;
203 char *outfile = 0;
204
205 TeXStack stack[MAX_TEX_STACK];
206 static int texSp = -1;
207 LaTeXStack lstack[MAX_TEX_STACK];
208 int lSp = -1;
209 SectionStack sstack[MAX_TEX_STACK];
210 static int SSp = -1;
211
212 /* The "brace" stack */
213 #define MAX_BLOC_FNAME 50
214 typedef struct {
215 int lineno;
216 char filename[255];
217 } BraceElment;
218 #define MAX_BLOC 50
219 static BraceElment bloc[MAX_BLOC];
220
221 /* TeX special characters on startup */
222 char CommandChar = '\\';
223 char SubscriptChar = '_';
224 char SuperscriptChar = '^';
225 char MathmodeChar = '$';
226 char CommentChar = '%';
227 char LbraceChar = '{';
228 char RbraceChar = '}';
229 char ArgChar = '#';
230 char AlignChar = '&';
231 char ActiveChar = '\0'; /* Normally not set. We allow a single char
232 to be active; (will be) used for obeylines */
233 void (*activeCharAction)(char *) = 0;
234
235 /* Special user commands */
236 char *UserIndexName = 0;
237
238 /* File for latex or graphics output errors */
239 char latex_errname[300];
240
241 /* File name base for generated image files (default img) */
242 char imgfilebase[MAX_IMAGE_FILE_BASE];
243
244 /*
245 This file contains the actions for processing a subset of LaTeXinfo
246 files
247 */
248
TXSetDebug(int flag)249 void TXSetDebug( int flag )
250 {
251 DebugArgs = flag;
252 DebugCommands = flag;
253 }
254
TXSetDebugFile(int flag)255 void TXSetDebugFile( int flag )
256 {
257 DebugFile = flag;
258 }
259
TXSetDebugFont(int flag)260 void TXSetDebugFont( int flag )
261 {
262 DebugFont = flag;
263 }
264
TXSetUseIfTex(int flag)265 void TXSetUseIfTex( int flag )
266 {
267 UseIfTex = flag;
268 }
269
TXSetLatexUnknown(int flag)270 void TXSetLatexUnknown( int flag )
271 {
272 LatexUnknownEnvs = flag;
273 }
274
TXSetProcessManPageTokens(flag)275 void TXSetProcessManPageTokens( flag )
276 int flag;
277 {
278 ProcessManPageTokens = flag;
279 }
280
TXSetLatexTables(int flag)281 void TXSetLatexTables( int flag )
282 {
283 LatexTables = flag;
284 }
TXSetLatexMath(int flag)285 void TXSetLatexMath( int flag )
286 {
287 LatexMath = flag;
288 }
289
TXSetSimpleMath(int flag)290 void TXSetSimpleMath( int flag )
291 {
292 SimpleMath = flag;
293 }
294
TXSetLatexAgain(int flag)295 void TXSetLatexAgain( int flag )
296 {
297 LatexAgain = flag;
298 }
299
TXSetFiles(char * fin,char * fout)300 void TXSetFiles( char *fin, char *fout )
301 {
302 outfile = (char *)MALLOC( OUTFILE_SIZE );
303 CHKPTR(outfile);
304 strcpy( outfile, fout );
305 InFName[0] = (char *)MALLOC( strlen(fin) + 1 );
306 CHKPTR(InFName[0]);
307 strcpy( InFName[0], fin );
308 }
309
TeXAbort(char * routine,char * msg)310 void TeXAbort( char *routine, char *msg )
311 {
312 fprintf( stdout, "%s:%s\n", routine, msg ? msg : "No message" );
313 fprintf( stdout, "File %s line %d\n",
314 InFName[curfile] ? InFName[curfile]: "", LineNo[curfile] );
315 exit(1);
316 }
317
TXPrintLocation(FILE * fp)318 void TXPrintLocation( FILE *fp )
319 {
320 fprintf( fp, "File %s line %d\n",
321 InFName[curfile] ? InFName[curfile]: "", LineNo[curfile] );
322 }
323
324 /* Output a command */
TeXoutcmd(FILE * fout,char * str)325 void TeXoutcmd( FILE *fout, char *str )
326 {
327 char buf[102];
328 if (strlen(str) >= 100) {
329 fprintf( stderr,
330 "Error in TeXoutcmd (internal error, command too long)!\n" );
331 return;
332 }
333 buf[0] = TOK_START;
334 strcpy( buf+1, str );
335 buf[strlen(buf)+1] = 0;
336 buf[strlen(buf)] = TOK_END;
337 if (InArg) {
338 if (!ArgBuffer) {
339 ArgBuffer = MALLOC( MAX_TOKEN );
340 CHKPTR(ArgBuffer);
341 }
342
343 strcat( ArgBuffer, buf );
344 } /* SCAppendToken( buf ); */
345 else {
346 if (ProcessManPageTokens)
347 TXoutactiveToken( buf );
348 else
349 WriteString( fout, buf );
350 }
351 }
352
353 /* Output text (may be pushed back for rescanning) */
TeXoutstr(FILE * fout,char * str)354 void TeXoutstr( FILE *fout, char *str )
355 {
356 if (InArg) {
357 if (!ArgBuffer) {
358 ArgBuffer = MALLOC( MAX_TOKEN );
359 CHKPTR(ArgBuffer);
360 }
361 strcat( ArgBuffer, str );
362 } /* SCAppendToken( str ); */
363 else {
364 if (ProcessManPageTokens)
365 TXoutactiveToken( str );
366 else
367 WriteString( fout, str );
368 }
369 }
370
TeXoutsp(FILE * fout,int nsp)371 void TeXoutsp( FILE *fout, int nsp )
372 {
373 int i;
374 if (!InDocument) return;
375 for (i=0; i<nsp; i++) TeXoutstr( fout, " " );
376 }
377
378 /* Read a TeX token; control sequences (\name) are read as a single token.
379 nsp is the number of preceding blanks. Returns the first character in
380 the token (or EOF)
381 */
TeXReadToken(char * token,int * nsp)382 int TeXReadToken( char *token, int *nsp )
383 {
384 int ch, ch2, d;
385
386 ch = SCTxtFindNextANToken( fpin[curfile], token, MAX_TOKEN, nsp );
387 if (ch == '\\') {
388 ch2 = SCTxtFindNextANToken( fpin[curfile], token+1, MAX_TOKEN-1, &d );
389 if (d > 0) {
390 /* If there were leading blanks, convert them into a single
391 blank and push the token back */
392 SCPushToken( token+1 );
393 token[1] = ' ';
394 token[2] = 0;
395 }
396 }
397 return ch;
398 }
399
400 /* Read a macro name, having read the first \ */
TeXReadMacroName(char * token)401 void TeXReadMacroName( char *token )
402 {
403 int ch, nsp;
404
405 while ( (ch = SCTxtFindNextANToken( fpin[curfile], token, MAX_TOKEN, &nsp ))
406 == EOF) {
407 if (DebugCommands)
408 fprintf( stdout, "EOF in TeXskipEnv while reading macro\n" );
409 TXPopFile();
410 }
411 if (nsp != 0) {
412 SCPushToken( token );
413 strcpy( token, " " );
414 }
415 }
416
417 /*
418 Get a TeX argument. Return 0 if no matching argument found, 1 otherwise.
419 if doeval is false, don't process any command that is found; instead,
420 just copy it.
421
422 A complication here is that we may need to recursively evaluate the tokens
423 that are being read. We have to be careful to avoid rescanning the
424 same text over and over. We do this by having EACH invocation of
425 TeXGetGenArg create a private output buffer that is used by the output
426 routines to append the output into each time "TXProcessCommand" is
427 invoked. At the end of the call to TXProcessCommand, this output is
428 pushed back onto the input buffer.
429
430 2/11/97
431 If a comment character is defined, we skip to the end of the line
432 */
433 #define MAX_MEM_STACK 128
434 /* Just to avoid constant mallocs, we maintain a stack of memory */
435 /* Points to last used element */
436 /* When new space is allocated, it MUST have size MAX_TOKEN */
437 static int mem_stack_sp = -1;
438 static int mem_stack_wm = -1;
439 static char *(mem_stack[MAX_MEM_STACK]);
440 #define ALLOC_TOKEN(t) {\
441 if (mem_stack_sp < mem_stack_wm) {\
442 t = mem_stack[++mem_stack_sp];\
443 }else {\
444 if (mem_stack_wm >= MAX_MEM_STACK) {\
445 fprintf( stderr, "Overflow in TeX argument processing!\n" );\
446 exit(1);\
447 }\
448 mem_stack[++mem_stack_wm] = MALLOC( MAX_TOKEN );\
449 t = mem_stack[++mem_stack_sp];}}
450
451 #define FREE_TOKEN(t) mem_stack_sp--;
452
453 /*
454 Return 1 for found argument, 0 for no arg, and -1 for error.
455 */
456 static int GetArgDepth=0;
TeXGetGenArg(FILE * fin,char * token,int maxtoken,char sc,char ec,int doeval)457 int TeXGetGenArg( FILE *fin, char *token, int maxtoken, char sc, char ec,
458 int doeval )
459 {
460 int ch, nsp, i, oldinarg = InArg;
461 char *local_buf, *save_buf, *save_buf2;
462 char mtoken[MAX_TOKEN];
463 /* tf and mf save the token state */
464 char *tf = token;
465 int mf = maxtoken;
466 int depth = 0, found;
467 TeXEntry E;
468
469 GetArgDepth++;
470 found = 0;
471 save_buf = ArgBuffer;
472 ALLOC_TOKEN(local_buf);
473 ArgBuffer = local_buf;
474 /* ArgBuffer = local_buf = MALLOC( MAX_TOKEN );
475 if (!local_buf) {
476 fprintf( stderr, "Out of memory!\n" );
477 exit(1);
478 }
479 */
480 local_buf[0] = 0; /* In case we don't push anything back */
481 while ((ch = SCTxtFindNextANToken( fin, token, maxtoken, &nsp )) == EOF) {
482 if (DebugCommands)
483 fprintf( stdout, "EOF in TeXGetGenArg\n" );
484 TXPopFile();
485 }
486 if (DebugArgs) fprintf( stdout, "ARG-start: ch = %c\n", ch );
487 if (ch == sc) {
488 found = 1;
489 depth = 1;
490 InArg = 1;
491 token[0] = 0;
492 while (maxtoken > 0) {
493 while ((ch = SCTxtFindNextANToken( fin, mtoken, MAX_TOKEN, &nsp )) ==
494 EOF) {
495 if (DebugCommands)
496 fprintf( stdout, "EOF in TeXGetGenArg while reading arg.\n" );
497 /* This is almost certainly an error */
498 fprintf( stdout, "EOF while reading an argument in file %s[%d]\n",
499 InFName[curfile], LineNo[curfile] );
500 if (CmdName[0])
501 fprintf( stdout, "In command %s\n", CmdName );
502 TXPopFile();
503 }
504 if (DebugArgs) {
505 fprintf( stdout, "ARG(%d):%s\n", GetArgDepth, mtoken );
506 }
507 for (i=0; i<nsp; i++) token[i] = ' ';
508 token += nsp;
509 maxtoken -= nsp;
510 /* We must correctly process enter and leave groups. Note that since
511 we may be looking for [] instead of {}, we defer the testing for
512 {} to the end */
513 if (ch == ec) {
514 depth--;
515 if (depth == 0) break;
516 if (!doeval) {
517 *token++ = ec;
518 maxtoken--;
519 }
520 }
521 else if (ch == sc) {
522 depth++;
523 if (!doeval) {
524 *token++ = sc;
525 maxtoken--;
526 }
527 }
528 /* Skip comments 2/11/97 */
529 else if (ch == CommentChar) {
530 SCTxtDiscardToEndOfLine( fin );
531 LineNo[curfile]++;
532 continue;
533 }
534 else if (mtoken[0] == '\\') {
535 TeXReadMacroName( mtoken );
536 if (DebugArgs)
537 fprintf( stdout, "ARGcmd(%d):\\%s\n", GetArgDepth, mtoken );
538 /* DONT REPROCESS RTF commands */
539 /* NEEDS TO BE CHANGED FOR HTML */
540 if (0) {
541 }
542 else {
543 if (doeval) {
544 #ifndef FOO
545 ArgBuffer = local_buf;
546 TeXProcessCommand( mtoken, fin, (FILE *)0 );
547 ArgBuffer = local_buf;
548 SCPushToken( local_buf );
549 local_buf[0] = 0;
550 InArg = 1;
551 #else
552 /* I think that this should allocate a new buffer
553 for args, then push the evaluation of that
554 back onto the stack ... */
555 /* ArgBuffer = local_buf; */
556 char *tmpbuf;
557 ALLOC_TOKEN(tmpbuf)
558 tmpbuf[0] = 0;
559 ArgBuffer = tmpbuf;
560 TeXProcessCommand( mtoken, fin, (FILE *)0 );
561 ArgBuffer = local_buf;
562 /* I'm not sure about this either. It is really
563 time to redesign the code.... */
564 SCPushToken( tmpbuf );
565 /* SCPushToken( local_buf ); */
566 local_buf[0] = 0;
567 /* FREE(tmpbuf); */
568 FREE_TOKEN;
569 InArg = 1;
570 #endif
571 }
572 else {
573 *token++ = '\\';
574 maxtoken--;
575 strcpy( token, mtoken );
576 token += strlen( mtoken );
577 maxtoken -= strlen( mtoken );
578 }
579 }
580 }
581 else {
582 if (DebugArgs)
583 fprintf( stdout, "->ARG(%d):%s\n", GetArgDepth, mtoken );
584 strcpy( token, mtoken );
585 token += strlen( mtoken );
586 maxtoken -= strlen( mtoken );
587 }
588
589 if (ch == RbraceChar) {
590 /* In case any output is generated... */
591 save_buf2 = ArgBuffer;
592 ArgBuffer = local_buf;
593 local_buf[0] = 0;
594 TXegroup( &E );
595 SCPushToken( local_buf );
596 local_buf[0] = 0;
597 ArgBuffer = save_buf2;
598 }
599 else if (ch == LbraceChar)
600 TXbgroup( &E );
601 }
602 token[0] = 0;
603 InArg = oldinarg;
604 }
605 else {
606 SCPushToken( token );
607 token[0] = 0;
608 }
609 FREE_TOKEN(local_buf);
610 /* mem_stack_sp--; */
611 /*FREE( local_buf );*/
612 ArgBuffer = save_buf;
613 if (maxtoken <= 0) {
614 if (maxtoken < 0)
615 fprintf( stderr, "token size exceeded by %d\n", -maxtoken );
616 fprintf( stderr, "Argument too long in file %s line %d; aborting\n",
617 InFName[curfile] ? InFName[curfile]: "<input>", LineNo[curfile] );
618 if (strlen(tf) < 80) {
619 fprintf( stderr, "Token(%d) was %s\n", mf, tf );
620 }
621 else {
622 fprintf( stderr, "Token(%d) was %.40s...%40s\n", mf, tf, tf );
623 }
624 found = -1;
625 /* exit(1); */
626 }
627 if (DebugArgs && found) {
628 fprintf( stdout, "ARG-end:arg is |" );
629 TXPrintToken( stdout, tf );
630 fprintf( stdout, "|\n" );
631 }
632 /* else just use the single token */
633 GetArgDepth--;
634 return found;
635 }
636
637 /* Get a TeX argument */
TeXGetArg(FILE * fin,char * token,int maxtoken)638 int TeXGetArg( FILE *fin, char *token, int maxtoken )
639 {
640 int rc = TeXGetGenArg( fin, token, maxtoken, LbraceChar, RbraceChar, 1 );
641 if (rc < 0) {
642 fprintf( stdout, "Error getting argument\n" );
643 }
644 return rc;
645 }
646
647 /* This is a version of TeXGetArg that aborts on failure */
TeXMustGetArg(FILE * fin,char * token,int maxtoken,char * caller,char * texcmd)648 void TeXMustGetArg( FILE *fin, char *token, int maxtoken,
649 char *caller, char *texcmd )
650 {
651 if (TeXGetGenArg( fin, token, maxtoken, LbraceChar, RbraceChar, 1 ) < 0) {
652 TeXAbort( caller, texcmd );
653 }
654 }
655
TXnop(TeXEntry * e)656 void TXnop( TeXEntry *e )
657 {
658 int i;
659
660 /* Tex command that has no effect in RTF file */
661 if (DebugCommands)
662 fprintf( stdout, "Skipping %d arguments for %s\n", e->nargs, e->name );
663 /* Don't bother to evaluate arguments that we are skipping */
664 PUSHCURTOK;
665 for (i=0; i<e->nargs; i++) {
666 if (TeXGetGenArg( fpin[curfile], curtok, MAX_TOKEN,
667 LbraceChar, RbraceChar, 0 ) == -1) {
668 TeXAbort( "TXnop", e->name );
669 }
670 }
671 POPCURTOK;
672 }
673
674 /* Copy a string and return it in newly allocated memory */
TXCopy(char * s)675 char *TXCopy( char *s )
676 {
677 char *n;
678 n = MALLOC( strlen( s ) + 1 );
679 strcpy( n, s );
680 return n;
681 }
682
683 /* Place the argument in the location stored in the ctx */
TXsavearg(TeXEntry * e)684 void TXsavearg( TeXEntry *e )
685 {
686 PUSHCURTOK;
687 strncpy( CmdName, e->name, sizeof(CmdName)-1 );
688 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXsavearg", e->name );
689 strcpy( (char *)(e->ctx), curtok );
690 CmdName[0] = 0;
691 POPCURTOK;
692 }
693
694 /* Replace \name with a string */
TXname(TeXEntry * e)695 void TXname( TeXEntry *e )
696 {
697 if (!InDocument) return;
698 TeXoutstr( fpout, (char *)(e->ctx) );
699 }
700
701 /* Output raw HTML (or RTF) */
TXraw(TeXEntry * e)702 void TXraw( TeXEntry *e )
703 {
704 if (!InDocument) return;
705 TeXoutcmd( fpout, (char *)(e->ctx) );
706 }
707
TXcomment(TeXEntry * e)708 void TXcomment( TeXEntry *e )
709 {
710 SCTxtDiscardToEndOfLine( fpin[curfile] );
711 LineNo[curfile]++;
712 }
713
714 /* Do \char`\\ */
TXchar(TeXEntry * e)715 void TXchar( TeXEntry *e )
716 {
717 int ch, nsp;
718
719 PUSHCURTOK;
720 ch = SCTxtFindNextANToken( fpin[curfile], curtok, MAX_TOKEN, &nsp );
721 if (ch == EOF) return;
722 if (ch == '`') {
723 ch = TeXReadToken( curtok, &nsp );
724 TeXoutstr( fpout, curtok );
725 }
726 else
727 TeXoutstr( fpout, curtok );
728 POPCURTOK;
729 }
730
731 /* Remove a LaTeX [...]. Leave the token in "token"; if there is
732 no [], set token[0] to 0 */
TXRemoveOptionalArg(char * token)733 void TXRemoveOptionalArg( char *token )
734 {
735 int ch;
736 int nsp;
737
738 token[0] = 0;
739 ch = SCTxtFindNextANToken( fpin[curfile], token, MAX_TOKEN, &nsp );
740 SCPushToken( token );
741 if (ch == '[') {
742 /* Strip the token */
743 if (TeXGetGenArg( fpin[curfile], token, MAX_TOKEN, '[', ']', 0 ) == -1)
744 TeXAbort( "TXRemoveOptionalArg", (char *)0 );
745 }
746 else
747 token[0] = 0;
748 }
749
750 /* Remove a LaTeX * (as in \vspace*{3in}) */
TXRemoveOptionalStar(char * token)751 void TXRemoveOptionalStar( char *token )
752 {
753 int ch;
754 int nsp;
755
756 token[0] = 0;
757 ch = SCTxtFindNextANToken( fpin[curfile], token, MAX_TOKEN, &nsp );
758 if (ch != '*')
759 SCPushToken( token );
760 }
761
762 /* This is nop, but after removing any optional * */
TXnopStar(TeXEntry * e)763 void TXnopStar( TeXEntry *e )
764 {
765 PUSHCURTOK;
766 TXRemoveOptionalStar( curtok );
767 POPCURTOK;
768 TXnop( e );
769 }
770
771 /* the \\ can have the form \\[dimen] for adding space; this
772 routine eats the [...] */
TXdoublebw(TeXEntry * e)773 void TXdoublebw( TeXEntry *e )
774 {
775 PUSHCURTOK;
776 TXRemoveOptionalArg( curtok );
777 POPCURTOK;
778 if (HandleAlign && lstack[lSp].env == TXTABULAR)
779 TeXEndHalignRow();
780 else
781 TXbw2( e );
782 }
783
TXnewline(TeXEntry * e)784 void TXnewline( TeXEntry *e )
785 {
786 PUSHCURTOK;
787 TXRemoveOptionalArg( curtok );
788 POPCURTOK;
789 TXbw2( e );
790 }
791 /* generate the date. Probably not in the expected format */
TXtoday(TeXEntry * e)792 void TXtoday( TeXEntry *e )
793 {
794 char date[100];
795 SYGetDate( date );
796 SCPushToken( date );
797 }
798
799 /* For ref to work, we need to install the \label defines in a label table */
TXref(TeXEntry * e)800 void TXref( TeXEntry *e )
801 {
802 int refnumber = 0;
803 char *refname;
804 char fname[256];
805 char lfname[256];
806
807 if (DebugCommands)
808 fprintf( stdout, "Getting argument for %s\n", e->name );
809 PUSHCURTOK;
810 strcmp( CmdName, "ref" );
811 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXref", e->name );
812 if (!InDocument) {
813 POPCURTOK;
814 return;
815 }
816 ReplaceWhite( curtok );
817 /* Match name to section and generate node reference */
818 refname = LabelLookup( curtok, &refnumber, fname );
819
820 if (refname) {
821 if (refnumber >= 0) {
822 if (fname)
823 snprintf( lfname, sizeof(lfname), "%s#Node", fname );
824 else
825 strncpy( lfname, "Node", sizeof(lfname) );
826 WritePointerText( fpout, refname, lfname, refnumber );
827 }
828 else {
829 WritePointerText( fpout, refname, fname, refnumber );
830 }
831 }
832 else
833 fprintf( stderr, "\\ref{%s} unknown (%s line %d)\n",
834 curtok,
835 InFName[curfile] ? InFName[curfile]: "",
836 LineNo[curfile] );
837 POPCURTOK;
838 CmdName[0] = 0;
839 }
840
841 /*
842 A label within an equation, table, or figure should be treated
843 differently. In particular, for cases where we use an image file for
844 the equation etc, we really need to place a new anchor and node number
845 around the equation etc.
846
847 Note that the anchor need only be around a small part;
848 also, we could ALWAYS place the anchor and only use it as required.
849 */
TXlabel(TeXEntry * e)850 void TXlabel( TeXEntry *e )
851 {
852 if (DebugCommands)
853 fprintf( stdout, "Getting argument for %s\n", e->name );
854 PUSHCURTOK;
855 strcpy( CmdName, "label" );
856 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXlabel", e->name );
857 /* goken in ref refers to the value of LabelName */
858 ReplaceWhite( curtok );
859
860 /* Originally, the value of the label was just the section that contained
861 the label. This gave both poor label names and rather imprecise
862 location to a reference */
863 if (NumberedEnvironmentType == ENV_NONE)
864 WriteLabeltoauxfile( CurSeqnum-1, outfile, curtok, CurNodename );
865 else {
866 char buf[10];
867 if (!envjumpname || !envjumpname[0]) {
868 fprintf( ferr,
869 "Label %s occurs in an unexpected environment at %s, line %d\n",
870 curtok, InFName[curfile], LineNo[curfile] );
871 POPCURTOK;
872 return;
873 }
874 snprintf( buf, sizeof(buf), "%d", envJumpNum );
875 WriteLabeltoauxfile( -1, envjumpname, curtok, buf );
876 }
877 POPCURTOK;
878 CmdName[0] = 0;
879 }
880
881 /* Just use the section names as the reference */
TXhref(TeXEntry * e)882 void TXhref( TeXEntry *e )
883 {
884 LINK *RefedSection;
885 int dummy;
886 char lfname[256];
887 char *topicfile;
888
889 if (!InDocument) return;
890 strcpy( CmdName, "href" );
891 if (DebugCommands)
892 fprintf( stdout, "Getting argument for %s\n", e->name );
893 PUSHCURTOK;
894 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "THhref", e->name );
895 ReplaceWhite( curtok );
896 RefedSection = SRLookup( topicctx, curtok, (char *)0, &dummy );
897 if (!RefedSection) {
898 fprintf( stderr, "Could not find %s in topicctx\n", curtok );
899 POPCURTOK;
900 return;
901 }
902 topicfile = TopicFilename( RefedSection );
903 if (topicfile)
904 snprintf( lfname, sizeof(lfname), "%s#Node", topicfile );
905 else
906 strncpy( lfname, "Node", sizeof(lfname) );
907 WritePointerText( fpout, curtok, lfname, RefedSection->number );
908 /* \hrefa has a second argument that is used in the LaTeX version as the
909 replacement text */
910 if (e->nargs > 1) {
911 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXhref", e->name );
912 }
913 POPCURTOK;
914 CmdName[0] = 0;
915 }
916
TXmore(TeXEntry * e)917 void TXmore( TeXEntry *e )
918 {
919 TeXoutstr( fpout, " (Press " );
920 TXref( e );
921 TeXoutstr( fpout, " for more information)\n" );
922 }
923
924 /*
925 * This is ugly, but there are several places where comment characters are used
926 * We should really combine them
927 */
928 #define MAX_COMMENT_DEPTH 25
929 static char SavedCommentChar[MAX_COMMENT_DEPTH];
930 static char SavedCommentChar2[MAX_COMMENT_DEPTH];
931 static int comment_depth=0;
PushCommentChar(char new_c)932 void PushCommentChar( char new_c )
933 {
934 SavedCommentChar[comment_depth] = CommentChar;
935 SavedCommentChar2[comment_depth++] = SCGetCommentChar();
936 CommentChar = new_c;
937 SCSetCommentChar( new_c );
938 }
PopCommentChar(void)939 void PopCommentChar( void )
940 {
941 CommentChar = SavedCommentChar[--comment_depth];
942 SCSetCommentChar( SavedCommentChar2[comment_depth] );
943 }
944
TXcode(TeXEntry * e)945 void TXcode( TeXEntry *e )
946 {
947 /* output in "code" font */
948 if (!InDocument) return;
949 strcpy( CmdName, "code" );
950 if (DebugCommands)
951 fprintf( stdout, "Getting argument for %s\n", e->name );
952 PUSHCURTOK;
953 /* We must allow comments (any arbitrary character) */
954 PushCommentChar( '\0' );
955 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXcode", e->name );
956 PopCommentChar();
957 TXbgroup( e );
958 TXfont_tt( e );
959 TeXoutstr( fpout, curtok );
960 TXegroup( e );
961 POPCURTOK;
962 CmdName[0] = 0;
963 }
964
TXroutine(TeXEntry * e)965 void TXroutine( TeXEntry *e )
966 {
967 /* output in "code" font */
968 if (!InDocument) return;
969 strcpy( CmdName, "routine" );
970 if (DebugCommands)
971 fprintf( stdout, "Getting argument for %s\n", e->name );
972 PUSHCURTOK;
973 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXroutine", e->name );
974 AddToIndex( curtok, CurNodename, CurSeqnum - 1, 0 );
975 TXbgroup( e );
976 TXfont_tt( e );
977 TeXoutstr( fpout, curtok );
978 TXegroup( e );
979 POPCURTOK;
980 CmdName[0] = 0;
981 }
982
TXdfn(TeXEntry * e)983 void TXdfn( TeXEntry *e )
984 {
985 /* output in "definition" font */
986 if (!InDocument) return;
987 if (DebugCommands)
988 fprintf( stdout, "Getting argument for %s\n", e->name );
989 PUSHCURTOK;
990 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXdfn", e->name );
991 TXbgroup( e );
992 TXem( e );
993 TeXoutstr( fpout, curtok );
994 TXegroup( e );
995 POPCURTOK;
996 }
997
TXvar(TeXEntry * e)998 void TXvar( TeXEntry *e )
999 {
1000 /* output in "var" font */
1001 if (!InDocument) return;
1002 if (DebugCommands)
1003 fprintf( stdout, "Getting argument for %s\n", e->name );
1004 PUSHCURTOK;
1005 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXvar", e->name );
1006 TXbgroup( e );
1007 TXem( e );
1008 TeXoutstr( fpout, curtok );
1009 TXegroup( e );
1010 POPCURTOK;
1011 }
1012
TXfile(TeXEntry * e)1013 void TXfile( TeXEntry *e )
1014 {
1015 /* output in "file" font */
1016 if (!InDocument) return;
1017 if (DebugCommands)
1018 fprintf( stdout, "Getting argument for %s\n", e->name );
1019 PUSHCURTOK;
1020 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXfile", e->name );
1021 TXbgroup( e );
1022 TXfont_ss( e );
1023 TeXoutstr( fpout, curtok );
1024 TXegroup( e );
1025 POPCURTOK;
1026 }
1027
TXatletter(TeXEntry * e)1028 void TXatletter( TeXEntry *e )
1029 {
1030 SCSetAtLetter( 1 );
1031 }
1032
TXatother(TeXEntry * e)1033 void TXatother( TeXEntry *e )
1034 {
1035 SCSetAtLetter( 0 );
1036 }
1037
1038 static char asistoken[MAX_TOKEN];
TXasis(e)1039 void TXasis( e )
1040 TeXEntry *e;
1041 {
1042 int i;
1043
1044 if (DebugCommands)
1045 fprintf( stdout, "Getting %d arguments for %s\n", e->nargs, e->name );
1046 for (i=0; i<e->nargs; i++) {
1047 if (TeXGetArg( fpin[curfile], asistoken, MAX_TOKEN ) == -1) {
1048 fprintf( stdout, "Failed to get argument for %s\n", e->name );
1049 TeXAbort( "TXasis", e->name );
1050 }
1051 if (InDocument)
1052 TeXoutstr( fpout, asistoken );
1053 }
1054 }
1055
1056 /* This is "as-is", but with a surrounding group
1057 */
TXasisGrouped(TeXEntry * e)1058 void TXasisGrouped( TeXEntry *e )
1059 {
1060 int i;
1061
1062 TXbgroup( e );
1063 if (DebugCommands)
1064 fprintf( stdout, "Getting %d arguments for %s\n", e->nargs, e->name );
1065 strncpy( CmdName, e->name, sizeof(CmdName)-1 );
1066 for (i=0; i<e->nargs; i++) {
1067 if (TeXGetArg( fpin[curfile], asistoken, MAX_TOKEN ) == -1) {
1068 fprintf( stdout, "Failed to get argument for %s\n", e->name );
1069 TeXAbort( "TXasisGrouped", e->name );
1070 }
1071 if (InDocument) {
1072 TeXoutstr( fpout, asistoken );
1073 }
1074 }
1075 TXegroup( e );
1076 CmdName[0] = 0;
1077 }
1078
1079 /* This is like asis, but handles the "to <dimension>", which may be \hsize */
TXbox(TeXEntry * e)1080 void TXbox( TeXEntry *e )
1081 {
1082 int i, nsp, ch;
1083
1084 ch = SCTxtFindNextANToken( fpin[curfile], asistoken, MAX_TOKEN, &nsp );
1085 if (ch == EOF) return;
1086 if (strcmp( asistoken, "to" ) == 0) {
1087 /* Very simple-minded: look for \name or <value><scale> */
1088 ch = TeXReadToken( asistoken, &nsp );
1089 if (ch != '\\') {
1090 SCPushToken( asistoken );
1091 TXReadDimen( fpin[curfile] );
1092 }
1093 }
1094 else
1095 SCPushToken( asistoken );
1096
1097 TXbgroup( e );
1098 if (DebugCommands)
1099 fprintf( stdout, "Getting %d arguments for %s\n", e->nargs, e->name );
1100 strncpy( CmdName, e->name, sizeof(CmdName)-1 );
1101 for (i=0; i<e->nargs; i++) {
1102 if (TeXGetArg( fpin[curfile], asistoken, MAX_TOKEN ) == -1) {
1103 fprintf( stdout, "Failed to get argument for %s\n", e->name );
1104 TeXAbort( "TXbox", e->name );
1105 }
1106 if (InDocument)
1107 TeXoutstr( fpout, asistoken );
1108 }
1109 TXegroup( e );
1110 CmdName[0] = 0;
1111 }
1112
1113 /* Handle \input and \include commands */
1114 /*
1115 Problem. The TeX \input does not require an argument; you
1116 can use \input filename. Need to check for that case and add it
1117 to the list of 'predoc' commands
1118 */
TXinclude(TeXEntry * e)1119 void TXinclude( TeXEntry *e )
1120 {
1121 char *p;
1122 int ch;
1123 if (DebugCommands)
1124 fprintf( stdout, "Getting argument for %s\n", e->name );
1125 PUSHCURTOK;
1126 curtok[0] = 0;
1127 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXinclude", e->name );
1128 if (strlen(curtok) == 0) {
1129 /* Get next space-delimited token that is not a right brace*/
1130 /* (What are the rules on input?) */
1131 while ((ch = SCTxtGetChar( fpin[curfile] )) != -1 &&
1132 isspace(ch) && ch != '\n' && ch != RbraceChar);
1133 p = curtok;
1134 *p++ = ch;
1135 while ((ch = SCTxtGetChar( fpin[curfile] )) != -1 && !isspace(ch)
1136 && ch != RbraceChar)
1137 *p++ = ch;
1138 *p = 0;
1139 /* We still need to EVALUATE any TeX commands in this string !!! */
1140 /* Need a command to evaluate a buffer */
1141 /* We cheat by pushing back { curtok } and making getarg to all
1142 of the work */
1143 SCPushChar( RbraceChar );
1144 SCPushToken( curtok );
1145 SCPushChar( LbraceChar );
1146 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN,
1147 "TXinclude", e->name );
1148 }
1149 if (DebugCommands || DebugFile)
1150 fprintf( stdout, "About to open |%s|\n", curtok );
1151
1152 if (!InDocument) {
1153 /* fprintf( stderr, "\\include{%s}\n", curtok ); */
1154 strcat( predoc, "\\include{" );
1155 strcat( predoc, curtok );
1156 strcat( predoc, "}\n" );
1157 }
1158 /* Catch the case where a file hasn't been closed */
1159 if (fpin[curfile+1]) fclose( fpin[curfile+1] );
1160
1161 /* In some cases, particularly complex macro files used in Books,
1162 we may want to skip reading an include file, instead relying on
1163 customized defintions provide through a definitions file. Without
1164 this, we'd have to implement the most complex parts of TeX, including
1165 catcode changes, expandafter, etc. This include file name is
1166 specified in a defs file using the skipinclude command */
1167 if (TXIsSkipFile( curtok )) {
1168 POPCURTOK;
1169 return;
1170 }
1171 /* Check for a replacemtn file name */
1172 {
1173 char newtok[MAX_TOKEN];
1174 if (TXIsReplaceFile( curtok, newtok )) {
1175 strcpy( curtok, newtok );
1176 }
1177 }
1178
1179 /* Push this file and process it */
1180 fpin[++curfile] = fopen( curtok, "r" );
1181 if (!fpin[curfile]) {
1182 strcat( curtok, ".tex" );
1183 fpin[curfile] = fopen( curtok, "r" );
1184 if (!fpin[curfile]) {
1185 curfile--;
1186 fprintf( stderr, "(TXinclude) Could not open file %s\n", curtok );
1187 POPCURTOK;;
1188 return;
1189 }
1190 }
1191 InFName[curfile] = STRDUP( curtok );
1192 CHKPTR(InFName[curfile]);
1193 LineNo[curfile] = 1; /* Line numbers are 1-origin */
1194 POPCURTOK;
1195 }
1196
TXPopFile(void)1197 void TXPopFile( void )
1198 {
1199 if (DebugCommands) {
1200 fprintf( stdout, "Popping file from stack!\n" );
1201 }
1202 if (InFName[curfile]) {
1203 FREE( InFName[curfile] );
1204 }
1205 curfile--;
1206 if (curfile < 0) {
1207 fprintf( stderr, "EOF in input; aborting\n" );
1208 fprintf( stderr,
1209 "(Reached an end-of-file in the top-level file without an \\end{document})\n" );
1210 exit(1);
1211 }
1212 }
1213
1214 /* ----------------------------------------------------------------------- */
1215 /*
1216 This implements my \fileinclude{filename} macro which includes the
1217 entire contents of filename in verbatim form
1218 */
TXfileinclude(TeXEntry * e)1219 void TXfileinclude( TeXEntry *e )
1220 {
1221 char line[257];
1222 FILE *fp;
1223
1224 if (DebugCommands)
1225 fprintf( stdout, "Getting argument for %s\n", e->name );
1226 PUSHCURTOK;
1227 curtok[0] = 0;
1228 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN,
1229 "TXfileinclude", e->name );
1230 if (DebugCommands || DebugFile)
1231 fprintf( stdout, "About to open |%s|\n", curtok );
1232
1233 fp = fopen( curtok, "r" );
1234 if (!fp) {
1235 fprintf( stderr, "(TXfileinclude) Could not open file %s\n", curtok );
1236 POPCURTOK;
1237 return;
1238 }
1239 /* Start of verbatim output */
1240 TXWriteStartNewLine( fpout );
1241 TXpreformated( fpout, 1 );
1242 TXbgroup( e );
1243 TXfont_tt( e );
1244
1245 /* We'd like to map tokens here as well */
1246 while (fgets( line, sizeof(line)-1, fp )) {
1247 if (ProcessManPageTokens)
1248 /* Eventually used WriteString(fpout,...) */
1249 TXoutactiveToken( line );
1250 else
1251 WriteString( fpout, line );
1252
1253 /* WriteStringRaw( fpout, line ); */
1254 }
1255 /* End of verbatim output */
1256 TXegroup( e );
1257 TXpreformated( fpout, 0 );
1258 fclose( fp );
1259 POPCURTOK;
1260 }
1261 /*
1262 TXIfFileExists - Implement the LaTeX command:
1263 if file #1 exists, do #2 else do #3
1264
1265 This routine may not be nested.
1266 */
TXIfFileExists(TeXEntry * e)1267 void TXIfFileExists( TeXEntry *e )
1268 {
1269 FILE *fp;
1270
1271 if (DebugCommands)
1272 fprintf( stdout, "Getting argument for %s\n", e->name );
1273 PUSHCURTOK;
1274 curtok[0] = 0;
1275 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN,
1276 "TXIfFileExists", e->name );
1277 if (DebugCommands || DebugFile)
1278 fprintf( stdout, "Attempting to open file %s\n", curtok );
1279 fp = fopen( curtok, "r" );
1280 /* We need to read these args *but not evaluate them* until after
1281 they are pushed back */
1282 if (fp) {
1283 char savetok[MAX_TOKEN];
1284 fclose( fp );
1285 /* Use genarg because we want to suppress evaluation */
1286 if (TeXGetGenArg( fpin[curfile], savetok, MAX_TOKEN,
1287 LbraceChar, RbraceChar, 0 ) < 0)
1288 TeXAbort( "TXIfFileExists", e->name );
1289 if (TeXGetGenArg( fpin[curfile], curtok, MAX_TOKEN,
1290 LbraceChar, RbraceChar, 0 ) < 0)
1291 TeXAbort( "TXIfFileExists", e->name );
1292 /* Push back the second token */
1293 SCPushToken( savetok );
1294 }
1295 else {
1296 if (TeXGetGenArg( fpin[curfile], curtok, MAX_TOKEN,
1297 LbraceChar, RbraceChar, 0 ) < 0)
1298 TeXAbort( "TXIfFileExists", e->name );
1299 if (TeXGetGenArg( fpin[curfile], curtok, MAX_TOKEN,
1300 LbraceChar, RbraceChar, 0 ) < 0)
1301 TeXAbort( "TXIfFileExists", e->name );
1302 /* Push back the third token */
1303 SCPushToken( curtok );
1304 }
1305 POPCURTOK;
1306 }
1307
1308 static LINK *LastSection = 0;
1309 int splitlevel = -1;
1310 char splitdir[256];
1311
TXSetSplitLevel(int sl,char * dir)1312 void TXSetSplitLevel( int sl, char *dir )
1313 {
1314 splitlevel = sl;
1315 if (strlen(dir) > sizeof(splitdir) - 1) {
1316 TeXAbort( "TXSetSplitLevel", "directory name too long" );
1317 }
1318 strncpy( splitdir, dir, sizeof(splitdir) );
1319 }
1320
1321 /*
1322 Generate the output for a new section; may start by generating the contents
1323 table for the previous section.
1324
1325 In order to generate the "correct" navigation links, we use the "next"
1326 links created when the contents aux (.hux file) were read in.
1327 To do this, we keep track of where we were in that list with a local
1328 variable LastSection.
1329
1330 */
TXsection(TeXEntry * e)1331 void TXsection( TeXEntry *e )
1332 {
1333 int level = (int)(PTRINT)(e->ctx), ch;
1334 int dummy;
1335 char *p;
1336 int isUnnumbered = 0;
1337
1338 TeXWriteContents( fpout );
1339
1340 if (level < MinSectionKind) MinSectionKind = level;
1341
1342 /* Must put a marker at the END of each section */
1343 if (CurSeqnum > 0) {
1344 /* Before we do this, we'd like to add the jump lines for the subsections.
1345 We can get this information from the aux file (but not now, since
1346 we've started writing the new one). */
1347 if (LastSection) {
1348 if (NumChildren( LastSection ) > 0) {
1349 WriteChildren( fpout, LastSection, -1 );
1350 }
1351 }
1352 WriteEndofTopic( fpout );
1353 /* Add the buttons at the bottom of the section if requested
1354 (tohtml only) */
1355 if (DestIsHtml) {
1356 /* fputs( "\n<P><HR>\n", fpout ); */
1357 WriteSectionButtonsBottom( fpout, CurNodename, LastSection );
1358 }
1359 }
1360
1361 /* First, check for a *. discard if seen */
1362 ch = SCTxtGetChar( fpin[curfile] );
1363 /* FIXME: If an asterisk, the section is neither numbered nor
1364 updates the section number. */
1365 if (ch == '*')
1366 isUnnumbered = 1;
1367 else
1368 SCPushChar( ch );
1369
1370 /* Start a new section (at several levels) */
1371 /* Pop section stack if this item is at same level or lower */
1372 if (SSp >= 0 && sstack[SSp].level == level) {
1373 if (!isUnnumbered)
1374 sstack[SSp].count ++;
1375 }
1376 else {
1377 if (SSp >= 0 && sstack[SSp].level >= level) {
1378 /* Move up in heirarchy */
1379 while (SSp >= 0 && sstack[SSp].level >= level ) SSp--;
1380 SSp++;
1381 if (!isUnnumbered)
1382 sstack[SSp].count++;
1383 }
1384 else {
1385 /* Move down */
1386 SSp++;
1387 sstack[SSp].level = level;
1388 sstack[SSp].count = 1;
1389 }
1390 }
1391
1392 /* First, check for a *. discard if seen */
1393 ch = SCTxtGetChar( fpin[curfile] );
1394 /* FIXME: If an asterisk, the section is neither numbered nor
1395 updates the section number. */
1396 if (ch == '*')
1397 isUnnumbered = 1;
1398 else
1399 SCPushChar( ch );
1400
1401 if (DebugCommands)
1402 fprintf( stdout, "Getting argument for %s\n", e->name );
1403 PUSHCURTOK;
1404 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN,
1405 "TXsection(arg)", e->name );
1406 /* Remove any leading blanks */
1407 if (curtok[0] == ' ') {
1408 char *p = curtok;
1409 char *p1 = curtok;
1410 /* Find the first nonblank */
1411 while (*p == ' ') p++;
1412 /* Move the first nonblank over, and then copy the rest of the string */
1413 while (*p != 0) *p1++ = *p++;
1414 *p1 = 0;
1415 }
1416 /* Remove any trailing blanks */
1417 p = curtok + strlen(curtok) - 1;
1418 if (*p == ' ') {
1419 while (p > curtok && *p == ' ') p--;
1420 *++p = 0;
1421 }
1422 strncpy( CurNodename, curtok, sizeof(CurNodename) - 1 );
1423
1424 /* Write out section numbers in the "natural way" */
1425 if (IncludeSectionNumbers && !isUnnumbered) {
1426 int i;
1427 for (i=0; i<=SSp; i++) fprintf( stdout, "%d.", sstack[i].count );
1428 fprintf( stdout, " %s\n", CurNodename );
1429 }
1430
1431 if (level <= splitlevel) {
1432 /* Need to close current file and open new file. */
1433 /* New file name is directory/node#.html */
1434 if (fpout) {
1435 WriteEndPage( fpout );
1436 }
1437 if (!outfile) {
1438 outfile = (char *)MALLOC( OUTFILE_SIZE );
1439 CHKPTR(outfile);
1440 }
1441 snprintf( outfile, OUTFILE_SIZE, "%s%cnode%d.%s",
1442 splitdir, DirSep, CurSeqnum, HTML_Suffix );
1443 fclose( fpout );
1444 fpout = fopen( outfile, "w" );
1445 if (!fpout) {
1446 fprintf( ferr, "(TXsection) Could not open file %s\n", outfile );
1447 TeXAbort( "TXsection(file)", (char *)0 );
1448 }
1449 /* We use the local name (in the directory) for all references */
1450 snprintf( outfile, OUTFILE_SIZE, "node%d.%s", CurSeqnum, HTML_Suffix );
1451 WriteHeadPage( fpout );
1452 WriteFileTitle( fpout, curtok );
1453 WriteBeginPage( fpout );
1454 }
1455 ReplaceWhite( curtok );
1456 WRtoauxfile( CurSeqnum++, outfile, level, curtok );
1457
1458 /* FIXME: Why the if (1)? */
1459 if (1) {
1460 LastSection = GetNextLink( LastSection );
1461 /* Check that this matches the name */
1462 if (LastSection && strcmp(LastSection->topicname,curtok) != 0) {
1463 fprintf( stderr, "**Mismatch in section; expected \"%s\" found \"%s\"\n",
1464 curtok, LastSection->topicname );
1465 }
1466 }
1467 else {
1468 /* Lookup the section in the aux file list */
1469 LastSection = SRLookup( topicctx, curtok, (char *)0, &dummy );
1470 if (!LastSection) {
1471 fprintf( stderr, "**Could not find %s in topicctx\n", curtok );
1472 }
1473 }
1474
1475 /* Output section headers */
1476 if (IncludeSectionNumbers && !isUnnumbered) {
1477 char tmptok[MAX_TOKEN], *p;
1478 int i;
1479 p = tmptok;
1480 for (i=0; i<=SSp; i++) {
1481 sprintf( p, "%d.", sstack[i].count );
1482 p += strlen(p);
1483 }
1484 strcat( p, " " );
1485 strcat( p, curtok );
1486 WriteSectionAnchor( fpout, tmptok, "Node", CurSeqnum-1,
1487 (int)(PTRINT)(e->ctx) );
1488 }
1489 else {
1490 WriteSectionAnchor( fpout, curtok, "Node", CurSeqnum-1,
1491 (int)(PTRINT)(e->ctx) );
1492 }
1493 WriteSectionButtons( fpout, curtok, LastSection );
1494
1495 /* These values (entrylevel, number) aren't correct */
1496 /* Write the section numbers by prefixing the section entry values */
1497 WriteSectionHeader( fpout, curtok, "Node", CurSeqnum-1, (char *)0,
1498 (int)(PTRINT)(e->ctx) );
1499 /* Insert tree links to parent, child, and sibling. Sets name for subsequent
1500 label statements */
1501 WriteTextHeader( fpout );
1502
1503 /* Skip any newlines until we find the first non-blank */
1504 SCSkipNewlines( fpin[curfile] );
1505 POPCURTOK;
1506 }
1507
1508 /*
1509 This is a special version of section for the first page (vtitle) of
1510 a set of slides.
1511 */
TXtitlesection(TeXEntry * e)1512 void TXtitlesection( TeXEntry *e )
1513 {
1514 int level = (int)(PTRINT)(e->ctx), ch;
1515 int dummy;
1516
1517 /* Start a new section (at several levels) */
1518 /* Pop section stack if this item is at same level or lower */
1519 while (SSp >= 0 && sstack[SSp].level >= level ) SSp--;
1520 SSp++;
1521 sstack[SSp].count = 1;
1522
1523 /* First, check for a *. discard if seen */
1524 ch = SCTxtGetChar( fpin[curfile] );
1525 if (ch != '*') SCPushChar( ch );
1526
1527 if (DebugCommands)
1528 fprintf( stdout, "Getting argument for %s\n", e->name );
1529 PUSHCURTOK;
1530 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXsection", (char *)0 );
1531 strncpy( CurNodename, curtok, sizeof(CurNodename) - 1 );
1532
1533 WriteHeadPage( fpout );
1534 WriteFileTitle( fpout, curtok );
1535 WriteBeginPage( fpout );
1536 ReplaceWhite( curtok );
1537 WRtoauxfile( CurSeqnum++, outfile, level, curtok );
1538
1539 /* Lookup the section in the aux file list */
1540 LastSection = SRLookup( topicctx, curtok, (char *)0, &dummy );
1541 if (!LastSection) {
1542 fprintf( stderr, "Could not find %s in topicctx\n", curtok );
1543 }
1544
1545 /* Output section headers */
1546 WriteSectionAnchor( fpout, curtok, "Node", CurSeqnum-1,
1547 (int)(PTRINT)(e->ctx) );
1548 WriteSectionButtons( fpout, curtok, LastSection );
1549
1550 /* These values (entrylevel, number) aren't correct */
1551 WriteSectionHeader( fpout, curtok, "Node", CurSeqnum-1, (char *)0,
1552 (int)(PTRINT)(e->ctx) );
1553
1554 /* Insert tree links to parent, child, and sibling. Sets name for subsequent
1555 label statements */
1556 WriteTextHeader( fpout );
1557
1558 /* Skip any newlines until we find the first non-blank */
1559 SCSkipNewlines( fpin[curfile] );
1560 TXWriteStartNewLine( fpout );
1561 POPCURTOK;
1562 }
1563
PrintLastSectionName(FILE * fp)1564 void PrintLastSectionName( FILE *fp )
1565 {
1566 if (LastSection)
1567 fprintf( fp, "%s\n", LastSection->topicname );
1568 else
1569 fprintf( fp, "<before first section>\n" );
1570 }
1571
1572 /* Paragraphs are a very restricted form of section */
TXparagraph(TeXEntry * e)1573 void TXparagraph( TeXEntry *e )
1574 {
1575 int ch;
1576
1577 /* First, check for a *. discard if seen */
1578 ch = SCTxtGetChar( fpin[curfile] );
1579 if (ch != '*') SCPushChar( ch );
1580
1581 if (DebugCommands)
1582 fprintf( stdout, "Getting argument for %s\n", e->name );
1583 PUSHCURTOK;
1584 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN,
1585 "TXparagraph(arg)", e->name );
1586
1587 /* Output a new paragraph */
1588 TXWritePar( fpout );
1589 /* Output the paragraph title. Font choice? */
1590 TeXoutstr( fpout, curtok );
1591 /* Output some space */
1592 TeXoutstr( fpout, " " );
1593 /* Skip any newlines until we find the first non-blank */
1594 SCSkipNewlines( fpin[curfile] );
1595 POPCURTOK;
1596 }
1597
1598
1599 /*
1600 \vtt is rather special. We want to start processing, but most of the
1601 code expects to see a \begin{document} ... \end{document}.
1602 */
TXvtt(TeXEntry * e)1603 void TXvtt( TeXEntry *e )
1604 {
1605 if (!InDocument) {
1606 TXStyleEPSF( TeXlist, fpin[curfile], fpout );
1607 TXStyleAnlhtext( TeXlist, fpin[curfile], fpout );
1608 InDocument = 1;
1609 TXStartDoc(1);
1610 TXtitlesection( e );
1611 TeXskipEnv( e, "_vtt", 1 );
1612 }
1613 else {
1614 TXsection( e );
1615 }
1616 }
TXvt(TeXEntry * e)1617 void TXvt( TeXEntry *e )
1618 {
1619 if (!InDocument) {
1620 TXStyleEPSF( TeXlist, fpin[curfile], fpout );
1621 TXStyleAnlhtext( TeXlist, fpin[curfile], fpout );
1622 InDocument = 1;
1623 TXStartDoc(1);
1624 TeXskipEnv( e, "_vtt", 1 );
1625 }
1626 }
TXdetails(TeXEntry * e)1627 void TXdetails( TeXEntry *e )
1628 {
1629 TeXoutstr( fpout, "(Press " );
1630 TXhref( e );
1631 TeXoutstr( fpout, " for details)" );
1632 }
1633
1634 /* ----------------------------------------------------------------------- */
1635 /* Code for long environments:
1636 iftex
1637 tex
1638 example
1639 verbatim
1640 */
1641
1642 /* Skip over an environment. If flag, write out text and process TeX command,
1643 otherwise, just skip */
TeXskipEnv(TeXEntry * e,char * name,int flag)1644 void TeXskipEnv( TeXEntry *e, char *name, int flag )
1645 {
1646 int nsp, ch;
1647 FILE *fout = fpout;
1648 int last_was_nl = 0;
1649 int last_skip = AmSkipping;
1650 char *btext, *etext;
1651 int nargs;
1652 int line_num = LineNo[curfile]; /* Line number where we start */
1653
1654 /* If we are here, we assume that we are in valid TeX. This is a
1655 temporary hack. What we'd like to do is wait until we see either
1656 a command that generates non-blank output or a section/chapter/part
1657 command */
1658 if (!InOutputBody) {
1659 if (DebugOutput) printf( "Starting a page in skipenv\n" );
1660 /* Start the page if we haven't already */
1661 WriteHeadPage( fpout );
1662 /* We don't have a good title. Use the input file name */
1663 WriteFileTitle( fpout, InFName[0] );
1664 /* WriteBeginPage sets InOutputBody to 1 */
1665 WriteBeginPage( fpout );
1666 /* In case we created a new file */
1667 fout = fpout;
1668 }
1669
1670 /* First, remove any newlines */
1671 if (strcmp( name, "verbatim" ) != 0 &&
1672 (!UsingLatexinfo || strcmp( name, "example" ) != 0)) {
1673 /* Preserve blanks before first non-blank character */
1674 SCSkipNewlines2( fpin[curfile] );
1675 }
1676
1677 /* Flush output at the beginning of each environment (makes debugging a
1678 little easier) */
1679 fflush( fpout );
1680 if (DebugCommands)
1681 fprintf( stdout, "Processing environment %s (skipenv)\n", name );
1682 AmSkipping = !flag;
1683 PUSHCURTOK;
1684 while (1) {
1685 while ( (ch =
1686 SCTxtFindNextANToken(fpin[curfile], curtok, MAX_TOKEN, &nsp )) == EOF) {
1687 if (DebugCommands)
1688 fprintf( stdout, "EOF in TeXskipEnv\n" );
1689 /* Special case for vtt */
1690 if (curfile == 0 && strcmp( name, "_vtt" ) == 0) {
1691 break;
1692 }
1693 TXPopFile();
1694 }
1695 if (ch == EOF) break;
1696 if (InVerbatim && ch == CommandChar) {
1697 last_was_nl = 0;
1698 TeXoutsp( fout, nsp );
1699 TeXReadMacroName( curtok );
1700 if (strcmp( curtok, "end" ) == 0) {
1701 if (DebugCommands)
1702 fprintf( stdout, "Getting argument for end{}\n" );
1703 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN,
1704 "TXSkipEnv", e->name );
1705 if (strcmp( name, curtok ) == 0) {
1706 /* We've found the end of the verbatim */
1707 break;
1708 }
1709 else {
1710 /* Ignore it */
1711 TeXoutstr( fout, "\\end{" );
1712 TeXoutstr( fout, curtok );
1713 TeXoutstr( fout, "}" );
1714 }
1715 }
1716 else {
1717 TeXoutstr( fout, "\\" );
1718 TeXoutstr( fout, curtok );
1719 }
1720 continue;
1721 }
1722
1723 if (InVerbatim) {
1724 TeXoutsp( fout, nsp );
1725 if (ch == '\n') {
1726 /* In preformatted output, we don't need any pars */
1727 TeXoutstr( fout, NewLineString );
1728 last_was_nl = 1;
1729 }
1730 else
1731 TeXoutstr( fout, curtok );
1732 }
1733 else {
1734 if (ch == CommentChar) {
1735 SCTxtDiscardToEndOfLine( fpin[curfile] );
1736 LineNo[curfile]++;
1737 continue;
1738 }
1739 if (ch == MathmodeChar && !UsingLatexinfo) {
1740 TeXoutsp( fout, nsp );
1741 TXProcessDollar( e, LatexMath, 1 );
1742 }
1743 else if (ch == AlignChar && HandleAlign &&
1744 lstack[lSp].env == TXTABULAR) {
1745 /* We want to be prepared to put an alignment command,
1746 but to support the \multicolumn command, we
1747 need to wait until we are sure that the next
1748 command is not \multicolumn. Not handled yet */
1749 TeXPutAlign();
1750 }
1751 else if (ch == CommandChar) {
1752 last_was_nl = 0;
1753 TeXoutsp( fout, nsp );
1754 TeXReadMacroName( curtok );
1755
1756 if (strcmp( curtok, "end" ) == 0) {
1757 if (DebugCommands)
1758 fprintf( stdout, "Getting argument for end{}\n" );
1759 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN,
1760 "TeXSkipEnv", e->name );
1761 if (LookupEnv( curtok, &btext, &etext, &nargs)) {
1762 if (etext) {
1763 if (DebugCommands)
1764 fprintf( stdout, "Pushing back |%s|\n", etext );
1765 SCPushToken( etext );
1766 }
1767 }
1768 else if (strcmp( curtok, name ) != 0) {
1769 if (flag)
1770 fprintf( ferr,
1771 "<skipEnv>%s does not match %s (started at line %d), at %s line %d\n",
1772 curtok, name, line_num,
1773 InFName[curfile] ? InFName[curfile]: "", LineNo[curfile] );
1774 }
1775 else
1776 break;
1777 }
1778 else {
1779 /* Need to process TeX command */
1780 if (flag) {
1781 TeXProcessCommand( curtok, fpin[curfile], fout );
1782 /* Incase we change fpout */
1783 fout = fpout;
1784 }
1785 }
1786 }
1787 else if (ch == ActiveChar) {
1788 TXActiveCharDo(curtok);
1789 }
1790 else {
1791 if (flag) {
1792 TeXoutsp( fout, nsp );
1793 if (ch == '\n') {
1794 if (last_was_nl) {
1795 TXWritePar( fout );
1796 SCSkipNewlines( fpin[curfile] );
1797 }
1798 else if (lSp >= 0)
1799 (*lstack[lSp].newline)( fout );
1800 else
1801 TeXoutNewline( fout );
1802 last_was_nl = 1;
1803 }
1804 else {
1805 if (ch == LbraceChar) {
1806 if (BraceCount >= MAX_BLOC) {
1807 TeXAbort( "", "Braces too deep" );
1808 }
1809 strncpy( bloc[BraceCount].filename, InFName[curfile],
1810 MAX_BLOC_FNAME );
1811 bloc[BraceCount++].lineno = LineNo[curfile];
1812 /* fprintf( fout, "**+%d[%d]**",
1813 LineNo[curfile], BraceCount ); */
1814 TXbgroup( e );
1815 }
1816 else if (ch == RbraceChar) {
1817 BraceCount--;
1818 /* fprintf( fout, "**-%d[%d]**",
1819 LineNo[curfile], BraceCount ); */
1820 if (BraceCount < 0) {
1821 fprintf( ferr,
1822 "Improperly nested brace at %s line %d in ",
1823 InFName[curfile] ? InFName[curfile]: "",
1824 LineNo[curfile] );
1825 PrintLastSectionName( ferr );
1826 /* Reset brace count */
1827 BraceCount = 0;
1828 }
1829 TXegroup( e );
1830 } else {
1831 TeXoutstr( fout, curtok );
1832 }
1833 last_was_nl = 0;
1834 }
1835 }
1836 }
1837 }
1838 }
1839 POPCURTOK;
1840 AmSkipping = last_skip;
1841 /* Skip the newlines and the end of the environment */
1842 SCSkipNewlines( fpin[curfile] );
1843 if (DebugCommands)
1844 fprintf( stdout, "Done with environment %s\n", name );
1845 }
1846
1847 /* This is a version of skipEnv that just copies to output; it DOES handle
1848 nested versions of itself.
1849
1850 if doout is false, generate no output
1851
1852 As a special case, we need to watch for \label{...}, since we may need that
1853 name to resolve references.
1854
1855 We must process comments, since we must properly detect the following
1856 \begin{foo}
1857 ...
1858 %\end{foo}
1859 %\begin{foo}
1860 ...
1861 \end{foo}
1862
1863 That is, if % is a comment character, we must stop looking for \end
1864 to match. If we are doing something like verbatim, we have to
1865 turn off the comment character (set to null)
1866 */
TeXskipRaw(TeXEntry * e,char * name,int doout)1867 void TeXskipRaw( TeXEntry *e, char *name, int doout )
1868 {
1869 int nsp, ch;
1870 FILE *fout = fpout;
1871 /* int (*oldtrans)( char *, int ); */
1872 /* char commentchar; */
1873
1874 /* First, remove any newlines */
1875 SCSkipNewlines( fpin[curfile] );
1876
1877 /*
1878 commentchar = SCGetCommentChar();
1879 SCSetCommentChar( 0 );
1880 */
1881 /*
1882 oldtrans = SCSetTranslate( (int (*)( char *, int ))0 );
1883 */
1884 if (DebugCommands)
1885 fprintf( stdout, "Processing environment %s (skipRaw)\n", name );
1886 PUSHCURTOK;
1887 while (1) {
1888 while ( (ch = TeXReadToken( curtok, &nsp )) == EOF) {
1889 if (DebugCommands)
1890 fprintf( stdout, "EOF in TeXskipRaw\n" );
1891 /* Special case for vtt */
1892 if (curfile == 0 && strcmp( name, "_vtt" ) == 0) {
1893 break;
1894 }
1895 TXPopFile();
1896 }
1897 if (ch == EOF) break;
1898 if (DebugCommands) {
1899 fprintf( stdout, "Token is %s\n", curtok );
1900 }
1901 if (ch == CommentChar) {
1902 /* Handle comments */
1903 if (doout) {
1904 TeXoutsp( fout, nsp );
1905 TeXoutstr( fout, curtok );
1906 TeXoutstr( fout, NewLineString );
1907 }
1908 SCTxtDiscardToEndOfLine( fpin[curfile] );
1909 }
1910 else if (ch == CommandChar) {
1911 if (doout)
1912 TeXoutsp( fout, nsp );
1913
1914 if (strcmp( curtok, "\\end" ) == 0) {
1915 if (DebugCommands)
1916 fprintf( stdout, "Getting argument for end{}\n" );
1917 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN,
1918 "TXSkipRaw", e->name );
1919 /* Check for a user-defined environment type */
1920 if (strcmp( curtok, name ) != 0) {
1921 if (doout)
1922 fprintf( fout, "\\end{%s}\n", curtok );
1923 }
1924 else {
1925 break;
1926 }
1927 }
1928 else if (strcmp( curtok, "\\label" ) == 0) {
1929 /* Need to process a label command */
1930 TXlabel( e );
1931 /* Add a dummy incase this is the only thing on a line */
1932 if (doout)
1933 TeXoutstr( fout, "\\label{eq-foo}" );
1934 }
1935 else if (strcmp( curtok, "\\caption" ) == 0) {
1936 /* Need to increment the appropriate counter/name */
1937 TXcaptionHandling( e );
1938 }
1939 else {
1940 if (doout) {
1941 TeXoutstr( fout, curtok );
1942 }
1943 }
1944 }
1945 else {
1946 if (doout) {
1947 TeXoutsp( fout, nsp );
1948 TeXoutstr( fout, curtok );
1949 }
1950 }
1951 }
1952 /* Skip the newlines and the end of the environment */
1953 /* SCSetTranslate( oldtrans ); */
1954 /*
1955 SCSetCommentChar( commentchar );
1956 */
1957 SCSkipNewlines( fpin[curfile] );
1958 if (DebugCommands)
1959 fprintf( stdout, "Done with environment %s\n", name );
1960 POPCURTOK;
1961 }
1962
1963
1964 /*
1965 See if the named file exists in the current or split directory
1966 */
FileExists(char * fname)1967 int FileExists( char *fname )
1968 {
1969 FILE *fp;
1970 int exists = 0;
1971 if (splitlevel >= 0) {
1972 char *fname2;
1973 fname2 = (char *)MALLOC( 1024 );
1974 if (!fname2) {
1975 fprintf( stderr, "Out of memory!\n" );
1976 exit(1);
1977 }
1978 sprintf( fname2, "%s/%s", splitdir, fname );
1979 fp = fopen( fname2, "r" );
1980 FREE( fname2 );
1981 }
1982 else {
1983 fp = fopen( fname, "r" );
1984 }
1985 if (fp) {
1986 exists = 1;
1987 fclose( fp );
1988 }
1989 return exists;
1990 }
1991
1992 /*
1993 Manage math mode (\[ .. \] or \( ... \) )
1994 */
TXmathmode(TeXEntry * e)1995 void TXmathmode( TeXEntry *e )
1996 {
1997 #ifndef FOO
1998 /* If display math, make it look like $$ starts it */
1999 if (e->name[0] == '[') SCPushToken( "$" );
2000 TXProcessDollar( e, LatexMath, 1 );
2001 return;
2002 #else
2003 if (DebugCommands) fprintf( stdout, "Starting math mode processing\n" );
2004 if (LatexUnknownEnvs || LatexMath) {
2005 char bname[100];
2006 char fname[100];
2007 char name[4];
2008 snprintf( bname, sizeof(bname), "%s%d", imgfilebase, imageno++ );
2009 strcpy( fname, bname );
2010 strcat( fname, "." );
2011 strcat( fname, ImageExt );
2012
2013 name[0] = '\\';
2014 name[1] = e->name[0];
2015 name[2] = 0;
2016 if (LatexAgain || !FileExists( fname )) {
2017 /* We always process, because either LatexAgain is 1,
2018 or the file does not exists */
2019 RunLatex( (char *)0, (char *)0, bname, name, ImageExt, 1 );
2020 }
2021 else if (FileExists( fname ) && !LatexAgain) {
2022 /* Skip over the section */
2023 RunLatex( (char *)0, (char *)0, bname, name, ImageExt, 0 );
2024 }
2025
2026 if (name[1] == '[') {
2027 /*
2028 if (envjumpname && envjumpname[0])
2029 TXAnchoredImage( e, envjumpname, fname );
2030 else
2031 */
2032 TXimage( e, fname );
2033 }
2034 else /* \( ... \) */
2035 TXInlineImage( e, fname );
2036 }
2037 #endif
2038 }
2039
2040 int itemizelevel = -1;
2041
2042 /* Copy this envrionment without doing anything */
TeXBenign(TeXEntry * e,char * name)2043 void TeXBenign( TeXEntry *e, char *name )
2044 {
2045 TXbgroup( e );
2046 TeXskipEnv( e, name, 1 );
2047 TXegroup( e );
2048 }
2049
TeXitemize(TeXEntry * e)2050 void TeXitemize( TeXEntry *e )
2051 {
2052 itemizelevel++;
2053 lstack[++lSp].env = TXITEMIZE;
2054 lstack[lSp].newline = TeXoutNewline;
2055 lstack[lSp].label_node_name = 0;
2056 lstack[lSp].label_text = 0;
2057 lstack[lSp].line_num = LineNo[curfile];
2058 lstack[lSp].extra_data = 0;
2059 TXbitemize( e );
2060 TeXskipEnv( e, "itemize", 1 );
2061 TXeitemize( e );
2062 itemizelevel--;
2063 lSp--;
2064 TXWriteStartNewLine( fpout );
2065 }
2066
TeXenumerate(TeXEntry * e)2067 void TeXenumerate( TeXEntry *e )
2068 {
2069 itemizelevel++;
2070 lstack[++lSp].env = TXENUMERATE;
2071 lstack[lSp].num = 1;
2072 lstack[lSp].newline = TeXoutNewline;
2073 lstack[lSp].label_node_name = 0;
2074 lstack[lSp].label_text = 0;
2075 lstack[lSp].line_num = LineNo[curfile];
2076 lstack[lSp].extra_data = 0;
2077 TXbenumerate( e );
2078 TeXskipEnv( e, "enumerate", 1 );
2079 TXeenumerate( e );
2080 itemizelevel--;
2081 lSp--;
2082 /* Note that the begin/end enumerate generates a newline already */
2083 /* TXWriteStartNewLine( fpout ); */
2084 }
2085
TeXdescription(TeXEntry * e)2086 void TeXdescription( TeXEntry *e )
2087 {
2088 itemizelevel++;
2089 lstack[++lSp].env = TXDESCRIPTION;
2090 lstack[lSp].newline = TeXoutNewline;
2091 lstack[lSp].label_node_name = 0;
2092 lstack[lSp].label_text = 0;
2093 lstack[lSp].line_num = LineNo[curfile];
2094 lstack[lSp].extra_data = 0;
2095 TXbdescription( e );
2096 TeXskipEnv( e, "description", 1 );
2097 TXedescription( e );
2098 itemizelevel--;
2099 lSp--;
2100 TXWriteStartNewLine( fpout );
2101 }
2102
2103 /*
2104 This handles \begin{list}{itemtext} ... \end{list}
2105 itemtext is stored in p1 and MUST BE PROCESSED AGAIN
2106 */
TeXDoList(TeXEntry * e,char * itemtext,char * itemcommands)2107 void TeXDoList( TeXEntry *e, char *itemtext, char *itemcommands )
2108 {
2109 itemizelevel++;
2110 lstack[++lSp].env = TXLIST;
2111 lstack[lSp].num = 1;
2112 lstack[lSp].newline = TeXoutNewline;
2113 lstack[lSp].p1 = itemtext;
2114 lstack[lSp].p2 = itemcommands;
2115 lstack[lSp].label_node_name = 0;
2116 lstack[lSp].label_text = 0;
2117 lstack[lSp].line_num = LineNo[curfile];
2118 lstack[lSp].extra_data = 0;
2119 /* May want description instead of itemize */
2120 /* TXbitemize( e ); */
2121 TeXskipEnv( e, "list", 1 );
2122 /* TXeitemize( e ); */
2123 itemizelevel--;
2124 lSp--;
2125 TXWriteStartNewLine( fpout );
2126 }
2127
TeXsmall(TeXEntry * e)2128 void TeXsmall( TeXEntry *e )
2129 {
2130 TeXskipEnv( e, "small", 1 );
2131 }
2132
2133
TXverb(TeXEntry * e)2134 void TXverb( TeXEntry *e )
2135 {
2136 int ch;
2137 int match;
2138 char *p;
2139
2140 if (DebugCommands) fprintf( stdout, "LaTeX verb command\n" );
2141 PUSHCURTOK;
2142 p = curtok;
2143 match = SCTxtGetChar( fpin[curfile] );
2144 if (match == EOF) return;
2145 while ( (ch = SCTxtGetChar( fpin[curfile] )) != match ) {
2146 *p++ = ch;
2147 }
2148 *p++ = 0;
2149 TeXoutstr( fpout, curtok );
2150 POPCURTOK;
2151 }
2152
TeXverbatim(TeXEntry * e)2153 void TeXverbatim( TeXEntry *e )
2154 {
2155 /* char comment_char; */
2156 /* Skip code until find an \end{verbatim}.
2157 In verbatim mode, ignore any \ EXCEPT \end{verbatim} (How?) */
2158 InVerbatim = 1;
2159 TXWriteStartNewLine( fpout );
2160 TXpreformated( fpout, 1 );
2161 TXbgroup( e );
2162 TXfont_tt( e );
2163 lstack[++lSp].env = TXVERBATIM;
2164 lstack[lSp].newline = TXWriteStartNewLine;
2165 lstack[lSp].label_node_name = 0;
2166 lstack[lSp].label_text = 0;
2167 lstack[lSp].line_num = LineNo[curfile];
2168 lstack[lSp].extra_data = 0;
2169
2170 /* Verbatim has no comments! */
2171 /*
2172 comment_char = SCGetCommentChar();
2173 SCSetCommentChar( (char)0 );
2174 */
2175 /* Skip newlines at the head of the verbatim. This isn't precisely
2176 correct; I think that it should skip at most one.
2177 SCSkipNewlines2 is better about this. */
2178 SCSkipNewlines2( fpin[curfile] );
2179
2180 TeXskipEnv( e, "verbatim", 1 );
2181 /*
2182 SCSetCommentChar( comment_char );
2183 */
2184 TXegroup( e );
2185 TXpreformated( fpout, 0 );
2186 lSp--;
2187 InVerbatim = 0;
2188 }
2189
2190 /*
2191 void TeXCenter( TeXEntry *e )
2192 {
2193 TXbcenter( fpout );
2194 TeXskipEnv( e, "center", 0 );
2195 TXecenter( fpout );
2196 }
2197
2198 void TeXCenterline( TeXEntry *e )
2199 {
2200 TXbcenter( fpout );
2201 TXasisGrouped( e );
2202 TXecenter( fpout );
2203 }
2204 */
2205 /* ----------------------------------------------------------------------- */
2206 /*
2207 There should really be a generic
2208 TeXSimpleEnv(
2209 startfcn( FILE *, TeXEntry * ), "name", endfcn( FILE *, TeXEntry * ) )
2210 for things like center and quote, as an improvement over TeXBenign
2211
2212 Then these can be put into the basedefs by having the commands for start
2213 and end in the basedefs file and stored in the TeXEntry (which could
2214 store the functions themselves)
2215 */
TXbegin(TeXEntry * e)2216 void TXbegin( TeXEntry *e )
2217 {
2218 /* Process the beginning of an environment */
2219 char *p;
2220 char *btext, *etext;
2221 int nargs;
2222
2223 /* (look for tex, enumerate, description, example, iftex, etc ) */
2224 if (DebugCommands)
2225 fprintf( stdout, "Getting argument for begin{}\n" );
2226 PUSHCURTOK;
2227 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN,
2228 "TXbegin argument", e->name );
2229 if (strcmp( curtok, "iftex" ) == 0) {
2230 if (UseIfTex) TeXBenign( e, "iftex" );
2231 else TeXiftex( e );
2232 }
2233 else if (strcmp( curtok, "tex" ) == 0) TeXtex( e );
2234 /* MPI reports use example as a variation of theorem, not verbatim,
2235 as LatexInfo does. We need to configure this somehow...
2236 In fact, we need to label it as an Example, with example numbers...
2237 */
2238 else if (UsingLatexinfo && strcmp( curtok, "example" ) == 0) TeXexample( e );
2239 else if (strcmp( curtok, "verbatim" ) == 0) TeXverbatim( e );
2240 else if (strcmp( curtok, "menu" ) == 0) TeXmenu( e );
2241 else if (strcmp( curtok, "ifinfo" ) == 0) {
2242 if (UseIfTex) TeXskipEnv( e, "ifinfo", 0 );
2243 else TeXBenign( e, "ifinfo" );
2244 }
2245 /* There should be a way to specify these in the basedef file */
2246 /* else if (strcmp( curtok, "center" ) == 0) TeXCenter( e ); */
2247 else if (strcmp( curtok, "benign" ) == 0) TeXBenign( e, "benign" );
2248 else if (strcmp( curtok, "displaymath") == 0 && !UsingLatexinfo) {
2249 if (LatexMath) {
2250 TXProcessDollar( e, LatexMath, 0 );
2251 }
2252 else
2253 TeXBenign( e, "displaymath" );
2254 }
2255 #ifdef FOO
2256 else if (strcmp( curtok, "centering" ) == 0) TeXBenign( e, "centering" );
2257 else if (strcmp( curtok, "normalsize" ) == 0) TeXBenign( e, "normalsize" );
2258 else if (strcmp( curtok, "abstract" ) == 0) TeXBenign( e, "abstract" );
2259 else if (strcmp( curtok, "raggedright" ) == 0) TeXBenign( e, "raggedright" );
2260 else if (strcmp( curtok, "flushleft" ) == 0) TeXBenign( e, "flushleft" );
2261 else if (strcmp( curtok, "sloppypar" ) == 0) TeXBenign( e, "sloppypar" );
2262 else if (strcmp( curtok, "quote" ) == 0) TeXBenign( e, "quote" );
2263 #endif
2264 else if (strcmp( curtok, "slide" ) == 0) {
2265 /* Strip the color arg */
2266 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN,
2267 "TXbegin slide", e->name );
2268 /* Pick the equivalent slide format */
2269 TXvt( e );
2270 /* Need a new page ... */
2271 TeXBenign( e, "slide" );
2272 }
2273 #ifdef FOO
2274 else if (strcmp( curtok, "quotation" ) == 0) {
2275 TXWritePar( fpout );
2276 TeXBenign( e, "quotation" );
2277 TXWritePar( fpout );
2278 }
2279 #endif
2280 else if (strcmp( curtok, "figure" ) == 0) {
2281 /* Remove optional positioning */
2282 TXRemoveOptionalArg( curtok );
2283 NumberedEnvironmentType = ENV_FIGURE;
2284 TeXBenign( e, "figure" );
2285 NumberedEnvironmentType = ENV_NONE;
2286 }
2287 else if (strcmp( curtok, "thebibliography" ) == 0) {
2288 /* Eat the next argument */
2289 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN,
2290 "TXbegin thebibliography", e->name );
2291 /* Need to act as if "Section{Bibliography}" seen */
2292 SCPushToken( "{Bibliography}" );
2293 e->ctx = (void*)(PTRINT)MinSectionKind;
2294 TXsection( e );
2295 TeXBenign( e, "thebibliography" );
2296 }
2297 /* displaymath should be like \[ ... \] */
2298 /* math should be like \( ... \) */
2299 /* Note that in LaTeX, \begin{foo}...\end{foo} is just like (almost)
2300 \foo ... \endfoo, and \displaymath=\[, \enddisplaymath=\] */
2301 else if (strcmp( curtok, "theindex" ) == 0) {
2302 /* An index done with the regular system is useless, since the names
2303 have pages. Instead, we skip the index entirely, then dump
2304 the results of our own use of \index */
2305 SCPushToken( "{Index}" );
2306 e->ctx = (void*)(PTRINT)MinSectionKind;
2307 TXsection( e );
2308 TeXskipEnv( e, "theindex", 0 );
2309 WriteIndex( fpout, 2 );
2310 }
2311 else if (UserIndexName && strcmp( curtok, UserIndexName ) == 0) {
2312 /* An index done with the regular system is useless, since the names
2313 have pages. Instead, we skip the index entirely, then dump
2314 the results of our own use of \index */
2315 SCPushToken( "{Index}" );
2316 e->ctx = (void*)(PTRINT)MinSectionKind;
2317 TXsection( e );
2318 TeXskipEnv( e, UserIndexName, 0 );
2319 WriteIndex( fpout, 2 );
2320 }
2321 else if (!LatexTables && (strcmp( curtok, "table" ) == 0)) {
2322 /* Remove optional positioning */
2323 TXRemoveOptionalArg( curtok );
2324 NumberedEnvironmentType = ENV_TABLE;
2325 TeXBenign( e, "table" );
2326 NumberedEnvironmentType = ENV_NONE;
2327 }
2328 else if (strcmp( curtok, "small" ) == 0) TeXsmall( e );
2329 #ifdef FOO
2330 else if (strcmp( curtok, "tiny" ) == 0) TeXBenign( e, "tiny" );
2331 #endif
2332 else if (!LatexTables && (strcmp( curtok, "tabular" ) == 0))
2333 if (HandleAlign) {
2334 lstack[++lSp].env = TXTABULAR;
2335 lstack[lSp].newline = TeXoutNewline;
2336 lstack[lSp].line_num = LineNo[curfile];
2337 lstack[lSp].extra_data = 0;
2338 TeXGetTabularDefn();
2339 TeXBeginHalignTable();
2340 TeXBenign( e, "tabular" );
2341 TeXEndHalignTable();
2342 --lSp;
2343 }
2344 else {
2345 TeXtabular( e );
2346 }
2347 else if (strcmp( curtok, "document" ) == 0) {
2348 InDocument = 1;
2349 TXStartDoc(1);
2350 TXInitialCommands(); /* Push back any initial commands */
2351 TeXBenign( e, "document" );
2352 InDocument = 0;
2353 TXStartDoc(0);
2354 }
2355 else if (strcmp( curtok, "description" ) == 0) TeXdescription( e );
2356 else if (strcmp( curtok, "itemize" ) == 0) TeXitemize( e );
2357 else if (strcmp( curtok, "enumerate" ) == 0) TeXenumerate( e );
2358 else if (strcmp( curtok, "list" ) == 0) {
2359 char *itemtext, *itemcommands;
2360 /* 2 arguments; first is text for \item, second is code executed for
2361 each item */
2362 /* fprintf( stdout,"Ignoring details list environment defn for now\n" ); */
2363 /* Note that we need to allocate the itemtext and itemcommands,
2364 since list environments may be nested */
2365 ALLOC_TOKEN(itemtext);
2366 ALLOC_TOKEN(itemcommands);
2367 /*
2368 itemtext = (char *)MALLOC( MAX_TOKEN ); CHKPTR(itemtext);
2369 itemcommands = (char *)MALLOC( MAX_TOKEN ); CHKPTR(itemcommands);
2370 */
2371 TeXMustGetArg( fpin[curfile], itemtext, MAX_TOKEN,
2372 "TXbegin list itemtext", e->name );
2373 TeXMustGetArg( fpin[curfile], itemcommands, MAX_TOKEN,
2374 "TXbegin list itemcommands", e->name );
2375 TeXDoList( e, itemtext, itemcommands );
2376 /*
2377 FREE( itemtext );
2378 FREE( itemcommands );
2379 */
2380 FREE_TOKEN(itemcommands);
2381 FREE_TOKEN(itemtext);
2382 }
2383 else if (LookupEnv( curtok, &btext, &etext, &nargs)) {
2384 /* Really needs to look for arguments; use def's pushback with eval */
2385 if (DebugCommands) {
2386 fprintf( stdout, "Processing user-defined environment %s\n", curtok );
2387 fprintf( stdout, "defined as begin:|%s|\nend:|%s|\n",
2388 btext ? btext : "<NULL>", etext ? etext : "<NULL>" );
2389 }
2390 PushBeginEnv( btext, nargs );
2391 /* TeXBenign( e, curtok ); */
2392 }
2393 /*
2394 else if () {
2395 This code should look up the name \"curtok", if defined, then do that.
2396 The corresponding end code should look up \end"curtok". This can
2397 be used to handle things like \begin{em} ... \end{em}, which has
2398 the effect of {\em ...} . We might be able to integrate this
2399 with lookupenv...
2400 }
2401 */
2402 else {
2403 p = STRDUP( curtok ); CHKPTR(p);
2404 /* Identify environment as table, figure, equation, or none */
2405 if (strcmp( p, "table" ) == 0) {
2406 NumberedEnvironmentType = ENV_TABLE;
2407 }
2408 else if (strcmp( p, "figure" ) == 0) {
2409 NumberedEnvironmentType = ENV_FIGURE;
2410 }
2411 else if (strcmp( p, "equation" ) == 0 ||
2412 strcmp( p, "eqnarray" ) == 0) {
2413 NumberedEnvironmentType = ENV_EQUATION;
2414 TeXSetEnvJump( "Equation" );
2415 TXcaptionHandling( e );
2416 }
2417 if (LatexUnknownEnvs ||
2418 (LatexTables &&
2419 (strcmp( curtok, "tabular" ) == 0 ||
2420 strcmp( curtok, "table" ) == 0))) {
2421 char bname[100];
2422 char fname[100];
2423
2424 if (DebugCommands) {
2425 fprintf( stdout, "Using Latex to process an environment\n" );
2426 }
2427 snprintf( bname, sizeof(bname), "%s%d", imgfilebase, imageno++ );
2428 strcpy( fname, bname );
2429 strcat( fname, "." );
2430 strcat( fname, ImageExt );
2431 if (LatexAgain || !FileExists( fname )) {
2432 RunLatex( curtok, (char *)0, bname, (char *)0, ImageExt, 1 );
2433 }
2434 else if (FileExists( fname ) && !LatexAgain) {
2435 RunLatex( curtok, (char *)0, bname, (char *)0, ImageExt, 0 );
2436 }
2437 /* If this is a figure or table environment, generate a target
2438 location for the image */
2439 if (NumberedEnvironmentType != ENV_NONE && envjumpname &&
2440 envjumpname[0])
2441 TXAnchoredImage( e, envjumpname, fname );
2442 else
2443 TXimage( e, fname );
2444 }
2445 else {
2446 if (!AmSkipping) /* && InDocument) */ {
2447 fprintf( ferr, "Unknown environment %s, %s line %d\n",
2448 curtok,
2449 InFName[curfile] ? InFName[curfile]: "",
2450 LineNo[curfile] );
2451 }
2452 TeXBenign( e, p );
2453 if (!AmSkipping) /* && InDocument) */ {
2454 fprintf( ferr, "End of unknown environment %s, %s line %d\n",
2455 curtok,
2456 InFName[curfile] ? InFName[curfile]: "",
2457 LineNo[curfile] );
2458 }
2459 }
2460 NumberedEnvironmentType = ENV_NONE;
2461 FREE( p );
2462 }
2463 POPCURTOK;
2464 }
2465
TXend(TeXEntry * e)2466 void TXend( TeXEntry *e )
2467 {
2468 PUSHCURTOK;
2469 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXend", e->name );
2470 /* Finish processing of an environment */
2471 if (lstack[lSp].env == TXTABULAR) {
2472 if (strcmp( "tabular", curtok ) != 0) {
2473 fprintf( stderr, "Saw end{%s} but expected tabular\n", curtok );
2474 }
2475 else {
2476 TeXEndHalignTable();
2477 FREE( lstack[lSp].extra_data );
2478 lSp--;
2479 }
2480 }
2481 POPCURTOK;
2482 }
2483
TXitem(TeXEntry * e)2484 void TXitem( TeXEntry *e )
2485 {
2486 char buf[12];
2487 /* Process an item based on the current environment */
2488 TXWriteStartItem( fpout );
2489 if (lstack[lSp].env == TXDESCRIPTION) {
2490 TXbdesItem( e );
2491 TXbgroup( e );
2492 TXbf( e );
2493 /* Defer reading option until here in case it causes direct output (for
2494 example, a pointer reference) */
2495 if (DebugCommands)
2496 fprintf( stdout, "Getting argument for item in description\n" );
2497 PUSHCURTOK;
2498 strncpy( CmdName, e->name, sizeof(CmdName)-1 );
2499 if (TeXGetGenArg( fpin[curfile], curtok, MAX_TOKEN, '[', ']', 1 ) != 1) {
2500 /* It is legal to forget the [], but probably unintended */
2501 fprintf( stdout,
2502 "Missing [] in description item in File %s line %d\n",
2503 InFName[curfile] ? InFName[curfile]: "", LineNo[curfile] );
2504 strcpy( curtok, " " );
2505 /* TeXAbort( "TXbegin description", e->name ); */
2506 }
2507 CmdName[0] = 0;
2508 /* FIXME: Need to process the curtok for commands */
2509 #if 0
2510 TeXoutstr( fpout, curtok );
2511 TXegroup( e );
2512 TXedesItem( e );
2513 #else
2514 SCPushCommand("<dd>\n");
2515 /* Not quite right - need an endgroup, or need to change */
2516 BraceCount++;
2517 SCPushToken("}");
2518 SCPushToken(curtok);
2519 #endif
2520 POPCURTOK;
2521 }
2522 else if (lstack[lSp].env == TXENUMERATE) {
2523 /* \item[] is legal in \enumerate */
2524 PUSHCURTOK;
2525 TXRemoveOptionalArg( curtok );
2526 POPCURTOK;
2527 /* We don't want to do this on the FIRST item in an enumerate */
2528 if (lstack[lSp].num > 1)
2529 TXWriteStartNewLine( fpout );
2530 sprintf( buf, "%d. ", lstack[lSp].num++ );
2531 TeXoutstr( fpout, buf );
2532 }
2533 else if (lstack[lSp].env == TXLIST) {
2534 /* We might want to allow bullet to be identified... */
2535 /* Remove any [] in the list argument. Save the value */
2536 /* eventually, if the is a labellength, use an html table to
2537 force the correct width */
2538 PUSHCURTOK;
2539 curtok[0] = 0;
2540 TXRemoveOptionalArg( curtok );
2541 TXWriteStartNewLine( fpout );
2542 /* This really needs to process the string FIRST before outputting it... */
2543 if (curtok[0]) {
2544 SCPushToken( curtok );
2545 }
2546 else {
2547 /* p1 is the itemtext, which is the text used if there is no optional
2548 argument */
2549 if (lstack[lSp].p1)
2550 SCPushToken( lstack[lSp].p1 );
2551 }
2552 /* TeXoutstr( fpout, lstack[lSp].p1 ); */
2553 if (lstack[lSp].p2)
2554 SCPushToken( lstack[lSp].p2 );
2555 POPCURTOK;
2556 }
2557 else {
2558 /* Assume itemize for now. This is incorrect for an index */
2559 TXbgroup( e );
2560 TXoutbullet( e );
2561 TXegroup( e );
2562 }
2563 SCSkipNewlines( fpin[curfile] );
2564 }
2565
2566 /* Process index entries */
TXcindex(TeXEntry * e)2567 void TXcindex( TeXEntry *e )
2568 {
2569 if (DebugCommands)
2570 fprintf( stdout, "Getting argument for %s\n", e->name );
2571 PUSHCURTOK;
2572 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXcindex", e->name );
2573 AddToIndex( curtok, CurNodename, CurSeqnum - 1, 1 );
2574 POPCURTOK;
2575 }
2576
TXfindex(TeXEntry * e)2577 void TXfindex( TeXEntry *e )
2578 {
2579 if (DebugCommands)
2580 fprintf( stdout, "Getting argument for %s\n", e->name );
2581 PUSHCURTOK;
2582 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXfindex", e->name );
2583 AddToIndex( curtok, CurNodename, CurSeqnum - 1, 0 );
2584 POPCURTOK;
2585 }
2586
TXindex(TeXEntry * e)2587 void TXindex( TeXEntry *e )
2588 {
2589 if (DebugCommands)
2590 fprintf( stdout, "Getting argument for %s\n", e->name );
2591 PUSHCURTOK;
2592 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXindex", e->name );
2593 AddToIndex( curtok, CurNodename, CurSeqnum - 1, 2 );
2594 POPCURTOK;
2595 }
2596
TXprintindex(TeXEntry * e)2597 void TXprintindex( TeXEntry *e )
2598 {
2599 int which;
2600
2601 if (DebugCommands)
2602 fprintf( stdout, "Getting argument for %s\n", e->name );
2603 PUSHCURTOK;
2604 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXprintindex", e->name );
2605 which = 0;
2606 if (strcmp( curtok, "cp" ) == 0) which = 1;
2607 WriteIndex( fpout, which );
2608 POPCURTOK;
2609 }
2610
TXmakeindex(TeXEntry * e)2611 void TXmakeindex( TeXEntry *e )
2612 {
2613 /* Does makeindex do some sort of heading? */
2614 /* WriteIndex( fpout, 2 ); */
2615 }
2616
2617 /* Process \documentstyle[]{}. Note that we need to save the document
2618 style inorder to process code in latex mode */
2619 char *preamble = 0;
2620 char *predoc = 0;
2621 char *documentcmd = 0;
2622
2623 #ifndef MAX_PATH_LEN
2624 #define MAX_PATH_LEN 1024
2625 #endif
TXLoadPackage(const char * p)2626 void TXLoadPackage( const char *p )
2627 {
2628 /* First, try to find name.def in the definition list. If
2629 found, load that */
2630 if (userpath[0]) {
2631 char filename[MAX_PATH_LEN];
2632 char fullfilename[MAX_PATH_LEN];
2633
2634 strcpy( filename, p );
2635 strcat( filename, ".def" );
2636 if (SYGetFileFromPath( userpath, filename, "DOCTEXT_USERPATH",
2637 fullfilename, 'r' )) {
2638 RdBaseDef( fullfilename );
2639 return;
2640 }
2641 }
2642
2643 /* Otherwise, check against predefined commands */
2644 if (strcmp( p, "latexinfo" ) == 0 ||
2645 strcmp( p, "latexinfo-1.2") == 0)
2646 TXStyleLatexInfo( TeXlist, fpin[curfile], fpout );
2647 else if (strcmp( p, "epsf" ) == 0)
2648 TXStyleEPSF( TeXlist, fpin[curfile], fpout );
2649 else if (strcmp( p, "psfig" ) == 0) {
2650 TXStylePsfig( TeXlist, fpin[curfile], fpout );
2651 /* Must defined the ESPF style, since we currently use
2652 them to implement psfig */
2653 TXStyleEPSF( TeXlist, fpin[curfile], fpout );
2654 }
2655 else if (strcmp( p, "graphics" ) == 0 ||
2656 strcmp( p, "graphicx" ) == 0 ||
2657 strcmp( p, "graphicsx" ) == 0) {
2658 TXInsertName( TeXlist, "includegraphics", TXincludegraphics,
2659 1, (void *)0 );
2660 }
2661 else if (strcmp( p, "11pt" ) == 0 ||
2662 strcmp( p, "12pt" ) == 0 ||
2663 strcmp( p, "twoside" ) == 0 ||
2664 strcmp( p, "fleqn" ) == 0)
2665 /* Standard packages that do not affect HTML formatting */
2666 ;
2667 /* My private styles ... */
2668 else if (strcmp( p, "fileinclude" ) == 0)
2669 ;
2670 else if (strcmp( p, "funclist" ) == 0)
2671 TXStyleFunclist( TeXlist, fpin[curfile], fpout );
2672 else if (strcmp( p, "tpage" ) == 0)
2673 TXStyleTpage( TeXlist, fpin[curfile], fpout );
2674 else if (strcmp( p, "tools" ) == 0)
2675 TXStyleTools( TeXlist, fpin[curfile], fpout );
2676 else if (strcmp( p, "anlhtext" ) == 0)
2677 TXStyleAnlhtext( TeXlist, fpin[curfile], fpout );
2678 else if (strcmp( p, "handpage" ) == 0)
2679 TXStyleANLHandpage( TeXlist, fpin[curfile], fpout );
2680 else if (strcmp( p, "urlsimple" ) == 0 ||
2681 strcmp( p, "code" ) == 0) {
2682 /* Simple defines URL and AURL */
2683 ;
2684 }
2685 else {
2686 fprintf( ferr,
2687 "Unknown documentstyle or package %s; provide\n\
2688 %s.def to define the commands\n", p, p );
2689 /* Question here is whether we should try to read the document
2690 style file */
2691 }
2692 }
2693
2694 /* Latex 2e specifies additional stuff using \usepackage, which may have
2695 a comma separate list of packages. Format is
2696 \usepackage[optional fields]{package-name}
2697 Note that it is common for the optional fields to be across multiple
2698 lines.
2699 */
TXusepackage(TeXEntry * e)2700 void TXusepackage( TeXEntry *e )
2701 {
2702 char *p, *ptr, *p1;
2703 int hadOptional=0;
2704
2705 PUSHCURTOK;
2706 strncpy( CmdName, e->name, sizeof(CmdName)-1 );
2707 TXRemoveOptionalArg(curtok);
2708 if (curtok[0]) {
2709 strcat(preamble, "\\usepackage[");
2710 strcat(preamble, curtok);
2711 strcat(preamble, "]");
2712 hadOptional = 1;
2713 }
2714 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXusepackage", e->name );
2715 if (curtok[0]) {
2716 if (!hadOptional) {
2717 strcat( preamble, "\\usepackage" );
2718 }
2719 strcat(preamble, "{");
2720 strcat( preamble, curtok );
2721 strcat( preamble, "}\n" );
2722 }
2723 if (1) {
2724 fprintf( stdout, "Procssing usepackage[...]{%s} in %s line %d\n",
2725 curtok, InFName[curfile] ? InFName[curfile]: "",
2726 LineNo[curfile] );
2727 }
2728 /* Now, get comma-separate list of packages and load each one */
2729 p = curtok;
2730 while (*p) {
2731 ptr = p;
2732 while (*ptr && *ptr != ',') ptr++;
2733 if (!*ptr) ptr[1] = 0; /* so the p = ptr + 1 below will exit */
2734 *ptr = 0; /* Change , to null */
2735 /* Skip over any path part of the specification */
2736 p1 = strrchr( p, '/' );
2737 if (p1) p = p1 + 1;
2738 TXLoadPackage( p );
2739 p = ptr + 1;
2740 }
2741
2742 CmdName[0] = 0;
2743 POPCURTOK;
2744 }
2745
TXdocumentstyle(TeXEntry * e)2746 void TXdocumentstyle( TeXEntry *e )
2747 {
2748 static char name[] = "documentstyle";
2749 char *p, *ptr, *p1;
2750
2751 preamble = (char *)MALLOC( 20000 ); CHKPTR(preamble);
2752 predoc = (char *)MALLOC( 20000 ); CHKPTR(predoc);
2753 predoc[0] = 0;
2754 preamble[0] = 0;
2755 if (!documentcmd) documentcmd = name;
2756
2757 PUSHCURTOK;
2758 if (TeXGetGenArg( fpin[curfile], curtok, MAX_TOKEN, '[', ']', 1 ) == 1) {
2759 strcat( preamble, "[" );
2760 strcat( preamble, curtok );
2761 strcat( preamble, "]" );
2762 p = curtok;
2763 while (*p) {
2764 /* Look for known styles */
2765 ptr = p;
2766 while (*ptr && *ptr != ',') ptr++;
2767 if (!*ptr) ptr[1] = 0; /* so the p = ptr + 1 below will exit */
2768 *ptr = 0;
2769 /* Skip over any path part of the specification */
2770 p1 = p;
2771 while (*p1) {
2772 if (*p1 == '/') p = p1 + 1;
2773 p1++;
2774 }
2775 TXLoadPackage( p );
2776 p = ptr + 1;
2777 }
2778 }
2779 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN,
2780 "TXdocumentstyle", (char *)0 );
2781 strcat( preamble, "{" );
2782 strcat( preamble, curtok );
2783 strcat( preamble, "}\n" );
2784 p = strrchr( curtok, '/' );
2785 if (!p) p = curtok;
2786 else p++;
2787 if (strcmp( p, "linfoem" ) == 0) {
2788 TXStyleLatexInfo( TeXlist, fpin[curfile], fpout );
2789 }
2790 POPCURTOK;
2791 }
2792
TXdocumentclass(TeXEntry * e)2793 void TXdocumentclass( TeXEntry *e )
2794 {
2795 static char name[] = "documentclass";
2796 TXdocumentstyle( e );
2797 documentcmd = name;
2798 }
2799
2800 /* Code for the title etc */
2801 #define MAX_TITLE 1000
2802 #define MAX_AUTHOR 1000
2803 static char TitleString[MAX_TITLE], AuthorString[MAX_AUTHOR];
TXtitle(TeXEntry * e)2804 void TXtitle( TeXEntry *e )
2805 {
2806 if (DebugCommands)
2807 fprintf( stdout, "Getting argument for %s\n", e->name );
2808 TeXMustGetArg( fpin[curfile], TitleString, MAX_TITLE, "TXtitle", e->name );
2809 }
2810
TXauthor(TeXEntry * e)2811 void TXauthor( TeXEntry *e )
2812 {
2813 if (DebugCommands)
2814 fprintf( stdout, "Getting argument for %s\n", e->name );
2815 TeXMustGetArg( fpin[curfile], AuthorString, MAX_AUTHOR,
2816 "TXauthor", e->name );
2817 }
TXdate(TeXEntry * e)2818 void TXdate( TeXEntry *e )
2819 {
2820 if (DebugCommands)
2821 fprintf( stdout, "Getting argument for %s\n", e->name );
2822 PUSHCURTOK;
2823 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXdata", e->name );
2824 POPCURTOK;
2825 }
TeXmaketitle(e)2826 void TeXmaketitle( e )
2827 TeXEntry *e;
2828 {
2829 TXmaketitle( e, TitleString, AuthorString );
2830 }
2831
TXDef(TeXEntry * e)2832 void TXDef( TeXEntry *e )
2833 {
2834 TXAddUserDef( TeXlist, e );
2835 }
TXNewCommand(TeXEntry * e)2836 void TXNewCommand( TeXEntry *e )
2837 {
2838 TXDoNewCommand( TeXlist, e );
2839 }
2840
TXNewLength(TeXEntry * e)2841 void TXNewLength( TeXEntry *e )
2842 {
2843 TXDoNewLength( TeXlist, e );
2844 }
2845
TXURL(TeXEntry * e)2846 void TXURL( TeXEntry *e )
2847 {
2848 PUSHCURTOK;
2849 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXURL", e->name );
2850 TXWriteHyperLink( fpout, curtok, curtok, 0 );
2851 POPCURTOK;
2852 }
2853
TXAURL(TeXEntry * e)2854 void TXAURL( TeXEntry *e )
2855 {
2856 char nametok[512];
2857
2858 PUSHCURTOK;
2859 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXAURL", e->name );
2860 TeXMustGetArg( fpin[curfile], nametok, MAX_TOKEN, "TXAURL", e->name );
2861 TXWriteHyperLink( fpout, nametok, curtok, 0 );
2862 POPCURTOK;
2863 }
2864
TXcite(TeXEntry * e)2865 void TXcite( TeXEntry *e )
2866 {
2867 int urltype;
2868 char *url, *text;
2869 char *p, *pn;
2870
2871 if (DebugCommands)
2872 fprintf( stdout, "Getting argument for %s\n", e->name );
2873 PUSHCURTOK;
2874 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXcite", e->name );
2875 /* Must handle the case of citations separated by commas */
2876 p = curtok;
2877 pn = 0;
2878 TeXoutstr( fpout, CitePrefix );
2879 while (p) {
2880 pn = strchr( p, ',' );
2881 if (pn) {
2882 *pn = 0;
2883 pn++;
2884 }
2885 if (RefMapLookup( "cite", p, &url, &urltype, &text )) {
2886 /* Found a hypertext reference */
2887 TXWriteHyperLink( fpout, text, url, urltype );
2888 }
2889 else if (BibLookup( p, &url, &text )) {
2890 /* code to handle a jump to the destination name returned */
2891 TXWriteHyperLink( fpout, text, url, urltype );
2892 }
2893 else {
2894 fprintf( fpout, "(ref %s)", p );
2895 fprintf( ferr, "citation to %s has no hyperlink\n", p );
2896 }
2897 p = pn;
2898 if (p)
2899 TeXoutstr( fpout, "," );
2900 }
2901 TeXoutstr( fpout, CiteSuffix );
2902
2903 /* \hcitea has a second argument that is used in the LaTeX version as the
2904 replacement text */
2905 if (e->nargs > 1) {
2906 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXhcite", e->name );
2907 }
2908 POPCURTOK;
2909 }
2910
2911 /*
2912 * Process catcode commands
2913 * \catcode<char>=code or \catcode`\<char>=code or \catcode`<char>=code
2914 *
2915 * Note that since a typical use is
2916 * \bgroup\catcode.... \egroup
2917 * we need to implement the full stack semantics of TeX scoping when
2918 * processing groups
2919 */
TXcatcode(TeXEntry * e)2920 void TXcatcode( TeXEntry *e )
2921 {
2922 char c, codetoken[21];
2923 int code, nsp;
2924
2925 if (IgnoreCatcode) return;
2926
2927 /* Read char */
2928 c = SCTxtGetChar( fpin[curfile] );
2929 if (c == '`') {
2930 c = SCTxtGetChar( fpin[curfile] );
2931 if (c == '\\') {
2932 c = SCTxtGetChar( fpin[curfile] );
2933 }
2934 }
2935 /* Read code */
2936 c = SCTxtGetChar( fpin[curfile] );
2937 if (c != '=') {
2938 fprintf( stderr, "Missing = in \\catcode command, %s line %d\n",
2939 InFName[curfile] ? InFName[curfile]: "",
2940 LineNo[curfile] );
2941 return;
2942 }
2943 SCTxtFindNextANToken( fpin[curfile], codetoken, 20, &nsp );
2944 code = atoi(codetoken);
2945
2946 /* Now, change the relevant character to the given class */
2947 switch (code) {
2948 case 1: /* begin group */
2949 break;
2950 case 2: /* end group */
2951 break;
2952 case 3: /* math shift */
2953 break;
2954 case 4: /* alignment tab */
2955 break;
2956 case 5: /* end of line */
2957 break;
2958 case 6: /* macro parameter character */
2959 break;
2960 case 7: /* superscript */
2961 break;
2962 case 8: /* subscript */
2963 break;
2964 case 9: /* Null */
2965 break;
2966 case 10: /* Blank space */
2967 break;
2968 case 11: /* Letters */
2969 break;
2970 case 12: /* Other */
2971 break;
2972 case 13: /* active */
2973 break;
2974 case 14: /* comment */
2975 break;
2976 case 15: /* invalid */
2977 break;
2978 default:
2979 fprintf( stderr,
2980 "Unrecognized code %d for %c in \\catcode command, %s line %d\n",
2981 code, c,
2982 InFName[curfile] ? InFName[curfile]: "",
2983 LineNo[curfile] );
2984 }
2985 return;
2986 }
2987
2988 /*
2989 This is a version of "output token" that makes a final check for a known
2990 name. If found, the hyperlink in inserted in its place
2991 */
2992 static char activetok[MAX_TOKEN];
2993 static int lasttok = 0;
2994 static int breakchar[256];
TXinitbreaktable(void)2995 void TXinitbreaktable( void )
2996 {
2997 int i;
2998 for (i=0; i<256; i++) {
2999 breakchar[i] = 0;
3000 if (isalnum((char)(i))) breakchar[i] = 1;
3001 }
3002 /* Add underscore */
3003 breakchar['_'] = 1;
3004 }
3005
TXoutactiveToken(char * token)3006 void TXoutactiveToken( char *token )
3007 {
3008 int urltype;
3009 char *url, *text;
3010
3011 /*
3012 * First, tokenize the output and check each token. Special case:
3013 * if we reach the end of the string without a "break" character, we must
3014 * delay processing until we get the break character, since the token may
3015 * be incomplete (for example, MPI_Send may be delivered to this
3016 * routine as MPI, then _, then Send.
3017 *
3018 * We must also be careful to skip over commands (TOK_START to TOK_END).
3019 */
3020 while (*token) {
3021 /* This really needs to tokenize the string */
3022 if (breakchar[(int)*token]) {
3023 /* The character is a "alphanum" */
3024 while (*token && breakchar[(int)*token]) {
3025 activetok[lasttok++] = *token++;
3026 if (lasttok >= MAX_TOKEN) {
3027 activetok[MAX_TOKEN-1] = 0;
3028 fprintf( stderr, "Token too long (%s)=n", activetok );
3029 return;
3030 }
3031 }
3032 activetok[lasttok] = 0;
3033 /* If we ended at a alnum-like token, don't output yet. */
3034 if (*token == 0) break;
3035 }
3036 else {
3037 /* If there is already something in the token buffer,
3038 drain it first */
3039 if (lasttok == 0) {
3040 /* Skip over the non-alphanum characters */
3041 if ((unsigned char)(*token) == TOK_START &&
3042 lasttok < MAX_TOKEN) {
3043 while (*token && (unsigned char)(*token) != TOK_END) {
3044 activetok[lasttok++] = *token++;
3045 }
3046 }
3047 else {
3048 while (*token && !breakchar[(int)*token] &&
3049 (unsigned char )(*token) != TOK_START &&
3050 lasttok < MAX_TOKEN) {
3051 activetok[lasttok++] = *token++;
3052 }
3053 }
3054 if (lasttok >= MAX_TOKEN) {
3055 activetok[MAX_TOKEN-1] = 0;
3056 fprintf( stderr, "Token too long (%s)=n", activetok );
3057 return;
3058 }
3059 activetok[lasttok] = 0;
3060 }
3061 }
3062 if (DoActiveTokens &&
3063 RefMapLookup( "man", activetok, &url, &urltype, &text )) {
3064 TXWriteHyperLink( fpout, text, url, urltype );
3065 }
3066 else {
3067 WriteString( fpout, activetok );
3068 }
3069 /* We've flushed the token */
3070 lasttok = 0;
3071 }
3072 }
3073
3074 /*
3075 * Process a Postscript or Encapsulated Postscript image.
3076 */
3077 static char imagefile[256];
3078 static char imgoutfile[256];
3079 static int AlwaysMakeNewGif = 0;
3080 static int DebugImages = 1;
TXepsfbox(TeXEntry * e)3081 void TXepsfbox( TeXEntry *e )
3082 {
3083 char *p;
3084 FILE *fp;
3085 char fname[256];
3086 int found_gif;
3087
3088 if (DebugCommands)
3089 fprintf( stdout, "Getting argument for %s\n", e->name );
3090 PUSHCURTOK;
3091 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXepsfbox", e->name );
3092
3093 /* Save the filename */
3094 strncpy( imagefile, curtok, sizeof(imagefile) );
3095
3096 /* Modify curtok by changing .ps or .eps to .gif */
3097 p = curtok + strlen(curtok) - 1;
3098 while (p > curtok && *p != '.') p--;
3099 strcpy( p+1, "gif" );
3100
3101 /* out file is the file without the directory */
3102 p = curtok;
3103 strncpy( imgoutfile, curtok, sizeof(imgoutfile) );
3104 while (*p) {
3105 if (p[0] == '/') strncpy( imgoutfile, p + 1, sizeof(imgoutfile) );
3106 p++;
3107 }
3108 /* Here are the file names:
3109 imagefile - original source file name
3110 curtok - the same as imagefile, but with .gif extension
3111 imgoutfile - the same as curtok, but without the directories
3112 fname - outputdirectory/imgoutfile
3113
3114 i.e., if imagefile = /home/foo/bar.eps, then
3115 curtok = /home/foo/bar.gif
3116 imgoutfile = bar.gif
3117
3118 Here are the rules for deciding whether to use an existing filename
3119 if (!AlwaysMakeNewGif)
3120 if (destdir/imgoutfile exists and is newer than imagefile)
3121 use destdir/imgoutfile (nothing to do)
3122 else if (curtok exists and is newer than imagefile)
3123 copy curtok to destdir
3124 if (no file yet, then try to generate one)
3125 */
3126
3127 /* Create the final output file name */
3128 if (splitlevel >=0)
3129 sprintf( fname, "%s/%s", splitdir, imgoutfile );
3130 else
3131 sprintf( fname, "./%s", imgoutfile );
3132 found_gif = 0;
3133 if (!AlwaysMakeNewGif) {
3134 if (DebugImages) {
3135 printf( "Checking for file %s (%s)\n",
3136 fname, SYiFileExists( fname, 'r' ) ? "Exists" : "Missing" );
3137 printf( "%s is %s than %s\n", fname,
3138 SYFileNewer( fname, imagefile ) ? "newer" : "older",
3139 imagefile );
3140 }
3141 if (SYiFileExists( fname, 'r' ) && SYFileNewer( fname, imagefile )) {
3142 /* The file we need is already where we need it */
3143 if (DebugImages) printf( "Found gif file %s\n", imagefile );
3144 found_gif = 1;
3145 }
3146 else {
3147 if (DebugImages) {
3148 printf( "Check for file %s (%s)\n",
3149 curtok, SYiFileExists( curtok, 'r' ) ? "Exists" : "Missing" );
3150 printf( "%s is %s than %s\n", curtok,
3151 SYFileNewer( curtok, imagefile ) ? "newer" : "older",
3152 imagefile );
3153 }
3154 if (SYiFileExists( curtok, 'r' ) &&
3155 SYFileNewer( curtok, imagefile )) {
3156 char tmpbuf[1024];
3157 if (DebugImages) printf( "Using %s for image\n", curtok );
3158 /* GIF version of file is in same directory as source file */
3159 sprintf( tmpbuf, "/bin/cp -f %s %s", curtok, fname );
3160 system( tmpbuf );
3161 found_gif = 1;
3162 }
3163 }
3164 }
3165 if (found_gif) {
3166 if (DebugImages) printf( "Using %s\n", imgoutfile );
3167 TXimage( e, imgoutfile );
3168 }
3169 else {
3170 #ifdef OLDEPSF
3171 /* See if the file exists */
3172 if (splitlevel >= 0) {
3173 /* first, is the file in the destination directory ? */
3174 sprintf( fname, "%s/%s", splitdir, imgoutfile );
3175 fp = fopen( fname, "r" );
3176 if (!fp) {
3177 /* Is it in the CURRENT directory */
3178 fp = fopen( imgoutfile, "r" );
3179 if (fp) {
3180 sprintf( fname, "/bin/cp -f %s %s", imgoutfile, splitdir );
3181 system( fname );
3182 }
3183 }
3184 }
3185 else {
3186 fp = fopen( imgoutfile, "r" );
3187 }
3188 if (fp) {
3189 fclose(fp);
3190 TXimage( e, imgoutfile );
3191 }
3192 else {
3193 #endif
3194 /* Try to generate it on the fly */
3195 #ifndef __MSDOS__
3196 char pgm[1024];
3197
3198 if (DebugImages) printf( "Attempting to create gif image file\n" );
3199 fp = fopen( imagefile, "r" );
3200 if (fp) {
3201 fclose( fp );
3202 sprintf( pgm, "%spstogif %s %s figure > /dev/null",
3203 PSPATH, imagefile, imgoutfile );
3204 system( pgm );
3205 /* The output of this is imgoutfile, not curtok */
3206 /* (was fopen( curtok, "r" )) */
3207 fp = fopen( imgoutfile, "r" );
3208 if (fp) {
3209 fclose( fp );
3210 if (splitlevel >= 0) {
3211 sprintf( pgm, "/bin/mv %s %s", imgoutfile, splitdir );
3212 system( pgm );
3213 }
3214 TXimage( e, imgoutfile );
3215 POPCURTOK;
3216 return;
3217 }
3218 }
3219 #endif
3220 fprintf( stderr, "No file %s available for image\n", curtok );
3221 fprintf( stderr, "(Could not open %s)\n", imagefile );
3222 TXbgroup( e );
3223 TXbf( e );
3224 TeXoutstr( fpout, "Image file " );
3225 TeXoutstr( fpout, imgoutfile );
3226 TeXoutstr( fpout, " to be provided..." );
3227 TXegroup( e );
3228 TXWriteStartNewLine( fpout );
3229 }
3230 POPCURTOK;
3231 }
3232
3233 /* psfig is like epsfbox, but with a different syntax */
3234 /* It also supports things that epsf doesn't, like angle commands */
3235 /* What we need to do is this:
3236 Find file= for figure= for the filename
3237 Find any angle= , bbllx=, bblly=, bburx=, bbury= commands
3238 (there are still others but these will do)
3239 If angle is not 0, then create a new file with
3240 angle rotate
3241 dx dy translate
3242 as the first commands, where
3243 dx and dy are choosen to make the picture fit in positive coords.
3244 Note that the new bounding box, after rotation, has
3245 corners with coords (x cos angle - y sin angle, y sin angle + y cos angle)
3246 (corner at (x,y) before rotation.
3247 Take the min x of these, and set dx = -(min x)
3248 Set dx as -(min y)
3249 (adjust if the bounding box doesn't start at (0,0).
3250 */
3251
3252 void TXpsfig( TeXEntry *e )
3253 {
3254 char *p, *fname;
3255
3256 if (DebugCommands)
3257 fprintf( stdout, "Getting argument for %s\n", e->name );
3258 PUSHCURTOK;
3259 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXpsfig", e->name );
3260
3261 p = curtok;
3262 /* Look for file= and figure= */
3263 /* Should look for xxxx= and then parse the xxxx */
3264 while (p && strncmp( p, "figure=", 7 ) != 0 &&
3265 strncmp( p, "file=", 5 ) != 0) {
3266 p = strchr( p, ',' );
3267 if (p) p++;
3268 }
3269 if (p) {
3270 /* get to the equal */
3271 p = strchr( p, '=' ) + 1;
3272 fname = p;
3273 p = strchr( p, ',' );
3274 if (p) *p = 0;
3275 SCPushToken( "}" );
3276 SCPushToken( fname );
3277 SCPushToken( "\\epsfbox{" );
3278 }
3279 else {
3280 fprintf( ferr, "Could not find file name for \\psfig command\n" );
3281 }
3282 POPCURTOK;
3283 }
3284
3285 /* FIXME: Add
3286
3287 includegraphics[width=dim]{filename}
3288
3289 File name may be missing the extension, in which case assume pdf
3290 */
3291
3292 void TXincludegraphics( TeXEntry *e )
3293 {
3294 int rc;
3295
3296 /* See if there is an option argument (which we'll ignore for now) */
3297 PUSHCURTOK;
3298 if (TeXGetGenArg( fpin[curfile], curtok, MAX_TOKEN, '[', ']', 1 ) == 1) {
3299 /* Use this to process any arguments that we might need with
3300 the picture */
3301 #if 0
3302 static char name[] = "includegraphics";
3303 char *p, *ptr, *p1;
3304 p = curtok;
3305 while (*p) {
3306 /* Look for known commands */
3307 ptr = p;
3308 while (*ptr && *ptr != ',') ptr++;
3309 if (!*ptr) ptr[1] = 0; /* so the p = ptr + 1 below will exit */
3310 *ptr = 0;
3311 /* Skip over any path part of the specification */
3312 p1 = p;
3313 while (*p1) {
3314 if (*p1 == '/') p = p1 + 1;
3315 p1++;
3316 }
3317 p = ptr + 1;
3318 }
3319 #endif
3320 }
3321 /* Get the file name */
3322 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN,
3323 "TXincludegraphics", (char *)0 );
3324 /* Try to find the file */
3325 rc = SYFindFileWithExtension( curtok, "gif:eps:pnm:ps:pdf" );
3326 if (rc == 1) {
3327 /* We may need to convert the file to one that can be displayed */
3328 rc = TXConvertFigureToGIF( curtok );
3329 if (rc == 1) {
3330 TXimage( 0, curtok );
3331 }
3332 else {
3333 fprintf( stderr, "Unable to convert %s to .gif\n", curtok );
3334 }
3335 }
3336 else {
3337 fprintf( stderr, "Cannot find graphics file %s\n", curtok );
3338 }
3339
3340 POPCURTOK;
3341 }
3342
3343 /* Process an animation entry. args are {mpg}{gif}{text} */
3344
3345 static char mpgtoken[256], giftoken[256];
3346
3347 void TXanimation( TeXEntry *e )
3348 {
3349 TeXMustGetArg( fpin[curfile], mpgtoken, 256, "TXanimation", e->name );
3350 TeXMustGetArg( fpin[curfile], giftoken, 256, "TXanimation", e->name );
3351 PUSHCURTOK;
3352 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN, "TXanimation", e->name );
3353 TXmovie( e, mpgtoken, giftoken, curtok );
3354 POPCURTOK;
3355 TXWriteStartNewLine( fpout );
3356 }
3357
3358 /* Initialization code */
3359 void TXInsertName( SRList *list, const char *name, void (*action)( TeXEntry *),
3360 int nargs, void *ctx )
3361 {
3362 LINK *l;
3363 int d;
3364 TeXEntry *new;
3365
3366 l = SRInsert( list, name, (char *)0, &d );
3367 new = NEW(TeXEntry); CHKPTR(new);
3368 l->priv = (void *)new;
3369 new->action = action;
3370 new->ctx = ctx;
3371 new->nargs = nargs;
3372 new->name = l->topicname;
3373 }
3374
3375 /*
3376 Initialize the TeX commands. This adds ONLY the ones that are
3377 not set by the basedefs.txt file.
3378 */
3379 void TXInit( FILE *fin, FILE *fout )
3380 {
3381 if (!TeXlist)
3382 TeXlist = SRCreate();
3383
3384 /* Insert the known LaTeXinfo commands into the table for processing */
3385
3386 TXInsertName( TeXlist, "def", TXDef, 0, (void *)0 );
3387 /* gdef should eventually be different */
3388 TXInsertName( TeXlist, "gdef", TXDef, 0, (void *)0 );
3389 TXInsertName( TeXlist, "let", TXlet, 0, (void *)0 );
3390 TXInsertName( TeXlist, "newcommand", TXNewCommand, 0, (void *)0 );
3391 TXInsertName( TeXlist, "newlength", TXNewLength, 0, (void *)0 );
3392 TXInsertName( TeXlist, "renewcommand", TXNewCommand, 0, (void *)0 );
3393 TXInsertName( TeXlist, "newenvironment", TXDoNewenvironment, 0, (void *)0 );
3394 TXInsertName( TeXlist, "renewenvironment", TXDoNewenvironment, 0, (void *)0 );
3395 TXInsertName( TeXlist, "newtheorem", TXDoNewtheorem, 0, (void *)0 );
3396 TXInsertName( TeXlist, "renewtheorem", TXDoNewtheorem, 0, (void *)0 );
3397
3398 TXInsertName( TeXlist, "obeylines", TXDoObeylines, 0, (void *)0 );
3399
3400 /* LaTeX conditionals */
3401 TXInsertName( TeXlist, "newif", TXNewif, 0, (void *)0 );
3402 TXInsertName( TeXlist, "else", TXElse, 0, (void *)0 );
3403 TXInsertName( TeXlist, "fi", TXFi, 0, (void *)0 );
3404
3405 /* Font controls. Old forms first */
3406 TXInsertName( TeXlist, "rm", TXrm, 0, (void *)0 );
3407 TXInsertName( TeXlist, "bf", TXbf, 0, (void *)0 );
3408 TXInsertName( TeXlist, "em", TXem, 0, (void *)0 );
3409 TXInsertName( TeXlist, "it", TXem, 0, (void *)0 );
3410 TXInsertName( TeXlist, "tt", TXtt, 0, (void *)0 );
3411 TXInsertName( TeXlist, "sf", TXsf, 0, (void *)0 );
3412
3413 TXInsertName( TeXlist, "label", TXlabel, 1, (void *)0 );
3414 TXInsertName( TeXlist, "ref", TXref, 1, (void *)0 );
3415
3416 TXInsertName( TeXlist, "pageref", TXref, 1, (void *)0 );
3417 TXInsertName( TeXlist, "documentstyle", TXdocumentstyle, 1, (void *)0 );
3418 TXInsertName( TeXlist, "documentclass", TXdocumentclass, 1, (void *)0 );
3419 TXInsertName( TeXlist, "usepackage", TXusepackage, 1, (void *)0 );
3420 TXInsertName( TeXlist, "title", TXtitle, 1, (void *)0 );
3421 TXInsertName( TeXlist, "author", TXauthor, 1, (void *)0 );
3422 TXInsertName( TeXlist, "date", TXdate, 1, (void *)0 );
3423 TXInsertName( TeXlist, "bullet", TXoutbullet, 0, (void *)0 );
3424
3425 TXInsertName( TeXlist, "index", TXindex, 1, (void *)0 );
3426 TXInsertName( TeXlist, "makeindex", TXmakeindex, 0, (void *)0 );
3427
3428 /* These should eventually process the TeX stack */
3429 TXInsertName( TeXlist, "bgroup", TXbgroup, 0, (void *)0 );
3430 TXInsertName( TeXlist, "egroup", TXegroup, 0, (void *)0 );
3431
3432 TXInsertName( TeXlist, "[", TXmath, 0, (void *)0 );
3433 TXInsertName( TeXlist, "]", TXmathend, 0, (void *)0 );
3434 if (LatexUnknownEnvs || LatexMath) {
3435 /* Need to change this... */
3436 TXInsertName( TeXlist, "(", TXmathmode, 0, (void *)0 );
3437 TXInsertName( TeXlist, ")", TXnop, 0, (void *)0 );
3438 TXInsertName( TeXlist, "[", TXmathmode, 0, (void *)0 );
3439 /* "]" is handled by TXmathmode... */
3440 TXInsertName( TeXlist, "]", TXnop, 0, (void *)0 );
3441 }
3442 else {
3443 TXInsertName( TeXlist, "(", TXinlinemath, 0, (void *)0 );
3444 TXInsertName( TeXlist, ")", TXinlinemathend, 0, (void *)0 );
3445 TXInsertName( TeXlist, "[", TXmath, 0, (void *)0 );
3446 TXInsertName( TeXlist, "]", TXmathend, 0, (void *)0 );
3447 }
3448 TXInsertName( TeXlist, "cite", TXcite, 0, (void *)0 );
3449 /* hcite is like cite, but it doesn't show up in LaTeX slides done with
3450 "header" */
3451 TXInsertName( TeXlist, "hcite", TXcite, 1, (void *)0 );
3452 TXInsertName( TeXlist, "hcitea", TXcite, 2, (void *)0 );
3453 TXInsertName( TeXlist, "maketitle", TeXmaketitle, 0, (void *)0 );
3454 TXInsertName( TeXlist, "include", TXinclude, 1, (void *)0 );
3455 TXInsertName( TeXlist, "input", TXinclude, 1, (void *)0 );
3456 TXInsertName( TeXlist, "IfFileExists", TXIfFileExists, 3, (void *)0 );
3457 TXInsertName( TeXlist, "char", TXchar, 0, (void *)0 );
3458 TXInsertName( TeXlist, "bibitem", TXbibitem, 1, (void *)0 );
3459
3460 /* These two are specific to latexinfo, but I'm using these in other
3461 situations */
3462 TXInsertName( TeXlist, "code", TXcode, 1, (void *)0 );
3463 TXInsertName( TeXlist, "verb", TXverb, 0, (void *)0 );
3464 TXInsertName( TeXlist, "file", TXfile, 1, (void *)0 );
3465
3466 /* Question: should part be 0, chapter 1, etc? */
3467 TXInsertName( TeXlist, "part", TXsection, 1, (void *)0 );
3468 TXInsertName( TeXlist, "chapter", TXsection, 1, (void *)0 );
3469 TXInsertName( TeXlist, "section", TXsection, 1, (void *)1 );
3470 TXInsertName( TeXlist, "subsection", TXsection, 1, (void *)2 );
3471 TXInsertName( TeXlist, "subsubsection", TXsection, 1, (void *)3 );
3472 TXInsertName( TeXlist, "subsubsubsection", TXsection, 1, (void *)4 );
3473
3474 /* Paragraph and subparagraph are sort of like sections, but they
3475 should not generate contents or links */
3476 TXInsertName( TeXlist, "paragraph", TXparagraph, 1, (void *)0 );
3477 TXInsertName( TeXlist, "subparagraph", TXparagraph, 1, (void *)1 );
3478
3479 /*
3480 TXInsertName( TeXlist, "paragraph", TXsection, 1, (void *)4 );
3481 TXInsertName( TeXlist, "subparagraph", TXsection, 1, (void *)5 );
3482 */
3483
3484 /* TeX commands to change what is allowed in a command name */
3485 TXInsertName( TeXlist, "makeatletter", TXatletter, 0, (void *)0 );
3486 TXInsertName( TeXlist, "makeatother", TXatother, 0, (void *)0 );
3487
3488 TXInsertName( TeXlist, "advance", TXadvance, 0, (void *)0 );
3489
3490 /* TeX commands that take numbers that should be ignored */
3491 TXInsertName( TeXlist, "penalty", TXnumber, 0, (void *)0 );
3492 TXInsertName( TeXlist, "hangafter", TXcounter, 0, (void *)0 );
3493
3494 TXInsertName( TeXlist, "begin", TXbegin, 1, (void *)0 );
3495 TXInsertName( TeXlist, "end", TXend, 1, (void *)0 );
3496 TXInsertName( TeXlist, "item", TXitem, 1, (void *)0 );
3497 /* TXInsertName( TeXlist, "bitmap", TXbitmap, 1, (void *)0 ); */
3498 TXInsertName( TeXlist, "\\", TXdoublebw, 0, (void *)0 );
3499 TXInsertName( TeXlist, "newline", TXnewline, 0, (void *)0 );
3500 /* Note that a \linebreak can have an optional argument (the desirability
3501 of a line break) */
3502 TXInsertName( TeXlist, "linebreak", TXnewline, 0, (void *)0 );
3503 TXInsertName( TeXlist, "bw", TXbw, 0, (void *)0 );
3504 TXInsertName( TeXlist, "back", TXbw, 0, (void *)0 );
3505
3506 /* \- is usually a discretionary hyphen */
3507 /* setlength needs to eat the first argument without evaluation;
3508 we don't do that yet. */
3509 TXInsertName( TeXlist, "setlength", TXnop, 2, (void *)0 );
3510 TXInsertName( TeXlist, "bibliography", TXDoBibliography, 1, (void *)0 );
3511 TXInsertName( TeXlist, "cleardoublepage", TXnop, 0, (void *)0 );
3512 TXInsertName( TeXlist, "today", TXtoday, 0, (void *)0 );
3513 TXInsertName( TeXlist, "vspace", TXnopStar, 1, (void *)0 );
3514 TXInsertName( TeXlist, "hspace", TXnopStar, 1, (void *)0 );
3515
3516 /* Be prepared for center environment */
3517 /* TXInsertName( TeXlist, "centerline", TeXCenterline, 1, (void *)0 );*/
3518 /* Just copy the arguments */
3519 TXInsertName( TeXlist, "caption", TXcaption, 1, (void *)0 );
3520
3521 /* Boxes need to look for "to size" arguments ????????? */
3522 TXInsertName( TeXlist, "hbox", TXbox, 0, (void *)0 );
3523 TXInsertName( TeXlist, "vbox", TXbox, 0, (void *)0 );
3524
3525 TXInsertName( TeXlist, "{", TXbbrace, 0, (void *)0 );
3526 TXInsertName( TeXlist, "}", TXebrace, 0, (void *)0 );
3527 if (!DestIsHtml)
3528 TXInsertName( TeXlist, "par", TXname, 0, TXCopy("par") );
3529 else
3530 TXInsertName( TeXlist, "par", TXnewline, 0, (void *)0 );
3531
3532 if (DestIsHtml) {
3533 char buf[10];
3534 buf[0] = TOK_START;
3535 strcpy( buf+1, "&" );
3536 buf[6] = TOK_END;
3537 buf[7] = 0;
3538 TXInsertName( TeXlist, "&", TXname, 0, TXCopy(buf) );
3539 }
3540 else
3541 TXInsertName( TeXlist, "&", TXname, 0, TXCopy("&") );
3542
3543 {
3544 char buf[4];
3545 buf[0] = TOK_START;
3546 buf[1] = '%';
3547 buf[2] = TOK_END;
3548 buf[3] = 0;
3549 TXInsertName( TeXlist, "%", TXname, 0, TXCopy(buf) );
3550 }
3551 /* Process \<space> and \<newline> as a single space */
3552 TXInsertName( TeXlist, " ", TXname, 0, TXCopy(" ") );
3553 TXInsertName( TeXlist, "\n", TXname, 0, TXCopy(" ") );
3554
3555 TXInsertName( TeXlist, "times", TXname, 0, TXCopy(" x ") );
3556
3557 TXInsertName( TeXlist, "fileinclude", TXfileinclude, 1, (void *)0 );
3558
3559 /* Slide commands */
3560 TXInsertName( TeXlist, "vt", TXvt, 0, (void *)1 );
3561 TXInsertName( TeXlist, "vtitle", TXvtt, 1, (void *)0 );
3562 TXInsertName( TeXlist, "vtt", TXvtt, 1, (void *)1 );
3563 TXInsertName( TeXlist, "vtts", TXvtt, 1, (void *)2 );
3564 TXInsertName( TeXlist, "vttss", TXvtt, 1, (void *)3 );
3565 TXInsertName( TeXlist, "vttsss", TXvtt, 1, (void *)4 );
3566 TXInsertName( TeXlist, "vttssss", TXvtt, 1, (void *)5 );
3567 TXInsertName( TeXlist, "vttsssss", TXvtt, 1, (void *)6 );
3568 TXInsertName( TeXlist, "href", TXhref, 1, (void *)0 );
3569 TXInsertName( TeXlist, "hrefa", TXhref, 2, (void *)0 );
3570 TXInsertName( TeXlist, "details", TXdetails, 1, (void *)0 );
3571
3572 /* Stuff generated by bibligraphy files */
3573 TXInsertName( TeXlist, "bibitem", TXbibitem, 1, (void *)0 );
3574
3575 /* Hypertext */
3576 TXInsertName( TeXlist, "URL", TXURL, 1, (void *)0 );
3577 TXInsertName( TeXlist, "AURL", TXAURL, 2, (void *)0 );
3578
3579 /* TeX accents */
3580 InitAccents();
3581
3582 /* HTML Tables */
3583 if (HandleAlign)
3584 InitTabular();
3585
3586 /* Initialize the name of the error output file */
3587 GetBaseName( latex_errname );
3588 strcat( latex_errname, ".ler" );
3589 }
3590
3591 void TeXProcessCommand( char *token, FILE *fin, FILE *fout )
3592 {
3593 LINK *l;
3594 TeXEntry *e;
3595 int i;
3596
3597 if (DebugCommands)
3598 fprintf( stdout, "Handling Command %s\n", token );
3599 l = SRLookup( TeXlist, token, token, &i );
3600 if (!l) {
3601 if (!AmSkipping) /* && InDocument) */
3602 fprintf( ferr, "Unknown LaTeX command %s, %s line %d\n",
3603 token,
3604 InFName[curfile] ? InFName[curfile]: "",
3605 LineNo[curfile] );
3606 /* If next token is {, eat {} until no more {} pairs */
3607 }
3608 else {
3609 e = (TeXEntry *)( l->priv );
3610 (*e->action)( e );
3611 }
3612 }
3613
3614 /* Write out the contents page
3615 * If the header hasn't been written, we need to add it.
3616 */
3617 static int ContentsDepth = 100;
3618 static int WrittenContents = 0;
3619 static char ContentsLocation[256];
3620
3621 void TeXNoContents( void )
3622 {
3623 WrittenContents = 1;
3624 }
3625 char *ContentsLoc( void )
3626 {
3627 if (!WrittenContents) return 0;
3628 return ContentsLocation;
3629 }
3630 void TeXWriteContents( FILE *fout )
3631 {
3632 if (WrittenContents) return;
3633 /* WRtoauxfile( 0, outfile, 0, "Contents" ); */
3634
3635 WriteHeadPage( fpout );
3636 WriteFileTitle( fpout, "Contents" );
3637 WriteBeginPage( fpout );
3638
3639 WriteSectionAnchor( fpout, "Contents", "Node", 0, 0 );
3640 if (outfile)
3641 sprintf( ContentsLocation, "%s#Node0", outfile );
3642 else
3643 strcpy( ContentsLocation, "Node0" );
3644 WriteSectionHeader( fpout, "Contents", "Node", 0, (char *)0, 0 );
3645 if (NumChildren( (void *)0 ) > 0 ) {
3646 WriteChildren( fpout, (void *)0, ContentsDepth );
3647 }
3648 CurSeqnum++;
3649 /* At this point, we'd like to generate the title and authors. */
3650 WriteTextHeader( fpout );
3651 /*WRfromauxfile( fout, 0 );*/
3652
3653 /* Switch to writing a new aux file */
3654 OpenWRAuxFile();
3655 WrittenContents = 1;
3656 }
3657
3658 /*
3659 Here is the beginning of a sketch of a routine to process a LaTeXInfo file
3660 */
3661 void ProcessLatexFile( int argc, char **argv, FILE *fin, FILE *fout )
3662 {
3663 int nsp, ch;
3664
3665 fpin[0] = fin;
3666 fpout = fout;
3667
3668 curtok = tokbuf = (char *)MALLOC( MAX_CURTOKS * MAX_TOKEN );
3669 toknum = 0;
3670 CHKPTR(curtok);
3671
3672 TXInit( fin, fout );
3673 ferr = fopen( "latex.err", "w" );
3674
3675 /* Define the symbols to process */
3676 TXinitbreaktable();
3677
3678 /* Try to read info file */
3679 topicctx = SRCreate();
3680 RdAuxFile( topicctx );
3681 /*
3682 SCSetCommentChar( '%' );
3683 */
3684 /* We shouldn't do this until we've seen the maketitle or the first section */
3685 /* Note that this is executed outside of the "begin{document}", so
3686 we have turned off all output here */
3687 PUSHCURTOK;
3688 while (1) {
3689 ch = TeXReadToken( curtok, &nsp );
3690 if (ch == EOF) {
3691 if (curfile > 0) {
3692 if (DebugCommands)
3693 fprintf( stdout, "EOF in ProcessLatexFile\n" );
3694 TXPopFile();
3695 }
3696 else break;
3697 }
3698 if (ch == CommentChar) {
3699 SCTxtDiscardToEndOfLine( fpin[curfile] );
3700 LineNo[curfile]++;
3701 }
3702 else if (ch == CommandChar) {
3703 /* TeXoutsp( fout, nsp ); */
3704 TeXProcessCommand( curtok+1, fpin[curfile], fout );
3705 }
3706 else if (ch == LbraceChar) {
3707 if (BraceCount >= MAX_BLOC) {
3708 TeXAbort( "", "Braces too deep" );
3709 }
3710 strncpy( bloc[BraceCount].filename, InFName[curfile],
3711 MAX_BLOC_FNAME );
3712 bloc[BraceCount++].lineno = LineNo[curfile];
3713 /* fprintf( fout, "**+%d[%d]**",
3714 LineNo[curfile], BraceCount ); */
3715 #ifdef FOO
3716 push stack (font, spacing parameters);
3717 #endif
3718 }
3719 else if (ch == RbraceChar) {
3720 BraceCount--;
3721 /* fprintf( fout, "**-%d[%d]**",
3722 LineNo[curfile], BraceCount ); */
3723 #ifdef FOO
3724 pop stack;
3725 #endif
3726 }
3727 else if (ch == AlignChar && HandleAlign) {
3728 TeXPutAlign();
3729 }
3730 else if (ch == ActiveChar) {
3731 TXActiveCharDo(curtok);
3732 }
3733 else {
3734 /*
3735 for (i=0; i<nsp; i++) fputs( " ", fout );
3736 if (ch == '\n' && lSp >= 0)
3737 (*lstack[lSp].newline)( fout );
3738 else
3739 fputs( curtok, fout );
3740 */
3741 }
3742 }
3743 POPCURTOK;
3744 WriteEndofTopic( fout );
3745 fclose( ferr );
3746 if (0)
3747 PrintAllContents(stdout);
3748 if (BraceCount != 0) {
3749 fprintf( stderr, "Brace count = %d\n", BraceCount );
3750 if (BraceCount > 0) {
3751 int ii;
3752 for (ii=0; ii<BraceCount; ii++)
3753 fprintf( stderr, "Unmatched brace near line %d in file %s\n",
3754 bloc[ii].lineno, bloc[ii].filename );
3755 }
3756 }
3757
3758 FREE( tokbuf );
3759 }
3760
3761 /* Manage the citation characters */
3762 void TXSetCitePrefix( char *s )
3763 {
3764 if (CitePrefix) FREE( CitePrefix );
3765 CitePrefix = STRDUP( s );
3766 CHKPTR(s);
3767 }
3768
3769 void TXSetCiteSuffix( char *s )
3770 {
3771 if (CiteSuffix) FREE( CiteSuffix );
3772 CiteSuffix = STRDUP( s );
3773 CHKPTR(s);
3774 }
3775
3776 /*
3777 * Print strings that may contain TOK_START/TOK_END sequences
3778 */
3779
3780 void TXPrintToken( FILE *fp, const char *str )
3781 {
3782 char c;
3783 while (*str) {
3784 c = *str++;
3785 if ((unsigned char)c == TOK_START) {
3786 fputs( "TOK_START", fp );
3787 }
3788 else if ((unsigned char)c == TOK_END) {
3789 fputs( "TOK_END", fp );
3790 }
3791 else if (isgraph(c) || c == ' ') {
3792 fputc( c, fp );
3793 }
3794 else {
3795 fputc( '^', fp );
3796 /* Make 7 bit */
3797 c = c & 0x7f;
3798 /* make at least space */
3799 if (c < 0x20) c |= 0x40;
3800 /* Delete is at the end of the range */
3801 if (c == 127) c = '?';
3802 fputc( c, fp );
3803 }
3804 }
3805 }
3806
3807 /*
3808 Notes on handling \" etc.
3809 These are tex commands that modify the next character. They should
3810 be thought of a commands that look at the next argument, which, since
3811 it does not start with a {, is a single letter. The mapping to HTML is
3812 (see http://www.hut.fi/~jkorpela/HTML3.2/latin1.html)
3813 \"A Ä Ä
3814 \`A À À
3815 \`E È È
3816 \`I Ì Ì
3817 \"O Ö Ö
3818 \`O Ò Ò
3819 \"U Ü Ü
3820 \"a ä ä
3821 \`a à à
3822 \`e è è
3823 \`i ì ì
3824 \"o ö ö
3825 \`o ò ò
3826 \"u ü ö
3827 \`u ù ù
3828 */
3829 #ifdef FOO
3830 // From TeXSkipEnv. I believe that this code is dead and can
3831 // never be executed
3832
3833 if (InVerbatim) {
3834 if (strcmp( curtok, "end" ) == 0) {
3835 if (DebugCommands)
3836 fprintf( stdout, "Getting argument for end{}\n" );
3837 TeXMustGetArg( fpin[curfile], curtok, MAX_TOKEN,
3838 "TXSkipEnv", e->name );
3839 /* Check for a user-defined environment type */
3840 if (LookupEnv( curtok, &btext, &etext, &nargs)) {
3841 if (etext) {
3842 if (DebugCommands)
3843 fprintf( stdout, "Pushing back |%s|\n", etext );
3844 SCPushToken( etext );
3845 }
3846 }
3847 else if (strcmp( curtok, name ) != 0) {
3848 if (flag)
3849 fprintf( ferr,
3850 "%s does not match %s (started at line %d), at %s line %d\n",
3851 curtok, name, line_num,
3852 InFName[curfile] ? InFName[curfile]: "", LineNo[curfile] );
3853 }
3854 else {
3855 break;
3856 }
3857 }
3858 else {
3859 if (DestIsHtml)
3860 TeXoutstr( fout, "\\" );
3861 else
3862 TeXoutstr( fout, "\\\\" );
3863 TeXoutstr( fout, curtok );
3864 }
3865 }
3866 else {
3867 }
3868 #endif
3869
3870 /* Eventually, we may prefer to use PNM of PNG files */
3871 static int debugF2GIF = 0;
3872
3873 /* Convert fname to GIF. Replace fname with the filename to be used to
3874 include the file in the generated output */
3875 int TXConvertFigureToGIF( char *fname )
3876 {
3877 char *p;
3878 char pgm[2048], fname2[2048];
3879 int rc = 0;
3880
3881 /* Determine the type of the file from the known types (if this
3882 ever gets long, we could use an array of types and methods to convert
3883 to GIF */
3884
3885 if (debugF2GIF)
3886 fprintf( stderr, "Converting file %s\n", fname );
3887
3888 /* Create the result file name. The result name is created from the
3889 basename of the result, with the target directory */
3890 p = fname + strlen(fname) - 1;
3891 /* find the dirctory separator, if any */
3892 while (p != fname && *p != DirSep) p--;
3893 if (*p == DirSep) p++;
3894 if (!splitdir || *splitdir == 0) {
3895 snprintf( fname2, sizeof(fname2), "%s", p );
3896 }
3897 else {
3898 snprintf( fname2, sizeof(fname2), "%s%c%s", splitdir, DirSep, p );
3899 }
3900 p = fname2 + strlen(fname2) - 1;
3901 while (p != fname2 && *p != '.') p--;
3902 *p = 0;
3903 strncpy( p, ".gif", 10 );
3904
3905 if (strstr( fname, ".gif" )) {
3906 if (debugF2GIF)
3907 fprintf( stderr, "Do we need to move %s to %s\n", fname, fname2 );
3908 /* Copy the file into the proper directory if it isn't there */
3909 if (strcmp( fname, fname2 ) != 0) {
3910 snprintf( pgm, sizeof(pgm), "/bin/cp -f %s %s", fname, fname2 );
3911 rc = system( pgm );
3912 if (rc) {
3913 fprintf( stderr, "Error code %d from %s\n", rc, pgm );
3914 return 0;
3915 }
3916 }
3917 p = fname2 + strlen(fname2) - 1;
3918 while (p != fname2 && *p != DirSep) p--;
3919 if (*p == DirSep) p++;
3920 strcpy( fname, p );
3921 return 1;
3922 }
3923
3924
3925 if ( strstr( fname, ".ps" ) != 0) {
3926 if (debugF2GIF) fprintf( stderr, "Converting ps to gif for %s\n",
3927 fname );
3928 /* The figure argument preserves color */
3929 snprintf( pgm, sizeof(pgm), "%spstogif %s %s figure >>%s 2>&1",
3930 PSPATH, fname, fname2, latex_errname );
3931 if (debugF2GIF)
3932 fprintf( stderr, "Running %s\n", pgm );
3933 rc = system( pgm );
3934 if (rc != 0) {
3935 fprintf( stderr, "Error code %d from %s\n", rc, pgm );
3936 return 0;
3937 }
3938 p = fname2 + strlen(fname2) - 1;
3939 while (p != fname2 && *p != DirSep) p--;
3940 if (*p == DirSep) p++;
3941 strcpy( fname, p );
3942 return 1;
3943 }
3944 else if ( strstr( fname, ".eps" ) != 0) {
3945 if (debugF2GIF) fprintf( stderr, "Converting eps to gif for %s\n",
3946 fname );
3947 /* The figure argument preserves color */
3948 snprintf( pgm, sizeof(pgm), "%spstogif %s %s figure >>%s 2>&1",
3949 PSPATH, fname, fname2, latex_errname );
3950 if (debugF2GIF)
3951 fprintf( stderr, "Running %s\n", pgm );
3952 rc = system( pgm );
3953 if (rc != 0) {
3954 fprintf( stderr, "Error code %d from %s\n", rc, pgm );
3955 return 0;
3956 }
3957 p = fname2 + strlen(fname2) - 1;
3958 while (p != fname2 && *p != DirSep) p--;
3959 if (*p == DirSep) p++;
3960 strcpy( fname, p );
3961 return 1;
3962 }
3963 else if ( strstr( fname, ".pnm" ) != 0) {
3964 return 1; /* Will this work? */
3965 }
3966 else if ( strstr( fname, ".pdf" ) != 0) {
3967 if (debugF2GIF) fprintf( stderr, "Converting pdf to gif for %s\n",
3968 fname );
3969 /* Change the output name to a .ps file */
3970 p = fname2 + strlen(fname2) - 1;
3971 while (p != fname2 && *p != '.') p--;
3972 strncpy( p, ".ps", 10 );
3973
3974 /* Remove the file that we're about to create. Ignore errors */
3975 unlink( fname2 );
3976 snprintf( pgm, sizeof(pgm), "pdf2ps %s %s >>%s 2>&1", fname, fname2,
3977 latex_errname );
3978 if (debugF2GIF)
3979 fprintf( stderr, "Running %s\n", pgm );
3980 rc = system( pgm );
3981 if (rc != 0) {
3982 fprintf( stderr, "Error code %d from %s\n", rc, pgm );
3983 return 0;
3984 }
3985 if (debugF2GIF)
3986 fprintf( stderr, "Now, convert %s to gif\n", fname2 );
3987 /* Now convert the postscript file */
3988 rc = TXConvertFigureToGIF( fname2 );
3989 strcpy( fname, fname2 );
3990 return rc;
3991 }
3992 return rc;
3993 }
3994
3995 /* Active character handling */
3996 void TXActiveCharSet( char ch, void (*fcn)(char *) )
3997 {
3998 ActiveChar = ch;
3999 activeCharAction = fcn;
4000 }
4001 void TXActiveCharClear(void)
4002 {
4003 ActiveChar = '\0';
4004 activeCharAction = 0;
4005 }
4006 void TXActiveCharDo(char *str)
4007 {
4008 if (activeCharAction) {
4009 (*activeCharAction)(str);
4010 }
4011 else {
4012 fprintf(stderr, "Attempt to invoke active char action with null action\n");
4013 }
4014 }
4015
4016 void TXObeylinesFlushLine(char *token)
4017 {
4018 if (!InDocument) return;
4019 TeXoutcmd( fpout, "<br>\n" );
4020 }
4021 void TXObeylinesClearActive(void)
4022 {
4023 TXActiveCharClear();
4024 }
4025 /* Obeylines changes the handling of \n until the current group ends */
4026 void TXDoObeylines(TeXEntry *e)
4027 {
4028 TXActiveCharSet('\n', TXObeylinesFlushLine);
4029 TXgroupPushAction(TXObeylinesClearActive);
4030 }
4031