Blame src/libopts/parse-duration.c

Packit Service 4684c1
/* Parse a time duration and return a seconds count
Packit Service 4684c1
   Copyright (C) 2008-2018 Free Software Foundation, Inc.
Packit Service 4684c1
   Written by Bruce Korb <bkorb@gnu.org>, 2008.
Packit Service 4684c1
Packit Service 4684c1
   This program is free software: you can redistribute it and/or modify
Packit Service 4684c1
   it under the terms of the GNU Lesser General Public License as published by
Packit Service 4684c1
   the Free Software Foundation; either version 2.1 of the License, or
Packit Service 4684c1
   (at your option) any later version.
Packit Service 4684c1
Packit Service 4684c1
   This program is distributed in the hope that it will be useful,
Packit Service 4684c1
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 4684c1
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 4684c1
   GNU Lesser General Public License for more details.
Packit Service 4684c1
Packit Service 4684c1
   You should have received a copy of the GNU Lesser General Public License
Packit Service 4684c1
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service 4684c1
Packit Service 4684c1
#include <config.h>
Packit Service 4684c1
Packit Service 4684c1
/* Specification.  */
Packit Service 4684c1
#include "parse-duration.h"
Packit Service 4684c1
Packit Service 4684c1
#include <ctype.h>
Packit Service 4684c1
#include <errno.h>
Packit Service 4684c1
#include <limits.h>
Packit Service 4684c1
#include <stdio.h>
Packit Service 4684c1
#include <stdlib.h>
Packit Service 4684c1
#include <string.h>
Packit Service 4684c1
Packit Service 4684c1
#include "intprops.h"
Packit Service 4684c1
Packit Service 4684c1
#ifndef NUL
Packit Service 4684c1
#define NUL '\0'
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
#define cch_t char const
Packit Service 4684c1
Packit Service 4684c1
typedef enum {
Packit Service 4684c1
  NOTHING_IS_DONE,
Packit Service 4684c1
  YEAR_IS_DONE,
Packit Service 4684c1
  MONTH_IS_DONE,
Packit Service 4684c1
  WEEK_IS_DONE,
Packit Service 4684c1
  DAY_IS_DONE,
Packit Service 4684c1
  HOUR_IS_DONE,
Packit Service 4684c1
  MINUTE_IS_DONE,
Packit Service 4684c1
  SECOND_IS_DONE
Packit Service 4684c1
} whats_done_t;
Packit Service 4684c1
Packit Service 4684c1
#define SEC_PER_MIN     60
Packit Service 4684c1
#define SEC_PER_HR      (SEC_PER_MIN * 60)
Packit Service 4684c1
#define SEC_PER_DAY     (SEC_PER_HR  * 24)
Packit Service 4684c1
#define SEC_PER_WEEK    (SEC_PER_DAY * 7)
Packit Service 4684c1
#define SEC_PER_MONTH   (SEC_PER_DAY * 30)
Packit Service 4684c1
#define SEC_PER_YEAR    (SEC_PER_DAY * 365)
Packit Service 4684c1
Packit Service 4684c1
#undef  MAX_DURATION
Packit Service 4684c1
#define MAX_DURATION    TYPE_MAXIMUM(time_t)
Packit Service 4684c1
Packit Service 4684c1
/* Wrapper around strtoul that does not require a cast.  */
Packit Service 4684c1
static unsigned long
Packit Service 4684c1
str_const_to_ul (cch_t * str, cch_t ** ppz, int base)
Packit Service 4684c1
{
Packit Service 4684c1
  return strtoul (str, (char **)ppz, base);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Wrapper around strtol that does not require a cast.  */
Packit Service 4684c1
static long
Packit Service 4684c1
str_const_to_l (cch_t * str, cch_t ** ppz, int base)
Packit Service 4684c1
{
Packit Service 4684c1
  return strtol (str, (char **)ppz, base);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Returns BASE + VAL * SCALE, interpreting BASE = BAD_TIME
Packit Service 4684c1
   with errno set as an error situation, and returning BAD_TIME
Packit Service 4684c1
   with errno set in an error situation.  */
Packit Service 4684c1
static time_t
Packit Service 4684c1
scale_n_add (time_t base, time_t val, int scale)
Packit Service 4684c1
{
Packit Service 4684c1
  if (base == BAD_TIME)
Packit Service 4684c1
    {
Packit Service 4684c1
      if (errno == 0)
Packit Service 4684c1
        errno = EINVAL;
Packit Service 4684c1
      return BAD_TIME;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  if (val > MAX_DURATION / scale)
Packit Service 4684c1
    {
Packit Service 4684c1
      errno = ERANGE;
Packit Service 4684c1
      return BAD_TIME;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  val *= scale;
Packit Service 4684c1
  if (base > MAX_DURATION - val)
Packit Service 4684c1
    {
Packit Service 4684c1
      errno = ERANGE;
Packit Service 4684c1
      return BAD_TIME;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  return base + val;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* After a number HH has been parsed, parse subsequent :MM or :MM:SS.  */
Packit Service 4684c1
static time_t
Packit Service 4684c1
parse_hr_min_sec (time_t start, cch_t * pz)
Packit Service 4684c1
{
Packit Service 4684c1
  int lpct = 0;
Packit Service 4684c1
Packit Service 4684c1
  errno = 0;
Packit Service 4684c1
Packit Service 4684c1
  /* For as long as our scanner pointer points to a colon *AND*
Packit Service 4684c1
     we've not looped before, then keep looping.  (two iterations max) */
Packit Service 4684c1
  while ((*pz == ':') && (lpct++ <= 1))
Packit Service 4684c1
    {
Packit Service 4684c1
      unsigned long v = str_const_to_ul (pz+1, &pz, 10);
Packit Service 4684c1
Packit Service 4684c1
      if (errno != 0)
Packit Service 4684c1
        return BAD_TIME;
Packit Service 4684c1
Packit Service 4684c1
      start = scale_n_add (v, start, 60);
Packit Service 4684c1
Packit Service 4684c1
      if (errno != 0)
Packit Service 4684c1
        return BAD_TIME;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  /* allow for trailing spaces */
Packit Service 4684c1
  while (isspace ((unsigned char)*pz))
Packit Service 4684c1
    pz++;
Packit Service 4684c1
  if (*pz != NUL)
Packit Service 4684c1
    {
Packit Service 4684c1
      errno = EINVAL;
Packit Service 4684c1
      return BAD_TIME;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  return start;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Parses a value and returns BASE + value * SCALE, interpreting
Packit Service 4684c1
   BASE = BAD_TIME with errno set as an error situation, and returning
Packit Service 4684c1
   BAD_TIME with errno set in an error situation.  */
Packit Service 4684c1
static time_t
Packit Service 4684c1
parse_scaled_value (time_t base, cch_t ** ppz, cch_t * endp, int scale)
Packit Service 4684c1
{
Packit Service 4684c1
  cch_t * pz = *ppz;
Packit Service 4684c1
  time_t val;
Packit Service 4684c1
Packit Service 4684c1
  if (base == BAD_TIME)
Packit Service 4684c1
    return base;
Packit Service 4684c1
Packit Service 4684c1
  errno = 0;
Packit Service 4684c1
  val = str_const_to_ul (pz, &pz, 10);
Packit Service 4684c1
  if (errno != 0)
Packit Service 4684c1
    return BAD_TIME;
Packit Service 4684c1
  while (isspace ((unsigned char)*pz))
Packit Service 4684c1
    pz++;
Packit Service 4684c1
  if (pz != endp)
Packit Service 4684c1
    {
Packit Service 4684c1
      errno = EINVAL;
Packit Service 4684c1
      return BAD_TIME;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  *ppz = pz;
Packit Service 4684c1
  return scale_n_add (base, val, scale);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Parses the syntax YEAR-MONTH-DAY.
Packit Service 4684c1
   PS points into the string, after "YEAR", before "-MONTH-DAY".  */
Packit Service 4684c1
static time_t
Packit Service 4684c1
parse_year_month_day (cch_t * pz, cch_t * ps)
Packit Service 4684c1
{
Packit Service 4684c1
  time_t res = 0;
Packit Service 4684c1
Packit Service 4684c1
  res = parse_scaled_value (0, &pz, ps, SEC_PER_YEAR);
Packit Service 4684c1
Packit Service 4684c1
  pz++; /* over the first '-' */
Packit Service 4684c1
  ps = strchr (pz, '-');
Packit Service 4684c1
  if (ps == NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      errno = EINVAL;
Packit Service 4684c1
      return BAD_TIME;
Packit Service 4684c1
    }
Packit Service 4684c1
  res = parse_scaled_value (res, &pz, ps, SEC_PER_MONTH);
Packit Service 4684c1
Packit Service 4684c1
  pz++; /* over the second '-' */
Packit Service 4684c1
  ps = pz + strlen (pz);
Packit Service 4684c1
  return parse_scaled_value (res, &pz, ps, SEC_PER_DAY);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Parses the syntax YYYYMMDD.  */
Packit Service 4684c1
static time_t
Packit Service 4684c1
parse_yearmonthday (cch_t * in_pz)
Packit Service 4684c1
{
Packit Service 4684c1
  time_t res = 0;
Packit Service 4684c1
  char   buf[8];
Packit Service 4684c1
  cch_t * pz;
Packit Service 4684c1
Packit Service 4684c1
  if (strlen (in_pz) != 8)
Packit Service 4684c1
    {
Packit Service 4684c1
      errno = EINVAL;
Packit Service 4684c1
      return BAD_TIME;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  memcpy (buf, in_pz, 4);
Packit Service 4684c1
  buf[4] = NUL;
Packit Service 4684c1
  pz = buf;
Packit Service 4684c1
  res = parse_scaled_value (0, &pz, buf + 4, SEC_PER_YEAR);
Packit Service 4684c1
Packit Service 4684c1
  memcpy (buf, in_pz + 4, 2);
Packit Service 4684c1
  buf[2] = NUL;
Packit Service 4684c1
  pz =   buf;
Packit Service 4684c1
  res = parse_scaled_value (res, &pz, buf + 2, SEC_PER_MONTH);
Packit Service 4684c1
Packit Service 4684c1
  memcpy (buf, in_pz + 6, 2);
Packit Service 4684c1
  buf[2] = NUL;
Packit Service 4684c1
  pz =   buf;
Packit Service 4684c1
  return parse_scaled_value (res, &pz, buf + 2, SEC_PER_DAY);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Parses the syntax yy Y mm M ww W dd D.  */
Packit Service 4684c1
static time_t
Packit Service 4684c1
parse_YMWD (cch_t * pz)
Packit Service 4684c1
{
Packit Service 4684c1
  time_t res = 0;
Packit Service 4684c1
  cch_t * ps = strchr (pz, 'Y');
Packit Service 4684c1
  if (ps != NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      res = parse_scaled_value (0, &pz, ps, SEC_PER_YEAR);
Packit Service 4684c1
      pz++;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  ps = strchr (pz, 'M');
Packit Service 4684c1
  if (ps != NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      res = parse_scaled_value (res, &pz, ps, SEC_PER_MONTH);
Packit Service 4684c1
      pz++;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  ps = strchr (pz, 'W');
Packit Service 4684c1
  if (ps != NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      res = parse_scaled_value (res, &pz, ps, SEC_PER_WEEK);
Packit Service 4684c1
      pz++;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  ps = strchr (pz, 'D');
Packit Service 4684c1
  if (ps != NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      res = parse_scaled_value (res, &pz, ps, SEC_PER_DAY);
Packit Service 4684c1
      pz++;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  while (isspace ((unsigned char)*pz))
Packit Service 4684c1
    pz++;
Packit Service 4684c1
  if (*pz != NUL)
Packit Service 4684c1
    {
Packit Service 4684c1
      errno = EINVAL;
Packit Service 4684c1
      return BAD_TIME;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  return res;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Parses the syntax HH:MM:SS.
Packit Service 4684c1
   PS points into the string, after "HH", before ":MM:SS".  */
Packit Service 4684c1
static time_t
Packit Service 4684c1
parse_hour_minute_second (cch_t * pz, cch_t * ps)
Packit Service 4684c1
{
Packit Service 4684c1
  time_t res = 0;
Packit Service 4684c1
Packit Service 4684c1
  res = parse_scaled_value (0, &pz, ps, SEC_PER_HR);
Packit Service 4684c1
Packit Service 4684c1
  pz++;
Packit Service 4684c1
  ps = strchr (pz, ':');
Packit Service 4684c1
  if (ps == NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      errno = EINVAL;
Packit Service 4684c1
      return BAD_TIME;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  res = parse_scaled_value (res, &pz, ps, SEC_PER_MIN);
Packit Service 4684c1
Packit Service 4684c1
  pz++;
Packit Service 4684c1
  ps = pz + strlen (pz);
Packit Service 4684c1
  return parse_scaled_value (res, &pz, ps, 1);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Parses the syntax HHMMSS.  */
Packit Service 4684c1
static time_t
Packit Service 4684c1
parse_hourminutesecond (cch_t * in_pz)
Packit Service 4684c1
{
Packit Service 4684c1
  time_t res = 0;
Packit Service 4684c1
  char   buf[4];
Packit Service 4684c1
  cch_t * pz;
Packit Service 4684c1
Packit Service 4684c1
  if (strlen (in_pz) != 6)
Packit Service 4684c1
    {
Packit Service 4684c1
      errno = EINVAL;
Packit Service 4684c1
      return BAD_TIME;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  memcpy (buf, in_pz, 2);
Packit Service 4684c1
  buf[2] = NUL;
Packit Service 4684c1
  pz = buf;
Packit Service 4684c1
  res = parse_scaled_value (0, &pz, buf + 2, SEC_PER_HR);
Packit Service 4684c1
Packit Service 4684c1
  memcpy (buf, in_pz + 2, 2);
Packit Service 4684c1
  buf[2] = NUL;
Packit Service 4684c1
  pz =   buf;
Packit Service 4684c1
  res = parse_scaled_value (res, &pz, buf + 2, SEC_PER_MIN);
Packit Service 4684c1
Packit Service 4684c1
  memcpy (buf, in_pz + 4, 2);
Packit Service 4684c1
  buf[2] = NUL;
Packit Service 4684c1
  pz =   buf;
Packit Service 4684c1
  return parse_scaled_value (res, &pz, buf + 2, 1);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Parses the syntax hh H mm M ss S.  */
Packit Service 4684c1
static time_t
Packit Service 4684c1
parse_HMS (cch_t * pz)
Packit Service 4684c1
{
Packit Service 4684c1
  time_t res = 0;
Packit Service 4684c1
  cch_t * ps = strchr (pz, 'H');
Packit Service 4684c1
  if (ps != NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      res = parse_scaled_value (0, &pz, ps, SEC_PER_HR);
Packit Service 4684c1
      pz++;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  ps = strchr (pz, 'M');
Packit Service 4684c1
  if (ps != NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      res = parse_scaled_value (res, &pz, ps, SEC_PER_MIN);
Packit Service 4684c1
      pz++;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  ps = strchr (pz, 'S');
Packit Service 4684c1
  if (ps != NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      res = parse_scaled_value (res, &pz, ps, 1);
Packit Service 4684c1
      pz++;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  while (isspace ((unsigned char)*pz))
Packit Service 4684c1
    pz++;
Packit Service 4684c1
  if (*pz != NUL)
Packit Service 4684c1
    {
Packit Service 4684c1
      errno = EINVAL;
Packit Service 4684c1
      return BAD_TIME;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  return res;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Parses a time (hours, minutes, seconds) specification in either syntax.  */
Packit Service 4684c1
static time_t
Packit Service 4684c1
parse_time (cch_t * pz)
Packit Service 4684c1
{
Packit Service 4684c1
  cch_t * ps;
Packit Service 4684c1
  time_t  res = 0;
Packit Service 4684c1
Packit Service 4684c1
  /*
Packit Service 4684c1
   *  Scan for a hyphen
Packit Service 4684c1
   */
Packit Service 4684c1
  ps = strchr (pz, ':');
Packit Service 4684c1
  if (ps != NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      res = parse_hour_minute_second (pz, ps);
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  /*
Packit Service 4684c1
   *  Try for a 'H', 'M' or 'S' suffix
Packit Service 4684c1
   */
Packit Service 4684c1
  else if (ps = strpbrk (pz, "HMS"),
Packit Service 4684c1
           ps == NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      /* Its a YYYYMMDD format: */
Packit Service 4684c1
      res = parse_hourminutesecond (pz);
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  else
Packit Service 4684c1
    res = parse_HMS (pz);
Packit Service 4684c1
Packit Service 4684c1
  return res;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Returns a substring of the given string, with spaces at the beginning and at
Packit Service 4684c1
   the end destructively removed, per SNOBOL.  */
Packit Service 4684c1
static char *
Packit Service 4684c1
trim (char * pz)
Packit Service 4684c1
{
Packit Service 4684c1
  /* trim leading white space */
Packit Service 4684c1
  while (isspace ((unsigned char)*pz))
Packit Service 4684c1
    pz++;
Packit Service 4684c1
Packit Service 4684c1
  /* trim trailing white space */
Packit Service 4684c1
  {
Packit Service 4684c1
    char * pe = pz + strlen (pz);
Packit Service 4684c1
    while ((pe > pz) && isspace ((unsigned char)pe[-1]))
Packit Service 4684c1
      pe--;
Packit Service 4684c1
    *pe = NUL;
Packit Service 4684c1
  }
Packit Service 4684c1
Packit Service 4684c1
  return pz;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/*
Packit Service 4684c1
 *  Parse the year/months/days of a time period
Packit Service 4684c1
 */
Packit Service 4684c1
static time_t
Packit Service 4684c1
parse_period (cch_t * in_pz)
Packit Service 4684c1
{
Packit Service 4684c1
  char * pT;
Packit Service 4684c1
  char * ps;
Packit Service 4684c1
  char * pz   = strdup (in_pz);
Packit Service 4684c1
  void * fptr = pz;
Packit Service 4684c1
  time_t res  = 0;
Packit Service 4684c1
Packit Service 4684c1
  if (pz == NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      errno = ENOMEM;
Packit Service 4684c1
      return BAD_TIME;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  pT = strchr (pz, 'T');
Packit Service 4684c1
  if (pT != NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      *(pT++) = NUL;
Packit Service 4684c1
      pz = trim (pz);
Packit Service 4684c1
      pT = trim (pT);
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  /*
Packit Service 4684c1
   *  Scan for a hyphen
Packit Service 4684c1
   */
Packit Service 4684c1
  ps = strchr (pz, '-');
Packit Service 4684c1
  if (ps != NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      res = parse_year_month_day (pz, ps);
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  /*
Packit Service 4684c1
   *  Try for a 'Y', 'M' or 'D' suffix
Packit Service 4684c1
   */
Packit Service 4684c1
  else if (ps = strpbrk (pz, "YMWD"),
Packit Service 4684c1
           ps == NULL)
Packit Service 4684c1
    {
Packit Service 4684c1
      /* Its a YYYYMMDD format: */
Packit Service 4684c1
      res = parse_yearmonthday (pz);
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  else
Packit Service 4684c1
    res = parse_YMWD (pz);
Packit Service 4684c1
Packit Service 4684c1
  if ((errno == 0) && (pT != NULL))
Packit Service 4684c1
    {
Packit Service 4684c1
      time_t val = parse_time (pT);
Packit Service 4684c1
      res = scale_n_add (res, val, 1);
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  free (fptr);
Packit Service 4684c1
  return res;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static time_t
Packit Service 4684c1
parse_non_iso8601 (cch_t * pz)
Packit Service 4684c1
{
Packit Service 4684c1
  whats_done_t whatd_we_do = NOTHING_IS_DONE;
Packit Service 4684c1
Packit Service 4684c1
  time_t res = 0;
Packit Service 4684c1
Packit Service 4684c1
  do  {
Packit Service 4684c1
    time_t val;
Packit Service 4684c1
Packit Service 4684c1
    errno = 0;
Packit Service 4684c1
    val = str_const_to_l (pz, &pz, 10);
Packit Service 4684c1
    if (errno != 0)
Packit Service 4684c1
      goto bad_time;
Packit Service 4684c1
Packit Service 4684c1
    /*  IF we find a colon, then we're going to have a seconds value.
Packit Service 4684c1
        We will not loop here any more.  We cannot already have parsed
Packit Service 4684c1
        a minute value and if we've parsed an hour value, then the result
Packit Service 4684c1
        value has to be less than an hour. */
Packit Service 4684c1
    if (*pz == ':')
Packit Service 4684c1
      {
Packit Service 4684c1
        if (whatd_we_do >= MINUTE_IS_DONE)
Packit Service 4684c1
          break;
Packit Service 4684c1
Packit Service 4684c1
        val = parse_hr_min_sec (val, pz);
Packit Service 4684c1
Packit Service 4684c1
        if ((whatd_we_do == HOUR_IS_DONE) && (val >= SEC_PER_HR))
Packit Service 4684c1
          break;
Packit Service 4684c1
Packit Service 4684c1
        return scale_n_add (res, val, 1);
Packit Service 4684c1
      }
Packit Service 4684c1
Packit Service 4684c1
    {
Packit Service 4684c1
      unsigned int mult;
Packit Service 4684c1
Packit Service 4684c1
      /*  Skip over white space following the number we just parsed. */
Packit Service 4684c1
      while (isspace ((unsigned char)*pz))
Packit Service 4684c1
        pz++;
Packit Service 4684c1
Packit Service 4684c1
      switch (*pz)
Packit Service 4684c1
        {
Packit Service 4684c1
        default:  goto bad_time;
Packit Service 4684c1
        case NUL:
Packit Service 4684c1
          return scale_n_add (res, val, 1);
Packit Service 4684c1
Packit Service 4684c1
        case 'y': case 'Y':
Packit Service 4684c1
          if (whatd_we_do >= YEAR_IS_DONE)
Packit Service 4684c1
            goto bad_time;
Packit Service 4684c1
          mult = SEC_PER_YEAR;
Packit Service 4684c1
          whatd_we_do = YEAR_IS_DONE;
Packit Service 4684c1
          break;
Packit Service 4684c1
Packit Service 4684c1
        case 'M':
Packit Service 4684c1
          if (whatd_we_do >= MONTH_IS_DONE)
Packit Service 4684c1
            goto bad_time;
Packit Service 4684c1
          mult = SEC_PER_MONTH;
Packit Service 4684c1
          whatd_we_do = MONTH_IS_DONE;
Packit Service 4684c1
          break;
Packit Service 4684c1
Packit Service 4684c1
        case 'W':
Packit Service 4684c1
          if (whatd_we_do >= WEEK_IS_DONE)
Packit Service 4684c1
            goto bad_time;
Packit Service 4684c1
          mult = SEC_PER_WEEK;
Packit Service 4684c1
          whatd_we_do = WEEK_IS_DONE;
Packit Service 4684c1
          break;
Packit Service 4684c1
Packit Service 4684c1
        case 'd': case 'D':
Packit Service 4684c1
          if (whatd_we_do >= DAY_IS_DONE)
Packit Service 4684c1
            goto bad_time;
Packit Service 4684c1
          mult = SEC_PER_DAY;
Packit Service 4684c1
          whatd_we_do = DAY_IS_DONE;
Packit Service 4684c1
          break;
Packit Service 4684c1
Packit Service 4684c1
        case 'h':
Packit Service 4684c1
          if (whatd_we_do >= HOUR_IS_DONE)
Packit Service 4684c1
            goto bad_time;
Packit Service 4684c1
          mult = SEC_PER_HR;
Packit Service 4684c1
          whatd_we_do = HOUR_IS_DONE;
Packit Service 4684c1
          break;
Packit Service 4684c1
Packit Service 4684c1
        case 'm':
Packit Service 4684c1
          if (whatd_we_do >= MINUTE_IS_DONE)
Packit Service 4684c1
            goto bad_time;
Packit Service 4684c1
          mult = SEC_PER_MIN;
Packit Service 4684c1
          whatd_we_do = MINUTE_IS_DONE;
Packit Service 4684c1
          break;
Packit Service 4684c1
Packit Service 4684c1
        case 's':
Packit Service 4684c1
          mult = 1;
Packit Service 4684c1
          whatd_we_do = SECOND_IS_DONE;
Packit Service 4684c1
          break;
Packit Service 4684c1
        }
Packit Service 4684c1
Packit Service 4684c1
      res = scale_n_add (res, val, mult);
Packit Service 4684c1
Packit Service 4684c1
      pz++;
Packit Service 4684c1
      while (isspace ((unsigned char)*pz))
Packit Service 4684c1
        pz++;
Packit Service 4684c1
      if (*pz == NUL)
Packit Service 4684c1
        return res;
Packit Service 4684c1
Packit Service 4684c1
      if (! isdigit ((unsigned char)*pz))
Packit Service 4684c1
        break;
Packit Service 4684c1
    }
Packit Service 4684c1
Packit Service 4684c1
  } while (whatd_we_do < SECOND_IS_DONE);
Packit Service 4684c1
Packit Service 4684c1
 bad_time:
Packit Service 4684c1
  errno = EINVAL;
Packit Service 4684c1
  return BAD_TIME;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
time_t
Packit Service 4684c1
parse_duration (char const * pz)
Packit Service 4684c1
{
Packit Service 4684c1
  while (isspace ((unsigned char)*pz))
Packit Service 4684c1
    pz++;
Packit Service 4684c1
Packit Service 4684c1
  switch (*pz)
Packit Service 4684c1
    {
Packit Service 4684c1
    case 'P':
Packit Service 4684c1
      return parse_period (pz + 1);
Packit Service 4684c1
Packit Service 4684c1
    case 'T':
Packit Service 4684c1
      return parse_time (pz + 1);
Packit Service 4684c1
Packit Service 4684c1
    default:
Packit Service 4684c1
      if (isdigit ((unsigned char)*pz))
Packit Service 4684c1
        return parse_non_iso8601 (pz);
Packit Service 4684c1
Packit Service 4684c1
      errno = EINVAL;
Packit Service 4684c1
      return BAD_TIME;
Packit Service 4684c1
    }
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/*
Packit Service 4684c1
 * Local Variables:
Packit Service 4684c1
 * mode: C
Packit Service 4684c1
 * c-file-style: "gnu"
Packit Service 4684c1
 * indent-tabs-mode: nil
Packit Service 4684c1
 * End:
Packit Service 4684c1
 * end of parse-duration.c */