strftime.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 575 行

C
575
字号
/* * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley.  The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#ifdef LIBC_RCSstatic const char rcsid[] =	"$\Id: strftime.c,v 1.11.2.4 1997/02/08 14:16:11 joerg Exp $";#endif#ifndef lint#ifndef NOIDstatic const char	elsieid[] = "@(#)strftime.c	7.38";/*** Based on the UCB version with the ID appearing below.** This is ANSIish only when "multibyte character == plain character".*/#endif /* !defined NOID */#endif /* !defined lint */#include "private.h"#ifndef LIBC_SCCS#ifndef lintstatic const char	sccsid[] = "@(#)strftime.c	5.4 (Berkeley) 3/14/89";#endif /* !defined lint */#endif /* !defined LIBC_SCCS */#include "tzfile.h"#include <fcntl.h>#include <locale.h>#include <sys/stat.h>#include "setlocale.h"struct lc_time_T {	const char *	mon[12];	const char *	month[12];	const char *	wday[7];	const char *	weekday[7];	const char *	X_fmt;	const char *	x_fmt;	const char *	c_fmt;	const char *	am;	const char *	pm;	const char *	date_fmt;};static struct lc_time_T		localebuf;static int using_locale;#define Locale	(using_locale ? &localebuf : &C_time_locale)static const struct lc_time_T	C_time_locale = {	{		"Jan", "Feb", "Mar", "Apr", "May", "Jun",		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"	}, {		"January", "February", "March", "April", "May", "June",		"July", "August", "September", "October", "November", "December"	}, {		"Sun", "Mon", "Tue", "Wed",		"Thu", "Fri", "Sat"	}, {		"Sunday", "Monday", "Tuesday", "Wednesday",		"Thursday", "Friday", "Saturday"	},	/* X_fmt */	"%H:%M:%S",	/*	** x_fmt	** Since the C language standard calls for	** "date, using locale's date format," anything goes.	** Using just numbers (as here) makes Quakers happier;	** it's also compatible with SVR4.	*/	"%m/%d/%y",	/*	** c_fmt (ctime-compatible)	** Note that	**	"%a %b %d %H:%M:%S %Y"	** is used by Solaris 2.3.	*/	"%a %b %e %X %Y",	/* am */	"AM",	/* pm */	"PM",	/* date_fmt */	"%a %b %e %X %Z %Y"};static char *	_add P((const char *, char *, const char *));static char *	_conv P((int, const char *, char *, const char *));static char *	_fmt P((const char *, const struct tm *, char *, const char *));static char *   _secs P((const struct tm *, char *, const char *));size_t strftime P((char *, size_t, const char *, const struct tm *));extern char *	tzname[];size_tstrftime(s, maxsize, format, t)	char *const s;	const size_t maxsize;	const char *const format;	const struct tm *const t;{	char *p;	tzset();	p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize);	if (p == s + maxsize)		return 0;	*p = '\0';	return p - s;}static char *_fmt(format, t, pt, ptlim)	const char *format;	const struct tm *const t;	char *pt;	const char *const ptlim;{	for ( ; *format; ++format) {		if (*format == '%') {label:			switch (*++format) {			case '\0':				--format;				break;			case 'A':				pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?					"?" : Locale->weekday[t->tm_wday],					pt, ptlim);				continue;			case 'a':				pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?					"?" : Locale->wday[t->tm_wday],					pt, ptlim);				continue;			case 'B':				pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?					"?" : Locale->month[t->tm_mon],					pt, ptlim);				continue;			case 'b':			case 'h':				pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?					"?" : Locale->mon[t->tm_mon],					pt, ptlim);				continue;			case 'C':				/*				** %C used to do a...				**	_fmt("%a %b %e %X %Y", t);				** ...whereas now POSIX 1003.2 calls for				** something completely different.				** (ado, 5/24/93)				*/				pt = _conv((t->tm_year + TM_YEAR_BASE) / 100,					"%02d", pt, ptlim);				continue;			case 'c':				pt = _fmt(Locale->c_fmt, t, pt, ptlim);				continue;			case 'D':				pt = _fmt("%m/%d/%y", t, pt, ptlim);				continue;			case 'd':				pt = _conv(t->tm_mday, "%02d", pt, ptlim);				continue;			case 'E':			case 'O':				/*				** POSIX locale extensions, a la				** Arnold Robbins' strftime version 3.0.				** The sequences				**	%Ec %EC %Ex %Ey %EY				**	%Od %oe %OH %OI %Om %OM				**	%OS %Ou %OU %OV %Ow %OW %Oy				** are supposed to provide alternate				** representations.				** (ado, 5/24/93)				*/				goto label;			case 'e':				pt = _conv(t->tm_mday, "%2d", pt, ptlim);				continue;			case 'H':				pt = _conv(t->tm_hour, "%02d", pt, ptlim);				continue;			case 'I':				pt = _conv((t->tm_hour % 12) ?					(t->tm_hour % 12) : 12,					"%02d", pt, ptlim);				continue;			case 'j':				pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);				continue;			case 'k':				/*				** This used to be...				**	_conv(t->tm_hour % 12 ?				**		t->tm_hour % 12 : 12, 2, ' ');				** ...and has been changed to the below to				** match SunOS 4.1.1 and Arnold Robbins'				** strftime version 3.0.  That is, "%k" and				** "%l" have been swapped.				** (ado, 5/24/93)				*/				pt = _conv(t->tm_hour, "%2d", pt, ptlim);				continue;#ifdef KITCHEN_SINK			case 'K':				/*				** After all this time, still unclaimed!				*/				pt = _add("kitchen sink", pt, ptlim);				continue;#endif /* defined KITCHEN_SINK */			case 'l':				/*				** This used to be...				**	_conv(t->tm_hour, 2, ' ');				** ...and has been changed to the below to				** match SunOS 4.1.1 and Arnold Robbin's				** strftime version 3.0.  That is, "%k" and				** "%l" have been swapped.				** (ado, 5/24/93)				*/				pt = _conv((t->tm_hour % 12) ?					(t->tm_hour % 12) : 12,					"%2d", pt, ptlim);				continue;			case 'M':				pt = _conv(t->tm_min, "%02d", pt, ptlim);				continue;			case 'm':				pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);				continue;			case 'n':				pt = _add("\n", pt, ptlim);				continue;			case 'p':				pt = _add((t->tm_hour >= 12) ?					Locale->pm :					Locale->am,					pt, ptlim);				continue;			case 'R':				pt = _fmt("%H:%M", t, pt, ptlim);				continue;			case 'r':				pt = _fmt("%I:%M:%S %p", t, pt, ptlim);				continue;			case 'S':				pt = _conv(t->tm_sec, "%02d", pt, ptlim);				continue;			case 's':				pt = _secs(t, pt, ptlim);				continue;			case 'T':				pt = _fmt("%H:%M:%S", t, pt, ptlim);				continue;			case 't':				pt = _add("\t", pt, ptlim);				continue;			case 'U':				pt = _conv((t->tm_yday + 7 - t->tm_wday) / 7,					"%02d", pt, ptlim);				continue;			case 'u':				/*				** From Arnold Robbins' strftime version 3.0:				** "ISO 8601: Weekday as a decimal number				** [1 (Monday) - 7]"				** (ado, 5/24/93)				*/				pt = _conv((t->tm_wday == 0) ? 7 : t->tm_wday,					"%d", pt, ptlim);				continue;			case 'V':				/*				** From Arnold Robbins' strftime version 3.0:				** "the week number of the year (the first				** Monday as the first day of week 1) as a				** decimal number (01-53).  The method for				** determining the week number is as specified				** by ISO 8601 (to wit: if the week containing				** January 1 has four or more days in the new				** year, then it is week 1, otherwise it is				** week 53 of the previous year and the next				** week is week 1)."				** (ado, 5/24/93)				*/				/*				** XXX--If January 1 falls on a Friday,				** January 1-3 are part of week 53 of the				** previous year.  By analogy, if January				** 1 falls on a Thursday, are December 29-31				** of the PREVIOUS year part of week 1???				** (ado 5/24/93)				*/				/*				** You are understood not to expect this.				*/				{					int	i;					i = (t->tm_yday + 10 - (t->tm_wday ?						(t->tm_wday - 1) : 6)) / 7;					if (i == 0) {						/*						** What day of the week does						** January 1 fall on?						*/						i = t->tm_wday -							(t->tm_yday - 1);						/*						** Fri Jan 1: 53						** Sun Jan 1: 52						** Sat Jan 1: 53 if previous						**		 year a leap						**		 year, else 52						*/						if (i == TM_FRIDAY)							i = 53;						else if (i == TM_SUNDAY)							i = 52;						else	i = isleap(t->tm_year +								TM_YEAR_BASE) ?								53 : 52;#ifdef XPG4_1994_04_09						/*						** As of 4/9/94, though,						** XPG4 calls for 53						** unconditionally.						*/						i = 53;#endif /* defined XPG4_1994_04_09 */					}					pt = _conv(i, "%02d", pt, ptlim);				}				continue;			case 'v':				/*				** From Arnold Robbins' strftime version 3.0:				** "date as dd-bbb-YYYY"				** (ado, 5/24/93)				*/				pt = _fmt("%e-%b-%Y", t, pt, ptlim);				continue;			case 'W':				pt = _conv((t->tm_yday + 7 -					(t->tm_wday ?					(t->tm_wday - 1) : 6)) / 7,					"%02d", pt, ptlim);				continue;			case 'w':				pt = _conv(t->tm_wday, "%d", pt, ptlim);				continue;			case 'X':				pt = _fmt(Locale->X_fmt, t, pt, ptlim);				continue;			case 'x':				pt = _fmt(Locale->x_fmt, t, pt, ptlim);				continue;			case 'y':				pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,					"%02d", pt, ptlim);				continue;			case 'Y':				pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d",					pt, ptlim);				continue;			case 'Z':				if (t->tm_zone != NULL)					pt = _add(t->tm_zone, pt, ptlim);				else				if (t->tm_isdst == 0 || t->tm_isdst == 1) {					pt = _add(tzname[t->tm_isdst],						pt, ptlim);				} else  pt = _add("?", pt, ptlim);				continue;			case '+':				pt = _fmt(Locale->date_fmt, t, pt, ptlim);				continue;			case '%':			/*			 * X311J/88-090 (4.12.3.5): if conversion char is			 * undefined, behavior is undefined.  Print out the			 * character itself as printf(3) also does.			 */			default:				break;			}		}		if (pt == ptlim)			break;		*pt++ = *format;	}	return pt;}static char *_conv(n, format, pt, ptlim)	const int n;	const char *const format;	char *const pt;	const char *const ptlim;{	char	buf[INT_STRLEN_MAXIMUM(int) + 1];	(void) sprintf(buf, format, n);	return _add(buf, pt, ptlim);}static char *_secs(t, pt, ptlim)	const struct tm *t;	char *pt;	const char *ptlim;{	char    buf[INT_STRLEN_MAXIMUM(int) + 1];	register time_t s;	struct tm tmp;	/* Make a copy, mktime(3) modifies the tm struct. */	tmp = *t;	s = mktime(&tmp);	(void) sprintf(buf, "%ld", s);	return _add(buf, pt, ptlim);}  static char *_add(str, pt, ptlim)	const char *str;	char *pt;	const char *const ptlim;{	while (pt < ptlim && (*pt = *str++) != '\0')		++pt;	return pt;}int__time_load_locale(const char *name){	static char *		locale_buf;	static char		locale_buf_C[] = "C";	int			fd;	char *			lbuf;	char *			p;	const char **		ap;	const char *		plim;	char                    filename[PATH_MAX];	struct stat		st;	size_t			namesize;	size_t			bufsize;	int                     save_using_locale;	save_using_locale = using_locale;	using_locale = 0;	if (name == NULL)		goto no_locale;	if (!strcmp(name, "C") || !strcmp(name, "POSIX"))		return 0;	/*	** If the locale name is the same as our cache, use the cache.	*/	lbuf = locale_buf;	if (lbuf != NULL && strcmp(name, lbuf) == 0) {		p = lbuf;		for (ap = (const char **) &localebuf;			ap < (const char **) (&localebuf + 1);				++ap)					*ap = p += strlen(p) + 1;		using_locale = 1;		return 0;	}	/*	** Slurp the locale file into the cache.	*/	namesize = strlen(name) + 1;	if (!_PathLocale)		goto no_locale;	/* Range checking not needed, 'name' size is limited */	strcpy(filename, _PathLocale);	strcat(filename, "/");	strcat(filename, name);	strcat(filename, "/LC_TIME");	fd = open(filename, O_RDONLY);	if (fd < 0)		goto no_locale;	if (fstat(fd, &st) != 0)		goto bad_locale;	if (st.st_size <= 0)		goto bad_locale;	bufsize = namesize + st.st_size;	locale_buf = NULL;	lbuf = (lbuf == NULL || lbuf == locale_buf_C) ?		malloc(bufsize) : realloc(lbuf, bufsize);	if (lbuf == NULL)		goto bad_locale;	(void) strcpy(lbuf, name);	p = lbuf + namesize;	plim = p + st.st_size;	if (read(fd, p, (size_t) st.st_size) != st.st_size)		goto bad_lbuf;	if (close(fd) != 0)		goto bad_lbuf;	/*	** Parse the locale file into localebuf.	*/	if (plim[-1] != '\n')		goto bad_lbuf;	for (ap = (const char **) &localebuf;		ap < (const char **) (&localebuf + 1);			++ap) {				if (p == plim)					goto reset_locale;				*ap = p;				while (*p != '\n')					++p;				*p++ = '\0';	}	/*	** Record the successful parse in the cache.	*/	locale_buf = lbuf;	using_locale = 1;	return 0;reset_locale:	/*	 * XXX - This may not be the correct thing to do in this case.	 * setlocale() assumes that we left the old locale alone.	 */	locale_buf = locale_buf_C;	localebuf = C_time_locale;	save_using_locale = 0;bad_lbuf:	free(lbuf);bad_locale:	(void) close(fd);no_locale:	using_locale = save_using_locale;	return -1;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?