Subversion Repositories wimsdev

Rev

Rev 13101 | 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[]={
12229 bpr 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","",""},
8185 bpr 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
{
12246 bpr 135
  char *p1, *p2, *p;
136
  rm_uservars=rm_userfns=0;
137
  p=getvar("wims_rawmath_variables");
138
  if(p!=NULL && *p!=0) {
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;
10 reyssat 145
    }
12246 bpr 146
  }
147
  p=getvar("wims_rawmath_functions");
148
  if(p!=NULL && *p!=0) {
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;
10 reyssat 155
    }
12246 bpr 156
  }
10 reyssat 157
}
158
 
5503 bpr 159
/* Try to split a word into recognizable variables */
10 reyssat 160
char *mathname_split(char *p)
161
{
12246 bpr 162
  int c,i,j,type;
10 reyssat 163
 
12246 bpr 164
  c=0;
165
  beg: for(i=get_evalcnt()-1;
166
  i>=0 && strncmp(p,get_evalname(i),strlen(get_evalname(i)))!=0;
167
  i--);
168
  if(i>=0 && get_evaltype(i)>0) {
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;
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);
12246 bpr 182
    i--);
183
  if(i>=0) {
184
    type=mathname[i].style;
185
    j=strlen(mathname[i].name);
186
    goto gotit;
187
  }
188
  for(i=0;i<rm_uservars &&
189
    strncmp(rm_uservar[i],p,strlen(rm_uservar[i]));i++);
190
  if(i<rm_uservars) {
191
    type=RM_VAR;
192
    j=strlen(rm_uservar[i]); goto gotit;
193
  }
194
  for(i=0;i<rm_userfns &&
5503 bpr 195
      strncmp(p,rm_userfn[i],strlen(rm_userfn[i]));i++);
12249 bpr 196
  if(i<rm_userfns) {
197
    type=RM_FN;
198
    j=strlen(rm_userfn[i]); goto gotit;
199
  }
12246 bpr 200
  return NULL;
10 reyssat 201
}
202
 
5465 bpr 203
int __replace_badchar (char *p, char *old, char *new)
12246 bpr 204
{
205
  int cnt = 0;
5465 bpr 206
  char *p1 ;
207
  while((p1=strstr(p,old))!=NULL) {
5503 bpr 208
    string_modify(p,p1,p1+strlen(old),"%s",new);
7673 bpr 209
    cnt++;
5465 bpr 210
  }
211
  return cnt ;
212
}
10 reyssat 213
 
5517 bpr 214
/* translate |x| into abs(x)*/
5465 bpr 215
int __replace_abs ( char *p )
7673 bpr 216
{
12246 bpr 217
  char *p1, *p2 ;
218
  while((p1=strchr(p,'|'))!=NULL) {
219
    p2=find_matching(p1+1,'|');
220
    if(p2==NULL) { return 1; break;} /* error; drop it. */
221
    *p2=')'; string_modify(p,p1,p1+1,"abs(");
222
  }
223
  return 0;
5465 bpr 224
}
225
 
226
/* signs: translate ++, +-, -+, ... into one sign. */
5491 kbelabas 227
void __replace_plusminus ( char *p )
7673 bpr 228
{
12246 bpr 229
  char *p1, *p2;
230
  for(p1=p;*p1!=0;p1++) {
231
    int sign, redundant;
232
    if(*p1!='+' && *p1!='-') continue;
233
    if(*p1=='+') sign=1; else sign=-1;
234
    redundant=0;
235
    for(p2=find_word_start(p1+1);*p2=='+' || *p2=='-';
236
    p2=find_word_start(p2+1)) {
237
      if(*p2=='-') sign*=-1;
238
      redundant=1;
239
    }
240
    if(redundant && *p2!='>' && strncmp(p2,"&gt;",4)!=0) {
241
      if(sign==1) *p1='+'; else *p1='-';
242
      ovlstrcpy(p1+1,p2);
243
    }
244
  }
5465 bpr 245
}
246
 
247
/* dangling decimal points
8155 bpr 248
 * 4. --> 4.0  4.x -> 4.0x
249
 * .5 -> 0.5
250
 * another treatment is done in insmath (will replace .. by , )
251
 */
5465 bpr 252
void __treat_decimal(char *p)
12246 bpr 253
{
254
  char *p1 ;
5465 bpr 255
  for(p1=strchr(p,'.'); p1!=NULL; p1=strchr(p1+1,'.')) {
5503 bpr 256
        /* multiple .. is conserved */
257
    if(*(p1+1)=='.') {
12246 bpr 258
      do p1++; while(*p1=='.'); continue;
10 reyssat 259
    }
5503 bpr 260
    if(p1>p && myisdigit(*(p1-1)) && myisdigit(*(p1+1))) continue;
261
        /* Non-digit dangling '.' is removed */
262
    if((p1<=p || !myisdigit(*(p1-1))) && !myisdigit(*(p1+1))) {
12246 bpr 263
      ovlstrcpy(p1,p1+1); p1--; continue;
5503 bpr 264
    }
265
    if(p1==p || !myisdigit(*(p1-1))) { // nondigit.digit
12246 bpr 266
      string_modify(p,p1,p1,"0"); p1++; //add zero before point
5503 bpr 267
    }
268
    if(!myisdigit(*(p1+1))) string_modify(p,p1+1,p1+1,"0"); //add zero after point
269
  }
5465 bpr 270
}
271
 
5517 bpr 272
/* replace new-lines, tabs, " */
5465 bpr 273
void __replace_space(char *p)
7673 bpr 274
{
12246 bpr 275
  char *p1 ;
276
  for(p1=p;*p1!=0; p1++) {
5517 bpr 277
    if(*p1=='\\' || isspace(*p1)) *p1=' ';// replace \ and all spaces by a simple space -
11736 bpr 278
    if(*p1=='\"') { string_modify(p,p1,p1+1,"''"); p1++;} // replace " by ''
5465 bpr 279
  }
280
}
281
 
13101 bpr 282
/* Error-tolerant raw math translation routine
283
 * Translate error-laden raw math into machine-understandable form.
8155 bpr 284
 * do nothing if there is some { or \\
285
 */
5465 bpr 286
void rawmath(char *p)
287
{
12246 bpr 288
  char *p1, *p2, *p3, *p4;
289
  char warnbuf[1024];
290
  int ambiguous=0,unknown=0,flatpower=0,badprec=0,unmatch=0;// for warning
5465 bpr 291
 
8155 bpr 292
/* looks like a TeX source : do nothing */
12246 bpr 293
  if( (strchr(p,'\\')!=NULL || strchr(p,'{')!=NULL)) return;
294
  if(strchr(p,'^')==NULL) flatpower=-1;
295
  if(strlen(p)>=MAX_LINELEN) {*p=0; return;}
296
  p1=find_word_start(p);if(*p1==0) return;
297
  while(*p1=='+') p1++;
298
  if(p1>p) ovlstrcpy(p,p1);
299
  (void)__replace_badchar(p,"**", "^");
300
  (void)__replace_badchar(p,"\xa0", " ");
12259 bpr 301
 
302
/*if (__replace_badchar(p,"²", "^2 ")) flatpower=1;
12246 bpr 303
  if (__replace_badchar(p,"³", "^3 ")) flatpower=1;
12259 bpr 304
*/
305
  if (__replace_badchar(p,"\xB2", "^2 ")) flatpower=1;
306
  if (__replace_badchar(p,"\xB3", "^3 ")) flatpower=1;
12246 bpr 307
  unmatch=__replace_abs(p);
308
  __replace_plusminus(p) ;
309
  __replace_space(p);
310
  __treat_decimal(p);
311
  if (rawmath_easy) return;
5465 bpr 312
 
8155 bpr 313
/* Principal translation: justapositions to multiplications */
12246 bpr 314
  if(strstr(p,"^1/")!=NULL) badprec=1;
315
  getuservar();
316
  for(p1=p;*p1;p1++) {
317
    if(!isalnum(*p1) && *p1!=')' && *p1!=']') continue;
318
    if(*p1==')' || *p1==']') {
319
      p2=find_word_start(++p1);
320
      add_star:
321
      if(isalnum(*p2) || *p2=='(' || *p2=='[') {
5503 bpr 322
        if(*p2=='(' && *p1==')') ambiguous=1;
323
        if(p2>p1) *p1='*';
324
        else string_modify(p,p1,p1,"*");
12246 bpr 325
      }
326
      p1--;continue;
10 reyssat 327
    }
5503 bpr 328
    p2=find_mathvar_end(p1); p3=find_word_start(p2);
329
    if(myisdigit(*p1)) {
12246 bpr 330
      p1=p2; p2=p3; goto add_star;
5503 bpr 331
    }
332
    else {
12246 bpr 333
      char buf[MAX_LINELEN+1];
334
      int i;
335
      if(p2-p2>30) goto ambig;
336
      memcpy(buf,p1,p2-p1);buf[p2-p1]=0;
337
      i=search_evaltab(buf);
338
      if(i>=0 && get_evaltype(i)>0) {
339
        fnname1:
340
        p1=p2;p2=p3;
8155 bpr 341
/*fnname:*/
12246 bpr 342
        if(*p2 && *p2!='(' && *p2!='*' && *p2!='/') {
343
          char hatbuf[MAX_LINELEN+1];
344
          hatbuf[0]=')'; hatbuf[1]=0;
345
          if(*p2=='^') {
346
            p3=p2+1;while(*p3==' ' || *p3=='+' || *p3=='-') p3++;
347
            if(*p3=='(') {
348
              p3=find_matching(p3+1,')');
349
              if(p3==NULL) {unmatch=1; p3=p+strlen(p);}
350
              else p3++;
5503 bpr 351
            }
12246 bpr 352
            else p3=find_mathvar_end(p3);
353
            memmove(hatbuf+1,p2,p3-p2);hatbuf[p3-p2+1]=0;
354
            ovlstrcpy(p2,p3);
355
            while(*p2==' ') p2++;
356
            if(*p2=='*' || *p2=='/') {
357
              p1--;continue;
5503 bpr 358
            }
12246 bpr 359
            if(*p2=='(') {
360
              p3=find_matching(p2+1,')');
361
              if(p3==NULL) {unmatch=1; p3=p+strlen(p);}
362
              else p3++;
363
              string_modify(p,p3,p3,"%s",hatbuf+1);
364
              goto dd2;
5503 bpr 365
            }
366
          }
12246 bpr 367
          p3=p2;if(*p3=='+' || *p3=='-') p3++;
368
          while(isalnum(*p3) || *p3=='*' || *p3=='/' || *p3=='.')
369
            p3++;
370
          for(p4=p2; p4<p3 && !isalnum(*p4); p4++);
371
          if(p4>=p3) {
372
            if(hatbuf[1]) string_modify(p,p2,p2,"%s",hatbuf+1);
373
          }
374
          else {
375
            string_modify(p,p3,p3,"%s",hatbuf);
376
            if(p1==p2) string_modify(p,p2,p2,"(");
377
            else *p1='(';
378
          }
379
          dd2:
380
          ambiguous=1;
5503 bpr 381
        }
12246 bpr 382
        p1--;continue;
383
      }
384
      i=search_list(mathname,mathname_no,sizeof(mathname[0]),buf);
385
      if(i>=0) {
386
        if(mathname[i].replace[0]!=0) {
387
          string_modify(p,p1,p2,mathname[i].replace);
388
          p2=p1+strlen(mathname[i].replace);
389
          p3=find_word_start(p2);
390
        }
391
        switch(mathname[i].style) {
392
          case RM_FN:
393
            goto fnname1;
7673 bpr 394
 
12246 bpr 395
          case RM_VAR:
396
            p1=p2;p2=p3; goto add_star;
7673 bpr 397
 
12246 bpr 398
          case RM_PREFIX:
399
            if(*p3!='c' && *p3!='s' && *p3!='t' &&
400
              *p3!='C' && *p3!='S' && *p3!='T') break;
401
            ambiguous=1;
402
            ovlstrcpy(p2,p3); p1--; continue;
5503 bpr 403
        }
12246 bpr 404
      }
405
      i=search_list(hmname,hmname_no,sizeof(hmname[0]),buf);
406
      if(i>=0) {
407
        p1=p2; p2=p3; goto add_star;
408
      }
409
      for(i=0;i<rm_uservars && strcmp(buf,rm_uservar[i]);i++);
410
      if(i<rm_uservars) {
5503 bpr 411
          p1=p2;p2=p3;goto add_star;
12246 bpr 412
      }
413
      for(i=0;i<rm_userfns && strcmp(buf,rm_userfn[i]);i++);
414
      if(i<rm_userfns) goto fnname1;
415
      if(p2-p1>8) goto ambig;
416
      if(mathname_split(buf)!=NULL) {
417
        ambiguous=1;
418
        string_modify(p,p1,p2,"%s",buf);
419
        p1--; continue;
420
      }
8155 bpr 421
/* unknown name */
12246 bpr 422
      ambig: p1=p2;p2=p3;
423
      if(strlen(buf)>1) {
424
        for(p3=buf;*p3!=0 && !myisdigit(*p3);p3++);
425
        if(*p3!=0 && flatpower!=0) flatpower=1;
5503 bpr 426
        else {
12246 bpr 427
          unknown=1;
428
          force_setvar("wims_warn_rawmath_parm",buf);
5503 bpr 429
        }
430
      }
12246 bpr 431
      else {
432
        if(*p2=='(') ambiguous=1;
433
      }
434
      if(isalnum(*p2)) {
435
        if(p2>p1) *p1='*';
436
        else string_modify(p,p1,p1,"*");
437
      }
438
      p1--;continue;
5503 bpr 439
    }
12246 bpr 440
  }
441
  warnbuf[0]=0;
442
  if(ambiguous) strcat(warnbuf," ambiguous");
443
  if(unknown) strcat(warnbuf," unknown");
444
  if(flatpower>0) strcat(warnbuf," flatpower");
445
  if(badprec>0) strcat(warnbuf," badprec");
446
  if(unmatch>0) strcat(warnbuf," unmatched_parentheses");
447
  if(warnbuf[0]) {
5503 bpr 448
    char buf[MAX_LINELEN+1],*p;
449
    p=getvar("wims_warn_rawmath");
450
    if(p!=NULL && *p!=0) {
12246 bpr 451
      snprintf(buf,sizeof(buf),"%s %s",p,warnbuf);
452
      force_setvar("wims_warn_rawmath",buf);
10 reyssat 453
    }
5503 bpr 454
    else force_setvar("wims_warn_rawmath",warnbuf);
12246 bpr 455
  }
10 reyssat 456
}
457
 
8155 bpr 458
 /* replace < and > by html code if htmlmath_gtlt=yes
459
  * is only used in deduc - not documented
460
  */
7673 bpr 461
void __replace_htmlmath_gtlt (char *p)
12246 bpr 462
{
463
  char *pp;
464
  char *p1=getvar("htmlmath_gtlt");
465
  if(p1!=NULL && strcmp(p1,"yes")==0) {
466
    for(pp=strchr(p,'<'); pp!=NULL; pp=strchr(pp+1,'<'))
5503 bpr 467
      string_modify(p,pp,pp+1,"&lt;");
12246 bpr 468
    for(pp=strchr(p,'>'); pp!=NULL; pp=strchr(pp+1,'>'))
5503 bpr 469
      string_modify(p,pp,pp+1,"&gt;");
12246 bpr 470
  }
5465 bpr 471
}
472
 
7673 bpr 473
/* exponents or indices :
5551 bpr 474
 *  all digits or + or - following a ^ or _ are considered as in exponent/subscript
475
 *  expression with ( ) following a ^ or _ are  considered as in exponent/subscript
476
 *  the parenthesis are suppressed except in case of exponent and only digits.
8155 bpr 477
 *  if int n != 0, use html code, else use tex code
478
 */
5551 bpr 479
void __replace_exponent(char *p, int n)
5465 bpr 480
{
12246 bpr 481
  char *p1;
482
  char *SUPBEG, *SUPEND;
483
  if (n) { SUPBEG = "<sup>"; SUPEND = "</sup>";}
484
  else { SUPBEG = "^{"; SUPEND = "}";}
5465 bpr 485
 
12246 bpr 486
  for(p1=strchr(p,'^');p1!=NULL;p1=strchr(p1+1,'^')) {
487
    char *p2, *p3, *pp;
488
    char c;
489
    p3 = p2 = find_word_start(p1+1);
490
    if(*p2=='+' || *p2=='-') p2++;
491
    p2 = find_word_start(p2);
8500 bpr 492
/* add '}' to recognized parenthesis in exponent
7673 bpr 493
 * !mathmlmath 2 \cdot x^{3} will now produce correct exponent...
494
 * !mathmlmath should convert LaTeX input into correct MathML
495
 */
12246 bpr 496
    if(*p2=='(' || *p2 == '{') { /* ^[+-]( */
497
      if(*p2 == '('){ p2 = find_matching(p2+1,')');}else { if(*p2 == '{'){ p2 = find_matching(p2+1,'}');}}
5465 bpr 498
            /* no matching ')' : p2 = end of line; otherwise just after ')' */
12246 bpr 499
      if (p2==NULL) p2=p+strlen(p); else p2++;
5465 bpr 500
            /* ^( followed by any number of digits/letters, up to p2
501
             * [FIXME: no sign?] */
502
            /* do we remove parentheses containing exponent group ? */
12246 bpr 503
      if (*p3=='(') for(pp=p3+1;pp<p2-1;pp++) {
504
        if(!isalnum(*pp)) {
7673 bpr 505
                    /* not a digit/letter. Remove (). */
12246 bpr 506
          p3++;*(p2-1)=0;break;
507
        }
5517 bpr 508
                /* x^(2), parentheses not removed */
12246 bpr 509
      }
8155 bpr 510
/* p3: start of word after ^
511
 * matching parentheses from exponent group. : f^(4) 4-derivative
512
 * don't  ignore / remove a leading + sign in exponent group : Cu^+
513
 */
12246 bpr 514
    }
515
    else { /* ^[+-] */
516
      char *ptt=p2;
517
      p2=find_word_start(find_mathvar_end(p2));
518
      if(*p2=='(' && isalpha(*ptt)) {
519
              /* ^[+-]var( */
520
        char *p2t;
521
        p2t=find_matching(p2+1,')'); if(p2t!=NULL) p2=p2t+1;
522
              /* FIXME: what if no matching ) ? */
523
      }
8155 bpr 524
/* ^[+-]var(...): p2 points after closing ')'
525
 * FIXME: I don't think this 'else' branch is sensible. One
526
 * should NOT accept x^b(c+1) as meaning x^[b(c+1)]. I would
527
 * remove it altogether.
528
 */
12246 bpr 529
    }
8155 bpr 530
/* p1 points at ^ before exponent group
531
 * p2 points at end of exponent group
532
 * p3 = exponent group (sometimes stripped, without parentheses)
533
 *
534
 * truncate string p at p2 [ c = char deleted by truncation ]
535
 */
12246 bpr 536
    c = *p2;if(c!=0) *p2++=0;
5465 bpr 537
        /* replace ^<exponent group>. Add back missing character 'c' */
12246 bpr 538
    string_modify(p,p1,p2, "%s%s%s%c",SUPBEG,p3,SUPEND,c);
539
  }
5465 bpr 540
}
541
 
5551 bpr 542
/* if int n != 0, use html code, else use tex code */
543
void __replace_subscript(char *p, int n)
5465 bpr 544
{
545
   char *p1, *p2;
5503 bpr 546
   char *SUBBEG, *SUBEND;
7673 bpr 547
   if (n) {SUBBEG = "<sub>"; SUBEND = "</sub>";}
5503 bpr 548
   else {SUBBEG = "_{"; SUBEND = "}";}
5465 bpr 549
   for(p1=strchr(p,'_');p1!=NULL;p1=strchr(p1+1,'_')) {
5503 bpr 550
     char buff[256];
551
     p2=p1+1;
552
     if(*p2=='(') p2=find_matching(p2+1,')');
553
     else p2=find_mathvar_end(p2);
554
     if(p2==NULL || p2>p1+64) continue;
555
     if(*(p1+1)=='(') p2++;
556
     memmove(buff,p1+1,p2-p1-1); buff[p2-p1-1]=0;
557
     strip_enclosing_par(buff);
558
     string_modify(p,p1,p2,"%s%s%s",SUBBEG,buff,SUBEND);}
5465 bpr 559
}
560
 
5517 bpr 561
/* get rid of 1*.. ..*1  exemple : 1 * x, x/1 */
5465 bpr 562
void __replace_getrid1 (char *p)
12246 bpr 563
{
564
  char *p1, *p2, *p3 ;
565
  for(p1=p;*p1;p1++) {
566
    if(*p1!='1') continue;
567
    if(myisdigit(*(p1+1)) || *(p1+1)=='.' ||
568
      (p1>p && (isalnum(*(p1-1)) || *(p1-1)=='.')) ) continue;
569
    p2=find_word_start(p1+1);
570
    if(p1>p+2 && (*(p1-1)=='-' || *(p1-1)=='+')) {
571
      for(p3=p1-2; p3>p && isspace(*p3); p3--);
572
      if(p3>p+1 && (*p3=='E' || *p3=='e')) { /* ??? */
5503 bpr 573
        p3--; while(p3>p && isspace(*p3)) p3--;
574
        if(myisdigit(*p3) || *p3=='.') continue;
575
      }
12246 bpr 576
    }
577
    if(p1==p) p3="+";
578
    else for(p3=p1-1;p3>p && isspace(*p3);p3--);
579
    if(*p2=='*' && *p3!='/') {/* delete 1 if 1* or /1 */
580
      ovlstrcpy(p1,p2+1);continue;
581
    }
582
    if(isalpha(*p2) && *p3!='/') {
583
      ovlstrcpy(p1,p2);continue;
584
    }
585
    if(*p3=='/' && *p2!='<') ovlstrcpy(p3,p2);
10 reyssat 586
 
12246 bpr 587
  }
5465 bpr 588
}
589
 
590
/* get rid of '*' */
591
void __replace_getridstar (char *p)
12246 bpr 592
{
593
  char *p1 ;
594
  for(p1=strchr(p,'*');p1!=NULL;p1=strchr(p1+1,'*')) {
5503 bpr 595
    char *pq;
596
    pq=find_word_start(p1+1);
597
    if(myisdigit(*pq)) {
12246 bpr 598
      string_modify(p,p1,pq,"&times;");
599
      continue;
10 reyssat 600
    }
5503 bpr 601
    if(p1>p && (isalpha(*(p1-1)) || *(p1-1)==')' || *(p1-1)=='>')
602
       && (isalnum(*pq) || *pq=='$')) *p1=' ';
603
    else {
604
        ovlstrcpy(p1,p1+1);p1--;
605
    }
606
  }
5465 bpr 607
}
608
 
13101 bpr 609
/* <=, >=, ->, =>, <=>, !=, <-> <-->, <-
13144 bpr 610
 * if int n != 0, use html code, else use tex code
8155 bpr 611
 */
5551 bpr 612
 
613
void __replace_arrow ( char *p, int n)
12246 bpr 614
{
615
  char *p1, *p2, *m_prefix;
616
  if (n) m_prefix="$m_"; else m_prefix="\\";
7673 bpr 617
 
12246 bpr 618
  for(p1=strstr(p,"&lt;="); p1!=NULL; p1=strstr(p1+1,"&lt;=")) {
619
    if(*(p1+5)!='&' && *(p1+5)!='=')
620
      string_modify(p,p1,p1+5, "%sle",m_prefix);
621
    else {
622
      for(p2=p1+5; *p2=='='; p2++);
623
      if(strncmp(p2,"&gt;",4)==0) {
624
        if(p2>p1+5) { string_modify(p,p1,p2+4,"%sLongleftrightarrow",m_prefix);}
625
        else { string_modify(p,p1,p2+4,"%sLeftrightarrow",m_prefix);}
5503 bpr 626
      }
12246 bpr 627
      else { string_modify(p,p1,p2,"%sLongleftarrow",m_prefix);}
10 reyssat 628
    }
12246 bpr 629
  }
630
  for(p1=strstr(p,"&gt;="); p1!=NULL; p1=strstr(p1+1,"&gt;=")) {
631
    if(*(p1+5)!='=') { string_modify(p,p1,p1+5,"%sge",m_prefix);}
632
  }
633
  for(p1=strstr(p,"-&gt;"); p1; p1=strstr(p1+1,"-&gt;")) {
634
    for(p2=p1; p2>p && *(p2-1)=='-'; p2--);
635
    if(p2>p && *(p2-1)==';') continue;
636
    if(p2<p1) { string_modify(p,p2,p1+5,"%slongrightarrow",m_prefix);}
637
    else {  string_modify(p,p1,p1+5,"%srightarrow",m_prefix);}
638
  }
639
  for(p1=strstr(p,"=&gt;"); p1; p1=strstr(p1+1,"=&gt;")) {
640
    for(p2=p1; p2>p && *(p2-1)=='='; p2--);
641
    if(p2>p && *(p2-1)==';') continue;
642
    if(p2<p1) { string_modify(p,p2,p1+5,"%sLongrightarrow",m_prefix);}
643
    else { string_modify(p,p1,p1+5,"%sRightarrow",m_prefix) ;}
644
  }
13101 bpr 645
  /* <->, <-->, <- */
646
  /* <-- not implemented because -- is replaced by + elsewhere */
647
  for(p1=strstr(p,"&lt;-"); p1!=NULL; p1=strstr(p1+1,"&lt;-")) {
648
    for(p2=p1+5; *p2=='-'; p2++);
649
    if(strncmp(p2,"&gt;",4)==0)
650
      if ((p2-p1)%2)
651
        string_modify(p,p1,p2+4,(p2>p1+5) ? "%slongleftrightarrow" : "%sleftrightarrow",m_prefix);
652
      else
653
        string_modify(p,p1,p2+4,(p2>p1+6) ? "%sleftrightharpoons" : "%sleftrightharpoons",m_prefix);
654
    else
655
      string_modify(p,p1,p2,(p2>p1+5) ? "%slongleftarrow " : "%sleftarrow ",m_prefix);
656
  }
657
 
658
  /* Not equal */
12246 bpr 659
  for(p1=strstr(p,"!="); p1; p1=strstr(p1+1,"!=")) {
660
    if(p1>p && !isspace(*(p1-1))) continue;
661
    string_modify(p,p1,p1+2,"%sneq",m_prefix);
662
  }
5465 bpr 663
}
664
 
5503 bpr 665
/* why <tt> is used sometimes ? replace single characters by italics one
666
 * is it useful in mathml ?
8155 bpr 667
 */
5551 bpr 668
void __replace_italics (char *p, int n)
12246 bpr 669
{
670
  char *p1, *p2, *p3, pbuf[16];
5503 bpr 671
  char *ITBEG, *ITEND, *ITtBEG, *ITtEND;
5551 bpr 672
   if (n) {
5503 bpr 673
     ITBEG = "<i>";ITtBEG = "<i><tt>";
674
     ITEND = "</i>";ITtEND = "</tt></i>";
675
  } else {;
676
     ITBEG = "" ; ITtBEG = "";
677
     ITEND = ""; ITtEND = "";
678
  }
7673 bpr 679
 
5503 bpr 680
  for(p1=p;*p1;p1++) {
681
    if(*p1=='<') {
12246 bpr 682
      p1=strchr(p1,'>');
683
      if(p1==NULL) break; //recognize an html tag < >
684
      else continue;
10 reyssat 685
    }
5503 bpr 686
    if(*p1=='=' && *(p1+1)=='-') {
687
        string_modify(p,p1+1,p1+1," "); p1+=2; continue;
688
    }
689
    if(*p1=='\'') {
12246 bpr 690
      for(p2=p1+1;*p2=='\'';p2++);
691
      memmove(pbuf,p1,p2-p1); pbuf[p2-p1]=0;
692
      string_modify(p,p1,p2,"%s%s%s",ITtBEG,pbuf,ITtEND);
693
      p1=p2+strlen(ITtBEG)+strlen(ITtEND)-1;
694
      continue;
5503 bpr 695
    }
696
    if(!isalpha(*p1)) continue;
697
/* unique letter.*/
698
    for(p2=p1+1;isalpha(*p2);p2++);
699
    p3=find_word_start(p2);
700
    if(p2>p1+5 ||
701
       (p2>p1+1 && (*p3==';' || *p3=='(' || myisdigit(*p2))))
12246 bpr 702
      {p1=p2-1; continue;}
5503 bpr 703
    if(strncasecmp(p3,"</i>",strlen("</i>"))==0) continue;
704
    memmove(pbuf,p1,p2-p1); pbuf[p2-p1]=0;
705
    string_modify(p,p1,p2,"%s%s%s",ITBEG,pbuf,ITEND);
706
    p1=p2+strlen(ITBEG)+strlen(ITEND)-1;
12246 bpr 707
  }
10 reyssat 708
}
5466 bpr 709
 
5551 bpr 710
/* float (1.2 E-03) : 3E+021 -> 3 × 10^{21} - 3E-21 -> 3 × 10^{-21}
711
 * or replace variable name (alpha)
8155 bpr 712
 * if int n != 0, use html code, else use tex code
713
 */
5551 bpr 714
void __replace_mathvar(char *p,int n)
12246 bpr 715
{
716
  char *p1, *p2, *p3;
5503 bpr 717
  char *EXPBEG, *EXPEND, *EXPBEGMINUS, *SUBBEG, *SUBEND, *m_prefix;
7673 bpr 718
 
5551 bpr 719
  if ( n ) {
12246 bpr 720
    EXPBEG = " &times; 10<sup>";
721
    EXPBEGMINUS = " &times; 10<sup>-";
722
    EXPEND = "</sup>";
723
    SUBBEG = "<sub>";
724
    SUBEND = "</sub>";
725
    m_prefix="$m_";
5503 bpr 726
  } else {
12246 bpr 727
    EXPBEG = " \\times 10^{" ;
728
    EXPBEGMINUS = " \\times 10^{-" ;
729
    EXPEND = "}";
730
    SUBBEG = "_{";
731
    SUBEND = "}";
732
    m_prefix="\\";
5466 bpr 733
  }
5503 bpr 734
  for (p1=find_mathvar_start(p);*p1!=0;p1=find_mathvar_start(p2)) {
735
    char buf[MAX_LINELEN+1];
8155 bpr 736
/* if the variable is preceded by \ do nothing
737
 * in fact this should not arrive
738
 */
7673 bpr 739
    if (p1>p && *(p1-1) == '\\' ) break ;
5503 bpr 740
    p2 = find_mathvar_end(p1);
12246 bpr 741
    if (p1 == p2) break;
5503 bpr 742
    memmove(buf,p1,p2-p1);buf[p2-p1]=0;
5466 bpr 743
 
5503 bpr 744
    if(myisdigit(buf[0])) {
8155 bpr 745
/* number : 3E+021 -> 3 x 10^{21} - 3E-21 -> 3 x 10^{-21} */
12246 bpr 746
      int k = 1, minus = 0;
5503 bpr 747
 
748
/* see putnumber in texmath.c*/
12246 bpr 749
      if( (p3 = strpbrk(buf, "Ee")) == NULL) continue;
750
      p1 += p3-buf;
5503 bpr 751
            //count the number of 0, +, -
12246 bpr 752
      if (*(p1+k) == '-') { minus = 1; k++; }
753
      while(*(p1+k)=='0' || *(p1+k)=='+') k++;
5503 bpr 754
 
12246 bpr 755
      string_modify(p,p1,p1+k, minus? EXPBEGMINUS: EXPBEG);
756
      p2 += strlen(minus? EXPBEGMINUS: EXPBEG)-k;
757
      string_modify(p,p2,p2, EXPEND);
758
      p2 += strlen(EXPEND);
759
    }
760
    else {
8155 bpr 761
/* alphabetic name, replace greek letters and symbols in hmname
762
 * not done in texmath.c
763
 */
12246 bpr 764
      int i = search_list(hmname,hmname_no,sizeof(hmname[0]),buf);
765
      char *n, *r;
766
      if(i<0) { /* not in list */
767
        int k = strlen(buf)-1;
768
        if(myisdigit(buf[k])) {
769
          while(k>0 && myisdigit(buf[k-1])) k--;
770
          string_modify(buf,buf+k,buf+k,SUBBEG);
771
          string_modify(p,p1,p2,"%s%s",buf,SUBEND);
772
          p2+=strlen(SUBBEG)+strlen(SUBEND);
5503 bpr 773
        }
12246 bpr 774
        continue;
775
      }
776
      n = hmname[i].name;
777
      r = mathalign_base < 2? hmname[i].replace: hmname[i].replacem;
778
      if(r[0]==0) { /* replace = "" */
779
        string_modify(p,p1,p2,"%s%s",m_prefix, n);
780
        p2 = p1+strlen(n)+strlen(m_prefix);
781
      } else {
782
        string_modify(p,p1,p2,"%s",r);
783
        p2 = p1+strlen(r);
784
      }
785
    }
5503 bpr 786
  }
5465 bpr 787
}
788
 
7673 bpr 789
/* translate raw math expression coming from calculators into best html way
8155 bpr 790
 * if int n != 0, use html code, else use tex code
791
 */
5551 bpr 792
void __htmlmath(char *p,int n)
5465 bpr 793
{
12246 bpr 794
  if(!rawmath_easy) { rawmath_easy=1; rawmath(p); rawmath_easy=0;}
795
  __replace_htmlmath_gtlt(p); //only used in deductio
796
  __replace_exponent(p,n);
797
  __replace_subscript(p,n);
798
  __replace_getrid1(p);
799
  __replace_mathvar(p,n);
800
  __replace_getridstar(p);
801
  __replace_arrow(p,n);
5503 bpr 802
/* Now make substitutions */
12246 bpr 803
  substit(p);
5503 bpr 804
/* Make single names italic - done automatically by mathml */
5551 bpr 805
   __replace_italics(p,n);
5465 bpr 806
   strip_trailing_spaces(p);
807
}
808
 
7673 bpr 809
void htmlmath(char *p)
5465 bpr 810
{
5551 bpr 811
 __htmlmath(p,1) ;
5544 bpr 812
}
813
 
814
/* if mathml is closed, it will be just htmlmath*/
815
 
7673 bpr 816
void mathmlmath(char *p)
817
{
8500 bpr 818
    /*
819
     if force_mathml variable is set to "yes", do not (never) use 'htmlmath'
820
     in output, so command: !mathmlmath some_LaTeX_string will produce mathml
821
     (mathml \input inputfields may be included)
8499 schaersvoo 822
    */
12246 bpr 823
  if( strcmp( getvar("force_mathml"),"yes") == 0 ){ mathalign_base = 2;mathml(p,1);return; }
824
  if (mathalign_base == 2) { __htmlmath(p,0) ; mathml(p,1);} else { __htmlmath(p,1) ;}
5465 bpr 825
}