added GAME_FNIGGIUM and GAME_SETHERAL
[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 ================
604 COM_CheckParm
605
606 Returns the position (1 to argc-1) in the program's argument list
607 where the given parameter apears, or 0 if not present
608 ================
609 */
610 int COM_CheckParm (const char *parm)
611 {
612         int i;
613
614         for (i=1 ; i<com_argc ; i++)
615         {
616                 if (!com_argv[i])
617                         continue;               // NEXTSTEP sometimes clears appkit vars.
618                 if (!strcmp (parm,com_argv[i]))
619                         return i;
620         }
621
622         return 0;
623 }
624
625 /*
626 ================
627 COM_CheckRegistered
628
629 Looks for the pop.txt file and verifies it.
630 Sets the "registered" cvar.
631 Immediately exits out if an alternate game was attempted to be started without
632 being registered.
633 ================
634 */
635 void COM_CheckRegistered (void)
636 {
637         Cvar_Set ("cmdline", com_cmdline);
638
639         if (!FS_FileExists("gfx/pop.lmp"))
640         {
641                 if (fs_modified)
642                         Con_Printf ("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
643                 else
644                         Con_Printf ("Playing shareware version.\n");
645                 return;
646         }
647
648         Cvar_Set ("registered", "1");
649         Con_Printf ("Playing registered version.\n");
650 }
651
652
653 /*
654 ================
655 COM_InitArgv
656 ================
657 */
658 void COM_InitArgv (void)
659 {
660         int i, j, n;
661         // reconstitute the command line for the cmdline externally visible cvar
662         n = 0;
663         for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
664         {
665                 i = 0;
666                 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
667                         com_cmdline[n++] = com_argv[j][i++];
668                 if (n < (CMDLINE_LENGTH - 1))
669                         com_cmdline[n++] = ' ';
670                 else
671                         break;
672         }
673         com_cmdline[n] = 0;
674 }
675
676 void COM_InitGameType (void)
677 {
678         char name[MAX_OSPATH];
679         FS_StripExtension (com_argv[0], name, sizeof (name));
680         COM_ToLowerString (name, name, sizeof (name));
681
682         if (strstr(name, "transfusion"))
683                 gamemode = GAME_TRANSFUSION;
684         else if (strstr(name, "nexuiz"))
685                 gamemode = GAME_NEXUIZ;
686         else if (strstr(name, "nehahra"))
687                 gamemode = GAME_NEHAHRA;
688         else if (strstr(name, "hipnotic"))
689                 gamemode = GAME_HIPNOTIC;
690         else if (strstr(name, "rogue"))
691                 gamemode = GAME_ROGUE;
692         else if (strstr(name, "gvb2"))
693                 gamemode = GAME_GOODVSBAD2;
694         else if (strstr(name, "teu"))
695                 gamemode = GAME_TEU;
696         else if (strstr(name, "battlemech"))
697                 gamemode = GAME_BATTLEMECH;
698         else if (strstr(name, "zymotic"))
699                 gamemode = GAME_ZYMOTIC;
700         else if (strstr(name, "fniggium"))
701                 gamemode = GAME_FNIGGIUM;
702         else if (strstr(name, "setheral"))
703                 gamemode = GAME_SETHERAL;
704         else
705                 gamemode = GAME_NORMAL;
706
707         if (COM_CheckParm ("-transfusion"))
708                 gamemode = GAME_TRANSFUSION;
709         else if (COM_CheckParm ("-nexuiz"))
710                 gamemode = GAME_NEXUIZ;
711         else if (COM_CheckParm ("-nehahra"))
712                 gamemode = GAME_NEHAHRA;
713         else if (COM_CheckParm ("-hipnotic"))
714                 gamemode = GAME_HIPNOTIC;
715         else if (COM_CheckParm ("-rogue"))
716                 gamemode = GAME_ROGUE;
717         else if (COM_CheckParm ("-quake"))
718                 gamemode = GAME_NORMAL;
719         else if (COM_CheckParm ("-goodvsbad2"))
720                 gamemode = GAME_GOODVSBAD2;
721         else if (COM_CheckParm ("-teu"))
722                 gamemode = GAME_TEU;
723         else if (COM_CheckParm ("-battlemech"))
724                 gamemode = GAME_BATTLEMECH;
725         else if (COM_CheckParm ("-zymotic"))
726                 gamemode = GAME_ZYMOTIC;
727         else if (COM_CheckParm ("-fniggium"))
728                 gamemode = GAME_FNIGGIUM;
729         else if (COM_CheckParm ("-setheral"))
730                 gamemode = GAME_SETHERAL;
731
732         switch(gamemode)
733         {
734         case GAME_NORMAL:
735                 gamename = "DarkPlaces-Quake";
736                 gamedirname = "";
737                 break;
738         case GAME_HIPNOTIC:
739                 gamename = "Darkplaces-Hipnotic";
740                 gamedirname = "hipnotic";
741                 break;
742         case GAME_ROGUE:
743                 gamename = "Darkplaces-Rogue";
744                 gamedirname = "rogue";
745                 break;
746         case GAME_NEHAHRA:
747                 gamename = "DarkPlaces-Nehahra";
748                 gamedirname = "nehahra";
749                 break;
750         case GAME_NEXUIZ:
751                 gamename = "Nexuiz";
752                 gamedirname = "data";
753                 break;
754         case GAME_TRANSFUSION:
755                 gamename = "Transfusion";
756                 gamedirname = "transfusion";
757                 break;
758         case GAME_GOODVSBAD2:
759                 gamename = "GoodVs.Bad2";
760                 gamedirname = "rts";
761                 break;
762         case GAME_TEU:
763                 gamename = "TheEvilUnleashed";
764                 gamedirname = "baseteu";
765                 break;
766         case GAME_BATTLEMECH:
767                 gamename = "Battlemech";
768                 gamedirname = "base";
769                 break;
770         case GAME_ZYMOTIC:
771                 gamename = "Zymotic";
772                 gamedirname = "data";
773                 break;
774         case GAME_FNIGGIUM:
775                 gamename = "Fniggium";
776                 gamedirname = "data";
777                 break;
778         case GAME_SETHERAL:
779                 gamename = "Setheral";
780                 gamedirname = "data";
781                 break;
782         default:
783                 Sys_Error("COM_InitGameType: unknown gamemode %i\n", gamemode);
784                 break;
785         }
786 }
787
788
789 extern void Mathlib_Init(void);
790 extern void FS_Init (void);
791
792 /*
793 ================
794 COM_Init
795 ================
796 */
797 void COM_Init (void)
798 {
799 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
800         qbyte swaptest[2] = {1,0};
801
802 // set the byte swapping variables in a portable manner
803         if ( *(short *)swaptest == 1)
804         {
805                 BigShort = ShortSwap;
806                 LittleShort = ShortNoSwap;
807                 BigLong = LongSwap;
808                 LittleLong = LongNoSwap;
809                 BigFloat = FloatSwap;
810                 LittleFloat = FloatNoSwap;
811         }
812         else
813         {
814                 BigShort = ShortNoSwap;
815                 LittleShort = ShortSwap;
816                 BigLong = LongNoSwap;
817                 LittleLong = LongSwap;
818                 BigFloat = FloatNoSwap;
819                 LittleFloat = FloatSwap;
820         }
821 #endif
822
823         Cvar_RegisterVariable (&registered);
824         Cvar_RegisterVariable (&cmdline);
825
826         Mathlib_Init();
827
828         FS_Init ();
829         Con_InitLogging();
830         COM_CheckRegistered ();
831
832         COM_InitGameType();
833 }
834
835
836 /*
837 ============
838 va
839
840 does a varargs printf into a temp buffer, so I don't need to have
841 varargs versions of all text functions.
842 FIXME: make this buffer size safe someday
843 ============
844 */
845 char *va(const char *format, ...)
846 {
847         va_list argptr;
848         // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
849         static char string[8][1024], *s;
850         static int stringindex = 0;
851
852         s = string[stringindex];
853         stringindex = (stringindex + 1) & 7;
854         va_start (argptr, format);
855         vsnprintf (s, sizeof (string[0]), format,argptr);
856         va_end (argptr);
857
858         return s;
859 }
860
861
862 //======================================
863
864 void COM_ToLowerString (const char *in, char *out, size_t size_out)
865 {
866         if (size_out == 0)
867                 return;
868
869         while (*in && size_out > 1)
870         {
871                 if (*in >= 'A' && *in <= 'Z')
872                         *out++ = *in++ + 'a' - 'A';
873                 else
874                         *out++ = *in++;
875                 size_out--;
876         }
877         *out = '\0';
878 }
879
880 void COM_ToUpperString (const char *in, char *out, size_t size_out)
881 {
882         if (size_out == 0)
883                 return;
884
885         while (*in && size_out > 1)
886         {
887                 if (*in >= 'a' && *in <= 'z')
888                         *out++ = *in++ + 'A' - 'a';
889                 else
890                         *out++ = *in++;
891                 size_out--;
892         }
893         *out = '\0';
894 }
895
896 int COM_StringBeginsWith(const char *s, const char *match)
897 {
898         for (;*s && *match;s++, match++)
899                 if (*s != *match)
900                         return false;
901         return true;
902 }
903
904 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
905 {
906         int argc, commentprefixlength;
907         char *tokenbufend;
908         const char *l;
909         argc = 0;
910         tokenbufend = tokenbuf + tokenbufsize;
911         l = *text;
912         commentprefixlength = 0;
913         if (commentprefix)
914                 commentprefixlength = strlen(commentprefix);
915         while (*l && *l != '\n')
916         {
917                 if (*l > ' ')
918                 {
919                         if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
920                         {
921                                 while (*l && *l != '\n')
922                                         l++;
923                                 break;
924                         }
925                         if (argc >= maxargc)
926                                 return -1;
927                         argv[argc++] = tokenbuf;
928                         if (*l == '"')
929                         {
930                                 l++;
931                                 while (*l && *l != '"')
932                                 {
933                                         if (tokenbuf >= tokenbufend)
934                                                 return -1;
935                                         *tokenbuf++ = *l++;
936                                 }
937                                 if (*l == '"')
938                                         l++;
939                         }
940                         else
941                         {
942                                 while (*l > ' ')
943                                 {
944                                         if (tokenbuf >= tokenbufend)
945                                                 return -1;
946                                         *tokenbuf++ = *l++;
947                                 }
948                         }
949                         if (tokenbuf >= tokenbufend)
950                                 return -1;
951                         *tokenbuf++ = 0;
952                 }
953                 else
954                         l++;
955         }
956         if (*l == '\n')
957                 l++;
958         *text = l;
959         return argc;
960 }
961
962 // written by Elric, thanks Elric!
963 char *SearchInfostring(const char *infostring, const char *key)
964 {
965         static char value [256];
966         char crt_key [256];
967         size_t value_ind, key_ind;
968         char c;
969
970         if (*infostring++ != '\\')
971                 return NULL;
972
973         value_ind = 0;
974         for (;;)
975         {
976                 key_ind = 0;
977
978                 // Get the key name
979                 for (;;)
980                 {
981                         c = *infostring++;
982
983                         if (c == '\0')
984                                 return NULL;
985                         if (c == '\\' || key_ind == sizeof (crt_key) - 1)
986                         {
987                                 crt_key[key_ind] = '\0';
988                                 break;
989                         }
990
991                         crt_key[key_ind++] = c;
992                 }
993
994                 // If it's the key we are looking for, save it in "value"
995                 if (!strcmp(crt_key, key))
996                 {
997                         for (;;)
998                         {
999                                 c = *infostring++;
1000
1001                                 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1002                                 {
1003                                         value[value_ind] = '\0';
1004                                         return value;
1005                                 }
1006
1007                                 value[value_ind++] = c;
1008                         }
1009                 }
1010
1011                 // Else, skip the value
1012                 for (;;)
1013                 {
1014                         c = *infostring++;
1015
1016                         if (c == '\0')
1017                                 return NULL;
1018                         if (c == '\\')
1019                                 break;
1020                 }
1021         }
1022 }
1023
1024
1025 //========================================================
1026 // strlcat and strlcpy, from OpenBSD
1027
1028 /*
1029  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1030  *
1031  * Permission to use, copy, modify, and distribute this software for any
1032  * purpose with or without fee is hereby granted, provided that the above
1033  * copyright notice and this permission notice appear in all copies.
1034  *
1035  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1036  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1037  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1038  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1039  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1040  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1041  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1042  */
1043
1044 /*      $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $    */
1045 /*      $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $     */
1046
1047
1048 // Most (all?) BSDs already have them
1049 #if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__)
1050
1051 size_t
1052 strlcat(char *dst, const char *src, size_t siz)
1053 {
1054         register char *d = dst;
1055         register const char *s = src;
1056         register size_t n = siz;
1057         size_t dlen;
1058
1059         /* Find the end of dst and adjust bytes left but don't go past end */
1060         while (n-- != 0 && *d != '\0')
1061                 d++;
1062         dlen = d - dst;
1063         n = siz - dlen;
1064
1065         if (n == 0)
1066                 return(dlen + strlen(s));
1067         while (*s != '\0') {
1068                 if (n != 1) {
1069                         *d++ = *s;
1070                         n--;
1071                 }
1072                 s++;
1073         }
1074         *d = '\0';
1075
1076         return(dlen + (s - src));       /* count does not include NUL */
1077 }
1078
1079 size_t
1080 strlcpy(char *dst, const char *src, size_t siz)
1081 {
1082         register char *d = dst;
1083         register const char *s = src;
1084         register size_t n = siz;
1085
1086         /* Copy as many bytes as will fit */
1087         if (n != 0 && --n != 0) {
1088                 do {
1089                         if ((*d++ = *s++) == 0)
1090                                 break;
1091                 } while (--n != 0);
1092         }
1093
1094         /* Not enough room in dst, add NUL and traverse rest of src */
1095         if (n == 0) {
1096                 if (siz != 0)
1097                         *d = '\0';              /* NUL-terminate dst */
1098                 while (*s++)
1099                         ;
1100         }
1101
1102         return(s - src - 1);    /* count does not include NUL */
1103 }
1104
1105 #endif  // #if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__)