stamen

Static Menu Generator
git clone git://git.dimitrijedobrota.com/stamen.git
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING

commit 075d692948c0933690afdb61764047bf3e00466f
parent ca36d15bfaaa0846e70bb0ad32da1fc11c1d8fef
author Dimitrije Dobrota <mail@dimitrijedobrota.com>
date Wed, 6 Dec 2023 20:08:29 +0000

Error fixing and new C++ namespace bindings * C++ stamen namespace for improved consistency * Ability to start dynamic menu from custom panel * Fix memory leak in Menu::Enries * Removed redundancy * Update README

Diffstat:
M CMakeLists.txt | + -
M README.md | ++++++++++++++++++++++ -
M demo/dynamic.cpp | +++++++++++++ --------
M demo/main.cpp | + -
M include/menu.h | +++++++++++++ ----------
M include/stamen.h | +++++++++++++++ -
M src/generate.cpp | ++++++
M src/menu.cpp | +++++++++++ ----
M src/stamen.cpp | +++ -

9 files changed, 85 insertions(+), 27 deletions(-)


diff --git a/ CMakeLists.txt b/ CMakeLists.txt

@@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) project( Stamen
VERSION 0.0.18
VERSION 0.0.19
DESCRIPTION "Static menu generator" LANGUAGES C CXX )

diff --git a/ README.md b/ README.md

@@ -75,6 +75,8 @@ Please reference demo folder for relevant usage example. There are a few things needed before you begin.
* All types and functions with prefix stamen_ are also available in namespace
stamen:: in C++ for easier use.
* Panel and item codes must be one word. In addition they must be valid C/C++ function names if static menu is to be build correctly. * Each free function must have `int name(int)` signature as prescribed by

@@ -125,7 +127,7 @@ terminates, but you can use in any way you see fit. #### Dynamic menu In dynamic mode, configuration file is read every time the program is run. In
order to invoke the menu you need to add the following code to your C/C++
order to invoke the menu you need to add the following snippet to your C
program: ```

@@ -144,6 +146,25 @@ stamen_insert("free function code", some_free_function); stamen_dynamic("panel code"); ```
For C++ there is a namespaced version of the functions:
```
#include <stamen.h>
const stamen::display_f stamen_display = stamen::builtin_display;
// read the configuration
stamen::read("path to config");
// register free functions
stamen::insert("free function code", some_free_function);
...
// start the menu on specific panel
stamen::dynamic("panel code");
```
`
## Version History * 1.0

diff --git a/ demo/dynamic.cpp b/ demo/dynamic.cpp

@@ -1,7 +1,7 @@
#include <stamen.h>
#include <iostream>
#include <stamen.h>
const stamen_display_f stamen_display = stamen_builtin_display;
const stamen::display_f stamen_display = stamen::builtin_display;
int finish(int) { exit(1); }

@@ -21,11 +21,16 @@ int operation3(int) { } int main() {
stamen_read("./bin/demo_menu.conf");
stamen_insert("finish", finish);
stamen_insert("operation1", operation1);
stamen_insert("operation2", operation2);
stamen_insert("operation3", operation3);
stamen_dynamic();
// read the configuration
stamen::read("./bin/demo_menu.conf");
// register free functions
stamen::insert("finish", finish);
stamen::insert("operation1", operation1);
stamen::insert("operation2", operation2);
stamen::insert("operation3", operation3);
// start the menu on specific panel
stamen::dynamic("menu_main");
return 0; }

diff --git a/ demo/main.cpp b/ demo/main.cpp

@@ -5,7 +5,7 @@ // need to link against stamen library // in order to use stamen_builtin_display
const stamen_display_f stamen_display = stamen_builtin_display;
const stamen::display_f stamen_display = stamen::builtin_display;
int operation1(int) { std::cout << "operation 1" << std::endl;

diff --git a/ include/menu.h b/ include/menu.h

@@ -9,14 +9,14 @@ #include <unordered_map> #include <vector>
namespace stamen {
class Menu { friend class Generator;
using callback_f = stamen_callback_f;
using item_t = stamen_item_t;
static std::unordered_map<std::string, Menu> menu_lookup; static std::unordered_map<std::string, callback_f> free_lookup;
static std::string display_stub_default;
struct private_ctor_t {};

@@ -28,7 +28,10 @@ public: Menu(const Menu &) = delete; Menu &operator=(const Menu &) = delete;
static int dynamic() { return display_stub(-1); };
static int dynamic(const std::string &code) {
display_stub_default = code;
return display_stub(-1);
};
static void read(const std::string &s); static void print(const std::string &entry) { print(entry, 1); } static void insert(const std::string &s, callback_f callback) {

@@ -60,18 +63,16 @@ private: static void print(const std::string &entry, const int depth); static int display_stub(int idx);
static const Menu *getMenu(const std::string &code) {
const auto it = menu_lookup.find(code);
if (it == menu_lookup.end()) return nullptr;
return &it->second;
}
struct Entries { struct code_t { const std::string code; const std::string prompt; };
~Entries() {
for (const auto [_, prompt] : items) delete[] prompt;
}
std::vector<code_t> codes; std::vector<item_t> items;

@@ -89,4 +90,6 @@ private: Entries entries; };
} // namespace stamen
#endif

diff --git a/ include/stamen.h b/ include/stamen.h

@@ -18,11 +18,25 @@ struct stamen_item_t { typedef int (*stamen_display_f)(const char *, const stamen_item_t[], int); extern const stamen_display_f stamen_display;
EXTERNC int stamen_dynamic(void);
EXTERNC int stamen_dynamic(const char *code);
EXTERNC void stamen_read(const char *filename); EXTERNC void stamen_insert(const char *code, stamen_callback_f callback); EXTERNC int stamen_builtin_display(const char *title, const stamen_item_t itemv[], int size);
#ifdef __cplusplus
namespace stamen {
using callback_f = stamen_callback_f;
using display_f = stamen_display_f;
using item_t = stamen_item_t;
const auto dynamic = stamen_dynamic;
const auto read = stamen_read;
const auto insert = stamen_insert;
const auto builtin_display = stamen_builtin_display;
} // namespace stamen
#endif
#endif

diff --git a/ src/generate.cpp b/ src/generate.cpp

@@ -6,6 +6,8 @@ #include <iostream> #include <string>
namespace stamen {
class Generator { public: static void generateInclude(std::ostream &os) {

@@ -39,6 +41,10 @@ public: } };
} // namespace stamen
using namespace stamen;
int main(const int argc, const char *argv[]) { const auto args = std::span(argv, size_t(argc));

diff --git a/ src/menu.cpp b/ src/menu.cpp

@@ -9,8 +9,11 @@ #include <tuple> #include <utility>
namespace stamen {
std::unordered_map<std::string, Menu> Menu::menu_lookup;
std::unordered_map<std::string, Menu::callback_f> Menu::free_lookup;
std::unordered_map<std::string, callback_f> Menu::free_lookup;
std::string Menu::display_stub_default;
void Menu::read(const std::string &s) { std::string line, delim, code, prompt;

@@ -35,8 +38,9 @@ void Menu::read(const std::string &s) { } void Menu::print(const std::string &code, const int depth) {
const Menu *menu = getMenu(code);
if (!menu) return;
const auto it = menu_lookup.find(code);
if (it == menu_lookup.end()) return;
const Menu *menu = &it->second;
if (depth == 1) std::cout << std::format("{}({})\n", menu->title, code);

@@ -50,7 +54,8 @@ void Menu::print(const std::string &code, const int depth) { int Menu::display_stub(int idx) { static std::deque<const Menu *> st;
const std::string &code = st.size() ? st.back()->getCode(idx) : "menu_main";
const std::string &code =
st.size() ? st.back()->getCode(idx) : display_stub_default;
const auto ml_it = menu_lookup.find(code); if (ml_it != menu_lookup.end()) {

@@ -68,3 +73,5 @@ int Menu::display_stub(int idx) { std::cout << "Stamen: nothing to do..." << std::endl; return 1; }
} // namespace stamen

diff --git a/ src/stamen.cpp b/ src/stamen.cpp

@@ -7,7 +7,9 @@ #include <ostream> #include <variant>
int stamen_dynamic(void) { return Menu::dynamic(); }
using namespace stamen;
int stamen_dynamic(const char *code) { return Menu::dynamic(code); }
void stamen_read(const char *filename) { Menu::read(filename); } void stamen_insert(const char *code, stamen_callback_f callback) { Menu::insert(code, callback);