gonzui


Format: Advanced Search

t2ex/bsd_source/lib/libc/src_bsd/time/strptime.cbare sourcepermlink (0.10 seconds)

Search this content:

    1: /*      $OpenBSD: strptime.c,v 1.15 2012/01/16 17:42:45 millert Exp $ */
    2: /*      $NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $ */
    3: 
    4: /*-
    5:  * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
    6:  * All rights reserved.
    7:  *
    8:  * This code was contributed to The NetBSD Foundation by Klaus Klein.
    9:  *
   10:  * Redistribution and use in source and binary forms, with or without
   11:  * modification, are permitted provided that the following conditions
   12:  * are met:
   13:  * 1. Redistributions of source code must retain the above copyright
   14:  *    notice, this list of conditions and the following disclaimer.
   15:  * 2. Redistributions in binary form must reproduce the above copyright
   16:  *    notice, this list of conditions and the following disclaimer in the
   17:  *    documentation and/or other materials provided with the distribution.
   18:  *
   19:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23:  * BE 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 BUSINESS
   26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29:  * POSSIBILITY OF SUCH DAMAGE.
   30:  */
   31: 
   32: //#include <sys/localedef.h>
   33: #include <ctype.h>
   34: //#include <locale.h>
   35: #include <string.h>
   36: #include <strings.h>
   37: #include <time.h>
   38: //#include <tzfile.h>
   39: 
   40: #define TM_YEAR_BASE 1900
   41: #define DAYSPERNYEAR 365
   42: #define MONSPERYEAR 12
   43: #define DAYSPERWEEK 7
   44: #define EPOCH_YEAR 1970
   45: #define EPOCH_WDAY 4
   46: #define isleap(year) (((((year)) % 4) == 0 && (((year)) % 100) != 0) || (((year)) % 400) == 0)
   47: #define _ctloc(x) (_CurrentTimeLocale.x)
   48: static const struct {
   49:         const char *abday[7];
   50:         const char *day[7];
   51:         const char *abmon[12];
   52:         const char *mon[12];
   53:         const char *am_pm[2];
   54:         const char *d_t_fmt;
   55:         const char *d_fmt;
   56:         const char *t_fmt;
   57: } _CurrentTimeLocale = {
   58:         .abday={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"},
   59:         .day={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"},
   60:         .abmon={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"},
   61:         .mon={"January","February","March","April","May","June","July","August","September","October","November","December"},
   62:         .am_pm={"AM","PM"},
   63:         .d_t_fmt="%a %b %e %T %Y",
   64:         .d_fmt="%a %b %e %Y",
   65:         .t_fmt="%T"
   66: };
   67: 
   68: /*
   69:  * We do not implement alternate representations. However, we always
   70:  * check whether a given modifier is allowed for a certain conversion.
   71:  */
   72: #define _ALT_E                  0x01
   73: #define _ALT_O                  0x02
   74: #define _LEGAL_ALT(x)           { if (alt_format & ~(x)) return (0); }
   75: 
   76: /*
   77:  * We keep track of some of the fields we set in order to compute missing ones.
   78:  */
   79: #define FIELD_TM_MON    (1 << 0)
   80: #define FIELD_TM_MDAY   (1 << 1)
   81: #define FIELD_TM_WDAY   (1 << 2)
   82: #define FIELD_TM_YDAY   (1 << 3)
   83: #define FIELD_TM_YEAR   (1 << 4)
   84: 
   85: //static char gmt[] = { "GMT" };
   86: #ifdef TM_ZONE
   87: static char utc[] = { "UTC" };
   88: #endif
   89: /* RFC-822/RFC-2822 */
   90: static const char * const nast[5] = {
   91:        "EST",    "CST",    "MST",    "PST",    "\0\0\0"
   92: };
   93: static const char * const nadt[5] = {
   94:        "EDT",    "CDT",    "MDT",    "PDT",    "\0\0\0"
   95: };
   96: 
   97: static const int mon_lengths[2][MONSPERYEAR] = {
   98:         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
   99:         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  100: };
  101: 
  102: static  int _conv_num(const unsigned char **, int *, int, int);
  103: static  int leaps_thru_end_of(const int y);
  104: static  char *_strptime(const char *, const char *, struct tm *, int);
  105: static  const unsigned char *_find_string(const unsigned char *, int *, const char * const *,
  106:             const char * const *, int);
  107: 
  108: char *
  109: strptime(const char *buf, const char *fmt, struct tm *tm)
  110: {
  111:         return(_strptime(buf, fmt, tm, 1));
  112: }
  113: 
  114: static char *
  115: _strptime(const char *buf, const char *fmt, struct tm *tm, int initialize)
  116: {
  117:         unsigned char c;
  118:         const unsigned char *bp, *ep;
  119:         size_t len;
  120:         int alt_format, i, offs;
  121:         int neg = 0;
  122:         static int century, relyear, fields;
  123: 
  124:         if (initialize) {
  125: #if     1   /*** Modified on T2EX ***/
  126:                 century = -1;
  127: #else
  128:                 century = TM_YEAR_BASE;
  129: #endif
  130:                 relyear = -1;
  131:                 fields = 0;
  132:         }
  133: 
  134:         bp = (unsigned char *)buf;
  135:         while ((c = *fmt) != '\0') {
  136:                 /* Clear `alternate' modifier prior to new conversion. */
  137:                 alt_format = 0;
  138: 
  139:                 /* Eat up white-space. */
  140:                 if (isspace(c)) {
  141:                         while (isspace(*bp))
  142:                                 bp++;
  143: 
  144:                         fmt++;
  145:                         continue;
  146:                 }
  147:                                 
  148:                 if ((c = *fmt++) != '%')
  149:                         goto literal;
  150: 
  151: 
  152: again:          switch (c = *fmt++) {
  153:                 case '%':     /* "%%" is converted to "%". */
  154: literal:
  155:                 if (c != *bp++)
  156:                         return (NULL);
  157: 
  158:                 break;
  159: 
  160:                 /*
  161:                  * "Alternative" modifiers. Just set the appropriate flag
  162:                  * and start over again.
  163:                  */
  164:                 case 'E':     /* "%E?" alternative conversion modifier. */
  165:                         _LEGAL_ALT(0);
  166:                         alt_format |= _ALT_E;
  167:                         goto again;
  168: 
  169:                 case 'O':     /* "%O?" alternative conversion modifier. */
  170:                         _LEGAL_ALT(0);
  171:                         alt_format |= _ALT_O;
  172:                         goto again;
  173:                         
  174:                 /*
  175:                  * "Complex" conversion rules, implemented through recursion.
  176:                  */
  177:                 case 'c':     /* Date and time, using the locale's format. */
  178:                         _LEGAL_ALT(_ALT_E);
  179:                         if (!(bp = (unsigned char*)_strptime((char*)bp, _ctloc(d_t_fmt), tm, 0)))
  180:                                 return (NULL);
  181:                         break;
  182: 
  183:                 case 'D':     /* The date as "%m/%d/%y". */
  184:                         _LEGAL_ALT(0);
  185:                         if (!(bp = (unsigned char*)_strptime((char*)bp, "%m/%d/%y", tm, 0)))
  186:                                 return (NULL);
  187:                         break;
  188: 
  189:                 case 'F':     /* The date as "%Y-%m-%d". */
  190:                         _LEGAL_ALT(0);
  191:                         if (!(bp =(unsigned char*) _strptime((char*)bp, "%Y-%m-%d", tm, 0)))
  192:                                 return (NULL);
  193:                         continue;
  194: 
  195:                 case 'R':     /* The time as "%H:%M". */
  196:                         _LEGAL_ALT(0);
  197:                         if (!(bp = (unsigned char*)_strptime((char*)bp, "%H:%M", tm, 0)))
  198:                                 return (NULL);
  199:                         break;
  200: 
  201:                 case 'r':     /* The time as "%I:%M:%S %p". */
  202:                         _LEGAL_ALT(0);
  203:                         if (!(bp =(unsigned char*) _strptime((char*)bp, "%I:%M:%S %p", tm, 0)))
  204:                                 return (NULL);
  205:                         break;
  206: 
  207:                 case 'T':     /* The time as "%H:%M:%S". */
  208:                         _LEGAL_ALT(0);
  209:                         if (!(bp = (unsigned char*)_strptime((char*)bp, "%H:%M:%S", tm, 0)))
  210:                                 return (NULL);
  211:                         break;
  212: 
  213:                 case 'X':     /* The time, using the locale's format. */
  214:                         _LEGAL_ALT(_ALT_E);
  215:                         if (!(bp = (unsigned char*)_strptime((char*)bp, _ctloc(t_fmt), tm, 0)))
  216:                                 return (NULL);
  217:                         break;
  218: 
  219:                 case 'x':     /* The date, using the locale's format. */
  220:                         _LEGAL_ALT(_ALT_E);
  221:                         if (!(bp = (unsigned char*)_strptime((char*)bp, _ctloc(d_fmt), tm, 0)))
  222:                                 return (NULL);
  223:                         break;
  224: 
  225:                 /*
  226:                  * "Elementary" conversion rules.
  227:                  */
  228:                 case 'A':     /* The day of week, using the locale's form. */
  229:                 case 'a':
  230:                         _LEGAL_ALT(0);
  231:                         for (i = 0; i < 7; i++) {
  232:                                 /* Full name. */
  233:                                 len = strlen(_ctloc(day[i]));
  234:                                 if (strncasecmp(_ctloc(day[i]), (char*)bp, len) == 0)
  235:                                         break;
  236: 
  237:                                 /* Abbreviated name. */
  238:                                 len = strlen(_ctloc(abday[i]));
  239:                                 if (strncasecmp(_ctloc(abday[i]), (char*)bp, len) == 0)
  240:                                         break;
  241:                         }
  242: 
  243:                         /* Nothing matched. */
  244:                         if (i == 7)
  245:                                 return (NULL);
  246: 
  247:                         tm->tm_wday = i;
  248:                         bp += len;
  249:                         fields |= FIELD_TM_WDAY;
  250:                         break;
  251: 
  252:                 case 'B':     /* The month, using the locale's form. */
  253:                 case 'b':
  254:                 case 'h':
  255:                         _LEGAL_ALT(0);
  256:                         for (i = 0; i < 12; i++) {
  257:                                 /* Full name. */
  258:                                 len = strlen(_ctloc(mon[i]));
  259:                                 if (strncasecmp(_ctloc(mon[i]), (char*)bp, len) == 0)
  260:                                         break;
  261: 
  262:                                 /* Abbreviated name. */
  263:                                 len = strlen(_ctloc(abmon[i]));
  264:                                 if (strncasecmp(_ctloc(abmon[i]), (char*)bp, len) == 0)
  265:                                         break;
  266:                         }
  267: 
  268:                         /* Nothing matched. */
  269:                         if (i == 12)
  270:                                 return (NULL);
  271: 
  272:                         tm->tm_mon = i;
  273:                         bp += len;
  274:                         fields |= FIELD_TM_MON;
  275:                         break;
  276: 
  277:                 case 'C':     /* The century number. */
  278:                         _LEGAL_ALT(_ALT_E);
  279:                         if (!(_conv_num(&bp, &i, 0, 99)))
  280:                                 return (NULL);
  281: 
  282:                         century = i * 100;
  283:                         break;
  284: 
  285:                 case 'd':     /* The day of month. */
  286:                 case 'e':
  287:                         _LEGAL_ALT(_ALT_O);
  288:                         if (!(_conv_num(&bp, &tm->tm_mday, 1, 31)))
  289:                                 return (NULL);
  290:                         fields |= FIELD_TM_MDAY;
  291:                         break;
  292: 
  293:                 case 'k':     /* The hour (24-hour clock representation). */
  294:                         _LEGAL_ALT(0);
  295:                         /* FALLTHROUGH */
  296:                 case 'H':
  297:                         _LEGAL_ALT(_ALT_O);
  298:                         if (!(_conv_num(&bp, &tm->tm_hour, 0, 23)))
  299:                                 return (NULL);
  300:                         break;
  301: 
  302:                 case 'l':     /* The hour (12-hour clock representation). */
  303:                         _LEGAL_ALT(0);
  304:                         /* FALLTHROUGH */
  305:                 case 'I':
  306:                         _LEGAL_ALT(_ALT_O);
  307:                         if (!(_conv_num(&bp, &tm->tm_hour, 1, 12)))
  308:                                 return (NULL);
  309:                         break;
  310: 
  311:                 case 'j':     /* The day of year. */
  312:                         _LEGAL_ALT(0);
  313:                         if (!(_conv_num(&bp, &tm->tm_yday, 1, 366)))
  314:                                 return (NULL);
  315:                         tm->tm_yday--;
  316:                         fields |= FIELD_TM_YDAY;
  317:                         break;
  318: 
  319:                 case 'M':     /* The minute. */
  320:                         _LEGAL_ALT(_ALT_O);
  321:                         if (!(_conv_num(&bp, &tm->tm_min, 0, 59)))
  322:                                 return (NULL);
  323:                         break;
  324: 
  325:                 case 'm':     /* The month. */
  326:                         _LEGAL_ALT(_ALT_O);
  327:                         if (!(_conv_num(&bp, &tm->tm_mon, 1, 12)))
  328:                                 return (NULL);
  329:                         tm->tm_mon--;
  330:                         fields |= FIELD_TM_MON;
  331:                         break;
  332: 
  333:                 case 'p':     /* The locale's equivalent of AM/PM. */
  334:                         _LEGAL_ALT(0);
  335:                         /* AM? */
  336:                         len = strlen(_ctloc(am_pm[0]));
  337:                         if (strncasecmp(_ctloc(am_pm[0]), (char*)bp, len) == 0) {
  338:                                 if (tm->tm_hour > 12)       /* i.e., 13:00 AM ?! */
  339:                                         return (NULL);
  340:                                 else if (tm->tm_hour == 12)
  341:                                         tm->tm_hour = 0;
  342: 
  343:                                 bp += len;
  344:                                 break;
  345:                         }
  346:                         /* PM? */
  347:                         len = strlen(_ctloc(am_pm[1]));
  348:                         if (strncasecmp(_ctloc(am_pm[1]), (char*)bp, len) == 0) {
  349:                                 if (tm->tm_hour > 12)       /* i.e., 13:00 PM ?! */
  350:                                         return (NULL);
  351:                                 else if (tm->tm_hour < 12)
  352:                                         tm->tm_hour += 12;
  353: 
  354:                                 bp += len;
  355:                                 break;
  356:                         }
  357: 
  358:                         /* Nothing matched. */
  359:                         return (NULL);
  360: 
  361:                 case 'S':     /* The seconds. */
  362:                         _LEGAL_ALT(_ALT_O);
  363:                         if (!(_conv_num(&bp, &tm->tm_sec, 0, 61)))
  364:                                 return (NULL);
  365:                         break;
  366: 
  367:                 case 'U':     /* The week of year, beginning on sunday. */
  368:                 case 'W':     /* The week of year, beginning on monday. */
  369:                         _LEGAL_ALT(_ALT_O);
  370:                         /*
  371:                          * XXX This is bogus, as we can not assume any valid
  372:                          * information present in the tm structure at this
  373:                          * point to calculate a real value, so just check the
  374:                          * range for now.
  375:                          */
  376:                          if (!(_conv_num(&bp, &i, 0, 53)))
  377:                                 return (NULL);
  378:                          break;
  379: 
  380:                 case 'w':     /* The day of week, beginning on sunday. */
  381:                         _LEGAL_ALT(_ALT_O);
  382:                         if (!(_conv_num(&bp, &tm->tm_wday, 0, 6)))
  383:                                 return (NULL);
  384:                         fields |= FIELD_TM_WDAY;
  385:                         break;
  386: 
  387:                 case 'u':     /* The day of week, monday = 1. */
  388:                         _LEGAL_ALT(_ALT_O);
  389:                         if (!(_conv_num(&bp, &i, 1, 7)))
  390:                                 return (NULL);
  391:                         tm->tm_wday = i % 7;
  392:                         fields |= FIELD_TM_WDAY;
  393:                         continue;
  394: 
  395:                 case 'g':     /* The year corresponding to the ISO week
  396:                                  * number but without the century.
  397:                                  */
  398:                         if (!(_conv_num(&bp, &i, 0, 99)))
  399:                                 return (NULL);                              
  400:                         continue;
  401: 
  402:                 case 'G':     /* The year corresponding to the ISO week
  403:                                  * number with century.
  404:                                  */
  405:                         do
  406:                                 bp++;
  407:                         while (isdigit(*bp));
  408:                         continue;
  409: 
  410:                 case 'V':     /* The ISO 8601:1988 week number as decimal */
  411:                         if (!(_conv_num(&bp, &i, 0, 53)))
  412:                                 return (NULL);
  413:                         continue;
  414: 
  415:                 case 'Y':     /* The year. */
  416:                         _LEGAL_ALT(_ALT_E);
  417:                         if (!(_conv_num(&bp, &i, 0, 9999)))
  418:                                 return (NULL);
  419: 
  420:                         relyear = -1;
  421: #if     1           /*** Modified on T2EX ***/
  422:                         century = -1;
  423: #endif
  424:                         tm->tm_year = i - TM_YEAR_BASE;
  425:                         fields |= FIELD_TM_YEAR;
  426:                         break;
  427: 
  428:                 case 'y':     /* The year within the century (2 digits). */
  429:                         _LEGAL_ALT(_ALT_E | _ALT_O);
  430:                         if (!(_conv_num(&bp, &relyear, 0, 99)))
  431:                                 return (NULL);
  432:                         break;
  433: 
  434:                 case 'Z':
  435:                         //tzset();
  436:                         if (/*strncmp((const char *)bp, gmt, 3) == 0*/isupper(bp[0])&&isupper(bp[1])&&isupper(bp[2])) {
  437:                                 tm->tm_isdst = 0;
  438: #ifdef TM_GMTOFF
  439:                                 tm->TM_GMTOFF = 0;
  440: #endif
  441: #ifdef TM_ZONE
  442:                                 tm->TM_ZONE = gmt;
  443: #endif
  444:                                 bp += 3;
  445:                         } else {
  446:                                 ep = /*_find_string(bp, &i,
  447:                                                     (const char * const *)tzname,
  448:                                                      NULL, 2)*/NULL;
  449:                                 if (ep != NULL) {
  450:                                         tm->tm_isdst = i;
  451: #ifdef TM_GMTOFF
  452:                                         tm->TM_GMTOFF = -(timezone);
  453: #endif
  454: #ifdef TM_ZONE
  455:                                         tm->TM_ZONE = tzname[i];
  456: #endif
  457:                                 }
  458:                                 bp = ep;
  459:                         }
  460:                         continue;
  461: 
  462:                 case 'z':
  463:                         /*
  464:                          * We recognize all ISO 8601 formats:
  465:                          * Z = Zulu time/UTC
  466:                          * [+-]hhmm
  467:                          * [+-]hh:mm
  468:                          * [+-]hh
  469:                          * We recognize all RFC-822/RFC-2822 formats:
  470:                          * UT|GMT
  471:                          *          North American : UTC offsets
  472:                          * E[DS]T = Eastern : -4 | -5
  473:                          * C[DS]T = Central : -5 | -6
  474:                          * M[DS]T = Mountain: -6 | -7
  475:                          * P[DS]T = Pacific : -7 | -8
  476:                          *          Military
  477:                          * [A-IL-M] = -1 ... -9 (J not used)
  478:                          * [N-Y]  = +1 ... +12
  479:                          */
  480:                         while (isspace(*bp))
  481:                                 bp++;
  482: 
  483:                         switch (*bp++) {
  484:                         case 'G':
  485:                                 if (*bp++ != 'M')
  486:                                         return NULL;
  487:                                 /*FALLTHROUGH*/
  488:                         case 'U':
  489:                                 if (*bp++ != 'T')
  490:                                         return NULL;
  491:                                 /*FALLTHROUGH*/
  492:                         case 'Z':
  493:                                 tm->tm_isdst = 0;
  494: #ifdef TM_GMTOFF
  495:                                 tm->TM_GMTOFF = 0;
  496: #endif
  497: #ifdef TM_ZONE
  498:                                 tm->TM_ZONE = utc;
  499: #endif
  500:                                 continue;
  501:                         case '+':
  502:                                 neg = 0;
  503:                                 break;
  504:                         case '-':
  505:                                 neg = 1;
  506:                                 break;
  507:                         default:
  508:                                 --bp;
  509:                                 ep = _find_string(bp, &i, nast, NULL, 4);
  510:                                 if (ep != NULL) {
  511: #ifdef TM_GMTOFF
  512:                                         tm->TM_GMTOFF = -5 - i;
  513: #endif
  514: #ifdef TM_ZONE
  515:                                         tm->TM_ZONE = __UNCONST(nast[i]);
  516: #endif
  517:                                         bp = ep;
  518:                                         continue;
  519:                                 }
  520:                                 ep = _find_string(bp, &i, nadt, NULL, 4);
  521:                                 if (ep != NULL) {
  522:                                         tm->tm_isdst = 1;
  523: #ifdef TM_GMTOFF
  524:                                         tm->TM_GMTOFF = -4 - i;
  525: #endif
  526: #ifdef TM_ZONE
  527:                                         tm->TM_ZONE = __UNCONST(nadt[i]);
  528: #endif
  529:                                         bp = ep;
  530:                                         continue;
  531:                                 }
  532: 
  533:                                 if ((*bp >= 'A' && *bp <= 'I') ||
  534:                                     (*bp >= 'L' && *bp <= 'Y')) {
  535: #ifdef TM_GMTOFF
  536:                                         /* Argh! No 'J'! */
  537:                                         if (*bp >= 'A' && *bp <= 'I')
  538:                                                 tm->TM_GMTOFF =
  539:                                                     ('A' - 1) - (int)*bp;
  540:                                         else if (*bp >= 'L' && *bp <= 'M')
  541:                                                 tm->TM_GMTOFF = 'A' - (int)*bp;
  542:                                         else if (*bp >= 'N' && *bp <= 'Y')
  543:                                                 tm->TM_GMTOFF = (int)*bp - 'M';
  544: #endif
  545: #ifdef TM_ZONE
  546:                                         tm->TM_ZONE = NULL; /* XXX */
  547: #endif
  548:                                         bp++;
  549:                                         continue;
  550:                                 }
  551:                                 return NULL;
  552:                         }
  553:                         offs = 0;
  554:                         for (i = 0; i < 4; ) {
  555:                                 if (isdigit(*bp)) {
  556:                                         offs = offs * 10 + (*bp++ - '0');
  557:                                         i++;
  558:                                         continue;
  559:                                 }
  560:                                 if (i == 2 && *bp == ':') {
  561:                                         bp++;
  562:                                         continue;
  563:                                 }
  564:                                 break;
  565:                         }
  566:                         switch (i) {
  567:                         case 2:
  568:                                 offs *= 100;
  569:                                 break;
  570:                         case 4:
  571:                                 i = offs % 100;
  572:                                 if (i >= 60)
  573:                                         return NULL;
  574:                                 /* Convert minutes into decimal */
  575:                                 offs = (offs / 100) * 100 + (i * 50) / 30;
  576:                                 break;
  577:                         default:
  578:                                 return NULL;
  579:                         }
  580:                         if (neg)
  581:                                 offs = -offs;
  582:                         tm->tm_isdst = 0;    /* XXX */
  583: #ifdef TM_GMTOFF
  584:                         tm->TM_GMTOFF = offs;
  585: #endif
  586: #ifdef TM_ZONE
  587:                         tm->TM_ZONE = NULL;  /* XXX */
  588: #endif
  589:                         continue;
  590: 
  591:                 /*
  592:                  * Miscellaneous conversions.
  593:                  */
  594:                 case 'n':     /* Any kind of white-space. */
  595:                 case 't':
  596:                         _LEGAL_ALT(0);
  597:                         while (isspace(*bp))
  598:                                 bp++;
  599:                         break;
  600: 
  601: 
  602:                 default:      /* Unknown/unsupported conversion. */
  603:                         return (NULL);
  604:                 }
  605: 
  606: 
  607:         }
  608: 
  609:         /*
  610:          * We need to evaluate the two digit year spec (%y)
  611:          * last as we can get a century spec (%C) at any time.
  612:          */
  613: #if     1   /*** Modified on T2EX ***/
  614:         if (relyear != -1) {
  615:                 if (century == -1 || century == TM_YEAR_BASE) {
  616:                         if (relyear <= 68)
  617:                                 tm->tm_year = relyear + 2000 - TM_YEAR_BASE;
  618:                         else
  619:                                 tm->tm_year = relyear + 1900 - TM_YEAR_BASE;
  620:                 } else {
  621:                         tm->tm_year = relyear + century - TM_YEAR_BASE;
  622:                 }
  623:                 fields |= FIELD_TM_YEAR;
  624:         } else if (century != -1) {
  625:                 if ((fields & FIELD_TM_YEAR) == 0)    tm->tm_year = 0;
  626:                 else  tm->tm_year %= 100;              /* case of %Y %C */
  627:                 tm->tm_year += century - TM_YEAR_BASE;
  628:                 fields |= FIELD_TM_YEAR;
  629:         }
  630: #else
  631:         if (relyear != -1) {
  632:                 if (century == TM_YEAR_BASE) {
  633:                         if (relyear <= 68)
  634:                                 tm->tm_year = relyear + 2000 - TM_YEAR_BASE;
  635:                         else
  636:                                 tm->tm_year = relyear + 1900 - TM_YEAR_BASE;
  637:                 } else {
  638:                         tm->tm_year = relyear + century - TM_YEAR_BASE;
  639:                 }
  640:                 fields |= FIELD_TM_YEAR;
  641:         }
  642: #endif
  643: 
  644:         /* Compute some missing values when possible. */
  645:         if (fields & FIELD_TM_YEAR) {
  646:                 const int year = tm->tm_year + TM_YEAR_BASE;
  647:                 const int *mon_lens = mon_lengths[isleap(year)];
  648:                 if (!(fields & FIELD_TM_YDAY) &&
  649:                     (fields & (FIELD_TM_MON|FIELD_TM_MDAY))) {
  650:                         tm->tm_yday = tm->tm_mday - 1;
  651:                         for (i = 0; i < tm->tm_mon; i++)
  652:                                 tm->tm_yday += mon_lens[i];
  653:                         fields |= FIELD_TM_YDAY;
  654:                 }
  655:                 if (fields & FIELD_TM_YDAY) {
  656:                         int days = tm->tm_yday;
  657:                         if (!(fields & FIELD_TM_WDAY)) {
  658:                                 tm->tm_wday = EPOCH_WDAY +
  659:                                     ((year - EPOCH_YEAR) % DAYSPERWEEK) *
  660:                                     (DAYSPERNYEAR % DAYSPERWEEK) +
  661:                                     leaps_thru_end_of(year - 1) -
  662:                                     leaps_thru_end_of(EPOCH_YEAR - 1) +
  663:                                     tm->tm_yday;
  664:                                 tm->tm_wday %= DAYSPERWEEK;
  665:                                 if (tm->tm_wday < 0)
  666:                                         tm->tm_wday += DAYSPERWEEK;
  667:                         }
  668:                         if (!(fields & FIELD_TM_MON)) {
  669:                                 tm->tm_mon = 0;
  670:                                 while (tm->tm_mon < MONSPERYEAR && days >= mon_lens[tm->tm_mon])
  671:                                         days -= mon_lens[tm->tm_mon++];
  672:                         }
  673:                         if (!(fields & FIELD_TM_MDAY))
  674:                                 tm->tm_mday = days + 1;
  675:                 }
  676:         }
  677: 
  678:         return ((char *)bp);
  679: }
  680: 
  681: 
  682: static int
  683: _conv_num(const unsigned char **buf, int *dest, int llim, int ulim)
  684: {
  685:         int result = 0;
  686:         int rulim = ulim;
  687: 
  688:         if (**buf < '0' || **buf > '9')
  689:                 return (0);
  690: 
  691:         /* we use rulim to break out of the loop when we run out of digits */
  692:         do {
  693:                 result *= 10;
  694:                 result += *(*buf)++ - '0';
  695:                 rulim /= 10;
  696:         } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
  697: 
  698:         if (result < llim || result > ulim)
  699:                 return (0);
  700: 
  701:         *dest = result;
  702:         return (1);
  703: }
  704: 
  705: static const unsigned char *
  706: _find_string(const unsigned char *bp, int *tgt, const char * const *n1,
  707:                 const char * const *n2, int c)
  708: {
  709:         int i;
  710:         unsigned int len;
  711: 
  712:         /* check full name - then abbreviated ones */
  713:         for (; n1 != NULL; n1 = n2, n2 = NULL) {
  714:                 for (i = 0; i < c; i++, n1++) {
  715:                         len = strlen(*n1);
  716:                         if (strncasecmp(*n1, (const char *)bp, len) == 0) {
  717:                                 *tgt = i;
  718:                                 return bp + len;
  719:                         }
  720:                 }
  721:         }
  722: 
  723:         /* Nothing matched */
  724:         return NULL;
  725: }
  726: 
  727: static int              
  728: leaps_thru_end_of(const int y)
  729: {
  730:         return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
  731:                 -(leaps_thru_end_of(-(y + 1)) + 1);
  732: }