Back to index

wims  3.65+svn20090927
rawmath.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 
00018 /* internal variable */
00019 int rawmath_easy=0;
00020 
00021 #include "hmname.c"
00022 
00023 enum {RM_UNKNOWN, RM_FN, RM_VAR, RM_PREFIX};
00024 
00025 struct {
00026     char *name;
00027     int style;
00028     char *replace;
00029 } mathname[]={
00030       {"Arc", RM_PREFIX,    "arc"},
00031       {"Arg", RM_PREFIX,    "arg"},
00032       {"Ci",  RM_FN,        ""},
00033       {"E",   RM_VAR,              ""},
00034       {"Euler", RM_VAR,            ""},
00035       {"I",   RM_VAR,              ""},
00036       {"Int", RM_FN,        ""},
00037       {"PI",  RM_VAR,              ""},
00038       {"Pi",  RM_VAR,              ""},
00039       {"Prod",       RM_FN,        ""},
00040       {"Si",  RM_FN,        ""},
00041       {"Sum", RM_FN,        ""},
00042       {"arc", RM_PREFIX,    ""},
00043       {"arg", RM_PREFIX,    ""},
00044       {"binomial",RM_FN,    ""},
00045       {"diff",       RM_FN,        ""},
00046       {"e",   RM_VAR,              ""},
00047       {"erf", RM_FN,        ""},
00048       {"euler", RM_VAR,            ""},
00049       {"i",   RM_VAR,              ""},
00050       {"infinity",RM_VAR,   ""},
00051       {"int", RM_FN,        ""},
00052       {"integrate",RM_FN,   ""},
00053       {"neq", RM_VAR,              ""},
00054       {"pi",  RM_VAR,              ""},
00055       {"prod",       RM_FN,        ""},
00056       {"product",RM_FN,            ""},
00057       {"psi", RM_FN,        ""},
00058       {"sum", RM_FN,        ""},
00059       {"theta", RM_FN,             ""},
00060       {"x",   RM_VAR,              ""},
00061       {"y",   RM_VAR,              ""},
00062       {"z",   RM_VAR,              ""},
00063       {"zeta",  RM_FN,             ""},
00064 };
00065 #define mathname_no (sizeof(mathname)/sizeof(mathname[0]))
00066 char rm_vbuf[MAX_LINELEN+1],rm_fbuf[MAX_LINELEN+1];
00067 char *rm_uservar[MAX_LINELEN+1],*rm_userfn[MAX_LINELEN+1];
00068 int  rm_uservars,rm_userfns;
00069 
00070        /* add user-defined variables and function names,
00071         * internal, only called by rawmath(). */
00072 void getuservar(void)
00073 {
00074     char *p1, *p2, *p;
00075     rm_uservars=rm_userfns=0;
00076     p=getvar("wims_rawmath_variables");
00077     if(p!=NULL && *p!=0) {
00078        strcpy(rm_vbuf,p);
00079        for(p=rm_vbuf;*p;p++) if(*p==',') *p=' ';
00080        for(p1=find_word_start(rm_vbuf);*p1;p1=find_word_start(p2)) {
00081            rm_uservar[rm_uservars++]=p1;
00082            p2=find_word_end(p1);
00083            if(*p2!=0) *(p2++)=0;
00084        }
00085     }
00086     p=getvar("wims_rawmath_functions");
00087     if(p!=NULL && *p!=0) {
00088        strcpy(rm_fbuf,p);
00089        for(p=rm_fbuf;*p;p++) if(*p==',') *p=' ';
00090        for(p1=find_word_start(rm_fbuf);*p1;p1=find_word_start(p2)) {
00091            rm_userfn[rm_userfns++]=p1;
00092            p2=find_word_end(p1);
00093            if(*p2!=0) *(p2++)=0;
00094        }
00095     }
00096 }
00097 
00098        /* Try to split a word into recognizable variables */
00099 char *mathname_split(char *p)
00100 {
00101     int c,i,j,type;
00102 
00103     c=0;
00104     beg: for(i=get_evalcnt()-1;
00105        i>=0 && strncmp(p,get_evalname(i),strlen(get_evalname(i)))!=0;
00106        i--);
00107     if(i>=0 && get_evaltype(i)>0) {
00108        type=RM_FN;
00109        j=strlen(get_evalname(i));
00110        gotit:
00111        if(!*(p+j)) return p;
00112        if(myisdigit(*(p+j)) && type!=RM_FN) return NULL;
00113        if(!c) {string_modify(p,p+j,p+j," "); p+=j+1;}
00114        else p+=j;
00115        c++; goto beg;
00116     }
00117     for(i=mathname_no-1;
00118        i>=0 && 
00119        (strncmp(p,mathname[i].name,strlen(mathname[i].name))!=0
00120         || mathname[i].style==RM_PREFIX);
00121        i--);
00122     if(i>=0) {
00123        type=mathname[i].style;
00124        j=strlen(mathname[i].name);
00125        goto gotit;
00126     }
00127     for(i=0;i<rm_uservars && 
00128        strncmp(rm_uservar[i],p,strlen(rm_uservar[i]));i++);
00129     if(i<rm_uservars) {
00130        type=RM_VAR;
00131        j=strlen(rm_uservar[i]); goto gotit;
00132     }
00133     for(i=0;i<rm_userfns && 
00134        strncmp(p,rm_userfn[i],strlen(rm_userfn[i]));i++);
00135     if(i<rm_userfns) {
00136        type=RM_FN;
00137        j=strlen(rm_userfn[i]); goto gotit;
00138     }
00139     return NULL;    
00140 }
00141 
00142        /* Error-tolerante raw math translation routine */
00143        /* Translate error-laden raw math into machine-understandable form. */
00144 void rawmath(char *p)
00145 {
00146     char *p1, *p2, *p3, *p4;
00147     char warnbuf[1024];
00148     int modified=0,user_prohibited=0;
00149     int ambiguous=0,unknown=0,flatpower=0,badprec=0,unmatch=0;
00150 
00151        /* looks like a TeX source */
00152     if(strchr(p,'\\')!=NULL || strchr(p,'{')!=NULL) return;
00153     if(strchr(p,'^')==NULL) flatpower=-1;
00154     if(strlen(p)>=MAX_LINELEN) {*p=0; return;}
00155     if(strncmp(p,"1-1+",strlen("1-1+"))==0) user_prohibited=1;
00156     p1=find_word_start(p);if(*p1==0) return;
00157     while(*p1=='+') p1++;
00158     if(p1>p) strcpy(p,p1);
00159        /* translate ** into ^ */
00160     while((p1=strstr(p,"**"))!=NULL) {
00161        string_modify(p,p1,p1+strlen("**"),"^");
00162        modified++;
00163     }
00164     while((p1=strchr(p,''))!=NULL) {
00165        string_modify(p,p1,p1+1,"^2 ");
00166        flatpower=1;
00167        modified++;
00168     }
00169     while((p1=strchr(p,''))!=NULL) {
00170        string_modify(p,p1,p1+1,"^3 ");
00171        flatpower=1;
00172        modified++;
00173     }
00174     while((p1=strchr(p,''))!=NULL) {
00175        *p1='^'; modified++;
00176     }
00177        /* translate |x| into abs(x) */
00178     while((p1=strchr(p,'|'))!=NULL) {
00179        p2=find_matching(p1+1,'|');
00180        if(p2==NULL) {unmatch=1; break;}   /* error; drop it. */
00181        *p2=')'; string_modify(p,p1,p1+1,"abs(");
00182     }
00183         /* signs: translate ++, +-, -+, ... into one sign. */
00184     for(p1=p;*p1!=0;p1++) {
00185        int sign, redundant;
00186        if(*p1!='+' && *p1!='-') continue;
00187        if(*p1=='+') sign=1; else sign=-1;
00188        redundant=0;
00189        for(p2=find_word_start(p1+1);*p2=='+' || *p2=='-';
00190            p2=find_word_start(p2+1)) {
00191             if(*p2=='-') sign*=-1;
00192             redundant=1;
00193        }
00194        if(redundant && *p2!='>' && strncmp(p2,"&gt;",4)!=0) {
00195            if(sign==1) *p1='+'; else *p1='-';
00196            strcpy(p1+1,p2);
00197            modified++;
00198        }
00199     }
00200        /* First translation: lower cases, parentheses, new-lines, tabs. */
00201     for(p1=p;*p1!=0; p1++) {
00202        /* *p1=tolower(*p1); */
00203 /*     if(*p1=='[' || *p1=='{') *p1='(';
00204        if(*p1==']' || *p1=='}') *p1=')';
00205 */     if(*p1=='\\' || isspace(*p1)) *p1=' ';
00206        if(*p1=='\"') {
00207            string_modify(p,p1,p1+1,"''"); p1++;
00208        }
00209     }
00210        /* dangling decimal points */
00211     for(p1=strchr(p,'.'); p1!=NULL; p1=strchr(p1+1,'.')) {
00212               /* multiple .. is conserved */
00213        if(*(p1+1)=='.') {
00214            do p1++; while(*p1=='.'); continue;
00215        }
00216        if(p1>p && myisdigit(*(p1-1)) && myisdigit(*(p1+1))) continue;
00217               /* Non-digit dangling '.' is removed */
00218        if((p1<=p || !myisdigit(*(p1-1))) && !myisdigit(*(p1+1))) {
00219            strcpy(p1,p1+1); p1--; continue;
00220        }
00221        if(p1==p || !myisdigit(*(p1-1))) {
00222            string_modify(p,p1,p1,"0"); p1++;
00223        }
00224        if(!myisdigit(*(p1+1))) string_modify(p,p1+1,p1+1,"0");
00225     }
00226     if(rawmath_easy || user_prohibited) return;
00227        /* Principal translation: justapositions to multiplications */
00228     if(strstr(p,"^1/")!=NULL) badprec=1;
00229     getuservar();
00230     for(p1=p;*p1;p1++) {
00231        if(!isalnum(*p1) && *p1!=')' && *p1!=']') continue;
00232        if(*p1==')' || *p1==']') {
00233            p2=find_word_start(++p1);
00234            add_star:
00235            if(isalnum(*p2) || *p2=='(' || *p2=='[') {
00236               if(*p2=='(' && *p1==')') ambiguous=1;
00237               if(p2>p1) *p1='*';
00238               else string_modify(p,p1,p1,"*");
00239               modified++;
00240            }
00241            p1--;continue;
00242        }
00243        p2=find_mathvar_end(p1); p3=find_word_start(p2);
00244        if(myisdigit(*p1)) {
00245            p1=p2; p2=p3; goto add_star;
00246        }
00247        else {
00248            char buf[MAX_LINELEN+1];
00249            int i;
00250            if(p2-p2>30) goto ambig;
00251            memcpy(buf,p1,p2-p1);buf[p2-p1]=0;
00252            i=search_evaltab(buf);
00253            if(i>=0 && get_evaltype(i)>0) {
00254               fnname1:
00255               p1=p2;p2=p3;
00256               /*fnname:*/
00257               if(*p2 && *p2!='(' && *p2!='*' && *p2!='/') {
00258                   char hatbuf[MAX_LINELEN+1];
00259                   hatbuf[0]=')'; hatbuf[1]=0;
00260                   if(*p2=='^') {
00261                      p3=p2+1;while(*p3==' ' || *p3=='+' || *p3=='-') p3++;
00262                       if(*p3=='(') {
00263                          p3=find_matching(p3+1,')');
00264                          if(p3==NULL) {unmatch=1; p3=p+strlen(p);}
00265                          else p3++;
00266                      }
00267                      else p3=find_mathvar_end(p3);
00268                      memmove(hatbuf+1,p2,p3-p2);hatbuf[p3-p2+1]=0;
00269                      strcpy(p2,p3);
00270                      while(*p2==' ') p2++;
00271                      if(*p2=='*' || *p2=='/') {
00272                          p1--;continue;
00273                      }
00274                      if(*p2=='(') {
00275                          p3=find_matching(p2+1,')');
00276                          if(p3==NULL) {unmatch=1; p3=p+strlen(p);}
00277                          else p3++;
00278                          string_modify(p,p3,p3,"%s",hatbuf+1);
00279                          goto dd2;
00280                      }
00281                   }
00282                   p3=p2;if(*p3=='+' || *p3=='-') p3++;
00283                   while(isalnum(*p3) || *p3=='*' || *p3=='/' || *p3=='.')
00284                     p3++;
00285                   for(p4=p2; p4<p3 && !isalnum(*p4); p4++);
00286                   if(p4>=p3) {
00287                      if(hatbuf[1]) string_modify(p,p2,p2,"%s",hatbuf+1);
00288                   }
00289                   else {
00290                      string_modify(p,p3,p3,"%s",hatbuf);
00291                      if(p1==p2) string_modify(p,p2,p2,"(");
00292                      else *p1='(';
00293                   }
00294                   dd2:
00295                   modified++;ambiguous=1;
00296               }
00297               p1--;continue;
00298            }
00299            i=search_list(mathname,mathname_no,sizeof(mathname[0]),buf);
00300            if(i>=0) {
00301               if(mathname[i].replace[0]!=0) {
00302                   string_modify(p,p1,p2,mathname[i].replace);
00303                   p2=p1+strlen(mathname[i].replace);
00304                   p3=find_word_start(p2);
00305               }
00306               switch(mathname[i].style) {
00307                   case RM_FN:
00308                     goto fnname1;
00309                   
00310                   case RM_VAR:
00311                     p1=p2;p2=p3; goto add_star;
00312                   
00313                   case RM_PREFIX:
00314                     if(*p3!='c' && *p3!='s' && *p3!='t' && 
00315                       *p3!='C' && *p3!='S' && *p3!='T') break;
00316                     ambiguous=1;
00317                     strcpy(p2,p3); p1--; continue;
00318               }
00319            }
00320            i=search_list(hmname,hmname_no,sizeof(hmname[0]),buf);
00321            if(i>=0) {
00322               p1=p2; p2=p3; goto add_star;
00323            }
00324            for(i=0;i<rm_uservars && strcmp(buf,rm_uservar[i]);i++);
00325            if(i<rm_uservars) {
00326               p1=p2;p2=p3;goto add_star;
00327            }
00328            for(i=0;i<rm_userfns && strcmp(buf,rm_userfn[i]);i++);
00329            if(i<rm_userfns) goto fnname1;
00330            if(p2-p1>8) goto ambig;
00331            if(mathname_split(buf)!=NULL) {
00332               ambiguous=1;
00333               string_modify(p,p1,p2,"%s",buf);
00334               p1--; continue;
00335            }
00336             /* unknown name */
00337            ambig: p1=p2;p2=p3;
00338            if(strlen(buf)>1) {
00339               for(p3=buf;*p3!=0 && !myisdigit(*p3);p3++);
00340               if(*p3!=0 && flatpower!=0) flatpower=1; 
00341               else {
00342                   unknown=1;
00343                   force_setvar("wims_warn_rawmath_parm",buf);
00344               }
00345            }
00346            else {
00347               if(*p2=='(') ambiguous=1;
00348            }
00349            if(isalnum(*p2)) {
00350               if(p2>p1) *p1='*';
00351               else string_modify(p,p1,p1,"*");
00352               modified++;
00353            }
00354            p1--;continue;
00355        }
00356     }
00357     warnbuf[0]=0;
00358     if(ambiguous) strcat(warnbuf," ambiguous");
00359     if(unknown) strcat(warnbuf," unknown");
00360     if(flatpower>0) strcat(warnbuf," flatpower");
00361     if(badprec>0) strcat(warnbuf," badprec");
00362     if(unmatch>0) strcat(warnbuf," unmatched_parentheses");
00363     if(warnbuf[0]) {
00364        char buf[MAX_LINELEN+1],*p;
00365        p=getvar("wims_warn_rawmath");
00366        if(p!=NULL && *p!=0) {
00367            snprintf(buf,sizeof(buf),"%s %s",p,warnbuf);
00368            force_setvar("wims_warn_rawmath",buf);
00369        }
00370        else force_setvar("wims_warn_rawmath",warnbuf);
00371     }
00372 }
00373 
00374        /* translate raw math expression into best html way */
00375 void htmlmath(char *p)
00376 {
00377     char *p1,*p2,*p3,*pp,pbuf[16];
00378     char c;
00379 
00380     if(!rawmath_easy) {
00381        rawmath_easy=1; rawmath(p); rawmath_easy=0;
00382     }
00383     p1=getvar("htmlmath_gtlt"); if(p1!=NULL && strcmp(p1,"yes")==0) {
00384        for(pp=strchr(p,'<'); pp!=NULL; pp=strchr(pp+1,'<'))
00385          string_modify(p,pp,pp+1,"&lt;");
00386        for(pp=strchr(p,'>'); pp!=NULL; pp=strchr(pp+1,'>'))
00387          string_modify(p,pp,pp+1,"&gt;");
00388     }
00389       /* exponents */
00390     for(p1=strchr(p,'^');p1!=NULL;p1=strchr(p1+1,'^')) {
00391        p3=p2=find_word_start(p1+1);
00392        if(*p2=='+' || *p2=='-') p2++;
00393        p2=find_word_start(p2);
00394        if(*p2=='(') {
00395            p2=find_matching(p2+1,')');
00396            if(p2==NULL) p2=p+strlen(p); else p2++;
00397            if(*p3=='(') for(pp=p3+1;pp<p2-1;pp++) {
00398               if(!isalnum(*pp)) {
00399                   p3++;*(p2-1)=0;break;
00400               }
00401            }
00402        }
00403        else {
00404            char *ptt=p2;
00405            p2=find_word_start(find_mathvar_end(p2));
00406            if(*p2=='(' && isalpha(*ptt)) {
00407               char *p2t;
00408               p2t=find_matching(p2+1,')'); if(p2t!=NULL) p2=p2t+1;
00409            }
00410        }
00411        c=*p2;if(c!=0) *p2++=0;
00412        string_modify(p,p1,p2,"<sup>%s</sup>%c",p3,c);
00413     }
00414        /* explicit subscription */
00415     for(p1=strchr(p,'_');p1!=NULL;p1=strchr(p1+1,'_')) {
00416        char buff[256];
00417        p2=p1+1;
00418        if(*p2=='(') p2=find_matching(p2+1,')');
00419        else p2=find_mathvar_end(p2);
00420        if(p2==NULL || p2>p1+64) continue;
00421        if(*(p1+1)=='(') p2++;
00422        memmove(buff,p1+1,p2-p1-1); buff[p2-p1-1]=0;
00423        strip_enclosing_par(buff);
00424        string_modify(p,p1,p2,"<sub>%s</sub>",buff);
00425     }
00426       /* get rid of 1*.. ..*1 */
00427     for(p1=p;*p1;p1++) {
00428        if(*p1!='1') continue;
00429        if(myisdigit(*(p1+1)) || *(p1+1)=='.' ||
00430           (p1>p && (isalnum(*(p1-1)) || *(p1-1)=='.')) ) continue;
00431        p2=find_word_start(p1+1);
00432        if(p1>p+2 && (*(p1-1)=='-' || *(p1-1)=='+')) {
00433            for(p3=p1-2; p3>p && isspace(*p3); p3--);
00434            if(p3>p+1 && (*p3=='E' || *p3=='e')) {
00435               p3--; while(p3>p && isspace(*p3)) p3--;
00436               if(myisdigit(*p3) || *p3=='.') continue;
00437            }
00438        }
00439        if(p1==p) p3="+"; 
00440        else for(p3=p1-1;p3>p && isspace(*p3);p3--);
00441        if(*p2=='*' && *p3!='/') {
00442            strcpy(p1,p2+1);continue;
00443        }
00444        if(isalpha(*p2) && *p3!='/') {
00445            strcpy(p1,p2);continue;
00446        }
00447        if(*p3=='/' && *p2!='<') strcpy(p3,p2);
00448 
00449     }
00450        /* exponents of 10, or greek letters */
00451     for(p1=find_mathvar_start(p);*p1!=0;p1=find_mathvar_start(p2)) {
00452        char buf[MAX_LINELEN+1];
00453        char expstr[]=" &times; 10<sup>";
00454        p2=find_mathvar_end(p1);
00455        memmove(buf,p1,p2-p1);buf[p2-p1]=0;
00456        if(myisdigit(buf[0])) { /* number */
00457            int k;
00458            if((p3=strchr(buf,'e'))==NULL && (p3=strchr(buf,'E'))==NULL)
00459              continue;
00460            p1+=p3-buf;
00461            for(k=1;*(p1+k)=='0' || *(p1+k)=='+';k++);
00462            string_modify(p,p1,p1+k,expstr);
00463            p2+=strlen(expstr)-1;
00464            string_modify(p,p2,p2,"</sup>");
00465            p2+=strlen("</sup>");
00466        }
00467        else { /* alphabetic name */
00468            int i;
00469            i=search_list(hmname,hmname_no,sizeof(hmname[0]),buf);
00470            if(i<0) {
00471               if(myisdigit(buf[strlen(buf)-1])) {
00472                   int k;
00473                   for(k=strlen(buf);k>0 && myisdigit(buf[k-1]); k--);
00474                   string_modify(buf,buf+k,buf+k,"<sub>");
00475                   string_modify(p,p1,p2,"%s</sub>",buf);
00476                   p2+=strlen("<sub>")+strlen("</sub>");
00477               }
00478               continue;
00479            }
00480            if(hmname[i].replace[0]==0) {
00481               string_modify(p,p1,p2,"$(m_%s)",hmname[i].name);
00482               p2=p1+strlen(hmname[i].name)+5;
00483            }
00484            else {
00485               string_modify(p,p1,p2,"%s",hmname[i].replace);
00486               p2=p1+strlen(hmname[i].replace);
00487            }
00488        }
00489     }
00490       /* get rid of '*' */
00491     for(p1=strchr(p,'*');p1!=NULL;p1=strchr(p1+1,'*')) {
00492        char *pq;
00493        pq=find_word_start(p1+1);
00494        if(myisdigit(*pq)) {
00495            string_modify(p,p1,pq,"&times;");
00496            continue;
00497        }
00498        if(p1>p && (isalpha(*(p1-1)) || *(p1-1)==')' || *(p1-1)=='>')
00499           && (isalnum(*pq) || *pq=='$')) *p1=' ';
00500        else {
00501            strcpy(p1,p1+1);p1--;
00502        }
00503     }
00504        /* <=, >=, ->, =>, <=> */
00505     for(p1=strstr(p,"&lt;="); p1!=NULL; p1=strstr(p1+1,"&lt;=")) {
00506        if(*(p1+5)!='&' && *(p1+5)!='=') 
00507          string_modify(p,p1,p1+5,"$(m_le)");
00508        else {
00509            for(p2=p1+5; *p2=='='; p2++);
00510            if(strncmp(p2,"&gt;",4)==0) {
00511               if(p2>p1+5) string_modify(p,p1,p2+4,"$(m_Longleftrightarrow)");
00512               else string_modify(p,p1,p2+4,"$(m_Leftrightarrow)");
00513            }
00514            else string_modify(p,p1,p2,"$(m_Longleftarrow)");
00515        }
00516     }
00517     for(p1=strstr(p,"&gt;="); p1!=NULL; p1=strstr(p1+1,"&gt;=")) {
00518        if(*(p1+5)!='=') string_modify(p,p1,p1+5,"$(m_ge)");
00519     }
00520     for(p1=strstr(p,"-&gt;"); p1; p1=strstr(p1+1,"-&gt;")) {
00521        for(p2=p1; p2>p && *(p2-1)=='-'; p2--);
00522        if(p2>p && *(p2-1)==';') continue;
00523        if(p2<p1) string_modify(p,p2,p1+5,"$(m_longrightarrow)");
00524        else string_modify(p,p1,p1+5,"$(m_rightarrow)");
00525     }
00526     for(p1=strstr(p,"=&gt;"); p1; p1=strstr(p1+1,"=&gt;")) {
00527        for(p2=p1; p2>p && *(p2-1)=='='; p2--);
00528        if(p2>p && *(p2-1)==';') continue;
00529        if(p2<p1) string_modify(p,p2,p1+5,"$(m_Longrightarrow)");
00530        else string_modify(p,p1,p1+5,"$(m_Rightarrow)");
00531     }
00532        /* Not equal */
00533     for(p1=strstr(p,"!="); p1; p1=strstr(p1+1,"!=")) {
00534        if(p1>p && !isspace(*(p1-1))) continue;
00535        string_modify(p,p1,p1+2,"$(m_neq)");
00536     }
00537        /* Now make substitutions */
00538     substit(p);
00539        /* Make single names italic */
00540     for(p1=p;*p1;p1++) {
00541        if(*p1=='<') {
00542            p1=strchr(p1,'>'); if(p1==NULL) break;
00543            else continue;
00544        }
00545        if(*p1=='=' && *(p1+1)=='-') {
00546            string_modify(p,p1+1,p1+1," "); p1+=2; continue;
00547        }
00548        if(*p1=='\'') {
00549            for(p2=p1+1;*p2=='\'';p2++);
00550            memmove(pbuf,p1,p2-p1); pbuf[p2-p1]=0;
00551            string_modify(p,p1,p2,"<i><tt>%s</tt></i>",pbuf);
00552            p1=p2+strlen("<i><tt></i></tt>")-1;
00553            continue;
00554        }
00555        if(!isalpha(*p1)) continue;
00556        for(p2=p1+1;isalpha(*p2);p2++);
00557        p3=find_word_start(p2);
00558        if(p2>p1+5 ||
00559           (p2>p1+1 && (*p3==';' || *p3=='(' || myisdigit(*p2))))
00560            {p1=p2-1; continue;}
00561        if(strncasecmp(p3,"</i>",strlen("</i>"))==0) continue;
00562        memmove(pbuf,p1,p2-p1); pbuf[p2-p1]=0;
00563        string_modify(p,p1,p2,"<i>%s</i>",pbuf);
00564        p1=p2+strlen("<i></i>")-1;
00565     }
00566     strip_trailing_spaces(p);
00567 }
00568