@@ -2982,36 +2982,15 @@ rmext(const char *p, int l1, const char *e)
2982
2982
return 0 ;
2983
2983
}
2984
2984
2985
- /*
2986
- * call-seq:
2987
- * File.basename(file_name [, suffix] ) -> base_name
2988
- *
2989
- * Returns the last component of the filename given in <i>file_name</i>,
2990
- * which must be formed using forward slashes (``<code>/</code>'')
2991
- * regardless of the separator used on the local file system. If
2992
- * <i>suffix</i> is given and present at the end of <i>file_name</i>,
2993
- * it is removed.
2994
- *
2995
- * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
2996
- * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
2997
- */
2998
-
2999
- static VALUE
3000
- rb_file_s_basename (int argc , VALUE * argv )
2985
+ const char *
2986
+ ruby_find_basename (const char * name , long * len , long * ext )
3001
2987
{
3002
- VALUE fname , fext , basename ;
3003
- const char * name , * p ;
2988
+ const char * p ;
3004
2989
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
3005
2990
const char * root ;
3006
2991
#endif
3007
- int f , n ;
2992
+ long f , n = -1 ;
3008
2993
3009
- if (rb_scan_args (argc , argv , "11" , & fname , & fext ) == 2 ) {
3010
- StringValue (fext );
3011
- }
3012
- FilePathStringValue (fname );
3013
- if (RSTRING_LEN (fname ) == 0 || !* (name = RSTRING_PTR (fname )))
3014
- return rb_str_new_shared (fname );
3015
2994
name = skipprefix (name );
3016
2995
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
3017
2996
root = name ;
@@ -3050,11 +3029,57 @@ rb_file_s_basename(int argc, VALUE *argv)
3050
3029
#else
3051
3030
n = chompdirsep (p ) - p ;
3052
3031
#endif
3032
+ }
3033
+
3034
+ if (len )
3035
+ * len = f ;
3036
+ if (ext )
3037
+ * ext = n ;
3038
+ return p ;
3039
+ }
3040
+
3041
+ /*
3042
+ * call-seq:
3043
+ * File.basename(file_name [, suffix] ) -> base_name
3044
+ *
3045
+ * Returns the last component of the filename given in <i>file_name</i>,
3046
+ * which must be formed using forward slashes (``<code>/</code>'')
3047
+ * regardless of the separator used on the local file system. If
3048
+ * <i>suffix</i> is given and present at the end of <i>file_name</i>,
3049
+ * it is removed.
3050
+ *
3051
+ * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
3052
+ * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
3053
+ */
3054
+
3055
+ static VALUE
3056
+ rb_file_s_basename (int argc , VALUE * argv )
3057
+ {
3058
+ VALUE fname , fext , basename ;
3059
+ const char * name , * p ;
3060
+ long f , n ;
3061
+
3062
+ if (rb_scan_args (argc , argv , "11" , & fname , & fext ) == 2 ) {
3063
+ rb_encoding * enc ;
3064
+ StringValue (fext );
3065
+ if (!rb_enc_asciicompat (enc = rb_enc_get (fext ))) {
3066
+ rb_raise (rb_eEncCompatError , "ascii incompatible character encodings: %s" ,
3067
+ rb_enc_name (enc ));
3068
+ }
3069
+ }
3070
+ FilePathStringValue (fname );
3071
+ if (!NIL_P (fext )) rb_enc_check (fname , fext );
3072
+ if (RSTRING_LEN (fname ) == 0 || !* (name = RSTRING_PTR (fname )))
3073
+ return rb_str_new_shared (fname );
3074
+
3075
+ p = ruby_find_basename (name , & f , & n );
3076
+ if (n >= 0 ) {
3053
3077
if (NIL_P (fext ) || !(f = rmext (p , n , StringValueCStr (fext )))) {
3054
3078
f = n ;
3055
3079
}
3056
3080
if (f == RSTRING_LEN (fname )) return rb_str_new_shared (fname );
3057
3081
}
3082
+
3058
3083
basename = rb_str_new (p , f );
3059
3084
rb_enc_copy (basename , fname );
3060
3085
OBJ_INFECT (basename , fname );
@@ -3114,32 +3139,27 @@ rb_file_s_dirname(VALUE klass, VALUE fname)
3114
3139
}
3115
3140
3116
3141
/*
3117
- * call-seq:
3118
- * File.extname(path) -> string
3119
- *
3120
- * Returns the extension (the portion of file name in <i>path</i>
3121
- * after the period).
3122
- *
3123
- * File.extname("test.rb") #=> ".rb"
3124
- * File.extname("a/b/d/test.rb") #=> ".rb"
3125
- * File.extname("test") #=> ""
3126
- * File.extname(".profile") #=> ""
3127
- *
3142
+ * accept a String, and return the pointer of the extension.
3143
+ * if len is passed, set the length of extension to it.
3144
+ * returned pointer is in ``name'' or NULL.
3145
+ * returns *len
3146
+ * no dot NULL 0
3147
+ * dotfile top 0
3148
+ * end with dot dot 1
3149
+ * .ext dot len of .ext
3150
+ * .ext:stream dot len of .ext without :stream (NT only)
3151
+ *
3128
3152
*/
3129
-
3130
- static VALUE
3131
- rb_file_s_extname (VALUE klass , VALUE fname )
3153
+ const char *
3154
+ ruby_find_extname (const char * name , long * len )
3132
3155
{
3133
- const char * name , * p , * e ;
3134
- VALUE extname ;
3156
+ const char * p , * e ;
3135
3157
3136
- FilePathStringValue (fname );
3137
- name = StringValueCStr (fname );
3138
3158
p = strrdirsep (name ); /* get the last path component */
3139
3159
if (!p )
3140
3160
p = name ;
3141
3161
else
3142
- name = ++ p ;
3162
+ do name = ++ p ; while ( isdirsep ( * p )) ;
3143
3163
3144
3164
e = 0 ;
3145
3165
while (* p && * p == '.' ) p ++ ;
@@ -3170,9 +3190,46 @@ rb_file_s_extname(VALUE klass, VALUE fname)
3170
3190
break ;
3171
3191
p = CharNext (p );
3172
3192
}
3173
- if (!e || e == name || e + 1 == p ) /* no dot, or the only dot is first or end? */
3193
+
3194
+ if (len ) {
3195
+ /* no dot, or the only dot is first or end? */
3196
+ if (!e || e == name )
3197
+ * len = 0 ;
3198
+ else if (e + 1 == p )
3199
+ * len = 1 ;
3200
+ else
3201
+ * len = p - e ;
3202
+ }
3203
+ return e ;
3204
+ }
3205
+
3206
+ /*
3207
+ * call-seq:
3208
+ * File.extname(path) -> string
3209
+ *
3210
+ * Returns the extension (the portion of file name in <i>path</i>
3211
+ * after the period).
3212
+ *
3213
+ * File.extname("test.rb") #=> ".rb"
3214
+ * File.extname("a/b/d/test.rb") #=> ".rb"
3215
+ * File.extname("test") #=> ""
3216
+ * File.extname(".profile") #=> ""
3217
+ *
3218
+ */
3219
+
3220
+ static VALUE
3221
+ rb_file_s_extname (VALUE klass , VALUE fname )
3222
+ {
3223
+ const char * name , * e ;
3224
+ long len ;
3225
+ VALUE extname ;
3226
+
3227
+ FilePathStringValue (fname );
3228
+ name = StringValueCStr (fname );
3229
+ e = ruby_find_extname (name , & len );
3230
+ if (len <= 1 )
3174
3231
return rb_str_new (0 , 0 );
3175
- extname = rb_str_new (e , p - e ); /* keep the dot, too! */
3232
+ extname = rb_str_new (e , len ); /* keep the dot, too! */
3176
3233
rb_enc_copy (extname , fname );
3177
3234
OBJ_INFECT (extname , fname );
3178
3235
return extname ;
0 commit comments