added CVAR_SAVE and CVAR_NOTIFY flags to cvar_t structure (at the beginning), updated...
[divverent/darkplaces.git] / quakeio.c
1 /*
2         quakeio.c
3
4         (description)
5
6         Copyright (C) 1996-1997  Id Software, Inc.
7         Copyright (C) 1999,2000  contributors of the QuakeForge project
8         Please see the file "AUTHORS" for a list of contributors
9
10         This program is free software; you can redistribute it and/or
11         modify it under the terms of the GNU General Public License
12         as published by the Free Software Foundation; either version 2
13         of the License, or (at your option) any later version.
14
15         This program is distributed in the hope that it will be useful,
16         but WITHOUT ANY WARRANTY; without even the implied warranty of
17         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
19         See the GNU General Public License for more details.
20
21         You should have received a copy of the GNU General Public License
22         along with this program; if not, write to:
23
24                 Free Software Foundation, Inc.
25                 59 Temple Place - Suite 330
26                 Boston, MA  02111-1307, USA
27
28         $Id$
29 */
30
31 #include "quakedef.h"
32 #include <stdlib.h>
33 #include <string.h>
34 #ifdef WIN32
35 # include <io.h>
36 # include <fcntl.h>
37 #else
38 # include <pwd.h>
39 # include <unistd.h>
40 #endif
41
42 //#ifdef _MSC_VER
43 //# define _POSIX_
44 //#endif
45
46 #include <stdarg.h>
47 #include <stdlib.h>
48 #include <limits.h>
49
50 #ifndef PATH_MAX
51 # define PATH_MAX 512
52 #endif
53
54 #include "quakeio.h"
55
56 #ifdef WIN32
57 # ifndef __BORLANDC__
58 #  define setmode _setmode
59 #  define O_BINARY _O_BINARY
60 # endif
61 #endif
62
63 void
64 Qexpand_squiggle (const char *path, char *dest)
65 {
66         char       *home;
67
68 #ifndef _WIN32
69         struct passwd *pwd_ent;
70 #endif
71
72         if (strncmp (path, "~/", 2) != 0) {
73                 strcpy (dest, path);
74                 return;
75         }
76
77 #ifdef _WIN32
78         // LordHavoc: first check HOME to duplicate previous version behavior
79         // (also handy if someone wants it somewhere other than their
80         //  windows directory)
81         home = getenv ("HOME");
82         if (!home || !home[0])
83                 home = getenv ("WINDIR");
84 #else
85         if ((pwd_ent = getpwuid (getuid ()))) {
86                 home = pwd_ent->pw_dir;
87         } else
88                 home = getenv ("HOME");
89 #endif
90
91         if (home) {
92                 strcpy (dest, home);
93                 strncat (dest, path + 1, MAX_OSPATH - strlen (dest));   // skip
94                                                                                                                                 // leading ~
95         } else
96                 strcpy (dest, path);
97 }
98
99 int
100 Qrename (const char *old, const char *new)
101 {
102         char        e_old[PATH_MAX];
103         char        e_new[PATH_MAX];
104
105         Qexpand_squiggle (old, e_old);
106         Qexpand_squiggle (new, e_new);
107         return rename (e_old, e_new);
108 }
109
110 QFile *
111 Qopen (const char *path, const char *mode)
112 {
113         QFile      *file;
114         char        m[80], *p;
115         int         zip = 0;
116         char        e_path[PATH_MAX];
117
118         Qexpand_squiggle (path, e_path);
119         path = e_path;
120
121         for (p = m; *mode && p - m < (sizeof (m) - 1); mode++) {
122                 if (*mode == 'z') {
123                         zip = 1;
124                         continue;
125                 }
126 #ifndef HAVE_ZLIB
127                 if (strchr ("0123456789fh", *mode)) {
128                         continue;
129                 }
130 #endif
131                 *p++ = *mode;
132         }
133         *p = 0;
134
135         file = qmalloc (sizeof (*file));
136         memset(file, 0, sizeof(*file));
137         if (!file)
138                 return 0;
139 #ifdef HAVE_ZLIB
140         if (zip) {
141                 file->gzfile = gzopen (path, m);
142                 if (!file->gzfile) {
143                         qfree (file);
144                         return 0;
145                 }
146         } else
147 #endif
148         {
149                 file->file = fopen (path, m);
150                 if (!file->file) {
151                         qfree (file);
152                         return 0;
153                 }
154         }
155         return file;
156 }
157
158 QFile *
159 Qdopen (int fd, const char *mode)
160 {
161         QFile      *file;
162         char        m[80], *p;
163         int         zip = 0;
164
165         for (p = m; *mode && p - m < (sizeof (m) - 1); mode++) {
166                 if (*mode == 'z') {
167                         zip = 1;
168                         continue;
169                 }
170                 *p++ = *mode;
171         }
172
173         *p = 0;
174
175         file = qmalloc (sizeof (*file));
176         memset(file, 0, sizeof(*file));
177         if (!file)
178                 return 0;
179 #ifdef HAVE_ZLIB
180         if (zip) {
181                 file->gzfile = gzdopen (fd, m);
182                 if (!file->gzfile) {
183                         qfree (file);
184                         return 0;
185                 }
186         } else
187 #endif
188         {
189                 file->file = fdopen (fd, m);
190                 if (!file->file) {
191                         qfree (file);
192                         return 0;
193                 }
194         }
195 #ifdef WIN32
196         if (file->file)
197                 setmode (_fileno (file->file), O_BINARY);
198 #endif
199         return file;
200 }
201
202 void
203 Qclose (QFile *file)
204 {
205         if (file->file)
206                 fclose (file->file);
207 #ifdef HAVE_ZLIB
208         else
209                 gzclose (file->gzfile);
210 #endif
211         qfree (file);
212 }
213
214 int
215 Qread (QFile *file, void *buf, int count)
216 {
217         if (file->file)
218                 return fread (buf, 1, count, file->file);
219 #ifdef HAVE_ZLIB
220         else
221                 return gzread (file->gzfile, buf, count);
222 #else
223         return -1;
224 #endif
225 }
226
227 int
228 Qwrite (QFile *file, void *buf, int count)
229 {
230         if (file->file)
231                 return fwrite (buf, 1, count, file->file);
232 #ifdef HAVE_ZLIB
233         else
234                 return gzwrite (file->gzfile, buf, count);
235 #else
236         return -1;
237 #endif
238 }
239
240 int
241 Qprintf (QFile *file, const char *fmt, ...)
242 {
243         va_list     args;
244         int         ret = -1;
245
246         va_start (args, fmt);
247         if (file->file)
248                 ret = vfprintf (file->file, fmt, args);
249 #ifdef HAVE_ZLIB
250         else {
251                 char        buf[4096];
252
253                 va_start (args, fmt);
254 #ifdef HAVE_VSNPRINTF
255                 (void) vsnprintf (buf, sizeof (buf), fmt, args);
256 #else
257                 (void) vsprintf (buf, fmt, args);
258 #endif
259                 va_end (args);
260                 ret = strlen (buf);                             /* some *snprintf don't return the nb 
261                                                                                    of bytes written */
262                 if (ret > 0)
263                         ret = gzwrite (file->gzfile, buf, (unsigned) ret);
264         }
265 #endif
266         va_end (args);
267         return ret;
268 }
269
270 char *
271 Qgets (QFile *file, char *buf, int count)
272 {
273         if (file->file)
274                 return fgets (buf, count, file->file);
275 #ifdef HAVE_ZLIB
276         else
277                 return gzgets (file->gzfile, buf, count);
278 #else
279         return 0;
280 #endif
281 }
282
283 int
284 Qgetc (QFile *file)
285 {
286         if (file->file)
287                 return fgetc (file->file);
288 #ifdef HAVE_ZLIB
289         else
290                 return gzgetc (file->gzfile);
291 #else
292         return -1;
293 #endif
294 }
295
296 int
297 Qputc (QFile *file, int c)
298 {
299         if (file->file)
300                 return fputc (c, file->file);
301 #ifdef HAVE_ZLIB
302         else
303                 return gzputc (file->gzfile, c);
304 #else
305         return -1;
306 #endif
307 }
308
309 int
310 Qseek (QFile *file, long offset, int whence)
311 {
312         if (file->file)
313                 return fseek (file->file, offset, whence);
314 #ifdef HAVE_ZLIB
315         else
316                 return gzseek (file->gzfile, offset, whence);
317 #else
318         return -1;
319 #endif
320 }
321
322 long
323 Qtell (QFile *file)
324 {
325         if (file->file)
326                 return ftell (file->file);
327 #ifdef HAVE_ZLIB
328         else
329                 return gztell (file->gzfile);
330 #else
331         return -1;
332 #endif
333 }
334
335 int
336 Qflush (QFile *file)
337 {
338         if (file->file)
339                 return fflush (file->file);
340 #ifdef HAVE_ZLIB
341         else
342                 return gzflush (file->gzfile, Z_SYNC_FLUSH);
343 #else
344         return -1;
345 #endif
346 }
347
348 int
349 Qeof (QFile *file)
350 {
351         if (file->file)
352                 return feof (file->file);
353 #ifdef HAVE_ZLIB
354         else
355                 return gzeof (file->gzfile);
356 #else
357         return -1;
358 #endif
359 }
360
361 /*
362
363         Qgetline
364
365         Dynamic length version of Qgets. DO NOT free the buffer.
366
367 */
368 char *
369 Qgetline (QFile *file)
370 {
371         static int  size = 256;
372         static char *buf = 0;
373         int         len;
374
375         if (!buf)
376                 buf = malloc (size);
377
378         if (!Qgets (file, buf, size))
379                 return 0;
380
381         len = strlen (buf);
382         while (buf[len - 1] != '\n' && buf[len - 1] != '\r') {
383                 char       *t = realloc (buf, size + 256);
384
385                 if (!t)
386                         Host_Error("Qgetline: realloc failed, out of memory?\n");
387                 buf = t;
388                 size += 256;
389                 if (!Qgets (file, buf + len, size - len))
390                         break;
391                 len = strlen (buf);
392         }
393         while ((len = strlen(buf)) && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
394                 buf[len - 1] = 0;
395         return buf;
396 }