/*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
 
 *
 
 *  This program is free software; you can redistribute it and/or modify
 
 *  it under the terms of the GNU General Public License as published by
 
 *  the Free Software Foundation; either version 2 of the License, or
 
 *  (at your option) any later version.
 
 *
 
 *  This program is distributed in the hope that it will be useful,
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 *  GNU General Public License for more details.
 
 *
 
 *  You should have received a copy of the GNU General Public License
 
 *  along with this program; if not, write to the Free Software
 
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 */
 
/* subroutines for texmath */
 
#include "wims.h"
 
 
 
/* Careful! increasing this number risks stack overflow. */
 
#define MAX_FACTORS 256
 
 
 
enum {
 
    type_integer, type_numeric, type_var,
 
      type_poly, type_transcend
 
};
 
 
 
typedef struct afactor{
 
    char *beg, *end;
 
    int type, side;
 
} afactor;
 
 
 
char texmathbuf[MAX_LINELEN+1];
 
char *find_term_end(char *p);
 
void t_onestring(char *p);
 
void t_oneterm(char *p, int num);
 
void t_onefactor(struct afactor *p, int num);
 
/* never used or defined ?? */
 
void n_onestring(char *p);
 
void n_oneterm(char *p, int num);
 
void n_onefactor(struct afactor *p, int num);
 
/* */
 
void texmath(char *p);
 
 
 
/* print to texmathbuf */
 
void tprint(char *s,...)
 
{
 
    va_list vp;
 
    char buf[MAX_LINELEN+1];
 
 
 
      user_error("cmd_output_too_long");
 
}
 
/* transforms sum(n,n=1..infinity) , product(n/(n+1),n=1..infinity). */
 
void _tex_sums(char *p, char *name, int type)
 
{
 
    char *p1,*p2,*p3;
 
    p1=find_item_end(p); if(*p1) *(p1++)=0;
 
    p2=find_item_end(p1); p3=strparstr(p1,"=");
 
    if(p3<p2) p2=p3;
 
    if(*p2) *(p2++)=0;
 
    p3=find_item_end(p2);
 
    if(*p3) *(p3++)=0;
 
    tprint("\\%s ",name);
 
    if(type) {
 
      if(*p2) {
 
        tprint("_{"); t_onestring(p2); tprint("}");
 
      }
 
    }
 
    else if(*p1) {
 
      tprint("_{%s",p1);
 
      if(*p2) { tprint("="); t_onestring(p2); }
 
      tprint("}");
 
    }
 
    if(*p3) {
 
      tprint("^{"); t_onestring(p3); tprint("}");
 
    }
 
    strip_trailing_spaces
(p
); if(find_term_end
(p
)<p
+strlen(p
)) { 
      tprint("\\left("); t_onestring(p); tprint("\\right)");
 
    }
 
    else t_onestring(p);
 
    if(type && *p1) {
 
      strip_trailing_spaces(p1); tprint("\\,\\textrm{d}"); // case of the integrale
 
      if(find_term_end
(p1
)<p1
+strlen(p1
)) {  
        tprint("\\left("); t_onestring(p1); tprint("\\right)");
 
      }
 
      else t_onestring(p1);
 
    }
 
}
 
 
 
/* integration, sum and product */
 
void tex_int(char *p) {  _tex_sums(p,"int",1); }
 
void tex_sum(char *p) {  _tex_sums(p,"sum",0); }
 
void tex_prod(char *p) { _tex_sums(p,"prod",0);}
 
 
 
struct tmathfn tmathfn[]={
 
      {"Arg",      1,  "\\rm{Arg}",      "\\right)"},
 
      {"Int",      2,  "","",        tex_int},
 
      {"Prod",     2,  "","",        tex_prod},
 
      {"Sum",      2,  "","",        tex_sum},
 
      {"abs",      0,  "\\left|",      "\\right|"},
 
      {"acos",     1,  "\\rm{arccos}",  "\\right)"},
 
      {"acosh",    1,  "\\rm{Argch}",      "\\right)"},
 
      {"arg",      1,  "\\rm{Arg}",      "\\right)"},
 
      {"asin",     1,  "\\rm{arcsin}",  "\\right)"},
 
      {"asinh",    1,  "\\rm{Argsh}",      "\\right)"},
 
      {"atan",     1,  "\\rm{arctg}",      "\\right)"},
 
      {"atanh",    1,  "\\rm{Argth}",      "\\right)"},
 
      {"ch",       1,  "\\rm{ch}",      "\\right)"},
 
      {"conj",     0,  "\\overline{",      "}"},
 
      {"conjugate",0,  "\\overline{",      "}"},
 
      {"cos",      1,  "\\cos",      "\\right)"},
 
      {"cosh",     1,  "\\rm{ch}",      "\\right)"},
 
      {"cot",      1,  "\\rm{ctg}",      "\\right)"},
 
      {"cotan",    1,  "\\rm{ctg}",      "\\right)"},
 
      {"cotanh",   1,  "\\rm{cth}",      "\\right)"},
 
      {"csc",      1,  "\\rm{csc}",      "\\right)"},
 
      {"ctg",      1,  "\\rm{ctg}",      "\\right)"},
 
      {"cth",      1,  "\\rm{cth}",      "\\right)"},
 
      {"det",      1,  "\\rm{det}",      "\\right)"},
 
      {"erf",      1,  "\\rm{erf}",      "\\right)"},
 
      {"exp",      1,  "\\exp",      "\\right)"},
 
      {"int",      2,  "","",        tex_int},
 
      {"integrate",2,  "","",        tex_int},
 
      {"lg",       1,  "\\rm{lg}",      "\\right)"},
 
      {"ln",       1,  "\\ln",        "\\right)"},
 
      {"log",      1,  "\\log",      "\\right)"},
 
      {"prod",     2,  "","",        tex_prod},
 
      {"product",  2,  "","",        tex_prod},
 
      {"sec",      1,  "\\rm{sec}",      "\\right)"},
 
      {"sgn",      1,  "\\rm{sgn}",      "\\right)"},
 
      {"sh",       1,  "\\rm{sh}",      "\\right)"},
 
      {"sign",     1,  "\\rm{sign}",      "\\right)"},
 
      {"sin",      1,  "\\sin",      "\\right)"},
 
      {"sinh",     1,  "\\rm{sh}",      "\\right)"},
 
      {"sqrt",     0,  "\\sqrt{",      "}"},
 
      {"sum",      2,  "","",        tex_sum},
 
      {"tan",      1,  "\\tan",      "\\right)"},
 
      {"tanh",     1,  "\\rm{th}",      "\\right)"},
 
      {"tg",       1,  "\\rm{tg}",      "\\right)"},
 
      {"th",       1,  "\\rm{th}",      "\\right)"}
 
};
 
 
 
int tmathfn_no=(sizeof(tmathfn)/sizeof(tmathfn[0]));
 
 
 
struct tmathvar tmathvar[]={
 
      {"CC",      "\\mathbb{C}"},
 
      {"Delta",   "\\Delta"},
 
      {"Gamma",   "\\Gamma"},
 
      {"Inf",     "\\infty"},
 
      {"Lambda",  "\\Lambda"},
 
      {"NN",      "\\mathbb{N}"},
 
      {"Omega",   "\\Omega"},
 
      {"PI",      "\\pi"},
 
      {"Phi",     "\\Phi"},
 
      {"Pi",      "\\Pi"},
 
      {"Psi",     "\\Psi"},
 
      {"QQ",      "\\mathbb{Q}"},
 
      {"RR",      "\\mathbb{R}"},
 
      {"Sigma",   "\\Sigma"},
 
      {"Theta",   "\\Theta"},
 
      {"Upsilon", "\\Upsilon"},
 
      {"Xi",      "\\Xi"},
 
      {"ZZ",      "\\mathbb{Z}"},
 
      {"aleph",   "\\aleph"},
 
      {"alpha",   "\\alpha"},
 
      {"beta",   "\\beta"},
 
      {"chi",    "\\chi"},
 
      {"delta",  "\\delta"},
 
      {"epsilon","\\epsilon"},
 
      {"eta",    "\\eta"},
 
      {"gamma",  "\\gamma"},
 
      {"inf",    "\\infty"},
 
      {"infinity","\\infty"},
 
      {"infty",  "\\infty"},
 
      {"iota",   "\\iota"},
 
      {"kappa",  "\\kappa"},
 
      {"lambda", "\\lambda"},
 
      {"mu",     "\\mu"},
 
      {"neq",    "\\neq"},
 
      {"nu",     "\\nu"},
 
      {"omega",  "\\omega"},
 
      {"phi",    "\\phi"},
 
      {"pi",     "\\pi"},
 
      {"psi",    "\\psi"},
 
      {"rho",    "\\rho"},
 
      {"sigma",  "\\sigma"},
 
      {"tau",    "\\tau"},
 
      {"theta",  "\\theta"},
 
      {"xi",     "\\xi"},
 
      {"zeta",   "\\zeta"}
 
};
 
 
 
int tmathvar_no=(sizeof(tmathvar)/sizeof(tmathvar[0]));
 
 
 
 
 
/* find the end of an additive term. */
 
char *find_term_end(char *p)
 
{
 
    char *pp;
 
    pp=p;
 
    if(*pp==',' || *pp==';' || *pp=='=' || *pp=='<') pp++;
 
    while(*pp=='+' || *pp=='-' || *pp=='=' || *pp=='>') pp++;
 
    for(;*pp;pp++) {
 
      switch(*pp) {
 
        case '(': pp=find_matching(pp+1,')'); goto loopend;
 
        case '[': pp=find_matching(pp+1,']'); goto loopend;
 
/*     case '{': pp=find_matching(pp+1,'}'); goto loopend;*/
 
 
 
        case 0:
 
        case '<':
 
        case '>':
 
        case ',':
 
        case ';':
 
        case '=':
 
        case ')':
 
        case ']':
 
        case '}':
 
        case '-':
 
        case '+': return pp;
 
 
 
        case '*':
 
        case '/':
 
        case '^': {
 
          while(*(pp+1)=='+' || *(pp+1)=='-') pp++;
 
          goto loopend;
 
        }
 
      }
 
        pp=find_mathvar_end(pp); pp--; continue;
 
      }
 
      continue;
 
      loopend:
 
      if(pp==NULL) module_error("unmatched_parentheses");
 
    }
 
    return pp;
 
}
 
 
 
/* find the end of an multiplicative factor. */
 
char *find_factor_end(char *p)
 
{
 
    char *pp;
 
    pp=p; if(*pp==',' || *pp==';' || *pp=='=') pp++;
 
    while(*pp=='+' || *pp=='-' || *pp=='*' || *pp=='/') pp++;
 
    for(;*pp;pp++) {
 
      switch(*pp) {
 
        case '(': pp=find_matching(pp+1,')'); goto loopend;
 
        case '[': pp=find_matching(pp+1,']'); goto loopend;
 
/*    case '{': pp=find_matching(pp+1,'}'); goto loopend;*/
 
 
 
        case 0:
 
        case '<':
 
        case '>':
 
        case ',':
 
        case ';':
 
        case '=':
 
        case ')':
 
        case ']':
 
        case '}':
 
        case '+':
 
        case '-':
 
        case '*':
 
        case '/': return pp;
 
 
 
        case '^': {
 
          while(*(pp+1)=='+' || *(pp+1)=='-') pp++;
 
          goto loopend;
 
        }
 
      }
 
        pp=find_mathvar_end(pp); pp--; continue;
 
      }
 
      continue;
 
      loopend:
 
      if(pp==NULL) module_error("unmatched_parentheses");
 
    }
 
    return pp;
 
}
 
 
 
    /* returns the number of terms */
 
int term_cnt(char *p)
 
{
 
    char *pe, *pp;
 
    int i;
 
 
 
    for(i=0,pp=p;pp<pe;pp=find_term_end(pp),i++);
 
    return i;
 
}
 
 
 
/* Print a number: transform 4E+05 in 4 \times 10^{5} and  4E-05 in 4 \times 10^{-5}
 
suppress multiple + or 0 ; see rawmath.c
 
*/
 
void putnumber(char *p)
 
 {
 
     char *sgn 
= "", *pp 
= strpbrk(p
,"Ee");  
     if (pp == NULL) { tprint("%s",p); return; }
 
     *pp++ = 0;
 
     if (*pp == '-') { sgn = "-"; pp++; }
 
     while (*pp == '0' || *pp == '+') pp++;
 
     tprint("%s \\times 10^{%s%s}", p, sgn, pp);
 
 }
 
 
 
/* Print a variable name ; transform abc475 in abc_475 */
 
void putvar(char *p)
 
{
 
    char vbuf[1024];
 
    char *pp, *p2;
 
    int i;
 
 
 
    vbuf[0]=0;
 
    if(*(p+1)==0) {tprint("%c",*p); return;}
 
    if(myisdigit(*pp)) {
 
    for(p2=pp+1;myisdigit(*p2);p2++);
 
    if(*p2==0) {/* subscript */
 
        mystrncpy(vbuf,pp,sizeof(vbuf));*pp=0;
 
    }
 
    }
 
    i=search_list(tmathvar, tmathvar_no, sizeof(tmathvar[0]), p);
 
    if(i>=0) tprint("%s ",tmathvar[i].tex);
 
    else tprint("%s ",p);
 
    if(vbuf[0]) {
 
    if(vbuf[1]==0) tprint("_%c ",vbuf[0]);
 
    else tprint("_{%s} ",vbuf);
 
    }
 
}
 
 
 
/* sort according to type */
 
int fsort(const void *p1, const void *p2)
 
{
 
  struct afactor *t1, *t2;
 
  int i1,i2;
 
 
 
  t1=*(struct afactor **) p1; t2=*(struct afactor **) p2;
 
  i1=t1->type; i2=t2->type;
 
  if(i1>type_var) i1=type_var;
 
  if(i2>type_var) i2=type_var;
 
  return i1-i2;
 
}
 
 
 
void t_oneterm(char *p, int num)
 
{
 
  int sign, fcnt, s, i, dentype, rel;
 
  char *pp, *pe, *pt;
 
  struct afactor factors[MAX_FACTORS];
 
  struct afactor *numerator[MAX_FACTORS],
 
    *denominator[MAX_FACTORS],
 
    *neutral[MAX_FACTORS];
 
  int numcnt,dencnt,neucnt;
 
/* interpret some arrows */
 
  rel=0;
 
  switch(*p) {
 
    case '<': {
 
      rel++; p++; if(*p!='=') {tprint(" < "); break;} // <
 
      do p++; while(*p=='=');
 
      if(*p!='>') {tprint("\\le ");break;} // <= , <===
 
      else {tprint("\\iff ");p++; break;} // <==>
 
    }
 
    case '>': {
 
      rel++; p++; if(*p!='=') {tprint(" > "); rel=1; break;} // >
 
      while(*p=='=') p++;
 
        tprint("\\ge "); // >=
 
        break;
 
    }
 
    case '-': {
 
      for(pp=p;*pp=='-';pp++);
 
      if(*pp!='>') break;
 
      rel++; tprint("\\to "); p=++pp; //->
 
      break;
 
    }
 
    case '=': {
 
        rel++; for(pp=p;*pp=='=';pp++);
 
        if(*pp!='>') break;
 
        tprint("\\Rightarrow "); p=++pp; // =>
 
        break;
 
    }
 
  }
 
  if(*p==',' || *p==';' || *p=='=') {tprint("%c",*p); p++; num=0;}
 
    sign=1; while(*p=='+' || *p=='-') {
 
      if(*p=='-') sign*=-1;
 
      p++;
 
  }
 
  for(fcnt=0, pp=p; fcnt<MAX_FACTORS && *pp; fcnt++, pp=pe) {
 
    s=1;
 
    while(*pp=='*' || *pp=='/') {
 
      if(*pp=='/') s=-1;
 
      pp++;
 
    }
 
    factors[fcnt].side=s;
 
    while(*pp=='+' || *pp=='-') {
 
      if(*pp=='-') sign*=-1;
 
      pp++;
 
    }
 
    pe=find_factor_end(pp); if(pe<=pp) break;
 
    factors[fcnt].beg=pp; factors[fcnt].end=pe;
 
    if(pe-pp==1 && *pp=='1') fcnt--;
 
    if(*pp=='(') {
 
      char *pt, *pe2, buf[MAX_LINELEN+1];
 
      int ss;
 
      pp++; pt=find_matching(pp,')');
 
      if(pt>=pe-1) {
 
        memmove(buf
,pp
,pt
-pp
); buf
[pt
-pp
]=0;  
        i=term_cnt(buf);
 
        if(i==1) { /* remove parentheses */
 
          for(;pp<pt && fcnt<MAX_FACTORS;pp=pe2,fcnt++) {
 
            ss=s;
 
            while(*pp=='*' || *pp=='/') {
 
              if(*pp=='/') ss=-s;
 
              pp++;
 
            }
 
            factors[fcnt].side=ss;
 
            while(*pp=='+' || *pp=='-') {
 
              if(*pp=='-') sign*=-1;
 
              pp++;
 
            }
 
            pe2=find_factor_end(pp);
 
            if(pe2<=pp) goto bailout;
 
            factors[fcnt].beg=pp; factors[fcnt].end=pe2;
 
            if(pe2-pp==1 && *pp=='1') fcnt--;
 
          }
 
          fcnt--;
 
        }
 
      }
 
    }
 
  }
 
  bailout:
 
/* decide if the factor is of type numeric, integer, poly, transcend or variable
 
*  (see priorities)
 
*/
 
  for(i=0;i<fcnt;i++) {
 
    pp=factors[i].beg; pe=factors[i].end;
 
    if(myisdigit(*pp) || *pp=='.') {
 
      for(pt=pp;pt<pe && myisdigit(*pt);pt++);
 
      if(pt<pe) factors[i].type=type_numeric; // digits with a point
 
      else factors[i].type=type_integer;  // digits without point
 
      continue;
 
    }
 
    if(*pp=='(') {
 
      factors[i].type=type_poly; continue; //there exists a parenthesis
 
    }
 
    if(pt!=NULL && pt<pe) factors[i].type=type_transcend; //??
 
    else factors[i].type=type_var;  // variable in other cases
 
  }
 
  dentype=-1;
 
  for(i=0;i<fcnt;i++) if(factors[i].side<0 && factors[i].type>dentype)
 
    dentype=factors[i].type; // denominator type will be compared to the type of the factors
 
  dencnt=numcnt=neucnt=0;
 
  for(i=0;i<fcnt;i++) {
 
    if(factors[i].type>dentype) neutral[neucnt++]=factors+i;
 
    else {
 
      if(factors[i].side>0) numerator[numcnt++]=factors+i;
 
      else denominator[dencnt++]=factors+i;
 
    }
 
  }
 
  if(dencnt
>0) qsort(denominator
,dencnt
,sizeof(denominator
[0]),fsort
);  
  if(numcnt
>0) qsort(numerator
,numcnt
,sizeof(numerator
[0]),fsort
);  
  if(neucnt
>0) qsort(neutral
,neucnt
,sizeof(neutral
[0]),fsort
);  
  if(sign>0 && num>0 && rel==0) tprint(" +");
 
  if(sign<0) tprint(" -");
 
  if(fcnt<1) tprint("1 "); // no factors why 1 - don't remove the 1 if [1,2;3,4], the 1 is useful?
 
  if(dencnt>0) {
 
    tprint(" {");
 
    if(numcnt==0) tprint(" 1"); // no numerator ? will write {1 over denominator}
 
    else {/* numerator */
 
      if(numcnt==1 && *numerator[0]->beg=='(' &&
 
          find_matching(numerator[0]->beg+1,')')==(numerator[0]->end)-1) {
 
        *(numerator[0]->end-1)=0;
 
        t_onestring(numerator[0]->beg+1);
 
        *(numerator[0]->end-1)=')';
 
      }
 
      else for(i=0; i<numcnt; i++) {t_onefactor(numerator[i],i);
 
      if(i<numcnt-1) tprint(" ");} /* add space between factors */
 
    }
 
    tprint(" \\over ");      /* Now denominator */
 
    if(dencnt==1 && *denominator[0]->beg=='(' &&
 
      find_matching(denominator[0]->beg+1,')')==(denominator[0]->end)-1) {
 
       *(denominator[0]->end-1)=0;
 
       t_onestring(denominator[0]->beg+1);
 
       *(denominator[0]->end-1)=')';
 
    }
 
    else for(i=0;i<dencnt;i++) {t_onefactor(denominator[i],i);
 
    if(i<dencnt-1) tprint(" ");} /* add space between factors */
 
    tprint("} ");
 
  }
 
  for(i=0;i<neucnt;i++) {t_onefactor(neutral[i],i+dencnt);
 
  if(i<neucnt-1) tprint(" ");} /* add space between factors */
 
}
 
 
 
/* put exponential */
 
void t_exponential(char *pp)
 
{
 
  char *pe, *pt;
 
  int t=0;
 
 
 
  while(*pp 
&& strchr("!'\"",*pp
)!=NULL
) {  
    tprint("%c",*pp); pp++;
 
  }
 
  if(*pp=='^') pp++; else return;
 
  if(*pp=='(') {
 
    pe=find_matching(pp+1,')');
 
    if(*(pe+1)==0) {
 
      pp++;*pe=0;
 
      for(pt
=pp
;*pt 
&& (isalnum(*pt
) || *pt
=='.');pt
++);  
      if(*pt==0) t=1;
 
    }
 
  }
 
  if(strlen(pp
)==1 && t
==0) tprint
("^%s ",pp
);  
  else {
 
    tprint(" ^{"); if(t) tprint("(");
 
    t_onestring(pp);
 
    if(t) tprint(")");
 
    tprint("} ");
 
  }
 
}
 
 
 
void t_onefactor(struct afactor *fb, int num)
 
{
 
  char *p, *pe, lp, *rp, rp2, rpbuf[128];
 
  char fbuf[MAX_LINELEN+1], pbuf[MAX_LINELEN+1];
 
  int i;
 
 
 
  memmove(pbuf
,fb
->beg
,fb
->end
-fb
->beg
);  
  pbuf[fb->end-fb->beg]=0;
 
  if(num>0 && (myisdigit(pbuf[0]) || pbuf[0]=='.'))
 
    tprint("\\times ");
 
  rp2=')'; p=pbuf;
 
  lp=*p; switch(lp) {
 
    case '(': rp2=')';  break;
 
    case '[': { /* verify for matrices */
 
      char *pt;
 
      pe=find_matching(p+1,']');
 
      for(pt=p+1;pt<pe;pt++) {
 
        switch(*pt) {
 
          case '(': pt=find_matching(pt+1,')'); break;
 
          case '[': pt=find_matching(pt+1,']'); break;
 
          case '{': pt=find_matching(pt+1,'}'); break;
 
          case '|': pt=find_matching(pt+1,'|'); break;
 
 
 
          case ',':
 
          case ';': goto out;
 
        }
 
      }
 
      out: if(*pt==';' || *pt==',') { /* is matrix of the form [ 1,2;5,6] */
 
        char mbuf[MAX_LINELEN+1];
 
        char *pp, *pt;
 
 
 
        p++; if(*pe) *pe++=0;
 
        tprint(" \\begin{pmatrix}");
 
        for(pp=p,i=0;*pp;pp=pt,i++) {
 
          pt=find_term_end(pp);
 
          memmove(mbuf
,pp
,pt
-pp
); mbuf
[pt
-pp
]=0;  
          t_oneterm(mbuf,i);
 
          if(*pt==',') {
 
            tprint(" &"); pt++; i=-1;
 
          }
 
          if(*pt==';') {
 
            tprint("\\cr "); pt++; i=-1;
 
          }
 
        }
 
        tprint(" \\end{pmatrix}"); goto expon;
 
      }
 
      rp2=']'; break;
 
    }
 
    case '{': { /* protected */
 
      pe=find_matching(p+1,'}');
 
      *pe=0;tprint(" %s} ",p);
 
      goto expon;
 
    }
 
  }
 
  tprint(" \\left%c",lp);
 
  snprintf(rpbuf
,sizeof(rpbuf
),"\\right%c ",rp2
); rp
=rpbuf
;  
  paren: p++;pe=find_matching(p,rp2); *pe=0;
 
  t_onestring(p); tprint(rp); pe++; goto expon;
 
  }
 
  pe
=find_mathvar_end
(p
); while(*pe 
&& strchr("'\"!",*pe
)!=NULL
) pe
++; 
  memmove(fbuf
,p
,pe
-p
); fbuf
[pe
-p
]=0;  
  if(myisdigit(*p) || *p=='.') putnumber(fbuf);
 
    pe
=find_mathvar_end
(p
); while(*pe 
&& strchr("'\"!",*pe
)!=NULL
) pe
++; 
    if(*pe=='(') {
 
      p=pe;
 
/* search in list of math functions*/
 
      i=search_list(tmathfn, tmathfn_no, sizeof(tmathfn[0]), fbuf);
 
      if(i>=0) {
 
        switch(tmathfn[i].expind) {
 
          case 0: {
 
            tprint(" %s",tmathfn[i].left);
 
            rp=tmathfn[i].right; break;
 
          }
 
          case 1: {
 
            tprint(" %s",tmathfn[i].left);
 
            pe=find_matching(pe+1,')')+1;
 
            if(*pe 
&& strchr("^'\"!",*pe
)!=NULL
) {  
              t_exponential(pe); *pe=0;
 
            }
 
            tprint(" \\left("); rp=tmathfn[i].right;
 
            break;
 
          }
 
          case 2: {  /* routine */
 
            p++;pe=find_matching(p,rp2); *pe=0;
 
            tmathfn[i].routine(p);
 
            pe++; goto expon;
 
          }
 
          default: rp=""; break;
 
        }
 
      }
 
      else {
 
        putvar(fbuf);
 
        rp="\\right) "; tprint(" \\left(");
 
      }
 
      rp2=')'; goto paren;
 
    }
 
    else {
 
      putvar(fbuf);
 
      if(*pe=='_') {
 
        char *ptt, buff[256];
 
        tprint("_"); pe++;
 
        if(*pe=='(') {
 
          ptt=find_matching(pe+1,')'); if(ptt) ptt++;
 
        }
 
        else {
 
          if(*pe=='{') {
 
            ptt=find_matching(pe+1,'}'); if(ptt) ptt++;
 
          }
 
          else ptt=find_mathvar_end(pe);
 
        }
 
        if(ptt==NULL || ptt-pe>128) goto expon;
 
        memmove(buff
,pe
,ptt
-pe
); buff
[ptt
-pe
]=0; pe
=ptt
;  
        strip_enclosing_par(buff);
 
        tprint("{%s}",buff);
 
      }
 
    }
 
  }
 
    /* exponential */
 
  expon
: if(*pe 
&& strchr("^'\"!",*pe
)!=NULL
) t_exponential
(pe
); 
}
 
 
 
void t_onestring(char *p)
 
{
 
  char termbuf[MAX_LINELEN+1];
 
  char *pp, *pe;
 
  int i;
 
 
 
  for(pp=p,i=0;*pp;pp=pe,i++) {
 
  pe=find_term_end(pp);
 
  memmove(termbuf
,pp
,pe
-pp
); termbuf
[pe
-pp
]=0;  
  t_oneterm(termbuf,i);
 
  }
 
}
 
/* replace \pmatrix{  } by latex syntax \begin{pmatrix} .. \end{pmatrix} */
 
 
 
void _replace_matrix ( char *p , char *s_mat1, char *s_mat2 )
 
{
 
  char pbuf[MAX_LINELEN];
 
  while ( (p 
= strstr(p
,s_mat1
)) ){  
    char *p2 
= find_matching
(p
+strlen(s_mat1
),'}');  
    long len 
= p2
-p
-strlen(s_mat1
);  
    if (!p2) { module_error("unmatched_parentheses"); return; }
 
    p2 ++ ;
 
    string_modify(p, p, p2, "\\begin{%s}%s\\end{%s}",s_mat2,pbuf,s_mat2);
 
  }
 
}
 
 
 
/* translate raw math expression into TeX source */
 
void texmath(char *p)
 
{
 
  char *pp;
 
  _replace_matrix (p,"\\matrix{","matrix");
 
  _replace_matrix (p,"\\pmatrix{","pmatrix");
 
  if(strpbrk(p
,"{}\\")!=NULL
) return;  
    if(pp
>p 
&& !isspace(*(pp
-1))) continue;  
    string_modify(p,pp,pp+2,"*neq*");
 
  }
 
/* remove spaces */
 
  for(pp=p; *pp; pp++) {
 
  if(isspace(*pp
)) {ovlstrcpy
(pp
,pp
+1); pp
--;}  
  }
 
/* replace ** by ^  see __replace_badchar(p,"**", "^");*/
 
    *pp='^'; ovlstrcpy(pp+1,pp+2);
 
  }
 
  if(check_parentheses(p,1)!=0) module_error("unmatched_parentheses");
 
  texmathbuf[0]=0; t_onestring(p);
 
  singlespace(texmathbuf);strip_trailing_spaces(texmathbuf);
 
  mystrncpy(p,texmathbuf,MAX_LINELEN);
 
}