Print this page
2964 need POSIX 2008 locale object support
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Approved by: TBD
   1 /*
   2  * Copyright (c) 2014 Gary Mills

   3  * Copyright 2011, Nexenta Systems, Inc.  All rights reserved.
   4  * Copyright (c) 1994 Powerdog Industries.  All rights reserved.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions
   8  * are met:
   9  *
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  *
  13  * 2. Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer
  15  *    in the documentation and/or other materials provided with the
  16  *    distribution.
  17  *
  18  * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
  19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
  22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  25  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  27  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  28  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29  *
  30  * The views and conclusions contained in the software and documentation
  31  * are those of the authors and should not be interpreted as representing
  32  * official policies, either expressed or implied, of Powerdog Industries.
  33  */
  34 
  35 #include "lint.h"
  36 #include <time.h>
  37 #include <ctype.h>
  38 #include <errno.h>
  39 #include <stdlib.h>
  40 #include <string.h>
  41 #include <pthread.h>
  42 #include <alloca.h>

  43 #include "timelocal.h"

  44 
  45 #define asizeof(a)      (sizeof (a) / sizeof ((a)[0]))
  46 
  47 #define F_GMT           (1 << 0)
  48 #define F_ZERO          (1 << 1)
  49 #define F_RECURSE       (1 << 2)
  50 
  51 static char *
  52 __strptime(const char *buf, const char *fmt, struct tm *tm, int *flagsp)


  53 {
  54         char    c;
  55         const char *ptr;
  56         int     i, len, recurse = 0;
  57         int Ealternative, Oalternative;
  58         struct lc_time_T *tptr = __get_current_time_locale();
  59 
  60         if (*flagsp & F_RECURSE)
  61                 recurse = 1;
  62         *flagsp |= F_RECURSE;
  63 
  64         if (*flagsp & F_ZERO)
  65                 (void) memset(tm, 0, sizeof (*tm));
  66         *flagsp &= ~F_ZERO;
  67 
  68         ptr = fmt;
  69         while (*ptr != 0) {
  70                 if (*buf == 0)
  71                         break;
  72 
  73                 c = *ptr++;
  74 
  75                 if (c != '%') {
  76                         if (isspace(c))
  77                                 while (isspace(*buf))
  78                                         buf++;
  79                         else if (c != *buf++)
  80                                 return (NULL);
  81                         continue;
  82                 }
  83 
  84                 Ealternative = 0;
  85                 Oalternative = 0;
  86 label:
  87                 c = *ptr++;
  88                 switch (c) {
  89                 case 0:
  90                 case '%':
  91                         if (*buf++ != '%')
  92                                 return (NULL);
  93                         break;
  94 
  95                 case '+':
  96                         buf = __strptime(buf, tptr->date_fmt, tm, flagsp);
  97                         if (buf == NULL)
  98                                 return (NULL);
  99                         break;
 100 
 101                 case 'C':
 102                         if (!isdigit(*buf))
 103                                 return (NULL);
 104 
 105                         /* XXX This will break for 3-digit centuries. */
 106                         len = 2;
 107                         for (i = 0; len && isdigit(*buf); buf++) {
 108                                 i *= 10;
 109                                 i += *buf - '0';
 110                                 len--;
 111                         }
 112                         if (i < 19)
 113                                 return (NULL);
 114 
 115                         tm->tm_year = i * 100 - 1900;
 116                         break;
 117 
 118                 case 'c':
 119                         buf = __strptime(buf, tptr->c_fmt, tm, flagsp);
 120                         if (buf == NULL)
 121                                 return (NULL);
 122                         break;
 123 
 124                 case 'D':
 125                         buf = __strptime(buf, "%m/%d/%y", tm, flagsp);
 126                         if (buf == NULL)
 127                                 return (NULL);
 128                         break;
 129 
 130                 case 'E':
 131                         if (Ealternative || Oalternative)
 132                                 break;
 133                         Ealternative++;
 134                         goto label;
 135 
 136                 case 'O':
 137                         if (Ealternative || Oalternative)
 138                                 break;
 139                         Oalternative++;
 140                         goto label;
 141 
 142                 case 'F':
 143                         buf = __strptime(buf, "%Y-%m-%d", tm, flagsp);
 144                         if (buf == NULL)
 145                                 return (NULL);
 146                         break;
 147 
 148                 case 'R':
 149                         buf = __strptime(buf, "%H:%M", tm, flagsp);
 150                         if (buf == NULL)
 151                                 return (NULL);
 152                         break;
 153 
 154                 case 'r':
 155                         buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp);
 156                         if (buf == NULL)
 157                                 return (NULL);
 158                         break;
 159 
 160                 case 'T':
 161                         buf = __strptime(buf, "%H:%M:%S", tm, flagsp);
 162                         if (buf == NULL)
 163                                 return (NULL);
 164                         break;
 165 
 166                 case 'X':
 167                         buf = __strptime(buf, tptr->X_fmt, tm, flagsp);
 168                         if (buf == NULL)
 169                                 return (NULL);
 170                         break;
 171 
 172                 case 'x':
 173                         buf = __strptime(buf, tptr->x_fmt, tm, flagsp);
 174                         if (buf == NULL)
 175                                 return (NULL);
 176                         break;
 177 
 178                 case 'j':
 179                         if (!isdigit(*buf))
 180                                 return (NULL);
 181 
 182                         len = 3;
 183                         for (i = 0; len && isdigit(*buf); buf++) {
 184                                 i *= 10;
 185                                 i += *buf - '0';
 186                                 len--;
 187                         }
 188                         if (i < 1 || i > 366)
 189                                 return (NULL);
 190 
 191                         tm->tm_yday = i - 1;
 192                         break;
 193 


 502                         break;
 503                 case 'n':
 504                 case 't':
 505                         while (isspace(*buf))
 506                                 buf++;
 507                         break;
 508                 }
 509         }
 510 
 511         if (!recurse) {
 512                 if (buf && (*flagsp & F_GMT)) {
 513                         time_t t = timegm(tm);
 514                         (void) localtime_r(&t, tm);
 515                 }
 516         }
 517 
 518         return ((char *)buf);
 519 }
 520 
 521 char *
 522 strptime(const char *buf, const char *fmt, struct tm *tm)

 523 {
 524         int     flags = F_ZERO;
 525 
 526         return (__strptime(buf, fmt, tm, &flags));


 527 }
 528 
 529 /*
 530  * This is used by Solaris, and is a variant that does not clear the
 531  * incoming tm.  It is triggered by -D_STRPTIME_DONTZERO.
 532  */
 533 char *
 534 __strptime_dontzero(const char *buf, const char *fmt, struct tm *tm)

 535 {
 536         int     flags = 0;
 537 
 538         return (__strptime(buf, fmt, tm, &flags));





















 539 }
   1 /*
   2  * Copyright (c) 2014 Gary Mills
   3  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
   4  * Copyright 2011, Nexenta Systems, Inc.  All rights reserved.
   5  * Copyright (c) 1994 Powerdog Industries.  All rights reserved.
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  *
  11  * 1. Redistributions of source code must retain the above copyright
  12  *    notice, this list of conditions and the following disclaimer.
  13  *
  14  * 2. Redistributions in binary form must reproduce the above copyright
  15  *    notice, this list of conditions and the following disclaimer
  16  *    in the documentation and/or other materials provided with the
  17  *    distribution.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
  20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
  23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  26  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  28  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  29  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30  *
  31  * The views and conclusions contained in the software and documentation
  32  * are those of the authors and should not be interpreted as representing
  33  * official policies, either expressed or implied, of Powerdog Industries.
  34  */
  35 
  36 #include "lint.h"
  37 #include <time.h>
  38 #include <ctype.h>
  39 #include <errno.h>
  40 #include <stdlib.h>
  41 #include <string.h>
  42 #include <pthread.h>
  43 #include <alloca.h>
  44 #include <locale.h>
  45 #include "timelocal.h"
  46 #include "localeimpl.h"
  47 
  48 #define asizeof(a)      (sizeof (a) / sizeof ((a)[0]))
  49 
  50 #define F_GMT           (1 << 0)

  51 #define F_RECURSE       (1 << 2)
  52 
  53 static char *
  54 __strptime(const char *_RESTRICT_KYWD buf, const char *_RESTRICT_KYWD fmt,
  55     struct tm *_RESTRICT_KYWD tm, int *_RESTRICT_KYWD flagsp,
  56     locale_t _RESTRICT_KYWD loc)
  57 {
  58         char    c;
  59         const char *ptr;
  60         int     i, len, recurse = 0;
  61         int Ealternative, Oalternative;
  62         const struct lc_time *tptr = loc->time;
  63 
  64         if (*flagsp & F_RECURSE)
  65                 recurse = 1;
  66         *flagsp |= F_RECURSE;
  67 




  68         ptr = fmt;
  69         while (*ptr != 0) {
  70                 if (*buf == 0)
  71                         break;
  72 
  73                 c = *ptr++;
  74 
  75                 if (c != '%') {
  76                         if (isspace(c))
  77                                 while (isspace(*buf))
  78                                         buf++;
  79                         else if (c != *buf++)
  80                                 return (NULL);
  81                         continue;
  82                 }
  83 
  84                 Ealternative = 0;
  85                 Oalternative = 0;
  86 label:
  87                 c = *ptr++;
  88                 switch (c) {
  89                 case 0:
  90                 case '%':
  91                         if (*buf++ != '%')
  92                                 return (NULL);
  93                         break;
  94 
  95                 case '+':
  96                         buf = __strptime(buf, tptr->date_fmt, tm, flagsp, loc);
  97                         if (buf == NULL)
  98                                 return (NULL);
  99                         break;
 100 
 101                 case 'C':
 102                         if (!isdigit(*buf))
 103                                 return (NULL);
 104 
 105                         /* XXX This will break for 3-digit centuries. */
 106                         len = 2;
 107                         for (i = 0; len && isdigit(*buf); buf++) {
 108                                 i *= 10;
 109                                 i += *buf - '0';
 110                                 len--;
 111                         }
 112                         if (i < 19)
 113                                 return (NULL);
 114 
 115                         tm->tm_year = i * 100 - 1900;
 116                         break;
 117 
 118                 case 'c':
 119                         buf = __strptime(buf, tptr->c_fmt, tm, flagsp, loc);
 120                         if (buf == NULL)
 121                                 return (NULL);
 122                         break;
 123 
 124                 case 'D':
 125                         buf = __strptime(buf, "%m/%d/%y", tm, flagsp, loc);
 126                         if (buf == NULL)
 127                                 return (NULL);
 128                         break;
 129 
 130                 case 'E':
 131                         if (Ealternative || Oalternative)
 132                                 break;
 133                         Ealternative++;
 134                         goto label;
 135 
 136                 case 'O':
 137                         if (Ealternative || Oalternative)
 138                                 break;
 139                         Oalternative++;
 140                         goto label;
 141 
 142                 case 'F':
 143                         buf = __strptime(buf, "%Y-%m-%d", tm, flagsp, loc);
 144                         if (buf == NULL)
 145                                 return (NULL);
 146                         break;
 147 
 148                 case 'R':
 149                         buf = __strptime(buf, "%H:%M", tm, flagsp, loc);
 150                         if (buf == NULL)
 151                                 return (NULL);
 152                         break;
 153 
 154                 case 'r':
 155                         buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp, loc);
 156                         if (buf == NULL)
 157                                 return (NULL);
 158                         break;
 159 
 160                 case 'T':
 161                         buf = __strptime(buf, "%H:%M:%S", tm, flagsp, loc);
 162                         if (buf == NULL)
 163                                 return (NULL);
 164                         break;
 165 
 166                 case 'X':
 167                         buf = __strptime(buf, tptr->X_fmt, tm, flagsp, loc);
 168                         if (buf == NULL)
 169                                 return (NULL);
 170                         break;
 171 
 172                 case 'x':
 173                         buf = __strptime(buf, tptr->x_fmt, tm, flagsp, loc);
 174                         if (buf == NULL)
 175                                 return (NULL);
 176                         break;
 177 
 178                 case 'j':
 179                         if (!isdigit(*buf))
 180                                 return (NULL);
 181 
 182                         len = 3;
 183                         for (i = 0; len && isdigit(*buf); buf++) {
 184                                 i *= 10;
 185                                 i += *buf - '0';
 186                                 len--;
 187                         }
 188                         if (i < 1 || i > 366)
 189                                 return (NULL);
 190 
 191                         tm->tm_yday = i - 1;
 192                         break;
 193 


 502                         break;
 503                 case 'n':
 504                 case 't':
 505                         while (isspace(*buf))
 506                                 buf++;
 507                         break;
 508                 }
 509         }
 510 
 511         if (!recurse) {
 512                 if (buf && (*flagsp & F_GMT)) {
 513                         time_t t = timegm(tm);
 514                         (void) localtime_r(&t, tm);
 515                 }
 516         }
 517 
 518         return ((char *)buf);
 519 }
 520 
 521 char *
 522 strptime(const char *_RESTRICT_KYWD buf, const char *_RESTRICT_KYWD fmt,
 523     struct tm *_RESTRICT_KYWD tm)
 524 {
 525         int     flags = 0;
 526 
 527         (void) memset(tm, 0, sizeof (*tm));
 528 
 529         return (__strptime(buf, fmt, tm, &flags, uselocale(NULL)));
 530 }
 531 
 532 /*
 533  * This is used by Solaris, and is a variant that does not clear the
 534  * incoming tm.  It is triggered by -D_STRPTIME_DONTZERO.
 535  */
 536 char *
 537 __strptime_dontzero(const char *_RESTRICT_KYWD buf,
 538     const char *_RESTRICT_KYWD fmt, struct tm *_RESTRICT_KYWD tm)
 539 {
 540         int     flags = 0;
 541 
 542         return (__strptime(buf, fmt, tm, &flags, uselocale(NULL)));
 543 }
 544 
 545 /*
 546  * strptime_l is an extension that seems natural, and indeed, MacOS X
 547  * includes it within their <xlocale.h> and it is part of GNU libc as well.
 548  * For now we restrict it to the cases where strict namespaces are not
 549  * included.  We expect to see it in a future version of POSIX.  locale_t is
 550  * not a restrict, since the spec for it doesn't assume its a pointer.  We
 551  * therefore pass it analagously to the way strftime_l is specified.
 552  *
 553  * We are not providing a non-zeroing version at this time.
 554  */
 555 char *
 556 strptime_l(const char *_RESTRICT_KYWD buf, const char *_RESTRICT_KYWD fmt,
 557     struct tm *_RESTRICT_KYWD tm, locale_t loc)
 558 {
 559         int     flags =  0;
 560 
 561         (void) memset(tm, 0, sizeof (*tm));
 562 
 563         return (__strptime(buf, fmt, tm, &flags, loc));
 564 }