aboutsummaryrefslogtreecommitdiffstats
path: root/strftime.c
diff options
context:
space:
mode:
Diffstat (limited to 'strftime.c')
-rw-r--r--strftime.c47
1 files changed, 36 insertions, 11 deletions
diff --git a/strftime.c b/strftime.c
index 1164db01d1..b02c482d3b 100644
--- a/strftime.c
+++ b/strftime.c
@@ -48,6 +48,7 @@
*/
#include "ruby/ruby.h"
+#include "ruby/encoding.h"
#include "timev.h"
#ifndef GAWK
@@ -167,13 +168,19 @@ max(int a, int b)
/* strftime --- produce formatted time */
+/*
+ * enc is the encoding of the format. It is used as the encoding of resulted
+ * string, but the name of the month and weekday are always US-ASCII. So it
+ * is only used for the timezone name on Windows.
+ */
static size_t
-rb_strftime_with_timespec(char *s, size_t maxsize, const char *format, const struct vtm *vtm, VALUE timev, struct timespec *ts, int gmt)
+rb_strftime_with_timespec(char *s, size_t maxsize, const char *format, rb_encoding *enc, const struct vtm *vtm, VALUE timev, struct timespec *ts, int gmt)
{
const char *const endp = s + maxsize;
const char *const start = s;
const char *sp, *tp;
- auto char tbuf[100];
+#define TBUFSIZE 100
+ auto char tbuf[TBUFSIZE];
long off;
ptrdiff_t i;
int w;
@@ -205,6 +212,11 @@ rb_strftime_with_timespec(char *s, size_t maxsize, const char *format, const str
return 0;
}
+ if (enc && (enc == rb_usascii_encoding() ||
+ enc == rb_ascii8bit_encoding() || enc == rb_locale_encoding())) {
+ enc = NULL;
+ }
+
for (; *format && s < endp - 1; format++) {
#define FLAG_FOUND() do { \
if (precision > 0 || flags & (BIT_OF(LOCALE_E)|BIT_OF(LOCALE_O))) \
@@ -234,7 +246,7 @@ rb_strftime_with_timespec(char *s, size_t maxsize, const char *format, const str
} while (0)
#define STRFTIME(fmt) \
do { \
- i = rb_strftime_with_timespec(s, endp - s, (fmt), vtm, timev, ts, gmt); \
+ i = rb_strftime_with_timespec(s, endp - s, (fmt), enc, vtm, timev, ts, gmt); \
if (!i) return 0; \
if (precision > i) {\
NEEDS(precision); \
@@ -506,11 +518,24 @@ rb_strftime_with_timespec(char *s, size_t maxsize, const char *format, const str
tp = "UTC";
break;
}
- if (vtm->zone == NULL)
- tp = "";
- else
+ if (vtm->zone == NULL) {
+ i = 0;
+ }
+ else {
tp = vtm->zone;
- i = strlen(tp);
+ if (enc) {
+ for (i = 0; i < TBUFSIZE && tp[i]; i++) {
+ if ((unsigned char)tp[i] > 0x7F) {
+ VALUE str = rb_str_conv_enc_opts(rb_str_new_cstr(tp), rb_locale_encoding(), enc, ECONV_UNDEF_REPLACE|ECONV_INVALID_REPLACE, Qnil);
+ i = strlcpy(tbuf, RSTRING_PTR(str), TBUFSIZE);
+ tp = tbuf;
+ break;
+ }
+ }
+ }
+ else
+ i = strlen(tp);
+ }
break;
#ifdef SYSV_EXT
@@ -782,15 +807,15 @@ rb_strftime_with_timespec(char *s, size_t maxsize, const char *format, const str
}
size_t
-rb_strftime(char *s, size_t maxsize, const char *format, const struct vtm *vtm, VALUE timev, int gmt)
+rb_strftime(char *s, size_t maxsize, const char *format, rb_encoding *enc, const struct vtm *vtm, VALUE timev, int gmt)
{
- return rb_strftime_with_timespec(s, maxsize, format, vtm, timev, NULL, gmt);
+ return rb_strftime_with_timespec(s, maxsize, format, enc, vtm, timev, NULL, gmt);
}
size_t
-rb_strftime_timespec(char *s, size_t maxsize, const char *format, const struct vtm *vtm, struct timespec *ts, int gmt)
+rb_strftime_timespec(char *s, size_t maxsize, const char *format, rb_encoding *enc, const struct vtm *vtm, struct timespec *ts, int gmt)
{
- return rb_strftime_with_timespec(s, maxsize, format, vtm, Qnil, ts, gmt);
+ return rb_strftime_with_timespec(s, maxsize, format, enc, vtm, Qnil, ts, gmt);
}
/* isleap --- is a year a leap year? */