60 #include <sys/types.h> 63 #if defined(TM_IN_SYS_TIME) || !defined(GAWK) 64 #include <sys/types.h> 76 #define MAILHEADER_EXT 1 77 #define ISO_DATE_EXT 1 79 #if defined(ISO_DATE_EXT) 80 #if ! defined(POSIX2_DATE) 85 #if defined(POSIX2_DATE) 86 #if ! defined(SYSV_EXT) 89 #if ! defined(SUNOS_EXT) 94 #if defined(POSIX2_DATE) 95 #define adddecl(stuff) stuff 97 #define adddecl(stuff) 102 #if !defined __STDC__ && !defined _WIN32 104 static int weeknumber();
106 static int weeknumber_v();
107 adddecl(
static int iso8601wknum_v();)
109 static int weeknumber(
const struct tm *timeptr,
int firstweekday);
110 adddecl(
static int iso8601wknum(
const struct tm *timeptr);)
111 static int weeknumber_v(
const struct vtm *vtm,
int firstweekday);
112 adddecl(
static int iso8601wknum_v(
const struct vtm *vtm);)
125 #define range(low, item, hi) max((low), min((item), (hi))) 134 return (a < b ? a : b);
144 return (a > b ? a : b);
147 #ifdef NO_STRING_LITERAL_CONCATENATION 148 #error No string literal concatenation 151 #define add(x,y) (rb_funcall((x), '+', 1, (y))) 152 #define sub(x,y) (rb_funcall((x), '-', 1, (y))) 153 #define mul(x,y) (rb_funcall((x), '*', 1, (y))) 154 #define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y))) 155 #define div(x,y) (rb_funcall((x), rb_intern("div"), 1, (y))) 156 #define mod(x,y) (rb_funcall((x), '%', 1, (y))) 161 #define BIT_OF(n) (1U<<(n)) 164 resize_buffer(
VALUE ftime,
char *s,
const char **start,
const char **endp,
165 ptrdiff_t n,
size_t maxsize)
167 size_t len = s - *start;
168 size_t nlen = len + n * 2;
170 if (nlen < len || nlen > maxsize) {
182 buffer_size_check(
const char *s,
183 const char *format_end,
size_t format_len,
187 const char *format = format_end-format_len;
194 case_conv(
char *s, ptrdiff_t i,
int flags)
228 rb_strftime_with_timespec(
VALUE ftime,
const char *format,
size_t format_len,
230 struct timespec *ts,
int gmt,
size_t maxsize)
234 const char *start = s;
236 const char *
const format_end = format + format_len;
244 int precision, flags, colons;
246 #ifdef MAILHEADER_EXT 251 static const char days_l[][10] = {
252 "Sunday",
"Monday",
"Tuesday",
"Wednesday",
253 "Thursday",
"Friday",
"Saturday",
255 static const char months_l[][10] = {
256 "January",
"February",
"March",
"April",
257 "May",
"June",
"July",
"August",
"September",
258 "October",
"November",
"December",
260 static const char ampm[][3] = {
"AM",
"PM", };
262 if (format ==
NULL || format_len == 0 || vtm ==
NULL) {
275 for (; format < format_end; format++) {
276 #define FLAG_FOUND() do { \ 280 #define NEEDS(n) do { \ 281 if (s >= endp || (n) >= endp - s - 1) { \ 282 s = resize_buffer(ftime, s, &start, &endp, (n), maxsize); \ 283 buffer_size_check(s, format_end, format_len, enc); \ 286 #define FILL_PADDING(i) do { \ 287 if (!(flags & BIT_OF(LEFT)) && precision > (i)) { \ 289 memset(s, padding ? padding : ' ', precision - (i)); \ 290 s += precision - (i); \ 296 #define FMT_PADDING(fmt, def_pad) \ 297 (&"%*"fmt"\0""%0*"fmt[\ 298 (padding == '0' || (!padding && (def_pad) == '0')) ? \ 299 rb_strlen_lit("%*"fmt)+1 : 0]) 300 #define FMT_PRECISION(def_prec) \ 301 ((flags & BIT_OF(LEFT)) ? (1) : \ 302 (precision <= 0) ? (def_prec) : (precision)) 303 #define FMT(def_pad, def_prec, fmt, val) \ 305 precision = FMT_PRECISION(def_prec); \ 308 rb_str_set_len(ftime, len); \ 309 rb_str_catf(ftime, FMT_PADDING(fmt, def_pad), \ 311 RSTRING_GETMEM(ftime, s, len); \ 312 endp = (start = s) + rb_str_capacity(ftime); \ 315 #define STRFTIME(fmt) \ 318 rb_str_set_len(ftime, len); \ 319 if (!rb_strftime_with_timespec(ftime, (fmt), rb_strlen_lit(fmt), \ 320 enc, vtm, timev, ts, gmt, maxsize)) \ 322 s = RSTRING_PTR(ftime); \ 323 i = RSTRING_LEN(ftime) - len; \ 324 endp = (start = s) + rb_str_capacity(ftime); \ 326 if (i > 0) case_conv(s, i, flags); \ 327 if (precision > i) {\ 329 memmove(s + precision - i, s, i);\ 330 memset(s, padding ? padding : ' ', precision - i); \ 335 #define FMTV(def_pad, def_prec, fmt, val) \ 338 if (FIXNUM_P(tmp)) { \ 339 FMT((def_pad), (def_prec), "l"fmt, FIX2LONG(tmp)); \ 342 const int base = ((fmt[0] == 'x') ? 16 : \ 343 (fmt[0] == 'o') ? 8 : \ 345 precision = FMT_PRECISION(def_prec); \ 346 if (!padding) padding = (def_pad); \ 347 tmp = format_value(tmp, base); \ 348 i = RSTRING_LEN(tmp); \ 350 rb_str_set_len(ftime, s-start); \ 351 rb_str_append(ftime, tmp); \ 352 RSTRING_GETMEM(ftime, s, len); \ 353 endp = (start = s) + rb_str_capacity(ftime); \ 358 tp = memchr(format,
'%', format_end - format);
359 if (!tp) tp = format_end;
361 memcpy(s, format, tp - format);
364 if (format == format_end)
break;
373 if (++format >= format_end)
goto unknown;
385 if (vtm->wday < 0 || vtm->wday > 6)
388 i = 3, tp = days_l[vtm->wday];
396 if (vtm->wday < 0 || vtm->wday > 6)
399 i =
strlen(tp = days_l[vtm->wday]);
410 if (vtm->mon < 1 || vtm->mon > 12)
413 i = 3, tp = months_l[vtm->mon-1];
421 if (vtm->mon < 1 || vtm->mon > 12)
424 i =
strlen(tp = months_l[vtm->mon-1]);
432 i =
range(1, vtm->mday, 31);
433 FMT(
'0', 2,
"d", (
int)i);
437 i =
range(0, vtm->hour, 23);
438 FMT(
'0', 2,
"d", (
int)i);
442 i =
range(0, vtm->hour, 23);
447 FMT(
'0', 2,
"d", (
int)i);
451 i =
range(1, vtm->yday, 366);
452 FMT(
'0', 3,
"d", (
int)i);
456 i =
range(1, vtm->mon, 12);
457 FMT(
'0', 2,
"d", (
int)i);
461 i =
range(0, vtm->min, 59);
462 FMT(
'0', 2,
"d", (
int)i);
472 i =
range(0, vtm->hour, 23);
490 FMTV(
'0', 1,
"d", sec);
495 i =
range(0, vtm->sec, 60);
496 FMT(
'0', 2,
"d", (
int)i);
500 FMT(
'0', 2,
"d", weeknumber_v(vtm, 0));
504 i =
range(0, vtm->wday, 6);
505 FMT(
'0', 1,
"d", (
int)i);
509 FMT(
'0', 2,
"d", weeknumber_v(vtm, 1));
522 FMT(
'0', 2,
"d", (
int)i);
528 FMT(
'0', 0 <= y ? 4 : 5,
"ld", y);
531 FMTV(
'0', 4,
"d", vtm->year);
535 #ifdef MAILHEADER_EXT 552 precision = precision <= 5 ? 2 : precision-3;
553 NEEDS(precision + 3);
557 precision = precision <= 6 ? 2 : precision-4;
558 NEEDS(precision + 4);
562 precision = precision <= 9 ? 2 : precision-7;
563 NEEDS(precision + 7);
567 if (off % 3600 == 0) {
568 precision = precision <= 3 ? 2 : precision-1;
569 NEEDS(precision + 3);
571 else if (off % 60 == 0) {
572 precision = precision <= 6 ? 2 : precision-4;
573 NEEDS(precision + 4);
576 precision = precision <= 9 ? 2 : precision-7;
577 NEEDS(precision + 9);
585 i =
snprintf(s, endp - s, (padding ==
' ' ?
"%+*ld" :
"%+.*ld"),
586 precision + (padding ==
' '), sign * (off / 3600));
588 if (sign < 0 && off < 3600) {
589 *(padding ==
' ' ? s + i - 2 : s) =
'-';
593 if (colons == 3 && off == 0)
597 i =
snprintf(s, endp - s,
"%02d", (
int)(off / 60));
601 if (colons == 3 && off == 0)
605 i =
snprintf(s, endp - s,
"%02d", (
int)off);
622 if (vtm->zone ==
NULL) {
628 for (i = 0; i <
TBUFSIZE && tp[i]; i++) {
629 if ((
unsigned char)tp[i] > 0x7F) {
658 FMT(
' ', 2,
"d",
range(1, vtm->mday, 31));
676 i =
range(0, vtm->hour, 23);
677 FMT(
' ', 2,
"d", (
int)i);
681 i =
range(0, vtm->hour, 23);
686 FMT(
' ', 2,
"d", (
int)i);
705 if (!format[1] || !
strchr(
"cCxXyY", format[1]))
710 if (!format[1] || !
strchr(
"deHkIlmMSuUVwWy", format[1]))
715 FMT(
'0', 2,
"d", iso8601wknum_v(vtm));
720 FMT(
'0', 1,
"d", vtm->wday == 0 ? 7 : vtm->wday);
737 VALUE yv = vtm->year;
738 w = iso8601wknum_v(vtm);
739 if (vtm->mon == 12 && w == 1)
741 else if (vtm->mon == 1 && w >= 52)
744 if (*format ==
'G') {
747 FMT(
'0', 0 <= y ? 4 : 5,
"ld", y);
750 FMTV(
'0', 4,
"d", yv);
756 FMT(
'0', 2,
"ld", y);
779 if (precision <= 0) {
787 snprintf(s, endp - s,
"%09ld", subsec);
788 memset(s+9,
'0', precision-9);
793 for (i = 0; i < 9-precision; i++)
795 snprintf(s, endp - s,
"%0*ld", precision, subsec);
821 VALUE args[2], result;
839 padding = precision = 0;
858 for (colons = 1; colons <= 3; ++colons) {
859 if (format+colons >= format_end)
goto unknown;
860 if (format[colons] ==
'z')
break;
861 if (format[colons] !=
':')
goto unknown;
863 format += colons - 1;
868 case '1':
case '2':
case '3':
case '4':
869 case '5':
case '6':
case '7':
case '8':
case '9':
874 if (ov || u > INT_MAX)
goto unknown;
893 s = case_conv(s, i, flags);
896 if (format != format_end) {
906 strftime_size_limit(
size_t format_len)
908 size_t limit = format_len * (1*1024*1024);
909 if (limit < format_len) limit = format_len;
910 else if (limit < 1024) limit = 1024;
919 return rb_strftime_with_timespec(result, format, format_len, enc,
920 vtm, timev,
NULL, gmt,
921 strftime_size_limit(format_len));
929 return rb_strftime_with_timespec(result, format, format_len, enc,
931 strftime_size_limit(format_len));
936 rb_strftime_limit(
const char *format,
size_t format_len,
938 int gmt,
size_t maxsize)
941 return rb_strftime_with_timespec(result, format, format_len, enc,
942 vtm,
Qnil, ts, gmt, maxsize);
951 return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
956 vtm2tm_noyear(
const struct vtm *vtm,
struct tm *result)
963 tm.tm_mon = vtm->mon-1;
964 tm.tm_mday = vtm->mday;
965 tm.tm_hour = vtm->hour;
966 tm.tm_min = vtm->min;
967 tm.tm_sec = vtm->sec;
968 tm.tm_wday = vtm->wday;
969 tm.tm_yday = vtm->yday-1;
970 tm.tm_isdst = vtm->isdst;
971 #if defined(HAVE_STRUCT_TM_TM_GMTOFF) 972 tm.tm_gmtoff =
NUM2LONG(vtm->utc_offset);
974 #if defined(HAVE_TM_ZONE) 975 tm.tm_zone = (
char *)vtm->zone;
984 iso8601wknum(
const struct tm *timeptr)
1000 int weeknum, jan1day;
1003 weeknum = weeknumber(timeptr, 1);
1018 jan1day = timeptr->tm_wday - (timeptr->tm_yday % 7);
1047 #ifdef USE_BROKEN_XPG4 1055 dec31ly.tm_mon = 11;
1056 dec31ly.tm_mday = 31;
1057 dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1;
1058 dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900L);
1059 weeknum = iso8601wknum(& dec31ly);
1065 if (timeptr->tm_mon == 11) {
1079 wday = timeptr->tm_wday;
1080 mday = timeptr->tm_mday;
1081 if ( (wday == 1 && (mday >= 29 && mday <= 31))
1082 || (wday == 2 && (mday == 30 || mday == 31))
1083 || (wday == 3 && mday == 31))
1091 iso8601wknum_v(
const struct vtm *vtm)
1094 vtm2tm_noyear(vtm, &tm);
1095 return iso8601wknum(&tm);
1105 weeknumber(
const struct tm *timeptr,
int firstweekday)
1107 int wday = timeptr->tm_wday;
1110 if (firstweekday == 1) {
1116 ret = ((timeptr->tm_yday + 7 - wday) / 7);
1123 weeknumber_v(
const struct vtm *vtm,
int firstweekday)
1126 vtm2tm_noyear(vtm, &tm);
1127 return weeknumber(&tm, firstweekday);
1133 Date: Wed, 24 Apr 91 20:54:08 MDT
1134 From: Michal Jaegermann <audfax!emory!vm.ucs.UAlberta.CA!NTOMCZAK>
1135 To: arnold@audiofax.com
1138 in a process of fixing of strftime() in libraries on Atari ST
I grabbed
1139 some pieces of code from your own strftime. When doing that it came
1140 to mind that your weeknumber()
function compiles a little bit nicer
1141 in the following form:
1146 return (timeptr->tm_yday - timeptr->tm_wday +
1147 (firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7;
1149 How nicer it depends on a compiler, of course, but always a tiny bit.
1153 ntomczak@vm.ucs.ualberta.ca
1156 #ifdef TEST_STRFTIME 1188 #include <sys/time.h> 1197 static char *array[] =
1199 "(%%A) full weekday name, var length (Sunday..Saturday) %A",
1200 "(%%B) full month name, var length (January..December) %B",
1202 "(%%D) date (%%m/%%d/%%y) %D",
1203 "(%%E) Locale extensions (ignored) %E",
1204 "(%%H) hour (24-hour clock, 00..23) %H",
1205 "(%%I) hour (12-hour clock, 01..12) %I",
1206 "(%%M) minute (00..59) %M",
1207 "(%%O) Locale extensions (ignored) %O",
1208 "(%%R) time, 24-hour (%%H:%%M) %R",
1209 "(%%S) second (00..60) %S",
1210 "(%%T) time, 24-hour (%%H:%%M:%%S) %T",
1211 "(%%U) week of year, Sunday as first day of week (00..53) %U",
1212 "(%%V) week of year according to ISO 8601 %V",
1213 "(%%W) week of year, Monday as first day of week (00..53) %W",
1214 "(%%X) appropriate locale time representation (%H:%M:%S) %X",
1215 "(%%Y) year with century (1970...) %Y",
1216 "(%%Z) timezone (EDT), or blank if timezone not determinable %Z",
1217 "(%%a) locale's abbreviated weekday name (Sun..Sat) %a",
1218 "(%%b) locale's abbreviated month name (Jan..Dec) %b",
1219 "(%%c) full date (Sat Nov 4 12:02:33 1989)%n%t%t%t %c",
1220 "(%%d) day of the month (01..31) %d",
1221 "(%%e) day of the month, blank-padded ( 1..31) %e",
1222 "(%%h) should be same as (%%b) %h",
1223 "(%%j) day of the year (001..366) %j",
1224 "(%%k) hour, 24-hour clock, blank pad ( 0..23) %k",
1225 "(%%l) hour, 12-hour clock, blank pad ( 1..12) %l",
1226 "(%%m) month (01..12) %m",
1227 "(%%p) locale's AM or PM based on 12-hour clock %p",
1228 "(%%r) time, 12-hour (same as %%I:%%M:%%S %%p) %r",
1229 "(%%u) ISO 8601: Weekday as decimal number [1 (Monday) - 7] %u",
1230 "(%%v) VMS date (dd-bbb-YYYY) %v",
1231 "(%%w) day of week (0..6, Sunday == 0) %w",
1232 "(%%x) appropriate locale date representation %x",
1233 "(%%y) last two digits of year (00..99) %y",
1234 "(%%z) timezone offset east of GMT as HHMM (e.g. -0500) %z",
1246 char string[MAXTIME];
1257 clock = time((
long *) 0);
1258 tm = localtime(&clock);
1260 for (k = 0; next = array[k]; k++) {
1261 length = strftime(
string, MAXTIME, next, tm);
1262 printf(
"%s\n",
string);
size_t strlen(const char *)
void rb_syserr_fail_str(int e, VALUE mesg)
VALUE rb_fstring_cstr(const char *str)
VALUE rb_strftime_timespec(const char *format, size_t format_len, rb_encoding *enc, const struct vtm *vtm, struct timespec *ts, int gmt)
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
void rb_str_set_len(VALUE, long)
VALUE rb_strftime(const char *format, size_t format_len, rb_encoding *enc, const struct vtm *vtm, VALUE timev, int gmt)
VALUE rb_Integer(VALUE)
Equivalent to Kernel#Integer in Ruby.
VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
RUBY_EXTERN unsigned long ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow)
#define RB_TYPE_P(obj, type)
#define ECONV_INVALID_REPLACE
#define range(low, item, hi)
VALUE rb_big2str(VALUE x, int base)
VALUE rb_str_resize(VALUE, long)
VALUE rb_str_format(int, const VALUE *, VALUE)
void rb_str_modify_expand(VALUE, long)
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 *)
register unsigned int len
#define StringValueCStr(v)
#define ECONV_UNDEF_REPLACE
size_t rb_str_capacity(VALUE str)
#define FMT(def_pad, def_prec, fmt, val)
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
int main(int argc, char **argv)
rb_encoding * rb_ascii8bit_encoding(void)
#define FMTV(def_pad, def_prec, fmt, val)