GRASS Programmer's Manual  6.4.2(2012)
scan.c
Go to the documentation of this file.
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 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines