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 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
429 // attention, it has been eradicated from here, its only (former) use in
430 // all of darkplaces.
432 static char *hexchar = "0123456789ABCDEF";
433 void Com_HexDumpToConsole(const qbyte *data, int size)
437 char *cur, *flushpointer;
440 flushpointer = text + 512;
441 for (i = 0;i < size;)
447 *cur++ = hexchar[(i >> 12) & 15];
448 *cur++ = hexchar[(i >> 8) & 15];
449 *cur++ = hexchar[(i >> 4) & 15];
450 *cur++ = hexchar[(i >> 0) & 15];
452 for (j = 0;j < n;j++)
456 *cur++ = hexchar[(d[j] >> 4) & 15] | 0x80;
457 *cur++ = hexchar[(d[j] >> 0) & 15] | 0x80;
461 *cur++ = hexchar[(d[j] >> 4) & 15];
462 *cur++ = hexchar[(d[j] >> 0) & 15];
470 for (j = 0;j < n;j++)
471 *cur++ = (d[j] >= ' ' && d[j] <= 0x7E) ? d[j] : '.';
476 if (cur >= flushpointer || i >= size)
479 Con_Printf("%s", text);
485 void SZ_HexDumpToConsole(const sizebuf_t *buf)
487 Com_HexDumpToConsole(buf->data, buf->cursize);
491 //============================================================================
498 Parse a token out of a string
501 int COM_ParseToken(const char **datapointer, int returnnewline)
504 const char *data = *datapointer;
517 for (;*data <= ' ' && (*data != '\n' || !returnnewline);data++)
527 if (data[0] == '/' && data[1] == '/')
530 while (*data && *data != '\n')
534 else if (data[0] == '/' && data[1] == '*')
538 while (*data && (data[0] != '*' || data[1] != '/'))
543 else if (*data == '\"')
546 for (data++;*data != '\"';data++)
548 if (!*data || len >= (int)sizeof(com_token) - 1)
554 com_token[len++] = *data;
557 *datapointer = data+1;
560 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == '\'' || *data == ':' || *data == ',' || *data == ';')
563 com_token[len++] = *data++;
571 for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != '\'' && *data != ':' && *data != ',' && *data != ';';data++)
573 if (len >= (int)sizeof(com_token) - 1)
579 com_token[len++] = *data;
589 COM_ParseTokenConsole
591 Parse a token out of a string, behaving like the qwcl console
594 int COM_ParseTokenConsole(const char **datapointer)
597 const char *data = *datapointer;
610 for (;*data <= ' ';data++)
620 if (*data == '/' && data[1] == '/')
623 while (*data && *data != '\n')
627 else if (*data == '\"')
630 for (data++;*data != '\"';data++)
632 if (!*data || len >= (int)sizeof(com_token) - 1)
638 com_token[len++] = *data;
641 *datapointer = data+1;
647 for (;*data > ' ';data++)
649 if (len >= (int)sizeof(com_token) - 1)
655 com_token[len++] = *data;
668 Returns the position (1 to argc-1) in the program's argument list
669 where the given parameter apears, or 0 if not present
672 int COM_CheckParm (const char *parm)
676 for (i=1 ; i<com_argc ; i++)
679 continue; // NEXTSTEP sometimes clears appkit vars.
680 if (!strcmp (parm,com_argv[i]))
691 Looks for the pop.txt file and verifies it.
692 Sets the "registered" cvar.
693 Immediately exits out if an alternate game was attempted to be started without
697 void COM_CheckRegistered (void)
699 Cvar_Set ("cmdline", com_cmdline);
701 if (!FS_FileExists("gfx/pop.lmp"))
704 Con_Printf ("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
706 Con_Printf ("Playing shareware version.\n");
710 Cvar_Set ("registered", "1");
711 Con_Printf ("Playing registered version.\n");
720 void COM_InitArgv (void)
723 // reconstitute the command line for the cmdline externally visible cvar
725 for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
728 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
729 com_cmdline[n++] = com_argv[j][i++];
730 if (n < (CMDLINE_LENGTH - 1))
731 com_cmdline[n++] = ' ';
738 void COM_InitGameType (void)
740 char name[MAX_OSPATH];
741 FS_StripExtension (com_argv[0], name, sizeof (name));
742 COM_ToLowerString (name, name, sizeof (name));
744 if (strstr(name, "transfusion"))
745 gamemode = GAME_TRANSFUSION;
746 else if (strstr(name, "nexuiz"))
747 gamemode = GAME_NEXUIZ;
748 else if (strstr(name, "nehahra"))
749 gamemode = GAME_NEHAHRA;
750 else if (strstr(name, "hipnotic"))
751 gamemode = GAME_HIPNOTIC;
752 else if (strstr(name, "rogue"))
753 gamemode = GAME_ROGUE;
754 else if (strstr(name, "gvb2"))
755 gamemode = GAME_GOODVSBAD2;
756 else if (strstr(name, "teu"))
758 else if (strstr(name, "battlemech"))
759 gamemode = GAME_BATTLEMECH;
760 else if (strstr(name, "zymotic"))
761 gamemode = GAME_ZYMOTIC;
762 else if (strstr(name, "fniggium"))
763 gamemode = GAME_FNIGGIUM;
764 else if (strstr(name, "setheral"))
765 gamemode = GAME_SETHERAL;
766 else if (strstr(name, "som"))
768 else if (strstr(name, "tenebrae"))
769 gamemode = GAME_TENEBRAE;
771 gamemode = GAME_NORMAL;
773 if (COM_CheckParm ("-transfusion"))
774 gamemode = GAME_TRANSFUSION;
775 else if (COM_CheckParm ("-nexuiz"))
776 gamemode = GAME_NEXUIZ;
777 else if (COM_CheckParm ("-nehahra"))
778 gamemode = GAME_NEHAHRA;
779 else if (COM_CheckParm ("-hipnotic"))
780 gamemode = GAME_HIPNOTIC;
781 else if (COM_CheckParm ("-rogue"))
782 gamemode = GAME_ROGUE;
783 else if (COM_CheckParm ("-quake"))
784 gamemode = GAME_NORMAL;
785 else if (COM_CheckParm ("-goodvsbad2"))
786 gamemode = GAME_GOODVSBAD2;
787 else if (COM_CheckParm ("-teu"))
789 else if (COM_CheckParm ("-battlemech"))
790 gamemode = GAME_BATTLEMECH;
791 else if (COM_CheckParm ("-zymotic"))
792 gamemode = GAME_ZYMOTIC;
793 else if (COM_CheckParm ("-fniggium"))
794 gamemode = GAME_FNIGGIUM;
795 else if (COM_CheckParm ("-setheral"))
796 gamemode = GAME_SETHERAL;
797 else if (COM_CheckParm ("-som"))
799 else if (COM_CheckParm ("-tenebrae"))
800 gamemode = GAME_TENEBRAE;
805 gamename = "DarkPlaces-Quake";
809 gamename = "Darkplaces-Hipnotic";
810 gamedirname = "hipnotic";
813 gamename = "Darkplaces-Rogue";
814 gamedirname = "rogue";
817 gamename = "DarkPlaces-Nehahra";
818 gamedirname = "nehahra";
822 gamedirname = "data";
824 case GAME_TRANSFUSION:
825 gamename = "Transfusion";
826 gamedirname = "basetf";
828 case GAME_GOODVSBAD2:
829 gamename = "GoodVs.Bad2";
833 gamename = "TheEvilUnleashed";
834 gamedirname = "baseteu";
836 case GAME_BATTLEMECH:
837 gamename = "Battlemech";
838 gamedirname = "base";
841 gamename = "Zymotic";
842 gamedirname = "data";
845 gamename = "Fniggium";
846 gamedirname = "data";
849 gamename = "Setheral";
850 gamedirname = "data";
853 gamename = "Son of Man";
854 gamedirname = "data";
857 gamename = "DarkPlaces-Tenebrae";
858 gamedirname = "tenebrae";
861 Sys_Error("COM_InitGameType: unknown gamemode %i\n", gamemode);
867 extern void Mathlib_Init(void);
868 extern void FS_Init (void);
877 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
878 qbyte swaptest[2] = {1,0};
880 // set the byte swapping variables in a portable manner
881 if ( *(short *)swaptest == 1)
883 BigShort = ShortSwap;
884 LittleShort = ShortNoSwap;
886 LittleLong = LongNoSwap;
887 BigFloat = FloatSwap;
888 LittleFloat = FloatNoSwap;
892 BigShort = ShortNoSwap;
893 LittleShort = ShortSwap;
894 BigLong = LongNoSwap;
895 LittleLong = LongSwap;
896 BigFloat = FloatNoSwap;
897 LittleFloat = FloatSwap;
901 Cvar_RegisterVariable (®istered);
902 Cvar_RegisterVariable (&cmdline);
908 COM_CheckRegistered ();
918 does a varargs printf into a temp buffer, so I don't need to have
919 varargs versions of all text functions.
920 FIXME: make this buffer size safe someday
923 char *va(const char *format, ...)
926 // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
927 static char string[8][1024], *s;
928 static int stringindex = 0;
930 s = string[stringindex];
931 stringindex = (stringindex + 1) & 7;
932 va_start (argptr, format);
933 vsnprintf (s, sizeof (string[0]), format,argptr);
940 //======================================
942 void COM_ToLowerString (const char *in, char *out, size_t size_out)
947 while (*in && size_out > 1)
949 if (*in >= 'A' && *in <= 'Z')
950 *out++ = *in++ + 'a' - 'A';
958 void COM_ToUpperString (const char *in, char *out, size_t size_out)
963 while (*in && size_out > 1)
965 if (*in >= 'a' && *in <= 'z')
966 *out++ = *in++ + 'A' - 'a';
974 int COM_StringBeginsWith(const char *s, const char *match)
976 for (;*s && *match;s++, match++)
982 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
984 int argc, commentprefixlength;
988 tokenbufend = tokenbuf + tokenbufsize;
990 commentprefixlength = 0;
992 commentprefixlength = strlen(commentprefix);
993 while (*l && *l != '\n')
997 if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
999 while (*l && *l != '\n')
1003 if (argc >= maxargc)
1005 argv[argc++] = tokenbuf;
1009 while (*l && *l != '"')
1011 if (tokenbuf >= tokenbufend)
1022 if (tokenbuf >= tokenbufend)
1027 if (tokenbuf >= tokenbufend)
1040 // written by Elric, thanks Elric!
1041 char *SearchInfostring(const char *infostring, const char *key)
1043 static char value [256];
1045 size_t value_ind, key_ind;
1048 if (*infostring++ != '\\')
1063 if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1065 crt_key[key_ind] = '\0';
1069 crt_key[key_ind++] = c;
1072 // If it's the key we are looking for, save it in "value"
1073 if (!strcmp(crt_key, key))
1079 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1081 value[value_ind] = '\0';
1085 value[value_ind++] = c;
1089 // Else, skip the value
1103 //========================================================
1104 // strlcat and strlcpy, from OpenBSD
1107 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1109 * Permission to use, copy, modify, and distribute this software for any
1110 * purpose with or without fee is hereby granted, provided that the above
1111 * copyright notice and this permission notice appear in all copies.
1113 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1114 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1115 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1116 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1117 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1118 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1119 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1122 /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
1123 /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
1126 #ifndef HAVE_STRLCAT
1128 strlcat(char *dst, const char *src, size_t siz)
1130 register char *d = dst;
1131 register const char *s = src;
1132 register size_t n = siz;
1135 /* Find the end of dst and adjust bytes left but don't go past end */
1136 while (n-- != 0 && *d != '\0')
1142 return(dlen + strlen(s));
1143 while (*s != '\0') {
1152 return(dlen + (s - src)); /* count does not include NUL */
1154 #endif // #ifndef HAVE_STRLCAT
1157 #ifndef HAVE_STRLCPY
1159 strlcpy(char *dst, const char *src, size_t siz)
1161 register char *d = dst;
1162 register const char *s = src;
1163 register size_t n = siz;
1165 /* Copy as many bytes as will fit */
1166 if (n != 0 && --n != 0) {
1168 if ((*d++ = *s++) == 0)
1173 /* Not enough room in dst, add NUL and traverse rest of src */
1176 *d = '\0'; /* NUL-terminate dst */
1181 return(s - src - 1); /* count does not include NUL */
1184 #endif // #ifndef HAVE_STRLCPY