Add PS3 target

This commit is contained in:
libretroadmin 2023-02-20 20:58:00 +01:00
parent 1351a4fe2c
commit 0e8fbd2000
28 changed files with 2532 additions and 2060 deletions

View File

@ -63,15 +63,18 @@ include:
file: '/ios9.yml'
################################## CONSOLES ################################
# PlayStation 2
- project: 'libretro-infrastructure/ci-templates'
file: '/ps2-static.yml'
# PlayStation3
- project: 'libretro-infrastructure/ci-templates'
file: '/psl1ght-static.yml'
# PlayStation Vita
- project: 'libretro-infrastructure/ci-templates'
file: '/vita-static.yml'
# PlayStation 2
- project: 'libretro-infrastructure/ci-templates'
file: '/ps2-static.yml'
# Nintendo 3DS
- project: 'libretro-infrastructure/ci-templates'
file: '/ctr-static.yml'
@ -215,18 +218,24 @@ libretro-build-tvos-arm64:
- .core-defs
################################### CONSOLES #################################
# PlayStation2
libretro-build-ps2:
extends:
- .libretro-ps2-static-retroarch-master
- .core-defs
# PlayStation3
libretro-build-psl1ght:
extends:
- .libretro-psl1ght-static-retroarch-master
- .core-defs
# PlayStation Vita
libretro-build-vita:
extends:
- .libretro-vita-static-retroarch-master
- .core-defs
# PlayStation 2
libretro-build-ps2:
extends:
- .libretro-ps2-static-retroarch-master
- .core-defs
# Nintendo 3DS
libretro-build-ctr:
extends:

View File

@ -60,10 +60,3 @@ size_t strlcat(char *dest, const char *source, size_t size)
return len + strlcpy(dest, source, size);
}
#endif
char *strldup(const char *s, size_t n)
{
char *dst = (char*)malloc(sizeof(char) * (n + 1));
strlcpy(dst, s, n);
return dst;
}

View File

@ -37,27 +37,28 @@
void *fopen_utf8(const char * filename, const char * mode)
{
#if defined(LEGACY_WIN32)
FILE *ret = NULL;
char * filename_local = utf8_to_local_string_alloc(filename);
if (!filename_local)
return NULL;
ret = fopen(filename_local, mode);
if (filename_local)
{
FILE *ret = fopen(filename_local, mode);
free(filename_local);
return ret;
return ret;
}
#else
wchar_t * filename_w = utf8_to_utf16_string_alloc(filename);
wchar_t * mode_w = utf8_to_utf16_string_alloc(mode);
FILE* ret = NULL;
if (filename_w && mode_w)
ret = _wfopen(filename_w, mode_w);
wchar_t * filename_w = utf8_to_utf16_string_alloc(filename);
if (filename_w)
{
FILE *ret = NULL;
wchar_t *mode_w = utf8_to_utf16_string_alloc(mode);
if (mode_w)
{
ret = _wfopen(filename_w, mode_w);
free(mode_w);
}
free(filename_w);
if (mode_w)
free(mode_w);
return ret;
return ret;
}
#endif
return NULL;
}
#endif

View File

@ -23,7 +23,6 @@
#include <stdint.h>
#include <stddef.h>
#include <encodings/crc32.h>
#include <streams/file_stream.h>
#include <stdlib.h>
static const uint32_t crc32_table[256] = {
@ -90,51 +89,3 @@ uint32_t encoding_crc32(uint32_t crc, const uint8_t *buf, size_t len)
return crc ^ 0xffffffff;
}
#define CRC32_BUFFER_SIZE 1048576
#define CRC32_MAX_MB 64
/**
* Calculate a CRC32 from the first part of the given file.
* "first part" being the first (CRC32_BUFFER_SIZE * CRC32_MAX_MB)
* bytes.
*
* Returns: the crc32, or 0 if there was an error.
*/
uint32_t file_crc32(uint32_t crc, const char *path)
{
unsigned i;
RFILE *file = NULL;
unsigned char *buf = NULL;
if (!path)
return 0;
file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0);
if (!file)
goto error;
buf = (unsigned char*)malloc(CRC32_BUFFER_SIZE);
if (!buf)
goto error;
for (i = 0; i < CRC32_MAX_MB; i++)
{
int64_t nread = filestream_read(file, buf, CRC32_BUFFER_SIZE);
if (nread < 0)
goto error;
crc = encoding_crc32(crc, buf, (size_t)nread);
if (filestream_eof(file))
break;
}
free(buf);
filestream_close(file);
return crc;
error:
if (buf)
free(buf);
if (file)
filestream_close(file);
return 0;
}

View File

@ -51,9 +51,12 @@ static unsigned leading_ones(uint8_t c)
return ones;
}
/* Simple implementation. Assumes the sequence is
* properly synchronized and terminated. */
/**
* utf8_conv_utf32:
*
* Simple implementation. Assumes the sequence is
* properly synchronized and terminated.
**/
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
const char *in, size_t in_size)
{
@ -79,7 +82,7 @@ size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
for (i = 0; i < extra; i++, in++, shift -= 6)
c |= (*in & 0x3f) << shift;
*out++ = c;
*out++ = c;
in_size -= 1 + extra;
out_chars--;
ret++;
@ -88,6 +91,11 @@ size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
return ret;
}
/**
* utf16_conv_utf8:
*
* Leaf function.
**/
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
const uint16_t *in, size_t in_size)
{
@ -148,16 +156,20 @@ bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
return false;
}
/* Acts mostly like strlcpy.
/**
* utf8cpy:
*
* Acts mostly like strlcpy.
*
* Copies the given number of UTF-8 characters,
* but at most d_len bytes.
* but at most @d_len bytes.
*
* Always NULL terminates.
* Does not copy half a character.
* Always NULL terminates. Does not copy half a character.
* @s is assumed valid UTF-8.
* Use only if @chars is considerably less than @d_len.
*
* Returns number of bytes. 's' is assumed valid UTF-8.
* Use only if 'chars' is considerably less than 'd_len'. */
* @return Number of bytes.
**/
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
{
const uint8_t *sb = (const uint8_t*)s;
@ -186,6 +198,11 @@ size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
return sb-sb_org;
}
/**
* utf8skip:
*
* Leaf function
**/
const char *utf8skip(const char *str, size_t chars)
{
const uint8_t *strb = (const uint8_t*)str;
@ -204,6 +221,11 @@ const char *utf8skip(const char *str, size_t chars)
return (const char*)strb;
}
/**
* utf8len:
*
* Leaf function.
**/
size_t utf8len(const char *string)
{
size_t ret = 0;
@ -220,7 +242,15 @@ size_t utf8len(const char *string)
return ret;
}
/* Does not validate the input, returns garbage if it's not UTF-8. */
/**
* utf8_walk:
*
* Does not validate the input.
*
* Leaf function.
*
* @return Returns garbage if it's not UTF-8.
**/
uint32_t utf8_walk(const char **string)
{
uint8_t first = UTF8_WALKBYTE(string);
@ -248,24 +278,23 @@ static bool utf16_to_char(uint8_t **utf_data,
size_t *dest_len, const uint16_t *in)
{
unsigned len = 0;
while (in[len] != '\0')
len++;
utf16_conv_utf8(NULL, dest_len, in, len);
*dest_len += 1;
*utf_data = (uint8_t*)malloc(*dest_len);
if (*utf_data == 0)
return false;
return utf16_conv_utf8(*utf_data, dest_len, in, len);
if ((*utf_data = (uint8_t*)malloc(*dest_len)) != 0)
return utf16_conv_utf8(*utf_data, dest_len, in, len);
return false;
}
/**
* utf16_to_char_string:
**/
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
{
size_t dest_len = 0;
uint8_t *utf16_data = NULL;
bool ret = utf16_to_char(&utf16_data, &dest_len, in);
size_t dest_len = 0;
uint8_t *utf16_data = NULL;
bool ret = utf16_to_char(&utf16_data, &dest_len, in);
if (ret)
{
@ -274,13 +303,17 @@ bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
}
free(utf16_data);
utf16_data = NULL;
utf16_data = NULL;
return ret;
}
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
/* Returned pointer MUST be freed by the caller if non-NULL. */
/**
* mb_to_mb_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
static char *mb_to_mb_string_alloc(const char *str,
enum CodePage cp_in, enum CodePage cp_out)
{
@ -300,10 +333,8 @@ static char *mb_to_mb_string_alloc(const char *str,
if (!path_buf_wide_len)
return strdup(str);
path_buf_wide = (wchar_t*)
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
if (path_buf_wide)
if ((path_buf_wide = (wchar_t*)
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t))))
{
MultiByteToWideChar(cp_in, 0,
str, -1, path_buf_wide, path_buf_wide_len);
@ -347,45 +378,49 @@ static char *mb_to_mb_string_alloc(const char *str,
}
#endif
/* Returned pointer MUST be freed by the caller if non-NULL. */
/**
* utf8_to_local_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
char* utf8_to_local_string_alloc(const char *str)
{
if (str && *str)
{
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
#else
/* assume string needs no modification if not on Windows */
return strdup(str);
return strdup(str); /* Assume string needs no modification if not on Windows */
#endif
}
return NULL;
}
/* Returned pointer MUST be freed by the caller if non-NULL. */
char* local_to_utf8_string_alloc(const char *str)
/**
* local_to_utf8_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
char *local_to_utf8_string_alloc(const char *str)
{
if (str && *str)
{
if (str && *str)
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
#else
/* assume string needs no modification if not on Windows */
return strdup(str);
return strdup(str); /* Assume string needs no modification if not on Windows */
#endif
}
return NULL;
return NULL;
}
/* Returned pointer MUST be freed by the caller if non-NULL. */
/**
* utf8_to_utf16_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
wchar_t* utf8_to_utf16_string_alloc(const char *str)
{
#ifdef _WIN32
int len = 0;
int out_len = 0;
#else
size_t len = 0;
size_t out_len = 0;
#endif
wchar_t *buf = NULL;
@ -393,63 +428,55 @@ wchar_t* utf8_to_utf16_string_alloc(const char *str)
return NULL;
#ifdef _WIN32
len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
if (len)
if ((len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)))
{
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
if (!buf)
if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
return NULL;
out_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len);
if ((MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len)) < 0)
{
free(buf);
return NULL;
}
}
else
{
/* fallback to ANSI codepage instead */
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
if (len)
/* Fallback to ANSI codepage instead */
if ((len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)))
{
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
if (!buf)
if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
return NULL;
out_len = MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len);
if ((MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len)) < 0)
{
free(buf);
return NULL;
}
}
}
if (out_len < 0)
{
free(buf);
return NULL;
}
#else
/* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
len = mbstowcs(NULL, str, 0) + 1;
if (len)
if ((len = mbstowcs(NULL, str, 0) + 1))
{
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
if (!buf)
if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
return NULL;
out_len = mbstowcs(buf, str, len);
}
if (out_len == (size_t)-1)
{
free(buf);
return NULL;
if ((mbstowcs(buf, str, len)) == (size_t)-1)
{
free(buf);
return NULL;
}
}
#endif
return buf;
}
/* Returned pointer MUST be freed by the caller if non-NULL. */
/**
* utf16_to_utf8_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
char* utf16_to_utf8_string_alloc(const wchar_t *str)
{
#ifdef _WIN32
@ -465,20 +492,17 @@ char* utf16_to_utf8_string_alloc(const wchar_t *str)
#ifdef _WIN32
{
UINT code_page = CP_UTF8;
len = WideCharToMultiByte(code_page,
0, str, -1, NULL, 0, NULL, NULL);
/* fallback to ANSI codepage instead */
if (!len)
if (!(len = WideCharToMultiByte(code_page,
0, str, -1, NULL, 0, NULL, NULL)))
{
code_page = CP_ACP;
len = WideCharToMultiByte(code_page,
0, str, -1, NULL, 0, NULL, NULL);
}
buf = (char*)calloc(len, sizeof(char));
if (!buf)
if (!(buf = (char*)calloc(len, sizeof(char))))
return NULL;
if (WideCharToMultiByte(code_page,
@ -491,13 +515,9 @@ char* utf16_to_utf8_string_alloc(const wchar_t *str)
#else
/* NOTE: For now, assume non-Windows platforms'
* locale is already UTF-8. */
len = wcstombs(NULL, str, 0) + 1;
if (len)
if ((len = wcstombs(NULL, str, 0) + 1))
{
buf = (char*)calloc(len, sizeof(char));
if (!buf)
if (!(buf = (char*)calloc(len, sizeof(char))))
return NULL;
if (wcstombs(buf, str, len) == (size_t)-1)

File diff suppressed because it is too large Load Diff

View File

@ -24,13 +24,11 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <sys/stat.h>
#include <boolean.h>
#include <file/file_path.h>
#include <retro_assert.h>
#include <compat/strl.h>
#include <compat/posix_string.h>
#include <retro_miscellaneous.h>
@ -74,7 +72,7 @@ int path_stat(const char *path)
*
* Checks if path is a directory.
*
* Returns: true (1) if path is a directory, otherwise false (0).
* @return true if path is a directory, otherwise false.
*/
bool path_is_directory(const char *path)
{
@ -105,8 +103,10 @@ int32_t path_get_size(const char *path)
* @dir : directory
*
* Create directory on filesystem.
*
* Recursive function.
*
* Returns: true (1) if directory could be created, otherwise false (0).
* @return true if directory could be created, otherwise false.
**/
bool path_mkdir(const char *dir)
{
@ -118,12 +118,10 @@ bool path_mkdir(const char *dir)
/* Use heap. Real chance of stack
* overflow if we recurse too hard. */
basedir = strdup(dir);
if (!(basedir = strdup(dir)))
return false;
if (!basedir)
return false;
path_parent_dir(basedir);
path_parent_dir(basedir, strlen(basedir));
if (!*basedir || !strcmp(basedir, dir))
{

View File

@ -165,6 +165,7 @@ extern int audioAddData(uint32_t portNum, float *data,
#define ioPadGetData cellPadGetData
#define ioPadInit cellPadInit
#define ioPadEnd cellPadEnd
#define ioPadSetPortSetting cellPadSetPortSetting
#endif
/*============================================================
@ -198,6 +199,13 @@ extern int audioAddData(uint32_t portNum, float *data,
#else
#include <cell/mouse.h>
#define mouseInfo CellMouseInfo
#define mouseData CellMouseData
#define ioMouseInit cellMouseInit
#define ioMouseGetData cellMouseGetData
#define ioMouseEnd cellMouseEnd
#define ioMouseGetInfo cellMouseGetInfo
#endif
#endif
@ -683,25 +691,56 @@ extern int audioAddData(uint32_t portNum, float *data,
#define FS_TYPE_DIR 1
#ifdef __PSL1GHT__
#include <lv2/sysfs.h>
#ifndef O_RDONLY
#define O_RDONLY SYS_O_RDONLY
#endif
#ifndef O_WRONLY
#define O_WRONLY SYS_O_WRONLY
#endif
#ifndef O_CREAT
#define O_CREAT SYS_O_CREAT
#endif
#ifndef O_TRUNC
#define O_TRUNC SYS_O_TRUNC
#endif
#ifndef O_RDWR
#define O_RDWR SYS_O_RDWR
#endif
#else
#include <cell/cell_fs.h>
#ifndef O_RDONLY
#define O_RDONLY CELL_FS_O_RDONLY
#endif
#ifndef O_WRONLY
#define O_WRONLY CELL_FS_O_WRONLY
#endif
#ifndef O_CREAT
#define O_CREAT CELL_FS_O_CREAT
#endif
#ifndef O_TRUNC
#define O_TRUNC CELL_FS_O_TRUNC
#endif
#ifndef O_RDWR
#define O_RDWR CELL_FS_O_RDWR
#endif
#ifndef sysFsStat
#define sysFsStat cellFsStat
#define sysFSStat CellFsStat
#endif
#ifndef sysFSDirent
#define sysFSDirent CellFsDirent
#endif
#ifndef sysFsOpendir
#define sysFsOpendir cellFsOpendir
#endif
#ifndef sysFsReaddir
#define sysFsReaddir cellFsReaddir
#endif
#ifndef sysFSDirent
#define sysFSDirent CellFsDirent
#endif
#ifndef sysFsClosedir
#define sysFsClosedir cellFsClosedir
#endif
#endif
#endif

View File

@ -38,29 +38,99 @@ enum CodePage
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
};
/**
* utf8_conv_utf32:
*
* Simple implementation. Assumes the sequence is
* properly synchronized and terminated.
**/
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
const char *in, size_t in_size);
/**
* utf16_conv_utf8:
*
* Leaf function.
**/
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
const uint16_t *in, size_t in_size);
/**
* utf8len:
*
* Leaf function.
**/
size_t utf8len(const char *string);
/**
* utf8cpy:
*
* Acts mostly like strlcpy.
*
* Copies the given number of UTF-8 characters,
* but at most @d_len bytes.
*
* Always NULL terminates. Does not copy half a character.
* @s is assumed valid UTF-8.
* Use only if @chars is considerably less than @d_len.
*
* Hidden non-leaf function cost:
* - Calls memcpy
*
* @return Number of bytes.
**/
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);
/**
* utf8skip:
*
* Leaf function
**/
const char *utf8skip(const char *str, size_t chars);
/**
* utf8_walk:
*
* Does not validate the input.
*
* Leaf function.
*
* @return Returns garbage if it's not UTF-8.
**/
uint32_t utf8_walk(const char **string);
/**
* utf16_to_char_string:
**/
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);
char* utf8_to_local_string_alloc(const char *str);
/**
* utf8_to_local_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
char *utf8_to_local_string_alloc(const char *str);
char* local_to_utf8_string_alloc(const char *str);
/**
* local_to_utf8_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
char *local_to_utf8_string_alloc(const char *str);
wchar_t* utf8_to_utf16_string_alloc(const char *str);
/**
* utf8_to_utf16_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
wchar_t *utf8_to_utf16_string_alloc(const char *str);
char* utf16_to_utf8_string_alloc(const wchar_t *str);
/**
* utf16_to_utf8_string_alloc:
*
* @return Returned pointer MUST be freed by the caller if non-NULL.
**/
char *utf16_to_utf8_string_alloc(const wchar_t *str);
RETRO_END_DECLS

View File

@ -51,6 +51,28 @@ enum
RARCH_FILE_UNSUPPORTED
};
struct path_linked_list
{
char *path;
struct path_linked_list *next;
};
/**
* Create a new linked list with one item in it
* The path on this item will be set to NULL
**/
struct path_linked_list* path_linked_list_new(void);
/* Free the entire linked list */
void path_linked_list_free(struct path_linked_list *in_path_linked_list);
/**
* Add a node to the linked list with this path
* If the first node's path if it's not yet set,
* set this instead
**/
void path_linked_list_add_path(struct path_linked_list *in_path_linked_list, char *path);
/**
* path_is_compressed_file:
* @path : path
@ -81,12 +103,12 @@ bool path_is_compressed_file(const char *path);
* path_get_archive_delim:
* @path : path
*
* Gets delimiter of an archive file. Only the first '#'
* Find delimiter of an archive file. Only the first '#'
* after a compression extension is considered.
*
* Returns: pointer to the delimiter in the path if it contains
* a compressed file, otherwise NULL.
*/
* @return pointer to the delimiter in the path if it contains
* a path inside a compressed file, otherwise NULL.
**/
const char *path_get_archive_delim(const char *path);
/**
@ -96,10 +118,28 @@ const char *path_get_archive_delim(const char *path);
* Gets extension of file. Only '.'s
* after the last slash are considered.
*
* Returns: extension part from the path.
*/
* Hidden non-leaf function cost:
* - calls string_is_empty()
* - calls strrchr
*
* @return extension part from the path.
**/
const char *path_get_extension(const char *path);
/**
* path_get_extension_mutable:
* @path : path
*
* Specialized version of path_get_extension(). Return
* value is mutable.
*
* Gets extension of file. Only '.'s
* after the last slash are considered.
*
* @return extension part from the path.
**/
char *path_get_extension_mutable(const char *path);
/**
* path_remove_extension:
* @path : path
@ -108,7 +148,10 @@ const char *path_get_extension(const char *path);
* text after and including the last '.'.
* Only '.'s after the last slash are considered.
*
* Returns:
* Hidden non-leaf function cost:
* - calls strrchr
*
* @return
* 1) If path has an extension, returns path with the
* extension removed.
* 2) If there is no extension, returns NULL.
@ -122,9 +165,26 @@ char *path_remove_extension(char *path);
*
* Get basename from @path.
*
* Returns: basename from path.
* Hidden non-leaf function cost:
* - Calls path_get_archive_delim()
* - can call find_last_slash() once if it returns NULL
*
* @return basename from path.
**/
const char *path_basename(const char *path);
/**
* path_basename_nocompression:
* @path : path
*
* Specialized version of path_basename().
* Get basename from @path.
*
* Hidden non-leaf function cost:
* - Calls find_last_slash()
*
* @return basename from path.
**/
const char *path_basename_nocompression(const char *path);
/**
@ -139,12 +199,13 @@ void path_basedir(char *path);
/**
* path_parent_dir:
* @path : path
* @len : length of @path
*
* Extracts parent directory by mutating path.
* Assumes that path is a directory. Keeps trailing '/'.
* If the path was already at the root directory, returns empty string
**/
void path_parent_dir(char *path);
void path_parent_dir(char *path, size_t len);
/**
* path_resolve_realpath:
@ -156,7 +217,7 @@ void path_parent_dir(char *path);
*
* Relative paths are rebased on the current working dir.
*
* Returns: @buf if successful, NULL otherwise.
* @return @buf if successful, NULL otherwise.
* Note: Not implemented on consoles
* Note: Symlinks are only resolved on Unix-likes
* Note: The current working dir might not be what you expect,
@ -178,8 +239,11 @@ char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks);
* Both @path and @base are assumed to be absolute paths without "." or "..".
*
* E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp
*
* @return Length of the string copied into @out
**/
size_t path_relative_to(char *out, const char *path, const char *base, size_t size);
size_t path_relative_to(char *out, const char *path, const char *base,
size_t size);
/**
* path_is_absolute:
@ -187,7 +251,7 @@ size_t path_relative_to(char *out, const char *path, const char *base, size_t si
*
* Checks if @path is an absolute path or a relative path.
*
* Returns: true if path is absolute, false if path is relative.
* @return true if path is absolute, false if path is relative.
**/
bool path_is_absolute(const char *path);
@ -211,8 +275,15 @@ bool path_is_absolute(const char *path);
* out_path = "/foo/bar/baz/boo.asm"
* E.g.: in_path = "/foo/bar/baz/boo.c", replace = "" =>
* out_path = "/foo/bar/baz/boo"
*
* Hidden non-leaf function cost:
* - calls strlcpy 2x
* - calls strrchr
* - calls strlcat
*
* @return Length of the string copied into @out
*/
void fill_pathname(char *out_path, const char *in_path,
size_t fill_pathname(char *out_path, const char *in_path,
const char *replace, size_t size);
/**
@ -226,6 +297,12 @@ void fill_pathname(char *out_path, const char *in_path,
*
* E.g.:
* out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
*
* Hidden non-leaf function cost:
* - Calls rtime_localtime()
* - Calls strftime
* - Calls strlcat
*
**/
size_t fill_dated_filename(char *out_filename,
const char *ext, size_t size);
@ -242,34 +319,33 @@ size_t fill_dated_filename(char *out_filename,
*
* E.g.:
* out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
*
* Hidden non-leaf function cost:
* - Calls time
* - Calls rtime_localtime()
* - Calls strlcpy
* - Calls string_is_empty()
* - Calls strftime
* - Calls strlcat at least 2x
*
* @return Length of the string copied into @out_path
**/
void fill_str_dated_filename(char *out_filename,
size_t fill_str_dated_filename(char *out_filename,
const char *in_str, const char *ext, size_t size);
/**
* fill_pathname_noext:
* @out_path : output path
* @in_path : input path
* @replace : what to replace
* @size : buffer size of output path
*
* Appends a filename extension 'replace' to 'in_path', and outputs
* result in 'out_path'.
*
* Assumes in_path has no extension. If an extension is still
* present in 'in_path', it will be ignored.
*
*/
size_t fill_pathname_noext(char *out_path, const char *in_path,
const char *replace, size_t size);
/**
* find_last_slash:
* @str : input path
* @str : path
* @size : size of path
*
* Gets a pointer to the last slash in the input path.
* Find last slash in path. Tries to find
* a backslash on Windows too which takes precedence
* over regular slash.
* Hidden non-leaf function cost:
* - calls strrchr
*
* Returns: a pointer to the last slash in the input path.
* @return pointer to last slash/backslash found in @str.
**/
char *find_last_slash(const char *str);
@ -289,6 +365,11 @@ char *find_last_slash(const char *str);
*
* E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
* replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
*
* Hidden non-leaf function cost:
* - Calls fill_pathname_slash()
* - Calls path_basename()
* - Calls strlcat 2x
**/
size_t fill_pathname_dir(char *in_dir, const char *in_basename,
const char *replace, size_t size);
@ -300,16 +381,15 @@ size_t fill_pathname_dir(char *in_dir, const char *in_basename,
* @size : size of output path
*
* Copies basename of @in_path into @out_path.
*
* Hidden non-leaf function cost:
* - Calls path_basename()
* - Calls strlcpy
*
* @return length of the string copied into @out
**/
size_t fill_pathname_base(char *out_path, const char *in_path, size_t size);
void fill_pathname_base_noext(char *out_dir,
const char *in_path, size_t size);
size_t fill_pathname_base_ext(char *out,
const char *in_path, const char *ext,
size_t size);
/**
* fill_pathname_basedir:
* @out_dir : output directory
@ -319,12 +399,13 @@ size_t fill_pathname_base_ext(char *out,
* Copies base directory of @in_path into @out_path.
* If in_path is a path without any slashes (relative current directory),
* @out_path will get path "./".
*
* Hidden non-leaf function cost:
* - Calls strlcpy
* - Calls path_basedir()
**/
void fill_pathname_basedir(char *out_path, const char *in_path, size_t size);
void fill_pathname_basedir_noext(char *out_dir,
const char *in_path, size_t size);
/**
* fill_pathname_parent_dir_name:
* @out_dir : output directory
@ -333,7 +414,13 @@ void fill_pathname_basedir_noext(char *out_dir,
*
* Copies only the parent directory name of @in_dir into @out_dir.
* The two buffers must not overlap. Removes trailing '/'.
* Returns true on success, false if a slash was not found in the path.
*
* Hidden non-leaf function cost:
* - Calls strdup
* - Calls find_last_slash() x times
* - Can call strlcpy
*
* @return true on success, false if a slash was not found in the path.
**/
bool fill_pathname_parent_dir_name(char *out_dir,
const char *in_dir, size_t size);
@ -347,6 +434,11 @@ bool fill_pathname_parent_dir_name(char *out_dir,
* Copies parent directory of @in_dir into @out_dir.
* Assumes @in_dir is a directory. Keeps trailing '/'.
* If the path was already at the root directory, @out_dir will be an empty string.
*
* Hidden non-leaf function cost:
* - Can call strlcpy if (@out_dir != @in_dir)
* - Calls strlen if (@out_dir == @in_dir)
* - Calls path_parent_dir()
**/
void fill_pathname_parent_dir(char *out_dir,
const char *in_dir, size_t size);
@ -374,30 +466,53 @@ void fill_pathname_resolve_relative(char *out_path, const char *in_refpath,
* @size : size of output path
*
* Joins a directory (@dir) and path (@path) together.
* Makes sure not to get two consecutive slashes
* Makes sure not to get two consecutive slashes
* between directory and path.
*
* Hidden non-leaf function cost:
* - calls strlcpy
* - calls fill_pathname_slash()
* - calls strlcat
*
* Deprecated. Use fill_pathname_join_special() instead
* if you can ensure @dir != @out_path
*
* @return Length of the string copied into @out_path
**/
size_t fill_pathname_join(char *out_path, const char *dir,
const char *path, size_t size);
/**
* fill_pathname_join_special:
* @out_path : output path
* @dir : directory. Cannot be identical to @out_path
* @path : path
* @size : size of output path
*
*
* Specialized version of fill_pathname_join.
* Unlike fill_pathname_join(),
* @dir and @out_path CANNOT be identical.
*
* Joins a directory (@dir) and path (@path) together.
* Makes sure not to get two consecutive slashes
* between directory and path.
*
* Hidden non-leaf function cost:
* - calls strlcpy
* - calls find_last_slash()
* - calls strlcat
*
* @return Length of the string copied into @out_path
**/
size_t fill_pathname_join_special(char *out_path,
const char *dir, const char *path, size_t size);
size_t fill_pathname_join_special_ext(char *out_path,
const char *dir, const char *path,
const char *last, const char *ext,
size_t size);
size_t fill_pathname_join_concat_noext(char *out_path,
const char *dir, const char *path,
const char *concat,
size_t size);
size_t fill_pathname_join_concat(char *out_path,
const char *dir, const char *path,
const char *concat,
size_t size);
void fill_pathname_join_noext(char *out_path,
const char *dir, const char *path, size_t size);
/**
* fill_pathname_join_delim:
* @out_path : output path
@ -408,45 +523,57 @@ void fill_pathname_join_noext(char *out_path,
*
* Joins a directory (@dir) and path (@path) together
* using the given delimiter (@delim).
*
* Hidden non-leaf function cost:
* - can call strlen
* - can call strlcpy
* - can call strlcat
**/
size_t fill_pathname_join_delim(char *out_path, const char *dir,
const char *path, const char delim, size_t size);
size_t fill_pathname_join_delim_concat(char *out_path, const char *dir,
const char *path, const char delim, const char *concat,
size_t size);
size_t fill_pathname_expand_special(char *out_path,
const char *in_path, size_t size);
size_t fill_pathname_abbreviate_special(char *out_path,
const char *in_path, size_t size);
/**
* fill_short_pathname_representation:
* @out_rep : output representation
* @in_path : input path
* @size : size of output representation
* fill_pathname_abbreviated_or_relative:
*
* Generates a short representation of path. It should only
* be used for displaying the result; the output representation is not
* binding in any meaningful way (for a normal path, this is the same as basename)
* In case of more complex URLs, this should cut everything except for
* the main image file.
* Fills the supplied path with either the abbreviated path or
* the relative path, which ever one has less depth / number of slashes
*
* If lengths of abbreviated and relative paths are the same,
* the relative path will be used
* @in_path can be an absolute, relative or abbreviated path
*
* E.g.: "/path/to/game.img" -> game.img
* "/path/to/myarchive.7z#folder/to/game.img" -> game.img
*/
size_t fill_short_pathname_representation(char* out_rep,
const char *in_path, size_t size);
void fill_short_pathname_representation_noext(char* out_rep,
const char *in_path, size_t size);
void fill_pathname_expand_special(char *out_path,
const char *in_path, size_t size);
void fill_pathname_abbreviate_special(char *out_path,
const char *in_path, size_t size);
void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size);
* @return Length of the string copied into @out_path
**/
size_t fill_pathname_abbreviated_or_relative(char *out_path,
const char *in_refpath, const char *in_path, size_t size);
/**
* pathname_conform_slashes_to_os:
*
* @path : path
*
* Leaf function.
*
* Changes the slashes to the correct kind for the os
* So forward slash on linux and backslash on Windows
**/
void pathname_conform_slashes_to_os(char *path);
/**
* pathname_make_slashes_portable:
* @path : path
*
* Leaf function.
*
* Change all slashes to forward so they are more
* portable between Windows and Linux
**/
void pathname_make_slashes_portable(char *path);
/**
@ -464,8 +591,8 @@ void path_basedir_wrapper(char *path);
*
* Checks if character (@c) is a slash.
*
* Returns: true (1) if character is a slash, otherwise false (0).
*/
* @return true if character is a slash, otherwise false.
**/
#ifdef _WIN32
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
#else
@ -477,8 +604,8 @@ void path_basedir_wrapper(char *path);
*
* Gets the default slash separator.
*
* Returns: default slash separator.
*/
* @return default slash separator.
**/
#ifdef _WIN32
#define PATH_DEFAULT_SLASH() "\\"
#define PATH_DEFAULT_SLASH_C() '\\'
@ -494,6 +621,11 @@ void path_basedir_wrapper(char *path);
*
* Assumes path is a directory. Appends a slash
* if not already there.
* Hidden non-leaf function cost:
* - calls find_last_slash()
* - can call strlcat once if it returns false
* - calls strlen
**/
void fill_pathname_slash(char *path, size_t size);
@ -509,7 +641,16 @@ void fill_pathname_home_dir(char *buf, size_t size);
*
* Create directory on filesystem.
*
* Returns: true (1) if directory could be created, otherwise false (0).
* Recursive function.
*
* Hidden non-leaf function cost:
* - Calls strdup
* - Calls path_parent_dir()
* - Calls strcmp
* - Calls path_is_directory()
* - Calls path_mkdir()
*
* @return true if directory could be created, otherwise false.
**/
bool path_mkdir(const char *dir);
@ -519,7 +660,7 @@ bool path_mkdir(const char *dir);
*
* Checks if path is a directory.
*
* Returns: true (1) if path is a directory, otherwise false (0).
* @return true if path is a directory, otherwise false.
*/
bool path_is_directory(const char *path);

View File

@ -31,6 +31,11 @@
#include <retro_inline.h>
#include <retro_math.h>
/**
* sinc:
*
* Pure function.
**/
static INLINE double sinc(double val)
{
if (fabs(val) < 0.00001)
@ -38,7 +43,12 @@ static INLINE double sinc(double val)
return sin(val) / val;
}
/* Paeth prediction filter. */
/**
* paeth:
*
* Pure function.
* Paeth prediction filter.
**/
static INLINE int paeth(int a, int b, int c)
{
int p = a + b - c;
@ -53,11 +63,17 @@ static INLINE int paeth(int a, int b, int c)
return c;
}
/* Modified Bessel function of first order.
* Check Wiki for mathematical definition ... */
/**
* besseli0:
*
* Pure function.
*
* Modified Bessel function of first order.
* Check Wiki for mathematical definition ...
**/
static INLINE double besseli0(double x)
{
unsigned i;
int i;
double sum = 0.0;
double factorial = 1.0;
double factorial_mult = 0.0;
@ -69,12 +85,11 @@ static INLINE double besseli0(double x)
* Luckily, it converges rather fast. */
for (i = 0; i < 18; i++)
{
sum += x_pow * two_div_pow / (factorial * factorial);
sum += x_pow * two_div_pow / (factorial * factorial);
factorial_mult += 1.0;
x_pow *= x_sqr;
two_div_pow *= 0.25;
factorial *= factorial_mult;
x_pow *= x_sqr;
two_div_pow *= 0.25;
factorial *= factorial_mult;
}
return sum;
@ -85,9 +100,4 @@ static INLINE double kaiser_window_function(double index, double beta)
return besseli0(beta * sqrtf(1 - index * index));
}
static INLINE double lanzcos_window_function(double index)
{
return sinc(M_PI * index);
}
#endif

View File

@ -69,7 +69,7 @@ extern "C" {
# endif
# endif
# else
# if defined(__GNUC__) && __GNUC__ >= 4 && !defined(__PS3__)
# if defined(__GNUC__) && __GNUC__ >= 4
# define RETRO_API RETRO_CALLCONV __attribute__((__visibility__("default")))
# else
# define RETRO_API RETRO_CALLCONV
@ -283,6 +283,14 @@ enum retro_language
RETRO_LANGUAGE_HEBREW = 21,
RETRO_LANGUAGE_ASTURIAN = 22,
RETRO_LANGUAGE_FINNISH = 23,
RETRO_LANGUAGE_INDONESIAN = 24,
RETRO_LANGUAGE_SWEDISH = 25,
RETRO_LANGUAGE_UKRAINIAN = 26,
RETRO_LANGUAGE_CZECH = 27,
RETRO_LANGUAGE_CATALAN_VALENCIA = 28,
RETRO_LANGUAGE_CATALAN = 29,
RETRO_LANGUAGE_BRITISH_ENGLISH = 30,
RETRO_LANGUAGE_HUNGARIAN = 31,
RETRO_LANGUAGE_LAST,
/* Ensure sizeof(enum) == sizeof(int) */
@ -1722,6 +1730,70 @@ enum retro_mod
* Must be called in retro_set_environment().
*/
#define RETRO_ENVIRONMENT_SET_VARIABLE 70
/* const struct retro_variable * --
* Allows an implementation to notify the frontend
* that a core option value has changed.
*
* retro_variable::key and retro_variable::value
* must match strings that have been set previously
* via one of the following:
*
* - RETRO_ENVIRONMENT_SET_VARIABLES
* - RETRO_ENVIRONMENT_SET_CORE_OPTIONS
* - RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
* - RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
* - RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
*
* After changing a core option value via this
* callback, RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
* will return true.
*
* If data is NULL, no changes will be registered
* and the callback will return true; an
* implementation may therefore pass NULL in order
* to test whether the callback is supported.
*/
#define RETRO_ENVIRONMENT_GET_THROTTLE_STATE (71 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* struct retro_throttle_state * --
* Allows an implementation to get details on the actual rate
* the frontend is attempting to call retro_run().
*/
#define RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT (72 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* int * --
* Tells the core about the context the frontend is asking for savestate.
* (see enum retro_savestate_context)
*/
#define RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT (73 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* struct retro_hw_render_context_negotiation_interface * --
* Before calling SET_HW_RNEDER_CONTEXT_NEGOTIATION_INTERFACE, a core can query
* which version of the interface is supported.
*
* Frontend looks at interface_type and returns the maximum supported
* context negotiation interface version.
* If the interface_type is not supported or recognized by the frontend, a version of 0
* must be returned in interface_version and true is returned by frontend.
*
* If this environment call returns true with interface_version greater than 0,
* a core can always use a negotiation interface version larger than what the frontend returns, but only
* earlier versions of the interface will be used by the frontend.
* A frontend must not reject a negotiation interface version that is larger than
* what the frontend supports. Instead, the frontend will use the older entry points that it recognizes.
* If this is incompatible with a particular core's requirements, it can error out early.
*
* Backwards compatibility note:
* This environment call was introduced after Vulkan v1 context negotiation.
* If this environment call is not supported by frontend - i.e. the environment call returns false -
* only Vulkan v1 context negotiation is supported (if Vulkan HW rendering is supported at all).
* If a core uses Vulkan negotiation interface with version > 1, negotiation may fail unexpectedly.
* All future updates to the context negotiation interface implies that frontend must support
* this environment call to query support.
*/
/* VFS functionality */
/* File paths:
@ -2959,6 +3031,35 @@ enum retro_pixel_format
RETRO_PIXEL_FORMAT_UNKNOWN = INT_MAX
};
enum retro_savestate_context
{
/* Standard savestate written to disk. */
RETRO_SAVESTATE_CONTEXT_NORMAL = 0,
/* Savestate where you are guaranteed that the same instance will load the save state.
* You can store internal pointers to code or data.
* It's still a full serialization and deserialization, and could be loaded or saved at any time.
* It won't be written to disk or sent over the network.
*/
RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE = 1,
/* Savestate where you are guaranteed that the same emulator binary will load that savestate.
* You can skip anything that would slow down saving or loading state but you can not store internal pointers.
* It won't be written to disk or sent over the network.
* Example: "Second Instance" runahead
*/
RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY = 2,
/* Savestate used within a rollback netplay feature.
* You should skip anything that would unnecessarily increase bandwidth usage.
* It won't be written to disk but it will be sent over the network.
*/
RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY = 3,
/* Ensure sizeof() == sizeof(int). */
RETRO_SAVESTATE_CONTEXT_UNKNOWN = INT_MAX
};
struct retro_message
{
const char *msg; /* Message to be displayed. */
@ -3430,6 +3531,10 @@ struct retro_core_option_definition
const char *default_value;
};
#ifdef __PS3__
#undef local
#endif
struct retro_core_options_intl
{
/* Pointer to an array of retro_core_option_definition structs
@ -3667,6 +3772,43 @@ struct retro_fastforwarding_override
bool inhibit_toggle;
};
/* During normal operation. Rate will be equal to the core's internal FPS. */
#define RETRO_THROTTLE_NONE 0
/* While paused or stepping single frames. Rate will be 0. */
#define RETRO_THROTTLE_FRAME_STEPPING 1
/* During fast forwarding.
* Rate will be 0 if not specifically limited to a maximum speed. */
#define RETRO_THROTTLE_FAST_FORWARD 2
/* During slow motion. Rate will be less than the core's internal FPS. */
#define RETRO_THROTTLE_SLOW_MOTION 3
/* While rewinding recorded save states. Rate can vary depending on the rewind
* speed or be 0 if the frontend is not aiming for a specific rate. */
#define RETRO_THROTTLE_REWINDING 4
/* While vsync is active in the video driver and the target refresh rate is
* lower than the core's internal FPS. Rate is the target refresh rate. */
#define RETRO_THROTTLE_VSYNC 5
/* When the frontend does not throttle in any way. Rate will be 0.
* An example could be if no vsync or audio output is active. */
#define RETRO_THROTTLE_UNBLOCKED 6
struct retro_throttle_state
{
/* The current throttling mode. Should be one of the values above. */
unsigned mode;
/* How many times per second the frontend aims to call retro_run.
* Depending on the mode, it can be 0 if there is no known fixed rate.
* This won't be accurate if the total processing time of the core and
* the frontend is longer than what is available for one frame. */
float rate;
};
/* Callbacks */
/* Environment callback. Gives implementations a way of performing

View File

@ -91,4 +91,100 @@ static INLINE uint32_t prev_pow2(uint32_t v)
return v - (v >> 1);
}
/**
* clamp:
* @v : initial value
*
* Get the clamped value based on initial value.
*
* Returns: clamped value (derived from @v).
**/
static INLINE float clamp_value(float v, float min, float max)
{
return v <= min ? min : v >= max ? max : v;
}
/**
* saturate_value:
* @v : initial value
*
* Get the clamped 0.0-1.0 value based on initial value.
*
* Returns: clamped 0.0-1.0 value (derived from @v).
**/
static INLINE float saturate_value(float v)
{
return clamp_value(v, 0.0f, 1.0f);
}
/**
* dot_product:
* @a : left hand vector value
* @b : right hand vector value
*
* Get the dot product of the two passed in vectors.
*
* Returns: dot product value (derived from @a and @b).
**/
static INLINE float dot_product(const float* a, const float* b)
{
return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
}
/**
* convert_rgb_to_yxy:
* @rgb : in RGB colour space value
* @Yxy : out Yxy colour space value
*
* Convert from RGB colour space to Yxy colour space.
*
* Returns: Yxy colour space value (derived from @rgb).
**/
static INLINE void convert_rgb_to_yxy(const float* rgb, float* Yxy)
{
float inv;
float xyz[3];
float one[3] = {1.0, 1.0, 1.0};
float rgb_xyz[3][3] = {
{0.4124564, 0.3575761, 0.1804375},
{0.2126729, 0.7151522, 0.0721750},
{0.0193339, 0.1191920, 0.9503041}
};
xyz[0] = dot_product(rgb_xyz[0], rgb);
xyz[1] = dot_product(rgb_xyz[1], rgb);
xyz[2] = dot_product(rgb_xyz[2], rgb);
inv = 1.0f / dot_product(xyz, one);
Yxy[0] = xyz[1];
Yxy[1] = xyz[0] * inv;
Yxy[2] = xyz[1] * inv;
}
/**
* convert_yxy_to_rgb:
* @rgb : in Yxy colour space value
* @Yxy : out rgb colour space value
*
* Convert from Yxy colour space to rgb colour space.
*
* Returns: rgb colour space value (derived from @Yxy).
**/
static INLINE void convert_yxy_to_rgb(const float* Yxy, float* rgb)
{
float xyz[3];
float xyz_rgb[3][3] = {
{3.2404542, -1.5371385, -0.4985314},
{-0.9692660, 1.8760108, 0.0415560},
{0.0556434, -0.2040259, 1.0572252}
};
xyz[0] = Yxy[0] * Yxy[1] / Yxy[2];
xyz[1] = Yxy[0];
xyz[2] = Yxy[0] * (1.0 - Yxy[1] - Yxy[2]) / Yxy[2];
rgb[0] = dot_product(xyz_rgb[0], xyz);
rgb[1] = dot_product(xyz_rgb[1], xyz);
rgb[2] = dot_product(xyz_rgb[2], xyz);
}
#endif

View File

@ -74,14 +74,29 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
return false;
}
static INLINE bool bits_any_different(uint32_t *a, uint32_t *b, uint32_t count)
{
uint32_t i;
for (i = 0; i < count; i++)
{
if (a[i] != b[i])
return true;
}
return false;
}
#ifndef PATH_MAX_LENGTH
#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS) || defined(__PSL1GHT__) || defined(__PS3__)
#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(__PSL1GHT__) || defined(__PS3__)
#define PATH_MAX_LENGTH 512
#else
#define PATH_MAX_LENGTH 4096
#endif
#endif
#ifndef NAME_MAX_LENGTH
#define NAME_MAX_LENGTH 256
#endif
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif

View File

@ -83,7 +83,7 @@ static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
*
* Sleeps for a specified amount of milliseconds (@msec).
**/
#if defined(PSP) || defined(VITA)
#if defined(VITA)
#define retro_sleep(msec) (sceKernelDelayThread(1000 * (msec)))
#elif defined(_3DS)
#define retro_sleep(msec) (svcSleepThread(1000000 * (s64)(msec)))
@ -102,7 +102,7 @@ static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
#else
#define retro_sleep(msec) \
{ \
struct timespec tv = {0}; \
struct timespec tv; \
tv.tv_sec = msec / 1000; \
tv.tv_nsec = (msec % 1000) * 1000000; \
nanosleep(&tv, NULL); \

View File

@ -59,7 +59,7 @@ int64_t filestream_truncate(RFILE *stream, int64_t length);
* @bufsize : optional buffer size (-1 or 0 to use default)
*
* Opens a file for reading or writing, depending on the requested mode.
* Returns a pointer to an RFILE if opened successfully, otherwise NULL.
* @return A pointer to an RFILE if opened successfully, otherwise NULL.
**/
RFILE* filestream_open(const char *path, unsigned mode, unsigned hints);
@ -75,16 +75,39 @@ void filestream_rewind(RFILE *stream);
int filestream_close(RFILE *stream);
/**
* filestream_read_file:
* @path : path to file.
* @buf : buffer to allocate and read the contents of the
* file into. Needs to be freed manually.
* @len : optional output integer containing bytes read.
*
* Read the contents of a file into @buf.
*
* @return Non-zero on success.
*/
int64_t filestream_read_file(const char *path, void **buf, int64_t *len);
char* filestream_gets(RFILE *stream, char *s, size_t len);
int filestream_getc(RFILE *stream);
int filestream_vscanf(RFILE *stream, const char* format, va_list *args);
int filestream_scanf(RFILE *stream, const char* format, ...);
int filestream_eof(RFILE *stream);
/**
* filestream_write_file:
* @path : path to file.
* @data : contents to write to the file.
* @size : size of the contents.
*
* Writes data to a file.
*
* @return true on success, otherwise false.
**/
bool filestream_write_file(const char *path, const void *data, int64_t size);
int filestream_putc(RFILE *stream, int c);
@ -105,7 +128,11 @@ const char* filestream_get_path(RFILE *stream);
bool filestream_exists(const char *path);
/* Returned pointer must be freed by the caller. */
/**
* filestream_getline:
*
* Returned pointer must be freed by the caller.
**/
char* filestream_getline(RFILE *stream);
libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream);

View File

@ -92,16 +92,20 @@ static INLINE bool string_ends_with_size(const char *str, const char *suffix,
static INLINE bool string_ends_with(const char *str, const char *suffix)
{
if (!str || !suffix)
return false;
return string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
return str && suffix && string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
}
/* Returns the length of 'str' (c.f. strlen()), but only
/**
* strlen_size:
*
* Leaf function.
*
* @return the length of 'str' (c.f. strlen()), but only
* checks the first 'size' characters
* - If 'str' is NULL, returns 0
* - If 'str' is not NULL and no '\0' character is found
* in the first 'size' characters, returns 'size' */
* in the first 'size' characters, returns 'size'
**/
static INLINE size_t strlen_size(const char *str, size_t size)
{
size_t i = 0;
@ -130,25 +134,68 @@ static INLINE bool string_is_equal_case_insensitive(const char *a,
return (result == 0);
}
static INLINE bool string_starts_with_case_insensitive(const char *str,
const char *prefix)
{
int result = 0;
const unsigned char *p1 = (const unsigned char*)str;
const unsigned char *p2 = (const unsigned char*)prefix;
if (!str || !prefix)
return false;
if (p1 == p2)
return true;
while ((result = tolower (*p1++) - tolower (*p2)) == 0)
if (*p2++ == '\0')
break;
return (result == 0 || *p2 == '\0');
}
char *string_to_upper(char *s);
char *string_to_lower(char *s);
char *string_ucwords(char *s);
char *string_replace_substring(const char *in, const char *pattern,
const char *by);
char *string_replace_substring(const char *in,
const char *pattern, size_t pattern_len,
const char *replacement, size_t replacement_len);
/* Remove leading whitespaces */
/**
* string_trim_whitespace_left:
*
* Remove leading whitespaces
**/
char *string_trim_whitespace_left(char *const s);
/* Remove trailing whitespaces */
/**
* string_trim_whitespace_right:
*
* Remove trailing whitespaces
**/
char *string_trim_whitespace_right(char *const s);
/* Remove leading and trailing whitespaces */
/**
* string_trim_whitespace:
*
* Remove leading and trailing whitespaces
**/
char *string_trim_whitespace(char *const s);
/*
/**
* word_wrap:
* @dst : pointer to destination buffer.
* @dst_size : size of destination buffer.
* @src : pointer to input string.
* @src_len : length of @src
* @line_width : max number of characters per line.
* @wideglyph_width : not used, but is necessary to keep
* compatibility with word_wrap_wideglyph().
* @max_lines : max lines of destination string.
* 0 means no limit.
*
* Wraps string specified by 'src' to destination buffer
* specified by 'dst' and 'dst_size'.
* This function assumes that all glyphs in the string
@ -156,58 +203,57 @@ char *string_trim_whitespace(char *const s);
* regular Latin characters - i.e. it will not wrap
* correctly any text containing so-called 'wide' Unicode
* characters (e.g. CJK languages, emojis, etc.).
*
* @param dst pointer to destination buffer.
* @param dst_size size of destination buffer.
* @param src pointer to input string.
* @param line_width max number of characters per line.
* @param wideglyph_width not used, but is necessary to keep
* compatibility with word_wrap_wideglyph().
* @param max_lines max lines of destination string.
* 0 means no limit.
*/
void word_wrap(char *dst, size_t dst_size, const char *src,
**/
void word_wrap(char *dst, size_t dst_size, const char *src, size_t src_len,
int line_width, int wideglyph_width, unsigned max_lines);
/*
* Wraps string specified by 'src' to destination buffer
* specified by 'dst' and 'dst_size'.
/**
* word_wrap_wideglyph:
* @dst : pointer to destination buffer.
* @dst_size : size of destination buffer.
* @src : pointer to input string.
* @src_len : length of @src
* @line_width : max number of characters per line.
* @wideglyph_width : effective width of 'wide' Unicode glyphs.
* the value here is normalised relative to the
* typical on-screen pixel width of a regular
* Latin character:
* - a regular Latin character is defined to
* have an effective width of 100
* - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
* - e.g. if 'wide' Unicode characters in 'src'
* have an on-screen pixel width twice that of
* regular Latin characters, wideglyph_width
* would be 200
* @max_lines : max lines of destination string.
* 0 means no limit.
*
* Wraps string specified by @src to destination buffer
* specified by @dst and @dst_size.
* This function assumes that all glyphs in the string
* are:
* - EITHER 'non-wide' Unicode glyphs, with an on-screen
* pixel width similar to that of regular Latin characters
* - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
* with an on-screen pixel width defined by 'wideglyph_width'
* with an on-screen pixel width defined by @wideglyph_width
* Note that wrapping may occur in inappropriate locations
* if 'src' string contains 'wide' Unicode characters whose
* if @src string contains 'wide' Unicode characters whose
* on-screen pixel width deviates greatly from the set
* 'wideglyph_width' value.
*
* @param dst pointer to destination buffer.
* @param dst_size size of destination buffer.
* @param src pointer to input string.
* @param line_width max number of characters per line.
* @param wideglyph_width effective width of 'wide' Unicode glyphs.
* the value here is normalised relative to the
* typical on-screen pixel width of a regular
* Latin character:
* - a regular Latin character is defined to
* have an effective width of 100
* - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
* - e.g. if 'wide' Unicode characters in 'src'
* have an on-screen pixel width twice that of
* regular Latin characters, wideglyph_width
* would be 200
* @param max_lines max lines of destination string.
* 0 means no limit.
*/
void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src,
int line_width, int wideglyph_width, unsigned max_lines);
* @wideglyph_width value.
**/
void word_wrap_wideglyph(
char *dst, size_t dst_size,
const char *src, size_t src_len,
int line_width, int wideglyph_width,
unsigned max_lines);
/* Splits string into tokens seperated by 'delim'
/**
* string_tokenize:
*
* Splits string into tokens seperated by @delim
* > Returned token string must be free()'d
* > Returns NULL if token is not found
* > After each call, 'str' is set to the position after the
* > After each call, @str is set to the position after the
* last found token
* > Tokens *include* empty strings
* Usage example:
@ -220,29 +266,120 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src,
* free(token);
* token = NULL;
* }
*/
**/
char* string_tokenize(char **str, const char *delim);
/* Removes every instance of character 'c' from 'str' */
/**
* string_remove_all_chars:
* @str : input string (must be non-NULL, otherwise UB)
*
* Leaf function.
*
* Removes every instance of character @c from @str
**/
void string_remove_all_chars(char *str, char c);
/* Replaces every instance of character 'find' in 'str'
* with character 'replace' */
/**
* string_replace_all_chars:
* @str : input string (must be non-NULL, otherwise UB)
* @find : character to find
* @replace : character to replace @find with
*
* Hidden non-leaf function cost:
* - Calls strchr (in a loop)
*
* Replaces every instance of character @find in @str
* with character @replace
**/
void string_replace_all_chars(char *str, char find, char replace);
/* Converts string to unsigned integer.
* Returns 0 if string is invalid */
/**
* string_to_unsigned:
* @str : input string
*
* Converts string to unsigned integer.
*
* @return 0 if string is invalid, otherwise > 0
**/
unsigned string_to_unsigned(const char *str);
/* Converts hexadecimal string to unsigned integer.
/**
* string_hex_to_unsigned:
* @str : input string (must be non-NULL, otherwise UB)
*
* Converts hexadecimal string to unsigned integer.
* Handles optional leading '0x'.
* Returns 0 if string is invalid */
*
* @return 0 if string is invalid, otherwise > 0
**/
unsigned string_hex_to_unsigned(const char *str);
char *string_init(const char *src);
void string_set(char **string, const char *src);
/**
* string_count_occurrences_single_character:
*
* Leaf function.
*
* Get the total number of occurrences of character @c in @str.
*
* @return Total number of occurrences of character @c
*/
int string_count_occurrences_single_character(const char *str, char c);
/**
* string_replace_whitespace_with_single_character:
*
* Leaf function.
*
* Replaces all spaces with given character @c.
**/
void string_replace_whitespace_with_single_character(char *str, char c);
/**
* string_replace_multi_space_with_single_space:
*
* Leaf function.
*
* Replaces multiple spaces with a single space in a string.
**/
void string_replace_multi_space_with_single_space(char *str);
/**
* string_remove_all_whitespace:
*
* Leaf function.
*
* Remove all spaces from the given string.
**/
void string_remove_all_whitespace(char *str_trimmed, const char *str);
/* Retrieve the last occurance of the given character in a string. */
int string_index_last_occurance(const char *str, char c);
/**
* string_find_index_substring_string:
* @str : input string (must be non-NULL, otherwise UB)
* @substr : substring to find in @str
*
* Hidden non-leaf function cost:
* - Calls strstr
*
* Find the position of substring @substr in string @str.
**/
int string_find_index_substring_string(const char *str, const char *substr);
/**
* string_copy_only_ascii:
*
* Leaf function.
*
* Strips non-ASCII characters from a string.
**/
void string_copy_only_ascii(char *str_stripped, const char *str);
extern const unsigned char lr_char_props[256];
RETRO_END_DECLS

View File

@ -62,7 +62,7 @@ enum vfs_scheme
VFS_SCHEME_CDROM
};
#ifndef __WINRT__
#if !(defined(__WINRT__) && defined(__cplusplus_winrt))
#ifdef VFS_FRONTEND
struct retro_vfs_file_handle
#else

View File

@ -71,6 +71,12 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream);
int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream);
#ifdef __WINRT__
void uwp_set_acl(const wchar_t* path, const wchar_t* AccessString);
#endif
RETRO_END_DECLS
#endif

View File

@ -65,7 +65,6 @@ static int qstrcmp_dir(const void *a_, const void *b_)
* @dir_first : move the directories in the listing to the top?
*
* Sorts a directory listing.
*
**/
void dir_list_sort(struct string_list *list, bool dir_first)
{
@ -79,7 +78,6 @@ void dir_list_sort(struct string_list *list, bool dir_first)
* @list : pointer to the directory listing
*
* Frees a directory listing.
*
**/
void dir_list_free(struct string_list *list)
{
@ -105,7 +103,7 @@ bool dir_list_deinitialize(struct string_list *list)
*
* Add files within a directory to an existing string list
*
* Returns: -1 on error, 0 on success.
* @return -1 on error, 0 on success.
**/
static int dir_list_read(const char *dir,
struct string_list *list, struct string_list *ext_list,
@ -139,8 +137,7 @@ static int dir_list_read(const char *dir,
continue;
}
file_path[0] = '\0';
fill_pathname_join(file_path, dir, name, sizeof(file_path));
fill_pathname_join_special(file_path, dir, name, sizeof(file_path));
if (retro_dirent_is_dir(entry, NULL))
{
@ -206,7 +203,7 @@ error:
*
* Create a directory listing, appending to an existing list
*
* Returns: true success, false in case of error.
* @return Returns true on success, otherwise false.
**/
bool dir_list_append(struct string_list *list,
const char *dir,
@ -241,7 +238,7 @@ bool dir_list_append(struct string_list *list,
*
* Create a directory listing.
*
* Returns: pointer to a directory listing of type 'struct string_list *' on success,
* @return pointer to a directory listing of type 'struct string_list *' on success,
* NULL in case of error. Has to be freed manually.
**/
struct string_list *dir_list_new(const char *dir,
@ -264,17 +261,20 @@ struct string_list *dir_list_new(const char *dir,
return list;
}
/* Warning: 'list' must zero initialised before
* calling this function, otherwise memory leaks/
* undefined behaviour will occur */
/**
* dir_list_initialize:
*
* NOTE: @list must zero initialised before
* calling this function, otherwise UB.
**/
bool dir_list_initialize(struct string_list *list,
const char *dir,
const char *ext, bool include_dirs,
bool include_hidden, bool include_compressed,
bool recursive)
{
if (!list || !string_list_initialize(list))
return false;
return dir_list_append(list, dir, ext, include_dirs,
if (list && string_list_initialize(list))
return dir_list_append(list, dir, ext, include_dirs,
include_hidden, include_compressed, recursive);
return false;
}

View File

@ -55,18 +55,6 @@ static bool file_list_deinitialize_internal(file_list_t *list)
return true;
}
bool file_list_initialize(file_list_t *list)
{
if (!list)
return false;
list->list = NULL;
list->capacity = 0;
list->size = 0;
return true;
}
bool file_list_reserve(file_list_t *list, size_t nitems)
{
const size_t item_size = sizeof(struct item_file);
@ -75,9 +63,7 @@ bool file_list_reserve(file_list_t *list, size_t nitems)
if (nitems < list->capacity || nitems > (size_t)-1/item_size)
return false;
new_data = (struct item_file*)realloc(list->list, nitems * item_size);
if (!new_data)
if (!(new_data = (struct item_file*)realloc(list->list, nitems * item_size)))
return false;
memset(&new_data[list->capacity], 0, item_size * (nitems - list->capacity));
@ -88,18 +74,6 @@ bool file_list_reserve(file_list_t *list, size_t nitems)
return true;
}
bool file_list_prepend(file_list_t *list,
const char *path, const char *label,
unsigned type, size_t directory_ptr,
size_t entry_idx)
{
return file_list_insert(list, path,
label, type,
directory_ptr, entry_idx,
0
);
}
bool file_list_insert(file_list_t *list,
const char *path, const char *label,
unsigned type, size_t directory_ptr,
@ -184,19 +158,6 @@ bool file_list_append(file_list_t *list,
return true;
}
size_t file_list_get_size(const file_list_t *list)
{
if (!list)
return 0;
return list->size;
}
size_t file_list_get_directory_ptr(const file_list_t *list)
{
size_t size = list ? list->size : 0;
return list->list[size].directory_ptr;
}
void file_list_pop(file_list_t *list, size_t *directory_ptr)
{
if (!list)
@ -262,21 +223,7 @@ void file_list_clear(file_list_t *list)
list->size = 0;
}
void file_list_set_label_at_offset(file_list_t *list, size_t idx,
const char *label)
{
if (!list)
return;
if (list->list[idx].label)
free(list->list[idx].label);
list->list[idx].alt = NULL;
if (label)
list->list[idx].label = strdup(label);
}
void file_list_get_label_at_offset(const file_list_t *list, size_t idx,
static void file_list_get_label_at_offset(const file_list_t *list, size_t idx,
const char **label)
{
if (!label || !list)
@ -339,18 +286,6 @@ void *file_list_get_userdata_at_offset(const file_list_t *list, size_t idx)
return list->list[idx].userdata;
}
void file_list_set_userdata(const file_list_t *list, size_t idx, void *ptr)
{
if (list && ptr)
list->list[idx].userdata = ptr;
}
void file_list_set_actiondata(const file_list_t *list, size_t idx, void *ptr)
{
if (list && ptr)
list->list[idx].actiondata = ptr;
}
void *file_list_get_actiondata_at_offset(const file_list_t *list, size_t idx)
{
if (!list)
@ -376,38 +311,6 @@ void file_list_free_userdata(const file_list_t *list, size_t idx)
list->list[idx].userdata = NULL;
}
void *file_list_get_last_actiondata(const file_list_t *list)
{
if (!list)
return NULL;
return list->list[list->size - 1].actiondata;
}
void file_list_get_at_offset(const file_list_t *list, size_t idx,
const char **path, const char **label, unsigned *file_type,
size_t *entry_idx)
{
if (!list)
return;
if (path)
*path = list->list[idx].path;
if (label)
*label = list->list[idx].label;
if (file_type)
*file_type = list->list[idx].type;
if (entry_idx)
*entry_idx = list->list[idx].entry_idx;
}
void file_list_get_last(const file_list_t *list,
const char **path, const char **label,
unsigned *file_type, size_t *entry_idx)
{
if (list && list->size)
file_list_get_at_offset(list, list->size - 1, path, label, file_type, entry_idx);
}
bool file_list_search(const file_list_t *list, const char *needle, size_t *idx)
{
size_t i;
@ -430,8 +333,7 @@ bool file_list_search(const file_list_t *list, const char *needle, size_t *idx)
continue;
}
str = (const char *)strcasestr(alt, needle);
if (str == alt)
if ((str = (const char *)strcasestr(alt, needle)) == alt)
{
/* Found match with first chars, best possible match. */
*idx = i;

View File

@ -62,7 +62,7 @@ static bool string_list_deinitialize_internal(struct string_list *list)
*
* Change maximum capacity of string list's size.
*
* Returns: true (1) if successful, otherwise false (0).
* @return true if successful, otherwise false.
**/
static bool string_list_capacity(struct string_list *list, size_t cap)
{
@ -85,7 +85,7 @@ static bool string_list_capacity(struct string_list *list, size_t cap)
* @list : pointer to string list object
*
* Frees a string list.
*/
**/
void string_list_free(struct string_list *list)
{
if (!list)
@ -113,8 +113,8 @@ bool string_list_deinitialize(struct string_list *list)
*
* Creates a new string list. Has to be freed manually.
*
* Returns: new string list if successful, otherwise NULL.
*/
* @return New string list if successful, otherwise NULL.
**/
struct string_list *string_list_new(void)
{
struct string_list_elem *
@ -164,7 +164,7 @@ bool string_list_initialize(struct string_list *list)
*
* Appends a new element to the string list.
*
* Returns: true (1) if successful, otherwise false (0).
* @return true if successful, otherwise false.
**/
bool string_list_append(struct string_list *list, const char *elem,
union string_list_elem_attr attr)
@ -182,8 +182,7 @@ bool string_list_append(struct string_list *list, const char *elem,
(list->cap > 0) ? (list->cap * 2) : 32))
return false;
data_dup = strdup(elem);
if (!data_dup)
if (!(data_dup = strdup(elem)))
return false;
list->elems[list->size].data = data_dup;
@ -202,7 +201,7 @@ bool string_list_append(struct string_list *list, const char *elem,
*
* Appends a new element to the string list.
*
* Returns: true (1) if successful, otherwise false (0).
* @return true if successful, otherwise false.
**/
bool string_list_append_n(struct string_list *list, const char *elem,
unsigned length, union string_list_elem_attr attr)
@ -213,9 +212,7 @@ bool string_list_append_n(struct string_list *list, const char *elem,
!string_list_capacity(list, list->cap * 2))
return false;
data_dup = (char*)malloc(length + 1);
if (!data_dup)
if (!(data_dup = (char*)malloc(length + 1)))
return false;
strlcpy(data_dup, elem, length + 1);
@ -251,7 +248,7 @@ void string_list_set(struct string_list *list,
*
* A string list will be joined/concatenated as a
* string to @buffer, delimited by @delim.
*/
**/
void string_list_join_concat(char *buffer, size_t size,
const struct string_list *list, const char *delim)
{
@ -261,7 +258,7 @@ void string_list_join_concat(char *buffer, size_t size,
/* If buffer is already 'full', nothing
* further can be added
* > This condition will also be triggered
* if buffer is not NUL-terminated,
* if buffer is not NULL-terminated,
* in which case any attempt to increment
* buffer or decrement size would lead to
* undefined behaviour */
@ -298,8 +295,7 @@ struct string_list *string_split(const char *str, const char *delim)
if (!list)
return NULL;
copy = strdup(str);
if (!copy)
if (!(copy = strdup(str)))
goto error;
tmp = strtok_r(copy, delim, &save);
@ -334,8 +330,7 @@ bool string_split_noalloc(struct string_list *list,
if (!list)
return false;
copy = strdup(str);
if (!copy)
if (!(copy = strdup(str)))
return false;
tmp = strtok_r(copy, delim, &save);
@ -367,8 +362,8 @@ bool string_split_noalloc(struct string_list *list,
* Includes empty strings - i.e. two adjacent delimiters will resolve
* to a string list element of "".
*
* Returns: new string list if successful, otherwise NULL.
*/
* @return New string list if successful, otherwise NULL.
**/
struct string_list *string_separate(char *str, const char *delim)
{
char *token = NULL;
@ -377,15 +372,13 @@ struct string_list *string_separate(char *str, const char *delim)
/* Sanity check */
if (!str || string_is_empty(delim))
goto error;
return NULL;
if (!(list = string_list_new()))
return NULL;
str_ptr = &str;
list = string_list_new();
token = string_tokenize(str_ptr, delim);
if (!list)
goto error;
token = string_tokenize(str_ptr, delim);
while (token)
{
union string_list_elem_attr attr;
@ -393,22 +386,17 @@ struct string_list *string_separate(char *str, const char *delim)
attr.i = 0;
if (!string_list_append(list, token, attr))
goto error;
{
free(token);
string_list_free(list);
return NULL;
}
free(token);
token = NULL;
token = string_tokenize(str_ptr, delim);
}
return list;
error:
if (token)
free(token);
if (list)
string_list_free(list);
return NULL;
}
bool string_separate_noalloc(
@ -446,68 +434,66 @@ bool string_separate_noalloc(
/**
* string_list_find_elem:
* @list : pointer to string list
* @elem : element to find inside the string list.
*
* @param list
* Pointer to string list
* @param elem
* Element to find inside the string list.
*
* Searches for an element (@elem) inside the string list.
*
* Returns: true (1) if element could be found, otherwise false (0).
* @return Number of elements found, otherwise 0.
*/
int string_list_find_elem(const struct string_list *list, const char *elem)
{
size_t i;
if (!list)
return false;
for (i = 0; i < list->size; i++)
if (list)
{
if (string_is_equal_noncase(list->elems[i].data, elem))
return (int)(i + 1);
size_t i;
for (i = 0; i < list->size; i++)
{
if (string_is_equal_noncase(list->elems[i].data, elem))
return (int)(i + 1);
}
}
return false;
return 0;
}
/**
* string_list_find_elem_prefix:
* @list : pointer to string list
* @prefix : prefix to append to @elem
* @elem : element to find inside the string list.
*
* @param list
* Pointer to string list
* @param prefix
* Prefix to append to @elem
* @param elem
* Element to find inside the string list.
*
* Searches for an element (@elem) inside the string list. Will
* also search for the same element prefixed by @prefix.
*
* Returns: true (1) if element could be found, otherwise false (0).
* @return true if element could be found, otherwise false.
*/
bool string_list_find_elem_prefix(const struct string_list *list,
const char *prefix, const char *elem)
{
size_t i;
char prefixed[255];
if (!list)
return false;
prefixed[0] = '\0';
strlcpy(prefixed, prefix, sizeof(prefixed));
strlcat(prefixed, elem, sizeof(prefixed));
for (i = 0; i < list->size; i++)
{
if (string_is_equal_noncase(list->elems[i].data, elem) ||
string_is_equal_noncase(list->elems[i].data, prefixed))
if ( string_is_equal_noncase(list->elems[i].data, elem)
|| string_is_equal_noncase(list->elems[i].data, prefixed))
return true;
}
return false;
}
struct string_list *string_list_clone(
const struct string_list *src)
struct string_list *string_list_clone(const struct string_list *src)
{
unsigned i;
size_t i;
struct string_list_elem
*elems = NULL;
struct string_list
@ -519,14 +505,13 @@ struct string_list *string_list_clone(
dest->elems = NULL;
dest->size = src->size;
dest->cap = src->cap;
if (dest->cap < dest->size)
if (src->cap < dest->size)
dest->cap = dest->size;
else
dest->cap = src->cap;
elems = (struct string_list_elem*)
calloc(dest->cap, sizeof(struct string_list_elem));
if (!elems)
if (!(elems = (struct string_list_elem*)
calloc(dest->cap, sizeof(struct string_list_elem))))
{
free(dest);
return NULL;
@ -536,11 +521,11 @@ struct string_list *string_list_clone(
for (i = 0; i < src->size; i++)
{
const char *_src = src->elems[i].data;
size_t len = _src ? strlen(_src) : 0;
const char *_src = src->elems[i].data;
size_t len = _src ? strlen(_src) : 0;
dest->elems[i].data = NULL;
dest->elems[i].attr = src->elems[i].attr;
dest->elems[i].data = NULL;
dest->elems[i].attr = src->elems[i].attr;
if (len != 0)
{

View File

@ -25,7 +25,6 @@
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -46,7 +45,6 @@ struct RFILE
{
struct retro_vfs_file_handle *hfile;
bool error_flag;
bool eof_flag;
};
static retro_vfs_get_path_t filestream_get_path_cb = NULL;
@ -109,18 +107,14 @@ bool filestream_exists(const char *path)
if (!path || !*path)
return false;
dummy = filestream_open(
if (!(dummy = filestream_open(
path,
RETRO_VFS_FILE_ACCESS_READ,
RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!dummy)
RETRO_VFS_FILE_ACCESS_HINT_NONE)))
return false;
if (filestream_close(dummy) != 0)
if (dummy)
free(dummy);
free(dummy);
dummy = NULL;
return true;
@ -165,7 +159,7 @@ int64_t filestream_truncate(RFILE *stream, int64_t length)
* @hints :
*
* Opens a file for reading or writing, depending on the requested mode.
* Returns a pointer to an RFILE if opened successfully, otherwise NULL.
* @return A pointer to an RFILE if opened successfully, otherwise NULL.
**/
RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
{
@ -184,7 +178,6 @@ RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
output = (RFILE*)malloc(sizeof(RFILE));
output->error_flag = false;
output->eof_flag = false;
output->hfile = fp;
return output;
}
@ -221,14 +214,14 @@ int filestream_getc(RFILE *stream)
return EOF;
}
int filestream_scanf(RFILE *stream, const char* format, ...)
int filestream_vscanf(RFILE *stream, const char* format, va_list *args)
{
char buf[4096];
char subfmt[64];
va_list args;
const char * bufiter = buf;
va_list args_copy;
const char *bufiter = buf;
int ret = 0;
int64_t startpos = filestream_tell(stream);
int64_t startpos = 0;
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
if (maxlen <= 0)
@ -236,7 +229,16 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
buf[maxlen] = '\0';
va_start(args, format);
/* Have to copy the input va_list here
* > Calling va_arg() on 'args' directly would
* cause the va_list to have an indeterminate value
* in the function calling filestream_vscanf(),
* leading to unexpected behaviour */
#ifdef __va_copy
__va_copy(args_copy, *args);
#else
va_copy(args_copy, *args);
#endif
while (*format)
{
@ -302,7 +304,7 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
}
else
{
int v = sscanf(bufiter, subfmt, va_arg(args, void*), &sublen);
int v = sscanf(bufiter, subfmt, va_arg(args_copy, void*), &sublen);
if (v == EOF)
return EOF;
if (v != 1)
@ -327,13 +329,24 @@ int filestream_scanf(RFILE *stream, const char* format, ...)
}
}
va_end(args);
filestream_seek(stream, startpos+(bufiter-buf),
va_end(args_copy);
startpos = filestream_tell(stream);
filestream_seek(stream, startpos + (bufiter - buf),
RETRO_VFS_SEEK_POSITION_START);
return ret;
}
int filestream_scanf(RFILE *stream, const char* format, ...)
{
int result;
va_list vl;
va_start(vl, format);
result = filestream_vscanf(stream, format, &vl);
va_end(vl);
return result;
}
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
{
int64_t output;
@ -348,14 +361,12 @@ int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
stream->eof_flag = false;
return output;
}
int filestream_eof(RFILE *stream)
{
return stream->eof_flag;
return filestream_tell(stream) == filestream_get_size(stream) ? EOF : 0;
}
int64_t filestream_tell(RFILE *stream)
@ -380,7 +391,6 @@ void filestream_rewind(RFILE *stream)
return;
filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);
stream->error_flag = false;
stream->eof_flag = false;
}
int64_t filestream_read(RFILE *stream, void *s, int64_t len)
@ -395,8 +405,6 @@ int64_t filestream_read(RFILE *stream, void *s, int64_t len)
if (output == VFS_ERROR_RETURN_VALUE)
stream->error_flag = true;
if (output < len)
stream->eof_flag = true;
return output;
}
@ -494,9 +502,7 @@ int filestream_printf(RFILE *stream, const char* format, ...)
int filestream_error(RFILE *stream)
{
if (stream && stream->error_flag)
return 1;
return 0;
return (stream && stream->error_flag);
}
int filestream_close(RFILE *stream)
@ -525,7 +531,7 @@ int filestream_close(RFILE *stream)
*
* Read the contents of a file into @buf.
*
* Returns: non zero on success.
* @return Non-zero on success.
*/
int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
{
@ -542,25 +548,20 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
return 0;
}
content_buf_size = filestream_get_size(file);
if (content_buf_size < 0)
if ((content_buf_size = filestream_get_size(file)) < 0)
goto error;
content_buf = malloc((size_t)(content_buf_size + 1));
if (!content_buf)
if (!(content_buf = malloc((size_t)(content_buf_size + 1))))
goto error;
if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1))
goto error;
ret = filestream_read(file, content_buf, (int64_t)content_buf_size);
if (ret < 0)
if ((ret = filestream_read(file, content_buf, (int64_t)content_buf_size)) <
0)
goto error;
if (filestream_close(file) != 0)
if (file)
free(file);
free(file);
*buf = content_buf;
@ -574,9 +575,8 @@ int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
return 1;
error:
if (file)
if (filestream_close(file) != 0)
free(file);
if (filestream_close(file) != 0)
free(file);
if (content_buf)
free(content_buf);
if (len)
@ -593,8 +593,8 @@ error:
*
* Writes data to a file.
*
* Returns: true (1) on success, false (0) otherwise.
*/
* @return true on success, otherwise false.
**/
bool filestream_write_file(const char *path, const void *data, int64_t size)
{
int64_t ret = 0;
@ -603,20 +603,18 @@ bool filestream_write_file(const char *path, const void *data, int64_t size)
RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!file)
return false;
ret = filestream_write(file, data, size);
if (filestream_close(file) != 0)
if (file)
free(file);
if (ret != size)
return false;
return true;
free(file);
return (ret == size);
}
/* Returned pointer must be freed by the caller. */
char* filestream_getline(RFILE *stream)
/**
* filestream_getline:
*
* Returned pointer must be freed by the caller.
**/
char *filestream_getline(RFILE *stream)
{
char *newline_tmp = NULL;
size_t cur_size = 8;
@ -631,16 +629,15 @@ char* filestream_getline(RFILE *stream)
return NULL;
}
in = filestream_getc(stream);
in = filestream_getc(stream);
while (in != EOF && in != '\n')
{
if (idx == cur_size)
{
cur_size *= 2;
newline_tmp = (char*)realloc(newline, cur_size + 1);
if (!newline_tmp)
if (!(newline_tmp = (char*)realloc(newline, cur_size + 1)))
{
free(newline);
return NULL;

View File

@ -69,17 +69,27 @@ RFILE* rfopen(const char *path, const char *mode)
int rfclose(RFILE* stream)
{
if (!stream)
return EOF;
return filestream_close(stream);
}
int64_t rftell(RFILE* stream)
{
if (!stream)
return -1;
return filestream_tell(stream);
}
int64_t rfseek(RFILE* stream, int64_t offset, int origin)
{
int seek_position = -1;
if (!stream)
return -1;
switch (origin)
{
case SEEK_SET:
@ -99,39 +109,61 @@ int64_t rfseek(RFILE* stream, int64_t offset, int origin)
int64_t rfread(void* buffer,
size_t elem_size, size_t elem_count, RFILE* stream)
{
if (!stream || (elem_size == 0) || (elem_count == 0))
return 0;
return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size);
}
char *rfgets(char *buffer, int maxCount, RFILE* stream)
{
if (!stream)
return NULL;
return filestream_gets(stream, buffer, maxCount);
}
int rfgetc(RFILE* stream)
{
if (!stream)
return EOF;
return filestream_getc(stream);
}
int64_t rfwrite(void const* buffer,
size_t elem_size, size_t elem_count, RFILE* stream)
{
return filestream_write(stream, buffer, elem_size * elem_count);
if (!stream || (elem_size == 0) || (elem_count == 0))
return 0;
return (filestream_write(stream, buffer, elem_size * elem_count) / elem_size);
}
int rfputc(int character, RFILE * stream)
{
return filestream_putc(stream, character);
if (!stream)
return EOF;
return filestream_putc(stream, character);
}
int64_t rfflush(RFILE * stream)
{
return filestream_flush(stream);
if (!stream)
return EOF;
return filestream_flush(stream);
}
int rfprintf(RFILE * stream, const char * format, ...)
{
int result;
va_list vl;
if (!stream)
return -1;
va_start(vl, format);
result = filestream_vprintf(stream, format, vl);
va_end(vl);
@ -152,8 +184,12 @@ int rfscanf(RFILE * stream, const char * format, ...)
{
int result;
va_list vl;
if (!stream)
return 0;
va_start(vl, format);
result = filestream_scanf(stream, format, vl);
result = filestream_vscanf(stream, format, &vl);
va_end(vl);
return result;
}

View File

@ -24,6 +24,7 @@
#include <ctype.h>
#include <string.h>
#include <compat/strl.h>
#include <string/stdstring.h>
#include <encodings/utf.h>
@ -89,9 +90,11 @@ char *string_ucwords(char *s)
}
char *string_replace_substring(const char *in,
const char *pattern, const char *replacement)
const char *pattern, size_t pattern_len,
const char *replacement, size_t replacement_len)
{
size_t numhits, pattern_len, replacement_len, outlen;
size_t outlen;
size_t numhits = 0;
const char *inat = NULL;
const char *inprev = NULL;
char *out = NULL;
@ -102,9 +105,6 @@ char *string_replace_substring(const char *in,
if (!pattern || !replacement)
return strdup(in);
pattern_len = strlen(pattern);
replacement_len = strlen(replacement);
numhits = 0;
inat = in;
while ((inat = strstr(inat, pattern)))
@ -114,9 +114,8 @@ char *string_replace_substring(const char *in,
}
outlen = strlen(in) - pattern_len*numhits + replacement_len*numhits;
out = (char *)malloc(outlen+1);
if (!out)
if (!(out = (char *)malloc(outlen+1)))
return NULL;
outat = out;
@ -129,7 +128,7 @@ char *string_replace_substring(const char *in,
outat += inat-inprev;
memcpy(outat, replacement, replacement_len);
outat += replacement_len;
inat += pattern_len;
inat += pattern_len;
inprev = inat;
}
strcpy(outat, inprev);
@ -137,7 +136,11 @@ char *string_replace_substring(const char *in,
return out;
}
/* Remove leading whitespaces */
/**
* string_trim_whitespace_left:
*
* Remove leading whitespaces
**/
char *string_trim_whitespace_left(char *const s)
{
if (s && *s)
@ -158,7 +161,11 @@ char *string_trim_whitespace_left(char *const s)
return s;
}
/* Remove trailing whitespaces */
/**
* string_trim_whitespace_right:
*
* Remove trailing whitespaces
**/
char *string_trim_whitespace_right(char *const s)
{
if (s && *s)
@ -178,7 +185,11 @@ char *string_trim_whitespace_right(char *const s)
return s;
}
/* Remove leading and trailing whitespaces */
/**
* string_trim_whitespace:
*
* Remove leading and trailing whitespaces
**/
char *string_trim_whitespace(char *const s)
{
string_trim_whitespace_right(s); /* order matters */
@ -187,12 +198,33 @@ char *string_trim_whitespace(char *const s)
return s;
}
void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines)
/**
* word_wrap:
* @dst : pointer to destination buffer.
* @dst_size : size of destination buffer.
* @src : pointer to input string.
* @line_width : max number of characters per line.
* @wideglyph_width : not used, but is necessary to keep
* compatibility with word_wrap_wideglyph().
* @max_lines : max lines of destination string.
* 0 means no limit.
*
* Wraps string specified by 'src' to destination buffer
* specified by 'dst' and 'dst_size'.
* This function assumes that all glyphs in the string
* have an on-screen pixel width similar to that of
* regular Latin characters - i.e. it will not wrap
* correctly any text containing so-called 'wide' Unicode
* characters (e.g. CJK languages, emojis, etc.).
**/
void word_wrap(
char *dst, size_t dst_size,
const char *src, size_t src_len,
int line_width, int wideglyph_width, unsigned max_lines)
{
char *lastspace = NULL;
unsigned counter = 0;
unsigned lines = 1;
size_t src_len = strlen(src);
const char *src_end = src + src_len;
/* Prevent buffer overflow */
@ -201,17 +233,15 @@ void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int
/* Early return if src string length is less
* than line width */
if (src_len < line_width)
if (src_len < (size_t)line_width)
{
strcpy(dst, src);
strlcpy(dst, src, dst_size);
return;
}
while (*src != '\0')
{
unsigned char_len;
char_len = (unsigned)(utf8skip(src, 1) - src);
unsigned char_len = (unsigned)(utf8skip(src, 1) - src);
counter++;
if (*src == ' ')
@ -227,7 +257,7 @@ void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int
* length is less than line width */
if (src_end - src <= line_width)
{
strcpy(dst, src);
strlcpy(dst, src, dst_size);
return;
}
}
@ -254,7 +284,7 @@ void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int
* length is less than line width */
if (src_end - src < line_width)
{
strcpy(dst, src);
strlcpy(dst, src, dst_size);
return;
}
}
@ -264,11 +294,46 @@ void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int
*dst = '\0';
}
void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines)
/**
* word_wrap_wideglyph:
* @dst : pointer to destination buffer.
* @dst_size : size of destination buffer.
* @src : pointer to input string.
* @line_width : max number of characters per line.
* @wideglyph_width : effective width of 'wide' Unicode glyphs.
* the value here is normalised relative to the
* typical on-screen pixel width of a regular
* Latin character:
* - a regular Latin character is defined to
* have an effective width of 100
* - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
* - e.g. if 'wide' Unicode characters in 'src'
* have an on-screen pixel width twice that of
* regular Latin characters, wideglyph_width
* would be 200
* @max_lines : max lines of destination string.
* 0 means no limit.
*
* Wraps string specified by @src to destination buffer
* specified by @dst and @dst_size.
* This function assumes that all glyphs in the string
* are:
* - EITHER 'non-wide' Unicode glyphs, with an on-screen
* pixel width similar to that of regular Latin characters
* - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
* with an on-screen pixel width defined by @wideglyph_width
* Note that wrapping may occur in inappropriate locations
* if @src string contains 'wide' Unicode characters whose
* on-screen pixel width deviates greatly from the set
* @wideglyph_width value.
**/
void word_wrap_wideglyph(char *dst, size_t dst_size,
const char *src, size_t src_len, int line_width,
int wideglyph_width, unsigned max_lines)
{
char *lastspace = NULL;
char *lastwideglyph = NULL;
const char *src_end = src + strlen(src);
const char *src_end = src + src_len;
unsigned lines = 1;
/* 'line_width' means max numbers of characters per line,
* but this metric is only meaningful when dealing with
@ -305,9 +370,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
while (*src != '\0')
{
unsigned char_len;
char_len = (unsigned)(utf8skip(src, 1) - src);
unsigned char_len = (unsigned)(utf8skip(src, 1) - src);
counter_normalized += 100;
/* Prevent buffer overflow */
@ -315,7 +378,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
break;
if (*src == ' ')
lastspace = dst; /* Remember the location of the whitespace */
lastspace = dst; /* Remember the location of the whitespace */
else if (*src == '\n')
{
/* If newlines embedded in the input,
@ -335,7 +398,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
{
/* Remember the location of the first byte
* whose length as UTF-8 >= 3*/
lastwideglyph = dst;
lastwideglyph = dst;
counter_normalized += additional_counter_normalized;
}
@ -354,9 +417,9 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
/* Insert newline character */
*lastwideglyph = '\n';
lines++;
src -= dst - lastwideglyph;
dst = lastwideglyph + 1;
lastwideglyph = NULL;
src -= dst - lastwideglyph;
dst = lastwideglyph + 1;
lastwideglyph = NULL;
/* Early return if remaining src string
* length is less than line width */
@ -372,9 +435,9 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
* with newline character */
*lastspace = '\n';
lines++;
src -= dst - lastspace - 1;
dst = lastspace + 1;
lastspace = NULL;
src -= dst - lastspace - 1;
dst = lastspace + 1;
lastspace = NULL;
/* Early return if remaining src string
* length is less than line width */
@ -390,10 +453,13 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
*dst = '\0';
}
/* Splits string into tokens seperated by 'delim'
/**
* string_tokenize:
*
* Splits string into tokens seperated by @delim
* > Returned token string must be free()'d
* > Returns NULL if token is not found
* > After each call, 'str' is set to the position after the
* > After each call, @str is set to the position after the
* last found token
* > Tokens *include* empty strings
* Usage example:
@ -406,7 +472,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_w
* free(token);
* token = NULL;
* }
*/
**/
char* string_tokenize(char **str, const char *delim)
{
/* Taken from https://codereview.stackexchange.com/questions/216956/strtok-function-thread-safe-supports-empty-tokens-doesnt-change-string# */
@ -419,25 +485,20 @@ char* string_tokenize(char **str, const char *delim)
if (!str || string_is_empty(delim))
return NULL;
str_ptr = *str;
/* Note: we don't check string_is_empty() here,
* empty strings are valid */
if (!str_ptr)
if (!(str_ptr = *str))
return NULL;
/* Search for delimiter */
delim_ptr = strstr(str_ptr, delim);
if (delim_ptr)
if ((delim_ptr = strstr(str_ptr, delim)))
token_len = delim_ptr - str_ptr;
else
token_len = strlen(str_ptr);
/* Allocate token string */
token = (char *)malloc((token_len + 1) * sizeof(char));
if (!token)
if (!(token = (char *)malloc((token_len + 1) * sizeof(char))))
return NULL;
/* Copy token */
@ -450,42 +511,53 @@ char* string_tokenize(char **str, const char *delim)
return token;
}
/* Removes every instance of character 'c' from 'str' */
/**
* string_remove_all_chars:
* @str : input string (must be non-NULL, otherwise UB)
*
* Leaf function.
*
* Removes every instance of character @c from @str
**/
void string_remove_all_chars(char *str, char c)
{
char *read_ptr = NULL;
char *write_ptr = NULL;
if (string_is_empty(str))
return;
read_ptr = str;
write_ptr = str;
char *read_ptr = str;
char *write_ptr = str;
while (*read_ptr != '\0')
{
*write_ptr = *read_ptr++;
write_ptr += (*write_ptr != c) ? 1 : 0;
if (*write_ptr != c)
write_ptr++;
}
*write_ptr = '\0';
}
/* Replaces every instance of character 'find' in 'str'
* with character 'replace' */
/**
* string_replace_all_chars:
* @str : input string (must be non-NULL, otherwise UB)
* @find : character to find
* @replace : character to replace @find with
*
* Replaces every instance of character @find in @str
* with character @replace
**/
void string_replace_all_chars(char *str, char find, char replace)
{
char *str_ptr = str;
if (string_is_empty(str))
return;
while ((str_ptr = strchr(str_ptr, find)))
*str_ptr++ = replace;
}
/* Converts string to unsigned integer.
* Returns 0 if string is invalid */
/**
* string_to_unsigned:
* @str : input string
*
* Converts string to unsigned integer.
*
* @return 0 if string is invalid, otherwise > 0
**/
unsigned string_to_unsigned(const char *str)
{
const char *ptr = NULL;
@ -502,27 +574,33 @@ unsigned string_to_unsigned(const char *str)
return (unsigned)strtoul(str, NULL, 10);
}
/* Converts hexadecimal string to unsigned integer.
/**
* string_hex_to_unsigned:
* @str : input string (must be non-NULL, otherwise UB)
*
* Converts hexadecimal string to unsigned integer.
* Handles optional leading '0x'.
* Returns 0 if string is invalid */
*
* @return 0 if string is invalid, otherwise > 0
**/
unsigned string_hex_to_unsigned(const char *str)
{
const char *hex_str = str;
const char *ptr = NULL;
size_t len;
if (string_is_empty(str))
return 0;
/* Remove leading '0x', if required */
len = strlen(str);
if (len >= 2)
if ((str[0] == '0') &&
((str[1] == 'x') || (str[1] == 'X')))
if (str[0] != '\0' && str[1] != '\0')
{
if ( (str[0] == '0') &&
((str[1] == 'x') ||
(str[1] == 'X')))
{
hex_str = str + 2;
if (string_is_empty(hex_str))
if (string_is_empty(hex_str))
return 0;
}
}
else
return 0;
/* Check for valid characters */
@ -534,3 +612,117 @@ unsigned string_hex_to_unsigned(const char *str)
return (unsigned)strtoul(hex_str, NULL, 16);
}
/**
* string_count_occurrences_single_character:
*
* Leaf function.
*
* Get the total number of occurrences of character @c in @str.
*
* @return Total number of occurrences of character @c
*/
int string_count_occurrences_single_character(const char *str, char c)
{
int count = 0;
for (; *str; str++)
if (*str == c)
count++;
return count;
}
/**
* string_replace_whitespace_with_single_character:
*
* Leaf function.
*
* Replaces all spaces with given character @c.
**/
void string_replace_whitespace_with_single_character(char *str, char c)
{
for (; *str; str++)
if (ISSPACE(*str))
*str = c;
}
/**
* string_replace_multi_space_with_single_space:
*
* Leaf function.
*
* Replaces multiple spaces with a single space in a string.
**/
void string_replace_multi_space_with_single_space(char *str)
{
char *str_trimmed = str;
bool prev_is_space = false;
bool curr_is_space = false;
for (; *str; str++)
{
curr_is_space = ISSPACE(*str);
if (prev_is_space && curr_is_space)
continue;
*str_trimmed++ = *str;
prev_is_space = curr_is_space;
}
*str_trimmed = '\0';
}
/**
* string_remove_all_whitespace:
*
* Leaf function.
*
* Remove all spaces from the given string.
**/
void string_remove_all_whitespace(char *str_trimmed, const char *str)
{
for (; *str; str++)
if (!ISSPACE(*str))
*str_trimmed++ = *str;
*str_trimmed = '\0';
}
/**
* Retrieve the last occurance of the given character in a string.
*/
int string_index_last_occurance(const char *str, char c)
{
const char *pos = strrchr(str, c);
if (pos)
return (int)(pos - str);
return -1;
}
/**
* string_find_index_substring_string:
* @str : input string (must be non-NULL, otherwise UB)
* @substr : substring to find in @str
*
* Find the position of substring @substr in string @str.
**/
int string_find_index_substring_string(const char *str, const char *substr)
{
const char *pos = strstr(str, substr);
if (pos)
return (int)(pos - str);
return -1;
}
/**
* string_copy_only_ascii:
*
* Leaf function.
*
* Strips non-ASCII characters from a string.
**/
void string_copy_only_ascii(char *str_stripped, const char *str)
{
for (; *str; str++)
if (*str > 0x1F && *str < 0x7F)
*str_stripped++ = *str;
*str_stripped = '\0';
}

View File

@ -22,7 +22,6 @@
#ifdef HAVE_THREADS
#include <rthreads/rthreads.h>
#include <retro_assert.h>
#include <stdlib.h>
#endif
@ -41,8 +40,6 @@ void rtime_init(void)
#ifdef HAVE_THREADS
if (!rtime_localtime_lock)
rtime_localtime_lock = slock_new();
retro_assert(rtime_localtime_lock);
#endif
}

View File

@ -26,7 +26,7 @@
#include <errno.h>
#include <sys/types.h>
#include <string/stdstring.h>
#include <string/stdstring.h> /* string_is_empty */
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -57,11 +57,6 @@
# include <dirent.h>
# endif
# include <unistd.h>
# if defined(ORBIS)
# include <sys/fcntl.h>
# include <sys/dirent.h>
# include <orbisFile.h>
# endif
# if defined(WIIU)
# include <malloc.h>
# endif
@ -74,11 +69,6 @@
# include <psp2/io/fcntl.h>
# include <psp2/io/dirent.h>
# include <psp2/io/stat.h>
#elif defined(ORBIS)
# include <orbisFile.h>
# include <ps4link.h>
# include <sys/dirent.h>
# include <sys/fcntl.h>
#elif !defined(_WIN32)
# if defined(PSP)
# include <pspiofilemgr.h>
@ -124,19 +114,66 @@
#include <unistd.h>
#endif
#if defined(ORBIS)
#include <orbisFile.h>
#include <sys/fcntl.h>
#include <sys/dirent.h>
#endif
#if defined(PSP)
#include <pspkernel.h>
#endif
#if defined(__PS3__) || defined(__PSL1GHT__)
#include <defines/ps3_defines.h>
#if defined(__PSL1GHT__)
#define FS_SUCCEEDED 0
#define FS_TYPE_DIR 1
#ifdef __PSL1GHT__
#include <lv2/sysfs.h>
#ifndef O_RDONLY
#define O_RDONLY SYS_O_RDONLY
#endif
#ifndef O_WRONLY
#define O_WRONLY SYS_O_WRONLY
#endif
#ifndef O_CREAT
#define O_CREAT SYS_O_CREAT
#endif
#ifndef O_TRUNC
#define O_TRUNC SYS_O_TRUNC
#endif
#ifndef O_RDWR
#define O_RDWR SYS_O_RDWR
#endif
#else
#include <cell/cell_fs.h>
#ifndef O_RDONLY
#define O_RDONLY CELL_FS_O_RDONLY
#endif
#ifndef O_WRONLY
#define O_WRONLY CELL_FS_O_WRONLY
#endif
#ifndef O_CREAT
#define O_CREAT CELL_FS_O_CREAT
#endif
#ifndef O_TRUNC
#define O_TRUNC CELL_FS_O_TRUNC
#endif
#ifndef O_RDWR
#define O_RDWR CELL_FS_O_RDWR
#endif
#ifndef sysFsStat
#define sysFsStat cellFsStat
#endif
#ifndef sysFSDirent
#define sysFSDirent CellFsDirent
#endif
#ifndef sysFsOpendir
#define sysFsOpendir cellFsOpendir
#endif
#ifndef sysFsReaddir
#define sysFsReaddir cellFsReaddir
#endif
#ifndef sysFSDirent
#define sysFSDirent CellFsDirent
#endif
#ifndef sysFsClosedir
#define sysFsClosedir cellFsClosedir
#endif
#endif
#endif
@ -165,7 +202,9 @@
#include <vfs/vfs_implementation.h>
#include <libretro.h>
#if defined(HAVE_MMAP)
#include <memmap.h>
#endif
#include <encodings/utf.h>
#include <compat/fopen_utf8.h>
#include <file/file_path.h>
@ -198,13 +237,6 @@ int64_t retro_vfs_file_seek_internal(
#ifdef ATLEAST_VC2005
/* VC2005 and up have a special 64-bit fseek */
return _fseeki64(stream->fp, offset, whence);
#elif defined(ORBIS)
{
int ret = orbisLseek(stream->fd, offset, whence);
if (ret < 0)
return -1;
return 0;
}
#elif defined(HAVE_64BIT_OFFSETS)
return fseeko(stream->fp, (off_t)offset, whence);
#else
@ -267,19 +299,6 @@ int64_t retro_vfs_file_seek_internal(
libretro_vfs_implementation_file *retro_vfs_file_open_impl(
const char *path, unsigned mode, unsigned hints)
{
#if defined(VFS_FRONTEND) || defined(HAVE_CDROM)
int path_len = (int)strlen(path);
#endif
#ifdef VFS_FRONTEND
const char *dumb_prefix = "vfsonly://";
size_t dumb_prefix_siz = STRLEN_CONST("vfsonly://");
int dumb_prefix_len = (int)dumb_prefix_siz;
#endif
#ifdef HAVE_CDROM
const char *cdrom_prefix = "cdrom://";
size_t cdrom_prefix_siz = STRLEN_CONST("cdrom://");
int cdrom_prefix_len = (int)cdrom_prefix_siz;
#endif
int flags = 0;
const char *mode_str = NULL;
libretro_vfs_implementation_file *stream =
@ -304,9 +323,18 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
stream->scheme = VFS_SCHEME_NONE;
#ifdef VFS_FRONTEND
if (path_len >= dumb_prefix_len)
if (!memcmp(path, dumb_prefix, dumb_prefix_len))
path += dumb_prefix_siz;
if ( path
&& path[0] == 'v'
&& path[1] == 'f'
&& path[2] == 's'
&& path[3] == 'o'
&& path[4] == 'n'
&& path[5] == 'l'
&& path[6] == 'y'
&& path[7] == ':'
&& path[8] == '/'
&& path[9] == '/')
path += sizeof("vfsonly://")-1;
#endif
#ifdef HAVE_CDROM
@ -323,13 +351,19 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
stream->cdrom.last_frame[0] = '\0';
stream->cdrom.last_frame_valid = false;
if (path_len > cdrom_prefix_len)
if ( path
&& path[0] == 'c'
&& path[1] == 'd'
&& path[2] == 'r'
&& path[3] == 'o'
&& path[4] == 'm'
&& path[5] == ':'
&& path[6] == '/'
&& path[7] == '/'
&& path[8] != '\0')
{
if (!memcmp(path, cdrom_prefix, cdrom_prefix_len))
{
path += cdrom_prefix_siz;
stream->scheme = VFS_SCHEME_CDROM;
}
path += sizeof("cdrom://")-1;
stream->scheme = VFS_SCHEME_CDROM;
}
#endif
@ -357,24 +391,20 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
mode_str = "wb";
flags = O_WRONLY | O_CREAT | O_TRUNC;
#if !defined(ORBIS)
#if !defined(_WIN32)
flags |= S_IRUSR | S_IWUSR;
#else
flags |= O_BINARY;
#endif
#endif
break;
case RETRO_VFS_FILE_ACCESS_READ_WRITE:
mode_str = "w+b";
flags = O_RDWR | O_CREAT | O_TRUNC;
#if !defined(ORBIS)
#if !defined(_WIN32)
flags |= S_IRUSR | S_IWUSR;
#else
flags |= O_BINARY;
#endif
#endif
break;
@ -383,12 +413,10 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
mode_str = "r+b";
flags = O_RDWR;
#if !defined(ORBIS)
#if !defined(_WIN32)
flags |= S_IRUSR | S_IWUSR;
#else
flags |= O_BINARY;
#endif
#endif
break;
@ -398,15 +426,6 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
{
#ifdef ORBIS
int fd = orbisOpen(path, flags, 0644);
if (fd < 0)
{
stream->fd = -1;
goto error;
}
stream->fd = fd;
#else
FILE *fp;
#ifdef HAVE_CDROM
if (stream->scheme == VFS_SCHEME_CDROM)
@ -423,13 +442,12 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
else
#endif
{
fp = (FILE*)fopen_utf8(path, mode_str);
if (!fp)
if (!(fp = (FILE*)fopen_utf8(path, mode_str)))
goto error;
stream->fp = fp;
}
/* Regarding setvbuf:
*
* https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
@ -453,19 +471,14 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
#elif defined(WIIU)
if (stream->scheme != VFS_SCHEME_CDROM)
{
const int bufsize = 128*1024;
const int bufsize = 128 * 1024;
stream->buf = (char*)memalign(0x40, bufsize);
if (stream->fp)
setvbuf(stream->fp, stream->buf, _IOFBF, bufsize);
}
#elif !defined(PSP)
if (stream->scheme != VFS_SCHEME_CDROM)
{
stream->buf = (char*)calloc(1, 0x4000);
if (stream->fp)
setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000);
}
#endif
#endif
}
else
@ -501,18 +514,12 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
stream->mapped = (uint8_t*)mmap((void*)0,
stream->mapsize, PROT_READ, MAP_SHARED, stream->fd, 0);
if (stream->mapped == MAP_FAILED)
if ((stream->mapped = (uint8_t*)mmap((void*)0,
stream->mapsize, PROT_READ, MAP_SHARED, stream->fd, 0)) == MAP_FAILED)
stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;
}
#endif
}
#ifdef ORBIS
stream->size = orbisLseek(stream->fd, 0, SEEK_END);
orbisLseek(stream->fd, 0, SEEK_SET);
#else
#ifdef HAVE_CDROM
if (stream->scheme == VFS_SCHEME_CDROM)
{
@ -533,7 +540,6 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl(
retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
}
#endif
return stream;
error:
@ -568,14 +574,7 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
}
if (stream->fd > 0)
{
#ifdef ORBIS
orbisClose(stream->fd);
stream->fd = -1;
#else
close(stream->fd);
#endif
}
#ifdef HAVE_CDROM
end:
if (stream->cdrom.cue_buf)
@ -598,12 +597,7 @@ int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream)
if (stream->scheme == VFS_SCHEME_CDROM)
return retro_vfs_file_error_cdrom(stream);
#endif
#ifdef ORBIS
/* TODO/FIXME - implement this? */
return 0;
#else
return ferror(stream->fp);
#endif
}
int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream)
@ -615,18 +609,20 @@ int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream)
int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length)
{
if (!stream)
return -1;
#ifdef _WIN32
if (_chsize(_fileno(stream->fp), length) != 0)
return -1;
if (stream && _chsize(_fileno(stream->fp), length) == 0)
{
stream->size = length;
return 0;
}
#elif !defined(VITA) && !defined(PSP) && !defined(PS2) && !defined(ORBIS) && (!defined(SWITCH) || defined(HAVE_LIBNX))
if (ftruncate(fileno(stream->fp), (off_t)length) != 0)
return -1;
if (stream && ftruncate(fileno(stream->fp), (off_t)length) == 0)
{
stream->size = length;
return 0;
}
#endif
return 0;
return -1;
}
int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
@ -640,14 +636,6 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
if (stream->scheme == VFS_SCHEME_CDROM)
return retro_vfs_file_tell_cdrom(stream);
#endif
#ifdef ORBIS
{
int64_t ret = orbisLseek(stream->fd, 0, SEEK_CUR);
if (ret < 0)
return -1;
return ret;
}
#else
#ifdef ATLEAST_VC2005
/* VC2005 and up have a special 64-bit ftell */
return _ftelli64(stream->fp);
@ -655,7 +643,6 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
return ftello(stream->fp);
#else
return ftell(stream->fp);
#endif
#endif
}
#ifdef HAVE_MMAP
@ -674,21 +661,7 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream,
int64_t offset, int seek_position)
{
int whence = -1;
switch (seek_position)
{
case RETRO_VFS_SEEK_POSITION_START:
whence = SEEK_SET;
break;
case RETRO_VFS_SEEK_POSITION_CURRENT:
whence = SEEK_CUR;
break;
case RETRO_VFS_SEEK_POSITION_END:
whence = SEEK_END;
break;
}
return retro_vfs_file_seek_internal(stream, offset, whence);
return retro_vfs_file_seek_internal(stream, offset, seek_position);
}
int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
@ -703,13 +676,7 @@ int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
if (stream->scheme == VFS_SCHEME_CDROM)
return retro_vfs_file_read_cdrom(stream, s, len);
#endif
#ifdef ORBIS
if (orbisRead(stream->fd, s, (size_t)len) < 0)
return -1;
return 0;
#else
return fread(s, 1, (size_t)len, stream->fp);
#endif
}
#ifdef HAVE_MMAP
if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
@ -732,36 +699,41 @@ int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len)
{
int64_t pos = 0;
size_t result = -1;
if (!stream)
return -1;
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
{
#ifdef ORBIS
if (orbisWrite(stream->fd, s, (size_t)len) < 0)
return -1;
return 0;
#else
return fwrite(s, 1, (size_t)len, stream->fp);
#endif
}
pos = retro_vfs_file_tell_impl(stream);
result = fwrite(s, 1, (size_t)len, stream->fp);
if (result != -1 && pos + result > stream->size)
stream->size = pos + result;
return result;
}
#ifdef HAVE_MMAP
if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
return -1;
#endif
return write(stream->fd, s, (size_t)len);
pos = retro_vfs_file_tell_impl(stream);
result = write(stream->fd, s, (size_t)len);
if (result != -1 && pos + result > stream->size)
stream->size = pos + result;
return result;
}
int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream)
{
if (!stream)
return -1;
#ifdef ORBIS
return 0;
#else
return fflush(stream->fp) == 0 ? 0 : -1;
#endif
if (stream && fflush(stream->fp) == 0)
return 0;
return -1;
}
int retro_vfs_file_remove_impl(const char *path)
@ -777,9 +749,7 @@ int retro_vfs_file_remove_impl(const char *path)
if (!path || !*path)
return -1;
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
path_local = utf8_to_local_string_alloc(path);
if (path_local)
if ((path_local = utf8_to_local_string_alloc(path)))
{
int ret = remove(path_local);
free(path_local);
@ -788,9 +758,7 @@ int retro_vfs_file_remove_impl(const char *path)
return 0;
}
#else
path_wide = utf8_to_utf16_string_alloc(path);
if (path_wide)
if ((path_wide = utf8_to_utf16_string_alloc(path)))
{
int ret = _wremove(path_wide);
free(path_wide);
@ -799,16 +767,11 @@ int retro_vfs_file_remove_impl(const char *path)
return 0;
}
#endif
return -1;
#elif defined(ORBIS)
/* Orbis
* TODO/FIXME - stub for now */
return 0;
#else
if (remove(path) == 0)
return 0;
return -1;
#endif
return -1;
}
int retro_vfs_file_rename_impl(const char *old_path, const char *new_path)
@ -860,13 +823,6 @@ int retro_vfs_file_rename_impl(const char *old_path, const char *new_path)
#endif
return ret;
#elif defined(ORBIS)
/* Orbis */
/* TODO/FIXME - Stub for now */
if (!old_path || !*old_path || !new_path || !*new_path)
return -1;
return 0;
#else
/* Every other platform */
if (!old_path || !*old_path || !new_path || !*new_path)
@ -888,7 +844,7 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
{
bool is_dir = false;
bool is_character_special = false;
#if defined(VITA) || defined(PSP)
#if defined(VITA)
/* Vita / PSP */
SceIoStat buf;
int dir_ret;
@ -901,7 +857,7 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
tmp = strdup(path);
len = strlen(tmp);
if (tmp[len-1] == '/')
tmp[len-1] = '\0';
tmp[len-1] = '\0';
dir_ret = sceIoGetstat(tmp, &buf);
free(tmp);
@ -912,21 +868,6 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
*size = (int32_t)buf.st_size;
is_dir = FIO_S_ISDIR(buf.st_mode);
#elif defined(ORBIS)
/* Orbis */
int dir_ret = 0;
if (!path || !*path)
return 0;
if (size)
*size = (int32_t)buf.st_size;
dir_ret = orbisDopen(path);
is_dir = dir_ret > 0;
orbisDclose(dir_ret);
is_character_special = S_ISCHR(buf.st_mode);
#elif defined(__PSL1GHT__) || defined(__PS3__)
/* Lowlevel Lv2 */
sysFSStat buf;
@ -992,12 +933,10 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
if (string_is_empty(path))
return 0;
path_buf = strdup(path);
if (!path_buf)
if (!(path_buf = strdup(path)))
return 0;
len = strlen(path_buf);
if (len > 0)
if ((len = strlen(path_buf)) > 0)
if (path_buf[len - 1] == '/')
path_buf[len - 1] = '\0';
@ -1033,7 +972,7 @@ int retro_vfs_stat_impl(const char *path, int32_t *size)
#if defined(VITA)
#define path_mkdir_error(ret) (((ret) == SCE_ERROR_ERRNO_EEXIST))
#elif defined(PSP) || defined(PS2) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(ORBIS)
#elif defined(PSP) || defined(PS2) || defined(_3DS) || defined(WIIU) || defined(SWITCH)
#define path_mkdir_error(ret) ((ret) == -1)
#else
#define path_mkdir_error(ret) ((ret) < 0 && errno == EEXIST)
@ -1056,13 +995,11 @@ int retro_vfs_mkdir_impl(const char *dir)
#endif
#elif defined(IOS)
int ret = mkdir(dir, 0755);
#elif defined(VITA) || defined(PSP)
#elif defined(VITA)
int ret = sceIoMkdir(dir, 0777);
#elif defined(ORBIS)
int ret = orbisMkdir(dir, 0755);
#elif defined(__QNX__)
int ret = mkdir(dir, 0777);
#elif defined(GEKKO)
#elif defined(GEKKO) || defined(WIIU)
/* On GEKKO platforms, mkdir() fails if
* the path has a trailing slash. We must
* therefore remove it. */
@ -1109,16 +1046,13 @@ struct libretro_vfs_implementation_dir
HANDLE directory;
bool next;
char path[PATH_MAX_LENGTH];
#elif defined(VITA) || defined(PSP)
#elif defined(VITA)
SceUID directory;
SceIoDirent entry;
#elif defined(__PSL1GHT__) || defined(__PS3__)
int error;
int directory;
sysFSDirent entry;
#elif defined(ORBIS)
int directory;
struct dirent entry;
#else
DIR *directory;
const struct dirent *entry;
@ -1129,7 +1063,7 @@ static bool dirent_check_error(libretro_vfs_implementation_dir *rdir)
{
#if defined(_WIN32)
return (rdir->directory == INVALID_HANDLE_VALUE);
#elif defined(VITA) || defined(PSP) || defined(ORBIS)
#elif defined(VITA) || defined(ORBIS)
return (rdir->directory < 0);
#elif defined(__PSL1GHT__) || defined(__PS3__)
return (rdir->error != FS_SUCCEEDED);
@ -1142,7 +1076,6 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
const char *name, bool include_hidden)
{
#if defined(_WIN32)
unsigned path_len;
char path_buf[1024];
size_t copied = 0;
#if defined(LEGACY_WIN32)
@ -1153,28 +1086,25 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
#endif
libretro_vfs_implementation_dir *rdir;
/*Reject null or empty string paths*/
/* Reject NULL or empty string paths*/
if (!name || (*name == 0))
return NULL;
/*Allocate RDIR struct. Tidied later with retro_closedir*/
rdir = (libretro_vfs_implementation_dir*)calloc(1, sizeof(*rdir));
if (!rdir)
if (!(rdir = (libretro_vfs_implementation_dir*)
calloc(1, sizeof(*rdir))))
return NULL;
rdir->orig_path = strdup(name);
#if defined(_WIN32)
path_buf[0] = '\0';
path_len = strlen(name);
copied = strlcpy(path_buf, name, sizeof(path_buf));
/* Non-NT platforms don't like extra slashes in the path */
if (name[path_len - 1] != '\\')
path_buf[copied++] = '\\';
if (path_buf[copied - 1] != '\\')
path_buf [copied++] = '\\';
path_buf[copied] = '*';
path_buf[copied ] = '*';
path_buf[copied+1] = '\0';
#if defined(LEGACY_WIN32)
@ -1191,15 +1121,13 @@ libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
free(path_wide);
#endif
#elif defined(VITA) || defined(PSP)
#elif defined(VITA)
rdir->directory = sceIoDopen(name);
#elif defined(_3DS)
rdir->directory = !string_is_empty(name) ? opendir(name) : NULL;
rdir->entry = NULL;
#elif defined(__PSL1GHT__) || defined(__PS3__)
rdir->error = sysFsOpendir(name, &rdir->directory);
#elif defined(ORBIS)
rdir->directory = orbisDopen(name);
#else
rdir->directory = opendir(name);
rdir->entry = NULL;
@ -1231,14 +1159,12 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
rdir->next = true;
return (rdir->directory != INVALID_HANDLE_VALUE);
#elif defined(VITA) || defined(PSP)
#elif defined(VITA)
return (sceIoDread(rdir->directory, &rdir->entry) > 0);
#elif defined(__PSL1GHT__) || defined(__PS3__)
uint64_t nread;
rdir->error = sysFsReaddir(rdir->directory, &rdir->entry, &nread);
return (nread != 0);
#elif defined(ORBIS)
return (orbisDread(rdir->directory, &rdir->entry) > 0);
#else
return ((rdir->entry = readdir(rdir->directory)) != NULL);
#endif
@ -1257,7 +1183,7 @@ const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir
if (name)
free(name);
return (char*)rdir->entry.cFileName;
#elif defined(VITA) || defined(PSP) || defined(ORBIS) || defined(__PSL1GHT__) || defined(__PS3__)
#elif defined(VITA) || defined(__PSL1GHT__) || defined(__PS3__)
return rdir->entry.d_name;
#else
if (!rdir || !rdir->entry)
@ -1271,22 +1197,12 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
#if defined(_WIN32)
const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
#elif defined(PSP) || defined(VITA)
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
#if defined(PSP)
return (entry->d_stat.st_attr & FIO_SO_IFDIR) == FIO_SO_IFDIR;
#elif defined(VITA)
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
return SCE_S_ISDIR(entry->d_stat.st_mode);
#endif
#elif defined(__PSL1GHT__) || defined(__PS3__)
sysFSDirent *entry = (sysFSDirent*)&rdir->entry;
return (entry->d_type == FS_TYPE_DIR);
#elif defined(ORBIS)
const struct dirent *entry = &rdir->entry;
if (entry->d_type == DT_DIR)
return true;
if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
return false;
#else
struct stat buf;
char path[PATH_MAX_LENGTH];
@ -1299,8 +1215,7 @@ bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
return false;
#endif
/* dirent struct doesn't have d_type, do it the slow way ... */
path[0] = '\0';
fill_pathname_join(path, rdir->orig_path, retro_vfs_dirent_get_name_impl(rdir), sizeof(path));
fill_pathname_join_special(path, rdir->orig_path, retro_vfs_dirent_get_name_impl(rdir), sizeof(path));
if (stat(path, &buf) < 0)
return false;
return S_ISDIR(buf.st_mode);
@ -1315,12 +1230,10 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
#if defined(_WIN32)
if (rdir->directory != INVALID_HANDLE_VALUE)
FindClose(rdir->directory);
#elif defined(VITA) || defined(PSP)
#elif defined(VITA)
sceIoDclose(rdir->directory);
#elif defined(__PSL1GHT__) || defined(__PS3__)
rdir->error = sysFsClosedir(rdir->directory);
#elif defined(ORBIS)
orbisDclose(rdir->directory);
#else
if (rdir->directory)
closedir(rdir->directory);

File diff suppressed because it is too large Load Diff