58 #include <sys/types.h>
61 #if defined(TM_IN_SYS_TIME) || !defined(GAWK)
62 #include <sys/types.h>
74 #define MAILHEADER_EXT 1
75 #define ISO_DATE_EXT 1
77 #if defined(ISO_DATE_EXT)
78 #if ! defined(POSIX2_DATE)
83 #if defined(POSIX2_DATE)
84 #if ! defined(SYSV_EXT)
87 #if ! defined(SUNOS_EXT)
92 #if defined(POSIX2_DATE)
93 #define adddecl(stuff) stuff
95 #define adddecl(stuff)
101 #if !defined __STDC__ && !defined _WIN32
108 static int weeknumber(
const struct tm *timeptr,
int firstweekday);
125 #define range(low, item, hi) max((low), min((item), (hi)))
140 return (a < b ? a : b);
156 return (a > b ? a : b);
159 #ifdef NO_STRING_LITERAL_CONCATENATION
160 #error No string literal concatenation
163 #define add(x,y) (rb_funcall((x), '+', 1, (y)))
164 #define sub(x,y) (rb_funcall((x), '-', 1, (y)))
165 #define mul(x,y) (rb_funcall((x), '*', 1, (y)))
166 #define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y)))
167 #define div(x,y) (rb_funcall((x), rb_intern("div"), 1, (y)))
168 #define mod(x,y) (rb_funcall((x), '%', 1, (y)))
174 const struct tmx *tmx)
176 char *endp = s + maxsize;
183 int precision, flags, colons;
185 enum {LEFT, CHCASE, LOWER, UPPER, LOCALE_O, LOCALE_E};
186 #define BIT_OF(n) (1U<<(n))
189 static const char days_l[][10] = {
190 "Sunday",
"Monday",
"Tuesday",
"Wednesday",
191 "Thursday",
"Friday",
"Saturday",
193 static const char months_l[][10] = {
194 "January",
"February",
"March",
"April",
195 "May",
"June",
"July",
"August",
"September",
196 "October",
"November",
"December",
198 static const char ampm[][3] = {
"AM",
"PM", };
200 if (s ==
NULL || format ==
NULL || tmx ==
NULL || maxsize == 0)
210 for (; *format && s < endp - 1; format++) {
211 #define FLAG_FOUND() do { \
212 if (precision > 0 || flags & (BIT_OF(LOCALE_E)|BIT_OF(LOCALE_O))) \
215 #define NEEDS(n) do if (s >= endp || (n) >= endp - s - 1) goto err; while (0)
216 #define FILL_PADDING(i) do { \
217 if (!(flags & BIT_OF(LEFT)) && precision > (i)) { \
219 memset(s, padding ? padding : ' ', precision - (i)); \
220 s += precision - (i); \
226 #define FMT(def_pad, def_prec, fmt, val) \
229 if (precision <= 0) precision = (def_prec); \
230 if (flags & BIT_OF(LEFT)) precision = 1; \
231 l = snprintf(s, endp - s, \
232 ((padding == '0' || (!padding && (def_pad) == '0')) ? "%0*"fmt : "%*"fmt), \
234 if (l < 0) goto err; \
237 #define STRFTIME(fmt) \
239 i = date_strftime_with_tmx(s, endp - s, (fmt), tmx); \
241 if (precision > i) {\
242 if (start + maxsize < s + precision) { \
246 memmove(s + precision - i, s, i);\
247 memset(s, padding ? padding : ' ', precision - i); \
252 #define FMTV(def_pad, def_prec, fmt, val) \
255 if (FIXNUM_P(tmp)) { \
256 FMT((def_pad), (def_prec), "l"fmt, FIX2LONG(tmp)); \
259 VALUE args[2], result; \
261 if (precision <= 0) precision = (def_prec); \
262 if (flags & BIT_OF(LEFT)) precision = 1; \
263 args[0] = INT2FIX(precision); \
265 if (padding == '0' || (!padding && (def_pad) == '0')) \
266 result = rb_str_format(2, args, rb_str_new2("%0*"fmt)); \
268 result = rb_str_format(2, args, rb_str_new2("%*"fmt)); \
269 l = strlcpy(s, StringValueCStr(result), endp-s); \
270 if ((size_t)(endp-s) <= l) \
276 if (*format !=
'%') {
298 if (flags &
BIT_OF(CHCASE)) {
304 if (wday < 0 || wday > 6)
307 i = 3, tp = days_l[wday];
312 if (flags &
BIT_OF(CHCASE)) {
318 if (wday < 0 || wday > 6)
321 i =
strlen(tp = days_l[wday]);
329 if (flags &
BIT_OF(CHCASE)) {
335 if (mon < 1 || mon > 12)
338 i = 3, tp = months_l[mon-1];
343 if (flags &
BIT_OF(CHCASE)) {
349 if (mon < 1 || mon > 12)
352 i =
strlen(tp = months_l[mon-1]);
362 FMT(
'0', 2,
"d", (
int)i);
367 FMT(
'0', 2,
"d", (
int)i);
376 FMT(
'0', 2,
"d", (
int)i);
385 FMT(
'0', 2,
"d", (
int)i);
390 FMT(
'0', 2,
"d", (
int)i);
395 if ((*format ==
'p' && (flags &
BIT_OF(CHCASE))) ||
396 (*format ==
'P' && !(flags & (
BIT_OF(CHCASE)|
BIT_OF(UPPER))))) {
418 FMT(
'0', 2,
"d", (
int)i);
427 FMT(
'0', 1,
"d", (
int)i);
444 FMT(
'0', 2,
"d", (
int)i);
452 FMT(
'0', 0 <= y ? 4 : 5,
"ld", y);
455 FMTV(
'0', 4,
"d", year);
460 #ifdef MAILHEADER_EXT
472 if ((aoff / 3600) < 10)
477 if (flags &
BIT_OF(LEFT) && hl == 1)
482 precision = precision <= (3 + hw) ? hw : precision-3;
483 NEEDS(precision + 3);
487 precision = precision <= (4 + hw) ? hw : precision-4;
488 NEEDS(precision + 4);
492 precision = precision <= (7 + hw) ? hw : precision-7;
493 NEEDS(precision + 7);
498 if (aoff % 3600 == 0) {
499 precision = precision <= (1 + hw) ? hw : precision-1;
500 NEEDS(precision + 3);
502 else if (aoff % 60 == 0) {
503 precision = precision <= (4 + hw) ? hw : precision-4;
504 NEEDS(precision + 4);
507 precision = precision <= (7 + hw) ? hw : precision-7;
508 NEEDS(precision + 7);
517 if (padding ==
' ' && precision > hl) {
518 i =
snprintf(s, endp - s,
"%*s", precision - hl,
"");
529 i =
snprintf(s, endp - s,
"%.*ld", precision, off / 3600);
533 if (colons == 3 && off == 0)
537 i =
snprintf(s, endp - s,
"%02d", (
int)(off / 60));
541 if (colons == 3 && off == 0)
545 i =
snprintf(s, endp - s,
"%02d", (
int)off);
554 if (flags &
BIT_OF(CHCASE)) {
603 FMT(
' ', 2,
"d", (
int)i);
612 FMT(
' ', 2,
"d", (
int)i);
629 flags |=
BIT_OF(LOCALE_E);
630 if (*(format + 1) &&
strchr(
"cCxXyY", *(format + 1)))
635 flags |=
BIT_OF(LOCALE_O);
636 if (*(format + 1) &&
strchr(
"deHImMSuUVwWy",
653 FMT(
'0', 2,
"d", (
int)i);
661 FMT(
'0', 0 <= y ? 4 : 5,
"ld", y);
664 FMTV(
'0', 4,
"d", year);
686 if (precision <= 0) {
727 STRFTIME(
"%a %b %e %H:%M:%S %Z %Y");
733 padding = precision = 0;
757 case '1':
case '2':
case '3':
case '4':
758 case '5':
case '6':
case '7':
case '8':
case '9':
761 precision = (int)strtoul(format, &e, 10);
799 if (*format ==
'\0') {
808 const struct tmx *tmx)
825 return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
829 tmx2tm_noyear(
const struct tmx *tmx,
struct tm *
result)
844 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
847 #if defined(HAVE_TM_ZONE)
859 const struct tm *timeptr;
879 int weeknum, jan1day;
897 jan1day = timeptr->tm_wday - (timeptr->tm_yday % 7);
926 #ifdef USE_BROKEN_XPG4
935 dec31ly.tm_mday = 31;
936 dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1;
937 dec31ly.tm_yday = 364 +
isleap(dec31ly.tm_year + 1900L);
944 if (timeptr->tm_mon == 11) {
958 wday = timeptr->tm_wday;
959 mday = timeptr->tm_mday;
960 if ( (wday == 1 && (mday >= 29 && mday <= 31))
961 || (wday == 2 && (mday == 30 || mday == 31))
962 || (wday == 3 && mday == 31))
973 tmx2tm_noyear(tmx, &tm);
986 const struct tm *timeptr;
990 weeknumber(
const struct tm *timeptr,
int firstweekday)
993 int wday = timeptr->tm_wday;
996 if (firstweekday == 1) {
1002 ret = ((timeptr->tm_yday + 7 - wday) / 7);
1012 tmx2tm_noyear(tmx, &tm);
1020 Date: Wed, 24 Apr 91 20:54:08 MDT
1021 From: Michal Jaegermann <audfax!emory!vm.ucs.UAlberta.CA!NTOMCZAK>
1022 To: arnold@audiofax.com
1025 in a process of fixing of strftime() in libraries on Atari ST
I grabbed
1026 some pieces of code from your own strftime. When doing that it came
1027 to mind that your
weeknumber() function compiles a little bit nicer
1028 in the following form:
1033 return (timeptr->tm_yday - timeptr->tm_wday +
1034 (firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7;
1036 How nicer it depends on a compiler, of course, but always a tiny bit.
1040 ntomczak@vm.ucs.ualberta.ca
1043 #ifdef TEST_STRFTIME
1076 #include <sys/time.h>
1085 static char *array[] =
1087 "(%%A) full weekday name, var length (Sunday..Saturday) %A",
1088 "(%%B) full month name, var length (January..December) %B",
1090 "(%%D) date (%%m/%%d/%%y) %D",
1091 "(%%E) Locale extensions (ignored) %E",
1092 "(%%H) hour (24-hour clock, 00..23) %H",
1093 "(%%I) hour (12-hour clock, 01..12) %I",
1094 "(%%M) minute (00..59) %M",
1095 "(%%O) Locale extensions (ignored) %O",
1096 "(%%R) time, 24-hour (%%H:%%M) %R",
1097 "(%%S) second (00..60) %S",
1098 "(%%T) time, 24-hour (%%H:%%M:%%S) %T",
1099 "(%%U) week of year, Sunday as first day of week (00..53) %U",
1100 "(%%V) week of year according to ISO 8601 %V",
1101 "(%%W) week of year, Monday as first day of week (00..53) %W",
1102 "(%%X) appropriate locale time representation (%H:%M:%S) %X",
1103 "(%%Y) year with century (1970...) %Y",
1104 "(%%Z) timezone (EDT), or blank if timezone not determinable %Z",
1105 "(%%a) locale's abbreviated weekday name (Sun..Sat) %a",
1106 "(%%b) locale's abbreviated month name (Jan..Dec) %b",
1107 "(%%c) full date (Sat Nov 4 12:02:33 1989)%n%t%t%t %c",
1108 "(%%d) day of the month (01..31) %d",
1109 "(%%e) day of the month, blank-padded ( 1..31) %e",
1110 "(%%h) should be same as (%%b) %h",
1111 "(%%j) day of the year (001..366) %j",
1112 "(%%k) hour, 24-hour clock, blank pad ( 0..23) %k",
1113 "(%%l) hour, 12-hour clock, blank pad ( 1..12) %l",
1114 "(%%m) month (01..12) %m",
1115 "(%%p) locale's AM or PM based on 12-hour clock %p",
1116 "(%%r) time, 12-hour (same as %%I:%%M:%%S %%p) %r",
1117 "(%%u) ISO 8601: Weekday as decimal number [1 (Monday) - 7] %u",
1118 "(%%v) VMS date (dd-bbb-YYYY) %v",
1119 "(%%w) day of week (0..6, Sunday == 0) %w",
1120 "(%%x) appropriate locale date representation %x",
1121 "(%%y) last two digits of year (00..99) %y",
1122 "(%%z) timezone offset east of GMT as HHMM (e.g. -0500) %z",
1134 char string[MAXTIME];
1146 tm = localtime(&clock);
1148 for (k = 0; next = array[k]; k++) {
1149 length = strftime(
string, MAXTIME, next, tm);
1150 printf(
"%s\n",
string);
static long NUM2LONG(VALUE x)
size_t strlen(const char *)
#define FMT(def_pad, def_prec, fmt, val)
static int max(int a, int b)
static int isleap(long year)
static int iso8601wknum_v(const struct vtm *vtm)
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
static size_t date_strftime_with_tmx(char *s, size_t maxsize, const char *format, const struct tmx *tmx)
static int iso8601wknum(struct tm *timeptr) const
static int min(int a, int b)
size_t date_strftime(char *s, size_t maxsize, const char *format, const struct tmx *tmx)
#define range(low, item, hi)
VALUE rb_str_format(int, const VALUE *, VALUE)
#define FMTV(def_pad, def_prec, fmt, val)
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
#define StringValueCStr(v)
static int weeknumber_v(const struct vtm *vtm, int firstweekday)
int main(int argc, char **argv)
VALUE rb_str_new2(const char *)