Back to index

wims  3.65+svn20090927
insplot.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        /* Interface gnuplot to wims */
00019 
00020 /*************** Customization: change values hereafter ****************/
00021 
00022 #define tmpdir "/tmp"
00023        /* limit of input/output file sizes */
00024 #define fsizelim 131072
00025        /* limit of parameter string */
00026 #define parmlim 131072
00027        /* number of versions */
00028 #define versions 2
00029        /* gp prompt string */
00030 #define gpprompt "\n? "
00031        /* string which defines the start of gp output 
00032         * (in order to cut gp header) */
00033 #define startstring "start line 49521845"
00034        /* This is the good bye string of gp, signaling end of output. */
00035 #define goodbyestring "? Good bye!"
00036 
00037 char header[]="Pi=pi\n\
00038 PI=pi\n\
00039 e=exp(1)\n\
00040 E=exp(1)\n\
00041 ln(x) = log(x)\n\
00042 ch(x) = cosh(x)\n\
00043 sh(x) = sinh(x)\n\
00044 th(x) = tanh(x)\n\
00045 arccos(x) = acos(x)\n\
00046 arcsin(x) = asin(x)\n\
00047 tg(x)    = tan(x)\n\
00048 arctan(x) = atan(x)\n\
00049 arctg(x)  = atan(x)\n\
00050 Argch(x)  = acosh(x)\n\
00051 Argsh(x)  = asinh(x)\n\
00052 Argth(x)  = atanh(x)\n\
00053 argch(x)  = acosh(x)\n\
00054 argsh(x)  = asinh(x)\n\
00055 argth(x)  = atanh(x)\n\
00056 set samples 400\n\
00057 ";
00058 
00059 /***************** Nothing should need change hereafter *****************/
00060 
00061 #include <stdio.h>
00062 #include <stdlib.h>
00063 #include <stdarg.h>
00064 #include <unistd.h>
00065 #include <string.h>
00066 #include <ctype.h>
00067 #include <time.h>
00068 #include <sys/time.h>
00069 
00070 #define SETUP_NO (sizeof(setups)/sizeof(setups[0]))
00071 #define MYNAME_NO (sizeof(name2version)/sizeof(name2version[0]))
00072 
00073        /* gpversion=0: gp1.39; gpversion=1: gp2.0. */
00074 int gpversion, mypid, precision;
00075 char inputfname[256], outputfname[256];
00076 char *parm;
00077 
00078 void *xmalloc(size_t n)
00079 {
00080     void *p;
00081     p=malloc(n);
00082     if(p==NULL) {
00083        fprintf(stderr, "pari: Malloc failure.");
00084        exit(1);
00085     }
00086     return p;
00087 }
00088 
00089        /* system(), but with variable parms */
00090 int call_sh(char *s,...)
00091 {
00092     va_list vp;
00093     char buf[1024];
00094     
00095     va_start(vp,s);
00096     vsnprintf(buf,sizeof(buf),s,vp);
00097     va_end(vp);
00098     return system(buf);
00099 }
00100 
00101        /* check for security violations in command string */
00102 void check_parm(void)
00103 {
00104     char *p;
00105     for(p=parm;*p!=0;p++) {
00106          /* no espace commands. */
00107        if(*p!='\n') continue;
00108        while(*p!=0 && isspace(*p)) p++;
00109        if(*p=='\\' && *(p+1)!='v') *p='.';
00110     }
00111 }
00112 
00113        /* patches the gnuplot integer division (mis)feature. */
00114 void gnuplot_patch(char *p,int oneline)
00115 {
00116     char *pp;
00117     for(pp=strchr(p,'/');pp!=NULL;pp=strchr(pp+1,'/')) {
00118        char *p1;
00119        if(pp<=p || !isdigit(*(pp-1)) || !isdigit(*(pp+1))) continue;
00120        for(p1=pp-2;p1>=p && isdigit(*p1);p1--);
00121        if(p1>=p && *p1=='.') continue;
00122        for(p1=pp+2;*p1 && isdigit(*p1);p1++);
00123        if(*p1=='.') continue;
00124        string_modify(p,p1,p1,".0");
00125     }
00126     for(pp=strchr(p,'^');pp!=NULL;pp=strchr(pp+1,'^'))
00127       string_modify(p,pp,pp+1,"**");
00128        /* disallow new lines and ';' */
00129     if(oneline)
00130       for(pp=p;*pp!=0;pp++) if(*pp==';' || *pp=='\n') *pp=' ';
00131 }
00132 
00133        /* This is to disable pipe in the gnuplot plotting function.
00134         * We do not allow ' followed by < . */
00135 void prepare_insplot_parm(char *p)
00136 {
00137     int i,j; char *pp, *s;
00138     double d;
00139     char setbuf[MAX_LINELEN+10],buf[MAX_LINELEN+1];
00140     
00141     j=strlen(p);
00142       /* pipe in plot command */
00143     for(i=0;i<j;i++) {
00144        if(*(p+i)!='\'' && *(p+i)!='"') continue;
00145        pp=find_word_start(p+i+1); if(*pp=='<') {
00146            module_error("illegal_plot_cmd"); exit(1);
00147        }
00148     }
00149     gnuplot_patch(p,1);
00150        /* multiplot */
00151     pp=getvar("insplot_split");i=evalue(pp);
00152        /* arbitrary limit: 16 multiplots */
00153     if(i>0 && i<=16) {
00154        char tbuf[MAX_LINELEN+1];
00155        snprintf(buf,sizeof(buf),"%d",i); setenv("multiplot",buf,1);
00156        for(j=1;j<=i;j++) {
00157            snprintf(buf,sizeof(buf),"insplot_parm_%d",j);
00158            pp=getvar(buf);
00159            snprintf(tbuf,sizeof(tbuf),"%s",pp);
00160            gnuplot_patch(tbuf,1);
00161            setenv(buf,tbuf,1);
00162        }
00163        
00164     }
00165        /* no illegal chaining */
00166     pp=getvar("insplot_font"); if(pp!=NULL) {
00167        for(s=pp;s<pp+MAX_LINELEN && *s;s++) 
00168          if(*s==';' || *s=='\n' || *s==' ') *s=0;
00169        if(s>=pp+MAX_LINELEN) *s=0;
00170        setvar("insplot_font",pp);
00171     }
00172     pp=getvar("insplot_set"); if(pp!=NULL) {
00173        char tbuf[MAX_LINELEN+1];
00174        snprintf(tbuf,sizeof(tbuf),"%s",pp);
00175        i=strlen(tbuf)-1;
00176        while(i>0 && isspace(tbuf[i])) i--;
00177        if(tbuf[i]==';') tbuf[i]=0;
00178        gnuplot_patch(tbuf,0);pp=tbuf;
00179        strcpy(setbuf,"set "); j=strlen("set ");
00180        for(i=0; *(pp+i)!=0 && j<MAX_LINELEN; i++) {
00181            if(*(pp+i)=='\n') {setbuf[j++]=' '; continue;}
00182            if(*(pp+i)!=';') {setbuf[j++]=*(pp+i); continue;}
00183            strcpy(setbuf+j,"\nset "); j+=strlen("\nset ");
00184        }
00185        setbuf[j]=0;
00186        setenv("insplot_set",setbuf,1);
00187     }
00188     else setenv("insplot_set","",1);
00189       /* frames of animation */
00190     pp=getvar("ins_anim_frames");
00191     if(pp!=NULL) i=evalue(pp); else i=1;
00192     if(i>=INS_LIMIT) i=INS_LIMIT-1; if(i<1) i=1;
00193     if(strstr(setbuf,"step")==NULL && strstr(p,"step")==NULL
00194        && varchr(setbuf,"s")==NULL && varchr(p,"s")==NULL) i=1;
00195     snprintf(buf,sizeof(buf),"%d",i);
00196     setenv("ins_anim_frames",buf,1);
00197     setvar("ins_anim_frames","");
00198       /* delay of animation */
00199     pp=getvar("ins_anim_delay");
00200     if(pp!=NULL) d=evalue(pp); else d=0;
00201     if(d>=10) d=10; if(d<0) d=0;
00202     i=d*100;
00203     snprintf(buf,sizeof(buf),"%d",i);
00204     setenv("ins_anim_delay",buf,1);
00205 }
00206 
00207        /* strip trailing zeros */
00208 void strip_zeros(char *p)
00209 {
00210     char *pp, *p2, *numend, *ee;
00211     int i;
00212     for(pp=p;*pp!=0;pp++) {
00213        if(!isdigit(*pp)) continue;
00214        i=0;
00215        for(numend=pp;isdigit(*numend) || *numend=='.';numend++)
00216          if(*numend=='.') i=1;
00217        if(i==0) {
00218            pp=numend-1;continue;
00219        }
00220        for(p2=numend;p2>pp && *(p2-1)=='0';p2--);
00221        for(ee=numend;isspace(*ee);ee++);
00222        if(*(pp+1)=='.' && (*ee=='E' || *ee=='e') 
00223           && *(ee+1)=='-') {
00224            int k=0;
00225            char *pt=ee+2;
00226            while(isdigit(*pt)) {
00227               k*=10;k+=*pt-'0';pt++;
00228            }
00229            if(k>precision*2 || (k>precision && *pp=='0')) {
00230               
00231               sprintf(pp,"0.0%s",pt);
00232               
00233               pp+=strlen("0.0")-1;
00234               continue;
00235            }
00236        }
00237        
00238        if(*(p2-1)=='.' && p2<numend) p2++; 
00239        
00240        if(p2<numend) {
00241            strcpy(p2,numend);numend=p2;
00242        }
00243        pp=numend-1;
00244     }
00245 }
00246 
00247        /* process and print gp output */
00248 void output(char *p)
00249 {
00250     int i,n;
00251     char *pp, *pe, *pt;
00252     pp=strstr(p,startstring);
00253     if(pp==NULL) return;
00254     pp=strstr(pp,gpprompt); if(pp==NULL) return;
00255     pe=strstr(pp,goodbyestring);
00256     if(pe>=pp) *pe=0;
00257     while(pp!=NULL) {
00258        pp++;
00259        pe=strstr(pp,gpprompt);
00260        if(pe>=pp) *pe=0;
00261        pp=strchr(pp,'\n');
00262        if(pp==NULL) {
00263            emptyline:
00264            puts(""); pp=pe; continue;
00265        }
00266        pp++; n=strlen(pp);
00267        if(n==0) goto emptyline;
00268               /* make every output one-line */
00269        for(i=0;i<n;i++) {
00270            if(*(pp+i)=='\n') {
00271               if(*(pp+i+1)!='%') *(pp+i)=' ';
00272               else {*(pp+i)=0; break;}
00273            }
00274        }
00275          /* strip leading and trailing spaces */
00276        while(isspace(*pp) && pp<pe) pp++;
00277        pt=pp+strlen(pp)-1;
00278        while(isspace(*pt) && pt>pp) pt--;
00279          /* remove parentheses of matrix output */
00280        if(memcmp(pp,"Mat(",4)==0 && *pt==')') {
00281            *(pt--)=0; pp+=4;
00282        }
00283        if(*pp=='[' && *pt==']') {
00284            *(pt--)=0; pp++;
00285        }
00286        strip_zeros(pp);
00287        puts(pp); pp=pe;
00288     }
00289 }
00290 
00291 void call_gnuplot(void)
00292 {
00293     int i,r;
00294     char *p;
00295     FILE *ff;
00296     struct timeval t;
00297     
00298     setenv(gprcenv,gprc[gpversion],1);
00299     mypid=getpid();
00300     snprintf(inputfname,sizeof(inputfname),"%s/gp_input.%d",tmpdir,mypid);
00301     snprintf(outputfname,sizeof(outputfname),"%s/gp_output.%d",tmpdir,mypid);
00302     ff=fopen(inputfname,"w");
00303     if(ff==NULL) {
00304        fprintf(stderr,"insplot: cannot open file %s.\n",inputfname); exit(1);
00305     }
00306     gettimeofday(&t,NULL);
00307     r=t.tv_usec*t.tv_sec;
00308     fprintf(ff,"\nsetrand(%d)\n",r);
00309     for(i=0;i<SETUP_NO;i++) {
00310        p=getenv(setups[i].wname);
00311        if(p==NULL || *p==0) p=setups[i].defaultval;
00312        fprintf(ff,"%s%s\n",setups[i].gpset[gpversion],p);
00313        if(strstr(setups[i].wname,"pari_precision")!=NULL)
00314          precision=atoi(p);
00315        if(precision<0) precision=-precision;
00316     }
00317     fputs(header,ff);
00318     fprintf(ff,"print(\"%s\")\n",startstring);
00319     check_parm();
00320     fwrite(parm,1,strlen(parm),ff);
00321     fclose(ff);
00322     call_sh("%s <%s >%s",gpcmd[gpversion],inputfname,outputfname);
00323     ff=fopen(outputfname,"r");
00324     if(ff!=NULL) {
00325        long int l;
00326        char *obuf;
00327        fseek(ff,0,SEEK_END); l=ftell(ff); fseek(ff,0,SEEK_SET);
00328        if(l<0) l=0; if(l>fsizelim) l=fsizelim;
00329        obuf=xmalloc(l+1);
00330        l=fread(obuf,1,l,ff); fclose(ff);
00331        if(l>0) obuf[l]=0; else obuf[0]=0;
00332        output(obuf); 
00333     }
00334     unlink(inputfname); unlink(outputfname);
00335 }
00336 
00337 int main(int argc,char *argv[])
00338 {
00339     char *p;
00340     int i;
00341        /* Must have at least 2 parameters. */
00342     if(argc<3) return 0;
00343     parm=getenv("ins_source");
00344        /* nothing to do if no parameter */
00345     if(parm==NULL || *parm==0) return 0;
00346     i=strlen(parm); if(i<0 || i>parmlim) {
00347        fprintf(stderr,"insplot..processor: parameter too long. \n"); exit(1);
00348     }
00349     call_gnuplot();
00350     return 0;    
00351 }
00352