Annotation of embedaddon/trafshow/strftime.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (c) 1989, 1993
                      3:  *     The Regents of the University of California.  All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  * 3. All advertising materials mentioning features or use of this software
                     14:  *    must display the following acknowledgement:
                     15:  *     This product includes software developed by the University of
                     16:  *     California, Berkeley and its contributors.
                     17:  * 4. Neither the name of the University nor the names of its contributors
                     18:  *    may be used to endorse or promote products derived from this software
                     19:  *    without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     31:  * SUCH DAMAGE.
                     32:  */
                     33: 
                     34: #if defined(LIBC_SCCS) && !defined(lint)
                     35: static char sccsid[] = "@(#)strftime.c 8.1 (Berkeley) 6/4/93";
                     36: #endif /* LIBC_SCCS and not lint */
                     37: 
                     38: #include <sys/types.h>
                     39: #include <sys/time.h>
                     40: #include <tzfile.h>
                     41: #include <limits.h>
                     42: #include <stdio.h>
                     43: 
                     44: /*
                     45: ** 302 / 1000 is log10(2.0) rounded up.
                     46: ** Subtract one for the sign bit;
                     47: ** add one for integer division truncation;
                     48: ** add one more for a minus sign.
                     49: */
                     50: #define INT_STRLEN_MAXIMUM(type) \
                     51:        ((sizeof(type) * CHAR_BIT - 1) * 302 / 1000 + 2)
                     52: 
                     53: /*
                     54: ** Based on elsieid[] = "@(#)strftime.c        7.15"
                     55: **
                     56: ** This is ANSIish only when time is treated identically in all locales and
                     57: ** when "multibyte character == plain character".
                     58: */
                     59: 
                     60: static const char afmt[][4] = {
                     61:        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
                     62: };
                     63: static const char Afmt[][10] = {
                     64:        "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
                     65:        "Saturday"
                     66: };
                     67: static const char bfmt[][4] = {
                     68:        "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
                     69:        "Oct", "Nov", "Dec"
                     70: };
                     71: static const char Bfmt[][10] = {
                     72:        "January", "February", "March", "April", "May", "June", "July",
                     73:        "August", "September", "October", "November", "December"
                     74: };
                     75: 
                     76: static char *_add __P((const char *, char *, const char *));
                     77: static char *_conv __P((int, const char *, char *, const char *));
                     78: static char *_secs __P((const struct tm *, char *, const char *));
                     79: static char *_fmt __P((const char *, const struct tm *, char *, const char *));
                     80: 
                     81: extern char *tzname[];
                     82: 
                     83: size_t
                     84: strftime(s, maxsize, format, t)
                     85:        char *s;
                     86:        size_t maxsize;
                     87:        const char *format;
                     88:        const struct tm *t;
                     89: {
                     90:        char *p;
                     91: 
                     92:        p = _fmt(format, t, s, s + maxsize);
                     93:        if (p == s + maxsize)
                     94:                return (0);
                     95:        *p = '\0';
                     96:        return (p - s);
                     97: }
                     98: 
                     99: static char *
                    100: _fmt(format, t, pt, ptlim)
                    101:        const char *format;
                    102:        const struct tm *t;
                    103:        char *pt;
                    104:        const char *ptlim;
                    105: {
                    106:        for (; *format; ++format) {
                    107:                if (*format == '%') {
                    108: label:
                    109:                        switch(*++format) {
                    110:                        case '\0':
                    111:                                --format;
                    112:                                break;
                    113:                        case 'A':
                    114:                                pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
                    115:                                        "?" : Afmt[t->tm_wday], pt, ptlim);
                    116:                                continue;
                    117:                        case 'a':
                    118:                                pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
                    119:                                        "?" : afmt[t->tm_wday], pt, ptlim);
                    120:                                continue;
                    121:                        case 'B':
                    122:                                pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
                    123:                                        "?" : Bfmt[t->tm_mon], pt, ptlim);
                    124:                                continue;
                    125:                        case 'b':
                    126:                        case 'h':
                    127:                                pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
                    128:                                        "?" : bfmt[t->tm_mon], pt, ptlim);
                    129:                                continue;
                    130:                        case 'c':
                    131:                                pt = _fmt("%D %X", t, pt, ptlim);
                    132:                                continue;
                    133:                        case 'C':
                    134:                                /*
                    135:                                ** %C used to do a...
                    136:                                **      _fmt("%a %b %e %X %Y", t);
                    137:                                ** ...whereas now POSIX 1003.2 calls for
                    138:                                ** something completely different.
                    139:                                ** (ado, 5/24/93)
                    140:                                */
                    141:                                pt = _conv((t->tm_year + TM_YEAR_BASE) / 100,
                    142:                                        "%02d", pt, ptlim);
                    143:                                continue;
                    144:                        case 'D':
                    145:                                pt = _fmt("%m/%d/%y", t, pt, ptlim);
                    146:                                continue;
                    147:                        case 'x':
                    148:                                /*
                    149:                                ** Version 3.0 of strftime from Arnold Robbins
                    150:                                ** (arnold@skeeve.atl.ga.us) does the
                    151:                                ** equivalent of...
                    152:                                **      _fmt("%a %b %e %Y");
                    153:                                ** ...for %x; since the X3J11 C language
                    154:                                ** standard calls for "date, using locale's
                    155:                                ** date format," anything goes.  Using just
                    156:                                ** numbers (as here) makes Quakers happier.
                    157:                                ** Word from Paul Eggert (eggert@twinsun.com)
                    158:                                ** is that %Y-%m-%d is the ISO standard date
                    159:                                ** format, specified in ISO 2014 and later
                    160:                                ** ISO 8601:1988, with a summary available in
                    161:                                ** pub/doc/ISO/english/ISO8601.ps.Z on
                    162:                                ** ftp.uni-erlangen.de.
                    163:                                ** (ado, 5/30/93)
                    164:                                */
                    165:                                pt = _fmt("%m/%d/%y", t, pt, ptlim);
                    166:                                continue;
                    167:                        case 'd':
                    168:                                pt = _conv(t->tm_mday, "%02d", pt, ptlim);
                    169:                                continue;
                    170:                        case 'E':
                    171:                        case 'O':
                    172:                                /*
                    173:                                ** POSIX locale extensions, a la
                    174:                                ** Arnold Robbins' strftime version 3.0.
                    175:                                ** The sequences
                    176:                                **      %Ec %EC %Ex %Ey %EY
                    177:                                **      %Od %oe %OH %OI %Om %OM
                    178:                                **      %OS %Ou %OU %OV %Ow %OW %Oy
                    179:                                ** are supposed to provide alternate
                    180:                                ** representations.
                    181:                                ** (ado, 5/24/93)
                    182:                                */
                    183:                                goto label;
                    184:                        case 'e':
                    185:                                pt = _conv(t->tm_mday, "%2d", pt, ptlim);
                    186:                                continue;
                    187:                        case 'H':
                    188:                                pt = _conv(t->tm_hour, "%02d", pt, ptlim);
                    189:                                continue;
                    190:                        case 'I':
                    191:                                pt = _conv((t->tm_hour % 12) ?
                    192:                                        (t->tm_hour % 12) : 12,
                    193:                                        "%02d", pt, ptlim);
                    194:                                continue;
                    195:                        case 'j':
                    196:                                pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);
                    197:                                continue;
                    198:                        case 'k':
                    199:                                /*
                    200:                                ** This used to be...
                    201:                                **      _conv(t->tm_hour % 12 ?
                    202:                                **              t->tm_hour % 12 : 12, 2, ' ');
                    203:                                ** ...and has been changed to the below to
                    204:                                ** match SunOS 4.1.1 and Arnold Robbins'
                    205:                                ** strftime version 3.0.  That is, "%k" and
                    206:                                ** "%l" have been swapped.
                    207:                                ** (ado, 5/24/93)
                    208:                                */
                    209:                                pt = _conv(t->tm_hour, "%2d", pt, ptlim);
                    210:                                continue;
                    211: #ifdef KITCHEN_SINK
                    212:                        case 'K':
                    213:                                /*
                    214:                                ** After all this time, still unclaimed!
                    215:                                */
                    216:                                pt = _add("kitchen sink", pt, ptlim);
                    217:                                continue;
                    218: #endif /* defined KITCHEN_SINK */
                    219:                        case 'l':
                    220:                                /*
                    221:                                ** This used to be...
                    222:                                **      _conv(t->tm_hour, 2, ' ');
                    223:                                ** ...and has been changed to the below to
                    224:                                ** match SunOS 4.1.1 and Arnold Robbin's
                    225:                                ** strftime version 3.0.  That is, "%k" and
                    226:                                ** "%l" have been swapped.
                    227:                                ** (ado, 5/24/93)
                    228:                                */
                    229:                                pt = _conv((t->tm_hour % 12) ?
                    230:                                        (t->tm_hour % 12) : 12,
                    231:                                        "%2d", pt, ptlim);
                    232:                                continue;
                    233:                        case 'M':
                    234:                                pt = _conv(t->tm_min, "%02d", pt, ptlim);
                    235:                                continue;
                    236:                        case 'm':
                    237:                                pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);
                    238:                                continue;
                    239:                        case 'n':
                    240:                                pt = _add("\n", pt, ptlim);
                    241:                                continue;
                    242:                        case 'p':
                    243:                                pt = _add(t->tm_hour >= 12 ? "PM" : "AM",
                    244:                                        pt, ptlim);
                    245:                                continue;
                    246:                        case 'R':
                    247:                                pt = _fmt("%H:%M", t, pt, ptlim);
                    248:                                continue;
                    249:                        case 'r':
                    250:                                pt = _fmt("%I:%M:%S %p", t, pt, ptlim);
                    251:                                continue;
                    252:                        case 'S':
                    253:                                pt = _conv(t->tm_sec, "%02d", pt, ptlim);
                    254:                                continue;
                    255:                        case 's':
                    256:                                pt = _secs(t, pt, ptlim);
                    257:                                continue;
                    258:                        case 'T':
                    259:                        case 'X':
                    260:                                pt = _fmt("%H:%M:%S", t, pt, ptlim);
                    261:                                continue;
                    262:                        case 't':
                    263:                                pt = _add("\t", pt, ptlim);
                    264:                                continue;
                    265:                        case 'U':
                    266:                                pt = _conv((t->tm_yday + 7 - t->tm_wday) / 7,
                    267:                                        "%02d", pt, ptlim);
                    268:                                continue;
                    269:                        case 'u':
                    270:                                /*
                    271:                                ** From Arnold Robbins' strftime version 3.0:
                    272:                                ** "ISO 8601: Weekday as a decimal number
                    273:                                ** [1 (Monday) - 7]"
                    274:                                ** (ado, 5/24/93)
                    275:                                */
                    276:                                pt = _conv((t->tm_wday == 0) ? 7 : t->tm_wday,
                    277:                                        "%d", pt, ptlim);
                    278:                                continue;
                    279:                        case 'V':
                    280:                                /*
                    281:                                ** From Arnold Robbins' strftime version 3.0:
                    282:                                ** "the week number of the year (the first
                    283:                                ** Monday as the first day of week 1) as a
                    284:                                ** decimal number (01-53).  The method for
                    285:                                ** determining the week number is as specified
                    286:                                ** by ISO 8601 (to wit: if the week containing
                    287:                                ** January 1 has four or more days in the new
                    288:                                ** year, then it is week 1, otherwise it is
                    289:                                ** week 53 of the previous year and the next
                    290:                                ** week is week 1)."
                    291:                                ** (ado, 5/24/93)
                    292:                                */
                    293:                                /*
                    294:                                ** XXX--If January 1 falls on a Friday,
                    295:                                ** January 1-3 are part of week 53 of the
                    296:                                ** previous year.  By analogy, if January
                    297:                                ** 1 falls on a Thursday, are December 29-31
                    298:                                ** of the PREVIOUS year part of week 1???
                    299:                                ** (ado 5/24/93)
                    300:                                **
                    301:                                ** You are understood not to expect this.
                    302:                                */
                    303:                                {
                    304:                                        int i;
                    305: 
                    306:                                        i = (t->tm_yday + 10 - (t->tm_wday ?
                    307:                                                (t->tm_wday - 1) : 6)) / 7;
                    308:                                        pt = _conv((i == 0) ? 53 : i,
                    309:                                                "%02d", pt, ptlim);
                    310:                                }
                    311:                                continue;
                    312: #ifdef notdef
                    313:                                /* Not in POSIX date(1), System V or ANSI C. */
                    314:                        case 'v':
                    315:                                /*
                    316:                                ** From Arnold Robbins' strftime version 3.0:
                    317:                                ** "date as dd-bbb-YYYY"
                    318:                                ** (ado, 5/24/93)
                    319:                                */
                    320:                                pt = _fmt("%e-%b-%Y", t, pt, ptlim);
                    321:                                continue;
                    322: #endif
                    323:                        case 'W':
                    324:                                pt = _conv((t->tm_yday + 7 -
                    325:                                        (t->tm_wday ?
                    326:                                        (t->tm_wday - 1) : 6)) / 7,
                    327:                                        "%02d", pt, ptlim);
                    328:                                continue;
                    329:                        case 'w':
                    330:                                pt = _conv(t->tm_wday, "%d", pt, ptlim);
                    331:                                continue;
                    332:                        case 'y':
                    333:                                pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,
                    334:                                        "%02d", pt, ptlim);
                    335:                                continue;
                    336:                        case 'Y':
                    337:                                pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d",
                    338:                                        pt, ptlim);
                    339:                                continue;
                    340:                        case 'Z':
                    341: #ifdef TM_ZONE
                    342:                                if (t->TM_ZONE)
                    343:                                        pt = _add(t->TM_ZONE, pt, ptlim);
                    344:                                else
                    345: #endif /* defined TM_ZONE */
                    346:                                if (t->tm_isdst == 0 || t->tm_isdst == 1) {
                    347:                                        pt = _add(tzname[t->tm_isdst],
                    348:                                                pt, ptlim);
                    349:                                } else  pt = _add("?", pt, ptlim);
                    350:                                continue;
                    351:                        case '%':
                    352:                        /*
                    353:                         * X311J/88-090 (4.12.3.5): if conversion char is
                    354:                         * undefined, behavior is undefined.  Print out the
                    355:                         * character itself as printf(3) does.
                    356:                         */
                    357:                        default:
                    358:                                break;
                    359:                        }
                    360:                }
                    361:                if (pt == ptlim)
                    362:                        break;
                    363:                *pt++ = *format;
                    364:        }
                    365:        return (pt);
                    366: }
                    367: 
                    368: static char *
                    369: _secs(t, pt, ptlim)
                    370:        const struct tm *t;
                    371:        char *pt;
                    372:        const char *ptlim;
                    373: {
                    374:        struct tm tmp;
                    375:        time_t s;
                    376: 
                    377:        tmp = *t;
                    378:        s = mktime(&tmp);
                    379:        return (_conv((int)s, "%d", pt, ptlim));
                    380: }
                    381: 
                    382: static char *
                    383: _conv(n, format, pt, ptlim)
                    384:        int n;
                    385:        const char *format;
                    386:        char *pt;
                    387:        const char *ptlim;
                    388: {
                    389:        char buf[INT_STRLEN_MAXIMUM(int) + 1];
                    390: 
                    391:        (void) sprintf(buf, format, n);
                    392:        return (_add(buf, pt, ptlim));
                    393: }
                    394: 
                    395: static char *
                    396: _add(str, pt, ptlim)
                    397:        const char *str;
                    398:        char *pt;
                    399:        const char *ptlim;
                    400: {
                    401: 
                    402:        while (pt < ptlim && (*pt = *str++) != '\0')
                    403:                ++pt;
                    404:        return (pt);
                    405: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>