1 /*
2 * (C) Copyright 2005- 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_gen
23 IMPLEMENTS = dump
24 IMPLEMENTS = destroy
25 MEMBERS = grib_concept_value* concept
26 MEMBERS = char* basename
27 MEMBERS = char* masterDir
28 MEMBERS = char* localDir
29 MEMBERS = int nofail
30 END_CLASS_DEF
31
32 */
33
34 /* START_CLASS_IMP */
35
36 /*
37
38 Don't edit anything between START_CLASS_IMP and END_CLASS_IMP
39 Instead edit values between START_CLASS_DEF and END_CLASS_DEF
40 or edit "action.class" and rerun ./make_class.pl
41
42 */
43
44 static void init_class(grib_action_class*);
45 static void dump(grib_action* d, FILE*, int);
46 static void destroy(grib_context*, grib_action*);
47
48
49 typedef struct grib_action_concept
50 {
51 grib_action act;
52 /* Members defined in gen */
53 long len;
54 grib_arguments* params;
55 /* Members defined in concept */
56 grib_concept_value* concept;
57 char* basename;
58 char* masterDir;
59 char* localDir;
60 int nofail;
61 } grib_action_concept;
62
63 extern grib_action_class* grib_action_class_gen;
64
65 static grib_action_class _grib_action_class_concept = {
66 &grib_action_class_gen, /* super */
67 "action_class_concept", /* name */
68 sizeof(grib_action_concept), /* size */
69 0, /* inited */
70 &init_class, /* init_class */
71 0, /* init */
72 &destroy, /* destroy */
73
74 &dump, /* dump */
75 0, /* xref */
76
77 0, /* create_accessor*/
78
79 0, /* notify_change */
80 0, /* reparse */
81 0, /* execute */
82 };
83
84 grib_action_class* grib_action_class_concept = &_grib_action_class_concept;
85
init_class(grib_action_class * c)86 static void init_class(grib_action_class* c)
87 {
88 c->xref = (*(c->super))->xref;
89 c->create_accessor = (*(c->super))->create_accessor;
90 c->notify_change = (*(c->super))->notify_change;
91 c->reparse = (*(c->super))->reparse;
92 c->execute = (*(c->super))->execute;
93 }
94 /* END_CLASS_IMP */
95
96 #if GRIB_PTHREADS
97 static pthread_once_t once = PTHREAD_ONCE_INIT;
98 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
99
init()100 static void init()
101 {
102 pthread_mutexattr_t attr;
103 pthread_mutexattr_init(&attr);
104 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
105 pthread_mutex_init(&mutex, &attr);
106 pthread_mutexattr_destroy(&attr);
107 }
108 #elif GRIB_OMP_THREADS
109 static int once = 0;
110 static omp_nest_lock_t mutex;
111
init()112 static void init()
113 {
114 GRIB_OMP_CRITICAL(lock_action_class_concept_c)
115 {
116 if (once == 0) {
117 omp_init_nest_lock(&mutex);
118 once = 1;
119 }
120 }
121 }
122 #endif
123
124 static grib_concept_value* get_concept(grib_handle* h, grib_action_concept* self);
125
action_concept_get_concept(grib_accessor * a)126 grib_concept_value* action_concept_get_concept(grib_accessor* a)
127 {
128 return get_concept(grib_handle_of_accessor(a), (grib_action_concept*)a->creator);
129 }
130
action_concept_get_nofail(grib_accessor * a)131 int action_concept_get_nofail(grib_accessor* a)
132 {
133 grib_action_concept* self = (grib_action_concept*)a->creator;
134 return self->nofail;
135 }
136
grib_action_create_concept(grib_context * context,const char * name,grib_concept_value * concept,const char * basename,const char * name_space,const char * defaultkey,const char * masterDir,const char * localDir,const char * ecmfDir,int flags,int nofail)137 grib_action* grib_action_create_concept(grib_context* context,
138 const char* name,
139 grib_concept_value* concept,
140 const char* basename, const char* name_space, const char* defaultkey,
141 const char* masterDir, const char* localDir, const char* ecmfDir, int flags, int nofail)
142 {
143 grib_action_concept* a = NULL;
144 grib_action_class* c = grib_action_class_concept;
145 grib_action* act = (grib_action*)grib_context_malloc_clear_persistent(context, c->size);
146 act->op = grib_context_strdup_persistent(context, "concept");
147
148 act->cclass = c;
149 a = (grib_action_concept*)act;
150 act->context = context;
151 act->flags = flags;
152
153 if (name_space)
154 act->name_space = grib_context_strdup_persistent(context, name_space);
155
156 if (basename)
157 a->basename = grib_context_strdup_persistent(context, basename);
158 else
159 a->basename = NULL;
160
161 if (masterDir)
162 a->masterDir = grib_context_strdup_persistent(context, masterDir);
163 else
164 a->masterDir = NULL;
165
166 if (localDir)
167 a->localDir = grib_context_strdup_persistent(context, localDir);
168 else
169 a->localDir = NULL;
170
171 if (defaultkey)
172 act->defaultkey = grib_context_strdup_persistent(context, defaultkey);
173
174 a->concept = concept;
175 if (concept) {
176 grib_concept_value* conc_val = concept;
177 grib_trie* index = grib_trie_new(context);
178 while (conc_val) {
179 conc_val->index = index;
180 grib_trie_insert_no_replace(index, conc_val->name, conc_val);
181 conc_val = conc_val->next;
182 }
183 }
184 act->name = grib_context_strdup_persistent(context, name);
185
186 a->nofail = nofail;
187
188 return act;
189 }
190
dump(grib_action * act,FILE * f,int lvl)191 static void dump(grib_action* act, FILE* f, int lvl)
192 {
193 int i = 0;
194
195 for (i = 0; i < lvl; i++)
196 grib_context_print(act->context, f, " ");
197
198 printf("concept(%s) { ", act->name);
199 printf("\n");
200
201 for (i = 0; i < lvl; i++)
202 grib_context_print(act->context, f, " ");
203 printf("}\n");
204 }
205
destroy(grib_context * context,grib_action * act)206 static void destroy(grib_context* context, grib_action* act)
207 {
208 grib_action_concept* self = (grib_action_concept*)act;
209
210 grib_concept_value* v = self->concept;
211 if (v) {
212 grib_trie_delete_container(v->index);
213 }
214 while (v) {
215 grib_concept_value* n = v->next;
216 grib_concept_value_delete(context, v);
217 v = n;
218 }
219 grib_context_free_persistent(context, self->masterDir);
220 grib_context_free_persistent(context, self->localDir);
221 grib_context_free_persistent(context, self->basename);
222 }
223
get_concept_impl(grib_handle * h,grib_action_concept * self)224 static grib_concept_value* get_concept_impl(grib_handle* h, grib_action_concept* self)
225 {
226 char buf[4096] = {0,};
227 char master[1024] = {0,};
228 char local[1024] = {0,};
229 char masterDir[1024] = {0,};
230 size_t lenMasterDir = 1024;
231 char key[4096] = {0,};
232 char* full = 0;
233 int id;
234
235 grib_context* context = ((grib_action*)self)->context;
236 grib_concept_value* c = NULL;
237
238 if (self->concept != NULL)
239 return self->concept;
240
241 Assert(self->masterDir);
242 grib_get_string(h, self->masterDir, masterDir, &lenMasterDir);
243
244 sprintf(buf, "%s/%s", masterDir, self->basename);
245
246 grib_recompose_name(h, NULL, buf, master, 1);
247
248 if (self->localDir) {
249 char localDir[1024] = {0,};
250 size_t lenLocalDir = 1024;
251 grib_get_string(h, self->localDir, localDir, &lenLocalDir);
252 sprintf(buf, "%s/%s", localDir, self->basename);
253 grib_recompose_name(h, NULL, buf, local, 1);
254 }
255
256 sprintf(key, "%s%s", master, local);
257
258 id = grib_itrie_get_id(h->context->concepts_index, key);
259 if ((c = h->context->concepts[id]) != NULL)
260 return c;
261
262 if (*local && (full = grib_context_full_defs_path(context, local)) != NULL) {
263 c = grib_parse_concept_file(context, full);
264 grib_context_log(h->context, GRIB_LOG_DEBUG,
265 "Loading concept %s from %s", ((grib_action*)self)->name, full);
266 }
267
268 full = grib_context_full_defs_path(context, master);
269
270 if (c) {
271 grib_concept_value* last = c;
272 while (last->next)
273 last = last->next;
274 if (full) {
275 last->next = grib_parse_concept_file(context, full);
276 }
277 }
278 else if (full) {
279 c = grib_parse_concept_file(context, full);
280 }
281 else {
282 grib_context_log(context, GRIB_LOG_FATAL,
283 "unable to find definition file %s in %s:%s\nDefinition files path=\"%s\"",
284 self->basename, master, local, context->grib_definition_files_path);
285 return NULL;
286 }
287
288 if (full) {
289 grib_context_log(h->context, GRIB_LOG_DEBUG,
290 "Loading concept %s from %s", ((grib_action*)self)->name, full);
291 }
292
293 h->context->concepts[id] = c;
294 if (c) {
295 grib_trie* index = grib_trie_new(context);
296 while (c) {
297 c->index = index;
298 grib_trie_insert_no_replace(index, c->name, c);
299 c = c->next;
300 }
301 }
302
303 return h->context->concepts[id];
304 }
305
get_concept(grib_handle * h,grib_action_concept * self)306 static grib_concept_value* get_concept(grib_handle* h, grib_action_concept* self)
307 {
308 grib_concept_value* result = NULL;
309 GRIB_MUTEX_INIT_ONCE(&once, &init)
310 GRIB_MUTEX_LOCK(&mutex);
311
312 result = get_concept_impl(h, self);
313
314 GRIB_MUTEX_UNLOCK(&mutex);
315 return result;
316 }
317
concept_condition_expression_true(grib_handle * h,grib_concept_condition * c,char * exprVal)318 static int concept_condition_expression_true(grib_handle* h, grib_concept_condition* c, char* exprVal)
319 {
320 long lval;
321 long lres = 0;
322 int ok = 0;
323 int err = 0;
324 const int type = grib_expression_native_type(h, c->expression);
325
326 switch (type) {
327 case GRIB_TYPE_LONG:
328 grib_expression_evaluate_long(h, c->expression, &lres);
329 ok = (grib_get_long(h, c->name, &lval) == GRIB_SUCCESS) &&
330 (lval == lres);
331 if (ok)
332 sprintf(exprVal, "%ld", lres);
333 break;
334
335 case GRIB_TYPE_DOUBLE: {
336 double dval;
337 double dres = 0.0;
338 grib_expression_evaluate_double(h, c->expression, &dres);
339 ok = (grib_get_double(h, c->name, &dval) == GRIB_SUCCESS) &&
340 (dval == dres);
341 if (ok)
342 sprintf(exprVal, "%g", dres);
343 break;
344 }
345
346 case GRIB_TYPE_STRING: {
347 const char* cval;
348 char buf[80];
349 char tmp[80];
350 size_t len = sizeof(buf);
351 size_t size = sizeof(tmp);
352
353 ok = (grib_get_string(h, c->name, buf, &len) == GRIB_SUCCESS) &&
354 ((cval = grib_expression_evaluate_string(h, c->expression, tmp, &size, &err)) != NULL) &&
355 (err == 0) && (strcmp(buf, cval) == 0);
356 if (ok)
357 sprintf(exprVal, "%s", cval);
358 break;
359 }
360
361 default:
362 /* TODO: */
363 break;
364 }
365 return ok;
366 }
367
368 /* Caller has to allocate space for the result.
369 * INPUTS: h, key and value (can be NULL)
370 * OUTPUT: result
371 * Example: key='typeOfLevel' whose value is 'mixedLayerDepth',
372 * result='typeOfFirstFixedSurface=169,typeOfSecondFixedSurface=255'
373 */
get_concept_condition_string(grib_handle * h,const char * key,const char * value,char * result)374 int get_concept_condition_string(grib_handle* h, const char* key, const char* value, char* result)
375 {
376 int err = 0;
377 int length = 0;
378 char strVal[64] = {0,};
379 char exprVal[256] = {0,};
380 const char* pValue = value;
381 size_t len = sizeof(strVal);
382 grib_concept_value* concept_value = NULL;
383 grib_accessor* acc = grib_find_accessor(h, key);
384 if (!acc)
385 return GRIB_NOT_FOUND;
386
387 if (!value) {
388 err = grib_get_string(h, key, strVal, &len);
389 if (err)
390 return GRIB_INTERNAL_ERROR;
391 pValue = strVal;
392 }
393
394 concept_value = action_concept_get_concept(acc);
395 while (concept_value) {
396 grib_concept_condition* concept_condition = concept_value->conditions;
397 if (strcmp(pValue, concept_value->name) == 0) {
398 while (concept_condition) {
399 grib_expression* expression = concept_condition->expression;
400 const char* condition_name = concept_condition->name;
401 Assert(expression);
402 if (concept_condition_expression_true(h, concept_condition, exprVal) && strcmp(condition_name, "one") != 0) {
403 length += sprintf(result + length, "%s%s=%s",
404 (length == 0 ? "" : ","), condition_name, exprVal);
405 }
406 concept_condition = concept_condition->next;
407 }
408 }
409
410 concept_value = concept_value->next;
411 }
412 if (length == 0)
413 return GRIB_CONCEPT_NO_MATCH;
414 return GRIB_SUCCESS;
415 }
416