@@ -1132,114 +1132,145 @@ namespace path
11321132 // /
11331133 // /
11341134
1135- // Join two or more pathname components, inserting "\\" as needed.
1136- std::string join_nt (const std::string & a, const std::string & b)
1135+ std::string join_nt (const std::vector< std::string > & paths)
11371136 {
1138- std::string path = a;
1139-
1140- bool b_nts = false ;
1141- if (path.empty ())
1142- {
1143- b_nts = true ;
1144- }
1145- else if (isabs_nt (b))
1137+ if (paths.empty ()) return " " ;
1138+ if (paths.size () == 1 ) return paths[0 ];
1139+
1140+ std::string path = paths[0 ];
1141+
1142+ for (unsigned int i=1 ; i<paths.size (); ++i)
11461143 {
1147- // This probably wipes out path so far. However, it's more
1148- // complicated if path begins with a drive letter:
1149- // 1. join('c:', '/a') == 'c:/a'
1150- // 2. join('c:/', '/a') == 'c:/a'
1151- // But
1152- // 3. join('c:/a', '/b') == '/b'
1153- // 4. join('c:', 'd:/') = 'd:/'
1154- // 5. join('c:/', 'd:/') = 'd:/'
1155-
1156- if ( (pystring::slice (path, 1 , 2 ) != " :" ) ||
1157- (pystring::slice (b, 1 , 2 ) == " :" ) )
1158- {
1159- // Path doesnt start with a drive letter
1160- b_nts = true ;
1161- }
1162- // Else path has a drive letter, and b doesn't but is absolute.
1163- else if ((path.size ()>3 ) ||
1164- ((path.size ()==3 ) && !pystring::endswith (path, " /" ) && !pystring::endswith (path, " \\ " )))
1144+ std::string b = paths[i];
1145+
1146+ bool b_nts = false ;
1147+ if (path.empty ())
11651148 {
11661149 b_nts = true ;
11671150 }
1168- }
1169-
1170- if (b_nts)
1171- {
1172- path = b;
1173- }
1174- else
1175- {
1176- // Join, and ensure there's a separator.
1177- // assert len(path) > 0
1178- if ( pystring::endswith (path, " /" ) || pystring::endswith (path, " \\ " ))
1151+ else if (isabs_nt (b))
11791152 {
1180- if (pystring::startswith (b," /" ) || pystring::startswith (b," \\ " ))
1153+ // This probably wipes out path so far. However, it's more
1154+ // complicated if path begins with a drive letter:
1155+ // 1. join('c:', '/a') == 'c:/a'
1156+ // 2. join('c:/', '/a') == 'c:/a'
1157+ // But
1158+ // 3. join('c:/a', '/b') == '/b'
1159+ // 4. join('c:', 'd:/') = 'd:/'
1160+ // 5. join('c:/', 'd:/') = 'd:/'
1161+
1162+ if ( (pystring::slice (path, 1 , 2 ) != " :" ) ||
1163+ (pystring::slice (b, 1 , 2 ) == " :" ) )
11811164 {
1182- path += pystring::slice (b, 1 );
1165+ // Path doesnt start with a drive letter
1166+ b_nts = true ;
11831167 }
1184- else
1168+ // Else path has a drive letter, and b doesn't but is absolute.
1169+ else if ((path.size ()>3 ) ||
1170+ ((path.size ()==3 ) && !pystring::endswith (path, " /" ) && !pystring::endswith (path, " \\ " )))
11851171 {
1186- path += b ;
1172+ b_nts = true ;
11871173 }
11881174 }
1189- else if (pystring::endswith (path, " :" ))
1175+
1176+ if (b_nts)
11901177 {
1191- path + = b;
1178+ path = b;
11921179 }
1193- else if (!b. empty ())
1180+ else
11941181 {
1195- if (pystring::startswith (b," /" ) || pystring::startswith (b," \\ " ))
1182+ // Join, and ensure there's a separator.
1183+ // assert len(path) > 0
1184+ if ( pystring::endswith (path, " /" ) || pystring::endswith (path, " \\ " ))
1185+ {
1186+ if (pystring::startswith (b," /" ) || pystring::startswith (b," \\ " ))
1187+ {
1188+ path += pystring::slice (b, 1 );
1189+ }
1190+ else
1191+ {
1192+ path += b;
1193+ }
1194+ }
1195+ else if (pystring::endswith (path, " :" ))
11961196 {
11971197 path += b;
11981198 }
1199+ else if (!b.empty ())
1200+ {
1201+ if (pystring::startswith (b," /" ) || pystring::startswith (b," \\ " ))
1202+ {
1203+ path += b;
1204+ }
1205+ else
1206+ {
1207+ path += " \\ " + b;
1208+ }
1209+ }
11991210 else
12001211 {
1201- path += " \\ " + b;
1212+ // path is not empty and does not end with a backslash,
1213+ // but b is empty; since, e.g., split('a/') produces
1214+ // ('a', ''), it's best if join() adds a backslash in
1215+ // this case.
1216+ path += " \\ " ;
12021217 }
12031218 }
1204- else
1205- {
1206- // path is not empty and does not end with a backslash,
1207- // but b is empty; since, e.g., split('a/') produces
1208- // ('a', ''), it's best if join() adds a backslash in
1209- // this case.
1210- path += " \\ " ;
1211- }
12121219 }
1213-
1220+
12141221 return path;
12151222 }
1223+
1224+ // Join two or more pathname components, inserting "\\" as needed.
1225+ std::string join_nt (const std::string & a, const std::string & b)
1226+ {
1227+ std::vector< std::string > paths (2 );
1228+ paths[0 ] = a;
1229+ paths[1 ] = b;
1230+ return join_nt (paths);
1231+ }
12161232
12171233 // Join pathnames.
12181234 // If any component is an absolute path, all previous path components
12191235 // will be discarded.
12201236 // Ignore the previous parts if a part is absolute.
12211237 // Insert a '/' unless the first part is empty or already ends in '/'.
12221238
1223- std::string join_posix (const std::string & a, const std::string & b )
1239+ std::string join_posix (const std::vector< std::string > & paths )
12241240 {
1225- std::string path = a;
1226-
1227- if (pystring::startswith (b, " /" ))
1228- {
1229- path = b;
1230- }
1231- else if (path.empty () || pystring::endswith (path, " /" ))
1232- {
1233- path += b;
1234- }
1235- else
1241+ if (paths.empty ()) return " " ;
1242+ if (paths.size () == 1 ) return paths[0 ];
1243+
1244+ std::string path = paths[0 ];
1245+
1246+ for (unsigned int i=1 ; i<paths.size (); ++i)
12361247 {
1237- path += " /" + b;
1248+ std::string b = paths[i];
1249+ if (pystring::startswith (b, " /" ))
1250+ {
1251+ path = b;
1252+ }
1253+ else if (path.empty () || pystring::endswith (path, " /" ))
1254+ {
1255+ path += b;
1256+ }
1257+ else
1258+ {
1259+ path += " /" + b;
1260+ }
12381261 }
1239-
1262+
12401263 return path;
12411264 }
12421265
1266+ std::string join_posix (const std::string & a, const std::string & b)
1267+ {
1268+ std::vector< std::string > paths (2 );
1269+ paths[0 ] = a;
1270+ paths[1 ] = b;
1271+ return join_posix (paths);
1272+ }
1273+
12431274 std::string join (const std::string & path1, const std::string & path2)
12441275 {
12451276#ifdef WINDOWS
@@ -1250,6 +1281,15 @@ namespace path
12501281 }
12511282
12521283
1284+ std::string join (const std::vector< std::string > & paths)
1285+ {
1286+ #ifdef WINDOWS
1287+ return join_nt (paths);
1288+ #else
1289+ return join_posix (paths);
1290+ #endif
1291+ }
1292+
12531293 // ////////////////////////////////////////////////////////////////////////////////////////////
12541294 // /
12551295 // /
@@ -1593,6 +1633,19 @@ PYSTRING_ADD_TEST(pystring_os_path, join)
15931633 PYSTRING_CHECK_EQUAL (join_posix (" ../a" ," /b" ), " /b" );
15941634 PYSTRING_CHECK_EQUAL (join_posix (" ../a" ," b" ), " ../a/b" );
15951635
1636+ std::vector< std::string > paths;
1637+ PYSTRING_CHECK_EQUAL (join_posix (paths), " " );
1638+ paths.push_back (" /a" );
1639+ PYSTRING_CHECK_EQUAL (join_posix (paths), " /a" );
1640+ paths.push_back (" b" );
1641+ PYSTRING_CHECK_EQUAL (join_posix (paths), " /a/b" );
1642+ paths.push_back (" c/" );
1643+ PYSTRING_CHECK_EQUAL (join_posix (paths), " /a/b/c/" );
1644+ paths.push_back (" d" );
1645+ PYSTRING_CHECK_EQUAL (join_posix (paths), " /a/b/c/d" );
1646+ paths.push_back (" /e" );
1647+ PYSTRING_CHECK_EQUAL (join_posix (paths), " /e" );
1648+
15961649 PYSTRING_CHECK_EQUAL (join_nt (" c:" ," /a" ), " c:/a" );
15971650 PYSTRING_CHECK_EQUAL (join_nt (" c:/" ," /a" ), " c:/a" );
15981651 PYSTRING_CHECK_EQUAL (join_nt (" c:/a" ," /b" ), " /b" );
0 commit comments