Changeset 2070 for trunk


Ignore:
Timestamp:
Jun 23, 2005, 8:07:14 AM (20 years ago)
Author:
bird
Message:

Fixed various parsing and calculation bugs.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/emx/src/lib/time/strptime.c

    • Property cvs2svn:cvs-rev changed from 1.7 to 1.8
    r2069 r2070  
    3838  if (!(s = parse_fmt (s, FMT, tm, &mask))) \
    3939    return NULL;
    40 #define NUMBER(DST,MIN,MAX,ADD) \
    41   if (!(s = parse_number (s, DST, MIN, MAX, ADD))) \
     40#define NUMBER(DST,MIN,MAX,ADD,LEN) \
     41  if (!(s = parse_number (s, DST, MIN, MAX, ADD, LEN))) \
    4242    return NULL;
    4343#define STRING(STR) \
     
    4949
    5050static const char *parse_number (const char *s, int *dst,
    51   int min, int max, int add)
     51  int min, int max, int add, int len)
    5252{
    5353  int n;
     
    5858    return NULL;
    5959  n = 0;
    60   while (isdigit (*s))
     60  while (isdigit (*s) && len-- > 0)
    6161    n = n * 10 + (*s++ - '0');  /* TODO: check for overflow */
    6262  if (n < min || (max >= 0 && n > max))
     
    109109
    110110#define MASK_CENTURY    0x00000001
    111 #define MASK_YEAR2      0x00000002
    112 #define MASK_YEAR4      0x00000004
    113 #define MASK_YEAR       (MASK_YEAR2 | MASK_YEAR4)
     111#define MASK_YEAR_ANY   0x10000000     
     112#define MASK_YEAR2      0x10000002
     113#define MASK_YEAR4      0x10000004
    114114#define MASK_YEARDAY    0x00000008
    115115#define MASK_MONTH      0x00000010
    116116#define MASK_MONTHDAY   0x00000020
    117 #define MASK_WEEKS      0x00000040
    118 #define MASK_WEEKM      0x00000080
    119 #define MASK_WEEK       (MASK_WEEKM | MASK_WEEKS)
     117#define MASK_WEEK_ANY   0x20000000
     118#define MASK_WEEKS      0x20000040
     119#define MASK_WEEKM      0x20000080
     120#define MASK_WEEKI      0x20001000
    120121#define MASK_WEEKDAY    0x00000100
    121122#define MASK_HOUR       0x00000200
     
    190191
    191192        case 'C': /* Century number */
    192           NUMBER (&century, 0, 99, 0);
     193          NUMBER (&century, 0, 99, 0, 2);
    193194          mask |= MASK_CENTURY;
    194195          break;
     
    196197        case 'd': /* Day of the month (1-31) */
    197198        case 'e':
    198           NUMBER (&tm->tm_mday, 1, 31, 0);
     199          NUMBER (&tm->tm_mday, 1, 31, 0, 2);
    199200          mask |= MASK_MONTHDAY;
    200201          break;
     
    204205          break;
    205206
     207        case 'F': /* ISO Date - C99 */
     208          RECURSE ("%Y-%m-%d");
     209          break;
     210
    206211        case 'H': /* Hour (00-23) */
    207212        case 'k':
    208           NUMBER (&tm->tm_hour, 0, 23, 0);
     213          NUMBER (&tm->tm_hour, 0, 23, 0, 2);
    209214          mask |= MASK_HOUR;
    210215          break;
     
    212217        case 'I': /* Hour (01-12) */
    213218        case 'l':
    214           NUMBER (&tm->tm_hour, 1, 12, 0);
     219          NUMBER (&tm->tm_hour, 1, 12, 0, 2);
    215220          mask |= MASK_HOUR;
    216221          break;
    217222
    218223        case 'j': /* Day of the year (1-366) */
    219           NUMBER (&tm->tm_yday, 1, 366, -1);
     224          NUMBER (&tm->tm_yday, 1, 366, -1, 3);
    220225          mask |= MASK_YEARDAY;
    221226          break;
    222227
    223228        case 'm': /* Month (01-12) */
    224           NUMBER (&tm->tm_mon, 1, 12, -1);
     229          NUMBER (&tm->tm_mon, 1, 12, -1, 2);
    225230          mask |= MASK_MONTH;
    226231          break;
    227232
    228233        case 'M': /* Minutes (00-59) */
    229           NUMBER (&tm->tm_min, 0, 59, 0);
     234          NUMBER (&tm->tm_min, 0, 59, 0, 2);
    230235          mask |= MASK_MINUTE;
    231236          break;
     
    237242          break;
    238243
    239         case 'p': /* am or pm */
     244        case 'p': /* AM or PM */
    240245          if (!(mask & MASK_HOUR)
    241246           || (tm->tm_hour < 1)
    242247           || (tm->tm_hour > 12))
    243248            return NULL;
    244           if ((t = parse_string (s, __libc_gLocaleTime.am)) != NULL)
     249          if (   (t = parse_string (s, "AM")) != NULL
     250              || (t = parse_string (s, __libc_gLocaleTime.am)) != NULL)
    245251          {
    246252            if (tm->tm_hour == 12)
    247253              tm->tm_hour = 0;
    248254          }
    249           else if ((t = parse_string (s, __libc_gLocaleTime.pm)) != NULL)
     255          else if (   (t = parse_string (s, "PM")) != NULL
     256                   || (t = parse_string (s, __libc_gLocaleTime.pm)) != NULL)
    250257          {
    251258            if (tm->tm_hour != 12)
     
    257264          break;
    258265
     266        case 'P': /* am or pm */
     267          if (!(mask & MASK_HOUR)
     268           || (tm->tm_hour < 1)
     269           || (tm->tm_hour > 12))
     270            return NULL;
     271          if (   (t = parse_string (s, "am")) != NULL
     272              || (t = parse_string (s, __libc_gLocaleTime.am)) != NULL)
     273          {
     274            if (tm->tm_hour == 12)
     275              tm->tm_hour = 0;
     276          }
     277          else if (   (t = parse_string (s, "pm")) != NULL
     278                   || (t = parse_string (s, __libc_gLocaleTime.pm)) != NULL)
     279          {
     280            if (tm->tm_hour != 12)
     281              tm->tm_hour += 12;
     282          }
     283          else
     284            return NULL;
     285          s = t;
     286          break;
     287
    259288        case 'r': /* HH:MM:SS am/pm */
    260289          RECURSE ("%I:%M:%S %p");
     
    266295
    267296        case 'S': /* Seconds (00-61(?)) */
    268           NUMBER (&tm->tm_sec, 0, 61, 0);
     297          NUMBER (&tm->tm_sec, 0, 61, 0, 2);
    269298          mask |= MASK_SECOND;
    270299          break;
     
    281310
    282311        case 'w': /* Weekday (0-6), 0 = Sunday */
    283           NUMBER (&tm->tm_wday, 0, 6, 0);
     312          NUMBER (&tm->tm_wday, 0, 6, 0, 1);
    284313          mask |= MASK_WEEKDAY;
    285314          break;
    286315
    287316        case 'U': /* Week number (0-53), 0 = Sunday */
    288           NUMBER (&week, 0, 53, 0);
     317          NUMBER (&week, 0, 53, 0, 2);
    289318          mask |= MASK_WEEKS;
    290319          break;
    291320
    292321        case 'W': /* Week number (0-53), 0 = Monday */
    293           NUMBER (&week, 0, 53, 0);
     322          NUMBER (&week, 0, 53, 0, 2);
    294323          mask |= MASK_WEEKM;
    295324          break;
     
    304333
    305334        case 'y':
    306           NUMBER (&tm->tm_year, 0, 99, 0);
     335          NUMBER (&tm->tm_year, 0, 99, 0, 2);
    307336          if (tm->tm_year < 69)
    308337            tm->tm_year += 100;
     
    311340
    312341        case 'Y':
    313           NUMBER (&tm->tm_year, 1900, -1, -1900);
     342          NUMBER (&tm->tm_year, 1900, -1, -1900, 4);
    314343          mask |= MASK_YEAR4;
    315344          /* Ignore century since it was explicitely given */
    316           century = -1; mask &= ~MASK_CENTURY;
     345          century = -1;
     346          mask &= ~MASK_CENTURY;
    317347          break;
    318348
     
    325355  if (mask & MASK_CENTURY)
    326356  {
    327     if (!(mask & MASK_YEAR))
     357    if (!(mask & MASK_YEAR_ANY))
    328358      tm->tm_year = 0;
    329359    tm->tm_year = (century - 19) * 100 + (tm->tm_year % 100);
     
    335365    mask |= *retmask;
    336366
    337   if ((mask & MASK_YEAR) && (mask & MASK_YEARDAY)
     367  if ((mask & MASK_YEAR_ANY) && (mask & MASK_YEARDAY)
    338368   && (mask & (MASK_MONTH | MASK_MONTHDAY)) != (MASK_MONTH | MASK_MONTHDAY))
    339369  {
     
    341371    const unsigned short *md = _leap_year (tm->tm_year + 1900) ?
    342372      _month_day_leap : _month_day_non_leap;
    343     for (tm->tm_mon = 0; tm->tm_mon < 12 && tm->tm_yday < md [tm->tm_mon];
    344          tm->tm_mon++) ;
     373    for (tm->tm_mon = 11; tm->tm_mon > 0 && tm->tm_yday < md [tm->tm_mon]; tm->tm_mon--)
     374        /* nothing */;
    345375    tm->tm_mday = 1 + tm->tm_yday - md [tm->tm_mon];
    346376    mask |= MASK_MONTH | MASK_MONTHDAY;
     
    349379  if (!(mask & MASK_YEARDAY))
    350380  {
    351     if ((mask & MASK_WEEK) && (mask & MASK_WEEKDAY) && (mask & MASK_YEAR)
     381    if ((mask & MASK_WEEK_ANY) && (mask & MASK_WEEKDAY) && (mask & MASK_YEAR_ANY)
    352382     && (tm->tm_year >= 70) && (tm->tm_year <= 206))
    353383    {
    354384      /* Compute day of the year given week number and weekday */
    355       int dow = (4 + _year_day [tm->tm_year]) % 7;
    356       if (mask & MASK_WEEKM)
    357         dow--;
    358       dow = (tm->tm_wday - dow) % 7;
    359       if (dow < 0) dow += 7;
     385      int dow = (mask & MASK_WEEKM) == MASK_WEEKM ? 3 : 4;
     386      dow = (dow + _year_day [tm->tm_year]) % 7;
     387      if (!dow)
     388          week--;
     389      dow = (tm->tm_wday - ((mask & MASK_WEEKM) == MASK_WEEKM) - dow) % 7;
     390      if (dow < 0)
     391        dow += 7;
    360392      tm->tm_yday = week * 7 + dow;
    361393      mask |= MASK_YEARDAY;
    362394    }
    363     else if ((mask & MASK_YEAR) && (mask & MASK_MONTH) && (mask & MASK_MONTHDAY))
     395    else if ((mask & MASK_YEAR_ANY) && (mask & MASK_MONTH) && (mask & MASK_MONTHDAY))
    364396    {
    365397      /* Compute year day from month and day of the month */
     
    371403  }
    372404
    373   if (!(mask & MASK_WEEKDAY) && (mask & MASK_YEAR) && (mask & MASK_YEARDAY))
     405  if (!(mask & MASK_WEEKDAY) && (mask & MASK_YEAR_ANY) && (mask & MASK_YEARDAY))
    374406  {
    375407    /* Compute day of the week if it was not given */
     
    385417  }
    386418
    387   if (((mask & (MASK_WEEK | MASK_WEEKDAY | MASK_YEAR)) == (MASK_WEEK | MASK_WEEKDAY | MASK_YEAR))
     419  if (((mask & (MASK_WEEK_ANY | MASK_WEEKDAY | MASK_YEAR_ANY)) == (MASK_WEEK_ANY | MASK_WEEKDAY | MASK_YEAR_ANY))
    388420   && ((mask & (MASK_MONTH | MASK_MONTHDAY)) != (MASK_MONTH | MASK_MONTHDAY)))
    389421  {
     
    393425    int days;
    394426
    395     for (days = tm->tm_yday, tm->tm_mon = 0; days >= md [tm->tm_mon];
    396          days -= md [tm->tm_mon], tm->tm_mon++)
    397       ;
    398     tm->tm_mday = 1 + days;
     427    for (tm->tm_mon = 11; tm->tm_mon > 0 && tm->tm_yday < md [tm->tm_mon]; tm->tm_mon--)
     428        /* nothing */;
     429    tm->tm_mday = 1 + tm->tm_yday - md [tm->tm_mon];
    399430    mask |= MASK_MONTH | MASK_MONTHDAY;
    400431  }
     
    403434     that are not located inside the tm structure. */
    404435  if (retmask)
    405     *retmask |= mask & ~(MASK_WEEK | MASK_CENTURY);
     436    *retmask |= mask & ~(MASK_WEEKI | MASK_WEEKM | MASK_WEEKS | MASK_CENTURY);
    406437
    407438  return s;
Note: See TracChangeset for help on using the changeset viewer.