From ffd196dcdf50a1e503f9132f7e17b5e8ee69f3f6 Mon Sep 17 00:00:00 2001 From: Ahti Legonkov Date: Tue, 4 Jul 2023 09:06:43 +0300 Subject: [PATCH 1/4] Refactor config parsing - rename some globals - return unique_ptr from read_config_recursive - make functions used in config.cpp only, static --- winlirc/config.cpp | 164 ++++++++++++++++++++++----------------------- winlirc/config.h | 9 --- 2 files changed, 80 insertions(+), 93 deletions(-) diff --git a/winlirc/config.cpp b/winlirc/config.cpp index 4842d7d..061216a 100644 --- a/winlirc/config.cpp +++ b/winlirc/config.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -16,34 +17,35 @@ #include #include +enum directive { ID_none, ID_remote, ID_codes, ID_raw_codes, ID_raw_name }; + static constexpr size_t LINE_LEN = 1024; static constexpr uint32_t MAX_INCLUDES = 10; static constexpr char whitespace[] = " \t"; -static int line; -static int parse_error; +static int g_line; +static int g_parse_error; -static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, int depth); +static std::unique_ptr read_config_recursive(FILE *f, winlirc::istring_view name, int depth); template requires(std::is_integral_v) static Int s_str_to_int(std::basic_string_view s) { - Int out; - auto end = s.data() + s.size(); auto const base = [&]() { if (s.starts_with("0x")) { s.remove_prefix(2); return 16; } - else - return 10; + return 10; }(); - auto res = std::from_chars(s.data(), end, out, base); + Int out; + auto end = s.data() + s.size(); + auto res = std::from_chars(s.data(), end, out, base); if (res.ec == std::errc{} && res.ptr == end) return out; - parse_error = 1; + g_parse_error = 1; return Int{}; } @@ -77,25 +79,25 @@ static lirc_t s_strtolirc_t(std::basic_string_view val) return s_str_to_int(val); } -int checkMode(int is_mode, int c_mode, char const* error) +static int checkMode(int is_mode, int c_mode, char const* error) noexcept { if (is_mode!=c_mode) { - parse_error=1; - return(0); + g_parse_error=1; + return 0; } - return(1); + return 1; } -int addSignal(std::vector& signals, winlirc::istring_view val) +static int addSignal(std::vector& signals, winlirc::istring_view val) noexcept { auto t=s_strtolirc_t(val); - if(parse_error) return(0); + if(g_parse_error) return(0); signals.push_back(t); return(1); } -ir_ncode* defineCode(winlirc::istring_view key, winlirc::istring_view val, ir_ncode* code) +static ir_ncode* defineCode(winlirc::istring_view key, winlirc::istring_view val, ir_ncode* code) noexcept { *code = ir_ncode{}; code->name = std::string{ begin(key), end(key) }; @@ -103,7 +105,7 @@ ir_ncode* defineCode(winlirc::istring_view key, winlirc::istring_view val, ir_nc return code; } -ir_code_node* defineNode(ir_ncode* code, winlirc::istring_view val) +static ir_code_node* defineNode(ir_ncode* code, winlirc::istring_view val) noexcept { auto node = std::make_unique(); auto const res = node.get(); @@ -123,7 +125,7 @@ ir_code_node* defineNode(ir_ncode* code, winlirc::istring_view val) return res; } -int parseFlags(winlirc::istring_view val) +static int parseFlags(winlirc::istring_view val) noexcept { int flags = 0; while (!val.empty()) @@ -136,7 +138,7 @@ int parseFlags(winlirc::istring_view val) flagIt == std::end(all_flags) || (flagIt->flag & IR_PROTOCOL_MASK) && (flags & IR_PROTOCOL_MASK)) { - parse_error = 1; + g_parse_error = 1; return 0; } flags = flags | flagIt->flag; @@ -144,7 +146,11 @@ int parseFlags(winlirc::istring_view val) return flags; } -int defineRemote(winlirc::istring_view key, winlirc::istring_view val, winlirc::istring_view val2, ir_remote *rem) +static int defineRemote( + winlirc::istring_view key, + winlirc::istring_view val, + winlirc::istring_view val2, + ir_remote* rem) noexcept { if ("name" == key){ rem->name.assign(val.begin(), val.end()); @@ -255,7 +261,7 @@ int defineRemote(winlirc::istring_view key, winlirc::istring_view val, winlirc:: else if ("serial_mode" == key){ if(val[0]<'5' || val[0]>'9') { - parse_error=1; + g_parse_error=1; return 0; } rem->bits_in_byte=val[0]-'0'; @@ -271,7 +277,7 @@ int defineRemote(winlirc::istring_view key, winlirc::istring_view val, winlirc:: rem->parity = IR_PARITY_ODD; break; default: - parse_error=1; + g_parse_error=1; return 0; } if(val.substr(2) == "1.5") @@ -332,7 +338,7 @@ int defineRemote(winlirc::istring_view key, winlirc::istring_view val, winlirc:: return(2); } } - parse_error=1; + g_parse_error=1; return(0); } @@ -371,24 +377,21 @@ static int sanityChecks(ir_remote *rem) return 1; } -ir_remote* sort_by_bit_count(ir_remote *remotes) +static std::unique_ptr sort_by_bit_count(std::unique_ptr remotes) noexcept { - std::vector v; - for (auto rem = remotes; rem != nullptr; rem = rem->next.get()) + assert(remotes); + std::vector> v; + while (remotes) { - v.push_back(rem); + v.push_back(std::exchange(remotes, std::move(remotes->next))); } - std::sort(v.begin(), v.end(), [](auto& a, auto& b) { return bit_count(a) < bit_count(b); }); - for (ir_remote* rem : v) - { - rem->next.release(); - } - for (size_t i = 1; i < v.size(); ++i) + std::sort(v.begin(), v.end(), [](auto& a, auto& b) { return bit_count(a.get()) < bit_count(b.get()); }); + + for (size_t i = v.size() - 2; i != ~size_t{}; --i) { - v[i - 1]->next.reset(v[i]); + v[i]->next = std::move(v[i + 1]); } - v.back()->next.reset(); - return v[0]; + return std::move(v[0]); } static winlirc::istring_view lirc_parse_include(winlirc::istring_view s) @@ -418,15 +421,16 @@ static winlirc::istring lirc_parse_relative(winlirc::istring_view child, winlirc std::unique_ptr read_config(FILE *f, const char *name) { - return std::unique_ptr{ read_config_recursive(f, name, 0) }; + return read_config_recursive(f, name, 0); } -static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, int depth) +static std::unique_ptr read_config_recursive(FILE *f, winlirc::istring_view name, int depth) { char bufx[LINE_LEN + 1]; winlirc::istring_view key, val, val2; int argc; - ir_remote *top_rem=nullptr,*rem=nullptr; + std::unique_ptr top_rem; + ir_remote* rem = nullptr; std::vector codes_list,raw_codes; std::vector signals; ir_ncode raw_code{}; @@ -434,16 +438,16 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in ir_ncode *code; int mode=ID_none; - line=0; - parse_error=0; + g_line=0; + g_parse_error=0; while(fgets(bufx,LINE_LEN,f)!=nullptr) { winlirc::istring_view buf{ bufx }; - line++; + g_line++; if (buf.size() == LINE_LEN && buf.back() != '\n') { - parse_error=1; + g_parse_error=1; break; } @@ -464,19 +468,19 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in if ("include" == key){ if (depth > MAX_INCLUDES) { - parse_error=-1; + g_parse_error=-1; break; } auto childName = lirc_parse_include(val); if (childName.empty()){ - parse_error=-1; + g_parse_error=-1; break; } auto fullPath = lirc_parse_relative(childName, name); if (fullPath.empty()) { - parse_error=-1; + g_parse_error=-1; break; } @@ -484,24 +488,20 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in auto const openResult = fopen_s(&childFile, fullPath.c_str(), "r"); if (childFile != nullptr) { - int save_line = line; + int save_line = g_line; if (!top_rem){ /* create first remote */ - rem = read_config_recursive(childFile, fullPath, depth + 1); - if(rem != (void *) -1 && rem != nullptr) { - top_rem = rem; - } else { - rem = nullptr; - } + top_rem = read_config_recursive(childFile, fullPath, depth + 1); + rem = top_rem.get(); }else{ /* create new remote */ - rem->next.reset(read_config_recursive(childFile, fullPath, depth + 1)); - rem=rem->next.get(); + rem->next = read_config_recursive(childFile, fullPath, depth + 1); + rem = rem->next.get(); } fclose(childFile); - line = save_line; + g_line = save_line; } }else if ("begin" == key){ if ("codes" == val){ @@ -510,7 +510,7 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in if (!checkMode(mode, ID_remote, "begin codes")) break; if (!rem->codes.empty()){ - parse_error=1; + g_parse_error=1; break; } @@ -524,7 +524,7 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in "begin raw_codes")) break; if (!rem->codes.empty()){ - parse_error=1; + g_parse_error=1; break; } set_protocol(rem, RAW_CODES); @@ -535,22 +535,23 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in }else if("remote" == val){ /* create new remote */ - if(!checkMode(mode, ID_none, - "begin remote")) break; + if(!checkMode(mode, ID_none, "begin remote")) + break; mode=ID_remote; if (!top_rem){ /* create first remote */ - rem = top_rem = new ir_remote{}; + top_rem = std::make_unique(); + rem = top_rem.get(); }else{ /* create new remote */ - rem->next.reset(new ir_remote{}); - rem=rem->next.get(); + rem->next = std::make_unique(); + rem = rem->next.get(); } }else if(mode==ID_codes){ code=defineCode(key, val, &name_code); - while(!parse_error && !val2.empty()) + while(!g_parse_error && !val2.empty()) { struct ir_code_node *node; @@ -561,7 +562,7 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in code->current=nullptr; codes_list.push_back(std::move(*code)); }else{ - parse_error=1; + g_parse_error=1; } }else if ("end" == key){ @@ -581,7 +582,7 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in raw_code.signals=signals; if(raw_code.length()%2==0) { - parse_error=1; + g_parse_error=1; } raw_codes.push_back(std::move(raw_code)); mode=ID_raw_codes; @@ -597,7 +598,7 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in if (!checkMode(mode,ID_remote, "end remote")) break; if(!sanityChecks(rem)) { - parse_error=1; + g_parse_error=1; break; } @@ -608,7 +609,7 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in mode=ID_none; /* switch back */ }else if(mode==ID_codes){ code=defineCode(key, val, &name_code); - while(!parse_error && !val2.empty()) + while(!g_parse_error && !val2.empty()) { if(val2[0]=='#') break; /* comment */ ir_code_node* node=defineNode(code, val2); @@ -617,7 +618,7 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in code->current=nullptr; codes_list.push_back(std::move(*code)); }else{ - parse_error=1; + g_parse_error=1; } } else { switch (mode){ @@ -626,7 +627,7 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in break; case ID_codes: code=defineCode(key, val, &name_code); - while(!parse_error && !val2.empty()) + while(!g_parse_error && !val2.empty()) { if(val2[0]=='#') break; /* comment */ ir_code_node* node=defineNode(code, val2); @@ -643,7 +644,7 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in raw_code.signals = std::move(signals); if(raw_code.length()%2==0) { - parse_error=1; + g_parse_error=1; } raw_codes.push_back(std::move(raw_code)); } @@ -655,7 +656,7 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in }else{ if(mode==ID_raw_codes) { - parse_error=1; + g_parse_error=1; break; } if(!addSignal(signals, key)) break; @@ -678,10 +679,10 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in break; } }else{ - parse_error=1; + g_parse_error=1; break; } - if (parse_error){ + if (g_parse_error){ break; } } @@ -702,25 +703,24 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in rem->codes = std::move(codes_list); break; } - if(!parse_error) + if(!g_parse_error) { - parse_error=1; + g_parse_error=1; } } - if (parse_error){ + if (g_parse_error){ static int print_error = 1; if(print_error) { } - delete top_rem; if(depth == 0) print_error = 1; return nullptr; } /* kick reverse flag */ /* handle RC6 flag to be backwards compatible: previous RC-6 config files did not set rc6_mask */ - rem=top_rem; + rem=top_rem.get(); while(rem!=nullptr) { if((!is_raw(rem)) && rem->flags&REVERSE) @@ -803,9 +803,5 @@ static ir_remote * read_config_recursive(FILE *f, winlirc::istring_view name, in rem=rem->next.get(); } - top_rem = sort_by_bit_count(top_rem); -# if defined(DEBUG) && !defined(DAEMONIZE) - /*fprint_remotes(stderr, top_rem);*/ -# endif - return (top_rem); + return sort_by_bit_count(std::move(top_rem)); } diff --git a/winlirc/config.h b/winlirc/config.h index 7026ca9..bd6cb51 100644 --- a/winlirc/config.h +++ b/winlirc/config.h @@ -33,14 +33,5 @@ static constexpr flaglist all_flags[]= {"REPEAT_HEADER", REPEAT_HEADER}, }; -/* - config stuff -*/ - -enum directive {ID_none,ID_remote,ID_codes,ID_raw_codes,ID_raw_name}; - -/* some safer functions */ struct ir_remote; - -int checkMode(int is_mode, int c_mode, char const* error); std::unique_ptr read_config(FILE *f, const char *name); From 02e1025637c4877a15328aea940537f1bcffb2ef Mon Sep 17 00:00:00 2001 From: Ahti Legonkov Date: Thu, 6 Jul 2023 03:15:25 +0300 Subject: [PATCH 2/4] Remove global parse_error --- winlirc/config.cpp | 1348 ++++++++++++++++++++++---------------------- 1 file changed, 669 insertions(+), 679 deletions(-) diff --git a/winlirc/config.cpp b/winlirc/config.cpp index 061216a..aeb1320 100644 --- a/winlirc/config.cpp +++ b/winlirc/config.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include #include @@ -23,375 +25,360 @@ static constexpr size_t LINE_LEN = 1024; static constexpr uint32_t MAX_INCLUDES = 10; static constexpr char whitespace[] = " \t"; static int g_line; -static int g_parse_error; +//static int g_parse_error; -static std::unique_ptr read_config_recursive(FILE *f, winlirc::istring_view name, int depth); +static std::unique_ptr read_config_recursive(FILE* f, winlirc::istring_view name, int depth); -template -requires(std::is_integral_v) -static Int s_str_to_int(std::basic_string_view s) +template + requires(std::is_integral_v) +static std::expected s_str_to_int(std::span s) { auto const base = [&]() { - if (s.starts_with("0x")) + if (s.size() >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { - s.remove_prefix(2); + s = s.subspan(2); return 16; } return 10; }(); - Int out; - auto end = s.data() + s.size(); - auto res = std::from_chars(s.data(), end, out, base); - if (res.ec == std::errc{} && res.ptr == end) + Int out; + auto end = s.data() + s.size(); + auto res = std::from_chars(s.data(), end, out, base); + if (res.ec == std::errc{}&& res.ptr == end) return out; - g_parse_error = 1; - return Int{}; + return std::unexpected{std::make_error_code(std::errc::invalid_argument)}; } -template -static ir_code s_strtocode(std::basic_string_view val) +static std::expected s_strtocode(std::span val) { return s_str_to_int(val); } -template -static unsigned long s_strtoul(std::basic_string_view val) +static std::expected s_strtoul(std::span val) { return s_str_to_int(val); } -template -static int s_strtoi(std::basic_string_view val) +static std::expected s_strtoi(std::span val) { return s_str_to_int(val); } -template -static unsigned int s_strtoui(std::basic_string_view val) +static std::expected s_strtoui(std::span val) { return s_str_to_int(val); } -template -static lirc_t s_strtolirc_t(std::basic_string_view val) +static std::expected s_strtolirc_t(std::span val) { return s_str_to_int(val); } -static int checkMode(int is_mode, int c_mode, char const* error) noexcept +static std::expected checkMode(int is_mode, int c_mode, char const* error) noexcept { - if (is_mode!=c_mode) - { - g_parse_error=1; - return 0; - } - return 1; + if (is_mode != c_mode) + return std::unexpected{ std::make_error_code(std::errc::state_not_recoverable) }; + return {}; } -static int addSignal(std::vector& signals, winlirc::istring_view val) noexcept +static std::expected addSignal(std::vector& signals, winlirc::istring_view val) noexcept { - auto t=s_strtolirc_t(val); - if(g_parse_error) return(0); - signals.push_back(t); - return(1); + auto t = s_strtolirc_t(val); + if (!t) + return std::unexpected{t.error()}; + signals.push_back(*t); + return {}; } -static ir_ncode* defineCode(winlirc::istring_view key, winlirc::istring_view val, ir_ncode* code) noexcept +static std::expected defineCode(winlirc::istring_view key, winlirc::istring_view val, ir_ncode* code) noexcept { - *code = ir_ncode{}; - code->name = std::string{ begin(key), end(key) }; - code->code = s_strtocode(val); - return code; + *code = ir_ncode{}; + code->name = std::string{ begin(key), end(key) }; + if (auto c = s_strtocode(val)) + { + code->code = *c; + return code; + } + else + { + return std::unexpected{c.error()}; + } } -static ir_code_node* defineNode(ir_ncode* code, winlirc::istring_view val) noexcept +static std::expected defineNode(ir_ncode* code, winlirc::istring_view val) noexcept { - auto node = std::make_unique(); - auto const res = node.get(); - node->code=s_strtocode(val); - node->next=nullptr; - - if (code->current == nullptr) - { - code->current = node.get(); - code->next = std::move(node); - } - else - { - code->current = node.get(); - code->current->next = std::move(node); - } - return res; + if (auto c = s_strtocode(val)) + { + auto node = std::make_unique(); + auto const res = node.get(); + node->code = *c; + node->next = nullptr; + + if (code->current == nullptr) + { + code->current = node.get(); + code->next = std::move(node); + } + else + { + code->current = node.get(); + code->current->next = std::move(node); + } + return res; + } + else + { + return std::unexpected{c.error()}; + } } -static int parseFlags(winlirc::istring_view val) noexcept +static std::expected parseFlags(winlirc::istring_view val) noexcept { int flags = 0; while (!val.empty()) { auto flagName = strtok(val, "|"); - auto flagIt = std::find_if(std::begin(all_flags), std::end(all_flags), [&](auto& fp) { + auto flagIt = std::find_if(std::begin(all_flags), std::end(all_flags), [&](auto& fp) { return fp.name == flagName; }); - if ( - flagIt == std::end(all_flags) || - (flagIt->flag & IR_PROTOCOL_MASK) && (flags & IR_PROTOCOL_MASK)) + if (flagIt == std::end(all_flags) || + (flagIt->flag & IR_PROTOCOL_MASK) && (flags & IR_PROTOCOL_MASK)) { - g_parse_error = 1; - return 0; + return std::unexpected{std::make_error_code(std::errc::invalid_argument)}; } flags = flags | flagIt->flag; } return flags; } -static int defineRemote( +template +static std::expected parse_field( + T ir_remote::* member, + ParsedValue val, + ir_remote* rem) noexcept +{ + if (val) { + rem->*member = *val; + return {}; + } + return std::unexpected{val.error()}; +} + +template +std::expected operator&&(std::expected&& lhs, Fun&& fun) +{ + if (lhs) + return fun(std::move(lhs)); + return lhs; +} + +static std::expected defineRemote( winlirc::istring_view key, winlirc::istring_view val, winlirc::istring_view val2, ir_remote* rem) noexcept { - if ("name" == key){ - rem->name.assign(val.begin(), val.end()); - return(1); - } - else if ("bits" == key){ - rem->bits=s_strtoi(val); - return(1); - } - else if ("flags" == key){ - rem->flags|=parseFlags(val); - return(1); - } - else if ("eps" == key){ - rem->eps=s_strtoi(val); - return(1); - } - else if ("aeps" == key){ - rem->aeps=s_strtoi(val); - return(1); - } - else if ("plead" == key){ - rem->plead=s_strtolirc_t(val); - return(1); - } - else if ("ptrail" == key){ - rem->ptrail=s_strtolirc_t(val); - return(1); - } - else if ("pre_data_bits" == key){ - rem->pre_data_bits=s_strtoi(val); - return(1); - } - else if ("pre_data" == key){ - rem->pre_data=s_strtocode(val); - return(1); - } - else if ("post_data_bits" == key){ - rem->post_data_bits=s_strtoi(val); - return(1); - } - else if ("post_data" == key){ - rem->post_data=s_strtocode(val); - return(1); - } - else if ("gap" == key){ - if(!val2.empty()) - { - rem->gap2=s_strtoul(val2); - } - rem->gap=s_strtoul(val); - return(!val2.empty() ? 2:1); - } - else if ("repeat_gap" == key){ - rem->repeat_gap=s_strtoul(val); - return(1); - } - /* obsolete: use toggle_bit_mask instead */ - else if ("toggle_bit" == key){ - rem->toggle_bit = s_strtoi(val); - return 1; - } - else if ("toggle_bit_mask" == key){ - rem->toggle_bit_mask = s_strtocode(val); - return 1; - } - else if ("toggle_mask" == key){ - rem->toggle_mask=s_strtocode(val); - return(1); - } - else if ("rc6_mask" == key){ - rem->rc6_mask=s_strtocode(val); - return(1); - } - else if ("ignore_mask" == key){ - rem->ignore_mask=s_strtocode(val); - return(1); - } - /* obsolete name */ - else if ("repeat_bit" == key){ - rem->toggle_bit=s_strtoi(val); - return(1); - } - else if ("suppress_repeat" == key){ - //rem->suppress_repeat=s_strtoi(val); //TODO support this per remote - return(1); - } - else if ("min_repeat" == key){ - rem->min_repeat=s_strtoi(val); - return(1); - } - else if ("min_code_repeat" == key){ - rem->min_code_repeat=s_strtoi(val); - return(1); - } - else if ("frequency" == key){ - rem->freq=s_strtoui(val); - return(1); - } - else if ("duty_cycle" == key){ - rem->duty_cycle=s_strtoui(val); - return(1); - } - else if ("baud" == key){ - rem->baud=s_strtoui(val); - return(1); - } - else if ("serial_mode" == key){ - if(val[0]<'5' || val[0]>'9') - { - g_parse_error=1; - return 0; - } - rem->bits_in_byte=val[0]-'0'; - switch(toupper(val[1])) - { - case 'N': - rem->parity = IR_PARITY_NONE; - break; - case 'E': - rem->parity = IR_PARITY_EVEN; - break; - case 'O': - rem->parity = IR_PARITY_ODD; - break; - default: - g_parse_error=1; - return 0; - } - if(val.substr(2) == "1.5") - { - rem->stop_bits=3; - } - else - { - rem->stop_bits=s_strtoui(val.substr(2))*2; - } - return(1); - } - else if (!val2.empty()) - { - if ("header" == key){ - rem->phead=s_strtolirc_t(val); - rem->shead=s_strtolirc_t(val2); - return(2); - } - else if ("three" == key){ - rem->pthree=s_strtolirc_t(val); - rem->sthree=s_strtolirc_t(val2); - return(2); - } - else if ("two" == key){ - rem->ptwo=s_strtolirc_t(val); - rem->stwo=s_strtolirc_t(val2); - return(2); - } - else if ("one" == key){ - rem->pone=s_strtolirc_t(val); - rem->sone=s_strtolirc_t(val2); - return(2); - } - else if ("zero" == key){ - rem->pzero=s_strtolirc_t(val); - rem->szero=s_strtolirc_t(val2); - return(2); - } - else if ("foot" == key){ - rem->pfoot=s_strtolirc_t(val); - rem->sfoot=s_strtolirc_t(val2); - return(2); - } - else if ("repeat" == key){ - rem->prepeat=s_strtolirc_t(val); - rem->srepeat=s_strtolirc_t(val2); - return(2); - } - else if ("pre" == key){ - rem->pre_p=s_strtolirc_t(val); - rem->pre_s=s_strtolirc_t(val2); - return(2); - } - else if ("post" == key){ - rem->post_p=s_strtolirc_t(val); - rem->post_s=s_strtolirc_t(val2); - return(2); - } - } - g_parse_error=1; - return(0); + if ("name" == key) { + rem->name.assign(val.begin(), val.end()); + return {}; + } + else if ("bits" == key) { + return parse_field(&ir_remote::bits, s_strtoi(val), rem); + } + else if ("flags" == key) { + return parse_field(&ir_remote::flags, parseFlags(val), rem); + } + else if ("eps" == key) { + return parse_field(&ir_remote::eps, s_strtoi(val), rem); + } + else if ("aeps" == key) { + return parse_field(&ir_remote::aeps, s_strtoi(val), rem); + } + else if ("plead" == key) { + return parse_field(&ir_remote::plead, s_strtolirc_t(val), rem); + } + else if ("ptrail" == key) { + return parse_field(&ir_remote::ptrail, s_strtolirc_t(val), rem); + } + else if ("pre_data_bits" == key) { + return parse_field(&ir_remote::pre_data_bits, s_strtoi(val), rem); + } + else if ("pre_data" == key) { + return parse_field(&ir_remote::pre_data, s_strtocode(val), rem); + } + else if ("post_data_bits" == key) { + return parse_field(&ir_remote::post_data_bits, s_strtoi(val), rem); + } + else if ("post_data" == key) { + return parse_field(&ir_remote::post_data, s_strtocode(val), rem); + } + else if ("gap" == key) { + if (!val2.empty()) { + if (auto f = parse_field(&ir_remote::gap2, s_strtoul(val2), rem); !f) + return f; + } + return parse_field(&ir_remote::gap, s_strtoul(val), rem); + } + else if ("repeat_gap" == key) { + return parse_field(&ir_remote::repeat_gap, s_strtoul(val), rem); + } + else if ("toggle_bit" == key + || "repeat_bit" == key/* obsolete name */) { + /* obsolete: use toggle_bit_mask instead */ + return parse_field(&ir_remote::toggle_bit, s_strtoi(val), rem); + } + else if ("toggle_bit_mask" == key) { + return parse_field(&ir_remote::toggle_bit_mask, s_strtocode(val), rem); + } + else if ("toggle_mask" == key) { + return parse_field(&ir_remote::toggle_mask, s_strtocode(val), rem); + } + else if ("rc6_mask" == key) { + return parse_field(&ir_remote::rc6_mask, s_strtocode(val), rem); + } + else if ("ignore_mask" == key) { + return parse_field(&ir_remote::ignore_mask, s_strtocode(val), rem); + } + else if ("suppress_repeat" == key) { + //rem->suppress_repeat=s_strtoi(val); //TODO support this per remote + return {}; + } + else if ("min_repeat" == key) { + return parse_field(&ir_remote::min_repeat, s_strtoi(val), rem); + } + else if ("min_code_repeat" == key) { + return parse_field(&ir_remote::min_code_repeat, s_strtoi(val), rem); + } + else if ("frequency" == key) { + return parse_field(&ir_remote::freq, s_strtoui(val), rem); + } + else if ("duty_cycle" == key) { + return parse_field(&ir_remote::duty_cycle, s_strtoui(val), rem); + } + else if ("baud" == key) { + return parse_field(&ir_remote::baud, s_strtoui(val), rem); + } + else if ("serial_mode" == key) { + if (val[0] < '5' || '9' < val[0]) + { + return std::unexpected(std::make_error_code(std::errc::invalid_argument)); + } + rem->bits_in_byte = val[0] - '0'; + switch (val[1]) + { + case 'n': case 'N': + rem->parity = IR_PARITY_NONE; + break; + case 'e': case 'E': + rem->parity = IR_PARITY_EVEN; + break; + case 'o': case 'O': + rem->parity = IR_PARITY_ODD; + break; + default: + return std::unexpected(std::make_error_code(std::errc::invalid_argument)); + } + if (val.substr(2) == "1.5") + rem->stop_bits = 3; + else if (auto v = s_strtoui(val.substr(2))) + rem->stop_bits = *v; + else + return std::unexpected(v.error()); + return {}; + } + else if (!val2.empty()) + { + if ("header" == key) { + return parse_field(&ir_remote::phead, s_strtolirc_t(val), rem) + .and_then([&] { return parse_field(&ir_remote::shead, s_strtolirc_t(val2), rem); }); + } + else if ("three" == key) { + return parse_field(&ir_remote::pthree, s_strtolirc_t(val), rem) + .and_then([&] { return parse_field(&ir_remote::sthree, s_strtolirc_t(val2), rem); }); + } + else if ("two" == key) { + return parse_field(&ir_remote::ptwo, s_strtolirc_t(val), rem) + .and_then([&] { return parse_field(&ir_remote::stwo, s_strtolirc_t(val2), rem); }); + } + else if ("one" == key) { + return parse_field(&ir_remote::pone, s_strtolirc_t(val), rem) + .and_then([&] { return parse_field(&ir_remote::sone, s_strtolirc_t(val2), rem); }); + } + else if ("zero" == key) { + return parse_field(&ir_remote::pzero, s_strtolirc_t(val), rem) + .and_then([&] { return parse_field(&ir_remote::szero, s_strtolirc_t(val2), rem); }); + } + else if ("foot" == key) { + return parse_field(&ir_remote::pfoot, s_strtolirc_t(val), rem) + .and_then([&] { return parse_field(&ir_remote::sfoot, s_strtolirc_t(val2), rem); }); + } + else if ("repeat" == key) { + return parse_field(&ir_remote::prepeat, s_strtolirc_t(val), rem) + .and_then([&] { return parse_field(&ir_remote::srepeat, s_strtolirc_t(val2), rem); }); + } + else if ("pre" == key) { + return parse_field(&ir_remote::pre_p, s_strtolirc_t(val), rem) + .and_then([&] { return parse_field(&ir_remote::pre_s, s_strtolirc_t(val2), rem); }); + } + else if ("post" == key) { + return parse_field(&ir_remote::post_p, s_strtolirc_t(val), rem) + .and_then([&] { return parse_field(&ir_remote::post_s, s_strtolirc_t(val2), rem); }); + } + } + return std::unexpected{std::make_error_code(std::errc::invalid_argument)}; } -static int sanityChecks(ir_remote *rem) +static int sanityChecks(ir_remote* rem) { - if (rem->name.empty()) - { - return 0; - } - - if(is_raw(rem)) return 1; - - if((rem->pre_data&gen_mask(rem->pre_data_bits)) != rem->pre_data) - { - rem->pre_data &= gen_mask(rem->pre_data_bits); - } - if((rem->post_data&gen_mask(rem->post_data_bits)) != rem->post_data) - { - rem->post_data &= gen_mask(rem->post_data_bits); - } - for (auto codes = rem->codes.begin(); codes != rem->codes.end(); codes++) - { - if ((codes->code & gen_mask(rem->bits)) != codes->code) - { - codes->code &= gen_mask(rem->bits); - } - for (auto node = codes->next.get(); node != nullptr; node = node->next.get()) - { - if ((node->code & gen_mask(rem->bits)) != node->code) - { - node->code &= gen_mask(rem->bits); - } - } - } - - return 1; + if (rem->name.empty()) + { + return 0; + } + + if (is_raw(rem)) return 1; + + if ((rem->pre_data & gen_mask(rem->pre_data_bits)) != rem->pre_data) + { + rem->pre_data &= gen_mask(rem->pre_data_bits); + } + if ((rem->post_data & gen_mask(rem->post_data_bits)) != rem->post_data) + { + rem->post_data &= gen_mask(rem->post_data_bits); + } + for (auto codes = rem->codes.begin(); codes != rem->codes.end(); codes++) + { + if ((codes->code & gen_mask(rem->bits)) != codes->code) + { + codes->code &= gen_mask(rem->bits); + } + for (auto node = codes->next.get(); node != nullptr; node = node->next.get()) + { + if ((node->code & gen_mask(rem->bits)) != node->code) + { + node->code &= gen_mask(rem->bits); + } + } + } + + return 1; } static std::unique_ptr sort_by_bit_count(std::unique_ptr remotes) noexcept { - assert(remotes); - std::vector> v; - while (remotes) - { - v.push_back(std::exchange(remotes, std::move(remotes->next))); - } - std::sort(v.begin(), v.end(), [](auto& a, auto& b) { return bit_count(a.get()) < bit_count(b.get()); }); - - for (size_t i = v.size() - 2; i != ~size_t{}; --i) - { - v[i]->next = std::move(v[i + 1]); - } - return std::move(v[0]); + assert(remotes); + std::vector> v; + while (remotes) + { + v.push_back(std::exchange(remotes, std::move(remotes->next))); + } + std::sort(v.begin(), v.end(), [](auto& a, auto& b) { return bit_count(a.get()) < bit_count(b.get()); }); + + for (size_t i = v.size() - 2; i != ~size_t{}; --i) + { + v[i]->next = std::move(v[i + 1]); + } + return std::move(v[0]); } static winlirc::istring_view lirc_parse_include(winlirc::istring_view s) @@ -408,400 +395,403 @@ static winlirc::istring_view lirc_parse_include(winlirc::istring_view s) static winlirc::istring lirc_parse_relative(winlirc::istring_view child, winlirc::istring_view current) { - if (current.empty()) - return static_cast(child); + if (current.empty()) + return static_cast(child); - std::filesystem::path p{ child }; - if (p.is_absolute()) - return static_cast(child); + std::filesystem::path p{ child }; + if (p.is_absolute()) + return static_cast(child); - auto cur = std::filesystem::path { current }.remove_filename() / child; - return cur.string().c_str(); + auto cur = std::filesystem::path{ current }.remove_filename() / child; + return cur.string().c_str(); } -std::unique_ptr read_config(FILE *f, const char *name) +std::unique_ptr read_config(FILE* f, const char* name) { - return read_config_recursive(f, name, 0); + return read_config_recursive(f, name, 0); } -static std::unique_ptr read_config_recursive(FILE *f, winlirc::istring_view name, int depth) +static std::unique_ptr read_config_recursive(FILE* f, winlirc::istring_view name, int depth) { char bufx[LINE_LEN + 1]; - winlirc::istring_view key, val, val2; - int argc; - std::unique_ptr top_rem; - ir_remote* rem = nullptr; - std::vector codes_list,raw_codes; - std::vector signals; - ir_ncode raw_code{}; - ir_ncode name_code{}; - ir_ncode *code; - int mode=ID_none; - - g_line=0; - g_parse_error=0; - - while(fgets(bufx,LINE_LEN,f)!=nullptr) - { + winlirc::istring_view key, val, val2; + std::unique_ptr top_rem; + ir_remote* rem = nullptr; + std::vector codes_list, raw_codes; + std::vector signals; + ir_ncode raw_code{}; + ir_ncode name_code{}; + ir_ncode* code; + int mode = ID_none; + + g_line = 0; + + while (fgets(bufx, LINE_LEN, f) != nullptr) + { winlirc::istring_view buf{ bufx }; - g_line++; + g_line++; if (buf.size() == LINE_LEN && buf.back() != '\n') - { - g_parse_error=1; - break; - } + { + return nullptr; + } - if (!buf.empty() && buf.back() == '\n') + if (!buf.empty() && buf.back() == '\n') buf.remove_suffix(1); if (!buf.empty() && buf.back() == '\r') buf.remove_suffix(1); - /* ignore comments */ - if(!buf.empty() && buf[0]=='#') - continue; - - key=strtok(buf, whitespace); - /* ignore empty lines */ - if(key.empty()) continue; - val=strtok(buf, whitespace); - if(!val.empty()){ - val2=strtok(buf, whitespace); - - if ("include" == key){ - if (depth > MAX_INCLUDES) { - g_parse_error=-1; - break; - } - - auto childName = lirc_parse_include(val); - if (childName.empty()){ - g_parse_error=-1; - break; - } - - auto fullPath = lirc_parse_relative(childName, name); - if (fullPath.empty()) { - g_parse_error=-1; - break; - } - - FILE* childFile; - auto const openResult = fopen_s(&childFile, fullPath.c_str(), "r"); - if (childFile != nullptr) - { - int save_line = g_line; - - if (!top_rem){ - /* create first remote */ - top_rem = read_config_recursive(childFile, fullPath, depth + 1); - rem = top_rem.get(); - }else{ - /* create new remote */ - - rem->next = read_config_recursive(childFile, fullPath, depth + 1); - rem = rem->next.get(); - } - fclose(childFile); - g_line = save_line; - } - }else if ("begin" == key){ - if ("codes" == val){ - /* init codes mode */ - - if (!checkMode(mode, ID_remote, - "begin codes")) break; - if (!rem->codes.empty()){ - g_parse_error=1; - break; - } - - codes_list.clear(); - codes_list.reserve(30); - mode=ID_codes; - }else if("raw_codes" == val){ - /* init raw_codes mode */ - - if(!checkMode(mode, ID_remote, - "begin raw_codes")) break; - if (!rem->codes.empty()){ - - g_parse_error=1; - break; - } - set_protocol(rem, RAW_CODES); - raw_code.code=0; - raw_codes.clear(); - raw_codes.reserve(30); - mode=ID_raw_codes; - }else if("remote" == val){ - /* create new remote */ - - if(!checkMode(mode, ID_none, "begin remote")) - break; - mode=ID_remote; - if (!top_rem){ - /* create first remote */ - - top_rem = std::make_unique(); - rem = top_rem.get(); - }else{ - /* create new remote */ - - rem->next = std::make_unique(); - rem = rem->next.get(); - } - }else if(mode==ID_codes){ - code=defineCode(key, val, &name_code); - while(!g_parse_error && !val2.empty()) - { - struct ir_code_node *node; - - if(val2[0]=='#') break; /* comment */ - node=defineNode(code, val2); - val2=strtok(buf, whitespace); - } - code->current=nullptr; - codes_list.push_back(std::move(*code)); - }else{ - g_parse_error=1; - } - }else if ("end" == key){ - - if ("codes" == val){ - /* end Codes mode */ - if (!checkMode(mode, ID_codes, - "end codes")) break; - rem->codes = std::move(codes_list); - codes_list.clear(); - mode=ID_remote; /* switch back */ - - }else if("raw_codes" == val){ - /* end raw codes mode */ - - - if(mode==ID_raw_name){ - raw_code.signals=signals; - if(raw_code.length()%2==0) - { - g_parse_error=1; - } - raw_codes.push_back(std::move(raw_code)); - mode=ID_raw_codes; - } - if(!checkMode(mode,ID_raw_codes, - "end raw_codes")) break; - rem->codes = std::move(raw_codes); - raw_codes.clear(); - mode=ID_remote; /* switch back */ - }else if("remote" == val){ - /* end remote mode */ - /* print_remote(rem); */ - if (!checkMode(mode,ID_remote, - "end remote")) break; - if(!sanityChecks(rem)) { - g_parse_error=1; - break; - } - - /* not really necessary because we - clear the alloced memory */ - rem->next=nullptr; - rem->last_code=nullptr; - mode=ID_none; /* switch back */ - }else if(mode==ID_codes){ - code=defineCode(key, val, &name_code); - while(!g_parse_error && !val2.empty()) - { - if(val2[0]=='#') break; /* comment */ - ir_code_node* node=defineNode(code, val2); - val2=strtok(buf, whitespace); - } - code->current=nullptr; - codes_list.push_back(std::move(*code)); - }else{ - g_parse_error=1; - } - } else { - switch (mode){ - case ID_remote: - argc=defineRemote(key, val, val2, rem); - break; - case ID_codes: - code=defineCode(key, val, &name_code); - while(!g_parse_error && !val2.empty()) - { - if(val2[0]=='#') break; /* comment */ - ir_code_node* node=defineNode(code, val2); - val2=strtok(buf, whitespace); - } - code->current=nullptr; - codes_list.push_back(std::move(*code)); - break; - case ID_raw_codes: - case ID_raw_name: - if("name" == key){ - if(mode==ID_raw_name) - { - raw_code.signals = std::move(signals); - if(raw_code.length()%2==0) - { - g_parse_error=1; - } - raw_codes.push_back(std::move(raw_code)); - } - raw_code.name = std::string{ begin(val), end(val) }; - raw_code.code++; - signals.clear(); - signals.reserve(50); - mode=ID_raw_name; - }else{ - if(mode==ID_raw_codes) - { - g_parse_error=1; - break; - } - if(!addSignal(signals, key)) break; - if(!addSignal(signals, val)) break; - if (!val2.empty()){ - if (!addSignal(signals, val2)){ - break; - } - } - while (true){ - auto val=strtok(buf, whitespace); - if (val.empty() || !addSignal(signals, val)) break; - } - } - break; - } - } - }else if(mode==ID_raw_name){ - if(!addSignal(signals, key)){ - break; - } - }else{ - g_parse_error=1; - break; - } - if (g_parse_error){ - break; - } - } - if(mode!=ID_none) - { - switch(mode) - { - case ID_raw_name: - if (raw_code.name != std::nullopt) - { - raw_code.name->clear(); - signals.clear(); - } - case ID_raw_codes: - rem->codes = std::move(raw_codes); - break; - case ID_codes: - rem->codes = std::move(codes_list); - break; - } - if(!g_parse_error) - { - g_parse_error=1; - } - } - if (g_parse_error){ - static int print_error = 1; - - if(print_error) { - - } - if(depth == 0) print_error = 1; - return nullptr; - } - /* kick reverse flag */ - /* handle RC6 flag to be backwards compatible: previous RC-6 - config files did not set rc6_mask */ - rem=top_rem.get(); - while(rem!=nullptr) - { - if((!is_raw(rem)) && rem->flags&REVERSE) - { - if(has_pre(rem)) - { - rem->pre_data=reverse(rem->pre_data, - rem->pre_data_bits); - } - if(has_post(rem)) - { - rem->post_data=reverse(rem->post_data, - rem->post_data_bits); - } - for (auto& c : rem->codes) - { - c.code = reverse(c.code, rem->bits); - } - rem->flags=rem->flags&(~REVERSE); - rem->flags=rem->flags|COMPAT_REVERSE; - /* don't delete the flag because we still need - it to remain compatible with older versions - */ - } - if(rem->flags&RC6 && rem->rc6_mask==0 && rem->toggle_bit>0) - { - int all_bits=bit_count(rem); - - rem->rc6_mask=((ir_code) 1)<<(all_bits-rem->toggle_bit); - } - if(rem->toggle_bit > 0) - { - int all_bits=bit_count(rem); - - if(!has_toggle_bit_mask(rem)) - { - rem->toggle_bit_mask=((ir_code) 1)<<(all_bits-rem->toggle_bit); - } - rem->toggle_bit = 0; - } - if(has_toggle_bit_mask(rem)) - { - if(!is_raw(rem) && !rem->codes.empty()) - { - rem->toggle_bit_mask_state = (rem->codes[0].code & rem->toggle_bit_mask); - if(rem->toggle_bit_mask_state) - { - /* start with state set to 0 for backwards compatibility */ - rem->toggle_bit_mask_state ^= rem->toggle_bit_mask; - } - } - } - if(is_serial(rem)) - { - if(rem->baud>0) - { - lirc_t base=1000000/rem->baud; - if(rem->pzero==0 && rem->szero==0) - { - rem->pzero=base; - } - if(rem->pone==0 && rem->sone==0) - { - rem->sone=base; - } - } - if(rem->bits_in_byte==0) - { - rem->bits_in_byte=8; - } - } - if(rem->min_code_repeat>0) - { - if(!has_repeat(rem) || - rem->min_code_repeat>rem->min_repeat) - { - rem->min_code_repeat = 0; - } - } - rem=rem->next.get(); - } - - return sort_by_bit_count(std::move(top_rem)); + /* ignore comments */ + if (!buf.empty() && buf[0] == '#') + continue; + + key = strtok(buf, whitespace); + /* ignore empty lines */ + if (key.empty()) continue; + val = strtok(buf, whitespace); + if (!val.empty()) { + val2 = strtok(buf, whitespace); + + if ("include" == key) { + if (depth > MAX_INCLUDES) { + return nullptr; + } + + auto childName = lirc_parse_include(val); + if (childName.empty()) { + return nullptr; + } + + auto fullPath = lirc_parse_relative(childName, name); + if (fullPath.empty()) { + return nullptr; + } + + FILE* childFile; + auto const openResult = fopen_s(&childFile, fullPath.c_str(), "r"); + if (childFile != nullptr) + { + int save_line = g_line; + + if (!top_rem) { + /* create first remote */ + top_rem = read_config_recursive(childFile, fullPath, depth + 1); + rem = top_rem.get(); + } + else { + /* create new remote */ + + rem->next = read_config_recursive(childFile, fullPath, depth + 1); + rem = rem->next.get(); + } + fclose(childFile); + g_line = save_line; + } + } + else if ("begin" == key) { + if ("codes" == val) { + /* init codes mode */ + + if (!checkMode(mode, ID_remote, + "begin codes")) break; + if (!rem->codes.empty()) { + return nullptr; + } + + codes_list.clear(); + codes_list.reserve(30); + mode = ID_codes; + } + else if ("raw_codes" == val) { + /* init raw_codes mode */ + + if (!checkMode(mode, ID_remote, + "begin raw_codes")) break; + if (!rem->codes.empty()) { + + return nullptr; + } + set_protocol(rem, RAW_CODES); + raw_code.code = 0; + raw_codes.clear(); + raw_codes.reserve(30); + mode = ID_raw_codes; + } + else if ("remote" == val) { + /* create new remote */ + + if (!checkMode(mode, ID_none, "begin remote")) + break; + mode = ID_remote; + if (!top_rem) { + /* create first remote */ + + top_rem = std::make_unique(); + rem = top_rem.get(); + } + else { + /* create new remote */ + + rem->next = std::make_unique(); + rem = rem->next.get(); + } + } + else if (mode == ID_codes) { + auto c = defineCode(key, val, &name_code); + if (!c) + return nullptr; + code = *c; + while (!val2.empty()) + { + if (val2[0] == '#') break; /* comment */ + if (!defineNode(code, val2)) + break; + val2 = strtok(buf, whitespace); + } + code->current = nullptr; + codes_list.push_back(std::move(*code)); + } + else { + return nullptr; + } + } + else if ("end" == key) { + + if ("codes" == val) { + /* end Codes mode */ + if (!checkMode(mode, ID_codes, "end codes")) + break; + rem->codes = std::move(codes_list); + codes_list.clear(); + mode = ID_remote; /* switch back */ + + } + else if ("raw_codes" == val) { + /* end raw codes mode */ + + + if (mode == ID_raw_name) { + raw_code.signals = signals; + if (raw_code.length() % 2 == 0) + return nullptr; + raw_codes.push_back(std::move(raw_code)); + mode = ID_raw_codes; + } + if (!checkMode(mode, ID_raw_codes, "end raw_codes")) + break; + rem->codes = std::move(raw_codes); + raw_codes.clear(); + mode = ID_remote; /* switch back */ + } + else if ("remote" == val) { + /* end remote mode */ + /* print_remote(rem); */ + if (!checkMode(mode, ID_remote, "end remote")) + break; + if (!sanityChecks(rem)) + return nullptr; + + /* not really necessary because we + clear the alloced memory */ + rem->next = nullptr; + rem->last_code = nullptr; + mode = ID_none; /* switch back */ + } + else if (mode == ID_codes) { + auto c = defineCode(key, val, &name_code); + if (!c) + return nullptr; + code = *c; + while (!val2.empty()) + { + if (val2[0] == '#') break; /* comment */ + auto node = defineNode(code, val2); + if (!node) + break; + val2 = strtok(buf, whitespace); + } + code->current = nullptr; + codes_list.push_back(std::move(*code)); + } + else { + return nullptr; + } + } + else { + switch (mode) { + case ID_remote: + defineRemote(key, val, val2, rem); + break; + case ID_codes: { + auto c = defineCode(key, val, &name_code); + if (!c) + return nullptr; + code = *c; + while (!val2.empty()) + { + if (val2[0] == '#') break; /* comment */ + auto node = defineNode(code, val2); + if (!node) + break; + val2 = strtok(buf, whitespace); + } + code->current = nullptr; + codes_list.push_back(std::move(*code)); + break; + } + case ID_raw_codes: + case ID_raw_name: + if ("name" == key) { + if (mode == ID_raw_name) + { + raw_code.signals = std::move(signals); + if (raw_code.length() % 2 == 0) + return nullptr; + raw_codes.push_back(std::move(raw_code)); + } + raw_code.name = std::string{ begin(val), end(val) }; + raw_code.code++; + signals.clear(); + signals.reserve(50); + mode = ID_raw_name; + } + else { + if (mode == ID_raw_codes) + { + return nullptr; + } + if (!addSignal(signals, key)) break; + if (!addSignal(signals, val)) break; + if (!val2.empty()) { + if (!addSignal(signals, val2)) { + break; + } + } + while (true) { + auto val = strtok(buf, whitespace); + if (val.empty() || !addSignal(signals, val)) break; + } + } + break; + } + } + } + else if (mode == ID_raw_name) { + if (!addSignal(signals, key)) { + break; + } + } + else { + return nullptr; + } + + } + if (mode != ID_none) + { + switch (mode) + { + case ID_raw_name: + if (raw_code.name != std::nullopt) + { + raw_code.name->clear(); + signals.clear(); + } + case ID_raw_codes: + rem->codes = std::move(raw_codes); + break; + case ID_codes: + rem->codes = std::move(codes_list); + break; + } + //if (!g_parse_error) + //{ + // g_parse_error = 1; + //} + } + + /* kick reverse flag */ + /* handle RC6 flag to be backwards compatible: previous RC-6 + config files did not set rc6_mask */ + rem = top_rem.get(); + while (rem != nullptr) + { + if ((!is_raw(rem)) && rem->flags & REVERSE) + { + if (has_pre(rem)) + { + rem->pre_data = reverse(rem->pre_data, + rem->pre_data_bits); + } + if (has_post(rem)) + { + rem->post_data = reverse(rem->post_data, + rem->post_data_bits); + } + for (auto& c : rem->codes) + { + c.code = reverse(c.code, rem->bits); + } + rem->flags = rem->flags & (~REVERSE); + rem->flags = rem->flags | COMPAT_REVERSE; + /* don't delete the flag because we still need + it to remain compatible with older versions + */ + } + if (rem->flags & RC6 && rem->rc6_mask == 0 && rem->toggle_bit > 0) + { + int all_bits = bit_count(rem); + + rem->rc6_mask = ((ir_code)1) << (all_bits - rem->toggle_bit); + } + if (rem->toggle_bit > 0) + { + int all_bits = bit_count(rem); + + if (!has_toggle_bit_mask(rem)) + { + rem->toggle_bit_mask = ((ir_code)1) << (all_bits - rem->toggle_bit); + } + rem->toggle_bit = 0; + } + if (has_toggle_bit_mask(rem)) + { + if (!is_raw(rem) && !rem->codes.empty()) + { + rem->toggle_bit_mask_state = (rem->codes[0].code & rem->toggle_bit_mask); + if (rem->toggle_bit_mask_state) + { + /* start with state set to 0 for backwards compatibility */ + rem->toggle_bit_mask_state ^= rem->toggle_bit_mask; + } + } + } + if (is_serial(rem)) + { + if (rem->baud > 0) + { + lirc_t base = 1000000 / rem->baud; + if (rem->pzero == 0 && rem->szero == 0) + { + rem->pzero = base; + } + if (rem->pone == 0 && rem->sone == 0) + { + rem->sone = base; + } + } + if (rem->bits_in_byte == 0) + { + rem->bits_in_byte = 8; + } + } + if (rem->min_code_repeat > 0) + { + if (!has_repeat(rem) || + rem->min_code_repeat > rem->min_repeat) + { + rem->min_code_repeat = 0; + } + } + rem = rem->next.get(); + } + + return sort_by_bit_count(std::move(top_rem)); } From 3d1ae08ffb9a54ac165446e9efcca41a7d14f5d6 Mon Sep 17 00:00:00 2001 From: Ahti Legonkov Date: Thu, 6 Jul 2023 15:12:19 +0300 Subject: [PATCH 3/4] Use operator&& instead of .and_then --- winlirc/config.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/winlirc/config.cpp b/winlirc/config.cpp index aeb1320..ae5285d 100644 --- a/winlirc/config.cpp +++ b/winlirc/config.cpp @@ -166,10 +166,16 @@ static std::expected parse_field( } template +requires (std::is_same_v && std::is_invocable_v || + !std::is_same_v && std::is_invocable_v) std::expected operator&&(std::expected&& lhs, Fun&& fun) { - if (lhs) - return fun(std::move(lhs)); + if (lhs) { + if constexpr (std::is_same_v) + return fun(); + else + return fun(std::move(*lhs)); + } return lhs; } @@ -291,39 +297,39 @@ static std::expected defineRemote( { if ("header" == key) { return parse_field(&ir_remote::phead, s_strtolirc_t(val), rem) - .and_then([&] { return parse_field(&ir_remote::shead, s_strtolirc_t(val2), rem); }); + && [&] { return parse_field(&ir_remote::shead, s_strtolirc_t(val2), rem); }; } else if ("three" == key) { return parse_field(&ir_remote::pthree, s_strtolirc_t(val), rem) - .and_then([&] { return parse_field(&ir_remote::sthree, s_strtolirc_t(val2), rem); }); + && [&] { return parse_field(&ir_remote::sthree, s_strtolirc_t(val2), rem); }; } else if ("two" == key) { return parse_field(&ir_remote::ptwo, s_strtolirc_t(val), rem) - .and_then([&] { return parse_field(&ir_remote::stwo, s_strtolirc_t(val2), rem); }); + && [&] { return parse_field(&ir_remote::stwo, s_strtolirc_t(val2), rem); }; } else if ("one" == key) { return parse_field(&ir_remote::pone, s_strtolirc_t(val), rem) - .and_then([&] { return parse_field(&ir_remote::sone, s_strtolirc_t(val2), rem); }); + && [&] { return parse_field(&ir_remote::sone, s_strtolirc_t(val2), rem); }; } else if ("zero" == key) { return parse_field(&ir_remote::pzero, s_strtolirc_t(val), rem) - .and_then([&] { return parse_field(&ir_remote::szero, s_strtolirc_t(val2), rem); }); + && [&] { return parse_field(&ir_remote::szero, s_strtolirc_t(val2), rem); }; } else if ("foot" == key) { return parse_field(&ir_remote::pfoot, s_strtolirc_t(val), rem) - .and_then([&] { return parse_field(&ir_remote::sfoot, s_strtolirc_t(val2), rem); }); + && [&] { return parse_field(&ir_remote::sfoot, s_strtolirc_t(val2), rem); }; } else if ("repeat" == key) { return parse_field(&ir_remote::prepeat, s_strtolirc_t(val), rem) - .and_then([&] { return parse_field(&ir_remote::srepeat, s_strtolirc_t(val2), rem); }); + && [&] { return parse_field(&ir_remote::srepeat, s_strtolirc_t(val2), rem); }; } else if ("pre" == key) { return parse_field(&ir_remote::pre_p, s_strtolirc_t(val), rem) - .and_then([&] { return parse_field(&ir_remote::pre_s, s_strtolirc_t(val2), rem); }); + && [&] { return parse_field(&ir_remote::pre_s, s_strtolirc_t(val2), rem); }; } else if ("post" == key) { return parse_field(&ir_remote::post_p, s_strtolirc_t(val), rem) - .and_then([&] { return parse_field(&ir_remote::post_s, s_strtolirc_t(val2), rem); }); + && [&] { return parse_field(&ir_remote::post_s, s_strtolirc_t(val2), rem); }; } } return std::unexpected{std::make_error_code(std::errc::invalid_argument)}; From bdc3ac7a309c13d9211137bea592d6eae929bcc2 Mon Sep 17 00:00:00 2001 From: Ahti Legonkov Date: Thu, 6 Jul 2023 15:55:41 +0300 Subject: [PATCH 4/4] Clean up a bit. Make g_line non-global --- winlirc/config.cpp | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/winlirc/config.cpp b/winlirc/config.cpp index ae5285d..2517512 100644 --- a/winlirc/config.cpp +++ b/winlirc/config.cpp @@ -24,8 +24,6 @@ enum directive { ID_none, ID_remote, ID_codes, ID_raw_codes, ID_raw_name }; static constexpr size_t LINE_LEN = 1024; static constexpr uint32_t MAX_INCLUDES = 10; static constexpr char whitespace[] = " \t"; -static int g_line; -//static int g_parse_error; static std::unique_ptr read_config_recursive(FILE* f, winlirc::istring_view name, int depth); @@ -179,7 +177,7 @@ std::expected operator&&(std::expected&& lhs, Fun&& fun) return lhs; } -static std::expected defineRemote( +static std::expected parse_field( winlirc::istring_view key, winlirc::istring_view val, winlirc::istring_view val2, @@ -430,7 +428,7 @@ static std::unique_ptr read_config_recursive(FILE* f, winlirc::istrin ir_ncode* code; int mode = ID_none; - g_line = 0; + int g_line = 0; while (fgets(bufx, LINE_LEN, f) != nullptr) { @@ -475,8 +473,6 @@ static std::unique_ptr read_config_recursive(FILE* f, winlirc::istrin auto const openResult = fopen_s(&childFile, fullPath.c_str(), "r"); if (childFile != nullptr) { - int save_line = g_line; - if (!top_rem) { /* create first remote */ top_rem = read_config_recursive(childFile, fullPath, depth + 1); @@ -489,7 +485,6 @@ static std::unique_ptr read_config_recursive(FILE* f, winlirc::istrin rem = rem->next.get(); } fclose(childFile); - g_line = save_line; } } else if ("begin" == key) { @@ -624,7 +619,7 @@ static std::unique_ptr read_config_recursive(FILE* f, winlirc::istrin else { switch (mode) { case ID_remote: - defineRemote(key, val, val2, rem); + parse_field(key, val, val2, rem); break; case ID_codes: { auto c = defineCode(key, val, &name_code); @@ -707,10 +702,6 @@ static std::unique_ptr read_config_recursive(FILE* f, winlirc::istrin rem->codes = std::move(codes_list); break; } - //if (!g_parse_error) - //{ - // g_parse_error = 1; - //} } /* kick reverse flag */