Annotation of embedaddon/trafshow/strftime.c, revision 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>