1  | 
     | 
     | 
    /*	$OpenBSD: asctime.c,v 1.23 2015/10/24 18:13:18 guenther Exp $ */  | 
    
    
    2  | 
     | 
     | 
    /*  | 
    
    
    3  | 
     | 
     | 
    ** This file is in the public domain, so clarified as of  | 
    
    
    4  | 
     | 
     | 
    ** 1996-06-05 by Arthur David Olson.  | 
    
    
    5  | 
     | 
     | 
    */  | 
    
    
    6  | 
     | 
     | 
     | 
    
    
    7  | 
     | 
     | 
    /*  | 
    
    
    8  | 
     | 
     | 
    ** Avoid the temptation to punt entirely to strftime;  | 
    
    
    9  | 
     | 
     | 
    ** the output of strftime is supposed to be locale specific  | 
    
    
    10  | 
     | 
     | 
    ** whereas the output of asctime is supposed to be constant.  | 
    
    
    11  | 
     | 
     | 
    */  | 
    
    
    12  | 
     | 
     | 
     | 
    
    
    13  | 
     | 
     | 
    #include <errno.h>  | 
    
    
    14  | 
     | 
     | 
    #include <stdio.h>  | 
    
    
    15  | 
     | 
     | 
    #include <string.h>  | 
    
    
    16  | 
     | 
     | 
    #include "private.h"  | 
    
    
    17  | 
     | 
     | 
    #include "tzfile.h"  | 
    
    
    18  | 
     | 
     | 
    #include "thread_private.h"  | 
    
    
    19  | 
     | 
     | 
     | 
    
    
    20  | 
     | 
     | 
    /*  | 
    
    
    21  | 
     | 
     | 
    ** Some systems only handle "%.2d"; others only handle "%02d";  | 
    
    
    22  | 
     | 
     | 
    ** "%02.2d" makes (most) everybody happy.  | 
    
    
    23  | 
     | 
     | 
    ** At least some versions of gcc warn about the %02.2d;  | 
    
    
    24  | 
     | 
     | 
    ** we conditionalize below to avoid the warning.  | 
    
    
    25  | 
     | 
     | 
    */  | 
    
    
    26  | 
     | 
     | 
    /*  | 
    
    
    27  | 
     | 
     | 
    ** All years associated with 32-bit time_t values are exactly four digits long;  | 
    
    
    28  | 
     | 
     | 
    ** some years associated with 64-bit time_t values are not.  | 
    
    
    29  | 
     | 
     | 
    ** Vintage programs are coded for years that are always four digits long  | 
    
    
    30  | 
     | 
     | 
    ** and may assume that the newline always lands in the same place.  | 
    
    
    31  | 
     | 
     | 
    ** For years that are less than four digits, we pad the output with  | 
    
    
    32  | 
     | 
     | 
    ** leading zeroes to get the newline in the traditional place.  | 
    
    
    33  | 
     | 
     | 
    ** The -4 ensures that we get four characters of output even if  | 
    
    
    34  | 
     | 
     | 
    ** we call a strftime variant that produces fewer characters for some years.  | 
    
    
    35  | 
     | 
     | 
    ** The ISO C 1999 and POSIX 1003.1-2004 standards prohibit padding the year,  | 
    
    
    36  | 
     | 
     | 
    ** but many implementations pad anyway; most likely the standards are buggy.  | 
    
    
    37  | 
     | 
     | 
    */  | 
    
    
    38  | 
     | 
     | 
    #define ASCTIME_FMT	"%.3s %.3s%3d %2.2d:%2.2d:%2.2d %-4s\n"  | 
    
    
    39  | 
     | 
     | 
     | 
    
    
    40  | 
     | 
     | 
    /*  | 
    
    
    41  | 
     | 
     | 
    ** For years that are more than four digits we put extra spaces before the year  | 
    
    
    42  | 
     | 
     | 
    ** so that code trying to overwrite the newline won't end up overwriting  | 
    
    
    43  | 
     | 
     | 
    ** a digit within a year and truncating the year (operating on the assumption  | 
    
    
    44  | 
     | 
     | 
    ** that no output is better than wrong output).  | 
    
    
    45  | 
     | 
     | 
    */  | 
    
    
    46  | 
     | 
     | 
    #define ASCTIME_FMT_B	"%.3s %.3s%3d %2.2d:%2.2d:%2.2d     %s\n"  | 
    
    
    47  | 
     | 
     | 
     | 
    
    
    48  | 
     | 
     | 
    #define STD_ASCTIME_BUF_SIZE	26  | 
    
    
    49  | 
     | 
     | 
    /*  | 
    
    
    50  | 
     | 
     | 
    ** Big enough for something such as  | 
    
    
    51  | 
     | 
     | 
    ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648     -2147483648\n  | 
    
    
    52  | 
     | 
     | 
    ** (two three-character abbreviations, five strings denoting integers,  | 
    
    
    53  | 
     | 
     | 
    ** seven explicit spaces, two explicit colons, a newline,  | 
    
    
    54  | 
     | 
     | 
    ** and a trailing ASCII nul).  | 
    
    
    55  | 
     | 
     | 
    ** The values above are for systems where an int is 32 bits and are provided  | 
    
    
    56  | 
     | 
     | 
    ** as an example; the define below calculates the maximum for the system at  | 
    
    
    57  | 
     | 
     | 
    ** hand.  | 
    
    
    58  | 
     | 
     | 
    */  | 
    
    
    59  | 
     | 
     | 
    #define MAX_ASCTIME_BUF_SIZE	(2*3+5*INT_STRLEN_MAXIMUM(int)+7+2+1+1)  | 
    
    
    60  | 
     | 
     | 
     | 
    
    
    61  | 
     | 
     | 
    static char *  | 
    
    
    62  | 
     | 
     | 
    asctime3(const struct tm *timeptr, char *buf, int bufsize)  | 
    
    
    63  | 
     | 
     | 
    { | 
    
    
    64  | 
     | 
     | 
    	static const char	wday_name[][4] = { | 
    
    
    65  | 
     | 
     | 
    		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"  | 
    
    
    66  | 
     | 
     | 
    	};  | 
    
    
    67  | 
     | 
     | 
    	static const char	mon_name[][4] = { | 
    
    
    68  | 
     | 
     | 
    		"Jan", "Feb", "Mar", "Apr", "May", "Jun",  | 
    
    
    69  | 
     | 
     | 
    		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"  | 
    
    
    70  | 
     | 
     | 
    	};  | 
    
    
    71  | 
     | 
     | 
    	const char *	wn;  | 
    
    
    72  | 
     | 
     | 
    	const char *	mn;  | 
    
    
    73  | 
     | 
     | 
    	char		year[INT_STRLEN_MAXIMUM(int) + 2];  | 
    
    
    74  | 
     | 
     | 
    	int		len;  | 
    
    
    75  | 
     | 
     | 
     | 
    
    
    76  | 
     | 
     | 
    	if (timeptr == NULL) { | 
    
    
    77  | 
     | 
     | 
    		errno = EINVAL;  | 
    
    
    78  | 
     | 
     | 
    		strlcpy(buf, "??? ??? ?? ??:??:?? ????\n", bufsize);  | 
    
    
    79  | 
     | 
     | 
    		return buf;  | 
    
    
    80  | 
     | 
     | 
    	}  | 
    
    
    81  | 
     | 
     | 
    	if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)  | 
    
    
    82  | 
     | 
     | 
    		wn = "???";  | 
    
    
    83  | 
     | 
     | 
    	else  | 
    
    
    84  | 
     | 
     | 
    		wn = wday_name[timeptr->tm_wday];  | 
    
    
    85  | 
     | 
     | 
    	if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)  | 
    
    
    86  | 
     | 
     | 
    		mn = "???";  | 
    
    
    87  | 
     | 
     | 
    	else  | 
    
    
    88  | 
     | 
     | 
    		mn = mon_name[timeptr->tm_mon];  | 
    
    
    89  | 
     | 
     | 
    	/*  | 
    
    
    90  | 
     | 
     | 
    	** Use strftime's %Y to generate the year, to avoid overflow problems  | 
    
    
    91  | 
     | 
     | 
    	** when computing timeptr->tm_year + TM_YEAR_BASE.  | 
    
    
    92  | 
     | 
     | 
    	** Assume that strftime is unaffected by other out-of-range members  | 
    
    
    93  | 
     | 
     | 
    	** (e.g., timeptr->tm_mday) when processing "%Y".  | 
    
    
    94  | 
     | 
     | 
    	*/  | 
    
    
    95  | 
     | 
     | 
    	(void) strftime(year, sizeof year, "%Y", timeptr);  | 
    
    
    96  | 
     | 
     | 
    	len = snprintf(buf, bufsize,  | 
    
    
    97  | 
     | 
     | 
    	    ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B),  | 
    
    
    98  | 
     | 
     | 
    	    wn, mn,  | 
    
    
    99  | 
     | 
     | 
    	    timeptr->tm_mday, timeptr->tm_hour,  | 
    
    
    100  | 
     | 
     | 
    	    timeptr->tm_min, timeptr->tm_sec,  | 
    
    
    101  | 
     | 
     | 
    	    year);  | 
    
    
    102  | 
     | 
     | 
    	if (len != -1 && len < bufsize) { | 
    
    
    103  | 
     | 
     | 
    		return buf;  | 
    
    
    104  | 
     | 
     | 
    	} else { | 
    
    
    105  | 
     | 
     | 
    		errno = EOVERFLOW;  | 
    
    
    106  | 
     | 
     | 
    		return NULL;  | 
    
    
    107  | 
     | 
     | 
    	}  | 
    
    
    108  | 
     | 
     | 
    }  | 
    
    
    109  | 
     | 
     | 
     | 
    
    
    110  | 
     | 
     | 
    /*  | 
    
    
    111  | 
     | 
     | 
    ** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, 2004 Edition.  | 
    
    
    112  | 
     | 
     | 
    */  | 
    
    
    113  | 
     | 
     | 
     | 
    
    
    114  | 
     | 
     | 
    char *  | 
    
    
    115  | 
     | 
     | 
    asctime_r(const struct tm *timeptr, char *buf)  | 
    
    
    116  | 
     | 
     | 
    { | 
    
    
    117  | 
     | 
     | 
    	/*  | 
    
    
    118  | 
     | 
     | 
    	** P1003 8.3.5.2 says that asctime_r() can only assume at most  | 
    
    
    119  | 
     | 
     | 
    	** a 26 byte buffer.  | 
    
    
    120  | 
     | 
     | 
    	*/  | 
    
    
    121  | 
     | 
     | 
    	return asctime3(timeptr, buf, STD_ASCTIME_BUF_SIZE);  | 
    
    
    122  | 
     | 
     | 
    }  | 
    
    
    123  | 
     | 
     | 
    DEF_WEAK(asctime_r);  | 
    
    
    124  | 
     | 
     | 
     | 
    
    
    125  | 
     | 
     | 
    /*  | 
    
    
    126  | 
     | 
     | 
    ** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, 2004 Edition.  | 
    
    
    127  | 
     | 
     | 
    */  | 
    
    
    128  | 
     | 
     | 
     | 
    
    
    129  | 
     | 
     | 
    char *  | 
    
    
    130  | 
     | 
     | 
    asctime(const struct tm *timeptr)  | 
    
    
    131  | 
     | 
     | 
    { | 
    
    
    132  | 
     | 
     | 
    	static char result[MAX_ASCTIME_BUF_SIZE];  | 
    
    
    133  | 
     | 
     | 
    	_THREAD_PRIVATE_KEY(asctime);  | 
    
    
    134  | 
     | 
     | 
    	char *resultp = (char *)_THREAD_PRIVATE(asctime, result, NULL);  | 
    
    
    135  | 
     | 
     | 
     | 
    
    
    136  | 
     | 
     | 
    	if (resultp == NULL)  | 
    
    
    137  | 
     | 
     | 
    		return NULL;  | 
    
    
    138  | 
     | 
     | 
    	else  | 
    
    
    139  | 
     | 
     | 
    		return asctime3(timeptr, resultp, sizeof(result));  | 
    
    
    140  | 
     | 
     | 
    }  | 
    
    
    141  | 
     | 
     | 
    DEF_STRONG(asctime);  |