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