1258945Sroberto/* Parse a time duration and return a seconds count 2285612Sdelphij Copyright (C) 2008-2015 Free Software Foundation, Inc. 3258945Sroberto Written by Bruce Korb <bkorb@gnu.org>, 2008. 4258945Sroberto 5258945Sroberto This program is free software: you can redistribute it and/or modify 6280849Scy it under the terms of the GNU Lesser General Public License as published by 7280849Scy the Free Software Foundation; either version 2.1 of the License, or 8258945Sroberto (at your option) any later version. 9258945Sroberto 10258945Sroberto This program is distributed in the hope that it will be useful, 11258945Sroberto but WITHOUT ANY WARRANTY; without even the implied warranty of 12258945Sroberto MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13280849Scy GNU Lesser General Public License for more details. 14258945Sroberto 15280849Scy You should have received a copy of the GNU Lesser General Public License 16258945Sroberto along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17258945Sroberto 18258945Sroberto#include <config.h> 19258945Sroberto 20258945Sroberto/* Specification. */ 21258945Sroberto#include "parse-duration.h" 22258945Sroberto 23258945Sroberto#include <ctype.h> 24258945Sroberto#include <errno.h> 25258945Sroberto#include <limits.h> 26258945Sroberto#include <stdio.h> 27258945Sroberto#include <stdlib.h> 28258945Sroberto#include <string.h> 29258945Sroberto 30280849Scy#include "intprops.h" 31280849Scy 32258945Sroberto#ifndef NUL 33258945Sroberto#define NUL '\0' 34258945Sroberto#endif 35258945Sroberto 36258945Sroberto#define cch_t char const 37258945Sroberto 38258945Srobertotypedef enum { 39258945Sroberto NOTHING_IS_DONE, 40258945Sroberto YEAR_IS_DONE, 41258945Sroberto MONTH_IS_DONE, 42258945Sroberto WEEK_IS_DONE, 43258945Sroberto DAY_IS_DONE, 44258945Sroberto HOUR_IS_DONE, 45258945Sroberto MINUTE_IS_DONE, 46258945Sroberto SECOND_IS_DONE 47258945Sroberto} whats_done_t; 48258945Sroberto 49258945Sroberto#define SEC_PER_MIN 60 50258945Sroberto#define SEC_PER_HR (SEC_PER_MIN * 60) 51258945Sroberto#define SEC_PER_DAY (SEC_PER_HR * 24) 52258945Sroberto#define SEC_PER_WEEK (SEC_PER_DAY * 7) 53258945Sroberto#define SEC_PER_MONTH (SEC_PER_DAY * 30) 54258945Sroberto#define SEC_PER_YEAR (SEC_PER_DAY * 365) 55258945Sroberto 56280849Scy#undef MAX_DURATION 57280849Scy#define MAX_DURATION TYPE_MAXIMUM(time_t) 58258945Sroberto 59258945Sroberto/* Wrapper around strtoul that does not require a cast. */ 60280849Scystatic unsigned long 61258945Srobertostr_const_to_ul (cch_t * str, cch_t ** ppz, int base) 62258945Sroberto{ 63294569Sdelphij char * pz; 64294569Sdelphij int rv = strtoul (str, &pz, base); 65294569Sdelphij *ppz = pz; 66294569Sdelphij return rv; 67258945Sroberto} 68258945Sroberto 69258945Sroberto/* Wrapper around strtol that does not require a cast. */ 70280849Scystatic long 71258945Srobertostr_const_to_l (cch_t * str, cch_t ** ppz, int base) 72258945Sroberto{ 73294569Sdelphij char * pz; 74294569Sdelphij int rv = strtol (str, &pz, base); 75294569Sdelphij *ppz = pz; 76294569Sdelphij return rv; 77258945Sroberto} 78258945Sroberto 79258945Sroberto/* Returns BASE + VAL * SCALE, interpreting BASE = BAD_TIME 80258945Sroberto with errno set as an error situation, and returning BAD_TIME 81258945Sroberto with errno set in an error situation. */ 82280849Scystatic time_t 83258945Srobertoscale_n_add (time_t base, time_t val, int scale) 84258945Sroberto{ 85258945Sroberto if (base == BAD_TIME) 86258945Sroberto { 87258945Sroberto if (errno == 0) 88258945Sroberto errno = EINVAL; 89258945Sroberto return BAD_TIME; 90258945Sroberto } 91258945Sroberto 92280849Scy if (val > MAX_DURATION / scale) 93258945Sroberto { 94258945Sroberto errno = ERANGE; 95258945Sroberto return BAD_TIME; 96258945Sroberto } 97258945Sroberto 98258945Sroberto val *= scale; 99280849Scy if (base > MAX_DURATION - val) 100258945Sroberto { 101258945Sroberto errno = ERANGE; 102258945Sroberto return BAD_TIME; 103258945Sroberto } 104258945Sroberto 105258945Sroberto return base + val; 106258945Sroberto} 107258945Sroberto 108258945Sroberto/* After a number HH has been parsed, parse subsequent :MM or :MM:SS. */ 109258945Srobertostatic time_t 110258945Srobertoparse_hr_min_sec (time_t start, cch_t * pz) 111258945Sroberto{ 112258945Sroberto int lpct = 0; 113258945Sroberto 114258945Sroberto errno = 0; 115258945Sroberto 116258945Sroberto /* For as long as our scanner pointer points to a colon *AND* 117258945Sroberto we've not looped before, then keep looping. (two iterations max) */ 118258945Sroberto while ((*pz == ':') && (lpct++ <= 1)) 119258945Sroberto { 120258945Sroberto unsigned long v = str_const_to_ul (pz+1, &pz, 10); 121258945Sroberto 122258945Sroberto if (errno != 0) 123258945Sroberto return BAD_TIME; 124258945Sroberto 125258945Sroberto start = scale_n_add (v, start, 60); 126258945Sroberto 127258945Sroberto if (errno != 0) 128258945Sroberto return BAD_TIME; 129258945Sroberto } 130258945Sroberto 131258945Sroberto /* allow for trailing spaces */ 132258945Sroberto while (isspace ((unsigned char)*pz)) 133258945Sroberto pz++; 134258945Sroberto if (*pz != NUL) 135258945Sroberto { 136258945Sroberto errno = EINVAL; 137258945Sroberto return BAD_TIME; 138258945Sroberto } 139258945Sroberto 140258945Sroberto return start; 141258945Sroberto} 142258945Sroberto 143258945Sroberto/* Parses a value and returns BASE + value * SCALE, interpreting 144258945Sroberto BASE = BAD_TIME with errno set as an error situation, and returning 145258945Sroberto BAD_TIME with errno set in an error situation. */ 146258945Srobertostatic time_t 147258945Srobertoparse_scaled_value (time_t base, cch_t ** ppz, cch_t * endp, int scale) 148258945Sroberto{ 149258945Sroberto cch_t * pz = *ppz; 150258945Sroberto time_t val; 151258945Sroberto 152258945Sroberto if (base == BAD_TIME) 153258945Sroberto return base; 154258945Sroberto 155258945Sroberto errno = 0; 156258945Sroberto val = str_const_to_ul (pz, &pz, 10); 157258945Sroberto if (errno != 0) 158258945Sroberto return BAD_TIME; 159258945Sroberto while (isspace ((unsigned char)*pz)) 160258945Sroberto pz++; 161258945Sroberto if (pz != endp) 162258945Sroberto { 163258945Sroberto errno = EINVAL; 164258945Sroberto return BAD_TIME; 165258945Sroberto } 166258945Sroberto 167258945Sroberto *ppz = pz; 168258945Sroberto return scale_n_add (base, val, scale); 169258945Sroberto} 170258945Sroberto 171258945Sroberto/* Parses the syntax YEAR-MONTH-DAY. 172258945Sroberto PS points into the string, after "YEAR", before "-MONTH-DAY". */ 173258945Srobertostatic time_t 174258945Srobertoparse_year_month_day (cch_t * pz, cch_t * ps) 175258945Sroberto{ 176258945Sroberto time_t res = 0; 177258945Sroberto 178258945Sroberto res = parse_scaled_value (0, &pz, ps, SEC_PER_YEAR); 179258945Sroberto 180258945Sroberto pz++; /* over the first '-' */ 181258945Sroberto ps = strchr (pz, '-'); 182258945Sroberto if (ps == NULL) 183258945Sroberto { 184258945Sroberto errno = EINVAL; 185258945Sroberto return BAD_TIME; 186258945Sroberto } 187258945Sroberto res = parse_scaled_value (res, &pz, ps, SEC_PER_MONTH); 188258945Sroberto 189258945Sroberto pz++; /* over the second '-' */ 190258945Sroberto ps = pz + strlen (pz); 191258945Sroberto return parse_scaled_value (res, &pz, ps, SEC_PER_DAY); 192258945Sroberto} 193258945Sroberto 194258945Sroberto/* Parses the syntax YYYYMMDD. */ 195258945Srobertostatic time_t 196258945Srobertoparse_yearmonthday (cch_t * in_pz) 197258945Sroberto{ 198258945Sroberto time_t res = 0; 199258945Sroberto char buf[8]; 200258945Sroberto cch_t * pz; 201258945Sroberto 202258945Sroberto if (strlen (in_pz) != 8) 203258945Sroberto { 204258945Sroberto errno = EINVAL; 205258945Sroberto return BAD_TIME; 206258945Sroberto } 207258945Sroberto 208258945Sroberto memcpy (buf, in_pz, 4); 209258945Sroberto buf[4] = NUL; 210258945Sroberto pz = buf; 211258945Sroberto res = parse_scaled_value (0, &pz, buf + 4, SEC_PER_YEAR); 212258945Sroberto 213258945Sroberto memcpy (buf, in_pz + 4, 2); 214258945Sroberto buf[2] = NUL; 215258945Sroberto pz = buf; 216258945Sroberto res = parse_scaled_value (res, &pz, buf + 2, SEC_PER_MONTH); 217258945Sroberto 218258945Sroberto memcpy (buf, in_pz + 6, 2); 219258945Sroberto buf[2] = NUL; 220258945Sroberto pz = buf; 221258945Sroberto return parse_scaled_value (res, &pz, buf + 2, SEC_PER_DAY); 222258945Sroberto} 223258945Sroberto 224258945Sroberto/* Parses the syntax yy Y mm M ww W dd D. */ 225258945Srobertostatic time_t 226258945Srobertoparse_YMWD (cch_t * pz) 227258945Sroberto{ 228258945Sroberto time_t res = 0; 229258945Sroberto cch_t * ps = strchr (pz, 'Y'); 230258945Sroberto if (ps != NULL) 231258945Sroberto { 232258945Sroberto res = parse_scaled_value (0, &pz, ps, SEC_PER_YEAR); 233258945Sroberto pz++; 234258945Sroberto } 235258945Sroberto 236258945Sroberto ps = strchr (pz, 'M'); 237258945Sroberto if (ps != NULL) 238258945Sroberto { 239258945Sroberto res = parse_scaled_value (res, &pz, ps, SEC_PER_MONTH); 240258945Sroberto pz++; 241258945Sroberto } 242258945Sroberto 243258945Sroberto ps = strchr (pz, 'W'); 244258945Sroberto if (ps != NULL) 245258945Sroberto { 246258945Sroberto res = parse_scaled_value (res, &pz, ps, SEC_PER_WEEK); 247258945Sroberto pz++; 248258945Sroberto } 249258945Sroberto 250258945Sroberto ps = strchr (pz, 'D'); 251258945Sroberto if (ps != NULL) 252258945Sroberto { 253258945Sroberto res = parse_scaled_value (res, &pz, ps, SEC_PER_DAY); 254258945Sroberto pz++; 255258945Sroberto } 256258945Sroberto 257258945Sroberto while (isspace ((unsigned char)*pz)) 258258945Sroberto pz++; 259258945Sroberto if (*pz != NUL) 260258945Sroberto { 261258945Sroberto errno = EINVAL; 262258945Sroberto return BAD_TIME; 263258945Sroberto } 264258945Sroberto 265258945Sroberto return res; 266258945Sroberto} 267258945Sroberto 268258945Sroberto/* Parses the syntax HH:MM:SS. 269258945Sroberto PS points into the string, after "HH", before ":MM:SS". */ 270258945Srobertostatic time_t 271258945Srobertoparse_hour_minute_second (cch_t * pz, cch_t * ps) 272258945Sroberto{ 273258945Sroberto time_t res = 0; 274258945Sroberto 275258945Sroberto res = parse_scaled_value (0, &pz, ps, SEC_PER_HR); 276258945Sroberto 277258945Sroberto pz++; 278258945Sroberto ps = strchr (pz, ':'); 279258945Sroberto if (ps == NULL) 280258945Sroberto { 281258945Sroberto errno = EINVAL; 282258945Sroberto return BAD_TIME; 283258945Sroberto } 284258945Sroberto 285258945Sroberto res = parse_scaled_value (res, &pz, ps, SEC_PER_MIN); 286258945Sroberto 287258945Sroberto pz++; 288258945Sroberto ps = pz + strlen (pz); 289258945Sroberto return parse_scaled_value (res, &pz, ps, 1); 290258945Sroberto} 291258945Sroberto 292258945Sroberto/* Parses the syntax HHMMSS. */ 293258945Srobertostatic time_t 294258945Srobertoparse_hourminutesecond (cch_t * in_pz) 295258945Sroberto{ 296258945Sroberto time_t res = 0; 297258945Sroberto char buf[4]; 298258945Sroberto cch_t * pz; 299258945Sroberto 300258945Sroberto if (strlen (in_pz) != 6) 301258945Sroberto { 302258945Sroberto errno = EINVAL; 303258945Sroberto return BAD_TIME; 304258945Sroberto } 305258945Sroberto 306258945Sroberto memcpy (buf, in_pz, 2); 307258945Sroberto buf[2] = NUL; 308258945Sroberto pz = buf; 309258945Sroberto res = parse_scaled_value (0, &pz, buf + 2, SEC_PER_HR); 310258945Sroberto 311258945Sroberto memcpy (buf, in_pz + 2, 2); 312258945Sroberto buf[2] = NUL; 313258945Sroberto pz = buf; 314258945Sroberto res = parse_scaled_value (res, &pz, buf + 2, SEC_PER_MIN); 315258945Sroberto 316258945Sroberto memcpy (buf, in_pz + 4, 2); 317258945Sroberto buf[2] = NUL; 318258945Sroberto pz = buf; 319258945Sroberto return parse_scaled_value (res, &pz, buf + 2, 1); 320258945Sroberto} 321258945Sroberto 322258945Sroberto/* Parses the syntax hh H mm M ss S. */ 323258945Srobertostatic time_t 324258945Srobertoparse_HMS (cch_t * pz) 325258945Sroberto{ 326258945Sroberto time_t res = 0; 327258945Sroberto cch_t * ps = strchr (pz, 'H'); 328258945Sroberto if (ps != NULL) 329258945Sroberto { 330258945Sroberto res = parse_scaled_value (0, &pz, ps, SEC_PER_HR); 331258945Sroberto pz++; 332258945Sroberto } 333258945Sroberto 334258945Sroberto ps = strchr (pz, 'M'); 335258945Sroberto if (ps != NULL) 336258945Sroberto { 337258945Sroberto res = parse_scaled_value (res, &pz, ps, SEC_PER_MIN); 338258945Sroberto pz++; 339258945Sroberto } 340258945Sroberto 341258945Sroberto ps = strchr (pz, 'S'); 342258945Sroberto if (ps != NULL) 343258945Sroberto { 344258945Sroberto res = parse_scaled_value (res, &pz, ps, 1); 345258945Sroberto pz++; 346258945Sroberto } 347258945Sroberto 348258945Sroberto while (isspace ((unsigned char)*pz)) 349258945Sroberto pz++; 350258945Sroberto if (*pz != NUL) 351258945Sroberto { 352258945Sroberto errno = EINVAL; 353258945Sroberto return BAD_TIME; 354258945Sroberto } 355258945Sroberto 356258945Sroberto return res; 357258945Sroberto} 358258945Sroberto 359258945Sroberto/* Parses a time (hours, minutes, seconds) specification in either syntax. */ 360258945Srobertostatic time_t 361258945Srobertoparse_time (cch_t * pz) 362258945Sroberto{ 363258945Sroberto cch_t * ps; 364258945Sroberto time_t res = 0; 365258945Sroberto 366258945Sroberto /* 367258945Sroberto * Scan for a hyphen 368258945Sroberto */ 369258945Sroberto ps = strchr (pz, ':'); 370258945Sroberto if (ps != NULL) 371258945Sroberto { 372258945Sroberto res = parse_hour_minute_second (pz, ps); 373258945Sroberto } 374258945Sroberto 375258945Sroberto /* 376258945Sroberto * Try for a 'H', 'M' or 'S' suffix 377258945Sroberto */ 378258945Sroberto else if (ps = strpbrk (pz, "HMS"), 379258945Sroberto ps == NULL) 380258945Sroberto { 381258945Sroberto /* Its a YYYYMMDD format: */ 382258945Sroberto res = parse_hourminutesecond (pz); 383258945Sroberto } 384258945Sroberto 385258945Sroberto else 386258945Sroberto res = parse_HMS (pz); 387258945Sroberto 388258945Sroberto return res; 389258945Sroberto} 390258945Sroberto 391258945Sroberto/* Returns a substring of the given string, with spaces at the beginning and at 392258945Sroberto the end destructively removed, per SNOBOL. */ 393258945Srobertostatic char * 394258945Srobertotrim (char * pz) 395258945Sroberto{ 396258945Sroberto /* trim leading white space */ 397258945Sroberto while (isspace ((unsigned char)*pz)) 398258945Sroberto pz++; 399258945Sroberto 400258945Sroberto /* trim trailing white space */ 401258945Sroberto { 402258945Sroberto char * pe = pz + strlen (pz); 403258945Sroberto while ((pe > pz) && isspace ((unsigned char)pe[-1])) 404258945Sroberto pe--; 405258945Sroberto *pe = NUL; 406258945Sroberto } 407258945Sroberto 408258945Sroberto return pz; 409258945Sroberto} 410258945Sroberto 411258945Sroberto/* 412258945Sroberto * Parse the year/months/days of a time period 413258945Sroberto */ 414258945Srobertostatic time_t 415258945Srobertoparse_period (cch_t * in_pz) 416258945Sroberto{ 417258945Sroberto char * pT; 418258945Sroberto char * ps; 419258945Sroberto char * pz = strdup (in_pz); 420258945Sroberto void * fptr = pz; 421258945Sroberto time_t res = 0; 422258945Sroberto 423258945Sroberto if (pz == NULL) 424258945Sroberto { 425258945Sroberto errno = ENOMEM; 426258945Sroberto return BAD_TIME; 427258945Sroberto } 428258945Sroberto 429258945Sroberto pT = strchr (pz, 'T'); 430258945Sroberto if (pT != NULL) 431258945Sroberto { 432258945Sroberto *(pT++) = NUL; 433258945Sroberto pz = trim (pz); 434258945Sroberto pT = trim (pT); 435258945Sroberto } 436258945Sroberto 437258945Sroberto /* 438258945Sroberto * Scan for a hyphen 439258945Sroberto */ 440258945Sroberto ps = strchr (pz, '-'); 441258945Sroberto if (ps != NULL) 442258945Sroberto { 443258945Sroberto res = parse_year_month_day (pz, ps); 444258945Sroberto } 445258945Sroberto 446258945Sroberto /* 447258945Sroberto * Try for a 'Y', 'M' or 'D' suffix 448258945Sroberto */ 449258945Sroberto else if (ps = strpbrk (pz, "YMWD"), 450258945Sroberto ps == NULL) 451258945Sroberto { 452258945Sroberto /* Its a YYYYMMDD format: */ 453258945Sroberto res = parse_yearmonthday (pz); 454258945Sroberto } 455258945Sroberto 456258945Sroberto else 457258945Sroberto res = parse_YMWD (pz); 458258945Sroberto 459258945Sroberto if ((errno == 0) && (pT != NULL)) 460258945Sroberto { 461258945Sroberto time_t val = parse_time (pT); 462258945Sroberto res = scale_n_add (res, val, 1); 463258945Sroberto } 464258945Sroberto 465258945Sroberto free (fptr); 466258945Sroberto return res; 467258945Sroberto} 468258945Sroberto 469258945Srobertostatic time_t 470258945Srobertoparse_non_iso8601 (cch_t * pz) 471258945Sroberto{ 472258945Sroberto whats_done_t whatd_we_do = NOTHING_IS_DONE; 473258945Sroberto 474258945Sroberto time_t res = 0; 475258945Sroberto 476258945Sroberto do { 477258945Sroberto time_t val; 478258945Sroberto 479258945Sroberto errno = 0; 480258945Sroberto val = str_const_to_l (pz, &pz, 10); 481258945Sroberto if (errno != 0) 482258945Sroberto goto bad_time; 483258945Sroberto 484258945Sroberto /* IF we find a colon, then we're going to have a seconds value. 485258945Sroberto We will not loop here any more. We cannot already have parsed 486258945Sroberto a minute value and if we've parsed an hour value, then the result 487258945Sroberto value has to be less than an hour. */ 488258945Sroberto if (*pz == ':') 489258945Sroberto { 490258945Sroberto if (whatd_we_do >= MINUTE_IS_DONE) 491258945Sroberto break; 492258945Sroberto 493258945Sroberto val = parse_hr_min_sec (val, pz); 494258945Sroberto 495258945Sroberto if ((whatd_we_do == HOUR_IS_DONE) && (val >= SEC_PER_HR)) 496258945Sroberto break; 497258945Sroberto 498258945Sroberto return scale_n_add (res, val, 1); 499258945Sroberto } 500258945Sroberto 501258945Sroberto { 502258945Sroberto unsigned int mult; 503258945Sroberto 504258945Sroberto /* Skip over white space following the number we just parsed. */ 505258945Sroberto while (isspace ((unsigned char)*pz)) 506258945Sroberto pz++; 507258945Sroberto 508258945Sroberto switch (*pz) 509258945Sroberto { 510258945Sroberto default: goto bad_time; 511258945Sroberto case NUL: 512258945Sroberto return scale_n_add (res, val, 1); 513258945Sroberto 514258945Sroberto case 'y': case 'Y': 515258945Sroberto if (whatd_we_do >= YEAR_IS_DONE) 516258945Sroberto goto bad_time; 517258945Sroberto mult = SEC_PER_YEAR; 518258945Sroberto whatd_we_do = YEAR_IS_DONE; 519258945Sroberto break; 520258945Sroberto 521258945Sroberto case 'M': 522258945Sroberto if (whatd_we_do >= MONTH_IS_DONE) 523258945Sroberto goto bad_time; 524258945Sroberto mult = SEC_PER_MONTH; 525258945Sroberto whatd_we_do = MONTH_IS_DONE; 526258945Sroberto break; 527258945Sroberto 528258945Sroberto case 'W': 529258945Sroberto if (whatd_we_do >= WEEK_IS_DONE) 530258945Sroberto goto bad_time; 531258945Sroberto mult = SEC_PER_WEEK; 532258945Sroberto whatd_we_do = WEEK_IS_DONE; 533258945Sroberto break; 534258945Sroberto 535258945Sroberto case 'd': case 'D': 536258945Sroberto if (whatd_we_do >= DAY_IS_DONE) 537258945Sroberto goto bad_time; 538258945Sroberto mult = SEC_PER_DAY; 539258945Sroberto whatd_we_do = DAY_IS_DONE; 540258945Sroberto break; 541258945Sroberto 542258945Sroberto case 'h': 543258945Sroberto if (whatd_we_do >= HOUR_IS_DONE) 544258945Sroberto goto bad_time; 545258945Sroberto mult = SEC_PER_HR; 546258945Sroberto whatd_we_do = HOUR_IS_DONE; 547258945Sroberto break; 548258945Sroberto 549258945Sroberto case 'm': 550258945Sroberto if (whatd_we_do >= MINUTE_IS_DONE) 551258945Sroberto goto bad_time; 552258945Sroberto mult = SEC_PER_MIN; 553258945Sroberto whatd_we_do = MINUTE_IS_DONE; 554258945Sroberto break; 555258945Sroberto 556258945Sroberto case 's': 557258945Sroberto mult = 1; 558258945Sroberto whatd_we_do = SECOND_IS_DONE; 559258945Sroberto break; 560258945Sroberto } 561258945Sroberto 562258945Sroberto res = scale_n_add (res, val, mult); 563258945Sroberto 564258945Sroberto pz++; 565258945Sroberto while (isspace ((unsigned char)*pz)) 566258945Sroberto pz++; 567258945Sroberto if (*pz == NUL) 568258945Sroberto return res; 569258945Sroberto 570258945Sroberto if (! isdigit ((unsigned char)*pz)) 571258945Sroberto break; 572258945Sroberto } 573258945Sroberto 574258945Sroberto } while (whatd_we_do < SECOND_IS_DONE); 575258945Sroberto 576258945Sroberto bad_time: 577258945Sroberto errno = EINVAL; 578258945Sroberto return BAD_TIME; 579258945Sroberto} 580258945Sroberto 581258945Srobertotime_t 582258945Srobertoparse_duration (char const * pz) 583258945Sroberto{ 584258945Sroberto while (isspace ((unsigned char)*pz)) 585258945Sroberto pz++; 586258945Sroberto 587258945Sroberto switch (*pz) 588258945Sroberto { 589258945Sroberto case 'P': 590258945Sroberto return parse_period (pz + 1); 591258945Sroberto 592258945Sroberto case 'T': 593258945Sroberto return parse_time (pz + 1); 594258945Sroberto 595258945Sroberto default: 596258945Sroberto if (isdigit ((unsigned char)*pz)) 597258945Sroberto return parse_non_iso8601 (pz); 598258945Sroberto 599258945Sroberto errno = EINVAL; 600258945Sroberto return BAD_TIME; 601258945Sroberto } 602258945Sroberto} 603258945Sroberto 604258945Sroberto/* 605258945Sroberto * Local Variables: 606258945Sroberto * mode: C 607258945Sroberto * c-file-style: "gnu" 608258945Sroberto * indent-tabs-mode: nil 609258945Sroberto * End: 610258945Sroberto * end of parse-duration.c */ 611