1 /*
2  * Copyright 2005-2018 ECMWF.
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  *
7  * In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
8  * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
9  */
10 
11 /***************************************************************************
12  *   Jean Baptiste Filippi - 01.11.2005                                                           *
13  *   Enrico Fucile
14  *                                                                         *
15  ***************************************************************************/
16 #include "grib_api_internal.h"
17 /*
18    This is used by make_class.pl
19 
20    START_CLASS_DEF
21    CLASS      = action
22    SUPER      = action_class_section
23    IMPLEMENTS = create_accessor
24    IMPLEMENTS = dump
25    IMPLEMENTS = destroy
26    IMPLEMENTS = xref
27    IMPLEMENTS = compile
28    IMPLEMENTS = reparse;execute
29    MEMBERS    = grib_expression *expression
30    MEMBERS    = grib_action     *block_true
31    MEMBERS    = grib_action     *block_false
32    MEMBERS    = int transient
33    END_CLASS_DEF
34 
35  */
36 
37 /* START_CLASS_IMP */
38 
39 /*
40 
41 Don't edit anything between START_CLASS_IMP and END_CLASS_IMP
42 Instead edit values between START_CLASS_DEF and END_CLASS_DEF
43 or edit "action.class" and rerun ./make_class.pl
44 
45 */
46 
47 static void init_class      (grib_action_class*);
48 static void dump            (grib_action* d, FILE*,int);
49 static void xref            (grib_action* d, FILE* f,const char* path);
50 static void compile         (grib_action* a, grib_compiler* compiler);
51 static void destroy         (grib_context*,grib_action*);
52 static int create_accessor(grib_section*,grib_action*,grib_loader*);
53 static grib_action* reparse(grib_action* a,grib_accessor* acc,int *doit);
54 static int execute(grib_action* a,grib_handle* h);
55 
56 
57 typedef struct grib_action_if {
58     grib_action          act;
59 /* Members defined in section */
60 /* Members defined in if */
61 	grib_expression *expression;
62 	grib_action     *block_true;
63 	grib_action     *block_false;
64 	int transient;
65 } grib_action_if;
66 
67 extern grib_action_class* grib_action_class_section;
68 
69 static grib_action_class _grib_action_class_if = {
70     &grib_action_class_section,                              /* super                     */
71     "action_class_if",                              /* name                      */
72     sizeof(grib_action_if),            /* size                      */
73     0,                                   /* inited */
74     &init_class,                         /* init_class */
75     0,                               /* init                      */
76     &destroy,                            /* destroy */
77 
78     &dump,                               /* dump                      */
79     &xref,                               /* xref                      */
80 
81     &create_accessor,             /* create_accessor*/
82 
83     0,                            /* notify_change */
84     &reparse,                            /* reparse */
85     &execute,                            /* execute */
86     &compile,                            /* compile */
87 };
88 
89 grib_action_class* grib_action_class_if = &_grib_action_class_if;
90 
init_class(grib_action_class * c)91 static void init_class(grib_action_class* c)
92 {
93 	c->notify_change	=	(*(c->super))->notify_change;
94 }
95 /* END_CLASS_IMP */
96 
grib_action_create_if(grib_context * context,grib_expression * expression,grib_action * block_true,grib_action * block_false,int transient)97 grib_action* grib_action_create_if( grib_context* context,
98         grib_expression* expression,
99         grib_action* block_true,grib_action* block_false,int transient)
100 {
101     char name[1024];
102     grib_action_if* a ;
103     grib_action_class* c   = grib_action_class_if;
104     grib_action* act       = (grib_action*)grib_context_malloc_clear_persistent(context,c->size);
105     act->op              = grib_context_strdup_persistent(context,"section");
106 
107     act->cclass       = c;
108     a                 = (grib_action_if*)act;
109     act->context      = context;
110 
111     a->expression  = expression;
112     a->block_true  = block_true;
113     a->block_false = block_false;
114     a->transient   = transient;
115 
116     if (transient)
117         sprintf(name,"__if%p",(void*)a);
118     else
119         sprintf(name,"_if%p",(void*)a);
120 
121     act->name      = grib_context_strdup_persistent(context,name);
122 
123     return act;
124 }
125 
compile(grib_action * act,grib_compiler * compiler)126 static void compile(grib_action* act, grib_compiler *compiler)
127 {
128     grib_action_if* a  = (grib_action_if*)act;
129     char t[80];
130     char f[80];
131 
132     if(a->block_true)
133         grib_compile_action_branch(a->block_true, compiler,t);
134     else
135         strcpy(t,"NULL");
136 
137     if(a->block_false)
138         grib_compile_action_branch(a->block_false, compiler,f);
139     else
140         strcpy(f,"NULL");
141 
142     fprintf(compiler->out,"%s = grib_action_create_if(ctx,",compiler->var);
143     grib_compile_expression(a->expression, compiler);
144     fprintf(compiler->out,",%s,%s,%d);\n", t,f,a->transient);
145 }
146 
create_accessor(grib_section * p,grib_action * act,grib_loader * h)147 static int create_accessor( grib_section* p, grib_action* act, grib_loader *h)
148 {
149     grib_action_if* a = (grib_action_if*)act;
150     grib_action* next = NULL;
151     int ret = 0;
152     long lres=0;
153 
154     grib_accessor* as = NULL;
155     grib_section*  gs = NULL;
156 
157     as = grib_accessor_factory(p, act,0,NULL);
158     if(!as)return GRIB_INTERNAL_ERROR;
159     gs = as->sub_section;
160     grib_push_accessor(as,p->block);
161 
162     if ((ret=grib_expression_evaluate_long(p->h,a->expression,&lres)) != GRIB_SUCCESS)
163         return ret;
164 
165     if(lres)
166         next = a->block_true;
167     else
168         next = a->block_false;
169 
170     if(p->h->context->debug > 1)
171     {
172         printf("EVALUATE create_accessor_handle ");
173         grib_expression_print(p->h->context,a->expression,p->h);
174         printf(" [%s][_if%p]\n", (next == a->block_true ? "true":"false"), (void*)a);
175 
176         /*grib_dump_action_branch(stdout,next,5);*/
177     }
178 
179     gs->branch = next;
180     grib_dependency_observe_expression(as,a->expression);
181 
182     while(next){
183 
184         ret = grib_create_accessor(gs, next, h);
185         if(ret != GRIB_SUCCESS) return ret;
186         next= next->next;
187     }
188 
189     return GRIB_SUCCESS;
190 }
191 
execute(grib_action * act,grib_handle * h)192 static int execute(grib_action* act, grib_handle *h)
193 {
194     grib_action_if* a = (grib_action_if*)act;
195     grib_action* next = NULL;
196     int ret = 0;
197     long lres=0;
198 
199     /* See GRIB-394 */
200     int type = grib_expression_native_type(h, a->expression);
201     if (type != GRIB_TYPE_DOUBLE) {
202         if ((ret=grib_expression_evaluate_long(h,a->expression,&lres)) != GRIB_SUCCESS) {
203             if (ret == GRIB_NOT_FOUND) lres=0;
204             else return ret;
205         }
206     }
207     else {
208         double dres = 0.0;
209         ret = grib_expression_evaluate_double(h, a->expression, &dres);
210         lres = (long)dres;
211         if ( ret != GRIB_SUCCESS ) {
212             if (ret == GRIB_NOT_FOUND) lres=0;
213             else return ret;
214         }
215     }
216 
217     if(lres)
218         next = a->block_true;
219     else
220         next = a->block_false;
221 
222     while(next){
223         ret = grib_action_execute(next, h);
224         if(ret != GRIB_SUCCESS) return ret;
225         next= next->next;
226     }
227 
228     return GRIB_SUCCESS;
229 }
230 
dump(grib_action * act,FILE * f,int lvl)231 static void dump(grib_action* act, FILE* f, int lvl)
232 {
233     grib_action_if* a = (grib_action_if*)act;
234     int i = 0;
235 
236     for (i=0;i<lvl;i++)
237         grib_context_print(act->context,f,"     ");
238 
239     printf("if(%s) { ",act->name);  grib_expression_print(act->context,a->expression,0);
240     printf("\n");
241 
242     if(a->block_true){
243         /*      grib_context_print(act->context,f,"IF \t TODO \n");  TODO */
244         grib_dump_action_branch(f,a->block_true,lvl+1);
245     }
246     if(a->block_false){
247         printf("}\n");
248         for (i=0;i<lvl;i++)
249             grib_context_print(act->context,f,"     ");
250         printf("else(%s) { ",act->name);  grib_expression_print(act->context,a->expression,0);
251         /*     grib_context_print(act->context,f,"ELSE \n" );*/
252         grib_dump_action_branch(f,a->block_false,lvl+1);
253     }
254     for (i=0;i<lvl;i++)
255         grib_context_print(act->context,f,"     ");
256     printf("}\n");
257 }
258 
reparse(grib_action * a,grib_accessor * acc,int * doit)259 static grib_action* reparse(grib_action* a,grib_accessor* acc,int* doit)
260 {
261     int ret=0;
262     long lres=0;
263     grib_action_if* self = (grib_action_if*)a;
264 
265     /* printf("reparse %s %s\n",a->name,acc->name); */
266 
267     if((ret=grib_expression_evaluate_long(acc->parent->h,self->expression,&lres)) != GRIB_SUCCESS)
268         grib_context_log(acc->parent->h->context,
269                 GRIB_LOG_ERROR,"if reparse  grib_expression_evaluate_long %s",
270                 grib_get_error_message(ret));
271 
272     if(lres)
273         return self->block_true;
274     else
275         return self->block_false;
276 
277 }
278 
destroy(grib_context * context,grib_action * act)279 static void destroy(grib_context* context,grib_action* act)
280 {
281     grib_action_if* a = (grib_action_if*) act;
282     grib_action *t = a->block_true;
283     grib_action *f = a->block_false;
284 
285     while(t)
286     {
287         grib_action *nt = t->next;
288         grib_action_delete(context,t);
289         t = nt;
290     }
291 
292     while(f)
293     {
294         grib_action *nf = f->next;
295         grib_action_delete(context,f);
296         f = nf;
297     }
298 
299 
300     grib_expression_free(context,a->expression);
301 
302     grib_context_free_persistent(context, act->name);
303     grib_context_free_persistent(context, act->op);
304 }
305 
xref(grib_action * d,FILE * f,const char * path)306 static void xref(grib_action* d, FILE* f,const char* path)
307 {
308 }
309