GRASS GIS 8 Programmer's Manual 8.4.1(2025)-45ca3179ab
Loading...
Searching...
No Matches
scan.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 1995. Bill Brown <brown@gis.uiuc.edu> & Michael Shapiro
3 *
4 * This program is free software under the GPL (>=v2)
5 * Read the file GPL.TXT coming with GRASS for details.
6 */
7#include <stdio.h>
8#include <string.h>
9#include <grass/datetime.h>
10
11static int scan_absolute(DateTime *, const char *);
12static int more(const char **);
13static int minus_sign(const char **);
14static int is_bc(const char **);
15static int is_relative(const char *);
16static int relative_term(const char **, double *, int *, int *, int *);
17static int scan_tz(const char *, int *);
18static int get_word(const char **, char *);
19static char lowercase(char);
20static int which_month(const char *, int *);
21static int scan_relative(DateTime *, const char *);
22static int is_space(char);
23static int is_digit(char);
24static void skip_space(const char **);
25static int get_int(const char **, int *, int *);
26static int get_double(const char **, double *, int *, int *);
27
28/*!
29 * \brief
30 *
31 * Convert the ascii string
32 * into a DateTime. This determines the mode/from/to based on the string, inits
33 * 'dt' and then sets values in 'dt' based on the [???]
34 * Returns 0 if 'string' is legal, -1 if not.
35 *
36 * \param dt
37 * \param buf
38 * \return int
39 */
40
41int datetime_scan(DateTime *dt, const char *buf)
42{
43 if (is_relative(buf)) {
44 if (scan_relative(dt, buf))
45 return 0;
46 return datetime_error(-1, "Invalid interval datetime format");
47 }
48 if (scan_absolute(dt, buf))
49 return 0;
50 return datetime_error(-2, "Invalid absolute datetime format");
51}
52
53static const char *month_names[] = {"jan", "feb", "mar", "apr", "may", "jun",
54 "jul", "aug", "sep", "oct", "nov", "dec"};
55
56static int scan_absolute(DateTime *dt, const char *buf)
57{
58 char word[1024];
59 int n;
60 int ndigits;
61 int tz = 0;
62 int have_tz = 0;
63 int bc = 0;
64 int to, fracsec = 0;
65 int year, month, day = 0, hour, minute;
66 double second;
67 const char *p;
68
69 p = buf;
70 if (!more(&p))
71 return 0;
72
73 if (!get_int(&p, &n, &ndigits)) { /* no day, so must be month, like Jan */
74 if (!get_word(&p, word))
75 return 0;
76 if (!which_month(word, &month))
77 return 0;
78 if (!get_int(&p, &year, &ndigits)) /* year following the month */
79 return 0;
80 to = DATETIME_MONTH;
81 if (is_bc(&p))
82 bc = 1;
83 goto set;
84 }
85
86 bc = is_bc(&p);
87 if (bc || !get_word(&p, word)) { /* just a year */
88 year = n;
89 to = DATETIME_YEAR;
90 goto set;
91 }
92 to = DATETIME_DAY; /* must be at least: day Mon year [bc] */
93 day = n;
94 if (!which_month(word, &month))
95 return 0;
96 if (!get_int(&p, &year, &ndigits))
97 return 0;
98 if (is_bc(&p))
99 bc = 1;
100
101 /* now for the time */
102 if (!get_int(&p, &hour, &ndigits))
103 goto set;
104 to = DATETIME_HOUR;
105 if (*p != ':')
106 goto set;
107 p++;
108 if (!get_int(&p, &minute, &ndigits))
109 return 0;
110 if (ndigits != 2)
111 return 0;
112 to = DATETIME_MINUTE;
113 if (*p != ':')
114 goto timezone;
115 p++;
116 if (!get_double(&p, &second, &ndigits, &fracsec))
117 return 0;
118 if (ndigits != 2)
119 return 0;
120 to = DATETIME_SECOND;
121
122timezone:
123 if (!get_word(&p, word))
124 goto set;
125 if (!scan_tz(word, &tz))
126 return 0;
127 have_tz = 1;
128
129set:
130 if (more(&p)) /* make sure there isn't anything else */
131 return 0;
132 if (datetime_set_type(dt, DATETIME_ABSOLUTE, DATETIME_YEAR, to, fracsec))
133 return 0;
134 for (n = DATETIME_YEAR; n <= to; n++) {
135 switch (n) {
136 case DATETIME_YEAR:
137 if (datetime_set_year(dt, year))
138 return 0;
139 break;
140 case DATETIME_MONTH:
141 if (datetime_set_month(dt, month))
142 return 0;
143 break;
144 case DATETIME_DAY:
145 if (datetime_set_day(dt, day))
146 return 0;
147 break;
148 case DATETIME_HOUR:
149 if (datetime_set_hour(dt, hour))
150 return 0;
151 break;
152 case DATETIME_MINUTE:
153 if (datetime_set_minute(dt, minute))
154 return 0;
155 break;
156 case DATETIME_SECOND:
157 if (datetime_set_second(dt, second))
158 return 0;
159 break;
160 }
161 }
162 if (bc)
164 if (have_tz && datetime_set_timezone(dt, tz))
165 return 0;
166
167 return 1;
168}
169
170static int scan_relative(DateTime *dt, const char *buf)
171{
172 const char *p;
173 double x;
174 int ndigits, ndecimal;
175 int pos;
176 int neg = 0;
177 int year = 0, month = 0, day = 0, hour = 0, minute = 0, fracsec = 0;
178 double second = 0.0;
179 int from = DATETIME_SECOND + 1, to = DATETIME_YEAR - 1;
180
181 p = buf;
182 neg = minus_sign(&p);
183 if (!more(&p))
184 return 0;
185
186 while (relative_term(&p, &x, &ndigits, &ndecimal, &pos)) {
187 if (from > pos)
188 from = pos;
189 if (to < pos)
190 to = pos;
191
192 if (pos != DATETIME_SECOND && ndecimal != 0)
193 return 0;
194
195 switch (pos) {
196 case DATETIME_YEAR:
197 year = (int)x;
198 break;
199 case DATETIME_MONTH:
200 month = (int)x;
201 break;
202 case DATETIME_DAY:
203 day = (int)x;
204 ;
205 break;
206 case DATETIME_HOUR:
207 hour = (int)x;
208 break;
209 case DATETIME_MINUTE:
210 minute = (int)x;
211 break;
212 case DATETIME_SECOND:
213 second = x;
214 fracsec = ndecimal;
215 break;
216 }
217 }
218
219 if (more(&p)) /* make sure there isn't anything else */
220 return 0;
221 if (datetime_set_type(dt, DATETIME_RELATIVE, from, to, fracsec))
222 return 0;
223 for (pos = from; pos <= to; pos++) {
224 switch (pos) {
225 case DATETIME_YEAR:
226 if (datetime_set_year(dt, year))
227 return 0;
228 break;
229 case DATETIME_MONTH:
230 if (datetime_set_month(dt, month))
231 return 0;
232 break;
233 case DATETIME_DAY:
234 if (datetime_set_day(dt, day))
235 return 0;
236 break;
237 case DATETIME_HOUR:
238 if (datetime_set_hour(dt, hour))
239 return 0;
240 break;
241 case DATETIME_MINUTE:
242 if (datetime_set_minute(dt, minute))
243 return 0;
244 break;
245 case DATETIME_SECOND:
246 if (datetime_set_second(dt, second))
247 return 0;
248 break;
249 }
250 }
251 if (neg)
253
254 return 1;
255}
256
257static int is_space(char c)
258{
259 return (c == ' ' || c == '\t' || c == '\n');
260}
261
262static int is_digit(char c)
263{
264 return (c >= '0' && c <= '9');
265}
266
267static void skip_space(const char **s)
268{
269 while (is_space(**s))
270 (*s)++;
271}
272
273static int get_int(const char **s, int *n, int *ndigits)
274{
275 const char *p;
276
277 *n = 0;
278 skip_space(s);
279 p = *s;
280 for (*ndigits = 0; is_digit(*p); (*ndigits)++) {
281 *n *= 10;
282 *n += *p - '0';
283 p++;
284 }
285 if (*ndigits > 0)
286 *s = p;
287 return (*ndigits > 0);
288}
289
290static int get_double(const char **s, double *x,
291 int *ndigits, /* number of digits before decimal */
292 int *ndecimal)
293{ /* number of decimal places */
294 char buf[1024];
295 char *b;
296 const char *p;
297
298 skip_space(s);
299
300 p = *s;
301 *ndecimal = 0;
302 b = buf;
303
304 for (*ndigits = 0; is_digit(*p); (*ndigits)++)
305 *b++ = *p++;
306 if (*p == '.') {
307 *b++ = *p++;
308 while (is_digit(*p)) {
309 *b++ = *p++;
310 (*ndecimal)++;
311 }
312 }
313 *b = 0;
314 if (sscanf(buf, "%lf", x) != 1)
315 return 0;
316 *s = p;
317 return 1;
318}
319
320/* if pos is non-zero, *(p-1) must be legal */
321/*
322 static int
323 is_wordend (pos, p)
324 int pos;
325 char *p;
326 {
327 int d1, d0;
328
329 if ('\0'==(*p)) return (1);
330 if (is_space(*p)) return (1);
331 if (pos){
332 d0 = is_digit(*(p-1));
333 d1 = is_digit(*p);
334 return(d0 != d1);
335 }
336 return (0);
337
338 }
339 */
340
341/* get a word (between white space) and convert to lowercase */
342static int get_word(const char **s, char *word)
343{
344 const char *p;
345 int any;
346
347 skip_space(s);
348 p = *s;
349 for (any = 0; *p && !is_space(*p); any = 1)
350 *word++ = lowercase(*p++);
351 *word = 0;
352 *s = p;
353 return any;
354}
355
356static char lowercase(char c)
357{
358 if (c >= 'A' && c <= 'Z')
359 c += 'a' - 'A';
360 return c;
361}
362
363static int which_month(const char *name, int *n)
364{
365 int i;
366
367 for (i = 0; i < 12; i++)
368 if (strcmp(name, month_names[i]) == 0) {
369 *n = i + 1;
370 return 1;
371 }
372 return 0;
373}
374
375static int is_bc(const char **s)
376{
377 const char *p;
378 char word[1024];
379
380 p = *s;
381 if (!get_word(&p, word))
382 return 0;
383 if (strcmp("bc", word) != 0)
384 return 0;
385 *s = p;
386 return 1;
387}
388
389static int scan_tz(const char *word, int *tz)
390{
391 int neg = 0;
392
393 if (word[0] == '+')
394 neg = 0;
395 else if (word[0] == '-')
396 neg = 1;
397 else
398 return 0;
399
400 if (!is_digit(word[1]))
401 return 0;
402 if (!is_digit(word[2]))
403 return 0;
404 if (!is_digit(word[3]))
405 return 0;
406 if (!is_digit(word[4]))
407 return 0;
408
409 *tz = (word[1] - '0') * 600 + (word[2] - '0') * 60 + (word[3] - '0') * 10 +
410 (word[4] - '0');
411 if (neg)
412 *tz = -(*tz);
413 return 1;
414}
415
416/* returns
417 0 not a recognized term
418 1 valid term, but perhaps illegal value
419 */
420static int relative_term(const char **s, double *x, int *ndigits, int *ndecimal,
421 int *pos)
422{
423 char word[1024];
424 const char *p;
425
426 p = *s;
427 if (!get_double(&p, x, ndigits, ndecimal) || !get_word(&p, word))
428 return 0;
429
430 if (strcmp(word, "year") == 0 || strcmp(word, "years") == 0)
431 *pos = DATETIME_YEAR;
432 else if (strcmp(word, "month") == 0 || strcmp(word, "months") == 0 ||
433 strcmp(word, "mon") == 0)
434 *pos = DATETIME_MONTH;
435 else if (strcmp(word, "day") == 0 || strcmp(word, "days") == 0)
436 *pos = DATETIME_DAY;
437 else if (strcmp(word, "hour") == 0 || strcmp(word, "hours") == 0)
438 *pos = DATETIME_HOUR;
439 else if (strcmp(word, "minute") == 0 || strcmp(word, "minutes") == 0 ||
440 strcmp(word, "min") == 0)
441 *pos = DATETIME_MINUTE;
442 else if (strcmp(word, "second") == 0 || strcmp(word, "seconds") == 0 ||
443 strcmp(word, "sec") == 0)
444 *pos = DATETIME_SECOND;
445 else
446 return 0;
447 *s = p;
448 return 1;
449}
450
451static int minus_sign(const char **s)
452{
453 skip_space(s);
454 if (**s == '-') {
455 (*s)++;
456 return 1;
457 }
458 return 0;
459}
460
461static int is_relative(const char *buf)
462{
463 int n;
464 double x;
465 const char *p;
466
467 p = buf;
468 (void)minus_sign(&p);
469 return relative_term(&p, &x, &n, &n, &n) != 0;
470}
471
472static int more(const char **s)
473{
474 skip_space(s);
475 return **s != 0;
476}
int datetime_error(int code, char *msg)
record 'code' and 'msg' as error code/msg (in static variables) code==0 will clear the error (ie set ...
double b
const char * name
Definition named_colr.c:6
int datetime_scan(DateTime *dt, const char *buf)
Convert the ascii string into a DateTime. This determines the mode/from/to based on the string,...
Definition scan.c:41
void datetime_set_negative(DateTime *dt)
Makes the DateTime negative. (B.C. for ABSOLUTE DateTimes)
Definition sign.c:64
int datetime_set_type(DateTime *dt, int mode, int from, int to, int fracsec)
Definition type.c:36
int datetime_set_timezone(DateTime *dt, int minutes)
returns 0 on success
Definition tz1.c:67
int datetime_set_day(DateTime *dt, int day)
if dt.mode = ABSOLUTE, then the dt.year, dt.month:
Definition values.c:340
int datetime_set_month(DateTime *dt, int month)
if dt.mode = ABSOLUTE, this also sets dt.day = 0
Definition values.c:288
int datetime_set_hour(DateTime *dt, int hour)
returns 0 on success or negative value on error
Definition values.c:382
int datetime_set_year(DateTime *dt, int year)
if dt.mode = ABSOLUTE, this also sets dt.day = 0
Definition values.c:241
int datetime_set_second(DateTime *dt, double second)
returns 0 on success or negative value on error
Definition values.c:466
int datetime_set_minute(DateTime *dt, int minute)
returns 0 on success or negative value on error
Definition values.c:424
#define x