59 #include <sys/types.h>
62 #if defined(TM_IN_SYS_TIME) || !defined(GAWK)
63 #include <sys/types.h>
75 #define MAILHEADER_EXT 1
76 #define ISO_DATE_EXT 1
78 #if defined(ISO_DATE_EXT)
79 #if ! defined(POSIX2_DATE)
84 #if defined(POSIX2_DATE)
85 #if ! defined(SYSV_EXT)
88 #if ! defined(SUNOS_EXT)
93 #if defined(POSIX2_DATE)
94 #define adddecl(stuff) stuff
96 #define adddecl(stuff)
101 #if !defined __STDC__ && !defined _WIN32
108 static int weeknumber(
const struct tm *timeptr,
int firstweekday);
124 #define range(low, item, hi) max((low), min((item), (hi)))
133 return (a < b ? a : b);
143 return (a > b ? a : b);
146 #ifdef NO_STRING_LITERAL_CONCATENATION
147 #error No string literal concatenation
150 #define add(x,y) (rb_funcall((x), '+', 1, (y)))
151 #define sub(x,y) (rb_funcall((x), '-', 1, (y)))
152 #define mul(x,y) (rb_funcall((x), '*', 1, (y)))
153 #define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y)))
154 #define div(x,y) (rb_funcall((x), rb_intern("div"), 1, (y)))
155 #define mod(x,y) (rb_funcall((x), '%', 1, (y)))
167 const char *
const endp = s + maxsize;
168 const char *
const start = s;
176 int precision, flags, colons;
178 enum {LEFT, CHCASE, LOWER, UPPER};
179 #define BIT_OF(n) (1U<<(n))
180 #ifdef MAILHEADER_EXT
185 static const char days_l[][10] = {
186 "Sunday",
"Monday",
"Tuesday",
"Wednesday",
187 "Thursday",
"Friday",
"Saturday",
189 static const char months_l[][10] = {
190 "January",
"February",
"March",
"April",
191 "May",
"June",
"July",
"August",
"September",
192 "October",
"November",
"December",
194 static const char ampm[][3] = {
"AM",
"PM", };
196 if (s ==
NULL || format ==
NULL || vtm ==
NULL || maxsize == 0)
211 for (; *format && s < endp - 1; format++) {
212 #define FLAG_FOUND() do { \
216 #define NEEDS(n) do if (s >= endp || (n) >= endp - s - 1) goto err; while (0)
217 #define FILL_PADDING(i) do { \
218 if (!(flags & BIT_OF(LEFT)) && precision > (i)) { \
220 memset(s, padding ? padding : ' ', precision - (i)); \
221 s += precision - (i); \
227 #define FMT(def_pad, def_prec, fmt, val) \
230 if (precision <= 0) precision = (def_prec); \
231 if (flags & BIT_OF(LEFT)) precision = 1; \
232 l = snprintf(s, endp - s, \
233 ((padding == '0' || (!padding && (def_pad) == '0')) ? "%0*"fmt : "%*"fmt), \
235 if (l < 0) goto err; \
238 #define STRFTIME(fmt) \
240 i = rb_strftime_with_timespec(s, endp - s, (fmt), enc, vtm, timev, ts, gmt); \
242 if (precision > i) {\
244 memmove(s + precision - i, s, i);\
245 memset(s, padding ? padding : ' ', precision - i); \
250 #define FMTV(def_pad, def_prec, fmt, val) \
253 if (FIXNUM_P(tmp)) { \
254 FMT((def_pad), (def_prec), "l"fmt, FIX2LONG(tmp)); \
257 VALUE args[2], result; \
259 if (precision <= 0) precision = (def_prec); \
260 if (flags & BIT_OF(LEFT)) precision = 1; \
261 args[0] = INT2FIX(precision); \
263 if (padding == '0' || (!padding && (def_pad) == '0')) \
264 result = rb_str_format(2, args, rb_str_new2("%0*"fmt)); \
266 result = rb_str_format(2, args, rb_str_new2("%*"fmt)); \
267 l = strlcpy(s, StringValueCStr(result), endp-s); \
268 if ((size_t)(endp-s) <= l) \
274 if (*format !=
'%') {
296 if (flags &
BIT_OF(CHCASE)) {
303 i = 3, tp = days_l[vtm->
wday];
307 if (flags &
BIT_OF(CHCASE)) {
321 if (flags &
BIT_OF(CHCASE)) {
325 if (vtm->
mon < 1 || vtm->
mon > 12)
328 i = 3, tp = months_l[vtm->
mon-1];
332 if (flags &
BIT_OF(CHCASE)) {
336 if (vtm->
mon < 1 || vtm->
mon > 12)
348 FMT(
'0', 2,
"d", (
int)i);
353 FMT(
'0', 2,
"d", (
int)i);
362 FMT(
'0', 2,
"d", (
int)i);
371 FMT(
'0', 2,
"d", (
int)i);
376 FMT(
'0', 2,
"d", (
int)i);
381 if ((*format ==
'p' && (flags &
BIT_OF(CHCASE))) ||
382 (*format ==
'P' && !(flags & (
BIT_OF(CHCASE)|
BIT_OF(UPPER))))) {
404 FMTV(
'0', 1,
"d", sec);
410 FMT(
'0', 2,
"d", (
int)i);
419 FMT(
'0', 1,
"d", (
int)i);
436 FMT(
'0', 2,
"d", (
int)i);
442 FMT(
'0', 0 <= y ? 4 : 5,
"ld", y);
449 #ifdef MAILHEADER_EXT
465 precision = precision <= 5 ? 2 : precision-3;
466 NEEDS(precision + 3);
470 precision = precision <= 6 ? 2 : precision-4;
471 NEEDS(precision + 4);
475 precision = precision <= 9 ? 2 : precision-7;
476 NEEDS(precision + 7);
480 if (off % 3600 == 0) {
481 precision = precision <= 3 ? 2 : precision-1;
482 NEEDS(precision + 3);
484 else if (off % 60 == 0) {
485 precision = precision <= 6 ? 2 : precision-4;
486 NEEDS(precision + 4);
489 precision = precision <= 9 ? 2 : precision-7;
490 NEEDS(precision + 9);
498 i =
snprintf(s, endp - s, (padding ==
' ' ?
"%+*ld" :
"%+.*ld"),
499 precision + 1, sign * (off / 3600));
501 if (sign < 0 && off < 3600) {
502 *(padding ==
' ' ? s + i - 2 : s) =
'-';
506 if (colons == 3 && off == 0)
510 i =
snprintf(s, endp - s,
"%02d", (
int)(off / 60));
514 if (colons == 3 && off == 0)
518 i =
snprintf(s, endp - s,
"%02d", (
int)off);
526 if (flags &
BIT_OF(CHCASE)) {
541 for (i = 0; i <
TBUFSIZE && tp[
i]; i++) {
542 if ((
unsigned char)tp[i] > 0x7F) {
590 FMT(
' ', 2,
"d", (
int)i);
599 FMT(
' ', 2,
"d", (
int)i);
618 if (!format[1] || !
strchr(
"cCxXyY", format[1]))
623 if (!format[1] || !
strchr(
"deHkIlmMSuUVwWy", format[1]))
652 if (vtm->
mon == 12 && w == 1)
654 else if (vtm->
mon == 1 && w >= 52)
657 if (*format ==
'G') {
660 FMT(
'0', 0 <= y ? 4 : 5,
"ld", y);
663 FMTV(
'0', 4,
"d", yv);
669 FMT(
'0', 2,
"ld", y);
692 if (precision <= 0) {
700 snprintf(s, endp - s,
"%09ld", subsec);
701 memset(s+9,
'0', precision-9);
706 for (i = 0; i < 9-precision; i++)
708 snprintf(s, endp - s,
"%0*ld", precision, subsec);
751 padding = precision = 0;
771 size_t l = strspn(format,
":");
772 if (l > 3 || format[l] !=
'z')
goto unknown;
780 case '1':
case '2':
case '3':
case '4':
781 case '5':
case '6':
case '7':
case '8':
case '9':
784 precision = (int)strtoul(format, &e, 10);
822 if (*format ==
'\0') {
846 return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
858 tm.tm_mon = vtm->
mon-1;
859 tm.tm_mday = vtm->
mday;
860 tm.tm_hour = vtm->
hour;
861 tm.tm_min = vtm->
min;
862 tm.tm_sec = vtm->
sec;
863 tm.tm_wday = vtm->
wday;
864 tm.tm_yday = vtm->
yday-1;
865 tm.tm_isdst = vtm->
isdst;
866 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
869 #if defined(HAVE_TM_ZONE)
870 tm.tm_zone = (
char *)vtm->
zone;
895 int weeknum, jan1day;
913 jan1day = timeptr->tm_wday - (timeptr->tm_yday % 7);
942 #ifdef USE_BROKEN_XPG4
951 dec31ly.tm_mday = 31;
952 dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1;
953 dec31ly.tm_yday = 364 +
isleap(dec31ly.tm_year + 1900L);
960 if (timeptr->tm_mon == 11) {
974 wday = timeptr->tm_wday;
975 mday = timeptr->tm_mday;
976 if ( (wday == 1 && (mday >= 29 && mday <= 31))
977 || (wday == 2 && (mday == 30 || mday == 31))
978 || (wday == 3 && mday == 31))
1002 int wday = timeptr->tm_wday;
1005 if (firstweekday == 1) {
1011 ret = ((timeptr->tm_yday + 7 - wday) / 7);
1028 Date: Wed, 24 Apr 91 20:54:08 MDT
1029 From: Michal Jaegermann <audfax!emory!vm.ucs.UAlberta.CA!NTOMCZAK>
1030 To: arnold@audiofax.com
1033 in a process of fixing of strftime() in libraries on Atari ST
I grabbed
1034 some pieces of code from your own strftime. When doing that it came
1035 to mind that your
weeknumber() function compiles a little bit nicer
1036 in the following form:
1041 return (timeptr->tm_yday - timeptr->tm_wday +
1042 (firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7;
1044 How nicer it depends on a compiler, of course, but always a tiny bit.
1048 ntomczak@vm.ucs.ualberta.ca
1051 #ifdef TEST_STRFTIME
1083 #include <sys/time.h>
1092 static char *array[] =
1094 "(%%A) full weekday name, var length (Sunday..Saturday) %A",
1095 "(%%B) full month name, var length (January..December) %B",
1097 "(%%D) date (%%m/%%d/%%y) %D",
1098 "(%%E) Locale extensions (ignored) %E",
1099 "(%%H) hour (24-hour clock, 00..23) %H",
1100 "(%%I) hour (12-hour clock, 01..12) %I",
1101 "(%%M) minute (00..59) %M",
1102 "(%%O) Locale extensions (ignored) %O",
1103 "(%%R) time, 24-hour (%%H:%%M) %R",
1104 "(%%S) second (00..60) %S",
1105 "(%%T) time, 24-hour (%%H:%%M:%%S) %T",
1106 "(%%U) week of year, Sunday as first day of week (00..53) %U",
1107 "(%%V) week of year according to ISO 8601 %V",
1108 "(%%W) week of year, Monday as first day of week (00..53) %W",
1109 "(%%X) appropriate locale time representation (%H:%M:%S) %X",
1110 "(%%Y) year with century (1970...) %Y",
1111 "(%%Z) timezone (EDT), or blank if timezone not determinable %Z",
1112 "(%%a) locale's abbreviated weekday name (Sun..Sat) %a",
1113 "(%%b) locale's abbreviated month name (Jan..Dec) %b",
1114 "(%%c) full date (Sat Nov 4 12:02:33 1989)%n%t%t%t %c",
1115 "(%%d) day of the month (01..31) %d",
1116 "(%%e) day of the month, blank-padded ( 1..31) %e",
1117 "(%%h) should be same as (%%b) %h",
1118 "(%%j) day of the year (001..366) %j",
1119 "(%%k) hour, 24-hour clock, blank pad ( 0..23) %k",
1120 "(%%l) hour, 12-hour clock, blank pad ( 1..12) %l",
1121 "(%%m) month (01..12) %m",
1122 "(%%p) locale's AM or PM based on 12-hour clock %p",
1123 "(%%r) time, 12-hour (same as %%I:%%M:%%S %%p) %r",
1124 "(%%u) ISO 8601: Weekday as decimal number [1 (Monday) - 7] %u",
1125 "(%%v) VMS date (dd-bbb-YYYY) %v",
1126 "(%%w) day of week (0..6, Sunday == 0) %w",
1127 "(%%x) appropriate locale date representation %x",
1128 "(%%y) last two digits of year (00..99) %y",
1129 "(%%z) timezone offset east of GMT as HHMM (e.g. -0500) %z",
1141 char string[MAXTIME];
1152 clock = time((
long *) 0);
1153 tm = localtime(&clock);
1155 for (k = 0; next = array[k]; k++) {
1156 length = strftime(
string, MAXTIME, next, tm);
1157 printf(
"%s\n",
string);
size_t strlen(const char *)
static int max(int a, int b)
static int isleap(long year)
static int iso8601wknum_v(const struct vtm *vtm)
static size_t rb_strftime_with_timespec(char *s, size_t maxsize, const char *format, rb_encoding *enc, const struct vtm *vtm, VALUE timev, struct timespec *ts, int gmt)
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
size_t rb_strftime_timespec(char *s, size_t maxsize, const char *format, rb_encoding *enc, const struct vtm *vtm, struct timespec *ts, int gmt)
#define ECONV_INVALID_REPLACE
#define range(low, item, hi)
size_t rb_strftime(char *s, size_t maxsize, const char *format, rb_encoding *enc, const struct vtm *vtm, VALUE timev, int gmt)
VALUE rb_str_format(int, const VALUE *, VALUE)
rb_encoding * rb_usascii_encoding(void)
rb_encoding * rb_locale_encoding(void)
char * strchr(char *, char)
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
VALUE rb_str_new_cstr(const char *)
#define StringValueCStr(v)
static void vtm2tm_noyear(const struct vtm *vtm, struct tm *result)
#define ECONV_UNDEF_REPLACE
static int weeknumber_v(const struct vtm *vtm, int firstweekday)
static int iso8601wknum(const struct tm *timeptr)
#define FMT(def_pad, def_prec, fmt, val)
int main(int argc, char **argv)
rb_encoding * rb_ascii8bit_encoding(void)
#define FMTV(def_pad, def_prec, fmt, val)
VALUE rb_str_new2(const char *)