遍历 boost 属性 树时变量变空
variables go empty while traversing boost property tree
我知道我似乎有自己回答问题的习惯,但到目前为止我一直停留在这个问题上,需要一些帮助。
我编写了一些代码来将 json 格式的文件加载到 class 系统中。我把所有的代码放在这里:
https://github.com/tomzooi/readreq
简而言之,我想做的是:
首先,我创建了一些代码,可以读取 "requirements" 文件并使用 class.h 中的要求 class 存储它
同样,我可以以人类可读的格式输出以进行筛选或将其存储在 json 文件中。这有效。
然后我希望能够读取 JSON 文件并再次使用相同的 Requirement 对象将其存储在内存中,但是这并不是很好(到目前为止)。
现在的主要问题是我遍历属性树的部分,这主要是在这个递归函数中完成的:
void display(const int depth, const boost::property_tree::ptree& tree, Requirement * cur_requirement, std::vector<Requirement> &requirements) {
unsigned int count;
std::string label,level,description;
boost::property_tree::ptree kids = tree.get_child("");
bool godown = false;
for (const auto& v : kids) { // v is of type ptree::value_type
std::cout << std::string("").assign(depth+1,'#') << " ";
std::string nodestr = tree.get<std::string>(v.first);
//std::cout << v.first << " = " << nodestr << std::endl;
if (v.first == "label") {
label = nodestr;
std::cout << "lbl: " << label << std::endl;
}
else if(v.first == "level") {
//std::cout << "LABEL!";
level = nodestr;
std::cout << "lvl: " << level << std::endl;
}
else if(v.first == "description") {
description = nodestr;
std::cout << "dsc: " << description << std::endl;
}
else if(v.first == "children") { //going down, store stuff first
if(depth == 0) { //zero depth
std::cout << "zero depth...";
requirements.emplace_back(level, description, label,cur_requirement);
cur_requirement = &requirements.back();
}
else { //one or higher depth
std::cout << "at depth " << depth << "..." << std::flush;
cur_requirement->children.emplace_back(level,description,label,cur_requirement->parent);
cur_requirement = &cur_requirement->children.back();
}
std::cout << "going down" << std::endl;
//cur_requirement = &cur_requirement->children.back();
display(depth+1, v.second, cur_requirement,requirements);
}
else if(v.first == "") {
std::cout << "empty v.first ... level: " << level << std::endl;
if(depth == 0) { //zero depth
std::cout << "store at zero depth...";
requirements.emplace_back(level, description, label,cur_requirement);
cur_requirement = &requirements.back();
}
else { //one or higher depth
std::cout << "store at depth " << depth << " : " << level << "--" << description << std::flush;
cur_requirement->children.emplace_back(level,description,label,cur_requirement->parent);
//cur_requirement = &cur_requirement->children.back();
}
std:: cout << " going to next " << std::endl;
//cur_requirement = &cur_requirement->children.back();
display(depth, v.second, cur_requirement,requirements);
}
else {
std:: cout << "what else..." << std::endl;
}
// v.first is the name of the child
// v.second is the child tree
}
};
我目前得到的输出是这样的:
[tom@tomtop dev]$ ./readreq The_system.F.req.json
name: The system prefix: F
# lvl: should
# dsc: very well performance wise
# lbl: goperf
# zero depth...going down
## empty v.first ... level:
store at depth 1 : -- going to next
## lvl: should
## dsc: be listening to spaces as well
## lbl: lisspace
## empty v.first ... level:
store at depth 1 : -- going to next
## lvl: will
## dsc: a lot of levels back down again
## at depth 1...going down
### empty v.first ... level:
store at depth 2 : -- going to next
### lvl: empty
### dsc: empty
### lbl: empty
### at depth 2...going down
#### empty v.first ... level:
store at depth 3 : -- going to next
#### lvl: can
#### dsc: skip all the way back here
#### lbl: skiphere
#### empty v.first ... level:
store at depth 3 : -- going to next
#### lvl: can
#### dsc: take three linestr
#### lbl: threelines
level: should description:very well performance wise label: goperf
level: description: label:
level: description: label:
level: will description:a lot of levels back down again label:
level: description: label:
level: empty description:empty label: empty
level: description: label:
level: description: label:
其中大部分都说得通,而且大部分似乎都行得通,但有一件事让我不解。 属性 树的组织方式是在每个 "child" 之前以及数组元素之间都有一个 "empty" 节点。 (如果我错了,请纠正我,我对 属性 树不太熟悉)。
所以在我遇到 "children" 或 ""(空)元素后,我想存储我之前收集的数据,存储在变量级别、描述和标签中。
有趣的是,当元素为 "children" 时,这就像一个魅力,但是,当元素为 "" 时,变量突然为空,即使变量没有重新初始化,我也没有深入 属性 树,我只在 for 循环中迭代到下一个 "kid"。
所以我希望输出是这样的:
## lvl: should
## dsc: be listening to spaces as well
## lbl: lisspace
## empty v.first ... level: should
store at depth 1 : should -- be listening to spaces as well going to next
最后一行(由
生成
std::cout << "empty v.first ... level: " << level << std::endl;
std::cout << "store at depth " << depth << " : " << level << "--" << description << std::flush;
) 显示:
store at depth 1 : -- going to next
给人的印象是标签、描述和级别不知何故是空的,而且没有任何地方可以让它们空着。
因此,如果有人能向我解释这种神秘行为,我将非常高兴。
我试了15分钟。我无法理解您要实现的目标。
请参见更新
注释
cur_requirement
应该被初始化。
您在这里调用 UB:
requirements.emplace_back(level, description, label, cur_requirement);
cur_requirement = &requirements.back();
您正在将指针存储到已放置要求中的向量元素。但是,放置可能会重新分配,使所有指针和迭代器无效。
Rethink your data model (prefer value-semantics? use containers with stable iterators? reserve up-front?)
- See: Iterator invalidation rules
更新
所以,这是我清理 display
函数(我将其重命名为 parse_json
因为它就是这样做的):
void parse_json(int depth, boost::property_tree::ptree const& tree, Requirement& cur)
{
cur.label = tree.get("label", "");
cur.level = tree.get("level", "");
cur.description = tree.get("description", "");
if (auto kids = tree.get_child_optional("children")) {
for (auto& kid : *kids) {
std::cout << "at depth " << depth << "... " << std::flush;
cur.children.emplace_back(&cur);
std::cout << "going down" << std::endl;
parse_json(depth + 1, kid.second, cur.children.back());
}
}
}
完整演示
看到整个程序都清理干净了。请注意,我已将 vector
替换为 list
以避免在读取更多子节点时使父指针无效
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <exception>
#include <fstream>
#include <iostream>
#include <string>
#include <list>
class Requirement {
public:
bool empty;
std::string level;
std::string description;
std::string label;
Requirement const* parent;
std::list <Requirement> children;
Requirement(Requirement const* p);
Requirement(std::string l, std::string d, std::string la, Requirement const* p); // unused
void print(std::string indent = "");
void print_json(std::ostream &os, std::string indent = "");
};
Requirement::Requirement(Requirement const* p)
: empty(false), parent(p)
{
}
Requirement::Requirement(std::string l, std::string d, std::string la,Requirement const* p) // unused
: empty(false),
level(std::move(l)), description(std::move(d)), label(std::move(la)), parent(p)
{
}
void Requirement::print_json(std::ostream &os, std::string indent) {
os << "{";
indent += '\t';
os
<< "\n" << indent << "\"level\":\"" << level << "\", "
<< "\n" << indent << "\"description\":\"" << description << "\"";
if(label.length() > 1) {
os << ",\n" << indent << "\"label\":\"" << label <<"\"";
}
if (!children.empty()) {
os << ", \"children\":[\n";
bool first = true;
for(auto& child : children) {
if (!first)
os << ',';
first=false;
os << "\n" << indent;
child.print_json(os, indent);
}
os << "]";
}
indent.resize(indent.size() - 1);
os << "\n" << indent << "}";
}
void Requirement::print(std::string indent) {
std::cout << indent << "level: " << level << " description:" << description << " label: " << label << std::endl;
for (Requirement kid : children)
kid.print(indent + '\t');
}
void parse_json(int depth, boost::property_tree::ptree const& tree, Requirement& cur)
{
cur.label = tree.get("label", "");
cur.level = tree.get("level", "");
cur.description = tree.get("description", "");
if (auto kids = tree.get_child_optional("children")) {
for (auto& kid : *kids) {
std::cout << "at depth " << depth << "... " << std::flush;
cur.children.emplace_back(&cur);
std::cout << "going down" << std::endl;
parse_json(depth + 1, kid.second, cur.children.back());
}
}
}
int main(int argc, char* argv[])
{
if (argc>1) try {
std::ifstream ss(argv[1]);
boost::property_tree::ptree pt;
boost::property_tree::read_json(ss, pt);
Requirement root(nullptr);
parse_json(0, pt, root);
std::cout << std::endl << std::endl;
root.print("; debug: ");
root.print_json(std::cout);
}
catch (std::exception const& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
}
输出为:
at depth 0... going down
at depth 0... going down
at depth 1... going down
at depth 2... going down
at depth 2... going down
; debug: level: should description:very well performance wise label: goperf
; debug: level: should description:be listening to spaces as well label: lisspace
; debug: level: will description:a lot of levels back down again label:
; debug: level: empty description:empty label: empty
; debug: level: can description:skip all the way back here label: skiphere
; debug: level: can description:take three linestr label: threelines
{
"level":"should",
"description":"very well performance wise",
"label":"goperf", "children":[
{
"level":"should",
"description":"be listening to spaces as well",
"label":"lisspace"
},
{
"level":"will",
"description":"a lot of levels back down again", "children":[
{
"level":"empty",
"description":"empty",
"label":"empty", "children":[
{
"level":"can",
"description":"skip all the way back here",
"label":"skiphere"
},
{
"level":"can",
"description":"take three linestr",
"label":"threelines"
}]
}]
}]
}
请注意,代码大约只有一半大小:)
我最终也链接了 main.cpp(现在称为 readreq.cpp),虽然我没能很好地递归,但它确实成功了。还必须更改其他一些内容,以便能够拥有需求列表的基础(不仅仅是一个根),代码也在 github 上
https://github.com/tomzooi/readreq
基本变化:
#include <fstream>
#include <iostream>
#include "class.h"
#include <vector>
#include <string>
//#include <regex>
#include <boost/regex.hpp>
#include <iterator>
#include <algorithm>
#include <math.h>
//how many spaces are interpreted as one tab or level
#define SPACES 8
#define LINEBUFSIZE 500
void parse_req(unsigned int cur_depth, std::ifstream &f, std::list<Requirement> &reqlist,unsigned int linenr=0) {
std::string line;
unsigned int count = 0;
unsigned int depth = 0;
Requirement * cur(nullptr);
boost::regex re("\t+|\s{2,}"); //regex split parameter (one or more tabs or 2 or more spaces)
std::list<Requirement>* lptr(&reqlist);
while (std::getline(f, line)) {
linenr++;
// std::cout << "(" << linenr << "): " << line;
depth = line.find_first_not_of(" "); //find first none space or tab character
boost::sregex_token_iterator i(line.begin()+depth, line.end(), re, -1); //split line by tabs and spaces
boost::sregex_token_iterator j;
count = 0; //reset count
if (depth == cur_depth) {
lptr->emplace_back(lptr->back().parent);
cur = &lptr->back();
}
else if (depth > cur_depth) { //go deeper
cur_depth = depth;
lptr = &lptr->back().children;
lptr->emplace_back(cur);
cur = &lptr->back();
}
else if (depth < cur_depth) { //go down
//lptr = cur->parent;
while (cur_depth > depth) {
cur_depth--;
std::cout << "deeper : " << cur_depth << std::endl << std::flush;
lptr = &(lptr->back().parent->parent->children);
}
if(cur_depth != 0) {
lptr->emplace_back(lptr->back().parent);
cur = &lptr->back();
}
else {
reqlist.emplace_back(nullptr);
cur = &reqlist.back();
}
}
while(i != j) { //for all splitted parts
switch(count) {
case 0:
cur->level =*i++;
//std::cout << "lvl: " << cur->level << " ";
break;
case 1:
cur->description = *i++;
//std::cout << "dsc: " << cur.description << std::endl;
break;
case 2:
cur->label = *i++;
break;
default:
*i++;
break;
}
count++;
}
if (count < 2) { //too less arguments
std::cout << "ERROR(" << linenr << "): nead at least two parts for an requirement (level and description), less than two found, halting." << std::endl;
break;
}
if (count > 3) { //too much arguments
std::cout << "WARNING(" << linenr << "): More then three arguments found, ignoring fourth or more argument" << std::endl;
}
}
}
int main(int argc, char *argv[]) {
// class Requirement req("will", "do good work", "good");
if ( argc != 3 ) // argc should be 2 for correct execution
// We print argv[0] assuming it is the program name
std::cout<<"usage: "<< argv[0] <<" <filename input> <filename output>\n";
else {
std::ifstream file(argv[1]); //try to open file
if(!file.is_open()) { //if we can't
std::cout << "Could not open file" ;
}
else { //sucesfully opened file
std::list<Requirement> requirements;
parse_req(0,file,requirements);
std::ofstream outfile(argv[2]); //try to open file
outfile << "{ \"requirements\":[";
for (Requirement req : requirements) {
req.print();
req.print_json(outfile);
if (requirements.back().description != req.description) {
outfile << ",";
}
}
outfile << "]}";
std::cout << "success!" << std::endl;
}
}
return 0;
}
我知道我似乎有自己回答问题的习惯,但到目前为止我一直停留在这个问题上,需要一些帮助。
我编写了一些代码来将 json 格式的文件加载到 class 系统中。我把所有的代码放在这里: https://github.com/tomzooi/readreq
简而言之,我想做的是: 首先,我创建了一些代码,可以读取 "requirements" 文件并使用 class.h 中的要求 class 存储它 同样,我可以以人类可读的格式输出以进行筛选或将其存储在 json 文件中。这有效。
然后我希望能够读取 JSON 文件并再次使用相同的 Requirement 对象将其存储在内存中,但是这并不是很好(到目前为止)。
现在的主要问题是我遍历属性树的部分,这主要是在这个递归函数中完成的:
void display(const int depth, const boost::property_tree::ptree& tree, Requirement * cur_requirement, std::vector<Requirement> &requirements) {
unsigned int count;
std::string label,level,description;
boost::property_tree::ptree kids = tree.get_child("");
bool godown = false;
for (const auto& v : kids) { // v is of type ptree::value_type
std::cout << std::string("").assign(depth+1,'#') << " ";
std::string nodestr = tree.get<std::string>(v.first);
//std::cout << v.first << " = " << nodestr << std::endl;
if (v.first == "label") {
label = nodestr;
std::cout << "lbl: " << label << std::endl;
}
else if(v.first == "level") {
//std::cout << "LABEL!";
level = nodestr;
std::cout << "lvl: " << level << std::endl;
}
else if(v.first == "description") {
description = nodestr;
std::cout << "dsc: " << description << std::endl;
}
else if(v.first == "children") { //going down, store stuff first
if(depth == 0) { //zero depth
std::cout << "zero depth...";
requirements.emplace_back(level, description, label,cur_requirement);
cur_requirement = &requirements.back();
}
else { //one or higher depth
std::cout << "at depth " << depth << "..." << std::flush;
cur_requirement->children.emplace_back(level,description,label,cur_requirement->parent);
cur_requirement = &cur_requirement->children.back();
}
std::cout << "going down" << std::endl;
//cur_requirement = &cur_requirement->children.back();
display(depth+1, v.second, cur_requirement,requirements);
}
else if(v.first == "") {
std::cout << "empty v.first ... level: " << level << std::endl;
if(depth == 0) { //zero depth
std::cout << "store at zero depth...";
requirements.emplace_back(level, description, label,cur_requirement);
cur_requirement = &requirements.back();
}
else { //one or higher depth
std::cout << "store at depth " << depth << " : " << level << "--" << description << std::flush;
cur_requirement->children.emplace_back(level,description,label,cur_requirement->parent);
//cur_requirement = &cur_requirement->children.back();
}
std:: cout << " going to next " << std::endl;
//cur_requirement = &cur_requirement->children.back();
display(depth, v.second, cur_requirement,requirements);
}
else {
std:: cout << "what else..." << std::endl;
}
// v.first is the name of the child
// v.second is the child tree
}
};
我目前得到的输出是这样的:
[tom@tomtop dev]$ ./readreq The_system.F.req.json
name: The system prefix: F
# lvl: should
# dsc: very well performance wise
# lbl: goperf
# zero depth...going down
## empty v.first ... level:
store at depth 1 : -- going to next
## lvl: should
## dsc: be listening to spaces as well
## lbl: lisspace
## empty v.first ... level:
store at depth 1 : -- going to next
## lvl: will
## dsc: a lot of levels back down again
## at depth 1...going down
### empty v.first ... level:
store at depth 2 : -- going to next
### lvl: empty
### dsc: empty
### lbl: empty
### at depth 2...going down
#### empty v.first ... level:
store at depth 3 : -- going to next
#### lvl: can
#### dsc: skip all the way back here
#### lbl: skiphere
#### empty v.first ... level:
store at depth 3 : -- going to next
#### lvl: can
#### dsc: take three linestr
#### lbl: threelines
level: should description:very well performance wise label: goperf
level: description: label:
level: description: label:
level: will description:a lot of levels back down again label:
level: description: label:
level: empty description:empty label: empty
level: description: label:
level: description: label:
其中大部分都说得通,而且大部分似乎都行得通,但有一件事让我不解。 属性 树的组织方式是在每个 "child" 之前以及数组元素之间都有一个 "empty" 节点。 (如果我错了,请纠正我,我对 属性 树不太熟悉)。
所以在我遇到 "children" 或 ""(空)元素后,我想存储我之前收集的数据,存储在变量级别、描述和标签中。
有趣的是,当元素为 "children" 时,这就像一个魅力,但是,当元素为 "" 时,变量突然为空,即使变量没有重新初始化,我也没有深入 属性 树,我只在 for 循环中迭代到下一个 "kid"。
所以我希望输出是这样的:
## lvl: should
## dsc: be listening to spaces as well
## lbl: lisspace
## empty v.first ... level: should
store at depth 1 : should -- be listening to spaces as well going to next
最后一行(由
生成std::cout << "empty v.first ... level: " << level << std::endl; std::cout << "store at depth " << depth << " : " << level << "--" << description << std::flush;
) 显示:
store at depth 1 : -- going to next
给人的印象是标签、描述和级别不知何故是空的,而且没有任何地方可以让它们空着。
因此,如果有人能向我解释这种神秘行为,我将非常高兴。
我试了15分钟。我无法理解您要实现的目标。
请参见更新
注释
cur_requirement
应该被初始化。您在这里调用 UB:
requirements.emplace_back(level, description, label, cur_requirement); cur_requirement = &requirements.back();
您正在将指针存储到已放置要求中的向量元素。但是,放置可能会重新分配,使所有指针和迭代器无效。
Rethink your data model (prefer value-semantics? use containers with stable iterators? reserve up-front?)
- See: Iterator invalidation rules
更新
所以,这是我清理 display
函数(我将其重命名为 parse_json
因为它就是这样做的):
void parse_json(int depth, boost::property_tree::ptree const& tree, Requirement& cur)
{
cur.label = tree.get("label", "");
cur.level = tree.get("level", "");
cur.description = tree.get("description", "");
if (auto kids = tree.get_child_optional("children")) {
for (auto& kid : *kids) {
std::cout << "at depth " << depth << "... " << std::flush;
cur.children.emplace_back(&cur);
std::cout << "going down" << std::endl;
parse_json(depth + 1, kid.second, cur.children.back());
}
}
}
完整演示
看到整个程序都清理干净了。请注意,我已将 vector
替换为 list
以避免在读取更多子节点时使父指针无效
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <exception>
#include <fstream>
#include <iostream>
#include <string>
#include <list>
class Requirement {
public:
bool empty;
std::string level;
std::string description;
std::string label;
Requirement const* parent;
std::list <Requirement> children;
Requirement(Requirement const* p);
Requirement(std::string l, std::string d, std::string la, Requirement const* p); // unused
void print(std::string indent = "");
void print_json(std::ostream &os, std::string indent = "");
};
Requirement::Requirement(Requirement const* p)
: empty(false), parent(p)
{
}
Requirement::Requirement(std::string l, std::string d, std::string la,Requirement const* p) // unused
: empty(false),
level(std::move(l)), description(std::move(d)), label(std::move(la)), parent(p)
{
}
void Requirement::print_json(std::ostream &os, std::string indent) {
os << "{";
indent += '\t';
os
<< "\n" << indent << "\"level\":\"" << level << "\", "
<< "\n" << indent << "\"description\":\"" << description << "\"";
if(label.length() > 1) {
os << ",\n" << indent << "\"label\":\"" << label <<"\"";
}
if (!children.empty()) {
os << ", \"children\":[\n";
bool first = true;
for(auto& child : children) {
if (!first)
os << ',';
first=false;
os << "\n" << indent;
child.print_json(os, indent);
}
os << "]";
}
indent.resize(indent.size() - 1);
os << "\n" << indent << "}";
}
void Requirement::print(std::string indent) {
std::cout << indent << "level: " << level << " description:" << description << " label: " << label << std::endl;
for (Requirement kid : children)
kid.print(indent + '\t');
}
void parse_json(int depth, boost::property_tree::ptree const& tree, Requirement& cur)
{
cur.label = tree.get("label", "");
cur.level = tree.get("level", "");
cur.description = tree.get("description", "");
if (auto kids = tree.get_child_optional("children")) {
for (auto& kid : *kids) {
std::cout << "at depth " << depth << "... " << std::flush;
cur.children.emplace_back(&cur);
std::cout << "going down" << std::endl;
parse_json(depth + 1, kid.second, cur.children.back());
}
}
}
int main(int argc, char* argv[])
{
if (argc>1) try {
std::ifstream ss(argv[1]);
boost::property_tree::ptree pt;
boost::property_tree::read_json(ss, pt);
Requirement root(nullptr);
parse_json(0, pt, root);
std::cout << std::endl << std::endl;
root.print("; debug: ");
root.print_json(std::cout);
}
catch (std::exception const& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
}
输出为:
at depth 0... going down
at depth 0... going down
at depth 1... going down
at depth 2... going down
at depth 2... going down
; debug: level: should description:very well performance wise label: goperf
; debug: level: should description:be listening to spaces as well label: lisspace
; debug: level: will description:a lot of levels back down again label:
; debug: level: empty description:empty label: empty
; debug: level: can description:skip all the way back here label: skiphere
; debug: level: can description:take three linestr label: threelines
{
"level":"should",
"description":"very well performance wise",
"label":"goperf", "children":[
{
"level":"should",
"description":"be listening to spaces as well",
"label":"lisspace"
},
{
"level":"will",
"description":"a lot of levels back down again", "children":[
{
"level":"empty",
"description":"empty",
"label":"empty", "children":[
{
"level":"can",
"description":"skip all the way back here",
"label":"skiphere"
},
{
"level":"can",
"description":"take three linestr",
"label":"threelines"
}]
}]
}]
}
请注意,代码大约只有一半大小:)
我最终也链接了 main.cpp(现在称为 readreq.cpp),虽然我没能很好地递归,但它确实成功了。还必须更改其他一些内容,以便能够拥有需求列表的基础(不仅仅是一个根),代码也在 github 上 https://github.com/tomzooi/readreq 基本变化:
#include <fstream>
#include <iostream>
#include "class.h"
#include <vector>
#include <string>
//#include <regex>
#include <boost/regex.hpp>
#include <iterator>
#include <algorithm>
#include <math.h>
//how many spaces are interpreted as one tab or level
#define SPACES 8
#define LINEBUFSIZE 500
void parse_req(unsigned int cur_depth, std::ifstream &f, std::list<Requirement> &reqlist,unsigned int linenr=0) {
std::string line;
unsigned int count = 0;
unsigned int depth = 0;
Requirement * cur(nullptr);
boost::regex re("\t+|\s{2,}"); //regex split parameter (one or more tabs or 2 or more spaces)
std::list<Requirement>* lptr(&reqlist);
while (std::getline(f, line)) {
linenr++;
// std::cout << "(" << linenr << "): " << line;
depth = line.find_first_not_of(" "); //find first none space or tab character
boost::sregex_token_iterator i(line.begin()+depth, line.end(), re, -1); //split line by tabs and spaces
boost::sregex_token_iterator j;
count = 0; //reset count
if (depth == cur_depth) {
lptr->emplace_back(lptr->back().parent);
cur = &lptr->back();
}
else if (depth > cur_depth) { //go deeper
cur_depth = depth;
lptr = &lptr->back().children;
lptr->emplace_back(cur);
cur = &lptr->back();
}
else if (depth < cur_depth) { //go down
//lptr = cur->parent;
while (cur_depth > depth) {
cur_depth--;
std::cout << "deeper : " << cur_depth << std::endl << std::flush;
lptr = &(lptr->back().parent->parent->children);
}
if(cur_depth != 0) {
lptr->emplace_back(lptr->back().parent);
cur = &lptr->back();
}
else {
reqlist.emplace_back(nullptr);
cur = &reqlist.back();
}
}
while(i != j) { //for all splitted parts
switch(count) {
case 0:
cur->level =*i++;
//std::cout << "lvl: " << cur->level << " ";
break;
case 1:
cur->description = *i++;
//std::cout << "dsc: " << cur.description << std::endl;
break;
case 2:
cur->label = *i++;
break;
default:
*i++;
break;
}
count++;
}
if (count < 2) { //too less arguments
std::cout << "ERROR(" << linenr << "): nead at least two parts for an requirement (level and description), less than two found, halting." << std::endl;
break;
}
if (count > 3) { //too much arguments
std::cout << "WARNING(" << linenr << "): More then three arguments found, ignoring fourth or more argument" << std::endl;
}
}
}
int main(int argc, char *argv[]) {
// class Requirement req("will", "do good work", "good");
if ( argc != 3 ) // argc should be 2 for correct execution
// We print argv[0] assuming it is the program name
std::cout<<"usage: "<< argv[0] <<" <filename input> <filename output>\n";
else {
std::ifstream file(argv[1]); //try to open file
if(!file.is_open()) { //if we can't
std::cout << "Could not open file" ;
}
else { //sucesfully opened file
std::list<Requirement> requirements;
parse_req(0,file,requirements);
std::ofstream outfile(argv[2]); //try to open file
outfile << "{ \"requirements\":[";
for (Requirement req : requirements) {
req.print();
req.print_json(outfile);
if (requirements.back().description != req.description) {
outfile << ",";
}
}
outfile << "]}";
std::cout << "success!" << std::endl;
}
}
return 0;
}