use SceAppSettings instead of custom ui

This commit is contained in:
olebeck 2025-08-10 12:25:55 +02:00
parent 0ed1850509
commit 3644ddc02f
17 changed files with 2651 additions and 348 deletions

View File

@ -1 +0,0 @@
/build/

View File

@ -12,6 +12,27 @@ FetchContent_Declare(
)
FetchContent_MakeAvailable(ScePaf_External)
add_subdirectory(SceIniFileProcessor)
add_library(iniparser_paf
iniparser_paf/src/dictionary.c
iniparser_paf/src/iniparser.c
)
target_link_libraries(iniparser_paf
ScePafStdc_stub
SceLibKernel_stub
SceLibc_stub
)
target_include_directories(iniparser_paf PUBLIC
iniparser_paf/src/
)
target_compile_options(iniparser_paf PRIVATE
-Wl,-q -Wall -fno-builtin -fshort-wchar -Wno-unused-function -Wno-sign-compare
)
add_executable(isle-config
src/app.cpp
src/main.cpp
@ -22,7 +43,7 @@ set_target_properties(isle-config PROPERTIES
)
target_compile_options(isle-config PRIVATE
-fno-rtti -fno-exceptions -Wl,-q -Wall -fno-builtin -fshort-wchar -Wno-unused-function -Wno-sign-compare
-fno-rtti -fno-exceptions -Wl,-q -Wall -fno-builtin -fshort-wchar -Wno-unused-function -Wno-sign-compare -fno-use-cxa-atexit
)
target_link_options(isle-config PRIVATE
@ -39,16 +60,23 @@ target_link_libraries(isle-config PRIVATE
ScePafWidget_stub
ScePafCommon_stub
ScePafStdc_stub
SceAppSettings_stub
SceFios2_stub
#Isle::iniparser
iniparser_paf
)
block()
vita_create_self(isle-config.self isle-config
CONFIG exports.yml
UNSAFE
STRIPPED
REL_OPTIMIZE
)
endblock()
target_include_directories(isle-config PUBLIC
include
)
vita_create_self(isle-config.self isle-config
CONFIG exports.yml
UNSAFE
STRIPPED
REL_OPTIMIZE
)
include(${scepaf_external_SOURCE_DIR}/rco.cmake)
make_rco(cxml/config_plugin.xml config_plugin.rco)

View File

@ -1,265 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml-model href="https://raw.githubusercontent.com/olebeck/paf-rcd/refs/heads/master/rco.xsd" type="application/xml" schematypens="http://www.w3.org/2001/XMLSchema"?>
<resource version="0.1" type="normal" id="config_plugin">
<filetable>
<file src="settings.xml" type="application/xml" id="settings.xml" compress="off" />
</filetable>
<pagetable>
<page id="page_main">
<plane style="_common_style_plane_transparent">
<layout_hint size="960, 544" />
<box> <!-- horizontal -->
<layout_box adjust="1, 1" layout_type="2" />
<plane texture="tex_shark" id="shark_image">
<layout_hint pos="0, 0" size="203, 544" align="1, 0" anchor="1, 0" />
</plane>
<plane texture="tex_settings_bg">
<layout_hint adjust="1, 1" />
<template_ref id="config_page_main" template="config_main"/>
<plane id="bottom_buttons" style="_common_style_plane_transparent"> <!-- bottom buttons -->
<layout_hint adjust="1, 0" size="0, 75" anchor="0, 1" align="0, 1" />
<box style="_common_default_style_box">
<layout_box space="20" layout_type="2" />
<button style="style_save_and_exit_button" id="save_exit_button"
label="msg_save_exit">
<layout_hint adjust="2, 2" />
</button>
<button style="style_save_and_launch_button" id="start_game_button"
label="msg_save_launch">
<layout_hint adjust="2, 2" />
</button>
<button style="style_exit_button" id="exit_button" label="msg_exit">
<layout_hint adjust="2, 2" />
</button>
</box>
</plane>
</plane>
</box>
</plane>
</page>
</pagetable>
<templatetable>
<template id="config_main">
<scroll_view style="_common_style_scroll_view_transparent"
w_sbar_v="vertical_scroll_bar" snap_anim_time="0">
<layout_hint adjust="1, 1" align="0, 1" anchor="0, 1"/>
<box> <!-- vertical scroll -->
<layout_box layout_type="1" space="40" adjust="1, 2" left_margin="20" right_margin="20"/>
<plane style="_common_style_plane_transparent"> <!-- spacing for tabs on top -->
<layout_hint size="0, 0" adjust="1, 0" />
</plane>
<box> <!-- Island Texture Quality -->
<layout_box layout_type="1" space="25"/>
<text label="msg_island_texture">
<layout_hint adjust="2, 2" />
</text>
<radio_box style="_common_default_style_radio_box">
<layout_hint adjust="2, 2" />
<box>
<layout_box layout_type="2" space="15" adjust="2, 2" />
<radio_button style="_common_default_style_radio_button">
<layout_hint size="44, 44" />
</radio_button>
<text label="msg_quality_low">
<layout_hint adjust="2, 2" />
</text>
<radio_button style="_common_default_style_radio_button">
<layout_hint size="44, 44" />
</radio_button>
<text label="msg_quality_medium">
<layout_hint adjust="2, 2" />
</text>
<radio_button style="_common_default_style_radio_button">
<layout_hint size="44, 44" />
</radio_button>
<text label="msg_quality_high">
<layout_hint adjust="2, 2" />
</text>
</box>
</radio_box>
</box>
<box> <!-- Island Model Quality -->
<layout_box layout_type="1" space="25"/>
<text label="msg_island_quality">
<layout_hint adjust="2, 2" />
</text>
<radio_box style="_common_default_style_radio_box">
<box>
<layout_box layout_type="2" space="15" />
<radio_button style="_common_default_style_radio_button">
<layout_hint size="44, 44" />
</radio_button>
<text label="msg_texture_fast">
<layout_hint adjust="2, 2" />
</text>
<radio_button style="_common_default_style_radio_button">
<layout_hint size="44, 44" />
</radio_button>
<text label="msg_texture_high">
<layout_hint adjust="2, 2" />
</text>
</box>
</radio_box>
</box>
<box> <!-- sliders -->
<layout_box layout_type="2" space="40" />
<box> <!-- Max LOD -->
<layout_box layout_type="1" space="20" />
<text label="msg_max_lod">
<layout_hint adjust="2, 2" />
</text>
<plane>
<layout_hint adjust="2, 2" />
<slidebar style="_common_default_style_slidebar" slider_label_margin="20"
slider_label_mode="1" slider_size="64, 64, 0" slider_label_pos_mode="3"
touch_mode="1" id="_sample_widget_slidebar">
<layout_hint alpha="1" align="0" size="200, 12, 0" />
</slidebar>
</plane>
</box>
<box> <!-- Max Allowed Extras -->
<layout_box layout_type="1" space="20" />
<text label="msg_max_allowed_extras">
<layout_hint adjust="2, 2" />
</text>
<plane>
<layout_hint adjust="2, 2" />
<slidebar style="_common_default_style_slidebar" slider_size="52, 52, 0"
slider_label_pos_mode="3" touch_mode="1" id="_sample_widget_slidebar">
<layout_hint alpha="1" align="0" size="200, 12, 0" />
</slidebar>
</plane>
</box>
</box>
<box> <!-- checkboxes -->
<layout_box layout_type="1" space="20" align="1, 0" anchor="1, 0" />
<box> <!-- 3d sound -->
<layout_box layout_type="2" space="10" align="1" anchor="1" />
<check_box style="_common_style_check_box_scalable">
<layout_hint size="40, 40, 0" />
</check_box>
<text label="msg_3d_sound">
<layout_hint adjust="2, 2" />
</text>
</box>
<box> <!-- music -->
<layout_box layout_type="2" space="10" align="1" anchor="2" />
<check_box style="_common_style_check_box_scalable">
<layout_hint size="40, 40, 0" />
</check_box>
<text label="msg_music">
<layout_hint adjust="2, 2" />
</text>
</box>
<box> <!-- wide view angle -->
<layout_box layout_type="2" space="10" align="1" anchor="1" />
<check_box style="_common_style_check_box_scalable">
<layout_hint size="40, 40, 0" />
</check_box>
<text label="msg_wide_view_angle">
<layout_hint adjust="2, 2" />
</text>
</box>
<box> <!-- texture loader -->
<layout_box layout_type="2" space="10" align="1" anchor="1" />
<check_box style="_common_style_check_box_scalable">
<layout_hint size="40, 40, 0" />
</check_box>
<text label="msg_texture_loader">
<layout_hint adjust="2, 2" />
</text>
</box>
</box>
<plane style="_common_style_plane_transparent"> <!-- spacing for buttons on bottom -->
<layout_hint size="0, 60" adjust="1, 0" />
</plane>
</box>
<scrollbar style="_common_default_style_scrollbar" id="vertical_scroll_bar"
scroll_type="0">
<layout_hint size="5, 0" />
</scrollbar>
</scroll_view>
</template>
</templatetable>
<styletable>
<style_button glow_obj="plane_obj3" color="1, 1, 1, 1" highlight_obj="plane_obj2"
label_obj="text_obj1" bg_obj="plane_obj1" adjust_min_size="170, 54"
id="style_save_and_launch_button">
<planeobj color="0.09, 0.81, 0.39, 1" texture0="_common_texture_button_white" id="plane_obj1" />
<textobj font_size="20" color="1, 1, 1, 1" align_x="1" align_y="1" adjust_x="1" adjust_y="1" id="text_obj1" />
<planeobj color="1, 1, 1, 1" texture0="_common_texture_button" id="plane_obj2" />
<planeobj texture0="_common_texture_button_glow" blend="2" id="plane_obj3" />
</style_button>
<style_button glow_obj="plane_obj3" color="1, 1, 1, 1" highlight_obj="plane_obj2"
label_obj="text_obj1" bg_obj="plane_obj1" adjust_min_size="170, 54"
id="style_save_and_exit_button">
<planeobj color="0, 0.5, 0.9, 1" texture0="_common_texture_button_white" id="plane_obj1" />
<textobj font_size="20" color="1, 1, 1, 1" align_x="1" align_y="1" adjust_x="1" adjust_y="1" id="text_obj1" />
<planeobj color="1, 1, 1, 1" texture0="_common_texture_button" id="plane_obj2" />
<planeobj texture0="_common_texture_button_glow" blend="2" id="plane_obj3" />
</style_button>
<style_button glow_obj="plane_obj3" color="1, 1, 1, 1" highlight_obj="plane_obj2"
label_obj="text_obj1" bg_obj="plane_obj1" adjust_min_size="170, 54" id="style_exit_button">
<planeobj color="0.96, 0.32, 0.25, 1" texture0="_common_texture_button_white" id="plane_obj1" />
<textobj font_size="20" color="1, 1, 1, 1" align_x="1" align_y="1" adjust_x="1" adjust_y="1" id="text_obj1" />
<planeobj color="1, 1, 1, 1" texture0="_common_texture_button" id="plane_obj2" />
<planeobj texture0="_common_texture_button_glow" blend="2" id="plane_obj3" />
</style_button>
</styletable>
<stringtable>
<!--
<stringtable>
<!--
<locale src_="locale/ja.xml" compress="on" id="ja" />
-->
-->
<locale src="locale/en.xml" compress="on" id="en" />
<!--
<!--
<locale src_="locale/en-gb.xml" compress="on" id="en-gb" />
<locale src_="locale/zh-s.xml" compress="on" id="zh-s" />
<locale src_="locale/zh-t.xml" compress="on" id="zh-t" />
@ -278,15 +29,6 @@
<locale src_="locale/sv.xml" compress="on" id="sv" />
<locale src_="locale/pt-br.xml" compress="on" id="pt-br" />
<locale src_="locale/tr.xml" compress="on" id="tr" />
-->
-->
</stringtable>
<texturetable>
<texture id="tex_shark" src="textures/shark.png" type="texture/png" />
<texture id="tex_settings_bg" src="textures/tex_settings_bg.gim" type="texture/gim" />
</texturetable>
<filetable>
</filetable>
</resource>
</resource>

View File

@ -1,38 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<stringset>
<string id="msg_lego_island_config" src="Lego Island Config"/>
<string id="msg_diskpath" src="isle:diskpath" />
<string id="msg_cdpath" src="isle:cdpath" />
<string id="msg_savepath" src="isle:savepath" />
<!-- Main Page -->
<string id="msg_lego_island_config" src="Lego Island Config"/>
<string id="msg_page_game" src="Game" />
<string id="msg_page_graphics" src="Graphics" />
<string id="msg_page_controls" src="Controls" />
<string id="msg_page_extensions" src="Extensions" />
<string id="msg_wide_view_angle" src="Wide View Angle" />
<string id="msg_3d_sound" src="3D Sound" />
<string id="msg_music" src="Music" />
<!-- Game Page -->
<string id="msg_data_path" src="Data Path" />
<string id="msg_save_path" src="Save Path" />
<string id="msg_3d_sound" src="3D Sound" />
<string id="msg_music" src="Music" />
<string id="msg_cursor_sensitivity" src="Cursor Sensitivity" />
<string id="msg_transition_type" src="Transition Type" />
<string id="msg_transition_none" src="none" />
<string id="msg_transition_dissolve" src="dissolve" />
<string id="msg_transition_mosaic" src="mosaic" />
<string id="msg_transition_wipe_down" src="wipe down" />
<string id="msg_transition_windows" src="windows" />
<string id="msg_island_quality" src="Island Quality" />
<string id="msg_quality_low" src="low" />
<string id="msg_quality_medium" src="medium" />
<string id="msg_quality_high" src="high" />
<!-- Graphics -->
<string id="msg_island_texture_quality" src="Island Texture Quality" />
<string id="msg_texture_fast" src="fast" />
<string id="msg_texture_high" src="high" />
<string id="msg_island_texture" src="Island Texture Quality" />
<string id="msg_texture_fast" src="fast" />
<string id="msg_texture_high" src="high" />
<string id="msg_island_model_quality" src="Island Model Quality" />
<string id="msg_quality_low" src="low" />
<string id="msg_quality_medium" src="medium" />
<string id="msg_quality_high" src="high" />
<string id="msg_max_lod" src="Max LOD" />
<string id="msg_max_allowed_extras" src="Max Allowed Extras" />
<string id="msg_max_lod" src="Maximum LOD" />
<string id="msg_max_actors" src="Maximum Actors" />
<string id="msg_transition_type" src="isle:Transition Type" />
<string id="msg_transition_none" src="none" />
<string id="msg_transition_dissolve" src="dissolve" />
<string id="msg_transition_mosaic" src="mosaic" />
<string id="msg_transition_wipe_down" src="wipe down" />
<string id="msg_transition_windows" src="windows" />
<!-- Controls -->
<string id="msg_touch_control_scheme" src="Touch Control Scheme" />
<string id="msg_virtual_gamepad" src="Virtual Gamepad" />
<string id="msg_virtual_arrow_keys" src="Virtual Arrow Keys" />
<string id="msg_virtual_mouse" src="Virtual Mouse" />
<string id="msg_rumble" src="Rumble" />
<string id="msg_texture_loader" src="Texture Loader Extension" />
<!-- Extensions -->
<string id="msg_texture_loader_extension" src="Texture Loader Extension" />
<string id="msg_texture_loader_path" src="Texture Loader Path" />
<string id="msg_save_exit" src="Save &amp; Exit" />
<string id="msg_save_launch" src="Save &amp; Launch" />
<string id="msg_exit" src="Exit" />
</stringset>
<!-- footer -->
<string id="msg_save_exit" src="Save &amp; Exit" />
<string id="msg_save_launch" src="Save &amp; Launch" />
<string id="msg_exit" src="Exit" />
</stringset>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<application_settings version="1.0" bg_color="4.0, 21.0, 105.0, 255.0">
<setting_list id="lego_island_config" title="msg_lego_island_config">
<setting_list id="page_game" title="msg_page_game" style="edit" icon="tex_spanner">
<text_field id="data_path" title="msg_data_path" max_length="255" min_length="0" keyboard_type="alphabet" key="data_path" default_value=""/>
<text_field id="save_path" title="msg_save_path" max_length="255" min_length="0" keyboard_type="alphabet" key="save_path" default_value=""/>
<list id="transition_type" title="msg_transition_type" key="transition_type" default_value="0">
<list_item id="transition_none" title="msg_transition_none" value="0" />
<list_item id="transition_dissolve" title="msg_transition_dissolve" value="1" />
<list_item id="transition_mosaic" title="msg_transition_mosaic" value="2" />
<list_item id="transition_wipe_down" title="msg_transition_wipe_down" value="3" />
<list_item id="transition_windows" title="msg_transition_windows" value="4" />
</list>
<toggle_switch id="music" title="msg_music" key="music" default_value="1"/>
<toggle_switch id="3d_sound" title="msg_3d_sound" key="3d_sound" default_value="1"/>
</setting_list>
<setting_list id="page_graphics" title="msg_page_graphics" style="edit" icon="tex_spanner">
<list id="island_texture_quality" title="msg_island_texture_quality" key="island_texture_quality" default_value="0">
<list_item id="texture_fast" title="msg_texture_fast" value="0" />
<list_item id="texture_high" title="msg_texture_high" value="1" />
</list>
<list id="island_model_quality" title="msg_island_model_quality" key="island_model_quality" default_value="0">
<list_item id="quality_low" title="msg_quality_low" value="0" />
<list_item id="quality_medium" title="msg_quality_medium" value="1" />
<list_item id="quality_high" title="msg_quality_high" value="2" />
</list>
</setting_list>
<setting_list id="page_controls" title="msg_page_controls" style="edit" icon="tex_spanner">
<list id="touch_control_scheme" title="msg_touch_control_scheme" key="touch_control_scheme" default_value="0">
<list_item id="virtual_gamepad" title="msg_virtual_gamepad" value="0" />
<list_item id="virtual_arrow_keys" title="msg_virtual_arrow_keys" value="1" />
<list_item id="virtual_mouse" title="msg_virtual_mouse" value="2" />
</list>
<toggle_switch id="rumble" title="msg_rumble" key="rumble" default_value="1"/>
</setting_list>
<setting_list id="page_extensions" title="msg_page_extensions" style="edit" icon="tex_spanner">
<toggle_switch id="texture_loader_extension" title="msg_texture_loader_extension" key="texture_loader_extension" default_value="0"/>
<text_field id="texture_loader_path" title="msg_texture_loader_path" max_length="255" min_length="0" keyboard_type="alphabet" key="texture_loader_path" default_value=""/>
</setting_list>
</setting_list>
</application_settings>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

136
CONFIG/vita/include/fios2.h Normal file
View File

@ -0,0 +1,136 @@
#include <stdint.h>
#include <stddef.h>
#include <psp2/kernel/threadmgr.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct SceFiosBuffer {
void *pPtr;
size_t length;
} SceFiosBuffer;
#define SCE_FIOS_THREAD_TYPES 3
typedef struct SceFiosParams
{
uint32_t initialized : 1;
uint32_t paramsSize : 15;
uint32_t pathMax : 16;
uint32_t profiling;
uint32_t ioThreadCount;
uint32_t threadsPerScheduler;
uint32_t extraFlag1 : 1;
uint32_t extraFlags : 31;
uint32_t maxChunk;
uint8_t maxDecompressorThreadCount;
uint8_t reserved1;
uint8_t reserved2;
uint8_t reserved3;
intptr_t reserved4;
intptr_t reserved5;
SceFiosBuffer opStorage;
SceFiosBuffer fhStorage;
SceFiosBuffer dhStorage;
SceFiosBuffer chunkStorage;
void* pVprintf;
void* pMemcpy;
void* pProfileCallback;
int threadPriority[SCE_FIOS_THREAD_TYPES];
int threadAffinity[SCE_FIOS_THREAD_TYPES];
int threadStackSize[SCE_FIOS_THREAD_TYPES];
} SceFiosParams;
#define SCE_KERNEL_HIGHEST_PRIORITY_USER (64)
#define SCE_KERNEL_LOWEST_PRIORITY_USER (191)
#define SCE_FIOS_IO_THREAD_DEFAULT_PRIORITY (SCE_KERNEL_HIGHEST_PRIORITY_USER+2)
#define SCE_FIOS_DECOMPRESSOR_THREAD_DEFAULT_PRIORITY (SCE_KERNEL_LOWEST_PRIORITY_USER-2)
#define SCE_FIOS_CALLBACK_THREAD_DEFAULT_PRIORITY (SCE_KERNEL_HIGHEST_PRIORITY_USER+2)
#define SCE_FIOS_THREAD_DEFAULT_AFFINITY SCE_KERNEL_CPU_MASK_USER_2
#define SCE_FIOS_IO_THREAD_DEFAULT_AFFINITY SCE_FIOS_THREAD_DEFAULT_AFFINITY
#define SCE_FIOS_DECOMPRESSOR_THREAD_DEFAULT_AFFINITY SCE_KERNEL_THREAD_CPU_AFFINITY_MASK_DEFAULT
#define SCE_FIOS_CALLBACK_THREAD_DEFAULT_AFFINITY SCE_FIOS_THREAD_DEFAULT_AFFINITY
#define SCE_FIOS_IO_THREAD_DEFAULT_STACKSIZE (8*1024)
#define SCE_FIOS_DECOMPRESSOR_THREAD_DEFAULT_STACKSIZE (16*1024)
#define SCE_FIOS_CALLBACK_THREAD_DEFAULT_STACKSIZE (8*1024)
#define SCE_FIOS_PARAMS_INITIALIZER { 0, sizeof(SceFiosParams), 0, 0, \
2, 2, \
0, 0, \
(256*1024), \
2, 0, 0, 0, 0, 0, \
{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \
NULL, NULL, NULL, \
{ SCE_FIOS_IO_THREAD_DEFAULT_PRIORITY, SCE_FIOS_DECOMPRESSOR_THREAD_DEFAULT_PRIORITY, SCE_FIOS_CALLBACK_THREAD_DEFAULT_PRIORITY }, \
{ SCE_FIOS_IO_THREAD_DEFAULT_AFFINITY, SCE_FIOS_DECOMPRESSOR_THREAD_DEFAULT_AFFINITY, SCE_FIOS_CALLBACK_THREAD_DEFAULT_AFFINITY}, \
{ SCE_FIOS_IO_THREAD_DEFAULT_STACKSIZE, SCE_FIOS_DECOMPRESSOR_THREAD_DEFAULT_STACKSIZE, SCE_FIOS_CALLBACK_THREAD_DEFAULT_STACKSIZE}}
#define SCE_FIOS_IO_THREAD 0
#define SCE_FIOS_DECOMPRESSOR_THREAD 1
#define SCE_FIOS_CALLBACK_THREAD 2
#define SCE_FIOS_FH_SIZE 80
#define SCE_FIOS_DH_SIZE 80
#define SCE_FIOS_OP_SIZE 168
#define SCE_FIOS_CHUNK_SIZE 64
#define SCE_FIOS_ALIGN_UP(val,align) (((val) + ((align)-1)) & ~((align)-1))
#define SCE_FIOS_STORAGE_SIZE(num, size) \
(((num) * (size)) + SCE_FIOS_ALIGN_UP(SCE_FIOS_ALIGN_UP((num), 8) / 8, 8))
#define SCE_FIOS_DH_STORAGE_SIZE(numDHs, pathMax) \
SCE_FIOS_STORAGE_SIZE(numDHs, SCE_FIOS_DH_SIZE + pathMax)
#define SCE_FIOS_FH_STORAGE_SIZE(numFHs,pathMax) \
SCE_FIOS_STORAGE_SIZE(numFHs, SCE_FIOS_FH_SIZE + pathMax)
#define SCE_FIOS_OP_STORAGE_SIZE(numOps,pathMax) \
SCE_FIOS_STORAGE_SIZE(numOps, SCE_FIOS_OP_SIZE + pathMax)
#define SCE_FIOS_CHUNK_STORAGE_SIZE(numChunks) \
SCE_FIOS_STORAGE_SIZE(numChunks, SCE_FIOS_CHUNK_SIZE)
int sceFiosInitialize(SceFiosParams* params);
typedef int64_t SceFiosTime;
typedef int32_t SceFiosHandle;
typedef SceFiosHandle SceFiosFH;
typedef struct SceFiosOpenParams
{
uint32_t openFlags:16;
uint32_t opFlags:16;
uint32_t reserved;
SceFiosBuffer buffer;
} SceFiosOpenParams;
typedef struct SceFiosOpAttr
{
SceFiosTime deadline;
void* pCallback;
void * pCallbackContext;
int32_t priority : 8;
uint32_t opflags : 24;
uint32_t userTag;
void * userPtr;
void * pReserved;
} SceFiosOpAttr;
int sceFiosFHOpenWithModeSync(const SceFiosOpAttr *pAttr, SceFiosFH *pOutFH, const char *pPath, const SceFiosOpenParams *pOpenParams, int32_t nativeMode);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,4 @@
// clang-format off
#include <stdarg.h>
#include <paf.h>
// clang-format on

View File

View File

@ -0,0 +1,381 @@
/*-------------------------------------------------------------------------*/
/**
@file dictionary.c
@author N. Devillard
@brief Implements a dictionary for string variables.
This module implements a simple dictionary object, i.e. a list
of string/string associations. This object is useful to store e.g.
informations retrieved from a configuration file (ini files).
*/
/*--------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include "dictionary.h"
#include "pafstd.h"
/** Minimal allocated number of entries in a dictionary */
#define DICTMINSZ 128
/*---------------------------------------------------------------------------
Private functions
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Duplicate a string
@param s String to duplicate
@return Pointer to a newly allocated string, to be freed with free()
This is a replacement for strdup(). This implementation is provided
for systems that do not have it.
*/
/*--------------------------------------------------------------------------*/
static char * xstrdup(const char * s)
{
char * t ;
size_t len ;
if (!s)
return NULL ;
len = strlen(s) + 1 ;
t = (char*) malloc(len) ;
if (t) {
memcpy(t, s, len) ;
}
return t ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Double the size of the dictionary
@param d Dictionary to grow
@return This function returns non-zero in case of failure
*/
/*--------------------------------------------------------------------------*/
static int dictionary_grow(dictionary * d)
{
char ** new_val ;
char ** new_key ;
unsigned * new_hash ;
new_val = (char**) calloc(d->size * 2, sizeof *d->val);
new_key = (char**) calloc(d->size * 2, sizeof *d->key);
new_hash = (unsigned*) calloc(d->size * 2, sizeof *d->hash);
if (!new_val || !new_key || !new_hash) {
/* An allocation failed, leave the dictionary unchanged */
if (new_val)
free(new_val);
if (new_key)
free(new_key);
if (new_hash)
free(new_hash);
return -1 ;
}
/* Initialize the newly allocated space */
memcpy(new_val, d->val, d->size * sizeof(char *));
memcpy(new_key, d->key, d->size * sizeof(char *));
memcpy(new_hash, d->hash, d->size * sizeof(unsigned));
/* Delete previous data */
free(d->val);
free(d->key);
free(d->hash);
/* Actually update the dictionary */
d->size *= 2 ;
d->val = new_val;
d->key = new_key;
d->hash = new_hash;
return 0 ;
}
/*---------------------------------------------------------------------------
Function codes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Compute the hash key for a string.
@param key Character string to use for key.
@return 1 unsigned int on at least 32 bits.
This hash function has been taken from an Article in Dr Dobbs Journal.
This is normally a collision-free function, distributing keys evenly.
The key is stored anyway in the struct so that collision can be avoided
by comparing the key itself in last resort.
*/
/*--------------------------------------------------------------------------*/
unsigned dictionary_hash(const char * key)
{
size_t len ;
unsigned hash ;
size_t i ;
if (!key)
return 0 ;
len = strlen(key);
for (hash=0, i=0 ; i<len ; i++) {
hash += (unsigned)key[i] ;
hash += (hash<<10);
hash ^= (hash>>6) ;
}
hash += (hash <<3);
hash ^= (hash >>11);
hash += (hash <<15);
return hash ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Create a new dictionary object.
@param size Optional initial size of the dictionary.
@return 1 newly allocated dictionary object.
This function allocates a new dictionary object of given size and returns
it. If you do not know in advance (roughly) the number of entries in the
dictionary, give size=0.
*/
/*-------------------------------------------------------------------------*/
dictionary * dictionary_new(size_t size)
{
dictionary * d ;
/* If no size was specified, allocate space for DICTMINSZ */
if (size<DICTMINSZ) size=DICTMINSZ ;
d = (dictionary*) calloc(1, sizeof *d) ;
if (d) {
d->size = size ;
d->val = (char**) calloc(size, sizeof *d->val);
d->key = (char**) calloc(size, sizeof *d->key);
d->hash = (unsigned*) calloc(size, sizeof *d->hash);
if (!d->size || !d->val || !d->hash) {
free((void *) d->size);
free((void *) d->val);
free((void *) d->hash);
free(d);
d = NULL;
}
}
return d ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Delete a dictionary object
@param d dictionary object to deallocate.
@return void
Deallocate a dictionary object and all memory associated to it.
*/
/*--------------------------------------------------------------------------*/
void dictionary_del(dictionary * d)
{
size_t i ;
if (d==NULL) return ;
for (i=0 ; i<d->size ; i++) {
if (d->key[i]!=NULL)
free(d->key[i]);
if (d->val[i]!=NULL)
free(d->val[i]);
}
free(d->val);
free(d->key);
free(d->hash);
free(d);
return ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Get a value from a dictionary.
@param d dictionary object to search.
@param key Key to look for in the dictionary.
@param def Default value to return if key not found.
@return 1 pointer to internally allocated character string.
This function locates a key in a dictionary and returns a pointer to its
value, or the passed 'def' pointer if no such key can be found in
dictionary. The returned character pointer points to data internal to the
dictionary object, you should not try to free it or modify it.
*/
/*--------------------------------------------------------------------------*/
const char * dictionary_get(const dictionary * d, const char * key, const char * def)
{
unsigned hash ;
size_t i ;
if(d == NULL || key == NULL)
return def ;
hash = dictionary_hash(key);
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
/* Compare hash */
if (hash==d->hash[i]) {
/* Compare string, to avoid hash collisions */
if (!strcmp(key, d->key[i])) {
return d->val[i] ;
}
}
}
return def ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Set a value in a dictionary.
@param d dictionary object to modify.
@param key Key to modify or add.
@param val Value to add.
@return int 0 if Ok, anything else otherwise
If the given key is found in the dictionary, the associated value is
replaced by the provided one. If the key cannot be found in the
dictionary, it is added to it.
It is Ok to provide a NULL value for val, but NULL values for the dictionary
or the key are considered as errors: the function will return immediately
in such a case.
Notice that if you dictionary_set a variable to NULL, a call to
dictionary_get will return a NULL value: the variable will be found, and
its value (NULL) is returned. In other words, setting the variable
content to NULL is equivalent to deleting the variable from the
dictionary. It is not possible (in this implementation) to have a key in
the dictionary without value.
This function returns non-zero in case of failure.
*/
/*--------------------------------------------------------------------------*/
int dictionary_set(dictionary * d, const char * key, const char * val)
{
size_t i ;
unsigned hash ;
if (d==NULL || key==NULL) return -1 ;
/* Compute hash for this key */
hash = dictionary_hash(key) ;
/* Find if value is already in dictionary */
if (d->n>0) {
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
if (hash==d->hash[i]) { /* Same hash value */
if (!strcmp(key, d->key[i])) { /* Same key */
/* Found a value: modify and return */
if (d->val[i]!=NULL)
free(d->val[i]);
d->val[i] = (val ? xstrdup(val) : NULL);
/* Value has been modified: return */
return 0 ;
}
}
}
}
/* Add a new value */
/* See if dictionary needs to grow */
if (d->n==d->size) {
/* Reached maximum size: reallocate dictionary */
if (dictionary_grow(d) != 0)
return -1;
}
/* Insert key in the first empty slot. Start at d->n and wrap at
d->size. Because d->n < d->size this will necessarily
terminate. */
for (i=d->n ; d->key[i] ; ) {
if(++i == d->size) i = 0;
}
/* Copy key */
d->key[i] = xstrdup(key);
d->val[i] = (val ? xstrdup(val) : NULL) ;
d->hash[i] = hash;
d->n ++ ;
return 0 ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Delete a key in a dictionary
@param d dictionary object to modify.
@param key Key to remove.
@return void
This function deletes a key in a dictionary. Nothing is done if the
key cannot be found.
*/
/*--------------------------------------------------------------------------*/
void dictionary_unset(dictionary * d, const char * key)
{
unsigned hash ;
size_t i ;
if (key == NULL || d == NULL) {
return;
}
hash = dictionary_hash(key);
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
/* Compare hash */
if (hash==d->hash[i]) {
/* Compare string, to avoid hash collisions */
if (!strcmp(key, d->key[i])) {
/* Found key */
break ;
}
}
}
if (i>=d->size)
/* Key not found */
return ;
free(d->key[i]);
d->key[i] = NULL ;
if (d->val[i]!=NULL) {
free(d->val[i]);
d->val[i] = NULL ;
}
d->hash[i] = 0 ;
d->n -- ;
return ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Dump a dictionary to an opened file pointer.
@param d Dictionary to dump
@param f Opened file pointer.
@return void
Dumps a dictionary onto an opened file pointer. Key pairs are printed out
as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
output file pointers.
*/
/*--------------------------------------------------------------------------*/
void dictionary_dump(const dictionary * d, FILE * out)
{
size_t i ;
if (d==NULL || out==NULL) return ;
if (d->n<1) {
fprintf(out, "empty dictionary\n");
return ;
}
for (i=0 ; i<d->size ; i++) {
if (d->key[i]) {
fprintf(out, "%20s\t[%s]\n",
d->key[i],
d->val[i] ? d->val[i] : "UNDEF");
}
}
return ;
}

View File

@ -0,0 +1,170 @@
/*-------------------------------------------------------------------------*/
/**
@file dictionary.h
@author N. Devillard
@brief Implements a dictionary for string variables.
This module implements a simple dictionary object, i.e. a list
of string/string associations. This object is useful to store e.g.
informations retrieved from a configuration file (ini files).
*/
/*--------------------------------------------------------------------------*/
#ifndef _DICTIONARY_H_
#define _DICTIONARY_H_
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include "pafstd.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------
New types
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Dictionary object
This object contains a list of string/string associations. Each
association is identified by a unique string key. Looking up values
in the dictionary is speeded up by the use of a (hopefully collision-free)
hash function.
*/
/*-------------------------------------------------------------------------*/
typedef struct _dictionary_ {
unsigned n ; /** Number of entries in dictionary */
size_t size ; /** Storage size */
char ** val ; /** List of string values */
char ** key ; /** List of string keys */
unsigned * hash ; /** List of hash values for keys */
} dictionary ;
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Compute the hash key for a string.
@param key Character string to use for key.
@return 1 unsigned int on at least 32 bits.
This hash function has been taken from an Article in Dr Dobbs Journal.
This is normally a collision-free function, distributing keys evenly.
The key is stored anyway in the struct so that collision can be avoided
by comparing the key itself in last resort.
*/
/*--------------------------------------------------------------------------*/
unsigned dictionary_hash(const char * key);
/*-------------------------------------------------------------------------*/
/**
@brief Create a new dictionary object.
@param size Optional initial size of the dictionary.
@return 1 newly allocated dictionary object.
This function allocates a new dictionary object of given size and returns
it. If you do not know in advance (roughly) the number of entries in the
dictionary, give size=0.
*/
/*--------------------------------------------------------------------------*/
dictionary * dictionary_new(size_t size);
/*-------------------------------------------------------------------------*/
/**
@brief Delete a dictionary object
@param d dictionary object to deallocate.
@return void
Deallocate a dictionary object and all memory associated to it.
*/
/*--------------------------------------------------------------------------*/
void dictionary_del(dictionary * vd);
/*-------------------------------------------------------------------------*/
/**
@brief Get a value from a dictionary.
@param d dictionary object to search.
@param key Key to look for in the dictionary.
@param def Default value to return if key not found.
@return 1 pointer to internally allocated character string.
This function locates a key in a dictionary and returns a pointer to its
value, or the passed 'def' pointer if no such key can be found in
dictionary. The returned character pointer points to data internal to the
dictionary object, you should not try to free it or modify it.
*/
/*--------------------------------------------------------------------------*/
const char * dictionary_get(const dictionary * d, const char * key, const char * def);
/*-------------------------------------------------------------------------*/
/**
@brief Set a value in a dictionary.
@param d dictionary object to modify.
@param key Key to modify or add.
@param val Value to add.
@return int 0 if Ok, anything else otherwise
If the given key is found in the dictionary, the associated value is
replaced by the provided one. If the key cannot be found in the
dictionary, it is added to it.
It is Ok to provide a NULL value for val, but NULL values for the dictionary
or the key are considered as errors: the function will return immediately
in such a case.
Notice that if you dictionary_set a variable to NULL, a call to
dictionary_get will return a NULL value: the variable will be found, and
its value (NULL) is returned. In other words, setting the variable
content to NULL is equivalent to deleting the variable from the
dictionary. It is not possible (in this implementation) to have a key in
the dictionary without value.
This function returns non-zero in case of failure.
*/
/*--------------------------------------------------------------------------*/
int dictionary_set(dictionary * vd, const char * key, const char * val);
/*-------------------------------------------------------------------------*/
/**
@brief Delete a key in a dictionary
@param d dictionary object to modify.
@param key Key to remove.
@return void
This function deletes a key in a dictionary. Nothing is done if the
key cannot be found.
*/
/*--------------------------------------------------------------------------*/
void dictionary_unset(dictionary * d, const char * key);
/*-------------------------------------------------------------------------*/
/**
@brief Dump a dictionary to an opened file pointer.
@param d Dictionary to dump
@param f Opened file pointer.
@return void
Dumps a dictionary onto an opened file pointer. Key pairs are printed out
as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
output file pointers.
*/
/*--------------------------------------------------------------------------*/
void dictionary_dump(const dictionary * d, FILE * out);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,958 @@
/*-------------------------------------------------------------------------*/
/**
@file iniparser.c
@author N. Devillard
@brief Parser for ini files.
*/
/*--------------------------------------------------------------------------*/
/*---------------------------- Includes ------------------------------------*/
#include <ctype.h>
#include "pafstd.h"
#include <stdint.h>
#include <stdarg.h>
#include "iniparser.h"
/*---------------------------- Defines -------------------------------------*/
#define ASCIILINESZ (1024)
#define INI_INVALID_KEY ((char*)-1)
/*---------------------------------------------------------------------------
Private to this module
---------------------------------------------------------------------------*/
/**
* This enum stores the status for each parsed line (internal use only).
*/
typedef enum _line_status_ {
LINE_UNPROCESSED,
LINE_ERROR,
LINE_EMPTY,
LINE_COMMENT,
LINE_SECTION,
LINE_VALUE
} line_status ;
/*-------------------------------------------------------------------------*/
/**
@brief Convert a string to lowercase.
@param in String to convert.
@param out Output buffer.
@param len Size of the out buffer.
@return ptr to the out buffer or NULL if an error occured.
This function convert a string into lowercase.
At most len - 1 elements of the input string will be converted.
*/
/*--------------------------------------------------------------------------*/
static const char * strlwc(const char * in, char *out, unsigned len)
{
unsigned i ;
if (in==NULL || out == NULL || len==0) return NULL ;
i=0 ;
while (in[i] != '\0' && i < len-1) {
out[i] = (char)tolower((int)in[i]);
i++ ;
}
out[i] = '\0';
return out ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Duplicate a string
@param s String to duplicate
@return Pointer to a newly allocated string, to be freed with free()
This is a replacement for strdup(). This implementation is provided
for systems that do not have it.
*/
/*--------------------------------------------------------------------------*/
static char * xstrdup(const char * s)
{
char * t ;
size_t len ;
if (!s)
return NULL ;
len = strlen(s) + 1 ;
t = (char*) malloc(len) ;
if (t) {
memcpy(t, s, len) ;
}
return t ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Remove blanks at the beginning and the end of a string.
@param str String to parse and alter.
@return unsigned New size of the string.
*/
/*--------------------------------------------------------------------------*/
static unsigned strstrip(char * s)
{
char *last = NULL ;
char *dest = s;
if (s==NULL) return 0;
last = s + strlen(s);
while (isspace((unsigned char)*s) && *s) s++;
while (last > s) {
if (!isspace((unsigned char)*(last-1)))
break ;
last -- ;
}
*last = (char)0;
memmove(dest,s,last - s + 1);
return last - s;
}
/*-------------------------------------------------------------------------*/
/**
@brief Default error callback for iniparser: wraps `fprintf(stderr, ...)`.
*/
/*--------------------------------------------------------------------------*/
static int default_error_callback(const char *format, ...)
{
int ret = 0;
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
return ret;
}
static int (*iniparser_error_callback)(const char*, ...) = default_error_callback;
/*-------------------------------------------------------------------------*/
/**
@brief Configure a function to receive the error messages.
@param errback Function to call.
By default, the error will be printed on stderr. If a null pointer is passed
as errback the error callback will be switched back to default.
*/
/*--------------------------------------------------------------------------*/
void iniparser_set_error_callback(int (*errback)(const char *, ...))
{
if (errback) {
iniparser_error_callback = errback;
} else {
iniparser_error_callback = default_error_callback;
}
}
/*-------------------------------------------------------------------------*/
/**
@brief Get number of sections in a dictionary
@param d Dictionary to examine
@return int Number of sections found in dictionary
This function returns the number of sections found in a dictionary.
The test to recognize sections is done on the string stored in the
dictionary: a section name is given as "section" whereas a key is
stored as "section:key", thus the test looks for entries that do not
contain a colon.
This clearly fails in the case a section name contains a colon, but
this should simply be avoided.
This function returns -1 in case of error.
*/
/*--------------------------------------------------------------------------*/
int iniparser_getnsec(const dictionary * d)
{
size_t i ;
int nsec ;
if (d==NULL) return -1 ;
nsec=0 ;
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
if (strchr(d->key[i], ':')==NULL) {
nsec ++ ;
}
}
return nsec ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Get name for section n in a dictionary.
@param d Dictionary to examine
@param n Section number (from 0 to nsec-1).
@return Pointer to char string
This function locates the n-th section in a dictionary and returns
its name as a pointer to a string statically allocated inside the
dictionary. Do not free or modify the returned string!
This function returns NULL in case of error.
*/
/*--------------------------------------------------------------------------*/
const char * iniparser_getsecname(const dictionary * d, int n)
{
size_t i ;
int foundsec ;
if (d==NULL || n<0) return NULL ;
foundsec=0 ;
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
if (strchr(d->key[i], ':')==NULL) {
foundsec++ ;
if (foundsec>n)
break ;
}
}
if (foundsec<=n) {
return NULL ;
}
return d->key[i] ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Dump a dictionary to an opened file pointer.
@param d Dictionary to dump.
@param f Opened file pointer to dump to.
@return void
This function prints out the contents of a dictionary, one element by
line, onto the provided file pointer. It is OK to specify @c stderr
or @c stdout as output files. This function is meant for debugging
purposes mostly.
*/
/*--------------------------------------------------------------------------*/
void iniparser_dump(const dictionary * d, FILE * f)
{
size_t i ;
if (d==NULL || f==NULL) return ;
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
if (d->val[i]!=NULL) {
fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
} else {
fprintf(f, "[%s]=UNDEF\n", d->key[i]);
}
}
return ;
}
static void escape_value(char *escaped, char *value) {
char c;
int v = 0;
int e = 0;
if(!escaped || !value)
return;
while((c = value[v]) != '\0') {
if(c == '\\' || c == '"') {
escaped[e] = '\\';
e++;
}
escaped[e] = c;
v++;
e++;
}
escaped[e] = '\0';
}
/*-------------------------------------------------------------------------*/
/**
@brief Save a dictionary to a loadable ini file
@param d Dictionary to dump
@param f Opened file pointer to dump to
@return void
This function dumps a given dictionary into a loadable ini file.
It is Ok to specify @c stderr or @c stdout as output files.
*/
/*--------------------------------------------------------------------------*/
void iniparser_dump_ini(const dictionary * d, FILE * f)
{
size_t i ;
size_t nsec ;
const char * secname ;
char escaped[(ASCIILINESZ * 2) + 2] = "";
if (d==NULL || f==NULL) return ;
nsec = iniparser_getnsec(d);
if (nsec<1) {
/* No section in file: dump all keys as they are */
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
escape_value(escaped, d->val[i]);
fprintf(f, "%s = \"%s\"\n", d->key[i], escaped);
}
return ;
}
for (i=0 ; i<nsec ; i++) {
secname = iniparser_getsecname(d, i) ;
iniparser_dumpsection_ini(d, secname, f);
}
fprintf(f, "\n");
return ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Save a dictionary section to a loadable ini file
@param d Dictionary to dump
@param s Section name of dictionary to dump
@param f Opened file pointer to dump to
@return void
This function dumps a given section of a given dictionary into a loadable ini
file. It is Ok to specify @c stderr or @c stdout as output files.
*/
/*--------------------------------------------------------------------------*/
void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f)
{
size_t j ;
char keym[ASCIILINESZ+1];
int seclen ;
char escaped[(ASCIILINESZ * 2) + 2] = "";
if (d==NULL || f==NULL) return;
if (! iniparser_find_entry(d, s)) return;
if (strlen(s) > sizeof(keym)) return;
seclen = (int)strlen(s);
fprintf(f, "\n[%s]\n", s);
sprintf(keym, "%s:", s);
for (j=0 ; j<d->size ; j++) {
if (d->key[j]==NULL)
continue ;
if (!strncmp(d->key[j], keym, seclen+1)) {
escape_value(escaped, d->val[j]);
fprintf(f, "%-30s = \"%s\"\n", d->key[j]+seclen+1, escaped);
}
}
fprintf(f, "\n");
return ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Get the number of keys in a section of a dictionary.
@param d Dictionary to examine
@param s Section name of dictionary to examine
@return Number of keys in section
*/
/*--------------------------------------------------------------------------*/
int iniparser_getsecnkeys(const dictionary * d, const char * s)
{
int seclen, nkeys ;
char keym[ASCIILINESZ+1];
size_t j ;
nkeys = 0;
if (d==NULL) return nkeys;
if (! iniparser_find_entry(d, s)) return nkeys;
seclen = (int)strlen(s);
strlwc(s, keym, sizeof(keym));
keym[seclen] = ':';
for (j=0 ; j<d->size ; j++) {
if (d->key[j]==NULL)
continue ;
if (!strncmp(d->key[j], keym, seclen+1))
nkeys++;
}
return nkeys;
}
/*-------------------------------------------------------------------------*/
/**
@brief Get the number of keys in a section of a dictionary.
@param d Dictionary to examine
@param s Section name of dictionary to examine
@param keys Already allocated array to store the keys in
@return The pointer passed as `keys` argument or NULL in case of error
This function queries a dictionary and finds all keys in a given section.
The keys argument should be an array of pointers which size has been
determined by calling `iniparser_getsecnkeys` function prior to this one.
Each pointer in the returned char pointer-to-pointer is pointing to
a string allocated in the dictionary; do not free or modify them.
*/
/*--------------------------------------------------------------------------*/
const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys)
{
size_t i, j, seclen ;
char keym[ASCIILINESZ+1];
if (d==NULL || keys==NULL) return NULL;
if (! iniparser_find_entry(d, s)) return NULL;
seclen = strlen(s);
strlwc(s, keym, sizeof(keym));
keym[seclen] = ':';
i = 0;
for (j=0 ; j<d->size ; j++) {
if (d->key[j]==NULL)
continue ;
if (!strncmp(d->key[j], keym, seclen+1)) {
keys[i] = d->key[j];
i++;
}
}
return keys;
}
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key
@param d Dictionary to search
@param key Key string to look for
@param def Default value to return if key not found.
@return pointer to statically allocated character string
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the pointer passed as 'def' is returned.
The returned char pointer is pointing to a string allocated in
the dictionary, do not free or modify it.
*/
/*--------------------------------------------------------------------------*/
const char * iniparser_getstring(const dictionary * d, const char * key, const char * def)
{
const char * lc_key ;
const char * sval ;
char tmp_str[ASCIILINESZ+1];
if (d==NULL || key==NULL)
return def ;
lc_key = strlwc(key, tmp_str, sizeof(tmp_str));
sval = dictionary_get(d, lc_key, def);
return sval ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to an long int
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return long integer
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
Supported values for integers include the usual C notation
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
are supported. Examples:
"42" -> 42
"042" -> 34 (octal -> decimal)
"0x42" -> 66 (hexa -> decimal)
Warning: the conversion may overflow in various ways. Conversion is
totally outsourced to strtol(), see the associated man page for overflow
handling.
Credits: Thanks to A. Becker for suggesting strtol()
*/
/*--------------------------------------------------------------------------*/
long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound)
{
const char * str ;
str = iniparser_getstring(d, key, INI_INVALID_KEY);
if (str==NULL || str==INI_INVALID_KEY) return notfound ;
return strtol(str, NULL, 0);
}
int64_t iniparser_getint64(const dictionary * d, const char * key, int64_t notfound)
{
const char * str ;
str = iniparser_getstring(d, key, INI_INVALID_KEY);
if (str==NULL || str==INI_INVALID_KEY) return notfound ;
return strtoimax(str, NULL, 0);
}
uint64_t iniparser_getuint64(const dictionary * d, const char * key, uint64_t notfound)
{
const char * str ;
str = iniparser_getstring(d, key, INI_INVALID_KEY);
if (str==NULL || str==INI_INVALID_KEY) return notfound ;
return strtoumax(str, NULL, 0);
}
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to an int
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return integer
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
Supported values for integers include the usual C notation
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
are supported. Examples:
"42" -> 42
"042" -> 34 (octal -> decimal)
"0x42" -> 66 (hexa -> decimal)
Warning: the conversion may overflow in various ways. Conversion is
totally outsourced to strtol(), see the associated man page for overflow
handling.
Credits: Thanks to A. Becker for suggesting strtol()
*/
/*--------------------------------------------------------------------------*/
int iniparser_getint(const dictionary * d, const char * key, int notfound)
{
return (int)iniparser_getlongint(d, key, notfound);
}
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to a double
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return double
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
*/
/*--------------------------------------------------------------------------*/
double iniparser_getdouble(const dictionary * d, const char * key, double notfound)
{
const char * str ;
str = iniparser_getstring(d, key, INI_INVALID_KEY);
if (str==NULL || str==INI_INVALID_KEY) return notfound ;
return atof(str);
}
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to a boolean
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return integer
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
A true boolean is found if one of the following is matched:
- A string starting with 'y'
- A string starting with 'Y'
- A string starting with 't'
- A string starting with 'T'
- A string starting with '1'
A false boolean is found if one of the following is matched:
- A string starting with 'n'
- A string starting with 'N'
- A string starting with 'f'
- A string starting with 'F'
- A string starting with '0'
The notfound value returned if no boolean is identified, does not
necessarily have to be 0 or 1.
*/
/*--------------------------------------------------------------------------*/
int iniparser_getboolean(const dictionary * d, const char * key, int notfound)
{
int ret ;
const char * c ;
c = iniparser_getstring(d, key, INI_INVALID_KEY);
if (c==NULL || c==INI_INVALID_KEY) return notfound ;
if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
ret = 1 ;
} else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
ret = 0 ;
} else {
ret = notfound ;
}
return ret;
}
/*-------------------------------------------------------------------------*/
/**
@brief Finds out if a given entry exists in a dictionary
@param ini Dictionary to search
@param entry Name of the entry to look for
@return integer 1 if entry exists, 0 otherwise
Finds out if a given entry exists in the dictionary. Since sections
are stored as keys with NULL associated values, this is the only way
of querying for the presence of sections in a dictionary.
*/
/*--------------------------------------------------------------------------*/
int iniparser_find_entry(const dictionary * ini, const char * entry)
{
int found=0 ;
if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
found = 1 ;
}
return found ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Set an entry in a dictionary.
@param ini Dictionary to modify.
@param entry Entry to modify (entry name)
@param val New value to associate to the entry.
@return int 0 if Ok, -1 otherwise.
If the given entry can be found in the dictionary, it is modified to
contain the provided value. If it cannot be found, the entry is created.
It is Ok to set val to NULL.
*/
/*--------------------------------------------------------------------------*/
int iniparser_set(dictionary * ini, const char * entry, const char * val)
{
char tmp_key[ASCIILINESZ+1] = {0};
char tmp_val[ASCIILINESZ+1] = {0};
size_t len;
if(val) {
len = strlen(val);
len = len > ASCIILINESZ ? ASCIILINESZ : len;
memcpy(tmp_val, val, len) ;
val = tmp_val;
}
return dictionary_set(ini, strlwc(entry, tmp_key, sizeof(tmp_key)), val);
}
/*-------------------------------------------------------------------------*/
/**
@brief Delete an entry in a dictionary
@param ini Dictionary to modify
@param entry Entry to delete (entry name)
@return void
If the given entry can be found, it is deleted from the dictionary.
*/
/*--------------------------------------------------------------------------*/
void iniparser_unset(dictionary * ini, const char * entry)
{
char tmp_str[ASCIILINESZ+1];
dictionary_unset(ini, strlwc(entry, tmp_str, sizeof(tmp_str)));
}
static void parse_quoted_value(char *value, char quote) {
char c;
char *quoted;
int q = 0, v = 0;
int esc = 0;
if(!value)
return;
quoted = xstrdup(value);
if(!quoted) {
iniparser_error_callback("iniparser: memory allocation failure\n");
goto end_of_value;
}
while((c = quoted[q]) != '\0') {
if(!esc) {
if(c == '\\') {
esc = 1;
q++;
continue;
}
if(c == quote) {
goto end_of_value;
}
}
esc = 0;
value[v] = c;
v++;
q++;
}
end_of_value:
value[v] = '\0';
free(quoted);
}
/*-------------------------------------------------------------------------*/
/**
@brief Load a single line from an INI file
@param input_line Input line, may be concatenated multi-line input
@param section Output space to store section
@param key Output space to store key
@param value Output space to store value
@return line_status value
*/
/*--------------------------------------------------------------------------*/
static line_status iniparser_line(
const char * input_line,
char * section,
char * key,
char * value)
{
line_status sta ;
char * line = NULL;
size_t len ;
int d_quote;
line = xstrdup(input_line);
len = strstrip(line);
sta = LINE_UNPROCESSED ;
if (len<1) {
/* Empty line */
sta = LINE_EMPTY ;
} else if (line[0]=='#' || line[0]==';') {
/* Comment line */
sta = LINE_COMMENT ;
} else if (line[0]=='[' && line[len-1]==']') {
/* Section name without opening square bracket */
sscanf(line, "[%[^\n]", section);
len = strlen(section);
/* Section name without closing square bracket */
if(section[len-1] == ']')
{
section[len-1] = '\0';
}
strstrip(section);
strlwc(section, section, len);
sta = LINE_SECTION ;
} else if ((d_quote = sscanf (line, "%[^=] = \"%[^\n]\"", key, value)) == 2
|| sscanf (line, "%[^=] = '%[^\n]'", key, value) == 2) {
/* Usual key=value with quotes, with or without comments */
strstrip(key);
strlwc(key, key, len);
if(d_quote == 2)
parse_quoted_value(value, '"');
else
parse_quoted_value(value, '\'');
/* Don't strip spaces from values surrounded with quotes */
sta = LINE_VALUE ;
} else if (sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
/* Usual key=value without quotes, with or without comments */
strstrip(key);
strlwc(key, key, len);
strstrip(value);
/*
* sscanf cannot handle '' or "" as empty values
* this is done here
*/
if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
value[0]=0 ;
}
sta = LINE_VALUE ;
} else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
|| sscanf(line, "%[^=] %[=]", key, value) == 2) {
/*
* Special cases:
* key=
* key=;
* key=#
*/
strstrip(key);
strlwc(key, key, len);
value[0]=0 ;
sta = LINE_VALUE ;
} else {
/* Generate syntax error */
sta = LINE_ERROR ;
}
free(line);
return sta ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Parse an ini file and return an allocated dictionary object
@param in File to read.
@param ininame Name of the ini file to read (only used for nicer error messages)
@return Pointer to newly allocated dictionary
This is the parser for ini files. This function is called, providing
the file to be read. It returns a dictionary object that should not
be accessed directly, but through accessor functions instead.
The returned dictionary must be freed using iniparser_freedict().
*/
/*--------------------------------------------------------------------------*/
dictionary * iniparser_load_file(FILE * in, const char * ininame)
{
char line [ASCIILINESZ+1] ;
char section [ASCIILINESZ+1] ;
char key [ASCIILINESZ+1] ;
char tmp [(ASCIILINESZ * 2) + 2] ;
char val [ASCIILINESZ+1] ;
int last=0 ;
int len ;
int lineno=0 ;
int errs=0;
int mem_err=0;
dictionary * dict ;
dict = dictionary_new(0) ;
if (!dict) {
return NULL ;
}
memset(line, 0, ASCIILINESZ);
memset(section, 0, ASCIILINESZ);
memset(key, 0, ASCIILINESZ);
memset(val, 0, ASCIILINESZ);
last=0 ;
while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
lineno++ ;
len = (int)strlen(line)-1;
if (len<=0)
continue;
/* Safety check against buffer overflows */
if (line[len]!='\n' && !feof(in)) {
iniparser_error_callback(
"iniparser: input line too long in %s (%d)\n",
ininame,
lineno);
dictionary_del(dict);
return NULL ;
}
/* Get rid of \n and spaces at end of line */
while ((len>=0) &&
((line[len]=='\n') || (isspace((unsigned char)line[len])))) {
line[len]=0 ;
len-- ;
}
if (len < 0) { /* Line was entirely \n and/or spaces */
len = 0;
}
/* Detect multi-line */
if (line[len]=='\\') {
/* Multi-line value */
last=len ;
continue ;
} else {
last=0 ;
}
switch (iniparser_line(line, section, key, val)) {
case LINE_EMPTY:
case LINE_COMMENT:
break ;
case LINE_SECTION:
mem_err = dictionary_set(dict, section, NULL);
break ;
case LINE_VALUE:
sprintf(tmp, "%s:%s", section, key);
mem_err = dictionary_set(dict, tmp, val);
break ;
case LINE_ERROR:
iniparser_error_callback(
"iniparser: syntax error in %s (%d):\n-> %s\n",
ininame,
lineno,
line);
errs++ ;
break;
default:
break ;
}
memset(line, 0, ASCIILINESZ);
last=0;
if (mem_err<0) {
iniparser_error_callback("iniparser: memory allocation failure\n");
break ;
}
}
if (errs) {
dictionary_del(dict);
dict = NULL ;
}
return dict ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Parse an ini file and return an allocated dictionary object
@param ininame Name of the ini file to read.
@return Pointer to newly allocated dictionary
This is the parser for ini files. This function is called, providing
the name of the file to be read. It returns a dictionary object that
should not be accessed directly, but through accessor functions
instead.
The returned dictionary must be freed using iniparser_freedict().
*/
/*--------------------------------------------------------------------------*/
dictionary * iniparser_load(const char * ininame)
{
FILE * in ;
dictionary * dict ;
if ((in=fopen(ininame, "r"))==NULL) {
iniparser_error_callback("iniparser: cannot open %s\n", ininame);
return NULL ;
}
dict = iniparser_load_file(in, ininame);
fclose(in);
return dict ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Free all memory associated to an ini dictionary
@param d Dictionary to free
@return void
Free all memory associated to an ini dictionary.
It is mandatory to call this function before the dictionary object
gets out of the current context.
*/
/*--------------------------------------------------------------------------*/
void iniparser_freedict(dictionary * d)
{
dictionary_del(d);
}

View File

@ -0,0 +1,446 @@
/*-------------------------------------------------------------------------*/
/**
@file iniparser.h
@author N. Devillard
@brief Parser for ini files.
*/
/*--------------------------------------------------------------------------*/
#ifndef _INIPARSER_H_
#define _INIPARSER_H_
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include "dictionary.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*-------------------------------------------------------------------------*/
/**
@brief Configure a function to receive the error messages.
@param errback Function to call.
By default, the error will be printed on stderr. If a null pointer is passed
as errback the error callback will be switched back to default.
*/
/*--------------------------------------------------------------------------*/
void iniparser_set_error_callback(int (*errback)(const char *, ...));
/*-------------------------------------------------------------------------*/
/**
@brief Get number of sections in a dictionary
@param d Dictionary to examine
@return int Number of sections found in dictionary
This function returns the number of sections found in a dictionary.
The test to recognize sections is done on the string stored in the
dictionary: a section name is given as "section" whereas a key is
stored as "section:key", thus the test looks for entries that do not
contain a colon.
This clearly fails in the case a section name contains a colon, but
this should simply be avoided.
This function returns -1 in case of error.
*/
/*--------------------------------------------------------------------------*/
int iniparser_getnsec(const dictionary * d);
/*-------------------------------------------------------------------------*/
/**
@brief Get name for section n in a dictionary.
@param d Dictionary to examine
@param n Section number (from 0 to nsec-1).
@return Pointer to char string
This function locates the n-th section in a dictionary and returns
its name as a pointer to a string statically allocated inside the
dictionary. Do not free or modify the returned string!
This function returns NULL in case of error.
*/
/*--------------------------------------------------------------------------*/
const char * iniparser_getsecname(const dictionary * d, int n);
/*-------------------------------------------------------------------------*/
/**
@brief Save a dictionary to a loadable ini file
@param d Dictionary to dump
@param f Opened file pointer to dump to
This function dumps a given dictionary into a loadable ini file.
It is Ok to specify @c stderr or @c stdout as output files.
All values are quoted, these charecters are escaped:
- ' : the quote character (e.g. "String with \"Quotes\"")
- \ : the backslash character (e.g. "C:\\tmp")
*/
/*--------------------------------------------------------------------------*/
void iniparser_dump_ini(const dictionary * d, FILE * f);
/*-------------------------------------------------------------------------*/
/**
@brief Save a dictionary section to a loadable ini file
@param d Dictionary to dump
@param s Section name of dictionary to dump
@param f Opened file pointer to dump to
This function dumps a given section of a given dictionary into a loadable ini
file. It is Ok to specify @c stderr or @c stdout as output files.
*/
/*--------------------------------------------------------------------------*/
void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f);
/*-------------------------------------------------------------------------*/
/**
@brief Dump a dictionary to an opened file pointer.
@param d Dictionary to dump.
@param f Opened file pointer to dump to.
This function prints out the contents of a dictionary, one element by
line, onto the provided file pointer. It is OK to specify @c stderr
or @c stdout as output files. This function is meant for debugging
purposes mostly.
*/
/*--------------------------------------------------------------------------*/
void iniparser_dump(const dictionary * d, FILE * f);
/*-------------------------------------------------------------------------*/
/**
@brief Get the number of keys in a section of a dictionary.
@param d Dictionary to examine
@param s Section name of dictionary to examine
@return Number of keys in section
*/
/*--------------------------------------------------------------------------*/
int iniparser_getsecnkeys(const dictionary * d, const char * s);
/*-------------------------------------------------------------------------*/
/**
@brief Get the number of keys in a section of a dictionary.
@param d Dictionary to examine
@param s Section name of dictionary to examine
@param keys Already allocated array to store the keys in
@return The pointer passed as `keys` argument or NULL in case of error
This function queries a dictionary and finds all keys in a given section.
The keys argument should be an array of pointers which size has been
determined by calling `iniparser_getsecnkeys` function prior to this one.
Each pointer in the returned char pointer-to-pointer is pointing to
a string allocated in the dictionary; do not free or modify them.
*/
/*--------------------------------------------------------------------------*/
const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys);
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key
@param d Dictionary to search
@param key Key string to look for
@param def Default value to return if key not found.
@return pointer to statically allocated character string
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the pointer passed as 'def' is returned.
The returned char pointer is pointing to a string allocated in
the dictionary, do not free or modify it.
*/
/*--------------------------------------------------------------------------*/
const char * iniparser_getstring(const dictionary * d, const char * key, const char * def);
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to an int
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return integer
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
Supported values for integers include the usual C notation
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
are supported. Examples:
- "42" -> 42
- "042" -> 34 (octal -> decimal)
- "0x42" -> 66 (hexa -> decimal)
Warning: the conversion may overflow in various ways. Conversion is
totally outsourced to strtol(), see the associated man page for overflow
handling.
Credits: Thanks to A. Becker for suggesting strtol()
*/
/*--------------------------------------------------------------------------*/
int iniparser_getint(const dictionary * d, const char * key, int notfound);
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to an long int
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return integer
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
Supported values for integers include the usual C notation
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
are supported. Examples:
- "42" -> 42
- "042" -> 34 (octal -> decimal)
- "0x42" -> 66 (hexa -> decimal)
Warning: the conversion may overflow in various ways. Conversion is
totally outsourced to strtol(), see the associated man page for overflow
handling.
*/
/*--------------------------------------------------------------------------*/
long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound);
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to an int64_t
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return integer
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
Supported values for integers include the usual C notation
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
are supported. Examples:
- "42" -> 42
- "042" -> 34 (octal -> decimal)
- "0x42" -> 66 (hexa -> decimal)
Warning: the conversion may overflow in various ways. Conversion is
totally outsourced to strtoimax(), see the associated man page for overflow
handling.
This function is usefull on 32bit architectures where `long int` is only
32bit.
*/
/*--------------------------------------------------------------------------*/
int64_t iniparser_getint64(const dictionary * d, const char * key, int64_t notfound);
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to an uint64_t
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return integer
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
Supported values for integers include the usual C notation
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
are supported. Examples:
- "42" -> 42
- "042" -> 34 (octal -> decimal)
- "0x42" -> 66 (hexa -> decimal)
Warning: the conversion may overflow in various ways. Conversion is
totally outsourced to strtoumax(), see the associated man page for overflow
handling.
This function is usefull on 32bit architectures where `long int` is only
32bit.
*/
/*--------------------------------------------------------------------------*/
uint64_t iniparser_getuint64(const dictionary * d, const char * key, uint64_t notfound);
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to a double
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return double
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
*/
/*--------------------------------------------------------------------------*/
double iniparser_getdouble(const dictionary * d, const char * key, double notfound);
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to a boolean
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return integer
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
A true boolean is found if one of the following is matched:
- A string starting with 'y'
- A string starting with 'Y'
- A string starting with 't'
- A string starting with 'T'
- A string starting with '1'
A false boolean is found if one of the following is matched:
- A string starting with 'n'
- A string starting with 'N'
- A string starting with 'f'
- A string starting with 'F'
- A string starting with '0'
The notfound value returned if no boolean is identified, does not
necessarily have to be 0 or 1.
*/
/*--------------------------------------------------------------------------*/
int iniparser_getboolean(const dictionary * d, const char * key, int notfound);
/*-------------------------------------------------------------------------*/
/**
@brief Set an entry in a dictionary.
@param ini Dictionary to modify.
@param entry Entry to modify (entry name)
@param val New value to associate to the entry.
@return int 0 if Ok, -1 otherwise.
If the given entry can be found in the dictionary, it is modified to
contain the provided value. If it cannot be found, the entry is created.
It is Ok to set val to NULL.
*/
/*--------------------------------------------------------------------------*/
int iniparser_set(dictionary * ini, const char * entry, const char * val);
/*-------------------------------------------------------------------------*/
/**
@brief Delete an entry in a dictionary
@param ini Dictionary to modify
@param entry Entry to delete (entry name)
If the given entry can be found, it is deleted from the dictionary.
*/
/*--------------------------------------------------------------------------*/
void iniparser_unset(dictionary * ini, const char * entry);
/*-------------------------------------------------------------------------*/
/**
@brief Finds out if a given entry exists in a dictionary
@param ini Dictionary to search
@param entry Name of the entry to look for
@return integer 1 if entry exists, 0 otherwise
Finds out if a given entry exists in the dictionary. Since sections
are stored as keys with NULL associated values, this is the only way
of querying for the presence of sections in a dictionary.
*/
/*--------------------------------------------------------------------------*/
int iniparser_find_entry(const dictionary * ini, const char * entry) ;
/*-------------------------------------------------------------------------*/
/**
@brief Parse an ini file and return an allocated dictionary object
@param ininame Name of the ini file to read.
@return Pointer to newly allocated dictionary
This is the parser for ini files. This function is called, providing
the name of the file to be read. It returns a dictionary object that
should not be accessed directly, but through accessor functions
instead.
Iff the value is a quoted string it supports some escape sequences:
- \" or ' : the quote character
(e.g. 'String with "Quotes"' or "String with 'Quotes'")
- \ : the backslash character (e.g. "C:\tmp")
Escape sequences always start with a backslash. Additional escape sequences
might be added in the future. Backslash characters must be escaped. Any other
sequence then those outlined above is invalid and may lead to unpredictable
results.
The returned dictionary must be freed using iniparser_freedict().
*/
/*--------------------------------------------------------------------------*/
dictionary * iniparser_load(const char * ininame);
/*-------------------------------------------------------------------------*/
/**
@brief Parse an ini file and return an allocated dictionary object
@param in File to read.
@param ininame Name of the ini file to read (only used for nicer error messages)
@return Pointer to newly allocated dictionary
This is the parser for ini files. This function is called, providing
the file to be read. It returns a dictionary object that should not
be accessed directly, but through accessor functions instead.
Iff the value is a quoted string it supports some escape sequences:
- \" or ' : the quote character
(e.g. 'String with "Quotes"' or "String with 'Quotes'")
- \ : the backslash character (e.g. "C:\tmp")
Escape sequences always start with a backslash. Additional escape sequences
might be added in the future. Backslash characters must be escaped. Any other
sequence then those outlined above is invalid and may lead to unpredictable
results.
The returned dictionary must be freed using iniparser_freedict().
*/
/*--------------------------------------------------------------------------*/
dictionary * iniparser_load_file(FILE * in, const char * ininame);
/*-------------------------------------------------------------------------*/
/**
@brief Free all memory associated to an ini dictionary
@param d Dictionary to free
Free all memory associated to an ini dictionary.
It is mandatory to call this function before the dictionary object
gets out of the current context.
*/
/*--------------------------------------------------------------------------*/
void iniparser_freedict(dictionary * d);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,44 @@
#ifndef __PAFSTD__
#define __PAFSTD__
#include <paf/std/stdlib.h>
#include <paf/std/string.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#define malloc sce_paf_malloc
#define memcpy sce_paf_memcpy
#define memset sce_paf_memset
#define memmove sce_paf_memmove
#define free sce_paf_free
#define calloc sce_paf_calloc
// _ctype_ isnt called that in scelibc, so just stub the functions that are needed
inline int _is_space(char c) {
return (c == ' ' || c == '\f' || c == '\n' ||
c == '\r' || c == '\t' || c == '\v');
}
inline int _to_lower(int c) {
if (c >= 'A' && c <= 'Z') {
return c + ('a' - 'A');
}
return c;
}
inline int _is_digit(int c) {
return (c >= '0' && c <= '9');
}
#undef isspace
#undef tolower
#undef isdigit
#define isspace _is_space
#define tolower _to_lower
#define isdigit _is_digit
#endif

View File

@ -1,55 +1,395 @@
// clang-format off
#include <stdarg.h>
#include <paf.h>
// clang-format on
#include "pafinc.h"
#include <app_settings.h>
#include <psp2/kernel/clib.h>
#include <psp2/io/fcntl.h>
#include <psp2/sysmodule.h>
#include <psp2/kernel/modulemgr.h>
#include <psp2/appmgr.h>
#include "fios2.h"
#include <iniparser.h>
const char* g_iniPath = "ux0:data/isledecomp/isle/isle.ini";
paf::Framework* g_fw;
paf::ui::Scene* g_rootPage;
paf::Plugin* g_plugin;
paf::Plugin* g_configPlugin;
sce::AppSettings* g_appSettings;
sce::AppSettings::Interface* g_appSetIf;
void loadPluginCB(paf::Plugin* plugin)
{
g_plugin = plugin;
plugin->SetLocale(Locale_EN);
paf::Plugin::PageOpenParam pageOpenParam;
pageOpenParam.option = paf::Plugin::PageOption_None;
paf::ui::Scene* pScene = plugin->PageOpen("page_main", pageOpenParam);
g_rootPage = pScene;
struct Config {
paf::string m_base_path;
paf::string m_cd_path;
paf::string m_save_path;
int m_transition_type;
int m_texture_quality;
int m_model_quality;
int m_touch_scheme;
bool m_wide_view_angle;
bool m_music;
bool m_3d_sound;
bool m_haptic;
bool m_draw_cursor;
bool m_texture_load;
paf::string m_texture_path;
float m_max_lod;
int m_max_actors;
float m_frame_delta;
const auto saveAndExitButton = static_cast<paf::ui::Button*>(pScene->FindChild("save_exit_button"));
const auto startAndExitButton = static_cast<paf::ui::Button*>(pScene->FindChild("start_game_button"));
const auto exitButton = static_cast<paf::ui::Button*>(pScene->FindChild("exit_button"));
void Init() {
m_frame_delta = 10.0f;
m_transition_type = 3; // 3: Mosaic
m_wide_view_angle = true;
m_music = true;
m_3d_sound = true;
m_haptic = true;
m_touch_scheme = 2;
m_texture_load = true;
m_texture_path = "/textures/";
m_model_quality = 2;
m_texture_quality = 1;
m_max_lod = 3.5f;
m_max_actors = 20;
}
void LoadIni() {
dictionary* dict = iniparser_load(g_iniPath);
if (!dict) {
dict = dictionary_new(0);
}
#define GET_INT(x, name) x = iniparser_getint(dict, name, x)
#define GET_FLOAT(x, name) x = iniparser_getdouble(dict, name, x)
#define GET_STRING(x, name) x = iniparser_getstring(dict, name, x.c_str()); sceClibPrintf("%s: %s\n", name, x.c_str())
#define GET_BOOLEAN(x, name) x = iniparser_getboolean(dict, name, x)
GET_STRING(m_base_path, "isle:diskpath");
GET_STRING(m_cd_path, "isle:cdpath");
GET_STRING(m_save_path, "isle:savepath");
//m_display_bit_depth = iniparser_getint(dict, "isle:Display Bit Depth", -1);
//GET_BOOLEAN(m_flip_surfaces, "isle:Flip Surfaces");
//GET_BOOLEAN(m_full_screen, "isle:Full Screen");
//GET_BOOLEAN(m_exclusive_full_screen, "isle:Exclusive Full Screen");
GET_INT(m_transition_type, "isle:Transition Type");
GET_INT(m_touch_scheme, "isle:Touch Scheme");
//GET_BOOLEAN(m_3d_video_ram, "isle:Back Buffers in Video RAM");
GET_BOOLEAN(m_wide_view_angle, "isle:Wide View Angle");
GET_BOOLEAN(m_3d_sound, "isle:3DSound");
GET_BOOLEAN(m_draw_cursor, "isle:Draw Cursor");
GET_INT(m_model_quality, "isle:Island Quality");
GET_INT(m_texture_quality, "isle:Island Texture");
//GET_BOOLEAN(m_use_joystick, "isle:UseJoystick");
GET_BOOLEAN(m_haptic, "isle:Haptic");
GET_BOOLEAN(m_music, "isle:Music");
//GET_INT(m_joystick_index, "isle:JoystickIndex");
GET_FLOAT(m_max_lod, "isle:Max LOD");
GET_INT(m_max_actors, "isle:Max Allowed Extras");
GET_BOOLEAN(m_texture_load, "extensions:texture loader");
GET_STRING(m_texture_path, "texture loader:texture path");
//GET_INT(m_aspect_ratio, "isle:Aspect Ratio");
//GET_INT(m_x_res, "isle:Horizontal Resolution");
//GET_INT(m_y_res, "isle:Vertical Resolution");
GET_FLOAT(m_frame_delta, "isle:Frame Delta");
#undef GET_INT
#undef GET_FLOAT
#undef GET_STRING
#undef GET_BOOLEAN
iniparser_freedict(dict);
}
bool SaveIni() {
dictionary* dict = dictionary_new(0);
char buffer[128];
#define SetIniBool(NAME, VALUE) iniparser_set(dict, NAME, VALUE ? "true" : "false")
#define SetIniInt(NAME, VALUE) { \
sceClibPrintf(buffer, "%d", VALUE); \
iniparser_set(dict, NAME, buffer); \
}
#define SetIniFloat(NAME, VALUE) { \
sceClibPrintf(buffer, "%f", VALUE); \
iniparser_set(dict, NAME, buffer); \
}
#define SetString(NAME, VALUE) iniparser_set(dict, NAME, VALUE)
SetIniInt("isle:Display Bit Depth", 32);
SetIniBool("isle:Flip Surfaces", false);
SetIniBool("isle:Full Screen", true);
SetIniBool("isle:Exclusive Full Screen", true);
SetIniBool("isle:Wide View Angle", true); // option?
SetIniInt("isle:Transition Type", m_transition_type);
SetIniInt("isle:Touch Scheme", m_touch_scheme);
SetIniBool("isle:3DSound", m_3d_sound);
SetIniBool("isle:Music", m_music);
SetIniBool("isle:Haptic", m_haptic);
SetIniBool("isle:UseJoystick", true);
SetIniInt("isle:JoystickIndex", 0);
SetIniBool("isle:Draw Cursor", m_draw_cursor);
SetIniBool("extensions:texture loader", m_texture_load);
SetString("texture loader:texture path", m_texture_path.c_str());
SetIniBool("isle:Back Buffers in Video RAM", true);
SetIniInt("isle:Island Quality", m_model_quality);
SetIniInt("isle:Island Texture", m_texture_quality);
SetIniFloat("isle:Max LOD", m_max_lod);
SetIniInt("isle:Max Allowed Extras", m_max_actors);
SetIniInt("isle:Aspect Ratio", 0);
SetIniInt("isle:Horizontal Resolution", 640);
SetIniInt("isle:Vertical Resolution", 480);
SetIniFloat("isle:Frame Delta", 10.0f);
#undef SetIniBool
#undef SetIniInt
#undef SetIniFloat
#undef SetString
FILE* fd = fopen(g_iniPath, "w");
if(fd) {
iniparser_dump_ini(dict, fd);
}
iniparser_freedict(dict);
return true;
}
void ToSettings(sce::AppSettings* appSettings) {
appSettings->SetString("data_path", this->m_base_path.c_str());
appSettings->SetString("save_path", this->m_save_path.c_str());
}
void FromSettings(sce::AppSettings* appSettings) {
}
};
Config g_config;
paf::Plugin* load_config_plugin(paf::Framework* paf_fw) {
paf::Plugin::InitParam pluginParam;
pluginParam.name = "config_plugin";
pluginParam.caller_name = "__main__";
pluginParam.resource_file = "app0:/config_plugin.rco";
pluginParam.init_func = NULL;
pluginParam.start_func = NULL;
pluginParam.stop_func = NULL;
pluginParam.exit_func = NULL;
paf::Plugin::LoadSync(pluginParam);
return paf_fw->FindPlugin("config_plugin");
}
int paf_main(void)
int load_app_settings_plugin() {
paf::Plugin::InitParam pluginParam;
sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_INTERNAL_BXCE);
sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_INTERNAL_INI_FILE_PROCESSOR);
sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_INTERNAL_COMMON_GUI_DIALOG);
pluginParam.name = "app_settings_plugin";
pluginParam.resource_file = "vs0:vsh/common/app_settings_plugin.rco";
pluginParam.caller_name = "__main__";
pluginParam.set_param_func = sce::AppSettings::PluginSetParamCB;
pluginParam.init_func = sce::AppSettings::PluginInitCB;
pluginParam.start_func = sce::AppSettings::PluginStartCB;
pluginParam.stop_func = sce::AppSettings::PluginStopCB;
pluginParam.exit_func = sce::AppSettings::PluginExitCB;
pluginParam.module_file = "vs0:vsh/common/app_settings.suprx";
pluginParam.draw_priority = 0x96;
paf::Plugin::LoadSync(pluginParam);
return 0;
}
bool do_launch = false;
void save_and_exit() {
g_config.FromSettings(g_appSettings);
g_config.SaveIni();
g_fw->RequestShutdown();
}
void save_and_launch() {
g_config.FromSettings(g_appSettings);
g_config.SaveIni();
g_fw->RequestShutdown();
do_launch = true;
}
void CBOnStartPageTransition(const char *elementId, int32_t type)
{
paf::Framework::InitParam fwParam;
}
void CBOnPageActivate(const char *elementId, int32_t type)
{
}
void CBOnPageDeactivate(const char *elementId, int32_t type)
{
}
int32_t CBOnCheckVisible(const char *elementId, bool *pIsVisible)
{
*pIsVisible = true;
return SCE_OK;
}
int32_t CBOnPreCreate(const char *elementId, sce::AppSettings::Element *element)
{
return SCE_OK;
}
int32_t CBOnPostCreate(const char *elementId, paf::ui::Widget *widget)
{
return SCE_OK;
}
int32_t CBOnPress(const char *elementId, const char *newValue)
{
if(sce_paf_strcmp(elementId, "save_exit_button") == 0) {
save_and_exit();
return SCE_OK;
}
if(sce_paf_strcmp(elementId, "save_launch_button") == 0) {
save_and_launch();
return SCE_OK;
}
sceClibPrintf("OnPress %s %s\n", elementId, newValue);
return SCE_OK;
}
int32_t CBOnPress2(const char *elementId, const char *newValue)
{
return SCE_OK;
}
void CBOnTerm(int32_t result)
{
sceKernelExitProcess(0);
}
const wchar_t *CBOnGetString(const char *elementId)
{
wchar_t* res = g_configPlugin->GetString(elementId);
if(res[0] != 0) {
return res;
}
return L"unknown string";
}
int32_t CBOnGetSurface(paf::graph::Surface **surf, const char *elementId)
{
return SCE_OK;
}
void open_settings() {
g_config.Init();
g_config.LoadIni();
g_config.ToSettings(g_appSettings);
sce::AppSettings::InterfaceCallbacks ifCb;
ifCb.onStartPageTransitionCb = CBOnStartPageTransition;
ifCb.onPageActivateCb = CBOnPageActivate;
ifCb.onPageDeactivateCb = CBOnPageDeactivate;
ifCb.onCheckVisible = CBOnCheckVisible;
ifCb.onPreCreateCb = CBOnPreCreate;
ifCb.onPostCreateCb = CBOnPostCreate;
ifCb.onPressCb = CBOnPress;
ifCb.onPressCb2 = CBOnPress2;
ifCb.onTermCb = CBOnTerm;
ifCb.onGetStringCb = (sce::AppSettings::InterfaceCallbacks::GetStringCallback)CBOnGetString;
ifCb.onGetSurfaceCb = CBOnGetSurface;
paf::wstring msg_save_exit(g_configPlugin->GetString("msg_save_exit"));
paf::wstring msg_save_launch(g_configPlugin->GetString("msg_save_launch"));
paf::wstring msg_exit(g_configPlugin->GetString("msg_exit"));
paf::Plugin* appSetPlug = paf::Plugin::Find("app_settings_plugin");
g_appSetIf = (sce::AppSettings::Interface *)appSetPlug->GetInterface(1);
g_appSetIf->Show(&ifCb);
g_appSetIf->AddFooterButton("save_exit_button", &msg_save_exit, 1);
g_appSetIf->AddFooterButton("save_launch_button", &msg_save_launch, 2);
g_appSetIf->ShowFooter();
}
#define MAX_PATH_LENGTH 256
static int64_t g_OpStorage[SCE_FIOS_OP_STORAGE_SIZE(64, MAX_PATH_LENGTH) / sizeof(int64_t) + 1];
static int64_t g_ChunkStorage[SCE_FIOS_CHUNK_STORAGE_SIZE(1024) / sizeof(int64_t) + 1];
static int64_t g_FHStorage[SCE_FIOS_FH_STORAGE_SIZE(1024, MAX_PATH_LENGTH) / sizeof(int64_t) + 1];
static int64_t g_DHStorage[SCE_FIOS_DH_STORAGE_SIZE(32, MAX_PATH_LENGTH) / sizeof(int64_t) + 1];
void init_fios2() {
sceSysmoduleLoadModule(SCE_SYSMODULE_FIOS2);
SceFiosParams params = SCE_FIOS_PARAMS_INITIALIZER;
params.opStorage.pPtr = g_OpStorage;
params.opStorage.length = sizeof(g_OpStorage);
params.chunkStorage.pPtr = g_ChunkStorage;
params.chunkStorage.length = sizeof(g_ChunkStorage);
params.fhStorage.pPtr = g_FHStorage;
params.fhStorage.length = sizeof(g_FHStorage);
params.dhStorage.pPtr = g_DHStorage;
params.dhStorage.length = sizeof(g_DHStorage);
params.pathMax = MAX_PATH_LENGTH;
params.threadAffinity[SCE_FIOS_IO_THREAD] = 0x10000;
params.threadAffinity[SCE_FIOS_CALLBACK_THREAD] = 0;
params.threadAffinity[SCE_FIOS_DECOMPRESSOR_THREAD] = 0;
params.threadPriority[SCE_FIOS_IO_THREAD] = 64;
params.threadPriority[SCE_FIOS_CALLBACK_THREAD] = 191;
params.threadPriority[SCE_FIOS_DECOMPRESSOR_THREAD] = 191;
int ret = sceFiosInitialize(&params);
if(ret < 0) {
sceClibPrintf("sceFiosInitialize: %08x\n", ret);
}
}
int paf_main(void) {
init_fios2();
paf::Framework::InitParam fwParam;
fwParam.mode = paf::Framework::Mode_Normal;
paf::Framework* paf_fw = new paf::Framework(fwParam);
if (paf_fw != NULL) {
g_fw = paf_fw;
paf::Framework* paf_fw = new paf::Framework(fwParam);
g_fw = paf_fw;
paf_fw->LoadCommonResourceSync();
paf_fw->LoadCommonResourceSync();
load_app_settings_plugin();
paf::Plugin* configPlugin = load_config_plugin(paf_fw);
g_configPlugin = configPlugin;
configPlugin->SetLocale(Locale_EN);
paf::Plugin::InitParam pluginParam;
size_t fileSize = 0;
const char *mimeType = nullptr;
auto settingsXmlFile = configPlugin->GetResource()->GetFile("settings.xml", &fileSize, &mimeType);
pluginParam.name = "config_plugin";
pluginParam.caller_name = "__main__";
pluginParam.resource_file = "app0:/config_plugin.rco";
pluginParam.init_func = NULL;
pluginParam.start_func = loadPluginCB;
pluginParam.stop_func = NULL;
pluginParam.exit_func = NULL;
sce::AppSettings::InitParam settingsParam;
settingsParam.xml_file = settingsXmlFile;
settingsParam.alloc_cb = sce_paf_malloc;
settingsParam.free_cb = sce_paf_free;
settingsParam.realloc_cb = sce_paf_realloc;
settingsParam.safemem_offset = 0;
settingsParam.safemem_size = 0x400;
paf::Plugin::LoadSync(pluginParam);
paf_fw->Run();
}
sce::AppSettings::GetInstance(settingsParam, &g_appSettings);
g_appSettings->Initialize();
sceClibPrintf("[SAMPLE] Failed to run PAF instance\n");
open_settings();
paf_fw->Run();
exit(0);
return 0;
if(do_launch) {
sceAppMgrLoadExec("app0:/eboot.bin", NULL, NULL);
}
return 0;
}

View File

@ -1,7 +1,4 @@
// clang-format off
#include <stdarg.h>
#include <paf.h>
// clang-format on
#include "pafinc.h"
#include <psp2/kernel/clib.h>
#include <psp2/kernel/modulemgr.h>
#include <psp2/kernel/processmgr.h>
@ -59,8 +56,8 @@ extern "C" int module_start(SceSize args, void* argp)
);
}
paf_main();
res = paf_main();
sceKernelExitProcess(res);
return SCE_KERNEL_START_SUCCESS;
}