asctime.c 4.7 KB

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