117209Swollman/* 217209Swollman** This file is in the public domain, so clarified as of 3192625Sedwin** 1996-06-05 by Arthur David Olson. 417209Swollman*/ 515923Sscrappy 6192625Sedwin/* 7192625Sedwin** Avoid the temptation to punt entirely to strftime; 8192625Sedwin** the output of strftime is supposed to be locale specific 9192625Sedwin** whereas the output of asctime is supposed to be constant. 10192625Sedwin*/ 11192625Sedwin 12111010Snectar#include <sys/cdefs.h> 132708Swollman#ifndef lint 142708Swollman#ifndef NOID 15214411Sedwinstatic char elsieid[] __unused = "@(#)asctime.c 8.5"; 162708Swollman#endif /* !defined NOID */ 172708Swollman#endif /* !defined lint */ 1892986Sobrien__FBSDID("$FreeBSD$"); 192708Swollman 202708Swollman/*LINTLIBRARY*/ 212708Swollman 2271579Sdeischen#include "namespace.h" 232708Swollman#include "private.h" 2471579Sdeischen#include "un-namespace.h" 252708Swollman#include "tzfile.h" 262708Swollman 272708Swollman/* 28192625Sedwin** Some systems only handle "%.2d"; others only handle "%02d"; 29192625Sedwin** "%02.2d" makes (most) everybody happy. 30192625Sedwin** At least some versions of gcc warn about the %02.2d; 31192625Sedwin** we conditionalize below to avoid the warning. 322708Swollman*/ 33192625Sedwin/* 34192625Sedwin** All years associated with 32-bit time_t values are exactly four digits long; 35192625Sedwin** some years associated with 64-bit time_t values are not. 36192625Sedwin** Vintage programs are coded for years that are always four digits long 37192625Sedwin** and may assume that the newline always lands in the same place. 38192625Sedwin** For years that are less than four digits, we pad the output with 39192625Sedwin** leading zeroes to get the newline in the traditional place. 40192625Sedwin** The -4 ensures that we get four characters of output even if 41192625Sedwin** we call a strftime variant that produces fewer characters for some years. 42192625Sedwin** The ISO C 1999 and POSIX 1003.1-2004 standards prohibit padding the year, 43192625Sedwin** but many implementations pad anyway; most likely the standards are buggy. 44192625Sedwin*/ 45192625Sedwin#ifdef __GNUC__ 46192625Sedwin#define ASCTIME_FMT "%.3s %.3s%3d %2.2d:%2.2d:%2.2d %-4s\n" 47192625Sedwin#else /* !defined __GNUC__ */ 48192625Sedwin#define ASCTIME_FMT "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %-4s\n" 49192625Sedwin#endif /* !defined __GNUC__ */ 50192625Sedwin/* 51192625Sedwin** For years that are more than four digits we put extra spaces before the year 52192625Sedwin** so that code trying to overwrite the newline won't end up overwriting 53192625Sedwin** a digit within a year and truncating the year (operating on the assumption 54192625Sedwin** that no output is better than wrong output). 55192625Sedwin*/ 56192625Sedwin#ifdef __GNUC__ 57192625Sedwin#define ASCTIME_FMT_B "%.3s %.3s%3d %2.2d:%2.2d:%2.2d %s\n" 58192625Sedwin#else /* !defined __GNUC__ */ 59192625Sedwin#define ASCTIME_FMT_B "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %s\n" 60192625Sedwin#endif /* !defined __GNUC__ */ 612708Swollman 62192625Sedwin#define STD_ASCTIME_BUF_SIZE 26 63192625Sedwin/* 64192625Sedwin** Big enough for something such as 65192625Sedwin** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n 66192625Sedwin** (two three-character abbreviations, five strings denoting integers, 67192625Sedwin** seven explicit spaces, two explicit colons, a newline, 68192625Sedwin** and a trailing ASCII nul). 69192625Sedwin** The values above are for systems where an int is 32 bits and are provided 70192625Sedwin** as an example; the define below calculates the maximum for the system at 71192625Sedwin** hand. 72192625Sedwin*/ 73192625Sedwin#define MAX_ASCTIME_BUF_SIZE (2*3+5*INT_STRLEN_MAXIMUM(int)+7+2+1+1) 74192625Sedwin 75192625Sedwinstatic char buf_asctime[MAX_ASCTIME_BUF_SIZE]; 76192625Sedwin 77192625Sedwin/* 78192625Sedwin** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, 2004 Edition. 79192625Sedwin*/ 80192625Sedwin 812708Swollmanchar * 82130461Sstefanfasctime_r(timeptr, buf) 8335285Sphkconst struct tm * timeptr; 84130461Sstefanfchar * buf; 852708Swollman{ 862708Swollman static const char wday_name[][3] = { 872708Swollman "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 882708Swollman }; 892708Swollman static const char mon_name[][3] = { 902708Swollman "Jan", "Feb", "Mar", "Apr", "May", "Jun", 912708Swollman "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 922708Swollman }; 9392889Sobrien const char * wn; 9492889Sobrien const char * mn; 95192625Sedwin char year[INT_STRLEN_MAXIMUM(int) + 2]; 96192625Sedwin char result[MAX_ASCTIME_BUF_SIZE]; 972708Swollman 98214411Sedwin if (timeptr == NULL) { 99214411Sedwin errno = EINVAL; 100214411Sedwin return strcpy(buf, "??? ??? ?? ??:??:?? ????\n"); 101214411Sedwin } 1022708Swollman if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK) 1032708Swollman wn = "???"; 1042708Swollman else wn = wday_name[timeptr->tm_wday]; 1052708Swollman if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR) 1062708Swollman mn = "???"; 1072708Swollman else mn = mon_name[timeptr->tm_mon]; 1082708Swollman /* 109192625Sedwin ** Use strftime's %Y to generate the year, to avoid overflow problems 110192625Sedwin ** when computing timeptr->tm_year + TM_YEAR_BASE. 111192625Sedwin ** Assume that strftime is unaffected by other out-of-range members 112192625Sedwin ** (e.g., timeptr->tm_mday) when processing "%Y". 1132708Swollman */ 114192625Sedwin (void) strftime(year, sizeof year, "%Y", timeptr); 115192625Sedwin /* 116192625Sedwin ** We avoid using snprintf since it's not available on all systems. 117192625Sedwin */ 118192625Sedwin (void) sprintf(result, 119192625Sedwin ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B), 1202708Swollman wn, mn, 1212708Swollman timeptr->tm_mday, timeptr->tm_hour, 1222708Swollman timeptr->tm_min, timeptr->tm_sec, 123192625Sedwin year); 124214411Sedwin if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime) 125214411Sedwin return strcpy(buf, result); 126214411Sedwin else { 127192625Sedwin#ifdef EOVERFLOW 128192625Sedwin errno = EOVERFLOW; 129192625Sedwin#else /* !defined EOVERFLOW */ 130192625Sedwin errno = EINVAL; 131192625Sedwin#endif /* !defined EOVERFLOW */ 132192625Sedwin return NULL; 133192625Sedwin } 1342708Swollman} 135130461Sstefanf 136130461Sstefanf/* 137192625Sedwin** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, 2004 Edition. 138130461Sstefanf*/ 139130461Sstefanf 140130461Sstefanfchar * 141130461Sstefanfasctime(timeptr) 142130461Sstefanfconst struct tm * timeptr; 143130461Sstefanf{ 144192625Sedwin return asctime_r(timeptr, buf_asctime); 145130461Sstefanf} 146