Initial sauer
[SauerbratenRemote.git] / src / shared / tools.cpp
blobb96961ed6920dc903650e9cd32221e499774a9b3
1 // implementation of generic tools
3 #include "pch.h"
4 #include "tools.h"
6 ///////////////////////// file system ///////////////////////
8 #ifndef WIN32
9 #include <unistd.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12 #include <dirent.h>
13 #endif
15 string homedir = "";
16 vector<char *> packagedirs;
18 char *path(char *s)
20 for(char *t = s; (t = strpbrk(t, "/\\")); *t++ = PATHDIV);
21 for(char *prevdir = NULL, *curdir = s;;)
23 prevdir = curdir[0]==PATHDIV ? curdir+1 : curdir;
24 curdir = strchr(prevdir, PATHDIV);
25 if(!curdir) break;
26 if(prevdir+1==curdir && prevdir[0]=='.')
28 memmove(prevdir, curdir+1, strlen(curdir+1)+1);
29 curdir = prevdir;
31 else if(curdir[1]=='.' && curdir[2]=='.' && curdir[3]==PATHDIV)
33 if(prevdir+2==curdir && prevdir[0]=='.' && prevdir[1]=='.') continue;
34 memmove(prevdir, curdir+4, strlen(curdir+4)+1);
35 curdir = prevdir;
38 return s;
41 char *path(const char *s, bool copy)
43 static string tmp;
44 s_strcpy(tmp, s);
45 path(tmp);
46 return tmp;
49 const char *parentdir(const char *directory)
51 const char *p = strrchr(directory, '/');
52 if(!p) p = strrchr(directory, '\\');
53 if(!p) p = directory;
54 static string parent;
55 size_t len = p-directory+1;
56 s_strncpy(parent, directory, len);
57 return parent;
60 bool fileexists(const char *path, const char *mode)
62 bool exists = true;
63 if(mode[0]=='w' || mode[0]=='a') path = parentdir(path);
64 #ifdef WIN32
65 if(GetFileAttributes(path) == INVALID_FILE_ATTRIBUTES) exists = false;
66 #else
67 if(access(path, R_OK | (mode[0]=='w' || mode[0]=='a' ? W_OK : 0)) == -1) exists = false;
68 #endif
69 return exists;
72 bool createdir(const char *path)
74 size_t len = strlen(path);
75 if(path[len-1]==PATHDIV)
77 static string strip;
78 path = s_strncpy(strip, path, len);
80 #ifdef WIN32
81 return CreateDirectory(path, NULL)!=0;
82 #else
83 return mkdir(path, 0777)==0;
84 #endif
87 static void fixdir(char *dir)
89 path(dir);
90 size_t len = strlen(dir);
91 if(dir[len-1]!=PATHDIV)
93 dir[len] = PATHDIV;
94 dir[len+1] = '\0';
98 void sethomedir(const char *dir)
100 fixdir(s_strcpy(homedir, dir));
103 void addpackagedir(const char *dir)
105 fixdir(packagedirs.add(newstringbuf(dir)));
108 const char *findfile(const char *filename, const char *mode)
110 static string s;
111 if(homedir[0])
113 s_sprintf(s)("%s%s", homedir, filename);
114 if(fileexists(s, mode)) return s;
115 if(mode[0]=='w' || mode[0]=='a')
117 string dirs;
118 s_strcpy(dirs, s);
119 char *dir = strchr(dirs[0]==PATHDIV ? dirs+1 : dirs, PATHDIV);
120 while(dir)
122 *dir = '\0';
123 if(!fileexists(dirs, "r") && !createdir(dirs)) return s;
124 *dir = PATHDIV;
125 dir = strchr(dir+1, PATHDIV);
127 return s;
130 if(mode[0]=='w' || mode[0]=='a') return filename;
131 loopv(packagedirs)
133 s_sprintf(s)("%s%s", packagedirs[i], filename);
134 if(fileexists(s, mode)) return s;
136 return filename;
139 FILE *openfile(const char *filename, const char *mode)
141 const char *found = findfile(filename, mode);
142 if(!found) return NULL;
143 return fopen(found, mode);
146 gzFile opengzfile(const char *filename, const char *mode)
148 const char *found = findfile(filename, mode);
149 if(!found) return NULL;
150 return gzopen(found, mode);
153 char *loadfile(const char *fn, int *size)
155 FILE *f = openfile(fn, "rb");
156 if(!f) return NULL;
157 fseek(f, 0, SEEK_END);
158 int len = ftell(f);
159 if(len<=0) { fclose(f); return NULL; }
160 fseek(f, 0, SEEK_SET);
161 char *buf = new char[len+1];
162 if(!buf) { fclose(f); return NULL; }
163 buf[len] = 0;
164 size_t rlen = fread(buf, 1, len, f);
165 fclose(f);
166 if(size_t(len)!=rlen)
168 delete[] buf;
169 return NULL;
171 if(size!=NULL) *size = len;
172 return buf;
175 bool listdir(const char *dir, const char *ext, vector<char *> &files)
177 int extsize = ext ? (int)strlen(ext)+1 : 0;
178 #if defined(WIN32)
179 s_sprintfd(pathname)("%s\\*.%s", dir, ext ? ext : "*");
180 WIN32_FIND_DATA FindFileData;
181 HANDLE Find = FindFirstFile(path(pathname), &FindFileData);
182 if(Find != INVALID_HANDLE_VALUE)
184 do {
185 files.add(newstring(FindFileData.cFileName, (int)strlen(FindFileData.cFileName) - extsize));
186 } while(FindNextFile(Find, &FindFileData));
187 return true;
189 #else
190 string pathname;
191 s_strcpy(pathname, dir);
192 DIR *d = opendir(path(pathname));
193 if(d)
195 struct dirent *de;
196 while((de = readdir(d)) != NULL)
198 if(!ext) files.add(newstring(de->d_name));
199 else
201 int namelength = (int)strlen(de->d_name) - extsize;
202 if(namelength > 0 && de->d_name[namelength] == '.' && strncmp(de->d_name+namelength+1, ext, extsize-1)==0)
203 files.add(newstring(de->d_name, namelength));
206 closedir(d);
207 return true;
209 #endif
210 else return false;
213 int listfiles(const char *dir, const char *ext, vector<char *> &files)
215 int dirs = 0;
216 if(listdir(dir, ext, files)) dirs++;
217 string s;
218 if(homedir[0])
220 s_sprintf(s)("%s%s", homedir, dir);
221 if(listdir(s, ext, files)) dirs++;
223 loopv(packagedirs)
225 s_sprintf(s)("%s%s", packagedirs[i], dir);
226 if(listdir(s, ext, files)) dirs++;
228 return dirs;
231 ///////////////////////// misc tools ///////////////////////
233 void endianswap(void *memory, int stride, int length) // little endian as storage format
235 static const int littleendian = 1;
236 if(!*(const char *)&littleendian) loop(w, length) loop(i, stride/2)
238 uchar *p = (uchar *)memory+w*stride;
239 uchar t = p[i];
240 p[i] = p[stride-i-1];
241 p[stride-i-1] = t;
246 ////////////////////////// rnd numbers ////////////////////////////////////////
248 #define N (624)
249 #define M (397)
250 #define K (0x9908B0DFU)
251 #define hiBit(u) ((u) & 0x80000000U)
252 #define loBit(u) ((u) & 0x00000001U)
253 #define loBits(u) ((u) & 0x7FFFFFFFU)
254 #define mixBits(u, v) (hiBit(u)|loBits(v))
256 static uint state[N+1];
257 static uint *next;
258 static int left = -1;
260 void seedMT(uint seed)
262 register uint x = (seed | 1U) & 0xFFFFFFFFU, *s = state;
263 register int j;
264 for(left=0, *s++=x, j=N; --j; *s++ = (x*=69069U) & 0xFFFFFFFFU);
267 uint reloadMT(void)
269 register uint *p0=state, *p2=state+2, *pM=state+M, s0, s1;
270 register int j;
271 if(left < -1) seedMT(time(NULL));
272 left=N-1, next=state+1;
273 for(s0=state[0], s1=state[1], j=N-M+1; --j; s0=s1, s1=*p2++) *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
274 for(pM=state, j=M; --j; s0=s1, s1=*p2++) *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
275 s1=state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
276 s1 ^= (s1 >> 11);
277 s1 ^= (s1 << 7) & 0x9D2C5680U;
278 s1 ^= (s1 << 15) & 0xEFC60000U;
279 return(s1 ^ (s1 >> 18));
282 uint randomMT(void)
284 uint y;
285 if(--left < 0) return(reloadMT());
286 y = *next++;
287 y ^= (y >> 11);
288 y ^= (y << 7) & 0x9D2C5680U;
289 y ^= (y << 15) & 0xEFC60000U;
290 return(y ^ (y >> 18));