egra: added slightly faster sorter to agg mini
[iv.d.git] / vfs / posixci.d
blob492bcc495dafbad9d4adbb36d302fab1efaa282c
1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module iv.vfs.posixci /*is aliced*/;
19 import iv.alice;
20 import iv.vfs.config;
22 static if (VFS_NORMAL_OS) {
24 import core.sys.posix.dirent;
25 import iv.vfs.koi8;
28 // `name` will be modified
29 package bool findFileCI (const(char)[] path, char[] name, bool asDir) nothrow @nogc {
30 import core.sys.posix.dirent;
31 import core.stdc.stdlib : alloca;
32 if (path.length == 0) path = ".";
33 while (path.length && path[$-1] == '/') path = path[0..$-1];
34 if (path.length == 0) path = "/";
35 if (path.length+name.length > 4094) return false;
36 char* tmpbuf = cast(char*)alloca(path.length+name.length+2);
37 tmpbuf[0..path.length] = path[];
38 // check if we have perfect match
40 import core.sys.posix.sys.stat;
41 tmpbuf[path.length] = '/';
42 tmpbuf[path.length+1..path.length+1+name.length] = name[];
43 tmpbuf[path.length+1+name.length] = '\0';
44 stat_t st = void;
45 auto res = stat(tmpbuf, &st);
46 if (res == 0) {
47 // the file is here
48 if ((asDir && (st.st_mode&(S_IFDIR|S_IFLNK)) != 0) || (!asDir && (st.st_mode&(S_IFREG|S_IFLNK)) != 0)) {
49 return true;
53 // vanilla dmd has bug in dirent definition: it's not aligned
54 /*static if (dirent.d_name.offsetof == 19)*/ {
55 tmpbuf[path.length] = '\0';
56 auto dir = opendir(tmpbuf);
57 if (dir is null) return false;
58 scope(exit) closedir(dir);
59 for (;;) {
60 auto de = readdir(dir);
61 if (de is null) break;
62 //{ import core.stdc.stdio : printf; printf("[%s]\n", de.d_name.ptr); }
63 const(char)[] dename;
64 uint pos = 0;
65 while (pos < de.d_name.length && de.d_name.ptr[pos]) ++pos;
66 dename = de.d_name[0..pos];
67 if (dename != "." && dename != ".." && koi8StrCaseEqu(name, dename)) {
68 // i found her... maybe
69 import core.sys.posix.sys.stat;
70 tmpbuf[path.length] = '/';
71 tmpbuf[path.length+1..path.length+1+dename.length] = dename[];
72 tmpbuf[path.length+1+dename.length] = '\0';
73 stat_t st = void;
74 auto res = stat(tmpbuf, &st);
75 if (res == 0) {
76 // the file is here
77 if ((asDir && (st.st_mode&(S_IFDIR|S_IFLNK)) != 0) || (!asDir && (st.st_mode&(S_IFREG|S_IFLNK)) != 0)) {
78 name[] = dename[];
79 return true;
85 return false;
89 // `path` will be modified; returns new path (slice of `path`) or `null` (and `path` is not modified)
90 package char[] dirNormalize (char[] path) nothrow @nogc {
91 char[1024*3] tmpbuf;
92 uint tpos, ppos;
93 if (path.length && path[0] == '/') tmpbuf.ptr[tpos++] = '/';
94 while (ppos < path.length) {
95 if (path.ptr[ppos] == '/') {
96 while (ppos < path.length && path.ptr[ppos] == '/') ++ppos;
97 continue;
99 uint pend = ppos;
100 while (pend < path.length && path.ptr[pend] != '/') ++pend;
101 assert(pend > ppos);
102 if (pend < path.length) ++pend;
103 const(char)[] nm = path[ppos..pend];
104 if (nm == "../" || nm == "..") {
105 if (tpos == 0) return null;
106 --tpos; // skip slash
107 while (tpos > 0 && tmpbuf.ptr[tpos-1] != '/') --tpos;
108 //if (tpos == 0) return null;
109 } else if (nm != "./" && nm != ".") {
110 if (tpos+nm.length >= tmpbuf.length) return null;
111 tmpbuf[tpos..tpos+nm.length] = nm[];
112 tpos += pend-ppos;
114 ppos = pend;
116 if (tpos == 0) return null;
117 if (tpos > 1 && tmpbuf.ptr[tpos-1] == '/') --tpos;
118 path[0..tpos] = tmpbuf[0..tpos];
119 return path[0..tpos];
123 // `asDir`: should last element be threated as directory?
124 // `path` will be modified; returns new path (slice of `path`) or `null`
125 package char[] findPathCI (char[] path, bool asDir=false) nothrow @nogc {
126 path = dirNormalize(path);
127 if (path is null) return null;
128 if (path.length == 0) return null;
129 uint ppos = 0;
130 while (ppos < path.length) {
131 // first slash?
132 if (ppos == 0 && path[0] == '/') {
133 ++ppos;
134 continue;
136 uint pend = ppos;
137 while (pend < path.length && path.ptr[pend] != '/') ++pend;
138 assert(pend > ppos);
139 if (!findFileCI(path[0..ppos], path[ppos..pend], (pend < path.length ? true : asDir))) return null;
140 ppos = pend+1;
142 return path;
149 void main () {
150 import std.stdio;
152 //char[] path = "//foo/bar////./z/./../../..".dup;
153 char[] path = "//foo/bar////./z/./././..".dup;
154 writeln(findPathCI(path));
157 char[] name = "PosixCI.D".dup;
158 writeln(findPathCI(name));
161 char[] name = "SaMpLES".dup;
162 writeln(findPathCI(name, true));
165 char[] name = "SaMpLES".dup;
166 writeln(findPathCI(name, true));
169 char[] name = "./SaMpLES/sAMPle00.d".dup;
170 writeln(findPathCI(name));
173 char[] name = "./SaMpLES/../sAMPle00.d/../PosixCI.d".dup;
174 writeln(findPathCI(name));
177 char[] name = "posixci.d".dup;
178 writeln(findPathCI(name));