mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2024-11-29 11:24:19 +01:00
e19413dd5b
--HG-- rename : sourcemm/IPluginManager.h => core/IPluginManager.h rename : sourcemm/ISmmAPI.h => core/ISmmAPI.h rename : sourcemm/ISmmPlugin.h => core/ISmmPlugin.h rename : sourcemm/ISmmPluginExt.h => core/ISmmPluginExt.h rename : sourcemm/LICENSE.txt => core/LICENSE.txt rename : sourcemm/Makefile => core/Makefile rename : sourcemm/changelog.txt => core/changelog.txt rename : sourcemm/episode1/console.cpp => core/episode1/console.cpp rename : sourcemm/episode1/console.h => core/episode1/console.h rename : sourcemm/episode1/convar_smm.h => core/episode1/convar_smm.h rename : sourcemm/episode1/msvc8/sourcemm.sln => core/episode1/msvc8/sourcemm.sln rename : sourcemm/episode1/msvc8/sourcemm.vcproj => core/episode1/msvc8/sourcemm.vcproj rename : sourcemm/episode1/provider_ep1.cpp => core/episode1/provider_ep1.cpp rename : sourcemm/episode1/provider_ep1.h => core/episode1/provider_ep1.h rename : sourcemm/episode1/vsp_listener.cpp => core/episode1/vsp_listener.cpp rename : sourcemm/episode1/vsp_listener.h => core/episode1/vsp_listener.h rename : sourcemm/metamod.cpp => core/metamod.cpp rename : sourcemm/metamod.h => core/metamod.h rename : sourcemm/metamod_console.cpp => core/metamod_console.cpp rename : sourcemm/metamod_console.h => core/metamod_console.h rename : sourcemm/metamod_oslink.cpp => core/metamod_oslink.cpp rename : sourcemm/metamod_oslink.h => core/metamod_oslink.h rename : sourcemm/metamod_plugins.cpp => core/metamod_plugins.cpp rename : sourcemm/metamod_plugins.h => core/metamod_plugins.h rename : sourcemm/metamod_provider.h => core/metamod_provider.h rename : sourcemm/metamod_util.cpp => core/metamod_util.cpp rename : sourcemm/metamod_util.h => core/metamod_util.h rename : sourcemm/episode2/console.cpp => core/provider/console.cpp rename : sourcemm/episode2/console.h => core/provider/console.h rename : sourcemm/episode2/msvc8/sourcemm.sln => core/provider/msvc8/sourcemm.sln rename : sourcemm/episode2/msvc8/sourcemm.vcproj => core/provider/msvc8/sourcemm.vcproj rename : sourcemm/episode2/msvc9/sourcemm.sln => core/provider/msvc9/sourcemm.sln rename : sourcemm/episode2/msvc9/sourcemm.vcproj => core/provider/msvc9/sourcemm.vcproj rename : sourcemm/episode2/provider_ep2.cpp => core/provider/provider_ep2.cpp rename : sourcemm/episode2/provider_ep2.h => core/provider/provider_ep2.h rename : sourcemm/episode2/vsp_listener.cpp => core/provider/vsp_listener.cpp rename : sourcemm/episode2/vsp_listener.h => core/provider/vsp_listener.h rename : sourcehook/FastDelegate.h => core/sourcehook/FastDelegate.h rename : sourcehook/generate/FastDelegate.h => core/sourcehook/generate/FastDelegate.h rename : sourcehook/generate/FastDelegate.hxx => core/sourcehook/generate/FastDelegate.hxx rename : sourcehook/generate/generate => core/sourcehook/generate/generate rename : sourcehook/generate/generate.bat => core/sourcehook/generate/generate.bat rename : sourcehook/generate/sh_memfuncinfo.h => core/sourcehook/generate/sh_memfuncinfo.h rename : sourcehook/generate/sh_memfuncinfo.hxx => core/sourcehook/generate/sh_memfuncinfo.hxx rename : sourcehook/generate/shworker.bin => core/sourcehook/generate/shworker.bin rename : sourcehook/generate/shworker.exe => core/sourcehook/generate/shworker.exe rename : sourcehook/generate/shworker/Makefile => core/sourcehook/generate/shworker/Makefile rename : sourcehook/generate/shworker/fd_hopter.cpp => core/sourcehook/generate/shworker/fd_hopter.cpp rename : sourcehook/generate/shworker/msvc7/shworker.vcproj => core/sourcehook/generate/shworker/msvc7/shworker.vcproj rename : sourcehook/generate/shworker/msvc8/shworker.vcproj => core/sourcehook/generate/shworker/msvc8/shworker.vcproj rename : sourcehook/generate/shworker/shworker.cpp => core/sourcehook/generate/shworker/shworker.cpp rename : sourcehook/generate/sourcehook.h => core/sourcehook/generate/sourcehook.h rename : sourcehook/generate/sourcehook.hxx => core/sourcehook/generate/sourcehook.hxx rename : sourcehook/sh_list.h => core/sourcehook/sh_list.h rename : sourcehook/sh_memfuncinfo.h => core/sourcehook/sh_memfuncinfo.h rename : sourcehook/sh_memory.h => core/sourcehook/sh_memory.h rename : sourcehook/sh_pagealloc.h => core/sourcehook/sh_pagealloc.h rename : sourcehook/sh_stack.h => core/sourcehook/sh_stack.h rename : sourcehook/sh_string.h => core/sourcehook/sh_string.h rename : sourcehook/sh_tinyhash.h => core/sourcehook/sh_tinyhash.h rename : sourcehook/sh_vector.h => core/sourcehook/sh_vector.h rename : sourcehook/sourcehook.cpp => core/sourcehook/sourcehook.cpp rename : sourcehook/sourcehook.h => core/sourcehook/sourcehook.h rename : sourcehook/sourcehook_hookmangen.cpp => core/sourcehook/sourcehook_hookmangen.cpp rename : sourcehook/sourcehook_hookmangen.h => core/sourcehook/sourcehook_hookmangen.h rename : sourcehook/sourcehook_hookmangen_x86.h => core/sourcehook/sourcehook_hookmangen_x86.h rename : sourcehook/sourcehook_impl.h => core/sourcehook/sourcehook_impl.h rename : sourcehook/sourcehook_impl_chook.h => core/sourcehook/sourcehook_impl_chook.h rename : sourcehook/sourcehook_impl_chookidman.h => core/sourcehook/sourcehook_impl_chookidman.h rename : sourcehook/sourcehook_impl_chookmaninfo.h => core/sourcehook/sourcehook_impl_chookmaninfo.h rename : sourcehook/sourcehook_impl_ciface.h => core/sourcehook/sourcehook_impl_ciface.h rename : sourcehook/sourcehook_impl_cproto.h => core/sourcehook/sourcehook_impl_cproto.h rename : sourcehook/sourcehook_impl_cvfnptr.h => core/sourcehook/sourcehook_impl_cvfnptr.h rename : sourcehook/sourcehook_pibuilder.h => core/sourcehook/sourcehook_pibuilder.h rename : sourcehook/test/Makefile => core/sourcehook/test/Makefile rename : sourcehook/test/generate.bat => core/sourcehook/test/generate.bat rename : sourcehook/test/main.cpp => core/sourcehook/test/main.cpp rename : sourcehook/test/msvc7/test.vcproj => core/sourcehook/test/msvc7/test.vcproj rename : sourcehook/test/msvc8/test.vcproj => core/sourcehook/test/msvc8/test.vcproj rename : sourcehook/test/sourcehook_test.h => core/sourcehook/test/sourcehook_test.h rename : sourcehook/test/test1.cpp => core/sourcehook/test/test1.cpp rename : sourcehook/test/test2.cpp => core/sourcehook/test/test2.cpp rename : sourcehook/test/test3.cpp => core/sourcehook/test/test3.cpp rename : sourcehook/test/test4.cpp => core/sourcehook/test/test4.cpp rename : sourcehook/test/testbail.cpp => core/sourcehook/test/testbail.cpp rename : sourcehook/test/testbail.h => core/sourcehook/test/testbail.h rename : sourcehook/test/testbail2.cpp => core/sourcehook/test/testbail2.cpp rename : sourcehook/test/testevents.h => core/sourcehook/test/testevents.h rename : sourcehook/test/testhookmangen.cpp => core/sourcehook/test/testhookmangen.cpp rename : sourcehook/test/testhookmangen.h => core/sourcehook/test/testhookmangen.h rename : sourcehook/test/testhookmangen.hxx => core/sourcehook/test/testhookmangen.hxx rename : sourcehook/test/testlist.cpp => core/sourcehook/test/testlist.cpp rename : sourcehook/test/testmanual.cpp => core/sourcehook/test/testmanual.cpp rename : sourcehook/test/testmulti.cpp => core/sourcehook/test/testmulti.cpp rename : sourcehook/test/testrecall.cpp => core/sourcehook/test/testrecall.cpp rename : sourcehook/test/testreentr.cpp => core/sourcehook/test/testreentr.cpp rename : sourcehook/test/testref.cpp => core/sourcehook/test/testref.cpp rename : sourcehook/test/testrefret.cpp => core/sourcehook/test/testrefret.cpp rename : sourcehook/test/testvphooks.cpp => core/sourcehook/test/testvphooks.cpp rename : sourcemm/svn_version.h => core/svn_version.h rename : sourcemm/svn_version.tpl => core/svn_version.tpl rename : sourcemm/version.rc => core/version.rc
429 lines
8.1 KiB
C++
429 lines
8.1 KiB
C++
/**
|
|
* vim: set ts=4 :
|
|
* ======================================================
|
|
* Metamod:Source
|
|
* Copyright (C) 2004-2008 AlliedModders LLC and authors.
|
|
* All rights reserved.
|
|
* ======================================================
|
|
*
|
|
* This software is provided 'as-is', without any express or implied warranty.
|
|
* In no event will the authors be held liable for any damages arising from
|
|
* the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software in a
|
|
* product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
*
|
|
* Version: $Id$
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include "metamod_util.h"
|
|
#include "metamod_oslink.h"
|
|
|
|
/**
|
|
* @brief Utility functions
|
|
* @file util.cpp
|
|
*/
|
|
|
|
const char *UTIL_GetExtension(const char *file)
|
|
{
|
|
int len = strlen(file);
|
|
int i = 0;
|
|
|
|
for (i = len - 1; i >= 0; i--)
|
|
{
|
|
if (file[i] == '/' || file[i] == '\\')
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if ((file[i] == '.') && (i != len - 1))
|
|
{
|
|
return (const char *)&(file[i + 1]);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void UTIL_TrimLeft(char *buffer)
|
|
{
|
|
/* Let's think of this as our iterator */
|
|
char *i = buffer;
|
|
|
|
/* Make sure the buffer isn't null */
|
|
if (i && *i)
|
|
{
|
|
/* Add up number of whitespace characters */
|
|
while(isspace((unsigned char) *i))
|
|
{
|
|
i++;
|
|
}
|
|
|
|
/* If whitespace chars in buffer then adjust string so first non-whitespace char is at start of buffer */
|
|
if (i != buffer)
|
|
{
|
|
memmove(buffer, i, (strlen(i) + 1) * sizeof(char));
|
|
}
|
|
}
|
|
}
|
|
|
|
void UTIL_TrimRight(char *buffer)
|
|
{
|
|
/* Make sure buffer isn't null */
|
|
if (buffer)
|
|
{
|
|
size_t len = strlen(buffer);
|
|
|
|
/* Loop through buffer backwards while replacing whitespace chars with null chars */
|
|
for (size_t i = len - 1; i >= 0; i--)
|
|
{
|
|
if (isspace((unsigned char) buffer[i]))
|
|
{
|
|
buffer[i] = '\0';
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* :TODO: this should skip string literals */
|
|
void UTIL_TrimComments(char *buffer)
|
|
{
|
|
int num_sc = 0;
|
|
size_t len = strlen(buffer);
|
|
if (buffer)
|
|
{
|
|
for (int i = len - 1; i >= 0; i--)
|
|
{
|
|
if (buffer[i] == '/')
|
|
{
|
|
if (++num_sc >= 2 && i==0)
|
|
{
|
|
buffer[i] = '\0';
|
|
return;
|
|
}
|
|
} else {
|
|
if (num_sc >= 2)
|
|
{
|
|
buffer[i] = '\0';
|
|
return;
|
|
}
|
|
num_sc = 0;
|
|
}
|
|
/* size_t won't go below 0, manually break out */
|
|
if (i == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UTIL_KeySplit(const char *str, char *buf1, size_t len1, char *buf2, size_t len2)
|
|
{
|
|
size_t start;
|
|
size_t len = strlen(str);
|
|
|
|
for (start = 0; start < len; start++)
|
|
{
|
|
if (!isspace(str[start]))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
size_t end;
|
|
for (end = start; end < len; end++)
|
|
{
|
|
if (isspace(str[end]))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
size_t i, c = 0;
|
|
for (i = start; i < end; i++, c++)
|
|
{
|
|
if (c >= len1)
|
|
{
|
|
break;
|
|
}
|
|
buf1[c] = str[i];
|
|
}
|
|
buf1[c] = '\0';
|
|
|
|
for (start = end; start < len; start++)
|
|
{
|
|
if (!isspace(str[start]))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (c = 0; start < len; start++, c++)
|
|
{
|
|
if (c >= len2)
|
|
{
|
|
break;
|
|
}
|
|
buf2[c] = str[start];
|
|
}
|
|
buf2[c] = '\0';
|
|
}
|
|
|
|
bool UTIL_PathCmp(const char *path1, const char *path2)
|
|
{
|
|
size_t pos1 = 0, pos2 = 0;
|
|
|
|
while (true)
|
|
{
|
|
if (path1[pos1] == '\0' || path2[pos2] == '\0')
|
|
{
|
|
return (path1[pos1] == path2[pos2]);
|
|
}
|
|
|
|
if (path1[pos1] == PATH_SEP_CHAR)
|
|
{
|
|
if (path2[pos2] != PATH_SEP_CHAR)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/* Look for extra path chars */
|
|
while (path1[++pos1])
|
|
{
|
|
if (path1[pos1] != PATH_SEP_CHAR)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while (path2[++pos2])
|
|
{
|
|
if (path2[pos2] != PATH_SEP_CHAR)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* If we're at a different non-alphanumeric, the next character MUST match */
|
|
if ((((unsigned)path1[pos1] & 0x80) && path1[pos1] != path2[pos2])
|
|
||
|
|
!isalpha(path1[pos1]) && (path1[pos1] != path2[pos2])
|
|
)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
if (toupper(path1[pos1]) != toupper(path2[pos2]))
|
|
#else
|
|
if (path1[pos1] != path2[pos2])
|
|
#endif
|
|
{
|
|
return false;
|
|
}
|
|
|
|
pos1++;
|
|
pos2++;
|
|
}
|
|
}
|
|
|
|
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
size_t len = vsnprintf(buffer, maxlength, fmt, ap);
|
|
va_end(ap);
|
|
|
|
if (len >= maxlength)
|
|
{
|
|
len = maxlength - 1;
|
|
buffer[len] = '\0';
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params)
|
|
{
|
|
size_t len = vsnprintf(buffer, maxlength, fmt, params);
|
|
|
|
if (len >= maxlength)
|
|
{
|
|
len = maxlength - 1;
|
|
buffer[len] = '\0';
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
inline bool pathchar_isalpha(char a)
|
|
{
|
|
return (((a & 1<<7) == 0) && isalpha(a));
|
|
}
|
|
|
|
inline bool pathchar_sep(char a)
|
|
{
|
|
#if defined WIN32
|
|
return (a == '/' || a == '\\');
|
|
#elif defined __linux__
|
|
return (a == '/');
|
|
#endif
|
|
}
|
|
|
|
inline bool pathstr_isabsolute(const char *str)
|
|
{
|
|
#if defined WIN32
|
|
return (pathchar_isalpha(str[0])
|
|
&& str[1] == ':'
|
|
&& pathchar_sep(str[2]));
|
|
#elif defined __linux__
|
|
return (str[0] == '/');
|
|
#endif
|
|
}
|
|
|
|
inline bool pathchar_cmp(char a, char b)
|
|
{
|
|
#if defined WIN32
|
|
if (pathchar_isalpha(a) && pathchar_isalpha(b))
|
|
{
|
|
return (tolower(a) == tolower(b));
|
|
}
|
|
/* Either path separator is acceptable */
|
|
if (pathchar_sep(a))
|
|
{
|
|
return pathchar_sep(b);
|
|
}
|
|
#endif
|
|
return (a == b);
|
|
}
|
|
|
|
/**
|
|
* @brief Forms a relative path given two absolute paths.
|
|
*
|
|
* @param buffer Buffer to store relative path in.
|
|
* @param maxlength Maximum length of the output buffer.
|
|
* @param relTo Destination folder to use as a working directory.
|
|
* Final folder name should not be pathchar-terminated.
|
|
* @param relFrom Source file or folder to use as a target.
|
|
* @return True on success, false on failure.
|
|
*/
|
|
bool UTIL_Relatize(char buffer[],
|
|
size_t maxlength,
|
|
const char *relTo,
|
|
const char *relFrom)
|
|
{
|
|
/* We don't allow relative paths in here, force
|
|
* the user to resolve these himself!
|
|
*/
|
|
if (!pathstr_isabsolute(relTo)
|
|
|| !pathstr_isabsolute(relFrom))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#if defined WIN32
|
|
/* Relative paths across drives are not possible */
|
|
if (!pathchar_cmp(relTo[0], relFrom[0]))
|
|
{
|
|
return false;
|
|
}
|
|
/* Get rid of the drive and semicolon part */
|
|
relTo = &relTo[2];
|
|
relFrom = &relFrom[2];
|
|
#endif
|
|
|
|
/* Eliminate the common root between the paths */
|
|
const char *rootTo = NULL;
|
|
const char *rootFrom = NULL;
|
|
while (*relTo != '\0' && *relFrom != '\0')
|
|
{
|
|
/* If we get to a new path sequence, start over */
|
|
if (pathchar_sep(*relTo)
|
|
&& pathchar_sep(*relFrom))
|
|
{
|
|
rootTo = relTo;
|
|
rootFrom = relFrom;
|
|
/* If the paths don't compare, stop looking for a common root */
|
|
} else if (!pathchar_cmp(*relTo, *relFrom)) {
|
|
break;
|
|
}
|
|
relTo++;
|
|
relFrom++;
|
|
}
|
|
|
|
/* NULLs shouldn't happen! */
|
|
if (rootTo == NULL
|
|
|| rootFrom == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
size_t numLevels = 0;
|
|
|
|
/* The root case is special!
|
|
* Don't count anything from it.
|
|
*/
|
|
if (*(rootTo + 1) != '\0')
|
|
{
|
|
/* Search for how many levels we need to go up.
|
|
* Since the root pointer points to a '/', we increment
|
|
* the initial pointer by one.
|
|
*/
|
|
while (*rootTo != '\0')
|
|
{
|
|
if (pathchar_sep(*rootTo))
|
|
{
|
|
/* Check for an improper trailing slash,
|
|
* just to be nice even though the user
|
|
* should NOT have done this!
|
|
*/
|
|
if (*(rootTo + 1) == '\0')
|
|
{
|
|
break;
|
|
}
|
|
numLevels++;
|
|
}
|
|
rootTo++;
|
|
}
|
|
}
|
|
|
|
/* Now build the new relative path. */
|
|
size_t len, total = 0;
|
|
while (numLevels--)
|
|
{
|
|
len = _snprintf(&buffer[total], maxlength - total, ".." PATH_SEP_STR);
|
|
if (len >= maxlength - total)
|
|
{
|
|
/* Not enough space in the buffer */
|
|
return false;
|
|
}
|
|
total += len;
|
|
}
|
|
|
|
/* Add the absolute path. */
|
|
len = _snprintf(&buffer[total], maxlength - total, "%s", &rootFrom[1]);
|
|
if (len >= maxlength - total)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|