File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / trafshow / strftime.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:55:18 2012 UTC (12 years, 4 months ago) by misho
Branches: trafshow, MAIN
CVS tags: v5_2_3p0, v5_2_3, HEAD
trafshow

    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>