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