dvander@2168: /** dvander@2168: * vim: set ts=4 : dvander@2168: * ============================================================================= dvander@2168: * SourceMod dvander@2168: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. dvander@2168: * ============================================================================= dvander@2168: * dvander@2168: * This program is free software; you can redistribute it and/or modify it under dvander@2168: * the terms of the GNU General Public License, version 3.0, as published by the dvander@2168: * Free Software Foundation. dvander@2168: * dvander@2168: * This program is distributed in the hope that it will be useful, but WITHOUT dvander@2168: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@2168: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more dvander@2168: * details. dvander@2168: * dvander@2168: * You should have received a copy of the GNU General Public License along with dvander@2168: * this program. If not, see . dvander@2168: * dvander@2168: * As a special exception, AlliedModders LLC gives you permission to link the dvander@2168: * code of this program (as well as its derivative works) to "Half-Life 2," the dvander@2168: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software dvander@2168: * by the Valve Corporation. You must obey the GNU General Public License in dvander@2168: * all respects for all other code used. Additionally, AlliedModders LLC grants dvander@2168: * this exception to all derivative works. AlliedModders LLC defines further dvander@2168: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), dvander@2168: * or . dvander@2168: * dvander@2168: * Version: $Id$ dvander@2168: */ dvander@2168: dvander@2168: #include dvander@2168: #include dvander@2168: #include dvander@2168: #include dvander@2168: #include dvander@2168: #include "sm_stringutil.h" dvander@2168: #include "LibrarySys.h" dvander@2168: dvander@2168: LibrarySystem g_LibSys; dvander@2168: dvander@2168: CLibrary::~CLibrary() dvander@2168: { dvander@2168: if (m_lib) dvander@2168: { dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: FreeLibrary(m_lib); dvander@2168: #elif defined PLATFORM_POSIX dvander@2168: dlclose(m_lib); dvander@2168: #endif dvander@2168: m_lib = NULL; dvander@2168: } dvander@2168: } dvander@2168: dvander@2168: CLibrary::CLibrary(LibraryHandle me) dvander@2168: { dvander@2168: m_lib = me; dvander@2168: } dvander@2168: dvander@2168: void CLibrary::CloseLibrary() dvander@2168: { dvander@2168: delete this; dvander@2168: } dvander@2168: dvander@2168: void *CLibrary::GetSymbolAddress(const char *symname) dvander@2168: { dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: return GetProcAddress(m_lib, symname); dvander@2168: #elif defined PLATFORM_POSIX dvander@2168: return dlsym(m_lib, symname); dvander@2168: #endif dvander@2168: } dvander@2168: dvander@2168: dvander@2168: /******************** dvander@2168: ** Directory Code ** dvander@2168: ********************/ dvander@2168: dvander@2168: dvander@2168: CDirectory::CDirectory(const char *path) dvander@2168: { dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: char newpath[PLATFORM_MAX_PATH]; dvander@2168: snprintf(newpath, sizeof(newpath), "%s\\*.*", path); dvander@2168: m_dir = FindFirstFileA(newpath, &m_fd); dvander@2168: if (!IsValid()) dvander@2168: { dvander@2168: m_fd.cFileName[0] = '\0'; dvander@2168: } dvander@2168: #elif defined PLATFORM_POSIX dvander@2168: m_dir = opendir(path); dvander@2168: if (IsValid()) dvander@2168: { dvander@2168: /* :TODO: we need to read past "." and ".."! */ dvander@2168: ep = readdir(m_dir); dvander@2168: snprintf(m_origpath, PLATFORM_MAX_PATH, "%s", path); dvander@2168: } else { dvander@2168: ep = NULL; dvander@2168: } dvander@2168: #endif dvander@2168: } dvander@2168: dvander@2168: CDirectory::~CDirectory() dvander@2168: { dvander@2168: if (IsValid()) dvander@2168: { dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: FindClose(m_dir); dvander@2168: #elif defined PLATFORM_POSIX dvander@2168: closedir(m_dir); dvander@2168: #endif dvander@2168: } dvander@2168: } dvander@2168: dvander@2168: void CDirectory::NextEntry() dvander@2168: { dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: if (FindNextFile(m_dir, &m_fd) == 0) dvander@2168: { dvander@2168: FindClose(m_dir); dvander@2168: m_dir = INVALID_HANDLE_VALUE; dvander@2168: } dvander@2168: #elif defined PLATFORM_POSIX dvander@2168: if ((ep=readdir(m_dir)) == NULL) dvander@2168: { dvander@2168: closedir(m_dir); dvander@2168: m_dir = NULL; dvander@2168: } dvander@2168: #endif dvander@2168: } dvander@2168: dvander@2168: bool CDirectory::IsEntryValid() dvander@2168: { dvander@2168: return IsValid(); dvander@2168: } dvander@2168: dvander@2168: bool CDirectory::IsEntryDirectory() dvander@2168: { dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: return ((m_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY); dvander@2168: #elif defined PLATFORM_LINUX dvander@2168: char temppath[PLATFORM_MAX_PATH]; dvander@2168: snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName()); dvander@2168: return g_LibSys.IsPathDirectory(temppath); dvander@2168: #endif dvander@2168: } dvander@2168: dvander@2168: bool CDirectory::IsEntryFile() dvander@2168: { dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: return !(m_fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE)); dvander@2168: #elif defined PLATFORM_POSIX dvander@2168: char temppath[PLATFORM_MAX_PATH]; dvander@2168: snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName()); dvander@2168: return g_LibSys.IsPathFile(temppath); dvander@2168: #endif dvander@2168: } dvander@2168: dvander@2168: const char *CDirectory::GetEntryName() dvander@2168: { dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: return m_fd.cFileName; dvander@2168: #elif defined PLATFORM_LINUX dvander@2168: return ep ? ep->d_name : ""; dvander@2168: #endif dvander@2168: } dvander@2168: dvander@2168: bool CDirectory::MoreFiles() dvander@2168: { dvander@2168: return IsValid(); dvander@2168: } dvander@2168: dvander@2168: bool CDirectory::IsValid() dvander@2168: { dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: return (m_dir != INVALID_HANDLE_VALUE); dvander@2168: #elif defined PLATFORM_LINUX dvander@2168: return (m_dir != NULL); dvander@2168: #endif dvander@2168: } dvander@2168: dvander@2168: dvander@2168: /************************* dvander@2168: ** Library System Code ** dvander@2168: *************************/ dvander@2168: dvander@2168: dvander@2168: bool LibrarySystem::PathExists(const char *path) dvander@2168: { dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: DWORD attr = GetFileAttributesA(path); dvander@2168: dvander@2168: return (attr != INVALID_FILE_ATTRIBUTES); dvander@2168: #elif defined PLATFORM_POSIX dvander@2168: struct stat s; dvander@2168: dvander@2168: return (stat(path, &s) == 0); dvander@2168: #endif dvander@2168: } dvander@2168: dvander@2168: bool LibrarySystem::IsPathFile(const char *path) dvander@2168: { dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: DWORD attr = GetFileAttributes(path); dvander@2168: dvander@2168: if (attr == INVALID_FILE_ATTRIBUTES) dvander@2168: { dvander@2168: return false; dvander@2168: } dvander@2168: dvander@2168: if (attr & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE)) dvander@2168: { dvander@2168: return false; dvander@2168: } dvander@2168: dvander@2168: return true; dvander@2168: #elif defined PLATFORM_LINUX dvander@2168: struct stat s; dvander@2168: dvander@2168: if (stat(path, &s) != 0) dvander@2168: { dvander@2168: return false; dvander@2168: } dvander@2168: dvander@2168: return S_ISREG(s.st_mode) ? true : false; dvander@2168: #endif dvander@2168: } dvander@2168: dvander@2168: bool LibrarySystem::IsPathDirectory(const char *path) dvander@2168: { dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: DWORD attr = GetFileAttributes(path); dvander@2168: dvander@2168: if (attr == INVALID_FILE_ATTRIBUTES) dvander@2168: { dvander@2168: return false; dvander@2168: } dvander@2168: dvander@2168: if (attr & FILE_ATTRIBUTE_DIRECTORY) dvander@2168: { dvander@2168: return true; dvander@2168: } dvander@2168: dvander@2168: #elif defined PLATFORM_LINUX dvander@2168: struct stat s; dvander@2168: dvander@2168: if (stat(path, &s) != 0) dvander@2168: { dvander@2168: return false; dvander@2168: } dvander@2168: dvander@2168: if (S_ISDIR(s.st_mode)) dvander@2168: { dvander@2168: return true; dvander@2168: } dvander@2168: #endif dvander@2168: dvander@2168: return false; dvander@2168: } dvander@2168: dvander@2168: IDirectory *LibrarySystem::OpenDirectory(const char *path) dvander@2168: { dvander@2168: CDirectory *dir = new CDirectory(path); dvander@2168: dvander@2168: if (!dir->IsValid()) dvander@2168: { dvander@2168: delete dir; dvander@2168: return NULL; dvander@2168: } dvander@2168: dvander@2168: return dir; dvander@2168: } dvander@2168: dvander@2168: void LibrarySystem::GetPlatformError(char *error, size_t maxlength) dvander@2168: { dvander@2168: if (error && maxlength) dvander@2168: { dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: DWORD dw = GetLastError(); dvander@2168: FormatMessageA( dvander@2168: FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, dvander@2168: NULL, dvander@2168: dw, dvander@2168: MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), dvander@2168: (LPSTR)error, dvander@2168: maxlength, dvander@2168: NULL); dvander@2168: #elif defined PLATFORM_POSIX dvander@2168: UTIL_Format(error, maxlength, "%s", strerror(errno)); dvander@2168: #endif dvander@2168: } dvander@2168: } dvander@2168: dvander@2168: void LibrarySystem::GetLoaderError(char *buffer, size_t maxlength) dvander@2168: { dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: GetPlatformError(buffer, maxlength); dvander@2168: #elif defined PLATFORM_POSIX dvander@2168: if (buffer != NULL && maxlength) dvander@2168: { dvander@2168: strncopy(buffer, dlerror(), maxlength); dvander@2168: } dvander@2168: #endif dvander@2168: } dvander@2168: dvander@2168: void LibrarySystem::CloseDirectory(IDirectory *dir) dvander@2168: { dvander@2168: delete dir; dvander@2168: } dvander@2168: dvander@2168: ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t maxlength) dvander@2168: { dvander@2168: LibraryHandle lib; dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: lib = LoadLibraryA(path); dvander@2168: #elif defined PLATFORM_POSIX dvander@2168: lib = dlopen(path, RTLD_NOW); dvander@2168: #endif dvander@2168: dvander@2168: if (lib == NULL) dvander@2168: { dvander@2168: GetLoaderError(error, maxlength); dvander@2168: return NULL; dvander@2168: } dvander@2168: dvander@2168: return new CLibrary(lib); dvander@2168: } dvander@2168: dvander@2168: size_t LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...) dvander@2168: { dvander@2168: va_list ap; dvander@2168: va_start(ap, fmt); dvander@2168: size_t mylen = vsnprintf(buffer, len, fmt, ap); dvander@2168: va_end(ap); dvander@2168: dvander@2168: if (mylen >= len) dvander@2168: { dvander@2168: mylen = len - 1; dvander@2168: buffer[mylen] = '\0'; dvander@2168: } dvander@2168: dvander@2168: for (size_t i=0; i= 0 && i <= length - 1; dvander@2168: i--) dvander@2168: { dvander@2168: if (path[i] == '/' dvander@2168: #if defined PLATFORM_WINDOWS dvander@2168: || path[i] == '\\' dvander@2168: #endif dvander@2168: ) dvander@2168: { dvander@2168: return UTIL_Format(buffer, maxlength, "%s", &path[i+1]); dvander@2168: } dvander@2168: } dvander@2168: dvander@2168: /* We scanned and found no path separator */ dvander@2168: return UTIL_Format(buffer, maxlength, "%s", path); dvander@2168: } dvander@2168: dvander@2168: bool LibrarySystem::FileTime(const char *path, FileTimeType type, time_t *pTime) dvander@2168: { dvander@2168: #ifdef PLATFORM_WINDOWS dvander@2168: struct _stat s; dvander@2168: if (_stat(path, &s) != 0) dvander@2168: #elif defined PLATFORM_POSIX dvander@2168: struct stat s; dvander@2168: if (stat(path, &s) != 0) dvander@2168: #endif dvander@2168: { dvander@2168: return false; dvander@2168: } dvander@2168: dvander@2168: if (type == FileTime_LastAccess) dvander@2168: { dvander@2168: *pTime = s.st_atime; dvander@2168: } dvander@2168: else if (type == FileTime_Created) dvander@2168: { dvander@2168: *pTime = s.st_ctime; dvander@2168: } dvander@2168: else if (type == FileTime_LastChange) dvander@2168: { dvander@2168: *pTime = s.st_mtime; dvander@2168: } dvander@2168: dvander@2168: return true; dvander@2168: }