├── .gitignore
├── .travis.yml
├── CMakeLists.txt
├── History.txt
├── LICENSE
├── dist.info
├── doc
└── index.html
├── include
└── xml
│ └── Parser.h
├── readme.md
├── scripts
├── bind.lua
├── build.lua
└── doc.lua
├── src
├── Parser.cpp
├── bind
│ ├── dub
│ │ ├── dub.cpp
│ │ └── dub.h
│ ├── xml_Parser.cpp
│ └── xml_core.cpp
└── vendor
│ ├── license.txt
│ ├── manual.html
│ ├── rapidxml.hpp
│ ├── rapidxml_iterators.hpp
│ ├── rapidxml_print.hpp
│ └── rapidxml_utils.hpp
├── test
├── Parser_test.lua
├── all.lua
├── fixtures
│ ├── doxy.xml
│ ├── foo.xml
│ └── large.xml
└── xml_test.lua
├── xml-1.1.3-1.rockspec
├── xml.lua
└── xml
├── Parser.lua
└── init.lua
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.o
3 | *.so
4 | *.swp
5 | /html
6 | /build
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: erlang
2 |
3 | # Try using multiple Lua Implementations
4 | env:
5 | - LUA_VERSION='5.1' LUA="lua5.1"
6 | - LUA_VERSION='5.1' LUA="luajit" # Wee need to install lua5.1 or luarocks won't build
7 | - LUA_VERSION='5.2' LUA="lua5.2"
8 | - LUA_VERSION='5.3' LUA="lua"
9 |
10 | branches:
11 | only:
12 | - master
13 |
14 | install:
15 | - test "$LUA_VERSION" = "5.3" || sudo apt-get install lua$LUA_VERSION liblua$LUA_VERSION-dev
16 | - test "$LUA" = "luajit" && git clone http://luajit.org/git/luajit-2.0.git && cd luajit-2.0/ && sudo make install && cd .. || true
17 | - test "$LUA_VERSION" = "5.3" && wget http://www.lua.org/ftp/lua-5.3.0.tar.gz && tar xzf lua-5.3.0.tar.gz && cd lua-5.3.0 && make linux && sudo make install && cd .. || true
18 | - git clone git://github.com/keplerproject/luarocks.git
19 | - cd luarocks
20 | - ./configure --lua-version=$LUA_VERSION --versioned-rocks-dir
21 | - make build
22 | - sudo make install
23 | - cd ..
24 | # Install testing dependency
25 | - sudo luarocks-$LUA_VERSION install lut
26 | # Build module
27 | - sudo luarocks-$LUA_VERSION make
28 |
29 | # Run tests
30 | script:
31 | - $LUA -v && $LUA test/all.lua
32 |
33 | notifications:
34 | recipients:
35 | - gaspard@teti.ch
36 | email:
37 | on_success: change
38 | on_failure: always
39 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | #
2 | # MACHINE GENERATED FILE. DO NOT EDIT.
3 | #
4 | # CMake build file for xml
5 | #
6 | # This file has been generated by lut.Builder 1.2.1
7 | #
8 |
9 | cmake_minimum_required(VERSION 2.8)
10 | # --------------------------------------------------------------
11 | # xml
12 | # --------------------------------------------------------------
13 | set(MODULE_NAME xml)
14 |
15 | # Where to install Lua files
16 | if(LUA_INSTALL_DIR)
17 | set(INSTALL_PATH ${LUA_INSTALL_DIR})
18 | else(LUA_INSTALL_DIR)
19 | set(INSTALL_PATH "${CMAKE_BINARY_DIR}/lib" CACHE STRING "Install directory path")
20 | endif(LUA_INSTALL_DIR)
21 | message("INSTALL Lua 'xml' TO '${INSTALL_PATH}'")
22 |
23 | # Where to install binary modules
24 | if(LUA_INSTALL_BINDIR)
25 | set(INSTALL_BINPATH ${LUA_INSTALL_BINDIR})
26 | else(LUA_INSTALL_BINDIR)
27 | set(INSTALL_BINPATH "${CMAKE_BINARY_DIR}/lib" CACHE STRING "Install directory path")
28 | endif(LUA_INSTALL_BINDIR)
29 | message("INSTALL binary 'xml' TO '${INSTALL_BINPATH}'")
30 |
31 | # --------------------------------------------------------------
32 | # module
33 | # --------------------------------------------------------------
34 | add_custom_target(${MODULE_NAME} true)
35 |
36 |
37 | # -------- PLAT
38 | set(LINK_LIBS )
39 |
40 | if(UNIX)
41 | if(APPLE)
42 | set(PLAT "macosx")
43 | set(LINK_FLAGS "-bundle -undefined dynamic_lookup -all_load")
44 | set(LINK_LIBS "stdc++")
45 | else(APPLE)
46 | set(PLAT "linux")
47 | set(LINK_FLAGS "-shared")
48 | set(LINK_LIBS "stdc++")
49 | endif(APPLE)
50 | else(UNIX)
51 | if(WIN32)
52 | set(PLAT "win32")
53 | else(WIN32)
54 | set(PLAT "unsupported")
55 | endif(WIN32)
56 | endif(UNIX)
57 |
58 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -fPIC -O2")
59 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -fPIC -O2")
60 | if (RELEASE)
61 | add_definitions(-O2 -DNDEBUG)
62 | endif(RELEASE)
63 |
64 | # --------------------------------------------------------------
65 | # xml.core
66 | # --------------------------------------------------------------
67 | set(core "${MODULE_NAME}_core")
68 |
69 | include_directories(/usr/local/include include src/bind src/vendor)
70 |
71 | file(GLOB CORE_SOURCES src/*.c src/*.cpp src/bind/dub/*.cpp src/bind/*.cpp src/${PLAT}/*.cpp src/${PLAT}/*.mm)
72 |
73 | add_library(${core} MODULE ${CORE_SOURCES})
74 | if(LINK_LIBS)
75 | target_link_libraries(${core} ${LINK_LIBS})
76 | endif(LINK_LIBS)
77 | set_target_properties(${core}
78 | PROPERTIES OUTPUT_NAME core
79 | LINK_FLAGS ${LINK_FLAGS}
80 | PREFIX ""
81 | SUFFIX ".so"
82 | )
83 |
84 |
85 | add_dependencies(${MODULE_NAME} ${core})
86 |
87 | # --------------------------------------------------------------
88 | # install
89 | # --------------------------------------------------------------
90 | install(TARGETS ${core}
91 | DESTINATION ${INSTALL_BINPATH}/${MODULE_NAME}
92 | )
93 |
94 | # --------------------------------------------------------------
95 | # install
96 | # --------------------------------------------------------------
97 | install(DIRECTORY ${MODULE_NAME}
98 | DESTINATION ${INSTALL_PATH}
99 | )
100 |
101 |
102 |
--------------------------------------------------------------------------------
/History.txt:
--------------------------------------------------------------------------------
1 | == 1.1.3 2015-05-11
2 |
3 | * Added support for lua 5.3.
4 |
5 | == 1.1.2 2015-05-05
6 |
7 | * Fix build on Windows.
8 |
9 | == 1.1.1 2014-08-15
10 |
11 | * Fixed lub dependency information.
12 | * Using lut.Builder to update build files.
13 |
14 | == 1.1.0 2014-02-01
15 |
16 | * Changes in API to reflect yaml library. 'parse' is now 'load' and 'load'
17 | is 'loadpath'.
18 | * Fixed bindings by using latest dub binder.
19 | * Added support for CMake build.
20 |
21 | == 1.0.0 2014-01-26
22 |
23 | * Initial release.
24 | * When 'xml' tag name is missing, use 'table' as tag name.
25 | * Added option to trim whitespace.
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Lubyk is licensed under the terms of the MIT license reproduced below.
3 | This means that Lubyk is free software and can be used for both academic
4 | and commercial purposes at absolutely no cost.
5 |
6 | This project uses RapidXML Copyright (c) 2006, 2007 Marcin Kalicinski also
7 | released under the MIT license.
8 |
9 | ===============================================================================
10 |
11 | This file is part of the LUBYK project (http://lubyk.org)
12 | Copyright (c) 2007-2013 by Gaspard Bucher (http://teti.ch).
13 |
14 | rapidxml
15 | Copyright (c) 2006, 2007 Marcin Kalicinski
16 |
17 | ------------------------------------------------------------------------------
18 |
19 | Permission is hereby granted, free of charge, to any person obtaining a copy
20 | of this software and associated documentation files (the "Software"), to deal
21 | in the Software without restriction, including without limitation the rights
22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 | copies of the Software, and to permit persons to whom the Software is
24 | furnished to do so, subject to the following conditions:
25 |
26 | The above copyright notice and this permission notice shall be included in
27 | all copies or substantial portions of the Software.
28 |
29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 | THE SOFTWARE.
36 |
37 | ===============================================================================
38 |
39 |
--------------------------------------------------------------------------------
/dist.info:
--------------------------------------------------------------------------------
1 | name = "xml"
2 | version = "1.1.2"
3 |
4 | desc = "Very fast xml parser based on RapidXML"
5 | author = "Gaspard Bucher"
6 | license = "MIT"
7 | url = "http://doc.lubyk.org/xml.html"
8 | maintainer = "Gaspard Bucher"
9 |
10 | depends = {
11 | "lua >= 5.1, < 5.4",
12 | "lub >= 1.0.3, < 2",
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/doc/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | xml
5 |
6 |
7 | Online documentation
8 | doc.lubyk.org/xml.html
9 |
10 | Generate
11 | lua scripts/makedoc.lua && open html/index.html
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/include/xml/Parser.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | This file is part of the LUBYK project (http://lubyk.org)
5 | Copyright (c) 2007-2014 by Gaspard Bucher (http://teti.ch).
6 |
7 | ------------------------------------------------------------------------------
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy
10 | of this software and associated documentation files (the "Software"), to deal
11 | in the Software without restriction, including without limitation the rights
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | copies of the Software, and to permit persons to whom the Software is
14 | furnished to do so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | THE SOFTWARE.
26 |
27 | ==============================================================================
28 | */
29 |
30 | #ifndef LUBYK_INCLUDE_XML_PARSER_H_
31 | #define LUBYK_INCLUDE_XML_PARSER_H_
32 |
33 | #include "dub/dub.h" // dub::Exception
34 |
35 | namespace xml {
36 |
37 | /** Simple xml parser (singleton).
38 | */
39 | class Parser {
40 | public:
41 | enum Type {
42 | Default = 0,
43 | TrimWhitespace,
44 | NonDestructive,
45 | Fastest,
46 | };
47 |
48 | Parser(Type type = Default);
49 | ~Parser();
50 |
51 | // Receive an xml string and return a Lua table. The received string can be
52 | // modified in place.
53 | LuaStackSize load(lua_State *L);
54 | private:
55 | Type type_;
56 |
57 | class Implementation;
58 | Implementation *impl_;
59 |
60 | };
61 |
62 | } // xml
63 |
64 | #endif // LUBYK_INCLUDE_XML_PARSER_H_
65 |
66 |
67 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | xml for lua [](https://travis-ci.org/lubyk/xml)
2 | ===========
3 |
4 | Very fast and simple XML parser for Lua based on RapidXML 1.13.
5 |
6 | [Documentation](http://doc.lubyk.org/xml.html).
7 |
8 | install
9 | -------
10 |
11 | luarocks install xml
12 |
13 | install on Windows
14 | ------------------
15 |
16 | luarocks install xml CC=g++ LD=g++
17 |
--------------------------------------------------------------------------------
/scripts/bind.lua:
--------------------------------------------------------------------------------
1 | --
2 | -- Update binding files for this project
3 | --
4 | local lub = require 'lub'
5 | local dub = require 'dub'
6 |
7 | local ins = dub.Inspector {
8 | INPUT = {
9 | lub.path '|../include/xml',
10 | },
11 | --doc_dir = base .. '/tmp',
12 | --html = true,
13 | --keep_xml = true,
14 | }
15 |
16 | local binder = dub.LuaBinder()
17 |
18 | binder:bind(ins, {
19 | output_directory = lub.path '|../src/bind',
20 | -- Remove this part in included headers
21 | header_base = lub.path '|../include',
22 | -- Create a single library.
23 | single_lib = 'xml',
24 | -- Open the library with require 'xml.core' (not 'xml')
25 | luaopen = 'xml_core',
26 | })
27 |
--------------------------------------------------------------------------------
/scripts/build.lua:
--------------------------------------------------------------------------------
1 | --
2 | -- Update build files for this project
3 | --
4 | package.path = './?.lua;'..package.path
5 | package.cpath = './?.so;' ..package.cpath
6 |
7 | local lut = require 'lut'
8 | local lib = require 'xml'
9 |
10 | lut.Builder(lib):make()
11 |
--------------------------------------------------------------------------------
/scripts/doc.lua:
--------------------------------------------------------------------------------
1 | --
2 | -- Generate documentation for this project into 'html' folder
3 | --
4 | local lut = require 'lut'
5 | lut.Doc.make {
6 | sources = {
7 | 'xml',
8 | },
9 | target = 'html',
10 | format = 'html',
11 | header = [[Lubyk documentation
]],
12 | index = [=[
13 | --[[--
14 | # Lubyk documentation
15 |
16 | ## List of available modules
17 | --]]--
18 | ]=]
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/src/Parser.cpp:
--------------------------------------------------------------------------------
1 | #include "xml/Parser.h"
2 | #include "rapidxml.hpp"
3 |
4 | #include
5 |
6 |
7 | xml::Parser::Parser(Type type)
8 | : type_(type) {
9 | }
10 |
11 | xml::Parser::~Parser() {
12 | }
13 |
14 | static void parseDom(lua_State *L, rapidxml::xml_node<> *node) {
15 | lua_newtable(L);
16 | //
17 | int tbl_pos = lua_gettop(L);
18 |
19 | lua_pushlstring(L, node->name(), node->name_size());
20 | // "tag"
21 | lua_setfield(L, -2, "xml");
22 | //
23 |
24 | // Parse attributes
25 | for (rapidxml::xml_attribute<> *attr = node->first_attribute();
26 | attr; attr = attr->next_attribute()) {
27 | //
28 | lua_pushlstring(L, attr->name(), attr->name_size());
29 | // "key"
30 | lua_pushlstring(L, attr->value(), attr->value_size());
31 | // "key" "value"
32 | lua_rawset(L, tbl_pos);
33 | }
34 | //
35 |
36 | // Parse children nodes
37 | int pos = 0;
38 | for(rapidxml::xml_node<> *child = node->first_node();
39 | child; child = child->next_sibling()) {
40 | //
41 | switch(child->type()) {
42 | case rapidxml::node_element:
43 | parseDom(L, child);
44 | break;
45 | case rapidxml::node_data: // continue
46 | case rapidxml::node_cdata:
47 | lua_pushlstring(L, child->value(), child->value_size());
48 | break;
49 | case rapidxml::node_comment: // continue
50 | case rapidxml::node_declaration: // continue
51 | case rapidxml::node_doctype: // continue
52 | case rapidxml::node_pi: // continue
53 | default:
54 | // ignore
55 | continue;
56 | }
57 |
58 | //
59 | lua_rawseti(L, tbl_pos, ++pos);
60 | }
61 | //
62 | }
63 |
64 | // Simple helper class to handle copy and auto freeing.
65 | struct String {
66 | char *text_;
67 | String(const char *text, size_t len) : text_(NULL) {
68 | text_ = (char*)malloc(len * sizeof(char));
69 | if (text_) {
70 | strncpy(text_, text, len);
71 | }
72 | }
73 |
74 | ~String() {
75 | if (text_) {
76 | free(text_);
77 | }
78 | }
79 | };
80 |
81 | // Receive an xml string and return a Lua table.
82 | LuaStackSize xml::Parser::load(lua_State *L) {
83 | size_t len;
84 | const char *xml_str = dub::checklstring(L, 2, &len);
85 | ++len; // for \0 termination
86 | rapidxml::xml_document<> doc; // character type defaults to char
87 |
88 | switch(type_) {
89 | case NonDestructive:
90 | doc.parse(const_cast(xml_str));
91 | parseDom(L, doc.first_node());
92 | return 1;
93 | case TrimWhitespace: {
94 | // Parsing is destructive: make an exception safe copy.
95 | String text(xml_str, len);
96 | if (!text.text_) return 0;
97 | doc.parse(text.text_);
98 | parseDom(L, doc.first_node());
99 | //
100 | return 1;
101 | }
102 | case Default: // continue
103 | default: {
104 | // Parsing is destructive: make an exception safe copy.
105 | String text(xml_str, len);
106 | if (!text.text_) return 0;
107 | doc.parse(text.text_);
108 | parseDom(L, doc.first_node());
109 | //
110 | return 1;
111 | }
112 | }
113 | }
114 |
115 |
--------------------------------------------------------------------------------
/src/bind/dub/dub.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | This file is part of the DUB bindings generator (http://lubyk.org/dub)
5 | Copyright (c) 2007-2012 by Gaspard Bucher (http://teti.ch).
6 |
7 | ------------------------------------------------------------------------------
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy
10 | of this software and associated documentation files (the "Software"), to deal
11 | in the Software without restriction, including without limitation the rights
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | copies of the Software, and to permit persons to whom the Software is
14 | furnished to do so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | THE SOFTWARE.
26 |
27 | ==============================================================================
28 | */
29 | #include "dub/dub.h"
30 |
31 | #include // malloc
32 | #include // strlen strcmp
33 | #include // assert
34 |
35 | #define DUB_EXCEPTION_BUFFER_SIZE 256
36 | #define TYPE_EXCEPTION_MSG "expected %s, found %s"
37 | #define TYPE_EXCEPTION_SMSG "expected %s, found %s (using super)"
38 | #define DEAD_EXCEPTION_MSG "using deleted %s"
39 | #define DUB_MAX_IN_SHIFT 4294967296
40 |
41 | #if LUA_VERSION_NUM > 501
42 | #define DUB_LUA_FIVE_TWO
43 | #else
44 | #define DUB_LUA_FIVE_ONE
45 | #endif
46 |
47 | #define DUB_INIT_CODE "local class = ...\nif class.new then\nsetmetatable(class, {\n __call = function(lib, ...)\n return lib.new(...)\n end,\n})\nend\n"
48 | #define DUB_INIT_ERR "[string \"Dub init code\"]"
49 | // Define the callback error function. We store the error function in
50 | // self._errfunc so that it can also be used from Lua (this error function
51 | // captures the currently global 'print' which is useful for remote network objects).
52 | #define DUB_ERRFUNC "local self, print = ...\n\
53 | local errfunc = function(...)\n\
54 | local err = self.error\n\
55 | if err then\n\
56 | err(self, ...)\n\
57 | else\n\
58 | print('error', ...)\n\
59 | end\n\
60 | end\n\
61 | self._errfunc = errfunc\n\
62 | return errfunc"
63 |
64 | using namespace dub;
65 |
66 | void dub::printStack(lua_State *L, const char *msg) {
67 | int top = lua_gettop(L);
68 | if (msg) {
69 | printf("============ %s (%i)\n", msg, top);
70 | } else {
71 | printf("============ (%i)\n", top);
72 | }
73 | for(int i=1; i<=top; ++i) {
74 | if (lua_isstring(L, i)) {
75 | printf(" \"%s\"\n", lua_tostring(L, i));
76 | } else {
77 | printf(" %s\n", lua_typename(L, lua_type(L, i)));
78 | }
79 |
80 | }
81 | printf("===============================\n");
82 | }
83 |
84 | // ======================================================================
85 | // =============================================== dub::Exception
86 | // ======================================================================
87 | Exception::Exception(const char *format, ...) {
88 | char buffer[DUB_EXCEPTION_BUFFER_SIZE];
89 | va_list args;
90 | va_start(args, format);
91 | vsnprintf(buffer, DUB_EXCEPTION_BUFFER_SIZE, format, args);
92 | va_end(args);
93 | message_ = buffer;
94 | }
95 |
96 | Exception::~Exception() throw() {}
97 |
98 | const char* Exception::what() const throw() {
99 | return message_.c_str();
100 | }
101 |
102 |
103 | TypeException::TypeException(lua_State *L, int narg, const char *type, bool is_super) :
104 | Exception(is_super ? TYPE_EXCEPTION_SMSG : TYPE_EXCEPTION_MSG, type, luaL_typename(L, narg)) {}
105 |
106 | // ======================================================================
107 | // =============================================== dub::Object
108 | // ======================================================================
109 | void Object::dub_pushobject(lua_State *L, void *ptr, const char *tname, bool gc) {
110 | DubUserdata *udata = (DubUserdata*)lua_newuserdata(L, sizeof(DubUserdata));
111 | udata->ptr = ptr;
112 | udata->gc = gc;
113 | if (dub_userdata_) {
114 | // We already have a userdata. Push a new userdata (copy to this item,
115 | // should never gc).
116 | assert(!gc);
117 | udata->gc = false;
118 | } else {
119 | // First initialization.
120 | dub_userdata_ = udata;
121 | }
122 | // the userdata is now on top of the stack
123 |
124 | // set metatable (contains methods)
125 | lua_getfield(L, LUA_REGISTRYINDEX, tname);
126 | lua_setmetatable(L, -2);
127 | //
128 | }
129 |
130 | // ======================================================================
131 | // =============================================== dub::Thread
132 | // ======================================================================
133 | void Thread::dub_pushobject(lua_State *L, void *ptr, const char *tname, bool gc) {
134 | if (dub_L) {
135 | if (!strcmp(tname, dub_typename_)) {
136 | // Pushing same type again.
137 |
138 | // We do not care about gc being false here since we share the same userdata
139 | // object.
140 | // push self
141 | lua_pushvalue(dub_L, 1);
142 | lua_xmove(dub_L, L, 1);
143 | //
144 | } else {
145 | // Type cast.
146 | assert(!gc);
147 | dub::pushudata(L, ptr, tname, gc);
148 | //
149 | }
150 | return;
151 | }
152 |
153 | // initialization
154 |
155 | //--=============================================== setup super
156 | lua_newtable(L);
157 | //
158 | Object::dub_pushobject(L, ptr, tname, gc);
159 | //
160 | dub_typename_ = tname;
161 | lua_pushlstring(L, "super", 5);
162 | // 'super'
163 | lua_pushvalue(L, -2);
164 | // 'super'
165 | lua_rawset(L, -4); // .super =
166 | //
167 |
168 | //--=============================================== setup metatable on self
169 | lua_getfield(L, LUA_REGISTRYINDEX, tname);
170 | //
171 | lua_setmetatable(L, -3); // setmetatable(self, mt)
172 | //
173 |
174 | //--=============================================== setup lua thread
175 | // Create env table used for garbage collection protection.
176 | lua_newtable(L);
177 | //
178 | lua_pushvalue(L, -1);
179 | //
180 | #ifdef DUB_LUA_FIVE_ONE
181 | if (!lua_setfenv(L, -3)) { // setfenv(udata, env)
182 | //
183 | lua_pop(L, 3);
184 | //
185 | throw Exception("Could not set userdata env on '%s'.", lua_typename(L, lua_type(L, -3)));
186 | }
187 | #else
188 | lua_setuservalue(L, -3);
189 | //
190 | #endif
191 |
192 | //
193 | dub_L = lua_newthread(L);
194 | //
195 |
196 | // Store the thread in the userdata environment table so it is not
197 | // garbage collected too soon.
198 | luaL_ref(L, -2);
199 | //
200 |
201 | //--=============================================== prepare error function
202 | int error = luaL_loadbuffer(L, DUB_ERRFUNC, strlen(DUB_ERRFUNC), "Dub error function");
203 | if (error) {
204 | throw Exception("Error evaluating error function code (%s).", lua_tostring(L, -1));
205 | }
206 | // (errloader)
207 |
208 | lua_pushvalue(L, -4);
209 | // (errloader)
210 |
211 | #ifdef DUB_LUA_FIVE_ONE
212 | lua_getfield(L, LUA_GLOBALSINDEX, "print");
213 | #else
214 | lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
215 | // <_G>
216 | lua_getfield(L, -1, "print");
217 | // (errloader) <_G> (print)
218 | lua_remove(L, -2);
219 | #endif
220 |
221 | // (errloader) (print)
222 |
223 | error = lua_pcall(L, 2, 1, 0);
224 | if (error) {
225 | throw Exception("Error executing error function code (%s).", lua_tostring(L, -1));
226 | }
227 |
228 |
229 | //
230 | lua_remove(L, -2);
231 | //
232 | lua_remove(L, -2);
233 | //
234 |
235 | //--=============================================== prepare thread stack
236 | // Transfer a copy of to thread stack
237 | lua_pushvalue(L, -2);
238 | //
239 | lua_pushvalue(L, -2);
240 | //
241 | lua_xmove(L, dub_L, 2);
242 | lua_pop(L, 1);
243 |
244 | // dub_L:
245 | // L:
246 | }
247 |
248 | bool Thread::dub_pushcallback(const char *name) const {
249 | lua_State *L = const_cast(dub_L);
250 | lua_getfield(L, 1, name);
251 | if (lua_isnil(L, -1)) {
252 | lua_pop(L, 1);
253 | return false;
254 | } else {
255 | lua_pushvalue(L, 1);
256 | // ...
257 | return true;
258 | }
259 | }
260 |
261 | void Thread::dub_pushvalue(const char *name) const {
262 | lua_State *L = const_cast(dub_L);
263 | lua_getfield(L, 1, name);
264 | }
265 |
266 | bool Thread::dub_call(int param_count, int retval_count) const {
267 | lua_State *L = const_cast(dub_L);
268 | int status = lua_pcall(L, param_count, retval_count, 2);
269 | if (status) {
270 | if (status == LUA_ERRRUN) {
271 | // failure properly handled by the error handler
272 | } else if (status == LUA_ERRMEM) {
273 | // memory allocation failure
274 | fprintf(stderr, "Memory allocation failure (%s).\n", lua_tostring(dub_L, -1));
275 | } else {
276 | // error in error handler
277 | fprintf(stderr, "Error in error handler (%s).\n", lua_tostring(dub_L, -1));
278 | }
279 | lua_pop(dub_L, 1);
280 | return false;
281 | }
282 | return true;
283 | }
284 |
285 |
286 |
287 |
288 | // ======================================================================
289 | // =============================================== dub::error
290 | // ======================================================================
291 | // This calls lua_Error after preparing the error message with line
292 | // and number.
293 | int dub::error(lua_State *L) {
294 | // ...
295 | luaL_where(L, 1);
296 | // ...
297 | // Does it match 'Dub init code' ?
298 | const char *w = lua_tostring(L, -1);
299 | if (!strncmp(w, DUB_INIT_ERR, strlen(DUB_INIT_ERR))) {
300 | // error in ctor, show calling place, not dub init code.
301 | lua_pop(L, 1);
302 | luaL_where(L, 2);
303 | }
304 | // ...
305 | lua_pushvalue(L, -2);
306 | // ...
307 | lua_remove(L, -3);
308 | // ...
309 | lua_concat(L, 2);
310 | return lua_error(L);
311 | }
312 |
313 |
314 |
315 |
316 | // ======================================================================
317 | // =============================================== dub::protect
318 | // ======================================================================
319 |
320 | // TODO: Can we make this faster ?
321 | inline void push_own_env(lua_State *L, int ud) {
322 | #ifdef DUB_LUA_FIVE_ONE
323 | lua_getfenv(L, ud);
324 | // ... ...
325 | lua_pushstring(L, ".");
326 | // ... ... "."
327 | lua_rawget(L, -2); // ["."]
328 | // ... ... ?>
329 | if (!lua_rawequal(L, -1, ud)) {
330 | // ... ...
331 | // does not have it's own env table
332 | lua_pop(L, 2);
333 | // ... ...
334 | #else
335 | lua_getuservalue(L, ud);
336 | // ... ...
337 | if (lua_isnil(L, -1)) {
338 | lua_pop(L, 1);
339 | #endif
340 | // ... ...
341 | // Create env table
342 | lua_newtable(L);
343 | // ... ...
344 | lua_pushstring(L, ".");
345 | // ... ... "."
346 | lua_pushvalue(L, ud);
347 | // ... ... "."
348 | lua_rawset(L, -3); // env["."] = udata
349 | // ... ...
350 | lua_pushvalue(L, -1);
351 | // ... ...
352 | #ifdef DUB_LUA_FIVE_ONE
353 | if (!lua_setfenv(L, ud)) {
354 | luaL_error(L, "Could not set userdata env on '%s'.", lua_typename(L, lua_type(L, ud)));
355 | }
356 | #else
357 | lua_setuservalue(L, ud);
358 | #endif
359 | // ... ...
360 | } else {
361 | // ... ...
362 | // has its own env table
363 | lua_pop(L, 1);
364 | // ... ...
365 | }
366 | }
367 |
368 | void dub::protect(lua_State *L, int owner, int original, const char *key) {
369 | // Point to original to avoid original gc before owner.
370 | push_own_env(L, owner);
371 | // ...
372 | lua_pushvalue(L, original);
373 | // ...
374 | lua_setfield(L, -2, key); // env["key"] =
375 | // ...
376 | lua_pop(L, 1);
377 | // ...
378 | }
379 |
380 | // ======================================================================
381 | // =============================================== dub::pushudata
382 | // ======================================================================
383 |
384 | void dub::pushudata(lua_State *L, const void *cptr, const char *tname, bool gc) {
385 | // To avoid users spending time with const issues.
386 | void *ptr = const_cast(cptr);
387 | // If anything is changed here, it must be reflected in dub::Object::dub_pushobject.
388 | DubUserdata *userdata = (DubUserdata*)lua_newuserdata(L, sizeof(DubUserdata));
389 | userdata->ptr = ptr;
390 | if (!gc) {
391 | // Point to original (self) to avoid original gc.
392 | dub::protect(L, lua_gettop(L), 1, "_");
393 | }
394 |
395 | userdata->gc = gc;
396 |
397 | // the userdata is now on top of the stack
398 | luaL_getmetatable(L, tname);
399 | if (lua_isnil(L, -1)) {
400 | lua_pop(L, 1);
401 | // create empty metatable on the fly for opaque types.
402 | luaL_newmetatable(L, tname);
403 | }
404 | //
405 |
406 | // set metatable (contains methods)
407 | lua_setmetatable(L, -2);
408 | }
409 |
410 | // ======================================================================
411 | // =============================================== dub::check ...
412 | // ======================================================================
413 | // These methods are slight adaptations from luaxlib.c
414 | // Copyright (C) 1994-2008 Lua.org, PUC-Rio.
415 |
416 | lua_Number dub::checknumber(lua_State *L, int narg) noexcept(false) {
417 | #ifdef DUB_LUA_FIVE_ONE
418 | lua_Number d = lua_tonumber(L, narg);
419 | if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */
420 | throw TypeException(L, narg, lua_typename(L, LUA_TNUMBER));
421 | return d;
422 | #else
423 | int isnum = 0;
424 | lua_Number d = lua_tonumberx(L, narg, &isnum);
425 | if (!isnum)
426 | throw TypeException(L, narg, lua_typename(L, LUA_TNUMBER));
427 | return d;
428 | #endif
429 | }
430 |
431 | lua_Integer dub::checkinteger(lua_State *L, int narg) noexcept(false) {
432 | #ifdef DUB_LUA_FIVE_ONE
433 | lua_Integer d = lua_tointeger(L, narg);
434 | if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */
435 | throw TypeException(L, narg, lua_typename(L, LUA_TNUMBER));
436 | return d;
437 | #else
438 | int isnum = 0;
439 | lua_Integer d = lua_tointegerx(L, narg, &isnum);
440 | if (!isnum)
441 | throw TypeException(L, narg, lua_typename(L, LUA_TNUMBER));
442 | return d;
443 | #endif
444 | }
445 |
446 | const char *dub::checklstring(lua_State *L, int narg, size_t *len) noexcept(false) {
447 | const char *s = lua_tolstring(L, narg, len);
448 | if (!s) throw TypeException(L, narg, lua_typename(L, LUA_TSTRING));
449 | return s;
450 | }
451 |
452 | void **dub::checkudata(lua_State *L, int ud, const char *tname, bool keep_mt) noexcept(false) {
453 | void **p = (void**)lua_touserdata(L, ud);
454 | if (p != NULL) { /* value is a userdata? */
455 | if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
456 | lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */
457 | if (lua_rawequal(L, -1, -2)) {
458 | // same (correct) metatable
459 | if (!keep_mt) {
460 | lua_pop(L, 2);
461 | } else {
462 | // keep 1 metatable on top (needed by bindings)
463 | lua_pop(L, 1);
464 | }
465 | if (!*p) {
466 | throw dub::Exception(DEAD_EXCEPTION_MSG, tname);
467 | }
468 | return p;
469 | }
470 | }
471 | }
472 | throw TypeException(L, ud, tname); /* else error */
473 | return NULL; /* to avoid warnings */
474 | }
475 |
476 |
477 | static inline void **dub_cast_ud(lua_State *L, int ud, const char *tname) {
478 | // .. ...
479 | lua_pop(L, 1);
480 | // ... ...
481 | // TODO: optmize by putting this cast value in the registry.
482 | lua_pushlstring(L, "_cast_", 6);
483 | // ... ... "_cast_"
484 | lua_rawget(L, -2);
485 | if (lua_isfunction(L, -1)) {
486 | lua_pushvalue(L, ud);
487 | lua_pushstring(L, tname);
488 | // ... ... cast_func "OtherType"
489 | lua_call(L, 2, 1);
490 | // ... ...
491 | void **p = (void**)lua_touserdata(L, -1);
492 | if (p != NULL) {
493 | // done
494 | return p;
495 | }
496 | }
497 |
498 | // ... ... nil
499 | // Does not change stack size (only last element).
500 | return NULL;
501 | }
502 |
503 | static inline void **getsdata(lua_State *L, int ud, const char *tname, bool keep_mt) noexcept(false) {
504 | void **p = (void**)lua_touserdata(L, ud);
505 | if (p != NULL) { /* value is a userdata? */
506 | if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
507 | lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */
508 | if (lua_rawequal(L, -1, -2)) {
509 | // same (correct) metatable
510 | lua_pop(L, keep_mt ? 1 : 2);
511 | } else {
512 | p = dub_cast_ud(L, ud, tname);
513 | // ... ...
514 | if (p && keep_mt) {
515 | lua_remove(L, -2);
516 | } else {
517 | lua_pop(L, 2);
518 | }
519 | }
520 | }
521 | } else if (lua_istable(L, ud)) {
522 | if (ud < 0) {
523 | ud = lua_gettop(L) + 1 + ud;
524 | }
525 | // get p from super
526 | // ... ...
527 | // TODO: optimize by storing key in registry ?
528 | lua_pushlstring(L, "super", 5);
529 | // ... ... 'super'
530 | lua_rawget(L, ud);
531 | // ... ...
532 | p = (void**)lua_touserdata(L, -1);
533 | if (p != NULL) {
534 | // ... ...
535 | if (lua_getmetatable(L, -1)) { /* does it have a metatable? */
536 | // ... ...
537 | lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */
538 | // ... ...
539 | if (lua_rawequal(L, -1, -2)) {
540 | // same (correct) metatable
541 | lua_remove(L, -3);
542 | // ... ...
543 | lua_pop(L, keep_mt ? 1 : 2);
544 | } else {
545 | lua_remove(L, -3);
546 | // ... ...
547 | p = dub_cast_ud(L, ud, tname);
548 | // ... ...
549 | if (p && keep_mt) {
550 | lua_remove(L, -2);
551 | // ... ...
552 | } else {
553 | lua_pop(L, 2);
554 | // ... ...
555 | }
556 | }
557 | } else {
558 | lua_pop(L, 1);
559 | // ... ...
560 | }
561 | } else {
562 | lua_pop(L, 1);
563 | // ... ...
564 | }
565 | }
566 | return p;
567 | }
568 |
569 | void **dub::checksdata_n(lua_State *L, int ud, const char *tname, bool keep_mt) {
570 | void **p = getsdata(L, ud, tname, keep_mt);
571 | if (!p) {
572 | luaL_error(L, TYPE_EXCEPTION_MSG, tname, luaL_typename(L, ud));
573 | } else if (!*p) {
574 | // dead object
575 | luaL_error(L, DEAD_EXCEPTION_MSG, tname);
576 | }
577 | return p;
578 | }
579 |
580 | void **dub::issdata(lua_State *L, int ud, const char *tname, int type) {
581 | if (type == LUA_TUSERDATA || type == LUA_TTABLE) {
582 | void **p = getsdata(L, ud, tname, false);
583 | if (!p) {
584 | return NULL;
585 | } else if (!*p) {
586 | // dead object
587 | throw dub::Exception(DEAD_EXCEPTION_MSG, tname);
588 | } else {
589 | return p;
590 | }
591 | } else {
592 | return NULL;
593 | }
594 | }
595 |
596 | void **dub::checksdata(lua_State *L, int ud, const char *tname, bool keep_mt) noexcept(false) {
597 | void **p = getsdata(L, ud, tname, keep_mt);
598 | if (!p) {
599 | throw dub::TypeException(L, ud, tname);
600 | } else if (!*p) {
601 | // dead object
602 | throw dub::Exception(DEAD_EXCEPTION_MSG, tname);
603 | }
604 | return p;
605 | }
606 |
607 | void **dub::checksdata_d(lua_State *L, int ud, const char *tname) noexcept(false) {
608 | void **p = getsdata(L, ud, tname, false);
609 | if (!p) {
610 | throw dub::TypeException(L, ud, tname);
611 | }
612 | // do not check for dead objects
613 | return p;
614 | }
615 |
616 | // ======================================================================
617 | // =============================================== dub::setup
618 | // ======================================================================
619 |
620 | void dub::setup(lua_State *L, const char *type_name) {
621 | // meta-table should be on top
622 | //
623 | lua_getfield(L, -1, "__index");
624 | if (lua_isnil(L, -1)) {
625 | lua_pop(L, 1);
626 | lua_pushvalue(L, -1);
627 | // .__index =
628 | lua_setfield(L, -2, "__index");
629 | } else {
630 | // We already have a custom __index metamethod.
631 | lua_pop(L, 1);
632 | }
633 | //
634 | lua_pushstring(L, type_name);
635 | // "type_name"
636 | // ."type" = "type_name"
637 | lua_setfield(L, -2, "type");
638 |
639 | //
640 |
641 | // Setup the __call meta-table with an upvalue
642 | // printf("%s\n", DUB_INIT_CODE);
643 | /*
644 | local class = ...
645 | -- new can be nil for abstract types
646 | if class.new then
647 | setmetatable(class, {
648 | __call = function(lib, ...)
649 | -- We could keep lib.new in an upvalue but this
650 | -- prevents rewriting class.new in Lua which is
651 | -- very useful.
652 | return lib.new(...)
653 | end,
654 | })
655 | end
656 | */
657 | int error = luaL_loadbuffer(L, DUB_INIT_CODE, strlen(DUB_INIT_CODE), "Dub init code");
658 | if (error) {
659 | fprintf(stderr, "%s", lua_tostring(L, -1));
660 | lua_pop(L, 1); /* pop error message from the stack */
661 | } else {
662 | //
663 | lua_pushvalue(L, -2);
664 | //
665 | error = lua_pcall(L, 1, 0, 0);
666 | if (error) {
667 | fprintf(stderr, "%s", lua_tostring(L, -1));
668 | lua_pop(L, 1); /* pop error message from the stack */
669 | }
670 | }
671 | // free(lua_code);
672 | //
673 | }
674 |
675 | int dub::hash(const char *str, int sz) {
676 | unsigned int h = 0;
677 | int c;
678 |
679 | while ( (c = *str++) ) {
680 | // FIXME: integer constant is too large for 'long' type
681 | unsigned int h1 = (h << 6) % DUB_MAX_IN_SHIFT;
682 | unsigned int h2 = (h << 16) % DUB_MAX_IN_SHIFT;
683 | h = c + h1 + h2 - h;
684 | h = h % DUB_MAX_IN_SHIFT;
685 | }
686 | return h % sz;
687 | }
688 |
689 | // register constants in the table at the top
690 | void dub::register_const(lua_State *L, const dub::const_Reg*l) {
691 | for (; l->name; l++) {
692 | // push each constant into the table at top
693 | lua_pushnumber(L, l->value);
694 | lua_setfield(L, -2, l->name);
695 | }
696 | }
697 |
698 | // This is called whenever we ask for obj:deleted() in Lua
699 | int dub::isDeleted(lua_State *L) {
700 | void **p = (void**)lua_touserdata(L, 1);
701 | if (p == NULL && lua_istable(L, 1)) {
702 | // get p from super
703 | //
704 | // TODO: optimize by storing key in registry ?
705 | lua_pushlstring(L, "super", 5);
706 | // 'super'
707 | lua_rawget(L, 1);
708 | //
709 | p = (void**)lua_touserdata(L, 2);
710 | lua_pop(L, 1);
711 | //
712 | }
713 | lua_pushboolean(L, p && !*p);
714 | return 1;
715 | }
716 |
717 | // Compatibility with luaL_register on lua 5.1 and 5.2
718 | void dub::fregister(lua_State *L, const luaL_Reg *l) {
719 | #ifdef DUB_LUA_FIVE_ONE
720 | luaL_register(L, NULL, l);
721 | #else
722 | luaL_setfuncs(L, l, 0);
723 | #endif
724 | }
725 |
726 |
727 |
--------------------------------------------------------------------------------
/src/bind/dub/dub.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | This file is part of the DUB bindings generator (http://lubyk.org/dub)
5 | Copyright (c) 2007-2012 by Gaspard Bucher (http://teti.ch).
6 |
7 | ------------------------------------------------------------------------------
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy
10 | of this software and associated documentation files (the "Software"), to deal
11 | in the Software without restriction, including without limitation the rights
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | copies of the Software, and to permit persons to whom the Software is
14 | furnished to do so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | THE SOFTWARE.
26 |
27 | ==============================================================================
28 | */
29 | #ifndef DUB_BINDING_GENERATOR_DUB_H_
30 | #define DUB_BINDING_GENERATOR_DUB_H_
31 |
32 | #include // strlen strcmp
33 |
34 | #ifndef DUB_ASSERT_KEY
35 | #define DUB_ASSERT_KEY(k, m) strcmp(k, m)
36 | // Use this to avoid the overhead of strcmp in get/set of public attributes.
37 | // if you avoid strcmp, bad keys can map to any other key.
38 | //#define DUB_ASSERT_KEY(k, m) false
39 | #endif
40 | #define KEY_EXCEPTION_MSG "invalid key '%s'"
41 |
42 | typedef int LuaStackSize;
43 |
44 | #ifndef DUB_EXPORT
45 | #ifdef _WIN32
46 | #define DUB_EXPORT extern "C" __declspec(dllexport)
47 | #else
48 | #define DUB_EXPORT extern "C"
49 | #endif
50 | #endif
51 |
52 | #ifdef __cplusplus
53 | extern "C" {
54 | #endif
55 | // We need C linkage because lua lib is compiled as C code
56 | #include
57 | #include
58 | #ifdef __cplusplus
59 | }
60 | #endif
61 |
62 | #include // std::string for Exception
63 | #include // std::exception
64 |
65 | // Helpers to check for explicit 'false' or 'true' return values.
66 | #define lua_isfalse(L,i) (lua_isboolean(L,i) && !lua_toboolean(L,i))
67 | #define lua_istrue(L,i) (lua_isboolean(L,i) && lua_toboolean(L,i))
68 | #define luaL_checkboolean(L,n) (lua_toboolean(L,n))
69 |
70 | struct DubUserdata {
71 | void *ptr;
72 | bool gc;
73 | };
74 |
75 | // ======================================================================
76 | // =============================================== dub::Exception
77 | // ======================================================================
78 | namespace dub {
79 |
80 | /** All exceptions raised by dub::check.. are instances of this class. All
81 | * exceptions deriving from std::exception have their message displayed
82 | * in Lua (through lua_error).
83 | */
84 | class Exception : public std::exception {
85 | std::string message_;
86 | public:
87 | explicit Exception(const char *format, ...);
88 | ~Exception() throw();
89 | const char* what() const throw();
90 | };
91 |
92 | class TypeException : public Exception {
93 | public:
94 | explicit TypeException(lua_State *L, int narg, const char *type, bool is_super = false);
95 | };
96 |
97 | /** This class allows an object to be deleted from either C++ or Lua.
98 | * When Lua deletes the object, dub_destroy is called. When C++ deletes
99 | * the object, the related userdata is invalidated.
100 | */
101 | class Object {
102 | public:
103 | Object() : dub_userdata_(NULL) {}
104 |
105 | /** The destructor marks the userdata as deleted so that Lua no
106 | * longer tries to access it.
107 | */
108 | virtual ~Object() {
109 | if (dub_userdata_) {
110 | // Protect from gc.
111 | dub_userdata_->gc = false;
112 | // Invalidate Lua userdata.
113 | dub_userdata_->ptr = NULL;
114 | }
115 | }
116 |
117 | /** This is called on object instanciation by dub instead of
118 | * dub::pushudata to setup dub_userdata_.
119 | *
120 | */
121 | void dub_pushobject(lua_State *L, void *ptr, const char *type_name, bool gc = true);
122 |
123 | protected:
124 | /** Pointer to the userdata. *userdata => pointer to C++ object.
125 | */
126 | DubUserdata *dub_userdata_;
127 | };
128 |
129 | /** This class creates a 'self' table and prepares a thread
130 | * that can be used for callbacks from C++ to Lua.
131 | */
132 | class Thread : public Object {
133 | public:
134 | Thread()
135 | : dub_L(NULL) {}
136 | /** This is called on object instanciation by dub to create the lua
137 | * thread, prepare the table and setup metamethods. This is
138 | * called instead of dub::pushudata.
139 | *
140 | */
141 | void dub_pushobject(lua_State *L, void *ptr, const char *type_name, bool gc = true);
142 |
143 | /** Push function 'name' found in on the stack with as
144 | * first argument.
145 | *
146 | * Constness is there to make it easy to implement callbacks like
147 | * int rowCount() const, without requiring users to fiddle with constness
148 | * which is not a notion part of Lua anyway.
149 | */
150 | bool dub_pushcallback(const char *name) const;
151 |
152 | /** Push any lua value from self on the stack.
153 | */
154 | void dub_pushvalue(const char *name) const;
155 |
156 | /** Execute the protected call. If an error occurs, dub tries to find
157 | * an 'error' function in and calls this function with the
158 | * error string. If no error function is found, the error message is
159 | * just printed out to stderr.
160 | */
161 | bool dub_call(int param_count, int retval_count) const;
162 |
163 | /** Lua thread that contains on stack position 1. This lua thread
164 | * is public to ease object state manipulation from C++ (but stack *must
165 | * not* be messed up).
166 | */
167 | lua_State *dub_L;
168 |
169 | protected:
170 | /** Type name (allows faster check for cast).
171 | */
172 | const char *dub_typename_;
173 | };
174 |
175 | // ======================================================================
176 | // =============================================== dub::pushclass
177 | // ======================================================================
178 |
179 | // To ease storing a LuaRef in a void* pointer.
180 | struct DubRef {
181 | int ref;
182 |
183 | static int set(lua_State *L, void **ptr, int id) {
184 | if (lua_isnil(L, id)) {
185 | cleanup(L, ptr);
186 | } else {
187 | DubRef *ref;
188 | if (*ptr) {
189 | ref = (DubRef*)*ptr;
190 | luaL_unref(L, LUA_REGISTRYINDEX, ref->ref);
191 | } else {
192 | ref = new DubRef();
193 | *ptr = ref;
194 | }
195 | ref->ref = luaL_ref(L, LUA_REGISTRYINDEX);
196 | }
197 | return 0;
198 | }
199 |
200 | static int push(lua_State *L, void *ptr) {
201 | if (ptr) {
202 | DubRef *ref = (DubRef*)ptr;
203 | lua_rawgeti(L, LUA_REGISTRYINDEX, ref->ref);
204 | return 1;
205 | } else {
206 | return 0;
207 | }
208 | }
209 |
210 | static void cleanup(lua_State *L, void **ptr) {
211 | if (*ptr) {
212 | DubRef *ref = (DubRef*)*ptr;
213 | luaL_unref(L, LUA_REGISTRYINDEX, ref->ref);
214 | delete ref;
215 | *ptr = NULL;
216 | }
217 | }
218 | };
219 |
220 | /** Push a custom type on the stack.
221 | * Since the value is passed as a pointer, we assume it has been created
222 | * using 'new' and Lua can safely call delete when it needs to garbage-
223 | * -collect it.
224 | *
225 | * Constness: we const cast all passed values to ease passing read-only
226 | * arguments without requiring users to fiddle with constness which is not
227 | * a notion part of Lua anyway.
228 | */
229 | void pushudata(lua_State *L, const void *ptr, const char *type_name, bool gc = true);
230 |
231 | template
232 | struct DubFullUserdata {
233 | T *ptr;
234 | T obj;
235 | };
236 |
237 | template
238 | void pushfulldata(lua_State *L, const T &obj, const char *type_name) {
239 | DubFullUserdata *copy = (DubFullUserdata*)lua_newuserdata(L, sizeof(DubFullUserdata));
240 | copy->obj = obj;
241 | // now **copy gives back the object.
242 | copy->ptr = ©->obj;
243 |
244 | // the userdata is now on top of the stack
245 |
246 | // set metatable (contains methods)
247 | luaL_getmetatable(L, type_name);
248 | lua_setmetatable(L, -2);
249 | }
250 |
251 | template
252 | void pushclass(lua_State *L, const T &obj, const char *type_name) {
253 | T *copy = new T(obj);
254 | pushudata(L, (void*)copy, type_name);
255 | }
256 |
257 | // ======================================================================
258 | // =============================================== dub::pushclass2
259 | // ======================================================================
260 |
261 | /** Push a custom type on the stack and give it the pointer to the userdata.
262 | * Passing the userdata enables early deletion from C++ that safely
263 | * invalidates the userdatum by calling
264 | */
265 | template
266 | void pushclass2(lua_State *L, T *ptr, const char *type_name) {
267 | T **userdata = (T**)lua_newuserdata(L, sizeof(T*));
268 | *userdata = ptr;
269 |
270 | // Store pointer in class so that it can set it to NULL on destroy with
271 | // *userdata = NULL
272 | ptr->luaInit((void**)userdata);
273 | //
274 | luaL_getmetatable(L, type_name);
275 | //
276 | lua_setmetatable(L, -2);
277 | //
278 | }
279 |
280 | // ======================================================================
281 | // =============================================== constants
282 | // ======================================================================
283 |
284 | typedef struct const_Reg {
285 | const char *name;
286 | double value;
287 | } const_Reg;
288 |
289 | // register constants in the table at the top
290 | void register_const(lua_State *L, const const_Reg *l);
291 |
292 | // ======================================================================
293 | // =============================================== dub_check ...
294 | // ======================================================================
295 |
296 | // These provide the same funcionality as their equivalent luaL_check... but they
297 | // throw std::exception which can be caught (eventually to call lua_error).
298 | lua_Number checknumber(lua_State *L, int narg) noexcept(false);
299 | lua_Integer checkinteger(lua_State *L, int narg) noexcept(false);
300 | const char *checklstring(lua_State *L, int narg, size_t *len) noexcept(false);
301 | void **checkudata(lua_State *L, int ud, const char *tname, bool keep_mt = false) noexcept(false);
302 |
303 | // Super aware userdata calls (finds userdata inside provided table with table.super).
304 | void **checksdata(lua_State *L, int ud, const char *tname, bool keep_mt = false) noexcept(false);
305 | // Super aware userdata calls that DOES NOT check for dangling pointers (used in
306 | // __gc binding).
307 | void **checksdata_d(lua_State *L, int ud, const char *tname) noexcept(false);
308 | // Return pointer if the type is correct. Used to resolve overloaded functions when there
309 | // is no other alternative (arg count, native types). We return the pointer so that we can
310 | // optimize away the corresponding 'dub_checksdata'.
311 | void **issdata(lua_State *L, int ud, const char *tname, int type);
312 | // Does not throw exceptions. This method behaves exactly like luaL_checkudata but searches
313 | // for table.super before calling lua_error. We cannot use throw() because of differing
314 | // implementations for luaL_error (luajit throws an exception on luaL_error).
315 | void **checksdata_n(lua_State *L, int ud, const char *tname, bool keep_mt = false);
316 |
317 | inline const char *checkstring(lua_State *L, int narg) noexcept(false) {
318 | return checklstring(L, narg, NULL);
319 | }
320 |
321 | inline int checkboolean(lua_State *L, int narg) noexcept {
322 | return lua_toboolean(L, narg);
323 | }
324 |
325 | // This calls lua_Error after preparing the error message with line
326 | // and number.
327 | int error(lua_State *L);
328 |
329 | // This is a Lua binding called whenever we ask for obj:deleted() in Lua
330 | int isDeleted(lua_State *L);
331 |
332 | /** Protect garbage collection from pointers stored in objects or
333 | * retrieved in userdata copies.
334 | */
335 | void protect(lua_State *L, int owner, int original, const char *key);
336 |
337 | /** Prepare index function, setup 'type' field and __call metamethod.
338 | */
339 | void setup(lua_State *L, const char *class_name);
340 |
341 | // sdbm function: taken from http://www.cse.yorku.ca/~oz/hash.html
342 | // This version is slightly adapted to cope with different
343 | // hash sizes (and to be easy to write in Lua).
344 | int hash(const char *str, int sz);
345 |
346 | // Simple debugging function to print stack content.
347 | void printStack(lua_State *L, const char *msg = NULL);
348 |
349 | // Compatibility with luaL_register on lua 5.1 and 5.2
350 | void fregister(lua_State *L, const luaL_Reg *l);
351 |
352 |
353 | } // dub
354 |
355 | #endif // DUB_BINDING_GENERATOR_DUB_H_
356 |
357 |
--------------------------------------------------------------------------------
/src/bind/xml_Parser.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * MACHINE GENERATED FILE. DO NOT EDIT.
4 | *
5 | * Bindings for class Parser
6 | *
7 | * This file has been generated by dub 2.2.2.
8 | */
9 | #include "dub/dub.h"
10 | #include "xml/Parser.h"
11 |
12 | using namespace xml;
13 |
14 | /** xml::Parser::Parser(Type type=Default)
15 | * include/xml/Parser.h:48
16 | */
17 | static int Parser_Parser(lua_State *L) {
18 | try {
19 | int top__ = lua_gettop(L);
20 | if (top__ >= 1) {
21 | xml::Parser::Type type = (xml::Parser::Type)dub::checkinteger(L, 1);
22 | Parser *retval__ = new Parser(type);
23 | dub::pushudata(L, retval__, "xml.Parser", true);
24 | return 1;
25 | } else {
26 | Parser *retval__ = new Parser();
27 | dub::pushudata(L, retval__, "xml.Parser", true);
28 | return 1;
29 | }
30 | } catch (std::exception &e) {
31 | lua_pushfstring(L, "new: %s", e.what());
32 | } catch (...) {
33 | lua_pushfstring(L, "new: Unknown exception");
34 | }
35 | return dub::error(L);
36 | }
37 |
38 | /** xml::Parser::~Parser()
39 | * include/xml/Parser.h:49
40 | */
41 | static int Parser__Parser(lua_State *L) {
42 | try {
43 | DubUserdata *userdata = ((DubUserdata*)dub::checksdata_d(L, 1, "xml.Parser"));
44 | if (userdata->gc) {
45 | Parser *self = (Parser *)userdata->ptr;
46 | delete self;
47 | }
48 | userdata->gc = false;
49 | return 0;
50 | } catch (std::exception &e) {
51 | lua_pushfstring(L, "__gc: %s", e.what());
52 | } catch (...) {
53 | lua_pushfstring(L, "__gc: Unknown exception");
54 | }
55 | return dub::error(L);
56 | }
57 |
58 | /** LuaStackSize xml::Parser::load(lua_State *L)
59 | * include/xml/Parser.h:53
60 | */
61 | static int Parser_load(lua_State *L) {
62 | try {
63 | Parser *self = *((Parser **)dub::checksdata(L, 1, "xml.Parser"));
64 | return self->load(L);
65 | } catch (std::exception &e) {
66 | lua_pushfstring(L, "load: %s", e.what());
67 | } catch (...) {
68 | lua_pushfstring(L, "load: Unknown exception");
69 | }
70 | return dub::error(L);
71 | }
72 |
73 |
74 |
75 | // --=============================================== __tostring
76 | static int Parser___tostring(lua_State *L) {
77 | Parser *self = *((Parser **)dub::checksdata_n(L, 1, "xml.Parser"));
78 | lua_pushfstring(L, "xml.Parser: %p", self);
79 |
80 | return 1;
81 | }
82 |
83 | // --=============================================== METHODS
84 |
85 | static const struct luaL_Reg Parser_member_methods[] = {
86 | { "new" , Parser_Parser },
87 | { "__gc" , Parser__Parser },
88 | { "load" , Parser_load },
89 | { "__tostring" , Parser___tostring },
90 | { "deleted" , dub::isDeleted },
91 | { NULL, NULL},
92 | };
93 |
94 | // --=============================================== CONSTANTS
95 | static const struct dub::const_Reg Parser_const[] = {
96 | { "Default" , Parser::Default },
97 | { "TrimWhitespace", Parser::TrimWhitespace },
98 | { "NonDestructive", Parser::NonDestructive },
99 | { "Fastest" , Parser::Fastest },
100 | { NULL, 0},
101 | };
102 |
103 | DUB_EXPORT int luaopen_xml_Parser(lua_State *L)
104 | {
105 | // Create the metatable which will contain all the member methods
106 | luaL_newmetatable(L, "xml.Parser");
107 | //
108 | // register class constants
109 | dub::register_const(L, Parser_const);
110 |
111 | // register member methods
112 | dub::fregister(L, Parser_member_methods);
113 | // setup meta-table
114 | dub::setup(L, "xml.Parser");
115 | //
116 | return 1;
117 | }
118 |
--------------------------------------------------------------------------------
/src/bind/xml_core.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * MACHINE GENERATED FILE. DO NOT EDIT.
4 | *
5 | * Bindings for library xml
6 | *
7 | * This file has been generated by dub 2.2.2.
8 | */
9 | #include "dub/dub.h"
10 | #include "xml/Parser.h"
11 |
12 | using namespace xml;
13 |
14 | extern "C" {
15 | int luaopen_xml_Parser(lua_State *L);
16 | }
17 |
18 | // --=============================================== FUNCTIONS
19 | static const struct luaL_Reg xml_functions[] = {
20 | { NULL, NULL},
21 | };
22 |
23 |
24 | DUB_EXPORT int luaopen_xml_core(lua_State *L) {
25 | lua_newtable(L);
26 | //
27 | dub::fregister(L, xml_functions);
28 | //
29 |
30 | luaopen_xml_Parser(L);
31 | //
32 | lua_setfield(L, -2, "Parser");
33 |
34 | //
35 | return 1;
36 | }
37 |
--------------------------------------------------------------------------------
/src/vendor/license.txt:
--------------------------------------------------------------------------------
1 | Use of this software is granted under one of the following two licenses,
2 | to be chosen freely by the user.
3 |
4 | 1. Boost Software License - Version 1.0 - August 17th, 2003
5 | ===============================================================================
6 |
7 | Copyright (c) 2006, 2007 Marcin Kalicinski
8 |
9 | Permission is hereby granted, free of charge, to any person or organization
10 | obtaining a copy of the software and accompanying documentation covered by
11 | this license (the "Software") to use, reproduce, display, distribute,
12 | execute, and transmit the Software, and to prepare derivative works of the
13 | Software, and to permit third-parties to whom the Software is furnished to
14 | do so, all subject to the following:
15 |
16 | The copyright notices in the Software and this entire statement, including
17 | the above license grant, this restriction and the following disclaimer,
18 | must be included in all copies of the Software, in whole or in part, and
19 | all derivative works of the Software, unless such copies or derivative
20 | works are solely in the form of machine-executable object code generated by
21 | a source language processor.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
26 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
27 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
28 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 | DEALINGS IN THE SOFTWARE.
30 |
31 | 2. The MIT License
32 | ===============================================================================
33 |
34 | Copyright (c) 2006, 2007 Marcin Kalicinski
35 |
36 | Permission is hereby granted, free of charge, to any person obtaining a copy
37 | of this software and associated documentation files (the "Software"), to deal
38 | in the Software without restriction, including without limitation the rights
39 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
40 | of the Software, and to permit persons to whom the Software is furnished to do so,
41 | subject to the following conditions:
42 |
43 | The above copyright notice and this permission notice shall be included in all
44 | copies or substantial portions of the Software.
45 |
46 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
49 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
52 | IN THE SOFTWARE.
53 |
--------------------------------------------------------------------------------
/src/vendor/manual.html:
--------------------------------------------------------------------------------
1 | RAPIDXML Manual
Version 1.13