stamen

Static Menu Generator
git clone git://git.dimitrijedobrota.com/stamen.git
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |

commit45ebb3b798a9cf306ccfce512db8755e22cc472e
parentcd594065e953fe49c1ba109a1ceaf360f759a290
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateThu, 13 Jun 2024 19:43:46 +0200

Improve C++ interface with namespace * Distintion between C and C++ interfaces * Extract C++ interface from stamen.h into stamen.hpp * Fix generation to reflect changes

Diffstat:
MCMakeLists.txt|+-
Mdemo/CMakeLists.txt|++++------------
Mdemo/dynamic.cpp|++++--
Mdemo/main.cpp|++--
Minclude/menu.h|+-
Minclude/stamen.h|++++++++++++-------------------
Ainclude/stamen.hpp|+++++++++++++++++++++
Msrc/CMakeLists.txt|++++++++-----
Asrc/c_bindings.cpp|+++++++++++++++++++
Msrc/generate.cpp|+++++++++++++++++++++++++--------------
Msrc/menu.cpp|-
Msrc/stamen.cpp|++++++++-------

12 files changed, 105 insertions(+), 64 deletions(-)


diff --git a/CMakeLists.txt b/CMakeLists.txt

@@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

project(
Stamen
VERSION 1.0.0
VERSION 1.0.1
DESCRIPTION "Static menu generator"
LANGUAGES C CXX
)

diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt

@@ -9,12 +9,9 @@ add_custom_command(

COMMENT "Generating menu files"
)
add_executable(demo
main.cpp
${GENERATE_OUT}/demo_menu.cpp
)
add_executable(demo main.cpp ${GENERATE_OUT}/demo_menu.cpp)
target_link_libraries(demo stamen)
set_target_properties(demo PROPERTIES LINKER_LANGUAGE CXX)
target_include_directories(demo PRIVATE ${GENERATE_OUT} ${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties(demo PROPERTIES

@@ -23,8 +20,6 @@ set_target_properties(demo PROPERTIES

RUNTIME_OUTPUT_DIRECTORY "${GENERATE_OUT}"
)
add_custom_command(
OUTPUT ${GENERATE_OUT}/demo_menu.h ${GENERATE_OUT}/demo_menu.c
COMMAND ${GENERATE_OUT}/stamen-generate ${GENERATE_OUT}/demo_menu.conf c

@@ -32,12 +27,9 @@ add_custom_command(

COMMENT "Generating cmenu files"
)
add_executable(cdemo
main.c
${GENERATE_OUT}/demo_menu.c
)
add_executable(cdemo main.c ${GENERATE_OUT}/demo_menu.c)
target_link_libraries(cdemo stamen)
set_target_properties(cdemo PROPERTIES LINKER_LANGUAGE C)
target_include_directories(cdemo PRIVATE ${GENERATE_OUT} ${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties(cdemo PROPERTIES

diff --git a/demo/dynamic.cpp b/demo/dynamic.cpp

@@ -1,7 +1,9 @@

#include "stamen.hpp"
#include <iostream>
#include <stamen.h>
const stamen::display_f stamen_display = stamen::builtin_display;
// need to link against stamen library
// in order to use stamen::builtin_display
const stamen::display_f &stamen::display = stamen::builtin_display;
int finish(int) { exit(1); }

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_builtin_display
const stamen::display_f stamen_display = stamen::builtin_display;
// in order to use 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

@@ -1,7 +1,7 @@

#ifndef STAMEN_MENU_H
#define STAMEN_MENU_H
#include "stamen.h"
#include "stamen.hpp"
#include <cstring>
#include <iostream>

diff --git a/include/stamen.h b/include/stamen.h

@@ -2,9 +2,8 @@

#define STAMEN_STAMEN_H
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC extern
extern "C" {
namespace stamen {
#endif
typedef int (*stamen_callback_f)(int);

@@ -18,25 +17,19 @@ 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(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 {
#if !defined __cplusplus || defined WITH_C_BINDINGS
using callback_f = stamen_callback_f;
using display_f = stamen_display_f;
using item_t = stamen_item_t;
int stamen_dynamic(const char *code);
void stamen_read(const char *filename);
void stamen_insert(const char *code, stamen_callback_f callback);
int stamen_builtin_display(const char *title, const stamen_item_t itemv[],
int size);
const auto dynamic = stamen_dynamic;
const auto read = stamen_read;
const auto insert = stamen_insert;
const auto builtin_display = stamen_builtin_display;
#endif
#ifdef __cplusplus
} // namespace stamen
} // extern "C"
#endif
#endif
#endif // STAMEN_STAMEN_H

diff --git a/include/stamen.hpp b/include/stamen.hpp

@@ -0,0 +1,21 @@

#ifndef STAMEN_STAMEN_HPP
#define STAMEN_STAMEN_HPP
#include "stamen.h"
namespace stamen {
using callback_f = stamen_callback_f;
using display_f = stamen_display_f;
using item_t = stamen_item_t;
extern const display_f &display;
int dynamic(const char *code);
void read(const char *filename);
void insert(const char *code, callback_f callback);
int builtin_display(const char *title, const item_t itemv[], int size);
} // namespace stamen
#endif

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt

@@ -1,12 +1,15 @@

add_library(stamen-include INTERFACE)
target_include_directories(stamen-include INTERFACE ../include)
add_library(stamen STATIC stamen.cpp menu.cpp c_bindings.cpp)
target_include_directories(stamen PUBLIC ../include)
target_compile_definitions(stamen PRIVATE WITH_C_BINDINGS)
set_target_properties(stamen PROPERTIES LINKER_LANGUAGE CXX)
add_library(stamen stamen.cpp menu.cpp)
target_link_libraries(stamen PUBLIC stamen-include)
set_target_properties(stamen PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
PUBLIC_HEADER ../include/stamen.h
DEBUG_POSTFIX "d"
PUBLIC_HEADER "../include/stamen.h;../include/stamen.hpp"
MACOSX_RPATH ON
WINDOWS_EXPORT_ALL_SYMBOLS ON
)
install(TARGETS stamen

diff --git a/src/c_bindings.cpp b/src/c_bindings.cpp

@@ -0,0 +1,19 @@

#include "stamen.h"
#include "stamen.hpp"
namespace stamen {
int stamen_dynamic(const char *code) { return dynamic(code); }
void stamen_read(const char *filename) { return read(filename); }
void stamen_insert(const char *code, stamen_callback_f callback) {
return insert(code, callback);
}
int stamen_builtin_display(const char *title, const stamen_item_t itemv[],
int size) {
return builtin_display(title, itemv, size);
}
} // namespace stamen

diff --git a/src/generate.cpp b/src/generate.cpp

@@ -10,33 +10,44 @@ namespace stamen {

class Generator {
public:
static void generateInclude(std::ostream &os) {
static void generateInclude(std::ostream &os, bool cpp) {
os << "#ifndef STAMEN_MENU_H\n";
os << "#define STAMEN_MENU_H\n\n";
os << "#include <stamen.h>\n\n";
if (cpp) os << "#include \"stamen.hpp\"\n\n";
else os << "#include \"stamen.h\"\n\n";
for (const auto &[code, menu] : Menu::menu_lookup) {
os << std::format("int {}(int);\n", menu.getCode());
}
os << "\n#endif\n";
}
static void generateSource(std::ostream &os) {
os << "#include <stamen.h>\n";
static void generateSource(std::ostream &os, bool cpp) {
if (cpp) os << "#include \"stamen.hpp\"\n\n";
else os << "#include \"stamen.h\"\n\n";
os << "#include \"shared.h\"\n\n";
for (const auto &[code, menu] : Menu::menu_lookup) {
os << std::format("int {}(int) {{\n", menu.getCode());
os << std::format("\tstatic const stamen_item_t items[] = {{\n");
if (cpp) os << "\tstatic const stamen::item_t items[] = ";
else os << "\tstatic const stamen_item_t items[] = ";
os << "{\n";
for (int i = 0; i < menu.getSize(); i++) {
os << std::format("\t\t{{ {}, \"{}\" }},\n", menu.getCode(i),
menu.getPrompt(i));
os << "\t\t{ " << menu.getCode(i);
os << ", \"" << menu.getPrompt(i) << "\" },\n";
}
os << std::format("\t}};\n");
os << "\t};\n";
if (cpp) os << "\treturn stamen::display";
else os << "\treturn stamen_display";
os << std::format("\treturn stamen_display(\"{}\", items, "
"sizeof(items) / sizeof(items[0]));\n",
menu.getTitle());
os << std::format("}}\n\n");
os << std::format("(\"{}\"", menu.getTitle());
os << ", items, sizeof(items) / sizeof(items[0]));\n";
os << "}\n\n";
}
}
};

@@ -63,8 +74,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);
Generator::generateInclude(include);
Generator::generateSource(source, cpp);
Generator::generateInclude(include, cpp);
return 0;
}

diff --git a/src/menu.cpp b/src/menu.cpp

@@ -1,5 +1,4 @@

#include "menu.h"
#include "stamen.h"
#include <deque>
#include <format>

diff --git a/src/stamen.cpp b/src/stamen.cpp

@@ -1,4 +1,4 @@

#include "stamen.h"
#include "stamen.hpp"
#include "menu.h"
#include <cmath>

@@ -7,16 +7,15 @@

#include <ostream>
#include <variant>
using namespace stamen;
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) {
int dynamic(const char *code) { return Menu::dynamic(code); }
void read(const char *filename) { Menu::read(filename); }
void insert(const char *code, callback_f callback) {
Menu::insert(code, callback);
}
int stamen_builtin_display(const char *title, const stamen_item_t itemv[],
int size) {
int 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;

@@ -56,3 +55,5 @@ int stamen_builtin_display(const char *title, const stamen_item_t itemv[],

return 1;
}
} // namespace stamen