Back to index

wims  3.65+svn20090927
texmath.c
Go to the documentation of this file.
00001 /*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
00002  *
00003  *  This program is free software; you can redistribute it and/or modify
00004  *  it under the terms of the GNU General Public License as published by
00005  *  the Free Software Foundation; either version 2 of the License, or
00006  *  (at your option) any later version.
00007  *
00008  *  This program is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  *  GNU General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU General Public License
00014  *  along with this program; if not, write to the Free Software
00015  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00016  */
00017        /* subroutines for texmath */
00018 
00019         /* Careful! increasing this number risks stack overflow. */
00020 #define MAX_FACTORS 256
00021 
00022 enum {
00023     type_integer, type_numeric, type_var,
00024       type_poly, type_transcend
00025 };
00026 
00027 typedef struct afactor{
00028     char *beg, *end;
00029     int type, side;
00030 } afactor;
00031 
00032 char texmathbuf[MAX_LINELEN+1];
00033 char *find_term_end(char *p);
00034 void t_onestring(char *p);
00035 void t_oneterm(char *p, int num);
00036 void t_onefactor(struct afactor *p, int num);
00037 void n_onestring(char *p);
00038 void n_oneterm(char *p, int num);
00039 void n_onefactor(struct afactor *p, int num);
00040 void texmath(char *p);
00041 
00042        /* print to texmathbuf */
00043 void tprint(char *s,...)
00044 {
00045     va_list vp;
00046     char buf[MAX_LINELEN+1];
00047 
00048     va_start(vp,s); vsnprintf(buf,sizeof(buf),s,vp); va_end(vp);
00049     if(strlen(buf)+strlen(texmathbuf)>=MAX_LINELEN) 
00050       user_error("cmd_output_too_long");
00051     strcat(texmathbuf,buf);
00052 }
00053 
00054 void _tex_sums(char *p, char *name, int type)
00055 {
00056     char *p1,*p2,*p3;
00057     p1=find_item_end(p); if(*p1) *(p1++)=0;
00058     p2=find_item_end(p1); p3=strparstr(p1,"=");
00059     if(p3<p2) p2=p3; if(*p2) *(p2++)=0;
00060     p3=find_item_end(p2);
00061     if(*p3) *(p3++)=0;
00062     tprint("\\%s ",name);
00063     if(type) {
00064        if(*p2) {
00065            tprint("_{"); t_onestring(p2); tprint("}");
00066        }
00067     }
00068     else if(*p1) {
00069        tprint("_{%s",p1);
00070        if(*p2) { tprint("="); t_onestring(p2);   }
00071        tprint("}");
00072     }
00073     if(*p3) {
00074        tprint("^{"); t_onestring(p3); tprint("}");
00075     }
00076     strip_trailing_spaces(p); if(find_term_end(p)<p+strlen(p)) {
00077        tprint("\\left("); t_onestring(p); tprint("\\right)");
00078     }
00079     else t_onestring(p);
00080     if(type && *p1) {
00081        strip_trailing_spaces(p1); tprint("d");
00082        if(find_term_end(p1)<p1+strlen(p1)) {
00083            tprint("\\left("); t_onestring(p1); tprint("\\right)");
00084        }
00085        else t_onestring(p1);
00086     }
00087 }
00088 
00089        /* integration, sum and product */
00090 void tex_int(char *p) {  _tex_sums(p,"int",1); }
00091 void tex_sum(char *p) {  _tex_sums(p,"sum",0); }
00092 void tex_prod(char *p) { _tex_sums(p,"prod",0);}
00093 
00094 struct {
00095     char *name;
00096     int expind;
00097     char *left, *right;
00098     void (*routine) (char *p);
00099 } tmathfn[]={
00100        {"Arg",              1,     "{\\rm Arg}",        "\\right)"},
00101         {"Int",             2,     "","",               tex_int},
00102         {"Prod",     2,     "","",               tex_prod},
00103         {"Sum",             2,     "","",               tex_sum},
00104         {"abs",             0,     "\\left|",           "\\right|"},
00105        {"acos",      1,     "{\\rm arccos}",     "\\right)"},
00106        {"acosh",     1,     "{\\rm Argch}",             "\\right)"},
00107        {"arg",              1,     "{\\rm Arg}",        "\\right)"},
00108        {"asin",      1,     "{\\rm arcsin}",     "\\right)"},
00109        {"asinh",     1,     "{\\rm Argsh}",             "\\right)"},
00110        {"atan",      1,     "{\\rm arctg}",             "\\right)"},
00111        {"atanh",     1,     "{\\rm Argth}",             "\\right)"},
00112        {"ch",        1,     "{\\rm ch}",         "\\right)"},
00113         {"conj",     0,     "\\overline{",              "}"},
00114         {"conjugate",       0,     "\\overline{",              "}"},
00115        {"cos",              1,     "\\cos",             "\\right)"},
00116        {"cosh",      1,     "{\\rm ch}",         "\\right)"},
00117        {"cot",              1,     "{\\rm ctg}",        "\\right)"},
00118        {"cotan",     1,     "{\\rm ctg}",        "\\right)"},
00119        {"cotanh",    1,     "{\\rm cth}",        "\\right)"},
00120        {"csc",              1,     "{\\rm csc}",        "\\right)"},
00121        {"ctg",              1,     "{\\rm ctg}",        "\\right)"},
00122        {"cth",              1,     "{\\rm cth}",        "\\right)"},
00123        {"det",              1,     "{\\rm det}",        "\\right)"},
00124        {"erf",              1,     "{\\rm erf}",        "\\right)"},
00125        {"exp",              1,     "\\exp",             "\\right)"},
00126         {"int",             2,     "","",               tex_int},
00127         {"integrate",       2,     "","",               tex_int},
00128        {"lg",        1,     "{\\rm lg}",         "\\right)"},
00129        {"ln",        1,     "\\ln",                     "\\right)"},
00130        {"log",              1,     "\\log",             "\\right)"},
00131         {"prod",     2,     "","",               tex_prod},
00132         {"product",  2,     "","",               tex_prod},
00133        {"sec",              1,     "{\\rm sec}",        "\\right)"},
00134        {"sgn",              1,     "{\\rm sgn}",        "\\right)"},
00135        {"sh",        1,     "{\\rm sh}",         "\\right)"},
00136        {"sign",      1,     "{\\rm sign}",              "\\right)"},
00137        {"sin",              1,     "\\sin",             "\\right)"},
00138        {"sinh",      1,     "{\\rm sh}",         "\\right)"},
00139        {"sqrt",      0,     "\\sqrt{",           "}"},
00140         {"sum",             2,     "","",               tex_sum},
00141        {"tan",              1,     "\\tan",             "\\right)"},
00142        {"tanh",      1,     "{\\rm th}",         "\\right)"},
00143        {"tg",        1,     "{\\rm tg}",         "\\right)"},
00144        {"th",        1,     "{\\rm th}",         "\\right)"}
00145 };
00146 
00147 #define tmathfn_no (sizeof(tmathfn)/sizeof(tmathfn[0]))
00148 
00149 struct {
00150     char *name, *tex;
00151 } tmathvar[]={
00152         {"CC",              "\\mathbb{C}"},
00153        {"Delta",     "\\Delta"},
00154        {"Gamma",     "\\Gamma"},
00155         {"Inf",             "\\infty"},
00156         {"Lambda",   "\\Lambda"},
00157         {"NN",              "\\mathbb{N}"},
00158         {"Omega",    "\\Omega"},
00159        {"PI",        "\\pi"},
00160        {"Phi",              "\\Phi"},
00161        {"Pi",        "\\Pi"},
00162        {"Psi",              "\\Psi"},
00163         {"QQ",              "\\mathbb{Q}"},
00164         {"RR",              "\\mathbb{R}"},
00165        {"Sigma",     "\\Sigma"},
00166        {"Theta",     "\\Theta"},
00167         {"Upsilon",  "\\Upsilon"},
00168         {"Xi",              "\\Xi"},
00169         {"ZZ",              "\\mathbb{Z}"},
00170         {"aleph",    "\\aleph"},
00171        {"alpha",     "\\alpha"},
00172         {"beta",     "\\beta"},
00173         {"chi",             "\\chi"},
00174         {"delta",    "\\delta"},
00175         {"epsilon",  "\\epsilon"},
00176         {"eta",             "\\eta"},
00177         {"gamma",    "\\gamma"},
00178         {"inf",             "\\infty"},
00179         {"infinity", "\\infty"},
00180         {"infty",    "\\infty"},
00181         {"iota",     "\\iota"},
00182         {"kappa",    "\\kappa"},
00183         {"lambda",   "\\lambda"},
00184         {"mu",              "\\mu"},
00185         {"neq",             "\\neq"},
00186         {"nu",              "\\nu"},
00187         {"omega",    "\\omega"},
00188        {"phi",              "\\phi"},
00189        {"pi",        "\\pi"},
00190        {"psi",              "\\psi"},
00191         {"rho",             "\\rho"},
00192         {"sigma",    "\\sigma"},
00193         {"tau",             "\\tau"},
00194        {"theta",     "\\theta"},
00195         {"xi",              "\\xi"},
00196         {"zeta",     "\\zeta"}
00197 };
00198 
00199 #define tmathvar_no (sizeof(tmathvar)/sizeof(tmathvar[0]))
00200 
00201 
00202        /* find the end of an additive term. */
00203 char *find_term_end(char *p)
00204 {
00205     char *pp;
00206     pp=p; 
00207     if(*pp==',' || *pp==';' || *pp=='=' || *pp=='<') pp++;
00208     while(*pp=='+' || *pp=='-' || *pp=='=' || *pp=='>') pp++;
00209     for(;*pp;pp++) {
00210        switch(*pp) {
00211            case '(': pp=find_matching(pp+1,')'); goto loopend;
00212            case '[': pp=find_matching(pp+1,']'); goto loopend;
00213 /*         case '{': pp=find_matching(pp+1,'}'); goto loopend; */
00214            
00215            case 0:
00216            case '<':
00217            case '>':
00218            case ',':
00219            case ';':
00220            case '=':
00221            case ')':
00222            case ']':
00223            case '}':
00224            case '-':
00225            case '+': return pp;
00226            
00227            case '*':
00228            case '/':
00229            case '^': {
00230               while(*(pp+1)=='+' || *(pp+1)=='-') pp++;
00231               goto loopend;
00232            }
00233        }
00234        if(isalnum(*pp) || *pp=='.') {
00235            pp=find_mathvar_end(pp); pp--; continue;
00236        }
00237        continue;
00238        loopend:
00239        if(pp==NULL) module_error("unmatched_parentheses");
00240     }
00241     return pp;
00242 }
00243 
00244        /* find the end of an multiplicative factor. */
00245 char *find_factor_end(char *p)
00246 {
00247     char *pp;
00248     pp=p; if(*pp==',' || *pp==';' || *pp=='=') pp++;
00249     while(*pp=='+' || *pp=='-' || *pp=='*' || *pp=='/') pp++;
00250     for(;*pp;pp++) {
00251        switch(*pp) {
00252            case '(': pp=find_matching(pp+1,')'); goto loopend;
00253            case '[': pp=find_matching(pp+1,']'); goto loopend;
00254 /*         case '{': pp=find_matching(pp+1,'}'); goto loopend; */
00255            
00256            case 0:
00257            case '<':
00258            case '>':
00259            case ',':
00260            case ';':
00261            case '=':
00262            case ')':
00263            case ']':
00264            case '}':
00265            case '+':
00266            case '-':
00267            case '*':
00268            case '/': return pp;
00269            
00270            case '^': {
00271               while(*(pp+1)=='+' || *(pp+1)=='-') pp++;
00272               goto loopend;
00273            }
00274        }
00275        if(isalnum(*pp) || *pp=='.') {
00276            pp=find_mathvar_end(pp); pp--; continue;
00277        }
00278        continue;
00279        loopend:
00280        if(pp==NULL) module_error("unmatched_parentheses");
00281     }
00282     return pp;
00283 }
00284 
00285        /* returns the number of terms */
00286 int term_cnt(char *p)
00287 {
00288     char *pe, *pp;
00289     int i;
00290     
00291     pe=p+strlen(p);
00292     for(i=0,pp=p;pp<pe;pp=find_term_end(pp),i++);
00293     return i;
00294 }
00295 
00296        /* Print a number */
00297 void putnumber(char *p)
00298 {
00299     char *pp;
00300     pp=strpbrk(p,"Ee");
00301     if(pp==NULL) {tprint("%s",p); return;}
00302     *pp++=0;
00303     tprint("%s \\times 10^{%s} ",p,pp);
00304 }
00305 
00306        /* Print a variable name */
00307 void putvar(char *p)
00308 {
00309     char vbuf[1024];
00310     char *pp, *p2;
00311     int i;
00312     
00313     vbuf[0]=0;
00314     if(*(p+1)==0) {tprint("%c",*p); return;}
00315     for(pp=p;isalpha(*pp);pp++);
00316     if(myisdigit(*pp)) {
00317        for(p2=pp+1;myisdigit(*p2);p2++);
00318        if(*p2==0) {  /* subscript */
00319            mystrncpy(vbuf,pp,sizeof(vbuf));*pp=0;
00320        }
00321     }
00322     i=search_list(tmathvar, tmathvar_no, sizeof(tmathvar[0]), p);
00323     if(i>=0) tprint("%s ",tmathvar[i].tex);
00324     else tprint("%s ",p);
00325     if(vbuf[0]) {
00326        if(vbuf[1]==0) tprint("_%c ",vbuf[0]);
00327        else tprint("_{%s} ",vbuf);
00328     }
00329 }
00330 
00331 int fsort(const void *p1, const void *p2)
00332 {
00333     struct afactor *t1, *t2;
00334     int i1,i2;
00335     
00336     t1=*(struct afactor **) p1; t2=*(struct afactor **) p2;
00337     i1=t1->type; i2=t2->type;
00338     if(i1>type_var) i1=type_var; if(i2>type_var) i2=type_var;
00339     return i1-i2;
00340     
00341 }
00342 
00343 void t_oneterm(char *p, int num)
00344 {
00345     int sign, fcnt, s, i, dentype, rel;
00346     char *pp, *pe, *pt;
00347     struct afactor factors[MAX_FACTORS];
00348     struct afactor *numerator[MAX_FACTORS], 
00349       *denominator[MAX_FACTORS], 
00350       *neutral[MAX_FACTORS];
00351     int numcnt,dencnt,neucnt;
00352 
00353     rel=0; switch(*p) {
00354        case '<': {
00355            rel++; p++; if(*p!='=') {tprint(" < "); break;}
00356            do p++; while(*p=='=');
00357            if(*p!='>') {tprint("\\le ");break;}
00358            else {tprint("\\iff ");p++; break;}
00359        }
00360        case '>': {
00361            rel++; p++; if(*p!='=') {tprint(" > "); rel=1; break;}
00362            while(*p=='=') p++; tprint("\\ge ");
00363            break;
00364        }
00365        case '-': {
00366            for(pp=p;*pp=='-';pp++);
00367            if(*pp!='>') break;
00368            rel++; tprint("\\to "); p=++pp;
00369            break;
00370        }
00371        case '=': {
00372            rel++; for(pp=p;*pp=='=';pp++);
00373            if(*pp!='>') break;
00374            tprint("\\Rightarrow "); p=++pp;
00375            break;
00376        }
00377     }
00378     if(*p==',' || *p==';' || *p=='=') {tprint("%c",*p); p++; num=0;}
00379     sign=1; while(*p=='+' || *p=='-') {
00380        if(*p=='-') sign*=-1;
00381        p++;
00382     }
00383     for(fcnt=0, pp=p; fcnt<MAX_FACTORS && *pp; fcnt++, pp=pe) {
00384        s=1;
00385        while(*pp=='*' || *pp=='/') {
00386            if(*pp=='/') s=-1; 
00387            pp++;
00388        }
00389        factors[fcnt].side=s;
00390        while(*pp=='+' || *pp=='-') {
00391            if(*pp=='-') sign*=-1;
00392            pp++;
00393        }
00394        pe=find_factor_end(pp);     if(pe<=pp) break;
00395        factors[fcnt].beg=pp; factors[fcnt].end=pe;
00396        if(pe-pp==1 && *pp=='1') fcnt--;
00397        if(*pp=='(') {
00398            char *pt, *pe2, buf[MAX_LINELEN+1];
00399            int ss;
00400            pp++; pt=find_matching(pp,')');
00401            if(pt>=pe-1) {
00402               memmove(buf,pp,pt-pp); buf[pt-pp]=0;
00403               i=term_cnt(buf);
00404               if(i==1) {    /* remove parentheses */
00405                   for(;pp<pt && fcnt<MAX_FACTORS;pp=pe2,fcnt++) {
00406                      ss=s; while(*pp=='*' || *pp=='/') {
00407                          if(*pp=='/') ss=-1; 
00408                          pp++;
00409                      }
00410                      factors[fcnt].side=ss;
00411                      while(*pp=='+' || *pp=='-') {
00412                          if(*pp=='-') sign*=-1;
00413                          pp++;
00414                      }
00415                      pe2=find_factor_end(pp);
00416                      if(pe2<=pp) goto bailout;
00417                      factors[fcnt].beg=pp; factors[fcnt].end=pe2;
00418                      if(pe2-pp==1 && *pp=='1') fcnt--;
00419                   }
00420                   fcnt--;
00421               }
00422            }
00423        }
00424     }
00425     bailout:
00426     for(i=0;i<fcnt;i++) {
00427        pp=factors[i].beg; pe=factors[i].end;
00428        if(myisdigit(*pp) || *pp=='.') {
00429            for(pt=pp;pt<pe && myisdigit(*pt);pt++);
00430            if(pt<pe) factors[i].type=type_numeric;
00431            else factors[i].type=type_integer;
00432            continue;       
00433        }
00434        if(*pp=='(') {
00435            factors[i].type=type_poly; continue;
00436        }
00437        pt=strchr(pp,'('); 
00438        if(pt!=NULL && pt<pe) factors[i].type=type_transcend;
00439        else factors[i].type=type_var;
00440     }
00441     dentype=-1;
00442     for(i=0;i<fcnt;i++) if(factors[i].side<0 && factors[i].type>dentype)
00443       dentype=factors[i].type;
00444     dencnt=numcnt=neucnt=0;
00445     for(i=0;i<fcnt;i++) {
00446        if(factors[i].type>dentype) neutral[neucnt++]=factors+i;
00447        else {
00448            if(factors[i].side>0) numerator[numcnt++]=factors+i;
00449            else denominator[dencnt++]=factors+i;
00450        }
00451     }
00452     if(dencnt>0) qsort(denominator,dencnt,sizeof(denominator[0]),fsort);
00453     if(numcnt>0) qsort(numerator,numcnt,sizeof(numerator[0]),fsort);
00454     if(neucnt>0) qsort(neutral,neucnt,sizeof(neutral[0]),fsort);
00455     if(sign>0 && num>0 && rel==0) tprint(" +");
00456     if(sign<0) tprint(" -");
00457     if(fcnt<1) tprint("1 ");
00458     if(dencnt>0) {
00459        tprint(" {");
00460        if(numcnt==0) tprint(" 1"); 
00461        else {        /* numerator */
00462            if(numcnt==1 && *numerator[0]->beg=='(' && 
00463               find_matching(numerator[0]->beg+1,')')==(numerator[0]->end)-1) {
00464               *(numerator[0]->end-1)=0;
00465               t_onestring(numerator[0]->beg+1);
00466               *(numerator[0]->end-1)=')';
00467            }
00468            else for(i=0; i<numcnt; i++) t_onefactor(numerator[i],i);
00469        }
00470        tprint(" \\over ");  /* Now denominator */
00471        if(dencnt==1 && *denominator[0]->beg=='(' && 
00472           find_matching(denominator[0]->beg+1,')')==(denominator[0]->end)-1) {
00473            *(denominator[0]->end-1)=0;
00474            t_onestring(denominator[0]->beg+1);
00475            *(denominator[0]->end-1)=')';
00476        }
00477        else for(i=0;i<dencnt;i++) t_onefactor(denominator[i],i);
00478        tprint("} ");
00479     }
00480     for(i=0;i<neucnt;i++) t_onefactor(neutral[i],i+dencnt);
00481 }
00482 
00483        /* put exponential */
00484 void t_exponential(char *pp)
00485 {
00486     char *pe, *pt;
00487     int t=0;
00488     
00489     while(*pp && strchr("!'\"",*pp)!=NULL) {
00490        tprint("%c",*pp); pp++;
00491     }
00492     if(*pp=='^') pp++; else return;
00493     if(*pp=='(') {
00494        pe=find_matching(pp+1,')');
00495        if(*(pe+1)==0) {
00496            pp++;*pe=0;
00497            for(pt=pp;*pt && (isalnum(*pt) || *pt=='.');pt++);
00498            if(*pt==0) t=1;
00499        }
00500     }
00501     if(strlen(pp)==1 && t==0) tprint("^%s ",pp);
00502     else {
00503        tprint(" ^{"); if(t) tprint("(");
00504        t_onestring(pp);
00505        if(t) tprint(")"); tprint("} ");
00506     }
00507 }
00508 
00509 void t_onefactor(struct afactor *fb, int num)
00510 {
00511     char *p, *pe, lp, *rp, rp2, rpbuf[128];
00512     char fbuf[MAX_LINELEN+1], pbuf[MAX_LINELEN+1];
00513     int i;
00514 
00515     memmove(pbuf,fb->beg,fb->end-fb->beg);
00516     pbuf[fb->end-fb->beg]=0;
00517     if(num>0 && (myisdigit(pbuf[0]) || pbuf[0]=='.'))
00518       tprint("\\times ");
00519     rp2=')'; p=pbuf;
00520     if(strchr("({[",*p)!=NULL) {
00521        lp=*p; switch(lp) {
00522            case '(': rp2=')';  break;
00523            case '[': {      /* verify for matrices */
00524               char *pt;
00525               pe=find_matching(p+1,']');
00526               for(pt=p+1;pt<pe;pt++) {
00527                   switch(*pt) {
00528                      case '(': pt=find_matching(pt+1,')'); break;
00529                      case '[': pt=find_matching(pt+1,']'); break;
00530                      case '{': pt=find_matching(pt+1,'}'); break;
00531                      case '|': pt=find_matching(pt+1,'|'); break;
00532                      
00533                      case ',':
00534                      case ';': goto out;
00535                   }
00536               }
00537               out: if(*pt==';' || *pt==',') {    /* is matrix */
00538                   char mbuf[MAX_LINELEN+1];
00539                   char *pp, *pt;
00540                   
00541                   p++; if(*pe) *pe++=0;
00542                   tprint(" \\pmatrix{");
00543                   for(pp=p,i=0;*pp;pp=pt,i++) {
00544                      pt=find_term_end(pp);
00545                      memmove(mbuf,pp,pt-pp); mbuf[pt-pp]=0;
00546                      t_oneterm(mbuf,i);
00547                      if(*pt==',') {
00548                          tprint(" &"); pt++; i=-1;
00549                      }
00550                      if(*pt==';') {
00551                          tprint("\\cr "); pt++; i=-1;
00552                      }
00553                   }
00554                   tprint(" }"); goto expon;
00555               }             
00556               rp2=']'; break;
00557            }
00558            case '{': {      /* protected */
00559               pe=find_matching(p+1,'}');
00560               *pe=0;tprint(" %s} ",p);
00561               goto expon;
00562            }
00563        }
00564        tprint(" \\left%c",lp); 
00565        snprintf(rpbuf,sizeof(rpbuf),"\\right%c ",rp2); rp=rpbuf;
00566        paren: p++;pe=find_matching(p,rp2); *pe=0;
00567        t_onestring(p); tprint(rp); pe++; goto expon;
00568     }
00569     pe=find_mathvar_end(p); while(*pe && strchr("'\"!",*pe)!=NULL) pe++;
00570     memmove(fbuf,p,pe-p); fbuf[pe-p]=0;
00571     if(myisdigit(*p) || *p=='.') putnumber(fbuf);
00572     if(isalpha(*p)) {
00573        pe=find_mathvar_end(p); while(*pe && strchr("'\"!",*pe)!=NULL) pe++;
00574        if(*pe=='(') {
00575            p=pe;
00576            i=search_list(tmathfn, tmathfn_no, sizeof(tmathfn[0]), fbuf);
00577            if(i>=0) {
00578               switch(tmathfn[i].expind) {
00579                   case 0: {
00580                      tprint(" %s",tmathfn[i].left);
00581                      rp=tmathfn[i].right; break;
00582                   }
00583                   case 1: {
00584                      tprint(" %s",tmathfn[i].left);
00585                      pe=find_matching(pe+1,')')+1;
00586                      if(*pe && strchr("^'\"!",*pe)!=NULL) {
00587                          t_exponential(pe); *pe=0;
00588                      }
00589                      tprint(" \\left("); rp=tmathfn[i].right;
00590                      break;
00591                   }
00592                   case 2: { /* routine */
00593                      p++;pe=find_matching(p,rp2); *pe=0;
00594                      tmathfn[i].routine(p);
00595                      pe++; goto expon;
00596                   }
00597                   default: rp=""; break;
00598               }
00599            }
00600            else {
00601               putvar(fbuf);
00602               rp="\\right) "; tprint(" \\left(");
00603            }
00604            rp2=')'; goto paren;
00605        }
00606        else {
00607            putvar(fbuf);
00608            if(*pe=='_') {
00609               char *ptt, buff[256];
00610               tprint("_"); pe++;
00611               if(*pe=='(') {
00612                   ptt=find_matching(pe+1,')'); if(ptt) ptt++;
00613               }
00614               else {
00615                   if(*pe=='{') {
00616                      ptt=find_matching(pe+1,'}'); if(ptt) ptt++;
00617                   }
00618                   else ptt=find_mathvar_end(pe);
00619               }
00620               if(ptt==NULL || ptt-pe>128) goto expon;
00621               memmove(buff,pe,ptt-pe); buff[ptt-pe]=0; pe=ptt;
00622               strip_enclosing_par(buff);
00623               tprint("{%s}",buff);
00624            }
00625        }
00626     }
00627        /* exponential */
00628     expon: if(*pe && strchr("^'\"!",*pe)!=NULL) t_exponential(pe);
00629 }
00630 
00631 void t_onestring(char *p)
00632 {
00633     char termbuf[MAX_LINELEN+1];
00634     char *pp, *pe;
00635     int i;
00636 
00637     for(pp=p,i=0;*pp;pp=pe,i++) {
00638        pe=find_term_end(pp);
00639        memmove(termbuf,pp,pe-pp); termbuf[pe-pp]=0;
00640        t_oneterm(termbuf,i);
00641     }
00642 }
00643     
00644        /* translate raw math expression into TeX source */
00645 void texmath(char *p)
00646 {
00647     char *pp;
00648 
00649     if(strpbrk(p,"{}\\")!=NULL) return;
00650     for(pp=strstr(p,"!="); pp; pp=strstr(pp+1,"!=")) {
00651        if(pp>p && !isspace(*(pp-1))) continue;
00652        string_modify(p,pp,pp+2,"*neq*");
00653     }
00654        /* remove spaces */
00655     for(pp=p; *pp; pp++) {
00656        if(isspace(*pp)) {strcpy(pp,pp+1); pp--;}
00657     }
00658        /* replace ** by ^ */
00659     for(pp=strstr(p,"**"); pp!=NULL; pp=strstr(pp,"**")) {
00660       *pp='^'; strcpy(pp+1,pp+2);
00661     }
00662     if(check_parentheses(p,1)!=0) module_error("unmatched_parentheses");
00663     texmathbuf[0]=0; t_onestring(p);
00664     mystrncpy(p,texmathbuf,MAX_LINELEN);
00665 }
00666