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