summaryrefslogtreecommitdiff
path: root/file.c
diff options
context:
space:
mode:
authorshyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-11-22 07:21:34 +0000
committershyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-11-22 07:21:34 +0000
commitd5e7bf424e08f21a6dbc6291e50590a969c6f6db (patch)
treee80041f9f8966c28b12fd3dc221ca467e74a6cdd /file.c
parentb8f2ee898450661a6568f0fd27a9f2266b55239a (diff)
Fri, 2 Jul 2010 14:35:10 +0000 usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
merge revision(s) 28525:28568: * file.c (ruby_find_basename, ruby_find_extname): split from rb_file_s_basename() and rb_file_s_extname(). * util.c (ruby_add_suffix): support arbitrary length of the suffix to get rid of the potential buffer overflow. reported by tarui. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@28526 b2dd03c8-39d4-4d8f-98ff-823fe69b080e Signed-off-by: URABE, Shyouhei <shyouhei@ruby-lang.org> merge from trunk (r28565) * file.c (ruby_find_basename): set correct baselen. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@28566 b2dd03c8-39d4-4d8f-98ff-823fe69b080e Signed-off-by: URABE, Shyouhei <shyouhei@ruby-lang.org> merge from trunk (r28565) * file.c (ruby_find_basename): set correct baselen. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@28568 b2dd03c8-39d4-4d8f-98ff-823fe69b080e Signed-off-by: URABE, Shyouhei <shyouhei@ruby-lang.org> git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_7@29855 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'file.c')
-rw-r--r--file.c141
1 files changed, 108 insertions, 33 deletions
diff --git a/file.c b/file.c
index 9452d046d9..1bb3364daa 100644
--- a/file.c
+++ b/file.c
@@ -2881,24 +2881,17 @@ rmext(p, l1, e)
* File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
*/
-static VALUE
-rb_file_s_basename(argc, argv)
- int argc;
- VALUE *argv;
+const char *
+ruby_find_basename(name, baselen, alllen)
+ const char *name;
+ long *baselen, *alllen;
{
- VALUE fname, fext, basename;
- const char *name, *p;
+ const char *p, *q, *e;
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
const char *root;
#endif
- int f, n;
+ long f = 0, n = -1;
- if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) {
- StringValue(fext);
- }
- StringValue(fname);
- if (RSTRING(fname)->len == 0 || !*(name = RSTRING(fname)->ptr))
- return fname;
name = skipprefix(name);
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
root = name;
@@ -2937,11 +2930,59 @@ rb_file_s_basename(argc, argv)
#else
n = chompdirsep(p) - p;
#endif
+ for (q = p; q - p < n && *q == '.'; q++);
+ for (e = 0; q - p < n; q = CharNext(q)) {
+ if (*q == '.') e = q;
+ }
+ if (e) f = e - p;
+ else f = n;
+ }
+
+ if (baselen)
+ *baselen = f;
+ if (alllen)
+ *alllen = n;
+ return p;
+}
+
+/*
+ * call-seq:
+ * File.basename(file_name [, suffix] ) -> base_name
+ *
+ * Returns the last component of the filename given in <i>file_name</i>,
+ * which must be formed using forward slashes (``<code>/</code>'')
+ * regardless of the separator used on the local file system. If
+ * <i>suffix</i> is given and present at the end of <i>file_name</i>,
+ * it is removed.
+ *
+ * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
+ * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
+ */
+
+static VALUE
+rb_file_s_basename(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE fname, fext, basename;
+ const char *name, *p;
+ long f, n;
+
+ if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) {
+ StringValue(fext);
+ }
+ StringValue(fname);
+ if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname)))
+ return fname;
+
+ p = ruby_find_basename(name, &f, &n);
+ if (n >= 0) {
if (NIL_P(fext) || !(f = rmext(p, n, StringValueCStr(fext)))) {
f = n;
}
if (f == RSTRING_LEN(fname)) return fname;
}
+
basename = rb_str_new(p, f);
OBJ_INFECT(basename, fname);
return basename;
@@ -2999,27 +3040,24 @@ rb_file_s_dirname(klass, fname)
}
/*
- * call-seq:
- * File.extname(path) -> string
- *
- * Returns the extension (the portion of file name in <i>path</i>
- * after the period).
- *
- * File.extname("test.rb") #=> ".rb"
- * File.extname("a/b/d/test.rb") #=> ".rb"
- * File.extname("test") #=> ""
- * File.extname(".profile") #=> ""
- *
+ * accept a String, and return the pointer of the extension.
+ * if len is passed, set the length of extension to it.
+ * returned pointer is in ``name'' or NULL.
+ * returns *len
+ * no dot NULL 0
+ * dotfile top 0
+ * end with dot dot 1
+ * .ext dot len of .ext
+ * .ext:stream dot len of .ext without :stream (NT only)
+ *
*/
-
-static VALUE
-rb_file_s_extname(klass, fname)
- VALUE klass, fname;
+const char *
+ruby_find_extname(name, len)
+ const char *name;
+ long *len;
{
- const char *name, *p, *e;
- VALUE extname;
+ const char *p, *e;
- name = StringValueCStr(fname);
p = strrdirsep(name); /* get the last path component */
if (!p)
p = name;
@@ -3054,9 +3092,46 @@ rb_file_s_extname(klass, fname)
break;
p = CharNext(p);
}
- if (!e || e == name || e+1 == p) /* no dot, or the only dot is first or end? */
+
+ if (len) {
+ /* no dot, or the only dot is first or end? */
+ if (!e || e == name)
+ *len = 0;
+ else if (e+1 == p)
+ *len = 1;
+ else
+ *len = p - e;
+ }
+ return e;
+}
+
+/*
+ * call-seq:
+ * File.extname(path) -> string
+ *
+ * Returns the extension (the portion of file name in <i>path</i>
+ * after the period).
+ *
+ * File.extname("test.rb") #=> ".rb"
+ * File.extname("a/b/d/test.rb") #=> ".rb"
+ * File.extname("test") #=> ""
+ * File.extname(".profile") #=> ""
+ *
+ */
+
+static VALUE
+rb_file_s_extname(klass, fname)
+ VALUE klass, fname;
+{
+ const char *name, *e;
+ long len;
+ VALUE extname;
+
+ name = StringValueCStr(fname);
+ e = ruby_find_extname(name, &len);
+ if (len <= 1)
return rb_str_new(0, 0);
- extname = rb_str_new(e, p - e); /* keep the dot, too! */
+ extname = rb_str_new(e, len); /* keep the dot, too! */
OBJ_INFECT(extname, fname);
return extname;
}