Subversion Repositories wimsdev

Rev

Rev 5512 | Rev 5516 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  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. /* subroutines for texmath */
  18.  
  19.         /* Careful! increasing this number risks stack overflow. */
  20. #define MAX_FACTORS 256
  21.  
  22. enum {
  23.     type_integer, type_numeric, type_var,
  24.       type_poly, type_transcend
  25. };
  26.  
  27. typedef struct afactor{
  28.     char *beg, *end;
  29.     int type, side;
  30. } afactor;
  31.  
  32. char texmathbuf[MAX_LINELEN+1];
  33. char *find_term_end(char *p);
  34. void t_onestring(char *p);
  35. void t_oneterm(char *p, int num);
  36. void t_onefactor(struct afactor *p, int num);
  37. void n_onestring(char *p);
  38. void n_oneterm(char *p, int num);
  39. void n_onefactor(struct afactor *p, int num);
  40. void texmath(char *p);
  41.  
  42. /* print to texmathbuf */
  43. void tprint(char *s,...)
  44. {
  45.     va_list vp;
  46.     char buf[MAX_LINELEN+1];
  47.  
  48.     va_start(vp,s); vsnprintf(buf,sizeof(buf),s,vp); va_end(vp);
  49.     if(strlen(buf)+strlen(texmathbuf)>=MAX_LINELEN)
  50.       user_error("cmd_output_too_long");
  51.     strcat(texmathbuf,buf);
  52. }
  53. /* transforms sum(n,n=1..infinity) , product(n/(n+1),n=1..infinity). */
  54. void _tex_sums(char *p, char *name, int type)
  55. {
  56.     char *p1,*p2,*p3;
  57.     p1=find_item_end(p); if(*p1) *(p1++)=0;
  58.     p2=find_item_end(p1); p3=strparstr(p1,"=");
  59.     if(p3<p2) p2=p3; if(*p2) *(p2++)=0;
  60.     p3=find_item_end(p2);
  61.     if(*p3) *(p3++)=0;
  62.     tprint("\\%s ",name);
  63.     if(type) {
  64.       if(*p2) {
  65.         tprint("_{"); t_onestring(p2); tprint("}");
  66.       }
  67.     }
  68.     else if(*p1) {
  69.       tprint("_{%s",p1);
  70.       if(*p2) { tprint("="); t_onestring(p2); }
  71.       tprint("}");
  72.     }
  73.     if(*p3) {
  74.       tprint("^{"); t_onestring(p3); tprint("}");
  75.     }
  76.     strip_trailing_spaces(p); if(find_term_end(p)<p+strlen(p)) {
  77.       tprint("\\left("); t_onestring(p); tprint("\\right)");
  78.     }
  79.     else t_onestring(p);
  80.     if(type && *p1) {
  81.       strip_trailing_spaces(p1); tprint("d"); // case of the integrale
  82.       if(find_term_end(p1)<p1+strlen(p1)) {
  83.         tprint("\\left("); t_onestring(p1); tprint("\\right)");
  84.       }
  85.       else t_onestring(p1);
  86.     }
  87. }
  88.  
  89. /* integration, sum and product */
  90. void tex_int(char *p) {  _tex_sums(p,"int",1); }
  91. void tex_sum(char *p) {  _tex_sums(p,"sum",0); }
  92. void tex_prod(char *p) { _tex_sums(p,"prod",0);}
  93.  
  94. struct {
  95.     char *name;
  96.     int expind;
  97.     char *left, *right;
  98.     void (*routine) (char *p);
  99. } tmathfn[]={
  100.       {"Arg",      1,  "\\rm{Arg}",      "\\right)"},
  101.       {"Int",      2,  "","",        tex_int},
  102.       {"Prod",     2,  "","",        tex_prod},
  103.       {"Sum",      2,  "","",        tex_sum},
  104.       {"abs",      0,  "\\left|",      "\\right|"},
  105.       {"acos",     1,  "\\rm{arccos}",  "\\right)"},
  106.       {"acosh",    1,  "\\rm{Argch}",      "\\right)"},
  107.       {"arg",      1,  "\\rm{Arg}",      "\\right)"},
  108.       {"asin",     1,  "\\rm{arcsin}",  "\\right)"},
  109.       {"asinh",    1,  "\\rm{Argsh}",      "\\right)"},
  110.       {"atan",     1,  "\\rm{arctg}",      "\\right)"},
  111.       {"atanh",    1,  "\\rm{Argth}",      "\\right)"},
  112.       {"ch",       1,  "\\rm{ch}",      "\\right)"},
  113.       {"conj",     0,  "\\overline{",      "}"},
  114.       {"conjugate",0,  "\\overline{",      "}"},
  115.       {"cos",      1,  "\\cos",      "\\right)"},
  116.       {"cosh",     1,  "\\rm{ch}",      "\\right)"},
  117.       {"cot",      1,  "\\rm{ctg}",      "\\right)"},
  118.       {"cotan",    1,  "\\rm{ctg}",      "\\right)"},
  119.       {"cotanh",   1,  "\\rm{cth}",      "\\right)"},
  120.       {"csc",      1,  "\\rm{csc}",      "\\right)"},
  121.       {"ctg",      1,  "\\rm{ctg}",      "\\right)"},
  122.       {"cth",      1,  "\\rm{cth}",      "\\right)"},
  123.       {"det",      1,  "\\rm{det}",      "\\right)"},
  124.       {"erf",      1,  "\\rm{erf}",      "\\right)"},
  125.       {"exp",      1,  "\\exp",      "\\right)"},
  126.       {"int",      2,  "","",        tex_int},
  127.       {"integrate",2,  "","",        tex_int},
  128.       {"lg",       1,  "\\rm{lg}",      "\\right)"},
  129.       {"ln",       1,  "\\ln",        "\\right)"},
  130.       {"log",      1,  "\\log",      "\\right)"},
  131.       {"prod",     2,  "","",        tex_prod},
  132.       {"product",  2,  "","",        tex_prod},
  133.       {"sec",      1,  "\\rm{sec}",      "\\right)"},
  134.       {"sgn",      1,  "\\rm{sgn}",      "\\right)"},
  135.       {"sh",       1,  "\\rm{sh}",      "\\right)"},
  136.       {"sign",     1,  "\\rm{sign}",      "\\right)"},
  137.       {"sin",      1,  "\\sin",      "\\right)"},
  138.       {"sinh",     1,  "\\rm{sh}",      "\\right)"},
  139.       {"sqrt",     0,  "\\sqrt{",      "}"},
  140.       {"sum",      2,  "","",        tex_sum},
  141.       {"tan",      1,  "\\tan",      "\\right)"},
  142.       {"tanh",     1,  "\\rm{th}",      "\\right)"},
  143.       {"tg",       1,  "\\rm{tg}",      "\\right)"},
  144.       {"th",       1,  "\\rm{th}",      "\\right)"}
  145. };
  146.  
  147. #define tmathfn_no (sizeof(tmathfn)/sizeof(tmathfn[0]))
  148.  
  149. struct {
  150.     char *name, *tex;
  151. } tmathvar[]={
  152.       {"CC",      "\\mathbb{C}"},
  153.       {"Delta",   "\\Delta"},
  154.       {"Gamma",   "\\Gamma"},
  155.       {"Inf",     "\\infty"},
  156.       {"Lambda",  "\\Lambda"},
  157.       {"NN",      "\\mathbb{N}"},
  158.       {"Omega",   "\\Omega"},
  159.       {"PI",      "\\pi"},
  160.       {"Phi",     "\\Phi"},
  161.       {"Pi",      "\\Pi"},
  162.       {"Psi",     "\\Psi"},
  163.       {"QQ",      "\\mathbb{Q}"},
  164.       {"RR",      "\\mathbb{R}"},
  165.       {"Sigma",   "\\Sigma"},
  166.       {"Theta",   "\\Theta"},
  167.       {"Upsilon", "\\Upsilon"},
  168.       {"Xi",      "\\Xi"},
  169.       {"ZZ",      "\\mathbb{Z}"},
  170.       {"aleph",   "\\aleph"},
  171.       {"alpha",   "\\alpha"},
  172.       {"beta",   "\\beta"},
  173.       {"chi",    "\\chi"},
  174.       {"delta",  "\\delta"},
  175.       {"epsilon","\\epsilon"},
  176.       {"eta",    "\\eta"},
  177.       {"gamma",  "\\gamma"},
  178.       {"inf",    "\\infty"},
  179.       {"infinity","\\infty"},
  180.       {"infty",  "\\infty"},
  181.       {"iota",   "\\iota"},
  182.       {"kappa",  "\\kappa"},
  183.       {"lambda", "\\lambda"},
  184.       {"mu",     "\\mu"},
  185.       {"neq",    "\\neq"},
  186.       {"nu",     "\\nu"},
  187.       {"omega",  "\\omega"},
  188.       {"phi",    "\\phi"},
  189.       {"pi",     "\\pi"},
  190.       {"psi",    "\\psi"},
  191.       {"rho",    "\\rho"},
  192.       {"sigma",  "\\sigma"},
  193.       {"tau",    "\\tau"},
  194.       {"theta",  "\\theta"},
  195.       {"xi",     "\\xi"},
  196.       {"zeta",   "\\zeta"}
  197. };
  198.  
  199. #define tmathvar_no (sizeof(tmathvar)/sizeof(tmathvar[0]))
  200.  
  201.  
  202. /* find the end of an additive term. */
  203. char *find_term_end(char *p)
  204. {
  205.     char *pp;
  206.     pp=p;
  207.     if(*pp==',' || *pp==';' || *pp=='=' || *pp=='<') pp++;
  208.     while(*pp=='+' || *pp=='-' || *pp=='=' || *pp=='>') pp++;
  209.     for(;*pp;pp++) {
  210.       switch(*pp) {
  211.         case '(': pp=find_matching(pp+1,')'); goto loopend;
  212.         case '[': pp=find_matching(pp+1,']'); goto loopend;
  213. /*     case '{': pp=find_matching(pp+1,'}'); goto loopend;*/
  214.          
  215.         case 0:
  216.         case '<':
  217.         case '>':
  218.         case ',':
  219.         case ';':
  220.         case '=':
  221.         case ')':
  222.         case ']':
  223.         case '}':
  224.         case '-':
  225.         case '+': return pp;
  226.  
  227.         case '*':
  228.         case '/':
  229.         case '^': {
  230.           while(*(pp+1)=='+' || *(pp+1)=='-') pp++;
  231.           goto loopend;
  232.         }
  233.       }
  234.       if(isalnum(*pp) || *pp=='.') {
  235.         pp=find_mathvar_end(pp); pp--; continue;
  236.       }
  237.       continue;
  238.       loopend:
  239.       if(pp==NULL) module_error("unmatched_parentheses");
  240.     }
  241.     return pp;
  242. }
  243.  
  244. /* find the end of an multiplicative factor. */
  245. char *find_factor_end(char *p)
  246. {
  247.     char *pp;
  248.     pp=p; if(*pp==',' || *pp==';' || *pp=='=') pp++;
  249.     while(*pp=='+' || *pp=='-' || *pp=='*' || *pp=='/') pp++;
  250.     for(;*pp;pp++) {
  251.       switch(*pp) {
  252.         case '(': pp=find_matching(pp+1,')'); goto loopend;
  253.         case '[': pp=find_matching(pp+1,']'); goto loopend;
  254. /*    case '{': pp=find_matching(pp+1,'}'); goto loopend;*/
  255.        
  256.         case 0:
  257.         case '<':
  258.         case '>':
  259.         case ',':
  260.         case ';':
  261.         case '=':
  262.         case ')':
  263.         case ']':
  264.         case '}':
  265.         case '+':
  266.         case '-':
  267.         case '*':
  268.         case '/': return pp;
  269.    
  270.         case '^': {
  271.           while(*(pp+1)=='+' || *(pp+1)=='-') pp++;
  272.           goto loopend;
  273.         }
  274.       }
  275.       if(isalnum(*pp) || *pp=='.') {
  276.         pp=find_mathvar_end(pp); pp--; continue;
  277.       }
  278.       continue;
  279.       loopend:
  280.       if(pp==NULL) module_error("unmatched_parentheses");
  281.     }
  282.     return pp;
  283. }
  284.  
  285.     /* returns the number of terms */
  286. int term_cnt(char *p)
  287. {
  288.     char *pe, *pp;
  289.     int i;
  290.    
  291.     pe=p+strlen(p);
  292.     for(i=0,pp=p;pp<pe;pp=find_term_end(pp),i++);
  293.     return i;
  294. }
  295.  
  296. /* Print a number: transform 4E+05 in 4 \times 10^{5} and  4E-05 in 4 \times 10^{-5}
  297. suppress multiple + or 0 - see rawmath.c
  298. */
  299. void putnumber(char *p)
  300. {
  301.     char *pp;
  302.     pp=strpbrk(p,"Ee");
  303.     if(pp==NULL) {tprint("%s",p); return;}
  304.     *pp++=0;
  305.     if (pp[0]=='-') { tprint("%s \\times 10^{-",p) ; *pp++; } else tprint("%s \\times 10^{",p);
  306.     int k;
  307.     for(k=0; *(pp+k)=='0' || *(pp+k)=='+'; k++ );
  308.     pp=pp+k;
  309.     tprint("%s}",pp);
  310. }
  311.  
  312. /* Print a variable name ; transform abc475 in abc_475 */
  313. void putvar(char *p)
  314. {
  315.     char vbuf[1024];
  316.     char *pp, *p2;
  317.     int i;
  318.    
  319.     vbuf[0]=0;
  320.     if(*(p+1)==0) {tprint("%c",*p); return;}
  321.     for(pp=p;isalpha(*pp);pp++);
  322.     if(myisdigit(*pp)) {
  323.     for(p2=pp+1;myisdigit(*p2);p2++);
  324.     if(*p2==0) {/* subscript */
  325.         mystrncpy(vbuf,pp,sizeof(vbuf));*pp=0;
  326.     }
  327.     }
  328.     i=search_list(tmathvar, tmathvar_no, sizeof(tmathvar[0]), p);
  329.     if(i>=0) tprint("%s ",tmathvar[i].tex);
  330.     else tprint("%s ",p);
  331.     if(vbuf[0]) {
  332.     if(vbuf[1]==0) tprint("_%c ",vbuf[0]);
  333.     else tprint("_{%s} ",vbuf);
  334.     }
  335. }
  336.  
  337. /* sort according to type */
  338. int fsort(const void *p1, const void *p2)
  339. {
  340.     struct afactor *t1, *t2;
  341.     int i1,i2;
  342.    
  343.     t1=*(struct afactor **) p1; t2=*(struct afactor **) p2;
  344.     i1=t1->type; i2=t2->type;
  345.     if(i1>type_var) i1=type_var; if(i2>type_var) i2=type_var;
  346.     return i1-i2;
  347. }
  348.  
  349. void t_oneterm(char *p, int num)
  350. {
  351.     int sign, fcnt, s, i, dentype, rel;
  352.     char *pp, *pe, *pt;
  353.     struct afactor factors[MAX_FACTORS];
  354.     struct afactor *numerator[MAX_FACTORS],
  355.       *denominator[MAX_FACTORS],
  356.       *neutral[MAX_FACTORS];
  357.     int numcnt,dencnt,neucnt;
  358. /* interpret some arrows */
  359.     rel=0; switch(*p) {
  360.       case '<': {
  361.         rel++; p++; if(*p!='=') {tprint(" < "); break;} // <
  362.         do p++; while(*p=='=');
  363.         if(*p!='>') {tprint("\\le ");break;} // <= , <===
  364.         else {tprint("\\iff ");p++; break;} // <==>
  365.       }
  366.       case '>': {
  367.         rel++; p++; if(*p!='=') {tprint(" > "); rel=1; break;} // >
  368.         while(*p=='=') p++; tprint("\\ge "); // >=
  369.         break;
  370.       }
  371.       case '-': {
  372.         for(pp=p;*pp=='-';pp++);
  373.         if(*pp!='>') break;
  374.         rel++; tprint("\\to "); p=++pp; //->
  375.         break;
  376.       }
  377.      case '=': {
  378.         rel++; for(pp=p;*pp=='=';pp++);
  379.         if(*pp!='>') break;
  380.         tprint("\\Rightarrow "); p=++pp; // =>
  381.         break;
  382.       }
  383.     }
  384.     if(*p==',' || *p==';' || *p=='=') {tprint("%c",*p); p++; num=0;}
  385.     sign=1; while(*p=='+' || *p=='-') {
  386.       if(*p=='-') sign*=-1;
  387.       p++;
  388.     }
  389.     for(fcnt=0, pp=p; fcnt<MAX_FACTORS && *pp; fcnt++, pp=pe) {
  390.       s=1;
  391.       while(*pp=='*' || *pp=='/') {
  392.         if(*pp=='/') s=-1;
  393.         pp++;
  394.       }
  395.       factors[fcnt].side=s;
  396.       while(*pp=='+' || *pp=='-') {
  397.         if(*pp=='-') sign*=-1;
  398.         pp++;
  399.       }
  400.       pe=find_factor_end(pp); if(pe<=pp) break;
  401.       factors[fcnt].beg=pp; factors[fcnt].end=pe;
  402.       if(pe-pp==1 && *pp=='1') fcnt--;
  403.       if(*pp=='(') {
  404.         char *pt, *pe2, buf[MAX_LINELEN+1];
  405.         int ss;
  406.         pp++; pt=find_matching(pp,')');
  407.         if(pt>=pe-1) {
  408.           memmove(buf,pp,pt-pp); buf[pt-pp]=0;
  409.           i=term_cnt(buf);
  410.           if(i==1) { /* remove parentheses */
  411.               for(;pp<pt && fcnt<MAX_FACTORS;pp=pe2,fcnt++) {
  412.                 ss=s; while(*pp=='*' || *pp=='/') {
  413.                     if(*pp=='/') ss=-1;
  414.                     pp++;
  415.                 }
  416.                 factors[fcnt].side=ss;
  417.                 while(*pp=='+' || *pp=='-') {
  418.                     if(*pp=='-') sign*=-1;
  419.                     pp++;
  420.                 }
  421.                 pe2=find_factor_end(pp);
  422.                 if(pe2<=pp) goto bailout;
  423.                 factors[fcnt].beg=pp; factors[fcnt].end=pe2;
  424.                 if(pe2-pp==1 && *pp=='1') fcnt--;
  425.               }
  426.               fcnt--;
  427.           }
  428.         }
  429.       }
  430.     }
  431.     bailout:
  432. /* decide if the factor is of type numeric, integer, poly, transcend or variable
  433. *  (see priorities)
  434. */
  435.     for(i=0;i<fcnt;i++) {
  436.       pp=factors[i].beg; pe=factors[i].end;
  437.       if(myisdigit(*pp) || *pp=='.') {
  438.         for(pt=pp;pt<pe && myisdigit(*pt);pt++);
  439.         if(pt<pe) factors[i].type=type_numeric; // digits with a point
  440.         else factors[i].type=type_integer;  // digits without point
  441.         continue;
  442.       }
  443.       if(*pp=='(') {
  444.         factors[i].type=type_poly; continue; //there exists a parenthesis
  445.       }
  446.       pt=strchr(pp,'(');
  447.       if(pt!=NULL && pt<pe) factors[i].type=type_transcend; //??
  448.       else factors[i].type=type_var;  // variable in other cases
  449.     }
  450.     dentype=-1;
  451.     for(i=0;i<fcnt;i++) if(factors[i].side<0 && factors[i].type>dentype)
  452.       dentype=factors[i].type; // denominator type will be compared to the type of the factors
  453.     dencnt=numcnt=neucnt=0;
  454.     for(i=0;i<fcnt;i++) {
  455.       if(factors[i].type>dentype) neutral[neucnt++]=factors+i;
  456.       else {
  457.         if(factors[i].side>0) numerator[numcnt++]=factors+i;
  458.         else denominator[dencnt++]=factors+i;
  459.       }
  460.     }
  461.     if(dencnt>0) qsort(denominator,dencnt,sizeof(denominator[0]),fsort);
  462.     if(numcnt>0) qsort(numerator,numcnt,sizeof(numerator[0]),fsort);
  463.     if(neucnt>0) qsort(neutral,neucnt,sizeof(neutral[0]),fsort);
  464.     if(sign>0 && num>0 && rel==0) tprint(" +");
  465.     if(sign<0) tprint(" -");
  466.     if(fcnt<1) tprint("1 ");
  467.     if(dencnt>0) {
  468.       tprint(" {");
  469.       if(numcnt==0) tprint(" 1"); // no numerator ? will write {1 over denominator}
  470.       else {/* numerator */
  471.         if(numcnt==1 && *numerator[0]->beg=='(' &&
  472.            find_matching(numerator[0]->beg+1,')')==(numerator[0]->end)-1) {
  473.           *(numerator[0]->end-1)=0;
  474.           t_onestring(numerator[0]->beg+1);
  475.           *(numerator[0]->end-1)=')';
  476.         }
  477.         else for(i=0; i<numcnt; i++) t_onefactor(numerator[i],i);
  478.       }
  479.       tprint(" \\over ");      /* Now denominator */
  480.       if(dencnt==1 && *denominator[0]->beg=='(' &&
  481.         find_matching(denominator[0]->beg+1,')')==(denominator[0]->end)-1) {
  482.          *(denominator[0]->end-1)=0;
  483.          t_onestring(denominator[0]->beg+1);
  484.          *(denominator[0]->end-1)=')';
  485.       }
  486.       else for(i=0;i<dencnt;i++) t_onefactor(denominator[i],i);
  487.       tprint("} ");
  488.     }
  489.     for(i=0;i<neucnt;i++) t_onefactor(neutral[i],i+dencnt);
  490. }
  491.  
  492.     /* put exponential */
  493. void t_exponential(char *pp)
  494. {
  495.     char *pe, *pt;
  496.     int t=0;
  497.    
  498.     while(*pp && strchr("!'\"",*pp)!=NULL) {
  499.       tprint("%c",*pp); pp++;
  500.     }
  501.     if(*pp=='^') pp++; else return;
  502.     if(*pp=='(') {
  503.       pe=find_matching(pp+1,')');
  504.       if(*(pe+1)==0) {
  505.         pp++;*pe=0;
  506.         for(pt=pp;*pt && (isalnum(*pt) || *pt=='.');pt++);
  507.         if(*pt==0) t=1;
  508.       }
  509.     }
  510.     if(strlen(pp)==1 && t==0) tprint("^%s ",pp);
  511.     else {
  512.       tprint(" ^{"); if(t) tprint("(");
  513.       t_onestring(pp);
  514.       if(t) tprint(")"); tprint("} ");
  515.     }
  516. }
  517.  
  518. void t_onefactor(struct afactor *fb, int num)
  519. {
  520.     char *p, *pe, lp, *rp, rp2, rpbuf[128];
  521.     char fbuf[MAX_LINELEN+1], pbuf[MAX_LINELEN+1];
  522.     int i;
  523.  
  524.     memmove(pbuf,fb->beg,fb->end-fb->beg);
  525.     pbuf[fb->end-fb->beg]=0;
  526.     if(num>0 && (myisdigit(pbuf[0]) || pbuf[0]=='.'))
  527.       tprint("\\times ");
  528.     rp2=')'; p=pbuf;
  529.     if(strchr("({[",*p)!=NULL) {
  530.     lp=*p; switch(lp) {
  531.         case '(': rp2=')';  break;
  532.         case '[': { /* verify for matrices */
  533.           char *pt;
  534.           pe=find_matching(p+1,']');
  535.           for(pt=p+1;pt<pe;pt++) {
  536.               switch(*pt) {
  537.                 case '(': pt=find_matching(pt+1,')'); break;
  538.                 case '[': pt=find_matching(pt+1,']'); break;
  539.                 case '{': pt=find_matching(pt+1,'}'); break;
  540.                 case '|': pt=find_matching(pt+1,'|'); break;
  541.                
  542.                 case ',':
  543.                 case ';': goto out;
  544.               }
  545.           }
  546.           out: if(*pt==';' || *pt==',') { /* is matrix of the form [ 1,2;5,6] */
  547.               char mbuf[MAX_LINELEN+1];
  548.               char *pp, *pt;
  549.  
  550.               p++; if(*pe) *pe++=0;
  551.               tprint(" \\begin{pmatrix}");
  552.               for(pp=p,i=0;*pp;pp=pt,i++) {
  553.                 pt=find_term_end(pp);
  554.                 memmove(mbuf,pp,pt-pp); mbuf[pt-pp]=0;
  555.                 t_oneterm(mbuf,i);
  556.                 if(*pt==',') {
  557.                     tprint(" &"); pt++; i=-1;
  558.                 }
  559.                 if(*pt==';') {
  560.                     tprint("\\cr "); pt++; i=-1;
  561.                 }
  562.               }
  563.               tprint(" \\end{pmatrix}"); goto expon;
  564.           }
  565.           rp2=']'; break;
  566.         }
  567.         case '{': { /* protected */
  568.           pe=find_matching(p+1,'}');
  569.           *pe=0;tprint(" %s} ",p);
  570.           goto expon;
  571.         }
  572.     }
  573.     tprint(" \\left%c",lp);
  574.     snprintf(rpbuf,sizeof(rpbuf),"\\right%c ",rp2); rp=rpbuf;
  575.     paren: p++;pe=find_matching(p,rp2); *pe=0;
  576.     t_onestring(p); tprint(rp); pe++; goto expon;
  577.     }
  578.     pe=find_mathvar_end(p); while(*pe && strchr("'\"!",*pe)!=NULL) pe++;
  579.     memmove(fbuf,p,pe-p); fbuf[pe-p]=0;
  580.     if(myisdigit(*p) || *p=='.') putnumber(fbuf);
  581.     if(isalpha(*p)) {
  582.     pe=find_mathvar_end(p); while(*pe && strchr("'\"!",*pe)!=NULL) pe++;
  583.     if(*pe=='(') {
  584.         p=pe;
  585. /* search in list of math functions*/
  586.         i=search_list(tmathfn, tmathfn_no, sizeof(tmathfn[0]), fbuf);
  587.         if(i>=0) {
  588.           switch(tmathfn[i].expind) {
  589.               case 0: {
  590.                 tprint(" %s",tmathfn[i].left);
  591.                 rp=tmathfn[i].right; break;
  592.               }
  593.               case 1: {
  594.                 tprint(" %s",tmathfn[i].left);
  595.                 pe=find_matching(pe+1,')')+1;
  596.                 if(*pe && strchr("^'\"!",*pe)!=NULL) {
  597.                     t_exponential(pe); *pe=0;
  598.                 }
  599.                 tprint(" \\left("); rp=tmathfn[i].right;
  600.                 break;
  601.               }
  602.               case 2: {  /* routine */
  603.                 p++;pe=find_matching(p,rp2); *pe=0;
  604.                 tmathfn[i].routine(p);
  605.                 pe++; goto expon;
  606.               }
  607.               default: rp=""; break;
  608.           }
  609.         }
  610.         else {
  611.           putvar(fbuf);
  612.           rp="\\right) "; tprint(" \\left(");
  613.         }
  614.         rp2=')'; goto paren;
  615.     }
  616.     else {
  617.         putvar(fbuf);
  618.         if(*pe=='_') {
  619.           char *ptt, buff[256];
  620.           tprint("_"); pe++;
  621.           if(*pe=='(') {
  622.               ptt=find_matching(pe+1,')'); if(ptt) ptt++;
  623.           }
  624.           else {
  625.               if(*pe=='{') {
  626.                 ptt=find_matching(pe+1,'}'); if(ptt) ptt++;
  627.               }
  628.               else ptt=find_mathvar_end(pe);
  629.           }
  630.           if(ptt==NULL || ptt-pe>128) goto expon;
  631.           memmove(buff,pe,ptt-pe); buff[ptt-pe]=0; pe=ptt;
  632.           strip_enclosing_par(buff);
  633.           tprint("{%s}",buff);
  634.         }
  635.     }
  636.     }
  637.     /* exponential */
  638.     expon: if(*pe && strchr("^'\"!",*pe)!=NULL) t_exponential(pe);
  639. }
  640.  
  641. void t_onestring(char *p)
  642. {
  643.     char termbuf[MAX_LINELEN+1];
  644.     char *pp, *pe;
  645.     int i;
  646.  
  647.     for(pp=p,i=0;*pp;pp=pe,i++) {
  648.     pe=find_term_end(pp);
  649.     memmove(termbuf,pp,pe-pp); termbuf[pe-pp]=0;
  650.     t_oneterm(termbuf,i);
  651.     }
  652. }
  653. /* replace \pmatrix{  } by latex syntax \begin{pmatrix} .. \end{pmatrix} */
  654.  
  655. void _replace_matrix ( char *p , char *s_mat1, char *s_mat2 )
  656. { char pbuf[MAX_LINELEN];
  657.   while ( (p = strstr(p,s_mat1)) )
  658.   { char *p2 = find_matching(p+strlen(s_mat1),'}');
  659.     long len = p2-p-strlen(s_mat1);
  660.     if (!p2) { module_error("unmatched_parentheses"); return; }
  661.     memcpy(pbuf, p+strlen(s_mat1), len); pbuf[len]= 0;
  662.     p2 ++ ;
  663.     string_modify(p, p, p2, "\\begin{%s}%s\\end{%s}",s_mat2,pbuf,s_mat2);
  664.   }
  665. }
  666.  
  667. /* translate raw math expression into TeX source */
  668. void texmath(char *p)
  669. {
  670.     char *pp;
  671.     _replace_matrix (p,"\\matrix{","matrix");
  672.     _replace_matrix (p,"\\pmatrix{","pmatrix");
  673.     if(strpbrk(p,"{}\\")!=NULL) return;
  674.     for(pp=strstr(p,"!="); pp; pp=strstr(pp+1,"!=")) {
  675.       if(pp>p && !isspace(*(pp-1))) continue;
  676.       string_modify(p,pp,pp+2,"*neq*");
  677.     }
  678. /* remove spaces */
  679.     for(pp=p; *pp; pp++) {
  680.     if(isspace(*pp)) {ovlstrcpy(pp,pp+1); pp--;}
  681.     }
  682.     /* replace ** by ^ */
  683.     for(pp=strstr(p,"**"); pp!=NULL; pp=strstr(pp,"**")) {
  684.       *pp='^'; ovlstrcpy(pp+1,pp+2);
  685.     }
  686.     if(check_parentheses(p,1)!=0) module_error("unmatched_parentheses");
  687.     texmathbuf[0]=0; t_onestring(p);
  688.     mystrncpy(p,texmathbuf,MAX_LINELEN);
  689. }
  690.