Print this page
    
3141 strptime() doesn't support %t
    
      
        | Split | Close | 
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/libc/port/locale/strptime.c
          +++ new/usr/src/lib/libc/port/locale/strptime.c
   1    1  /*
        2 + * Copyright (c) 2014 Gary Mills
   2    3   * Copyright 2011, Nexenta Systems, Inc.  All rights reserved.
   3    4   * Copyright (c) 1994 Powerdog Industries.  All rights reserved.
   4    5   *
   5    6   * Redistribution and use in source and binary forms, with or without
   6    7   * modification, are permitted provided that the following conditions
   7    8   * are met:
   8    9   *
   9   10   * 1. Redistributions of source code must retain the above copyright
  10   11   *    notice, this list of conditions and the following disclaimer.
  11   12   *
  12   13   * 2. Redistributions in binary form must reproduce the above copyright
  13   14   *    notice, this list of conditions and the following disclaimer
  14   15   *    in the documentation and/or other materials provided with the
  15   16   *    distribution.
  16   17   *
  17   18   * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
  18   19   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19   20   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  20   21   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
  21   22   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22   23   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23   24   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  24   25   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  25   26   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  26   27   * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  27   28   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28   29   *
  29   30   * The views and conclusions contained in the software and documentation
  30   31   * are those of the authors and should not be interpreted as representing
  31   32   * official policies, either expressed or implied, of Powerdog Industries.
  32   33   */
  33   34  
  34   35  #include "lint.h"
  35   36  #include <time.h>
  36   37  #include <ctype.h>
  37   38  #include <errno.h>
  38   39  #include <stdlib.h>
  39   40  #include <string.h>
  40   41  #include <pthread.h>
  41   42  #include <alloca.h>
  42   43  #include "timelocal.h"
  43   44  
  44   45  #define asizeof(a)      (sizeof (a) / sizeof ((a)[0]))
  45   46  
  46   47  #define F_GMT           (1 << 0)
  47   48  #define F_ZERO          (1 << 1)
  48   49  #define F_RECURSE       (1 << 2)
  49   50  
  50   51  static char *
  51   52  __strptime(const char *buf, const char *fmt, struct tm *tm, int *flagsp)
  52   53  {
  53   54          char    c;
  54   55          const char *ptr;
  55   56          int     i, len, recurse = 0;
  56   57          int Ealternative, Oalternative;
  57   58          struct lc_time_T *tptr = __get_current_time_locale();
  58   59  
  59   60          if (*flagsp & F_RECURSE)
  60   61                  recurse = 1;
  61   62          *flagsp |= F_RECURSE;
  62   63  
  63   64          if (*flagsp & F_ZERO)
  64   65                  (void) memset(tm, 0, sizeof (*tm));
  65   66          *flagsp &= ~F_ZERO;
  66   67  
  67   68          ptr = fmt;
  68   69          while (*ptr != 0) {
  69   70                  if (*buf == 0)
  70   71                          break;
  71   72  
  72   73                  c = *ptr++;
  73   74  
  74   75                  if (c != '%') {
  75   76                          if (isspace(c))
  76   77                                  while (isspace(*buf))
  77   78                                          buf++;
  78   79                          else if (c != *buf++)
  79   80                                  return (NULL);
  80   81                          continue;
  81   82                  }
  82   83  
  83   84                  Ealternative = 0;
  84   85                  Oalternative = 0;
  85   86  label:
  86   87                  c = *ptr++;
  87   88                  switch (c) {
  88   89                  case 0:
  89   90                  case '%':
  90   91                          if (*buf++ != '%')
  91   92                                  return (NULL);
  92   93                          break;
  93   94  
  94   95                  case '+':
  95   96                          buf = __strptime(buf, tptr->date_fmt, tm, flagsp);
  96   97                          if (buf == NULL)
  97   98                                  return (NULL);
  98   99                          break;
  99  100  
 100  101                  case 'C':
 101  102                          if (!isdigit(*buf))
 102  103                                  return (NULL);
 103  104  
 104  105                          /* XXX This will break for 3-digit centuries. */
 105  106                          len = 2;
 106  107                          for (i = 0; len && isdigit(*buf); buf++) {
 107  108                                  i *= 10;
 108  109                                  i += *buf - '0';
 109  110                                  len--;
 110  111                          }
 111  112                          if (i < 19)
 112  113                                  return (NULL);
 113  114  
 114  115                          tm->tm_year = i * 100 - 1900;
 115  116                          break;
 116  117  
 117  118                  case 'c':
 118  119                          buf = __strptime(buf, tptr->c_fmt, tm, flagsp);
 119  120                          if (buf == NULL)
 120  121                                  return (NULL);
 121  122                          break;
 122  123  
 123  124                  case 'D':
 124  125                          buf = __strptime(buf, "%m/%d/%y", tm, flagsp);
 125  126                          if (buf == NULL)
 126  127                                  return (NULL);
 127  128                          break;
 128  129  
 129  130                  case 'E':
 130  131                          if (Ealternative || Oalternative)
 131  132                                  break;
 132  133                          Ealternative++;
 133  134                          goto label;
 134  135  
 135  136                  case 'O':
 136  137                          if (Ealternative || Oalternative)
 137  138                                  break;
 138  139                          Oalternative++;
 139  140                          goto label;
 140  141  
 141  142                  case 'F':
 142  143                          buf = __strptime(buf, "%Y-%m-%d", tm, flagsp);
 143  144                          if (buf == NULL)
 144  145                                  return (NULL);
 145  146                          break;
 146  147  
 147  148                  case 'R':
 148  149                          buf = __strptime(buf, "%H:%M", tm, flagsp);
 149  150                          if (buf == NULL)
 150  151                                  return (NULL);
 151  152                          break;
 152  153  
 153  154                  case 'r':
 154  155                          buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp);
 155  156                          if (buf == NULL)
 156  157                                  return (NULL);
 157  158                          break;
 158  159  
 159  160                  case 'T':
 160  161                          buf = __strptime(buf, "%H:%M:%S", tm, flagsp);
 161  162                          if (buf == NULL)
 162  163                                  return (NULL);
 163  164                          break;
 164  165  
 165  166                  case 'X':
 166  167                          buf = __strptime(buf, tptr->X_fmt, tm, flagsp);
 167  168                          if (buf == NULL)
 168  169                                  return (NULL);
 169  170                          break;
 170  171  
 171  172                  case 'x':
 172  173                          buf = __strptime(buf, tptr->x_fmt, tm, flagsp);
 173  174                          if (buf == NULL)
 174  175                                  return (NULL);
 175  176                          break;
 176  177  
 177  178                  case 'j':
 178  179                          if (!isdigit(*buf))
 179  180                                  return (NULL);
 180  181  
 181  182                          len = 3;
 182  183                          for (i = 0; len && isdigit(*buf); buf++) {
 183  184                                  i *= 10;
 184  185                                  i += *buf - '0';
 185  186                                  len--;
 186  187                          }
 187  188                          if (i < 1 || i > 366)
 188  189                                  return (NULL);
 189  190  
 190  191                          tm->tm_yday = i - 1;
 191  192                          break;
 192  193  
 193  194                  case 'M':
 194  195                  case 'S':
 195  196                          if (*buf == 0 || isspace(*buf))
 196  197                                  break;
 197  198  
 198  199                          if (!isdigit(*buf))
 199  200                                  return (NULL);
 200  201  
 201  202                          len = 2;
 202  203                          for (i = 0; len && isdigit(*buf); buf++) {
 203  204                                  i *= 10;
 204  205                                  i += *buf - '0';
 205  206                                  len--;
 206  207                          }
 207  208  
  
    | ↓ open down ↓ | 196 lines elided | ↑ open up ↑ | 
 208  209                          if (c == 'M') {
 209  210                                  if (i > 59)
 210  211                                          return (NULL);
 211  212                                  tm->tm_min = i;
 212  213                          } else {
 213  214                                  if (i > 60)
 214  215                                          return (NULL);
 215  216                                  tm->tm_sec = i;
 216  217                          }
 217  218  
 218      -                        if (isspace(*buf))
 219      -                                while (*ptr != 0 && !isspace(*ptr))
 220      -                                        ptr++;
 221  219                          break;
 222  220  
 223  221                  case 'H':
 224  222                  case 'I':
 225  223                  case 'k':
 226  224                  case 'l':
 227  225                          /*
 228  226                           * Of these, %l is the only specifier explicitly
 229  227                           * documented as not being zero-padded.  However,
 230  228                           * there is no harm in allowing zero-padding.
 231  229                           *
 232  230                           * XXX The %l specifier may gobble one too many
 233  231                           * digits if used incorrectly.
 234  232                           */
 235  233                          if (!isdigit(*buf))
 236  234                                  return (NULL);
 237  235  
 238  236                          len = 2;
 239  237                          for (i = 0; len && isdigit(*buf); buf++) {
 240  238                                  i *= 10;
 241  239                                  i += *buf - '0';
  
    | ↓ open down ↓ | 11 lines elided | ↑ open up ↑ | 
 242  240                                  len--;
 243  241                          }
 244  242                          if (c == 'H' || c == 'k') {
 245  243                                  if (i > 23)
 246  244                                          return (NULL);
 247  245                          } else if (i > 12)
 248  246                                  return (NULL);
 249  247  
 250  248                          tm->tm_hour = i;
 251  249  
 252      -                        if (isspace(*buf))
 253      -                                while (*ptr != 0 && !isspace(*ptr))
 254      -                                        ptr++;
 255  250                          break;
 256  251  
 257  252                  case 'p':
 258  253                          /*
 259  254                           * XXX This is bogus if parsed before hour-related
 260  255                           * specifiers.
 261  256                           */
 262  257                          len = strlen(tptr->am);
 263  258                          if (strncasecmp(buf, tptr->am, len) == 0) {
 264  259                                  if (tm->tm_hour > 12)
 265  260                                          return (NULL);
 266  261                                  if (tm->tm_hour == 12)
 267  262                                          tm->tm_hour = 0;
 268  263                                  buf += len;
 269  264                                  break;
 270  265                          }
 271  266  
 272  267                          len = strlen(tptr->pm);
 273  268                          if (strncasecmp(buf, tptr->pm, len) == 0) {
 274  269                                  if (tm->tm_hour > 12)
 275  270                                          return (NULL);
 276  271                                  if (tm->tm_hour != 12)
 277  272                                          tm->tm_hour += 12;
 278  273                                  buf += len;
 279  274                                  break;
 280  275                          }
 281  276  
 282  277                          return (NULL);
 283  278  
 284  279                  case 'A':
 285  280                  case 'a':
 286  281                          for (i = 0; i < asizeof(tptr->weekday); i++) {
 287  282                                  len = strlen(tptr->weekday[i]);
 288  283                                  if (strncasecmp(buf, tptr->weekday[i], len) ==
 289  284                                      0)
 290  285                                          break;
 291  286                                  len = strlen(tptr->wday[i]);
 292  287                                  if (strncasecmp(buf, tptr->wday[i], len) == 0)
 293  288                                          break;
 294  289                          }
 295  290                          if (i == asizeof(tptr->weekday))
 296  291                                  return (NULL);
 297  292  
 298  293                          tm->tm_wday = i;
 299  294                          buf += len;
 300  295                          break;
 301  296  
 302  297                  case 'U':
 303  298                  case 'W':
 304  299                          /*
 305  300                           * XXX This is bogus, as we can not assume any valid
 306  301                           * information present in the tm structure at this
 307  302                           * point to calculate a real value, so just check the
 308  303                           * range for now.
 309  304                           */
 310  305                          if (!isdigit(*buf))
 311  306                                  return (NULL);
  
    | ↓ open down ↓ | 47 lines elided | ↑ open up ↑ | 
 312  307  
 313  308                          len = 2;
 314  309                          for (i = 0; len && isdigit(*buf); buf++) {
 315  310                                  i *= 10;
 316  311                                  i += *buf - '0';
 317  312                                  len--;
 318  313                          }
 319  314                          if (i > 53)
 320  315                                  return (NULL);
 321  316  
 322      -                        if (isspace(*buf))
 323      -                                while (*ptr != 0 && !isspace(*ptr))
 324      -                                        ptr++;
 325  317                          break;
 326  318  
 327  319                  case 'w':
 328  320                          if (!isdigit(*buf))
 329  321                                  return (NULL);
 330  322  
 331  323                          i = *buf - '0';
 332  324                          if (i > 6)
 333  325                                  return (NULL);
 334  326  
 335  327                          tm->tm_wday = i;
 336  328  
 337      -                        if (isspace(*buf))
 338      -                                while (*ptr != 0 && !isspace(*ptr))
 339      -                                        ptr++;
 340  329                          break;
 341  330  
      331 +                case 'd':
 342  332                  case 'e':
 343  333                          /*
 344  334                           * The %e format has a space before single digits
 345  335                           * which we need to skip.
 346  336                           */
 347  337                          if (isspace(*buf))
 348  338                                  buf++;
 349      -                        /* FALLTHROUGH */
 350      -                case 'd':
 351  339                          /*
 352  340                           * The %e specifier is explicitly documented as not
 353  341                           * being zero-padded but there is no harm in allowing
 354  342                           * such padding.
 355  343                           *
 356  344                           * XXX The %e specifier may gobble one too many
 357  345                           * digits if used incorrectly.
 358  346                           */
 359  347                          if (!isdigit(*buf))
 360  348                                  return (NULL);
 361  349  
 362  350                          len = 2;
  
    | ↓ open down ↓ | 2 lines elided | ↑ open up ↑ | 
 363  351                          for (i = 0; len && isdigit(*buf); buf++) {
 364  352                                  i *= 10;
 365  353                                  i += *buf - '0';
 366  354                                  len--;
 367  355                          }
 368  356                          if (i > 31)
 369  357                                  return (NULL);
 370  358  
 371  359                          tm->tm_mday = i;
 372  360  
 373      -                        if (isspace(*buf))
 374      -                                while (*ptr != 0 && !isspace(*ptr))
 375      -                                        ptr++;
 376  361                          break;
 377  362  
 378  363                  case 'B':
 379  364                  case 'b':
 380  365                  case 'h':
 381  366                          for (i = 0; i < asizeof(tptr->month); i++) {
 382  367                                  len = strlen(tptr->month[i]);
 383  368                                  if (strncasecmp(buf, tptr->month[i], len) == 0)
 384  369                                          break;
 385  370                          }
 386  371                          /*
 387  372                           * Try the abbreviated month name if the full name
 388  373                           * wasn't found.
 389  374                           */
 390  375                          if (i == asizeof(tptr->month)) {
 391  376                                  for (i = 0; i < asizeof(tptr->month); i++) {
 392  377                                          len = strlen(tptr->mon[i]);
 393  378                                          if (strncasecmp(buf, tptr->mon[i],
 394  379                                              len) == 0)
 395  380                                                  break;
 396  381                                  }
 397  382                          }
 398  383                          if (i == asizeof(tptr->month))
 399  384                                  return (NULL);
 400  385  
 401  386                          tm->tm_mon = i;
 402  387                          buf += len;
 403  388                          break;
 404  389  
 405  390                  case 'm':
 406  391                          if (!isdigit(*buf))
 407  392                                  return (NULL);
 408  393  
 409  394                          len = 2;
  
    | ↓ open down ↓ | 24 lines elided | ↑ open up ↑ | 
 410  395                          for (i = 0; len && isdigit(*buf); buf++) {
 411  396                                  i *= 10;
 412  397                                  i += *buf - '0';
 413  398                                  len--;
 414  399                          }
 415  400                          if (i < 1 || i > 12)
 416  401                                  return (NULL);
 417  402  
 418  403                          tm->tm_mon = i - 1;
 419  404  
 420      -                        if (isspace(*buf))
 421      -                                while (*ptr != NULL && !isspace(*ptr))
 422      -                                        ptr++;
 423  405                          break;
 424  406  
 425  407                  case 's':
 426  408                          {
 427  409                          char *cp;
 428  410                          int sverrno;
 429  411                          time_t t;
 430  412  
 431  413                          sverrno = errno;
 432  414                          errno = 0;
 433  415                          t = strtol(buf, &cp, 10);
 434  416                          if (errno == ERANGE) {
 435  417                                  errno = sverrno;
 436  418                                  return (NULL);
 437  419                          }
 438  420                          errno = sverrno;
 439  421                          buf = cp;
 440  422                          (void) gmtime_r(&t, tm);
 441  423                          *flagsp |= F_GMT;
 442  424                          }
 443  425                          break;
 444  426  
 445  427                  case 'Y':
 446  428                  case 'y':
 447  429                          if (*buf == NULL || isspace(*buf))
 448  430                                  break;
 449  431  
 450  432                          if (!isdigit(*buf))
 451  433                                  return (NULL);
 452  434  
 453  435                          len = (c == 'Y') ? 4 : 2;
 454  436                          for (i = 0; len && isdigit(*buf); buf++) {
 455  437                                  i *= 10;
 456  438                                  i += *buf - '0';
 457  439                                  len--;
  
    | ↓ open down ↓ | 25 lines elided | ↑ open up ↑ | 
 458  440                          }
 459  441                          if (c == 'Y')
 460  442                                  i -= 1900;
 461  443                          if (c == 'y' && i < 69)
 462  444                                  i += 100;
 463  445                          if (i < 0)
 464  446                                  return (NULL);
 465  447  
 466  448                          tm->tm_year = i;
 467  449  
 468      -                        if (isspace(*buf))
 469      -                                while (*ptr != 0 && !isspace(*ptr))
 470      -                                        ptr++;
 471  450                          break;
 472  451  
 473  452                  case 'Z':
 474  453                          {
 475  454                          const char *cp = buf;
 476  455                          char *zonestr;
 477  456  
 478  457                          while (isupper(*cp))
 479  458                                  ++cp;
 480  459                          if (cp - buf) {
 481  460                                  zonestr = alloca(cp - buf + 1);
 482  461                                  (void) strncpy(zonestr, buf, cp - buf);
 483  462                                  zonestr[cp - buf] = '\0';
 484  463                                  tzset();
 485  464                                  if (strcmp(zonestr, "GMT") == 0) {
 486  465                                          *flagsp |= F_GMT;
 487  466                                  } else if (0 == strcmp(zonestr, tzname[0])) {
 488  467                                          tm->tm_isdst = 0;
 489  468                                  } else if (0 == strcmp(zonestr, tzname[1])) {
 490  469                                          tm->tm_isdst = 1;
 491  470                                  } else {
 492  471                                          return (NULL);
 493  472                                  }
 494  473                                  buf += cp - buf;
 495  474                          }
 496  475                          }
 497  476                          break;
 498  477  
 499  478                  case 'z':
 500  479                          {
 501  480                          int sign = 1;
 502  481  
 503  482                          if (*buf != '+') {
 504  483                                  if (*buf == '-')
 505  484                                          sign = -1;
 506  485                                  else
 507  486                                          return (NULL);
 508  487                          }
 509  488                          buf++;
 510  489                          i = 0;
 511  490                          for (len = 4; len > 0; len--) {
 512  491                                  if (!isdigit(*buf))
 513  492                                          return (NULL);
  
    | ↓ open down ↓ | 33 lines elided | ↑ open up ↑ | 
 514  493                                  i *= 10;
 515  494                                  i += *buf - '0';
 516  495                                  buf++;
 517  496                          }
 518  497  
 519  498                          tm->tm_hour -= sign * (i / 100);
 520  499                          tm->tm_min -= sign * (i % 100);
 521  500                          *flagsp |= F_GMT;
 522  501                          }
 523  502                          break;
      503 +                case 'n':
      504 +                case 't':
      505 +                        while (isspace(*buf))
      506 +                                buf++;
      507 +                        break;
 524  508                  }
 525  509          }
 526  510  
 527  511          if (!recurse) {
 528  512                  if (buf && (*flagsp & F_GMT)) {
 529  513                          time_t t = timegm(tm);
 530  514                          (void) localtime_r(&t, tm);
 531  515                  }
 532  516          }
 533  517  
 534  518          return ((char *)buf);
 535  519  }
 536  520  
 537  521  char *
 538  522  strptime(const char *buf, const char *fmt, struct tm *tm)
 539  523  {
 540  524          int     flags = F_ZERO;
 541  525  
 542  526          return (__strptime(buf, fmt, tm, &flags));
 543  527  }
 544  528  
 545  529  /*
 546  530   * This is used by Solaris, and is a variant that does not clear the
 547  531   * incoming tm.  It is triggered by -D_STRPTIME_DONTZERO.
 548  532   */
 549  533  char *
 550  534  __strptime_dontzero(const char *buf, const char *fmt, struct tm *tm)
 551  535  {
 552  536          int     flags = 0;
 553  537  
 554  538          return (__strptime(buf, fmt, tm, &flags));
 555  539  }
  
    | ↓ open down ↓ | 22 lines elided | ↑ open up ↑ | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX