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