Changeset 1692
- Timestamp:
- 06/24/10 01:14:06 (14 years ago)
- Files:
-
- trunk/docsrc/changelog.dd (modified) (1 diff)
- trunk/phobos/std/path.d (modified) (13 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/docsrc/changelog.dd
r1688 r1692 13 13 $(LI $(BUGZILLA 978): std.utf's toUTF* functions accept some invalid and reject some valid UTF) 14 14 $(LI $(BUGZILLA 996): Error in doc on implicit conversion between pointer and array) 15 15 $(LI $(BUGZILLA 2275): std.utf.toUTF16z() should return const(wchar)*) 16 16 $(LI $(BUGZILLA 2872): Length, opIndex for Map) 17 17 $(LI $(BUGZILLA 3202): std.math.pow cause dead loop) 18 18 $(LI $(BUGZILLA 3355): std.string.cmp works incorrectly for mixed-type and different-length strings) 19 19 $(LI $(BUGZILLA 3386): to!bool(string) is not implemented) 20 20 $(LI $(BUGZILLA 3436): std.functional.compose with only one function) 21 21 $(LI $(BUGZILLA 3439): std.range.Sequence.opIndex not consistent after calling popFront().) 22 22 $(LI $(BUGZILLA 3447): std.file uses unconventional file permissions) 23 $(LI $(BUGZILLA 3937): os.path.dirname fails on absolute path) 23 24 $(LI $(BUGZILLA 3961): Error with to!(somestruct)) 24 25 $(LI $(BUGZILLA 4109): (reopened) writeln doesn't work with empty static array) 25 26 $(LI $(BUGZILLA 4171): std.random.uniform does not work for a range of characters) 27 $(LI $(BUGZILLA 4260): windows & basename) 26 28 $(LI $(BUGZILLA 4327): std.container.Array.Range.~this() tries to call free(T[])) 27 29 $(LI $(BUGZILLA 4362): std.range.repeat and cycle do not have a .save() method 28 30 $(LI $(BUGZILLA 4363): std.algorithm.Until is not a forward range) 29 31 ) 30 32 ) 31 33 32 34 <div id=version> 33 35 $(UL 34 36 $(NEW 048) 35 37 $(NEW 047) trunk/phobos/std/path.d
r1591 r1692 20 20 * Copyright Digital Mars 2000 - 2009. 21 21 * Distributed under the Boost Software License, Version 1.0. 22 22 * (See accompanying file LICENSE_1_0.txt or copy at 23 23 * http://www.boost.org/LICENSE_1_0.txt) 24 24 */ 25 25 module std.path; 26 26 27 27 //debug=path; // uncomment to turn on debugging printf's 28 28 //private import std.stdio; 29 29 30 import std. contracts, std.conv, std.file, std.process, std.string, std.traits;30 import std.array, std.conv, std.file, std.process, std.string, std.traits; 31 31 import core.stdc.errno, core.stdc.stdlib; 32 32 33 33 version(Posix) 34 34 { 35 35 private import core.sys.posix.pwd; 36 36 private import core.exception : onOutOfMemoryError; 37 37 } 38 38 39 39 version(Windows) 40 40 { … … 95 95 * also terminates the search. 96 96 * 97 97 * Returns: If a dot was found, characters to its right are 98 98 * returned. If a path separator was found, or fullname didn't 99 99 * contain any dots or path separators, returns null. 100 100 * 101 101 * Throws: Nothing. 102 102 * 103 103 * Examples: 104 104 * ----- 105 * version(Win 32)105 * version(Windows) 106 106 * { 107 107 * getExt(r"d:\path\foo.bat") // "bat" 108 108 * getExt(r"d:\path.two\bar") // null 109 109 * } 110 110 * version(Posix) 111 111 * { 112 112 * getExt(r"/home/user.name/bar.") // "" 113 113 * getExt(r"d:\\path.two\\bar") // "two\\bar" 114 114 * getExt(r"/home/user/.resource") // "resource" 115 115 * } 116 116 * ----- 117 117 */ 118 118 119 119 string getExt(string fullname) 120 120 { 121 121 auto i = fullname.length; 122 122 while (i > 0) 123 123 { 124 if (fullname[i - 1] == '.') 125 return fullname[i .. fullname.length]; 126 i--; 127 version(Win32) 128 { 129 if (fullname[i] == ':' || fullname[i] == '\\') 130 break; 131 } 132 version(Posix) 133 { 134 if (fullname[i] == '/') 135 break; 136 } 124 if (fullname[i - 1] == '.') 125 return fullname[i .. fullname.length]; 126 i--; 127 version(Windows) 128 { 129 if (fullname[i] == ':' || fullname[i] == '\\') 130 break; 131 } 132 else version(Posix) 133 { 134 if (fullname[i] == '/') 135 break; 136 } 137 else 138 { 139 static assert(0); 140 } 137 141 } 138 142 return null; 139 143 } 140 144 141 145 unittest 142 146 { 143 147 debug(path) printf("path.getExt.unittest\n"); 144 148 string result; 145 149 146 version (Win 32)150 version (Windows) 147 151 result = getExt("d:\\path\\foo.bat"); 148 152 version (Posix) 149 153 result = getExt("/path/foo.bat"); 150 154 auto i = cmp(result, "bat"); 151 155 assert(i == 0); 152 156 153 version (Win 32)157 version (Windows) 154 158 result = getExt("d:\\path\\foo."); 155 159 version (Posix) 156 160 result = getExt("d/path/foo."); 157 161 i = cmp(result, ""); 158 162 assert(i == 0); 159 163 160 version (Win 32)164 version (Windows) 161 165 result = getExt("d:\\path\\foo"); 162 166 version (Posix) 163 167 result = getExt("d/path/foo"); 164 168 i = cmp(result, ""); 165 169 assert(i == 0); 166 170 167 version (Win 32)171 version (Windows) 168 172 result = getExt("d:\\path.bar\\foo"); 169 173 version (Posix) 170 174 result = getExt("/path.bar/foo"); 171 175 172 176 i = cmp(result, ""); 173 177 assert(i == 0); 174 178 175 179 result = getExt("foo"); 176 180 i = cmp(result, ""); 177 181 assert(i == 0); … … 186 190 * also terminates the search. 187 191 * 188 192 * Returns: If a dot was found, characters to its left are 189 193 * returned. If a path separator was found, or fullname didn't 190 194 * contain any dots or path separators, returns null. 191 195 * 192 196 * Throws: Nothing. 193 197 * 194 198 * Examples: 195 199 * ----- 196 * version(Win 32)200 * version(Windows) 197 201 * { 198 202 * getName(r"d:\path\foo.bat") => "d:\path\foo" 199 203 * getName(r"d:\path.two\bar") => null 200 204 * } 201 205 * version(Posix) 202 206 * { 203 207 * getName("/home/user.name/bar.") => "/home/user.name/bar" 204 208 * getName(r"d:\path.two\bar") => "d:\path" 205 209 * getName("/home/user/.resource") => "/home/user/" 206 210 * } 207 211 * ----- 208 212 */ 209 213 210 214 string getName(string fullname) 211 215 { 212 216 auto i = fullname.length; 213 217 while (i > 0) 214 218 { 215 if (fullname[i - 1] == '.') 216 return fullname[0 .. i - 1]; 217 i--; 218 version(Win32) 219 { 220 if (fullname[i] == ':' || fullname[i] == '\\') 221 break; 222 } 223 version(Posix) 224 { 225 if (fullname[i] == '/') 226 break; 227 } 219 if (fullname[i - 1] == '.') 220 return fullname[0 .. i - 1]; 221 i--; 222 version(Windows) 223 { 224 if (fullname[i] == ':' || fullname[i] == '\\') 225 break; 226 } 227 else version(Posix) 228 { 229 if (fullname[i] == '/') 230 break; 231 } 232 else 233 { 234 static assert(0); 235 } 228 236 } 229 237 return null; 230 238 } 231 239 232 240 unittest 233 241 { 234 242 debug(path) printf("path.getName.unittest\n"); 235 243 string result; 236 244 237 245 result = getName("foo.bar"); 238 246 auto i = cmp(result, "foo"); 239 247 assert(i == 0); 240 248 241 249 result = getName("d:\\path.two\\bar"); 242 version (Win 32)250 version (Windows) 243 251 i = cmp(result, ""); 244 252 version (Posix) 245 253 i = cmp(result, "d:\\path"); 246 254 assert(i == 0); 247 255 } 248 256 249 257 /************************** 250 258 * Extracts the base name of a path and optionally chops off a 251 259 * specific suffix. 252 260 * … … 258 266 * $(D_PARAM fullname) otherwise. If the kept portion has suffix 259 267 * $(D_PARAM extension), remove that suffix. Return the remaining string. 260 268 * 261 269 * Returns: The portion of $(D_PARAM fullname) left after the path 262 270 * part and the extension part, if any, have been removed. 263 271 * 264 272 * Throws: Nothing. 265 273 * 266 274 * Examples: 267 275 * ----- 268 * version(Win 32)276 * version(Windows) 269 277 * { 270 278 * basename(r"d:\path\foo.bat") => "foo.bat" 271 279 * basename(r"d:\path\foo", ".bat") => "foo" 272 280 * } 273 281 * version(Posix) 274 282 * { 275 283 * basename("/home/user.name/bar.") => "bar." 276 284 * basename("/home/user.name/bar.", ".") => "bar" 277 285 * } 278 286 * ----- 279 287 */ 280 288 281 S basename(S)(S fullname, string extension = null) 289 String basename(String, ExtString = string)(String fullname, ExtString extension = null) 290 if (isSomeString!(String) && isSomeString!(ExtString)) 282 291 out (result) 283 292 { 284 293 assert(result.length <= fullname.length); 285 294 } 286 295 body 287 296 { 288 auto i = fullname.length;289 for (; i > 0; i--)290 {291 version(Win32)292 {293 if (fullname[i - 1] == ':' || fullname[i - 1] == '\\' )297 auto i = fullname.length; 298 for (; i > 0; i--) 299 { 300 version(Windows) 301 { 302 if (fullname[i - 1] == ':' || fullname[i - 1] == '\\' || fullname[i - 1] == '/') 294 303 break; 295 }296 version(Posix)297 {304 } 305 else version(Posix) 306 { 298 307 if (fullname[i - 1] == '/') 299 308 break; 300 } 301 } 302 return chomp(fullname[i .. fullname.length], 303 extension ? extension : ""); 309 } 310 else 311 { 312 static assert(0); 313 } 314 } 315 return chomp(fullname[i .. fullname.length], 316 extension.length ? extension : ""); 304 317 } 305 318 306 319 /** Alias for $(D_PARAM basename), kept for backward 307 320 * compatibility. New code should use $(D_PARAM basename). */ 308 321 alias basename getBaseName; 309 322 310 323 unittest 311 324 { 312 325 debug(path) printf("path.basename.unittest\n"); 313 326 string result; … … 324 337 version (Posix) 325 338 result = basename("a/b"); 326 339 assert(result == "b"); 327 340 328 341 version (Windows) 329 342 result = basename("a\\b.cde", ".cde"); 330 343 version (Posix) 331 344 result = basename("a/b.cde", ".cde"); 332 345 assert(result == "b"); 333 346 347 version (Windows) 348 { 349 assert(basename("abc/xyz") == "xyz"); 350 assert(basename("abc/") == ""); 351 assert(basename("C:/a/b") == "b"); 352 assert(basename(`C:\a/b`) == "b"); 353 } 354 355 assert(basename("~/dmd.conf"w, ".conf"d) == "dmd"); 356 assert(basename("~/dmd.conf"d, ".conf"d) == "dmd"); 357 assert(basename("dmd.conf"w.dup, ".conf"d.dup) == "dmd"); 334 358 } 335 359 336 360 /************************** 337 361 * Extracts the directory part of a path. 338 362 * 339 363 * This function will search $(D fullname) from the end until the 340 364 * first path separator or first character of $(D fullname) is 341 365 * reached. Under Windows, the drive letter separator ($(I colon)) 342 366 * also terminates the search. 343 367 * 344 368 * Returns: If a path separator was found, all the characters to its 345 * left are returned. Otherwise, $(D ".") is returned. 346 * 347 * Under Windows, the found path separator will be included in the 348 * returned string if it is preceeded by a colon. 369 * left without any trailing path separators are returned. Otherwise, 370 * $(D ".") is returned. 371 * 372 * The found path separator will be included in the returned string 373 * if and only if it represents the root. 349 374 * 350 375 * Throws: Nothing. 351 376 * 352 377 * Examples: 353 378 * ----- 354 * version(Win 32)379 * version(Windows) 355 380 * { 356 381 * assert(dirname(r"d:\path\foo.bat") == r"d:\path"); 357 * assert(dirname(dirname(r"d:\path\foo.bat")) == r"d:\"); 382 * assert(dirname(r"d:\path") == r"d:\"); 383 * assert(dirname("d:foo.bat") == "d:."); 384 * assert(dirname("foo.bat") == "."); 358 385 * } 359 386 * version(Posix) 360 387 * { 361 388 * assert(dirname("/home/user") == "/home"); 362 * assert(dirname(dirname("/home/user")) == ""); 363 * } 364 * ----- 365 */ 366 367 Char[] dirname(Char)(Char[] fullname) 368 { 369 auto i = fullname.length; 370 for (; i > 0; i--) 371 { 372 version(Win32) 373 { 374 if (fullname[i - 1] == ':') 389 * assert(dirname("/home") == "/"); 390 * assert(dirname("user") == "."); 391 * } 392 * ----- 393 */ 394 395 String dirname(String)(String fullname) 396 if (isSomeString!(String)) 397 { 398 Unqual!String s = fullname; 399 400 version (Posix) 401 { 402 enum immutable(String) sep = .sep, 403 curdir = .curdir; 404 for (; !s.empty; s.popBack) 405 { 406 if (s.endsWith(sep)) 375 407 break; 376 if (fullname[i - 1] == sep[0] || fullname[i - 1] == altsep[0]) 408 } 409 if (s.empty) 410 return to!(String)(curdir); 411 412 // remove excess non-root slashes: "/home//" --> "/home" 413 while (s.length > sep.length && s.endsWith(sep)) 414 s.popBack; 415 return s; 416 } 417 else version (Windows) 418 { 419 enum immutable(String) sep = .sep, 420 altsep = .altsep, 421 curdir = .curdir, 422 drvsep = ":"; 423 bool foundSep; 424 for (; !s.empty; s.popBack) 425 { 426 if (uint withWhat = s.endsWith(sep, altsep, drvsep)) 377 427 { 378 // Leave separator when it's the starting character 379 // (current root) or when it's preceded by ':' 380 // (absolute root) 381 if (i != 1 && fullname[i - 2] != ':') 382 i--; 428 foundSep = (withWhat != 3); 383 429 break; 384 430 } 385 431 } 386 version(Posix) 387 { 388 if (fullname[i - 1] == sep[0]) 389 { i--; 432 if (!foundSep) 433 { 434 if (s.empty) 435 return to!(String)(curdir); 436 else 437 return to!(String)(s ~ curdir); // cases like "C:." 438 } 439 440 // remove excess non-root separators: "C:\\" --> "C:\" 441 while (s.endsWith(sep) || s.endsWith(altsep)) 442 { 443 auto ss = s.save; 444 s.popBack; 445 if (s.empty || s.endsWith(drvsep)) 446 { 447 s = ss; // preserve path separator representing root 390 448 break; 391 449 } 392 450 } 393 } 394 return i == 0 ? to!(Char[])(".") : fullname[0 .. i]; 451 return s; 452 } 453 else // unknown platform 454 { 455 static assert(0); 456 } 395 457 } 396 458 397 459 unittest 398 460 { 399 461 assert(dirname("") == "."); 400 462 assert(dirname("fileonly") == "."); 463 401 464 version (Posix) 402 465 { 403 466 assert(dirname("/path/to/file") == "/path/to"); 404 } 405 else 406 { 407 version (Win32) 408 { 409 assert(dirname(r"\path\to\file") == r"\path\to"); 410 assert(dirname(r"\foo") == r"\"); 411 assert(dirname(r"c:\foo") == r"c:\"); 412 } 467 assert(dirname("/home") == "/"); 468 469 assert(dirname("/dev/zero"w) == "/dev"); 470 assert(dirname("/dev/null"d) == "/dev"); 471 assert(dirname(".login"w.dup) == "."); 472 assert(dirname(".login"d.dup) == "."); 473 474 // doc example 475 assert(dirname("/home/user") == "/home"); 476 assert(dirname("/home") == "/"); 477 assert(dirname("user") == "."); 478 } 479 version (Windows) 480 { 481 assert(dirname(r"\path\to\file") == r"\path\to"); 482 assert(dirname(r"\foo") == r"\"); 483 assert(dirname(r"c:\foo") == r"c:\"); 484 485 assert(dirname("\\Windows"w) == "\\"); 486 assert(dirname("\\Users"d) == "\\"); 487 assert(dirname("ntuser.dat"w.dup) == "."); 488 assert(dirname("ntuser.dat"d.dup) == "."); 489 490 // doc example 491 assert(dirname(r"d:\path\foo.bat") == r"d:\path"); 492 assert(dirname(r"d:\path") == "d:\\"); 493 assert(dirname("d:foo.bat") == "d:."); 494 assert(dirname("foo.bat") == "."); 413 495 } 414 496 } 415 497 416 498 /** Alias for $(D_PARAM dirname), kept for backward 417 499 * compatibility. New code should use $(D_PARAM dirname). */ 418 500 alias dirname getDirName; 419 501 420 502 unittest 421 503 { 422 504 string filename = "foo/bar"; 423 505 auto d = getDirName(filename); 424 506 assert(d == "foo"); 425 507 } 508 509 unittest // dirname + basename 510 { 511 static immutable Common_dirbasename_testcases = 512 [ 513 [ "/usr/lib" , "/usr" , "lib" ], 514 [ "/usr/" , "/usr" , "" ], 515 [ "/usr" , "/" , "usr" ], 516 [ "/" , "/" , "" ], 517 518 [ "var/run" , "var" , "run" ], 519 [ "var/" , "var" , "" ], 520 [ "var" , "." , "var" ], 521 [ "." , "." , "." ], 522 523 [ "/usr///lib", "/usr" , "lib" ], 524 [ "///usr///" , "///usr" , "" ], 525 [ "///usr" , "/" , "usr" ], 526 [ "///" , "/" , "" ], 527 [ "var///run" , "var" , "run" ], 528 [ "var///" , "var" , "" ], 529 530 [ "a/b/c" , "a/b" , "c" ], 531 [ "a///c" , "a" , "c" ], 532 [ "/\u7A74" , "/" , "\u7A74" ], 533 [ "/\u7A74/." , "/\u7A74", "." ] 534 ]; 535 536 static immutable Windows_dirbasename_testcases = 537 Common_dirbasename_testcases ~ 538 [ 539 [ "C:\\Users\\7mi", "C:\\Users", "7mi" ], 540 [ "C:\\Users\\" , "C:\\Users", "" ], 541 [ "C:\\Users" , "C:\\" , "Users" ], 542 [ "C:\\" , "C:\\" , "" ], 543 544 [ "C:Temp" , "C:." , "Temp" ], 545 [ "C:" , "C:." , "" ], 546 [ "\\dmd\\src" , "\\dmd" , "src" ], 547 [ "\\dmd\\" , "\\dmd" , "" ], 548 [ "\\dmd" , "\\" , "dmd" ], 549 550 [ "C:/Users/7mi" , "C:/Users" , "7mi" ], 551 [ "C:/Users/" , "C:/Users" , "" ], 552 [ "C:/Users" , "C:/" , "Users" ], 553 [ "C:/" , "C:/" , "" ], 554 555 [ "C:\\//WinNT" , "C:\\" , "WinNT" ], 556 [ "C://\\WinNT" , "C:/" , "WinNT" ], 557 558 [ `a\b\c` , `a\b` , "c" ], 559 [ `a\\\c` , "a" , "c" ] 560 ]; 561 562 version (Windows) 563 alias Windows_dirbasename_testcases testcases; 564 else 565 alias Common_dirbasename_testcases testcases; 566 567 foreach (tc; testcases) 568 { 569 string path = tc[0]; 570 string dir = tc[1]; 571 string base = tc[2]; 572 573 assert(path.dirname == dir); 574 assert(path.basename == base); 575 } 576 } 577 426 578 427 579 /******************************** 428 580 * Extracts the drive letter of a path. 429 581 * 430 582 * This function will search fullname for a colon from the beginning. 431 583 * 432 584 * Returns: If a colon is found, all the characters to its left 433 585 * plus the colon are returned. Otherwise, null is returned. 434 586 * 435 587 * Under Linux, this function always returns null immediately. … … 443 595 */ 444 596 445 597 String getDrive(String)(String fullname) if (isSomeString!(String)) 446 598 // @@@ BUG 2799 447 599 // out(result) 448 600 // { 449 601 // assert(result.length <= fullname.length); 450 602 // } 451 603 body 452 604 { 453 version(Win32)454 {455 foreach (i; 0 .. fullname.length)456 {605 version(Windows) 606 { 607 foreach (i; 0 .. fullname.length) 608 { 457 609 if (fullname[i] == ':') 458 610 return fullname[0 .. i + 1]; 459 } 460 return null; 461 } 462 version(Posix) 463 { 464 return null; 465 } 611 } 612 return null; 613 } 614 else version(Posix) 615 { 616 return null; 617 } 618 else 619 { 620 static assert(0); 621 } 466 622 } 467 623 468 624 /**************************** 469 625 * Appends a default extension to a filename. 470 626 * 471 627 * This function first searches filename for an extension and 472 628 * appends ext if there is none. ext should not have any leading 473 629 * dots, one will be inserted between filename and ext if filename 474 630 * doesn't already end with one. 475 631 * … … 551 707 * Checks if path is absolute. 552 708 * 553 709 * Returns: non-zero if the path starts from the root directory (Linux) or 554 710 * drive letter and root directory (Windows), 555 711 * zero otherwise. 556 712 * 557 713 * Throws: Nothing. 558 714 * 559 715 * Examples: 560 716 * ----- 561 * version(Win 32)717 * version(Windows) 562 718 * { 563 719 * isabs(r"relative\path") => 0 564 720 * isabs(r"\relative\path") => 0 565 721 * isabs(r"d:\absolute") => 1 566 722 * } 567 723 * version(Posix) 568 724 * { 569 725 * isabs("/home/user") => 1 570 726 * isabs("foo") => 0 571 727 * } 572 728 * ----- 573 729 */ 574 730 575 731 bool isabs(in char[] path) 576 732 { 577 733 auto d = getDrive(path); 578 734 version (Windows) 579 735 { 580 return d.length < path.length && 581 (path[d.length] == sep[0] || path[d.length] == altsep[0]); 736 return d.length < path.length && 737 (path[d.length] == sep[0] || path[d.length] == altsep[0]); 738 } 739 else version (Posix) 740 { 741 return d.length < path.length && path[d.length] == sep[0]; 582 742 } 583 743 else 584 return d.length < path.length && path[d.length] == sep[0]; 744 { 745 static assert(0); 746 } 585 747 } 586 748 587 749 unittest 588 750 { 589 751 debug(path) printf("path.isabs.unittest\n"); 590 752 591 753 version (Windows) 592 754 { 593 755 assert(!isabs(r"relative\path")); 594 756 assert(isabs(r"\relative\path")); … … 647 809 * If p1 doesn't have a trailing path separator, one will be appended 648 810 * to it before concatenating p2. 649 811 * 650 812 * Returns: p1 ~ p2. However, if p2 is an absolute path, only p2 651 813 * will be returned. 652 814 * 653 815 * Throws: Nothing. 654 816 * 655 817 * Examples: 656 818 * ----- 657 * version(Win 32)819 * version(Windows) 658 820 * { 659 821 * join(r"c:\foo", "bar") => r"c:\foo\bar" 660 822 * join("foo", r"d:\bar") => r"d:\bar" 661 823 * } 662 824 * version(Posix) 663 825 * { 664 826 * join("/foo/", "bar") => "/foo/bar" 665 827 * join("/foo", "/bar") => "/bar" 666 828 * } 667 829 * ----- … … 677 839 // Focus on exactly two components 678 840 version (Posix) 679 841 { 680 842 if (isabs(p2)) return p2.idup; 681 843 if (p1.endsWith(sep[]) || altsep.length && p1.endsWith(altsep[])) 682 844 { 683 845 return cast(string) (p1 ~ p2); 684 846 } 685 847 return cast(string) (p1 ~ sep ~ p2); 686 848 } 687 version (Windows)849 else version (Windows) 688 850 { 689 851 if (!p2.length) 690 852 return p1.idup; 691 853 if (!p1.length) 692 854 return p2.idup; 693 855 694 856 string p; 695 857 const(char)[] d1; 696 858 697 859 if (getDrive(p2)) … … 718 880 { 719 881 p = cast(string) (p1 ~ p2); 720 882 } 721 883 else 722 884 { 723 885 p = cast(string)(p1 ~ sep ~ p2); 724 886 } 725 887 } 726 888 return p; 727 889 } 890 else // unknown platform 891 { 892 static assert(0); 893 } 728 894 } 729 895 730 896 unittest 731 897 { 732 898 debug(path) printf("path.join.unittest\n"); 733 899 734 900 string p; 735 901 int i; 736 902 737 903 p = join("foo", "bar"); 738 version (Win 32)904 version (Windows) 739 905 i = cmp(p, "foo\\bar"); 740 906 version (Posix) 741 907 i = cmp(p, "foo/bar"); 742 908 assert(i == 0); 743 909 744 version (Win 32)910 version (Windows) 745 911 { p = join("foo\\", "bar"); 746 912 i = cmp(p, "foo\\bar"); 747 913 } 748 914 version (Posix) 749 915 { p = join("foo/", "bar"); 750 916 i = cmp(p, "foo/bar"); 751 917 } 752 918 assert(i == 0); 753 919 754 version (Win 32)920 version (Windows) 755 921 { p = join("foo", "\\bar"); 756 922 i = cmp(p, "\\bar"); 757 923 } 758 924 version (Posix) 759 925 { p = join("foo", "/bar"); 760 926 i = cmp(p, "/bar"); 761 927 } 762 928 assert(i == 0); 763 929 764 version (Win 32)930 version (Windows) 765 931 { p = join("foo\\", "\\bar"); 766 932 i = cmp(p, "\\bar"); 767 933 } 768 934 version (Posix) 769 935 { p = join("foo/", "/bar"); 770 936 i = cmp(p, "/bar"); 771 937 } 772 938 assert(i == 0); 773 939 774 version(Win 32)940 version(Windows) 775 941 { 776 942 p = join("d:", "bar"); 777 943 i = cmp(p, "d:bar"); 778 944 assert(i == 0); 779 945 780 946 p = join("d:\\", "bar"); 781 947 i = cmp(p, "d:\\bar"); 782 948 assert(i == 0); 783 949 784 950 p = join("d:\\", "\\bar"); … … 815 981 * 816 982 * Under Windows, the comparison is done ignoring case. Under Linux 817 983 * an exact match is performed. 818 984 * 819 985 * Returns: non zero if c1 matches c2, zero otherwise. 820 986 * 821 987 * Throws: Nothing. 822 988 * 823 989 * Examples: 824 990 * ----- 825 * version(Win 32)991 * version(Windows) 826 992 * { 827 993 * fncharmatch('a', 'b') => 0 828 994 * fncharmatch('A', 'a') => 1 829 995 * } 830 996 * version(Posix) 831 997 * { 832 998 * fncharmatch('a', 'b') => 0 833 999 * fncharmatch('A', 'a') => 0 834 1000 * } 835 1001 * ----- 836 1002 */ 837 1003 838 1004 bool fncharmatch(dchar c1, dchar c2) 839 1005 { 840 version (Win32) 841 { 842 if (c1 != c2) 843 { 844 if ('A' <= c1 && c1 <= 'Z') 845 c1 += cast(char)'a' - 'A'; 846 if ('A' <= c2 && c2 <= 'Z') 847 c2 += cast(char)'a' - 'A'; 848 return c1 == c2; 849 } 850 return true; 851 } 852 version (Posix) 853 { 854 return c1 == c2; 1006 version (Windows) 1007 { 1008 if (c1 != c2) 1009 { 1010 if ('A' <= c1 && c1 <= 'Z') 1011 c1 += cast(char)'a' - 'A'; 1012 if ('A' <= c2 && c2 <= 'Z') 1013 c2 += cast(char)'a' - 'A'; 1014 return c1 == c2; 1015 } 1016 return true; 1017 } 1018 else version (Posix) 1019 { 1020 return c1 == c2; 1021 } 1022 else 1023 { 1024 static assert(0); 855 1025 } 856 1026 } 857 1027 858 1028 /************************************ 859 1029 * Matches a pattern against a filename. 860 1030 * 861 1031 * Some characters of pattern have special a meaning (they are 862 1032 * <i>meta-characters</i>) and <b>can't</b> be escaped. These are: 863 1033 * <p><table> 864 1034 * <tr><td><b>*</b></td> … … 878 1048 * further portions of the filename. 879 1049 * 880 1050 * Returns: non zero if pattern matches filename, zero otherwise. 881 1051 * 882 1052 * See_Also: fncharmatch(). 883 1053 * 884 1054 * Throws: Nothing. 885 1055 * 886 1056 * Examples: 887 1057 * ----- 888 * version(Win 32)1058 * version(Windows) 889 1059 * { 890 1060 * fnmatch("foo.bar", "*") => 1 891 1061 * fnmatch(r"foo/foo\bar", "f*b*r") => 1 892 1062 * fnmatch("foo.bar", "f?bar") => 0 893 1063 * fnmatch("Goo.bar", "[fg]???bar") => 1 894 1064 * fnmatch(r"d:\foo\bar", "d*foo?bar") => 1 895 1065 * } 896 1066 * version(Posix) 897 1067 * { 898 1068 * fnmatch("Go*.bar", "[fg]???bar") => 0 … … 989 1159 break; 990 1160 } 991 1161 } 992 1162 return ni >= filename.length; 993 1163 } 994 1164 995 1165 unittest 996 1166 { 997 1167 debug(path) printf("path.fnmatch.unittest\n"); 998 1168 999 version (Win 32)1169 version (Windows) 1000 1170 assert(fnmatch("foo", "Foo")); 1001 1171 version (Posix) 1002 1172 assert(!fnmatch("foo", "Foo")); 1003 1173 assert(fnmatch("foo", "*")); 1004 1174 assert(fnmatch("foo.bar", "*")); 1005 1175 assert(fnmatch("foo.bar", "*.*")); 1006 1176 assert(fnmatch("foo.bar", "foo*")); 1007 1177 assert(fnmatch("foo.bar", "f*bar")); 1008 1178 assert(fnmatch("foo.bar", "f*b*r")); 1009 1179 assert(fnmatch("foo.bar", "f???bar"));
