[ruby-dev:26586] Re: SystemCallError.new("abc") => #<SystemCallError: unknown error - ab>
From:
nobuyoshi nakada <nobuyoshi.nakada@...>
Date:
2005-07-20 09:41:24 UTC
List:
ruby-dev #26586
なかだです。
At Wed, 20 Jul 2005 00:52:30 +0900,
Yukihiro Matsumoto wrote in [ruby-dev:26580]:
> |ところで、こんな感じのものを作って使いまわすのはどうでしょうか。
> |size_t len が必要なくなるのが嬉しい気がします。
>
> 本当は rb_sprintf() みたいなのを実現したいですね。でも、ちょっ
> とコストが。
ちと手抜きですが。
Index: error.c
===================================================================
RCS file: /cvs/ruby/src/ruby/error.c,v
retrieving revision 1.114
diff -U2 -p -r1.114 error.c
--- error.c 20 Jul 2005 01:08:13 -0000 1.114
+++ error.c 20 Jul 2005 08:54:11 -0000
@@ -957,12 +957,8 @@ syserr_initialize(argc, argv, self)
if (!NIL_P(mesg)) {
VALUE str = mesg;
- size_t len;
StringValue(str);
- len = strlen(err)+RSTRING(str)->len+3;
- mesg = rb_str_new(0, len);
- snprintf(RSTRING(mesg)->ptr, len+1, "%s - %.*s", err,
- (int)RSTRING(str)->len, RSTRING(str)->ptr);
- RSTRING(mesg)->len = strlen(RSTRING(mesg)->ptr);
+ mesg = rb_sprintf("%s - %.*s", err,
+ (int)RSTRING(str)->len, RSTRING(str)->ptr);
}
else {
Index: intern.h
===================================================================
RCS file: /cvs/ruby/src/ruby/intern.h,v
retrieving revision 1.172
diff -U2 -p -r1.172 intern.h
--- intern.h 14 Jul 2005 15:11:52 -0000 1.172
+++ intern.h 20 Jul 2005 09:27:26 -0000
@@ -16,4 +16,10 @@
#define RUBY_INTERN_H 1
+#ifdef HAVE_STDARG_PROTOTYPES
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+
/*
* Functions and variables that are used by more than one source file of
@@ -451,4 +457,7 @@ const char *ruby_signal_name _((int));
/* sprintf.c */
VALUE rb_f_sprintf _((int, VALUE*));
+VALUE rb_sprintf __((const char*, ...));
+VALUE rb_vsprintf _((const char*, va_list));
+VALUE rb_str_format _((int, VALUE *, VALUE));
/* string.c */
VALUE rb_str_new _((const char*, long));
Index: sprintf.c
===================================================================
RCS file: /cvs/ruby/src/ruby/sprintf.c,v
retrieving revision 1.46
diff -U2 -p -r1.46 sprintf.c
--- sprintf.c 7 Jun 2005 08:22:41 -0000 1.46
+++ sprintf.c 20 Jul 2005 09:34:35 -0000
@@ -16,4 +16,11 @@
#include <ctype.h>
#include <math.h>
+#ifdef HAVE_STDARG_PROTOTYPES
+#include <stdarg.h>
+#define va_init_list(a,b) va_start(a,b)
+#else
+#include <varargs.h>
+#define va_init_list(a,b) va_start(a)
+#endif
#define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */
@@ -82,4 +89,8 @@ sign_bits(base, p)
#define FWIDTH 32
#define FPREC 64
+#define FHALF 0200
+#define FLONG 0400
+#define FSIZE2 01000
+#define FFLOAT 02000
#define CHECK(l) do {\
@@ -97,4 +108,10 @@ sign_bits(base, p)
} while (0)
+#define FILL(c, l) do { \
+ CHECK(l);\
+ memset(&buf[blen], c, l);\
+ blen += (l);\
+} while (0)
+
#define GETARG() (nextvalue != Qundef ? nextvalue : \
posarg < 0 ? \
@@ -233,5 +250,13 @@ rb_f_sprintf(argc, argv)
VALUE *argv;
{
+ return rb_str_format(argc - 1, argv + 1, GETNTHARG(0));
+}
+
+VALUE
+rb_str_format(argc, argv, fmt)
+ int argc;
+ VALUE *argv;
VALUE fmt;
+{
const char *p, *end;
char *buf;
@@ -247,5 +272,6 @@ rb_f_sprintf(argc, argv)
VALUE str;
- fmt = GETNTHARG(0);
+ ++argc;
+ --argv;
if (OBJ_TAINTED(fmt)) tainted = 1;
StringValue(fmt);
@@ -381,11 +407,12 @@ rb_f_sprintf(argc, argv)
char c;
- if (!(flags & FMINUS))
- while (--width > 0)
- PUSH(" ", 1);
c = NUM2INT(val) & 0xff;
- PUSH(&c, 1);
- while (--width > 0)
- PUSH(" ", 1);
+ if (!(flags & FWIDTH)) {
+ PUSH(&c, 1);
+ }
+ else {
+ FILL(' ', width);
+ buf[blen - ((flags & FMINUS) ? width : 1)] = c;
+ }
}
break;
@@ -805,5 +832,263 @@ fmt_setup(buf, c, flags, width, prec)
}
+ switch (flags & (FLONG|FHALF|FSIZE2)) {
+#ifdef HAVE_LONG_LONG
+ case FLONG|FSIZE2:
+ *buf++ = 'l';
+#endif
+ case FLONG:
+ *buf++ = 'l';
+ break;
+ case FHALF|FSIZE2:
+ *buf++ = 'h';
+ case FHALF:
+ *buf++ = 'h';
+ break;
+#ifdef HAVE_LONG_DOUBLE
+ case FSIZE2:
+ *buf++ = 'L';
+ break;
+#endif
+ }
+
*buf++ = c;
*buf = '\0';
}
+
+VALUE
+rb_vsprintf(format, ap)
+ const char *format;
+ va_list ap;
+{
+ const char *p;
+ char *buf;
+ int blen, bsiz;
+ VALUE result;
+ char fmt[256];
+
+ int width, prec, flags = FNONE;
+ VALUE str;
+
+ p = format;
+ blen = 0;
+ bsiz = 120;
+ result = rb_str_buf_new(bsiz);
+ buf = RSTRING(result)->ptr;
+
+ for (p = format; *p; p++) {
+ const char *t;
+ int n;
+
+ for (t = p; *t && *t != '%'; t++) ;
+ PUSH(p, t - p);
+ if (!*t) break;
+ p = t + 1; /* skip `%' */
+
+ width = prec = -1;
+ retry:
+ switch (*p) {
+ default:
+ --p;
+ continue;
+
+ case ' ':
+ flags |= FSPACE;
+ p++;
+ goto retry;
+
+ case '#':
+ flags |= FSHARP;
+ p++;
+ goto retry;
+
+ case '+':
+ flags |= FPLUS;
+ p++;
+ goto retry;
+
+ case '-':
+ flags |= FMINUS;
+ p++;
+ goto retry;
+
+ case '0':
+ flags |= FZERO;
+ p++;
+ goto retry;
+
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = 0;
+ for (; ISDIGIT(*p); p++) {
+ n = 10 * n + (*p - '0');
+ }
+ width = n;
+ flags |= FWIDTH;
+ goto retry;
+
+ case '*':
+ flags |= FWIDTH;
+ width = va_arg(ap, int);
+ if (width < 0) {
+ flags |= FMINUS;
+ width = -width;
+ }
+ p++;
+ goto retry;
+
+ case '.':
+ flags |= FPREC;
+
+ prec = 0;
+ p++;
+ if (*p == '*') {
+ prec = va_arg(ap, int);
+ if (prec < 0) { /* ignore negative precision */
+ flags &= ~FPREC;
+ }
+ p++;
+ goto retry;
+ }
+
+ for (; ISDIGIT(*p); p++) {
+ prec = 10 * prec + (*p - '0');
+ }
+ goto retry;
+
+ case 'l':
+ if (flags & FLONG)
+ flags |= FSIZE2;
+ else
+ flags = (flags & ~(FSIZE2|FHALF)) | FLONG;
+ goto retry;
+
+ case 'h':
+ if (flags & FHALF)
+ flags |= FSIZE2;
+ else
+ flags = (flags & ~(FSIZE2|FLONG)) | FHALF;
+ goto retry;
+
+ case 'L':
+ flags = (flags & ~(FLONG|FHALF)) | FSIZE2;
+ goto retry;
+
+ case '\n':
+ p--;
+ case '%':
+ PUSH("%", 1);
+ break;
+
+ case 'n':
+ switch (flags & (FLONG|FHALF|FSIZE2)) {
+#ifdef HAVE_LONG_LONG
+ case FLONG|FSIZE2:
+ *va_arg(ap, LONG_LONG *) = (LONG_LONG)blen;
+ break;
+#endif
+ case FLONG:
+ *va_arg(ap, long *) = blen;
+ break;
+ case FHALF|FSIZE2:
+ *va_arg(ap, short *) = (short)blen;
+ break;
+ case FHALF:
+ *va_arg(ap, char *) = (char)blen;
+ break;
+ default:
+ *va_arg(ap, int*) = blen;
+ break;
+ }
+ break;
+
+ case 'c':
+ FILL(' ', width);
+ buf[blen - ((flags & FMINUS) ? width : 1)] = (va_arg(ap, int) & 0xff);
+ break;
+
+ case 'f':
+ case 'g':
+ case 'G':
+ case 'e':
+ case 'E':
+ flags |= FFLOAT;
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'x':
+ case 'X':
+ case 'u':
+ case 's':
+ case 'p':
+ {
+ fmt_setup(fmt, *p, flags, width, prec);
+ if (flags & FWIDTH) {
+ width += 32;
+ }
+ else {
+ width = 64;
+ }
+ CHECK(width);
+ if (*p == 's') {
+ snprintf(&buf[blen], width, fmt, va_arg(ap, const char *));
+ }
+ else if (*p == 'p') {
+ snprintf(&buf[blen], width, fmt, va_arg(ap, const void *));
+ }
+ else if (flags & FFLOAT) {
+ switch (flags & (FLONG|FHALF|FSIZE2)) {
+#ifdef HAVE_LONG_DOUBLE
+ case FSIZE2:
+ snprintf(&buf[blen], width, fmt, va_arg(ap, long double));
+ break;
+#endif
+ default:
+ snprintf(&buf[blen], width, fmt, va_arg(ap, double));
+ break;
+ }
+ }
+ else {
+ switch (flags & (FLONG|FHALF|FSIZE2)) {
+#ifdef HAVE_LONG_LONG
+ case FLONG|FSIZE2:
+ snprintf(&buf[blen], width, fmt, va_arg(ap, LONG_LONG));
+ break;
+#endif
+ case FLONG:
+ snprintf(&buf[blen], width, fmt, va_arg(ap, long));
+ break;
+ default:
+ snprintf(&buf[blen], width, fmt, va_arg(ap, int));
+ break;
+ }
+ }
+ blen += strlen(&buf[blen]);
+ }
+ break;
+ }
+ flags = FNONE;
+ }
+
+ rb_str_resize(result, blen);
+
+ return result;
+}
+
+VALUE
+#ifdef HAVE_STDARG_PROTOTYPES
+rb_sprintf(const char *format, ...)
+#else
+ruby_sprintf(format, va_alist)
+ const char *format;
+ va_dcl
+#endif
+{
+ VALUE result;
+ va_list ap;
+
+ va_init_list(ap, format);
+ result = rb_vsprintf(format, ap);
+ va_end(ap);
+
+ return result;
+}
Index: string.c
===================================================================
RCS file: /cvs/ruby/src/ruby/string.c,v
retrieving revision 1.230
diff -U2 -p -r1.230 string.c
--- string.c 4 Mar 2005 06:47:41 -0000 1.230
+++ string.c 20 Jul 2005 09:26:25 -0000
@@ -445,20 +445,11 @@ rb_str_times(str, times)
static VALUE
-rb_str_format(str, arg)
+rb_str_format_m(str, arg)
VALUE str, arg;
{
- VALUE *argv;
-
if (TYPE(arg) == T_ARRAY) {
- argv = ALLOCA_N(VALUE, RARRAY(arg)->len + 1);
- argv[0] = str;
- MEMCPY(argv+1, RARRAY(arg)->ptr, VALUE, RARRAY(arg)->len);
- return rb_f_sprintf(RARRAY(arg)->len+1, argv);
+ return rb_str_format(RARRAY(arg)->len, RARRAY(arg)->ptr, str);
}
-
- argv = ALLOCA_N(VALUE, 2);
- argv[0] = str;
- argv[1] = arg;
- return rb_f_sprintf(2, argv);
+ return rb_str_format(1, &arg, str);
}
@@ -4670,5 +4661,5 @@ Init_String()
rb_define_method(rb_cString, "+", rb_str_plus, 1);
rb_define_method(rb_cString, "*", rb_str_times, 1);
- rb_define_method(rb_cString, "%", rb_str_format, 1);
+ rb_define_method(rb_cString, "%", rb_str_format_m, 1);
rb_define_method(rb_cString, "[]", rb_str_aref_m, -1);
rb_define_method(rb_cString, "[]=", rb_str_aset_m, -1);
--
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
中田 伸悦