1 /*
2 sys.c
3
4 virtual filesystem functions
5
6 Copyright (C) 1996-1997 Id Software, Inc.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17 See the GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to:
21
22 Free Software Foundation, Inc.
23 59 Temple Place - Suite 330
24 Boston, MA 02111-1307, USA
25
26 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_STRING_H
32 # include <string.h>
33 #endif
34 #ifdef HAVE_STRINGS_H
35 # include <strings.h>
36 #endif
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40 #ifdef HAVE_LIMITS_H
41 # include <limits.h>
42 #endif
43 #ifdef HAVE_CONIO_H
44 # include <conio.h>
45 #endif
46 #ifdef HAVE_IO_H
47 # include <io.h>
48 #endif
49 #ifdef HAVE_WINDOWS_H
50 # include "winquake.h"
51 # include "shlobj.h"
52 #endif
53 #ifdef HAVE_SYS_MMAN_H
54 # include <sys/mman.h>
55 #endif
56 #ifdef HAVE_SYS_SELECT_H
57 # include <sys/select.h>
58 #endif
59 #ifdef HAVE_PWD_H
60 # include <pwd.h>
61 #endif
62
63 #include <signal.h>
64 #include <setjmp.h>
65 #include <errno.h>
66 #include <fcntl.h>
67 #include <stdarg.h>
68 #include <time.h>
69 #include <sys/stat.h>
70 #ifdef HAVE_SYS_TIME_H
71 #include <sys/time.h>
72 #endif
73 #include <sys/types.h>
74
75 #ifdef HAVE_DIRECT_H
76 #include <direct.h>
77 #endif
78
79 #include "qfalloca.h"
80
81 #include "QF/cmd.h"
82 #include "QF/cvar.h"
83 #include "QF/dstring.h"
84 #include "QF/mathlib.h"
85 #include "QF/sys.h"
86 #include "QF/quakefs.h"
87 #include "QF/va.h"
88
89 #include "compat.h"
90
91 static void Sys_StdPrintf (const char *fmt, va_list args);
92 static void Sys_ErrPrintf (const char *fmt, va_list args);
93
94 VISIBLE cvar_t *sys_nostdout;
95 VISIBLE cvar_t *sys_extrasleep;
96 cvar_t *sys_dead_sleep;
97 cvar_t *sys_sleep;
98
99 int sys_checksum;
100
101 static sys_printf_t sys_std_printf_function = Sys_StdPrintf;
102 static sys_printf_t sys_err_printf_function = Sys_ErrPrintf;
103
104 typedef struct shutdown_list_s {
105 struct shutdown_list_s *next;
106 void (*func)(void);
107 } shutdown_list_t;
108
109 static shutdown_list_t *shutdown_list;
110
111 #ifndef _WIN32
112 static int do_stdin = 1;
113 qboolean stdin_ready;
114 #endif
115
116 /* The translation table between the graphical font and plain ASCII --KB */
117 VISIBLE const char sys_char_map[256] = {
118 '\0', '#', '#', '#', '#', '.', '#', '#',
119 '#', 9, 10, '#', ' ', 13, '.', '.',
120 '[', ']', '0', '1', '2', '3', '4', '5',
121 '6', '7', '8', '9', '.', '<', '=', '>',
122 ' ', '!', '"', '#', '$', '%', '&', '\'',
123 '(', ')', '*', '+', ',', '-', '.', '/',
124 '0', '1', '2', '3', '4', '5', '6', '7',
125 '8', '9', ':', ';', '<', '=', '>', '?',
126 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
127 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
128 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
129 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
130 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
131 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
132 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
133 'x', 'y', 'z', '{', '|', '}', '~', '<',
134
135 '<', '=', '>', '#', '#', '.', '#', '#',
136 '#', '#', ' ', '#', ' ', '>', '.', '.',
137 '[', ']', '0', '1', '2', '3', '4', '5',
138 '6', '7', '8', '9', '.', '<', '=', '>',
139 ' ', '!', '"', '#', '$', '%', '&', '\'',
140 '(', ')', '*', '+', ',', '-', '.', '/',
141 '0', '1', '2', '3', '4', '5', '6', '7',
142 '8', '9', ':', ';', '<', '=', '>', '?',
143 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
144 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
145 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
146 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
147 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
148 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
149 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
150 'x', 'y', 'z', '{', '|', '}', '~', '<'
151 };
152
153 #define MAXPRINTMSG 4096
154
155
156 #ifndef USE_INTEL_ASM
157 void
Sys_MaskFPUExceptions(void)158 Sys_MaskFPUExceptions (void)
159 {
160 }
161 #endif
162
163 int
Sys_mkdir(const char * path)164 Sys_mkdir (const char *path)
165 {
166 #ifdef HAVE_MKDIR
167 # ifdef _WIN32
168 if (mkdir (path) == 0)
169 return 0;
170 # else
171 if (mkdir (path, 0777) == 0)
172 return 0;
173 # endif
174 #else
175 # ifdef HAVE__MKDIR
176 if (_mkdir (path) == 0)
177 return 0;
178 # else
179 # error do not know how to make directories
180 # endif
181 #endif
182 if (errno != EEXIST)
183 return -1;
184 return 0;
185 }
186
187 VISIBLE int
Sys_FileTime(const char * path)188 Sys_FileTime (const char *path)
189 {
190 #ifdef HAVE_ACCESS
191 if (access (path, R_OK) == 0)
192 return 0;
193 #else
194 # ifdef HAVE__ACCESS
195 if (_access (path, R_OK) == 0)
196 return 0;
197 # else
198 int fd;
199
200 if ((fd = open (path, O_RDONLY)) >= 0) {
201 close (fd);
202 return 0;
203 }
204 # endif
205 #endif
206 return -1;
207 }
208
209 /*
210 Sys_SetPrintf
211
212 for want of a better name, but it sets the function pointer for the
213 actual implementation of Sys_Printf.
214 */
215 VISIBLE void
Sys_SetStdPrintf(sys_printf_t func)216 Sys_SetStdPrintf (sys_printf_t func)
217 {
218 sys_std_printf_function = func;
219 }
220
221 VISIBLE void
Sys_SetErrPrintf(sys_printf_t func)222 Sys_SetErrPrintf (sys_printf_t func)
223 {
224 sys_err_printf_function = func;
225 }
226
227 void
Sys_Print(FILE * stream,const char * fmt,va_list args)228 Sys_Print (FILE *stream, const char *fmt, va_list args)
229 {
230 static dstring_t *msg;
231 unsigned char *p;
232
233 if (!msg)
234 msg = dstring_new ();
235
236 dvsprintf (msg, fmt, args);
237
238 if (stream == stderr) {
239 #ifdef _WIN32
240 MessageBox (NULL, msg->str, "Fatal Error", 0 /* MB_OK */ );
241 #endif
242 fputs ("Fatal Error: ", stream);
243 }
244
245 /* translate to ASCII instead of printing [xx] --KB */
246 for (p = (unsigned char *) msg->str; *p; p++)
247 putc (sys_char_map[*p], stream);
248
249 if (stream == stderr) {
250 fputs ("\n", stream);
251 }
252 fflush (stream);
253 }
254
255 static void
Sys_StdPrintf(const char * fmt,va_list args)256 Sys_StdPrintf (const char *fmt, va_list args)
257 {
258 if (sys_nostdout && sys_nostdout->int_val)
259 return;
260 Sys_Print (stdout, fmt, args);
261 }
262
263 static void
Sys_ErrPrintf(const char * fmt,va_list args)264 Sys_ErrPrintf (const char *fmt, va_list args)
265 {
266 Sys_Print (stderr, fmt, args);
267 }
268
269 VISIBLE void
Sys_Printf(const char * fmt,...)270 Sys_Printf (const char *fmt, ...)
271 {
272 va_list args;
273 va_start (args, fmt);
274 sys_std_printf_function (fmt, args);
275 va_end (args);
276 }
277
278 VISIBLE void
Sys_MaskPrintf(int mask,const char * fmt,...)279 Sys_MaskPrintf (int mask, const char *fmt, ...)
280 {
281 va_list args;
282
283 if (!developer || !(developer->int_val & mask))
284 return;
285 va_start (args, fmt);
286 sys_std_printf_function (fmt, args);
287 va_end (args);
288 }
289
290 VISIBLE double
Sys_DoubleTime(void)291 Sys_DoubleTime (void)
292 {
293 static qboolean first = true;
294 #ifdef _WIN32
295 # if 0
296 static DWORD starttime;
297 DWORD now;
298
299 now = timeGetTime ();
300
301 if (first) {
302 first = false;
303 starttime = now;
304 return 0.0;
305 }
306
307 if (now < starttime) // wrapped?
308 return (now / 1000.0) + (LONG_MAX - starttime / 1000.0);
309
310 if (now - starttime == 0)
311 return 0.0;
312
313 return (now - starttime) / 1000.0;
314 # else
315 // MH's solution combining timeGetTime for stability and
316 // QueryPerformanceCounter for precision.
317 static __int64 qpcfreq = 0;
318 static __int64 currqpccount = 0;
319 static __int64 lastqpccount = 0;
320 static double qpcfudge = 0;
321 DWORD currtime = 0;
322 static DWORD lasttime = 0;
323 static DWORD starttime = 0;
324
325 if (first) {
326 timeBeginPeriod (1);
327 starttime = lasttime = timeGetTime ();
328 QueryPerformanceFrequency ((LARGE_INTEGER *) &qpcfreq);
329 QueryPerformanceCounter ((LARGE_INTEGER *) &lastqpccount);
330 first = false;
331 return 0;
332 }
333
334 // get the current time from both counters
335 currtime = timeGetTime ();
336 QueryPerformanceCounter ((LARGE_INTEGER *) &currqpccount);
337
338 if (currtime != lasttime) {
339 // requery the frequency in case it changes (which it can on multicore
340 // machines)
341 QueryPerformanceFrequency ((LARGE_INTEGER *) &qpcfreq);
342
343 // store back times and calc a fudge factor as timeGetTime can
344 // overshoot on a sub-millisecond scale
345 qpcfudge = (((double) (currqpccount - lastqpccount)
346 / (double) qpcfreq))
347 - ((double) (currtime - lasttime) * 0.001);
348 lastqpccount = currqpccount;
349 lasttime = currtime;
350 } else {
351 qpcfudge = 0;
352 }
353
354 // the final time is the base from timeGetTime plus an addition from QPC
355 return ((double) (currtime - starttime) * 0.001)
356 + ((double) (currqpccount - lastqpccount) / (double) qpcfreq)
357 + qpcfudge;
358 # endif
359 #else
360 struct timeval tp;
361 struct timezone tzp;
362 double now;
363 static double start_time;
364
365 gettimeofday (&tp, &tzp);
366
367 now = tp.tv_sec + tp.tv_usec / 1e6;
368
369 if (first) {
370 first = false;
371 start_time = now;
372 }
373
374 return now - start_time;
375 #endif
376 }
377
378 VISIBLE void
Sys_TimeOfDay(date_t * date)379 Sys_TimeOfDay (date_t *date)
380 {
381 struct tm *newtime;
382 time_t long_time;
383
384 time (&long_time);
385 newtime = localtime (&long_time);
386
387 date->day = newtime->tm_mday;
388 date->mon = newtime->tm_mon;
389 date->year = newtime->tm_year + 1900;
390 date->hour = newtime->tm_hour;
391 date->min = newtime->tm_min;
392 date->sec = newtime->tm_sec;
393 strftime (date->str, 128, "%a %b %d, %H:%M %Y", newtime);
394 }
395
396 VISIBLE void
Sys_MakeCodeWriteable(uintptr_t startaddr,size_t length)397 Sys_MakeCodeWriteable (uintptr_t startaddr, size_t length)
398 {
399 #ifdef _WIN32
400 DWORD flOldProtect;
401
402 if (!VirtualProtect
403 ((LPVOID) startaddr, length, PAGE_READWRITE, &flOldProtect))
404 Sys_Error ("Protection change failed");
405 #else
406 # ifdef HAVE_MPROTECT
407 int r;
408 unsigned long endaddr = startaddr + length;
409 # ifdef HAVE__SC_PAGESIZE
410 long psize = sysconf (_SC_PAGESIZE);
411
412 startaddr &= ~(psize - 1);
413 endaddr = (endaddr + psize - 1) & ~(psize -1);
414 # else
415 # ifdef HAVE_GETPAGESIZE
416 int psize = getpagesize ();
417
418 startaddr &= ~(psize - 1);
419 endaddr = (endaddr + psize - 1) & ~(psize - 1);
420 # endif
421 # endif
422 // systems with mprotect but not getpagesize (or similar) probably don't
423 // need to page align the arguments to mprotect (eg, QNX)
424 r = mprotect ((char *) startaddr, endaddr - startaddr,
425 PROT_EXEC | PROT_READ | PROT_WRITE);
426
427 if (r < 0)
428 Sys_Error ("Protection change failed");
429 # endif
430 #endif
431 }
432
433 VISIBLE void
Sys_Init_Cvars(void)434 Sys_Init_Cvars (void)
435 {
436 sys_nostdout = Cvar_Get ("sys_nostdout", "0", CVAR_NONE, NULL,
437 "Set to disable std out");
438 sys_extrasleep = Cvar_Get ("sys_extrasleep", "0", CVAR_NONE, NULL,
439 "Set to cause whatever amount delay in "
440 "microseconds you want. Mostly "
441 "useful to generate simulated bad "
442 "connections.");
443 sys_dead_sleep = Cvar_Get ("sys_dead_sleep", "0", CVAR_NONE, NULL,
444 "When set, the server gets NO cpu if no "
445 "clients are connected and there's no other "
446 "activity. *MIGHT* cause problems with some "
447 "mods.");
448 sys_sleep = Cvar_Get ("sys_sleep", "8", CVAR_NONE, NULL, "Sleep how long "
449 "in seconds between checking for connections. "
450 "Minimum is 0, maximum is 13");
451 }
452
453 void
Sys_Shutdown(void)454 Sys_Shutdown (void)
455 {
456 shutdown_list_t *t;
457
458 while (shutdown_list) {
459 shutdown_list->func ();
460 t = shutdown_list;
461 shutdown_list = shutdown_list->next;
462 free (t);
463 }
464 }
465
466 VISIBLE void
Sys_Quit(void)467 Sys_Quit (void)
468 {
469 Sys_Shutdown ();
470
471 exit (0);
472 }
473
474 #if defined (HAVE_VA_COPY)
475 # define VA_COPY(a,b) va_copy (a, b)
476 #elif defined (HAVE__VA_COPY)
477 # define VA_COPY(a,b) __va_copy (a, b)
478 #else
479 # define VA_COPY(a,b) memcpy (a, b, sizeof (a))
480 #endif
481
482 VISIBLE void
Sys_Error(const char * error,...)483 Sys_Error (const char *error, ...)
484 {
485 va_list args;
486 #ifdef VA_LIST_IS_ARRAY
487 va_list tmp_args;
488 #endif
489 static int in_sys_error = 0;
490
491 if (in_sys_error) {
492 ssize_t cnt;
493 const char *msg = "\nSys_Error: recursive error condition\n";
494 cnt = write (2, msg, strlen (msg));
495 if (cnt < 0)
496 perror ("write failed");
497 abort ();
498 }
499 in_sys_error = 1;
500
501 va_start (args, error);
502 #ifdef VA_LIST_IS_ARRAY
503 VA_COPY (tmp_args, args);
504 #endif
505 sys_err_printf_function (error, args);
506 va_end (args);
507
508 Sys_Shutdown ();
509
510 if (sys_err_printf_function != Sys_ErrPrintf) {
511 // print the message again using the default error printer to increase
512 // the chances of the error being seen.
513 #ifdef VA_LIST_IS_ARRAY
514 VA_COPY (args, tmp_args);
515 #endif
516 Sys_ErrPrintf (error, args);
517 }
518
519 exit (1);
520 }
521
522 VISIBLE void
Sys_RegisterShutdown(void (* func)(void))523 Sys_RegisterShutdown (void (*func) (void))
524 {
525 shutdown_list_t *p;
526 if (!func)
527 return;
528 p = malloc (sizeof (*p));
529 if (!p)
530 Sys_Error ("Sys_RegisterShutdown: insufficient memory");
531 p->func = func;
532 p->next = shutdown_list;
533 shutdown_list = p;
534 }
535
536 VISIBLE int
Sys_TimeID(void)537 Sys_TimeID (void) //FIXME I need a new name, one that doesn't make me feel 3 feet thick
538 {
539 int val;
540 #ifdef HAVE_GETUID
541 val = ((int) (getpid () + getuid () * 1000) * time (NULL)) & 0xffff;
542 #else
543 val = ((int) (Sys_DoubleTime () * 1000) * time (NULL)) & 0xffff;
544 #endif
545 return val;
546 }
547
548 VISIBLE void
Sys_PageIn(void * ptr,int size)549 Sys_PageIn (void *ptr, int size)
550 {
551 //may or may not be useful in linux #ifdef _WIN32
552 byte *x;
553 int m, n;
554
555 // touch all the memory to make sure it's there. The 16-page skip is to
556 // keep Win 95 from thinking we're trying to page ourselves in (we are
557 // doing that, of course, but there's no reason we shouldn't)
558 x = (byte *) ptr;
559
560 for (n = 0; n < 4; n++) {
561 for (m = 0; m < (size - 16 * 0x1000); m += 4) {
562 sys_checksum += *(int *) &x[m];
563 sys_checksum += *(int *) &x[m + 16 * 0x1000];
564 }
565 }
566 //#endif
567 }
568
569 VISIBLE void
Sys_DebugLog(const char * file,const char * fmt,...)570 Sys_DebugLog (const char *file, const char *fmt, ...)
571 {
572 va_list args;
573 static dstring_t *data;
574 int fd;
575
576 if (!data)
577 data = dstring_newstr ();
578
579 va_start (args, fmt);
580 dvsprintf (data, fmt, args);
581 va_end (args);
582 if ((fd = open (file, O_WRONLY | O_CREAT | O_APPEND, 0644)) >= 0) {
583 if (write (fd, data->str, data->size - 1) != (ssize_t) (data->size - 1))
584 Sys_Printf ("Error writing %s: %s\n", file, strerror(errno));
585 close (fd);
586 }
587 }
588
589 VISIBLE int
Sys_CheckInput(int idle,int net_socket)590 Sys_CheckInput (int idle, int net_socket)
591 {
592 fd_set fdset;
593 int res;
594 struct timeval _timeout;
595 struct timeval *timeout = 0;
596
597 #ifdef _WIN32
598 int sleep_msec;
599 // Now we want to give some processing time to other applications,
600 // such as qw_client, running on this machine.
601 sleep_msec = sys_sleep->int_val;
602 if (sleep_msec > 0) {
603 if (sleep_msec > 13)
604 sleep_msec = 13;
605 Sleep (sleep_msec);
606 }
607
608 _timeout.tv_sec = 0;
609 _timeout.tv_usec = net_socket < 0 ? 0 : 20;
610 #else
611 _timeout.tv_sec = 0;
612 _timeout.tv_usec = net_socket < 0 ? 0 : 2000;
613 #endif
614 // select on the net socket and stdin
615 // the only reason we have a timeout at all is so that if the last
616 // connected client times out, the message would not otherwise
617 // be printed until the next event.
618 FD_ZERO (&fdset);
619 #ifndef _WIN32
620 if (do_stdin)
621 FD_SET (0, &fdset);
622 #endif
623 if (net_socket >= 0)
624 FD_SET (((unsigned) net_socket), &fdset); // cast needed for windows
625
626 if (!idle || !sys_dead_sleep->int_val)
627 timeout = &_timeout;
628
629 res = select (max (net_socket, 0) + 1, &fdset, NULL, NULL, timeout);
630 if (res == 0 || res == -1)
631 return 0;
632 #ifndef _WIN32
633 stdin_ready = FD_ISSET (0, &fdset);
634 #endif
635 return 1;
636 }
637
638 /*
639 Sys_ConsoleInput
640
641 Checks for a complete line of text typed in at the console, then forwards
642 it to the host command processor
643 */
644 VISIBLE const char *
Sys_ConsoleInput(void)645 Sys_ConsoleInput (void)
646 {
647 static char text[256];
648 static int len = 0;
649
650 #ifdef _WIN32
651 int c;
652
653 // read a line out
654 while (_kbhit ()) {
655 c = _getch ();
656 putch (c);
657 if (c == '\r') {
658 text[len] = 0;
659 putch ('\n');
660 len = 0;
661 return text;
662 }
663 if (c == 8) {
664 if (len) {
665 putch (' ');
666 putch (c);
667 len--;
668 text[len] = 0;
669 }
670 continue;
671 }
672 text[len] = c;
673 len++;
674 if (len < (int) sizeof (text))
675 text[len] = 0;
676 else {
677 // buffer is full
678 len = 0;
679 text[sizeof (text) - 1] = 0;
680 return text;
681 }
682 }
683
684 return NULL;
685 #else
686 if (!stdin_ready || !do_stdin)
687 return NULL; // the select didn't say it was ready
688 stdin_ready = false;
689
690 len = read (0, text, sizeof (text));
691 if (len == 0) {
692 // end of file
693 do_stdin = 0;
694 return NULL;
695 }
696 if (len < 1)
697 return NULL;
698 text[len - 1] = 0; // rip off the \n and terminate
699
700 return text;
701 #endif
702 }
703
704 static jmp_buf aiee_abort;
705
706 typedef struct sh_stack_s {
707 struct sh_stack_s *next;
708 int (*signal_hook)(int,void*);
709 void *data;
710 } sh_stack_t;
711
712 static sh_stack_t *sh_stack;
713 static sh_stack_t *free_sh;
714 static int (*signal_hook)(int,void*);
715 static void *signal_hook_data;
716
717 VISIBLE void
Sys_PushSignalHook(int (* hook)(int,void *),void * data)718 Sys_PushSignalHook (int (*hook)(int, void *), void *data)
719 {
720 sh_stack_t *s;
721
722 if (free_sh) {
723 s = free_sh;
724 } else {
725 s = malloc (sizeof (sh_stack_t));
726 s->next = 0;
727 }
728 s->signal_hook = signal_hook;
729 s->data = signal_hook_data;
730 signal_hook = hook;
731 signal_hook_data = data;
732
733 free_sh = s->next;
734 s->next = sh_stack;
735 sh_stack = s;
736 }
737
738 VISIBLE void
Sys_PopSignalHook(void)739 Sys_PopSignalHook (void)
740 {
741 if (sh_stack) {
742 sh_stack_t *s;
743
744 signal_hook = sh_stack->signal_hook;
745 signal_hook_data = sh_stack->data;
746
747 s = sh_stack->next;
748 sh_stack->next = free_sh;
749 free_sh = sh_stack;
750 sh_stack = s;
751 }
752 }
753
754 static void
aiee(int sig)755 aiee (int sig)
756 {
757 printf ("AIEE, signal %d in shutdown code, giving up\n", sig);
758 longjmp (aiee_abort, 1);
759 }
760
761 static void
signal_handler(int sig)762 signal_handler (int sig)
763 {
764 int volatile recover = 0; // volatile for longjump
765
766 printf ("Received signal %d, exiting...\n", sig);
767
768 switch (sig) {
769 case SIGINT:
770 case SIGTERM:
771 #ifndef _WIN32
772 case SIGHUP:
773 signal (SIGHUP, SIG_DFL);
774 #endif
775 signal (SIGINT, SIG_DFL);
776 signal (SIGTERM, SIG_DFL);
777 Sys_Quit ();
778 default:
779 #ifndef _WIN32
780 signal (SIGQUIT, aiee);
781 signal (SIGTRAP, aiee);
782 signal (SIGIOT, aiee);
783 signal (SIGBUS, aiee);
784 #endif
785 signal (SIGILL, aiee);
786 signal (SIGSEGV, aiee);
787 signal (SIGFPE, aiee);
788
789 if (!setjmp (aiee_abort)) {
790 if (signal_hook)
791 recover = signal_hook (sig, signal_hook_data);
792 Sys_Shutdown ();
793 }
794
795 if (recover) {
796 #ifndef _WIN32
797 signal (SIGQUIT, signal_handler);
798 signal (SIGTRAP, signal_handler);
799 signal (SIGIOT, signal_handler);
800 signal (SIGBUS, signal_handler);
801 #endif
802 signal (SIGILL, signal_handler);
803 signal (SIGSEGV, signal_handler);
804 signal (SIGFPE, signal_handler);
805 } else {
806 #ifndef _WIN32
807 signal (SIGQUIT, SIG_DFL);
808 signal (SIGTRAP, SIG_DFL);
809 signal (SIGIOT, SIG_DFL);
810 signal (SIGBUS, SIG_DFL);
811 #endif
812 signal (SIGILL, SIG_DFL);
813 signal (SIGSEGV, SIG_DFL);
814 signal (SIGFPE, SIG_DFL);
815 }
816 }
817 }
818
819 VISIBLE void
Sys_Init(void)820 Sys_Init (void)
821 {
822 // catch signals
823 #ifndef _WIN32
824 signal (SIGHUP, signal_handler);
825 signal (SIGQUIT, signal_handler);
826 signal (SIGTRAP, signal_handler);
827 signal (SIGIOT, signal_handler);
828 signal (SIGBUS, signal_handler);
829 #endif
830 signal (SIGINT, signal_handler);
831 signal (SIGILL, signal_handler);
832 signal (SIGSEGV, signal_handler);
833 signal (SIGTERM, signal_handler);
834 signal (SIGFPE, signal_handler);
835
836 Cvar_Init_Hash ();
837 Cmd_Init_Hash ();
838 Cvar_Init ();
839 Sys_Init_Cvars ();
840
841 Cmd_Init ();
842 }
843
844 VISIBLE int
Sys_CreatePath(const char * path)845 Sys_CreatePath (const char *path)
846 {
847 char *ofs;
848 char *e_path = alloca (strlen (path) + 1);
849
850 strcpy (e_path, path);
851 for (ofs = e_path + 1; *ofs; ofs++) {
852 if (*ofs == '/') { // create the directory
853 *ofs = 0;
854 if (Sys_mkdir (e_path) == -1)
855 return -1;
856 *ofs = '/';
857 }
858 }
859 return 0;
860 }
861
862 char *
Sys_ExpandSquiggle(const char * path)863 Sys_ExpandSquiggle (const char *path)
864 {
865 const char *home = 0;
866 #ifdef _WIN32
867 char userpath[MAX_PATH]; // sigh, why can't windows give the size?
868 #else
869 # ifdef HAVE_GETUID
870 struct passwd *pwd_ent;
871 # endif
872 #endif
873
874 if (strncmp (path, "~/", 2) != 0) {
875 return strdup (path);
876 }
877
878 #ifdef _WIN32
879 if (SHGetFolderPathA (0, CSIDL_LOCAL_APPDATA, 0, 0, userpath) == S_OK) {
880 home = userpath;
881 }
882 // LordHavoc: first check HOME to duplicate previous version behavior
883 // (also handy if someone wants it elsewhere than their windows directory)
884 if (!home)
885 home = getenv ("HOME");
886 if (!home || !home[0])
887 home = getenv ("USERPROFILE");
888 if (!home || !home[0])
889 home = 0;
890 #else
891 # ifdef HAVE_GETUID
892 if ((pwd_ent = getpwuid (getuid ()))) {
893 home = pwd_ent->pw_dir;
894 } else
895 home = getenv ("HOME");
896 # endif
897 #endif
898
899 if (!home)
900 home = ".";
901 return nva ("%s%s", home, path + 1); // skip leading ~
902 }
903