mwcxx/bindgen.cxx

567 lines
13 KiB
C++
Raw Normal View History

2026-04-16 15:01:47 +09:00
#include <xemil.h>
#include <map>
#include <string>
#include <fstream>
2026-04-17 19:42:14 +09:00
#include <sstream>
#include <locale>
struct typeinfo {
2026-04-17 21:26:28 +09:00
std::string type;
std::string name;
std::string struct_name;
int pointer;
2026-04-17 19:42:14 +09:00
};
2026-04-16 15:01:47 +09:00
struct property {
2026-04-17 21:26:28 +09:00
typeinfo type;
int common;
2026-04-17 22:25:28 +09:00
};
struct handler {
int common;
int has_arg;
2026-04-17 21:26:28 +09:00
typeinfo arg_type;
2026-04-16 15:01:47 +09:00
};
2026-04-17 19:42:14 +09:00
std::map<std::string, std::ofstream> files;
2026-04-16 15:01:47 +09:00
std::map<std::string, property> props;
2026-04-17 22:25:28 +09:00
std::map<std::string, handler> handlers;
2026-04-16 15:01:47 +09:00
2026-04-17 19:42:14 +09:00
std::locale locale;
2026-04-17 22:25:28 +09:00
static std::string get_ctype(typeinfo type, int name = 1, int do_ptr = 1) {
2026-04-17 19:42:14 +09:00
std::string ret = "";
if(type.type == "integer") {
ret += "int";
} else if(type.type == "string") {
ret += "MwCXX::String";
} else if(type.type == "pixmap") {
ret += "MwLLPixmap";
} else if(type.type == "pointer") {
ret += "void*";
} else if(type.type == "struct") {
ret += type.struct_name;
}
2026-04-17 22:25:28 +09:00
if(do_ptr && type.pointer) ret += "*";
2026-04-17 19:42:14 +09:00
if(name && type.name != "") {
ret += " " + type.name;
}
return ret;
}
static std::string get_type(typeinfo type) {
if(type.type == "integer") {
return "Integer";
} else if(type.type == "string") {
return "Text";
}
return "Void";
}
static std::string uppercase(std::string str) {
std::string r = str;
for(int i = 0; i < r.size(); i++) {
r[i] = std::toupper(r[i], locale);
}
return r;
}
static std::string lowercase(std::string str) {
std::string r = str;
for(int i = 0; i < r.size(); i++) {
r[i] = std::tolower(r[i], locale);
}
2026-04-16 15:01:47 +09:00
2026-04-17 19:42:14 +09:00
return r;
2026-04-16 15:01:47 +09:00
}
2026-04-17 19:42:14 +09:00
#define ATTR_TO_BOOL(node, x) ((s = xl_get_attribute(node, (x))) != NULL) && (strcmp(s, "no") != 0);
static typeinfo xml_to_type(xl_node_t* node) {
char* s;
typeinfo ret;
ret.type = node->name;
ret.name = ((s = xl_get_attribute(node, "name")) != NULL) ? s : "";
ret.struct_name = ((s = xl_get_attribute(node, "defname")) != NULL) ? s : "";
ret.pointer = ATTR_TO_BOOL(node, "pointer");
return ret;
}
2026-04-17 22:25:28 +09:00
static std::string upperfirst(std::string str) {
2026-04-17 19:42:14 +09:00
return uppercase(str.substr(0, 1)) + str.substr(1);
}
static void scan_property(xl_node_t* node) {
2026-04-17 22:25:28 +09:00
property prop;
char* s;
2026-04-16 15:01:47 +09:00
if(node->type != XL_NODE_NODE) return;
2026-04-17 19:42:14 +09:00
prop.type = xml_to_type(node);
prop.common = ATTR_TO_BOOL(node, "common");
2026-04-17 22:25:28 +09:00
props[xl_get_attribute(node, "name")] = prop;
}
static void scan_properties(xl_node_t* node) {
xl_node_t* child = node->first_child;
2026-04-17 19:42:14 +09:00
while(child != NULL) {
2026-04-17 22:25:28 +09:00
scan_property(child);
2026-04-17 19:42:14 +09:00
child = child->next;
}
2026-04-17 22:25:28 +09:00
}
2026-04-16 15:01:47 +09:00
2026-04-17 22:25:28 +09:00
static void scan_handler(xl_node_t* node) {
handler handl;
char* s;
xl_node_t* child = node->first_child;
if(node->type != XL_NODE_NODE) return;
handl.common = ATTR_TO_BOOL(node, "common");
handl.has_arg = 0;
while(child != NULL) {
if(child->type == XL_NODE_NODE) {
handl.has_arg = 1;
handl.arg_type = xml_to_type(child);
}
child = child->next;
}
handlers[xl_get_attribute(node, "name")] = handl;
2026-04-16 15:01:47 +09:00
}
2026-04-17 22:25:28 +09:00
static void scan_handlers(xl_node_t* node) {
2026-04-16 15:01:47 +09:00
xl_node_t* child = node->first_child;
2026-04-17 19:42:14 +09:00
while(child != NULL) {
2026-04-17 22:25:28 +09:00
scan_handler(child);
2026-04-16 15:01:47 +09:00
child = child->next;
}
}
2026-04-17 19:42:14 +09:00
static std::string widget_property_header(std::string name, std::string indent = "") {
std::stringstream strm;
2026-04-17 22:25:28 +09:00
strm << indent + get_ctype(props[name].type, 0) + " Get" + upperfirst(name) + "();" << std::endl;
strm << indent + "void Set" + upperfirst(name) + "(" + get_ctype(props[name].type, 0) + " value);" << std::endl;
2026-04-17 19:42:14 +09:00
return strm.str();
}
2026-04-17 22:25:28 +09:00
static std::string scan_widget_property_header(xl_node_t* node, std::string indent) {
xl_node_t* child = node->first_child;
if(node->type != XL_NODE_NODE) return "";
return widget_property_header(xl_get_attribute(node, "name"), indent);
}
static std::string scan_widget_properties_header(xl_node_t* node, std::string indent) {
std::string r = "";
xl_node_t* child = node->first_child;
while(child != NULL) {
r += scan_widget_property_header(child, indent);
child = child->next;
}
return r;
}
2026-04-17 19:42:14 +09:00
static std::string widget_property_source(std::string widget, std::string name) {
std::stringstream strm;
2026-04-17 22:25:28 +09:00
strm << get_ctype(props[name].type, 0) + " MwCXX::" + widget + "::Get" + upperfirst(name) + "() {" << std::endl;
2026-04-17 19:42:14 +09:00
strm << " return (" + get_ctype(props[name].type, 0) + ")MwGet" + get_type(props[name].type) + "(this->widget, MwN" + name + ");" << std::endl;
strm << "}" << std::endl;
strm << std::endl;
2026-04-17 22:25:28 +09:00
strm << "void MwCXX::" + widget + "::Set" + upperfirst(name) + "(" + get_ctype(props[name].type, 0) + " value) {" << std::endl;
2026-04-17 19:42:14 +09:00
if(props[name].type.type == "string") {
strm << "#ifndef MWCXX_USE_C_STRING" << std::endl;
strm << " MwSetText(this->widget, MwN" + name + ", value.c_str());" << std::endl;
strm << "#else" << std::endl;
}
strm << " MwSet" + get_type(props[name].type) + "(this->widget, MwN" + name + ", (" + get_ctype(props[name].type, 0) + ")value);" << std::endl;
if(props[name].type.type == "string") {
strm << "#endif" << std::endl;
}
strm << "}" << std::endl;
strm << std::endl;
return strm.str();
}
2026-04-17 22:25:28 +09:00
static std::string scan_widget_property_source(xl_node_t* node, std::string widget) {
2026-04-17 19:42:14 +09:00
xl_node_t* child = node->first_child;
if(node->type != XL_NODE_NODE) return "";
2026-04-17 22:25:28 +09:00
return widget_property_source(widget, xl_get_attribute(node, "name"));
2026-04-17 19:42:14 +09:00
}
2026-04-17 22:25:28 +09:00
static std::string scan_widget_properties_source(xl_node_t* node, std::string widget) {
2026-04-17 19:42:14 +09:00
std::string r = "";
xl_node_t* child = node->first_child;
while(child != NULL) {
2026-04-17 22:25:28 +09:00
r += scan_widget_property_source(child, widget);
2026-04-17 19:42:14 +09:00
child = child->next;
}
return r;
}
2026-04-17 22:25:28 +09:00
static std::string widget_handler_header(std::string name, std::string indent = "") {
std::stringstream strm;
strm << indent + "virtual void On" + upperfirst(name) + "(" + (handlers[name].has_arg ? (get_ctype(handlers[name].arg_type, 0, 0) + " value") : "") + ") {};" << std::endl;
return strm.str();
}
static std::string scan_widget_handler_header(xl_node_t* node, std::string indent) {
2026-04-17 19:42:14 +09:00
xl_node_t* child = node->first_child;
if(node->type != XL_NODE_NODE) return "";
2026-04-17 22:25:28 +09:00
return widget_handler_header(xl_get_attribute(node, "name"), indent);
2026-04-17 19:42:14 +09:00
}
2026-04-17 22:25:28 +09:00
static std::string scan_widget_handlers_header(xl_node_t* node, std::string indent) {
2026-04-17 19:42:14 +09:00
std::string r = "";
xl_node_t* child = node->first_child;
while(child != NULL) {
2026-04-17 22:25:28 +09:00
r += scan_widget_handler_header(child, indent);
child = child->next;
}
return r;
}
static std::string widget_handler_source(std::string widget, std::string name) {
std::stringstream strm;
std::string cast = "";
if(handlers[name].has_arg) {
cast = "(" + get_ctype(handlers[name].arg_type, 0) + ")";
if(handlers[name].arg_type.pointer) cast = "*" + cast;
if(handlers[name].arg_type.type == "string") cast += "(char*)";
cast += "call";
}
strm << "static void __On" + upperfirst(name) + "(MwWidget handle, void* user, void* call) {" << std::endl;
strm << " ((MwCXX::" + widget + "*)user)->On" + upperfirst(name) + "(" + cast + ");" << std::endl;
strm << "}" << std::endl;
strm << std::endl;
return strm.str();
}
static std::string scan_widget_handler_source(xl_node_t* node, std::string widget) {
xl_node_t* child = node->first_child;
if(node->type != XL_NODE_NODE) return "";
return widget_handler_source(widget, xl_get_attribute(node, "name"));
}
static std::string scan_widget_handlers_source(xl_node_t* node, std::string widget) {
std::string r = "";
xl_node_t* child = node->first_child;
while(child != NULL) {
r += scan_widget_handler_source(child, widget);
2026-04-17 19:42:14 +09:00
child = child->next;
}
return r;
}
static void scan_widget(xl_node_t* node) {
std::string name;
2026-04-17 22:25:28 +09:00
xl_node_t** p_nodes;
xl_node_t** h_nodes;
xl_node_t* child;
2026-04-17 19:42:14 +09:00
int i;
if(node->type != XL_NODE_NODE) return;
2026-04-17 22:25:28 +09:00
p_nodes = xl_get_path(node, "properties");
h_nodes = xl_get_path(node, "handlers");
2026-04-17 19:42:14 +09:00
name = xl_get_attribute(node, "name");
#define OFS files["W" + name + ".h"]
OFS = std::ofstream("include/MwCXX/Widget/" + name + ".h");
OFS << "#ifndef __MWCXX_WIDGET_" + uppercase(name) + "_H__" << std::endl;
OFS << "#define __MWCXX_WIDGET_" + uppercase(name) + "_H__" << std::endl;
OFS << std::endl;
OFS << "#include <MwCXX/MachDep.h>" << std::endl;
OFS << "#include <MwCXX/Widget/Base.h>" << std::endl;
OFS << std::endl;
OFS << "#include <Mw/Widget/" + name + ".h>" << std::endl;
OFS << std::endl;
OFS << "namespace MwCXX {" << std::endl;
OFS << " class " + name + " : public MwCXX::Base {" << std::endl;
2026-04-17 22:25:28 +09:00
OFS << " protected:" << std::endl;
OFS << " virtual void RegisterHandlers();" << std::endl;
OFS << std::endl;
2026-04-17 21:26:28 +09:00
OFS << " public:" << std::endl;
OFS << " " + name + "(MwWidget widget);" << std::endl;
OFS << " " + name + "(MwCXX::String name, MwCXX::Base* parent, int x, int y, unsigned int width, unsigned int height);" << std::endl;
2026-04-17 19:42:14 +09:00
2026-04-17 22:25:28 +09:00
if(p_nodes != NULL) {
2026-04-17 19:42:14 +09:00
std::string r = "";
2026-04-17 22:25:28 +09:00
for(i = 0; p_nodes[i] != NULL; i++) {
r += scan_widget_properties_header(p_nodes[i], "\t\t");
}
if(r != "") OFS << std::endl
<< r;
}
if(h_nodes != NULL) {
std::string r = "";
for(i = 0; h_nodes[i] != NULL; i++) {
r += scan_widget_handlers_header(h_nodes[i], "\t\t");
2026-04-17 19:42:14 +09:00
}
if(r != "") OFS << std::endl
<< r;
}
OFS << " };" << std::endl;
OFS << "}; // namespace MwCXX" << std::endl;
OFS << std::endl;
OFS << "#endif" << std::endl;
#undef OFS
#define OFS files["W" + name + ".cxx"]
OFS = std::ofstream("src/widget/" + lowercase(name) + ".cxx");
if(name == "OpenGL" || name == "Vulkan") OFS << "#define MW_" + uppercase(name) + "_NO_INCLUDE" << std::endl;
OFS << "#include <MwCXX/Widget/" + name + ".h>" << std::endl;
OFS << std::endl;
OFS << "MwCXX::" + name + "::" + name + "(MwWidget widget) : MwCXX::Base(widget) {" << std::endl;
2026-04-17 22:25:28 +09:00
OFS << " this->RegisterHandlers();" << std::endl;
2026-04-17 19:42:14 +09:00
OFS << "}" << std::endl;
OFS << std::endl;
OFS << "MwCXX::" + name + "::" + name + "(MwCXX::String name, MwCXX::Base* parent, int x, int y, unsigned int width, unsigned int height) : MwCXX::Base(Mw" + name + "Class, name, parent, x, y, width, height) {" << std::endl;
2026-04-17 22:25:28 +09:00
OFS << " this->RegisterHandlers();" << std::endl;
2026-04-17 19:42:14 +09:00
OFS << "}" << std::endl;
OFS << std::endl;
2026-04-17 22:25:28 +09:00
if(p_nodes != NULL) {
for(i = 0; p_nodes[i] != NULL; i++) {
OFS << scan_widget_properties_source(p_nodes[i], name);
}
}
if(h_nodes != NULL) {
for(i = 0; h_nodes[i] != NULL; i++) {
OFS << scan_widget_handlers_source(h_nodes[i], name);
}
}
OFS << "void MwCXX::" + name + "::RegisterHandlers() {" << std::endl;
if(h_nodes != NULL) {
for(i = 0; h_nodes[i] != NULL; i++) {
for(child = h_nodes[i]->first_child; child != NULL; child = child->next) {
std::string hname;
if(child->type != XL_NODE_NODE) continue;
hname = xl_get_attribute(child, "name");
OFS << " MwAddUserHandler(this->widget, MwN" + hname + "Handler, __On" + upperfirst(hname) + ", (void*)this);" << std::endl;
}
2026-04-17 19:42:14 +09:00
}
}
2026-04-17 22:25:28 +09:00
OFS << "}" << std::endl;
2026-04-17 19:42:14 +09:00
#undef OFS
2026-04-17 22:25:28 +09:00
if(p_nodes != NULL) free(p_nodes);
if(h_nodes != NULL) free(h_nodes);
2026-04-17 19:42:14 +09:00
files["objs"] << " src/widget/" + lowercase(name) + ".o";
}
static void scan_widgets(xl_node_t* node) {
xl_node_t* child = node->first_child;
while(child != NULL) {
scan_widget(child);
child = child->next;
}
}
static void base_widget() {
2026-04-17 22:25:28 +09:00
int f;
2026-04-17 19:42:14 +09:00
#define OFS files["WBaseAuto.h"]
OFS = std::ofstream("include/MwCXX/Widget/BaseAuto.h");
2026-04-17 22:25:28 +09:00
f = 0;
2026-04-17 19:42:14 +09:00
for(auto p = props.begin(); p != props.end(); p++) {
if(!p->second.common) continue;
OFS << widget_property_header(p->first);
2026-04-17 22:25:28 +09:00
f = 1;
}
if(f) OFS << std::endl;
for(auto p = handlers.begin(); p != handlers.end(); p++) {
if(!p->second.common) continue;
OFS << widget_handler_header(p->first);
2026-04-17 19:42:14 +09:00
}
#undef OFS
#define OFS files["WBaseAuto.cxx"]
OFS = std::ofstream("src/widget/baseauto.cxx");
OFS << "#include <MwCXX/Widget/Base.h>" << std::endl;
for(auto p = props.begin(); p != props.end(); p++) {
if(!p->second.common) continue;
2026-04-17 22:25:28 +09:00
OFS << widget_property_source("Base", p->first);
}
for(auto h = handlers.begin(); h != handlers.end(); h++) {
if(!h->second.common) continue;
OFS << widget_handler_source("Base", h->first);
2026-04-17 19:42:14 +09:00
}
2026-04-17 22:25:28 +09:00
OFS << "void MwCXX::Base::RegisterHandlers() {" << std::endl;
for(auto h = handlers.begin(); h != handlers.end(); h++) {
if(!h->second.common) continue;
OFS << " MwAddUserHandler(this->widget, MwN" + h->first + "Handler, __On" + upperfirst(h->first) + ", (void*)this);" << std::endl;
}
OFS << "}" << std::endl;
2026-04-17 19:42:14 +09:00
#undef OFS
files["objs"] << " src/widget/baseauto.o";
}
int main(int argc, char** argv) {
2026-04-16 15:01:47 +09:00
xemil_t* h;
2026-04-17 19:42:14 +09:00
int fail = 0;
2026-04-16 15:01:47 +09:00
2026-04-17 19:42:14 +09:00
if(argc < 2) {
2026-04-16 15:01:47 +09:00
printf("Usage: %s XML\n", argv[0]);
return 1;
}
2026-04-17 19:42:14 +09:00
locale = std::locale::classic();
2026-04-16 15:01:47 +09:00
h = xl_open_file(argv[1]);
2026-04-17 19:42:14 +09:00
if(h != NULL) {
2026-04-16 15:01:47 +09:00
h->param.new_text = 1;
if(xl_parse(h)) {
xl_node_t** nodes;
2026-04-17 19:42:14 +09:00
files["objs"] = std::ofstream("objs.mk");
2026-04-16 15:01:47 +09:00
2026-04-17 19:42:14 +09:00
files["objs"] << "OBJS +=";
2026-04-16 15:01:47 +09:00
2026-04-17 19:42:14 +09:00
if((nodes = xl_get_path(h->root, "properties")) != NULL) {
for(int i = 0; nodes[i] != NULL; i++) {
2026-04-16 15:01:47 +09:00
scan_properties(nodes[i]);
}
2026-04-17 19:42:14 +09:00
free(nodes);
}
2026-04-17 22:25:28 +09:00
if((nodes = xl_get_path(h->root, "handlers")) != NULL) {
for(int i = 0; nodes[i] != NULL; i++) {
scan_handlers(nodes[i]);
}
free(nodes);
}
2026-04-17 19:42:14 +09:00
base_widget();
if((nodes = xl_get_path(h->root, "widgets")) != NULL) {
for(int i = 0; nodes[i] != NULL; i++) {
scan_widgets(nodes[i]);
}
free(nodes);
2026-04-16 15:01:47 +09:00
}
2026-04-17 19:42:14 +09:00
files["objs"] << std::endl;
2026-04-16 15:01:47 +09:00
2026-04-17 19:42:14 +09:00
for(auto f = files.begin(); f != files.end(); f++) {
f->second.close();
}
} else {
2026-04-16 15:01:47 +09:00
fail = 1;
}
xl_close(h);
2026-04-17 19:42:14 +09:00
} else {
2026-04-16 15:01:47 +09:00
fail = 1;
}
2026-04-17 19:42:14 +09:00
if(fail) {
2026-04-16 15:01:47 +09:00
fprintf(stderr, "Failed to parse XML\n");
return 1;
}
return 0;
}