mirror of
https://github.com/libretro/beetle-psx-libretro.git
synced 2024-11-27 02:40:31 +00:00
Update libretro-common
This commit is contained in:
parent
6094309d1c
commit
b1cb46f92e
@ -24,7 +24,7 @@
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#include <retro_common.h>
|
||||
#if _MSC_VER >= 1900
|
||||
#if _MSC_VER >= 1800
|
||||
#include <stdio.h> /* added for _vsnprintf_s and _vscprintf on VS2015 and VS2017 */
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
@ -55,13 +55,19 @@ int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list
|
||||
|
||||
if (size != 0)
|
||||
#if (_MSC_VER <= 1310)
|
||||
count = _vsnprintf(outBuf, size, format, ap);
|
||||
count = _vsnprintf(outBuf, size - 1, format, ap);
|
||||
#else
|
||||
count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
|
||||
count = _vsnprintf_s(outBuf, size, size - 1, format, ap);
|
||||
#endif
|
||||
if (count == -1)
|
||||
count = _vscprintf(format, ap);
|
||||
|
||||
if (count == size)
|
||||
{
|
||||
/* there was no room for a NULL, so truncate the last character */
|
||||
outBuf[size - 1] = '\0';
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -107,6 +107,13 @@ if __name__ == '__main__':
|
||||
f.write('typedef GLint GLfixed;\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#if defined(OSX) && !defined(MAC_OS_X_VERSION_10_7)\n')
|
||||
f.write('typedef long long int GLint64;\n')
|
||||
f.write('typedef unsigned long long int GLuint64;\n')
|
||||
f.write('typedef unsigned long long int GLuint64EXT;\n')
|
||||
f.write('typedef struct __GLsync *GLsync;\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
dump(f, typedefs)
|
||||
dump(f, overrides)
|
||||
dump(f, externs)
|
||||
|
@ -33,6 +33,19 @@ RETRO_BEGIN_DECLS
|
||||
#define glTexCoord2f rglTexCoord2f
|
||||
|
||||
/* more forward-compatible GL subset symbols */
|
||||
#define glGetInteger64v rglGetInteger64v
|
||||
#define glGenSamplers rglGenSamplers
|
||||
#define glBindSampler rglBindSampler
|
||||
#define glSamplerParameteri rglSamplerParameteri
|
||||
#define glGetBufferSubData rglGetBufferSubData
|
||||
#define glUniform2iv rglUniform2iv
|
||||
#define glUniform2uiv rglUniform2uiv
|
||||
#define glTextureView rglTextureView
|
||||
#define glGetQueryObjectuiv rglGetQueryObjectuiv
|
||||
#define glGenQueries rglGenQueries
|
||||
#define glDeleteQueries rglDeleteQueries
|
||||
#define glBeginQuery rglBeginQuery
|
||||
#define glEndQuery rglEndQuery
|
||||
#define glBlitFramebuffer rglBlitFramebuffer
|
||||
#define glVertexAttrib4f rglVertexAttrib4f
|
||||
#define glVertexAttrib4fv rglVertexAttrib4fv
|
||||
@ -135,13 +148,14 @@ RETRO_BEGIN_DECLS
|
||||
#define glUniformBlockBinding rglUniformBlockBinding
|
||||
#define glGetUniformBlockIndex rglGetUniformBlockIndex
|
||||
#define glGetActiveUniformBlockiv rglGetActiveUniformBlockiv
|
||||
#define glBindBufferBase rglBindBufferBase
|
||||
#define glBindBufferBase rglBindBufferBase
|
||||
#define glGetUniformIndices rglGetUniformIndices
|
||||
#define glGetActiveUniformsiv rglGetActiveUniformsiv
|
||||
#define glGetError rglGetError
|
||||
#define glClear rglClear
|
||||
#define glPolygonMode rglPolygonMode
|
||||
#define glLineWidth rglLineWidth
|
||||
#define glTexImage3D rglTexImage3D
|
||||
#define glTexImage2DMultisample rglTexImage2DMultisample
|
||||
#define glTexStorage2DMultisample rglTexStorage2DMultisample
|
||||
#define glMemoryBarrier rglMemoryBarrier
|
||||
@ -329,6 +343,27 @@ void rglVertexAttrib4f(GLuint name, GLfloat x, GLfloat y,
|
||||
void rglVertexAttrib4fv(GLuint name, GLfloat* v);
|
||||
void rglDeleteProgram(GLuint program);
|
||||
void rglDeleteBuffers(GLsizei n, const GLuint *buffers);
|
||||
void rglUniform2uiv( GLint location,
|
||||
GLsizei count,
|
||||
const GLuint *value);
|
||||
void rglTextureView( GLuint texture,
|
||||
GLenum target,
|
||||
GLuint origtexture,
|
||||
GLenum internalformat,
|
||||
GLuint minlevel,
|
||||
GLuint numlevels,
|
||||
GLuint minlayer,
|
||||
GLuint numlayers);
|
||||
void rglGenQueries( GLsizei n,
|
||||
GLuint * ids);
|
||||
void rglDeleteQueries( GLsizei n,
|
||||
const GLuint * ids);
|
||||
void rglBeginQuery( GLenum target,
|
||||
GLuint id);
|
||||
void rglEndQuery( GLenum target);
|
||||
void rglGetQueryObjectuiv( GLuint id,
|
||||
GLenum pname,
|
||||
GLuint * params);
|
||||
void rglBlitFramebuffer(
|
||||
GLint srcX0, GLint srcY0,
|
||||
GLint srcX1, GLint srcY1,
|
||||
@ -383,6 +418,16 @@ GLenum rglGetError(void);
|
||||
void rglClear(GLbitfield mask);
|
||||
void rglPolygonMode(GLenum face, GLenum mode);
|
||||
void rglLineWidth(GLfloat width);
|
||||
void rglTexImage3D( GLenum target,
|
||||
GLint level,
|
||||
GLint internalFormat,
|
||||
GLsizei width,
|
||||
GLsizei height,
|
||||
GLsizei depth,
|
||||
GLint border,
|
||||
GLenum format,
|
||||
GLenum type,
|
||||
const GLvoid * data);
|
||||
void rglTexImage2DMultisample( GLenum target,
|
||||
GLsizei samples,
|
||||
GLenum internalformat,
|
||||
@ -408,6 +453,22 @@ void rglFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length
|
||||
GLenum rglClientWaitSync(void *sync, GLbitfield flags, uint64_t timeout);
|
||||
void rglDrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
|
||||
GLvoid *indices, GLint basevertex);
|
||||
void rglGetBufferSubData( GLenum target,
|
||||
GLintptr offset,
|
||||
GLsizeiptr size,
|
||||
GLvoid * data);
|
||||
void rglSamplerParameteri( GLuint sampler,
|
||||
GLenum pname,
|
||||
GLint param);
|
||||
void rglBindSampler( GLuint unit,
|
||||
GLuint sampler);
|
||||
void rglGenSamplers( GLsizei n,
|
||||
GLuint *samplers);
|
||||
void rglGetInteger64v( GLenum pname,
|
||||
int64_t * data);
|
||||
void rglUniform2iv( GLint location,
|
||||
GLsizei count,
|
||||
const GLint *value);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
|
@ -599,9 +599,12 @@ enum retro_mod
|
||||
* GET_VARIABLE.
|
||||
* This allows the frontend to present these variables to
|
||||
* a user dynamically.
|
||||
* This should be called as early as possible (ideally in
|
||||
* retro_set_environment).
|
||||
*
|
||||
* This should be called the first time as early as
|
||||
* possible (ideally in retro_set_environment).
|
||||
* Afterward it may be called again for the core to communicate
|
||||
* updated options to the frontend, but the number of core
|
||||
* options must not change from the number in the initial call.
|
||||
*
|
||||
* 'data' points to an array of retro_variable structs
|
||||
* terminated by a { NULL, NULL } element.
|
||||
* retro_variable::key should be namespaced to not collide
|
||||
@ -775,17 +778,18 @@ enum retro_mod
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31
|
||||
/* const char ** --
|
||||
* Returns the "save" directory of the frontend.
|
||||
* This directory can be used to store SRAM, memory cards,
|
||||
* high scores, etc, if the libretro core
|
||||
* Returns the "save" directory of the frontend, unless there is no
|
||||
* save directory available. The save directory should be used to
|
||||
* store SRAM, memory cards, high scores, etc, if the libretro core
|
||||
* cannot use the regular memory interface (retro_get_memory_data()).
|
||||
*
|
||||
* NOTE: libretro cores used to check GET_SYSTEM_DIRECTORY for
|
||||
* similar things before.
|
||||
* They should still check GET_SYSTEM_DIRECTORY if they want to
|
||||
* be backwards compatible.
|
||||
* The path here can be NULL. It should only be non-NULL if the
|
||||
* frontend user has set a specific save path.
|
||||
* If the frontend cannot designate a save directory, it will return
|
||||
* NULL to indicate that the core should attempt to operate without a
|
||||
* save directory set.
|
||||
*
|
||||
* NOTE: early libretro cores used the system directory for save
|
||||
* files. Cores that need to be backwards-compatible can still check
|
||||
* GET_SYSTEM_DIRECTORY.
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32
|
||||
/* const struct retro_system_av_info * --
|
||||
@ -853,26 +857,39 @@ enum retro_mod
|
||||
#define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35
|
||||
/* const struct retro_controller_info * --
|
||||
* This environment call lets a libretro core tell the frontend
|
||||
* which controller types are recognized in calls to
|
||||
* which controller subclasses are recognized in calls to
|
||||
* retro_set_controller_port_device().
|
||||
*
|
||||
* Some emulators such as Super Nintendo
|
||||
* support multiple lightgun types which must be specifically
|
||||
* selected from.
|
||||
* It is therefore sometimes necessary for a frontend to be able
|
||||
* to tell the core about a special kind of input device which is
|
||||
* not covered by the libretro input API.
|
||||
* Some emulators such as Super Nintendo support multiple lightgun
|
||||
* types which must be specifically selected from. It is therefore
|
||||
* sometimes necessary for a frontend to be able to tell the core
|
||||
* about a special kind of input device which is not specifcally
|
||||
* provided by the Libretro API.
|
||||
*
|
||||
* In order for a frontend to understand the workings of an input device,
|
||||
* it must be a specialized type
|
||||
* of the generic device types already defined in the libretro API.
|
||||
* In order for a frontend to understand the workings of those devices,
|
||||
* they must be defined as a specialized subclass of the generic device
|
||||
* types already defined in the libretro API.
|
||||
*
|
||||
* Which devices are supported can vary per input port.
|
||||
* The core must pass an array of const struct retro_controller_info which
|
||||
* is terminated with a blanked out struct. Each element of the struct
|
||||
* corresponds to an ascending port index to
|
||||
* retro_set_controller_port_device().
|
||||
* Even if special device types are set in the libretro core,
|
||||
* is terminated with a blanked out struct. Each element of the
|
||||
* retro_controller_info struct corresponds to the ascending port index
|
||||
* that is passed to retro_set_controller_port_device() when that function
|
||||
* is called to indicate to the core that the frontend has changed the
|
||||
* active device subclass. SEE ALSO: retro_set_controller_port_device()
|
||||
*
|
||||
* The ascending input port indexes provided by the core in the struct
|
||||
* are generally presented by frontends as ascending User # or Player #,
|
||||
* such as Player 1, Player 2, Player 3, etc. Which device subclasses are
|
||||
* supported can vary per input port.
|
||||
*
|
||||
* The first inner element of each entry in the retro_controller_info array
|
||||
* is a retro_controller_description struct that specifies the names and
|
||||
* codes of all device subclasses that are available for the corresponding
|
||||
* User or Player, beginning with the generic Libretro device that the
|
||||
* subclasses are derived from. The second inner element of each entry is the
|
||||
* total number of subclasses that are listed in the retro_controller_description.
|
||||
*
|
||||
* NOTE: Even if special device types are set in the libretro core,
|
||||
* libretro should only poll input based on the base input device types.
|
||||
*/
|
||||
#define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
@ -1159,6 +1176,41 @@ struct retro_led_interface
|
||||
* * State will never be saved when using Hard Disable Audio.
|
||||
*/
|
||||
|
||||
#define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* struct retro_midi_interface ** --
|
||||
* Returns a MIDI interface that can be used for raw data I/O.
|
||||
*/
|
||||
|
||||
/* Retrieves the current state of the MIDI input.
|
||||
* Returns true if it's enabled, false otherwise. */
|
||||
typedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void);
|
||||
|
||||
/* Retrieves the current state of the MIDI output.
|
||||
* Returns true if it's enabled, false otherwise */
|
||||
typedef bool (RETRO_CALLCONV *retro_midi_output_enabled_t)(void);
|
||||
|
||||
/* Reads next byte from the input stream.
|
||||
* Returns true if byte is read, false otherwise. */
|
||||
typedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t *byte);
|
||||
|
||||
/* Writes byte to the output stream.
|
||||
* 'delta_time' is in microseconds and represent time elapsed since previous write.
|
||||
* Returns true if byte is written, false otherwise. */
|
||||
typedef bool (RETRO_CALLCONV *retro_midi_write_t)(uint8_t byte, uint32_t delta_time);
|
||||
|
||||
/* Flushes previously written data.
|
||||
* Returns true if successful, false otherwise. */
|
||||
typedef bool (RETRO_CALLCONV *retro_midi_flush_t)(void);
|
||||
|
||||
struct retro_midi_interface
|
||||
{
|
||||
retro_midi_input_enabled_t input_enabled;
|
||||
retro_midi_output_enabled_t output_enabled;
|
||||
retro_midi_read_t read;
|
||||
retro_midi_write_t write;
|
||||
retro_midi_flush_t flush;
|
||||
};
|
||||
|
||||
#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* const struct retro_hw_render_interface ** --
|
||||
* Returns an API specific rendering interface for accessing API specific data.
|
||||
@ -2333,7 +2385,13 @@ RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info);
|
||||
* will only poll input based on that particular device type. It is only a
|
||||
* hint to the libretro core when a core cannot automatically detect the
|
||||
* appropriate input device type on its own. It is also relevant when a
|
||||
* core can change its behavior depending on device type. */
|
||||
* core can change its behavior depending on device type.
|
||||
*
|
||||
* As part of the core's implementation of retro_set_controller_port_device,
|
||||
* the core should call RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS to notify the
|
||||
* frontend if the descriptions for any controls have changed as a
|
||||
* result of changing the device type.
|
||||
*/
|
||||
RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device);
|
||||
|
||||
/* Resets the current game. */
|
||||
@ -2365,7 +2423,9 @@ RETRO_API bool retro_unserialize(const void *data, size_t size);
|
||||
RETRO_API void retro_cheat_reset(void);
|
||||
RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code);
|
||||
|
||||
/* Loads a game. */
|
||||
/* Loads a game.
|
||||
* Return true to indicate successful loading and false to indicate load failure.
|
||||
*/
|
||||
RETRO_API bool retro_load_game(const struct retro_game_info *game);
|
||||
|
||||
/* Loads a "special" kind of game. Should not be used,
|
||||
@ -2375,7 +2435,7 @@ RETRO_API bool retro_load_game_special(
|
||||
const struct retro_game_info *info, size_t num_info
|
||||
);
|
||||
|
||||
/* Unloads a currently loaded game. */
|
||||
/* Unloads the currently loaded game. Called before retro_deinit(void). */
|
||||
RETRO_API void retro_unload_game(void);
|
||||
|
||||
/* Gets region of game. */
|
||||
|
@ -73,6 +73,34 @@ printf("This is C++, version %d.\n", __cplusplus);
|
||||
/* This is not standard C. __STDC__ is not defined. */
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
|
||||
/* Try to find out if we're compiling for WinRT or non-WinRT */
|
||||
#if defined(_MSC_VER) && defined(__has_include)
|
||||
#if __has_include(<winapifamily.h>)
|
||||
#define HAVE_WINAPIFAMILY_H 1
|
||||
#else
|
||||
#define HAVE_WINAPIFAMILY_H 0
|
||||
#endif
|
||||
|
||||
/* If _USING_V110_SDK71_ is defined it means we are using the Windows XP toolset. */
|
||||
#elif defined(_MSC_VER) && (_MSC_VER >= 1700 && !_USING_V110_SDK71_) /* _MSC_VER == 1700 for Visual Studio 2012 */
|
||||
#define HAVE_WINAPIFAMILY_H 1
|
||||
#else
|
||||
#define HAVE_WINAPIFAMILY_H 0
|
||||
#endif
|
||||
|
||||
#if HAVE_WINAPIFAMILY_H
|
||||
#include <winapifamily.h>
|
||||
#define WINAPI_FAMILY_WINRT (!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP))
|
||||
#else
|
||||
#define WINAPI_FAMILY_WINRT 0
|
||||
#endif /* HAVE_WINAPIFAMILY_H */
|
||||
|
||||
#if WINAPI_FAMILY_WINRT
|
||||
#undef __WINRT__
|
||||
#define __WINRT__ 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -155,4 +155,18 @@ typedef struct
|
||||
uint32_t data[8];
|
||||
} retro_bits_t;
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef _WIN64
|
||||
# define PRI_SIZET PRIu64
|
||||
# else
|
||||
#if _MSC_VER == 1800
|
||||
# define PRI_SIZET PRIu32
|
||||
#else
|
||||
# define PRI_SIZET "u"
|
||||
#endif
|
||||
# endif
|
||||
#else
|
||||
# define PRI_SIZET "zu"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -78,6 +78,8 @@ char *filestream_gets(RFILE *stream, char *s, size_t len);
|
||||
|
||||
int filestream_getc(RFILE *stream);
|
||||
|
||||
int filestream_scanf(RFILE *stream, const char* format, ...);
|
||||
|
||||
int filestream_eof(RFILE *stream);
|
||||
|
||||
bool filestream_write_file(const char *path, const void *data, int64_t size);
|
||||
|
@ -45,7 +45,10 @@ static INLINE bool string_is_equal(const char *a, const char *b)
|
||||
if (!a || !b)
|
||||
return false;
|
||||
while(*a && (*a == *b))
|
||||
a++, b++;
|
||||
{
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
return (*(const unsigned char*)a - *(const unsigned char*)b) == 0;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@ -191,6 +192,98 @@ int filestream_getc(RFILE *stream)
|
||||
return EOF;
|
||||
}
|
||||
|
||||
int filestream_scanf(RFILE *stream, const char* format, ...)
|
||||
{
|
||||
char buf[4096];
|
||||
char subfmt[64];
|
||||
va_list args;
|
||||
|
||||
const char * bufiter = buf;
|
||||
int64_t startpos = filestream_tell(stream);
|
||||
int ret = 0;
|
||||
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
|
||||
|
||||
buf[maxlen] = '\0';
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
while (*format)
|
||||
{
|
||||
if (*format == '%')
|
||||
{
|
||||
int sublen;
|
||||
|
||||
char* subfmtiter = subfmt;
|
||||
bool asterisk = false;
|
||||
|
||||
*subfmtiter++ = *format++; /* '%' */
|
||||
|
||||
/* %[*][width][length]specifier */
|
||||
|
||||
if (*format == '*')
|
||||
{
|
||||
asterisk = true;
|
||||
*subfmtiter++ = *format++;
|
||||
}
|
||||
|
||||
while (isdigit(*format)) *subfmtiter++ = *format++; /* width */
|
||||
|
||||
/* length */
|
||||
if (*format == 'h' || *format == 'l')
|
||||
{
|
||||
if (format[1] == format[0]) *subfmtiter++ = *format++;
|
||||
*subfmtiter++ = *format++;
|
||||
}
|
||||
else if (*format == 'j' || *format == 'z' || *format == 't' || *format == 'L')
|
||||
{
|
||||
*subfmtiter++ = *format++;
|
||||
}
|
||||
|
||||
/* specifier - always a single character (except ]) */
|
||||
if (*format == '[')
|
||||
{
|
||||
while (*format != ']') *subfmtiter++ = *format++;
|
||||
*subfmtiter++ = *format++;
|
||||
}
|
||||
else *subfmtiter++ = *format++;
|
||||
|
||||
*subfmtiter++ = '%';
|
||||
*subfmtiter++ = 'n';
|
||||
*subfmtiter++ = '\0';
|
||||
|
||||
if (sizeof(void*) != sizeof(long*)) abort(); /* all pointers must have the same size */
|
||||
if (asterisk)
|
||||
{
|
||||
if (sscanf(bufiter, subfmt, &sublen) != 0) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sscanf(bufiter, subfmt, va_arg(args, void*), &sublen) != 1) break;
|
||||
}
|
||||
|
||||
ret++;
|
||||
bufiter += sublen;
|
||||
}
|
||||
else if (isspace(*format))
|
||||
{
|
||||
while (isspace(*bufiter)) bufiter++;
|
||||
format++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*bufiter != *format)
|
||||
break;
|
||||
bufiter++;
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
filestream_seek(stream, startpos+(bufiter-buf), RETRO_VFS_SEEK_POSITION_START);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
|
||||
{
|
||||
int64_t output;
|
||||
|
@ -109,7 +109,10 @@ char *string_trim_whitespace_left(char *const s)
|
||||
char *cur = s;
|
||||
|
||||
while(*cur && isspace((unsigned char)*cur))
|
||||
++cur, --len;
|
||||
{
|
||||
++cur;
|
||||
--len;
|
||||
}
|
||||
|
||||
if(s != cur)
|
||||
memmove(s, cur, len + 1);
|
||||
@ -128,7 +131,10 @@ char *string_trim_whitespace_right(char *const s)
|
||||
char *cur = s + len - 1;
|
||||
|
||||
while(cur != s && isspace((unsigned char)*cur))
|
||||
--cur, --len;
|
||||
{
|
||||
--cur;
|
||||
--len;
|
||||
}
|
||||
|
||||
cur[isspace((unsigned char)*cur) ? 0 : 1] = '\0';
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user