| /* Copyright 2023 The ChromiumOS Authors |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| /* Specialised YamlNode, representing a YAML mapping. |
| * |
| * This is equivalent to maps/dictionaries in programming languages. |
| * |
| * Keys are always strings in this implementation. |
| * (YAML itself allows any node to be a key). |
| */ |
| |
| #include "tools/mctk/yaml_tree.h" |
| |
| #include <linux/types.h> |
| #include <yaml.h> |
| |
| #include <memory> /* std::unique_ptr */ |
| #include <string> |
| #include <utility> /* std::move, std::pair */ |
| #include <vector> |
| |
| #include "tools/mctk/debug.h" |
| |
| /* Caller is responsible for deleting the event passed in */ |
| std::unique_ptr<YamlMap> YamlMap::FromParserEvent(yaml_parser_t& parser, |
| yaml_event_t& start_event) { |
| MCTK_ASSERT_EQ(start_event.type, YAML_MAPPING_START_EVENT); |
| |
| auto new_map = std::make_unique<YamlMap>(); |
| if (!new_map) |
| return NULL; |
| |
| /* Store YAML formatting style for debugging purposes */ |
| new_map->implicit_ = start_event.data.mapping_start.implicit; |
| new_map->style_ = start_event.data.mapping_start.style; |
| |
| while (true) { |
| yaml_event_t event; |
| |
| if (!yaml_parser_parse(&parser, &event)) |
| goto error; |
| |
| if (event.type == YAML_MAPPING_END_EVENT) { |
| yaml_event_delete(&event); |
| return new_map; |
| } |
| |
| /* Part 1: We expect a scalar as a key */ |
| if (event.type != YAML_SCALAR_EVENT) { |
| yaml_event_delete(&event); |
| goto error; |
| } |
| |
| std::string key((const char*)event.data.scalar.value, |
| event.data.scalar.length); |
| |
| yaml_event_delete(&event); |
| |
| /* Part 2: Parse any node type as a value */ |
| auto value = YamlNode::FromParser(parser); |
| if (!value) |
| goto error; |
| |
| new_map->map_.push_back(YamlMapPair(key, std::move(value))); |
| } |
| |
| error: |
| return NULL; |
| } |
| |
| bool YamlMap::Emit(yaml_emitter_t& emitter) { |
| yaml_event_t event; |
| |
| if (!yaml_mapping_start_event_initialize( |
| &event, NULL, reinterpret_cast<const yaml_char_t*>(YAML_MAP_TAG), |
| implicit_, style_)) |
| return false; |
| if (!yaml_emitter_emit(&emitter, &event)) |
| return false; |
| |
| for (YamlMapPair& pair : this->map_) { |
| if (!yaml_scalar_event_initialize( |
| &event, NULL, NULL, |
| reinterpret_cast<const yaml_char_t*>(pair.first.c_str()), -1, 1, 1, |
| YAML_ANY_SCALAR_STYLE)) |
| return false; |
| if (!yaml_emitter_emit(&emitter, &event)) |
| return false; |
| |
| pair.second->Emit(emitter); |
| } |
| |
| if (!yaml_mapping_end_event_initialize(&event)) |
| return false; |
| if (!yaml_emitter_emit(&emitter, &event)) |
| return false; |
| |
| return true; |
| } |