Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
10 | reyssat | 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; |
||
3718 | reyssat | 179 | ovlstrcpy(setbuf,"set "); j=strlen("set "); |
10 | reyssat | 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;} |
||
3718 | reyssat | 183 | ovlstrcpy(setbuf+j,"\nset "); j+=strlen("\nset "); |
10 | reyssat | 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) { |
||
3718 | reyssat | 241 | ovlstrcpy(p2,numend);numend=p2; |
10 | reyssat | 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 |