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

Annotation of src/lib/libc/time/strptime.c, Revision 1.28

1.28    ! martin      1: /*     $NetBSD: strptime.c,v 1.27 2008/04/25 20:51:10 ginsbach Exp $   */
1.1       mrg         2:
1.3       kleink      3: /*-
1.27      ginsbach    4:  * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
1.3       kleink      5:  * All rights reserved.
                      6:  *
                      7:  * This code was contributed to The NetBSD Foundation by Klaus Klein.
1.24      dsl         8:  * Heavily optimised by David Laight
1.1       mrg         9:  *
1.3       kleink     10:  * Redistribution and use in source and binary forms, with or without
1.1       mrg        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
1.3       kleink     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
1.1       mrg        18:  *
1.3       kleink     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
1.1       mrg        24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1.3       kleink     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.
1.1       mrg        30:  */
                     31:
1.6       christos   32: #include <sys/cdefs.h>
1.3       kleink     33: #if defined(LIBC_SCCS) && !defined(lint)
1.28    ! martin     34: __RCSID("$NetBSD: strptime.c,v 1.27 2008/04/25 20:51:10 ginsbach Exp $");
1.1       mrg        35: #endif
                     36:
1.7       jtc        37: #include "namespace.h"
1.3       kleink     38: #include <sys/localedef.h>
                     39: #include <ctype.h>
1.1       mrg        40: #include <locale.h>
1.3       kleink     41: #include <string.h>
1.1       mrg        42: #include <time.h>
1.12      mycroft    43: #include <tzfile.h>
1.7       jtc        44:
                     45: #ifdef __weak_alias
1.19      mycroft    46: __weak_alias(strptime,_strptime)
1.7       jtc        47: #endif
1.3       kleink     48:
1.21      cgd        49: #define        _ctloc(x)               (_CurrentTimeLocale->x)
1.3       kleink     50:
                     51: /*
                     52:  * We do not implement alternate representations. However, we always
                     53:  * check whether a given modifier is allowed for a certain conversion.
                     54:  */
1.16      kleink     55: #define ALT_E                  0x01
                     56: #define ALT_O                  0x02
1.24      dsl        57: #define        LEGAL_ALT(x)            { if (alt_format & ~(x)) return NULL; }
1.3       kleink     58:
1.26      ginsbach   59: static const char gmt[4] = { "GMT" };
1.3       kleink     60:
1.24      dsl        61: static const u_char *conv_num(const unsigned char *, int *, uint, uint);
1.23      dsl        62: static const u_char *find_string(const u_char *, int *, const char * const *,
                     63:        const char * const *, int);
1.3       kleink     64:
1.1       mrg        65:
1.2       kleink     66: char *
1.23      dsl        67: strptime(const char *buf, const char *fmt, struct tm *tm)
1.1       mrg        68: {
1.20      itohy      69:        unsigned char c;
                     70:        const unsigned char *bp;
1.16      kleink     71:        int alt_format, i, split_year = 0;
1.23      dsl        72:        const char *new_fmt;
1.3       kleink     73:
1.22      christos   74:        bp = (const u_char *)buf;
1.3       kleink     75:
1.24      dsl        76:        while (bp != NULL && (c = *fmt++) != '\0') {
1.3       kleink     77:                /* Clear `alternate' modifier prior to new conversion. */
                     78:                alt_format = 0;
1.23      dsl        79:                i = 0;
1.3       kleink     80:
                     81:                /* Eat up white-space. */
                     82:                if (isspace(c)) {
                     83:                        while (isspace(*bp))
                     84:                                bp++;
1.2       kleink     85:                        continue;
                     86:                }
1.23      dsl        87:
1.24      dsl        88:                if (c != '%')
1.3       kleink     89:                        goto literal;
                     90:
                     91:
                     92: again:         switch (c = *fmt++) {
                     93:                case '%':       /* "%%" is converted to "%". */
                     94: literal:
1.14      tv         95:                        if (c != *bp++)
1.24      dsl        96:                                return NULL;
1.23      dsl        97:                        LEGAL_ALT(0);
                     98:                        continue;
1.3       kleink     99:
                    100:                /*
                    101:                 * "Alternative" modifiers. Just set the appropriate flag
                    102:                 * and start over again.
                    103:                 */
                    104:                case 'E':       /* "%E?" alternative conversion modifier. */
1.16      kleink    105:                        LEGAL_ALT(0);
                    106:                        alt_format |= ALT_E;
1.3       kleink    107:                        goto again;
                    108:
                    109:                case 'O':       /* "%O?" alternative conversion modifier. */
1.16      kleink    110:                        LEGAL_ALT(0);
                    111:                        alt_format |= ALT_O;
1.3       kleink    112:                        goto again;
1.23      dsl       113:
1.3       kleink    114:                /*
                    115:                 * "Complex" conversion rules, implemented through recursion.
                    116:                 */
                    117:                case 'c':       /* Date and time, using the locale's format. */
1.23      dsl       118:                        new_fmt = _ctloc(d_t_fmt);
                    119:                        goto recurse;
1.3       kleink    120:
                    121:                case 'D':       /* The date as "%m/%d/%y". */
1.23      dsl       122:                        new_fmt = "%m/%d/%y";
1.16      kleink    123:                        LEGAL_ALT(0);
1.23      dsl       124:                        goto recurse;
1.18      tv        125:
1.27      ginsbach  126:                case 'F':       /* The date as "%Y-%m-%d". */
                    127:                        new_fmt = "%Y-%m-%d";
                    128:                        LEGAL_ALT(0);
                    129:                        goto recurse;
                    130:
1.3       kleink    131:                case 'R':       /* The time as "%H:%M". */
1.23      dsl       132:                        new_fmt = "%H:%M";
1.16      kleink    133:                        LEGAL_ALT(0);
1.23      dsl       134:                        goto recurse;
1.3       kleink    135:
                    136:                case 'r':       /* The time in 12-hour clock representation. */
1.23      dsl       137:                        new_fmt =_ctloc(t_fmt_ampm);
1.16      kleink    138:                        LEGAL_ALT(0);
1.23      dsl       139:                        goto recurse;
1.3       kleink    140:
                    141:                case 'T':       /* The time as "%H:%M:%S". */
1.23      dsl       142:                        new_fmt = "%H:%M:%S";
1.16      kleink    143:                        LEGAL_ALT(0);
1.23      dsl       144:                        goto recurse;
1.3       kleink    145:
                    146:                case 'X':       /* The time, using the locale's format. */
1.23      dsl       147:                        new_fmt =_ctloc(t_fmt);
                    148:                        goto recurse;
1.3       kleink    149:
                    150:                case 'x':       /* The date, using the locale's format. */
1.23      dsl       151:                        new_fmt =_ctloc(d_fmt);
                    152:                    recurse:
                    153:                        bp = (const u_char *)strptime((const char *)bp,
                    154:                                                            new_fmt, tm);
1.16      kleink    155:                        LEGAL_ALT(ALT_E);
1.23      dsl       156:                        continue;
1.3       kleink    157:
                    158:                /*
                    159:                 * "Elementary" conversion rules.
                    160:                 */
                    161:                case 'A':       /* The day of week, using the locale's form. */
                    162:                case 'a':
1.23      dsl       163:                        bp = find_string(bp, &tm->tm_wday, _ctloc(day),
                    164:                                        _ctloc(abday), 7);
1.16      kleink    165:                        LEGAL_ALT(0);
1.23      dsl       166:                        continue;
1.2       kleink    167:
1.3       kleink    168:                case 'B':       /* The month, using the locale's form. */
                    169:                case 'b':
                    170:                case 'h':
1.23      dsl       171:                        bp = find_string(bp, &tm->tm_mon, _ctloc(mon),
                    172:                                        _ctloc(abmon), 12);
1.16      kleink    173:                        LEGAL_ALT(0);
1.23      dsl       174:                        continue;
1.2       kleink    175:
1.3       kleink    176:                case 'C':       /* The century number. */
1.24      dsl       177:                        i = 20;
1.23      dsl       178:                        bp = conv_num(bp, &i, 0, 99);
1.2       kleink    179:
1.24      dsl       180:                        i = i * 100 - TM_YEAR_BASE;
                    181:                        if (split_year)
                    182:                                i += tm->tm_year % 100;
                    183:                        split_year = 1;
                    184:                        tm->tm_year = i;
1.23      dsl       185:                        LEGAL_ALT(ALT_E);
                    186:                        continue;
1.2       kleink    187:
1.3       kleink    188:                case 'd':       /* The day of month. */
                    189:                case 'e':
1.23      dsl       190:                        bp = conv_num(bp, &tm->tm_mday, 1, 31);
1.16      kleink    191:                        LEGAL_ALT(ALT_O);
1.23      dsl       192:                        continue;
1.2       kleink    193:
1.3       kleink    194:                case 'k':       /* The hour (24-hour clock representation). */
1.16      kleink    195:                        LEGAL_ALT(0);
1.3       kleink    196:                        /* FALLTHROUGH */
                    197:                case 'H':
1.23      dsl       198:                        bp = conv_num(bp, &tm->tm_hour, 0, 23);
1.16      kleink    199:                        LEGAL_ALT(ALT_O);
1.23      dsl       200:                        continue;
1.2       kleink    201:
1.3       kleink    202:                case 'l':       /* The hour (12-hour clock representation). */
1.16      kleink    203:                        LEGAL_ALT(0);
1.3       kleink    204:                        /* FALLTHROUGH */
                    205:                case 'I':
1.23      dsl       206:                        bp = conv_num(bp, &tm->tm_hour, 1, 12);
1.13      tv        207:                        if (tm->tm_hour == 12)
                    208:                                tm->tm_hour = 0;
1.23      dsl       209:                        LEGAL_ALT(ALT_O);
                    210:                        continue;
1.2       kleink    211:
1.3       kleink    212:                case 'j':       /* The day of year. */
1.23      dsl       213:                        i = 1;
                    214:                        bp = conv_num(bp, &i, 1, 366);
                    215:                        tm->tm_yday = i - 1;
1.16      kleink    216:                        LEGAL_ALT(0);
1.23      dsl       217:                        continue;
1.2       kleink    218:
1.3       kleink    219:                case 'M':       /* The minute. */
1.23      dsl       220:                        bp = conv_num(bp, &tm->tm_min, 0, 59);
1.16      kleink    221:                        LEGAL_ALT(ALT_O);
1.23      dsl       222:                        continue;
1.2       kleink    223:
1.3       kleink    224:                case 'm':       /* The month. */
1.23      dsl       225:                        i = 1;
                    226:                        bp = conv_num(bp, &i, 1, 12);
                    227:                        tm->tm_mon = i - 1;
1.16      kleink    228:                        LEGAL_ALT(ALT_O);
1.23      dsl       229:                        continue;
1.2       kleink    230:
1.3       kleink    231:                case 'p':       /* The locale's equivalent of AM/PM. */
1.24      dsl       232:                        bp = find_string(bp, &i, _ctloc(am_pm), NULL, 2);
1.23      dsl       233:                        if (tm->tm_hour > 11)
1.24      dsl       234:                                return NULL;
1.23      dsl       235:                        tm->tm_hour += i * 12;
1.16      kleink    236:                        LEGAL_ALT(0);
1.23      dsl       237:                        continue;
1.2       kleink    238:
1.3       kleink    239:                case 'S':       /* The seconds. */
1.23      dsl       240:                        bp = conv_num(bp, &tm->tm_sec, 0, 61);
1.16      kleink    241:                        LEGAL_ALT(ALT_O);
1.23      dsl       242:                        continue;
1.1       mrg       243:
1.3       kleink    244:                case 'U':       /* The week of year, beginning on sunday. */
                    245:                case 'W':       /* The week of year, beginning on monday. */
                    246:                        /*
                    247:                         * XXX This is bogus, as we can not assume any valid
                    248:                         * information present in the tm structure at this
                    249:                         * point to calculate a real value, so just check the
                    250:                         * range for now.
                    251:                         */
1.23      dsl       252:                         bp = conv_num(bp, &i, 0, 53);
                    253:                         LEGAL_ALT(ALT_O);
                    254:                         continue;
1.2       kleink    255:
1.3       kleink    256:                case 'w':       /* The day of week, beginning on sunday. */
1.23      dsl       257:                        bp = conv_num(bp, &tm->tm_wday, 0, 6);
1.16      kleink    258:                        LEGAL_ALT(ALT_O);
1.23      dsl       259:                        continue;
1.2       kleink    260:
1.3       kleink    261:                case 'Y':       /* The year. */
1.24      dsl       262:                        i = TM_YEAR_BASE;       /* just for data sanity... */
1.23      dsl       263:                        bp = conv_num(bp, &i, 0, 9999);
1.8       mycroft   264:                        tm->tm_year = i - TM_YEAR_BASE;
1.23      dsl       265:                        LEGAL_ALT(ALT_E);
                    266:                        continue;
1.2       kleink    267:
1.9       mycroft   268:                case 'y':       /* The year within 100 years of the epoch. */
1.24      dsl       269:                        /* LEGAL_ALT(ALT_E | ALT_O); */
1.23      dsl       270:                        bp = conv_num(bp, &i, 0, 99);
1.8       mycroft   271:
1.24      dsl       272:                        if (split_year)
                    273:                                /* preserve century */
                    274:                                i += (tm->tm_year / 100) * 100;
                    275:                        else {
                    276:                                split_year = 1;
                    277:                                if (i <= 68)
                    278:                                        i = i + 2000 - TM_YEAR_BASE;
                    279:                                else
                    280:                                        i = i + 1900 - TM_YEAR_BASE;
1.13      tv        281:                        }
1.24      dsl       282:                        tm->tm_year = i;
1.23      dsl       283:                        continue;
1.2       kleink    284:
1.26      ginsbach  285:                case 'Z':
                    286:                        tzset();
                    287:                        if (strncmp((const char *)bp, gmt, 3) == 0) {
                    288:                                tm->tm_isdst = 0;
                    289: #ifdef TM_GMTOFF
                    290:                                tm->TM_GMTOFF = 0;
                    291: #endif
                    292: #ifdef TM_ZONE
                    293:                                tm->TM_ZONE = gmt;
                    294: #endif
                    295:                                bp += 3;
                    296:                        } else {
                    297:                                const unsigned char *ep;
                    298:
                    299:                                ep = find_string(bp, &i,
                    300:                                                 (const char * const *)tzname,
                    301:                                                  NULL, 2);
                    302:                                if (ep != NULL) {
                    303:                                        tm->tm_isdst = i;
                    304: #ifdef TM_GMTOFF
                    305:                                        tm->TM_GMTOFF = -(timezone);
                    306: #endif
                    307: #ifdef TM_ZONE
                    308:                                        tm->TM_ZONE = tzname[i];
                    309: #endif
                    310:                                }
                    311:                                bp = ep;
                    312:                        }
                    313:                        continue;
                    314:
1.3       kleink    315:                /*
                    316:                 * Miscellaneous conversions.
                    317:                 */
                    318:                case 'n':       /* Any kind of white-space. */
                    319:                case 't':
                    320:                        while (isspace(*bp))
                    321:                                bp++;
1.23      dsl       322:                        LEGAL_ALT(0);
                    323:                        continue;
1.2       kleink    324:
1.1       mrg       325:
1.3       kleink    326:                default:        /* Unknown/unsupported conversion. */
1.24      dsl       327:                        return NULL;
1.3       kleink    328:                }
                    329:        }
1.2       kleink    330:
1.25      christos  331:        return __UNCONST(bp);
1.3       kleink    332: }
1.2       kleink    333:
                    334:
1.23      dsl       335: static const u_char *
1.24      dsl       336: conv_num(const unsigned char *buf, int *dest, uint llim, uint ulim)
1.3       kleink    337: {
1.24      dsl       338:        uint result = 0;
1.23      dsl       339:        unsigned char ch;
1.18      tv        340:
                    341:        /* The limit also determines the number of valid digits. */
1.24      dsl       342:        uint rulim = ulim;
1.2       kleink    343:
1.23      dsl       344:        ch = *buf;
                    345:        if (ch < '0' || ch > '9')
1.24      dsl       346:                return NULL;
1.2       kleink    347:
1.3       kleink    348:        do {
1.18      tv        349:                result *= 10;
1.23      dsl       350:                result += ch - '0';
1.18      tv        351:                rulim /= 10;
1.23      dsl       352:                ch = *++buf;
                    353:        } while ((result * 10 <= ulim) && rulim && ch >= '0' && ch <= '9');
1.2       kleink    354:
1.18      tv        355:        if (result < llim || result > ulim)
1.24      dsl       356:                return NULL;
1.1       mrg       357:
1.18      tv        358:        *dest = result;
1.23      dsl       359:        return buf;
                    360: }
                    361:
                    362: static const u_char *
                    363: find_string(const u_char *bp, int *tgt, const char * const *n1,
                    364:                const char * const *n2, int c)
                    365: {
                    366:        int i;
                    367:        unsigned int len;
                    368:
1.24      dsl       369:        /* check full name - then abbreviated ones */
                    370:        for (; n1 != NULL; n1 = n2, n2 = NULL) {
                    371:                for (i = 0; i < c; i++, n1++) {
                    372:                        len = strlen(*n1);
                    373:                        if (strncasecmp(*n1, (const char *)bp, len) == 0) {
                    374:                                *tgt = i;
                    375:                                return bp + len;
                    376:                        }
                    377:                }
1.23      dsl       378:        }
1.24      dsl       379:
                    380:        /* Nothing matched */
                    381:        return NULL;
1.1       mrg       382: }

CVSweb <webmaster@jp.NetBSD.org>