1290001Sglebius/* Parse a time duration and return a seconds count 2290001Sglebius Copyright (C) 2008-2015 Free Software Foundation, Inc. 3290001Sglebius Written by Bruce Korb <bkorb@gnu.org>, 2008. 4290001Sglebius 5290001Sglebius This program is free software: you can redistribute it and/or modify 6290001Sglebius it under the terms of the GNU Lesser General Public License as published by 7290001Sglebius the Free Software Foundation; either version 2.1 of the License, or 8290001Sglebius (at your option) any later version. 9290001Sglebius 10290001Sglebius This program is distributed in the hope that it will be useful, 11290001Sglebius but WITHOUT ANY WARRANTY; without even the implied warranty of 12290001Sglebius MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13290001Sglebius GNU Lesser General Public License for more details. 14290001Sglebius 15290001Sglebius You should have received a copy of the GNU Lesser General Public License 16290001Sglebius along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17290001Sglebius 18290001Sglebius#include <config.h> 19290001Sglebius 20290001Sglebius/* Specification. */ 21290001Sglebius#include "parse-duration.h" 22290001Sglebius 23290001Sglebius#include <ctype.h> 24290001Sglebius#include <errno.h> 25290001Sglebius#include <limits.h> 26290001Sglebius#include <stdio.h> 27290001Sglebius#include <stdlib.h> 28290001Sglebius#include <string.h> 29290001Sglebius 30290001Sglebius#include "intprops.h" 31290001Sglebius 32290001Sglebius#ifndef NUL 33290001Sglebius#define NUL '\0' 34290001Sglebius#endif 35290001Sglebius 36290001Sglebius#define cch_t char const 37290001Sglebius 38290001Sglebiustypedef enum { 39290001Sglebius NOTHING_IS_DONE, 40290001Sglebius YEAR_IS_DONE, 41290001Sglebius MONTH_IS_DONE, 42290001Sglebius WEEK_IS_DONE, 43290001Sglebius DAY_IS_DONE, 44290001Sglebius HOUR_IS_DONE, 45290001Sglebius MINUTE_IS_DONE, 46290001Sglebius SECOND_IS_DONE 47290001Sglebius} whats_done_t; 48290001Sglebius 49290001Sglebius#define SEC_PER_MIN 60 50290001Sglebius#define SEC_PER_HR (SEC_PER_MIN * 60) 51290001Sglebius#define SEC_PER_DAY (SEC_PER_HR * 24) 52290001Sglebius#define SEC_PER_WEEK (SEC_PER_DAY * 7) 53290001Sglebius#define SEC_PER_MONTH (SEC_PER_DAY * 30) 54290001Sglebius#define SEC_PER_YEAR (SEC_PER_DAY * 365) 55290001Sglebius 56290001Sglebius#undef MAX_DURATION 57290001Sglebius#define MAX_DURATION TYPE_MAXIMUM(time_t) 58290001Sglebius 59290001Sglebius/* Wrapper around strtoul that does not require a cast. */ 60290001Sglebiusstatic unsigned long 61290001Sglebiusstr_const_to_ul (cch_t * str, cch_t ** ppz, int base) 62290001Sglebius{ 63294905Sdelphij char * pz; 64294905Sdelphij int rv = strtoul (str, &pz, base); 65294905Sdelphij *ppz = pz; 66294905Sdelphij return rv; 67290001Sglebius} 68290001Sglebius 69290001Sglebius/* Wrapper around strtol that does not require a cast. */ 70290001Sglebiusstatic long 71290001Sglebiusstr_const_to_l (cch_t * str, cch_t ** ppz, int base) 72290001Sglebius{ 73294905Sdelphij char * pz; 74294905Sdelphij int rv = strtol (str, &pz, base); 75294905Sdelphij *ppz = pz; 76294905Sdelphij return rv; 77290001Sglebius} 78290001Sglebius 79290001Sglebius/* Returns BASE + VAL * SCALE, interpreting BASE = BAD_TIME 80290001Sglebius with errno set as an error situation, and returning BAD_TIME 81290001Sglebius with errno set in an error situation. */ 82290001Sglebiusstatic time_t 83290001Sglebiusscale_n_add (time_t base, time_t val, int scale) 84290001Sglebius{ 85290001Sglebius if (base == BAD_TIME) 86290001Sglebius { 87290001Sglebius if (errno == 0) 88290001Sglebius errno = EINVAL; 89290001Sglebius return BAD_TIME; 90290001Sglebius } 91290001Sglebius 92290001Sglebius if (val > MAX_DURATION / scale) 93290001Sglebius { 94290001Sglebius errno = ERANGE; 95290001Sglebius return BAD_TIME; 96290001Sglebius } 97290001Sglebius 98290001Sglebius val *= scale; 99290001Sglebius if (base > MAX_DURATION - val) 100290001Sglebius { 101290001Sglebius errno = ERANGE; 102290001Sglebius return BAD_TIME; 103290001Sglebius } 104290001Sglebius 105290001Sglebius return base + val; 106290001Sglebius} 107290001Sglebius 108290001Sglebius/* After a number HH has been parsed, parse subsequent :MM or :MM:SS. */ 109290001Sglebiusstatic time_t 110290001Sglebiusparse_hr_min_sec (time_t start, cch_t * pz) 111290001Sglebius{ 112290001Sglebius int lpct = 0; 113290001Sglebius 114290001Sglebius errno = 0; 115290001Sglebius 116290001Sglebius /* For as long as our scanner pointer points to a colon *AND* 117290001Sglebius we've not looped before, then keep looping. (two iterations max) */ 118290001Sglebius while ((*pz == ':') && (lpct++ <= 1)) 119290001Sglebius { 120290001Sglebius unsigned long v = str_const_to_ul (pz+1, &pz, 10); 121290001Sglebius 122290001Sglebius if (errno != 0) 123290001Sglebius return BAD_TIME; 124290001Sglebius 125290001Sglebius start = scale_n_add (v, start, 60); 126290001Sglebius 127290001Sglebius if (errno != 0) 128290001Sglebius return BAD_TIME; 129290001Sglebius } 130290001Sglebius 131290001Sglebius /* allow for trailing spaces */ 132290001Sglebius while (isspace ((unsigned char)*pz)) 133290001Sglebius pz++; 134290001Sglebius if (*pz != NUL) 135290001Sglebius { 136290001Sglebius errno = EINVAL; 137290001Sglebius return BAD_TIME; 138290001Sglebius } 139290001Sglebius 140290001Sglebius return start; 141290001Sglebius} 142290001Sglebius 143290001Sglebius/* Parses a value and returns BASE + value * SCALE, interpreting 144290001Sglebius BASE = BAD_TIME with errno set as an error situation, and returning 145290001Sglebius BAD_TIME with errno set in an error situation. */ 146290001Sglebiusstatic time_t 147290001Sglebiusparse_scaled_value (time_t base, cch_t ** ppz, cch_t * endp, int scale) 148290001Sglebius{ 149290001Sglebius cch_t * pz = *ppz; 150290001Sglebius time_t val; 151290001Sglebius 152290001Sglebius if (base == BAD_TIME) 153290001Sglebius return base; 154290001Sglebius 155290001Sglebius errno = 0; 156290001Sglebius val = str_const_to_ul (pz, &pz, 10); 157290001Sglebius if (errno != 0) 158290001Sglebius return BAD_TIME; 159290001Sglebius while (isspace ((unsigned char)*pz)) 160290001Sglebius pz++; 161290001Sglebius if (pz != endp) 162290001Sglebius { 163290001Sglebius errno = EINVAL; 164290001Sglebius return BAD_TIME; 165290001Sglebius } 166290001Sglebius 167290001Sglebius *ppz = pz; 168290001Sglebius return scale_n_add (base, val, scale); 169290001Sglebius} 170290001Sglebius 171290001Sglebius/* Parses the syntax YEAR-MONTH-DAY. 172290001Sglebius PS points into the string, after "YEAR", before "-MONTH-DAY". */ 173290001Sglebiusstatic time_t 174290001Sglebiusparse_year_month_day (cch_t * pz, cch_t * ps) 175290001Sglebius{ 176290001Sglebius time_t res = 0; 177290001Sglebius 178290001Sglebius res = parse_scaled_value (0, &pz, ps, SEC_PER_YEAR); 179290001Sglebius 180290001Sglebius pz++; /* over the first '-' */ 181290001Sglebius ps = strchr (pz, '-'); 182290001Sglebius if (ps == NULL) 183290001Sglebius { 184290001Sglebius errno = EINVAL; 185290001Sglebius return BAD_TIME; 186290001Sglebius } 187290001Sglebius res = parse_scaled_value (res, &pz, ps, SEC_PER_MONTH); 188290001Sglebius 189290001Sglebius pz++; /* over the second '-' */ 190290001Sglebius ps = pz + strlen (pz); 191290001Sglebius return parse_scaled_value (res, &pz, ps, SEC_PER_DAY); 192290001Sglebius} 193290001Sglebius 194290001Sglebius/* Parses the syntax YYYYMMDD. */ 195290001Sglebiusstatic time_t 196290001Sglebiusparse_yearmonthday (cch_t * in_pz) 197290001Sglebius{ 198290001Sglebius time_t res = 0; 199290001Sglebius char buf[8]; 200290001Sglebius cch_t * pz; 201290001Sglebius 202290001Sglebius if (strlen (in_pz) != 8) 203290001Sglebius { 204290001Sglebius errno = EINVAL; 205290001Sglebius return BAD_TIME; 206290001Sglebius } 207290001Sglebius 208290001Sglebius memcpy (buf, in_pz, 4); 209290001Sglebius buf[4] = NUL; 210290001Sglebius pz = buf; 211290001Sglebius res = parse_scaled_value (0, &pz, buf + 4, SEC_PER_YEAR); 212290001Sglebius 213290001Sglebius memcpy (buf, in_pz + 4, 2); 214290001Sglebius buf[2] = NUL; 215290001Sglebius pz = buf; 216290001Sglebius res = parse_scaled_value (res, &pz, buf + 2, SEC_PER_MONTH); 217290001Sglebius 218290001Sglebius memcpy (buf, in_pz + 6, 2); 219290001Sglebius buf[2] = NUL; 220290001Sglebius pz = buf; 221290001Sglebius return parse_scaled_value (res, &pz, buf + 2, SEC_PER_DAY); 222290001Sglebius} 223290001Sglebius 224290001Sglebius/* Parses the syntax yy Y mm M ww W dd D. */ 225290001Sglebiusstatic time_t 226290001Sglebiusparse_YMWD (cch_t * pz) 227290001Sglebius{ 228290001Sglebius time_t res = 0; 229290001Sglebius cch_t * ps = strchr (pz, 'Y'); 230290001Sglebius if (ps != NULL) 231290001Sglebius { 232290001Sglebius res = parse_scaled_value (0, &pz, ps, SEC_PER_YEAR); 233290001Sglebius pz++; 234290001Sglebius } 235290001Sglebius 236290001Sglebius ps = strchr (pz, 'M'); 237290001Sglebius if (ps != NULL) 238290001Sglebius { 239290001Sglebius res = parse_scaled_value (res, &pz, ps, SEC_PER_MONTH); 240290001Sglebius pz++; 241290001Sglebius } 242290001Sglebius 243290001Sglebius ps = strchr (pz, 'W'); 244290001Sglebius if (ps != NULL) 245290001Sglebius { 246290001Sglebius res = parse_scaled_value (res, &pz, ps, SEC_PER_WEEK); 247290001Sglebius pz++; 248290001Sglebius } 249290001Sglebius 250290001Sglebius ps = strchr (pz, 'D'); 251290001Sglebius if (ps != NULL) 252290001Sglebius { 253290001Sglebius res = parse_scaled_value (res, &pz, ps, SEC_PER_DAY); 254290001Sglebius pz++; 255290001Sglebius } 256290001Sglebius 257290001Sglebius while (isspace ((unsigned char)*pz)) 258290001Sglebius pz++; 259290001Sglebius if (*pz != NUL) 260290001Sglebius { 261290001Sglebius errno = EINVAL; 262290001Sglebius return BAD_TIME; 263290001Sglebius } 264290001Sglebius 265290001Sglebius return res; 266290001Sglebius} 267290001Sglebius 268290001Sglebius/* Parses the syntax HH:MM:SS. 269290001Sglebius PS points into the string, after "HH", before ":MM:SS". */ 270290001Sglebiusstatic time_t 271290001Sglebiusparse_hour_minute_second (cch_t * pz, cch_t * ps) 272290001Sglebius{ 273290001Sglebius time_t res = 0; 274290001Sglebius 275290001Sglebius res = parse_scaled_value (0, &pz, ps, SEC_PER_HR); 276290001Sglebius 277290001Sglebius pz++; 278290001Sglebius ps = strchr (pz, ':'); 279290001Sglebius if (ps == NULL) 280290001Sglebius { 281290001Sglebius errno = EINVAL; 282290001Sglebius return BAD_TIME; 283290001Sglebius } 284290001Sglebius 285290001Sglebius res = parse_scaled_value (res, &pz, ps, SEC_PER_MIN); 286290001Sglebius 287290001Sglebius pz++; 288290001Sglebius ps = pz + strlen (pz); 289290001Sglebius return parse_scaled_value (res, &pz, ps, 1); 290290001Sglebius} 291290001Sglebius 292290001Sglebius/* Parses the syntax HHMMSS. */ 293290001Sglebiusstatic time_t 294290001Sglebiusparse_hourminutesecond (cch_t * in_pz) 295290001Sglebius{ 296290001Sglebius time_t res = 0; 297290001Sglebius char buf[4]; 298290001Sglebius cch_t * pz; 299290001Sglebius 300290001Sglebius if (strlen (in_pz) != 6) 301290001Sglebius { 302290001Sglebius errno = EINVAL; 303290001Sglebius return BAD_TIME; 304290001Sglebius } 305290001Sglebius 306290001Sglebius memcpy (buf, in_pz, 2); 307290001Sglebius buf[2] = NUL; 308290001Sglebius pz = buf; 309290001Sglebius res = parse_scaled_value (0, &pz, buf + 2, SEC_PER_HR); 310290001Sglebius 311290001Sglebius memcpy (buf, in_pz + 2, 2); 312290001Sglebius buf[2] = NUL; 313290001Sglebius pz = buf; 314290001Sglebius res = parse_scaled_value (res, &pz, buf + 2, SEC_PER_MIN); 315290001Sglebius 316290001Sglebius memcpy (buf, in_pz + 4, 2); 317290001Sglebius buf[2] = NUL; 318290001Sglebius pz = buf; 319290001Sglebius return parse_scaled_value (res, &pz, buf + 2, 1); 320290001Sglebius} 321290001Sglebius 322290001Sglebius/* Parses the syntax hh H mm M ss S. */ 323290001Sglebiusstatic time_t 324290001Sglebiusparse_HMS (cch_t * pz) 325290001Sglebius{ 326290001Sglebius time_t res = 0; 327290001Sglebius cch_t * ps = strchr (pz, 'H'); 328290001Sglebius if (ps != NULL) 329290001Sglebius { 330290001Sglebius res = parse_scaled_value (0, &pz, ps, SEC_PER_HR); 331290001Sglebius pz++; 332290001Sglebius } 333290001Sglebius 334290001Sglebius ps = strchr (pz, 'M'); 335290001Sglebius if (ps != NULL) 336290001Sglebius { 337290001Sglebius res = parse_scaled_value (res, &pz, ps, SEC_PER_MIN); 338290001Sglebius pz++; 339290001Sglebius } 340290001Sglebius 341290001Sglebius ps = strchr (pz, 'S'); 342290001Sglebius if (ps != NULL) 343290001Sglebius { 344290001Sglebius res = parse_scaled_value (res, &pz, ps, 1); 345290001Sglebius pz++; 346290001Sglebius } 347290001Sglebius 348290001Sglebius while (isspace ((unsigned char)*pz)) 349290001Sglebius pz++; 350290001Sglebius if (*pz != NUL) 351290001Sglebius { 352290001Sglebius errno = EINVAL; 353290001Sglebius return BAD_TIME; 354290001Sglebius } 355290001Sglebius 356290001Sglebius return res; 357290001Sglebius} 358290001Sglebius 359290001Sglebius/* Parses a time (hours, minutes, seconds) specification in either syntax. */ 360290001Sglebiusstatic time_t 361290001Sglebiusparse_time (cch_t * pz) 362290001Sglebius{ 363290001Sglebius cch_t * ps; 364290001Sglebius time_t res = 0; 365290001Sglebius 366290001Sglebius /* 367290001Sglebius * Scan for a hyphen 368290001Sglebius */ 369290001Sglebius ps = strchr (pz, ':'); 370290001Sglebius if (ps != NULL) 371290001Sglebius { 372290001Sglebius res = parse_hour_minute_second (pz, ps); 373290001Sglebius } 374290001Sglebius 375290001Sglebius /* 376290001Sglebius * Try for a 'H', 'M' or 'S' suffix 377290001Sglebius */ 378290001Sglebius else if (ps = strpbrk (pz, "HMS"), 379290001Sglebius ps == NULL) 380290001Sglebius { 381290001Sglebius /* Its a YYYYMMDD format: */ 382290001Sglebius res = parse_hourminutesecond (pz); 383290001Sglebius } 384290001Sglebius 385290001Sglebius else 386290001Sglebius res = parse_HMS (pz); 387290001Sglebius 388290001Sglebius return res; 389290001Sglebius} 390290001Sglebius 391290001Sglebius/* Returns a substring of the given string, with spaces at the beginning and at 392290001Sglebius the end destructively removed, per SNOBOL. */ 393290001Sglebiusstatic char * 394290001Sglebiustrim (char * pz) 395290001Sglebius{ 396290001Sglebius /* trim leading white space */ 397290001Sglebius while (isspace ((unsigned char)*pz)) 398290001Sglebius pz++; 399290001Sglebius 400290001Sglebius /* trim trailing white space */ 401290001Sglebius { 402290001Sglebius char * pe = pz + strlen (pz); 403290001Sglebius while ((pe > pz) && isspace ((unsigned char)pe[-1])) 404290001Sglebius pe--; 405290001Sglebius *pe = NUL; 406290001Sglebius } 407290001Sglebius 408290001Sglebius return pz; 409290001Sglebius} 410290001Sglebius 411290001Sglebius/* 412290001Sglebius * Parse the year/months/days of a time period 413290001Sglebius */ 414290001Sglebiusstatic time_t 415290001Sglebiusparse_period (cch_t * in_pz) 416290001Sglebius{ 417290001Sglebius char * pT; 418290001Sglebius char * ps; 419290001Sglebius char * pz = strdup (in_pz); 420290001Sglebius void * fptr = pz; 421290001Sglebius time_t res = 0; 422290001Sglebius 423290001Sglebius if (pz == NULL) 424290001Sglebius { 425290001Sglebius errno = ENOMEM; 426290001Sglebius return BAD_TIME; 427290001Sglebius } 428290001Sglebius 429290001Sglebius pT = strchr (pz, 'T'); 430290001Sglebius if (pT != NULL) 431290001Sglebius { 432290001Sglebius *(pT++) = NUL; 433290001Sglebius pz = trim (pz); 434290001Sglebius pT = trim (pT); 435290001Sglebius } 436290001Sglebius 437290001Sglebius /* 438290001Sglebius * Scan for a hyphen 439290001Sglebius */ 440290001Sglebius ps = strchr (pz, '-'); 441290001Sglebius if (ps != NULL) 442290001Sglebius { 443290001Sglebius res = parse_year_month_day (pz, ps); 444290001Sglebius } 445290001Sglebius 446290001Sglebius /* 447290001Sglebius * Try for a 'Y', 'M' or 'D' suffix 448290001Sglebius */ 449290001Sglebius else if (ps = strpbrk (pz, "YMWD"), 450290001Sglebius ps == NULL) 451290001Sglebius { 452290001Sglebius /* Its a YYYYMMDD format: */ 453290001Sglebius res = parse_yearmonthday (pz); 454290001Sglebius } 455290001Sglebius 456290001Sglebius else 457290001Sglebius res = parse_YMWD (pz); 458290001Sglebius 459290001Sglebius if ((errno == 0) && (pT != NULL)) 460290001Sglebius { 461290001Sglebius time_t val = parse_time (pT); 462290001Sglebius res = scale_n_add (res, val, 1); 463290001Sglebius } 464290001Sglebius 465290001Sglebius free (fptr); 466290001Sglebius return res; 467290001Sglebius} 468290001Sglebius 469290001Sglebiusstatic time_t 470290001Sglebiusparse_non_iso8601 (cch_t * pz) 471290001Sglebius{ 472290001Sglebius whats_done_t whatd_we_do = NOTHING_IS_DONE; 473290001Sglebius 474290001Sglebius time_t res = 0; 475290001Sglebius 476290001Sglebius do { 477290001Sglebius time_t val; 478290001Sglebius 479290001Sglebius errno = 0; 480290001Sglebius val = str_const_to_l (pz, &pz, 10); 481290001Sglebius if (errno != 0) 482290001Sglebius goto bad_time; 483290001Sglebius 484290001Sglebius /* IF we find a colon, then we're going to have a seconds value. 485290001Sglebius We will not loop here any more. We cannot already have parsed 486290001Sglebius a minute value and if we've parsed an hour value, then the result 487290001Sglebius value has to be less than an hour. */ 488290001Sglebius if (*pz == ':') 489290001Sglebius { 490290001Sglebius if (whatd_we_do >= MINUTE_IS_DONE) 491290001Sglebius break; 492290001Sglebius 493290001Sglebius val = parse_hr_min_sec (val, pz); 494290001Sglebius 495290001Sglebius if ((whatd_we_do == HOUR_IS_DONE) && (val >= SEC_PER_HR)) 496290001Sglebius break; 497290001Sglebius 498290001Sglebius return scale_n_add (res, val, 1); 499290001Sglebius } 500290001Sglebius 501290001Sglebius { 502290001Sglebius unsigned int mult; 503290001Sglebius 504290001Sglebius /* Skip over white space following the number we just parsed. */ 505290001Sglebius while (isspace ((unsigned char)*pz)) 506290001Sglebius pz++; 507290001Sglebius 508290001Sglebius switch (*pz) 509290001Sglebius { 510290001Sglebius default: goto bad_time; 511290001Sglebius case NUL: 512290001Sglebius return scale_n_add (res, val, 1); 513290001Sglebius 514290001Sglebius case 'y': case 'Y': 515290001Sglebius if (whatd_we_do >= YEAR_IS_DONE) 516290001Sglebius goto bad_time; 517290001Sglebius mult = SEC_PER_YEAR; 518290001Sglebius whatd_we_do = YEAR_IS_DONE; 519290001Sglebius break; 520290001Sglebius 521290001Sglebius case 'M': 522290001Sglebius if (whatd_we_do >= MONTH_IS_DONE) 523290001Sglebius goto bad_time; 524290001Sglebius mult = SEC_PER_MONTH; 525290001Sglebius whatd_we_do = MONTH_IS_DONE; 526290001Sglebius break; 527290001Sglebius 528290001Sglebius case 'W': 529290001Sglebius if (whatd_we_do >= WEEK_IS_DONE) 530290001Sglebius goto bad_time; 531290001Sglebius mult = SEC_PER_WEEK; 532290001Sglebius whatd_we_do = WEEK_IS_DONE; 533290001Sglebius break; 534290001Sglebius 535290001Sglebius case 'd': case 'D': 536290001Sglebius if (whatd_we_do >= DAY_IS_DONE) 537290001Sglebius goto bad_time; 538290001Sglebius mult = SEC_PER_DAY; 539290001Sglebius whatd_we_do = DAY_IS_DONE; 540290001Sglebius break; 541290001Sglebius 542290001Sglebius case 'h': 543290001Sglebius if (whatd_we_do >= HOUR_IS_DONE) 544290001Sglebius goto bad_time; 545290001Sglebius mult = SEC_PER_HR; 546290001Sglebius whatd_we_do = HOUR_IS_DONE; 547290001Sglebius break; 548290001Sglebius 549290001Sglebius case 'm': 550290001Sglebius if (whatd_we_do >= MINUTE_IS_DONE) 551290001Sglebius goto bad_time; 552290001Sglebius mult = SEC_PER_MIN; 553290001Sglebius whatd_we_do = MINUTE_IS_DONE; 554290001Sglebius break; 555290001Sglebius 556290001Sglebius case 's': 557290001Sglebius mult = 1; 558290001Sglebius whatd_we_do = SECOND_IS_DONE; 559290001Sglebius break; 560290001Sglebius } 561290001Sglebius 562290001Sglebius res = scale_n_add (res, val, mult); 563290001Sglebius 564290001Sglebius pz++; 565290001Sglebius while (isspace ((unsigned char)*pz)) 566290001Sglebius pz++; 567290001Sglebius if (*pz == NUL) 568290001Sglebius return res; 569290001Sglebius 570290001Sglebius if (! isdigit ((unsigned char)*pz)) 571290001Sglebius break; 572290001Sglebius } 573290001Sglebius 574290001Sglebius } while (whatd_we_do < SECOND_IS_DONE); 575290001Sglebius 576290001Sglebius bad_time: 577290001Sglebius errno = EINVAL; 578290001Sglebius return BAD_TIME; 579290001Sglebius} 580290001Sglebius 581290001Sglebiustime_t 582290001Sglebiusparse_duration (char const * pz) 583290001Sglebius{ 584290001Sglebius while (isspace ((unsigned char)*pz)) 585290001Sglebius pz++; 586290001Sglebius 587290001Sglebius switch (*pz) 588290001Sglebius { 589290001Sglebius case 'P': 590290001Sglebius return parse_period (pz + 1); 591290001Sglebius 592290001Sglebius case 'T': 593290001Sglebius return parse_time (pz + 1); 594290001Sglebius 595290001Sglebius default: 596290001Sglebius if (isdigit ((unsigned char)*pz)) 597290001Sglebius return parse_non_iso8601 (pz); 598290001Sglebius 599290001Sglebius errno = EINVAL; 600290001Sglebius return BAD_TIME; 601290001Sglebius } 602290001Sglebius} 603290001Sglebius 604290001Sglebius/* 605290001Sglebius * Local Variables: 606290001Sglebius * mode: C 607290001Sglebius * c-file-style: "gnu" 608290001Sglebius * indent-tabs-mode: nil 609290001Sglebius * End: 610290001Sglebius * end of parse-duration.c */ 611