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  *   Enrico Fucile
13  *******************************************/
14 
15 #include "grib_api_internal.h"
16 /*
17    This is used by make_class.pl
18 
19    START_CLASS_DEF
20    CLASS      = accessor
21    SUPER      = grib_accessor_class_abstract_long_vector
22    IMPLEMENTS = pack_string;unpack_string;value_count
23    IMPLEMENTS = pack_long;unpack_long;dump
24    IMPLEMENTS = get_native_type;string_length
25    IMPLEMENTS = init; destroy
26    MEMBERS    = const char* p1
27    MEMBERS    = const char* p2
28    MEMBERS    = const char* timeRangeIndicator
29    MEMBERS    = const char *unit
30    MEMBERS    = const char *step_unit
31    MEMBERS    = const char *stepType
32    MEMBERS    = const char *patch_fp_precip
33    MEMBERS    = int error_on_units
34    END_CLASS_DEF
35 
36  */
37 
38 /* START_CLASS_IMP */
39 
40 /*
41 
42 Don't edit anything between START_CLASS_IMP and END_CLASS_IMP
43 Instead edit values between START_CLASS_DEF and END_CLASS_DEF
44 or edit "accessor.class" and rerun ./make_class.pl
45 
46 */
47 
48 static int get_native_type(grib_accessor*);
49 static int pack_long(grib_accessor*, const long* val, size_t* len);
50 static int pack_string(grib_accessor*, const char*, size_t* len);
51 static int unpack_long(grib_accessor*, long* val, size_t* len);
52 static int unpack_string(grib_accessor*, char*, size_t* len);
53 static size_t string_length(grib_accessor*);
54 static int value_count(grib_accessor*, long*);
55 static void destroy(grib_context*, grib_accessor*);
56 static void dump(grib_accessor*, grib_dumper*);
57 static void init(grib_accessor*, const long, grib_arguments*);
58 static void init_class(grib_accessor_class*);
59 
60 typedef struct grib_accessor_g1step_range
61 {
62     grib_accessor att;
63     /* Members defined in gen */
64     /* Members defined in abstract_long_vector */
65     long* v;
66     long pack_index;
67     int number_of_elements;
68     /* Members defined in g1step_range */
69     const char* p1;
70     const char* p2;
71     const char* timeRangeIndicator;
72     const char* unit;
73     const char* step_unit;
74     const char* stepType;
75     const char* patch_fp_precip;
76     int error_on_units;
77 } grib_accessor_g1step_range;
78 
79 extern grib_accessor_class* grib_accessor_class_abstract_long_vector;
80 
81 static grib_accessor_class _grib_accessor_class_g1step_range = {
82     &grib_accessor_class_abstract_long_vector, /* super                     */
83     "g1step_range",                            /* name                      */
84     sizeof(grib_accessor_g1step_range),        /* size                      */
85     0,                                         /* inited */
86     &init_class,                               /* init_class */
87     &init,                                     /* init                      */
88     0,                                         /* post_init                      */
89     &destroy,                                  /* free mem                       */
90     &dump,                                     /* describes himself         */
91     0,                                         /* get length of section     */
92     &string_length,                            /* get length of string      */
93     &value_count,                              /* get number of values      */
94     0,                                         /* get number of bytes      */
95     0,                                         /* get offset to bytes           */
96     &get_native_type,                          /* get native type               */
97     0,                                         /* get sub_section                */
98     0,                                         /* grib_pack procedures long      */
99     0,                                         /* grib_pack procedures long      */
100     &pack_long,                                /* grib_pack procedures long      */
101     &unpack_long,                              /* grib_unpack procedures long    */
102     0,                                         /* grib_pack procedures double    */
103     0,                                         /* grib_unpack procedures double  */
104     &pack_string,                              /* grib_pack procedures string    */
105     &unpack_string,                            /* grib_unpack procedures string  */
106     0,                                         /* grib_pack array procedures string    */
107     0,                                         /* grib_unpack array procedures string  */
108     0,                                         /* grib_pack procedures bytes     */
109     0,                                         /* grib_unpack procedures bytes   */
110     0,                                         /* pack_expression */
111     0,                                         /* notify_change   */
112     0,                                         /* update_size   */
113     0,                                         /* preferred_size   */
114     0,                                         /* resize   */
115     0,                                         /* nearest_smaller_value */
116     0,                                         /* next accessor    */
117     0,                                         /* compare vs. another accessor   */
118     0,                                         /* unpack only ith value          */
119     0,                                         /* unpack a subarray         */
120     0,                                         /* clear          */
121     0,                                         /* clone accessor          */
122 };
123 
124 
125 grib_accessor_class* grib_accessor_class_g1step_range = &_grib_accessor_class_g1step_range;
126 
127 
init_class(grib_accessor_class * c)128 static void init_class(grib_accessor_class* c)
129 {
130     c->next_offset            = (*(c->super))->next_offset;
131     c->byte_count             = (*(c->super))->byte_count;
132     c->byte_offset            = (*(c->super))->byte_offset;
133     c->sub_section            = (*(c->super))->sub_section;
134     c->pack_missing           = (*(c->super))->pack_missing;
135     c->is_missing             = (*(c->super))->is_missing;
136     c->pack_double            = (*(c->super))->pack_double;
137     c->unpack_double          = (*(c->super))->unpack_double;
138     c->pack_string_array      = (*(c->super))->pack_string_array;
139     c->unpack_string_array    = (*(c->super))->unpack_string_array;
140     c->pack_bytes             = (*(c->super))->pack_bytes;
141     c->unpack_bytes           = (*(c->super))->unpack_bytes;
142     c->pack_expression        = (*(c->super))->pack_expression;
143     c->notify_change          = (*(c->super))->notify_change;
144     c->update_size            = (*(c->super))->update_size;
145     c->preferred_size         = (*(c->super))->preferred_size;
146     c->resize                 = (*(c->super))->resize;
147     c->nearest_smaller_value  = (*(c->super))->nearest_smaller_value;
148     c->next                   = (*(c->super))->next;
149     c->compare                = (*(c->super))->compare;
150     c->unpack_double_element  = (*(c->super))->unpack_double_element;
151     c->unpack_double_subarray = (*(c->super))->unpack_double_subarray;
152     c->clear                  = (*(c->super))->clear;
153     c->make_clone             = (*(c->super))->make_clone;
154 }
155 
156 /* END_CLASS_IMP */
157 
init(grib_accessor * a,const long l,grib_arguments * c)158 static void init(grib_accessor* a, const long l, grib_arguments* c)
159 {
160     grib_accessor_g1step_range* self = (grib_accessor_g1step_range*)a;
161     grib_handle* h                   = grib_handle_of_accessor(a);
162     int n                            = 0;
163     self->p1                         = grib_arguments_get_name(h, c, n++);
164     self->p2                         = grib_arguments_get_name(h, c, n++);
165     self->timeRangeIndicator         = grib_arguments_get_name(h, c, n++);
166     self->unit                       = grib_arguments_get_name(h, c, n++);
167     self->step_unit                  = grib_arguments_get_name(h, c, n++);
168     self->stepType                   = grib_arguments_get_name(h, c, n++);
169     self->patch_fp_precip            = grib_arguments_get_name(h, c, n++);
170     self->error_on_units             = 1;
171 
172     self->number_of_elements = 2;
173     self->v                  = (long*)grib_context_malloc_clear(h->context,
174                                                sizeof(long) * self->number_of_elements);
175     self->pack_index         = -1;
176     a->dirty                 = 1;
177 
178     a->length = 0;
179 }
180 
dump(grib_accessor * a,grib_dumper * dumper)181 static void dump(grib_accessor* a, grib_dumper* dumper)
182 {
183     grib_dump_string(dumper, a, NULL);
184 }
185 
186 static const int u2s1[] = {
187     60,                   /* (0) minutes */
188     3600,                 /* (1) hour    */
189     86400,                /* (2) day     */
190     2592000,              /* (3) month     */
191     -1,                   /* (4) */
192     -1,                   /* (5) */
193     -1,                   /* (6) */
194     -1,                   /* (7) */
195     -1,                   /* (8) */
196     -1,                   /* (9) */
197     10800,                /* (10) 3 hours */
198     21600,                /* (11) 6 hours */
199     43200,                /* (12) 12 hours */
200     900,                  /* (13) 15 minutes  */
201     1800,                 /* (14) 30 minutes */
202     1 /* (15) seconds  */ /* See ECC-316 */
203 };
204 
205 static const int units_index[] = {
206     1, 0, 10, 11, 12, 2, 0, 13, 14, 15
207 };
208 
209 static const int u2s[] = {
210     60,      /* (0) minutes */
211     3600,    /* (1) hour    */
212     86400,   /* (2) day     */
213     2592000, /* (3) month     */
214     -1,      /* (4) */
215     -1,      /* (5) */
216     -1,      /* (6) */
217     -1,      /* (7) */
218     -1,      /* (8) */
219     -1,      /* (9) */
220     10800,   /* (10) 3 hours */
221     21600,   /* (11) 6 hours */
222     43200,   /* (12) 12 hours */
223     1,       /* (13) seconds  */
224     900,     /* (14) 15 minutes  */
225     1800     /* (15) 30 minutes  */
226 };
227 
228 
grib_g1_step_get_steps(grib_accessor * a,long * start,long * theEnd)229 int grib_g1_step_get_steps(grib_accessor* a, long* start, long* theEnd)
230 {
231     grib_accessor_g1step_range* self = (grib_accessor_g1step_range*)a;
232     int err                          = 0;
233     long p1 = 0, p2 = 0, unit = 0, timeRangeIndicator = 0, timeRangeIndicatorFromStepRange = 0;
234     long step_unit    = 1;
235     char stepType[20] = {0,};
236     size_t stepTypeLen = 20;
237     long newstart, newend;
238     int factor = 1;
239     long u2sf, u2sf_step_unit;
240     grib_handle* hand = grib_handle_of_accessor(a);
241 
242     if (self->step_unit != NULL)
243         grib_get_long_internal(hand, self->step_unit, &step_unit);
244 
245     if (err != GRIB_SUCCESS)
246         return err;
247 
248     err = grib_get_long_internal(hand, self->unit, &unit);
249     if (err)
250         return err;
251     if (unit == 254) {
252         unit = 15; /* See ECC-316: WMO says 254 is for 'seconds' but we use 15! */
253     }
254 
255     err = grib_get_long_internal(hand, self->p1, &p1);
256     if (err)
257         return err;
258 
259     err = grib_get_long_internal(hand, self->p2, &p2);
260     if (err)
261         return err;
262 
263     err = grib_get_long_internal(hand, self->timeRangeIndicator, &timeRangeIndicator);
264     if (err)
265         return err;
266 
267     /* TODO move to the def file */
268     err = grib_get_long(hand, "timeRangeIndicatorFromStepRange", &timeRangeIndicatorFromStepRange);
269     if (err) return err;
270 
271     if (timeRangeIndicatorFromStepRange == 10)
272         timeRangeIndicator = timeRangeIndicatorFromStepRange;
273 
274     if (self->stepType) {
275         err = grib_get_string_internal(hand, self->stepType, stepType, &stepTypeLen);
276         if (err)
277             return err;
278     }
279     else
280         sprintf(stepType, "unknown");
281 
282     *start  = p1;
283     *theEnd = p2;
284 
285     if (timeRangeIndicator == 10)
286         *start = *theEnd = (p1 << 8) | (p2 << 0);
287     else if (!strcmp(stepType, "instant"))
288         *start = *theEnd = p1;
289     else if (!strcmp(stepType, "accum") && timeRangeIndicator == 0) {
290         *start  = 0;
291         *theEnd = p1;
292     }
293 
294     if (u2s1[unit] == u2s[step_unit] || (*start == 0 && *theEnd == 0))
295         return 0;
296 
297     newstart = (*start) * u2s1[unit];
298     newend   = (*theEnd) * u2s1[unit];
299 
300     if (newstart < 0 || newend < 0) {
301         factor = 60;
302         u2sf   = u2s1[unit] / factor;
303         if (u2s1[unit] % factor)
304             return GRIB_DECODING_ERROR;
305         newstart       = (*start) * u2sf;
306         newend         = (*theEnd) * u2sf;
307         u2sf_step_unit = u2s[step_unit] / factor;
308         if (u2s[step_unit] % factor)
309             return GRIB_DECODING_ERROR;
310     }
311     else {
312         u2sf_step_unit = u2s[step_unit];
313     }
314 
315     if (newstart % u2sf_step_unit != 0 || newend % u2sf_step_unit != 0) {
316         return GRIB_DECODING_ERROR;
317     }
318     else {
319         *start  = newstart / u2sf_step_unit;
320         *theEnd = newend / u2sf_step_unit;
321     }
322 
323     return 0;
324 }
325 
unpack_string(grib_accessor * a,char * val,size_t * len)326 static int unpack_string(grib_accessor* a, char* val, size_t* len)
327 {
328     grib_accessor_g1step_range* self = (grib_accessor_g1step_range*)a;
329     char buf[100];
330     size_t size = 0;
331     long start = 0, theEnd = 0;
332     long timeRangeIndicator = 0;
333     long unit;
334     int err            = 0;
335     char stepType[20]  = {0,};
336     size_t stepTypeLen = 20;
337     grib_handle* hand  = grib_handle_of_accessor(a);
338 
339     if ((err = grib_g1_step_get_steps(a, &start, &theEnd)) != GRIB_SUCCESS) {
340         size_t step_unit_string_len = 10;
341         char step_unit_string[10];
342 
343         if (self->step_unit != NULL)
344             grib_get_string(hand, self->step_unit, step_unit_string, &step_unit_string_len);
345         else
346             sprintf(step_unit_string, "h");
347 
348         if (self->error_on_units) {
349             grib_get_long_internal(hand, self->unit, &unit);
350             if (unit == 254) {
351                 unit = 15; /* See ECC-316 */
352             }
353             grib_set_long_internal(hand, self->step_unit, unit);
354             grib_context_log(a->context, GRIB_LOG_ERROR,
355                              "unable to represent the step in %s\n                    Hint: try changing the step units",
356                              step_unit_string);
357         }
358         return err;
359     }
360 
361     err = grib_get_long_internal(hand, self->timeRangeIndicator, &timeRangeIndicator);
362     if (err)
363         return err;
364 
365     if (self->stepType) {
366         err = grib_get_string_internal(hand, self->stepType, stepType, &stepTypeLen);
367         if (err)
368             return err;
369     }
370     else
371         sprintf(stepType, "unknown");
372 
373     /* Patch for old forecast probabilities */
374     if (self->patch_fp_precip) {
375         start += 24;
376     }
377 
378     if (strcmp(stepType, "instant") == 0) {
379         sprintf(buf, "%ld", start);
380     }
381     else if ((strcmp(stepType, "avgfc") == 0) ||
382              (strcmp(stepType, "avgua") == 0) ||
383              (strcmp(stepType, "avgia") == 0) ||
384              (strcmp(stepType, "varins") == 0)) {
385         sprintf(buf, "%ld", start);
386     }
387     else if (
388         (strcmp(stepType, "accum") == 0) ||
389         (strcmp(stepType, "avg") == 0) ||
390         (strcmp(stepType, "min") == 0) ||
391         (strcmp(stepType, "max") == 0) ||
392         (strcmp(stepType, "rms") == 0) ||
393         (strcmp(stepType, "diff") == 0) ||
394         (strcmp(stepType, "avgas") == 0) ||
395         (strcmp(stepType, "avgad") == 0) ||
396         (strcmp(stepType, "avgid") == 0) ||
397         (strcmp(stepType, "varas") == 0) ||
398         (strcmp(stepType, "varad") == 0)) {
399         if (start == theEnd) {
400             sprintf(buf, "%ld", theEnd);
401         }
402         else {
403             sprintf(buf, "%ld-%ld", start, theEnd);
404         }
405     }
406     else {
407         grib_context_log(a->context, GRIB_LOG_ERROR, "Unknown stepType=[%s] timeRangeIndicator=[%ld]", stepType, timeRangeIndicator);
408         return GRIB_NOT_IMPLEMENTED;
409     }
410 
411     size = strlen(buf) + 1;
412 
413     if (*len < size)
414         return GRIB_ARRAY_TOO_SMALL;
415 
416     *len = size;
417 
418     memcpy(val, buf, size);
419 
420     return GRIB_SUCCESS;
421 }
422 
grib_g1_step_apply_units(long * start,long * theEnd,long * step_unit,long * P1,long * P2,long * unit,const int max,const int instant)423 int grib_g1_step_apply_units(long* start, long* theEnd, long* step_unit,
424                              long* P1, long* P2, long* unit,
425                              const int max, const int instant)
426 {
427     int j = 0;
428     long start_sec, end_sec;
429     int index     = 0;
430     int max_index = sizeof(units_index) / sizeof(*units_index);
431 
432     while (*unit != units_index[index] && index != max_index)
433         index++;
434 
435     start_sec = *start * u2s[*step_unit];
436     *P2       = 0;
437 
438     if (instant) {
439         *unit = units_index[0];
440         for (j = index; j < max_index; j++) {
441             if (start_sec % u2s1[*unit] == 0 &&
442                 (*P1 = start_sec / u2s1[*unit]) <= max)
443                 return 0;
444             *unit = units_index[j];
445         }
446         for (j = 0; j < index; j++) {
447             if (start_sec % u2s1[*unit] == 0 &&
448                 (*P1 = start_sec / u2s1[*unit]) <= max)
449                 return 0;
450             *unit = units_index[j];
451         }
452     }
453     else {
454         end_sec = *theEnd * u2s[*step_unit];
455         *unit   = units_index[0];
456         for (j = index; j < max_index; j++) {
457             if (start_sec % u2s1[*unit] == 0 &&
458                 end_sec % u2s1[*unit] == 0 &&
459                 (*P1 = start_sec / u2s1[*unit]) <= max &&
460                 (*P2 = end_sec / u2s1[*unit]) <= max)
461                 return 0;
462             *unit = units_index[j];
463         }
464         for (j = 0; j < index; j++) {
465             if (start_sec % u2s1[*unit] == 0 &&
466                 end_sec % u2s1[*unit] == 0 &&
467                 (*P1 = start_sec / u2s1[*unit]) <= max &&
468                 (*P2 = end_sec / u2s1[*unit]) <= max)
469                 return 0;
470             *unit = units_index[j];
471         }
472     }
473 
474     return GRIB_WRONG_STEP;
475 }
476 
pack_string(grib_accessor * a,const char * val,size_t * len)477 static int pack_string(grib_accessor* a, const char* val, size_t* len)
478 {
479     grib_accessor_g1step_range* self = (grib_accessor_g1step_range*)a;
480     grib_handle* h                   = grib_handle_of_accessor(a);
481     long timeRangeIndicator = 0, P1 = 0, P2 = 0;
482     long start = 0, theEnd = -1, unit = 0, ounit = 0, step_unit = 1;
483     int ret = 0;
484     long end_sec, start_sec;
485     char *p = NULL, *q = NULL;
486     int instant       = 0;
487     char stepType[20] = {0,};
488     size_t stepTypeLen = 20;
489 
490     if (self->stepType) {
491         ret = grib_get_string_internal(grib_handle_of_accessor(a), self->stepType, stepType, &stepTypeLen);
492         if (ret)
493             return ret;
494     }
495     else
496         sprintf(stepType, "unknown");
497 
498     if ((ret = grib_set_long_internal(h, "timeRangeIndicatorFromStepRange", -1)))
499         return ret;
500 
501     /* don't change timeRangeIndicator when setting step EXCEPT IF instant*/
502     if ((ret = grib_get_long_internal(h, self->timeRangeIndicator, &timeRangeIndicator)))
503         return ret;
504 
505     instant = (strcmp(stepType, "instant") == 0) ? 1 : 0;
506 
507     if ((ret = grib_get_long_internal(h, self->unit, &unit)))
508         return ret;
509     if (unit == 254) {
510         unit = 15; /* See ECC-316 */
511     }
512 
513     if (self->step_unit != NULL && (ret = grib_get_long_internal(h, self->step_unit, &step_unit)))
514         return ret;
515 
516     ounit = unit;
517 
518     start  = strtol(val, &p, 10);
519     theEnd = start;
520     if (*p != 0)
521         theEnd = strtol(++p, &q, 10);
522 
523     if (start == 0 && theEnd == 0) {
524         if ((ret = grib_set_long_internal(h, self->p1, start)) != GRIB_SUCCESS)
525             return ret;
526         ret = grib_set_long_internal(h, self->p2, theEnd);
527         return ret;
528     }
529     end_sec   = theEnd * u2s[step_unit];
530     start_sec = start * u2s[step_unit];
531 
532     if ((end_sec > 918000 || start_sec > 918000) &&
533         h->context->gribex_mode_on && instant) {
534         timeRangeIndicator = 10;
535         if ((ret = grib_set_long_internal(h, self->timeRangeIndicator, 10)))
536             return ret;
537         /* TODO move to the def file*/
538         if ((ret = grib_set_long_internal(h, "timeRangeIndicatorFromStepRange", 10)))
539             return ret;
540     }
541 
542     if (timeRangeIndicator == 10) {
543         /*
544         * timeRangeIndicator = 10 means 'P1 occupies octets 19 and 20' i.e. 16 bits
545         */
546         long off                   = 0;
547         grib_accessor* p1_accessor = NULL;
548         if (theEnd != start && !h->context->gribex_mode_on) {
549             if (h->context->gribex_mode_on == 0) {
550                 grib_context_log(h->context, GRIB_LOG_ERROR,
551                                  "Unable to set %s: end must be equal to start when timeRangeIndicator=10",
552                                  a->name);
553                 return GRIB_WRONG_STEP;
554             }
555             else
556                 start = theEnd;
557         }
558         if ((ret = grib_g1_step_apply_units(&start, &theEnd, &step_unit, &P1, &P2, &unit, 65535, instant)) != GRIB_SUCCESS) {
559             grib_context_log(h->context, GRIB_LOG_ERROR, "unable to find units to set %s=%s", a->name, val);
560             return ret;
561         }
562 
563         p1_accessor = grib_find_accessor(grib_handle_of_accessor(a), self->p1);
564         if (p1_accessor == NULL) {
565             grib_context_log(h->context, GRIB_LOG_ERROR, "unable to find accessor %s", self->p1);
566             return GRIB_NOT_FOUND;
567         }
568         off = p1_accessor->offset * 8;
569         /* Note: here we assume the key P2 is one octet and immediately follows P1. Hence 16 bits */
570         if (h->context->debug)
571             fprintf(stderr, "ECCODES DEBUG grib_set_long %s=%ld (as two octets)\n", p1_accessor->name, P1);
572         ret = grib_encode_unsigned_long(grib_handle_of_accessor(a)->buffer->data, P1, &off, 16);
573         if (ret != 0)
574             return ret;
575 
576         if (ounit != unit)
577             ret = grib_set_long_internal(h, self->unit, unit);
578 
579         return ret;
580     }
581 
582     if ((ret = grib_g1_step_apply_units(&start, &theEnd, &step_unit, &P1, &P2, &unit, 255, instant)) != GRIB_SUCCESS) {
583         if (instant || h->context->gribex_mode_on) {
584             long off                   = 0;
585             grib_accessor* p1_accessor = NULL;
586             if ((ret = grib_set_long_internal(h, self->timeRangeIndicator, 10)))
587                 return ret;
588             /* TODO move to the def file*/
589             if ((ret = grib_set_long_internal(h, "timeRangeIndicatorFromStepRange", 10)))
590                 return ret;
591             if (theEnd != start && !h->context->gribex_mode_on) {
592                 grib_context_log(h->context, GRIB_LOG_ERROR,
593                                  "Unable to set %s: end must be equal to start when timeRangeIndicator=10",
594                                  a->name);
595                 return GRIB_WRONG_STEP;
596             }
597             else
598                 start = theEnd;
599 
600             if ((ret = grib_g1_step_apply_units(&start, &theEnd, &step_unit, &P1, &P2, &unit, 65535, instant)) != GRIB_SUCCESS) {
601                 grib_context_log(h->context, GRIB_LOG_ERROR, "unable to find units to set %s=%s", a->name, val);
602                 return ret;
603             }
604 
605             p1_accessor = grib_find_accessor(grib_handle_of_accessor(a), self->p1);
606             if (p1_accessor == NULL) {
607                 grib_context_log(h->context, GRIB_LOG_ERROR, "unable to find accessor %s", self->p1);
608                 return GRIB_NOT_FOUND;
609             }
610             off = p1_accessor->offset * 8;
611             /* Note:  case for timeRangeIndicator of 10
612              * We assume the key P2 is one octet and immediately follows P1. Hence 16 bits
613              */
614             if (h->context->debug)
615                 fprintf(stderr, "ECCODES DEBUG grib_set_long %s=%ld (as two octets)\n", p1_accessor->name, P1);
616             ret = grib_encode_unsigned_long(grib_handle_of_accessor(a)->buffer->data, P1, &off, 16);
617             if (ret != 0)
618                 return ret;
619 
620             if (ounit != unit)
621                 ret = grib_set_long_internal(h, self->unit, unit);
622         }
623 
624         return ret;
625     }
626 
627     if (ounit != unit)
628         if ((ret = grib_set_long_internal(h, self->unit, unit)) != GRIB_SUCCESS)
629             return ret;
630 
631     if ((ret = grib_set_long_internal(h, self->p1, P1)) != GRIB_SUCCESS)
632         return ret;
633     if ((ret = grib_set_long_internal(h, self->p2, P2)) != GRIB_SUCCESS)
634         return ret;
635 
636     self->v[0] = start;
637     self->v[1] = theEnd;
638     a->dirty   = 0;
639 
640     return 0;
641 }
642 
value_count(grib_accessor * a,long * count)643 static int value_count(grib_accessor* a, long* count)
644 {
645     *count = 1;
646     return 0;
647 }
648 
string_length(grib_accessor * a)649 static size_t string_length(grib_accessor* a)
650 {
651     return 255;
652 }
653 
pack_long(grib_accessor * a,const long * val,size_t * len)654 static int pack_long(grib_accessor* a, const long* val, size_t* len)
655 {
656     char buff[256];
657     size_t bufflen                   = 100;
658     char sval[100]                   = { 0 };
659     char* p                          = sval;
660     size_t svallen                   = 100;
661     grib_accessor_g1step_range* self = (grib_accessor_g1step_range*)a;
662     char stepType[20]                = {0,};
663     size_t stepTypeLen = 20;
664     long step_unit     = 0;
665     int err            = 0;
666 
667     if (self->stepType) {
668         err = grib_get_string_internal(grib_handle_of_accessor(a), self->stepType, stepType, &stepTypeLen);
669         if (err)
670             return err;
671     }
672     else
673         sprintf(stepType, "unknown");
674 
675     if (self->step_unit != NULL && (err = grib_get_long_internal(grib_handle_of_accessor(a), self->step_unit, &step_unit)))
676         return err;
677 
678     switch (self->pack_index) {
679         case -1:
680             self->pack_index = -1;
681             sprintf(buff, "%ld", *val);
682             return pack_string(a, buff, &bufflen);
683         case 0:
684             self->pack_index     = -1;
685             self->error_on_units = 0;
686             unpack_string(a, sval, &svallen);
687             self->error_on_units = 1;
688             while (*p != '-' && *p != '\0')
689                 p++;
690             if (*p == '-') {
691                 sprintf(buff, "%ld-%s", *val, ++p);
692             }
693             else {
694                 if (strcmp(stepType, "instant") && strcmp(stepType, "avgd")) {
695                     sprintf(buff, "%ld-%s", *val, sval);
696                 }
697                 else {
698                     sprintf(buff, "%ld", *val);
699                 }
700             }
701             return pack_string(a, buff, &bufflen);
702         case 1:
703             self->pack_index     = -1;
704             self->error_on_units = 0;
705             unpack_string(a, sval, &svallen);
706             self->error_on_units = 1;
707             while (*p != '-' && *p != '\0')
708                 p++;
709             if (*p == '-') {
710                 *p = '\0';
711                 sprintf(buff, "%s-%ld", sval, *val);
712             }
713             else {
714                 if (strcmp(stepType, "instant") && strcmp(stepType, "avgd")) {
715                     sprintf(buff, "%s-%ld", sval, *val);
716                 }
717                 else {
718                     sprintf(buff, "%ld", *val);
719                 }
720             }
721             return pack_string(a, buff, &bufflen);
722         default:
723             Assert(self->pack_index < 2);
724             break;
725     }
726 
727     return GRIB_INTERNAL_ERROR;
728 }
729 
unpack_long(grib_accessor * a,long * val,size_t * len)730 static int unpack_long(grib_accessor* a, long* val, size_t* len)
731 {
732     grib_accessor_g1step_range* self = (grib_accessor_g1step_range*)a;
733     char buff[100];
734     size_t bufflen = 100;
735     long start, theEnd;
736     char* p = buff;
737     char* q = NULL;
738     int err = 0;
739 
740     /*TODO implement dirty*/
741     if ((err = unpack_string(a, buff, &bufflen)) != GRIB_SUCCESS)
742         return err;
743 
744     start  = strtol(buff, &p, 10);
745     theEnd = start;
746     if (*p != 0)
747         theEnd = strtol(++p, &q, 10);
748 
749     if (self->pack_index == 1)
750         *val = start;
751     else
752         *val = theEnd;
753 
754     self->v[0] = start;
755     self->v[1] = theEnd;
756     a->dirty   = 0;
757 
758     return 0;
759 }
760 
get_native_type(grib_accessor * a)761 static int get_native_type(grib_accessor* a)
762 {
763     return GRIB_TYPE_STRING;
764 }
765 
destroy(grib_context * c,grib_accessor * a)766 static void destroy(grib_context* c, grib_accessor* a)
767 {
768     grib_accessor_g1step_range* self = (grib_accessor_g1step_range*)a;
769     grib_context_free(c, self->v);
770 }
771