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];
45 const char *gamedirname;
46 const char *gamescreenshotname;
47 char com_modname[MAX_OSPATH] = "";
51 ============================================================================
55 ============================================================================
58 short ShortSwap (short l)
77 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
80 float FloatSwap (float f)
90 dat2.b[0] = dat1.b[3];
91 dat2.b[1] = dat1.b[2];
92 dat2.b[2] = dat1.b[1];
93 dat2.b[3] = dat1.b[0];
98 // Extract integers from buffers
100 unsigned int BuffBigLong (const qbyte *buffer)
102 return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
105 unsigned short BuffBigShort (const qbyte *buffer)
107 return (buffer[0] << 8) | buffer[1];
110 unsigned int BuffLittleLong (const qbyte *buffer)
112 return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
115 unsigned short BuffLittleShort (const qbyte *buffer)
117 return (buffer[1] << 8) | buffer[0];
122 ==============================================================================
126 Handles byte ordering and avoids alignment errors
127 ==============================================================================
134 void MSG_WriteChar (sizebuf_t *sb, int c)
138 buf = SZ_GetSpace (sb, 1);
142 void MSG_WriteByte (sizebuf_t *sb, int c)
146 buf = SZ_GetSpace (sb, 1);
150 void MSG_WriteShort (sizebuf_t *sb, int c)
154 buf = SZ_GetSpace (sb, 2);
159 void MSG_WriteLong (sizebuf_t *sb, int c)
163 buf = SZ_GetSpace (sb, 4);
165 buf[1] = (c>>8)&0xff;
166 buf[2] = (c>>16)&0xff;
170 void MSG_WriteFloat (sizebuf_t *sb, float f)
180 dat.l = LittleLong (dat.l);
182 SZ_Write (sb, &dat.l, 4);
185 void MSG_WriteString (sizebuf_t *sb, const char *s)
188 SZ_Write (sb, "", 1);
190 SZ_Write (sb, s, strlen(s)+1);
193 void MSG_WriteCoord13i (sizebuf_t *sb, float f)
196 MSG_WriteShort (sb, (int)(f * 8.0f + 0.5f));
198 MSG_WriteShort (sb, (int)(f * 8.0f - 0.5f));
201 void MSG_WriteCoord16i (sizebuf_t *sb, float f)
204 MSG_WriteShort (sb, (int)(f + 0.5f));
206 MSG_WriteShort (sb, (int)(f - 0.5f));
209 void MSG_WriteCoord32f (sizebuf_t *sb, float f)
211 MSG_WriteFloat (sb, f);
214 void MSG_WriteCoord (sizebuf_t *sb, float f, int protocol)
216 if (protocol == PROTOCOL_QUAKE)
217 MSG_WriteCoord13i (sb, f);
218 else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5)
219 MSG_WriteCoord32f (sb, f);
220 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
221 MSG_WriteCoord16i (sb, f);
223 Host_Error("MSG_WriteCoord: unknown protocol\n");
226 void MSG_WriteVector (sizebuf_t *sb, float *v, int protocol)
228 MSG_WriteCoord (sb, v[0], protocol);
229 MSG_WriteCoord (sb, v[1], protocol);
230 MSG_WriteCoord (sb, v[2], protocol);
233 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
234 void MSG_WriteAngle8i (sizebuf_t *sb, float f)
237 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
239 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) - 0.5f) & 255);
242 void MSG_WriteAngle16i (sizebuf_t *sb, float f)
245 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
247 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535);
250 void MSG_WriteAngle32f (sizebuf_t *sb, float f)
252 MSG_WriteFloat (sb, f);
260 qboolean msg_badread;
262 void MSG_BeginReading (void)
268 int MSG_ReadLittleShort (void)
270 if (msg_readcount+2 > net_message.cursize)
276 return (short)(net_message.data[msg_readcount-2] | (net_message.data[msg_readcount-1]<<8));
279 int MSG_ReadBigShort (void)
281 if (msg_readcount+2 > net_message.cursize)
287 return (short)((net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1]);
290 int MSG_ReadLittleLong (void)
292 if (msg_readcount+4 > net_message.cursize)
298 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);
301 int MSG_ReadBigLong (void)
303 if (msg_readcount+4 > net_message.cursize)
309 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];
312 float MSG_ReadLittleFloat (void)
319 if (msg_readcount+4 > net_message.cursize)
325 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);
329 float MSG_ReadBigFloat (void)
336 if (msg_readcount+4 > net_message.cursize)
342 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];
346 char *MSG_ReadString (void)
348 static char string[2048];
350 for (l = 0;l < (int) sizeof(string) - 1 && (c = MSG_ReadChar()) != -1 && c != 0;l++)
356 int MSG_ReadBytes (int numbytes, unsigned char *out)
359 for (l = 0;l < numbytes && (c = MSG_ReadChar()) != -1;l++)
364 float MSG_ReadCoord13i (void)
366 return MSG_ReadLittleShort() * (1.0f/8.0f);
369 float MSG_ReadCoord16i (void)
371 return (signed short) MSG_ReadLittleShort();
374 float MSG_ReadCoord32f (void)
376 return MSG_ReadLittleFloat();
379 float MSG_ReadCoord (int protocol)
381 if (protocol == PROTOCOL_QUAKE)
382 return MSG_ReadCoord13i();
383 else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5)
384 return MSG_ReadCoord32f();
385 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
386 return MSG_ReadCoord16i();
387 Host_Error("MSG_ReadCoord: unknown protocol\n");
391 void MSG_ReadVector (float *v, int protocol)
393 v[0] = MSG_ReadCoord(protocol);
394 v[1] = MSG_ReadCoord(protocol);
395 v[2] = MSG_ReadCoord(protocol);
398 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
399 float MSG_ReadAngle8i (void)
401 return MSG_ReadByte () * (360.0f/256.0f);
404 float MSG_ReadAngle16i (void)
406 return MSG_ReadShort () * (360.0f/65536.0f);
409 float MSG_ReadAngle32f (void)
411 return MSG_ReadFloat ();
415 //===========================================================================
417 void SZ_Alloc (sizebuf_t *buf, int startsize, const char *name)
421 buf->mempool = Mem_AllocPool(name, 0, NULL);
422 buf->data = Mem_Alloc(buf->mempool, startsize);
423 buf->maxsize = startsize;
428 void SZ_Free (sizebuf_t *buf)
430 Mem_FreePool(&buf->mempool);
436 void SZ_Clear (sizebuf_t *buf)
441 void *SZ_GetSpace (sizebuf_t *buf, int length)
445 if (buf->cursize + length > buf->maxsize)
447 if (!buf->allowoverflow)
448 Host_Error ("SZ_GetSpace: overflow without allowoverflow set\n");
450 if (length > buf->maxsize)
451 Host_Error ("SZ_GetSpace: %i is > full buffer size\n", length);
453 buf->overflowed = true;
454 Con_Print("SZ_GetSpace: overflow\n");
458 data = buf->data + buf->cursize;
459 buf->cursize += length;
464 void SZ_Write (sizebuf_t *buf, const void *data, int length)
466 memcpy (SZ_GetSpace(buf,length),data,length);
469 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
470 // attention, it has been eradicated from here, its only (former) use in
471 // all of darkplaces.
473 static char *hexchar = "0123456789ABCDEF";
474 void Com_HexDumpToConsole(const qbyte *data, int size)
478 char *cur, *flushpointer;
481 flushpointer = text + 512;
482 for (i = 0;i < size;)
489 *cur++ = hexchar[(i >> 12) & 15];
490 *cur++ = hexchar[(i >> 8) & 15];
491 *cur++ = hexchar[(i >> 4) & 15];
492 *cur++ = hexchar[(i >> 0) & 15];
495 for (j = 0;j < 16;j++)
499 *cur++ = hexchar[(d[j] >> 4) & 15];
500 *cur++ = hexchar[(d[j] >> 0) & 15];
511 for (j = 0;j < 16;j++)
515 if (d[j] >= ' ' && d[j] <= 127)
525 if (cur >= flushpointer || i >= size)
534 void SZ_HexDumpToConsole(const sizebuf_t *buf)
536 Com_HexDumpToConsole(buf->data, buf->cursize);
540 //============================================================================
547 Parse a token out of a string
550 int COM_ParseToken(const char **datapointer, int returnnewline)
553 const char *data = *datapointer;
566 for (;*data <= ' ' && (*data != '\n' || !returnnewline);data++)
576 if (data[0] == '/' && data[1] == '/')
579 while (*data && *data != '\n')
583 else if (data[0] == '/' && data[1] == '*')
587 while (*data && (data[0] != '*' || data[1] != '/'))
592 else if (*data == '\"')
595 for (data++;*data != '\"';data++)
597 if (!*data || len >= (int)sizeof(com_token) - 1)
603 com_token[len++] = *data;
606 *datapointer = data+1;
609 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == '\'' || *data == ':' || *data == ',' || *data == ';')
612 com_token[len++] = *data++;
620 for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != '\'' && *data != ':' && *data != ',' && *data != ';';data++)
622 if (len >= (int)sizeof(com_token) - 1)
628 com_token[len++] = *data;
638 COM_ParseTokenConsole
640 Parse a token out of a string, behaving like the qwcl console
643 int COM_ParseTokenConsole(const char **datapointer)
646 const char *data = *datapointer;
659 for (;*data <= ' ';data++)
669 if (*data == '/' && data[1] == '/')
672 while (*data && *data != '\n')
676 else if (*data == '\"')
679 for (data++;*data != '\"';data++)
681 if (!*data || len >= (int)sizeof(com_token) - 1)
687 com_token[len++] = *data;
690 *datapointer = data+1;
696 for (;*data > ' ';data++)
698 if (len >= (int)sizeof(com_token) - 1)
704 com_token[len++] = *data;
717 Returns the position (1 to argc-1) in the program's argument list
718 where the given parameter apears, or 0 if not present
721 int COM_CheckParm (const char *parm)
725 for (i=1 ; i<com_argc ; i++)
728 continue; // NEXTSTEP sometimes clears appkit vars.
729 if (!strcmp (parm,com_argv[i]))
740 Looks for the pop.txt file and verifies it.
741 Sets the "registered" cvar.
742 Immediately exits out if an alternate game was attempted to be started without
746 void COM_CheckRegistered (void)
748 Cvar_Set ("cmdline", com_cmdline);
750 if (!FS_FileExists("gfx/pop.lmp"))
753 Con_Print("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
755 Con_Print("Playing shareware version.\n");
759 Cvar_Set ("registered", "1");
760 Con_Print("Playing registered version.\n");
769 void COM_InitArgv (void)
772 // reconstitute the command line for the cmdline externally visible cvar
774 for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
777 if (strstr(com_argv[j], " "))
779 // arg contains whitespace, store quotes around it
780 com_cmdline[n++] = '\"';
781 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
782 com_cmdline[n++] = com_argv[j][i++];
783 com_cmdline[n++] = '\"';
787 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
788 com_cmdline[n++] = com_argv[j][i++];
790 if (n < (CMDLINE_LENGTH - 1))
791 com_cmdline[n++] = ' ';
799 //===========================================================================
805 const char* prog_name;
807 const char* gamename;
808 const char* gamedirname;
809 const char* gamescreenshotname;
812 static const gamemode_info_t gamemode_info [] =
813 {// prog_name cmdline gamename gamedirname gamescreenshotname
816 { "", "-quake", "DarkPlaces-Quake", "", "dp" },
818 { "hipnotic", "-hipnotic", "Darkplaces-Hipnotic", "hipnotic", "dp" },
820 { "rogue", "-rogue", "Darkplaces-Rogue", "rogue", "dp" },
822 { "nehahra", "-nehahra", "DarkPlaces-Nehahra", "nehahra", "dp" },
824 { "nexuiz", "-nexuiz", "Nexuiz", "data", "nexuiz" },
826 { "transfusion", "-transfusion", "Transfusion", "basetf", "transfusion" },
828 { "gvb2", "-goodvsbad2", "GoodVs.Bad2", "rts", "gvb2" },
830 { "teu", "-teu", "TheEvilUnleashed", "baseteu", "teu" },
832 { "battlemech", "-battlemech", "Battlemech", "base", "battlemech" },
834 { "zymotic", "-zymotic", "Zymotic", "data", "zymotic" },
836 { "fniggium", "-fniggium", "Fniggium", "data", "fniggium" },
838 { "setheral", "-setheral", "Setheral", "data", "setheral" },
840 { "som", "-som", "Son of Man", "sonofman", "som" },
842 { "tenebrae", "-tenebrae", "DarkPlaces-Tenebrae", "tenebrae", "dp" },
844 { "neoteric", "-neoteric", "Neoteric", "neobase", "neo" },
846 { "openquartz", "-openquartz", "OpenQuartz", "id1", "openquartz"},
848 { "prydon", "-prydon", "PrydonGate", "prydon", "prydon"},
850 { "netherworld", "-netherworld", "Dark Masters", "netherworld", "nw"},
853 void COM_InitGameType (void)
855 char name [MAX_OSPATH];
858 FS_StripExtension (com_argv[0], name, sizeof (name));
859 COM_ToLowerString (name, name, sizeof (name));
861 // Check the binary name; default to GAME_NORMAL (0)
862 gamemode = GAME_NORMAL;
863 for (i = 1; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
864 if (strstr (name, gamemode_info[i].prog_name))
870 // Look for a command-line option
871 for (i = 0; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
872 if (COM_CheckParm (gamemode_info[i].cmdline))
878 gamename = gamemode_info[gamemode].gamename;
879 gamedirname = gamemode_info[gamemode].gamedirname;
880 gamescreenshotname = gamemode_info[gamemode].gamescreenshotname;
884 extern void Mathlib_Init(void);
885 extern void FS_Init (void);
894 Cvar_RegisterVariable (®istered);
895 Cvar_RegisterVariable (&cmdline);
901 COM_CheckRegistered ();
909 does a varargs printf into a temp buffer, so I don't need to have
910 varargs versions of all text functions.
911 FIXME: make this buffer size safe someday
914 char *va(const char *format, ...)
917 // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
918 static char string[8][1024], *s;
919 static int stringindex = 0;
921 s = string[stringindex];
922 stringindex = (stringindex + 1) & 7;
923 va_start (argptr, format);
924 vsnprintf (s, sizeof (string[0]), format,argptr);
931 //======================================
933 void COM_ToLowerString (const char *in, char *out, size_t size_out)
938 while (*in && size_out > 1)
940 if (*in >= 'A' && *in <= 'Z')
941 *out++ = *in++ + 'a' - 'A';
949 void COM_ToUpperString (const char *in, char *out, size_t size_out)
954 while (*in && size_out > 1)
956 if (*in >= 'a' && *in <= 'z')
957 *out++ = *in++ + 'A' - 'a';
965 int COM_StringBeginsWith(const char *s, const char *match)
967 for (;*s && *match;s++, match++)
973 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
975 int argc, commentprefixlength;
979 tokenbufend = tokenbuf + tokenbufsize;
981 commentprefixlength = 0;
983 commentprefixlength = strlen(commentprefix);
984 while (*l && *l != '\n')
988 if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
990 while (*l && *l != '\n')
996 argv[argc++] = tokenbuf;
1000 while (*l && *l != '"')
1002 if (tokenbuf >= tokenbufend)
1013 if (tokenbuf >= tokenbufend)
1018 if (tokenbuf >= tokenbufend)
1031 // written by Elric, thanks Elric!
1032 char *SearchInfostring(const char *infostring, const char *key)
1034 static char value [256];
1036 size_t value_ind, key_ind;
1039 if (*infostring++ != '\\')
1054 if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1056 crt_key[key_ind] = '\0';
1060 crt_key[key_ind++] = c;
1063 // If it's the key we are looking for, save it in "value"
1064 if (!strcmp(crt_key, key))
1070 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1072 value[value_ind] = '\0';
1076 value[value_ind++] = c;
1080 // Else, skip the value
1094 //========================================================
1095 // strlcat and strlcpy, from OpenBSD
1098 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1100 * Permission to use, copy, modify, and distribute this software for any
1101 * purpose with or without fee is hereby granted, provided that the above
1102 * copyright notice and this permission notice appear in all copies.
1104 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1105 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1106 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1107 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1108 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1109 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1110 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1113 /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
1114 /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
1117 #ifndef HAVE_STRLCAT
1119 strlcat(char *dst, const char *src, size_t siz)
1121 register char *d = dst;
1122 register const char *s = src;
1123 register size_t n = siz;
1126 /* Find the end of dst and adjust bytes left but don't go past end */
1127 while (n-- != 0 && *d != '\0')
1133 return(dlen + strlen(s));
1134 while (*s != '\0') {
1143 return(dlen + (s - src)); /* count does not include NUL */
1145 #endif // #ifndef HAVE_STRLCAT
1148 #ifndef HAVE_STRLCPY
1150 strlcpy(char *dst, const char *src, size_t siz)
1152 register char *d = dst;
1153 register const char *s = src;
1154 register size_t n = siz;
1156 /* Copy as many bytes as will fit */
1157 if (n != 0 && --n != 0) {
1159 if ((*d++ = *s++) == 0)
1164 /* Not enough room in dst, add NUL and traverse rest of src */
1167 *d = '\0'; /* NUL-terminate dst */
1172 return(s - src - 1); /* count does not include NUL */
1175 #endif // #ifndef HAVE_STRLCPY