Rev 7673 | Rev 8185 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
10 | reyssat | 1 | /* Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis |
2 | * |
||
3 | * This program is free software; you can redistribute it and/or modify |
||
4 | * it under the terms of the GNU General Public License as published by |
||
5 | * the Free Software Foundation; either version 2 of the License, or |
||
6 | * (at your option) any later version. |
||
7 | * |
||
8 | * This program is distributed in the hope that it will be useful, |
||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
11 | * GNU General Public License for more details. |
||
12 | * |
||
13 | * You should have received a copy of the GNU General Public License |
||
14 | * along with this program; if not, write to the Free Software |
||
15 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||
16 | */ |
||
17 | |||
18 | /* internal variable */ |
||
19 | int rawmath_easy=0; |
||
20 | |||
21 | #include "hmname.c" |
||
22 | enum {RM_UNKNOWN, RM_FN, RM_VAR, RM_PREFIX}; |
||
23 | |||
24 | struct { |
||
25 | char *name; |
||
26 | int style; |
||
27 | char *replace; |
||
28 | } mathname[]={ |
||
5503 | bpr | 29 | {"Arc", RM_PREFIX, "arc"}, |
30 | {"Arg", RM_PREFIX, "arg"}, |
||
31 | {"Ci", RM_FN, ""}, |
||
32 | {"E", RM_VAR, ""}, |
||
33 | {"Euler", RM_VAR, ""}, |
||
34 | {"I", RM_VAR, ""}, |
||
35 | {"Int", RM_FN, ""}, |
||
36 | {"PI", RM_VAR, ""}, |
||
37 | {"Pi", RM_VAR, ""}, |
||
38 | {"Prod", RM_FN, ""}, |
||
39 | {"Si", RM_FN, ""}, |
||
40 | {"Sum", RM_FN, ""}, |
||
41 | {"arc", RM_PREFIX, ""}, |
||
42 | {"arg", RM_PREFIX, ""}, |
||
43 | {"binomial",RM_FN, ""}, |
||
44 | {"diff", RM_FN, ""}, |
||
45 | {"e", RM_VAR, ""}, |
||
46 | {"erf", RM_FN, ""}, |
||
47 | {"euler", RM_VAR, ""}, |
||
48 | {"i", RM_VAR, ""}, |
||
49 | {"infinity",RM_VAR, ""}, |
||
50 | {"int", RM_FN, ""}, |
||
51 | {"integrate",RM_FN, ""}, |
||
52 | {"neq", RM_VAR, ""}, |
||
53 | {"pi", RM_VAR, ""}, |
||
54 | {"prod", RM_FN, ""}, |
||
55 | {"product", RM_FN, ""}, |
||
56 | {"psi", RM_FN, ""}, |
||
57 | {"sum", RM_FN, ""}, |
||
58 | {"theta", RM_FN, ""}, |
||
59 | {"x", RM_VAR, ""}, |
||
60 | {"y", RM_VAR, ""}, |
||
61 | {"z", RM_VAR, ""}, |
||
62 | {"zeta", RM_FN, ""}, |
||
10 | reyssat | 63 | }; |
64 | #define mathname_no (sizeof(mathname)/sizeof(mathname[0])) |
||
65 | char rm_vbuf[MAX_LINELEN+1],rm_fbuf[MAX_LINELEN+1]; |
||
66 | char *rm_uservar[MAX_LINELEN+1],*rm_userfn[MAX_LINELEN+1]; |
||
67 | int rm_uservars,rm_userfns; |
||
68 | |||
5503 | bpr | 69 | /* add user-defined variables and function names, |
8155 | bpr | 70 | * internal, only called by rawmath(). |
71 | */ |
||
10 | reyssat | 72 | void getuservar(void) |
73 | { |
||
74 | char *p1, *p2, *p; |
||
75 | rm_uservars=rm_userfns=0; |
||
76 | p=getvar("wims_rawmath_variables"); |
||
77 | if(p!=NULL && *p!=0) { |
||
5503 | bpr | 78 | ovlstrcpy(rm_vbuf,p); |
79 | for(p=rm_vbuf;*p;p++) if(*p==',') *p=' '; |
||
80 | for(p1=find_word_start(rm_vbuf);*p1;p1=find_word_start(p2)) { |
||
81 | rm_uservar[rm_uservars++]=p1; |
||
82 | p2=find_word_end(p1); |
||
83 | if(*p2!=0) *(p2++)=0; |
||
84 | } |
||
10 | reyssat | 85 | } |
86 | p=getvar("wims_rawmath_functions"); |
||
87 | if(p!=NULL && *p!=0) { |
||
5503 | bpr | 88 | ovlstrcpy(rm_fbuf,p); |
89 | for(p=rm_fbuf;*p;p++) if(*p==',') *p=' '; |
||
90 | for(p1=find_word_start(rm_fbuf);*p1;p1=find_word_start(p2)) { |
||
91 | rm_userfn[rm_userfns++]=p1; |
||
92 | p2=find_word_end(p1); |
||
93 | if(*p2!=0) *(p2++)=0; |
||
94 | } |
||
10 | reyssat | 95 | } |
96 | } |
||
97 | |||
5503 | bpr | 98 | /* Try to split a word into recognizable variables */ |
10 | reyssat | 99 | char *mathname_split(char *p) |
100 | { |
||
101 | int c,i,j,type; |
||
102 | |||
103 | c=0; |
||
104 | beg: for(i=get_evalcnt()-1; |
||
5503 | bpr | 105 | i>=0 && strncmp(p,get_evalname(i),strlen(get_evalname(i)))!=0; |
106 | i--); |
||
10 | reyssat | 107 | if(i>=0 && get_evaltype(i)>0) { |
5503 | bpr | 108 | type=RM_FN; |
109 | j=strlen(get_evalname(i)); |
||
110 | gotit: |
||
111 | if(!*(p+j)) return p; |
||
112 | if(myisdigit(*(p+j)) && type!=RM_FN) return NULL; |
||
113 | if(!c) {string_modify(p,p+j,p+j," "); p+=j+1;} |
||
114 | else p+=j; |
||
115 | c++; goto beg; |
||
10 | reyssat | 116 | } |
117 | for(i=mathname_no-1; |
||
7673 | bpr | 118 | i>=0 && |
5503 | bpr | 119 | (strncmp(p,mathname[i].name,strlen(mathname[i].name))!=0 |
120 | || mathname[i].style==RM_PREFIX); |
||
121 | i--); |
||
10 | reyssat | 122 | if(i>=0) { |
5503 | bpr | 123 | type=mathname[i].style; |
124 | j=strlen(mathname[i].name); |
||
125 | goto gotit; |
||
10 | reyssat | 126 | } |
7673 | bpr | 127 | for(i=0;i<rm_uservars && |
5503 | bpr | 128 | strncmp(rm_uservar[i],p,strlen(rm_uservar[i]));i++); |
10 | reyssat | 129 | if(i<rm_uservars) { |
5503 | bpr | 130 | type=RM_VAR; |
131 | j=strlen(rm_uservar[i]); goto gotit; |
||
10 | reyssat | 132 | } |
7673 | bpr | 133 | for(i=0;i<rm_userfns && |
5503 | bpr | 134 | strncmp(p,rm_userfn[i],strlen(rm_userfn[i]));i++); |
10 | reyssat | 135 | if(i<rm_userfns) { |
5503 | bpr | 136 | type=RM_FN; |
137 | j=strlen(rm_userfn[i]); goto gotit; |
||
10 | reyssat | 138 | } |
7673 | bpr | 139 | return NULL; |
10 | reyssat | 140 | } |
141 | |||
5465 | bpr | 142 | int __replace_badchar (char *p, char *old, char *new) |
143 | { int cnt = 0; |
||
144 | char *p1 ; |
||
145 | while((p1=strstr(p,old))!=NULL) { |
||
5503 | bpr | 146 | string_modify(p,p1,p1+strlen(old),"%s",new); |
7673 | bpr | 147 | cnt++; |
5465 | bpr | 148 | } |
149 | return cnt ; |
||
150 | } |
||
10 | reyssat | 151 | |
5517 | bpr | 152 | /* translate |x| into abs(x)*/ |
5465 | bpr | 153 | int __replace_abs ( char *p ) |
7673 | bpr | 154 | { |
5465 | bpr | 155 | char *p1, *p2 ; |
10 | reyssat | 156 | while((p1=strchr(p,'|'))!=NULL) { |
5503 | bpr | 157 | p2=find_matching(p1+1,'|'); |
158 | if(p2==NULL) { return 1; break;} /* error; drop it. */ |
||
159 | *p2=')'; string_modify(p,p1,p1+1,"abs("); |
||
10 | reyssat | 160 | } |
5465 | bpr | 161 | return 0; |
162 | } |
||
163 | |||
164 | /* signs: translate ++, +-, -+, ... into one sign. */ |
||
5491 | kbelabas | 165 | void __replace_plusminus ( char *p ) |
7673 | bpr | 166 | { |
5465 | bpr | 167 | char *p1, *p2; |
168 | for(p1=p;*p1!=0;p1++) { |
||
5503 | bpr | 169 | int sign, redundant; |
170 | if(*p1!='+' && *p1!='-') continue; |
||
171 | if(*p1=='+') sign=1; else sign=-1; |
||
172 | redundant=0; |
||
173 | for(p2=find_word_start(p1+1);*p2=='+' || *p2=='-'; |
||
174 | p2=find_word_start(p2+1)) { |
||
175 | if(*p2=='-') sign*=-1; |
||
176 | redundant=1; |
||
177 | } |
||
178 | if(redundant && *p2!='>' && strncmp(p2,">",4)!=0) { |
||
179 | if(sign==1) *p1='+'; else *p1='-'; |
||
180 | ovlstrcpy(p1+1,p2); |
||
181 | } |
||
5465 | bpr | 182 | } |
183 | } |
||
184 | |||
185 | /* dangling decimal points |
||
8155 | bpr | 186 | * 4. --> 4.0 4.x -> 4.0x |
187 | * .5 -> 0.5 |
||
188 | * another treatment is done in insmath (will replace .. by , ) |
||
189 | */ |
||
5465 | bpr | 190 | void __treat_decimal(char *p) |
191 | { char *p1 ; |
||
192 | for(p1=strchr(p,'.'); p1!=NULL; p1=strchr(p1+1,'.')) { |
||
5503 | bpr | 193 | /* multiple .. is conserved */ |
194 | if(*(p1+1)=='.') { |
||
195 | do p1++; while(*p1=='.'); continue; |
||
10 | reyssat | 196 | } |
5503 | bpr | 197 | if(p1>p && myisdigit(*(p1-1)) && myisdigit(*(p1+1))) continue; |
198 | /* Non-digit dangling '.' is removed */ |
||
199 | if((p1<=p || !myisdigit(*(p1-1))) && !myisdigit(*(p1+1))) { |
||
200 | ovlstrcpy(p1,p1+1); p1--; continue; |
||
201 | } |
||
202 | if(p1==p || !myisdigit(*(p1-1))) { // nondigit.digit |
||
203 | string_modify(p,p1,p1,"0"); p1++; //add zero before point |
||
204 | } |
||
205 | if(!myisdigit(*(p1+1))) string_modify(p,p1+1,p1+1,"0"); //add zero after point |
||
206 | } |
||
5465 | bpr | 207 | } |
208 | |||
5517 | bpr | 209 | /* replace new-lines, tabs, " */ |
5465 | bpr | 210 | void __replace_space(char *p) |
7673 | bpr | 211 | { |
5465 | bpr | 212 | char *p1 ; |
5503 | bpr | 213 | for(p1=p;*p1!=0; p1++) { |
5517 | bpr | 214 | if(*p1=='\\' || isspace(*p1)) *p1=' ';// replace \ and all spaces by a simple space - |
215 | if(*p1=='\"') string_modify(p,p1,p1+1,"''"); p1++; // replace " by '' |
||
5465 | bpr | 216 | } |
217 | } |
||
218 | |||
8155 | bpr | 219 | /* Error-tolerante raw math translation routine |
220 | * Translate error-laden raw math into machine-understandable form. |
||
221 | * do nothing if there is some { or \\ |
||
222 | */ |
||
5465 | bpr | 223 | void rawmath(char *p) |
224 | { |
||
225 | char *p1, *p2, *p3, *p4; |
||
226 | char warnbuf[1024]; |
||
227 | int ambiguous=0,unknown=0,flatpower=0,badprec=0,unmatch=0;// for warning |
||
228 | |||
8155 | bpr | 229 | /* looks like a TeX source : do nothing */ |
5517 | bpr | 230 | if( (strchr(p,'\\')!=NULL || strchr(p,'{')!=NULL)) return; |
5465 | bpr | 231 | if(strchr(p,'^')==NULL) flatpower=-1; |
232 | if(strlen(p)>=MAX_LINELEN) {*p=0; return;} |
||
233 | p1=find_word_start(p);if(*p1==0) return; |
||
234 | while(*p1=='+') p1++; |
||
235 | if(p1>p) ovlstrcpy(p,p1); |
||
5491 | kbelabas | 236 | (void)__replace_badchar(p,"**", "^"); |
237 | if (__replace_badchar(p,"²", "^2 ")) flatpower=1; |
||
238 | if (__replace_badchar(p,"³", "^3 ")) flatpower=1; |
||
5517 | bpr | 239 | unmatch=__replace_abs(p); |
7673 | bpr | 240 | __replace_plusminus(p) ; |
5465 | bpr | 241 | __replace_space(p); |
242 | __treat_decimal(p); |
||
5491 | kbelabas | 243 | if (rawmath_easy) return; |
5465 | bpr | 244 | |
8155 | bpr | 245 | /* Principal translation: justapositions to multiplications */ |
10 | reyssat | 246 | if(strstr(p,"^1/")!=NULL) badprec=1; |
247 | getuservar(); |
||
248 | for(p1=p;*p1;p1++) { |
||
5503 | bpr | 249 | if(!isalnum(*p1) && *p1!=')' && *p1!=']') continue; |
250 | if(*p1==')' || *p1==']') { |
||
251 | p2=find_word_start(++p1); |
||
252 | add_star: |
||
253 | if(isalnum(*p2) || *p2=='(' || *p2=='[') { |
||
254 | if(*p2=='(' && *p1==')') ambiguous=1; |
||
255 | if(p2>p1) *p1='*'; |
||
256 | else string_modify(p,p1,p1,"*"); |
||
257 | } |
||
258 | p1--;continue; |
||
10 | reyssat | 259 | } |
5503 | bpr | 260 | p2=find_mathvar_end(p1); p3=find_word_start(p2); |
261 | if(myisdigit(*p1)) { |
||
262 | p1=p2; p2=p3; goto add_star; |
||
263 | } |
||
264 | else { |
||
265 | char buf[MAX_LINELEN+1]; |
||
266 | int i; |
||
267 | if(p2-p2>30) goto ambig; |
||
268 | memcpy(buf,p1,p2-p1);buf[p2-p1]=0; |
||
269 | i=search_evaltab(buf); |
||
270 | if(i>=0 && get_evaltype(i)>0) { |
||
271 | fnname1: |
||
272 | p1=p2;p2=p3; |
||
8155 | bpr | 273 | /*fnname:*/ |
5503 | bpr | 274 | if(*p2 && *p2!='(' && *p2!='*' && *p2!='/') { |
275 | char hatbuf[MAX_LINELEN+1]; |
||
276 | hatbuf[0]=')'; hatbuf[1]=0; |
||
277 | if(*p2=='^') { |
||
278 | p3=p2+1;while(*p3==' ' || *p3=='+' || *p3=='-') p3++; |
||
279 | if(*p3=='(') { |
||
280 | p3=find_matching(p3+1,')'); |
||
281 | if(p3==NULL) {unmatch=1; p3=p+strlen(p);} |
||
282 | else p3++; |
||
283 | } |
||
284 | else p3=find_mathvar_end(p3); |
||
285 | memmove(hatbuf+1,p2,p3-p2);hatbuf[p3-p2+1]=0; |
||
286 | ovlstrcpy(p2,p3); |
||
287 | while(*p2==' ') p2++; |
||
288 | if(*p2=='*' || *p2=='/') { |
||
289 | p1--;continue; |
||
290 | } |
||
291 | if(*p2=='(') { |
||
292 | p3=find_matching(p2+1,')'); |
||
293 | if(p3==NULL) {unmatch=1; p3=p+strlen(p);} |
||
294 | else p3++; |
||
295 | string_modify(p,p3,p3,"%s",hatbuf+1); |
||
296 | goto dd2; |
||
297 | } |
||
298 | } |
||
299 | p3=p2;if(*p3=='+' || *p3=='-') p3++; |
||
300 | while(isalnum(*p3) || *p3=='*' || *p3=='/' || *p3=='.') |
||
301 | p3++; |
||
302 | for(p4=p2; p4<p3 && !isalnum(*p4); p4++); |
||
303 | if(p4>=p3) { |
||
304 | if(hatbuf[1]) string_modify(p,p2,p2,"%s",hatbuf+1); |
||
305 | } |
||
306 | else { |
||
307 | string_modify(p,p3,p3,"%s",hatbuf); |
||
308 | if(p1==p2) string_modify(p,p2,p2,"("); |
||
309 | else *p1='('; |
||
310 | } |
||
311 | dd2: |
||
312 | ambiguous=1; |
||
313 | } |
||
314 | p1--;continue; |
||
315 | } |
||
316 | i=search_list(mathname,mathname_no,sizeof(mathname[0]),buf); |
||
317 | if(i>=0) { |
||
318 | if(mathname[i].replace[0]!=0) { |
||
319 | string_modify(p,p1,p2,mathname[i].replace); |
||
320 | p2=p1+strlen(mathname[i].replace); |
||
321 | p3=find_word_start(p2); |
||
322 | } |
||
323 | switch(mathname[i].style) { |
||
324 | case RM_FN: |
||
325 | goto fnname1; |
||
7673 | bpr | 326 | |
5503 | bpr | 327 | case RM_VAR: |
328 | p1=p2;p2=p3; goto add_star; |
||
7673 | bpr | 329 | |
5503 | bpr | 330 | case RM_PREFIX: |
7673 | bpr | 331 | if(*p3!='c' && *p3!='s' && *p3!='t' && |
5503 | bpr | 332 | *p3!='C' && *p3!='S' && *p3!='T') break; |
333 | ambiguous=1; |
||
334 | ovlstrcpy(p2,p3); p1--; continue; |
||
335 | } |
||
336 | } |
||
337 | i=search_list(hmname,hmname_no,sizeof(hmname[0]),buf); |
||
338 | if(i>=0) { |
||
339 | p1=p2; p2=p3; goto add_star; |
||
340 | } |
||
341 | for(i=0;i<rm_uservars && strcmp(buf,rm_uservar[i]);i++); |
||
342 | if(i<rm_uservars) { |
||
343 | p1=p2;p2=p3;goto add_star; |
||
344 | } |
||
345 | for(i=0;i<rm_userfns && strcmp(buf,rm_userfn[i]);i++); |
||
346 | if(i<rm_userfns) goto fnname1; |
||
347 | if(p2-p1>8) goto ambig; |
||
348 | if(mathname_split(buf)!=NULL) { |
||
349 | ambiguous=1; |
||
350 | string_modify(p,p1,p2,"%s",buf); |
||
351 | p1--; continue; |
||
352 | } |
||
8155 | bpr | 353 | /* unknown name */ |
5503 | bpr | 354 | ambig: p1=p2;p2=p3; |
355 | if(strlen(buf)>1) { |
||
356 | for(p3=buf;*p3!=0 && !myisdigit(*p3);p3++); |
||
7673 | bpr | 357 | if(*p3!=0 && flatpower!=0) flatpower=1; |
5503 | bpr | 358 | else { |
359 | unknown=1; |
||
360 | force_setvar("wims_warn_rawmath_parm",buf); |
||
361 | } |
||
362 | } |
||
363 | else { |
||
364 | if(*p2=='(') ambiguous=1; |
||
365 | } |
||
366 | if(isalnum(*p2)) { |
||
367 | if(p2>p1) *p1='*'; |
||
368 | else string_modify(p,p1,p1,"*"); |
||
369 | } |
||
370 | p1--;continue; |
||
371 | } |
||
372 | } |
||
10 | reyssat | 373 | warnbuf[0]=0; |
374 | if(ambiguous) strcat(warnbuf," ambiguous"); |
||
375 | if(unknown) strcat(warnbuf," unknown"); |
||
376 | if(flatpower>0) strcat(warnbuf," flatpower"); |
||
377 | if(badprec>0) strcat(warnbuf," badprec"); |
||
378 | if(unmatch>0) strcat(warnbuf," unmatched_parentheses"); |
||
379 | if(warnbuf[0]) { |
||
5503 | bpr | 380 | char buf[MAX_LINELEN+1],*p; |
381 | p=getvar("wims_warn_rawmath"); |
||
382 | if(p!=NULL && *p!=0) { |
||
383 | snprintf(buf,sizeof(buf),"%s %s",p,warnbuf); |
||
384 | force_setvar("wims_warn_rawmath",buf); |
||
10 | reyssat | 385 | } |
5503 | bpr | 386 | else force_setvar("wims_warn_rawmath",warnbuf); |
387 | } |
||
10 | reyssat | 388 | } |
389 | |||
8155 | bpr | 390 | /* replace < and > by html code if htmlmath_gtlt=yes |
391 | * is only used in deduc - not documented |
||
392 | */ |
||
7673 | bpr | 393 | void __replace_htmlmath_gtlt (char *p) |
5465 | bpr | 394 | { char *pp; |
7673 | bpr | 395 | char *p1=getvar("htmlmath_gtlt"); |
5503 | bpr | 396 | if(p1!=NULL && strcmp(p1,"yes")==0) { |
397 | for(pp=strchr(p,'<'); pp!=NULL; pp=strchr(pp+1,'<')) |
||
398 | string_modify(p,pp,pp+1,"<"); |
||
399 | for(pp=strchr(p,'>'); pp!=NULL; pp=strchr(pp+1,'>')) |
||
400 | string_modify(p,pp,pp+1,">"); |
||
5465 | bpr | 401 | } |
402 | } |
||
403 | |||
7673 | bpr | 404 | /* exponents or indices : |
5551 | bpr | 405 | * all digits or + or - following a ^ or _ are considered as in exponent/subscript |
406 | * expression with ( ) following a ^ or _ are considered as in exponent/subscript |
||
407 | * the parenthesis are suppressed except in case of exponent and only digits. |
||
8155 | bpr | 408 | * if int n != 0, use html code, else use tex code |
409 | */ |
||
5551 | bpr | 410 | void __replace_exponent(char *p, int n) |
5465 | bpr | 411 | { |
5503 | bpr | 412 | char *p1; |
413 | char *SUPBEG, *SUPEND; |
||
7673 | bpr | 414 | if (n) { SUPBEG = "<sup>"; SUPEND = "</sup>";} |
5503 | bpr | 415 | else { SUPBEG = "^{"; SUPEND = "}";} |
5465 | bpr | 416 | |
10 | reyssat | 417 | for(p1=strchr(p,'^');p1!=NULL;p1=strchr(p1+1,'^')) { |
5465 | bpr | 418 | char *p2, *p3, *pp; |
419 | char c; |
||
420 | p3 = p2 = find_word_start(p1+1); |
||
421 | if(*p2=='+' || *p2=='-') p2++; |
||
422 | p2 = find_word_start(p2); |
||
7673 | bpr | 423 | /* jm.evers 31.1.2014 |
424 | * add '}' to recognized parenthesis in exponent |
||
425 | * !mathmlmath 2 \cdot x^{3} will now produce correct exponent... |
||
426 | * !mathmlmath should convert LaTeX input into correct MathML |
||
427 | */ |
||
7415 | schaersvoo | 428 | if(*p2=='(' || *p2 == '{') { /* ^[+-]( */ |
7673 | bpr | 429 | if(*p2 == '('){ p2 = find_matching(p2+1,')');}else { if(*p2 == '{'){ p2 = find_matching(p2+1,'}');}} |
5465 | bpr | 430 | /* no matching ')' : p2 = end of line; otherwise just after ')' */ |
431 | if (p2==NULL) p2=p+strlen(p); else p2++; |
||
432 | /* ^( followed by any number of digits/letters, up to p2 |
||
433 | * [FIXME: no sign?] */ |
||
434 | /* do we remove parentheses containing exponent group ? */ |
||
435 | if (*p3=='(') for(pp=p3+1;pp<p2-1;pp++) { |
||
436 | if(!isalnum(*pp)) { |
||
7673 | bpr | 437 | /* not a digit/letter. Remove (). */ |
5465 | bpr | 438 | p3++;*(p2-1)=0;break; |
439 | } |
||
5517 | bpr | 440 | /* x^(2), parentheses not removed */ |
5465 | bpr | 441 | } |
8155 | bpr | 442 | /* p3: start of word after ^ |
443 | * matching parentheses from exponent group. : f^(4) 4-derivative |
||
444 | * don't ignore / remove a leading + sign in exponent group : Cu^+ |
||
445 | */ |
||
5465 | bpr | 446 | } else { /* ^[+-] */ |
447 | char *ptt=p2; |
||
448 | p2=find_word_start(find_mathvar_end(p2)); |
||
449 | if(*p2=='(' && isalpha(*ptt)) { |
||
450 | /* ^[+-]var( */ |
||
451 | char *p2t; |
||
452 | p2t=find_matching(p2+1,')'); if(p2t!=NULL) p2=p2t+1; |
||
453 | /* FIXME: what if no matching ) ? */ |
||
454 | } |
||
8155 | bpr | 455 | /* ^[+-]var(...): p2 points after closing ')' |
456 | * FIXME: I don't think this 'else' branch is sensible. One |
||
457 | * should NOT accept x^b(c+1) as meaning x^[b(c+1)]. I would |
||
458 | * remove it altogether. |
||
459 | */ |
||
5465 | bpr | 460 | } |
8155 | bpr | 461 | /* p1 points at ^ before exponent group |
462 | * p2 points at end of exponent group |
||
463 | * p3 = exponent group (sometimes stripped, without parentheses) |
||
464 | * |
||
465 | * truncate string p at p2 [ c = char deleted by truncation ] |
||
466 | */ |
||
5465 | bpr | 467 | c = *p2;if(c!=0) *p2++=0; |
468 | /* replace ^<exponent group>. Add back missing character 'c' */ |
||
5503 | bpr | 469 | string_modify(p,p1,p2, "%s%s%s%c",SUPBEG,p3,SUPEND,c); |
10 | reyssat | 470 | } |
5465 | bpr | 471 | } |
472 | |||
5551 | bpr | 473 | /* if int n != 0, use html code, else use tex code */ |
474 | void __replace_subscript(char *p, int n) |
||
5465 | bpr | 475 | { |
476 | char *p1, *p2; |
||
5503 | bpr | 477 | char *SUBBEG, *SUBEND; |
7673 | bpr | 478 | if (n) {SUBBEG = "<sub>"; SUBEND = "</sub>";} |
5503 | bpr | 479 | else {SUBBEG = "_{"; SUBEND = "}";} |
5465 | bpr | 480 | for(p1=strchr(p,'_');p1!=NULL;p1=strchr(p1+1,'_')) { |
5503 | bpr | 481 | char buff[256]; |
482 | p2=p1+1; |
||
483 | if(*p2=='(') p2=find_matching(p2+1,')'); |
||
484 | else p2=find_mathvar_end(p2); |
||
485 | if(p2==NULL || p2>p1+64) continue; |
||
486 | if(*(p1+1)=='(') p2++; |
||
487 | memmove(buff,p1+1,p2-p1-1); buff[p2-p1-1]=0; |
||
488 | strip_enclosing_par(buff); |
||
489 | string_modify(p,p1,p2,"%s%s%s",SUBBEG,buff,SUBEND);} |
||
5465 | bpr | 490 | } |
491 | |||
5517 | bpr | 492 | /* get rid of 1*.. ..*1 exemple : 1 * x, x/1 */ |
5465 | bpr | 493 | void __replace_getrid1 (char *p) |
7673 | bpr | 494 | { char *p1, *p2, *p3 ; |
10 | reyssat | 495 | for(p1=p;*p1;p1++) { |
5503 | bpr | 496 | if(*p1!='1') continue; |
497 | if(myisdigit(*(p1+1)) || *(p1+1)=='.' || |
||
498 | (p1>p && (isalnum(*(p1-1)) || *(p1-1)=='.')) ) continue; |
||
499 | p2=find_word_start(p1+1); |
||
500 | if(p1>p+2 && (*(p1-1)=='-' || *(p1-1)=='+')) { |
||
501 | for(p3=p1-2; p3>p && isspace(*p3); p3--); |
||
7673 | bpr | 502 | if(p3>p+1 && (*p3=='E' || *p3=='e')) { /* ??? */ |
5503 | bpr | 503 | p3--; while(p3>p && isspace(*p3)) p3--; |
504 | if(myisdigit(*p3) || *p3=='.') continue; |
||
505 | } |
||
506 | } |
||
7673 | bpr | 507 | if(p1==p) p3="+"; |
5503 | bpr | 508 | else for(p3=p1-1;p3>p && isspace(*p3);p3--); |
509 | if(*p2=='*' && *p3!='/') {/* delete 1 if 1* or /1 */ |
||
510 | ovlstrcpy(p1,p2+1);continue; |
||
511 | } |
||
512 | if(isalpha(*p2) && *p3!='/') { |
||
513 | ovlstrcpy(p1,p2);continue; |
||
514 | } |
||
515 | if(*p3=='/' && *p2!='<') ovlstrcpy(p3,p2); |
||
10 | reyssat | 516 | |
517 | } |
||
5465 | bpr | 518 | } |
519 | |||
520 | /* get rid of '*' */ |
||
521 | void __replace_getridstar (char *p) |
||
522 | { char *p1 ; |
||
523 | for(p1=strchr(p,'*');p1!=NULL;p1=strchr(p1+1,'*')) { |
||
5503 | bpr | 524 | char *pq; |
525 | pq=find_word_start(p1+1); |
||
526 | if(myisdigit(*pq)) { |
||
527 | string_modify(p,p1,pq,"×"); |
||
528 | continue; |
||
10 | reyssat | 529 | } |
5503 | bpr | 530 | if(p1>p && (isalpha(*(p1-1)) || *(p1-1)==')' || *(p1-1)=='>') |
531 | && (isalnum(*pq) || *pq=='$')) *p1=' '; |
||
532 | else { |
||
533 | ovlstrcpy(p1,p1+1);p1--; |
||
534 | } |
||
535 | } |
||
5465 | bpr | 536 | } |
537 | |||
7673 | bpr | 538 | /* <=, >=, ->, =>, <=> |
8155 | bpr | 539 | * if int n != 0, use html code, else use tex code |
540 | */ |
||
5551 | bpr | 541 | |
542 | void __replace_arrow ( char *p, int n) |
||
5503 | bpr | 543 | { char *p1, *p2, *m_prefix; |
5551 | bpr | 544 | if (n) m_prefix="$m_"; else m_prefix="\\"; |
7673 | bpr | 545 | |
10 | reyssat | 546 | for(p1=strstr(p,"<="); p1!=NULL; p1=strstr(p1+1,"<=")) { |
7673 | bpr | 547 | if(*(p1+5)!='&' && *(p1+5)!='=') |
5503 | bpr | 548 | string_modify(p,p1,p1+5, "%sle",m_prefix); |
549 | else { |
||
550 | for(p2=p1+5; *p2=='='; p2++); |
||
551 | if(strncmp(p2,">",4)==0) { |
||
7673 | bpr | 552 | if(p2>p1+5) { string_modify(p,p1,p2+4,"%sLongleftrightarrow",m_prefix);} |
553 | else { string_modify(p,p1,p2+4,"%sLeftrightarrow",m_prefix);} |
||
5503 | bpr | 554 | } |
555 | else { string_modify(p,p1,p2,"%sLongleftarrow",m_prefix);} |
||
556 | } |
||
10 | reyssat | 557 | } |
558 | for(p1=strstr(p,">="); p1!=NULL; p1=strstr(p1+1,">=")) { |
||
5503 | bpr | 559 | if(*(p1+5)!='=') { string_modify(p,p1,p1+5,"%sge",m_prefix);} |
10 | reyssat | 560 | } |
561 | for(p1=strstr(p,"->"); p1; p1=strstr(p1+1,"->")) { |
||
5503 | bpr | 562 | for(p2=p1; p2>p && *(p2-1)=='-'; p2--); |
563 | if(p2>p && *(p2-1)==';') continue; |
||
564 | if(p2<p1) { string_modify(p,p2,p1+5,"%slongrightarrow",m_prefix);} |
||
565 | else { string_modify(p,p1,p1+5,"%srightarrow",m_prefix);} |
||
10 | reyssat | 566 | } |
567 | for(p1=strstr(p,"=>"); p1; p1=strstr(p1+1,"=>")) { |
||
5503 | bpr | 568 | for(p2=p1; p2>p && *(p2-1)=='='; p2--); |
569 | if(p2>p && *(p2-1)==';') continue; |
||
570 | if(p2<p1) { string_modify(p,p2,p1+5,"%sLongrightarrow",m_prefix);} |
||
571 | else { string_modify(p,p1,p1+5,"%sRightarrow",m_prefix) ;} |
||
10 | reyssat | 572 | } |
5503 | bpr | 573 | /* Not equal */ |
10 | reyssat | 574 | for(p1=strstr(p,"!="); p1; p1=strstr(p1+1,"!=")) { |
5503 | bpr | 575 | if(p1>p && !isspace(*(p1-1))) continue; |
576 | string_modify(p,p1,p1+2,"%sneq",m_prefix); |
||
10 | reyssat | 577 | } |
5465 | bpr | 578 | } |
579 | |||
5503 | bpr | 580 | /* why <tt> is used sometimes ? replace single characters by italics one |
581 | * is it useful in mathml ? |
||
8155 | bpr | 582 | */ |
5551 | bpr | 583 | void __replace_italics (char *p, int n) |
5465 | bpr | 584 | { char *p1, *p2, *p3, pbuf[16]; |
5503 | bpr | 585 | char *ITBEG, *ITEND, *ITtBEG, *ITtEND; |
5551 | bpr | 586 | if (n) { |
5503 | bpr | 587 | ITBEG = "<i>";ITtBEG = "<i><tt>"; |
588 | ITEND = "</i>";ITtEND = "</tt></i>"; |
||
589 | } else {; |
||
590 | ITBEG = "" ; ITtBEG = ""; |
||
591 | ITEND = ""; ITtEND = ""; |
||
592 | } |
||
7673 | bpr | 593 | |
5503 | bpr | 594 | for(p1=p;*p1;p1++) { |
595 | if(*p1=='<') { |
||
596 | p1=strchr(p1,'>'); if(p1==NULL) break; //recognize an html tag < > |
||
597 | else continue; |
||
10 | reyssat | 598 | } |
5503 | bpr | 599 | if(*p1=='=' && *(p1+1)=='-') { |
600 | string_modify(p,p1+1,p1+1," "); p1+=2; continue; |
||
601 | } |
||
602 | if(*p1=='\'') { |
||
603 | for(p2=p1+1;*p2=='\'';p2++); |
||
604 | memmove(pbuf,p1,p2-p1); pbuf[p2-p1]=0; |
||
605 | string_modify(p,p1,p2,"%s%s%s",ITtBEG,pbuf,ITtEND); |
||
606 | p1=p2+strlen(ITtBEG)+strlen(ITtEND)-1; |
||
607 | continue; |
||
608 | } |
||
609 | if(!isalpha(*p1)) continue; |
||
610 | /* unique letter.*/ |
||
611 | for(p2=p1+1;isalpha(*p2);p2++); |
||
612 | p3=find_word_start(p2); |
||
613 | if(p2>p1+5 || |
||
614 | (p2>p1+1 && (*p3==';' || *p3=='(' || myisdigit(*p2)))) |
||
615 | {p1=p2-1; continue;} |
||
616 | if(strncasecmp(p3,"</i>",strlen("</i>"))==0) continue; |
||
617 | memmove(pbuf,p1,p2-p1); pbuf[p2-p1]=0; |
||
618 | string_modify(p,p1,p2,"%s%s%s",ITBEG,pbuf,ITEND); |
||
619 | p1=p2+strlen(ITBEG)+strlen(ITEND)-1; |
||
620 | } |
||
10 | reyssat | 621 | } |
5466 | bpr | 622 | |
5551 | bpr | 623 | /* float (1.2 E-03) : 3E+021 -> 3 × 10^{21} - 3E-21 -> 3 × 10^{-21} |
624 | * or replace variable name (alpha) |
||
8155 | bpr | 625 | * if int n != 0, use html code, else use tex code |
626 | */ |
||
5551 | bpr | 627 | void __replace_mathvar(char *p,int n) |
5466 | bpr | 628 | { char *p1, *p2, *p3; |
5503 | bpr | 629 | char *EXPBEG, *EXPEND, *EXPBEGMINUS, *SUBBEG, *SUBEND, *m_prefix; |
7673 | bpr | 630 | |
5551 | bpr | 631 | if ( n ) { |
5503 | bpr | 632 | EXPBEG = " × 10<sup>"; |
633 | EXPBEGMINUS = " × 10<sup>-"; |
||
634 | EXPEND = "</sup>"; |
||
635 | SUBBEG = "<sub>"; |
||
636 | SUBEND = "</sub>"; |
||
637 | m_prefix="$m_"; |
||
638 | } else { |
||
639 | EXPBEG = " \\times 10^{" ; |
||
640 | EXPBEGMINUS = " \\times 10^{-" ; |
||
641 | EXPEND = "}"; |
||
642 | SUBBEG = "_{"; |
||
643 | SUBEND = "}"; |
||
644 | m_prefix="\\"; |
||
5466 | bpr | 645 | } |
5503 | bpr | 646 | for (p1=find_mathvar_start(p);*p1!=0;p1=find_mathvar_start(p2)) { |
647 | char buf[MAX_LINELEN+1]; |
||
8155 | bpr | 648 | /* if the variable is preceded by \ do nothing |
649 | * in fact this should not arrive |
||
650 | */ |
||
7673 | bpr | 651 | if (p1>p && *(p1-1) == '\\' ) break ; |
5503 | bpr | 652 | p2 = find_mathvar_end(p1); |
653 | if (p1 == p2) break; |
||
654 | memmove(buf,p1,p2-p1);buf[p2-p1]=0; |
||
5466 | bpr | 655 | |
5503 | bpr | 656 | if(myisdigit(buf[0])) { |
8155 | bpr | 657 | /* number : 3E+021 -> 3 x 10^{21} - 3E-21 -> 3 x 10^{-21} */ |
5503 | bpr | 658 | int k = 1, minus = 0; |
659 | |||
660 | /* see putnumber in texmath.c*/ |
||
661 | if( (p3 = strpbrk(buf, "Ee")) == NULL) continue; |
||
662 | p1 += p3-buf; |
||
663 | //count the number of 0, +, - |
||
5517 | bpr | 664 | if (*(p1+k) == '-') { minus = 1; k++; } |
5503 | bpr | 665 | while(*(p1+k)=='0' || *(p1+k)=='+') k++; |
666 | |||
5517 | bpr | 667 | string_modify(p,p1,p1+k, minus? EXPBEGMINUS: EXPBEG); |
668 | p2 += strlen(minus? EXPBEGMINUS: EXPBEG)-k; |
||
669 | string_modify(p,p2,p2, EXPEND); |
||
670 | p2 += strlen(EXPEND); |
||
5503 | bpr | 671 | } else { |
8155 | bpr | 672 | /* alphabetic name, replace greek letters and symbols in hmname |
673 | * not done in texmath.c |
||
674 | */ |
||
5503 | bpr | 675 | int i = search_list(hmname,hmname_no,sizeof(hmname[0]),buf); |
676 | char *n, *r; |
||
677 | if(i<0) { /* not in list */ |
||
678 | int k = strlen(buf)-1; |
||
679 | if(myisdigit(buf[k])) { |
||
680 | while(k>0 && myisdigit(buf[k-1])) k--; |
||
681 | string_modify(buf,buf+k,buf+k,SUBBEG); |
||
682 | string_modify(p,p1,p2,"%s%s",buf,SUBEND); |
||
683 | p2+=strlen(SUBBEG)+strlen(SUBEND); |
||
684 | } |
||
685 | continue; |
||
686 | } |
||
687 | n = hmname[i].name; |
||
688 | r = mathalign_base < 2? hmname[i].replace: hmname[i].replacem; |
||
689 | if(r[0]==0) { /* replace = "" */ |
||
690 | string_modify(p,p1,p2,"%s%s",m_prefix, n); |
||
691 | p2 = p1+strlen(n)+strlen(m_prefix); |
||
692 | } else { |
||
693 | string_modify(p,p1,p2,"%s",r); |
||
694 | p2 = p1+strlen(r); |
||
695 | } |
||
696 | } |
||
697 | } |
||
5465 | bpr | 698 | } |
699 | |||
7673 | bpr | 700 | /* translate raw math expression coming from calculators into best html way |
8155 | bpr | 701 | * if int n != 0, use html code, else use tex code |
702 | */ |
||
5551 | bpr | 703 | void __htmlmath(char *p,int n) |
5465 | bpr | 704 | { |
5503 | bpr | 705 | if(!rawmath_easy) { rawmath_easy=1; rawmath(p); rawmath_easy=0;} |
5466 | bpr | 706 | __replace_htmlmath_gtlt(p); //only used in deductio |
5551 | bpr | 707 | __replace_exponent(p,n); |
708 | __replace_subscript(p,n); |
||
5517 | bpr | 709 | __replace_getrid1(p); |
5551 | bpr | 710 | __replace_mathvar(p,n); |
5517 | bpr | 711 | __replace_getridstar(p); |
5551 | bpr | 712 | __replace_arrow(p,n); |
5503 | bpr | 713 | /* Now make substitutions */ |
5465 | bpr | 714 | substit(p); |
5503 | bpr | 715 | /* Make single names italic - done automatically by mathml */ |
5551 | bpr | 716 | __replace_italics(p,n); |
5465 | bpr | 717 | strip_trailing_spaces(p); |
718 | } |
||
719 | |||
7673 | bpr | 720 | void htmlmath(char *p) |
5465 | bpr | 721 | { |
5551 | bpr | 722 | __htmlmath(p,1) ; |
5544 | bpr | 723 | } |
724 | |||
725 | /* if mathml is closed, it will be just htmlmath*/ |
||
726 | |||
7673 | bpr | 727 | void mathmlmath(char *p) |
728 | { |
||
5551 | bpr | 729 | if (mathalign_base == 2) { __htmlmath(p,0) ; mathml(p,1);} else { __htmlmath(p,1) ;} |
5465 | bpr | 730 | } |