stamen

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

commit 08ff305c12bb4a7f9cc10610f51616b096647aa6
parent f4fed18ad7916907f96caaa641143d3ed00f02f6
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Thu, 30 Nov 2023 19:11:48 +0000

Great simplification

* Remove option for creating dynamic menus
* Greatly simplify handling and future extensions
* Simplify C interface
* Get rid of hacky array conversion
* Simplify demo programs

Diffstat:
MCMakeLists.txt | 2+-
Mdemo/main.c | 31+++----------------------------
Mdemo/main.cpp | 34+++++-----------------------------
Minclude/stamen.h | 45++++++++++++---------------------------------
Minclude/stamenc.h | 1-
Msrc/generate.cpp | 13+++++--------
Msrc/stamen.cpp | 17++++++++++-------
Msrc/stamenc.cpp | 11++---------
8 files changed, 38 insertions(+), 116 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) project( Stamen - VERSION 0.0.12 + VERSION 0.0.13 DESCRIPTION "Static menu generator" LANGUAGES C CXX ) diff --git a/demo/main.c b/demo/main.c @@ -1,8 +1,8 @@ #include "demo_menu.h" #include "stamenc.h" + #include <stdio.h> #include <stdlib.h> -#include <string.h> const display_f display = stamen_builtin_display; @@ -29,37 +29,12 @@ int finish(void) { exit(0); } -int menu_static_run(void) { return menu_main(); } -int menu_dynamic_run(void) { return stamen_start("menu_main"); } - int menu_dynamic_print(void) { stamen_print("menu_main"); return 1; } -int main(int argc, const char *argv[]) { - const char *filename = "./demo_menu.conf"; - char buffer[FILENAME_MAX] = {0}; - const char *sep = strrchr(argv[0], '/'); - if (sep) { - const size_t size = sep - argv[0] + 1; - memcpy(buffer, argv[0], size); - memcpy(buffer + size, filename, strlen(filename)); - } - - stamen_read(sep ? buffer : filename); - stamen_insert("finish", finish); - stamen_insert("operation1", operation1); - stamen_insert("operation2", operation2); - stamen_insert("operation3", operation3); - - static const item_t items[] = { - { menu_static_run, "Run statically generated menu"}, - { menu_dynamic_run, "Run dynamic menu"}, - {menu_dynamic_print, "Print dynamic menu"}, - { finish, "Quit"}, - }; - display("Menu demo program", items, sizeof(items) / sizeof(item_t)); - +int main(void) { + menu_main(); return 0; } diff --git a/demo/main.cpp b/demo/main.cpp @@ -1,6 +1,7 @@ -#include <iostream> - #include "demo_menu.hpp" +#include "stamen.h" + +#include <iostream> using stamen::Menu; @@ -31,32 +32,7 @@ int finish(void) { exit(0); } -int menu_static_run(void) { return stamen::menu_main(); } -int menu_dynamic_run(void) { return Menu::start("menu_main"); } - -int menu_dynamic_print(void) { - Menu::print("menu_main"); - return 1; -} - -int main(int argc, const char *argv[]) { - std::string name(argv[0]); - std::string::size_type pos = name.rfind('/'); - std::string base = pos != std::string::npos ? name.substr(0, pos) : "."; - - Menu::read(base + "/demo_menu.conf"); - Menu::insert("finish", finish); - Menu::insert("operation1", operation1); - Menu::insert("operation2", operation2); - Menu::insert("operation3", operation3); - - static const Menu::item_t items[] = { - { menu_static_run, "Run statically generated menu"}, - { menu_dynamic_run, "Run dynamic menu"}, - {menu_dynamic_print, "Print dynamic menu"}, - { finish, "Quit"}, - }; - Menu::display("Menu demo program", items, - sizeof(items) / sizeof(Menu::item_t)); +int main(void) { + stamen::menu_main(); return 0; } diff --git a/include/stamen.h b/include/stamen.h @@ -32,41 +32,13 @@ public: Menu(private_ctor_t, const std::string &code, const callback_f callback) : Menu(code, callback) {} - struct item_t { - item_t() {} - item_t(const callback_f func, const std::string &prompt) - : callback(func), prompt(prompt) {} - - item_t(const std::string &code, const std::string &prompt) - : code(code), prompt(prompt) {} - - const std::string getCode(void) const { return code; } - const std::string getPrompt(void) const { return prompt; } - const callback_f getCallback(void) const { return callback; } - - int operator()(void) const { return callback ? callback() : start(code); } - - private: - std::string prompt, code; - callback_f callback = nullptr; - }; - - typedef int (*display_f)(const std::string &, const item_t[], std::size_t); + typedef int (*display_f)(const std::string &, const ::item_t[], std::size_t); static const display_f display; static void read(const std::string &s); static void insert(const std::string &code, const callback_f callback); static void print(const std::string &entry) { print(entry, 1); } - static int start(const std::string &entry) { - const Menu *menu = getMenu(entry); - if (!menu) return 1; - return menu->operator()(); - } - - int operator()() const { - return callback ? callback() : display(title, items.data(), items.size()); - } private: Menu(const std::string &code, const std::string &prompt) @@ -92,7 +64,14 @@ private: const std::string code, title; const callback_f callback = nullptr; - std::vector<item_t> items; + + struct lookup_item_t { + lookup_item_t(const std::string &code, const std::string &prompt) + : code(code), prompt(prompt) {} + const std::string code, prompt; + }; + + std::vector<lookup_item_t> items; }; inline void Menu::read(const std::string &s) { @@ -132,13 +111,13 @@ inline void Menu::print(const std::string &code, const int depth) { if (!menu->callback) { for (const auto &item : menu->items) { std::cout << std::format("{}{} ({})\n", std::string(depth << 1, ' '), - item.getPrompt(), item.getCode()); - menu->print(item.getCode(), depth + 1); + item.prompt, item.code); + menu->print(item.code, depth + 1); } } } -int builtinDisplay(const std::string &title, const Menu::item_t items[], +int builtinDisplay(const std::string &title, const ::item_t items[], std::size_t size); } // namespace stamen diff --git a/include/stamenc.h b/include/stamenc.h @@ -20,7 +20,6 @@ extern const display_f display; EXTERNC void stamen_read(const char *file); EXTERNC void stamen_print(const char *entry); -EXTERNC int stamen_start(const char *entry); EXTERNC void stamen_insert(const char *code, callback_f callback); EXTERNC int stamen_builtin_display(const char *title, const item_t items[], int size); diff --git a/src/generate.cpp b/src/generate.cpp @@ -16,7 +16,6 @@ public: static void generateInclude(std::ostream &os, bool cpp) { os << "#ifndef STAMEN_MENU_H\n"; os << "#define STAMEN_MENU_H\n\n"; - os << std::format("#include <stamen{}.h>\n\n", !cpp ? "c" : ""); if (cpp) os << "namespace stamen {\n\n"; for (const auto &[code, _] : Menu::getLookup()) { const Menu *menu = Menu::getMenu(code); @@ -25,7 +24,7 @@ public: os << std::format("int {}(void);\n", menu->code); } if (cpp) os << "\n}\n"; - os << "#endif\n"; + os << "\n#endif\n"; } static void generateSource(std::ostream &os, bool cpp) { @@ -38,15 +37,13 @@ public: if (menu->callback) continue; os << std::format("int {}(void) {{\n", menu->code); - os << std::format("\tstatic const {}item_t items[] = {{\n", - cpp ? "Menu::" : ""); + os << std::format("\tstatic const item_t items[] = {{\n"); for (const auto &item : menu->items) { - os << std::format("\t\t{{ {}, \"{}\" }},\n", item.getCode(), - item.getPrompt()); + os << std::format("\t\t{{ {}, \"{}\" }},\n", item.code, item.prompt); } os << std::format("\t}};\n"); - os << std::format("\treturn {0}display(\"{1}\", items, " - "sizeof(items) / sizeof({0}item_t));\n", + os << std::format("\treturn {}display(\"{}\", items, " + "sizeof(items) / sizeof(item_t));\n", cpp ? "Menu::" : "", menu->title); os << std::format("}}\n\n"); } diff --git a/src/stamen.cpp b/src/stamen.cpp @@ -3,17 +3,19 @@ #include <format> #include <iostream> #include <ostream> +#include <variant> namespace stamen { -int builtinDisplay(const std::string &title, const Menu::item_t items[], +int builtinDisplay(const std::string &title, const ::item_t items[], std::size_t size) { int choice; const int digits = std::log10(size) + 1; + while (true) { std::cout << std::format("{}:\n", title); for (auto i = 0ul; i < size; i++) { - std::cout << std::format(" {:{}}. {}\n", i, digits, items[i].getPrompt()); + std::cout << std::format(" {:{}}. {}\n", i, digits, items[i].prompt); } while (true) { @@ -24,11 +26,12 @@ int builtinDisplay(const std::string &title, const Menu::item_t items[], return 1; } - const Menu::item_t &chosen = items[choice]; - std::cout << std::format("Choice: {}\n\n", chosen.getPrompt()); - const int res = chosen(); - if (res > 1) return res - 1; - else break; + std::cout << std::format("Choice: {}\n\n", items[choice].prompt); + const int res = items[choice].callback(); + if (res > 1) + return res - 1; + else + break; } else if (std::cin.eof()) { std::cerr << "encountered end of input!\n"; diff --git a/src/stamenc.cpp b/src/stamenc.cpp @@ -1,4 +1,5 @@ #include "../include/stamen.h" +#include "../include/stamenc.h" using namespace stamen; @@ -6,18 +7,10 @@ const Menu::display_f Menu::display = nullptr; void stamen_read(const char *file) { stamen::Menu::read(file); } void stamen_print(const char *entry) { stamen::Menu::print(entry); } -int stamen_start(const char *entry) { return stamen::Menu::start(entry); } void stamen_insert(const char *code, callback_f callback) { Menu::insert(code, callback); } int stamen_builtin_display(const char *title, const item_t items[], int size) { - Menu::item_t *litems = new Menu::item_t[size]; - if (!litems) return -1; - for (int i = 0; i < size; i++) { - litems[i] = Menu::item_t(items[i].callback, items[i].prompt); - } - const int ret = builtinDisplay(title, litems, size); - delete[] litems; - return ret; + return builtinDisplay(title, items, size); }