bool ConfigParser::parse(const std::string& file, ConfigNode* ptr) { ConfigScanner scanner; ConfigLexer lexer; ConfigNode* root = ptr; if (!scanner.read(file)) { std::cerr << "Couldn't find config file: " << file << "\n"; return false; } lexer.setScanner(&scanner); int token_type; std::string token_data; std::string token_label; std::deque<ConfigNode*> nodeStack; ConfigNode* currentNode = root; nodeStack.push_back(currentNode); while (lexer.get_token(&token_type, &token_data)) { if (!token_type) { std::cerr << "Unrecognised data!\n"; return false; } // Include other files only if we're in the root node if ((token_type == CONFIG_TOKEN_ENTITY) && (token_data == "include") && (currentNode == root)) { int tmp_type; std::string tmp_data; lexer.get_token(&tmp_type, &tmp_data); if (tmp_type == CONFIG_TOKEN_STRING) { if (tmp_data == file) { std::cerr << "Warning: recursion detected! Not including `" << tmp_data << "`.\n"; continue; } if (!parse(tmp_data, root)) { return false; } continue; } else { lexer.put_token(tmp_type, tmp_data); } } if ((token_type == CONFIG_TOKEN_ENTITY) || (token_type == CONFIG_TOKEN_LABEL)) { token_label.assign(token_data); } if (token_type == CONFIG_TOKEN_OPERATOR_ASSIGN) { if (currentNode != root) { currentNode->clear(); } } if (token_type == CONFIG_TOKEN_BOOLEAN) { ConfigNode* newNode = (token_label.size() && currentNode->has(token_label)) ? currentNode->get(token_label) : new ConfigNode; newNode->setData(token_data == "true"); if (token_label.size()) { currentNode->set(token_label, newNode, true); token_label.clear(); } else { currentNode->add(newNode); } } if (token_type == CONFIG_TOKEN_STRING) { ConfigNode* newNode = (token_label.size() && currentNode->has(token_label)) ? currentNode->get(token_label) : new ConfigNode; newNode->setData(token_data); if (token_label.size()) { currentNode->set(token_label, newNode, true); token_label.clear(); } else { currentNode->add(newNode); } } if (token_type == CONFIG_TOKEN_NUMBER) { ConfigNode* newNode = (token_label.size() && currentNode->has(token_label)) ? currentNode->get(token_label) : new ConfigNode; newNode->setData((double)::atof(token_data.c_str())); if (token_label.size()) { currentNode->set(token_label, newNode, true); token_label.clear(); } else { currentNode->add(newNode); } } if (token_type == CONFIG_TOKEN_LIST_OPEN) { ConfigNode* newNode = (token_label.size() && currentNode->has(token_label)) ? currentNode->get(token_label) : new ConfigNode; newNode->setType(CONFIG_NODE_LIST); if (token_label.size()) { currentNode->set(token_label, newNode, true); newNode = currentNode->get(token_label, true); token_label.clear(); } else { currentNode->add(newNode); } nodeStack.push_back(currentNode); currentNode = newNode; } if (token_type == CONFIG_TOKEN_LIST_CLOSE) { currentNode = nodeStack.back(); nodeStack.pop_back(); } } return true; }
bool ConfigParser::parse(std::istream& data, ConfigNode::Ptr ptr) { ConfigScanner scanner; ConfigLexer lexer(scanner); ConfigNode::Ptr root = ptr; data.seekg(0, std::ios::end); const size_t data_size = size_t(data.tellg()); data.seekg(0, std::ios::beg); char* buf = new char[data_size]; data.read(buf, data_size); std::string data_str(buf, data_size); delete[] buf; if (!scanner.read(data_str)) { std::cerr << "Couldn't read data!\n"; return false; } int token_type; std::string token_data; std::string token_label; std::stack<ConfigNode::Ptr> nodeStack; ConfigNode::Ptr currentNode = root; nodeStack.push(currentNode); while (lexer.get_token(token_type, token_data)) { if (!token_type) { std::cerr << "Unrecognised data!\n"; return false; } // Include other files only if we're in the root node if (token_type == CONFIG_TOKEN_ENTITY && token_data == "include" && currentNode == root) { int tmp_type; std::string tmp_data; lexer.get_token(tmp_type, tmp_data); if (tmp_type == CONFIG_TOKEN_STRING) { if (m_includes >= MAX_INCLUDES) { std::cerr << "reached maximum number of include directives: " << m_includes << "\n"; return false; } // allow only filename without path if ((tmp_data.find('/') != std::string::npos) || (tmp_data.find('\\') != std::string::npos)) { std::cerr << "include directive accepts only filename: " << tmp_data << "\n"; return false; } // prepend home path const std::string var = "system.path.home"; const ConfigNode::Ptr node = root->get(var, false); std::string home; if (!node || (home = node->sData()).empty()) { std::cerr << "include directive is not allowed before: " << var << "\n"; return false; } tmp_data = relativeToAbsolute(home) + PATH_SEPARATOR + tmp_data; if (!parse(tmp_data, root)) { return false; } m_includes++; continue; } else { lexer.put_token(tmp_type, tmp_data); } } if (token_type == CONFIG_TOKEN_ENTITY || token_type == CONFIG_TOKEN_LABEL) { token_label = token_data; } else if (token_type == CONFIG_TOKEN_OPERATOR_ASSIGN) { if (currentNode != root) { currentNode->clear(); } } else if (token_type == CONFIG_TOKEN_BOOLEAN) { ConfigNode::Ptr newNode(!token_label.empty() && currentNode->has(token_label) ? currentNode->get(token_label) : ConfigNode::Ptr(new ConfigNode)); newNode->setData(token_data == "true"); if (!token_label.empty()) { currentNode->set(token_label, newNode, true); token_label.clear(); } else { currentNode->add(newNode); } } else if (token_type == CONFIG_TOKEN_STRING) { ConfigNode::Ptr newNode(!token_label.empty() && currentNode->has(token_label) ? currentNode->get(token_label) : ConfigNode::Ptr(new ConfigNode)); newNode->setData(token_data); if (!token_label.empty()) { currentNode->set(token_label, newNode, true); token_label.clear(); } else { currentNode->add(newNode); } } else if (token_type == CONFIG_TOKEN_NUMBER) { ConfigNode::Ptr newNode(token_label.size() && currentNode->has(token_label) ? currentNode->get(token_label) : ConfigNode::Ptr(new ConfigNode)); newNode->setData((double)::atof(token_data.c_str())); if (!token_label.empty()) { currentNode->set(token_label, newNode, true); token_label.clear(); } else { currentNode->add(newNode); } } else if (token_type == CONFIG_TOKEN_LIST_OPEN) { ConfigNode::Ptr newNode(token_label.size() && currentNode->has(token_label) ? currentNode->get(token_label) : ConfigNode::Ptr(new ConfigNode)); newNode->setType(CONFIG_NODE_LIST); if (!token_label.empty()) { currentNode->set(token_label, newNode, true); newNode = currentNode->get(token_label, true); token_label.clear(); } else { currentNode->add(newNode); } nodeStack.push(currentNode); currentNode = newNode; } else if (token_type == CONFIG_TOKEN_LIST_CLOSE) { currentNode = nodeStack.top(); nodeStack.pop(); } } return true; }