* ext/date/date_strftime.c: should also be aware of flags on

complex specifier.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35659 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
tadf 2012-05-15 22:03:37 +00:00
Родитель b4bdb2f2eb
Коммит 00fd38644d
3 изменённых файлов: 76 добавлений и 31 удалений

Просмотреть файл

@ -1,3 +1,8 @@
Wed May 16 06:59:41 2012 Tadayoshi Funaba <tadf@dotrb.org>
* ext/date/date_strftime.c: should also be aware of flags on
complex specifier.
Wed May 16 05:11:29 2012 Aaron Patterson <aaron@tenderlovemaking.com>
* ext/psych/lib/psych/visitors/to_ruby.rb: fix a bug with string

Просмотреть файл

@ -23,6 +23,24 @@
#define div(x,y) (rb_funcall((x), rb_intern("div"), 1, (y)))
#define mod(x,y) (rb_funcall((x), '%', 1, (y)))
static void
upcase(char *s, size_t i)
{
do {
if (ISLOWER(*s))
*s = TOUPPER(*s);
} while (s++, --i);
}
static void
downcase(char *s, size_t i)
{
do {
if (ISUPPER(*s))
*s = TOLOWER(*s);
} while (s++, --i);
}
/* strftime --- produce formatted time */
static size_t
@ -37,7 +55,8 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
int v, w;
int precision, flags, colons;
char padding;
enum {LEFT, CHCASE, LOWER, UPPER, LOCALE_O, LOCALE_E};
/* LOCALE_[OE] and COLONS are actually modifiers, not flags */
enum {LEFT, CHCASE, LOWER, UPPER, LOCALE_O, LOCALE_E, COLONS};
#define BIT_OF(n) (1U<<(n))
/* various tables for locale C */
@ -64,7 +83,7 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
for (; *format && s < endp - 1; format++) {
#define FLAG_FOUND() do { \
if (precision > 0 || flags & (BIT_OF(LOCALE_E)|BIT_OF(LOCALE_O))) \
if (precision > 0 || flags & (BIT_OF(LOCALE_E) | BIT_OF(LOCALE_O) | BIT_OF(COLONS))) \
goto unknown; \
} while (0)
#define NEEDS(n) do if (s >= endp || (n) >= endp - s - 1) goto err; while (0)
@ -94,7 +113,9 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
do { \
i = date_strftime_with_tmx(s, endp - s, (fmt), tmx); \
if (!i) return 0; \
if (precision > i) { \
if (flags & BIT_OF(UPPER)) \
upcase(s, i); \
if (!(flags & BIT_OF(LEFT)) && precision > i) { \
if (start + maxsize < s + precision) { \
errno = ERANGE; \
return 0; \
@ -148,7 +169,7 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
case 'A': /* full weekday name */
case 'a': /* abbreviated weekday name */
if (flags & BIT_OF(CHCASE)) {
flags &= ~(BIT_OF(LOWER)|BIT_OF(CHCASE));
flags &= ~(BIT_OF(LOWER) | BIT_OF(CHCASE));
flags |= BIT_OF(UPPER);
}
{
@ -168,7 +189,7 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
case 'b': /* abbreviated month name */
case 'h': /* same as %b */
if (flags & BIT_OF(CHCASE)) {
flags &= ~(BIT_OF(LOWER)|BIT_OF(CHCASE));
flags &= ~(BIT_OF(LOWER) | BIT_OF(CHCASE));
flags |= BIT_OF(UPPER);
}
{
@ -311,8 +332,8 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
case 'P': /* am or pm based on 12-hour clock */
case 'p': /* AM or PM based on 12-hour clock */
if ((*format == 'p' && (flags & BIT_OF(CHCASE))) ||
(*format == 'P' && !(flags & (BIT_OF(CHCASE)|BIT_OF(UPPER))))) {
flags &= ~(BIT_OF(UPPER)|BIT_OF(CHCASE));
(*format == 'P' && !(flags & (BIT_OF(CHCASE) | BIT_OF(UPPER))))) {
flags &= ~(BIT_OF(UPPER) | BIT_OF(CHCASE));
flags |= BIT_OF(LOWER);
}
v = range(0, tmx_hour, 23);
@ -401,7 +422,7 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
case 'Z': /* time zone name or abbreviation */
if (flags & BIT_OF(CHCASE)) {
flags &= ~(BIT_OF(UPPER)|BIT_OF(CHCASE));
flags &= ~(BIT_OF(UPPER) | BIT_OF(CHCASE));
flags |= BIT_OF(LOWER);
}
{
@ -508,6 +529,10 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
}
continue;
case '+':
STRFTIME("%a %b %e %H:%M:%S %Z %Y");
continue;
case 'E':
/* POSIX locale extensions, ignored for now */
flags |= BIT_OF(LOCALE_E);
@ -522,9 +547,19 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
goto again;
goto unknown;
case '+':
STRFTIME("%a %b %e %H:%M:%S %Z %Y");
continue;
case ':':
flags |= BIT_OF(COLONS);
{
size_t l = strspn(format, ":");
format += l;
if (*format == 'z') {
colons = l;
format--;
goto again;
}
format -= l;
}
goto unknown;
case '_':
FLAG_FOUND();
@ -534,7 +569,6 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
case '-':
FLAG_FOUND();
flags |= BIT_OF(LEFT);
padding = precision = 0;
goto again;
case '^':
@ -547,16 +581,8 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
flags |= BIT_OF(CHCASE);
goto again;
case ':':
colons++;
goto again;
case '%':
FILL_PADDING(1);
*s++ = '%';
continue;
case '0':
FLAG_FOUND();
padding = '0';
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
@ -567,6 +593,11 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
goto again;
}
case '%':
FILL_PADDING(1);
*s++ = '%';
continue;
default:
unknown:
i = format - sp + 1;
@ -580,21 +611,15 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
if (i) {
FILL_PADDING(i);
memcpy(s, tp, i);
switch (flags & (BIT_OF(UPPER)|BIT_OF(LOWER))) {
switch (flags & (BIT_OF(UPPER) | BIT_OF(LOWER))) {
case BIT_OF(UPPER):
do {
if (ISLOWER(*s)) *s = TOUPPER(*s);
} while (s++, --i);
upcase(s, i);
break;
case BIT_OF(LOWER):
do {
if (ISUPPER(*s)) *s = TOLOWER(*s);
} while (s++, --i);
break;
default:
s += i;
downcase(s, i);
break;
}
s += i;
}
}
if (s >= endp) {

Просмотреть файл

@ -336,6 +336,21 @@ class TestDateStrftime < Test::Unit::TestCase
assert_equal('+09:08:07', d.strftime('%:::z'))
end
def test_strftime__gnuext_complex
d = DateTime.parse('2001-02-03T04:05:06+09:00')
assert_equal('Sat Feb 3 04:05:06 2001', d.strftime('%-100c'))
assert_equal('Sat Feb 3 04:05:06 2001'.rjust(100), d.strftime('%100c'))
assert_equal('Sat Feb 3 04:05:06 2001'.rjust(100), d.strftime('%_100c'))
assert_equal('Sat Feb 3 04:05:06 2001'.rjust(100, '0'), d.strftime('%0100c'))
assert_equal('SAT FEB 3 04:05:06 2001', d.strftime('%^c'))
assert_equal('Sat Feb 3 04:05:06 +09:00 2001', d.strftime('%-100+'))
assert_equal('Sat Feb 3 04:05:06 +09:00 2001'.rjust(100), d.strftime('%100+'))
assert_equal('Sat Feb 3 04:05:06 +09:00 2001'.rjust(100), d.strftime('%_100+'))
assert_equal('Sat Feb 3 04:05:06 +09:00 2001'.rjust(100, '0'), d.strftime('%0100+'))
assert_equal('SAT FEB 3 04:05:06 +09:00 2001', d.strftime('%^+'))
end
def test__different_format
d = Date.new(2001,2,3)