Elric added BuffBigLong, BuffBigShort, BuffLittleLong, and BuffLittleShort functions...
[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 dpprotocol)
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_ReadShort (void)
261 {
262         int c;
263
264         if (msg_readcount+2 > net_message.cursize)
265         {
266                 msg_badread = true;
267                 return -1;
268         }
269
270         c = (short)(net_message.data[msg_readcount]
271         + (net_message.data[msg_readcount+1]<<8));
272
273         msg_readcount += 2;
274
275         return c;
276 }
277
278 int MSG_ReadLong (void)
279 {
280         int c;
281
282         if (msg_readcount+4 > net_message.cursize)
283         {
284                 msg_badread = true;
285                 return -1;
286         }
287
288         c = net_message.data[msg_readcount]
289         + (net_message.data[msg_readcount+1]<<8)
290         + (net_message.data[msg_readcount+2]<<16)
291         + (net_message.data[msg_readcount+3]<<24);
292
293         msg_readcount += 4;
294
295         return c;
296 }
297
298 float MSG_ReadFloat (void)
299 {
300         union
301         {
302                 qbyte b[4];
303                 float f;
304                 int l;
305         } dat;
306
307         dat.b[0] =      net_message.data[msg_readcount];
308         dat.b[1] =      net_message.data[msg_readcount+1];
309         dat.b[2] =      net_message.data[msg_readcount+2];
310         dat.b[3] =      net_message.data[msg_readcount+3];
311         msg_readcount += 4;
312
313         dat.l = LittleLong (dat.l);
314
315         return dat.f;
316 }
317
318 char *MSG_ReadString (void)
319 {
320         static char string[2048];
321         int l,c;
322
323         l = 0;
324         do
325         {
326                 c = MSG_ReadChar ();
327                 if (c == -1 || c == 0)
328                         break;
329                 string[l] = c;
330                 l++;
331         } while (l < (int)sizeof(string)-1);
332
333         string[l] = 0;
334
335         return string;
336 }
337
338 // used by server (always latest dpprotocol)
339 float MSG_ReadDPCoord (void)
340 {
341         return (signed short) MSG_ReadShort();
342 }
343
344 // used by client
345 float MSG_ReadCoord (void)
346 {
347         if (dpprotocol == DPPROTOCOL_VERSION2 || dpprotocol == DPPROTOCOL_VERSION3)
348                 return (signed short) MSG_ReadShort();
349         else if (dpprotocol == DPPROTOCOL_VERSION1)
350                 return MSG_ReadFloat();
351         else
352                 return MSG_ReadShort() * (1.0f/8.0f);
353 }
354
355
356 //===========================================================================
357
358 void SZ_Alloc (sizebuf_t *buf, int startsize, const char *name)
359 {
360         if (startsize < 256)
361                 startsize = 256;
362         buf->mempool = Mem_AllocPool(name);
363         buf->data = Mem_Alloc(buf->mempool, startsize);
364         buf->maxsize = startsize;
365         buf->cursize = 0;
366 }
367
368
369 void SZ_Free (sizebuf_t *buf)
370 {
371         Mem_FreePool(&buf->mempool);
372         buf->data = NULL;
373         buf->maxsize = 0;
374         buf->cursize = 0;
375 }
376
377 void SZ_Clear (sizebuf_t *buf)
378 {
379         buf->cursize = 0;
380 }
381
382 void *SZ_GetSpace (sizebuf_t *buf, int length)
383 {
384         void *data;
385
386         if (buf->cursize + length > buf->maxsize)
387         {
388                 if (!buf->allowoverflow)
389                         Host_Error ("SZ_GetSpace: overflow without allowoverflow set\n");
390
391                 if (length > buf->maxsize)
392                         Host_Error ("SZ_GetSpace: %i is > full buffer size\n", length);
393
394                 buf->overflowed = true;
395                 Con_Printf ("SZ_GetSpace: overflow\n");
396                 SZ_Clear (buf);
397         }
398
399         data = buf->data + buf->cursize;
400         buf->cursize += length;
401
402         return data;
403 }
404
405 void SZ_Write (sizebuf_t *buf, const void *data, int length)
406 {
407         memcpy (SZ_GetSpace(buf,length),data,length);
408 }
409
410 void SZ_Print (sizebuf_t *buf, const char *data)
411 {
412         int len;
413         len = strlen(data)+1;
414
415 // byte * cast to keep VC++ happy
416         if (buf->data[buf->cursize-1])
417                 memcpy ((qbyte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
418         else
419                 memcpy ((qbyte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
420 }
421
422 static char *hexchar = "0123456789ABCDEF";
423 void Com_HexDumpToConsole(const qbyte *data, int size)
424 {
425         int i, j, n;
426         char text[1024];
427         char *cur, *flushpointer;
428         const qbyte *d;
429         cur = text;
430         flushpointer = text + 512;
431         for (i = 0;i < size;)
432         {
433                 n = 16;
434                 if (n > size - i)
435                         n = size - i;
436                 d = data + i;
437                 *cur++ = hexchar[(i >> 12) & 15];
438                 *cur++ = hexchar[(i >>  8) & 15];
439                 *cur++ = hexchar[(i >>  4) & 15];
440                 *cur++ = hexchar[(i >>  0) & 15];
441                 *cur++ = ':';
442                 for (j = 0;j < n;j++)
443                 {
444                         if (j & 1)
445                         {
446                                 *cur++ = hexchar[(d[j] >> 4) & 15] | 0x80;
447                                 *cur++ = hexchar[(d[j] >> 0) & 15] | 0x80;
448                         }
449                         else
450                         {
451                                 *cur++ = hexchar[(d[j] >> 4) & 15];
452                                 *cur++ = hexchar[(d[j] >> 0) & 15];
453                         }
454                 }
455                 for (;j < 16;j++)
456                 {
457                         *cur++ = ' ';
458                         *cur++ = ' ';
459                 }
460                 for (j = 0;j < n;j++)
461                         *cur++ = (d[j] >= ' ' && d[j] <= 0x7E) ? d[j] : '.';
462                 for (;j < 16;j++)
463                         *cur++ = ' ';
464                 *cur++ = '\n';
465                 i += n;
466                 if (cur >= flushpointer || i >= size)
467                 {
468                         *cur++ = 0;
469                         Con_Printf("%s", text);
470                         cur = text;
471                 }
472         }
473 }
474
475 void SZ_HexDumpToConsole(const sizebuf_t *buf)
476 {
477         Com_HexDumpToConsole(buf->data, buf->cursize);
478 }
479
480
481 //============================================================================
482
483
484 /*
485 ==============
486 COM_ParseToken
487
488 Parse a token out of a string
489 ==============
490 */
491 int COM_ParseToken (const char **datapointer)
492 {
493         int c;
494         int len;
495         const char *data = *datapointer;
496
497         len = 0;
498         com_token[0] = 0;
499
500         if (!data)
501         {
502                 *datapointer = NULL;
503                 return false;
504         }
505
506 // skip whitespace
507 skipwhite:
508         while ((c = *data) <= ' ')
509         {
510                 if (c == 0)
511                 {
512                         // end of file
513                         *datapointer = NULL;
514                         return false;
515                 }
516                 data++;
517         }
518
519 // skip // comments
520         if (c=='/' && data[1] == '/')
521         {
522                 while (*data && *data != '\n')
523                         data++;
524                 goto skipwhite;
525         }
526
527
528 // handle quoted strings specially
529         if (c == '\"')
530         {
531                 data++;
532                 while (1)
533                 {
534                         c = *data++;
535                         if (c=='\"' || !c)
536                         {
537                                 com_token[len] = 0;
538                                 *datapointer = data;
539                                 return true;
540                         }
541                         com_token[len] = c;
542                         len++;
543                 }
544         }
545
546 // parse single characters
547         if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
548         {
549                 com_token[len] = c;
550                 len++;
551                 com_token[len] = 0;
552                 *datapointer = data+1;
553                 return true;
554         }
555
556 // parse a regular word
557         do
558         {
559                 com_token[len] = c;
560                 data++;
561                 len++;
562                 c = *data;
563                 if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
564                         break;
565         } while (c>32);
566
567         com_token[len] = 0;
568         *datapointer = data;
569         return true;
570 }
571
572
573 /*
574 ================
575 COM_CheckParm
576
577 Returns the position (1 to argc-1) in the program's argument list
578 where the given parameter apears, or 0 if not present
579 ================
580 */
581 int COM_CheckParm (const char *parm)
582 {
583         int i;
584
585         for (i=1 ; i<com_argc ; i++)
586         {
587                 if (!com_argv[i])
588                         continue;               // NEXTSTEP sometimes clears appkit vars.
589                 if (!strcmp (parm,com_argv[i]))
590                         return i;
591         }
592
593         return 0;
594 }
595
596 /*
597 ================
598 COM_CheckRegistered
599
600 Looks for the pop.txt file and verifies it.
601 Sets the "registered" cvar.
602 Immediately exits out if an alternate game was attempted to be started without
603 being registered.
604 ================
605 */
606 void COM_CheckRegistered (void)
607 {
608         Cvar_Set ("cmdline", com_cmdline);
609
610         if (!FS_FileExists("gfx/pop.lmp"))
611         {
612                 if (fs_modified)
613                         Con_Printf ("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
614                 else
615                         Con_Printf ("Playing shareware version.\n");
616                 return;
617         }
618
619         Cvar_Set ("registered", "1");
620         Con_Printf ("Playing registered version.\n");
621 }
622
623
624 /*
625 ================
626 COM_InitArgv
627 ================
628 */
629 void COM_InitArgv (void)
630 {
631         int i, j, n;
632         // reconstitute the command line for the cmdline externally visible cvar
633         n = 0;
634         for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
635         {
636                 i = 0;
637                 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
638                         com_cmdline[n++] = com_argv[j][i++];
639                 if (n < (CMDLINE_LENGTH - 1))
640                         com_cmdline[n++] = ' ';
641                 else
642                         break;
643         }
644         com_cmdline[n] = 0;
645 }
646
647 void COM_InitGameType (void)
648 {
649         char name[MAX_OSPATH];
650         FS_StripExtension(com_argv[0], name);
651         COM_ToLowerString(name, name);
652
653         if (strstr(name, "transfusion"))
654                 gamemode = GAME_TRANSFUSION;
655         else if (strstr(name, "nexiuz"))
656                 gamemode = GAME_NEXIUZ;
657         else if (strstr(name, "nehahra"))
658                 gamemode = GAME_NEHAHRA;
659         else if (strstr(name, "hipnotic"))
660                 gamemode = GAME_HIPNOTIC;
661         else if (strstr(name, "rogue"))
662                 gamemode = GAME_ROGUE;
663         else
664                 gamemode = GAME_NORMAL;
665
666         if (COM_CheckParm ("-transfusion"))
667                 gamemode = GAME_TRANSFUSION;
668         else if (COM_CheckParm ("-nexiuz"))
669                 gamemode = GAME_NEXIUZ;
670         else if (COM_CheckParm ("-nehahra"))
671                 gamemode = GAME_NEHAHRA;
672         else if (COM_CheckParm ("-hipnotic"))
673                 gamemode = GAME_HIPNOTIC;
674         else if (COM_CheckParm ("-rogue"))
675                 gamemode = GAME_ROGUE;
676         else if (COM_CheckParm ("-quake"))
677                 gamemode = GAME_NORMAL;
678
679         switch(gamemode)
680         {
681         case GAME_NORMAL:
682                 gamename = "DarkPlaces-Quake";
683                 gamedirname = "";
684                 break;
685         case GAME_HIPNOTIC:
686                 gamename = "Darkplaces-Hipnotic";
687                 gamedirname = "hipnotic";
688                 break;
689         case GAME_ROGUE:
690                 gamename = "Darkplaces-Rogue";
691                 gamedirname = "rogue";
692                 break;
693         case GAME_NEHAHRA:
694                 gamename = "DarkPlaces-Nehahra";
695                 gamedirname = "nehahra";
696                 break;
697         case GAME_NEXIUZ:
698                 gamename = "Nexiuz";
699                 gamedirname = "data";
700                 break;
701         case GAME_TRANSFUSION:
702                 gamename = "Transfusion";
703                 gamedirname = "transfusion";
704                 break;
705         default:
706                 Sys_Error("COM_InitGameType: unknown gamemode %i\n", gamemode);
707                 break;
708         }
709 }
710
711
712 extern void Mathlib_Init(void);
713 extern void FS_Init (void);
714
715 /*
716 ================
717 COM_Init
718 ================
719 */
720 void COM_Init (void)
721 {
722 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
723         qbyte swaptest[2] = {1,0};
724
725 // set the byte swapping variables in a portable manner
726         if ( *(short *)swaptest == 1)
727         {
728                 BigShort = ShortSwap;
729                 LittleShort = ShortNoSwap;
730                 BigLong = LongSwap;
731                 LittleLong = LongNoSwap;
732                 BigFloat = FloatSwap;
733                 LittleFloat = FloatNoSwap;
734         }
735         else
736         {
737                 BigShort = ShortNoSwap;
738                 LittleShort = ShortSwap;
739                 BigLong = LongNoSwap;
740                 LittleLong = LongSwap;
741                 BigFloat = FloatNoSwap;
742                 LittleFloat = FloatSwap;
743         }
744 #endif
745
746         Cvar_RegisterVariable (&registered);
747         Cvar_RegisterVariable (&cmdline);
748
749         Mathlib_Init();
750
751         FS_Init ();
752         COM_CheckRegistered ();
753
754         COM_InitGameType();
755 }
756
757
758 /*
759 ============
760 va
761
762 does a varargs printf into a temp buffer, so I don't need to have
763 varargs versions of all text functions.
764 FIXME: make this buffer size safe someday
765 ============
766 */
767 char *va(const char *format, ...)
768 {
769         va_list argptr;
770         // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
771         static char string[8][1024], *s;
772         static int stringindex = 0;
773
774         s = string[stringindex];
775         stringindex = (stringindex + 1) & 7;
776         va_start (argptr, format);
777         vsprintf (s, format,argptr);
778         va_end (argptr);
779
780         return s;
781 }
782
783
784 //======================================
785 // LordHavoc: added these because they are useful
786
787 void COM_ToLowerString(const char *in, char *out)
788 {
789         while (*in)
790         {
791                 if (*in >= 'A' && *in <= 'Z')
792                         *out++ = *in++ + 'a' - 'A';
793                 else
794                         *out++ = *in++;
795         }
796 }
797
798 void COM_ToUpperString(const char *in, char *out)
799 {
800         while (*in)
801         {
802                 if (*in >= 'a' && *in <= 'z')
803                         *out++ = *in++ + 'A' - 'a';
804                 else
805                         *out++ = *in++;
806         }
807 }
808
809 int COM_StringBeginsWith(const char *s, const char *match)
810 {
811         for (;*s && *match;s++, match++)
812                 if (*s != *match)
813                         return false;
814         return true;
815 }