[BACK]Return to strptime.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / time

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/lib/libc/time/strptime.c between version 1.22 and 1.23

version 1.22, 2000/12/20 20:56:34 version 1.23, 2005/03/04 21:41:42
Line 60  __weak_alias(strptime,_strptime)
Line 60  __weak_alias(strptime,_strptime)
  */   */
 #define ALT_E                   0x01  #define ALT_E                   0x01
 #define ALT_O                   0x02  #define ALT_O                   0x02
 #define LEGAL_ALT(x)            { if (alt_format & ~(x)) return (0); }  #define LEGAL_ALT(x)            { if (alt_format & ~(x)) return 0; }
   
   
 static  int conv_num __P((const unsigned char **, int *, int, int));  static const u_char *conv_num(const unsigned char *, int *, int, int);
   static const u_char *find_string(const u_char *, int *, const char * const *,
           const char * const *, int);
   
   
 char *  char *
 strptime(buf, fmt, tm)  strptime(const char *buf, const char *fmt, struct tm *tm)
         const char *buf, *fmt;  
         struct tm *tm;  
 {  {
         unsigned char c;          unsigned char c;
         const unsigned char *bp;          const unsigned char *bp;
         size_t len = 0;  
         int alt_format, i, split_year = 0;          int alt_format, i, split_year = 0;
           const char *new_fmt;
   
         bp = (const u_char *)buf;          bp = (const u_char *)buf;
   
         while ((c = *fmt) != '\0') {          while (bp != NULL && (c = *fmt) != '\0') {
                 /* Clear `alternate' modifier prior to new conversion. */                  /* Clear `alternate' modifier prior to new conversion. */
                 alt_format = 0;                  alt_format = 0;
                   i = 0;
   
                 /* Eat up white-space. */                  /* Eat up white-space. */
                 if (isspace(c)) {                  if (isspace(c)) {
Line 90  strptime(buf, fmt, tm)
Line 91  strptime(buf, fmt, tm)
                         fmt++;                          fmt++;
                         continue;                          continue;
                 }                  }
   
                 if ((c = *fmt++) != '%')                  if ((c = *fmt++) != '%')
                         goto literal;                          goto literal;
   
Line 99  again:  switch (c = *fmt++) {
Line 100  again:  switch (c = *fmt++) {
                 case '%':       /* "%%" is converted to "%". */                  case '%':       /* "%%" is converted to "%". */
 literal:  literal:
                         if (c != *bp++)                          if (c != *bp++)
                                 return (0);                                  return 0;
                         break;                          LEGAL_ALT(0);
                           continue;
   
                 /*                  /*
                  * "Alternative" modifiers. Just set the appropriate flag                   * "Alternative" modifiers. Just set the appropriate flag
Line 115  literal:
Line 117  literal:
                         LEGAL_ALT(0);                          LEGAL_ALT(0);
                         alt_format |= ALT_O;                          alt_format |= ALT_O;
                         goto again;                          goto again;
   
                 /*                  /*
                  * "Complex" conversion rules, implemented through recursion.                   * "Complex" conversion rules, implemented through recursion.
                  */                   */
                 case 'c':       /* Date and time, using the locale's format. */                  case 'c':       /* Date and time, using the locale's format. */
                         LEGAL_ALT(ALT_E);                          new_fmt = _ctloc(d_t_fmt);
                         if (!(bp = (const u_char *)strptime((const char *)bp,                          goto recurse;
                             _ctloc(d_t_fmt), tm)))  
                                 return (0);  
                         break;  
   
                 case 'D':       /* The date as "%m/%d/%y". */                  case 'D':       /* The date as "%m/%d/%y". */
                           new_fmt = "%m/%d/%y";
                         LEGAL_ALT(0);                          LEGAL_ALT(0);
                         if (!(bp = (const u_char *) strptime((const char *)bp,                          goto recurse;
                             "%m/%d/%y", tm)))  
                                 return (0);  
                         break;  
   
                 case 'R':       /* The time as "%H:%M". */                  case 'R':       /* The time as "%H:%M". */
                           new_fmt = "%H:%M";
                         LEGAL_ALT(0);                          LEGAL_ALT(0);
                         if (!(bp = (const u_char *)strptime((const char *)bp,                          goto recurse;
                             "%H:%M", tm)))  
                                 return (0);  
                         break;  
   
                 case 'r':       /* The time in 12-hour clock representation. */                  case 'r':       /* The time in 12-hour clock representation. */
                           new_fmt =_ctloc(t_fmt_ampm);
                         LEGAL_ALT(0);                          LEGAL_ALT(0);
                         if (!(bp = (const u_char *)strptime((const char *)bp,                          goto recurse;
                             _ctloc(t_fmt_ampm), tm)))  
                                 return (0);  
                         break;  
   
                 case 'T':       /* The time as "%H:%M:%S". */                  case 'T':       /* The time as "%H:%M:%S". */
                           new_fmt = "%H:%M:%S";
                         LEGAL_ALT(0);                          LEGAL_ALT(0);
                         if (!(bp = (const u_char *)strptime((const char *)bp,                          goto recurse;
                             "%H:%M:%S", tm)))  
                                 return (0);  
                         break;  
   
                 case 'X':       /* The time, using the locale's format. */                  case 'X':       /* The time, using the locale's format. */
                         LEGAL_ALT(ALT_E);                          new_fmt =_ctloc(t_fmt);
                         if (!(bp = (const u_char *)strptime((const char *)bp,                          goto recurse;
                             _ctloc(t_fmt), tm)))  
                                 return (0);  
                         break;  
   
                 case 'x':       /* The date, using the locale's format. */                  case 'x':       /* The date, using the locale's format. */
                           new_fmt =_ctloc(d_fmt);
                       recurse:
                           bp = (const u_char *)strptime((const char *)bp,
                                                               new_fmt, tm);
                         LEGAL_ALT(ALT_E);                          LEGAL_ALT(ALT_E);
                         if (!(bp = (const u_char *)strptime((const char *)bp,                          continue;
                             _ctloc(d_fmt), tm)))  
                                 return (0);  
                         break;  
   
                 /*                  /*
                  * "Elementary" conversion rules.                   * "Elementary" conversion rules.
                  */                   */
                 case 'A':       /* The day of week, using the locale's form. */                  case 'A':       /* The day of week, using the locale's form. */
                 case 'a':                  case 'a':
                           bp = find_string(bp, &tm->tm_wday, _ctloc(day),
                                           _ctloc(abday), 7);
                         LEGAL_ALT(0);                          LEGAL_ALT(0);
                         for (i = 0; i < 7; i++) {                          continue;
                                 /* Full name. */  
                                 len = strlen(_ctloc(day[i]));  
                                 if (strncasecmp(_ctloc(day[i]),  
                                     (const char *)bp, len) == 0)  
                                         break;  
   
                                 /* Abbreviated name. */  
                                 len = strlen(_ctloc(abday[i]));  
                                 if (strncasecmp(_ctloc(abday[i]),  
                                     (const char *)bp, len) == 0)  
                                         break;  
                         }  
   
                         /* Nothing matched. */  
                         if (i == 7)  
                                 return (0);  
   
                         tm->tm_wday = i;  
                         bp += len;  
                         break;  
   
                 case 'B':       /* The month, using the locale's form. */                  case 'B':       /* The month, using the locale's form. */
                 case 'b':                  case 'b':
                 case 'h':                  case 'h':
                           bp = find_string(bp, &tm->tm_mon, _ctloc(mon),
                                           _ctloc(abmon), 12);
                         LEGAL_ALT(0);                          LEGAL_ALT(0);
                         for (i = 0; i < 12; i++) {                          continue;
                                 /* Full name. */  
                                 len = strlen(_ctloc(mon[i]));  
                                 if (strncasecmp(_ctloc(mon[i]),  
                                     (const char *)bp, len) == 0)  
                                         break;  
   
                                 /* Abbreviated name. */  
                                 len = strlen(_ctloc(abmon[i]));  
                                 if (strncasecmp(_ctloc(abmon[i]),  
                                     (const char *)bp, len) == 0)  
                                         break;  
                         }  
   
                         /* Nothing matched. */  
                         if (i == 12)  
                                 return (0);  
   
                         tm->tm_mon = i;  
                         bp += len;  
                         break;  
   
                 case 'C':       /* The century number. */                  case 'C':       /* The century number. */
                         LEGAL_ALT(ALT_E);                          bp = conv_num(bp, &i, 0, 99);
                         if (!(conv_num(&bp, &i, 0, 99)))                          if (bp == NULL)
                                 return (0);                                  return NULL;
   
                         if (split_year) {                          if (split_year) {
                                 tm->tm_year = (tm->tm_year % 100) + (i * 100);                                  tm->tm_year = (tm->tm_year % 100) + (i * 100);
Line 233  literal:
Line 186  literal:
                                 tm->tm_year = i * 100;                                  tm->tm_year = i * 100;
                                 split_year = 1;                                  split_year = 1;
                         }                          }
                         break;                          tm->tm_year -= TM_YEAR_BASE;
                           LEGAL_ALT(ALT_E);
                           continue;
   
                 case 'd':       /* The day of month. */                  case 'd':       /* The day of month. */
                 case 'e':                  case 'e':
                           bp = conv_num(bp, &tm->tm_mday, 1, 31);
                         LEGAL_ALT(ALT_O);                          LEGAL_ALT(ALT_O);
                         if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))                          continue;
                                 return (0);  
                         break;  
   
                 case 'k':       /* The hour (24-hour clock representation). */                  case 'k':       /* The hour (24-hour clock representation). */
                         LEGAL_ALT(0);                          LEGAL_ALT(0);
                         /* FALLTHROUGH */                          /* FALLTHROUGH */
                 case 'H':                  case 'H':
                           bp = conv_num(bp, &tm->tm_hour, 0, 23);
                         LEGAL_ALT(ALT_O);                          LEGAL_ALT(ALT_O);
                         if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))                          continue;
                                 return (0);  
                         break;  
   
                 case 'l':       /* The hour (12-hour clock representation). */                  case 'l':       /* The hour (12-hour clock representation). */
                         LEGAL_ALT(0);                          LEGAL_ALT(0);
                         /* FALLTHROUGH */                          /* FALLTHROUGH */
                 case 'I':                  case 'I':
                         LEGAL_ALT(ALT_O);                          bp = conv_num(bp, &tm->tm_hour, 1, 12);
                         if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))  
                                 return (0);  
                         if (tm->tm_hour == 12)                          if (tm->tm_hour == 12)
                                 tm->tm_hour = 0;                                  tm->tm_hour = 0;
                         break;                          LEGAL_ALT(ALT_O);
                           continue;
   
                 case 'j':       /* The day of year. */                  case 'j':       /* The day of year. */
                         LEGAL_ALT(0);                          i = 1;
                         if (!(conv_num(&bp, &i, 1, 366)))                          bp = conv_num(bp, &i, 1, 366);
                                 return (0);  
                         tm->tm_yday = i - 1;                          tm->tm_yday = i - 1;
                         break;                          LEGAL_ALT(0);
                           continue;
   
                 case 'M':       /* The minute. */                  case 'M':       /* The minute. */
                           bp = conv_num(bp, &tm->tm_min, 0, 59);
                         LEGAL_ALT(ALT_O);                          LEGAL_ALT(ALT_O);
                         if (!(conv_num(&bp, &tm->tm_min, 0, 59)))                          continue;
                                 return (0);  
                         break;  
   
                 case 'm':       /* The month. */                  case 'm':       /* The month. */
                         LEGAL_ALT(ALT_O);                          i = 1;
                         if (!(conv_num(&bp, &i, 1, 12)))                          bp = conv_num(bp, &i, 1, 12);
                                 return (0);  
                         tm->tm_mon = i - 1;                          tm->tm_mon = i - 1;
                         break;                          LEGAL_ALT(ALT_O);
                           continue;
   
                 case 'p':       /* The locale's equivalent of AM/PM. */                  case 'p':       /* The locale's equivalent of AM/PM. */
                           bp = find_string(bp, &i, _ctloc(am_pm),
                                           _ctloc(am_pm), 2);
                           if (tm->tm_hour > 11)
                                   return 0;
                           tm->tm_hour += i * 12;
                         LEGAL_ALT(0);                          LEGAL_ALT(0);
                         /* AM? */                          continue;
                         if (strcasecmp(_ctloc(am_pm[0]),  
                             (const char *)bp) == 0) {  
                                 if (tm->tm_hour > 11)  
                                         return (0);  
   
                                 bp += strlen(_ctloc(am_pm[0]));  
                                 break;  
                         }  
                         /* PM? */  
                         else if (strcasecmp(_ctloc(am_pm[1]),  
                             (const char *)bp) == 0) {  
                                 if (tm->tm_hour > 11)  
                                         return (0);  
   
                                 tm->tm_hour += 12;  
                                 bp += strlen(_ctloc(am_pm[1]));  
                                 break;  
                         }  
   
                         /* Nothing matched. */  
                         return (0);  
   
                 case 'S':       /* The seconds. */                  case 'S':       /* The seconds. */
                           bp = conv_num(bp, &tm->tm_sec, 0, 61);
                         LEGAL_ALT(ALT_O);                          LEGAL_ALT(ALT_O);
                         if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))                          continue;
                                 return (0);  
                         break;  
   
                 case 'U':       /* The week of year, beginning on sunday. */                  case 'U':       /* The week of year, beginning on sunday. */
                 case 'W':       /* The week of year, beginning on monday. */                  case 'W':       /* The week of year, beginning on monday. */
                         LEGAL_ALT(ALT_O);  
                         /*                          /*
                          * XXX This is bogus, as we can not assume any valid                           * XXX This is bogus, as we can not assume any valid
                          * information present in the tm structure at this                           * information present in the tm structure at this
                          * point to calculate a real value, so just check the                           * point to calculate a real value, so just check the
                          * range for now.                           * range for now.
                          */                           */
                          if (!(conv_num(&bp, &i, 0, 53)))                           bp = conv_num(bp, &i, 0, 53);
                                 return (0);                           LEGAL_ALT(ALT_O);
                          break;                           continue;
   
                 case 'w':       /* The day of week, beginning on sunday. */                  case 'w':       /* The day of week, beginning on sunday. */
                           bp = conv_num(bp, &tm->tm_wday, 0, 6);
                         LEGAL_ALT(ALT_O);                          LEGAL_ALT(ALT_O);
                         if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))                          continue;
                                 return (0);  
                         break;  
   
                 case 'Y':       /* The year. */                  case 'Y':       /* The year. */
                         LEGAL_ALT(ALT_E);                          bp = conv_num(bp, &i, 0, 9999);
                         if (!(conv_num(&bp, &i, 0, 9999)))                          if (bp == NULL)
                                 return (0);                                  return NULL;
   
                         tm->tm_year = i - TM_YEAR_BASE;                          tm->tm_year = i - TM_YEAR_BASE;
                         break;                          LEGAL_ALT(ALT_E);
                           continue;
   
                 case 'y':       /* The year within 100 years of the epoch. */                  case 'y':       /* The year within 100 years of the epoch. */
                         LEGAL_ALT(ALT_E | ALT_O);                          bp = conv_num(bp, &i, 0, 99);
                         if (!(conv_num(&bp, &i, 0, 99)))                          if (bp == NULL)
                                 return (0);                                  return NULL;
   
                         if (split_year) {                          if (split_year) {
                                 tm->tm_year = ((tm->tm_year / 100) * 100) + i;                                  tm->tm_year = ((tm->tm_year / 100) * 100) + i;
                                 break;                                  continue;
                         }                          }
                         split_year = 1;                          split_year = 1;
                         if (i <= 68)                          if (i <= 68)
                                 tm->tm_year = i + 2000 - TM_YEAR_BASE;                                  tm->tm_year = i + 2000 - TM_YEAR_BASE;
                         else                          else
                                 tm->tm_year = i + 1900 - TM_YEAR_BASE;                                  tm->tm_year = i + 1900 - TM_YEAR_BASE;
                         break;                          /* LEGAL_ALT(ALT_E | ALT_O); */
                           continue;
   
                 /*                  /*
                  * Miscellaneous conversions.                   * Miscellaneous conversions.
                  */                   */
                 case 'n':       /* Any kind of white-space. */                  case 'n':       /* Any kind of white-space. */
                 case 't':                  case 't':
                         LEGAL_ALT(0);  
                         while (isspace(*bp))                          while (isspace(*bp))
                                 bp++;                                  bp++;
                         break;                          LEGAL_ALT(0);
                           continue;
   
   
                 default:        /* Unknown/unsupported conversion. */                  default:        /* Unknown/unsupported conversion. */
                         return (0);                          return 0;
                 }                  }
   
   
         }          }
   
         /* LINTED functional specification */          /* LINTED functional specification */
         return ((char *)bp);          return (char *)bp;
 }  }
   
   
 static int  static const u_char *
 conv_num(buf, dest, llim, ulim)  conv_num(const unsigned char *buf, int *dest, int llim, int ulim)
         const unsigned char **buf;  
         int *dest;  
         int llim, ulim;  
 {  {
         int result = 0;          int result = 0;
           unsigned char ch;
   
         /* The limit also determines the number of valid digits. */          /* The limit also determines the number of valid digits. */
         int rulim = ulim;          int rulim = ulim;
   
         if (**buf < '0' || **buf > '9')          ch = *buf;
                 return (0);          if (ch < '0' || ch > '9')
                   return 0;
   
         do {          do {
                 result *= 10;                  result *= 10;
                 result += *(*buf)++ - '0';                  result += ch - '0';
                 rulim /= 10;                  rulim /= 10;
         } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');                  ch = *++buf;
           } while ((result * 10 <= ulim) && rulim && ch >= '0' && ch <= '9');
   
         if (result < llim || result > ulim)          if (result < llim || result > ulim)
                 return (0);                  return 0;
   
         *dest = result;          *dest = result;
         return (1);          return buf;
   }
   
   static const u_char *
   find_string(const u_char *bp, int *tgt, const char * const *n1,
                   const char * const *n2, int c)
   {
           int i;
           unsigned int len;
   
           for (i = 0; ; i++, n1++, n2++) {
                   if (i > c)
                           /* Nothing matched */
                           return NULL;
                   /* Full name - must check first! */
                   len = strlen(*n1);
                   if (strncasecmp(*n1, (const char *)bp, len) == 0)
                           break;
                   /* Abbreviated name. */
                   len = strlen(*n2);
                   if (strncasecmp(*n2, (const char *)bp, len) == 0)
                           break;
           }
           *tgt = i;
           return bp + len;
 }  }

Legend:
Removed from v.1.22  
changed lines
  Added in v.1.23

CVSweb <webmaster@jp.NetBSD.org>