@@ -3571,8 +3571,8 @@ static const char file_alt_separator[] = {FILE_ALT_SEPARATOR, '\0'};
35713571# define isADS (x ) 0
35723572#endif
35733573
3574- #define Next (p , e , enc ) ((p) + ((enc ) ? rb_enc_mbclen((p), (e), (enc)) : 1))
3575- #define Inc (p , e , enc ) ((p) = Next((p), (e), (enc)))
3574+ #define Next (p , e , mb_enc , enc ) ((p) + ((mb_enc ) ? rb_enc_mbclen((p), (e), (enc)) : 1))
3575+ #define Inc (p , e , mb_enc , enc ) ((p) = Next((p), (e), (mb_enc ), (enc)))
35763576
35773577#if defined(DOSISH_UNC )
35783578#define has_unc (buf ) (isdirsep((buf)[0]) && isdirsep((buf)[1]))
@@ -3645,31 +3645,37 @@ skiproot(const char *path, const char *end)
36453645 return (char * )path ;
36463646}
36473647
3648- #define nextdirsep rb_enc_path_next
3649- char *
3650- rb_enc_path_next (const char * s , const char * e , rb_encoding * enc )
3648+ static inline char *
3649+ enc_path_next (const char * s , const char * e , bool mb_enc , rb_encoding * enc )
36513650{
36523651 while (s < e && !isdirsep (* s )) {
3653- Inc (s , e , enc );
3652+ Inc (s , e , mb_enc , enc );
36543653 }
36553654 return (char * )s ;
36563655}
36573656
3657+ #define nextdirsep rb_enc_path_next
3658+ char *
3659+ rb_enc_path_next (const char * s , const char * e , rb_encoding * enc )
3660+ {
3661+ return enc_path_next (s , e , true, enc );
3662+ }
3663+
36583664#if defined(DOSISH_UNC ) || defined(DOSISH_DRIVE_LETTER )
3659- #define skipprefix rb_enc_path_skip_prefix
3665+ #define skipprefix enc_path_skip_prefix
36603666#else
3661- #define skipprefix (path , end , enc ) (path)
3667+ #define skipprefix (path , end , mb_enc , enc ) (path)
36623668#endif
3663- char *
3664- rb_enc_path_skip_prefix (const char * path , const char * end , rb_encoding * enc )
3669+ static inline char *
3670+ enc_path_skip_prefix (const char * path , const char * end , bool mb_enc , rb_encoding * enc )
36653671{
36663672#if defined(DOSISH_UNC ) || defined(DOSISH_DRIVE_LETTER )
36673673#ifdef DOSISH_UNC
36683674 if (path + 2 <= end && isdirsep (path [0 ]) && isdirsep (path [1 ])) {
36693675 path += 2 ;
36703676 while (path < end && isdirsep (* path )) path ++ ;
3671- if ((path = rb_enc_path_next (path , end , enc )) < end && path [0 ] && path [1 ] && !isdirsep (path [1 ]))
3672- path = rb_enc_path_next (path + 1 , end , enc );
3677+ if ((path = enc_path_next (path , end , mb_enc , enc )) < end && path [0 ] && path [1 ] && !isdirsep (path [1 ]))
3678+ path = enc_path_next (path + 1 , end , mb_enc , enc );
36733679 return (char * )path ;
36743680 }
36753681#endif
@@ -3681,11 +3687,17 @@ rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
36813687 return (char * )path ;
36823688}
36833689
3690+ char *
3691+ rb_enc_path_skip_prefix (const char * path , const char * end , rb_encoding * enc )
3692+ {
3693+ return enc_path_skip_prefix (path , end , true, enc );
3694+ }
3695+
36843696static inline char *
36853697skipprefixroot (const char * path , const char * end , rb_encoding * enc )
36863698{
36873699#if defined(DOSISH_UNC ) || defined(DOSISH_DRIVE_LETTER )
3688- char * p = skipprefix (path , end , enc );
3700+ char * p = skipprefix (path , end , true, enc );
36893701 while (isdirsep (* p )) p ++ ;
36903702 return p ;
36913703#else
@@ -3705,34 +3717,35 @@ rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
37053717 last = (char * )tmp ;
37063718 }
37073719 else {
3708- Inc (path , end , enc );
3720+ Inc (path , end , true, enc );
37093721 }
37103722 }
37113723 return last ;
37123724}
37133725
37143726static inline char *
3715- strrdirsep (const char * path , const char * end , rb_encoding * enc )
3727+ strrdirsep (const char * path , const char * end , bool mb_enc , rb_encoding * enc )
37163728{
3717- if (RB_LIKELY (enc == NULL )) {
3718- const char * cursor = end - 1 ;
3729+ if (RB_UNLIKELY (mb_enc )) {
3730+ return rb_enc_path_last_separator (path , end , enc );
3731+ }
37193732
3720- while (isdirsep (cursor [0 ])) {
3721- cursor -- ;
3722- }
3733+ const char * cursor = end - 1 ;
37233734
3724- while (cursor >= path ) {
3725- if (isdirsep (cursor [0 ])) {
3726- while (cursor > path && isdirsep (cursor [-1 ])) {
3727- cursor -- ;
3728- }
3729- return (char * )cursor ;
3735+ while (isdirsep (cursor [0 ])) {
3736+ cursor -- ;
3737+ }
3738+
3739+ while (cursor >= path ) {
3740+ if (isdirsep (cursor [0 ])) {
3741+ while (cursor > path && isdirsep (cursor [-1 ])) {
3742+ cursor -- ;
37303743 }
3731- cursor -- ;
3744+ return ( char * ) cursor ;
37323745 }
3733- return NULL ;
3746+ cursor -- ;
37343747 }
3735- return rb_enc_path_last_separator ( path , end , enc ) ;
3748+ return NULL ;
37363749}
37373750
37383751static char *
@@ -3745,7 +3758,7 @@ chompdirsep(const char *path, const char *end, rb_encoding *enc)
37453758 if (path >= end ) return (char * )last ;
37463759 }
37473760 else {
3748- Inc (path , end , enc );
3761+ Inc (path , end , true, enc );
37493762 }
37503763 }
37513764 return (char * )path ;
@@ -3790,7 +3803,7 @@ ntfs_tail(const char *path, const char *end, rb_encoding *enc)
37903803 if (isADS (* path )) path ++ ;
37913804 }
37923805 else {
3793- Inc (path , end , enc );
3806+ Inc (path , end , true, enc );
37943807 }
37953808 }
37963809 return (char * )path ;
@@ -3852,7 +3865,7 @@ copy_home_path(VALUE result, const char *dir)
38523865 rb_enc_associate_index (result , encidx );
38533866#if defined DOSISH || defined __CYGWIN__
38543867 enc = rb_enc_from_index (encidx );
3855- for (bend = (p = buf ) + dirlen ; p < bend ; Inc (p , bend , enc )) {
3868+ for (bend = (p = buf ) + dirlen ; p < bend ; Inc (p , bend , true, enc )) {
38563869 if (* p == '\\' ) {
38573870 * p = '/' ;
38583871 }
@@ -4096,7 +4109,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
40964109 if (isdirsep (* s )) {
40974110 /* specified full path, but not drive letter nor UNC */
40984111 /* we need to get the drive letter or UNC share name */
4099- p = skipprefix (buf , p , enc );
4112+ p = skipprefix (buf , p , true, enc );
41004113 }
41014114 else
41024115#endif /* defined DOSISH || defined __CYGWIN__ */
@@ -4124,7 +4137,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
41244137 rb_str_set_len (result , p - buf + 1 );
41254138 BUFCHECK (bdiff + 1 >= buflen );
41264139 p [1 ] = 0 ;
4127- root = skipprefix (buf , p + 1 , enc );
4140+ root = skipprefix (buf , p + 1 , true, enc );
41284141
41294142 b = s ;
41304143 while (* s ) {
@@ -4140,7 +4153,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
41404153 /* We must go back to the parent */
41414154 char * n ;
41424155 * p = '\0' ;
4143- if (!(n = strrdirsep (root , p , enc ))) {
4156+ if (!(n = strrdirsep (root , p , true, enc ))) {
41444157 * p = '/' ;
41454158 }
41464159 else {
@@ -4203,7 +4216,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
42034216 }
42044217 }
42054218#endif /* __APPLE__ */
4206- Inc (s , fend , enc );
4219+ Inc (s , fend , true, enc );
42074220 break ;
42084221 }
42094222 }
@@ -4503,7 +4516,7 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE f
45034516 if (* prefixlenp < RSTRING_LEN (* resolvedp )) {
45044517 const char * resolved_str = RSTRING_PTR (* resolvedp );
45054518 const char * resolved_names = resolved_str + * prefixlenp ;
4506- const char * lastsep = strrdirsep (resolved_names , resolved_str + RSTRING_LEN (* resolvedp ), enc );
4519+ const char * lastsep = strrdirsep (resolved_names , resolved_str + RSTRING_LEN (* resolvedp ), true, enc );
45074520 long len = lastsep ? lastsep - resolved_names : 0 ;
45084521 rb_str_resize (* resolvedp , * prefixlenp + len );
45094522 }
@@ -4653,7 +4666,7 @@ rb_check_realpath_emulate(VALUE basedir, VALUE path, rb_encoding *origenc, enum
46534666 if (* prefixptr == FILE_ALT_SEPARATOR ) {
46544667 * prefixptr = '/' ;
46554668 }
4656- Inc (prefixptr , pend , enc );
4669+ Inc (prefixptr , pend , true, enc );
46574670 }
46584671#endif
46594672
@@ -4907,7 +4920,7 @@ ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encodin
49074920 long f = 0 , n = -1 ;
49084921
49094922 end = name + (alllen ? (size_t )* alllen : strlen (name ));
4910- name = skipprefix (name , end , enc );
4923+ name = skipprefix (name , end , true, enc );
49114924#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
49124925 root = name ;
49134926#endif
@@ -4934,7 +4947,7 @@ ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encodin
49344947#endif /* defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC */
49354948 }
49364949 else {
4937- if (!(p = strrdirsep (name , end , enc ))) {
4950+ if (!(p = strrdirsep (name , end , true, enc ))) {
49384951 p = name ;
49394952 }
49404953 else {
@@ -4946,7 +4959,7 @@ ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encodin
49464959 n = chompdirsep (p , end , enc ) - p ;
49474960#endif
49484961 for (q = p ; q - p < n && * q == '.' ; q ++ );
4949- for (e = 0 ; q - p < n ; Inc (q , end , enc )) {
4962+ for (e = 0 ; q - p < n ; Inc (q , end , true, enc )) {
49504963 if (* q == '.' ) e = q ;
49514964 }
49524965 if (e ) f = e - p ;
@@ -5059,30 +5072,23 @@ rb_file_dirname(VALUE fname)
50595072 return rb_file_dirname_n (fname , 1 );
50605073}
50615074
5062- static inline rb_encoding *
5063- path_enc_get (VALUE str )
5064- {
5065- if (RB_LIKELY (rb_str_enc_fastpath (str ))) {
5066- return NULL ;
5067- }
5068- return rb_str_enc_get (str );
5069- }
5070-
50715075static VALUE
50725076rb_file_dirname_n (VALUE fname , int n )
50735077{
50745078 const char * name , * root , * p , * end ;
50755079 VALUE dirname ;
5076- rb_encoding * enc ;
50775080
50785081 if (n < 0 ) rb_raise (rb_eArgError , "negative level: %d" , n );
50795082 CheckPath (fname , name );
50805083 end = name + RSTRING_LEN (fname );
5081- enc = path_enc_get (fname );
5084+
5085+ bool mb_enc = !rb_str_enc_fastpath (fname );
5086+ rb_encoding * enc = rb_str_enc_get (fname );
5087+
50825088 root = skiproot (name , end );
50835089#ifdef DOSISH_UNC
50845090 if (root > name + 1 && isdirsep (* name ))
5085- root = skipprefix (name = root - 2 , end , enc );
5091+ root = skipprefix (name = root - 2 , end , mb_enc , enc );
50865092#else
50875093 if (root > name + 1 )
50885094 name = root - 1 ;
@@ -5093,7 +5099,7 @@ rb_file_dirname_n(VALUE fname, int n)
50935099 else {
50945100 p = end ;
50955101 while (n ) {
5096- if (!(p = strrdirsep (root , p , enc ))) {
5102+ if (!(p = strrdirsep (root , p , mb_enc , enc ))) {
50975103 p = root ;
50985104 break ;
50995105 }
@@ -5102,17 +5108,17 @@ rb_file_dirname_n(VALUE fname, int n)
51025108 }
51035109
51045110 if (p == name ) {
5105- return rb_enc_str_new ("." , 1 , rb_str_enc_get ( fname ) );
5111+ return rb_enc_str_new ("." , 1 , enc );
51065112 }
51075113#ifdef DOSISH_DRIVE_LETTER
51085114 if (has_drive_letter (name ) && isdirsep (* (name + 2 ))) {
51095115 const char * top = skiproot (name + 2 , end );
5110- dirname = rb_enc_str_new (name , 3 , rb_str_enc_get ( fname ) );
5116+ dirname = rb_enc_str_new (name , 3 , enc );
51115117 rb_str_cat (dirname , top , p - top );
51125118 }
51135119 else
51145120#endif
5115- dirname = rb_enc_str_new (name , p - name , rb_str_enc_get ( fname ) );
5121+ dirname = rb_enc_str_new (name , p - name , enc );
51165122#ifdef DOSISH_DRIVE_LETTER
51175123 if (has_drive_letter (name ) && root == name + 2 && p - name == 2 )
51185124 rb_str_cat (dirname , "." , 1 );
@@ -5137,7 +5143,7 @@ ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
51375143{
51385144 const char * p , * e , * end = name + (len ? * len : (long )strlen (name ));
51395145
5140- p = strrdirsep (name , end , enc ); /* get the last path component */
5146+ p = strrdirsep (name , end , true, enc ); /* get the last path component */
51415147 if (!p )
51425148 p = name ;
51435149 else
@@ -5170,7 +5176,7 @@ ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
51705176#endif
51715177 else if (isdirsep (* p ))
51725178 break ;
5173- Inc (p , end , enc );
5179+ Inc (p , end , true , enc );
51745180 }
51755181
51765182 if (len ) {
0 commit comments