Easier platform porting (#108)
* Create PORTING.md * Creates io_platform abstraction * removes miniposix * remove unistd refs * removes watcom functions * fixes shadow rendering memory leak
This commit is contained in:
parent
d3ebbb6f1f
commit
7e14a97692
|
|
@ -20,7 +20,6 @@ option(BUILD_TESTS "Build unit tests." OFF)
|
|||
find_package(SDL2 REQUIRED)
|
||||
|
||||
add_subdirectory(lib/libsmacker)
|
||||
add_subdirectory(lib/miniposix)
|
||||
add_subdirectory(lib/glad)
|
||||
add_subdirectory(lib/cglm EXCLUDE_FROM_ALL)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
# Porting Dethrace to other systems
|
||||
|
||||
## Operating Systems
|
||||
|
||||
See: xxx
|
||||
|
||||
Assuming an operating system called _foo_, follow the steps to add support for it.
|
||||
|
||||
1. Add a new file `os/foo.h` and implement the required functions defined in `os.h`:
|
||||
- `OS_GetTime`
|
||||
- `OS_Sleep`
|
||||
- `OS_Basename`
|
||||
- `OS_GetFirstFileInDirectory`
|
||||
- `OS_GetNextFileInDirectory`
|
||||
- `OS_IsDebuggerPresent`
|
||||
- `OS_InstallSignalHandler`
|
||||
|
||||
2. Update `src/harness/CMakeLists.h` and add a new conditional section for "os/foo.h", based on existing conditions for Windows, MacOS etc.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
...
|
||||
elseif( _FOO_ )
|
||||
target_sources(harness PRIVATE
|
||||
os/foo.c
|
||||
)
|
||||
...
|
||||
```
|
||||
|
||||
## IO Platform (windowing / input / rendering)
|
||||
|
||||
An `IOPlatform` in _dethrace_ implements windowing and input handling, and points to a _renderer_.
|
||||
|
||||
The default IO platform is `SDL_OpenGL`, which uses SDL for windowing and input, and OpenGL for rendering. See `io_platforms/sdl_gl.c`.
|
||||
|
||||
To add a new `IOPlatform`:
|
||||
|
||||
1. Create `io_platforms/my_platform.c` file and implement the required functions defined in `io_platform.h`:
|
||||
- `Window_Create`
|
||||
- `Window_PollEvents`
|
||||
- `Window_Swap`
|
||||
- `Input_GetKeyMap`
|
||||
- `Input_IsKeyDown`
|
||||
|
||||
`Window_Create` returns a `tRenderer*`, which must implement the interface defined in `renderers/renderer.h`. See `renderers/gl` for an example.
|
||||
|
||||
2. Add a new conditional section in `src/harness/CMakeLists.txt` for your new platform
|
||||
|
||||
For example:
|
||||
```
|
||||
if (IO_PLATFORM STREQUAL "My_Platform")
|
||||
target_sources(harness PRIVATE
|
||||
io_platforms/my_platform.c
|
||||
)
|
||||
endif()
|
||||
```
|
||||
|
||||
3. Run cmake to update your build with the new platform
|
||||
```sh
|
||||
cd build
|
||||
cmake -DIO_PLATFORM=My_Platform ..
|
||||
```
|
||||
|
||||
4. Build
|
||||
```
|
||||
cmake --build .
|
||||
```
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
include(CheckIncludeFile)
|
||||
|
||||
# Check if we are missing any posix headers we consider required.
|
||||
check_include_file(strings.h HAVE_STRINGS_H)
|
||||
check_include_file(libgen.h HAVE_LIBGEN_H)
|
||||
check_include_file(dirent.h HAVE_DIRENT_H)
|
||||
check_include_file(fnmatch.h HAVE_FNMATCH_H)
|
||||
check_include_file(getopt.h HAVE_GETOPT_H)
|
||||
check_include_file(unistd.h HAVE_UNISTD_H)
|
||||
|
||||
if(HAVE_STRINGS_H AND HAVE_UNISTD_H AND HAVE_LIBGEN_H AND HAVE_DIRENT_H AND HAVE_FNMATCH_H AND HAVE_GETOPT_H)
|
||||
add_library(miniposix INTERFACE)
|
||||
else()
|
||||
add_library(miniposix STATIC)
|
||||
|
||||
# Only win32 targets should really need miniposix at all, but just to be safe.
|
||||
if(WIN32)
|
||||
target_compile_definitions(miniposix PUBLIC _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE WIN32_LEAN_AND_MEAN)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT HAVE_STRINGS_H)
|
||||
target_sources(miniposix PRIVATE strings/strings.c strings/strings.h)
|
||||
target_include_directories(miniposix PUBLIC strings)
|
||||
endif()
|
||||
|
||||
if(NOT HAVE_LIBGEN_H)
|
||||
target_sources(miniposix PRIVATE libgen/libgen.c libgen/libgen.h)
|
||||
target_include_directories(miniposix PUBLIC libgen)
|
||||
endif()
|
||||
|
||||
if(NOT HAVE_DIRENT_H)
|
||||
target_sources(miniposix PRIVATE dirent/dirent.c dirent/dirent.h)
|
||||
target_include_directories(miniposix PUBLIC dirent)
|
||||
endif()
|
||||
|
||||
if(NOT HAVE_FNMATCH_H)
|
||||
target_sources(miniposix PRIVATE fnmatch/fnmatch.c fnmatch/fnmatch.h)
|
||||
target_include_directories(miniposix PUBLIC fnmatch)
|
||||
endif()
|
||||
|
||||
if(NOT HAVE_GETOPT_H)
|
||||
target_sources(miniposix PRIVATE getopt/getopt.c getopt/getopt.h)
|
||||
target_include_directories(miniposix PUBLIC getopt)
|
||||
endif()
|
||||
|
||||
if(NOT HAVE_UNISTD_H)
|
||||
target_sources(miniposix PRIVATE unistd/unistd.h)
|
||||
target_include_directories(miniposix PUBLIC unistd)
|
||||
endif()
|
||||
|
|
@ -1,382 +0,0 @@
|
|||
#include <dirent.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
struct __dir
|
||||
{
|
||||
struct dirent *entries;
|
||||
HANDLE fd;
|
||||
long int count;
|
||||
long int index;
|
||||
};
|
||||
|
||||
static void __seterrno(int value)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
_set_errno(value);
|
||||
#else /* _MSC_VER */
|
||||
errno = value;
|
||||
#endif /* _MSC_VER */
|
||||
}
|
||||
|
||||
int closedir(DIR *dirp)
|
||||
{
|
||||
struct __dir *data = NULL;
|
||||
if (!dirp) {
|
||||
__seterrno(EBADF);
|
||||
return -1;
|
||||
}
|
||||
data = (struct __dir *)dirp;
|
||||
CloseHandle((HANDLE)data->fd);
|
||||
free(data->entries);
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __islink(const wchar_t *name, char *buffer)
|
||||
{
|
||||
DWORD io_result = 0;
|
||||
DWORD bytes_returned = 0;
|
||||
HANDLE hFile =
|
||||
CreateFileW(name, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
io_result = DeviceIoControl(
|
||||
hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytes_returned, NULL);
|
||||
|
||||
CloseHandle(hFile);
|
||||
|
||||
if (io_result == 0)
|
||||
return 0;
|
||||
|
||||
return ((REPARSE_GUID_DATA_BUFFER *)buffer)->ReparseTag == IO_REPARSE_TAG_SYMLINK;
|
||||
}
|
||||
|
||||
static __ino_t __inode(const wchar_t *name)
|
||||
{
|
||||
__ino_t value = { 0 };
|
||||
BOOL result;
|
||||
FILE_ID_INFO fileid;
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
HANDLE hFile = CreateFileW(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return value;
|
||||
|
||||
result = GetFileInformationByHandleEx(hFile, FileIdInfo, &fileid, sizeof(fileid));
|
||||
if (result) {
|
||||
value.serial = fileid.VolumeSerialNumber;
|
||||
memcpy(value.fileid, fileid.FileId.Identifier, 16);
|
||||
} else {
|
||||
result = GetFileInformationByHandle(hFile, &info);
|
||||
if (result) {
|
||||
value.serial = info.dwVolumeSerialNumber;
|
||||
memcpy(value.fileid + 8, &info.nFileIndexHigh, 4);
|
||||
memcpy(value.fileid + 12, &info.nFileIndexLow, 4);
|
||||
}
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
return value;
|
||||
}
|
||||
|
||||
static DIR *__internal_opendir(wchar_t *wname, int size)
|
||||
{
|
||||
struct __dir *data = NULL;
|
||||
struct dirent *tmp_entries = NULL;
|
||||
static char default_char = '?';
|
||||
static wchar_t *prefix = L"\\\\?\\";
|
||||
static wchar_t *suffix = L"\\*.*";
|
||||
int extra_prefix = 4; /* use prefix "\\?\" to handle long file names */
|
||||
static int extra_suffix = 4; /* use suffix "\*.*" to find everything */
|
||||
WIN32_FIND_DATAW w32fd = { 0 };
|
||||
HANDLE hFindFile = INVALID_HANDLE_VALUE;
|
||||
static int grow_factor = 2;
|
||||
char *buffer = NULL;
|
||||
|
||||
/* Ensure path only uses windows separator, of FindFirstFileW will fail. */
|
||||
wchar_t* rep = wname;
|
||||
while ((rep = wcschr(rep, L'/')) != NULL) {
|
||||
*rep++ = L'\\';
|
||||
}
|
||||
|
||||
memcpy(wname + extra_prefix + size - 1, suffix, sizeof(wchar_t) * extra_prefix);
|
||||
wname[size + extra_prefix + extra_suffix - 1] = 0;
|
||||
|
||||
if (memcmp(wname + extra_prefix, L"\\\\?\\", sizeof(wchar_t) * extra_prefix) == 0) {
|
||||
wname += extra_prefix;
|
||||
extra_prefix = 0;
|
||||
}
|
||||
|
||||
hFindFile = FindFirstFileW(wname, &w32fd);
|
||||
if (INVALID_HANDLE_VALUE == hFindFile) {
|
||||
__seterrno(ENOENT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = (struct __dir *)malloc(sizeof(struct __dir));
|
||||
if (!data)
|
||||
goto out_of_memory;
|
||||
wname[extra_prefix + size - 1] = 0;
|
||||
data->fd = CreateFileW(wname, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
wname[extra_prefix + size - 1] = L'\\';
|
||||
data->count = 16;
|
||||
data->index = 0;
|
||||
data->entries = (struct dirent *)malloc(sizeof(struct dirent) * data->count);
|
||||
if (!data->entries)
|
||||
goto out_of_memory;
|
||||
buffer = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
||||
if (!buffer)
|
||||
goto out_of_memory;
|
||||
do {
|
||||
WideCharToMultiByte(
|
||||
CP_UTF8, 0, w32fd.cFileName, -1, data->entries[data->index].d_name, NAME_MAX, &default_char, NULL);
|
||||
|
||||
memcpy(wname + extra_prefix + size, w32fd.cFileName, sizeof(wchar_t) * NAME_MAX);
|
||||
|
||||
if (((w32fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT)
|
||||
&& __islink(wname, buffer))
|
||||
data->entries[data->index].d_type = DT_LNK;
|
||||
else if ((w32fd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) == FILE_ATTRIBUTE_DEVICE)
|
||||
data->entries[data->index].d_type = DT_CHR;
|
||||
else if ((w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
|
||||
data->entries[data->index].d_type = DT_DIR;
|
||||
else
|
||||
data->entries[data->index].d_type = DT_REG;
|
||||
|
||||
data->entries[data->index].d_ino = __inode(wname);
|
||||
data->entries[data->index].d_reclen = sizeof(struct dirent);
|
||||
data->entries[data->index].d_namelen = (unsigned char)wcslen(w32fd.cFileName);
|
||||
data->entries[data->index].d_off = 0;
|
||||
|
||||
if (++data->index == data->count) {
|
||||
tmp_entries = (struct dirent *)realloc(data->entries, sizeof(struct dirent) * data->count * grow_factor);
|
||||
if (!tmp_entries)
|
||||
goto out_of_memory;
|
||||
data->entries = tmp_entries;
|
||||
data->count *= grow_factor;
|
||||
}
|
||||
} while (FindNextFileW(hFindFile, &w32fd) != 0);
|
||||
|
||||
free(buffer);
|
||||
FindClose(hFindFile);
|
||||
|
||||
data->count = data->index;
|
||||
data->index = 0;
|
||||
return (DIR *)data;
|
||||
out_of_memory:
|
||||
if (data) {
|
||||
if (INVALID_HANDLE_VALUE != (HANDLE)data->fd)
|
||||
CloseHandle((HANDLE)data->fd);
|
||||
free(data->entries);
|
||||
}
|
||||
free(buffer);
|
||||
free(data);
|
||||
if (INVALID_HANDLE_VALUE != hFindFile)
|
||||
FindClose(hFindFile);
|
||||
__seterrno(ENOMEM);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static wchar_t *__get_buffer()
|
||||
{
|
||||
wchar_t *name = malloc(sizeof(wchar_t) * (NTFS_MAX_PATH + NAME_MAX + 8));
|
||||
if (name)
|
||||
memcpy(name, L"\\\\?\\", sizeof(wchar_t) * 4);
|
||||
return name;
|
||||
}
|
||||
|
||||
DIR *opendir(const char *name)
|
||||
{
|
||||
DIR *dirp = NULL;
|
||||
wchar_t *wname = __get_buffer();
|
||||
int size = 0;
|
||||
if (!wname) {
|
||||
__seterrno(ENOMEM);
|
||||
return NULL;
|
||||
}
|
||||
size = MultiByteToWideChar(CP_UTF8, 0, name, -1, wname + 4, NTFS_MAX_PATH);
|
||||
if (0 == size) {
|
||||
free(wname);
|
||||
return NULL;
|
||||
}
|
||||
dirp = __internal_opendir(wname, size);
|
||||
free(wname);
|
||||
return dirp;
|
||||
}
|
||||
|
||||
DIR *_wopendir(const wchar_t *name)
|
||||
{
|
||||
DIR *dirp = NULL;
|
||||
wchar_t *wname = __get_buffer();
|
||||
int size = 0;
|
||||
if (!wname) {
|
||||
__seterrno(ENOMEM);
|
||||
return NULL;
|
||||
}
|
||||
size = (int)wcslen(name);
|
||||
if (size > NTFS_MAX_PATH) {
|
||||
free(wname);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(wname + 4, name, sizeof(wchar_t) * (size + 1));
|
||||
dirp = __internal_opendir(wname, size + 1);
|
||||
free(wname);
|
||||
return dirp;
|
||||
}
|
||||
|
||||
DIR *fdopendir(int fd)
|
||||
{
|
||||
DIR *dirp = NULL;
|
||||
wchar_t *wname = __get_buffer();
|
||||
int size = 0;
|
||||
if (!wname) {
|
||||
__seterrno(ENOMEM);
|
||||
return NULL;
|
||||
}
|
||||
size = GetFinalPathNameByHandleW((HANDLE)((intptr_t)fd), wname, NTFS_MAX_PATH, FILE_NAME_NORMALIZED);
|
||||
if (0 == size) {
|
||||
free(wname);
|
||||
__seterrno(ENOTDIR);
|
||||
return NULL;
|
||||
}
|
||||
dirp = __internal_opendir(wname, size + 1);
|
||||
free(wname);
|
||||
return dirp;
|
||||
}
|
||||
|
||||
struct dirent *readdir(DIR *dirp)
|
||||
{
|
||||
struct __dir *data = (struct __dir *)dirp;
|
||||
if (!data) {
|
||||
__seterrno(EBADF);
|
||||
return NULL;
|
||||
}
|
||||
if (data->index < data->count) {
|
||||
return &data->entries[data->index++];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
|
||||
{
|
||||
struct __dir *data = (struct __dir *)dirp;
|
||||
if (!data) {
|
||||
return EBADF;
|
||||
}
|
||||
if (data->index < data->count) {
|
||||
if (entry)
|
||||
memcpy(entry, &data->entries[data->index++], sizeof(struct dirent));
|
||||
if (result)
|
||||
*result = entry;
|
||||
} else if (result)
|
||||
*result = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void seekdir(DIR *dirp, long int offset)
|
||||
{
|
||||
if (dirp) {
|
||||
struct __dir *data = (struct __dir *)dirp;
|
||||
data->index = (offset < data->count) ? offset : data->index;
|
||||
}
|
||||
}
|
||||
|
||||
void rewinddir(DIR *dirp)
|
||||
{
|
||||
seekdir(dirp, 0);
|
||||
}
|
||||
|
||||
long int telldir(DIR *dirp)
|
||||
{
|
||||
if (!dirp) {
|
||||
__seterrno(EBADF);
|
||||
return -1;
|
||||
}
|
||||
return ((struct __dir *)dirp)->count;
|
||||
}
|
||||
|
||||
int dirfd(DIR *dirp)
|
||||
{
|
||||
if (!dirp) {
|
||||
__seterrno(EINVAL);
|
||||
return -1;
|
||||
}
|
||||
return (int)((struct __dir *)dirp)->fd;
|
||||
}
|
||||
|
||||
int scandir(const char *dirp,
|
||||
struct dirent ***namelist,
|
||||
int (*filter)(const struct dirent *),
|
||||
int (*compar)(const struct dirent **, const struct dirent **))
|
||||
{
|
||||
struct dirent **entries = NULL, **tmp_entries = NULL;
|
||||
long int i = 0, index = 0, count = 16;
|
||||
DIR *d = opendir(dirp);
|
||||
struct __dir *data = (struct __dir *)d;
|
||||
if (!data) {
|
||||
closedir(d);
|
||||
__seterrno(ENOENT);
|
||||
return -1;
|
||||
}
|
||||
entries = (struct dirent **)malloc(sizeof(struct dirent *) * count);
|
||||
if (!entries) {
|
||||
closedir(d);
|
||||
__seterrno(ENOMEM);
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < data->count; ++i) {
|
||||
if (!filter || filter(&data->entries[i])) {
|
||||
entries[index] = (struct dirent *)malloc(sizeof(struct dirent));
|
||||
if (!entries[index]) {
|
||||
closedir(d);
|
||||
for (i = 0; i < index; ++i)
|
||||
free(entries[index]);
|
||||
free(entries);
|
||||
__seterrno(ENOMEM);
|
||||
return -1;
|
||||
}
|
||||
memcpy(entries[index], &data->entries[i], sizeof(struct dirent));
|
||||
if (++index == count) {
|
||||
tmp_entries = (struct dirent **)realloc(entries, sizeof(struct dirent *) * count * 2);
|
||||
if (!tmp_entries) {
|
||||
closedir(d);
|
||||
for (i = 0; i < index; ++i)
|
||||
free(entries[index - 1]);
|
||||
free(entries);
|
||||
__seterrno(ENOMEM);
|
||||
return -1;
|
||||
}
|
||||
entries = tmp_entries;
|
||||
count *= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
qsort(entries, index, sizeof(struct dirent *), compar);
|
||||
entries[index] = NULL;
|
||||
if (namelist)
|
||||
*namelist = entries;
|
||||
closedir(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int alphasort(const void *a, const void *b)
|
||||
{
|
||||
struct dirent **dira = (struct dirent **)a, **dirb = (struct dirent **)b;
|
||||
if (!dira || !dirb)
|
||||
return 0;
|
||||
return strcoll((*dira)->d_name, (*dirb)->d_name);
|
||||
}
|
||||
|
||||
static int __strverscmp(const char *s1, const char *s2)
|
||||
{
|
||||
return alphasort(s1, s2);
|
||||
}
|
||||
|
||||
int versionsort(const void *a, const void *b)
|
||||
{
|
||||
struct dirent **dira = (struct dirent **)a, **dirb = (struct dirent **)b;
|
||||
if (!dira || !dirb)
|
||||
return 0;
|
||||
return __strverscmp((*dira)->d_name, (*dirb)->d_name);
|
||||
}
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
MIT License
|
||||
Copyright (c) 2019 win32ports
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef WIN32PORTS_DIRENT_H
|
||||
#define WIN32PORTS_DIRENT_H
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#pragma message("this dirent.h implementation is for Windows only!")
|
||||
|
||||
#elif defined __MINGW32__
|
||||
|
||||
#include <../include/dirent.h>
|
||||
|
||||
#else
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#ifndef NAME_MAX
|
||||
#define NAME_MAX 260
|
||||
#endif /* NAME_MAX */
|
||||
|
||||
#ifndef DT_UNKNOWN
|
||||
#define DT_UNKNOWN 0
|
||||
#endif /* DT_UNKNOWN */
|
||||
|
||||
#ifndef DT_FIFO
|
||||
#define DT_FIFO 1
|
||||
#endif /* DT_FIFO */
|
||||
|
||||
#ifndef DT_CHR
|
||||
#define DT_CHR 2
|
||||
#endif /* DT_CHR */
|
||||
|
||||
#ifndef DT_DIR
|
||||
#define DT_DIR 4
|
||||
#endif /* DT_DIR */
|
||||
|
||||
#ifndef DT_BLK
|
||||
#define DT_BLK 6
|
||||
#endif /* DT_BLK */
|
||||
|
||||
#ifndef DT_REG
|
||||
#define DT_REG 8
|
||||
#endif /* DT_REF */
|
||||
|
||||
#ifndef DT_LNK
|
||||
#define DT_LNK 10
|
||||
#endif /* DT_LNK */
|
||||
|
||||
#ifndef DT_SOCK
|
||||
#define DT_SOCK 12
|
||||
#endif /* DT_SOCK */
|
||||
|
||||
#ifndef DT_WHT
|
||||
#define DT_WHT 14
|
||||
#endif /* DT_WHT */
|
||||
|
||||
#ifndef _DIRENT_HAVE_D_NAMLEN
|
||||
#define _DIRENT_HAVE_D_NAMLEN 1
|
||||
#endif /* _DIRENT_HAVE_D_NAMLEN */
|
||||
|
||||
#ifndef _DIRENT_HAVE_D_RECLEN
|
||||
#define _DIRENT_HAVE_D_RECLEN 1
|
||||
#endif /* _DIRENT_HAVE_D_RECLEN */
|
||||
|
||||
#ifndef _DIRENT_HAVE_D_OFF
|
||||
#define _DIRENT_HAVE_D_OFF 1
|
||||
#endif /* _DIRENT_HAVE_D_OFF */
|
||||
|
||||
#ifndef _DIRENT_HAVE_D_TYPE
|
||||
#define _DIRENT_HAVE_D_TYPE 1
|
||||
#endif /* _DIRENT_HAVE_D_TYPE */
|
||||
|
||||
#ifndef NTFS_MAX_PATH
|
||||
#define NTFS_MAX_PATH 32768
|
||||
#endif /* NTFS_MAX_PATH */
|
||||
|
||||
typedef struct __dir DIR;
|
||||
|
||||
typedef struct ino_t
|
||||
{
|
||||
unsigned long long serial;
|
||||
unsigned char fileid[16];
|
||||
} __ino_t;
|
||||
|
||||
struct dirent
|
||||
{
|
||||
__ino_t d_ino;
|
||||
off_t d_off;
|
||||
unsigned short d_reclen;
|
||||
unsigned char d_namelen;
|
||||
unsigned char d_type;
|
||||
char d_name[NAME_MAX];
|
||||
};
|
||||
|
||||
int closedir(DIR *dirp);
|
||||
DIR *opendir(const char *name);
|
||||
DIR *_wopendir(const wchar_t *name);
|
||||
DIR *fdopendir(int fd);
|
||||
struct dirent *readdir(DIR *dirp);
|
||||
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
|
||||
void seekdir(DIR *dirp, long int offset);
|
||||
void rewinddir(DIR *dirp);
|
||||
long int telldir(DIR *dirp);
|
||||
int dirfd(DIR *dirp);
|
||||
int scandir(const char *dirp,
|
||||
struct dirent ***namelist,
|
||||
int (*filter)(const struct dirent *),
|
||||
int (*compar)(const struct dirent **, const struct dirent **));
|
||||
int alphasort(const void *a, const void *b);
|
||||
int versionsort(const void *a, const void *b);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* WIN32PORTS_DIRENT_H */
|
||||
|
|
@ -1,311 +0,0 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 1989, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Guido van Rossum.
|
||||
*
|
||||
* Copyright (c) 2011 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
* Portions of this software were developed by David Chisnall
|
||||
* under sponsorship from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
|
||||
* Compares a filename or pathname to a pattern.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some notes on multibyte character support:
|
||||
* 1. Patterns with illegal byte sequences match nothing.
|
||||
* 2. Illegal byte sequences in the "string" argument are handled by treating
|
||||
* them as single-byte characters with a value of the first byte of the
|
||||
* sequence cast to wchar_t.
|
||||
* 3. Multibyte conversion state objects (mbstate_t) are passed around and
|
||||
* used for most, but not all, conversions. Further work will be required
|
||||
* to support state-dependent encodings.
|
||||
*/
|
||||
|
||||
#include <fnmatch.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
|
||||
#define EOS '\0'
|
||||
|
||||
#define RANGE_MATCH 1
|
||||
#define RANGE_NOMATCH 0
|
||||
#define RANGE_ERROR (-1)
|
||||
|
||||
static int rangematch(const char *, wchar_t, int, char **, mbstate_t *);
|
||||
static int fnmatch1(const char *, const char *, const char *, int, mbstate_t,
|
||||
mbstate_t);
|
||||
|
||||
int
|
||||
fnmatch(const char *pattern, const char *string, int flags)
|
||||
{
|
||||
static const mbstate_t initial;
|
||||
|
||||
return (fnmatch1(pattern, string, string, flags, initial, initial));
|
||||
}
|
||||
|
||||
static int
|
||||
fnmatch1(const char *pattern, const char *string, const char *stringstart,
|
||||
int flags, mbstate_t patmbs, mbstate_t strmbs)
|
||||
{
|
||||
const char *bt_pattern, *bt_string;
|
||||
mbstate_t bt_patmbs, bt_strmbs;
|
||||
char *newp;
|
||||
char c;
|
||||
wchar_t pc, sc;
|
||||
size_t pclen, sclen;
|
||||
|
||||
bt_pattern = bt_string = NULL;
|
||||
for (;;) {
|
||||
pclen = mbrtowc(&pc, pattern, MB_LEN_MAX, &patmbs);
|
||||
if (pclen == (size_t)-1 || pclen == (size_t)-2)
|
||||
return (FNM_NOMATCH);
|
||||
pattern += pclen;
|
||||
sclen = mbrtowc(&sc, string, MB_LEN_MAX, &strmbs);
|
||||
if (sclen == (size_t)-1 || sclen == (size_t)-2) {
|
||||
sc = (unsigned char)*string;
|
||||
sclen = 1;
|
||||
memset(&strmbs, 0, sizeof(strmbs));
|
||||
}
|
||||
switch (pc) {
|
||||
case EOS:
|
||||
if ((flags & FNM_LEADING_DIR) && sc == '/')
|
||||
return (0);
|
||||
if (sc == EOS)
|
||||
return (0);
|
||||
goto backtrack;
|
||||
case '?':
|
||||
if (sc == EOS)
|
||||
return (FNM_NOMATCH);
|
||||
if (sc == '/' && (flags & FNM_PATHNAME))
|
||||
goto backtrack;
|
||||
if (sc == '.' && (flags & FNM_PERIOD) &&
|
||||
(string == stringstart ||
|
||||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
|
||||
goto backtrack;
|
||||
string += sclen;
|
||||
break;
|
||||
case '*':
|
||||
c = *pattern;
|
||||
/* Collapse multiple stars. */
|
||||
while (c == '*')
|
||||
c = *++pattern;
|
||||
|
||||
if (sc == '.' && (flags & FNM_PERIOD) &&
|
||||
(string == stringstart ||
|
||||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
|
||||
goto backtrack;
|
||||
|
||||
/* Optimize for pattern with * at end or before /. */
|
||||
if (c == EOS)
|
||||
if (flags & FNM_PATHNAME)
|
||||
return ((flags & FNM_LEADING_DIR) ||
|
||||
strchr(string, '/') == NULL ?
|
||||
0 : FNM_NOMATCH);
|
||||
else
|
||||
return (0);
|
||||
else if (c == '/' && flags & FNM_PATHNAME) {
|
||||
if ((string = strchr(string, '/')) == NULL)
|
||||
return (FNM_NOMATCH);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* First try the shortest match for the '*' that
|
||||
* could work. We can forget any earlier '*' since
|
||||
* there is no way having it match more characters
|
||||
* can help us, given that we are already here.
|
||||
*/
|
||||
bt_pattern = pattern, bt_patmbs = patmbs;
|
||||
bt_string = string, bt_strmbs = strmbs;
|
||||
break;
|
||||
case '[':
|
||||
if (sc == EOS)
|
||||
return (FNM_NOMATCH);
|
||||
if (sc == '/' && (flags & FNM_PATHNAME))
|
||||
goto backtrack;
|
||||
if (sc == '.' && (flags & FNM_PERIOD) &&
|
||||
(string == stringstart ||
|
||||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
|
||||
goto backtrack;
|
||||
|
||||
switch (rangematch(pattern, sc, flags, &newp,
|
||||
&patmbs)) {
|
||||
case RANGE_ERROR:
|
||||
goto norm;
|
||||
case RANGE_MATCH:
|
||||
pattern = newp;
|
||||
break;
|
||||
case RANGE_NOMATCH:
|
||||
goto backtrack;
|
||||
}
|
||||
string += sclen;
|
||||
break;
|
||||
case '\\':
|
||||
if (!(flags & FNM_NOESCAPE)) {
|
||||
pclen = mbrtowc(&pc, pattern, MB_LEN_MAX,
|
||||
&patmbs);
|
||||
if (pclen == 0 || pclen == (size_t)-1 ||
|
||||
pclen == (size_t)-2)
|
||||
return (FNM_NOMATCH);
|
||||
pattern += pclen;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
norm:
|
||||
string += sclen;
|
||||
if (pc == sc)
|
||||
;
|
||||
else if ((flags & FNM_CASEFOLD) &&
|
||||
(towlower(pc) == towlower(sc)))
|
||||
;
|
||||
else {
|
||||
backtrack:
|
||||
/*
|
||||
* If we have a mismatch (other than hitting
|
||||
* the end of the string), go back to the last
|
||||
* '*' seen and have it match one additional
|
||||
* character.
|
||||
*/
|
||||
if (bt_pattern == NULL)
|
||||
return (FNM_NOMATCH);
|
||||
sclen = mbrtowc(&sc, bt_string, MB_LEN_MAX,
|
||||
&bt_strmbs);
|
||||
if (sclen == (size_t)-1 ||
|
||||
sclen == (size_t)-2) {
|
||||
sc = (unsigned char)*bt_string;
|
||||
sclen = 1;
|
||||
memset(&bt_strmbs, 0,
|
||||
sizeof(bt_strmbs));
|
||||
}
|
||||
if (sc == EOS)
|
||||
return (FNM_NOMATCH);
|
||||
if (sc == '/' && flags & FNM_PATHNAME)
|
||||
return (FNM_NOMATCH);
|
||||
bt_string += sclen;
|
||||
pattern = bt_pattern, patmbs = bt_patmbs;
|
||||
string = bt_string, strmbs = bt_strmbs;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static int __wcollate_range_cmp(wchar_t c1, wchar_t c2)
|
||||
{
|
||||
wchar_t s1[2], s2[2];
|
||||
|
||||
s1[0] = c1;
|
||||
s1[1] = L'\0';
|
||||
s2[0] = c2;
|
||||
s2[1] = L'\0';
|
||||
return (wcscoll(s1, s2));
|
||||
}
|
||||
|
||||
static int
|
||||
rangematch(const char *pattern, wchar_t test, int flags, char **newp,
|
||||
mbstate_t *patmbs)
|
||||
{
|
||||
int negate, ok;
|
||||
wchar_t c, c2;
|
||||
size_t pclen;
|
||||
const char *origpat;
|
||||
|
||||
/*
|
||||
* A bracket expression starting with an unquoted circumflex
|
||||
* character produces unspecified results (IEEE 1003.2-1992,
|
||||
* 3.13.2). This implementation treats it like '!', for
|
||||
* consistency with the regular expression syntax.
|
||||
* J.T. Conklin (conklin@ngai.kaleida.com)
|
||||
*/
|
||||
if ((negate = (*pattern == '!' || *pattern == '^')))
|
||||
++pattern;
|
||||
|
||||
if (flags & FNM_CASEFOLD)
|
||||
test = towlower(test);
|
||||
|
||||
/*
|
||||
* A right bracket shall lose its special meaning and represent
|
||||
* itself in a bracket expression if it occurs first in the list.
|
||||
* -- POSIX.2 2.8.3.2
|
||||
*/
|
||||
ok = 0;
|
||||
origpat = pattern;
|
||||
for (;;) {
|
||||
if (*pattern == ']' && pattern > origpat) {
|
||||
pattern++;
|
||||
break;
|
||||
} else if (*pattern == '\0') {
|
||||
return (RANGE_ERROR);
|
||||
} else if (*pattern == '/' && (flags & FNM_PATHNAME)) {
|
||||
return (RANGE_NOMATCH);
|
||||
} else if (*pattern == '\\' && !(flags & FNM_NOESCAPE))
|
||||
pattern++;
|
||||
pclen = mbrtowc(&c, pattern, MB_LEN_MAX, patmbs);
|
||||
if (pclen == (size_t)-1 || pclen == (size_t)-2)
|
||||
return (RANGE_NOMATCH);
|
||||
pattern += pclen;
|
||||
|
||||
if (flags & FNM_CASEFOLD)
|
||||
c = towlower(c);
|
||||
|
||||
if (*pattern == '-' && *(pattern + 1) != EOS &&
|
||||
*(pattern + 1) != ']') {
|
||||
if (*++pattern == '\\' && !(flags & FNM_NOESCAPE))
|
||||
if (*pattern != EOS)
|
||||
pattern++;
|
||||
pclen = mbrtowc(&c2, pattern, MB_LEN_MAX, patmbs);
|
||||
if (pclen == (size_t)-1 || pclen == (size_t)-2)
|
||||
return (RANGE_NOMATCH);
|
||||
pattern += pclen;
|
||||
if (c2 == EOS)
|
||||
return (RANGE_ERROR);
|
||||
|
||||
if (flags & FNM_CASEFOLD)
|
||||
c2 = towlower(c2);
|
||||
|
||||
if (__wcollate_range_cmp(c, test) <= 0
|
||||
&& __wcollate_range_cmp(test, c2) <= 0
|
||||
)
|
||||
ok = 1;
|
||||
} else if (c == test)
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
*newp = (char *)pattern;
|
||||
return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
* @(#)fnmatch.h 8.1 (Berkeley) 6/2/93
|
||||
*/
|
||||
|
||||
#ifndef WIN32PORTS_FNMATCH_H
|
||||
#define WIN32PORTS_FNMATCH_H
|
||||
|
||||
#define FNM_NOMATCH 1 /* Match failed. */
|
||||
|
||||
#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */
|
||||
#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */
|
||||
#define FNM_PERIOD 0x04 /* Period must be matched by period. */
|
||||
|
||||
#if __XSI_VISIBLE
|
||||
#define FNM_NOSYS (-1) /* Reserved. */
|
||||
#endif
|
||||
|
||||
#define FNM_LEADING_DIR 0x08 /* Ignore /<tail> after Imatch. */
|
||||
#define FNM_CASEFOLD 0x10 /* Case insensitive search. */
|
||||
#define FNM_IGNORECASE FNM_CASEFOLD
|
||||
#define FNM_FILE_NAME FNM_PATHNAME
|
||||
|
||||
int fnmatch(const char *, const char *, int);
|
||||
|
||||
#endif /* !WIN32PORTS_FNMATCH_H */
|
||||
|
|
@ -1,361 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1997 Gregory Pietsch
|
||||
|
||||
[These files] are hereby placed in the public domain without restrictions. Just
|
||||
give the author credit, don't claim you wrote it or prevent anyone else from
|
||||
using it.
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
getopt.c - Read command line options
|
||||
|
||||
AUTHOR: Gregory Pietsch
|
||||
CREATED Fri Jan 10 21:13:05 1997
|
||||
|
||||
DESCRIPTION:
|
||||
|
||||
The getopt() function parses the command line arguments. Its arguments argc
|
||||
and argv are the argument count and array as passed to the main() function
|
||||
on program invocation. The argument optstring is a list of available option
|
||||
characters. If such a character is followed by a colon (`:'), the option
|
||||
takes an argument, which is placed in optarg. If such a character is
|
||||
followed by two colons, the option takes an optional argument, which is
|
||||
placed in optarg. If the option does not take an argument, optarg is NULL.
|
||||
|
||||
The external variable optind is the index of the next array element of argv
|
||||
to be processed; it communicates from one call to the next which element to
|
||||
process.
|
||||
|
||||
The getopt_long() function works like getopt() except that it also accepts
|
||||
long options started by two dashes `--'. If these take values, it is either
|
||||
in the form
|
||||
|
||||
--arg=value
|
||||
|
||||
or
|
||||
|
||||
--arg value
|
||||
|
||||
It takes the additional arguments longopts which is a pointer to the first
|
||||
element of an array of type GETOPT_LONG_OPTION_T. The last element of the
|
||||
array has to be filled with NULL for the name field.
|
||||
|
||||
The longind pointer points to the index of the current long option relative
|
||||
to longopts if it is non-NULL.
|
||||
|
||||
The getopt() function returns the option character if the option was found
|
||||
successfully, `:' if there was a missing parameter for one of the options,
|
||||
`?' for an unknown option character, and EOF for the end of the option list.
|
||||
|
||||
The getopt_long() function's return value is described in the header file.
|
||||
|
||||
The function getopt_long_only() is identical to getopt_long(), except that a
|
||||
plus sign `+' can introduce long options as well as `--'.
|
||||
|
||||
The following describes how to deal with options that follow non-option
|
||||
argv-elements.
|
||||
|
||||
If the caller did not specify anything, the default is REQUIRE_ORDER if the
|
||||
environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise.
|
||||
|
||||
REQUIRE_ORDER means don't recognize them as options; stop option processing
|
||||
when the first non-option is seen. This is what Unix does. This mode of
|
||||
operation is selected by either setting the environment variable
|
||||
POSIXLY_CORRECT, or using `+' as the first character of the optstring
|
||||
parameter.
|
||||
|
||||
PERMUTE is the default. We permute the contents of ARGV as we scan, so that
|
||||
eventually all the non-options are at the end. This allows options to be
|
||||
given in any order, even with programs that were not written to expect this.
|
||||
|
||||
RETURN_IN_ORDER is an option available to programs that were written to
|
||||
expect options and other argv-elements in any order and that care about the
|
||||
ordering of the two. We describe each non-option argv-element as if it were
|
||||
the argument of an option with character code 1. Using `-' as the first
|
||||
character of the optstring parameter selects this mode of operation.
|
||||
|
||||
The special argument `--' forces an end of option-scanning regardless of the
|
||||
value of ordering. In the case of RETURN_IN_ORDER, only `--' can cause
|
||||
getopt() and friends to return EOF with optind != argc.
|
||||
|
||||
COPYRIGHT NOTICE AND DISCLAIMER:
|
||||
|
||||
Copyright (C) 1997 Gregory Pietsch
|
||||
|
||||
This file and the accompanying getopt.h header file are hereby placed in the
|
||||
public domain without restrictions. Just give the author credit, don't
|
||||
claim you wrote it or prevent anyone else from using it.
|
||||
|
||||
Gregory Pietsch's current e-mail address:
|
||||
gpietsch@comcast.net
|
||||
****************************************************************************/
|
||||
|
||||
/* include files */
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* macros */
|
||||
|
||||
/* types */
|
||||
typedef enum GETOPT_ORDERING_T
|
||||
{
|
||||
PERMUTE,
|
||||
RETURN_IN_ORDER,
|
||||
REQUIRE_ORDER
|
||||
} GETOPT_ORDERING_T;
|
||||
|
||||
/* globally-defined variables */
|
||||
char *optarg = NULL;
|
||||
int optind = 0;
|
||||
int opterr = 1;
|
||||
int optopt = '?';
|
||||
|
||||
/* functions */
|
||||
|
||||
/* reverse_argv_elements: reverses num elements starting at argv */
|
||||
static void reverse_argv_elements(char **argv, int num)
|
||||
{
|
||||
int i;
|
||||
char *tmp;
|
||||
|
||||
for (i = 0; i < (num >> 1); i++) {
|
||||
tmp = argv[i];
|
||||
argv[i] = argv[num - i - 1];
|
||||
argv[num - i - 1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* permute: swap two blocks of argv-elements given their lengths */
|
||||
static void permute(char **argv, int len1, int len2)
|
||||
{
|
||||
reverse_argv_elements(argv, len1);
|
||||
reverse_argv_elements(argv, len1 + len2);
|
||||
reverse_argv_elements(argv, len2);
|
||||
}
|
||||
|
||||
/* is_option: is this argv-element an option or the end of the option list? */
|
||||
static int is_option(char *argv_element, int only)
|
||||
{
|
||||
return ((argv_element == NULL) || (argv_element[0] == '-') || (only && argv_element[0] == '+'));
|
||||
}
|
||||
|
||||
/* getopt_internal: the function that does all the dirty work */
|
||||
static int getopt_internal(int argc, char **argv, char *shortopts, GETOPT_LONG_OPTION_T *longopts, int *longind, int only)
|
||||
{
|
||||
GETOPT_ORDERING_T ordering = PERMUTE;
|
||||
static size_t optwhere = 0;
|
||||
size_t permute_from = 0;
|
||||
int num_nonopts = 0;
|
||||
int optindex = 0;
|
||||
size_t match_chars = 0;
|
||||
char *possible_arg = NULL;
|
||||
int longopt_match = -1;
|
||||
int has_arg = -1;
|
||||
char *cp = NULL;
|
||||
int arg_next = 0;
|
||||
|
||||
/* first, deal with silly parameters and easy stuff */
|
||||
if (argc == 0 || argv == NULL || (shortopts == NULL && longopts == NULL))
|
||||
return (optopt = '?');
|
||||
if (optind >= argc || argv[optind] == NULL)
|
||||
return EOF;
|
||||
if (strcmp(argv[optind], "--") == 0) {
|
||||
optind++;
|
||||
return EOF;
|
||||
}
|
||||
/* if this is our first time through */
|
||||
if (optind == 0) {
|
||||
optind = 1;
|
||||
optwhere = 1;
|
||||
}
|
||||
|
||||
/* define ordering */
|
||||
if (shortopts != NULL && (*shortopts == '-' || *shortopts == '+')) {
|
||||
ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER;
|
||||
shortopts++;
|
||||
} else
|
||||
ordering = (getenv("POSIXLY_CORRECT") != NULL) ? REQUIRE_ORDER : PERMUTE;
|
||||
|
||||
/*
|
||||
* based on ordering, find our next option, if we're at the beginning of
|
||||
* one
|
||||
*/
|
||||
if (optwhere == 1) {
|
||||
switch (ordering) {
|
||||
case PERMUTE:
|
||||
permute_from = optind;
|
||||
num_nonopts = 0;
|
||||
while (!is_option(argv[optind], only)) {
|
||||
optind++;
|
||||
num_nonopts++;
|
||||
}
|
||||
if (argv[optind] == NULL) {
|
||||
/* no more options */
|
||||
optind = (int)permute_from;
|
||||
return EOF;
|
||||
} else if (strcmp(argv[optind], "--") == 0) {
|
||||
/* no more options, but have to get `--' out of the way */
|
||||
permute(argv + permute_from, num_nonopts, 1);
|
||||
optind = (int)(permute_from + 1);
|
||||
return EOF;
|
||||
}
|
||||
break;
|
||||
case RETURN_IN_ORDER:
|
||||
if (!is_option(argv[optind], only)) {
|
||||
optarg = argv[optind++];
|
||||
return (optopt = 1);
|
||||
}
|
||||
break;
|
||||
case REQUIRE_ORDER:
|
||||
if (!is_option(argv[optind], only))
|
||||
return EOF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* we've got an option, so parse it */
|
||||
|
||||
/* first, is it a long option? */
|
||||
if (longopts != NULL && (strncmp(argv[optind], "--", 2) == 0 || (only && argv[optind][0] == '+')) && optwhere == 1) {
|
||||
/* handle long options */
|
||||
if (strncmp(argv[optind], "--", 2) == 0)
|
||||
optwhere = 2;
|
||||
longopt_match = -1;
|
||||
possible_arg = strchr(argv[optind] + optwhere, '=');
|
||||
if (possible_arg == NULL) {
|
||||
/* no =, so next argv might be arg */
|
||||
match_chars = strlen(argv[optind]);
|
||||
possible_arg = argv[optind] + match_chars;
|
||||
match_chars = match_chars - optwhere;
|
||||
} else
|
||||
match_chars = (possible_arg - argv[optind]) - optwhere;
|
||||
for (optindex = 0; longopts[optindex].name != NULL; optindex++) {
|
||||
if (strncmp(argv[optind] + optwhere, longopts[optindex].name, match_chars) == 0) {
|
||||
/* do we have an exact match? */
|
||||
if (match_chars == strlen(longopts[optindex].name)) {
|
||||
longopt_match = optindex;
|
||||
break;
|
||||
}
|
||||
/* do any characters match? */
|
||||
else {
|
||||
if (longopt_match < 0)
|
||||
longopt_match = optindex;
|
||||
else {
|
||||
/* we have ambiguous options */
|
||||
if (opterr)
|
||||
fprintf(stderr,
|
||||
"%s: option `%s' is ambiguous "
|
||||
"(could be `--%s' or `--%s')\n",
|
||||
argv[0],
|
||||
argv[optind],
|
||||
longopts[longopt_match].name,
|
||||
longopts[optindex].name);
|
||||
return (optopt = '?');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (longopt_match >= 0)
|
||||
has_arg = longopts[longopt_match].has_arg;
|
||||
}
|
||||
/* if we didn't find a long option, is it a short option? */
|
||||
if (longopt_match < 0 && shortopts != NULL) {
|
||||
cp = strchr(shortopts, argv[optind][optwhere]);
|
||||
if (cp == NULL) {
|
||||
/* couldn't find option in shortopts */
|
||||
if (opterr)
|
||||
fprintf(stderr, "%s: invalid option -- `-%c'\n", argv[0], argv[optind][optwhere]);
|
||||
optwhere++;
|
||||
if (argv[optind][optwhere] == '\0') {
|
||||
optind++;
|
||||
optwhere = 1;
|
||||
}
|
||||
return (optopt = '?');
|
||||
}
|
||||
has_arg = ((cp[1] == ':') ? ((cp[2] == ':') ? optional_argument : required_argument) : no_argument);
|
||||
possible_arg = argv[optind] + optwhere + 1;
|
||||
optopt = *cp;
|
||||
}
|
||||
/* get argument and reset optwhere */
|
||||
arg_next = 0;
|
||||
switch (has_arg) {
|
||||
case optional_argument:
|
||||
if (*possible_arg == '=')
|
||||
possible_arg++;
|
||||
if (*possible_arg != '\0') {
|
||||
optarg = possible_arg;
|
||||
optwhere = 1;
|
||||
} else
|
||||
optarg = NULL;
|
||||
break;
|
||||
case required_argument:
|
||||
if (*possible_arg == '=')
|
||||
possible_arg++;
|
||||
if (*possible_arg != '\0') {
|
||||
optarg = possible_arg;
|
||||
optwhere = 1;
|
||||
} else if (optind + 1 >= argc) {
|
||||
if (opterr) {
|
||||
fprintf(stderr, "%s: argument required for option `", argv[0]);
|
||||
if (longopt_match >= 0)
|
||||
fprintf(stderr, "--%s'\n", longopts[longopt_match].name);
|
||||
else
|
||||
fprintf(stderr, "-%c'\n", *cp);
|
||||
}
|
||||
optind++;
|
||||
return (optopt = ':');
|
||||
} else {
|
||||
optarg = argv[optind + 1];
|
||||
arg_next = 1;
|
||||
optwhere = 1;
|
||||
}
|
||||
break;
|
||||
case no_argument:
|
||||
if (longopt_match < 0) {
|
||||
optwhere++;
|
||||
if (argv[optind][optwhere] == '\0')
|
||||
optwhere = 1;
|
||||
} else
|
||||
optwhere = 1;
|
||||
optarg = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* do we have to permute or otherwise modify optind? */
|
||||
if (ordering == PERMUTE && optwhere == 1 && num_nonopts != 0) {
|
||||
permute(argv + permute_from, num_nonopts, 1 + arg_next);
|
||||
optind = (int)(permute_from + 1 + arg_next);
|
||||
} else if (optwhere == 1)
|
||||
optind = optind + 1 + arg_next;
|
||||
|
||||
/* finally return */
|
||||
if (longopt_match >= 0) {
|
||||
if (longind != NULL)
|
||||
*longind = longopt_match;
|
||||
if (longopts[longopt_match].flag != NULL) {
|
||||
*(longopts[longopt_match].flag) = longopts[longopt_match].val;
|
||||
return 0;
|
||||
} else
|
||||
return longopts[longopt_match].val;
|
||||
} else
|
||||
return optopt;
|
||||
}
|
||||
|
||||
int getopt(int argc, char **argv, char *optstring)
|
||||
{
|
||||
return getopt_internal(argc, argv, optstring, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
int getopt_long(int argc, char **argv, const char *shortopts, const GETOPT_LONG_OPTION_T *longopts, int *longind)
|
||||
{
|
||||
return getopt_internal(argc, argv, (char *)shortopts, (GETOPT_LONG_OPTION_T *)longopts, longind, 0);
|
||||
}
|
||||
|
||||
int getopt_long_only(int argc, char **argv, const char *shortopts, const GETOPT_LONG_OPTION_T *longopts, int *longind)
|
||||
{
|
||||
return getopt_internal(argc, argv, (char *)shortopts, (GETOPT_LONG_OPTION_T *)longopts, longind, 1);
|
||||
}
|
||||
|
||||
/* end of file GETOPT.C */
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1997 Gregory Pietsch
|
||||
|
||||
[These files] are hereby placed in the public domain without restrictions. Just
|
||||
give the author credit, don't claim you wrote it or prevent anyone else from
|
||||
using it.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef WIN32PORTS_GETOPT_H
|
||||
#define WIN32PORTS_GETOPT_H
|
||||
#ifndef _WIN32
|
||||
|
||||
#pragma message("this getopt.h implementation is for Windows only!")
|
||||
|
||||
#elif defined __MINGW32__
|
||||
|
||||
#include <../include/getopt.h>
|
||||
|
||||
#else
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* include files needed by this include file */
|
||||
|
||||
/* macros defined by this include file */
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
|
||||
/* types defined by this include file */
|
||||
|
||||
/* GETOPT_LONG_OPTION_T: The type of long option */
|
||||
typedef struct GETOPT_LONG_OPTION_T
|
||||
{
|
||||
const char *name; /* the name of the long option */
|
||||
int has_arg; /* one of the above macros */
|
||||
int *flag; /* determines if getopt_long() returns a
|
||||
* value for a long option; if it is
|
||||
* non-NULL, 0 is returned as a function
|
||||
* value and the value of val is stored in
|
||||
* the area pointed to by flag. Otherwise,
|
||||
* val is returned. */
|
||||
int val; /* determines the value to return if flag is
|
||||
* NULL. */
|
||||
} GETOPT_LONG_OPTION_T;
|
||||
|
||||
typedef GETOPT_LONG_OPTION_T option;
|
||||
|
||||
/* externally-defined variables */
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
extern int opterr;
|
||||
extern int optopt;
|
||||
|
||||
/* function prototypes */
|
||||
int getopt(int argc, char **argv, char *optstring);
|
||||
int getopt_long(int argc, char **argv, const char *shortopts, const GETOPT_LONG_OPTION_T *longopts, int *longind);
|
||||
int getopt_long_only(int argc, char **argv, const char *shortopts, const GETOPT_LONG_OPTION_T *longopts, int *longind);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* WIN32PORTS_GETOPT_H */
|
||||
|
|
@ -1,263 +0,0 @@
|
|||
/* basename.c
|
||||
*
|
||||
* $Id: basename.c,v 1.2 2007/03/08 23:15:58 keithmarshall Exp $
|
||||
*
|
||||
* Provides an implementation of the "basename" function, conforming
|
||||
* to SUSv3, with extensions to accommodate Win32 drive designators,
|
||||
* and suitable for use on native Microsoft(R) Win32 platforms.
|
||||
*
|
||||
* Written by Keith Marshall <keithmarshall@users.sourceforge.net>
|
||||
*
|
||||
* This is free software. You may redistribute and/or modify it as you
|
||||
* see fit, without restriction of copyright.
|
||||
*
|
||||
* This software is provided "as is", in the hope that it may be useful,
|
||||
* but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
|
||||
* MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no
|
||||
* time will the author accept any form of liability for any damages,
|
||||
* however caused, resulting from the use of this software.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
char *basename(char *path)
|
||||
{
|
||||
static char *retfail = NULL;
|
||||
size_t len;
|
||||
/* to handle path names for files in multibyte character locales,
|
||||
* we need to set up LC_CTYPE to match the host file system locale
|
||||
*/
|
||||
char *locale = setlocale(LC_CTYPE, NULL);
|
||||
|
||||
if (locale != NULL)
|
||||
locale = strdup(locale);
|
||||
setlocale(LC_CTYPE, "");
|
||||
|
||||
if (path && *path) {
|
||||
/* allocate sufficient local storage space,
|
||||
* in which to create a wide character reference copy of path
|
||||
*/
|
||||
len = mbstowcs(NULL, path, 0);
|
||||
wchar_t *refcopy = malloc(sizeof(wchar_t) * (1 + len));
|
||||
/* create the wide character reference copy of path,
|
||||
* and step over the drive designator, if present ...
|
||||
*/
|
||||
wchar_t *refpath = refcopy;
|
||||
|
||||
if ((len = mbstowcs(refpath, path, len)) > 1 && refpath[1] == L':') {
|
||||
/* FIXME: maybe should confirm *refpath is a valid drive designator */
|
||||
refpath += 2;
|
||||
}
|
||||
/* ensure that our wide character reference path is NUL terminated */
|
||||
refcopy[len] = L'\0';
|
||||
/* check again, just to ensure we still have a non-empty path name ... */
|
||||
if (*refpath) {
|
||||
/* and, when we do, process it in the wide character domain ...
|
||||
* scanning from left to right, to the char after the final dir separator. */
|
||||
wchar_t *refname;
|
||||
|
||||
for (refname = refpath; *refpath; ++refpath) {
|
||||
if (*refpath == L'/' || *refpath == L'\\') {
|
||||
/* we found a dir separator ...
|
||||
* step over it, and any others which immediately follow it. */
|
||||
while (*refpath == L'/' || *refpath == L'\\')
|
||||
++refpath;
|
||||
/* if we didn't reach the end of the path string ... */
|
||||
if (*refpath)
|
||||
/* then we have a new candidate for the base name. */
|
||||
refname = refpath;
|
||||
/* otherwise ...
|
||||
* strip off any trailing dir separators which we found. */
|
||||
else
|
||||
while (refpath > refname && (*--refpath == L'/' || *refpath == L'\\'))
|
||||
*refpath = L'\0';
|
||||
}
|
||||
}
|
||||
/* in the wide character domain ...
|
||||
* refname now points at the resolved base name ... */
|
||||
if (*refname) {
|
||||
/* if it's not empty,
|
||||
* then we transform the full normalised path back into
|
||||
* the multibyte character domain, and skip over the dirname,
|
||||
* to return the resolved basename. */
|
||||
if ((len = wcstombs(path, refcopy, len)) != (size_t)(-1))
|
||||
path[len] = '\0';
|
||||
*refname = L'\0';
|
||||
if ((len = wcstombs(NULL, refcopy, 0)) != (size_t)(-1))
|
||||
path += len;
|
||||
} else {
|
||||
/* the basename is empty, so return the default value of "/",
|
||||
* transforming from wide char to multibyte char domain, and
|
||||
* returning it in our own buffer. */
|
||||
retfail = realloc(retfail, len = 1 + wcstombs(NULL, L"/", 0));
|
||||
wcstombs(path = retfail, L"/", len);
|
||||
}
|
||||
/* restore the caller's locale, clean up, and return the result */
|
||||
setlocale(LC_CTYPE, locale);
|
||||
free(locale);
|
||||
free(refcopy);
|
||||
return path;
|
||||
}
|
||||
/* or we had an empty residual path name, after the drive designator,
|
||||
* in which case we simply fall through ... */
|
||||
free(refcopy);
|
||||
}
|
||||
/* and, if we get to here ...
|
||||
* the path name is either NULL, or it decomposes to an empty string;
|
||||
* in either case, we return the default value of "." in our own buffer,
|
||||
* reloading it with the correct value, transformed from the wide char
|
||||
* to the multibyte char domain, just in case the caller trashed it
|
||||
* after a previous call.
|
||||
*/
|
||||
retfail = realloc(retfail, len = 1 + wcstombs(NULL, L".", 0));
|
||||
wcstombs(retfail, L".", len);
|
||||
|
||||
/* restore the caller's locale, clean up, and return the result. */
|
||||
setlocale(LC_CTYPE, locale);
|
||||
free(locale);
|
||||
return retfail;
|
||||
}
|
||||
|
||||
char *dirname(char *path)
|
||||
{
|
||||
static char *retfail = NULL;
|
||||
size_t len;
|
||||
/* to handle path names for files in multibyte character locales,
|
||||
* we need to set up LC_CTYPE to match the host file system locale. */
|
||||
char *locale = setlocale(LC_CTYPE, NULL);
|
||||
|
||||
if (locale != NULL)
|
||||
locale = strdup(locale);
|
||||
setlocale(LC_CTYPE, "");
|
||||
|
||||
if (path && *path) {
|
||||
/* allocate sufficient local storage space,
|
||||
* in which to create a wide character reference copy of path. */
|
||||
len = mbstowcs(NULL, path, 0);
|
||||
wchar_t *refcopy = malloc(sizeof(wchar_t) * (1 + len));
|
||||
/* create the wide character reference copy of path */
|
||||
wchar_t *refpath = refcopy;
|
||||
|
||||
len = mbstowcs(refpath, path, len);
|
||||
refcopy[len] = L'\0';
|
||||
/* SUSv3 identifies a special case, where path is exactly equal to "//";
|
||||
* (we will also accept "\\" in the Win32 context, but not "/\" or "\/",
|
||||
* and neither will we consider paths with an initial drive designator).
|
||||
* For this special case, SUSv3 allows the implementation to choose to
|
||||
* return "/" or "//", (or "\" or "\\", since this is Win32); we will
|
||||
* simply return the path unchanged, (i.e. "//" or "\\"). */
|
||||
if (len > 1 && (refpath[0] == L'/' || refpath[0] == L'\\')) {
|
||||
if (refpath[1] == refpath[0] && refpath[2] == L'\0') {
|
||||
setlocale(LC_CTYPE, locale);
|
||||
free(locale);
|
||||
free(refcopy);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
/* For all other cases ...
|
||||
* step over the drive designator, if present ... */
|
||||
else if (len > 1 && refpath[1] == L':') {
|
||||
/* FIXME: maybe should confirm *refpath is a valid drive designator. */
|
||||
refpath += 2;
|
||||
}
|
||||
/* check again, just to ensure we still have a non-empty path name ... */
|
||||
if (*refpath) {
|
||||
/* reproduce the scanning logic of the "basename" function
|
||||
* to locate the basename component of the current path string,
|
||||
* (but also remember where the dirname component starts). */
|
||||
wchar_t *refname, *the_basename;
|
||||
for (refname = the_basename = refpath; *refpath; ++refpath) {
|
||||
if (*refpath == L'/' || *refpath == L'\\') {
|
||||
/* we found a dir separator ...
|
||||
* step over it, and any others which immediately follow it. */
|
||||
while (*refpath == L'/' || *refpath == L'\\')
|
||||
++refpath;
|
||||
/* if we didn't reach the end of the path string ... */
|
||||
if (*refpath)
|
||||
/* then we have a new candidate for the base name. */
|
||||
the_basename = refpath;
|
||||
else
|
||||
/* we struck an early termination of the path string,
|
||||
* with trailing dir separators following the base name,
|
||||
* so break out of the for loop, to avoid overrun. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* now check,
|
||||
* to confirm that we have distinct dirname and basename components. */
|
||||
if (the_basename > refname) {
|
||||
/* and, when we do ...
|
||||
* backtrack over all trailing separators on the dirname component,
|
||||
* (but preserve exactly two initial dirname separators, if identical),
|
||||
* and add a NUL terminator in their place. */
|
||||
do
|
||||
--the_basename;
|
||||
while (the_basename > refname && (*the_basename == L'/' || *the_basename == L'\\'));
|
||||
if (the_basename == refname && (refname[0] == L'/' || refname[0] == L'\\') && refname[1] == refname[0]
|
||||
&& refname[2] != L'/' && refname[2] != L'\\')
|
||||
++the_basename;
|
||||
*++the_basename = L'\0';
|
||||
/* if the resultant dirname begins with EXACTLY two dir separators,
|
||||
* AND both are identical, then we preserve them. */
|
||||
refpath = refcopy;
|
||||
while ((*refpath == L'/' || *refpath == L'\\'))
|
||||
++refpath;
|
||||
if ((refpath - refcopy) > 2 || refcopy[1] != refcopy[0])
|
||||
refpath = refcopy;
|
||||
/* and finally ...
|
||||
* we remove any residual, redundantly duplicated separators from the dirname,
|
||||
* reterminate, and return it. */
|
||||
refname = refpath;
|
||||
while (*refpath) {
|
||||
if ((*refname++ = *refpath) == L'/' || *refpath++ == L'\\') {
|
||||
while (*refpath == L'/' || *refpath == L'\\')
|
||||
++refpath;
|
||||
}
|
||||
}
|
||||
*refname = L'\0';
|
||||
/* finally ...
|
||||
* transform the resolved dirname back into the multibyte char domain,
|
||||
* restore the caller's locale, and return the resultant dirname. */
|
||||
if ((len = wcstombs(path, refcopy, len)) != (size_t)(-1))
|
||||
path[len] = '\0';
|
||||
} else {
|
||||
/* either there were no dirname separators in the path name,
|
||||
* or there was nothing else ... */
|
||||
if (*refname == L'/' || *refname == L'\\') {
|
||||
/* it was all separators, so return one. */
|
||||
++refname;
|
||||
} else {
|
||||
/* there were no separators, so return '.'. */
|
||||
*refname++ = L'.';
|
||||
}
|
||||
/* add a NUL terminator, in either case,
|
||||
* then transform to the multibyte char domain,
|
||||
* using our own buffer. */
|
||||
*refname = L'\0';
|
||||
retfail = realloc(retfail, len = 1 + wcstombs(NULL, refcopy, 0));
|
||||
wcstombs(path = retfail, refcopy, len);
|
||||
}
|
||||
/* restore caller's locale, clean up, and return the resolved dirname. */
|
||||
setlocale(LC_CTYPE, locale);
|
||||
free(locale);
|
||||
free(refcopy);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
/* path is NULL, or an empty string; default return value is "." ...
|
||||
* return this in our own buffer, regenerated by wide char transform,
|
||||
* in case the caller trashed it after a previous call.
|
||||
*/
|
||||
retfail = realloc(retfail, len = 1 + wcstombs(NULL, L".", 0));
|
||||
wcstombs(retfail, L".", len);
|
||||
/* restore caller's locale, clean up, and return the default dirname. */
|
||||
setlocale(LC_CTYPE, locale);
|
||||
free(locale);
|
||||
return retfail;
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
#ifndef WIN32PORTS_LIBGEN_H
|
||||
#define WIN32PORTS_LIBGEN_H
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#pragma message("this libgen.h implementation is for Windows only!")
|
||||
|
||||
#elif defined __MINGW32__
|
||||
|
||||
#include <../include/libgen.h>
|
||||
|
||||
#else
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
char *basename(char *);
|
||||
char *dirname(char *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* WIN32PORTS_LIBGEN_H */
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
MIT License
|
||||
Copyright (c) 2019 win32ports
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include <strings.h>
|
||||
|
||||
extern inline void explicit_bzero(void *s, size_t n);
|
||||
extern inline int ffs(int i);
|
||||
extern inline int ffsl(long i);
|
||||
extern inline int ffsll(long long i);
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
MIT License
|
||||
Copyright (c) 2019 win32ports
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef WIN32PORTS_STRINGS_H
|
||||
#define WIN32PORTS_STRINGS_H
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#pragma message("this strings.h implementation is for Windows only!")
|
||||
|
||||
#elif defined __MINGW32__
|
||||
|
||||
#include <../include/strings.h>
|
||||
|
||||
#else
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#define bcmp(s1, s2, n) memcmp(s1, s2, n)
|
||||
#define bcopy(s, d, n) memcpy(d, s, n)
|
||||
#define bzero(s, n) memset(s, 0, n)
|
||||
|
||||
inline void explicit_bzero(void *s, size_t n)
|
||||
{
|
||||
volatile char *vs = (volatile char *)s;
|
||||
while (n) {
|
||||
*vs++ = 0;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
#define index(s, c) strchr(s, c)
|
||||
#define rindex(s, c) strrchr(s, c)
|
||||
|
||||
inline int ffs(int i)
|
||||
{
|
||||
int bit;
|
||||
|
||||
if (0 == i)
|
||||
return 0;
|
||||
|
||||
for (bit = 1; !(i & 1); ++bit)
|
||||
i >>= 1;
|
||||
return bit;
|
||||
}
|
||||
|
||||
inline int ffsl(long i)
|
||||
{
|
||||
int bit;
|
||||
|
||||
if (0 == i)
|
||||
return 0;
|
||||
|
||||
for (bit = 1; !(i & 1); ++bit)
|
||||
i >>= 1;
|
||||
return bit;
|
||||
}
|
||||
|
||||
inline int ffsll(long long i)
|
||||
{
|
||||
int bit;
|
||||
|
||||
if (0 == i)
|
||||
return 0;
|
||||
|
||||
for (bit = 1; !(i & 1); ++bit)
|
||||
i >>= 1;
|
||||
return bit;
|
||||
}
|
||||
|
||||
#define strcasecmp(s1, s2) _stricmp(s1, s2)
|
||||
#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
|
||||
#define strcasecmp_l(s1, s2, loc) _stricmp_l(s1, s2, loc)
|
||||
#define strncasecmp_l(s1, s2, n, loc) _strnicmp_l(s1, s2, n, loc)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* WIN32PORTS_STRINGS_H */
|
||||
|
|
@ -1,265 +0,0 @@
|
|||
/*
|
||||
MIT License
|
||||
Copyright (c) 2019 win32ports
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef WIN32PORTS_UNISTD_H
|
||||
#define WIN32PORTS_UNISTD_H
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#pragma message("this unistd.h implementation is for Windows only!")
|
||||
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef _INC_IO
|
||||
#include <io.h> /* _access() */
|
||||
#endif /* _INC_IO */
|
||||
|
||||
#ifndef _INC_DIRECT
|
||||
#include <direct.h> /* _chdir() */
|
||||
#endif /* _INC_DIRECT */
|
||||
|
||||
#ifndef _INC_PROCESS
|
||||
#include <process.h> /* _execl() */
|
||||
#endif /* _INC_PROCESS */
|
||||
|
||||
#include <sys/stat.h> /* */
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#ifndef R_OK
|
||||
#define R_OK 04
|
||||
#endif /* R_OK */
|
||||
|
||||
#ifndef W_OK
|
||||
#define W_OK 02
|
||||
#endif /* W_OK */
|
||||
|
||||
#ifndef X_OK
|
||||
#define X_OK R_OK
|
||||
#endif /* X_OK */
|
||||
|
||||
#ifndef F_OK
|
||||
#define F_OK 00
|
||||
#endif /* F_OK */
|
||||
|
||||
#ifndef STDIN_FILENO
|
||||
#define STDIN_FILENO 0
|
||||
#endif /* STDIN_FILENO */
|
||||
|
||||
#ifndef STDOUT_FILENO
|
||||
#define STDOUT_FILENO 1
|
||||
#endif /* STDOUT_FILENO */
|
||||
|
||||
#ifndef STDERR_FILENO
|
||||
#define STDERR_FILENO 2
|
||||
#endif /* STDERR_FILENO */
|
||||
|
||||
/* permission bits below must be defined in sys/stat.h, but MSVC lacks them */
|
||||
|
||||
#ifndef S_IRWXU
|
||||
#define S_IRWXU 0700
|
||||
#endif /* S_IRWXU */
|
||||
|
||||
#ifndef S_IRUSR
|
||||
#define S_IRUSR 0400
|
||||
#endif /* S_IRUSR */
|
||||
|
||||
#ifndef S_IWUSR
|
||||
#define S_IWUSR 0200
|
||||
#endif /* S_IWUSR */
|
||||
|
||||
#ifndef S_IXUSR
|
||||
#define S_IXUSR 0100
|
||||
#endif /* S_IXUSR */
|
||||
|
||||
#ifndef S_IRWXG
|
||||
#define S_IRWXG 070
|
||||
#endif /* S_IRWXG */
|
||||
|
||||
#ifndef S_IRGRP
|
||||
#define S_IRGRP 040
|
||||
#endif /* S_IRGRP */
|
||||
|
||||
#ifndef S_IWGRP
|
||||
#define S_IWGRP 020
|
||||
#endif /* S_IWGRP */
|
||||
|
||||
#ifndef S_IXGRP
|
||||
#define S_IXGRP 010
|
||||
#endif /* S_IXGRP */
|
||||
|
||||
#ifndef S_IRWXO
|
||||
#define S_IRWXO 07
|
||||
#endif /* S_IRWXO */
|
||||
|
||||
#ifndef S_IROTH
|
||||
#define S_IROTH 04
|
||||
#endif /* S_IROTH */
|
||||
|
||||
#ifndef S_IWOTH
|
||||
#define S_IWOTH 02
|
||||
#endif /* S_IWOTH */
|
||||
|
||||
#ifndef S_IXOTH
|
||||
#define S_IXOTH 01
|
||||
#endif /* S_IXOTH */
|
||||
|
||||
#ifndef S_ISUID
|
||||
#define S_ISUID 04000
|
||||
#endif /* S_ISUID */
|
||||
|
||||
#ifndef S_ISGID
|
||||
#define S_ISGID 02000
|
||||
#endif /* S_ISGID */
|
||||
|
||||
#ifndef S_ISVTX
|
||||
#define S_ISVTX 01000
|
||||
#endif /* S_ISVTX */
|
||||
|
||||
#ifndef S_IRWXUGO
|
||||
#define S_IRWXUGO 0777
|
||||
#endif /* S_IRWXUGO */
|
||||
|
||||
#ifndef S_IALLUGO
|
||||
#define S_IALLUGO 0777
|
||||
#endif /* S_IALLUGO */
|
||||
|
||||
#ifndef S_IRUGO
|
||||
#define S_IRUGO 0444
|
||||
#endif /* S_IRUGO */
|
||||
|
||||
#ifndef S_IWUGO
|
||||
#define S_IWUGO 0222
|
||||
#endif /* S_IWUGO */
|
||||
|
||||
#ifndef S_IXUGO
|
||||
#define S_IXUGO 0111
|
||||
#endif /* S_IXUGO */
|
||||
|
||||
#ifndef _S_IFMT
|
||||
#define _S_IFMT 0xF000
|
||||
#endif /* _S_IFMT */
|
||||
|
||||
#ifndef _S_IFIFO
|
||||
#define _S_IFIFO 0x1000
|
||||
#endif /* _S_IFIFO */
|
||||
|
||||
#ifndef _S_IFCHR
|
||||
#define _S_IFCHR 0x2000
|
||||
#endif /* _S_IFCHR */
|
||||
|
||||
#ifndef _S_IFDIR
|
||||
#define _S_IFDIR 0x4000
|
||||
#endif /* _S_IFDIR */
|
||||
|
||||
#ifndef _S_IFBLK
|
||||
#define _S_IFBLK 0x6000
|
||||
#endif /* _S_IFBLK */
|
||||
|
||||
#ifndef _S_IFREG
|
||||
#define _S_IFREG 0x8000
|
||||
#endif /* _S_IFREG */
|
||||
|
||||
#ifndef _S_IFLNK
|
||||
#define _S_IFLNK 0xA000
|
||||
#endif /* _S_IFLNK */
|
||||
|
||||
#ifndef _S_IFSOCK
|
||||
#define _S_IFSOCK 0xC000
|
||||
#endif /* _S_IFSOCK */
|
||||
|
||||
#ifndef S_IFMT
|
||||
#define S_IFMT _S_IFMT
|
||||
#endif /* S_IFMT */
|
||||
|
||||
#ifndef S_IFIFO
|
||||
#define S_IFIFO _S_IFIFO
|
||||
#endif /* S_IFIFO */
|
||||
|
||||
#ifndef S_IFCHR
|
||||
#define S_IFCHR _S_IFCHR
|
||||
#endif /* S_IFCHR */
|
||||
|
||||
#ifndef S_IFDIR
|
||||
#define S_IFDIR _S_IFDIR
|
||||
#endif /* S_IFDIR */
|
||||
|
||||
#ifndef S_IFBLK
|
||||
#define S_IFBLK _S_IFBLK
|
||||
#endif /* S_IFBLK */
|
||||
|
||||
#ifndef S_IFREG
|
||||
#define S_IFREG _S_IFREG
|
||||
#endif /* S_IFREG */
|
||||
|
||||
#ifndef S_IFLNK
|
||||
#define S_IFLNK _S_IFLNK
|
||||
#endif /* S_IFLNK */
|
||||
|
||||
#ifndef S_IFSOCK
|
||||
#define S_IFSOCK _S_IFSOCK
|
||||
#endif /* S_IFSOCK */
|
||||
|
||||
#ifndef S_ISTYPE
|
||||
#define S_ISTYPE(mode, mask) (((mode)&S_IFMT) == (mask))
|
||||
#endif /* S_ISTYPE */
|
||||
|
||||
#ifndef S_ISFIFO
|
||||
#define S_ISFIFO(mode) S_ISTYPE(mode, S_IFIFO)
|
||||
#endif /* S_ISFIFO */
|
||||
|
||||
#ifndef S_ISCHR
|
||||
#define S_ISCHR(mode) S_ISTYPE(mode, S_IFCHR)
|
||||
#endif /* S_ISCHR */
|
||||
|
||||
#ifndef S_ISDIR
|
||||
#define S_ISDIR(mode) S_ISTYPE(mode, S_IFDIR)
|
||||
#endif /* S_ISDIR */
|
||||
|
||||
#ifndef S_ISBLK
|
||||
#define S_ISBLK(mode) S_ISTYPE(mode, S_IFBLK)
|
||||
#endif /* S_ISBLK */
|
||||
|
||||
#ifndef S_ISREG
|
||||
#define S_ISREG(mode) S_ISTYPE(mode, S_IFREG)
|
||||
#endif /* S_ISREG */
|
||||
|
||||
#ifndef S_ISLNK
|
||||
#define S_ISLNK(mode) S_ISTYPE(mode, S_IFLNK)
|
||||
#endif /* S_ISLNK */
|
||||
|
||||
#ifndef S_ISSOCK
|
||||
#define S_ISSOCK(mode) S_ISTYPE(mode, S_IFSOCK)
|
||||
#endif /* S_ISSOCK */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* WIN32PORTS_UNISTD_H */
|
||||
|
|
@ -10,7 +10,7 @@ target_include_directories(brender
|
|||
include
|
||||
)
|
||||
|
||||
target_link_libraries(brender PRIVATE harness miniposix)
|
||||
target_link_libraries(brender PRIVATE harness)
|
||||
|
||||
if(NOT MSVC)
|
||||
target_compile_options(brender PRIVATE
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "harness/trace.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
// IDA: void __cdecl BrNewList(br_list *list)
|
||||
void BrNewList(br_list* list) {
|
||||
|
|
|
|||
|
|
@ -11,38 +11,38 @@
|
|||
|
||||
br_file_primitives _BrFilePrimsNull = {
|
||||
"NULL",
|
||||
(int(*)(br_datafile*,br_uint_32))&BrNullOther,
|
||||
(int(*)(br_datafile*, br_uint_32, br_uint_32))&BrNullOther,
|
||||
(int(*)(br_datafile*, br_uint_32*))&BrNullOther,
|
||||
(void(*)(br_datafile*, br_uint_32))&BrNullOther,
|
||||
(br_uint_32(*)(br_datafile*))&BrNullOther,
|
||||
(int(*)(br_datafile*))&BrNullOther,
|
||||
(br_uint_32(*)(br_datafile*, br_file_struct*, void*))&BrNullOther,
|
||||
(br_uint_32(*)(br_datafile*, br_file_struct*, void*))&BrNullOther,
|
||||
(int(*)(br_datafile*, br_file_struct*, void*))&BrNullOther,
|
||||
(int(*)(br_datafile*, void*, int, int, int, int))&BrNullOther,
|
||||
(void*(*)(br_datafile*, void*, int*, int, int))&BrNullOther,
|
||||
(int(*)(br_datafile*, void*, int, int, int, int))&BrNullOther,
|
||||
(int(*)(br_datafile*, char*))&BrNullOther,
|
||||
(char*(*)(br_datafile*, char*))&BrNullOther,
|
||||
(int(*)(br_datafile*, char*))&BrNullOther,
|
||||
(int (*)(br_datafile*, br_uint_32)) & BrNullOther,
|
||||
(int (*)(br_datafile*, br_uint_32, br_uint_32)) & BrNullOther,
|
||||
(int (*)(br_datafile*, br_uint_32*)) & BrNullOther,
|
||||
(void (*)(br_datafile*, br_uint_32)) & BrNullOther,
|
||||
(br_uint_32(*)(br_datafile*)) & BrNullOther,
|
||||
(int (*)(br_datafile*)) & BrNullOther,
|
||||
(br_uint_32(*)(br_datafile*, br_file_struct*, void*)) & BrNullOther,
|
||||
(br_uint_32(*)(br_datafile*, br_file_struct*, void*)) & BrNullOther,
|
||||
(int (*)(br_datafile*, br_file_struct*, void*)) & BrNullOther,
|
||||
(int (*)(br_datafile*, void*, int, int, int, int)) & BrNullOther,
|
||||
(void* (*)(br_datafile*, void*, int*, int, int)) & BrNullOther,
|
||||
(int (*)(br_datafile*, void*, int, int, int, int)) & BrNullOther,
|
||||
(int (*)(br_datafile*, char*)) & BrNullOther,
|
||||
(char* (*)(br_datafile*, char*)) & BrNullOther,
|
||||
(int (*)(br_datafile*, char*)) & BrNullOther,
|
||||
};
|
||||
|
||||
br_file_primitives _BrFilePrimsReadBinary = {
|
||||
"Read Binary",
|
||||
&DfSkipBinary,
|
||||
(int(*)(br_datafile*, br_uint_32, br_uint_32))&BrNullOther,
|
||||
(int (*)(br_datafile*, br_uint_32, br_uint_32)) & BrNullOther,
|
||||
&DfChunkReadBinary,
|
||||
(void(*)(br_datafile*, br_uint_32))&BrNullOther,
|
||||
(void (*)(br_datafile*, br_uint_32)) & BrNullOther,
|
||||
&DfCountReadBinary,
|
||||
&DfCountSizeBinary,
|
||||
(br_uint_32(*)(br_datafile*, br_file_struct*, void*))&BrNullOther,
|
||||
(br_uint_32(*)(br_datafile*, br_file_struct*, void*)) & BrNullOther,
|
||||
&DfStructReadBinary,
|
||||
&DfStructSizeBinary,
|
||||
(int(*)(br_datafile*, void*, int, int, int, int))&BrNullOther,
|
||||
(int (*)(br_datafile*, void*, int, int, int, int)) & BrNullOther,
|
||||
&DfBlockReadBinary,
|
||||
&DfBlockSizeBinary,
|
||||
(int(*)(br_datafile*, char*))&BrNullOther,
|
||||
(int (*)(br_datafile*, char*)) & BrNullOther,
|
||||
&DfNameReadBinary,
|
||||
&DfNameSizeBinary,
|
||||
};
|
||||
|
|
@ -51,36 +51,36 @@ br_file_primitives _BrFilePrimsWriteBinary = {
|
|||
"Write Binary",
|
||||
&DfSkipBinary,
|
||||
&DfChunkWriteBinary,
|
||||
(int(*)(br_datafile*, br_uint_32*))&BrNullOther,
|
||||
(int (*)(br_datafile*, br_uint_32*)) & BrNullOther,
|
||||
&DfCountWriteBinary,
|
||||
(br_uint_32(*)(br_datafile*))&BrNullOther,
|
||||
(br_uint_32(*)(br_datafile*)) & BrNullOther,
|
||||
&DfCountSizeBinary,
|
||||
&DfStructWriteBinary,
|
||||
(br_uint_32(*)(br_datafile*, br_file_struct*, void*))&BrNullOther,
|
||||
(br_uint_32(*)(br_datafile*, br_file_struct*, void*)) & BrNullOther,
|
||||
&DfStructSizeBinary,
|
||||
&DfBlockWriteBinary,
|
||||
(void*(*)(br_datafile*, void*, int*, int, int))&BrNullOther,
|
||||
(void* (*)(br_datafile*, void*, int*, int, int)) & BrNullOther,
|
||||
&DfBlockSizeBinary,
|
||||
&DfNameWriteBinary,
|
||||
(char*(*)(br_datafile*, char*))&BrNullOther,
|
||||
(char* (*)(br_datafile*, char*)) & BrNullOther,
|
||||
&DfNameSizeBinary,
|
||||
};
|
||||
|
||||
br_file_primitives _BrFilePrimsReadText = {
|
||||
"Read Text",
|
||||
&DfSkipText,
|
||||
(int(*)(br_datafile*, br_uint_32, br_uint_32))&BrNullOther,
|
||||
(int (*)(br_datafile*, br_uint_32, br_uint_32)) & BrNullOther,
|
||||
&DfChunkReadText,
|
||||
(void(*)(br_datafile*, br_uint_32))&BrNullOther,
|
||||
(void (*)(br_datafile*, br_uint_32)) & BrNullOther,
|
||||
&DfCountReadText,
|
||||
&DfCountSizeText,
|
||||
(br_uint_32(*)(br_datafile*, br_file_struct*, void*))&BrNullOther,
|
||||
(br_uint_32(*)(br_datafile*, br_file_struct*, void*)) & BrNullOther,
|
||||
&DfStructReadText,
|
||||
&DfStructSizeText,
|
||||
(int(*)(br_datafile*, void*, int, int, int, int))&BrNullOther,
|
||||
(int (*)(br_datafile*, void*, int, int, int, int)) & BrNullOther,
|
||||
&DfBlockReadText,
|
||||
&DfBlockSizeText,
|
||||
(int(*)(br_datafile*, char*))&BrNullOther,
|
||||
(int (*)(br_datafile*, char*)) & BrNullOther,
|
||||
&DfNameReadText,
|
||||
&DfNameSizeText,
|
||||
};
|
||||
|
|
@ -89,18 +89,18 @@ br_file_primitives _BrFilePrimsWriteText = {
|
|||
"Write Text",
|
||||
&DfSkipText,
|
||||
&DfChunkWriteText,
|
||||
(int(*)(br_datafile*, br_uint_32*))&BrNullOther,
|
||||
(int (*)(br_datafile*, br_uint_32*)) & BrNullOther,
|
||||
&DfCountWriteText,
|
||||
(br_uint_32(*)(br_datafile*))&BrNullOther,
|
||||
(br_uint_32(*)(br_datafile*)) & BrNullOther,
|
||||
&DfCountSizeText,
|
||||
&DfStructWriteText,
|
||||
(br_uint_32(*)(br_datafile*, br_file_struct*, void*))&BrNullOther,
|
||||
(br_uint_32(*)(br_datafile*, br_file_struct*, void*)) & BrNullOther,
|
||||
&DfStructSizeText,
|
||||
&DfBlockWriteText,
|
||||
(void*(*)(br_datafile*, void*, int*, int, int))&BrNullOther,
|
||||
(void* (*)(br_datafile*, void*, int*, int, int)) & BrNullOther,
|
||||
&DfBlockSizeText,
|
||||
&DfNameWriteText,
|
||||
(char*(*)(br_datafile*, char*))&BrNullOther,
|
||||
(char* (*)(br_datafile*, char*)) & BrNullOther,
|
||||
&DfNameSizeText,
|
||||
};
|
||||
|
||||
|
|
@ -289,7 +289,8 @@ int TextReadLine(br_datafile* df, char** ident, char** data) {
|
|||
}
|
||||
for (; (*cp == ' ') || (*cp == '\t'); cp++) {
|
||||
}
|
||||
if (*cp != '\0') break;
|
||||
if (*cp != '\0')
|
||||
break;
|
||||
}
|
||||
*ident = cp;
|
||||
while ((*cp != ' ') && (*cp != '\t') && (*cp != '\0')) {
|
||||
|
|
@ -320,7 +321,7 @@ br_uint_16 scalarTypeConvert(br_datafile* df, br_uint_16 t) {
|
|||
LOG_TRACE9("(%p, %d)", df, t);
|
||||
|
||||
if (df->scalar_type == BRT_FIXED) {
|
||||
switch(t) {
|
||||
switch (t) {
|
||||
case DF_TYPE_BR_SCALAR:
|
||||
return DF_TYPE_BR_FIXED;
|
||||
case DF_TYPE_BR_FRACTION:
|
||||
|
|
@ -418,8 +419,8 @@ br_uint_32 DfStructWriteBinary(br_datafile* df, br_file_struct* str, void* base)
|
|||
DfStructWriteBinary(df, sm->extra, mp);
|
||||
break;
|
||||
case DF_TYPE_ASCIZ:
|
||||
if (*(char **)mp != NULL) {
|
||||
BrFileWrite(*(char **)mp, 1, BrStrLen(*(char**)mp), df->h);
|
||||
if (*(char**)mp != NULL) {
|
||||
BrFileWrite(*(char**)mp, 1, BrStrLen(*(char**)mp), df->h);
|
||||
}
|
||||
BrFilePutChar('\0', df->h);
|
||||
break;
|
||||
|
|
@ -822,14 +823,14 @@ br_uint_32 StructWriteTextSub(br_datafile* df, br_file_struct* str, void* base,
|
|||
StructWriteTextSub(df, sm->extra, mp, indent + 2);
|
||||
break;
|
||||
case DF_TYPE_ASCIZ:
|
||||
if (*(char **)mp == NULL) {
|
||||
if (*(char**)mp == NULL) {
|
||||
w = BrFilePrintf(df->h, "NULL");
|
||||
} else {
|
||||
w = BrFilePrintf(df->h, "\"%s\"", *(char **)mp);
|
||||
w = BrFilePrintf(df->h, "\"%s\"", *(char**)mp);
|
||||
}
|
||||
break;
|
||||
case DF_TYPE_BR_COLOUR:
|
||||
w = BrFilePrintf(df->h, "%d,%d,%d", (br_uint_8)((*(br_uint_32 *)mp) >> 16), (br_uint_8)((*(br_uint_32 *)mp) >> 8), (br_uint_8)((*(br_uint_32 *)mp)));
|
||||
w = BrFilePrintf(df->h, "%d,%d,%d", (br_uint_8)((*(br_uint_32*)mp) >> 16), (br_uint_8)((*(br_uint_32*)mp) >> 8), (br_uint_8)((*(br_uint_32*)mp)));
|
||||
break;
|
||||
case DF_TYPE_BR_FRACTION_X:
|
||||
w = BrFilePrintf(df->h, "%g", (double)BrFixedFractionToFloat(*(br_fraction_x*)mp));
|
||||
|
|
@ -1499,7 +1500,7 @@ int DfChunksInterpret(br_datafile* df, br_chunks_table* table) {
|
|||
|
||||
while (1) {
|
||||
id = df->prims->chunk_read(df, &length);
|
||||
//LOG_DEBUG("chunk id=%d, len=%d", id, length);
|
||||
// LOG_DEBUG("chunk id=%d, len=%d", id, length);
|
||||
if (id == (br_uint_32)-1) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -1563,7 +1564,6 @@ br_datafile* DfOpen(char* name, int write, br_token scalar_type) {
|
|||
h = BrFileOpenRead(name, 8u, DfFileIdentify, &mode);
|
||||
}
|
||||
if (h == NULL) {
|
||||
LOG_WARN("returning NULL");
|
||||
return NULL;
|
||||
}
|
||||
df = BrResAllocate(fw.res, sizeof(br_datafile), BR_MEMORY_DATAFILE);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ target_include_directories(dethrace_obj
|
|||
pd
|
||||
)
|
||||
|
||||
target_link_libraries(dethrace_obj PUBLIC miniposix SDL2::SDL2 smacker harness brender s3 cglm)
|
||||
target_link_libraries(dethrace_obj PUBLIC SDL2::SDL2 smacker harness brender s3 cglm)
|
||||
|
||||
if (CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
target_compile_options(dethrace_obj PRIVATE
|
||||
|
|
@ -154,8 +154,6 @@ target_sources(dethrace_obj PRIVATE
|
|||
pd/net.h
|
||||
pc-dos/dossys.c
|
||||
pd/sys.h
|
||||
watcom_functions.c
|
||||
watcom_functions.h
|
||||
)
|
||||
|
||||
# Create our main game binary.
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "globvrpb.h"
|
||||
#include "graphics.h"
|
||||
#include "harness/config.h"
|
||||
#include "harness/os.h"
|
||||
#include "harness/trace.h"
|
||||
#include "input.h"
|
||||
#include "loading.h"
|
||||
|
|
@ -13,7 +14,6 @@
|
|||
#include "utility.h"
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
tS32 gLast_demo_end_anim;
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ void PlaySmackerFile(char* pSmack_name) {
|
|||
tPath_name the_path;
|
||||
br_colour* br_colours_ptr;
|
||||
tU8* smack_colours_ptr;
|
||||
//Smack* smk;
|
||||
// Smack* smk;
|
||||
int i;
|
||||
int j;
|
||||
int len;
|
||||
|
|
@ -83,10 +83,7 @@ void PlaySmackerFile(char* pSmack_name) {
|
|||
smk_info_video(s, &w, &h, NULL);
|
||||
double fps = 1000000.0 / usf;
|
||||
int delay_ms = (1 / fps) * 1000;
|
||||
#ifndef _WIN32
|
||||
ts.tv_sec = delay_ms / 1000;
|
||||
ts.tv_nsec = (delay_ms % 1000) * 1000000;
|
||||
#endif
|
||||
|
||||
smk_enable_video(s, 1);
|
||||
|
||||
smk_first(s);
|
||||
|
|
@ -112,13 +109,8 @@ void PlaySmackerFile(char* pSmack_name) {
|
|||
if (AnyKeyDown() || EitherMouseButtonDown()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// wait until its time for the next frame
|
||||
#ifndef _WIN32
|
||||
nanosleep(&ts, &ts);
|
||||
#else
|
||||
Sleep(delay_ms);
|
||||
#endif
|
||||
OS_Sleep(delay_ms);
|
||||
} while (smk_next(s) == SMK_MORE);
|
||||
|
||||
smk_close(s);
|
||||
|
|
@ -138,7 +130,7 @@ void DoOpeningAnimation() {
|
|||
LOG_TRACE("()");
|
||||
PlaySmackerFile("LOGO.SMK");
|
||||
PlaySmackerFile(harness_game_info.defines.INTRO_SMK_FILE);
|
||||
return WaitForNoKeys();
|
||||
WaitForNoKeys();
|
||||
}
|
||||
|
||||
// IDA: void __cdecl DoNewGameAnimation()
|
||||
|
|
|
|||
|
|
@ -282,8 +282,6 @@ void MAMSInitMem() {
|
|||
FILE* f;
|
||||
tPath_name the_path;
|
||||
LOG_TRACE("()");
|
||||
|
||||
LOG_WARN("nop in Windows (doing something for DOS?)");
|
||||
}
|
||||
|
||||
// IDA: void __usercall PrintMemoryDump(int pFlags@<EAX>, char *pTitle@<EDX>)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "globvars.h"
|
||||
#include "graphics.h"
|
||||
#include "harness/trace.h"
|
||||
#include "network.h"
|
||||
|
|
@ -148,27 +149,26 @@ void FatalError(int pStr_index, ...) {
|
|||
|
||||
va_start(ap, pStr_index);
|
||||
|
||||
int read_timer = PDGetTotalTime();
|
||||
gError_code = 0x20000000 + read_timer;
|
||||
strcpy(the_str, gError_messages[pStr_index - 1]);
|
||||
gError_code = 0x20000000 + PDGetTotalTime();
|
||||
strcpy(the_str, gError_messages[pStr_index]);
|
||||
sub_pt = temp_str;
|
||||
|
||||
for (i = 0; i < strlen(the_str); i++) {
|
||||
if (the_str[i] == '%') {
|
||||
sub_str = va_arg(ap, char*);
|
||||
StripCR(sub_str);
|
||||
strcpy(sub_pt, sub_str);
|
||||
sub_pt += strlen(sub_str);
|
||||
} else {
|
||||
*sub_pt = the_str[i];
|
||||
sub_pt++;
|
||||
while (1) {
|
||||
|
||||
sub_pt = strchr(the_str, '%');
|
||||
if (!sub_pt) {
|
||||
break;
|
||||
}
|
||||
sub_str = va_arg(ap, char*);
|
||||
StripCR(sub_str);
|
||||
strcpy(temp_str, sub_pt + 1);
|
||||
strcpy(sub_pt, sub_str);
|
||||
strcat(the_str, temp_str);
|
||||
}
|
||||
*sub_pt = 0;
|
||||
va_end(ap);
|
||||
dr_dprintf(the_str);
|
||||
FadePaletteUp();
|
||||
PDFatalError(temp_str);
|
||||
PDFatalError(the_str);
|
||||
}
|
||||
|
||||
// IDA: void __cdecl NonFatalError(int pStr_index, ...)
|
||||
|
|
@ -205,22 +205,40 @@ void NonFatalError(int pStr_index, ...) {
|
|||
// IDA: void __cdecl CloseDiagnostics()
|
||||
void CloseDiagnostics() {
|
||||
LOG_TRACE("()");
|
||||
|
||||
fclose(gDiagnostic_file);
|
||||
}
|
||||
|
||||
// IDA: void __cdecl OpenDiagnostics()
|
||||
void OpenDiagnostics() {
|
||||
LOG_TRACE("()");
|
||||
|
||||
gDiagnostic_file = fopen("DIAGNOST.TXT", "w");
|
||||
|
||||
fputs("DIAGNOSTIC OUTPUT\n", gDiagnostic_file);
|
||||
// todo: generate a real date
|
||||
fprintf(gDiagnostic_file, "Date / time : %s\n\n\n", "Mon Mar 24 16 : 32 : 33 1997");
|
||||
}
|
||||
|
||||
// Renamed from dprintf to avoid collisions to stdio
|
||||
// This function is stripped from the retail binary, we've guessed at the implementation
|
||||
void dr_dprintf(char* fmt_string, ...) {
|
||||
static tU32 first_time = 0;
|
||||
va_list args;
|
||||
tU32 the_time;
|
||||
|
||||
if (first_time == 0) {
|
||||
first_time = GetTotalTime();
|
||||
}
|
||||
the_time = GetTotalTime() - first_time;
|
||||
|
||||
fprintf(gDiagnostic_file, "%7d.%02d: ", the_time / 1000, the_time % 100);
|
||||
|
||||
printf("dprintf: ");
|
||||
va_start(args, fmt_string);
|
||||
vprintf(fmt_string, args);
|
||||
vfprintf(gDiagnostic_file, fmt_string, args);
|
||||
va_end(args);
|
||||
printf("\n");
|
||||
|
||||
fputs("\n", gDiagnostic_file);
|
||||
}
|
||||
|
||||
// IDA: int __usercall DoErrorInterface@<EAX>(int pMisc_text_index@<EAX>)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
#include "sound.h"
|
||||
#include "utility.h"
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int gPalette_allocate_count;
|
||||
int gPalette_fuck_prevention;
|
||||
|
|
@ -694,7 +693,7 @@ int StartFlic(char* pFile_name, int pIndex, tFlic_descriptor_ptr pFlic_info, tU3
|
|||
} else {
|
||||
pFlic_info->f = NULL;
|
||||
pFlic_info->data = (char*)pData_ptr;
|
||||
//TOOD: remove this - we added this line because of the padding hack in PlayNextFlicFrame2
|
||||
// TOOD: remove this - we added this line because of the padding hack in PlayNextFlicFrame2
|
||||
pFlic_info->data_start = (char*)pData_ptr;
|
||||
}
|
||||
pFlic_info->bytes_remaining = MemReadU32(&pFlic_info->data);
|
||||
|
|
@ -746,7 +745,7 @@ int StartFlic(char* pFile_name, int pIndex, tFlic_descriptor_ptr pFlic_info, tU3
|
|||
if (pDest_pixelmap) {
|
||||
pFlic_info->first_pixel = (tU8*)pDest_pixelmap->pixels + pDest_pixelmap->row_bytes * pFlic_info->y_offset + pFlic_info->x_offset;
|
||||
}
|
||||
//LOG_DEBUG("first pixel %p %p", pFlic_info->first_pixel, pDest_pixelmap->pixels);
|
||||
// LOG_DEBUG("first pixel %p %p", pFlic_info->first_pixel, pDest_pixelmap->pixels);
|
||||
pFlic_info->the_pixelmap = pDest_pixelmap;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -809,7 +808,7 @@ void DoColourMap(tFlic_descriptor_ptr pFlic_info, tU32 chunk_length) {
|
|||
red = MemReadU8(&pFlic_info->data);
|
||||
blue = MemReadU8(&pFlic_info->data);
|
||||
green = MemReadU8(&pFlic_info->data);
|
||||
//argb
|
||||
// argb
|
||||
palette_pixels[0] = green * 4;
|
||||
palette_pixels[1] = blue * 4;
|
||||
palette_pixels[2] = red * 4;
|
||||
|
|
@ -887,13 +886,13 @@ void DoColour256(tFlic_descriptor* pFlic_info, tU32 chunk_length) {
|
|||
red = MemReadU8(&pFlic_info->data);
|
||||
blue = MemReadU8(&pFlic_info->data);
|
||||
green = MemReadU8(&pFlic_info->data);
|
||||
//argb
|
||||
// argb
|
||||
palette_pixels[0] = green;
|
||||
palette_pixels[1] = blue;
|
||||
palette_pixels[2] = red;
|
||||
palette_pixels[3] = 0;
|
||||
palette_pixels += 4;
|
||||
//LOG_DEBUG("color %d", current_colour);
|
||||
// LOG_DEBUG("color %d", current_colour);
|
||||
}
|
||||
if (!gPalette_fuck_prevention) {
|
||||
DRSetPaletteEntries(gPalette, current_colour, change_count);
|
||||
|
|
@ -1172,7 +1171,7 @@ int PlayNextFlicFrame2(tFlic_descriptor* pFlic_info, int pPanel_flic) {
|
|||
int data_knocked_off;
|
||||
int read_amount;
|
||||
|
||||
//LOG_DEBUG("%d (%p), frames left: %d offset: %d", pFlic_info->the_index, pFlic_info, pFlic_info->frames_left, (pFlic_info->data - pFlic_info->data_start) + 4);
|
||||
// LOG_DEBUG("%d (%p), frames left: %d offset: %d", pFlic_info->the_index, pFlic_info, pFlic_info->frames_left, (pFlic_info->data - pFlic_info->data_start) + 4);
|
||||
PossibleService();
|
||||
frame_length = MemReadU32(&pFlic_info->data);
|
||||
magic_bytes = MemReadU16(&pFlic_info->data);
|
||||
|
|
@ -1229,7 +1228,7 @@ int PlayNextFlicFrame2(tFlic_descriptor* pFlic_info, int pPanel_flic) {
|
|||
MemSkipBytes(&pFlic_info->data, chunk_length - 6);
|
||||
break;
|
||||
}
|
||||
//TODO: something like // p &= 0xfffffffffffffffe;
|
||||
// TODO: something like // p &= 0xfffffffffffffffe;
|
||||
int a = (pFlic_info->data - pFlic_info->data_start);
|
||||
if (a % 2 == 1) {
|
||||
pFlic_info->data++;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
#include "utility.h"
|
||||
#include "world.h"
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
|
@ -2389,7 +2388,7 @@ void DropInImageFromTop(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip,
|
|||
tS32 the_time;
|
||||
int drop_distance;
|
||||
LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
|
||||
|
||||
|
||||
start_time = PDGetTotalTime();
|
||||
drop_distance = pImage->height - pTop_clip + pTop;
|
||||
while (1) {
|
||||
|
|
@ -2413,7 +2412,7 @@ void DropOutImageThruBottom(br_pixelmap* pImage, int pLeft, int pTop, int pTop_c
|
|||
tS32 the_time;
|
||||
int drop_distance;
|
||||
LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
|
||||
|
||||
|
||||
start_time = PDGetTotalTime();
|
||||
drop_distance = pBottom_clip - pTop;
|
||||
while (1) {
|
||||
|
|
@ -2437,7 +2436,7 @@ void DropInImageFromBottom(br_pixelmap* pImage, int pLeft, int pTop, int pTop_cl
|
|||
tS32 the_time;
|
||||
int drop_distance;
|
||||
LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
|
||||
|
||||
|
||||
start_time = PDGetTotalTime();
|
||||
drop_distance = pBottom_clip - pTop;
|
||||
while (1) {
|
||||
|
|
@ -2461,7 +2460,7 @@ void DropOutImageThruTop(br_pixelmap* pImage, int pLeft, int pTop, int pTop_clip
|
|||
tS32 the_time;
|
||||
int drop_distance;
|
||||
LOG_TRACE("(%p, %d, %d, %d, %d)", pImage, pLeft, pTop, pTop_clip, pBottom_clip);
|
||||
|
||||
|
||||
start_time = PDGetTotalTime();
|
||||
drop_distance = pImage->height - pTop_clip + pTop;
|
||||
while (1) {
|
||||
|
|
|
|||
|
|
@ -3195,9 +3195,6 @@ FILE* DRfopen(char* pFilename, char* pMode) {
|
|||
PDFatalError(msg);
|
||||
}
|
||||
}
|
||||
if (result == NULL) {
|
||||
LOG_WARN("failed for %d", errno);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -638,8 +638,6 @@ tRace_result MainGameLoop() {
|
|||
gAbandon_game = 0;
|
||||
}
|
||||
|
||||
Harness_Hook_MainGameLoop();
|
||||
|
||||
} while (gProgram_state.prog_status == eProg_game_ongoing
|
||||
&& !MungeRaceFinished()
|
||||
&& !gAbandon_game
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Added >>
|
||||
#define MIN_SERVICE_INTERVAL 200
|
||||
|
|
@ -1312,7 +1311,7 @@ void EncodeFile(char* pThe_path) {
|
|||
fclose(d);
|
||||
|
||||
PDFileUnlock(pThe_path);
|
||||
unlink(pThe_path);
|
||||
remove(pThe_path);
|
||||
rename(new_file, pThe_path);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#include "harness/hooks.h"
|
||||
#include "pd/sys.h"
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern int original_main(int pArgc, char* pArgv[]);
|
||||
|
||||
|
|
@ -10,15 +9,15 @@ int main(int argc, char* argv[]) {
|
|||
/* Attach to the console that started us if any */
|
||||
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||
/* We attached successfully, lets redirect IO to the consoles handles if not already redirected */
|
||||
if (_fileno(stdout) == -2 || _get_osfhandle(fileno(stdout)) == -2) {
|
||||
if (_fileno(stdout) == -2 || _get_osfhandle(_fileno(stdout)) == -2) {
|
||||
freopen("CONOUT$", "w", stdout);
|
||||
}
|
||||
|
||||
if (_fileno(stderr) == -2 || _get_osfhandle(fileno(stderr)) == -2) {
|
||||
if (_fileno(stderr) == -2 || _get_osfhandle(_fileno(stderr)) == -2) {
|
||||
freopen("CONOUT$", "w", stderr);
|
||||
}
|
||||
|
||||
if (_fileno(stdin) == -2 || _get_osfhandle(fileno(stdin)) == -2) {
|
||||
if (_fileno(stdin) == -2 || _get_osfhandle(_fileno(stdin)) == -2) {
|
||||
freopen("CONIN$", "r", stdin);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -352,6 +352,7 @@ void PDNetObtainSystemUserName(char* pName, int pMax_length) {
|
|||
int size;
|
||||
char buffer[16];
|
||||
BOOL result;
|
||||
|
||||
#endif
|
||||
|
||||
dr_dprintf("PDNetObtainSystemUserName()\n");
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "graphics.h"
|
||||
#include "harness/config.h"
|
||||
#include "harness/hooks.h"
|
||||
#include "harness/os.h"
|
||||
#include "harness/trace.h"
|
||||
#include "input.h"
|
||||
#include "loadsave.h"
|
||||
|
|
@ -13,43 +14,12 @@
|
|||
#include "pd/sys.h"
|
||||
#include "sound.h"
|
||||
#include "utility.h"
|
||||
#include "watcom_functions.h"
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define NS_PER_SEC (1000ULL * 1000ULL * 1000ULL)
|
||||
#define CLOCK_MONOTONIC 1
|
||||
|
||||
int clock_gettime(int dummy, struct timespec* tv) {
|
||||
static LARGE_INTEGER ticksPerSec;
|
||||
LARGE_INTEGER ticks;
|
||||
double seconds;
|
||||
|
||||
if (!ticksPerSec.QuadPart) {
|
||||
QueryPerformanceFrequency(&ticksPerSec);
|
||||
if (!ticksPerSec.QuadPart) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
QueryPerformanceCounter(&ticks);
|
||||
|
||||
seconds = (double)ticks.QuadPart / (double)ticksPerSec.QuadPart;
|
||||
tv->tv_sec = (time_t)seconds;
|
||||
tv->tv_nsec = (long)((ULONGLONG)(seconds * NS_PER_SEC) % NS_PER_SEC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __DOS__
|
||||
#define GFX_INIT_STRING_32X20X8 "MCGA,W:320,H:200,B:8"
|
||||
|
|
@ -230,9 +200,9 @@ void KeyBegin() {
|
|||
// *(_WORD *)gScan_code[9] = 56;
|
||||
// *(_WORD *)gScan_code[10] = 29;
|
||||
|
||||
//gPrev_keyboard_handler = (void (__fastcall *)())dos_getvect(9);
|
||||
//unk_142E6C = v2;
|
||||
//dos_setvect(9, KeyboardHandler);
|
||||
// gPrev_keyboard_handler = (void (__fastcall *)())dos_getvect(9);
|
||||
// unk_142E6C = v2;
|
||||
// dos_setvect(9, KeyboardHandler);
|
||||
}
|
||||
|
||||
// IDA: void __cdecl KeyEnd()
|
||||
|
|
@ -297,8 +267,6 @@ void PDFatalError(char* pThe_str) {
|
|||
|
||||
// wait for keypress
|
||||
|
||||
Harness_Debug_PrintStack();
|
||||
|
||||
if (!_unittest_do_not_exit) {
|
||||
exit(1);
|
||||
}
|
||||
|
|
@ -318,9 +286,9 @@ void PDInitialiseSystem() {
|
|||
|
||||
KeyBegin();
|
||||
|
||||
//v4 = DOSMouseBegin();
|
||||
// v4 = DOSMouseBegin();
|
||||
gJoystick_deadzone = 8000;
|
||||
//gUpper_loop_limit = sub_A1940(v4, v5, v3, v6) / 2;
|
||||
// gUpper_loop_limit = sub_A1940(v4, v5, v3, v6) / 2;
|
||||
|
||||
// Demo does not ship with KEYBOARD.COK file
|
||||
if (harness_game_info.mode != eGame_carmageddon_demo) {
|
||||
|
|
@ -520,20 +488,12 @@ void PDBuildAppPath(char* pThe_path) {
|
|||
void PDForEveryFile(char* pThe_path, void (*pAction_routine)(char*)) {
|
||||
char find_path[256];
|
||||
char found_path[256];
|
||||
//find_t the_find_buffer;
|
||||
DIR* d;
|
||||
struct dirent* entry;
|
||||
|
||||
d = opendir(pThe_path);
|
||||
if (d) {
|
||||
while ((entry = readdir(d)) != NULL) {
|
||||
// only files, and only files that don't start with '.'
|
||||
if (entry->d_type == DT_REG && entry->d_name[0] != '.') {
|
||||
PathCat(found_path, pThe_path, entry->d_name);
|
||||
pAction_routine(found_path);
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
char* found = OS_GetFirstFileInDirectory(pThe_path);
|
||||
while (found != NULL) {
|
||||
PathCat(found_path, pThe_path, found);
|
||||
pAction_routine(found_path);
|
||||
found = OS_GetNextFileInDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -592,9 +552,7 @@ void PDGetMousePosition(int* pX_coord, int* pY_coord) {
|
|||
|
||||
// IDA: int __cdecl PDGetTotalTime()
|
||||
int PDGetTotalTime() {
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_MONOTONIC, &spec);
|
||||
return spec.tv_sec * 1000 + spec.tv_nsec / 1000000;
|
||||
return OS_GetTime();
|
||||
}
|
||||
|
||||
// IDA: int __usercall PDServiceSystem@<EAX>(tU32 pTime_since_last_call@<EAX>)
|
||||
|
|
@ -637,9 +595,10 @@ void PDDisposeActionReplayBuffer(char* pBuffer) {
|
|||
|
||||
// IDA: void __usercall Usage(char *pProgpath@<EAX>)
|
||||
void Usage(char* pProgpath) {
|
||||
char basename[9];
|
||||
// char basename[9];
|
||||
char basename[256]; // fix: changed from 9 to avoid overflow on longer filenames
|
||||
|
||||
splitpath(pProgpath, NULL, NULL, basename, NULL);
|
||||
OS_Basename(pProgpath, basename);
|
||||
|
||||
fprintf(stderr,
|
||||
"Usage: %s [%s] [%s YonFactor] [%s CarSimplificationLevel] [%s SoundDetailLevel] [%s] [%s] [%s] [%s] [%s] [%s]\nWhere YonFactor is between 0 and 1,\nCarSimplificationLevel is a whole number between 0 and %d,\nand SoundDetailLevel is a whole number.\n",
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
#include "watcom_functions.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <libgen.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#else
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
void splitpath(char* path, char* drive, char* dir, char* fname, char* ext) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
_splitpath(path, drive, dir, fname, ext);
|
||||
#else
|
||||
// shortcut - we only ever call this method asking for 'fname'
|
||||
// 9 is hardcoded to match `basename` defined in `Usage`
|
||||
strncpy(fname, basename(path), 9);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef _WATCOM_FUNCTIONS_H_
|
||||
#define _WATCOM_FUNCTIONS_H_
|
||||
|
||||
void splitpath(char* path, char* drive, char* dir, char* fname, char* ext);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
add_library(harness STATIC)
|
||||
|
||||
if (NOT DEFINED IO_PLATFORM)
|
||||
set(IO_PLATFORM "SDL_OpenGL")
|
||||
endif()
|
||||
|
||||
target_include_directories(harness
|
||||
PRIVATE
|
||||
.
|
||||
|
|
@ -9,7 +13,7 @@ target_include_directories(harness
|
|||
include
|
||||
)
|
||||
|
||||
target_link_libraries(harness PRIVATE miniposix brender SDL2::SDL2 glad s3 cglm_headers)
|
||||
target_link_libraries(harness PRIVATE brender s3 cglm_headers)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(harness PRIVATE dbghelp)
|
||||
|
|
@ -30,39 +34,45 @@ target_sources(harness PRIVATE
|
|||
include/harness/hooks.h
|
||||
include/harness/trace.h
|
||||
include/harness/config.h
|
||||
include/harness/os.h
|
||||
|
||||
cameras/debug_camera.c
|
||||
cameras/debug_camera.h
|
||||
harness_trace.c
|
||||
harness.c
|
||||
harness.h
|
||||
sdl/gl_renderer.c
|
||||
sdl/gl_renderer.h
|
||||
sdl/gl_renderer_shaders.c
|
||||
sdl/gl_renderer_shaders.h
|
||||
sdl/gl_brender_stored_context.c
|
||||
sdl/gl_brender_stored_context.h
|
||||
io_platforms/io_platform.h
|
||||
renderers/null.h
|
||||
renderers/renderer.h
|
||||
brender_emu/renderer_impl.c
|
||||
brender_emu/renderer_impl.h
|
||||
sound/sound.c
|
||||
sound/sound.h
|
||||
sdl/common.c
|
||||
sdl/common.h
|
||||
platforms/sdl_gl.h
|
||||
platforms/null.h
|
||||
stack_trace_handler.h
|
||||
)
|
||||
|
||||
if (IO_PLATFORM STREQUAL "SDL_OpenGL")
|
||||
target_sources(harness PRIVATE
|
||||
io_platforms/sdl_gl.c
|
||||
renderers/gl/gl_renderer.c
|
||||
renderers/gl/gl_renderer.h
|
||||
renderers/gl/shaders.c
|
||||
renderers/gl/shaders.h
|
||||
renderers/gl/stored_context.c
|
||||
renderers/gl/stored_context.h
|
||||
)
|
||||
target_link_libraries(harness PRIVATE SDL2::SDL2 glad)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_sources(harness PRIVATE
|
||||
platforms/platform_windows.c
|
||||
os/windows.c
|
||||
)
|
||||
elseif(APPLE)
|
||||
target_sources(harness PRIVATE
|
||||
platforms/platform_macosx.c
|
||||
os/macos.c
|
||||
)
|
||||
else()
|
||||
target_sources(harness PRIVATE
|
||||
platforms/platform_linux.c
|
||||
os/linux.c
|
||||
)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
#include "harness.h"
|
||||
#include "brender_emu/renderer_impl.h"
|
||||
#include "include/harness/config.h"
|
||||
#include "platforms/null.h"
|
||||
#include "platforms/sdl_gl.h"
|
||||
#include "include/harness/os.h"
|
||||
#include "io_platforms/io_platform.h"
|
||||
#include "renderers/null.h"
|
||||
#include "sound/sound.h"
|
||||
#include "stack_trace_handler.h"
|
||||
|
||||
#include <strings.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
tPlatform* platform;
|
||||
tRenderer* renderer;
|
||||
br_pixelmap* palette;
|
||||
uint32_t* screen_buffer;
|
||||
harness_br_renderer* renderer_state;
|
||||
|
|
@ -21,6 +22,7 @@ br_pixelmap* last_src = NULL;
|
|||
br_pixelmap *last_colour_buffer, *last_depth_buffer;
|
||||
|
||||
unsigned int last_frame_time = 0;
|
||||
int force_nullrenderer = 0;
|
||||
|
||||
extern unsigned int GetTotalTime();
|
||||
extern uint8_t gScan_code[123][2];
|
||||
|
|
@ -71,11 +73,10 @@ void Harness_Init(int* argc, char* argv[]) {
|
|||
Harness_ProcessCommandLine(argc, argv);
|
||||
|
||||
if (harness_game_config.install_signalhandler) {
|
||||
install_signal_handler(argv[0]);
|
||||
OS_InstallSignalHandler(argv[0]);
|
||||
}
|
||||
platform->Init();
|
||||
|
||||
int* keymap = platform->GetKeyMap();
|
||||
int* keymap = Input_GetKeyMap();
|
||||
if (keymap != NULL) {
|
||||
for (int i = 0; i < 123; i++) {
|
||||
gScan_code[i][0] = keymap[i];
|
||||
|
|
@ -98,15 +99,13 @@ void Harness_Init(int* argc, char* argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
void Harness_Debug_PrintStack() {
|
||||
#ifndef _WIN32
|
||||
posix_print_stack_trace();
|
||||
#endif
|
||||
// used by unit tests
|
||||
void Harness_ForceNullRenderer() {
|
||||
force_nullrenderer = 1;
|
||||
renderer = &null_renderer;
|
||||
}
|
||||
|
||||
int Harness_ProcessCommandLine(int* argc, char* argv[]) {
|
||||
char* platform_name = NULL;
|
||||
|
||||
for (int i = 1; i < *argc; i++) {
|
||||
int handled = 0;
|
||||
|
||||
|
|
@ -118,10 +117,6 @@ int Harness_ProcessCommandLine(int* argc, char* argv[]) {
|
|||
harness_debug_level = atoi(s + 1);
|
||||
LOG_INFO("debug level set to %d", harness_debug_level);
|
||||
handled = 1;
|
||||
} else if (strstr(argv[i], "--platform=") != NULL) {
|
||||
platform_name = strstr(argv[i], "=") + 1;
|
||||
LOG_INFO("Platform set to: %s", platform_name);
|
||||
handled = 1;
|
||||
} else if (strstr(argv[i], "--physics-step-time=") != NULL) {
|
||||
char* s = strstr(argv[i], "=");
|
||||
harness_game_config.physics_step_time = atof(s + 1);
|
||||
|
|
@ -152,39 +147,31 @@ int Harness_ProcessCommandLine(int* argc, char* argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
if (platform_name == NULL) {
|
||||
platform_name = "sdl_gl";
|
||||
}
|
||||
|
||||
if (strcmp(platform_name, "sdl_gl") == 0) {
|
||||
platform = &sdl_gl_platform;
|
||||
} else if (strcmp(platform_name, "null") == 0) {
|
||||
platform = &null_platform;
|
||||
} else {
|
||||
LOG_PANIC("Invalid platform: %s", platform_name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Harness_Hook_DOSGfxBegin() {
|
||||
platform->NewWindow("Dethrace", 640, 400, 320, 200);
|
||||
if (force_nullrenderer) {
|
||||
return;
|
||||
}
|
||||
renderer = Window_Create("Dethrace", 640, 400, 320, 200);
|
||||
}
|
||||
|
||||
// Render 2d back buffer
|
||||
void Harness_RenderScreen(br_pixelmap* dst, br_pixelmap* src) {
|
||||
platform->RenderFullScreenQuad((uint8_t*)src->pixels, 320, 200);
|
||||
renderer->FullScreenQuad((uint8_t*)src->pixels, 320, 200);
|
||||
|
||||
last_dst = dst;
|
||||
last_src = src;
|
||||
}
|
||||
|
||||
void Harness_Hook_BrDevPaletteSetOld(br_pixelmap* pm) {
|
||||
platform->SetPalette((uint8_t*)pm->pixels);
|
||||
renderer->SetPalette((uint8_t*)pm->pixels);
|
||||
palette = pm;
|
||||
|
||||
if (last_dst) {
|
||||
Harness_RenderScreen(last_dst, last_src);
|
||||
platform->Swap();
|
||||
Window_Swap(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -200,74 +187,78 @@ void Harness_Hook_BrV1dbRendererBegin(br_v1db_state* v1db) {
|
|||
v1db->renderer = (br_renderer*)renderer_state;
|
||||
}
|
||||
|
||||
void Harness_Hook_MainGameLoop() {
|
||||
int Harness_CalculateFrameDelay() {
|
||||
if (harness_game_config.fps == 0) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (last_frame_time) {
|
||||
unsigned int frame_time = GetTotalTime() - last_frame_time;
|
||||
unsigned int now = GetTotalTime();
|
||||
|
||||
if (last_frame_time != 0) {
|
||||
unsigned int frame_time = now - last_frame_time;
|
||||
last_frame_time = now;
|
||||
if (frame_time < 100) {
|
||||
|
||||
int sleep_time = (1000 / harness_game_config.fps) - frame_time;
|
||||
if (sleep_time > 5) {
|
||||
SDL_Delay(sleep_time);
|
||||
return sleep_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_frame_time = GetTotalTime();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Begin 3d scene
|
||||
void Harness_Hook_BrZbSceneRenderBegin(br_actor* world, br_actor* camera, br_pixelmap* colour_buffer, br_pixelmap* depth_buffer) {
|
||||
last_colour_buffer = colour_buffer;
|
||||
last_depth_buffer = depth_buffer;
|
||||
platform->BeginScene(camera, colour_buffer);
|
||||
renderer->BeginScene(camera, colour_buffer);
|
||||
}
|
||||
|
||||
void Harness_Hook_BrZbSceneRenderAdd(br_actor* tree) {
|
||||
}
|
||||
|
||||
void Harness_Hook_renderFaces(br_actor* actor, br_model* model, br_material* material, br_token type) {
|
||||
platform->RenderModel(actor, model, renderer_state->state.matrix.model_to_view);
|
||||
renderer->Model(actor, model, renderer_state->state.matrix.model_to_view);
|
||||
}
|
||||
|
||||
void Harness_Hook_BrZbSceneRenderEnd() {
|
||||
platform->EndScene();
|
||||
renderer->EndScene();
|
||||
}
|
||||
|
||||
// Called by game to swap buffers at end of frame rendering
|
||||
void Harness_Hook_BrPixelmapDoubleBuffer(br_pixelmap* dst, br_pixelmap* src) {
|
||||
|
||||
// draw the current colour_buffer (2d screen) contents
|
||||
platform->FlushBuffers(last_colour_buffer, last_depth_buffer);
|
||||
renderer->FlushBuffers(last_colour_buffer, last_depth_buffer);
|
||||
Harness_RenderScreen(dst, src);
|
||||
|
||||
platform->Swap();
|
||||
platform->PollEvents();
|
||||
int delay_ms = Harness_CalculateFrameDelay();
|
||||
Window_Swap(delay_ms);
|
||||
|
||||
renderer->ClearBuffers();
|
||||
Window_PollEvents();
|
||||
|
||||
last_frame_time = GetTotalTime();
|
||||
}
|
||||
|
||||
int Harness_Hook_KeyDown(unsigned char pScan_code) {
|
||||
return platform->IsKeyDown(pScan_code);
|
||||
return Input_IsKeyDown(pScan_code);
|
||||
}
|
||||
|
||||
void Harness_Hook_PDServiceSystem() {
|
||||
platform->PollEvents();
|
||||
Window_PollEvents();
|
||||
}
|
||||
void Harness_Hook_PDSetKeyArray() {
|
||||
platform->PollEvents();
|
||||
Window_PollEvents();
|
||||
}
|
||||
|
||||
void Harness_Hook_BrMaterialUpdate(br_material* mat, br_uint_16 flags) {
|
||||
// LOG_DEBUG("buffermat %s", mat->identifier);
|
||||
platform->BufferMaterial(mat);
|
||||
renderer->BufferMaterial(mat);
|
||||
}
|
||||
|
||||
void Harness_Hook_BrBufferUpdate(br_pixelmap* pm, br_token use, br_uint_16 flags) {
|
||||
if (use == BRT_COLOUR_MAP_O || use == BRT_UNKNOWN) {
|
||||
platform->BufferTexture(pm);
|
||||
renderer->BufferTexture(pm);
|
||||
} else {
|
||||
LOG_PANIC("use %d", use);
|
||||
}
|
||||
|
|
@ -281,6 +272,5 @@ void Harness_Hook_S3StopAllOutletSounds() {
|
|||
}
|
||||
|
||||
void Harness_Hook_FlushRenderer() {
|
||||
platform->FlushBuffers(last_colour_buffer, last_depth_buffer);
|
||||
renderer->FlushBuffers(last_colour_buffer, last_depth_buffer);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,23 +4,7 @@
|
|||
#include "brender/br_types.h"
|
||||
#include "harness/trace.h"
|
||||
|
||||
typedef struct tPlatform {
|
||||
void (*Init)();
|
||||
void (*NewWindow)(char* title, int width, int height, int render_width, int render_height);
|
||||
void (*PollEvents)();
|
||||
int* (*GetKeyMap)();
|
||||
int (*IsKeyDown)(unsigned char pScan_code);
|
||||
void (*BeginScene)(br_actor* camera, br_pixelmap* colour_buffer);
|
||||
void (*EndScene)();
|
||||
void (*SetPalette)(uint8_t* palette);
|
||||
void (*RenderFullScreenQuad)(uint8_t* src, int width, int height);
|
||||
void (*RenderModel)(br_actor* actor, br_model* model, br_matrix34 model_matrix);
|
||||
void (*Swap)();
|
||||
void (*BufferTexture)(br_pixelmap* pm);
|
||||
void (*BufferMaterial)(br_material* mat);
|
||||
void (*FlushBuffers)(br_pixelmap* color_buffer, br_pixelmap* depth_buffer);
|
||||
|
||||
} tPlatform;
|
||||
void Harness_ForceNullRenderer();
|
||||
|
||||
typedef struct tCamera {
|
||||
void (*update)();
|
||||
|
|
@ -29,4 +13,6 @@ typedef struct tCamera {
|
|||
void (*setPosition)();
|
||||
} tCamera;
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
#include "harness/trace.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
|
|
|||
|
|
@ -3,14 +3,15 @@
|
|||
|
||||
#include "brender/br_types.h"
|
||||
|
||||
void Harness_Init(int* argc, char* argv[]);
|
||||
|
||||
// Hooks are called from original game code.
|
||||
|
||||
// Dethrace hooks
|
||||
void Harness_Init(int* argc, char* argv[]);
|
||||
int Harness_Hook_KeyDown(unsigned char pScan_code);
|
||||
void Harness_Hook_PDServiceSystem();
|
||||
void Harness_Hook_PDSetKeyArray();
|
||||
void Harness_Hook_MainGameLoop(); // limit FPS
|
||||
// void Harness_Hook_MainGameLoop(); // limit FPS
|
||||
void Harness_Hook_FlushRenderer(); // synchronize in-memory framebuffer and depthbuffer
|
||||
|
||||
// BRender hooks
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
#ifndef HARNESS_OS_H
|
||||
#define HARNESS_OS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#define getcwd _getcwd
|
||||
#define chdir _chdir
|
||||
#define access _access
|
||||
#define F_OK 0
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
|
||||
#if _MSC_VER < 1900
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
// Required: return timestamp in milliseconds.
|
||||
uint32_t OS_GetTime(void);
|
||||
|
||||
// Required: sleep for specified milliseconds
|
||||
void OS_Sleep(int ms);
|
||||
|
||||
// Required: begin a directory iteration and return name of first file
|
||||
char* OS_GetFirstFileInDirectory(char* path);
|
||||
|
||||
// Required: continue directory iteration. If no more files, return NULL
|
||||
char* OS_GetNextFileInDirectory(void);
|
||||
|
||||
// Required: copy the `basename` component of `path` into `base`
|
||||
void OS_Basename(char* path, char* base);
|
||||
|
||||
// Optional: return true if a debugger is detected
|
||||
int OS_IsDebuggerPresent(void);
|
||||
|
||||
// Optional: install a handler to print stack trace during a crash
|
||||
void OS_InstallSignalHandler(char* program_name);
|
||||
|
||||
#endif
|
||||
|
|
@ -3,16 +3,9 @@
|
|||
|
||||
#include "brender/br_types.h"
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined _WIN32 && !defined sleep
|
||||
#define sleep(x) _sleep(x)
|
||||
#endif
|
||||
|
||||
extern int harness_debug_level;
|
||||
extern int PlatformIsDebuggerPresent(void);
|
||||
|
||||
void Harness_Debug_PrintStack();
|
||||
extern int OS_IsDebuggerPresent(void);
|
||||
|
||||
void debug_printf(const char* fmt, const char* fn, const char* fmt2, ...);
|
||||
void debug_print_vector3(const char* fmt, const char* fn, char* msg, br_vector3* v);
|
||||
|
|
@ -46,26 +39,26 @@ void debug_print_matrix4(const char* fmt, const char* fn, char* name, br_matrix4
|
|||
#define LOG_MATRIX4(msg, m) debug_print_matrix4("\033[0;34m[DEBUG] %s ", __FUNCTION__, msg, m)
|
||||
#define LOG_INFO(...) debug_printf("\033[0;34m[INFO] %s ", __FUNCTION__, __VA_ARGS__)
|
||||
#define LOG_WARN(...) debug_printf("\033[0;33m[WARN] %s ", __FUNCTION__, __VA_ARGS__)
|
||||
#define LOG_PANIC(...) \
|
||||
do { \
|
||||
debug_printf("\033[0;31m[PANIC] %s ", __FUNCTION__, __VA_ARGS__); \
|
||||
if (PlatformIsDebuggerPresent()) \
|
||||
abort(); \
|
||||
else \
|
||||
exit(1); \
|
||||
#define LOG_PANIC(...) \
|
||||
do { \
|
||||
debug_printf("\033[0;31m[PANIC] %s ", __FUNCTION__, __VA_ARGS__); \
|
||||
if (OS_IsDebuggerPresent()) \
|
||||
abort(); \
|
||||
else \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
#define LOG_WARN_ONCE(...) \
|
||||
static int warn_printed = 0; \
|
||||
if (!warn_printed) { \
|
||||
debug_printf("\033[0;33m[WARN] %s ", __FUNCTION__, __VA_ARGS__); \
|
||||
warn_printed = 1; \
|
||||
#define LOG_WARN_ONCE(...) \
|
||||
static int warn_printed = 0; \
|
||||
if (!warn_printed) { \
|
||||
debug_printf("\033[0;33m[WARN] %s ", __FUNCTION__, __VA_ARGS__); \
|
||||
warn_printed = 1; \
|
||||
}
|
||||
|
||||
#define NOT_IMPLEMENTED() \
|
||||
#define NOT_IMPLEMENTED() \
|
||||
LOG_PANIC("not implemented")
|
||||
|
||||
#define TELL_ME_IF_WE_PASS_THIS_WAY() \
|
||||
#define TELL_ME_IF_WE_PASS_THIS_WAY() \
|
||||
LOG_PANIC("code path not expected")
|
||||
|
||||
#define STUB() \
|
||||
|
|
@ -78,6 +71,6 @@ void debug_print_matrix4(const char* fmt, const char* fn, char* name, br_matrix4
|
|||
stub_printed = 1; \
|
||||
}
|
||||
|
||||
//int count_open_fds();
|
||||
// int count_open_fds();
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef PLATFORM_H
|
||||
#define PLATFORM_H
|
||||
|
||||
#include "../renderers/renderer.h"
|
||||
|
||||
tRenderer* Window_Create(char* title, int width, int height, int pRender_width, int pRender_height);
|
||||
void Window_PollEvents(void);
|
||||
void Window_Swap(int delay_ms_after_swap);
|
||||
int* Input_GetKeyMap(void);
|
||||
int Input_IsKeyDown(unsigned char scan_code);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,5 +1,12 @@
|
|||
#include "common.h"
|
||||
#include <glad/glad.h>
|
||||
|
||||
// this needs to be included after glad.h
|
||||
#include <SDL.h>
|
||||
#include <SDL_opengl.h>
|
||||
|
||||
#include "../renderers/gl/gl_renderer.h"
|
||||
#include "../renderers/renderer.h"
|
||||
#include "harness/trace.h"
|
||||
|
||||
// Errol's keymap
|
||||
int keymap[123] = {
|
||||
|
|
@ -112,15 +119,69 @@ int keymap[123] = {
|
|||
SDL_SCANCODE_SPACE
|
||||
};
|
||||
|
||||
SDL_Window* window;
|
||||
SDL_GLContext context;
|
||||
uint8_t sdl_key_state[256];
|
||||
|
||||
void SDLPlatform_Init() {
|
||||
if (SDL_Init(SDL_INIT_TIMER) != 0) {
|
||||
LOG_PANIC("SDL_INIT_TIMER error: %s", SDL_GetError());
|
||||
tRenderer gl_renderer = {
|
||||
GLRenderer_Init,
|
||||
GLRenderer_BeginScene,
|
||||
GLRenderer_EndScene,
|
||||
GLRenderer_SetPalette,
|
||||
GLRenderer_FullScreenQuad,
|
||||
GLRenderer_Model,
|
||||
GLRenderer_ClearBuffers,
|
||||
GLRenderer_BufferTexture,
|
||||
GLRenderer_BufferMaterial,
|
||||
GLRenderer_FlushBuffers
|
||||
};
|
||||
|
||||
tRenderer* Window_Create(char* title, int width, int height, int pRender_width, int pRender_height) {
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||
LOG_PANIC("SDL_INIT_VIDEO error: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE) != 0) {
|
||||
LOG_PANIC("Failed to set SDL_GL_CONTEXT_PROFILE_MASK attribute. %s", SDL_GetError());
|
||||
};
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
|
||||
window = SDL_CreateWindow(title,
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
width, height,
|
||||
SDL_WINDOW_OPENGL);
|
||||
|
||||
if (!window) {
|
||||
LOG_PANIC("Failed to create window");
|
||||
}
|
||||
|
||||
// Don't grab the mouse when a debugger is present
|
||||
if (!OS_IsDebuggerPresent()) {
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
}
|
||||
|
||||
// SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN);
|
||||
|
||||
context = SDL_GL_CreateContext(window);
|
||||
if (!context) {
|
||||
LOG_PANIC("Failed to call SDL_GL_CreateContext. %s", SDL_GetError());
|
||||
}
|
||||
|
||||
// Load GL extensions using glad
|
||||
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
|
||||
LOG_PANIC("Failed to initialize the OpenGL context with GLAD.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
gl_renderer.Init(width, height, pRender_width, pRender_height);
|
||||
return &gl_renderer;
|
||||
}
|
||||
|
||||
void SDLPlatform_PollEvents() {
|
||||
void Window_PollEvents() {
|
||||
SDL_Event event;
|
||||
|
||||
while (SDL_PollEvent(&event)) {
|
||||
|
|
@ -134,7 +195,7 @@ void SDLPlatform_PollEvents() {
|
|||
}
|
||||
if (event.key.type == SDL_KEYDOWN) {
|
||||
sdl_key_state[event.key.keysym.scancode] = 1;
|
||||
//LOG_DEBUG("key %d", key->keysym.scancode);
|
||||
// LOG_DEBUG("key %d", key->keysym.scancode);
|
||||
} else {
|
||||
sdl_key_state[event.key.keysym.scancode] = 0;
|
||||
}
|
||||
|
|
@ -148,10 +209,18 @@ void SDLPlatform_PollEvents() {
|
|||
}
|
||||
}
|
||||
|
||||
int* SDLPlatform_GetKeyMap() {
|
||||
void Window_Swap(int delay_ms_after_swap) {
|
||||
SDL_GL_SwapWindow(window);
|
||||
|
||||
if (delay_ms_after_swap != 0) {
|
||||
SDL_Delay(delay_ms_after_swap);
|
||||
}
|
||||
}
|
||||
|
||||
int* Input_GetKeyMap() {
|
||||
return (int*)keymap;
|
||||
}
|
||||
|
||||
int SDLPlatform_IsKeyDown(unsigned char scan_code) {
|
||||
int Input_IsKeyDown(unsigned char scan_code) {
|
||||
return sdl_key_state[scan_code];
|
||||
}
|
||||
|
|
@ -1,7 +1,14 @@
|
|||
// Based on https://gist.github.com/jvranish/4441299
|
||||
|
||||
#include "harness/os.h"
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <execinfo.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
|
|
@ -9,158 +16,107 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
#ifdef _WIN64
|
||||
#define Esp Rsp
|
||||
#define Eip Rip
|
||||
#define Ebp Rbp
|
||||
#endif
|
||||
#else
|
||||
#include <err.h>
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
static int stack_nbr = 0;
|
||||
static char _program_name[1024];
|
||||
#define MAX_STACK_FRAMES 64
|
||||
static void* stack_traces[MAX_STACK_FRAMES];
|
||||
#define TRACER_PID_STRING "TracerPid:"
|
||||
DIR* directory_iterator;
|
||||
|
||||
/* Resolve symbol name and source location given the path to the executable
|
||||
and an address */
|
||||
uint32_t OS_GetTime() {
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_MONOTONIC, &spec);
|
||||
return spec.tv_sec * 1000 + spec.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
void OS_Sleep(int delay_ms) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = delay_ms / 1000;
|
||||
ts.tv_nsec = (delay_ms % 1000) * 1000000;
|
||||
nanosleep(&ts, &ts);
|
||||
}
|
||||
|
||||
char* OS_GetFirstFileInDirectory(char* path) {
|
||||
directory_iterator = opendir(path);
|
||||
if (directory_iterator == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return OS_GetNextFileInDirectory();
|
||||
}
|
||||
|
||||
char* OS_GetNextFileInDirectory(void) {
|
||||
struct dirent* entry;
|
||||
|
||||
if (directory_iterator == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
while ((entry = readdir(directory_iterator)) != NULL) {
|
||||
if (entry->d_type == DT_REG) {
|
||||
return entry->d_name;
|
||||
}
|
||||
}
|
||||
closedir(directory_iterator);
|
||||
directory_iterator = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void OS_Basename(char* path, char* base) {
|
||||
strcpy(base, basename(path));
|
||||
}
|
||||
|
||||
int OS_IsDebuggerPresent() {
|
||||
char buf[4096];
|
||||
int status_fd;
|
||||
ssize_t num_read;
|
||||
char* tracer_pid_ptr;
|
||||
char* char_ptr;
|
||||
|
||||
status_fd = open("/proc/self/status", O_RDONLY);
|
||||
if (status_fd == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
num_read = read(status_fd, buf, sizeof(buf) - 1);
|
||||
close(status_fd);
|
||||
if (num_read <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf[num_read] = '\0';
|
||||
tracer_pid_ptr = strstr(buf, TRACER_PID_STRING);
|
||||
if (tracer_pid_ptr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (char_ptr = tracer_pid_ptr + sizeof(TRACER_PID_STRING) - 1; char_ptr <= buf + num_read; ++char_ptr) {
|
||||
if (isspace(*char_ptr)) {
|
||||
continue;
|
||||
} else {
|
||||
return isdigit(*char_ptr) != 0 && *char_ptr != '0';
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Resolve symbol name and source location given the path to the executable and an address
|
||||
int addr2line(char const* const program_name, void const* const addr) {
|
||||
char addr2line_cmd[512] = { 0 };
|
||||
|
||||
/* have addr2line map the address to the relent line in the code */
|
||||
#ifdef __APPLE__
|
||||
/* apple does things differently... */
|
||||
sprintf(addr2line_cmd, "atos -o %.256s %p", program_name, addr);
|
||||
#else
|
||||
/* have addr2line map the address to the related line in the code */
|
||||
sprintf(addr2line_cmd, "addr2line -f -p -e %.256s %p", program_name, addr);
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "%d: ", stack_nbr++);
|
||||
return system(addr2line_cmd);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void windows_print_stacktrace(CONTEXT* context) {
|
||||
SymInitialize(GetCurrentProcess(), 0, true);
|
||||
|
||||
STACKFRAME frame = { 0 };
|
||||
|
||||
/* setup initial stack frame */
|
||||
frame.AddrPC.Offset = context->Eip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context->Esp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context->Ebp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
|
||||
while (StackWalk(IMAGE_FILE_MACHINE_I386,
|
||||
GetCurrentProcess(),
|
||||
GetCurrentThread(),
|
||||
&frame,
|
||||
context,
|
||||
0,
|
||||
SymFunctionTableAccess,
|
||||
SymGetModuleBase,
|
||||
0)) {
|
||||
addr2line(_program_name, (void*)frame.AddrPC.Offset);
|
||||
}
|
||||
|
||||
SymCleanup(GetCurrentProcess());
|
||||
}
|
||||
|
||||
LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS* ExceptionInfo) {
|
||||
switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
fputs("Error: EXCEPTION_ACCESS_VIOLATION\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
fputs("Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
fputs("Error: EXCEPTION_BREAKPOINT\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
fputs("Error: EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_FLT_DENORMAL_OPERAND:
|
||||
fputs("Error: EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
fputs("Error: EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_FLT_INEXACT_RESULT:
|
||||
fputs("Error: EXCEPTION_FLT_INEXACT_RESULT\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_FLT_INVALID_OPERATION:
|
||||
fputs("Error: EXCEPTION_FLT_INVALID_OPERATION\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_FLT_OVERFLOW:
|
||||
fputs("Error: EXCEPTION_FLT_OVERFLOW\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_FLT_STACK_CHECK:
|
||||
fputs("Error: EXCEPTION_FLT_STACK_CHECK\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_FLT_UNDERFLOW:
|
||||
fputs("Error: EXCEPTION_FLT_UNDERFLOW\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
fputs("Error: EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
fputs("Error: EXCEPTION_IN_PAGE_ERROR\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
fputs("Error: EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_INT_OVERFLOW:
|
||||
fputs("Error: EXCEPTION_INT_OVERFLOW\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_INVALID_DISPOSITION:
|
||||
fputs("Error: EXCEPTION_INVALID_DISPOSITION\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
|
||||
fputs("Error: EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
fputs("Error: EXCEPTION_PRIV_INSTRUCTION\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_SINGLE_STEP:
|
||||
fputs("Error: EXCEPTION_SINGLE_STEP\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
fputs("Error: EXCEPTION_STACK_OVERFLOW\n", stderr);
|
||||
break;
|
||||
default:
|
||||
fputs("Error: Unrecognized Exception\n", stderr);
|
||||
break;
|
||||
}
|
||||
fflush(stderr);
|
||||
/* If this is a stack overflow then we can't walk the stack, so just show
|
||||
where the error happened */
|
||||
if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) {
|
||||
windows_print_stacktrace(ExceptionInfo->ContextRecord);
|
||||
} else {
|
||||
addr2line(_program_name, (void*)ExceptionInfo->ContextRecord->Eip);
|
||||
}
|
||||
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
void install_signal_handler(char* program_name) {
|
||||
strcpy(_program_name, program_name);
|
||||
SetUnhandledExceptionFilter(windows_exception_handler);
|
||||
}
|
||||
#else
|
||||
|
||||
#define MAX_STACK_FRAMES 64
|
||||
static void* stack_traces[MAX_STACK_FRAMES];
|
||||
|
||||
void posix_print_stack_trace() {
|
||||
void print_stack_trace() {
|
||||
int i, trace_size = 0;
|
||||
char** messages = (char**)NULL;
|
||||
|
||||
|
|
@ -181,7 +137,7 @@ void posix_print_stack_trace() {
|
|||
}
|
||||
}
|
||||
|
||||
void posix_signal_handler(int sig, siginfo_t* siginfo, void* context) {
|
||||
void signal_handler(int sig, siginfo_t* siginfo, void* context) {
|
||||
(void)context;
|
||||
fputs("\n******************\n", stderr);
|
||||
|
||||
|
|
@ -264,7 +220,7 @@ void posix_signal_handler(int sig, siginfo_t* siginfo, void* context) {
|
|||
break;
|
||||
}
|
||||
fputs("******************\n", stderr);
|
||||
posix_print_stack_trace();
|
||||
print_stack_trace();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
@ -283,7 +239,7 @@ void resolve_full_path(char* path, const char* argv0) {
|
|||
}
|
||||
}
|
||||
|
||||
void install_signal_handler(char* program_name) {
|
||||
void OS_InstallSignalHandler(char* program_name) {
|
||||
|
||||
resolve_full_path(_program_name, program_name);
|
||||
|
||||
|
|
@ -304,16 +260,10 @@ void install_signal_handler(char* program_name) {
|
|||
/* register our signal handlers */
|
||||
{
|
||||
struct sigaction sig_action = {};
|
||||
sig_action.sa_sigaction = posix_signal_handler;
|
||||
sig_action.sa_sigaction = signal_handler;
|
||||
sigemptyset(&sig_action.sa_mask);
|
||||
|
||||
#ifdef __APPLE__
|
||||
/* for some reason we backtrace() doesn't work on osx
|
||||
when we use an alternate stack */
|
||||
sig_action.sa_flags = SA_SIGINFO;
|
||||
#else
|
||||
sig_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
#endif
|
||||
|
||||
if (sigaction(SIGSEGV, &sig_action, NULL) != 0) {
|
||||
err(1, "sigaction");
|
||||
|
|
@ -335,4 +285,3 @@ void install_signal_handler(char* program_name) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,286 @@
|
|||
// Based on https://gist.github.com/jvranish/4441299
|
||||
|
||||
#include "harness/os.h"
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <execinfo.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int stack_nbr = 0;
|
||||
static char _program_name[1024];
|
||||
#define MAX_STACK_FRAMES 64
|
||||
static void* stack_traces[MAX_STACK_FRAMES];
|
||||
DIR* directory_iterator;
|
||||
|
||||
uint32_t OS_GetTime() {
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_MONOTONIC, &spec);
|
||||
return spec.tv_sec * 1000 + spec.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
void OS_Sleep(int delay_ms) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = delay_ms / 1000;
|
||||
ts.tv_nsec = (delay_ms % 1000) * 1000000;
|
||||
nanosleep(&ts, &ts);
|
||||
}
|
||||
|
||||
char* OS_GetFirstFileInDirectory(char* path) {
|
||||
directory_iterator = opendir(path);
|
||||
if (directory_iterator == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return OS_GetNextFileInDirectory();
|
||||
}
|
||||
|
||||
char* OS_GetNextFileInDirectory(void) {
|
||||
struct dirent* entry;
|
||||
|
||||
if (directory_iterator == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
while ((entry = readdir(directory_iterator)) != NULL) {
|
||||
if (entry->d_type == DT_REG) {
|
||||
return entry->d_name;
|
||||
}
|
||||
}
|
||||
closedir(directory_iterator);
|
||||
directory_iterator = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void OS_Basename(char* path, char* base) {
|
||||
strcpy(base, basename(path));
|
||||
}
|
||||
|
||||
// https://developer.apple.com/library/archive/qa/qa1361/_index.html
|
||||
// FIXME:
|
||||
// Important: Because the definition of the kinfo_proc structure (in <sys/sysctl.h>) is conditionalized by __APPLE_API_UNSTABLE,
|
||||
// you should restrict use of the above code to the debug build of your program.
|
||||
|
||||
int OS_IsDebuggerPresent()
|
||||
// Returns true if the current process is being debugged (either
|
||||
// running under the debugger or has a debugger attached post facto).
|
||||
{
|
||||
int junk;
|
||||
int mib[4];
|
||||
struct kinfo_proc info;
|
||||
size_t size;
|
||||
|
||||
// Initialize the flags so that, if sysctl fails for some bizarre
|
||||
// reason, we get a predictable result.
|
||||
|
||||
info.kp_proc.p_flag = 0;
|
||||
|
||||
// Initialize mib, which tells sysctl the info we want, in this case
|
||||
// we're looking for information about a specific process ID.
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = getpid();
|
||||
|
||||
// Call sysctl.
|
||||
|
||||
size = sizeof(info);
|
||||
junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
|
||||
assert(junk == 0);
|
||||
|
||||
// We're being debugged if the P_TRACED flag is set.
|
||||
|
||||
return ((info.kp_proc.p_flag & P_TRACED) != 0);
|
||||
}
|
||||
|
||||
// Resolve symbol name and source location given the path to the executable and an address
|
||||
int addr2line(char const* const program_name, void const* const addr) {
|
||||
char addr2line_cmd[512] = { 0 };
|
||||
|
||||
/* have addr2line map the address to the related line in the code */
|
||||
sprintf(addr2line_cmd, "atos -o %.256s %p", program_name, addr);
|
||||
|
||||
fprintf(stderr, "%d: ", stack_nbr++);
|
||||
return system(addr2line_cmd);
|
||||
}
|
||||
|
||||
void print_stack_trace() {
|
||||
int i, trace_size = 0;
|
||||
char** messages = (char**)NULL;
|
||||
|
||||
fputs("\nStack trace:\n", stderr);
|
||||
|
||||
trace_size = backtrace(stack_traces, MAX_STACK_FRAMES);
|
||||
messages = backtrace_symbols(stack_traces, trace_size);
|
||||
|
||||
/* skip the first couple stack frames (as they are this function and
|
||||
our handler) and also skip the last frame as it's (always?) junk. */
|
||||
for (i = 3; i < (trace_size - 1); ++i) {
|
||||
if (addr2line(_program_name, stack_traces[i]) != 0) {
|
||||
printf(" error determining line # for: %s\n", messages[i]);
|
||||
}
|
||||
}
|
||||
if (messages) {
|
||||
free(messages);
|
||||
}
|
||||
}
|
||||
|
||||
void signal_handler(int sig, siginfo_t* siginfo, void* context) {
|
||||
(void)context;
|
||||
fputs("\n******************\n", stderr);
|
||||
|
||||
switch (sig) {
|
||||
case SIGSEGV:
|
||||
fputs("Caught SIGSEGV\n", stderr);
|
||||
break;
|
||||
case SIGINT:
|
||||
fputs("Caught SIGINT\n", stderr);
|
||||
break;
|
||||
case SIGFPE:
|
||||
switch (siginfo->si_code) {
|
||||
case FPE_INTDIV:
|
||||
fputs("Caught SIGFPE: FPE_INTDIV\n", stderr);
|
||||
break;
|
||||
case FPE_INTOVF:
|
||||
fputs("Caught SIGFPE: FPE_INTOVF\n", stderr);
|
||||
break;
|
||||
case FPE_FLTDIV:
|
||||
fputs("Caught SIGFPE: FPE_FLTDIV\n", stderr);
|
||||
break;
|
||||
case FPE_FLTOVF:
|
||||
fputs("Caught SIGFPE: FPE_FLTOVF\n", stderr);
|
||||
break;
|
||||
case FPE_FLTUND:
|
||||
fputs("Caught SIGFPE: FPE_FLTUND\n", stderr);
|
||||
break;
|
||||
case FPE_FLTRES:
|
||||
fputs("Caught SIGFPE: FPE_FLTRES\n", stderr);
|
||||
break;
|
||||
case FPE_FLTINV:
|
||||
fputs("Caught SIGFPE: FPE_FLTINV\n", stderr);
|
||||
break;
|
||||
case FPE_FLTSUB:
|
||||
fputs("Caught SIGFPE: FPE_FLTSUB\n", stderr);
|
||||
break;
|
||||
default:
|
||||
fputs("Caught SIGFPE: Arithmetic Exception\n", stderr);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SIGILL:
|
||||
switch (siginfo->si_code) {
|
||||
case ILL_ILLOPC:
|
||||
fputs("Caught SIGILL: ILL_ILLOPC\n", stderr);
|
||||
break;
|
||||
case ILL_ILLOPN:
|
||||
fputs("Caught SIGILL: ILL_ILLOPN\n", stderr);
|
||||
break;
|
||||
case ILL_ILLADR:
|
||||
fputs("Caught SIGILL: ILL_ILLADR\n", stderr);
|
||||
break;
|
||||
case ILL_ILLTRP:
|
||||
fputs("Caught SIGILL: ILL_ILLTRP\n", stderr);
|
||||
break;
|
||||
case ILL_PRVOPC:
|
||||
fputs("Caught SIGILL: ILL_PRVOPC\n", stderr);
|
||||
break;
|
||||
case ILL_PRVREG:
|
||||
fputs("Caught SIGILL: ILL_PRVREG\n", stderr);
|
||||
break;
|
||||
case ILL_COPROC:
|
||||
fputs("Caught SIGILL: ILL_COPROC\n", stderr);
|
||||
break;
|
||||
case ILL_BADSTK:
|
||||
fputs("Caught SIGILL: ILL_BADSTK\n", stderr);
|
||||
break;
|
||||
default:
|
||||
fputs("Caught SIGILL: Illegal Instruction\n", stderr);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SIGTERM:
|
||||
fputs("Caught SIGTERM\n", stderr);
|
||||
break;
|
||||
case SIGABRT:
|
||||
fputs("Caught SIGABRT\n", stderr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fputs("******************\n", stderr);
|
||||
print_stack_trace();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static uint8_t alternate_stack[SIGSTKSZ];
|
||||
|
||||
void resolve_full_path(char* path, const char* argv0) {
|
||||
if (argv0[0] == '/') { // run with absolute path
|
||||
strcpy(path, argv0);
|
||||
} else { // run with relative path
|
||||
if (NULL == getcwd(path, PATH_MAX)) {
|
||||
perror("getcwd error");
|
||||
return;
|
||||
}
|
||||
strcat(path, "/");
|
||||
strcat(path, argv0);
|
||||
}
|
||||
}
|
||||
|
||||
void OS_InstallSignalHandler(char* program_name) {
|
||||
|
||||
resolve_full_path(_program_name, program_name);
|
||||
|
||||
/* setup alternate stack */
|
||||
{
|
||||
stack_t ss = {};
|
||||
/* malloc is usually used here, I'm not 100% sure my static allocation
|
||||
is valid but it seems to work just fine. */
|
||||
ss.ss_sp = (void*)alternate_stack;
|
||||
ss.ss_size = SIGSTKSZ;
|
||||
ss.ss_flags = 0;
|
||||
|
||||
if (sigaltstack(&ss, NULL) != 0) {
|
||||
err(1, "sigaltstack");
|
||||
}
|
||||
}
|
||||
|
||||
/* register our signal handlers */
|
||||
{
|
||||
struct sigaction sig_action = {};
|
||||
sig_action.sa_sigaction = signal_handler;
|
||||
sigemptyset(&sig_action.sa_mask);
|
||||
|
||||
sig_action.sa_flags = SA_SIGINFO;
|
||||
|
||||
if (sigaction(SIGSEGV, &sig_action, NULL) != 0) {
|
||||
err(1, "sigaction");
|
||||
}
|
||||
if (sigaction(SIGFPE, &sig_action, NULL) != 0) {
|
||||
err(1, "sigaction");
|
||||
}
|
||||
if (sigaction(SIGINT, &sig_action, NULL) != 0) {
|
||||
err(1, "sigaction");
|
||||
}
|
||||
if (sigaction(SIGILL, &sig_action, NULL) != 0) {
|
||||
err(1, "sigaction");
|
||||
}
|
||||
if (sigaction(SIGTERM, &sig_action, NULL) != 0) {
|
||||
err(1, "sigaction");
|
||||
}
|
||||
if (sigaction(SIGABRT, &sig_action, NULL) != 0) {
|
||||
err(1, "sigaction");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
// Based on https://gist.github.com/jvranish/4441299
|
||||
|
||||
// this has to be first
|
||||
#include <windows.h>
|
||||
|
||||
#include <imagehlp.h>
|
||||
|
||||
#include "harness/os.h"
|
||||
#include <assert.h>
|
||||
#include <direct.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN64
|
||||
#define Esp Rsp
|
||||
#define Eip Rip
|
||||
#define Ebp Rbp
|
||||
#endif
|
||||
|
||||
static int stack_nbr = 0;
|
||||
static char _program_name[1024];
|
||||
LARGE_INTEGER qpc_start_time, EndingTime, ElapsedMicroseconds;
|
||||
LARGE_INTEGER qpc_ticks_per_sec;
|
||||
|
||||
HANDLE directory_handle = NULL;
|
||||
char last_found_file[260];
|
||||
|
||||
uint32_t OS_GetTime() {
|
||||
LARGE_INTEGER now;
|
||||
if (qpc_start_time.QuadPart == 0) {
|
||||
QueryPerformanceFrequency(&qpc_ticks_per_sec);
|
||||
QueryPerformanceCounter(&qpc_start_time);
|
||||
}
|
||||
|
||||
QueryPerformanceCounter(&now);
|
||||
return (uint32_t)(((now.QuadPart - qpc_start_time.QuadPart) * 1000) / qpc_ticks_per_sec.QuadPart);
|
||||
}
|
||||
|
||||
void OS_Sleep(int delay_ms) {
|
||||
Sleep(delay_ms);
|
||||
}
|
||||
|
||||
char* OS_GetFirstFileInDirectory(char* path) {
|
||||
char with_extension[256];
|
||||
WIN32_FIND_DATA find_data;
|
||||
HANDLE hFind = NULL;
|
||||
|
||||
strcpy(with_extension, path);
|
||||
strcat(with_extension, "\\*.???");
|
||||
directory_handle = FindFirstFile(with_extension, &find_data);
|
||||
if (directory_handle == INVALID_HANDLE_VALUE) {
|
||||
return NULL;
|
||||
}
|
||||
strcpy(last_found_file, find_data.cFileName);
|
||||
return last_found_file;
|
||||
}
|
||||
|
||||
// Required: continue directory iteration. If no more files, return NULL
|
||||
char* OS_GetNextFileInDirectory(void) {
|
||||
WIN32_FIND_DATA find_data;
|
||||
if (directory_handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (FindNextFile(directory_handle, &find_data)) {
|
||||
strcpy(last_found_file, find_data.cFileName);
|
||||
return last_found_file;
|
||||
}
|
||||
FindClose(directory_handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void OS_Basename(char* path, char* base) {
|
||||
_splitpath(path, NULL, NULL, base, NULL);
|
||||
}
|
||||
|
||||
int OS_IsDebuggerPresent() {
|
||||
return IsDebuggerPresent();
|
||||
}
|
||||
|
||||
int addr2line(char const* const program_name, void const* const addr) {
|
||||
char addr2line_cmd[512] = { 0 };
|
||||
|
||||
sprintf(addr2line_cmd, "addr2line -f -p -e %.256s %p", program_name, addr);
|
||||
|
||||
fprintf(stderr, "%d: ", stack_nbr++);
|
||||
return system(addr2line_cmd);
|
||||
}
|
||||
|
||||
void print_stacktrace(CONTEXT* context) {
|
||||
|
||||
SymInitialize(GetCurrentProcess(), 0, true);
|
||||
|
||||
STACKFRAME frame = { 0 };
|
||||
|
||||
/* setup initial stack frame */
|
||||
frame.AddrPC.Offset = context->Eip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context->Esp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context->Ebp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
|
||||
while (StackWalk(IMAGE_FILE_MACHINE_I386,
|
||||
GetCurrentProcess(),
|
||||
GetCurrentThread(),
|
||||
&frame,
|
||||
context,
|
||||
0,
|
||||
SymFunctionTableAccess,
|
||||
SymGetModuleBase,
|
||||
0)) {
|
||||
addr2line(_program_name, (void*)frame.AddrPC.Offset);
|
||||
}
|
||||
|
||||
SymCleanup(GetCurrentProcess());
|
||||
}
|
||||
|
||||
LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS* ExceptionInfo) {
|
||||
switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
fputs("Error: EXCEPTION_ACCESS_VIOLATION\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
fputs("Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
fputs("Error: EXCEPTION_BREAKPOINT\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
fputs("Error: EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_FLT_DENORMAL_OPERAND:
|
||||
fputs("Error: EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
fputs("Error: EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_FLT_INEXACT_RESULT:
|
||||
fputs("Error: EXCEPTION_FLT_INEXACT_RESULT\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_FLT_INVALID_OPERATION:
|
||||
fputs("Error: EXCEPTION_FLT_INVALID_OPERATION\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_FLT_OVERFLOW:
|
||||
fputs("Error: EXCEPTION_FLT_OVERFLOW\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_FLT_STACK_CHECK:
|
||||
fputs("Error: EXCEPTION_FLT_STACK_CHECK\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_FLT_UNDERFLOW:
|
||||
fputs("Error: EXCEPTION_FLT_UNDERFLOW\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
fputs("Error: EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
fputs("Error: EXCEPTION_IN_PAGE_ERROR\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
fputs("Error: EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_INT_OVERFLOW:
|
||||
fputs("Error: EXCEPTION_INT_OVERFLOW\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_INVALID_DISPOSITION:
|
||||
fputs("Error: EXCEPTION_INVALID_DISPOSITION\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
|
||||
fputs("Error: EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
fputs("Error: EXCEPTION_PRIV_INSTRUCTION\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_SINGLE_STEP:
|
||||
fputs("Error: EXCEPTION_SINGLE_STEP\n", stderr);
|
||||
break;
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
fputs("Error: EXCEPTION_STACK_OVERFLOW\n", stderr);
|
||||
break;
|
||||
default:
|
||||
fputs("Error: Unrecognized Exception\n", stderr);
|
||||
break;
|
||||
}
|
||||
fflush(stderr);
|
||||
/* If this is a stack overflow then we can't walk the stack, so just show
|
||||
where the error happened */
|
||||
if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) {
|
||||
print_stacktrace(ExceptionInfo->ContextRecord);
|
||||
} else {
|
||||
addr2line(_program_name, (void*)ExceptionInfo->ContextRecord->Eip);
|
||||
}
|
||||
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
void OS_InstallSignalHandler(char* program_name) {
|
||||
strcpy(_program_name, program_name);
|
||||
SetUnhandledExceptionFilter(windows_exception_handler);
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef HARNESS_PLATFORM_H
|
||||
#define HARNESS_PLATFORM_H
|
||||
|
||||
int PlatformIsDebuggerPresent(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
#include "platforms/platform.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define TRACER_PID_STRING "TracerPid:"
|
||||
|
||||
int PlatformIsDebuggerPresent() {
|
||||
char buf[4096];
|
||||
int status_fd;
|
||||
ssize_t num_read;
|
||||
char* tracer_pid_ptr;
|
||||
char* char_ptr;
|
||||
|
||||
status_fd = open("/proc/self/status", O_RDONLY);
|
||||
if (status_fd == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
num_read = read(status_fd, buf, sizeof(buf) - 1);
|
||||
close(status_fd);
|
||||
if (num_read <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf[num_read] = '\0';
|
||||
tracer_pid_ptr = strstr(buf, TRACER_PID_STRING);
|
||||
if (tracer_pid_ptr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (char_ptr = tracer_pid_ptr + sizeof(TRACER_PID_STRING) - 1; char_ptr <= buf + num_read; ++char_ptr)
|
||||
{
|
||||
if (isspace(*char_ptr)) {
|
||||
continue;
|
||||
} else {
|
||||
return isdigit(*char_ptr) != 0 && *char_ptr != '0';
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
|
||||
// https://developer.apple.com/library/archive/qa/qa1361/_index.html
|
||||
// FIXME:
|
||||
// Important: Because the definition of the kinfo_proc structure (in <sys/sysctl.h>) is conditionalized by __APPLE_API_UNSTABLE,
|
||||
// you should restrict use of the above code to the debug build of your program.
|
||||
|
||||
int PlatformIsDebuggerPresent()
|
||||
// Returns true if the current process is being debugged (either
|
||||
// running under the debugger or has a debugger attached post facto).
|
||||
{
|
||||
int junk;
|
||||
int mib[4];
|
||||
struct kinfo_proc info;
|
||||
size_t size;
|
||||
|
||||
// Initialize the flags so that, if sysctl fails for some bizarre
|
||||
// reason, we get a predictable result.
|
||||
|
||||
info.kp_proc.p_flag = 0;
|
||||
|
||||
// Initialize mib, which tells sysctl the info we want, in this case
|
||||
// we're looking for information about a specific process ID.
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = getpid();
|
||||
|
||||
// Call sysctl.
|
||||
|
||||
size = sizeof(info);
|
||||
junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
|
||||
assert(junk == 0);
|
||||
|
||||
// We're being debugged if the P_TRACED flag is set.
|
||||
|
||||
return ((info.kp_proc.p_flag & P_TRACED) != 0);
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#include <windows.h>
|
||||
|
||||
int PlatformIsDebuggerPresent() {
|
||||
return IsDebuggerPresent();
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#ifndef SDL_GL_PLATFORM_H
|
||||
#define SDL_GL_PLATFORM_H
|
||||
|
||||
#include "harness.h"
|
||||
#include "sdl/common.h"
|
||||
#include "sdl/gl_renderer.h"
|
||||
|
||||
tPlatform sdl_gl_platform = {
|
||||
SDLPlatform_Init,
|
||||
GLRenderer_CreateWindow,
|
||||
SDLPlatform_PollEvents,
|
||||
SDLPlatform_GetKeyMap,
|
||||
SDLPlatform_IsKeyDown,
|
||||
GLRenderer_BeginScene,
|
||||
GLRenderer_EndScene,
|
||||
GLRenderer_SetPalette,
|
||||
GLRenderer_RenderFullScreenQuad,
|
||||
GLRenderer_RenderModel,
|
||||
GLRenderer_Swap,
|
||||
GLRenderer_BufferTexture,
|
||||
GLRenderer_BufferMaterial,
|
||||
GLRenderer_FlushBuffers
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,20 +1,15 @@
|
|||
#include "gl_renderer.h"
|
||||
#include "brender/brender.h"
|
||||
#include "cameras/debug_camera.h"
|
||||
#include "gl_brender_stored_context.h"
|
||||
#include "gl_renderer_shaders.h"
|
||||
#include "harness.h"
|
||||
#include "harness/trace.h"
|
||||
#include "platforms/platform.h"
|
||||
#include "shaders.h"
|
||||
#include "stored_context.h"
|
||||
|
||||
#include <cglm/cglm.h>
|
||||
#include <glad/glad.h>
|
||||
#include <string.h>
|
||||
|
||||
// this needs to be included after glad.h
|
||||
#include <SDL_opengl.h>
|
||||
|
||||
SDL_Window* window;
|
||||
SDL_GLContext context;
|
||||
GLuint screen_buffer_vao, screen_buffer_ebo;
|
||||
GLuint screen_texture, palette_texture, depth_texture;
|
||||
|
||||
|
|
@ -178,18 +173,12 @@ void SetupFullScreenRectGeometry() {
|
|||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void InitializeOpenGLContext() {
|
||||
void GLRenderer_Init(int width, int height, int pRender_width, int pRender_height) {
|
||||
|
||||
context = SDL_GL_CreateContext(window);
|
||||
if (!context) {
|
||||
LOG_PANIC("Failed to call SDL_GL_CreateContext. %s", SDL_GetError());
|
||||
}
|
||||
|
||||
// Load GL extensions using glad
|
||||
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
|
||||
LOG_PANIC("Failed to initialize the OpenGL context with GLAD.");
|
||||
exit(1);
|
||||
}
|
||||
window_width = width;
|
||||
window_height = height;
|
||||
render_width = pRender_width;
|
||||
render_height = pRender_height;
|
||||
|
||||
int maxTextureImageUnits;
|
||||
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureImageUnits);
|
||||
|
|
@ -235,48 +224,10 @@ void InitializeOpenGLContext() {
|
|||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
CHECK_GL_ERROR("initializeOpenGLContext");
|
||||
}
|
||||
|
||||
void GLRenderer_CreateWindow(char* title, int width, int height, int pRender_width, int pRender_height) {
|
||||
window_width = width;
|
||||
window_height = height;
|
||||
render_width = pRender_width;
|
||||
render_height = pRender_height;
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||
LOG_PANIC("SDL_INIT_VIDEO error: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE) != 0) {
|
||||
LOG_PANIC("Failed to set SDL_GL_CONTEXT_PROFILE_MASK attribute. %s", SDL_GetError());
|
||||
};
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
|
||||
window = SDL_CreateWindow(title,
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
width, height,
|
||||
SDL_WINDOW_OPENGL);
|
||||
|
||||
if (!window) {
|
||||
LOG_PANIC("Failed to create window");
|
||||
}
|
||||
|
||||
// Don't grab the mouse when a debugger is present
|
||||
if (!PlatformIsDebuggerPresent()) {
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
}
|
||||
|
||||
// SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN);
|
||||
|
||||
InitializeOpenGLContext();
|
||||
|
||||
screen_buffer_flip_pixels = malloc(sizeof(uint8_t) * render_width * render_height);
|
||||
depth_buffer_flip_pixels = malloc(sizeof(uint16_t) * render_width * render_height);
|
||||
|
||||
CHECK_GL_ERROR("initializeOpenGLContext");
|
||||
}
|
||||
|
||||
void GLRenderer_SetPalette(uint8_t* rgba_colors) {
|
||||
|
|
@ -374,7 +325,7 @@ void GLRenderer_EndScene() {
|
|||
CHECK_GL_ERROR("GLRenderer_RenderFullScreenQuad");
|
||||
}
|
||||
|
||||
void GLRenderer_RenderFullScreenQuad(uint8_t* screen_buffer, int width, int height) {
|
||||
void GLRenderer_FullScreenQuad(uint8_t* screen_buffer, int width, int height) {
|
||||
glViewport(0, 0, window_width, window_height);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
|
@ -392,8 +343,7 @@ void GLRenderer_RenderFullScreenQuad(uint8_t* screen_buffer, int width, int heig
|
|||
CHECK_GL_ERROR("GLRenderer_RenderFullScreenQuad");
|
||||
}
|
||||
|
||||
void GLRenderer_Swap() {
|
||||
SDL_GL_SwapWindow(window);
|
||||
void GLRenderer_ClearBuffers() {
|
||||
// clear our virtual framebuffer
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id);
|
||||
|
|
@ -407,6 +357,8 @@ void build_model(br_model* model) {
|
|||
tStored_model_context* ctx;
|
||||
v11model* v11;
|
||||
|
||||
LOG_DEBUG("called %s", model->identifier);
|
||||
|
||||
v11 = model->prepared;
|
||||
ctx = NewStoredModelContext();
|
||||
|
||||
|
|
@ -469,13 +421,12 @@ void build_model(br_model* model) {
|
|||
}
|
||||
|
||||
glGenVertexArrays(1, &ctx->vao_id);
|
||||
GLuint vbo_id;
|
||||
glGenBuffers(1, &vbo_id);
|
||||
glGenBuffers(1, &ctx->vbo_id);
|
||||
glGenBuffers(1, &ctx->ebo_id);
|
||||
|
||||
// Vertices }
|
||||
// Vertices
|
||||
glBindVertexArray(ctx->vao_id);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ctx->vbo_id);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(fmt_vertex) * total_verts, verts, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(fmt_vertex), (void*)offsetof(fmt_vertex, p));
|
||||
glEnableVertexAttribArray(0);
|
||||
|
|
@ -491,6 +442,7 @@ void build_model(br_model* model) {
|
|||
|
||||
free(verts);
|
||||
free(indices);
|
||||
|
||||
model->stored = ctx;
|
||||
|
||||
CHECK_GL_ERROR("after build model");
|
||||
|
|
@ -519,7 +471,7 @@ void setActiveMaterial(tStored_material* material) {
|
|||
}
|
||||
}
|
||||
|
||||
void GLRenderer_RenderModel(br_actor* actor, br_model* model, br_matrix34 model_matrix) {
|
||||
void GLRenderer_Model(br_actor* actor, br_model* model, br_matrix34 model_matrix) {
|
||||
tStored_model_context* ctx;
|
||||
ctx = model->stored;
|
||||
v11model* v11 = model->prepared;
|
||||
|
|
@ -533,6 +485,7 @@ void GLRenderer_RenderModel(br_actor* actor, br_model* model, br_matrix34 model_
|
|||
if (ctx == NULL) {
|
||||
build_model(model);
|
||||
ctx = model->stored;
|
||||
|
||||
// DebugCamera_SetPosition(model_matrix.m[3][0], model_matrix.m[3][1], model_matrix.m[3][2]);
|
||||
}
|
||||
CHECK_GL_ERROR("rm1");
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
#define HARNESS_GL_RENDERER
|
||||
|
||||
#include "harness.h"
|
||||
#include <SDL.h>
|
||||
|
||||
#define CHECK_GL_ERROR(msg) \
|
||||
{ \
|
||||
|
|
@ -12,15 +11,15 @@
|
|||
} \
|
||||
}
|
||||
|
||||
void GLRenderer_CreateWindow(char* title, int width, int height, int render_width, int render_height);
|
||||
void GLRenderer_Init(int width, int height, int render_width, int render_height);
|
||||
void GLRenderer_SetPalette(uint8_t* rgba_colors);
|
||||
void GLRenderer_BeginScene(br_actor* camera, br_pixelmap* colour_buffer);
|
||||
void GLRenderer_EndScene();
|
||||
void GLRenderer_RenderFullScreenQuad(uint8_t* screen_buffer, int width, int height);
|
||||
void GLRenderer_Swap();
|
||||
void GLRenderer_RenderModel(br_actor* actor, br_model* model, br_matrix34 model_matrix);
|
||||
void GLRenderer_FullScreenQuad(uint8_t* screen_buffer, int width, int height);
|
||||
void GLRenderer_Model(br_actor* actor, br_model* model, br_matrix34 model_matrix);
|
||||
void GLRenderer_BufferTexture(br_pixelmap* pm);
|
||||
void GLRenderer_BufferMaterial(br_material* mat);
|
||||
void GLRenderer_ClearBuffers();
|
||||
void GLRenderer_FlushBuffers(br_pixelmap* color_buffer, br_pixelmap* depth_buffer);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
#include "gl_brender_stored_context.h"
|
||||
#include "stored_context.h"
|
||||
#include "../include/harness/trace.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void _free(br_object* o) {
|
||||
tStored_model_context* ctx = (tStored_model_context*)o;
|
||||
glDeleteVertexArrays(1, &ctx->vao_id);
|
||||
glDeleteBuffers(1, &ctx->vbo_id);
|
||||
glDeleteBuffers(1, &ctx->ebo_id);
|
||||
free(o);
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
typedef struct tStored_model_context {
|
||||
br_object_dispatch* dispatch;
|
||||
GLuint vao_id, ebo_id;
|
||||
GLuint vao_id, vbo_id, ebo_id;
|
||||
} tStored_model_context;
|
||||
|
||||
typedef struct tStored_pixelmap {
|
||||
|
|
@ -1,33 +1,25 @@
|
|||
#include "harness.h"
|
||||
#include "renderer.h"
|
||||
|
||||
void Null_Init() {}
|
||||
void Null_CreateWindow(char* title, int width, int height, int render_width, int render_height) {}
|
||||
void Null_PollEvents() {}
|
||||
int* Null_GetKeyMap() { return NULL; }
|
||||
int Null_IsKeyDown(unsigned char pScan_code) { return 0; }
|
||||
void Null_BeginFrame(br_actor* camera, br_pixelmap* colour_buffer) {}
|
||||
void Null_EndFrame() {}
|
||||
void Null_SetPalette(uint8_t* palette) {}
|
||||
void Null_RenderFullScreenQuad(uint8_t* src, int width, int height) {}
|
||||
void Null_RenderModel(br_actor* actor, br_model* model, br_matrix34 model_matrix) {}
|
||||
void Null_RenderFrameBuffer() {}
|
||||
void Null_Swap() {}
|
||||
void Null_ClearBuffers() {}
|
||||
void Null_BufferTexture(br_pixelmap* pm) {}
|
||||
void Null_BufferMaterial(br_material* mat) {}
|
||||
void Null_FlushBuffers(br_pixelmap* color_buffer, br_pixelmap* depth_buffer) {}
|
||||
|
||||
tPlatform null_platform = {
|
||||
tRenderer null_renderer = {
|
||||
Null_Init,
|
||||
Null_CreateWindow,
|
||||
Null_PollEvents,
|
||||
Null_GetKeyMap,
|
||||
Null_IsKeyDown,
|
||||
Null_BeginFrame,
|
||||
Null_EndFrame,
|
||||
Null_SetPalette,
|
||||
Null_RenderFullScreenQuad,
|
||||
Null_RenderModel,
|
||||
Null_Swap,
|
||||
Null_ClearBuffers,
|
||||
Null_BufferTexture,
|
||||
Null_BufferMaterial,
|
||||
Null_FlushBuffers
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef HARNESS_RENDERER_H
|
||||
#define HARNESS_RENDERER_H
|
||||
|
||||
#include "brender/br_types.h"
|
||||
|
||||
typedef struct tRenderer {
|
||||
void (*Init)(int width, int height, int pRender_width, int pRender_height);
|
||||
void (*BeginScene)(br_actor* camera, br_pixelmap* colour_buffer);
|
||||
void (*EndScene)();
|
||||
void (*SetPalette)(uint8_t* palette);
|
||||
void (*FullScreenQuad)(uint8_t* src, int width, int height);
|
||||
void (*Model)(br_actor* actor, br_model* model, br_matrix34 model_matrix);
|
||||
void (*ClearBuffers)();
|
||||
void (*BufferTexture)(br_pixelmap* pm);
|
||||
void (*BufferMaterial)(br_material* mat);
|
||||
void (*FlushBuffers)(br_pixelmap* color_buffer, br_pixelmap* depth_buffer);
|
||||
|
||||
} tRenderer;
|
||||
|
||||
#endif
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef SDL_PLATFORM_H
|
||||
#define SDL_PLATFORM_H
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void SDLPlatform_Init();
|
||||
void SDLPlatform_PollEvents();
|
||||
int* SDLPlatform_GetKeyMap();
|
||||
int SDLPlatform_IsKeyDown(unsigned char scan_code);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
add_executable(dethrace_test)
|
||||
add_test(NAME test_dethrace COMMAND dethrace_test)
|
||||
|
||||
set(IO_PLATFORM "SDL_OpenGL")
|
||||
|
||||
target_link_libraries(dethrace_test PRIVATE glad dethrace_obj)
|
||||
|
||||
target_include_directories(dethrace_test PRIVATE
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tests.h"
|
||||
|
||||
|
|
@ -24,7 +23,7 @@ void test_controls_CheckKevKeys() {
|
|||
gKeys_pressed = 0;
|
||||
result = KevKeyService();
|
||||
}
|
||||
sleep_s(2);
|
||||
OS_Sleep(2000);
|
||||
gKeys_pressed = 0;
|
||||
|
||||
CheckKevKeys();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#include "tests.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/globvars.h"
|
||||
#include "pd/sys.h"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include <string.h>
|
||||
|
||||
void test_errors_FatalError() {
|
||||
FatalError(0x6c, "test_errors", "FATAL");
|
||||
FatalError(107, "test_errors", "FATAL");
|
||||
TEST_ASSERT_EQUAL_STRING("Can't open 'test_errors'", _unittest_last_fatal_error);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#include "common/globvars.h"
|
||||
#include "common/input.h"
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void test_input_KevKeyService() {
|
||||
int i;
|
||||
|
|
@ -15,7 +14,7 @@ void test_input_KevKeyService() {
|
|||
gKeys_pressed = 0;
|
||||
result = KevKeyService();
|
||||
}
|
||||
sleep_s(2);
|
||||
OS_Sleep(2000);
|
||||
gKeys_pressed = 0;
|
||||
result = KevKeyService();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#include "tests.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "CORE/PIXELMAP/pixelmap.h"
|
||||
#include "common/globvars.h"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#include "tests.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/globvars.h"
|
||||
#include "common/powerup.h"
|
||||
|
|
|
|||
16
test/main.c
16
test/main.c
|
|
@ -1,4 +1,5 @@
|
|||
#include "harness/hooks.h"
|
||||
#include "harness/os.h"
|
||||
#include "tests.h"
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -6,7 +7,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define UNITY_USE_COMMAND_LINE_ARGS 1
|
||||
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
#include "CORE/PIXELMAP/pixelmap.h"
|
||||
#include "CORE/V1DB/actsupt.h"
|
||||
#include "CORE/V1DB/dbsetup.h"
|
||||
#include "common/errors.h"
|
||||
#include "common/newgame.h"
|
||||
#include "common/utility.h"
|
||||
|
||||
|
|
@ -23,6 +24,7 @@
|
|||
#include "common/grafdata.h"
|
||||
#include "harness.h"
|
||||
#include "harness/config.h"
|
||||
#include "harness/os.h"
|
||||
|
||||
#define debug(format_, ...) fprintf(stderr, format_, __VA_ARGS__)
|
||||
|
||||
|
|
@ -167,6 +169,8 @@ void setup_global_vars(int argc, char* argv[]) {
|
|||
|
||||
strcpy(gBasic_car_names[0], "BLKEAGLE.TXT");
|
||||
|
||||
OpenDiagnostics();
|
||||
|
||||
setup_temp_folder();
|
||||
printf("INFO: temp folder is \"%s\"\n", temp_folder);
|
||||
|
||||
|
|
@ -182,20 +186,14 @@ void setup_global_vars(int argc, char* argv[]) {
|
|||
fake_argv[fake_argc++] = "--no-signal-handler";
|
||||
}
|
||||
Harness_Init(&fake_argc, fake_argv);
|
||||
|
||||
Harness_ForceNullRenderer();
|
||||
}
|
||||
|
||||
int has_data_directory() {
|
||||
return root_dir != NULL;
|
||||
}
|
||||
|
||||
void sleep_s(int sec) {
|
||||
#ifdef _WIN32
|
||||
Sleep(1000 * sec);
|
||||
#else
|
||||
sleep(sec);
|
||||
#endif
|
||||
}
|
||||
|
||||
void create_temp_file(char buffer[PATH_MAX + 1], const char* prefix) {
|
||||
#ifdef _WIN32
|
||||
DWORD attributes;
|
||||
|
|
|
|||
23
test/tests.h
23
test/tests.h
|
|
@ -2,6 +2,7 @@
|
|||
#define TESTS_H
|
||||
|
||||
#include "framework/unity.h"
|
||||
#include "harness/os.h"
|
||||
#include "harness/trace.h"
|
||||
|
||||
#ifndef PATH_MAX
|
||||
|
|
@ -14,23 +15,23 @@
|
|||
#define HOST_NL "\n"
|
||||
#endif
|
||||
|
||||
void TEST_ASSERT_EQUAL_FILE_CONTENTS_BINARY(const uint8_t *expected, char *filename, int len);
|
||||
void TEST_ASSERT_EQUAL_FILE_TEXT(const char *expected, char *filename);
|
||||
void TEST_ASSERT_EQUAL_FILE_CONTENTS_BINARY(const uint8_t* expected, char* filename, int len);
|
||||
void TEST_ASSERT_EQUAL_FILE_TEXT(const char* expected, char* filename);
|
||||
|
||||
extern int has_data_directory();
|
||||
extern void sleep_s(int sec);
|
||||
void create_temp_file(char buffer[PATH_MAX+1], const char *prefix);
|
||||
void create_temp_file(char buffer[PATH_MAX + 1], const char* prefix);
|
||||
|
||||
#define REQUIRES_DATA_DIRECTORY() \
|
||||
if (!has_data_directory()) \
|
||||
TEST_IGNORE();
|
||||
|
||||
#define TEST_ASSERT_FLOAT_ARRAY_WITHIN(delta, expected, actual, num_elements) do { \
|
||||
float *priv_expected = (float*)(expected); \
|
||||
float *priv_actual = (float*)(actual); \
|
||||
for(int it = (num_elements); it != 0; --it, ++priv_expected, ++priv_actual) { \
|
||||
TEST_ASSERT_FLOAT_WITHIN((delta), *priv_expected, *priv_actual); \
|
||||
} \
|
||||
} while (0)
|
||||
#define TEST_ASSERT_FLOAT_ARRAY_WITHIN(delta, expected, actual, num_elements) \
|
||||
do { \
|
||||
float* priv_expected = (float*)(expected); \
|
||||
float* priv_actual = (float*)(actual); \
|
||||
for (int it = (num_elements); it != 0; --it, ++priv_expected, ++priv_actual) { \
|
||||
TEST_ASSERT_FLOAT_WITHIN((delta), *priv_expected, *priv_actual); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue