//contains generic plugin code for dll/qvm //it's this one or the engine... #include "plugin.h" #include #include plugcorefuncs_t *plugfuncs; plugcmdfuncs_t *cmdfuncs; plugcvarfuncs_t *cvarfuncs; //plugclientfuncs_t *clientfuncs; /* An implementation of some 'standard' functions */ void Q_strlncpy(char *d, const char *s, int sizeofd, int lenofs) { int i; sizeofd--; if (sizeofd < 0) return; //this could be an error for (i=0; lenofs-- > 0; i++) { if (i == sizeofd) break; *d++ = *s++; } *d='\0'; } void Q_strlcpy(char *d, const char *s, int n) { int i; n--; if (n < 0) return; //this could be an error for (i=0; *s; i++) { if (i == n) break; *d++ = *s++; } *d='\0'; } void Q_strlcat(char *d, const char *s, int n) { if (n) { int dlen = strlen(d); int slen = strlen(s)+1; if (slen > (n-1)-dlen) slen = (n-1)-dlen; memcpy(d+dlen, s, slen); d[n - 1] = 0; } } char *Plug_Info_ValueForKey (const char *s, const char *key, char *out, size_t outsize) { int isvalue = 0; const char *start; char *oout = out; *out = 0; if (*s != '\\') return out; //gah, get lost with your corrupt infostrings. start = ++s; while(1) { while(s[0] == '\\' && s[1] == '\\') s+=2; if (s[0] != '\\' && *s) { s++; continue; } //okay, it terminates here isvalue = !isvalue; if (isvalue) { if (strlen(key) == (size_t)(s - start) && !strncmp(start, key, s - start)) { s++; while (outsize --> 1) { if (s[0] == '\\' && s[1] == '\\') s++; else if (s[0] == '\\' || !s[0]) break; *out++ = *s++; } *out++ = 0; return oout; } } if (*s) start = ++s; else break; } return oout; } //returns true on truncation qboolean VARGS Q_vsnprintfz (char *dest, size_t size, const char *fmt, va_list argptr) { size_t ret; #ifdef _WIN32 //doesn't null terminate. //returns -1 on truncation ret = _vsnprintf (dest, size, fmt, argptr); dest[size-1] = 0; //shitty paranoia #else //always null terminates. //returns length regardless of truncation. ret = vsnprintf (dest, size, fmt, argptr); #endif #ifdef _DEBUG if (ret>=size) plugfuncs->Error("Q_vsnprintfz: Truncation\n"); #endif //if ret is -1 (windows oversize, or general error) then it'll be treated as unsigned so really long. this makes the following check quite simple. return (ret>=size) ? qtrue : qfalse; } //windows/linux have inconsistant snprintf //this is an attempt to get them consistant and safe //size is the total size of the buffer //returns true on overflow (will be truncated). qboolean VARGS Q_snprintfz (char *dest, size_t size, const char *fmt, ...) { va_list argptr; size_t ret; va_start (argptr, fmt); #ifdef _WIN32 //doesn't null terminate. //returns -1 on truncation ret = _vsnprintf (dest, size, fmt, argptr); dest[size-1] = 0; //shitty paranoia #else //always null terminates. //returns length regardless of truncation. ret = vsnprintf (dest, size, fmt, argptr); #endif va_end (argptr); #ifdef _DEBUG if (ret>=size) plugfuncs->Error("Q_vsnprintfz: Truncation\n"); #endif //if ret is -1 (windows oversize, or general error) then it'll be treated as unsigned so really long. this makes the following check quite simple. return (ret>=size) ? qtrue : qfalse; } char *va(const char *format, ...) //Identical in function to the one in Quake, though I can assure you that I wrote it... { //It's not exactly hard, just easy to use, so gets duplicated lots. va_list argptr; static char string[1024]; va_start (argptr, format); Q_vsnprintfz (string, sizeof(string), format,argptr); va_end (argptr); return string; } #ifdef _WIN32 // don't use these functions in MSVC8 #if (_MSC_VER < 1400) int QDECL linuxlike_snprintf(char *buffer, int size, const char *format, ...) { #undef _vsnprintf int ret; va_list argptr; if (size <= 0) return 0; size--; va_start (argptr, format); ret = _vsnprintf (buffer,size, format,argptr); va_end (argptr); buffer[size] = '\0'; return ret; } int QDECL linuxlike_vsnprintf(char *buffer, int size, const char *format, va_list argptr) { #undef _vsnprintf int ret; if (size <= 0) return 0; size--; ret = _vsnprintf (buffer,size, format,argptr); buffer[size] = '\0'; return ret; } #elif (_MSC_VER < 1900) int VARGS linuxlike_snprintf_vc8(char *buffer, int size, const char *format, ...) { int ret; va_list argptr; va_start (argptr, format); ret = vsnprintf_s (buffer,size, _TRUNCATE, format,argptr); va_end (argptr); return ret; } #endif #endif void Con_Printf(const char *format, ...) { va_list argptr; static char string[1024]; va_start (argptr, format); Q_vsnprintfz (string, sizeof(string), format,argptr); va_end (argptr); plugfuncs->Print(string); } void Con_DPrintf(const char *format, ...) { va_list argptr; static char string[1024]; if (!cvarfuncs->GetFloat("developer")) return; va_start (argptr, format); Q_vsnprintfz (string, sizeof(string), format,argptr); va_end (argptr); plugfuncs->Print(string); } void Sys_Errorf(const char *format, ...) { va_list argptr; static char string[1024]; va_start (argptr, format); Q_vsnprintfz (string, sizeof(string), format,argptr); va_end (argptr); plugfuncs->Error(string); } qboolean ZF_ReallocElements(void **ptr, size_t *elements, size_t newelements, size_t elementsize) { void *n; size_t oldsize; size_t newsize; //protect against malicious overflows if (newelements > SIZE_MAX / elementsize) return false; oldsize = *elements * elementsize; newsize = newelements * elementsize; n = plugfuncs->Realloc(*ptr, newsize); if (!n) return false; if (newsize > oldsize) memset((char*)n+oldsize, 0, newsize - oldsize); *elements = newelements; *ptr = n; return true; } #ifdef __cplusplus extern "C" #endif qboolean NATIVEEXPORT FTEPlug_Init(plugcorefuncs_t *corefuncs) { plugfuncs = corefuncs; cmdfuncs = (plugcmdfuncs_t*)plugfuncs->GetEngineInterface(plugcmdfuncs_name, sizeof(*cmdfuncs)); cvarfuncs = (plugcvarfuncs_t*)plugfuncs->GetEngineInterface(plugcvarfuncs_name, sizeof(*cvarfuncs)); if (!plugfuncs || !cmdfuncs || !cvarfuncs) return qfalse; //erk return Plug_Init(); }