core/systems/LibrarySys.cpp
author Scott Ehlert <ds@alliedmods.net>
Thu Apr 17 09:23:18 2008 +0000 (2008-04-17)
changeset 2012 bd0a140e2bff
parent 2011 d0be3ddbba1e
child 2013 5cf82fea0177
permissions -rw-r--r--
Oops. Fixed ILibrarySys::GetFileExtension() to work properly on Windows again.
(Had accidentally copied revised version from my Linux-only propcheck program)
ds@1952
     1
/**
ds@1952
     2
 * vim: set ts=4 :
ds@1952
     3
 * =============================================================================
ds@1952
     4
 * SourceMod
ds@1952
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1952
     6
 * =============================================================================
ds@1952
     7
 *
ds@1952
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1952
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1952
    10
 * Free Software Foundation.
ds@1952
    11
 * 
ds@1952
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1952
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1952
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1952
    15
 * details.
ds@1952
    16
 *
ds@1952
    17
 * You should have received a copy of the GNU General Public License along with
ds@1952
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
ds@1952
    19
 *
ds@1952
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1952
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1952
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1952
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1952
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1952
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1952
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1952
    27
 * or <http://www.sourcemod.net/license.php>.
ds@1952
    28
 *
ds@1952
    29
 * Version: $Id$
ds@1952
    30
 */
ds@1952
    31
ds@1952
    32
#include <sys/stat.h>
ds@1952
    33
#include <stdio.h>
ds@1952
    34
#include <stdarg.h>
ds@1952
    35
#include <string.h>
ds@1952
    36
#include <sm_platform.h>
ds@1952
    37
#include "sm_stringutil.h"
ds@1952
    38
#include "LibrarySys.h"
ds@1952
    39
ds@1952
    40
LibrarySystem g_LibSys;
ds@1952
    41
ds@1952
    42
CLibrary::~CLibrary()
ds@1952
    43
{
ds@1952
    44
	if (m_lib)
ds@1952
    45
	{
ds@1952
    46
#if defined PLATFORM_WINDOWS
ds@1952
    47
		FreeLibrary(m_lib);
ds@1952
    48
#elif defined PLATFORM_POSIX
ds@1952
    49
		dlclose(m_lib);
ds@1952
    50
#endif
ds@1952
    51
		m_lib = NULL;
ds@1952
    52
	}
ds@1952
    53
}
ds@1952
    54
ds@1952
    55
CLibrary::CLibrary(LibraryHandle me)
ds@1952
    56
{
ds@1952
    57
	m_lib = me;
ds@1952
    58
}
ds@1952
    59
ds@1952
    60
void CLibrary::CloseLibrary()
ds@1952
    61
{
ds@1952
    62
	delete this;
ds@1952
    63
}
ds@1952
    64
ds@1952
    65
void *CLibrary::GetSymbolAddress(const char *symname)
ds@1952
    66
{
ds@1952
    67
#if defined PLATFORM_WINDOWS
ds@1952
    68
	return GetProcAddress(m_lib, symname);
ds@1952
    69
#elif defined PLATFORM_POSIX
ds@1952
    70
	return dlsym(m_lib, symname);
ds@1952
    71
#endif
ds@1952
    72
}
ds@1952
    73
ds@1952
    74
ds@1952
    75
/********************
ds@1952
    76
 ** Directory Code **
ds@1952
    77
 ********************/
ds@1952
    78
ds@1952
    79
ds@1952
    80
CDirectory::CDirectory(const char *path)
ds@1952
    81
{
ds@1952
    82
#if defined PLATFORM_WINDOWS
ds@1952
    83
	char newpath[PLATFORM_MAX_PATH];
ds@1952
    84
	snprintf(newpath, sizeof(newpath), "%s\\*.*", path);
ds@1952
    85
	m_dir = FindFirstFileA(newpath, &m_fd);
ds@1952
    86
	if (!IsValid())
ds@1952
    87
	{
ds@1952
    88
		m_fd.cFileName[0] = '\0';
ds@1952
    89
	}
ds@1952
    90
#elif defined PLATFORM_POSIX
ds@1952
    91
	m_dir = opendir(path);
ds@1952
    92
	if (IsValid())
ds@1952
    93
	{
ds@1952
    94
		/* :TODO: we need to read past "." and ".."! */
ds@1952
    95
		ep = readdir(m_dir);
ds@1952
    96
		snprintf(m_origpath, PLATFORM_MAX_PATH, "%s", path);
ds@1952
    97
	} else {
ds@1952
    98
		ep = NULL;
ds@1952
    99
	}
ds@1952
   100
#endif
ds@1952
   101
}
ds@1952
   102
ds@1952
   103
CDirectory::~CDirectory()
ds@1952
   104
{
ds@1952
   105
	if (IsValid())
ds@1952
   106
	{
ds@1952
   107
#if defined PLATFORM_WINDOWS
ds@1952
   108
		FindClose(m_dir);
ds@1952
   109
#elif defined PLATFORM_POSIX
ds@1952
   110
		closedir(m_dir);
ds@1952
   111
#endif
ds@1952
   112
	}
ds@1952
   113
}
ds@1952
   114
ds@1952
   115
void CDirectory::NextEntry()
ds@1952
   116
{
ds@1952
   117
#if defined PLATFORM_WINDOWS
ds@1952
   118
	if (FindNextFile(m_dir, &m_fd) == 0)
ds@1952
   119
	{
ds@1952
   120
		FindClose(m_dir);
ds@1952
   121
		m_dir = INVALID_HANDLE_VALUE;
ds@1952
   122
	}
ds@1952
   123
#elif defined PLATFORM_POSIX
ds@1952
   124
	if ((ep=readdir(m_dir)) == NULL)
ds@1952
   125
	{
ds@1952
   126
		closedir(m_dir);
ds@1952
   127
		m_dir = NULL;
ds@1952
   128
	}
ds@1952
   129
#endif
ds@1952
   130
}
ds@1952
   131
ds@1952
   132
bool CDirectory::IsEntryValid()
ds@1952
   133
{
ds@1952
   134
	return IsValid();
ds@1952
   135
}
ds@1952
   136
ds@1952
   137
bool CDirectory::IsEntryDirectory()
ds@1952
   138
{
ds@1952
   139
#if defined PLATFORM_WINDOWS
ds@1952
   140
	return ((m_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
ds@1952
   141
#elif defined PLATFORM_LINUX
ds@1952
   142
	char temppath[PLATFORM_MAX_PATH];
ds@1952
   143
	snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
ds@1952
   144
	return g_LibSys.IsPathDirectory(temppath);
ds@1952
   145
#endif
ds@1952
   146
}
ds@1952
   147
ds@1952
   148
bool CDirectory::IsEntryFile()
ds@1952
   149
{
ds@1952
   150
#if defined PLATFORM_WINDOWS
ds@1952
   151
	return !(m_fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE));
ds@1952
   152
#elif defined PLATFORM_POSIX
ds@1952
   153
	char temppath[PLATFORM_MAX_PATH];
ds@1952
   154
	snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
ds@1952
   155
	return g_LibSys.IsPathFile(temppath);
ds@1952
   156
#endif
ds@1952
   157
}
ds@1952
   158
ds@1952
   159
const char *CDirectory::GetEntryName()
ds@1952
   160
{
ds@1952
   161
#if defined PLATFORM_WINDOWS
ds@1952
   162
	return m_fd.cFileName;
ds@1952
   163
#elif defined PLATFORM_LINUX
ds@1952
   164
	return ep ? ep->d_name : "";
ds@1952
   165
#endif
ds@1952
   166
}
ds@1952
   167
ds@1952
   168
bool CDirectory::MoreFiles()
ds@1952
   169
{
ds@1952
   170
	return IsValid();
ds@1952
   171
}
ds@1952
   172
ds@1952
   173
bool CDirectory::IsValid()
ds@1952
   174
{
ds@1952
   175
#if defined PLATFORM_WINDOWS
ds@1952
   176
	return (m_dir != INVALID_HANDLE_VALUE);
ds@1952
   177
#elif defined PLATFORM_LINUX
ds@1952
   178
	return (m_dir != NULL);
ds@1952
   179
#endif
ds@1952
   180
}
ds@1952
   181
ds@1952
   182
ds@1952
   183
/*************************
ds@1952
   184
 ** Library System Code **
ds@1952
   185
 *************************/
ds@1952
   186
ds@1952
   187
ds@1952
   188
bool LibrarySystem::PathExists(const char *path)
ds@1952
   189
{
ds@1952
   190
#if defined PLATFORM_WINDOWS
ds@1952
   191
	DWORD attr = GetFileAttributesA(path);
ds@1952
   192
ds@1952
   193
	return (attr != INVALID_FILE_ATTRIBUTES);
ds@1952
   194
#elif defined PLATFORM_POSIX
ds@1952
   195
	struct stat s;
ds@1952
   196
ds@1952
   197
	return (stat(path, &s) == 0);
ds@1952
   198
#endif
ds@1952
   199
}
ds@1952
   200
ds@1952
   201
bool LibrarySystem::IsPathFile(const char *path)
ds@1952
   202
{
ds@1952
   203
#if defined PLATFORM_WINDOWS
ds@1952
   204
	DWORD attr = GetFileAttributes(path);
ds@1952
   205
ds@1952
   206
	if (attr == INVALID_FILE_ATTRIBUTES)
ds@1952
   207
	{
ds@1952
   208
		return false;
ds@1952
   209
	}
ds@1952
   210
ds@1952
   211
	if (attr & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
ds@1952
   212
	{
ds@1952
   213
		return false;
ds@1952
   214
	}
ds@1952
   215
ds@1952
   216
	return true;
ds@1952
   217
#elif defined PLATFORM_LINUX
ds@1952
   218
	struct stat s;
ds@1952
   219
ds@1952
   220
	if (stat(path, &s) != 0)
ds@1952
   221
	{
ds@1952
   222
		return false;
ds@1952
   223
	}
ds@1952
   224
ds@1952
   225
	return S_ISREG(s.st_mode) ? true : false;
ds@1952
   226
#endif
ds@1952
   227
}
ds@1952
   228
ds@1952
   229
bool LibrarySystem::IsPathDirectory(const char *path)
ds@1952
   230
{
ds@1952
   231
#if defined PLATFORM_WINDOWS
ds@1952
   232
	DWORD attr = GetFileAttributes(path);
ds@1952
   233
ds@1952
   234
	if (attr == INVALID_FILE_ATTRIBUTES)
ds@1952
   235
	{
ds@1952
   236
		return false;
ds@1952
   237
	}
ds@1952
   238
ds@1952
   239
	if (attr & FILE_ATTRIBUTE_DIRECTORY)
ds@1952
   240
	{
ds@1952
   241
		return true;
ds@1952
   242
	}
ds@1952
   243
ds@1952
   244
#elif defined PLATFORM_LINUX
ds@1952
   245
	struct stat s;
ds@1952
   246
ds@1952
   247
	if (stat(path, &s) != 0)
ds@1952
   248
	{
ds@1952
   249
		return false;
ds@1952
   250
	}
ds@1952
   251
ds@1952
   252
	if (S_ISDIR(s.st_mode))
ds@1952
   253
	{
ds@1952
   254
		return true;
ds@1952
   255
	}
ds@1952
   256
#endif
ds@1952
   257
ds@1952
   258
	return false;
ds@1952
   259
}
ds@1952
   260
ds@1952
   261
IDirectory *LibrarySystem::OpenDirectory(const char *path)
ds@1952
   262
{
ds@1952
   263
	CDirectory *dir = new CDirectory(path);
ds@1952
   264
ds@1952
   265
	if (!dir->IsValid())
ds@1952
   266
	{
ds@1952
   267
		delete dir;
ds@1952
   268
		return NULL;
ds@1952
   269
	}
ds@1952
   270
ds@1952
   271
	return dir;
ds@1952
   272
}
ds@1952
   273
ds@1952
   274
void LibrarySystem::GetPlatformError(char *error, size_t maxlength)
ds@1952
   275
{
ds@1952
   276
	if (error && maxlength)
ds@1952
   277
	{
ds@1952
   278
#if defined PLATFORM_WINDOWS
ds@1952
   279
		DWORD dw = GetLastError();
ds@1952
   280
		FormatMessageA(
ds@1952
   281
			FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
ds@1952
   282
			NULL,
ds@1952
   283
			dw,
ds@1952
   284
			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
ds@1952
   285
			(LPSTR)error,
ds@1952
   286
			maxlength,
ds@1952
   287
			NULL);
ds@1952
   288
#elif defined PLATFORM_POSIX
dvander@1974
   289
		UTIL_Format(error, maxlength, "%s", strerror(errno));
ds@1952
   290
#endif
ds@1952
   291
	}
ds@1952
   292
}
ds@1952
   293
dvander@1974
   294
void LibrarySystem::GetLoaderError(char *buffer, size_t maxlength)
dvander@1974
   295
{
dvander@1974
   296
#if defined PLATFORM_WINDOWS
dvander@1974
   297
	GetPlatformError(buffer, maxlength);
dvander@1974
   298
#elif defined PLATFORM_POSIX
dvander@1974
   299
	if (buffer != NULL && maxlength)
dvander@1974
   300
	{
dvander@1974
   301
		strncopy(buffer, dlerror(), maxlength);
dvander@1974
   302
	}
dvander@1974
   303
#endif
dvander@1974
   304
}
dvander@1974
   305
ds@1952
   306
void LibrarySystem::CloseDirectory(IDirectory *dir)
ds@1952
   307
{
ds@1952
   308
	delete dir;
ds@1952
   309
}
ds@1952
   310
ds@1952
   311
ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t maxlength)
ds@1952
   312
{
ds@1952
   313
	LibraryHandle lib;
ds@1952
   314
#if defined PLATFORM_WINDOWS
ds@1952
   315
	lib = LoadLibraryA(path);
ds@1952
   316
#elif defined PLATFORM_POSIX
ds@1952
   317
	lib = dlopen(path, RTLD_NOW);
dvander@1974
   318
#endif
dvander@1974
   319
dvander@1974
   320
	if (lib == NULL)
ds@1952
   321
	{
dvander@1974
   322
		GetLoaderError(error, maxlength);
dvander@1974
   323
		return NULL;
ds@1952
   324
	}
ds@1952
   325
ds@1952
   326
	return new CLibrary(lib);
ds@1952
   327
}
ds@1952
   328
ds@1952
   329
size_t LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...)
ds@1952
   330
{
ds@1952
   331
	va_list ap;
ds@1952
   332
	va_start(ap, fmt);
ds@1952
   333
	size_t mylen = vsnprintf(buffer, len, fmt, ap);
ds@1952
   334
	va_end(ap);
ds@1952
   335
ds@1952
   336
	if (mylen >= len)
ds@1952
   337
	{
ds@1952
   338
		mylen = len - 1;
ds@1952
   339
		buffer[mylen] = '\0';
ds@1952
   340
	}
ds@1952
   341
ds@1952
   342
	for (size_t i=0; i<mylen; i++)
ds@1952
   343
	{
ds@1952
   344
		if (buffer[i] == PLATFORM_SEP_ALTCHAR)
ds@1952
   345
		{
ds@1952
   346
			buffer[i] = PLATFORM_SEP_CHAR;
ds@1952
   347
		}
ds@1952
   348
	}
ds@1952
   349
ds@1952
   350
	return mylen;
ds@1952
   351
}
ds@1952
   352
ds@1952
   353
const char *LibrarySystem::GetFileExtension(const char *filename)
ds@1952
   354
{
ds@2011
   355
	size_t len, end, i;
ds@2011
   356
ds@2011
   357
	len = strlen(filename);
ds@1952
   358
ds@2011
   359
	/* Minimum string length for filename with ext would be 3; example: a.a */
ds@2011
   360
	if (len < 3)
ds@1952
   361
	{
ds@2011
   362
		return NULL;
ds@2011
   363
	}
ds@2011
   364
ds@2011
   365
	end = len - 1;
ds@2011
   366
ds@2011
   367
	for (i = end; i <= end; i--)
ds@2011
   368
	{
ds@2012
   369
		if (filename[i] == PLATFORM_SEP_CHAR || filename[i] == PLATFORM_SEP_ALTCHAR)
ds@1952
   370
		{
ds@1952
   371
			break;
ds@1952
   372
		}
ds@1952
   373
ds@2011
   374
		if (filename[i] == '.' && i != end && i != 0)
ds@1952
   375
		{
ds@1952
   376
			return &filename[++i];
ds@1952
   377
		}
ds@1952
   378
	}
ds@1952
   379
ds@1952
   380
	return NULL;
ds@1952
   381
}
ds@1952
   382
ds@1952
   383
bool LibrarySystem::CreateFolder(const char *path)
ds@1952
   384
{
ds@1952
   385
#if defined PLATFORM_WINDOWS
ds@1952
   386
	return (mkdir(path) != -1);
ds@1952
   387
#elif defined PLATFORM_POSIX
ds@1952
   388
	return (mkdir(path, 0775) != -1);
ds@1952
   389
#endif
ds@1952
   390
}
ds@1952
   391
ds@1952
   392
size_t LibrarySystem::GetFileFromPath(char *buffer, size_t maxlength, const char *path)
ds@1952
   393
{
ds@1952
   394
	size_t length = strlen(path);
ds@1952
   395
ds@1952
   396
	for (size_t i = length - 1;
ds@1952
   397
		 i >= 0 && i <= length - 1;
ds@1952
   398
		 i--)
ds@1952
   399
	{
ds@1952
   400
		if (path[i] == '/' 
ds@1952
   401
#if defined PLATFORM_WINDOWS
ds@1952
   402
			|| path[i] == '\\'
ds@1952
   403
#endif
ds@1952
   404
			)
ds@1952
   405
		{
ds@1952
   406
			return UTIL_Format(buffer, maxlength, "%s", &path[i+1]);
ds@1952
   407
		}
ds@1952
   408
	}
ds@1952
   409
ds@1952
   410
	/* We scanned and found no path separator */
ds@1952
   411
	return UTIL_Format(buffer, maxlength, "%s", path);
ds@1952
   412
}
ds@1952
   413
ds@1952
   414
bool LibrarySystem::FileTime(const char *path, FileTimeType type, time_t *pTime)
ds@1952
   415
{
ds@1952
   416
#ifdef PLATFORM_WINDOWS
ds@1952
   417
	struct _stat s;
ds@1952
   418
	if (_stat(path, &s) != 0)
ds@1952
   419
#elif defined PLATFORM_POSIX
ds@1952
   420
	struct stat s;
ds@1952
   421
	if (stat(path, &s) != 0)
ds@1952
   422
#endif
ds@1952
   423
	{
ds@1952
   424
		return false;
ds@1952
   425
	}
ds@1952
   426
ds@1952
   427
	if (type == FileTime_LastAccess)
ds@1952
   428
	{
ds@1952
   429
		*pTime = s.st_atime;
ds@1952
   430
	}
ds@1952
   431
	else if (type == FileTime_Created)
ds@1952
   432
	{
ds@1952
   433
		*pTime = s.st_ctime;
ds@1952
   434
	}
ds@1952
   435
	else if (type == FileTime_LastChange)
ds@1952
   436
	{
ds@1952
   437
		*pTime = s.st_mtime;
ds@1952
   438
	}
ds@1952
   439
ds@1952
   440
	return true;
ds@1952
   441
}