support duplicate names
This commit is contained in:
+7
-3
@@ -4,7 +4,6 @@ tft can create and display family trees on the terminal.
|
|||||||
|
|
||||||
|
|
||||||
HOW TO CREATE:
|
HOW TO CREATE:
|
||||||
|
|
||||||
Trees are created using the tft file format, for example this tft file:
|
Trees are created using the tft file format, for example this tft file:
|
||||||
|
|
||||||
# This is a comment
|
# This is a comment
|
||||||
@@ -44,7 +43,6 @@ DEPENDENCIES:
|
|||||||
ncursesw development library (libncursesw5-dev on Debian/Ubuntu)
|
ncursesw development library (libncursesw5-dev on Debian/Ubuntu)
|
||||||
|
|
||||||
HOW TO INSTALL:
|
HOW TO INSTALL:
|
||||||
|
|
||||||
Make sure you satisfy the dependencies and have permissons and execute:
|
Make sure you satisfy the dependencies and have permissons and execute:
|
||||||
git clone https://gitlab.com/venelin98/tft.git
|
git clone https://gitlab.com/venelin98/tft.git
|
||||||
cd tft
|
cd tft
|
||||||
@@ -52,5 +50,11 @@ Make sure you satisfy the dependencies and have permissons and execute:
|
|||||||
|
|
||||||
|
|
||||||
HOW TO USE:
|
HOW TO USE:
|
||||||
|
|
||||||
tft ${MY_TFT_FILE}
|
tft ${MY_TFT_FILE}
|
||||||
|
|
||||||
|
TFT FORMAT:
|
||||||
|
- All spaces are ignored e.g.: Adam 0 and Adam0 are equivalent
|
||||||
|
- '_' in names is converted to ' '
|
||||||
|
- Number at the end of a name is used to disambiguate when multiple people have identical names e.g.:
|
||||||
|
Adam0 is the first added Adam, Adam1 is the second added Adam
|
||||||
|
- Must end with a newline
|
||||||
|
|||||||
+43
-12
@@ -39,6 +39,11 @@ namespace /* internal */
|
|||||||
/* result */
|
/* result */
|
||||||
Tree* cur_tree;
|
Tree* cur_tree;
|
||||||
|
|
||||||
|
bool isNum(char c)
|
||||||
|
{
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
void unexpected_char(char c)
|
void unexpected_char(char c)
|
||||||
{
|
{
|
||||||
cerr << "Line " << line << ": Unexpected '" << c << "'\n";
|
cerr << "Line " << line << ": Unexpected '" << c << "'\n";
|
||||||
@@ -56,7 +61,8 @@ namespace /* internal */
|
|||||||
{
|
{
|
||||||
while(it_data < end_data &&
|
while(it_data < end_data &&
|
||||||
*it_data != ',' &&
|
*it_data != ',' &&
|
||||||
*it_data != '\n')
|
*it_data != '\n' &&
|
||||||
|
!isNum(*it_data))
|
||||||
{
|
{
|
||||||
if(*it_data == ':' /* && *it_data == '-' */)
|
if(*it_data == ':' /* && *it_data == '-' */)
|
||||||
unexpected_char(*it_data);
|
unexpected_char(*it_data);
|
||||||
@@ -65,6 +71,17 @@ namespace /* internal */
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U32 sameNamedIndex(char*& it_data)
|
||||||
|
{
|
||||||
|
U32 res = 0;
|
||||||
|
if(isNum(*it_data))
|
||||||
|
{
|
||||||
|
res = *it_data - '0'; /* todo many digits */
|
||||||
|
++it_data;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
Sex findSex(char*& it_data)
|
Sex findSex(char*& it_data)
|
||||||
{
|
{
|
||||||
Sex res = M;
|
Sex res = M;
|
||||||
@@ -137,6 +154,7 @@ namespace /* internal */
|
|||||||
pair<person_id, person_id> processParents(char*& it_data)
|
pair<person_id, person_id> processParents(char*& it_data)
|
||||||
{
|
{
|
||||||
pair<person_id, person_id> res(Nobody, Nobody);
|
pair<person_id, person_id> res(Nobody, Nobody);
|
||||||
|
U32 same_name_index = 0;
|
||||||
string name; /* todo dont use string */
|
string name; /* todo dont use string */
|
||||||
for(; it_data < end_data; ++it_data)
|
for(; it_data < end_data; ++it_data)
|
||||||
{
|
{
|
||||||
@@ -144,11 +162,12 @@ namespace /* internal */
|
|||||||
{
|
{
|
||||||
case ',':
|
case ',':
|
||||||
if(res.first == Nobody)
|
if(res.first == Nobody)
|
||||||
res.first = cur_tree->findId(name.data());
|
res.first = cur_tree->findId(name.data())[same_name_index]; /* todo validate index */
|
||||||
else if(res.second == Nobody)
|
else if(res.second == Nobody)
|
||||||
res.second = cur_tree->findId(name.data());
|
res.second = cur_tree->findId(name.data())[same_name_index];
|
||||||
else
|
else
|
||||||
/* todo */exit(1);
|
/* todo */exit(1);
|
||||||
|
same_name_index = 0;
|
||||||
name.clear();
|
name.clear();
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
@@ -159,23 +178,27 @@ namespace /* internal */
|
|||||||
case '\n':
|
case '\n':
|
||||||
++line;
|
++line;
|
||||||
if(res.first == Nobody)
|
if(res.first == Nobody)
|
||||||
res.first = cur_tree->findId(name.data());
|
res.first = cur_tree->findId(name.data())[same_name_index];
|
||||||
else
|
else
|
||||||
res.second = cur_tree->findId(name.data());
|
res.second = cur_tree->findId(name.data())[same_name_index];
|
||||||
return prev_parents = res;
|
return prev_parents = res;
|
||||||
case '_':
|
case '_':
|
||||||
name.push_back(' ');
|
name.push_back(' ');
|
||||||
break;
|
break;
|
||||||
|
case '0' ... '9':
|
||||||
|
same_name_index = *it_data - '0';
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
name.push_back(*it_data);
|
name.push_back(*it_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unexpected_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<person_id> parseSpouses(char*& it_data)
|
vector<person_id> parseSpouses(char*& it_data)
|
||||||
{
|
{
|
||||||
vector<person_id> res;
|
vector<person_id> res;
|
||||||
|
U32 same_name_index = 0;
|
||||||
string name;
|
string name;
|
||||||
for(; it_data < end_data; ++it_data)
|
for(; it_data < end_data; ++it_data)
|
||||||
{
|
{
|
||||||
@@ -184,25 +207,29 @@ namespace /* internal */
|
|||||||
case ',':
|
case ',':
|
||||||
if(!name.empty())
|
if(!name.empty())
|
||||||
{
|
{
|
||||||
res.push_back( cur_tree->findId(name.data()) );
|
res.push_back( cur_tree->findId(name.data())[same_name_index] );
|
||||||
name.clear();
|
name.clear();
|
||||||
|
same_name_index = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
unexpected_char(',');
|
unexpected_char(',');
|
||||||
break;
|
break;
|
||||||
case '\n':
|
case '\n':
|
||||||
++line;
|
++line;
|
||||||
res.push_back( cur_tree->findId(name.data()) );
|
res.push_back( cur_tree->findId(name.data())[same_name_index] );
|
||||||
return res;
|
return res;
|
||||||
case '_':
|
case '_':
|
||||||
name.push_back(' ');
|
name.push_back(' ');
|
||||||
break;
|
break;
|
||||||
|
case '0' ... '9':
|
||||||
|
same_name_index = *it_data - '0';
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
name.push_back(*it_data);
|
name.push_back(*it_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!name.empty())
|
if(!name.empty())
|
||||||
res.push_back( cur_tree->findId(name.data()) );
|
res.push_back( cur_tree->findId(name.data())[same_name_index] );
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,15 +262,19 @@ namespace /* internal */
|
|||||||
EventTime birth{};
|
EventTime birth{};
|
||||||
EventTime death{};
|
EventTime death{};
|
||||||
|
|
||||||
proceedToNameEnd(it_data);
|
proceedToNameEnd(it_data); /* todo merge funcs */
|
||||||
/* string_view name(name_start, it_data); */
|
|
||||||
string name(name_start, it_data);
|
string name(name_start, it_data);
|
||||||
|
|
||||||
|
U32 same_name_index = sameNamedIndex(it_data);
|
||||||
|
/* string_view name(name_start, it_data); */
|
||||||
for(char& c: name)
|
for(char& c: name)
|
||||||
{
|
{
|
||||||
if(c == '_')
|
if(c == '_')
|
||||||
c = ' ';
|
c = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Sex sex = findSex(it_data);
|
Sex sex = findSex(it_data);
|
||||||
|
|
||||||
for(; it_data < end_data; ++it_data)
|
for(; it_data < end_data; ++it_data)
|
||||||
@@ -332,7 +363,7 @@ namespace /* internal */
|
|||||||
|
|
||||||
Tree parseTftFile(fd_t file)
|
Tree parseTftFile(fd_t file)
|
||||||
{
|
{
|
||||||
Tree result("name");
|
Tree result("t");
|
||||||
cur_tree = &result;
|
cur_tree = &result;
|
||||||
|
|
||||||
MappedFile mapedfile = mapfile(file);
|
MappedFile mapedfile = mapfile(file);
|
||||||
|
|||||||
+6
-5
@@ -107,14 +107,15 @@ person_id Tree::last()
|
|||||||
return people.size() - 1;
|
return people.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
person_id Tree::findId(const char* name) const
|
vector<person_id> Tree::findId(const char* name) const
|
||||||
{
|
{
|
||||||
|
vector<person_id> res;
|
||||||
for (person_id i = 0; i < people.size(); ++i)
|
for (person_id i = 0; i < people.size(); ++i)
|
||||||
{
|
{
|
||||||
if (name == people[i].name)
|
if (name == people[i].name)
|
||||||
return i;
|
res.push_back(i);
|
||||||
}
|
}
|
||||||
return Nobody;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
person_id Tree::findId(const char* name, Sex s) const
|
person_id Tree::findId(const char* name, Sex s) const
|
||||||
@@ -286,7 +287,7 @@ void Tree::addPerson(const char* name, Sex sex, unsigned father, unsigned mother
|
|||||||
bool Tree::addRelation(const char* firstName, const RelType type, const char* secondName)
|
bool Tree::addRelation(const char* firstName, const RelType type, const char* secondName)
|
||||||
{
|
{
|
||||||
|
|
||||||
return addRelation(findId(firstName), type, findId(secondName));
|
return addRelation(findId(firstName)[0], type, findId(secondName)[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Tree::addRelation(const unsigned first, const RelType type, const unsigned second, bool update)
|
bool Tree::addRelation(const unsigned first, const RelType type, const unsigned second, bool update)
|
||||||
@@ -341,7 +342,7 @@ void Tree::addRelOneSide(person_id first, RelType type, person_id second)
|
|||||||
|
|
||||||
void Tree::removeRelation(const char* firstName, const char* secondName)
|
void Tree::removeRelation(const char* firstName, const char* secondName)
|
||||||
{
|
{
|
||||||
removeRelation(findId(firstName), findId(secondName));
|
removeRelation(findId(firstName)[0], findId(secondName)[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tree::removePerson(const person_id id)
|
void Tree::removePerson(const person_id id)
|
||||||
|
|||||||
+1
-1
@@ -45,7 +45,7 @@ public:
|
|||||||
void rename(const char* newName);
|
void rename(const char* newName);
|
||||||
|
|
||||||
person_id last();
|
person_id last();
|
||||||
person_id findId(const char* name) const;
|
std::vector<person_id> findId(const char* name) const;
|
||||||
person_id findId(const char* name, Sex) const;
|
person_id findId(const char* name, Sex) const;
|
||||||
person_id findOldestAncestor(person_id, Sex) const;//
|
person_id findOldestAncestor(person_id, Sex) const;//
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user