2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // common.c -- misc functions used in client and server
30 cvar_t registered = {0, "registered","0"};
31 cvar_t cmdline = {0, "cmdline","0"};
33 extern qboolean fs_modified; // set true if using non-id files
37 const char **com_argv;
39 // LordHavoc: made commandline 1024 characters instead of 256
40 #define CMDLINE_LENGTH 1024
41 char com_cmdline[CMDLINE_LENGTH];
46 char com_modname[MAX_OSPATH];
50 ============================================================================
54 ============================================================================
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);
66 short ShortSwap (short l)
76 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
77 short ShortNoSwap (short l)
92 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
95 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
96 int LongNoSwap (int l)
102 float FloatSwap (float 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];
119 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
120 float FloatNoSwap (float f)
127 // Extract integers from buffers
129 unsigned int BuffBigLong (const qbyte *buffer)
131 return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
134 unsigned short BuffBigShort (const qbyte *buffer)
136 return (buffer[0] << 8) | buffer[1];
139 unsigned int BuffLittleLong (const qbyte *buffer)
141 return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
144 unsigned short BuffLittleShort (const qbyte *buffer)
146 return (buffer[1] << 8) | buffer[0];
151 ==============================================================================
155 Handles byte ordering and avoids alignment errors
156 ==============================================================================
163 void MSG_WriteChar (sizebuf_t *sb, int c)
167 buf = SZ_GetSpace (sb, 1);
171 void MSG_WriteByte (sizebuf_t *sb, int c)
175 buf = SZ_GetSpace (sb, 1);
179 void MSG_WriteShort (sizebuf_t *sb, int c)
183 buf = SZ_GetSpace (sb, 2);
188 void MSG_WriteLong (sizebuf_t *sb, int c)
192 buf = SZ_GetSpace (sb, 4);
194 buf[1] = (c>>8)&0xff;
195 buf[2] = (c>>16)&0xff;
199 void MSG_WriteFloat (sizebuf_t *sb, float f)
209 dat.l = LittleLong (dat.l);
211 SZ_Write (sb, &dat.l, 4);
214 void MSG_WriteString (sizebuf_t *sb, const char *s)
217 SZ_Write (sb, "", 1);
219 SZ_Write (sb, s, strlen(s)+1);
222 // used by server (always latest PROTOCOL_DARKPLACES)
223 void MSG_WriteDPCoord (sizebuf_t *sb, float f)
226 MSG_WriteShort (sb, (int)(f + 0.5f));
228 MSG_WriteShort (sb, (int)(f - 0.5f));
231 void MSG_WritePreciseAngle (sizebuf_t *sb, float f)
234 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
236 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535);
239 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
240 void MSG_WriteAngle (sizebuf_t *sb, float f)
243 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
245 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) - 0.5f) & 255);
252 qboolean msg_badread;
254 void MSG_BeginReading (void)
260 int MSG_ReadLittleShort (void)
262 if (msg_readcount+2 > net_message.cursize)
268 return (short)(net_message.data[msg_readcount-2] | (net_message.data[msg_readcount-1]<<8));
271 int MSG_ReadBigShort (void)
273 if (msg_readcount+2 > net_message.cursize)
279 return (short)((net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1]);
282 int MSG_ReadLittleLong (void)
284 if (msg_readcount+4 > net_message.cursize)
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);
293 int MSG_ReadBigLong (void)
295 if (msg_readcount+4 > net_message.cursize)
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];
304 float MSG_ReadLittleFloat (void)
311 if (msg_readcount+4 > net_message.cursize)
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);
321 float MSG_ReadBigFloat (void)
328 if (msg_readcount+4 > net_message.cursize)
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];
338 char *MSG_ReadString (void)
340 static char string[2048];
342 for (l = 0;l < (int) sizeof(string) - 1 && (c = MSG_ReadChar()) != -1 && c != 0;l++)
348 int MSG_ReadBytes (int numbytes, unsigned char *out)
351 for (l = 0;l < numbytes && (c = MSG_ReadChar()) != -1;l++)
356 // used by server (always latest PROTOCOL_DARKPLACES)
357 float MSG_ReadDPCoord (void)
359 return (signed short) MSG_ReadLittleShort();
363 float MSG_ReadCoord (void)
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();
370 return MSG_ReadLittleShort() * (1.0f/8.0f);
374 //===========================================================================
376 void SZ_Alloc (sizebuf_t *buf, int startsize, const char *name)
380 buf->mempool = Mem_AllocPool(name);
381 buf->data = Mem_Alloc(buf->mempool, startsize);
382 buf->maxsize = startsize;
387 void SZ_Free (sizebuf_t *buf)
389 Mem_FreePool(&buf->mempool);
395 void SZ_Clear (sizebuf_t *buf)
400 void *SZ_GetSpace (sizebuf_t *buf, int length)
404 if (buf->cursize + length > buf->maxsize)
406 if (!buf->allowoverflow)
407 Host_Error ("SZ_GetSpace: overflow without allowoverflow set\n");
409 if (length > buf->maxsize)
410 Host_Error ("SZ_GetSpace: %i is > full buffer size\n", length);
412 buf->overflowed = true;
413 Con_Printf ("SZ_GetSpace: overflow\n");
417 data = buf->data + buf->cursize;
418 buf->cursize += length;
423 void SZ_Write (sizebuf_t *buf, const void *data, int length)
425 memcpy (SZ_GetSpace(buf,length),data,length);
428 void SZ_Print (sizebuf_t *buf, const char *data)
431 len = strlen(data)+1;
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
437 memcpy ((qbyte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
440 static char *hexchar = "0123456789ABCDEF";
441 void Com_HexDumpToConsole(const qbyte *data, int size)
445 char *cur, *flushpointer;
448 flushpointer = text + 512;
449 for (i = 0;i < size;)
455 *cur++ = hexchar[(i >> 12) & 15];
456 *cur++ = hexchar[(i >> 8) & 15];
457 *cur++ = hexchar[(i >> 4) & 15];
458 *cur++ = hexchar[(i >> 0) & 15];
460 for (j = 0;j < n;j++)
464 *cur++ = hexchar[(d[j] >> 4) & 15] | 0x80;
465 *cur++ = hexchar[(d[j] >> 0) & 15] | 0x80;
469 *cur++ = hexchar[(d[j] >> 4) & 15];
470 *cur++ = hexchar[(d[j] >> 0) & 15];
478 for (j = 0;j < n;j++)
479 *cur++ = (d[j] >= ' ' && d[j] <= 0x7E) ? d[j] : '.';
484 if (cur >= flushpointer || i >= size)
487 Con_Printf("%s", text);
493 void SZ_HexDumpToConsole(const sizebuf_t *buf)
495 Com_HexDumpToConsole(buf->data, buf->cursize);
499 //============================================================================
506 Parse a token out of a string
509 int COM_ParseToken(const char **datapointer, int returnnewline)
513 const char *data = *datapointer;
526 while ((c = *data) <= ' ' && (c != '\n' || !returnnewline))
537 // check if it's a comment
543 while (*data && *data != '\n')
550 while (*data && (*data != '*' || data[1] != '/'))
557 // handle quoted strings specially
575 // parse single characters
576 if (c == '{' || c == '}' || c == ')' || c == '(' || c == ']' || c == '[' || c == '\'' || c == ':' || c == ',' || c == ';' || c == '\n')
581 *datapointer = data+1;
585 // parse a regular word
592 if (c == '{' || c == '}' || c == ')' || c == '(' || c == ']' || c == '[' || c == '\'' || c == ':' || c == ',' || c == ';')
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
610 int COM_CheckParm (const char *parm)
614 for (i=1 ; i<com_argc ; i++)
617 continue; // NEXTSTEP sometimes clears appkit vars.
618 if (!strcmp (parm,com_argv[i]))
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
635 void COM_CheckRegistered (void)
637 Cvar_Set ("cmdline", com_cmdline);
639 if (!FS_FileExists("gfx/pop.lmp"))
642 Con_Printf ("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
644 Con_Printf ("Playing shareware version.\n");
648 Cvar_Set ("registered", "1");
649 Con_Printf ("Playing registered version.\n");
658 void COM_InitArgv (void)
661 // reconstitute the command line for the cmdline externally visible cvar
663 for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
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++] = ' ';
676 void COM_InitGameType (void)
678 char name[MAX_OSPATH];
679 FS_StripExtension (com_argv[0], name, sizeof (name));
680 COM_ToLowerString (name, name, sizeof (name));
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"))
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;
705 gamemode = GAME_NORMAL;
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"))
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;
735 gamename = "DarkPlaces-Quake";
739 gamename = "Darkplaces-Hipnotic";
740 gamedirname = "hipnotic";
743 gamename = "Darkplaces-Rogue";
744 gamedirname = "rogue";
747 gamename = "DarkPlaces-Nehahra";
748 gamedirname = "nehahra";
752 gamedirname = "data";
754 case GAME_TRANSFUSION:
755 gamename = "Transfusion";
756 gamedirname = "transfusion";
758 case GAME_GOODVSBAD2:
759 gamename = "GoodVs.Bad2";
763 gamename = "TheEvilUnleashed";
764 gamedirname = "baseteu";
766 case GAME_BATTLEMECH:
767 gamename = "Battlemech";
768 gamedirname = "base";
771 gamename = "Zymotic";
772 gamedirname = "data";
775 gamename = "Fniggium";
776 gamedirname = "data";
779 gamename = "Setheral";
780 gamedirname = "data";
783 Sys_Error("COM_InitGameType: unknown gamemode %i\n", gamemode);
789 extern void Mathlib_Init(void);
790 extern void FS_Init (void);
799 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
800 qbyte swaptest[2] = {1,0};
802 // set the byte swapping variables in a portable manner
803 if ( *(short *)swaptest == 1)
805 BigShort = ShortSwap;
806 LittleShort = ShortNoSwap;
808 LittleLong = LongNoSwap;
809 BigFloat = FloatSwap;
810 LittleFloat = FloatNoSwap;
814 BigShort = ShortNoSwap;
815 LittleShort = ShortSwap;
816 BigLong = LongNoSwap;
817 LittleLong = LongSwap;
818 BigFloat = FloatNoSwap;
819 LittleFloat = FloatSwap;
823 Cvar_RegisterVariable (®istered);
824 Cvar_RegisterVariable (&cmdline);
830 COM_CheckRegistered ();
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
845 char *va(const char *format, ...)
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;
852 s = string[stringindex];
853 stringindex = (stringindex + 1) & 7;
854 va_start (argptr, format);
855 vsnprintf (s, sizeof (string[0]), format,argptr);
862 //======================================
864 void COM_ToLowerString (const char *in, char *out, size_t size_out)
869 while (*in && size_out > 1)
871 if (*in >= 'A' && *in <= 'Z')
872 *out++ = *in++ + 'a' - 'A';
880 void COM_ToUpperString (const char *in, char *out, size_t size_out)
885 while (*in && size_out > 1)
887 if (*in >= 'a' && *in <= 'z')
888 *out++ = *in++ + 'A' - 'a';
896 int COM_StringBeginsWith(const char *s, const char *match)
898 for (;*s && *match;s++, match++)
904 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
906 int argc, commentprefixlength;
910 tokenbufend = tokenbuf + tokenbufsize;
912 commentprefixlength = 0;
914 commentprefixlength = strlen(commentprefix);
915 while (*l && *l != '\n')
919 if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
921 while (*l && *l != '\n')
927 argv[argc++] = tokenbuf;
931 while (*l && *l != '"')
933 if (tokenbuf >= tokenbufend)
944 if (tokenbuf >= tokenbufend)
949 if (tokenbuf >= tokenbufend)
962 // written by Elric, thanks Elric!
963 char *SearchInfostring(const char *infostring, const char *key)
965 static char value [256];
967 size_t value_ind, key_ind;
970 if (*infostring++ != '\\')
985 if (c == '\\' || key_ind == sizeof (crt_key) - 1)
987 crt_key[key_ind] = '\0';
991 crt_key[key_ind++] = c;
994 // If it's the key we are looking for, save it in "value"
995 if (!strcmp(crt_key, key))
1001 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1003 value[value_ind] = '\0';
1007 value[value_ind++] = c;
1011 // Else, skip the value
1025 //========================================================
1026 // strlcat and strlcpy, from OpenBSD
1029 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
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.
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.
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 $ */
1048 // Most (all?) BSDs already have them
1049 #if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__)
1052 strlcat(char *dst, const char *src, size_t siz)
1054 register char *d = dst;
1055 register const char *s = src;
1056 register size_t n = siz;
1059 /* Find the end of dst and adjust bytes left but don't go past end */
1060 while (n-- != 0 && *d != '\0')
1066 return(dlen + strlen(s));
1067 while (*s != '\0') {
1076 return(dlen + (s - src)); /* count does not include NUL */
1080 strlcpy(char *dst, const char *src, size_t siz)
1082 register char *d = dst;
1083 register const char *s = src;
1084 register size_t n = siz;
1086 /* Copy as many bytes as will fit */
1087 if (n != 0 && --n != 0) {
1089 if ((*d++ = *s++) == 0)
1094 /* Not enough room in dst, add NUL and traverse rest of src */
1097 *d = '\0'; /* NUL-terminate dst */
1102 return(s - src - 1); /* count does not include NUL */
1105 #endif // #if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__)