/* * This function checks to see if the current YAML::Node contains only keys * that we care about. Unknown keys should cause PLFS to spit out an error * rather than being silently ignored. * This is a bit nasty as it drills through the entire tree recursively * but it will catch any unknowns in one pass * * Returns true if all keys are valid * * Returns false if unknown keys are found and sets bad_key to an error * message that points out what key is invalid */ bool is_valid_node(const YAML::Node node, string** bad_key) { set<string> key_list(Valid_Keys, Valid_Keys + (sizeof(Valid_Keys) / sizeof(Valid_Keys[0])) ); string key; string err = "\nBad key or value in plfsrc: "; if(node.IsMap()) { for(YAML::const_iterator it=node.begin();it!=node.end();it++) { if(!it->first.IsNull()) { key = it->first.as<string>(); if(!is_valid_node(node[key],bad_key)) // recurse return false; if(key_list.find(key) == key_list.end()) { err.append(key); *bad_key = new string (err); return false; // this is an unknown key } } } } else if (node.IsSequence()) { for(unsigned int i = 0; i < node.size(); i++) if(!is_valid_node(node[i],bad_key)) // recurse return false; } else if (node.IsScalar() && node.as<string>().find(" ") != string::npos) { err.append(node.as<string>()); *bad_key = new string (err); return false; // no spaces in values allowed } return true; // all keys are valid }
inline std::string from_yaml(type_t<std::string>, const YAML::Node& value) { if (!value.IsScalar()) throw deserialize_error{"type must be a scalar but is " + yaml_type_name(value)}; return value.Scalar(); }
// Incrementally load YAML static NEVER_INLINE void operator +=(YAML::Node& left, const YAML::Node& node) { if (node && !node.IsNull()) { if (node.IsMap()) { for (const auto& pair : node) { if (pair.first.IsScalar()) { auto&& lhs = left[pair.first.Scalar()]; lhs += pair.second; } else { // Exotic case (TODO: probably doesn't work) auto&& lhs = left[YAML::Clone(pair.first)]; lhs += pair.second; } } } else if (node.IsScalar() || node.IsSequence()) { // Scalars and sequences are replaced completely, but this may change in future. // This logic may be overwritten by custom demands of every specific cfg:: node. left = node; } } }
Enum enum_from_yaml(const YAML::Node& value, std::true_type /*is_enum_reflectable*/) { if (!value.IsScalar()) throw deserialize_error{"type must be a scalar but is " + yaml_type_name(value)}; if (auto enum_value = kl::from_string<Enum>(value.Scalar())) return enum_value.get(); throw deserialize_error{"invalid enum value: " + value.Scalar()}; }
void Config::parseCommand(const YAML::Node& node, iCommandConfig& config) { //std::cerr << "Under active development!" << '\n'; //return; if(node.size() >= 1 && node.IsMap()) for (YAML::const_iterator iter=node.begin();iter!=node.end();++iter) { std::string key = iter->first.as<std::string>(); YAML::Node value = iter->second; Util::lowercase(key); //std::cout << key << std::endl; if(key == "command") { if(value.IsScalar()) { LOG(logger, DEBUG, "Proc: %s", value.as<std::string>().c_str()); config.command = Util::parseCommand(value.as<std::string>()); #if 0 // TODO: We need to take quotes from the user and send them all as // a single argument instead of multiple arguments. std::string cnfval = value.as<std::string>(); char* cmd = new char[cnfval.size() + 1]; cmd[cnfval.size()] = 0; memcpy(cmd, cnfval.c_str(), cnfval.size()); size_t size = 1; for(size_t i=0; i<cnfval.size(); i++) if(cmd[i] == ' ') size++; config.command = new char*[size+1]; config.command[size] = 0; config.command[0] = cmd; size_t csize = 0; for(size_t i=0; i<cnfval.size(); i++) { if(cmd[i] == ' ') { cmd[i] = 0; if(csize < size && (i + 1) < cnfval.size()) { config.command[++csize] = cmd+(unsigned int)i+1; } } } #endif } } else if( key == "enabled" ) { config.enabled = value.as<bool>(); } } //for(size_t i=0;config.command[i]; i++) //{ // std::cout << "==" << config.command[i] << '\n'; //} }
void CopyYaml( const YAML::Node& src, YAML::Node& dst ) { if( src.IsNull() ) { return; } if( src.IsScalar() ) { dst = src; return; }; YAML::Node::const_iterator iter; for( iter = src.begin(); iter != src.end(); iter++ ) { dst[ iter->first.as<std::string>() ] = iter->second; } }
T from_scalar_yaml(const YAML::Node& value) { if (!value.IsScalar()) throw deserialize_error{"type must be a scalar but is " + yaml_type_name(value)}; try { return value.as<T>(); } catch (const YAML::BadConversion& ex) { throw deserialize_error{ex.what()}; } }
void Server::tick() { YAML::Node tr = _tune.table[_block]; for (int i = 0; i < int(_channels.size()); i++) { if (_tick == 0 && i < int(tr.size()) && !tr[i].IsNull()) { string pat = tr[i].as<string>(); if (!_tune.patterns[pat]) throw logic_error("undefined pattern: " + pat); YAML::Node row = _tune.patterns[pat][_row]; if (row.IsScalar()) { auto cmds = get_multi_commands(row.as<string>()); int l = min(cmds.size(), _channels.size() - i + cmds.size()); for (int j = 0; j < l; j++) _channels[i + j].set_row_commands(cmds[j]); } } // midi if (_midi && i == _tune.midi_channel_nr) { struct { unsigned char type, val, x, y; } event; for (;;) { int l = Pm_Read(_midi, (PmEvent*) &event, 1); if (!l) break; static int last_note = 0; string row; if (event.type == 128 && event.val == last_note) row = "---"; else if (event.type == 144) { int i = event.val; row = string(1, "ccddeffggaab"[i%12]) + string(1, "-#-#--#-#-#-"[i%12]) + string(1, '0' + i/12); last_note = event.val; } if (!row.empty()) _channels[i].set_row_commands({ { "note", row } }); } } _channels[i].tick(_tune.instruments); } }
XmlRpc::XmlRpcValue YamlToXml( const YAML::Node& node ) { XmlRpc::XmlRpcValue xml; if( node.IsNull() ) { return xml; } else if( node.IsSequence() ) { std::vector< std::string > contents = node.as< std::vector< std::string > >(); xml.setSize( contents.size() ); for( unsigned int i = 0; i < contents.size(); i++ ) { xml[i] = contents[i]; } } else if( node.IsScalar() ) { xml = node.as< std::string >(); } else if( node.IsMap() ) { YAML::Node::const_iterator iter; for( iter = node.begin(); iter != node.end(); iter++ ) { std::string name = iter->first.as<std::string>(); xml[ name ] = YamlToXml( iter->second ); } } else { std::cerr << "Invalid YAML node type." << std::endl; } return xml; }
void cfg::decode(const YAML::Node& data, cfg::_base& rhs) { switch (rhs.get_type()) { case type::node: { if (data.IsScalar() || data.IsSequence()) { return; // ??? } for (const auto& pair : data) { if (!pair.first.IsScalar()) continue; // Find the key among existing nodes for (const auto& _pair : static_cast<node&>(rhs).get_nodes()) { if (_pair.first == pair.first.Scalar()) { decode(pair.second, *_pair.second); } } } break; } case type::set: { std::vector<std::string> values; if (YAML::convert<decltype(values)>::decode(data, values)) { rhs.from_list(std::move(values)); } break; } case type::log: { if (data.IsScalar() || data.IsSequence()) { return; // ??? } std::map<std::string, logs::level> values; for (const auto& pair : data) { if (!pair.first.IsScalar() || !pair.second.IsScalar()) continue; u64 value; if (cfg::try_to_enum_value(&value, &fmt_class_string<logs::level>::format, pair.second.Scalar())) { values.emplace(pair.first.Scalar(), static_cast<logs::level>(static_cast<int>(value))); } } static_cast<log_entry&>(rhs).set_map(std::move(values)); break; } default: { std::string value; if (YAML::convert<std::string>::decode(data, value)) { rhs.from_string(value); } break; // ??? } } }
void Config::parseWatcher(const YAML::Node& node) { size_t asterisk_count; if(node.size() >= 1 && node.IsMap()) for (YAML::const_iterator iter=node.begin();iter!=node.end();++iter) { std::string key = iter->first.as<std::string>(); YAML::Node value = iter->second; Util::lowercase(key); if(key == "filter") { if(!value.IsSequence()) std::cerr << "ERROR!\n"; for(YAML::const_iterator filter_iter=value.begin(); filter_iter!=value.end(); ++filter_iter) { asterisk_count = 0; std::string val = filter_iter->as<std::string>(); for(size_t i = 0; i < val.length(); i++) if(val[i] == '*') asterisk_count++; LOG(logger, DEBUG, "Filter: %s", val.c_str()); if(asterisk_count > 1) throw std::runtime_error("Could not open file"); mWatch.filters.push_back(val); } } else if(key == "include") { if(!value.IsSequence() && !value.IsScalar()) std::cerr << "ERROR!\n"; if(value.IsSequence()) { for(YAML::const_iterator filter_iter=value.begin(); filter_iter!=value.end(); ++filter_iter) { LOG(logger, DEBUG, "Include: %s", filter_iter->as<std::string>().c_str()); mWatch.include.push_back(filter_iter->as<std::string>()); } } else if(value.IsScalar()) { LOG(logger, DEBUG, "Include: %s", value.as<std::string>().c_str()); mWatch.include.push_back(value.as<std::string>()); } } else if(key == "exclude") { if(!value.IsSequence() && !value.IsScalar()) std::cerr << "ERROR!\n"; if(value.IsSequence()) { for(YAML::const_iterator filter_iter=value.begin(); filter_iter!=value.end(); ++filter_iter) { LOG(logger, DEBUG, "Exclude: %s", filter_iter->as<std::string>().c_str()); mWatch.exclude.push_back(filter_iter->as<std::string>()); } } else if(value.IsScalar()) { LOG(logger, DEBUG, "Exclude: %s", value.as<std::string>().c_str()); mWatch.exclude.push_back(value.as<std::string>()); } } else LOG(logger, DEBUG, "Value: %s\n", value.as<std::string>().c_str()); } }