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