Ruby  1.9.3p286(2012-10-12revision37165)
ext/pathname/pathname.c
Go to the documentation of this file.
00001 #include "ruby.h"
00002 
00003 static VALUE rb_cPathname;
00004 static ID id_at_path, id_to_path;
00005 
00006 static VALUE
00007 get_strpath(VALUE obj)
00008 {
00009     VALUE strpath;
00010     strpath = rb_ivar_get(obj, id_at_path);
00011     if (TYPE(strpath) != T_STRING)
00012         rb_raise(rb_eTypeError, "unexpected @path");
00013     return strpath;
00014 }
00015 
00016 static void
00017 set_strpath(VALUE obj, VALUE val)
00018 {
00019     rb_ivar_set(obj, id_at_path, val);
00020 }
00021 
00022 /*
00023  * Create a Pathname object from the given String (or String-like object).
00024  * If +path+ contains a NUL character (<tt>\0</tt>), an ArgumentError is raised.
00025  */
00026 static VALUE
00027 path_initialize(VALUE self, VALUE arg)
00028 {
00029     VALUE str;
00030     if (TYPE(arg) == T_STRING) {
00031         str = arg;
00032     }
00033     else {
00034         str = rb_check_funcall(arg, id_to_path, 0, NULL);
00035         if (str == Qundef)
00036             str = arg;
00037         StringValue(str);
00038     }
00039     if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str)))
00040         rb_raise(rb_eArgError, "pathname contains null byte");
00041     str = rb_obj_dup(str);
00042 
00043     set_strpath(self, str);
00044     OBJ_INFECT(self, str);
00045     return self;
00046 }
00047 
00048 static VALUE
00049 path_freeze(VALUE self)
00050 {
00051     rb_call_super(0, 0);
00052     rb_str_freeze(get_strpath(self));
00053     return self;
00054 }
00055 
00056 static VALUE
00057 path_taint(VALUE self)
00058 {
00059     rb_call_super(0, 0);
00060     rb_obj_taint(get_strpath(self));
00061     return self;
00062 }
00063 
00064 static VALUE
00065 path_untaint(VALUE self)
00066 {
00067     rb_call_super(0, 0);
00068     rb_obj_untaint(get_strpath(self));
00069     return self;
00070 }
00071 
00072 /*
00073  *  Compare this pathname with +other+.  The comparison is string-based.
00074  *  Be aware that two different paths (<tt>foo.txt</tt> and <tt>./foo.txt</tt>)
00075  *  can refer to the same file.
00076  */
00077 static VALUE
00078 path_eq(VALUE self, VALUE other)
00079 {
00080     if (!rb_obj_is_kind_of(other, rb_cPathname))
00081         return Qfalse;
00082     return rb_str_equal(get_strpath(self), get_strpath(other));
00083 }
00084 
00085 /*
00086  *  Provides for comparing pathnames, case-sensitively.
00087  */
00088 static VALUE
00089 path_cmp(VALUE self, VALUE other)
00090 {
00091     VALUE s1, s2;
00092     char *p1, *p2;
00093     char *e1, *e2;
00094     if (!rb_obj_is_kind_of(other, rb_cPathname))
00095         return Qnil;
00096     s1 = get_strpath(self);
00097     s2 = get_strpath(other);
00098     p1 = RSTRING_PTR(s1);
00099     p2 = RSTRING_PTR(s2);
00100     e1 = p1 + RSTRING_LEN(s1);
00101     e2 = p2 + RSTRING_LEN(s2);
00102     while (p1 < e1 && p2 < e2) {
00103         int c1, c2;
00104         c1 = (unsigned char)*p1++;
00105         c2 = (unsigned char)*p2++;
00106         if (c1 == '/') c1 = '\0';
00107         if (c2 == '/') c2 = '\0';
00108         if (c1 != c2) {
00109             if (c1 < c2)
00110                 return INT2FIX(-1);
00111             else
00112                 return INT2FIX(1);
00113         }
00114     }
00115     if (p1 < e1)
00116         return INT2FIX(1);
00117     if (p2 < e2)
00118         return INT2FIX(-1);
00119     return INT2FIX(0);
00120 }
00121 
00122 /* :nodoc: */
00123 static VALUE
00124 path_hash(VALUE self)
00125 {
00126     return INT2FIX(rb_str_hash(get_strpath(self)));
00127 }
00128 
00129 /*
00130  *  call-seq:
00131  *    pathname.to_s             -> string
00132  *    pathname.to_path          -> string
00133  *
00134  *  Return the path as a String.
00135  *
00136  *  to_path is implemented so Pathname objects are usable with File.open, etc.
00137  */
00138 static VALUE
00139 path_to_s(VALUE self)
00140 {
00141     return rb_obj_dup(get_strpath(self));
00142 }
00143 
00144 /* :nodoc: */
00145 static VALUE
00146 path_inspect(VALUE self)
00147 {
00148     const char *c = rb_obj_classname(self);
00149     VALUE str = get_strpath(self);
00150     return rb_sprintf("#<%s:%s>", c, RSTRING_PTR(str));
00151 }
00152 
00153 /*
00154  * Return a pathname which is substituted by String#sub.
00155  */
00156 static VALUE
00157 path_sub(int argc, VALUE *argv, VALUE self)
00158 {
00159     VALUE str = get_strpath(self);
00160 
00161     if (rb_block_given_p()) {
00162         str = rb_block_call(str, rb_intern("sub"), argc, argv, 0, 0);
00163     }
00164     else {
00165         str = rb_funcall2(str, rb_intern("sub"), argc, argv);
00166     }
00167     return rb_class_new_instance(1, &str, rb_obj_class(self));
00168 }
00169 
00170 /*
00171  * Return a pathname which the extension of the basename is substituted by
00172  * <i>repl</i>.
00173  *
00174  * If self has no extension part, <i>repl</i> is appended.
00175  */
00176 static VALUE
00177 path_sub_ext(VALUE self, VALUE repl)
00178 {
00179     VALUE str = get_strpath(self);
00180     VALUE str2;
00181     long extlen;
00182     const char *ext;
00183     const char *p;
00184 
00185     StringValue(repl);
00186     p = RSTRING_PTR(str);
00187     ext = ruby_find_extname(p, &extlen);
00188     if (ext == NULL) {
00189         ext = p + RSTRING_LEN(str);
00190     }
00191     else if (extlen <= 1) {
00192         ext += extlen;
00193     }
00194     str2 = rb_str_dup(str);
00195     rb_str_resize(str2, ext-p);
00196     rb_str_append(str2, repl);
00197     OBJ_INFECT(str2, str);
00198     return rb_class_new_instance(1, &str2, rb_obj_class(self));
00199 }
00200 
00201 /* Facade for File */
00202 
00203 /*
00204  * Returns the real (absolute) pathname of +self+ in the actual
00205  * filesystem not containing symlinks or useless dots.
00206  *
00207  * All components of the pathname must exist when this method is
00208  * called.
00209  *
00210  */
00211 static VALUE
00212 path_realpath(int argc, VALUE *argv, VALUE self)
00213 {
00214     VALUE basedir, str;
00215     rb_scan_args(argc, argv, "01", &basedir);
00216     str = rb_funcall(rb_cFile, rb_intern("realpath"), 2, get_strpath(self), basedir);
00217     return rb_class_new_instance(1, &str, rb_obj_class(self));
00218 }
00219 
00220 /*
00221  * Returns the real (absolute) pathname of +self+ in the actual filesystem.
00222  * The real pathname doesn't contain symlinks or useless dots.
00223  *
00224  * The last component of the real pathname can be nonexistent.
00225  */
00226 static VALUE
00227 path_realdirpath(int argc, VALUE *argv, VALUE self)
00228 {
00229     VALUE basedir, str;
00230     rb_scan_args(argc, argv, "01", &basedir);
00231     str = rb_funcall(rb_cFile, rb_intern("realdirpath"), 2, get_strpath(self), basedir);
00232     return rb_class_new_instance(1, &str, rb_obj_class(self));
00233 }
00234 
00235 /*
00236  * call-seq:
00237  *   pathname.each_line {|line| ... }
00238  *   pathname.each_line(sep=$/ [, open_args]) {|line| block }     -> nil
00239  *   pathname.each_line(limit [, open_args]) {|line| block }      -> nil
00240  *   pathname.each_line(sep, limit [, open_args]) {|line| block } -> nil
00241  *   pathname.each_line(...)                                      -> an_enumerator
00242  *
00243  * #each_line iterates over the line in the file.  It yields a String object
00244  * for each line.
00245  *
00246  * This method is availabel since 1.8.1.
00247  */
00248 static VALUE
00249 path_each_line(int argc, VALUE *argv, VALUE self)
00250 {
00251     VALUE args[4];
00252     int n;
00253 
00254     args[0] = get_strpath(self);
00255     n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
00256     if (rb_block_given_p()) {
00257         return rb_block_call(rb_cIO, rb_intern("foreach"), 1+n, args, 0, 0);
00258     }
00259     else {
00260         return rb_funcall2(rb_cIO, rb_intern("foreach"), 1+n, args);
00261     }
00262 }
00263 
00264 /*
00265  * call-seq:
00266  *   pathname.read([length [, offset]]) -> string
00267  *   pathname.read([length [, offset]], open_args) -> string
00268  *
00269  * See <tt>IO.read</tt>.  Returns all data from the file, or the first +N+ bytes
00270  * if specified.
00271  *
00272  */
00273 static VALUE
00274 path_read(int argc, VALUE *argv, VALUE self)
00275 {
00276     VALUE args[4];
00277     int n;
00278 
00279     args[0] = get_strpath(self);
00280     n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
00281     return rb_funcall2(rb_cIO, rb_intern("read"), 1+n, args);
00282 }
00283 
00284 /*
00285  * call-seq:
00286  *   pathname.binread([length [, offset]]) -> string
00287  *
00288  * See <tt>IO.binread</tt>.  Returns all the bytes from the file, or the first +N+
00289  * if specified.
00290  *
00291  */
00292 static VALUE
00293 path_binread(int argc, VALUE *argv, VALUE self)
00294 {
00295     VALUE args[3];
00296     int n;
00297 
00298     args[0] = get_strpath(self);
00299     n = rb_scan_args(argc, argv, "02", &args[1], &args[2]);
00300     return rb_funcall2(rb_cIO, rb_intern("binread"), 1+n, args);
00301 }
00302 
00303 /*
00304  * call-seq:
00305  *   pathname.readlines(sep=$/ [, open_args])     -> array
00306  *   pathname.readlines(limit [, open_args])      -> array
00307  *   pathname.readlines(sep, limit [, open_args]) -> array
00308  *
00309  * See <tt>IO.readlines</tt>.  Returns all the lines from the file.
00310  *
00311  */
00312 static VALUE
00313 path_readlines(int argc, VALUE *argv, VALUE self)
00314 {
00315     VALUE args[4];
00316     int n;
00317 
00318     args[0] = get_strpath(self);
00319     n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
00320     return rb_funcall2(rb_cIO, rb_intern("readlines"), 1+n, args);
00321 }
00322 
00323 /*
00324  * call-seq:
00325  *   pathname.sysopen([mode, [perm]])  -> fixnum
00326  *
00327  * See <tt>IO.sysopen</tt>.
00328  *
00329  */
00330 static VALUE
00331 path_sysopen(int argc, VALUE *argv, VALUE self)
00332 {
00333     VALUE args[3];
00334     int n;
00335 
00336     args[0] = get_strpath(self);
00337     n = rb_scan_args(argc, argv, "02", &args[1], &args[2]);
00338     return rb_funcall2(rb_cIO, rb_intern("sysopen"), 1+n, args);
00339 }
00340 
00341 /*
00342  * See <tt>File.atime</tt>.  Returns last access time.
00343  */
00344 static VALUE
00345 path_atime(VALUE self)
00346 {
00347     return rb_funcall(rb_cFile, rb_intern("atime"), 1, get_strpath(self));
00348 }
00349 
00350 /*
00351  * See <tt>File.ctime</tt>.  Returns last (directory entry, not file) change time.
00352  */
00353 static VALUE
00354 path_ctime(VALUE self)
00355 {
00356     return rb_funcall(rb_cFile, rb_intern("ctime"), 1, get_strpath(self));
00357 }
00358 
00359 /*
00360  * See <tt>File.mtime</tt>.  Returns last modification time.
00361  */
00362 static VALUE
00363 path_mtime(VALUE self)
00364 {
00365     return rb_funcall(rb_cFile, rb_intern("mtime"), 1, get_strpath(self));
00366 }
00367 
00368 /*
00369  * See <tt>File.chmod</tt>.  Changes permissions.
00370  */
00371 static VALUE
00372 path_chmod(VALUE self, VALUE mode)
00373 {
00374     return rb_funcall(rb_cFile, rb_intern("chmod"), 2, mode, get_strpath(self));
00375 }
00376 
00377 /*
00378  * See <tt>File.lchmod</tt>.
00379  */
00380 static VALUE
00381 path_lchmod(VALUE self, VALUE mode)
00382 {
00383     return rb_funcall(rb_cFile, rb_intern("lchmod"), 2, mode, get_strpath(self));
00384 }
00385 
00386 /*
00387  * See <tt>File.chown</tt>.  Change owner and group of file.
00388  */
00389 static VALUE
00390 path_chown(VALUE self, VALUE owner, VALUE group)
00391 {
00392     return rb_funcall(rb_cFile, rb_intern("chown"), 3, owner, group, get_strpath(self));
00393 }
00394 
00395 /*
00396  * See <tt>File.lchown</tt>.
00397  */
00398 static VALUE
00399 path_lchown(VALUE self, VALUE owner, VALUE group)
00400 {
00401     return rb_funcall(rb_cFile, rb_intern("lchown"), 3, owner, group, get_strpath(self));
00402 }
00403 
00404 /*
00405  * call-seq:
00406  *    pathname.fnmatch(pattern, [flags])        -> string
00407  *    pathname.fnmatch?(pattern, [flags])       -> string
00408  *
00409  * See <tt>File.fnmatch</tt>.  Return +true+ if the receiver matches the given
00410  * pattern.
00411  */
00412 static VALUE
00413 path_fnmatch(int argc, VALUE *argv, VALUE self)
00414 {
00415     VALUE str = get_strpath(self);
00416     VALUE pattern, flags;
00417     if (rb_scan_args(argc, argv, "11", &pattern, &flags) == 1)
00418         return rb_funcall(rb_cFile, rb_intern("fnmatch"), 2, pattern, str);
00419     else
00420         return rb_funcall(rb_cFile, rb_intern("fnmatch"), 3, pattern, str, flags);
00421 }
00422 
00423 /*
00424  * See <tt>File.ftype</tt>.  Returns "type" of file ("file", "directory",
00425  * etc).
00426  */
00427 static VALUE
00428 path_ftype(VALUE self)
00429 {
00430     return rb_funcall(rb_cFile, rb_intern("ftype"), 1, get_strpath(self));
00431 }
00432 
00433 /*
00434  * call-seq:
00435  *   pathname.make_link(old)
00436  *
00437  * See <tt>File.link</tt>.  Creates a hard link at _pathname_.
00438  */
00439 static VALUE
00440 path_make_link(VALUE self, VALUE old)
00441 {
00442     return rb_funcall(rb_cFile, rb_intern("link"), 2, old, get_strpath(self));
00443 }
00444 
00445 /*
00446  * See <tt>File.open</tt>.  Opens the file for reading or writing.
00447  */
00448 static VALUE
00449 path_open(int argc, VALUE *argv, VALUE self)
00450 {
00451     VALUE args[4];
00452     int n;
00453 
00454     args[0] = get_strpath(self);
00455     n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
00456     if (rb_block_given_p()) {
00457         return rb_block_call(rb_cFile, rb_intern("open"), 1+n, args, 0, 0);
00458     }
00459     else {
00460         return rb_funcall2(rb_cFile, rb_intern("open"), 1+n, args);
00461     }
00462 }
00463 
00464 /*
00465  * See <tt>File.readlink</tt>.  Read symbolic link.
00466  */
00467 static VALUE
00468 path_readlink(VALUE self)
00469 {
00470     VALUE str;
00471     str = rb_funcall(rb_cFile, rb_intern("readlink"), 1, get_strpath(self));
00472     return rb_class_new_instance(1, &str, rb_obj_class(self));
00473 }
00474 
00475 /*
00476  * See <tt>File.rename</tt>.  Rename the file.
00477  */
00478 static VALUE
00479 path_rename(VALUE self, VALUE to)
00480 {
00481     return rb_funcall(rb_cFile, rb_intern("rename"), 2, get_strpath(self), to);
00482 }
00483 
00484 /*
00485  * See <tt>File.stat</tt>.  Returns a <tt>File::Stat</tt> object.
00486  */
00487 static VALUE
00488 path_stat(VALUE self)
00489 {
00490     return rb_funcall(rb_cFile, rb_intern("stat"), 1, get_strpath(self));
00491 }
00492 
00493 /*
00494  * See <tt>File.lstat</tt>.
00495  */
00496 static VALUE
00497 path_lstat(VALUE self)
00498 {
00499     return rb_funcall(rb_cFile, rb_intern("lstat"), 1, get_strpath(self));
00500 }
00501 
00502 /*
00503  * call-seq:
00504  *   pathname.make_symlink(old)
00505  *
00506  * See <tt>File.symlink</tt>.  Creates a symbolic link.
00507  */
00508 static VALUE
00509 path_make_symlink(VALUE self, VALUE old)
00510 {
00511     return rb_funcall(rb_cFile, rb_intern("symlink"), 2, old, get_strpath(self));
00512 }
00513 
00514 /*
00515  * See <tt>File.truncate</tt>.  Truncate the file to +length+ bytes.
00516  */
00517 static VALUE
00518 path_truncate(VALUE self, VALUE length)
00519 {
00520     return rb_funcall(rb_cFile, rb_intern("truncate"), 2, get_strpath(self), length);
00521 }
00522 
00523 /*
00524  * See <tt>File.utime</tt>.  Update the access and modification times.
00525  */
00526 static VALUE
00527 path_utime(VALUE self, VALUE atime, VALUE mtime)
00528 {
00529     return rb_funcall(rb_cFile, rb_intern("utime"), 3, atime, mtime, get_strpath(self));
00530 }
00531 
00532 /*
00533  * See <tt>File.basename</tt>.  Returns the last component of the path.
00534  */
00535 static VALUE
00536 path_basename(int argc, VALUE *argv, VALUE self)
00537 {
00538     VALUE str = get_strpath(self);
00539     VALUE fext;
00540     if (rb_scan_args(argc, argv, "01", &fext) == 0)
00541         str = rb_funcall(rb_cFile, rb_intern("basename"), 1, str);
00542     else
00543         str = rb_funcall(rb_cFile, rb_intern("basename"), 2, str, fext);
00544     return rb_class_new_instance(1, &str, rb_obj_class(self));
00545 }
00546 
00547 /*
00548  * See <tt>File.dirname</tt>.  Returns all but the last component of the path.
00549  */
00550 static VALUE
00551 path_dirname(VALUE self)
00552 {
00553     VALUE str = get_strpath(self);
00554     str = rb_funcall(rb_cFile, rb_intern("dirname"), 1, str);
00555     return rb_class_new_instance(1, &str, rb_obj_class(self));
00556 }
00557 
00558 /*
00559  * See <tt>File.extname</tt>.  Returns the file's extension.
00560  */
00561 static VALUE
00562 path_extname(VALUE self)
00563 {
00564     VALUE str = get_strpath(self);
00565     return rb_funcall(rb_cFile, rb_intern("extname"), 1, str);
00566 }
00567 
00568 /*
00569  * See <tt>File.expand_path</tt>.
00570  */
00571 static VALUE
00572 path_expand_path(int argc, VALUE *argv, VALUE self)
00573 {
00574     VALUE str = get_strpath(self);
00575     VALUE dname;
00576     if (rb_scan_args(argc, argv, "01", &dname) == 0)
00577         str = rb_funcall(rb_cFile, rb_intern("expand_path"), 1, str);
00578     else
00579         str = rb_funcall(rb_cFile, rb_intern("expand_path"), 2, str, dname);
00580     return rb_class_new_instance(1, &str, rb_obj_class(self));
00581 }
00582 
00583 /*
00584  * See <tt>File.split</tt>.  Returns the #dirname and the #basename in an Array.
00585  */
00586 static VALUE
00587 path_split(VALUE self)
00588 {
00589     VALUE str = get_strpath(self);
00590     VALUE ary, dirname, basename;
00591     ary = rb_funcall(rb_cFile, rb_intern("split"), 1, str);
00592     ary = rb_check_array_type(ary);
00593     dirname = rb_ary_entry(ary, 0);
00594     basename = rb_ary_entry(ary, 1);
00595     dirname = rb_class_new_instance(1, &dirname, rb_obj_class(self));
00596     basename = rb_class_new_instance(1, &basename, rb_obj_class(self));
00597     return rb_ary_new3(2, dirname, basename);
00598 }
00599 
00600 /*
00601  * See <tt>FileTest.blockdev?</tt>.
00602  */
00603 static VALUE
00604 path_blockdev_p(VALUE self)
00605 {
00606     return rb_funcall(rb_mFileTest, rb_intern("blockdev?"), 1, get_strpath(self));
00607 }
00608 
00609 /*
00610  * See <tt>FileTest.chardev?</tt>.
00611  */
00612 static VALUE
00613 path_chardev_p(VALUE self)
00614 {
00615     return rb_funcall(rb_mFileTest, rb_intern("chardev?"), 1, get_strpath(self));
00616 }
00617 
00618 /*
00619  * See <tt>FileTest.executable?</tt>.
00620  */
00621 static VALUE
00622 path_executable_p(VALUE self)
00623 {
00624     return rb_funcall(rb_mFileTest, rb_intern("executable?"), 1, get_strpath(self));
00625 }
00626 
00627 /*
00628  * See <tt>FileTest.executable_real?</tt>.
00629  */
00630 static VALUE
00631 path_executable_real_p(VALUE self)
00632 {
00633     return rb_funcall(rb_mFileTest, rb_intern("executable_real?"), 1, get_strpath(self));
00634 }
00635 
00636 /*
00637  * See <tt>FileTest.exist?</tt>.
00638  */
00639 static VALUE
00640 path_exist_p(VALUE self)
00641 {
00642     return rb_funcall(rb_mFileTest, rb_intern("exist?"), 1, get_strpath(self));
00643 }
00644 
00645 /*
00646  * See <tt>FileTest.grpowned?</tt>.
00647  */
00648 static VALUE
00649 path_grpowned_p(VALUE self)
00650 {
00651     return rb_funcall(rb_mFileTest, rb_intern("grpowned?"), 1, get_strpath(self));
00652 }
00653 
00654 /*
00655  * See <tt>FileTest.directory?</tt>.
00656  */
00657 static VALUE
00658 path_directory_p(VALUE self)
00659 {
00660     return rb_funcall(rb_mFileTest, rb_intern("directory?"), 1, get_strpath(self));
00661 }
00662 
00663 /*
00664  * See <tt>FileTest.file?</tt>.
00665  */
00666 static VALUE
00667 path_file_p(VALUE self)
00668 {
00669     return rb_funcall(rb_mFileTest, rb_intern("file?"), 1, get_strpath(self));
00670 }
00671 
00672 /*
00673  * See <tt>FileTest.pipe?</tt>.
00674  */
00675 static VALUE
00676 path_pipe_p(VALUE self)
00677 {
00678     return rb_funcall(rb_mFileTest, rb_intern("pipe?"), 1, get_strpath(self));
00679 }
00680 
00681 /*
00682  * See <tt>FileTest.socket?</tt>.
00683  */
00684 static VALUE
00685 path_socket_p(VALUE self)
00686 {
00687     return rb_funcall(rb_mFileTest, rb_intern("socket?"), 1, get_strpath(self));
00688 }
00689 
00690 /*
00691  * See <tt>FileTest.owned?</tt>.
00692  */
00693 static VALUE
00694 path_owned_p(VALUE self)
00695 {
00696     return rb_funcall(rb_mFileTest, rb_intern("owned?"), 1, get_strpath(self));
00697 }
00698 
00699 /*
00700  * See <tt>FileTest.readable?</tt>.
00701  */
00702 static VALUE
00703 path_readable_p(VALUE self)
00704 {
00705     return rb_funcall(rb_mFileTest, rb_intern("readable?"), 1, get_strpath(self));
00706 }
00707 
00708 /*
00709  * See <tt>FileTest.world_readable?</tt>.
00710  */
00711 static VALUE
00712 path_world_readable_p(VALUE self)
00713 {
00714     return rb_funcall(rb_mFileTest, rb_intern("world_readable?"), 1, get_strpath(self));
00715 }
00716 
00717 /*
00718  * See <tt>FileTest.readable_real?</tt>.
00719  */
00720 static VALUE
00721 path_readable_real_p(VALUE self)
00722 {
00723     return rb_funcall(rb_mFileTest, rb_intern("readable_real?"), 1, get_strpath(self));
00724 }
00725 
00726 /*
00727  * See <tt>FileTest.setuid?</tt>.
00728  */
00729 static VALUE
00730 path_setuid_p(VALUE self)
00731 {
00732     return rb_funcall(rb_mFileTest, rb_intern("setuid?"), 1, get_strpath(self));
00733 }
00734 
00735 /*
00736  * See <tt>FileTest.setgid?</tt>.
00737  */
00738 static VALUE
00739 path_setgid_p(VALUE self)
00740 {
00741     return rb_funcall(rb_mFileTest, rb_intern("setgid?"), 1, get_strpath(self));
00742 }
00743 
00744 /*
00745  * See <tt>FileTest.size</tt>.
00746  */
00747 static VALUE
00748 path_size(VALUE self)
00749 {
00750     return rb_funcall(rb_mFileTest, rb_intern("size"), 1, get_strpath(self));
00751 }
00752 
00753 /*
00754  * See <tt>FileTest.size?</tt>.
00755  */
00756 static VALUE
00757 path_size_p(VALUE self)
00758 {
00759     return rb_funcall(rb_mFileTest, rb_intern("size?"), 1, get_strpath(self));
00760 }
00761 
00762 /*
00763  * See <tt>FileTest.sticky?</tt>.
00764  */
00765 static VALUE
00766 path_sticky_p(VALUE self)
00767 {
00768     return rb_funcall(rb_mFileTest, rb_intern("sticky?"), 1, get_strpath(self));
00769 }
00770 
00771 /*
00772  * See <tt>FileTest.symlink?</tt>.
00773  */
00774 static VALUE
00775 path_symlink_p(VALUE self)
00776 {
00777     return rb_funcall(rb_mFileTest, rb_intern("symlink?"), 1, get_strpath(self));
00778 }
00779 
00780 /*
00781  * See <tt>FileTest.writable?</tt>.
00782  */
00783 static VALUE
00784 path_writable_p(VALUE self)
00785 {
00786     return rb_funcall(rb_mFileTest, rb_intern("writable?"), 1, get_strpath(self));
00787 }
00788 
00789 /*
00790  * See <tt>FileTest.world_writable?</tt>.
00791  */
00792 static VALUE
00793 path_world_writable_p(VALUE self)
00794 {
00795     return rb_funcall(rb_mFileTest, rb_intern("world_writable?"), 1, get_strpath(self));
00796 }
00797 
00798 /*
00799  * See <tt>FileTest.writable_real?</tt>.
00800  */
00801 static VALUE
00802 path_writable_real_p(VALUE self)
00803 {
00804     return rb_funcall(rb_mFileTest, rb_intern("writable_real?"), 1, get_strpath(self));
00805 }
00806 
00807 /*
00808  * See <tt>FileTest.zero?</tt>.
00809  */
00810 static VALUE
00811 path_zero_p(VALUE self)
00812 {
00813     return rb_funcall(rb_mFileTest, rb_intern("zero?"), 1, get_strpath(self));
00814 }
00815 
00816 static VALUE
00817 glob_i(VALUE elt, VALUE klass, int argc, VALUE *argv)
00818 {
00819     return rb_yield(rb_class_new_instance(1, &elt, klass));
00820 }
00821 
00822 /*
00823  * See <tt>Dir.glob</tt>.  Returns or yields Pathname objects.
00824  */
00825 static VALUE
00826 path_s_glob(int argc, VALUE *argv, VALUE klass)
00827 {
00828     VALUE args[2];
00829     int n;
00830 
00831     n = rb_scan_args(argc, argv, "11", &args[0], &args[1]);
00832     if (rb_block_given_p()) {
00833         return rb_block_call(rb_cDir, rb_intern("glob"), n, args, glob_i, klass);
00834     }
00835     else {
00836         VALUE ary;
00837         long i;
00838         ary = rb_funcall2(rb_cDir, rb_intern("glob"), n, args);
00839         ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
00840         for (i = 0; i < RARRAY_LEN(ary); i++) {
00841             VALUE elt = RARRAY_PTR(ary)[i];
00842             elt = rb_class_new_instance(1, &elt, klass);
00843             rb_ary_store(ary, i, elt);
00844         }
00845         return ary;
00846     }
00847 }
00848 
00849 /*
00850  * See <tt>Dir.getwd</tt>.  Returns the current working directory as a Pathname.
00851  */
00852 static VALUE
00853 path_s_getwd(VALUE klass)
00854 {
00855     VALUE str;
00856     str = rb_funcall(rb_cDir, rb_intern("getwd"), 0);
00857     return rb_class_new_instance(1, &str, klass);
00858 }
00859 
00860 /*
00861  * Return the entries (files and subdirectories) in the directory, each as a
00862  * Pathname object.
00863  *
00864  * The result may contain the current directory #<Pathname:.> and the parent
00865  * directory #<Pathname:..>.
00866  */
00867 static VALUE
00868 path_entries(VALUE self)
00869 {
00870     VALUE klass, str, ary;
00871     long i;
00872     klass = rb_obj_class(self);
00873     str = get_strpath(self);
00874     ary = rb_funcall(rb_cDir, rb_intern("entries"), 1, str);
00875     ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
00876     for (i = 0; i < RARRAY_LEN(ary); i++) {
00877         VALUE elt = RARRAY_PTR(ary)[i];
00878         elt = rb_class_new_instance(1, &elt, klass);
00879         rb_ary_store(ary, i, elt);
00880     }
00881     return ary;
00882 }
00883 
00884 /*
00885  * See <tt>Dir.mkdir</tt>.  Create the referenced directory.
00886  */
00887 static VALUE
00888 path_mkdir(int argc, VALUE *argv, VALUE self)
00889 {
00890     VALUE str = get_strpath(self);
00891     VALUE vmode;
00892     if (rb_scan_args(argc, argv, "01", &vmode) == 0)
00893         return rb_funcall(rb_cDir, rb_intern("mkdir"), 1, str);
00894     else
00895         return rb_funcall(rb_cDir, rb_intern("mkdir"), 2, str, vmode);
00896 }
00897 
00898 /*
00899  * See <tt>Dir.rmdir</tt>.  Remove the referenced directory.
00900  */
00901 static VALUE
00902 path_rmdir(VALUE self)
00903 {
00904     return rb_funcall(rb_cDir, rb_intern("rmdir"), 1, get_strpath(self));
00905 }
00906 
00907 /*
00908  * See <tt>Dir.open</tt>.
00909  */
00910 static VALUE
00911 path_opendir(VALUE self)
00912 {
00913     VALUE args[1];
00914 
00915     args[0] = get_strpath(self);
00916     return rb_block_call(rb_cDir, rb_intern("open"), 1, args, 0, 0);
00917 }
00918 
00919 static VALUE
00920 each_entry_i(VALUE elt, VALUE klass, int argc, VALUE *argv)
00921 {
00922     return rb_yield(rb_class_new_instance(1, &elt, klass));
00923 }
00924 
00925 /*
00926  * Iterates over the entries (files and subdirectories) in the directory.  It
00927  * yields a Pathname object for each entry.
00928  *
00929  * This method has available since 1.8.1.
00930  */
00931 static VALUE
00932 path_each_entry(VALUE self)
00933 {
00934     VALUE args[1];
00935 
00936     args[0] = get_strpath(self);
00937     return rb_block_call(rb_cDir, rb_intern("foreach"), 1, args, each_entry_i, rb_obj_class(self));
00938 }
00939 
00940 static VALUE
00941 unlink_body(VALUE str)
00942 {
00943     return rb_funcall(rb_cDir, rb_intern("unlink"), 1, str);
00944 }
00945 
00946 static VALUE
00947 unlink_rescue(VALUE str, VALUE errinfo)
00948 {
00949     return rb_funcall(rb_cFile, rb_intern("unlink"), 1, str);
00950 }
00951 
00952 /*
00953  * Removes a file or directory, using <tt>File.unlink</tt> or
00954  * <tt>Dir.unlink</tt> as necessary.
00955  */
00956 static VALUE
00957 path_unlink(VALUE self)
00958 {
00959     VALUE eENOTDIR = rb_const_get_at(rb_mErrno, rb_intern("ENOTDIR"));
00960     VALUE str = get_strpath(self);
00961     return rb_rescue2(unlink_body, str, unlink_rescue, str, eENOTDIR, (VALUE)0);
00962 }
00963 
00964 /*
00965  * create a pathname object.
00966  *
00967  * This method is available since 1.8.5.
00968  */
00969 static VALUE
00970 path_f_pathname(VALUE self, VALUE str)
00971 {
00972     return rb_class_new_instance(1, &str, rb_cPathname);
00973 }
00974 
00975 /*
00976  * == Pathname
00977  *
00978  * Pathname represents a pathname which locates a file in a filesystem.
00979  * The pathname depends on OS: Unix, Windows, etc.
00980  * Pathname library works with pathnames of local OS.
00981  * However non-Unix pathnames are supported experimentally.
00982  *
00983  * It does not represent the file itself.
00984  * A Pathname can be relative or absolute.  It's not until you try to
00985  * reference the file that it even matters whether the file exists or not.
00986  *
00987  * Pathname is immutable.  It has no method for destructive update.
00988  *
00989  * The value of this class is to manipulate file path information in a neater
00990  * way than standard Ruby provides.  The examples below demonstrate the
00991  * difference.  *All* functionality from File, FileTest, and some from Dir and
00992  * FileUtils is included, in an unsurprising way.  It is essentially a facade for
00993  * all of these, and more.
00994  *
00995  * == Examples
00996  *
00997  * === Example 1: Using Pathname
00998  *
00999  *   require 'pathname'
01000  *   pn = Pathname.new("/usr/bin/ruby")
01001  *   size = pn.size              # 27662
01002  *   isdir = pn.directory?       # false
01003  *   dir  = pn.dirname           # Pathname:/usr/bin
01004  *   base = pn.basename          # Pathname:ruby
01005  *   dir, base = pn.split        # [Pathname:/usr/bin, Pathname:ruby]
01006  *   data = pn.read
01007  *   pn.open { |f| _ }
01008  *   pn.each_line { |line| _ }
01009  *
01010  * === Example 2: Using standard Ruby
01011  *
01012  *   pn = "/usr/bin/ruby"
01013  *   size = File.size(pn)        # 27662
01014  *   isdir = File.directory?(pn) # false
01015  *   dir  = File.dirname(pn)     # "/usr/bin"
01016  *   base = File.basename(pn)    # "ruby"
01017  *   dir, base = File.split(pn)  # ["/usr/bin", "ruby"]
01018  *   data = File.read(pn)
01019  *   File.open(pn) { |f| _ }
01020  *   File.foreach(pn) { |line| _ }
01021  *
01022  * === Example 3: Special features
01023  *
01024  *   p1 = Pathname.new("/usr/lib")   # Pathname:/usr/lib
01025  *   p2 = p1 + "ruby/1.8"            # Pathname:/usr/lib/ruby/1.8
01026  *   p3 = p1.parent                  # Pathname:/usr
01027  *   p4 = p2.relative_path_from(p3)  # Pathname:lib/ruby/1.8
01028  *   pwd = Pathname.pwd              # Pathname:/home/gavin
01029  *   pwd.absolute?                   # true
01030  *   p5 = Pathname.new "."           # Pathname:.
01031  *   p5 = p5 + "music/../articles"   # Pathname:music/../articles
01032  *   p5.cleanpath                    # Pathname:articles
01033  *   p5.realpath                     # Pathname:/home/gavin/articles
01034  *   p5.children                     # [Pathname:/home/gavin/articles/linux, ...]
01035  *
01036  * == Breakdown of functionality
01037  *
01038  * === Core methods
01039  *
01040  * These methods are effectively manipulating a String, because that's
01041  * all a path is.  Except for #mountpoint?, #children, #each_child,
01042  * #realdirpath and #realpath, they don't access the filesystem.
01043  *
01044  * - +
01045  * - #join
01046  * - #parent
01047  * - #root?
01048  * - #absolute?
01049  * - #relative?
01050  * - #relative_path_from
01051  * - #each_filename
01052  * - #cleanpath
01053  * - #realpath
01054  * - #realdirpath
01055  * - #children
01056  * - #each_child
01057  * - #mountpoint?
01058  *
01059  * === File status predicate methods
01060  *
01061  * These methods are a facade for FileTest:
01062  * - #blockdev?
01063  * - #chardev?
01064  * - #directory?
01065  * - #executable?
01066  * - #executable_real?
01067  * - #exist?
01068  * - #file?
01069  * - #grpowned?
01070  * - #owned?
01071  * - #pipe?
01072  * - #readable?
01073  * - #world_readable?
01074  * - #readable_real?
01075  * - #setgid?
01076  * - #setuid?
01077  * - #size
01078  * - #size?
01079  * - #socket?
01080  * - #sticky?
01081  * - #symlink?
01082  * - #writable?
01083  * - #world_writable?
01084  * - #writable_real?
01085  * - #zero?
01086  *
01087  * === File property and manipulation methods
01088  *
01089  * These methods are a facade for File:
01090  * - #atime
01091  * - #ctime
01092  * - #mtime
01093  * - #chmod(mode)
01094  * - #lchmod(mode)
01095  * - #chown(owner, group)
01096  * - #lchown(owner, group)
01097  * - #fnmatch(pattern, *args)
01098  * - #fnmatch?(pattern, *args)
01099  * - #ftype
01100  * - #make_link(old)
01101  * - #open(*args, &block)
01102  * - #readlink
01103  * - #rename(to)
01104  * - #stat
01105  * - #lstat
01106  * - #make_symlink(old)
01107  * - #truncate(length)
01108  * - #utime(atime, mtime)
01109  * - #basename(*args)
01110  * - #dirname
01111  * - #extname
01112  * - #expand_path(*args)
01113  * - #split
01114  *
01115  * === Directory methods
01116  *
01117  * These methods are a facade for Dir:
01118  * - Pathname.glob(*args)
01119  * - Pathname.getwd / Pathname.pwd
01120  * - #rmdir
01121  * - #entries
01122  * - #each_entry(&block)
01123  * - #mkdir(*args)
01124  * - #opendir(*args)
01125  *
01126  * === IO
01127  *
01128  * These methods are a facade for IO:
01129  * - #each_line(*args, &block)
01130  * - #read(*args)
01131  * - #binread(*args)
01132  * - #readlines(*args)
01133  * - #sysopen(*args)
01134  *
01135  * === Utilities
01136  *
01137  * These methods are a mixture of Find, FileUtils, and others:
01138  * - #find(&block)
01139  * - #mkpath
01140  * - #rmtree
01141  * - #unlink / #delete
01142  *
01143  *
01144  * == Method documentation
01145  *
01146  * As the above section shows, most of the methods in Pathname are facades.  The
01147  * documentation for these methods generally just says, for instance, "See
01148  * FileTest.writable?", as you should be familiar with the original method
01149  * anyway, and its documentation (e.g. through +ri+) will contain more
01150  * information.  In some cases, a brief description will follow.
01151  */
01152 void
01153 Init_pathname()
01154 {
01155     id_at_path = rb_intern("@path");
01156     id_to_path = rb_intern("to_path");
01157 
01158     rb_cPathname = rb_define_class("Pathname", rb_cObject);
01159     rb_define_method(rb_cPathname, "initialize", path_initialize, 1);
01160     rb_define_method(rb_cPathname, "freeze", path_freeze, 0);
01161     rb_define_method(rb_cPathname, "taint", path_taint, 0);
01162     rb_define_method(rb_cPathname, "untaint", path_untaint, 0);
01163     rb_define_method(rb_cPathname, "==", path_eq, 1);
01164     rb_define_method(rb_cPathname, "===", path_eq, 1);
01165     rb_define_method(rb_cPathname, "eql?", path_eq, 1);
01166     rb_define_method(rb_cPathname, "<=>", path_cmp, 1);
01167     rb_define_method(rb_cPathname, "hash", path_hash, 0);
01168     rb_define_method(rb_cPathname, "to_s", path_to_s, 0);
01169     rb_define_method(rb_cPathname, "to_path", path_to_s, 0);
01170     rb_define_method(rb_cPathname, "inspect", path_inspect, 0);
01171     rb_define_method(rb_cPathname, "sub", path_sub, -1);
01172     rb_define_method(rb_cPathname, "sub_ext", path_sub_ext, 1);
01173     rb_define_method(rb_cPathname, "realpath", path_realpath, -1);
01174     rb_define_method(rb_cPathname, "realdirpath", path_realdirpath, -1);
01175     rb_define_method(rb_cPathname, "each_line", path_each_line, -1);
01176     rb_define_method(rb_cPathname, "read", path_read, -1);
01177     rb_define_method(rb_cPathname, "binread", path_binread, -1);
01178     rb_define_method(rb_cPathname, "readlines", path_readlines, -1);
01179     rb_define_method(rb_cPathname, "sysopen", path_sysopen, -1);
01180     rb_define_method(rb_cPathname, "atime", path_atime, 0);
01181     rb_define_method(rb_cPathname, "ctime", path_ctime, 0);
01182     rb_define_method(rb_cPathname, "mtime", path_mtime, 0);
01183     rb_define_method(rb_cPathname, "chmod", path_chmod, 1);
01184     rb_define_method(rb_cPathname, "lchmod", path_lchmod, 1);
01185     rb_define_method(rb_cPathname, "chown", path_chown, 2);
01186     rb_define_method(rb_cPathname, "lchown", path_lchown, 2);
01187     rb_define_method(rb_cPathname, "fnmatch", path_fnmatch, -1);
01188     rb_define_method(rb_cPathname, "fnmatch?", path_fnmatch, -1);
01189     rb_define_method(rb_cPathname, "ftype", path_ftype, 0);
01190     rb_define_method(rb_cPathname, "make_link", path_make_link, 1);
01191     rb_define_method(rb_cPathname, "open", path_open, -1);
01192     rb_define_method(rb_cPathname, "readlink", path_readlink, 0);
01193     rb_define_method(rb_cPathname, "rename", path_rename, 1);
01194     rb_define_method(rb_cPathname, "stat", path_stat, 0);
01195     rb_define_method(rb_cPathname, "lstat", path_lstat, 0);
01196     rb_define_method(rb_cPathname, "make_symlink", path_make_symlink, 1);
01197     rb_define_method(rb_cPathname, "truncate", path_truncate, 1);
01198     rb_define_method(rb_cPathname, "utime", path_utime, 2);
01199     rb_define_method(rb_cPathname, "basename", path_basename, -1);
01200     rb_define_method(rb_cPathname, "dirname", path_dirname, 0);
01201     rb_define_method(rb_cPathname, "extname", path_extname, 0);
01202     rb_define_method(rb_cPathname, "expand_path", path_expand_path, -1);
01203     rb_define_method(rb_cPathname, "split", path_split, 0);
01204     rb_define_method(rb_cPathname, "blockdev?", path_blockdev_p, 0);
01205     rb_define_method(rb_cPathname, "chardev?", path_chardev_p, 0);
01206     rb_define_method(rb_cPathname, "executable?", path_executable_p, 0);
01207     rb_define_method(rb_cPathname, "executable_real?", path_executable_real_p, 0);
01208     rb_define_method(rb_cPathname, "exist?", path_exist_p, 0);
01209     rb_define_method(rb_cPathname, "grpowned?", path_grpowned_p, 0);
01210     rb_define_method(rb_cPathname, "directory?", path_directory_p, 0);
01211     rb_define_method(rb_cPathname, "file?", path_file_p, 0);
01212     rb_define_method(rb_cPathname, "pipe?", path_pipe_p, 0);
01213     rb_define_method(rb_cPathname, "socket?", path_socket_p, 0);
01214     rb_define_method(rb_cPathname, "owned?", path_owned_p, 0);
01215     rb_define_method(rb_cPathname, "readable?", path_readable_p, 0);
01216     rb_define_method(rb_cPathname, "world_readable?", path_world_readable_p, 0);
01217     rb_define_method(rb_cPathname, "readable_real?", path_readable_real_p, 0);
01218     rb_define_method(rb_cPathname, "setuid?", path_setuid_p, 0);
01219     rb_define_method(rb_cPathname, "setgid?", path_setgid_p, 0);
01220     rb_define_method(rb_cPathname, "size", path_size, 0);
01221     rb_define_method(rb_cPathname, "size?", path_size_p, 0);
01222     rb_define_method(rb_cPathname, "sticky?", path_sticky_p, 0);
01223     rb_define_method(rb_cPathname, "symlink?", path_symlink_p, 0);
01224     rb_define_method(rb_cPathname, "writable?", path_writable_p, 0);
01225     rb_define_method(rb_cPathname, "world_writable?", path_world_writable_p, 0);
01226     rb_define_method(rb_cPathname, "writable_real?", path_writable_real_p, 0);
01227     rb_define_method(rb_cPathname, "zero?", path_zero_p, 0);
01228     rb_define_singleton_method(rb_cPathname, "glob", path_s_glob, -1);
01229     rb_define_singleton_method(rb_cPathname, "getwd", path_s_getwd, 0);
01230     rb_define_singleton_method(rb_cPathname, "pwd", path_s_getwd, 0);
01231     rb_define_method(rb_cPathname, "entries", path_entries, 0);
01232     rb_define_method(rb_cPathname, "mkdir", path_mkdir, -1);
01233     rb_define_method(rb_cPathname, "rmdir", path_rmdir, 0);
01234     rb_define_method(rb_cPathname, "opendir", path_opendir, 0);
01235     rb_define_method(rb_cPathname, "each_entry", path_each_entry, 0);
01236     rb_define_method(rb_cPathname, "unlink", path_unlink, 0);
01237     rb_define_method(rb_cPathname, "delete", path_unlink, 0);
01238     rb_undef_method(rb_cPathname, "=~");
01239     rb_define_global_function("Pathname", path_f_pathname, 1);
01240 }
01241