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++)
357 float MSG_ReadCoord (void)
359 if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
360 return (signed short) MSG_ReadLittleShort();
361 else if (cl.protocol == PROTOCOL_DARKPLACES1)
362 return MSG_ReadLittleFloat();
364 return MSG_ReadLittleShort() * (1.0f/8.0f);
368 //===========================================================================
370 void SZ_Alloc (sizebuf_t *buf, int startsize, const char *name)
374 buf->mempool = Mem_AllocPool(name);
375 buf->data = Mem_Alloc(buf->mempool, startsize);
376 buf->maxsize = startsize;
381 void SZ_Free (sizebuf_t *buf)
383 Mem_FreePool(&buf->mempool);
389 void SZ_Clear (sizebuf_t *buf)
394 void *SZ_GetSpace (sizebuf_t *buf, int length)
398 if (buf->cursize + length > buf->maxsize)
400 if (!buf->allowoverflow)
401 Host_Error ("SZ_GetSpace: overflow without allowoverflow set\n");
403 if (length > buf->maxsize)
404 Host_Error ("SZ_GetSpace: %i is > full buffer size\n", length);
406 buf->overflowed = true;
407 Con_Printf ("SZ_GetSpace: overflow\n");
411 data = buf->data + buf->cursize;
412 buf->cursize += length;
417 void SZ_Write (sizebuf_t *buf, const void *data, int length)
419 memcpy (SZ_GetSpace(buf,length),data,length);
422 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
423 // attention, it has been eradicated from here, its only (former) use in
424 // all of darkplaces.
426 static char *hexchar = "0123456789ABCDEF";
427 void Com_HexDumpToConsole(const qbyte *data, int size)
431 char *cur, *flushpointer;
434 flushpointer = text + 512;
435 for (i = 0;i < size;)
441 *cur++ = hexchar[(i >> 12) & 15];
442 *cur++ = hexchar[(i >> 8) & 15];
443 *cur++ = hexchar[(i >> 4) & 15];
444 *cur++ = hexchar[(i >> 0) & 15];
446 for (j = 0;j < n;j++)
450 *cur++ = hexchar[(d[j] >> 4) & 15] | 0x80;
451 *cur++ = hexchar[(d[j] >> 0) & 15] | 0x80;
455 *cur++ = hexchar[(d[j] >> 4) & 15];
456 *cur++ = hexchar[(d[j] >> 0) & 15];
464 for (j = 0;j < n;j++)
465 *cur++ = (d[j] >= ' ' && d[j] <= 0x7E) ? d[j] : '.';
470 if (cur >= flushpointer || i >= size)
473 Con_Printf("%s", text);
479 void SZ_HexDumpToConsole(const sizebuf_t *buf)
481 Com_HexDumpToConsole(buf->data, buf->cursize);
485 //============================================================================
492 Parse a token out of a string
495 int COM_ParseToken(const char **datapointer, int returnnewline)
498 const char *data = *datapointer;
511 for (;*data <= ' ' && (*data != '\n' || !returnnewline);data++)
521 if (data[0] == '/' && data[1] == '/')
524 while (*data && *data != '\n')
528 else if (data[0] == '/' && data[1] == '*')
532 while (*data && (data[0] != '*' || data[1] != '/'))
537 else if (*data == '\"')
540 for (data++;*data != '\"';data++)
542 if (!*data || len >= (int)sizeof(com_token) - 1)
548 com_token[len++] = *data;
551 *datapointer = data+1;
554 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == '\'' || *data == ':' || *data == ',' || *data == ';')
557 com_token[len++] = *data++;
565 for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != '\'' && *data != ':' && *data != ',' && *data != ';';data++)
567 if (len >= (int)sizeof(com_token) - 1)
573 com_token[len++] = *data;
583 COM_ParseTokenConsole
585 Parse a token out of a string, behaving like the qwcl console
588 int COM_ParseTokenConsole(const char **datapointer)
591 const char *data = *datapointer;
604 for (;*data <= ' ';data++)
614 if (*data == '/' && data[1] == '/')
617 while (*data && *data != '\n')
621 else if (*data == '\"')
624 for (data++;*data != '\"';data++)
626 if (!*data || len >= (int)sizeof(com_token) - 1)
632 com_token[len++] = *data;
635 *datapointer = data+1;
641 for (;*data > ' ';data++)
643 if (len >= (int)sizeof(com_token) - 1)
649 com_token[len++] = *data;
662 Returns the position (1 to argc-1) in the program's argument list
663 where the given parameter apears, or 0 if not present
666 int COM_CheckParm (const char *parm)
670 for (i=1 ; i<com_argc ; i++)
673 continue; // NEXTSTEP sometimes clears appkit vars.
674 if (!strcmp (parm,com_argv[i]))
685 Looks for the pop.txt file and verifies it.
686 Sets the "registered" cvar.
687 Immediately exits out if an alternate game was attempted to be started without
691 void COM_CheckRegistered (void)
693 Cvar_Set ("cmdline", com_cmdline);
695 if (!FS_FileExists("gfx/pop.lmp"))
698 Con_Printf ("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
700 Con_Printf ("Playing shareware version.\n");
704 Cvar_Set ("registered", "1");
705 Con_Printf ("Playing registered version.\n");
714 void COM_InitArgv (void)
717 // reconstitute the command line for the cmdline externally visible cvar
719 for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
722 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
723 com_cmdline[n++] = com_argv[j][i++];
724 if (n < (CMDLINE_LENGTH - 1))
725 com_cmdline[n++] = ' ';
732 void COM_InitGameType (void)
734 char name[MAX_OSPATH];
735 FS_StripExtension (com_argv[0], name, sizeof (name));
736 COM_ToLowerString (name, name, sizeof (name));
738 if (strstr(name, "transfusion"))
739 gamemode = GAME_TRANSFUSION;
740 else if (strstr(name, "nexuiz"))
741 gamemode = GAME_NEXUIZ;
742 else if (strstr(name, "nehahra"))
743 gamemode = GAME_NEHAHRA;
744 else if (strstr(name, "hipnotic"))
745 gamemode = GAME_HIPNOTIC;
746 else if (strstr(name, "rogue"))
747 gamemode = GAME_ROGUE;
748 else if (strstr(name, "gvb2"))
749 gamemode = GAME_GOODVSBAD2;
750 else if (strstr(name, "teu"))
752 else if (strstr(name, "battlemech"))
753 gamemode = GAME_BATTLEMECH;
754 else if (strstr(name, "zymotic"))
755 gamemode = GAME_ZYMOTIC;
756 else if (strstr(name, "fniggium"))
757 gamemode = GAME_FNIGGIUM;
758 else if (strstr(name, "setheral"))
759 gamemode = GAME_SETHERAL;
760 else if (strstr(name, "som"))
762 else if (strstr(name, "tenebrae"))
763 gamemode = GAME_TENEBRAE;
765 gamemode = GAME_NORMAL;
767 if (COM_CheckParm ("-transfusion"))
768 gamemode = GAME_TRANSFUSION;
769 else if (COM_CheckParm ("-nexuiz"))
770 gamemode = GAME_NEXUIZ;
771 else if (COM_CheckParm ("-nehahra"))
772 gamemode = GAME_NEHAHRA;
773 else if (COM_CheckParm ("-hipnotic"))
774 gamemode = GAME_HIPNOTIC;
775 else if (COM_CheckParm ("-rogue"))
776 gamemode = GAME_ROGUE;
777 else if (COM_CheckParm ("-quake"))
778 gamemode = GAME_NORMAL;
779 else if (COM_CheckParm ("-goodvsbad2"))
780 gamemode = GAME_GOODVSBAD2;
781 else if (COM_CheckParm ("-teu"))
783 else if (COM_CheckParm ("-battlemech"))
784 gamemode = GAME_BATTLEMECH;
785 else if (COM_CheckParm ("-zymotic"))
786 gamemode = GAME_ZYMOTIC;
787 else if (COM_CheckParm ("-fniggium"))
788 gamemode = GAME_FNIGGIUM;
789 else if (COM_CheckParm ("-setheral"))
790 gamemode = GAME_SETHERAL;
791 else if (COM_CheckParm ("-som"))
793 else if (COM_CheckParm ("-tenebrae"))
794 gamemode = GAME_TENEBRAE;
799 gamename = "DarkPlaces-Quake";
803 gamename = "Darkplaces-Hipnotic";
804 gamedirname = "hipnotic";
807 gamename = "Darkplaces-Rogue";
808 gamedirname = "rogue";
811 gamename = "DarkPlaces-Nehahra";
812 gamedirname = "nehahra";
816 gamedirname = "data";
818 case GAME_TRANSFUSION:
819 gamename = "Transfusion";
820 gamedirname = "basetf";
822 case GAME_GOODVSBAD2:
823 gamename = "GoodVs.Bad2";
827 gamename = "TheEvilUnleashed";
828 gamedirname = "baseteu";
830 case GAME_BATTLEMECH:
831 gamename = "Battlemech";
832 gamedirname = "base";
835 gamename = "Zymotic";
836 gamedirname = "data";
839 gamename = "Fniggium";
840 gamedirname = "data";
843 gamename = "Setheral";
844 gamedirname = "data";
847 gamename = "Son of Man";
848 gamedirname = "data";
851 gamename = "DarkPlaces-Tenebrae";
852 gamedirname = "tenebrae";
855 Sys_Error("COM_InitGameType: unknown gamemode %i\n", gamemode);
861 extern void Mathlib_Init(void);
862 extern void FS_Init (void);
871 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
872 qbyte swaptest[2] = {1,0};
874 // set the byte swapping variables in a portable manner
875 if ( *(short *)swaptest == 1)
877 BigShort = ShortSwap;
878 LittleShort = ShortNoSwap;
880 LittleLong = LongNoSwap;
881 BigFloat = FloatSwap;
882 LittleFloat = FloatNoSwap;
886 BigShort = ShortNoSwap;
887 LittleShort = ShortSwap;
888 BigLong = LongNoSwap;
889 LittleLong = LongSwap;
890 BigFloat = FloatNoSwap;
891 LittleFloat = FloatSwap;
895 Cvar_RegisterVariable (®istered);
896 Cvar_RegisterVariable (&cmdline);
902 COM_CheckRegistered ();
912 does a varargs printf into a temp buffer, so I don't need to have
913 varargs versions of all text functions.
914 FIXME: make this buffer size safe someday
917 char *va(const char *format, ...)
920 // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
921 static char string[8][1024], *s;
922 static int stringindex = 0;
924 s = string[stringindex];
925 stringindex = (stringindex + 1) & 7;
926 va_start (argptr, format);
927 vsnprintf (s, sizeof (string[0]), format,argptr);
934 //======================================
936 void COM_ToLowerString (const char *in, char *out, size_t size_out)
941 while (*in && size_out > 1)
943 if (*in >= 'A' && *in <= 'Z')
944 *out++ = *in++ + 'a' - 'A';
952 void COM_ToUpperString (const char *in, char *out, size_t size_out)
957 while (*in && size_out > 1)
959 if (*in >= 'a' && *in <= 'z')
960 *out++ = *in++ + 'A' - 'a';
968 int COM_StringBeginsWith(const char *s, const char *match)
970 for (;*s && *match;s++, match++)
976 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
978 int argc, commentprefixlength;
982 tokenbufend = tokenbuf + tokenbufsize;
984 commentprefixlength = 0;
986 commentprefixlength = strlen(commentprefix);
987 while (*l && *l != '\n')
991 if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
993 while (*l && *l != '\n')
999 argv[argc++] = tokenbuf;
1003 while (*l && *l != '"')
1005 if (tokenbuf >= tokenbufend)
1016 if (tokenbuf >= tokenbufend)
1021 if (tokenbuf >= tokenbufend)
1034 // written by Elric, thanks Elric!
1035 char *SearchInfostring(const char *infostring, const char *key)
1037 static char value [256];
1039 size_t value_ind, key_ind;
1042 if (*infostring++ != '\\')
1057 if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1059 crt_key[key_ind] = '\0';
1063 crt_key[key_ind++] = c;
1066 // If it's the key we are looking for, save it in "value"
1067 if (!strcmp(crt_key, key))
1073 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1075 value[value_ind] = '\0';
1079 value[value_ind++] = c;
1083 // Else, skip the value
1097 //========================================================
1098 // strlcat and strlcpy, from OpenBSD
1101 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1103 * Permission to use, copy, modify, and distribute this software for any
1104 * purpose with or without fee is hereby granted, provided that the above
1105 * copyright notice and this permission notice appear in all copies.
1107 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1108 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1109 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1110 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1111 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1112 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1113 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1116 /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
1117 /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
1120 #ifndef HAVE_STRLCAT
1122 strlcat(char *dst, const char *src, size_t siz)
1124 register char *d = dst;
1125 register const char *s = src;
1126 register size_t n = siz;
1129 /* Find the end of dst and adjust bytes left but don't go past end */
1130 while (n-- != 0 && *d != '\0')
1136 return(dlen + strlen(s));
1137 while (*s != '\0') {
1146 return(dlen + (s - src)); /* count does not include NUL */
1148 #endif // #ifndef HAVE_STRLCAT
1151 #ifndef HAVE_STRLCPY
1153 strlcpy(char *dst, const char *src, size_t siz)
1155 register char *d = dst;
1156 register const char *s = src;
1157 register size_t n = siz;
1159 /* Copy as many bytes as will fit */
1160 if (n != 0 && --n != 0) {
1162 if ((*d++ = *s++) == 0)
1167 /* Not enough room in dst, add NUL and traverse rest of src */
1170 *d = '\0'; /* NUL-terminate dst */
1175 return(s - src - 1); /* count does not include NUL */
1178 #endif // #ifndef HAVE_STRLCPY