Compare commits

..
6 Commits
Author SHA1 Message Date
Themaister a4c901df57 Bit more logging when saving SRAM to be sure. 0.4! :D 2011-04-07 21:20:11 +02:00
Themaister f2cc19d1a7 Some fixups for SGB etc. 2011-04-07 21:06:31 +02:00
Themaister ad55829890 Convert to strlcpy/strlcat. More sane. 2011-04-03 22:29:36 +02:00
Themaister 6b8eea6363 Start with strlcpy/strlcat ... 2011-04-03 22:16:59 +02:00
Themaister b2d214ee79 Should fix path issues with UPS patching.
When filename had two dots ('.') in it,
using fill_pathname on g_extern.basename was wrong.
Added fill_pathname_noext to countermeasure this.
2011-04-03 21:43:25 +02:00
Themaister f5fb113563 Should fix case where we have 1 pass and scale attributes. 2011-03-30 23:09:29 +02:00
10 changed files with 164 additions and 81 deletions

No files matched your search

+5 -1
View File
@@ -2,7 +2,7 @@ include config.mk
TARGET = ssnes tools/ssnes-joyconfig
OBJ = ssnes.o file.o driver.o settings.o dynamic.o message.o rewind.o movie.o autosave.o gfx/gfx_common.o ups.o
OBJ = ssnes.o file.o driver.o settings.o dynamic.o message.o rewind.o movie.o autosave.o gfx/gfx_common.o ups.o strl.o
JOYCONFIG_OBJ = tools/ssnes-joyconfig.o conf/config_file.o
HEADERS = $(wildcard */*.h) $(wildcard *.h)
@@ -119,6 +119,10 @@ else
LIBS += $(libsnes)
endif
ifeq ($(HAVE_STRL), 1)
DEFINES += -DHAVE_STRL
endif
ifneq ($(V),1)
Q := @
endif
+1 -1
View File
@@ -1,6 +1,6 @@
TARGET = ssnes.exe
JTARGET = ssnes-joyconfig.exe
OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o message.o rewind.o movie.o autosave.o gfx/gfx_common.o ups.o
OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o message.o rewind.o movie.o autosave.o gfx/gfx_common.o ups.o strl.o
JOBJ = conf/config_file.o tools/main-stub.o tools/ssnes-joyconfig.o
CC = gcc
+10 -30
View File
@@ -24,6 +24,7 @@
#include "dynamic.h"
#include "movie.h"
#include "ups.h"
#include "strl.h"
#ifdef _WIN32
#include <io.h>
@@ -164,9 +165,9 @@ static ssize_t read_rom_file(FILE* file, void** buf)
}
}
else if (*g_extern.ups_name)
SSNES_LOG("Could not find UPS patch.\n");
SSNES_LOG("Could not find UPS patch in: \"%s\".\n", g_extern.ups_name);
// Remove SMC header if present.
// Remove copier header if present (512 first bytes).
if ((ret & 0x7fff) == 512)
{
memmove(ret_buf, ret_buf + 512, ret - 512);
@@ -257,7 +258,7 @@ void save_ram_file(const char* path, int type)
size_t size = psnes_get_memory_size(type);
uint8_t *data = psnes_get_memory_data(type);
if ( data && size > 0 )
if (data && size > 0)
dump_to_file(path, data, size);
}
@@ -276,14 +277,7 @@ static bool load_sgb_rom(void)
goto error;
}
extra_rom = fopen(g_extern.gb_rom_path, "rb");
if (!extra_rom)
{
SSNES_ERR("Couldn't open GameBoy ROM!\n");
goto error;
}
if ((extra_rom_len = read_rom_file(extra_rom, &extra_rom_buf)) == -1)
if ((extra_rom_len = read_file(g_extern.gb_rom_path, &extra_rom_buf)) == -1)
{
SSNES_ERR("Cannot read GameBoy rom.\n");
goto error;
@@ -330,14 +324,7 @@ static bool load_bsx_rom(bool slotted)
goto error;
}
extra_rom = fopen(g_extern.bsx_rom_path, "rb");
if (!extra_rom)
{
SSNES_ERR("Couldn't open BSX game rom!\n");
goto error;
}
if ((extra_rom_len = read_rom_file(extra_rom, &extra_rom_buf)) == -1)
if ((extra_rom_len = read_file(g_extern.bsx_rom_path, &extra_rom_buf)) == -1)
{
SSNES_ERR("Cannot read BSX game rom.\n");
goto error;
@@ -404,16 +391,9 @@ static bool load_sufami_rom(void)
{
if (strlen(roms[i]) > 0)
{
extra_rom[i] = fopen(roms[i], "rb");
if (!extra_rom[i])
if ((extra_rom_len[i] = read_file(roms[i], &extra_rom_buf[i])) == -1)
{
SSNES_ERR("Couldn't open BSX game rom!\n");
goto error;
}
if ((extra_rom_len[i] = read_rom_file(extra_rom[i], &extra_rom_buf[i])) == -1)
{
SSNES_ERR("Cannot read BSX game rom.\n");
SSNES_ERR("Cannot read Sufami game rom.\n");
goto error;
}
}
@@ -537,8 +517,8 @@ char** dir_list_new(const char *dir, const char *ext)
wchar_t wchar_buf[MAX_PATH + 1];
char utf8_buf[MAX_PATH + 3];
strncpy(utf8_buf, dir, MAX_PATH);
strcat(utf8_buf, "/*");
strlcpy(utf8_buf, dir, sizeof(utf8_buf));
strlcat(utf8_buf, "/*", sizeof(utf8_buf));
utf8_buf[MAX_PATH + 2] = '\0';
int ret = MultiByteToWideChar(CP_UTF8, 0, utf8_buf, strlen(utf8_buf), wchar_buf, MAX_PATH);
+13 -9
View File
@@ -320,7 +320,15 @@ static inline void gl_init_font(gl_t *gl, const char *font_path, unsigned font_s
static void gl_init_fbo(gl_t *gl, unsigned width, unsigned height)
{
#ifdef HAVE_FBO
if (!g_settings.video.render_to_texture && gl_shader_num() <= 1)
if (!g_settings.video.render_to_texture && gl_shader_num() == 0)
return;
struct gl_fbo_scale scale, scale_last;
gl_shader_scale(1, &scale);
gl_shader_scale(gl_shader_num(), &scale_last);
// No need to use FBOs.
if (gl_shader_num() == 1 && !scale.valid && !g_settings.video.render_to_texture)
return;
if (!load_fbo_proc())
@@ -330,13 +338,12 @@ static void gl_init_fbo(gl_t *gl, unsigned width, unsigned height)
}
gl->fbo_pass = gl_shader_num() - 1;
struct gl_fbo_scale scale;
gl_shader_scale(gl_shader_num(), &scale);
if (scale.valid)
if (scale_last.valid)
gl->fbo_pass++;
gl_shader_scale(1, &scale);
if (gl->fbo_pass <= 0)
gl->fbo_pass = 1;
if (!scale.valid)
{
scale.scale_x = g_settings.video.fbo_scale_x;
@@ -385,9 +392,6 @@ static void gl_init_fbo(gl_t *gl, unsigned width, unsigned height)
SSNES_LOG("Creating FBO 0 @ %ux%u\n", gl->fbo_rect[0].width, gl->fbo_rect[0].height);
if (gl->fbo_pass <= 0)
gl->fbo_pass = 1;
for (int i = 1; i < gl->fbo_pass; i++)
{
gl_shader_scale(i + 1, &gl->fbo_scale[i]);
+3 -1
View File
@@ -61,8 +61,10 @@ check_lib DYNAMIC -ldl dlopen
check_pkgconf FREETYPE freetype2
check_lib XVIDEO -lXv XvShmCreateImage
check_lib STRL -lc strlcpy
# Creates config.mk and config.h.
VARS="ALSA OSS AL RSOUND ROAR JACK PULSE SDL FILTER CG XML DYNAMIC FFMPEG AVCODEC AVFORMAT AVCORE AVUTIL SWSCALE SRC CONFIGFILE FREETYPE XVIDEO NETPLAY FBO"
VARS="ALSA OSS AL RSOUND ROAR JACK PULSE SDL FILTER CG XML DYNAMIC FFMPEG AVCODEC AVFORMAT AVCORE AVUTIL SWSCALE SRC CONFIGFILE FREETYPE XVIDEO NETPLAY FBO STRL"
create_config_make config.mk $VARS
create_config_header config.h $VARS
+1 -1
View File
@@ -1,7 +1,7 @@
. qb/qb.params.sh
PACKAGE_NAME=ssnes
PACKAGE_VERSION=0.4-beta
PACKAGE_VERSION=0.4
# Adds a command line opt to ./configure --help
# $1: Variable (HAVE_ALSA, HAVE_OSS, etc)
+6 -6
View File
@@ -18,7 +18,7 @@
#include "general.h"
#include "conf/config_file.h"
#include <assert.h>
#include <string.h>
#include "strl.h"
#include "config.def.h"
#ifdef HAVE_CONFIG_H
@@ -94,11 +94,11 @@ static void set_defaults(void)
}
if (def_video)
strncpy(g_settings.video.driver, def_video, sizeof(g_settings.video.driver) - 1);
strlcpy(g_settings.video.driver, def_video, sizeof(g_settings.video.driver));
if (def_audio)
strncpy(g_settings.audio.driver, def_audio, sizeof(g_settings.audio.driver) - 1);
strlcpy(g_settings.audio.driver, def_audio, sizeof(g_settings.audio.driver));
if (def_input)
strncpy(g_settings.input.driver, def_input, sizeof(g_settings.input.driver) - 1);
strlcpy(g_settings.input.driver, def_input, sizeof(g_settings.input.driver));
g_settings.video.xscale = xscale;
g_settings.video.yscale = yscale;
@@ -129,7 +129,7 @@ static void set_defaults(void)
g_settings.audio.in_rate = in_rate;
g_settings.audio.rate_step = audio_rate_step;
if (audio_device)
strncpy(g_settings.audio.device, audio_device, sizeof(g_settings.audio.device));
strlcpy(g_settings.audio.device, audio_device, sizeof(g_settings.audio.device));
g_settings.audio.latency = out_latency;
g_settings.audio.sync = audio_sync;
@@ -244,7 +244,7 @@ static config_file_t *open_default_config_file(void)
#define CONFIG_GET_STRING(var, key) do { \
if (config_get_string(conf, key, &tmp_str)) \
{ \
strncpy(g_settings.var, tmp_str, sizeof(g_settings.var) - 1); \
strlcpy(g_settings.var, tmp_str, sizeof(g_settings.var)); \
free(tmp_str); \
} \
} while(0)
+43 -32
View File
@@ -31,6 +31,7 @@
#include "rewind.h"
#include "movie.h"
#include "netplay.h"
#include "strl.h"
#include <assert.h>
#ifdef HAVE_SRC
#include <samplerate.h>
@@ -220,16 +221,22 @@ static int16_t input_state(bool port, unsigned device, unsigned index, unsigned
return res;
}
static void fill_pathname(char *out_path, char *in_path, const char *replace)
static void fill_pathname(char *out_path, const char *in_path, const char *replace, size_t size)
{
char tmp_path[strlen(in_path) + 1];
strcpy(tmp_path, in_path);
strlcpy(tmp_path, in_path, sizeof(tmp_path));
char *tok = NULL;
tok = strrchr(tmp_path, '.');
if (tok != NULL)
*tok = '\0';
strcpy(out_path, tmp_path);
strcat(out_path, replace);
assert(strlcpy(out_path, tmp_path, size) < size);
assert(strlcat(out_path, replace, size) < size);
}
static void fill_pathname_noext(char *out_path, const char *in_path, const char *replace, size_t size)
{
assert(strlcpy(out_path, in_path, size) < size);
assert(strlcat(out_path, replace, size) < size);
}
#ifdef _WIN32
@@ -241,7 +248,7 @@ static void fill_pathname(char *out_path, char *in_path, const char *replace)
#endif
#ifdef _WIN32
#define PACKAGE_VERSION "0.4-beta"
#define PACKAGE_VERSION "0.4"
#endif
#include "config.features.h"
@@ -320,7 +327,7 @@ static void set_basename(const char *path)
char *dst = strrchr(tmp, '.');
if (dst)
*dst = '\0';
strncpy(g_extern.basename, tmp, sizeof(g_extern.basename) - 1);
strlcpy(g_extern.basename, tmp, sizeof(g_extern.basename));
}
static void parse_input(int argc, char *argv[])
@@ -406,37 +413,37 @@ static void parse_input(int argc, char *argv[])
break;
case 's':
strncpy(g_extern.savefile_name_srm, optarg, sizeof(g_extern.savefile_name_srm) - 1);
strlcpy(g_extern.savefile_name_srm, optarg, sizeof(g_extern.savefile_name_srm));
g_extern.has_set_save_path = true;
break;
case 'g':
strncpy(g_extern.gb_rom_path, optarg, sizeof(g_extern.gb_rom_path) - 1);
strlcpy(g_extern.gb_rom_path, optarg, sizeof(g_extern.gb_rom_path));
g_extern.game_type = SSNES_CART_SGB;
break;
case 'b':
strncpy(g_extern.bsx_rom_path, optarg, sizeof(g_extern.bsx_rom_path) - 1);
strlcpy(g_extern.bsx_rom_path, optarg, sizeof(g_extern.bsx_rom_path));
g_extern.game_type = SSNES_CART_BSX;
break;
case 'B':
strncpy(g_extern.bsx_rom_path, optarg, sizeof(g_extern.bsx_rom_path) - 1);
strlcpy(g_extern.bsx_rom_path, optarg, sizeof(g_extern.bsx_rom_path));
g_extern.game_type = SSNES_CART_BSX_SLOTTED;
break;
case 'Y':
strncpy(g_extern.sufami_rom_path[0], optarg, sizeof(g_extern.sufami_rom_path[0]) - 1);
strlcpy(g_extern.sufami_rom_path[0], optarg, sizeof(g_extern.sufami_rom_path[0]));
g_extern.game_type = SSNES_CART_SUFAMI;
break;
case 'Z':
strncpy(g_extern.sufami_rom_path[1], optarg, sizeof(g_extern.sufami_rom_path[1]) - 1);
strlcpy(g_extern.sufami_rom_path[1], optarg, sizeof(g_extern.sufami_rom_path[1]));
g_extern.game_type = SSNES_CART_SUFAMI;
break;
case 'S':
strncpy(g_extern.savestate_name, optarg, sizeof(g_extern.savestate_name) - 1);
strlcpy(g_extern.savestate_name, optarg, sizeof(g_extern.savestate_name));
g_extern.has_set_state_path = true;
break;
@@ -461,19 +468,19 @@ static void parse_input(int argc, char *argv[])
#ifdef HAVE_CONFIGFILE
case 'c':
strncpy(g_extern.config_path, optarg, sizeof(g_extern.config_path) - 1);
strlcpy(g_extern.config_path, optarg, sizeof(g_extern.config_path));
break;
#endif
#ifdef HAVE_FFMPEG
case 'r':
strncpy(g_extern.record_path, optarg, sizeof(g_extern.record_path) - 1);
strlcpy(g_extern.record_path, optarg, sizeof(g_extern.record_path));
g_extern.recording = true;
break;
#endif
case 'P':
strncpy(g_extern.bsv_movie_path, optarg, sizeof(g_extern.bsv_movie_path) - 1);
strlcpy(g_extern.bsv_movie_path, optarg, sizeof(g_extern.bsv_movie_path));
g_extern.bsv_movie_playback = true;
break;
@@ -483,7 +490,7 @@ static void parse_input(int argc, char *argv[])
case 'C':
g_extern.netplay_enable = true;
strncpy(g_extern.netplay_server, optarg, sizeof(g_extern.netplay_server) - 1);
strlcpy(g_extern.netplay_server, optarg, sizeof(g_extern.netplay_server));
break;
case 'F':
@@ -493,7 +500,7 @@ static void parse_input(int argc, char *argv[])
break;
case 'U':
strncpy(g_extern.ups_name, optarg, sizeof(g_extern.ups_name) - 1);
strlcpy(g_extern.ups_name, optarg, sizeof(g_extern.ups_name));
break;
case 0:
@@ -530,9 +537,9 @@ static void parse_input(int argc, char *argv[])
}
// strl* would be nice :D
if (!g_extern.has_set_save_path)
fill_pathname(g_extern.savefile_name_srm, g_extern.basename, ".srm");
fill_pathname_noext(g_extern.savefile_name_srm, g_extern.basename, ".srm", sizeof(g_extern.savefile_name_srm));
if (!g_extern.has_set_state_path)
fill_pathname(g_extern.savestate_name, g_extern.basename, ".state");
fill_pathname_noext(g_extern.savestate_name, g_extern.basename, ".state", sizeof(g_extern.savestate_name));
}
else if (strlen(g_extern.savefile_name_srm) == 0)
{
@@ -619,22 +626,26 @@ static inline void save_files(void)
switch (g_extern.game_type)
{
case SSNES_CART_NORMAL:
SSNES_LOG("Saving regular SRAM.\n");
save_ram_file(g_extern.savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM);
save_ram_file(g_extern.savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC);
break;
case SSNES_CART_SGB:
SSNES_LOG("Saving Gameboy SRAM.\n");
save_ram_file(g_extern.savefile_name_srm, SNES_MEMORY_GAME_BOY_RAM);
save_ram_file(g_extern.savefile_name_rtc, SNES_MEMORY_GAME_BOY_RTC);
break;
case SSNES_CART_BSX:
case SSNES_CART_BSX_SLOTTED:
SSNES_LOG("Saving BSX (P)RAM.\n");
save_ram_file(g_extern.savefile_name_srm, SNES_MEMORY_BSX_RAM);
save_ram_file(g_extern.savefile_name_psrm, SNES_MEMORY_BSX_PRAM);
break;
case SSNES_CART_SUFAMI:
SSNES_LOG("Saving Sufami turbo A/B RAM.\n");
save_ram_file(g_extern.savefile_name_asrm, SNES_MEMORY_SUFAMI_TURBO_A_RAM);
save_ram_file(g_extern.savefile_name_bsrm, SNES_MEMORY_SUFAMI_TURBO_B_RAM);
break;
@@ -851,37 +862,37 @@ static void fill_pathnames(void)
case SSNES_CART_BSX_SLOTTED:
// BSX PSRM
if (!g_extern.has_set_save_path)
fill_pathname(g_extern.savefile_name_srm, g_extern.bsx_rom_path, ".srm");
fill_pathname(g_extern.savefile_name_srm, g_extern.bsx_rom_path, ".srm", sizeof(g_extern.savefile_name_srm));
if (!g_extern.has_set_state_path)
fill_pathname(g_extern.savestate_name, g_extern.bsx_rom_path, ".state");
fill_pathname(g_extern.savefile_name_psrm, g_extern.savefile_name_srm, ".psrm");
fill_pathname(g_extern.savestate_name, g_extern.bsx_rom_path, ".state", sizeof(g_extern.savestate_name));
fill_pathname(g_extern.savefile_name_psrm, g_extern.savefile_name_srm, ".psrm", sizeof(g_extern.savefile_name_psrm));
break;
case SSNES_CART_SUFAMI:
// SUFAMI ARAM
fill_pathname(g_extern.savefile_name_asrm, g_extern.savefile_name_srm, ".asrm");
fill_pathname(g_extern.savefile_name_asrm, g_extern.savefile_name_srm, ".asrm", sizeof(g_extern.savefile_name_asrm));
// SUFAMI BRAM
fill_pathname(g_extern.savefile_name_bsrm, g_extern.savefile_name_srm, ".bsrm");
fill_pathname(g_extern.savefile_name_bsrm, g_extern.savefile_name_srm, ".bsrm", sizeof(g_extern.savefile_name_bsrm));
break;
case SSNES_CART_SGB:
if (!g_extern.has_set_save_path)
fill_pathname(g_extern.savefile_name_srm, g_extern.gb_rom_path, ".srm");
fill_pathname(g_extern.savefile_name_srm, g_extern.gb_rom_path, ".srm", sizeof(g_extern.savefile_name_srm));
if (!g_extern.has_set_state_path)
fill_pathname(g_extern.savestate_name, g_extern.gb_rom_path, ".state");
fill_pathname(g_extern.savefile_name_rtc, g_extern.savefile_name_srm, ".rtc");
fill_pathname(g_extern.savestate_name, g_extern.gb_rom_path, ".state", sizeof(g_extern.savestate_name));
fill_pathname(g_extern.savefile_name_rtc, g_extern.savefile_name_srm, ".rtc", sizeof(g_extern.savefile_name_rtc));
break;
default:
// Infer .rtc save path from save ram path.
fill_pathname(g_extern.savefile_name_rtc, g_extern.savefile_name_srm, ".rtc");
fill_pathname(g_extern.savefile_name_rtc, g_extern.savefile_name_srm, ".rtc", sizeof(g_extern.savefile_name_rtc));
}
if (!g_extern.bsv_movie_playback)
fill_pathname(g_extern.bsv_movie_path, g_extern.savefile_name_srm, "");
fill_pathname(g_extern.bsv_movie_path, g_extern.savefile_name_srm, "", sizeof(g_extern.bsv_movie_path));
if (!(*g_extern.ups_name) && *g_extern.basename)
fill_pathname(g_extern.ups_name, g_extern.basename, ".ups");
fill_pathname_noext(g_extern.ups_name, g_extern.basename, ".ups", sizeof(g_extern.ups_name));
}
// Save or load state here.
@@ -1188,7 +1199,7 @@ static void check_shader_dir(void)
{
const char *shader = g_extern.shader_dir.elems[g_extern.shader_dir.ptr];
strncpy(g_settings.video.bsnes_shader_path, shader, sizeof(g_settings.video.bsnes_shader_path) - 1);
strlcpy(g_settings.video.bsnes_shader_path, shader, sizeof(g_settings.video.bsnes_shader_path));
g_settings.video.shader_type = SSNES_SHADER_BSNES;
msg_queue_clear(g_extern.msg_queue);
+47
View File
@@ -0,0 +1,47 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "strl.h"
#ifndef HAVE_STRL
// Implementation of strlcpy()/strlcat() based on OpenBSD.
size_t strlcpy(char *dest, const char *source, size_t size)
{
size_t src_size = 0;
size_t n = size;
if (n)
while (--n && (*dest++ = *source++)) src_size++;
if (!n)
{
if (size) *dest = '\0';
while (*source++) src_size++;
}
return src_size;
}
size_t strlcat(char *dest, const char *source, size_t size)
{
size_t len = strlen(dest);
dest += len;
size -= len;
return len + strlcpy(dest, source, size);
}
#endif
+35
View File
@@ -0,0 +1,35 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSNES_STRL_H
#define __SSNES_STRL_H
#include <string.h>
#include <stddef.h>
#include "config.h"
#ifndef HAVE_STRL
// Avoid possible naming collitions during link since we prefer to use the actual name.
#define strlcpy(dst, src, size) __strlcpy_ssnes(dst, src, size)
#define strlcat(dst, src, size) __strlcat_ssnes(dst, src, size)
size_t strlcpy(char *dest, const char *source, size_t size);
size_t strlcat(char *dest, const char *source, size_t size);
#endif
#endif