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"))
769 gamemode = GAME_NORMAL;
771 if (COM_CheckParm ("-transfusion"))
772 gamemode = GAME_TRANSFUSION;
773 else if (COM_CheckParm ("-nexuiz"))
774 gamemode = GAME_NEXUIZ;
775 else if (COM_CheckParm ("-nehahra"))
776 gamemode = GAME_NEHAHRA;
777 else if (COM_CheckParm ("-hipnotic"))
778 gamemode = GAME_HIPNOTIC;
779 else if (COM_CheckParm ("-rogue"))
780 gamemode = GAME_ROGUE;
781 else if (COM_CheckParm ("-quake"))
782 gamemode = GAME_NORMAL;
783 else if (COM_CheckParm ("-goodvsbad2"))
784 gamemode = GAME_GOODVSBAD2;
785 else if (COM_CheckParm ("-teu"))
787 else if (COM_CheckParm ("-battlemech"))
788 gamemode = GAME_BATTLEMECH;
789 else if (COM_CheckParm ("-zymotic"))
790 gamemode = GAME_ZYMOTIC;
791 else if (COM_CheckParm ("-fniggium"))
792 gamemode = GAME_FNIGGIUM;
793 else if (COM_CheckParm ("-setheral"))
794 gamemode = GAME_SETHERAL;
795 else if (COM_CheckParm ("-som"))
801 gamename = "DarkPlaces-Quake";
805 gamename = "Darkplaces-Hipnotic";
806 gamedirname = "hipnotic";
809 gamename = "Darkplaces-Rogue";
810 gamedirname = "rogue";
813 gamename = "DarkPlaces-Nehahra";
814 gamedirname = "nehahra";
818 gamedirname = "data";
820 case GAME_TRANSFUSION:
821 gamename = "Transfusion";
822 gamedirname = "basetf";
824 case GAME_GOODVSBAD2:
825 gamename = "GoodVs.Bad2";
829 gamename = "TheEvilUnleashed";
830 gamedirname = "baseteu";
832 case GAME_BATTLEMECH:
833 gamename = "Battlemech";
834 gamedirname = "base";
837 gamename = "Zymotic";
838 gamedirname = "data";
841 gamename = "Fniggium";
842 gamedirname = "data";
845 gamename = "Setheral";
846 gamedirname = "data";
849 gamename = "Son of Man";
850 gamedirname = "data";
853 Sys_Error("COM_InitGameType: unknown gamemode %i\n", gamemode);
859 extern void Mathlib_Init(void);
860 extern void FS_Init (void);
869 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
870 qbyte swaptest[2] = {1,0};
872 // set the byte swapping variables in a portable manner
873 if ( *(short *)swaptest == 1)
875 BigShort = ShortSwap;
876 LittleShort = ShortNoSwap;
878 LittleLong = LongNoSwap;
879 BigFloat = FloatSwap;
880 LittleFloat = FloatNoSwap;
884 BigShort = ShortNoSwap;
885 LittleShort = ShortSwap;
886 BigLong = LongNoSwap;
887 LittleLong = LongSwap;
888 BigFloat = FloatNoSwap;
889 LittleFloat = FloatSwap;
893 Cvar_RegisterVariable (®istered);
894 Cvar_RegisterVariable (&cmdline);
900 COM_CheckRegistered ();
910 does a varargs printf into a temp buffer, so I don't need to have
911 varargs versions of all text functions.
912 FIXME: make this buffer size safe someday
915 char *va(const char *format, ...)
918 // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
919 static char string[8][1024], *s;
920 static int stringindex = 0;
922 s = string[stringindex];
923 stringindex = (stringindex + 1) & 7;
924 va_start (argptr, format);
925 vsnprintf (s, sizeof (string[0]), format,argptr);
932 //======================================
934 void COM_ToLowerString (const char *in, char *out, size_t size_out)
939 while (*in && size_out > 1)
941 if (*in >= 'A' && *in <= 'Z')
942 *out++ = *in++ + 'a' - 'A';
950 void COM_ToUpperString (const char *in, char *out, size_t size_out)
955 while (*in && size_out > 1)
957 if (*in >= 'a' && *in <= 'z')
958 *out++ = *in++ + 'A' - 'a';
966 int COM_StringBeginsWith(const char *s, const char *match)
968 for (;*s && *match;s++, match++)
974 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
976 int argc, commentprefixlength;
980 tokenbufend = tokenbuf + tokenbufsize;
982 commentprefixlength = 0;
984 commentprefixlength = strlen(commentprefix);
985 while (*l && *l != '\n')
989 if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
991 while (*l && *l != '\n')
997 argv[argc++] = tokenbuf;
1001 while (*l && *l != '"')
1003 if (tokenbuf >= tokenbufend)
1014 if (tokenbuf >= tokenbufend)
1019 if (tokenbuf >= tokenbufend)
1032 // written by Elric, thanks Elric!
1033 char *SearchInfostring(const char *infostring, const char *key)
1035 static char value [256];
1037 size_t value_ind, key_ind;
1040 if (*infostring++ != '\\')
1055 if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1057 crt_key[key_ind] = '\0';
1061 crt_key[key_ind++] = c;
1064 // If it's the key we are looking for, save it in "value"
1065 if (!strcmp(crt_key, key))
1071 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1073 value[value_ind] = '\0';
1077 value[value_ind++] = c;
1081 // Else, skip the value
1095 //========================================================
1096 // strlcat and strlcpy, from OpenBSD
1099 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1101 * Permission to use, copy, modify, and distribute this software for any
1102 * purpose with or without fee is hereby granted, provided that the above
1103 * copyright notice and this permission notice appear in all copies.
1105 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1106 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1107 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1108 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1109 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1110 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1111 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1114 /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
1115 /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
1118 #ifndef HAVE_STRLCAT
1120 strlcat(char *dst, const char *src, size_t siz)
1122 register char *d = dst;
1123 register const char *s = src;
1124 register size_t n = siz;
1127 /* Find the end of dst and adjust bytes left but don't go past end */
1128 while (n-- != 0 && *d != '\0')
1134 return(dlen + strlen(s));
1135 while (*s != '\0') {
1144 return(dlen + (s - src)); /* count does not include NUL */
1146 #endif // #ifndef HAVE_STRLCAT
1149 #ifndef HAVE_STRLCPY
1151 strlcpy(char *dst, const char *src, size_t siz)
1153 register char *d = dst;
1154 register const char *s = src;
1155 register size_t n = siz;
1157 /* Copy as many bytes as will fit */
1158 if (n != 0 && --n != 0) {
1160 if ((*d++ = *s++) == 0)
1165 /* Not enough room in dst, add NUL and traverse rest of src */
1168 *d = '\0'; /* NUL-terminate dst */
1173 return(s - src - 1); /* count does not include NUL */
1176 #endif // #ifndef HAVE_STRLCPY