diff dmd/FileName.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children 7427ded8caf7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/FileName.d	Sat Oct 24 08:42:06 2009 +0400
@@ -0,0 +1,535 @@
+module dmd.FileName;
+
+import dmd.String;
+import dmd.Array;
+import dmd.OutBuffer;
+import dmd.File;
+
+import core.stdc.stdlib : malloc, alloca;
+import core.stdc.string : memcpy, strlen;
+import core.stdc.ctype : isspace;
+
+import std.contracts : assumeUnique;
+import std.string : cmp, icmp;
+import std.file : mkdirRecurse;
+
+import core.sys.windows.windows;
+
+class FileName : String
+{
+    this(string str)
+	{
+		super(str);
+	}
+
+    this(string path, string name)
+	{
+		super(combine(path, name));
+	}
+
+    hash_t hashCode()
+	{
+version (_WIN32) {
+		// We need a different hashCode because it must be case-insensitive
+		size_t len = str.length;
+		hash_t hash = 0;
+		ubyte* s = cast(ubyte*)str.ptr;
+
+		for (;;)
+		{
+			switch (len)
+			{
+				case 0:
+					return hash;
+
+				case 1:
+					hash *= 37;
+					hash += *(cast(ubyte*)s) | 0x20;
+					return hash;
+
+				case 2:
+					hash *= 37;
+					hash += *(cast(ushort*)s) | 0x2020;
+					return hash;
+
+				case 3:
+					hash *= 37;
+					hash += (*cast(ushort*)s) << 8 +
+						((cast(ubyte*)s)[2]) | 0x202020;
+					break;
+
+				default:
+					hash *= 37;
+					hash += (*cast(int*)s) | 0x20202020;
+					s += 4;
+					len -= 4;
+					break;
+			}
+		}
+} else {
+		// darwin HFS is case insensitive, though...
+		return super.hashCode();
+}
+	}
+
+    bool opEquals(Object obj)
+	{
+		return opCmp(obj) == 0;
+	}
+
+    static int equals(string name1, string name2)
+	{
+		return compare(name1, name2) == 0;
+	}
+
+    int opCmp(Object obj)
+	{
+		return compare(str, (cast(FileName)obj).str);
+	}
+
+    static int compare(string name1, string name2)
+	{
+version (_WIN32) {
+    return icmp(name1, name2);
+} else {
+    return cmp(name1, name2);
+}
+	}
+
+    static bool absolute(string name)
+	{
+version (_WIN32) {
+		return (*name == '\\') ||
+			(*name == '/')  ||
+			(*name && name[1] == ':');
+} else version (POSIX) {
+		return (*name == '/');
+} else {
+    static assert(false);
+}
+	}
+
+	/********************************
+	 * Return filename extension (read-only).
+	 * Points past '.' of extension.
+	 * If there isn't one, return NULL.
+	 */
+    static string ext(string str)
+	{
+		foreach_reverse (i, c; str)
+		{
+			switch (c)
+			{
+				case '.':
+					return str[i+1..$];
+version (POSIX) {
+				case '/':
+					return null;
+}
+version (_WIN32) {
+				case '\\':
+				case ':':
+				case '/':
+					return null;
+
+}				default:
+					break;
+			}
+		}
+		
+		return null;
+	}
+
+    string ext()
+	{
+		return ext(str);
+	}
+	
+	/********************************
+	 * Return filename with extension removed.
+	 */
+
+    static string removeExt(string str)
+	{
+		string e = ext(str);
+		if (e !is null)
+		{
+			size_t len = (e.ptr - str.ptr - 1);
+			return str[0..len];
+		}
+
+		return str;
+	}
+	
+	/********************************
+	 * Return filename name excluding path (read-only).
+	 */
+
+    static string name(string str)
+	{
+		foreach_reverse(i, c; str)
+		{
+			switch (c)
+			{
+version (POSIX) {
+				case '/':
+				   return str[i+1..$];
+}
+version (_WIN32) {
+				case '/':
+				case '\\':
+					return str[i+1..$];
+				case ':':
+					/* The ':' is a drive letter only if it is the second
+					 * character or the last character,
+					 * otherwise it is an ADS (Alternate Data Stream) separator.
+					 * Consider ADS separators as part of the file name.
+					 */
+					if (i == 1 || i == str.length - 1)
+						return str[i+1..$];
+}
+				default:
+					break;
+			}
+		}
+
+		return str;
+	}
+
+    string name()
+	{
+		return name(str);
+	}
+	
+	/**************************************
+	 * Return path portion of str.
+	 * Path will does not include trailing path separator.
+	 */
+
+    static string path(string str)
+	{
+		auto n = name(str).ptr;
+
+		if (n > str.ptr)
+		{
+			auto p = n - 1;
+version (POSIX) {
+			if (*p == '/')
+				n--;
+} else version (_WIN32) {
+			if (*p == '\\' || *p == '/')
+				n--;
+} else {
+			static assert(false);
+}
+		}
+
+		size_t pathlen = n - str.ptr;
+		return str[0..pathlen];
+	}
+	
+	/**************************************
+	 * Replace filename portion of path.
+	 */
+	
+    static string replaceName(string path, string name)
+	{
+		if (absolute(name))
+			return name;
+
+		string n = FileName.name(path);
+		if (n is path)
+			return name;
+
+		size_t pathlen = n.ptr - path.ptr;
+		size_t namelen = name.length;
+
+		char* f = cast(char*)malloc(pathlen + 1 + namelen + 1);
+		memcpy(f, path.ptr, pathlen);
+version (POSIX) {
+		if (path[pathlen - 1] != '/')
+		{
+			f[pathlen] = '/';
+			pathlen++;
+		}
+} else version (_WIN32) {
+		if (path[pathlen - 1] != '\\' &&
+			path[pathlen - 1] != '/' &&
+			path[pathlen - 1] != ':')
+		{
+			f[pathlen] = '\\';
+			pathlen++;
+		}
+} else {
+		static assert(false);
+}
+		memcpy(f + pathlen, name.ptr, namelen + 1);
+		
+		return assumeUnique(f[0..pathlen+namelen]);
+	}
+
+    static string combine(string path, string name)
+	{
+		size_t pathlen;
+		size_t namelen;
+
+		if (path.length == 0)
+			return name;
+
+		pathlen = path.length;
+		namelen = name.length;
+
+		char* f = cast(char*)malloc(pathlen + 1 + namelen + 1);
+
+		memcpy(f, path.ptr, pathlen);
+
+version (POSIX) {
+		if (path[pathlen - 1] != '/')
+		{
+			f[pathlen] = '/';
+			pathlen++;
+		}
+} else version (_WIN32) {
+		if (path[pathlen - 1] != '\\' && 
+			path[pathlen - 1] != '/'  &&
+			path[pathlen - 1] != ':')
+		{
+			f[pathlen] = '\\';
+			pathlen++;
+		}
+} else {
+		static assert(0);
+}
+		memcpy(f + pathlen, name.ptr, namelen + 1);
+
+		return assumeUnique(f[0..pathlen+namelen]);
+	}
+	
+    static string[] splitPath(const(char)[] spath)
+	{
+		char c = 0;				// unnecessary initializer is for VC /W4
+
+		scope OutBuffer buf = new OutBuffer();
+		string[] array;
+		
+		if (spath !is null)
+		{
+			const(char)* p = spath.ptr;
+			int len = spath.length;
+			do
+			{
+				char instring = 0;
+
+				while (len > 0 && isspace(*p))	{	// skip leading whitespace
+					p++;
+					--len;
+				}
+				
+				buf.reserve(len + 1);	// guess size of path
+				for (; len; p++, len--)
+				{
+					c = *p;
+					switch (c)
+					{
+						case '"':
+							instring ^= 1;	// toggle inside/outside of string
+							continue;
+
+	version (MACINTOSH) {
+						case ',':
+	}
+	version (_WIN32) {
+						case ';':
+	}
+	version (POSIX) {
+						case ':':
+	}
+							p++;
+							break;		// note that ; cannot appear as part
+										// of a path, quotes won't protect it
+
+						case 0x1A:		// ^Z means end of file
+						//case 0:
+							break;
+
+						case '\r':
+							continue;	// ignore carriage returns
+
+	version (POSIX) {
+						case '~':
+							buf.writestring(getenv("HOME"));
+							continue;
+	}
+
+	version (disabled) {
+						case ' ':
+						case '\t':		// tabs in filenames?
+							if (!instring)	// if not in string
+								break;	// treat as end of path
+	}
+						default:
+						buf.writeByte(c);
+						continue;
+					}
+					break;
+				}
+				if (buf.offset)		// if path is not empty
+				{
+					//buf.writeByte(0);	// to asciiz
+					array ~= buf.extractString();
+				}
+			} while (len > 0);
+		}
+		
+		return array;
+	}
+	
+    static FileName defaultExt(string name, string ext)
+	{
+		string e = FileName.ext(name);
+		if (e !is null) {
+			// if already has an extension
+			return new FileName(name);
+		}
+
+		size_t len = name.length;
+		size_t extlen = ext.length;
+		char* s = cast(char*)malloc(len + 1 + extlen + 1);
+		memcpy(s, name.ptr, len);
+		s[len] = '.';
+		memcpy(s + len + 1, ext.ptr, extlen + 1);
+
+		return new FileName(assumeUnique(s[0..len+1+extlen]));
+	}
+
+    static FileName forceExt(string name, string ext)
+	{
+		string e = FileName.ext(name);
+		if (e !is null)				// if already has an extension
+		{
+			size_t len = e.ptr - name.ptr;
+			size_t extlen = ext.length;
+
+			char* s = cast(char*)malloc(len + extlen + 1);
+			memcpy(s, name.ptr, len);
+			memcpy(s + len, ext.ptr, extlen + 1);
+			return new FileName(assumeUnique(s[0..len+extlen]));
+		}
+
+		return defaultExt(name, ext);	// doesn't have one
+	}
+	
+	/******************************
+	 * Return true if extensions match.
+	 */
+	
+    bool equalsExt(string ext)
+	{
+		string e = FileName.ext();
+		if (e.length == 0 && ext.length == 0)
+			return true;
+
+		if (e.length == 0 || ext.length == 0)
+			return false;
+
+version (POSIX) {
+		return cmp(e,ext) == 0;
+} else version (_WIN32) {
+		return icmp(e,ext) == 0;
+} else {
+		static assert(0);
+}
+	}
+	
+	/*************************************
+	 * Copy file from this to to.
+	 */
+
+    void CopyTo(FileName to)
+	{
+		scope File file = new File(this);
+
+version (_WIN32) {
+		file.touchtime = malloc(WIN32_FIND_DATA.sizeof);	// keep same file time
+} else version (POSIX) {
+		file.touchtime = malloc(stat.sizeof); // keep same file time
+} else {
+		static assert(0);
+}
+		file.readv();
+		file.name = to;
+		file.writev();
+	}
+	
+	/*************************************
+	 * Search Path for file.
+	 * Input:
+	 *	cwd	if true, search current directory before searching path
+	 */
+
+    static string searchPath(Array path, string name, bool cwd)
+	{
+		if (absolute(name)) {
+			return exists(name) ? name : null;
+		}
+		
+		if (cwd) {
+			if (exists(name)) {
+				return name;
+			}
+		}
+		
+		if (path !is null) {
+			foreach (i; 0..path.dim)
+			{
+				String p = cast(String)path.data[i];
+				string n = combine(p.str, name);
+
+				if (exists(n))
+					return n;
+			}
+		}
+		
+		return null;
+	}
+	
+    static int exists(string name)
+	{
+version (POSIX) {
+		stat st;
+
+		if (stat(name, &st) < 0)
+			return 0;
+		if (S_ISDIR(st.st_mode))
+			return 2;
+		return 1;
+} else version (_WIN32) {
+		HANDLE h = CreateFileA(toStringz(name), GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, HANDLE.init);	///
+		if (h == INVALID_HANDLE_VALUE) {
+			return 0;
+		}
+		
+		CloseHandle(h);
+
+		DWORD dw = GetFileAttributesA(name.ptr);	/// CARE!
+		if (dw == -1L) {
+			assert(false);
+			return 0;
+		} else if (dw & FILE_ATTRIBUTE_DIRECTORY) {
+			return 2;
+		} else {
+			return 1;
+		}
+} else {
+		static assert(0);
+}
+	}
+	
+    static void ensurePathExists(string path)
+	{
+		try {
+			mkdirRecurse(path);
+		} catch {
+		}
+	}
+}
\ No newline at end of file