15 #if defined(HAVE_SYS_TIME_H)
21 #define range(low, item, hi) (item)
23 #define add(x,y) (rb_funcall((x), '+', 1, (y)))
24 #define sub(x,y) (rb_funcall((x), '-', 1, (y)))
25 #define mul(x,y) (rb_funcall((x), '*', 1, (y)))
26 #define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y)))
27 #define div(x,y) (rb_funcall((x), rb_intern("div"), 1, (y)))
28 #define mod(x,y) (rb_funcall((x), '%', 1, (y)))
54 char *endp = s + maxsize;
64 enum {LEFT, CHCASE, LOWER, UPPER, LOCALE_O, LOCALE_E, COLONS};
65 #define BIT_OF(n) (1U<<(n))
68 static const char days_l[][10] = {
69 "Sunday",
"Monday",
"Tuesday",
"Wednesday",
70 "Thursday",
"Friday",
"Saturday",
72 static const char months_l[][10] = {
73 "January",
"February",
"March",
"April",
74 "May",
"June",
"July",
"August",
"September",
75 "October",
"November",
"December",
77 static const char ampm[][3] = {
"AM",
"PM", };
79 if (s ==
NULL || format ==
NULL || tmx ==
NULL || maxsize == 0)
89 for (; *format && s < endp - 1; format++) {
90 #define FLAG_FOUND() do { \
91 if (precision > 0 || flags & (BIT_OF(LOCALE_E) | BIT_OF(LOCALE_O) | BIT_OF(COLONS))) \
94 #define NEEDS(n) do if (s >= endp || (n) >= endp - s - 1) goto err; while (0)
95 #define FILL_PADDING(i) do { \
96 if (!(flags & BIT_OF(LEFT)) && precision > (i)) { \
98 memset(s, padding ? padding : ' ', precision - (i)); \
99 s += precision - (i); \
105 #define FMT(def_pad, def_prec, fmt, val) \
108 if (precision <= 0) precision = (def_prec); \
109 if (flags & BIT_OF(LEFT)) precision = 1; \
110 l = snprintf(s, endp - s, \
111 ((padding == '0' || (!padding && (def_pad) == '0')) ? \
112 "%0*"fmt : "%*"fmt), \
114 if (l < 0) goto err; \
117 #define STRFTIME(fmt) \
119 i = date_strftime_with_tmx(s, endp - s, (fmt), tmx); \
121 if (flags & BIT_OF(UPPER)) \
123 if (!(flags & BIT_OF(LEFT)) && precision > i) { \
124 if (start + maxsize < s + precision) { \
128 memmove(s + precision - i, s, i); \
129 memset(s, padding ? padding : ' ', precision - i); \
134 #define FMTV(def_pad, def_prec, fmt, val) \
137 if (FIXNUM_P(tmp)) { \
138 FMT((def_pad), (def_prec), "l"fmt, FIX2LONG(tmp)); \
141 VALUE args[2], result; \
143 if (precision <= 0) precision = (def_prec); \
144 if (flags & BIT_OF(LEFT)) precision = 1; \
145 args[0] = INT2FIX(precision); \
147 if (padding == '0' || (!padding && (def_pad) == '0')) \
148 result = rb_str_format(2, args, rb_str_new2("%0*"fmt)); \
150 result = rb_str_format(2, args, rb_str_new2("%*"fmt)); \
151 l = strlcpy(s, StringValueCStr(result), endp - s); \
152 if ((size_t)(endp - s) <= l) \
158 if (*format !=
'%') {
176 if (flags &
BIT_OF(CHCASE)) {
182 if (wday < 0 || wday > 6)
186 i =
strlen(tp = days_l[wday]);
188 i = 3, tp = days_l[wday];
196 if (flags &
BIT_OF(CHCASE)) {
202 if (mon < 1 || mon > 12)
206 i =
strlen(tp = months_l[mon - 1]);
208 i = 3, tp = months_l[mon - 1];
228 FMT((*format ==
'd') ?
'0' :
' ', 2,
"d", v);
241 FMT(
'0', 0 <= y ? 4 : 5,
"ld", y);
244 FMTV(
'0', 4,
"d", year);
258 FMT((*format ==
'H') ?
'0' :
' ', 2,
"d", v);
268 FMT((*format ==
'I') ?
'0' :
' ', 2,
"d", v);
304 (void)
snprintf(s, endp - s,
"%0*ld",
341 if ((*format ==
'p' && (flags &
BIT_OF(CHCASE))) ||
342 (*format ==
'P' && !(flags & (
BIT_OF(CHCASE) |
BIT_OF(UPPER))))) {
413 if (flags &
BIT_OF(CHCASE)) {
437 if ((aoff / 3600) < 10)
442 if (flags &
BIT_OF(LEFT) && hl == 1)
447 precision = precision <= (3 + hw) ? hw : precision - 3;
448 NEEDS(precision + 3);
452 precision = precision <= (4 + hw) ? hw : precision - 4;
453 NEEDS(precision + 4);
457 precision = precision <= (7 + hw) ? hw : precision - 7;
458 NEEDS(precision + 7);
463 if (aoff % 3600 == 0) {
464 precision = precision <= (1 + hw) ?
466 NEEDS(precision + 3);
468 else if (aoff % 60 == 0) {
469 precision = precision <= (4 + hw) ?
471 NEEDS(precision + 4);
474 precision = precision <= (7 + hw) ?
476 NEEDS(precision + 7);
485 if (padding ==
' ' && precision > hl) {
486 i =
snprintf(s, endp - s,
"%*s", precision - hl,
"");
497 i =
snprintf(s, endp - s,
"%.*ld", precision, off / 3600);
501 if (colons == 3 && off == 0)
505 i =
snprintf(s, endp - s,
"%02d", (
int)(off / 60));
509 if (colons == 3 && off == 0)
513 i =
snprintf(s, endp - s,
"%02d", (
int)off);
521 STRFTIME(
"%a %b %e %H:%M:%S %Z %Y");
526 flags |=
BIT_OF(LOCALE_E);
527 if (*(format + 1) &&
strchr(
"cCxXyY", *(format + 1)))
532 flags |=
BIT_OF(LOCALE_O);
533 if (*(format + 1) &&
strchr(
"deHkIlmMSuUVwWy", *(format + 1)))
540 size_t l = strspn(format,
":");
542 if (*format ==
'z') {
574 case '1':
case '2':
case '3':
case '4':
575 case '5':
case '6':
case '7':
case '8':
case '9':
578 precision = (int)strtoul(format, &e, 10);
615 if (*format ==
'\0') {
size_t strlen(const char *)
#define FMT(def_pad, def_prec, fmt, val)
static size_t date_strftime_with_tmx(char *s, size_t maxsize, const char *format, const struct tmx *tmx)
static void downcase(char *s, size_t i)
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
size_t date_strftime(char *s, size_t maxsize, const char *format, const struct tmx *tmx)
#define StringValueCStr(v)
#define range(low, item, hi)
VALUE rb_str_format(int, const VALUE *, VALUE)
#define FMTV(def_pad, def_prec, fmt, val)
char * strchr(char *, char)
static void upcase(char *s, size_t i)