* Set debugging levels by parsing the text in \a s. * For setting individual levels a string like \c "net=3,grf=6" should be used. * If the string starts with a number, the number is used as global debugging level. * @param s Text describing the wanted debugging levels. * @param error_func The function to call if a parse error occurs. */
| 142 | * @param error_func The function to call if a parse error occurs. |
| 143 | */ |
| 144 | void SetDebugString(std::string_view s, SetDebugStringErrorFunc error_func) |
| 145 | { |
| 146 | StringConsumer consumer{s}; |
| 147 | |
| 148 | /* Store planned changes into map during parse */ |
| 149 | std::map<std::string_view, int> new_levels; |
| 150 | |
| 151 | /* Global debugging level? */ |
| 152 | auto level = consumer.TryReadIntegerBase<int>(10); |
| 153 | if (level.has_value()) { |
| 154 | for (const auto &debug_level : _debug_levels) { |
| 155 | new_levels[debug_level.name] = *level; |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | static const std::string_view lowercase_letters{"abcdefghijklmnopqrstuvwxyz"}; |
| 160 | static const std::string_view lowercase_letters_and_digits{"abcdefghijklmnopqrstuvwxyz0123456789"}; |
| 161 | |
| 162 | /* Individual levels */ |
| 163 | while (consumer.AnyBytesLeft()) { |
| 164 | consumer.SkipUntilCharIn(lowercase_letters); |
| 165 | if (!consumer.AnyBytesLeft()) break; |
| 166 | |
| 167 | /* Find the level by name. */ |
| 168 | std::string_view key = consumer.ReadUntilCharNotIn(lowercase_letters); |
| 169 | auto it = std::ranges::find(_debug_levels, key, &DebugLevel::name); |
| 170 | if (it == std::end(_debug_levels)) { |
| 171 | error_func(fmt::format("Unknown debug level '{}'", key)); |
| 172 | return; |
| 173 | } |
| 174 | |
| 175 | /* Do not skip lowercase letters, so 'net misc=2' won't be resolved |
| 176 | * to setting 'net=2' and leaving misc untouched. */ |
| 177 | consumer.SkipUntilCharIn(lowercase_letters_and_digits); |
| 178 | level = consumer.TryReadIntegerBase<int>(10); |
| 179 | if (!level.has_value()) { |
| 180 | error_func(fmt::format("Level for '{}' must be a valid integer.", key)); |
| 181 | return; |
| 182 | } |
| 183 | |
| 184 | new_levels[it->name] = *level; |
| 185 | } |
| 186 | |
| 187 | /* Apply the changes after parse is successful */ |
| 188 | for (const auto &debug_level : _debug_levels) { |
| 189 | const auto &nl = new_levels.find(debug_level.name); |
| 190 | if (nl != new_levels.end()) { |
| 191 | *debug_level.level = nl->second; |
| 192 | } |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | /** |
| 197 | * Print out the current debug-level. |
no test coverage detected