scan.c 9.5 KB

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