stamenStatic 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);