[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
parse-duration tweaks
From: |
Bruno Haible |
Subject: |
parse-duration tweaks |
Date: |
Tue, 16 Dec 2008 12:26:27 +0100 |
User-agent: |
KMail/1.9.9 |
Hi Bruce,
Got some time to look at the parse-duration module again. I would propose these
changes:
- Comments, for maintainability.
- Don't put side effects into function call arguments. These functions may
be implemented as macros on inferior platforms, you never know.
- Don't test errno if res != BAD_TIME. For example, the free() call at the
end of parse_period() may set errno.
- Save errno around the call to fprintf. fprintf may set errno.
Also, can you clarify the purpose of having the
fprintf (stderr, _("Invalid time duration: %s\n"), pz);
in the function? Usually, when a function is designed as a library
function, it provides an error indicator through the return value (which
parse_duration does) and leaves the responsibility of signalling errors
to the caller.
2008-12-16 Bruno Haible <address@hidden>
* lib/parse-duration.h (parse_duration): Document return value
convention.
* lib/parse-duration.c: Include specification header first. Add
comments.
(parse_year_month_day, parse_hour_minute_second): Move side effects
outside of strchr call.
(parse_non_iso8601): Move side effects outside of isspace call.
(parse_duration): Don't test errno is res != BAD_TIME. Save errno
around fprintf call.
--- lib/parse-duration.h.orig 2008-12-16 12:21:06.000000000 +0100
+++ lib/parse-duration.h 2008-12-16 11:25:07.000000000 +0100
@@ -47,9 +47,11 @@
yy Y mm M ww W dd D
or it may be empty and followed by a 'T'. The "yyyymmdd" must be eight
- digits long. Note: months are always 30 days and years are always 365
- days long. 5 years is always 1825, not 1826 or 1827 depending on leap
- year considerations. 3 months is always 90 days. There is no consideration
+ digits long.
+
+ NOTE! Months are always 30 days and years are always 365 days long.
+ 5 years is always 1825, not 1826 or 1827 depending on leap year
+ considerations. 3 months is always 90 days. There is no consideration
for how many days are in the current, next or previous months.
For the final format:
@@ -75,8 +77,12 @@
#include <time.h>
+/* Return value when a valid duration cannot be parsed. */
#define BAD_TIME ((time_t)~0)
+/* Parses the given string. If it has the syntax of a valid duration,
+ this duration is returned. Otherwise, the return value is BAD_TIME,
+ and errno is set to either EINVAL (bad syntax) or ERANGE (out of range). */
extern time_t parse_duration(char const * in_pz);
#endif /* GNULIB_PARSE_DURATION_H */
--- lib/parse-duration.c.orig 2008-12-16 12:21:06.000000000 +0100
+++ lib/parse-duration.c 2008-12-16 12:04:25.000000000 +0100
@@ -17,6 +17,9 @@
#include <config.h>
+/* Specification. */
+#include "parse-duration.h"
+
#include <ctype.h>
#include <errno.h>
#include <limits.h>
@@ -25,8 +28,6 @@
#include <string.h>
#include "xalloc.h"
-#include "parse-duration.h"
-
#ifndef _
#define _(_s) _s
#endif
@@ -57,18 +58,23 @@
#define TIME_MAX 0x7FFFFFFF
+/* Wrapper around strtoul that does not require a cast. */
static unsigned long inline
str_const_to_ul (cch_t * str, cch_t ** ppz, int base)
{
return strtoul (str, (char **)ppz, base);
}
+/* Wrapper around strtol that does not require a cast. */
static long inline
str_const_to_l (cch_t * str, cch_t ** ppz, int base)
{
return strtol (str, (char **)ppz, base);
}
+/* 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 inline
scale_n_add (time_t base, time_t val, int scale)
{
@@ -95,6 +101,7 @@
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)
{
@@ -118,7 +125,8 @@
}
/* allow for trailing spaces */
- while (isspace ((unsigned char)*pz)) pz++;
+ while (isspace ((unsigned char)*pz))
+ pz++;
if (*pz != NUL)
{
errno = EINVAL;
@@ -128,6 +136,9 @@
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)
{
@@ -141,17 +152,20 @@
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)
{
@@ -159,7 +173,8 @@
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;
@@ -167,11 +182,12 @@
}
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)
{
@@ -201,6 +217,7 @@
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)
{
@@ -233,7 +250,8 @@
pz++;
}
- while (isspace ((unsigned char)*pz)) pz++;
+ while (isspace ((unsigned char)*pz))
+ pz++;
if (*pz != NUL)
{
errno = EINVAL;
@@ -243,6 +261,8 @@
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)
{
@@ -250,7 +270,8 @@
res = parse_scaled_value (0, &pz, ps, SEC_PER_HR);
- ps = strchr (++pz, ':');
+ pz++;
+ ps = strchr (pz, ':');
if (ps == NULL)
{
errno = EINVAL;
@@ -264,6 +285,7 @@
return parse_scaled_value (res, &pz, ps, 1);
}
+/* Parses the syntax HHMMSS. */
static time_t
parse_hourminutesecond (cch_t * in_pz)
{
@@ -293,6 +315,7 @@
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)
{
@@ -318,7 +341,8 @@
pz++;
}
- while (isspace ((unsigned char)*pz)) pz++;
+ while (isspace ((unsigned char)*pz))
+ pz++;
if (*pz != NUL)
{
errno = EINVAL;
@@ -328,6 +352,7 @@
return res;
}
+/* Parses a time (hours, minutes, seconds) specification in either syntax. */
static time_t
parse_time (cch_t * pz)
{
@@ -359,16 +384,20 @@
return res;
}
+/* Returns a substring of the given string, with spaces at the beginning and at
+ the end destructively removed. */
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;
}
@@ -462,7 +491,8 @@
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)
{
@@ -520,7 +550,9 @@
res = scale_n_add (res, val, mult);
- while (isspace ((unsigned char)*++pz)) ;
+ pz++;
+ while (isspace ((unsigned char)*pz))
+ pz++;
if (*pz == NUL)
return res;
@@ -539,14 +571,16 @@
parse_duration (char const * pz)
{
time_t res = 0;
+ int saved_errno;
- 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))
+ if (res == BAD_TIME)
break;
return res;
}
@@ -554,7 +588,7 @@
if (*pz == 'T')
{
res = parse_time (pz + 1);
- if ((errno != 0) || (res == BAD_TIME))
+ if (res == BAD_TIME)
break;
return res;
}
@@ -563,14 +597,14 @@
break;
res = parse_non_iso8601 (pz);
- if ((errno == 0) && (res != BAD_TIME))
+ if (res != BAD_TIME)
return res;
} while (0);
+ saved_errno = errno;
fprintf (stderr, _("Invalid time duration: %s\n"), pz);
- if (errno == 0)
- errno = EINVAL;
+ errno = saved_errno;
return BAD_TIME;
}
- parse-duration tweaks,
Bruno Haible <=