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