dt_status_t dt_from_string()

in src/dt.c [756:857]


dt_status_t dt_from_string(const char *str, const char *fmt, dt_representation_t *representation)
{
    struct tm tm = {0};
    dt_status_t status = DT_UNKNOWN_ERROR;
    size_t fmt_len = 0;
    const char *str_ptr = str;
    char fmt_buffer[255] = {0};
    int fractional_seconds_format_pos = 0;
    size_t fmt_start_pos = 0;
    size_t fractional_seconds_format_length = 0;
    size_t fractional_seconds_precision = 0;
    size_t fractional_digits_parsed = 0;
    unsigned long nano_second = 0;

    if (!representation || !str || !fmt) {
        return DT_INVALID_ARGUMENT;
    }

    // Checking for too long format string
    fmt_len = strlen(fmt);
    if (fmt_len >= sizeof(fmt_buffer)) {
        return DT_OVERFLOW;
    }

    while (1) {

        if (fmt_start_pos < fmt_len) {
            // There is some data in format string
            if (*str_ptr == '\0') {
                // No data to parse
                return DT_INVALID_ARGUMENT;
            }
        } else {
            // Format string has been expired
            if (*str_ptr != '\0') {
                // There is some extra data to parse
                return DT_INVALID_ARGUMENT;
            } else {
                // No data to parse
                break;
            }
        }

        // Searching for fractional format placeholder
        fractional_seconds_format_pos = dt_parse_fractional_seconds_format(fmt + fmt_start_pos,
                                                                           &fractional_seconds_format_length, &fractional_seconds_precision);

        if (fractional_seconds_format_pos < 0) {
            // No fractional seconds placeholder found -> parsing the rest of the string against the rest of format
            str_ptr = strptime(str_ptr, fmt + fmt_start_pos, &tm);   // FIXME: Warning on UNIX platform!
            if (str_ptr == NULL) {
                // Parsing error occured
                return DT_INVALID_ARGUMENT;
            }
            if (*str_ptr != '\0') {
                // There is some extra data to parse
                return DT_INVALID_ARGUMENT;
            }
            break;
        } else {
            if (fractional_seconds_format_pos > 0) {
                // Extracting leading format data to the buffer and parsing date-time value according this format
                memcpy(fmt_buffer, fmt + fmt_start_pos, fractional_seconds_format_pos);
                fmt_buffer[fractional_seconds_format_pos] = '\0';
                str_ptr = strptime(str_ptr, fmt_buffer, &tm);   // FIXME: Warning on UNIX platform!
                if (str_ptr == NULL) {
                    // Parsing error occured
                    return DT_INVALID_ARGUMENT;
                }
            }
            fmt_start_pos += (fractional_seconds_format_pos + fractional_seconds_format_length);

            // Parsing fractional seconds
            if (fractional_seconds_precision == 0) {
                fractional_seconds_precision = 9;
            }
            nano_second = 0;
            fractional_digits_parsed = 0;
            while (fractional_digits_parsed < fractional_seconds_precision) {
                if (!isdigit(*str_ptr)) {
                    if (fractional_digits_parsed == 0) {
                        // Parsing error occured
                        return DT_INVALID_ARGUMENT;
                    }
                    break;
                }
                nano_second *= 10UL;
                nano_second += (unsigned long) * str_ptr - '0';
                ++str_ptr;
                ++fractional_digits_parsed;
            }
            nano_second *= (unsigned long)pow(10, 9 - fractional_digits_parsed);
        }
    }

    status = dt_tm_to_representation(&tm, nano_second, representation);
    if (status != DT_OK) {
        return status;
    }

    return DT_OK;
}