⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 time.c

📁 它通过提供glibc兼容使得应用程序移植到较小的c 库时相当得容易. 它能够应用到带虚拟存储的Linux和uClinux上.在大多数带MMU部件的平台上为使它更加紧凑,它也能够编译成共享库.uClib
💻 C
📖 第 1 页 / 共 4 页
字号:
/*  Copyright (C) 2002     Manuel Novoa III * *  This library is free software; you can redistribute it and/or *  modify it under the terms of the GNU Library General Public *  License as published by the Free Software Foundation; either *  version 2 of the License, or (at your option) any later version. * *  This library is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *  Library General Public License for more details. * *  You should have received a copy of the GNU Library General Public *  License along with this library; if not, write to the Free *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//*  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! * *  Besides uClibc, I'm using this code in my libc for elks, which is *  a 16-bit environment with a fairly limited compiler.  It would make *  things much easier for me if this file isn't modified unnecessarily. *  In particular, please put any new or replacement functions somewhere *  else, and modify the makefile to use your version instead. *  Thanks.  Manuel * *  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! *//* June 15, 2002     Initial Notes: * * Note: It is assumed throught that time_t is either long or unsigned long. *       Similarly, clock_t is assumed to be long int. * * Warning: Assumptions are made about the layout of struct tm!  It is *    assumed that the initial fields of struct tm are (in order): *    tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday * * Reached the inital goal of supporting the ANSI/ISO C99 time functions * as well as SUSv3's strptime.  All timezone info is obtained from the * TZ env variable. * * Differences from glibc worth noting: * * Leap seconds are not considered here. * * glibc stores additional timezone info the struct tm, whereas we don't. * * Alternate digits and era handling are not currently implemented. * The modifiers are accepted, and tested for validity with the following * specifier, but are ignored otherwise. * * strftime does not implement glibc extension modifiers or widths for *     conversion specifiers.  However it does implement the glibc *     extension specifiers %l, %k, and %s.  It also recognizes %P, but *     treats it as a synonym for %p; i.e. doesn't convert to lower case. * * strptime implements the glibc extension specifiers.  However, it follows *     SUSv3 in requiring at least one non-alphanumeric char between *     conversion specifiers.  Also, strptime only sets struct tm fields *     for which format specifiers appear and does not try to infer other *     fields (such as wday) as glibc's version does. * * TODO - Since glibc's %l and %k can space-pad their output in strftime, *     it might be reasonable to eat whitespace first for those specifiers. *     This could be done by pushing " %I" and " %H" respectively so that *     leading whitespace is consumed.  This is really only an issue if %l *     or %k occurs at the start of the format string. * * TODO - Implement getdate? tzfile? struct tm extensions? * * TODO - Rework _time_mktime to remove the dependency on long long. *//* Oct 28, 2002 * * Fixed allowed char check for std and dst TZ fields. * * Added several options concerned with timezone support.  The names will * probably change once Erik gets the new config system in place. * * Defining __TIME_TZ_FILE causes tzset() to attempt to read the TZ value * from the file /etc/TZ if the TZ env variable isn't set.  The file contents * must be the intended value of TZ, followed by a newline.  No other chars, * spacing, etc is allowed.  As an example, an easy way for me to init * /etc/TZ appropriately would be:    echo CST6CDT > /etc/TZ * * Defining __TIME_TZ_FILE_ONCE will cause all further accesses of /etc/TZ * to be skipped once a legal value has been read. * * Defining __TIME_TZ_OPT_SPEED will cause a tzset() to keep a copy of the * last TZ setting string and do a "fast out" if the current string is the * same. * * Nov 21, 2002   Fix an error return case in _time_mktime. * * Nov 26, 2002   Fix bug in setting daylight and timezone when no (valid) TZ. *   Bug reported by Arne Bernin <arne@alamut.de> in regards to freeswan. */#define _GNU_SOURCE#define _STDIO_UTILITY#include <stdio.h>#include <stdlib.h>#include <stddef.h>#include <string.h>#include <time.h>#include <limits.h>#include <assert.h>#include <errno.h>#include <ctype.h>#include <langinfo.h>#include <locale.h>#ifndef __isleap#define __isleap(y) ( !((y) % 4) && ( ((y) % 100) || !((y) % 400) ) )#endif#ifndef TZNAME_MAX#define TZNAME_MAX _POSIX_TZNAME_MAX#endif/**********************************************************************//* The era code is currently unfinished. *//*  #define ENABLE_ERA_CODE */#define __TIME_TZ_FILE/* #define __TIME_TZ_FILE_ONCE */#define __TIME_TZ_OPT_SPEED#define TZ_BUFLEN		(2*TZNAME_MAX + 56)#ifdef __TIME_TZ_FILE#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include "paths.h"/* ":<tzname>+hh:mm:ss<tzname>+hh:mm:ss,Mmm.w.d/hh:mm:ss,Mmm.w.d/hh:mm:ss" + nul *//* 1 + 2*(1+TZNAME_MAX+1 + 9 + 7 + 9) + 1 = 2*TZNAME_MAX + 56 */#else  /* __TIME_TZ_FILE */#undef __TIME_TZ_FILE_ONCE#endif /* __TIME_TZ_FILE *//**********************************************************************/extern struct tm __time_tm;typedef struct {	long gmt_offset;	long dst_offset;	short day;					/* for J or normal */	short week;	short month;	short rule_type;			/* J, M, \0 */	char tzname[TZNAME_MAX+1];} rule_struct;#ifdef __UCLIBC_HAS_THREADS__#include <pthread.h>extern pthread_mutex_t _time_tzlock;#define TZLOCK		pthread_mutex_lock(&_time_tzlock)#define TZUNLOCK	pthread_mutex_unlock(&_time_tzlock)#else#define TZLOCK		((void) 0)#define TZUNLOCK	((void) 0)#endifextern rule_struct _time_tzinfo[2];extern struct tm *_time_t2tm(const time_t *__restrict timer,							 int offset, struct tm *__restrict result);extern time_t _time_mktime(struct tm *timeptr, int store_on_success);/**********************************************************************/#ifdef L_asctimestatic char __time_str[26];char *asctime(const struct tm *__restrict ptm){	return asctime_r(ptm, __time_str);}#endif/**********************************************************************/#ifdef L_asctime_r/* Strictly speaking, this implementation isn't correct.  ANSI/ISO specifies * that the implementation of asctime() be equivalent to * *   char *asctime(const struct tm *timeptr) *   { *       static char wday_name[7][3] = { *           "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" *       }; *       static char mon_name[12][3] = { *           "Jan", "Feb", "Mar", "Apr", "May", "Jun", *           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"  *       }; *       static char result[26]; *    *       sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", *           wday_name[timeptr->tm_wday],                    *           mon_name[timeptr->tm_mon], *           timeptr->tm_mday, timeptr->tm_hour, *           timeptr->tm_min, timeptr->tm_sec,   *           1900 + timeptr->tm_year);         *       return result; *   } * * but the above is either inherently unsafe, or carries with it the implicit * assumption that all fields of timeptr fall within their usual ranges, and * that the tm_year value falls in the range [-2899,8099] to avoid overflowing * the static buffer. * * If we take the implicit assumption as given, then the implementation below * is still incorrect for tm_year values < -900, as there will be either * 0-padding and/or a missing negative sign for the year conversion .  But given * the ususal use of asctime(), I think it isn't unreasonable to restrict correct * operation to the domain of years between 1000 and 9999. *//* This is generally a good thing, but if you're _sure_ any data passed will be * in range, you can #undef this. */#define SAFE_ASCTIME_R		1static const unsigned char at_data[] = {	'S', 'u', 'n', 'M', 'o', 'n', 'T', 'u', 'e', 'W', 'e', 'd',	'T', 'h', 'u', 'F', 'r', 'i', 'S', 'a', 't',	'J', 'a', 'n', 'F', 'e', 'b', 'M', 'a', 'r', 'A', 'p', 'r',	'M', 'a', 'y', 'J', 'u', 'n', 'J', 'u', 'l', 'A', 'u', 'g',	'S', 'e', 'p', 'O', 'c', 't', 'N', 'o', 'v', 'D', 'e', 'c', #ifdef SAFE_ASCTIME_R	'?', '?', '?', #endif	' ', '?', '?', '?',	' ', '0',	offsetof(struct tm, tm_mday),	' ', '0',	offsetof(struct tm, tm_hour),	':', '0',	offsetof(struct tm, tm_min),	':', '0',	offsetof(struct tm, tm_sec),	' ', '?', '?', '?', '?', '\n', 0};char *asctime_r(register const struct tm *__restrict ptm,				register char *__restrict buffer){	int tmp;	assert(ptm);	assert(buffer);#ifdef SAFE_ASCTIME_R	memcpy(buffer, at_data + 3*(7 + 12), sizeof(at_data) - 3*(7 + 12));	if (((unsigned int)(ptm->tm_wday)) <= 6) {		memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);	}	if (((unsigned int)(ptm->tm_mon)) <= 11) {		memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);	}#else	assert(((unsigned int)(ptm->tm_wday)) <= 6);	assert(((unsigned int)(ptm->tm_mon)) <= 11);	memcpy(buffer, at_data + 3*(7 + 12) - 3, sizeof(at_data) + 3 - 3*(7 + 12));	memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);	memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);#endif#ifdef SAFE_ASCTIME_R	buffer += 19;	tmp = ptm->tm_year + 1900;	if (((unsigned int) tmp) < 10000) {		buffer += 4;		do {			*buffer = '0' + (tmp % 10);			tmp /= 10;		} while (*--buffer == '?');	}#else  /* SAFE_ASCTIME_R */	buffer += 23;	tmp = ptm->tm_year + 1900;	assert( ((unsigned int) tmp) < 10000 );	do {		*buffer = '0' + (tmp % 10);		tmp /= 10;	} while (*--buffer == '?');#endif /* SAFE_ASCTIME_R */	do {		--buffer;		tmp = *((int *)(((const char *) ptm) + (int) *buffer));#ifdef SAFE_ASCTIME_R		if (((unsigned int) tmp) >= 100) { /* Just check 2 digit non-neg. */			buffer[-1] = *buffer = '?';		} else#else  /* SAFE_ASCTIME_R */		assert(((unsigned int) tmp) < 100); /* Just check 2 digit non-neg. */#endif /* SAFE_ASCTIME_R */		{			*buffer = '0' + (tmp % 10);#ifdef __BCC__			buffer[-1] = '0' + (tmp/10);#else  /* __BCC__ */			buffer[-1] += (tmp/10);#endif /* __BCC__ */		}	} while ((buffer -= 2)[-2] == '0');	if (*++buffer == '0') {		/* Space-pad day of month. */		*buffer = ' ';	}	return buffer - 8;}#endif/**********************************************************************/#ifdef L_clock#include <sys/times.h>/* Note: According to glibc... *    CAE XSH, Issue 4, Version 2: <time.h> *    The value of CLOCKS_PER_SEC is required to be 1 million on all *    XSI-conformant systems. */#ifndef __BCC__#if CLOCKS_PER_SEC != 1000000L#error unexpected value for CLOCKS_PER_SEC!#endif#endifclock_t clock(void){	struct tms xtms;	unsigned long t;	times(&xtms);	t = ((unsigned long) xtms.tms_utime) + xtms.tms_stime;#ifndef __UCLIBC_CLK_TCK_CONST#error __UCLIBC_CLK_TCK_CONST not defined!#endif#undef CLK_TCK#define CLK_TCK __UCLIBC_CLK_TCK_CONST#if CLK_TCK > CLOCKS_PER_SEC#error __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC!#elif CLK_TCK < 1#error __UCLIBC_CLK_TCK_CONST < 1!#endif#if (CLK_TCK == CLOCKS_PER_SEC)	return (t <= LONG_MAX) ? t : -1;#elif (CLOCKS_PER_SEC % CLK_TCK) == 0	return (t <= (LONG_MAX / (CLOCKS_PER_SEC/CLK_TCK)))		? t * (CLOCKS_PER_SEC/CLK_TCK)		: -1;#else	return (t <= ((LONG_MAX / CLOCKS_PER_SEC) * CLK_TCK				  + ((LONG_MAX % CLOCKS_PER_SEC) * CLK_TCK) / CLOCKS_PER_SEC))		? (((t / CLK_TCK) * CLOCKS_PER_SEC)		   + (((t % CLK_TCK) * CLOCKS_PER_SEC) / CLK_TCK))		: -1;#endif}#endif/**********************************************************************/#ifdef L_ctimechar *ctime(const time_t *clock){	/* ANSI/ISO/SUSv3 say that ctime is equivalent to the following. */	return asctime(localtime(clock));}#endif/**********************************************************************/#ifdef L_ctime_rchar *ctime_r(const time_t *clock, char *buf){	struct tm xtms;	return asctime_r(localtime_r(clock, &xtms), buf);}#endif/**********************************************************************/#ifdef L_difftime#include <float.h>#if FLT_RADIX != 2#error difftime implementation assumptions violated for you arch!#endifdouble difftime(time_t time1, time_t time0){#if (LONG_MAX >> DBL_MANT_DIG) == 0	/* time_t fits in the mantissa of a double. */	return ((double) time1) - time0;#elif ((LONG_MAX >> DBL_MANT_DIG) >> DBL_MANT_DIG) == 0	/* time_t can overflow the mantissa of a double. */	time_t t1, t0, d;	d = ((time_t) 1) << DBL_MANT_DIG;	t1 = time1 / d;	time1 -= (t1 * d);	t0 = time0 / d;	time0 -= (t0*d);	/* Since FLT_RADIX==2 and d is a power of 2, the only possible	 * rounding error in the expression below would occur from the	 * addition. */	return (((double) t1) - t0) * d + (((double) time1) - time0);#else#error difftime needs special implementation on your arch.#endif}#endif/**********************************************************************/#ifdef L_gmtimestruct tm *gmtime(const time_t *timer){	register struct tm *ptm = &__time_tm;	_time_t2tm(timer, 0, ptm); /* Can return NULL... */	return ptm;}#endif/**********************************************************************/#ifdef L_gmtime_rstruct tm *gmtime_r(const time_t *__restrict timer,					struct tm *__restrict result){	return _time_t2tm(timer, 0, result);}#endif/**********************************************************************/#ifdef L_localtimestruct tm *localtime(const time_t *timer){	register struct tm *ptm = &__time_tm;	/* In this implementation, tzset() is called by localtime_r().  */	localtime_r(timer, ptm);	/* Can return NULL... */	return ptm;}#endif/**********************************************************************/#ifdef L_localtime_rstatic const unsigned char day_cor[] = { /* non-leap */	31, 31, 34, 34, 35, 35, 36, 36, 36, 37, 37, 38, 38/* 	 0,  0,  3,  3,  4,  4,  5,  5,  5,  6,  6,  7,  7 *//*	    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 */};/* Note: timezone locking is done by localtime_r. */static int tm_isdst(register const struct tm *__restrict ptm){	register rule_struct *r = _time_tzinfo;	long sec;	int i, isdst, isleap, day, day0, monlen, mday;	int oday=0;				/* Note: oday can be uninitialized. */	isdst = 0;	if (r[1].tzname[0] != 0) {		/* First, get the current seconds offset from the start of the year.		 * Fields of ptm are assumed to be in their normal ranges. */		sec = ptm->tm_sec			+ 60 * (ptm->tm_min					+ 60 * (long)(ptm->tm_hour								  + 24 * ptm->tm_yday));

⌨️ 快捷键说明

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