GRASS Programmer's Manual
6.4.2(2012)
|
00001 /* 00002 * Copyright (C) 1995. Bill Brown <brown@gis.uiuc.edu> & Michael Shapiro 00003 * 00004 * This program is free software under the GPL (>=v2) 00005 * Read the file GPL.TXT coming with GRASS for details. 00006 */ 00007 #include <stdio.h> 00008 #include <string.h> 00009 #include <grass/datetime.h> 00010 00011 00012 static int scan_absolute(DateTime *, const char *); 00013 static int more(const char **); 00014 static int minus_sign(const char **); 00015 static int is_bc(const char **); 00016 static int is_relative(const char *); 00017 static int relative_term(const char **, double *, int *, int *, int *); 00018 static int scan_tz(const char *, int *); 00019 static int get_word(const char **, char *); 00020 static char lowercase(char); 00021 static int which_month(const char *, int *); 00022 static int scan_relative(DateTime *, const char *); 00023 static int is_space(char); 00024 static int is_digit(char); 00025 static void skip_space(const char **); 00026 static int get_int(const char **, int *, int *); 00027 static int get_double(const char **, double *, int *, int *); 00028 00029 00043 int datetime_scan(DateTime * dt, const char *buf) 00044 { 00045 if (is_relative(buf)) { 00046 if (scan_relative(dt, buf)) 00047 return 0; 00048 return datetime_error(-1, "Invalid interval datetime format"); 00049 } 00050 if (scan_absolute(dt, buf)) 00051 return 0; 00052 return datetime_error(-2, "Invalid absolute datetime format"); 00053 } 00054 00055 static const char *month_names[] = { 00056 "jan", "feb", "mar", "apr", "may", "jun", 00057 "jul", "aug", "sep", "oct", "nov", "dec" 00058 }; 00059 00060 static int scan_absolute(DateTime * dt, const char *buf) 00061 { 00062 char word[1024]; 00063 int n; 00064 int ndigits; 00065 int tz = 0; 00066 int have_tz = 0; 00067 int bc = 0; 00068 int to, fracsec = 0; 00069 int year, month, day = 0, hour, minute; 00070 double second; 00071 const char *p; 00072 00073 p = buf; 00074 if (!more(&p)) 00075 return 0; 00076 00077 if (!get_int(&p, &n, &ndigits)) { /* no day, so must be month, like Jan */ 00078 if (!get_word(&p, word)) 00079 return 0; 00080 if (!which_month(word, &month)) 00081 return 0; 00082 if (!get_int(&p, &year, &ndigits)) /* year following the month */ 00083 return 0; 00084 to = DATETIME_MONTH; 00085 if (is_bc(&p)) 00086 bc = 1; 00087 goto set; 00088 } 00089 00090 bc = is_bc(&p); 00091 if (bc || !get_word(&p, word)) { /* just a year */ 00092 year = n; 00093 to = DATETIME_YEAR; 00094 goto set; 00095 } 00096 to = DATETIME_DAY; /* must be at least: day Mon year [bc] */ 00097 day = n; 00098 if (!which_month(word, &month)) 00099 return 0; 00100 if (!get_int(&p, &year, &ndigits)) 00101 return 0; 00102 if (is_bc(&p)) 00103 bc = 1; 00104 00105 /* now for the time */ 00106 if (!get_int(&p, &hour, &ndigits)) 00107 goto set; 00108 to = DATETIME_HOUR; 00109 if (*p != ':') 00110 goto set; 00111 p++; 00112 if (!get_int(&p, &minute, &ndigits)) 00113 return 0; 00114 if (ndigits != 2) 00115 return 0; 00116 to = DATETIME_MINUTE; 00117 if (*p != ':') 00118 goto timezone; 00119 p++; 00120 if (!get_double(&p, &second, &ndigits, &fracsec)) 00121 return 0; 00122 if (ndigits != 2) 00123 return 0; 00124 to = DATETIME_SECOND; 00125 00126 timezone: 00127 if (!get_word(&p, word)) 00128 goto set; 00129 if (!scan_tz(word, &tz)) 00130 return 0; 00131 have_tz = 1; 00132 00133 set: 00134 if (more(&p)) /* make sure there isn't anything else */ 00135 return 0; 00136 if (datetime_set_type(dt, DATETIME_ABSOLUTE, DATETIME_YEAR, to, fracsec)) 00137 return 0; 00138 for (n = DATETIME_YEAR; n <= to; n++) { 00139 switch (n) { 00140 case DATETIME_YEAR: 00141 if (datetime_set_year(dt, year)) 00142 return 0; 00143 break; 00144 case DATETIME_MONTH: 00145 if (datetime_set_month(dt, month)) 00146 return 0; 00147 break; 00148 case DATETIME_DAY: 00149 if (datetime_set_day(dt, day)) 00150 return 0; 00151 break; 00152 case DATETIME_HOUR: 00153 if (datetime_set_hour(dt, hour)) 00154 return 0; 00155 break; 00156 case DATETIME_MINUTE: 00157 if (datetime_set_minute(dt, minute)) 00158 return 0; 00159 break; 00160 case DATETIME_SECOND: 00161 if (datetime_set_second(dt, second)) 00162 return 0; 00163 break; 00164 } 00165 } 00166 if (bc) 00167 datetime_set_negative(dt); 00168 if (have_tz && datetime_set_timezone(dt, tz)) 00169 return 0; 00170 00171 return 1; 00172 } 00173 00174 00175 static int scan_relative(DateTime * dt, const char *buf) 00176 { 00177 const char *p; 00178 double x; 00179 int ndigits, ndecimal; 00180 int pos; 00181 int neg = 0; 00182 int year = 0, month = 0, day = 0, hour = 0, minute = 0, fracsec = 0; 00183 double second = 0.0; 00184 int from = DATETIME_SECOND + 1, to = DATETIME_YEAR - 1; 00185 00186 p = buf; 00187 neg = minus_sign(&p); 00188 if (!more(&p)) 00189 return 0; 00190 00191 while (relative_term(&p, &x, &ndigits, &ndecimal, &pos)) { 00192 if (from > pos) 00193 from = pos; 00194 if (to < pos) 00195 to = pos; 00196 00197 if (pos != DATETIME_SECOND && ndecimal != 0) 00198 return 0; 00199 00200 switch (pos) { 00201 case DATETIME_YEAR: 00202 year = (int)x; 00203 break; 00204 case DATETIME_MONTH: 00205 month = (int)x; 00206 break; 00207 case DATETIME_DAY: 00208 day = (int)x;; 00209 break; 00210 case DATETIME_HOUR: 00211 hour = (int)x; 00212 break; 00213 case DATETIME_MINUTE: 00214 minute = (int)x; 00215 break; 00216 case DATETIME_SECOND: 00217 second = x; 00218 fracsec = ndecimal; 00219 break; 00220 } 00221 00222 } 00223 00224 if (more(&p)) /* make sure there isn't anything else */ 00225 return 0; 00226 if (datetime_set_type(dt, DATETIME_RELATIVE, from, to, fracsec)) 00227 return 0; 00228 for (pos = from; pos <= to; pos++) { 00229 switch (pos) { 00230 case DATETIME_YEAR: 00231 if (datetime_set_year(dt, year)) 00232 return 0; 00233 break; 00234 case DATETIME_MONTH: 00235 if (datetime_set_month(dt, month)) 00236 return 0; 00237 break; 00238 case DATETIME_DAY: 00239 if (datetime_set_day(dt, day)) 00240 return 0; 00241 break; 00242 case DATETIME_HOUR: 00243 if (datetime_set_hour(dt, hour)) 00244 return 0; 00245 break; 00246 case DATETIME_MINUTE: 00247 if (datetime_set_minute(dt, minute)) 00248 return 0; 00249 break; 00250 case DATETIME_SECOND: 00251 if (datetime_set_second(dt, second)) 00252 return 0; 00253 break; 00254 } 00255 } 00256 if (neg) 00257 datetime_set_negative(dt); 00258 00259 return 1; 00260 } 00261 00262 static int is_space(char c) 00263 { 00264 return (c == ' ' || c == '\t' || c == '\n'); 00265 } 00266 00267 static int is_digit(char c) 00268 { 00269 return (c >= '0' && c <= '9'); 00270 } 00271 00272 static void skip_space(const char **s) 00273 { 00274 while (is_space(**s)) 00275 (*s)++; 00276 } 00277 00278 static int get_int(const char **s, int *n, int *ndigits) 00279 { 00280 const char *p; 00281 00282 *n = 0; 00283 skip_space(s); 00284 p = *s; 00285 for (*ndigits = 0; is_digit(*p); (*ndigits)++) { 00286 *n *= 10; 00287 *n += *p - '0'; 00288 p++; 00289 } 00290 if (*ndigits > 0) 00291 *s = p; 00292 return (*ndigits > 0); 00293 } 00294 00295 static int get_double(const char **s, double *x, int *ndigits, /* number of digits before decimal */ 00296 int *ndecimal) 00297 { /* number of decimal places */ 00298 char buf[1024]; 00299 char *b; 00300 const char *p; 00301 00302 skip_space(s); 00303 00304 p = *s; 00305 *ndecimal = 0; 00306 b = buf; 00307 00308 for (*ndigits = 0; is_digit(*p); (*ndigits)++) 00309 *b++ = *p++; 00310 if (*p == '.') { 00311 *b++ = *p++; 00312 while (is_digit(*p)) { 00313 *b++ = *p++; 00314 (*ndecimal)++; 00315 } 00316 } 00317 *b = 0; 00318 if (sscanf(buf, "%lf", x) != 1) 00319 return 0; 00320 *s = p; 00321 return 1; 00322 } 00323 00324 00325 /* if pos is non-zero, *(p-1) must be legal */ 00326 /* 00327 static int 00328 is_wordend (pos, p) 00329 int pos; 00330 char *p; 00331 { 00332 int d1, d0; 00333 00334 if ('\0'==(*p)) return (1); 00335 if (is_space(*p)) return (1); 00336 if (pos){ 00337 d0 = is_digit(*(p-1)); 00338 d1 = is_digit(*p); 00339 return(d0 != d1); 00340 } 00341 return (0); 00342 00343 } 00344 */ 00345 00346 /* get a word (between white space) and convert to lowercase */ 00347 static int get_word(const char **s, char *word) 00348 { 00349 const char *p; 00350 int any; 00351 00352 skip_space(s); 00353 p = *s; 00354 for (any = 0; *p && !is_space(*p); any = 1) 00355 *word++ = lowercase(*p++); 00356 *word = 0; 00357 *s = p; 00358 return any; 00359 } 00360 00361 static char lowercase(char c) 00362 { 00363 if (c >= 'A' && c <= 'Z') 00364 c += 'a' - 'A'; 00365 return c; 00366 } 00367 00368 static int which_month(const char *name, int *n) 00369 { 00370 int i; 00371 00372 for (i = 0; i < 12; i++) 00373 if (strcmp(name, month_names[i]) == 0) { 00374 *n = i + 1; 00375 return 1; 00376 } 00377 return 0; 00378 } 00379 00380 static int is_bc(const char **s) 00381 { 00382 const char *p; 00383 char word[1024]; 00384 00385 p = *s; 00386 if (!get_word(&p, word)) 00387 return 0; 00388 if (strcmp("bc", word) != 0) 00389 return 0; 00390 *s = p; 00391 return 1; 00392 } 00393 00394 static int scan_tz(const char *word, int *tz) 00395 { 00396 int neg = 0; 00397 00398 if (word[0] == '+') 00399 neg = 0; 00400 else if (word[0] == '-') 00401 neg = 1; 00402 else 00403 return 0; 00404 00405 if (!is_digit(word[1])) 00406 return 0; 00407 if (!is_digit(word[2])) 00408 return 0; 00409 if (!is_digit(word[3])) 00410 return 0; 00411 if (!is_digit(word[4])) 00412 return 0; 00413 00414 *tz = (word[1] - '0') * 600 + (word[2] - '0') * 60 + 00415 (word[3] - '0') * 10 + (word[4] - '0'); 00416 if (neg) 00417 *tz = -(*tz); 00418 return 1; 00419 } 00420 00421 /* returns 00422 0 not a recognized term 00423 1 valid term, but perhaps illiegal value 00424 */ 00425 static int relative_term(const char **s, 00426 double *x, int *ndigits, int *ndecimal, int *pos) 00427 { 00428 char word[1024]; 00429 const char *p; 00430 00431 p = *s; 00432 if (!get_double(&p, x, ndigits, ndecimal) || !get_word(&p, word)) 00433 return 0; 00434 00435 if (strcmp(word, "year") == 0 || strcmp(word, "years") == 0) 00436 *pos = DATETIME_YEAR; 00437 else if (strcmp(word, "month") == 0 || strcmp(word, "months") == 0 || 00438 strcmp(word, "mon") == 0) 00439 *pos = DATETIME_MONTH; 00440 else if (strcmp(word, "day") == 0 || strcmp(word, "days") == 0) 00441 *pos = DATETIME_DAY; 00442 else if (strcmp(word, "hour") == 0 || strcmp(word, "hours") == 0) 00443 *pos = DATETIME_HOUR; 00444 else if (strcmp(word, "minute") == 0 || strcmp(word, "minutes") == 0 || 00445 strcmp(word, "min") == 0) 00446 *pos = DATETIME_MINUTE; 00447 else if (strcmp(word, "second") == 0 || strcmp(word, "seconds") == 0 || 00448 strcmp(word, "sec") == 0) 00449 *pos = DATETIME_SECOND; 00450 else 00451 return 0; 00452 *s = p; 00453 return 1; 00454 } 00455 00456 static int minus_sign(const char **s) 00457 { 00458 skip_space(s); 00459 if (**s == '-') { 00460 (*s)++; 00461 return 1; 00462 } 00463 return 0; 00464 } 00465 00466 static int is_relative(const char *buf) 00467 { 00468 int n; 00469 double x; 00470 const char *p; 00471 00472 p = buf; 00473 (void)minus_sign(&p); 00474 return relative_term(&p, &x, &n, &n, &n) != 0; 00475 } 00476 00477 static int more(const char **s) 00478 { 00479 skip_space(s); 00480 return **s != 0; 00481 }