commit ad4b84a3bae704a23f2a417764b1bf62270adfc6
parent 0ca7539acca2a05ac12c268598ee3cd1881515fc
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Sat, 2 Dec 2023 23:59:56 +0000
Restructure and improvements
* Restructure the project
* Remove redundancy
* Improve consistency
* Improve decomposition
* Target C and C++
Diffstat:
13 files changed, 147 insertions(+), 224 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(
Stamen
- VERSION 0.0.15
+ VERSION 0.0.16
DESCRIPTION "Static menu generator"
LANGUAGES C CXX
)
diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt
@@ -35,7 +35,7 @@ add_executable(cdemo
)
target_link_libraries(cdemo
- stamenc
+ stamen
)
add_custom_command(
diff --git a/demo/main.c b/demo/main.c
@@ -1,9 +1,11 @@
#include "demo_menu.h"
-#include "stamenc.h"
+#include "stamen.h"
#include <stdio.h>
#include <stdlib.h>
+// need to link against stamen library
+// in order to use stamen_builtin_display
const stamen_display_f stamen_display = stamen_builtin_display;
int operation1(void) {
@@ -29,11 +31,6 @@ int finish(void) {
exit(0);
}
-int menu_dynamic_print(void) {
- stamen_print("menu_main");
- return 1;
-}
-
int main(void) {
menu_main();
return 0;
diff --git a/demo/main.cpp b/demo/main.cpp
@@ -4,8 +4,8 @@
#include <iostream>
// need to link against stamen library
-// in order to use stamen::BuiltinDisplay
-const stamen_display_f stamen_display = stamen::builtinDisplay;
+// in order to use stamen_builtin_display
+const stamen_display_f stamen_display = stamen_builtin_display;
int operation1() {
std::cout << "operation 1" << std::endl;
@@ -31,6 +31,6 @@ int finish() {
}
int main() {
- stamen::menu_main();
+ menu_main();
return 0;
}
diff --git a/include/menu.h b/include/menu.h
@@ -0,0 +1,55 @@
+#ifndef STAMEN_MENU_H
+#define STAMEN_MENU_H
+
+#include "stamen.h"
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+class Menu {
+ struct private_ctor_t {};
+
+public:
+ using lookup_t = std::unordered_map<std::string, Menu>;
+ static lookup_t lookup;
+
+ static void read(const std::string &s);
+ static void print(const std::string &entry) { internal_print(entry, 1); }
+ static lookup_t &getLookup() { return lookup; }
+
+ Menu(const Menu &) = delete;
+ Menu &operator=(const Menu &) = delete;
+
+ // Tag type dispatch
+ Menu(private_ctor_t, const std::string &code, const std::string &prompt)
+ : Menu(code, prompt) {}
+
+ struct lookup_item_t {
+ const std::string code;
+ const std::string prompt;
+ };
+
+ [[nodiscard]] const std::string &getCode() const { return code; }
+ [[nodiscard]] const std::string &getTitle() const { return title; }
+ [[nodiscard]] const std::vector<lookup_item_t> &getItems() const {
+ return lookup_items;
+ }
+
+private:
+ Menu(std::string code, std::string prompt)
+ : code(std::move(code)), title(std::move(prompt)) {}
+
+ static const Menu *getMenu(const std::string &code) {
+ const auto it = lookup.find(code);
+ if (it == lookup.end()) return nullptr;
+ return &it->second;
+ }
+
+ static void internal_print(const std::string &entry, const int depth);
+
+ std::vector<lookup_item_t> lookup_items;
+ const std::string code, title;
+};
+
+#endif
diff --git a/include/shared.h b/include/shared.h
@@ -1,15 +0,0 @@
-#ifndef STAMEN_SHARED_H
-#define STAMEN_SHARED_H
-
-typedef int (*stamen_callback_f)(void);
-
-typedef struct item_t item_t;
-struct item_t {
- stamen_callback_f callback;
- const char *prompt;
-};
-
-typedef int (*stamen_display_f)(const char *, const item_t[], int);
-extern const stamen_display_f stamen_display;
-
-#endif
diff --git a/include/stamen.h b/include/stamen.h
@@ -1,120 +1,23 @@
-#ifndef STAMEN_H
-#define STAMEN_H
+#ifndef STAMEN_STAMEN_H
+#define STAMEN_STAMEN_H
-#include "shared.h"
-
-#include <exception>
-#include <format>
-#include <fstream>
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <tuple>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-namespace stamen {
-
-class Menu {
- struct private_ctor_t {};
-
-public:
- friend class Generator;
-
- using callback_f = stamen_callback_f;
- using display_f = stamen_display_f;
-
- Menu(const Menu &) = delete;
- Menu(Menu &&) = delete;
- Menu &operator=(const Menu &) = delete;
- Menu &operator=(Menu &&) = delete;
-
- // Tag type dispatch
- 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) {}
-
- static void read(const std::string &s);
- static void print(const std::string &entry) { internal_print(entry, 1); }
- static void insert(const std::string &code, const callback_f callback);
-
-private:
- Menu(std::string code, std::string prompt)
- : code(std::move(code)), title(std::move(prompt)) {}
-
- Menu(const std::string &code, const callback_f callback)
- : code(code), title(code), callback(callback) {}
-
- using lookup_t = std::unordered_map<std::string, Menu>;
- static lookup_t &getLookup() {
- static lookup_t lookup;
- return lookup;
- }
-
- static void internal_print(const std::string &entry, const int depth);
-
- static const Menu *getMenu(const std::string &code) {
- const static lookup_t &lookup = getLookup();
- const auto it = lookup.find(code);
- if (it == lookup.end()) return nullptr;
- return &it->second;
- }
+#ifdef __cplusplus
+#define EXTERNC extern "C"
+#else
+#define EXTERNC extern
+#endif
- const std::string code, title;
- const callback_f callback = nullptr;
+typedef int (*stamen_callback_f)(void);
- using lookup_item_t = std::pair<std::string, std::string>;
- std::vector<lookup_item_t> items;
+typedef struct item_t item_t;
+struct item_t {
+ stamen_callback_f callback;
+ const char *prompt;
};
-inline void Menu::read(const std::string &s) {
- std::string line, delim, code, prompt;
- std::fstream fs(s);
- char tmp = 0;
-
- lookup_t &lookup = getLookup();
- auto 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.emplace_back(code, prompt);
- }
- }
-}
-
-inline void Menu::insert(const std::string &code, const callback_f callback) {
- getLookup().emplace(std::piecewise_construct, std::forward_as_tuple(code),
- std::forward_as_tuple(private_ctor_t{}, code, callback));
-}
-
-inline void Menu::internal_print(const std::string &code, const int depth) {
- const Menu *menu = getMenu(code);
- if (!menu) return;
-
- if (depth == 1) std::cout << std::format("{}({})\n", menu->title, code);
-
- if (!menu->callback) {
- for (const auto &[code, prompt] : menu->items) {
- std::cout << std::format("{}{} ({})\n", std::string(depth << 1, ' '),
- prompt, code);
- menu->internal_print(code, depth + 1);
- }
- }
-}
-
-int builtinDisplay(const char *title, const ::item_t itemv[], int size);
+typedef int (*stamen_display_f)(const char *, const item_t[], int);
+extern const stamen_display_f stamen_display;
-} // namespace stamen
+EXTERNC int stamen_builtin_display(const char *title, const item_t itemv[], int size);
#endif
diff --git a/include/stamenc.h b/include/stamenc.h
@@ -1,17 +0,0 @@
-#ifndef CSTAMEN_H
-#define CSTAMEN_H
-
-#include "shared.h"
-
-#ifdef __cplusplus
-#define EXTERNC extern "C"
-#else
-#define EXTERNC extern
-#endif
-
-EXTERNC void stamen_read(const char *file);
-EXTERNC void stamen_print(const char *entry);
-EXTERNC void stamen_insert(const char *code, stamen_callback_f callback);
-EXTERNC int stamen_builtin_display(const char *title, const item_t itemv[], int size);
-
-#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
@@ -9,15 +9,12 @@ set_target_properties(stamen PROPERTIES
PUBLIC_HEADER ../include/stamen.h
)
-add_library(stamenc stamenc.cpp stamen.cpp)
-target_link_libraries(stamenc PUBLIC stamen-include)
-set_target_properties(stamenc PROPERTIES
- VERSION ${PROJECT_VERSION}
- SOVERSION ${PROJECT_VERSION_MAJOR}
- PUBLIC_HEADER ../include/stamenc.h
+install(TARGETS stamen
+ LIBRARY DESTINATION lib
+ PUBLIC_HEADER DESTINATION include
)
-add_executable(stamen-generate generate.cpp)
+add_executable(stamen-generate generate.cpp menu.cpp)
target_link_libraries(stamen-generate PRIVATE stamen-include)
target_include_directories(stamen-generate PUBLIC ../include)
@@ -27,10 +24,4 @@ set_target_properties(stamen-generate PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)
-
install(TARGETS stamen-generate DESTINATION bin)
-install(TARGETS stamen
- LIBRARY DESTINATION lib
- PUBLIC_HEADER DESTINATION include
-)
-
diff --git a/src/generate.cpp b/src/generate.cpp
@@ -1,60 +1,41 @@
-#include "stamen.h"
+#include "menu.h"
+#include <format>
+#include <fstream>
+#include <iostream>
#include <string>
-using namespace stamen;
-
-namespace stamen {
-
class Generator {
public:
- class EGenerate : std::exception {
- [[nodiscard]] const char *what() const noexcept override {
- return "Trying to access unknown code";
- }
- };
-
- static void generateInclude(std::ostream &os, bool cpp) {
+ static void generateInclude(std::ostream &os) {
os << "#ifndef STAMEN_MENU_H\n";
os << "#define STAMEN_MENU_H\n\n";
- if (cpp) os << "namespace stamen {\n\n";
- for (const auto &[code, _] : Menu::getLookup()) {
- const Menu *menu = Menu::getMenu(code);
- if (!menu) throw EGenerate();
- if (menu->callback) continue;
- os << std::format("int {}(void);\n", menu->code);
+ os << "#include <stamen.h>\n\n";
+ for (const auto &[code, menu] : Menu::getLookup()) {
+ os << std::format("int {}(void);\n", menu.getCode());
}
- if (cpp) os << "\n}\n";
os << "\n#endif\n";
}
- static void generateSource(std::ostream &os, bool cpp) {
- os << "#include <stamenc.h>\n";
+ static void generateSource(std::ostream &os) {
+ os << "#include <stamen.h>\n";
os << "#include \"shared.h\"\n\n";
- if (cpp) os << "namespace stamen {\n\n";
- for (const auto &[code, _] : Menu::getLookup()) {
- const Menu *menu = Menu::getMenu(code);
- if (!menu) throw EGenerate();
- if (menu->callback) continue;
-
- os << std::format("int {}(void) {{\n", menu->code);
+ for (const auto &[code, menu] : Menu::getLookup()) {
+ os << std::format("int {}(void) {{\n", menu.getCode());
os << std::format("\tstatic const item_t items[] = {{\n");
- for (const auto &[code, prompt] : menu->items) {
+ for (const auto &[code, prompt] : menu.getItems()) {
os << std::format("\t\t{{ {}, \"{}\" }},\n", code, prompt);
}
os << std::format("\t}};\n");
os << std::format("\treturn stamen_display(\"{}\", items, "
- "sizeof(items) / sizeof(item_t));\n",
- menu->title);
+ "sizeof(items) / sizeof(items[0]));\n",
+ menu.getTitle());
os << std::format("}}\n\n");
}
- if (cpp) os << "}\n";
}
};
-} // namespace stamen
-
int main(const int argc, const char *argv[]) {
const auto args = std::span(argv, size_t(argc));
@@ -73,8 +54,8 @@ int main(const int argc, const char *argv[]) {
std::string ext = cpp ? "pp" : "";
std::ofstream source(base + ".c" + ext), include(base + ".h" + ext);
- Generator::generateSource(source, cpp);
- Generator::generateInclude(include, cpp);
+ Generator::generateSource(source);
+ Generator::generateInclude(include);
return 0;
}
diff --git a/src/menu.cpp b/src/menu.cpp
@@ -0,0 +1,46 @@
+#include "menu.h"
+
+#include <format>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <tuple>
+#include <utility>
+
+Menu::lookup_t Menu::lookup;
+
+void Menu::read(const std::string &s) {
+ std::string line, delim, code, prompt;
+ std::fstream fs(s);
+ char tmp = 0;
+
+ lookup_t &lookup = getLookup();
+ auto 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.lookup_items.emplace_back(code, prompt);
+ }
+ }
+}
+
+void Menu::internal_print(const std::string &code, const int depth) {
+ const Menu *menu = getMenu(code);
+ if (!menu) return;
+
+ if (depth == 1) std::cout << std::format("{}({})\n", menu->title, code);
+
+ for (const auto &[code, prompt] : menu->lookup_items) {
+ std::cout << std::format("{}{} ({})\n", std::string(depth << 1, ' '),
+ prompt, code);
+ menu->internal_print(code, depth + 1);
+ }
+}
diff --git a/src/stamen.cpp b/src/stamen.cpp
@@ -1,13 +1,11 @@
-#include "../include/stamen.h"
+#include "stamen.h"
#include <cmath>
#include <format>
#include <iostream>
#include <ostream>
#include <variant>
-namespace stamen {
-
-int builtinDisplay(const char *title, const ::item_t itemv[], int size) {
+int stamen_builtin_display(const char *title, const ::item_t itemv[], int size) {
const size_t digits = size_t(std::log10(size)) + 1;
const auto items = std::span(itemv, size_t(size));
int choice = 0;
@@ -47,5 +45,3 @@ int builtinDisplay(const char *title, const ::item_t itemv[], int size) {
return 1;
}
-
-} // namespace stamen
diff --git a/src/stamenc.cpp b/src/stamenc.cpp
@@ -1,14 +0,0 @@
-#include "../include/stamenc.h"
-#include "../include/stamen.h"
-
-using namespace stamen;
-
-void stamen_read(const char *file) { stamen::Menu::read(file); }
-void stamen_print(const char *entry) { stamen::Menu::print(entry); }
-void stamen_insert(const char *code, stamen_callback_f callback) {
- Menu::insert(code, callback);
-}
-
-int stamen_builtin_display(const char *title, const item_t items[], int size) {
- return builtinDisplay(title, items, size);
-}