@@ -509,6 +509,15 @@ public IRubyObject inspect() {
509509 @ JRubyMethod (required = 1 , optional = 1 , meta = true )
510510 public static IRubyObject basename (ThreadContext context , IRubyObject recv , IRubyObject [] args ) {
511511 Ruby runtime = context .runtime ;
512+ final String separator = runtime .getClass ("File" ).getConstant ("SEPARATOR" ).toString ();
513+ final char separatorChar = separator .charAt (0 );
514+ String altSeparator = null ;
515+ char altSeparatorChar = '\0' ;
516+ final IRubyObject rbAltSeparator = runtime .getClass ("File" ).getConstant ("ALT_SEPARATOR" );
517+ if (rbAltSeparator != context .nil ) {
518+ altSeparator = rbAltSeparator .toString ();
519+ altSeparatorChar = altSeparator .charAt (0 );
520+ }
512521
513522 RubyString origString = StringSupport .checkEmbeddedNulls (runtime , get_path (context , args [0 ]));
514523 Encoding origEncoding = origString .getEncoding ();
@@ -542,16 +551,16 @@ public static IRubyObject basename(ThreadContext context, IRubyObject recv, IRub
542551 }
543552 }
544553
545- while (name .length () > 1 && name .charAt (name .length () - 1 ) == '/' ) {
554+ while (name .length () > 1 && ( name .charAt (name .length () - 1 ) == separatorChar || ( altSeparator != null && name . charAt ( name . length () - 1 ) == altSeparatorChar )) ) {
546555 name = name .substring (0 , name .length () - 1 );
547556 }
548557
549- // Paths which end in "/" or "\\" must be stripped off.
558+ // Paths which end in File::SEPARATOR or File::ALT_SEPARATOR must be stripped off.
550559 int slashCount = 0 ;
551560 int length = name .length ();
552561 for (int i = length - 1 ; i >= 0 ; i --) {
553562 char c = name .charAt (i );
554- if (c != '/' && c != '\\' ) {
563+ if (c != separatorChar && ( altSeparator == null || c != altSeparatorChar ) ) {
555564 break ;
556565 }
557566 slashCount ++;
@@ -560,13 +569,12 @@ public static IRubyObject basename(ThreadContext context, IRubyObject recv, IRub
560569 name = name .substring (0 , name .length () - slashCount );
561570 }
562571
563- int index = name .lastIndexOf ('/' );
564- if (index == -1 ) {
565- // XXX actually only on windows...
566- index = name .lastIndexOf ('\\' );
572+ int index = name .lastIndexOf (separatorChar );
573+ if (altSeparator != null ) {
574+ index = Math .max (index , name .lastIndexOf (altSeparatorChar ));
567575 }
568576
569- if (!name .equals ("/" ) && index != -1 ) {
577+ if (!( name .equals (separator ) || ( altSeparator != null && name . equals ( altSeparator )) ) && index != -1 ) {
570578 name = name .substring (index + 1 );
571579 }
572580
@@ -651,32 +659,57 @@ public static IRubyObject dirname(ThreadContext context, IRubyObject recv, IRuby
651659
652660 static Pattern PROTOCOL_PATTERN = Pattern .compile (URI_PREFIX_STRING + ".*" );
653661 public static String dirname (ThreadContext context , String jfilename ) {
654- String name = jfilename .replace ('\\' , '/' );
662+ final Ruby runtime = context .runtime ;
663+ final String separator = runtime .getClass ("File" ).getConstant ("SEPARATOR" ).toString ();
664+ final char separatorChar = separator .charAt (0 );
665+ String altSeparator = null ;
666+ char altSeparatorChar = '\0' ;
667+ final IRubyObject rbAltSeparator = runtime .getClass ("File" ).getConstant ("ALT_SEPARATOR" );
668+ if (rbAltSeparator != context .nil ) {
669+ altSeparator = rbAltSeparator .toString ();
670+ altSeparatorChar = altSeparator .charAt (0 );
671+ }
672+ String name = jfilename ;
673+ if (altSeparator != null ) {
674+ name = jfilename .replace (altSeparator , separator );
675+ }
655676 int minPathLength = 1 ;
656677 boolean trimmedSlashes = false ;
657678
679+ boolean startsWithSeparator = false ;
680+
681+ if (!name .isEmpty ()) {
682+ startsWithSeparator = name .charAt (0 ) == separatorChar ;
683+ }
684+
685+ boolean startsWithUNCOnWindows = Platform .IS_WINDOWS && startsWith (name , separatorChar , separatorChar );
686+
687+ if (startsWithUNCOnWindows ) {
688+ minPathLength = 2 ;
689+ }
690+
658691 boolean startsWithDriveLetterOnWindows = startsWithDriveLetterOnWindows (name );
659692
660693 if (startsWithDriveLetterOnWindows ) {
661694 minPathLength = 3 ;
662695 }
663696
664697 // jar like paths
665- if (name .contains (".jar!/" )) {
666- int start = name .indexOf ("!/" ) + 1 ;
698+ if (name .contains (".jar!" + separator )) {
699+ int start = name .indexOf ("!" + separator ) + 1 ;
667700 String path = dirname (context , name .substring (start ));
668- if (path .equals ("." ) || path .equals ("/" )) path = "" ;
701+ if (path .equals ("." ) || path .equals (separator )) path = "" ;
669702 return name .substring (0 , start ) + path ;
670703 }
671704 // address all the url like paths first
672705 if (PROTOCOL_PATTERN .matcher (name ).matches ()) {
673- int start = name .indexOf (":/" ) + 2 ;
706+ int start = name .indexOf (":" + separator ) + 2 ;
674707 String path = dirname (context , name .substring (start ));
675708 if (path .equals ("." )) path = "" ;
676709 return name .substring (0 , start ) + path ;
677710 }
678711
679- while (name .length () > minPathLength && name .charAt (name .length () - 1 ) == '/' ) {
712+ while (name .length () > minPathLength && name .charAt (name .length () - 1 ) == separatorChar ) {
680713 trimmedSlashes = true ;
681714 name = name .substring (0 , name .length () - 1 );
682715 }
@@ -691,7 +724,7 @@ public static String dirname(ThreadContext context, String jfilename) {
691724 }
692725 } else {
693726 //TODO deal with UNC names
694- int index = name .lastIndexOf ('/' );
727+ int index = name .lastIndexOf (separator );
695728
696729 if (index == -1 ) {
697730 if (startsWithDriveLetterOnWindows ) {
@@ -701,7 +734,7 @@ public static String dirname(ThreadContext context, String jfilename) {
701734 }
702735 }
703736 if (index == 0 ) {
704- return "/" ;
737+ return jfilename . substring ( 0 , 1 ) ;
705738 }
706739
707740 if (startsWithDriveLetterOnWindows && index == 2 ) {
@@ -710,24 +743,38 @@ public static String dirname(ThreadContext context, String jfilename) {
710743 index ++;
711744 }
712745
713- if (startsWith (jfilename , '\\' , '\\' )) {
714- index = jfilename .length ();
715- String [] split = jfilename .split (Pattern .quote ("\\ " ));
716- if (split [ split .length - 1 ].indexOf ('.' ) > -1 ) {
717- index = jfilename .lastIndexOf ('\\' );
746+ if (startsWithUNCOnWindows ) {
747+ index = jfilename .length ();
748+ String [] split = name .split (Pattern .quote (separator ));
749+ int pathSectionCount = 0 ;
750+ for (int i = 0 ; i < split .length ; i ++) {
751+ if (!split [i ].isEmpty ()) {
752+ pathSectionCount += 1 ;
718753 }
719-
754+ }
755+ if (pathSectionCount > 2 ) {
756+ index = name .lastIndexOf (separator );
757+ }
720758 }
721-
722759 result = jfilename .substring (0 , index );
760+ }
723761
762+ // trim leading slashes
763+ if (startsWithSeparator && result .length () > minPathLength ) {
764+ while (
765+ result .length () > minPathLength &&
766+ (result .charAt (minPathLength ) == separatorChar ||
767+ (altSeparator != null && result .charAt (minPathLength ) == altSeparatorChar ))
768+ ) {
769+ result = result .substring (1 , result .length ());
770+ }
724771 }
725772
726773 char endChar ;
727774 // trim trailing slashes
728775 while (result .length () > minPathLength ) {
729776 endChar = result .charAt (result .length () - 1 );
730- if (endChar == '/' || endChar == '\\' ) {
777+ if (endChar == separatorChar || ( altSeparator != null && endChar == altSeparatorChar ) ) {
731778 result = result .substring (0 , result .length () - 1 );
732779 } else {
733780 break ;
0 commit comments