amd64 fixes
[btb/d2x.git] / include / physfsx.h
1 /* $Id: physfsx.h,v 1.12 2006-07-29 04:02:40 chris Exp $ */
2
3 /*
4  *
5  * Some simple physfs extensions
6  *
7  */
8
9 #ifndef PHYSFSX_H
10 #define PHYSFSX_H
11
12 #if !defined(macintosh) && !defined(_MSC_VER)
13 #include <sys/param.h>
14 #endif
15 #if defined(__linux__)
16 #include <sys/vfs.h>
17 #elif defined(__MACH__) && defined(__APPLE__)
18 #include <sys/mount.h>
19 #endif
20 #include <string.h>
21 #include <stdarg.h>
22
23 #include <physfs.h>
24
25 #include "pstypes.h"
26 #include "error.h"
27 #include "vecmat.h"
28 #include "args.h"
29
30 // Initialise PhysicsFS, set up basic search paths and add arguments from .ini file(s).
31 // The arguments are used to determine the search paths, so the first .ini file must be
32 // in the same directory as D2X. A second one can be in the user directory.
33 static inline void PHYSFSX_init(int argc, char *argv[])
34 {
35         int t;
36
37         PHYSFS_init(argv[0]);
38         PHYSFS_permitSymbolicLinks(1);
39
40         PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1);
41         InitArgs( argc,argv );
42
43         if ((t = FindArg("-userdir"))
44 #ifdef __unix__
45                 || 1    // or if it's a unix platform
46 #endif
47                 )
48         {
49                 // This stuff below seems overly complicated - brad
50
51                 char *path = Args[t+1];
52                 char fullPath[PATH_MAX + 5];
53
54 #ifdef __unix__
55                 if (!t)
56                         path = "~/.d2x";
57 #endif
58                 PHYSFS_removeFromSearchPath(PHYSFS_getBaseDir());
59
60                 if (path[0] == '~') // yes, this tilde can be put before non-unix paths.
61                 {
62                         const char *home = PHYSFS_getUserDir();
63
64                         strcpy(fullPath, home); // prepend home to the path
65                         path++;
66                         if (*path == *PHYSFS_getDirSeparator())
67                                 path++;
68                         strncat(fullPath, path, PATH_MAX + 5 - strlen(home));
69                 }
70                 else
71                         strncpy(fullPath, path, PATH_MAX + 5);
72
73                 PHYSFS_setWriteDir(fullPath);
74                 if (!PHYSFS_getWriteDir())
75                 {                                               // need to make it
76                         char *p;
77                         char ancestor[PATH_MAX + 5];    // the directory which actually exists
78                         char child[PATH_MAX + 5];               // the directory relative to the above we're trying to make
79
80                         strcpy(ancestor, fullPath);
81                         while (!PHYSFS_getWriteDir() && ((p = strrchr(ancestor, *PHYSFS_getDirSeparator()))))
82                         {
83                                 if (p[1] == 0)
84                                 {                                       // separator at the end (intended here, for safety)
85                                         *p = 0;                 // kill this separator
86                                         if (!((p = strrchr(ancestor, *PHYSFS_getDirSeparator()))))
87                                                 break;          // give up, this is (usually) the root directory
88                                 }
89
90                                 p[1] = 0;                       // go to parent
91                                 PHYSFS_setWriteDir(ancestor);
92                         }
93
94                         strcpy(child, fullPath + strlen(ancestor));
95                         for (p = child; (p = strchr(p, *PHYSFS_getDirSeparator())); p++)
96                                 *p = '/';
97                         PHYSFS_mkdir(child);
98                         PHYSFS_setWriteDir(fullPath);
99                 }
100
101                 PHYSFS_addToSearchPath(PHYSFS_getWriteDir(), 1);
102                 AppendArgs();
103         }
104
105         if (!PHYSFS_getWriteDir())
106         {
107                 PHYSFS_setWriteDir(PHYSFS_getBaseDir());
108                 if (!PHYSFS_getWriteDir())
109                         Error("can't set write dir\n");
110                 else
111                         PHYSFS_addToSearchPath(PHYSFS_getWriteDir(), 0);
112         }
113
114         //tell cfile where hogdir is
115         if ((t=FindArg("-hogdir")))
116                 PHYSFS_addToSearchPath(Args[t + 1], 1);
117 #ifdef __unix__
118         else if (!FindArg("-nohogdir"))
119                 PHYSFS_addToSearchPath(SHAREPATH, 1);
120 #endif
121 }
122
123 static inline int PHYSFSX_readString(PHYSFS_file *file, char *s)
124 {
125         char *ptr = s;
126
127         if (PHYSFS_eof(file))
128                 *ptr = 0;
129         else
130                 do
131                         PHYSFS_read(file, ptr, 1, 1);
132                 while (!PHYSFS_eof(file) && *ptr++ != 0);
133
134         return strlen(s);
135 }
136
137 static inline int PHYSFSX_gets(PHYSFS_file *file, char *s)
138 {
139         char *ptr = s;
140
141         if (PHYSFS_eof(file))
142                 *ptr = 0;
143         else
144                 do
145                         PHYSFS_read(file, ptr, 1, 1);
146                 while (!PHYSFS_eof(file) && *ptr++ != '\n');
147
148         return strlen(s);
149 }
150
151 static inline int PHYSFSX_writeU8(PHYSFS_file *file, PHYSFS_uint8 val)
152 {
153         return PHYSFS_write(file, &val, 1, 1);
154 }
155
156 static inline int PHYSFSX_writeString(PHYSFS_file *file, char *s)
157 {
158         return PHYSFS_write(file, s, 1, strlen(s) + 1);
159 }
160
161 static inline int PHYSFSX_puts(PHYSFS_file *file, char *s)
162 {
163         return PHYSFS_write(file, s, 1, strlen(s));
164 }
165
166 static inline int PHYSFSX_putc(PHYSFS_file *file, int c)
167 {
168         unsigned char ch = (unsigned char)c;
169
170         if (PHYSFS_write(file, &ch, 1, 1) < 1)
171                 return -1;
172         else
173                 return (int)c;
174 }
175
176 static inline int PHYSFSX_printf(PHYSFS_file *file, char *format, ...)
177 {
178         char buffer[1024];
179         va_list args;
180
181         va_start(args, format);
182         vsprintf(buffer, format, args);
183
184         return PHYSFSX_puts(file, buffer);
185 }
186
187 #define PHYSFSX_writeFix        PHYSFS_writeSLE32
188 #define PHYSFSX_writeFixAng     PHYSFS_writeSLE16
189
190 static inline int PHYSFSX_writeVector(PHYSFS_file *file, vms_vector *v)
191 {
192         if (PHYSFSX_writeFix(file, v->x) < 1 ||
193          PHYSFSX_writeFix(file, v->y) < 1 ||
194          PHYSFSX_writeFix(file, v->z) < 1)
195                 return 0;
196
197         return 1;
198 }
199
200 static inline int PHYSFSX_writeAngleVec(PHYSFS_file *file, vms_angvec *v)
201 {
202         if (PHYSFSX_writeFixAng(file, v->p) < 1 ||
203          PHYSFSX_writeFixAng(file, v->b) < 1 ||
204          PHYSFSX_writeFixAng(file, v->h) < 1)
205                 return 0;
206
207         return 1;
208 }
209
210 static inline int PHYSFSX_writeMatrix(PHYSFS_file *file, vms_matrix *m)
211 {
212         if (PHYSFSX_writeVector(file, &m->rvec) < 1 ||
213          PHYSFSX_writeVector(file, &m->uvec) < 1 ||
214          PHYSFSX_writeVector(file, &m->fvec) < 1)
215                 return 0;
216
217         return 1;
218 }
219
220 static inline int PHYSFSX_getRealPath(const char *stdPath, char *realPath)
221 {
222         const char *realDir = PHYSFS_getRealDir(stdPath);
223         const char *sep = PHYSFS_getDirSeparator();
224         char *p;
225
226         if (!realDir)
227         {
228                 realDir = PHYSFS_getWriteDir();
229                 if (!realDir)
230                         return 0;
231         }
232
233         strncpy(realPath, realDir, PATH_MAX - 1);
234         if (strlen(realPath) >= strlen(sep))
235         {
236                 p = realPath + strlen(realPath) - strlen(sep);
237                 if (strcmp(p, sep)) // no sep at end of realPath
238                         strncat(realPath, sep, PATH_MAX - 1 - strlen(realPath));
239         }
240
241         if (strlen(stdPath) >= 1)
242                 if (*stdPath == '/')
243                         stdPath++;
244
245         while (*stdPath)
246         {
247                 if (*stdPath == '/')
248                         strncat(realPath, sep, PATH_MAX - 1 - strlen(realPath));
249                 else
250                 {
251                         if (strlen(realPath) < PATH_MAX - 2)
252                         {
253                                 p = realPath + strlen(realPath);
254                                 p[0] = *stdPath;
255                                 p[1] = '\0';
256                         }
257                 }
258                 stdPath++;
259         }
260
261         return 1;
262 }
263
264 static inline int PHYSFSX_rename(char *oldpath, char *newpath)
265 {
266         char old[PATH_MAX], new[PATH_MAX];
267
268         PHYSFSX_getRealPath(oldpath, old);
269         PHYSFSX_getRealPath(newpath, new);
270         return (rename(old, new) == 0);
271 }
272
273
274 // returns -1 if error
275 // Gets bytes free in current write dir
276 static inline PHYSFS_sint64 PHYSFSX_getFreeDiskSpace()
277 {
278 #if defined(__linux__) || (defined(__MACH__) && defined(__APPLE__))
279         struct statfs sfs;
280
281         if (!statfs(PHYSFS_getWriteDir(), &sfs))
282                 return (PHYSFS_sint64)(sfs.f_bavail * sfs.f_bsize);
283
284         return -1;
285 #else
286         return 0x7FFFFFFF;
287 #endif
288 }
289
290 //Open a file for reading, set up a buffer
291 static inline PHYSFS_file *PHYSFSX_openReadBuffered(char *filename)
292 {
293         PHYSFS_file *fp;
294         PHYSFS_uint64 bufSize;
295
296         if (filename[0] == '\x01')
297         {
298                 //FIXME: don't look in dir, only in hogfile
299                 filename++;
300         }
301
302         fp = PHYSFS_openRead(filename);
303         if (!fp)
304                 return NULL;
305
306         bufSize = PHYSFS_fileLength(fp);
307         while (!PHYSFS_setBuffer(fp, bufSize) && bufSize)
308                 bufSize /= 2;   // even if the error isn't memory full, for a 20MB file it'll only do this 8 times
309
310         return fp;
311 }
312
313 //Open a file for writing, set up a buffer
314 static inline PHYSFS_file *PHYSFSX_openWriteBuffered(char *filename)
315 {
316         PHYSFS_file *fp;
317         PHYSFS_uint64 bufSize = 1024*1024;      // hmm, seems like an OK size.
318
319         fp = PHYSFS_openWrite(filename);
320         if (!fp)
321                 return NULL;
322
323         while (!PHYSFS_setBuffer(fp, bufSize) && bufSize)
324                 bufSize /= 2;
325
326         return fp;
327 }
328
329 #endif /* PHYSFSX_H */