stamenStatic Menu Generator | 
          
| git clone git://git.dimitrijedobrota.com/stamen.git | 
| Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING | 
| commit | 08ff305c12bb4a7f9cc10610f51616b096647aa6 | 
| parent | f4fed18ad7916907f96caaa641143d3ed00f02f6 | 
| author | Dimitrije Dobrota < mail@dimitrijedobrota.com > | 
| date | Thu, 30 Nov 2023 19:11:48 +0000 | 
Great simplification
* Remove option for creating dynamic menus
* Greatly simplify handling and future extensions
* Simplify C interface
* Get rid of hacky array conversion
* Simplify demo programs
| M | CMakeLists.txt | | | + - | 
| M | demo/main.c | | | +++ ---------------------------- | 
| M | demo/main.cpp | | | +++++ ----------------------------- | 
| M | include/stamen.h | | | ++++++++++++ --------------------------------- | 
| M | include/stamenc.h | | | - | 
| M | src/generate.cpp | | | +++++ -------- | 
| M | src/stamen.cpp | | | ++++++++++ ------- | 
| M | src/stamenc.cpp | | | ++ --------- | 
8 files changed, 38 insertions(+), 116 deletions(-)
diff --git a/ CMakeLists.txt b/ CMakeLists.txt
          @@ -3,7 +3,7 @@ 
          set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
        
        
          project(
              Stamen
              VERSION 0.0.12
              VERSION 0.0.13
              DESCRIPTION "Static menu generator"
              LANGUAGES C CXX
          )
        
        diff --git a/ demo/main.c b/ demo/main.c
@@ -1,8 +1,8 @@
#include "demo_menu.h"
          #include "stamenc.h"
          #include <stdio.h>
          #include <stdlib.h>
          #include <string.h>
          const display_f display = stamen_builtin_display;
          
          @@ -29,37 +29,12 @@ 
          int finish(void) {
        
        
            exit(0);
          }
          int menu_static_run(void) { return menu_main(); }
          int menu_dynamic_run(void) { return stamen_start("menu_main"); }
          int menu_dynamic_print(void) {
            stamen_print("menu_main");
            return 1;
          }
          int main(int argc, const char *argv[]) {
            const char *filename = "./demo_menu.conf";
            char buffer[FILENAME_MAX] = {0};
            const char *sep = strrchr(argv[0], '/');
            if (sep) {
              const size_t size = sep - argv[0] + 1;
              memcpy(buffer, argv[0], size);
              memcpy(buffer + size, filename, strlen(filename));
            }
            stamen_read(sep ? buffer : filename);
            stamen_insert("finish", finish);
            stamen_insert("operation1", operation1);
            stamen_insert("operation2", operation2);
            stamen_insert("operation3", operation3);
            static const item_t items[] = {
                {   menu_static_run, "Run statically generated menu"},
                {  menu_dynamic_run,              "Run dynamic menu"},
                {menu_dynamic_print,            "Print dynamic menu"},
                {            finish,                          "Quit"},
            };
            display("Menu demo program", items, sizeof(items) / sizeof(item_t));
          int main(void) {
            menu_main();
            return 0;
          }
        
        diff --git a/ demo/main.cpp b/ demo/main.cpp
@@ -1,6 +1,7 @@
#include <iostream>
          #include "demo_menu.hpp"
          #include "stamen.h"
          #include <iostream>
          using stamen::Menu;
          
          @@ -31,32 +32,7 @@ 
          int finish(void) {
        
        
            exit(0);
          }
          int menu_static_run(void) { return stamen::menu_main(); }
          int menu_dynamic_run(void) { return Menu::start("menu_main"); }
          int menu_dynamic_print(void) {
            Menu::print("menu_main");
            return 1;
          }
          int main(int argc, const char *argv[]) {
            std::string name(argv[0]);
            std::string::size_type pos = name.rfind('/');
            std::string base = pos != std::string::npos ? name.substr(0, pos) : ".";
            Menu::read(base + "/demo_menu.conf");
            Menu::insert("finish", finish);
            Menu::insert("operation1", operation1);
            Menu::insert("operation2", operation2);
            Menu::insert("operation3", operation3);
            static const Menu::item_t items[] = {
                {   menu_static_run, "Run statically generated menu"},
                {  menu_dynamic_run,              "Run dynamic menu"},
                {menu_dynamic_print,            "Print dynamic menu"},
                {            finish,                          "Quit"},
            };
            Menu::display("Menu demo program", items,
                          sizeof(items) / sizeof(Menu::item_t));
          int main(void) {
            stamen::menu_main();
            return 0;
          }
        
        diff --git a/ include/stamen.h b/ include/stamen.h
          @@ -32,41 +32,13 @@ 
          public:
        
        
            Menu(private_ctor_t, const std::string &code, const callback_f callback)
                : Menu(code, callback) {}
            struct item_t {
              item_t() {}
              item_t(const callback_f func, const std::string &prompt)
                  : callback(func), prompt(prompt) {}
              item_t(const std::string &code, const std::string &prompt)
                  : code(code), prompt(prompt) {}
              const std::string getCode(void) const { return code; }
              const std::string getPrompt(void) const { return prompt; }
              const callback_f getCallback(void) const { return callback; }
              int operator()(void) const { return callback ? callback() : start(code); }
            private:
              std::string prompt, code;
              callback_f callback = nullptr;
            };
            typedef int (*display_f)(const std::string &, const item_t[], std::size_t);
            typedef int (*display_f)(const std::string &, const ::item_t[], std::size_t);
            static const display_f display;
            static void read(const std::string &s);
            static void insert(const std::string &code, const callback_f callback);
            static void print(const std::string &entry) { print(entry, 1); }
            static int start(const std::string &entry) {
              const Menu *menu = getMenu(entry);
              if (!menu) return 1;
              return menu->operator()();
            }
            int operator()() const {
              return callback ? callback() : display(title, items.data(), items.size());
            }
          private:
            Menu(const std::string &code, const std::string &prompt)
        
        
          @@ -92,7 +64,14 @@ 
          private:
        
        
            const std::string code, title;
            const callback_f callback = nullptr;
            std::vector<item_t> items;
            struct lookup_item_t {
              lookup_item_t(const std::string &code, const std::string &prompt)
                  : code(code), prompt(prompt) {}
              const std::string code, prompt;
            };
            std::vector<lookup_item_t> items;
          };
          inline void Menu::read(const std::string &s) {
        
        
          @@ -132,13 +111,13 @@ 
          inline void Menu::print(const std::string &code, const int depth) {
        
        
            if (!menu->callback) {
              for (const auto &item : menu->items) {
                std::cout << std::format("{}{} ({})\n", std::string(depth << 1, ' '),
                                         item.getPrompt(), item.getCode());
                menu->print(item.getCode(), depth + 1);
                                         item.prompt, item.code);
                menu->print(item.code, depth + 1);
              }
            }
          }
          int builtinDisplay(const std::string &title, const Menu::item_t items[],
          int builtinDisplay(const std::string &title, const ::item_t items[],
                             std::size_t size);
          } // namespace stamen
        
        diff --git a/ include/stamenc.h b/ include/stamenc.h
          @@ -20,7 +20,6 @@ 
          extern const display_f display;
        
        
          EXTERNC void stamen_read(const char *file);
          EXTERNC void stamen_print(const char *entry);
          EXTERNC int stamen_start(const char *entry);
          EXTERNC void stamen_insert(const char *code, callback_f callback);
          EXTERNC int stamen_builtin_display(const char *title, const item_t items[], int size);
          diff --git a/ src/generate.cpp b/ src/generate.cpp
          @@ -16,7 +16,6 @@ 
          public:
        
        
            static void generateInclude(std::ostream &os, bool cpp) {
              os << "#ifndef STAMEN_MENU_H\n";
              os << "#define STAMEN_MENU_H\n\n";
              os << std::format("#include <stamen{}.h>\n\n", !cpp ? "c" : "");
              if (cpp) os << "namespace stamen {\n\n";
              for (const auto &[code, _] : Menu::getLookup()) {
                const Menu *menu = Menu::getMenu(code);
        
        
          @@ -25,7 +24,7 @@ 
          public:
        
        
                os << std::format("int {}(void);\n", menu->code);
              }
              if (cpp) os << "\n}\n";
              os << "#endif\n";
              os << "\n#endif\n";
            }
            static void generateSource(std::ostream &os, bool cpp) {
        
        
          @@ -38,15 +37,13 @@ 
          public:
        
        
                if (menu->callback) continue;
                os << std::format("int {}(void) {{\n", menu->code);
                os << std::format("\tstatic const {}item_t items[] = {{\n",
                                  cpp ? "Menu::" : "");
                os << std::format("\tstatic const item_t items[] = {{\n");
                for (const auto &item : menu->items) {
                  os << std::format("\t\t{{ {}, \"{}\" }},\n", item.getCode(),
                                    item.getPrompt());
                  os << std::format("\t\t{{ {}, \"{}\" }},\n", item.code, item.prompt);
                }
                os << std::format("\t}};\n");
                os << std::format("\treturn {0}display(\"{1}\", items, "
                                  "sizeof(items) / sizeof({0}item_t));\n",
                os << std::format("\treturn {}display(\"{}\", items, "
                                  "sizeof(items) / sizeof(item_t));\n",
                                  cpp ? "Menu::" : "", menu->title);
                os << std::format("}}\n\n");
              }
        
        diff --git a/ src/stamen.cpp b/ src/stamen.cpp
@@ -3,17 +3,19 @@
#include <format>
          #include <iostream>
          #include <ostream>
          #include <variant>
          namespace stamen {
          int builtinDisplay(const std::string &title, const Menu::item_t items[],
          int 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());
                std::cout << std::format(" {:{}}. {}\n", i, digits, items[i].prompt);
              }
              while (true) {
        
        
          @@ -24,11 +26,12 @@ 
          int builtinDisplay(const std::string &title, const Menu::item_t items[],
        
        
                    return 1;
                  }
                  const Menu::item_t &chosen = items[choice];
                  std::cout << std::format("Choice: {}\n\n", chosen.getPrompt());
                  const int res = chosen();
                  if (res > 1) return res - 1;
                  else break;
                  std::cout << std::format("Choice: {}\n\n", items[choice].prompt);
                  const int res = items[choice].callback();
                  if (res > 1)
                    return res - 1;
                  else
                    break;
                } else if (std::cin.eof()) {
                  std::cerr << "encountered end of input!\n";
        
        diff --git a/ src/stamenc.cpp b/ src/stamenc.cpp
@@ -1,4 +1,5 @@
#include "../include/stamen.h"
          #include "../include/stamenc.h"
          using namespace stamen;
          
          @@ -6,18 +7,10 @@ 
          const Menu::display_f Menu::display = nullptr;
        
        
          void stamen_read(const char *file) { stamen::Menu::read(file); }
          void stamen_print(const char *entry) { stamen::Menu::print(entry); }
          int stamen_start(const char *entry) { return stamen::Menu::start(entry); }
          void stamen_insert(const char *code, callback_f callback) {
            Menu::insert(code, callback);
          }
          int stamen_builtin_display(const char *title, const item_t items[], int size) {
            Menu::item_t *litems = new Menu::item_t[size];
            if (!litems) return -1;
            for (int i = 0; i < size; i++) {
              litems[i] = Menu::item_t(items[i].callback, items[i].prompt);
            }
            const int ret = builtinDisplay(title, litems, size);
            delete[] litems;
            return ret;
            return builtinDisplay(title, items, size);
          }