lsnes rr2-β23
[lsnes.git] / src / cmdhelp / mkstubs.cpp
blobcfd519fdbb84cbe199706f27e154dbaaef833754
1 #include "json.hpp"
2 #include <string>
3 #include <fstream>
4 #include <sstream>
5 #include <set>
7 const char* hexes = "0123456789abcdef";
9 std::string quote_c_string(const std::string& raw);
11 std::string quote_c_string(const std::string& raw)
13 std::ostringstream out;
14 out << "\"";
15 for(auto i : raw) {
16 unsigned char ch = i;
17 if(ch == '\n')
18 out << "\\n";
19 else if(ch == '\"')
20 out << "\\\"";
21 else if(ch == '\\')
22 out << "\\\\";
23 else if(ch < 32 || ch > 126)
24 out << "\\x" << hexes[ch / 16] << hexes[ch % 16];
25 else
26 out << ch;
28 out << "\"";
29 return out.str();
32 std::string quote_help(const std::u32string& raw)
34 const size_t initial_width = 8;
35 const size_t break_width = 80;
36 std::ostringstream out;
37 //Compute split positions.
38 std::set<size_t> splits;
39 size_t last_word = 0;
40 size_t last_word_width = initial_width;
41 size_t width = initial_width;
42 for(size_t i = 0; i < raw.length(); i++) {
43 if(raw[i] == U'\n') {
44 splits.insert(i);
45 width = initial_width;
46 last_word = i;
47 last_word_width = initial_width;
49 if(raw[i] == U' ') {
50 width++;
51 if(width > break_width && last_word_width > initial_width) {
52 //Wordwrap at last word.
53 splits.insert(last_word);
54 width = width - last_word_width + initial_width;
56 last_word = i;
57 last_word_width = width;
58 } else {
59 //FIXME: Handle double-width characters.
60 width++;
63 out << "\t\"\\t";
64 for(size_t i = 0; i < raw.length(); i++) {
65 if(splits.count(i)) {
66 out << "\\n\"\n\t\"";
67 } else {
68 char32_t z[2] = {raw[i]};
69 if(z[0] == U'\"')
70 out << "\\\"";
71 else if(z[0] == U'\n')
72 out << "\\n";
73 else if(z[0] < 32 || z[0] == 127)
74 out << "\\x" << hexes[z[0] / 16] << hexes[z[0] % 16];
75 else
76 out << utf8::to8(z);
79 out << "\\n\"\n";
80 return out.str();
83 void process_command(const std::string& name, JSON::node& n, std::ostream& hdr, std::ostream& imp)
85 if(name == "__mod")
86 return;
87 std::string cmdsym = n.index(0).as_string8();
88 hdr << "extern command::stub " << cmdsym << ";" << std::endl;
89 imp << "command::stub " << cmdsym << " = {" << std::endl;
90 std::string desc = (n.index_count() >= 2) ? n.index(1).as_string8() :
91 "No description available";
92 imp << "\t" << quote_c_string(name) << ", " << quote_c_string(desc) << "," << std::endl;
93 bool first = true;
94 if(n.index_count() >= 3) {
95 auto& nc = n.index(2);
96 for(auto i = nc.begin(); i != nc.end(); i++) {
97 std::string hleafname = i.key8();
98 std::u32string hleafc = i->as_string();
99 if(!first)
100 imp << "\t\"\\n\"" << std::endl;
101 first = false;
102 imp << "\t" << quote_c_string(std::string("Syntax: ") + name + " " + hleafname + "\n")
103 << std::endl;
104 imp << quote_help(hleafc);
107 if(first) imp << "\t\"No help available for '" << name << "'\"" << std::endl;
108 imp << "};" << std::endl;
109 imp << std::endl;
112 int main(int argc, char** argv)
114 if(argc != 2) {
115 std::cerr << "Need one filename base" << std::endl;
116 return 1;
118 std::string fname = argv[1];
120 if(fname.length() > 5 && fname.substr(fname.length() - 5) == ".json")
121 fname = fname.substr(0, fname.length() - 5);
123 std::ifstream infile(fname + std::string(".json"));
124 std::string in_json;
125 std::string tmp;
126 while(infile) {
127 std::getline(infile, tmp);
128 in_json = in_json + tmp + "\n";
130 JSON::node n(in_json);
132 std::string modname = n["__mod"].as_string8();
134 std::ofstream hdr(fname + std::string(".hpp"));
135 std::ofstream impl(fname + std::string(".cpp"));
136 impl << "#include \"cmdhelp/" << fname << ".hpp\"" << std::endl;
137 impl << "namespace " << modname << std::endl;
138 impl << "{" << std::endl;
139 hdr << "#pragma once" << std::endl;
140 hdr << "#include \"library/command.hpp\"" << std::endl;
141 hdr << "namespace " << modname << std::endl;
142 hdr << "{" << std::endl;
143 for(auto i = n.begin(); i != n.end(); i++)
144 process_command(i.key8(), *i, hdr, impl);
145 impl << "}" << std::endl;
146 hdr << "}" << std::endl;
147 return 0;