parse-duration.c revision 285612
140939Sdes/* Parse a time duration and return a seconds count
2310060Sdes   Copyright (C) 2008-2015 Free Software Foundation, Inc.
3253680Sdes   Written by Bruce Korb <bkorb@gnu.org>, 2008.
440939Sdes
540939Sdes   This program is free software: you can redistribute it and/or modify
640939Sdes   it under the terms of the GNU Lesser General Public License as published by
740939Sdes   the Free Software Foundation; either version 2.1 of the License, or
840939Sdes   (at your option) any later version.
940939Sdes
1040939Sdes   This program is distributed in the hope that it will be useful,
1140939Sdes   but WITHOUT ANY WARRANTY; without even the implied warranty of
1240939Sdes   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1340939Sdes   GNU Lesser General Public License for more details.
1440939Sdes
1540939Sdes   You should have received a copy of the GNU Lesser General Public License
1640939Sdes   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1740939Sdes
1840939Sdes#include <config.h>
1940939Sdes
2040939Sdes/* Specification.  */
2140939Sdes#include "parse-duration.h"
2240939Sdes
2340939Sdes#include <ctype.h>
2440939Sdes#include <errno.h>
2540939Sdes#include <limits.h>
2640939Sdes#include <stdio.h>
2740939Sdes#include <stdlib.h>
2840939Sdes#include <string.h>
2940939Sdes
3084203Sdillon#include "intprops.h"
3184203Sdillon
3284203Sdillon#ifndef NUL
3341862Sdes#define NUL '\0'
3440939Sdes#endif
3555557Sdes
3662981Sdes#define cch_t char const
37174752Sdes
3840939Sdestypedef enum {
3940939Sdes  NOTHING_IS_DONE,
40174752Sdes  YEAR_IS_DONE,
4140939Sdes  MONTH_IS_DONE,
42210568Sdes  WEEK_IS_DONE,
4340939Sdes  DAY_IS_DONE,
44262560Sdes  HOUR_IS_DONE,
45109695Sdes  MINUTE_IS_DONE,
4660924Sdes  SECOND_IS_DONE
4741862Sdes} whats_done_t;
4841862Sdes
4940939Sdes#define SEC_PER_MIN     60
5040939Sdes#define SEC_PER_HR      (SEC_PER_MIN * 60)
5140939Sdes#define SEC_PER_DAY     (SEC_PER_HR  * 24)
52253680Sdes#define SEC_PER_WEEK    (SEC_PER_DAY * 7)
53253680Sdes#define SEC_PER_MONTH   (SEC_PER_DAY * 30)
54253680Sdes#define SEC_PER_YEAR    (SEC_PER_DAY * 365)
55253680Sdes
5640939Sdes#undef  MAX_DURATION
5740939Sdes#define MAX_DURATION    TYPE_MAXIMUM(time_t)
5840939Sdes
5940975Sdes/* Wrapper around strtoul that does not require a cast.  */
6040939Sdesstatic unsigned long
6140939Sdesstr_const_to_ul (cch_t * str, cch_t ** ppz, int base)
6240939Sdes{
6340939Sdes  return strtoul (str, (char **)ppz, base);
6440939Sdes}
65174588Sdes
66121423Sume/* Wrapper around strtol that does not require a cast.  */
6790267Sdesstatic long
68121423Sumestr_const_to_l (cch_t * str, cch_t ** ppz, int base)
6990267Sdes{
7090267Sdes  return strtol (str, (char **)ppz, base);
7190267Sdes}
7290267Sdes
7340939Sdes/* Returns BASE + VAL * SCALE, interpreting BASE = BAD_TIME
7440939Sdes   with errno set as an error situation, and returning BAD_TIME
7562981Sdes   with errno set in an error situation.  */
7675891Sarchiestatic time_t
7740939Sdesscale_n_add (time_t base, time_t val, int scale)
7862981Sdes{
7940939Sdes  if (base == BAD_TIME)
8040939Sdes    {
8140939Sdes      if (errno == 0)
8240939Sdes        errno = EINVAL;
8340939Sdes      return BAD_TIME;
8460924Sdes    }
85174588Sdes
8640939Sdes  if (val > MAX_DURATION / scale)
8790267Sdes    {
8890267Sdes      errno = ERANGE;
8990267Sdes      return BAD_TIME;
9040939Sdes    }
9140939Sdes
9240939Sdes  val *= scale;
9340939Sdes  if (base > MAX_DURATION - val)
9440939Sdes    {
9540939Sdes      errno = ERANGE;
96174588Sdes      return BAD_TIME;
9740939Sdes    }
98174588Sdes
9990267Sdes  return base + val;
10090267Sdes}
10140939Sdes
10240939Sdes/* After a number HH has been parsed, parse subsequent :MM or :MM:SS.  */
10340939Sdesstatic time_t
10440939Sdesparse_hr_min_sec (time_t start, cch_t * pz)
10540939Sdes{
10640939Sdes  int lpct = 0;
107174588Sdes
10840939Sdes  errno = 0;
10990267Sdes
11090267Sdes  /* For as long as our scanner pointer points to a colon *AND*
11190267Sdes     we've not looped before, then keep looping.  (two iterations max) */
11290267Sdes  while ((*pz == ':') && (lpct++ <= 1))
11390267Sdes    {
11490267Sdes      unsigned long v = str_const_to_ul (pz+1, &pz, 10);
11590267Sdes
11690267Sdes      if (errno != 0)
11790267Sdes        return BAD_TIME;
11890267Sdes
11990267Sdes      start = scale_n_add (v, start, 60);
12090267Sdes
12190267Sdes      if (errno != 0)
12290267Sdes        return BAD_TIME;
12390267Sdes    }
12490267Sdes
12590267Sdes  /* allow for trailing spaces */
12690267Sdes  while (isspace ((unsigned char)*pz))
12790267Sdes    pz++;
12890267Sdes  if (*pz != NUL)
12990267Sdes    {
13090267Sdes      errno = EINVAL;
13190267Sdes      return BAD_TIME;
13290267Sdes    }
13390267Sdes
13490267Sdes  return start;
13590267Sdes}
13690267Sdes
13790267Sdes/* Parses a value and returns BASE + value * SCALE, interpreting
13890267Sdes   BASE = BAD_TIME with errno set as an error situation, and returning
13990267Sdes   BAD_TIME with errno set in an error situation.  */
14090267Sdesstatic time_t
14190267Sdesparse_scaled_value (time_t base, cch_t ** ppz, cch_t * endp, int scale)
14290267Sdes{
14390267Sdes  cch_t * pz = *ppz;
14490267Sdes  time_t val;
14590267Sdes
14690267Sdes  if (base == BAD_TIME)
14790267Sdes    return base;
14890267Sdes
14990267Sdes  errno = 0;
15090267Sdes  val = str_const_to_ul (pz, &pz, 10);
15190267Sdes  if (errno != 0)
15290267Sdes    return BAD_TIME;
15390267Sdes  while (isspace ((unsigned char)*pz))
15490267Sdes    pz++;
15590267Sdes  if (pz != endp)
156315904Sdes    {
15790267Sdes      errno = EINVAL;
15890267Sdes      return BAD_TIME;
15990267Sdes    }
16040939Sdes
16140939Sdes  *ppz = pz;
16240939Sdes  return scale_n_add (base, val, scale);
16341862Sdes}
16441862Sdes
16541862Sdes/* Parses the syntax YEAR-MONTH-DAY.
16660924Sdes   PS points into the string, after "YEAR", before "-MONTH-DAY".  */
167174588Sdesstatic time_t
16841862Sdesparse_year_month_day (cch_t * pz, cch_t * ps)
16990267Sdes{
17090267Sdes  time_t res = 0;
17190267Sdes
17290267Sdes  res = parse_scaled_value (0, &pz, ps, SEC_PER_YEAR);
17390267Sdes
17490267Sdes  pz++; /* over the first '-' */
17541862Sdes  ps = strchr (pz, '-');
17641862Sdes  if (ps == NULL)
17741862Sdes    {
17840939Sdes      errno = EINVAL;
17940939Sdes      return BAD_TIME;
18040939Sdes    }
18168551Sdes  res = parse_scaled_value (res, &pz, ps, SEC_PER_MONTH);
18268551Sdes
18368551Sdes  pz++; /* over the second '-' */
184174588Sdes  ps = pz + strlen (pz);
18568551Sdes  return parse_scaled_value (res, &pz, ps, SEC_PER_DAY);
18690267Sdes}
18768551Sdes
18890267Sdes/* Parses the syntax YYYYMMDD.  */
18990267Sdesstatic time_t
19090267Sdesparse_yearmonthday (cch_t * in_pz)
19190267Sdes{
19290267Sdes  time_t res = 0;
19390267Sdes  char   buf[8];
19490267Sdes  cch_t * pz;
19568551Sdes
19668551Sdes  if (strlen (in_pz) != 8)
19768551Sdes    {
19868551Sdes      errno = EINVAL;
19968551Sdes      return BAD_TIME;
20068551Sdes    }
201174588Sdes
20268551Sdes  memcpy (buf, in_pz, 4);
20390267Sdes  buf[4] = NUL;
20490267Sdes  pz = buf;
20590267Sdes  res = parse_scaled_value (0, &pz, buf + 4, SEC_PER_YEAR);
20690267Sdes
20790267Sdes  memcpy (buf, in_pz + 4, 2);
20868551Sdes  buf[2] = NUL;
20968551Sdes  pz =   buf;
21098117Sdes  res = parse_scaled_value (res, &pz, buf + 2, SEC_PER_MONTH);
21168551Sdes
21297866Sdes  memcpy (buf, in_pz + 6, 2);
21397866Sdes  buf[2] = NUL;
21497866Sdes  pz =   buf;
215174588Sdes  return parse_scaled_value (res, &pz, buf + 2, SEC_PER_DAY);
21697866Sdes}
21797866Sdes
218236193Sjilles/* Parses the syntax yy Y mm M ww W dd D.  */
21997866Sdesstatic time_t
22097866Sdesparse_YMWD (cch_t * pz)
221109967Sdes{
22297866Sdes  time_t res = 0;
223221830Sdes  cch_t * ps = strchr (pz, 'Y');
224236193Sjilles  if (ps != NULL)
22597866Sdes    {
22698117Sdes      res = parse_scaled_value (0, &pz, ps, SEC_PER_YEAR);
22797866Sdes      pz++;
22897866Sdes    }
22997866Sdes
23097866Sdes  ps = strchr (pz, 'M');
23197866Sdes  if (ps != NULL)
23298117Sdes    {
23398117Sdes      res = parse_scaled_value (res, &pz, ps, SEC_PER_MONTH);
23498117Sdes      pz++;
235174588Sdes    }
23698117Sdes
23798117Sdes  ps = strchr (pz, 'W');
23898117Sdes  if (ps != NULL)
23998117Sdes    {
24098117Sdes      res = parse_scaled_value (res, &pz, ps, SEC_PER_WEEK);
24198117Sdes      pz++;
24298117Sdes    }
24398117Sdes
244310060Sdes  ps = strchr (pz, 'D');
245310060Sdes  if (ps != NULL)
246310060Sdes    {
247310060Sdes      res = parse_scaled_value (res, &pz, ps, SEC_PER_DAY);
248310060Sdes      pz++;
249310060Sdes    }
250310060Sdes
251315904Sdes  while (isspace ((unsigned char)*pz))
252315904Sdes    pz++;
253310060Sdes  if (*pz != NUL)
254310060Sdes    {
255315904Sdes      errno = EINVAL;
256315904Sdes      return BAD_TIME;
257315904Sdes    }
258315904Sdes
259315904Sdes  return res;
260315904Sdes}
261315904Sdes
262315904Sdes/* Parses the syntax HH:MM:SS.
263315904Sdes   PS points into the string, after "HH", before ":MM:SS".  */
264315904Sdesstatic time_t
265315904Sdesparse_hour_minute_second (cch_t * pz, cch_t * ps)
266315904Sdes{
267315904Sdes  time_t res = 0;
268315904Sdes
269315904Sdes  res = parse_scaled_value (0, &pz, ps, SEC_PER_HR);
270315904Sdes
271310060Sdes  pz++;
272315904Sdes  ps = strchr (pz, ':');
273310060Sdes  if (ps == NULL)
274315904Sdes    {
275310060Sdes      errno = EINVAL;
276310060Sdes      return BAD_TIME;
277315904Sdes    }
278310060Sdes
279310060Sdes  res = parse_scaled_value (res, &pz, ps, SEC_PER_MIN);
280315904Sdes
281315904Sdes  pz++;
282315904Sdes  ps = pz + strlen (pz);
283315904Sdes  return parse_scaled_value (res, &pz, ps, 1);
284315904Sdes}
285315904Sdes
286310060Sdes/* Parses the syntax HHMMSS.  */
287310060Sdesstatic time_t
288315904Sdesparse_hourminutesecond (cch_t * in_pz)
289310060Sdes{
290315904Sdes  time_t res = 0;
291315904Sdes  char   buf[4];
292310060Sdes  cch_t * pz;
293315904Sdes
294323660Smarius  if (strlen (in_pz) != 6)
295310060Sdes    {
296310060Sdes      errno = EINVAL;
297310060Sdes      return BAD_TIME;
298310060Sdes    }
299310060Sdes
300310060Sdes  memcpy (buf, in_pz, 2);
301310060Sdes  buf[2] = NUL;
302310060Sdes  pz = buf;
303310060Sdes  res = parse_scaled_value (0, &pz, buf + 2, SEC_PER_HR);
304310060Sdes
305310060Sdes  memcpy (buf, in_pz + 2, 2);
306310060Sdes  buf[2] = NUL;
307310060Sdes  pz =   buf;
308310060Sdes  res = parse_scaled_value (res, &pz, buf + 2, SEC_PER_MIN);
309315904Sdes
310315904Sdes  memcpy (buf, in_pz + 4, 2);
311315904Sdes  buf[2] = NUL;
312310060Sdes  pz =   buf;
313310060Sdes  return parse_scaled_value (res, &pz, buf + 2, 1);
314310060Sdes}
315310060Sdes
316310060Sdes/* Parses the syntax hh H mm M ss S.  */
317111816Sdesstatic time_t
318111816Sdesparse_HMS (cch_t * pz)
319111816Sdes{
320174588Sdes  time_t res = 0;
321111816Sdes  cch_t * ps = strchr (pz, 'H');
322310060Sdes  if (ps != NULL)
323111816Sdes    {
324111816Sdes      res = parse_scaled_value (0, &pz, ps, SEC_PER_HR);
325310060Sdes      pz++;
326111816Sdes    }
327310060Sdes
328310060Sdes  ps = strchr (pz, 'M');
329310060Sdes  if (ps != NULL)
330310060Sdes    {
331310060Sdes      res = parse_scaled_value (res, &pz, ps, SEC_PER_MIN);
332310060Sdes      pz++;
333310060Sdes    }
334111816Sdes
335111816Sdes  ps = strchr (pz, 'S');
336111816Sdes  if (ps != NULL)
337111816Sdes    {
33840939Sdes      res = parse_scaled_value (res, &pz, ps, 1);
33940939Sdes      pz++;
34097856Sdes    }
341174588Sdes
34240939Sdes  while (isspace ((unsigned char)*pz))
343310060Sdes    pz++;
344111816Sdes  if (*pz != NUL)
345310060Sdes    {
346310060Sdes      errno = EINVAL;
34740939Sdes      return BAD_TIME;
34890267Sdes    }
34941862Sdes
350310060Sdes  return res;
35190267Sdes}
352310060Sdes
353310060Sdes/* Parses a time (hours, minutes, seconds) specification in either syntax.  */
354310060Sdesstatic time_t
35540939Sdesparse_time (cch_t * pz)
356310060Sdes{
357310060Sdes  cch_t * ps;
358310060Sdes  time_t  res = 0;
359310060Sdes
360310060Sdes  /*
361310060Sdes   *  Scan for a hyphen
362310060Sdes   */
36390267Sdes  ps = strchr (pz, ':');
36490267Sdes  if (ps != NULL)
365310060Sdes    {
366310060Sdes      res = parse_hour_minute_second (pz, ps);
367310060Sdes    }
368310060Sdes
369310060Sdes  /*
370310060Sdes   *  Try for a 'H', 'M' or 'S' suffix
371310060Sdes   */
372310060Sdes  else if (ps = strpbrk (pz, "HMS"),
373310060Sdes           ps == NULL)
374310060Sdes    {
375310060Sdes      /* Its a YYYYMMDD format: */
376111816Sdes      res = parse_hourminutesecond (pz);
377310060Sdes    }
378310060Sdes
379310060Sdes  else
380310060Sdes    res = parse_HMS (pz);
381310060Sdes
382310060Sdes  return res;
383310060Sdes}
38490267Sdes
385310060Sdes/* Returns a substring of the given string, with spaces at the beginning and at
38690267Sdes   the end destructively removed, per SNOBOL.  */
387310060Sdesstatic char *
38890267Sdestrim (char * pz)
389310060Sdes{
390310060Sdes  /* trim leading white space */
391315904Sdes  while (isspace ((unsigned char)*pz))
392310060Sdes    pz++;
39390267Sdes
39440939Sdes  /* trim trailing white space */
395310060Sdes  {
396310060Sdes    char * pe = pz + strlen (pz);
397310060Sdes    while ((pe > pz) && isspace ((unsigned char)pe[-1]))
398310060Sdes      pe--;
399310060Sdes    *pe = NUL;
400310060Sdes  }
401310060Sdes
402310060Sdes  return pz;
403310060Sdes}
404310060Sdes
405310060Sdes/*
406310060Sdes *  Parse the year/months/days of a time period
40797856Sdes */
408310060Sdesstatic time_t
409310060Sdesparse_period (cch_t * in_pz)
410310060Sdes{
411310060Sdes  char * pT;
412310060Sdes  char * ps;
41340939Sdes  char * pz   = strdup (in_pz);
41441989Sdes  void * fptr = pz;
415253680Sdes  time_t res  = 0;
416253680Sdes
417253680Sdes  if (pz == NULL)
418253680Sdes    {
419253680Sdes      errno = ENOMEM;
420253680Sdes      return BAD_TIME;
421253680Sdes    }
422253680Sdes
423253680Sdes  pT = strchr (pz, 'T');
424253680Sdes  if (pT != NULL)
425253680Sdes    {
426253680Sdes      *(pT++) = NUL;
427253680Sdes      pz = trim (pz);
42841989Sdes      pT = trim (pT);
42955557Sdes    }
430253680Sdes
431253680Sdes  /*
432253680Sdes   *  Scan for a hyphen
433253680Sdes   */
434253680Sdes  ps = strchr (pz, '-');
435253680Sdes  if (ps != NULL)
436253680Sdes    {
437253680Sdes      res = parse_year_month_day (pz, ps);
438253680Sdes    }
439253680Sdes
440253680Sdes  /*
441253680Sdes   *  Try for a 'Y', 'M' or 'D' suffix
442253680Sdes   */
443253680Sdes  else if (ps = strpbrk (pz, "YMWD"),
444253680Sdes           ps == NULL)
445253680Sdes    {
446253680Sdes      /* Its a YYYYMMDD format: */
447253680Sdes      res = parse_yearmonthday (pz);
448253680Sdes    }
449253680Sdes
450253680Sdes  else
451253680Sdes    res = parse_YMWD (pz);
452253680Sdes
453253680Sdes  if ((errno == 0) && (pT != NULL))
454253680Sdes    {
455253680Sdes      time_t val = parse_time (pT);
456253680Sdes      res = scale_n_add (res, val, 1);
457253680Sdes    }
458253680Sdes
459253680Sdes  free (fptr);
460253680Sdes  return res;
461253680Sdes}
462253680Sdes
463253680Sdesstatic time_t
464253680Sdesparse_non_iso8601 (cch_t * pz)
465253680Sdes{
466253680Sdes  whats_done_t whatd_we_do = NOTHING_IS_DONE;
467253680Sdes
468253680Sdes  time_t res = 0;
469253680Sdes
470253680Sdes  do  {
471253680Sdes    time_t val;
472253680Sdes
473253680Sdes    errno = 0;
474253680Sdes    val = str_const_to_l (pz, &pz, 10);
475253680Sdes    if (errno != 0)
476253680Sdes      goto bad_time;
477253680Sdes
478253680Sdes    /*  IF we find a colon, then we're going to have a seconds value.
479253680Sdes        We will not loop here any more.  We cannot already have parsed
480253680Sdes        a minute value and if we've parsed an hour value, then the result
481253680Sdes        value has to be less than an hour. */
482253680Sdes    if (*pz == ':')
483253680Sdes      {
484253680Sdes        if (whatd_we_do >= MINUTE_IS_DONE)
485253680Sdes          break;
486253680Sdes
487253680Sdes        val = parse_hr_min_sec (val, pz);
488253680Sdes
489253680Sdes        if ((whatd_we_do == HOUR_IS_DONE) && (val >= SEC_PER_HR))
490253680Sdes          break;
491253680Sdes
492253680Sdes        return scale_n_add (res, val, 1);
493253680Sdes      }
494253680Sdes
495253680Sdes    {
496253680Sdes      unsigned int mult;
497253680Sdes
498253680Sdes      /*  Skip over white space following the number we just parsed. */
499253680Sdes      while (isspace ((unsigned char)*pz))
500253680Sdes        pz++;
501253680Sdes
502253680Sdes      switch (*pz)
503253680Sdes        {
504253680Sdes        default:  goto bad_time;
505253680Sdes        case NUL:
506253680Sdes          return scale_n_add (res, val, 1);
507253680Sdes
508253680Sdes        case 'y': case 'Y':
509253680Sdes          if (whatd_we_do >= YEAR_IS_DONE)
510253680Sdes            goto bad_time;
511253680Sdes          mult = SEC_PER_YEAR;
512253680Sdes          whatd_we_do = YEAR_IS_DONE;
513253680Sdes          break;
514253680Sdes
515253680Sdes        case 'M':
516253680Sdes          if (whatd_we_do >= MONTH_IS_DONE)
517253680Sdes            goto bad_time;
518253680Sdes          mult = SEC_PER_MONTH;
519253680Sdes          whatd_we_do = MONTH_IS_DONE;
520253680Sdes          break;
521253680Sdes
522253680Sdes        case 'W':
523253680Sdes          if (whatd_we_do >= WEEK_IS_DONE)
524253680Sdes            goto bad_time;
525253680Sdes          mult = SEC_PER_WEEK;
526253680Sdes          whatd_we_do = WEEK_IS_DONE;
527253680Sdes          break;
528253680Sdes
529253680Sdes        case 'd': case 'D':
530253680Sdes          if (whatd_we_do >= DAY_IS_DONE)
531253680Sdes            goto bad_time;
532253680Sdes          mult = SEC_PER_DAY;
533253680Sdes          whatd_we_do = DAY_IS_DONE;
534253680Sdes          break;
535253680Sdes
536253680Sdes        case 'h':
537253680Sdes          if (whatd_we_do >= HOUR_IS_DONE)
538253680Sdes            goto bad_time;
539253680Sdes          mult = SEC_PER_HR;
540253680Sdes          whatd_we_do = HOUR_IS_DONE;
541253680Sdes          break;
542253680Sdes
543253680Sdes        case 'm':
544253680Sdes          if (whatd_we_do >= MINUTE_IS_DONE)
545253680Sdes            goto bad_time;
546253680Sdes          mult = SEC_PER_MIN;
547253680Sdes          whatd_we_do = MINUTE_IS_DONE;
548253680Sdes          break;
549253680Sdes
550253680Sdes        case 's':
551253680Sdes          mult = 1;
552253680Sdes          whatd_we_do = SECOND_IS_DONE;
553253680Sdes          break;
554253680Sdes        }
555253680Sdes
556253680Sdes      res = scale_n_add (res, val, mult);
557253680Sdes
558253680Sdes      pz++;
559253680Sdes      while (isspace ((unsigned char)*pz))
560253680Sdes        pz++;
561253680Sdes      if (*pz == NUL)
562253680Sdes        return res;
563253680Sdes
564253680Sdes      if (! isdigit ((unsigned char)*pz))
565253680Sdes        break;
566253680Sdes    }
567253680Sdes
568253680Sdes  } while (whatd_we_do < SECOND_IS_DONE);
569253680Sdes
570253680Sdes bad_time:
571253680Sdes  errno = EINVAL;
572253680Sdes  return BAD_TIME;
573253680Sdes}
574253680Sdes
575253680Sdestime_t
576253680Sdesparse_duration (char const * pz)
577253680Sdes{
578253680Sdes  while (isspace ((unsigned char)*pz))
579253680Sdes    pz++;
580253680Sdes
581253680Sdes  switch (*pz)
582253680Sdes    {
583253680Sdes    case 'P':
584253680Sdes      return parse_period (pz + 1);
585253680Sdes
586253680Sdes    case 'T':
587294194Sdes      return parse_time (pz + 1);
588294194Sdes
589253680Sdes    default:
590253680Sdes      if (isdigit ((unsigned char)*pz))
591253680Sdes        return parse_non_iso8601 (pz);
592253680Sdes
593253680Sdes      errno = EINVAL;
594253680Sdes      return BAD_TIME;
595253680Sdes    }
596253680Sdes}
597253680Sdes
598253680Sdes/*
599253680Sdes * Local Variables:
600253680Sdes * mode: C
601253680Sdes * c-file-style: "gnu"
602253680Sdes * indent-tabs-mode: nil
603253680Sdes * End:
604253680Sdes * end of parse-duration.c */
605253680Sdes