u32 File::WriteNewKey(const char *case_key, const char *key, int key_len, LineItem *front, LineItem *end) { // Strip off dotted parts until we find it in the hash table for (int jj = key_len - 1; jj > 1; --jj) { // Search for next dot if (key[jj] != '.') continue; // Create a key from the parent part of the string u32 hash = MurmurHash(key, jj).Get32(); // Look up the parent item LineItem *parent = _table.Lookup(KeyAdapter(key, jj, hash)); if (parent) { // If parent is already enlisted, if (parent->_enlisted) { // Insert after parent end->_sort_next = parent->_sort_next; parent->_sort_next = front; } else { // NOTE: New items at end are all enlisted so will not get here with a new-item parent // Insert at front of the modified list end->_sort_next = _modded; _modded = front; } // Remember key depth _key_depth = parent->_depth; // Return end-of-line offset of parent return parent->_eol_offset ? parent->_eol_offset : parent->_sort_value; } else { // Create a hash table entry for this key LineItem *item = _table.Create(KeyAdapter(key, jj, hash)); if (!item) { CAT_FATAL("Ragdoll") << "Out of memory"; return 0; } // NOTE: Will not find this item as a parent during recursion // so leaving the item uninitialized for now is okay. // Recurse to find parent u32 offset = WriteNewKey(case_key, key, jj, item, end); // Go ahead and fill in the item item->_enlisted = true; item->_sort_value = offset; item->_eol_offset = 0; // Indicate it is a new item that needs new item processing item->_sort_next = front; item->_depth = ++_key_depth; item->_case_key.SetFromRangeString(case_key, jj); item->ClearValue(); CAT_DEBUG_ENFORCE(_key_depth <= Parser::MAX_TAB_RECURSION_DEPTH); return offset; } } // Did not find the parent at all, so this is a completely new item // Insert at the front of the eof list end->_sort_next = _eof_head; _eof_head = front; // Remember key depth _key_depth = -1; return 0; }
int Parser::ReadTokens(int root_key_len, int root_depth) { int eof = 0; do { // If there is not enough space to append the first token to the end of the root key, if (root_key_len + 1 + _first_len > MAX_CHARS) { // Signal EOF here to avoid mis-attributing keys CAT_WARN("Settings") << "Long line caused settings processing to abort early"; return 0; } // Append first token to root key int key_len = root_key_len + _first_len; char *write_key = _root_key + root_key_len; if (root_key_len > 0) { _root_key[root_key_len] = '.'; ++write_key; ++key_len; } memcpy(write_key, _first, _first_len); write_key[_first_len] = '\0'; // Add this path to the hash table SanitizedKey san_key(_root_key, key_len); KeyAdapter key_input(san_key); LineItem *item = _output_file->_table.Lookup(key_input); if (!item) { // Create a new item for this key item = _output_file->_table.Create(key_input); if (!_is_override) item->_enlisted = false; else { // Push onto the new list CAT_FSLL_PUSH_FRONT(_output_file->_newest, item, _sort_next); item->_enlisted = true; item->_case_key.SetFromRangeString(_root_key, key_len); } } else { if (!item->_enlisted) { // Push onto the modded list CAT_FSLL_PUSH_FRONT(_output_file->_modded, item, _sort_next); item->_enlisted = true; } } // Update item value if (item) { if (!_is_override) { // Calculate key end offset and end of line offset u32 key_end_offset = (u32)(_first + _first_len - _file_front); u32 eol_offset; if (!_eol) eol_offset = (u32)(_eof - _file_front); else eol_offset = (u32)(_eol - _file_front); item->_sort_value = key_end_offset; item->_eol_offset = eol_offset; } item->_depth = _depth; // If second token is set, if (_second_len > 0) item->SetValueRangeStr(_second, _second_len); else item->ClearValue(); } // For each line until EOF, eof = 0; int depth = _depth; while (NextLine()) { // Skip blank lines if (_first_len == 0) continue; // If new line depth is at or beneath the root, if (root_depth >= _depth) eof = 1; // Pass it back to the root to handle // If new line is a child of current depth, else if (depth < _depth) { // Otherwise the new line depth is deeper, so recurse and add onto the key eof = ReadTokens(key_len, depth); // If not EOF, if (eof != 0) { // If new line depth is at the same level as current token, if (root_depth < _depth) eof = 2; // Repeat whole routine again at this depth else eof = 1; // Pass it back to the root to handle } } else // New line depth is at about the same level as current eof = 2; // Repeat whole routine again at this depth break; } // Remove appended token _root_key[root_key_len] = '\0'; } while (eof == 2); return eof; }