From: nobuyoshi nakada Date: 2005-07-22T16:08:05+09:00 Subject: [ruby-dev:26599] Re: SystemCallError.new("abc") => # なかだです。 At Fri, 22 Jul 2005 00:43:09 +0900, H.Yamamoto wrote in [ruby-dev:26597]: > >それは環境を選びすぎでしょう。どこでもmissing/vsnprintf.cを使う > >ようにするんであれば、出力部分を差し替えられるようにして > >rb_str_cat()を呼ぶようにするという手もあります。 これを試してみました。 > 実際に計測してみると、vsnprintf(NULL, 0, .. の方法のほうが若干速いようなので、 > 使えるのなら使いたい気はするのです。ただ、この機能がない環境だと遅くなって > しまうので、やはり受け入れにくいかもしれません。 missing/vsnprintf.cが単純な分なのか、やや速くなるようです。 $ time ./.i686-cygwin/miniruby.exe -e '100000.times{SystemCallError.new("abc")}' real 0m1.260s user 0m1.265s sys 0m0.030s $ time ./.i686-cygwin/miniruby.exe -e '100000.times{SystemCallError.new("abc")}' real 0m1.207s user 0m1.202s sys 0m0.031s intern.h, error.c, string.cの差分は省略。 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 22 Jul 2005 06:33:28 -0000 @@ -16,4 +16,11 @@ #include #include +#ifdef HAVE_STDARG_PROTOTYPES +#include +#define va_init_list(a,b) va_start(a,b) +#else +#include +#define va_init_list(a,b) va_start(a) +#endif #define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */ @@ -97,4 +104,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 +246,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 +268,6 @@ rb_f_sprintf(argc, argv) VALUE str; - fmt = GETNTHARG(0); + ++argc; + --argv; if (OBJ_TAINTED(fmt)) tainted = 1; StringValue(fmt); @@ -381,11 +403,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; @@ -808,2 +831,80 @@ fmt_setup(buf, c, flags, width, prec) *buf = '\0'; } + +#undef FILE +#define FILE rb_printf_buffer +#define __sbuf rb_printf_sbuf +#define __sFILE rb_printf_sfile +#undef feof +#undef ferror +#undef fileno +#include "missing/vsnprintf.c" + +static int +ruby__sfvwrite(fp, uio) + register rb_printf_buffer *fp; + register struct __suio *uio; +{ + struct __siov *iov; + VALUE result = (VALUE)fp->_bf._base; + char *buf = fp->_p; + size_t len, n; + int blen = buf - RSTRING(result)->ptr, bsiz = fp->_w; + + if (RBASIC(result)->klass) { + rb_raise(rb_eRuntimeError, "rb_vsprintf reentered"); + } + if ((len = uio->uio_resid) == 0) + return 0; + CHECK(len); + fp->_w = bsiz; + for (iov = uio->uio_iov; len > 0; ++iov) { + MEMCPY(buf, iov->iov_base, char, n = iov->iov_len); + buf += n; + len -= n; + } + fp->_p = (unsigned char *)buf; + return 0; +} + +VALUE +rb_vsprintf(fmt, ap) + const char *fmt; + va_list ap; +{ + rb_printf_buffer f; + VALUE result; + + f._flags = __SWR | __SSTR; + f._bf._size = 0; + f._w = 120; + result = rb_str_buf_new(f._w); + f._bf._base = (unsigned char *)result; + f._p = (unsigned char *)RSTRING(result)->ptr; + RBASIC(result)->klass = 0; + f.vwrite = ruby__sfvwrite; + BSD_vfprintf(&f, fmt, ap); + RBASIC(result)->klass = rb_cString; + rb_str_resize(result, (char *)f._p - RSTRING(result)->ptr); + + 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: missing/vsnprintf.c =================================================================== RCS file: /cvs/ruby/src/ruby/missing/vsnprintf.c,v retrieving revision 1.8 diff -U2 -p -r1.8 vsnprintf.c --- missing/vsnprintf.c 1 Jul 2005 03:24:49 -0000 1.8 +++ missing/vsnprintf.c 22 Jul 2005 06:00:02 -0000 @@ -66,6 +66,12 @@ #define u_int unsigned int -#undef __P +#if !defined(HAVE_STDARG_PROTOTYPES) #if defined(__STDC__) +#define HAVE_STDARG_PROTOTYPES 1 +#endif +#endif + +#undef __P +#if defined(HAVE_STDARG_PROTOTYPES) # include # if !defined(__P) @@ -152,5 +158,7 @@ struct __sbuf { typedef struct __sFILE { unsigned char *_p; /* current position in (some) buffer */ +#if 0 int _r; /* read space left for getc() */ +#endif int _w; /* write space left for putc() */ short _flags; /* flags, below; this FILE is free if 0 */ @@ -158,4 +166,5 @@ typedef struct __sFILE { struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */ int _lbfsize; /* 0 or -_bf._size, for inline putc */ + int (*vwrite)(/* struct __sFILE*, struct __suio * */); } FILE; @@ -674,8 +683,7 @@ reswitch: switch (ch) { sign = '-'; } - } else { -#else /* _HAVE_SANE_QUAD_ */ - { + } else #endif /* _HAVE_SANE_QUAD_ */ + { ulval = SARG(); if ((long)ulval < 0) { @@ -1084,4 +1092,5 @@ vsnprintf(str, n, fmt, ap) f._bf._base = f._p = (unsigned char *)str; f._bf._size = f._w = n - 1; + f.vwrite = BSD__sfvwrite; ret = BSD_vfprintf(&f, fmt, ap); *f._p = 0; @@ -1093,12 +1102,6 @@ static char sccsid[] = "@(#)snprintf.c 8 #endif /* LIBC_SCCS and not lint */ -#if defined(__STDC__) -# include -#else -# include -#endif - int -#if defined(__STDC__) +#if defined(HAVE_STDARG_PROTOTYPES) snprintf(char *str, size_t n, char const *fmt, ...) #else @@ -1116,5 +1119,5 @@ va_dcl return (EOF); -#if defined(__STDC__) +#if defined(HAVE_STDARG_PROTOTYPES) va_start(ap, fmt); #else @@ -1124,4 +1127,5 @@ va_dcl f._bf._base = f._p = (unsigned char *)str; f._bf._size = f._w = n - 1; + f.vwrite = BSD__sfvwrite; ret = BSD_vfprintf(&f, fmt, ap); *f._p = 0; Index: win32/win32.c =================================================================== RCS file: /cvs/ruby/src/ruby/win32/win32.c,v retrieving revision 1.160 diff -U2 -p -r1.160 win32.c --- win32/win32.c 16 Jul 2005 06:59:05 -0000 1.160 +++ win32/win32.c 22 Jul 2005 06:39:23 -0000 @@ -3600,4 +3600,5 @@ rb_w32_utime(const char *path, struct ut } +#if 0 int rb_w32_vsnprintf(char *buf, size_t size, const char *format, va_list va) @@ -3619,4 +3620,5 @@ rb_w32_snprintf(char *buf, size_t size, return ret; } +#endif int Index: win32/win32.h =================================================================== RCS file: /cvs/ruby/src/ruby/win32/win32.h,v retrieving revision 1.67 diff -U2 -p -r1.67 win32.h --- win32/win32.h 16 Jul 2005 06:59:05 -0000 1.67 +++ win32/win32.h 22 Jul 2005 05:51:52 -0000 @@ -179,6 +179,8 @@ extern char **rb_w32_get_environ(void); extern void rb_w32_free_environ(char **); +#if 0 #define vsnprintf(s,n,f,l) rb_w32_vsnprintf(s,n,f,l) #define snprintf rb_w32_snprintf +#endif extern int rb_w32_vsnprintf(char *, size_t, const char *, va_list); extern int rb_w32_snprintf(char *, size_t, const char *, ...); -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦