Logo Search packages:      
Sourcecode: wims version File versions  Download package

texmath.c

/*    Copyright (C) 1998 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 */

        /* Careful! increasing this number risks stack overflow. */
#define MAX_FACTORS 256

enum {
    type_integer, type_numeric, type_var,
      type_poly, type_transcend
};

00027 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);
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];

    va_start(vp,s); vsnprintf(buf,sizeof(buf),s,vp); va_end(vp);
    if(strlen(buf)+strlen(texmathbuf)>=MAX_LINELEN) 
      user_error("cmd_output_too_long");
    strcat(texmathbuf,buf);
}

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("d");
      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 {
    char *name;
    int expind;
    char *left, *right;
    void (*routine) (char *p);
} 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)"}
};

#define tmathfn_no (sizeof(tmathfn)/sizeof(tmathfn[0]))

struct {
    char *name, *tex;
} 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"}
};

#define 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;
          }
      }
      if(isalnum(*pp) || *pp=='.') {
          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;
          }
      }
      if(isalnum(*pp) || *pp=='.') {
          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;
    
    pe=p+strlen(p);
    for(i=0,pp=p;pp<pe;pp=find_term_end(pp),i++);
    return i;
}

      /* Print a number */
void putnumber(char *p)
{
    char *pp;
    pp=strpbrk(p,"Ee");
    if(pp==NULL) {tprint("%s",p); return;}
    *pp++=0;
    tprint("%s \\times 10^{%s} ",p,pp);
}

      /* Print a variable name */
void putvar(char *p)
{
    char vbuf[1024];
    char *pp, *p2;
    int i;
    
    vbuf[0]=0;
    if(*(p+1)==0) {tprint("%c",*p); return;}
    for(pp=p;isalpha(*pp);pp++);
    if(isdigit(*pp)) {
      for(p2=pp+1;isdigit(*p2);p2++);
      if(*p2==0) {      /* subscript */
          snprintf(vbuf,sizeof(vbuf),"%s",pp);*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);
    }
}

int fsort(const void *p1, const void *p2)
{
    struct afactor **f1, **f2, *t1, *t2;
    int i1,i2;
    
    (const void *) f1=p1; (const void *) f2=p2;
    t1=*f1; t2=*f2;
    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;

    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=-1; 
                      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:
    for(i=0;i<fcnt;i++) {
      pp=factors[i].beg; pe=factors[i].end;
      if(isdigit(*pp) || *pp=='.') {
          pt=strpbrk(pp,"Ee."); 
          if(pt!=NULL && pt<pe) {
            factors[i].type=type_numeric; continue;
          }
          factors[i].type=type_integer; continue;           
      }
      if(*pp=='(') {
          factors[i].type=type_poly; continue;
      }
      pt=strchr(pp,'('); 
      if(pt!=NULL && pt<pe) factors[i].type=type_transcend;
      else factors[i].type=type_var;
    }
    dentype=-1;
    for(i=0;i<fcnt;i++) if(factors[i].side<0 && factors[i].type>dentype)
      dentype=factors[i].type;
    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 ");
    if(dencnt>0) {
      tprint(" {");
      if(numcnt==0) tprint(" 1"); 
      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);
      }
      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);
      tprint("} ");
    }
    for(i=0;i<neucnt;i++) t_onefactor(neutral[i],i+dencnt);
}

      /* 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 && (isdigit(pbuf[0]) || pbuf[0]=='.'))
      tprint("\\times ");
    rp2=')'; p=pbuf;
    if(strchr("({[",*p)!=NULL) {
      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 */
                char mbuf[MAX_LINELEN+1];
                char *pp, *pt;
                
                p++; if(*pe) *pe++=0;
                tprint(" \\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(" }"); 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(isdigit(*p) || *p=='.') putnumber(fbuf);
    if(isalpha(*p)) {
      pe=find_mathvar_end(p); while(*pe && strchr("'\"!",*pe)!=NULL) pe++;
      if(*pe=='(') {
          p=pe;
          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);
    }
}
    
      /* translate raw math expression into TeX source */
void texmath(char *p)
{
    char *pp;
    
    for(pp=strstr(p,"!="); pp; pp=strstr(pp+1,"!=")) {
      if(pp>p && !isspace(*(pp-1))) continue;
      string_modify(p,pp,pp+2,"*neq*");
    }
      /* remove spaces */
    for(pp=p; *pp; pp++) {
      if(isspace(*pp)) {strcpy(pp,pp+1); pp--;}
    }
      /* replace ** by ^ */
    for(pp=strstr(p,"**"); pp!=NULL; pp=strstr(pp,"**")) {
      *pp='^'; strcpy(pp+1,pp+2);
    }
    if(check_parentheses(p,1)!=0) module_error("unmatched_parentheses");
    texmathbuf[0]=0; t_onestring(p);
    snprintf(p,MAX_LINELEN,"%s",texmathbuf);
}


Generated by  Doxygen 1.6.0   Back to index