Subversion Repositories wimsdev

Rev

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