]>
git.saurik.com Git - apple/libc.git/blob - stdtime/strptime-fbsd.c
   2  * Powerdog Industries kindly requests feedback from anyone modifying 
   5  * Date: Thu, 05 Jun 1997 23:17:17 -0400   
   6  * From: Kevin Ruddy <kevin.ruddy@powerdog.com> 
   7  * To: James FitzGibbon <james@nexis.net> 
   8  * Subject: Re: Use of your strptime(3) code (fwd) 
  10  * The reason for the "no mod" clause was so that modifications would 
  11  * come back and we could integrate them and reissue so that a wider  
  12  * audience could use it (thereby spreading the wealth).  This has    
  13  * made it possible to get strptime to work on many operating systems. 
  14  * I'm not sure why that's "plain unacceptable" to the FreeBSD team. 
  16  * Anyway, you can change it to "with or without modification" as 
  20  * Powerdog Industries, Inc. 
  23  * Copyright (c) 1994 Powerdog Industries.  All rights reserved. 
  25  * Redistribution and use in source and binary forms, with or without 
  26  * modification, are permitted provided that the following conditions 
  28  * 1. Redistributions of source code must retain the above copyright 
  29  *    notice, this list of conditions and the following disclaimer. 
  30  * 2. Redistributions in binary form must reproduce the above copyright 
  31  *    notice, this list of conditions and the following disclaimer 
  32  *    in the documentation and/or other materials provided with the 
  34  * 3. All advertising materials mentioning features or use of this 
  35  *    software must display the following acknowledgement: 
  36  *      This product includes software developed by Powerdog Industries. 
  37  * 4. The name of Powerdog Industries may not be used to endorse or 
  38  *    promote products derived from this software without specific prior 
  41  * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY 
  42  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  44  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE 
  45  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  46  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  47  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
  48  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
  49  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
  50  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
  51  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  54 #include <sys/cdefs.h> 
  57 static char copyright
[] __unused 
= 
  58 "@(#) Copyright (c) 1994 Powerdog Industries.  All rights reserved."; 
  59 static char sccsid
[] __unused 
= "@(#)strptime.c 0.1 (Powerdog) 94/03/27"; 
  60 #endif /* !defined NOID */ 
  62 __FBSDID("$FreeBSD: src/lib/libc/stdtime/strptime.c,v 1.35 2003/11/17 04:19:15 nectar Exp $"); 
  64 #include "xlocale_private.h" 
  66 #include "namespace.h" 
  74 #include "un-namespace.h" 
  75 #include "libc_private.h" 
  76 #include "timelocal.h" 
  78 static char * _strptime(const char *, const char *, struct tm 
*, int *, locale_t
) __DARWIN_ALIAS(_strptime
); 
  79 time_t _mktime(struct tm 
*, const char *); 
  81 #define asizeof(a)      (sizeof (a) / sizeof ((a)[0])) 
  83 enum {CONVERT_NONE
, CONVERT_GMT
, CONVERT_ZONE
}; 
  86 _strptime(const char *buf
, const char *fmt
, struct tm 
*tm
, int *convp
, locale_t loc
) 
  95         int Ealternative
, Oalternative
; 
  96         struct lc_time_T 
*tptr 
= __get_current_time_locale(loc
); 
 102                         while (isspace_l((unsigned char)*ptr
, loc
)) { 
 105                         return ((*ptr
)==0) ? fmt 
: 0; /* trailing whitespace is ok */ 
 111                         if (isspace_l((unsigned char)c
, loc
)) 
 112                                 while (*buf 
!= 0 && isspace_l((unsigned char)*buf
, loc
)) 
 114                         else if (c 
!= *buf
++) 
 131                         buf 
= _strptime(buf
, tptr
->date_fmt
, tm
, convp
, loc
); 
 137                         if (!isdigit_l((unsigned char)*buf
, loc
)) 
 140                         /* XXX This will break for 3-digit centuries. */ 
 142                         for (i 
= 0; len 
&& *buf 
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) { 
 151                                 tm
->tm_year 
= (year 
% 100) + i 
* 100 - 1900; 
 153                         tm
->tm_year 
= i 
* 100 - 1900; 
 158                         buf 
= _strptime(buf
, tptr
->c_fmt
, tm
, convp
, loc
); 
 164                         buf 
= _strptime(buf
, "%m/%d/%y", tm
, convp
, loc
); 
 170                         if (Ealternative 
|| Oalternative
) 
 176                         if (Ealternative 
|| Oalternative
) 
 182                         buf 
= _strptime(buf
, "%Y-%m-%d", tm
, convp
, loc
); 
 188                         buf 
= _strptime(buf
, "%H:%M", tm
, convp
, loc
); 
 194                         buf 
= _strptime(buf
, tptr
->ampm_fmt
, tm
, convp
, loc
); 
 201                         if (!isspace((unsigned char)*buf
)) 
 203                         while (isspace((unsigned char)*buf
)) 
 208                         buf 
= _strptime(buf
, "%H:%M:%S", tm
, convp
, loc
); 
 214                         buf 
= _strptime(buf
, tptr
->X_fmt
, tm
, convp
, loc
); 
 220                         buf 
= _strptime(buf
, tptr
->x_fmt
, tm
, convp
, loc
); 
 226                         if (!isdigit_l((unsigned char)*buf
, loc
)) 
 230                         for (i 
= 0; len 
&& *buf 
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) { 
 235                         if (i 
< 1 || i 
> 366) 
 238                         tm
->tm_yday 
= yday 
= i 
- 1; 
 243                         if (*buf 
== 0 || isspace_l((unsigned char)*buf
, loc
)) 
 246                         if (!isdigit_l((unsigned char)*buf
, loc
)) 
 250                         for (i 
= 0; len 
&& *buf 
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) { 
 266                         if (*buf 
!= 0 && isspace_l((unsigned char)*buf
, loc
)) 
 267                                 while (*ptr 
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr 
!= '%') 
 276                          * Of these, %l is the only specifier explicitly 
 277                          * documented as not being zero-padded.  However, 
 278                          * there is no harm in allowing zero-padding. 
 280                          * XXX The %l specifier may gobble one too many 
 281                          * digits if used incorrectly. 
 283                         if (!isdigit_l((unsigned char)*buf
, loc
)) 
 287                         for (i 
= 0; len 
&& *buf 
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) { 
 292                         if (c 
== 'H' || c 
== 'k') { 
 300                         if (*buf 
!= 0 && isspace_l((unsigned char)*buf
, loc
)) 
 301                                 while (*ptr 
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr 
!= '%') 
 307                          * XXX This is bogus if parsed before hour-related 
 310                         len 
= strlen(tptr
->am
); 
 311                         if (strncasecmp_l(buf
, tptr
->am
, len
, loc
) == 0) { 
 312                                 if (tm
->tm_hour 
> 12) 
 314                                 if (tm
->tm_hour 
== 12) 
 320                         len 
= strlen(tptr
->pm
); 
 321                         if (strncasecmp_l(buf
, tptr
->pm
, len
, loc
) == 0) { 
 322                                 if (tm
->tm_hour 
> 12) 
 324                                 if (tm
->tm_hour 
!= 12) 
 334                         for (i 
= 0; i 
< asizeof(tptr
->weekday
); i
++) { 
 335                                 len 
= strlen(tptr
->weekday
[i
]); 
 336                                 if (strncasecmp_l(buf
, tptr
->weekday
[i
], 
 339                                 len 
= strlen(tptr
->wday
[i
]); 
 340                                 if (strncasecmp_l(buf
, tptr
->wday
[i
], 
 344                         if (i 
== asizeof(tptr
->weekday
)) 
 347                         tm
->tm_wday 
= wday 
= i
; 
 351                 case 'U':       /* Sunday week */ 
 352                 case 'W':       /* Monday week */ 
 353                         if (!isdigit_l((unsigned char)*buf
, loc
)) 
 357                         for (i 
= 0; len 
&& *buf 
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) { 
 365                         /* Calculate yday if we have enough data */ 
 366                         if ((year 
!= -1) && (wday 
!= -1)) { 
 372                                 mktm
.tm_min 
= mktm
.tm_hour 
= 0; 
 375                                 if (mktime(&mktm
) != -1) { 
 376                                         /* yday0 == Jan 1 == mktm.tm_wday */ 
 377                                         int delta 
= wday 
- mktm
.tm_wday
; 
 378                                         if (!wday 
&& c 
=='W') 
 379                                                 i
++; /* Sunday is part of the following week */ 
 380                                         yday 
= 7 * i 
+ delta
; 
 386                         if (*buf 
!= 0 && isspace_l((unsigned char)*buf
, loc
)) 
 387                                 while (*ptr 
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr 
!= '%') 
 391                 case 'u':       /* [1,7] */ 
 392                 case 'w':       /* [0,6] */ 
 393                         if (!isdigit_l((unsigned char)*buf
, loc
)) 
 397                         if (i 
> 6 + (c 
== 'u')) 
 401                         tm
->tm_wday 
= wday 
= i
; 
 403                         if (*buf 
!= 0 && isspace_l((unsigned char)*buf
, loc
)) 
 404                                 while (*ptr 
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr 
!= '%') 
 411                          * The %e specifier is explicitly documented as not 
 412                          * being zero-padded but there is no harm in allowing 
 415                          * XXX The %e specifier may gobble one too many 
 416                          * digits if used incorrectly. 
 418                         /* Leading space is ok if date is single digit */ 
 420                         if (isspace_l((unsigned char)buf
[0], loc
) && 
 421                             isdigit_l((unsigned char)buf
[1], loc
) && 
 422                             !isdigit_l((unsigned char)buf
[2], loc
)) { 
 426                         if (!isdigit_l((unsigned char)*buf
, loc
)) 
 429                         for (i 
= 0; len 
&& *buf 
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) { 
 439                         if (*buf 
!= 0 && isspace_l((unsigned char)*buf
, loc
)) 
 440                                 while (*ptr 
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr 
!= '%') 
 447                         for (i 
= 0; i 
< asizeof(tptr
->month
); i
++) { 
 450                                                 len 
= strlen(tptr
->alt_month
[i
]); 
 451                                                 if (strncasecmp_l(buf
, 
 457                                         len 
= strlen(tptr
->month
[i
]); 
 458                                         if (strncasecmp_l(buf
, tptr
->month
[i
], 
 461                                         len 
= strlen(tptr
->mon
[i
]); 
 462                                         if (strncasecmp_l(buf
, tptr
->mon
[i
], 
 467                         if (i 
== asizeof(tptr
->month
)) 
 475                         if (!isdigit_l((unsigned char)*buf
, loc
)) 
 479                         for (i 
= 0; len 
&& *buf 
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) { 
 489                         if (*buf 
!= 0 && isspace_l((unsigned char)*buf
, loc
)) 
 490                                 while (*ptr 
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr 
!= '%') 
 503                         n 
= strtol_l(buf
, &cp
, 10, loc
); 
 504                         if (errno 
== ERANGE 
|| (long)(t 
= n
) != n
) { 
 511                         *convp 
= CONVERT_GMT
; 
 517                         if (*buf 
== 0 || isspace_l((unsigned char)*buf
, loc
)) 
 520                         if (!isdigit_l((unsigned char)*buf
, loc
)) 
 525                                 for (i 
= 0; *buf 
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) { 
 531 #else /* !__DARWIN_UNIX03 */ 
 532                         len 
= (c 
== 'Y') ? 4 : 2; 
 533 #endif /* __DARWIN_UNIX03 */ 
 534                         for (i 
= 0; len 
&& *buf 
!= 0 && isdigit_l((unsigned char)*buf
, loc
); buf
++) { 
 541 #endif /* __DARWIN_UNIX03 */ 
 544                         if (c 
== 'y' && i 
< 69) 
 549                         tm
->tm_year 
= year 
= i
; 
 551                         if (*buf 
!= 0 && isspace_l((unsigned char)*buf
, loc
)) 
 552                                 while (*ptr 
!= 0 && !isspace_l((unsigned char)*ptr
, loc
) && *ptr 
!= '%') 
 561                         for (cp 
= buf
; *cp 
&& isupper((unsigned char)*cp
); ++cp
) {/*empty*/} 
 563                         if (len 
== 3 && strncmp(buf
, "GMT", 3) == 0) { 
 564                                 *convp 
= CONVERT_GMT
; 
 569                         tzlen 
= strlen(tzname
[0]); 
 570                         if (len 
== tzlen 
&& strncmp(buf
, tzname
[0], tzlen
) == 0) { 
 575                         tzlen 
= strlen(tzname
[1]); 
 576                         if (len 
== tzlen 
&& strncmp(buf
, tzname
[1], tzlen
) == 0) { 
 589                         if ((buf
[0] != '+' && buf
[0] != '-') 
 590                          || !isdigit_l((unsigned char)buf
[1], loc
) 
 591                          || !isdigit_l((unsigned char)buf
[2], loc
) 
 592                          || !isdigit_l((unsigned char)buf
[3], loc
) 
 593                          || !isdigit_l((unsigned char)buf
[4], loc
)) 
 595                         sscanf(buf
, "%c%2d%2d", &sign
, &hr
, &min
); 
 596                         *convp 
= CONVERT_ZONE
; 
 597                         tm
->tm_gmtoff 
= 60 * (60 * hr 
+ min
); 
 599                             tm
->tm_gmtoff 
= -tm
->tm_gmtoff
; 
 610 strptime(const char * __restrict buf
, const char * __restrict fmt
, 
 611     struct tm 
* __restrict tm
) 
 613         return strptime_l(buf
, fmt
, tm
, __current_locale()); 
 616 extern time_t timeoff(struct tm 
*, long); 
 619 strptime_l(const char * __restrict buf
, const char * __restrict fmt
, 
 620     struct tm 
* __restrict tm
, locale_t loc
) 
 625         NORMALIZE_LOCALE(loc
); 
 628         ret 
= _strptime(buf
, fmt
, tm
, &conv
, loc
); 
 639                         long offset 
= tm
->tm_gmtoff
; 
 641                         t 
= timeoff(tm
, offset
);