D - streams?
- Pavel Minayev (3/3) Jun 12 2002 Walter, I've just noticed that the latest D distrubution still
- Burton Radons (277/281) Jun 12 2002 My stat isn't in yet either, and I submitted that a month and a half
Walter, I've just noticed that the latest D distrubution still uses the old outdated stream module. Is there anything wrong with the new one, found on my site?
Jun 12 2002
Pavel Minayev wrote:Walter, I've just noticed that the latest D distrubution still uses the old outdated stream module. Is there anything wrong with the new one, found on my site?My stat isn't in yet either, and I submitted that a month and a half ago. Not to mention random and fmt... but weirdly enough, the imports I needed for it are in Phobos. Since I put this in one message a long time ago now, here's the code again, with some unittests added. It won't work out-of-box because the following program: import path; unittest { } int main(char[][] argv) { return 0; } Can't be linked when compiled with "c:\dmd\bin\dmd.exe -debug -unittest" - it gives a "Error 42: Symbol Undefined __ModuleInfo_path". I managed to ensure the unittests were working by taking path apart. -- /* For the string module */ -- /*************************************************** * Determine whether the string ends with another. */ bit endswith(char[] string, char[] match) { if (string.length < match.length) return 0; if (memcmp(&string [string.length - match.length], &match [0], match.length)) return 0; return 1; } unittest { assert(endswith("hello", "llo")); assert(!endswith("hello", "ell")); assert(!endswith("hello", "hhhhello")); } /*************************************************** * Determine whether the string begins with another. */ bit startswith(char[] string, char[] match) { if (string.length < match.length) return 0; if (memcmp(&string [0], &match [0], match.length)) return 0; return 1; } unittest { assert(startswith("hello", "hel")); assert(!startswith("hello", "ell")); assert(!startswith("hello", "helloooooo")); } -- /* For the file module */ -- import date; import path; /*************************************************** * Structure of a file stat. */ class Stat { char[] filename; /* Filename plus full path */ char[] filebase; /* Filename without path */ char[] alternate; /* Alternate (8.3) filename, no path */ d_time creation; /* When this file was created */ d_time access; /* When this file was last used (this will probably be writeTime in Linux) */ d_time write; /* When this file was last written */ long filesize; /* File size in bytes */ bit archive; /* Is an archive file */ bit directory; /* Is a directory */ bit hidden; /* Is hidden (Linux should probably flag this if the file starts with .) */ bit readonly; /* Is read-only (Linux should set this if the process can't write this file) */ bit system; /* Is a system file */ this (char[] path, WIN32_FIND_DATA finder) { SYSTEMTIME systemtime; FILETIME filetime; /* Get the filename and file size */ filebase = ((char []) finder.cFileName).dup; filename = path ~ filebase; alternate = ((char []) finder.cAlternateFileName).dup; filesize = (long) finder.nFileSizeHigh * (long) 0x100000000 + finder.nFileSizeLow; /* Get the attributes */ if (finder.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) archive = 1; if (finder.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) directory = 1; if (finder.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) hidden = 1; if (finder.dwFileAttributes & FILE_ATTRIBUTE_READONLY) readonly = 1; if (finder.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) system = 1; /* Get the times */ filetime = finder.ftCreationTime; if (filetime.dwLowDateTime == 0 && filetime.dwHighDateTime == 0) filetime = finder.ftLastWriteTime; if (!FileTimeToSystemTime(&filetime, &systemtime)) throw new FileError(filename, GetLastError()); creation = SYSTEMTIME2d_time(&systemtime, 0); filetime = finder.ftLastAccessTime; if (filetime.dwLowDateTime == 0 && filetime.dwHighDateTime == 0) filetime = finder.ftLastWriteTime; if (!FileTimeToSystemTime(&filetime, &systemtime)) throw new FileError(filename, GetLastError()); access = SYSTEMTIME2d_time(&systemtime, 0); filetime = finder.ftLastWriteTime; if (!FileTimeToSystemTime(&filetime, &systemtime)) throw new FileError(filename, GetLastError()); write = SYSTEMTIME2d_time(&systemtime, 0); } } /*************************************************** * Collate all files in a directory, returning an * array of strings. The strings do not contain the * path. Throws FileError if the directory does not * exist, if there was some file problem during the * collation, or if the path is malformed (generally * trying to use nonportable features). */ char[][] listdir(char[] path) { WIN32_FIND_DATA finder; HANDLE handle; char[][] list; bit done = 0; /* Since we want to flatten out platform differences, first we cry if the user tried to use Windows. */ if (find (path, (char) "*") >= 0 || find (path, (char) "?") >= 0) throw new FileError(path, "Path contains invalid characters"); /* Form the search path for Windows */ if (endswith(path, "/") || endswith(path, "\\")) path ~= "*"; else path ~= "/*"; /* Start the file search */ handle = FindFirstFileA(toStringz(path ~ "*"), &finder); if (handle == (HANDLE)-1) throw new FileError(path, GetLastError()); while (!done) { char[] filename; /* Handle this file in our own inimitable fashion */ filename = (char[]) finder.cFileName; list ~= filename.dup; /* Go to the next file or bust */ if (!FindNextFileA(handle, &finder)) { if (GetLastError() == ERROR_NO_MORE_FILES) done = 1; else { FindClose(handle); throw new FileError(path, GetLastError()); } } } /* Finished, clean up */ if (!FindClose(handle)) throw new FileError(path, GetLastError()); return list; } /*************************************************** * Collate all files in a directory, returning an * array of stats. Throws FileError if the * directory does not exist, if there was some file * problem during the collation, or if the path is * malformed (generally trying to use nonportable * features). */ Stat[] statdir(char[] path) { WIN32_FIND_DATA finder; HANDLE handle; Stat[] list; bit done = 0; /* Since we want to flatten out platform differences, first we cry if the user tried to use Windows. */ if (find (path, (char) "*") >= 0 || find (path, (char) "?") >= 0) throw new FileError(path, "Path contains invalid characters"); /* Form the search path for Windows */ if (!endswith(path, "/") && !endswith(path, "\\")) path ~= "/"; /* Start the file search */ handle = FindFirstFileA(toStringz(path ~ "*"), &finder); if (handle == (HANDLE)-1) throw new FileError(path, GetLastError()); while (!done) { /* Handle this file in our own inimitable fashion */ list ~= new Stat (path, finder); /* Go to the next file or bust */ if (!FindNextFileA(handle, &finder)) { if (GetLastError() == ERROR_NO_MORE_FILES) done = 1; else { FindClose(handle); throw new FileError(path, GetLastError()); } } } /* Finished, clean up */ if (!FindClose(handle)) throw new FileError(path, GetLastError()); return list; } /*************************************************** * Attempt to stat a single file, returning the * file details. This will throw FileError when the * file cannot be found or when the path is badly * formed. */ Stat stat(char[] filename) { WIN32_FIND_DATA finder; HANDLE handle; char[] path; Stat stat; /* Since we want to flatten out platform differences, first we cry if the user tried to use Windows. */ if (find (filename, (char) "*") >= 0 || find (filename, (char) "?")= 0)throw new FileError(filename, "Path contains invalid characters"); /* Start the file search */ handle = FindFirstFileA(toStringz(filename), &finder); if (handle == (HANDLE)-1) throw new FileError(filename, GetLastError()); /* Construct the path */ if (filename [0] != "/" && filename [0] != "\\") path = curdir; else path = getDirName(filename); /* Statify the sucker */ stat = new Stat(path, finder); /* Finish up */ if (!FindClose(handle)) throw new FileError(path ~ pathsep, GetLastError()); return stat; } unittest { /* Check that listdir, statdir, and stat are equivalent */ char[][] ls = listdir("."); Stat[] ss = statdir("."); Stat st; int c, d; /* They should have the same length */ assert(ls.length == ss.length); /* Do some cross-checking */ for (c = 0; c < ss.length; c ++) { /* Ensure it's in the other list */ for (d = 0; d < ls.length; d ++) { if (ls [d] == ss [c].filebase) break; } /* Ran off the end of the list */ if (d >= ls.length) { printf ("%.*s was not found in list", ss [c].filebase); assert(d < ls.length); /* If it isn't, we finished the loop */ } /* Now compare it to a manual stat */ st = stat(ss [c].filename); assert(st.filename == ss [c].filename); assert(st.filebase == ss [c].filebase); assert(st.alternate == ss [c].alternate); assert(st.creation == ss [c].creation); assert(st.access == ss [c].access); assert(st.write == ss [c].write); assert(st.filesize == ss [c].filesize); /* Make some sanity checks on the times */ assert(st.write >= st.creation); assert(st.access >= st.write); } }
Jun 12 2002