stamen

Stamen - static menu generator
git clone git://git.dimitrijedobrota.com/stamen.git
Log | Files | Refs | README | LICENSE

generate.cpp (4222B)


      1 #include <format>
      2 #include <fstream>
      3 #include <iostream>
      4 #include <string>
      5 
      6 #include "poafloc/poafloc.hpp"
      7 #include "stamen/menu.hpp"
      8 #include "stamen/stamen.hpp"
      9 
     10 struct arguments_t
     11 {
     12   std::string config;
     13   std::string display;
     14   std::string header = "shared.h";
     15   bool cpp           = false;
     16   bool user          = false;
     17 };
     18 
     19 void generate_include(std::ostream& ost)
     20 {
     21   ost << "#ifndef STAMEN_MENU_H\n";
     22   ost << "#define STAMEN_MENU_H\n\n";
     23 
     24   for (const auto& [code, menu] : stamen::menu::menu_lookup)
     25   {
     26     ost << std::format("int {}(size_t);\n", menu.get_code());
     27   }
     28 
     29   ost << "\n#endif\n";
     30 }
     31 
     32 void generate_source(std::ostream& ost, const arguments_t& args)
     33 {
     34   ost << std::format("#include \"{}\"\n", args.header);
     35   if (args.user)
     36   {
     37     if (args.cpp) ost << "#include \"stamen.hpp\"\n\n";
     38     else ost << "#include \"stamen.h\"\n\n";
     39   }
     40   else
     41   {
     42     if (args.cpp) ost << "#include <stamen/stamen.hpp>\n\n";
     43     else ost << "#include <stamen/stamen.h>\n\n";
     44   }
     45 
     46   ost << std::format("extern int {}(const char *title, ", args.display);
     47   if (args.cpp) ost << "const stamen::item_t itemv[], size_t size);\n\n";
     48   else ost << "const stamen_item_t itemv[], size_t size);\n\n";
     49 
     50   for (const auto& [code, menu] : stamen::menu::menu_lookup)
     51   {
     52     ost << std::format("int {}(size_t /* unused */) {{\n", menu.get_code());
     53 
     54     if (args.cpp) ost << "\tstatic const stamen::item_t items[] = ";
     55     else ost << "\tstatic const stamen_item_t items[] = ";
     56 
     57     ost << "{\n";
     58     for (auto i = 0UL; i < menu.get_size(); i++)
     59     {
     60       ost << "\t\t{ " << menu.get_code(i);
     61       ost << ", \"" << menu.get_prompt(i) << "\" },\n";
     62     }
     63     ost << "\t};\n";
     64 
     65     ost << std::format("\treturn {}(\"{}\"", args.display, menu.get_title());
     66     ost << ", items, sizeof(items) / sizeof(items[0]));\n";
     67     ost << "}\n\n";
     68   }
     69 }
     70 
     71 int parse_opt(int key, const char* arg, poafloc::Parser* parser)
     72 {
     73   auto* arguments = static_cast<arguments_t*>(parser->input());
     74   switch (key)
     75   {
     76     case 'd':
     77       arguments->display = arg;
     78       break;
     79     case 'h':
     80       arguments->header = arg;
     81       break;
     82     case 'u':
     83       arguments->user = true;
     84       break;
     85     case 666:
     86       arguments->cpp = false;
     87       break;
     88     case 777:
     89       arguments->cpp = true;
     90       break;
     91     case poafloc::ARG:
     92       if (!arguments->config.empty())
     93       {
     94         poafloc::failure(parser, 0, 0, "Too many arguments");
     95         poafloc::help(parser, stderr, poafloc::STD_USAGE);
     96       }
     97       arguments->config = arg;
     98       break;
     99     case poafloc::NO_ARGS:
    100       poafloc::failure(parser, 0, 0, "Missing an argument");
    101       poafloc::help(parser, stderr, poafloc::STD_USAGE);
    102       break;
    103     case poafloc::END:
    104       if (arguments->display.empty())
    105       {
    106         if (arguments->cpp) arguments->display = "stamen::builtin_display";
    107         else arguments->display = "stamen_builtin_display";
    108       }
    109       break;
    110     default:
    111       break;
    112   }
    113   return 0;
    114 }
    115 
    116 static const poafloc::option_t options[] {
    117     {nullptr, 0, nullptr, 0, "Output mode", 1},
    118     {"c", 666, nullptr, 0, "Generate files for C"},
    119     {"cpp", 777, nullptr, 0, "Generate files for C++"},
    120     {nullptr, 0, nullptr, 0, "Output settings", 2},
    121     {"display", 'd', "FUNC", 0, "Set display function to be called"},
    122     {"user", 'u', nullptr, 0, "Include user stamen headers"},
    123     {"header", 'h', "HDR", 0, "Header with free functions, default: shared.h"},
    124     {nullptr, 0, nullptr, 0, "Informational Options", -1},
    125     {nullptr},
    126 };
    127 
    128 static const poafloc::arg_t arg {
    129     options,
    130     parse_opt,
    131     "config_file",
    132     "",
    133 };
    134 
    135 int main(int argc, char* argv[])
    136 {
    137   arguments_t args;
    138 
    139   if (poafloc::parse(&arg, argc, argv, 0, &args) != 0)
    140   {
    141     std::cerr << "There was an error while parsing arguments";
    142     return 1;
    143   }
    144 
    145   const auto& config = args.config;
    146   stamen::menu::read(config.c_str());
    147 
    148   const std::string::size_type pos = args.config.rfind('.');
    149   const std::string ext            = args.cpp ? "pp" : "";
    150   const std::string base =
    151       pos != std::string::npos ? config.substr(0, pos) : config;
    152 
    153   std::ofstream include(base + ".h" + ext);
    154   generate_include(include);
    155 
    156   std::ofstream source(base + ".c" + ext);
    157   generate_source(source, args);
    158 
    159   return 0;
    160 }