1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
2 /*
3  * This file implements a simple if statement, using the LaTeX
4  * \newif\ifname, \nametrue, \namefalse
5  */
6 
7 #include "sowing.h"
8 #include "tex.h"
9 
10 static char iftoken[MAX_TOKEN];
11 
12 void TXDoIf( TeXEntry * );
13 void TXDoIfFalse( TeXEntry * );
14 void TXDoIfTrue( TeXEntry * );
15 void TeXskipUntil( char *([]), int );
16 
17 /*
18  *   Read a newif and define the name
19  */
TXNewif(TeXEntry * e)20 void TXNewif( TeXEntry *e )
21 {
22     int ch, nsp;
23     int *def;
24 
25     ch = TeXReadToken( iftoken, &nsp );
26     if (ch == EOF) return;
27 
28     def = NEW(int); CHKPTR(def);
29     *def = 1;
30     TXInsertName( TeXlist, iftoken + 1, TXDoIf, 0, (void *)def );
31     strcat( iftoken, "false" );
32     TXInsertName( TeXlist, iftoken + 3, TXDoIfFalse, 0, (void *)def );
33     iftoken[strlen(iftoken)-5] = '\0';
34     strcat( iftoken, "true" );
35     TXInsertName( TeXlist, iftoken + 3, TXDoIfTrue, 0, (void *)def );
36 }
37 
38 /* A stack of if values.  For now, we can only handle true values */
39 #define MAX_IF_STACK 30
40 static int if_sp = -1;
41 static int truth[MAX_IF_STACK];
42 
TXDoIf(TeXEntry * e)43 void TXDoIf( TeXEntry *e )
44 {
45     int *def = (int *)(e->ctx);
46     char *(names[2]);
47     names[0] = "else";
48     names[1] = "fi";
49     if (*def) {
50 	/* True branch */
51 	/* Tell \else or \if to be silent */
52 	if (if_sp >= MAX_IF_STACK-1)
53 	    fprintf( stderr, "Too many TeX ifs\n" );
54 	truth[++if_sp] = 1;
55     }
56     else {
57 	/* False branch */
58 	truth[++if_sp] = 0;
59 	/* Skip until we find a \else or \fi */
60 	TeXskipUntil( names, 2 );
61     }
62 }
63 
64 /* Set the if name to false */
TXDoIfFalse(TeXEntry * e)65 void TXDoIfFalse( TeXEntry *e )
66 {
67     int *def = (int *)(e->ctx);
68     *def = 0;
69 }
70 
71 /* Set the if name to true */
TXDoIfTrue(TeXEntry * e)72 void TXDoIfTrue( TeXEntry *e )
73 {
74     int *def = (int *)(e->ctx);
75     *def = 1;
76 }
77 
TXElse(TeXEntry * e)78 void TXElse( TeXEntry *e )
79 {
80     char *(names[1]);
81     /* If in the true branch, then skip, else ignore */
82     if (truth[if_sp]) {
83 	/* Skip and ignore until \fi */
84 	names[0] = "fi";
85 	TeXskipUntil( names, 1 );
86     }
87 }
88 
TXFi(TeXEntry * e)89 void TXFi( TeXEntry *e )
90 {
91     if (if_sp > 0)
92 	if_sp--;
93 }
94 
TeXskipUntil(char * (names[]),int n_names)95 void TeXskipUntil( char *(names[]), int n_names )
96 {
97     int nsp, ch;
98 
99     PUSHCURTOK;
100     while (1) {
101 	while ( (ch = TeXReadToken( curtok, &nsp )) == EOF) {
102 	    if (DebugCommands)
103 		fprintf( stdout, "EOF in TeXskipUntil\n" );
104 	    TXPopFile();
105 	}
106 	if (ch == EOF) break;
107 	if (DebugCommands) {
108 	    fprintf( stdout, "Token is %s\n", curtok );
109 	}
110 	if (ch == CommentChar) {
111 	    /* Handle comments */
112 	    SCTxtDiscardToEndOfLine( fpin[curfile] );
113 	}
114 	else if (ch == CommandChar) {
115 	    int i;
116 	    for (i=0; i<n_names; i++) {
117 		if (strcmp( curtok+1, names[i] ) == 0) {
118 		    if (DebugCommands)
119 			fprintf( stdout, "Found terminator %s\n", names[i] );
120 		    POPCURTOK;
121 		    return;
122 		}
123 	    }
124 	}
125     }
126 }
127 
128 /* Add an easy way to process if commands that are defined in other packages
129    TXAddPredefIf( ifname, istrue )
130  */
TXAddPredefIf(const char * ifname,int isTrue)131 void TXAddPredefIf( const char *ifname, int isTrue )
132 {
133     int *def;
134 
135     def = NEW(int); CHKPTR(def);
136     *def = isTrue;
137     TXInsertName( TeXlist, ifname, TXDoIf, 0, (void *)def );
138     strcpy( iftoken, ifname+2 );
139     strcat( iftoken, "false" );
140     TXInsertName( TeXlist, iftoken, TXDoIfFalse, 0, (void *)def );
141     iftoken[strlen(iftoken)-5] = '\0';
142     strcat( iftoken, "true" );
143     TXInsertName( TeXlist, iftoken, TXDoIfTrue, 0, (void *)def );
144 }
145