Subversion Repositories wimsdev

Rev

Rev 10 | Blame | Last modification | View Log | RSS feed

  1. /*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
  2.  *
  3.  *  This program is free software; you can redistribute it and/or modify
  4.  *  it under the terms of the GNU General Public License as published by
  5.  *  the Free Software Foundation; either version 2 of the License, or
  6.  *  (at your option) any later version.
  7.  *
  8.  *  This program is distributed in the hope that it will be useful,
  9.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  *  GNU General Public License for more details.
  12.  *
  13.  *  You should have received a copy of the GNU General Public License
  14.  *  along with this program; if not, write to the Free Software
  15.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  */
  17.  
  18.         /* Interface gnuplot to wims */
  19.  
  20. /*************** Customization: change values hereafter ****************/
  21.  
  22. #define tmpdir "/tmp"
  23.         /* limit of input/output file sizes */
  24. #define fsizelim 131072
  25.         /* limit of parameter string */
  26. #define parmlim 131072
  27.         /* number of versions */
  28. #define versions 2
  29.         /* gp prompt string */
  30. #define gpprompt "\n? "
  31.         /* string which defines the start of gp output
  32.          * (in order to cut gp header) */
  33. #define startstring "start line 49521845"
  34.         /* This is the good bye string of gp, signaling end of output. */
  35. #define goodbyestring "? Good bye!"
  36.  
  37. char header[]="Pi=pi\n\
  38. PI=pi\n\
  39. e=exp(1)\n\
  40. E=exp(1)\n\
  41. ln(x) = log(x)\n\
  42. ch(x) = cosh(x)\n\
  43. sh(x) = sinh(x)\n\
  44. th(x) = tanh(x)\n\
  45. arccos(x) = acos(x)\n\
  46. arcsin(x) = asin(x)\n\
  47. tg(x)     = tan(x)\n\
  48. arctan(x) = atan(x)\n\
  49. arctg(x)  = atan(x)\n\
  50. Argch(x)  = acosh(x)\n\
  51. Argsh(x)  = asinh(x)\n\
  52. Argth(x)  = atanh(x)\n\
  53. argch(x)  = acosh(x)\n\
  54. argsh(x)  = asinh(x)\n\
  55. argth(x)  = atanh(x)\n\
  56. set samples 400\n\
  57. ";
  58.  
  59. /***************** Nothing should need change hereafter *****************/
  60.  
  61. #include <stdio.h>
  62. #include <stdlib.h>
  63. #include <stdarg.h>
  64. #include <unistd.h>
  65. #include <string.h>
  66. #include <ctype.h>
  67. #include <time.h>
  68. #include <sys/time.h>
  69.  
  70. #define SETUP_NO (sizeof(setups)/sizeof(setups[0]))
  71. #define MYNAME_NO (sizeof(name2version)/sizeof(name2version[0]))
  72.  
  73.         /* gpversion=0: gp1.39; gpversion=1: gp2.0. */
  74. int gpversion, mypid, precision;
  75. char inputfname[256], outputfname[256];
  76. char *parm;
  77.  
  78. void *xmalloc(size_t n)
  79. {
  80.     void *p;
  81.     p=malloc(n);
  82.     if(p==NULL) {
  83.         fprintf(stderr, "pari: Malloc failure.");
  84.         exit(1);
  85.     }
  86.     return p;
  87. }
  88.  
  89.         /* system(), but with variable parms */
  90. int call_sh(char *s,...)
  91. {
  92.     va_list vp;
  93.     char buf[1024];
  94.    
  95.     va_start(vp,s);
  96.     vsnprintf(buf,sizeof(buf),s,vp);
  97.     va_end(vp);
  98.     return system(buf);
  99. }
  100.  
  101.         /* check for security violations in command string */
  102. void check_parm(void)
  103. {
  104.     char *p;
  105.     for(p=parm;*p!=0;p++) {
  106.           /* no espace commands. */
  107.         if(*p!='\n') continue;
  108.         while(*p!=0 && isspace(*p)) p++;
  109.         if(*p=='\\' && *(p+1)!='v') *p='.';
  110.     }
  111. }
  112.  
  113.         /* patches the gnuplot integer division (mis)feature. */
  114. void gnuplot_patch(char *p,int oneline)
  115. {
  116.     char *pp;
  117.     for(pp=strchr(p,'/');pp!=NULL;pp=strchr(pp+1,'/')) {
  118.         char *p1;
  119.         if(pp<=p || !isdigit(*(pp-1)) || !isdigit(*(pp+1))) continue;
  120.         for(p1=pp-2;p1>=p && isdigit(*p1);p1--);
  121.         if(p1>=p && *p1=='.') continue;
  122.         for(p1=pp+2;*p1 && isdigit(*p1);p1++);
  123.         if(*p1=='.') continue;
  124.         string_modify(p,p1,p1,".0");
  125.     }
  126.     for(pp=strchr(p,'^');pp!=NULL;pp=strchr(pp+1,'^'))
  127.       string_modify(p,pp,pp+1,"**");
  128.         /* disallow new lines and ';' */
  129.     if(oneline)
  130.       for(pp=p;*pp!=0;pp++) if(*pp==';' || *pp=='\n') *pp=' ';
  131. }
  132.  
  133.         /* This is to disable pipe in the gnuplot plotting function.
  134.          * We do not allow ' followed by < . */
  135. void prepare_insplot_parm(char *p)
  136. {
  137.     int i,j; char *pp, *s;
  138.     double d;
  139.     char setbuf[MAX_LINELEN+10],buf[MAX_LINELEN+1];
  140.    
  141.     j=strlen(p);
  142.       /* pipe in plot command */
  143.     for(i=0;i<j;i++) {
  144.         if(*(p+i)!='\'' && *(p+i)!='"') continue;
  145.         pp=find_word_start(p+i+1); if(*pp=='<') {
  146.             module_error("illegal_plot_cmd"); exit(1);
  147.         }
  148.     }
  149.     gnuplot_patch(p,1);
  150.         /* multiplot */
  151.     pp=getvar("insplot_split");i=evalue(pp);
  152.         /* arbitrary limit: 16 multiplots */
  153.     if(i>0 && i<=16) {
  154.         char tbuf[MAX_LINELEN+1];
  155.         snprintf(buf,sizeof(buf),"%d",i); setenv("multiplot",buf,1);
  156.         for(j=1;j<=i;j++) {
  157.             snprintf(buf,sizeof(buf),"insplot_parm_%d",j);
  158.             pp=getvar(buf);
  159.             snprintf(tbuf,sizeof(tbuf),"%s",pp);
  160.             gnuplot_patch(tbuf,1);
  161.             setenv(buf,tbuf,1);
  162.         }
  163.        
  164.     }
  165.         /* no illegal chaining */
  166.     pp=getvar("insplot_font"); if(pp!=NULL) {
  167.         for(s=pp;s<pp+MAX_LINELEN && *s;s++)
  168.           if(*s==';' || *s=='\n' || *s==' ') *s=0;
  169.         if(s>=pp+MAX_LINELEN) *s=0;
  170.         setvar("insplot_font",pp);
  171.     }
  172.     pp=getvar("insplot_set"); if(pp!=NULL) {
  173.         char tbuf[MAX_LINELEN+1];
  174.         snprintf(tbuf,sizeof(tbuf),"%s",pp);
  175.         i=strlen(tbuf)-1;
  176.         while(i>0 && isspace(tbuf[i])) i--;
  177.         if(tbuf[i]==';') tbuf[i]=0;
  178.         gnuplot_patch(tbuf,0);pp=tbuf;
  179.         ovlstrcpy(setbuf,"set "); j=strlen("set ");
  180.         for(i=0; *(pp+i)!=0 && j<MAX_LINELEN; i++) {
  181.             if(*(pp+i)=='\n') {setbuf[j++]=' '; continue;}
  182.             if(*(pp+i)!=';') {setbuf[j++]=*(pp+i); continue;}
  183.             ovlstrcpy(setbuf+j,"\nset "); j+=strlen("\nset ");
  184.         }
  185.         setbuf[j]=0;
  186.         setenv("insplot_set",setbuf,1);
  187.     }
  188.     else setenv("insplot_set","",1);
  189.       /* frames of animation */
  190.     pp=getvar("ins_anim_frames");
  191.     if(pp!=NULL) i=evalue(pp); else i=1;
  192.     if(i>=INS_LIMIT) i=INS_LIMIT-1; if(i<1) i=1;
  193.     if(strstr(setbuf,"step")==NULL && strstr(p,"step")==NULL
  194.        && varchr(setbuf,"s")==NULL && varchr(p,"s")==NULL) i=1;
  195.     snprintf(buf,sizeof(buf),"%d",i);
  196.     setenv("ins_anim_frames",buf,1);
  197.     setvar("ins_anim_frames","");
  198.       /* delay of animation */
  199.     pp=getvar("ins_anim_delay");
  200.     if(pp!=NULL) d=evalue(pp); else d=0;
  201.     if(d>=10) d=10; if(d<0) d=0;
  202.     i=d*100;
  203.     snprintf(buf,sizeof(buf),"%d",i);
  204.     setenv("ins_anim_delay",buf,1);
  205. }
  206.  
  207.         /* strip trailing zeros */
  208. void strip_zeros(char *p)
  209. {
  210.     char *pp, *p2, *numend, *ee;
  211.     int i;
  212.     for(pp=p;*pp!=0;pp++) {
  213.         if(!isdigit(*pp)) continue;
  214.         i=0;
  215.         for(numend=pp;isdigit(*numend) || *numend=='.';numend++)
  216.           if(*numend=='.') i=1;
  217.         if(i==0) {
  218.             pp=numend-1;continue;
  219.         }
  220.         for(p2=numend;p2>pp && *(p2-1)=='0';p2--);
  221.         for(ee=numend;isspace(*ee);ee++);
  222.         if(*(pp+1)=='.' && (*ee=='E' || *ee=='e')
  223.            && *(ee+1)=='-') {
  224.             int k=0;
  225.             char *pt=ee+2;
  226.             while(isdigit(*pt)) {
  227.                 k*=10;k+=*pt-'0';pt++;
  228.             }
  229.             if(k>precision*2 || (k>precision && *pp=='0')) {
  230.                
  231.                 sprintf(pp,"0.0%s",pt);
  232.                
  233.                 pp+=strlen("0.0")-1;
  234.                 continue;
  235.             }
  236.         }
  237.        
  238.         if(*(p2-1)=='.' && p2<numend) p2++;
  239.        
  240.         if(p2<numend) {
  241.             ovlstrcpy(p2,numend);numend=p2;
  242.         }
  243.         pp=numend-1;
  244.     }
  245. }
  246.  
  247.         /* process and print gp output */
  248. void output(char *p)
  249. {
  250.     int i,n;
  251.     char *pp, *pe, *pt;
  252.     pp=strstr(p,startstring);
  253.     if(pp==NULL) return;
  254.     pp=strstr(pp,gpprompt); if(pp==NULL) return;
  255.     pe=strstr(pp,goodbyestring);
  256.     if(pe>=pp) *pe=0;
  257.     while(pp!=NULL) {
  258.         pp++;
  259.         pe=strstr(pp,gpprompt);
  260.         if(pe>=pp) *pe=0;
  261.         pp=strchr(pp,'\n');
  262.         if(pp==NULL) {
  263.             emptyline:
  264.             puts(""); pp=pe; continue;
  265.         }
  266.         pp++; n=strlen(pp);
  267.         if(n==0) goto emptyline;
  268.                 /* make every output one-line */
  269.         for(i=0;i<n;i++) {
  270.             if(*(pp+i)=='\n') {
  271.                 if(*(pp+i+1)!='%') *(pp+i)=' ';
  272.                 else {*(pp+i)=0; break;}
  273.             }
  274.         }
  275.           /* strip leading and trailing spaces */
  276.         while(isspace(*pp) && pp<pe) pp++;
  277.         pt=pp+strlen(pp)-1;
  278.         while(isspace(*pt) && pt>pp) pt--;
  279.           /* remove parentheses of matrix output */
  280.         if(memcmp(pp,"Mat(",4)==0 && *pt==')') {
  281.             *(pt--)=0; pp+=4;
  282.         }
  283.         if(*pp=='[' && *pt==']') {
  284.             *(pt--)=0; pp++;
  285.         }
  286.         strip_zeros(pp);
  287.         puts(pp); pp=pe;
  288.     }
  289. }
  290.  
  291. void call_gnuplot(void)
  292. {
  293.     int i,r;
  294.     char *p;
  295.     FILE *ff;
  296.     struct timeval t;
  297.    
  298.     setenv(gprcenv,gprc[gpversion],1);
  299.     mypid=getpid();
  300.     snprintf(inputfname,sizeof(inputfname),"%s/gp_input.%d",tmpdir,mypid);
  301.     snprintf(outputfname,sizeof(outputfname),"%s/gp_output.%d",tmpdir,mypid);
  302.     ff=fopen(inputfname,"w");
  303.     if(ff==NULL) {
  304.         fprintf(stderr,"insplot: cannot open file %s.\n",inputfname); exit(1);
  305.     }
  306.     gettimeofday(&t,NULL);
  307.     r=t.tv_usec*t.tv_sec;
  308.     fprintf(ff,"\nsetrand(%d)\n",r);
  309.     for(i=0;i<SETUP_NO;i++) {
  310.         p=getenv(setups[i].wname);
  311.         if(p==NULL || *p==0) p=setups[i].defaultval;
  312.         fprintf(ff,"%s%s\n",setups[i].gpset[gpversion],p);
  313.         if(strstr(setups[i].wname,"pari_precision")!=NULL)
  314.           precision=atoi(p);
  315.         if(precision<0) precision=-precision;
  316.     }
  317.     fputs(header,ff);
  318.     fprintf(ff,"print(\"%s\")\n",startstring);
  319.     check_parm();
  320.     fwrite(parm,1,strlen(parm),ff);
  321.     fclose(ff);
  322.     call_sh("%s <%s >%s",gpcmd[gpversion],inputfname,outputfname);
  323.     ff=fopen(outputfname,"r");
  324.     if(ff!=NULL) {
  325.         long int l;
  326.         char *obuf;
  327.         fseek(ff,0,SEEK_END); l=ftell(ff); fseek(ff,0,SEEK_SET);
  328.         if(l<0) l=0; if(l>fsizelim) l=fsizelim;
  329.         obuf=xmalloc(l+1);
  330.         l=fread(obuf,1,l,ff); fclose(ff);
  331.         if(l>0) obuf[l]=0; else obuf[0]=0;
  332.         output(obuf);  
  333.     }
  334.     unlink(inputfname); unlink(outputfname);
  335. }
  336.  
  337. int main(int argc,char *argv[])
  338. {
  339.     char *p;
  340.     int i;
  341.         /* Must have at least 2 parameters. */
  342.     if(argc<3) return 0;
  343.     parm=getenv("ins_source");
  344.         /* nothing to do if no parameter */
  345.     if(parm==NULL || *parm==0) return 0;
  346.     i=strlen(parm); if(i<0 || i>parmlim) {
  347.         fprintf(stderr,"insplot..processor: parameter too long. \n"); exit(1);
  348.     }
  349.     call_gnuplot();
  350.     return 0;    
  351. }
  352.  
  353.