e$B$J$+$@$G$9!#e(B
At Fri, 22 Aug 2008 11:51:12 +0900,
Tanaka A. wrote in [ruby-dev:35909]:
e$B$N$h$&$K=q$1$k$N$G$9$,!"$3$A$i$Oe(BPerle$B$N$H$O0UL#$,0c$C$F!“e(B9e$B$h$jBg$-$$CM$r;XDje(B
e$B$7$?;~$K!”;XDj$7$?7e?t$K$J$k$h$&$KA0$Ke(B0e$B$r5M$a$k5!G=$G!"e(BNe$B0J30$NJQ49;XDjJ8e(B
e$B;z$G$b;H$($k$h$&$G$9!#e(B
e$B$A$g$C$H;n$7$F$_$F;W$C$?$N$G$9$,!"e(B9 e$B$h$jBg$-$JCM$r;XDj$7$?;~e(B
e$B$Oe(B 0 e$B$r1&$K$D$1$k$Y$-$8$c$J$$$G$9$+$M!#e(B
+1
Index: strftime.c
— strftime.c (revision 18771)
+++ strftime.c (working copy)
@@ -1,2 +1,4 @@
+/* -- c-file-style: “linux” -- /
+
/
- strftime.c
@@ -177,4 +179,5 @@ rb_strftime(char *s, size_t maxsize, con
char *endp = s + maxsize;
char *start = s;
- const char *sp, *tp;
auto char tbuf[100];
long off;
@@ -195,25 +198,27 @@ rb_strftime(char s, size_t maxsize, con
#endif / HAVE_TM_NAME /
#endif / HAVE_TM_ZONE */
-
int precision, flags;
-
enum {LEFT, CHCASE, LOWER, UPPER, SPACE, ZERO};
+#define BIT_OF(n) (1U<<(n))
/* various tables, useful in North America */
- static const char *days_a[] = {
- static const char days_a[][4] = {
“Sun”, “Mon”, “Tue”, “Wed”,
“Thu”, “Fri”, “Sat”,
};
- static const char *days_l[] = {
- static const char days_l[][10] = {
“Sunday”, “Monday”, “Tuesday”, “Wednesday”,
“Thursday”, “Friday”, “Saturday”,
};
- static const char *months_a[] = {
- static const char months_a[][4] = {
“Jan”, “Feb”, “Mar”, “Apr”, “May”, “Jun”,
“Jul”, “Aug”, “Sep”, “Oct”, “Nov”, “Dec”,
};
- static const char *months_l[] = {
- static const char months_l[][10] = {
“January”, “February”, “March”, “April”,
“May”, “June”, “July”, “August”, “September”,
“October”, “November”, “December”,
};
- static const char *ampm[] = { “AM”, “PM”, };
-
static const char ampm[][3] = { “AM”, “PM”, };
if (s == NULL || format == NULL || timeptr == NULL || maxsize == 0)
@@ -222,4 +227,5 @@ rb_strftime(char s, size_t maxsize, con
/ quick check if we even need to bother */
if (strchr(format, ‘%’) == NULL && strlen(format) + 1 >= maxsize) {
-
err:
errno = ERANGE;
return 0;
@@ -262,10 +268,29 @@ rb_strftime(char *s, size_t maxsize, con
for (; *format && s < endp - 1; format++) {
- tbuf[0] = ‘\0’;
+#define NEEDS(n) do if (s + (n) >= endp - 1) goto err; while (0)
+#define FMT(fmt, def_prec, val) \
- do { \
-
int l; \
-
if (precision == 0) break; \
-
if (precision < 0) precision = (def_prec); \
-
l = snprintf(s, endp - s, fmt, precision, val); \
-
if (l < 0) goto err; \
-
s += l; \
- } while (0)
+#define STRFTIME(fmt, tm) \
- do { \
-
i = strftime(s, endp - s, fmt, tm); \
-
if (!i) return 0; \
-
s += i; \
- } while (0)
- if (*format != ‘%’) {
*s++ = *format;
continue;
}
- tp = tbuf;
- sp = format;
precision = -1;
- flags = 0;
again:
switch (*++format) {
@@ -280,14 +305,14 @@ rb_strftime(char s, size_t maxsize, con
case ‘a’: / abbreviated weekday name */
if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6)
@@ -297,29 +322,29 @@ rb_strftime(char s, size_t maxsize, con
case ‘b’: / abbreviated month name */
if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)
-
STRFTIME("%a %b %e %H:%M:%S %Y", timeptr);
-
continue;
case ‘d’: /* day of the month, 01 - 31 */
i = range(1, timeptr->tm_mday, 31);
-
FMT("%.*d", 2, i);
-
continue;
case ‘H’: /* hour, 24-hour clock, 00 - 23 */
i = range(0, timeptr->tm_hour, 23);
-
FMT("%.*d", 2, i);
-
continue;
case ‘I’: /* hour, 12-hour clock, 01 - 12 */
@@ -329,63 +354,67 @@ rb_strftime(char *s, size_t maxsize, con
else if (i > 12)
i -= 12;
-
FMT("%.*d", 3, timeptr->tm_yday + 1);
-
continue;
case ‘m’: /* month, 01 - 12 */
i = range(0, timeptr->tm_mon, 11);
-
FMT("%.*d", 2, i);
-
continue;
case ‘p’: /* am or pm based on 12-hour clock */
-
if (flags & BIT_OF(CHCASE)) {
-
flags &= ~(BIT_OF(UPPER)|BIT_OF(CHCASE));
-
flags |= BIT_OF(LOWER);
-
}
i = range(0, timeptr->tm_hour, 23);
if (i < 12)
-
FMT("%.*d", 2, weeknumber(timeptr, 0));
-
continue;
case ‘w’: /* weekday, Sunday == 0, 0 - 6 */
i = range(0, timeptr->tm_wday, 6);
-
sprintf(tbuf, "%d", i);
-
break;
-
FMT("%.*d", 2, weeknumber(timeptr, 1));
-
continue;
case ‘x’: /* appropriate date representation */
-
STRFTIME("%H:%M:%S", timeptr);
-
continue;
case ‘y’: /* year without a century, 00 - 99 */
i = timeptr->tm_year % 100;
#ifdef MAILHEADER_EXT
@@ -407,6 +436,6 @@ rb_strftime(char s, size_t maxsize, con
case ‘z’: / time zone offset east of GMT e.g. -0600 */
if (gmt) {
-
strcpy(tbuf, "+0000");
-
break;
-
FMT("%+.*d", 4, 0);
-
continue;
}
#ifdef HAVE_TM_NAME
@@ -439,35 +468,38 @@ rb_strftime(char s, size_t maxsize, con
#endif / !HAVE_TM_NAME */
if (off < 0) {
-
FMT("%+.*ld", 4, off);
-
continue;
#endif /* MAILHEADER_EXT */
case 'Z': /* time zone name or abbrevation */
-
strcpy(tbuf, "UTC");
-
break;
#ifdef HAVE_TZNAME
i = (daylight && timeptr->tm_isdst > 0); /* 0 or 1 */
#else
#ifdef HAVE_TM_ZONE
#else
#ifdef HAVE_TM_NAME
#else
#ifdef HAVE_TIMEZONE
gettimeofday(& tv, & zone);
#ifdef TIMEZONE_VOID
#else
#endif /* TIMEZONE_VOID /
#endif / HAVE_TIMEZONE */
@@ -479,38 +511,38 @@ rb_strftime(char s, size_t maxsize, con
#ifdef SYSV_EXT
case ‘n’: / same as \n */
-
tbuf[0] = '\n';
-
tbuf[1] = '\0';
-
break;
-
tbuf[0] = '\t';
-
tbuf[1] = '\0';
-
break;
-
STRFTIME("%m/%d/%y", timeptr);
-
continue;
case ‘e’: /* day of month, blank padded */
-
sprintf(tbuf, "%2d", range(1, timeptr->tm_mday, 31));
-
break;
-
FMT("%.*d", 2, range(1, timeptr->tm_mday, 31));
-
continue;
case ‘r’: /* time as %I:%M:%S %p */
#endif
#ifdef SUNOS_EXT
case ‘k’: /* hour, 24-hour clock, blank pad */
-
sprintf(tbuf, "%2d", range(0, timeptr->tm_hour, 23));
-
break;
-
FMT("%*d", 2, range(0, timeptr->tm_hour, 23));
-
continue;
case ‘l’: /* hour, 12-hour clock, 1 - 12, blank pad */
@@ -520,6 +552,6 @@ rb_strftime(char *s, size_t maxsize, con
else if (i > 12)
i -= 12;
-
sprintf(tbuf, "%2d", i);
-
break;
-
FMT("%*d", 2, i);
-
continue;
#endif
@@ -527,12 +559,14 @@ rb_strftime(char s, size_t maxsize, con
#ifdef VMS_EXT
case ‘v’: / date as dd-bbb-YYYY */
-
sprintf(tbuf, "%2d-%3.3s-%4ld",
-
range(1, timeptr->tm_mday, 31),
-
months_a[range(0, timeptr->tm_mon, 11)],
-
timeptr->tm_year + 1900L);
-
w = snprintf(s, endp - s, "%2d-%3.3s-%4ld",
-
range(1, timeptr->tm_mday, 31),
-
months_a[range(0, timeptr->tm_mon, 11)],
-
timeptr->tm_year + 1900L);
-
if (w < 0) goto err;
for (i = 3; i < 6; i++)
-
if (islower(s[i]))
-
s[i] = toupper(s[i]);
-
s += w;
-
continue;
#endif
@@ -540,6 +574,6 @@ rb_strftime(char *s, size_t maxsize, con
#ifdef POSIX2_DATE
case ‘C’:
@@ -550,12 +584,11 @@ rb_strftime(char *s, size_t maxsize, con
case 'V': /* week of year according ISO 8601 */
-
FMT("%.*d", 2, iso8601wknum(timeptr));
-
continue;
case ‘u’:
/* ISO 8601: Weekday as a decimal number [1 (Monday) - 7] */
#endif /* POSIX2_DATE */
@@ -581,13 +614,14 @@ rb_strftime(char *s, size_t maxsize, con
if (*format == 'G')
#endif /* ISO_DATE_EXT */
-
-
case ‘L’:
-
w = 3;
-
goto subsec;
case ‘N’:
@@ -600,17 +634,25 @@ rb_strftime(char *s, size_t maxsize, con
* %9N nanosecond (9 digits)
*/
-
w = 9;
-
subsec:
{
-
if (precision == 0) continue;
-
if (precision < 0) {
-
precision = w;
-
}
-
NEEDS(precision);
-
if (precision < w) {
-
snprintf(tbuf, w + 1, "%.*ld", w, n);
-
memcpy(s, tbuf, precision);
}
-
if (precision == 0) break;
-
n /= pow(10, 9 - precision);
-
sprintf(fmt, "%%0%dld", precision);
-
sprintf(tbuf, fmt, n);
-
else {
-
snprintf(s, endp - s, "%.*ld", w, n);
-
memset(s + w, '0', precision - w);
-
}
-
s += precision;
}
-
continue;
case ‘F’: /* Equivalent to %Y-%m-%d */
@@ -619,39 +661,55 @@ rb_strftime(char *s, size_t maxsize, con
mon = range(0, timeptr->tm_mon, 11) + 1;
mday = range(1, timeptr->tm_mday, 31);
-
sprintf(tbuf, "%ld-%02d-%02d",
-
1900L + timeptr->tm_year, mon, mday);
-
i = snprintf(s, endp - s, "%ld-%02d-%02d",
-
1900L + timeptr->tm_year, mon, mday);
-
if (i < 0)
-
goto err;
-
s += i;
}
- case ‘-’:
-
flags |= BIT_OF(LEFT);
-
goto again;
-
- case ‘^’:
-
flags |= BIT_OF(UPPER);
-
goto again;
-
- case ‘#’:
-
flags |= BIT_OF(CHCASE);
-
goto again;
-
- case ‘_’:
-
flags |= BIT_OF(SPACE);
-
goto again;
-
- case ‘0’:
-
flags |= BIT_OF(ZERO);
- case ‘1’: case ‘2’: case ‘3’: case ‘4’:
- case ‘5’: case ‘6’: case ‘7’: case ‘8’: case ‘9’:
-
{
-
char *e;
-
precision = (int)strtoul(format, &e, 10);
-
format = e - 1;
goto again;
-
}
}
-
tbuf[0] = '%';
-
tbuf[1] = *format;
-
tbuf[2] = '\0';
-
break;
-
- default:
-
tp = sp;
-
i = format - sp + 1;
-
goto copy;
}
- i = strlen(tp);
- copy:
if (i) {
-
if (s + i < endp - 1) {
-
strcpy(s, tbuf);
-
s += i;
-
} else {
-
errno = ERANGE;
-
return 0;
-
}
-
NEEDS(i);
-
memcpy(s, tp, i);
-
s += i;
}
}
out:
if (s >= endp) {
- errno = ERANGE;
- return 0;
-
goto err;
}
if (*format == ‘\0’) {
Index: test/ruby/test_time.rb
===================================================================
— test/ruby/test_time.rb (revision 18771)
+++ test/ruby/test_time.rb (working copy)
@@ -382,15 +382,10 @@ class TestTime < Test::Unit::TestCase
t = Time.at(946684800, 123456.789)
- assert_equal(“123”, t.strftime("%L"))
- assert_equal(“123456789”, t.strftime("%N"))
assert_equal(“123”, t.strftime("%3N"))
assert_equal(“123456”, t.strftime("%6N"))
assert_equal(“123456789”, t.strftime("%9N"))
- assert_equal(“123456789”, t.strftime("%10N"))
- assert_equal(“123456789”, t.strftime("%1" + “0” * 100 + “N”))
- assert_equal(“1234567890”, t.strftime("%10N"))
assert_equal("", t.strftime("%0N"))
- assert_equal("%3S", t.strftime("%3S"))
- fmt = “%1” + “0” * 100 + “S”
- assert_equal(fmt, t.strftime(fmt))
-
assert_equal(“000”, t.strftime("%3S"))
t = Time.mktime(2001, 10, 1)
Index: lib/date/format.rb
===================================================================
— lib/date/format.rb (revision 18771)
+++ lib/date/format.rb (working copy)
@@ -154,6 +154,6 @@ class Date
end
@@ -258,10 +258,16 @@ class Date
when ‘k’; emit_a(hour, 2, f)
when ‘L’
- emit_n((sec_fraction / MILLISECONDS_IN_SECOND).floor, 3, f)
-
f[:n] = true
-
w = f[:w]
- s = emit_n((sec_fraction / MILLISECONDS_IN_SECOND).floor, 3, f)
-
w ? s[0, w] : s
when 'l'; emit_a((hour % 12).nonzero? || 12, 2, f)
when 'M', 'OM'; emit_n(min, 2, f)
when 'm', 'Om'; emit_n(mon, 2, f)
when 'N'
- emit_n((sec_fraction / NANOSECONDS_IN_SECOND).floor, 9, f)