1 29 package org.jruby; 30 31 import java.util.ArrayList ; 32 import java.util.List ; 33 34 import org.jruby.runtime.Block; 35 import org.jruby.runtime.CallbackFactory; 36 import org.jruby.runtime.ObjectAllocator; 37 import org.jruby.runtime.ThreadContext; 38 import org.jruby.runtime.builtin.IRubyObject; 39 40 import org.jruby.util.IOHandler; 41 import org.jruby.util.ByteList; 42 43 public class RubyStringIO extends RubyObject { 44 private static ObjectAllocator STRINGIO_ALLOCATOR = new ObjectAllocator() { 45 public IRubyObject allocate(Ruby runtime, RubyClass klass) { 46 return new RubyStringIO(runtime, klass); 47 } 48 }; 49 50 public static RubyClass createStringIOClass(final Ruby runtime) { 51 final RubyClass stringIOClass = runtime.defineClass("StringIO", runtime.getObject(), STRINGIO_ALLOCATOR); 52 53 final CallbackFactory callbackFactory = runtime.callbackFactory(RubyStringIO.class); 54 55 stringIOClass.getMetaClass().defineMethod("open", callbackFactory.getOptSingletonMethod("open")); 56 stringIOClass.defineMethod("initialize", callbackFactory.getOptMethod("initialize")); 57 stringIOClass.defineFastMethod("<<", callbackFactory.getFastMethod("append",RubyKernel.IRUBY_OBJECT)); 58 stringIOClass.defineFastMethod("binmode", callbackFactory.getFastMethod("binmode")); 59 stringIOClass.defineFastMethod("close", callbackFactory.getFastMethod("close")); 60 stringIOClass.defineFastMethod("closed?", callbackFactory.getFastMethod("closed_p")); 61 stringIOClass.defineFastMethod("close_read", callbackFactory.getFastMethod("close_read")); 62 stringIOClass.defineFastMethod("closed_read?", callbackFactory.getFastMethod("closed_read_p")); 63 stringIOClass.defineFastMethod("close_write", callbackFactory.getFastMethod("close_write")); 64 stringIOClass.defineFastMethod("closed_write?", callbackFactory.getFastMethod("closed_write_p")); 65 stringIOClass.defineMethod("each", callbackFactory.getOptMethod("each")); 66 stringIOClass.defineMethod("each_byte", callbackFactory.getMethod("each_byte")); 67 stringIOClass.defineMethod("each_line", callbackFactory.getMethod("each_line")); 68 stringIOClass.defineFastMethod("eof", callbackFactory.getFastMethod("eof")); 69 stringIOClass.defineFastMethod("eof?", callbackFactory.getFastMethod("eof_p")); 70 stringIOClass.defineFastMethod("fcntl", callbackFactory.getFastMethod("fcntl")); 71 stringIOClass.defineFastMethod("fileno", callbackFactory.getFastMethod("fileno")); 72 stringIOClass.defineFastMethod("flush", callbackFactory.getFastMethod("flush")); 73 stringIOClass.defineFastMethod("fsync", callbackFactory.getFastMethod("fsync")); 74 stringIOClass.defineFastMethod("getc", callbackFactory.getFastMethod("getc")); 75 stringIOClass.defineFastMethod("gets", callbackFactory.getFastOptMethod("gets")); 76 stringIOClass.defineFastMethod("isatty", callbackFactory.getFastMethod("isatty")); 77 stringIOClass.defineFastMethod("tty?", callbackFactory.getFastMethod("tty_p")); 79 stringIOClass.defineFastMethod("length", callbackFactory.getFastMethod("length")); 80 stringIOClass.defineFastMethod("lineno", callbackFactory.getFastMethod("lineno")); 81 stringIOClass.defineFastMethod("lineno=", callbackFactory.getFastMethod("set_lineno", RubyFixnum.class)); 82 stringIOClass.defineFastMethod("path", callbackFactory.getFastMethod("path")); 83 stringIOClass.defineFastMethod("pid", callbackFactory.getFastMethod("pid")); 84 stringIOClass.defineFastMethod("pos", callbackFactory.getFastMethod("pos")); 85 stringIOClass.defineFastMethod("tell", callbackFactory.getFastMethod("tell")); 87 stringIOClass.defineFastMethod("pos=", callbackFactory.getFastMethod("set_pos", RubyFixnum.class)); 88 stringIOClass.defineFastMethod("print", callbackFactory.getFastOptMethod("print")); 89 stringIOClass.defineFastMethod("printf", callbackFactory.getFastOptMethod("printf")); 90 stringIOClass.defineFastMethod("putc", callbackFactory.getFastMethod("putc", RubyKernel.IRUBY_OBJECT)); 91 stringIOClass.defineFastMethod("puts", callbackFactory.getFastOptMethod("puts")); 92 stringIOClass.defineFastMethod("read", callbackFactory.getFastOptMethod("read")); 93 stringIOClass.defineFastMethod("readchar", callbackFactory.getFastMethod("readchar")); 94 stringIOClass.defineFastMethod("readline", callbackFactory.getFastOptMethod("readline")); 95 stringIOClass.defineFastMethod("readlines", callbackFactory.getFastOptMethod("readlines")); 96 stringIOClass.defineFastMethod("reopen", callbackFactory.getFastMethod("reopen", RubyKernel.IRUBY_OBJECT)); 97 stringIOClass.defineFastMethod("rewind", callbackFactory.getFastMethod("rewind")); 98 stringIOClass.defineFastMethod("seek", callbackFactory.getFastOptMethod("seek")); 99 stringIOClass.defineFastMethod("size", callbackFactory.getFastMethod("size")); 100 stringIOClass.defineFastMethod("string", callbackFactory.getFastMethod("string")); 101 stringIOClass.defineFastMethod("string=", callbackFactory.getFastMethod("set_string",RubyString.class)); 102 stringIOClass.defineFastMethod("sync", callbackFactory.getFastMethod("sync")); 103 stringIOClass.defineFastMethod("sync=", callbackFactory.getFastMethod("set_sync", RubyKernel.IRUBY_OBJECT)); 104 stringIOClass.defineFastMethod("syswrite", callbackFactory.getFastMethod("syswrite", RubyKernel.IRUBY_OBJECT)); 105 stringIOClass.defineFastMethod("truncate", callbackFactory.getFastMethod("truncate", RubyFixnum.class)); 106 stringIOClass.defineFastMethod("ungetc", callbackFactory.getFastMethod("ungetc", RubyFixnum.class)); 107 stringIOClass.defineFastMethod("write", callbackFactory.getFastMethod("write", RubyKernel.IRUBY_OBJECT)); 108 109 return stringIOClass; 110 } 111 112 public static IRubyObject open(IRubyObject recv, IRubyObject[] args, Block block) { 113 RubyString str = recv.getRuntime().newString(""); 114 IRubyObject mode = recv.getRuntime().getNil(); 115 if (args.length > 0) { 116 str = args[0].convertToString(); 117 if (args.length > 1) { 118 mode = args[1]; 119 } 120 } 121 RubyStringIO strio = (RubyStringIO)((RubyClass)recv).newInstance(new IRubyObject[]{str,mode}, Block.NULL_BLOCK); 122 IRubyObject val = strio; 123 ThreadContext tc = recv.getRuntime().getCurrentContext(); 124 125 if (block.isGiven()) { 126 try { 127 val = tc.yield(strio, block); 128 } finally { 129 strio.close(); 130 } 131 } 132 return val; 133 } 134 135 protected RubyStringIO(Ruby runtime, RubyClass klass) { 136 super(runtime, klass); 137 } 138 139 private long pos = 0L; 140 private int lineno = 0; 141 private boolean eof = false; 142 private ByteList internal; 143 private boolean closedRead = false; 144 private boolean closedWrite = false; 145 146 public IRubyObject initialize(IRubyObject[] args, Block block) { 147 if (checkArgumentCount(args, 0, 2) > 0) { 148 internal = args[0].convertToString().getByteList(); 150 } else { 151 internal = new ByteList(); 152 } 153 return this; 154 } 155 156 public IRubyObject append(IRubyObject obj) { 157 ByteList val = ((RubyString)obj.callMethod(obj.getRuntime().getCurrentContext(),"to_s")).getByteList(); 158 int left = internal.length()-(int)pos; 159 internal.replace((int)pos,Math.min(val.length(),left),val); 160 pos += val.length(); 161 return this; 162 } 163 164 public IRubyObject binmode() { 165 return getRuntime().getTrue(); 166 } 167 168 public IRubyObject close() { 169 closedRead = true; 170 closedWrite = true; 171 return getRuntime().getNil(); 172 } 173 174 public IRubyObject closed_p() { 175 return (closedRead && closedWrite) ? getRuntime().getTrue() : getRuntime().getFalse(); 176 } 177 178 public IRubyObject close_read() { 179 closedRead = true; 180 return getRuntime().getNil(); 181 } 182 183 public IRubyObject closed_read_p() { 184 return closedRead ? getRuntime().getTrue() : getRuntime().getFalse(); 185 } 186 187 public IRubyObject close_write() { 188 closedWrite = true; 189 return getRuntime().getNil(); 190 } 191 192 public IRubyObject closed_write_p() { 193 return closedWrite ? getRuntime().getTrue() : getRuntime().getFalse(); 194 } 195 196 public IRubyObject each(IRubyObject[] args, Block block) { 197 IRubyObject line = gets(args); 198 ThreadContext context = getRuntime().getCurrentContext(); 199 while (!line.isNil()) { 200 context.yield(line, block); 201 line = gets(args); 202 } 203 return this; 204 } 205 206 public IRubyObject each_byte(Block block) { 207 RubyString.newString(getRuntime(),new ByteList(internal, (int)pos, internal.length())).each_byte(block); 208 return this; 209 } 210 211 public IRubyObject each_line(Block block) { 212 return each(new RubyObject[0], block); 213 } 214 215 public IRubyObject eof() { 216 return (pos >= internal.length() || eof) ? getRuntime().getTrue() : getRuntime().getFalse(); 217 } 218 219 public IRubyObject eof_p() { 220 return (pos >= internal.length() || eof) ? getRuntime().getTrue() : getRuntime().getFalse(); 221 } 222 223 public IRubyObject fcntl() { 224 throw getRuntime().newNotImplementedError("fcntl not implemented"); 225 } 226 227 public IRubyObject fileno() { 228 return getRuntime().getNil(); 229 } 230 231 public IRubyObject flush() { 232 return this; 233 } 234 235 public IRubyObject fsync() { 236 return RubyFixnum.zero(getRuntime()); 237 } 238 239 public IRubyObject getc() { 240 return getRuntime().newFixnum( internal.get((int)pos++) & 0xFF); 241 } 242 243 public IRubyObject internalGets(IRubyObject[] args) { 244 if (pos < internal.length() && !eof) { 245 String sep = ((RubyString)getRuntime().getGlobalVariables().get("$/")).getValue().toString(); 246 if (args.length>0) { 247 if (args[0].isNil()) { 248 ByteList buf = new ByteList(internal, (int)pos, internal.length()-(int)pos); 249 pos+=buf.length(); 250 return RubyString.newString(getRuntime(),buf); 251 } 252 sep = args[0].toString(); 253 } 254 String ss = RubyString.byteListToString(internal); 255 int ix = ss.indexOf(sep,(int)pos); 256 String add = sep; 257 if (-1 == ix) { 258 ix = internal.length(); 259 add = ""; 260 } 261 ByteList line = new ByteList(internal, (int)pos, ix-(int)pos); 262 line.append(RubyString.stringToBytes(add)); 263 pos = ix + add.length(); 264 lineno++; 265 return RubyString.newString(getRuntime(),line); 266 } 267 return getRuntime().getNil(); 268 } 269 270 public IRubyObject gets(IRubyObject[] args) { 271 IRubyObject result = internalGets(args); 272 if (!result.isNil()) { 273 getRuntime().getCurrentContext().setLastline(result); 274 } 275 return result; 276 } 277 278 public IRubyObject isatty() { 279 return getRuntime().getNil(); 280 } 281 282 public IRubyObject tty_p() { 283 return getRuntime().getNil(); 284 } 285 286 public IRubyObject length() { 287 return getRuntime().newFixnum(internal.length()); 288 } 289 290 public IRubyObject lineno() { 291 return getRuntime().newFixnum(lineno); 292 } 293 294 public IRubyObject set_lineno(RubyFixnum val) { 295 lineno = (int)val.getLongValue(); 296 return getRuntime().getNil(); 297 } 298 299 public IRubyObject path() { 300 return getRuntime().getNil(); 301 } 302 303 public IRubyObject pid() { 304 return getRuntime().getNil(); 305 } 306 307 public IRubyObject pos() { 308 return getRuntime().newFixnum(pos); 309 } 310 311 public IRubyObject tell() { 312 return getRuntime().newFixnum(pos); 313 } 314 315 public IRubyObject set_pos(RubyFixnum val) { 316 pos = (int)val.getLongValue(); 317 return getRuntime().getNil(); 318 } 319 320 public IRubyObject print(IRubyObject[] args) { 321 if (args.length != 0) { 322 for (int i=0,j=args.length;i<j;i++) { 323 append(args[i]); 324 } 325 } 326 IRubyObject sep = getRuntime().getGlobalVariables().get("$\\"); 327 if (!sep.isNil()) { 328 append(sep); 329 } 330 return getRuntime().getNil(); 331 } 332 333 public IRubyObject printf(IRubyObject[] args) { 334 append(RubyKernel.sprintf(this,args)); 335 return getRuntime().getNil(); 336 } 337 338 public IRubyObject putc(IRubyObject obj) { 339 append(obj); 340 return obj; 341 } 342 343 private static final ByteList NEWLINE_BL = new ByteList(new byte[]{10},false); 344 345 public IRubyObject puts(IRubyObject[] obj) { 346 if (obj.length == 0) { 347 append(RubyString.newString(getRuntime(),NEWLINE_BL)); 348 } 349 350 for (int i=0,j=obj.length;i<j;i++) { 351 append(obj[i]); 352 internal.unsafeReplace((int)(pos++),0,NEWLINE_BL); 353 } 354 return getRuntime().getNil(); 355 } 356 357 public IRubyObject read(IRubyObject[] args) { 358 ByteList buf = null; 359 if (!(pos >= internal.length() || eof)) { 360 if (args.length > 0 && !args[0].isNil()) { 361 int len = RubyNumeric.fix2int(args[0]); 362 int end = ((int)pos) + len; 363 if (end > internal.length()) { 364 buf = new ByteList(internal,(int)pos,internal.length()-(int)pos); 365 } else { 366 buf = new ByteList(internal,(int)pos,len); 367 } 368 } else { 369 buf = new ByteList(internal,(int)pos,internal.length()-(int)pos); 370 } 371 pos+= buf.length(); 372 } 373 IRubyObject ret = null; 374 if (buf == null) { 375 if (args.length > 0) { 376 return getRuntime().getNil(); 377 } 378 return getRuntime().newString(""); 379 } else { 380 if (args.length>1) { 381 ret = args[1].convertToString(); 382 ((RubyString)ret).setValue(buf); 383 } else { 384 ret = RubyString.newString(getRuntime(),buf); 385 } 386 } 387 388 return ret; 389 } 390 391 public IRubyObject readchar() { 392 return getc(); 393 } 394 395 public IRubyObject readline(IRubyObject[] args) { 396 return gets(args); 397 } 398 399 public IRubyObject readlines(IRubyObject[] arg) { 400 List lns = new ArrayList (); 401 while (!(pos >= internal.length() || eof)) { 402 lns.add(gets(arg)); 403 } 404 return getRuntime().newArray(lns); 405 } 406 407 public IRubyObject reopen(IRubyObject str) { 408 if (str instanceof RubyStringIO) { 409 pos = ((RubyStringIO)str).pos; 410 lineno = ((RubyStringIO)str).lineno; 411 eof = ((RubyStringIO)str).eof; 412 closedRead = ((RubyStringIO)str).closedRead; 413 closedWrite = ((RubyStringIO)str).closedWrite; 414 internal = new ByteList(((RubyStringIO)str).internal); 415 } else { 416 pos = 0L; 417 lineno = 0; 418 eof = false; 419 closedRead = false; 420 closedWrite = false; 421 internal = new ByteList(); 422 internal.append(str.convertToString().getByteList()); 423 } 424 return this; 425 } 426 427 public IRubyObject rewind() { 428 this.pos = 0L; 429 this.lineno = 0; 430 return RubyFixnum.zero(getRuntime()); 431 } 432 433 public IRubyObject seek(IRubyObject[] args) { 434 long amount = ((RubyNumeric)args[0]).getLongValue(); 435 int whence = IOHandler.SEEK_SET; 436 if (args.length > 1) { 437 whence = (int)(((RubyNumeric)args[1]).getLongValue()); 438 } 439 if (whence == IOHandler.SEEK_CUR) { 440 pos += amount; 441 } else if (whence == IOHandler.SEEK_END) { 442 pos = internal.length() + amount; 443 } else { 444 pos = amount; 445 } 446 return RubyFixnum.zero(getRuntime()); 447 } 448 449 public IRubyObject size() { 450 return getRuntime().newFixnum(internal.length()); 451 } 452 453 public IRubyObject string() { 454 return RubyString.newString(getRuntime(),internal); 455 } 456 457 public IRubyObject set_string(RubyString arg) { 458 return reopen(arg); 459 } 460 461 public IRubyObject sync() { 462 return getRuntime().getTrue(); 463 } 464 465 public IRubyObject set_sync(IRubyObject args) { 466 return args; 467 } 468 469 public IRubyObject syswrite(IRubyObject args) { 470 return write(args); 471 } 472 473 public IRubyObject truncate(RubyFixnum args) { 474 int len = (int) args.getLongValue(); 475 internal.length(len); 476 return RubyFixnum.zero(getRuntime()); 477 } 478 479 public IRubyObject ungetc(RubyFixnum args) { 480 internal.insert((int)pos,(int)args.getLongValue()); 481 return getRuntime().getNil(); 482 } 483 484 public IRubyObject write(IRubyObject args) { 485 String obj = args.toString(); 486 append(args); 487 return getRuntime().newFixnum(obj.length()); 488 } 489 } 490 | Popular Tags |