1#include "ruby.h" 2#include "ruby/encoding.h" 3 4static VALUE rb_cPathname; 5static ID id_at_path, id_to_path; 6 7static VALUE 8get_strpath(VALUE obj) 9{ 10 VALUE strpath; 11 strpath = rb_ivar_get(obj, id_at_path); 12 if (!RB_TYPE_P(strpath, T_STRING)) 13 rb_raise(rb_eTypeError, "unexpected @path"); 14 return strpath; 15} 16 17static void 18set_strpath(VALUE obj, VALUE val) 19{ 20 rb_ivar_set(obj, id_at_path, val); 21} 22 23/* 24 * Create a Pathname object from the given String (or String-like object). 25 * If +path+ contains a NULL character (<tt>\0</tt>), an ArgumentError is raised. 26 */ 27static VALUE 28path_initialize(VALUE self, VALUE arg) 29{ 30 VALUE str; 31 if (RB_TYPE_P(arg, T_STRING)) { 32 str = arg; 33 } 34 else { 35 str = rb_check_funcall(arg, id_to_path, 0, NULL); 36 if (str == Qundef) 37 str = arg; 38 StringValue(str); 39 } 40 if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str))) 41 rb_raise(rb_eArgError, "pathname contains null byte"); 42 str = rb_obj_dup(str); 43 44 set_strpath(self, str); 45 OBJ_INFECT(self, str); 46 return self; 47} 48 49/* 50 * call-seq: 51 * pathname.freeze -> obj 52 * 53 * Freezes this Pathname. 54 * 55 * See Object.freeze. 56 */ 57static VALUE 58path_freeze(VALUE self) 59{ 60 rb_call_super(0, 0); 61 rb_str_freeze(get_strpath(self)); 62 return self; 63} 64 65/* 66 * call-seq: 67 * pathname.taint -> obj 68 * 69 * Taints this Pathname. 70 * 71 * See Object.taint. 72 */ 73static VALUE 74path_taint(VALUE self) 75{ 76 rb_call_super(0, 0); 77 rb_obj_taint(get_strpath(self)); 78 return self; 79} 80 81/* 82 * call-seq: 83 * pathname.untaint -> obj 84 * 85 * Untaints this Pathname. 86 * 87 * See Object.untaint. 88 */ 89static VALUE 90path_untaint(VALUE self) 91{ 92 rb_call_super(0, 0); 93 rb_obj_untaint(get_strpath(self)); 94 return self; 95} 96 97/* 98 * Compare this pathname with +other+. The comparison is string-based. 99 * Be aware that two different paths (<tt>foo.txt</tt> and <tt>./foo.txt</tt>) 100 * can refer to the same file. 101 */ 102static VALUE 103path_eq(VALUE self, VALUE other) 104{ 105 if (!rb_obj_is_kind_of(other, rb_cPathname)) 106 return Qfalse; 107 return rb_str_equal(get_strpath(self), get_strpath(other)); 108} 109 110/* 111 * Provides a case-sensitive comparison operator for pathnames. 112 * 113 * Pathname.new('/usr') <=> Pathname.new('/usr/bin') 114 * #=> -1 115 * Pathname.new('/usr/bin') <=> Pathname.new('/usr/bin') 116 * #=> 0 117 * Pathname.new('/usr/bin') <=> Pathname.new('/USR/BIN') 118 * #=> 1 119 * 120 * It will return +-1+, +0+ or +1+ depending on the value of the left argument 121 * relative to the right argument. Or it will return +nil+ if the arguments 122 * are not comparable. 123 */ 124static VALUE 125path_cmp(VALUE self, VALUE other) 126{ 127 VALUE s1, s2; 128 char *p1, *p2; 129 char *e1, *e2; 130 if (!rb_obj_is_kind_of(other, rb_cPathname)) 131 return Qnil; 132 s1 = get_strpath(self); 133 s2 = get_strpath(other); 134 p1 = RSTRING_PTR(s1); 135 p2 = RSTRING_PTR(s2); 136 e1 = p1 + RSTRING_LEN(s1); 137 e2 = p2 + RSTRING_LEN(s2); 138 while (p1 < e1 && p2 < e2) { 139 int c1, c2; 140 c1 = (unsigned char)*p1++; 141 c2 = (unsigned char)*p2++; 142 if (c1 == '/') c1 = '\0'; 143 if (c2 == '/') c2 = '\0'; 144 if (c1 != c2) { 145 if (c1 < c2) 146 return INT2FIX(-1); 147 else 148 return INT2FIX(1); 149 } 150 } 151 if (p1 < e1) 152 return INT2FIX(1); 153 if (p2 < e2) 154 return INT2FIX(-1); 155 return INT2FIX(0); 156} 157 158/* :nodoc: */ 159static VALUE 160path_hash(VALUE self) 161{ 162 return INT2FIX(rb_str_hash(get_strpath(self))); 163} 164 165/* 166 * call-seq: 167 * pathname.to_s -> string 168 * pathname.to_path -> string 169 * 170 * Return the path as a String. 171 * 172 * to_path is implemented so Pathname objects are usable with File.open, etc. 173 */ 174static VALUE 175path_to_s(VALUE self) 176{ 177 return rb_obj_dup(get_strpath(self)); 178} 179 180/* :nodoc: */ 181static VALUE 182path_inspect(VALUE self) 183{ 184 const char *c = rb_obj_classname(self); 185 VALUE str = get_strpath(self); 186 return rb_sprintf("#<%s:%s>", c, RSTRING_PTR(str)); 187} 188 189/* 190 * Return a pathname which is substituted by String#sub. 191 * 192 * path1 = Pathname.new('/usr/bin/perl') 193 * path1.sub('perl', 'ruby') 194 * #=> #<Pathname:/usr/bin/ruby> 195 */ 196static VALUE 197path_sub(int argc, VALUE *argv, VALUE self) 198{ 199 VALUE str = get_strpath(self); 200 201 if (rb_block_given_p()) { 202 str = rb_block_call(str, rb_intern("sub"), argc, argv, 0, 0); 203 } 204 else { 205 str = rb_funcall2(str, rb_intern("sub"), argc, argv); 206 } 207 return rb_class_new_instance(1, &str, rb_obj_class(self)); 208} 209 210/* 211 * Return a pathname with +repl+ added as a suffix to the basename. 212 * 213 * If self has no extension part, +repl+ is appended. 214 * 215 * Pathname.new('/usr/bin/shutdown').sub_ext('.rb') 216 * #=> #<Pathname:/usr/bin/shutdown.rb> 217 */ 218static VALUE 219path_sub_ext(VALUE self, VALUE repl) 220{ 221 VALUE str = get_strpath(self); 222 VALUE str2; 223 long extlen; 224 const char *ext; 225 const char *p; 226 227 StringValue(repl); 228 p = RSTRING_PTR(str); 229 extlen = RSTRING_LEN(str); 230 ext = ruby_enc_find_extname(p, &extlen, rb_enc_get(str)); 231 if (ext == NULL) { 232 ext = p + RSTRING_LEN(str); 233 } 234 else if (extlen <= 1) { 235 ext += extlen; 236 } 237 str2 = rb_str_subseq(str, 0, ext-p); 238 rb_str_append(str2, repl); 239 OBJ_INFECT(str2, str); 240 return rb_class_new_instance(1, &str2, rb_obj_class(self)); 241} 242 243/* Facade for File */ 244 245/* 246 * Returns the real (absolute) pathname for +self+ in the actual 247 * filesystem. 248 * 249 * Does not contain symlinks or useless dots, +..+ and +.+. 250 * 251 * All components of the pathname must exist when this method is 252 * called. 253 * 254 */ 255static VALUE 256path_realpath(int argc, VALUE *argv, VALUE self) 257{ 258 VALUE basedir, str; 259 rb_scan_args(argc, argv, "01", &basedir); 260 str = rb_funcall(rb_cFile, rb_intern("realpath"), 2, get_strpath(self), basedir); 261 return rb_class_new_instance(1, &str, rb_obj_class(self)); 262} 263 264/* 265 * Returns the real (absolute) pathname of +self+ in the actual filesystem. 266 * 267 * Does not contain symlinks or useless dots, +..+ and +.+. 268 * 269 * The last component of the real pathname can be nonexistent. 270 */ 271static VALUE 272path_realdirpath(int argc, VALUE *argv, VALUE self) 273{ 274 VALUE basedir, str; 275 rb_scan_args(argc, argv, "01", &basedir); 276 str = rb_funcall(rb_cFile, rb_intern("realdirpath"), 2, get_strpath(self), basedir); 277 return rb_class_new_instance(1, &str, rb_obj_class(self)); 278} 279 280/* 281 * call-seq: 282 * pathname.each_line {|line| ... } 283 * pathname.each_line(sep=$/ [, open_args]) {|line| block } -> nil 284 * pathname.each_line(limit [, open_args]) {|line| block } -> nil 285 * pathname.each_line(sep, limit [, open_args]) {|line| block } -> nil 286 * pathname.each_line(...) -> an_enumerator 287 * 288 * Iterates over each line in the file and yields a String object for each. 289 */ 290static VALUE 291path_each_line(int argc, VALUE *argv, VALUE self) 292{ 293 VALUE args[4]; 294 int n; 295 296 args[0] = get_strpath(self); 297 n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]); 298 if (rb_block_given_p()) { 299 return rb_block_call(rb_cIO, rb_intern("foreach"), 1+n, args, 0, 0); 300 } 301 else { 302 return rb_funcall2(rb_cIO, rb_intern("foreach"), 1+n, args); 303 } 304} 305 306/* 307 * call-seq: 308 * pathname.read([length [, offset]]) -> string 309 * pathname.read([length [, offset]], open_args) -> string 310 * 311 * Returns all data from the file, or the first +N+ bytes if specified. 312 * 313 * See IO.read. 314 * 315 */ 316static VALUE 317path_read(int argc, VALUE *argv, VALUE self) 318{ 319 VALUE args[4]; 320 int n; 321 322 args[0] = get_strpath(self); 323 n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]); 324 return rb_funcall2(rb_cIO, rb_intern("read"), 1+n, args); 325} 326 327/* 328 * call-seq: 329 * pathname.binread([length [, offset]]) -> string 330 * 331 * Returns all the bytes from the file, or the first +N+ if specified. 332 * 333 * See IO.binread. 334 * 335 */ 336static VALUE 337path_binread(int argc, VALUE *argv, VALUE self) 338{ 339 VALUE args[3]; 340 int n; 341 342 args[0] = get_strpath(self); 343 n = rb_scan_args(argc, argv, "02", &args[1], &args[2]); 344 return rb_funcall2(rb_cIO, rb_intern("binread"), 1+n, args); 345} 346 347/* 348 * call-seq: 349 * pathname.readlines(sep=$/ [, open_args]) -> array 350 * pathname.readlines(limit [, open_args]) -> array 351 * pathname.readlines(sep, limit [, open_args]) -> array 352 * 353 * Returns all the lines from the file. 354 * 355 * See IO.readlines. 356 * 357 */ 358static VALUE 359path_readlines(int argc, VALUE *argv, VALUE self) 360{ 361 VALUE args[4]; 362 int n; 363 364 args[0] = get_strpath(self); 365 n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]); 366 return rb_funcall2(rb_cIO, rb_intern("readlines"), 1+n, args); 367} 368 369/* 370 * call-seq: 371 * pathname.sysopen([mode, [perm]]) -> fixnum 372 * 373 * See IO.sysopen. 374 * 375 */ 376static VALUE 377path_sysopen(int argc, VALUE *argv, VALUE self) 378{ 379 VALUE args[3]; 380 int n; 381 382 args[0] = get_strpath(self); 383 n = rb_scan_args(argc, argv, "02", &args[1], &args[2]); 384 return rb_funcall2(rb_cIO, rb_intern("sysopen"), 1+n, args); 385} 386 387/* 388 * call-seq: 389 * pathname.atime -> time 390 * 391 * Returns the last access time for the file. 392 * 393 * See File.atime. 394 */ 395static VALUE 396path_atime(VALUE self) 397{ 398 return rb_funcall(rb_cFile, rb_intern("atime"), 1, get_strpath(self)); 399} 400 401/* 402 * call-seq: 403 * pathname.ctime -> time 404 * 405 * Returns the last change time, using directory information, not the file itself. 406 * 407 * See File.ctime. 408 */ 409static VALUE 410path_ctime(VALUE self) 411{ 412 return rb_funcall(rb_cFile, rb_intern("ctime"), 1, get_strpath(self)); 413} 414 415/* 416 * call-seq: 417 * pathname.mtime -> time 418 * 419 * Returns the last modified time of the file. 420 * 421 * See File.mtime. 422 */ 423static VALUE 424path_mtime(VALUE self) 425{ 426 return rb_funcall(rb_cFile, rb_intern("mtime"), 1, get_strpath(self)); 427} 428 429/* 430 * call-seq: 431 * pathname.chmod -> integer 432 * 433 * Changes file permissions. 434 * 435 * See File.chmod. 436 */ 437static VALUE 438path_chmod(VALUE self, VALUE mode) 439{ 440 return rb_funcall(rb_cFile, rb_intern("chmod"), 2, mode, get_strpath(self)); 441} 442 443/* 444 * call-seq: 445 * pathname.lchmod -> integer 446 * 447 * Same as Pathname.chmod, but does not follow symbolic links. 448 * 449 * See File.lchmod. 450 */ 451static VALUE 452path_lchmod(VALUE self, VALUE mode) 453{ 454 return rb_funcall(rb_cFile, rb_intern("lchmod"), 2, mode, get_strpath(self)); 455} 456 457/* 458 * call-seq: 459 * pathname.chown -> integer 460 * 461 * Change owner and group of the file. 462 * 463 * See File.chown. 464 */ 465static VALUE 466path_chown(VALUE self, VALUE owner, VALUE group) 467{ 468 return rb_funcall(rb_cFile, rb_intern("chown"), 3, owner, group, get_strpath(self)); 469} 470 471/* 472 * call-seq: 473 * pathname.lchown -> integer 474 * 475 * Same as Pathname.chown, but does not follow symbolic links. 476 * 477 * See File.lchown. 478 */ 479static VALUE 480path_lchown(VALUE self, VALUE owner, VALUE group) 481{ 482 return rb_funcall(rb_cFile, rb_intern("lchown"), 3, owner, group, get_strpath(self)); 483} 484 485/* 486 * call-seq: 487 * pathname.fnmatch(pattern, [flags]) -> string 488 * pathname.fnmatch?(pattern, [flags]) -> string 489 * 490 * Return +true+ if the receiver matches the given pattern. 491 * 492 * See File.fnmatch. 493 */ 494static VALUE 495path_fnmatch(int argc, VALUE *argv, VALUE self) 496{ 497 VALUE str = get_strpath(self); 498 VALUE pattern, flags; 499 if (rb_scan_args(argc, argv, "11", &pattern, &flags) == 1) 500 return rb_funcall(rb_cFile, rb_intern("fnmatch"), 2, pattern, str); 501 else 502 return rb_funcall(rb_cFile, rb_intern("fnmatch"), 3, pattern, str, flags); 503} 504 505/* 506 * call-seq: 507 * pathname.ftype -> string 508 * 509 * Returns "type" of file ("file", "directory", etc). 510 * 511 * See File.ftype. 512 */ 513static VALUE 514path_ftype(VALUE self) 515{ 516 return rb_funcall(rb_cFile, rb_intern("ftype"), 1, get_strpath(self)); 517} 518 519/* 520 * call-seq: 521 * pathname.make_link(old) 522 * 523 * Creates a hard link at _pathname_. 524 * 525 * See File.link. 526 */ 527static VALUE 528path_make_link(VALUE self, VALUE old) 529{ 530 return rb_funcall(rb_cFile, rb_intern("link"), 2, old, get_strpath(self)); 531} 532 533/* 534 * Opens the file for reading or writing. 535 * 536 * See File.open. 537 */ 538static VALUE 539path_open(int argc, VALUE *argv, VALUE self) 540{ 541 VALUE args[4]; 542 int n; 543 544 args[0] = get_strpath(self); 545 n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]); 546 if (rb_block_given_p()) { 547 return rb_block_call(rb_cFile, rb_intern("open"), 1+n, args, 0, 0); 548 } 549 else { 550 return rb_funcall2(rb_cFile, rb_intern("open"), 1+n, args); 551 } 552} 553 554/* 555 * Read symbolic link. 556 * 557 * See File.readlink. 558 */ 559static VALUE 560path_readlink(VALUE self) 561{ 562 VALUE str; 563 str = rb_funcall(rb_cFile, rb_intern("readlink"), 1, get_strpath(self)); 564 return rb_class_new_instance(1, &str, rb_obj_class(self)); 565} 566 567/* 568 * Rename the file. 569 * 570 * See File.rename. 571 */ 572static VALUE 573path_rename(VALUE self, VALUE to) 574{ 575 return rb_funcall(rb_cFile, rb_intern("rename"), 2, get_strpath(self), to); 576} 577 578/* 579 * Returns a File::Stat object. 580 * 581 * See File.stat. 582 */ 583static VALUE 584path_stat(VALUE self) 585{ 586 return rb_funcall(rb_cFile, rb_intern("stat"), 1, get_strpath(self)); 587} 588 589/* 590 * See File.lstat. 591 */ 592static VALUE 593path_lstat(VALUE self) 594{ 595 return rb_funcall(rb_cFile, rb_intern("lstat"), 1, get_strpath(self)); 596} 597 598/* 599 * call-seq: 600 * pathname.make_symlink(old) 601 * 602 * Creates a symbolic link. 603 * 604 * See File.symlink. 605 */ 606static VALUE 607path_make_symlink(VALUE self, VALUE old) 608{ 609 return rb_funcall(rb_cFile, rb_intern("symlink"), 2, old, get_strpath(self)); 610} 611 612/* 613 * Truncates the file to +length+ bytes. 614 * 615 * See File.truncate. 616 */ 617static VALUE 618path_truncate(VALUE self, VALUE length) 619{ 620 return rb_funcall(rb_cFile, rb_intern("truncate"), 2, get_strpath(self), length); 621} 622 623/* 624 * Update the access and modification times of the file. 625 * 626 * See File.utime. 627 */ 628static VALUE 629path_utime(VALUE self, VALUE atime, VALUE mtime) 630{ 631 return rb_funcall(rb_cFile, rb_intern("utime"), 3, atime, mtime, get_strpath(self)); 632} 633 634/* 635 * Returns the last component of the path. 636 * 637 * See File.basename. 638 */ 639static VALUE 640path_basename(int argc, VALUE *argv, VALUE self) 641{ 642 VALUE str = get_strpath(self); 643 VALUE fext; 644 if (rb_scan_args(argc, argv, "01", &fext) == 0) 645 str = rb_funcall(rb_cFile, rb_intern("basename"), 1, str); 646 else 647 str = rb_funcall(rb_cFile, rb_intern("basename"), 2, str, fext); 648 return rb_class_new_instance(1, &str, rb_obj_class(self)); 649} 650 651/* 652 * Returns all but the last component of the path. 653 * 654 * See File.dirname. 655 */ 656static VALUE 657path_dirname(VALUE self) 658{ 659 VALUE str = get_strpath(self); 660 str = rb_funcall(rb_cFile, rb_intern("dirname"), 1, str); 661 return rb_class_new_instance(1, &str, rb_obj_class(self)); 662} 663 664/* 665 * Returns the file's extension. 666 * 667 * See File.extname. 668 */ 669static VALUE 670path_extname(VALUE self) 671{ 672 VALUE str = get_strpath(self); 673 return rb_funcall(rb_cFile, rb_intern("extname"), 1, str); 674} 675 676/* 677 * Returns the absolute path for the file. 678 * 679 * See File.expand_path. 680 */ 681static VALUE 682path_expand_path(int argc, VALUE *argv, VALUE self) 683{ 684 VALUE str = get_strpath(self); 685 VALUE dname; 686 if (rb_scan_args(argc, argv, "01", &dname) == 0) 687 str = rb_funcall(rb_cFile, rb_intern("expand_path"), 1, str); 688 else 689 str = rb_funcall(rb_cFile, rb_intern("expand_path"), 2, str, dname); 690 return rb_class_new_instance(1, &str, rb_obj_class(self)); 691} 692 693/* 694 * Returns the #dirname and the #basename in an Array. 695 * 696 * See File.split. 697 */ 698static VALUE 699path_split(VALUE self) 700{ 701 VALUE str = get_strpath(self); 702 VALUE ary, dirname, basename; 703 ary = rb_funcall(rb_cFile, rb_intern("split"), 1, str); 704 ary = rb_check_array_type(ary); 705 dirname = rb_ary_entry(ary, 0); 706 basename = rb_ary_entry(ary, 1); 707 dirname = rb_class_new_instance(1, &dirname, rb_obj_class(self)); 708 basename = rb_class_new_instance(1, &basename, rb_obj_class(self)); 709 return rb_ary_new3(2, dirname, basename); 710} 711 712/* 713 * See FileTest.blockdev?. 714 */ 715static VALUE 716path_blockdev_p(VALUE self) 717{ 718 return rb_funcall(rb_mFileTest, rb_intern("blockdev?"), 1, get_strpath(self)); 719} 720 721/* 722 * See FileTest.chardev?. 723 */ 724static VALUE 725path_chardev_p(VALUE self) 726{ 727 return rb_funcall(rb_mFileTest, rb_intern("chardev?"), 1, get_strpath(self)); 728} 729 730/* 731 * See FileTest.executable?. 732 */ 733static VALUE 734path_executable_p(VALUE self) 735{ 736 return rb_funcall(rb_mFileTest, rb_intern("executable?"), 1, get_strpath(self)); 737} 738 739/* 740 * See FileTest.executable_real?. 741 */ 742static VALUE 743path_executable_real_p(VALUE self) 744{ 745 return rb_funcall(rb_mFileTest, rb_intern("executable_real?"), 1, get_strpath(self)); 746} 747 748/* 749 * See FileTest.exist?. 750 */ 751static VALUE 752path_exist_p(VALUE self) 753{ 754 return rb_funcall(rb_mFileTest, rb_intern("exist?"), 1, get_strpath(self)); 755} 756 757/* 758 * See FileTest.grpowned?. 759 */ 760static VALUE 761path_grpowned_p(VALUE self) 762{ 763 return rb_funcall(rb_mFileTest, rb_intern("grpowned?"), 1, get_strpath(self)); 764} 765 766/* 767 * See FileTest.directory?. 768 */ 769static VALUE 770path_directory_p(VALUE self) 771{ 772 return rb_funcall(rb_mFileTest, rb_intern("directory?"), 1, get_strpath(self)); 773} 774 775/* 776 * See FileTest.file?. 777 */ 778static VALUE 779path_file_p(VALUE self) 780{ 781 return rb_funcall(rb_mFileTest, rb_intern("file?"), 1, get_strpath(self)); 782} 783 784/* 785 * See FileTest.pipe?. 786 */ 787static VALUE 788path_pipe_p(VALUE self) 789{ 790 return rb_funcall(rb_mFileTest, rb_intern("pipe?"), 1, get_strpath(self)); 791} 792 793/* 794 * See FileTest.socket?. 795 */ 796static VALUE 797path_socket_p(VALUE self) 798{ 799 return rb_funcall(rb_mFileTest, rb_intern("socket?"), 1, get_strpath(self)); 800} 801 802/* 803 * See FileTest.owned?. 804 */ 805static VALUE 806path_owned_p(VALUE self) 807{ 808 return rb_funcall(rb_mFileTest, rb_intern("owned?"), 1, get_strpath(self)); 809} 810 811/* 812 * See FileTest.readable?. 813 */ 814static VALUE 815path_readable_p(VALUE self) 816{ 817 return rb_funcall(rb_mFileTest, rb_intern("readable?"), 1, get_strpath(self)); 818} 819 820/* 821 * See FileTest.world_readable?. 822 */ 823static VALUE 824path_world_readable_p(VALUE self) 825{ 826 return rb_funcall(rb_mFileTest, rb_intern("world_readable?"), 1, get_strpath(self)); 827} 828 829/* 830 * See FileTest.readable_real?. 831 */ 832static VALUE 833path_readable_real_p(VALUE self) 834{ 835 return rb_funcall(rb_mFileTest, rb_intern("readable_real?"), 1, get_strpath(self)); 836} 837 838/* 839 * See FileTest.setuid?. 840 */ 841static VALUE 842path_setuid_p(VALUE self) 843{ 844 return rb_funcall(rb_mFileTest, rb_intern("setuid?"), 1, get_strpath(self)); 845} 846 847/* 848 * See FileTest.setgid?. 849 */ 850static VALUE 851path_setgid_p(VALUE self) 852{ 853 return rb_funcall(rb_mFileTest, rb_intern("setgid?"), 1, get_strpath(self)); 854} 855 856/* 857 * See FileTest.size. 858 */ 859static VALUE 860path_size(VALUE self) 861{ 862 return rb_funcall(rb_mFileTest, rb_intern("size"), 1, get_strpath(self)); 863} 864 865/* 866 * See FileTest.size?. 867 */ 868static VALUE 869path_size_p(VALUE self) 870{ 871 return rb_funcall(rb_mFileTest, rb_intern("size?"), 1, get_strpath(self)); 872} 873 874/* 875 * See FileTest.sticky?. 876 */ 877static VALUE 878path_sticky_p(VALUE self) 879{ 880 return rb_funcall(rb_mFileTest, rb_intern("sticky?"), 1, get_strpath(self)); 881} 882 883/* 884 * See FileTest.symlink?. 885 */ 886static VALUE 887path_symlink_p(VALUE self) 888{ 889 return rb_funcall(rb_mFileTest, rb_intern("symlink?"), 1, get_strpath(self)); 890} 891 892/* 893 * See FileTest.writable?. 894 */ 895static VALUE 896path_writable_p(VALUE self) 897{ 898 return rb_funcall(rb_mFileTest, rb_intern("writable?"), 1, get_strpath(self)); 899} 900 901/* 902 * See FileTest.world_writable?. 903 */ 904static VALUE 905path_world_writable_p(VALUE self) 906{ 907 return rb_funcall(rb_mFileTest, rb_intern("world_writable?"), 1, get_strpath(self)); 908} 909 910/* 911 * See FileTest.writable_real?. 912 */ 913static VALUE 914path_writable_real_p(VALUE self) 915{ 916 return rb_funcall(rb_mFileTest, rb_intern("writable_real?"), 1, get_strpath(self)); 917} 918 919/* 920 * See FileTest.zero?. 921 */ 922static VALUE 923path_zero_p(VALUE self) 924{ 925 return rb_funcall(rb_mFileTest, rb_intern("zero?"), 1, get_strpath(self)); 926} 927 928static VALUE 929glob_i(VALUE elt, VALUE klass, int argc, VALUE *argv) 930{ 931 return rb_yield(rb_class_new_instance(1, &elt, klass)); 932} 933 934/* 935 * Returns or yields Pathname objects. 936 * 937 * Pathname.glob("config/" "*.rb") 938 * #=> [#<Pathname:config/environment.rb>, #<Pathname:config/routes.rb>, ..] 939 * 940 * See Dir.glob. 941 */ 942static VALUE 943path_s_glob(int argc, VALUE *argv, VALUE klass) 944{ 945 VALUE args[2]; 946 int n; 947 948 n = rb_scan_args(argc, argv, "11", &args[0], &args[1]); 949 if (rb_block_given_p()) { 950 return rb_block_call(rb_cDir, rb_intern("glob"), n, args, glob_i, klass); 951 } 952 else { 953 VALUE ary; 954 long i; 955 ary = rb_funcall2(rb_cDir, rb_intern("glob"), n, args); 956 ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary"); 957 for (i = 0; i < RARRAY_LEN(ary); i++) { 958 VALUE elt = RARRAY_PTR(ary)[i]; 959 elt = rb_class_new_instance(1, &elt, klass); 960 rb_ary_store(ary, i, elt); 961 } 962 return ary; 963 } 964} 965 966/* 967 * Returns the current working directory as a Pathname. 968 * 969 * Pathname.getwd 970 * #=> #<Pathname:/home/zzak/projects/ruby> 971 * 972 * See Dir.getwd. 973 */ 974static VALUE 975path_s_getwd(VALUE klass) 976{ 977 VALUE str; 978 str = rb_funcall(rb_cDir, rb_intern("getwd"), 0); 979 return rb_class_new_instance(1, &str, klass); 980} 981 982/* 983 * Return the entries (files and subdirectories) in the directory, each as a 984 * Pathname object. 985 * 986 * The results contains just the names in the directory, without any trailing 987 * slashes or recursive look-up. 988 * 989 * pp Pathname.new('/usr/local').entries 990 * #=> [#<Pathname:share>, 991 * # #<Pathname:lib>, 992 * # #<Pathname:..>, 993 * # #<Pathname:include>, 994 * # #<Pathname:etc>, 995 * # #<Pathname:bin>, 996 * # #<Pathname:man>, 997 * # #<Pathname:games>, 998 * # #<Pathname:.>, 999 * # #<Pathname:sbin>, 1000 * # #<Pathname:src>] 1001 * 1002 * The result may contain the current directory <code>#<Pathname:.></code> and 1003 * the parent directory <code>#<Pathname:..></code>. 1004 * 1005 * If you don't want +.+ and +..+ and 1006 * want directories, consider Pathname#children. 1007 */ 1008static VALUE 1009path_entries(VALUE self) 1010{ 1011 VALUE klass, str, ary; 1012 long i; 1013 klass = rb_obj_class(self); 1014 str = get_strpath(self); 1015 ary = rb_funcall(rb_cDir, rb_intern("entries"), 1, str); 1016 ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary"); 1017 for (i = 0; i < RARRAY_LEN(ary); i++) { 1018 VALUE elt = RARRAY_PTR(ary)[i]; 1019 elt = rb_class_new_instance(1, &elt, klass); 1020 rb_ary_store(ary, i, elt); 1021 } 1022 return ary; 1023} 1024 1025/* 1026 * Create the referenced directory. 1027 * 1028 * See Dir.mkdir. 1029 */ 1030static VALUE 1031path_mkdir(int argc, VALUE *argv, VALUE self) 1032{ 1033 VALUE str = get_strpath(self); 1034 VALUE vmode; 1035 if (rb_scan_args(argc, argv, "01", &vmode) == 0) 1036 return rb_funcall(rb_cDir, rb_intern("mkdir"), 1, str); 1037 else 1038 return rb_funcall(rb_cDir, rb_intern("mkdir"), 2, str, vmode); 1039} 1040 1041/* 1042 * Remove the referenced directory. 1043 * 1044 * See Dir.rmdir. 1045 */ 1046static VALUE 1047path_rmdir(VALUE self) 1048{ 1049 return rb_funcall(rb_cDir, rb_intern("rmdir"), 1, get_strpath(self)); 1050} 1051 1052/* 1053 * Opens the referenced directory. 1054 * 1055 * See Dir.open. 1056 */ 1057static VALUE 1058path_opendir(VALUE self) 1059{ 1060 VALUE args[1]; 1061 1062 args[0] = get_strpath(self); 1063 return rb_block_call(rb_cDir, rb_intern("open"), 1, args, 0, 0); 1064} 1065 1066static VALUE 1067each_entry_i(VALUE elt, VALUE klass, int argc, VALUE *argv) 1068{ 1069 return rb_yield(rb_class_new_instance(1, &elt, klass)); 1070} 1071 1072/* 1073 * Iterates over the entries (files and subdirectories) in the directory, 1074 * yielding a Pathname object for each entry. 1075 */ 1076static VALUE 1077path_each_entry(VALUE self) 1078{ 1079 VALUE args[1]; 1080 1081 args[0] = get_strpath(self); 1082 return rb_block_call(rb_cDir, rb_intern("foreach"), 1, args, each_entry_i, rb_obj_class(self)); 1083} 1084 1085static VALUE 1086unlink_body(VALUE str) 1087{ 1088 return rb_funcall(rb_cDir, rb_intern("unlink"), 1, str); 1089} 1090 1091static VALUE 1092unlink_rescue(VALUE str, VALUE errinfo) 1093{ 1094 return rb_funcall(rb_cFile, rb_intern("unlink"), 1, str); 1095} 1096 1097/* 1098 * Removes a file or directory, using File.unlink if +self+ is a file, or 1099 * Dir.unlink as necessary. 1100 */ 1101static VALUE 1102path_unlink(VALUE self) 1103{ 1104 VALUE eENOTDIR = rb_const_get_at(rb_mErrno, rb_intern("ENOTDIR")); 1105 VALUE str = get_strpath(self); 1106 return rb_rescue2(unlink_body, str, unlink_rescue, str, eENOTDIR, (VALUE)0); 1107} 1108 1109/* 1110 * Creates a new Pathname object. 1111 */ 1112static VALUE 1113path_f_pathname(VALUE self, VALUE str) 1114{ 1115 return rb_class_new_instance(1, &str, rb_cPathname); 1116} 1117 1118/* 1119 * 1120 * Pathname represents the name of a file or directory on the filesystem, 1121 * but not the file itself. 1122 * 1123 * The pathname depends on the Operating System: Unix, Windows, etc. 1124 * This library works with pathnames of local OS, however non-Unix pathnames 1125 * are supported experimentally. 1126 * 1127 * A Pathname can be relative or absolute. It's not until you try to 1128 * reference the file that it even matters whether the file exists or not. 1129 * 1130 * Pathname is immutable. It has no method for destructive update. 1131 * 1132 * The goal of this class is to manipulate file path information in a neater 1133 * way than standard Ruby provides. The examples below demonstrate the 1134 * difference. 1135 * 1136 * *All* functionality from File, FileTest, and some from Dir and FileUtils is 1137 * included, in an unsurprising way. It is essentially a facade for all of 1138 * these, and more. 1139 * 1140 * == Examples 1141 * 1142 * === Example 1: Using Pathname 1143 * 1144 * require 'pathname' 1145 * pn = Pathname.new("/usr/bin/ruby") 1146 * size = pn.size # 27662 1147 * isdir = pn.directory? # false 1148 * dir = pn.dirname # Pathname:/usr/bin 1149 * base = pn.basename # Pathname:ruby 1150 * dir, base = pn.split # [Pathname:/usr/bin, Pathname:ruby] 1151 * data = pn.read 1152 * pn.open { |f| _ } 1153 * pn.each_line { |line| _ } 1154 * 1155 * === Example 2: Using standard Ruby 1156 * 1157 * pn = "/usr/bin/ruby" 1158 * size = File.size(pn) # 27662 1159 * isdir = File.directory?(pn) # false 1160 * dir = File.dirname(pn) # "/usr/bin" 1161 * base = File.basename(pn) # "ruby" 1162 * dir, base = File.split(pn) # ["/usr/bin", "ruby"] 1163 * data = File.read(pn) 1164 * File.open(pn) { |f| _ } 1165 * File.foreach(pn) { |line| _ } 1166 * 1167 * === Example 3: Special features 1168 * 1169 * p1 = Pathname.new("/usr/lib") # Pathname:/usr/lib 1170 * p2 = p1 + "ruby/1.8" # Pathname:/usr/lib/ruby/1.8 1171 * p3 = p1.parent # Pathname:/usr 1172 * p4 = p2.relative_path_from(p3) # Pathname:lib/ruby/1.8 1173 * pwd = Pathname.pwd # Pathname:/home/gavin 1174 * pwd.absolute? # true 1175 * p5 = Pathname.new "." # Pathname:. 1176 * p5 = p5 + "music/../articles" # Pathname:music/../articles 1177 * p5.cleanpath # Pathname:articles 1178 * p5.realpath # Pathname:/home/gavin/articles 1179 * p5.children # [Pathname:/home/gavin/articles/linux, ...] 1180 * 1181 * == Breakdown of functionality 1182 * 1183 * === Core methods 1184 * 1185 * These methods are effectively manipulating a String, because that's 1186 * all a path is. None of these access the file system except for 1187 * #mountpoint?, #children, #each_child, #realdirpath and #realpath. 1188 * 1189 * - + 1190 * - #join 1191 * - #parent 1192 * - #root? 1193 * - #absolute? 1194 * - #relative? 1195 * - #relative_path_from 1196 * - #each_filename 1197 * - #cleanpath 1198 * - #realpath 1199 * - #realdirpath 1200 * - #children 1201 * - #each_child 1202 * - #mountpoint? 1203 * 1204 * === File status predicate methods 1205 * 1206 * These methods are a facade for FileTest: 1207 * - #blockdev? 1208 * - #chardev? 1209 * - #directory? 1210 * - #executable? 1211 * - #executable_real? 1212 * - #exist? 1213 * - #file? 1214 * - #grpowned? 1215 * - #owned? 1216 * - #pipe? 1217 * - #readable? 1218 * - #world_readable? 1219 * - #readable_real? 1220 * - #setgid? 1221 * - #setuid? 1222 * - #size 1223 * - #size? 1224 * - #socket? 1225 * - #sticky? 1226 * - #symlink? 1227 * - #writable? 1228 * - #world_writable? 1229 * - #writable_real? 1230 * - #zero? 1231 * 1232 * === File property and manipulation methods 1233 * 1234 * These methods are a facade for File: 1235 * - #atime 1236 * - #ctime 1237 * - #mtime 1238 * - #chmod(mode) 1239 * - #lchmod(mode) 1240 * - #chown(owner, group) 1241 * - #lchown(owner, group) 1242 * - #fnmatch(pattern, *args) 1243 * - #fnmatch?(pattern, *args) 1244 * - #ftype 1245 * - #make_link(old) 1246 * - #open(*args, &block) 1247 * - #readlink 1248 * - #rename(to) 1249 * - #stat 1250 * - #lstat 1251 * - #make_symlink(old) 1252 * - #truncate(length) 1253 * - #utime(atime, mtime) 1254 * - #basename(*args) 1255 * - #dirname 1256 * - #extname 1257 * - #expand_path(*args) 1258 * - #split 1259 * 1260 * === Directory methods 1261 * 1262 * These methods are a facade for Dir: 1263 * - Pathname.glob(*args) 1264 * - Pathname.getwd / Pathname.pwd 1265 * - #rmdir 1266 * - #entries 1267 * - #each_entry(&block) 1268 * - #mkdir(*args) 1269 * - #opendir(*args) 1270 * 1271 * === IO 1272 * 1273 * These methods are a facade for IO: 1274 * - #each_line(*args, &block) 1275 * - #read(*args) 1276 * - #binread(*args) 1277 * - #readlines(*args) 1278 * - #sysopen(*args) 1279 * 1280 * === Utilities 1281 * 1282 * These methods are a mixture of Find, FileUtils, and others: 1283 * - #find(&block) 1284 * - #mkpath 1285 * - #rmtree 1286 * - #unlink / #delete 1287 * 1288 * 1289 * == Method documentation 1290 * 1291 * As the above section shows, most of the methods in Pathname are facades. The 1292 * documentation for these methods generally just says, for instance, "See 1293 * FileTest.writable?", as you should be familiar with the original method 1294 * anyway, and its documentation (e.g. through +ri+) will contain more 1295 * information. In some cases, a brief description will follow. 1296 */ 1297void 1298Init_pathname() 1299{ 1300 id_at_path = rb_intern("@path"); 1301 id_to_path = rb_intern("to_path"); 1302 1303 rb_cPathname = rb_define_class("Pathname", rb_cObject); 1304 rb_define_method(rb_cPathname, "initialize", path_initialize, 1); 1305 rb_define_method(rb_cPathname, "freeze", path_freeze, 0); 1306 rb_define_method(rb_cPathname, "taint", path_taint, 0); 1307 rb_define_method(rb_cPathname, "untaint", path_untaint, 0); 1308 rb_define_method(rb_cPathname, "==", path_eq, 1); 1309 rb_define_method(rb_cPathname, "===", path_eq, 1); 1310 rb_define_method(rb_cPathname, "eql?", path_eq, 1); 1311 rb_define_method(rb_cPathname, "<=>", path_cmp, 1); 1312 rb_define_method(rb_cPathname, "hash", path_hash, 0); 1313 rb_define_method(rb_cPathname, "to_s", path_to_s, 0); 1314 rb_define_method(rb_cPathname, "to_path", path_to_s, 0); 1315 rb_define_method(rb_cPathname, "inspect", path_inspect, 0); 1316 rb_define_method(rb_cPathname, "sub", path_sub, -1); 1317 rb_define_method(rb_cPathname, "sub_ext", path_sub_ext, 1); 1318 rb_define_method(rb_cPathname, "realpath", path_realpath, -1); 1319 rb_define_method(rb_cPathname, "realdirpath", path_realdirpath, -1); 1320 rb_define_method(rb_cPathname, "each_line", path_each_line, -1); 1321 rb_define_method(rb_cPathname, "read", path_read, -1); 1322 rb_define_method(rb_cPathname, "binread", path_binread, -1); 1323 rb_define_method(rb_cPathname, "readlines", path_readlines, -1); 1324 rb_define_method(rb_cPathname, "sysopen", path_sysopen, -1); 1325 rb_define_method(rb_cPathname, "atime", path_atime, 0); 1326 rb_define_method(rb_cPathname, "ctime", path_ctime, 0); 1327 rb_define_method(rb_cPathname, "mtime", path_mtime, 0); 1328 rb_define_method(rb_cPathname, "chmod", path_chmod, 1); 1329 rb_define_method(rb_cPathname, "lchmod", path_lchmod, 1); 1330 rb_define_method(rb_cPathname, "chown", path_chown, 2); 1331 rb_define_method(rb_cPathname, "lchown", path_lchown, 2); 1332 rb_define_method(rb_cPathname, "fnmatch", path_fnmatch, -1); 1333 rb_define_method(rb_cPathname, "fnmatch?", path_fnmatch, -1); 1334 rb_define_method(rb_cPathname, "ftype", path_ftype, 0); 1335 rb_define_method(rb_cPathname, "make_link", path_make_link, 1); 1336 rb_define_method(rb_cPathname, "open", path_open, -1); 1337 rb_define_method(rb_cPathname, "readlink", path_readlink, 0); 1338 rb_define_method(rb_cPathname, "rename", path_rename, 1); 1339 rb_define_method(rb_cPathname, "stat", path_stat, 0); 1340 rb_define_method(rb_cPathname, "lstat", path_lstat, 0); 1341 rb_define_method(rb_cPathname, "make_symlink", path_make_symlink, 1); 1342 rb_define_method(rb_cPathname, "truncate", path_truncate, 1); 1343 rb_define_method(rb_cPathname, "utime", path_utime, 2); 1344 rb_define_method(rb_cPathname, "basename", path_basename, -1); 1345 rb_define_method(rb_cPathname, "dirname", path_dirname, 0); 1346 rb_define_method(rb_cPathname, "extname", path_extname, 0); 1347 rb_define_method(rb_cPathname, "expand_path", path_expand_path, -1); 1348 rb_define_method(rb_cPathname, "split", path_split, 0); 1349 rb_define_method(rb_cPathname, "blockdev?", path_blockdev_p, 0); 1350 rb_define_method(rb_cPathname, "chardev?", path_chardev_p, 0); 1351 rb_define_method(rb_cPathname, "executable?", path_executable_p, 0); 1352 rb_define_method(rb_cPathname, "executable_real?", path_executable_real_p, 0); 1353 rb_define_method(rb_cPathname, "exist?", path_exist_p, 0); 1354 rb_define_method(rb_cPathname, "grpowned?", path_grpowned_p, 0); 1355 rb_define_method(rb_cPathname, "directory?", path_directory_p, 0); 1356 rb_define_method(rb_cPathname, "file?", path_file_p, 0); 1357 rb_define_method(rb_cPathname, "pipe?", path_pipe_p, 0); 1358 rb_define_method(rb_cPathname, "socket?", path_socket_p, 0); 1359 rb_define_method(rb_cPathname, "owned?", path_owned_p, 0); 1360 rb_define_method(rb_cPathname, "readable?", path_readable_p, 0); 1361 rb_define_method(rb_cPathname, "world_readable?", path_world_readable_p, 0); 1362 rb_define_method(rb_cPathname, "readable_real?", path_readable_real_p, 0); 1363 rb_define_method(rb_cPathname, "setuid?", path_setuid_p, 0); 1364 rb_define_method(rb_cPathname, "setgid?", path_setgid_p, 0); 1365 rb_define_method(rb_cPathname, "size", path_size, 0); 1366 rb_define_method(rb_cPathname, "size?", path_size_p, 0); 1367 rb_define_method(rb_cPathname, "sticky?", path_sticky_p, 0); 1368 rb_define_method(rb_cPathname, "symlink?", path_symlink_p, 0); 1369 rb_define_method(rb_cPathname, "writable?", path_writable_p, 0); 1370 rb_define_method(rb_cPathname, "world_writable?", path_world_writable_p, 0); 1371 rb_define_method(rb_cPathname, "writable_real?", path_writable_real_p, 0); 1372 rb_define_method(rb_cPathname, "zero?", path_zero_p, 0); 1373 rb_define_singleton_method(rb_cPathname, "glob", path_s_glob, -1); 1374 rb_define_singleton_method(rb_cPathname, "getwd", path_s_getwd, 0); 1375 rb_define_singleton_method(rb_cPathname, "pwd", path_s_getwd, 0); 1376 rb_define_method(rb_cPathname, "entries", path_entries, 0); 1377 rb_define_method(rb_cPathname, "mkdir", path_mkdir, -1); 1378 rb_define_method(rb_cPathname, "rmdir", path_rmdir, 0); 1379 rb_define_method(rb_cPathname, "opendir", path_opendir, 0); 1380 rb_define_method(rb_cPathname, "each_entry", path_each_entry, 0); 1381 rb_define_method(rb_cPathname, "unlink", path_unlink, 0); 1382 rb_define_method(rb_cPathname, "delete", path_unlink, 0); 1383 rb_undef_method(rb_cPathname, "=~"); 1384 rb_define_global_function("Pathname", path_f_pathname, 1); 1385} 1386