Compare commits
1 Commits
main
..
7058a14be0
| Author | SHA1 | Date | |
|---|---|---|---|
| 7058a14be0 |
+122
-6
@@ -1,5 +1,7 @@
|
||||
BasedOnStyle: WebKit
|
||||
IndentWidth: 8
|
||||
---
|
||||
Language: C
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Right
|
||||
ColumnLimit: 80
|
||||
@@ -44,12 +46,126 @@ ReflowComments: true
|
||||
SpacesBeforeTrailingComments: 3
|
||||
TabWidth: 8
|
||||
UseTab: AlignWithSpaces
|
||||
BreakAfterReturnType: Automatic
|
||||
PenaltyBreakAssignment: 0
|
||||
PenaltyReturnTypeOnItsOwnLine: 100000000
|
||||
PenaltyExcessCharacter: 10000000
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakBeforeFirstCallParameter: 0
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000000
|
||||
PenaltyExcessCharacter: 5
|
||||
PenaltyBreakOpenParenthesis: 5
|
||||
PenaltyBreakBeforeFirstCallParameter: 5
|
||||
PenaltyIndentedWhitespace: 0
|
||||
AttributeMacros:
|
||||
- FX_API
|
||||
ForEachMacros:
|
||||
- fx_btree_foreach
|
||||
- fx_queue_foreach
|
||||
MacroBlockBegin: "FX_(TYPE|ASSEMBLY)_.*_BEGIN"
|
||||
MacroBlockEnd: "FX_(TYPE|ASSEMBLY)_.*_END"
|
||||
---
|
||||
Language: ObjC
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Right
|
||||
ColumnLimit: 80
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignConsecutiveBitFields: None
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: AlignAfterOperator
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLambdasOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
BitFieldColonSpacing: Both
|
||||
BreakBeforeBraces: Linux
|
||||
BreakBeforeBinaryOperators: All
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakInheritanceList: BeforeComma
|
||||
BreakStringLiterals: true
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: true
|
||||
IncludeBlocks: Regroup
|
||||
SortIncludes: true
|
||||
IndentRequires: true
|
||||
NamespaceIndentation: Inner
|
||||
ReflowComments: true
|
||||
SpacesBeforeTrailingComments: 3
|
||||
TabWidth: 8
|
||||
UseTab: AlignWithSpaces
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000000
|
||||
PenaltyExcessCharacter: 5
|
||||
PenaltyBreakOpenParenthesis: 5
|
||||
PenaltyBreakBeforeFirstCallParameter: 5
|
||||
PenaltyIndentedWhitespace: 0
|
||||
AttributeMacros:
|
||||
- FX_API
|
||||
ForEachMacros:
|
||||
- fx_btree_foreach
|
||||
- fx_queue_foreach
|
||||
MacroBlockBegin: "FX_(TYPE|ASSEMBLY)_.*_BEGIN"
|
||||
MacroBlockEnd: "FX_(TYPE|ASSEMBLY)_.*_END"
|
||||
---
|
||||
Language: Cpp
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Right
|
||||
ColumnLimit: 80
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignConsecutiveBitFields: None
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: AlignAfterOperator
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLambdasOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
BitFieldColonSpacing: Both
|
||||
BreakBeforeBraces: Linux
|
||||
BreakBeforeBinaryOperators: All
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakInheritanceList: BeforeComma
|
||||
BreakStringLiterals: true
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: true
|
||||
IncludeBlocks: Regroup
|
||||
SortIncludes: true
|
||||
IndentRequires: true
|
||||
NamespaceIndentation: Inner
|
||||
ReflowComments: true
|
||||
SpacesBeforeTrailingComments: 3
|
||||
TabWidth: 8
|
||||
UseTab: AlignWithSpaces
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000000
|
||||
PenaltyExcessCharacter: 9999999
|
||||
PenaltyBreakOpenParenthesis: 5
|
||||
PenaltyBreakBeforeFirstCallParameter: 5
|
||||
PenaltyIndentedWhitespace: 0
|
||||
AttributeMacros:
|
||||
- FX_API
|
||||
|
||||
+8
-27
@@ -1,26 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
project(fx C ASM)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
include (TestBigEndian)
|
||||
include(Templates)
|
||||
include(Platform)
|
||||
|
||||
test_big_endian(is_big_endian)
|
||||
if (is_big_endian)
|
||||
message(STATUS "Target is Big Endian")
|
||||
add_compile_definitions(FX_ENDIAN=1)
|
||||
else ()
|
||||
message(STATUS "Target is Little Endian")
|
||||
add_compile_definitions(FX_ENDIAN=0)
|
||||
endif ()
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
set(fx_source_root ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
@@ -47,9 +33,10 @@ endif ()
|
||||
|
||||
message(STATUS "Floating point support: ${fx_enable_floating_point}")
|
||||
|
||||
get_platform_details(
|
||||
SYSTEM fx_system_name
|
||||
PROCESSOR fx_system_arch)
|
||||
set(fx_system_name ${CMAKE_SYSTEM_NAME})
|
||||
string(TOLOWER ${fx_system_name} fx_system_name)
|
||||
set(fx_system_arch ${CMAKE_SYSTEM_PROCESSOR})
|
||||
string(TOLOWER ${fx_system_arch} fx_system_arch)
|
||||
|
||||
message(STATUS "Target system: ${fx_system_name}-${fx_system_arch}")
|
||||
|
||||
@@ -57,16 +44,10 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Templates.cmake)
|
||||
|
||||
foreach (assembly ${fx_assemblies})
|
||||
add_subdirectory(assemblies/${assembly})
|
||||
endforeach (assembly)
|
||||
|
||||
if (fx_enable_tests)
|
||||
add_subdirectory(test)
|
||||
endif ()
|
||||
|
||||
set_target_properties(
|
||||
${fx_assemblies}
|
||||
PROPERTIES
|
||||
INSTALL_RPATH
|
||||
"${CMAKE_INSTALL_RPATH};${CMAKE_INSTALL_PREFIX}/lib")
|
||||
add_subdirectory(test)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <fx/macros.h>
|
||||
#include <fx/reflection/assembly.h>
|
||||
|
||||
FX_ASSEMBLY_BEGIN(fx_cmdline)
|
||||
FX_ASSEMBLY_BEGIN()
|
||||
FX_ASSEMBLY_NAME("fx.cmdline");
|
||||
FX_ASSEMBLY_VERSION(1, 0, 0, 0);
|
||||
FX_ASSEMBLY_END(fx_cmdline)
|
||||
FX_ASSEMBLY_END()
|
||||
|
||||
@@ -7,7 +7,8 @@ FX_ASSEMBLY_BEGIN()
|
||||
FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "array", fx_array);
|
||||
FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "bitbuffer", fx_bitbuffer);
|
||||
FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "bitmap", fx_bitmap);
|
||||
FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "hashtable", fx_hashtable);
|
||||
FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "dict", fx_dict);
|
||||
FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "hashmap", fx_hashmap);
|
||||
FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "list", fx_list);
|
||||
FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "tree", fx_tree);
|
||||
FX_ASSEMBLY_END()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <fx/macros.h>
|
||||
#include <fx/reflection/assembly.h>
|
||||
|
||||
FX_ASSEMBLY_BEGIN(fx_compression)
|
||||
FX_ASSEMBLY_BEGIN()
|
||||
FX_ASSEMBLY_NAME("fx.compression");
|
||||
FX_ASSEMBLY_VERSION(1, 0, 0, 0);
|
||||
FX_ASSEMBLY_END(fx_compression)
|
||||
FX_ASSEMBLY_END()
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
add_fx_assembly(
|
||||
NAME fx.diagnostics
|
||||
NAMESPACES fx.diagnostics
|
||||
DEPENDENCIES fx.runtime fx.collections fx.io)
|
||||
@@ -1,7 +0,0 @@
|
||||
#include <fx/macros.h>
|
||||
#include <fx/reflection/assembly.h>
|
||||
|
||||
FX_ASSEMBLY_BEGIN(fx_diagnostics)
|
||||
FX_ASSEMBLY_NAME("fx.diagnostics");
|
||||
FX_ASSEMBLY_VERSION(1, 0, 0, 0);
|
||||
FX_ASSEMBLY_END(fx_diagnostics)
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <fx/macros.h>
|
||||
#include <fx/reflection/assembly.h>
|
||||
|
||||
FX_ASSEMBLY_BEGIN(fx_io)
|
||||
FX_ASSEMBLY_NAME("fx.io");
|
||||
FX_ASSEMBLY_VERSION(1, 0, 0, 0);
|
||||
FX_ASSEMBLY_END(fx_io)
|
||||
FX_ASSEMBLY_BEGIN()
|
||||
FX_ASSEMBLY_NAME("fx.io");
|
||||
FX_ASSEMBLY_VERSION(1, 0, 0, 0);
|
||||
FX_ASSEMBLY_END()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
add_fx_assembly(
|
||||
NAME fx.runtime
|
||||
NAMESPACES fx fx.reflection
|
||||
DEPENDENCIES Threads::Threads)
|
||||
NAMESPACES fx fx.reflection)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <fx/macros.h>
|
||||
#include <fx/reflection/assembly.h>
|
||||
|
||||
FX_ASSEMBLY_BEGIN(fx_runtime)
|
||||
FX_ASSEMBLY_BEGIN()
|
||||
FX_ASSEMBLY_NAME("fx.runtime");
|
||||
FX_ASSEMBLY_VERSION(1, 0, 0, 0);
|
||||
FX_ASSEMBLY_EXPORT_TYPE("fx", "stream", fx_stream);
|
||||
@@ -9,4 +9,4 @@ FX_ASSEMBLY_BEGIN(fx_runtime)
|
||||
FX_ASSEMBLY_EXPORT_TYPE("fx", "stringstream", fx_stringstream);
|
||||
FX_ASSEMBLY_EXPORT_TYPE("fx", "iterator", fx_iterator);
|
||||
FX_ASSEMBLY_EXPORT_TYPE("fx.reflection", "assembly", fx_assembly);
|
||||
FX_ASSEMBLY_END(fx_runtime)
|
||||
FX_ASSEMBLY_END()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <fx/macros.h>
|
||||
#include <fx/reflection/assembly.h>
|
||||
|
||||
FX_ASSEMBLY_BEGIN(fx_serial)
|
||||
FX_ASSEMBLY_BEGIN()
|
||||
FX_ASSEMBLY_NAME("fx.serial");
|
||||
FX_ASSEMBLY_VERSION(1, 0, 0, 0);
|
||||
FX_ASSEMBLY_END(fx_serial)
|
||||
FX_ASSEMBLY_END()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <fx/macros.h>
|
||||
#include <fx/reflection/assembly.h>
|
||||
|
||||
FX_ASSEMBLY_BEGIN(fx_term)
|
||||
FX_ASSEMBLY_BEGIN()
|
||||
FX_ASSEMBLY_NAME("fx.term");
|
||||
FX_ASSEMBLY_VERSION(1, 0, 0, 0);
|
||||
FX_ASSEMBLY_END(fx_term)
|
||||
FX_ASSEMBLY_END()
|
||||
|
||||
+108
-43
@@ -49,37 +49,43 @@ if (FX_STATIC)
|
||||
set(_lib_suffix "-s")
|
||||
endif ()
|
||||
|
||||
set(assemblies ${FX_FIND_COMPONENTS})
|
||||
set(required_vars)
|
||||
set(supported_components Core Ds Term Cmd Io Serial Compress)
|
||||
set(components ${FX_FIND_COMPONENTS})
|
||||
string(REPLACE ";" ", " supported_components_string_list "${supported_components}")
|
||||
|
||||
if (NOT FX_INCLUDE_DIR)
|
||||
find_path(FX_INCLUDE_DIR
|
||||
NAMES fx/misc.h ${FX_FIND_ARGS}
|
||||
PATH_SUFFIXES include
|
||||
PATHS ${FX_SEARCH_PATHS})
|
||||
if (NOT components)
|
||||
set(components ${supported_components})
|
||||
endif ()
|
||||
|
||||
set(required_vars FX_INCLUDE_DIR)
|
||||
set(required_vars)
|
||||
|
||||
foreach (assembly ${assemblies})
|
||||
string(TOLOWER ${assembly} header_name)
|
||||
string(REPLACE "." "_" macro_name ${assembly})
|
||||
string(TOUPPER ${macro_name} macro_name)
|
||||
foreach (component ${components})
|
||||
if (NOT "${component}" IN_LIST supported_components)
|
||||
message(FATAL_ERROR "'${component}' is not a valid FX module.\nSupported modules: ${supported_components_string_list}")
|
||||
endif ()
|
||||
|
||||
set(lib_name ${assembly}${_lib_suffix})
|
||||
string(TOLOWER ${component} header_name)
|
||||
set(lib_name ${header_name}${_lib_suffix})
|
||||
|
||||
if (NOT ${macro_name}_LIBRARY)
|
||||
find_library(${macro_name}_LIBRARY
|
||||
NAMES ${lib_name} ${FX_FIND_ARGS}
|
||||
if (NOT FX_${component}_INCLUDE_DIR)
|
||||
find_path(FX_${component}_INCLUDE_DIR
|
||||
NAMES fx/${header_name}.h ${FX_FIND_ARGS}
|
||||
PATH_SUFFIXES include
|
||||
PATHS ${FX_SEARCH_PATHS})
|
||||
endif ()
|
||||
|
||||
if (NOT FX_${component}_LIBRARY)
|
||||
find_library(FX_${component}_LIBRARY
|
||||
NAMES fx-${lib_name} ${FX_FIND_ARGS}
|
||||
PATH_SUFFIXES lib
|
||||
PATHS ${FX_SEARCH_PATHS})
|
||||
else ()
|
||||
# on Windows, ensure paths are in canonical format (forward slahes):
|
||||
file(TO_CMAKE_PATH "${${macro_name}_LIBRARY}" ${macro_name}_LIBRARY)
|
||||
file(TO_CMAKE_PATH "${FX_${component}_LIBRARY}" FX_${component}_LIBRARY)
|
||||
endif()
|
||||
|
||||
list(APPEND required_vars ${macro_name}_LIBRARY)
|
||||
endforeach (assembly)
|
||||
list(APPEND required_vars FX_${component}_INCLUDE_DIR FX_${component}_LIBRARY)
|
||||
endforeach (component)
|
||||
|
||||
unset(FX_FIND_ARGS)
|
||||
|
||||
@@ -90,35 +96,94 @@ find_package_handle_standard_args(FX
|
||||
|
||||
if (FX_FOUND)
|
||||
set(created_targets)
|
||||
foreach (assembly ${assemblies})
|
||||
set(target_name ${assembly})
|
||||
string(REPLACE "fx." "" target_name ${target_name})
|
||||
string(SUBSTRING ${target_name} 0 1 target_name_prefix)
|
||||
string(TOUPPER ${target_name_prefix} target_name_prefix)
|
||||
string(SUBSTRING ${target_name} 1 -1 target_name_suffix)
|
||||
set(target_name ${target_name_prefix}${target_name_suffix})
|
||||
foreach (component ${components})
|
||||
string(TOLOWER ${component} header_name)
|
||||
set(lib_name ${header_name}${_lib_suffix})
|
||||
|
||||
string(TOLOWER ${assembly} header_name)
|
||||
string(REPLACE "." "_" macro_name ${assembly})
|
||||
string(REPLACE "." "_" macro_name ${assembly})
|
||||
string(TOUPPER ${macro_name} macro_name)
|
||||
|
||||
set(lib_name ${assembly}${_lib_suffix})
|
||||
|
||||
if (NOT TARGET FX::${target_name})
|
||||
add_library(FX::${target_name} UNKNOWN IMPORTED)
|
||||
set_target_properties(FX::${target_name} PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${FX_INCLUDE_DIR}")
|
||||
target_compile_definitions(FX::${target_name} INTERFACE _CRT_SECURE_NO_WARNINGS=1)
|
||||
if(NOT TARGET FX::${component})
|
||||
add_library(FX::${component} UNKNOWN IMPORTED)
|
||||
set_target_properties(FX::${component} PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${FX_${component}_INCLUDE_DIR}")
|
||||
target_compile_definitions(FX::${component} INTERFACE _CRT_SECURE_NO_WARNINGS=1)
|
||||
|
||||
if (FX_STATIC)
|
||||
target_compile_definitions(FX::${target_name} INTERFACE FX_STATIC=1)
|
||||
target_compile_definitions(FX::${component} INTERFACE FX_STATIC=1)
|
||||
endif ()
|
||||
|
||||
set_target_properties(FX::${target_name} PROPERTIES
|
||||
set_target_properties(FX::${component} PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||
IMPORTED_LOCATION "${${macro_name}_LIBRARY}")
|
||||
set(created_targets ${created_targets} ${assembly})
|
||||
IMPORTED_LOCATION "${FX_${component}_LIBRARY}")
|
||||
set(created_targets ${created_targets} ${component})
|
||||
endif ()
|
||||
endforeach (assembly)
|
||||
endforeach (component)
|
||||
|
||||
foreach (component ${created_targets})
|
||||
if ("${component}" STREQUAL "Ds")
|
||||
if (NOT TARGET FX::Core)
|
||||
message(FATAL_ERROR "FX: Module 'Ds' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(FX::Ds INTERFACE FX::Core)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Term")
|
||||
if (NOT TARGET FX::Core)
|
||||
message(FATAL_ERROR "FX: Module 'Term' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET FX::Ds)
|
||||
message(FATAL_ERROR "FX: Module 'Term' depends on 'Ds', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(FX::Term INTERFACE FX::Core FX::Ds)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Serial")
|
||||
if (NOT TARGET FX::Core)
|
||||
message(FATAL_ERROR "FX: Module 'Serial' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET FX::Ds)
|
||||
message(FATAL_ERROR "FX: Module 'Serial' depends on 'Ds', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(FX::Serial INTERFACE FX::Core FX::Ds)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Cmd")
|
||||
if (NOT TARGET FX::Core)
|
||||
message(FATAL_ERROR "FX: Module 'Cmd' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET FX::Ds)
|
||||
message(FATAL_ERROR "FX: Module 'Cmd' depends on 'Ds', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET FX::Term)
|
||||
message(FATAL_ERROR "FX: Module 'Cmd' depends on 'Term', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(FX::Cmd INTERFACE FX::Core FX::Ds FX::Term)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Io")
|
||||
if (NOT TARGET FX::Core)
|
||||
message(FATAL_ERROR "FX: Module 'Io' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET FX::Ds)
|
||||
message(FATAL_ERROR "FX: Module 'Io' depends on 'Ds', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(FX::Io INTERFACE FX::Core FX::Ds)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Compress")
|
||||
if (NOT TARGET FX::Core)
|
||||
message(FATAL_ERROR "FX: Module 'Compress' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(FX::Compress INTERFACE FX::Core FX::Ds)
|
||||
endif ()
|
||||
endforeach (component)
|
||||
endif()
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
function(get_platform_details)
|
||||
set(options)
|
||||
set(one_value_args SYSTEM PROCESSOR)
|
||||
set(multi_value_args
|
||||
NAMESPACES
|
||||
DEPENDENCIES
|
||||
LIBS)
|
||||
cmake_parse_arguments(PARSE_ARGV 0 arg
|
||||
"${options}"
|
||||
"${one_value_args}"
|
||||
"${multi_value_args}")
|
||||
|
||||
set(system_name "")
|
||||
|
||||
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
|
||||
set(system_name "linux")
|
||||
elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
|
||||
set(system_name "apple")
|
||||
elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
|
||||
set(system_name "win32")
|
||||
else ()
|
||||
string(TOLOWER "${CMAKE_SYSTEM_NAME}" system_name)
|
||||
endif ()
|
||||
|
||||
if ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64")
|
||||
set(system_arch "amd64")
|
||||
elseif ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "arm64")
|
||||
set(system_arch "aarch64")
|
||||
else ()
|
||||
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" system_arch)
|
||||
endif ()
|
||||
|
||||
set(${arg_SYSTEM} ${system_name} PARENT_SCOPE)
|
||||
set(${arg_PROCESSOR} ${system_arch} PARENT_SCOPE)
|
||||
endfunction (get_platform_details)
|
||||
|
||||
+10
-17
@@ -18,12 +18,10 @@ function(add_fx_assembly)
|
||||
|
||||
set(assembly_include_paths "")
|
||||
set(assembly_sources ${CMAKE_CURRENT_SOURCE_DIR}/assembly.c)
|
||||
set(assembly_headers)
|
||||
|
||||
foreach (dir ${arg_NAMESPACES})
|
||||
add_subdirectory(${fx_source_root}/${dir} ${fx_build_root}/namespaces/${dir})
|
||||
set(assembly_sources ${assembly_sources} ${namespace_sources})
|
||||
set(assembly_headers ${assembly_headers} ${namespace_headers})
|
||||
set(assembly_include_paths ${assembly_include_paths} ${namespace_include_paths})
|
||||
endforeach (dir)
|
||||
|
||||
@@ -47,23 +45,20 @@ function(add_fx_assembly)
|
||||
target_compile_definitions(${assembly_target_name} PRIVATE ${def})
|
||||
endforeach (def)
|
||||
|
||||
if (fx_enable_tests)
|
||||
foreach (ns ${arg_NAMESPACES})
|
||||
file(GLOB test_sources ${fx_source_root}/${ns}/test/*.c)
|
||||
foreach (test_file ${test_sources})
|
||||
get_filename_component(test_name ${test_file} NAME_WE)
|
||||
set(test_name ${ns}-${test_name})
|
||||
string(REPLACE "." "-" test_name ${test_name})
|
||||
add_executable(${test_name} ${test_file})
|
||||
target_link_libraries(${test_name} ${assembly_target_name})
|
||||
endforeach (test_file)
|
||||
endforeach (ns)
|
||||
endif ()
|
||||
|
||||
set_target_properties(${assembly_target_name} PROPERTIES
|
||||
FOLDER "${assembly_name}")
|
||||
|
||||
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
|
||||
if(IS_BIG_ENDIAN)
|
||||
target_compile_definitions(${assembly_target_name} PRIVATE
|
||||
BIG_ENDIAN)
|
||||
else()
|
||||
target_compile_definitions(${assembly_target_name} PRIVATE
|
||||
LITTLE_ENDIAN)
|
||||
endif()
|
||||
|
||||
install(TARGETS ${assembly_target_name})
|
||||
install(FILES ${headers} DESTINATION include/${assembly_path})
|
||||
endfunction(add_fx_assembly)
|
||||
|
||||
macro(export_fx_namespace_details ns_name)
|
||||
@@ -90,7 +85,6 @@ macro(export_fx_namespace_details ns_name)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/sys/${fx_system_name}/${fx_system_arch}/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/sys/${fx_system_name}/${fx_system_arch}/*.S)
|
||||
file(GLOB headers include/${namespace_path}/*.h)
|
||||
set(namespace_headers ${headers} PARENT_SCOPE)
|
||||
set(namespace_sources
|
||||
${namespace_sources}
|
||||
${base_namespace_sources}
|
||||
@@ -105,6 +99,5 @@ macro(export_fx_namespace_details ns_name)
|
||||
PARENT_SCOPE)
|
||||
set(internal_libs ${internal_libs} PARENT_SCOPE)
|
||||
set(internal_defines ${internal_defines} PARENT_SCOPE)
|
||||
install(FILES ${headers} DESTINATION include/${namespace_path})
|
||||
endmacro(export_fx_namespace_details)
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#include "command.h"
|
||||
|
||||
#include <fx/cmdline/cmd.h>
|
||||
#include <fx/cmd.h>
|
||||
#include <fx/string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "command.h"
|
||||
|
||||
#include <fx/cmdline/cmd.h>
|
||||
#include <fx/cmd.h>
|
||||
#include <fx/misc.h>
|
||||
#include <fx/string.h>
|
||||
#include <fx/term/print.h>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "command.h"
|
||||
|
||||
#include <fx/bst.h>
|
||||
#include <fx/cmdline/cmd.h>
|
||||
#include <fx/cmd.h>
|
||||
#include <fx/string.h>
|
||||
#include <fx/term/print.h>
|
||||
#include <fx/term/tty.h>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define _FX_COMMAND_H_
|
||||
|
||||
#include <fx/bst.h>
|
||||
#include <fx/cmdline/cmd.h>
|
||||
#include <fx/cmd.h>
|
||||
#include <fx/queue.h>
|
||||
#include <fx/string.h>
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#include "command.h"
|
||||
|
||||
#include <fx/cmdline/cmd.h>
|
||||
#include <fx/cmd.h>
|
||||
#include <fx/string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ enum fx_status fx_arglist_report_missing_option(
|
||||
}
|
||||
|
||||
fx_err("required option `" F_YELLOW "%s" F_RESET "` was not specified.",
|
||||
fx_stringstream_get_cstr(opt_name));
|
||||
fx_stringstream_ptr(opt_name));
|
||||
fx_i("usage: %s", fx_string_get_cstr(opt_string));
|
||||
fx_i("for more information, use `" F_YELLOW "--help" F_RESET "`");
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <fx/cmdline/cmd.h>
|
||||
#include <fx/cmd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
enum {
|
||||
@@ -27,24 +27,16 @@ const char *text
|
||||
"great pleasure.";
|
||||
|
||||
static int test_command(
|
||||
const fx_command *self,
|
||||
const fx_arglist *opt,
|
||||
const fx_array *args)
|
||||
const fx_command *self, const fx_arglist *opt, const fx_array *args)
|
||||
{
|
||||
printf("Hello, world!\n");
|
||||
|
||||
fx_arglist_iterator it;
|
||||
fx_arglist_iterator_begin(
|
||||
opt,
|
||||
FX_COMMAND_INVALID_ID,
|
||||
FX_COMMAND_INVALID_ID,
|
||||
&it);
|
||||
opt, FX_COMMAND_INVALID_ID, FX_COMMAND_INVALID_ID, &it);
|
||||
while (fx_arglist_iterator_is_valid(&it)) {
|
||||
printf("opt:%u,arg:%u,i:%zu,value: %s\n",
|
||||
it.opt_id,
|
||||
it.value->val_id,
|
||||
it.i,
|
||||
it.value->val_str);
|
||||
printf("opt:%u,arg:%u,i:%zu,value: %s\n", it.opt_id,
|
||||
it.value->val_id, it.i, it.value->val_str);
|
||||
|
||||
fx_arglist_iterator_next(&it);
|
||||
}
|
||||
|
||||
+124
-102
@@ -2,7 +2,6 @@
|
||||
#include <fx/iterator.h>
|
||||
#include <fx/stream.h>
|
||||
#include <fx/string.h>
|
||||
#include <fx/value.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -13,17 +12,17 @@ struct fx_array_p {
|
||||
size_t ar_len;
|
||||
/* maximum number of items that can currently be stored in array */
|
||||
size_t ar_cap;
|
||||
fx_value *ar_data;
|
||||
fx_object **ar_data;
|
||||
};
|
||||
|
||||
struct fx_array_iterator_p {
|
||||
const fx_array *_a;
|
||||
fx_array *_a;
|
||||
struct fx_array_p *_a_p;
|
||||
|
||||
/** The index of the current value */
|
||||
size_t i;
|
||||
/** The current value */
|
||||
fx_value *value;
|
||||
fx_object *value;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
@@ -33,7 +32,7 @@ static fx_status resize_array(struct fx_array_p *array, size_t new_capacity)
|
||||
if (array->ar_cap < new_capacity) {
|
||||
void *new_data = realloc(
|
||||
array->ar_data,
|
||||
new_capacity * sizeof(fx_value));
|
||||
new_capacity * sizeof(struct fx_dsref *));
|
||||
if (!new_data) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
@@ -41,12 +40,12 @@ static fx_status resize_array(struct fx_array_p *array, size_t new_capacity)
|
||||
array->ar_data = new_data;
|
||||
} else {
|
||||
for (size_t i = new_capacity; i < array->ar_len; i++) {
|
||||
fx_value_unset(&array->ar_data[i]);
|
||||
fx_object_unref(array->ar_data[i]);
|
||||
}
|
||||
|
||||
void *new_data = realloc(
|
||||
array->ar_data,
|
||||
new_capacity * sizeof(fx_value));
|
||||
new_capacity * sizeof(struct fx_dsref *));
|
||||
if (!new_data) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
@@ -64,7 +63,7 @@ static fx_status resize_array(struct fx_array_p *array, size_t new_capacity)
|
||||
|
||||
static fx_status array_insert(
|
||||
struct fx_array_p *array,
|
||||
fx_value value,
|
||||
fx_object *value,
|
||||
size_t at)
|
||||
{
|
||||
if (at == FX_NPOS) {
|
||||
@@ -85,13 +84,13 @@ static fx_status array_insert(
|
||||
}
|
||||
}
|
||||
|
||||
fx_value *src = array->ar_data + at;
|
||||
fx_value *dest = src + 1;
|
||||
size_t move_len = (array->ar_len - at) * sizeof(fx_value);
|
||||
fx_object **src = array->ar_data + at;
|
||||
fx_object **dest = src + 1;
|
||||
size_t move_len = (array->ar_len - at) * sizeof(struct fx_dsref *);
|
||||
|
||||
memmove(dest, src, move_len);
|
||||
|
||||
fx_value_copy(&array->ar_data[at], &value);
|
||||
array->ar_data[at] = fx_object_ref(value);
|
||||
array->ar_len++;
|
||||
|
||||
return FX_SUCCESS;
|
||||
@@ -103,11 +102,11 @@ static fx_status array_remove(struct fx_array_p *array, size_t at)
|
||||
return FX_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
fx_value *src = array->ar_data + at;
|
||||
fx_value *dest = src + 1;
|
||||
size_t move_len = array->ar_len * sizeof(fx_value);
|
||||
fx_object **src = array->ar_data + at;
|
||||
fx_object **dest = src + 1;
|
||||
size_t move_len = array->ar_len * sizeof(struct fx_dsref *);
|
||||
|
||||
fx_value_unset(&array->ar_data[at]);
|
||||
fx_object_unref(array->ar_data[at]);
|
||||
|
||||
memmove(dest, src, move_len);
|
||||
|
||||
@@ -126,17 +125,17 @@ static fx_status array_remove_back(struct fx_array_p *array)
|
||||
return array_remove(array, array->ar_len - 1);
|
||||
}
|
||||
|
||||
static fx_value array_pop(struct fx_array_p *array, size_t at)
|
||||
static fx_object *array_pop(struct fx_array_p *array, size_t at)
|
||||
{
|
||||
if (at >= array->ar_len) {
|
||||
return FX_VALUE_EMPTY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fx_value *dest = array->ar_data + at;
|
||||
fx_value *src = dest + 1;
|
||||
size_t move_len = array->ar_len * sizeof(fx_value);
|
||||
fx_object **src = array->ar_data + at;
|
||||
fx_object **dest = src + 1;
|
||||
size_t move_len = array->ar_len * sizeof(struct fx_dsref *);
|
||||
|
||||
fx_value out = array->ar_data[at];
|
||||
fx_object *out = array->ar_data[at];
|
||||
|
||||
memmove(dest, src, move_len);
|
||||
|
||||
@@ -145,40 +144,40 @@ static fx_value array_pop(struct fx_array_p *array, size_t at)
|
||||
return out;
|
||||
}
|
||||
|
||||
static fx_value array_pop_front(struct fx_array_p *array)
|
||||
static fx_object *array_pop_front(struct fx_array_p *array)
|
||||
{
|
||||
return array_pop(array, 0);
|
||||
}
|
||||
|
||||
static fx_value array_pop_back(struct fx_array_p *array)
|
||||
static fx_object *array_pop_back(struct fx_array_p *array)
|
||||
{
|
||||
return array_pop(array, array->ar_len - 1);
|
||||
}
|
||||
|
||||
static fx_value *array_get_ref(const struct fx_array_p *array, size_t at)
|
||||
static fx_object *array_at(const struct fx_array_p *array, size_t at)
|
||||
{
|
||||
if (at >= array->ar_len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &array->ar_data[at];
|
||||
return array->ar_data[at];
|
||||
}
|
||||
|
||||
static fx_value array_get(struct fx_array_p *array, size_t at)
|
||||
static fx_object *array_get(struct fx_array_p *array, size_t at)
|
||||
{
|
||||
if (at >= array->ar_len) {
|
||||
return FX_VALUE_EMPTY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fx_value_copy_return(array->ar_data[at]);
|
||||
return fx_object_ref(array->ar_data[at]);
|
||||
}
|
||||
|
||||
static size_t array_get_size(const struct fx_array_p *array)
|
||||
static size_t array_size(const struct fx_array_p *array)
|
||||
{
|
||||
return array->ar_len;
|
||||
}
|
||||
|
||||
static size_t array_get_capacity(const struct fx_array_p *array)
|
||||
static size_t array_capacity(const struct fx_array_p *array)
|
||||
{
|
||||
return array->ar_cap;
|
||||
}
|
||||
@@ -190,16 +189,18 @@ static void array_clear(struct fx_array_p *array)
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < array->ar_len; i++) {
|
||||
fx_value_unset(&array->ar_data[i]);
|
||||
fx_object_unref(array->ar_data[i]);
|
||||
}
|
||||
|
||||
memset(array->ar_data, 0x0, array->ar_cap * sizeof(fx_value));
|
||||
memset(array->ar_data, 0x0, array->ar_cap * sizeof(fx_object *));
|
||||
array->ar_len = 0;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_array *fx_array_create_with_values(const fx_value *values, size_t nr_values)
|
||||
fx_array *fx_array_create_with_values(
|
||||
fx_object *const *values,
|
||||
size_t nr_values)
|
||||
{
|
||||
fx_array *array = fx_array_create();
|
||||
if (!array) {
|
||||
@@ -210,14 +211,14 @@ fx_array *fx_array_create_with_values(const fx_value *values, size_t nr_values)
|
||||
|
||||
size_t real_nr_values = 0;
|
||||
for (size_t i = 0; i < nr_values; i++) {
|
||||
if (fx_value_is_set(&values[i])) {
|
||||
if (values[i]) {
|
||||
real_nr_values++;
|
||||
}
|
||||
}
|
||||
|
||||
p->ar_len = real_nr_values;
|
||||
p->ar_cap = real_nr_values;
|
||||
p->ar_data = calloc(real_nr_values, sizeof(fx_value));
|
||||
p->ar_data = calloc(real_nr_values, sizeof(struct fx_dsref *));
|
||||
if (!p->ar_data) {
|
||||
fx_array_unref(array);
|
||||
return NULL;
|
||||
@@ -225,13 +226,13 @@ fx_array *fx_array_create_with_values(const fx_value *values, size_t nr_values)
|
||||
|
||||
size_t index = 0;
|
||||
for (size_t i = 0; i < nr_values; i++) {
|
||||
fx_value_copy(&p->ar_data[index++], &values[i]);
|
||||
p->ar_data[index++] = fx_object_ref(values[i]);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
fx_status fx_array_insert(fx_array *array, fx_value value, size_t at)
|
||||
fx_status fx_array_insert(fx_array *array, fx_object *value, size_t at)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_insert, array, value, at);
|
||||
}
|
||||
@@ -251,39 +252,39 @@ fx_status fx_array_remove_back(fx_array *array)
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_remove_back, array);
|
||||
}
|
||||
|
||||
fx_value fx_array_pop(fx_array *array, size_t at)
|
||||
fx_object *fx_array_pop(fx_array *array, size_t at)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_pop, array, at);
|
||||
}
|
||||
|
||||
fx_value fx_array_pop_front(fx_array *array)
|
||||
fx_object *fx_array_pop_front(fx_array *array)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_pop_front, array);
|
||||
}
|
||||
|
||||
fx_value fx_array_pop_back(fx_array *array)
|
||||
fx_object *fx_array_pop_back(fx_array *array)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_pop_back, array);
|
||||
}
|
||||
|
||||
fx_value *fx_array_get_ref(const fx_array *array, size_t at)
|
||||
fx_object *fx_array_at(const fx_array *array, size_t at)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_get_ref, array, at);
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_at, array, at);
|
||||
}
|
||||
|
||||
fx_value fx_array_get(const fx_array *array, size_t at)
|
||||
fx_object *fx_array_get(fx_array *array, size_t at)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_get, array, at);
|
||||
}
|
||||
|
||||
size_t fx_array_get_size(const fx_array *array)
|
||||
size_t fx_array_size(const fx_array *array)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_get_size, array);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_size, array);
|
||||
}
|
||||
|
||||
size_t fx_array_get_capacity(const fx_array *array)
|
||||
size_t fx_array_capacity(const fx_array *array)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_get_capacity, array);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_capacity, array);
|
||||
}
|
||||
|
||||
void fx_array_clear(fx_array *array)
|
||||
@@ -293,12 +294,12 @@ void fx_array_clear(fx_array *array)
|
||||
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
|
||||
fx_status fx_array_push_back(fx_array *array, fx_value value)
|
||||
fx_status fx_array_append(fx_array *array, fx_object *value)
|
||||
{
|
||||
return fx_array_insert(array, value, FX_NPOS);
|
||||
}
|
||||
|
||||
fx_status fx_array_push_front(fx_array *array, fx_value value)
|
||||
fx_status fx_array_prepend(fx_array *array, fx_object *value)
|
||||
{
|
||||
return fx_array_insert(array, value, 0);
|
||||
}
|
||||
@@ -316,7 +317,7 @@ static void array_fini(fx_object *obj, void *priv)
|
||||
|
||||
if (array->ar_data) {
|
||||
for (size_t i = 0; i < array->ar_len; i++) {
|
||||
fx_value_unset(&array->ar_data[i]);
|
||||
fx_object_unref(array->ar_data[i]);
|
||||
}
|
||||
|
||||
free(array->ar_data);
|
||||
@@ -324,34 +325,29 @@ static void array_fini(fx_object *obj, void *priv)
|
||||
}
|
||||
}
|
||||
|
||||
static fx_status array_to_string(
|
||||
const fx_value *obj,
|
||||
fx_stream *out,
|
||||
const char *format)
|
||||
static void array_to_string(const fx_object *obj, fx_stream *out)
|
||||
{
|
||||
struct fx_array_p *array = fx_object_get_private(
|
||||
obj->v_object,
|
||||
FX_TYPE_ARRAY);
|
||||
struct fx_array_p *array = fx_object_get_private(obj, FX_TYPE_ARRAY);
|
||||
|
||||
if (!array->ar_len) {
|
||||
fx_stream_write_cstr(out, "[]", NULL);
|
||||
return FX_SUCCESS;
|
||||
return;
|
||||
}
|
||||
|
||||
fx_stream_write_cstr(out, "[\n", NULL);
|
||||
|
||||
fx_stream_push_indent(out, 1);
|
||||
size_t len = array_get_size(array);
|
||||
size_t len = array_size(array);
|
||||
|
||||
for (size_t i = 0; i < array->ar_len; i++) {
|
||||
fx_value *value = &array->ar_data[i];
|
||||
bool is_string = fx_value_is_type(value, FX_TYPE_STRING);
|
||||
fx_object *value = array->ar_data[i];
|
||||
bool is_string = fx_object_is_type(value, FX_TYPE_STRING);
|
||||
|
||||
if (is_string) {
|
||||
fx_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
fx_value_to_string(value, out, NULL);
|
||||
fx_object_to_string(value, out);
|
||||
|
||||
if (is_string) {
|
||||
fx_stream_write_char(out, '"');
|
||||
@@ -366,23 +362,40 @@ static fx_status array_to_string(
|
||||
|
||||
fx_stream_pop_indent(out);
|
||||
fx_stream_write_char(out, ']');
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static const fx_iterator *iterable_begin(const fx_object *obj)
|
||||
static fx_iterator *iterable_begin(fx_object *obj)
|
||||
{
|
||||
fx_array_iterator *it_obj = fx_object_create(FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_iterator_p *it = fx_object_get_private(
|
||||
it_obj,
|
||||
FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_ARRAY_ITERATOR);
|
||||
it->_a = obj;
|
||||
it->_a_p = fx_object_get_private(obj, FX_TYPE_ARRAY);
|
||||
it->i = 0;
|
||||
|
||||
if (it->_a_p->ar_len > 0) {
|
||||
it->value = &it->_a_p->ar_data[0];
|
||||
it->value = it->_a_p->ar_data[0];
|
||||
} else {
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
it->value = NULL;
|
||||
}
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static const fx_iterator *iterable_cbegin(const fx_object *obj)
|
||||
{
|
||||
fx_array_iterator *it_obj = fx_object_create(FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_ARRAY_ITERATOR);
|
||||
it->_a = (fx_array *)obj;
|
||||
it->_a_p = fx_object_get_private(obj, FX_TYPE_ARRAY);
|
||||
it->i = 0;
|
||||
|
||||
if (it->_a_p->ar_len > 0) {
|
||||
it->value = it->_a_p->ar_data[0];
|
||||
} else {
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
it->value = NULL;
|
||||
@@ -393,13 +406,12 @@ static const fx_iterator *iterable_begin(const fx_object *obj)
|
||||
|
||||
static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_array_iterator_p *it = fx_object_get_private(
|
||||
obj,
|
||||
FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_p *array = it->_a_p;
|
||||
|
||||
if (it->value == NULL || it->i >= array->ar_len) {
|
||||
return FX_ERR_NO_DATA;
|
||||
return false;
|
||||
}
|
||||
|
||||
it->i++;
|
||||
@@ -407,7 +419,7 @@ static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
if (it->i >= array->ar_len) {
|
||||
it->value = NULL;
|
||||
} else {
|
||||
it->value = &array->ar_data[it->i];
|
||||
it->value = array->ar_data[it->i];
|
||||
}
|
||||
|
||||
return (it->value != NULL) ? FX_SUCCESS : FX_ERR_NO_DATA;
|
||||
@@ -415,19 +427,22 @@ static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
|
||||
static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
{
|
||||
struct fx_array_iterator_p *it = fx_object_get_private(
|
||||
obj,
|
||||
FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_p *array = it->_a_p;
|
||||
|
||||
if (it->i >= array->ar_len) {
|
||||
return FX_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
if (array->ar_data[it->i] != it->value) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
array_remove(array, it->i);
|
||||
|
||||
if (it->i < array->ar_len) {
|
||||
it->value = &array->ar_data[it->i];
|
||||
it->value = array->ar_data[it->i];
|
||||
} else {
|
||||
it->value = NULL;
|
||||
}
|
||||
@@ -435,46 +450,52 @@ static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static const fx_value *iterator_get_value(const fx_iterator *obj)
|
||||
static fx_iterator_value iterator_get_value(fx_iterator *obj)
|
||||
{
|
||||
struct fx_array_iterator_p *it = fx_object_get_private(
|
||||
obj,
|
||||
FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_p *array = it->_a_p;
|
||||
struct fx_array_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
|
||||
|
||||
if (it->i >= array->ar_len) {
|
||||
return NULL;
|
||||
}
|
||||
return FX_ITERATOR_VALUE_PTR(it->value);
|
||||
}
|
||||
|
||||
return it->value;
|
||||
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_array_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
|
||||
|
||||
return FX_ITERATOR_VALUE_CPTR(it->value);
|
||||
}
|
||||
|
||||
static enum fx_status iterator_is_valid(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_array_iterator_p *it = fx_object_get_private(
|
||||
obj,
|
||||
FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_p *array = it->_a_p;
|
||||
|
||||
if (it->i >= array->ar_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (array->ar_data[it->i] != it->value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (it->value != NULL) ? FX_SUCCESS : FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- fx_array DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_array)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_array)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = array_to_string;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_INTERFACE_ENTRY(it_begin) = iterable_begin;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_END(fx_array)
|
||||
FX_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_array)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_array)
|
||||
FX_TYPE_ID(0xe3c46da1, 0x5f37, 0x4e44, 0xb53b, 0xff5a6200191b);
|
||||
@@ -486,17 +507,18 @@ FX_TYPE_DEFINITION_BEGIN(fx_array)
|
||||
FX_TYPE_DEFINITION_END(fx_array)
|
||||
|
||||
// ---- fx_array_iterator DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_array_iterator)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_array_iterator)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_END(fx_array_iterator)
|
||||
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_array_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_array_iterator)
|
||||
FX_TYPE_ID(0xe5e9e8b8, 0x14cb, 0x4192, 0x8138, 0xf45238a2ae73);
|
||||
|
||||
@@ -23,11 +23,11 @@ static void bitbuffer_fini(fx_object *obj, void *priv)
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_bitbuffer)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_bitbuffer)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_END(fx_bitbuffer)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_bitbuffer)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_bitbuffer)
|
||||
FX_TYPE_ID(0x628e33da, 0x3109, 0x4a5d, 0x98d5, 0xb0e4cb3ccb65);
|
||||
|
||||
+7
-14
@@ -1,7 +1,6 @@
|
||||
#include <fx/bitop.h>
|
||||
#include <fx/collections/bitmap.h>
|
||||
#include <fx/stream.h>
|
||||
#include <fx/value.h>
|
||||
#include <string.h>
|
||||
|
||||
#define BITS_PER_WORD (8 * sizeof(bitmap_word_t))
|
||||
@@ -307,14 +306,10 @@ static void bitmap_fini(fx_object *obj, void *priv)
|
||||
struct fx_bitmap_p *map = priv;
|
||||
}
|
||||
|
||||
static fx_status bitmap_to_string(
|
||||
const fx_value *obj,
|
||||
fx_stream *out,
|
||||
const char *format)
|
||||
static void bitmap_to_string(const fx_object *obj, fx_stream *out)
|
||||
{
|
||||
const struct fx_bitmap_p *map = fx_object_get_private(
|
||||
obj->v_object,
|
||||
FX_TYPE_BITMAP);
|
||||
const struct fx_bitmap_p *map
|
||||
= fx_object_get_private(obj, FX_TYPE_BITMAP);
|
||||
|
||||
unsigned char *bytes = (unsigned char *)map->map_words;
|
||||
size_t nr_bytes = map->map_nr_words * sizeof(bitmap_word_t);
|
||||
@@ -344,17 +339,15 @@ static fx_status bitmap_to_string(
|
||||
|
||||
fx_stream_write_fmt(out, NULL, "%c", (c & mask) ? '1' : '0');
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_bitmap)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_bitmap)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = bitmap_to_string;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_END(fx_bitmap)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_bitmap)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_bitmap)
|
||||
FX_TYPE_ID(0xea115cef, 0x8a63, 0x445f, 0x9474, 0xba9309d5dde8);
|
||||
|
||||
@@ -465,11 +465,11 @@ void buffer_fini(fx_object *obj, void *priv)
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_buffer)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_buffer)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_END(fx_buffer)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_buffer)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_buffer)
|
||||
FX_TYPE_ID(0x323e6858, 0x7a43, 0x4484, 0xa6fb, 0xe3d1e47ae637);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <fx/datetime.h>
|
||||
#include <fx/collections/datetime.h>
|
||||
#include <fx/stream.h>
|
||||
#include <fx/string.h>
|
||||
#include <fx/value.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
@@ -339,7 +338,7 @@ static enum fx_status encode_rfc3339(
|
||||
dt->dt_sec);
|
||||
|
||||
if (dt->dt_msec > 0) {
|
||||
fx_stream_write_fmt(out, NULL, ".%03ld", dt->dt_msec);
|
||||
fx_stream_write_fmt(out, NULL, ".%04ld", dt->dt_msec);
|
||||
}
|
||||
|
||||
if (!dt->dt_localtime) {
|
||||
@@ -567,13 +566,9 @@ static void datetime_fini(fx_object *obj, void *priv)
|
||||
struct fx_datetime_p *dt = priv;
|
||||
}
|
||||
|
||||
static fx_status _datetime_to_string(
|
||||
const fx_value *obj,
|
||||
fx_stream *out,
|
||||
const char *format)
|
||||
static void _datetime_to_string(const fx_object *obj, fx_stream *out)
|
||||
{
|
||||
struct fx_datetime_p *dt
|
||||
= fx_object_get_private(obj->v_object, FX_TYPE_DATETIME);
|
||||
struct fx_datetime_p *dt = fx_object_get_private(obj, FX_TYPE_DATETIME);
|
||||
|
||||
if (dt->dt_has_date) {
|
||||
fx_stream_write_fmt(
|
||||
@@ -612,17 +607,15 @@ static fx_status _datetime_to_string(
|
||||
dt->dt_zone_offset_minute);
|
||||
}
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_datetime)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_datetime)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = _datetime_to_string;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_END(fx_datetime)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_datetime)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_datetime)
|
||||
FX_TYPE_ID(0x06a6030b, 0x1e3c, 0x4be2, 0xbd23, 0xf34f4a8e68be);
|
||||
@@ -0,0 +1,732 @@
|
||||
#include <fx/collections/dict.h>
|
||||
#include <fx/hash.h>
|
||||
#include <fx/status.h>
|
||||
#include <fx/stream.h>
|
||||
#include <fx/string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct fx_dict_bucket_item {
|
||||
fx_queue_entry bi_entry;
|
||||
fx_string *bi_str;
|
||||
fx_object *bi_value;
|
||||
};
|
||||
|
||||
struct fx_dict_bucket {
|
||||
fx_bst_node bk_node;
|
||||
uint64_t bk_hash;
|
||||
fx_queue bk_items;
|
||||
};
|
||||
|
||||
struct fx_dict_p {
|
||||
fx_bst d_buckets;
|
||||
};
|
||||
|
||||
struct fx_dict_iterator_p {
|
||||
size_t i;
|
||||
fx_dict_item item;
|
||||
|
||||
fx_dict *_d;
|
||||
struct fx_dict_p *_d_p;
|
||||
fx_bst_node *_cbn;
|
||||
fx_queue_entry *_cqe;
|
||||
};
|
||||
|
||||
/*** MISC FUNCTIONS ***********************************************************/
|
||||
|
||||
static FX_BST_DEFINE_SIMPLE_GET(
|
||||
struct fx_dict_bucket,
|
||||
uint64_t,
|
||||
bk_node,
|
||||
bk_hash,
|
||||
get_bucket);
|
||||
static FX_BST_DEFINE_SIMPLE_INSERT(
|
||||
struct fx_dict_bucket,
|
||||
bk_node,
|
||||
bk_hash,
|
||||
put_bucket);
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static struct fx_dict_bucket *create_bucket(void)
|
||||
{
|
||||
struct fx_dict_bucket *bucket = malloc(sizeof *bucket);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(bucket, 0x0, sizeof *bucket);
|
||||
return bucket;
|
||||
}
|
||||
|
||||
static struct fx_dict_bucket_item *create_bucket_item(void)
|
||||
{
|
||||
struct fx_dict_bucket_item *item = malloc(sizeof *item);
|
||||
if (!item) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(item, 0x0, sizeof *item);
|
||||
return item;
|
||||
}
|
||||
|
||||
static fx_status dict_put(
|
||||
struct fx_dict_p *dict,
|
||||
const char *key,
|
||||
fx_object *value)
|
||||
{
|
||||
uint64_t hash = fx_hash_cstr(key);
|
||||
struct fx_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
|
||||
if (!bucket) {
|
||||
bucket = create_bucket();
|
||||
if (!bucket) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
bucket->bk_hash = hash;
|
||||
put_bucket(&dict->d_buckets, bucket);
|
||||
}
|
||||
|
||||
struct fx_dict_bucket_item *item = create_bucket_item();
|
||||
if (!item) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
item->bi_str = fx_string_create_from_cstr(key);
|
||||
item->bi_value = fx_object_ref(value);
|
||||
|
||||
fx_queue_push_back(&bucket->bk_items, &item->bi_entry);
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_status dict_put_sk(
|
||||
struct fx_dict_p *dict,
|
||||
const fx_string *key,
|
||||
fx_object *value)
|
||||
{
|
||||
uint64_t hash = fx_string_hash(key);
|
||||
struct fx_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
|
||||
if (!bucket) {
|
||||
bucket = create_bucket();
|
||||
if (!bucket) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
bucket->bk_hash = hash;
|
||||
put_bucket(&dict->d_buckets, bucket);
|
||||
}
|
||||
|
||||
struct fx_dict_bucket_item *item = create_bucket_item();
|
||||
if (!item) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
item->bi_str = fx_string_duplicate(key);
|
||||
item->bi_value = fx_object_ref(value);
|
||||
|
||||
fx_queue_push_back(&bucket->bk_items, &item->bi_entry);
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_object *dict_at(const struct fx_dict_p *dict, const char *key)
|
||||
{
|
||||
uint64_t hash = fx_hash_cstr(key);
|
||||
struct fx_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct fx_dict_bucket_item *item
|
||||
= fx_unbox(struct fx_dict_bucket_item, entry, bi_entry);
|
||||
|
||||
if (!strcmp(fx_string_get_cstr(item->bi_str), key)) {
|
||||
return item->bi_value;
|
||||
}
|
||||
|
||||
entry = fx_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static fx_object *dict_at_sk(const struct fx_dict_p *dict, const fx_string *key)
|
||||
{
|
||||
uint64_t hash = fx_string_hash(key);
|
||||
struct fx_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct fx_dict_bucket_item *item
|
||||
= fx_unbox(struct fx_dict_bucket_item, entry, bi_entry);
|
||||
|
||||
if (fx_string_compare(item->bi_str, key)) {
|
||||
return item->bi_value;
|
||||
}
|
||||
|
||||
entry = fx_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static fx_object *dict_get(struct fx_dict_p *dict, const char *key)
|
||||
{
|
||||
fx_object *value = dict_at(dict, key);
|
||||
if (value) {
|
||||
fx_object_ref(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static fx_object *dict_get_sk(struct fx_dict_p *dict, const fx_string *key)
|
||||
{
|
||||
fx_object *value = dict_at_sk(dict, key);
|
||||
if (value) {
|
||||
fx_object_ref(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool dict_has_key(const struct fx_dict_p *dict, const char *key)
|
||||
{
|
||||
return dict_at(dict, key) != NULL;
|
||||
}
|
||||
|
||||
static bool dict_has_skey(const struct fx_dict_p *dict, const fx_string *key)
|
||||
{
|
||||
return dict_at_sk(dict, key) != NULL;
|
||||
}
|
||||
|
||||
static size_t dict_get_size(const struct fx_dict_p *dict)
|
||||
{
|
||||
size_t count = 0;
|
||||
#if 0
|
||||
fx_bst_iterator it1;
|
||||
fx_queue_iterator it2;
|
||||
|
||||
fx_bst_foreach (&it1, &dict->d_buckets) {
|
||||
struct fx_dict_bucket *bucket
|
||||
= fx_unbox(struct fx_dict_bucket, it1.node, bk_node);
|
||||
|
||||
fx_queue_foreach (&it2, &bucket->bk_items) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool dict_is_empty(const struct fx_dict_p *dict)
|
||||
{
|
||||
fx_bst_node *first_node = fx_bst_first(&dict->d_buckets);
|
||||
struct fx_dict_bucket *first_bucket
|
||||
= fx_unbox(struct fx_dict_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
return true;
|
||||
}
|
||||
|
||||
fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items);
|
||||
struct fx_dict_bucket_item *first_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool get_next_node(
|
||||
struct fx_bst_node *cur_node,
|
||||
struct fx_queue_entry *cur_entry,
|
||||
struct fx_bst_node **out_next_node,
|
||||
struct fx_queue_entry **out_next_entry)
|
||||
{
|
||||
struct fx_dict_bucket *cur_bucket
|
||||
= fx_unbox(struct fx_dict_bucket, cur_node, bk_node);
|
||||
if (!cur_bucket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct fx_dict_bucket_item *cur_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, cur_entry, bi_entry);
|
||||
if (!cur_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct fx_bst_node *next_node = cur_node;
|
||||
struct fx_queue_entry *next_entry = fx_queue_next(cur_entry);
|
||||
if (!next_entry) {
|
||||
next_node = fx_bst_next(cur_node);
|
||||
if (!next_node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct fx_dict_bucket *next_bucket
|
||||
= fx_unbox(struct fx_dict_bucket, next_node, bk_node);
|
||||
if (!next_bucket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
next_entry = fx_queue_first(&next_bucket->bk_items);
|
||||
if (!next_entry) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct fx_dict_bucket_item *next_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, next_entry, bi_entry);
|
||||
if (!next_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_next_node = next_node;
|
||||
*out_next_entry = next_entry;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static fx_status delete_item(
|
||||
struct fx_dict_p *dict,
|
||||
struct fx_dict_bucket *bucket,
|
||||
struct fx_dict_bucket_item *item)
|
||||
{
|
||||
fx_queue_delete(&bucket->bk_items, &item->bi_entry);
|
||||
free(item);
|
||||
|
||||
if (fx_queue_empty(&bucket->bk_items)) {
|
||||
fx_bst_delete(&dict->d_buckets, &bucket->bk_node);
|
||||
free(bucket);
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
#if 0
|
||||
fx_dict *fx_dict_create_with_items(const fx_dict_item *items)
|
||||
{
|
||||
fx_dict *dict = fx_dict_create();
|
||||
if (!dict) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_dict_p *p = fx_object_get_private(dict, FX_TYPE_DICT);
|
||||
|
||||
for (size_t i = 0; items[i].key; i++) {
|
||||
dict_put(p, items[i].key, items[i].value);
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
#endif
|
||||
|
||||
fx_status fx_dict_put(fx_dict *dict, const char *key, fx_object *value)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_put, dict, key, value);
|
||||
}
|
||||
|
||||
fx_status fx_dict_put_sk(fx_dict *dict, const fx_string *key, fx_object *value)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_put_sk, dict, key, value);
|
||||
}
|
||||
|
||||
fx_object *fx_dict_at(const fx_dict *dict, const char *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_at, dict, key);
|
||||
}
|
||||
|
||||
fx_object *fx_dict_at_sk(const fx_dict *dict, const fx_string *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_at_sk, dict, key);
|
||||
}
|
||||
|
||||
fx_object *fx_dict_get(fx_dict *dict, const char *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_get, dict, key);
|
||||
}
|
||||
|
||||
fx_object *fx_dict_get_sk(fx_dict *dict, const fx_string *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_get_sk, dict, key);
|
||||
}
|
||||
|
||||
bool fx_dict_has_key(const fx_dict *dict, const char *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_has_key, dict, key);
|
||||
}
|
||||
|
||||
bool fx_dict_has_skey(const fx_dict *dict, const fx_string *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_has_skey, dict, key);
|
||||
}
|
||||
|
||||
size_t fx_dict_get_size(const fx_dict *dict)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DICT, dict_get_size, dict);
|
||||
}
|
||||
|
||||
bool fx_dict_is_empty(const fx_dict *dict)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DICT, dict_is_empty, dict);
|
||||
}
|
||||
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void dict_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_dict_p *dict = priv;
|
||||
}
|
||||
|
||||
static void dict_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_dict_p *dict = priv;
|
||||
|
||||
struct fx_bst_node *node = fx_bst_first(&dict->d_buckets);
|
||||
while (node) {
|
||||
struct fx_dict_bucket *bucket
|
||||
= fx_unbox(struct fx_dict_bucket, node, bk_node);
|
||||
struct fx_bst_node *next_node = fx_bst_next(node);
|
||||
fx_bst_delete(&dict->d_buckets, node);
|
||||
|
||||
struct fx_queue_entry *entry
|
||||
= fx_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct fx_dict_bucket_item *item = fx_unbox(
|
||||
struct fx_dict_bucket_item,
|
||||
entry,
|
||||
bi_entry);
|
||||
struct fx_queue_entry *next_entry
|
||||
= fx_queue_next(entry);
|
||||
fx_queue_delete(&bucket->bk_items, entry);
|
||||
|
||||
free(item->bi_str);
|
||||
fx_object_unref(item->bi_value);
|
||||
free(item);
|
||||
|
||||
entry = next_entry;
|
||||
}
|
||||
|
||||
free(bucket);
|
||||
node = next_node;
|
||||
}
|
||||
}
|
||||
|
||||
static void dict_to_string(const fx_object *obj, fx_stream *out)
|
||||
{
|
||||
struct fx_dict_p *dict = fx_object_get_private(obj, FX_TYPE_DICT);
|
||||
|
||||
if (dict_is_empty(dict)) {
|
||||
fx_stream_write_cstr(out, "{}", NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
fx_stream_write_cstr(out, "{\n", NULL);
|
||||
|
||||
fx_stream_push_indent(out, 1);
|
||||
size_t len = dict_get_size(dict);
|
||||
size_t i = 0;
|
||||
|
||||
struct fx_bst_node *node = fx_bst_first(&dict->d_buckets);
|
||||
while (node) {
|
||||
struct fx_dict_bucket *bucket
|
||||
= fx_unbox(struct fx_dict_bucket, node, bk_node);
|
||||
|
||||
struct fx_queue_entry *entry
|
||||
= fx_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct fx_dict_bucket_item *item = fx_unbox(
|
||||
struct fx_dict_bucket_item,
|
||||
entry,
|
||||
bi_entry);
|
||||
|
||||
fx_object_to_string(item->bi_str, out);
|
||||
fx_stream_write_cstr(out, ": ", NULL);
|
||||
|
||||
bool is_string = fx_object_is_type(
|
||||
item->bi_value,
|
||||
FX_TYPE_STRING);
|
||||
|
||||
if (is_string) {
|
||||
fx_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
fx_object_to_string(item->bi_value, out);
|
||||
|
||||
if (is_string) {
|
||||
fx_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
if (i < len - 1) {
|
||||
fx_stream_write_cstr(out, ",", NULL);
|
||||
}
|
||||
|
||||
fx_stream_write_char(out, '\n');
|
||||
entry = fx_queue_next(entry);
|
||||
i++;
|
||||
}
|
||||
node = fx_bst_next(node);
|
||||
}
|
||||
|
||||
fx_stream_pop_indent(out);
|
||||
fx_stream_write_char(out, '}');
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static fx_iterator *iterable_begin(fx_dict *dict)
|
||||
{
|
||||
fx_iterator *it_obj = fx_object_create(FX_TYPE_DICT_ITERATOR);
|
||||
if (!it_obj) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_dict_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_DICT_ITERATOR);
|
||||
|
||||
it->i = 0;
|
||||
it->_d = dict;
|
||||
it->_d_p = fx_object_get_private(dict, FX_TYPE_DICT);
|
||||
|
||||
if (dict_is_empty(it->_d_p)) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
fx_bst_node *first_node = fx_bst_first(&it->_d_p->d_buckets);
|
||||
struct fx_dict_bucket *first_bucket
|
||||
= fx_unbox(struct fx_dict_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items);
|
||||
struct fx_dict_bucket_item *first_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
it->item.key = first_item->bi_str;
|
||||
it->item.value = first_item->bi_value;
|
||||
|
||||
it->_d = dict;
|
||||
it->_cbn = first_node;
|
||||
it->_cqe = first_entry;
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static const fx_iterator *iterable_cbegin(const fx_dict *dict)
|
||||
{
|
||||
fx_iterator *it_obj = fx_object_create(FX_TYPE_DICT_ITERATOR);
|
||||
if (!it_obj) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_dict_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_DICT_ITERATOR);
|
||||
|
||||
it->i = 0;
|
||||
it->_d = (fx_dict *)dict;
|
||||
it->_d_p = fx_object_get_private(dict, FX_TYPE_DICT);
|
||||
|
||||
if (dict_is_empty(it->_d_p)) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
fx_bst_node *first_node = fx_bst_first(&it->_d_p->d_buckets);
|
||||
struct fx_dict_bucket *first_bucket
|
||||
= fx_unbox(struct fx_dict_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items);
|
||||
struct fx_dict_bucket_item *first_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
it->item.key = first_item->bi_str;
|
||||
it->item.value = first_item->bi_value;
|
||||
|
||||
it->_cbn = first_node;
|
||||
it->_cqe = first_entry;
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_dict_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DICT_ITERATOR);
|
||||
|
||||
struct fx_bst_node *next_node;
|
||||
struct fx_queue_entry *next_entry;
|
||||
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct fx_dict_bucket_item *next_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, next_entry, bi_entry);
|
||||
|
||||
if (!next_item) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
it->i++;
|
||||
it->item.key = next_item->bi_str;
|
||||
it->item.value = next_item->bi_value;
|
||||
|
||||
it->_cbn = next_node;
|
||||
it->_cqe = next_entry;
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
{
|
||||
struct fx_dict_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DICT_ITERATOR);
|
||||
|
||||
if ((it->item.key || it->item.value) && !(it->_cbn && it->_cqe)) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
if (!it->item.key || !it->_cqe) {
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct fx_bst_node *next_node;
|
||||
struct fx_queue_entry *next_entry;
|
||||
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct fx_dict_bucket *cur_bucket
|
||||
= fx_unbox(struct fx_dict_bucket, it->_cbn, bk_node);
|
||||
struct fx_dict_bucket_item *cur_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, it->_cqe, bi_entry);
|
||||
|
||||
struct fx_dict_bucket_item *next_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, next_entry, bi_entry);
|
||||
|
||||
fx_status status = delete_item(it->_d_p, cur_bucket, cur_item);
|
||||
if (FX_ERR(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (next_item) {
|
||||
it->item.key = next_item->bi_str;
|
||||
it->item.value = next_item->bi_value;
|
||||
|
||||
it->_cbn = next_node;
|
||||
it->_cqe = next_entry;
|
||||
} else {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
|
||||
it->_cbn = NULL;
|
||||
it->_cqe = NULL;
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_iterator_value iterator_get_value(fx_iterator *obj)
|
||||
{
|
||||
struct fx_dict_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DICT_ITERATOR);
|
||||
|
||||
return FX_ITERATOR_VALUE_PTR(&it->item);
|
||||
}
|
||||
|
||||
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_dict_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DICT_ITERATOR);
|
||||
|
||||
return FX_ITERATOR_VALUE_CPTR(&it->item);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- fx_dict DEFINITION
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_dict)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = dict_to_string;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_INTERFACE_ENTRY(it_begin) = iterable_begin;
|
||||
FX_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_dict)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_dict)
|
||||
FX_TYPE_ID(0xd2af61d9, 0xd0be, 0x4960, 0xbe3f, 0x509749814c10);
|
||||
FX_TYPE_CLASS(fx_dict_class);
|
||||
FX_TYPE_IMPLEMENTS(FX_TYPE_ITERABLE);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_dict_p);
|
||||
FX_TYPE_INSTANCE_INIT(dict_init);
|
||||
FX_TYPE_INSTANCE_FINI(dict_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_dict)
|
||||
|
||||
// ---- fx_dict_iterator DEFINITION
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_dict_iterator)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_dict_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_dict_iterator)
|
||||
FX_TYPE_ID(0x9ea96701, 0x1713, 0x4a3e, 0xbf63, 0xdc856b456f3b);
|
||||
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
|
||||
FX_TYPE_CLASS(fx_dict_iterator_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_dict_iterator_p);
|
||||
FX_TYPE_DEFINITION_END(fx_dict_iterator)
|
||||
+67
-88
@@ -32,9 +32,8 @@ struct fx_hashmap_p {
|
||||
struct fx_hashmap_iterator_p {
|
||||
size_t i;
|
||||
fx_hashmap_item item;
|
||||
fx_value item_value;
|
||||
|
||||
const fx_hashmap *_h;
|
||||
fx_hashmap *_h;
|
||||
struct fx_hashmap_p *_h_p;
|
||||
fx_bst_node *_cbn;
|
||||
fx_queue_entry *_cqe;
|
||||
@@ -113,18 +112,14 @@ static bool get_next_node(
|
||||
struct fx_bst_node **out_next_node,
|
||||
struct fx_queue_entry **out_next_entry)
|
||||
{
|
||||
struct fx_hashmap_bucket *cur_bucket = fx_unbox(
|
||||
struct fx_hashmap_bucket,
|
||||
cur_node,
|
||||
bk_node);
|
||||
struct fx_hashmap_bucket *cur_bucket
|
||||
= fx_unbox(struct fx_hashmap_bucket, cur_node, bk_node);
|
||||
if (!cur_bucket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct fx_hashmap_bucket_item *cur_item = fx_unbox(
|
||||
struct fx_hashmap_bucket_item,
|
||||
cur_entry,
|
||||
bi_entry);
|
||||
struct fx_hashmap_bucket_item *cur_item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, cur_entry, bi_entry);
|
||||
if (!cur_item) {
|
||||
return false;
|
||||
}
|
||||
@@ -151,10 +146,8 @@ static bool get_next_node(
|
||||
}
|
||||
}
|
||||
|
||||
struct fx_hashmap_bucket_item *next_item = fx_unbox(
|
||||
struct fx_hashmap_bucket_item,
|
||||
next_entry,
|
||||
bi_entry);
|
||||
struct fx_hashmap_bucket_item *next_item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, next_entry, bi_entry);
|
||||
if (!next_item) {
|
||||
return false;
|
||||
}
|
||||
@@ -193,9 +186,8 @@ static fx_status hashmap_put(
|
||||
const fx_hashmap_value *value)
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
struct fx_hashmap_bucket *bucket = get_bucket(
|
||||
&hashmap->h_buckets,
|
||||
hash);
|
||||
struct fx_hashmap_bucket *bucket
|
||||
= get_bucket(&hashmap->h_buckets, hash);
|
||||
|
||||
if (!bucket) {
|
||||
bucket = create_bucket();
|
||||
@@ -242,9 +234,8 @@ static const struct fx_hashmap_value *hashmap_get(
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
|
||||
struct fx_hashmap_bucket *bucket = get_bucket(
|
||||
&hashmap->h_buckets,
|
||||
hash);
|
||||
struct fx_hashmap_bucket *bucket
|
||||
= get_bucket(&hashmap->h_buckets, hash);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -271,9 +262,8 @@ static bool hashmap_has_key(
|
||||
const fx_hashmap_key *key)
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
struct fx_hashmap_bucket *bucket = get_bucket(
|
||||
&hashmap->h_buckets,
|
||||
hash);
|
||||
struct fx_hashmap_bucket *bucket
|
||||
= get_bucket(&hashmap->h_buckets, hash);
|
||||
if (!bucket) {
|
||||
return false;
|
||||
}
|
||||
@@ -303,10 +293,8 @@ static size_t hashmap_get_size(const struct fx_hashmap_p *hashmap)
|
||||
static bool hashmap_is_empty(const struct fx_hashmap_p *hashmap)
|
||||
{
|
||||
fx_bst_node *first_node = fx_bst_first(&hashmap->h_buckets);
|
||||
struct fx_hashmap_bucket *first_bucket = fx_unbox(
|
||||
struct fx_hashmap_bucket,
|
||||
first_node,
|
||||
bk_node);
|
||||
struct fx_hashmap_bucket *first_bucket
|
||||
= fx_unbox(struct fx_hashmap_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
return true;
|
||||
}
|
||||
@@ -370,9 +358,8 @@ fx_hashmap *fx_hashmap_create_with_items(const fx_hashmap_item *items)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_hashmap_p *p = fx_object_get_private(
|
||||
hashmap,
|
||||
FX_TYPE_HASHMAP);
|
||||
struct fx_hashmap_p *p
|
||||
= fx_object_get_private(hashmap, FX_TYPE_HASHMAP);
|
||||
|
||||
for (size_t i = 0; items[i].key.key_data && items[i].key.key_size;
|
||||
i++) {
|
||||
@@ -421,13 +408,12 @@ bool fx_hashmap_is_empty(const fx_hashmap *hashmap)
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_HASHMAP, hashmap_is_empty, hashmap);
|
||||
}
|
||||
|
||||
const fx_iterator *fx_hashmap_begin(const fx_hashmap *hashmap)
|
||||
fx_iterator *fx_hashmap_begin(fx_hashmap *hashmap)
|
||||
{
|
||||
fx_hashmap_iterator *it_obj = fx_object_create(
|
||||
FX_TYPE_HASHMAP_ITERATOR);
|
||||
struct fx_hashmap_iterator_p *it = fx_object_get_private(
|
||||
it_obj,
|
||||
FX_TYPE_HASHMAP_ITERATOR);
|
||||
fx_hashmap_iterator *it_obj
|
||||
= fx_object_create(FX_TYPE_HASHMAP_ITERATOR);
|
||||
struct fx_hashmap_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_HASHMAP_ITERATOR);
|
||||
|
||||
it->_h = hashmap;
|
||||
it->_h_p = fx_object_get_private(hashmap, FX_TYPE_HASHMAP);
|
||||
@@ -440,18 +426,16 @@ const fx_iterator *fx_hashmap_begin(const fx_hashmap *hashmap)
|
||||
}
|
||||
|
||||
struct fx_bst_node *first_node = fx_bst_first(&it->_h_p->h_buckets);
|
||||
struct fx_hashmap_bucket *first_bucket = fx_unbox(
|
||||
struct fx_hashmap_bucket,
|
||||
first_node,
|
||||
bk_node);
|
||||
struct fx_hashmap_bucket *first_bucket
|
||||
= fx_unbox(struct fx_hashmap_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
struct fx_queue_entry *first_entry = fx_queue_first(
|
||||
&first_bucket->bk_items);
|
||||
struct fx_queue_entry *first_entry
|
||||
= fx_queue_first(&first_bucket->bk_items);
|
||||
struct fx_hashmap_bucket_item *first_item = fx_unbox(
|
||||
struct fx_hashmap_bucket_item,
|
||||
first_entry,
|
||||
@@ -489,10 +473,8 @@ static void hashmap_fini(fx_object *obj, void *priv)
|
||||
|
||||
struct fx_bst_node *node = fx_bst_first(&map->h_buckets);
|
||||
while (node) {
|
||||
struct fx_hashmap_bucket *b = fx_unbox(
|
||||
struct fx_hashmap_bucket,
|
||||
node,
|
||||
bk_node);
|
||||
struct fx_hashmap_bucket *b
|
||||
= fx_unbox(struct fx_hashmap_bucket, node, bk_node);
|
||||
struct fx_bst_node *next_node = fx_bst_next(node);
|
||||
fx_bst_delete(&map->h_buckets, node);
|
||||
|
||||
@@ -502,8 +484,8 @@ static void hashmap_fini(fx_object *obj, void *priv)
|
||||
struct fx_hashmap_bucket_item,
|
||||
entry,
|
||||
bi_entry);
|
||||
struct fx_queue_entry *next_entry = fx_queue_next(
|
||||
entry);
|
||||
struct fx_queue_entry *next_entry
|
||||
= fx_queue_next(entry);
|
||||
fx_queue_delete(&b->bk_items, entry);
|
||||
|
||||
if (map->h_key_dtor) {
|
||||
@@ -528,9 +510,8 @@ static void hashmap_fini(fx_object *obj, void *priv)
|
||||
|
||||
static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_hashmap_iterator_p *it = fx_object_get_private(
|
||||
obj,
|
||||
FX_TYPE_HASHMAP_ITERATOR);
|
||||
struct fx_hashmap_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR);
|
||||
|
||||
struct fx_bst_node *next_node;
|
||||
struct fx_queue_entry *next_entry;
|
||||
@@ -539,10 +520,8 @@ static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct fx_hashmap_bucket_item *next_item = fx_unbox(
|
||||
struct fx_hashmap_bucket_item,
|
||||
next_entry,
|
||||
bi_entry);
|
||||
struct fx_hashmap_bucket_item *next_item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, next_entry, bi_entry);
|
||||
|
||||
if (!next_item) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
@@ -561,9 +540,8 @@ static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
|
||||
static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
{
|
||||
struct fx_hashmap_iterator_p *it = fx_object_get_private(
|
||||
obj,
|
||||
FX_TYPE_HASHMAP_ITERATOR);
|
||||
struct fx_hashmap_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR);
|
||||
|
||||
if ((it->item.key.key_data || it->item.value.value_data)
|
||||
&& !(it->_cbn && it->_cqe)) {
|
||||
@@ -581,19 +559,13 @@ static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct fx_hashmap_bucket *cur_bucket = fx_unbox(
|
||||
struct fx_hashmap_bucket,
|
||||
it->_cbn,
|
||||
bk_node);
|
||||
struct fx_hashmap_bucket_item *cur_item = fx_unbox(
|
||||
struct fx_hashmap_bucket_item,
|
||||
it->_cqe,
|
||||
bi_entry);
|
||||
struct fx_hashmap_bucket *cur_bucket
|
||||
= fx_unbox(struct fx_hashmap_bucket, it->_cbn, bk_node);
|
||||
struct fx_hashmap_bucket_item *cur_item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, it->_cqe, bi_entry);
|
||||
|
||||
struct fx_hashmap_bucket_item *next_item = fx_unbox(
|
||||
struct fx_hashmap_bucket_item,
|
||||
next_entry,
|
||||
bi_entry);
|
||||
struct fx_hashmap_bucket_item *next_item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, next_entry, bi_entry);
|
||||
|
||||
fx_status status = delete_item(it->_h_p, cur_bucket, cur_item);
|
||||
if (FX_ERR(status)) {
|
||||
@@ -618,27 +590,33 @@ static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static const fx_value *iterator_get_value(const fx_iterator *obj)
|
||||
static fx_iterator_value iterator_get_value(fx_iterator *obj)
|
||||
{
|
||||
struct fx_hashmap_iterator_p *it = fx_object_get_private(
|
||||
obj,
|
||||
FX_TYPE_HASHMAP_ITERATOR);
|
||||
it->item_value = FX_POINTER(&it->item);
|
||||
return &it->item_value;
|
||||
struct fx_hashmap_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR);
|
||||
return FX_ITERATOR_VALUE_PTR(&it->item);
|
||||
}
|
||||
|
||||
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
|
||||
{
|
||||
const struct fx_hashmap_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR);
|
||||
return FX_ITERATOR_VALUE_CPTR(&it->item);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- fx_hashmap DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_hashmap)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_hashmap)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_INTERFACE_ENTRY(it_begin) = fx_hashmap_begin;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_END(fx_hashmap)
|
||||
FX_INTERFACE_ENTRY(it_cbegin) = fx_hashmap_cbegin;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_hashmap)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_hashmap)
|
||||
FX_TYPE_ID(0x7bf5bcd1, 0x1ff3, 0x4e43, 0xbed8, 0x7c74f28348bf);
|
||||
@@ -650,17 +628,18 @@ FX_TYPE_DEFINITION_BEGIN(fx_hashmap)
|
||||
FX_TYPE_DEFINITION_END(fx_hashmap)
|
||||
|
||||
// ---- fx_hashmap_iterator DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_hashmap_iterator)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_hashmap_iterator)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_END(fx_hashmap_iterator)
|
||||
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_hashmap_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_hashmap_iterator)
|
||||
FX_TYPE_ID(0xd9658456, 0xdd80, 0x419a, 0xb23a, 0xb513013e6431);
|
||||
|
||||
@@ -1,765 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <fx/collections/hashtable.h>
|
||||
#include <fx/misc.h>
|
||||
#include <fx/reflection/property.h>
|
||||
#include <fx/status.h>
|
||||
#include <fx/string.h>
|
||||
#include <fx/vector.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
/* these primes are used as array capacities to avoid hash collisions. */
|
||||
static const size_t primes[] = {
|
||||
11,
|
||||
23,
|
||||
47,
|
||||
97,
|
||||
197,
|
||||
397,
|
||||
797,
|
||||
1597,
|
||||
3203,
|
||||
6421,
|
||||
12853,
|
||||
25717,
|
||||
51437,
|
||||
};
|
||||
|
||||
struct table_item {
|
||||
fx_hashtable_item *i_item;
|
||||
};
|
||||
|
||||
struct fx_hashtable_item_p {
|
||||
fx_hashtable_item *i_self;
|
||||
fx_value i_key, i_value;
|
||||
};
|
||||
|
||||
struct fx_hashtable_p {
|
||||
struct table_item *t_items;
|
||||
/* number of items currently stored in t_items */
|
||||
size_t t_count;
|
||||
/* index in primes[] that represents the current maximum size of
|
||||
* t_items */
|
||||
size_t t_max_index;
|
||||
};
|
||||
|
||||
struct fx_hashtable_iterator_p {
|
||||
size_t i;
|
||||
fx_hashtable_item *item;
|
||||
fx_value item_value;
|
||||
|
||||
const fx_hashtable *_h;
|
||||
struct fx_hashtable_p *_h_p;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static fx_status convert_key_to_index(
|
||||
const fx_value *v,
|
||||
struct table_item *table,
|
||||
size_t table_size,
|
||||
size_t *out_index)
|
||||
{
|
||||
uint64_t hash = 0;
|
||||
fx_status status = fx_value_hash(v, &hash);
|
||||
if (!FX_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
size_t base_index = hash % table_size;
|
||||
size_t index = base_index, i = 0;
|
||||
bool index_found = false;
|
||||
while (i <= table_size) {
|
||||
if (!table[index].i_item) {
|
||||
goto skip;
|
||||
}
|
||||
|
||||
const struct fx_hashtable_item_p *item = fx_object_get_private(
|
||||
table[index].i_item,
|
||||
FX_TYPE_HASHTABLE_ITEM);
|
||||
int cmp = fx_value_compare(&item->i_key, v);
|
||||
if (cmp == 0) {
|
||||
index_found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
skip:
|
||||
index = (base_index + (i * i)) % table_size;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!index_found) {
|
||||
return FX_ERR_NO_ENTRY;
|
||||
}
|
||||
|
||||
assert(index < table_size);
|
||||
*out_index = index;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_status allocate_index_for_key(
|
||||
const fx_value *v,
|
||||
struct table_item *table,
|
||||
size_t table_size,
|
||||
size_t *out_index)
|
||||
{
|
||||
uint64_t hash = 0;
|
||||
fx_status status = fx_value_hash(v, &hash);
|
||||
if (!FX_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
size_t index = hash % table_size;
|
||||
bool ok = false;
|
||||
|
||||
for (size_t i = 0; i < table_size; i++) {
|
||||
if (!table[index].i_item) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const struct fx_hashtable_item_p *item = fx_object_get_private(
|
||||
table[index].i_item,
|
||||
FX_TYPE_HASHTABLE_ITEM);
|
||||
int cmp = fx_value_compare(&item->i_key, v);
|
||||
if (cmp == 0) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
|
||||
index = (index + (i * i)) % table_size;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
return FX_ERR_NO_SPACE;
|
||||
}
|
||||
|
||||
assert(index < table_size);
|
||||
*out_index = index;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_status add_item_to_table(
|
||||
fx_hashtable_item *item,
|
||||
struct table_item *table,
|
||||
size_t table_capacity)
|
||||
{
|
||||
size_t index = 0;
|
||||
struct fx_hashtable_item_p *item_p
|
||||
= fx_object_get_private(item, FX_TYPE_HASHTABLE_ITEM);
|
||||
fx_status status = allocate_index_for_key(
|
||||
&item_p->i_key,
|
||||
table,
|
||||
table_capacity,
|
||||
&index);
|
||||
if (!FX_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (index >= table_capacity) {
|
||||
return FX_ERR_NO_SPACE;
|
||||
}
|
||||
|
||||
struct table_item *bucket = &table[index];
|
||||
if (bucket->i_item) {
|
||||
fx_hashtable_item_unref(bucket->i_item);
|
||||
}
|
||||
|
||||
bucket->i_item = item;
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_status destroy_table(
|
||||
struct table_item *table,
|
||||
size_t length,
|
||||
bool destroy_items)
|
||||
{
|
||||
if (!destroy_items) {
|
||||
free(table);
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
struct table_item *item = &table[i];
|
||||
if (!item->i_item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fx_hashtable_item_unref(item->i_item);
|
||||
}
|
||||
|
||||
free(table);
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_status migrate_table(
|
||||
struct table_item *src_table,
|
||||
size_t src_length,
|
||||
struct table_item *dest_table,
|
||||
size_t dest_capacity)
|
||||
{
|
||||
for (size_t i = 0; i < src_length; i++) {
|
||||
struct table_item *item = &src_table[i];
|
||||
if (!item->i_item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
add_item_to_table(item->i_item, dest_table, dest_capacity);
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_status resize_table(
|
||||
struct fx_hashtable_p *hashtable,
|
||||
size_t new_capacity_index)
|
||||
{
|
||||
size_t capacity = primes[new_capacity_index];
|
||||
struct table_item *new_table = calloc(capacity, sizeof *new_table);
|
||||
if (!new_table) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
fx_status status = migrate_table(
|
||||
hashtable->t_items,
|
||||
primes[hashtable->t_max_index],
|
||||
new_table,
|
||||
capacity);
|
||||
if (!FX_OK(status)) {
|
||||
free(new_table);
|
||||
return status;
|
||||
}
|
||||
|
||||
free(hashtable->t_items);
|
||||
hashtable->t_items = new_table;
|
||||
hashtable->t_max_index = new_capacity_index;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_status hashtable_put(
|
||||
struct fx_hashtable_p *hashtable,
|
||||
fx_value *key,
|
||||
fx_value *value)
|
||||
{
|
||||
fx_status status = FX_SUCCESS;
|
||||
size_t capacity = primes[hashtable->t_max_index];
|
||||
if (hashtable->t_count + 1 > capacity) {
|
||||
status = resize_table(hashtable, hashtable->t_max_index + 1);
|
||||
if (!FX_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
capacity = primes[hashtable->t_max_index];
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
do {
|
||||
status = allocate_index_for_key(
|
||||
key,
|
||||
hashtable->t_items,
|
||||
capacity,
|
||||
&index);
|
||||
if (status == FX_ERR_NO_SPACE) {
|
||||
status = resize_table(
|
||||
hashtable,
|
||||
hashtable->t_max_index + 1);
|
||||
if (!FX_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
capacity = primes[hashtable->t_max_index];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!FX_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
break;
|
||||
} while (1);
|
||||
|
||||
fx_hashtable_item *item = hashtable->t_items[index].i_item;
|
||||
struct fx_hashtable_item_p *item_p = NULL;
|
||||
if (!item) {
|
||||
item = fx_object_create(FX_TYPE_HASHTABLE_ITEM);
|
||||
if (!item) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
item_p = fx_object_get_private(item, FX_TYPE_HASHTABLE_ITEM);
|
||||
|
||||
fx_value_copy(&item_p->i_key, key);
|
||||
|
||||
hashtable->t_items[index].i_item = item;
|
||||
hashtable->t_count++;
|
||||
} else {
|
||||
item_p = fx_object_get_private(item, FX_TYPE_HASHTABLE_ITEM);
|
||||
fx_value_unset(&item_p->i_value);
|
||||
}
|
||||
|
||||
fx_value_copy(&item_p->i_value, value);
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static const fx_value *hashtable_get(
|
||||
const struct fx_hashtable_p *hashtable,
|
||||
const fx_value *key)
|
||||
{
|
||||
size_t index = 0;
|
||||
size_t capacity = primes[hashtable->t_max_index];
|
||||
fx_status status = convert_key_to_index(
|
||||
key,
|
||||
hashtable->t_items,
|
||||
capacity,
|
||||
&index);
|
||||
if (!FX_OK(status)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const fx_hashtable_item *item = hashtable->t_items[index].i_item;
|
||||
if (!item) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct fx_hashtable_item_p *item_p
|
||||
= fx_object_get_private(item, FX_TYPE_HASHTABLE_ITEM);
|
||||
return &item_p->i_value;
|
||||
}
|
||||
|
||||
static size_t hashtable_get_count(const struct fx_hashtable_p *hashtable)
|
||||
{
|
||||
return hashtable->t_count;
|
||||
}
|
||||
|
||||
static bool hashtable_is_empty(const struct fx_hashtable_p *hashtable)
|
||||
{
|
||||
return hashtable->t_count == 0;
|
||||
}
|
||||
|
||||
static const fx_value *hashtable_item_get_key(
|
||||
const struct fx_hashtable_item_p *item)
|
||||
{
|
||||
return &item->i_key;
|
||||
}
|
||||
|
||||
static const fx_value *hashtable_item_get_value(
|
||||
const struct fx_hashtable_item_p *item)
|
||||
{
|
||||
return &item->i_value;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_status fx_hashtable_put(
|
||||
fx_hashtable *hashtable,
|
||||
fx_value *key,
|
||||
fx_value *value)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_HASHTABLE,
|
||||
hashtable_put,
|
||||
hashtable,
|
||||
key,
|
||||
value);
|
||||
}
|
||||
|
||||
const fx_value *fx_hashtable_get(
|
||||
const fx_hashtable *hashtable,
|
||||
const fx_value *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_HASHTABLE,
|
||||
hashtable_get,
|
||||
hashtable,
|
||||
key);
|
||||
}
|
||||
|
||||
size_t fx_hashtable_get_count(const fx_hashtable *hashtable)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_TYPE_HASHTABLE,
|
||||
hashtable_get_count,
|
||||
hashtable);
|
||||
}
|
||||
|
||||
bool fx_hashtable_is_empty(const fx_hashtable *hashtable)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_TYPE_HASHTABLE,
|
||||
hashtable_is_empty,
|
||||
hashtable);
|
||||
}
|
||||
|
||||
const fx_value *fx_hashtable_item_get_key(const fx_hashtable_item *item)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_TYPE_HASHTABLE_ITEM,
|
||||
hashtable_item_get_key,
|
||||
item);
|
||||
}
|
||||
|
||||
const fx_value *fx_hashtable_item_get_value(const fx_hashtable_item *item)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_TYPE_HASHTABLE_ITEM,
|
||||
hashtable_item_get_value,
|
||||
item);
|
||||
}
|
||||
|
||||
const fx_iterator *fx_hashtable_begin(const fx_hashtable *hashtable)
|
||||
{
|
||||
fx_hashtable_iterator *it_obj
|
||||
= fx_object_create(FX_TYPE_HASHTABLE_ITERATOR);
|
||||
struct fx_hashtable_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_HASHTABLE_ITERATOR);
|
||||
|
||||
it->_h = hashtable;
|
||||
it->_h_p = fx_object_get_private(hashtable, FX_TYPE_HASHTABLE);
|
||||
|
||||
it->i = 0;
|
||||
if (fx_hashtable_is_empty(hashtable)) {
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
struct table_item *table = it->_h_p->t_items;
|
||||
size_t capacity = primes[it->_h_p->t_max_index];
|
||||
|
||||
while (it->i < capacity && table[it->i].i_item == NULL) {
|
||||
it->i++;
|
||||
}
|
||||
|
||||
it->item_value = FX_VALUE_OBJECT_REF(table[it->i].i_item);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void hashtable_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_hashtable_p *map = priv;
|
||||
map->t_max_index = 0;
|
||||
map->t_count = 0;
|
||||
|
||||
size_t capacity = primes[map->t_max_index];
|
||||
map->t_items = calloc(capacity, sizeof *map->t_items);
|
||||
}
|
||||
|
||||
static void hashtable_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_hashtable_p *map = priv;
|
||||
|
||||
size_t capacity = primes[map->t_max_index];
|
||||
size_t nr_destroyed = 0;
|
||||
for (size_t i = 0; i < capacity; i++) {
|
||||
if (map->t_items[i].i_item) {
|
||||
nr_destroyed++;
|
||||
fx_hashtable_item_unref(map->t_items[i].i_item);
|
||||
}
|
||||
}
|
||||
|
||||
free(map->t_items);
|
||||
}
|
||||
|
||||
static void hashtable_item_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_hashtable_item_p *item = priv;
|
||||
fx_value_unset(&item->i_key);
|
||||
fx_value_unset(&item->i_value);
|
||||
}
|
||||
|
||||
static void hashtable_iterator_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_hashtable_iterator_p *it = priv;
|
||||
fx_value_unset(&it->item_value);
|
||||
}
|
||||
|
||||
static fx_status to_string(
|
||||
const fx_value *obj,
|
||||
fx_stream *out,
|
||||
const char *format)
|
||||
{
|
||||
struct fx_hashtable_p *hashtable
|
||||
= fx_object_get_private(obj->v_object, FX_TYPE_HASHTABLE);
|
||||
|
||||
if (!hashtable->t_count) {
|
||||
fx_stream_write_cstr(out, "{}", NULL);
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
fx_stream_write_cstr(out, "{\n", NULL);
|
||||
|
||||
fx_stream_push_indent(out, 1);
|
||||
|
||||
size_t nr_written = 0;
|
||||
size_t capacity = primes[hashtable->t_max_index];
|
||||
for (size_t i = 0; i < capacity; i++) {
|
||||
fx_hashtable_item *item = hashtable->t_items[i].i_item;
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nr_written++;
|
||||
struct fx_hashtable_item_p *item_p
|
||||
= fx_object_get_private(item, FX_TYPE_HASHTABLE_ITEM);
|
||||
|
||||
const char *cstr = NULL;
|
||||
fx_value_get_cstr(&item_p->i_key, &cstr);
|
||||
|
||||
if (cstr) {
|
||||
fx_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
fx_value_to_string(&item_p->i_key, out, NULL);
|
||||
|
||||
if (cstr) {
|
||||
fx_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
fx_stream_write_cstr(out, " = ", NULL);
|
||||
|
||||
fx_value_get_cstr(&item_p->i_value, &cstr);
|
||||
if (cstr) {
|
||||
fx_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
fx_value_to_string(&item_p->i_value, out, NULL);
|
||||
|
||||
if (cstr) {
|
||||
fx_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
if (nr_written != hashtable->t_count) {
|
||||
fx_stream_write_char(out, ',');
|
||||
}
|
||||
|
||||
fx_stream_write_char(out, '\n');
|
||||
}
|
||||
|
||||
fx_stream_pop_indent(out);
|
||||
fx_stream_write_char(out, '}');
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_status clone(const fx_value *src_v, fx_value *dest_v)
|
||||
{
|
||||
fx_hashtable *src_table = NULL, *dest_table = NULL;
|
||||
fx_value_get_object(src_v, &src_table);
|
||||
|
||||
dest_table = fx_hashtable_create();
|
||||
if (!dest_table) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
struct fx_hashtable_p *src_p
|
||||
= fx_object_get_private(src_table, FX_TYPE_HASHTABLE);
|
||||
struct fx_hashtable_p *dest_p
|
||||
= fx_object_get_private(dest_table, FX_TYPE_HASHTABLE);
|
||||
dest_p->t_count = src_p->t_count;
|
||||
dest_p->t_max_index = src_p->t_max_index;
|
||||
size_t capacity = primes[dest_p->t_max_index];
|
||||
dest_p->t_items = calloc(capacity, sizeof *dest_p->t_items);
|
||||
if (!dest_p->t_items) {
|
||||
fx_hashtable_unref(dest_table);
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < capacity; i++) {
|
||||
if (!src_p->t_items[i].i_item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fx_hashtable *new_item
|
||||
= fx_object_create(FX_TYPE_HASHTABLE_ITEM);
|
||||
if (!new_item) {
|
||||
fx_hashtable_unref(dest_table);
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
struct fx_hashtable_item_p *src_item_p = fx_object_get_private(
|
||||
src_p->t_items[i].i_item,
|
||||
FX_TYPE_HASHTABLE_ITEM);
|
||||
struct fx_hashtable_item_p *new_item_p = fx_object_get_private(
|
||||
new_item,
|
||||
FX_TYPE_HASHTABLE_ITEM);
|
||||
new_item_p->i_key = fx_value_copy_return(src_item_p->i_key);
|
||||
new_item_p->i_value = fx_value_copy_return(src_item_p->i_value);
|
||||
dest_p->t_items[i].i_item = new_item;
|
||||
}
|
||||
|
||||
*dest_v = FX_VALUE_OBJECT(dest_table);
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_status get_key(
|
||||
const fx_value *item_value,
|
||||
const fx_property *prop,
|
||||
fx_value *out)
|
||||
{
|
||||
fx_hashtable_item *item = NULL;
|
||||
fx_value_get_object(item_value, &item);
|
||||
if (!item) {
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
struct fx_hashtable_item_p *item_p
|
||||
= fx_object_get_private(item, FX_TYPE_HASHTABLE_ITEM);
|
||||
fx_value_copy(out, &item_p->i_key);
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_status get_value(
|
||||
const fx_value *item_value,
|
||||
const fx_property *prop,
|
||||
fx_value *out)
|
||||
{
|
||||
fx_hashtable_item *item = NULL;
|
||||
fx_value_get_object(item_value, &item);
|
||||
if (!item) {
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
struct fx_hashtable_item_p *item_p
|
||||
= fx_object_get_private(item, FX_TYPE_HASHTABLE_ITEM);
|
||||
fx_value_copy(out, &item_p->i_value);
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_hashtable_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_HASHTABLE_ITERATOR);
|
||||
|
||||
fx_value_unset(&it->item_value);
|
||||
struct table_item *table = it->_h_p->t_items;
|
||||
size_t capacity = primes[it->_h_p->t_max_index];
|
||||
|
||||
it->i++;
|
||||
while (it->i < capacity && table[it->i].i_item == NULL) {
|
||||
it->i++;
|
||||
}
|
||||
|
||||
if (it->i >= capacity || !table[it->i].i_item) {
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
it->item_value = FX_VALUE_OBJECT_REF(table[it->i].i_item);
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
{
|
||||
struct fx_hashtable_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_HASHTABLE_ITERATOR);
|
||||
|
||||
struct table_item *table = it->_h_p->t_items;
|
||||
size_t capacity = primes[it->_h_p->t_max_index];
|
||||
|
||||
if (table[it->i].i_item) {
|
||||
fx_hashtable_item_unref(table[it->i].i_item);
|
||||
table[it->i].i_item = NULL;
|
||||
}
|
||||
|
||||
it->i++;
|
||||
while (it->i < capacity && table[it->i].i_item == NULL) {
|
||||
it->i++;
|
||||
}
|
||||
|
||||
if (it->i >= capacity || !table[it->i].i_item) {
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static const fx_value *iterator_get_value(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_hashtable_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_HASHTABLE_ITERATOR);
|
||||
struct table_item *table = it->_h_p->t_items;
|
||||
size_t capacity = primes[it->_h_p->t_max_index];
|
||||
|
||||
if (it->i >= capacity) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (table[it->i].i_item) {
|
||||
return &it->item_value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- fx_hashtable DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_hashtable)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = to_string;
|
||||
FX_INTERFACE_ENTRY(clone) = clone;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_INTERFACE_ENTRY(it_begin) = fx_hashtable_begin;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_END(fx_hashtable)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_hashtable)
|
||||
FX_TYPE_ID(0xc73b431c, 0x5bd5, 0x45ac, 0x888b, 0x35d352db1fe4);
|
||||
FX_TYPE_NAME("fx.collections.hashtable");
|
||||
FX_TYPE_CLASS(fx_hashtable_class);
|
||||
FX_TYPE_IMPLEMENTS(FX_TYPE_ITERABLE);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_hashtable_p);
|
||||
FX_TYPE_INSTANCE_INIT(hashtable_init);
|
||||
FX_TYPE_INSTANCE_FINI(hashtable_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_hashtable)
|
||||
|
||||
// ---- fx_hashtable_iterator DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_hashtable_iterator)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_END(fx_hashtable_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_hashtable_iterator)
|
||||
FX_TYPE_ID(0x42c6836d, 0xf801, 0x49f9, 0xba58, 0xf9cd6f1cb22d);
|
||||
FX_TYPE_NAME("fx.collections.hashtable.iterator");
|
||||
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
|
||||
FX_TYPE_CLASS(fx_hashtable_iterator_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_hashtable_iterator_p);
|
||||
FX_TYPE_INSTANCE_FINI(hashtable_iterator_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_hashtable_iterator)
|
||||
|
||||
// ---- fx_hashtable_item DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_hashtable_item)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_PROPERTY("key", get_key, NULL);
|
||||
FX_TYPE_PROPERTY("value", get_value, NULL);
|
||||
FX_TYPE_CLASS_END(fx_hashtable_item)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_hashtable_item)
|
||||
FX_TYPE_ID(0x748f78f3, 0x53df, 0x406c, 0x8777, 0x2075bd11fb97);
|
||||
FX_TYPE_NAME("fx.collections.hashtable.item");
|
||||
FX_TYPE_EXTENDS(FX_TYPE_OBJECT);
|
||||
FX_TYPE_CLASS(fx_hashtable_item_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_hashtable_item_p);
|
||||
FX_TYPE_INSTANCE_FINI(hashtable_item_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_hashtable_item)
|
||||
@@ -1,5 +1,13 @@
|
||||
#ifndef FX_COLLECTIONS_ARRAY_H_
|
||||
#define FX_COLLECTIONS_ARRAY_H_
|
||||
/**
|
||||
* A heterogeneous array of objects. fx_array only stores references
|
||||
* to the objects that it contains, not the object data itself.
|
||||
*
|
||||
* fx_array stores pointers to objects in a single contiguous array,
|
||||
* but this is an implementation detail that may change in the future.
|
||||
* Users of fx_array should not rely on this being the case.
|
||||
*/
|
||||
#ifndef FX_DS_ARRAY_H_
|
||||
#define FX_DS_ARRAY_H_
|
||||
|
||||
#include <fx/iterator.h>
|
||||
#include <fx/macros.h>
|
||||
@@ -22,42 +30,192 @@ FX_TYPE_CLASS_DECLARATION_END(fx_array)
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_array_iterator)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_array_iterator)
|
||||
|
||||
FX_API fx_type_id fx_array_get_type(void);
|
||||
FX_API fx_type_id fx_array_iterator_get_type(void);
|
||||
FX_API fx_type fx_array_get_type(void);
|
||||
FX_API fx_type fx_array_iterator_get_type(void);
|
||||
|
||||
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_array, FX_TYPE_ARRAY);
|
||||
|
||||
/**
|
||||
* Creates an fx_array initialised with the contents of the provided
|
||||
* fx_object pointer array. The fx_array will take a reference to each
|
||||
* object specified in `values`, and will increment the reference count.
|
||||
* The order of objects in the new fx_array will be the same as the order
|
||||
* of objects in `values`. Any NULL pointers in the `values` array will
|
||||
* be ignored, and will not result in gaps in the created fx_array.
|
||||
* However, `nr_values` should be large enough to cover the final
|
||||
* non-NULL pointer in `values`, including any NULL pointers in-between.
|
||||
*
|
||||
* @param values The list of object pointers which should make up the
|
||||
* contents of the new fx_array.
|
||||
* @param nr_values The size of the `values` array.
|
||||
* @return A pointer to the new fx_array, or NULL if an error occurred.
|
||||
*/
|
||||
FX_API fx_array *fx_array_create_with_values(
|
||||
const fx_value *values,
|
||||
fx_object *const *values,
|
||||
size_t nr_values);
|
||||
|
||||
/**
|
||||
* Remove all object references from an fx_array, resetting the size of the
|
||||
* array to zero. The reference counts of all objects in the array will be
|
||||
* decremented.
|
||||
*
|
||||
* @param array The fx_array to clear.
|
||||
*/
|
||||
FX_API void fx_array_clear(fx_array *array);
|
||||
|
||||
FX_API fx_status fx_array_push_back(fx_array *array, fx_value value);
|
||||
/**
|
||||
* Inserts an object at the end of an fx_array. The reference count of
|
||||
* the object will be incremented.
|
||||
*
|
||||
* @param array The fx_array to append the object to.
|
||||
* @param value The object to append.
|
||||
* @return FX_SUCCESS if the object was appended successfully, or an
|
||||
* error code if an error occurred.
|
||||
*/
|
||||
FX_API fx_status fx_array_append(fx_array *array, fx_object *value);
|
||||
|
||||
FX_API fx_status fx_array_push_front(fx_array *array, fx_value value);
|
||||
/**
|
||||
* Inserts an object at the beginning of an fx_array. The reference count
|
||||
* of the object will be incremented. All other objects in the array
|
||||
* will be moved to make space for the object being pre-pended.
|
||||
*
|
||||
* @param array The fx_array to prepend the object to.
|
||||
* @param value The object to prepend.
|
||||
* @return FX_SUCCESS if the object was prepended successfully, or an
|
||||
* error code if an error occurred.
|
||||
*/
|
||||
FX_API fx_status fx_array_prepend(fx_array *array, fx_object *value);
|
||||
|
||||
FX_API fx_status fx_array_insert(fx_array *array, fx_value value, size_t at);
|
||||
/**
|
||||
* Inserts an object into an fx_array at a given index. The reference
|
||||
* count of the object will be incremented. If the specified index is at
|
||||
* the beginning or mid-way through the array (i.e. not at the end),
|
||||
* some or all of the objects already in the array will be moved to make
|
||||
* space for the object being inserted.
|
||||
*
|
||||
* @param array The fx_array to insert the object into.
|
||||
* @param value The object to insert.
|
||||
* @param at The index to insert the object at. If the index is
|
||||
* `FX_NPOS`, the object will be inserted at the end of the fx_array.
|
||||
* @return FX_SUCCESS if the object was inserted, or a status code
|
||||
* describing any error that occurred.
|
||||
*/
|
||||
FX_API fx_status fx_array_insert(fx_array *array, fx_object *value, size_t at);
|
||||
|
||||
/**
|
||||
* Removes the object at the specified index from an fx_array. The
|
||||
* reference count of the removed object will be decremented. If the
|
||||
* specified index is at the beginning or mid-way through the array
|
||||
* (i.e. not at the end), the remaining objects will be moved to fill
|
||||
* the empty space created by the object's removal.
|
||||
*
|
||||
* @param array The fx_array to remove the object from.
|
||||
* @param at The index of the object to be removed.
|
||||
* @return FX_SUCCESS if the object was removed, or a status code
|
||||
* describing any error that occurred.
|
||||
*/
|
||||
FX_API fx_status fx_array_remove(fx_array *array, size_t at);
|
||||
|
||||
/**
|
||||
* Removes the object at the beginning of an fx_array. The reference count
|
||||
* of the removed object will be decremented. The remaining objects will be
|
||||
* moved to fill the empty space created by the object's removal.
|
||||
*
|
||||
* @param array The fx_array to remove the object from.
|
||||
* @return FX_SUCCESS if the object was removed, or a status code describing any
|
||||
* error that occurred.
|
||||
*/
|
||||
FX_API fx_status fx_array_remove_front(fx_array *array);
|
||||
|
||||
/**
|
||||
* Removes the object at the end of an fx_array. The reference count
|
||||
* of the removed object will be decremented.
|
||||
*
|
||||
* @param array The fx_array to remove the object from.
|
||||
* @return FX_SUCCESS if the object was removed, or a status code describing any
|
||||
* error that occurred.
|
||||
*/
|
||||
FX_API fx_status fx_array_remove_back(fx_array *array);
|
||||
|
||||
FX_API fx_value fx_array_pop(fx_array *array, size_t at);
|
||||
/**
|
||||
* Removes the object at the specified index of an fx_array, and returns
|
||||
* a pointer to it. The reference count of the removed object will NOT
|
||||
* be decremented. The caller becomes the owner of the array's reference
|
||||
* to the object. If the specified index is at the beginning or mid-way
|
||||
* through the array (i.e. not at the end), the remaining objects will
|
||||
* be moved to fill the empty space created by the object's removal.
|
||||
*
|
||||
* @param array The fx_array to remove the object from.
|
||||
* @param at The index of the object to be removed.
|
||||
* @return An pointer to the removed object. This pointer is owned by
|
||||
* the caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
FX_API fx_object *fx_array_pop(fx_array *array, size_t at);
|
||||
|
||||
FX_API fx_value fx_array_pop_front(fx_array *array);
|
||||
/**
|
||||
* Removes the object at the beginning of an fx_array, and returns a
|
||||
* pointer to it. The reference count of the removed object will NOT be
|
||||
* decremented. The caller becomes the owner of the array's reference to
|
||||
* the object. The remaining objects in the fx_array will be moved to
|
||||
* fill the empty space left by the removed object.
|
||||
*
|
||||
* @param array The fx_array to remove the object from.
|
||||
* @return An pointer to the removed object. This pointer is owned by
|
||||
* the caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
FX_API fx_object *fx_array_pop_front(fx_array *array);
|
||||
|
||||
FX_API fx_value fx_array_pop_back(fx_array *array);
|
||||
/**
|
||||
* Removes the object at the end of an fx_array, and returns a pointer to it.
|
||||
* The reference count of the removed object will NOT be decremented. The caller
|
||||
* becomes the owner of the array's reference to the object.
|
||||
*
|
||||
* @param array The fx_array to remove the object from.
|
||||
* @return An pointer to the removed object. This pointer is owned by the
|
||||
* caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
FX_API fx_object *fx_array_pop_back(fx_array *array);
|
||||
|
||||
FX_API fx_value *fx_array_get_ref(const fx_array *array, size_t at);
|
||||
/**
|
||||
* Returns an unowned pointer to the object at the given index of an fx_array.
|
||||
* The caller does not own the returned pointer, and MUST NOT release it.
|
||||
*
|
||||
* @param array The fx_array.
|
||||
* @param at The index of the object to return.
|
||||
* @return A pointer to the object at the given index. This pointer is NOT owned
|
||||
* by the caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
FX_API fx_object *fx_array_at(const fx_array *array, size_t at);
|
||||
|
||||
FX_API fx_value fx_array_get(const fx_array *array, size_t at);
|
||||
/**
|
||||
* Returns an owned pointer to the object at the given index of an
|
||||
* fx_array. The caller owns the returned pointer, and must release it
|
||||
* when they are finished with it.
|
||||
*
|
||||
* @param array The fx_array.
|
||||
* @param at The index of the object to return.
|
||||
* @return A pointer to the object at the given index. This pointer is
|
||||
* owned by the caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
FX_API fx_object *fx_array_get(fx_array *array, size_t at);
|
||||
|
||||
FX_API size_t fx_array_get_size(const fx_array *array);
|
||||
/**
|
||||
* Returns the number of objects contained in an fx_array.
|
||||
*
|
||||
* @param array The fx_array.
|
||||
* @return The number of objects contained in the fx_array.
|
||||
*/
|
||||
FX_API size_t fx_array_size(const fx_array *array);
|
||||
|
||||
FX_API size_t fx_array_get_capacity(const fx_array *array);
|
||||
/**
|
||||
* Returns the current maximum capacity of an fx_array. This represents
|
||||
* the number of objects that can be stored in an fx_array before its
|
||||
* internal buffer would need to be re-sized.
|
||||
*
|
||||
* @param array The fx_array.
|
||||
* @return The maximum capacity of the fx_array.
|
||||
*/
|
||||
FX_API size_t fx_array_capacity(const fx_array *array);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ FX_DECLARE_TYPE(fx_bitmap);
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_bitmap)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_bitmap)
|
||||
|
||||
FX_API fx_type_id fx_bitmap_get_type(void);
|
||||
FX_API fx_type fx_bitmap_get_type(void);
|
||||
|
||||
FX_API fx_bitmap *fx_bitmap_create(size_t nr_bits);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ FX_DECLARE_TYPE(fx_buffer);
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_buffer)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_buffer)
|
||||
|
||||
FX_API fx_type_id fx_buffer_get_type(void);
|
||||
FX_API fx_type fx_buffer_get_type(void);
|
||||
|
||||
FX_API fx_buffer *fx_buffer_create(size_t item_sz);
|
||||
FX_API fx_buffer *fx_buffer_create_from_bytes(const void *p, size_t len);
|
||||
|
||||
@@ -18,7 +18,7 @@ typedef enum fx_datetime_format {
|
||||
FX_DATETIME_FORMAT_RFC3339 = 1,
|
||||
} fx_datetime_format;
|
||||
|
||||
FX_API fx_type_id fx_datetime_get_type(void);
|
||||
FX_API fx_type fx_datetime_get_type(void);
|
||||
|
||||
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_datetime, FX_TYPE_DATETIME);
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifndef FX_DS_DICT_H_
|
||||
#define FX_DS_DICT_H_
|
||||
|
||||
#include <fx/bst.h>
|
||||
#include <fx/macros.h>
|
||||
#include <fx/misc.h>
|
||||
#include <fx/queue.h>
|
||||
#include <fx/status.h>
|
||||
#include <fx/string.h>
|
||||
|
||||
FX_DECLS_BEGIN;
|
||||
|
||||
#define FX_TYPE_DICT (fx_dict_get_type())
|
||||
#define FX_TYPE_DICT_ITERATOR (fx_dict_iterator_get_type())
|
||||
|
||||
struct fx_dict_p;
|
||||
|
||||
FX_DECLARE_TYPE(fx_dict);
|
||||
FX_DECLARE_TYPE(fx_dict_iterator);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_dict)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_dict)
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_dict_iterator)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_dict_iterator)
|
||||
|
||||
#define FX_DICT_ITEM(k, v) {.key = (k), .value = (v)}
|
||||
#define FX_DICT_ITEM_END {.key = NULL, .value = NULL}
|
||||
|
||||
#define fx_dict_foreach(it, dict) \
|
||||
for (int z__fx_unique_name() = fx_dict_iterator_begin(dict, it); \
|
||||
(it)->key != NULL; \
|
||||
fx_dict_iterator_next(it))
|
||||
|
||||
typedef struct fx_dict_item {
|
||||
const fx_string *key;
|
||||
fx_object *value;
|
||||
} fx_dict_item;
|
||||
|
||||
FX_API fx_type fx_dict_get_type(void);
|
||||
FX_API fx_type fx_dict_iterator_get_type(void);
|
||||
|
||||
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_dict, FX_TYPE_DICT);
|
||||
|
||||
#if 0
|
||||
FX_API fx_dict *fx_dict_create_with_items(const fx_dict_item *items);
|
||||
#endif
|
||||
|
||||
FX_API fx_status fx_dict_put(fx_dict *dict, const char *key, fx_object *value);
|
||||
FX_API fx_status
|
||||
fx_dict_put_sk(fx_dict *dict, const fx_string *key, fx_object *value);
|
||||
FX_API fx_object *fx_dict_at(const fx_dict *dict, const char *key);
|
||||
FX_API fx_object *fx_dict_at_sk(const fx_dict *dict, const fx_string *key);
|
||||
FX_API fx_object *fx_dict_get(fx_dict *dict, const char *key);
|
||||
FX_API fx_object *fx_dict_get_sk(fx_dict *dict, const fx_string *key);
|
||||
|
||||
FX_API bool fx_dict_has_key(const fx_dict *dict, const char *key);
|
||||
FX_API bool fx_dict_has_skey(const fx_dict *dict, const fx_string *key);
|
||||
FX_API size_t fx_dict_get_size(const fx_dict *dict);
|
||||
FX_API bool fx_dict_is_empty(const fx_dict *dict);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,6 @@
|
||||
#define FX_DS_HASHMAP_H_
|
||||
|
||||
#include <fx/bst.h>
|
||||
#include <fx/iterator.h>
|
||||
#include <fx/macros.h>
|
||||
#include <fx/misc.h>
|
||||
#include <fx/queue.h>
|
||||
@@ -61,8 +60,8 @@ typedef struct fx_hashmap_item {
|
||||
fx_hashmap_value value;
|
||||
} fx_hashmap_item;
|
||||
|
||||
FX_API fx_type_id fx_hashmap_get_type(void);
|
||||
FX_API fx_type_id fx_hashmap_iterator_get_type(void);
|
||||
FX_API fx_type fx_hashmap_get_type(void);
|
||||
FX_API fx_type fx_hashmap_iterator_get_type(void);
|
||||
|
||||
FX_API fx_hashmap *fx_hashmap_create(
|
||||
fx_hashmap_key_destructor key_dtor,
|
||||
@@ -83,7 +82,7 @@ FX_API bool fx_hashmap_has_key(
|
||||
FX_API size_t fx_hashmap_get_size(const fx_hashmap *hashmap);
|
||||
FX_API bool fx_hashmap_is_empty(const fx_hashmap *hashmap);
|
||||
|
||||
FX_API const fx_iterator *fx_hashmap_begin(const fx_hashmap *hashmap);
|
||||
FX_API fx_iterator *fx_hashmap_begin(fx_hashmap *hashmap);
|
||||
FX_API const fx_iterator *fx_hashmap_cbegin(const fx_hashmap *hashmap);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
#ifndef FX_COLLECTIONS_HASHTABLE_H_
|
||||
#define FX_COLLECTIONS_HASHTABLE_H_
|
||||
|
||||
#include <fx/bst.h>
|
||||
#include <fx/iterator.h>
|
||||
#include <fx/macros.h>
|
||||
#include <fx/misc.h>
|
||||
#include <fx/queue.h>
|
||||
#include <fx/status.h>
|
||||
#include <fx/value.h>
|
||||
#include <stddef.h>
|
||||
|
||||
FX_DECLS_BEGIN;
|
||||
|
||||
#define FX_TYPE_HASHTABLE (fx_hashtable_get_type())
|
||||
#define FX_TYPE_HASHTABLE_ITERATOR (fx_hashtable_iterator_get_type())
|
||||
#define FX_TYPE_HASHTABLE_ITEM (fx_hashtable_item_get_type())
|
||||
|
||||
FX_DECLARE_TYPE(fx_hashtable);
|
||||
FX_DECLARE_TYPE(fx_hashtable_iterator);
|
||||
FX_DECLARE_TYPE(fx_hashtable_item);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_hashtable)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_hashtable)
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_hashtable_iterator)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_hashtable_iterator)
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_hashtable_item)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_hashtable_item)
|
||||
|
||||
FX_API fx_type_id fx_hashtable_get_type(void);
|
||||
FX_API fx_type_id fx_hashtable_iterator_get_type(void);
|
||||
FX_API fx_type_id fx_hashtable_item_get_type(void);
|
||||
|
||||
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_hashtable, FX_TYPE_HASHTABLE);
|
||||
FX_API fx_hashtable *fx_hashtable_create(void);
|
||||
|
||||
FX_API fx_status
|
||||
fx_hashtable_put(fx_hashtable *hashtable, fx_value *key, fx_value *value);
|
||||
FX_API const fx_value *fx_hashtable_get(
|
||||
const fx_hashtable *hashtable,
|
||||
const fx_value *key);
|
||||
|
||||
FX_API size_t fx_hashtable_get_count(const fx_hashtable *hashtable);
|
||||
FX_API bool fx_hashtable_is_empty(const fx_hashtable *hashtable);
|
||||
|
||||
FX_API const fx_iterator *fx_hashtable_begin(const fx_hashtable *hashtable);
|
||||
|
||||
FX_API const fx_value *fx_hashtable_item_get_key(const fx_hashtable_item *item);
|
||||
FX_API const fx_value *fx_hashtable_item_get_value(
|
||||
const fx_hashtable_item *item);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -23,8 +23,8 @@ FX_TYPE_CLASS_DECLARATION_END(fx_list_iterator)
|
||||
|
||||
typedef struct fx_list_entry fx_list_entry;
|
||||
|
||||
FX_API fx_type_id fx_list_get_type(void);
|
||||
FX_API fx_type_id fx_list_iterator_get_type(void);
|
||||
FX_API fx_type fx_list_get_type(void);
|
||||
FX_API fx_type fx_list_iterator_get_type(void);
|
||||
|
||||
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_list, FX_TYPE_LIST);
|
||||
|
||||
@@ -59,7 +59,8 @@ FX_API void fx_list_delete_all(fx_list *q);
|
||||
|
||||
FX_API void *fx_list_entry_value(const fx_list_entry *entry);
|
||||
|
||||
FX_API const fx_iterator *fx_list_begin(const fx_list *q);
|
||||
FX_API fx_iterator *fx_list_begin(fx_list *q);
|
||||
FX_API const fx_iterator *fx_list_cbegin(const fx_list *q);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#ifndef FX_DS_TREE_H_
|
||||
#define FX_DS_TREE_H_
|
||||
|
||||
#include <fx/macros.h>
|
||||
#include <fx/misc.h>
|
||||
#include <fx/queue.h>
|
||||
#include <fx/string.h>
|
||||
|
||||
FX_DECLS_BEGIN;
|
||||
|
||||
#define FX_TYPE_TREE (fx_tree_get_type())
|
||||
#define FX_TYPE_TREE_ITERATOR (fx_tree_iterator_get_type())
|
||||
|
||||
FX_DECLARE_TYPE(fx_tree);
|
||||
FX_DECLARE_TYPE(fx_tree_iterator);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_tree)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_tree)
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_tree_iterator)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_tree_iterator)
|
||||
|
||||
#define FX_TREE_NODE_INIT ((fx_tree_node) {0})
|
||||
|
||||
#define FX_TREE_CONTAINER(t, m, v) \
|
||||
((void *)((v) ? (uintptr_t)(v) - (offsetof(t, m)) : 0))
|
||||
|
||||
typedef struct fx_tree_node {
|
||||
struct fx_tree_node *__p01, *__p02, *__p03;
|
||||
struct fx_queue_entry __q01;
|
||||
} fx_tree_node;
|
||||
|
||||
FX_API fx_type fx_tree_get_type(void);
|
||||
FX_API fx_type fx_tree_iterator_get_type(void);
|
||||
|
||||
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_tree, FX_TYPE_TREE);
|
||||
|
||||
FX_API void fx_tree_set_root(fx_tree *tree, struct fx_tree_node *node);
|
||||
|
||||
FX_API void fx_tree_node_add_child(fx_tree_node *parent, fx_tree_node *child);
|
||||
FX_API void fx_tree_node_add_sibling(fx_tree_node *node, fx_tree_node *to_add);
|
||||
|
||||
FX_API fx_tree_node *fx_tree_node_get_child(fx_tree_node *node, size_t at);
|
||||
FX_API fx_tree_node *fx_tree_node_get_parent(fx_tree_node *node);
|
||||
|
||||
FX_API fx_iterator *fx_tree_begin(fx_tree *tree);
|
||||
FX_API const fx_iterator *fx_tree_cbegin(const fx_tree *tree);
|
||||
|
||||
FX_API fx_iterator *fx_tree_node_begin(fx_tree_node *node);
|
||||
FX_API const fx_iterator *fx_tree_node_cbegin(const fx_tree_node *node);
|
||||
|
||||
FX_API fx_iterator *fx_tree_node_begin_recursive(fx_tree_node *node);
|
||||
FX_API const fx_iterator *fx_tree_node_cbegin_recursive(
|
||||
const fx_tree_node *node);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
#endif
|
||||
+68
-61
@@ -23,7 +23,6 @@ struct fx_list_iterator_p {
|
||||
|
||||
size_t i;
|
||||
void *item;
|
||||
fx_value item_value;
|
||||
fx_list_entry *entry;
|
||||
};
|
||||
|
||||
@@ -42,10 +41,8 @@ static void *list_first_item(const struct fx_list_p *q)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_list_entry *list_entry = fx_unbox(
|
||||
struct fx_list_entry,
|
||||
entry,
|
||||
e_entry);
|
||||
struct fx_list_entry *list_entry
|
||||
= fx_unbox(struct fx_list_entry, entry, e_entry);
|
||||
|
||||
return list_entry->e_data;
|
||||
}
|
||||
@@ -58,10 +55,8 @@ static void *list_last_item(const struct fx_list_p *q)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_list_entry *list_entry = fx_unbox(
|
||||
struct fx_list_entry,
|
||||
entry,
|
||||
e_entry);
|
||||
struct fx_list_entry *list_entry
|
||||
= fx_unbox(struct fx_list_entry, entry, e_entry);
|
||||
|
||||
return list_entry->e_data;
|
||||
}
|
||||
@@ -74,10 +69,8 @@ static struct fx_list_entry *list_first_entry(const struct fx_list_p *q)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_list_entry *list_entry = fx_unbox(
|
||||
struct fx_list_entry,
|
||||
entry,
|
||||
e_entry);
|
||||
struct fx_list_entry *list_entry
|
||||
= fx_unbox(struct fx_list_entry, entry, e_entry);
|
||||
|
||||
return list_entry;
|
||||
}
|
||||
@@ -90,10 +83,8 @@ static struct fx_list_entry *list_last_entry(const struct fx_list_p *q)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_list_entry *list_entry = fx_unbox(
|
||||
struct fx_list_entry,
|
||||
entry,
|
||||
e_entry);
|
||||
struct fx_list_entry *list_entry
|
||||
= fx_unbox(struct fx_list_entry, entry, e_entry);
|
||||
|
||||
return list_entry;
|
||||
}
|
||||
@@ -178,10 +169,8 @@ static void *list_pop_front(struct fx_list_p *q)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_list_entry *list_entry = fx_unbox(
|
||||
struct fx_list_entry,
|
||||
entry,
|
||||
e_entry);
|
||||
struct fx_list_entry *list_entry
|
||||
= fx_unbox(struct fx_list_entry, entry, e_entry);
|
||||
|
||||
void *item = list_entry->e_data;
|
||||
free(list_entry);
|
||||
@@ -198,10 +187,8 @@ static void *list_pop_back(struct fx_list_p *q)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_list_entry *list_entry = fx_unbox(
|
||||
struct fx_list_entry,
|
||||
entry,
|
||||
e_entry);
|
||||
struct fx_list_entry *list_entry
|
||||
= fx_unbox(struct fx_list_entry, entry, e_entry);
|
||||
|
||||
void *item = list_entry->e_data;
|
||||
free(list_entry);
|
||||
@@ -215,10 +202,8 @@ static struct fx_list_entry *find_item(struct fx_list_p *list, void *item)
|
||||
{
|
||||
struct fx_queue_entry *entry = fx_queue_first(&list->l_queue);
|
||||
while (entry) {
|
||||
struct fx_list_entry *list_entry = fx_unbox(
|
||||
struct fx_list_entry,
|
||||
entry,
|
||||
e_entry);
|
||||
struct fx_list_entry *list_entry
|
||||
= fx_unbox(struct fx_list_entry, entry, e_entry);
|
||||
|
||||
if (list_entry->e_data == item) {
|
||||
return list_entry;
|
||||
@@ -261,10 +246,8 @@ static void list_delete_all(struct fx_list_p *q)
|
||||
{
|
||||
struct fx_queue_entry *entry = fx_queue_first(&q->l_queue);
|
||||
while (entry) {
|
||||
struct fx_list_entry *list_entry = fx_unbox(
|
||||
struct fx_list_entry,
|
||||
entry,
|
||||
e_entry);
|
||||
struct fx_list_entry *list_entry
|
||||
= fx_unbox(struct fx_list_entry, entry, e_entry);
|
||||
struct fx_queue_entry *next = fx_queue_next(entry);
|
||||
|
||||
free(list_entry);
|
||||
@@ -402,12 +385,30 @@ void *fx_list_entry_value(const struct fx_list_entry *entry)
|
||||
return entry ? entry->e_data : NULL;
|
||||
}
|
||||
|
||||
const fx_iterator *fx_list_begin(const fx_list *q)
|
||||
fx_iterator *fx_list_begin(fx_list *q)
|
||||
{
|
||||
fx_list_iterator *it_obj = fx_object_create(FX_TYPE_LIST_ITERATOR);
|
||||
struct fx_list_iterator_p *it = fx_object_get_private(
|
||||
it_obj,
|
||||
FX_TYPE_LIST_ITERATOR);
|
||||
struct fx_list_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_LIST_ITERATOR);
|
||||
|
||||
it->_q = q;
|
||||
it->_q_p = fx_object_get_private(q, FX_TYPE_LIST);
|
||||
it->_q_entry = fx_queue_first(&it->_q_p->l_queue);
|
||||
|
||||
it->i = 0;
|
||||
it->entry = fx_unbox(struct fx_list_entry, it->_q_entry, e_entry);
|
||||
if (it->entry) {
|
||||
it->item = it->entry->e_data;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const fx_iterator *fx_list_cbegin(const fx_list *q)
|
||||
{
|
||||
fx_list_iterator *it_obj = fx_object_create(FX_TYPE_LIST_ITERATOR);
|
||||
struct fx_list_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_LIST_ITERATOR);
|
||||
|
||||
it->_q = (fx_list *)q;
|
||||
it->_q_p = fx_object_get_private(q, FX_TYPE_LIST);
|
||||
@@ -439,9 +440,8 @@ static void list_fini(fx_object *obj, void *priv)
|
||||
|
||||
static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_list_iterator_p *it = fx_object_get_private(
|
||||
obj,
|
||||
FX_TYPE_LIST_ITERATOR);
|
||||
struct fx_list_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_LIST_ITERATOR);
|
||||
|
||||
if (!it->_q_entry) {
|
||||
it->entry = NULL;
|
||||
@@ -467,9 +467,8 @@ static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
|
||||
static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
{
|
||||
struct fx_list_iterator_p *it = fx_object_get_private(
|
||||
obj,
|
||||
FX_TYPE_LIST_ITERATOR);
|
||||
struct fx_list_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_LIST_ITERATOR);
|
||||
|
||||
if (!it->entry || !it->_q_entry) {
|
||||
return FX_ERR_OUT_OF_BOUNDS;
|
||||
@@ -489,28 +488,35 @@ static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static const fx_value *iterator_get_value(const fx_iterator *obj)
|
||||
static fx_iterator_value iterator_get_value(fx_iterator *obj)
|
||||
{
|
||||
struct fx_list_iterator_p *it = fx_object_get_private(
|
||||
obj,
|
||||
FX_TYPE_LIST_ITERATOR);
|
||||
struct fx_list_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_LIST_ITERATOR);
|
||||
|
||||
it->item_value = FX_POINTER(it->item);
|
||||
return &it->item_value;
|
||||
return FX_ITERATOR_VALUE_PTR(it->item);
|
||||
}
|
||||
|
||||
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_list_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_LIST_ITERATOR);
|
||||
|
||||
return FX_ITERATOR_VALUE_CPTR(it->item);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- fx_list DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_list)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_list)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_INTERFACE_ENTRY(it_begin) = fx_list_begin;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_END(fx_list)
|
||||
FX_INTERFACE_ENTRY(it_cbegin) = fx_list_cbegin;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_list)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_list)
|
||||
FX_TYPE_ID(0x8730e66f, 0x0fd9, 0x4773, 0x9bbd, 0x6428f6e495eb);
|
||||
@@ -522,17 +528,18 @@ FX_TYPE_DEFINITION_BEGIN(fx_list)
|
||||
FX_TYPE_DEFINITION_END(fx_list)
|
||||
|
||||
// ---- fx_list_iterator DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_list_iterator)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_list_iterator)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_END(fx_list_iterator)
|
||||
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_list_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_list_iterator)
|
||||
FX_TYPE_ID(0xd9658456, 0xdd80, 0x419a, 0xb23a, 0xb513013e6431);
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
#include <fx/collections/array.h>
|
||||
#include <fx/int.h>
|
||||
#include <fx/ds/array.h>
|
||||
#include <fx/ds/number.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
#if 0
|
||||
fx_array *array = fx_array_create();
|
||||
fx_array_append(array, fx_int_create(32));
|
||||
fx_array_append(array, fx_int_create(64));
|
||||
fx_array_append(array, fx_int_create(128));
|
||||
fx_array_append(array, FX_RV_INT(32));
|
||||
fx_array_append(array, FX_RV_INT(64));
|
||||
fx_array_append(array, FX_RV_INT(128));
|
||||
|
||||
fx_iterator *it = fx_iterator_begin(array);
|
||||
fx_foreach_ptr(fx_object, obj, it)
|
||||
@@ -18,6 +17,5 @@ int main(void)
|
||||
fx_iterator_unref(it);
|
||||
|
||||
fx_array_unref(array);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
#include <fx/collections/hashtable.h>
|
||||
#include <fx/int.h>
|
||||
#include <fx/reflection/type.h>
|
||||
#include <fx/stream.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
fx_hashtable *ht = fx_hashtable_create();
|
||||
fx_hashtable_put(ht, &FX_INT(32), &FX_INT(64));
|
||||
fx_hashtable_put(ht, &FX_CSTR("hello"), &FX_INT(128));
|
||||
|
||||
const fx_value *v = fx_hashtable_get(ht, &FX_INT(32));
|
||||
if (v) {
|
||||
printf("32= ");
|
||||
fx_value_to_string(v, fx_stdout, NULL);
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("no value\n");
|
||||
}
|
||||
|
||||
const fx_iterator *it = fx_hashtable_begin(ht);
|
||||
fx_foreach(val, it)
|
||||
{
|
||||
fx_hashtable_item *item = NULL;
|
||||
fx_value_get_object(val, &item);
|
||||
printf("item %p\n", item);
|
||||
const fx_value *key, *value;
|
||||
key = fx_hashtable_item_get_key(item);
|
||||
value = fx_hashtable_item_get_value(item);
|
||||
|
||||
fx_iterator *prop_it = fx_type_get_properties(
|
||||
fx_type_get_by_id(FX_TYPE_HASHTABLE_ITEM));
|
||||
fx_foreach(prop_val, prop_it)
|
||||
{
|
||||
fx_property *prop;
|
||||
fx_value_get_object(prop_val, &prop);
|
||||
printf("%s = ", fx_property_get_name(prop));
|
||||
fx_value value = FX_VALUE_EMPTY;
|
||||
fx_property_get_value(prop, val, &value);
|
||||
fx_value_to_string(&value, fx_stdout, NULL);
|
||||
printf("\n");
|
||||
}
|
||||
fx_iterator_unref(prop_it);
|
||||
}
|
||||
fx_iterator_unref(it);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
#include <fx/float.h>
|
||||
#include <fx/ds/number.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
fx_number *number = fx_number_create_float(6.8);
|
||||
|
||||
printf("number=%zd\n", FX_NUMBER_IVAL(number));
|
||||
fx_number_unref(number);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <fx/string.h>
|
||||
#include <fx/ds/string.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
fx_string *string = fx_string_create_from_cstr("Hello, world!");
|
||||
fx_string *string = FX_CSTR("Hello, world!");
|
||||
printf("string object = ");
|
||||
fx_object_to_string(string, fx_stdout, NULL);
|
||||
fx_object_to_string(string, fx_stdout);
|
||||
printf("\n");
|
||||
fx_string_unref(string);
|
||||
return 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <fx/stream.h>
|
||||
#include <fx/string.h>
|
||||
#include <fx/stringstream.h>
|
||||
#include <fx/core/stream.h>
|
||||
#include <fx/core/stringstream.h>
|
||||
#include <fx/ds/string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
@@ -11,7 +11,7 @@ int main(int argc, const char **argv)
|
||||
fx_stream_read_all_bytes_s(fx_stdin, dest_stream, buf, &nr_read);
|
||||
|
||||
printf("done. read %zu bytes total.\n", nr_read);
|
||||
printf("%s\n", fx_stringstream_get_cstr(dest_stream));
|
||||
printf("%s\n", fx_stringstream_ptr(dest_stream));
|
||||
|
||||
fx_stringstream_unref(dest_stream);
|
||||
fx_stream_buffer_unref(buf);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <fx/string.h>
|
||||
#include <fx/stringstream.h>
|
||||
#include <fx/core/stringstream.h>
|
||||
#include <fx/ds/string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -8,24 +8,21 @@ int main(void)
|
||||
printf("-------------\n");
|
||||
fx_string *str = fx_string_create_from_cstr("Hello, world!\n");
|
||||
printf("%s\n", fx_string_get_cstr(str));
|
||||
printf("len:%zu, max:%zu\n",
|
||||
fx_string_get_size(str, FX_STRLEN_NORMAL),
|
||||
printf("len:%zu, max:%zu\n", fx_string_get_size(str, FX_STRLEN_NORMAL),
|
||||
fx_string_get_capacity(str));
|
||||
|
||||
fx_string_insert_cstr(str, "WOW!", 4);
|
||||
|
||||
printf("-------------\n");
|
||||
printf("%s\n", fx_string_get_cstr(str));
|
||||
printf("len:%zu, max:%zu\n",
|
||||
fx_string_get_size(str, FX_STRLEN_NORMAL),
|
||||
printf("len:%zu, max:%zu\n", fx_string_get_size(str, FX_STRLEN_NORMAL),
|
||||
fx_string_get_capacity(str));
|
||||
|
||||
fx_string_replace(str, 4, 4, "+");
|
||||
|
||||
printf("-------------\n");
|
||||
printf("%s\n", fx_string_get_cstr(str));
|
||||
printf("len:%zu, max:%zu\n",
|
||||
fx_string_get_size(str, FX_STRLEN_NORMAL),
|
||||
printf("len:%zu, max:%zu\n", fx_string_get_size(str, FX_STRLEN_NORMAL),
|
||||
fx_string_get_capacity(str));
|
||||
printf("-------------\n");
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
#include <fx/core/bst.h>
|
||||
#include <fx/core/iterator.h>
|
||||
#include <fx/ds/dict.h>
|
||||
#include <fx/ds/number.h>
|
||||
#include <fx/ds/tree.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define NITEMS 16
|
||||
|
||||
struct tree_item {
|
||||
int value;
|
||||
fx_tree_node node;
|
||||
};
|
||||
|
||||
struct bst_item {
|
||||
int value;
|
||||
fx_bst_node node;
|
||||
};
|
||||
|
||||
FX_BST_DEFINE_SIMPLE_GET(struct bst_item, int, node, value, get_node)
|
||||
FX_BST_DEFINE_SIMPLE_INSERT(struct bst_item, node, value, put_node)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
fx_dict *dict = fx_dict_create();
|
||||
fx_dict_put(dict, "hello", FX_RV_INT(32));
|
||||
fx_dict_put(dict, "world", FX_RV_INT(64));
|
||||
fx_dict_put(dict, "more", FX_RV_INT(128));
|
||||
fx_dict_put(dict, "other", FX_RV_INT(256));
|
||||
|
||||
fx_iterator *it = fx_iterator_begin(dict);
|
||||
|
||||
size_t i = 0;
|
||||
fx_foreach(fx_dict_item *, item, it)
|
||||
{
|
||||
printf("item %zu: %s=%d\n", i++, fx_string_get_cstr(item->key),
|
||||
fx_number_get_int(item->value));
|
||||
}
|
||||
|
||||
fx_iterator_unref(it);
|
||||
|
||||
fx_tree *tree = fx_tree_create();
|
||||
struct tree_item items2[NITEMS];
|
||||
|
||||
for (int i = 0; i < NITEMS; i++) {
|
||||
items2[i].value = i;
|
||||
items2[i].node = FX_TREE_NODE_INIT;
|
||||
}
|
||||
|
||||
fx_tree_set_root(tree, &items2[0].node);
|
||||
|
||||
fx_tree_node_add_child(&items2[0].node, &items2[1].node);
|
||||
fx_tree_node_add_child(&items2[0].node, &items2[2].node);
|
||||
fx_tree_node_add_child(&items2[0].node, &items2[3].node);
|
||||
fx_tree_node_add_child(&items2[0].node, &items2[7].node);
|
||||
fx_tree_node_add_child(&items2[1].node, &items2[4].node);
|
||||
fx_tree_node_add_child(&items2[1].node, &items2[5].node);
|
||||
fx_tree_node_add_child(&items2[4].node, &items2[6].node);
|
||||
|
||||
#if 0
|
||||
it = fx_iterator_begin(tree);
|
||||
fx_tree_iterator it2;
|
||||
fx_tree_foreach(&it2, tree)
|
||||
{
|
||||
struct tree_item *item = fx_unbox(struct tree_item, it2.node, node);
|
||||
|
||||
for (size_t i = 0; i < it2.depth; i++) {
|
||||
fputs(" ", stdout);
|
||||
}
|
||||
|
||||
printf("%u\n", item->value);
|
||||
}
|
||||
|
||||
fx_bst bst = {0};
|
||||
struct bst_item items3[NITEMS] = {0};
|
||||
for (int i = 0; i < NITEMS; i++) {
|
||||
items3[i].value = i;
|
||||
put_node(&bst, &items3[i]);
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
fx_bst_iterator it3;
|
||||
fx_bst_foreach (&it3, &bst) {
|
||||
struct bst_item *item
|
||||
= fx_unbox(struct bst_item, it3.node, node);
|
||||
|
||||
for (size_t i = 0; i < it3.depth; i++) {
|
||||
fputs(" ", stdout);
|
||||
}
|
||||
|
||||
printf("%d\n", item->value);
|
||||
}
|
||||
|
||||
fx_bst_iterator_begin(&bst, &it3);
|
||||
while (fx_bst_iterator_is_valid(&it3)) {
|
||||
struct bst_item *item
|
||||
= fx_unbox(struct bst_item, it3.node, node);
|
||||
|
||||
if (item->value == 9) {
|
||||
fx_bst_iterator_erase(&it3);
|
||||
} else {
|
||||
fx_bst_iterator_next(&it3);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
fx_bst_foreach (&it3, &bst) {
|
||||
struct bst_item *item
|
||||
= fx_unbox(struct bst_item, it3.node, node);
|
||||
|
||||
for (size_t i = 0; i < it3.depth; i++) {
|
||||
fputs(" ", stdout);
|
||||
}
|
||||
|
||||
printf("%d\n", item->value);
|
||||
}
|
||||
|
||||
fx_tree_unref(tree);
|
||||
#endif
|
||||
fx_dict_unref(dict);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <fx/string.h>
|
||||
#include <fx/stringstream.h>
|
||||
#include <fx/core/stringstream.h>
|
||||
#include <fx/ds/string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -10,17 +10,14 @@ int main(void)
|
||||
const char *s = fx_string_get_cstr(str);
|
||||
printf("%s\n", s);
|
||||
printf("len: %zu\n", fx_string_get_size(str, FX_STRLEN_NORMAL));
|
||||
printf("codepoints: %zu\n",
|
||||
fx_string_get_size(str, FX_STRLEN_CODEPOINTS));
|
||||
printf("codepoints: %zu\n", fx_string_get_size(str, FX_STRLEN_CODEPOINTS));
|
||||
|
||||
const char *delims[] = {"в"};
|
||||
size_t nr_delims = sizeof delims / sizeof delims[0];
|
||||
|
||||
fx_iterator *it = fx_string_tokenise(str, delims, nr_delims, 0);
|
||||
fx_foreach(val, it)
|
||||
fx_foreach(const char *, tok, it)
|
||||
{
|
||||
const char *tok = NULL;
|
||||
fx_value_get_cstr(val, &tok);
|
||||
printf("%s\n", tok);
|
||||
}
|
||||
fx_iterator_unref(it);
|
||||
@@ -0,0 +1,50 @@
|
||||
#include <CuTest.h>
|
||||
#include <fx/ds/string.h>
|
||||
|
||||
static void test_string_create(CuTest *tc)
|
||||
{
|
||||
fx_string *str = fx_string_create();
|
||||
|
||||
CuAssertPtrNotNull(tc, str);
|
||||
CuAssertIntEquals(tc, 0, fx_string_get_size(str, FX_STRLEN_NORMAL));
|
||||
CuAssertStrEquals(tc, "", fx_string_get_cstr(str));
|
||||
|
||||
fx_string_unref(str);
|
||||
|
||||
str = fx_string_create_from_c('A', 8);
|
||||
|
||||
CuAssertPtrNotNull(tc, str);
|
||||
CuAssertIntEquals(tc, 8, fx_string_get_size(str, FX_STRLEN_NORMAL));
|
||||
CuAssertStrEquals(tc, "AAAAAAAA", fx_string_get_cstr(str));
|
||||
|
||||
fx_string_unref(str);
|
||||
|
||||
str = fx_string_create_from_cstr("Hello, world!");
|
||||
|
||||
CuAssertPtrNotNull(tc, str);
|
||||
CuAssertIntEquals(tc, 13, fx_string_get_size(str, FX_STRLEN_NORMAL));
|
||||
CuAssertStrEquals(tc, "Hello, world!", fx_string_get_cstr(str));
|
||||
|
||||
fx_string_unref(str);
|
||||
}
|
||||
|
||||
static void test_string_length(CuTest *tc)
|
||||
{
|
||||
const char *cstr = "Hello, \033[91;1mworld!";
|
||||
fx_string *s = fx_string_create_from_cstr(cstr);
|
||||
|
||||
CuAssertIntEquals(tc, 13, fx_string_get_size(s, FX_STRLEN_IGNORE_ESC));
|
||||
CuAssertIntEquals(tc, 20, fx_string_get_size(s, FX_STRLEN_NORMAL));
|
||||
|
||||
fx_string_unref(s);
|
||||
}
|
||||
|
||||
CuSuite *get_all_tests(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
|
||||
SUITE_ADD_TEST(suite, test_string_create);
|
||||
SUITE_ADD_TEST(suite, test_string_length);
|
||||
|
||||
return suite;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <fx/uuid.h>
|
||||
#include <fx/ds/uuid.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
@@ -0,0 +1,390 @@
|
||||
#include <fx/collections/tree.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ITERATOR_RECURSIVE 0x01u
|
||||
|
||||
#define ITERATOR_IS_RECURSIVE(it) (((it)->_f01 & ITERATOR_RECURSIVE) != 0)
|
||||
#define ITERATOR_UNSET_RECURSIVE(it) ((it)->_f01 &= ~ITERATOR_RECURSIVE)
|
||||
#define ITERATOR_SET_RECURSIVE(it) ((it)->_f01 |= ITERATOR_RECURSIVE)
|
||||
|
||||
#define NODE_PARENT(n) ((n)->__p01)
|
||||
#define NODE_FIRST_CHILD(n) ((n)->__p02)
|
||||
#define NODE_NEXT_SIBLING(n) ((n)->__p03)
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct fx_tree_p {
|
||||
struct fx_tree_node *t_root;
|
||||
};
|
||||
|
||||
struct fx_tree_iterator_p {
|
||||
size_t i, depth;
|
||||
fx_tree_node *node;
|
||||
|
||||
unsigned char _f01;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static void tree_set_root(struct fx_tree_p *tree, struct fx_tree_node *node)
|
||||
{
|
||||
tree->t_root = node;
|
||||
}
|
||||
|
||||
static const struct fx_tree_node *next_node(
|
||||
const struct fx_tree_node *node,
|
||||
bool recursive,
|
||||
int *depth_diff)
|
||||
{
|
||||
if (!node) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!recursive) {
|
||||
node = NODE_NEXT_SIBLING(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
int d = 0;
|
||||
struct fx_tree_node *next = NODE_FIRST_CHILD(node);
|
||||
if (next) {
|
||||
d = 1;
|
||||
*depth_diff = d;
|
||||
return next;
|
||||
}
|
||||
|
||||
const struct fx_tree_node *n = node;
|
||||
next = NODE_NEXT_SIBLING(n);
|
||||
while (!next) {
|
||||
n = NODE_PARENT(n);
|
||||
if (!n) {
|
||||
break;
|
||||
}
|
||||
|
||||
d--;
|
||||
next = NODE_NEXT_SIBLING(n);
|
||||
}
|
||||
|
||||
*depth_diff = d;
|
||||
return next;
|
||||
}
|
||||
|
||||
static void remove_node(struct fx_tree_node *node)
|
||||
{
|
||||
struct fx_tree_node *parent = NODE_PARENT(node);
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct fx_tree_node *n0 = NULL, *n1 = NULL;
|
||||
n0 = NODE_FIRST_CHILD(parent);
|
||||
|
||||
while (n0) {
|
||||
if (n0 == node) {
|
||||
break;
|
||||
}
|
||||
|
||||
n1 = n0;
|
||||
n0 = NODE_NEXT_SIBLING(n0);
|
||||
}
|
||||
|
||||
if (!n0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (n1) {
|
||||
NODE_NEXT_SIBLING(n1) = NODE_NEXT_SIBLING(n0);
|
||||
} else {
|
||||
NODE_FIRST_CHILD(parent) = NODE_NEXT_SIBLING(n0);
|
||||
}
|
||||
|
||||
NODE_PARENT(n0) = NODE_NEXT_SIBLING(n0) = NULL;
|
||||
}
|
||||
|
||||
static void reparent_children(
|
||||
struct fx_tree_node *old_parent,
|
||||
struct fx_tree_node *new_parent)
|
||||
{
|
||||
struct fx_tree_node *last = NODE_FIRST_CHILD(new_parent);
|
||||
while (last && NODE_NEXT_SIBLING(last)) {
|
||||
last = NODE_NEXT_SIBLING(last);
|
||||
}
|
||||
|
||||
struct fx_tree_node *cur = NODE_FIRST_CHILD(old_parent);
|
||||
while (cur) {
|
||||
struct fx_tree_node *next = NODE_NEXT_SIBLING(cur);
|
||||
NODE_PARENT(cur) = new_parent;
|
||||
NODE_NEXT_SIBLING(cur) = NULL;
|
||||
|
||||
if (last) {
|
||||
NODE_NEXT_SIBLING(last) = cur;
|
||||
} else {
|
||||
NODE_FIRST_CHILD(new_parent) = cur;
|
||||
}
|
||||
|
||||
last = cur;
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
void fx_tree_set_root(fx_tree *tree, struct fx_tree_node *node)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_TREE, tree_set_root, tree, node);
|
||||
}
|
||||
|
||||
void fx_tree_node_add_child(
|
||||
struct fx_tree_node *parent,
|
||||
struct fx_tree_node *child)
|
||||
{
|
||||
if (NODE_PARENT(child)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NODE_PARENT(child) = parent;
|
||||
if (!NODE_FIRST_CHILD(parent)) {
|
||||
NODE_FIRST_CHILD(parent) = child;
|
||||
return;
|
||||
}
|
||||
|
||||
struct fx_tree_node *cur = NODE_FIRST_CHILD(parent);
|
||||
while (NODE_NEXT_SIBLING(cur)) {
|
||||
cur = NODE_NEXT_SIBLING(cur);
|
||||
}
|
||||
|
||||
NODE_NEXT_SIBLING(cur) = child;
|
||||
}
|
||||
|
||||
void fx_tree_node_add_sibling(
|
||||
struct fx_tree_node *node,
|
||||
struct fx_tree_node *to_add)
|
||||
{
|
||||
if (NODE_PARENT(to_add) || !NODE_PARENT(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
fx_tree_node_add_child(NODE_PARENT(node), to_add);
|
||||
}
|
||||
|
||||
struct fx_tree_node *fx_tree_node_get_child(
|
||||
struct fx_tree_node *node,
|
||||
size_t at)
|
||||
{
|
||||
size_t i = 0;
|
||||
struct fx_tree_node *cur = NODE_FIRST_CHILD(node);
|
||||
|
||||
while (i < at) {
|
||||
if (!cur) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cur = NODE_NEXT_SIBLING(cur);
|
||||
i++;
|
||||
}
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
fx_iterator *fx_tree_begin(fx_tree *tree)
|
||||
{
|
||||
struct fx_tree_p *p = fx_object_get_private(tree, FX_TYPE_TREE);
|
||||
return fx_tree_node_begin(p->t_root);
|
||||
}
|
||||
|
||||
const fx_iterator *fx_tree_cbegin(const fx_tree *tree)
|
||||
{
|
||||
struct fx_tree_p *p = fx_object_get_private(tree, FX_TYPE_TREE);
|
||||
return fx_tree_node_begin(p->t_root);
|
||||
}
|
||||
|
||||
fx_iterator *fx_tree_node_begin(struct fx_tree_node *node)
|
||||
{
|
||||
fx_tree_iterator *it_obj = fx_object_create(FX_TYPE_TREE_ITERATOR);
|
||||
struct fx_tree_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_TREE_ITERATOR);
|
||||
|
||||
it->node = NODE_FIRST_CHILD(node);
|
||||
it->i = 0;
|
||||
it->depth = 0;
|
||||
|
||||
ITERATOR_UNSET_RECURSIVE(it);
|
||||
|
||||
if (!it->node) {
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
}
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
const fx_iterator *fx_tree_node_cbegin(const struct fx_tree_node *node)
|
||||
{
|
||||
return fx_tree_node_begin((struct fx_tree_node *)node);
|
||||
}
|
||||
|
||||
fx_iterator *fx_tree_node_begin_recursive(struct fx_tree_node *node)
|
||||
{
|
||||
fx_tree_iterator *it_obj = fx_object_create(FX_TYPE_TREE_ITERATOR);
|
||||
struct fx_tree_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_TREE_ITERATOR);
|
||||
|
||||
it->node = node;
|
||||
it->i = 0;
|
||||
it->depth = 0;
|
||||
|
||||
ITERATOR_SET_RECURSIVE(it);
|
||||
|
||||
if (!it->node) {
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
}
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
const fx_iterator *fx_tree_node_cbegin_recursive(
|
||||
const struct fx_tree_node *node)
|
||||
{
|
||||
return fx_tree_node_begin_recursive((struct fx_tree_node *)node);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void tree_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_tree_p *tree = priv;
|
||||
}
|
||||
|
||||
static void tree_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_tree_p *tree = priv;
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_tree_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_TREE_ITERATOR);
|
||||
|
||||
int depth_diff = 0;
|
||||
const struct fx_tree_node *next
|
||||
= next_node(it->node, ITERATOR_IS_RECURSIVE(it), &depth_diff);
|
||||
|
||||
if (next) {
|
||||
it->depth += depth_diff;
|
||||
it->i++;
|
||||
} else {
|
||||
it->depth = 0;
|
||||
it->i = 0;
|
||||
}
|
||||
|
||||
it->node = (struct fx_tree_node *)next;
|
||||
return (it->node != NULL) ? FX_SUCCESS : FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
{
|
||||
struct fx_tree_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_TREE_ITERATOR);
|
||||
|
||||
if (!it->node) {
|
||||
return FX_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
struct fx_tree_node *parent = NODE_PARENT(it->node);
|
||||
if (!parent) {
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
int d = 0;
|
||||
struct fx_tree_node *n = it->node;
|
||||
struct fx_tree_node *next = NODE_NEXT_SIBLING(n);
|
||||
|
||||
if (!next) {
|
||||
next = NODE_FIRST_CHILD(n);
|
||||
}
|
||||
|
||||
while (!next) {
|
||||
n = NODE_PARENT(n);
|
||||
if (!n) {
|
||||
break;
|
||||
}
|
||||
|
||||
d--;
|
||||
next = NODE_NEXT_SIBLING(n);
|
||||
}
|
||||
|
||||
remove_node(it->node);
|
||||
reparent_children(it->node, parent);
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_iterator_value iterator_get_value(fx_iterator *obj)
|
||||
{
|
||||
struct fx_tree_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_TREE_ITERATOR);
|
||||
|
||||
if (!it->node) {
|
||||
return FX_ITERATOR_VALUE_NULL;
|
||||
}
|
||||
|
||||
return FX_ITERATOR_VALUE_PTR(it->node);
|
||||
}
|
||||
|
||||
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_tree_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_TREE_ITERATOR);
|
||||
|
||||
if (!it->node) {
|
||||
return FX_ITERATOR_VALUE_NULL;
|
||||
}
|
||||
|
||||
return FX_ITERATOR_VALUE_CPTR(it->node);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- fx_tree DEFINITION
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_tree)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_INTERFACE_ENTRY(it_begin) = fx_tree_begin;
|
||||
FX_INTERFACE_ENTRY(it_cbegin) = fx_tree_cbegin;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_tree)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_tree)
|
||||
FX_TYPE_ID(0x8d8fa36b, 0xc515, 0x4803, 0x8124, 0xfd704f01b8ae);
|
||||
FX_TYPE_CLASS(fx_tree_class);
|
||||
FX_TYPE_IMPLEMENTS(FX_TYPE_ITERABLE);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_tree_p);
|
||||
FX_TYPE_INSTANCE_INIT(tree_init);
|
||||
FX_TYPE_INSTANCE_FINI(tree_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_tree)
|
||||
|
||||
// ---- fx_tree_iterator DEFINITION
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_tree_iterator)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_tree_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_tree_iterator)
|
||||
FX_TYPE_ID(0xb896e671, 0x84b2, 0x4892, 0xaf09, 0x407f305f4bf8);
|
||||
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
|
||||
FX_TYPE_CLASS(fx_tree_iterator_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_tree_iterator_p);
|
||||
FX_TYPE_DEFINITION_END(fx_tree_iterator)
|
||||
@@ -162,7 +162,7 @@ static bool compressor_eof(const struct compressor_data *p)
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
enum fx_status fx_compressor_get_buffer_size(
|
||||
fx_type_id type,
|
||||
fx_type type,
|
||||
fx_compressor_mode mode,
|
||||
size_t *inbuf_size,
|
||||
size_t *outbuf_size)
|
||||
@@ -248,11 +248,11 @@ static void compressor_fini(fx_object *obj, void *priv)
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_compressor)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_compressor)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_END(fx_compressor)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_compressor)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_compressor)
|
||||
FX_TYPE_ID(0x452ee0f9, 0xfe12, 0x48a1, 0xb596, 0xad5b7a3940e7);
|
||||
|
||||
@@ -782,7 +782,7 @@ static enum fx_status cstream_restore_cursor_position(
|
||||
|
||||
enum fx_status fx_cstream_open(
|
||||
fx_stream *endpoint,
|
||||
fx_type_id compressor_type,
|
||||
fx_type compressor_type,
|
||||
fx_compressor_mode mode,
|
||||
fx_cstream **out)
|
||||
{
|
||||
@@ -989,12 +989,12 @@ static void cstream_fini(fx_object *obj, void *priv)
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_cstream)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_cstream)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_stream, FX_TYPE_STREAM)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_stream, FX_TYPE_STREAM)
|
||||
FX_INTERFACE_ENTRY(s_close) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_seek) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_tell) = NULL;
|
||||
@@ -1002,8 +1002,8 @@ FX_TYPE_CLASS_BEGIN(fx_cstream)
|
||||
FX_INTERFACE_ENTRY(s_read) = fx_cstream_read;
|
||||
FX_INTERFACE_ENTRY(s_write) = fx_cstream_write;
|
||||
FX_INTERFACE_ENTRY(s_reserve) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_stream, FX_TYPE_STREAM)
|
||||
FX_TYPE_CLASS_END(fx_cstream)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_stream, FX_TYPE_STREAM)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_cstream)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_cstream)
|
||||
FX_TYPE_ID(0xe1e899b5, 0x6a3c, 0x4f9c, 0xafd0, 0xaab3f156615c);
|
||||
|
||||
@@ -361,12 +361,12 @@ static enum fx_status set_mode(
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_zstd_compressor)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_zstd_compressor)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_compressor, FX_TYPE_COMPRESSOR)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_compressor, FX_TYPE_COMPRESSOR)
|
||||
FX_INTERFACE_ENTRY(c_buffer_size)
|
||||
= fx_zstd_compressor_get_buffer_size;
|
||||
FX_INTERFACE_ENTRY(c_compress) = compress;
|
||||
@@ -374,8 +374,8 @@ FX_TYPE_CLASS_BEGIN(fx_zstd_compressor)
|
||||
FX_INTERFACE_ENTRY(c_decompress) = decompress;
|
||||
FX_INTERFACE_ENTRY(c_reset) = reset;
|
||||
FX_INTERFACE_ENTRY(c_set_mode) = set_mode;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_compressor, FX_TYPE_COMPRESSOR)
|
||||
FX_TYPE_CLASS_END(fx_zstd_compressor)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_compressor, FX_TYPE_COMPRESSOR)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_zstd_compressor)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_zstd_compressor)
|
||||
FX_TYPE_ID(0x51d437fc, 0xe789, 0x4105, 0xbac7, 0xe6b3f45df198);
|
||||
|
||||
@@ -38,7 +38,7 @@ typedef struct fx_compressor_data {
|
||||
fx_ringbuffer *c_in, *c_out;
|
||||
} fx_compressor_data;
|
||||
|
||||
FX_API fx_type_id fx_compressor_get_type(void);
|
||||
FX_API fx_type fx_compressor_get_type(void);
|
||||
|
||||
#if 0
|
||||
FX_API fx_status fx_compressor_create(
|
||||
@@ -48,7 +48,7 @@ FX_API fx_status fx_compressor_create(
|
||||
#endif
|
||||
|
||||
FX_API fx_status fx_compressor_get_buffer_size(
|
||||
fx_type_id type,
|
||||
fx_type type,
|
||||
fx_compressor_mode mode,
|
||||
size_t *inbuf_size,
|
||||
size_t *outbuf_size);
|
||||
|
||||
@@ -16,11 +16,11 @@ FX_DECLARE_TYPE(fx_cstream);
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_cstream)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_cstream)
|
||||
|
||||
FX_API fx_type_id fx_cstream_get_type(void);
|
||||
FX_API fx_type fx_cstream_get_type(void);
|
||||
|
||||
FX_API fx_status fx_cstream_open(
|
||||
fx_stream *endpoint,
|
||||
fx_type_id compressor_type,
|
||||
fx_type compressor_type,
|
||||
enum fx_compressor_mode mode,
|
||||
fx_cstream **out);
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ FX_DECLARE_TYPE(fx_zstd_compressor);
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_zstd_compressor)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_compressor)
|
||||
|
||||
FX_API fx_type_id fx_zstd_compressor_get_type(void);
|
||||
FX_API fx_type fx_zstd_compressor_get_type(void);
|
||||
|
||||
FX_API fx_status fx_zstd_compressor_get_buffer_size(
|
||||
fx_compressor_mode mode,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include <assert.h>
|
||||
#include <fx/compression/compressor.h>
|
||||
#include <fx/compression/cstream.h>
|
||||
#include <fx/compression/zstd.h>
|
||||
#include <fx/ringbuffer.h>
|
||||
#include <fx/stream.h>
|
||||
#include <fx/compress/compressor.h>
|
||||
#include <fx/compress/cstream.h>
|
||||
#include <fx/compress/zstd.h>
|
||||
#include <fx/core/ringbuffer.h>
|
||||
#include <fx/core/stream.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -48,13 +48,9 @@ int main(int argc, const char **argv)
|
||||
|
||||
size_t nr_written = 0;
|
||||
fx_status status = fx_cstream_write(
|
||||
cstream,
|
||||
source,
|
||||
source_len,
|
||||
&nr_written);
|
||||
cstream, source, source_len, &nr_written);
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr,
|
||||
"write error: %s\n",
|
||||
fprintf(stderr, "write error: %s\n",
|
||||
fx_status_description(status));
|
||||
break;
|
||||
}
|
||||
@@ -63,19 +59,14 @@ int main(int argc, const char **argv)
|
||||
|
||||
if (compressed) {
|
||||
fx_cstream_end_compressed_section(
|
||||
cstream,
|
||||
&nr_written_compressed,
|
||||
&nr_written);
|
||||
cstream, &nr_written_compressed, &nr_written);
|
||||
}
|
||||
|
||||
size_t tx_total = 0;
|
||||
fx_cstream_tx_bytes(cstream, &tx_total);
|
||||
printf("iteration %d: wrote %zu (compressed) / %zu "
|
||||
"(uncompressed) / %zu (total) bytes (%s)\n",
|
||||
i,
|
||||
nr_written_compressed,
|
||||
nr_written,
|
||||
tx_total,
|
||||
i, nr_written_compressed, nr_written, tx_total,
|
||||
compressed ? "compressed" : "uncompressed");
|
||||
|
||||
compressed = !compressed;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include <assert.h>
|
||||
#include <fx/compression/compressor.h>
|
||||
#include <fx/compression/cstream.h>
|
||||
#include <fx/compression/zstd.h>
|
||||
#include <fx/ringbuffer.h>
|
||||
#include <fx/stream.h>
|
||||
#include <fx/compress/compressor.h>
|
||||
#include <fx/compress/cstream.h>
|
||||
#include <fx/compress/zstd.h>
|
||||
#include <fx/core/ringbuffer.h>
|
||||
#include <fx/core/stream.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -37,14 +37,10 @@ int main(int argc, const char **argv)
|
||||
memset(buf, 0x0, sizeof buf);
|
||||
|
||||
size_t nr_read = 0;
|
||||
fx_status status = fx_cstream_read(
|
||||
cstream,
|
||||
buf,
|
||||
sizeof buf - 1,
|
||||
&nr_read);
|
||||
fx_status status
|
||||
= fx_cstream_read(cstream, buf, sizeof buf - 1, &nr_read);
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr,
|
||||
"write error: %s\n",
|
||||
fprintf(stderr, "write error: %s\n",
|
||||
fx_status_description(status));
|
||||
break;
|
||||
}
|
||||
@@ -56,19 +52,14 @@ int main(int argc, const char **argv)
|
||||
size_t nr_read_compressed = 0;
|
||||
if (compressed) {
|
||||
fx_cstream_end_compressed_section(
|
||||
cstream,
|
||||
&nr_read_compressed,
|
||||
&nr_read);
|
||||
cstream, &nr_read_compressed, &nr_read);
|
||||
}
|
||||
|
||||
size_t tx_total = 0;
|
||||
fx_cstream_tx_bytes(cstream, &tx_total);
|
||||
printf(" * iteration %d: read %zu (compressed) / %zu "
|
||||
"(uncompressed) / %zu (total) bytes (%s)\n",
|
||||
i,
|
||||
nr_read_compressed,
|
||||
nr_read,
|
||||
tx_total,
|
||||
i, nr_read_compressed, nr_read, tx_total,
|
||||
compressed ? "compressed" : "uncompressed");
|
||||
printf("%s\n", buf);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <assert.h>
|
||||
#include <fx/compression/compressor.h>
|
||||
#include <fx/compression/zstd.h>
|
||||
#include <fx/ringbuffer.h>
|
||||
#include <fx/compress/compressor.h>
|
||||
#include <fx/compress/zstd.h>
|
||||
#include <fx/core/ringbuffer.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -12,10 +12,8 @@ int refill_input_buffer(FILE *fp, fx_ringbuffer *dest)
|
||||
while (1) {
|
||||
void *buf;
|
||||
size_t capacity;
|
||||
fx_status status = fx_ringbuffer_open_write_buffer(
|
||||
dest,
|
||||
&buf,
|
||||
&capacity);
|
||||
fx_status status
|
||||
= fx_ringbuffer_open_write_buffer(dest, &buf, &capacity);
|
||||
if (status == FX_ERR_NO_SPACE) {
|
||||
break;
|
||||
}
|
||||
@@ -45,10 +43,8 @@ int flush_output_buffer(FILE *fp, fx_ringbuffer *src)
|
||||
while (1) {
|
||||
const void *buf;
|
||||
size_t capacity;
|
||||
fx_status status = fx_ringbuffer_open_read_buffer(
|
||||
src,
|
||||
&buf,
|
||||
&capacity);
|
||||
fx_status status
|
||||
= fx_ringbuffer_open_read_buffer(src, &buf, &capacity);
|
||||
if (status == FX_ERR_NO_DATA) {
|
||||
break;
|
||||
}
|
||||
@@ -72,9 +68,7 @@ int flush_output_buffer(FILE *fp, fx_ringbuffer *src)
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
if (argc < 4) {
|
||||
fprintf(stderr,
|
||||
"usage: %s <C/D> <inpath> <outpath>\n",
|
||||
argv[0]);
|
||||
fprintf(stderr, "usage: %s <C/D> <inpath> <outpath>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -102,15 +96,12 @@ int main(int argc, const char **argv)
|
||||
}
|
||||
|
||||
fx_status status = FX_SUCCESS;
|
||||
fx_type_id compressor_type = FX_TYPE_ZSTD_COMPRESSOR;
|
||||
fx_type compressor_type = FX_TYPE_ZSTD_COMPRESSOR;
|
||||
fx_compressor *compressor = fx_object_create(compressor_type);
|
||||
|
||||
size_t inbuf_size, outbuf_size;
|
||||
fx_compressor_get_buffer_size(
|
||||
compressor_type,
|
||||
mode,
|
||||
&inbuf_size,
|
||||
&outbuf_size);
|
||||
compressor_type, mode, &inbuf_size, &outbuf_size);
|
||||
|
||||
fx_ringbuffer *in = fx_ringbuffer_create(inbuf_size);
|
||||
fx_ringbuffer *out = fx_ringbuffer_create(outbuf_size);
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
#include <assert.h>
|
||||
#include <fx/compression/compressor.h>
|
||||
#include <fx/compression/cstream.h>
|
||||
#include <fx/compression/zstd.h>
|
||||
#include <fx/ringbuffer.h>
|
||||
#include <fx/stream.h>
|
||||
#include <fx/compress/compressor.h>
|
||||
#include <fx/compress/cstream.h>
|
||||
#include <fx/compress/zstd.h>
|
||||
#include <fx/core/ringbuffer.h>
|
||||
#include <fx/core/stream.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define BUF_SIZE 32
|
||||
|
||||
static int compress(fx_type_id compressor_type, FILE *in, FILE *out)
|
||||
static int compress(fx_type compressor_type, FILE *in, FILE *out)
|
||||
{
|
||||
fx_stream *out_stream = fx_stream_open_fp(out);
|
||||
|
||||
fx_cstream *cstream;
|
||||
fx_status status = fx_cstream_open(
|
||||
out_stream,
|
||||
compressor_type,
|
||||
FX_COMPRESSOR_MODE_COMPRESS,
|
||||
&cstream);
|
||||
out_stream, compressor_type, FX_COMPRESSOR_MODE_COMPRESS, &cstream);
|
||||
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr, "cannot initialise compressor\n");
|
||||
@@ -51,16 +48,13 @@ static int compress(fx_type_id compressor_type, FILE *in, FILE *out)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decompress(fx_type_id compressor_type, FILE *in, FILE *out)
|
||||
static int decompress(fx_type compressor_type, FILE *in, FILE *out)
|
||||
{
|
||||
fx_stream *in_stream = fx_stream_open_fp(in);
|
||||
|
||||
fx_cstream *cstream;
|
||||
fx_status status = fx_cstream_open(
|
||||
in_stream,
|
||||
compressor_type,
|
||||
FX_COMPRESSOR_MODE_DECOMPRESS,
|
||||
&cstream);
|
||||
in_stream, compressor_type, FX_COMPRESSOR_MODE_DECOMPRESS, &cstream);
|
||||
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr, "cannot initialise compressor\n");
|
||||
@@ -72,14 +66,9 @@ static int decompress(fx_type_id compressor_type, FILE *in, FILE *out)
|
||||
char buf[4096];
|
||||
while (1) {
|
||||
size_t r = 0;
|
||||
fx_status status = fx_cstream_read(
|
||||
cstream,
|
||||
buf,
|
||||
sizeof buf,
|
||||
&r);
|
||||
fx_status status = fx_cstream_read(cstream, buf, sizeof buf, &r);
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr,
|
||||
"read error: %s\n",
|
||||
fprintf(stderr, "read error: %s\n",
|
||||
fx_status_description(status));
|
||||
return -1;
|
||||
}
|
||||
@@ -105,9 +94,7 @@ static int decompress(fx_type_id compressor_type, FILE *in, FILE *out)
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
if (argc < 4) {
|
||||
fprintf(stderr,
|
||||
"usage: %s <C/D> <inpath> <outpath>\n",
|
||||
argv[0]);
|
||||
fprintf(stderr, "usage: %s <C/D> <inpath> <outpath>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export_fx_namespace_details(fx.diagnostics)
|
||||
@@ -1,46 +0,0 @@
|
||||
#ifndef FX_DIAGNOSTICS_PROCESS_H_
|
||||
#define FX_DIAGNOSTICS_PROCESS_H_
|
||||
|
||||
#include <fx/collections/array.h>
|
||||
#include <fx/collections/hashtable.h>
|
||||
#include <fx/macros.h>
|
||||
#include <fx/stream.h>
|
||||
|
||||
FX_DECLS_BEGIN;
|
||||
|
||||
#define FX_DIAGNOSTICS_TYPE_PROCESS (fx_process_get_type())
|
||||
|
||||
FX_DECLARE_TYPE(fx_process);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_process)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_process)
|
||||
|
||||
typedef struct fx_process_start_info {
|
||||
bool proc_redirect_stdin, proc_redirect_stdout, proc_redirect_stderr;
|
||||
const char *proc_file_name;
|
||||
const fx_array *proc_args;
|
||||
const fx_hashtable *proc_environment;
|
||||
} fx_process_start_info;
|
||||
|
||||
FX_API fx_type_id fx_process_get_type(void);
|
||||
|
||||
FX_API fx_process *fx_process_create(const fx_process_start_info *info);
|
||||
|
||||
FX_API fx_process *fx_process_get_self(void);
|
||||
|
||||
FX_API fx_status fx_process_start(fx_process *proc);
|
||||
FX_API fx_status fx_process_wait(fx_process *proc, int *out_result);
|
||||
FX_API fx_status fx_process_kill(fx_process *proc);
|
||||
|
||||
FX_API const fx_hashtable *fx_process_get_environment(const fx_process *proc);
|
||||
FX_API fx_stream *fx_process_get_stdin(fx_process *proc);
|
||||
FX_API fx_stream *fx_process_get_stdout(fx_process *proc);
|
||||
FX_API fx_stream *fx_process_get_stderr(fx_process *proc);
|
||||
|
||||
FX_API void fx_process_close_stdin(fx_process *proc);
|
||||
FX_API void fx_process_close_stdout(fx_process *proc);
|
||||
FX_API void fx_process_close_stderr(fx_process *proc);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,570 +0,0 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <fx/collections/array.h>
|
||||
#include <fx/diagnostics/process.h>
|
||||
#include <fx/global.h>
|
||||
#include <fx/io/path.h>
|
||||
#include <fx/io/pipe.h>
|
||||
#include <fx/io/stream.h>
|
||||
#include <fx/iterator.h>
|
||||
#include <fx/macros.h>
|
||||
#include <fx/string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static fx_process *self = NULL;
|
||||
|
||||
extern const char **environ;
|
||||
|
||||
FX_API fx_type_id fx_process_iterator_get_type();
|
||||
|
||||
FX_DECLARE_TYPE(fx_process_iterator);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_process_iterator)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_process_iterator)
|
||||
|
||||
struct fx_process_p {
|
||||
fx_string *proc_exec_path;
|
||||
fx_array *proc_args;
|
||||
bool proc_redirect_stdin, proc_redirect_stdout, proc_redirect_stderr;
|
||||
fx_stream *proc_stdin, *proc_stdout, *proc_stderr;
|
||||
pid_t proc_id;
|
||||
fx_hashtable *proc_environment;
|
||||
};
|
||||
|
||||
struct fx_process_iterator_p {
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static bool exec_name_is_path(const char *s)
|
||||
{
|
||||
fx_wchar c;
|
||||
while (*s) {
|
||||
c = fx_wchar_utf8_codepoint_decode(s);
|
||||
if (c == FX_WCHAR_INVALID) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '/') {
|
||||
return true;
|
||||
}
|
||||
|
||||
s += fx_wchar_utf8_codepoint_stride(s);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const fx_string *get_path(void)
|
||||
{
|
||||
const char *path_env = NULL;
|
||||
fx_process *self = fx_process_get_self();
|
||||
if (!self) {
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
const fx_hashtable *env = fx_process_get_environment(self);
|
||||
if (!env) {
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
const fx_value *path_v = fx_hashtable_get(env, &FX_CSTR("PATH"));
|
||||
if (!path_v) {
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
fx_string *result = NULL;
|
||||
fx_value_get_object(path_v, &result);
|
||||
return result;
|
||||
|
||||
fallback:
|
||||
path_env = getenv("PATH");
|
||||
if (!path_env) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fx_string_create_from_cstr(path_env);
|
||||
}
|
||||
|
||||
static fx_status find_executable(fx_string *exec_path)
|
||||
{
|
||||
const char *exec_path_cstr = fx_string_get_cstr(exec_path);
|
||||
const fx_string *path_env = get_path();
|
||||
if (!path_env) {
|
||||
return FX_ERR_NO_ENTRY;
|
||||
}
|
||||
|
||||
const char *delim[] = {":"};
|
||||
size_t nr_delim = sizeof delim / sizeof delim[0];
|
||||
fx_path *path = NULL;
|
||||
fx_iterator *it = fx_string_tokenise(
|
||||
path_env,
|
||||
delim,
|
||||
nr_delim,
|
||||
FX_STRING_TOK_F_NORMAL);
|
||||
fx_status status = FX_ERR_NO_ENTRY;
|
||||
|
||||
fx_foreach(tok, it)
|
||||
{
|
||||
path = fx_path_join_list(2, tok, &FX_VALUE_OBJECT(exec_path));
|
||||
if (fx_path_is_file(path)) {
|
||||
fx_string_clear(exec_path);
|
||||
fx_string_append_cstr(
|
||||
exec_path,
|
||||
fx_path_get_cstr(path));
|
||||
status = FX_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fx_iterator_unref(it);
|
||||
fx_path_unref(path);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static fx_status process_start(struct fx_process_p *proc)
|
||||
{
|
||||
fx_iostream *in_r = NULL, *in_w = NULL;
|
||||
fx_iostream *out_r = NULL, *out_w = NULL;
|
||||
fx_iostream *err_r = NULL, *err_w = NULL;
|
||||
fx_status status = FX_SUCCESS;
|
||||
bool name_is_path
|
||||
= exec_name_is_path(fx_string_get_cstr(proc->proc_exec_path));
|
||||
|
||||
if (!name_is_path) {
|
||||
status = find_executable(proc->proc_exec_path);
|
||||
}
|
||||
|
||||
if (!FX_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (proc->proc_redirect_stdin) {
|
||||
status = fx_pipe_create(&in_r, &in_w);
|
||||
if (!FX_OK(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (proc->proc_redirect_stdout) {
|
||||
status = fx_pipe_create(&out_r, &out_w);
|
||||
if (!FX_OK(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (proc->proc_redirect_stderr) {
|
||||
status = fx_pipe_create(&err_r, &err_w);
|
||||
if (!FX_OK(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
status = FX_ERR_INVALID_ARGUMENT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (pid > 0) {
|
||||
proc->proc_id = pid;
|
||||
proc->proc_stdin = fx_iostream_ref(in_w);
|
||||
proc->proc_stdout = fx_iostream_ref(out_r);
|
||||
proc->proc_stderr = fx_iostream_ref(err_r);
|
||||
status = FX_SUCCESS;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
int fd = -1;
|
||||
if (proc->proc_redirect_stdin) {
|
||||
fx_iostream_unref(in_w);
|
||||
fd = fx_iostream_steal_os_handle(in_r);
|
||||
int err = dup2(fd, 0);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (proc->proc_redirect_stdout) {
|
||||
fx_iostream_unref(out_r);
|
||||
fd = fx_iostream_steal_os_handle(out_w);
|
||||
dup2(fd, 1);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (proc->proc_redirect_stderr) {
|
||||
fx_iostream_unref(err_r);
|
||||
fd = fx_iostream_steal_os_handle(err_w);
|
||||
dup2(fd, 2);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
const char **argv = NULL;
|
||||
const char **envp = NULL;
|
||||
const char *default_argv[] = {
|
||||
fx_string_get_cstr(proc->proc_exec_path),
|
||||
NULL,
|
||||
};
|
||||
|
||||
size_t argc = 0;
|
||||
size_t envc = 0;
|
||||
|
||||
if (proc->proc_args) {
|
||||
argc = fx_array_get_size(proc->proc_args);
|
||||
}
|
||||
|
||||
if (proc->proc_environment) {
|
||||
envc = fx_hashtable_get_count(proc->proc_environment);
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
argv = calloc(argc + 1, sizeof(char *));
|
||||
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
const fx_value *arg_value
|
||||
= fx_array_get_ref(proc->proc_args, i);
|
||||
fx_value_get_cstr(arg_value, &argv[i]);
|
||||
}
|
||||
} else {
|
||||
argv = default_argv;
|
||||
}
|
||||
|
||||
if (envc) {
|
||||
envp = calloc(envc + 1, sizeof(char *));
|
||||
size_t i = 0;
|
||||
fx_stringstream *tmp = fx_stringstream_create();
|
||||
const fx_iterator *it
|
||||
= fx_iterator_begin(proc->proc_environment);
|
||||
fx_foreach(v, it)
|
||||
{
|
||||
fx_hashtable_item *item = NULL;
|
||||
fx_value_get_object(v, &item);
|
||||
const fx_value *name_v
|
||||
= fx_hashtable_item_get_key(item);
|
||||
const fx_value *value_v
|
||||
= fx_hashtable_item_get_value(item);
|
||||
|
||||
fx_value_to_string(name_v, tmp, NULL);
|
||||
fx_stream_write_char(tmp, '=');
|
||||
fx_value_to_string(value_v, tmp, NULL);
|
||||
envp[i++] = fx_stringstream_steal(tmp);
|
||||
}
|
||||
|
||||
fx_iterator_unref(it);
|
||||
fx_string_unref(tmp);
|
||||
}
|
||||
|
||||
execve(fx_string_get_cstr(proc->proc_exec_path),
|
||||
(char *const *)argv,
|
||||
(char *const *)envp);
|
||||
exit(127);
|
||||
|
||||
cleanup:
|
||||
fx_iostream_unref(in_r);
|
||||
fx_iostream_unref(in_w);
|
||||
fx_iostream_unref(out_r);
|
||||
fx_iostream_unref(out_w);
|
||||
fx_iostream_unref(err_r);
|
||||
fx_iostream_unref(err_w);
|
||||
return status;
|
||||
}
|
||||
|
||||
static fx_status process_wait(struct fx_process_p *proc, int *out_result)
|
||||
{
|
||||
if (proc->proc_id == 0) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
int status = 0;
|
||||
|
||||
do {
|
||||
int err = waitpid(proc->proc_id, &status, WUNTRACED);
|
||||
if (err != 0) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
} while (!WIFEXITED(status));
|
||||
|
||||
proc->proc_id = 0;
|
||||
*out_result = WEXITSTATUS(status);
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static fx_status process_kill(struct fx_process_p *proc)
|
||||
{
|
||||
if (proc->proc_id == 0) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
int err = kill(proc->proc_id, SIGTERM);
|
||||
if (err != 0) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static const fx_hashtable *process_get_environment(
|
||||
const struct fx_process_p *proc)
|
||||
{
|
||||
return proc->proc_environment;
|
||||
}
|
||||
|
||||
static fx_stream *process_get_stdin(struct fx_process_p *proc)
|
||||
{
|
||||
return proc->proc_stdin;
|
||||
}
|
||||
|
||||
static fx_stream *process_get_stdout(struct fx_process_p *proc)
|
||||
{
|
||||
return proc->proc_stdout;
|
||||
}
|
||||
|
||||
static fx_stream *process_get_stderr(struct fx_process_p *proc)
|
||||
{
|
||||
return proc->proc_stderr;
|
||||
}
|
||||
|
||||
static void process_close_stdin(struct fx_process_p *proc)
|
||||
{
|
||||
fx_iostream_unref(proc->proc_stdin);
|
||||
proc->proc_stdin = NULL;
|
||||
}
|
||||
|
||||
static void process_close_stdout(struct fx_process_p *proc)
|
||||
{
|
||||
fx_iostream_unref(proc->proc_stdout);
|
||||
proc->proc_stdout = NULL;
|
||||
}
|
||||
|
||||
static void process_close_stderr(struct fx_process_p *proc)
|
||||
{
|
||||
fx_iostream_unref(proc->proc_stderr);
|
||||
proc->proc_stderr = NULL;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_process *fx_process_create(const fx_process_start_info *info)
|
||||
{
|
||||
fx_process *out = fx_object_create(FX_DIAGNOSTICS_TYPE_PROCESS);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_process_p *proc
|
||||
= fx_object_get_private(out, FX_DIAGNOSTICS_TYPE_PROCESS);
|
||||
|
||||
proc->proc_exec_path = fx_string_create_from_cstr(info->proc_file_name);
|
||||
if (!proc->proc_exec_path) {
|
||||
fx_process_unref(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
proc->proc_args = fx_array_ref((fx_array *)info->proc_args);
|
||||
|
||||
proc->proc_environment
|
||||
= fx_hashtable_ref((fx_hashtable *)info->proc_environment);
|
||||
proc->proc_redirect_stdin = info->proc_redirect_stdin;
|
||||
proc->proc_redirect_stdout = info->proc_redirect_stdout;
|
||||
proc->proc_redirect_stderr = info->proc_redirect_stderr;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
fx_process *fx_process_get_self(void)
|
||||
{
|
||||
if (self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
self = fx_object_create(FX_DIAGNOSTICS_TYPE_PROCESS);
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_process_p *proc
|
||||
= fx_object_get_private(self, FX_DIAGNOSTICS_TYPE_PROCESS);
|
||||
|
||||
proc->proc_id = getpid();
|
||||
fx_hashtable *env = fx_hashtable_create();
|
||||
|
||||
for (size_t i = 0; environ[i]; i++) {
|
||||
char *envstr = fx_strdup(environ[i]);
|
||||
|
||||
const char *name = envstr;
|
||||
char *sep = strchr(name, '=');
|
||||
const char *value = NULL;
|
||||
if (sep) {
|
||||
*sep = '\0';
|
||||
value = sep + 1;
|
||||
}
|
||||
|
||||
fx_string *name_str = fx_string_create_from_cstr(name);
|
||||
fx_string *value_str = fx_string_create();
|
||||
if (value) {
|
||||
fx_string_append_cstr(value_str, value);
|
||||
}
|
||||
|
||||
fx_hashtable_put(
|
||||
env,
|
||||
&FX_VALUE_OBJECT(name_str),
|
||||
&FX_VALUE_OBJECT(value_str));
|
||||
|
||||
fx_string_unref(name_str);
|
||||
fx_string_unref(value_str);
|
||||
free(envstr);
|
||||
}
|
||||
|
||||
proc->proc_environment = env;
|
||||
|
||||
fx_register_global(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
fx_status fx_process_start(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_start,
|
||||
proc);
|
||||
}
|
||||
|
||||
fx_status fx_process_wait(fx_process *proc, int *out_result)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_wait,
|
||||
proc,
|
||||
out_result);
|
||||
}
|
||||
|
||||
fx_status fx_process_kill(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_kill,
|
||||
proc);
|
||||
}
|
||||
|
||||
const fx_hashtable *fx_process_get_environment(const fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_get_environment,
|
||||
proc);
|
||||
}
|
||||
|
||||
fx_stream *fx_process_get_stdin(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_get_stdin,
|
||||
proc);
|
||||
}
|
||||
|
||||
fx_stream *fx_process_get_stdout(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_get_stdout,
|
||||
proc);
|
||||
}
|
||||
|
||||
fx_stream *fx_process_get_stderr(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_get_stderr,
|
||||
proc);
|
||||
}
|
||||
|
||||
void fx_process_close_stdin(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_V0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_close_stdin,
|
||||
proc);
|
||||
}
|
||||
|
||||
void fx_process_close_stdout(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_V0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_close_stdout,
|
||||
proc);
|
||||
}
|
||||
|
||||
void fx_process_close_stderr(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_V0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_close_stderr,
|
||||
proc);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void process_init(fx_object *obj, void *priv)
|
||||
{
|
||||
}
|
||||
|
||||
static void process_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_process_p *proc = priv;
|
||||
fx_array_unref(proc->proc_args);
|
||||
fx_iostream_unref(proc->proc_stdin);
|
||||
fx_iostream_unref(proc->proc_stdout);
|
||||
fx_iostream_unref(proc->proc_stderr);
|
||||
fx_string_unref(proc->proc_exec_path);
|
||||
fx_hashtable_unref(proc->proc_environment);
|
||||
}
|
||||
|
||||
/*** ITERATOR DEFINITION ******************************************************/
|
||||
|
||||
static enum fx_status process_iterator_move_next(const fx_iterator *obj)
|
||||
{
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
static const fx_value *process_iterator_get_value(const fx_iterator *obj)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_process)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_END(fx_process)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_process)
|
||||
FX_TYPE_ID(0x7334594f, 0xa1c3, 0x4715, 0xab69, 0x68a709e1b64b);
|
||||
FX_TYPE_NAME("fx.diagnostics.process");
|
||||
FX_TYPE_CLASS(fx_process_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_process_p);
|
||||
FX_TYPE_INSTANCE_INIT(process_init);
|
||||
FX_TYPE_INSTANCE_FINI(process_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_process)
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_process_iterator)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = process_iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = process_iterator_get_value;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_END(fx_process_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_process_iterator)
|
||||
FX_TYPE_ID(0x67eb13b6, 0x25d1, 0x424a, 0xb136, 0x871a07829089);
|
||||
FX_TYPE_NAME("fx.diagnostics.process.iterator");
|
||||
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
|
||||
FX_TYPE_CLASS(fx_process_iterator_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_process_iterator_p);
|
||||
FX_TYPE_DEFINITION_END(fx_process_iterator)
|
||||
@@ -1,491 +0,0 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <fx/collections/array.h>
|
||||
#include <fx/diagnostics/process.h>
|
||||
#include <fx/global.h>
|
||||
#include <fx/io/pipe.h>
|
||||
#include <fx/io/stream.h>
|
||||
#include <fx/iterator.h>
|
||||
#include <fx/macros.h>
|
||||
#include <fx/string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static fx_process *self = NULL;
|
||||
|
||||
extern const char **environ;
|
||||
|
||||
FX_API fx_type_id fx_process_iterator_get_type();
|
||||
|
||||
FX_DECLARE_TYPE(fx_process_iterator);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_process_iterator)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_process_iterator)
|
||||
|
||||
struct fx_process_p {
|
||||
fx_string *proc_exec_path;
|
||||
fx_array *proc_args;
|
||||
bool proc_redirect_stdin, proc_redirect_stdout, proc_redirect_stderr;
|
||||
fx_stream *proc_stdin, *proc_stdout, *proc_stderr;
|
||||
pid_t proc_id;
|
||||
fx_hashtable *proc_environment;
|
||||
};
|
||||
|
||||
struct fx_process_iterator_p {
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static fx_status process_start(struct fx_process_p *proc)
|
||||
{
|
||||
fx_iostream *in_r = NULL, *in_w = NULL;
|
||||
fx_iostream *out_r = NULL, *out_w = NULL;
|
||||
fx_iostream *err_r = NULL, *err_w = NULL;
|
||||
fx_status status = FX_SUCCESS;
|
||||
|
||||
if (proc->proc_redirect_stdin) {
|
||||
status = fx_pipe_create(&in_r, &in_w);
|
||||
if (!FX_OK(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (proc->proc_redirect_stdout) {
|
||||
status = fx_pipe_create(&out_r, &out_w);
|
||||
if (!FX_OK(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (proc->proc_redirect_stderr) {
|
||||
status = fx_pipe_create(&err_r, &err_w);
|
||||
if (!FX_OK(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
status = FX_ERR_INVALID_ARGUMENT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (pid > 0) {
|
||||
proc->proc_id = pid;
|
||||
proc->proc_stdin = fx_iostream_ref(in_w);
|
||||
proc->proc_stdout = fx_iostream_ref(out_r);
|
||||
proc->proc_stderr = fx_iostream_ref(err_r);
|
||||
status = FX_SUCCESS;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
int fd = -1;
|
||||
if (proc->proc_redirect_stdin) {
|
||||
fx_iostream_unref(in_w);
|
||||
fd = fx_iostream_steal_os_handle(in_r);
|
||||
int err = dup2(fd, 0);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (proc->proc_redirect_stdout) {
|
||||
fx_iostream_unref(out_r);
|
||||
fd = fx_iostream_steal_os_handle(out_w);
|
||||
dup2(fd, 1);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (proc->proc_redirect_stderr) {
|
||||
fx_iostream_unref(err_r);
|
||||
fd = fx_iostream_steal_os_handle(err_w);
|
||||
dup2(fd, 2);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
const char **argv = NULL;
|
||||
const char **envp = NULL;
|
||||
const char *default_argv[] = {
|
||||
fx_string_get_cstr(proc->proc_exec_path),
|
||||
NULL,
|
||||
};
|
||||
|
||||
size_t argc = 0;
|
||||
size_t envc = 0;
|
||||
|
||||
if (proc->proc_args) {
|
||||
argc = fx_array_get_size(proc->proc_args);
|
||||
}
|
||||
|
||||
if (proc->proc_environment) {
|
||||
envc = fx_hashtable_get_count(proc->proc_environment);
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
argv = calloc(argc + 1, sizeof(char *));
|
||||
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
const fx_value *arg_value
|
||||
= fx_array_get_ref(proc->proc_args, i);
|
||||
fx_value_get_cstr(arg_value, &argv[i]);
|
||||
}
|
||||
} else {
|
||||
argv = default_argv;
|
||||
}
|
||||
|
||||
if (envc) {
|
||||
envp = calloc(envc + 1, sizeof(char *));
|
||||
size_t i = 0;
|
||||
fx_stringstream *tmp = fx_stringstream_create();
|
||||
const fx_iterator *it
|
||||
= fx_iterator_begin(proc->proc_environment);
|
||||
fx_foreach(v, it)
|
||||
{
|
||||
fx_hashtable_item *item = NULL;
|
||||
fx_value_get_object(v, &item);
|
||||
const fx_value *name_v
|
||||
= fx_hashtable_item_get_key(item);
|
||||
const fx_value *value_v
|
||||
= fx_hashtable_item_get_value(item);
|
||||
|
||||
fx_value_to_string(name_v, tmp, NULL);
|
||||
fx_stream_write_char(tmp, '=');
|
||||
fx_value_to_string(value_v, tmp, NULL);
|
||||
envp[i++] = fx_stringstream_steal(tmp);
|
||||
}
|
||||
|
||||
fx_iterator_unref(it);
|
||||
fx_string_unref(tmp);
|
||||
}
|
||||
|
||||
execve(fx_string_get_cstr(proc->proc_exec_path),
|
||||
(char *const *)argv,
|
||||
(char *const *)envp);
|
||||
exit(127);
|
||||
|
||||
cleanup:
|
||||
fx_iostream_unref(in_r);
|
||||
fx_iostream_unref(in_w);
|
||||
fx_iostream_unref(out_r);
|
||||
fx_iostream_unref(out_w);
|
||||
fx_iostream_unref(err_r);
|
||||
fx_iostream_unref(err_w);
|
||||
return status;
|
||||
}
|
||||
|
||||
static fx_status process_wait(struct fx_process_p *proc, int *out_result)
|
||||
{
|
||||
if (proc->proc_id == 0) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
int status = 0;
|
||||
|
||||
do {
|
||||
int err = waitpid(proc->proc_id, &status, WUNTRACED);
|
||||
if (err != 0) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
} while (!WIFEXITED(status));
|
||||
|
||||
proc->proc_id = 0;
|
||||
*out_result = WEXITSTATUS(status);
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static fx_status process_kill(struct fx_process_p *proc)
|
||||
{
|
||||
if (proc->proc_id == 0) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
int err = kill(proc->proc_id, SIGTERM);
|
||||
if (err != 0) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static const fx_hashtable *process_get_environment(
|
||||
const struct fx_process_p *proc)
|
||||
{
|
||||
return proc->proc_environment;
|
||||
}
|
||||
|
||||
static fx_stream *process_get_stdin(struct fx_process_p *proc)
|
||||
{
|
||||
return proc->proc_stdin;
|
||||
}
|
||||
|
||||
static fx_stream *process_get_stdout(struct fx_process_p *proc)
|
||||
{
|
||||
return proc->proc_stdout;
|
||||
}
|
||||
|
||||
static fx_stream *process_get_stderr(struct fx_process_p *proc)
|
||||
{
|
||||
return proc->proc_stderr;
|
||||
}
|
||||
|
||||
static void process_close_stdin(struct fx_process_p *proc)
|
||||
{
|
||||
fx_iostream_unref(proc->proc_stdin);
|
||||
proc->proc_stdin = NULL;
|
||||
}
|
||||
|
||||
static void process_close_stdout(struct fx_process_p *proc)
|
||||
{
|
||||
fx_iostream_unref(proc->proc_stdout);
|
||||
proc->proc_stdout = NULL;
|
||||
}
|
||||
|
||||
static void process_close_stderr(struct fx_process_p *proc)
|
||||
{
|
||||
fx_iostream_unref(proc->proc_stderr);
|
||||
proc->proc_stderr = NULL;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_process *fx_process_create(const fx_process_start_info *info)
|
||||
{
|
||||
fx_process *out = fx_object_create(FX_DIAGNOSTICS_TYPE_PROCESS);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_process_p *proc
|
||||
= fx_object_get_private(out, FX_DIAGNOSTICS_TYPE_PROCESS);
|
||||
|
||||
proc->proc_exec_path = fx_string_create_from_cstr(info->proc_file_name);
|
||||
if (!proc->proc_exec_path) {
|
||||
fx_process_unref(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (info->proc_args_count > 0) {
|
||||
proc->proc_args = fx_array_create();
|
||||
if (!proc->proc_args) {
|
||||
fx_process_unref(out);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < info->proc_args_count; i++) {
|
||||
fx_string *arg = fx_string_create_from_cstr(info->proc_args[i]);
|
||||
if (!arg) {
|
||||
fx_process_unref(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fx_array_push_back(proc->proc_args, FX_VALUE_OBJECT(arg));
|
||||
fx_string_unref(arg);
|
||||
}
|
||||
|
||||
proc->proc_environment
|
||||
= fx_hashtable_ref((fx_hashtable *)info->proc_environment);
|
||||
proc->proc_redirect_stdin = info->proc_redirect_stdin;
|
||||
proc->proc_redirect_stdout = info->proc_redirect_stdout;
|
||||
proc->proc_redirect_stderr = info->proc_redirect_stderr;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
fx_process *fx_process_get_self(void)
|
||||
{
|
||||
if (self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
self = fx_object_create(FX_DIAGNOSTICS_TYPE_PROCESS);
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_process_p *proc
|
||||
= fx_object_get_private(self, FX_DIAGNOSTICS_TYPE_PROCESS);
|
||||
|
||||
proc->proc_id = getpid();
|
||||
fx_hashtable *env = fx_hashtable_create();
|
||||
|
||||
for (size_t i = 0; environ[i]; i++) {
|
||||
char *envstr = fx_strdup(environ[i]);
|
||||
|
||||
const char *name = envstr;
|
||||
char *sep = strchr(name, '=');
|
||||
const char *value = NULL;
|
||||
if (sep) {
|
||||
*sep = '\0';
|
||||
value = sep + 1;
|
||||
}
|
||||
|
||||
fx_string *name_str = fx_string_create_from_cstr(name);
|
||||
fx_string *value_str = fx_string_create();
|
||||
if (value) {
|
||||
fx_string_append_cstr(value_str, value);
|
||||
}
|
||||
|
||||
fx_hashtable_put(
|
||||
env,
|
||||
&FX_VALUE_OBJECT(name_str),
|
||||
&FX_VALUE_OBJECT(value_str));
|
||||
|
||||
fx_string_unref(name_str);
|
||||
fx_string_unref(value_str);
|
||||
free(envstr);
|
||||
}
|
||||
|
||||
proc->proc_environment = env;
|
||||
|
||||
fx_register_global(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
fx_status fx_process_start(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_start,
|
||||
proc);
|
||||
}
|
||||
|
||||
fx_status fx_process_wait(fx_process *proc, int *out_result)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_wait,
|
||||
proc,
|
||||
out_result);
|
||||
}
|
||||
|
||||
fx_status fx_process_kill(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_kill,
|
||||
proc);
|
||||
}
|
||||
|
||||
const fx_hashtable *fx_process_get_environment(const fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_get_environment,
|
||||
proc);
|
||||
}
|
||||
|
||||
fx_stream *fx_process_get_stdin(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_get_stdin,
|
||||
proc);
|
||||
}
|
||||
|
||||
fx_stream *fx_process_get_stdout(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_get_stdout,
|
||||
proc);
|
||||
}
|
||||
|
||||
fx_stream *fx_process_get_stderr(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_get_stderr,
|
||||
proc);
|
||||
}
|
||||
|
||||
void fx_process_close_stdin(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_V0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_close_stdin,
|
||||
proc);
|
||||
}
|
||||
|
||||
void fx_process_close_stdout(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_V0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_close_stdout,
|
||||
proc);
|
||||
}
|
||||
|
||||
void fx_process_close_stderr(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_V0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_close_stderr,
|
||||
proc);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void process_init(fx_object *obj, void *priv)
|
||||
{
|
||||
}
|
||||
|
||||
static void process_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_process_p *proc = priv;
|
||||
fx_array_unref(proc->proc_args);
|
||||
fx_iostream_unref(proc->proc_stdin);
|
||||
fx_iostream_unref(proc->proc_stdout);
|
||||
fx_iostream_unref(proc->proc_stderr);
|
||||
fx_string_unref(proc->proc_exec_path);
|
||||
fx_hashtable_unref(proc->proc_environment);
|
||||
}
|
||||
|
||||
/*** ITERATOR DEFINITION
|
||||
* ******************************************************/
|
||||
|
||||
static enum fx_status process_iterator_move_next(const fx_iterator *obj)
|
||||
{
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
static const fx_value *process_iterator_get_value(const fx_iterator *obj)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION
|
||||
* *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_process)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_END(fx_process)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_process)
|
||||
FX_TYPE_ID(0x7334594f, 0xa1c3, 0x4715, 0xab69, 0x68a709e1b64b);
|
||||
FX_TYPE_NAME("fx.diagnostics.process");
|
||||
FX_TYPE_CLASS(fx_process_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_process_p);
|
||||
FX_TYPE_INSTANCE_INIT(process_init);
|
||||
FX_TYPE_INSTANCE_FINI(process_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_process)
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_process_iterator)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = process_iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = process_iterator_get_value;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_END(fx_process_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_process_iterator)
|
||||
FX_TYPE_ID(0x67eb13b6, 0x25d1, 0x424a, 0xb136, 0x871a07829089);
|
||||
FX_TYPE_NAME("fx.diagnostics.process.iterator");
|
||||
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
|
||||
FX_TYPE_CLASS(fx_process_iterator_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_process_iterator_p);
|
||||
FX_TYPE_DEFINITION_END(fx_process_iterator)
|
||||
@@ -1,65 +0,0 @@
|
||||
#include <fx/diagnostics/process.h>
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *exec = argv[1];
|
||||
const char *msg = argv[2];
|
||||
|
||||
const fx_value arg_values[] = {
|
||||
FX_CSTR("hello"),
|
||||
FX_CSTR("world"),
|
||||
};
|
||||
fx_array *args = fx_array_create_with_values(
|
||||
arg_values,
|
||||
sizeof arg_values / sizeof arg_values[0]);
|
||||
|
||||
fx_process *self = fx_process_get_self();
|
||||
const fx_hashtable *env = fx_process_get_environment(self);
|
||||
|
||||
fx_process_start_info info = {
|
||||
.proc_args = args,
|
||||
.proc_redirect_stdout = true,
|
||||
.proc_redirect_stdin = true,
|
||||
.proc_file_name = exec,
|
||||
.proc_environment = env,
|
||||
};
|
||||
|
||||
fx_process *process = fx_process_create(&info);
|
||||
if (!process) {
|
||||
fprintf(stderr, "Process creation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fx_status status = fx_process_start(process);
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr,
|
||||
"Process creation failed: %s\n",
|
||||
fx_status_description(status));
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("process stdin: %s\n", msg);
|
||||
|
||||
fx_stream *in = fx_process_get_stdin(process);
|
||||
fx_stream_write_cstr(in, msg, NULL);
|
||||
fx_stream_write_char(in, '\n');
|
||||
fx_process_close_stdin(process);
|
||||
|
||||
fx_stream *out = fx_process_get_stdout(process);
|
||||
printf("process stdout:\n");
|
||||
printf("---------------------\n");
|
||||
|
||||
while (FX_OK(fx_stream_read_line_s(out, fx_stdout))) { }
|
||||
|
||||
printf("---------------------\n");
|
||||
|
||||
int result;
|
||||
fx_process_wait(process, &result);
|
||||
fx_process_unref(process);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -45,12 +45,12 @@ typedef struct fx_directory_entry {
|
||||
fx_file_info info;
|
||||
} fx_directory_entry;
|
||||
|
||||
FX_API fx_type_id fx_directory_get_type(void);
|
||||
FX_API fx_type_id fx_directory_iterator_get_type(void);
|
||||
FX_API fx_type fx_directory_get_type(void);
|
||||
FX_API fx_type fx_directory_iterator_get_type(void);
|
||||
|
||||
FX_API fx_result fx_directory_open(
|
||||
fx_directory *root,
|
||||
fx_value path,
|
||||
const fx_path *path,
|
||||
fx_directory_open_flags flags,
|
||||
fx_directory **out);
|
||||
FX_API fx_result fx_directory_open_temp(fx_directory **out);
|
||||
@@ -60,17 +60,22 @@ FX_API const char *fx_directory_get_path_cstr(const fx_directory *dir);
|
||||
FX_API const char *fx_directory_get_rel_path_cstr(const fx_directory *dir);
|
||||
FX_API fx_result fx_directory_delete(fx_directory *dir);
|
||||
|
||||
FX_API bool fx_directory_path_exists(const fx_directory *root, fx_value path);
|
||||
FX_API bool fx_directory_path_is_file(const fx_directory *root, fx_value path);
|
||||
FX_API bool fx_directory_path_exists(
|
||||
const fx_directory *root,
|
||||
const fx_path *path);
|
||||
FX_API bool fx_directory_path_is_file(
|
||||
const fx_directory *root,
|
||||
const fx_path *path);
|
||||
FX_API bool fx_directory_path_is_directory(
|
||||
const fx_directory *root,
|
||||
fx_value path);
|
||||
const fx_path *path);
|
||||
FX_API fx_result fx_directory_path_stat(
|
||||
const fx_directory *root,
|
||||
fx_value path,
|
||||
const fx_path *path,
|
||||
struct fx_file_info *out);
|
||||
FX_API fx_result
|
||||
fx_directory_path_unlink(const fx_directory *root, fx_value path);
|
||||
FX_API fx_result fx_directory_path_unlink(
|
||||
const fx_directory *root,
|
||||
const fx_path *path);
|
||||
|
||||
FX_API fx_iterator *fx_directory_begin(
|
||||
fx_directory *dir,
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <fx/macros.h>
|
||||
#include <fx/misc.h>
|
||||
#include <fx/stream.h>
|
||||
#include <fx/value.h>
|
||||
|
||||
FX_DECLS_BEGIN;
|
||||
|
||||
@@ -52,11 +51,11 @@ typedef struct fx_file_info {
|
||||
size_t length;
|
||||
} fx_file_info;
|
||||
|
||||
FX_API fx_type_id fx_file_get_type(void);
|
||||
FX_API fx_type fx_file_get_type(void);
|
||||
|
||||
FX_API fx_result fx_file_open(
|
||||
FX_TYPE_FWDREF(fx_directory) * root,
|
||||
fx_value path,
|
||||
const FX_TYPE_FWDREF(fx_path) * path,
|
||||
fx_file_mode mode,
|
||||
fx_file **out);
|
||||
FX_API fx_result fx_file_open_temp(fx_file_mode mode, fx_file **out);
|
||||
|
||||
@@ -18,25 +18,18 @@ FX_TYPE_CLASS_DECLARATION_END(fx_path)
|
||||
|
||||
#define FX_RV_PATH(cstr) FX_RV(fx_path_create_from_cstr(cstr))
|
||||
|
||||
typedef enum fx_system_path {
|
||||
FX_PATH_ROOT = 0,
|
||||
FX_PATH_CWD,
|
||||
FX_PATH_HOME,
|
||||
FX_PATH_CONFIG,
|
||||
} fx_system_path;
|
||||
|
||||
struct fx_file_info;
|
||||
|
||||
FX_API fx_type_id fx_path_get_type(void);
|
||||
FX_API fx_type fx_path_get_type(void);
|
||||
|
||||
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_path, FX_TYPE_PATH);
|
||||
|
||||
FX_API fx_path *fx_path_create_root();
|
||||
FX_API fx_path *fx_path_create_cwd();
|
||||
FX_API fx_path *fx_path_create_from_cstr(const char *path);
|
||||
FX_API fx_path *fx_path_get_system(fx_system_path path_type);
|
||||
FX_API fx_path *fx_path_duplicate(const fx_path *path);
|
||||
|
||||
FX_API fx_path *fx_path_join_array(const fx_value *values[], size_t nr_values);
|
||||
FX_API fx_path *fx_path_join_list(size_t count, ...);
|
||||
FX_API fx_path *fx_path_join(const fx_path *paths[], size_t nr_paths);
|
||||
|
||||
FX_API fx_path *fx_path_make_absolute(const fx_path *in);
|
||||
FX_API fx_path *fx_path_make_relative(const fx_path *in);
|
||||
@@ -56,7 +49,7 @@ FX_API enum fx_status fx_path_get_filename(
|
||||
const fx_path *path,
|
||||
fx_string *out_name);
|
||||
|
||||
FX_API const char *fx_path_get_cstr(const fx_path *path);
|
||||
FX_API const char *fx_path_ptr(const fx_path *path);
|
||||
FX_API size_t fx_path_length(const fx_path *path);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef FX_IO_PIPE_H_
|
||||
#define FX_IO_PIPE_H_
|
||||
|
||||
#include <fx/io/stream.h>
|
||||
|
||||
FX_API fx_status fx_pipe_create(fx_iostream **reader, fx_iostream **writer);
|
||||
|
||||
#endif
|
||||
@@ -1,29 +0,0 @@
|
||||
#ifndef FX_IO_STREAM_H_
|
||||
#define FX_IO_STREAM_H_
|
||||
|
||||
#include <fx/int.h>
|
||||
#include <fx/macros.h>
|
||||
#include <fx/stream.h>
|
||||
|
||||
FX_DECLS_BEGIN;
|
||||
|
||||
#define FX_IO_TYPE_STREAM (fx_iostream_get_type())
|
||||
|
||||
FX_DECLARE_TYPE(fx_iostream);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_iostream)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_iostream)
|
||||
|
||||
FX_API fx_type_id fx_iostream_get_type(void);
|
||||
|
||||
FX_API fx_iostream *fx_iostream_create(
|
||||
fx_stream_mode mode,
|
||||
uptr os_handle,
|
||||
bool close_handle_on_release);
|
||||
|
||||
FX_API uptr fx_iostream_get_os_handle(const fx_iostream *stream);
|
||||
FX_API uptr fx_iostream_steal_os_handle(fx_iostream *stream);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,29 +0,0 @@
|
||||
#include "posix.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fx/io/stream.h>
|
||||
#include <unistd.h>
|
||||
|
||||
fx_status fx_pipe_create(fx_iostream **reader, fx_iostream **writer)
|
||||
{
|
||||
int fds[2];
|
||||
int err = pipe(fds);
|
||||
if (err != 0) {
|
||||
return fx_status_from_errno(errno, FX_ERR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
fx_iostream *r = fx_iostream_create(FX_STREAM_READ, fds[0], true);
|
||||
fx_iostream *w = fx_iostream_create(FX_STREAM_WRITE, fds[1], true);
|
||||
|
||||
if (!r || !w) {
|
||||
fx_iostream_unref(r);
|
||||
fx_iostream_unref(w);
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
*reader = r;
|
||||
*writer = w;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
#include "posix.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fx/io/stream.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct fx_iostream_p {
|
||||
int s_fd;
|
||||
bool s_fd_close_on_release;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static uptr iostream_get_os_handle(const struct fx_iostream_p *stream)
|
||||
{
|
||||
return stream->s_fd;
|
||||
}
|
||||
|
||||
static uptr iostream_steal_os_handle(struct fx_iostream_p *stream)
|
||||
{
|
||||
uptr out = stream->s_fd;
|
||||
stream->s_fd = -1;
|
||||
stream->s_fd_close_on_release = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_iostream *fx_iostream_create(
|
||||
fx_stream_mode mode,
|
||||
uptr os_handle,
|
||||
bool close_handle_on_release)
|
||||
{
|
||||
fx_iostream *s = fx_object_create(FX_IO_TYPE_STREAM);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM);
|
||||
struct fx_iostream_p *p = fx_object_get_private(s, FX_IO_TYPE_STREAM);
|
||||
|
||||
cfg->s_mode = mode | Z__FX_STREAM_STATIC;
|
||||
p->s_fd = (int)os_handle;
|
||||
p->s_fd_close_on_release = close_handle_on_release;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
uptr fx_iostream_get_os_handle(const fx_iostream *stream)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_IO_TYPE_STREAM,
|
||||
iostream_get_os_handle,
|
||||
stream);
|
||||
}
|
||||
|
||||
uptr fx_iostream_steal_os_handle(fx_iostream *stream)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_IO_TYPE_STREAM,
|
||||
iostream_steal_os_handle,
|
||||
stream);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void iostream_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_iostream_p *stream = priv;
|
||||
}
|
||||
|
||||
static void iostream_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_iostream_p *stream = priv;
|
||||
|
||||
if (stream->s_fd_close_on_release) {
|
||||
close(stream->s_fd);
|
||||
}
|
||||
}
|
||||
|
||||
enum fx_status stream_read(
|
||||
fx_stream *stream,
|
||||
void *buf,
|
||||
size_t count,
|
||||
size_t *nr_read)
|
||||
{
|
||||
struct fx_iostream_p *s
|
||||
= fx_object_get_private(stream, FX_IO_TYPE_STREAM);
|
||||
|
||||
long r = read(s->s_fd, buf, count);
|
||||
if (r < 0) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
*nr_read = r;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
enum fx_status stream_write(
|
||||
fx_stream *stream,
|
||||
const void *buf,
|
||||
size_t count,
|
||||
size_t *nr_written)
|
||||
{
|
||||
struct fx_iostream_p *s
|
||||
= fx_object_get_private(stream, FX_IO_TYPE_STREAM);
|
||||
|
||||
long w = write(s->s_fd, buf, count);
|
||||
if (w < 0) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
*nr_written = w;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_iostream)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_stream, FX_TYPE_STREAM)
|
||||
FX_INTERFACE_ENTRY(s_close) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_seek) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_tell) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_getc) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_read) = stream_read;
|
||||
FX_INTERFACE_ENTRY(s_write) = stream_write;
|
||||
FX_INTERFACE_ENTRY(s_reserve) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_stream, FX_TYPE_STREAM)
|
||||
FX_TYPE_CLASS_END(fx_iostream)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_iostream)
|
||||
FX_TYPE_ID(0xc0b1c3c9, 0xa9c6, 0x4910, 0x8786, 0x574b0696e7aa);
|
||||
FX_TYPE_NAME("fx.io.stream");
|
||||
FX_TYPE_EXTENDS(FX_TYPE_STREAM);
|
||||
FX_TYPE_CLASS(fx_iostream_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_iostream_p);
|
||||
FX_TYPE_INSTANCE_INIT(iostream_init);
|
||||
FX_TYPE_INSTANCE_FINI(iostream_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_iostream)
|
||||
@@ -1,5 +1,3 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include "misc.h"
|
||||
#include "posix.h"
|
||||
|
||||
@@ -37,7 +35,6 @@ struct fx_directory_iterator_p {
|
||||
fx_directory *root;
|
||||
|
||||
fx_directory_entry entry;
|
||||
fx_value entry_value;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
@@ -53,12 +50,12 @@ static const fx_path *directory_get_rel_path(const struct fx_directory_p *dir)
|
||||
|
||||
static const char *directory_get_path_cstr(const struct fx_directory_p *dir)
|
||||
{
|
||||
return fx_path_get_cstr(dir->d_path_abs);
|
||||
return fx_path_ptr(dir->d_path_abs);
|
||||
}
|
||||
|
||||
static const char *directory_get_rel_path_cstr(const struct fx_directory_p *dir)
|
||||
{
|
||||
return fx_path_get_cstr(dir->d_path_rel);
|
||||
return fx_path_ptr(dir->d_path_rel);
|
||||
}
|
||||
|
||||
static fx_result directory_delete(
|
||||
@@ -88,12 +85,14 @@ static fx_result directory_delete(
|
||||
|
||||
static bool directory_path_exists(
|
||||
const struct fx_directory_p *root,
|
||||
fx_value path)
|
||||
const fx_path *path)
|
||||
{
|
||||
fx_path *abs_path = fx_path_join_list(
|
||||
2,
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&path);
|
||||
const fx_path *parts[] = {
|
||||
root ? root->d_path_abs : NULL,
|
||||
path,
|
||||
};
|
||||
|
||||
fx_path *abs_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
if (!abs_path) {
|
||||
return false;
|
||||
}
|
||||
@@ -106,14 +105,14 @@ static bool directory_path_exists(
|
||||
|
||||
static bool directory_path_is_file(
|
||||
const struct fx_directory_p *root,
|
||||
fx_value path)
|
||||
const fx_path *path)
|
||||
{
|
||||
const fx_value *parts[] = {};
|
||||
const fx_path *parts[] = {
|
||||
root ? root->d_path_abs : NULL,
|
||||
path,
|
||||
};
|
||||
|
||||
fx_path *abs_path = fx_path_join_list(
|
||||
2,
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&path);
|
||||
fx_path *abs_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
if (!abs_path) {
|
||||
return false;
|
||||
}
|
||||
@@ -126,14 +125,14 @@ static bool directory_path_is_file(
|
||||
|
||||
static bool directory_path_is_directory(
|
||||
const struct fx_directory_p *root,
|
||||
fx_value path)
|
||||
const fx_path *path)
|
||||
{
|
||||
const fx_value *parts[] = {};
|
||||
const fx_path *parts[] = {
|
||||
root ? root->d_path_abs : NULL,
|
||||
path,
|
||||
};
|
||||
|
||||
fx_path *abs_path = fx_path_join_list(
|
||||
2,
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&path);
|
||||
fx_path *abs_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
if (!abs_path) {
|
||||
return false;
|
||||
}
|
||||
@@ -146,15 +145,15 @@ static bool directory_path_is_directory(
|
||||
|
||||
static fx_result directory_path_stat(
|
||||
const struct fx_directory_p *root,
|
||||
fx_value path,
|
||||
const fx_path *path,
|
||||
struct fx_file_info *out)
|
||||
{
|
||||
const fx_value *parts[] = {};
|
||||
const fx_path *parts[] = {
|
||||
root ? root->d_path_abs : NULL,
|
||||
path,
|
||||
};
|
||||
|
||||
fx_path *abs_path = fx_path_join_list(
|
||||
2,
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&path);
|
||||
fx_path *abs_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
if (!abs_path) {
|
||||
return FX_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
@@ -167,14 +166,14 @@ static fx_result directory_path_stat(
|
||||
|
||||
static fx_result directory_path_unlink(
|
||||
const struct fx_directory_p *root,
|
||||
fx_value path)
|
||||
const fx_path *path)
|
||||
{
|
||||
const fx_value *parts[] = {};
|
||||
const fx_path *parts[] = {
|
||||
root ? root->d_path_abs : NULL,
|
||||
path,
|
||||
};
|
||||
|
||||
fx_path *abs_path = fx_path_join_list(
|
||||
2,
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&path);
|
||||
fx_path *abs_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
if (!abs_path) {
|
||||
return FX_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
@@ -254,7 +253,7 @@ static fx_result create_directory_hierarchy(
|
||||
|
||||
static fx_result directory_open(
|
||||
struct fx_directory_p *root,
|
||||
fx_value path,
|
||||
const fx_path *path,
|
||||
fx_directory_open_flags flags,
|
||||
fx_directory **out)
|
||||
{
|
||||
@@ -262,10 +261,7 @@ static fx_result directory_open(
|
||||
|
||||
int root_fd = root ? root->d_fd : AT_FDCWD;
|
||||
|
||||
fx_stringstream *path_str = fx_stringstream_create();
|
||||
fx_value_to_string(&path, path_str, NULL);
|
||||
const char *path_cstr = fx_stringstream_get_cstr(path_str);
|
||||
|
||||
const char *path_cstr = fx_path_ptr(path);
|
||||
if (root) {
|
||||
while (*path_cstr == '/') {
|
||||
path_cstr++;
|
||||
@@ -299,18 +295,16 @@ static fx_result directory_open(
|
||||
= fx_object_get_private(dir, FX_TYPE_DIRECTORY);
|
||||
|
||||
if (!root) {
|
||||
cwd = fx_path_get_system(FX_PATH_CWD);
|
||||
cwd = fx_path_create_cwd();
|
||||
}
|
||||
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : cwd),
|
||||
&FX_CSTR(path_cstr),
|
||||
const fx_path *parts[] = {
|
||||
root ? root->d_path_abs : cwd,
|
||||
path,
|
||||
};
|
||||
|
||||
fx_path *new_path
|
||||
= fx_path_join_array(parts, sizeof parts / sizeof parts[0]);
|
||||
fx_path *new_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
if (!new_path) {
|
||||
fx_stringstream_unref(path_str);
|
||||
return FX_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
@@ -319,7 +313,7 @@ static fx_result directory_open(
|
||||
}
|
||||
|
||||
p->d_path_abs = new_path;
|
||||
p->d_path_rel = fx_path_create_from_cstr(path_cstr);
|
||||
p->d_path_rel = fx_path_duplicate(path);
|
||||
p->d_fd = fd;
|
||||
|
||||
if (flags & FX_DIRECTORY_OPEN_DELETE_ON_CLOSE) {
|
||||
@@ -327,7 +321,6 @@ static fx_result directory_open(
|
||||
}
|
||||
|
||||
*out = dir;
|
||||
fx_stringstream_unref(path_str);
|
||||
|
||||
return FX_RESULT_SUCCESS;
|
||||
}
|
||||
@@ -336,7 +329,7 @@ static fx_result directory_open(
|
||||
|
||||
fx_result fx_directory_open(
|
||||
fx_directory *root,
|
||||
fx_value path,
|
||||
const fx_path *path,
|
||||
fx_directory_open_flags flags,
|
||||
fx_directory **out)
|
||||
{
|
||||
@@ -357,17 +350,19 @@ fx_result fx_directory_open_temp(fx_directory **out)
|
||||
while (1) {
|
||||
z__fx_io_generate_tmp_filename(name, sizeof name);
|
||||
snprintf(path, sizeof path, "/tmp/%s", name);
|
||||
fx_path *rpath = fx_path_create_from_cstr(path);
|
||||
|
||||
fx_directory *dir = NULL;
|
||||
fx_result status = fx_directory_open(
|
||||
FX_DIRECTORY_ROOT,
|
||||
FX_CSTR(path),
|
||||
rpath,
|
||||
FX_DIRECTORY_OPEN_CREATE,
|
||||
&dir);
|
||||
struct fx_directory_p *p
|
||||
= fx_object_get_private(dir, FX_TYPE_DIRECTORY);
|
||||
|
||||
if (fx_error_get_status_code(status) == FX_ERR_NAME_EXISTS) {
|
||||
fx_path_unref(rpath);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -375,7 +370,9 @@ fx_result fx_directory_open_temp(fx_directory **out)
|
||||
p->d_flags |= DIRECTORY_DELETE_ON_CLOSE;
|
||||
}
|
||||
|
||||
*out = dir;
|
||||
fx_path_unlink(rpath);
|
||||
fx_path_unref(rpath);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
@@ -419,7 +416,7 @@ fx_result fx_directory_delete(fx_directory *dir)
|
||||
return FX_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
bool fx_directory_path_exists(const fx_directory *root, fx_value path)
|
||||
bool fx_directory_path_exists(const fx_directory *root, const fx_path *path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_DIRECTORY,
|
||||
@@ -428,7 +425,7 @@ bool fx_directory_path_exists(const fx_directory *root, fx_value path)
|
||||
path);
|
||||
}
|
||||
|
||||
bool fx_directory_path_is_file(const fx_directory *root, fx_value path)
|
||||
bool fx_directory_path_is_file(const fx_directory *root, const fx_path *path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_DIRECTORY,
|
||||
@@ -437,7 +434,9 @@ bool fx_directory_path_is_file(const fx_directory *root, fx_value path)
|
||||
path);
|
||||
}
|
||||
|
||||
bool fx_directory_path_is_directory(const fx_directory *root, fx_value path)
|
||||
bool fx_directory_path_is_directory(
|
||||
const fx_directory *root,
|
||||
const fx_path *path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_DIRECTORY,
|
||||
@@ -448,7 +447,7 @@ bool fx_directory_path_is_directory(const fx_directory *root, fx_value path)
|
||||
|
||||
fx_result fx_directory_path_stat(
|
||||
const fx_directory *root,
|
||||
fx_value path,
|
||||
const fx_path *path,
|
||||
struct fx_file_info *out)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
@@ -459,7 +458,9 @@ fx_result fx_directory_path_stat(
|
||||
out);
|
||||
}
|
||||
|
||||
fx_result fx_directory_path_unlink(const fx_directory *root, fx_value path)
|
||||
fx_result fx_directory_path_unlink(
|
||||
const fx_directory *root,
|
||||
const fx_path *path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_DIRECTORY,
|
||||
@@ -507,8 +508,6 @@ static void update_iterator_data(struct fx_directory_iterator_p *it)
|
||||
fx_path *path = fx_path_create_from_cstr(
|
||||
ent->fts_path + fx_path_length(it->_p->d_path_abs) + 1);
|
||||
|
||||
fx_value_unset(&it->entry_value);
|
||||
it->entry_value = FX_POINTER(&it->entry);
|
||||
it->entry.filename = ent->fts_name;
|
||||
it->entry.filepath = path;
|
||||
|
||||
@@ -566,7 +565,7 @@ fx_iterator *fx_directory_begin(
|
||||
int fts_flags = FTS_COMFOLLOW | FTS_NOCHDIR;
|
||||
|
||||
const char *path_list[] = {
|
||||
fx_path_get_cstr(it->_p->d_path_abs),
|
||||
fx_path_ptr(it->_p->d_path_abs),
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -615,7 +614,12 @@ fx_iterator *fx_directory_begin(
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static const fx_iterator *iterator_begin(const fx_object *obj)
|
||||
static fx_iterator *iterator_begin(fx_object *obj)
|
||||
{
|
||||
return fx_directory_begin(obj, FX_DIRECTORY_ITERATE_PARENT_FIRST);
|
||||
}
|
||||
|
||||
static const fx_iterator *iterator_cbegin(const fx_object *obj)
|
||||
{
|
||||
return fx_directory_begin(
|
||||
(fx_object *)obj,
|
||||
@@ -675,9 +679,8 @@ static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
{
|
||||
struct fx_directory_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DIRECTORY_ITERATOR);
|
||||
fx_result result = fx_directory_path_unlink(
|
||||
it->root,
|
||||
FX_VALUE_OBJECT(it->entry.filepath));
|
||||
fx_result result
|
||||
= fx_directory_path_unlink(it->root, it->entry.filepath);
|
||||
if (fx_result_is_error(result)) {
|
||||
enum fx_status status = fx_error_get_status_code(result);
|
||||
fx_error_discard(result);
|
||||
@@ -687,26 +690,35 @@ static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
return iterator_move_next(obj);
|
||||
}
|
||||
|
||||
static const fx_value *iterator_get_value(const fx_iterator *obj)
|
||||
static fx_iterator_value iterator_get_value(fx_iterator *obj)
|
||||
{
|
||||
struct fx_directory_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DIRECTORY_ITERATOR);
|
||||
|
||||
return &it->entry_value;
|
||||
return FX_ITERATOR_VALUE_PTR(&it->entry);
|
||||
}
|
||||
|
||||
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_directory_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DIRECTORY_ITERATOR);
|
||||
|
||||
return FX_ITERATOR_VALUE_CPTR(&it->entry);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- fx_directory DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_directory)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_directory)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_INTERFACE_ENTRY(it_begin) = iterator_begin;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_END(fx_directory)
|
||||
FX_INTERFACE_ENTRY(it_cbegin) = iterator_cbegin;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_directory)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_directory)
|
||||
FX_TYPE_ID(0x10d36546, 0x7f96, 0x464b, 0xbc4d, 0xe504b283fa45);
|
||||
@@ -718,17 +730,18 @@ FX_TYPE_DEFINITION_BEGIN(fx_directory)
|
||||
FX_TYPE_DEFINITION_END(fx_directory)
|
||||
|
||||
// ---- fx_directory_iterator DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_directory_iterator)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_directory_iterator)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_END(fx_directory_iterator)
|
||||
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_directory_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_directory_iterator)
|
||||
FX_TYPE_ID(0xc707fce6, 0xc895, 0x4925, 0x8700, 0xa60641dee0cc);
|
||||
@@ -1,5 +1,3 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include "misc.h"
|
||||
#include "posix.h"
|
||||
|
||||
@@ -86,13 +84,13 @@ static fx_result file_open_shadow(
|
||||
= fx_path_create_from_cstr(fx_string_get_cstr(filename));
|
||||
fx_string_unref(filename);
|
||||
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(dir),
|
||||
&FX_VALUE_OBJECT(shadow_filename),
|
||||
const fx_path *parts[] = {
|
||||
dir,
|
||||
shadow_filename,
|
||||
};
|
||||
|
||||
fx_path *shadow_filepath
|
||||
= fx_path_join_array(parts, sizeof parts / sizeof parts[0]);
|
||||
= fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
fx_path_unref(dir);
|
||||
fx_path_unref(shadow_filename);
|
||||
|
||||
@@ -103,7 +101,7 @@ static fx_result file_open_shadow(
|
||||
fx_file *shadow_file;
|
||||
fx_result status = fx_file_open(
|
||||
FX_DIRECTORY_ROOT,
|
||||
FX_VALUE_OBJECT(shadow_filepath),
|
||||
shadow_filepath,
|
||||
mode,
|
||||
&shadow_file);
|
||||
fx_path_unref(shadow_filepath);
|
||||
@@ -229,14 +227,12 @@ static enum fx_status file_swap_shadow(
|
||||
z__fx_io_generate_tmp_filename(tmp_name, sizeof tmp_name);
|
||||
fx_path *tmp_name_p = fx_path_create_from_cstr(tmp_name);
|
||||
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(dir_path),
|
||||
&FX_VALUE_OBJECT(tmp_name_p),
|
||||
const fx_path *parts[] = {
|
||||
dir_path,
|
||||
tmp_name_p,
|
||||
};
|
||||
|
||||
tmp_path = fx_path_join_array(
|
||||
parts,
|
||||
sizeof parts / sizeof parts[0]);
|
||||
tmp_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
|
||||
fx_path_unref(tmp_name_p);
|
||||
|
||||
@@ -252,15 +248,11 @@ static enum fx_status file_swap_shadow(
|
||||
|
||||
int err;
|
||||
|
||||
err = rename(fx_path_ptr(main_file->path), fx_path_ptr(tmp_path));
|
||||
err = rename(
|
||||
fx_path_get_cstr(main_file->path),
|
||||
fx_path_get_cstr(tmp_path));
|
||||
err = rename(
|
||||
fx_path_get_cstr(shadow_file->path),
|
||||
fx_path_get_cstr(main_file->path));
|
||||
err = rename(
|
||||
fx_path_get_cstr(tmp_path),
|
||||
fx_path_get_cstr(shadow_file->path));
|
||||
fx_path_ptr(shadow_file->path),
|
||||
fx_path_ptr(main_file->path));
|
||||
err = rename(fx_path_ptr(tmp_path), fx_path_ptr(shadow_file->path));
|
||||
|
||||
fx_path_unref(tmp_path);
|
||||
|
||||
@@ -414,10 +406,11 @@ static enum fx_status stream_tell(const fx_stream *stream, size_t *pos)
|
||||
|
||||
fx_result fx_file_open(
|
||||
fx_directory *root,
|
||||
fx_value path,
|
||||
const fx_path *path,
|
||||
enum fx_file_mode mode,
|
||||
fx_file **out)
|
||||
{
|
||||
const fx_path *file_path = path;
|
||||
unsigned int flags = fx_mode_to_unix_mode(mode);
|
||||
|
||||
if (flags == (unsigned int)-1) {
|
||||
@@ -429,12 +422,16 @@ fx_result fx_file_open(
|
||||
if (root) {
|
||||
root_path = fx_directory_get_path(root);
|
||||
} else {
|
||||
root_path = fx_path_get_system(FX_PATH_CWD);
|
||||
root_path = fx_path_create_cwd();
|
||||
free_root_path = true;
|
||||
}
|
||||
|
||||
fx_path *abs_path
|
||||
= fx_path_join_list(2, &FX_VALUE_OBJECT(root_path), &path);
|
||||
const fx_path *parts[] = {
|
||||
root_path,
|
||||
file_path,
|
||||
};
|
||||
|
||||
fx_path *abs_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
|
||||
if (free_root_path) {
|
||||
fx_path_unref((fx_path *)root_path);
|
||||
@@ -444,7 +441,7 @@ fx_result fx_file_open(
|
||||
return FX_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
int fd = open(fx_path_get_cstr(abs_path), flags, 0644);
|
||||
int fd = open(fx_path_ptr(abs_path), flags, 0644);
|
||||
if (fd == -1) {
|
||||
fx_path_unref(abs_path);
|
||||
return FX_RESULT_STATUS(
|
||||
@@ -495,7 +492,7 @@ fx_result fx_file_open_temp(enum fx_file_mode mode, fx_file **out)
|
||||
|
||||
fx_result status = fx_file_open(
|
||||
FX_DIRECTORY_ROOT,
|
||||
FX_VALUE_OBJECT(rpath),
|
||||
rpath,
|
||||
mode | FX_FILE_CREATE_ONLY,
|
||||
out);
|
||||
|
||||
@@ -621,20 +618,20 @@ static void file_fini(fx_object *obj, void *priv)
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_file)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_file)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_stream, FX_TYPE_STREAM)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_stream, FX_TYPE_STREAM)
|
||||
FX_INTERFACE_ENTRY(s_close) = stream_close;
|
||||
FX_INTERFACE_ENTRY(s_getc) = stream_getc;
|
||||
FX_INTERFACE_ENTRY(s_read) = stream_read;
|
||||
FX_INTERFACE_ENTRY(s_write) = stream_write;
|
||||
FX_INTERFACE_ENTRY(s_seek) = stream_seek;
|
||||
FX_INTERFACE_ENTRY(s_tell) = stream_tell;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_stream, FX_TYPE_STREAM)
|
||||
FX_TYPE_CLASS_END(fx_file)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_stream, FX_TYPE_STREAM)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_file)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_file)
|
||||
FX_TYPE_ID(0x495a73f6, 0xb8c3, 0x4e17, 0xb5f4, 0x6fc321f67c7b);
|
||||
@@ -91,22 +91,22 @@ static bool path_is_directory(const struct fx_path_p *path)
|
||||
return (info.attrib & FX_FILE_ATTRIB_DIRECTORY) != 0;
|
||||
}
|
||||
|
||||
static void append_path(struct fx_path_p *dest, const fx_string *src)
|
||||
static void append_path(struct fx_path_p *dest, const struct fx_path_p *src)
|
||||
{
|
||||
const char *src_cstr = fx_string_get_cstr(src);
|
||||
if (src_cstr[0] == '/') {
|
||||
if (path_is_absolute(src)) {
|
||||
fx_string_clear(dest->p_pathstr);
|
||||
fx_string_append_s(dest->p_pathstr, src);
|
||||
fx_string_append_s(dest->p_pathstr, src->p_pathstr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fx_string_get_size(dest->p_pathstr, FX_STRLEN_NORMAL) > 0
|
||||
&& fx_string_get_last_char(dest->p_pathstr) != '/'
|
||||
&& fx_string_get_first_char(src) != '/') {
|
||||
fx_string_append_c(dest->p_pathstr, '/');
|
||||
&& fx_string_get_first_char(src->p_pathstr) != '/') {
|
||||
char s[] = {'/', 0};
|
||||
fx_string_append_cstr(dest->p_pathstr, s);
|
||||
}
|
||||
|
||||
fx_string_append_s(dest->p_pathstr, src);
|
||||
fx_string_append_s(dest->p_pathstr, src->p_pathstr);
|
||||
}
|
||||
|
||||
static enum fx_status path_unlink(const struct fx_path_p *path)
|
||||
@@ -199,6 +199,33 @@ fx_path *fx_path_create_root()
|
||||
return path;
|
||||
}
|
||||
|
||||
fx_path *fx_path_create_cwd()
|
||||
{
|
||||
const long buf_len = 2048;
|
||||
char *buf = malloc(buf_len);
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!getcwd(buf, buf_len)) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fx_path *path = fx_path_create();
|
||||
if (!path) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_path_p *p = fx_object_get_private(path, FX_TYPE_PATH);
|
||||
|
||||
fx_string_append_cstr(p->p_pathstr, buf);
|
||||
free(buf);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
fx_path *fx_path_create_from_cstr(const char *cstr)
|
||||
{
|
||||
fx_path *path = fx_path_create();
|
||||
@@ -231,49 +258,6 @@ fx_path *fx_path_create_from_cstr(const char *cstr)
|
||||
return path;
|
||||
}
|
||||
|
||||
fx_path *fx_path_get_system(fx_system_path path_type)
|
||||
{
|
||||
char path_buf[4096];
|
||||
const char *path_value = NULL, *default_value = NULL;
|
||||
switch (path_type) {
|
||||
case FX_PATH_ROOT:
|
||||
path_value = "/";
|
||||
break;
|
||||
case FX_PATH_CWD:
|
||||
if (getcwd(path_buf, sizeof path_buf) == NULL) {
|
||||
path_value = path_buf;
|
||||
}
|
||||
break;
|
||||
case FX_PATH_HOME:
|
||||
path_value = getenv("HOME");
|
||||
default_value = "~";
|
||||
break;
|
||||
case FX_PATH_CONFIG: {
|
||||
const char *home = getenv("HOME");
|
||||
path_value = getenv("XDG_CONFIG_HOME");
|
||||
snprintf(
|
||||
path_buf,
|
||||
sizeof path_buf,
|
||||
"%s/.config",
|
||||
home ? home : "~");
|
||||
default_value = path_buf;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (path_value) {
|
||||
return fx_path_create_from_cstr(path_value);
|
||||
}
|
||||
|
||||
if (default_value) {
|
||||
return fx_path_create_from_cstr(default_value);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fx_path *fx_path_duplicate(const fx_path *path)
|
||||
{
|
||||
fx_path *new_path = fx_path_create();
|
||||
@@ -293,7 +277,7 @@ fx_path *fx_path_duplicate(const fx_path *path)
|
||||
return new_path;
|
||||
}
|
||||
|
||||
fx_path *fx_path_join_array(const fx_value *values[], size_t nr_values)
|
||||
fx_path *fx_path_join(const fx_path *paths[], size_t nr_paths)
|
||||
{
|
||||
fx_path *result = fx_path_create();
|
||||
if (!result) {
|
||||
@@ -303,53 +287,14 @@ fx_path *fx_path_join_array(const fx_value *values[], size_t nr_values)
|
||||
struct fx_path_p *result_p
|
||||
= fx_object_get_private(result, FX_TYPE_PATH);
|
||||
|
||||
fx_stringstream *tmp = fx_stringstream_create();
|
||||
fx_string *value_s = fx_string_create();
|
||||
for (size_t i = 0; i < nr_values; i++) {
|
||||
if (!values[i]) {
|
||||
continue;
|
||||
for (size_t i = 0; i < nr_paths; i++) {
|
||||
if (paths[i]) {
|
||||
struct fx_path_p *path_p
|
||||
= fx_object_get_private(paths[i], FX_TYPE_PATH);
|
||||
append_path(result_p, path_p);
|
||||
}
|
||||
}
|
||||
|
||||
fx_stringstream_reset(tmp);
|
||||
fx_value_to_string(values[i], tmp, NULL);
|
||||
|
||||
fx_string_clear(value_s);
|
||||
fx_string_append_cstr(value_s, fx_stringstream_get_cstr(tmp));
|
||||
append_path(result_p, value_s);
|
||||
}
|
||||
|
||||
fx_string_unref(value_s);
|
||||
fx_stringstream_unref(tmp);
|
||||
return result;
|
||||
}
|
||||
|
||||
fx_path *fx_path_join_list(size_t count, ...)
|
||||
{
|
||||
fx_path *result = fx_path_create();
|
||||
if (!result) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_path_p *result_p
|
||||
= fx_object_get_private(result, FX_TYPE_PATH);
|
||||
va_list arg;
|
||||
va_start(arg, count);
|
||||
|
||||
fx_stringstream *tmp = fx_stringstream_create();
|
||||
fx_string *value_s = fx_string_create();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const fx_value *value = va_arg(arg, const fx_value *);
|
||||
|
||||
fx_stringstream_reset(tmp);
|
||||
fx_value_to_string(value, tmp, NULL);
|
||||
|
||||
fx_string_clear(value_s);
|
||||
fx_string_append_cstr(value_s, fx_stringstream_get_cstr(tmp));
|
||||
append_path(result_p, value_s);
|
||||
}
|
||||
|
||||
fx_string_unref(value_s);
|
||||
fx_stringstream_unref(tmp);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -418,7 +363,7 @@ enum fx_status fx_path_get_filename(const fx_path *path, fx_string *out_name)
|
||||
out_name);
|
||||
}
|
||||
|
||||
const char *fx_path_get_cstr(const fx_path *path)
|
||||
const char *fx_path_ptr(const fx_path *path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_PATH, path_ptr, path);
|
||||
}
|
||||
@@ -447,27 +392,20 @@ void path_fini(fx_object *obj, void *priv)
|
||||
fx_string_unref(path->p_pathstr);
|
||||
}
|
||||
|
||||
static fx_status path_to_string(
|
||||
const fx_value *obj,
|
||||
fx_stream *out,
|
||||
const char *format)
|
||||
void path_to_string(const fx_object *obj, fx_stream *out)
|
||||
{
|
||||
struct fx_path_p *path
|
||||
= fx_object_get_private(obj->v_object, FX_TYPE_PATH);
|
||||
struct fx_path_p *path = fx_object_get_private(obj, FX_TYPE_PATH);
|
||||
|
||||
return fx_stream_write_cstr(
|
||||
out,
|
||||
fx_string_get_cstr(path->p_pathstr),
|
||||
NULL);
|
||||
fx_stream_write_cstr(out, fx_string_get_cstr(path->p_pathstr), NULL);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_path)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_path)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = path_to_string;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_END(fx_path)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_path)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_path)
|
||||
FX_TYPE_ID(0x56dc32eb, 0xea96, 0x46ed, 0x85d3, 0x760fa4ad61f4);
|
||||
+59
-53
@@ -37,7 +37,6 @@ struct fx_directory_iterator_p {
|
||||
fx_directory *root;
|
||||
|
||||
fx_directory_entry entry;
|
||||
fx_value entry_value;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
@@ -53,12 +52,12 @@ static const fx_path *directory_get_rel_path(const struct fx_directory_p *dir)
|
||||
|
||||
static const char *directory_get_path_cstr(const struct fx_directory_p *dir)
|
||||
{
|
||||
return fx_path_get_cstr(dir->d_path_abs);
|
||||
return fx_path_ptr(dir->d_path_abs);
|
||||
}
|
||||
|
||||
static const char *directory_get_rel_path_cstr(const struct fx_directory_p *dir)
|
||||
{
|
||||
return fx_path_get_cstr(dir->d_path_rel);
|
||||
return fx_path_ptr(dir->d_path_rel);
|
||||
}
|
||||
|
||||
static fx_result directory_delete(
|
||||
@@ -90,13 +89,12 @@ static bool directory_path_exists(
|
||||
const struct fx_directory_p *root,
|
||||
const fx_path *path)
|
||||
{
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&FX_VALUE_OBJECT(path),
|
||||
const fx_path *parts[] = {
|
||||
root ? root->d_path_abs : NULL,
|
||||
path,
|
||||
};
|
||||
|
||||
fx_path *abs_path
|
||||
= fx_path_join_array(parts, sizeof parts / sizeof parts[0]);
|
||||
fx_path *abs_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
if (!abs_path) {
|
||||
return false;
|
||||
}
|
||||
@@ -111,13 +109,12 @@ static bool directory_path_is_file(
|
||||
const struct fx_directory_p *root,
|
||||
const fx_path *path)
|
||||
{
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&FX_VALUE_OBJECT(path),
|
||||
const fx_path *parts[] = {
|
||||
root ? root->d_path_abs : NULL,
|
||||
path,
|
||||
};
|
||||
|
||||
fx_path *abs_path
|
||||
= fx_path_join_array(parts, sizeof parts / sizeof parts[0]);
|
||||
fx_path *abs_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
if (!abs_path) {
|
||||
return false;
|
||||
}
|
||||
@@ -132,13 +129,12 @@ static bool directory_path_is_directory(
|
||||
const struct fx_directory_p *root,
|
||||
const fx_path *path)
|
||||
{
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&FX_VALUE_OBJECT(path),
|
||||
const fx_path *parts[] = {
|
||||
root ? root->d_path_abs : NULL,
|
||||
path,
|
||||
};
|
||||
|
||||
fx_path *abs_path
|
||||
= fx_path_join_array(parts, sizeof parts / sizeof parts[0]);
|
||||
fx_path *abs_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
if (!abs_path) {
|
||||
return false;
|
||||
}
|
||||
@@ -154,13 +150,12 @@ static fx_result directory_path_stat(
|
||||
const fx_path *path,
|
||||
struct fx_file_info *out)
|
||||
{
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&FX_VALUE_OBJECT(path),
|
||||
const fx_path *parts[] = {
|
||||
root ? root->d_path_abs : NULL,
|
||||
path,
|
||||
};
|
||||
|
||||
fx_path *abs_path
|
||||
= fx_path_join_array(parts, sizeof parts / sizeof parts[0]);
|
||||
fx_path *abs_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
if (!abs_path) {
|
||||
return FX_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
@@ -175,13 +170,12 @@ static fx_result directory_path_unlink(
|
||||
const struct fx_directory_p *root,
|
||||
const fx_path *path)
|
||||
{
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&FX_VALUE_OBJECT(path),
|
||||
const fx_path *parts[] = {
|
||||
root ? root->d_path_abs : NULL,
|
||||
path,
|
||||
};
|
||||
|
||||
fx_path *abs_path
|
||||
= fx_path_join_array(parts, sizeof parts / sizeof parts[0]);
|
||||
fx_path *abs_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
if (!abs_path) {
|
||||
return FX_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
@@ -269,7 +263,7 @@ static fx_result directory_open(
|
||||
|
||||
int root_fd = root ? root->d_fd : AT_FDCWD;
|
||||
|
||||
const char *path_cstr = fx_path_get_cstr(path);
|
||||
const char *path_cstr = fx_path_ptr(path);
|
||||
if (root) {
|
||||
while (*path_cstr == '/') {
|
||||
path_cstr++;
|
||||
@@ -303,16 +297,15 @@ static fx_result directory_open(
|
||||
= fx_object_get_private(dir, FX_TYPE_DIRECTORY);
|
||||
|
||||
if (!root) {
|
||||
cwd = fx_path_get_system(FX_PATH_CWD);
|
||||
cwd = fx_path_create_cwd();
|
||||
}
|
||||
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : cwd),
|
||||
&FX_VALUE_OBJECT(path),
|
||||
const fx_path *parts[] = {
|
||||
root ? root->d_path_abs : cwd,
|
||||
path,
|
||||
};
|
||||
|
||||
fx_path *new_path
|
||||
= fx_path_join_array(parts, sizeof parts / sizeof parts[0]);
|
||||
fx_path *new_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
if (!new_path) {
|
||||
return FX_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
@@ -517,8 +510,6 @@ static void update_iterator_data(struct fx_directory_iterator_p *it)
|
||||
fx_path *path = fx_path_create_from_cstr(
|
||||
ent->fts_path + fx_path_length(it->_p->d_path_abs) + 1);
|
||||
|
||||
fx_value_unset(&it->entry_value);
|
||||
it->entry_value = FX_POINTER(&it->entry);
|
||||
it->entry.filename = ent->fts_name;
|
||||
it->entry.filepath = path;
|
||||
|
||||
@@ -576,7 +567,7 @@ fx_iterator *fx_directory_begin(
|
||||
int fts_flags = FTS_COMFOLLOW | FTS_NOCHDIR;
|
||||
|
||||
const char *path_list[] = {
|
||||
fx_path_get_cstr(it->_p->d_path_abs),
|
||||
fx_path_ptr(it->_p->d_path_abs),
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -625,7 +616,12 @@ fx_iterator *fx_directory_begin(
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static const fx_iterator *iterator_begin(const fx_object *obj)
|
||||
static fx_iterator *iterator_begin(fx_object *obj)
|
||||
{
|
||||
return fx_directory_begin(obj, FX_DIRECTORY_ITERATE_PARENT_FIRST);
|
||||
}
|
||||
|
||||
static const fx_iterator *iterator_cbegin(const fx_object *obj)
|
||||
{
|
||||
return fx_directory_begin(
|
||||
(fx_object *)obj,
|
||||
@@ -696,26 +692,35 @@ static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
return iterator_move_next(obj);
|
||||
}
|
||||
|
||||
static const fx_value *iterator_get_value(const fx_iterator *obj)
|
||||
static fx_iterator_value iterator_get_value(fx_iterator *obj)
|
||||
{
|
||||
struct fx_directory_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DIRECTORY_ITERATOR);
|
||||
|
||||
return &it->entry_value;
|
||||
return FX_ITERATOR_VALUE_PTR(&it->entry);
|
||||
}
|
||||
|
||||
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_directory_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DIRECTORY_ITERATOR);
|
||||
|
||||
return FX_ITERATOR_VALUE_CPTR(&it->entry);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- fx_directory DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_directory)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_directory)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_INTERFACE_ENTRY(it_begin) = iterator_begin;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_END(fx_directory)
|
||||
FX_INTERFACE_ENTRY(it_cbegin) = iterator_cbegin;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_directory)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_directory)
|
||||
FX_TYPE_ID(0x10d36546, 0x7f96, 0x464b, 0xbc4d, 0xe504b283fa45);
|
||||
@@ -727,17 +732,18 @@ FX_TYPE_DEFINITION_BEGIN(fx_directory)
|
||||
FX_TYPE_DEFINITION_END(fx_directory)
|
||||
|
||||
// ---- fx_directory_iterator DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_directory_iterator)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_directory_iterator)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_END(fx_directory_iterator)
|
||||
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_directory_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_directory_iterator)
|
||||
FX_TYPE_ID(0xc707fce6, 0xc895, 0x4925, 0x8700, 0xa60641dee0cc);
|
||||
|
||||
+24
-31
@@ -86,13 +86,13 @@ static fx_result file_open_shadow(
|
||||
= fx_path_create_from_cstr(fx_string_get_cstr(filename));
|
||||
fx_string_unref(filename);
|
||||
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(dir),
|
||||
&FX_VALUE_OBJECT(shadow_filename),
|
||||
const fx_path *parts[] = {
|
||||
dir,
|
||||
shadow_filename,
|
||||
};
|
||||
|
||||
fx_path *shadow_filepath
|
||||
= fx_path_join_array(parts, sizeof parts / sizeof parts[0]);
|
||||
= fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
fx_path_unref(dir);
|
||||
fx_path_unref(shadow_filename);
|
||||
|
||||
@@ -229,14 +229,12 @@ static enum fx_status file_swap_shadow(
|
||||
z__fx_io_generate_tmp_filename(tmp_name, sizeof tmp_name);
|
||||
fx_path *tmp_name_p = fx_path_create_from_cstr(tmp_name);
|
||||
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(dir_path),
|
||||
&FX_VALUE_OBJECT(tmp_name_p),
|
||||
const fx_path *parts[] = {
|
||||
dir_path,
|
||||
tmp_name_p,
|
||||
};
|
||||
|
||||
tmp_path = fx_path_join_array(
|
||||
parts,
|
||||
sizeof parts / sizeof parts[0]);
|
||||
tmp_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
|
||||
fx_path_unref(tmp_name_p);
|
||||
|
||||
@@ -252,15 +250,11 @@ static enum fx_status file_swap_shadow(
|
||||
|
||||
int err;
|
||||
|
||||
err = rename(fx_path_ptr(main_file->path), fx_path_ptr(tmp_path));
|
||||
err = rename(
|
||||
fx_path_get_cstr(main_file->path),
|
||||
fx_path_get_cstr(tmp_path));
|
||||
err = rename(
|
||||
fx_path_get_cstr(shadow_file->path),
|
||||
fx_path_get_cstr(main_file->path));
|
||||
err = rename(
|
||||
fx_path_get_cstr(tmp_path),
|
||||
fx_path_get_cstr(shadow_file->path));
|
||||
fx_path_ptr(shadow_file->path),
|
||||
fx_path_ptr(main_file->path));
|
||||
err = rename(fx_path_ptr(tmp_path), fx_path_ptr(shadow_file->path));
|
||||
|
||||
fx_path_unref(tmp_path);
|
||||
|
||||
@@ -430,17 +424,16 @@ fx_result fx_file_open(
|
||||
if (root) {
|
||||
root_path = fx_directory_get_path(root);
|
||||
} else {
|
||||
root_path = fx_path_get_system(FX_PATH_CWD);
|
||||
root_path = fx_path_create_cwd();
|
||||
free_root_path = true;
|
||||
}
|
||||
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(root_path),
|
||||
&FX_VALUE_OBJECT(file_path),
|
||||
const fx_path *parts[] = {
|
||||
root_path,
|
||||
file_path,
|
||||
};
|
||||
|
||||
fx_path *abs_path
|
||||
= fx_path_join_array(parts, sizeof parts / sizeof parts[0]);
|
||||
fx_path *abs_path = fx_path_join(parts, sizeof parts / sizeof parts[0]);
|
||||
|
||||
if (free_root_path) {
|
||||
fx_path_unref((fx_path *)root_path);
|
||||
@@ -450,7 +443,7 @@ fx_result fx_file_open(
|
||||
return FX_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
int fd = open(fx_path_get_cstr(abs_path), flags, 0644);
|
||||
int fd = open(fx_path_ptr(abs_path), flags, 0644);
|
||||
if (fd == -1) {
|
||||
fx_path_unref(abs_path);
|
||||
return FX_RESULT_STATUS(
|
||||
@@ -627,20 +620,20 @@ static void file_fini(fx_object *obj, void *priv)
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_file)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_file)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_stream, FX_TYPE_STREAM)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_stream, FX_TYPE_STREAM)
|
||||
FX_INTERFACE_ENTRY(s_close) = stream_close;
|
||||
FX_INTERFACE_ENTRY(s_getc) = stream_getc;
|
||||
FX_INTERFACE_ENTRY(s_read) = stream_read;
|
||||
FX_INTERFACE_ENTRY(s_write) = stream_write;
|
||||
FX_INTERFACE_ENTRY(s_seek) = stream_seek;
|
||||
FX_INTERFACE_ENTRY(s_tell) = stream_tell;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_stream, FX_TYPE_STREAM)
|
||||
FX_TYPE_CLASS_END(fx_file)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_stream, FX_TYPE_STREAM)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_file)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_file)
|
||||
FX_TYPE_ID(0x495a73f6, 0xb8c3, 0x4e17, 0xb5f4, 0x6fc321f67c7b);
|
||||
|
||||
+49
-111
@@ -91,22 +91,22 @@ static bool path_is_directory(const struct fx_path_p *path)
|
||||
return (info.attrib & FX_FILE_ATTRIB_DIRECTORY) != 0;
|
||||
}
|
||||
|
||||
static void append_path(struct fx_path_p *dest, const fx_string *src)
|
||||
static void append_path(struct fx_path_p *dest, const struct fx_path_p *src)
|
||||
{
|
||||
const char *src_cstr = fx_string_get_cstr(src);
|
||||
if (src_cstr[0] == '/') {
|
||||
if (path_is_absolute(src)) {
|
||||
fx_string_clear(dest->p_pathstr);
|
||||
fx_string_append_s(dest->p_pathstr, src);
|
||||
fx_string_append_s(dest->p_pathstr, src->p_pathstr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fx_string_get_size(dest->p_pathstr, FX_STRLEN_NORMAL) > 0
|
||||
&& fx_string_get_last_char(dest->p_pathstr) != '/'
|
||||
&& fx_string_get_first_char(src) != '/') {
|
||||
fx_string_append_c(dest->p_pathstr, '/');
|
||||
&& fx_string_get_first_char(src->p_pathstr) != '/') {
|
||||
char s[] = {'/', 0};
|
||||
fx_string_append_cstr(dest->p_pathstr, s);
|
||||
}
|
||||
|
||||
fx_string_append_s(dest->p_pathstr, src);
|
||||
fx_string_append_s(dest->p_pathstr, src->p_pathstr);
|
||||
}
|
||||
|
||||
static enum fx_status path_unlink(const struct fx_path_p *path)
|
||||
@@ -199,6 +199,33 @@ fx_path *fx_path_create_root()
|
||||
return path;
|
||||
}
|
||||
|
||||
fx_path *fx_path_create_cwd()
|
||||
{
|
||||
const long buf_len = 2048;
|
||||
char *buf = malloc(buf_len);
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!getcwd(buf, buf_len)) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fx_path *path = fx_path_create();
|
||||
if (!path) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_path_p *p = fx_object_get_private(path, FX_TYPE_PATH);
|
||||
|
||||
fx_string_append_cstr(p->p_pathstr, buf);
|
||||
free(buf);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
fx_path *fx_path_create_from_cstr(const char *cstr)
|
||||
{
|
||||
fx_path *path = fx_path_create();
|
||||
@@ -231,49 +258,6 @@ fx_path *fx_path_create_from_cstr(const char *cstr)
|
||||
return path;
|
||||
}
|
||||
|
||||
fx_path *fx_path_get_system(fx_system_path path_type)
|
||||
{
|
||||
char path_buf[4096];
|
||||
const char *path_value = NULL, *default_value = NULL;
|
||||
switch (path_type) {
|
||||
case FX_PATH_ROOT:
|
||||
path_value = "/";
|
||||
break;
|
||||
case FX_PATH_CWD:
|
||||
if (getcwd(path_buf, sizeof path_buf) == NULL) {
|
||||
path_value = path_buf;
|
||||
}
|
||||
break;
|
||||
case FX_PATH_HOME:
|
||||
path_value = getenv("HOME");
|
||||
default_value = "~";
|
||||
break;
|
||||
case FX_PATH_CONFIG: {
|
||||
const char *home = getenv("HOME");
|
||||
path_value = getenv("XDG_CONFIG_HOME");
|
||||
snprintf(
|
||||
path_buf,
|
||||
sizeof path_buf,
|
||||
"%s/.config",
|
||||
home ? home : "~");
|
||||
default_value = path_buf;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (path_value) {
|
||||
return fx_path_create_from_cstr(path_value);
|
||||
}
|
||||
|
||||
if (default_value) {
|
||||
return fx_path_create_from_cstr(default_value);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fx_path *fx_path_duplicate(const fx_path *path)
|
||||
{
|
||||
fx_path *new_path = fx_path_create();
|
||||
@@ -293,7 +277,7 @@ fx_path *fx_path_duplicate(const fx_path *path)
|
||||
return new_path;
|
||||
}
|
||||
|
||||
fx_path *fx_path_join_array(const fx_value *values[], size_t nr_values)
|
||||
fx_path *fx_path_join(const fx_path *paths[], size_t nr_paths)
|
||||
{
|
||||
fx_path *result = fx_path_create();
|
||||
if (!result) {
|
||||
@@ -303,53 +287,14 @@ fx_path *fx_path_join_array(const fx_value *values[], size_t nr_values)
|
||||
struct fx_path_p *result_p
|
||||
= fx_object_get_private(result, FX_TYPE_PATH);
|
||||
|
||||
fx_stringstream *tmp = fx_stringstream_create();
|
||||
fx_string *value_s = fx_string_create();
|
||||
for (size_t i = 0; i < nr_values; i++) {
|
||||
if (!values[i]) {
|
||||
continue;
|
||||
for (size_t i = 0; i < nr_paths; i++) {
|
||||
if (paths[i]) {
|
||||
struct fx_path_p *path_p
|
||||
= fx_object_get_private(paths[i], FX_TYPE_PATH);
|
||||
append_path(result_p, path_p);
|
||||
}
|
||||
}
|
||||
|
||||
fx_stringstream_reset(tmp);
|
||||
fx_value_to_string(values[i], tmp, NULL);
|
||||
|
||||
fx_string_clear(value_s);
|
||||
fx_string_append_cstr(value_s, fx_stringstream_get_cstr(tmp));
|
||||
append_path(result_p, value_s);
|
||||
}
|
||||
|
||||
fx_string_unref(value_s);
|
||||
fx_stringstream_unref(tmp);
|
||||
return result;
|
||||
}
|
||||
|
||||
fx_path *fx_path_join_list(size_t count, ...)
|
||||
{
|
||||
fx_path *result = fx_path_create();
|
||||
if (!result) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_path_p *result_p
|
||||
= fx_object_get_private(result, FX_TYPE_PATH);
|
||||
va_list arg;
|
||||
va_start(arg, count);
|
||||
|
||||
fx_stringstream *tmp = fx_stringstream_create();
|
||||
fx_string *value_s = fx_string_create();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const fx_value *value = va_arg(arg, const fx_value *);
|
||||
|
||||
fx_stringstream_reset(tmp);
|
||||
fx_value_to_string(value, tmp, NULL);
|
||||
|
||||
fx_string_clear(value_s);
|
||||
fx_string_append_cstr(value_s, fx_stringstream_get_cstr(tmp));
|
||||
append_path(result_p, value_s);
|
||||
}
|
||||
|
||||
fx_string_unref(value_s);
|
||||
fx_stringstream_unref(tmp);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -418,7 +363,7 @@ enum fx_status fx_path_get_filename(const fx_path *path, fx_string *out_name)
|
||||
out_name);
|
||||
}
|
||||
|
||||
const char *fx_path_get_cstr(const fx_path *path)
|
||||
const char *fx_path_ptr(const fx_path *path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_PATH, path_ptr, path);
|
||||
}
|
||||
@@ -447,27 +392,20 @@ void path_fini(fx_object *obj, void *priv)
|
||||
fx_string_unref(path->p_pathstr);
|
||||
}
|
||||
|
||||
static fx_status path_to_string(
|
||||
const fx_value *obj,
|
||||
fx_stream *out,
|
||||
const char *format)
|
||||
void path_to_string(const fx_object *obj, fx_stream *out)
|
||||
{
|
||||
struct fx_path_p *path
|
||||
= fx_object_get_private(obj->v_object, FX_TYPE_PATH);
|
||||
struct fx_path_p *path = fx_object_get_private(obj, FX_TYPE_PATH);
|
||||
|
||||
return fx_stream_write_cstr(
|
||||
out,
|
||||
fx_string_get_cstr(path->p_pathstr),
|
||||
NULL);
|
||||
fx_stream_write_cstr(out, fx_string_get_cstr(path->p_pathstr), NULL);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_path)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_path)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = path_to_string;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_END(fx_path)
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_path)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_path)
|
||||
FX_TYPE_ID(0x56dc32eb, 0xea96, 0x46ed, 0x85d3, 0x760fa4ad61f4);
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#include "posix.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fx/io/stream.h>
|
||||
#include <unistd.h>
|
||||
|
||||
fx_status fx_pipe_create(fx_iostream **reader, fx_iostream **writer)
|
||||
{
|
||||
int fds[2];
|
||||
int err = pipe(fds);
|
||||
if (err != 0) {
|
||||
return fx_status_from_errno(errno, FX_ERR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
fx_iostream *r = fx_iostream_create(FX_STREAM_READ, fds[0], true);
|
||||
fx_iostream *w = fx_iostream_create(FX_STREAM_WRITE, fds[1], true);
|
||||
|
||||
if (!r || !w) {
|
||||
fx_iostream_unref(r);
|
||||
fx_iostream_unref(w);
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
*reader = r;
|
||||
*writer = w;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
#include "posix.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fx/io/stream.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct fx_iostream_p {
|
||||
int s_fd;
|
||||
bool s_fd_close_on_release;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static uptr iostream_get_os_handle(const struct fx_iostream_p *stream)
|
||||
{
|
||||
return stream->s_fd;
|
||||
}
|
||||
|
||||
static uptr iostream_steal_os_handle(struct fx_iostream_p *stream)
|
||||
{
|
||||
uptr out = stream->s_fd;
|
||||
stream->s_fd = -1;
|
||||
stream->s_fd_close_on_release = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_iostream *fx_iostream_create(
|
||||
fx_stream_mode mode,
|
||||
uptr os_handle,
|
||||
bool close_handle_on_release)
|
||||
{
|
||||
fx_iostream *s = fx_object_create(FX_IO_TYPE_STREAM);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM);
|
||||
struct fx_iostream_p *p = fx_object_get_private(s, FX_IO_TYPE_STREAM);
|
||||
|
||||
cfg->s_mode = mode | Z__FX_STREAM_STATIC;
|
||||
p->s_fd = (int)os_handle;
|
||||
p->s_fd_close_on_release = close_handle_on_release;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
uptr fx_iostream_get_os_handle(const fx_iostream *stream)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_IO_TYPE_STREAM,
|
||||
iostream_get_os_handle,
|
||||
stream);
|
||||
}
|
||||
|
||||
uptr fx_iostream_steal_os_handle(fx_iostream *stream)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_IO_TYPE_STREAM,
|
||||
iostream_steal_os_handle,
|
||||
stream);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void iostream_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_iostream_p *stream = priv;
|
||||
}
|
||||
|
||||
static void iostream_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_iostream_p *stream = priv;
|
||||
|
||||
if (stream->s_fd_close_on_release) {
|
||||
close(stream->s_fd);
|
||||
}
|
||||
}
|
||||
|
||||
static enum fx_status stream_read(
|
||||
fx_stream *stream,
|
||||
void *buf,
|
||||
size_t count,
|
||||
size_t *nr_read)
|
||||
{
|
||||
struct fx_iostream_p *s
|
||||
= fx_object_get_private(stream, FX_IO_TYPE_STREAM);
|
||||
|
||||
long r = read(s->s_fd, buf, count);
|
||||
if (r < 0) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
*nr_read = r;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status stream_write(
|
||||
fx_stream *stream,
|
||||
const void *buf,
|
||||
size_t count,
|
||||
size_t *nr_written)
|
||||
{
|
||||
struct fx_iostream_p *s
|
||||
= fx_object_get_private(stream, FX_IO_TYPE_STREAM);
|
||||
|
||||
long w = write(s->s_fd, buf, count);
|
||||
if (w < 0) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
*nr_written = w;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_iostream)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_stream, FX_TYPE_STREAM)
|
||||
FX_INTERFACE_ENTRY(s_close) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_seek) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_tell) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_getc) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_read) = stream_read;
|
||||
FX_INTERFACE_ENTRY(s_write) = stream_write;
|
||||
FX_INTERFACE_ENTRY(s_reserve) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_stream, FX_TYPE_STREAM)
|
||||
FX_TYPE_CLASS_END(fx_iostream)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_iostream)
|
||||
FX_TYPE_ID(0xc0b1c3c9, 0xa9c6, 0x4910, 0x8786, 0x574b0696e7aa);
|
||||
FX_TYPE_NAME("fx.io.stream");
|
||||
FX_TYPE_EXTENDS(FX_TYPE_STREAM);
|
||||
FX_TYPE_CLASS(fx_iostream_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_iostream_p);
|
||||
FX_TYPE_INSTANCE_INIT(iostream_init);
|
||||
FX_TYPE_INSTANCE_FINI(iostream_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_iostream)
|
||||
@@ -1,759 +0,0 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include "misc.h"
|
||||
#include "posix.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <fx/error.h>
|
||||
#include <fx/io/directory.h>
|
||||
#include <fx/string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
enum directory_flags {
|
||||
DIRECTORY_DELETE_ON_CLOSE = 0x01u,
|
||||
};
|
||||
|
||||
struct fx_directory_p {
|
||||
enum directory_flags d_flags;
|
||||
int d_fd;
|
||||
fx_path *d_path_rel;
|
||||
fx_path *d_path_abs;
|
||||
};
|
||||
|
||||
struct fx_directory_iterator_p {
|
||||
struct fx_directory_p *_p;
|
||||
|
||||
#if 0
|
||||
FTS *fts;
|
||||
FTSENT *ent;
|
||||
#endif
|
||||
|
||||
fx_directory_iterator_flags flags;
|
||||
fx_directory *root;
|
||||
|
||||
fx_directory_entry entry;
|
||||
fx_value entry_value;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
static const fx_path *directory_get_path(const struct fx_directory_p *dir)
|
||||
{
|
||||
return dir->d_path_abs;
|
||||
}
|
||||
|
||||
static const fx_path *directory_get_rel_path(const struct fx_directory_p *dir)
|
||||
{
|
||||
return dir->d_path_rel;
|
||||
}
|
||||
|
||||
static const char *directory_get_path_cstr(const struct fx_directory_p *dir)
|
||||
{
|
||||
return fx_path_get_cstr(dir->d_path_abs);
|
||||
}
|
||||
|
||||
static const char *directory_get_rel_path_cstr(const struct fx_directory_p *dir)
|
||||
{
|
||||
return fx_path_get_cstr(dir->d_path_rel);
|
||||
}
|
||||
|
||||
static fx_result directory_delete(
|
||||
fx_directory *dir,
|
||||
struct fx_directory_p *dir_p)
|
||||
{
|
||||
enum fx_status status = FX_SUCCESS;
|
||||
|
||||
fx_iterator *it
|
||||
= fx_directory_begin(dir, FX_DIRECTORY_ITERATE_PARENT_LAST);
|
||||
while (FX_OK(fx_iterator_get_status(it))) {
|
||||
fx_iterator_erase(it);
|
||||
}
|
||||
|
||||
status = fx_iterator_get_status(it);
|
||||
if (!FX_OK(status) && status != FX_ERR_NO_DATA) {
|
||||
return FX_RESULT_STATUS(status);
|
||||
}
|
||||
|
||||
status = fx_path_unlink(dir_p->d_path_abs);
|
||||
if (!FX_OK(status)) {
|
||||
return FX_RESULT_STATUS(status);
|
||||
}
|
||||
|
||||
return FX_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static bool directory_path_exists(
|
||||
const struct fx_directory_p *root,
|
||||
fx_value path)
|
||||
{
|
||||
fx_path *abs_path = fx_path_join_list(
|
||||
2,
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&path);
|
||||
if (!abs_path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = fx_path_exists(abs_path);
|
||||
fx_path_unref(abs_path);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool directory_path_is_file(
|
||||
const struct fx_directory_p *root,
|
||||
fx_value path)
|
||||
{
|
||||
const fx_value *parts[] = {};
|
||||
|
||||
fx_path *abs_path = fx_path_join_list(
|
||||
2,
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&path);
|
||||
if (!abs_path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = fx_path_is_file(abs_path);
|
||||
fx_path_unref(abs_path);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool directory_path_is_directory(
|
||||
const struct fx_directory_p *root,
|
||||
fx_value path)
|
||||
{
|
||||
const fx_value *parts[] = {};
|
||||
|
||||
fx_path *abs_path = fx_path_join_list(
|
||||
2,
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&path);
|
||||
if (!abs_path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = fx_path_is_directory(abs_path);
|
||||
fx_path_unref(abs_path);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static fx_result directory_path_stat(
|
||||
const struct fx_directory_p *root,
|
||||
fx_value path,
|
||||
struct fx_file_info *out)
|
||||
{
|
||||
const fx_value *parts[] = {};
|
||||
|
||||
fx_path *abs_path = fx_path_join_list(
|
||||
2,
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&path);
|
||||
if (!abs_path) {
|
||||
return FX_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
enum fx_status status = fx_path_stat(abs_path, out);
|
||||
fx_path_unref(abs_path);
|
||||
|
||||
return FX_RESULT_STATUS(status);
|
||||
}
|
||||
|
||||
static fx_result directory_path_unlink(
|
||||
const struct fx_directory_p *root,
|
||||
fx_value path)
|
||||
{
|
||||
const fx_value *parts[] = {};
|
||||
|
||||
fx_path *abs_path = fx_path_join_list(
|
||||
2,
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : NULL),
|
||||
&path);
|
||||
if (!abs_path) {
|
||||
return FX_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
enum fx_status status = fx_path_unlink(abs_path);
|
||||
fx_path_unref(abs_path);
|
||||
|
||||
return FX_RESULT_STATUS(status);
|
||||
}
|
||||
|
||||
static fx_result create_directory(struct fx_directory_p *root, const char *path)
|
||||
{
|
||||
#if 0
|
||||
int root_fd = root ? root->d_fd : -1;
|
||||
int err;
|
||||
|
||||
if (root_fd == -1) {
|
||||
err = mkdir(path, 0755);
|
||||
} else {
|
||||
err = mkdirat(root_fd, path, 0755);
|
||||
}
|
||||
|
||||
if (err == 0 || errno == EEXIST) {
|
||||
return FX_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
return fx_result_from_errno_with_subfilepath(
|
||||
errno,
|
||||
path,
|
||||
directory_get_rel_path_cstr(root),
|
||||
FX_ERR_IO_FAILURE);
|
||||
#endif
|
||||
return FX_RESULT_ERR(NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
static fx_result create_directory_hierarchy(
|
||||
struct fx_directory_p *root,
|
||||
const char *path)
|
||||
{
|
||||
#if 0
|
||||
int root_fd = root ? root->d_fd : AT_FDCWD;
|
||||
|
||||
char *path_buf = fx_strdup(path);
|
||||
if (!path_buf) {
|
||||
return FX_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
fx_result result = FX_RESULT_SUCCESS;
|
||||
for (size_t i = 0; path_buf[i]; i++) {
|
||||
if (path_buf[i] != '/') {
|
||||
continue;
|
||||
}
|
||||
|
||||
path_buf[i] = 0;
|
||||
|
||||
int err = mkdirat(root_fd, path_buf, 0755);
|
||||
if (err != 0 && errno != EEXIST) {
|
||||
result = fx_result_from_errno_with_subfilepath(
|
||||
errno,
|
||||
path_buf,
|
||||
directory_get_rel_path_cstr(root),
|
||||
FX_ERR_IO_FAILURE);
|
||||
break;
|
||||
}
|
||||
|
||||
path_buf[i] = '/';
|
||||
}
|
||||
|
||||
int err = mkdirat(root_fd, path_buf, 0755);
|
||||
if (err != 0 && errno != EEXIST) {
|
||||
result = fx_result_from_errno_with_subfilepath(
|
||||
errno,
|
||||
path_buf,
|
||||
directory_get_rel_path_cstr(root),
|
||||
FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
free(path_buf);
|
||||
return result;
|
||||
#endif
|
||||
return FX_RESULT_ERR(NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
static fx_result directory_open(
|
||||
struct fx_directory_p *root,
|
||||
fx_value path,
|
||||
fx_directory_open_flags flags,
|
||||
fx_directory **out)
|
||||
{
|
||||
#if 0
|
||||
enum fx_status status = FX_SUCCESS;
|
||||
|
||||
int root_fd = root ? root->d_fd : AT_FDCWD;
|
||||
|
||||
fx_stringstream *path_str = fx_stringstream_create();
|
||||
fx_value_to_string(&path, path_str, NULL);
|
||||
const char *path_cstr = fx_stringstream_get_cstr(path_str);
|
||||
|
||||
if (root) {
|
||||
while (*path_cstr == '/') {
|
||||
path_cstr++;
|
||||
}
|
||||
}
|
||||
|
||||
fx_result result = FX_RESULT_SUCCESS;
|
||||
if ((flags & FX_DIRECTORY_OPEN_CREATE_INTERMEDIATE)
|
||||
== FX_DIRECTORY_OPEN_CREATE_INTERMEDIATE) {
|
||||
result = create_directory_hierarchy(root, path_cstr);
|
||||
} else if (
|
||||
(flags & FX_DIRECTORY_OPEN_CREATE)
|
||||
== FX_DIRECTORY_OPEN_CREATE) {
|
||||
result = create_directory(root, path_cstr);
|
||||
}
|
||||
|
||||
if (fx_result_is_error(result)) {
|
||||
return fx_result_propagate(result);
|
||||
}
|
||||
|
||||
int fd = openat(root_fd, path_cstr, O_DIRECTORY);
|
||||
|
||||
if (fd == -1) {
|
||||
status = fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
return FX_RESULT_STATUS(status);
|
||||
}
|
||||
|
||||
fx_directory *dir = fx_object_create(FX_TYPE_DIRECTORY);
|
||||
fx_path *cwd = NULL;
|
||||
struct fx_directory_p *p
|
||||
= fx_object_get_private(dir, FX_TYPE_DIRECTORY);
|
||||
|
||||
if (!root) {
|
||||
cwd = fx_path_get_system(FX_PATH_CWD);
|
||||
}
|
||||
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(root ? root->d_path_abs : cwd),
|
||||
&FX_CSTR(path_cstr),
|
||||
};
|
||||
|
||||
fx_path *new_path
|
||||
= fx_path_join_array(parts, sizeof parts / sizeof parts[0]);
|
||||
if (!new_path) {
|
||||
fx_stringstream_unref(path_str);
|
||||
return FX_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
if (cwd) {
|
||||
fx_path_unref(cwd);
|
||||
}
|
||||
|
||||
p->d_path_abs = new_path;
|
||||
p->d_path_rel = fx_path_create_from_cstr(path_cstr);
|
||||
p->d_fd = fd;
|
||||
|
||||
if (flags & FX_DIRECTORY_OPEN_DELETE_ON_CLOSE) {
|
||||
p->d_flags = DIRECTORY_DELETE_ON_CLOSE;
|
||||
}
|
||||
|
||||
*out = dir;
|
||||
fx_stringstream_unref(path_str);
|
||||
|
||||
return FX_RESULT_SUCCESS;
|
||||
#endif
|
||||
return FX_RESULT_ERR(NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_result fx_directory_open(
|
||||
fx_directory *root,
|
||||
fx_value path,
|
||||
fx_directory_open_flags flags,
|
||||
fx_directory **out)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_DIRECTORY,
|
||||
directory_open,
|
||||
root,
|
||||
path,
|
||||
flags,
|
||||
out);
|
||||
}
|
||||
|
||||
fx_result fx_directory_open_temp(fx_directory **out)
|
||||
{
|
||||
char name[16];
|
||||
char path[128];
|
||||
|
||||
while (1) {
|
||||
z__fx_io_generate_tmp_filename(name, sizeof name);
|
||||
snprintf(path, sizeof path, "/tmp/%s", name);
|
||||
|
||||
fx_directory *dir = NULL;
|
||||
fx_result status = fx_directory_open(
|
||||
FX_DIRECTORY_ROOT,
|
||||
FX_CSTR(path),
|
||||
FX_DIRECTORY_OPEN_CREATE,
|
||||
&dir);
|
||||
struct fx_directory_p *p
|
||||
= fx_object_get_private(dir, FX_TYPE_DIRECTORY);
|
||||
|
||||
if (fx_error_get_status_code(status) == FX_ERR_NAME_EXISTS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dir) {
|
||||
p->d_flags |= DIRECTORY_DELETE_ON_CLOSE;
|
||||
}
|
||||
|
||||
*out = dir;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
const fx_path *fx_directory_get_path(const fx_directory *dir)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DIRECTORY, directory_get_path, dir);
|
||||
}
|
||||
|
||||
const fx_path *fx_directory_get_rel_path(const fx_directory *dir)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_TYPE_DIRECTORY,
|
||||
directory_get_rel_path,
|
||||
dir);
|
||||
}
|
||||
|
||||
const char *fx_directory_get_path_cstr(const fx_directory *dir)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_TYPE_DIRECTORY,
|
||||
directory_get_path_cstr,
|
||||
dir);
|
||||
}
|
||||
|
||||
const char *fx_directory_get_rel_path_cstr(const fx_directory *dir)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_TYPE_DIRECTORY,
|
||||
directory_get_rel_path_cstr,
|
||||
dir);
|
||||
}
|
||||
|
||||
fx_result fx_directory_delete(fx_directory *dir)
|
||||
{
|
||||
struct fx_directory_p *p
|
||||
= fx_object_get_private(dir, FX_TYPE_DIRECTORY);
|
||||
p->d_flags |= DIRECTORY_DELETE_ON_CLOSE;
|
||||
/* TODO allow object release functions to return a fx_result value */
|
||||
fx_directory_unref(dir);
|
||||
return FX_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
bool fx_directory_path_exists(const fx_directory *root, fx_value path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_DIRECTORY,
|
||||
directory_path_exists,
|
||||
root,
|
||||
path);
|
||||
}
|
||||
|
||||
bool fx_directory_path_is_file(const fx_directory *root, fx_value path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_DIRECTORY,
|
||||
directory_path_is_file,
|
||||
root,
|
||||
path);
|
||||
}
|
||||
|
||||
bool fx_directory_path_is_directory(const fx_directory *root, fx_value path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_DIRECTORY,
|
||||
directory_path_is_directory,
|
||||
root,
|
||||
path);
|
||||
}
|
||||
|
||||
fx_result fx_directory_path_stat(
|
||||
const fx_directory *root,
|
||||
fx_value path,
|
||||
struct fx_file_info *out)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_DIRECTORY,
|
||||
directory_path_stat,
|
||||
root,
|
||||
path,
|
||||
out);
|
||||
}
|
||||
|
||||
fx_result fx_directory_path_unlink(const fx_directory *root, fx_value path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_DIRECTORY,
|
||||
directory_path_unlink,
|
||||
root,
|
||||
path);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void directory_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_directory_p *dir = priv;
|
||||
}
|
||||
|
||||
static void directory_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_directory_p *dir = priv;
|
||||
|
||||
close(dir->d_fd);
|
||||
|
||||
if (dir->d_flags & DIRECTORY_DELETE_ON_CLOSE) {
|
||||
directory_delete(obj, dir);
|
||||
}
|
||||
|
||||
fx_path_unref(dir->d_path_abs);
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
#if 0
|
||||
static int ftsent_compare(const FTSENT **one, const FTSENT **two)
|
||||
{
|
||||
return (strcmp((*one)->fts_name, (*two)->fts_name));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void update_iterator_data(struct fx_directory_iterator_p *it)
|
||||
{
|
||||
if (it->entry.filepath) {
|
||||
fx_path_unref((fx_path *)it->entry.filepath);
|
||||
it->entry.filepath = NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
FTSENT *ent = it->ent;
|
||||
|
||||
fx_path *path = fx_path_create_from_cstr(
|
||||
ent->fts_path + fx_path_length(it->_p->d_path_abs) + 1);
|
||||
|
||||
fx_value_unset(&it->entry_value);
|
||||
it->entry_value = FX_POINTER(&it->entry);
|
||||
it->entry.filename = ent->fts_name;
|
||||
it->entry.filepath = path;
|
||||
|
||||
memset(&it->entry.info, 0x0, sizeof it->entry.info);
|
||||
|
||||
it->entry.info.length = ent->fts_statp->st_size;
|
||||
|
||||
if (S_ISREG(ent->fts_statp->st_mode)) {
|
||||
it->entry.info.attrib |= FX_FILE_ATTRIB_NORMAL;
|
||||
}
|
||||
|
||||
if (S_ISDIR(ent->fts_statp->st_mode)) {
|
||||
it->entry.info.attrib |= FX_FILE_ATTRIB_DIRECTORY;
|
||||
}
|
||||
|
||||
if (S_ISBLK(ent->fts_statp->st_mode)) {
|
||||
it->entry.info.attrib |= FX_FILE_ATTRIB_BLOCK_DEVICE;
|
||||
}
|
||||
|
||||
if (S_ISCHR(ent->fts_statp->st_mode)) {
|
||||
it->entry.info.attrib |= FX_FILE_ATTRIB_CHAR_DEVICE;
|
||||
}
|
||||
|
||||
if (S_ISLNK(ent->fts_statp->st_mode)) {
|
||||
it->entry.info.attrib |= FX_FILE_ATTRIB_SYMLINK;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void iterator_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_directory_iterator_p *it = priv;
|
||||
|
||||
if (it->entry.filepath) {
|
||||
fx_path_unref((fx_path *)it->entry.filepath);
|
||||
it->entry.filepath = NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (it->fts) {
|
||||
fts_close(it->fts);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
fx_iterator *fx_directory_begin(
|
||||
fx_directory *directory,
|
||||
enum fx_directory_iterator_flags flags)
|
||||
{
|
||||
#if 0
|
||||
fx_iterator *it_obj = fx_object_create(FX_TYPE_DIRECTORY_ITERATOR);
|
||||
struct fx_directory_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_DIRECTORY_ITERATOR);
|
||||
|
||||
it->flags = flags;
|
||||
it->root = directory;
|
||||
it->_p = fx_object_get_private(directory, FX_TYPE_DIRECTORY);
|
||||
|
||||
int fts_flags = FTS_COMFOLLOW | FTS_NOCHDIR;
|
||||
|
||||
const char *path_list[] = {
|
||||
fx_path_get_cstr(it->_p->d_path_abs),
|
||||
NULL,
|
||||
};
|
||||
|
||||
it->fts = fts_open((char *const *)path_list, fts_flags, ftsent_compare);
|
||||
|
||||
bool done = false;
|
||||
|
||||
while (!done) {
|
||||
it->ent = fts_read(it->fts);
|
||||
|
||||
if (!it->ent) {
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
if (it->ent->fts_level == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (it->ent->fts_info) {
|
||||
case FTS_DOT:
|
||||
continue;
|
||||
case FTS_F:
|
||||
done = true;
|
||||
break;
|
||||
case FTS_D:
|
||||
if (it->flags & FX_DIRECTORY_ITERATE_PARENT_LAST) {
|
||||
continue;
|
||||
}
|
||||
|
||||
done = true;
|
||||
break;
|
||||
case FTS_DP:
|
||||
if (it->flags & FX_DIRECTORY_ITERATE_PARENT_FIRST) {
|
||||
continue;
|
||||
}
|
||||
done = true;
|
||||
break;
|
||||
default:
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
update_iterator_data(it);
|
||||
return it_obj;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const fx_iterator *iterator_begin(const fx_object *obj)
|
||||
{
|
||||
return fx_directory_begin(
|
||||
(fx_object *)obj,
|
||||
FX_DIRECTORY_ITERATE_PARENT_FIRST);
|
||||
}
|
||||
|
||||
static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
{
|
||||
#if 0
|
||||
struct fx_directory_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DIRECTORY_ITERATOR);
|
||||
if (!it || !it->fts) {
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
|
||||
while (!done) {
|
||||
it->ent = fts_read(it->fts);
|
||||
|
||||
if (!it->ent) {
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
if (it->ent->fts_level == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (it->ent->fts_info) {
|
||||
case FTS_DOT:
|
||||
continue;
|
||||
case FTS_F:
|
||||
done = true;
|
||||
break;
|
||||
case FTS_D:
|
||||
if (it->flags & FX_DIRECTORY_ITERATE_PARENT_LAST) {
|
||||
continue;
|
||||
}
|
||||
done = true;
|
||||
break;
|
||||
case FTS_DP:
|
||||
if (it->flags & FX_DIRECTORY_ITERATE_PARENT_FIRST) {
|
||||
continue;
|
||||
}
|
||||
done = true;
|
||||
break;
|
||||
default:
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
update_iterator_data(it);
|
||||
return FX_SUCCESS;
|
||||
#endif
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
{
|
||||
struct fx_directory_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DIRECTORY_ITERATOR);
|
||||
fx_result result = fx_directory_path_unlink(
|
||||
it->root,
|
||||
FX_VALUE_OBJECT(it->entry.filepath));
|
||||
if (fx_result_is_error(result)) {
|
||||
enum fx_status status = fx_error_get_status_code(result);
|
||||
fx_error_discard(result);
|
||||
return status;
|
||||
}
|
||||
|
||||
return iterator_move_next(obj);
|
||||
}
|
||||
|
||||
static const fx_value *iterator_get_value(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_directory_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DIRECTORY_ITERATOR);
|
||||
|
||||
return &it->entry_value;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- fx_directory DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_directory)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_INTERFACE_ENTRY(it_begin) = iterator_begin;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_END(fx_directory)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_directory)
|
||||
FX_TYPE_ID(0x10d36546, 0x7f96, 0x464b, 0xbc4d, 0xe504b283fa45);
|
||||
FX_TYPE_CLASS(fx_directory_class);
|
||||
FX_TYPE_IMPLEMENTS(FX_TYPE_ITERABLE);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_directory_p);
|
||||
FX_TYPE_INSTANCE_INIT(directory_init);
|
||||
FX_TYPE_INSTANCE_FINI(directory_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_directory)
|
||||
|
||||
// ---- fx_directory_iterator DEFINITION
|
||||
FX_TYPE_CLASS_BEGIN(fx_directory_iterator)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_END(fx_directory_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_directory_iterator)
|
||||
FX_TYPE_ID(0xc707fce6, 0xc895, 0x4925, 0x8700, 0xa60641dee0cc);
|
||||
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
|
||||
FX_TYPE_CLASS(fx_directory_iterator_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_directory_iterator_p);
|
||||
FX_TYPE_DEFINITION_END(fx_directory_iterator)
|
||||
@@ -1,653 +0,0 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include "misc.h"
|
||||
#include "posix.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <fx/io/directory.h>
|
||||
#include <fx/io/file.h>
|
||||
#include <fx/io/path.h>
|
||||
#include <fx/random.h>
|
||||
#include <fx/string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define CHECK_FLAG(v, f) (((v) & (f)) == (f))
|
||||
|
||||
static enum fx_status stream_close(fx_stream *);
|
||||
static enum fx_status stream_getc(fx_stream *, int *);
|
||||
static enum fx_status stream_read(fx_stream *, void *, size_t, size_t *);
|
||||
static enum fx_status stream_write(fx_stream *, const void *, size_t, size_t *);
|
||||
static enum fx_status stream_seek(
|
||||
fx_stream *,
|
||||
long long,
|
||||
fx_stream_seek_origin);
|
||||
static enum fx_status stream_tell(const fx_stream *, size_t *);
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct fx_file_p {
|
||||
enum fx_file_mode mode;
|
||||
int fd;
|
||||
fx_path *path;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static unsigned int fx_mode_to_unix_mode(enum fx_file_mode mode)
|
||||
{
|
||||
unsigned int result = 0;
|
||||
|
||||
if (CHECK_FLAG(mode, FX_FILE_READ_WRITE)) {
|
||||
result |= O_RDWR;
|
||||
} else if (CHECK_FLAG(mode, FX_FILE_READ_ONLY)) {
|
||||
result |= O_RDONLY;
|
||||
} else if (CHECK_FLAG(mode, FX_FILE_WRITE_ONLY)) {
|
||||
result |= O_WRONLY;
|
||||
} else {
|
||||
return (unsigned int)-1;
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(mode, FX_FILE_TRUNCATE)) {
|
||||
result |= O_TRUNC;
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(mode, FX_FILE_CREATE)) {
|
||||
result |= O_CREAT;
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(mode, FX_FILE_CREATE_ONLY)) {
|
||||
result |= O_EXCL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static fx_result file_open_shadow(
|
||||
struct fx_file_p *original,
|
||||
enum fx_file_mode mode,
|
||||
fx_file **out)
|
||||
{
|
||||
mode |= FX_FILE_SHADOW | FX_FILE_DELETE_ON_CLOSE | FX_FILE_CREATE;
|
||||
|
||||
fx_path *dir;
|
||||
fx_path_get_directory(original->path, &dir);
|
||||
|
||||
fx_string *filename = fx_string_create();
|
||||
fx_path_get_filename(original->path, filename);
|
||||
|
||||
fx_string_prepend_cstr(filename, ".~");
|
||||
|
||||
fx_path *shadow_filename
|
||||
= fx_path_create_from_cstr(fx_string_get_cstr(filename));
|
||||
fx_string_unref(filename);
|
||||
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(dir),
|
||||
&FX_VALUE_OBJECT(shadow_filename),
|
||||
};
|
||||
|
||||
fx_path *shadow_filepath
|
||||
= fx_path_join_array(parts, sizeof parts / sizeof parts[0]);
|
||||
fx_path_unref(dir);
|
||||
fx_path_unref(shadow_filename);
|
||||
|
||||
if (fx_path_exists(shadow_filepath)) {
|
||||
fx_path_unlink(shadow_filepath);
|
||||
}
|
||||
|
||||
fx_file *shadow_file;
|
||||
fx_result status = fx_file_open(
|
||||
FX_DIRECTORY_ROOT,
|
||||
FX_VALUE_OBJECT(shadow_filepath),
|
||||
mode,
|
||||
&shadow_file);
|
||||
fx_path_unref(shadow_filepath);
|
||||
|
||||
if (fx_result_is_error(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
*out = shadow_file;
|
||||
return FX_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static const fx_path *file_path(const struct fx_file_p *file)
|
||||
{
|
||||
return file->path;
|
||||
}
|
||||
|
||||
static enum fx_status file_stat(
|
||||
struct fx_file_p *file,
|
||||
struct fx_file_info *out)
|
||||
{
|
||||
#if 0
|
||||
struct stat st;
|
||||
int err = fstat(file->fd, &st);
|
||||
|
||||
if (err != 0) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
|
||||
return fx_file_info_from_stat(&st, out);
|
||||
#endif
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static enum fx_status file_size(struct fx_file_p *file, size_t *out_len)
|
||||
{
|
||||
off_t cur = lseek(file->fd, 0, SEEK_CUR);
|
||||
if (cur == (off_t)-1) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
off_t len = lseek(file->fd, 0, SEEK_END);
|
||||
if (len == (off_t)-1) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
cur = lseek(file->fd, cur, SEEK_SET);
|
||||
if (cur == (off_t)-1) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
*out_len = (size_t)len;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status file_cursor(struct fx_file_p *file, size_t *out_pos)
|
||||
{
|
||||
off_t cur = lseek(file->fd, 0, SEEK_CUR);
|
||||
if (cur == (off_t)-1) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
*out_pos = (size_t)cur;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status file_resize(struct fx_file_p *file, size_t len)
|
||||
{
|
||||
#if 0
|
||||
int err = ftruncate(file->fd, len);
|
||||
if (err == 0) {
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
#endif
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static enum fx_status file_seek(
|
||||
struct fx_file_p *file,
|
||||
long long offset,
|
||||
enum fx_seek_basis basis)
|
||||
{
|
||||
int whence;
|
||||
switch (basis) {
|
||||
case FX_SEEK_BEGINNING:
|
||||
whence = SEEK_SET;
|
||||
break;
|
||||
case FX_SEEK_CURRENT:
|
||||
whence = SEEK_CUR;
|
||||
break;
|
||||
case FX_SEEK_END:
|
||||
whence = SEEK_END;
|
||||
break;
|
||||
default:
|
||||
return FX_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
int err = lseek(file->fd, offset, whence);
|
||||
if (err == (off_t)-1) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status file_swap_shadow(
|
||||
struct fx_file_p *main_file,
|
||||
struct fx_file_p *shadow_file)
|
||||
{
|
||||
if (main_file->mode & FX_FILE_SHADOW) {
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (!(shadow_file->mode & FX_FILE_SHADOW)) {
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
fx_path *dir_path;
|
||||
fx_path_get_directory(main_file->path, &dir_path);
|
||||
|
||||
fx_path *tmp_path = NULL;
|
||||
|
||||
while (1) {
|
||||
char tmp_name[16];
|
||||
z__fx_io_generate_tmp_filename(tmp_name, sizeof tmp_name);
|
||||
fx_path *tmp_name_p = fx_path_create_from_cstr(tmp_name);
|
||||
|
||||
const fx_value *parts[] = {
|
||||
&FX_VALUE_OBJECT(dir_path),
|
||||
&FX_VALUE_OBJECT(tmp_name_p),
|
||||
};
|
||||
|
||||
tmp_path = fx_path_join_array(
|
||||
parts,
|
||||
sizeof parts / sizeof parts[0]);
|
||||
|
||||
fx_path_unref(tmp_name_p);
|
||||
|
||||
if (!fx_path_exists(tmp_path)) {
|
||||
break;
|
||||
}
|
||||
|
||||
fx_path_unref(tmp_path);
|
||||
tmp_path = NULL;
|
||||
}
|
||||
|
||||
fx_path_unref(dir_path);
|
||||
|
||||
int err;
|
||||
|
||||
#if 0
|
||||
err = rename(
|
||||
fx_path_get_cstr(main_file->path),
|
||||
fx_path_get_cstr(tmp_path));
|
||||
err = rename(
|
||||
fx_path_get_cstr(shadow_file->path),
|
||||
fx_path_get_cstr(main_file->path));
|
||||
err = rename(
|
||||
fx_path_get_cstr(tmp_path),
|
||||
fx_path_get_cstr(shadow_file->path));
|
||||
#endif
|
||||
|
||||
fx_path_unref(tmp_path);
|
||||
|
||||
int fd = main_file->fd;
|
||||
main_file->fd = shadow_file->fd;
|
||||
shadow_file->fd = fd;
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status file_read(
|
||||
struct fx_file_p *file,
|
||||
size_t offset,
|
||||
size_t len,
|
||||
void *buf,
|
||||
size_t *nr_read)
|
||||
{
|
||||
if (offset != FX_OFFSET_CURRENT) {
|
||||
lseek(file->fd, offset, SEEK_SET);
|
||||
}
|
||||
|
||||
long r = read(file->fd, buf, len);
|
||||
|
||||
enum fx_status status = FX_SUCCESS;
|
||||
|
||||
if (r < 0) {
|
||||
status = fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
*nr_read = r;
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum fx_status file_write(
|
||||
struct fx_file_p *file,
|
||||
size_t offset,
|
||||
size_t len,
|
||||
const void *buf,
|
||||
size_t *nr_written)
|
||||
{
|
||||
if (offset != FX_OFFSET_CURRENT) {
|
||||
lseek(file->fd, offset, SEEK_SET);
|
||||
}
|
||||
|
||||
long w = write(file->fd, buf, len);
|
||||
|
||||
enum fx_status status = FX_SUCCESS;
|
||||
|
||||
if (w < 0) {
|
||||
status = fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
*nr_written = w;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*** STREAM FUNCTIONS *********************************************************/
|
||||
|
||||
static enum fx_status stream_close(fx_stream *stream)
|
||||
{
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status stream_getc(fx_stream *stream, int *out)
|
||||
{
|
||||
struct fx_file_p *file = fx_object_get_private(stream, FX_TYPE_FILE);
|
||||
char c;
|
||||
size_t nr_read = 0;
|
||||
|
||||
enum fx_status status
|
||||
= file_read(file, FX_OFFSET_CURRENT, sizeof c, &c, &nr_read);
|
||||
if (status != FX_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (nr_read == 0) {
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
*out = c;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status stream_read(
|
||||
fx_stream *stream,
|
||||
void *buf,
|
||||
size_t max,
|
||||
size_t *nr_read)
|
||||
{
|
||||
struct fx_file_p *file = fx_object_get_private(stream, FX_TYPE_FILE);
|
||||
|
||||
enum fx_status status
|
||||
= file_read(file, FX_OFFSET_CURRENT, max, buf, nr_read);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum fx_status stream_write(
|
||||
fx_stream *stream,
|
||||
const void *buf,
|
||||
size_t count,
|
||||
size_t *nr_written)
|
||||
{
|
||||
struct fx_file_p *file = fx_object_get_private(stream, FX_TYPE_FILE);
|
||||
|
||||
enum fx_status status
|
||||
= file_write(file, FX_OFFSET_CURRENT, count, buf, nr_written);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum fx_status stream_seek(
|
||||
fx_stream *stream,
|
||||
long long offset,
|
||||
fx_stream_seek_origin origin)
|
||||
{
|
||||
fx_seek_basis basis;
|
||||
switch (origin) {
|
||||
case FX_STREAM_SEEK_START:
|
||||
basis = FX_SEEK_BEGINNING;
|
||||
break;
|
||||
case FX_STREAM_SEEK_CURRENT:
|
||||
basis = FX_SEEK_CURRENT;
|
||||
break;
|
||||
case FX_STREAM_SEEK_END:
|
||||
basis = FX_SEEK_END;
|
||||
break;
|
||||
default:
|
||||
return FX_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
struct fx_file_p *file = fx_object_get_private(stream, FX_TYPE_FILE);
|
||||
|
||||
return file_seek(file, offset, basis);
|
||||
}
|
||||
|
||||
static enum fx_status stream_tell(const fx_stream *stream, size_t *pos)
|
||||
{
|
||||
const struct fx_file_p *file
|
||||
= fx_object_get_private(stream, FX_TYPE_FILE);
|
||||
off_t v = lseek(file->fd, 0, SEEK_CUR);
|
||||
if (v == (off_t)-1) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
*pos = v;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_result fx_file_open(
|
||||
fx_directory *root,
|
||||
fx_value path,
|
||||
enum fx_file_mode mode,
|
||||
fx_file **out)
|
||||
{
|
||||
unsigned int flags = fx_mode_to_unix_mode(mode);
|
||||
|
||||
if (flags == (unsigned int)-1) {
|
||||
return FX_RESULT_ERR(INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
const fx_path *root_path = NULL;
|
||||
bool free_root_path = false;
|
||||
if (root) {
|
||||
root_path = fx_directory_get_path(root);
|
||||
} else {
|
||||
root_path = fx_path_get_system(FX_PATH_CWD);
|
||||
free_root_path = true;
|
||||
}
|
||||
|
||||
fx_path *abs_path
|
||||
= fx_path_join_list(2, &FX_VALUE_OBJECT(root_path), &path);
|
||||
|
||||
if (free_root_path) {
|
||||
fx_path_unref((fx_path *)root_path);
|
||||
}
|
||||
|
||||
if (!abs_path) {
|
||||
return FX_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
int fd = open(fx_path_get_cstr(abs_path), flags);
|
||||
if (fd == -1) {
|
||||
fx_path_unref(abs_path);
|
||||
return FX_RESULT_STATUS(
|
||||
fx_status_from_errno(errno, FX_ERR_IO_FAILURE));
|
||||
}
|
||||
|
||||
fx_file *file = fx_object_create(FX_TYPE_FILE);
|
||||
if (!file) {
|
||||
close(fd);
|
||||
fx_path_unref(abs_path);
|
||||
return FX_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
struct fx_file_p *p = fx_object_get_private(file, FX_TYPE_FILE);
|
||||
fx_stream_cfg *cfg = fx_object_get_protected(file, FX_TYPE_STREAM);
|
||||
|
||||
if (mode & FX_FILE_READ_ONLY) {
|
||||
cfg->s_mode |= FX_STREAM_READ;
|
||||
}
|
||||
|
||||
if (mode & FX_FILE_WRITE_ONLY) {
|
||||
cfg->s_mode |= FX_STREAM_WRITE;
|
||||
}
|
||||
|
||||
if (mode & FX_FILE_BINARY) {
|
||||
cfg->s_mode |= FX_STREAM_BINARY;
|
||||
}
|
||||
|
||||
p->fd = fd;
|
||||
p->path = abs_path;
|
||||
p->mode = mode;
|
||||
|
||||
*out = file;
|
||||
return FX_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
fx_result fx_file_open_temp(enum fx_file_mode mode, fx_file **out)
|
||||
{
|
||||
mode |= FX_FILE_DELETE_ON_CLOSE;
|
||||
|
||||
char name[16];
|
||||
char path[128];
|
||||
|
||||
while (1) {
|
||||
z__fx_io_generate_tmp_filename(name, sizeof name);
|
||||
snprintf(path, sizeof path, "/tmp/%s", name);
|
||||
fx_path *rpath = fx_path_create_from_cstr(path);
|
||||
|
||||
fx_result status = fx_file_open(
|
||||
FX_DIRECTORY_ROOT,
|
||||
FX_VALUE_OBJECT(rpath),
|
||||
mode | FX_FILE_CREATE_ONLY,
|
||||
out);
|
||||
|
||||
if (fx_error_get_status_code(status) == FX_ERR_NAME_EXISTS) {
|
||||
fx_path_unref(rpath);
|
||||
continue;
|
||||
}
|
||||
|
||||
fx_path_unlink(rpath);
|
||||
fx_path_unref(rpath);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
fx_result fx_file_open_shadow(
|
||||
fx_file *original,
|
||||
enum fx_file_mode mode,
|
||||
fx_file **out)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_FILE,
|
||||
file_open_shadow,
|
||||
original,
|
||||
mode,
|
||||
out);
|
||||
}
|
||||
|
||||
const fx_path *fx_file_path(const fx_file *file)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_FILE, file_path, file);
|
||||
}
|
||||
|
||||
enum fx_status fx_file_stat(fx_file *file, struct fx_file_info *out)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_FILE, file_stat, file, out);
|
||||
}
|
||||
|
||||
enum fx_status fx_file_size(fx_file *file, size_t *out_len)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_FILE, file_size, file, out_len);
|
||||
}
|
||||
|
||||
enum fx_status fx_file_cursor(fx_file *file, size_t *out_pos)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_FILE, file_cursor, file, out_pos);
|
||||
}
|
||||
|
||||
enum fx_status fx_file_resize(fx_file *file, size_t len)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_FILE, file_resize, file, len);
|
||||
}
|
||||
|
||||
enum fx_status fx_file_seek(
|
||||
fx_file *file,
|
||||
long long offset,
|
||||
enum fx_seek_basis basis)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_FILE, file_seek, file, offset, basis);
|
||||
}
|
||||
|
||||
enum fx_status fx_file_swap_shadow(fx_file *main_file, fx_file *shadow_file)
|
||||
{
|
||||
struct fx_file_p *main_p
|
||||
= fx_object_get_private(main_file, FX_TYPE_FILE);
|
||||
struct fx_file_p *shadow_p
|
||||
= fx_object_get_private(main_file, FX_TYPE_FILE);
|
||||
return file_swap_shadow(main_p, shadow_p);
|
||||
}
|
||||
|
||||
enum fx_status fx_file_read(
|
||||
fx_file *file,
|
||||
size_t offset,
|
||||
size_t len,
|
||||
void *buf,
|
||||
size_t *nr_read)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_FILE,
|
||||
file_read,
|
||||
file,
|
||||
offset,
|
||||
len,
|
||||
buf,
|
||||
nr_read);
|
||||
}
|
||||
|
||||
enum fx_status fx_file_write(
|
||||
fx_file *file,
|
||||
size_t offset,
|
||||
size_t len,
|
||||
const void *buf,
|
||||
size_t *nr_written)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_FILE,
|
||||
file_write,
|
||||
file,
|
||||
offset,
|
||||
len,
|
||||
buf,
|
||||
nr_written);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void file_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_file_p *file = priv;
|
||||
}
|
||||
|
||||
static void file_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_file_p *file = priv;
|
||||
close(file->fd);
|
||||
|
||||
if (file->mode & FX_FILE_DELETE_ON_CLOSE) {
|
||||
fx_path_unlink(file->path);
|
||||
}
|
||||
|
||||
fx_path_unref(file->path);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_file)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_stream, FX_TYPE_STREAM)
|
||||
FX_INTERFACE_ENTRY(s_close) = stream_close;
|
||||
FX_INTERFACE_ENTRY(s_getc) = stream_getc;
|
||||
FX_INTERFACE_ENTRY(s_read) = stream_read;
|
||||
FX_INTERFACE_ENTRY(s_write) = stream_write;
|
||||
FX_INTERFACE_ENTRY(s_seek) = stream_seek;
|
||||
FX_INTERFACE_ENTRY(s_tell) = stream_tell;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_stream, FX_TYPE_STREAM)
|
||||
FX_TYPE_CLASS_END(fx_file)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_file)
|
||||
FX_TYPE_ID(0x495a73f6, 0xb8c3, 0x4e17, 0xb5f4, 0x6fc321f67c7b);
|
||||
FX_TYPE_EXTENDS(FX_TYPE_STREAM);
|
||||
FX_TYPE_CLASS(fx_file_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_file_p);
|
||||
FX_TYPE_INSTANCE_INIT(file_init);
|
||||
FX_TYPE_INSTANCE_FINI(file_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_file)
|
||||
@@ -1,21 +0,0 @@
|
||||
#include "misc.h"
|
||||
|
||||
#include <fx/random.h>
|
||||
|
||||
void z__fx_io_generate_tmp_filename(char *out, size_t len)
|
||||
{
|
||||
static const char *alphabet
|
||||
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
"01234567"
|
||||
"89+=-_.";
|
||||
static const size_t alphabet_len = 67;
|
||||
|
||||
fx_random_ctx *ctx = fx_random_global_ctx();
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
int v = fx_random_next_int64(ctx) % alphabet_len;
|
||||
out[i] = alphabet[v];
|
||||
}
|
||||
|
||||
out[len - 1] = 0;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef _IO_DARWIN_MISC_H_
|
||||
#define _IO_DARWIN_MISC_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
extern void z__fx_io_generate_tmp_filename(char *out, size_t len);
|
||||
|
||||
#endif
|
||||
@@ -1,486 +0,0 @@
|
||||
#include "posix.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <fx/io/file.h>
|
||||
#include <fx/io/path.h>
|
||||
#include <fx/string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct fx_path_p {
|
||||
fx_string *p_pathstr;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static fx_path *path_make_absolute(const struct fx_path_p *in)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static fx_path *path_make_relative(const struct fx_path_p *in)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static fx_path *path_make_canonical(const struct fx_path_p *in)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool path_is_absolute(const struct fx_path_p *path)
|
||||
{
|
||||
const char *s = fx_string_get_cstr(path->p_pathstr);
|
||||
return s[0] == '/';
|
||||
}
|
||||
|
||||
static const char *path_ptr(const struct fx_path_p *path)
|
||||
{
|
||||
return fx_string_get_cstr(path->p_pathstr);
|
||||
}
|
||||
|
||||
static enum fx_status path_stat(
|
||||
const struct fx_path_p *path,
|
||||
struct fx_file_info *out)
|
||||
{
|
||||
#if 0
|
||||
struct stat st;
|
||||
int err = stat(path_ptr(path), &st);
|
||||
|
||||
if (err != 0) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
|
||||
return fx_file_info_from_stat(&st, out);
|
||||
#endif
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static bool path_exists(const struct fx_path_p *path)
|
||||
{
|
||||
fx_file_info info;
|
||||
if (!FX_OK(path_stat(path, &info))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool path_is_file(const struct fx_path_p *path)
|
||||
{
|
||||
fx_file_info info;
|
||||
if (!FX_OK(path_stat(path, &info))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (info.attrib & FX_FILE_ATTRIB_NORMAL) != 0;
|
||||
}
|
||||
|
||||
static bool path_is_directory(const struct fx_path_p *path)
|
||||
{
|
||||
fx_file_info info;
|
||||
if (!FX_OK(path_stat(path, &info))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (info.attrib & FX_FILE_ATTRIB_DIRECTORY) != 0;
|
||||
}
|
||||
|
||||
static void append_path(struct fx_path_p *dest, const fx_string *src)
|
||||
{
|
||||
const char *src_cstr = fx_string_get_cstr(src);
|
||||
if (src_cstr[0] == '/') {
|
||||
fx_string_clear(dest->p_pathstr);
|
||||
fx_string_append_s(dest->p_pathstr, src);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fx_string_get_size(dest->p_pathstr, FX_STRLEN_NORMAL) > 0
|
||||
&& fx_string_get_last_char(dest->p_pathstr) != '/'
|
||||
&& fx_string_get_first_char(src) != '/') {
|
||||
fx_string_append_c(dest->p_pathstr, '/');
|
||||
}
|
||||
|
||||
fx_string_append_s(dest->p_pathstr, src);
|
||||
}
|
||||
|
||||
static enum fx_status path_unlink(const struct fx_path_p *path)
|
||||
{
|
||||
#if 0
|
||||
int err = remove(fx_string_get_cstr(path->p_pathstr));
|
||||
return err == 0 ? FX_SUCCESS
|
||||
: fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
#endif
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static enum fx_status path_get_directory(
|
||||
const struct fx_path_p *path,
|
||||
fx_path **out_dir_path)
|
||||
{
|
||||
fx_string *path_str = path->p_pathstr;
|
||||
long len = fx_string_get_size(path_str, FX_STRLEN_NORMAL);
|
||||
|
||||
const char *path_cstr = fx_string_get_cstr(path_str);
|
||||
char *sep = strrchr(path_cstr, '/');
|
||||
|
||||
if (!sep) {
|
||||
*out_dir_path = fx_path_create();
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
size_t dir_path_len = (size_t)(sep - path_cstr);
|
||||
fx_string *dir_path_s = fx_string_get_substr(path_str, 0, dir_path_len);
|
||||
|
||||
fx_path *dir_path
|
||||
= fx_path_create_from_cstr(fx_string_get_cstr(dir_path_s));
|
||||
fx_string_unref(dir_path_s);
|
||||
|
||||
*out_dir_path = dir_path;
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status path_get_filename(
|
||||
const struct fx_path_p *path,
|
||||
fx_string *out_name)
|
||||
{
|
||||
fx_string *path_str = path->p_pathstr;
|
||||
long len = fx_string_get_size(path_str, FX_STRLEN_NORMAL);
|
||||
|
||||
char *sep = strrchr(fx_string_get_cstr(path_str), '/');
|
||||
|
||||
if (!sep) {
|
||||
fx_string_append_s(out_name, path_str);
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
const char *filename = sep;
|
||||
while (*filename == '/' && *filename != '\0') {
|
||||
filename++;
|
||||
}
|
||||
|
||||
if (*filename == '\0') {
|
||||
fx_string_clear(out_name);
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
fx_string_append_cstr(out_name, filename);
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static size_t path_length(const struct fx_path_p *path)
|
||||
{
|
||||
return fx_string_get_size(path->p_pathstr, FX_STRLEN_NORMAL);
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_path *fx_path_create_root()
|
||||
{
|
||||
const char *system_drive = "/";
|
||||
size_t system_drive_len = strlen(system_drive);
|
||||
|
||||
fx_path *path = fx_path_create();
|
||||
if (!path) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_path_p *p = fx_object_get_private(path, FX_TYPE_PATH);
|
||||
|
||||
fx_string_append_cstr(p->p_pathstr, system_drive);
|
||||
if (system_drive[system_drive_len - 1] != '\\') {
|
||||
fx_string_append_c(p->p_pathstr, '\\');
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
fx_path *fx_path_create_from_cstr(const char *cstr)
|
||||
{
|
||||
fx_path *path = fx_path_create();
|
||||
if (!path) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_path_p *p = fx_object_get_private(path, FX_TYPE_PATH);
|
||||
|
||||
char prev = 0;
|
||||
|
||||
for (size_t i = 0; cstr[i]; i++) {
|
||||
char c = cstr[i];
|
||||
if (c == '\\') {
|
||||
c = '/';
|
||||
}
|
||||
|
||||
if (prev == '/' && c == '/') {
|
||||
continue;
|
||||
}
|
||||
|
||||
fx_string_append_c(p->p_pathstr, c);
|
||||
prev = c;
|
||||
}
|
||||
|
||||
while (fx_string_get_last_char(p->p_pathstr) == '/') {
|
||||
fx_string_pop_back(p->p_pathstr);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
fx_path *fx_path_get_system(fx_system_path path_type)
|
||||
{
|
||||
#if 0
|
||||
char path_buf[4096];
|
||||
const char *path_value = NULL, *default_value = NULL;
|
||||
switch (path_type) {
|
||||
case FX_PATH_ROOT:
|
||||
path_value = "/";
|
||||
break;
|
||||
case FX_PATH_CWD:
|
||||
if (getcwd(path_buf, sizeof path_buf) == NULL) {
|
||||
path_value = path_buf;
|
||||
}
|
||||
break;
|
||||
case FX_PATH_HOME:
|
||||
path_value = getenv("HOME");
|
||||
default_value = "~";
|
||||
break;
|
||||
case FX_PATH_CONFIG: {
|
||||
const char *home = getenv("HOME");
|
||||
path_value = getenv("XDG_CONFIG_HOME");
|
||||
snprintf(
|
||||
path_buf,
|
||||
sizeof path_buf,
|
||||
"%s/.config",
|
||||
home ? home : "~");
|
||||
default_value = path_buf;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (path_value) {
|
||||
return fx_path_create_from_cstr(path_value);
|
||||
}
|
||||
|
||||
if (default_value) {
|
||||
return fx_path_create_from_cstr(default_value);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fx_path *fx_path_duplicate(const fx_path *path)
|
||||
{
|
||||
fx_path *new_path = fx_path_create();
|
||||
if (!path) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_path_p *old_p = fx_object_get_private(path, FX_TYPE_PATH);
|
||||
struct fx_path_p *new_p = fx_object_get_private(new_path, FX_TYPE_PATH);
|
||||
|
||||
new_p->p_pathstr = fx_string_duplicate(old_p->p_pathstr);
|
||||
if (!new_p->p_pathstr) {
|
||||
fx_path_unref(new_path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new_path;
|
||||
}
|
||||
|
||||
fx_path *fx_path_join_array(const fx_value *values[], size_t nr_values)
|
||||
{
|
||||
fx_path *result = fx_path_create();
|
||||
if (!result) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_path_p *result_p
|
||||
= fx_object_get_private(result, FX_TYPE_PATH);
|
||||
|
||||
fx_stringstream *tmp = fx_stringstream_create();
|
||||
fx_string *value_s = fx_string_create();
|
||||
for (size_t i = 0; i < nr_values; i++) {
|
||||
if (!values[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fx_stringstream_reset(tmp);
|
||||
fx_value_to_string(values[i], tmp, NULL);
|
||||
|
||||
fx_string_clear(value_s);
|
||||
fx_string_append_cstr(value_s, fx_stringstream_get_cstr(tmp));
|
||||
append_path(result_p, value_s);
|
||||
}
|
||||
|
||||
fx_string_unref(value_s);
|
||||
fx_stringstream_unref(tmp);
|
||||
return result;
|
||||
}
|
||||
|
||||
fx_path *fx_path_join_list(size_t count, ...)
|
||||
{
|
||||
fx_path *result = fx_path_create();
|
||||
if (!result) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_path_p *result_p
|
||||
= fx_object_get_private(result, FX_TYPE_PATH);
|
||||
va_list arg;
|
||||
va_start(arg, count);
|
||||
|
||||
fx_stringstream *tmp = fx_stringstream_create();
|
||||
fx_string *value_s = fx_string_create();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const fx_value *value = va_arg(arg, const fx_value *);
|
||||
|
||||
fx_stringstream_reset(tmp);
|
||||
fx_value_to_string(value, tmp, NULL);
|
||||
|
||||
fx_string_clear(value_s);
|
||||
fx_string_append_cstr(value_s, fx_stringstream_get_cstr(tmp));
|
||||
append_path(result_p, value_s);
|
||||
}
|
||||
|
||||
fx_string_unref(value_s);
|
||||
fx_stringstream_unref(tmp);
|
||||
return result;
|
||||
}
|
||||
|
||||
fx_path *fx_path_make_absolute(const fx_path *in)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_PATH, path_make_absolute, in);
|
||||
}
|
||||
|
||||
fx_path *fx_path_make_relative(const fx_path *in)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_PATH, path_make_relative, in);
|
||||
}
|
||||
|
||||
fx_path *fx_path_make_canonical(const fx_path *in)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_PATH, path_make_canonical, in);
|
||||
}
|
||||
|
||||
bool fx_path_is_absolute(const fx_path *path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_PATH, path_is_absolute, path);
|
||||
}
|
||||
|
||||
bool fx_path_exists(const fx_path *path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_PATH, path_exists, path);
|
||||
}
|
||||
|
||||
bool fx_path_is_file(const fx_path *path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_PATH, path_is_file, path);
|
||||
}
|
||||
|
||||
bool fx_path_is_directory(const fx_path *path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_PATH, path_is_directory, path);
|
||||
}
|
||||
|
||||
enum fx_status fx_path_stat(const fx_path *path, struct fx_file_info *out)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_PATH, path_stat, path, out);
|
||||
}
|
||||
|
||||
enum fx_status fx_path_unlink(const fx_path *path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_PATH, path_unlink, path);
|
||||
}
|
||||
|
||||
enum fx_status fx_path_get_directory(
|
||||
const fx_path *path,
|
||||
fx_path **out_dir_path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_PATH,
|
||||
path_get_directory,
|
||||
path,
|
||||
out_dir_path);
|
||||
}
|
||||
|
||||
enum fx_status fx_path_get_filename(const fx_path *path, fx_string *out_name)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_PATH,
|
||||
path_get_filename,
|
||||
path,
|
||||
out_name);
|
||||
}
|
||||
|
||||
const char *fx_path_get_cstr(const fx_path *path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_PATH, path_ptr, path);
|
||||
}
|
||||
|
||||
size_t fx_path_length(const fx_path *path)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_PATH, path_length, path);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void path_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_path_p *path = priv;
|
||||
|
||||
path->p_pathstr = fx_string_create();
|
||||
if (!path->p_pathstr) {
|
||||
/* TODO return error */
|
||||
}
|
||||
}
|
||||
|
||||
void path_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_path_p *path = priv;
|
||||
|
||||
fx_string_unref(path->p_pathstr);
|
||||
}
|
||||
|
||||
static fx_status path_to_string(
|
||||
const fx_value *obj,
|
||||
fx_stream *out,
|
||||
const char *format)
|
||||
{
|
||||
struct fx_path_p *path
|
||||
= fx_object_get_private(obj->v_object, FX_TYPE_PATH);
|
||||
|
||||
return fx_stream_write_cstr(
|
||||
out,
|
||||
fx_string_get_cstr(path->p_pathstr),
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_path)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = path_to_string;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_END(fx_path)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_path)
|
||||
FX_TYPE_ID(0x56dc32eb, 0xea96, 0x46ed, 0x85d3, 0x760fa4ad61f4);
|
||||
FX_TYPE_CLASS(fx_path_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_path_p);
|
||||
FX_TYPE_INSTANCE_INIT(path_init);
|
||||
FX_TYPE_INSTANCE_FINI(path_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_path)
|
||||
@@ -1,32 +0,0 @@
|
||||
#include "posix.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fx/io/stream.h>
|
||||
#include <unistd.h>
|
||||
|
||||
fx_status fx_pipe_create(fx_iostream **reader, fx_iostream **writer)
|
||||
{
|
||||
#if 0
|
||||
int fds[2];
|
||||
int err = pipe(fds);
|
||||
if (err != 0) {
|
||||
return fx_status_from_errno(errno, FX_ERR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
fx_iostream *r = fx_iostream_create(FX_STREAM_READ, fds[0], true);
|
||||
fx_iostream *w = fx_iostream_create(FX_STREAM_WRITE, fds[1], true);
|
||||
|
||||
if (!r || !w) {
|
||||
fx_iostream_unref(r);
|
||||
fx_iostream_unref(w);
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
*reader = r;
|
||||
*writer = w;
|
||||
return FX_SUCCESS;
|
||||
#endif
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
#include <errno.h>
|
||||
#include <fx/error.h>
|
||||
#include <fx/io/file.h>
|
||||
#include <fx/status.h>
|
||||
|
||||
enum fx_status fx_status_from_errno(int error, enum fx_status default_value)
|
||||
{
|
||||
switch (error) {
|
||||
case 0:
|
||||
return FX_SUCCESS;
|
||||
case ENOENT:
|
||||
return FX_ERR_NO_ENTRY;
|
||||
case EEXIST:
|
||||
return FX_ERR_NAME_EXISTS;
|
||||
case ENOMEM:
|
||||
return FX_ERR_NO_MEMORY;
|
||||
case EINVAL:
|
||||
return FX_ERR_INVALID_ARGUMENT;
|
||||
case EIO:
|
||||
return FX_ERR_IO_FAILURE;
|
||||
case EISDIR:
|
||||
return FX_ERR_IS_DIRECTORY;
|
||||
case ENOTDIR:
|
||||
return FX_ERR_NOT_DIRECTORY;
|
||||
case EPERM:
|
||||
case EACCES:
|
||||
return FX_ERR_PERMISSION_DENIED;
|
||||
case ENOTSUP:
|
||||
case ENOSYS:
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
default:
|
||||
return default_value;
|
||||
}
|
||||
}
|
||||
|
||||
fx_result fx_result_from_errno_with_filepath(
|
||||
int error,
|
||||
const char *path,
|
||||
enum fx_status default_value)
|
||||
{
|
||||
switch (error) {
|
||||
case 0:
|
||||
return FX_RESULT_SUCCESS;
|
||||
case ENOENT:
|
||||
return FX_RESULT_STATUS_WITH_STRING(
|
||||
FX_ERR_NO_ENTRY,
|
||||
"Path @i{%s} does not exist",
|
||||
path);
|
||||
case ENOTDIR:
|
||||
return FX_RESULT_STATUS_WITH_STRING(
|
||||
FX_ERR_NOT_DIRECTORY,
|
||||
"Path @i{%s} is not a directory",
|
||||
path);
|
||||
case EISDIR:
|
||||
return FX_RESULT_STATUS_WITH_STRING(
|
||||
FX_ERR_IS_DIRECTORY,
|
||||
"Path @i{%s} is a directory",
|
||||
path);
|
||||
case EPERM:
|
||||
case EACCES:
|
||||
return FX_RESULT_STATUS_WITH_STRING(
|
||||
FX_ERR_PERMISSION_DENIED,
|
||||
"Permission denied while accessing path @i{%s}",
|
||||
path);
|
||||
default:
|
||||
return FX_RESULT_STATUS(
|
||||
fx_status_from_errno(error, default_value));
|
||||
}
|
||||
|
||||
return FX_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
fx_result fx_result_from_errno_with_subfilepath(
|
||||
int error,
|
||||
const char *path,
|
||||
const char *dir_path,
|
||||
enum fx_status default_value)
|
||||
{
|
||||
if (!dir_path) {
|
||||
return fx_result_propagate(fx_result_from_errno_with_filepath(
|
||||
error,
|
||||
path,
|
||||
default_value));
|
||||
}
|
||||
|
||||
switch (error) {
|
||||
case 0:
|
||||
return FX_RESULT_SUCCESS;
|
||||
case ENOENT:
|
||||
return FX_RESULT_STATUS_WITH_STRING(
|
||||
FX_ERR_NO_ENTRY,
|
||||
"Path @i{%s} in directory @i{%s} does not exist",
|
||||
path,
|
||||
dir_path);
|
||||
case ENOTDIR:
|
||||
return FX_RESULT_STATUS_WITH_STRING(
|
||||
FX_ERR_NOT_DIRECTORY,
|
||||
"Path @i{%s} in directory @i{%s} is not a directory",
|
||||
path,
|
||||
dir_path);
|
||||
case EISDIR:
|
||||
return FX_RESULT_STATUS_WITH_STRING(
|
||||
FX_ERR_IS_DIRECTORY,
|
||||
"Path @i{%s} in directory @i{%s} is a directory",
|
||||
path,
|
||||
dir_path);
|
||||
case EPERM:
|
||||
case EACCES:
|
||||
return FX_RESULT_STATUS_WITH_STRING(
|
||||
FX_ERR_PERMISSION_DENIED,
|
||||
"Permission denied while accessing path @i{%s} in "
|
||||
"directory @i{%s}",
|
||||
path,
|
||||
dir_path);
|
||||
default:
|
||||
return FX_RESULT_STATUS(
|
||||
fx_status_from_errno(error, default_value));
|
||||
}
|
||||
|
||||
return FX_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
#if 0
|
||||
enum fx_status fx_file_info_from_stat(
|
||||
const struct stat *st,
|
||||
struct fx_file_info *out)
|
||||
{
|
||||
out->length = st->st_size;
|
||||
|
||||
if (S_ISREG(st->st_mode)) {
|
||||
out->attrib |= FX_FILE_ATTRIB_NORMAL;
|
||||
}
|
||||
|
||||
if (S_ISDIR(st->st_mode)) {
|
||||
out->attrib |= FX_FILE_ATTRIB_DIRECTORY;
|
||||
}
|
||||
|
||||
if (S_ISBLK(st->st_mode)) {
|
||||
out->attrib |= FX_FILE_ATTRIB_BLOCK_DEVICE;
|
||||
}
|
||||
|
||||
if (S_ISCHR(st->st_mode)) {
|
||||
out->attrib |= FX_FILE_ATTRIB_CHAR_DEVICE;
|
||||
}
|
||||
|
||||
if (S_ISLNK(st->st_mode)) {
|
||||
out->attrib |= FX_FILE_ATTRIB_SYMLINK;
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
@@ -1,26 +0,0 @@
|
||||
#ifndef _IO_DARWIN_POSIX_H_
|
||||
#define _IO_DARWIN_POSIX_H_
|
||||
|
||||
#include <fx/error.h>
|
||||
#include <fx/status.h>
|
||||
|
||||
struct stat;
|
||||
struct fx_file_info;
|
||||
|
||||
extern enum fx_status fx_status_from_errno(
|
||||
int error,
|
||||
enum fx_status default_value);
|
||||
extern fx_result fx_result_from_errno_with_filepath(
|
||||
int error,
|
||||
const char *path,
|
||||
enum fx_status default_value);
|
||||
extern fx_result fx_result_from_errno_with_subfilepath(
|
||||
int error,
|
||||
const char *path,
|
||||
const char *dir_path,
|
||||
enum fx_status default_value);
|
||||
extern enum fx_status fx_file_info_from_stat(
|
||||
const struct stat *in,
|
||||
struct fx_file_info *out);
|
||||
|
||||
#endif
|
||||
@@ -1,149 +0,0 @@
|
||||
#include "posix.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fx/io/stream.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct fx_iostream_p {
|
||||
int s_fd;
|
||||
bool s_fd_close_on_release;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static uptr iostream_get_os_handle(const struct fx_iostream_p *stream)
|
||||
{
|
||||
return stream->s_fd;
|
||||
}
|
||||
|
||||
static uptr iostream_steal_os_handle(struct fx_iostream_p *stream)
|
||||
{
|
||||
uptr out = stream->s_fd;
|
||||
stream->s_fd = -1;
|
||||
stream->s_fd_close_on_release = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_iostream *fx_iostream_create(
|
||||
fx_stream_mode mode,
|
||||
uptr os_handle,
|
||||
bool close_handle_on_release)
|
||||
{
|
||||
fx_iostream *s = fx_object_create(FX_IO_TYPE_STREAM);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM);
|
||||
struct fx_iostream_p *p = fx_object_get_private(s, FX_IO_TYPE_STREAM);
|
||||
|
||||
cfg->s_mode = mode | Z__FX_STREAM_STATIC;
|
||||
p->s_fd = (int)os_handle;
|
||||
p->s_fd_close_on_release = close_handle_on_release;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
uptr fx_iostream_get_os_handle(const fx_iostream *stream)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_IO_TYPE_STREAM,
|
||||
iostream_get_os_handle,
|
||||
stream);
|
||||
}
|
||||
|
||||
uptr fx_iostream_steal_os_handle(fx_iostream *stream)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_IO_TYPE_STREAM,
|
||||
iostream_steal_os_handle,
|
||||
stream);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void iostream_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_iostream_p *stream = priv;
|
||||
}
|
||||
|
||||
static void iostream_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_iostream_p *stream = priv;
|
||||
|
||||
if (stream->s_fd_close_on_release) {
|
||||
close(stream->s_fd);
|
||||
}
|
||||
}
|
||||
|
||||
static enum fx_status stream_read(
|
||||
fx_stream *stream,
|
||||
void *buf,
|
||||
size_t count,
|
||||
size_t *nr_read)
|
||||
{
|
||||
struct fx_iostream_p *s
|
||||
= fx_object_get_private(stream, FX_IO_TYPE_STREAM);
|
||||
|
||||
long r = read(s->s_fd, buf, count);
|
||||
if (r < 0) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
*nr_read = r;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status stream_write(
|
||||
fx_stream *stream,
|
||||
const void *buf,
|
||||
size_t count,
|
||||
size_t *nr_written)
|
||||
{
|
||||
struct fx_iostream_p *s
|
||||
= fx_object_get_private(stream, FX_IO_TYPE_STREAM);
|
||||
|
||||
long w = write(s->s_fd, buf, count);
|
||||
if (w < 0) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
*nr_written = w;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_iostream)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_stream, FX_TYPE_STREAM)
|
||||
FX_INTERFACE_ENTRY(s_close) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_seek) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_tell) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_getc) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_read) = stream_read;
|
||||
FX_INTERFACE_ENTRY(s_write) = stream_write;
|
||||
FX_INTERFACE_ENTRY(s_reserve) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_stream, FX_TYPE_STREAM)
|
||||
FX_TYPE_CLASS_END(fx_iostream)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_iostream)
|
||||
FX_TYPE_ID(0xc0b1c3c9, 0xa9c6, 0x4910, 0x8786, 0x574b0696e7aa);
|
||||
FX_TYPE_NAME("fx.io.stream");
|
||||
FX_TYPE_EXTENDS(FX_TYPE_STREAM);
|
||||
FX_TYPE_CLASS(fx_iostream_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_iostream_p);
|
||||
FX_TYPE_INSTANCE_INIT(iostream_init);
|
||||
FX_TYPE_INSTANCE_FINI(iostream_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_iostream)
|
||||
@@ -60,7 +60,7 @@ enum fx_status fx_directory_open(
|
||||
}
|
||||
|
||||
HANDLE dir_handle = CreateFileA(
|
||||
fx_path_get_cstr(new_path), GENERIC_READ,
|
||||
fx_path_ptr(new_path), GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, INVALID_HANDLE_VALUE);
|
||||
|
||||
@@ -197,7 +197,7 @@ static bool move_into_directory(struct fx_directory_iterator *it, const char *di
|
||||
|
||||
state = push_iteration_state(it->_z);
|
||||
state->search_path = dir_path;
|
||||
state->search = FindFirstFileA(fx_path_get_cstr(search_path), &state->data);
|
||||
state->search = FindFirstFileA(fx_path_ptr(search_path), &state->data);
|
||||
|
||||
fx_path_release(search_path);
|
||||
fx_path_release(wildcard);
|
||||
@@ -224,7 +224,7 @@ static bool move_into_directory(struct fx_directory_iterator *it, const char *di
|
||||
static bool move_to_first_item(
|
||||
struct fx_directory_iterator *it, const struct fx_path *root_dir)
|
||||
{
|
||||
bool has_results = move_into_directory(it, fx_path_get_cstr(root_dir));
|
||||
bool has_results = move_into_directory(it, fx_path_ptr(root_dir));
|
||||
|
||||
if (!has_results) {
|
||||
return false;
|
||||
@@ -205,13 +205,13 @@ bool fx_path_is_absolute(const struct fx_path *path)
|
||||
|
||||
bool fx_path_exists(const struct fx_path *path)
|
||||
{
|
||||
DWORD attrib = GetFileAttributesA(fx_path_get_cstr(path));
|
||||
DWORD attrib = GetFileAttributesA(fx_path_ptr(path));
|
||||
return attrib != INVALID_FILE_ATTRIBUTES;
|
||||
}
|
||||
|
||||
bool fx_path_is_file(const struct fx_path *path)
|
||||
{
|
||||
DWORD attrib = GetFileAttributesA(fx_path_get_cstr(path));
|
||||
DWORD attrib = GetFileAttributesA(fx_path_ptr(path));
|
||||
if (attrib == INVALID_FILE_ATTRIBUTES) {
|
||||
return false;
|
||||
}
|
||||
@@ -221,7 +221,7 @@ bool fx_path_is_file(const struct fx_path *path)
|
||||
|
||||
bool fx_path_is_directory(const struct fx_path *path)
|
||||
{
|
||||
DWORD attrib = GetFileAttributesA(fx_path_get_cstr(path));
|
||||
DWORD attrib = GetFileAttributesA(fx_path_ptr(path));
|
||||
if (attrib == INVALID_FILE_ATTRIBUTES) {
|
||||
return false;
|
||||
}
|
||||
@@ -229,7 +229,7 @@ bool fx_path_is_directory(const struct fx_path *path)
|
||||
return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
}
|
||||
|
||||
const char *fx_path_get_cstr(const struct fx_path *path)
|
||||
const char *fx_path_ptr(const struct fx_path *path)
|
||||
{
|
||||
return fx_string_get_cstr(path->pathstr);
|
||||
}
|
||||
+1
-4
@@ -11,10 +11,7 @@ int main(int argc, const char **argv)
|
||||
|
||||
fx_directory *dir;
|
||||
fx_result result = fx_directory_open(
|
||||
NULL,
|
||||
FX_CSTR(path),
|
||||
FX_DIRECTORY_OPEN_CREATE_INTERMEDIATE,
|
||||
&dir);
|
||||
NULL, FX_RV_PATH(path), FX_DIRECTORY_OPEN_CREATE_INTERMEDIATE, &dir);
|
||||
if (fx_result_is_error(result)) {
|
||||
fx_throw(result);
|
||||
return -1;
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#include <fx/io/pipe.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
fx_iostream *read = NULL, *write = NULL;
|
||||
fx_status status = fx_pipe_create(&read, &write);
|
||||
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr,
|
||||
"failed to create pipe: %s\n",
|
||||
fx_status_description(status));
|
||||
return -1;
|
||||
}
|
||||
|
||||
fx_stream_write_cstr(write, "Hello, world!\n", NULL);
|
||||
|
||||
char buf[128];
|
||||
fx_stream_read_line(read, buf, sizeof buf);
|
||||
|
||||
printf("read from pipe: %s\n", buf);
|
||||
return 0;
|
||||
}
|
||||
+1
-1
@@ -9,7 +9,7 @@ int main(int argc, const char **argv)
|
||||
const char *path = argv[1];
|
||||
|
||||
fx_directory *dir;
|
||||
fx_result result = fx_directory_open(NULL, FX_CSTR(path), 0, &dir);
|
||||
fx_result result = fx_directory_open(NULL, FX_RV_PATH(path), 0, &dir);
|
||||
if (fx_result_is_error(result)) {
|
||||
fx_throw(result);
|
||||
return -1;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user