| 
							- // Copyright 2021 Jean Pierre Cimalando
 - //
 - // Licensed under the Apache License, Version 2.0 (the "License");
 - // you may not use this file except in compliance with the License.
 - // You may obtain a copy of the License at
 - //
 - //     http://www.apache.org/licenses/LICENSE-2.0
 - //
 - // Unless required by applicable law or agreed to in writing, software
 - // distributed under the License is distributed on an "AS IS" BASIS,
 - // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 - // See the License for the specific language governing permissions and
 - // limitations under the License.
 - //
 - // SPDX-License-Identifier: Apache-2.0
 - //
 - 
 - #include "ysfx_parse_menu.hpp"
 - #include "ysfx_utils.hpp"
 - #include <vector>
 - #include <cstring>
 - #include <cassert>
 - 
 - static void ysfx_menu_insn_clear(ysfx_menu_insn_t *insn)
 - {
 -         delete[] insn->name;
 - }
 - 
 - static bool ysfx_do_create_menu(std::vector<ysfx_menu_insn_t> &insns, const char **str, uint32_t *startid, uint32_t menudepth)
 - {
 -     if (menudepth >= 8)
 -         return false;
 - 
 -     ///
 -     auto shrink_insns_to = [&insns](size_t count) {
 -         assert(insns.size() >= count);
 -         while (insns.size() > count) {
 -             ysfx_menu_insn_clear(&insns.back());
 -             insns.pop_back();
 -         }
 -     };
 - 
 -     ///
 -     size_t insn_count_at_start = insns.size();
 - 
 -     ///
 -     size_t pos = 0;
 -     uint32_t id = *startid;
 - 
 -     const char *p = *str;
 -     const char *sep = strchr(p, '|');
 -     while (sep || *p) {
 -         size_t len = sep ? (size_t)(sep - p) : strlen(p);
 -         std::string buf(p, len);
 -         p += len;
 -         if (sep)
 -             sep = strchr(++p, '|');
 - 
 -         const char *q = buf.c_str();
 -         bool subm = false;
 -         size_t insn_count_at_subm = 0;
 -         bool done = false;
 -         uint32_t item_flags = 0;
 -         while (*q && strchr(">#!<", *q)) {
 -             if (*q == '>' && !subm) {
 -                 insn_count_at_subm = insns.size();
 -                 insns.emplace_back();
 -                 insns.back().opcode = ysfx_menu_sub;
 -                 subm = ysfx_do_create_menu(insns, &p, &id, menudepth + 1);
 -                 insns.emplace_back();
 -                 insns.back().opcode = ysfx_menu_endsub;
 -                 sep = strchr(p, '|');
 -             }
 -             if (*q == '#')
 -                 item_flags |= ysfx_menu_item_disabled;
 -             if (*q == '!')
 -                 item_flags |= ysfx_menu_item_checked;
 -             if (*q == '<')
 -                 done = true;
 -             ++q;
 -         }
 -         if (*q) {
 -             if (subm) {
 -                 for (ysfx_menu_insn_t *insn : {&insns[insn_count_at_subm], &insns.back()}) {
 -                     insn->name = ysfx::strdup_using_new(q);
 -                     insn->item_flags = item_flags;
 -                 }
 -             }
 -             else {
 -                 ysfx_menu_insn_t &insn = (insns.emplace_back(), insns.back());
 -                 insn.opcode = ysfx_menu_item;
 -                 insn.id = id++;
 -                 insn.name = ysfx::strdup_using_new(q);
 -                 insn.item_flags = item_flags;
 -             }
 -         }
 -         else {
 -             if (subm)
 -                 shrink_insns_to(insn_count_at_subm);
 -             if (!done) {
 -                 ysfx_menu_insn_t &insn = (insns.emplace_back(), insns.back());
 -                 insn.opcode = ysfx_menu_separator;
 -             }
 -         }
 -         ++pos;
 -         if (done)
 -             break;
 -     }
 - 
 -     *str = p;
 -     *startid = id;
 - 
 -     ///
 -     if (!pos) {
 -         shrink_insns_to(insn_count_at_start);
 -         return false;
 -     }
 - 
 -     return true;
 - }
 - 
 - ysfx_menu_t *ysfx_parse_menu(const char *text)
 - {
 -     std::vector<ysfx_menu_insn_t> insns;
 -     insns.reserve(256);
 - 
 -     ///
 -     auto cleanup = ysfx::defer([&insns]() {
 -         for (ysfx_menu_insn_t &insn : insns)
 -             ysfx_menu_insn_clear(&insn);
 -     });
 - 
 -     ///
 -     const char *textpos = text;
 -     uint32_t id = 1;
 -     ysfx_do_create_menu(insns, &textpos, &id, 0);
 - 
 -     ///
 -     ysfx_menu_u menu{new ysfx_menu_t};
 -     menu->insn_count = (uint32_t)insns.size();
 -     menu->insns = new ysfx_menu_insn_t[menu->insn_count];
 -     memcpy(menu->insns, insns.data(), menu->insn_count * sizeof(ysfx_menu_insn_t));
 -     insns.clear();
 -     return menu.release();
 - }
 - 
 - void ysfx_menu_free(ysfx_menu_t *menu)
 - {
 -     if (!menu)
 -         return;
 - 
 -     for (uint32_t i = 0; i < menu->insn_count; ++i)
 -         ysfx_menu_insn_clear(&menu->insns[i]);
 - 
 -     delete[] menu->insns;
 -     delete menu;
 - }
 
 
  |