/** * Macros: * WIKI = StdPath * Copyright: * Copyright (c) 2001-2005 by Digital Mars * All Rights Reserved * www.digitalmars.com */ // File name parsing module std.path; //debug=path; // uncomment to turn on debugging printf's private import std.string; version(Win32) { const char[1] sep = "\\"; /// String used to separate directory names in a path. const char[1] altsep = "/"; /// Alternate version of sep[], used in Windows. const char[1] pathsep = ";"; /// Path separator string. const char[2] linesep = "\r\n"; /// String used to separate lines. const char[1] curdir = "."; /// String representing the current directory. const char[2] pardir = ".."; /// String representing the parent directory. } version(linux) { const char[1] sep = "/"; /// String used to separate directory names in a path. const char[0] altsep; /// Alternate version of sep[], used in Windows. const char[1] pathsep = ":"; /// Path separator string. const char[1] linesep = "\n"; /// String used to separate lines. const char[1] curdir = "."; /// String representing the current directory. const char[2] pardir = ".."; /// String representing the parent directory. } /************************** * Get extension. * For example, "d:\path\foo.bat" returns "bat". */ char[] getExt(char[] fullname) { uint i; i = fullname.length; while (i > 0) { if (fullname[i - 1] == '.') return fullname[i .. fullname.length]; i--; version(Win32) { if (fullname[i] == ':' || fullname[i] == '\\') break; } version(linux) { if (fullname[i] == '/') break; } } return null; } unittest { debug(path) printf("path.getExt.unittest\n"); int i; char[] result; version (Win32) result = getExt("d:\\path\\foo.bat"); version (linux) result = getExt("/path/foo.bat"); i = cmp(result, "bat"); assert(i == 0); version (Win32) result = getExt("d:\\path\\foo."); version (linux) result = getExt("d/path/foo."); i = cmp(result, ""); assert(i == 0); version (Win32) result = getExt("d:\\path\\foo"); version (linux) result = getExt("d/path/foo"); i = cmp(result, ""); assert(i == 0); version (Win32) result = getExt("d:\\path.bar\\foo"); version (linux) result = getExt("/path.bar/foo"); i = cmp(result, ""); assert(i == 0); result = getExt("foo"); i = cmp(result, ""); assert(i == 0); } /************************** * Get base name. * For example, "d:\path\foo.bat" returns "foo.bat". */ char[] getBaseName(char[] fullname) out (result) { assert(result.length <= fullname.length); } body { uint i; for (i = fullname.length; i > 0; i--) { version(Win32) { if (fullname[i - 1] == ':' || fullname[i - 1] == '\\') break; } version(linux) { if (fullname[i - 1] == '/') break; } } return fullname[i .. fullname.length]; } unittest { debug(path) printf("path.getBaseName.unittest\n"); int i; char[] result; version (Win32) result = getBaseName("d:\\path\\foo.bat"); version (linux) result = getBaseName("/path/foo.bat"); //printf("result = '%.*s'\n", result); i = cmp(result, "foo.bat"); assert(i == 0); version (Win32) result = getBaseName("a\\b"); version (linux) result = getBaseName("a/b"); i = cmp(result, "b"); assert(i == 0); } /************************** * Get directory name. * For example, "d:\path\foo.bat" returns "d:\path". */ char[] getDirName(char[] fullname) out (result) { assert(result.length <= fullname.length); } body { uint i; for (i = fullname.length; i > 0; i--) { version(Win32) { if (fullname[i - 1] == ':') break; if (fullname[i - 1] == '\\') { i--; break; } } version(linux) { if (fullname[i - 1] == '/') { i--; break; } } } return fullname[0 .. i]; } /******************************** * Get drive. * For example, "d:\path\foo.bat" returns "d:". */ char[] getDrive(char[] fullname) out (result) { assert(result.length <= fullname.length); } body { version(Win32) { int i; for (i = 0; i < fullname.length; i++) { if (fullname[i] == ':') return fullname[0 .. i + 1]; } return null; } version(linux) { return null; } } /**************************** * If filename doesn't already have an extension, * append the extension ext and return the result. */ char[] defaultExt(char[] filename, char[] ext) { char[] existing; existing = getExt(filename); if (existing.length == 0) { // Check for filename ending in '.' if (filename.length && filename[filename.length - 1] == '.') filename ~= ext; else filename = filename ~ "." ~ ext; } return filename; } /**************************** * Strip any existing extension off of filename and add the new extension ext. * Return the result. */ char[] addExt(char[] filename, char[] ext) { char[] existing; existing = getExt(filename); if (existing.length == 0) { // Check for filename ending in '.' if (filename.length && filename[filename.length - 1] == '.') filename ~= ext; else filename = filename ~ "." ~ ext; } else { filename = filename[0 .. filename.length - existing.length] ~ ext; } return filename; } /************************************* * Return !=0 if path is absolute (i.e. it starts from the root directory). */ int isabs(char[] path) { char[] d = getDrive(path); return d.length < path.length && path[d.length] == sep[0]; } /************************************* * Join two path components p1 and p2 and return the result. */ char[] join(char[] p1, char[] p2) { if (!p2.length) return p1; if (!p1.length) return p2; char[] p; char[] d1; version(Win32) { if (getDrive(p2)) { p = p2; } else { d1 = getDrive(p1); if (p1.length == d1.length) { p = p1 ~ p2; } else if (p2[0] == '\\') { if (d1.length == 0) p = p2; else if (p1[p1.length - 1] == '\\') p = p1 ~ p2[1 .. p2.length]; else p = p1 ~ p2; } else if (p1[p1.length - 1] == '\\') { p = p1 ~ p2; } else { p = p1 ~ sep ~ p2; } } } version(linux) { if (p2[0] == sep[0]) { p = p2; } else if (p1[p1.length - 1] == sep[0]) { p = p1 ~ p2; } else { p = p1 ~ sep ~ p2; } } return p; } unittest { debug(path) printf("path.join.unittest\n"); char[] p; int i; p = join("foo", "bar"); version (Win32) i = cmp(p, "foo\\bar"); version (linux) i = cmp(p, "foo/bar"); assert(i == 0); version (Win32) { p = join("foo\\", "bar"); i = cmp(p, "foo\\bar"); } version (linux) { p = join("foo/", "bar"); i = cmp(p, "foo/bar"); } assert(i == 0); version (Win32) { p = join("foo", "\\bar"); i = cmp(p, "\\bar"); } version (linux) { p = join("foo", "/bar"); i = cmp(p, "/bar"); } assert(i == 0); version (Win32) { p = join("foo\\", "\\bar"); i = cmp(p, "\\bar"); } version (linux) { p = join("foo/", "/bar"); i = cmp(p, "/bar"); } assert(i == 0); version(Win32) { p = join("d:", "bar"); i = cmp(p, "d:bar"); assert(i == 0); p = join("d:\\", "bar"); i = cmp(p, "d:\\bar"); assert(i == 0); p = join("d:\\", "\\bar"); i = cmp(p, "d:\\bar"); assert(i == 0); p = join("d:\\foo", "bar"); i = cmp(p, "d:\\foo\\bar"); assert(i == 0); p = join("d:", "\\bar"); i = cmp(p, "d:\\bar"); assert(i == 0); p = join("foo", "d:"); i = cmp(p, "d:"); assert(i == 0); p = join("foo", "d:\\"); i = cmp(p, "d:\\"); assert(i == 0); p = join("foo", "d:\\bar"); i = cmp(p, "d:\\bar"); assert(i == 0); } } /********************************* * Match file name characters c1 and c2. * Case sensitivity depends on the operating system. */ int fncharmatch(dchar c1, dchar c2) { version (Win32) { if (c1 != c2) { if ('A' <= c1 && c1 <= 'Z') c1 += cast(char)'a' - 'A'; if ('A' <= c2 && c2 <= 'Z') c2 += cast(char)'a' - 'A'; return c1 == c2; } return true; } version (linux) { return c1 == c2; } } /************************************ * Match filename with pattern, using the following wildcards: * *
* | match 0 or more characters * |
? | match any character * |
[chars] | match any character that appears between the [] * |
[!chars] | match any character that does not appear between the [! ] * |