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 #include "grib_api_internal.h"
12
13 /*
14 This is used by make_class.pl
15
16 START_CLASS_DEF
17 CLASS = accessor
18 SUPER = grib_accessor_class_long
19 IMPLEMENTS = unpack_long
20 IMPLEMENTS = init;dump
21 MEMBERS=const char* date
22 MEMBERS=const char* time
23 MEMBERS=const char* step
24 MEMBERS=const char* stepUnits
25 MEMBERS=const char* hours
26 MEMBERS=const char* minutes
27 END_CLASS_DEF
28
29 */
30
31 /* START_CLASS_IMP */
32
33 /*
34
35 Don't edit anything between START_CLASS_IMP and END_CLASS_IMP
36 Instead edit values between START_CLASS_DEF and END_CLASS_DEF
37 or edit "accessor.class" and rerun ./make_class.pl
38
39 */
40
41 static int unpack_long(grib_accessor*, long* val, size_t* len);
42 static void dump(grib_accessor*, grib_dumper*);
43 static void init(grib_accessor*, const long, grib_arguments*);
44 static void init_class(grib_accessor_class*);
45
46 typedef struct grib_accessor_validity_time
47 {
48 grib_accessor att;
49 /* Members defined in gen */
50 /* Members defined in long */
51 /* Members defined in validity_time */
52 const char* date;
53 const char* time;
54 const char* step;
55 const char* stepUnits;
56 const char* hours;
57 const char* minutes;
58 } grib_accessor_validity_time;
59
60 extern grib_accessor_class* grib_accessor_class_long;
61
62 static grib_accessor_class _grib_accessor_class_validity_time = {
63 &grib_accessor_class_long, /* super */
64 "validity_time", /* name */
65 sizeof(grib_accessor_validity_time), /* size */
66 0, /* inited */
67 &init_class, /* init_class */
68 &init, /* init */
69 0, /* post_init */
70 0, /* free mem */
71 &dump, /* describes himself */
72 0, /* get length of section */
73 0, /* get length of string */
74 0, /* get number of values */
75 0, /* get number of bytes */
76 0, /* get offset to bytes */
77 0, /* get native type */
78 0, /* get sub_section */
79 0, /* grib_pack procedures long */
80 0, /* grib_pack procedures long */
81 0, /* grib_pack procedures long */
82 &unpack_long, /* grib_unpack procedures long */
83 0, /* grib_pack procedures double */
84 0, /* grib_unpack procedures double */
85 0, /* grib_pack procedures string */
86 0, /* grib_unpack procedures string */
87 0, /* grib_pack array procedures string */
88 0, /* grib_unpack array procedures string */
89 0, /* grib_pack procedures bytes */
90 0, /* grib_unpack procedures bytes */
91 0, /* pack_expression */
92 0, /* notify_change */
93 0, /* update_size */
94 0, /* preferred_size */
95 0, /* resize */
96 0, /* nearest_smaller_value */
97 0, /* next accessor */
98 0, /* compare vs. another accessor */
99 0, /* unpack only ith value */
100 0, /* unpack a subarray */
101 0, /* clear */
102 0, /* clone accessor */
103 };
104
105
106 grib_accessor_class* grib_accessor_class_validity_time = &_grib_accessor_class_validity_time;
107
108
init_class(grib_accessor_class * c)109 static void init_class(grib_accessor_class* c)
110 {
111 c->next_offset = (*(c->super))->next_offset;
112 c->string_length = (*(c->super))->string_length;
113 c->value_count = (*(c->super))->value_count;
114 c->byte_count = (*(c->super))->byte_count;
115 c->byte_offset = (*(c->super))->byte_offset;
116 c->get_native_type = (*(c->super))->get_native_type;
117 c->sub_section = (*(c->super))->sub_section;
118 c->pack_missing = (*(c->super))->pack_missing;
119 c->is_missing = (*(c->super))->is_missing;
120 c->pack_long = (*(c->super))->pack_long;
121 c->pack_double = (*(c->super))->pack_double;
122 c->unpack_double = (*(c->super))->unpack_double;
123 c->pack_string = (*(c->super))->pack_string;
124 c->unpack_string = (*(c->super))->unpack_string;
125 c->pack_string_array = (*(c->super))->pack_string_array;
126 c->unpack_string_array = (*(c->super))->unpack_string_array;
127 c->pack_bytes = (*(c->super))->pack_bytes;
128 c->unpack_bytes = (*(c->super))->unpack_bytes;
129 c->pack_expression = (*(c->super))->pack_expression;
130 c->notify_change = (*(c->super))->notify_change;
131 c->update_size = (*(c->super))->update_size;
132 c->preferred_size = (*(c->super))->preferred_size;
133 c->resize = (*(c->super))->resize;
134 c->nearest_smaller_value = (*(c->super))->nearest_smaller_value;
135 c->next = (*(c->super))->next;
136 c->compare = (*(c->super))->compare;
137 c->unpack_double_element = (*(c->super))->unpack_double_element;
138 c->unpack_double_subarray = (*(c->super))->unpack_double_subarray;
139 c->clear = (*(c->super))->clear;
140 c->make_clone = (*(c->super))->make_clone;
141 }
142
143 /* END_CLASS_IMP */
144
145 /* Table of multipliers to convert step units to minutes */
146 static const double u2m[] = {
147 1, /* index 0: minutes */
148 60, /* index 1: hour */
149 24 * 60, /* index 2: day */
150 24 * 60 * 30, /* index 3: month */
151 -1, /* index 4: year */
152 -1, /* index 5: decade */
153 -1, /* index 6: 30 years */
154 -1, /* index 7: century */
155 -1, /* index 8: RESERVED */
156 -1, /* index 9: RESERVED */
157 3 * 60, /* index 10: 3 hours */
158 6 * 60, /* index 11: 6 hours */
159 12 * 60, /* index 12: 12 hours */
160 1 / 60.0, /* index 13: seconds */
161 15, /* index 14: 15 mins */
162 30 /* index 15: 30 mins */
163 };
164
convert_to_minutes(long step,long stepUnits)165 static long convert_to_minutes(long step, long stepUnits)
166 {
167 double result = 0;
168 if (stepUnits == 0)
169 return step; /* unit=minutes so no change */
170 if (stepUnits == 1)
171 return step * 60; /* unit=hours */
172 if (stepUnits == 13)
173 return step / 60; /* unit=seconds*/
174 /* Assert( stepUnits < sizeof(u2m)/sizeof(u2m[0]) ); */
175
176 result = step * u2m[stepUnits];
177 return (long)result;
178 }
179
init(grib_accessor * a,const long l,grib_arguments * c)180 static void init(grib_accessor* a, const long l, grib_arguments* c)
181 {
182 grib_accessor_validity_time* self = (grib_accessor_validity_time*)a;
183 grib_handle* hand = grib_handle_of_accessor(a);
184 int n = 0;
185
186 self->date = grib_arguments_get_name(hand, c, n++);
187 self->time = grib_arguments_get_name(hand, c, n++);
188 self->step = grib_arguments_get_name(hand, c, n++);
189 self->stepUnits = grib_arguments_get_name(hand, c, n++);
190 self->hours = grib_arguments_get_name(hand, c, n++);
191 self->minutes = grib_arguments_get_name(hand, c, n++);
192
193 a->flags |= GRIB_ACCESSOR_FLAG_READ_ONLY;
194 }
195
dump(grib_accessor * a,grib_dumper * dumper)196 static void dump(grib_accessor* a, grib_dumper* dumper)
197 {
198 grib_dump_long(dumper, a, NULL);
199 }
200
unpack_long(grib_accessor * a,long * val,size_t * len)201 static int unpack_long(grib_accessor* a, long* val, size_t* len)
202 {
203 grib_accessor_validity_time* self = (grib_accessor_validity_time*)a;
204 grib_handle* hand = grib_handle_of_accessor(a);
205 int ret = 0;
206 long date = 0;
207 long time = 0;
208 long step = 0;
209 long stepUnits = 0;
210 long hours = 0, minutes = 0, step_mins = 0, tmp, tmp_hrs, tmp_mins;
211
212 if (self->hours) {
213 if ((ret = grib_get_long_internal(hand, self->hours, &hours)) != GRIB_SUCCESS)
214 return ret;
215 if ((ret = grib_get_long_internal(hand, self->minutes, &minutes)) != GRIB_SUCCESS)
216 return ret;
217 *val = hours * 100 + minutes;
218 return GRIB_SUCCESS;
219 }
220 if ((ret = grib_get_long_internal(hand, self->date, &date)) != GRIB_SUCCESS)
221 return ret;
222 if ((ret = grib_get_long_internal(hand, self->time, &time)) != GRIB_SUCCESS)
223 return ret;
224 if ((ret = grib_get_long(hand, self->step, &step)) != GRIB_SUCCESS) {
225 if ((ret = grib_get_long_internal(hand, "endStep", &step)) != GRIB_SUCCESS) {
226 return ret; /* See ECC-817 */
227 }
228 }
229
230 /* Seconds will always be zero. So convert to minutes */
231 if (self->stepUnits) {
232 if ((ret = grib_get_long_internal(hand, self->stepUnits, &stepUnits)) != GRIB_SUCCESS)
233 return ret;
234 step_mins = convert_to_minutes(step, stepUnits);
235 }
236
237 minutes = time % 100;
238 hours = time / 100;
239 tmp = minutes + step_mins; /* add the step to our minutes */
240 tmp_hrs = tmp / 60; /* how many hours and mins is that? */
241 tmp_mins = tmp % 60;
242 hours += tmp_hrs; /* increment hours */
243 if (hours > 0) {
244 hours = hours % 24; /* wrap round if >= 24 */
245 }
246 else {
247 /* GRIB-29: Negative forecast time */
248 while (hours < 0) {
249 hours += 24;
250 }
251 }
252 time = hours * 100 + tmp_mins;
253
254 if (*len < 1)
255 return GRIB_ARRAY_TOO_SMALL;
256
257 *val = time;
258
259 return GRIB_SUCCESS;
260 }
261