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