1 /* dim.c: main layout/dimentioning routines. */
2
3 /* This file is part of asciiTeX.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 The Free Software Foundation, Inc.
17 59 Temple Place, Suite 330
18 Boston, MA 02111 USA
19
20
21 Authors:
22 Original program (eqascii): Przemek Borys
23 Fork by: Bart Pieters
24
25 *************************************************************************/
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include "asciiTeX_struct.h"
31 #include "parsedef.h"
32 #include "utils.h"
33 #include "frac.h"
34 #include "sscript.h"
35 #include "sqrt.h"
36 #include "ouline.h"
37 #include "symbols.h"
38 #include "brace.h"
39 #include "array.h"
40 #include "limit.h"
41
42 const KEYWORD Keys[] = {
43 {"^{", 2, SUPER},
44 {"_{", 2, SUB},
45 {"\\frac", 5, FRAC},
46 {"\\sqrt", 5, SQRT},
47 {"\\overline", 9, OVERLINE},
48 {"\\underline", 10, UNDERLINE},
49 {"\\limit", 6, LIMIT},
50 {"\\left", 5, BRACES},
51 {"\\begin{array}", 13, ARRAY},
52 {"\\to", 3, TO},
53 {"\\leadsto", 8, LEADSTO},
54 {"\\sum", 4, SUM},
55 {"\\prod", 5, PROD},
56 {"\\int", 4, INT},
57 {"\\oint", 5, OINT},
58 {"\\infty", 6, INFTY},
59 {"\\lceil", 6, LCEIL},
60 {"\\rceil", 6, RCEIL},
61 {"\\lfloor", 7, LFLOOR},
62 {"\\rfloor", 7, RFLOOR},
63 {"\\", 1, ESCAPE},
64 {NULL, ERR}
65 };
66 PRSDEF
LookupKey(char * txt,const KEYWORD * Keys)67 LookupKey(char *txt, const KEYWORD * Keys)
68 {
69 for (; Keys->name; Keys++)
70 {
71 if (strncmp(txt, Keys->name, Keys->len) == 0)
72 break;
73 }
74 return Keys->Nr;
75 }
76
77 char *
findLineEnd(char * txt)78 findLineEnd(char *txt)
79 {
80 int len = strlen(txt);
81 int i;
82 for (i = 0; i < len; i++)
83 {
84 /* return pointer to the next endline */
85 if (strncmp(txt + i, "\\begin", 6) == 0) /* skip nested parts */
86 i = 4 + getbegin_endEnd(txt + i + 6) - txt;
87 else if (strncmp(txt + i, "\\left", 5) == 0)
88 i = 6 + findClosingLRBrace(txt + i + 5) - txt;
89 else if (txt[i] == '{')
90 i = findClosingBrace(txt + i + 1) - txt;
91 else if (txt[i] == '\n')
92 return txt + i;
93
94 }
95 return txt+i; /* no line end found */
96 }
97
98 Tdim
dim(char * txt,struct Tgraph * graph)99 dim(char *txt, struct Tgraph * graph)
100 {
101 /* a linewidth mechanism were cool, i.e. automatic braking of the line */
102 /* baceline should jump current y down, x should be the maximum x of all lines */
103 /* a flag for linebreak should be placed, containing the y jump size */
104 /* so that the draw routines know when to add to y and reset x zo 0 */
105 int i;
106 int len = strlen(txt); /* length of text passed
107 * to parse */
108 Tdim our; /* the dimensions of our current object */
109 char *gpos; /* points to the tree node's text */
110 char *end;
111 PRSDEF K; /* keynumber, result from the
112 * keywordlookup */
113 our.x = 0;
114 our.y = 1;
115 our.baseline = 0;
116 graph->children = 0; /* at the beginning the tree doesn't have
117 * children. We must first find them */
118 graph->txt = (char *) malloc(len + 1); /* allocating the same
119 * length is OK. Special
120 * characters in output
121 * are 2 chars
122 * long--shorter than in
123 * the input */
124 gpos = graph->txt; /* we setup now this pointer */
125 *gpos = 0;
126 if (*(end=findLineEnd(txt))!='\0')
127 {
128 /* the current level contains one or more line ends */
129 /* the current level will become aan array of lines */
130 int nlines=0;
131 char * start=txt;
132 char **lines = (char **) malloc(sizeof(char *));
133 Tdim out;
134 if (SYNTAX_ERR_FLAG==S_ERR)
135 return out;
136 *gpos = 1; /* See parsedef.h for the keyword
137 * definitions */
138 gpos++;
139 *gpos = (char) ARRAY;
140 gpos++;
141 *gpos = 0;
142 newChild(graph);
143 graph->down[graph->children - 1]->options = malloc((2)*sizeof(char));
144 graph->down[graph->children - 1]->options[0] = 'c'; /* default col alignment */
145 graph->down[graph->children - 1]->options[1] = '\0'; /* default col alignment */
146 /* count how many lines we have */
147 while (1)
148 {
149 lines =(char **) realloc(lines,(nlines + 1) * (sizeof(char *)));
150 lines[nlines] = (char *) malloc(end - start + 1);
151 strncpy(lines[nlines], start, end - start);
152 lines[nlines][end - start] = '\0'; /* terminate the string */
153 nlines++;
154 if (*end=='\0')
155 break;
156 start=end+1;
157 end=findLineEnd(start);
158 }
159 /* fill the array with the lines */
160
161 #define Array (graph->down[graph->children-1])
162 Array->array = malloc(sizeof(Tarray));
163 Array->array->rows = nlines;
164 Array->array->cols = 1;
165 Array->array->rowy = (int *) calloc(nlines, sizeof(int));
166 Array->array->colx = (int *) calloc(1, sizeof(int));
167 for (i = 0; i < nlines; i++)
168 {
169 out = dim(lines[i], newChild(Array));
170 if (out.x > Array->array->colx[0])
171 Array->array->colx[0] = out.x;
172 if (out.y > Array->array->rowy[i])
173 Array->array->rowy[i] = out.y;
174 free(lines[i]);
175 }
176 free(lines);
177 Array->dim.x = 0;
178 Array->dim.x += Array->array->colx[0];
179 Array->dim.y = 0;
180 for (i = 0; i < nlines; i++)
181 Array->dim.y += Array->array->rowy[i];
182
183 Array->dim.y += Array->array->rows - 1;
184 Array->dim.x += Array->array->cols - 1;
185
186 Array->dim.baseline = Array->dim.y / 2;
187
188 our.x += Array->dim.x;
189 if (our.baseline < Array->dim.baseline)
190 {
191 our.y += Array->dim.baseline - our.baseline;
192 our.baseline = Array->dim.baseline;
193 }
194 if (our.y < Array->dim.y)
195 our.y = Array->dim.y;
196 #undef Array
197 graph->dim = our;
198 return our;
199 }
200 for (i = 0; i < len; i++)
201 {
202 if(SYNTAX_ERR_FLAG==S_ERR)
203 return our;
204 if ((txt[i] != '\\') && (txt[i] != '_') && (txt[i] != '^'))
205 {
206 our.x++;
207 *gpos = txt[i];
208 gpos++;
209 *gpos = 0;
210 } else
211 {
212 K = LookupKey(txt + i, Keys);
213 switch (K)
214 {
215 case SUPER:
216 i += dimSuperscript(txt + i, &gpos, &our,
217 graph);
218 break;
219 case SUB:
220 i += dimSubscript(txt + i, &gpos, &our,
221 graph);
222 break;
223 case FRAC:
224 i += dimFrac(txt + i, &gpos, &our, graph);
225 break;
226 case SQRT:
227 i += dimSqrt(txt + i, &gpos, &our, graph);
228 break;
229 case OVERLINE:
230 i += dimOverl(txt + i, &gpos, &our, graph);
231 break;
232 case UNDERLINE:
233 i += dimUnderl(txt + i, &gpos, &our,
234 graph);
235 break;
236 case LIMIT:
237 i += dimLimit(txt + i, &gpos, &our, graph);
238 break;
239 case BRACES:
240 i += dimBrace(txt + i, &gpos, &our, graph);
241 break;
242 case ARRAY:
243 i += dimArray(txt + i, &gpos, &our, graph);
244 break;
245 case TO:
246 i += dimTo(txt + i, &gpos, &our, graph);
247 break;
248 case LEADSTO:
249 i += dimLeadsto(txt + i, &gpos, &our,
250 graph);
251 break;
252 case SUM:
253 i += dimSum(txt + i, &gpos, &our, graph);
254 break;
255 case PROD:
256 i += dimProd(txt + i, &gpos, &our, graph);
257 break;
258 case INT:
259 i += dimInt(txt + i, &gpos, &our, graph);
260 break;
261 case OINT:
262 i += dimOint(txt + i, &gpos, &our, graph);
263 break;
264 case INFTY:
265 strcat(gpos, "oo");
266 gpos += 2;
267 our.x += 2;
268 i += 5;
269 break;
270 case RCEIL:
271 i += dimRceil(txt + i, &gpos, &our, graph);
272 break;
273 case LCEIL:
274 i += dimLceil(txt + i, &gpos, &our, graph);
275 break;
276 case RFLOOR:
277 i += dimRfloor(txt + i, &gpos, &our,
278 graph);
279 break;
280 case LFLOOR:
281 i += dimLfloor(txt + i, &gpos, &our,
282 graph);
283 break;
284 case ESCAPE:
285 i++;
286 our.x++;
287 *gpos = txt[i];
288 gpos++;
289 *gpos = 0;
290 break;
291 case ERR:
292 default:
293 fprintf(stderr,
294 "I screwed up in dim, this should never happen!\n");
295 exit(1);
296 break;
297 }
298 }
299 }
300 graph->dim = our;
301 return our;
302 }
303
304 char *
PotLineEnd(char * txt)305 PotLineEnd(char *txt)
306 {
307 int len = strlen(txt);
308 int i,j;
309 char * plbp = "+-*/=~";
310 for (i = 0; i < len; i++)
311 {
312 /* return pointer to the next potential endline position */
313 if (strncmp(txt + i, "\\begin", 6) == 0) /* skip nested parts */
314 i = 4 + getbegin_endEnd(txt + i + 6) - txt;
315 else if (strncmp(txt + i, "\\left", 5) == 0)
316 i = 6 + findClosingLRBrace(txt + i + 5) - txt;
317 else if (txt[i] == '{')
318 i = findClosingBrace(txt + i + 1) - txt;
319 else if (txt[i] == '\\')
320 i++;
321 else if (txt[i] == '\n')
322 return txt + i;
323 else
324 for (j=0;j<6;j++)
325 if(plbp[j]==txt[i])
326 return txt + i + 1;
327
328 }
329 return txt+i; /* no potential line end found */
330 }
331
332 Tdim
eqdim(char * txt,struct Tgraph * graph,int ll)333 eqdim(char *txt, struct Tgraph * graph, int ll)
334 {
335 /* if the linelength (ll) is zero we do not break, otherwise we try to fit the eq within ll
336 columns */
337 if (ll)
338 {
339 /* position linebreaks at + - / * = in the top level */
340 char * END=txt+strlen(txt);
341 struct Tgraph *dummy = malloc(sizeof(struct Tgraph));
342 Tdim dumdim;
343 char * start=txt;
344 char * end, c;
345 char * prevplb=NULL;
346 int x=0;
347 while(start<END)
348 {
349 end=PotLineEnd(start);
350 if (SYNTAX_ERR_FLAG==S_ERR)
351 return dumdim;
352 c=*end;
353 *end='\0';
354 InitGraph(dummy);
355 dumdim=dim(start,dummy);
356 if (SYNTAX_ERR_FLAG==S_ERR)
357 return dumdim;
358 *end=c;
359 dealloc(dummy);
360 x+=dumdim.x;
361 if(dumdim.x>ll)
362 SyntaxWarning("Warning: overfull line\n");
363
364 if((x>ll)&&(prevplb))
365 {
366 /* at the previous potential line end we have to place one */
367 /* in order to make it easy we create a single char line end, \n */
368 /* note that enters are removed in preparse to allow multi line editing
369 */
370 *(prevplb)='\n';
371 x=dumdim.x;
372 }
373 if(c=='\n')
374 {
375 /* the current end is already a break */
376 /* reset x, prevent a new linebreak */
377 prevplb=NULL;
378 x=0;
379 end++;
380 }
381 else
382 prevplb=end;
383
384 start=end;
385 }
386 free(dummy);
387 }
388 return dim(txt, graph);
389 }
390