Node: make _generate_serial_child_name manipulate numbers as String

The conversion from an String to int can overflow int and int64
so it is safer to manipulate strings when we try to find the next
available name for a Node.
This commit is contained in:
lupoDharkael 2018-11-20 18:00:58 +01:00
parent 173b342ca7
commit 1025e3ecea

View file

@ -1008,6 +1008,32 @@ void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) {
}
}
// Return s + 1 as if it were an integer
String increase_numeric_string(const String &s) {
String res = s;
bool carry = res.length() > 0;
for (int i = res.length() - 1; i >= 0; i--) {
if (!carry) {
break;
}
CharType n = s[i];
if (n == '9') { // keep carry as true: 9 + 1
res[i] = '0';
} else {
res[i] = s[i] + 1;
carry = false;
}
}
if (carry) {
res = "1" + res;
}
return res;
}
String Node::_generate_serial_child_name(Node *p_child) {
String name = p_child->data.name;
@ -1040,42 +1066,38 @@ String Node::_generate_serial_child_name(Node *p_child) {
}
String nnsep = _get_name_num_separator();
int num = 0;
bool explicit_zero = false;
if (nums.length() > 0 && name.substr(name.length() - nnsep.length() - nums.length(), nnsep.length()) == nnsep) {
// Base name + Separator + Number
num = nums.to_int();
name = name.substr(0, name.length() - nnsep.length() - nums.length()); // Keep base name
if (num == 0) {
explicit_zero = true;
int name_last_index = name.length() - nnsep.length() - nums.length();
// Assign the base name + separator to name if we have numbers preceded by a separator
if (nums.length() > 0 && name.substr(name_last_index, nnsep.length()) == nnsep) {
name = name.substr(0, name_last_index + nnsep.length()).strip_edges();
} else {
nums = "";
}
Vector<String> children_names;
for (int i = 0; i < data.children.size(); i++) {
String child_name = data.children[i]->data.name;
if (data.children[i] == p_child)
continue;
if (child_name.begins_with(name)) {
children_names.push_back(child_name);
}
}
int num_places = nums.length();
for (;;) {
String attempt = (name + (num > 0 || explicit_zero ? nnsep + itos(num).pad_zeros(num_places) : "")).strip_edges();
bool found = false;
for (int i = 0; i < data.children.size(); i++) {
if (data.children[i] == p_child)
continue;
if (data.children[i]->data.name == attempt) {
found = true;
break;
}
}
if (!found) {
String attempt = name + nums;
if (children_names.find(attempt) == -1) {
return attempt;
} else {
if (num == 0) {
if (explicit_zero) {
// Name ended in separator + 0; user expects to get to separator + 1
num = 1;
} else {
// Name was undecorated so skip to 2 for a more natural result
num = 2;
}
if (nums.length() == 0) {
// Name was undecorated so skip to 2 for a more natural result
nums = "2";
name += nnsep; // Add separator because nums.length() > 0 was false
} else {
num++;
nums = increase_numeric_string(nums);
}
}
}