commit 26a75511cae93934528c2c3e09c1307d20086552
parent 77eabec835fddbe4e8d83608b538090d8de2c3cb
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Fri, 17 Nov 2023 02:22:39 +0000
Rebrand
* Rebrand project to stamen
* Add header guard to generated include file
* Fix bug where -1 would not go back
Diffstat:
11 files changed, 242 insertions(+), 239 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -2,9 +2,9 @@ cmake_minimum_required(VERSION 3.25.2)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(
- Menu
- VERSION 0.0.7
- DESCRIPTION "Experimentation with dinamic menus"
+ Stamen
+ VERSION 0.0.8
+ DESCRIPTION "Static menu generator"
LANGUAGES CXX
)
diff --git a/README.md b/README.md
@@ -107,7 +107,7 @@ will create source file and include file in the current directory with the name
as the configuration file but with extensions `.cpp` and `.h` respectively.
Include file will contain declarations for all of the menu functions inside
-`menu` namespace. You should include this file in your code.
+`stamen` namespace. You should include this file in your code.
Source file contains definitions for the menu functions. It also includes
`shared.h` file which should contain declarations for all of the free functions
diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt
@@ -4,13 +4,13 @@ add_executable(demo
)
target_link_libraries(demo
- menu
+ stamen
)
ADD_CUSTOM_COMMAND(
OUTPUT demo_menu.h demo_menu.cpp
- COMMAND ${CMAKE_BINARY_DIR}/bin/generate ${CMAKE_CURRENT_SOURCE_DIR}/demo_menu.conf
- DEPENDS demo_menu.conf generate
+ COMMAND ${CMAKE_BINARY_DIR}/bin/stamen-generate ${CMAKE_CURRENT_SOURCE_DIR}/demo_menu.conf
+ DEPENDS demo_menu.conf stamen-generate
COMMENT "Generating menu files"
)
diff --git a/demo/main.cpp b/demo/main.cpp
@@ -27,7 +27,7 @@ int finish(void) {
exit(0);
}
-int menu_static_run(void) { return menu::menu_main(); }
+int menu_static_run(void) { return stamen::menu_main(); }
int menu_dynamic_run(void) { return Menu::start("menu_main"); }
int menu_dynamic_print(void) {
diff --git a/demo/shared.h b/demo/shared.h
@@ -1,5 +1,5 @@
-#ifndef DEMO_SHARED_H
-#define DEMO_SHARED_H
+#ifndef STAMEN_DEMO_SHARED_H
+#define STAMEN_DEMO_SHARED_H
int finish(void);
int operation1(void);
diff --git a/include/menu.h b/include/menu.h
@@ -1,122 +0,0 @@
-#ifndef MENU_H
-#define MENU_H
-
-#include <exception>
-#include <format>
-#include <fstream>
-#include <iostream>
-#include <memory>
-#include <sstream>
-#include <string>
-#include <tuple>
-#include <unordered_map>
-#include <vector>
-
-class Menu {
- Menu(const Menu &) = delete;
- Menu &operator=(const Menu &) = delete;
-
- struct private_ctor_t {};
-
-public:
- typedef int (*callback_f)(void);
-
- Menu(private_ctor_t, const std::string &code, const std::string &prompt)
- : Menu(code, prompt) {}
-
- Menu(private_ctor_t, const std::string &code, const callback_f callback)
- : Menu(code, callback) {}
-
- class EMenu : std::exception {
- virtual const char *what() const noexcept override {
- return "Trying to access an unknown menu";
- }
- };
-
- struct item_t {
- friend class Menu;
-
- item_t(const callback_f func, const std::string &prompt)
- : callback(func), prompt(prompt) {}
-
- const std::string getPrompt(void) const { return prompt; }
- const callback_f getCallback(void) const { return callback; }
-
- int operator()(void) const {
- return callback ? callback() : getMenu(code)();
- }
-
- private:
- item_t(const std::string &code, const std::string &prompt)
- : code(code), prompt(prompt) {}
-
- const std::string prompt, code;
- const callback_f callback = nullptr;
- };
-
- static void read(const std::string &s) {
- std::string line, delim, code, prompt;
- std::fstream fs(s);
- char tmp;
-
- lookup_t::iterator last = lookup.end();
- while (std::getline(fs, line)) {
- if (line.empty()) continue;
- std::istringstream ss(line);
- ss >> delim >> code;
- ss.ignore(1, ' '), std::getline(ss, prompt);
- if (delim == "+") {
- const auto [iter, succ] = lookup.emplace(
- std::piecewise_construct, std::forward_as_tuple(code),
- std::forward_as_tuple(private_ctor_t{}, code, prompt));
- last = iter;
- } else {
- last->second.items.push_back({code, prompt});
- }
- }
- }
-
- static int start(const std::string &entry) { return getMenu(entry)(); }
- static void insert(const std::string &code, const callback_f callback) {
- lookup.emplace(std::piecewise_construct, std::forward_as_tuple(code),
- std::forward_as_tuple(private_ctor_t{}, code, callback));
- }
-
- static void print(const std::string &entry) { print(entry, 1); }
-
- static void generateSource(std::ostream &os);
- static void generateInclude(std::ostream &os);
-
- typedef int (*display_f)(const std::string &, const item_t[], std::size_t);
- static const display_f display;
- static int builtinDisplay(const std::string &title, const item_t items[],
- std::size_t size);
-
- int operator()() const {
- return callback ? callback() : display(title, items.data(), items.size());
- }
-
-private:
- Menu(const std::string &code, const std::string &prompt)
- : code(code), title(prompt) {}
-
- Menu(const std::string &code, const callback_f callback)
- : code(code), title(code), callback(callback) {}
-
- typedef std::unordered_map<std::string, Menu> lookup_t;
- static lookup_t lookup;
-
- static void print(const std::string &entry, const int depth);
-
- static const Menu &getMenu(const std::string &code) {
- const auto it = lookup.find(code);
- if (it == lookup.end()) throw EMenu();
- return it->second;
- }
-
- const std::string code, title;
- const callback_f callback = nullptr;
- std::vector<item_t> items;
-};
-
-#endif
diff --git a/include/stamen.h b/include/stamen.h
@@ -0,0 +1,122 @@
+#ifndef STAMEN_H
+#define STAMEN_H
+
+#include <exception>
+#include <format>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <tuple>
+#include <unordered_map>
+#include <vector>
+
+class Menu {
+ Menu(const Menu &) = delete;
+ Menu &operator=(const Menu &) = delete;
+
+ struct private_ctor_t {};
+
+public:
+ typedef int (*callback_f)(void);
+
+ Menu(private_ctor_t, const std::string &code, const std::string &prompt)
+ : Menu(code, prompt) {}
+
+ Menu(private_ctor_t, const std::string &code, const callback_f callback)
+ : Menu(code, callback) {}
+
+ class EMenu : std::exception {
+ virtual const char *what() const noexcept override {
+ return "Trying to access an unknown menu";
+ }
+ };
+
+ struct item_t {
+ friend class Menu;
+
+ item_t(const callback_f func, const std::string &prompt)
+ : callback(func), prompt(prompt) {}
+
+ const std::string getPrompt(void) const { return prompt; }
+ const callback_f getCallback(void) const { return callback; }
+
+ int operator()(void) const {
+ return callback ? callback() : getMenu(code)();
+ }
+
+ private:
+ item_t(const std::string &code, const std::string &prompt)
+ : code(code), prompt(prompt) {}
+
+ const std::string prompt, code;
+ const callback_f callback = nullptr;
+ };
+
+ static void read(const std::string &s) {
+ std::string line, delim, code, prompt;
+ std::fstream fs(s);
+ char tmp;
+
+ lookup_t::iterator last = lookup.end();
+ while (std::getline(fs, line)) {
+ if (line.empty()) continue;
+ std::istringstream ss(line);
+ ss >> delim >> code;
+ ss.ignore(1, ' '), std::getline(ss, prompt);
+ if (delim == "+") {
+ const auto [iter, succ] = lookup.emplace(
+ std::piecewise_construct, std::forward_as_tuple(code),
+ std::forward_as_tuple(private_ctor_t{}, code, prompt));
+ last = iter;
+ } else {
+ last->second.items.push_back({code, prompt});
+ }
+ }
+ }
+
+ static int start(const std::string &entry) { return getMenu(entry)(); }
+ static void insert(const std::string &code, const callback_f callback) {
+ lookup.emplace(std::piecewise_construct, std::forward_as_tuple(code),
+ std::forward_as_tuple(private_ctor_t{}, code, callback));
+ }
+
+ static void print(const std::string &entry) { print(entry, 1); }
+
+ static void generateSource(std::ostream &os);
+ static void generateInclude(std::ostream &os);
+
+ typedef int (*display_f)(const std::string &, const item_t[], std::size_t);
+ static const display_f display;
+ static int builtinDisplay(const std::string &title, const item_t items[],
+ std::size_t size);
+
+ int operator()() const {
+ return callback ? callback() : display(title, items.data(), items.size());
+ }
+
+private:
+ Menu(const std::string &code, const std::string &prompt)
+ : code(code), title(prompt) {}
+
+ Menu(const std::string &code, const callback_f callback)
+ : code(code), title(code), callback(callback) {}
+
+ typedef std::unordered_map<std::string, Menu> lookup_t;
+ static lookup_t lookup;
+
+ static void print(const std::string &entry, const int depth);
+
+ static const Menu &getMenu(const std::string &code) {
+ const auto it = lookup.find(code);
+ if (it == lookup.end()) throw EMenu();
+ return it->second;
+ }
+
+ const std::string code, title;
+ const callback_f callback = nullptr;
+ std::vector<item_t> items;
+};
+
+#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
@@ -1,22 +1,22 @@
-add_library(menu
- menu.cpp
+add_library(stamen
+ stamen.cpp
)
-target_include_directories(menu
+target_include_directories(stamen
PUBLIC ../include
)
-add_executable(generate generate.cpp)
+add_executable(stamen-generate generate.cpp)
-target_link_libraries(generate
- PRIVATE menu
+target_link_libraries(stamen-generate
+ PRIVATE stamen
)
-target_include_directories(generate
+target_include_directories(stamen-generate
PUBLIC ../include
)
-set_target_properties(generate PROPERTIES
+set_target_properties(stamen-generate PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
diff --git a/src/generate.cpp b/src/generate.cpp
@@ -1,4 +1,4 @@
-#include "menu.h"
+#include "stamen.h"
#include <string>
const Menu::display_f Menu::display = Menu::builtinDisplay;
diff --git a/src/menu.cpp b/src/menu.cpp
@@ -1,98 +0,0 @@
-#include "../include/menu.h"
-#include <cmath>
-#include <format>
-#include <fstream>
-#include <iostream>
-#include <ostream>
-#include <stack>
-#include <unordered_set>
-
-std::unordered_map<std::string, Menu> Menu::lookup;
-
-int Menu::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());
- }
-
- while (true) {
- std::cout << "Choose an option: ";
- if (std::cin >> choice && choice >= -1 && choice < size) {
- if (choice == -1) {
- std::cout << "Choice: back\n";
- return 1;
- }
-
- const item_t &chosen = items[choice];
- std::cout << std::format("Choice: {}\n\n", chosen.getPrompt());
- const int res = chosen();
- if (res > 1) return res - 1;
-
- break;
- } else if (std::cin.eof()) {
- std::cerr << "encountered end of input!\n";
- return std::numeric_limits<int>::max();
- } else {
- std::cin.clear();
- std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
- }
- std::cout << "Invalid option, please choose again!\n";
- }
- std::cout << std::endl;
- }
-
- return 1;
-}
-
-void Menu::generateInclude(std::ostream &os) {
- os << "#include \"menu.h\"\n\n";
- os << "namespace menu {\n\n";
- for (const auto &[code, _] : lookup) {
- const Menu &menu = getMenu(code);
- if (menu.callback) continue;
- os << std::format("int {}(void);\n", menu.code);
- }
- os << "\n}\n";
-}
-
-void Menu::generateSource(std::ostream &os) {
- os << "#include \"menu.h\"\n";
- os << "#include \"shared.h\"\n";
- os << "\nnamespace menu {\n";
- for (const auto &[code, _] : lookup) {
- const Menu &menu = getMenu(code);
- if (menu.callback) continue;
-
- os << std::format("int {}(void) {{\n", menu.code);
- os << std::format("\tstatic const Menu::item_t items[] = {{\n");
- for (const auto &item : menu.items) {
- os << std::format("\t\t{{{}, \"{}\"}},\n", item.code, item.prompt);
- }
- os << std::format("\t}};\n");
- os << std::format("\treturn Menu::display(\"{}\", items, "
- "sizeof(items) / sizeof(Menu::item_t));\n",
- menu.title);
- os << std::format("}}\n\n");
- }
- os << "\n}\n";
-}
-
-void Menu::print(const std::string &code, const int depth) {
- const auto it = lookup.find(code);
- if (it == lookup.end()) return;
- const Menu &menu = it->second;
-
- if (depth == 1) std::cout << std::format("{}({})\n", menu.title, code);
-
- if (!menu.callback) {
- for (const auto &item : menu.items) {
- std::cout << std::format("{}{}({})\n", std::string(depth << 1, ' '),
- item.prompt, item.code);
- menu.print(item.code, depth + 1);
- }
- }
-}
diff --git a/src/stamen.cpp b/src/stamen.cpp
@@ -0,0 +1,101 @@
+#include "../include/stamen.h"
+#include <cmath>
+#include <format>
+#include <fstream>
+#include <iostream>
+#include <ostream>
+#include <stack>
+#include <unordered_set>
+
+std::unordered_map<std::string, Menu> Menu::lookup;
+
+int Menu::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());
+ }
+
+ while (true) {
+ std::cout << "Choose an option: ";
+ if (std::cin >> choice && choice >= -1 && choice < (int)size) {
+ if (choice == -1) {
+ std::cout << "Choice: back\n";
+ return 1;
+ }
+
+ const item_t &chosen = items[choice];
+ std::cout << std::format("Choice: {}\n\n", chosen.getPrompt());
+ const int res = chosen();
+ if (res > 1) return res - 1;
+
+ break;
+ } else if (std::cin.eof()) {
+ std::cerr << "encountered end of input!\n";
+ return std::numeric_limits<int>::max();
+ } else {
+ std::cin.clear();
+ std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
+ }
+ std::cout << "Invalid option, please choose again!\n";
+ }
+ std::cout << std::endl;
+ }
+
+ return 1;
+}
+
+void Menu::generateInclude(std::ostream &os) {
+ os << "#ifndef STAMEN_MENU_H\n";
+ os << "#define STAMEN_MENU_H\n\n";
+ os << "#include <stamen.h>\n\n";
+ os << "namespace stamen {\n\n";
+ for (const auto &[code, _] : lookup) {
+ const Menu &menu = getMenu(code);
+ if (menu.callback) continue;
+ os << std::format("int {}(void);\n", menu.code);
+ }
+ os << "\n}\n";
+ os << "#endif\n";
+}
+
+void Menu::generateSource(std::ostream &os) {
+ os << "#include <stamen.h>\n";
+ os << "#include \"shared.h\"\n";
+ os << "\nnamespace stamen {\n";
+ for (const auto &[code, _] : lookup) {
+ const Menu &menu = getMenu(code);
+ if (menu.callback) continue;
+
+ os << std::format("int {}(void) {{\n", menu.code);
+ os << std::format("\tstatic const Menu::item_t items[] = {{\n");
+ for (const auto &item : menu.items) {
+ os << std::format("\t\t{{{}, \"{}\"}},\n", item.code, item.prompt);
+ }
+ os << std::format("\t}};\n");
+ os << std::format("\treturn Menu::display(\"{}\", items, "
+ "sizeof(items) / sizeof(Menu::item_t));\n",
+ menu.title);
+ os << std::format("}}\n\n");
+ }
+ os << "\n}\n";
+}
+
+void Menu::print(const std::string &code, const int depth) {
+ const auto it = lookup.find(code);
+ if (it == lookup.end()) return;
+ const Menu &menu = it->second;
+
+ if (depth == 1) std::cout << std::format("{}({})\n", menu.title, code);
+
+ if (!menu.callback) {
+ for (const auto &item : menu.items) {
+ std::cout << std::format("{}{}({})\n", std::string(depth << 1, ' '),
+ item.prompt, item.code);
+ menu.print(item.code, depth + 1);
+ }
+ }
+}