From 56667df53720309ac001a242ac2696691734f277 Mon Sep 17 00:00:00 2001 From: Dominik Wagner Date: Sat, 29 May 2021 10:44:49 +0200 Subject: [PATCH 01/13] adding toml11 as it seems that cpptoml was discontinued and won't support tomlv1.0 anymore --- .gitmodules | 3 +++ submodules/toml11 | 1 + 2 files changed, 4 insertions(+) create mode 160000 submodules/toml11 diff --git a/.gitmodules b/.gitmodules index 5e4d775..91506bd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "submodules/cpptoml"] path = submodules/cpptoml url = https://github.com/skystrife/cpptoml.git +[submodule "submodules/toml11"] + path = submodules/toml11 + url = git@github.com:ToruNiina/toml11.git diff --git a/submodules/toml11 b/submodules/toml11 new file mode 160000 index 0000000..6473810 --- /dev/null +++ b/submodules/toml11 @@ -0,0 +1 @@ +Subproject commit 647381020ef04b5d41d540ec489eba45e82d90a7 From f6bf380c5bf17ecd7d8b8c293a18cd711e521edb Mon Sep 17 00:00:00 2001 From: Dominik Wagner Date: Sun, 30 May 2021 13:20:03 +0200 Subject: [PATCH 02/13] towards basic parsing --- toml-examples/wrong.toml | 18 + tomlutil.xcodeproj/project.pbxproj | 73 +++- .../xcshareddata/xcschemes/tomlutil.xcscheme | 16 +- tomlutil/LMPTOMLSerialization.mm | 391 ++++++++++-------- tomlutil/LMP_cpptoml_visitors.h | 177 -------- tomlutil/LMP_toml_visitors.h | 287 +++++++++++++ 6 files changed, 599 insertions(+), 363 deletions(-) create mode 100644 toml-examples/wrong.toml delete mode 100644 tomlutil/LMP_cpptoml_visitors.h create mode 100644 tomlutil/LMP_toml_visitors.h diff --git a/toml-examples/wrong.toml b/toml-examples/wrong.toml new file mode 100644 index 0000000..866cb12 --- /dev/null +++ b/toml-examples/wrong.toml @@ -0,0 +1,18 @@ +################################################################################ +## Comment + +# Speak your mind with the hash symbol. They go from the symbol to the end of +# the line. + + +################################################################################ +## Table + +# Tables (also known as hash tables or dictionaries) are collections of +# key/value pairs. They appear in square brackets on a line by themselves. + +asdfpoin1!@ j= ;alskjfasdf + +[table] + +key = "value" # Yeah, you can do this. diff --git a/tomlutil.xcodeproj/project.pbxproj b/tomlutil.xcodeproj/project.pbxproj index 429f450..b5e1270 100644 --- a/tomlutil.xcodeproj/project.pbxproj +++ b/tomlutil.xcodeproj/project.pbxproj @@ -28,9 +28,31 @@ F22CB70A217B1FD600D1565D /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; F22CB712217B239300D1565D /* LMPTOMLSerialization.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LMPTOMLSerialization.h; sourceTree = ""; }; F22CB713217B239300D1565D /* LMPTOMLSerialization.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LMPTOMLSerialization.mm; sourceTree = ""; }; - F22CB715217B2B1C00D1565D /* cpptoml.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = cpptoml.h; path = submodules/cpptoml/include/cpptoml.h; sourceTree = SOURCE_ROOT; }; + F23131842663608400AFE2BA /* toml.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = toml.hpp; path = submodules/toml11/toml.hpp; sourceTree = SOURCE_ROOT; }; F2962202217F303B00C44751 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - F2BC7534217B44D10056FAED /* LMP_cpptoml_visitors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LMP_cpptoml_visitors.h; sourceTree = ""; }; + F2BC7534217B44D10056FAED /* LMP_toml_visitors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LMP_toml_visitors.h; sourceTree = ""; }; + F2FAE3732663A3DC0080F81A /* region.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = region.hpp; sourceTree = ""; }; + F2FAE3742663A3DC0080F81A /* datetime.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = datetime.hpp; sourceTree = ""; }; + F2FAE3752663A3DC0080F81A /* serializer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = serializer.hpp; sourceTree = ""; }; + F2FAE3762663A3DC0080F81A /* utility.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = utility.hpp; sourceTree = ""; }; + F2FAE3772663A3DC0080F81A /* get.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = get.hpp; sourceTree = ""; }; + F2FAE3782663A3DC0080F81A /* parser.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = parser.hpp; sourceTree = ""; }; + F2FAE3792663A3DC0080F81A /* literal.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = literal.hpp; sourceTree = ""; }; + F2FAE37A2663A3DC0080F81A /* macros.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = macros.hpp; sourceTree = ""; }; + F2FAE37B2663A3DC0080F81A /* traits.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = traits.hpp; sourceTree = ""; }; + F2FAE37C2663A3DC0080F81A /* comments.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = comments.hpp; sourceTree = ""; }; + F2FAE37D2663A3DC0080F81A /* source_location.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = source_location.hpp; sourceTree = ""; }; + F2FAE37E2663A3DC0080F81A /* combinator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = combinator.hpp; sourceTree = ""; }; + F2FAE37F2663A3DC0080F81A /* value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = value.hpp; sourceTree = ""; }; + F2FAE3802663A3DC0080F81A /* from.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = from.hpp; sourceTree = ""; }; + F2FAE3812663A3DC0080F81A /* result.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = result.hpp; sourceTree = ""; }; + F2FAE3822663A3DC0080F81A /* into.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = into.hpp; sourceTree = ""; }; + F2FAE3832663A3DC0080F81A /* lexer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = lexer.hpp; sourceTree = ""; }; + F2FAE3842663A3DC0080F81A /* string.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = string.hpp; sourceTree = ""; }; + F2FAE3852663A3DC0080F81A /* storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = storage.hpp; sourceTree = ""; }; + F2FAE3862663A3DC0080F81A /* color.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = color.hpp; sourceTree = ""; }; + F2FAE3872663A3DC0080F81A /* types.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = types.hpp; sourceTree = ""; }; + F2FAE3882663A3DC0080F81A /* exception.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = exception.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -66,13 +88,44 @@ F22CB70A217B1FD600D1565D /* main.m */, F22CB712217B239300D1565D /* LMPTOMLSerialization.h */, F22CB713217B239300D1565D /* LMPTOMLSerialization.mm */, - F2BC7534217B44D10056FAED /* LMP_cpptoml_visitors.h */, - F22CB715217B2B1C00D1565D /* cpptoml.h */, + F2BC7534217B44D10056FAED /* LMP_toml_visitors.h */, + F23131842663608400AFE2BA /* toml.hpp */, + F2FAE3722663A3DC0080F81A /* toml */, F2962202217F303B00C44751 /* Info.plist */, ); path = tomlutil; sourceTree = ""; }; + F2FAE3722663A3DC0080F81A /* toml */ = { + isa = PBXGroup; + children = ( + F2FAE3732663A3DC0080F81A /* region.hpp */, + F2FAE3742663A3DC0080F81A /* datetime.hpp */, + F2FAE3752663A3DC0080F81A /* serializer.hpp */, + F2FAE3762663A3DC0080F81A /* utility.hpp */, + F2FAE3772663A3DC0080F81A /* get.hpp */, + F2FAE3782663A3DC0080F81A /* parser.hpp */, + F2FAE3792663A3DC0080F81A /* literal.hpp */, + F2FAE37A2663A3DC0080F81A /* macros.hpp */, + F2FAE37B2663A3DC0080F81A /* traits.hpp */, + F2FAE37C2663A3DC0080F81A /* comments.hpp */, + F2FAE37D2663A3DC0080F81A /* source_location.hpp */, + F2FAE37E2663A3DC0080F81A /* combinator.hpp */, + F2FAE37F2663A3DC0080F81A /* value.hpp */, + F2FAE3802663A3DC0080F81A /* from.hpp */, + F2FAE3812663A3DC0080F81A /* result.hpp */, + F2FAE3822663A3DC0080F81A /* into.hpp */, + F2FAE3832663A3DC0080F81A /* lexer.hpp */, + F2FAE3842663A3DC0080F81A /* string.hpp */, + F2FAE3852663A3DC0080F81A /* storage.hpp */, + F2FAE3862663A3DC0080F81A /* color.hpp */, + F2FAE3872663A3DC0080F81A /* types.hpp */, + F2FAE3882663A3DC0080F81A /* exception.hpp */, + ); + name = toml; + path = submodules/toml11/toml; + sourceTree = SOURCE_ROOT; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -143,7 +196,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -188,7 +241,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -202,7 +255,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -241,7 +294,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = macosx; @@ -251,11 +304,9 @@ F22CB70F217B1FD600D1565D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CODE_SIGN_STYLE = Automatic; CREATE_INFOPLIST_SECTION_IN_BINARY = YES; INFOPLIST_FILE = tomlutil/Info.plist; - MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = productions.monkey.lone.tomlutil; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -264,11 +315,9 @@ F22CB710217B1FD600D1565D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CODE_SIGN_STYLE = Automatic; CREATE_INFOPLIST_SECTION_IN_BINARY = YES; INFOPLIST_FILE = tomlutil/Info.plist; - MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = productions.monkey.lone.tomlutil; PRODUCT_NAME = "$(TARGET_NAME)"; }; diff --git a/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme b/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme index 6ac5dad..e89e474 100644 --- a/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme +++ b/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme @@ -27,8 +27,6 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> - - - - + + + isEnabled = "YES"> + isEnabled = "NO"> + + - - #include #include #include +#include "LMP_toml_visitors.h" + + NSErrorDomain const LMPTOMLErrorDomain = @"productions.monkey.lone.TOML"; static NSInteger const LMPTOMLParseErrorCode = 7031; static NSInteger const LMPTOMLWriteErrorCode = 7001; @@ -27,182 +30,238 @@ @implementation LMPTOMLSerialization +template struct overloaded : Ts... { using Ts::operator()...; }; +// explicit deduction guide (not needed as of C++20) +template overloaded(Ts...) -> overloaded; + + (NSDictionary *)TOMLObjectWithData:(NSData *)data error:(NSError **)error { - try { - char *bytes = (char *)data.bytes; - membuf sbuf(bytes, bytes + data.length); - std::istream in(&sbuf); - cpptoml::parser p{in}; - std::shared_ptr g = p.parse(); -// std::cout << (*g) << std::endl; - - // convert table to standard Objective-C objects - toml_nsdictionary_writer dw; - g->accept(dw); - NSDictionary *result = dw.dictionary(); - - return result; - } catch (const cpptoml::parse_exception& e) { - if (error) { - *error = [NSError errorWithDomain:LMPTOMLErrorDomain - code:LMPTOMLParseErrorCode - userInfo:@{ - NSLocalizedDescriptionKey : @"Input TOML could not be parsed", - NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:@"%s", e.what()], - }]; - } - return nil; - } -} + + try { + char *bytes = (char *)data.bytes; -static void writeDictionaryToTable(NSDictionary *dict, std::shared_ptr table) { - for (NSString *key in dict.keyEnumerator) { - auto cppKey = std::string(key.UTF8String); - auto cppValue = ObjectToValue(dict[key]); - table->insert(cppKey, cppValue); - } -} +// seems to have issues now with modern cpp, need to fix. only reads two bytes before it ends. +// membuf sbuf(bytes, bytes + data.length); +// std::istream stream(&sbuf); + + std::istringstream stream(std::string(bytes, data.length)); -static std::shared_ptr ObjectToValue(id objectValue) { - if ([objectValue isKindOfClass:[NSString class]]) { - NSString *val = objectValue; - return cpptoml::make_value(std::string(val.UTF8String)); - } else if ([objectValue isKindOfClass:[NSNumber class]]) { - NSNumber *val = objectValue; - if ((__bridge CFBooleanRef)val == kCFBooleanTrue || - (__bridge CFBooleanRef)val == kCFBooleanFalse) { - return cpptoml::make_value(val.boolValue); - } else if (CFNumberIsFloatType((__bridge CFNumberRef)val)) { - return cpptoml::make_value(val.doubleValue); - } else { - return cpptoml::make_value(val.longLongValue); - } - } else if ([objectValue isKindOfClass:[NSArray class]]) { - if ([[objectValue firstObject] isKindOfClass:[NSDictionary class]]) { - return ArrayToTableArray(objectValue); - } else { - return ArrayToArray(objectValue); - } - } else if ([objectValue isKindOfClass:[NSDictionary class]]) { - return DictionaryToTable(objectValue); - } else if ([objectValue isKindOfClass:[NSDateComponents class]]) { - NSDateComponents *dc = objectValue; - if (YES) { - if (dc.year == NSDateComponentUndefined) { - cpptoml::local_time lt; - if (dc.hour != NSDateComponentUndefined) { - lt.hour = (int)dc.hour; - } - if (dc.minute != NSDateComponentUndefined) { - lt.minute = (int)dc.minute; - } - if (dc.second != NSDateComponentUndefined) { - lt.second = (int)dc.second; - } - if (dc.nanosecond != NSDateComponentUndefined) { - lt.microsecond = (int)(dc.nanosecond / 1000); - } - return cpptoml::make_value(lt); - } + const auto data = toml::parse(stream); +// cpptoml::parser p{in}; +// std::shared_ptr g = p.parse(); + // std::cout << (*g) << std::endl; - cpptoml::local_date ld; - ld.year = (int)dc.year; - ld.month = (int)dc.month; - ld.day = (int)dc.day; - if (dc.hour == NSDateComponentUndefined) { - return cpptoml::make_value(ld); - } + toml_nsdictionary_writer dw; - cpptoml::local_datetime ldt; - static_cast(ldt) = ld; - ldt.hour = (int)dc.hour; - ldt.minute = (int)dc.minute; - ldt.second = (int)dc.second; - if (dc.nanosecond != NSDateComponentUndefined) { - ldt.microsecond = (int)(dc.nanosecond / 1000); - } - if (!dc.timeZone) { - return cpptoml::make_value(ldt); - } + dw.visit(toml::get(data)); + + // convert table to standard Objective-C objects +// toml_nsdictionary_writer dw; + // g->accept(dw); + - cpptoml::offset_datetime odt; - static_cast(odt) = ldt; - int minutesFromGMT = (int)[dc.timeZone secondsFromGMT] / 60; - odt.hour_offset = minutesFromGMT / 60; - odt.minute_offset = minutesFromGMT % 60; - return cpptoml::make_value(odt); - } - - } else { - auto reason = std::string([NSString stringWithFormat:@"%@ cannot be encoded to TOML", objectValue].UTF8String); - throw std::out_of_range{reason}; - } -} + // std::cout << " --- " << data << " --- \n"; -static std::shared_ptr ArrayToTableArray(NSArray *array) { - auto tarr = cpptoml::make_table_array(); - for (NSDictionary *objectValue in array) { - tarr->push_back(DictionaryToTable(objectValue)); - } - return tarr; -} + toml::visit(overloaded { + [](const toml::table &val) -> void {std::cout << "table"; }, + [](const auto& val) -> void { + std::cout << "some visit"; + //val << std::endl; + } + }, data); -static std::shared_ptr ArrayToArray(NSArray *array) { - auto arr = cpptoml::make_array(); - for (id objectValue in array) { - auto val = ObjectToValue(objectValue); - if (val->is_value()) { - // FIXME: there needs to be better cpp foo to make this not be redundant - if ([objectValue isKindOfClass:[NSString class]]) { - NSString *val = objectValue; - arr->push_back(std::string(val.UTF8String)); - } else if ([objectValue isKindOfClass:[NSNumber class]]) { - NSNumber *val = objectValue; - if ((__bridge CFBooleanRef)val == kCFBooleanTrue || - (__bridge CFBooleanRef)val == kCFBooleanFalse) { - arr->push_back((bool)val.boolValue); - } else if (CFNumberIsFloatType((__bridge CFNumberRef)val)) { - arr->push_back(val.doubleValue); - } else { - arr->push_back(val.longLongValue); - } + + NSDictionary *result = dw.dictionary(); + + return result; + } catch (const toml::exception& e) { + if (error) { + *error = [NSError errorWithDomain:LMPTOMLErrorDomain + code:LMPTOMLParseErrorCode + userInfo:@{ + NSLocalizedDescriptionKey : @"Input TOML could not be parsed", + NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:@"%s", e.what()], + }]; } - } else if (val->is_array()) { - arr->push_back(val->as_array()); - } else if (val->is_table()) { - arr->push_back(val->as_array()); + return nil; } - } - return arr; -} - -static std::shared_ptr DictionaryToTable(NSDictionary *dictionary) { - auto tbl = cpptoml::make_table(); - writeDictionaryToTable(dictionary, tbl); - return tbl; + return nil; +// try { +// char *bytes = (char *)data.bytes; +// membuf sbuf(bytes, bytes + data.length); +// std::istream in(&sbuf); +// cpptoml::parser p{in}; +// std::shared_ptr g = p.parse(); +// // std::cout << (*g) << std::endl; +// +// // convert table to standard Objective-C objects +// toml_nsdictionary_writer dw; +// g->accept(dw); +// NSDictionary *result = dw.dictionary(); +// +// return result; +// } catch (const cpptoml::parse_exception& e) { +// if (error) { +// *error = [NSError errorWithDomain:LMPTOMLErrorDomain +// code:LMPTOMLParseErrorCode +// userInfo:@{ +// NSLocalizedDescriptionKey : @"Input TOML could not be parsed", +// NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:@"%s", e.what()], +// }]; +// } +// return nil; +// } } +//static void writeDictionaryToTable(NSDictionary *dict, std::shared_ptr table) { +// for (NSString *key in dict.keyEnumerator) { +// auto cppKey = std::string(key.UTF8String); +// auto cppValue = ObjectToValue(dict[key]); +// table->insert(cppKey, cppValue); +// } +//} +// +//static std::shared_ptr ObjectToValue(id objectValue) { +// if ([objectValue isKindOfClass:[NSString class]]) { +// NSString *val = objectValue; +// return cpptoml::make_value(std::string(val.UTF8String)); +// } else if ([objectValue isKindOfClass:[NSNumber class]]) { +// NSNumber *val = objectValue; +// if ((__bridge CFBooleanRef)val == kCFBooleanTrue || +// (__bridge CFBooleanRef)val == kCFBooleanFalse) { +// return cpptoml::make_value(val.boolValue); +// } else if (CFNumberIsFloatType((__bridge CFNumberRef)val)) { +// return cpptoml::make_value(val.doubleValue); +// } else { +// return cpptoml::make_value(val.longLongValue); +// } +// } else if ([objectValue isKindOfClass:[NSArray class]]) { +// if ([[objectValue firstObject] isKindOfClass:[NSDictionary class]]) { +// return ArrayToTableArray(objectValue); +// } else { +// return ArrayToArray(objectValue); +// } +// } else if ([objectValue isKindOfClass:[NSDictionary class]]) { +// return DictionaryToTable(objectValue); +// } else if ([objectValue isKindOfClass:[NSDateComponents class]]) { +// NSDateComponents *dc = objectValue; +// if (YES) { +// if (dc.year == NSDateComponentUndefined) { +// cpptoml::local_time lt; +// if (dc.hour != NSDateComponentUndefined) { +// lt.hour = (int)dc.hour; +// } +// if (dc.minute != NSDateComponentUndefined) { +// lt.minute = (int)dc.minute; +// } +// if (dc.second != NSDateComponentUndefined) { +// lt.second = (int)dc.second; +// } +// if (dc.nanosecond != NSDateComponentUndefined) { +// lt.microsecond = (int)(dc.nanosecond / 1000); +// } +// return cpptoml::make_value(lt); +// } +// +// cpptoml::local_date ld; +// ld.year = (int)dc.year; +// ld.month = (int)dc.month; +// ld.day = (int)dc.day; +// if (dc.hour == NSDateComponentUndefined) { +// return cpptoml::make_value(ld); +// } +// +// cpptoml::local_datetime ldt; +// static_cast(ldt) = ld; +// ldt.hour = (int)dc.hour; +// ldt.minute = (int)dc.minute; +// ldt.second = (int)dc.second; +// if (dc.nanosecond != NSDateComponentUndefined) { +// ldt.microsecond = (int)(dc.nanosecond / 1000); +// } +// if (!dc.timeZone) { +// return cpptoml::make_value(ldt); +// } +// +// cpptoml::offset_datetime odt; +// static_cast(odt) = ldt; +// int minutesFromGMT = (int)[dc.timeZone secondsFromGMT] / 60; +// odt.hour_offset = minutesFromGMT / 60; +// odt.minute_offset = minutesFromGMT % 60; +// return cpptoml::make_value(odt); +// } +// +// } else { +// auto reason = std::string([NSString stringWithFormat:@"%@ cannot be encoded to TOML", objectValue].UTF8String); +// throw std::out_of_range{reason}; +// } +//} +// +//static std::shared_ptr ArrayToTableArray(NSArray *array) { +// auto tarr = cpptoml::make_table_array(); +// for (NSDictionary *objectValue in array) { +// tarr->push_back(DictionaryToTable(objectValue)); +// } +// return tarr; +//} +// +//static std::shared_ptr ArrayToArray(NSArray *array) { +// auto arr = cpptoml::make_array(); +// for (id objectValue in array) { +// auto val = ObjectToValue(objectValue); +// if (val->is_value()) { +// // FIXME: there needs to be better cpp foo to make this not be redundant +// if ([objectValue isKindOfClass:[NSString class]]) { +// NSString *val = objectValue; +// arr->push_back(std::string(val.UTF8String)); +// } else if ([objectValue isKindOfClass:[NSNumber class]]) { +// NSNumber *val = objectValue; +// if ((__bridge CFBooleanRef)val == kCFBooleanTrue || +// (__bridge CFBooleanRef)val == kCFBooleanFalse) { +// arr->push_back((bool)val.boolValue); +// } else if (CFNumberIsFloatType((__bridge CFNumberRef)val)) { +// arr->push_back(val.doubleValue); +// } else { +// arr->push_back(val.longLongValue); +// } +// } +// } else if (val->is_array()) { +// arr->push_back(val->as_array()); +// } else if (val->is_table()) { +// arr->push_back(val->as_array()); +// } +// } +// return arr; +//} +// +// +//static std::shared_ptr DictionaryToTable(NSDictionary *dictionary) { +// auto tbl = cpptoml::make_table(); +// writeDictionaryToTable(dictionary, tbl); +// return tbl; +//} + + (NSData *)dataWithTOMLObject:(NSDictionary *)tomlObject error:(NSError **)error { - try { - auto root = DictionaryToTable(tomlObject); - - std::stringstream s(""); - s << *root; - std::string str = s.str(); - NSData *result = [NSData dataWithBytes:str.data() length:str.length()]; - return result; - } catch (const std::invalid_argument& e) { - if (error) { - *error = [NSError errorWithDomain:LMPTOMLErrorDomain - code:LMPTOMLWriteErrorCode - userInfo:@{ - NSLocalizedDescriptionKey : @"Input objects could not be converted to TOML", - NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:@"%s", e.what()], - }]; - } - return nil; - } +// try { +// auto root = DictionaryToTable(tomlObject); +// +// std::stringstream s(""); +// s << *root; +// std::string str = s.str(); +// NSData *result = [NSData dataWithBytes:str.data() length:str.length()]; +// return result; +// } catch (const std::invalid_argument& e) { +// if (error) { +// *error = [NSError errorWithDomain:LMPTOMLErrorDomain +// code:LMPTOMLWriteErrorCode +// userInfo:@{ +// NSLocalizedDescriptionKey : @"Input objects could not be converted to TOML", +// NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:@"%s", e.what()], +// }]; +// } +// return nil; +// } + return nil; } static NSString *TOMLTimeStringFromComponents(NSDateComponents *dc) { diff --git a/tomlutil/LMP_cpptoml_visitors.h b/tomlutil/LMP_cpptoml_visitors.h deleted file mode 100644 index b5d063d..0000000 --- a/tomlutil/LMP_cpptoml_visitors.h +++ /dev/null @@ -1,177 +0,0 @@ -// -// LMP_cpptoml_visitors.h -// tomlutil -// -// Created by dom on 10/20/18. -// Copyright © 2018 Lone Monkey Productions. All rights reserved. -// - -#ifndef LMP_cpptoml_visitors_h -#define LMP_cpptoml_visitors_h - -/** - * A visitor for toml objects that writes to an NSMutableDictionary - */ -class toml_nsdictionary_writer { -public: - toml_nsdictionary_writer() { - currentDictionary_ = resultContainer_ = [NSMutableDictionary new]; - currentKey_ = @"TOMLRoot"; - } - - NSDictionary *dictionary() { - return [resultContainer_[@"TOMLRoot"] copy]; - } - - - void visit(const cpptoml::value& v) { - id value = [NSString stringWithUTF8String:v.get().c_str()]; - writeValue(value); - } - - void visit(const cpptoml::value& v) { - id value = [NSNumber numberWithLongLong:v.get()]; - writeValue(value); - } - - void visit(const cpptoml::value& v) { - id value = [NSNumber numberWithDouble:v.get()]; - writeValue(value); - } - - void visit(const cpptoml::value& v) { - id value = ({ - cpptoml::local_date ld = v.get(); - NSDateComponents *result = [NSDateComponents new]; - result.year = ld.year; - result.month = ld.month; - result.day = ld.day; - result; - }); - writeValue(value); - } - - void visit(const cpptoml::value& v) { - id value = ({ - cpptoml::local_time ld = v.get(); - NSDateComponents *result = [NSDateComponents new]; - result.hour = ld.hour; - result.minute = ld.minute; - result.second = ld.second; - result.nanosecond = ld.microsecond * 1000; - result; - }); - writeValue(value); - } - - void visit(const cpptoml::value& v) { - id value = ({ - cpptoml::local_datetime ld = v.get(); - NSDateComponents *result = [NSDateComponents new]; - result.year = ld.year; - result.month = ld.month; - result.day = ld.day; - result.hour = ld.hour; - result.minute = ld.minute; - result.second = ld.second; - result.nanosecond = ld.microsecond * 1000; - result; - }); - writeValue(value); - } - - void visit(const cpptoml::value& v) { - id value = ({ - cpptoml::offset_datetime ld = v.get(); - NSDateComponents *result = [NSDateComponents new]; - result.year = ld.year; - result.month = ld.month; - result.day = ld.day; - result.hour = ld.hour; - result.minute = ld.minute; - result.second = ld.second; - result.nanosecond = ld.microsecond * 1000; - result.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:(ld.hour_offset * 60 + ld.minute_offset) * 60]; - result; - }); - writeValue(value); - } - - void visit(const cpptoml::value& v) { - id value = v.get() ? @YES : @NO; - writeValue(value); - } - - void visit(const cpptoml::array& arr) { - withContainerIsDictionary( NO, ^{ - for (auto it = arr.get().begin(); it != arr.get().end(); it++) { - (*it)->accept(*this); - } - }); - } - - void visit(const cpptoml::table_array& tarr) { - - withContainerIsDictionary( NO, ^{ - auto arr = tarr.get(); - for (auto ait = arr.begin(); ait != arr.end(); ait++) { - (*ait)->accept(*this); - } - }); - - } - - void visit(const cpptoml::table& t) { - withContainerIsDictionary( YES, ^{ - for (auto it = t.begin(); it != t.end(); it++) { - currentKey_ = [NSString stringWithUTF8String:it->first.c_str()]; - it->second->accept(*this); - } - }); - } - -private: - - void withContainerIsDictionary(BOOL isDictionary, dispatch_block_t stuff) { - NSMutableArray *array = currentArray_; - NSMutableDictionary *dict = currentDictionary_; - NSString *key = currentKey_; - - if (isDictionary) { - NSMutableDictionary *contextDictionary = [NSMutableDictionary new]; - writeValue(contextDictionary); - - currentDictionary_ = contextDictionary; - currentArray_ = nil; - } else { - NSMutableArray *contextArray = [NSMutableArray new]; - writeValue(contextArray); - - currentArray_ = contextArray; - } - - stuff(); - - currentKey_ = key; - currentArray_ = array; - currentDictionary_ = dict; - } - - void writeValue(id value) { - if (currentArray_) { - [currentArray_ addObject:value]; - } else { - currentDictionary_[currentKey_] = value; - } - } - - NSMutableDictionary *resultContainer_; - NSMutableDictionary *currentDictionary_; - NSString *currentKey_; - NSMutableArray *currentArray_; -}; - - - - -#endif /* LMP_cpptoml_visitors_h */ diff --git a/tomlutil/LMP_toml_visitors.h b/tomlutil/LMP_toml_visitors.h new file mode 100644 index 0000000..5018db6 --- /dev/null +++ b/tomlutil/LMP_toml_visitors.h @@ -0,0 +1,287 @@ +// +// LMP_cpptoml_visitors.h +// tomlutil +// +// Created by dom on 10/20/18. +// Copyright © 2018 Lone Monkey Productions. All rights reserved. +// + +#ifndef LMP_toml_visitors_h +#define LMP_toml_visitors_h +#include "toml.hpp" +/** + * A visitor for toml objects that writes to an NSMutableDictionary + */ +class toml_nsdictionary_writer { +public: + toml_nsdictionary_writer() { + currentDictionary_ = resultContainer_ = [NSMutableDictionary new]; + currentKey_ = @"TOMLRoot"; + } + + NSDictionary *dictionary() { + return [resultContainer_[@"TOMLRoot"] copy]; + } + + +// void visit(const cpptoml::value& v) { +// id value = [NSString stringWithUTF8String:v.get().c_str()]; +// writeValue(value); +// } +// +// void visit(const cpptoml::value& v) { +// id value = [NSNumber numberWithLongLong:v.get()]; +// writeValue(value); +// } +// +// void visit(const cpptoml::value& v) { +// id value = [NSNumber numberWithDouble:v.get()]; +// writeValue(value); +// } +// +// void visit(const cpptoml::value& v) { +// id value = ({ +// cpptoml::local_date ld = v.get(); +// NSDateComponents *result = [NSDateComponents new]; +// result.year = ld.year; +// result.month = ld.month; +// result.day = ld.day; +// result; +// }); +// writeValue(value); +// } +// +// void visit(const cpptoml::value& v) { +// id value = ({ +// cpptoml::local_time ld = v.get(); +// NSDateComponents *result = [NSDateComponents new]; +// result.hour = ld.hour; +// result.minute = ld.minute; +// result.second = ld.second; +// result.nanosecond = ld.microsecond * 1000; +// result; +// }); +// writeValue(value); +// } +// +// void visit(const cpptoml::value& v) { +// id value = ({ +// cpptoml::local_datetime ld = v.get(); +// NSDateComponents *result = [NSDateComponents new]; +// result.year = ld.year; +// result.month = ld.month; +// result.day = ld.day; +// result.hour = ld.hour; +// result.minute = ld.minute; +// result.second = ld.second; +// result.nanosecond = ld.microsecond * 1000; +// result; +// }); +// writeValue(value); +// } +// +// void visit(const cpptoml::value& v) { +// id value = ({ +// cpptoml::offset_datetime ld = v.get(); +// NSDateComponents *result = [NSDateComponents new]; +// result.year = ld.year; +// result.month = ld.month; +// result.day = ld.day; +// result.hour = ld.hour; +// result.minute = ld.minute; +// result.second = ld.second; +// result.nanosecond = ld.microsecond * 1000; +// result.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:(ld.hour_offset * 60 + ld.minute_offset) * 60]; +// result; +// }); +// writeValue(value); +// } +// +// void visit(const cpptoml::value& v) { +// id value = v.get() ? @YES : @NO; +// writeValue(value); +// } +// +// void visit(const cpptoml::array& arr) { +// withContainerIsDictionary( NO, ^{ +// for (auto it = arr.get().begin(); it != arr.get().end(); it++) { +// (*it)->accept(*this); +// } +// }); +// } +// +// void visit(const cpptoml::table_array& tarr) { +// +// withContainerIsDictionary( NO, ^{ +// auto arr = tarr.get(); +// for (auto ait = arr.begin(); ait != arr.end(); ait++) { +// (*ait)->accept(*this); +// } +// }); +// +// } +// +// void visit(const cpptoml::table& t) { +// withContainerIsDictionary( YES, ^{ +// for (auto it = t.begin(); it != t.end(); it++) { +// currentKey_ = [NSString stringWithUTF8String:it->first.c_str()]; +// it->second->accept(*this); +// } +// }); +// } + + void visit(const toml::string& v) { + id value = [NSString stringWithUTF8String: static_cast(v).c_str()]; + writeValue(value); + } + + void visit(const toml::local_date& v) { + id value = ({ + NSDateComponents *result = [NSDateComponents new]; + result.year = v.year; + result.month = v.month + 1; + result.day = v.day; + result; + }); + writeValue(value); + } + + void visit(const toml::local_time& v) { + id value = ({ + NSDateComponents *result = [NSDateComponents new]; + result.hour = v.hour; + result.minute = v.minute; + result.second = v.second; + result.nanosecond = v.millisecond * 1000000 + v.microsecond * 1000 + v.nanosecond; + result; + }); + NSLog(@"%@", [value debugDescription]); + writeValue(value); + } + + + +// void visit(const toml::local_datetime& v) { +// id value = ({ +// NSDateComponents *result = [NSDateComponents new]; +// result.year = v.year; +// result.month = v.month + 1; +// result.day = v.day; +// result.hour = ld.hour; +// result.minute = ld.minute; +// result.second = ld.second; +// result.nanosecond = ld.microsecond * 1000; +// result.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:(ld.hour_offset * 60 + ld.minute_offset) * 60]; +// result; +// }); +// writeValue(value); +// } + + + void visit(const toml::array& t) { + withContainerIsDictionary( NO, ^{ + for (auto it = t.begin(); it != t.end(); it++) { +// std::cout << it->first << " -> " << it->second << std::endl; + visit(*it); + } +// std::cout << "array" << std::endl; + }); + } + + + void visit(const toml::table& t) { + withContainerIsDictionary( YES, ^{ + for (auto it = t.begin(); it != t.end(); it++) { + + currentKey_ = [NSString stringWithUTF8String: it->first.c_str()]; + +// std::cout << it->first << " -> " << it->second << std::endl; + visit(it->second); + } +// std::cout << "Table" << std::endl; + }); + } + + void visit(const toml::value& dunno) { + switch (dunno.type()) { + case toml::value_t::boolean: + writeValue(dunno.as_boolean() ? @YES : @NO); + break; + case toml::value_t::integer: + writeValue(@(dunno.as_integer())); + break; + case toml::value_t::floating: + writeValue(@(dunno.as_floating())); + break; + case toml::value_t::string : + visit(toml::get(dunno)); + break; + case toml::value_t::array : + visit(toml::get(dunno)); + break; + case toml::value_t::table : + visit(toml::get(dunno)); + break; + case toml::value_t::local_date : + visit(toml::get(dunno)); + break; + case toml::value_t::local_time : + visit(toml::get(dunno)); + break; +// case toml::value_t::local_datetime : +// visit(toml::get(dunno)); +// break; +// case toml::value_t::offset_datetime : +// visit(toml::get(dunno)); + break; + default: + std::cout << "- '" << dunno << "' --------- not yet implemented" << std::endl; + break; + } + } + +private: + + void withContainerIsDictionary(BOOL isDictionary, dispatch_block_t stuff) { + NSMutableArray *array = currentArray_; + NSMutableDictionary *dict = currentDictionary_; + NSString *key = currentKey_; + + if (isDictionary) { + NSMutableDictionary *contextDictionary = [NSMutableDictionary new]; + writeValue(contextDictionary); + + currentDictionary_ = contextDictionary; + currentArray_ = nil; + } else { + NSMutableArray *contextArray = [NSMutableArray new]; + writeValue(contextArray); + + currentArray_ = contextArray; + } + + stuff(); + + currentKey_ = key; + currentArray_ = array; + currentDictionary_ = dict; + } + + void writeValue(id value) { + if (currentArray_) { + [currentArray_ addObject:value]; + } else { + currentDictionary_[currentKey_] = value; + } + } + + NSMutableDictionary *resultContainer_; + NSMutableDictionary *currentDictionary_; + NSString *currentKey_; + NSMutableArray *currentArray_; +}; + + + + +#endif /* LMP_toml_visitors_h */ From d210f324219a0d869cc9314d9cbb7bf6c3304a70 Mon Sep 17 00:00:00 2001 From: Dominik Wagner Date: Sun, 30 May 2021 15:50:43 +0200 Subject: [PATCH 03/13] made parsing work again --- tomlutil/LMPTOMLSerialization.h | 2 +- tomlutil/LMPTOMLSerialization.mm | 118 ++++++--------------- tomlutil/LMP_toml_visitors.h | 175 +++++++------------------------ 3 files changed, 72 insertions(+), 223 deletions(-) diff --git a/tomlutil/LMPTOMLSerialization.h b/tomlutil/LMPTOMLSerialization.h index 463cfdc..aa09cb4 100644 --- a/tomlutil/LMPTOMLSerialization.h +++ b/tomlutil/LMPTOMLSerialization.h @@ -16,7 +16,7 @@ extern NSErrorDomain const LMPTOMLErrorDomain; @param data NSData representing a TOML file @param error helpful information if the parsing fails - @return NSDictionary representing the contents of the TOML file. Note that given dates will be represented as NSDateComponents, use +serializationObjectWtihTOMLObject: to convert those to RFC3339 strings that can be used in JSON or PropertyList serializations. + @return NSDictionary representing the contents of the TOML file. Note that given dates will be represented as NSDateComponents, use +serializableObjectWithTOMLObject: to convert those to RFC3339 strings that can be used in JSON or PropertyList serializations. */ + (NSDictionary *)TOMLObjectWithData:(NSData *)data error:(NSError **)error; diff --git a/tomlutil/LMPTOMLSerialization.mm b/tomlutil/LMPTOMLSerialization.mm index 05d3fbe..48265ff 100644 --- a/tomlutil/LMPTOMLSerialization.mm +++ b/tomlutil/LMPTOMLSerialization.mm @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "LMP_toml_visitors.h" @@ -22,95 +23,44 @@ static NSInteger const LMPTOMLParseErrorCode = 7031; static NSInteger const LMPTOMLWriteErrorCode = 7001; -struct membuf : std::streambuf { - membuf(char* begin, char* end) { - this->setg(begin, begin, end); - } -}; - @implementation LMPTOMLSerialization -template struct overloaded : Ts... { using Ts::operator()...; }; -// explicit deduction guide (not needed as of C++20) -template overloaded(Ts...) -> overloaded; - + (NSDictionary *)TOMLObjectWithData:(NSData *)data error:(NSError **)error { - try { - char *bytes = (char *)data.bytes; - -// seems to have issues now with modern cpp, need to fix. only reads two bytes before it ends. -// membuf sbuf(bytes, bytes + data.length); -// std::istream stream(&sbuf); - - std::istringstream stream(std::string(bytes, data.length)); - - const auto data = toml::parse(stream); -// cpptoml::parser p{in}; -// std::shared_ptr g = p.parse(); - // std::cout << (*g) << std::endl; - - toml_nsdictionary_writer dw; - - dw.visit(toml::get(data)); - - // convert table to standard Objective-C objects -// toml_nsdictionary_writer dw; - // g->accept(dw); - - - // std::cout << " --- " << data << " --- \n"; - - toml::visit(overloaded { - [](const toml::table &val) -> void {std::cout << "table"; }, - [](const auto& val) -> void { - std::cout << "some visit"; - //val << std::endl; - } - }, data); - - - NSDictionary *result = dw.dictionary(); - - return result; - } catch (const toml::exception& e) { - if (error) { - *error = [NSError errorWithDomain:LMPTOMLErrorDomain - code:LMPTOMLParseErrorCode - userInfo:@{ - NSLocalizedDescriptionKey : @"Input TOML could not be parsed", - NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:@"%s", e.what()], - }]; - } - return nil; + try { + char *bytes = (char *)data.bytes; + + // deprecated but seems to do what i want, the implementation previously was missing seek capabilities. + // see https://stackoverflow.com/questions/13059091/creating-an-input-stream-from-constant-memory#comment115305688_13059195 + std::strstreambuf sbuf(bytes, data.length); + std::istream stream(&sbuf); + + // this works as well, probably does more copying than we need + // std::istringstream stream(std::string(bytes, data.length)); + + // parse + const auto data = toml::parse(stream); + + // convert table to standard Objective-C objects + toml_nsdictionary_writer dw; + dw.visit(toml::get(data)); + + // std::cout << " --- " << data << " --- \n"; + + NSDictionary *result = dw.dictionary(); + return result; + + } catch (const toml::exception& e) { + if (error) { + *error = [NSError errorWithDomain:LMPTOMLErrorDomain + code:LMPTOMLParseErrorCode + userInfo:@{ + NSLocalizedDescriptionKey : @"Input TOML could not be parsed", + NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:@"%s", e.what()], + }]; } - - return nil; -// try { -// char *bytes = (char *)data.bytes; -// membuf sbuf(bytes, bytes + data.length); -// std::istream in(&sbuf); -// cpptoml::parser p{in}; -// std::shared_ptr g = p.parse(); -// // std::cout << (*g) << std::endl; -// -// // convert table to standard Objective-C objects -// toml_nsdictionary_writer dw; -// g->accept(dw); -// NSDictionary *result = dw.dictionary(); -// -// return result; -// } catch (const cpptoml::parse_exception& e) { -// if (error) { -// *error = [NSError errorWithDomain:LMPTOMLErrorDomain -// code:LMPTOMLParseErrorCode -// userInfo:@{ -// NSLocalizedDescriptionKey : @"Input TOML could not be parsed", -// NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:@"%s", e.what()], -// }]; -// } -// return nil; -// } + return nil; + } } //static void writeDictionaryToTable(NSDictionary *dict, std::shared_ptr table) { diff --git a/tomlutil/LMP_toml_visitors.h b/tomlutil/LMP_toml_visitors.h index 5018db6..116f897 100644 --- a/tomlutil/LMP_toml_visitors.h +++ b/tomlutil/LMP_toml_visitors.h @@ -23,113 +23,6 @@ class toml_nsdictionary_writer { return [resultContainer_[@"TOMLRoot"] copy]; } - -// void visit(const cpptoml::value& v) { -// id value = [NSString stringWithUTF8String:v.get().c_str()]; -// writeValue(value); -// } -// -// void visit(const cpptoml::value& v) { -// id value = [NSNumber numberWithLongLong:v.get()]; -// writeValue(value); -// } -// -// void visit(const cpptoml::value& v) { -// id value = [NSNumber numberWithDouble:v.get()]; -// writeValue(value); -// } -// -// void visit(const cpptoml::value& v) { -// id value = ({ -// cpptoml::local_date ld = v.get(); -// NSDateComponents *result = [NSDateComponents new]; -// result.year = ld.year; -// result.month = ld.month; -// result.day = ld.day; -// result; -// }); -// writeValue(value); -// } -// -// void visit(const cpptoml::value& v) { -// id value = ({ -// cpptoml::local_time ld = v.get(); -// NSDateComponents *result = [NSDateComponents new]; -// result.hour = ld.hour; -// result.minute = ld.minute; -// result.second = ld.second; -// result.nanosecond = ld.microsecond * 1000; -// result; -// }); -// writeValue(value); -// } -// -// void visit(const cpptoml::value& v) { -// id value = ({ -// cpptoml::local_datetime ld = v.get(); -// NSDateComponents *result = [NSDateComponents new]; -// result.year = ld.year; -// result.month = ld.month; -// result.day = ld.day; -// result.hour = ld.hour; -// result.minute = ld.minute; -// result.second = ld.second; -// result.nanosecond = ld.microsecond * 1000; -// result; -// }); -// writeValue(value); -// } -// -// void visit(const cpptoml::value& v) { -// id value = ({ -// cpptoml::offset_datetime ld = v.get(); -// NSDateComponents *result = [NSDateComponents new]; -// result.year = ld.year; -// result.month = ld.month; -// result.day = ld.day; -// result.hour = ld.hour; -// result.minute = ld.minute; -// result.second = ld.second; -// result.nanosecond = ld.microsecond * 1000; -// result.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:(ld.hour_offset * 60 + ld.minute_offset) * 60]; -// result; -// }); -// writeValue(value); -// } -// -// void visit(const cpptoml::value& v) { -// id value = v.get() ? @YES : @NO; -// writeValue(value); -// } -// -// void visit(const cpptoml::array& arr) { -// withContainerIsDictionary( NO, ^{ -// for (auto it = arr.get().begin(); it != arr.get().end(); it++) { -// (*it)->accept(*this); -// } -// }); -// } -// -// void visit(const cpptoml::table_array& tarr) { -// -// withContainerIsDictionary( NO, ^{ -// auto arr = tarr.get(); -// for (auto ait = arr.begin(); ait != arr.end(); ait++) { -// (*ait)->accept(*this); -// } -// }); -// -// } -// -// void visit(const cpptoml::table& t) { -// withContainerIsDictionary( YES, ^{ -// for (auto it = t.begin(); it != t.end(); it++) { -// currentKey_ = [NSString stringWithUTF8String:it->first.c_str()]; -// it->second->accept(*this); -// } -// }); -// } - void visit(const toml::string& v) { id value = [NSString stringWithUTF8String: static_cast(v).c_str()]; writeValue(value); @@ -155,36 +48,48 @@ class toml_nsdictionary_writer { result.nanosecond = v.millisecond * 1000000 + v.microsecond * 1000 + v.nanosecond; result; }); - NSLog(@"%@", [value debugDescription]); +// NSLog(@"%@", [value debugDescription]); writeValue(value); } + // untested, need to be looked again to have proper roundtrip I guess. + void visit(const toml::local_datetime& v) { + id value = ({ + NSDateComponents *result = [NSDateComponents new]; + result.year = v.date.year; + result.month = v.date.month + 1; + result.day = v.date.day; + result.hour = v.time.hour; + result.minute = v.time.minute; + result.second = v.time.second; + result.nanosecond = v.time.millisecond * 1000000 + v.time.microsecond * 1000 + v.time.nanosecond; + result; + }); + writeValue(value); + } - -// void visit(const toml::local_datetime& v) { -// id value = ({ -// NSDateComponents *result = [NSDateComponents new]; -// result.year = v.year; -// result.month = v.month + 1; -// result.day = v.day; -// result.hour = ld.hour; -// result.minute = ld.minute; -// result.second = ld.second; -// result.nanosecond = ld.microsecond * 1000; -// result.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:(ld.hour_offset * 60 + ld.minute_offset) * 60]; -// result; -// }); -// writeValue(value); -// } + void visit(const toml::offset_datetime& v) { + id value = ({ + NSDateComponents *result = [NSDateComponents new]; + result.year = v.date.year; + result.month = v.date.month + 1; + result.day = v.date.day; + result.hour = v.time.hour; + result.minute = v.time.minute; + result.second = v.time.second; + result.nanosecond = v.time.millisecond * 1000000 + v.time.microsecond * 1000 + v.time.nanosecond; + result.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:(v.offset.hour * 60 + v.offset.minute) * 60]; + result; + }); + writeValue(value); + } void visit(const toml::array& t) { withContainerIsDictionary( NO, ^{ for (auto it = t.begin(); it != t.end(); it++) { -// std::cout << it->first << " -> " << it->second << std::endl; visit(*it); } -// std::cout << "array" << std::endl; }); } @@ -192,13 +97,9 @@ class toml_nsdictionary_writer { void visit(const toml::table& t) { withContainerIsDictionary( YES, ^{ for (auto it = t.begin(); it != t.end(); it++) { - currentKey_ = [NSString stringWithUTF8String: it->first.c_str()]; - -// std::cout << it->first << " -> " << it->second << std::endl; visit(it->second); } -// std::cout << "Table" << std::endl; }); } @@ -228,13 +129,14 @@ class toml_nsdictionary_writer { case toml::value_t::local_time : visit(toml::get(dunno)); break; -// case toml::value_t::local_datetime : -// visit(toml::get(dunno)); -// break; -// case toml::value_t::offset_datetime : -// visit(toml::get(dunno)); + case toml::value_t::local_datetime : + visit(toml::get(dunno)); + break; + case toml::value_t::offset_datetime : + visit(toml::get(dunno)); break; default: + // have all types now, should not happen anymore™ std::cout << "- '" << dunno << "' --------- not yet implemented" << std::endl; break; } @@ -281,7 +183,4 @@ class toml_nsdictionary_writer { NSMutableArray *currentArray_; }; - - - #endif /* LMP_toml_visitors_h */ From e3e4fe74fb2ffdfd839e2caa72278fcf9025f0ca Mon Sep 17 00:00:00 2001 From: Dominik Wagner Date: Mon, 31 May 2021 07:05:53 +0200 Subject: [PATCH 04/13] Improved error output and tty color support detection --- .../xcshareddata/xcschemes/tomlutil.xcscheme | 4 +- tomlutil/LMPTOMLSerialization.h | 7 ++ tomlutil/LMPTOMLSerialization.mm | 25 +++++- tomlutil/main.m | 78 +++++++++++-------- 4 files changed, 76 insertions(+), 38 deletions(-) diff --git a/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme b/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme index e89e474..2ab0f17 100644 --- a/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme +++ b/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme @@ -78,11 +78,11 @@ + isEnabled = "NO"> + isEnabled = "YES"> diff --git a/tomlutil/LMPTOMLSerialization.h b/tomlutil/LMPTOMLSerialization.h index aa09cb4..ea27b0a 100644 --- a/tomlutil/LMPTOMLSerialization.h +++ b/tomlutil/LMPTOMLSerialization.h @@ -8,6 +8,9 @@ extern NSErrorDomain const LMPTOMLErrorDomain; +extern NSString * const LMPTOMLErrorInfoKeyColorizedReason; + +extern NSString * const LMPTOMLOptionKeySourceFileURL; @interface LMPTOMLSerialization : NSObject @@ -15,11 +18,15 @@ extern NSErrorDomain const LMPTOMLErrorDomain; Generate a Foundation Dictionary from TOML data. @param data NSData representing a TOML file + @param options NSDictionary with options for the toml parsing @param error helpful information if the parsing fails @return NSDictionary representing the contents of the TOML file. Note that given dates will be represented as NSDateComponents, use +serializableObjectWithTOMLObject: to convert those to RFC3339 strings that can be used in JSON or PropertyList serializations. */ ++ (NSDictionary *)TOMLObjectWithData:(NSData *)data options:(NSDictionary *)options error:(NSError **)error; + + (NSDictionary *)TOMLObjectWithData:(NSData *)data error:(NSError **)error; + /** Generates NSData representation of the TOMLObject. The representation is UTF8 and can be stored directly as a TOML file. diff --git a/tomlutil/LMPTOMLSerialization.mm b/tomlutil/LMPTOMLSerialization.mm index 48265ff..5b20332 100644 --- a/tomlutil/LMPTOMLSerialization.mm +++ b/tomlutil/LMPTOMLSerialization.mm @@ -5,7 +5,7 @@ #import "LMPTOMLSerialization.h" -// #define TOML11_COLORIZE_ERROR_MESSAGE +#define TOML11_COLORIZE_ERROR_MESSAGE // #define TOML11_PRESERVE_COMMENTS_BY_DEFAULT #include "toml.hpp" @@ -23,9 +23,19 @@ static NSInteger const LMPTOMLParseErrorCode = 7031; static NSInteger const LMPTOMLWriteErrorCode = 7001; +NSString * const LMPTOMLErrorInfoKeyColorizedReason = @"ColoredFailureReason"; + +extern NSString * const LMPTOMLOptionKeySourceFileURL = @"sourceFileURL"; + + + @implementation LMPTOMLSerialization + (NSDictionary *)TOMLObjectWithData:(NSData *)data error:(NSError **)error { + return [self TOMLObjectWithData:data options:nil error:error]; +} + ++ (NSDictionary *)TOMLObjectWithData:(NSData *)data options:(NSDictionary *)options error:(NSError **)error { try { char *bytes = (char *)data.bytes; @@ -38,8 +48,12 @@ @implementation LMPTOMLSerialization // this works as well, probably does more copying than we need // std::istringstream stream(std::string(bytes, data.length)); + NSURL *fileSourceURL = options[LMPTOMLOptionKeySourceFileURL]; + + NSString *filePath = fileSourceURL ? fileSourceURL.relativePath : @"anonymous input"; + // parse - const auto data = toml::parse(stream); + const auto data = toml::parse(stream, filePath.UTF8String); // convert table to standard Objective-C objects toml_nsdictionary_writer dw; @@ -52,11 +66,16 @@ @implementation LMPTOMLSerialization } catch (const toml::exception& e) { if (error) { + NSString *coloredWhat = @(e.what()); + NSRegularExpression *regEx = [NSRegularExpression regularExpressionWithPattern:@"\033\\[\\d+m" options:0 error:nil]; + NSString *cleanWhat = [regEx stringByReplacingMatchesInString:coloredWhat options:0 range:NSMakeRange(0, coloredWhat.length) withTemplate:@""]; + *error = [NSError errorWithDomain:LMPTOMLErrorDomain code:LMPTOMLParseErrorCode userInfo:@{ NSLocalizedDescriptionKey : @"Input TOML could not be parsed", - NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:@"%s", e.what()], + NSLocalizedFailureReasonErrorKey : cleanWhat, + LMPTOMLErrorInfoKeyColorizedReason : coloredWhat, }]; } return nil; diff --git a/tomlutil/main.m b/tomlutil/main.m index d6815ad..90e6178 100644 --- a/tomlutil/main.m +++ b/tomlutil/main.m @@ -17,26 +17,28 @@ typedef CF_ENUM(int, LMPFileFormat) { FileFormatNone = 99991, }; -static void showLineWithContext(FILE *file, NSString *fullSourceString, NSInteger lineNumber, int context) { - NSInteger lineNumberStart = MAX(1, lineNumber - context); - NSInteger lineNumberStop = lineNumber + context; - - NSMutableArray *lineArray = [NSMutableArray new]; - __block NSInteger currentLineNumber = 1; - [fullSourceString enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) { - if (currentLineNumber >= lineNumberStart) { - [lineArray addObject:line]; - } - if (currentLineNumber >= lineNumberStop) { *stop = YES; } - currentLineNumber += 1; - }]; - currentLineNumber = lineNumberStart; - int lineMaxWidth = (int)ceil(log10(lineNumberStop)) + 1; - [lineArray enumerateObjectsUsingBlock:^(NSString *line, NSUInteger index, BOOL *_stop) { - NSInteger number = index + lineNumberStart; - fprintf(file, "%s%*ld: %s\n", number == lineNumber ? "➤" : " ", lineMaxWidth, (long)number, [[line stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]] UTF8String]); - }]; -} + +// unused toml11 provides ample output +//static void showLineWithContext(FILE *file, NSString *fullSourceString, NSInteger lineNumber, int context) { +// NSInteger lineNumberStart = MAX(1, lineNumber - context); +// NSInteger lineNumberStop = lineNumber + context; +// +// NSMutableArray *lineArray = [NSMutableArray new]; +// __block NSInteger currentLineNumber = 1; +// [fullSourceString enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) { +// if (currentLineNumber >= lineNumberStart) { +// [lineArray addObject:line]; +// } +// if (currentLineNumber >= lineNumberStop) { *stop = YES; } +// currentLineNumber += 1; +// }]; +// currentLineNumber = lineNumberStart; +// int lineMaxWidth = (int)ceil(log10(lineNumberStop)) + 1; +// [lineArray enumerateObjectsUsingBlock:^(NSString *line, NSUInteger index, BOOL *_stop) { +// NSInteger number = index + lineNumberStart; +// fprintf(file, "%s%*ld: %s\n", number == lineNumber ? "➤" : " ", lineMaxWidth, (long)number, [[line stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]] UTF8String]); +// }]; +//} void showErrorAndHalt(NSError *error, NSData *inputData) { if (!error) { @@ -44,7 +46,22 @@ void showErrorAndHalt(NSError *error, NSData *inputData) { } char *bold=""; char *stopBold=""; - if (isatty([[NSFileHandle fileHandleWithStandardError] fileDescriptor])) { + + BOOL supportsAnsiColor = isatty([[NSFileHandle fileHandleWithStandardError] fileDescriptor]); + + if (supportsAnsiColor) { + NSString *term = [[NSProcessInfo processInfo] environment][@"TERM"] ; + if (term && ( + [term rangeOfString:@"color" options:NSCaseInsensitiveSearch].location != NSNotFound || + [term rangeOfString:@"ansi" options:NSCaseInsensitiveSearch].location != NSNotFound + ) + ){ + } else { + supportsAnsiColor = NO; + } + + } + if (supportsAnsiColor) { bold="\033[1m"; stopBold="\033[0m"; } @@ -53,19 +70,14 @@ void showErrorAndHalt(NSError *error, NSData *inputData) { fputs(error.localizedDescription.UTF8String, stderr); fputs(stopBold, stderr); fputs("\n", stderr); - fputs(error.localizedFailureReason.UTF8String, stderr); - fputs("\n", stderr); - if ([error.domain isEqualToString:LMPTOMLErrorDomain]) { - NSString *errorString = error.localizedFailureReason; - NSRange atLineRange = [errorString rangeOfString:@"at line "]; - if (atLineRange.location != NSNotFound) { - int context = 1; - NSInteger lineNumber = [[errorString substringFromIndex:NSMaxRange(atLineRange)] integerValue]; - showLineWithContext(stderr, [[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding], lineNumber, context); - } + if (supportsAnsiColor && error.userInfo[LMPTOMLErrorInfoKeyColorizedReason]) { + fputs([error.userInfo[LMPTOMLErrorInfoKeyColorizedReason] UTF8String], stderr); + } else { + fputs(error.localizedFailureReason.UTF8String, stderr); } - + fputs("\n", stderr); + exit(EXIT_FAILURE); } @@ -183,7 +195,7 @@ int main(int argc, const char * argv[]) { } if (inputFormat == FileFormatTOML) { - tomlObject = [LMPTOMLSerialization TOMLObjectWithData:inputData error:&error]; + tomlObject = [LMPTOMLSerialization TOMLObjectWithData:inputData options:filenameString ? @{LMPTOMLOptionKeySourceFileURL : [NSURL fileURLWithPath:filenameString]} : nil error:&error]; showErrorAndHalt(error, inputData); } else if (inputFormat == FileFormatJSON) { dictionaryObject = [NSJSONSerialization JSONObjectWithData:inputData options:0 error:&error]; From 4fdfb981251196583a7796ebc154b645c06d4e61 Mon Sep 17 00:00:00 2001 From: Dominik Wagner Date: Mon, 31 May 2021 10:15:18 +0200 Subject: [PATCH 05/13] bumping the version and fixing some roundtrips --- tomlutil/Info.plist | 6 +++--- tomlutil/LMPTOMLSerialization.mm | 28 ++++++++++++++++++++-------- tomlutil/main.m | 13 +++++++++---- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/tomlutil/Info.plist b/tomlutil/Info.plist index d39cf27..ccba116 100644 --- a/tomlutil/Info.plist +++ b/tomlutil/Info.plist @@ -5,9 +5,9 @@ CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleShortVersionString - 1.1.0 - LPMCpptomlVersion - 0.1.1 + 2.0.0 + LPMToml11Version + 3.7.0 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} diff --git a/tomlutil/LMPTOMLSerialization.mm b/tomlutil/LMPTOMLSerialization.mm index 5b20332..41ceaf8 100644 --- a/tomlutil/LMPTOMLSerialization.mm +++ b/tomlutil/LMPTOMLSerialization.mm @@ -40,7 +40,7 @@ @implementation LMPTOMLSerialization try { char *bytes = (char *)data.bytes; - // deprecated but seems to do what i want, the implementation previously was missing seek capabilities. + // deprecated but seems to do what I want, the implementation previously was missing seek capabilities. // see https://stackoverflow.com/questions/13059091/creating-an-input-stream-from-constant-memory#comment115305688_13059195 std::strstreambuf sbuf(bytes, data.length); std::istream stream(&sbuf); @@ -236,7 +236,7 @@ + (NSData *)dataWithTOMLObject:(NSDictionary *)tomlObject error: static NSString *TOMLTimeStringFromComponents(NSDateComponents *dc) { NSMutableString *result = [NSMutableString new]; if (dc.year != NSDateComponentUndefined) { - [result appendFormat:@"%04d-%02d-%2d", (int)dc.year, (int)dc.month, (int)dc.day]; + [result appendFormat:@"%04d-%02d-%02d", (int)dc.year, (int)dc.month, (int)dc.day]; } if (dc.minute != NSDateComponentUndefined) { if (result.length > 0) { @@ -259,18 +259,30 @@ + (NSData *)dataWithTOMLObject:(NSDictionary *)tomlObject error: return result; } +static NSArray *serializableArray(NSArray *array) { + NSMutableArray *result = [array mutableCopy]; + NSUInteger index = result.count; + while (index-- != 0) { + id value = result[index]; + if ([value isKindOfClass:[NSArray class]]) { + result[index] = serializableArray(value); + } else if ([value isKindOfClass:[NSDictionary class]]) { + result[index] = [LMPTOMLSerialization serializableObjectWithTOMLObject:value]; + } else if ([value isKindOfClass:[NSDateComponents class]]) { + result[index] = TOMLTimeStringFromComponents(value); + } + } + return result; +} + + (NSDictionary *)serializableObjectWithTOMLObject:(NSDictionary *)tomlObject { NSMutableDictionary *result = [tomlObject mutableCopy]; for (NSString *key in result.allKeys) { id value = result[key]; if ([value isKindOfClass:[NSDictionary class]]) { result[key] = [self serializableObjectWithTOMLObject:value]; - } else if ([value isKindOfClass:[NSArray class]] && [[value firstObject] isKindOfClass:[NSDictionary class]]) { - NSMutableArray *array = [NSMutableArray new]; - for (NSDictionary *dict in value) { - [array addObject:[self serializableObjectWithTOMLObject:dict]]; - } - result[key] = array; + } else if ([value isKindOfClass:[NSArray class]]) { + result[key] = serializableArray(value); } else if ([value isKindOfClass:[NSDateComponents class]]) { result[key] = TOMLTimeStringFromComponents(value); } diff --git a/tomlutil/main.m b/tomlutil/main.m index 90e6178..f1ad57d 100644 --- a/tomlutil/main.m +++ b/tomlutil/main.m @@ -98,16 +98,16 @@ int main(int argc, const char * argv[]) { if (argc <= 1) { NSString *shortVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; // NSString *bundleVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]; - NSString *cpptomlVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"LPMCpptomlVersion"]; + NSString *toml11Version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"LPMToml11Version"]; - NSString *versionLineString = [NSString stringWithFormat:@"tomlutil v%@ (cpptoml v%@)", shortVersion, cpptomlVersion]; + NSString *versionLineString = [NSString stringWithFormat:@"tomlutil v%@ (toml11 v%@)", shortVersion, toml11Version]; puts(versionLineString.UTF8String); puts(""); puts("Usage: tomlutil [-f json|xml1|binary1|toml] file [outputfile]\n\n" "A file of '-' reads from stdin. Can read json, plists and toml. Output defaults to stdout.\n" - "-f format Output format. One of json, xml, binary1, toml. Defaults to toml.\n" - "-lint Just lint with cpptoml, no output."); + "-f format Output format. One of json, xml1, binary1, toml. Defaults to toml.\n" + "-lint Just lint with toml11, no output."); return EXIT_SUCCESS; } @@ -129,7 +129,12 @@ int main(int argc, const char * argv[]) { if (outputFormat != FileFormatNone) { outputFormat = [@{ @"toml" : @(FileFormatTOML), + @"json" : @(FileFormatJSON), + + @"plist" : @(FileFormatPlistXML), + @"xml" : @(FileFormatPlistXML), + @"binary" : @(FileFormatPlistBinary), @"xml1" : @(FileFormatPlistXML), @"binary1" : @(FileFormatPlistBinary), }[argument] intValue] ?: outputFormat; From 31cbcd44c546dc8bbf67bdd71a1245c8e095b77f Mon Sep 17 00:00:00 2001 From: Dominik Wagner Date: Mon, 31 May 2021 11:44:19 +0200 Subject: [PATCH 06/13] almost done --- tomlutil/LMPTOMLSerialization.mm | 271 ++++++++++++++----------------- 1 file changed, 124 insertions(+), 147 deletions(-) diff --git a/tomlutil/LMPTOMLSerialization.mm b/tomlutil/LMPTOMLSerialization.mm index 41ceaf8..0dce11d 100644 --- a/tomlutil/LMPTOMLSerialization.mm +++ b/tomlutil/LMPTOMLSerialization.mm @@ -82,155 +82,132 @@ @implementation LMPTOMLSerialization } } -//static void writeDictionaryToTable(NSDictionary *dict, std::shared_ptr table) { -// for (NSString *key in dict.keyEnumerator) { -// auto cppKey = std::string(key.UTF8String); -// auto cppValue = ObjectToValue(dict[key]); -// table->insert(cppKey, cppValue); -// } -//} -// -//static std::shared_ptr ObjectToValue(id objectValue) { -// if ([objectValue isKindOfClass:[NSString class]]) { -// NSString *val = objectValue; -// return cpptoml::make_value(std::string(val.UTF8String)); -// } else if ([objectValue isKindOfClass:[NSNumber class]]) { -// NSNumber *val = objectValue; -// if ((__bridge CFBooleanRef)val == kCFBooleanTrue || -// (__bridge CFBooleanRef)val == kCFBooleanFalse) { -// return cpptoml::make_value(val.boolValue); -// } else if (CFNumberIsFloatType((__bridge CFNumberRef)val)) { -// return cpptoml::make_value(val.doubleValue); -// } else { -// return cpptoml::make_value(val.longLongValue); -// } -// } else if ([objectValue isKindOfClass:[NSArray class]]) { -// if ([[objectValue firstObject] isKindOfClass:[NSDictionary class]]) { -// return ArrayToTableArray(objectValue); -// } else { -// return ArrayToArray(objectValue); -// } -// } else if ([objectValue isKindOfClass:[NSDictionary class]]) { -// return DictionaryToTable(objectValue); -// } else if ([objectValue isKindOfClass:[NSDateComponents class]]) { -// NSDateComponents *dc = objectValue; -// if (YES) { -// if (dc.year == NSDateComponentUndefined) { -// cpptoml::local_time lt; -// if (dc.hour != NSDateComponentUndefined) { -// lt.hour = (int)dc.hour; -// } -// if (dc.minute != NSDateComponentUndefined) { -// lt.minute = (int)dc.minute; -// } -// if (dc.second != NSDateComponentUndefined) { -// lt.second = (int)dc.second; -// } -// if (dc.nanosecond != NSDateComponentUndefined) { -// lt.microsecond = (int)(dc.nanosecond / 1000); -// } -// return cpptoml::make_value(lt); -// } -// -// cpptoml::local_date ld; -// ld.year = (int)dc.year; -// ld.month = (int)dc.month; -// ld.day = (int)dc.day; -// if (dc.hour == NSDateComponentUndefined) { -// return cpptoml::make_value(ld); -// } -// -// cpptoml::local_datetime ldt; -// static_cast(ldt) = ld; -// ldt.hour = (int)dc.hour; -// ldt.minute = (int)dc.minute; -// ldt.second = (int)dc.second; -// if (dc.nanosecond != NSDateComponentUndefined) { -// ldt.microsecond = (int)(dc.nanosecond / 1000); -// } -// if (!dc.timeZone) { -// return cpptoml::make_value(ldt); -// } -// -// cpptoml::offset_datetime odt; -// static_cast(odt) = ldt; -// int minutesFromGMT = (int)[dc.timeZone secondsFromGMT] / 60; -// odt.hour_offset = minutesFromGMT / 60; -// odt.minute_offset = minutesFromGMT % 60; -// return cpptoml::make_value(odt); -// } -// -// } else { -// auto reason = std::string([NSString stringWithFormat:@"%@ cannot be encoded to TOML", objectValue].UTF8String); -// throw std::out_of_range{reason}; -// } -//} -// -//static std::shared_ptr ArrayToTableArray(NSArray *array) { -// auto tarr = cpptoml::make_table_array(); -// for (NSDictionary *objectValue in array) { -// tarr->push_back(DictionaryToTable(objectValue)); -// } -// return tarr; -//} -// -//static std::shared_ptr ArrayToArray(NSArray *array) { -// auto arr = cpptoml::make_array(); -// for (id objectValue in array) { -// auto val = ObjectToValue(objectValue); -// if (val->is_value()) { -// // FIXME: there needs to be better cpp foo to make this not be redundant -// if ([objectValue isKindOfClass:[NSString class]]) { -// NSString *val = objectValue; -// arr->push_back(std::string(val.UTF8String)); -// } else if ([objectValue isKindOfClass:[NSNumber class]]) { -// NSNumber *val = objectValue; -// if ((__bridge CFBooleanRef)val == kCFBooleanTrue || -// (__bridge CFBooleanRef)val == kCFBooleanFalse) { -// arr->push_back((bool)val.boolValue); -// } else if (CFNumberIsFloatType((__bridge CFNumberRef)val)) { -// arr->push_back(val.doubleValue); -// } else { -// arr->push_back(val.longLongValue); -// } -// } -// } else if (val->is_array()) { -// arr->push_back(val->as_array()); -// } else if (val->is_table()) { -// arr->push_back(val->as_array()); -// } -// } -// return arr; -//} -// -// -//static std::shared_ptr DictionaryToTable(NSDictionary *dictionary) { -// auto tbl = cpptoml::make_table(); -// writeDictionaryToTable(dictionary, tbl); -// return tbl; -//} +static toml::value DictionaryToTable(NSDictionary *dict) { + toml::table table; + for (NSString *key in dict.keyEnumerator) { + auto cppKey = std::string(key.UTF8String); + auto cppValue = ObjectToValue(dict[key]); + table.insert(std::make_pair(cppKey, cppValue)); + } + return toml::value(table); +} + +static toml::value ArrayToArray(NSArray *array) { + toml::array result; + for (id value in array) { + result.push_back(ObjectToValue(value)); + } + return toml::value(result); +} + +static toml::value ObjectToValue(id objectValue) { + if ([objectValue isKindOfClass:[NSString class]]) { + return toml::value(std::string([objectValue UTF8String])); + } else if ([objectValue isKindOfClass:[NSNumber class]]) { + if ((__bridge CFBooleanRef)objectValue == kCFBooleanTrue || + (__bridge CFBooleanRef)objectValue == kCFBooleanFalse) { + return toml::value((__bridge CFBooleanRef)objectValue == kCFBooleanTrue); + } else if (CFNumberIsFloatType((__bridge CFNumberRef)objectValue)) { + return toml::value([objectValue doubleValue]); + } else { + return toml::value([objectValue longLongValue]); + } + } else if ([objectValue isKindOfClass:[NSDictionary class]]) { + return DictionaryToTable(objectValue); + } else if ([objectValue isKindOfClass:[NSArray class]]) { + return ArrayToArray(objectValue); + } else if ([objectValue isKindOfClass:[NSDateComponents class]]) { + NSDateComponents *dc = objectValue; + + if (dc.year == NSDateComponentUndefined) { + toml::local_time lt; + if (dc.hour != NSDateComponentUndefined) { + lt.hour = (int)dc.hour; + } + if (dc.minute != NSDateComponentUndefined) { + lt.minute = (int)dc.minute; + } + if (dc.second != NSDateComponentUndefined) { + lt.second = (int)dc.second; + } + if (dc.nanosecond != NSDateComponentUndefined) { + lt.nanosecond = (int)(dc.nanosecond % 1000); + long ms = dc.nanosecond / 1000; + lt.microsecond = (int)(ms % 1000); + lt.millisecond = (int)ms / 1000; + } + return toml::value(lt); + } else { + toml::local_date ld((int16_t)dc.year, (toml::month_t)(dc.month - 1), (uint8_t)dc.day); + if (dc.second == NSDateComponentUndefined) { + return toml::value(ld); + } + else { + toml::local_time lt; + if (dc.hour != NSDateComponentUndefined) { + lt.hour = (int)dc.hour; + } + if (dc.minute != NSDateComponentUndefined) { + lt.minute = (int)dc.minute; + } + if (dc.second != NSDateComponentUndefined) { + lt.second = (int)dc.second; + } + if (dc.nanosecond != NSDateComponentUndefined) { + lt.nanosecond = (int)(dc.nanosecond % 1000); + long ms = dc.nanosecond / 1000; + lt.microsecond = (int)(ms % 1000); + lt.millisecond = (int)ms / 1000; + } + + toml::local_datetime ldt(ld, lt); + if (!dc.timeZone) { + return toml::value(ldt); + } else { + int minutesFromGMT = (int)[dc.timeZone secondsFromGMT] / 60; + toml::offset_datetime dt(ldt, toml::time_offset(minutesFromGMT / 60, minutesFromGMT % 60)); + return toml::value(dt); + } + } + } + + } else { + return toml::value("--- unkonwn ---"); + } +} + (NSData *)dataWithTOMLObject:(NSDictionary *)tomlObject error:(NSError **)error { -// try { -// auto root = DictionaryToTable(tomlObject); -// -// std::stringstream s(""); -// s << *root; -// std::string str = s.str(); -// NSData *result = [NSData dataWithBytes:str.data() length:str.length()]; -// return result; -// } catch (const std::invalid_argument& e) { -// if (error) { -// *error = [NSError errorWithDomain:LMPTOMLErrorDomain -// code:LMPTOMLWriteErrorCode -// userInfo:@{ -// NSLocalizedDescriptionKey : @"Input objects could not be converted to TOML", -// NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:@"%s", e.what()], -// }]; -// } -// return nil; -// } - return nil; + try { +// __auto_type dict = @{@"test1" : @1, @"testBool" : @YES, @"testString" : @"some string", @"test3.14" : @(M_PI), +// @"subtable" : @{ @"two" : @"zwo"}, +// @"some array" : @[@1, @2, @3], +// @"some other array" : @[@"oans", @"zwoa"], +// }; + + auto root = DictionaryToTable(tomlObject); + std::stringstream s(""); + // setw makes inline tables if they fit + // std::setprecision(7) e.g. would also set the float precision. we might want that for the future + s << std::setw(100) << root << std::endl; + std::string str = s.str(); + NSData *result = [NSData dataWithBytes:str.data() length:str.length()]; + return result; + } catch (const toml::exception& e) { + if (error) { + NSString *coloredWhat = @(e.what()); + NSRegularExpression *regEx = [NSRegularExpression regularExpressionWithPattern:@"\033\\[\\d+m" options:0 error:nil]; + NSString *cleanWhat = [regEx stringByReplacingMatchesInString:coloredWhat options:0 range:NSMakeRange(0, coloredWhat.length) withTemplate:@""]; + + *error = [NSError errorWithDomain:LMPTOMLErrorDomain + code:LMPTOMLWriteErrorCode + userInfo:@{ + NSLocalizedDescriptionKey : @"Input objects could not be converted to TOML", + NSLocalizedFailureReasonErrorKey : cleanWhat, + LMPTOMLErrorInfoKeyColorizedReason : coloredWhat, + }]; + } + return nil; + } } static NSString *TOMLTimeStringFromComponents(NSDateComponents *dc) { From b032755cdfb0fa64ed4861fd8871e747e0da6b7e Mon Sep 17 00:00:00 2001 From: Dominik Wagner Date: Fri, 17 Sep 2021 08:59:34 +0200 Subject: [PATCH 07/13] supporting -v/-h/--version/--help now to be a nicer command line citizen --- tomlutil.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/tomlutil.xcscheme | 10 ++-- tomlutil/main.m | 53 ++++++++++++++----- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/tomlutil.xcodeproj/project.pbxproj b/tomlutil.xcodeproj/project.pbxproj index b5e1270..022e6f5 100644 --- a/tomlutil.xcodeproj/project.pbxproj +++ b/tomlutil.xcodeproj/project.pbxproj @@ -152,7 +152,7 @@ F22CB6FF217B1FD600D1565D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1000; + LastUpgradeCheck = 1300; ORGANIZATIONNAME = "Lone Monkey Productions"; TargetAttributes = { F22CB706217B1FD600D1565D = { diff --git a/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme b/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme index 2ab0f17..484f907 100644 --- a/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme +++ b/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme @@ -1,6 +1,6 @@ + isEnabled = "NO"> + isEnabled = "YES"> + isEnabled = "YES"> + isEnabled = "NO"> diff --git a/tomlutil/main.m b/tomlutil/main.m index f1ad57d..fb7e139 100644 --- a/tomlutil/main.m +++ b/tomlutil/main.m @@ -93,21 +93,48 @@ static LMPFileFormat formatFromFilename(NSString *filename) { return result; } -int main(int argc, const char * argv[]) { - @autoreleasepool { - if (argc <= 1) { - NSString *shortVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; +static NSString *version_string(void) { + NSString *shortVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; // NSString *bundleVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]; - NSString *toml11Version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"LPMToml11Version"]; + NSString *toml11Version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"LPMToml11Version"]; - NSString *versionLineString = [NSString stringWithFormat:@"tomlutil v%@ (toml11 v%@)", shortVersion, toml11Version]; - - puts(versionLineString.UTF8String); - puts(""); - puts("Usage: tomlutil [-f json|xml1|binary1|toml] file [outputfile]\n\n" - "A file of '-' reads from stdin. Can read json, plists and toml. Output defaults to stdout.\n" - "-f format Output format. One of json, xml1, binary1, toml. Defaults to toml.\n" - "-lint Just lint with toml11, no output."); + NSString *versionLineString = [NSString stringWithFormat:@"tomlutil v%@ (toml11 v%@)", shortVersion, toml11Version]; + return versionLineString; +} + +static void show_help(BOOL versionOnly) { + + puts(version_string().UTF8String); + + if (versionOnly) { + return; + } + + puts(""); + puts("Usage: tomlutil [-f json|xml1|binary1|toml] file [outputfile]\n\n" + "A file of '-' reads from stdin. Can read json, plists and toml. Output defaults to stdout.\n" + "-f format Output format. One of json, xml1, binary1, toml. Defaults to toml.\n" + "-lint Just lint with toml11, no output."); +} + +int main(int argc, const char * argv[]) { + @autoreleasepool { + + BOOL showHelp = argc <= 1; + + if (!showHelp && argc == 2) { + NSString *argument = [[NSProcessInfo processInfo].arguments lastObject]; + NSArray *helpArgs = @[@"-h",@"-help",@"--help"]; + if ([helpArgs containsObject:argument]) { + showHelp = YES; + } else if ([@[@"-v",@"-version",@"--version"] containsObject:argument]) { + show_help(YES); + return EXIT_SUCCESS; + } + } + + if (showHelp) { + show_help(NO); return EXIT_SUCCESS; } From 978a9c70fb3fc2fe9fe13a7ef20eb480e0b0f903 Mon Sep 17 00:00:00 2001 From: Dominik Wagner Date: Fri, 17 Sep 2021 15:42:01 +0200 Subject: [PATCH 08/13] Add a "Products" group with the build tomutil in it --- tomlutil.xcodeproj/project.pbxproj | 10 ++++++++++ .../xcshareddata/xcschemes/tomlutil.xcscheme | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/tomlutil.xcodeproj/project.pbxproj b/tomlutil.xcodeproj/project.pbxproj index 022e6f5..2c411d7 100644 --- a/tomlutil.xcodeproj/project.pbxproj +++ b/tomlutil.xcodeproj/project.pbxproj @@ -29,6 +29,7 @@ F22CB712217B239300D1565D /* LMPTOMLSerialization.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LMPTOMLSerialization.h; sourceTree = ""; }; F22CB713217B239300D1565D /* LMPTOMLSerialization.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LMPTOMLSerialization.mm; sourceTree = ""; }; F23131842663608400AFE2BA /* toml.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = toml.hpp; path = submodules/toml11/toml.hpp; sourceTree = SOURCE_ROOT; }; + F2657CF126F4D26B00C279B9 /* tomlutil */ = {isa = PBXFileReference; lastKnownFileType = text; path = tomlutil; sourceTree = BUILT_PRODUCTS_DIR; }; F2962202217F303B00C44751 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; F2BC7534217B44D10056FAED /* LMP_toml_visitors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LMP_toml_visitors.h; sourceTree = ""; }; F2FAE3732663A3DC0080F81A /* region.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = region.hpp; sourceTree = ""; }; @@ -92,10 +93,19 @@ F23131842663608400AFE2BA /* toml.hpp */, F2FAE3722663A3DC0080F81A /* toml */, F2962202217F303B00C44751 /* Info.plist */, + F2657CF026F4D24E00C279B9 /* Products */, ); path = tomlutil; sourceTree = ""; }; + F2657CF026F4D24E00C279B9 /* Products */ = { + isa = PBXGroup; + children = ( + F2657CF126F4D26B00C279B9 /* tomlutil */, + ); + name = Products; + sourceTree = ""; + }; F2FAE3722663A3DC0080F81A /* toml */ = { isa = PBXGroup; children = ( diff --git a/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme b/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme index 484f907..783113c 100644 --- a/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme +++ b/tomlutil.xcodeproj/xcshareddata/xcschemes/tomlutil.xcscheme @@ -78,11 +78,11 @@ + isEnabled = "NO"> + isEnabled = "YES"> From 069068b6b1b67c4f9465c03e9f4e0bfdff16e980 Mon Sep 17 00:00:00 2001 From: Dominik Wagner Date: Sun, 15 May 2022 17:11:06 +0200 Subject: [PATCH 09/13] Update to toml11 3.7.1 and remove cpptoml submodule --- .gitmodules | 3 --- submodules/cpptoml | 1 - submodules/toml11 | 2 +- tomlutil/main.m | 23 ----------------------- 4 files changed, 1 insertion(+), 28 deletions(-) delete mode 160000 submodules/cpptoml diff --git a/.gitmodules b/.gitmodules index 91506bd..edd4ca7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "submodules/cpptoml"] - path = submodules/cpptoml - url = https://github.com/skystrife/cpptoml.git [submodule "submodules/toml11"] path = submodules/toml11 url = git@github.com:ToruNiina/toml11.git diff --git a/submodules/cpptoml b/submodules/cpptoml deleted file mode 160000 index fededad..0000000 --- a/submodules/cpptoml +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fededad7169e538ca47e11a9ee9251bc361a9a65 diff --git a/submodules/toml11 b/submodules/toml11 index 6473810..dcfe39a 160000 --- a/submodules/toml11 +++ b/submodules/toml11 @@ -1 +1 @@ -Subproject commit 647381020ef04b5d41d540ec489eba45e82d90a7 +Subproject commit dcfe39a783a94e8d52c885e5883a6fbb21529019 diff --git a/tomlutil/main.m b/tomlutil/main.m index fb7e139..c6bc0ee 100644 --- a/tomlutil/main.m +++ b/tomlutil/main.m @@ -17,29 +17,6 @@ typedef CF_ENUM(int, LMPFileFormat) { FileFormatNone = 99991, }; - -// unused toml11 provides ample output -//static void showLineWithContext(FILE *file, NSString *fullSourceString, NSInteger lineNumber, int context) { -// NSInteger lineNumberStart = MAX(1, lineNumber - context); -// NSInteger lineNumberStop = lineNumber + context; -// -// NSMutableArray *lineArray = [NSMutableArray new]; -// __block NSInteger currentLineNumber = 1; -// [fullSourceString enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) { -// if (currentLineNumber >= lineNumberStart) { -// [lineArray addObject:line]; -// } -// if (currentLineNumber >= lineNumberStop) { *stop = YES; } -// currentLineNumber += 1; -// }]; -// currentLineNumber = lineNumberStart; -// int lineMaxWidth = (int)ceil(log10(lineNumberStop)) + 1; -// [lineArray enumerateObjectsUsingBlock:^(NSString *line, NSUInteger index, BOOL *_stop) { -// NSInteger number = index + lineNumberStart; -// fprintf(file, "%s%*ld: %s\n", number == lineNumber ? "➤" : " ", lineMaxWidth, (long)number, [[line stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]] UTF8String]); -// }]; -//} - void showErrorAndHalt(NSError *error, NSData *inputData) { if (!error) { return; From 3b36b0998851f112bd52ba34b83be237b70fa699 Mon Sep 17 00:00:00 2001 From: Dominik Wagner Date: Sun, 5 Feb 2023 08:02:59 +0100 Subject: [PATCH 10/13] Fixing mastodon, removing twitter --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e8c1ac..f1417bc 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ Full header: ## Authors -* **Dominik Wagner** - [monkeydom](https://github.com/monkeydom) - [@monkeydom@mastodon.technology](https://mastodon.technology/@monkeydom) - [@monkeydom](https://twitter.com/monkeydom) +* **Dominik Wagner** - [monkeydom](https://github.com/monkeydom) - [@monkeydom@mastodon.social](https://mastodon.social/@monkeydom) ## License From 362dac14766edab2d76d2d5c163533fc2e488109 Mon Sep 17 00:00:00 2001 From: Dominik Wagner Date: Sat, 11 Feb 2023 14:21:24 +0100 Subject: [PATCH 11/13] Allow for json5 and don't excape the slashes --- tomlutil/main.m | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tomlutil/main.m b/tomlutil/main.m index c6bc0ee..204f6ea 100644 --- a/tomlutil/main.m +++ b/tomlutil/main.m @@ -207,7 +207,11 @@ int main(int argc, const char * argv[]) { tomlObject = [LMPTOMLSerialization TOMLObjectWithData:inputData options:filenameString ? @{LMPTOMLOptionKeySourceFileURL : [NSURL fileURLWithPath:filenameString]} : nil error:&error]; showErrorAndHalt(error, inputData); } else if (inputFormat == FileFormatJSON) { - dictionaryObject = [NSJSONSerialization JSONObjectWithData:inputData options:0 error:&error]; + NSJSONReadingOptions opts = NSJSONReadingFragmentsAllowed; + if (@available(macOS 12.0, *)) { + opts |= NSJSONReadingJSON5Allowed; + } + dictionaryObject = [NSJSONSerialization JSONObjectWithData:inputData options:opts error:&error]; showErrorAndHalt(error, inputData); } else { dictionaryObject = [NSPropertyListSerialization propertyListWithData:inputData options:0 format:nil error:&error]; @@ -247,6 +251,8 @@ int main(int argc, const char * argv[]) { if (@available(macOS 10.13, *)) { options |= NSJSONWritingSortedKeys; } + options |= NSJSONWritingWithoutEscapingSlashes; + outputData = [NSJSONSerialization dataWithJSONObject:dictionaryObject options:options error:&error]; showErrorAndHalt(error, inputData); } else { From 1f11b8a6a65a2537c41edad927b8eada8a528441 Mon Sep 17 00:00:00 2001 From: Dominik Wagner Date: Sat, 11 Feb 2023 14:37:43 +0100 Subject: [PATCH 12/13] Updated versions and README.md --- README.md | 177 ++++++++++++++++++++++++++++---------------- tomlutil/Info.plist | 4 +- tomlutil/main.m | 2 +- 3 files changed, 115 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index f1417bc..cb51279 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # ObjectiveTOML -ObjectiveTOML is a clean and nice Objective-C API to read and write [TOML](https://github.com/toml-lang/toml) files. It is utilizing [cpptoml](https://github.com/skystrife/cpptoml) and therefore on par with its TOML compliance. At time of writing this is [TOML 0.5.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md) +ObjectiveTOML is a clean and nice Objective-C API to read and write [TOML](https://github.com/toml-lang/toml) files. It is utilizing [toml11](https://github.com/ToruNiina/toml11) and therefore on par with its TOML compliance. At time of writing this is [TOML 1.0.0](https://toml.io/en/v1.0.0) -The main target is a small command line utility `tomlutil` to convert between TOML, JSON and the xml and binary plist format on macOS. To use the API in your app it should be enough to snapshot the .h and .mm files of the project to your project. +The main target is a small command line utility `tomlutil` to convert between TOML, JSON and the xml and binary plist format on macOS. The API is aligned with `NSJSONSerialization`: @@ -19,97 +19,141 @@ NSDictionary * tomlObject = The `tomlutil` has nice parsing error reporting (if you only want this, you can use the `-lint` option: ``` -$> ./tomlutil ObjectiveTOML/toml-examples/example-v0.4.0.toml +$> ./tomlutil -lint toml-examples/wrong.toml 🚫 Input TOML could not be parsed -Failed to parse value type at line 32 - 31: [x.y.z.w] # for this to work -> 32: unsupported = - 33: +[error] toml::parse_key_value_pair: invalid format for key + --> toml-examples/wrong.toml + | + 14 | asdfpoin1!@ j= ;alskjfasdf + | ^--- invalid character in key + | +Hint: Did you forget '.' to separate dotted-key? +Hint: Allowed characters for bare key are [0-9a-zA-Z_-]. ``` Current usage output: ``` -tomlutil v1.1.0 (cpptoml v0.1.1) +tomlutil v2.0.0 (toml11 v3.7.1) Usage: tomlutil [-f json|xml1|binary1|toml] file [outputfile] A file of '-' reads from stdin. Can read json, plists and toml. Output defaults to stdout. --f format Output format. One of json, xml, binary1, toml. Defaults to toml. --lint Just lint with cpptoml, no output. +-f format Output format. One of json, xml1, binary1, toml. Defaults to toml. +-lint Just lint with toml11, no output. +┌─(...-cxgxrczcjchjyyhfjlnxipqyqbsh/Build/Products/Debug)───(dom@darthy:s001)─┐ ``` Simple conversion of the Mojave News.app plist to TOML: ```toml -$ ./tomlutil /Applications/News.app/Contents/Info.plist -BuildMachineOSBuild = "17A405001" -CFBundleDevelopmentRegion = "en" -CFBundleDisplayName = "News" -CFBundleExecutable = "News" -CFBundleHelpBookFolder = "News.help" +$> ./tomlutil /System/Applications/News.app/Contents/Info.plist +SBAppUsesLocalNotifications = true +DTSDKBuild = "22D40" +UILaunchStoryboardName = "LaunchScreen" CFBundleHelpBookName = "com.apple.News.help" -CFBundleIconFile = "AppIcon_macOS.icns" -CFBundleIconName = "AppIcon" -CFBundleIdentifier = "com.apple.news" -CFBundleInfoDictionaryVersion = "6.0" +NSSupportsSuddenTermination = true +DTPlatformVersion = "13.2" +UIViewGroupOpacity = false +CFBundleDisplayName = "News" CFBundleName = "News" +HPDHelpProjectIdentifier = "news" +UIDeviceFamily = [6] CFBundlePackageType = "APPL" -CFBundleShortVersionString = "4.0" +UIRequiredDeviceCapabilities = ["armv7"] CFBundleSignature = "????" -CFBundleSupportedPlatforms = ["MacOSX"] -CFBundleVersion = "1637.9" -DTCompiler = "com.apple.compilers.llvm.clang.1_0" -DTPlatformBuild = "10L213p" -DTPlatformName = "macosx" -DTPlatformVersion = "10.14" -DTSDKBuild = "18A371" -DTSDKName = "macosx10.14internal" -DTXcode = "1000" -DTXcodeBuild = "10L213p" -HPDHelpProjectIdentifier = "news" -LSCounterpartIdentifiers = ["com.apple.nanonews"] -LSMinimumSystemVersion = "10.14" -LSSupportedRegions = ["US", "GB", "AU"] +UIMenuBarItemTitleQuit = "Quit News" +CFBundleVersion = "3270.0.1" +LSSupportedRegions = ["US","GB","AU","CA"] +NSLocationDefaultAccuracyReduced = true +UIMenuBarItemTitleHelp = "News Help" +NSLocationUsageDescription = """ +Get top local news and weather, and locally relevant search results an\ +d ads.\ +""" +UIMenuBarItemTitleAbout = "About News" +UIMenuBarItemTitleHide = "Hide News" NSCalendarsUsageDescription = "This will let you add events from News to your calendar." -NSContactsUsageDescription = "" -NSHumanReadableCopyright = "Copyright © 2018 Apple. All rights reserved." -NSLocationWhenInUseUsageDescription = "Your location is used to deliver locally relevant information such as search results and weather." +CFBundleSupportedPlatforms = ["MacOSX"] +NSLocationWhenInUseUsageDescription = """ +Get top local news and weather, and locally relevant search r\ +esults and ads.\ +""" +CFBundleInfoDictionaryVersion = "6.0" +LSMinimumSystemVersion = "13.2" +CFBundleIdentifier = "com.apple.news" +NSHumanReadableCopyright = "Copyright © 2022 Apple Inc. All rights reserved." NSPhotoLibraryAddUsageDescription = "" -NSPhotoLibraryUsageDescription = "" -NSUserActivityTypes = ["com.apple.news.articleViewing", "com.apple.news.feedBrowsing", "com.apple.news.forYou", "com.apple.news.saved", "com.apple.news.history"] -SBAppUsesLocalNotifications = true +UIWhitePointAdaptivityStyle = "UIWhitePointAdaptivityStyleReading" +NSContactsUsageDescription = "" +NSSupportsAutomaticTermination = true +CFBundleShortVersionString = "8.2.1" +CFBundleIconFile = "AppIcon" +CTIgnoreUserFonts = true UIAppFonts = [] -UIApplicationShortcutWidget = "com.apple.news.widget" -UIBackgroundModes = ["audio", "fetch", "remote-notification"] -UIDeviceFamily = [1, 2] -UILaunchStoryboardName = "LaunchScreen" -UIMainStoryboardFile = "Main" -UIMenuBarItemTitleAbout = "About News" -UIMenuBarItemTitleHelp = "News Help" -UIMenuBarItemTitleHide = "Hide News" -UIMenuBarItemTitleQuit = "Quit News" -UIRequiredDeviceCapabilities = ["armv7"] -UIStatusBarHidden = false -UISupportedInterfaceOrientations = ["UIInterfaceOrientationPortrait", "UIInterfaceOrientationLandscapeLeft", "UIInterfaceOrientationLandscapeRight"] -"UISupportedInterfaceOrientations~ipad" = ["UIInterfaceOrientationPortrait", "UIInterfaceOrientationPortraitUpsideDown", "UIInterfaceOrientationLandscapeLeft", "UIInterfaceOrientationLandscapeRight"] UIUserInterfaceStyle = "Automatic" +DTXcodeBuild = "14A6270d" +CFBundleExecutable = "News" +DTCompiler = "com.apple.compilers.llvm.clang.1_0" +CFBundleIconName = "AppIcon" +UIStatusBarHidden = false +"UISupportedInterfaceOrientations~ipad" = [ +"UIInterfaceOrientationPortrait", +"UIInterfaceOrientationPortraitUpsideDown", +"UIInterfaceOrientationLandscapeLeft", +"UIInterfaceOrientationLandscapeRight", +] +BuildMachineOSBuild = "20A241133" UIViewControllerBasedStatusBarAppearance = true +UIBackgroundModes = ["audio","fetch","remote-notification"] +NSAccentColorName = "NewsAccentColor" UIViewEdgeAntialiasing = false -UIViewGroupOpacity = false -UIWhitePointAdaptivityStyle = "UIWhitePointAdaptivityStyleReading" +DTPlatformName = "macosx" +SBMatchingApplicationGenres = [ +"News","Reference","Entertainment","Productivity","Education", +"Business", +] +NSUserActivityTypes = [ +"TagIntent","TodayIntent","com.apple.news.articleViewing", +"com.apple.news.feedBrowsing","com.apple.news.feedBackCatalog", +"com.apple.news.forYou","com.apple.news.history","com.apple.news.saved", +"com.apple.news.magazineSections","com.apple.news.link", +] +UIApplicationShortcutWidget = "com.apple.news.widget" +CFBundleDevelopmentRegion = "en" +UISupportedInterfaceOrientations = ["UIInterfaceOrientationPortrait"] +CFBundleHelpBookFolder = "News.help" +BGTaskSchedulerPermittedIdentifiers = ["com.apple.news.backgroundFetchManager"] _LSSupportsRemoval = true -[CFBundleIcons] -["CFBundleIcons~ipad"] -[[CFBundleURLTypes]] - CFBundleTypeRole = "Editor" - CFBundleURLName = "com.apple.NewsCustomScheme" - CFBundleURLSchemes = ["applenews", "applenewss", "feed"] +DTSDKName = "macosx13.2.internal" +DTPlatformBuild = "22D40" +NSPhotoLibraryUsageDescription = "" +DTXcode = "1400" +LSCounterpartIdentifiers = ["com.apple.nanonews"] + [[UIApplicationShortcutItems]] - UIApplicationShortcutItemIconFile = "ios_for_you_icon_large" - UIApplicationShortcutItemTitle = "ApplicationShortcutItemForYou" - UIApplicationShortcutItemType = "com.apple.news.openforyou" +UIApplicationShortcutItemTitle = "ApplicationShortcutItemForYou" +UIApplicationShortcutItemIconFile = "ios_for_you_icon_large" +UIApplicationShortcutItemType = "com.apple.news.openforyou" +[UNUserNotificationCenter] +UNSuppressUserAuthorizationPrompt = false + +[UIApplicationSceneManifest] +UIApplicationSupportsMultipleScenes = "1" + +[UIApplicationSceneManifest.UISceneConfigurations] + +[[UIApplicationSceneManifest.UISceneConfigurations.UIWindowSceneSessionRoleApplication]] +UISceneConfigurationName = "Default Configuration" +UISceneDelegateClassName = "NewsUI2.SceneDelegate" +UISceneClassName = "TeaUI.WindowScene" + + +[[CFBundleURLTypes]] +CFBundleURLSchemes = ["applenews","applenewss"] +CFBundleURLName = "com.apple.NewsCustomScheme" +CFBundleTypeRole = "Editor" ``` Full header: @@ -150,6 +194,9 @@ Full header: ## Changelog +* v2.0.0 + * switched to [toml11] (https://github.com/ToruNiina/toml11 + * v1.1.0 * Updated to cpptoml v0.1.1 * Added more arguments, help and error reporting to the `tomlutil` diff --git a/tomlutil/Info.plist b/tomlutil/Info.plist index ccba116..39cb141 100644 --- a/tomlutil/Info.plist +++ b/tomlutil/Info.plist @@ -6,8 +6,8 @@ $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleShortVersionString 2.0.0 - LPMToml11Version - 3.7.0 + LMPToml11Version + 3.7.1 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} diff --git a/tomlutil/main.m b/tomlutil/main.m index 204f6ea..ab3a4e8 100644 --- a/tomlutil/main.m +++ b/tomlutil/main.m @@ -73,7 +73,7 @@ static LMPFileFormat formatFromFilename(NSString *filename) { static NSString *version_string(void) { NSString *shortVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; // NSString *bundleVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]; - NSString *toml11Version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"LPMToml11Version"]; + NSString *toml11Version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"LMPToml11Version"]; NSString *versionLineString = [NSString stringWithFormat:@"tomlutil v%@ (toml11 v%@)", shortVersion, toml11Version]; return versionLineString; From 999f86ce65acfcd697877af63785f6ed308a976c Mon Sep 17 00:00:00 2001 From: Dominik Wagner Date: Sun, 12 Feb 2023 14:14:09 +0100 Subject: [PATCH 13/13] Fixing README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index cb51279..ff73bef 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,6 @@ Usage: tomlutil [-f json|xml1|binary1|toml] file [outputfile] A file of '-' reads from stdin. Can read json, plists and toml. Output defaults to stdout. -f format Output format. One of json, xml1, binary1, toml. Defaults to toml. -lint Just lint with toml11, no output. -┌─(...-cxgxrczcjchjyyhfjlnxipqyqbsh/Build/Products/Debug)───(dom@darthy:s001)─┐ ``` Simple conversion of the Mojave News.app plist to TOML: