Subversion Repositories wimsdev

Rev

Rev 10 | Rev 5459 | 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.  
  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");
  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 */
  297. void putnumber(char *p)
  298. {
  299.     char *pp;
  300.     pp=strpbrk(p,"Ee");
  301.     if(pp==NULL) {tprint("%s",p); return;}
  302.     *pp++=0;
  303.     tprint("%s \\times 10^{%s} ",p,pp);
  304. }
  305.  
  306.         /* Print a variable name */
  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. int fsort(const void *p1, const void *p2)
  332. {
  333.     struct afactor *t1, *t2;
  334.     int i1,i2;
  335.    
  336.     t1=*(struct afactor **) p1; t2=*(struct afactor **) p2;
  337.     i1=t1->type; i2=t2->type;
  338.     if(i1>type_var) i1=type_var; if(i2>type_var) i2=type_var;
  339.     return i1-i2;
  340.    
  341. }
  342.  
  343. void t_oneterm(char *p, int num)
  344. {
  345.     int sign, fcnt, s, i, dentype, rel;
  346.     char *pp, *pe, *pt;
  347.     struct afactor factors[MAX_FACTORS];
  348.     struct afactor *numerator[MAX_FACTORS],
  349.       *denominator[MAX_FACTORS],
  350.       *neutral[MAX_FACTORS];
  351.     int numcnt,dencnt,neucnt;
  352.  
  353.     rel=0; switch(*p) {
  354.         case '<': {
  355.             rel++; p++; if(*p!='=') {tprint(" < "); break;}
  356.             do p++; while(*p=='=');
  357.             if(*p!='>') {tprint("\\le ");break;}
  358.             else {tprint("\\iff ");p++; break;}
  359.         }
  360.         case '>': {
  361.             rel++; p++; if(*p!='=') {tprint(" > "); rel=1; break;}
  362.             while(*p=='=') p++; tprint("\\ge ");
  363.             break;
  364.         }
  365.         case '-': {
  366.             for(pp=p;*pp=='-';pp++);
  367.             if(*pp!='>') break;
  368.             rel++; tprint("\\to "); p=++pp;
  369.             break;
  370.         }
  371.         case '=': {
  372.             rel++; for(pp=p;*pp=='=';pp++);
  373.             if(*pp!='>') break;
  374.             tprint("\\Rightarrow "); p=++pp;
  375.             break;
  376.         }
  377.     }
  378.     if(*p==',' || *p==';' || *p=='=') {tprint("%c",*p); p++; num=0;}
  379.     sign=1; while(*p=='+' || *p=='-') {
  380.         if(*p=='-') sign*=-1;
  381.         p++;
  382.     }
  383.     for(fcnt=0, pp=p; fcnt<MAX_FACTORS && *pp; fcnt++, pp=pe) {
  384.         s=1;
  385.         while(*pp=='*' || *pp=='/') {
  386.             if(*pp=='/') s=-1;
  387.             pp++;
  388.         }
  389.         factors[fcnt].side=s;
  390.         while(*pp=='+' || *pp=='-') {
  391.             if(*pp=='-') sign*=-1;
  392.             pp++;
  393.         }
  394.         pe=find_factor_end(pp); if(pe<=pp) break;
  395.         factors[fcnt].beg=pp; factors[fcnt].end=pe;
  396.         if(pe-pp==1 && *pp=='1') fcnt--;
  397.         if(*pp=='(') {
  398.             char *pt, *pe2, buf[MAX_LINELEN+1];
  399.             int ss;
  400.             pp++; pt=find_matching(pp,')');
  401.             if(pt>=pe-1) {
  402.                 memmove(buf,pp,pt-pp); buf[pt-pp]=0;
  403.                 i=term_cnt(buf);
  404.                 if(i==1) {      /* remove parentheses */
  405.                     for(;pp<pt && fcnt<MAX_FACTORS;pp=pe2,fcnt++) {
  406.                         ss=s; while(*pp=='*' || *pp=='/') {
  407.                             if(*pp=='/') ss=-1;
  408.                             pp++;
  409.                         }
  410.                         factors[fcnt].side=ss;
  411.                         while(*pp=='+' || *pp=='-') {
  412.                             if(*pp=='-') sign*=-1;
  413.                             pp++;
  414.                         }
  415.                         pe2=find_factor_end(pp);
  416.                         if(pe2<=pp) goto bailout;
  417.                         factors[fcnt].beg=pp; factors[fcnt].end=pe2;
  418.                         if(pe2-pp==1 && *pp=='1') fcnt--;
  419.                     }
  420.                     fcnt--;
  421.                 }
  422.             }
  423.         }
  424.     }
  425.     bailout:
  426.     for(i=0;i<fcnt;i++) {
  427.         pp=factors[i].beg; pe=factors[i].end;
  428.         if(myisdigit(*pp) || *pp=='.') {
  429.             for(pt=pp;pt<pe && myisdigit(*pt);pt++);
  430.             if(pt<pe) factors[i].type=type_numeric;
  431.             else factors[i].type=type_integer;
  432.             continue;        
  433.         }
  434.         if(*pp=='(') {
  435.             factors[i].type=type_poly; continue;
  436.         }
  437.         pt=strchr(pp,'(');
  438.         if(pt!=NULL && pt<pe) factors[i].type=type_transcend;
  439.         else factors[i].type=type_var;
  440.     }
  441.     dentype=-1;
  442.     for(i=0;i<fcnt;i++) if(factors[i].side<0 && factors[i].type>dentype)
  443.       dentype=factors[i].type;
  444.     dencnt=numcnt=neucnt=0;
  445.     for(i=0;i<fcnt;i++) {
  446.         if(factors[i].type>dentype) neutral[neucnt++]=factors+i;
  447.         else {
  448.             if(factors[i].side>0) numerator[numcnt++]=factors+i;
  449.             else denominator[dencnt++]=factors+i;
  450.         }
  451.     }
  452.     if(dencnt>0) qsort(denominator,dencnt,sizeof(denominator[0]),fsort);
  453.     if(numcnt>0) qsort(numerator,numcnt,sizeof(numerator[0]),fsort);
  454.     if(neucnt>0) qsort(neutral,neucnt,sizeof(neutral[0]),fsort);
  455.     if(sign>0 && num>0 && rel==0) tprint(" +");
  456.     if(sign<0) tprint(" -");
  457.     if(fcnt<1) tprint("1 ");
  458.     if(dencnt>0) {
  459.         tprint(" {");
  460.         if(numcnt==0) tprint(" 1");
  461.         else {          /* numerator */
  462.             if(numcnt==1 && *numerator[0]->beg=='(' &&
  463.                find_matching(numerator[0]->beg+1,')')==(numerator[0]->end)-1) {
  464.                 *(numerator[0]->end-1)=0;
  465.                 t_onestring(numerator[0]->beg+1);
  466.                 *(numerator[0]->end-1)=')';
  467.             }
  468.             else for(i=0; i<numcnt; i++) t_onefactor(numerator[i],i);
  469.         }
  470.         tprint(" \\over ");     /* Now denominator */
  471.         if(dencnt==1 && *denominator[0]->beg=='(' &&
  472.            find_matching(denominator[0]->beg+1,')')==(denominator[0]->end)-1) {
  473.             *(denominator[0]->end-1)=0;
  474.             t_onestring(denominator[0]->beg+1);
  475.             *(denominator[0]->end-1)=')';
  476.         }
  477.         else for(i=0;i<dencnt;i++) t_onefactor(denominator[i],i);
  478.         tprint("} ");
  479.     }
  480.     for(i=0;i<neucnt;i++) t_onefactor(neutral[i],i+dencnt);
  481. }
  482.  
  483.         /* put exponential */
  484. void t_exponential(char *pp)
  485. {
  486.     char *pe, *pt;
  487.     int t=0;
  488.    
  489.     while(*pp && strchr("!'\"",*pp)!=NULL) {
  490.         tprint("%c",*pp); pp++;
  491.     }
  492.     if(*pp=='^') pp++; else return;
  493.     if(*pp=='(') {
  494.         pe=find_matching(pp+1,')');
  495.         if(*(pe+1)==0) {
  496.             pp++;*pe=0;
  497.             for(pt=pp;*pt && (isalnum(*pt) || *pt=='.');pt++);
  498.             if(*pt==0) t=1;
  499.         }
  500.     }
  501.     if(strlen(pp)==1 && t==0) tprint("^%s ",pp);
  502.     else {
  503.         tprint(" ^{"); if(t) tprint("(");
  504.         t_onestring(pp);
  505.         if(t) tprint(")"); tprint("} ");
  506.     }
  507. }
  508.  
  509. void t_onefactor(struct afactor *fb, int num)
  510. {
  511.     char *p, *pe, lp, *rp, rp2, rpbuf[128];
  512.     char fbuf[MAX_LINELEN+1], pbuf[MAX_LINELEN+1];
  513.     int i;
  514.  
  515.     memmove(pbuf,fb->beg,fb->end-fb->beg);
  516.     pbuf[fb->end-fb->beg]=0;
  517.     if(num>0 && (myisdigit(pbuf[0]) || pbuf[0]=='.'))
  518.       tprint("\\times ");
  519.     rp2=')'; p=pbuf;
  520.     if(strchr("({[",*p)!=NULL) {
  521.         lp=*p; switch(lp) {
  522.             case '(': rp2=')';  break;
  523.             case '[': { /* verify for matrices */
  524.                 char *pt;
  525.                 pe=find_matching(p+1,']');
  526.                 for(pt=p+1;pt<pe;pt++) {
  527.                     switch(*pt) {
  528.                         case '(': pt=find_matching(pt+1,')'); break;
  529.                         case '[': pt=find_matching(pt+1,']'); break;
  530.                         case '{': pt=find_matching(pt+1,'}'); break;
  531.                         case '|': pt=find_matching(pt+1,'|'); break;
  532.                        
  533.                         case ',':
  534.                         case ';': goto out;
  535.                     }
  536.                 }
  537.                 out: if(*pt==';' || *pt==',') { /* is matrix */
  538.                     char mbuf[MAX_LINELEN+1];
  539.                     char *pp, *pt;
  540.                    
  541.                     p++; if(*pe) *pe++=0;
  542.                     tprint(" \\pmatrix{");
  543.                     for(pp=p,i=0;*pp;pp=pt,i++) {
  544.                         pt=find_term_end(pp);
  545.                         memmove(mbuf,pp,pt-pp); mbuf[pt-pp]=0;
  546.                         t_oneterm(mbuf,i);
  547.                         if(*pt==',') {
  548.                             tprint(" &"); pt++; i=-1;
  549.                         }
  550.                         if(*pt==';') {
  551.                             tprint("\\cr "); pt++; i=-1;
  552.                         }
  553.                     }
  554.                     tprint(" }"); goto expon;
  555.                 }              
  556.                 rp2=']'; break;
  557.             }
  558.             case '{': { /* protected */
  559.                 pe=find_matching(p+1,'}');
  560.                 *pe=0;tprint(" %s} ",p);
  561.                 goto expon;
  562.             }
  563.         }
  564.         tprint(" \\left%c",lp);
  565.         snprintf(rpbuf,sizeof(rpbuf),"\\right%c ",rp2); rp=rpbuf;
  566.         paren: p++;pe=find_matching(p,rp2); *pe=0;
  567.         t_onestring(p); tprint(rp); pe++; goto expon;
  568.     }
  569.     pe=find_mathvar_end(p); while(*pe && strchr("'\"!",*pe)!=NULL) pe++;
  570.     memmove(fbuf,p,pe-p); fbuf[pe-p]=0;
  571.     if(myisdigit(*p) || *p=='.') putnumber(fbuf);
  572.     if(isalpha(*p)) {
  573.         pe=find_mathvar_end(p); while(*pe && strchr("'\"!",*pe)!=NULL) pe++;
  574.         if(*pe=='(') {
  575.             p=pe;
  576.             i=search_list(tmathfn, tmathfn_no, sizeof(tmathfn[0]), fbuf);
  577.             if(i>=0) {
  578.                 switch(tmathfn[i].expind) {
  579.                     case 0: {
  580.                         tprint(" %s",tmathfn[i].left);
  581.                         rp=tmathfn[i].right; break;
  582.                     }
  583.                     case 1: {
  584.                         tprint(" %s",tmathfn[i].left);
  585.                         pe=find_matching(pe+1,')')+1;
  586.                         if(*pe && strchr("^'\"!",*pe)!=NULL) {
  587.                             t_exponential(pe); *pe=0;
  588.                         }
  589.                         tprint(" \\left("); rp=tmathfn[i].right;
  590.                         break;
  591.                     }
  592.                     case 2: {   /* routine */
  593.                         p++;pe=find_matching(p,rp2); *pe=0;
  594.                         tmathfn[i].routine(p);
  595.                         pe++; goto expon;
  596.                     }
  597.                     default: rp=""; break;
  598.                 }
  599.             }
  600.             else {
  601.                 putvar(fbuf);
  602.                 rp="\\right) "; tprint(" \\left(");
  603.             }
  604.             rp2=')'; goto paren;
  605.         }
  606.         else {
  607.             putvar(fbuf);
  608.             if(*pe=='_') {
  609.                 char *ptt, buff[256];
  610.                 tprint("_"); pe++;
  611.                 if(*pe=='(') {
  612.                     ptt=find_matching(pe+1,')'); if(ptt) ptt++;
  613.                 }
  614.                 else {
  615.                     if(*pe=='{') {
  616.                         ptt=find_matching(pe+1,'}'); if(ptt) ptt++;
  617.                     }
  618.                     else ptt=find_mathvar_end(pe);
  619.                 }
  620.                 if(ptt==NULL || ptt-pe>128) goto expon;
  621.                 memmove(buff,pe,ptt-pe); buff[ptt-pe]=0; pe=ptt;
  622.                 strip_enclosing_par(buff);
  623.                 tprint("{%s}",buff);
  624.             }
  625.         }
  626.     }
  627.         /* exponential */
  628.     expon: if(*pe && strchr("^'\"!",*pe)!=NULL) t_exponential(pe);
  629. }
  630.  
  631. void t_onestring(char *p)
  632. {
  633.     char termbuf[MAX_LINELEN+1];
  634.     char *pp, *pe;
  635.     int i;
  636.  
  637.     for(pp=p,i=0;*pp;pp=pe,i++) {
  638.         pe=find_term_end(pp);
  639.         memmove(termbuf,pp,pe-pp); termbuf[pe-pp]=0;
  640.         t_oneterm(termbuf,i);
  641.     }
  642. }
  643.    
  644.         /* translate raw math expression into TeX source */
  645. void texmath(char *p)
  646. {
  647.     char *pp;
  648.  
  649.     if(strpbrk(p,"{}\\")!=NULL) return;
  650.     for(pp=strstr(p,"!="); pp; pp=strstr(pp+1,"!=")) {
  651.         if(pp>p && !isspace(*(pp-1))) continue;
  652.         string_modify(p,pp,pp+2,"*neq*");
  653.     }
  654.         /* remove spaces */
  655.     for(pp=p; *pp; pp++) {
  656.         if(isspace(*pp)) {ovlstrcpy(pp,pp+1); pp--;}
  657.     }
  658.         /* replace ** by ^ */
  659.     for(pp=strstr(p,"**"); pp!=NULL; pp=strstr(pp,"**")) {
  660.       *pp='^'; ovlstrcpy(pp+1,pp+2);
  661.     }
  662.     if(check_parentheses(p,1)!=0) module_error("unmatched_parentheses");
  663.     texmathbuf[0]=0; t_onestring(p);
  664.     mystrncpy(p,texmathbuf,MAX_LINELEN);
  665. }
  666.  
  667.