diff options
| author | Rafael G. Martins <rafael@rafaelmartins.eng.br> | 2015-10-24 18:47:41 -0200 | 
|---|---|---|
| committer | Rafael G. Martins <rafael@rafaelmartins.eng.br> | 2015-10-24 18:47:41 -0200 | 
| commit | 7127defbaa3701fc3444feb3233401e2829fc1b6 (patch) | |
| tree | 452d47a9ee63dcdbc2ba4c0bee9b562af483233f /src | |
| parent | 3a5ea19f35e4228cd782d69f21f52656c1e9a1b8 (diff) | |
| download | blogc-7127defbaa3701fc3444feb3233401e2829fc1b6.tar.gz blogc-7127defbaa3701fc3444feb3233401e2829fc1b6.tar.bz2 blogc-7127defbaa3701fc3444feb3233401e2829fc1b6.zip | |
datetime-parser: initial implementation. not used yet
Diffstat (limited to 'src')
| -rw-r--r-- | src/datetime-parser.c | 375 | ||||
| -rw-r--r-- | src/datetime-parser.h | 17 | ||||
| -rw-r--r-- | src/error.c | 3 | ||||
| -rw-r--r-- | src/error.h | 1 | 
4 files changed, 396 insertions, 0 deletions
| diff --git a/src/datetime-parser.c b/src/datetime-parser.c new file mode 100644 index 0000000..1d39490 --- /dev/null +++ b/src/datetime-parser.c @@ -0,0 +1,375 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2015 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#ifdef HAVE_TIME_H +#include <time.h> +#endif /* HAVE_TIME_H */ + +#include <string.h> +#include <stdio.h> + +#include "error.h" +#include "utils/utils.h" +#include "datetime-parser.h" + + +typedef enum { +    DATETIME_FIRST_YEAR = 1, +    DATETIME_SECOND_YEAR, +    DATETIME_THIRD_YEAR, +    DATETIME_FOURTH_YEAR, +    DATETIME_FIRST_HYPHEN, +    DATETIME_FIRST_MONTH, +    DATETIME_SECOND_MONTH, +    DATETIME_SECOND_HYPHEN, +    DATETIME_FIRST_DAY, +    DATETIME_SECOND_DAY, +    DATETIME_SPACE, +    DATETIME_FIRST_HOUR, +    DATETIME_SECOND_HOUR, +    DATETIME_FIRST_COLON, +    DATETIME_FIRST_MINUTE, +    DATETIME_SECOND_MINUTE, +    DATETIME_SECOND_COLON, +    DATETIME_FIRST_SECOND, +    DATETIME_SECOND_SECOND, +    DATETIME_DONE, +} blogc_datetime_state_t; + + +char* +blogc_convert_datetime(const char *orig, const char *format, +    blogc_error_t **err) +{ +    if (err == NULL || *err != NULL) +        return NULL; + +    struct tm t; +    memset(&t, 0, sizeof(struct tm)); +    t.tm_isdst = -1; + +    blogc_datetime_state_t state = DATETIME_FIRST_YEAR; +    int tmp = 0; +    int diff = '0'; + +    for (unsigned int i = 0; orig[i] != '\0'; i++) { +        char c = orig[i]; + +        switch (state) { + +            case DATETIME_FIRST_YEAR: +                if (c >= '0' && c <= '9') { +                    tmp += (c - diff) * 1000; +                    state = DATETIME_SECOND_YEAR; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid first digit of year. " +                    "Found '%c', must be integer >= 0 and <= 9.", c); +                break; + +            case DATETIME_SECOND_YEAR: +                if (c >= '0' && c <= '9') { +                    tmp += (c - diff) * 100; +                    state = DATETIME_THIRD_YEAR; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid second digit of year. " +                    "Found '%c', must be integer >= 0 and <= 9.", c); +                break; + +            case DATETIME_THIRD_YEAR: +                if (c >= '0' && c <= '9') { +                    tmp += (c - diff) * 10; +                    state = DATETIME_FOURTH_YEAR; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid third digit of year. " +                    "Found '%c', must be integer >= 0 and <= 9.", c); +                break; + +            case DATETIME_FOURTH_YEAR: +                if (c >= '0' && c <= '9') { +                    tmp += c - diff - 1900; +                    if (tmp < 0) { +                        *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                            "Invalid year. Found %d, must be >= 1900.", +                            tmp + 1900); +                        break; +                    } +                    t.tm_year = tmp; +                    state = DATETIME_FIRST_HYPHEN; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid fourth digit of year. " +                    "Found '%c', must be integer >= 0 and <= 9.", c); +                break; + +            case DATETIME_FIRST_HYPHEN: +                if (c == '-') { +                    tmp = 0; +                    state = DATETIME_FIRST_MONTH; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid separator between year and month. " +                    "Found '%c', must be '-'.", c); +                break; + +            case DATETIME_FIRST_MONTH: +                if (c >= '0' && c <= '1') { +                    tmp += (c - diff) * 10; +                    state = DATETIME_SECOND_MONTH; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid first digit of month. " +                    "Found '%c', must be integer >= 0 and <= 1.", c); +                break; + +            case DATETIME_SECOND_MONTH: +                if (c >= '0' && c <= '9') { +                    tmp += c - diff - 1; +                    if (tmp < 0 || tmp > 11) { +                        *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                            "Invalid month. Found %d, must be >= 1 and <= 12.", +                            tmp + 1); +                        break; +                    } +                    t.tm_mon = tmp; +                    state = DATETIME_SECOND_HYPHEN; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid second digit of month. " +                    "Found '%c', must be integer >= 0 and <= 9.", c); +                break; + +            case DATETIME_SECOND_HYPHEN: +                if (c == '-') { +                    tmp = 0; +                    state = DATETIME_FIRST_DAY; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid separator between month and day. " +                    "Found '%c', must be '-'.", c); +                break; + +            case DATETIME_FIRST_DAY: +                if (c >= '0' && c <= '3') { +                    tmp += (c - diff) * 10; +                    state = DATETIME_SECOND_DAY; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid first digit of day. " +                    "Found '%c', must be integer >= 0 and <= 3.", c); +                break; + +            case DATETIME_SECOND_DAY: +                if (c >= '0' && c <= '9') { +                    tmp += c - diff; +                    if (tmp < 1 || tmp > 31) { +                        *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                            "Invalid day. Found %d, must be >= 1 and <= 31.", +                            tmp); +                        break; +                    } +                    t.tm_mday = tmp; +                    state = DATETIME_SPACE; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid second digit of day. " +                    "Found '%c', must be integer >= 0 and <= 9.", c); +                break; + +            case DATETIME_SPACE: +                if (c == ' ') { +                    tmp = 0; +                    state = DATETIME_FIRST_HOUR; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid separator between date and time. " +                    "Found '%c', must be ' ' (empty space).", c); +                break; + +            case DATETIME_FIRST_HOUR: +                if (c >= '0' && c <= '2') { +                    tmp += (c - diff) * 10; +                    state = DATETIME_SECOND_HOUR; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid first digit of hours. " +                    "Found '%c', must be integer >= 0 and <= 2.", c); +                break; + +            case DATETIME_SECOND_HOUR: +                if (c >= '0' && c <= '9') { +                    tmp += c - diff; +                    if (tmp < 0 || tmp > 23) { +                        *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                            "Invalid hours. Found %d, must be >= 0 and <= 23.", +                            tmp); +                        break; +                    } +                    t.tm_hour = tmp; +                    state = DATETIME_FIRST_COLON; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid second digit of hours. " +                    "Found '%c', must be integer >= 0 and <= 9.", c); +                break; + +            case DATETIME_FIRST_COLON: +                if (c == ':') { +                    tmp = 0; +                    state = DATETIME_FIRST_MINUTE; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid separator between hours and minutes. " +                    "Found '%c', must be ':'.", c); +                break; + +            case DATETIME_FIRST_MINUTE: +                if (c >= '0' && c <= '5') { +                    tmp += (c - diff) * 10; +                    state = DATETIME_SECOND_MINUTE; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid first digit of minutes. " +                    "Found '%c', must be integer >= 0 and <= 5.", c); +                break; + +            case DATETIME_SECOND_MINUTE: +                if (c >= '0' && c <= '9') { +                    tmp += c - diff; +                    if (tmp < 0 || tmp > 59) { +                        // this won't happen because we are restricting the digits +                        // to 00-59 already, but lets keep the code here for +                        // reference. +                        *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                            "Invalid minutes. Found %d, must be >= 0 and <= 59.", +                            tmp); +                        break; +                    } +                    t.tm_min = tmp; +                    state = DATETIME_SECOND_COLON; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid second digit of minutes. " +                    "Found '%c', must be integer >= 0 and <= 9.", c); +                break; + +            case DATETIME_SECOND_COLON: +                if (c == ':') { +                    tmp = 0; +                    state = DATETIME_FIRST_SECOND; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid separator between minutes and seconds. " +                    "Found '%c', must be ':'.", c); +                break; + +            case DATETIME_FIRST_SECOND: +                if (c >= '0' && c <= '6') { +                    tmp += (c - diff) * 10; +                    state = DATETIME_SECOND_SECOND; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid first digit of seconds. " +                    "Found '%c', must be integer >= 0 and <= 6.", c); +                break; + +            case DATETIME_SECOND_SECOND: +                if (c >= '0' && c <= '9') { +                    tmp += c - diff; +                    if (tmp < 0 || tmp > 60) { +                        *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                            "Invalid seconds. Found %d, must be >= 0 and <= 60.", +                            tmp); +                        break; +                    } +                    t.tm_sec = tmp; +                    state = DATETIME_DONE; +                    break; +                } +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid second digit of seconds. " +                    "Found '%c', must be integer >= 0 and <= 9.", c); +                break; + +            case DATETIME_DONE: +                // well, its done ;) +                break; +        } + +        if (*err != NULL) +            return NULL; +    } + +    if (*err == NULL) { +        switch (state) { +            case DATETIME_FIRST_YEAR: +            case DATETIME_SECOND_YEAR: +            case DATETIME_THIRD_YEAR: +            case DATETIME_FOURTH_YEAR: +            case DATETIME_FIRST_HYPHEN: +            case DATETIME_FIRST_MONTH: +            case DATETIME_SECOND_MONTH: +            case DATETIME_SECOND_HYPHEN: +            case DATETIME_FIRST_DAY: +            case DATETIME_SECOND_DAY: +            case DATETIME_FIRST_HOUR: +            case DATETIME_SECOND_HOUR: +            case DATETIME_FIRST_MINUTE: +            case DATETIME_SECOND_MINUTE: +            case DATETIME_FIRST_SECOND: +            case DATETIME_SECOND_SECOND: +                *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, +                    "Invalid datetime string. " +                    "Found '%s', formats allowed are: 'yyyy-mm-dd hh:mm:ss', " +                    "'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and 'yyyy-mm-dd'.", +                    orig); +                return NULL; + +            case DATETIME_SPACE: +            case DATETIME_FIRST_COLON: +            case DATETIME_SECOND_COLON: +            case DATETIME_DONE: +                break;  // these states are ok +        } +    } + +    mktime(&t); + +    char buf[1024]; +    if (0 == strftime(buf, sizeof(buf), format, &t)) { +        fprintf(stderr, "blogc: warning: Failed to format DATE variable, " +            "FORMAT is too long: %s\n", format); +        return b_strdup(orig); +    } + +    return b_strdup(buf); +} diff --git a/src/datetime-parser.h b/src/datetime-parser.h new file mode 100644 index 0000000..7f94545 --- /dev/null +++ b/src/datetime-parser.h @@ -0,0 +1,17 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2015 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#ifndef _DATETIME_H +#define _DATETIME_H + +#include "error.h" + +char* blogc_convert_datetime(const char *orig, const char *format, +    blogc_error_t **err); + +#endif /* _DATETIME_H */ diff --git a/src/error.c b/src/error.c index d3d045d..0576d34 100644 --- a/src/error.c +++ b/src/error.c @@ -119,6 +119,9 @@ blogc_error_print(blogc_error_t *err)          case BLOGC_ERROR_TEMPLATE_PARSER:              fprintf(stderr, "Template parser error: %s\n", err->msg);              break; +        case BLOGC_ERROR_DATETIME_PARSER: +            fprintf(stderr, "Datetime parser error: %s\n", err->msg); +            break;          case BLOGC_ERROR_LOADER:              fprintf(stderr, "Loader error: %s\n", err->msg);              break; diff --git a/src/error.h b/src/error.h index 8b5a2e5..d9b2862 100644 --- a/src/error.h +++ b/src/error.h @@ -15,6 +15,7 @@  typedef enum {      BLOGC_ERROR_SOURCE_PARSER = 1,      BLOGC_ERROR_TEMPLATE_PARSER, +    BLOGC_ERROR_DATETIME_PARSER,      BLOGC_ERROR_LOADER,  } blogc_error_type_t; | 
