/* Parse a time duration and return a seconds count
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008-2014 Free Software Foundation, Inc.
Written by Bruce Korb <bkorb@gnu.org>, 2008.
This program is free software: you can redistribute it and/or modify
#include <config.h>
+/* Specification. */
+#include "parse-duration.h"
+
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
-#include "parse-duration.h"
-
-#ifndef _
-#define _(_s) _s
-#endif
-
#ifndef NUL
#define NUL '\0'
#endif
#define TIME_MAX 0x7FFFFFFF
-static unsigned long inline
+/* Wrapper around strtoul that does not require a cast. */
+static unsigned long
str_const_to_ul (cch_t * str, cch_t ** ppz, int base)
{
return strtoul (str, (char **)ppz, base);
}
-static long inline
+/* Wrapper around strtol that does not require a cast. */
+static long
str_const_to_l (cch_t * str, cch_t ** ppz, int base)
{
return strtol (str, (char **)ppz, base);
}
-static time_t inline
+/* Returns BASE + VAL * SCALE, interpreting BASE = BAD_TIME
+ with errno set as an error situation, and returning BAD_TIME
+ with errno set in an error situation. */
+static time_t
scale_n_add (time_t base, time_t val, int scale)
{
if (base == BAD_TIME)
return base + val;
}
+/* After a number HH has been parsed, parse subsequent :MM or :MM:SS. */
static time_t
parse_hr_min_sec (time_t start, cch_t * pz)
{
}
/* allow for trailing spaces */
- while (isspace ((unsigned char)*pz)) pz++;
+ while (isspace ((unsigned char)*pz))
+ pz++;
if (*pz != NUL)
{
errno = EINVAL;
return start;
}
+/* Parses a value and returns BASE + value * SCALE, interpreting
+ BASE = BAD_TIME with errno set as an error situation, and returning
+ BAD_TIME with errno set in an error situation. */
static time_t
parse_scaled_value (time_t base, cch_t ** ppz, cch_t * endp, int scale)
{
val = str_const_to_ul (pz, &pz, 10);
if (errno != 0)
return BAD_TIME;
- while (isspace ((unsigned char)*pz)) pz++;
+ while (isspace ((unsigned char)*pz))
+ pz++;
if (pz != endp)
{
errno = EINVAL;
return BAD_TIME;
}
- *ppz = pz;
+ *ppz = pz;
return scale_n_add (base, val, scale);
}
+/* Parses the syntax YEAR-MONTH-DAY.
+ PS points into the string, after "YEAR", before "-MONTH-DAY". */
static time_t
parse_year_month_day (cch_t * pz, cch_t * ps)
{
res = parse_scaled_value (0, &pz, ps, SEC_PER_YEAR);
- ps = strchr (++pz, '-');
+ pz++; /* over the first '-' */
+ ps = strchr (pz, '-');
if (ps == NULL)
{
errno = EINVAL;
}
res = parse_scaled_value (res, &pz, ps, SEC_PER_MONTH);
- pz++;
+ pz++; /* over the second '-' */
ps = pz + strlen (pz);
return parse_scaled_value (res, &pz, ps, SEC_PER_DAY);
}
+/* Parses the syntax YYYYMMDD. */
static time_t
parse_yearmonthday (cch_t * in_pz)
{
return parse_scaled_value (res, &pz, buf + 2, SEC_PER_DAY);
}
+/* Parses the syntax yy Y mm M ww W dd D. */
static time_t
parse_YMWD (cch_t * pz)
{
pz++;
}
- while (isspace ((unsigned char)*pz)) pz++;
+ while (isspace ((unsigned char)*pz))
+ pz++;
if (*pz != NUL)
{
errno = EINVAL;
return res;
}
+/* Parses the syntax HH:MM:SS.
+ PS points into the string, after "HH", before ":MM:SS". */
static time_t
parse_hour_minute_second (cch_t * pz, cch_t * ps)
{
res = parse_scaled_value (0, &pz, ps, SEC_PER_HR);
- ps = strchr (++pz, ':');
+ pz++;
+ ps = strchr (pz, ':');
if (ps == NULL)
{
errno = EINVAL;
return parse_scaled_value (res, &pz, ps, 1);
}
+/* Parses the syntax HHMMSS. */
static time_t
parse_hourminutesecond (cch_t * in_pz)
{
return parse_scaled_value (res, &pz, buf + 2, 1);
}
+/* Parses the syntax hh H mm M ss S. */
static time_t
parse_HMS (cch_t * pz)
{
pz++;
}
- while (isspace ((unsigned char)*pz)) pz++;
+ while (isspace ((unsigned char)*pz))
+ pz++;
if (*pz != NUL)
{
errno = EINVAL;
return res;
}
+/* Parses a time (hours, minutes, seconds) specification in either syntax. */
static time_t
parse_time (cch_t * pz)
{
return res;
}
+/* Returns a substring of the given string, with spaces at the beginning and at
+ the end destructively removed, per SNOBOL. */
static char *
-trim(char * pz)
+trim (char * pz)
{
/* trim leading white space */
- while (isspace ((unsigned char)*pz)) pz++;
+ while (isspace ((unsigned char)*pz))
+ pz++;
/* trim trailing white space */
{
char * pe = pz + strlen (pz);
- while ((pe > pz) && isspace ((unsigned char)pe[-1])) pe--;
+ while ((pe > pz) && isspace ((unsigned char)pe[-1]))
+ pe--;
*pe = NUL;
}
static time_t
parse_period (cch_t * in_pz)
{
- char * pz = xstrdup (in_pz);
- char * pT = strchr (pz, 'T');
+ char * pT;
char * ps;
+ char * pz = strdup (in_pz);
void * fptr = pz;
time_t res = 0;
- if (pT != NUL)
+ if (pz == NULL)
+ {
+ errno = ENOMEM;
+ return BAD_TIME;
+ }
+
+ pT = strchr (pz, 'T');
+ if (pT != NULL)
{
*(pT++) = NUL;
pz = trim (pz);
}
static time_t
-parse_non_iso8601(cch_t * pz)
+parse_non_iso8601 (cch_t * pz)
{
whats_done_t whatd_we_do = NOTHING_IS_DONE;
unsigned int mult;
/* Skip over white space following the number we just parsed. */
- while (isspace ((unsigned char)*pz)) pz++;
+ while (isspace ((unsigned char)*pz))
+ pz++;
switch (*pz)
{
res = scale_n_add (res, val, mult);
- while (isspace ((unsigned char)*++pz)) ;
+ pz++;
+ while (isspace ((unsigned char)*pz))
+ pz++;
if (*pz == NUL)
return res;
time_t
parse_duration (char const * pz)
{
- time_t res = 0;
+ while (isspace ((unsigned char)*pz))
+ pz++;
- while (isspace ((unsigned char)*pz)) pz++;
-
- do {
- if (*pz == 'P')
- {
- res = parse_period (pz + 1);
- if ((errno != 0) || (res == BAD_TIME))
- break;
- return res;
- }
-
- if (*pz == 'T')
- {
- res = parse_time (pz + 1);
- if ((errno != 0) || (res == BAD_TIME))
- break;
- return res;
- }
-
- if (! isdigit ((unsigned char)*pz))
- break;
+ switch (*pz)
+ {
+ case 'P':
+ return parse_period (pz + 1);
- res = parse_non_iso8601 (pz);
- if ((errno == 0) && (res != BAD_TIME))
- return res;
+ case 'T':
+ return parse_time (pz + 1);
- } while (0);
+ default:
+ if (isdigit ((unsigned char)*pz))
+ return parse_non_iso8601 (pz);
- fprintf (stderr, _("Invalid time duration: %s\n"), pz);
- if (errno == 0)
- errno = EINVAL;
- return BAD_TIME;
+ errno = EINVAL;
+ return BAD_TIME;
+ }
}
/*