stamen

Stamen - static menu generator
git clone git://git.dimitrijedobrota.com/stamen.git
Log | Files | Refs | README | LICENSE

commit cd12b2fea38be76fe6bd2c607598c785d979c25e
parent 199eba24714cb83271e636100315011def07ded9
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Fri, 14 Jun 2024 11:33:39 +0200

Split menu in its own set of headers

Diffstat:
MCMakeLists.txt | 12++++--------
Mdemo/dynamic.cpp | 15++++++++-------
Minclude/menu.h | 91+++++++++----------------------------------------------------------------------
Ainclude/menu.hpp | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/stamen.h | 6+-----
Minclude/stamen.hpp | 4----
Msrc/CMakeLists.txt | 2+-
Msrc/c_bindings.cpp | 20+++++++++++---------
Msrc/generate.cpp | 10+++++-----
Msrc/menu.cpp | 72+++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/stamen.cpp | 10----------
11 files changed, 154 insertions(+), 165 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -70,14 +70,10 @@ install( ) install( - EXPORT - stamenTargets - NAMESPACE - "stamen::" - DESTINATION - ${INSTALL_CMAKEDIR} - COMPONENT - dev + EXPORT stamenTargets + NAMESPACE "stamen::" + DESTINATION ${INSTALL_CMAKEDIR} + COMPONENT dev ) include(CMakePackageConfigHelpers) diff --git a/demo/dynamic.cpp b/demo/dynamic.cpp @@ -1,6 +1,7 @@ -#include "stamen.hpp" #include <iostream> +#include "menu.hpp" + int finish(int) { exit(1); } int operation1(int) { @@ -20,15 +21,15 @@ int operation3(int) { int main() { // read the configuration - stamen::read("./bin/demo_menu.conf"); + stamen::menu::read("./bin/demo_menu.conf"); // register free functions - stamen::insert("finish", finish); - stamen::insert("operation1", operation1); - stamen::insert("operation2", operation2); - stamen::insert("operation3", operation3); + stamen::menu::insert("finish", finish); + stamen::menu::insert("operation1", operation1); + stamen::menu::insert("operation2", operation2); + stamen::menu::insert("operation3", operation3); // start the menu on specific panel - stamen::dynamic("menu_main", stamen::builtin_display); + stamen::menu::dynamic("menu_main", stamen::builtin_display); return 0; } diff --git a/include/menu.h b/include/menu.h @@ -1,91 +1,20 @@ #ifndef STAMEN_MENU_H #define STAMEN_MENU_H -#include "stamen.hpp" - -#include <cstring> -#include <iostream> -#include <string> -#include <unordered_map> -#include <vector> +#include "stamen.h" +#ifdef __cplusplus +extern "C" { namespace stamen { +#endif -class Menu { - struct private_ctor_t {}; - - public: - // Tag type dispatch - Menu(private_ctor_t, const std::string &code, const std::string &prompt) - : Menu(code, prompt) {} - - Menu(const Menu &) = delete; - Menu &operator=(const Menu &) = delete; - Menu(Menu &&) = delete; - Menu &operator=(Menu &&) = delete; - ~Menu() noexcept = default; - - static int dynamic(const std::string &code, display_f display) { - Menu::display_stub_default = code; - Menu::display = display; - return display_stub(-1); - }; - - static void read(const std::string &s); - static void insert(const std::string &s, callback_f callback) { - free_lookup.emplace(s, callback); - } - - const std::string &getCode() const { return code; } - const std::string &getTitle() const { return title; } - - const item_t *getItemv() const { return entries.items.data(); } - std::size_t getSize() const { return entries.items.size(); } - - callback_f getCallback(std::size_t idx) const; - const std::string &getCode(std::size_t idx) const; - const std::string &getPrompt(std::size_t idx) const; - - static std::unordered_map<std::string, Menu> menu_lookup; - - private: - Menu(std::string code, std::string prompt) - : code(std::move(code)), title(std::move(prompt)) {} - - struct entries_t { - entries_t() = default; - entries_t(const entries_t &) = delete; - entries_t &operator=(const entries_t &) = delete; - entries_t(entries_t &&) = delete; - entries_t &operator=(entries_t &&) = delete; - ~entries_t() noexcept { - for (const auto [_, prompt] : items) { - delete[] prompt; - } - } - - void insert(const std::string &code, const std::string &prompt, - callback_f callback = display_stub); - - struct code_t { - std::string code; - std::string prompt; - }; - - std::vector<code_t> codes; - std::vector<item_t> items; - }; - - const std::string code, title; - entries_t entries; - - static int display_stub(int idx); - - static std::unordered_map<std::string, callback_f> free_lookup; - static std::string display_stub_default; - static display_f display; -}; +void stamen_menu_read(const char *filename); +void stamen_menu_insert(const char *code, stamen_callback_f callback); +int stamen_menu_dynamic(const char *code, stamen_display_f display); +#ifdef __cplusplus } // namespace stamen +} // extern "C" +#endif #endif diff --git a/include/menu.hpp b/include/menu.hpp @@ -0,0 +1,77 @@ +#ifndef STAMEN_MENU_HPP +#define STAMEN_MENU_HPP + +#include "stamen.hpp" + +#include <cstring> +#include <iostream> +#include <string> +#include <unordered_map> +#include <vector> + +namespace stamen { +namespace menu { + +class menu_t; + +extern std::unordered_map<std::string, callback_f> free_lookup; +extern std::unordered_map<std::string, menu_t> menu_lookup; +extern std::string display_stub_default; +extern display_f display; + +void read(const char *filename); +void insert(const char *code, callback_f callback); +int dynamic(const char *code, display_f display); +int display_stub(int idx); + +class menu_t { + struct private_ctor_t {}; + friend void read(const char *filename); + + public: + // Tag type dispatch + menu_t(private_ctor_t, const std::string &code, const std::string &prompt) + : menu_t(code, prompt) {} + + ~menu_t() noexcept { + for (const auto [_, prompt] : items) { + delete[] prompt; + } + } + + const std::string &getCode() const { return code; } + const std::string &getTitle() const { return title; } + + const item_t *getItemv() const { return items.data(); } + std::size_t getSize() const { return items.size(); } + + auto getCallback(std::size_t idx) const { return items[idx].callback; } + const auto &getCode(std::size_t idx) const { return codes[idx].code; } + const auto &getPrompt(std::size_t idx) const { return codes[idx].prompt; } + + private: + menu_t(std::string code, std::string prompt) + : code(std::move(code)), title(std::move(prompt)) {} + + menu_t(const menu_t &) = delete; + menu_t &operator=(const menu_t &) = delete; + menu_t(menu_t &&) = delete; + menu_t &operator=(menu_t &&) = delete; + + void insert(const std::string &code, const std::string &prompt, + callback_f callback = display_stub); + + struct code_t { + std::string code; + std::string prompt; + }; + + const std::string code, title; + std::vector<code_t> codes; + std::vector<item_t> items; +}; + +} // namespace menu +} // namespace stamen + +#endif diff --git a/include/stamen.h b/include/stamen.h @@ -18,10 +18,6 @@ typedef int (*stamen_display_f)(const char *, const stamen_item_t[], int); #if !defined __cplusplus || defined WITH_C_BINDINGS -void stamen_read(const char *filename); -void stamen_insert(const char *code, stamen_callback_f callback); - -int stamen_dynamic(const char *code, stamen_display_f display); int stamen_builtin_display(const char *title, const stamen_item_t itemv[], int size); @@ -32,4 +28,4 @@ int stamen_builtin_display(const char *title, const stamen_item_t itemv[], } // extern "C" #endif -#endif // STAMEN_STAMEN_H +#endif diff --git a/include/stamen.hpp b/include/stamen.hpp @@ -9,10 +9,6 @@ using callback_f = stamen_callback_f; using display_f = stamen_display_f; using item_t = stamen_item_t; -void read(const char *filename); -void insert(const char *code, callback_f callback); - -int dynamic(const char *code, display_f display); int builtin_display(const char *title, const item_t itemv[], int size); } // namespace stamen diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt @@ -7,7 +7,7 @@ set_target_properties(stamen PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR} DEBUG_POSTFIX "d" - PUBLIC_HEADER "include/stamen.h;include/stamen.hpp" + PUBLIC_HEADER "include/stamen.h;include/stamen.hpp;include/menu.h;include/menu.hpp" MACOSX_RPATH ON WINDOWS_EXPORT_ALL_SYMBOLS ON ) diff --git a/src/c_bindings.cpp b/src/c_bindings.cpp @@ -1,21 +1,23 @@ -#include "stamen.h" +#include "menu.hpp" #include "stamen.hpp" namespace stamen { -void stamen_read(const char *filename) { return read(filename); } +int stamen_builtin_display(const char *title, const stamen_item_t itemv[], int size) { + return builtin_display(title, itemv, size); +} + +namespace menu { + +void stamen_menu_read(const char *filename) { return read(filename); } -void stamen_insert(const char *code, stamen_callback_f callback) { +void stamen_menu_insert(const char *code, stamen_callback_f callback) { return insert(code, callback); } -int stamen_dynamic(const char *code, stamen_display_f display) { +int stamen_menu_dynamic(const char *code, stamen_display_f display) { return dynamic(code, display); } -int stamen_builtin_display(const char *title, const stamen_item_t itemv[], - int size) { - return builtin_display(title, itemv, size); -} - +} // namespace menu } // namespace stamen diff --git a/src/generate.cpp b/src/generate.cpp @@ -1,7 +1,7 @@ #include <args/args.hpp> -#include "menu.h" -#include "stamen.h" +#include "menu.hpp" +#include "stamen.hpp" #include <format> #include <fstream> @@ -31,7 +31,7 @@ void generateInclude(std::ostream &os) { generateIncludeHeaders(os); - for (const auto &[code, menu] : stamen::Menu::menu_lookup) { + for (const auto &[code, menu] : stamen::menu::menu_lookup) { os << std::format("int {}(int);\n", menu.getCode()); } @@ -46,7 +46,7 @@ void generateSource(std::ostream &os) { if (opt.cpp) os << "const stamen::item_t itemv[], int size);\n\n"; else os << "const stamen_item_t itemv[], int size);\n\n"; - for (const auto &[code, menu] : stamen::Menu::menu_lookup) { + for (const auto &[code, menu] : stamen::menu::menu_lookup) { os << std::format("int {}(int) {{\n", menu.getCode()); if (opt.cpp) os << "\tstatic const stamen::item_t items[] = "; @@ -116,7 +116,7 @@ int main(int argc, char *argv[]) { } const auto &config = opt.config; - stamen::Menu::read(config); + stamen::menu::read(config.c_str()); std::string::size_type pos = opt.config.rfind('.'); std::string base = diff --git a/src/menu.cpp b/src/menu.cpp @@ -1,4 +1,4 @@ -#include "menu.h" +#include "menu.hpp" #include <deque> #include <format> @@ -9,36 +9,16 @@ #include <utility> namespace stamen { +namespace menu { -std::unordered_map<std::string, Menu> Menu::menu_lookup; -std::unordered_map<std::string, callback_f> Menu::free_lookup; -std::string Menu::display_stub_default; -display_f Menu::display; +std::unordered_map<std::string, menu_t> menu_lookup; +std::unordered_map<std::string, callback_f> free_lookup; +std::string display_stub_default; +display_f display; -void Menu::entries_t::insert(const std::string &code, - const std::string &prompt, callback_f callback) { - char *buffer = new char[prompt.size() + 1]; - strcpy(buffer, prompt.c_str()); - - items.emplace_back(callback, buffer); - codes.emplace_back(code, prompt); -} - -const std::string &Menu::getCode(std::size_t idx) const { - return entries.codes[idx].code; -} - -const std::string &Menu::getPrompt(std::size_t idx) const { - return entries.codes[idx].prompt; -} - -callback_f Menu::getCallback(std::size_t idx) const { - return entries.items[idx].callback; -} - -void Menu::read(const std::string &s) { +void read(const char *filename) { std::string line, delim, code, prompt; - std::fstream fs(s); + std::fstream fs(filename); auto last = menu_lookup.end(); while (std::getline(fs, line)) { @@ -48,28 +28,40 @@ void Menu::read(const std::string &s) { ss >> delim >> code >> std::ws; std::getline(ss, prompt); - if (delim != "+") last->second.entries.insert(code, prompt); + if (delim != "+") last->second.insert(code, prompt); else { const auto [iter, succ] = menu_lookup.emplace( std::piecewise_construct, std::forward_as_tuple(code), - std::forward_as_tuple(private_ctor_t{}, code, prompt)); + std::forward_as_tuple(menu_t::private_ctor_t{}, code, prompt)); last = iter; } } } -int Menu::display_stub(int idx) { - static std::deque<const Menu *> st; +void insert(const char *code, callback_f callback) { + free_lookup.emplace(code, callback); +} + +int dynamic(const char *code, display_f display) { + menu::display_stub_default = code; + menu::display = display; + return display_stub(-1); +} + +int display_stub(int idx) { + static std::deque<const menu_t *> st; const std::string &code = !st.empty() ? st.back()->getCode(idx) : display_stub_default; const auto ml_it = menu_lookup.find(code); if (ml_it != menu_lookup.end()) { - const Menu &menu = ml_it->second; - st.push_back(&menu); - int ret = display(menu.title.c_str(), menu.getItemv(), menu.getSize()); + const auto &m = ml_it->second; + + st.push_back(&m); + int ret = display(m.getTitle().c_str(), m.getItemv(), m.getSize()); st.pop_back(); + return ret; } @@ -80,4 +72,14 @@ int Menu::display_stub(int idx) { return 1; } +void menu_t::insert(const std::string &code, const std::string &prompt, + callback_f callback) { + char *buffer = new char[prompt.size() + 1]; + strcpy(buffer, prompt.c_str()); + + items.emplace_back(callback, buffer); + codes.emplace_back(code, prompt); +} + +} // namespace menu } // namespace stamen diff --git a/src/stamen.cpp b/src/stamen.cpp @@ -9,16 +9,6 @@ namespace stamen { -void read(const char *filename) { Menu::read(filename); } - -void insert(const char *code, callback_f callback) { - Menu::insert(code, callback); -} - -int dynamic(const char *code, display_f display) { - return Menu::dynamic(code, display); -} - int builtin_display(const char *title, const item_t itemv[], int size) { const auto items = std::span(itemv, size_t(size)); const size_t dgts = size_t(std::log10(size)) + 1;