1 /* Copyright (C) 1988-2005 by Brian Doty and the Institute
2 of Global Environment and Society (IGES).
3
4 See file COPYRIGHT for more information. */
5
6 /* Authored by B. Doty */
7
8 /*
9 * Include ./configure's header file
10 */
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include <stdio.h>
16 #include <math.h>
17 #include "grads.h"
18
19 static char pout[256]; /* Build error msgs here */
20 static int pass=0; /* Internal pass number */
21
22 /* Debugging routine to print the current stack */
23
24 /*
25 void stkdmp (struct smem *, int);
26
27 void stkdmp (struct smem *stack, int curr) {
28 struct gagrid *pgr;
29 int i;
30
31 printf ("Stack: %i\n",curr);
32 for (i=0;i<=curr;i++) {
33 printf ("->");
34 if (stack[i].type==0) {
35 pgr = stack[i].obj.pgr;
36 printf (" Grid %g \n",*pgr->grid);
37 } else if (stack[i].type==1) {
38 printf (" Oper %i \n",stack[i].obj.op);
39 } else if (stack[i].type==2) {
40 printf (" Right Paren \n");
41 } else if (stack[i].type==3) {
42 printf (" Left Paren \n");
43 } else printf (" Unknown %i \n",stack[i].type);
44 }
45 }
46 */
47
48 /* Evaluate a GrADS expression. The expression must have
49 blanks removed. The expression is evaluated with respect
50 to the environment defined in the status block (pst).
51 This routine is invoked recursively from functions in order
52 to evaluate sub-expressions. */
53
gaexpr(char * expr,struct gastat * pst)54 int gaexpr (char *expr, struct gastat *pst) {
55 struct gagrid *pgr;
56 struct gastn *stn;
57 struct smem *stack;
58 char *ptr, *pos;
59 float val;
60 int cmdlen,i,j,rc,curr;
61 int state,cont,err;
62 int size;
63
64 if (gaqsig()) return(1);
65 pass++;
66
67 cmdlen = strlen(expr);
68 size = cmdlen * ( 7 + sizeof(struct smem) );
69 stack = (struct smem *)malloc(size);
70 if (stack==NULL) {
71 gaprnt (0,"Memory Allocation Error: parser stack\n");
72 return (1);
73 }
74
75 state=1;
76 curr = -1;
77 pos = expr;
78
79 cont=1; err=0;
80 while (cont) { /* Loop while parsing exprssn */
81
82 if (state) { /* Expect operand or '(' */
83
84 if (*pos=='(') { /* Handle left paren */
85 curr++;
86 stack[curr].type = 2;
87 pos++;
88 }
89
90 else if (*pos=='-') { /* Handle unary '-' operator */
91 curr++;
92 stack[curr].type = -1;
93 stack[curr].obj.pgr = gagrvl(-1.0);
94 curr++;
95 stack[curr].type=1; stack[curr].obj.op = 0;
96 pos++;
97 }
98
99 else if (*pos>='0' && *pos<='9') { /* Handle numeric value */
100 if ((ptr=valprs(pos,&val))==NULL) {
101 cont=0; err=1;
102 i = 1 + pos - expr;
103 gaprnt (0,"Syntax Error: Invalid numeric value\n");
104 } else {
105 curr++;
106 stack[curr].type = -1;
107 stack[curr].obj.pgr = gagrvl(val);
108 /* stkdmp(stack,curr); */
109 rc = eval(0, stack, &curr);
110 if (rc) {
111 err=1; cont=0;
112 }
113 state = 0;
114 pos=ptr;
115 }
116 }
117
118 else if (*pos>='a' && *pos<='z') { /* Handle variable */
119 if ((ptr=varprs(pos, pst))==NULL) {
120 cont=0; err=1;
121 } else {
122 curr++;
123 if (pst->type) {
124 stack[curr].type = -1;
125 stack[curr].obj.pgr = pst->result.pgr;
126 } else {
127 stack[curr].type = -2;
128 stack[curr].obj.stn = pst->result.stn;
129 }
130 /* stkdmp(stack,curr); */
131 rc = eval(0, stack, &curr);
132 if (rc) {
133 err=1; cont=0;
134 }
135 state = 0;
136 pos=ptr;
137 }
138 }
139
140 else {
141 cont=0; err=1;
142 gaprnt (0,"Syntax Error: Expected operand or '('\n");
143 }
144
145 } else { /* Expect operator or ')' */
146
147 if (*pos==')') { /* Handle right paren */
148 curr++;
149 stack[curr].type = 3;
150 pos++;
151 rc = eval(0, stack, &curr); /* Process stack */
152 if (rc) {
153 err=1; cont=0;
154 pos--;
155 }
156 }
157
158 /* Handle operator */
159
160 else if ( (*pos=='*')||(*pos=='/')||(*pos=='+')||(*pos=='-') ) {
161 curr++;
162 stack[curr].type=1;
163 if (*pos=='*') stack[curr].obj.op=0;
164 if (*pos=='/') stack[curr].obj.op=1;
165 if (*pos=='+') stack[curr].obj.op=2;
166 if (*pos=='-') {
167 stack[curr].obj.op=2;
168 curr++;
169 stack[curr].type = -1;
170 stack[curr].obj.pgr = gagrvl(-1.0);
171 curr++;
172 stack[curr].type=1; stack[curr].obj.op = 0;
173 }
174 /* stkdmp(stack,curr); */
175 pos++;
176 state=1;
177 }
178
179 else {
180 gaprnt (0,"Syntax Error: Expected operator or ')'\n");
181 cont=0; err=1;
182 }
183 }
184 if (*pos=='\0'||*pos=='\n') cont=0;
185 }
186
187 if (!err) {
188 rc = eval(1, stack, &curr);
189 /* stkdmp(stack,curr); */
190 if (rc) {
191 err=1;
192 } else {
193 if (curr==0) {
194 if (stack[0].type == -1) {
195 pst->type = 1;
196 pst->result.pgr = stack[0].obj.pgr;
197 } else if (stack[0].type == -2) {
198 pst->type = 0;
199 pst->result.stn = stack[0].obj.stn;
200 } else {
201 gaprnt (0,"GAEXPR Logic Error Number 29\n");
202 err=1;
203 }
204 }
205 else {
206 gaprnt (0,"Syntax Error: Unmatched Parens\n");
207 err=1;
208 }
209 }
210 }
211
212 if (err) {
213 if (pass==1) {
214 i = 1 + pos - expr;
215 sprintf (pout," Error ocurred at column %i\n",i);
216 gaprnt (0,pout);
217 }
218
219 /* free any memory still hung off the stack */
220
221 for (i=0; i<curr; i++) {
222 if (stack[i].type==-1) {
223 pgr = stack[i].obj.pgr;
224 gagfre(pgr);
225 } else if (stack[i].type==-2) {
226 stn = stack[i].obj.stn;
227 for (j=0; j<BLKNUM; j++) {
228 if (stn->blks[j] != NULL) free (stn->blks[j]);
229 }
230 free (stn);
231 }
232 }
233 }
234
235 free (stack);
236 pass--;
237 return (err);
238 }
239
240
241 /* Evaluate the stack. If the state is zero, then don't go
242 past an addition operation unless enclosed in parens.
243 If state is one, then do all operations to get the result.
244 If we hit an error, set up the stack pointer to insure
245 everything gets freed properly. */
246
eval(int state,struct smem * stack,int * cpos)247 int eval (int state, struct smem *stack, int *cpos) {
248 int cont,op,pflag,err,rc;
249 int curr,curr1,curr2;
250
251 curr = *cpos;
252 err = 0;
253 cont = 1;
254 pflag = 0;
255 while (curr>0 && cont) {
256
257 /* Handle an operand in the stack. An operand is preceded by
258 either a left paren, or an operator. We will do an operation
259 if it is * or /, or if it is enclosed in parens, or if we
260 have hit the end of the expression. */
261
262 if (stack[curr].type<0) { /* Operand? */
263 curr2 = curr; /* Remember operand */
264 curr--; /* Look at prior item */
265 if (stack[curr].type==2) { /* Left paren? */
266 if (pflag) { /* Was there a matching right?*/
267 stack[curr].type = stack[curr2].type; /* Yes, restack oprnd*/
268 stack[curr].obj = stack[curr2].obj;
269 pflag=0; /* Have evaluated parens */
270 } else { /* If not, */
271 cont = 0; /* stop here, */
272 curr++; /* leaving operand on stack */
273 }
274 } else if (stack[curr].type==1) { /* Prior item an operator? */
275 op = stack[curr].obj.op; /* Remember operator */
276 curr--; /* Get other operand */
277 if (stack[curr].type>0) { /* Better be an operand */
278 cont = 0; /* If not then an error */
279 err = 1;
280 gaprnt (0,"Internal logic check 12 \n");
281 } else { /* Is an operand... */
282 curr1 = curr; /* Get the operand */
283 if ( op<2 || pflag || state ) { /* Operate? */
284 rc = gaoper(stack,curr1,curr2,curr,op); /* Yes... */
285 if (rc) { /* Did we get an error? */
286 cont = 0; err = 1; /* Yes... don't continue */
287 curr+=2; /* Leave ptr so can free ops */
288 }
289 } else { /* Don't operate... */
290 curr+=2; /* Leave stuff stacked */
291 cont = 0; /* Won't continue */
292 }
293 }
294 } else { /* Prior item invalid */
295 gaprnt (0,"Internal logic check 14 \n");
296 cont = 0; err = 1;
297 }
298
299 } else if (stack[curr].type==3) { /* Current item right paren? */
300 pflag=1; /* Indicate we found paren */
301 curr--; /* Unstack it */
302
303 } else { cont=0; err=1; } /* Invalid if not op or paren */
304 }
305 *cpos = curr;
306 return (err);
307 }
308
309 /* Perform an operation on two data objects. Determine what class
310 of data we are working with and call the appropriate routine */
311
gaoper(struct smem * stack,int c1,int c2,int c,int op)312 int gaoper (struct smem *stack, int c1, int c2, int c, int op) {
313 struct gagrid *pgr;
314 struct gastn *stn;
315
316 /* If both grids, do grid-grid operation */
317
318 if (stack[c1].type==-1 && stack[c2].type==-1) {
319 pgr = gagrop(stack[c1].obj.pgr, stack[c2].obj.pgr, op, 1);
320 if (pgr==NULL) return (1);
321 stack[c].type = -1;
322 stack[c].obj.pgr = pgr;
323 return (0);
324 }
325
326 /* If both stns, do stn-stn operation */
327
328 if (stack[c1].type==-2 && stack[c2].type==-2) {
329 stn = gastop(stack[c1].obj.stn, stack[c2].obj.stn, op, 1);
330 if (stn==NULL) return (1);
331 stack[c].type = -2;
332 stack[c].obj.stn = stn;
333 return (0);
334 }
335
336 /* Operation between grid and stn is invalid -- unless the grid
337 is really a constant. Check for this. */
338
339 if (stack[c1].type == -1) pgr=stack[c1].obj.pgr;
340 if (stack[c2].type == -1) pgr=stack[c2].obj.pgr;
341 if (pgr->idim == -1 && pgr->jdim == -1) {
342 if (stack[c1].type == -2) {
343 stn = gascop (stack[c1].obj.stn, pgr->rmin, op, 0);
344 } else {
345 stn = gascop (stack[c2].obj.stn, pgr->rmin, op, 1);
346 }
347 if (stn==NULL) return (1);
348 gagfre (pgr);
349 stack[c].type = -2;
350 stack[c].obj.stn = stn;
351 } else {
352 gaprnt (0,"Operation Error: Incompatable Data Types\n");
353 gaprnt (0," One operand was stn data, other was grid\n");
354 return (1);
355 }
356 return (0);
357 }
358
359 /* Perform the operation between two grid data objects.
360 Varying dimensions must match. Grids with fewer varying dimensions
361 are 'expanded' to match the larger grid as needed. */
362
gagrop(struct gagrid * pgr1,struct gagrid * pgr2,int op,int rel)363 struct gagrid *gagrop (struct gagrid *pgr1, struct gagrid *pgr2,
364 int op, int rel) {
365
366 float *val1, *val2;
367 int dnum1,dnum2;
368 struct gagrid *pgr;
369 int incr,imax,omax;
370 int i,i1,i2,swap;
371
372 /* Figure out how many varying dimensions for each grid. */
373
374 val1 = pgr1->grid;
375 dnum1 = 0;
376 if (pgr1->idim > -1) dnum1++;
377 if (pgr1->jdim > -1) dnum1++;
378
379 val2 = pgr2->grid;
380 dnum2 = 0;
381 if (pgr2->idim > -1) dnum2++;
382 if (pgr2->jdim > -1) dnum2++;
383
384 /* Force operand 1 (pgr1, dnum1, etc.) to have fewer varying dims. */
385
386 swap = 0;
387 if (dnum2<dnum1) {
388 pgr = pgr1;
389 pgr1 = pgr2;
390 pgr2 = pgr;
391 val1 = pgr1->grid;
392 val2 = pgr2->grid;
393 swap = 1;
394 i = dnum1; dnum1 = dnum2; dnum2 = i;
395 }
396
397 /* Check the validity of the operation (same dimensions varying;
398 same absolute dimension ranges. First do the case where there
399 are the same number of dimensions varying (dnum1=dnum2=0,1,2). */
400
401 if (dnum1==dnum2) {
402 if (pgr1->idim != pgr2->idim || pgr1->jdim!=pgr2->jdim) goto err1;
403 i = pgr1->idim;
404 if (dnum1>0 && gagchk(pgr1,pgr2,pgr1->idim)) goto err2;
405 i = pgr1->jdim;
406 if (dnum1>1 && gagchk(pgr1,pgr2,pgr1->jdim)) goto err2;
407 incr = 0;
408 imax = pgr1->isiz * pgr1->jsiz;
409
410 /* Case where dnum1=0, dnum2=1 or 2. */
411
412 } else if (dnum1==0) {
413 incr = pgr2->isiz * pgr2->jsiz;
414 imax = 1;
415
416 /* Case where dnum1=1, dnum2=2. */
417
418 } else {
419 i = pgr1->idim;
420 if (gagchk(pgr1,pgr2,pgr1->idim)) goto err2;
421 if (pgr1->idim==pgr2->idim) {
422 incr = 0;
423 imax = pgr1->isiz;
424 } else if (pgr1->idim==pgr2->jdim) {
425 incr = pgr2->isiz;
426 imax = pgr1->isiz;
427 } else goto err1;
428 }
429 omax = pgr2->isiz * pgr2->jsiz;
430
431 /* Perform the operation. Put the result in operand 2 (which is
432 always the operand with the greater number of varying
433 dimensions). The smaller grid is 'expanded' by using incrementing
434 variables which will cause the values in the smaller grid to be
435 used multiple times as needed. */
436
437 i1 = 0; i2 = 0;
438 for (i=0; i<omax; i++) {
439 if (*val1==pgr1->undef || *val2==pgr2->undef) *val2=pgr2->undef;
440 else {
441 if (op==2) *val2 = *val1 + *val2;
442 else if (op==0) *val2 = *val1 * *val2;
443 else if (op==1) {
444 if (swap) {
445 if (*val1==0.0) *val2 = pgr2->undef;
446 else *val2 = *val2 / *val1;
447 } else {
448 if (*val2==0.0) *val2 = pgr2->undef;
449 else *val2 = *val1 / *val2;
450 }
451 } else if (op==10) {
452 if (swap) *val2 = pow(*val2,*val1);
453 else *val2 = pow(*val1,*val2);
454 } else if (op==11) *val2 = hypot(*val1,*val2);
455 else if (op==12) {
456 if (*val1==0.0 && *val2==0.0) *val2 = 0.0;
457 else {
458 if (swap) *val2 = atan2(*val2,*val1);
459 else *val2 = atan2(*val1,*val2);
460 }
461 } else if (op==13) {
462 if (swap) {
463 if (*val1<0.0) *val2 = pgr2->undef;
464 } else {
465 if (*val2<0.0) *val2 = pgr2->undef;
466 else *val2 = *val1;
467 }
468 }
469 else {
470 gaprnt (0,"Internal logic check 17: invalid oper value\n");
471 return (NULL);
472 }
473 }
474 val2++; i2++;
475 if (i2>=incr) {i2=0; val1++; i1++;} /* Special increment for*/
476 if (i1>=imax) {i1=0; val1=pgr1->grid;} /* the smaller grid */
477 }
478
479 /* If requested, release the storage for operand 1 (which does not
480 contain the result). Note that this refers to operand 1 AFTER
481 the possible grid swap earlier in the routine. */
482
483 if (rel) {
484 gagfre(pgr1);
485 }
486
487 return (pgr2);
488
489 err1:
490 gaprnt (0,"Operation error: Incompatable grids \n");
491 gaprnt (1," Varying dimensions are different\n");
492 sprintf (pout," 1st grid dims = %i %i 2nd = %i %i \n",
493 pgr1->idim, pgr2->idim, pgr1->jdim, pgr2->jdim);
494 gaprnt (2,pout);
495 return (NULL);
496
497 err2:
498 gaprnt (0,"Operation error: Incompatable grids \n");
499 gaprnt (1," Dimension ranges aren't equivalent\n");
500 sprintf (pout," Dimension = %i\n",i);
501 gaprnt (2, pout);
502 sprintf (pout," 1st grid range = %i %i 2nd = %i %i \n",
503 pgr1->dimmin[i],pgr1->dimmax[i],
504 pgr2->dimmin[i],pgr2->dimmax[i]);
505 gaprnt (2,pout);
506 return (NULL);
507 }
508
509
510 /* Perform operation on two stn data items. The operation is done
511 only when the varying dimensions are equal. Currently, only
512 three station data dimension environments are supported:
513 X,Y varying (X,Y plot), T varying (time series), and Z
514 varying (vertical profile). This routine will probably need to
515 be rewritten at some point. */
516
gastop(struct gastn * stn1,struct gastn * stn2,int op,int rel)517 struct gastn *gastop (struct gastn *stn1, struct gastn *stn2,
518 int op, int rel) {
519 struct gastn *stn;
520 struct garpt *rpt1,*rpt2;
521 int swap,i,j,flag,dimtyp;
522
523 /* Verify dimension environment */
524
525 if (stn1->idim==0 && stn1->jdim==1 && stn2->idim==0 &&
526 stn2->jdim==1) dimtyp = 1;
527 else if (stn1->idim==2 && stn1->jdim==-1 && stn2->idim==2 &&
528 stn2->jdim==-1) dimtyp = 2;
529 else if (stn1->idim==3 && stn1->jdim==-1 && stn2->idim==3 &&
530 stn2->jdim==-1) dimtyp = 3;
531 else {
532 gaprnt (0,"Invalid dimension environment for station data");
533 gaprnt (0," operation\n");
534 return (NULL);
535 }
536
537 /* Set it up so first stn set has fewer stations */
538
539 swap=0;
540 if (stn1->rnum > stn2->rnum) {
541 stn=stn1;
542 stn1=stn2;
543 stn2=stn;
544 swap=1;
545 }
546
547 /* Loop through stations of 1st station set. Find matching
548 stations in 2nd station set. If a match, perform operation.
549 Any duplicates in the 2nd station set get ignored. */
550
551 rpt1 = stn1->rpt;
552 for (i=0; i<stn1->rnum; i++,rpt1=rpt1->rpt) {
553 if (rpt1->val == stn1->undef) continue;
554 flag = 0;
555 rpt2 = stn2->rpt;
556 for (j=0; j<stn2->rnum; j++,rpt2=rpt2->rpt) {
557 if (rpt2->val == stn2->undef) continue;
558 if (dimtyp==1 && rpt1->lat != rpt2->lat) continue;
559 if (dimtyp==1 && rpt1->lon != rpt2->lon) continue;
560 if (dimtyp==2 && rpt1->lev != rpt2->lev) continue;
561 if (dimtyp==3 && rpt1->tim != rpt2->tim) continue;
562 if (op==2) rpt1->val = rpt1->val + rpt2->val;
563 else if (op==0) rpt1->val = rpt1->val * rpt2->val;
564 else if (op==1) {
565 if (swap) {
566 if (rpt1->val==0.0) rpt1->val = stn1->undef;
567 else rpt1->val = rpt2->val / rpt1->val;
568 } else {
569 if (rpt2->val==0.0) rpt1->val = stn1->undef;
570 else rpt1->val = rpt1->val / rpt2->val;
571 }
572 } else if (op==10) {
573 if (swap) rpt1->val = pow(rpt2->val,rpt1->val);
574 else rpt1->val = pow(rpt1->val,rpt2->val);
575 } else if (op==11) rpt1->val = hypot(rpt1->val,rpt2->val);
576 else if (op==12) {
577 if (rpt1->val==0.0 && rpt2->val==0.0) rpt1->val = 0.0;
578 else rpt1->val = atan2(rpt1->val,rpt2->val);
579 } else if (op==13) {
580 if (swap) {
581 if (rpt1->val<0.0) rpt1->val = stn1->undef;
582 /*** bug fixed by Y.Tahara ***/
583 else rpt1->val = rpt2->val;
584 /*****************************/
585 } else {
586 if (rpt2->val<0.0) rpt1->val = stn1->undef;
587 }
588 }
589 else {
590 gaprnt (0,"Internal logic check 57: invalid oper value\n");
591 return (NULL);
592 }
593 flag=1;
594 break;
595 }
596 if (!flag) rpt1->val = stn1->undef;
597 }
598
599 /* Release storage if requested then return */
600
601 if (rel) {
602 for (i=0; i<BLKNUM; i++) {
603 if (stn2->blks[i] != NULL) free (stn2->blks[i]);
604 }
605 free (stn2);
606 }
607 return (stn1);
608 }
609
610 /* Perform operation between a stn set and a constant */
611
gascop(struct gastn * stn,float val,int op,int swap)612 struct gastn *gascop (struct gastn *stn, float val, int op, int swap) {
613 struct garpt *rpt;
614 int i;
615
616 /* Loop through stations. Perform operation. */
617
618 rpt = stn->rpt;
619 for (i=0; i<stn->rnum; i++,rpt=rpt->rpt) {
620 if (rpt->val == stn->undef) continue;
621 if (op==2) rpt->val = rpt->val + val;
622 else if (op==0) rpt->val = rpt->val * val;
623 else if (op==1) {
624 if (swap) {
625 if (rpt->val==0.0) rpt->val = stn->undef;
626 else rpt->val = val / rpt->val;
627 } else {
628 if (val==0.0) rpt->val = stn->undef;
629 else rpt->val = rpt->val / val;
630 }
631 } else if (op==10) {
632 if (swap) rpt->val = pow(val,rpt->val);
633 else rpt->val = pow(rpt->val,val);
634 } else if (op==11) rpt->val = hypot(rpt->val,val);
635 else if (op==12) {
636 if (rpt->val==0.0 && val==0.0) rpt->val = 0.0;
637 else {
638 if (swap) rpt->val = atan2(val,rpt->val);
639 else rpt->val = atan2(rpt->val,val);
640 }
641 } else if (op==13) {
642 if (rpt->val<0.0) rpt->val = stn->undef;
643 }
644 else {
645 gaprnt (0,"Internal logic check 57: invalid oper value\n");
646 return (NULL);
647 }
648 }
649 return (stn);
650 }
651
652 /* Put a constant value into a grid. We will change this at
653 some point to have three data types (grid, stn, constant) but
654 for now it is easier to keep the constant grid concept. */
655
gagrvl(float val)656 struct gagrid *gagrvl (float val) {
657 struct gagrid *pgr;
658 int i;
659 int size;
660
661 size = sizeof(struct gagrid);
662 pgr = (struct gagrid *)malloc(size);
663
664 if (pgr==NULL) {
665 gaprnt (0,"Unable to allocate memory for grid structure \n");
666 return (NULL);
667 }
668
669 /* Fill in gagrid variables */
670
671 pgr->pfile = NULL;
672 pgr->undef = -9.99E33;
673 pgr->pvar = NULL;
674 pgr->idim = -1;
675 pgr->jdim = -1;
676 pgr->alocf = 0;
677 for (i=0;i<4;i++) {
678 pgr->dimmin[i]=0;
679 pgr->dimmax[i]=0;
680 }
681 pgr->rmin = val;
682 pgr->rmax = val;
683 pgr->grid = &pgr->rmin;
684 pgr->isiz = 1;
685 pgr->jsiz = 1;
686 pgr->exprsn = NULL;
687 return (pgr);
688 }
689
690 /* Handle a variable or function call. If successful, we return
691 a data object (pointed to by the pst) and a ptr to the first
692 character after the variable or function name. If an error
693 happens, we return a NULL pointer. */
694
varprs(char * ch,struct gastat * pst)695 char *varprs (char *ch, struct gastat *pst) {
696 struct gagrid *pgr,*pgr2;
697 char name[20], vnam[20], cc, *pos;
698 int i,fnum,ii,jj,dval,rc,dotflg,idim,jdim,dim,sbu;
699 int id[4];
700 float dmin[4],dmax[4],d1,d2;
701 int gmin[4],gmax[4];
702 struct gafile *pfi;
703 struct gavar *pvar, *pvar2, vfake;
704 float (*conv) (float *, float);
705 float *cvals,*r,*r2,lonr,rlon,dir,spd,wrot,a,b;
706 int size,j,dotest;
707
708 /* Get the variable or function name. It must start with a
709 letter, and consist of letters or numbers or underscore. */
710
711 i=0;
712 while ( (*ch>='a' && *ch<='z') || (*ch>='0' && *ch<='9' ) || (*ch == '_') ) {
713 name[i] = *ch;
714 vnam[i] = *ch;
715 ch++; i++;
716 if (i>16) break;
717 }
718 name[i] = '\0';
719 vnam[i] = '\0'; /* Save 'i' for next loop */
720
721 /* Check for the data set number in the variable name. If there,
722 then this has to be a variable name. */
723
724 fnum = pst->fnum;
725 dotflg=0;
726 if (*ch == '.') {
727 dotflg=1;
728 ch++;
729 pos = intprs(ch,&fnum);
730 if (pos==NULL || fnum<1) {
731 sprintf (pout,"Syntax error: Bad file number for variable %s \n",
732 name);
733 gaprnt (0,pout);
734 return (NULL);
735 }
736 vnam[i] = '.';
737 i++;
738 while (ch<pos) {
739 vnam[i] = *ch;
740 ch++; i++;
741 }
742 vnam[i] = '\0';
743 }
744
745 /* Check for a predefined data object. */
746
747 pfi = NULL;
748 pvar = NULL;
749 if (!dotflg) pfi = getdfn(name,pst);
750
751 /* If not a defined grid, get a pointer to a file structure */
752
753 if (pfi==NULL) {
754 if (!dotflg) pfi = pst->pfid;
755 else {
756 pfi = pst->pfi1;
757 for (i=1; i<fnum && pfi!=NULL; i++) pfi = pfi->pforw;
758 if (pfi==NULL) {
759 gaprnt (0,"Data Request Error: File number out of range \n");
760 sprintf (pout," Variable = %s \n",vnam);
761 gaprnt (0,pout);
762 return (NULL);
763 }
764 }
765
766 /* Check here for predefined variable name: lat,lon,lev */
767
768 if ( cmpwrd(name,"lat") ||
769 cmpwrd(name,"lon") ||
770 cmpwrd(name,"lev") ) {
771 pvar = &vfake;
772 vfake.levels = -999;
773 if (cmpwrd(name,"lon")) vfake.offset = 0;
774 if (cmpwrd(name,"lat")) vfake.offset = 1;
775 if (cmpwrd(name,"lev")) vfake.offset = 2;
776 if (pfi->type==2 || pfi->type==3) {
777 sprintf (pout,"Data Request Error: Predefined variable %s\n",
778 vnam);
779 gaprnt (0,pout);
780 gaprnt (0," is only defined for grid type files\n");
781 sprintf (pout," File %i is a station file\n",fnum);
782 gaprnt (0,pout);
783 return (NULL);
784 }
785 } else {
786
787 /* See if this is a variable name. If not, either give an error
788 message (if a file number was specified) or check for a function
789 call via rtnprs. */
790
791 pvar = pfi->pvar1;
792 for (i=0; (i<pfi->vnum)&&(!cmpwrd(name,pvar->abbrv)); i++) pvar++;
793 if (i>=pfi->vnum) {
794 if (dotflg) {
795 gaprnt (0,"Data Request Error: Invalid variable name \n");
796 sprintf (pout," Variable '%s' not found in file %i\n",vnam,fnum);
797 gaprnt (0,pout);
798 return (NULL);
799 } else {
800 ch = rtnprs(ch,name,pst); /* Handle function call */
801 return (ch);
802 }
803 }
804 }
805 }
806
807 /* It wasn't a function call (or we would have returned).
808 If the variable is to a stn type file, call the parser
809 routine that handles stn requests. */
810
811 if (pfi->type==2 || pfi->type==3) {
812 ch = stnvar (ch, vnam, pfi, pvar, pst);
813 return (ch);
814 }
815
816 /* We are dealing with a grid data request. We handle this inline.
817 Our default dimension limits are defined in gastat. These
818 may be modified by the user (by specifying the new settings
819 in parens). First get grid coordinates of the limits, then
820 figure out if user modifies these. */
821
822 /* Convert world coordinates in the status block to grid
823 dimensions using the file scaling for this variable. */
824
825 for (i=0;i<3;i++) {
826 conv = pfi->ab2gr[i];
827 cvals = pfi->abvals[i];
828 dmin[i] = conv(cvals,pst->dmin[i]);
829 dmax[i] = conv(cvals,pst->dmax[i]);
830 }
831 dmin[3] = t2gr(pfi->abvals[3],&(pst->tmin));
832 dmax[3] = t2gr(pfi->abvals[3],&(pst->tmax));
833
834 /* Round varying dimensions 'outwards' to integral grid
835 units. */
836
837 for (i=0;i<4;i++) {
838 if (i==pst->idim || i==pst->jdim) {
839 dmin[i] = floor(dmin[i]+0.0001);
840 dmax[i] = ceil(dmax[i]-0.0001);
841 if (dmax[i]<=dmin[i]) {
842 gaprnt (0,"Data Request Error: Invalid grid coordinates\n");
843 sprintf (pout," Varying dimension %i decreases: %g to %g \n",
844 i,dmin[i],dmax[i]);
845 gaprnt (0,pout);
846 sprintf (pout," Error ocurred getting variable '%s'\n",vnam);
847 gaprnt (0,pout);
848 return (NULL);
849 }
850 }
851 }
852
853 /* Check for user provided dimension expressions */
854
855 if (*ch=='(') {
856 ch++;
857 for (i=0;i<4;i++) id[i] = 0;
858 while (*ch!=')') {
859 pos = dimprs(ch, pst, pfi, &dim, &d1, 1, &rc);
860 if (pos==NULL) {
861 sprintf (pout," Variable name = %s\n",vnam);
862 gaprnt (0,pout);
863 return (NULL);
864 }
865 if (id[dim]) {
866 gaprnt (0,"Syntax Error: Invalid dimension expression\n");
867 gaprnt (0," Same dimension specified multiple times ");
868 sprintf (pout,"for variable = %s\n",vnam);
869 gaprnt (0,pout);
870 return (NULL);
871 }
872 id[dim] = 1;
873 if ( dim==pst->idim || dim==pst->jdim) {
874 gaprnt (0,"Data Request Error: Invalid dimension expression\n");
875 gaprnt (0," Attempt to set or modify varying dimension\n");
876 sprintf (pout," Variable = %s, Dimension = %i \n",vnam,dim);
877 gaprnt (0,pout);
878 return (NULL);
879 }
880 dmin[dim] = d1;
881 dmax[dim] = d1;
882 ch = pos;
883 if (*ch == ',') ch++;
884 }
885 ch++;
886 }
887
888 /* If request from a defined grid, ignore fixed dimensions
889 in the defined grid */
890
891
892 if (pfi->type==4) {
893 for (i=0; i<4; i++) {
894 if (pfi->dnum[i]==1) {
895 dmin[i] = 0.0;
896 dmax[i] = 0.0;
897 }
898 }
899 }
900
901 /* All the grid level coordinates are set. Insure they
902 are integral values, otherwise we can't do it. The varying
903 dimensions will be integral (since we forced them to be
904 earlier) so this is only relevent for fixed dimensions. */
905
906 for (i=0; i<4; i++) {
907 if (dmin[i]<0.0) ii = (int)(dmin[i]-0.1);
908 else ii = (int)(dmin[i]+0.1);
909 d1 = ii;
910 if (dmax[i]<0.0) ii = (int)(dmax[i]-0.1);
911 else ii = (int)(dmax[i]+0.1);
912 d2 = ii;
913 /*mf ---
914 ignore z test if variable has not levels
915 ---mf*/
916 dotest=1;
917 if(pvar) {
918 if(!pvar->levels && i == 2) dotest=0;
919 }
920
921 if ((fabs(dmin[i]-d1)>0.001 || fabs(dmax[i]-d2)>0.001) && dotest ) {
922 gaprnt (0,"Data Request Error: Invalid grid coordinates\n");
923 gaprnt (0," World coordinates convert to non-integer");
924 gaprnt (0," grid coordinates\n");
925 sprintf (pout," Variable = %s Dimension = %i \n",vnam,i);
926 gaprnt (0,pout);
927 return (NULL);
928 }
929 }
930
931 /* Variable has been parsed and is valid, and the ch pointer is
932 set to the first character past it. We now need to set up
933 the grid requestor block and get the grid. */
934
935 size = sizeof(struct gagrid);
936 pgr = (struct gagrid *)malloc(size);
937
938 if (pgr==NULL) {
939 gaprnt (0,"Memory Allocation Error: Grid Request Block\n");
940 return (NULL);
941 }
942
943 /* Fill in gagrid variables */
944
945 idim = pst->idim; jdim = pst->jdim;
946 pgr->alocf = 0;
947 pgr->pfile = pfi;
948 pgr->undef = pfi->undef;
949 pgr->pvar = pvar;
950 pgr->idim = idim;
951 pgr->jdim = jdim;
952 pgr->iwrld = 0; pgr->jwrld = 0;
953 for (i=0;i<4;i++) {
954 if (dmin[i]<0.0) pgr->dimmin[i] = (int)(dmin[i]-0.1);
955 else pgr->dimmin[i] = (int)(dmin[i]+0.1);
956 if (dmax[i]<0.0) pgr->dimmax[i] = (int)(dmax[i]-0.1);
957 else pgr->dimmax[i] = (int)(dmax[i]+0.1);
958 }
959 pgr->exprsn = NULL;
960 pgr->ilinr = 1;
961 pgr->jlinr = 1;
962 if (idim>-1 && idim<3) {
963 pgr->igrab = pfi->gr2ab[idim];
964 pgr->iabgr = pfi->ab2gr[idim];
965 }
966 if (jdim>-1 && jdim<3) {
967 pgr->jgrab = pfi->gr2ab[jdim];
968 pgr->jabgr = pfi->ab2gr[jdim];
969 }
970 if (idim>-1) {
971 pgr->ivals = pfi->grvals[idim];
972 pgr->iavals = pfi->abvals[idim];
973 pgr->ilinr = pfi->linear[idim];
974 }
975 if (jdim>-1) {
976 pgr->jvals = pfi->grvals[jdim];
977 pgr->javals = pfi->abvals[jdim];
978 pgr->jlinr = pfi->linear[jdim];
979 }
980 pgr->grid = NULL;
981
982 if (pfi && pvar && pfi->ppflag && pfi->ppwrot && pvar->vecpair>0) {
983 pgr2 = (struct gagrid *)malloc(sizeof(struct gagrid));
984 if (pgr2==NULL) {
985 gaprnt (0,"Memory allocation error: Data I/O \n");
986 gagfre(pgr);
987 return (NULL);
988 }
989 *pgr2 = *pgr;
990 }
991
992 /* Get grid */
993
994 rc = gaggrd (pgr);
995
996 if (rc>0) {
997 sprintf (pout,"Data Request Error: Error for variable '%s'\n", vnam);
998 gaprnt (0,pout);
999 gagfre(pgr);
1000 return (NULL);
1001 }
1002 if (rc<0) {
1003 sprintf (pout," Warning issued for variable = %s\n",vnam);
1004 gaprnt (2,pout);
1005 }
1006
1007 /* Special test for auto-interpolated data, when the
1008 data requested is U or V. User MUST indicate variable unit
1009 number in the descriptor file for auto-rotation to take place */
1010
1011 if (pfi && pvar && pfi->ppflag && pfi->ppwrot && pvar->vecpair>0) {
1012
1013 /* Find the matching vector component */
1014 if (pvar->isu) sbu=0; /* if pvar is u, then matching component should not be u */
1015 else sbu=1; /* pvar is v, so matching component should be u */
1016 pvar2 = pfi->pvar1;
1017 i = 0;
1018 while (i<pfi->vnum) {
1019 if ((pvar2->vecpair == pvar->vecpair) &&
1020 (pvar2->isu == sbu)) break;
1021 pvar2++; i++;
1022 }
1023 if (i>=pfi->vnum) { /* didn't find a match */
1024 r = pgr->grid;
1025 size = pgr->isiz*pgr->jsiz;
1026 for (i=0; i<size; i++) {*r=pgr->undef; r++;}
1027 } else {
1028 /* get the 2nd grid */
1029 pgr2->pvar = pvar2;
1030 rc = gaggrd (pgr2);
1031 if (rc>0) {
1032 sprintf (pout,"Data Request Error: Error for variable '%s'\n", vnam);
1033 gaprnt (0,pout);
1034 gagfre(pgr);
1035 gagfre(pgr2);
1036 return (NULL);
1037 }
1038 /* r is u component, r2 is v component */
1039 if (pvar2->isu) {
1040 r = pgr2->grid;
1041 r2 = pgr->grid;
1042 } else {
1043 r = pgr->grid;
1044 r2 = pgr2->grid;
1045 }
1046 ii = pgr->dimmin[0];
1047 jj = pgr->dimmin[1];
1048 for (j=0; j<pgr->jsiz; j++) {
1049 if (pgr->idim == 0) ii = pgr->dimmin[0];
1050 if (pgr->idim == 1) jj = pgr->dimmin[1];
1051 for (i=0; i<pgr->isiz; i++) {
1052 if (*r==pgr->undef || *r2==pgr->undef) { /* u or v is undefined */
1053 *r = pgr->undef;
1054 *r2 = pgr->undef;
1055 } else {
1056 if (ii<1 || ii>pfi->dnum[0] ||
1057 jj<1 || jj>pfi->dnum[1]) { /* outside file's grid dimensions */
1058 *r = pgr->undef;
1059 *r2 = pgr->undef;
1060 } else {
1061 /* get wrot value for grid element */
1062 wrot = *(pfi->ppw + (jj-1)*pfi->dnum[0] + ii - 1);
1063 if (wrot < -900.0) {
1064 *r = pgr->undef;
1065 *r2 = pgr->undef;
1066 }
1067 else if (wrot != 0.0) {
1068 if (pvar2->isu) {
1069 *r2 = (*r)*sin(wrot) + (*r2)*cos(wrot); /* display variable is v */
1070 }
1071 else {
1072 *r = (*r)*cos(wrot) - (*r2)*sin(wrot); /* display variable is u */
1073 }
1074 }
1075 }
1076 }
1077 r++; r2++;
1078 if (pgr->idim == 0) ii++;
1079 if (pgr->idim == 1) jj++;
1080 }
1081 if (pgr->jdim == 1) jj++;
1082 }
1083 gagfre(pgr2);
1084 }
1085 }
1086
1087 pst->result.pgr = pgr;
1088 pst->type = 1;
1089 return (ch);
1090 }
1091
1092 /* Check that a specific dimension range is equivalent
1093 between two grids. The dimension range is defined in the
1094 grid descriptor block in terms of grid coordinates, so
1095 conversions are made to absolute coordinates to insure
1096 equivalence in an absolute sense.
1097
1098 A true result means the grids don't match. */
1099
gagchk(struct gagrid * pgr1,struct gagrid * pgr2,int dim)1100 int gagchk (struct gagrid *pgr1, struct gagrid *pgr2, int dim) {
1101 float gmin1,gmax1,gmin2,gmax2,fuz1,fuz2,fuzz;
1102 float (*conv1) (float *, float);
1103 float (*conv2) (float *, float);
1104 float *vals1, *vals2;
1105 int i1,i2,i,siz1,siz2;
1106 struct dt dtim1,dtim2;
1107
1108 if (dim<0) return(0);
1109
1110 if (dim==pgr1->idim) {
1111 conv1 = pgr1->igrab;
1112 vals1 = pgr1->ivals;
1113 i1 = pgr1->ilinr;
1114 siz1 = pgr1->isiz;
1115 } else if (dim==pgr1->jdim) {
1116 conv1 = pgr1->jgrab;
1117 vals1 = pgr1->jvals;
1118 i1 = pgr1->jlinr;
1119 siz1 = pgr1->jsiz;
1120 } else return (1);
1121
1122 if (dim==pgr2->idim) {
1123 conv2 = pgr2->igrab;
1124 vals2 = pgr2->ivals;
1125 i2 = pgr2->ilinr;
1126 siz2 = pgr2->isiz;
1127 } else if (dim==pgr2->jdim) {
1128 conv2 = pgr2->jgrab;
1129 vals2 = pgr2->jvals;
1130 i2 = pgr2->jlinr;
1131 siz2 = pgr2->jsiz;
1132 } else return (1);
1133
1134 if (siz1 != siz2) return(1);
1135 gmin1 = pgr1->dimmin[dim];
1136 gmax1 = pgr1->dimmax[dim];
1137 gmin2 = pgr2->dimmin[dim];
1138 gmax2 = pgr2->dimmax[dim];
1139
1140 if (dim==3) { /* Dimension is time. */
1141 gr2t (vals1, gmin1, &dtim1);
1142 gr2t (vals2, gmin2, &dtim2);
1143 if (dtim1.yr != dtim2.yr) return (1);
1144 if (dtim1.mo != dtim2.mo) return (1);
1145 if (dtim1.dy != dtim2.dy) return (1);
1146 if (dtim1.hr != dtim2.hr) return (1);
1147 if (dtim1.mn != dtim2.mn) return (1);
1148 gr2t (vals1, gmax1, &dtim1);
1149 gr2t (vals2, gmax2, &dtim2);
1150 if (dtim1.yr != dtim2.yr) return (1);
1151 if (dtim1.mo != dtim2.mo) return (1);
1152 if (dtim1.dy != dtim2.dy) return (1);
1153 if (dtim1.hr != dtim2.hr) return (1);
1154 if (dtim1.mn != dtim2.mn) return (1);
1155 return (0);
1156 }
1157
1158 /* Check endpoints. If unequal, then automatic no match. */
1159
1160
1161 /*
1162 * original code
1163 *
1164 * if ( (conv1(vals1,gmin1)) != (conv2(vals2,gmin2)) ) return (1);
1165 * if ( (conv1(vals1,gmax1)) != (conv2(vals2,gmax2)) ) return (1);
1166 *
1167 */
1168
1169 fuz1=fabs(conv1(vals1,gmax1)-conv1(vals1,gmin1))*FUZZ_SCALE;
1170 fuz2=fabs(conv2(vals2,gmax2)-conv2(vals2,gmin2))*FUZZ_SCALE;
1171 fuzz=(fuz1+fuz2)*0.5;
1172
1173 /* printf("fff fuzz = %g\n",fuzz); */
1174
1175 if ( fabs((conv1(vals1,gmin1)) - (conv2(vals2,gmin2))) > fuzz ) return (1);
1176 if ( fabs((conv1(vals1,gmax1)) - (conv2(vals2,gmax2))) > fuzz ) return (1);
1177
1178 if (i1!=i2) return (1);
1179
1180 if (i1) return (0); /* If linear then matches */
1181
1182 /* Nonlinear, but endpoints match. Check every grid point for a
1183 match. If any non-matches, then not a match. */
1184
1185 for (i=0; i<siz1; i++) {
1186
1187 /*
1188 * original codel
1189 *
1190 * if ( (conv1(vals1,gmin1+(float)i)) != (conv2(vals2,gmin2+(float)i)) ) {
1191 * return (1);
1192 * }
1193 */
1194
1195 /*
1196 * printf("fff %g\n",fabs((conv1(vals1,gmin1+(float)i)) -(conv2(vals2,gmin2+(float)i))));
1197 */
1198 if ( fabs((conv1(vals1,gmin1+(float)i)) -(conv2(vals2,gmin2+(float)i))) > fuzz ) {
1199 return (1);
1200 }
1201
1202 }
1203 return (0);
1204 }
1205
1206 /* Check for defined data object. If found, make copy and return
1207 descriptor. */
1208
getdfn(char * name,struct gastat * pst)1209 struct gafile *getdfn (char *name, struct gastat *pst) {
1210 struct gadefn *pdf;
1211
1212 /* See if the name is a defined grid */
1213
1214 pdf = pst->pdf1;
1215 while (pdf!=NULL && !cmpwrd(name,pdf->abbrv)) pdf = pdf->pforw;
1216 if (pdf==NULL) return(NULL);
1217 return (pdf->pfi);
1218 }
1219
1220 /* Handle a station data request variable. */
1221
stnvar(char * ch,char * vnam,struct gafile * pfi,struct gavar * pvar,struct gastat * pst)1222 char *stnvar (char *ch, char *vnam, struct gafile *pfi,
1223 struct gavar *pvar, struct gastat *pst) {
1224 struct gastn *stn;
1225 float dmin[4],dmax[4],d,radius;
1226 int id[6],dim,size,i,rc,rflag,sflag;
1227 char *pos;
1228 char stid[10];
1229
1230 rflag = 0;
1231 sflag = 0;
1232
1233 /* We want to finish parsing the variable name by looking at
1234 any dimension settings by the user. First initialize the
1235 request environment to that found in the pst. */
1236
1237 for (i=0;i<3;i++) {
1238 dmin[i] = pst->dmin[i];
1239 dmax[i] = pst->dmax[i];
1240 }
1241 dmin[3] = t2gr(pfi->abvals[3],&(pst->tmin));
1242 dmax[3] = t2gr(pfi->abvals[3],&(pst->tmax));
1243
1244 /* Check for user provided dimension expressions */
1245
1246 if (*ch=='(') {
1247 ch++;
1248 for (i=0;i<6;i++) id[i] = 0;
1249 while (*ch!=')') {
1250 if (!cmpch(ch,"stid=",5)) { /* special stid= arg */
1251 for (i=0; i<8; i++) stid[i] = ' ';
1252 stid[8] = '\0';
1253 pos = ch+5;
1254 i=0;
1255 while (*pos!=',' && *pos!=')' && i<8) {
1256 stid[i] = *pos;
1257 pos++;
1258 i++;
1259 }
1260 if (i==0) {
1261 gaprnt (0,"Dimension Expression Error: No stid provided\n");
1262 pos=NULL;
1263 }
1264 if (i>8) {
1265 gaprnt (0,"Dimension Expression Error: stid too long\n");
1266 pos=NULL;
1267 }
1268 dim=5;
1269 } else {
1270 pos = dimprs(ch, pst, pfi, &dim, &d, 0, &rc);
1271 }
1272 if (pos==NULL) {
1273 sprintf (pout," Variable name = %s\n",vnam);
1274 gaprnt (0,pout);
1275 return (NULL);
1276 }
1277 if (dim==9) dim=4;
1278 if (id[dim]>1) {
1279 gaprnt (0,"Syntax Error: Invalid dimension expression\n");
1280 gaprnt (0," Same dimension specified more than twice ");
1281 sprintf (pout,"for variable = %s\n",vnam);
1282 gaprnt (0,pout);
1283 return (NULL);
1284 }
1285 if ( dim==pst->idim || dim==pst->jdim ||
1286 ( dim>3 && (pst->idim==0 || pst->idim==1 || pst->jdim==1))) {
1287 gaprnt (0,"Data Request Error: Invalid dimension expression\n");
1288 gaprnt (0," Attempt to set or modify varying dimension\n");
1289 sprintf (pout," Variable = %s, Dimension = %i \n",vnam,dim);
1290 gaprnt (0,pout);
1291 return (NULL);
1292 }
1293 if (dim==4) {
1294 rflag = 1;
1295 radius = d;
1296 } else if (dim==5) {
1297 sflag = 1;
1298 } else {
1299 if (id[dim]==0) dmin[dim] = d;
1300 dmax[dim] = d;
1301 }
1302 ch = pos;
1303 if (*ch == ',') ch++;
1304 id[dim]++;
1305 }
1306 ch++;
1307 }
1308
1309 /* Verify that dmin is less than or equal to dmax for all our dims */
1310
1311 for (i=0; i<4; i++) {
1312 if ((i!=2 && dmin[i]>dmax[i]) || (i==2 && dmax[i]>dmin[i])) {
1313 gaprnt (0,"Data Request Error: Invalid grid coordinates\n");
1314 sprintf (pout," Varying dimension %i decreases: %g to %g \n",
1315 i,dmin[i],dmax[i]);
1316 gaprnt (0,pout);
1317 sprintf (pout," Error ocurred getting variable '%s'\n",vnam);
1318 gaprnt (0,pout);
1319 return (NULL);
1320 }
1321 }
1322
1323 /* Looks like the user specified good stuff, and we are ready to
1324 try to get some data. Allocate and fill in a gastn block. */
1325
1326 size = sizeof(struct gastn);
1327 stn = (struct gastn *)malloc(size);
1328 if (stn==NULL) {
1329 gaprnt (0,"Memory Allocation Error: Station Request Block \n");
1330 return (NULL);
1331 }
1332
1333 stn->rnum = 0;
1334 stn->rpt = NULL;
1335 stn->pfi = pfi;
1336 stn->idim = pst->idim;
1337 stn->jdim = pst->jdim;
1338 stn->undef = pfi->undef;
1339 stn->tmin = dmin[3];
1340 stn->tmax = dmax[3];
1341 stn->ftmin = dmin[3];
1342 stn->ftmax = dmax[3];
1343 stn->pvar = pvar;
1344 for (i=0; i<3; i++) {
1345 stn->dmin[i] = dmin[i];
1346 stn->dmax[i] = dmax[i];
1347 }
1348 stn->rflag = rflag;
1349 stn->radius = radius;
1350 stn->sflag = sflag;
1351 if (sflag) {
1352 for (i=0; i<8; i++) stn->stid[i] = stid[i];
1353 }
1354 stn->tvals = (float *)malloc(sizeof(float)*8);
1355 if (stn->tvals==NULL) {
1356 free (stn);
1357 gaprnt (0,"Memory Allocation Error: Station Request Block \n");
1358 return (NULL);
1359 }
1360 for (i=0; i<8; i++) *(stn->tvals+i) = *(pfi->grvals[3]+i);
1361
1362 rc = gagstn (stn);
1363
1364 if (rc) {
1365 sprintf (pout,"Data Request Error: Variable is '%s'\n",vnam);
1366 gaprnt (0,pout);
1367 free (stn);
1368 return (NULL);
1369 }
1370 pst->result.stn = stn;
1371 pst->type = 0;
1372 return (ch);
1373 }
1374