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