]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - common.c
added Math_atov function (ascii to vector), tries to parse any imaginable vector...
[xonotic/darkplaces.git] / common.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // common.c -- misc functions used in client and server
21
22 #include <stdlib.h>
23 #include <fcntl.h>
24 #ifndef WIN32
25 #include <unistd.h>
26 #endif
27
28 #include "quakedef.h"
29
30 cvar_t registered = {0, "registered","0"};
31 cvar_t cmdline = {0, "cmdline","0"};
32
33 extern qboolean fs_modified;   // set true if using non-id files
34
35 char com_token[1024];
36 int com_argc;
37 const char **com_argv;
38
39 // LordHavoc: made commandline 1024 characters instead of 256
40 #define CMDLINE_LENGTH  1024
41 char com_cmdline[CMDLINE_LENGTH];
42
43 int gamemode;
44 char *gamename;
45 char *gamedirname;
46 char com_modname[MAX_OSPATH];
47
48
49 /*
50 ============================================================================
51
52                                         BYTE ORDER FUNCTIONS
53
54 ============================================================================
55 */
56
57 #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 ==============================================================================
128
129                         MESSAGE IO FUNCTIONS
130
131 Handles byte ordering and avoids alignment errors
132 ==============================================================================
133 */
134
135 //
136 // writing functions
137 //
138
139 void MSG_WriteChar (sizebuf_t *sb, int c)
140 {
141         qbyte    *buf;
142         
143         buf = SZ_GetSpace (sb, 1);
144         buf[0] = c;
145 }
146
147 void MSG_WriteByte (sizebuf_t *sb, int c)
148 {
149         qbyte    *buf;
150         
151         buf = SZ_GetSpace (sb, 1);
152         buf[0] = c;
153 }
154
155 void MSG_WriteShort (sizebuf_t *sb, int c)
156 {
157         qbyte    *buf;
158
159         buf = SZ_GetSpace (sb, 2);
160         buf[0] = c&0xff;
161         buf[1] = c>>8;
162 }
163
164 void MSG_WriteLong (sizebuf_t *sb, int c)
165 {
166         qbyte    *buf;
167
168         buf = SZ_GetSpace (sb, 4);
169         buf[0] = c&0xff;
170         buf[1] = (c>>8)&0xff;
171         buf[2] = (c>>16)&0xff;
172         buf[3] = c>>24;
173 }
174
175 void MSG_WriteFloat (sizebuf_t *sb, float f)
176 {
177         union
178         {
179                 float   f;
180                 int     l;
181         } dat;
182
183
184         dat.f = f;
185         dat.l = LittleLong (dat.l);
186
187         SZ_Write (sb, &dat.l, 4);
188 }
189
190 void MSG_WriteString (sizebuf_t *sb, const char *s)
191 {
192         if (!s)
193                 SZ_Write (sb, "", 1);
194         else
195                 SZ_Write (sb, s, strlen(s)+1);
196 }
197
198 // used by server (always latest dpprotocol)
199 void MSG_WriteDPCoord (sizebuf_t *sb, float f)
200 {
201         if (f >= 0)
202                 MSG_WriteShort (sb, (int)(f + 0.5f));
203         else
204                 MSG_WriteShort (sb, (int)(f - 0.5f));
205 }
206
207 void MSG_WritePreciseAngle (sizebuf_t *sb, float f)
208 {
209         if (f >= 0)
210                 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
211         else
212                 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535);
213 }
214
215 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
216 void MSG_WriteAngle (sizebuf_t *sb, float f)
217 {
218         if (f >= 0)
219                 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
220         else
221                 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) - 0.5f) & 255);
222 }
223
224 //
225 // reading functions
226 //
227 int msg_readcount;
228 qboolean msg_badread;
229
230 void MSG_BeginReading (void)
231 {
232         msg_readcount = 0;
233         msg_badread = false;
234 }
235
236 int MSG_ReadShort (void)
237 {
238         int c;
239
240         if (msg_readcount+2 > net_message.cursize)
241         {
242                 msg_badread = true;
243                 return -1;
244         }
245
246         c = (short)(net_message.data[msg_readcount]
247         + (net_message.data[msg_readcount+1]<<8));
248
249         msg_readcount += 2;
250
251         return c;
252 }
253
254 int MSG_ReadLong (void)
255 {
256         int c;
257
258         if (msg_readcount+4 > net_message.cursize)
259         {
260                 msg_badread = true;
261                 return -1;
262         }
263
264         c = net_message.data[msg_readcount]
265         + (net_message.data[msg_readcount+1]<<8)
266         + (net_message.data[msg_readcount+2]<<16)
267         + (net_message.data[msg_readcount+3]<<24);
268
269         msg_readcount += 4;
270
271         return c;
272 }
273
274 float MSG_ReadFloat (void)
275 {
276         union
277         {
278                 qbyte b[4];
279                 float f;
280                 int l;
281         } dat;
282
283         dat.b[0] =      net_message.data[msg_readcount];
284         dat.b[1] =      net_message.data[msg_readcount+1];
285         dat.b[2] =      net_message.data[msg_readcount+2];
286         dat.b[3] =      net_message.data[msg_readcount+3];
287         msg_readcount += 4;
288
289         dat.l = LittleLong (dat.l);
290
291         return dat.f;
292 }
293
294 char *MSG_ReadString (void)
295 {
296         static char string[2048];
297         int l,c;
298
299         l = 0;
300         do
301         {
302                 c = MSG_ReadChar ();
303                 if (c == -1 || c == 0)
304                         break;
305                 string[l] = c;
306                 l++;
307         } while (l < (int)sizeof(string)-1);
308
309         string[l] = 0;
310
311         return string;
312 }
313
314 // used by server (always latest dpprotocol)
315 float MSG_ReadDPCoord (void)
316 {
317         return (signed short) MSG_ReadShort();
318 }
319
320 // used by client
321 float MSG_ReadCoord (void)
322 {
323         if (dpprotocol == DPPROTOCOL_VERSION2 || dpprotocol == DPPROTOCOL_VERSION3)
324                 return (signed short) MSG_ReadShort();
325         else if (dpprotocol == DPPROTOCOL_VERSION1)
326                 return MSG_ReadFloat();
327         else
328                 return MSG_ReadShort() * (1.0f/8.0f);
329 }
330
331
332 //===========================================================================
333
334 void SZ_Alloc (sizebuf_t *buf, int startsize, const char *name)
335 {
336         if (startsize < 256)
337                 startsize = 256;
338         buf->mempool = Mem_AllocPool(name);
339         buf->data = Mem_Alloc(buf->mempool, startsize);
340         buf->maxsize = startsize;
341         buf->cursize = 0;
342 }
343
344
345 void SZ_Free (sizebuf_t *buf)
346 {
347         Mem_FreePool(&buf->mempool);
348         buf->data = NULL;
349         buf->maxsize = 0;
350         buf->cursize = 0;
351 }
352
353 void SZ_Clear (sizebuf_t *buf)
354 {
355         buf->cursize = 0;
356 }
357
358 void *SZ_GetSpace (sizebuf_t *buf, int length)
359 {
360         void *data;
361
362         if (buf->cursize + length > buf->maxsize)
363         {
364                 if (!buf->allowoverflow)
365                         Host_Error ("SZ_GetSpace: overflow without allowoverflow set\n");
366
367                 if (length > buf->maxsize)
368                         Host_Error ("SZ_GetSpace: %i is > full buffer size\n", length);
369
370                 buf->overflowed = true;
371                 Con_Printf ("SZ_GetSpace: overflow\n");
372                 SZ_Clear (buf);
373         }
374
375         data = buf->data + buf->cursize;
376         buf->cursize += length;
377
378         return data;
379 }
380
381 void SZ_Write (sizebuf_t *buf, const void *data, int length)
382 {
383         memcpy (SZ_GetSpace(buf,length),data,length);
384 }
385
386 void SZ_Print (sizebuf_t *buf, const char *data)
387 {
388         int len;
389         len = strlen(data)+1;
390
391 // byte * cast to keep VC++ happy
392         if (buf->data[buf->cursize-1])
393                 memcpy ((qbyte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
394         else
395                 memcpy ((qbyte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
396 }
397
398 static char *hexchar = "0123456789ABCDEF";
399 void Com_HexDumpToConsole(const qbyte *data, int size)
400 {
401         int i, j, n;
402         char text[1024];
403         char *cur, *flushpointer;
404         const qbyte *d;
405         cur = text;
406         flushpointer = text + 512;
407         for (i = 0;i < size;)
408         {
409                 n = 16;
410                 if (n > size - i)
411                         n = size - i;
412                 d = data + i;
413                 *cur++ = hexchar[(i >> 12) & 15];
414                 *cur++ = hexchar[(i >>  8) & 15];
415                 *cur++ = hexchar[(i >>  4) & 15];
416                 *cur++ = hexchar[(i >>  0) & 15];
417                 *cur++ = ':';
418                 for (j = 0;j < n;j++)
419                 {
420                         if (j & 1)
421                         {
422                                 *cur++ = hexchar[(d[j] >> 4) & 15] | 0x80;
423                                 *cur++ = hexchar[(d[j] >> 0) & 15] | 0x80;
424                         }
425                         else
426                         {
427                                 *cur++ = hexchar[(d[j] >> 4) & 15];
428                                 *cur++ = hexchar[(d[j] >> 0) & 15];
429                         }
430                 }
431                 for (;j < 16;j++)
432                 {
433                         *cur++ = ' ';
434                         *cur++ = ' ';
435                 }
436                 for (j = 0;j < n;j++)
437                         *cur++ = (d[j] >= ' ' && d[j] <= 0x7E) ? d[j] : '.';
438                 for (;j < 16;j++)
439                         *cur++ = ' ';
440                 *cur++ = '\n';
441                 i += n;
442                 if (cur >= flushpointer || i >= size)
443                 {
444                         *cur++ = 0;
445                         Con_Printf("%s", text);
446                         cur = text;
447                 }
448         }
449 }
450
451 void SZ_HexDumpToConsole(const sizebuf_t *buf)
452 {
453         Com_HexDumpToConsole(buf->data, buf->cursize);
454 }
455
456
457 //============================================================================
458
459
460 /*
461 ==============
462 COM_ParseToken
463
464 Parse a token out of a string
465 ==============
466 */
467 int COM_ParseToken (const char **datapointer)
468 {
469         int c;
470         int len;
471         const char *data = *datapointer;
472
473         len = 0;
474         com_token[0] = 0;
475
476         if (!data)
477         {
478                 *datapointer = NULL;
479                 return false;
480         }
481
482 // skip whitespace
483 skipwhite:
484         while ((c = *data) <= ' ')
485         {
486                 if (c == 0)
487                 {
488                         // end of file
489                         *datapointer = NULL;
490                         return false;
491                 }
492                 data++;
493         }
494
495 // skip // comments
496         if (c=='/' && data[1] == '/')
497         {
498                 while (*data && *data != '\n')
499                         data++;
500                 goto skipwhite;
501         }
502
503
504 // handle quoted strings specially
505         if (c == '\"')
506         {
507                 data++;
508                 while (1)
509                 {
510                         c = *data++;
511                         if (c=='\"' || !c)
512                         {
513                                 com_token[len] = 0;
514                                 *datapointer = data;
515                                 return true;
516                         }
517                         com_token[len] = c;
518                         len++;
519                 }
520         }
521
522 // parse single characters
523         if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
524         {
525                 com_token[len] = c;
526                 len++;
527                 com_token[len] = 0;
528                 *datapointer = data+1;
529                 return true;
530         }
531
532 // parse a regular word
533         do
534         {
535                 com_token[len] = c;
536                 data++;
537                 len++;
538                 c = *data;
539                 if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
540                         break;
541         } while (c>32);
542
543         com_token[len] = 0;
544         *datapointer = data;
545         return true;
546 }
547
548
549 /*
550 ================
551 COM_CheckParm
552
553 Returns the position (1 to argc-1) in the program's argument list
554 where the given parameter apears, or 0 if not present
555 ================
556 */
557 int COM_CheckParm (const char *parm)
558 {
559         int i;
560
561         for (i=1 ; i<com_argc ; i++)
562         {
563                 if (!com_argv[i])
564                         continue;               // NEXTSTEP sometimes clears appkit vars.
565                 if (!strcmp (parm,com_argv[i]))
566                         return i;
567         }
568
569         return 0;
570 }
571
572 /*
573 ================
574 COM_CheckRegistered
575
576 Looks for the pop.txt file and verifies it.
577 Sets the "registered" cvar.
578 Immediately exits out if an alternate game was attempted to be started without
579 being registered.
580 ================
581 */
582 void COM_CheckRegistered (void)
583 {
584         Cvar_Set ("cmdline", com_cmdline);
585
586         if (!FS_FileExists("gfx/pop.lmp"))
587         {
588                 if (fs_modified)
589                         Con_Printf ("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
590                 else
591                         Con_Printf ("Playing shareware version.\n");
592                 return;
593         }
594
595         Cvar_Set ("registered", "1");
596         Con_Printf ("Playing registered version.\n");
597 }
598
599
600 /*
601 ================
602 COM_InitArgv
603 ================
604 */
605 void COM_InitArgv (void)
606 {
607         int i, j, n;
608         // reconstitute the command line for the cmdline externally visible cvar
609         n = 0;
610         for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
611         {
612                 i = 0;
613                 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
614                         com_cmdline[n++] = com_argv[j][i++];
615                 if (n < (CMDLINE_LENGTH - 1))
616                         com_cmdline[n++] = ' ';
617                 else
618                         break;
619         }
620         com_cmdline[n] = 0;
621 }
622
623 void COM_InitGameType (void)
624 {
625         char name[MAX_OSPATH];
626         FS_StripExtension(com_argv[0], name);
627         COM_ToLowerString(name, name);
628
629         if (strstr(name, "transfusion"))
630                 gamemode = GAME_TRANSFUSION;
631         else if (strstr(name, "nexiuz"))
632                 gamemode = GAME_NEXIUZ;
633         else if (strstr(name, "nehahra"))
634                 gamemode = GAME_NEHAHRA;
635         else if (strstr(name, "hipnotic"))
636                 gamemode = GAME_HIPNOTIC;
637         else if (strstr(name, "rogue"))
638                 gamemode = GAME_ROGUE;
639         else
640                 gamemode = GAME_NORMAL;
641
642         if (COM_CheckParm ("-transfusion"))
643                 gamemode = GAME_TRANSFUSION;
644         else if (COM_CheckParm ("-nexiuz"))
645                 gamemode = GAME_NEXIUZ;
646         else if (COM_CheckParm ("-nehahra"))
647                 gamemode = GAME_NEHAHRA;
648         else if (COM_CheckParm ("-hipnotic"))
649                 gamemode = GAME_HIPNOTIC;
650         else if (COM_CheckParm ("-rogue"))
651                 gamemode = GAME_ROGUE;
652         else if (COM_CheckParm ("-quake"))
653                 gamemode = GAME_NORMAL;
654
655         switch(gamemode)
656         {
657         case GAME_NORMAL:
658                 gamename = "DarkPlaces-Quake";
659                 gamedirname = "";
660                 break;
661         case GAME_HIPNOTIC:
662                 gamename = "Darkplaces-Hipnotic";
663                 gamedirname = "hipnotic";
664                 break;
665         case GAME_ROGUE:
666                 gamename = "Darkplaces-Rogue";
667                 gamedirname = "rogue";
668                 break;
669         case GAME_NEHAHRA:
670                 gamename = "DarkPlaces-Nehahra";
671                 gamedirname = "nehahra";
672                 break;
673         case GAME_NEXIUZ:
674                 gamename = "Nexiuz";
675                 gamedirname = "data";
676                 break;
677         case GAME_TRANSFUSION:
678                 gamename = "Transfusion";
679                 gamedirname = "transfusion";
680                 break;
681         default:
682                 Sys_Error("COM_InitGameType: unknown gamemode %i\n", gamemode);
683                 break;
684         }
685 }
686
687
688 extern void Mathlib_Init(void);
689 extern void FS_Init (void);
690
691 /*
692 ================
693 COM_Init
694 ================
695 */
696 void COM_Init (void)
697 {
698 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
699         qbyte swaptest[2] = {1,0};
700
701 // set the byte swapping variables in a portable manner
702         if ( *(short *)swaptest == 1)
703         {
704                 BigShort = ShortSwap;
705                 LittleShort = ShortNoSwap;
706                 BigLong = LongSwap;
707                 LittleLong = LongNoSwap;
708                 BigFloat = FloatSwap;
709                 LittleFloat = FloatNoSwap;
710         }
711         else
712         {
713                 BigShort = ShortNoSwap;
714                 LittleShort = ShortSwap;
715                 BigLong = LongNoSwap;
716                 LittleLong = LongSwap;
717                 BigFloat = FloatNoSwap;
718                 LittleFloat = FloatSwap;
719         }
720 #endif
721
722         Cvar_RegisterVariable (&registered);
723         Cvar_RegisterVariable (&cmdline);
724
725         Mathlib_Init();
726
727         FS_Init ();
728         COM_CheckRegistered ();
729
730         COM_InitGameType();
731 }
732
733
734 /*
735 ============
736 va
737
738 does a varargs printf into a temp buffer, so I don't need to have
739 varargs versions of all text functions.
740 FIXME: make this buffer size safe someday
741 ============
742 */
743 char *va(const char *format, ...)
744 {
745         va_list argptr;
746         // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
747         static char string[8][1024], *s;
748         static int stringindex = 0;
749
750         s = string[stringindex];
751         stringindex = (stringindex + 1) & 7;
752         va_start (argptr, format);
753         vsprintf (s, format,argptr);
754         va_end (argptr);
755
756         return s;
757 }
758
759
760 //======================================
761 // LordHavoc: added these because they are useful
762
763 void COM_ToLowerString(const char *in, char *out)
764 {
765         while (*in)
766         {
767                 if (*in >= 'A' && *in <= 'Z')
768                         *out++ = *in++ + 'a' - 'A';
769                 else
770                         *out++ = *in++;
771         }
772 }
773
774 void COM_ToUpperString(const char *in, char *out)
775 {
776         while (*in)
777         {
778                 if (*in >= 'a' && *in <= 'z')
779                         *out++ = *in++ + 'A' - 'a';
780                 else
781                         *out++ = *in++;
782         }
783 }
784
785 int COM_StringBeginsWith(const char *s, const char *match)
786 {
787         for (;*s && *match;s++, match++)
788                 if (*s != *match)
789                         return false;
790         return true;
791 }