ext/stringio/stringio.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   stringio.c -
00004 
00005   $Author: yugui $
00006   $RoughId: stringio.c,v 1.13 2002/03/14 03:24:18 nobu Exp $
00007   created at: Tue Feb 19 04:10:38 JST 2002
00008 
00009   All the files in this distribution are covered under the Ruby's
00010   license (see the file COPYING).
00011 
00012 **********************************************************************/
00013 
00014 #include "ruby.h"
00015 #include "ruby/io.h"
00016 #include "ruby/encoding.h"
00017 #if defined(HAVE_FCNTL_H) || defined(_WIN32)
00018 #include <fcntl.h>
00019 #elif defined(HAVE_SYS_FCNTL_H)
00020 #include <sys/fcntl.h>
00021 #endif
00022 
00023 struct StringIO {
00024     VALUE string;
00025     long pos;
00026     long lineno;
00027     int flags;
00028     int count;
00029 };
00030 
00031 static void strio_init(int, VALUE *, struct StringIO *);
00032 
00033 #define IS_STRIO(obj) (rb_typeddata_is_kind_of(obj, &strio_data_type))
00034 #define error_inval(msg) (errno = EINVAL, rb_sys_fail(msg))
00035 
00036 static struct StringIO *
00037 strio_alloc(void)
00038 {
00039     struct StringIO *ptr = ALLOC(struct StringIO);
00040     ptr->string = Qnil;
00041     ptr->pos = 0;
00042     ptr->lineno = 0;
00043     ptr->flags = 0;
00044     ptr->count = 1;
00045     return ptr;
00046 }
00047 
00048 static void
00049 strio_mark(void *p)
00050 {
00051     struct StringIO *ptr = p;
00052     if (ptr) {
00053         rb_gc_mark(ptr->string);
00054     }
00055 }
00056 
00057 static void
00058 strio_free(void *p)
00059 {
00060     struct StringIO *ptr = p;
00061     if (--ptr->count <= 0) {
00062         xfree(ptr);
00063     }
00064 }
00065 
00066 static size_t
00067 strio_memsize(const void *p)
00068 {
00069     const struct StringIO *ptr = p;
00070     if (!ptr) return 0;
00071     return sizeof(struct StringIO);
00072 }
00073 
00074 static const rb_data_type_t strio_data_type = {
00075     "strio",
00076     strio_mark,
00077     strio_free,
00078     strio_memsize,
00079 };
00080 
00081 #define check_strio(self) ((struct StringIO*)rb_check_typeddata(self, &strio_data_type))
00082 
00083 static struct StringIO*
00084 get_strio(VALUE self)
00085 {
00086     struct StringIO *ptr = check_strio(rb_io_taint_check(self));
00087 
00088     if (!ptr) {
00089         rb_raise(rb_eIOError, "uninitialized stream");
00090     }
00091     return ptr;
00092 }
00093 
00094 static VALUE
00095 strio_substr(struct StringIO *ptr, long pos, long len)
00096 {
00097     VALUE str = ptr->string;
00098     rb_encoding *enc = rb_enc_get(str);
00099     long rlen = RSTRING_LEN(str) - pos;
00100 
00101     if (len > rlen) len = rlen;
00102     if (len < 0) len = 0;
00103     return rb_enc_str_new(RSTRING_PTR(str)+pos, len, enc);
00104 }
00105 
00106 #define StringIO(obj) get_strio(obj)
00107 
00108 #define CLOSED(ptr) (!((ptr)->flags & FMODE_READWRITE))
00109 #define READABLE(ptr) ((ptr)->flags & FMODE_READABLE)
00110 #define WRITABLE(ptr) ((ptr)->flags & FMODE_WRITABLE)
00111 
00112 static struct StringIO*
00113 readable(struct StringIO *ptr)
00114 {
00115     if (!READABLE(ptr)) {
00116         rb_raise(rb_eIOError, "not opened for reading");
00117     }
00118     return ptr;
00119 }
00120 
00121 static struct StringIO*
00122 writable(struct StringIO *ptr)
00123 {
00124     if (!WRITABLE(ptr)) {
00125         rb_raise(rb_eIOError, "not opened for writing");
00126     }
00127     if (!OBJ_TAINTED(ptr->string)) {
00128         rb_secure(4);
00129     }
00130     return ptr;
00131 }
00132 
00133 static void
00134 check_modifiable(struct StringIO *ptr)
00135 {
00136     if (OBJ_FROZEN(ptr->string)) {
00137         rb_raise(rb_eIOError, "not modifiable string");
00138     }
00139 }
00140 
00141 static VALUE
00142 strio_s_allocate(VALUE klass)
00143 {
00144     return TypedData_Wrap_Struct(klass, &strio_data_type, 0);
00145 }
00146 
00147 /*
00148  * call-seq: StringIO.new(string=""[, mode])
00149  *
00150  * Creates new StringIO instance from with _string_ and _mode_.
00151  */
00152 static VALUE
00153 strio_initialize(int argc, VALUE *argv, VALUE self)
00154 {
00155     struct StringIO *ptr = check_strio(self);
00156 
00157     if (!ptr) {
00158         DATA_PTR(self) = ptr = strio_alloc();
00159     }
00160     rb_call_super(0, 0);
00161     strio_init(argc, argv, ptr);
00162     return self;
00163 }
00164 
00165 static void
00166 strio_init(int argc, VALUE *argv, struct StringIO *ptr)
00167 {
00168     VALUE string, mode;
00169     int trunc = 0;
00170 
00171     switch (rb_scan_args(argc, argv, "02", &string, &mode)) {
00172       case 2:
00173         if (FIXNUM_P(mode)) {
00174             int flags = FIX2INT(mode);
00175             ptr->flags = rb_io_modenum_flags(flags);
00176             trunc = flags & O_TRUNC;
00177         }
00178         else {
00179             const char *m = StringValueCStr(mode);
00180             ptr->flags = rb_io_mode_flags(m);
00181             trunc = *m == 'w';
00182         }
00183         StringValue(string);
00184         if ((ptr->flags & FMODE_WRITABLE) && OBJ_FROZEN(string)) {
00185             errno = EACCES;
00186             rb_sys_fail(0);
00187         }
00188         if (trunc) {
00189             rb_str_resize(string, 0);
00190         }
00191         break;
00192       case 1:
00193         StringValue(string);
00194         ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
00195         break;
00196       case 0:
00197         string = rb_enc_str_new("", 0, rb_default_external_encoding());
00198         ptr->flags = FMODE_READWRITE;
00199         break;
00200     }
00201     ptr->string = string;
00202     ptr->pos = 0;
00203     ptr->lineno = 0;
00204 }
00205 
00206 static VALUE
00207 strio_finalize(VALUE self)
00208 {
00209     struct StringIO *ptr = StringIO(self);
00210     ptr->string = Qnil;
00211     ptr->flags &= ~FMODE_READWRITE;
00212     return self;
00213 }
00214 
00215 /*
00216  * call-seq: StringIO.open(string=""[, mode]) {|strio| ...}
00217  *
00218  * Equivalent to StringIO.new except that when it is called with a block, it
00219  * yields with the new instance and closes it, and returns the result which
00220  * returned from the block.
00221  */
00222 static VALUE
00223 strio_s_open(int argc, VALUE *argv, VALUE klass)
00224 {
00225     VALUE obj = rb_class_new_instance(argc, argv, klass);
00226     if (!rb_block_given_p()) return obj;
00227     return rb_ensure(rb_yield, obj, strio_finalize, obj);
00228 }
00229 
00230 /*
00231  * Returns +false+.  Just for compatibility to IO.
00232  */
00233 static VALUE
00234 strio_false(VALUE self)
00235 {
00236     StringIO(self);
00237     return Qfalse;
00238 }
00239 
00240 /*
00241  * Returns +nil+.  Just for compatibility to IO.
00242  */
00243 static VALUE
00244 strio_nil(VALUE self)
00245 {
00246     StringIO(self);
00247     return Qnil;
00248 }
00249 
00250 /*
00251  * Returns *strio* itself.  Just for compatibility to IO.
00252  */
00253 static VALUE
00254 strio_self(VALUE self)
00255 {
00256     StringIO(self);
00257     return self;
00258 }
00259 
00260 /*
00261  * Returns 0.  Just for compatibility to IO.
00262  */
00263 static VALUE
00264 strio_0(VALUE self)
00265 {
00266     StringIO(self);
00267     return INT2FIX(0);
00268 }
00269 
00270 /*
00271  * Returns the argument unchanged.  Just for compatibility to IO.
00272  */
00273 static VALUE
00274 strio_first(VALUE self, VALUE arg)
00275 {
00276     StringIO(self);
00277     return arg;
00278 }
00279 
00280 /*
00281  * Raises NotImplementedError.
00282  */
00283 static VALUE
00284 strio_unimpl(int argc, VALUE *argv, VALUE self)
00285 {
00286     StringIO(self);
00287     rb_notimplement();
00288     return Qnil;                /* not reached */
00289 }
00290 
00291 /*
00292  * call-seq: strio.string     -> string
00293  *
00294  * Returns underlying String object, the subject of IO.
00295  */
00296 static VALUE
00297 strio_get_string(VALUE self)
00298 {
00299     return StringIO(self)->string;
00300 }
00301 
00302 /*
00303  * call-seq:
00304  *   strio.string = string  -> string
00305  *
00306  * Changes underlying String object, the subject of IO.
00307  */
00308 static VALUE
00309 strio_set_string(VALUE self, VALUE string)
00310 {
00311     struct StringIO *ptr = StringIO(self);
00312 
00313     rb_io_taint_check(self);
00314     ptr->flags &= ~FMODE_READWRITE;
00315     StringValue(string);
00316     ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
00317     ptr->pos = 0;
00318     ptr->lineno = 0;
00319     return ptr->string = string;
00320 }
00321 
00322 /*
00323  * call-seq:
00324  *   strio.close  -> nil
00325  *
00326  * Closes strio.  The *strio* is unavailable for any further data
00327  * operations; an +IOError+ is raised if such an attempt is made.
00328  */
00329 static VALUE
00330 strio_close(VALUE self)
00331 {
00332     struct StringIO *ptr = StringIO(self);
00333     if (CLOSED(ptr)) {
00334         rb_raise(rb_eIOError, "closed stream");
00335     }
00336     ptr->flags &= ~FMODE_READWRITE;
00337     return Qnil;
00338 }
00339 
00340 /*
00341  * call-seq:
00342  *   strio.close_read    -> nil
00343  *
00344  * Closes the read end of a StringIO.  Will raise an +IOError+ if the
00345  * *strio* is not readable.
00346  */
00347 static VALUE
00348 strio_close_read(VALUE self)
00349 {
00350     struct StringIO *ptr = StringIO(self);
00351     if (!READABLE(ptr)) {
00352         rb_raise(rb_eIOError, "closing non-duplex IO for reading");
00353     }
00354     ptr->flags &= ~FMODE_READABLE;
00355     return Qnil;
00356 }
00357 
00358 /*
00359  * call-seq:
00360  *   strio.close_write    -> nil
00361  *
00362  * Closes the write end of a StringIO.  Will raise an  +IOError+ if the
00363  * *strio* is not writeable.
00364  */
00365 static VALUE
00366 strio_close_write(VALUE self)
00367 {
00368     struct StringIO *ptr = StringIO(self);
00369     if (!WRITABLE(ptr)) {
00370         rb_raise(rb_eIOError, "closing non-duplex IO for writing");
00371     }
00372     ptr->flags &= ~FMODE_WRITABLE;
00373     return Qnil;
00374 }
00375 
00376 /*
00377  * call-seq:
00378  *   strio.closed?    -> true or false
00379  *
00380  * Returns +true+ if *strio* is completely closed, +false+ otherwise.
00381  */
00382 static VALUE
00383 strio_closed(VALUE self)
00384 {
00385     struct StringIO *ptr = StringIO(self);
00386     if (!CLOSED(ptr)) return Qfalse;
00387     return Qtrue;
00388 }
00389 
00390 /*
00391  * call-seq:
00392  *   strio.closed_read?    -> true or false
00393  *
00394  * Returns +true+ if *strio* is not readable, +false+ otherwise.
00395  */
00396 static VALUE
00397 strio_closed_read(VALUE self)
00398 {
00399     struct StringIO *ptr = StringIO(self);
00400     if (READABLE(ptr)) return Qfalse;
00401     return Qtrue;
00402 }
00403 
00404 /*
00405  * call-seq:
00406  *   strio.closed_write?    -> true or false
00407  *
00408  * Returns +true+ if *strio* is not writable, +false+ otherwise.
00409  */
00410 static VALUE
00411 strio_closed_write(VALUE self)
00412 {
00413     struct StringIO *ptr = StringIO(self);
00414     if (WRITABLE(ptr)) return Qfalse;
00415     return Qtrue;
00416 }
00417 
00418 /*
00419  * call-seq:
00420  *   strio.eof     -> true or false
00421  *   strio.eof?    -> true or false
00422  *
00423  * Returns true if *strio* is at end of file. The stringio must be
00424  * opened for reading or an +IOError+ will be raised.
00425  */
00426 static VALUE
00427 strio_eof(VALUE self)
00428 {
00429     struct StringIO *ptr = readable(StringIO(self));
00430     if (ptr->pos < RSTRING_LEN(ptr->string)) return Qfalse;
00431     return Qtrue;
00432 }
00433 
00434 /* :nodoc: */
00435 static VALUE
00436 strio_copy(VALUE copy, VALUE orig)
00437 {
00438     struct StringIO *ptr;
00439 
00440     orig = rb_convert_type(orig, T_DATA, "StringIO", "to_strio");
00441     if (copy == orig) return copy;
00442     ptr = StringIO(orig);
00443     if (check_strio(copy)) {
00444         strio_free(DATA_PTR(copy));
00445     }
00446     DATA_PTR(copy) = ptr;
00447     OBJ_INFECT(copy, orig);
00448     ++ptr->count;
00449     return copy;
00450 }
00451 
00452 /*
00453  * call-seq:
00454  *   strio.lineno    -> integer
00455  *
00456  * Returns the current line number in *strio*. The stringio must be
00457  * opened for reading. +lineno+ counts the number of times  +gets+ is
00458  * called, rather than the number of newlines  encountered. The two
00459  * values will differ if +gets+ is  called with a separator other than
00460  * newline.  See also the  <code>$.</code> variable.
00461  */
00462 static VALUE
00463 strio_get_lineno(VALUE self)
00464 {
00465     return LONG2NUM(StringIO(self)->lineno);
00466 }
00467 
00468 /*
00469  * call-seq:
00470  *   strio.lineno = integer    -> integer
00471  *
00472  * Manually sets the current line number to the given value.
00473  * <code>$.</code> is updated only on the next read.
00474  */
00475 static VALUE
00476 strio_set_lineno(VALUE self, VALUE lineno)
00477 {
00478     StringIO(self)->lineno = NUM2LONG(lineno);
00479     return lineno;
00480 }
00481 
00482 /* call-seq: strio.binmode -> true */
00483 #define strio_binmode strio_self
00484 
00485 /* call-seq: strio.fcntl */
00486 #define strio_fcntl strio_unimpl
00487 
00488 /* call-seq: strio.flush -> strio */
00489 #define strio_flush strio_self
00490 
00491 /* call-seq: strio.fsync -> 0 */
00492 #define strio_fsync strio_0
00493 
00494 /*
00495  * call-seq:
00496  *   strio.reopen(other_StrIO)     -> strio
00497  *   strio.reopen(string, mode)    -> strio
00498  *
00499  * Reinitializes *strio* with the given <i>other_StrIO</i> or _string_
00500  * and _mode_ (see StringIO#new).
00501  */
00502 static VALUE
00503 strio_reopen(int argc, VALUE *argv, VALUE self)
00504 {
00505     rb_io_taint_check(self);
00506     if (argc == 1 && TYPE(*argv) != T_STRING) {
00507         return strio_copy(self, *argv);
00508     }
00509     strio_init(argc, argv, StringIO(self));
00510     return self;
00511 }
00512 
00513 /*
00514  * call-seq:
00515  *   strio.pos     -> integer
00516  *   strio.tell    -> integer
00517  *
00518  * Returns the current offset (in bytes) of *strio*.
00519  */
00520 static VALUE
00521 strio_get_pos(VALUE self)
00522 {
00523     return LONG2NUM(StringIO(self)->pos);
00524 }
00525 
00526 /*
00527  * call-seq:
00528  *   strio.pos = integer    -> integer
00529  *
00530  * Seeks to the given position (in bytes) in *strio*.
00531  */
00532 static VALUE
00533 strio_set_pos(VALUE self, VALUE pos)
00534 {
00535     struct StringIO *ptr = StringIO(self);
00536     long p = NUM2LONG(pos);
00537     if (p < 0) {
00538         error_inval(0);
00539     }
00540     ptr->pos = p;
00541     return pos;
00542 }
00543 
00544 /*
00545  * call-seq:
00546  *   strio.rewind    -> 0
00547  *
00548  * Positions *strio* to the beginning of input, resetting
00549  * +lineno+ to zero.
00550  */
00551 static VALUE
00552 strio_rewind(VALUE self)
00553 {
00554     struct StringIO *ptr = StringIO(self);
00555     ptr->pos = 0;
00556     ptr->lineno = 0;
00557     return INT2FIX(0);
00558 }
00559 
00560 /*
00561  * call-seq:
00562  *   strio.seek(amount, whence=SEEK_SET) -> 0
00563  *
00564  * Seeks to a given offset _amount_ in the stream according to
00565  * the value of _whence_ (see IO#seek).
00566  */
00567 static VALUE
00568 strio_seek(int argc, VALUE *argv, VALUE self)
00569 {
00570     VALUE whence;
00571     struct StringIO *ptr = StringIO(self);
00572     long offset;
00573 
00574     rb_scan_args(argc, argv, "11", NULL, &whence);
00575     offset = NUM2LONG(argv[0]);
00576     if (CLOSED(ptr)) {
00577         rb_raise(rb_eIOError, "closed stream");
00578     }
00579     switch (NIL_P(whence) ? 0 : NUM2LONG(whence)) {
00580       case 0:
00581         break;
00582       case 1:
00583         offset += ptr->pos;
00584         break;
00585       case 2:
00586         offset += RSTRING_LEN(ptr->string);
00587         break;
00588       default:
00589         error_inval("invalid whence");
00590     }
00591     if (offset < 0) {
00592         error_inval(0);
00593     }
00594     ptr->pos = offset;
00595     return INT2FIX(0);
00596 }
00597 
00598 /*
00599  * call-seq:
00600  *   strio.sync    -> true
00601  *
00602  * Returns +true+ always.
00603  */
00604 static VALUE
00605 strio_get_sync(VALUE self)
00606 {
00607     StringIO(self);
00608     return Qtrue;
00609 }
00610 
00611 /* call-seq: strio.sync = boolean -> boolean */
00612 #define strio_set_sync strio_first
00613 
00614 #define strio_tell strio_get_pos
00615 
00616 /*
00617  * call-seq:
00618  *   strio.bytes {|byte| block }      -> strio
00619  *   strio.bytes                      -> anEnumerator
00620  *
00621  *   strio.each_byte {|byte| block }  -> strio
00622  *   strio.each_byte                  -> anEnumerator
00623  *
00624  * See IO#each_byte.
00625  */
00626 static VALUE
00627 strio_each_byte(VALUE self)
00628 {
00629     struct StringIO *ptr = readable(StringIO(self));
00630 
00631     RETURN_ENUMERATOR(self, 0, 0);
00632 
00633     while (ptr->pos < RSTRING_LEN(ptr->string)) {
00634         char c = RSTRING_PTR(ptr->string)[ptr->pos++];
00635         rb_yield(CHR2FIX(c));
00636     }
00637     return self;
00638 }
00639 
00640 /*
00641  * call-seq:
00642  *   strio.getc   -> string or nil
00643  *
00644  * See IO#getc.
00645  */
00646 static VALUE
00647 strio_getc(VALUE self)
00648 {
00649     struct StringIO *ptr = readable(StringIO(self));
00650     rb_encoding *enc = rb_enc_get(ptr->string);
00651     int len;
00652     char *p;
00653 
00654     if (ptr->pos >= RSTRING_LEN(ptr->string)) {
00655         return Qnil;
00656     }
00657     p = RSTRING_PTR(ptr->string)+ptr->pos;
00658     len = rb_enc_mbclen(p, RSTRING_END(ptr->string), enc);
00659     ptr->pos += len;
00660     return rb_enc_str_new(p, len, rb_enc_get(ptr->string));
00661 }
00662 
00663 /*
00664  * call-seq:
00665  *   strio.getbyte   -> fixnum or nil
00666  *
00667  * See IO#getbyte.
00668  */
00669 static VALUE
00670 strio_getbyte(VALUE self)
00671 {
00672     struct StringIO *ptr = readable(StringIO(self));
00673     int c;
00674     if (ptr->pos >= RSTRING_LEN(ptr->string)) {
00675         return Qnil;
00676     }
00677     c = RSTRING_PTR(ptr->string)[ptr->pos++];
00678     return CHR2FIX(c);
00679 }
00680 
00681 static void
00682 strio_extend(struct StringIO *ptr, long pos, long len)
00683 {
00684     long olen;
00685 
00686     check_modifiable(ptr);
00687     olen = RSTRING_LEN(ptr->string);
00688     if (pos + len > olen) {
00689         rb_str_resize(ptr->string, pos + len);
00690         if (pos > olen)
00691             MEMZERO(RSTRING_PTR(ptr->string) + olen, char, pos - olen);
00692     }
00693     else {
00694         rb_str_modify(ptr->string);
00695     }
00696 }
00697 
00698 /*
00699  * call-seq:
00700  *   strio.ungetc(string)   -> nil
00701  *
00702  * Pushes back one character (passed as a parameter) onto *strio*
00703  * such that a subsequent buffered read will return it.  There is no
00704  * limitation for multiple pushbacks including pushing back behind the
00705  * beginning of the buffer string.
00706  */
00707 static VALUE
00708 strio_ungetc(VALUE self, VALUE c)
00709 {
00710     struct StringIO *ptr = readable(StringIO(self));
00711     long lpos, clen;
00712     char *p, *pend;
00713     rb_encoding *enc, *enc2;
00714 
00715     if (NIL_P(c)) return Qnil;
00716     if (FIXNUM_P(c)) {
00717         int cc = FIX2INT(c);
00718         char buf[16];
00719 
00720         enc = rb_enc_get(ptr->string);
00721         rb_enc_mbcput(cc, buf, enc);
00722         c = rb_enc_str_new(buf, rb_enc_codelen(cc, enc), enc);
00723     }
00724     else {
00725         SafeStringValue(c);
00726         enc = rb_enc_get(ptr->string);
00727         enc2 = rb_enc_get(c);
00728         if (enc != enc2 && enc != rb_ascii8bit_encoding()) {
00729             c = rb_str_conv_enc(c, enc2, enc);
00730         }
00731     }
00732     if (RSTRING_LEN(ptr->string) < ptr->pos) {
00733         long len = RSTRING_LEN(ptr->string);
00734         rb_str_resize(ptr->string, ptr->pos - 1);
00735         memset(RSTRING_PTR(ptr->string) + len, 0, ptr->pos - len - 1);
00736         rb_str_concat(ptr->string, c);
00737         ptr->pos--;
00738     }
00739     else {
00740         /* get logical position */
00741         lpos = 0; p = RSTRING_PTR(ptr->string); pend = p + ptr->pos;
00742         for (;;) {
00743             clen = rb_enc_mbclen(p, pend, enc);
00744             if (p+clen >= pend) break;
00745             p += clen;
00746             lpos++;
00747         }
00748         clen = p - RSTRING_PTR(ptr->string);
00749         rb_str_update(ptr->string, lpos, ptr->pos ? 1 : 0, c);
00750         ptr->pos = clen;
00751     }
00752 
00753     return Qnil;
00754 }
00755 
00756 /*
00757  * call-seq:
00758  *   strio.ungetbyte(fixnum)   -> nil
00759  *
00760  * See IO#ungetbyte
00761  */
00762 static VALUE
00763 strio_ungetbyte(VALUE self, VALUE c)
00764 {
00765     struct StringIO *ptr = readable(StringIO(self));
00766     char buf[1], *cp = buf;
00767     long pos = ptr->pos, cl = 1;
00768     VALUE str = ptr->string;
00769 
00770     if (NIL_P(c)) return Qnil;
00771     if (FIXNUM_P(c)) {
00772         buf[0] = (char)FIX2INT(c);
00773     }
00774     else {
00775         SafeStringValue(c);
00776         cp = RSTRING_PTR(c);
00777         cl = RSTRING_LEN(c);
00778         if (cl == 0) return Qnil;
00779     }
00780     rb_str_modify(str);
00781     if (cl > pos) {
00782         char *s;
00783         long rest = RSTRING_LEN(str) - pos;
00784         rb_str_resize(str, rest + cl);
00785         s = RSTRING_PTR(str);
00786         memmove(s + cl, s + pos, rest);
00787         pos = 0;
00788     }
00789     else {
00790         pos -= cl;
00791     }
00792     memcpy(RSTRING_PTR(str) + pos, cp, cl);
00793     ptr->pos = pos;
00794     RB_GC_GUARD(c);
00795     return Qnil;
00796 }
00797 
00798 /*
00799  * call-seq:
00800  *   strio.readchar   -> string
00801  *
00802  * See IO#readchar.
00803  */
00804 static VALUE
00805 strio_readchar(VALUE self)
00806 {
00807     VALUE c = strio_getc(self);
00808     if (NIL_P(c)) rb_eof_error();
00809     return c;
00810 }
00811 
00812 /*
00813  * call-seq:
00814  *   strio.readbyte   -> fixnum
00815  *
00816  * See IO#readbyte.
00817  */
00818 static VALUE
00819 strio_readbyte(VALUE self)
00820 {
00821     VALUE c = strio_getbyte(self);
00822     if (NIL_P(c)) rb_eof_error();
00823     return c;
00824 }
00825 
00826 /*
00827  * call-seq:
00828  *   strio.chars {|char| block }      -> strio
00829  *   strio.chars                      -> anEnumerator
00830  *
00831  *   strio.each_char {|char| block }  -> strio
00832  *   strio.each_char                  -> anEnumerator
00833  *
00834  * See IO#each_char.
00835  */
00836 static VALUE
00837 strio_each_char(VALUE self)
00838 {
00839     VALUE c;
00840 
00841     RETURN_ENUMERATOR(self, 0, 0);
00842 
00843     while (!NIL_P(c = strio_getc(self))) {
00844         rb_yield(c);
00845     }
00846     return self;
00847 }
00848 
00849 /*
00850  * call-seq:
00851  *   strio.codepoints {|c| block }      -> strio
00852  *   strio.codepoints                   -> anEnumerator
00853  *
00854  *   strio.each_codepoint {|c| block }  -> strio
00855  *   strio.each_codepoint               -> anEnumerator
00856  *
00857  * See IO#each_codepoint.
00858  */
00859 static VALUE
00860 strio_each_codepoint(VALUE self)
00861 {
00862     struct StringIO *ptr;
00863     rb_encoding *enc;
00864     unsigned int c;
00865     int n;
00866 
00867     RETURN_ENUMERATOR(self, 0, 0);
00868 
00869     ptr = readable(StringIO(self));
00870     enc = rb_enc_get(ptr->string);
00871     for (;;) {
00872         if (ptr->pos >= RSTRING_LEN(ptr->string)) {
00873             return self;
00874         }
00875 
00876         c = rb_enc_codepoint_len(RSTRING_PTR(ptr->string)+ptr->pos,
00877                                  RSTRING_END(ptr->string), &n, enc);
00878         rb_yield(UINT2NUM(c));
00879         ptr->pos += n;
00880     }
00881     return self;
00882 }
00883 
00884 /* Boyer-Moore search: copied from regex.c */
00885 static void
00886 bm_init_skip(long *skip, const char *pat, long m)
00887 {
00888     int c;
00889 
00890     for (c = 0; c < (1 << CHAR_BIT); c++) {
00891         skip[c] = m;
00892     }
00893     while (--m) {
00894         skip[(unsigned char)*pat++] = m;
00895     }
00896 }
00897 
00898 static long
00899 bm_search(const char *little, long llen, const char *big, long blen, const long *skip)
00900 {
00901     long i, j, k;
00902 
00903     i = llen - 1;
00904     while (i < blen) {
00905         k = i;
00906         j = llen - 1;
00907         while (j >= 0 && big[k] == little[j]) {
00908             k--;
00909             j--;
00910         }
00911         if (j < 0) return k + 1;
00912         i += skip[(unsigned char)big[i]];
00913     }
00914     return -1;
00915 }
00916 
00917 static VALUE
00918 strio_getline(int argc, VALUE *argv, struct StringIO *ptr)
00919 {
00920     const char *s, *e, *p;
00921     long n, limit = 0;
00922     VALUE str;
00923 
00924     if (argc == 0) {
00925         str = rb_rs;
00926     }
00927     else {
00928         VALUE lim, tmp;
00929 
00930         rb_scan_args(argc, argv, "11", &str, &lim);
00931         if (!NIL_P(lim)) limit = NUM2LONG(lim);
00932         else if (!NIL_P(str) && TYPE(str) != T_STRING) {
00933             tmp = rb_check_string_type(str);
00934             if (NIL_P(tmp)) {
00935                 limit = NUM2LONG(str);
00936                 if (limit == 0) return rb_str_new(0,0);
00937                 str = rb_rs;
00938             }
00939             else {
00940                 str = tmp;
00941             }
00942         }
00943         else if (!NIL_P(str)) {
00944             StringValue(str);
00945         }
00946     }
00947 
00948     if (ptr->pos >= (n = RSTRING_LEN(ptr->string))) {
00949         return Qnil;
00950     }
00951     s = RSTRING_PTR(ptr->string);
00952     e = s + RSTRING_LEN(ptr->string);
00953     s += ptr->pos;
00954     if (limit > 0 && s + limit < e) {
00955         e = rb_enc_right_char_head(s, s + limit, e, rb_enc_get(ptr->string));
00956     }
00957     if (NIL_P(str)) {
00958         str = strio_substr(ptr, ptr->pos, e - s);
00959     }
00960     else if ((n = RSTRING_LEN(str)) == 0) {
00961         p = s;
00962         while (*p == '\n') {
00963             if (++p == e) {
00964                 return Qnil;
00965             }
00966         }
00967         s = p;
00968         while ((p = memchr(p, '\n', e - p)) && (p != e)) {
00969             if (*++p == '\n') {
00970                 e = p + 1;
00971                 break;
00972             }
00973         }
00974         str = strio_substr(ptr, s - RSTRING_PTR(ptr->string), e - s);
00975     }
00976     else if (n == 1) {
00977         if ((p = memchr(s, RSTRING_PTR(str)[0], e - s)) != 0) {
00978             e = p + 1;
00979         }
00980         str = strio_substr(ptr, ptr->pos, e - s);
00981     }
00982     else {
00983         if (n < e - s) {
00984             if (e - s < 1024) {
00985                 for (p = s; p + n <= e; ++p) {
00986                     if (MEMCMP(p, RSTRING_PTR(str), char, n) == 0) {
00987                         e = p + n;
00988                         break;
00989                     }
00990                 }
00991             }
00992             else {
00993                 long skip[1 << CHAR_BIT], pos;
00994                 p = RSTRING_PTR(str);
00995                 bm_init_skip(skip, p, n);
00996                 if ((pos = bm_search(p, n, s, e - s, skip)) >= 0) {
00997                     e = s + pos + n;
00998                 }
00999             }
01000         }
01001         str = strio_substr(ptr, ptr->pos, e - s);
01002     }
01003     ptr->pos = e - RSTRING_PTR(ptr->string);
01004     ptr->lineno++;
01005     return str;
01006 }
01007 
01008 /*
01009  * call-seq:
01010  *   strio.gets(sep=$/)     -> string or nil
01011  *   strio.gets(limit)      -> string or nil
01012  *   strio.gets(sep, limit) -> string or nil
01013  *
01014  * See IO#gets.
01015  */
01016 static VALUE
01017 strio_gets(int argc, VALUE *argv, VALUE self)
01018 {
01019     VALUE str = strio_getline(argc, argv, readable(StringIO(self)));
01020 
01021     rb_lastline_set(str);
01022     return str;
01023 }
01024 
01025 /*
01026  * call-seq:
01027  *   strio.readline(sep=$/)     -> string
01028  *   strio.readline(limit)      -> string or nil
01029  *   strio.readline(sep, limit) -> string or nil
01030  *
01031  * See IO#readline.
01032  */
01033 static VALUE
01034 strio_readline(int argc, VALUE *argv, VALUE self)
01035 {
01036     VALUE line = strio_gets(argc, argv, self);
01037     if (NIL_P(line)) rb_eof_error();
01038     return line;
01039 }
01040 
01041 /*
01042  * call-seq:
01043  *   strio.each(sep=$/) {|line| block }         -> strio
01044  *   strio.each(limit) {|line| block }          -> strio
01045  *   strio.each(sep, limit) {|line| block }     -> strio
01046  *   strio.each(...)                            -> anEnumerator
01047  *
01048  *   strio.each_line(sep=$/) {|line| block }    -> strio
01049  *   strio.each_line(limit) {|line| block }     -> strio
01050  *   strio.each_line(sep,limit) {|line| block } -> strio
01051  *   strio.each_line(...)                       -> anEnumerator
01052  *
01053  *   strio.lines(sep=$/) {|line| block }        -> strio
01054  *   strio.lines(limit) {|line| block }         -> strio
01055  *   strio.lines(sep,limit) {|line| block }     -> strio
01056  *   strio.lines(...)                           -> anEnumerator
01057  *
01058  * See IO#each.
01059  */
01060 static VALUE
01061 strio_each(int argc, VALUE *argv, VALUE self)
01062 {
01063     struct StringIO *ptr = StringIO(self);
01064     VALUE line;
01065 
01066     RETURN_ENUMERATOR(self, argc, argv);
01067 
01068     while (!NIL_P(line = strio_getline(argc, argv, readable(ptr)))) {
01069         rb_yield(line);
01070     }
01071     return self;
01072 }
01073 
01074 /*
01075  * call-seq:
01076  *   strio.readlines(sep=$/)    ->   array
01077  *   strio.readlines(limit)     ->   array
01078  *   strio.readlines(sep,limit) ->   array
01079  *
01080  * See IO#readlines.
01081  */
01082 static VALUE
01083 strio_readlines(int argc, VALUE *argv, VALUE self)
01084 {
01085     struct StringIO *ptr = StringIO(self);
01086     VALUE ary = rb_ary_new(), line;
01087     while (!NIL_P(line = strio_getline(argc, argv, readable(ptr)))) {
01088         rb_ary_push(ary, line);
01089     }
01090     return ary;
01091 }
01092 
01093 /*
01094  * call-seq:
01095  *   strio.write(string)    -> integer
01096  *   strio.syswrite(string) -> integer
01097  *
01098  * Appends the given string to the underlying buffer string of *strio*.
01099  * The stream must be opened for writing.  If the argument is not a
01100  * string, it will be converted to a string using <code>to_s</code>.
01101  * Returns the number of bytes written.  See IO#write.
01102  */
01103 static VALUE
01104 strio_write(VALUE self, VALUE str)
01105 {
01106     struct StringIO *ptr = writable(StringIO(self));
01107     long len, olen;
01108     rb_encoding *enc, *enc2;
01109 
01110     RB_GC_GUARD(str);
01111     if (TYPE(str) != T_STRING)
01112         str = rb_obj_as_string(str);
01113     enc = rb_enc_get(ptr->string);
01114     enc2 = rb_enc_get(str);
01115     if (enc != enc2 && enc != rb_ascii8bit_encoding()) {
01116         str = rb_str_conv_enc(str, enc2, enc);
01117     }
01118     len = RSTRING_LEN(str);
01119     if (len == 0) return INT2FIX(0);
01120     check_modifiable(ptr);
01121     olen = RSTRING_LEN(ptr->string);
01122     if (ptr->flags & FMODE_APPEND) {
01123         ptr->pos = olen;
01124     }
01125     if (ptr->pos == olen) {
01126         rb_str_cat(ptr->string, RSTRING_PTR(str), len);
01127     }
01128     else {
01129         strio_extend(ptr, ptr->pos, len);
01130         memmove(RSTRING_PTR(ptr->string)+ptr->pos, RSTRING_PTR(str), len);
01131         OBJ_INFECT(ptr->string, str);
01132     }
01133     OBJ_INFECT(ptr->string, self);
01134     ptr->pos += len;
01135     return LONG2NUM(len);
01136 }
01137 
01138 /*
01139  * call-seq:
01140  *   strio << obj     -> strio
01141  *
01142  * See IO#<<.
01143  */
01144 #define strio_addstr rb_io_addstr
01145 
01146 /*
01147  * call-seq:
01148  *   strio.print()             -> nil
01149  *   strio.print(obj, ...)     -> nil
01150  *
01151  * See IO#print.
01152  */
01153 #define strio_print rb_io_print
01154 
01155 /*
01156  * call-seq:
01157  *   strio.printf(format_string [, obj, ...] )   -> nil
01158  *
01159  * See IO#printf.
01160  */
01161 #define strio_printf rb_io_printf
01162 
01163 /*
01164  * call-seq:
01165  *   strio.putc(obj)    -> obj
01166  *
01167  * See IO#putc.
01168  */
01169 static VALUE
01170 strio_putc(VALUE self, VALUE ch)
01171 {
01172     struct StringIO *ptr = writable(StringIO(self));
01173     int c = NUM2CHR(ch);
01174     long olen;
01175 
01176     check_modifiable(ptr);
01177     olen = RSTRING_LEN(ptr->string);
01178     if (ptr->flags & FMODE_APPEND) {
01179         ptr->pos = olen;
01180     }
01181     strio_extend(ptr, ptr->pos, 1);
01182     RSTRING_PTR(ptr->string)[ptr->pos++] = c;
01183     OBJ_INFECT(ptr->string, self);
01184     return ch;
01185 }
01186 
01187 /*
01188  * call-seq:
01189  *   strio.puts(obj, ...)    -> nil
01190  *
01191  * See IO#puts.
01192  */
01193 #define strio_puts rb_io_puts
01194 
01195 /*
01196  * call-seq:
01197  *   strio.read([length [, buffer]])    -> string, buffer, or nil
01198  *
01199  * See IO#read.
01200  */
01201 static VALUE
01202 strio_read(int argc, VALUE *argv, VALUE self)
01203 {
01204     struct StringIO *ptr = readable(StringIO(self));
01205     VALUE str = Qnil;
01206     long len;
01207 
01208     switch (argc) {
01209       case 2:
01210         str = argv[1];
01211         StringValue(str);
01212         rb_str_modify(str);
01213       case 1:
01214         if (!NIL_P(argv[0])) {
01215             len = NUM2LONG(argv[0]);
01216             if (len < 0) {
01217                 rb_raise(rb_eArgError, "negative length %ld given", len);
01218             }
01219             if (len > 0 && ptr->pos >= RSTRING_LEN(ptr->string)) {
01220                 if (!NIL_P(str)) rb_str_resize(str, 0);
01221                 return Qnil;
01222             }
01223             break;
01224         }
01225         /* fall through */
01226       case 0:
01227         len = RSTRING_LEN(ptr->string);
01228         if (len <= ptr->pos) {
01229             if (NIL_P(str)) {
01230                 str = rb_str_new(0, 0);
01231             }
01232             else {
01233                 rb_str_resize(str, 0);
01234             }
01235             return str;
01236         }
01237         else {
01238             len -= ptr->pos;
01239         }
01240         break;
01241       default:
01242         rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
01243     }
01244     if (NIL_P(str)) {
01245         str = strio_substr(ptr, ptr->pos, len);
01246         if (argc > 0) rb_enc_associate(str, rb_ascii8bit_encoding());
01247     }
01248     else {
01249         long rest = RSTRING_LEN(ptr->string) - ptr->pos;
01250         if (len > rest) len = rest;
01251         rb_str_resize(str, len);
01252         MEMCPY(RSTRING_PTR(str), RSTRING_PTR(ptr->string) + ptr->pos, char, len);
01253     }
01254     if (NIL_P(str)) {
01255         str = rb_str_new(0, 0);
01256         len = 0;
01257     }
01258     else {
01259         ptr->pos += len = RSTRING_LEN(str);
01260     }
01261     return str;
01262 }
01263 
01264 /*
01265  * call-seq:
01266  *   strio.sysread(integer[, outbuf])    -> string
01267  *
01268  * Similar to #read, but raises +EOFError+ at end of string instead of
01269  * returning +nil+, as well as IO#sysread does.
01270  */
01271 static VALUE
01272 strio_sysread(int argc, VALUE *argv, VALUE self)
01273 {
01274     VALUE val = strio_read(argc, argv, self);
01275     if (NIL_P(val)) {
01276         rb_eof_error();
01277     }
01278     return val;
01279 }
01280 
01281 #define strio_syswrite strio_write
01282 
01283 /*
01284  * call-seq:
01285  *   strio.isatty -> nil
01286  *   strio.tty? -> nil
01287  *
01288  */
01289 #define strio_isatty strio_false
01290 
01291 /* call-seq: strio.pid -> nil */
01292 #define strio_pid strio_nil
01293 
01294 /* call-seq: strio.fileno -> nil */
01295 #define strio_fileno strio_nil
01296 
01297 /*
01298  * call-seq:
01299  *   strio.size   -> integer
01300  *
01301  * Returns the size of the buffer string.
01302  */
01303 static VALUE
01304 strio_size(VALUE self)
01305 {
01306     VALUE string = StringIO(self)->string;
01307     if (NIL_P(string)) {
01308         rb_raise(rb_eIOError, "not opened");
01309     }
01310     return ULONG2NUM(RSTRING_LEN(string));
01311 }
01312 
01313 /*
01314  * call-seq:
01315  *   strio.truncate(integer)    -> 0
01316  *
01317  * Truncates the buffer string to at most _integer_ bytes. The *strio*
01318  * must be opened for writing.
01319  */
01320 static VALUE
01321 strio_truncate(VALUE self, VALUE len)
01322 {
01323     VALUE string = writable(StringIO(self))->string;
01324     long l = NUM2LONG(len);
01325     long plen = RSTRING_LEN(string);
01326     if (l < 0) {
01327         error_inval("negative legnth");
01328     }
01329     rb_str_resize(string, l);
01330     if (plen < l) {
01331         MEMZERO(RSTRING_PTR(string) + plen, char, l - plen);
01332     }
01333     return len;
01334 }
01335 
01336 /*
01337  *  call-seq:
01338  *     strio.external_encoding   => encoding
01339  *
01340  *  Returns the Encoding object that represents the encoding of the file.
01341  *  If strio is write mode and no encoding is specified, returns <code>nil</code>.
01342  */
01343 
01344 static VALUE
01345 strio_external_encoding(VALUE self)
01346 {
01347     return rb_enc_from_encoding(rb_enc_get(StringIO(self)->string));
01348 }
01349 
01350 /*
01351  *  call-seq:
01352  *     strio.internal_encoding   => encoding
01353  *
01354  *  Returns the Encoding of the internal string if conversion is
01355  *  specified.  Otherwise returns nil.
01356  */
01357 
01358 static VALUE
01359 strio_internal_encoding(VALUE self)
01360 {
01361      return Qnil;
01362 }
01363 
01364 /*
01365  *  call-seq:
01366  *     strio.set_encoding(ext_enc)                => strio
01367  *
01368  *  Tagged with the encoding specified.
01369  */
01370 
01371 static VALUE
01372 strio_set_encoding(VALUE self, VALUE ext_enc)
01373 {
01374     rb_encoding* enc;
01375     VALUE str = StringIO(self)->string;
01376     enc = rb_to_encoding(ext_enc);
01377     rb_enc_associate(str, enc);
01378     return self;
01379 }
01380 
01381 /*
01382  * Pseudo I/O on String object.
01383  */
01384 void
01385 Init_stringio()
01386 {
01387     VALUE StringIO = rb_define_class("StringIO", rb_cData);
01388 
01389     rb_include_module(StringIO, rb_mEnumerable);
01390     rb_define_alloc_func(StringIO, strio_s_allocate);
01391     rb_define_singleton_method(StringIO, "open", strio_s_open, -1);
01392     rb_define_method(StringIO, "initialize", strio_initialize, -1);
01393     rb_define_method(StringIO, "initialize_copy", strio_copy, 1);
01394     rb_define_method(StringIO, "reopen", strio_reopen, -1);
01395 
01396     rb_define_method(StringIO, "string", strio_get_string, 0);
01397     rb_define_method(StringIO, "string=", strio_set_string, 1);
01398     rb_define_method(StringIO, "lineno", strio_get_lineno, 0);
01399     rb_define_method(StringIO, "lineno=", strio_set_lineno, 1);
01400 
01401     rb_define_method(StringIO, "binmode", strio_binmode, 0);
01402     rb_define_method(StringIO, "close", strio_close, 0);
01403     rb_define_method(StringIO, "close_read", strio_close_read, 0);
01404     rb_define_method(StringIO, "close_write", strio_close_write, 0);
01405     rb_define_method(StringIO, "closed?", strio_closed, 0);
01406     rb_define_method(StringIO, "closed_read?", strio_closed_read, 0);
01407     rb_define_method(StringIO, "closed_write?", strio_closed_write, 0);
01408     rb_define_method(StringIO, "eof", strio_eof, 0);
01409     rb_define_method(StringIO, "eof?", strio_eof, 0);
01410     rb_define_method(StringIO, "fcntl", strio_fcntl, -1);
01411     rb_define_method(StringIO, "flush", strio_flush, 0);
01412     rb_define_method(StringIO, "fsync", strio_fsync, 0);
01413     rb_define_method(StringIO, "pos", strio_get_pos, 0);
01414     rb_define_method(StringIO, "pos=", strio_set_pos, 1);
01415     rb_define_method(StringIO, "rewind", strio_rewind, 0);
01416     rb_define_method(StringIO, "seek", strio_seek, -1);
01417     rb_define_method(StringIO, "sync", strio_get_sync, 0);
01418     rb_define_method(StringIO, "sync=", strio_set_sync, 1);
01419     rb_define_method(StringIO, "tell", strio_tell, 0);
01420 
01421     rb_define_method(StringIO, "each", strio_each, -1);
01422     rb_define_method(StringIO, "each_line", strio_each, -1);
01423     rb_define_method(StringIO, "lines", strio_each, -1);
01424     rb_define_method(StringIO, "each_byte", strio_each_byte, 0);
01425     rb_define_method(StringIO, "bytes", strio_each_byte, 0);
01426     rb_define_method(StringIO, "each_char", strio_each_char, 0);
01427     rb_define_method(StringIO, "chars", strio_each_char, 0);
01428     rb_define_method(StringIO, "each_codepoint", strio_each_codepoint, 0);
01429     rb_define_method(StringIO, "codepoints", strio_each_codepoint, 0);
01430     rb_define_method(StringIO, "getc", strio_getc, 0);
01431     rb_define_method(StringIO, "ungetc", strio_ungetc, 1);
01432     rb_define_method(StringIO, "ungetbyte", strio_ungetbyte, 1);
01433     rb_define_method(StringIO, "readchar", strio_readchar, 0);
01434     rb_define_method(StringIO, "getbyte", strio_getbyte, 0);
01435     rb_define_method(StringIO, "readbyte", strio_readbyte, 0);
01436     rb_define_method(StringIO, "gets", strio_gets, -1);
01437     rb_define_method(StringIO, "readline", strio_readline, -1);
01438     rb_define_method(StringIO, "readlines", strio_readlines, -1);
01439     rb_define_method(StringIO, "read", strio_read, -1);
01440     rb_define_method(StringIO, "sysread", strio_sysread, -1);
01441     rb_define_method(StringIO, "readpartial", strio_sysread, -1);
01442     rb_define_method(StringIO, "read_nonblock", strio_sysread, -1);
01443 
01444     rb_define_method(StringIO, "write", strio_write, 1);
01445     rb_define_method(StringIO, "<<", strio_addstr, 1);
01446     rb_define_method(StringIO, "print", strio_print, -1);
01447     rb_define_method(StringIO, "printf", strio_printf, -1);
01448     rb_define_method(StringIO, "putc", strio_putc, 1);
01449     rb_define_method(StringIO, "puts", strio_puts, -1);
01450     rb_define_method(StringIO, "syswrite", strio_syswrite, 1);
01451     rb_define_method(StringIO, "write_nonblock", strio_syswrite, 1);
01452 
01453     rb_define_method(StringIO, "isatty", strio_isatty, 0);
01454     rb_define_method(StringIO, "tty?", strio_isatty, 0);
01455     rb_define_method(StringIO, "pid", strio_pid, 0);
01456     rb_define_method(StringIO, "fileno", strio_fileno, 0);
01457     rb_define_method(StringIO, "size", strio_size, 0);
01458     rb_define_method(StringIO, "length", strio_size, 0);
01459     rb_define_method(StringIO, "truncate", strio_truncate, 1);
01460 
01461     rb_define_method(StringIO, "external_encoding", strio_external_encoding, 0);
01462     rb_define_method(StringIO, "internal_encoding", strio_internal_encoding, 0);
01463     rb_define_method(StringIO, "set_encoding", strio_set_encoding, 1);
01464 }
01465 

Generated on Wed Aug 10 09:17:05 2011 for Ruby by  doxygen 1.4.7