Subversion Repositories wimsdev

Rev

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