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: }