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