changed Com_HexDumpToConsole to print space separated 4 byte groups, added some comme...
[divverent/darkplaces.git] / common.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
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.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // common.c -- misc functions used in client and server
21
22 #include <stdlib.h>
23 #include <fcntl.h>
24 #ifndef WIN32
25 #include <unistd.h>
26 #endif
27
28 #include "quakedef.h"
29
30 cvar_t registered = {0, "registered","0"};
31 cvar_t cmdline = {0, "cmdline","0"};
32
33 extern qboolean fs_modified;   // set true if using non-id files
34
35 char com_token[1024];
36 int com_argc;
37 const char **com_argv;
38
39 // LordHavoc: made commandline 1024 characters instead of 256
40 #define CMDLINE_LENGTH  1024
41 char com_cmdline[CMDLINE_LENGTH];
42
43 int gamemode;
44 char *gamename;
45 char *gamedirname;
46 char com_modname[MAX_OSPATH] = "";
47
48
49 /*
50 ============================================================================
51
52                                         BYTE ORDER FUNCTIONS
53
54 ============================================================================
55 */
56
57 short   ShortSwap (short l)
58 {
59         qbyte    b1,b2;
60
61         b1 = l&255;
62         b2 = (l>>8)&255;
63
64         return (b1<<8) + b2;
65 }
66
67 int    LongSwap (int l)
68 {
69         qbyte    b1,b2,b3,b4;
70
71         b1 = l&255;
72         b2 = (l>>8)&255;
73         b3 = (l>>16)&255;
74         b4 = (l>>24)&255;
75
76         return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
77 }
78
79 float FloatSwap (float f)
80 {
81         union
82         {
83                 float   f;
84                 qbyte    b[4];
85         } dat1, dat2;
86
87
88         dat1.f = f;
89         dat2.b[0] = dat1.b[3];
90         dat2.b[1] = dat1.b[2];
91         dat2.b[2] = dat1.b[1];
92         dat2.b[3] = dat1.b[0];
93         return dat2.f;
94 }
95
96
97 // Extract integers from buffers
98
99 unsigned int BuffBigLong (const qbyte *buffer)
100 {
101         return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
102 }
103
104 unsigned short BuffBigShort (const qbyte *buffer)
105 {
106         return (buffer[0] << 8) | buffer[1];
107 }
108
109 unsigned int BuffLittleLong (const qbyte *buffer)
110 {
111         return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
112 }
113
114 unsigned short BuffLittleShort (const qbyte *buffer)
115 {
116         return (buffer[1] << 8) | buffer[0];
117 }
118
119
120 /*
121 ==============================================================================
122
123                         MESSAGE IO FUNCTIONS
124
125 Handles byte ordering and avoids alignment errors
126 ==============================================================================
127 */
128
129 //
130 // writing functions
131 //
132
133 void MSG_WriteChar (sizebuf_t *sb, int c)
134 {
135         qbyte    *buf;
136
137         buf = SZ_GetSpace (sb, 1);
138         buf[0] = c;
139 }
140
141 void MSG_WriteByte (sizebuf_t *sb, int c)
142 {
143         qbyte    *buf;
144
145         buf = SZ_GetSpace (sb, 1);
146         buf[0] = c;
147 }
148
149 void MSG_WriteShort (sizebuf_t *sb, int c)
150 {
151         qbyte    *buf;
152
153         buf = SZ_GetSpace (sb, 2);
154         buf[0] = c&0xff;
155         buf[1] = c>>8;
156 }
157
158 void MSG_WriteLong (sizebuf_t *sb, int c)
159 {
160         qbyte    *buf;
161
162         buf = SZ_GetSpace (sb, 4);
163         buf[0] = c&0xff;
164         buf[1] = (c>>8)&0xff;
165         buf[2] = (c>>16)&0xff;
166         buf[3] = c>>24;
167 }
168
169 void MSG_WriteFloat (sizebuf_t *sb, float f)
170 {
171         union
172         {
173                 float   f;
174                 int     l;
175         } dat;
176
177
178         dat.f = f;
179         dat.l = LittleLong (dat.l);
180
181         SZ_Write (sb, &dat.l, 4);
182 }
183
184 void MSG_WriteString (sizebuf_t *sb, const char *s)
185 {
186         if (!s)
187                 SZ_Write (sb, "", 1);
188         else
189                 SZ_Write (sb, s, strlen(s)+1);
190 }
191
192 // used by server (always latest PROTOCOL_DARKPLACES)
193 void MSG_WriteDPCoord (sizebuf_t *sb, float f)
194 {
195         if (f >= 0)
196                 MSG_WriteShort (sb, (int)(f + 0.5f));
197         else
198                 MSG_WriteShort (sb, (int)(f - 0.5f));
199 }
200
201 void MSG_WritePreciseAngle (sizebuf_t *sb, float f)
202 {
203         if (f >= 0)
204                 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
205         else
206                 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535);
207 }
208
209 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
210 void MSG_WriteAngle (sizebuf_t *sb, float f)
211 {
212         if (f >= 0)
213                 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
214         else
215                 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) - 0.5f) & 255);
216 }
217
218 //
219 // reading functions
220 //
221 int msg_readcount;
222 qboolean msg_badread;
223
224 void MSG_BeginReading (void)
225 {
226         msg_readcount = 0;
227         msg_badread = false;
228 }
229
230 int MSG_ReadLittleShort (void)
231 {
232         if (msg_readcount+2 > net_message.cursize)
233         {
234                 msg_badread = true;
235                 return -1;
236         }
237         msg_readcount += 2;
238         return (short)(net_message.data[msg_readcount-2] | (net_message.data[msg_readcount-1]<<8));
239 }
240
241 int MSG_ReadBigShort (void)
242 {
243         if (msg_readcount+2 > net_message.cursize)
244         {
245                 msg_badread = true;
246                 return -1;
247         }
248         msg_readcount += 2;
249         return (short)((net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1]);
250 }
251
252 int MSG_ReadLittleLong (void)
253 {
254         if (msg_readcount+4 > net_message.cursize)
255         {
256                 msg_badread = true;
257                 return -1;
258         }
259         msg_readcount += 4;
260         return net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
261 }
262
263 int MSG_ReadBigLong (void)
264 {
265         if (msg_readcount+4 > net_message.cursize)
266         {
267                 msg_badread = true;
268                 return -1;
269         }
270         msg_readcount += 4;
271         return (net_message.data[msg_readcount-4]<<24) + (net_message.data[msg_readcount-3]<<16) + (net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1];
272 }
273
274 float MSG_ReadLittleFloat (void)
275 {
276         union
277         {
278                 float f;
279                 int l;
280         } dat;
281         if (msg_readcount+4 > net_message.cursize)
282         {
283                 msg_badread = true;
284                 return -1;
285         }
286         msg_readcount += 4;
287         dat.l = net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
288         return dat.f;
289 }
290
291 float MSG_ReadBigFloat (void)
292 {
293         union
294         {
295                 float f;
296                 int l;
297         } dat;
298         if (msg_readcount+4 > net_message.cursize)
299         {
300                 msg_badread = true;
301                 return -1;
302         }
303         msg_readcount += 4;
304         dat.l = (net_message.data[msg_readcount-4]<<24) | (net_message.data[msg_readcount-3]<<16) | (net_message.data[msg_readcount-2]<<8) | net_message.data[msg_readcount-1];
305         return dat.f;
306 }
307
308 char *MSG_ReadString (void)
309 {
310         static char string[2048];
311         int l,c;
312         for (l = 0;l < (int) sizeof(string) - 1 && (c = MSG_ReadChar()) != -1 && c != 0;l++)
313                 string[l] = c;
314         string[l] = 0;
315         return string;
316 }
317
318 int MSG_ReadBytes (int numbytes, unsigned char *out)
319 {
320         int l, c;
321         for (l = 0;l < numbytes && (c = MSG_ReadChar()) != -1;l++)
322                 out[l] = c;
323         return l;
324 }
325
326 // used by client
327 float MSG_ReadCoord (void)
328 {
329         if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
330                 return (signed short) MSG_ReadLittleShort();
331         else if (cl.protocol == PROTOCOL_DARKPLACES1)
332                 return MSG_ReadLittleFloat();
333         else
334                 return MSG_ReadLittleShort() * (1.0f/8.0f);
335 }
336
337
338 //===========================================================================
339
340 void SZ_Alloc (sizebuf_t *buf, int startsize, const char *name)
341 {
342         if (startsize < 256)
343                 startsize = 256;
344         buf->mempool = Mem_AllocPool(name);
345         buf->data = Mem_Alloc(buf->mempool, startsize);
346         buf->maxsize = startsize;
347         buf->cursize = 0;
348 }
349
350
351 void SZ_Free (sizebuf_t *buf)
352 {
353         Mem_FreePool(&buf->mempool);
354         buf->data = NULL;
355         buf->maxsize = 0;
356         buf->cursize = 0;
357 }
358
359 void SZ_Clear (sizebuf_t *buf)
360 {
361         buf->cursize = 0;
362 }
363
364 void *SZ_GetSpace (sizebuf_t *buf, int length)
365 {
366         void *data;
367
368         if (buf->cursize + length > buf->maxsize)
369         {
370                 if (!buf->allowoverflow)
371                         Host_Error ("SZ_GetSpace: overflow without allowoverflow set\n");
372
373                 if (length > buf->maxsize)
374                         Host_Error ("SZ_GetSpace: %i is > full buffer size\n", length);
375
376                 buf->overflowed = true;
377                 Con_Print("SZ_GetSpace: overflow\n");
378                 SZ_Clear (buf);
379         }
380
381         data = buf->data + buf->cursize;
382         buf->cursize += length;
383
384         return data;
385 }
386
387 void SZ_Write (sizebuf_t *buf, const void *data, int length)
388 {
389         memcpy (SZ_GetSpace(buf,length),data,length);
390 }
391
392 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
393 // attention, it has been eradicated from here, its only (former) use in
394 // all of darkplaces.
395
396 static char *hexchar = "0123456789ABCDEF";
397 void Com_HexDumpToConsole(const qbyte *data, int size)
398 {
399         int i, j, n;
400         char text[1024];
401         char *cur, *flushpointer;
402         const qbyte *d;
403         cur = text;
404         flushpointer = text + 512;
405         for (i = 0;i < size;)
406         {
407                 n = 16;
408                 if (n > size - i)
409                         n = size - i;
410                 d = data + i;
411                 // print offset
412                 *cur++ = hexchar[(i >> 12) & 15];
413                 *cur++ = hexchar[(i >>  8) & 15];
414                 *cur++ = hexchar[(i >>  4) & 15];
415                 *cur++ = hexchar[(i >>  0) & 15];
416                 *cur++ = ':';
417                 // print hex
418                 for (j = 0;j < 16;j++)
419                 {
420                         if (j < n)
421                         {
422                                 *cur++ = hexchar[(d[j] >> 4) & 15];
423                                 *cur++ = hexchar[(d[j] >> 0) & 15];
424                         }
425                         else
426                         {
427                                 *cur++ = ' ';
428                                 *cur++ = ' ';
429                         }
430                         if ((j & 3) == 0)
431                                 *cur++ = ' ';
432                 }
433                 // print text
434                 for (j = 0;j < 16;j++)
435                 {
436                         if (j < n)
437                         {
438                                 if (d[j] >= ' ' && d[j] <= 127)
439                                         *cur++ = d[j];
440                                 else
441                                         *cur++ = '.';
442                         }
443                         else
444                                 *cur++ = ' ';
445                 }
446                 *cur++ = '\n';
447                 i += n;
448                 if (cur >= flushpointer || i >= size)
449                 {
450                         *cur++ = 0;
451                         Con_Print(text);
452                         cur = text;
453                 }
454         }
455 }
456
457 void SZ_HexDumpToConsole(const sizebuf_t *buf)
458 {
459         Com_HexDumpToConsole(buf->data, buf->cursize);
460 }
461
462
463 //============================================================================
464
465
466 /*
467 ==============
468 COM_ParseToken
469
470 Parse a token out of a string
471 ==============
472 */
473 int COM_ParseToken(const char **datapointer, int returnnewline)
474 {
475         int len;
476         const char *data = *datapointer;
477
478         len = 0;
479         com_token[0] = 0;
480
481         if (!data)
482         {
483                 *datapointer = NULL;
484                 return false;
485         }
486
487 // skip whitespace
488 skipwhite:
489         for (;*data <= ' ' && (*data != '\n' || !returnnewline);data++)
490         {
491                 if (*data == 0)
492                 {
493                         // end of file
494                         *datapointer = NULL;
495                         return false;
496                 }
497         }
498
499         if (data[0] == '/' && data[1] == '/')
500         {
501                 // comment
502                 while (*data && *data != '\n')
503                         data++;
504                 goto skipwhite;
505         }
506         else if (data[0] == '/' && data[1] == '*')
507         {
508                 // comment
509                 data++;
510                 while (*data && (data[0] != '*' || data[1] != '/'))
511                         data++;
512                 data += 2;
513                 goto skipwhite;
514         }
515         else if (*data == '\"')
516         {
517                 // quoted string
518                 for (data++;*data != '\"';data++)
519                 {
520                         if (!*data || len >= (int)sizeof(com_token) - 1)
521                         {
522                                 com_token[0] = 0;
523                                 *datapointer = NULL;
524                                 return false;
525                         }
526                         com_token[len++] = *data;
527                 }
528                 com_token[len] = 0;
529                 *datapointer = data+1;
530                 return true;
531         }
532         else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == '\'' || *data == ':' || *data == ',' || *data == ';')
533         {
534                 // single character
535                 com_token[len++] = *data++;
536                 com_token[len] = 0;
537                 *datapointer = data;
538                 return true;
539         }
540         else
541         {
542                 // regular word
543                 for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != '\'' && *data != ':' && *data != ',' && *data != ';';data++)
544                 {
545                         if (len >= (int)sizeof(com_token) - 1)
546                         {
547                                 com_token[0] = 0;
548                                 *datapointer = NULL;
549                                 return false;
550                         }
551                         com_token[len++] = *data;
552                 }
553                 com_token[len] = 0;
554                 *datapointer = data;
555                 return true;
556         }
557 }
558
559 /*
560 ==============
561 COM_ParseTokenConsole
562
563 Parse a token out of a string, behaving like the qwcl console
564 ==============
565 */
566 int COM_ParseTokenConsole(const char **datapointer)
567 {
568         int len;
569         const char *data = *datapointer;
570
571         len = 0;
572         com_token[0] = 0;
573
574         if (!data)
575         {
576                 *datapointer = NULL;
577                 return false;
578         }
579
580 // skip whitespace
581 skipwhite:
582         for (;*data <= ' ';data++)
583         {
584                 if (*data == 0)
585                 {
586                         // end of file
587                         *datapointer = NULL;
588                         return false;
589                 }
590         }
591
592         if (*data == '/' && data[1] == '/')
593         {
594                 // comment
595                 while (*data && *data != '\n')
596                         data++;
597                 goto skipwhite;
598         }
599         else if (*data == '\"')
600         {
601                 // quoted string
602                 for (data++;*data != '\"';data++)
603                 {
604                         if (!*data || len >= (int)sizeof(com_token) - 1)
605                         {
606                                 com_token[0] = 0;
607                                 *datapointer = NULL;
608                                 return false;
609                         }
610                         com_token[len++] = *data;
611                 }
612                 com_token[len] = 0;
613                 *datapointer = data+1;
614                 return true;
615         }
616         else
617         {
618                 // regular word
619                 for (;*data > ' ';data++)
620                 {
621                         if (len >= (int)sizeof(com_token) - 1)
622                         {
623                                 com_token[0] = 0;
624                                 *datapointer = NULL;
625                                 return false;
626                         }
627                         com_token[len++] = *data;
628                 }
629                 com_token[len] = 0;
630                 *datapointer = data;
631                 return true;
632         }
633 }
634
635
636 /*
637 ================
638 COM_CheckParm
639
640 Returns the position (1 to argc-1) in the program's argument list
641 where the given parameter apears, or 0 if not present
642 ================
643 */
644 int COM_CheckParm (const char *parm)
645 {
646         int i;
647
648         for (i=1 ; i<com_argc ; i++)
649         {
650                 if (!com_argv[i])
651                         continue;               // NEXTSTEP sometimes clears appkit vars.
652                 if (!strcmp (parm,com_argv[i]))
653                         return i;
654         }
655
656         return 0;
657 }
658
659 /*
660 ================
661 COM_CheckRegistered
662
663 Looks for the pop.txt file and verifies it.
664 Sets the "registered" cvar.
665 Immediately exits out if an alternate game was attempted to be started without
666 being registered.
667 ================
668 */
669 void COM_CheckRegistered (void)
670 {
671         Cvar_Set ("cmdline", com_cmdline);
672
673         if (!FS_FileExists("gfx/pop.lmp"))
674         {
675                 if (fs_modified)
676                         Con_Print("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
677                 else
678                         Con_Print("Playing shareware version.\n");
679                 return;
680         }
681
682         Cvar_Set ("registered", "1");
683         Con_Print("Playing registered version.\n");
684 }
685
686
687 /*
688 ================
689 COM_InitArgv
690 ================
691 */
692 void COM_InitArgv (void)
693 {
694         int i, j, n;
695         // reconstitute the command line for the cmdline externally visible cvar
696         n = 0;
697         for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
698         {
699                 i = 0;
700                 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
701                         com_cmdline[n++] = com_argv[j][i++];
702                 if (n < (CMDLINE_LENGTH - 1))
703                         com_cmdline[n++] = ' ';
704                 else
705                         break;
706         }
707         com_cmdline[n] = 0;
708 }
709
710 void COM_InitGameType (void)
711 {
712         char name[MAX_OSPATH];
713         FS_StripExtension (com_argv[0], name, sizeof (name));
714         COM_ToLowerString (name, name, sizeof (name));
715
716         if (strstr(name, "transfusion"))
717                 gamemode = GAME_TRANSFUSION;
718         else if (strstr(name, "nexuiz"))
719                 gamemode = GAME_NEXUIZ;
720         else if (strstr(name, "nehahra"))
721                 gamemode = GAME_NEHAHRA;
722         else if (strstr(name, "hipnotic"))
723                 gamemode = GAME_HIPNOTIC;
724         else if (strstr(name, "rogue"))
725                 gamemode = GAME_ROGUE;
726         else if (strstr(name, "gvb2"))
727                 gamemode = GAME_GOODVSBAD2;
728         else if (strstr(name, "teu"))
729                 gamemode = GAME_TEU;
730         else if (strstr(name, "battlemech"))
731                 gamemode = GAME_BATTLEMECH;
732         else if (strstr(name, "zymotic"))
733                 gamemode = GAME_ZYMOTIC;
734         else if (strstr(name, "fniggium"))
735                 gamemode = GAME_FNIGGIUM;
736         else if (strstr(name, "setheral"))
737                 gamemode = GAME_SETHERAL;
738         else if (strstr(name, "som"))
739                 gamemode = GAME_SOM;
740         else if (strstr(name, "tenebrae"))
741                 gamemode = GAME_TENEBRAE;
742         else
743                 gamemode = GAME_NORMAL;
744
745         if (COM_CheckParm ("-transfusion"))
746                 gamemode = GAME_TRANSFUSION;
747         else if (COM_CheckParm ("-nexuiz"))
748                 gamemode = GAME_NEXUIZ;
749         else if (COM_CheckParm ("-nehahra"))
750                 gamemode = GAME_NEHAHRA;
751         else if (COM_CheckParm ("-hipnotic"))
752                 gamemode = GAME_HIPNOTIC;
753         else if (COM_CheckParm ("-rogue"))
754                 gamemode = GAME_ROGUE;
755         else if (COM_CheckParm ("-quake"))
756                 gamemode = GAME_NORMAL;
757         else if (COM_CheckParm ("-goodvsbad2"))
758                 gamemode = GAME_GOODVSBAD2;
759         else if (COM_CheckParm ("-teu"))
760                 gamemode = GAME_TEU;
761         else if (COM_CheckParm ("-battlemech"))
762                 gamemode = GAME_BATTLEMECH;
763         else if (COM_CheckParm ("-zymotic"))
764                 gamemode = GAME_ZYMOTIC;
765         else if (COM_CheckParm ("-fniggium"))
766                 gamemode = GAME_FNIGGIUM;
767         else if (COM_CheckParm ("-setheral"))
768                 gamemode = GAME_SETHERAL;
769         else if (COM_CheckParm ("-som"))
770                 gamemode = GAME_SOM;
771         else if (COM_CheckParm ("-tenebrae"))
772                 gamemode = GAME_TENEBRAE;
773
774         switch(gamemode)
775         {
776         case GAME_NORMAL:
777                 gamename = "DarkPlaces-Quake";
778                 gamedirname = "";
779                 break;
780         case GAME_HIPNOTIC:
781                 gamename = "Darkplaces-Hipnotic";
782                 gamedirname = "hipnotic";
783                 break;
784         case GAME_ROGUE:
785                 gamename = "Darkplaces-Rogue";
786                 gamedirname = "rogue";
787                 break;
788         case GAME_NEHAHRA:
789                 gamename = "DarkPlaces-Nehahra";
790                 gamedirname = "nehahra";
791                 break;
792         case GAME_NEXUIZ:
793                 gamename = "Nexuiz";
794                 gamedirname = "data";
795                 break;
796         case GAME_TRANSFUSION:
797                 gamename = "Transfusion";
798                 gamedirname = "basetf";
799                 break;
800         case GAME_GOODVSBAD2:
801                 gamename = "GoodVs.Bad2";
802                 gamedirname = "rts";
803                 break;
804         case GAME_TEU:
805                 gamename = "TheEvilUnleashed";
806                 gamedirname = "baseteu";
807                 break;
808         case GAME_BATTLEMECH:
809                 gamename = "Battlemech";
810                 gamedirname = "base";
811                 break;
812         case GAME_ZYMOTIC:
813                 gamename = "Zymotic";
814                 gamedirname = "data";
815                 break;
816         case GAME_FNIGGIUM:
817                 gamename = "Fniggium";
818                 gamedirname = "data";
819                 break;
820         case GAME_SETHERAL:
821                 gamename = "Setheral";
822                 gamedirname = "data";
823                 break;
824         case GAME_SOM:
825                 gamename = "Son of Man";
826                 gamedirname = "data";
827                 break;
828         case GAME_TENEBRAE:
829                 gamename = "DarkPlaces-Tenebrae";
830                 gamedirname = "tenebrae";
831                 break;
832         default:
833                 Sys_Error("COM_InitGameType: unknown gamemode %i\n", gamemode);
834                 break;
835         }
836 }
837
838
839 extern void Mathlib_Init(void);
840 extern void FS_Init (void);
841
842 /*
843 ================
844 COM_Init
845 ================
846 */
847 void COM_Init (void)
848 {
849         Cvar_RegisterVariable (&registered);
850         Cvar_RegisterVariable (&cmdline);
851
852         Mathlib_Init();
853
854         FS_Init ();
855         Log_Init ();
856         COM_CheckRegistered ();
857
858         COM_InitGameType();
859 }
860
861
862 /*
863 ============
864 va
865
866 does a varargs printf into a temp buffer, so I don't need to have
867 varargs versions of all text functions.
868 FIXME: make this buffer size safe someday
869 ============
870 */
871 char *va(const char *format, ...)
872 {
873         va_list argptr;
874         // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
875         static char string[8][1024], *s;
876         static int stringindex = 0;
877
878         s = string[stringindex];
879         stringindex = (stringindex + 1) & 7;
880         va_start (argptr, format);
881         vsnprintf (s, sizeof (string[0]), format,argptr);
882         va_end (argptr);
883
884         return s;
885 }
886
887
888 //======================================
889
890 void COM_ToLowerString (const char *in, char *out, size_t size_out)
891 {
892         if (size_out == 0)
893                 return;
894
895         while (*in && size_out > 1)
896         {
897                 if (*in >= 'A' && *in <= 'Z')
898                         *out++ = *in++ + 'a' - 'A';
899                 else
900                         *out++ = *in++;
901                 size_out--;
902         }
903         *out = '\0';
904 }
905
906 void COM_ToUpperString (const char *in, char *out, size_t size_out)
907 {
908         if (size_out == 0)
909                 return;
910
911         while (*in && size_out > 1)
912         {
913                 if (*in >= 'a' && *in <= 'z')
914                         *out++ = *in++ + 'A' - 'a';
915                 else
916                         *out++ = *in++;
917                 size_out--;
918         }
919         *out = '\0';
920 }
921
922 int COM_StringBeginsWith(const char *s, const char *match)
923 {
924         for (;*s && *match;s++, match++)
925                 if (*s != *match)
926                         return false;
927         return true;
928 }
929
930 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
931 {
932         int argc, commentprefixlength;
933         char *tokenbufend;
934         const char *l;
935         argc = 0;
936         tokenbufend = tokenbuf + tokenbufsize;
937         l = *text;
938         commentprefixlength = 0;
939         if (commentprefix)
940                 commentprefixlength = strlen(commentprefix);
941         while (*l && *l != '\n')
942         {
943                 if (*l > ' ')
944                 {
945                         if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
946                         {
947                                 while (*l && *l != '\n')
948                                         l++;
949                                 break;
950                         }
951                         if (argc >= maxargc)
952                                 return -1;
953                         argv[argc++] = tokenbuf;
954                         if (*l == '"')
955                         {
956                                 l++;
957                                 while (*l && *l != '"')
958                                 {
959                                         if (tokenbuf >= tokenbufend)
960                                                 return -1;
961                                         *tokenbuf++ = *l++;
962                                 }
963                                 if (*l == '"')
964                                         l++;
965                         }
966                         else
967                         {
968                                 while (*l > ' ')
969                                 {
970                                         if (tokenbuf >= tokenbufend)
971                                                 return -1;
972                                         *tokenbuf++ = *l++;
973                                 }
974                         }
975                         if (tokenbuf >= tokenbufend)
976                                 return -1;
977                         *tokenbuf++ = 0;
978                 }
979                 else
980                         l++;
981         }
982         if (*l == '\n')
983                 l++;
984         *text = l;
985         return argc;
986 }
987
988 // written by Elric, thanks Elric!
989 char *SearchInfostring(const char *infostring, const char *key)
990 {
991         static char value [256];
992         char crt_key [256];
993         size_t value_ind, key_ind;
994         char c;
995
996         if (*infostring++ != '\\')
997                 return NULL;
998
999         value_ind = 0;
1000         for (;;)
1001         {
1002                 key_ind = 0;
1003
1004                 // Get the key name
1005                 for (;;)
1006                 {
1007                         c = *infostring++;
1008
1009                         if (c == '\0')
1010                                 return NULL;
1011                         if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1012                         {
1013                                 crt_key[key_ind] = '\0';
1014                                 break;
1015                         }
1016
1017                         crt_key[key_ind++] = c;
1018                 }
1019
1020                 // If it's the key we are looking for, save it in "value"
1021                 if (!strcmp(crt_key, key))
1022                 {
1023                         for (;;)
1024                         {
1025                                 c = *infostring++;
1026
1027                                 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1028                                 {
1029                                         value[value_ind] = '\0';
1030                                         return value;
1031                                 }
1032
1033                                 value[value_ind++] = c;
1034                         }
1035                 }
1036
1037                 // Else, skip the value
1038                 for (;;)
1039                 {
1040                         c = *infostring++;
1041
1042                         if (c == '\0')
1043                                 return NULL;
1044                         if (c == '\\')
1045                                 break;
1046                 }
1047         }
1048 }
1049
1050
1051 //========================================================
1052 // strlcat and strlcpy, from OpenBSD
1053
1054 /*
1055  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1056  *
1057  * Permission to use, copy, modify, and distribute this software for any
1058  * purpose with or without fee is hereby granted, provided that the above
1059  * copyright notice and this permission notice appear in all copies.
1060  *
1061  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1062  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1063  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1064  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1065  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1066  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1067  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1068  */
1069
1070 /*      $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $    */
1071 /*      $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $     */
1072
1073
1074 #ifndef HAVE_STRLCAT
1075 size_t
1076 strlcat(char *dst, const char *src, size_t siz)
1077 {
1078         register char *d = dst;
1079         register const char *s = src;
1080         register size_t n = siz;
1081         size_t dlen;
1082
1083         /* Find the end of dst and adjust bytes left but don't go past end */
1084         while (n-- != 0 && *d != '\0')
1085                 d++;
1086         dlen = d - dst;
1087         n = siz - dlen;
1088
1089         if (n == 0)
1090                 return(dlen + strlen(s));
1091         while (*s != '\0') {
1092                 if (n != 1) {
1093                         *d++ = *s;
1094                         n--;
1095                 }
1096                 s++;
1097         }
1098         *d = '\0';
1099
1100         return(dlen + (s - src));       /* count does not include NUL */
1101 }
1102 #endif  // #ifndef HAVE_STRLCAT
1103
1104
1105 #ifndef HAVE_STRLCPY
1106 size_t
1107 strlcpy(char *dst, const char *src, size_t siz)
1108 {
1109         register char *d = dst;
1110         register const char *s = src;
1111         register size_t n = siz;
1112
1113         /* Copy as many bytes as will fit */
1114         if (n != 0 && --n != 0) {
1115                 do {
1116                         if ((*d++ = *s++) == 0)
1117                                 break;
1118                 } while (--n != 0);
1119         }
1120
1121         /* Not enough room in dst, add NUL and traverse rest of src */
1122         if (n == 0) {
1123                 if (siz != 0)
1124                         *d = '\0';              /* NUL-terminate dst */
1125                 while (*s++)
1126                         ;
1127         }
1128
1129         return(s - src - 1);    /* count does not include NUL */
1130 }
1131
1132 #endif  // #ifndef HAVE_STRLCPY