[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
parse_time()
From: |
Bruce Korb |
Subject: |
parse_time() |
Date: |
Sat, 01 Nov 2008 16:37:00 -0700 |
User-agent: |
Thunderbird 2.0.0.12 (X11/20071114) |
Hi,
I had need of a function to convert some variation of a time (duration)
specification into a count of seconds. For your amusement and optional
inclusion...(I *think* I've got papers on file for gnulib....)
It accepts several formats:
[DD d] [HH h] [MM m] [SS s]
[DD d] [[HH:]MM:]SS
[DD d] [HH h] [MM:]SS
though it is unhappy if it finds nothing.
Cheers - Bruce
/* Parse a time duration and return a seconds count
Copyright (C) 2008 Free Software Foundation, Inc.
Written by Bruce Korb <address@hidden>, 2008.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <time.h>
#ifndef _
#define _(_s) _s
#endif
#ifndef NUL
#define NUL '\0'
#endif
typedef enum {
NOTHING_IS_DONE,
DAY_IS_DONE,
HOUR_IS_DONE,
MINUTE_IS_DONE,
SECOND_IS_DONE
} whats_done_t;
#define SEC_PER_MIN 60
#define SEC_PER_HR (SEC_PER_MIN * 60)
#define SEC_PER_DAY (SEC_PER_HR * 24)
#define TIME_MAX 0x7FFFFFFF
static time_t
parse_hr_min_sec(time_t start, char * pz)
{
int lpct = 0;
/* For as long as our scanner pointer points to a colon *AND*
we've not looped before, then keep looping. (two iterations max) */
while ((*pz == ':') && (lpct++ == 0))
{
if ( (start > TIME_MAX / 60)
|| ! isdigit((int)*pz))
{
errno = EINVAL;
return ~0;
}
start *= 60;
errno = 0;
{
unsigned long v = strtoul(pz, &pz, 10);
if (errno != 0)
return ~0;
if (start > TIME_MAX - v)
{
errno = EINVAL;
return ~0;
}
start += v;
}
}
/* allow for trailing spaces */
while (isspace(*pz)) pz++;
if (*pz != NUL)
{
errno = EINVAL;
return ~0;
}
return start;
}
time_t
parse_time(char const * in_pz)
{
whats_done_t whatd_we_do = NOTHING_IS_DONE;
char * pz;
time_t val;
time_t res = 0;
while (isspace(*in_pz)) in_pz++;
if (! isdigit((int)*in_pz)) goto bad_time;
do {
errno = 0;
val = strtol(in_pz, &pz, 10);
if (errno != 0)
goto bad_time;
/* IF we find a colon, then we're going to have a seconds value.
We will not loop here any more. We cannot already have parsed
a minute value and if we've parsed an hour value, then the result
value has to be less than an hour. */
if (*pz == ':')
{
if (whatd_we_do >= MINUTE_IS_DONE)
break;
val = parse_hr_min_sec(val, pz);
if ((errno != 0) || (res > TIME_MAX - val))
break;
if ((whatd_we_do == HOUR_IS_DONE) && (val >= SEC_PER_HR))
break;
/* Check for overflow */
if (res > TIME_MAX - val)
break;
return res + val;
}
{
unsigned int mult;
while (isspace(*pz)) pz++;
switch (*pz)
{
default: goto bad_time;
case NUL:
/* Check for overflow */
if (res > TIME_MAX - val)
goto bad_time;
return val + res;
case 'd':
if (whatd_we_do >= DAY_IS_DONE)
goto bad_time;
mult = SEC_PER_DAY;
whatd_we_do = DAY_IS_DONE;
break;
case 'h':
if (whatd_we_do >= HOUR_IS_DONE)
goto bad_time;
mult = SEC_PER_HR;
whatd_we_do = HOUR_IS_DONE;
break;
case 'm':
if (whatd_we_do >= MINUTE_IS_DONE)
goto bad_time;
mult = SEC_PER_MIN;
whatd_we_do = MINUTE_IS_DONE;
break;
case 's':
mult = 1;
whatd_we_do = SECOND_IS_DONE;
break;
}
/* Check for overflow: value that overflows or an overflowing
result when "val" gets added to it. */
if (val > TIME_MAX / mult)
break;
val *= mult;
if (res > TIME_MAX - val)
break;
res += val;
while (isspace(*pz)) pz++;
if (*pz == NUL)
return res;
if (! isdigit(*pz))
break;
}
} while (whatd_we_do < SECOND_IS_DONE);
bad_time:
fprintf(stderr, _("Invalid time duration: %s\n"), in_pz);
errno = EINVAL;
return (time_t)~0;
}
- parse_time(),
Bruce Korb <=
- Re: parse_time(), Bruno Haible, 2008/11/02
- Re: parse_time(), Bruce Korb, 2008/11/02
- Re: parse_time(), Bruno Haible, 2008/11/02
- Re: parse_duration(), Bruce Korb, 2008/11/02
- Re: parse_duration(), Bruno Haible, 2008/11/03
- Re: parse_duration(), Bruce Korb, 2008/11/04
- Re: parse_duration(), Bruno Haible, 2008/11/05
- Re: parse_duration(), Bruce Korb, 2008/11/05
- Re: parse_duration(), Bruce Korb, 2008/11/16
- Re: parse_duration(), Bruno Haible, 2008/11/17