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