06d51a415d917107b1fa002092edd2cda96f460b
[xonotic/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                 *cur++ = hexchar[(i >> 12) & 15];
412                 *cur++ = hexchar[(i >>  8) & 15];
413                 *cur++ = hexchar[(i >>  4) & 15];
414                 *cur++ = hexchar[(i >>  0) & 15];
415                 *cur++ = ':';
416                 for (j = 0;j < n;j++)
417                 {
418                         if (j & 1)
419                         {
420                                 *cur++ = hexchar[(d[j] >> 4) & 15] | 0x80;
421                                 *cur++ = hexchar[(d[j] >> 0) & 15] | 0x80;
422                         }
423                         else
424                         {
425                                 *cur++ = hexchar[(d[j] >> 4) & 15];
426                                 *cur++ = hexchar[(d[j] >> 0) & 15];
427                         }
428                 }
429                 for (;j < 16;j++)
430                 {
431                         *cur++ = ' ';
432                         *cur++ = ' ';
433                 }
434                 for (j = 0;j < n;j++)
435                         *cur++ = (d[j] >= ' ' && d[j] <= 0x7E) ? d[j] : '.';
436                 for (;j < 16;j++)
437                         *cur++ = ' ';
438                 *cur++ = '\n';
439                 i += n;
440                 if (cur >= flushpointer || i >= size)
441                 {
442                         *cur++ = 0;
443                         Con_Print(text);
444                         cur = text;
445                 }
446         }
447 }
448
449 void SZ_HexDumpToConsole(const sizebuf_t *buf)
450 {
451         Com_HexDumpToConsole(buf->data, buf->cursize);
452 }
453
454
455 //============================================================================
456
457
458 /*
459 ==============
460 COM_ParseToken
461
462 Parse a token out of a string
463 ==============
464 */
465 int COM_ParseToken(const char **datapointer, int returnnewline)
466 {
467         int len;
468         const char *data = *datapointer;
469
470         len = 0;
471         com_token[0] = 0;
472
473         if (!data)
474         {
475                 *datapointer = NULL;
476                 return false;
477         }
478
479 // skip whitespace
480 skipwhite:
481         for (;*data <= ' ' && (*data != '\n' || !returnnewline);data++)
482         {
483                 if (*data == 0)
484                 {
485                         // end of file
486                         *datapointer = NULL;
487                         return false;
488                 }
489         }
490
491         if (data[0] == '/' && data[1] == '/')
492         {
493                 // comment
494                 while (*data && *data != '\n')
495                         data++;
496                 goto skipwhite;
497         }
498         else if (data[0] == '/' && data[1] == '*')
499         {
500                 // comment
501                 data++;
502                 while (*data && (data[0] != '*' || data[1] != '/'))
503                         data++;
504                 data += 2;
505                 goto skipwhite;
506         }
507         else if (*data == '\"')
508         {
509                 // quoted string
510                 for (data++;*data != '\"';data++)
511                 {
512                         if (!*data || len >= (int)sizeof(com_token) - 1)
513                         {
514                                 com_token[0] = 0;
515                                 *datapointer = NULL;
516                                 return false;
517                         }
518                         com_token[len++] = *data;
519                 }
520                 com_token[len] = 0;
521                 *datapointer = data+1;
522                 return true;
523         }
524         else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == '\'' || *data == ':' || *data == ',' || *data == ';')
525         {
526                 // single character
527                 com_token[len++] = *data++;
528                 com_token[len] = 0;
529                 *datapointer = data;
530                 return true;
531         }
532         else
533         {
534                 // regular word
535                 for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != '\'' && *data != ':' && *data != ',' && *data != ';';data++)
536                 {
537                         if (len >= (int)sizeof(com_token) - 1)
538                         {
539                                 com_token[0] = 0;
540                                 *datapointer = NULL;
541                                 return false;
542                         }
543                         com_token[len++] = *data;
544                 }
545                 com_token[len] = 0;
546                 *datapointer = data;
547                 return true;
548         }
549 }
550
551 /*
552 ==============
553 COM_ParseTokenConsole
554
555 Parse a token out of a string, behaving like the qwcl console
556 ==============
557 */
558 int COM_ParseTokenConsole(const char **datapointer)
559 {
560         int len;
561         const char *data = *datapointer;
562
563         len = 0;
564         com_token[0] = 0;
565
566         if (!data)
567         {
568                 *datapointer = NULL;
569                 return false;
570         }
571
572 // skip whitespace
573 skipwhite:
574         for (;*data <= ' ';data++)
575         {
576                 if (*data == 0)
577                 {
578                         // end of file
579                         *datapointer = NULL;
580                         return false;
581                 }
582         }
583
584         if (*data == '/' && data[1] == '/')
585         {
586                 // comment
587                 while (*data && *data != '\n')
588                         data++;
589                 goto skipwhite;
590         }
591         else if (*data == '\"')
592         {
593                 // quoted string
594                 for (data++;*data != '\"';data++)
595                 {
596                         if (!*data || len >= (int)sizeof(com_token) - 1)
597                         {
598                                 com_token[0] = 0;
599                                 *datapointer = NULL;
600                                 return false;
601                         }
602                         com_token[len++] = *data;
603                 }
604                 com_token[len] = 0;
605                 *datapointer = data+1;
606                 return true;
607         }
608         else
609         {
610                 // regular word
611                 for (;*data > ' ';data++)
612                 {
613                         if (len >= (int)sizeof(com_token) - 1)
614                         {
615                                 com_token[0] = 0;
616                                 *datapointer = NULL;
617                                 return false;
618                         }
619                         com_token[len++] = *data;
620                 }
621                 com_token[len] = 0;
622                 *datapointer = data;
623                 return true;
624         }
625 }
626
627
628 /*
629 ================
630 COM_CheckParm
631
632 Returns the position (1 to argc-1) in the program's argument list
633 where the given parameter apears, or 0 if not present
634 ================
635 */
636 int COM_CheckParm (const char *parm)
637 {
638         int i;
639
640         for (i=1 ; i<com_argc ; i++)
641         {
642                 if (!com_argv[i])
643                         continue;               // NEXTSTEP sometimes clears appkit vars.
644                 if (!strcmp (parm,com_argv[i]))
645                         return i;
646         }
647
648         return 0;
649 }
650
651 /*
652 ================
653 COM_CheckRegistered
654
655 Looks for the pop.txt file and verifies it.
656 Sets the "registered" cvar.
657 Immediately exits out if an alternate game was attempted to be started without
658 being registered.
659 ================
660 */
661 void COM_CheckRegistered (void)
662 {
663         Cvar_Set ("cmdline", com_cmdline);
664
665         if (!FS_FileExists("gfx/pop.lmp"))
666         {
667                 if (fs_modified)
668                         Con_Print("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
669                 else
670                         Con_Print("Playing shareware version.\n");
671                 return;
672         }
673
674         Cvar_Set ("registered", "1");
675         Con_Print("Playing registered version.\n");
676 }
677
678
679 /*
680 ================
681 COM_InitArgv
682 ================
683 */
684 void COM_InitArgv (void)
685 {
686         int i, j, n;
687         // reconstitute the command line for the cmdline externally visible cvar
688         n = 0;
689         for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
690         {
691                 i = 0;
692                 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
693                         com_cmdline[n++] = com_argv[j][i++];
694                 if (n < (CMDLINE_LENGTH - 1))
695                         com_cmdline[n++] = ' ';
696                 else
697                         break;
698         }
699         com_cmdline[n] = 0;
700 }
701
702 void COM_InitGameType (void)
703 {
704         char name[MAX_OSPATH];
705         FS_StripExtension (com_argv[0], name, sizeof (name));
706         COM_ToLowerString (name, name, sizeof (name));
707
708         if (strstr(name, "transfusion"))
709                 gamemode = GAME_TRANSFUSION;
710         else if (strstr(name, "nexuiz"))
711                 gamemode = GAME_NEXUIZ;
712         else if (strstr(name, "nehahra"))
713                 gamemode = GAME_NEHAHRA;
714         else if (strstr(name, "hipnotic"))
715                 gamemode = GAME_HIPNOTIC;
716         else if (strstr(name, "rogue"))
717                 gamemode = GAME_ROGUE;
718         else if (strstr(name, "gvb2"))
719                 gamemode = GAME_GOODVSBAD2;
720         else if (strstr(name, "teu"))
721                 gamemode = GAME_TEU;
722         else if (strstr(name, "battlemech"))
723                 gamemode = GAME_BATTLEMECH;
724         else if (strstr(name, "zymotic"))
725                 gamemode = GAME_ZYMOTIC;
726         else if (strstr(name, "fniggium"))
727                 gamemode = GAME_FNIGGIUM;
728         else if (strstr(name, "setheral"))
729                 gamemode = GAME_SETHERAL;
730         else if (strstr(name, "som"))
731                 gamemode = GAME_SOM;
732         else if (strstr(name, "tenebrae"))
733                 gamemode = GAME_TENEBRAE;
734         else
735                 gamemode = GAME_NORMAL;
736
737         if (COM_CheckParm ("-transfusion"))
738                 gamemode = GAME_TRANSFUSION;
739         else if (COM_CheckParm ("-nexuiz"))
740                 gamemode = GAME_NEXUIZ;
741         else if (COM_CheckParm ("-nehahra"))
742                 gamemode = GAME_NEHAHRA;
743         else if (COM_CheckParm ("-hipnotic"))
744                 gamemode = GAME_HIPNOTIC;
745         else if (COM_CheckParm ("-rogue"))
746                 gamemode = GAME_ROGUE;
747         else if (COM_CheckParm ("-quake"))
748                 gamemode = GAME_NORMAL;
749         else if (COM_CheckParm ("-goodvsbad2"))
750                 gamemode = GAME_GOODVSBAD2;
751         else if (COM_CheckParm ("-teu"))
752                 gamemode = GAME_TEU;
753         else if (COM_CheckParm ("-battlemech"))
754                 gamemode = GAME_BATTLEMECH;
755         else if (COM_CheckParm ("-zymotic"))
756                 gamemode = GAME_ZYMOTIC;
757         else if (COM_CheckParm ("-fniggium"))
758                 gamemode = GAME_FNIGGIUM;
759         else if (COM_CheckParm ("-setheral"))
760                 gamemode = GAME_SETHERAL;
761         else if (COM_CheckParm ("-som"))
762                 gamemode = GAME_SOM;
763         else if (COM_CheckParm ("-tenebrae"))
764                 gamemode = GAME_TENEBRAE;
765
766         switch(gamemode)
767         {
768         case GAME_NORMAL:
769                 gamename = "DarkPlaces-Quake";
770                 gamedirname = "";
771                 break;
772         case GAME_HIPNOTIC:
773                 gamename = "Darkplaces-Hipnotic";
774                 gamedirname = "hipnotic";
775                 break;
776         case GAME_ROGUE:
777                 gamename = "Darkplaces-Rogue";
778                 gamedirname = "rogue";
779                 break;
780         case GAME_NEHAHRA:
781                 gamename = "DarkPlaces-Nehahra";
782                 gamedirname = "nehahra";
783                 break;
784         case GAME_NEXUIZ:
785                 gamename = "Nexuiz";
786                 gamedirname = "data";
787                 break;
788         case GAME_TRANSFUSION:
789                 gamename = "Transfusion";
790                 gamedirname = "basetf";
791                 break;
792         case GAME_GOODVSBAD2:
793                 gamename = "GoodVs.Bad2";
794                 gamedirname = "rts";
795                 break;
796         case GAME_TEU:
797                 gamename = "TheEvilUnleashed";
798                 gamedirname = "baseteu";
799                 break;
800         case GAME_BATTLEMECH:
801                 gamename = "Battlemech";
802                 gamedirname = "base";
803                 break;
804         case GAME_ZYMOTIC:
805                 gamename = "Zymotic";
806                 gamedirname = "data";
807                 break;
808         case GAME_FNIGGIUM:
809                 gamename = "Fniggium";
810                 gamedirname = "data";
811                 break;
812         case GAME_SETHERAL:
813                 gamename = "Setheral";
814                 gamedirname = "data";
815                 break;
816         case GAME_SOM:
817                 gamename = "Son of Man";
818                 gamedirname = "data";
819                 break;
820         case GAME_TENEBRAE:
821                 gamename = "DarkPlaces-Tenebrae";
822                 gamedirname = "tenebrae";
823                 break;
824         default:
825                 Sys_Error("COM_InitGameType: unknown gamemode %i\n", gamemode);
826                 break;
827         }
828 }
829
830
831 extern void Mathlib_Init(void);
832 extern void FS_Init (void);
833
834 /*
835 ================
836 COM_Init
837 ================
838 */
839 void COM_Init (void)
840 {
841         Cvar_RegisterVariable (&registered);
842         Cvar_RegisterVariable (&cmdline);
843
844         Mathlib_Init();
845
846         FS_Init ();
847         Con_InitLogging();
848         COM_CheckRegistered ();
849
850         COM_InitGameType();
851 }
852
853
854 /*
855 ============
856 va
857
858 does a varargs printf into a temp buffer, so I don't need to have
859 varargs versions of all text functions.
860 FIXME: make this buffer size safe someday
861 ============
862 */
863 char *va(const char *format, ...)
864 {
865         va_list argptr;
866         // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
867         static char string[8][1024], *s;
868         static int stringindex = 0;
869
870         s = string[stringindex];
871         stringindex = (stringindex + 1) & 7;
872         va_start (argptr, format);
873         vsnprintf (s, sizeof (string[0]), format,argptr);
874         va_end (argptr);
875
876         return s;
877 }
878
879
880 //======================================
881
882 void COM_ToLowerString (const char *in, char *out, size_t size_out)
883 {
884         if (size_out == 0)
885                 return;
886
887         while (*in && size_out > 1)
888         {
889                 if (*in >= 'A' && *in <= 'Z')
890                         *out++ = *in++ + 'a' - 'A';
891                 else
892                         *out++ = *in++;
893                 size_out--;
894         }
895         *out = '\0';
896 }
897
898 void COM_ToUpperString (const char *in, char *out, size_t size_out)
899 {
900         if (size_out == 0)
901                 return;
902
903         while (*in && size_out > 1)
904         {
905                 if (*in >= 'a' && *in <= 'z')
906                         *out++ = *in++ + 'A' - 'a';
907                 else
908                         *out++ = *in++;
909                 size_out--;
910         }
911         *out = '\0';
912 }
913
914 int COM_StringBeginsWith(const char *s, const char *match)
915 {
916         for (;*s && *match;s++, match++)
917                 if (*s != *match)
918                         return false;
919         return true;
920 }
921
922 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
923 {
924         int argc, commentprefixlength;
925         char *tokenbufend;
926         const char *l;
927         argc = 0;
928         tokenbufend = tokenbuf + tokenbufsize;
929         l = *text;
930         commentprefixlength = 0;
931         if (commentprefix)
932                 commentprefixlength = strlen(commentprefix);
933         while (*l && *l != '\n')
934         {
935                 if (*l > ' ')
936                 {
937                         if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
938                         {
939                                 while (*l && *l != '\n')
940                                         l++;
941                                 break;
942                         }
943                         if (argc >= maxargc)
944                                 return -1;
945                         argv[argc++] = tokenbuf;
946                         if (*l == '"')
947                         {
948                                 l++;
949                                 while (*l && *l != '"')
950                                 {
951                                         if (tokenbuf >= tokenbufend)
952                                                 return -1;
953                                         *tokenbuf++ = *l++;
954                                 }
955                                 if (*l == '"')
956                                         l++;
957                         }
958                         else
959                         {
960                                 while (*l > ' ')
961                                 {
962                                         if (tokenbuf >= tokenbufend)
963                                                 return -1;
964                                         *tokenbuf++ = *l++;
965                                 }
966                         }
967                         if (tokenbuf >= tokenbufend)
968                                 return -1;
969                         *tokenbuf++ = 0;
970                 }
971                 else
972                         l++;
973         }
974         if (*l == '\n')
975                 l++;
976         *text = l;
977         return argc;
978 }
979
980 // written by Elric, thanks Elric!
981 char *SearchInfostring(const char *infostring, const char *key)
982 {
983         static char value [256];
984         char crt_key [256];
985         size_t value_ind, key_ind;
986         char c;
987
988         if (*infostring++ != '\\')
989                 return NULL;
990
991         value_ind = 0;
992         for (;;)
993         {
994                 key_ind = 0;
995
996                 // Get the key name
997                 for (;;)
998                 {
999                         c = *infostring++;
1000
1001                         if (c == '\0')
1002                                 return NULL;
1003                         if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1004                         {
1005                                 crt_key[key_ind] = '\0';
1006                                 break;
1007                         }
1008
1009                         crt_key[key_ind++] = c;
1010                 }
1011
1012                 // If it's the key we are looking for, save it in "value"
1013                 if (!strcmp(crt_key, key))
1014                 {
1015                         for (;;)
1016                         {
1017                                 c = *infostring++;
1018
1019                                 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1020                                 {
1021                                         value[value_ind] = '\0';
1022                                         return value;
1023                                 }
1024
1025                                 value[value_ind++] = c;
1026                         }
1027                 }
1028
1029                 // Else, skip the value
1030                 for (;;)
1031                 {
1032                         c = *infostring++;
1033
1034                         if (c == '\0')
1035                                 return NULL;
1036                         if (c == '\\')
1037                                 break;
1038                 }
1039         }
1040 }
1041
1042
1043 //========================================================
1044 // strlcat and strlcpy, from OpenBSD
1045
1046 /*
1047  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1048  *
1049  * Permission to use, copy, modify, and distribute this software for any
1050  * purpose with or without fee is hereby granted, provided that the above
1051  * copyright notice and this permission notice appear in all copies.
1052  *
1053  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1054  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1055  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1056  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1057  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1058  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1059  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1060  */
1061
1062 /*      $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $    */
1063 /*      $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $     */
1064
1065
1066 #ifndef HAVE_STRLCAT
1067 size_t
1068 strlcat(char *dst, const char *src, size_t siz)
1069 {
1070         register char *d = dst;
1071         register const char *s = src;
1072         register size_t n = siz;
1073         size_t dlen;
1074
1075         /* Find the end of dst and adjust bytes left but don't go past end */
1076         while (n-- != 0 && *d != '\0')
1077                 d++;
1078         dlen = d - dst;
1079         n = siz - dlen;
1080
1081         if (n == 0)
1082                 return(dlen + strlen(s));
1083         while (*s != '\0') {
1084                 if (n != 1) {
1085                         *d++ = *s;
1086                         n--;
1087                 }
1088                 s++;
1089         }
1090         *d = '\0';
1091
1092         return(dlen + (s - src));       /* count does not include NUL */
1093 }
1094 #endif  // #ifndef HAVE_STRLCAT
1095
1096
1097 #ifndef HAVE_STRLCPY
1098 size_t
1099 strlcpy(char *dst, const char *src, size_t siz)
1100 {
1101         register char *d = dst;
1102         register const char *s = src;
1103         register size_t n = siz;
1104
1105         /* Copy as many bytes as will fit */
1106         if (n != 0 && --n != 0) {
1107                 do {
1108                         if ((*d++ = *s++) == 0)
1109                                 break;
1110                 } while (--n != 0);
1111         }
1112
1113         /* Not enough room in dst, add NUL and traverse rest of src */
1114         if (n == 0) {
1115                 if (siz != 0)
1116                         *d = '\0';              /* NUL-terminate dst */
1117                 while (*s++)
1118                         ;
1119         }
1120
1121         return(s - src - 1);    /* count does not include NUL */
1122 }
1123
1124 #endif  // #ifndef HAVE_STRLCPY