Nyx Node
Loading...
Searching...
No Matches
format.c
1/* NyxNode
2 * Author: Jérôme ODIER <jerome.odier@lpsc.in2p3.fr>
3 * SPDX-License-Identifier: GPL-2.0-only (Mongoose backend) or GPL-3.0+
4 */
5
6/*--------------------------------------------------------------------------------------------------------------------*/
7
8#include <math.h>
9#include <ctype.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include "../nyx_node_internal.h"
15
16/*--------------------------------------------------------------------------------------------------------------------*/
17/* UTILITIES */
18/*--------------------------------------------------------------------------------------------------------------------*/
19
20static const double NAN_double = (double) NAN;
21
22/*--------------------------------------------------------------------------------------------------------------------*/
23
24static bool _parse_format(char *result_conv, int *result_lcnt, int *result_w, int *result_f, STR_t s)
25{
26 /*----------------------------------------------------------------------------------------------------------------*/
27
28 STR_t p = strchr(s, '%');
29 if(p == NULL) { return false; }
30
31 p++;
32
33 STR_t q = strchr(p, '%');
34 if(q != NULL) { return false; }
35
36 /*----------------------------------------------------------------------------------------------------------------*/
37
38 while(*p == '+' || *p == '-' || *p == ' ' || *p == '#' || *p == '0') { p++; }
39
40 /*----------------------------------------------------------------------------------------------------------------*/
41
42 int w = 0;
43 int f = 0;
44
45 bool have_w = false;
46 bool have_f = false;
47
48 while(isdigit((unsigned char) *p)) { w = (w * 10) + (*p++ - '0'); have_w = true; }
49
50 if(*p == '.')
51 {
52 p++;
53
54 while(isdigit((unsigned char) *p)) { f = (f * 10) + (*p++ - '0'); have_f = true; }
55 }
56
57 /*----------------------------------------------------------------------------------------------------------------*/
58
59 if(*p == 'm')
60 {
61 /*------------------------------------------------------------------------------------------------------------*/
62
63 p++;
64
65 /*------------------------------------------------------------------------------------------------------------*/
66
67 if(*p != '\0') { return false; }
68
69 if(!have_w || !have_f) { return false; }
70
71 if(f != 3 && f != 5 && f != 6 && f != 8 && f != 9) { return false; }
72
73 /*------------------------------------------------------------------------------------------------------------*/
74
75 if(result_conv != NULL) { *result_conv = 'm'; }
76 if(result_lcnt != NULL) { *result_lcnt = 0 ; }
77 if(result_w != NULL) { *result_w = w ; }
78 if(result_f != NULL) { *result_f = f ; }
79
80 /*------------------------------------------------------------------------------------------------------------*/
81
82 return true;
83 }
84
85 /*----------------------------------------------------------------------------------------------------------------*/
86
87 int lcnt = 0;
88
89 if(*p == 'l') {
90 lcnt = 1; p++;
91 if(*p == 'l') {
92 lcnt = 2; p++;
93 }
94 }
95 else if(*p == 'h' || *p == 'j' || *p == 'z' || *p == 't' || *p == 'L')
96 {
97 return false;
98 }
99
100 /*----------------------------------------------------------------------------------------------------------------*/
101
102 if(*p == '\0') { return false; }
103
104 char conv = *p++; if(conv == 'n') { return false; }
105
106 if(*p != '\0') { return false; }
107
108 /*----------------------------------------------------------------------------------------------------------------*/
109
110 if(result_conv != NULL) { *result_conv = conv; }
111 if(result_lcnt != NULL) { *result_lcnt = lcnt; }
112 if(result_w != NULL) { *result_w = 0x00; }
113 if(result_f != NULL) { *result_f = 0x00; }
114
115 /*----------------------------------------------------------------------------------------------------------------*/
116
117 return true;
118}
119
120/*--------------------------------------------------------------------------------------------------------------------*/
121
122static double sextod(STR_t p)
123{
124 double deg;
125 double min;
126 double sec;
127
128 /*----------------------------------------------------------------------------------------------------------------*/
129
130 while(*p != '\0' && isspace((unsigned char) *p)) { p++; }
131
132 /*----------------------------------------------------------------------------------------------------------------*/
133
134 double sign = 1;
135
136 for(;;)
137 {
138 /**/ if(*p == '-') { sign *= -1; p++; }
139 else if(*p == '+') { sign *= +1; p++; }
140 else {
141 break;
142 }
143 }
144
145 /*----------------------------------------------------------------------------------------------------------------*/
146
147 str_t end1 = NULL;
148 deg = (double) strtol(p, &end1, 10);
149
150 if(p == end1) {
151 return NAN_double;
152 }
153 p = end1;
154
155 /*----------------------------------------------------------------------------------------------------------------*/
156
157 if(*p != ':') { return NAN_double; } p++;
158
159 /*----------------------------------------------------------------------------------------------------------------*/
160
161 STR_t colon = strchr(p, ':');
162
163 if(colon != NULL)
164 {
165 /*------------------------------------------------------------------------------------------------------------*/
166
167 str_t end2 = NULL;
168 min = (double) strtol(p, &end2, 10);
169
170 if(p == end2) {
171 return NAN_double;
172 }
173 p = end2;
174
175 /*------------------------------------------------------------------------------------------------------------*/
176
177 if(p != colon) { return NAN_double; } p++;
178
179 /*------------------------------------------------------------------------------------------------------------*/
180
181 str_t end3 = NULL;
182 sec = (double) strtod(p, &end3);
183
184 if(p == end3) {
185 return NAN_double;
186 }
187 p = end3;
188
189 /*------------------------------------------------------------------------------------------------------------*/
190 }
191 else
192 {
193 /*------------------------------------------------------------------------------------------------------------*/
194
195 str_t end4 = NULL;
196 min = (double) strtod(p, &end4);
197
198 if(p == end4) {
199 return NAN_double;
200 }
201 p = end4;
202
203 /*------------------------------------------------------------------------------------------------------------*/
204
205 sec = 0.0;
206
207 /*------------------------------------------------------------------------------------------------------------*/
208 }
209
210 /*----------------------------------------------------------------------------------------------------------------*/
211
212 while(*p != '\0' && isspace((unsigned char) *p)) { p++; }
213
214 /*----------------------------------------------------------------------------------------------------------------*/
215
216 if(*p != '\0') { return NAN_double; }
217
218 if(!(min >= 0.0 && min < 60.0)) { return NAN_double; }
219
220 if(!(sec >= 0.0 && sec < 60.0)) { return NAN_double; }
221
222 /*----------------------------------------------------------------------------------------------------------------*/
223
224 return sign * (deg + (min / 60.0) + (sec / 3600.0));
225
226 /*----------------------------------------------------------------------------------------------------------------*/
227}
228
229/*--------------------------------------------------------------------------------------------------------------------*/
230
231static int snprintm(str_t dst_str, size_t dst_len, int w, int f, double value)
232{
233 /*----------------------------------------------------------------------------------------------------------------*/
234
235 STR_t sign_str = signbit(value) ? "-"
236 : ""
237 ;
238
239 value = fabs(value);
240
241 /*----------------------------------------------------------------------------------------------------------------*/
242
243 int deg_i = (int) floor(value);
244
245 double frac_d = value - (double) deg_i;
246
247 /*----------------------------------------------------------------------------------------------------------------*/
248
249 char core[64];
250
251 switch(f)
252 {
253 case 3: /* :mm */
254 {
255 long m1 = lround(frac_d * 60.0);
256 int mm = (int) m1;
257
258 if(mm >= 60) { mm = 0; deg_i++; }
259
260 snprintf(core, sizeof(core), "%s%d:%02d", sign_str, deg_i, mm);
261 }
262 break;
263
264 case 5: /* :mm.m */
265 {
266 long m10 = lround(frac_d * 600.0);
267 int mm = (int) (m10 / 10);
268 int mm_t1 = (int) (m10 % 10);
269
270 if(mm >= 60) { mm = 0; deg_i++; }
271
272 snprintf(core, sizeof(core), "%s%d:%02d.%01d", sign_str, deg_i, mm, mm_t1);
273 }
274 break;
275
276 case 6: /* :mm:ss */
277 {
278 long s1 = lround(frac_d * 3600.0);
279 int mm = (int) (s1 / 60);
280 int ss = (int) (s1 % 60);
281
282 if(mm >= 60) { mm = 0; deg_i++; }
283
284 snprintf(core, sizeof(core), "%s%d:%02d:%02d", sign_str, deg_i, mm, ss);
285 }
286 break;
287
288 case 8: /* :mm:ss.s */
289 {
290 long s10 = lround(frac_d * 36000.0);
291 int mm = (int) (s10 / 600);
292 int ss = (int) (s10 % 600 / 10);
293 int ss_t1 = (int) (s10 % 10);
294
295 if(mm >= 60) { mm = 0; deg_i++; }
296
297 snprintf(core, sizeof(core), "%s%d:%02d:%02d.%01d", sign_str, deg_i, mm, ss, ss_t1);
298 }
299 break;
300
301 case 9: default: /* :mm:ss.ss */
302 {
303 long s100 = lround(frac_d * 360000.0);
304 int mm = (int) (s100 / 6000);
305 int ss = (int) (s100 % 6000 / 100);
306 int ss_t2 = (int) (s100 % 100);
307
308 if(mm >= 60) { mm = 0; deg_i++; }
309
310 snprintf(core, sizeof(core), "%s%d:%02d:%02d.%02d", sign_str, deg_i, mm, ss, ss_t2);
311 }
312 break;
313 }
314
315 /*----------------------------------------------------------------------------------------------------------------*/
316
317 if(w > 0) {
318 return snprintf(dst_str, dst_len, "%*s", w, core);
319 } else {
320 return snprintf(dst_str, dst_len, "%s", core);
321 }
322
323 /*----------------------------------------------------------------------------------------------------------------*/
324}
325
326/*--------------------------------------------------------------------------------------------------------------------*/
327/* NUMBER FORMATTER */
328/*--------------------------------------------------------------------------------------------------------------------*/
329
330str_t internal_variant_to_string(STR_t format, nyx_variant_t value)
331{
332 /*----------------------------------------------------------------------------------------------------------------*/
333
334 char conv;
335 int lcnt, w, f;
336
337 char buffer[64];
338
339 if(_parse_format(&conv, &lcnt, &w, &f, format))
340 {
341 int l;
342
343 /**/ if(lcnt == 1)
344 {
345 if(/* NOSONAR */ (value.type == NYX_VARIANT_TYPE_LONG && (conv == 'd' /*----------------------------------------------------------------------------------------------------*/) && (l = snprintf(buffer, sizeof(buffer), format, value.value._long)) >= 0)
346 /* NOSONAR */ ||
347 /* NOSONAR */ (value.type == NYX_VARIANT_TYPE_ULONG && (conv == 'u' || conv == 'o' || conv == 'x' || conv == 'X' /*-------------------------------------------------------*/) && (l = snprintf(buffer, sizeof(buffer), format, value.value._ulong)) >= 0)
348 /* NOSONAR */ ||
349 /* NOSONAR */ (value.type == NYX_VARIANT_TYPE_DOUBLE && (conv == 'f' || conv == 'F' || conv == 'e' || conv == 'E' || conv == 'g' || conv == 'G' || conv == 'a' || conv == 'A') && (l = snprintf(buffer, sizeof(buffer), format, value.value._double)) >= 0)
350 /* NOSONAR */ ||
351 /* NOSONAR */ (value.type == NYX_VARIANT_TYPE_DOUBLE && (conv == 'm' /*----------------------------------------------------------------------------------------------------*/) && (l = snprintm(buffer, sizeof(buffer), w, f, value.value._double)) >= 0)
352 ) {
353 if((size_t) l < sizeof(buffer))
354 {
355 for(int i = 0; i < l; i++) if(buffer[i] == ',') buffer[i] = '.';
356
357 return nyx_string_dup(buffer);
358 }
359 }
360 }
361 else if(lcnt == 0)
362 {
363 if(/* NOSONAR */ (value.type == NYX_VARIANT_TYPE_INT && (conv == 'd' /*----------------------------------------------------------------------------------------------------*/) && (l = snprintf(buffer, sizeof(buffer), format, value.value._int)) >= 0)
364 /* NOSONAR */ ||
365 /* NOSONAR */ (value.type == NYX_VARIANT_TYPE_UINT && (conv == 'u' || conv == 'o' || conv == 'x' || conv == 'X' /*-------------------------------------------------------*/) && (l = snprintf(buffer, sizeof(buffer), format, value.value._uint)) >= 0)
366 /* NOSONAR */ ||
367 /* NOSONAR */ (value.type == NYX_VARIANT_TYPE_DOUBLE && (conv == 'f' || conv == 'F' || conv == 'e' || conv == 'E' || conv == 'g' || conv == 'G' || conv == 'a' || conv == 'A') && (l = snprintf(buffer, sizeof(buffer), format, value.value._double)) >= 0)
368 /* NOSONAR */ ||
369 /* NOSONAR */ (value.type == NYX_VARIANT_TYPE_DOUBLE && (conv == 'm' /*----------------------------------------------------------------------------------------------------*/) && (l = snprintm(buffer, sizeof(buffer), w, f, value.value._double)) >= 0)
370 ) {
371 if((size_t) l < sizeof(buffer))
372 {
373 for(int i = 0; i < l; i++) if(buffer[i] == ',') buffer[i] = '.';
374
375 return nyx_string_dup(buffer);
376 }
377 }
378 }
379 }
380
381 /*----------------------------------------------------------------------------------------------------------------*/
382
383 NYX_LOG_ERROR("This function is not compatible with the format `%s`", format);
384
385 /*----------------------------------------------------------------------------------------------------------------*/
386
387 return nyx_string_dup("0");
388
389 /*----------------------------------------------------------------------------------------------------------------*/
390}
391
392/*--------------------------------------------------------------------------------------------------------------------*/
393
394nyx_variant_t internal_string_to_variant(STR_t format, STR_t value)
395{
396 char conv;
397 int lcnt;
398
399 if(_parse_format(&conv, &lcnt, NULL, NULL, format))
400 {
401 /*------------------------------------------------------------------------------------------------------------*/
402
403 if(conv == 'd')
404 {
405 return lcnt > 0 ? NYX_VARIANT_FROM_LONG((int64_t) strtol(value, NULL, 10))
406 : NYX_VARIANT_FROM_INT((int32_t) strtol(value, NULL, 10))
407 ;
408 }
409
410 /*------------------------------------------------------------------------------------------------------------*/
411
412 if(conv == 'u')
413 {
414 return lcnt > 0 ? NYX_VARIANT_FROM_ULONG((uint64_t) strtoul(value, NULL, 10))
415 : NYX_VARIANT_FROM_UINT((uint32_t) strtoul(value, NULL, 10))
416 ;
417 }
418
419 /*------------------------------------------------------------------------------------------------------------*/
420
421 if(conv == 'o')
422 {
423 return lcnt > 0 ? NYX_VARIANT_FROM_ULONG((uint64_t) strtoul(value, NULL, 8))
424 : NYX_VARIANT_FROM_UINT((uint32_t) strtoul(value, NULL, 8))
425 ;
426 }
427
428 /*------------------------------------------------------------------------------------------------------------*/
429
430 if(conv == 'x' || conv == 'X')
431 {
432 return lcnt > 0 ? NYX_VARIANT_FROM_ULONG((uint64_t) strtoul(value, NULL, 16))
433 : NYX_VARIANT_FROM_UINT((uint32_t) strtoul(value, NULL, 16))
434 ;
435 }
436
437 /*------------------------------------------------------------------------------------------------------------*/
438
439 if(conv == 'f' || conv == 'F' || conv == 'e' || conv == 'E' || conv == 'g' || conv == 'G' || conv == 'a' || conv == 'A')
440 {
441 return NYX_VARIANT_FROM_DOUBLE(strtod(value, NULL));
442 }
443
444 if(conv == 'm' /*----------------------------------------------------------------------------------------------------*/)
445 {
446 return NYX_VARIANT_FROM_DOUBLE(sextod(value));
447 }
448
449 /*------------------------------------------------------------------------------------------------------------*/
450 }
451
452 NYX_LOG_ERROR("This function is not compatible with the format `%s`", format);
453
454 return NYX_VARIANT_FROM_INT(0);
455}
456
457/*--------------------------------------------------------------------------------------------------------------------*/
#define NYX_LOG_ERROR(fmt,...)
Logs an error message.
Definition nyx_node.h:219
#define STR_t
Alias for const char *.
Definition nyx_node.h:71
__NYX_NULLABLE__ str_t nyx_string_dup(__NYX_NULLABLE__ STR_t s)
Similar to libc strdup.
#define str_t
Alias for char *.
Definition nyx_node.h:70