mirror of
				https://github.com/minetest-mods/irc.git
				synced 2025-10-31 13:25:26 +01:00 
			
		
		
		
	Compare commits
	
		
			99 Commits
		
	
	
		
			rewrite
			...
			612a94bbf1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 612a94bbf1 | |||
|  | 5e3659761b | ||
|  | ac0387786c | ||
|  | 05ab5e9fbd | ||
| 2a88c47de4 | |||
| 0f00fa8c7e | |||
| 351a86cbf2 | |||
| 1b71c304c5 | |||
| 47f889c178 | |||
|  | 1c23f8987b | ||
|  | 66bb7fc47d | ||
|  | 6a7053582d | ||
|  | 5e877956a5 | ||
|  | 60bf32e157 | ||
|  | b4fbccd64a | ||
|  | c9c57a6f93 | ||
|  | f57bdba5e9 | ||
|  | 070eb51236 | ||
|  | e80bbe3a62 | ||
|  | 1d4fd5a162 | ||
|  | 6bf4e111c2 | ||
|  | 5f8850bc15 | ||
|  | 2f55e0f9a0 | ||
|  | 78fbe26a2c | ||
|  | 33542b07fe | ||
|  | 6bbb26f9f9 | ||
|  | ae0cb08e3e | ||
|  | bb5f549193 | ||
|  | 4c334e9967 | ||
|  | a18820356a | ||
|  | 0c8538bfb8 | ||
|  | 9f8b4fd4af | ||
|  | 73cdb58c99 | ||
|  | 3e2d98f9ef | ||
|  | 12248cc847 | ||
|  | 160088c232 | ||
|  | 03070e41c4 | ||
|  | b5786979ab | ||
|  | d5ad8ffca4 | ||
|  | 0f6e1dacc4 | ||
|  | ecc1d450ba | ||
|  | 18f286f4b5 | ||
|  | 0c47e10a90 | ||
|  | 43493eb2ea | ||
|  | f98282818d | ||
|  | 03edbd29ed | ||
|  | 464f2febee | ||
|  | 0c900dbac2 | ||
|  | 38832b3c55 | ||
|  | fd1a570794 | ||
|  | 18b80bd127 | ||
|  | 43cb77fab8 | ||
|  | df229cabe6 | ||
|  | 30fa81a3ab | ||
|  | 32294995be | ||
|  | d0ebde3884 | ||
|  | 9e15a886b4 | ||
|  | 12b1b07afe | ||
|  | e92eec3987 | ||
|  | 8aa442e87f | ||
|  | 5655f75946 | ||
|  | 8e6a9a287f | ||
|  | 26ca287b09 | ||
|  | 3b35bb1871 | ||
|  | 56a5de4a91 | ||
|  | 706a6fbe27 | ||
|  | e87d2e5bf2 | ||
|  | ed20a55899 | ||
|  | 13d6116f8e | ||
|  | af4b92921f | ||
|  | f88760a273 | ||
|  | 4c70a06e87 | ||
|  | 69492966a7 | ||
|  | ea24a7501c | ||
|  | cdc6067e87 | ||
|  | 8d8a8ec519 | ||
|  | d1a0579135 | ||
|  | 3a06814f18 | ||
|  | 8e4b863549 | ||
|  | a25527100a | ||
|  | 5604fa5582 | ||
|  | 10f32b77b0 | ||
|  | aa299b7a10 | ||
|  | d81f80155f | ||
|  | c3ddf1df70 | ||
|  | 0d57978c84 | ||
|  | 99c7c56733 | ||
|  | d21f5b3403 | ||
|  | b647378490 | ||
|  | a1671fca52 | ||
|  | 0901083dd0 | ||
|  | 85b4ba3f8f | ||
|  | 290082760b | ||
|  | 5b0671b512 | ||
|  | ccea0ff33c | ||
|  | 4313a06505 | ||
|  | 25696a8e9a | ||
|  | b3ae3f5f03 | ||
|  | c7f989dd85 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,2 @@ | |||||||
| Build | *~ | ||||||
| irc |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,3 @@ | |||||||
| [submodule "src/LuaIRC"] | [submodule "irc"] | ||||||
| 	path = src/LuaIRC | 	path = irc | ||||||
| 	url = https://github.com/ShadowNinja/LuaIRC.git | 	url = https://sys4.fr/gitea/mtcontrib/LuaIRC.git | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								.luacheckrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								.luacheckrc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  |  | ||||||
|  | allow_defined_top = true | ||||||
|  |  | ||||||
|  | read_globals = { | ||||||
|  | 	"minetest", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | exclude_files = { | ||||||
|  | 	"irc/*", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | globals = { | ||||||
|  | 	"irc", | ||||||
|  | } | ||||||
| @@ -1,63 +1,66 @@ | |||||||
| IRC Mod API | IRC Mod API | ||||||
| ----------- | =========== | ||||||
|  | 
 | ||||||
| This file documents the Minetest IRC mod API. | This file documents the Minetest IRC mod API. | ||||||
| 
 | 
 | ||||||
| BASICS | Basics | ||||||
| ------ | ------ | ||||||
| In order to allow your mod to interface with this mod, you must add 'irc' | 
 | ||||||
|  (without the quotes) to your mod's 'depends.txt' file. | In order to allow your mod to interface with this mod, you must add `irc` | ||||||
|  | to your mod's `depends.txt` file. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| REFERENCE | Reference | ||||||
| --------- | --------- | ||||||
| 
 | 
 | ||||||
| mt_irc:say([name, ]message) | irc.say([name,] message) | ||||||
| Sends <message> to either the channel (if <name> is nil or not specified), | Sends <message> to either the channel (if <name> is nil or not specified), | ||||||
| or to the given user (if <name> is specified). | or to the given user (if <name> is specified). | ||||||
| Example: | Example: | ||||||
| 	mt_irc:say("Hello, Channel!") | 	irc.say("Hello, Channel!") | ||||||
| 	mt_irc:say("john1234", "How are you?") | 	irc.say("john1234", "How are you?") | ||||||
| 
 | 
 | ||||||
| mt_irc:register_bot_command(name, cmdDef) | irc.register_bot_command(name, cmdDef) | ||||||
| 	Registers a new bot command named <name>. | 	Registers a new bot command named <name>. | ||||||
| 	When an user sends a private message to the bot with the command name, the | 	When an user sends a private message to the bot with the command name, the | ||||||
| 	command's function is called. | 	command's function is called. | ||||||
| 	Here's the format of a command definition (<cmdDef>): | 	Here's the format of a command definition (<cmdDef>): | ||||||
| 	cmdDef = { | 		cmdDef = { | ||||||
| 		params = "<param1> ...",      -- A description of the command's parameters | 			params = "<param1> ...",      -- A description of the command's parameters | ||||||
| 		description = "My command",   -- A description of what the command does. (one-liner) | 			description = "My command",   -- A description of what the command does. (one-liner) | ||||||
| 		func = function(user, param) | 			func = function(user, args) | ||||||
| 			-- This function gets called when the command is invoked. | 				-- This function gets called when the command is invoked. | ||||||
| 			-- <user> is a user table for the user that ran the command. | 				-- <user> is a user table for the user that ran the command. | ||||||
| 			--   (See the LuaIRC documentation for details.) | 				--   (See the LuaIRC documentation for details.) | ||||||
| 			--   It contains fields such as 'nick' and 'ident' | 				--   It contains fields such as 'nick' and 'ident' | ||||||
| 			-- <param> is a string of parameters to the command (may be "") | 				-- <args> is a string of arguments to the command (may be "") | ||||||
| 		end, | 				-- This function should return boolean success and a message. | ||||||
| 	}; | 			end, | ||||||
|  | 		}; | ||||||
| 	Example: | 	Example: | ||||||
| 	mt_irc:register_bot_command("hello", { | 		irc.register_bot_command("hello", { | ||||||
| 		params = "", | 			params = "", | ||||||
| 		description = "Greet user", | 			description = "Greet user", | ||||||
| 		func = function(user, param) | 			func = function(user, param) | ||||||
| 			mt_irc:say(user.nick, "Hello!") | 				return true, "Hello!" | ||||||
| 		end, | 			end, | ||||||
| 	}); | 		}); | ||||||
| 
 | 
 | ||||||
| mt_irc.joined_players[name] | irc.joined_players[name] | ||||||
| 	This table holds the players who are currently on the channel (may be less | 	This table holds the players who are currently on the channel (may be less | ||||||
| 	than the players in the game). It is modified by the /part and /join chat | 	than the players in the game). It is modified by the /part and /join chat | ||||||
| 	commands. | 	commands. | ||||||
| 	Example: | 	Example: | ||||||
| 	if mt_irc.joined_players["joe"] then | 	if irc.joined_players["joe"] then | ||||||
| 		-- Joe is talking on IRC | 		-- Joe is talking on IRC | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
| mt_irc:register_hook(name, func) | irc.register_hook(name, func) | ||||||
| 	Registers a function to be called when an event happens. <name> is the name | 	Registers a function to be called when an event happens. <name> is the name | ||||||
| 	of the event, and <func> is the function to be called. See HOOKS below | 	of the event, and <func> is the function to be called. See HOOKS below | ||||||
| 	for more information | 	for more information | ||||||
| 	Example: | 	Example: | ||||||
| 	mt_irc:register_hook("OnSend", function(line) | 	irc.register_hook("OnSend", function(line) | ||||||
| 		print("SEND: "..line) | 		print("SEND: "..line) | ||||||
| 	end) | 	end) | ||||||
| 
 | 
 | ||||||
| @@ -69,18 +72,18 @@ string.expandvars(string, vars) | |||||||
| 	are left verbatim in the string. | 	are left verbatim in the string. | ||||||
| 	Example: | 	Example: | ||||||
| 	local tpl = "$(foo) $(bar) $(baz)" | 	local tpl = "$(foo) $(bar) $(baz)" | ||||||
| 	local s = tpl:expandvars({ foo=1, bar="Hello" }) | 	local s = tpl:expandvars({foo=1, bar="Hello"}) | ||||||
| 	assert(s == "1 Hello $(baz)")  | 	assert(s == "1 Hello $(baz)")  | ||||||
| 
 | 
 | ||||||
| In addition, all the configuration options decribed in `README.txt' are | In addition, all the configuration options decribed in `README.txt` are | ||||||
| available to other mods, though they should be considered "read only". Do | available to other mods, though they should be considered read-only. Do | ||||||
| not modify these settings at runtime or you will most likely crash the | not modify these settings at runtime or you might crash the server! | ||||||
| server! |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| HOOKS | Hooks | ||||||
| --------- | ----- | ||||||
| The 'mt_irc:register_hook' function can register functions to be called | 
 | ||||||
|  | The `irc.register_hook` function can register functions to be called | ||||||
| when some events happen. The events supported are the same as the LuaIRC | when some events happen. The events supported are the same as the LuaIRC | ||||||
| ones with a few added (mostly for internal use). | ones with a few added (mostly for internal use). | ||||||
| See src/LuaIRC/doc/irc.luadoc for more information. | See src/LuaIRC/doc/irc.luadoc for more information. | ||||||
							
								
								
									
										143
									
								
								CMakeLists.txt
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								CMakeLists.txt
									
									
									
									
									
								
							| @@ -1,143 +0,0 @@ | |||||||
|  |  | ||||||
| # :mode=cmake: |  | ||||||
|  |  | ||||||
| cmake_minimum_required(VERSION 2.8) |  | ||||||
|  |  | ||||||
| project(MINETEST_IRC C) |  | ||||||
|  |  | ||||||
| set(MINETEST_IRC_VERSION 0.2.0) |  | ||||||
|  |  | ||||||
| list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") |  | ||||||
|  |  | ||||||
| set(LUA_SRCS |  | ||||||
| 	src/lua/lapi.c |  | ||||||
| 	src/lua/lcode.c |  | ||||||
| 	src/lua/ldebug.c |  | ||||||
| 	src/lua/ldo.c |  | ||||||
| 	src/lua/ldump.c |  | ||||||
| 	src/lua/lfunc.c |  | ||||||
| 	src/lua/lgc.c |  | ||||||
| 	src/lua/llex.c |  | ||||||
| 	src/lua/lmem.c |  | ||||||
| 	src/lua/lobject.c |  | ||||||
| 	src/lua/lopcodes.c |  | ||||||
| 	src/lua/lparser.c |  | ||||||
| 	src/lua/lstate.c |  | ||||||
| 	src/lua/lstring.c |  | ||||||
| 	src/lua/ltable.c |  | ||||||
| 	src/lua/ltm.c |  | ||||||
| 	src/lua/lundump.c |  | ||||||
| 	src/lua/lvm.c |  | ||||||
| 	src/lua/lzio.c |  | ||||||
| 	src/lua/lauxlib.c |  | ||||||
| 	src/lua/lbaselib.c |  | ||||||
| 	src/lua/ldblib.c |  | ||||||
| 	src/lua/liolib.c |  | ||||||
| 	src/lua/lmathlib.c |  | ||||||
| 	src/lua/loslib.c |  | ||||||
| 	src/lua/ltablib.c |  | ||||||
| 	src/lua/lstrlib.c |  | ||||||
| 	src/lua/loadlib.c |  | ||||||
| 	src/lua/linit.c |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| set(LUASOCKET_SRCS |  | ||||||
| 	src/luasocket/compat51.c |  | ||||||
| 	src/luasocket/luasocket.c |  | ||||||
| 	src/luasocket/timeout.c |  | ||||||
| 	src/luasocket/buffer.c |  | ||||||
| 	src/luasocket/io.c |  | ||||||
| 	src/luasocket/auxiliar.c |  | ||||||
| 	src/luasocket/options.c |  | ||||||
| 	src/luasocket/inet.c |  | ||||||
| 	src/luasocket/tcp.c |  | ||||||
| 	src/luasocket/udp.c |  | ||||||
| 	src/luasocket/except.c |  | ||||||
| 	src/luasocket/select.c |  | ||||||
| 	src/luasocket/buffer.c |  | ||||||
| 	src/luasocket/auxiliar.c |  | ||||||
| 	src/luasocket/options.c |  | ||||||
| 	src/luasocket/timeout.c |  | ||||||
| 	src/luasocket/io.c |  | ||||||
| 	src/luasocket/mime.c |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| if(WIN32) |  | ||||||
| 	list(APPEND LUASOCKET_SRCS src/luasocket/wsocket.c) |  | ||||||
| 	set(LUASOCKET_EXTRA_LIBS -lwininet) |  | ||||||
| else() |  | ||||||
| 	list(APPEND LUASOCKET_SRCS src/luasocket/usocket.c src/luasocket/unix.c) |  | ||||||
| endif() |  | ||||||
|  |  | ||||||
| include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) |  | ||||||
| include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/lua) |  | ||||||
| include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/luasocket) |  | ||||||
|  |  | ||||||
| add_library(luasocket_lib MODULE ${LUASOCKET_SRCS} ${LUA_SRCS}) |  | ||||||
|  |  | ||||||
| set_target_properties(luasocket_lib PROPERTIES |  | ||||||
| 	OUTPUT_NAME luasocket) |  | ||||||
|  |  | ||||||
| if(WIN32) |  | ||||||
| 	# When using MinGW32, CMake prefixes DLLs with "lib". Force remove |  | ||||||
| 	#  this prefix regardless of compiler. |  | ||||||
| 	set_target_properties(luasocket_lib PROPERTIES |  | ||||||
| 		PREFIX "") |  | ||||||
| 	if (NOT MSVC) # GCC? |  | ||||||
| 		# The `-fPIC' flag generates a warning on MinGW32, which combined |  | ||||||
| 		#  with `-Werror' makes that an error though `-fPIC' is ignored. |  | ||||||
| 		#  We use `-fno-PIC' to avoid that. |  | ||||||
| 		set_target_properties(luasocket_lib PROPERTIES |  | ||||||
| 			COMPILE_FLAGS "-fno-PIC -Wall -Werror") |  | ||||||
| 	endif() |  | ||||||
| 	find_library(ws2_32_lib NAMES ws2_32) |  | ||||||
| 	target_link_libraries(luasocket_lib ${ws2_32_lib}) |  | ||||||
| else() # Possibly Unix |  | ||||||
| 	set_target_properties(luasocket_lib PROPERTIES |  | ||||||
| 		COMPILE_FLAGS "-Wall -Werror") |  | ||||||
| endif() |  | ||||||
|  |  | ||||||
| set(dir ${CMAKE_CURRENT_BINARY_DIR}/irc/) |  | ||||||
|  |  | ||||||
| if(WIN32) |  | ||||||
| 	set(lib "${CMAKE_CURRENT_BINARY_DIR}/luasocket.dll") |  | ||||||
| else() |  | ||||||
| 	set(lib "${CMAKE_CURRENT_BINARY_DIR}/libluasocket.so") |  | ||||||
| endif() |  | ||||||
|  |  | ||||||
| add_custom_target(pack_mod ALL |  | ||||||
| 	WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} |  | ||||||
|  |  | ||||||
| 	# LuaIRC |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E make_directory ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy_directory src/LuaIRC ${dir}/irc |  | ||||||
|  |  | ||||||
| 	# luasocket |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E make_directory ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/luasocket/ftp.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/luasocket/http.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/luasocket/ltn12.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/luasocket/mime.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/luasocket/smtp.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/luasocket/socket.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/luasocket/tp.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/luasocket/url.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/luasocket/LICENSE.txt ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy ${lib} ${dir} |  | ||||||
|  |  | ||||||
| 	# IRC mod |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E make_directory ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/init.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/hooks.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/messages.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/config.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/callback.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/chatcmds.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/botcmds.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/player_part.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/util.lua ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy README.txt ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/API.txt ${dir} |  | ||||||
| 	COMMAND ${CMAKE_COMMAND} -E copy src/LICENSE.txt ${dir} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| @@ -1,17 +1,17 @@ | |||||||
| Copyright (c) 2013, Diego Martinez (kaeza) | Copyright (c) 2013, Diego Martinez (kaeza) | ||||||
| All rights reserved. | All rights reserved. | ||||||
| 
 | 
 | ||||||
| Redistribution and use in source and binary forms, with or without modification, | Redistribution and use in source and binary forms, with or without | ||||||
| are permitted provided that the following conditions are met: | modification, are permitted provided that the following conditions are met: | ||||||
|  - Redistributions of source code must retain the above copyright notice, |  - Redistributions of source code must retain the above copyright notice, | ||||||
|    this list of conditions and the following disclaimer. |    this list of conditions and the following disclaimer. | ||||||
|  - Redistributions in binary form must reproduce the above copyright notice, |  - Redistributions in binary form must reproduce the above copyright notice, | ||||||
|    this list of conditions and the following disclaimer in the documentation |    this list of conditions and the following disclaimer in the documentation | ||||||
|    and/or other materials provided with the distribution. |    and/or other materials provided with the distribution. | ||||||
| 
 | 
 | ||||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||||
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||||
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||||
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||||
							
								
								
									
										181
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | |||||||
|  |  | ||||||
|  | IRC Mod for Minetest | ||||||
|  | ==================== | ||||||
|  |  | ||||||
|  | Introduction | ||||||
|  | ------------ | ||||||
|  |  | ||||||
|  | This mod is just a glue between IRC and Minetest. It provides two-way | ||||||
|  |  communication between the in-game chat, and an arbitrary IRC channel. | ||||||
|  |  | ||||||
|  | The forum topic is [here][forum]. | ||||||
|  |  | ||||||
|  | [forum]: https://forum.minetest.net/viewtopic.php?f=11&t=3905 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Installing | ||||||
|  | ---------- | ||||||
|  |  | ||||||
|  | Quick one line install for Linux: | ||||||
|  |  | ||||||
|  | 	cd <Mods directory> && git clone --recursive https://github.com/minetest-mods/irc.git | ||||||
|  |  | ||||||
|  | Please change `<Mods directory>` to fit your installation of Minetest. | ||||||
|  | For more information, see [the wiki][wiki]. | ||||||
|  |  | ||||||
|  | The IRC mod's git repository uses submodules, therefore you will have to run | ||||||
|  | `git submodule init` when first installing the mod (unless you used | ||||||
|  | `--recursive` as above), and `git submodule update` every time that a submodule | ||||||
|  | is updated. These steps can be combined into `git submodule update --init`. | ||||||
|  |  | ||||||
|  | You'll need to install LuaSocket. You can do so with your package manager on | ||||||
|  | many distributions, for example: | ||||||
|  |  | ||||||
|  | 	# # On Arch Linux: | ||||||
|  | 	# pacman -S lua51-socket | ||||||
|  | 	# # On Debian/Ubuntu: | ||||||
|  | 	# # Debian/Ubuntu's LuaSocket packages are broken, so use LuaRocks. | ||||||
|  | 	# apt-get install luarocks | ||||||
|  | 	# luarocks install luasocket | ||||||
|  |  | ||||||
|  | You will also need to add IRC to your trusted mods if you haven't disabled mod | ||||||
|  | security. Here's an example configuration line: | ||||||
|  |  | ||||||
|  | 	secure.trusted_mods = irc | ||||||
|  |  | ||||||
|  | [wiki]: https://wiki.minetest.net/Installing_mods | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Settings | ||||||
|  | -------- | ||||||
|  |  | ||||||
|  | All settings are changed in `minetest.conf`. If any of these settings | ||||||
|  | are not set, the default value is used. | ||||||
|  |  | ||||||
|  | * `irc.server` (string): | ||||||
|  |   The address of the IRC server to connect to. | ||||||
|  |  | ||||||
|  | * `irc.channel` (string): | ||||||
|  |   The IRC channel to join. | ||||||
|  |  | ||||||
|  | * `irc.interval` (number, default 2.0): | ||||||
|  |   This prevents the server from flooding. It should be at | ||||||
|  |   least 2.0 but can be higher. After four messages this much | ||||||
|  |   time must pass between folowing messages. | ||||||
|  |  | ||||||
|  | * `irc.nick` (string): | ||||||
|  |   Nickname the server uses when it connects to IRC. | ||||||
|  |  | ||||||
|  | * `irc.password` (string, default nil): | ||||||
|  |   Password to use when connecting to the server. | ||||||
|  |  | ||||||
|  | * `irc.NSPass` (string, default nil): | ||||||
|  |   NickServ password. Don't set this if you use SASL authentication. | ||||||
|  |  | ||||||
|  | * `irc.sasl.pass` (string, default nil): | ||||||
|  |   SASL password, same as nickserv password. | ||||||
|  |   You should use this instead of NickServ authentication | ||||||
|  |   if the server supports it. | ||||||
|  |  | ||||||
|  | * `irc.sasl.user` (string, default `irc.nick`): | ||||||
|  |   The SASL username. This should normaly be set to your | ||||||
|  |   NickServ account name. | ||||||
|  |  | ||||||
|  | * `irc.debug` (boolean, default false): | ||||||
|  |   Whether to output debug information. | ||||||
|  |  | ||||||
|  | * `irc.disable_auto_connect` (boolean, default false): | ||||||
|  |   If false, the bot is connected by default. If true, a player with | ||||||
|  |   the 'irc_admin' privilege has to use the `/irc_connect` command to | ||||||
|  |   connect to the server. | ||||||
|  |  | ||||||
|  | * `irc.disable_auto_join` (boolean, default false): | ||||||
|  |   If false, players join the channel automatically upon entering the | ||||||
|  |   game. If true, each user must manually use the `/join` command to | ||||||
|  |   join the channel. In any case, the players may use the `/part` | ||||||
|  |   command to opt-out of being in the channel. | ||||||
|  |  | ||||||
|  | * `irc.send_join_part` (boolean, default true): | ||||||
|  |   Determines whether to send player join and part messages to the channel. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Usage | ||||||
|  | ----- | ||||||
|  |  | ||||||
|  | Once the game is connected to the IRC channel, chatting in-game will send | ||||||
|  | messages to the channel, and will be visible by anyone. Also, messages sent | ||||||
|  | to the channel will be visible in-game. | ||||||
|  |  | ||||||
|  | Messages that begin with `[off]` from in-game or IRC are not sent to the | ||||||
|  | other side. | ||||||
|  |  | ||||||
|  | This mod also adds a few chat commands: | ||||||
|  |  | ||||||
|  | * `/irc_msg <nick> <message>`: | ||||||
|  |   Send a private message to a IRC user. | ||||||
|  |  | ||||||
|  | * `/join`: | ||||||
|  |   Join the IRC chat. | ||||||
|  |  | ||||||
|  | * `/part`: | ||||||
|  |   Part the IRC chat. | ||||||
|  |  | ||||||
|  | * `/irc_connect`: | ||||||
|  |   Connect the bot manually to the IRC network. | ||||||
|  |  | ||||||
|  | * `/irc_disconnect`: | ||||||
|  |   Disconnect the bot manually from the IRC network (this does not | ||||||
|  |   shutdown the game). | ||||||
|  |  | ||||||
|  | * `/irc_reconnect`: | ||||||
|  |   Equivalent to `/irc_disconnect` followed by `/irc_connect`. | ||||||
|  |  | ||||||
|  | You can also send private messages from IRC to in-game players | ||||||
|  | by sending a private message to the bot (set with the `irc.nick` | ||||||
|  | option above), in the following format: | ||||||
|  |  | ||||||
|  | 	@playername message | ||||||
|  |  | ||||||
|  | For example, if there's a player named `mtuser`, you can send him/her | ||||||
|  | a private message from IRC with: | ||||||
|  |  | ||||||
|  | 	/msg server_nick @mtuser Hello! | ||||||
|  |  | ||||||
|  | The bot also supports some basic commands, which are invoked by saying | ||||||
|  | the bot name followed by either a colon or a comma and the command, or | ||||||
|  | sending a private message to it. For example: `ServerBot: help whereis`. | ||||||
|  |  | ||||||
|  | * `help [<command>]`: | ||||||
|  |   Prints help about a command, or a list of supported commands if no | ||||||
|  |   command is given. | ||||||
|  |  | ||||||
|  | * `uptime`: | ||||||
|  |   Prints the server's running time. | ||||||
|  |  | ||||||
|  | * `whereis <player>`: | ||||||
|  |   Prints the coordinates of the given player. | ||||||
|  |  | ||||||
|  | * `players`: | ||||||
|  |   Lists players currently in the server. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Thanks | ||||||
|  | ------ | ||||||
|  |  | ||||||
|  | I'd like to thank the users who supported this mod both on the Minetest | ||||||
|  | Forums and on the `#minetest` channel. In no particular order: | ||||||
|  |  | ||||||
|  | 0gb.us, ShadowNinja, Shaun/kizeren, RAPHAEL, DARGON, Calinou, Exio, | ||||||
|  | vortexlabs/mrtux, marveidemanis, marktraceur, jmf/john\_minetest, | ||||||
|  | sdzen/Muadtralk, VanessaE, PilzAdam, sfan5, celeron55, KikaRz, | ||||||
|  | OldCoder, RealBadAngel, and all the people who commented in the | ||||||
|  | forum topic. Thanks to you all! | ||||||
|  |  | ||||||
|  |  | ||||||
|  | License | ||||||
|  | ------- | ||||||
|  |  | ||||||
|  | See `LICENSE.txt` for details. | ||||||
|  |  | ||||||
|  | The files in the `irc` directory are part of the LuaIRC project. | ||||||
|  | See `irc/LICENSE.txt` for details. | ||||||
							
								
								
									
										217
									
								
								README.txt
									
									
									
									
									
								
							
							
						
						
									
										217
									
								
								README.txt
									
									
									
									
									
								
							| @@ -1,217 +0,0 @@ | |||||||
| IRC Mod for Minetest |  | ||||||
| (C) 2012 Diego Martínez <kaeza@users.sf.net> |  | ||||||
|  |  | ||||||
| INTRODUCTION |  | ||||||
| ------------ |  | ||||||
| This mod is just a glue between luasocket, LuaIRC, and Minetest. It |  | ||||||
|  provides a two-way communication between the in-game chat, and an |  | ||||||
|  arbitrary IRC channel.  |  | ||||||
|  |  | ||||||
| The forum topic is at http://minetest.net/forum/viewtopic.php?id=3905 |  | ||||||
|  |  | ||||||
|   |  | ||||||
| COMPILING |  | ||||||
| --------- |  | ||||||
| Make sure you have CMake (http://cmake.org/), and of course, a C compiler, |  | ||||||
|  on your system before proceeding. |  | ||||||
| For Windows, try MinGW32 (http://mingw.org/). |  | ||||||
| For Unix-based systems, you should not have any problems with the C compiler |  | ||||||
|  since there's one (almost) always available. Puppy Linux users of course |  | ||||||
|  need a separate 'devx.sfs' (from the same place where you got the Puppy |  | ||||||
|  ISO), since vanilla Puppy does not come with 'gcc'. See your Puppy docs for |  | ||||||
|  more info about how to install additional SFS files. |  | ||||||
|  |  | ||||||
| Quick one line build for linux.   |  | ||||||
|  |  | ||||||
| git clone https://github.com/kaeza/minetest-irc.git && cd minetest-irc && git submodule update --init && ./quick_install.sh <mod directory> |  | ||||||
| Please change <mod directory> to fit your install of minetest. |  | ||||||
|  |  | ||||||
| To compile and pack the mod: |  | ||||||
|  |  | ||||||
|   - Open a command prompt/terminal and CD to the minetest-irc directory. |  | ||||||
|   - (optional) Create a directory named "Build", and CD into it: |  | ||||||
|       mkdir Build |  | ||||||
|       cd Build |  | ||||||
|   - Run CMake to generate the build system (see your CMake docs for more |  | ||||||
|      information about command line options, in particular the '-G' option). |  | ||||||
|       cmake . (cmake .. if you made a seperate build directory) |  | ||||||
|   - Use the build tool for the generated build system to compile the |  | ||||||
|      native library. For example, if using Microsoft Visual Studio, open |  | ||||||
|      the generated workspace and build from there. If using make, just run |  | ||||||
|      "make" from within the Build directory. |  | ||||||
|   - After building you will have a folder named 'irc' in your build folder. |  | ||||||
| 	 Move that to your mod folder. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| INSTALLING |  | ||||||
| ---------- |  | ||||||
| Just put the created 'irc' directory in any of the directories where |  | ||||||
|  Minetest looks for mods. For more information, see: |  | ||||||
|     http://wiki.minetest.com/wiki/Installing_mods |  | ||||||
|  |  | ||||||
|  |  | ||||||
| SETTINGS |  | ||||||
| -------- |  | ||||||
| All settings are changed in 'minetest.conf'. If any of these settings |  | ||||||
|  are either not set or false, the default value is used. |  | ||||||
|  |  | ||||||
|     irc.server (string, default "irc.freenode.net") |  | ||||||
|         This is the IRC server the mod connects to. |  | ||||||
|  |  | ||||||
|     irc.channel (string, default "##mt-irc-mod") |  | ||||||
|         The IRC channel to join. |  | ||||||
|  |  | ||||||
|     irc.interval (number, default 2.0) |  | ||||||
|         This prevents the server from flooding. It should be at |  | ||||||
|         least 2.0 but can be higher. After four messages this much |  | ||||||
|         time must pass between folowing messages. |  | ||||||
|  |  | ||||||
|     irc.timeout (number, default 60.0) |  | ||||||
|         Underlying socket timeout in seconds. This is the time before |  | ||||||
|         the system drops an idle connection. |  | ||||||
|  |  | ||||||
|     irc.nick (string, default "minetest-"..<server-id>) |  | ||||||
|         Nickname used as "proxy" for the in-game chat.  |  | ||||||
|         "<server-id>" is a random 32 bit number. |  | ||||||
|  |  | ||||||
|     irc.password (string, default "") |  | ||||||
|         Password to use when connecting to the server. |  | ||||||
|  |  | ||||||
|     irc.NSPass (string, default nil) |  | ||||||
|         NickServ password. Don't use this if you use SASL authentication. |  | ||||||
|  |  | ||||||
|     irc.SASLPass (string, default nil) |  | ||||||
|         SASL password, same as nickserv password. |  | ||||||
|         You should use this instead of NickServ authentication |  | ||||||
|         if the server supports it. |  | ||||||
|  |  | ||||||
|     irc.SASLUser (string, default irc.nick) |  | ||||||
|         The SASL username. This should normaly be set to your main NickServ account name. |  | ||||||
|  |  | ||||||
|     irc.format_out (string, default "<$(name)> $(message)") |  | ||||||
|         This specifies how to send the messages from in-game to IRC. |  | ||||||
|         The strings can contain "macros" (or variable substitutions), which |  | ||||||
|         are specified as "$(macro_name)". |  | ||||||
|         Currently, these macros are supported: |  | ||||||
|           $(name)       The name of the player sending the message. |  | ||||||
|           $(message)    The actual message text. |  | ||||||
|         Any unrecognized macro will be left in the message verbatim. |  | ||||||
|         For example, if a user named "mtuser" is saying "Hello!", then: |  | ||||||
|           "<$(name)> $(message)" |  | ||||||
|         ...will yield... |  | ||||||
|           "<mtuser> Hello!" |  | ||||||
|         ...and... |  | ||||||
|           "$(name): $(message) $(xyz)" |  | ||||||
|         ...will yield... |  | ||||||
|           "mtuser: Hello! $(xyz)" |  | ||||||
|  |  | ||||||
|     irc.format_in (string, |  | ||||||
|      default "<$(name)@IRC> $(message)") |  | ||||||
|         This specifies how the messages gotten from the IRC channel are |  | ||||||
|         displayed in-game. |  | ||||||
|         The strings can contain "macros" (or variable substitutions), which |  | ||||||
|         are specified as "$(macro_name)". |  | ||||||
|         Currently, these macros are supported: |  | ||||||
|           $(name)       The nickname of the user sending the message. |  | ||||||
|           $(message)    The actual message text. |  | ||||||
|           $(server)     The IRC server. |  | ||||||
|           $(port)       The IRC server port. |  | ||||||
|           $(channel)    The IRC channel. |  | ||||||
|         In the default configuration, this will yield: |  | ||||||
|           <IRCUser@IRC> Hello! |  | ||||||
|  |  | ||||||
|     irc.debug (boolean, default false) |  | ||||||
|         Whether to output debug information. |  | ||||||
|  |  | ||||||
|     irc.disable_auto_connect (boolean, default false) |  | ||||||
|         If false, the bot is connected by default. If true, a player with |  | ||||||
|          the 'irc_admin' privilege has to use the /irc_connect command to |  | ||||||
|          connect to the server. |  | ||||||
|  |  | ||||||
|     irc.disable_auto_join (boolean, default false) |  | ||||||
|         If false, players join the channel automatically upon entering the |  | ||||||
|          game. If true, each user must manually use the /join command to |  | ||||||
|          join the channel. In any case, the players may use the /part |  | ||||||
|          command to opt-out of being in the channel. |  | ||||||
|  |  | ||||||
| USAGE |  | ||||||
| ----- |  | ||||||
| Once the game is connected to the IRC channel, chatting using the 'T' or |  | ||||||
|  F10 hotkeys will send the messages to the channel, and will be visible |  | ||||||
|  by anyone. Also, when someone sends a message to the channel, that text |  | ||||||
|  will be visible in-game. |  | ||||||
|  |  | ||||||
| This mod also adds a few chat commands: |  | ||||||
|  |  | ||||||
|     /irc_msg <nick> <message> |  | ||||||
|         Sends a private message to a IRC user. |  | ||||||
|  |  | ||||||
|     /join |  | ||||||
|         Join the IRC channel. |  | ||||||
|  |  | ||||||
|     /part |  | ||||||
|         Part the IRC channel. |  | ||||||
|  |  | ||||||
|     /irc_connect |  | ||||||
|         Connect the bot manually to the IRC network. |  | ||||||
|  |  | ||||||
|     /irc_disconnect |  | ||||||
|         Disconnect the bot manually from the IRC network (this does not |  | ||||||
|         shutdown the game). |  | ||||||
|  |  | ||||||
|     /irc_reconnect |  | ||||||
|         Equivilant to /irc_disconnect followed by /irc_connect. |  | ||||||
|  |  | ||||||
| You can also send private messages from IRC to in-game players, though |  | ||||||
|  it's a bit tricky. |  | ||||||
|  |  | ||||||
| To do it, you must send a private message to the bot (set with |  | ||||||
|  the 'irc.nick' option above), in the following format: |  | ||||||
|     @playername message |  | ||||||
| For example, if there's a player named 'mtuser', you can send him/her |  | ||||||
|  a private message from IRC with: |  | ||||||
|     /msg server_nick @mtuser Hello! |  | ||||||
|  |  | ||||||
| To avoid possible misunderstandings (since all in-game players use the |  | ||||||
|  same IRC user to converse with you), the "proxy" user will reject any |  | ||||||
|  private messages that are not in that format, and will send back a |  | ||||||
|  nice reminder as a private message. |  | ||||||
|  |  | ||||||
| The bot also supports some basic commands, which are invoked by sending |  | ||||||
|  a private message to it. Use '!help' to get a list of commands, and |  | ||||||
|  '!help <command>' to get help about a specific command. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| THANKS |  | ||||||
| ------ |  | ||||||
| I'd like to thank the users who supported this mod both on the Minetest |  | ||||||
|  Forums and on the #minetest channel. In no particular order: |  | ||||||
|  |  | ||||||
| 	0gb.us, ShadowNinja, Shaun/kizeren, RAPHAEL, DARGON, Calinou, Exio, |  | ||||||
| 	vortexlabs/mrtux, marveidemanis, marktraceur, jmf/john_minetest, |  | ||||||
| 	sdzen/Muadtralk, VanessaE, PilzAdam, sfan5, celeron55, KikaRz, |  | ||||||
| 	OldCoder, RealBadAngel, and all the people who commented in the |  | ||||||
| 	forum topic. Thanks to you all! |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LICENSE |  | ||||||
| ------- |  | ||||||
|             DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE  |  | ||||||
|                     Version 2, December 2004  |  | ||||||
|  |  | ||||||
|  Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>  |  | ||||||
|  |  | ||||||
|  Everyone is permitted to copy and distribute verbatim or modified  |  | ||||||
|  copies of this license document, and changing it is allowed as long  |  | ||||||
|  as the name is changed.  |  | ||||||
|  |  | ||||||
|             DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE  |  | ||||||
|    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |  | ||||||
|  |  | ||||||
| 	0. You just DO WHAT THE FUCK YOU WANT TO. |  | ||||||
|  |  | ||||||
| The files 'http.lua', 'ltn12.lua', 'mime.lua', 'smtp.lua', 'socket.lua', |  | ||||||
|  and 'url.lua' are part of the luasocket project |  | ||||||
|  (http://luasocket.luaforge.org/). See 'src/luasocket/LICENSE.txt' for |  | ||||||
|  licensing information. |  | ||||||
|  |  | ||||||
							
								
								
									
										176
									
								
								botcmds.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								botcmds.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,176 @@ | |||||||
|  |  | ||||||
|  | irc.bot_commands = {} | ||||||
|  |  | ||||||
|  | -- From RFC1459: | ||||||
|  | -- "Because of IRC’s scandanavian origin, the characters {}| are | ||||||
|  | --  considered to be the lower case equivalents of the characters | ||||||
|  | --  []\, respectively." | ||||||
|  | local irctolower = { ["["]="{", ["\\"]="|", ["]"]="}" } | ||||||
|  |  | ||||||
|  | local function irclower(s) | ||||||
|  | 	return (s:lower():gsub("[%[%]\\]", irctolower)) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | local function nickequals(nick1, nick2) | ||||||
|  | 	return irclower(nick1) == irclower(nick2) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function irc.check_botcmd(msg) | ||||||
|  | 	local prefix = irc.config.command_prefix | ||||||
|  | 	local nick = irc.conn.nick | ||||||
|  | 	local text = msg.args[2] | ||||||
|  | 	local nickpart = text:sub(1, #nick) | ||||||
|  | 	local suffix = text:sub(#nick+1, #nick+2) | ||||||
|  |  | ||||||
|  | 	-- First check for a nick prefix | ||||||
|  | 	if nickequals(nickpart, nick) | ||||||
|  | 			and (suffix == ": " or suffix == ", ") then | ||||||
|  | 		irc.bot_command(msg, text:sub(#nick + 3)) | ||||||
|  | 		return true | ||||||
|  | 	-- Then check for the configured prefix | ||||||
|  | 	elseif prefix and text:sub(1, #prefix):lower() == prefix:lower() then | ||||||
|  | 		irc.bot_command(msg, text:sub(#prefix + 1)) | ||||||
|  | 		return true | ||||||
|  | 	end | ||||||
|  | 	return false | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.bot_command(msg, text) | ||||||
|  | 	-- Remove leading whitespace | ||||||
|  | 	text = text:match("^%s*(.*)") | ||||||
|  | 	if text:sub(1, 1) == "@" then | ||||||
|  | 		local _, _, player_to, message = text:find("^.([^%s]+)%s(.+)$") | ||||||
|  | 		if not player_to then | ||||||
|  | 			return | ||||||
|  | 		elseif not minetest.get_player_by_name(player_to) then | ||||||
|  | 			irc.reply("User '"..player_to.."' is not in the game.") | ||||||
|  | 			return | ||||||
|  | 		elseif not irc.joined_players[player_to] then | ||||||
|  | 			irc.reply("User '"..player_to.."' is not using IRC.") | ||||||
|  | 			return | ||||||
|  | 		end | ||||||
|  | 		minetest.chat_send_player(player_to, | ||||||
|  | 				minetest.colorize(irc.config.pm_color, | ||||||
|  | 				"PM from "..msg.user.nick.."@IRC: "..message, false)) | ||||||
|  | 		irc.reply("Message sent!") | ||||||
|  | 		return | ||||||
|  | 	end | ||||||
|  | 	local pos = text:find(" ", 1, true) | ||||||
|  | 	local cmd, args | ||||||
|  | 	if pos then | ||||||
|  | 		cmd = text:sub(1, pos - 1) | ||||||
|  | 		args = text:sub(pos + 1) | ||||||
|  | 	else | ||||||
|  | 		cmd = text | ||||||
|  | 		args = "" | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	if not irc.bot_commands[cmd] then | ||||||
|  | 		irc.reply("Unknown command '"..cmd.."'. Try 'help'." | ||||||
|  | 			.." Or use @playername <message> to send a private message") | ||||||
|  | 		return | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	local _, message = irc.bot_commands[cmd].func(msg.user, args) | ||||||
|  | 	if message then | ||||||
|  | 		irc.reply(message) | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.register_bot_command(name, def) | ||||||
|  | 	if (not def.func) or (type(def.func) ~= "function") then | ||||||
|  | 		error("Erroneous bot command definition. def.func missing.", 2) | ||||||
|  | 	elseif name:sub(1, 1) == "@" then | ||||||
|  | 		error("Erroneous bot command name. Command name begins with '@'.", 2) | ||||||
|  | 	end | ||||||
|  | 	irc.bot_commands[name] = def | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | irc.register_bot_command("help", { | ||||||
|  | 	params = "<command>", | ||||||
|  | 	description = "Get help about a command", | ||||||
|  | 	func = function(_, args) | ||||||
|  | 		if args == "" then | ||||||
|  | 			local cmdlist = { } | ||||||
|  | 			for name in pairs(irc.bot_commands) do | ||||||
|  | 				cmdlist[#cmdlist+1] = name | ||||||
|  | 			end | ||||||
|  | 			return true, "Available commands: "..table.concat(cmdlist, ", ") | ||||||
|  | 					.." -- Use 'help <command name>' to get" | ||||||
|  | 					.." help about a specific command." | ||||||
|  | 		end | ||||||
|  |  | ||||||
|  | 		local cmd = irc.bot_commands[args] | ||||||
|  | 		if not cmd then | ||||||
|  | 			return false, "Unknown command '"..args.."'." | ||||||
|  | 		end | ||||||
|  |  | ||||||
|  | 		return true, ("Usage: %s%s %s -- %s"):format( | ||||||
|  | 				irc.config.command_prefix or "", | ||||||
|  | 				args, | ||||||
|  | 				cmd.params or "<no parameters>", | ||||||
|  | 				cmd.description or "<no description>") | ||||||
|  | 	end | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | irc.register_bot_command("list", { | ||||||
|  | 	params = "", | ||||||
|  | 	description = "List available commands.", | ||||||
|  | 	func = function() | ||||||
|  | 		return false, "The `list` command has been merged into `help`." | ||||||
|  | 				.." Use `help` with no arguments to get a list." | ||||||
|  | 	end | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | irc.register_bot_command("whereis", { | ||||||
|  | 	params = "<player>", | ||||||
|  | 	description = "Tell the location of <player>", | ||||||
|  | 	func = function(_, args) | ||||||
|  | 		if args == "" then | ||||||
|  | 			return false, "Player name required." | ||||||
|  | 		end | ||||||
|  | 		local player = minetest.get_player_by_name(args) | ||||||
|  | 		if not player then | ||||||
|  | 			return false, "There is no player named '"..args.."'" | ||||||
|  | 		end | ||||||
|  | 		local fmt = "Player %s is at (%.2f,%.2f,%.2f)" | ||||||
|  | 		local pos = player:get_pos() | ||||||
|  | 		return true, fmt:format(args, pos.x, pos.y, pos.z) | ||||||
|  | 	end | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | local starttime = os.time() | ||||||
|  | irc.register_bot_command("uptime", { | ||||||
|  | 	description = "Tell how much time the server has been up", | ||||||
|  | 	func = function() | ||||||
|  | 		local cur_time = os.time() | ||||||
|  | 		local diff = os.difftime(cur_time, starttime) | ||||||
|  | 		local fmt = "Server has been running for %d:%02d:%02d" | ||||||
|  | 		return true, fmt:format( | ||||||
|  | 			math.floor(diff / 60 / 60), | ||||||
|  | 			math.floor(diff / 60) % 60, | ||||||
|  | 			math.floor(diff) % 60 | ||||||
|  | 		) | ||||||
|  | 	end | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | irc.register_bot_command("players", { | ||||||
|  | 	description = "List the players on the server", | ||||||
|  | 	func = function() | ||||||
|  | 		local players = minetest.get_connected_players() | ||||||
|  | 		local names = {} | ||||||
|  | 		for _, player in pairs(players) do | ||||||
|  | 			table.insert(names, player:get_player_name()) | ||||||
|  | 		end | ||||||
|  | 		return true, "Connected players: " | ||||||
|  | 				..table.concat(names, ", ") | ||||||
|  | 	end | ||||||
|  | }) | ||||||
|  |  | ||||||
							
								
								
									
										41
									
								
								callback.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								callback.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | -- This file is licensed under the terms of the BSD 2-clause license. | ||||||
|  | -- See LICENSE.txt for details. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | minetest.register_on_joinplayer(function(player) | ||||||
|  | 	local name = player:get_player_name() | ||||||
|  | 	if irc.connected and irc.config.send_join_part then | ||||||
|  | 		irc.say("*** "..name.." joined the game") | ||||||
|  | 	end | ||||||
|  | end) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | minetest.register_on_leaveplayer(function(player, timed_out) | ||||||
|  | 	local name = player:get_player_name() | ||||||
|  | 	if irc.connected and irc.config.send_join_part then | ||||||
|  | 		irc.say("*** "..name.." left the game".. | ||||||
|  | 				(timed_out and " (Timed out)" or "")) | ||||||
|  | 	end | ||||||
|  | end) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | minetest.register_on_chat_message(function(name, message) | ||||||
|  | 	if not irc.connected | ||||||
|  | 	   or message:sub(1, 1) == "/" | ||||||
|  | 	   or message:sub(1, 5) == "[off]" | ||||||
|  | 	   or not irc.joined_players[name] | ||||||
|  | 	   or (not minetest.check_player_privs(name, {shout=true})) then | ||||||
|  | 		return | ||||||
|  | 	end | ||||||
|  | 	local nl = message:find("\n", 1, true) | ||||||
|  | 	if nl then | ||||||
|  | 		message = message:sub(1, nl - 1) | ||||||
|  | 	end | ||||||
|  | 	irc.say(irc.playerMessage(name, core.strip_colors(message))) | ||||||
|  | end) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | minetest.register_on_shutdown(function() | ||||||
|  | 	irc.disconnect("Game shutting down.") | ||||||
|  | end) | ||||||
|  |  | ||||||
							
								
								
									
										134
									
								
								chatcmds.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								chatcmds.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,134 @@ | |||||||
|  | -- This file is licensed under the terms of the BSD 2-clause license. | ||||||
|  | -- See LICENSE.txt for details. | ||||||
|  |  | ||||||
|  | -- Note: This file does NOT conatin every chat command, only general ones. | ||||||
|  | -- Feature-specific commands (like /join) are in their own files. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | minetest.register_chatcommand("irc_msg", { | ||||||
|  | 	params = "<name> <message>", | ||||||
|  | 	description = "Send a private message to an IRC user", | ||||||
|  | 	privs = {shout=true}, | ||||||
|  | 	func = function(name, param) | ||||||
|  | 		if not irc.connected then | ||||||
|  | 			return false, "Not connected to IRC. Use /irc_connect to connect." | ||||||
|  | 		end | ||||||
|  | 		local found, _, toname, message = param:find("^([^%s]+)%s(.+)") | ||||||
|  | 		if not found then | ||||||
|  | 			return false, "Invalid usage, see /help irc_msg." | ||||||
|  | 		end | ||||||
|  | 		local toname_l = toname:lower() | ||||||
|  | 		local validNick = false | ||||||
|  | 		local hint = "They have to be in the channel" | ||||||
|  | 		for nick in pairs(irc.conn.channels[irc.config.channel].users) do | ||||||
|  | 			if nick:lower() == toname_l then | ||||||
|  | 				validNick = true | ||||||
|  | 				break | ||||||
|  | 			end | ||||||
|  | 		end | ||||||
|  | 		if toname_l:find("serv$") or toname_l:find("bot$") then | ||||||
|  | 			hint = "it looks like a bot or service" | ||||||
|  | 			validNick = false | ||||||
|  | 		end | ||||||
|  | 		if not validNick then | ||||||
|  | 			return false, "You can not message that user. ("..hint..")" | ||||||
|  | 		end | ||||||
|  | 		irc.say(toname, irc.playerMessage(name, message)) | ||||||
|  | 		return true, "Message sent!" | ||||||
|  | 	end | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | minetest.register_chatcommand("irc_names", { | ||||||
|  | 	params = "", | ||||||
|  | 	description = "List the users in IRC.", | ||||||
|  | 	func = function() | ||||||
|  | 		if not irc.connected then | ||||||
|  | 			return false, "Not connected to IRC. Use /irc_connect to connect." | ||||||
|  | 		end | ||||||
|  | 		local users = { } | ||||||
|  | 		for nick in pairs(irc.conn.channels[irc.config.channel].users) do | ||||||
|  | 			table.insert(users, nick) | ||||||
|  | 		end | ||||||
|  | 		return true, "Users in IRC: "..table.concat(users, ", ") | ||||||
|  | 	end | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | minetest.register_chatcommand("irc_connect", { | ||||||
|  | 	description = "Connect to the IRC server.", | ||||||
|  | 	privs = {irc_admin=true}, | ||||||
|  | 	func = function(name) | ||||||
|  | 		if irc.connected then | ||||||
|  | 			return false, "You are already connected to IRC." | ||||||
|  | 		end | ||||||
|  | 		minetest.chat_send_player(name, "IRC: Connecting...") | ||||||
|  | 		irc.connect() | ||||||
|  | 	end | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | minetest.register_chatcommand("irc_disconnect", { | ||||||
|  | 	params = "[message]", | ||||||
|  | 	description = "Disconnect from the IRC server.", | ||||||
|  | 	privs = {irc_admin=true}, | ||||||
|  | 	func = function(name, param) | ||||||
|  | 		if not irc.connected then | ||||||
|  | 			return false, "Not connected to IRC. Use /irc_connect to connect." | ||||||
|  | 		end | ||||||
|  | 		if param == "" then | ||||||
|  | 			param = "Manual disconnect by "..name | ||||||
|  | 		end | ||||||
|  | 		irc.disconnect(param) | ||||||
|  | 	end | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | minetest.register_chatcommand("irc_reconnect", { | ||||||
|  | 	description = "Reconnect to the IRC server.", | ||||||
|  | 	privs = {irc_admin=true}, | ||||||
|  | 	func = function(name) | ||||||
|  | 		if not irc.connected then | ||||||
|  | 			return false, "Not connected to IRC. Use /irc_connect to connect." | ||||||
|  | 		end | ||||||
|  | 		minetest.chat_send_player(name, "IRC: Reconnecting...") | ||||||
|  | 		irc.disconnect("Reconnecting...") | ||||||
|  | 		irc.connect() | ||||||
|  | 	end | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | minetest.register_chatcommand("irc_quote", { | ||||||
|  | 	params = "<command>", | ||||||
|  | 	description = "Send a raw command to the IRC server.", | ||||||
|  | 	privs = {irc_admin=true}, | ||||||
|  | 	func = function(name, param) | ||||||
|  | 		if not irc.connected then | ||||||
|  | 			return false, "Not connected to IRC. Use /irc_connect to connect." | ||||||
|  | 		end | ||||||
|  | 		irc.queue(param) | ||||||
|  | 		minetest.chat_send_player(name, "Command sent!") | ||||||
|  | 	end | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | local oldme = minetest.chatcommands["me"].func | ||||||
|  | -- luacheck: ignore | ||||||
|  | minetest.chatcommands["me"].func = function(name, param, ...) | ||||||
|  | 	irc.say(("* %s %s"):format(name, param)) | ||||||
|  | 	return oldme(name, param, ...) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | if irc.config.send_kicks and minetest.chatcommands["kick"] then | ||||||
|  | 	local oldkick = minetest.chatcommands["kick"].func | ||||||
|  | 	-- luacheck: ignore | ||||||
|  | 	minetest.chatcommands["kick"].func = function(name, param, ...) | ||||||
|  | 		local plname, reason = param:match("^(%S+)%s*(.*)$") | ||||||
|  | 		if not plname then | ||||||
|  | 			return false, "Usage: /kick player [reason]" | ||||||
|  | 		end | ||||||
|  | 		irc.say(("*** Kicked %s.%s"):format(name, | ||||||
|  | 				reason~="" and " Reason: "..reason or "")) | ||||||
|  | 		return oldkick(name, param, ...) | ||||||
|  | 	end | ||||||
|  | end | ||||||
| @@ -1,22 +0,0 @@ | |||||||
|  |  | ||||||
| # :mode=cmake: |  | ||||||
|  |  | ||||||
| set(CMAKE_SYSTEM_NAME Windows) |  | ||||||
|  |  | ||||||
| set(PLATFORM i586-mingw32msvc) |  | ||||||
|  |  | ||||||
| set(MGW_TOOLCHAIN_PATH |  | ||||||
|     /usr/${PLATFORM} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| set(WIN32 1) |  | ||||||
|  |  | ||||||
| set(CMAKE_C_COMPILER /usr/bin/${PLATFORM}-gcc) |  | ||||||
| set(CMAKE_RC_COMPILER /usr/bin/${PLATFORM}-windres) |  | ||||||
|  |  | ||||||
| set(CMAKE_FIND_ROOT_PATH ${MGW_TOOLCHAIN_PATH}) |  | ||||||
|  |  | ||||||
| set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) |  | ||||||
|  |  | ||||||
| set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) |  | ||||||
| set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) |  | ||||||
							
								
								
									
										59
									
								
								config.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								config.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | |||||||
|  | -- This file is licensed under the terms of the BSD 2-clause license. | ||||||
|  | -- See LICENSE.txt for details. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | irc.config = {} | ||||||
|  |  | ||||||
|  | local function setting(stype, name, default, required) | ||||||
|  | 	local value | ||||||
|  | 	if minetest.settings and minetest.settings.get and minetest.settings.get_bool then | ||||||
|  | 		if stype == "bool" then | ||||||
|  | 			value = minetest.settings:get_bool("irc."..name) | ||||||
|  | 		elseif stype == "string" then | ||||||
|  | 			value = minetest.settings:get("irc."..name) | ||||||
|  | 		elseif stype == "number" then | ||||||
|  | 			value = tonumber(minetest.settings:get("irc."..name)) | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  | 	if value == nil then | ||||||
|  | 		if required then | ||||||
|  | 			error("Required configuration option irc.".. | ||||||
|  | 				name.." missing.") | ||||||
|  | 		end | ||||||
|  | 		value = default | ||||||
|  | 	end | ||||||
|  | 	irc.config[name] = value | ||||||
|  | end | ||||||
|  |  | ||||||
|  | ------------------------- | ||||||
|  | -- BASIC USER SETTINGS -- | ||||||
|  | ------------------------- | ||||||
|  |  | ||||||
|  | setting("string", "nick", nil, true) -- Nickname | ||||||
|  | setting("string", "server", nil, true) -- Server address to connect to | ||||||
|  | setting("number", "port", 6667) -- Server port to connect to | ||||||
|  | setting("string", "NSPass") -- NickServ password | ||||||
|  | setting("string", "sasl.user", irc.config.nick) -- SASL username | ||||||
|  | setting("string", "username", "Minetest") -- Username/ident | ||||||
|  | setting("string", "realname", "Minetest") -- Real name/GECOS | ||||||
|  | setting("string", "sasl.pass") -- SASL password | ||||||
|  | setting("string", "channel", nil, true) -- Channel to join | ||||||
|  | setting("string", "key") -- Key for the channel | ||||||
|  | setting("bool",   "send_join_part", true) -- Whether to send player join and part messages to the channel | ||||||
|  | setting("bool",   "send_kicks", false) -- Whether to send player kicked messages to the channel | ||||||
|  |  | ||||||
|  | ----------------------- | ||||||
|  | -- ADVANCED SETTINGS -- | ||||||
|  | ----------------------- | ||||||
|  |  | ||||||
|  | setting("string", "password") -- Server password | ||||||
|  | setting("bool",   "secure", false) -- Enable a TLS connection, requires LuaSEC | ||||||
|  | setting("number", "timeout", 60) -- Underlying socket timeout in seconds. | ||||||
|  | setting("number", "reconnect", 600) -- Time between reconnection attempts, in seconds. | ||||||
|  | setting("string", "command_prefix") -- Prefix to use for bot commands | ||||||
|  | setting("bool",   "debug", false) -- Enable debug output | ||||||
|  | setting("bool",   "enable_player_part", true) -- Whether to enable players joining and parting the channel | ||||||
|  | setting("bool",   "auto_join", true) -- Whether to automatically show players in the channel when they join | ||||||
|  | setting("bool",   "auto_connect", true) -- Whether to automatically connect to the server on mod load | ||||||
|  | setting("string", "chat_color", "#339933") -- Color of IRC chat in-game, green by default | ||||||
|  | setting("string", "pm_color", "#8800AA") -- Color of IRC PMs in-game, purple by default | ||||||
							
								
								
									
										263
									
								
								hooks.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								hooks.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,263 @@ | |||||||
|  | -- This file is licensed under the terms of the BSD 2-clause license. | ||||||
|  | -- See LICENSE.txt for details. | ||||||
|  |  | ||||||
|  | local ie = ... | ||||||
|  |  | ||||||
|  | -- MIME is part of LuaSocket | ||||||
|  | local b64e = ie.require("mime").b64 | ||||||
|  |  | ||||||
|  | irc.hooks = {} | ||||||
|  | irc.registered_hooks = {} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | local stripped_chars = "[\2\31]" | ||||||
|  |  | ||||||
|  | local function normalize(text) | ||||||
|  | 	-- Strip colors | ||||||
|  | 	text = text:gsub("\3[0-9][0-9,]*", "") | ||||||
|  |  | ||||||
|  | 	return text:gsub(stripped_chars, "") | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.doHook(conn) | ||||||
|  | 	for name, hook in pairs(irc.registered_hooks) do | ||||||
|  | 		for _, func in pairs(hook) do | ||||||
|  | 			conn:hook(name, func) | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.register_hook(name, func) | ||||||
|  | 	irc.registered_hooks[name] = irc.registered_hooks[name] or {} | ||||||
|  | 	table.insert(irc.registered_hooks[name], func) | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.raw(line) | ||||||
|  | 	if irc.config.debug then | ||||||
|  | 		print("RECV: "..line) | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.send(line) | ||||||
|  | 	if irc.config.debug then | ||||||
|  | 		print("SEND: "..line) | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.chat(msg) | ||||||
|  | 	local channel, text = msg.args[1], msg.args[2] | ||||||
|  | 	if text:sub(1, 1) == string.char(1) then | ||||||
|  | 		irc.conn:invoke("OnCTCP", msg) | ||||||
|  | 		return | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	if channel == irc.conn.nick then | ||||||
|  | 		irc.last_from = msg.user.nick | ||||||
|  | 		irc.conn:invoke("PrivateMessage", msg) | ||||||
|  | 	else | ||||||
|  | 		irc.last_from = channel | ||||||
|  | 		irc.conn:invoke("OnChannelChat", msg) | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | local function get_core_version() | ||||||
|  | 	local status = minetest.get_server_status() | ||||||
|  | 	local start_pos = select(2, status:find("version=", 1, true)) | ||||||
|  | 	local end_pos = status:find(",", start_pos, true) | ||||||
|  | 	return status:sub(start_pos + 1, end_pos - 1) | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.ctcp(msg) | ||||||
|  | 	local text = msg.args[2]:sub(2, -2)  -- Remove ^C | ||||||
|  | 	local args = text:split(' ') | ||||||
|  | 	local command = args[1]:upper() | ||||||
|  |  | ||||||
|  | 	local function reply(s) | ||||||
|  | 		irc.queue(irc.msgs.notice(msg.user.nick, | ||||||
|  | 				("\1%s %s\1"):format(command, s))) | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	if command == "ACTION" and msg.args[1] == irc.config.channel then | ||||||
|  | 		local action = text:sub(8, -1) | ||||||
|  | 		irc.sendLocal(("* %s@IRC %s"):format(msg.user.nick, action)) | ||||||
|  | 	elseif command == "VERSION" then | ||||||
|  | 		reply(("Minetest version %s, IRC mod version %s.") | ||||||
|  | 			:format(get_core_version(), irc.version)) | ||||||
|  | 	elseif command == "PING" then | ||||||
|  | 		reply(args[2]) | ||||||
|  | 	elseif command == "TIME" then | ||||||
|  | 		reply(os.date()) | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.channelChat(msg) | ||||||
|  | 	local text = normalize(msg.args[2]) | ||||||
|  |  | ||||||
|  | 	irc.check_botcmd(msg) | ||||||
|  |  | ||||||
|  | 	-- Don't let a user impersonate someone else by using the nick "IRC" | ||||||
|  | 	local fake = msg.user.nick:lower():match("^[il|]rc$") | ||||||
|  | 	if fake then | ||||||
|  | 		irc.sendLocal("<"..msg.user.nick.."@IRC> "..text) | ||||||
|  | 		return | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	-- Support multiple servers in a channel better by converting: | ||||||
|  | 	-- "<server@IRC> <player> message" into "<player@server> message" | ||||||
|  | 	-- "<server@IRC> *** player joined/left the game" into "*** player joined/left server" | ||||||
|  | 	-- and "<server@IRC> * player orders a pizza" into "* player@server orders a pizza" | ||||||
|  | 	local foundchat, _, chatnick, chatmessage = | ||||||
|  | 		text:find("^<([^>]+)> (.*)$") | ||||||
|  | 	local foundjoin, _, joinnick = | ||||||
|  | 		text:find("^%*%*%* ([^%s]+) joined the game$") | ||||||
|  | 	local foundleave, _, leavenick = | ||||||
|  | 		text:find("^%*%*%* ([^%s]+) left the game$") | ||||||
|  | 	local foundtimedout, _, timedoutnick = | ||||||
|  | 		text:find("^%*%*%* ([^%s]+) left the game %(Timed out%)$") | ||||||
|  | 	local foundaction, _, actionnick, actionmessage = | ||||||
|  | 		text:find("^%* ([^%s]+) (.*)$") | ||||||
|  |  | ||||||
|  | 	if text:sub(1, 5) == "[off]" then | ||||||
|  | 		return | ||||||
|  | 	elseif foundchat then | ||||||
|  | 		irc.sendLocal(("<%s@%s> %s") | ||||||
|  | 				:format(chatnick, msg.user.nick, chatmessage)) | ||||||
|  | 	elseif foundjoin then | ||||||
|  | 		irc.sendLocal(("*** %s joined %s") | ||||||
|  | 				:format(joinnick, msg.user.nick)) | ||||||
|  | 	elseif foundleave then | ||||||
|  | 		irc.sendLocal(("*** %s left %s") | ||||||
|  | 				:format(leavenick, msg.user.nick)) | ||||||
|  | 	elseif foundtimedout then | ||||||
|  | 		irc.sendLocal(("*** %s left %s (Timed out)") | ||||||
|  | 				:format(timedoutnick, msg.user.nick)) | ||||||
|  | 	elseif foundaction then | ||||||
|  | 		irc.sendLocal(("* %s@%s %s") | ||||||
|  | 				:format(actionnick, msg.user.nick, actionmessage)) | ||||||
|  | 	else | ||||||
|  | 		irc.sendLocal(("<%s@IRC> %s"):format(msg.user.nick, text)) | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.pm(msg) | ||||||
|  | 	-- Trim prefix if it is found | ||||||
|  | 	local text = msg.args[2] | ||||||
|  | 	local prefix = irc.config.command_prefix | ||||||
|  | 	if prefix and text:sub(1, #prefix) == prefix then | ||||||
|  | 		text = text:sub(#prefix + 1) | ||||||
|  | 	end | ||||||
|  | 	irc.bot_command(msg, text) | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.kick(channel, target, prefix, reason) | ||||||
|  | 	if target == irc.conn.nick then | ||||||
|  | 		minetest.chat_send_all("IRC: kicked from "..channel.." by "..prefix.nick..".") | ||||||
|  | 		irc.disconnect("Kicked") | ||||||
|  | 	else | ||||||
|  | 		irc.sendLocal(("-!- %s was kicked from %s by %s [%s]") | ||||||
|  | 				:format(target, channel, prefix.nick, reason)) | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.notice(user, target, message) | ||||||
|  | 	if user.nick and target == irc.config.channel then | ||||||
|  | 		irc.sendLocal("-"..user.nick.."@IRC- "..message) | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.mode(user, target, modes, ...) | ||||||
|  | 	local by = "" | ||||||
|  | 	if user.nick then | ||||||
|  | 		by = " by "..user.nick | ||||||
|  | 	end | ||||||
|  | 	local options = "" | ||||||
|  | 	if select("#", ...) > 0 then | ||||||
|  | 		options = " " | ||||||
|  | 	end | ||||||
|  | 	options = options .. table.concat({...}, " ") | ||||||
|  | 	minetest.chat_send_all(("-!- mode/%s [%s%s]%s") | ||||||
|  | 			:format(target, modes, options, by)) | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.nick(user, newNick) | ||||||
|  | 	irc.sendLocal(("-!- %s is now known as %s") | ||||||
|  | 			:format(user.nick, newNick)) | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.join(user, channel) | ||||||
|  | 	irc.sendLocal(("-!- %s joined %s") | ||||||
|  | 			:format(user.nick, channel)) | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.part(user, channel, reason) | ||||||
|  | 	reason = reason or "" | ||||||
|  | 	irc.sendLocal(("-!- %s has left %s [%s]") | ||||||
|  | 			:format(user.nick, channel, reason)) | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.quit(user, reason) | ||||||
|  | 	irc.sendLocal(("-!- %s has quit [%s]") | ||||||
|  | 			:format(user.nick, reason)) | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.disconnect(_, isError) | ||||||
|  | 	irc.connected = false | ||||||
|  | 	if isError then | ||||||
|  | 		minetest.log("error",  "IRC: Error: Disconnected, reconnecting in one minute.") | ||||||
|  | 		minetest.chat_send_all("IRC: Error: Disconnected, reconnecting in one minute.") | ||||||
|  | 		minetest.after(60, irc.connect, irc) | ||||||
|  | 	else | ||||||
|  | 		minetest.log("action", "IRC: Disconnected.") | ||||||
|  | 		minetest.chat_send_all("IRC: Disconnected.") | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.hooks.preregister(conn) | ||||||
|  | 	if not (irc.config["sasl.user"] and irc.config["sasl.pass"]) then return end | ||||||
|  | 	local authString = b64e( | ||||||
|  | 		("%s\x00%s\x00%s"):format( | ||||||
|  | 		irc.config["sasl.user"], | ||||||
|  | 		irc.config["sasl.user"], | ||||||
|  | 		irc.config["sasl.pass"]) | ||||||
|  | 	) | ||||||
|  | 	conn:send("CAP REQ sasl") | ||||||
|  | 	conn:send("AUTHENTICATE PLAIN") | ||||||
|  | 	conn:send("AUTHENTICATE "..authString) | ||||||
|  | 	conn:send("CAP END") | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | irc.register_hook("PreRegister",     irc.hooks.preregister) | ||||||
|  | irc.register_hook("OnRaw",           irc.hooks.raw) | ||||||
|  | irc.register_hook("OnSend",          irc.hooks.send) | ||||||
|  | irc.register_hook("DoPrivmsg",       irc.hooks.chat) | ||||||
|  | irc.register_hook("OnPart",          irc.hooks.part) | ||||||
|  | irc.register_hook("OnKick",          irc.hooks.kick) | ||||||
|  | irc.register_hook("OnJoin",          irc.hooks.join) | ||||||
|  | irc.register_hook("OnQuit",          irc.hooks.quit) | ||||||
|  | irc.register_hook("NickChange",      irc.hooks.nick) | ||||||
|  | irc.register_hook("OnCTCP",          irc.hooks.ctcp) | ||||||
|  | irc.register_hook("PrivateMessage",  irc.hooks.pm) | ||||||
|  | irc.register_hook("OnNotice",        irc.hooks.notice) | ||||||
|  | irc.register_hook("OnChannelChat",   irc.hooks.channelChat) | ||||||
|  | irc.register_hook("OnModeChange",    irc.hooks.mode) | ||||||
|  | irc.register_hook("OnDisconnect",    irc.hooks.disconnect) | ||||||
|  |  | ||||||
							
								
								
									
										227
									
								
								init.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								init.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | |||||||
|  | -- This file is licensed under the terms of the BSD 2-clause license. | ||||||
|  | -- See LICENSE.txt for details. | ||||||
|  |  | ||||||
|  | local modpath = minetest.get_modpath(minetest.get_current_modname()) | ||||||
|  |  | ||||||
|  | -- Handle mod security if needed | ||||||
|  | local ie, req_ie = _G, minetest.request_insecure_environment | ||||||
|  | if req_ie then ie = req_ie() end | ||||||
|  | if not ie then | ||||||
|  | 	error("The IRC mod requires access to insecure functions in order ".. | ||||||
|  | 		"to work.  Please add the irc mod to your secure.trusted_mods ".. | ||||||
|  | 		"setting or disable the irc mod.") | ||||||
|  | end | ||||||
|  |  | ||||||
|  | ie.package.path = | ||||||
|  | 		-- To find LuaIRC's init.lua | ||||||
|  | 		modpath.."/?/init.lua;" | ||||||
|  | 		-- For LuaIRC to find its files | ||||||
|  | 		..modpath.."/?.lua;" | ||||||
|  | 		..ie.package.path | ||||||
|  |  | ||||||
|  | -- The build of Lua that Minetest comes with only looks for libraries under | ||||||
|  | -- /usr/local/share and /usr/local/lib but LuaSocket is often installed under | ||||||
|  | -- /usr/share and /usr/lib. | ||||||
|  | if not rawget(_G, "jit") and package.config:sub(1, 1) == "/" then | ||||||
|  |  | ||||||
|  | 	ie.package.path = ie.package.path.. | ||||||
|  | 			";/usr/share/lua/5.1/?.lua".. | ||||||
|  | 			";/usr/share/lua/5.1/?/init.lua" | ||||||
|  |  | ||||||
|  | 	ie.package.cpath = ie.package.cpath.. | ||||||
|  | 			";/usr/lib/lua/5.1/?.so".. | ||||||
|  | 			";/usr/lib64/lua/5.1/?.so" | ||||||
|  |  | ||||||
|  | 	ie.package.cpath = "/usr/lib/x86_64-linux-gnu/lua/5.1/?.so;"..ie.package.cpath | ||||||
|  |  | ||||||
|  |  | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- Temporarily set require so that LuaIRC can access it | ||||||
|  | local old_require = require | ||||||
|  | require = ie.require | ||||||
|  |  | ||||||
|  | -- Silence warnings about `module` in `ltn12`. | ||||||
|  | local old_module = rawget(_G, "module") | ||||||
|  | rawset(_G, "module", ie.module) | ||||||
|  |  | ||||||
|  | local lib = ie.require("irc") | ||||||
|  |  | ||||||
|  | irc = { | ||||||
|  | 	version = "0.2.0", | ||||||
|  | 	connected = false, | ||||||
|  | 	cur_time = 0, | ||||||
|  | 	message_buffer = {}, | ||||||
|  | 	recent_message_count = 0, | ||||||
|  | 	joined_players = {}, | ||||||
|  | 	modpath = modpath, | ||||||
|  | 	lib = lib, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | -- Compatibility | ||||||
|  | rawset(_G, "mt_irc", irc) | ||||||
|  |  | ||||||
|  | local getinfo = debug.getinfo | ||||||
|  | local warned = { } | ||||||
|  |  | ||||||
|  | local function warn_deprecated(k) | ||||||
|  | 	local info = getinfo(3) | ||||||
|  | 	local loc = info.source..":"..info.currentline | ||||||
|  | 	if warned[loc] then return end | ||||||
|  | 	warned[loc] = true | ||||||
|  | 	print("COLON: "..tostring(k)) | ||||||
|  | 	minetest.log("warning", "Deprecated use of colon notation when calling" | ||||||
|  | 			.." method `"..tostring(k).."` at "..loc) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- This is a hack. | ||||||
|  | setmetatable(irc, { | ||||||
|  | 	__newindex = function(t, k, v) | ||||||
|  | 		if type(v) == "function" then | ||||||
|  | 			local f = v | ||||||
|  | 			v = function(me, ...) | ||||||
|  | 				if rawequal(me, t) then | ||||||
|  | 					warn_deprecated(k) | ||||||
|  | 					return f(...) | ||||||
|  | 				else | ||||||
|  | 					return f(me, ...) | ||||||
|  | 				end | ||||||
|  | 			end | ||||||
|  | 		end | ||||||
|  | 		rawset(t, k, v) | ||||||
|  | 	end, | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | dofile(modpath.."/config.lua") | ||||||
|  | dofile(modpath.."/messages.lua") | ||||||
|  | loadfile(modpath.."/hooks.lua")(ie) | ||||||
|  | dofile(modpath.."/callback.lua") | ||||||
|  | dofile(modpath.."/chatcmds.lua") | ||||||
|  | dofile(modpath.."/botcmds.lua") | ||||||
|  |  | ||||||
|  | -- Restore old (safe) functions | ||||||
|  | require = old_require | ||||||
|  | rawset(_G, "module", old_module) | ||||||
|  |  | ||||||
|  | if irc.config.enable_player_part then | ||||||
|  | 	dofile(modpath.."/player_part.lua") | ||||||
|  | else | ||||||
|  | 	setmetatable(irc.joined_players, {__index = function() return true end}) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | minetest.register_privilege("irc_admin", { | ||||||
|  | 	description = "Allow IRC administrative tasks to be performed.", | ||||||
|  | 	give_to_singleplayer = true, | ||||||
|  | 	give_to_admin = true, | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | local stepnum = 0 | ||||||
|  |  | ||||||
|  | minetest.register_globalstep(function(dtime) return irc.step(dtime) end) | ||||||
|  |  | ||||||
|  | function irc.step() | ||||||
|  | 	if stepnum == 3 then | ||||||
|  | 		if irc.config.auto_connect then | ||||||
|  | 			irc.connect() | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  | 	stepnum = stepnum + 1 | ||||||
|  |  | ||||||
|  | 	if not irc.connected then return end | ||||||
|  |  | ||||||
|  | 	-- Hooks will manage incoming messages and errors | ||||||
|  | 	local good, err = xpcall(function() irc.conn:think() end, debug.traceback) | ||||||
|  | 	if not good then | ||||||
|  | 		print(err) | ||||||
|  | 		return | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.connect() | ||||||
|  | 	if irc.connected then | ||||||
|  | 		minetest.log("error", "IRC: Ignoring attempt to connect when already connected.") | ||||||
|  | 		return | ||||||
|  | 	end | ||||||
|  | 	irc.conn = irc.lib.new({ | ||||||
|  | 		nick = irc.config.nick, | ||||||
|  | 		username = irc.config.username, | ||||||
|  | 		realname = irc.config.realname, | ||||||
|  | 	}) | ||||||
|  | 	irc.doHook(irc.conn) | ||||||
|  |  | ||||||
|  | 	-- We need to swap the `require` function again since | ||||||
|  | 	-- LuaIRC `require`s `ssl` if `irc.secure` is true. | ||||||
|  | 	old_require = require | ||||||
|  | 	require = ie.require | ||||||
|  |  | ||||||
|  | 	local good, message = pcall(function() | ||||||
|  | 		irc.conn:connect({ | ||||||
|  | 			host = irc.config.server, | ||||||
|  | 			port = irc.config.port, | ||||||
|  | 			password = irc.config.password, | ||||||
|  | 			timeout = irc.config.timeout, | ||||||
|  | 			reconnect = irc.config.reconnect, | ||||||
|  | 			secure = irc.config.secure | ||||||
|  | 		}) | ||||||
|  | 	end) | ||||||
|  |  | ||||||
|  | 	require = old_require | ||||||
|  |  | ||||||
|  | 	if not good then | ||||||
|  | 		minetest.log("error", ("IRC: Connection error: %s: %s -- Reconnecting in %d seconds...") | ||||||
|  | 					:format(irc.config.server, message, irc.config.reconnect)) | ||||||
|  | 		minetest.after(irc.config.reconnect, function() irc.connect() end) | ||||||
|  | 		return | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	if irc.config.NSPass then | ||||||
|  | 		irc.conn:queue(irc.msgs.privmsg( | ||||||
|  | 				"NickServ", "IDENTIFY "..irc.config.NSPass)) | ||||||
|  | 	end | ||||||
|  |  | ||||||
|  | 	irc.conn:join(irc.config.channel, irc.config.key) | ||||||
|  | 	irc.connected = true | ||||||
|  | 	minetest.log("action", "IRC: Connected!") | ||||||
|  | 	minetest.chat_send_all("IRC: Connected!") | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.disconnect(message) | ||||||
|  | 	if irc.connected then | ||||||
|  | 		--The OnDisconnect hook will clear irc.connected and print a disconnect message | ||||||
|  | 		irc.conn:disconnect(message) | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.say(to, message) | ||||||
|  | 	if not message then | ||||||
|  | 		message = to | ||||||
|  | 		to = irc.config.channel | ||||||
|  | 	end | ||||||
|  | 	to = to or irc.config.channel | ||||||
|  |  | ||||||
|  | 	irc.queue(irc.msgs.privmsg(to, message)) | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.reply(message) | ||||||
|  | 	if not irc.last_from then | ||||||
|  | 		return | ||||||
|  | 	end | ||||||
|  | 	message = message:gsub("[\r\n%z]", " \\n ") | ||||||
|  | 	irc.say(irc.last_from, message) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function irc.send(msg) | ||||||
|  | 	if not irc.connected then return end | ||||||
|  | 	irc.conn:send(msg) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function irc.queue(msg) | ||||||
|  | 	if not irc.connected then return end | ||||||
|  | 	irc.conn:queue(msg) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | minetest.log("action", "[irc] loaded.") | ||||||
							
								
								
									
										1
									
								
								irc
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								irc
									
									
									
									
									
										Submodule
									
								
							 Submodule irc added at b8d594e651
									
								
							
							
								
								
									
										17
									
								
								messages.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								messages.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | -- This file is licensed under the terms of the BSD 2-clause license. | ||||||
|  | -- See LICENSE.txt for details. | ||||||
|  |  | ||||||
|  | irc.msgs = irc.lib.msgs | ||||||
|  |  | ||||||
|  | function irc.logChat(message) | ||||||
|  | 	minetest.log("action", "IRC CHAT: "..message) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function irc.sendLocal(message) | ||||||
|  | 	minetest.chat_send_all(minetest.colorize(irc.config.chat_color, message)) | ||||||
|  | 	irc.logChat(message) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function irc.playerMessage(name, message) | ||||||
|  | 	return ("<%s> %s"):format(name, message) | ||||||
|  | end | ||||||
							
								
								
									
										5
									
								
								mod.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								mod.conf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | name = irc | ||||||
|  | description = """ | ||||||
|  | This mod is just a glue between IRC and Minetest. | ||||||
|  | It provides two-way communication between the in-game chat, and an arbitrary IRC channel. | ||||||
|  | """ | ||||||
							
								
								
									
										72
									
								
								player_part.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								player_part.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | -- This file is licensed under the terms of the BSD 2-clause license. | ||||||
|  | -- See LICENSE.txt for details. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function irc.player_part(name) | ||||||
|  | 	if not irc.joined_players[name] then | ||||||
|  | 		return false, "You are not in the channel" | ||||||
|  | 	end | ||||||
|  | 	irc.joined_players[name] = nil | ||||||
|  | 	return true, "You left the channel" | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function irc.player_join(name) | ||||||
|  | 	if irc.joined_players[name] then | ||||||
|  | 		return false, "You are already in the channel" | ||||||
|  | 	elseif not minetest.get_player_by_name(name) then | ||||||
|  | 		return false, "You need to be in-game to join the channel" | ||||||
|  | 	end | ||||||
|  | 	irc.joined_players[name] = true | ||||||
|  | 	return true, "You joined the channel" | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | minetest.register_chatcommand("join", { | ||||||
|  | 	description = "Join the IRC channel", | ||||||
|  | 	privs = {shout=true}, | ||||||
|  | 	func = function(name) | ||||||
|  | 		return irc.player_join(name) | ||||||
|  | 	end | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | minetest.register_chatcommand("part", { | ||||||
|  | 	description = "Part the IRC channel", | ||||||
|  | 	privs = {shout=true}, | ||||||
|  | 	func = function(name) | ||||||
|  | 		return irc.player_part(name) | ||||||
|  | 	end | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | minetest.register_chatcommand("who", { | ||||||
|  | 	description = "Tell who is currently on the channel", | ||||||
|  | 	privs = {}, | ||||||
|  | 	func = function() | ||||||
|  | 		local out, n = { }, 0 | ||||||
|  | 		for plname in pairs(irc.joined_players) do | ||||||
|  | 			n = n + 1 | ||||||
|  | 			out[n] = plname | ||||||
|  | 		end | ||||||
|  | 		table.sort(out) | ||||||
|  | 		return true, "Players in channel: "..table.concat(out, ", ") | ||||||
|  | 	end | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | minetest.register_on_joinplayer(function(player) | ||||||
|  | 	local name = player:get_player_name() | ||||||
|  | 	irc.joined_players[name] = irc.config.auto_join | ||||||
|  | end) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | minetest.register_on_leaveplayer(function(player) | ||||||
|  | 	local name = player:get_player_name() | ||||||
|  | 	irc.joined_players[name] = nil | ||||||
|  | end) | ||||||
|  |  | ||||||
|  | function irc.sendLocal(message) | ||||||
|  | 	for name, _ in pairs(irc.joined_players) do | ||||||
|  | 		minetest.chat_send_player(name, | ||||||
|  | 					minetest.colorize(irc.config.chat_color, message)) | ||||||
|  | 	end | ||||||
|  | 	irc.logChat(message) | ||||||
|  | end | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| #! /bin/sh |  | ||||||
|  |  | ||||||
| mkdir -p Build  \ |  | ||||||
| && cd Build     \ |  | ||||||
| && cmake ..     \ |  | ||||||
| && make         \ |  | ||||||
| && cd ..        \ |  | ||||||
| && cp -r Build/irc $1 |  | ||||||
							
								
								
									
										75
									
								
								settingtypes.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								settingtypes.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | |||||||
|  |  | ||||||
|  | [Basic] | ||||||
|  |  | ||||||
|  | # Whether to automatically connect to the server on mod load. | ||||||
|  | # If false, you must use /irc_connect to connect. | ||||||
|  | irc.auto_connect (Auto-connect on load) bool true | ||||||
|  |  | ||||||
|  | # Nickname for the bot. May only contain characters A-Z, 0-9 | ||||||
|  | # '{', '}', '[', ']', '|', '^', '-', or '_'. | ||||||
|  | irc.nick (Bot nickname) string Minetest | ||||||
|  |  | ||||||
|  | # Server to connect to. | ||||||
|  | irc.server (IRC server) string irc.freenode.net | ||||||
|  |  | ||||||
|  | # Server port. | ||||||
|  | # The standard IRC protocol port is 6667 for regular servers, | ||||||
|  | # or 6697 for SSL-enabled servers. | ||||||
|  | # If unsure, leave at 6667. | ||||||
|  | irc.port (IRC server port) int 6667 1 65535 | ||||||
|  |  | ||||||
|  | # Channel the bot joins after connecting. | ||||||
|  | irc.channel (Channel to join) string ##mt-irc-mod | ||||||
|  |  | ||||||
|  | [Authentication] | ||||||
|  |  | ||||||
|  | # Password for authenticating to NickServ. | ||||||
|  | # Leave empty to not authenticate with NickServ. | ||||||
|  | irc.NSPass (NickServ password) string | ||||||
|  |  | ||||||
|  | # IRC server password. | ||||||
|  | # Leave empty for no password. | ||||||
|  | irc.password (Server password) string | ||||||
|  |  | ||||||
|  | # Password for joining the channel. | ||||||
|  | # Leave empty if your channel is not protected. | ||||||
|  | irc.key (Channel key) string | ||||||
|  |  | ||||||
|  | # Enable TLS connection. | ||||||
|  | # Requires LuaSEC <https://github.com/brunoos/luasec>. | ||||||
|  | irc.secure (Use TLS) bool false | ||||||
|  |  | ||||||
|  | # Username for SASL authentication. | ||||||
|  | # Leave empty to use the nickname. | ||||||
|  | irc.sasl.user (SASL username) string | ||||||
|  |  | ||||||
|  | # Password for SASL authentication. | ||||||
|  | # Leave empty to not authenticate via SASL. | ||||||
|  | irc.sasl.pass (SASL password) string | ||||||
|  |  | ||||||
|  | [Advanced] | ||||||
|  |  | ||||||
|  | # Enable this to make the bot send messages when players join | ||||||
|  | # or leave the game server. | ||||||
|  | irc.send_join_part (Send join and part messages) bool true | ||||||
|  |  | ||||||
|  | # Enable this to make the bot send messages when players are kicked. | ||||||
|  | irc.send_kicks (Send kick messages) bool false | ||||||
|  |  | ||||||
|  | # Underlying socket timeout in seconds. | ||||||
|  | irc.timeout (Timeout) int 60 1 | ||||||
|  |  | ||||||
|  | # Time between reconnection attempts, in seconds. | ||||||
|  | irc.reconnect (Reconnect delay) int 600 1 | ||||||
|  |  | ||||||
|  | # Prefix to use for bot commands. | ||||||
|  | irc.command_prefix (Command prefix) string | ||||||
|  |  | ||||||
|  | # Enable debug output. | ||||||
|  | irc.debug (Debug mode) bool false | ||||||
|  |  | ||||||
|  | # Whether to enable players joining and parting the channel. | ||||||
|  | irc.enable_player_part (Allow player join/part) bool true | ||||||
|  |  | ||||||
|  | # Whether to automatically show players in the channel when they join. | ||||||
|  | irc.auto_join (Auto join players) bool true | ||||||
 Submodule src/LuaIRC deleted from bc79606de0
									
								
							
							
								
								
									
										106
									
								
								src/botcmds.lua
									
									
									
									
									
								
							
							
						
						
									
										106
									
								
								src/botcmds.lua
									
									
									
									
									
								
							| @@ -1,106 +0,0 @@ | |||||||
| mt_irc.bot_commands = {} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc:bot_command(user, message) |  | ||||||
| 	local pos = message:find(" ", 1, true) |  | ||||||
| 	local cmd, args |  | ||||||
| 	if pos then |  | ||||||
| 		cmd = message:sub(1, pos - 1) |  | ||||||
| 		args = message:sub(pos + 1) |  | ||||||
| 	else |  | ||||||
| 		cmd = message |  | ||||||
| 		args = "" |  | ||||||
| 	end |  | ||||||
|   |  | ||||||
| 	if not self.bot_commands[cmd] then |  | ||||||
| 		self:say(user.nick, "Unknown command '"..cmd.."'. Try `!help'." |  | ||||||
| 			.." Or use @playername <message> to send a private message") |  | ||||||
| 		return |  | ||||||
| 	end |  | ||||||
|   |  | ||||||
| 	self.bot_commands[cmd].func(user, args) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc:register_bot_command(name, def) |  | ||||||
| 	if (not def.func) or (type(def.func) ~= "function") then |  | ||||||
| 		error("Erroneous bot command definition. def.func missing.", 2) |  | ||||||
| 	end |  | ||||||
| 	self.bot_commands[name] = def |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| mt_irc:register_bot_command("help", { |  | ||||||
| 	params = "<command>", |  | ||||||
| 	description = "Get help about a command", |  | ||||||
| 	func = function(user, args) |  | ||||||
| 		if args == "" then |  | ||||||
| 			mt_irc:say(user.nick, "No command name specified. Use 'list' for a list of cammands") |  | ||||||
| 			return |  | ||||||
| 		end |  | ||||||
|  |  | ||||||
| 		local cmd = mt_irc.bot_commands[args] |  | ||||||
| 		if not cmd then |  | ||||||
| 			mt_irc:say(user.nick, "Unknown command '"..cmdname.."'.") |  | ||||||
| 			return |  | ||||||
| 		end |  | ||||||
|  |  | ||||||
| 		local usage = ("Usage: %c%s %s -- %s"):format( |  | ||||||
| 				mt_irc.config.command_prefix, |  | ||||||
| 				args, |  | ||||||
| 				cmd.params or "<no parameters>", |  | ||||||
| 				cmd.description or "<no description>") |  | ||||||
| 		mt_irc:say(user.nick, usage)		 |  | ||||||
| 	end |  | ||||||
| }) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| mt_irc:register_bot_command("list", { |  | ||||||
| 	params = "", |  | ||||||
| 	description = "List available commands.", |  | ||||||
| 	func = function(user, args) |  | ||||||
| 		local cmdlist = "Available commands: " |  | ||||||
| 		for name, cmd in pairs(mt_irc.bot_commands) do |  | ||||||
| 			cmdlist = cmdlist..name..", " |  | ||||||
| 		end |  | ||||||
| 		mt_irc:say(user.nick, cmdlist |  | ||||||
| 			.." -- Use 'help <command name>' to get help about a specific command.") |  | ||||||
| 	end |  | ||||||
| }) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| mt_irc:register_bot_command("whereis", { |  | ||||||
| 	params = "<player>", |  | ||||||
| 	description = "Tell the location of <player>", |  | ||||||
| 	func = function(user, args) |  | ||||||
| 		if args == "" then |  | ||||||
| 			mt_irc:bot_help(user, "whereis") |  | ||||||
| 			return |  | ||||||
| 		end |  | ||||||
| 		local player = minetest.env:get_player_by_name(args) |  | ||||||
| 		if player then |  | ||||||
| 			local fmt = "Player %s is at (%.2f,%.2f,%.2f)" |  | ||||||
| 			local pos = player:getpos() |  | ||||||
| 			mt_irc:say(user.nick, fmt:format(args, pos.x, pos.y, pos.z)) |  | ||||||
| 			return |  | ||||||
| 		end |  | ||||||
| 		mt_irc:say(user.nick, "There is No player named '"..args.."'") |  | ||||||
| 	end |  | ||||||
| }) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| local starttime = os.time() |  | ||||||
| mt_irc:register_bot_command("uptime", { |  | ||||||
| 	description = "Tell how much time the server has been up", |  | ||||||
| 	func = function(user, args) |  | ||||||
| 		local cur_time = os.time() |  | ||||||
| 		local diff = os.difftime(cur_time, starttime) |  | ||||||
| 		local fmt = "Server has been running for %d:%02d:%02d" |  | ||||||
| 		mt_irc:say(user.nick, fmt:format( |  | ||||||
| 			math.floor(diff / 60 / 60), |  | ||||||
| 			math.mod(math.floor(diff / 60), 60), |  | ||||||
| 			math.mod(math.floor(diff), 60) |  | ||||||
| 		)) |  | ||||||
| 	end |  | ||||||
| }) |  | ||||||
|  |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| -- This file is licensed under the terms of the BSD 2-clause license. |  | ||||||
| -- See LICENSE.txt for details. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| minetest.register_on_joinplayer(function(player) |  | ||||||
| 	local name = player:get_player_name() |  | ||||||
| 	if mt_irc.connected then |  | ||||||
| 		mt_irc:say("*** "..name.." joined the game") |  | ||||||
| 	end |  | ||||||
| end) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| minetest.register_on_leaveplayer(function(player) |  | ||||||
| 	local name = player:get_player_name() |  | ||||||
| 	if mt_irc.connected then |  | ||||||
| 		mt_irc:say("*** "..name.." left the game") |  | ||||||
| 	end |  | ||||||
| end) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| minetest.register_on_chat_message(function(name, message) |  | ||||||
| 	if not mt_irc.connected |  | ||||||
| 	   or message:sub(1, 1) == "/" |  | ||||||
| 	   or not mt_irc.joined_players[name] |  | ||||||
| 	   or (not minetest.check_player_privs(name, {shout=true})) then |  | ||||||
| 		return |  | ||||||
| 	end |  | ||||||
| 	mt_irc:queueMsg(mt_irc.msgs.playerMessage(mt_irc.config.channel, name, message)) |  | ||||||
| end) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| minetest.register_on_shutdown(function() |  | ||||||
| 	mt_irc:disconnect("Game shutting down.") |  | ||||||
| end) |  | ||||||
|  |  | ||||||
							
								
								
									
										104
									
								
								src/chatcmds.lua
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								src/chatcmds.lua
									
									
									
									
									
								
							| @@ -1,104 +0,0 @@ | |||||||
| -- This file is licensed under the terms of the BSD 2-clause license. |  | ||||||
| -- See LICENSE.txt for details. |  | ||||||
|  |  | ||||||
| -- Note: This file does NOT conatin every chat command, only general ones. |  | ||||||
| -- Feature-specific commands (like /join) are in their own files. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| minetest.register_chatcommand("irc_msg", { |  | ||||||
| 	params = "<name> <message>", |  | ||||||
| 	description = "Send a private message to an IRC user", |  | ||||||
| 	privs = {shout=true}, |  | ||||||
| 	func = function(name, param) |  | ||||||
| 		if not mt_irc.connected then |  | ||||||
| 			minetest.chat_send_player(name, "Not connected to IRC. Use /irc_connect to connect.") |  | ||||||
| 			return |  | ||||||
| 		end |  | ||||||
| 		local found, _, toname, message = param:find("^([^%s]+)%s(.+)") |  | ||||||
| 		if not found then |  | ||||||
| 			minetest.chat_send_player(name, "Invalid usage, see /help irc_msg.") |  | ||||||
| 			return |  | ||||||
| 		end |  | ||||||
| 		local validNick = false |  | ||||||
| 		for nick, user in pairs(mt_irc.conn.channels[mt_irc.config.channel].users) do |  | ||||||
| 			if nick:lower() == toname:lower() then |  | ||||||
| 				validNick = true |  | ||||||
| 				break |  | ||||||
| 			end |  | ||||||
| 		end |  | ||||||
| 		if toname:find("Serv|Bot") then |  | ||||||
| 			validNick = false |  | ||||||
| 		end |  | ||||||
| 		if not validNick then |  | ||||||
| 			minetest.chat_send_player(name, |  | ||||||
| 				"You can not message that user. (Hint: They have to be in the channel)") |  | ||||||
| 			return |  | ||||||
| 		end |  | ||||||
| 		mt_irc:queueMsg(mt_irc.msgs.playerMessage(toname, name, message)) |  | ||||||
| 		minetest.chat_send_player(name, "Message sent!") |  | ||||||
| 	end |  | ||||||
| }) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| minetest.register_chatcommand("irc_connect", { |  | ||||||
| 	description = "Connect to the IRC server.", |  | ||||||
| 	privs = {irc_admin=true}, |  | ||||||
| 	func = function(name, param) |  | ||||||
| 		if mt_irc.connected then |  | ||||||
| 			minetest.chat_send_player(name, "You are already connected to IRC.") |  | ||||||
| 			return |  | ||||||
| 		end |  | ||||||
| 		minetest.chat_send_player(name, "IRC: Connecting...") |  | ||||||
| 		mt_irc:connect() |  | ||||||
| 	end |  | ||||||
| }) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| minetest.register_chatcommand("irc_disconnect", { |  | ||||||
| 	description = "Disconnect from the IRC server.", |  | ||||||
| 	privs = {irc_admin=true}, |  | ||||||
| 	func = function(name, param) |  | ||||||
| 		if not mt_irc.connected then |  | ||||||
| 			minetest.chat_send_player(name, "You are not connected to IRC.") |  | ||||||
| 			return |  | ||||||
| 		end |  | ||||||
| 		mt_irc:disconnect("Manual disconnect.") |  | ||||||
| 	end |  | ||||||
| }) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| minetest.register_chatcommand("irc_reconnect", { |  | ||||||
| 	description = "Reconnect to the IRC server.", |  | ||||||
| 	privs = {irc_admin=true}, |  | ||||||
| 	func = function(name, param) |  | ||||||
| 		if not mt_irc.connected then |  | ||||||
| 			minetest.chat_send_player(name, "You are not connected to IRC.") |  | ||||||
| 			return |  | ||||||
| 		end |  | ||||||
| 		mt_irc:disconnect("Reconnecting...") |  | ||||||
| 		mt_irc:connect() |  | ||||||
| 	end |  | ||||||
| }) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| minetest.register_chatcommand("irc_quote", { |  | ||||||
| 	params = "<command>", |  | ||||||
| 	description = "Send a raw command to the IRC server.", |  | ||||||
| 	privs = {irc_admin=true}, |  | ||||||
| 	func = function(name, param) |  | ||||||
| 		if not mt_irc.connected then |  | ||||||
| 			minetest.chat_send_player(name, "You are not connected to IRC.") |  | ||||||
| 			return |  | ||||||
| 		end |  | ||||||
| 		mt_irc:queueMsg(param) |  | ||||||
| 		minetest.chat_send_player(name, "Command sent!") |  | ||||||
| 	end |  | ||||||
| }) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| local oldme = minetest.chatcommands["me"].func |  | ||||||
| minetest.chatcommands["me"].func = function(name, param) |  | ||||||
| 	oldme(name, param) |  | ||||||
| 	mt_irc:say(("* %s %s"):format(name, param)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| @@ -1,91 +0,0 @@ | |||||||
| -- This file is licensed under the terms of the BSD 2-clause license. |  | ||||||
| -- See LICENSE.txt for details. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| local config = {} |  | ||||||
|  |  | ||||||
| ------------------------- |  | ||||||
| -- BASIC USER SETTINGS -- |  | ||||||
| ------------------------- |  | ||||||
|  |  | ||||||
| -- Nickname (string, default "minetest-"..<server-id>) |  | ||||||
| --  (<server-id> is a random string of 6 hexidecimal numbers). |  | ||||||
| config.nick = minetest.setting_get("irc.nick") |  | ||||||
|  |  | ||||||
| -- Server to connect on joinplayer (string, default "irc.freenode.net") |  | ||||||
| config.server = minetest.setting_get("irc.server") or "irc.freenode.net" |  | ||||||
|  |  | ||||||
| -- Port to connect on joinplayer (number, default 6667) |  | ||||||
| config.port = tonumber(minetest.setting_get("irc.port")) or 6667 |  | ||||||
|  |  | ||||||
| -- NickServ password |  | ||||||
| config.NSPass = minetest.setting_get("irc.NSPass") |  | ||||||
|  |  | ||||||
| -- SASL password (Blank to disable SASL authentication) |  | ||||||
| config.SASLPass = minetest.setting_get("irc.SASLPass") |  | ||||||
|  |  | ||||||
| -- Channel to connect on joinplayer (string, default "##mt-irc-mod") |  | ||||||
| config.channel = minetest.setting_get("irc.channel") or "##mt-irc-mod" |  | ||||||
|  |  | ||||||
| -- Key for the channel (string, default nil) |  | ||||||
| config.key = minetest.setting_get("irc.key") |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ----------------------- |  | ||||||
| -- ADVANCED SETTINGS -- |  | ||||||
| ----------------------- |  | ||||||
|  |  | ||||||
| -- Server password (string, default "") |  | ||||||
| config.password = minetest.setting_get("irc.password") |  | ||||||
|  |  | ||||||
| -- SASL username |  | ||||||
| config.SASLUser = minetest.setting_get("irc.SASLUser") or config.nick |  | ||||||
|  |  | ||||||
| -- Enable a TLS connection, requires LuaSEC (bool, default false) |  | ||||||
| config.secure = minetest.setting_getbool("irc.secure") |  | ||||||
|  |  | ||||||
| -- Time between chat updates in seconds (number, default 2.1). Setting this too low can cause "Excess flood" disconnects. |  | ||||||
| config.interval = tonumber(minetest.setting_get("irc.interval")) or 2.0 |  | ||||||
|  |  | ||||||
| -- Underlying socket timeout in seconds (number, default 60.0). |  | ||||||
| config.timeout = tonumber(minetest.setting_get("irc.timeout")) or 60.0 |  | ||||||
|  |  | ||||||
| -- Prefix to use for bot commands (char, default '!') |  | ||||||
| config.command_prefix = minetest.setting_get("irc.command_prefix") or '!' |  | ||||||
| config.command_prefix = config.command_prefix:sub(1, 1) |  | ||||||
|  |  | ||||||
| -- The format of messages sent to IRC server (string, default "<$(name)> $(message)") |  | ||||||
| -- See `README.txt' for the macros supported here. |  | ||||||
| config.format_out = minetest.setting_get("irc.format_out") or "<$(name)> $(message)" |  | ||||||
|  |  | ||||||
| -- The format of messages sent to IRC server (string, default "<$(name)@IRC> $(message)") |  | ||||||
| -- See `README.txt' for the macros supported here. |  | ||||||
| config.format_in = minetest.setting_get("irc.format_in") or "<$(name)@IRC> $(message)" |  | ||||||
|  |  | ||||||
| -- Enable debug output (boolean, default false) |  | ||||||
| config.debug = minetest.setting_getbool("irc.debug") |  | ||||||
|  |  | ||||||
| -- Whether to enable players joining and parting the channel |  | ||||||
| config.enable_player_part = not minetest.setting_getbool("irc.disable_player_part") |  | ||||||
|  |  | ||||||
| -- Whether to automatically join the channel when player joins |  | ||||||
| --  (boolean, default true) |  | ||||||
| config.auto_join = not minetest.setting_getbool("irc.disable_auto_join") |  | ||||||
|  |  | ||||||
| -- Whether to automatically connect to the server on mod load |  | ||||||
| --  (boolean, default true) |  | ||||||
| config.auto_connect = not minetest.setting_getbool("irc.disable_auto_connect") |  | ||||||
|  |  | ||||||
| -- Set default server nick if not specified. |  | ||||||
| if not config.nick then |  | ||||||
| 	local pr = PseudoRandom(os.time()) |  | ||||||
| 	-- Workaround for bad distribution in minetest PRNG implementation. |  | ||||||
| 	config.nick = ("MT-%02X%02X%02X"):format( |  | ||||||
| 		pr:next(0, 255), |  | ||||||
| 		pr:next(0, 255), |  | ||||||
| 		pr:next(0, 255) |  | ||||||
| 	) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| mt_irc.config = config |  | ||||||
|  |  | ||||||
							
								
								
									
										211
									
								
								src/hooks.lua
									
									
									
									
									
								
							
							
						
						
									
										211
									
								
								src/hooks.lua
									
									
									
									
									
								
							| @@ -1,211 +0,0 @@ | |||||||
| -- This file is licensed under the terms of the BSD 2-clause license. |  | ||||||
| -- See LICENSE.txt for details. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| mt_irc.hooks = {} |  | ||||||
| mt_irc.registered_hooks = {} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc:doHook(conn) |  | ||||||
| 	for name, hook in pairs(self.registered_hooks) do |  | ||||||
| 		for _, func in pairs(hook) do |  | ||||||
| 			conn:hook(name, func) |  | ||||||
| 		end |  | ||||||
| 	end |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc:register_hook(name, func) |  | ||||||
| 	self.registered_hooks[name] = self.registered_hooks[name] or {} |  | ||||||
| 	table.insert(self.registered_hooks[name], func) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.raw(line) |  | ||||||
| 	if mt_irc.config.debug then |  | ||||||
| 		print("RECV: "..line) |  | ||||||
| 	end |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.send(line) |  | ||||||
| 	if mt_irc.config.debug then |  | ||||||
| 		print("SEND: "..line) |  | ||||||
| 	end |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.chat(user, channel, message) |  | ||||||
| 	-- Strip bold, underline, and colors |  | ||||||
| 	message = message:gsub('\2', '') |  | ||||||
| 	message = message:gsub('\31', '') |  | ||||||
| 	message = message:gsub('\3[0-9][0-9,]*', '') |  | ||||||
| 	if channel == mt_irc.conn.nick then |  | ||||||
| 		mt_irc.conn:invoke("PrivateMessage", user, message) |  | ||||||
| 	else |  | ||||||
| 		local c = string.char(1) |  | ||||||
| 		local found, _, action = message:find(("^%sACTION ([^%s]*)%s$"):format(c, c, c)) |  | ||||||
| 		if found then |  | ||||||
| 			mt_irc.conn:invoke("OnChannelAction", user, channel, action) |  | ||||||
| 		else |  | ||||||
| 			mt_irc.conn:invoke("OnChannelChat", user, channel, message) |  | ||||||
| 		end |  | ||||||
| 	end |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.channelChat(user, channel, message) |  | ||||||
| 	local t = { |  | ||||||
| 		access=user.access, |  | ||||||
| 		name=user.nick, |  | ||||||
| 		message=message, |  | ||||||
| 		server=mt_irc.conn.host, |  | ||||||
| 		port=mt_irc.conn.port, |  | ||||||
| 		channel=channel |  | ||||||
| 	} |  | ||||||
| 	local text = mt_irc.config.format_in:expandvars(t) |  | ||||||
| 	mt_irc:sendLocal(text) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.pm(user, message) |  | ||||||
| 	local player_to |  | ||||||
| 	local msg |  | ||||||
| 	if message:sub(1, 1) == "@" then |  | ||||||
| 		local found, _, player_to, message = message:find("^.([^%s]+)%s(.+)$") |  | ||||||
| 		if not mt_irc.joined_players[player_to] then |  | ||||||
| 			mt_irc:say(user.nick, "User '"..player_to.."' has parted.") |  | ||||||
| 			return |  | ||||||
| 		elseif not minetest.get_player_by_name(player_to) then |  | ||||||
| 			mt_irc:say(user.nick, "User '"..player_to.."' is not in the game.") |  | ||||||
| 			return |  | ||||||
| 		end |  | ||||||
| 		local t = { |  | ||||||
| 			name=user.nick, |  | ||||||
| 			message=message, |  | ||||||
| 			server=mt_irc.server, |  | ||||||
| 			port=mt_irc.port, |  | ||||||
| 			channel=mt_irc.channel |  | ||||||
| 		} |  | ||||||
| 		local text = mt_irc.config.format_in:expandvars(t) |  | ||||||
| 		minetest.chat_send_player(player_to, "PM: "..text, false) |  | ||||||
| 		mt_irc:say(user.nick, "Message sent!") |  | ||||||
| 	elseif message:sub(1, 1) == "!" then |  | ||||||
| 		mt_irc:bot_command(user, message:sub(2)) |  | ||||||
| 		return |  | ||||||
| 	else |  | ||||||
| 		mt_irc:say(user.nick, "Invalid command. Use '" |  | ||||||
| 				..mt_irc.config.command_prefix |  | ||||||
| 				.."list' to see possible commands.") |  | ||||||
| 		return |  | ||||||
| 	end |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.kick(channel, target, prefix, reason) |  | ||||||
| 	if target == mt_irc.conn.nick then |  | ||||||
| 		minetest.chat_send_all("IRC: kicked from "..channel.." by "..prefix.nick..".") |  | ||||||
| 		mt_irc:disconnect("Kicked") |  | ||||||
| 	else |  | ||||||
| 		mt_irc:sendLocal(("-!- %s was kicked from %s by %s [%s]") |  | ||||||
| 				:format(target, channel, prefix.nick, reason)) |  | ||||||
| 	end |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.notice(user, target, message) |  | ||||||
| 	if not user.nick then return end --Server NOTICEs |  | ||||||
| 	if target == mt_irc.conn.nick then return end |  | ||||||
| 	mt_irc:sendLocal("--"..user.nick.."@IRC-- "..message) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.mode(user, target, modes, ...) |  | ||||||
| 	local by = "" |  | ||||||
| 	if user.nick then |  | ||||||
| 		by = " by "..user.nick |  | ||||||
| 	end |  | ||||||
| 	local options = "" |  | ||||||
| 	for _, option in pairs({...}) do |  | ||||||
| 		options = options.." "..option |  | ||||||
| 	end |  | ||||||
| 	minetest.chat_send_all(("-!- mode/%s [%s%s]%s") |  | ||||||
| 			:format(target, modes, options, by)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.nick(user, newNick) |  | ||||||
| 	mt_irc:sendLocal(("-!- %s is now known as %s") |  | ||||||
| 			:format(user.nick, newNick)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.join(user, channel) |  | ||||||
| 	mt_irc:sendLocal(("-!- %s joined %s") |  | ||||||
| 			:format(user.nick, channel)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.part(user, channel, reason) |  | ||||||
| 	reason = reason or "" |  | ||||||
| 	mt_irc:sendLocal(("-!- %s has left %s [%s]") |  | ||||||
| 			:format(user.nick, channel, reason)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.quit(user, reason) |  | ||||||
| 	mt_irc:sendLocal(("-!- %s has quit [%s]") |  | ||||||
| 			:format(user.nick, reason)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.action(user, channel, message) |  | ||||||
| 	mt_irc:sendLocal(("* %s@IRC %s") |  | ||||||
| 			:format(user.nick, message)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.disconnect(message, isError) |  | ||||||
| 	mt_irc.connected = false |  | ||||||
| 	if isError then |  | ||||||
| 		minetest.log("error",  "IRC: Error: Disconnected, reconnecting in one minute.") |  | ||||||
| 		minetest.chat_send_all("IRC: Error: Disconnected, reconnecting in one minute.") |  | ||||||
| 		minetest.after(60, mt_irc.connect) |  | ||||||
| 	else |  | ||||||
| 		minetest.log("action", "IRC: Disconnected.") |  | ||||||
| 		minetest.chat_send_all("IRC: Disconnected.") |  | ||||||
| 	end |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc.hooks.preregister(conn) |  | ||||||
| 	if not (mt_irc.config.SASLUser and mt_irc.config.SASLPass) then return end |  | ||||||
| 	local authString = mt_irc.b64e( |  | ||||||
| 		("%s\x00%s\x00%s"):format( |  | ||||||
| 		mt_irc.config.SASLUser, |  | ||||||
| 		mt_irc.config.SASLUser, |  | ||||||
| 		mt_irc.config.SASLPass) |  | ||||||
| 	) |  | ||||||
| 	conn:send("CAP REQ sasl") |  | ||||||
| 	conn:send("AUTHENTICATE PLAIN") |  | ||||||
| 	conn:send("AUTHENTICATE "..authString) |  | ||||||
| 	--LuaIRC will send CAP END |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| mt_irc:register_hook("PreRegister",     mt_irc.hooks.preregister) |  | ||||||
| mt_irc:register_hook("OnRaw",           mt_irc.hooks.raw) |  | ||||||
| mt_irc:register_hook("OnSend",          mt_irc.hooks.send) |  | ||||||
| mt_irc:register_hook("OnChat",          mt_irc.hooks.chat) |  | ||||||
| mt_irc:register_hook("OnPart",          mt_irc.hooks.part) |  | ||||||
| mt_irc:register_hook("OnKick",          mt_irc.hooks.kick) |  | ||||||
| mt_irc:register_hook("OnJoin",          mt_irc.hooks.join) |  | ||||||
| mt_irc:register_hook("OnQuit",          mt_irc.hooks.quit) |  | ||||||
| mt_irc:register_hook("NickChange",      mt_irc.hooks.nick) |  | ||||||
| mt_irc:register_hook("OnChannelAction", mt_irc.hooks.action) |  | ||||||
| mt_irc:register_hook("PrivateMessage",  mt_irc.hooks.pm) |  | ||||||
| mt_irc:register_hook("OnNotice",        mt_irc.hooks.notice) |  | ||||||
| mt_irc:register_hook("OnChannelChat",   mt_irc.hooks.channelChat) |  | ||||||
| mt_irc:register_hook("OnModeChange",    mt_irc.hooks.mode) |  | ||||||
| mt_irc:register_hook("OnDisconnect",    mt_irc.hooks.disconnect) |  | ||||||
|  |  | ||||||
							
								
								
									
										144
									
								
								src/init.lua
									
									
									
									
									
								
							
							
						
						
									
										144
									
								
								src/init.lua
									
									
									
									
									
								
							| @@ -1,144 +0,0 @@ | |||||||
| -- This file is licensed under the terms of the BSD 2-clause license. |  | ||||||
| -- See LICENSE.txt for details. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| mt_irc = { |  | ||||||
| 	connected = false, |  | ||||||
| 	cur_time = 0, |  | ||||||
| 	message_buffer = {}, |  | ||||||
| 	recent_message_count = 0, |  | ||||||
| 	joined_players = {}, |  | ||||||
| 	modpath = minetest.get_modpath("irc") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| -- To find LuaIRC and LuaSocket |  | ||||||
| package.path = mt_irc.modpath.."/?/init.lua;" |  | ||||||
| 		..mt_irc.modpath.."/irc/?.lua;" |  | ||||||
| 		..mt_irc.modpath.."/?.lua;" |  | ||||||
| 		..package.path |  | ||||||
| package.cpath = mt_irc.modpath.."/lib?.so;" |  | ||||||
| 		..mt_irc.modpath.."/?.dll;" |  | ||||||
| 		..package.cpath |  | ||||||
|  |  | ||||||
| local irc = require('irc') |  | ||||||
|  |  | ||||||
| dofile(mt_irc.modpath.."/config.lua") |  | ||||||
| dofile(mt_irc.modpath.."/messages.lua") |  | ||||||
| dofile(mt_irc.modpath.."/hooks.lua") |  | ||||||
| dofile(mt_irc.modpath.."/callback.lua") |  | ||||||
| dofile(mt_irc.modpath.."/chatcmds.lua") |  | ||||||
| dofile(mt_irc.modpath.."/botcmds.lua") |  | ||||||
| dofile(mt_irc.modpath.."/util.lua") |  | ||||||
| if mt_irc.config.enable_player_part then |  | ||||||
| 	dofile(mt_irc.modpath.."/player_part.lua") |  | ||||||
| else |  | ||||||
| 	setmetatable(mt_irc.joined_players, {__index = function(index) return true end}) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| minetest.register_privilege("irc_admin", { |  | ||||||
| 	description = "Allow IRC administrative tasks to be performed.", |  | ||||||
| 	give_to_singleplayer = true |  | ||||||
| }) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| minetest.register_globalstep(function(dtime) return mt_irc:step(dtime) end) |  | ||||||
|  |  | ||||||
| function mt_irc:step(dtime) |  | ||||||
| 	if not self.connected then return end |  | ||||||
|  |  | ||||||
| 	-- Tick down the recent message count |  | ||||||
| 	self.cur_time = self.cur_time + dtime |  | ||||||
| 	if self.cur_time >= self.config.interval then |  | ||||||
| 		if self.recent_message_count > 0 then |  | ||||||
| 			self.recent_message_count = self.recent_message_count - 1 |  | ||||||
| 		end |  | ||||||
| 		self.cur_time = self.cur_time - self.config.interval |  | ||||||
| 	end |  | ||||||
|  |  | ||||||
| 	-- Hooks will manage incoming messages and errors |  | ||||||
| 	if not pcall(function() mt_irc.conn:think() end) then |  | ||||||
| 		return |  | ||||||
| 	end |  | ||||||
|  |  | ||||||
| 	-- Send messages in the buffer |  | ||||||
| 	if #self.message_buffer > 10 then |  | ||||||
| 		minetest.log("error", "IRC: Message buffer overflow, clearing.") |  | ||||||
| 		self.message_buffer = {} |  | ||||||
| 	elseif #self.message_buffer > 0 then |  | ||||||
| 		for i=1, #self.message_buffer do |  | ||||||
| 			if self.recent_message_count > 4 then break end |  | ||||||
| 			self.recent_message_count = self.recent_message_count + 1 |  | ||||||
| 			local msg = table.remove(self.message_buffer, 1) --Pop the first message |  | ||||||
| 			self:send(msg) |  | ||||||
| 		end |  | ||||||
| 	end |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc:connect() |  | ||||||
| 	if self.connected then |  | ||||||
| 		minetest.log("error", "IRC: Ignoring attempt to connect when already connected.") |  | ||||||
| 		return |  | ||||||
| 	end |  | ||||||
| 	self.conn = irc.new({ |  | ||||||
| 		nick = self.config.nick, |  | ||||||
| 		username = "Minetest", |  | ||||||
| 		realname = "Minetest", |  | ||||||
| 	}) |  | ||||||
| 	self:doHook(self.conn) |  | ||||||
| 	good, message = pcall(function() |  | ||||||
| 		mt_irc.conn:connect({ |  | ||||||
| 			host = mt_irc.config.server, |  | ||||||
| 			port = mt_irc.config.port, |  | ||||||
| 			pass = mt_irc.config.password, |  | ||||||
| 			timeout = mt_irc.config.timeout, |  | ||||||
| 			secure = mt_irc.config.secure |  | ||||||
| 		}) |  | ||||||
| 	end) |  | ||||||
|  |  | ||||||
| 	if not good then |  | ||||||
| 		minetest.log("error", ("IRC: Connection error: %s: %s -- Reconnecting in ten minutes...") |  | ||||||
| 					:format(self.config.server, message)) |  | ||||||
| 		minetest.after(600, function() mt_irc:connect() end) |  | ||||||
| 		return |  | ||||||
| 	end |  | ||||||
|  |  | ||||||
| 	if self.config.NSPass then |  | ||||||
| 		self:say("NickServ", "IDENTIFY "..self.config.NSPass) |  | ||||||
| 	end |  | ||||||
|  |  | ||||||
| 	self.conn:join(self.config.channel, self.config.key) |  | ||||||
| 	self.connected = true |  | ||||||
| 	minetest.log("action", "IRC: Connected!") |  | ||||||
| 	minetest.chat_send_all("IRC: Connected!") |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc:disconnect(message) |  | ||||||
| 	if self.connected then |  | ||||||
| 		--The OnDisconnect hook will clear self.connected and print a disconnect message |  | ||||||
| 		self.conn:disconnect(message) |  | ||||||
| 	end |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc:say(to, message) |  | ||||||
| 	if not message then |  | ||||||
| 		message = to |  | ||||||
| 		to = self.config.channel |  | ||||||
| 	end |  | ||||||
| 	to = to or self.config.channel |  | ||||||
|  |  | ||||||
| 	self:queueMsg(self.msgs.privmsg(to, message)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function mt_irc:send(line) |  | ||||||
| 	self.conn:send(line) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| if mt_irc.config.auto_connect then |  | ||||||
| 	mt_irc:connect() |  | ||||||
| end |  | ||||||
|  |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
|  |  | ||||||
| # :mode=cmake:noTabs=true:tabSize=4: |  | ||||||
|  |  | ||||||
| set(LUA_SRCS |  | ||||||
|     lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c |  | ||||||
|     lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c |  | ||||||
|     lundump.c lvm.c lzio.c |  | ||||||
|     lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c ltablib.c |  | ||||||
|     lstrlib.c loadlib.c linit.c |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| add_library(lua_lib ${LUA_SRCS}) |  | ||||||
| set_target_properties(lua_lib |  | ||||||
|     PROPERTIES |  | ||||||
|     OUTPUT_NAME lua51-minetest-irc |  | ||||||
| ) |  | ||||||
							
								
								
									
										1077
									
								
								src/lua/lapi.c
									
									
									
									
									
								
							
							
						
						
									
										1077
									
								
								src/lua/lapi.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,16 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lapi.h,v 2.2 2005/04/25 19:24:10 roberto Exp $ |  | ||||||
| ** Auxiliary functions from Lua API |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef lapi_h |  | ||||||
| #define lapi_h |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "lobject.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o); |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,647 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lauxlib.c,v 1.158 2006/01/16 12:42:21 roberto Exp $ |  | ||||||
| ** Auxiliary functions for building Lua libraries |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <ctype.h> |  | ||||||
| #include <errno.h> |  | ||||||
| #include <stdarg.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* This file uses only the official API of Lua. |  | ||||||
| ** Any function declared here could be written as an application function. |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #define lauxlib_c |  | ||||||
| #define LUA_LIB |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lauxlib.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define FREELIST_REF	0	/* free list of references */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* convert a stack index to positive */ |  | ||||||
| #define abs_index(L, i)		((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ |  | ||||||
| 					lua_gettop(L) + (i) + 1) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** Error-report functions |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { |  | ||||||
|   lua_Debug ar; |  | ||||||
|   if (!lua_getstack(L, 0, &ar))  /* no stack frame? */ |  | ||||||
|     return luaL_error(L, "bad argument #%d (%s)", narg, extramsg); |  | ||||||
|   lua_getinfo(L, "n", &ar); |  | ||||||
|   if (strcmp(ar.namewhat, "method") == 0) { |  | ||||||
|     narg--;  /* do not count `self' */ |  | ||||||
|     if (narg == 0)  /* error is in the self argument itself? */ |  | ||||||
|       return luaL_error(L, "calling " LUA_QS " on bad self (%s)", |  | ||||||
|                            ar.name, extramsg); |  | ||||||
|   } |  | ||||||
|   if (ar.name == NULL) |  | ||||||
|     ar.name = "?"; |  | ||||||
|   return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)", |  | ||||||
|                         narg, ar.name, extramsg); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { |  | ||||||
|   const char *msg = lua_pushfstring(L, "%s expected, got %s", |  | ||||||
|                                     tname, luaL_typename(L, narg)); |  | ||||||
|   return luaL_argerror(L, narg, msg); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void tag_error (lua_State *L, int narg, int tag) { |  | ||||||
|   luaL_typerror(L, narg, lua_typename(L, tag)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void luaL_where (lua_State *L, int level) { |  | ||||||
|   lua_Debug ar; |  | ||||||
|   if (lua_getstack(L, level, &ar)) {  /* check function at level */ |  | ||||||
|     lua_getinfo(L, "Sl", &ar);  /* get info about it */ |  | ||||||
|     if (ar.currentline > 0) {  /* is there info? */ |  | ||||||
|       lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   lua_pushliteral(L, "");  /* else, no information available... */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { |  | ||||||
|   va_list argp; |  | ||||||
|   va_start(argp, fmt); |  | ||||||
|   luaL_where(L, 1); |  | ||||||
|   lua_pushvfstring(L, fmt, argp); |  | ||||||
|   va_end(argp); |  | ||||||
|   lua_concat(L, 2); |  | ||||||
|   return lua_error(L); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, |  | ||||||
|                                  const char *const lst[]) { |  | ||||||
|   const char *name = (def) ? luaL_optstring(L, narg, def) : |  | ||||||
|                              luaL_checkstring(L, narg); |  | ||||||
|   int i; |  | ||||||
|   for (i=0; lst[i]; i++) |  | ||||||
|     if (strcmp(lst[i], name) == 0) |  | ||||||
|       return i; |  | ||||||
|   return luaL_argerror(L, narg, |  | ||||||
|                        lua_pushfstring(L, "invalid option " LUA_QS, name)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { |  | ||||||
|   lua_getfield(L, LUA_REGISTRYINDEX, tname);  /* get registry.name */ |  | ||||||
|   if (!lua_isnil(L, -1))  /* name already in use? */ |  | ||||||
|     return 0;  /* leave previous value on top, but return 0 */ |  | ||||||
|   lua_pop(L, 1); |  | ||||||
|   lua_newtable(L);  /* create metatable */ |  | ||||||
|   lua_pushvalue(L, -1); |  | ||||||
|   lua_setfield(L, LUA_REGISTRYINDEX, tname);  /* registry.name = metatable */ |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { |  | ||||||
|   void *p = lua_touserdata(L, ud); |  | ||||||
|   lua_getfield(L, LUA_REGISTRYINDEX, tname);  /* get correct metatable */ |  | ||||||
|   if (p == NULL || !lua_getmetatable(L, ud) || !lua_rawequal(L, -1, -2)) |  | ||||||
|     luaL_typerror(L, ud, tname); |  | ||||||
|   lua_pop(L, 2);  /* remove both metatables */ |  | ||||||
|   return p; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { |  | ||||||
|   if (!lua_checkstack(L, space)) |  | ||||||
|     luaL_error(L, "stack overflow (%s)", mes); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) { |  | ||||||
|   if (lua_type(L, narg) != t) |  | ||||||
|     tag_error(L, narg, t); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void luaL_checkany (lua_State *L, int narg) { |  | ||||||
|   if (lua_type(L, narg) == LUA_TNONE) |  | ||||||
|     luaL_argerror(L, narg, "value expected"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) { |  | ||||||
|   const char *s = lua_tolstring(L, narg, len); |  | ||||||
|   if (!s) tag_error(L, narg, LUA_TSTRING); |  | ||||||
|   return s; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, |  | ||||||
|                                         const char *def, size_t *len) { |  | ||||||
|   if (lua_isnoneornil(L, narg)) { |  | ||||||
|     if (len) |  | ||||||
|       *len = (def ? strlen(def) : 0); |  | ||||||
|     return def; |  | ||||||
|   } |  | ||||||
|   else return luaL_checklstring(L, narg, len); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { |  | ||||||
|   lua_Number d = lua_tonumber(L, narg); |  | ||||||
|   if (d == 0 && !lua_isnumber(L, narg))  /* avoid extra test when d is not 0 */ |  | ||||||
|     tag_error(L, narg, LUA_TNUMBER); |  | ||||||
|   return d; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { |  | ||||||
|   return luaL_opt(L, luaL_checknumber, narg, def); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { |  | ||||||
|   lua_Integer d = lua_tointeger(L, narg); |  | ||||||
|   if (d == 0 && !lua_isnumber(L, narg))  /* avoid extra test when d is not 0 */ |  | ||||||
|     tag_error(L, narg, LUA_TNUMBER); |  | ||||||
|   return d; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, |  | ||||||
|                                                       lua_Integer def) { |  | ||||||
|   return luaL_opt(L, luaL_checkinteger, narg, def); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { |  | ||||||
|   if (!lua_getmetatable(L, obj))  /* no metatable? */ |  | ||||||
|     return 0; |  | ||||||
|   lua_pushstring(L, event); |  | ||||||
|   lua_rawget(L, -2); |  | ||||||
|   if (lua_isnil(L, -1)) { |  | ||||||
|     lua_pop(L, 2);  /* remove metatable and metafield */ |  | ||||||
|     return 0; |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     lua_remove(L, -2);  /* remove only metatable */ |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { |  | ||||||
|   obj = abs_index(L, obj); |  | ||||||
|   if (!luaL_getmetafield(L, obj, event))  /* no metafield? */ |  | ||||||
|     return 0; |  | ||||||
|   lua_pushvalue(L, obj); |  | ||||||
|   lua_call(L, 1, 1); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void (luaL_register) (lua_State *L, const char *libname, |  | ||||||
|                                 const luaL_Reg *l) { |  | ||||||
|   luaI_openlib(L, libname, l, 0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int libsize (const luaL_Reg *l) { |  | ||||||
|   int size = 0; |  | ||||||
|   for (; l->name; l++) size++; |  | ||||||
|   return size; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void luaI_openlib (lua_State *L, const char *libname, |  | ||||||
|                               const luaL_Reg *l, int nup) { |  | ||||||
|   if (libname) { |  | ||||||
|     int size = libsize(l); |  | ||||||
|     /* check whether lib already exists */ |  | ||||||
|     luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", size); |  | ||||||
|     lua_getfield(L, -1, libname);  /* get _LOADED[libname] */ |  | ||||||
|     if (!lua_istable(L, -1)) {  /* not found? */ |  | ||||||
|       lua_pop(L, 1);  /* remove previous result */ |  | ||||||
|       /* try global variable (and create one if it does not exist) */ |  | ||||||
|       if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) |  | ||||||
|         luaL_error(L, "name conflict for module " LUA_QS, libname); |  | ||||||
|       lua_pushvalue(L, -1); |  | ||||||
|       lua_setfield(L, -3, libname);  /* _LOADED[libname] = new table */ |  | ||||||
|     } |  | ||||||
|     lua_remove(L, -2);  /* remove _LOADED table */ |  | ||||||
|     lua_insert(L, -(nup+1));  /* move library table to below upvalues */ |  | ||||||
|   } |  | ||||||
|   for (; l->name; l++) { |  | ||||||
|     int i; |  | ||||||
|     for (i=0; i<nup; i++)  /* copy upvalues to the top */ |  | ||||||
|       lua_pushvalue(L, -nup); |  | ||||||
|     lua_pushcclosure(L, l->func, nup); |  | ||||||
|     lua_setfield(L, -(nup+2), l->name); |  | ||||||
|   } |  | ||||||
|   lua_pop(L, nup);  /* remove upvalues */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** getn-setn: size for arrays |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #if defined(LUA_COMPAT_GETN) |  | ||||||
|  |  | ||||||
| static int checkint (lua_State *L, int topop) { |  | ||||||
|   int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1; |  | ||||||
|   lua_pop(L, topop); |  | ||||||
|   return n; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void getsizes (lua_State *L) { |  | ||||||
|   lua_getfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); |  | ||||||
|   if (lua_isnil(L, -1)) {  /* no `size' table? */ |  | ||||||
|     lua_pop(L, 1);  /* remove nil */ |  | ||||||
|     lua_newtable(L);  /* create it */ |  | ||||||
|     lua_pushvalue(L, -1);  /* `size' will be its own metatable */ |  | ||||||
|     lua_setmetatable(L, -2); |  | ||||||
|     lua_pushliteral(L, "kv"); |  | ||||||
|     lua_setfield(L, -2, "__mode");  /* metatable(N).__mode = "kv" */ |  | ||||||
|     lua_pushvalue(L, -1); |  | ||||||
|     lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES");  /* store in register */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void luaL_setn (lua_State *L, int t, int n) { |  | ||||||
|   t = abs_index(L, t); |  | ||||||
|   lua_pushliteral(L, "n"); |  | ||||||
|   lua_rawget(L, t); |  | ||||||
|   if (checkint(L, 1) >= 0) {  /* is there a numeric field `n'? */ |  | ||||||
|     lua_pushliteral(L, "n");  /* use it */ |  | ||||||
|     lua_pushinteger(L, n); |  | ||||||
|     lua_rawset(L, t); |  | ||||||
|   } |  | ||||||
|   else {  /* use `sizes' */ |  | ||||||
|     getsizes(L); |  | ||||||
|     lua_pushvalue(L, t); |  | ||||||
|     lua_pushinteger(L, n); |  | ||||||
|     lua_rawset(L, -3);  /* sizes[t] = n */ |  | ||||||
|     lua_pop(L, 1);  /* remove `sizes' */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaL_getn (lua_State *L, int t) { |  | ||||||
|   int n; |  | ||||||
|   t = abs_index(L, t); |  | ||||||
|   lua_pushliteral(L, "n");  /* try t.n */ |  | ||||||
|   lua_rawget(L, t); |  | ||||||
|   if ((n = checkint(L, 1)) >= 0) return n; |  | ||||||
|   getsizes(L);  /* else try sizes[t] */ |  | ||||||
|   lua_pushvalue(L, t); |  | ||||||
|   lua_rawget(L, -2); |  | ||||||
|   if ((n = checkint(L, 2)) >= 0) return n; |  | ||||||
|   return (int)lua_objlen(L, t); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, |  | ||||||
|                                                                const char *r) { |  | ||||||
|   const char *wild; |  | ||||||
|   size_t l = strlen(p); |  | ||||||
|   luaL_Buffer b; |  | ||||||
|   luaL_buffinit(L, &b); |  | ||||||
|   while ((wild = strstr(s, p)) != NULL) { |  | ||||||
|     luaL_addlstring(&b, s, wild - s);  /* push prefix */ |  | ||||||
|     luaL_addstring(&b, r);  /* push replacement in place of pattern */ |  | ||||||
|     s = wild + l;  /* continue after `p' */ |  | ||||||
|   } |  | ||||||
|   luaL_addstring(&b, s);  /* push last suffix */ |  | ||||||
|   luaL_pushresult(&b); |  | ||||||
|   return lua_tostring(L, -1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API const char *luaL_findtable (lua_State *L, int idx, |  | ||||||
|                                        const char *fname, int szhint) { |  | ||||||
|   const char *e; |  | ||||||
|   lua_pushvalue(L, idx); |  | ||||||
|   do { |  | ||||||
|     e = strchr(fname, '.'); |  | ||||||
|     if (e == NULL) e = fname + strlen(fname); |  | ||||||
|     lua_pushlstring(L, fname, e - fname); |  | ||||||
|     lua_rawget(L, -2); |  | ||||||
|     if (lua_isnil(L, -1)) {  /* no such field? */ |  | ||||||
|       lua_pop(L, 1);  /* remove this nil */ |  | ||||||
|       lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ |  | ||||||
|       lua_pushlstring(L, fname, e - fname); |  | ||||||
|       lua_pushvalue(L, -2); |  | ||||||
|       lua_settable(L, -4);  /* set new table into field */ |  | ||||||
|     } |  | ||||||
|     else if (!lua_istable(L, -1)) {  /* field has a non-table value? */ |  | ||||||
|       lua_pop(L, 2);  /* remove table and value */ |  | ||||||
|       return fname;  /* return problematic part of the name */ |  | ||||||
|     } |  | ||||||
|     lua_remove(L, -2);  /* remove previous table */ |  | ||||||
|     fname = e + 1; |  | ||||||
|   } while (*e == '.'); |  | ||||||
|   return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** Generic Buffer manipulation |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define bufflen(B)	((B)->p - (B)->buffer) |  | ||||||
| #define bufffree(B)	((size_t)(LUAL_BUFFERSIZE - bufflen(B))) |  | ||||||
|  |  | ||||||
| #define LIMIT	(LUA_MINSTACK/2) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int emptybuffer (luaL_Buffer *B) { |  | ||||||
|   size_t l = bufflen(B); |  | ||||||
|   if (l == 0) return 0;  /* put nothing on stack */ |  | ||||||
|   else { |  | ||||||
|     lua_pushlstring(B->L, B->buffer, l); |  | ||||||
|     B->p = B->buffer; |  | ||||||
|     B->lvl++; |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void adjuststack (luaL_Buffer *B) { |  | ||||||
|   if (B->lvl > 1) { |  | ||||||
|     lua_State *L = B->L; |  | ||||||
|     int toget = 1;  /* number of levels to concat */ |  | ||||||
|     size_t toplen = lua_strlen(L, -1); |  | ||||||
|     do { |  | ||||||
|       size_t l = lua_strlen(L, -(toget+1)); |  | ||||||
|       if (B->lvl - toget + 1 >= LIMIT || toplen > l) { |  | ||||||
|         toplen += l; |  | ||||||
|         toget++; |  | ||||||
|       } |  | ||||||
|       else break; |  | ||||||
|     } while (toget < B->lvl); |  | ||||||
|     lua_concat(L, toget); |  | ||||||
|     B->lvl = B->lvl - toget + 1; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { |  | ||||||
|   if (emptybuffer(B)) |  | ||||||
|     adjuststack(B); |  | ||||||
|   return B->buffer; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { |  | ||||||
|   while (l--) |  | ||||||
|     luaL_addchar(B, *s++); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { |  | ||||||
|   luaL_addlstring(B, s, strlen(s)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void luaL_pushresult (luaL_Buffer *B) { |  | ||||||
|   emptybuffer(B); |  | ||||||
|   lua_concat(B->L, B->lvl); |  | ||||||
|   B->lvl = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void luaL_addvalue (luaL_Buffer *B) { |  | ||||||
|   lua_State *L = B->L; |  | ||||||
|   size_t vl; |  | ||||||
|   const char *s = lua_tolstring(L, -1, &vl); |  | ||||||
|   if (vl <= bufffree(B)) {  /* fit into buffer? */ |  | ||||||
|     memcpy(B->p, s, vl);  /* put it there */ |  | ||||||
|     B->p += vl; |  | ||||||
|     lua_pop(L, 1);  /* remove from stack */ |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     if (emptybuffer(B)) |  | ||||||
|       lua_insert(L, -2);  /* put buffer before new value */ |  | ||||||
|     B->lvl++;  /* add new value into B stack */ |  | ||||||
|     adjuststack(B); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { |  | ||||||
|   B->L = L; |  | ||||||
|   B->p = B->buffer; |  | ||||||
|   B->lvl = 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaL_ref (lua_State *L, int t) { |  | ||||||
|   int ref; |  | ||||||
|   t = abs_index(L, t); |  | ||||||
|   if (lua_isnil(L, -1)) { |  | ||||||
|     lua_pop(L, 1);  /* remove from stack */ |  | ||||||
|     return LUA_REFNIL;  /* `nil' has a unique fixed reference */ |  | ||||||
|   } |  | ||||||
|   lua_rawgeti(L, t, FREELIST_REF);  /* get first free element */ |  | ||||||
|   ref = (int)lua_tointeger(L, -1);  /* ref = t[FREELIST_REF] */ |  | ||||||
|   lua_pop(L, 1);  /* remove it from stack */ |  | ||||||
|   if (ref != 0) {  /* any free element? */ |  | ||||||
|     lua_rawgeti(L, t, ref);  /* remove it from list */ |  | ||||||
|     lua_rawseti(L, t, FREELIST_REF);  /* (t[FREELIST_REF] = t[ref]) */ |  | ||||||
|   } |  | ||||||
|   else {  /* no free elements */ |  | ||||||
|     ref = (int)lua_objlen(L, t); |  | ||||||
|     ref++;  /* create new reference */ |  | ||||||
|   } |  | ||||||
|   lua_rawseti(L, t, ref); |  | ||||||
|   return ref; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { |  | ||||||
|   if (ref >= 0) { |  | ||||||
|     t = abs_index(L, t); |  | ||||||
|     lua_rawgeti(L, t, FREELIST_REF); |  | ||||||
|     lua_rawseti(L, t, ref);  /* t[ref] = t[FREELIST_REF] */ |  | ||||||
|     lua_pushinteger(L, ref); |  | ||||||
|     lua_rawseti(L, t, FREELIST_REF);  /* t[FREELIST_REF] = ref */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** Load functions |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| typedef struct LoadF { |  | ||||||
|   int extraline; |  | ||||||
|   FILE *f; |  | ||||||
|   char buff[LUAL_BUFFERSIZE]; |  | ||||||
| } LoadF; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *getF (lua_State *L, void *ud, size_t *size) { |  | ||||||
|   LoadF *lf = (LoadF *)ud; |  | ||||||
|   (void)L; |  | ||||||
|   if (lf->extraline) { |  | ||||||
|     lf->extraline = 0; |  | ||||||
|     *size = 1; |  | ||||||
|     return "\n"; |  | ||||||
|   } |  | ||||||
|   if (feof(lf->f)) return NULL; |  | ||||||
|   *size = fread(lf->buff, 1, LUAL_BUFFERSIZE, lf->f); |  | ||||||
|   return (*size > 0) ? lf->buff : NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int errfile (lua_State *L, const char *what, int fnameindex) { |  | ||||||
|   const char *serr = strerror(errno); |  | ||||||
|   const char *filename = lua_tostring(L, fnameindex) + 1; |  | ||||||
|   lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); |  | ||||||
|   lua_remove(L, fnameindex); |  | ||||||
|   return LUA_ERRFILE; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { |  | ||||||
|   LoadF lf; |  | ||||||
|   int status, readstatus; |  | ||||||
|   int c; |  | ||||||
|   int fnameindex = lua_gettop(L) + 1;  /* index of filename on the stack */ |  | ||||||
|   lf.extraline = 0; |  | ||||||
|   if (filename == NULL) { |  | ||||||
|     lua_pushliteral(L, "=stdin"); |  | ||||||
|     lf.f = stdin; |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     lua_pushfstring(L, "@%s", filename); |  | ||||||
|     lf.f = fopen(filename, "r"); |  | ||||||
|     if (lf.f == NULL) return errfile(L, "open", fnameindex); |  | ||||||
|   } |  | ||||||
|   c = getc(lf.f); |  | ||||||
|   if (c == '#') {  /* Unix exec. file? */ |  | ||||||
|     lf.extraline = 1; |  | ||||||
|     while ((c = getc(lf.f)) != EOF && c != '\n') ;  /* skip first line */ |  | ||||||
|     if (c == '\n') c = getc(lf.f); |  | ||||||
|   } |  | ||||||
|   if (c == LUA_SIGNATURE[0] && lf.f != stdin) {  /* binary file? */ |  | ||||||
|     fclose(lf.f); |  | ||||||
|     lf.f = fopen(filename, "rb");  /* reopen in binary mode */ |  | ||||||
|     if (lf.f == NULL) return errfile(L, "reopen", fnameindex); |  | ||||||
|     /* skip eventual `#!...' */ |  | ||||||
|    while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; |  | ||||||
|     lf.extraline = 0; |  | ||||||
|   } |  | ||||||
|   ungetc(c, lf.f); |  | ||||||
|   status = lua_load(L, getF, &lf, lua_tostring(L, -1)); |  | ||||||
|   readstatus = ferror(lf.f); |  | ||||||
|   if (lf.f != stdin) fclose(lf.f);  /* close file (even in case of errors) */ |  | ||||||
|   if (readstatus) { |  | ||||||
|     lua_settop(L, fnameindex);  /* ignore results from `lua_load' */ |  | ||||||
|     return errfile(L, "read", fnameindex); |  | ||||||
|   } |  | ||||||
|   lua_remove(L, fnameindex); |  | ||||||
|   return status; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct LoadS { |  | ||||||
|   const char *s; |  | ||||||
|   size_t size; |  | ||||||
| } LoadS; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *getS (lua_State *L, void *ud, size_t *size) { |  | ||||||
|   LoadS *ls = (LoadS *)ud; |  | ||||||
|   (void)L; |  | ||||||
|   if (ls->size == 0) return NULL; |  | ||||||
|   *size = ls->size; |  | ||||||
|   ls->size = 0; |  | ||||||
|   return ls->s; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, |  | ||||||
|                                 const char *name) { |  | ||||||
|   LoadS ls; |  | ||||||
|   ls.s = buff; |  | ||||||
|   ls.size = size; |  | ||||||
|   return lua_load(L, getS, &ls, name); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) { |  | ||||||
|   return luaL_loadbuffer(L, s, strlen(s), s); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { |  | ||||||
|   (void)ud; |  | ||||||
|   (void)osize; |  | ||||||
|   if (nsize == 0) { |  | ||||||
|     free(ptr); |  | ||||||
|     return NULL; |  | ||||||
|   } |  | ||||||
|   else |  | ||||||
|     return realloc(ptr, nsize); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int panic (lua_State *L) { |  | ||||||
|   (void)L;  /* to avoid warnings */ |  | ||||||
|   fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", |  | ||||||
|                    lua_tostring(L, -1)); |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API lua_State *luaL_newstate (void) { |  | ||||||
|   lua_State *L = lua_newstate(l_alloc, NULL); |  | ||||||
|   if (L) lua_atpanic(L, &panic); |  | ||||||
|   return L; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,172 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lauxlib.h,v 1.87 2005/12/29 15:32:11 roberto Exp $ |  | ||||||
| ** Auxiliary functions for building Lua libraries |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifndef lauxlib_h |  | ||||||
| #define lauxlib_h |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <stddef.h> |  | ||||||
| #include <stdio.h> |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #if defined(LUA_COMPAT_GETN) |  | ||||||
| LUALIB_API int (luaL_getn) (lua_State *L, int t); |  | ||||||
| LUALIB_API void (luaL_setn) (lua_State *L, int t, int n); |  | ||||||
| #else |  | ||||||
| #define luaL_getn(L,i)          ((int)lua_objlen(L, i)) |  | ||||||
| #define luaL_setn(L,i,j)        ((void)0)  /* no op! */ |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #if defined(LUA_COMPAT_OPENLIB) |  | ||||||
| #define luaI_openlib	luaL_openlib |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* extra error code for `luaL_load' */ |  | ||||||
| #define LUA_ERRFILE     (LUA_ERRERR+1) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct luaL_Reg { |  | ||||||
|   const char *name; |  | ||||||
|   lua_CFunction func; |  | ||||||
| } luaL_Reg; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname, |  | ||||||
|                                 const luaL_Reg *l, int nup); |  | ||||||
| LUALIB_API void (luaL_register) (lua_State *L, const char *libname, |  | ||||||
|                                 const luaL_Reg *l); |  | ||||||
| LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); |  | ||||||
| LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); |  | ||||||
| LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname); |  | ||||||
| LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); |  | ||||||
| LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, |  | ||||||
|                                                           size_t *l); |  | ||||||
| LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg, |  | ||||||
|                                           const char *def, size_t *l); |  | ||||||
| LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg); |  | ||||||
| LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); |  | ||||||
|  |  | ||||||
| LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg); |  | ||||||
| LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg, |  | ||||||
|                                           lua_Integer def); |  | ||||||
|  |  | ||||||
| LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); |  | ||||||
| LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); |  | ||||||
| LUALIB_API void (luaL_checkany) (lua_State *L, int narg); |  | ||||||
|  |  | ||||||
| LUALIB_API int   (luaL_newmetatable) (lua_State *L, const char *tname); |  | ||||||
| LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); |  | ||||||
|  |  | ||||||
| LUALIB_API void (luaL_where) (lua_State *L, int lvl); |  | ||||||
| LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); |  | ||||||
|  |  | ||||||
| LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def, |  | ||||||
|                                    const char *const lst[]); |  | ||||||
|  |  | ||||||
| LUALIB_API int (luaL_ref) (lua_State *L, int t); |  | ||||||
| LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); |  | ||||||
|  |  | ||||||
| LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename); |  | ||||||
| LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, |  | ||||||
|                                   const char *name); |  | ||||||
| LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); |  | ||||||
|  |  | ||||||
| LUALIB_API lua_State *(luaL_newstate) (void); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, |  | ||||||
|                                                   const char *r); |  | ||||||
|  |  | ||||||
| LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, |  | ||||||
|                                          const char *fname, int szhint); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** =============================================================== |  | ||||||
| ** some useful macros |  | ||||||
| ** =============================================================== |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #define luaL_argcheck(L, cond,numarg,extramsg)	\ |  | ||||||
| 		((void)((cond) || luaL_argerror(L, (numarg), (extramsg)))) |  | ||||||
| #define luaL_checkstring(L,n)	(luaL_checklstring(L, (n), NULL)) |  | ||||||
| #define luaL_optstring(L,n,d)	(luaL_optlstring(L, (n), (d), NULL)) |  | ||||||
| #define luaL_checkint(L,n)	((int)luaL_checkinteger(L, (n))) |  | ||||||
| #define luaL_optint(L,n,d)	((int)luaL_optinteger(L, (n), (d))) |  | ||||||
| #define luaL_checklong(L,n)	((long)luaL_checkinteger(L, (n))) |  | ||||||
| #define luaL_optlong(L,n,d)	((long)luaL_optinteger(L, (n), (d))) |  | ||||||
|  |  | ||||||
| #define luaL_typename(L,i)	lua_typename(L, lua_type(L,(i))) |  | ||||||
|  |  | ||||||
| #define luaL_dofile(L, fn)	(luaL_loadfile(L, fn) || lua_pcall(L, 0, 0, 0)) |  | ||||||
|  |  | ||||||
| #define luaL_dostring(L, s)	(luaL_loadstring(L, s) || lua_pcall(L, 0, 0, 0)) |  | ||||||
|  |  | ||||||
| #define luaL_getmetatable(L,n)	(lua_getfield(L, LUA_REGISTRYINDEX, (n))) |  | ||||||
|  |  | ||||||
| #define luaL_opt(L,f,n,d)	(lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** Generic Buffer manipulation |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct luaL_Buffer { |  | ||||||
|   char *p;			/* current position in buffer */ |  | ||||||
|   int lvl;  /* number of strings in the stack (level) */ |  | ||||||
|   lua_State *L; |  | ||||||
|   char buffer[LUAL_BUFFERSIZE]; |  | ||||||
| } luaL_Buffer; |  | ||||||
|  |  | ||||||
| #define luaL_addchar(B,c) \ |  | ||||||
|   ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ |  | ||||||
|    (*(B)->p++ = (char)(c))) |  | ||||||
|  |  | ||||||
| /* compatibility only */ |  | ||||||
| #define luaL_putchar(B,c)	luaL_addchar(B,c) |  | ||||||
|  |  | ||||||
| #define luaL_addsize(B,n)	((B)->p += (n)) |  | ||||||
|  |  | ||||||
| LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); |  | ||||||
| LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B); |  | ||||||
| LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); |  | ||||||
| LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); |  | ||||||
| LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); |  | ||||||
| LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* compatibility with ref system */ |  | ||||||
|  |  | ||||||
| /* pre-defined references */ |  | ||||||
| #define LUA_NOREF       (-2) |  | ||||||
| #define LUA_REFNIL      (-1) |  | ||||||
|  |  | ||||||
| #define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \ |  | ||||||
|       (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0)) |  | ||||||
|  |  | ||||||
| #define lua_unref(L,ref)        luaL_unref(L, LUA_REGISTRYINDEX, (ref)) |  | ||||||
|  |  | ||||||
| #define lua_getref(L,ref)       lua_rawgeti(L, LUA_REGISTRYINDEX, (ref)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define luaL_reg	luaL_Reg |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,643 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lbaselib.c,v 1.189 2006/01/18 11:49:12 roberto Exp $ |  | ||||||
| ** Basic library |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <ctype.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define lbaselib_c |  | ||||||
| #define LUA_LIB |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lauxlib.h" |  | ||||||
| #include "lualib.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** If your system does not support `stdout', you can just remove this function. |  | ||||||
| ** If you need, you can define your own `print' function, following this |  | ||||||
| ** model but changing `fputs' to put the strings at a proper place |  | ||||||
| ** (a console window or a log file, for instance). |  | ||||||
| */ |  | ||||||
| static int luaB_print (lua_State *L) { |  | ||||||
|   int n = lua_gettop(L);  /* number of arguments */ |  | ||||||
|   int i; |  | ||||||
|   lua_getglobal(L, "tostring"); |  | ||||||
|   for (i=1; i<=n; i++) { |  | ||||||
|     const char *s; |  | ||||||
|     lua_pushvalue(L, -1);  /* function to be called */ |  | ||||||
|     lua_pushvalue(L, i);   /* value to print */ |  | ||||||
|     lua_call(L, 1, 1); |  | ||||||
|     s = lua_tostring(L, -1);  /* get result */ |  | ||||||
|     if (s == NULL) |  | ||||||
|       return luaL_error(L, LUA_QL("tostring") " must return a string to " |  | ||||||
|                            LUA_QL("print")); |  | ||||||
|     if (i>1) fputs("\t", stdout); |  | ||||||
|     fputs(s, stdout); |  | ||||||
|     lua_pop(L, 1);  /* pop result */ |  | ||||||
|   } |  | ||||||
|   fputs("\n", stdout); |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_tonumber (lua_State *L) { |  | ||||||
|   int base = luaL_optint(L, 2, 10); |  | ||||||
|   if (base == 10) {  /* standard conversion */ |  | ||||||
|     luaL_checkany(L, 1); |  | ||||||
|     if (lua_isnumber(L, 1)) { |  | ||||||
|       lua_pushnumber(L, lua_tonumber(L, 1)); |  | ||||||
|       return 1; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     const char *s1 = luaL_checkstring(L, 1); |  | ||||||
|     char *s2; |  | ||||||
|     unsigned long n; |  | ||||||
|     luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); |  | ||||||
|     n = strtoul(s1, &s2, base); |  | ||||||
|     if (s1 != s2) {  /* at least one valid digit? */ |  | ||||||
|       while (isspace((unsigned char)(*s2))) s2++;  /* skip trailing spaces */ |  | ||||||
|       if (*s2 == '\0') {  /* no invalid trailing characters? */ |  | ||||||
|         lua_pushnumber(L, (lua_Number)n); |  | ||||||
|         return 1; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   lua_pushnil(L);  /* else not a number */ |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_error (lua_State *L) { |  | ||||||
|   int level = luaL_optint(L, 2, 1); |  | ||||||
|   lua_settop(L, 1); |  | ||||||
|   if (lua_isstring(L, 1) && level > 0) {  /* add extra information? */ |  | ||||||
|     luaL_where(L, level); |  | ||||||
|     lua_pushvalue(L, 1); |  | ||||||
|     lua_concat(L, 2); |  | ||||||
|   } |  | ||||||
|   return lua_error(L); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_getmetatable (lua_State *L) { |  | ||||||
|   luaL_checkany(L, 1); |  | ||||||
|   if (!lua_getmetatable(L, 1)) { |  | ||||||
|     lua_pushnil(L); |  | ||||||
|     return 1;  /* no metatable */ |  | ||||||
|   } |  | ||||||
|   luaL_getmetafield(L, 1, "__metatable"); |  | ||||||
|   return 1;  /* returns either __metatable field (if present) or metatable */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_setmetatable (lua_State *L) { |  | ||||||
|   int t = lua_type(L, 2); |  | ||||||
|   luaL_checktype(L, 1, LUA_TTABLE); |  | ||||||
|   luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, |  | ||||||
|                     "nil or table expected"); |  | ||||||
|   if (luaL_getmetafield(L, 1, "__metatable")) |  | ||||||
|     luaL_error(L, "cannot change a protected metatable"); |  | ||||||
|   lua_settop(L, 2); |  | ||||||
|   lua_setmetatable(L, 1); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void getfunc (lua_State *L) { |  | ||||||
|   if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); |  | ||||||
|   else { |  | ||||||
|     lua_Debug ar; |  | ||||||
|     int level = luaL_optint(L, 1, 1); |  | ||||||
|     luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); |  | ||||||
|     if (lua_getstack(L, level, &ar) == 0) |  | ||||||
|       luaL_argerror(L, 1, "invalid level"); |  | ||||||
|     lua_getinfo(L, "f", &ar); |  | ||||||
|     if (lua_isnil(L, -1)) |  | ||||||
|       luaL_error(L, "no function environment for tail call at level %d", |  | ||||||
|                     level); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_getfenv (lua_State *L) { |  | ||||||
|   getfunc(L); |  | ||||||
|   if (lua_iscfunction(L, -1))  /* is a C function? */ |  | ||||||
|     lua_pushvalue(L, LUA_GLOBALSINDEX);  /* return the thread's global env. */ |  | ||||||
|   else |  | ||||||
|     lua_getfenv(L, -1); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_setfenv (lua_State *L) { |  | ||||||
|   luaL_checktype(L, 2, LUA_TTABLE); |  | ||||||
|   getfunc(L); |  | ||||||
|   lua_pushvalue(L, 2); |  | ||||||
|   if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) { |  | ||||||
|     /* change environment of current thread */ |  | ||||||
|     lua_pushthread(L); |  | ||||||
|     lua_insert(L, -2); |  | ||||||
|     lua_setfenv(L, -2); |  | ||||||
|     return 0; |  | ||||||
|   } |  | ||||||
|   else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) |  | ||||||
|     luaL_error(L, |  | ||||||
|           LUA_QL("setfenv") " cannot change environment of given object"); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_rawequal (lua_State *L) { |  | ||||||
|   luaL_checkany(L, 1); |  | ||||||
|   luaL_checkany(L, 2); |  | ||||||
|   lua_pushboolean(L, lua_rawequal(L, 1, 2)); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_rawget (lua_State *L) { |  | ||||||
|   luaL_checktype(L, 1, LUA_TTABLE); |  | ||||||
|   luaL_checkany(L, 2); |  | ||||||
|   lua_settop(L, 2); |  | ||||||
|   lua_rawget(L, 1); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int luaB_rawset (lua_State *L) { |  | ||||||
|   luaL_checktype(L, 1, LUA_TTABLE); |  | ||||||
|   luaL_checkany(L, 2); |  | ||||||
|   luaL_checkany(L, 3); |  | ||||||
|   lua_settop(L, 3); |  | ||||||
|   lua_rawset(L, 1); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_gcinfo (lua_State *L) { |  | ||||||
|   lua_pushinteger(L, lua_getgccount(L)); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_collectgarbage (lua_State *L) { |  | ||||||
|   static const char *const opts[] = {"stop", "restart", "collect", |  | ||||||
|     "count", "step", "setpause", "setstepmul", NULL}; |  | ||||||
|   static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, |  | ||||||
|     LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; |  | ||||||
|   int o = luaL_checkoption(L, 1, "collect", opts); |  | ||||||
|   int ex = luaL_optint(L, 2, 0); |  | ||||||
|   int res = lua_gc(L, optsnum[o], ex); |  | ||||||
|   switch (optsnum[o]) { |  | ||||||
|     case LUA_GCCOUNT: { |  | ||||||
|       int b = lua_gc(L, LUA_GCCOUNTB, 0); |  | ||||||
|       lua_pushnumber(L, res + ((lua_Number)b/1024)); |  | ||||||
|       return 1; |  | ||||||
|     } |  | ||||||
|     case LUA_GCSTEP: { |  | ||||||
|       lua_pushboolean(L, res); |  | ||||||
|       return 1; |  | ||||||
|     } |  | ||||||
|     default: { |  | ||||||
|       lua_pushnumber(L, res); |  | ||||||
|       return 1; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_type (lua_State *L) { |  | ||||||
|   luaL_checkany(L, 1); |  | ||||||
|   lua_pushstring(L, luaL_typename(L, 1)); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_next (lua_State *L) { |  | ||||||
|   luaL_checktype(L, 1, LUA_TTABLE); |  | ||||||
|   lua_settop(L, 2);  /* create a 2nd argument if there isn't one */ |  | ||||||
|   if (lua_next(L, 1)) |  | ||||||
|     return 2; |  | ||||||
|   else { |  | ||||||
|     lua_pushnil(L); |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_pairs (lua_State *L) { |  | ||||||
|   luaL_checktype(L, 1, LUA_TTABLE); |  | ||||||
|   lua_pushvalue(L, lua_upvalueindex(1));  /* return generator, */ |  | ||||||
|   lua_pushvalue(L, 1);  /* state, */ |  | ||||||
|   lua_pushnil(L);  /* and initial value */ |  | ||||||
|   return 3; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int ipairsaux (lua_State *L) { |  | ||||||
|   int i = luaL_checkint(L, 2); |  | ||||||
|   luaL_checktype(L, 1, LUA_TTABLE); |  | ||||||
|   i++;  /* next value */ |  | ||||||
|   lua_pushinteger(L, i); |  | ||||||
|   lua_rawgeti(L, 1, i); |  | ||||||
|   return (lua_isnil(L, -1)) ? 0 : 2; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_ipairs (lua_State *L) { |  | ||||||
|   luaL_checktype(L, 1, LUA_TTABLE); |  | ||||||
|   lua_pushvalue(L, lua_upvalueindex(1));  /* return generator, */ |  | ||||||
|   lua_pushvalue(L, 1);  /* state, */ |  | ||||||
|   lua_pushinteger(L, 0);  /* and initial value */ |  | ||||||
|   return 3; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int load_aux (lua_State *L, int status) { |  | ||||||
|   if (status == 0)  /* OK? */ |  | ||||||
|     return 1; |  | ||||||
|   else { |  | ||||||
|     lua_pushnil(L); |  | ||||||
|     lua_insert(L, -2);  /* put before error message */ |  | ||||||
|     return 2;  /* return nil plus error message */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_loadstring (lua_State *L) { |  | ||||||
|   size_t l; |  | ||||||
|   const char *s = luaL_checklstring(L, 1, &l); |  | ||||||
|   const char *chunkname = luaL_optstring(L, 2, s); |  | ||||||
|   return load_aux(L, luaL_loadbuffer(L, s, l, chunkname)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_loadfile (lua_State *L) { |  | ||||||
|   const char *fname = luaL_optstring(L, 1, NULL); |  | ||||||
|   return load_aux(L, luaL_loadfile(L, fname)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Reader for generic `load' function: `lua_load' uses the |  | ||||||
| ** stack for internal stuff, so the reader cannot change the |  | ||||||
| ** stack top. Instead, it keeps its resulting string in a |  | ||||||
| ** reserved slot inside the stack. |  | ||||||
| */ |  | ||||||
| static const char *generic_reader (lua_State *L, void *ud, size_t *size) { |  | ||||||
|   (void)ud;  /* to avoid warnings */ |  | ||||||
|   luaL_checkstack(L, 2, "too many nested functions"); |  | ||||||
|   lua_pushvalue(L, 1);  /* get function */ |  | ||||||
|   lua_call(L, 0, 1);  /* call it */ |  | ||||||
|   if (lua_isnil(L, -1)) { |  | ||||||
|     *size = 0; |  | ||||||
|     return NULL; |  | ||||||
|   } |  | ||||||
|   else if (lua_isstring(L, -1)) { |  | ||||||
|     lua_replace(L, 3);  /* save string in a reserved stack slot */ |  | ||||||
|     return lua_tolstring(L, 3, size); |  | ||||||
|   } |  | ||||||
|   else luaL_error(L, "reader function must return a string"); |  | ||||||
|   return NULL;  /* to avoid warnings */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_load (lua_State *L) { |  | ||||||
|   int status; |  | ||||||
|   const char *cname = luaL_optstring(L, 2, "=(load)"); |  | ||||||
|   luaL_checktype(L, 1, LUA_TFUNCTION); |  | ||||||
|   lua_settop(L, 3);  /* function, eventual name, plus one reserved slot */ |  | ||||||
|   status = lua_load(L, generic_reader, NULL, cname); |  | ||||||
|   return load_aux(L, status); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_dofile (lua_State *L) { |  | ||||||
|   const char *fname = luaL_optstring(L, 1, NULL); |  | ||||||
|   int n = lua_gettop(L); |  | ||||||
|   if (luaL_loadfile(L, fname) != 0) lua_error(L); |  | ||||||
|   lua_call(L, 0, LUA_MULTRET); |  | ||||||
|   return lua_gettop(L) - n; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_assert (lua_State *L) { |  | ||||||
|   luaL_checkany(L, 1); |  | ||||||
|   if (!lua_toboolean(L, 1)) |  | ||||||
|     return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); |  | ||||||
|   return lua_gettop(L); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_unpack (lua_State *L) { |  | ||||||
|   int i, e, n; |  | ||||||
|   luaL_checktype(L, 1, LUA_TTABLE); |  | ||||||
|   i = luaL_optint(L, 2, 1); |  | ||||||
|   e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1)); |  | ||||||
|   n = e - i + 1;  /* number of elements */ |  | ||||||
|   if (n <= 0) return 0;  /* empty range */ |  | ||||||
|   luaL_checkstack(L, n, "table too big to unpack"); |  | ||||||
|   for (; i<=e; i++)  /* push arg[i...e] */ |  | ||||||
|     lua_rawgeti(L, 1, i); |  | ||||||
|   return n; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_select (lua_State *L) { |  | ||||||
|   int n = lua_gettop(L); |  | ||||||
|   if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { |  | ||||||
|     lua_pushinteger(L, n-1); |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     int i = luaL_checkint(L, 1); |  | ||||||
|     if (i < 0) i = n + i; |  | ||||||
|     else if (i > n) i = n; |  | ||||||
|     luaL_argcheck(L, 1 <= i, 1, "index out of range"); |  | ||||||
|     return n - i; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_pcall (lua_State *L) { |  | ||||||
|   int status; |  | ||||||
|   luaL_checkany(L, 1); |  | ||||||
|   status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); |  | ||||||
|   lua_pushboolean(L, (status == 0)); |  | ||||||
|   lua_insert(L, 1); |  | ||||||
|   return lua_gettop(L);  /* return status + all results */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_xpcall (lua_State *L) { |  | ||||||
|   int status; |  | ||||||
|   luaL_checkany(L, 2); |  | ||||||
|   lua_settop(L, 2); |  | ||||||
|   lua_insert(L, 1);  /* put error function under function to be called */ |  | ||||||
|   status = lua_pcall(L, 0, LUA_MULTRET, 1); |  | ||||||
|   lua_pushboolean(L, (status == 0)); |  | ||||||
|   lua_replace(L, 1); |  | ||||||
|   return lua_gettop(L);  /* return status + all results */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_tostring (lua_State *L) { |  | ||||||
|   luaL_checkany(L, 1); |  | ||||||
|   if (luaL_callmeta(L, 1, "__tostring"))  /* is there a metafield? */ |  | ||||||
|     return 1;  /* use its value */ |  | ||||||
|   switch (lua_type(L, 1)) { |  | ||||||
|     case LUA_TNUMBER: |  | ||||||
|       lua_pushstring(L, lua_tostring(L, 1)); |  | ||||||
|       break; |  | ||||||
|     case LUA_TSTRING: |  | ||||||
|       lua_pushvalue(L, 1); |  | ||||||
|       break; |  | ||||||
|     case LUA_TBOOLEAN: |  | ||||||
|       lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); |  | ||||||
|       break; |  | ||||||
|     case LUA_TNIL: |  | ||||||
|       lua_pushliteral(L, "nil"); |  | ||||||
|       break; |  | ||||||
|     default: |  | ||||||
|       lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); |  | ||||||
|       break; |  | ||||||
|   } |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_newproxy (lua_State *L) { |  | ||||||
|   lua_settop(L, 1); |  | ||||||
|   lua_newuserdata(L, 0);  /* create proxy */ |  | ||||||
|   if (lua_toboolean(L, 1) == 0) |  | ||||||
|     return 1;  /* no metatable */ |  | ||||||
|   else if (lua_isboolean(L, 1)) { |  | ||||||
|     lua_newtable(L);  /* create a new metatable `m' ... */ |  | ||||||
|     lua_pushvalue(L, -1);  /* ... and mark `m' as a valid metatable */ |  | ||||||
|     lua_pushboolean(L, 1); |  | ||||||
|     lua_rawset(L, lua_upvalueindex(1));  /* weaktable[m] = true */ |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     int validproxy = 0;  /* to check if weaktable[metatable(u)] == true */ |  | ||||||
|     if (lua_getmetatable(L, 1)) { |  | ||||||
|       lua_rawget(L, lua_upvalueindex(1)); |  | ||||||
|       validproxy = lua_toboolean(L, -1); |  | ||||||
|       lua_pop(L, 1);  /* remove value */ |  | ||||||
|     } |  | ||||||
|     luaL_argcheck(L, validproxy, 1, "boolean or proxy expected"); |  | ||||||
|     lua_getmetatable(L, 1);  /* metatable is valid; get it */ |  | ||||||
|   } |  | ||||||
|   lua_setmetatable(L, 2); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const luaL_Reg base_funcs[] = { |  | ||||||
|   {"assert", luaB_assert}, |  | ||||||
|   {"collectgarbage", luaB_collectgarbage}, |  | ||||||
|   {"dofile", luaB_dofile}, |  | ||||||
|   {"error", luaB_error}, |  | ||||||
|   {"gcinfo", luaB_gcinfo}, |  | ||||||
|   {"getfenv", luaB_getfenv}, |  | ||||||
|   {"getmetatable", luaB_getmetatable}, |  | ||||||
|   {"loadfile", luaB_loadfile}, |  | ||||||
|   {"load", luaB_load}, |  | ||||||
|   {"loadstring", luaB_loadstring}, |  | ||||||
|   {"next", luaB_next}, |  | ||||||
|   {"pcall", luaB_pcall}, |  | ||||||
|   {"print", luaB_print}, |  | ||||||
|   {"rawequal", luaB_rawequal}, |  | ||||||
|   {"rawget", luaB_rawget}, |  | ||||||
|   {"rawset", luaB_rawset}, |  | ||||||
|   {"select", luaB_select}, |  | ||||||
|   {"setfenv", luaB_setfenv}, |  | ||||||
|   {"setmetatable", luaB_setmetatable}, |  | ||||||
|   {"tonumber", luaB_tonumber}, |  | ||||||
|   {"tostring", luaB_tostring}, |  | ||||||
|   {"type", luaB_type}, |  | ||||||
|   {"unpack", luaB_unpack}, |  | ||||||
|   {"xpcall", luaB_xpcall}, |  | ||||||
|   {NULL, NULL} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** Coroutine library |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| static int auxresume (lua_State *L, lua_State *co, int narg) { |  | ||||||
|   int status; |  | ||||||
|   if (!lua_checkstack(co, narg)) |  | ||||||
|     luaL_error(L, "too many arguments to resume"); |  | ||||||
|   if (lua_status(co) == 0 && lua_gettop(co) == 0) { |  | ||||||
|     lua_pushliteral(L, "cannot resume dead coroutine"); |  | ||||||
|     return -1;  /* error flag */ |  | ||||||
|   } |  | ||||||
|   lua_xmove(L, co, narg); |  | ||||||
|   status = lua_resume(co, narg); |  | ||||||
|   if (status == 0 || status == LUA_YIELD) { |  | ||||||
|     int nres = lua_gettop(co); |  | ||||||
|     if (!lua_checkstack(L, nres)) |  | ||||||
|       luaL_error(L, "too many results to resume"); |  | ||||||
|     lua_xmove(co, L, nres);  /* move yielded values */ |  | ||||||
|     return nres; |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     lua_xmove(co, L, 1);  /* move error message */ |  | ||||||
|     return -1;  /* error flag */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_coresume (lua_State *L) { |  | ||||||
|   lua_State *co = lua_tothread(L, 1); |  | ||||||
|   int r; |  | ||||||
|   luaL_argcheck(L, co, 1, "coroutine expected"); |  | ||||||
|   r = auxresume(L, co, lua_gettop(L) - 1); |  | ||||||
|   if (r < 0) { |  | ||||||
|     lua_pushboolean(L, 0); |  | ||||||
|     lua_insert(L, -2); |  | ||||||
|     return 2;  /* return false + error message */ |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     lua_pushboolean(L, 1); |  | ||||||
|     lua_insert(L, -(r + 1)); |  | ||||||
|     return r + 1;  /* return true + `resume' returns */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_auxwrap (lua_State *L) { |  | ||||||
|   lua_State *co = lua_tothread(L, lua_upvalueindex(1)); |  | ||||||
|   int r = auxresume(L, co, lua_gettop(L)); |  | ||||||
|   if (r < 0) { |  | ||||||
|     if (lua_isstring(L, -1)) {  /* error object is a string? */ |  | ||||||
|       luaL_where(L, 1);  /* add extra info */ |  | ||||||
|       lua_insert(L, -2); |  | ||||||
|       lua_concat(L, 2); |  | ||||||
|     } |  | ||||||
|     lua_error(L);  /* propagate error */ |  | ||||||
|   } |  | ||||||
|   return r; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_cocreate (lua_State *L) { |  | ||||||
|   lua_State *NL = lua_newthread(L); |  | ||||||
|   luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, |  | ||||||
|     "Lua function expected"); |  | ||||||
|   lua_pushvalue(L, 1);  /* move function to top */ |  | ||||||
|   lua_xmove(L, NL, 1);  /* move function from L to NL */ |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_cowrap (lua_State *L) { |  | ||||||
|   luaB_cocreate(L); |  | ||||||
|   lua_pushcclosure(L, luaB_auxwrap, 1); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_yield (lua_State *L) { |  | ||||||
|   return lua_yield(L, lua_gettop(L)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_costatus (lua_State *L) { |  | ||||||
|   lua_State *co = lua_tothread(L, 1); |  | ||||||
|   luaL_argcheck(L, co, 1, "coroutine expected"); |  | ||||||
|   if (L == co) lua_pushliteral(L, "running"); |  | ||||||
|   else { |  | ||||||
|     switch (lua_status(co)) { |  | ||||||
|       case LUA_YIELD: |  | ||||||
|         lua_pushliteral(L, "suspended"); |  | ||||||
|         break; |  | ||||||
|       case 0: { |  | ||||||
|         lua_Debug ar; |  | ||||||
|         if (lua_getstack(co, 0, &ar) > 0)  /* does it have frames? */ |  | ||||||
|           lua_pushliteral(L, "normal");  /* it is running */ |  | ||||||
|         else if (lua_gettop(co) == 0) |  | ||||||
|             lua_pushliteral(L, "dead"); |  | ||||||
|         else |  | ||||||
|           lua_pushliteral(L, "suspended");  /* initial state */ |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       default:  /* some error occured */ |  | ||||||
|         lua_pushliteral(L, "dead"); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaB_corunning (lua_State *L) { |  | ||||||
|   if (lua_pushthread(L)) |  | ||||||
|     return 0;  /* main thread is not a coroutine */ |  | ||||||
|   else |  | ||||||
|     return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const luaL_Reg co_funcs[] = { |  | ||||||
|   {"create", luaB_cocreate}, |  | ||||||
|   {"resume", luaB_coresume}, |  | ||||||
|   {"running", luaB_corunning}, |  | ||||||
|   {"status", luaB_costatus}, |  | ||||||
|   {"wrap", luaB_cowrap}, |  | ||||||
|   {"yield", luaB_yield}, |  | ||||||
|   {NULL, NULL} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void auxopen (lua_State *L, const char *name, |  | ||||||
|                      lua_CFunction f, lua_CFunction u) { |  | ||||||
|   lua_pushcfunction(L, u); |  | ||||||
|   lua_pushcclosure(L, f, 1); |  | ||||||
|   lua_setfield(L, -2, name); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void base_open (lua_State *L) { |  | ||||||
|   /* set global _G */ |  | ||||||
|   lua_pushvalue(L, LUA_GLOBALSINDEX); |  | ||||||
|   lua_setglobal(L, "_G"); |  | ||||||
|   /* open lib into global table */ |  | ||||||
|   luaL_register(L, "_G", base_funcs); |  | ||||||
|   lua_pushliteral(L, LUA_VERSION); |  | ||||||
|   lua_setglobal(L, "_VERSION");  /* set global _VERSION */ |  | ||||||
|   /* `ipairs' and `pairs' need auxliliary functions as upvalues */ |  | ||||||
|   auxopen(L, "ipairs", luaB_ipairs, ipairsaux); |  | ||||||
|   auxopen(L, "pairs", luaB_pairs, luaB_next); |  | ||||||
|   /* `newproxy' needs a weaktable as upvalue */ |  | ||||||
|   lua_createtable(L, 0, 1);  /* new table `w' */ |  | ||||||
|   lua_pushvalue(L, -1);  /* `w' will be its own metatable */ |  | ||||||
|   lua_setmetatable(L, -2); |  | ||||||
|   lua_pushliteral(L, "kv"); |  | ||||||
|   lua_setfield(L, -2, "__mode");  /* metatable(w).__mode = "kv" */ |  | ||||||
|   lua_pushcclosure(L, luaB_newproxy, 1); |  | ||||||
|   lua_setglobal(L, "newproxy");  /* set global `newproxy' */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaopen_base (lua_State *L) { |  | ||||||
|   base_open(L); |  | ||||||
|   luaL_register(L, LUA_COLIBNAME, co_funcs); |  | ||||||
|   return 2; |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										825
									
								
								src/lua/lcode.c
									
									
									
									
									
								
							
							
						
						
									
										825
									
								
								src/lua/lcode.c
									
									
									
									
									
								
							| @@ -1,825 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lcode.c,v 2.24 2005/12/22 16:19:56 roberto Exp $ |  | ||||||
| ** Code generator for Lua |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <stdlib.h> |  | ||||||
|  |  | ||||||
| #define lcode_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lcode.h" |  | ||||||
| #include "ldebug.h" |  | ||||||
| #include "ldo.h" |  | ||||||
| #include "lgc.h" |  | ||||||
| #include "llex.h" |  | ||||||
| #include "lmem.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lopcodes.h" |  | ||||||
| #include "lparser.h" |  | ||||||
| #include "ltable.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define hasjumps(e)	((e)->t != (e)->f) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int isnumeral(expdesc *e) { |  | ||||||
|   return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_nil (FuncState *fs, int from, int n) { |  | ||||||
|   Instruction *previous; |  | ||||||
|   if (fs->pc > fs->lasttarget) {  /* no jumps to current position? */ |  | ||||||
|     if (fs->pc == 0)  /* function start? */ |  | ||||||
|       return;  /* positions are already clean */ |  | ||||||
|     if (GET_OPCODE(*(previous = &fs->f->code[fs->pc-1])) == OP_LOADNIL) { |  | ||||||
|       int pfrom = GETARG_A(*previous); |  | ||||||
|       int pto = GETARG_B(*previous); |  | ||||||
|       if (pfrom <= from && from <= pto+1) {  /* can connect both? */ |  | ||||||
|         if (from+n-1 > pto) |  | ||||||
|           SETARG_B(*previous, from+n-1); |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0);  /* else no optimization */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaK_jump (FuncState *fs) { |  | ||||||
|   int jpc = fs->jpc;  /* save list of jumps to here */ |  | ||||||
|   int j; |  | ||||||
|   fs->jpc = NO_JUMP; |  | ||||||
|   j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); |  | ||||||
|   luaK_concat(fs, &j, jpc);  /* keep them on hold */ |  | ||||||
|   return j; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_ret (FuncState *fs, int first, int nret) { |  | ||||||
|   luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { |  | ||||||
|   luaK_codeABC(fs, op, A, B, C); |  | ||||||
|   return luaK_jump(fs); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void fixjump (FuncState *fs, int pc, int dest) { |  | ||||||
|   Instruction *jmp = &fs->f->code[pc]; |  | ||||||
|   int offset = dest-(pc+1); |  | ||||||
|   lua_assert(dest != NO_JUMP); |  | ||||||
|   if (abs(offset) > MAXARG_sBx) |  | ||||||
|     luaX_syntaxerror(fs->ls, "control structure too long"); |  | ||||||
|   SETARG_sBx(*jmp, offset); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** returns current `pc' and marks it as a jump target (to avoid wrong |  | ||||||
| ** optimizations with consecutive instructions not in the same basic block). |  | ||||||
| */ |  | ||||||
| int luaK_getlabel (FuncState *fs) { |  | ||||||
|   fs->lasttarget = fs->pc; |  | ||||||
|   return fs->pc; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int getjump (FuncState *fs, int pc) { |  | ||||||
|   int offset = GETARG_sBx(fs->f->code[pc]); |  | ||||||
|   if (offset == NO_JUMP)  /* point to itself represents end of list */ |  | ||||||
|     return NO_JUMP;  /* end of list */ |  | ||||||
|   else |  | ||||||
|     return (pc+1)+offset;  /* turn offset into absolute position */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static Instruction *getjumpcontrol (FuncState *fs, int pc) { |  | ||||||
|   Instruction *pi = &fs->f->code[pc]; |  | ||||||
|   if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) |  | ||||||
|     return pi-1; |  | ||||||
|   else |  | ||||||
|     return pi; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** check whether list has any jump that do not produce a value |  | ||||||
| ** (or produce an inverted value) |  | ||||||
| */ |  | ||||||
| static int need_value (FuncState *fs, int list) { |  | ||||||
|   for (; list != NO_JUMP; list = getjump(fs, list)) { |  | ||||||
|     Instruction i = *getjumpcontrol(fs, list); |  | ||||||
|     if (GET_OPCODE(i) != OP_TESTSET) return 1; |  | ||||||
|   } |  | ||||||
|   return 0;  /* not found */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int patchtestreg (FuncState *fs, int node, int reg) { |  | ||||||
|   Instruction *i = getjumpcontrol(fs, node); |  | ||||||
|   if (GET_OPCODE(*i) != OP_TESTSET) |  | ||||||
|     return 0;  /* cannot patch other instructions */ |  | ||||||
|   if (reg != NO_REG && reg != GETARG_B(*i)) |  | ||||||
|     SETARG_A(*i, reg); |  | ||||||
|   else  /* no register to put value or register already has the value */ |  | ||||||
|     *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); |  | ||||||
|  |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void removevalues (FuncState *fs, int list) { |  | ||||||
|   for (; list != NO_JUMP; list = getjump(fs, list)) |  | ||||||
|       patchtestreg(fs, list, NO_REG); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, |  | ||||||
|                           int dtarget) { |  | ||||||
|   while (list != NO_JUMP) { |  | ||||||
|     int next = getjump(fs, list); |  | ||||||
|     if (patchtestreg(fs, list, reg)) |  | ||||||
|       fixjump(fs, list, vtarget); |  | ||||||
|     else |  | ||||||
|       fixjump(fs, list, dtarget);  /* jump to default target */ |  | ||||||
|     list = next; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void dischargejpc (FuncState *fs) { |  | ||||||
|   patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); |  | ||||||
|   fs->jpc = NO_JUMP; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_patchlist (FuncState *fs, int list, int target) { |  | ||||||
|   if (target == fs->pc) |  | ||||||
|     luaK_patchtohere(fs, list); |  | ||||||
|   else { |  | ||||||
|     lua_assert(target < fs->pc); |  | ||||||
|     patchlistaux(fs, list, target, NO_REG, target); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_patchtohere (FuncState *fs, int list) { |  | ||||||
|   luaK_getlabel(fs); |  | ||||||
|   luaK_concat(fs, &fs->jpc, list); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_concat (FuncState *fs, int *l1, int l2) { |  | ||||||
|   if (l2 == NO_JUMP) return; |  | ||||||
|   else if (*l1 == NO_JUMP) |  | ||||||
|     *l1 = l2; |  | ||||||
|   else { |  | ||||||
|     int list = *l1; |  | ||||||
|     int next; |  | ||||||
|     while ((next = getjump(fs, list)) != NO_JUMP)  /* find last element */ |  | ||||||
|       list = next; |  | ||||||
|     fixjump(fs, list, l2); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_checkstack (FuncState *fs, int n) { |  | ||||||
|   int newstack = fs->freereg + n; |  | ||||||
|   if (newstack > fs->f->maxstacksize) { |  | ||||||
|     if (newstack >= MAXSTACK) |  | ||||||
|       luaX_syntaxerror(fs->ls, "function or expression too complex"); |  | ||||||
|     fs->f->maxstacksize = cast_byte(newstack); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_reserveregs (FuncState *fs, int n) { |  | ||||||
|   luaK_checkstack(fs, n); |  | ||||||
|   fs->freereg += n; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void freereg (FuncState *fs, int reg) { |  | ||||||
|   if (!ISK(reg) && reg >= fs->nactvar) { |  | ||||||
|     fs->freereg--; |  | ||||||
|     lua_assert(reg == fs->freereg); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void freeexp (FuncState *fs, expdesc *e) { |  | ||||||
|   if (e->k == VNONRELOC) |  | ||||||
|     freereg(fs, e->u.s.info); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int addk (FuncState *fs, TValue *k, TValue *v) { |  | ||||||
|   lua_State *L = fs->L; |  | ||||||
|   TValue *idx = luaH_set(L, fs->h, k); |  | ||||||
|   Proto *f = fs->f; |  | ||||||
|   int oldsize = f->sizek; |  | ||||||
|   if (ttisnumber(idx)) { |  | ||||||
|     lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); |  | ||||||
|     return cast_int(nvalue(idx)); |  | ||||||
|   } |  | ||||||
|   else {  /* constant not found; create a new entry */ |  | ||||||
|     setnvalue(idx, cast_num(fs->nk)); |  | ||||||
|     luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, |  | ||||||
|                     MAXARG_Bx, "constant table overflow"); |  | ||||||
|     while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); |  | ||||||
|     setobj(L, &f->k[fs->nk], v); |  | ||||||
|     luaC_barrier(L, f, v); |  | ||||||
|     return fs->nk++; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaK_stringK (FuncState *fs, TString *s) { |  | ||||||
|   TValue o; |  | ||||||
|   setsvalue(fs->L, &o, s); |  | ||||||
|   return addk(fs, &o, &o); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaK_numberK (FuncState *fs, lua_Number r) { |  | ||||||
|   TValue o; |  | ||||||
|   setnvalue(&o, r); |  | ||||||
|   return addk(fs, &o, &o); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int boolK (FuncState *fs, int b) { |  | ||||||
|   TValue o; |  | ||||||
|   setbvalue(&o, b); |  | ||||||
|   return addk(fs, &o, &o); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int nilK (FuncState *fs) { |  | ||||||
|   TValue k, v; |  | ||||||
|   setnilvalue(&v); |  | ||||||
|   /* cannot use nil as key; instead use table itself to represent nil */ |  | ||||||
|   sethvalue(fs->L, &k, fs->h); |  | ||||||
|   return addk(fs, &k, &v); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { |  | ||||||
|   if (e->k == VCALL) {  /* expression is an open function call? */ |  | ||||||
|     SETARG_C(getcode(fs, e), nresults+1); |  | ||||||
|   } |  | ||||||
|   else if (e->k == VVARARG) { |  | ||||||
|     SETARG_B(getcode(fs, e), nresults+1); |  | ||||||
|     SETARG_A(getcode(fs, e), fs->freereg); |  | ||||||
|     luaK_reserveregs(fs, 1); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_setoneret (FuncState *fs, expdesc *e) { |  | ||||||
|   if (e->k == VCALL) {  /* expression is an open function call? */ |  | ||||||
|     e->k = VNONRELOC; |  | ||||||
|     e->u.s.info = GETARG_A(getcode(fs, e)); |  | ||||||
|   } |  | ||||||
|   else if (e->k == VVARARG) { |  | ||||||
|     SETARG_B(getcode(fs, e), 2); |  | ||||||
|     e->k = VRELOCABLE;  /* can relocate its simple result */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_dischargevars (FuncState *fs, expdesc *e) { |  | ||||||
|   switch (e->k) { |  | ||||||
|     case VLOCAL: { |  | ||||||
|       e->k = VNONRELOC; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VUPVAL: { |  | ||||||
|       e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0); |  | ||||||
|       e->k = VRELOCABLE; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VGLOBAL: { |  | ||||||
|       e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info); |  | ||||||
|       e->k = VRELOCABLE; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VINDEXED: { |  | ||||||
|       freereg(fs, e->u.s.aux); |  | ||||||
|       freereg(fs, e->u.s.info); |  | ||||||
|       e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux); |  | ||||||
|       e->k = VRELOCABLE; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VVARARG: |  | ||||||
|     case VCALL: { |  | ||||||
|       luaK_setoneret(fs, e); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     default: break;  /* there is one value available (somewhere) */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int code_label (FuncState *fs, int A, int b, int jump) { |  | ||||||
|   luaK_getlabel(fs);  /* those instructions may be jump targets */ |  | ||||||
|   return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void discharge2reg (FuncState *fs, expdesc *e, int reg) { |  | ||||||
|   luaK_dischargevars(fs, e); |  | ||||||
|   switch (e->k) { |  | ||||||
|     case VNIL: { |  | ||||||
|       luaK_nil(fs, reg, 1); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VFALSE:  case VTRUE: { |  | ||||||
|       luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VK: { |  | ||||||
|       luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VKNUM: { |  | ||||||
|       luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval)); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VRELOCABLE: { |  | ||||||
|       Instruction *pc = &getcode(fs, e); |  | ||||||
|       SETARG_A(*pc, reg); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VNONRELOC: { |  | ||||||
|       if (reg != e->u.s.info) |  | ||||||
|         luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     default: { |  | ||||||
|       lua_assert(e->k == VVOID || e->k == VJMP); |  | ||||||
|       return;  /* nothing to do... */ |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   e->u.s.info = reg; |  | ||||||
|   e->k = VNONRELOC; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void discharge2anyreg (FuncState *fs, expdesc *e) { |  | ||||||
|   if (e->k != VNONRELOC) { |  | ||||||
|     luaK_reserveregs(fs, 1); |  | ||||||
|     discharge2reg(fs, e, fs->freereg-1); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void exp2reg (FuncState *fs, expdesc *e, int reg) { |  | ||||||
|   discharge2reg(fs, e, reg); |  | ||||||
|   if (e->k == VJMP) |  | ||||||
|     luaK_concat(fs, &e->t, e->u.s.info);  /* put this jump in `t' list */ |  | ||||||
|   if (hasjumps(e)) { |  | ||||||
|     int final;  /* position after whole expression */ |  | ||||||
|     int p_f = NO_JUMP;  /* position of an eventual LOAD false */ |  | ||||||
|     int p_t = NO_JUMP;  /* position of an eventual LOAD true */ |  | ||||||
|     if (need_value(fs, e->t) || need_value(fs, e->f)) { |  | ||||||
|       int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); |  | ||||||
|       p_f = code_label(fs, reg, 0, 1); |  | ||||||
|       p_t = code_label(fs, reg, 1, 0); |  | ||||||
|       luaK_patchtohere(fs, fj); |  | ||||||
|     } |  | ||||||
|     final = luaK_getlabel(fs); |  | ||||||
|     patchlistaux(fs, e->f, final, reg, p_f); |  | ||||||
|     patchlistaux(fs, e->t, final, reg, p_t); |  | ||||||
|   } |  | ||||||
|   e->f = e->t = NO_JUMP; |  | ||||||
|   e->u.s.info = reg; |  | ||||||
|   e->k = VNONRELOC; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_exp2nextreg (FuncState *fs, expdesc *e) { |  | ||||||
|   luaK_dischargevars(fs, e); |  | ||||||
|   freeexp(fs, e); |  | ||||||
|   luaK_reserveregs(fs, 1); |  | ||||||
|   exp2reg(fs, e, fs->freereg - 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaK_exp2anyreg (FuncState *fs, expdesc *e) { |  | ||||||
|   luaK_dischargevars(fs, e); |  | ||||||
|   if (e->k == VNONRELOC) { |  | ||||||
|     if (!hasjumps(e)) return e->u.s.info;  /* exp is already in a register */ |  | ||||||
|     if (e->u.s.info >= fs->nactvar) {  /* reg. is not a local? */ |  | ||||||
|       exp2reg(fs, e, e->u.s.info);  /* put value on it */ |  | ||||||
|       return e->u.s.info; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   luaK_exp2nextreg(fs, e);  /* default */ |  | ||||||
|   return e->u.s.info; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_exp2val (FuncState *fs, expdesc *e) { |  | ||||||
|   if (hasjumps(e)) |  | ||||||
|     luaK_exp2anyreg(fs, e); |  | ||||||
|   else |  | ||||||
|     luaK_dischargevars(fs, e); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaK_exp2RK (FuncState *fs, expdesc *e) { |  | ||||||
|   luaK_exp2val(fs, e); |  | ||||||
|   switch (e->k) { |  | ||||||
|     case VKNUM: |  | ||||||
|     case VTRUE: |  | ||||||
|     case VFALSE: |  | ||||||
|     case VNIL: { |  | ||||||
|       if (fs->nk <= MAXINDEXRK) {  /* constant fit in RK operand? */ |  | ||||||
|         e->u.s.info = (e->k == VNIL)  ? nilK(fs) : |  | ||||||
|                       (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) : |  | ||||||
|                                         boolK(fs, (e->k == VTRUE)); |  | ||||||
|         e->k = VK; |  | ||||||
|         return RKASK(e->u.s.info); |  | ||||||
|       } |  | ||||||
|       else break; |  | ||||||
|     } |  | ||||||
|     case VK: { |  | ||||||
|       if (e->u.s.info <= MAXINDEXRK)  /* constant fit in argC? */ |  | ||||||
|         return RKASK(e->u.s.info); |  | ||||||
|       else break; |  | ||||||
|     } |  | ||||||
|     default: break; |  | ||||||
|   } |  | ||||||
|   /* not a constant in the right range: put it in a register */ |  | ||||||
|   return luaK_exp2anyreg(fs, e); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { |  | ||||||
|   switch (var->k) { |  | ||||||
|     case VLOCAL: { |  | ||||||
|       freeexp(fs, ex); |  | ||||||
|       exp2reg(fs, ex, var->u.s.info); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     case VUPVAL: { |  | ||||||
|       int e = luaK_exp2anyreg(fs, ex); |  | ||||||
|       luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VGLOBAL: { |  | ||||||
|       int e = luaK_exp2anyreg(fs, ex); |  | ||||||
|       luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VINDEXED: { |  | ||||||
|       int e = luaK_exp2RK(fs, ex); |  | ||||||
|       luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     default: { |  | ||||||
|       lua_assert(0);  /* invalid var kind to store */ |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   freeexp(fs, ex); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { |  | ||||||
|   int func; |  | ||||||
|   luaK_exp2anyreg(fs, e); |  | ||||||
|   freeexp(fs, e); |  | ||||||
|   func = fs->freereg; |  | ||||||
|   luaK_reserveregs(fs, 2); |  | ||||||
|   luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key)); |  | ||||||
|   freeexp(fs, key); |  | ||||||
|   e->u.s.info = func; |  | ||||||
|   e->k = VNONRELOC; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void invertjump (FuncState *fs, expdesc *e) { |  | ||||||
|   Instruction *pc = getjumpcontrol(fs, e->u.s.info); |  | ||||||
|   lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && |  | ||||||
|                                            GET_OPCODE(*pc) != OP_TEST); |  | ||||||
|   SETARG_A(*pc, !(GETARG_A(*pc))); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int jumponcond (FuncState *fs, expdesc *e, int cond) { |  | ||||||
|   if (e->k == VRELOCABLE) { |  | ||||||
|     Instruction ie = getcode(fs, e); |  | ||||||
|     if (GET_OPCODE(ie) == OP_NOT) { |  | ||||||
|       fs->pc--;  /* remove previous OP_NOT */ |  | ||||||
|       return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); |  | ||||||
|     } |  | ||||||
|     /* else go through */ |  | ||||||
|   } |  | ||||||
|   discharge2anyreg(fs, e); |  | ||||||
|   freeexp(fs, e); |  | ||||||
|   return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_goiftrue (FuncState *fs, expdesc *e) { |  | ||||||
|   int pc;  /* pc of last jump */ |  | ||||||
|   luaK_dischargevars(fs, e); |  | ||||||
|   switch (e->k) { |  | ||||||
|     case VK: case VKNUM: case VTRUE: { |  | ||||||
|       pc = NO_JUMP;  /* always true; do nothing */ |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VFALSE: { |  | ||||||
|       pc = luaK_jump(fs);  /* always jump */ |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VJMP: { |  | ||||||
|       invertjump(fs, e); |  | ||||||
|       pc = e->u.s.info; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     default: { |  | ||||||
|       pc = jumponcond(fs, e, 0); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   luaK_concat(fs, &e->f, pc);  /* insert last jump in `f' list */ |  | ||||||
|   luaK_patchtohere(fs, e->t); |  | ||||||
|   e->t = NO_JUMP; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void luaK_goiffalse (FuncState *fs, expdesc *e) { |  | ||||||
|   int pc;  /* pc of last jump */ |  | ||||||
|   luaK_dischargevars(fs, e); |  | ||||||
|   switch (e->k) { |  | ||||||
|     case VNIL: case VFALSE: { |  | ||||||
|       pc = NO_JUMP;  /* always false; do nothing */ |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VTRUE: { |  | ||||||
|       pc = luaK_jump(fs);  /* always jump */ |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VJMP: { |  | ||||||
|       pc = e->u.s.info; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     default: { |  | ||||||
|       pc = jumponcond(fs, e, 1); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   luaK_concat(fs, &e->t, pc);  /* insert last jump in `t' list */ |  | ||||||
|   luaK_patchtohere(fs, e->f); |  | ||||||
|   e->f = NO_JUMP; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void codenot (FuncState *fs, expdesc *e) { |  | ||||||
|   luaK_dischargevars(fs, e); |  | ||||||
|   switch (e->k) { |  | ||||||
|     case VNIL: case VFALSE: { |  | ||||||
|       e->k = VTRUE; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VK: case VKNUM: case VTRUE: { |  | ||||||
|       e->k = VFALSE; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VJMP: { |  | ||||||
|       invertjump(fs, e); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case VRELOCABLE: |  | ||||||
|     case VNONRELOC: { |  | ||||||
|       discharge2anyreg(fs, e); |  | ||||||
|       freeexp(fs, e); |  | ||||||
|       e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0); |  | ||||||
|       e->k = VRELOCABLE; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     default: { |  | ||||||
|       lua_assert(0);  /* cannot happen */ |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   /* interchange true and false lists */ |  | ||||||
|   { int temp = e->f; e->f = e->t; e->t = temp; } |  | ||||||
|   removevalues(fs, e->f); |  | ||||||
|   removevalues(fs, e->t); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { |  | ||||||
|   t->u.s.aux = luaK_exp2RK(fs, k); |  | ||||||
|   t->k = VINDEXED; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { |  | ||||||
|   lua_Number v1, v2, r; |  | ||||||
|   if (!isnumeral(e1) || !isnumeral(e2)) return 0; |  | ||||||
|   v1 = e1->u.nval; |  | ||||||
|   v2 = e2->u.nval; |  | ||||||
|   switch (op) { |  | ||||||
|     case OP_ADD: r = luai_numadd(v1, v2); break; |  | ||||||
|     case OP_SUB: r = luai_numsub(v1, v2); break; |  | ||||||
|     case OP_MUL: r = luai_nummul(v1, v2); break; |  | ||||||
|     case OP_DIV: |  | ||||||
|       if (v2 == 0) return 0;  /* do not attempt to divide by 0 */ |  | ||||||
|       r = luai_numdiv(v1, v2); break; |  | ||||||
|     case OP_MOD: |  | ||||||
|       if (v2 == 0) return 0;  /* do not attempt to divide by 0 */ |  | ||||||
|       r = luai_nummod(v1, v2); break; |  | ||||||
|     case OP_POW: r = luai_numpow(v1, v2); break; |  | ||||||
|     case OP_UNM: r = luai_numunm(v1); break; |  | ||||||
|     case OP_LEN: return 0;  /* no constant folding for 'len' */ |  | ||||||
|     default: lua_assert(0); r = 0; break; |  | ||||||
|   } |  | ||||||
|   if (luai_numisnan(r)) return 0;  /* do not attempt to produce NaN */ |  | ||||||
|   e1->u.nval = r; |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { |  | ||||||
|   if (constfolding(op, e1, e2)) |  | ||||||
|     return; |  | ||||||
|   else { |  | ||||||
|     int o1 = luaK_exp2RK(fs, e1); |  | ||||||
|     int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; |  | ||||||
|     freeexp(fs, e2); |  | ||||||
|     freeexp(fs, e1); |  | ||||||
|     e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); |  | ||||||
|     e1->k = VRELOCABLE; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, |  | ||||||
|                                                           expdesc *e2) { |  | ||||||
|   int o1 = luaK_exp2RK(fs, e1); |  | ||||||
|   int o2 = luaK_exp2RK(fs, e2); |  | ||||||
|   freeexp(fs, e2); |  | ||||||
|   freeexp(fs, e1); |  | ||||||
|   if (cond == 0 && op != OP_EQ) { |  | ||||||
|     int temp;  /* exchange args to replace by `<' or `<=' */ |  | ||||||
|     temp = o1; o1 = o2; o2 = temp;  /* o1 <==> o2 */ |  | ||||||
|     cond = 1; |  | ||||||
|   } |  | ||||||
|   e1->u.s.info = condjump(fs, op, cond, o1, o2); |  | ||||||
|   e1->k = VJMP; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { |  | ||||||
|   expdesc e2; |  | ||||||
|   e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; |  | ||||||
|   switch (op) { |  | ||||||
|     case OPR_MINUS: { |  | ||||||
|       if (e->k == VK) |  | ||||||
|         luaK_exp2anyreg(fs, e);  /* cannot operate on non-numeric constants */ |  | ||||||
|       codearith(fs, OP_UNM, e, &e2); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case OPR_NOT: codenot(fs, e); break; |  | ||||||
|     case OPR_LEN: { |  | ||||||
|       luaK_exp2anyreg(fs, e);  /* cannot operate on constants */ |  | ||||||
|       codearith(fs, OP_LEN, e, &e2); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     default: lua_assert(0); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { |  | ||||||
|   switch (op) { |  | ||||||
|     case OPR_AND: { |  | ||||||
|       luaK_goiftrue(fs, v); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case OPR_OR: { |  | ||||||
|       luaK_goiffalse(fs, v); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case OPR_CONCAT: { |  | ||||||
|       luaK_exp2nextreg(fs, v);  /* operand must be on the `stack' */ |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     default: { |  | ||||||
|       if (!isnumeral(v)) luaK_exp2RK(fs, v); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { |  | ||||||
|   switch (op) { |  | ||||||
|     case OPR_AND: { |  | ||||||
|       lua_assert(e1->t == NO_JUMP);  /* list must be closed */ |  | ||||||
|       luaK_dischargevars(fs, e2); |  | ||||||
|       luaK_concat(fs, &e1->f, e2->f); |  | ||||||
|       e1->k = e2->k; e1->u.s.info = e2->u.s.info; |  | ||||||
|       e1->u.s.aux = e2->u.s.aux; e1->t = e2->t; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case OPR_OR: { |  | ||||||
|       lua_assert(e1->f == NO_JUMP);  /* list must be closed */ |  | ||||||
|       luaK_dischargevars(fs, e2); |  | ||||||
|       luaK_concat(fs, &e1->t, e2->t); |  | ||||||
|       e1->k = e2->k; e1->u.s.info = e2->u.s.info; |  | ||||||
|       e1->u.s.aux = e2->u.s.aux; e1->f = e2->f; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case OPR_CONCAT: { |  | ||||||
|       luaK_exp2val(fs, e2); |  | ||||||
|       if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { |  | ||||||
|         lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1); |  | ||||||
|         freeexp(fs, e1); |  | ||||||
|         SETARG_B(getcode(fs, e2), e1->u.s.info); |  | ||||||
|         e1->k = e2->k; e1->u.s.info = e2->u.s.info; |  | ||||||
|       } |  | ||||||
|       else { |  | ||||||
|         luaK_exp2nextreg(fs, e2);  /* operand must be on the 'stack' */ |  | ||||||
|         codearith(fs, OP_CONCAT, e1, e2); |  | ||||||
|       } |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break; |  | ||||||
|     case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break; |  | ||||||
|     case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break; |  | ||||||
|     case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break; |  | ||||||
|     case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break; |  | ||||||
|     case OPR_POW: codearith(fs, OP_POW, e1, e2); break; |  | ||||||
|     case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break; |  | ||||||
|     case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break; |  | ||||||
|     case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break; |  | ||||||
|     case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break; |  | ||||||
|     case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break; |  | ||||||
|     case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break; |  | ||||||
|     default: lua_assert(0); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_fixline (FuncState *fs, int line) { |  | ||||||
|   fs->f->lineinfo[fs->pc - 1] = line; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int luaK_code (FuncState *fs, Instruction i, int line) { |  | ||||||
|   Proto *f = fs->f; |  | ||||||
|   dischargejpc(fs);  /* `pc' will change */ |  | ||||||
|   /* put new instruction in code array */ |  | ||||||
|   luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, |  | ||||||
|                   MAX_INT, "code size overflow"); |  | ||||||
|   f->code[fs->pc] = i; |  | ||||||
|   /* save corresponding line information */ |  | ||||||
|   luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, |  | ||||||
|                   MAX_INT, "code size overflow"); |  | ||||||
|   f->lineinfo[fs->pc] = line; |  | ||||||
|   return fs->pc++; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { |  | ||||||
|   lua_assert(getOpMode(o) == iABC); |  | ||||||
|   lua_assert(getBMode(o) != OpArgN || b == 0); |  | ||||||
|   lua_assert(getCMode(o) != OpArgN || c == 0); |  | ||||||
|   return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { |  | ||||||
|   lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); |  | ||||||
|   lua_assert(getCMode(o) == OpArgN); |  | ||||||
|   return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { |  | ||||||
|   int c =  (nelems - 1)/LFIELDS_PER_FLUSH + 1; |  | ||||||
|   int b = (tostore == LUA_MULTRET) ? 0 : tostore; |  | ||||||
|   lua_assert(tostore != 0); |  | ||||||
|   if (c <= MAXARG_C) |  | ||||||
|     luaK_codeABC(fs, OP_SETLIST, base, b, c); |  | ||||||
|   else { |  | ||||||
|     luaK_codeABC(fs, OP_SETLIST, base, b, 0); |  | ||||||
|     luaK_code(fs, cast(Instruction, c), fs->ls->lastline); |  | ||||||
|   } |  | ||||||
|   fs->freereg = base + 1;  /* free registers with list values */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,77 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lcode.h,v 1.47 2005/11/08 19:44:31 roberto Exp $ |  | ||||||
| ** Code generator for Lua |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef lcode_h |  | ||||||
| #define lcode_h |  | ||||||
|  |  | ||||||
| #include "llex.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lopcodes.h" |  | ||||||
| #include "lparser.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Marks the end of a patch list. It is an invalid value both as an absolute |  | ||||||
| ** address, and as a list link (would link an element to itself). |  | ||||||
| */ |  | ||||||
| #define NO_JUMP (-1) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** grep "ORDER OPR" if you change these enums |  | ||||||
| */ |  | ||||||
| typedef enum BinOpr { |  | ||||||
|   OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, |  | ||||||
|   OPR_CONCAT, |  | ||||||
|   OPR_NE, OPR_EQ, |  | ||||||
|   OPR_LT, OPR_LE, OPR_GT, OPR_GE, |  | ||||||
|   OPR_AND, OPR_OR, |  | ||||||
|   OPR_NOBINOPR |  | ||||||
| } BinOpr; |  | ||||||
|  |  | ||||||
| #define binopistest(op)	((op) >= OPR_NE) |  | ||||||
|  |  | ||||||
| typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define getcode(fs,e)	((fs)->f->code[(e)->u.s.info]) |  | ||||||
|  |  | ||||||
| #define luaK_codeAsBx(fs,o,A,sBx)	luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) |  | ||||||
|  |  | ||||||
| #define luaK_setmultret(fs,e)	luaK_setreturns(fs, e, LUA_MULTRET) |  | ||||||
|  |  | ||||||
| LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); |  | ||||||
| LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); |  | ||||||
| LUAI_FUNC void luaK_fixline (FuncState *fs, int line); |  | ||||||
| LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); |  | ||||||
| LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); |  | ||||||
| LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); |  | ||||||
| LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); |  | ||||||
| LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r); |  | ||||||
| LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); |  | ||||||
| LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); |  | ||||||
| LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); |  | ||||||
| LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); |  | ||||||
| LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); |  | ||||||
| LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); |  | ||||||
| LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); |  | ||||||
| LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); |  | ||||||
| LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); |  | ||||||
| LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); |  | ||||||
| LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); |  | ||||||
| LUAI_FUNC int luaK_jump (FuncState *fs); |  | ||||||
| LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); |  | ||||||
| LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); |  | ||||||
| LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); |  | ||||||
| LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); |  | ||||||
| LUAI_FUNC int luaK_getlabel (FuncState *fs); |  | ||||||
| LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v); |  | ||||||
| LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); |  | ||||||
| LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2); |  | ||||||
| LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
							
								
								
									
										397
									
								
								src/lua/ldblib.c
									
									
									
									
									
								
							
							
						
						
									
										397
									
								
								src/lua/ldblib.c
									
									
									
									
									
								
							| @@ -1,397 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: ldblib.c,v 1.104 2005/12/29 15:32:11 roberto Exp $ |  | ||||||
| ** Interface from Lua to its debug API |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define ldblib_c |  | ||||||
| #define LUA_LIB |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lauxlib.h" |  | ||||||
| #include "lualib.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int db_getregistry (lua_State *L) { |  | ||||||
|   lua_pushvalue(L, LUA_REGISTRYINDEX); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int db_getmetatable (lua_State *L) { |  | ||||||
|   luaL_checkany(L, 1); |  | ||||||
|   if (!lua_getmetatable(L, 1)) { |  | ||||||
|     lua_pushnil(L);  /* no metatable */ |  | ||||||
|   } |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int db_setmetatable (lua_State *L) { |  | ||||||
|   int t = lua_type(L, 2); |  | ||||||
|   luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, |  | ||||||
|                     "nil or table expected"); |  | ||||||
|   lua_settop(L, 2); |  | ||||||
|   lua_pushboolean(L, lua_setmetatable(L, 1)); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int db_getfenv (lua_State *L) { |  | ||||||
|   lua_getfenv(L, 1); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int db_setfenv (lua_State *L) { |  | ||||||
|   luaL_checktype(L, 2, LUA_TTABLE); |  | ||||||
|   lua_settop(L, 2); |  | ||||||
|   if (lua_setfenv(L, 1) == 0) |  | ||||||
|     luaL_error(L, LUA_QL("setfenv") |  | ||||||
|                   " cannot change environment of given object"); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void settabss (lua_State *L, const char *i, const char *v) { |  | ||||||
|   lua_pushstring(L, v); |  | ||||||
|   lua_setfield(L, -2, i); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void settabsi (lua_State *L, const char *i, int v) { |  | ||||||
|   lua_pushinteger(L, v); |  | ||||||
|   lua_setfield(L, -2, i); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static lua_State *getthread (lua_State *L, int *arg) { |  | ||||||
|   if (lua_isthread(L, 1)) { |  | ||||||
|     *arg = 1; |  | ||||||
|     return lua_tothread(L, 1); |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     *arg = 0; |  | ||||||
|     return L; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { |  | ||||||
|   if (L == L1) { |  | ||||||
|     lua_pushvalue(L, -2); |  | ||||||
|     lua_remove(L, -3); |  | ||||||
|   } |  | ||||||
|   else |  | ||||||
|     lua_xmove(L1, L, 1); |  | ||||||
|   lua_setfield(L, -2, fname); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int db_getinfo (lua_State *L) { |  | ||||||
|   lua_Debug ar; |  | ||||||
|   int arg; |  | ||||||
|   lua_State *L1 = getthread(L, &arg); |  | ||||||
|   const char *options = luaL_optstring(L, arg+2, "flnSu"); |  | ||||||
|   if (lua_isnumber(L, arg+1)) { |  | ||||||
|     if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { |  | ||||||
|       lua_pushnil(L);  /* level out of range */ |  | ||||||
|       return 1; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   else if (lua_isfunction(L, arg+1)) { |  | ||||||
|     lua_pushfstring(L, ">%s", options); |  | ||||||
|     options = lua_tostring(L, -1); |  | ||||||
|     lua_pushvalue(L, arg+1); |  | ||||||
|     lua_xmove(L, L1, 1); |  | ||||||
|   } |  | ||||||
|   else |  | ||||||
|     return luaL_argerror(L, arg+1, "function or level expected"); |  | ||||||
|   if (!lua_getinfo(L1, options, &ar)) |  | ||||||
|     return luaL_argerror(L, arg+2, "invalid option"); |  | ||||||
|   lua_createtable(L, 0, 2); |  | ||||||
|   if (strchr(options, 'S')) { |  | ||||||
|     settabss(L, "source", ar.source); |  | ||||||
|     settabss(L, "short_src", ar.short_src); |  | ||||||
|     settabsi(L, "linedefined", ar.linedefined); |  | ||||||
|     settabsi(L, "lastlinedefined", ar.lastlinedefined); |  | ||||||
|     settabss(L, "what", ar.what); |  | ||||||
|   } |  | ||||||
|   if (strchr(options, 'l')) |  | ||||||
|     settabsi(L, "currentline", ar.currentline); |  | ||||||
|   if (strchr(options, 'u')) |  | ||||||
|     settabsi(L, "nups", ar.nups); |  | ||||||
|   if (strchr(options, 'n')) { |  | ||||||
|     settabss(L, "name", ar.name); |  | ||||||
|     settabss(L, "namewhat", ar.namewhat); |  | ||||||
|   } |  | ||||||
|   if (strchr(options, 'L')) |  | ||||||
|     treatstackoption(L, L1, "activelines"); |  | ||||||
|   if (strchr(options, 'f')) |  | ||||||
|     treatstackoption(L, L1, "func"); |  | ||||||
|   return 1;  /* return table */ |  | ||||||
| } |  | ||||||
|      |  | ||||||
|  |  | ||||||
| static int db_getlocal (lua_State *L) { |  | ||||||
|   int arg; |  | ||||||
|   lua_State *L1 = getthread(L, &arg); |  | ||||||
|   lua_Debug ar; |  | ||||||
|   const char *name; |  | ||||||
|   if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar))  /* out of range? */ |  | ||||||
|     return luaL_argerror(L, arg+1, "level out of range"); |  | ||||||
|   name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2)); |  | ||||||
|   if (name) { |  | ||||||
|     lua_xmove(L1, L, 1); |  | ||||||
|     lua_pushstring(L, name); |  | ||||||
|     lua_pushvalue(L, -2); |  | ||||||
|     return 2; |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     lua_pushnil(L); |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int db_setlocal (lua_State *L) { |  | ||||||
|   int arg; |  | ||||||
|   lua_State *L1 = getthread(L, &arg); |  | ||||||
|   lua_Debug ar; |  | ||||||
|   if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar))  /* out of range? */ |  | ||||||
|     return luaL_argerror(L, arg+1, "level out of range"); |  | ||||||
|   luaL_checkany(L, arg+3); |  | ||||||
|   lua_settop(L, arg+3); |  | ||||||
|   lua_xmove(L, L1, 1); |  | ||||||
|   lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int auxupvalue (lua_State *L, int get) { |  | ||||||
|   const char *name; |  | ||||||
|   int n = luaL_checkint(L, 2); |  | ||||||
|   luaL_checktype(L, 1, LUA_TFUNCTION); |  | ||||||
|   if (lua_iscfunction(L, 1)) return 0;  /* cannot touch C upvalues from Lua */ |  | ||||||
|   name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); |  | ||||||
|   if (name == NULL) return 0; |  | ||||||
|   lua_pushstring(L, name); |  | ||||||
|   lua_insert(L, -(get+1)); |  | ||||||
|   return get + 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int db_getupvalue (lua_State *L) { |  | ||||||
|   return auxupvalue(L, 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int db_setupvalue (lua_State *L) { |  | ||||||
|   luaL_checkany(L, 3); |  | ||||||
|   return auxupvalue(L, 0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char KEY_HOOK = 'h'; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void hookf (lua_State *L, lua_Debug *ar) { |  | ||||||
|   static const char *const hooknames[] = |  | ||||||
|     {"call", "return", "line", "count", "tail return"}; |  | ||||||
|   lua_pushlightuserdata(L, (void *)&KEY_HOOK); |  | ||||||
|   lua_rawget(L, LUA_REGISTRYINDEX); |  | ||||||
|   lua_pushlightuserdata(L, L); |  | ||||||
|   lua_rawget(L, -2); |  | ||||||
|   if (lua_isfunction(L, -1)) { |  | ||||||
|     lua_pushstring(L, hooknames[(int)ar->event]); |  | ||||||
|     if (ar->currentline >= 0) |  | ||||||
|       lua_pushinteger(L, ar->currentline); |  | ||||||
|     else lua_pushnil(L); |  | ||||||
|     lua_assert(lua_getinfo(L, "lS", ar)); |  | ||||||
|     lua_call(L, 2, 0); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int makemask (const char *smask, int count) { |  | ||||||
|   int mask = 0; |  | ||||||
|   if (strchr(smask, 'c')) mask |= LUA_MASKCALL; |  | ||||||
|   if (strchr(smask, 'r')) mask |= LUA_MASKRET; |  | ||||||
|   if (strchr(smask, 'l')) mask |= LUA_MASKLINE; |  | ||||||
|   if (count > 0) mask |= LUA_MASKCOUNT; |  | ||||||
|   return mask; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static char *unmakemask (int mask, char *smask) { |  | ||||||
|   int i = 0; |  | ||||||
|   if (mask & LUA_MASKCALL) smask[i++] = 'c'; |  | ||||||
|   if (mask & LUA_MASKRET) smask[i++] = 'r'; |  | ||||||
|   if (mask & LUA_MASKLINE) smask[i++] = 'l'; |  | ||||||
|   smask[i] = '\0'; |  | ||||||
|   return smask; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void gethooktable (lua_State *L) { |  | ||||||
|   lua_pushlightuserdata(L, (void *)&KEY_HOOK); |  | ||||||
|   lua_rawget(L, LUA_REGISTRYINDEX); |  | ||||||
|   if (!lua_istable(L, -1)) { |  | ||||||
|     lua_pop(L, 1); |  | ||||||
|     lua_createtable(L, 0, 1); |  | ||||||
|     lua_pushlightuserdata(L, (void *)&KEY_HOOK); |  | ||||||
|     lua_pushvalue(L, -2); |  | ||||||
|     lua_rawset(L, LUA_REGISTRYINDEX); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int db_sethook (lua_State *L) { |  | ||||||
|   int arg; |  | ||||||
|   lua_State *L1 = getthread(L, &arg); |  | ||||||
|   if (lua_isnoneornil(L, arg+1)) { |  | ||||||
|     lua_settop(L, arg+1); |  | ||||||
|     lua_sethook(L1, NULL, 0, 0);  /* turn off hooks */ |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     const char *smask = luaL_checkstring(L, arg+2); |  | ||||||
|     int count = luaL_optint(L, arg+3, 0); |  | ||||||
|     luaL_checktype(L, arg+1, LUA_TFUNCTION); |  | ||||||
|     lua_sethook(L1, hookf, makemask(smask, count), count); |  | ||||||
|   } |  | ||||||
|   gethooktable(L1); |  | ||||||
|   lua_pushlightuserdata(L1, L1); |  | ||||||
|   lua_pushvalue(L, arg+1); |  | ||||||
|   lua_xmove(L, L1, 1); |  | ||||||
|   lua_rawset(L1, -3);  /* set new hook */ |  | ||||||
|   lua_pop(L1, 1);  /* remove hook table */ |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int db_gethook (lua_State *L) { |  | ||||||
|   int arg; |  | ||||||
|   lua_State *L1 = getthread(L, &arg); |  | ||||||
|   char buff[5]; |  | ||||||
|   int mask = lua_gethookmask(L1); |  | ||||||
|   lua_Hook hook = lua_gethook(L1); |  | ||||||
|   if (hook != NULL && hook != hookf)  /* external hook? */ |  | ||||||
|     lua_pushliteral(L, "external hook"); |  | ||||||
|   else { |  | ||||||
|     gethooktable(L1); |  | ||||||
|     lua_pushlightuserdata(L1, L1); |  | ||||||
|     lua_rawget(L1, -2);   /* get hook */ |  | ||||||
|     lua_remove(L1, -2);  /* remove hook table */ |  | ||||||
|     lua_xmove(L1, L, 1); |  | ||||||
|   } |  | ||||||
|   lua_pushstring(L, unmakemask(mask, buff)); |  | ||||||
|   lua_pushinteger(L, lua_gethookcount(L1)); |  | ||||||
|   return 3; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int db_debug (lua_State *L) { |  | ||||||
|   for (;;) { |  | ||||||
|     char buffer[250]; |  | ||||||
|     fputs("lua_debug> ", stderr); |  | ||||||
|     if (fgets(buffer, sizeof(buffer), stdin) == 0 || |  | ||||||
|         strcmp(buffer, "cont\n") == 0) |  | ||||||
|       return 0; |  | ||||||
|     if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || |  | ||||||
|         lua_pcall(L, 0, 0, 0)) { |  | ||||||
|       fputs(lua_tostring(L, -1), stderr); |  | ||||||
|       fputs("\n", stderr); |  | ||||||
|     } |  | ||||||
|     lua_settop(L, 0);  /* remove eventual returns */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define LEVELS1	12	/* size of the first part of the stack */ |  | ||||||
| #define LEVELS2	10	/* size of the second part of the stack */ |  | ||||||
|  |  | ||||||
| static int db_errorfb (lua_State *L) { |  | ||||||
|   int level; |  | ||||||
|   int firstpart = 1;  /* still before eventual `...' */ |  | ||||||
|   int arg; |  | ||||||
|   lua_State *L1 = getthread(L, &arg); |  | ||||||
|   lua_Debug ar; |  | ||||||
|   if (lua_isnumber(L, arg+2)) { |  | ||||||
|     level = (int)lua_tointeger(L, arg+2); |  | ||||||
|     lua_pop(L, 1); |  | ||||||
|   } |  | ||||||
|   else |  | ||||||
|     level = (L == L1) ? 1 : 0;  /* level 0 may be this own function */ |  | ||||||
|   if (lua_gettop(L) == arg) |  | ||||||
|     lua_pushliteral(L, ""); |  | ||||||
|   else if (!lua_isstring(L, arg+1)) return 1;  /* message is not a string */ |  | ||||||
|   else lua_pushliteral(L, "\n"); |  | ||||||
|   lua_pushliteral(L, "stack traceback:"); |  | ||||||
|   while (lua_getstack(L1, level++, &ar)) { |  | ||||||
|     if (level > LEVELS1 && firstpart) { |  | ||||||
|       /* no more than `LEVELS2' more levels? */ |  | ||||||
|       if (!lua_getstack(L1, level+LEVELS2, &ar)) |  | ||||||
|         level--;  /* keep going */ |  | ||||||
|       else { |  | ||||||
|         lua_pushliteral(L, "\n\t...");  /* too many levels */ |  | ||||||
|         while (lua_getstack(L1, level+LEVELS2, &ar))  /* find last levels */ |  | ||||||
|           level++; |  | ||||||
|       } |  | ||||||
|       firstpart = 0; |  | ||||||
|       continue; |  | ||||||
|     } |  | ||||||
|     lua_pushliteral(L, "\n\t"); |  | ||||||
|     lua_getinfo(L1, "Snl", &ar); |  | ||||||
|     lua_pushfstring(L, "%s:", ar.short_src); |  | ||||||
|     if (ar.currentline > 0) |  | ||||||
|       lua_pushfstring(L, "%d:", ar.currentline); |  | ||||||
|     if (*ar.namewhat != '\0')  /* is there a name? */ |  | ||||||
|         lua_pushfstring(L, " in function " LUA_QS, ar.name); |  | ||||||
|     else { |  | ||||||
|       if (*ar.what == 'm')  /* main? */ |  | ||||||
|         lua_pushfstring(L, " in main chunk"); |  | ||||||
|       else if (*ar.what == 'C' || *ar.what == 't') |  | ||||||
|         lua_pushliteral(L, " ?");  /* C function or tail call */ |  | ||||||
|       else |  | ||||||
|         lua_pushfstring(L, " in function <%s:%d>", |  | ||||||
|                            ar.short_src, ar.linedefined); |  | ||||||
|     } |  | ||||||
|     lua_concat(L, lua_gettop(L) - arg); |  | ||||||
|   } |  | ||||||
|   lua_concat(L, lua_gettop(L) - arg); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const luaL_Reg dblib[] = { |  | ||||||
|   {"debug", db_debug}, |  | ||||||
|   {"getfenv", db_getfenv}, |  | ||||||
|   {"gethook", db_gethook}, |  | ||||||
|   {"getinfo", db_getinfo}, |  | ||||||
|   {"getlocal", db_getlocal}, |  | ||||||
|   {"getregistry", db_getregistry}, |  | ||||||
|   {"getmetatable", db_getmetatable}, |  | ||||||
|   {"getupvalue", db_getupvalue}, |  | ||||||
|   {"setfenv", db_setfenv}, |  | ||||||
|   {"sethook", db_sethook}, |  | ||||||
|   {"setlocal", db_setlocal}, |  | ||||||
|   {"setmetatable", db_setmetatable}, |  | ||||||
|   {"setupvalue", db_setupvalue}, |  | ||||||
|   {"traceback", db_errorfb}, |  | ||||||
|   {NULL, NULL} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaopen_debug (lua_State *L) { |  | ||||||
|   luaL_register(L, LUA_DBLIBNAME, dblib); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										620
									
								
								src/lua/ldebug.c
									
									
									
									
									
								
							
							
						
						
									
										620
									
								
								src/lua/ldebug.c
									
									
									
									
									
								
							| @@ -1,620 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: ldebug.c,v 2.29 2005/12/22 16:19:56 roberto Exp $ |  | ||||||
| ** Debug Interface |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <stdarg.h> |  | ||||||
| #include <stddef.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define ldebug_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lapi.h" |  | ||||||
| #include "lcode.h" |  | ||||||
| #include "ldebug.h" |  | ||||||
| #include "ldo.h" |  | ||||||
| #include "lfunc.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lopcodes.h" |  | ||||||
| #include "lstate.h" |  | ||||||
| #include "lstring.h" |  | ||||||
| #include "ltable.h" |  | ||||||
| #include "ltm.h" |  | ||||||
| #include "lvm.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int currentpc (lua_State *L, CallInfo *ci) { |  | ||||||
|   if (!isLua(ci)) return -1;  /* function is not a Lua function? */ |  | ||||||
|   if (ci == L->ci) |  | ||||||
|     ci->savedpc = L->savedpc; |  | ||||||
|   return pcRel(ci->savedpc, ci_func(ci)->l.p); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int currentline (lua_State *L, CallInfo *ci) { |  | ||||||
|   int pc = currentpc(L, ci); |  | ||||||
|   if (pc < 0) |  | ||||||
|     return -1;  /* only active lua functions have current-line information */ |  | ||||||
|   else |  | ||||||
|     return getline(ci_func(ci)->l.p, pc); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** this function can be called asynchronous (e.g. during a signal) |  | ||||||
| */ |  | ||||||
| LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { |  | ||||||
|   if (func == NULL || mask == 0) {  /* turn off hooks? */ |  | ||||||
|     mask = 0; |  | ||||||
|     func = NULL; |  | ||||||
|   } |  | ||||||
|   L->hook = func; |  | ||||||
|   L->basehookcount = count; |  | ||||||
|   resethookcount(L); |  | ||||||
|   L->hookmask = cast_byte(mask); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUA_API lua_Hook lua_gethook (lua_State *L) { |  | ||||||
|   return L->hook; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUA_API int lua_gethookmask (lua_State *L) { |  | ||||||
|   return L->hookmask; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUA_API int lua_gethookcount (lua_State *L) { |  | ||||||
|   return L->basehookcount; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { |  | ||||||
|   int status; |  | ||||||
|   CallInfo *ci; |  | ||||||
|   lua_lock(L); |  | ||||||
|   for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { |  | ||||||
|     level--; |  | ||||||
|     if (f_isLua(ci))  /* Lua function? */ |  | ||||||
|       level -= ci->tailcalls;  /* skip lost tail calls */ |  | ||||||
|   } |  | ||||||
|   if (level == 0 && ci > L->base_ci) {  /* level found? */ |  | ||||||
|     status = 1; |  | ||||||
|     ar->i_ci = cast_int(ci - L->base_ci); |  | ||||||
|   } |  | ||||||
|   else if (level < 0) {  /* level is of a lost tail call? */ |  | ||||||
|     status = 1; |  | ||||||
|     ar->i_ci = 0; |  | ||||||
|   } |  | ||||||
|   else status = 0;  /* no such level */ |  | ||||||
|   lua_unlock(L); |  | ||||||
|   return status; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static Proto *getluaproto (CallInfo *ci) { |  | ||||||
|   return (isLua(ci) ? ci_func(ci)->l.p : NULL); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *findlocal (lua_State *L, CallInfo *ci, int n) { |  | ||||||
|   const char *name; |  | ||||||
|   Proto *fp = getluaproto(ci); |  | ||||||
|   if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL) |  | ||||||
|     return name;  /* is a local variable in a Lua function */ |  | ||||||
|   else { |  | ||||||
|     StkId limit = (ci == L->ci) ? L->top : (ci+1)->func; |  | ||||||
|     if (limit - ci->base >= n && n > 0)  /* is 'n' inside 'ci' stack? */ |  | ||||||
|       return "(*temporary)"; |  | ||||||
|     else |  | ||||||
|       return NULL; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { |  | ||||||
|   CallInfo *ci = L->base_ci + ar->i_ci; |  | ||||||
|   const char *name = findlocal(L, ci, n); |  | ||||||
|   lua_lock(L); |  | ||||||
|   if (name) |  | ||||||
|       luaA_pushobject(L, ci->base + (n - 1)); |  | ||||||
|   lua_unlock(L); |  | ||||||
|   return name; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { |  | ||||||
|   CallInfo *ci = L->base_ci + ar->i_ci; |  | ||||||
|   const char *name = findlocal(L, ci, n); |  | ||||||
|   lua_lock(L); |  | ||||||
|   if (name) |  | ||||||
|       setobjs2s(L, ci->base + (n - 1), L->top - 1); |  | ||||||
|   L->top--;  /* pop value */ |  | ||||||
|   lua_unlock(L); |  | ||||||
|   return name; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void funcinfo (lua_Debug *ar, Closure *cl) { |  | ||||||
|   if (cl->c.isC) { |  | ||||||
|     ar->source = "=[C]"; |  | ||||||
|     ar->linedefined = -1; |  | ||||||
|     ar->lastlinedefined = -1; |  | ||||||
|     ar->what = "C"; |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     ar->source = getstr(cl->l.p->source); |  | ||||||
|     ar->linedefined = cl->l.p->linedefined; |  | ||||||
|     ar->lastlinedefined = cl->l.p->lastlinedefined; |  | ||||||
|     ar->what = (ar->linedefined == 0) ? "main" : "Lua"; |  | ||||||
|   } |  | ||||||
|   luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void info_tailcall (lua_Debug *ar) { |  | ||||||
|   ar->name = ar->namewhat = ""; |  | ||||||
|   ar->what = "tail"; |  | ||||||
|   ar->lastlinedefined = ar->linedefined = ar->currentline = -1; |  | ||||||
|   ar->source = "=(tail call)"; |  | ||||||
|   luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); |  | ||||||
|   ar->nups = 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void collectvalidlines (lua_State *L, Closure *f) { |  | ||||||
|   if (f == NULL || f->c.isC) { |  | ||||||
|     setnilvalue(L->top); |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     Table *t = luaH_new(L, 0, 0); |  | ||||||
|     int *lineinfo = f->l.p->lineinfo; |  | ||||||
|     int i; |  | ||||||
|     for (i=0; i<f->l.p->sizelineinfo; i++) |  | ||||||
|       setbvalue(luaH_setnum(L, t, lineinfo[i]), 1); |  | ||||||
|     sethvalue(L, L->top, t);  |  | ||||||
|   } |  | ||||||
|   incr_top(L); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, |  | ||||||
|                     Closure *f, CallInfo *ci) { |  | ||||||
|   int status = 1; |  | ||||||
|   if (f == NULL) { |  | ||||||
|     info_tailcall(ar); |  | ||||||
|     return status; |  | ||||||
|   } |  | ||||||
|   for (; *what; what++) { |  | ||||||
|     switch (*what) { |  | ||||||
|       case 'S': { |  | ||||||
|         funcinfo(ar, f); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case 'l': { |  | ||||||
|         ar->currentline = (ci) ? currentline(L, ci) : -1; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case 'u': { |  | ||||||
|         ar->nups = f->c.nupvalues; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case 'n': { |  | ||||||
|         ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL; |  | ||||||
|         if (ar->namewhat == NULL) { |  | ||||||
|           ar->namewhat = "";  /* not found */ |  | ||||||
|           ar->name = NULL; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case 'L': |  | ||||||
|       case 'f':  /* handled by lua_getinfo */ |  | ||||||
|         break; |  | ||||||
|       default: status = 0;  /* invalid option */ |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return status; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { |  | ||||||
|   int status; |  | ||||||
|   Closure *f = NULL; |  | ||||||
|   CallInfo *ci = NULL; |  | ||||||
|   lua_lock(L); |  | ||||||
|   if (*what == '>') { |  | ||||||
|     StkId func = L->top - 1; |  | ||||||
|     luai_apicheck(L, ttisfunction(func)); |  | ||||||
|     what++;  /* skip the '>' */ |  | ||||||
|     f = clvalue(func); |  | ||||||
|     L->top--;  /* pop function */ |  | ||||||
|   } |  | ||||||
|   else if (ar->i_ci != 0) {  /* no tail call? */ |  | ||||||
|     ci = L->base_ci + ar->i_ci; |  | ||||||
|     lua_assert(ttisfunction(ci->func)); |  | ||||||
|     f = clvalue(ci->func); |  | ||||||
|   } |  | ||||||
|   status = auxgetinfo(L, what, ar, f, ci); |  | ||||||
|   if (strchr(what, 'f')) { |  | ||||||
|     if (f == NULL) setnilvalue(L->top); |  | ||||||
|     else setclvalue(L, L->top, f); |  | ||||||
|     incr_top(L); |  | ||||||
|   } |  | ||||||
|   if (strchr(what, 'L')) |  | ||||||
|     collectvalidlines(L, f); |  | ||||||
|   lua_unlock(L); |  | ||||||
|   return status; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** Symbolic Execution and code checker |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #define check(x)		if (!(x)) return 0; |  | ||||||
|  |  | ||||||
| #define checkjump(pt,pc)	check(0 <= pc && pc < pt->sizecode) |  | ||||||
|  |  | ||||||
| #define checkreg(pt,reg)	check((reg) < (pt)->maxstacksize) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int precheck (const Proto *pt) { |  | ||||||
|   check(pt->maxstacksize <= MAXSTACK); |  | ||||||
|   lua_assert(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); |  | ||||||
|   lua_assert(!(pt->is_vararg & VARARG_NEEDSARG) || |  | ||||||
|               (pt->is_vararg & VARARG_HASARG)); |  | ||||||
|   check(pt->sizeupvalues <= pt->nups); |  | ||||||
|   check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); |  | ||||||
|   check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define checkopenop(pt,pc)	luaG_checkopenop((pt)->code[(pc)+1]) |  | ||||||
|  |  | ||||||
| int luaG_checkopenop (Instruction i) { |  | ||||||
|   switch (GET_OPCODE(i)) { |  | ||||||
|     case OP_CALL: |  | ||||||
|     case OP_TAILCALL: |  | ||||||
|     case OP_RETURN: |  | ||||||
|     case OP_SETLIST: { |  | ||||||
|       check(GETARG_B(i) == 0); |  | ||||||
|       return 1; |  | ||||||
|     } |  | ||||||
|     default: return 0;  /* invalid instruction after an open call */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { |  | ||||||
|   switch (mode) { |  | ||||||
|     case OpArgN: check(r == 0); break; |  | ||||||
|     case OpArgU: break; |  | ||||||
|     case OpArgR: checkreg(pt, r); break; |  | ||||||
|     case OpArgK: |  | ||||||
|       check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize); |  | ||||||
|       break; |  | ||||||
|   } |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static Instruction symbexec (const Proto *pt, int lastpc, int reg) { |  | ||||||
|   int pc; |  | ||||||
|   int last;  /* stores position of last instruction that changed `reg' */ |  | ||||||
|   last = pt->sizecode-1;  /* points to final return (a `neutral' instruction) */ |  | ||||||
|   check(precheck(pt)); |  | ||||||
|   for (pc = 0; pc < lastpc; pc++) { |  | ||||||
|     Instruction i = pt->code[pc]; |  | ||||||
|     OpCode op = GET_OPCODE(i); |  | ||||||
|     int a = GETARG_A(i); |  | ||||||
|     int b = 0; |  | ||||||
|     int c = 0; |  | ||||||
|     check(op < NUM_OPCODES); |  | ||||||
|     checkreg(pt, a); |  | ||||||
|     switch (getOpMode(op)) { |  | ||||||
|       case iABC: { |  | ||||||
|         b = GETARG_B(i); |  | ||||||
|         c = GETARG_C(i); |  | ||||||
|         check(checkArgMode(pt, b, getBMode(op))); |  | ||||||
|         check(checkArgMode(pt, c, getCMode(op))); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case iABx: { |  | ||||||
|         b = GETARG_Bx(i); |  | ||||||
|         if (getBMode(op) == OpArgK) check(b < pt->sizek); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case iAsBx: { |  | ||||||
|         b = GETARG_sBx(i); |  | ||||||
|         if (getBMode(op) == OpArgR) { |  | ||||||
|           int dest = pc+1+b; |  | ||||||
|           check(0 <= dest && dest < pt->sizecode); |  | ||||||
|           if (dest > 0) { |  | ||||||
|             /* cannot jump to a setlist count */ |  | ||||||
|             Instruction d = pt->code[dest-1]; |  | ||||||
|             check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     if (testAMode(op)) { |  | ||||||
|       if (a == reg) last = pc;  /* change register `a' */ |  | ||||||
|     } |  | ||||||
|     if (testTMode(op)) { |  | ||||||
|       check(pc+2 < pt->sizecode);  /* check skip */ |  | ||||||
|       check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); |  | ||||||
|     } |  | ||||||
|     switch (op) { |  | ||||||
|       case OP_LOADBOOL: { |  | ||||||
|         check(c == 0 || pc+2 < pt->sizecode);  /* check its jump */ |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case OP_LOADNIL: { |  | ||||||
|         if (a <= reg && reg <= b) |  | ||||||
|           last = pc;  /* set registers from `a' to `b' */ |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case OP_GETUPVAL: |  | ||||||
|       case OP_SETUPVAL: { |  | ||||||
|         check(b < pt->nups); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case OP_GETGLOBAL: |  | ||||||
|       case OP_SETGLOBAL: { |  | ||||||
|         check(ttisstring(&pt->k[b])); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case OP_SELF: { |  | ||||||
|         checkreg(pt, a+1); |  | ||||||
|         if (reg == a+1) last = pc; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case OP_CONCAT: { |  | ||||||
|         check(b < c);  /* at least two operands */ |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case OP_TFORLOOP: { |  | ||||||
|         check(c >= 1);  /* at least one result (control variable) */ |  | ||||||
|         checkreg(pt, a+2+c);  /* space for results */ |  | ||||||
|         if (reg >= a+2) last = pc;  /* affect all regs above its base */ |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case OP_FORLOOP: |  | ||||||
|       case OP_FORPREP: |  | ||||||
|         checkreg(pt, a+3); |  | ||||||
|         /* go through */ |  | ||||||
|       case OP_JMP: { |  | ||||||
|         int dest = pc+1+b; |  | ||||||
|         /* not full check and jump is forward and do not skip `lastpc'? */ |  | ||||||
|         if (reg != NO_REG && pc < dest && dest <= lastpc) |  | ||||||
|           pc += b;  /* do the jump */ |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case OP_CALL: |  | ||||||
|       case OP_TAILCALL: { |  | ||||||
|         if (b != 0) { |  | ||||||
|           checkreg(pt, a+b-1); |  | ||||||
|         } |  | ||||||
|         c--;  /* c = num. returns */ |  | ||||||
|         if (c == LUA_MULTRET) { |  | ||||||
|           check(checkopenop(pt, pc)); |  | ||||||
|         } |  | ||||||
|         else if (c != 0) |  | ||||||
|           checkreg(pt, a+c-1); |  | ||||||
|         if (reg >= a) last = pc;  /* affect all registers above base */ |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case OP_RETURN: { |  | ||||||
|         b--;  /* b = num. returns */ |  | ||||||
|         if (b > 0) checkreg(pt, a+b-1); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case OP_SETLIST: { |  | ||||||
|         if (b > 0) checkreg(pt, a + b); |  | ||||||
|         if (c == 0) pc++; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case OP_CLOSURE: { |  | ||||||
|         int nup; |  | ||||||
|         check(b < pt->sizep); |  | ||||||
|         nup = pt->p[b]->nups; |  | ||||||
|         check(pc + nup < pt->sizecode); |  | ||||||
|         for (; nup>0; nup--) { |  | ||||||
|           OpCode op1 = GET_OPCODE(pt->code[pc+nup]); |  | ||||||
|           check(op1 == OP_GETUPVAL || op1 == OP_MOVE); |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case OP_VARARG: { |  | ||||||
|         check((pt->is_vararg & VARARG_ISVARARG) && |  | ||||||
|              !(pt->is_vararg & VARARG_NEEDSARG)); |  | ||||||
|         b--; |  | ||||||
|         if (b == LUA_MULTRET) check(checkopenop(pt, pc)); |  | ||||||
|         checkreg(pt, a+b-1); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       default: break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return pt->code[last]; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #undef check |  | ||||||
| #undef checkjump |  | ||||||
| #undef checkreg |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaG_checkcode (const Proto *pt) { |  | ||||||
|   return (symbexec(pt, pt->sizecode, NO_REG) != 0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *kname (Proto *p, int c) { |  | ||||||
|   if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) |  | ||||||
|     return svalue(&p->k[INDEXK(c)]); |  | ||||||
|   else |  | ||||||
|     return "?"; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos, |  | ||||||
|                                const char **name) { |  | ||||||
|   if (isLua(ci)) {  /* a Lua function? */ |  | ||||||
|     Proto *p = ci_func(ci)->l.p; |  | ||||||
|     int pc = currentpc(L, ci); |  | ||||||
|     Instruction i; |  | ||||||
|     *name = luaF_getlocalname(p, stackpos+1, pc); |  | ||||||
|     if (*name)  /* is a local? */ |  | ||||||
|       return "local"; |  | ||||||
|     i = symbexec(p, pc, stackpos);  /* try symbolic execution */ |  | ||||||
|     lua_assert(pc != -1); |  | ||||||
|     switch (GET_OPCODE(i)) { |  | ||||||
|       case OP_GETGLOBAL: { |  | ||||||
|         int g = GETARG_Bx(i);  /* global index */ |  | ||||||
|         lua_assert(ttisstring(&p->k[g])); |  | ||||||
|         *name = svalue(&p->k[g]); |  | ||||||
|         return "global"; |  | ||||||
|       } |  | ||||||
|       case OP_MOVE: { |  | ||||||
|         int a = GETARG_A(i); |  | ||||||
|         int b = GETARG_B(i);  /* move from `b' to `a' */ |  | ||||||
|         if (b < a) |  | ||||||
|           return getobjname(L, ci, b, name);  /* get name for `b' */ |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case OP_GETTABLE: { |  | ||||||
|         int k = GETARG_C(i);  /* key index */ |  | ||||||
|         *name = kname(p, k); |  | ||||||
|         return "field"; |  | ||||||
|       } |  | ||||||
|       case OP_GETUPVAL: { |  | ||||||
|         int u = GETARG_B(i);  /* upvalue index */ |  | ||||||
|         *name = p->upvalues ? getstr(p->upvalues[u]) : "?"; |  | ||||||
|         return "upvalue"; |  | ||||||
|       } |  | ||||||
|       case OP_SELF: { |  | ||||||
|         int k = GETARG_C(i);  /* key index */ |  | ||||||
|         *name = kname(p, k); |  | ||||||
|         return "method"; |  | ||||||
|       } |  | ||||||
|       default: break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return NULL;  /* no useful name found */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { |  | ||||||
|   Instruction i; |  | ||||||
|   if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1)) |  | ||||||
|     return NULL;  /* calling function is not Lua (or is unknown) */ |  | ||||||
|   ci--;  /* calling function */ |  | ||||||
|   i = ci_func(ci)->l.p->code[currentpc(L, ci)]; |  | ||||||
|   if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || |  | ||||||
|       GET_OPCODE(i) == OP_TFORLOOP) |  | ||||||
|     return getobjname(L, ci, GETARG_A(i), name); |  | ||||||
|   else |  | ||||||
|     return NULL;  /* no useful name can be found */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* only ANSI way to check whether a pointer points to an array */ |  | ||||||
| static int isinstack (CallInfo *ci, const TValue *o) { |  | ||||||
|   StkId p; |  | ||||||
|   for (p = ci->base; p < ci->top; p++) |  | ||||||
|     if (o == p) return 1; |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { |  | ||||||
|   const char *name = NULL; |  | ||||||
|   const char *t = luaT_typenames[ttype(o)]; |  | ||||||
|   const char *kind = (isinstack(L->ci, o)) ? |  | ||||||
|                          getobjname(L, L->ci, cast_int(o - L->base), &name) : |  | ||||||
|                          NULL; |  | ||||||
|   if (kind) |  | ||||||
|     luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", |  | ||||||
|                 op, kind, name, t); |  | ||||||
|   else |  | ||||||
|     luaG_runerror(L, "attempt to %s a %s value", op, t); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { |  | ||||||
|   if (ttisstring(p1)) p1 = p2; |  | ||||||
|   lua_assert(!ttisstring(p1)); |  | ||||||
|   luaG_typeerror(L, p1, "concatenate"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { |  | ||||||
|   TValue temp; |  | ||||||
|   if (luaV_tonumber(p1, &temp) == NULL) |  | ||||||
|     p2 = p1;  /* first operand is wrong */ |  | ||||||
|   luaG_typeerror(L, p2, "perform arithmetic on"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { |  | ||||||
|   const char *t1 = luaT_typenames[ttype(p1)]; |  | ||||||
|   const char *t2 = luaT_typenames[ttype(p2)]; |  | ||||||
|   if (t1[2] == t2[2]) |  | ||||||
|     luaG_runerror(L, "attempt to compare two %s values", t1); |  | ||||||
|   else |  | ||||||
|     luaG_runerror(L, "attempt to compare %s with %s", t1, t2); |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void addinfo (lua_State *L, const char *msg) { |  | ||||||
|   CallInfo *ci = L->ci; |  | ||||||
|   if (isLua(ci)) {  /* is Lua code? */ |  | ||||||
|     char buff[LUA_IDSIZE];  /* add file:line information */ |  | ||||||
|     int line = currentline(L, ci); |  | ||||||
|     luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE); |  | ||||||
|     luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaG_errormsg (lua_State *L) { |  | ||||||
|   if (L->errfunc != 0) {  /* is there an error handling function? */ |  | ||||||
|     StkId errfunc = restorestack(L, L->errfunc); |  | ||||||
|     if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); |  | ||||||
|     setobjs2s(L, L->top, L->top - 1);  /* move argument */ |  | ||||||
|     setobjs2s(L, L->top - 1, errfunc);  /* push function */ |  | ||||||
|     incr_top(L); |  | ||||||
|     luaD_call(L, L->top - 2, 1);  /* call it */ |  | ||||||
|   } |  | ||||||
|   luaD_throw(L, LUA_ERRRUN); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaG_runerror (lua_State *L, const char *fmt, ...) { |  | ||||||
|   va_list argp; |  | ||||||
|   va_start(argp, fmt); |  | ||||||
|   addinfo(L, luaO_pushvfstring(L, fmt, argp)); |  | ||||||
|   va_end(argp); |  | ||||||
|   luaG_errormsg(L); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: ldebug.h,v 2.3 2005/04/25 19:24:10 roberto Exp $ |  | ||||||
| ** Auxiliary functions from Debug Interface module |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef ldebug_h |  | ||||||
| #define ldebug_h |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "lstate.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define pcRel(pc, p)	(cast(int, (pc) - (p)->code) - 1) |  | ||||||
|  |  | ||||||
| #define getline(f,pc)	(((f)->lineinfo) ? (f)->lineinfo[pc] : 0) |  | ||||||
|  |  | ||||||
| #define resethookcount(L)	(L->hookcount = L->basehookcount) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUAI_FUNC void luaG_typeerror (lua_State *L, const TValue *o, |  | ||||||
|                                              const char *opname); |  | ||||||
| LUAI_FUNC void luaG_concaterror (lua_State *L, StkId p1, StkId p2); |  | ||||||
| LUAI_FUNC void luaG_aritherror (lua_State *L, const TValue *p1, |  | ||||||
|                                               const TValue *p2); |  | ||||||
| LUAI_FUNC int luaG_ordererror (lua_State *L, const TValue *p1, |  | ||||||
|                                              const TValue *p2); |  | ||||||
| LUAI_FUNC void luaG_runerror (lua_State *L, const char *fmt, ...); |  | ||||||
| LUAI_FUNC void luaG_errormsg (lua_State *L); |  | ||||||
| LUAI_FUNC int luaG_checkcode (const Proto *pt); |  | ||||||
| LUAI_FUNC int luaG_checkopenop (Instruction i); |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
							
								
								
									
										515
									
								
								src/lua/ldo.c
									
									
									
									
									
								
							
							
						
						
									
										515
									
								
								src/lua/ldo.c
									
									
									
									
									
								
							| @@ -1,515 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: ldo.c,v 2.37 2005/12/22 16:19:56 roberto Exp $ |  | ||||||
| ** Stack and Call structure of Lua |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <setjmp.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define ldo_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "ldebug.h" |  | ||||||
| #include "ldo.h" |  | ||||||
| #include "lfunc.h" |  | ||||||
| #include "lgc.h" |  | ||||||
| #include "lmem.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lopcodes.h" |  | ||||||
| #include "lparser.h" |  | ||||||
| #include "lstate.h" |  | ||||||
| #include "lstring.h" |  | ||||||
| #include "ltable.h" |  | ||||||
| #include "ltm.h" |  | ||||||
| #include "lundump.h" |  | ||||||
| #include "lvm.h" |  | ||||||
| #include "lzio.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** Error-recovery functions |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* chain list of long jump buffers */ |  | ||||||
| struct lua_longjmp { |  | ||||||
|   struct lua_longjmp *previous; |  | ||||||
|   luai_jmpbuf b; |  | ||||||
|   volatile int status;  /* error code */ |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { |  | ||||||
|   switch (errcode) { |  | ||||||
|     case LUA_ERRMEM: { |  | ||||||
|       setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case LUA_ERRERR: { |  | ||||||
|       setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case LUA_ERRSYNTAX: |  | ||||||
|     case LUA_ERRRUN: { |  | ||||||
|       setobjs2s(L, oldtop, L->top - 1);  /* error message on current top */ |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   L->top = oldtop + 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void restore_stack_limit (lua_State *L) { |  | ||||||
|   lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); |  | ||||||
|   if (L->size_ci > LUAI_MAXCALLS) {  /* there was an overflow? */ |  | ||||||
|     int inuse = cast_int(L->ci - L->base_ci); |  | ||||||
|     if (inuse + 1 < LUAI_MAXCALLS)  /* can `undo' overflow? */ |  | ||||||
|       luaD_reallocCI(L, LUAI_MAXCALLS); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void resetstack (lua_State *L, int status) { |  | ||||||
|   L->ci = L->base_ci; |  | ||||||
|   L->base = L->ci->base; |  | ||||||
|   luaF_close(L, L->base);  /* close eventual pending closures */ |  | ||||||
|   luaD_seterrorobj(L, status, L->base); |  | ||||||
|   L->nCcalls = 0; |  | ||||||
|   L->allowhook = 1; |  | ||||||
|   restore_stack_limit(L); |  | ||||||
|   L->errfunc = 0; |  | ||||||
|   L->errorJmp = NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaD_throw (lua_State *L, int errcode) { |  | ||||||
|   if (L->errorJmp) { |  | ||||||
|     L->errorJmp->status = errcode; |  | ||||||
|     LUAI_THROW(L, L->errorJmp); |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     L->status = cast_byte(errcode); |  | ||||||
|     if (G(L)->panic) { |  | ||||||
|       resetstack(L, errcode); |  | ||||||
|       lua_unlock(L); |  | ||||||
|       G(L)->panic(L); |  | ||||||
|     } |  | ||||||
|     exit(EXIT_FAILURE); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { |  | ||||||
|   struct lua_longjmp lj; |  | ||||||
|   lj.status = 0; |  | ||||||
|   lj.previous = L->errorJmp;  /* chain new error handler */ |  | ||||||
|   L->errorJmp = &lj; |  | ||||||
|   LUAI_TRY(L, &lj, |  | ||||||
|     (*f)(L, ud); |  | ||||||
|   ); |  | ||||||
|   L->errorJmp = lj.previous;  /* restore old error handler */ |  | ||||||
|   return lj.status; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void correctstack (lua_State *L, TValue *oldstack) { |  | ||||||
|   CallInfo *ci; |  | ||||||
|   GCObject *up; |  | ||||||
|   L->top = (L->top - oldstack) + L->stack; |  | ||||||
|   for (up = L->openupval; up != NULL; up = up->gch.next) |  | ||||||
|     gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; |  | ||||||
|   for (ci = L->base_ci; ci <= L->ci; ci++) { |  | ||||||
|     ci->top = (ci->top - oldstack) + L->stack; |  | ||||||
|     ci->base = (ci->base - oldstack) + L->stack; |  | ||||||
|     ci->func = (ci->func - oldstack) + L->stack; |  | ||||||
|   } |  | ||||||
|   L->base = (L->base - oldstack) + L->stack; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaD_reallocstack (lua_State *L, int newsize) { |  | ||||||
|   TValue *oldstack = L->stack; |  | ||||||
|   int realsize = newsize + 1 + EXTRA_STACK; |  | ||||||
|   lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); |  | ||||||
|   luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue); |  | ||||||
|   L->stacksize = realsize; |  | ||||||
|   L->stack_last = L->stack+newsize; |  | ||||||
|   correctstack(L, oldstack); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaD_reallocCI (lua_State *L, int newsize) { |  | ||||||
|   CallInfo *oldci = L->base_ci; |  | ||||||
|   luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); |  | ||||||
|   L->size_ci = newsize; |  | ||||||
|   L->ci = (L->ci - oldci) + L->base_ci; |  | ||||||
|   L->end_ci = L->base_ci + L->size_ci - 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaD_growstack (lua_State *L, int n) { |  | ||||||
|   if (n <= L->stacksize)  /* double size is enough? */ |  | ||||||
|     luaD_reallocstack(L, 2*L->stacksize); |  | ||||||
|   else |  | ||||||
|     luaD_reallocstack(L, L->stacksize + n); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static CallInfo *growCI (lua_State *L) { |  | ||||||
|   if (L->size_ci > LUAI_MAXCALLS)  /* overflow while handling overflow? */ |  | ||||||
|     luaD_throw(L, LUA_ERRERR); |  | ||||||
|   else { |  | ||||||
|     luaD_reallocCI(L, 2*L->size_ci); |  | ||||||
|     if (L->size_ci > LUAI_MAXCALLS) |  | ||||||
|       luaG_runerror(L, "stack overflow"); |  | ||||||
|   } |  | ||||||
|   return ++L->ci; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaD_callhook (lua_State *L, int event, int line) { |  | ||||||
|   lua_Hook hook = L->hook; |  | ||||||
|   if (hook && L->allowhook) { |  | ||||||
|     ptrdiff_t top = savestack(L, L->top); |  | ||||||
|     ptrdiff_t ci_top = savestack(L, L->ci->top); |  | ||||||
|     lua_Debug ar; |  | ||||||
|     ar.event = event; |  | ||||||
|     ar.currentline = line; |  | ||||||
|     if (event == LUA_HOOKTAILRET) |  | ||||||
|       ar.i_ci = 0;  /* tail call; no debug information about it */ |  | ||||||
|     else |  | ||||||
|       ar.i_ci = cast_int(L->ci - L->base_ci); |  | ||||||
|     luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */ |  | ||||||
|     L->ci->top = L->top + LUA_MINSTACK; |  | ||||||
|     lua_assert(L->ci->top <= L->stack_last); |  | ||||||
|     L->allowhook = 0;  /* cannot call hooks inside a hook */ |  | ||||||
|     lua_unlock(L); |  | ||||||
|     (*hook)(L, &ar); |  | ||||||
|     lua_lock(L); |  | ||||||
|     lua_assert(!L->allowhook); |  | ||||||
|     L->allowhook = 1; |  | ||||||
|     L->ci->top = restorestack(L, ci_top); |  | ||||||
|     L->top = restorestack(L, top); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { |  | ||||||
|   int i; |  | ||||||
|   int nfixargs = p->numparams; |  | ||||||
|   Table *htab = NULL; |  | ||||||
|   StkId base, fixed; |  | ||||||
|   for (; actual < nfixargs; ++actual) |  | ||||||
|     setnilvalue(L->top++); |  | ||||||
| #if defined(LUA_COMPAT_VARARG) |  | ||||||
|   if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */ |  | ||||||
|     int nvar = actual - nfixargs;  /* number of extra arguments */ |  | ||||||
|     lua_assert(p->is_vararg & VARARG_HASARG); |  | ||||||
|     luaC_checkGC(L); |  | ||||||
|     htab = luaH_new(L, nvar, 1);  /* create `arg' table */ |  | ||||||
|     for (i=0; i<nvar; i++)  /* put extra arguments into `arg' table */ |  | ||||||
|       setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i); |  | ||||||
|     /* store counter in field `n' */ |  | ||||||
|     setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar)); |  | ||||||
|   } |  | ||||||
| #endif |  | ||||||
|   /* move fixed parameters to final position */ |  | ||||||
|   fixed = L->top - actual;  /* first fixed argument */ |  | ||||||
|   base = L->top;  /* final position of first argument */ |  | ||||||
|   for (i=0; i<nfixargs; i++) { |  | ||||||
|     setobjs2s(L, L->top++, fixed+i); |  | ||||||
|     setnilvalue(fixed+i); |  | ||||||
|   } |  | ||||||
|   /* add `arg' parameter */ |  | ||||||
|   if (htab) { |  | ||||||
|     sethvalue(L, L->top++, htab); |  | ||||||
|     lua_assert(iswhite(obj2gco(htab))); |  | ||||||
|   } |  | ||||||
|   return base; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static StkId tryfuncTM (lua_State *L, StkId func) { |  | ||||||
|   const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); |  | ||||||
|   StkId p; |  | ||||||
|   ptrdiff_t funcr = savestack(L, func); |  | ||||||
|   if (!ttisfunction(tm)) |  | ||||||
|     luaG_typeerror(L, func, "call"); |  | ||||||
|   /* Open a hole inside the stack at `func' */ |  | ||||||
|   for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); |  | ||||||
|   incr_top(L); |  | ||||||
|   func = restorestack(L, funcr);  /* previous call may change stack */ |  | ||||||
|   setobj2s(L, func, tm);  /* tag method is the new function to be called */ |  | ||||||
|   return func; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define inc_ci(L) \ |  | ||||||
|   ((L->ci == L->end_ci) ? growCI(L) : \ |  | ||||||
|    (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaD_precall (lua_State *L, StkId func, int nresults) { |  | ||||||
|   LClosure *cl; |  | ||||||
|   ptrdiff_t funcr; |  | ||||||
|   if (!ttisfunction(func)) /* `func' is not a function? */ |  | ||||||
|     func = tryfuncTM(L, func);  /* check the `function' tag method */ |  | ||||||
|   funcr = savestack(L, func); |  | ||||||
|   cl = &clvalue(func)->l; |  | ||||||
|   L->ci->savedpc = L->savedpc; |  | ||||||
|   if (!cl->isC) {  /* Lua function? prepare its call */ |  | ||||||
|     CallInfo *ci; |  | ||||||
|     StkId st, base; |  | ||||||
|     Proto *p = cl->p; |  | ||||||
|     luaD_checkstack(L, p->maxstacksize); |  | ||||||
|     func = restorestack(L, funcr); |  | ||||||
|     if (!p->is_vararg) {  /* no varargs? */ |  | ||||||
|       base = func + 1; |  | ||||||
|       if (L->top > base + p->numparams) |  | ||||||
|         L->top = base + p->numparams; |  | ||||||
|     } |  | ||||||
|     else {  /* vararg function */ |  | ||||||
|       int nargs = cast_int(L->top - func) - 1; |  | ||||||
|       base = adjust_varargs(L, p, nargs); |  | ||||||
|       func = restorestack(L, funcr);  /* previous call may change the stack */ |  | ||||||
|     } |  | ||||||
|     ci = inc_ci(L);  /* now `enter' new function */ |  | ||||||
|     ci->func = func; |  | ||||||
|     L->base = ci->base = base; |  | ||||||
|     ci->top = L->base + p->maxstacksize; |  | ||||||
|     lua_assert(ci->top <= L->stack_last); |  | ||||||
|     L->savedpc = p->code;  /* starting point */ |  | ||||||
|     ci->tailcalls = 0; |  | ||||||
|     ci->nresults = nresults; |  | ||||||
|     for (st = L->top; st < ci->top; st++) |  | ||||||
|       setnilvalue(st); |  | ||||||
|     L->top = ci->top; |  | ||||||
|     if (L->hookmask & LUA_MASKCALL) { |  | ||||||
|       L->savedpc++;  /* hooks assume 'pc' is already incremented */ |  | ||||||
|       luaD_callhook(L, LUA_HOOKCALL, -1); |  | ||||||
|       L->savedpc--;  /* correct 'pc' */ |  | ||||||
|     } |  | ||||||
|     return PCRLUA; |  | ||||||
|   } |  | ||||||
|   else {  /* if is a C function, call it */ |  | ||||||
|     CallInfo *ci; |  | ||||||
|     int n; |  | ||||||
|     luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */ |  | ||||||
|     ci = inc_ci(L);  /* now `enter' new function */ |  | ||||||
|     ci->func = restorestack(L, funcr); |  | ||||||
|     L->base = ci->base = ci->func + 1; |  | ||||||
|     ci->top = L->top + LUA_MINSTACK; |  | ||||||
|     lua_assert(ci->top <= L->stack_last); |  | ||||||
|     ci->nresults = nresults; |  | ||||||
|     if (L->hookmask & LUA_MASKCALL) |  | ||||||
|       luaD_callhook(L, LUA_HOOKCALL, -1); |  | ||||||
|     lua_unlock(L); |  | ||||||
|     n = (*curr_func(L)->c.f)(L);  /* do the actual call */ |  | ||||||
|     lua_lock(L); |  | ||||||
|     if (n < 0)  /* yielding? */ |  | ||||||
|       return PCRYIELD; |  | ||||||
|     else { |  | ||||||
|       luaD_poscall(L, L->top - n); |  | ||||||
|       return PCRC; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static StkId callrethooks (lua_State *L, StkId firstResult) { |  | ||||||
|   ptrdiff_t fr = savestack(L, firstResult);  /* next call may change stack */ |  | ||||||
|   luaD_callhook(L, LUA_HOOKRET, -1); |  | ||||||
|   if (f_isLua(L->ci)) {  /* Lua function? */ |  | ||||||
|     while (L->ci->tailcalls--)  /* call hook for eventual tail calls */ |  | ||||||
|       luaD_callhook(L, LUA_HOOKTAILRET, -1); |  | ||||||
|   } |  | ||||||
|   return restorestack(L, fr); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaD_poscall (lua_State *L, StkId firstResult) { |  | ||||||
|   StkId res; |  | ||||||
|   int wanted, i; |  | ||||||
|   CallInfo *ci; |  | ||||||
|   if (L->hookmask & LUA_MASKRET) |  | ||||||
|     firstResult = callrethooks(L, firstResult); |  | ||||||
|   ci = L->ci--; |  | ||||||
|   res = ci->func;  /* res == final position of 1st result */ |  | ||||||
|   wanted = ci->nresults; |  | ||||||
|   L->base = (ci - 1)->base;  /* restore base */ |  | ||||||
|   L->savedpc = (ci - 1)->savedpc;  /* restore savedpc */ |  | ||||||
|   /* move results to correct place */ |  | ||||||
|   for (i = wanted; i != 0 && firstResult < L->top; i--) |  | ||||||
|     setobjs2s(L, res++, firstResult++); |  | ||||||
|   while (i-- > 0) |  | ||||||
|     setnilvalue(res++); |  | ||||||
|   L->top = res; |  | ||||||
|   return (wanted - LUA_MULTRET);  /* 0 iff wanted == LUA_MULTRET */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Call a function (C or Lua). The function to be called is at *func. |  | ||||||
| ** The arguments are on the stack, right after the function. |  | ||||||
| ** When returns, all the results are on the stack, starting at the original |  | ||||||
| ** function position. |  | ||||||
| */  |  | ||||||
| void luaD_call (lua_State *L, StkId func, int nResults) { |  | ||||||
|   if (++L->nCcalls >= LUAI_MAXCCALLS) { |  | ||||||
|     if (L->nCcalls == LUAI_MAXCCALLS) |  | ||||||
|       luaG_runerror(L, "C stack overflow"); |  | ||||||
|     else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) |  | ||||||
|       luaD_throw(L, LUA_ERRERR);  /* error while handing stack error */ |  | ||||||
|   } |  | ||||||
|   if (luaD_precall(L, func, nResults) == PCRLUA)  /* is a Lua function? */ |  | ||||||
|     luaV_execute(L, 1);  /* call it */ |  | ||||||
|   L->nCcalls--; |  | ||||||
|   luaC_checkGC(L); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void resume (lua_State *L, void *ud) { |  | ||||||
|   StkId firstArg = cast(StkId, ud); |  | ||||||
|   CallInfo *ci = L->ci; |  | ||||||
|   if (L->status != LUA_YIELD) {  /* start coroutine */ |  | ||||||
|     lua_assert(ci == L->base_ci && firstArg > L->base); |  | ||||||
|     if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) |  | ||||||
|       return; |  | ||||||
|   } |  | ||||||
|   else {  /* resuming from previous yield */ |  | ||||||
|     if (!f_isLua(ci)) {  /* `common' yield? */ |  | ||||||
|       /* finish interrupted execution of `OP_CALL' */ |  | ||||||
|       lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || |  | ||||||
|                  GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); |  | ||||||
|       if (luaD_poscall(L, firstArg))  /* complete it... */ |  | ||||||
|         L->top = L->ci->top;  /* and correct top if not multiple results */ |  | ||||||
|     } |  | ||||||
|     else  /* yielded inside a hook: just continue its execution */ |  | ||||||
|       L->base = L->ci->base; |  | ||||||
|   } |  | ||||||
|   L->status = 0; |  | ||||||
|   luaV_execute(L, cast_int(L->ci - L->base_ci)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int resume_error (lua_State *L, const char *msg) { |  | ||||||
|   L->top = L->ci->base; |  | ||||||
|   setsvalue2s(L, L->top, luaS_new(L, msg)); |  | ||||||
|   incr_top(L); |  | ||||||
|   lua_unlock(L); |  | ||||||
|   return LUA_ERRRUN; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUA_API int lua_resume (lua_State *L, int nargs) { |  | ||||||
|   int status; |  | ||||||
|   lua_lock(L); |  | ||||||
|   if (L->status != LUA_YIELD) { |  | ||||||
|     if (L->status != 0) |  | ||||||
|       return resume_error(L, "cannot resume dead coroutine"); |  | ||||||
|     else if (L->ci != L->base_ci) |  | ||||||
|       return resume_error(L, "cannot resume non-suspended coroutine"); |  | ||||||
|   } |  | ||||||
|   luai_userstateresume(L, nargs); |  | ||||||
|   lua_assert(L->errfunc == 0 && L->nCcalls == 0); |  | ||||||
|   status = luaD_rawrunprotected(L, resume, L->top - nargs); |  | ||||||
|   if (status != 0) {  /* error? */ |  | ||||||
|     L->status = cast_byte(status);  /* mark thread as `dead' */ |  | ||||||
|     luaD_seterrorobj(L, status, L->top); |  | ||||||
|     L->ci->top = L->top; |  | ||||||
|   } |  | ||||||
|   else |  | ||||||
|     status = L->status; |  | ||||||
|   lua_unlock(L); |  | ||||||
|   return status; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUA_API int lua_yield (lua_State *L, int nresults) { |  | ||||||
|   luai_userstateyield(L, nresults); |  | ||||||
|   lua_lock(L); |  | ||||||
|   if (L->nCcalls > 0) |  | ||||||
|     luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); |  | ||||||
|   L->base = L->top - nresults;  /* protect stack slots below */ |  | ||||||
|   L->status = LUA_YIELD; |  | ||||||
|   lua_unlock(L); |  | ||||||
|   return -1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaD_pcall (lua_State *L, Pfunc func, void *u, |  | ||||||
|                 ptrdiff_t old_top, ptrdiff_t ef) { |  | ||||||
|   int status; |  | ||||||
|   unsigned short oldnCcalls = L->nCcalls; |  | ||||||
|   ptrdiff_t old_ci = saveci(L, L->ci); |  | ||||||
|   lu_byte old_allowhooks = L->allowhook; |  | ||||||
|   ptrdiff_t old_errfunc = L->errfunc; |  | ||||||
|   L->errfunc = ef; |  | ||||||
|   status = luaD_rawrunprotected(L, func, u); |  | ||||||
|   if (status != 0) {  /* an error occurred? */ |  | ||||||
|     StkId oldtop = restorestack(L, old_top); |  | ||||||
|     luaF_close(L, oldtop);  /* close eventual pending closures */ |  | ||||||
|     luaD_seterrorobj(L, status, oldtop); |  | ||||||
|     L->nCcalls = oldnCcalls; |  | ||||||
|     L->ci = restoreci(L, old_ci); |  | ||||||
|     L->base = L->ci->base; |  | ||||||
|     L->savedpc = L->ci->savedpc; |  | ||||||
|     L->allowhook = old_allowhooks; |  | ||||||
|     restore_stack_limit(L); |  | ||||||
|   } |  | ||||||
|   L->errfunc = old_errfunc; |  | ||||||
|   return status; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Execute a protected parser. |  | ||||||
| */ |  | ||||||
| struct SParser {  /* data to `f_parser' */ |  | ||||||
|   ZIO *z; |  | ||||||
|   Mbuffer buff;  /* buffer to be used by the scanner */ |  | ||||||
|   const char *name; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| static void f_parser (lua_State *L, void *ud) { |  | ||||||
|   int i; |  | ||||||
|   Proto *tf; |  | ||||||
|   Closure *cl; |  | ||||||
|   struct SParser *p = cast(struct SParser *, ud); |  | ||||||
|   int c = luaZ_lookahead(p->z); |  | ||||||
|   luaC_checkGC(L); |  | ||||||
|   tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, |  | ||||||
|                                                              &p->buff, p->name); |  | ||||||
|   cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); |  | ||||||
|   cl->l.p = tf; |  | ||||||
|   for (i = 0; i < tf->nups; i++)  /* initialize eventual upvalues */ |  | ||||||
|     cl->l.upvals[i] = luaF_newupval(L); |  | ||||||
|   setclvalue(L, L->top, cl); |  | ||||||
|   incr_top(L); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { |  | ||||||
|   struct SParser p; |  | ||||||
|   int status; |  | ||||||
|   p.z = z; p.name = name; |  | ||||||
|   luaZ_initbuffer(L, &p.buff); |  | ||||||
|   status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); |  | ||||||
|   luaZ_freebuffer(L, &p.buff); |  | ||||||
|   return status; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,57 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: ldo.h,v 2.7 2005/08/24 16:15:49 roberto Exp $ |  | ||||||
| ** Stack and Call structure of Lua |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef ldo_h |  | ||||||
| #define ldo_h |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lstate.h" |  | ||||||
| #include "lzio.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define luaD_checkstack(L,n)	\ |  | ||||||
|   if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \ |  | ||||||
|     luaD_growstack(L, n); \ |  | ||||||
|   else condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define incr_top(L) {luaD_checkstack(L,1); L->top++;} |  | ||||||
|  |  | ||||||
| #define savestack(L,p)		((char *)(p) - (char *)L->stack) |  | ||||||
| #define restorestack(L,n)	((TValue *)((char *)L->stack + (n))) |  | ||||||
|  |  | ||||||
| #define saveci(L,p)		((char *)(p) - (char *)L->base_ci) |  | ||||||
| #define restoreci(L,n)		((CallInfo *)((char *)L->base_ci + (n))) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* results from luaD_precall */ |  | ||||||
| #define PCRLUA		0	/* initiated a call to a Lua function */ |  | ||||||
| #define PCRC		1	/* did a call to a C function */ |  | ||||||
| #define PCRYIELD	2	/* C funtion yielded */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* type of protected functions, to be ran by `runprotected' */ |  | ||||||
| typedef void (*Pfunc) (lua_State *L, void *ud); |  | ||||||
|  |  | ||||||
| LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); |  | ||||||
| LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line); |  | ||||||
| LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); |  | ||||||
| LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); |  | ||||||
| LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, |  | ||||||
|                                         ptrdiff_t oldtop, ptrdiff_t ef); |  | ||||||
| LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); |  | ||||||
| LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize); |  | ||||||
| LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); |  | ||||||
| LUAI_FUNC void luaD_growstack (lua_State *L, int n); |  | ||||||
|  |  | ||||||
| LUAI_FUNC void luaD_throw (lua_State *L, int errcode); |  | ||||||
| LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); |  | ||||||
|  |  | ||||||
| LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
							
								
								
									
										164
									
								
								src/lua/ldump.c
									
									
									
									
									
								
							
							
						
						
									
										164
									
								
								src/lua/ldump.c
									
									
									
									
									
								
							| @@ -1,164 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: ldump.c,v 1.15 2006/02/16 15:53:49 lhf Exp $ |  | ||||||
| ** save precompiled Lua chunks |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #include <stddef.h> |  | ||||||
|  |  | ||||||
| #define ldump_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lstate.h" |  | ||||||
| #include "lundump.h" |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|  lua_State* L; |  | ||||||
|  lua_Writer writer; |  | ||||||
|  void* data; |  | ||||||
|  int strip; |  | ||||||
|  int status; |  | ||||||
| } DumpState; |  | ||||||
|  |  | ||||||
| #define DumpMem(b,n,size,D)	DumpBlock(b,(n)*(size),D) |  | ||||||
| #define DumpVar(x,D)	 	DumpMem(&x,1,sizeof(x),D) |  | ||||||
|  |  | ||||||
| static void DumpBlock(const void* b, size_t size, DumpState* D) |  | ||||||
| { |  | ||||||
|  if (D->status==0) |  | ||||||
|  { |  | ||||||
|   lua_unlock(D->L); |  | ||||||
|   D->status=(*D->writer)(D->L,b,size,D->data); |  | ||||||
|   lua_lock(D->L); |  | ||||||
|  } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void DumpChar(int y, DumpState* D) |  | ||||||
| { |  | ||||||
|  char x=(char)y; |  | ||||||
|  DumpVar(x,D); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void DumpInt(int x, DumpState* D) |  | ||||||
| { |  | ||||||
|  DumpVar(x,D); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void DumpNumber(lua_Number x, DumpState* D) |  | ||||||
| { |  | ||||||
|  DumpVar(x,D); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void DumpVector(const void* b, int n, size_t size, DumpState* D) |  | ||||||
| { |  | ||||||
|  DumpInt(n,D); |  | ||||||
|  DumpMem(b,n,size,D); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void DumpString(const TString* s, DumpState* D) |  | ||||||
| { |  | ||||||
|  if (s==NULL || getstr(s)==NULL) |  | ||||||
|  { |  | ||||||
|   size_t size=0; |  | ||||||
|   DumpVar(size,D); |  | ||||||
|  } |  | ||||||
|  else |  | ||||||
|  { |  | ||||||
|   size_t size=s->tsv.len+1;		/* include trailing '\0' */ |  | ||||||
|   DumpVar(size,D); |  | ||||||
|   DumpBlock(getstr(s),size,D); |  | ||||||
|  } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #define DumpCode(f,D)	 DumpVector(f->code,f->sizecode,sizeof(Instruction),D) |  | ||||||
|  |  | ||||||
| static void DumpFunction(const Proto* f, const TString* p, DumpState* D); |  | ||||||
|  |  | ||||||
| static void DumpConstants(const Proto* f, DumpState* D) |  | ||||||
| { |  | ||||||
|  int i,n=f->sizek; |  | ||||||
|  DumpInt(n,D); |  | ||||||
|  for (i=0; i<n; i++) |  | ||||||
|  { |  | ||||||
|   const TValue* o=&f->k[i]; |  | ||||||
|   DumpChar(ttype(o),D); |  | ||||||
|   switch (ttype(o)) |  | ||||||
|   { |  | ||||||
|    case LUA_TNIL: |  | ||||||
| 	break; |  | ||||||
|    case LUA_TBOOLEAN: |  | ||||||
| 	DumpChar(bvalue(o),D); |  | ||||||
| 	break; |  | ||||||
|    case LUA_TNUMBER: |  | ||||||
| 	DumpNumber(nvalue(o),D); |  | ||||||
| 	break; |  | ||||||
|    case LUA_TSTRING: |  | ||||||
| 	DumpString(rawtsvalue(o),D); |  | ||||||
| 	break; |  | ||||||
|    default: |  | ||||||
| 	lua_assert(0);			/* cannot happen */ |  | ||||||
| 	break; |  | ||||||
|   } |  | ||||||
|  } |  | ||||||
|  n=f->sizep; |  | ||||||
|  DumpInt(n,D); |  | ||||||
|  for (i=0; i<n; i++) DumpFunction(f->p[i],f->source,D); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void DumpDebug(const Proto* f, DumpState* D) |  | ||||||
| { |  | ||||||
|  int i,n; |  | ||||||
|  n= (D->strip) ? 0 : f->sizelineinfo; |  | ||||||
|  DumpVector(f->lineinfo,n,sizeof(int),D); |  | ||||||
|  n= (D->strip) ? 0 : f->sizelocvars; |  | ||||||
|  DumpInt(n,D); |  | ||||||
|  for (i=0; i<n; i++) |  | ||||||
|  { |  | ||||||
|   DumpString(f->locvars[i].varname,D); |  | ||||||
|   DumpInt(f->locvars[i].startpc,D); |  | ||||||
|   DumpInt(f->locvars[i].endpc,D); |  | ||||||
|  } |  | ||||||
|  n= (D->strip) ? 0 : f->sizeupvalues; |  | ||||||
|  DumpInt(n,D); |  | ||||||
|  for (i=0; i<n; i++) DumpString(f->upvalues[i],D); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void DumpFunction(const Proto* f, const TString* p, DumpState* D) |  | ||||||
| { |  | ||||||
|  DumpString((f->source==p || D->strip) ? NULL : f->source,D); |  | ||||||
|  DumpInt(f->linedefined,D); |  | ||||||
|  DumpInt(f->lastlinedefined,D); |  | ||||||
|  DumpChar(f->nups,D); |  | ||||||
|  DumpChar(f->numparams,D); |  | ||||||
|  DumpChar(f->is_vararg,D); |  | ||||||
|  DumpChar(f->maxstacksize,D); |  | ||||||
|  DumpCode(f,D); |  | ||||||
|  DumpConstants(f,D); |  | ||||||
|  DumpDebug(f,D); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void DumpHeader(DumpState* D) |  | ||||||
| { |  | ||||||
|  char h[LUAC_HEADERSIZE]; |  | ||||||
|  luaU_header(h); |  | ||||||
|  DumpBlock(h,LUAC_HEADERSIZE,D); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** dump Lua function as precompiled chunk |  | ||||||
| */ |  | ||||||
| int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) |  | ||||||
| { |  | ||||||
|  DumpState D; |  | ||||||
|  D.L=L; |  | ||||||
|  D.writer=w; |  | ||||||
|  D.data=data; |  | ||||||
|  D.strip=strip; |  | ||||||
|  D.status=0; |  | ||||||
|  DumpHeader(&D); |  | ||||||
|  DumpFunction(f,NULL,&D); |  | ||||||
|  return D.status; |  | ||||||
| } |  | ||||||
							
								
								
									
										174
									
								
								src/lua/lfunc.c
									
									
									
									
									
								
							
							
						
						
									
										174
									
								
								src/lua/lfunc.c
									
									
									
									
									
								
							| @@ -1,174 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lfunc.c,v 2.12 2005/12/22 16:19:56 roberto Exp $ |  | ||||||
| ** Auxiliary functions to manipulate prototypes and closures |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <stddef.h> |  | ||||||
|  |  | ||||||
| #define lfunc_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lfunc.h" |  | ||||||
| #include "lgc.h" |  | ||||||
| #include "lmem.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lstate.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) { |  | ||||||
|   Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); |  | ||||||
|   luaC_link(L, obj2gco(c), LUA_TFUNCTION); |  | ||||||
|   c->c.isC = 1; |  | ||||||
|   c->c.env = e; |  | ||||||
|   c->c.nupvalues = cast_byte(nelems); |  | ||||||
|   return c; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) { |  | ||||||
|   Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); |  | ||||||
|   luaC_link(L, obj2gco(c), LUA_TFUNCTION); |  | ||||||
|   c->l.isC = 0; |  | ||||||
|   c->l.env = e; |  | ||||||
|   c->l.nupvalues = cast_byte(nelems); |  | ||||||
|   while (nelems--) c->l.upvals[nelems] = NULL; |  | ||||||
|   return c; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| UpVal *luaF_newupval (lua_State *L) { |  | ||||||
|   UpVal *uv = luaM_new(L, UpVal); |  | ||||||
|   luaC_link(L, obj2gco(uv), LUA_TUPVAL); |  | ||||||
|   uv->v = &uv->u.value; |  | ||||||
|   setnilvalue(uv->v); |  | ||||||
|   return uv; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| UpVal *luaF_findupval (lua_State *L, StkId level) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   GCObject **pp = &L->openupval; |  | ||||||
|   UpVal *p; |  | ||||||
|   UpVal *uv; |  | ||||||
|   while ((p = ngcotouv(*pp)) != NULL && p->v >= level) { |  | ||||||
|     lua_assert(p->v != &p->u.value); |  | ||||||
|     if (p->v == level) {  /* found a corresponding upvalue? */ |  | ||||||
|       if (isdead(g, obj2gco(p)))  /* is it dead? */ |  | ||||||
|         changewhite(obj2gco(p));  /* ressurect it */ |  | ||||||
|       return p; |  | ||||||
|     } |  | ||||||
|     pp = &p->next; |  | ||||||
|   } |  | ||||||
|   uv = luaM_new(L, UpVal);  /* not found: create a new one */ |  | ||||||
|   uv->tt = LUA_TUPVAL; |  | ||||||
|   uv->marked = luaC_white(g); |  | ||||||
|   uv->v = level;  /* current value lives in the stack */ |  | ||||||
|   uv->next = *pp;  /* chain it in the proper position */ |  | ||||||
|   *pp = obj2gco(uv); |  | ||||||
|   uv->u.l.prev = &g->uvhead;  /* double link it in `uvhead' list */ |  | ||||||
|   uv->u.l.next = g->uvhead.u.l.next; |  | ||||||
|   uv->u.l.next->u.l.prev = uv; |  | ||||||
|   g->uvhead.u.l.next = uv; |  | ||||||
|   lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); |  | ||||||
|   return uv; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void unlinkupval (UpVal *uv) { |  | ||||||
|   lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); |  | ||||||
|   uv->u.l.next->u.l.prev = uv->u.l.prev;  /* remove from `uvhead' list */ |  | ||||||
|   uv->u.l.prev->u.l.next = uv->u.l.next; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaF_freeupval (lua_State *L, UpVal *uv) { |  | ||||||
|   if (uv->v != &uv->u.value)  /* is it open? */ |  | ||||||
|     unlinkupval(uv);  /* remove from open list */ |  | ||||||
|   luaM_free(L, uv);  /* free upvalue */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaF_close (lua_State *L, StkId level) { |  | ||||||
|   UpVal *uv; |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   while ((uv = ngcotouv(L->openupval)) != NULL && uv->v >= level) { |  | ||||||
|     GCObject *o = obj2gco(uv); |  | ||||||
|     lua_assert(!isblack(o) && uv->v != &uv->u.value); |  | ||||||
|     L->openupval = uv->next;  /* remove from `open' list */ |  | ||||||
|     if (isdead(g, o)) |  | ||||||
|       luaF_freeupval(L, uv);  /* free upvalue */ |  | ||||||
|     else { |  | ||||||
|       unlinkupval(uv); |  | ||||||
|       setobj(L, &uv->u.value, uv->v); |  | ||||||
|       uv->v = &uv->u.value;  /* now current value lives here */ |  | ||||||
|       luaC_linkupval(L, uv);  /* link upvalue into `gcroot' list */ |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Proto *luaF_newproto (lua_State *L) { |  | ||||||
|   Proto *f = luaM_new(L, Proto); |  | ||||||
|   luaC_link(L, obj2gco(f), LUA_TPROTO); |  | ||||||
|   f->k = NULL; |  | ||||||
|   f->sizek = 0; |  | ||||||
|   f->p = NULL; |  | ||||||
|   f->sizep = 0; |  | ||||||
|   f->code = NULL; |  | ||||||
|   f->sizecode = 0; |  | ||||||
|   f->sizelineinfo = 0; |  | ||||||
|   f->sizeupvalues = 0; |  | ||||||
|   f->nups = 0; |  | ||||||
|   f->upvalues = NULL; |  | ||||||
|   f->numparams = 0; |  | ||||||
|   f->is_vararg = 0; |  | ||||||
|   f->maxstacksize = 0; |  | ||||||
|   f->lineinfo = NULL; |  | ||||||
|   f->sizelocvars = 0; |  | ||||||
|   f->locvars = NULL; |  | ||||||
|   f->linedefined = 0; |  | ||||||
|   f->lastlinedefined = 0; |  | ||||||
|   f->source = NULL; |  | ||||||
|   return f; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaF_freeproto (lua_State *L, Proto *f) { |  | ||||||
|   luaM_freearray(L, f->code, f->sizecode, Instruction); |  | ||||||
|   luaM_freearray(L, f->p, f->sizep, Proto *); |  | ||||||
|   luaM_freearray(L, f->k, f->sizek, TValue); |  | ||||||
|   luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); |  | ||||||
|   luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); |  | ||||||
|   luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); |  | ||||||
|   luaM_free(L, f); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaF_freeclosure (lua_State *L, Closure *c) { |  | ||||||
|   int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) : |  | ||||||
|                           sizeLclosure(c->l.nupvalues); |  | ||||||
|   luaM_freemem(L, c, size); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Look for n-th local variable at line `line' in function `func'. |  | ||||||
| ** Returns NULL if not found. |  | ||||||
| */ |  | ||||||
| const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { |  | ||||||
|   int i; |  | ||||||
|   for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) { |  | ||||||
|     if (pc < f->locvars[i].endpc) {  /* is variable active? */ |  | ||||||
|       local_number--; |  | ||||||
|       if (local_number == 0) |  | ||||||
|         return getstr(f->locvars[i].varname); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return NULL;  /* not found */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,34 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lfunc.h,v 2.4 2005/04/25 19:24:10 roberto Exp $ |  | ||||||
| ** Auxiliary functions to manipulate prototypes and closures |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef lfunc_h |  | ||||||
| #define lfunc_h |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "lobject.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define sizeCclosure(n)	(cast(int, sizeof(CClosure)) + \ |  | ||||||
|                          cast(int, sizeof(TValue)*((n)-1))) |  | ||||||
|  |  | ||||||
| #define sizeLclosure(n)	(cast(int, sizeof(LClosure)) + \ |  | ||||||
|                          cast(int, sizeof(TValue *)*((n)-1))) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUAI_FUNC Proto *luaF_newproto (lua_State *L); |  | ||||||
| LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e); |  | ||||||
| LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e); |  | ||||||
| LUAI_FUNC UpVal *luaF_newupval (lua_State *L); |  | ||||||
| LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); |  | ||||||
| LUAI_FUNC void luaF_close (lua_State *L, StkId level); |  | ||||||
| LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); |  | ||||||
| LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c); |  | ||||||
| LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv); |  | ||||||
| LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, |  | ||||||
|                                          int pc); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
							
								
								
									
										707
									
								
								src/lua/lgc.c
									
									
									
									
									
								
							
							
						
						
									
										707
									
								
								src/lua/lgc.c
									
									
									
									
									
								
							| @@ -1,707 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lgc.c,v 2.37 2005/12/22 16:19:56 roberto Exp $ |  | ||||||
| ** Garbage Collector |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define lgc_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "ldebug.h" |  | ||||||
| #include "ldo.h" |  | ||||||
| #include "lfunc.h" |  | ||||||
| #include "lgc.h" |  | ||||||
| #include "lmem.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lstate.h" |  | ||||||
| #include "lstring.h" |  | ||||||
| #include "ltable.h" |  | ||||||
| #include "ltm.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define GCSTEPSIZE	1024u |  | ||||||
| #define GCSWEEPMAX	40 |  | ||||||
| #define GCSWEEPCOST	10 |  | ||||||
| #define GCFINALIZECOST	100 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define maskmarks	cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) |  | ||||||
|  |  | ||||||
| #define makewhite(g,x)	\ |  | ||||||
|    ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g))) |  | ||||||
|  |  | ||||||
| #define white2gray(x)	reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) |  | ||||||
| #define black2gray(x)	resetbit((x)->gch.marked, BLACKBIT) |  | ||||||
|  |  | ||||||
| #define stringmark(s)	reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define isfinalized(u)		testbit((u)->marked, FINALIZEDBIT) |  | ||||||
| #define markfinalized(u)	l_setbit((u)->marked, FINALIZEDBIT) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define KEYWEAK         bitmask(KEYWEAKBIT) |  | ||||||
| #define VALUEWEAK       bitmask(VALUEWEAKBIT) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define markvalue(g,o) { checkconsistency(o); \ |  | ||||||
|   if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } |  | ||||||
|  |  | ||||||
| #define markobject(g,t) { if (iswhite(obj2gco(t))) \ |  | ||||||
| 		reallymarkobject(g, obj2gco(t)); } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define setthreshold(g)  (g->GCthreshold = (g->estimate/100) * g->gcpause) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void removeentry (Node *n) { |  | ||||||
|   lua_assert(ttisnil(gval(n))); |  | ||||||
|   if (iscollectable(gkey(n))) |  | ||||||
|     setttype(gkey(n), LUA_TDEADKEY);  /* dead key; remove it */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void reallymarkobject (global_State *g, GCObject *o) { |  | ||||||
|   lua_assert(iswhite(o) && !isdead(g, o)); |  | ||||||
|   white2gray(o); |  | ||||||
|   switch (o->gch.tt) { |  | ||||||
|     case LUA_TSTRING: { |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     case LUA_TUSERDATA: { |  | ||||||
|       Table *mt = gco2u(o)->metatable; |  | ||||||
|       gray2black(o);  /* udata are never gray */ |  | ||||||
|       if (mt) markobject(g, mt); |  | ||||||
|       markobject(g, gco2u(o)->env); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     case LUA_TUPVAL: { |  | ||||||
|       UpVal *uv = gco2uv(o); |  | ||||||
|       markvalue(g, uv->v); |  | ||||||
|       if (uv->v == &uv->u.value)  /* closed? */ |  | ||||||
|         gray2black(o);  /* open upvalues are never black */ |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     case LUA_TFUNCTION: { |  | ||||||
|       gco2cl(o)->c.gclist = g->gray; |  | ||||||
|       g->gray = o; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case LUA_TTABLE: { |  | ||||||
|       gco2h(o)->gclist = g->gray; |  | ||||||
|       g->gray = o; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case LUA_TTHREAD: { |  | ||||||
|       gco2th(o)->gclist = g->gray; |  | ||||||
|       g->gray = o; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case LUA_TPROTO: { |  | ||||||
|       gco2p(o)->gclist = g->gray; |  | ||||||
|       g->gray = o; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     default: lua_assert(0); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void marktmu (global_State *g) { |  | ||||||
|   GCObject *u = g->tmudata; |  | ||||||
|   if (u) { |  | ||||||
|     do { |  | ||||||
|       u = u->gch.next; |  | ||||||
|       makewhite(g, u);  /* may be marked, if left from previous GC */ |  | ||||||
|       reallymarkobject(g, u); |  | ||||||
|     } while (u != g->tmudata); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* move `dead' udata that need finalization to list `tmudata' */ |  | ||||||
| size_t luaC_separateudata (lua_State *L, int all) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   size_t deadmem = 0; |  | ||||||
|   GCObject **p = &g->mainthread->next; |  | ||||||
|   GCObject *curr; |  | ||||||
|   while ((curr = *p) != NULL) { |  | ||||||
|     if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) |  | ||||||
|       p = &curr->gch.next;  /* don't bother with them */ |  | ||||||
|     else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { |  | ||||||
|       markfinalized(gco2u(curr));  /* don't need finalization */ |  | ||||||
|       p = &curr->gch.next; |  | ||||||
|     } |  | ||||||
|     else {  /* must call its gc method */ |  | ||||||
|       deadmem += sizeudata(gco2u(curr)); |  | ||||||
|       markfinalized(gco2u(curr)); |  | ||||||
|       *p = curr->gch.next; |  | ||||||
|       /* link `curr' at the end of `tmudata' list */ |  | ||||||
|       if (g->tmudata == NULL)  /* list is empty? */ |  | ||||||
|         g->tmudata = curr->gch.next = curr;  /* creates a circular list */ |  | ||||||
|       else { |  | ||||||
|         curr->gch.next = g->tmudata->gch.next; |  | ||||||
|         g->tmudata->gch.next = curr; |  | ||||||
|         g->tmudata = curr; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return deadmem; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int traversetable (global_State *g, Table *h) { |  | ||||||
|   int i; |  | ||||||
|   int weakkey = 0; |  | ||||||
|   int weakvalue = 0; |  | ||||||
|   const TValue *mode; |  | ||||||
|   if (h->metatable) |  | ||||||
|     markobject(g, h->metatable); |  | ||||||
|   mode = gfasttm(g, h->metatable, TM_MODE); |  | ||||||
|   if (mode && ttisstring(mode)) {  /* is there a weak mode? */ |  | ||||||
|     weakkey = (strchr(svalue(mode), 'k') != NULL); |  | ||||||
|     weakvalue = (strchr(svalue(mode), 'v') != NULL); |  | ||||||
|     if (weakkey || weakvalue) {  /* is really weak? */ |  | ||||||
|       h->marked &= ~(KEYWEAK | VALUEWEAK);  /* clear bits */ |  | ||||||
|       h->marked |= cast_byte((weakkey << KEYWEAKBIT) | |  | ||||||
|                              (weakvalue << VALUEWEAKBIT)); |  | ||||||
|       h->gclist = g->weak;  /* must be cleared after GC, ... */ |  | ||||||
|       g->weak = obj2gco(h);  /* ... so put in the appropriate list */ |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   if (weakkey && weakvalue) return 1; |  | ||||||
|   if (!weakvalue) { |  | ||||||
|     i = h->sizearray; |  | ||||||
|     while (i--) |  | ||||||
|       markvalue(g, &h->array[i]); |  | ||||||
|   } |  | ||||||
|   i = sizenode(h); |  | ||||||
|   while (i--) { |  | ||||||
|     Node *n = gnode(h, i); |  | ||||||
|     lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); |  | ||||||
|     if (ttisnil(gval(n))) |  | ||||||
|       removeentry(n);  /* remove empty entries */ |  | ||||||
|     else { |  | ||||||
|       lua_assert(!ttisnil(gkey(n))); |  | ||||||
|       if (!weakkey) markvalue(g, gkey(n)); |  | ||||||
|       if (!weakvalue) markvalue(g, gval(n)); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return weakkey || weakvalue; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** All marks are conditional because a GC may happen while the |  | ||||||
| ** prototype is still being created |  | ||||||
| */ |  | ||||||
| static void traverseproto (global_State *g, Proto *f) { |  | ||||||
|   int i; |  | ||||||
|   if (f->source) stringmark(f->source); |  | ||||||
|   for (i=0; i<f->sizek; i++)  /* mark literals */ |  | ||||||
|     markvalue(g, &f->k[i]); |  | ||||||
|   for (i=0; i<f->sizeupvalues; i++) {  /* mark upvalue names */ |  | ||||||
|     if (f->upvalues[i]) |  | ||||||
|       stringmark(f->upvalues[i]); |  | ||||||
|   } |  | ||||||
|   for (i=0; i<f->sizep; i++) {  /* mark nested protos */ |  | ||||||
|     if (f->p[i]) |  | ||||||
|       markobject(g, f->p[i]); |  | ||||||
|   } |  | ||||||
|   for (i=0; i<f->sizelocvars; i++) {  /* mark local-variable names */ |  | ||||||
|     if (f->locvars[i].varname) |  | ||||||
|       stringmark(f->locvars[i].varname); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void traverseclosure (global_State *g, Closure *cl) { |  | ||||||
|   markobject(g, cl->c.env); |  | ||||||
|   if (cl->c.isC) { |  | ||||||
|     int i; |  | ||||||
|     for (i=0; i<cl->c.nupvalues; i++)  /* mark its upvalues */ |  | ||||||
|       markvalue(g, &cl->c.upvalue[i]); |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     int i; |  | ||||||
|     lua_assert(cl->l.nupvalues == cl->l.p->nups); |  | ||||||
|     markobject(g, cl->l.p); |  | ||||||
|     for (i=0; i<cl->l.nupvalues; i++)  /* mark its upvalues */ |  | ||||||
|       markobject(g, cl->l.upvals[i]); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void checkstacksizes (lua_State *L, StkId max) { |  | ||||||
|   int ci_used = cast_int(L->ci - L->base_ci);  /* number of `ci' in use */ |  | ||||||
|   int s_used = cast_int(max - L->stack);  /* part of stack in use */ |  | ||||||
|   if (L->size_ci > LUAI_MAXCALLS)  /* handling overflow? */ |  | ||||||
|     return;  /* do not touch the stacks */ |  | ||||||
|   if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) |  | ||||||
|     luaD_reallocCI(L, L->size_ci/2);  /* still big enough... */ |  | ||||||
|   condhardstacktests(luaD_reallocCI(L, ci_used + 1)); |  | ||||||
|   if (4*s_used < L->stacksize && |  | ||||||
|       2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) |  | ||||||
|     luaD_reallocstack(L, L->stacksize/2);  /* still big enough... */ |  | ||||||
|   condhardstacktests(luaD_reallocstack(L, s_used)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void traversestack (global_State *g, lua_State *l) { |  | ||||||
|   StkId o, lim; |  | ||||||
|   CallInfo *ci; |  | ||||||
|   markvalue(g, gt(l)); |  | ||||||
|   lim = l->top; |  | ||||||
|   for (ci = l->base_ci; ci <= l->ci; ci++) { |  | ||||||
|     lua_assert(ci->top <= l->stack_last); |  | ||||||
|     if (lim < ci->top) lim = ci->top; |  | ||||||
|   } |  | ||||||
|   for (o = l->stack; o < l->top; o++) |  | ||||||
|     markvalue(g, o); |  | ||||||
|   for (; o <= lim; o++) |  | ||||||
|     setnilvalue(o); |  | ||||||
|   checkstacksizes(l, lim); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** traverse one gray object, turning it to black. |  | ||||||
| ** Returns `quantity' traversed. |  | ||||||
| */ |  | ||||||
| static l_mem propagatemark (global_State *g) { |  | ||||||
|   GCObject *o = g->gray; |  | ||||||
|   lua_assert(isgray(o)); |  | ||||||
|   gray2black(o); |  | ||||||
|   switch (o->gch.tt) { |  | ||||||
|     case LUA_TTABLE: { |  | ||||||
|       Table *h = gco2h(o); |  | ||||||
|       g->gray = h->gclist; |  | ||||||
|       if (traversetable(g, h))  /* table is weak? */ |  | ||||||
|         black2gray(o);  /* keep it gray */ |  | ||||||
|       return sizeof(Table) + sizeof(TValue) * h->sizearray + |  | ||||||
|                              sizeof(Node) * sizenode(h); |  | ||||||
|     } |  | ||||||
|     case LUA_TFUNCTION: { |  | ||||||
|       Closure *cl = gco2cl(o); |  | ||||||
|       g->gray = cl->c.gclist; |  | ||||||
|       traverseclosure(g, cl); |  | ||||||
|       return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : |  | ||||||
|                            sizeLclosure(cl->l.nupvalues); |  | ||||||
|     } |  | ||||||
|     case LUA_TTHREAD: { |  | ||||||
|       lua_State *th = gco2th(o); |  | ||||||
|       g->gray = th->gclist; |  | ||||||
|       th->gclist = g->grayagain; |  | ||||||
|       g->grayagain = o; |  | ||||||
|       black2gray(o); |  | ||||||
|       traversestack(g, th); |  | ||||||
|       return sizeof(lua_State) + sizeof(TValue) * th->stacksize + |  | ||||||
|                                  sizeof(CallInfo) * th->size_ci; |  | ||||||
|     } |  | ||||||
|     case LUA_TPROTO: { |  | ||||||
|       Proto *p = gco2p(o); |  | ||||||
|       g->gray = p->gclist; |  | ||||||
|       traverseproto(g, p); |  | ||||||
|       return sizeof(Proto) + sizeof(Instruction) * p->sizecode + |  | ||||||
|                              sizeof(Proto *) * p->sizep + |  | ||||||
|                              sizeof(TValue) * p->sizek +  |  | ||||||
|                              sizeof(int) * p->sizelineinfo + |  | ||||||
|                              sizeof(LocVar) * p->sizelocvars + |  | ||||||
|                              sizeof(TString *) * p->sizeupvalues; |  | ||||||
|     } |  | ||||||
|     default: lua_assert(0); return 0; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void propagateall (global_State *g) { |  | ||||||
|   while (g->gray) propagatemark(g); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** The next function tells whether a key or value can be cleared from |  | ||||||
| ** a weak table. Non-collectable objects are never removed from weak |  | ||||||
| ** tables. Strings behave as `values', so are never removed too. for |  | ||||||
| ** other objects: if really collected, cannot keep them; for userdata |  | ||||||
| ** being finalized, keep them in keys, but not in values |  | ||||||
| */ |  | ||||||
| static int iscleared (const TValue *o, int iskey) { |  | ||||||
|   if (!iscollectable(o)) return 0; |  | ||||||
|   if (ttisstring(o)) { |  | ||||||
|     stringmark(rawtsvalue(o));  /* strings are `values', so are never weak */ |  | ||||||
|     return 0; |  | ||||||
|   } |  | ||||||
|   return iswhite(gcvalue(o)) || |  | ||||||
|     (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** clear collected entries from weaktables |  | ||||||
| */ |  | ||||||
| static void cleartable (GCObject *l) { |  | ||||||
|   while (l) { |  | ||||||
|     Table *h = gco2h(l); |  | ||||||
|     int i = h->sizearray; |  | ||||||
|     lua_assert(testbit(h->marked, VALUEWEAKBIT) || |  | ||||||
|                testbit(h->marked, KEYWEAKBIT)); |  | ||||||
|     if (testbit(h->marked, VALUEWEAKBIT)) { |  | ||||||
|       while (i--) { |  | ||||||
|         TValue *o = &h->array[i]; |  | ||||||
|         if (iscleared(o, 0))  /* value was collected? */ |  | ||||||
|           setnilvalue(o);  /* remove value */ |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     i = sizenode(h); |  | ||||||
|     while (i--) { |  | ||||||
|       Node *n = gnode(h, i); |  | ||||||
|       if (!ttisnil(gval(n)) &&  /* non-empty entry? */ |  | ||||||
|           (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { |  | ||||||
|         setnilvalue(gval(n));  /* remove value ... */ |  | ||||||
|         removeentry(n);  /* remove entry from table */ |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     l = h->gclist; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void freeobj (lua_State *L, GCObject *o) { |  | ||||||
|   switch (o->gch.tt) { |  | ||||||
|     case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; |  | ||||||
|     case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; |  | ||||||
|     case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; |  | ||||||
|     case LUA_TTABLE: luaH_free(L, gco2h(o)); break; |  | ||||||
|     case LUA_TTHREAD: { |  | ||||||
|       lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); |  | ||||||
|       luaE_freethread(L, gco2th(o)); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case LUA_TSTRING: { |  | ||||||
|       G(L)->strt.nuse--; |  | ||||||
|       luaM_freemem(L, o, sizestring(gco2ts(o))); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case LUA_TUSERDATA: { |  | ||||||
|       luaM_freemem(L, o, sizeudata(gco2u(o))); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     default: lua_assert(0); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define sweepwholelist(L,p)	sweeplist(L,p,MAX_LUMEM) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { |  | ||||||
|   GCObject *curr; |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   int deadmask = otherwhite(g); |  | ||||||
|   while ((curr = *p) != NULL && count-- > 0) { |  | ||||||
|     if (curr->gch.tt == LUA_TTHREAD)  /* sweep open upvalues of each thread */ |  | ||||||
|       sweepwholelist(L, &gco2th(curr)->openupval); |  | ||||||
|     if ((curr->gch.marked ^ WHITEBITS) & deadmask) {  /* not dead? */ |  | ||||||
|       lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); |  | ||||||
|       makewhite(g, curr);  /* make it white (for next cycle) */ |  | ||||||
|       p = &curr->gch.next; |  | ||||||
|     } |  | ||||||
|     else {  /* must erase `curr' */ |  | ||||||
|       lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); |  | ||||||
|       *p = curr->gch.next; |  | ||||||
|       if (curr == g->rootgc)  /* is the first element of the list? */ |  | ||||||
|         g->rootgc = curr->gch.next;  /* adjust first */ |  | ||||||
|       freeobj(L, curr); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return p; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void checkSizes (lua_State *L) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   /* check size of string hash */ |  | ||||||
|   if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && |  | ||||||
|       g->strt.size > MINSTRTABSIZE*2) |  | ||||||
|     luaS_resize(L, g->strt.size/2);  /* table is too big */ |  | ||||||
|   /* check size of buffer */ |  | ||||||
|   if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) {  /* buffer too big? */ |  | ||||||
|     size_t newsize = luaZ_sizebuffer(&g->buff) / 2; |  | ||||||
|     luaZ_resizebuffer(L, &g->buff, newsize); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void GCTM (lua_State *L) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   GCObject *o = g->tmudata->gch.next;  /* get first element */ |  | ||||||
|   Udata *udata = rawgco2u(o); |  | ||||||
|   const TValue *tm; |  | ||||||
|   /* remove udata from `tmudata' */ |  | ||||||
|   if (o == g->tmudata)  /* last element? */ |  | ||||||
|     g->tmudata = NULL; |  | ||||||
|   else |  | ||||||
|     g->tmudata->gch.next = udata->uv.next; |  | ||||||
|   udata->uv.next = g->mainthread->next;  /* return it to `root' list */ |  | ||||||
|   g->mainthread->next = o; |  | ||||||
|   makewhite(g, o); |  | ||||||
|   tm = fasttm(L, udata->uv.metatable, TM_GC); |  | ||||||
|   if (tm != NULL) { |  | ||||||
|     lu_byte oldah = L->allowhook; |  | ||||||
|     lu_mem oldt = g->GCthreshold; |  | ||||||
|     L->allowhook = 0;  /* stop debug hooks during GC tag method */ |  | ||||||
|     g->GCthreshold = 2*g->totalbytes;  /* avoid GC steps */ |  | ||||||
|     setobj2s(L, L->top, tm); |  | ||||||
|     setuvalue(L, L->top+1, udata); |  | ||||||
|     L->top += 2; |  | ||||||
|     luaD_call(L, L->top - 2, 0); |  | ||||||
|     L->allowhook = oldah;  /* restore hooks */ |  | ||||||
|     g->GCthreshold = oldt;  /* restore threshold */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Call all GC tag methods |  | ||||||
| */ |  | ||||||
| void luaC_callGCTM (lua_State *L) { |  | ||||||
|   while (G(L)->tmudata) |  | ||||||
|     GCTM(L); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaC_freeall (lua_State *L) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   int i; |  | ||||||
|   g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT);  /* mask to collect all elements */ |  | ||||||
|   sweepwholelist(L, &g->rootgc); |  | ||||||
|   for (i = 0; i < g->strt.size; i++)  /* free all string lists */ |  | ||||||
|     sweepwholelist(L, &g->strt.hash[i]); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void markmt (global_State *g) { |  | ||||||
|   int i; |  | ||||||
|   for (i=0; i<NUM_TAGS; i++) |  | ||||||
|     if (g->mt[i]) markobject(g, g->mt[i]); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* mark root set */ |  | ||||||
| static void markroot (lua_State *L) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   g->gray = NULL; |  | ||||||
|   g->grayagain = NULL; |  | ||||||
|   g->weak = NULL; |  | ||||||
|   markobject(g, g->mainthread); |  | ||||||
|   /* make global table be traversed before main stack */ |  | ||||||
|   markvalue(g, gt(g->mainthread)); |  | ||||||
|   markvalue(g, registry(L)); |  | ||||||
|   markmt(g); |  | ||||||
|   g->gcstate = GCSpropagate; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void remarkupvals (global_State *g) { |  | ||||||
|   UpVal *uv; |  | ||||||
|   for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { |  | ||||||
|     lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); |  | ||||||
|     if (isgray(obj2gco(uv))) |  | ||||||
|       markvalue(g, uv->v); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void atomic (lua_State *L) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   size_t udsize;  /* total size of userdata to be finalized */ |  | ||||||
|   /* remark occasional upvalues of (maybe) dead threads */ |  | ||||||
|   remarkupvals(g); |  | ||||||
|   /* traverse objects cautch by write barrier and by 'remarkupvals' */ |  | ||||||
|   propagateall(g); |  | ||||||
|   /* remark weak tables */ |  | ||||||
|   g->gray = g->weak; |  | ||||||
|   g->weak = NULL; |  | ||||||
|   lua_assert(!iswhite(obj2gco(g->mainthread))); |  | ||||||
|   markobject(g, L);  /* mark running thread */ |  | ||||||
|   markmt(g);  /* mark basic metatables (again) */ |  | ||||||
|   propagateall(g); |  | ||||||
|   /* remark gray again */ |  | ||||||
|   g->gray = g->grayagain; |  | ||||||
|   g->grayagain = NULL; |  | ||||||
|   propagateall(g); |  | ||||||
|   udsize = luaC_separateudata(L, 0);  /* separate userdata to be finalized */ |  | ||||||
|   marktmu(g);  /* mark `preserved' userdata */ |  | ||||||
|   propagateall(g);  /* remark, to propagate `preserveness' */ |  | ||||||
|   cleartable(g->weak);  /* remove collected objects from weak tables */ |  | ||||||
|   /* flip current white */ |  | ||||||
|   g->currentwhite = cast_byte(otherwhite(g)); |  | ||||||
|   g->sweepstrgc = 0; |  | ||||||
|   g->sweepgc = &g->rootgc; |  | ||||||
|   g->gcstate = GCSsweepstring; |  | ||||||
|   g->estimate = g->totalbytes - udsize;  /* first estimate */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static l_mem singlestep (lua_State *L) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   /*lua_checkmemory(L);*/ |  | ||||||
|   switch (g->gcstate) { |  | ||||||
|     case GCSpause: { |  | ||||||
|       markroot(L);  /* start a new collection */ |  | ||||||
|       return 0; |  | ||||||
|     } |  | ||||||
|     case GCSpropagate: { |  | ||||||
|       if (g->gray) |  | ||||||
|         return propagatemark(g); |  | ||||||
|       else {  /* no more `gray' objects */ |  | ||||||
|         atomic(L);  /* finish mark phase */ |  | ||||||
|         return 0; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     case GCSsweepstring: { |  | ||||||
|       lu_mem old = g->totalbytes; |  | ||||||
|       sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); |  | ||||||
|       if (g->sweepstrgc >= g->strt.size)  /* nothing more to sweep? */ |  | ||||||
|         g->gcstate = GCSsweep;  /* end sweep-string phase */ |  | ||||||
|       lua_assert(old >= g->totalbytes); |  | ||||||
|       g->estimate -= old - g->totalbytes; |  | ||||||
|       return GCSWEEPCOST; |  | ||||||
|     } |  | ||||||
|     case GCSsweep: { |  | ||||||
|       lu_mem old = g->totalbytes; |  | ||||||
|       g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); |  | ||||||
|       if (*g->sweepgc == NULL) {  /* nothing more to sweep? */ |  | ||||||
|         checkSizes(L); |  | ||||||
|         g->gcstate = GCSfinalize;  /* end sweep phase */ |  | ||||||
|       } |  | ||||||
|       lua_assert(old >= g->totalbytes); |  | ||||||
|       g->estimate -= old - g->totalbytes; |  | ||||||
|       return GCSWEEPMAX*GCSWEEPCOST; |  | ||||||
|     } |  | ||||||
|     case GCSfinalize: { |  | ||||||
|       if (g->tmudata) { |  | ||||||
|         GCTM(L); |  | ||||||
|         return GCFINALIZECOST; |  | ||||||
|       } |  | ||||||
|       else { |  | ||||||
|         g->gcstate = GCSpause;  /* end collection */ |  | ||||||
|         g->gcdept = 0; |  | ||||||
|         return 0; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     default: lua_assert(0); return 0; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaC_step (lua_State *L) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; |  | ||||||
|   if (lim == 0) |  | ||||||
|     lim = (MAX_LUMEM-1)/2;  /* no limit */ |  | ||||||
|   g->gcdept += g->totalbytes - g->GCthreshold; |  | ||||||
|   do { |  | ||||||
|     lim -= singlestep(L); |  | ||||||
|     if (g->gcstate == GCSpause) |  | ||||||
|       break; |  | ||||||
|   } while (lim > 0); |  | ||||||
|   if (g->gcstate != GCSpause) { |  | ||||||
|     if (g->gcdept < GCSTEPSIZE) |  | ||||||
|       g->GCthreshold = g->totalbytes + GCSTEPSIZE;  /* - lim/g->gcstepmul;*/ |  | ||||||
|     else { |  | ||||||
|       g->gcdept -= GCSTEPSIZE; |  | ||||||
|       g->GCthreshold = g->totalbytes; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     lua_assert(g->totalbytes >= g->estimate); |  | ||||||
|     setthreshold(g); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaC_fullgc (lua_State *L) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   if (g->gcstate <= GCSpropagate) { |  | ||||||
|     /* reset sweep marks to sweep all elements (returning them to white) */ |  | ||||||
|     g->sweepstrgc = 0; |  | ||||||
|     g->sweepgc = &g->rootgc; |  | ||||||
|     /* reset other collector lists */ |  | ||||||
|     g->gray = NULL; |  | ||||||
|     g->grayagain = NULL; |  | ||||||
|     g->weak = NULL; |  | ||||||
|     g->gcstate = GCSsweepstring; |  | ||||||
|   } |  | ||||||
|   lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); |  | ||||||
|   /* finish any pending sweep phase */ |  | ||||||
|   while (g->gcstate != GCSfinalize) { |  | ||||||
|     lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); |  | ||||||
|     singlestep(L); |  | ||||||
|   } |  | ||||||
|   markroot(L); |  | ||||||
|   while (g->gcstate != GCSpause) { |  | ||||||
|     singlestep(L); |  | ||||||
|   } |  | ||||||
|   setthreshold(g); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); |  | ||||||
|   lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); |  | ||||||
|   lua_assert(ttype(&o->gch) != LUA_TTABLE); |  | ||||||
|   /* must keep invariant? */ |  | ||||||
|   if (g->gcstate == GCSpropagate) |  | ||||||
|     reallymarkobject(g, v);  /* restore invariant */ |  | ||||||
|   else  /* don't mind */ |  | ||||||
|     makewhite(g, o);  /* mark as white just to avoid other barriers */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaC_barrierback (lua_State *L, Table *t) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   GCObject *o = obj2gco(t); |  | ||||||
|   lua_assert(isblack(o) && !isdead(g, o)); |  | ||||||
|   lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); |  | ||||||
|   black2gray(o);  /* make table gray (again) */ |  | ||||||
|   t->gclist = g->grayagain; |  | ||||||
|   g->grayagain = o; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   o->gch.next = g->rootgc; |  | ||||||
|   g->rootgc = o; |  | ||||||
|   o->gch.marked = luaC_white(g); |  | ||||||
|   o->gch.tt = tt; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaC_linkupval (lua_State *L, UpVal *uv) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   GCObject *o = obj2gco(uv); |  | ||||||
|   o->gch.next = g->rootgc;  /* link upvalue into `rootgc' list */ |  | ||||||
|   g->rootgc = o; |  | ||||||
|   if (isgray(o)) {  |  | ||||||
|     if (g->gcstate == GCSpropagate) { |  | ||||||
|       gray2black(o);  /* closed upvalues need barrier */ |  | ||||||
|       luaC_barrier(L, uv, uv->v); |  | ||||||
|     } |  | ||||||
|     else {  /* sweep phase: sweep it (turning it into white) */ |  | ||||||
|       makewhite(g, o); |  | ||||||
|       lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										110
									
								
								src/lua/lgc.h
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								src/lua/lgc.h
									
									
									
									
									
								
							| @@ -1,110 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lgc.h,v 2.15 2005/08/24 16:15:49 roberto Exp $ |  | ||||||
| ** Garbage Collector |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef lgc_h |  | ||||||
| #define lgc_h |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "lobject.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Possible states of the Garbage Collector |  | ||||||
| */ |  | ||||||
| #define GCSpause	0 |  | ||||||
| #define GCSpropagate	1 |  | ||||||
| #define GCSsweepstring	2 |  | ||||||
| #define GCSsweep	3 |  | ||||||
| #define GCSfinalize	4 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** some userful bit tricks |  | ||||||
| */ |  | ||||||
| #define resetbits(x,m)	((x) &= cast(lu_byte, ~(m))) |  | ||||||
| #define setbits(x,m)	((x) |= (m)) |  | ||||||
| #define testbits(x,m)	((x) & (m)) |  | ||||||
| #define bitmask(b)	(1<<(b)) |  | ||||||
| #define bit2mask(b1,b2)	(bitmask(b1) | bitmask(b2)) |  | ||||||
| #define l_setbit(x,b)	setbits(x, bitmask(b)) |  | ||||||
| #define resetbit(x,b)	resetbits(x, bitmask(b)) |  | ||||||
| #define testbit(x,b)	testbits(x, bitmask(b)) |  | ||||||
| #define set2bits(x,b1,b2)	setbits(x, (bit2mask(b1, b2))) |  | ||||||
| #define reset2bits(x,b1,b2)	resetbits(x, (bit2mask(b1, b2))) |  | ||||||
| #define test2bits(x,b1,b2)	testbits(x, (bit2mask(b1, b2))) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Layout for bit use in `marked' field: |  | ||||||
| ** bit 0 - object is white (type 0) |  | ||||||
| ** bit 1 - object is white (type 1) |  | ||||||
| ** bit 2 - object is black |  | ||||||
| ** bit 3 - for userdata: has been finalized |  | ||||||
| ** bit 3 - for tables: has weak keys |  | ||||||
| ** bit 4 - for tables: has weak values |  | ||||||
| ** bit 5 - object is fixed (should not be collected) |  | ||||||
| ** bit 6 - object is "super" fixed (only the main thread) |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define WHITE0BIT	0 |  | ||||||
| #define WHITE1BIT	1 |  | ||||||
| #define BLACKBIT	2 |  | ||||||
| #define FINALIZEDBIT	3 |  | ||||||
| #define KEYWEAKBIT	3 |  | ||||||
| #define VALUEWEAKBIT	4 |  | ||||||
| #define FIXEDBIT	5 |  | ||||||
| #define SFIXEDBIT	6 |  | ||||||
| #define WHITEBITS	bit2mask(WHITE0BIT, WHITE1BIT) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define iswhite(x)      test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) |  | ||||||
| #define isblack(x)      testbit((x)->gch.marked, BLACKBIT) |  | ||||||
| #define isgray(x)	(!isblack(x) && !iswhite(x)) |  | ||||||
|  |  | ||||||
| #define otherwhite(g)	(g->currentwhite ^ WHITEBITS) |  | ||||||
| #define isdead(g,v)	((v)->gch.marked & otherwhite(g) & WHITEBITS) |  | ||||||
|  |  | ||||||
| #define changewhite(x)	((x)->gch.marked ^= WHITEBITS) |  | ||||||
| #define gray2black(x)	l_setbit((x)->gch.marked, BLACKBIT) |  | ||||||
|  |  | ||||||
| #define valiswhite(x)	(iscollectable(x) && iswhite(gcvalue(x))) |  | ||||||
|  |  | ||||||
| #define luaC_white(g)	cast(lu_byte, (g)->currentwhite & WHITEBITS) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define luaC_checkGC(L) { \ |  | ||||||
|   condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \ |  | ||||||
|   if (G(L)->totalbytes >= G(L)->GCthreshold) \ |  | ||||||
| 	luaC_step(L); } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p)))  \ |  | ||||||
| 	luaC_barrierf(L,obj2gco(p),gcvalue(v)); } |  | ||||||
|  |  | ||||||
| #define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t)))  \ |  | ||||||
| 	luaC_barrierback(L,t); } |  | ||||||
|  |  | ||||||
| #define luaC_objbarrier(L,p,o)  \ |  | ||||||
| 	{ if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ |  | ||||||
| 		luaC_barrierf(L,obj2gco(p),obj2gco(o)); } |  | ||||||
|  |  | ||||||
| #define luaC_objbarriert(L,t,o)  \ |  | ||||||
|    { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } |  | ||||||
|  |  | ||||||
| LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all); |  | ||||||
| LUAI_FUNC void luaC_callGCTM (lua_State *L); |  | ||||||
| LUAI_FUNC void luaC_freeall (lua_State *L); |  | ||||||
| LUAI_FUNC void luaC_step (lua_State *L); |  | ||||||
| LUAI_FUNC void luaC_fullgc (lua_State *L); |  | ||||||
| LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt); |  | ||||||
| LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); |  | ||||||
| LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); |  | ||||||
| LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,38 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: linit.c,v 1.14 2005/12/29 15:32:11 roberto Exp $ |  | ||||||
| ** Initialization of libraries for lua.c |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define linit_c |  | ||||||
| #define LUA_LIB |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lualib.h" |  | ||||||
| #include "lauxlib.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const luaL_Reg lualibs[] = { |  | ||||||
|   {"", luaopen_base}, |  | ||||||
|   {LUA_LOADLIBNAME, luaopen_package}, |  | ||||||
|   {LUA_TABLIBNAME, luaopen_table}, |  | ||||||
|   {LUA_IOLIBNAME, luaopen_io}, |  | ||||||
|   {LUA_OSLIBNAME, luaopen_os}, |  | ||||||
|   {LUA_STRLIBNAME, luaopen_string}, |  | ||||||
|   {LUA_MATHLIBNAME, luaopen_math}, |  | ||||||
|   {LUA_DBLIBNAME, luaopen_debug}, |  | ||||||
|   {NULL, NULL} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API void luaL_openlibs (lua_State *L) { |  | ||||||
|   const luaL_Reg *lib = lualibs; |  | ||||||
|   for (; lib->func; lib++) { |  | ||||||
|     lua_pushcfunction(L, lib->func); |  | ||||||
|     lua_pushstring(L, lib->name); |  | ||||||
|     lua_call(L, 1, 0); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										532
									
								
								src/lua/liolib.c
									
									
									
									
									
								
							
							
						
						
									
										532
									
								
								src/lua/liolib.c
									
									
									
									
									
								
							| @@ -1,532 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: liolib.c,v 2.72 2006/01/28 12:59:13 roberto Exp $ |  | ||||||
| ** Standard I/O (and system) library |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <errno.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define liolib_c |  | ||||||
| #define LUA_LIB |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lauxlib.h" |  | ||||||
| #include "lualib.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define IO_INPUT	1 |  | ||||||
| #define IO_OUTPUT	2 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *const fnames[] = {"input", "output"}; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int pushresult (lua_State *L, int i, const char *filename) { |  | ||||||
|   int en = errno;  /* calls to Lua API may change this value */ |  | ||||||
|   if (i) { |  | ||||||
|     lua_pushboolean(L, 1); |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     lua_pushnil(L); |  | ||||||
|     if (filename) |  | ||||||
|       lua_pushfstring(L, "%s: %s", filename, strerror(en)); |  | ||||||
|     else |  | ||||||
|       lua_pushfstring(L, "%s", strerror(en)); |  | ||||||
|     lua_pushinteger(L, en); |  | ||||||
|     return 3; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void fileerror (lua_State *L, int arg, const char *filename) { |  | ||||||
|   lua_pushfstring(L, "%s: %s", filename, strerror(errno)); |  | ||||||
|   luaL_argerror(L, arg, lua_tostring(L, -1)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define topfile(L)	((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_type (lua_State *L) { |  | ||||||
|   void *ud; |  | ||||||
|   luaL_checkany(L, 1); |  | ||||||
|   ud = lua_touserdata(L, 1); |  | ||||||
|   lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); |  | ||||||
|   if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) |  | ||||||
|     lua_pushnil(L);  /* not a file */ |  | ||||||
|   else if (*((FILE **)ud) == NULL) |  | ||||||
|     lua_pushliteral(L, "closed file"); |  | ||||||
|   else |  | ||||||
|     lua_pushliteral(L, "file"); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static FILE *tofile (lua_State *L) { |  | ||||||
|   FILE **f = topfile(L); |  | ||||||
|   if (*f == NULL) |  | ||||||
|     luaL_error(L, "attempt to use a closed file"); |  | ||||||
|   return *f; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** When creating file handles, always creates a `closed' file handle |  | ||||||
| ** before opening the actual file; so, if there is a memory error, the |  | ||||||
| ** file is not left opened. |  | ||||||
| */ |  | ||||||
| static FILE **newfile (lua_State *L) { |  | ||||||
|   FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); |  | ||||||
|   *pf = NULL;  /* file handle is currently `closed' */ |  | ||||||
|   luaL_getmetatable(L, LUA_FILEHANDLE); |  | ||||||
|   lua_setmetatable(L, -2); |  | ||||||
|   return pf; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** this function has a separated environment, which defines the |  | ||||||
| ** correct __close for 'popen' files |  | ||||||
| */ |  | ||||||
| static int io_pclose (lua_State *L) { |  | ||||||
|   FILE **p = topfile(L); |  | ||||||
|   int ok = lua_pclose(L, *p); |  | ||||||
|   if (ok) *p = NULL; |  | ||||||
|   return pushresult(L, ok, NULL); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_fclose (lua_State *L) { |  | ||||||
|   FILE **p = topfile(L); |  | ||||||
|   int ok = (fclose(*p) == 0); |  | ||||||
|   if (ok) *p = NULL; |  | ||||||
|   return pushresult(L, ok, NULL); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int aux_close (lua_State *L) { |  | ||||||
|   lua_getfenv(L, 1); |  | ||||||
|   lua_getfield(L, -1, "__close"); |  | ||||||
|   return (lua_tocfunction(L, -1))(L); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_close (lua_State *L) { |  | ||||||
|   if (lua_isnone(L, 1)) |  | ||||||
|     lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); |  | ||||||
|   tofile(L);  /* make sure argument is a file */ |  | ||||||
|   return aux_close(L); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_gc (lua_State *L) { |  | ||||||
|   FILE *f = *topfile(L); |  | ||||||
|   /* ignore closed files and standard files */ |  | ||||||
|   if (f != NULL && f != stdin && f != stdout && f != stderr) |  | ||||||
|     aux_close(L); |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_tostring (lua_State *L) { |  | ||||||
|   FILE *f = *topfile(L); |  | ||||||
|   if (f == NULL) |  | ||||||
|     lua_pushstring(L, "file (closed)"); |  | ||||||
|   else |  | ||||||
|     lua_pushfstring(L, "file (%p)", f); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_open (lua_State *L) { |  | ||||||
|   const char *filename = luaL_checkstring(L, 1); |  | ||||||
|   const char *mode = luaL_optstring(L, 2, "r"); |  | ||||||
|   FILE **pf = newfile(L); |  | ||||||
|   *pf = fopen(filename, mode); |  | ||||||
|   return (*pf == NULL) ? pushresult(L, 0, filename) : 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_popen (lua_State *L) { |  | ||||||
|   const char *filename = luaL_checkstring(L, 1); |  | ||||||
|   const char *mode = luaL_optstring(L, 2, "r"); |  | ||||||
|   FILE **pf = newfile(L); |  | ||||||
|   *pf = lua_popen(L, filename, mode); |  | ||||||
|   return (*pf == NULL) ? pushresult(L, 0, filename) : 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_tmpfile (lua_State *L) { |  | ||||||
|   FILE **pf = newfile(L); |  | ||||||
|   *pf = tmpfile(); |  | ||||||
|   return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static FILE *getiofile (lua_State *L, int findex) { |  | ||||||
|   FILE *f; |  | ||||||
|   lua_rawgeti(L, LUA_ENVIRONINDEX, findex); |  | ||||||
|   f = *(FILE **)lua_touserdata(L, -1); |  | ||||||
|   if (f == NULL) |  | ||||||
|     luaL_error(L, "standard %s file is closed", fnames[findex - 1]); |  | ||||||
|   return f; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int g_iofile (lua_State *L, int f, const char *mode) { |  | ||||||
|   if (!lua_isnoneornil(L, 1)) { |  | ||||||
|     const char *filename = lua_tostring(L, 1); |  | ||||||
|     if (filename) { |  | ||||||
|       FILE **pf = newfile(L); |  | ||||||
|       *pf = fopen(filename, mode); |  | ||||||
|       if (*pf == NULL) |  | ||||||
|         fileerror(L, 1, filename); |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|       tofile(L);  /* check that it's a valid file handle */ |  | ||||||
|       lua_pushvalue(L, 1); |  | ||||||
|     } |  | ||||||
|     lua_rawseti(L, LUA_ENVIRONINDEX, f); |  | ||||||
|   } |  | ||||||
|   /* return current value */ |  | ||||||
|   lua_rawgeti(L, LUA_ENVIRONINDEX, f); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_input (lua_State *L) { |  | ||||||
|   return g_iofile(L, IO_INPUT, "r"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_output (lua_State *L) { |  | ||||||
|   return g_iofile(L, IO_OUTPUT, "w"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_readline (lua_State *L); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void aux_lines (lua_State *L, int idx, int toclose) { |  | ||||||
|   lua_pushvalue(L, idx); |  | ||||||
|   lua_pushboolean(L, toclose);  /* close/not close file when finished */ |  | ||||||
|   lua_pushcclosure(L, io_readline, 2); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int f_lines (lua_State *L) { |  | ||||||
|   tofile(L);  /* check that it's a valid file handle */ |  | ||||||
|   aux_lines(L, 1, 0); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_lines (lua_State *L) { |  | ||||||
|   if (lua_isnoneornil(L, 1)) {  /* no arguments? */ |  | ||||||
|     /* will iterate over default input */ |  | ||||||
|     lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); |  | ||||||
|     return f_lines(L); |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     const char *filename = luaL_checkstring(L, 1); |  | ||||||
|     FILE **pf = newfile(L); |  | ||||||
|     *pf = fopen(filename, "r"); |  | ||||||
|     if (*pf == NULL) |  | ||||||
|       fileerror(L, 1, filename); |  | ||||||
|     aux_lines(L, lua_gettop(L), 1); |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** READ |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int read_number (lua_State *L, FILE *f) { |  | ||||||
|   lua_Number d; |  | ||||||
|   if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { |  | ||||||
|     lua_pushnumber(L, d); |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
|   else return 0;  /* read fails */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int test_eof (lua_State *L, FILE *f) { |  | ||||||
|   int c = getc(f); |  | ||||||
|   ungetc(c, f); |  | ||||||
|   lua_pushlstring(L, NULL, 0); |  | ||||||
|   return (c != EOF); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int read_line (lua_State *L, FILE *f) { |  | ||||||
|   luaL_Buffer b; |  | ||||||
|   luaL_buffinit(L, &b); |  | ||||||
|   for (;;) { |  | ||||||
|     size_t l; |  | ||||||
|     char *p = luaL_prepbuffer(&b); |  | ||||||
|     if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) {  /* eof? */ |  | ||||||
|       luaL_pushresult(&b);  /* close buffer */ |  | ||||||
|       return (lua_strlen(L, -1) > 0);  /* check whether read something */ |  | ||||||
|     } |  | ||||||
|     l = strlen(p); |  | ||||||
|     if (l == 0 || p[l-1] != '\n') |  | ||||||
|       luaL_addsize(&b, l); |  | ||||||
|     else { |  | ||||||
|       luaL_addsize(&b, l - 1);  /* do not include `eol' */ |  | ||||||
|       luaL_pushresult(&b);  /* close buffer */ |  | ||||||
|       return 1;  /* read at least an `eol' */ |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int read_chars (lua_State *L, FILE *f, size_t n) { |  | ||||||
|   size_t rlen;  /* how much to read */ |  | ||||||
|   size_t nr;  /* number of chars actually read */ |  | ||||||
|   luaL_Buffer b; |  | ||||||
|   luaL_buffinit(L, &b); |  | ||||||
|   rlen = LUAL_BUFFERSIZE;  /* try to read that much each time */ |  | ||||||
|   do { |  | ||||||
|     char *p = luaL_prepbuffer(&b); |  | ||||||
|     if (rlen > n) rlen = n;  /* cannot read more than asked */ |  | ||||||
|     nr = fread(p, sizeof(char), rlen, f); |  | ||||||
|     luaL_addsize(&b, nr); |  | ||||||
|     n -= nr;  /* still have to read `n' chars */ |  | ||||||
|   } while (n > 0 && nr == rlen);  /* until end of count or eof */ |  | ||||||
|   luaL_pushresult(&b);  /* close buffer */ |  | ||||||
|   return (n == 0 || lua_strlen(L, -1) > 0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int g_read (lua_State *L, FILE *f, int first) { |  | ||||||
|   int nargs = lua_gettop(L) - 1; |  | ||||||
|   int success; |  | ||||||
|   int n; |  | ||||||
|   clearerr(f); |  | ||||||
|   if (nargs == 0) {  /* no arguments? */ |  | ||||||
|     success = read_line(L, f); |  | ||||||
|     n = first+1;  /* to return 1 result */ |  | ||||||
|   } |  | ||||||
|   else {  /* ensure stack space for all results and for auxlib's buffer */ |  | ||||||
|     luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); |  | ||||||
|     success = 1; |  | ||||||
|     for (n = first; nargs-- && success; n++) { |  | ||||||
|       if (lua_type(L, n) == LUA_TNUMBER) { |  | ||||||
|         size_t l = (size_t)lua_tointeger(L, n); |  | ||||||
|         success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); |  | ||||||
|       } |  | ||||||
|       else { |  | ||||||
|         const char *p = lua_tostring(L, n); |  | ||||||
|         luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); |  | ||||||
|         switch (p[1]) { |  | ||||||
|           case 'n':  /* number */ |  | ||||||
|             success = read_number(L, f); |  | ||||||
|             break; |  | ||||||
|           case 'l':  /* line */ |  | ||||||
|             success = read_line(L, f); |  | ||||||
|             break; |  | ||||||
|           case 'a':  /* file */ |  | ||||||
|             read_chars(L, f, ~((size_t)0));  /* read MAX_SIZE_T chars */ |  | ||||||
|             success = 1; /* always success */ |  | ||||||
|             break; |  | ||||||
|           default: |  | ||||||
|             return luaL_argerror(L, n, "invalid format"); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   if (ferror(f)) |  | ||||||
|     return pushresult(L, 0, NULL); |  | ||||||
|   if (!success) { |  | ||||||
|     lua_pop(L, 1);  /* remove last result */ |  | ||||||
|     lua_pushnil(L);  /* push nil instead */ |  | ||||||
|   } |  | ||||||
|   return n - first; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_read (lua_State *L) { |  | ||||||
|   return g_read(L, getiofile(L, IO_INPUT), 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int f_read (lua_State *L) { |  | ||||||
|   return g_read(L, tofile(L), 2); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_readline (lua_State *L) { |  | ||||||
|   FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); |  | ||||||
|   int sucess; |  | ||||||
|   if (f == NULL)  /* file is already closed? */ |  | ||||||
|     luaL_error(L, "file is already closed"); |  | ||||||
|   sucess = read_line(L, f); |  | ||||||
|   if (ferror(f)) |  | ||||||
|     return luaL_error(L, "%s", strerror(errno)); |  | ||||||
|   if (sucess) return 1; |  | ||||||
|   else {  /* EOF */ |  | ||||||
|     if (lua_toboolean(L, lua_upvalueindex(2))) {  /* generator created file? */ |  | ||||||
|       lua_settop(L, 0); |  | ||||||
|       lua_pushvalue(L, lua_upvalueindex(1)); |  | ||||||
|       aux_close(L);  /* close it */ |  | ||||||
|     } |  | ||||||
|     return 0; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int g_write (lua_State *L, FILE *f, int arg) { |  | ||||||
|   int nargs = lua_gettop(L) - 1; |  | ||||||
|   int status = 1; |  | ||||||
|   for (; nargs--; arg++) { |  | ||||||
|     if (lua_type(L, arg) == LUA_TNUMBER) { |  | ||||||
|       /* optimization: could be done exactly as for strings */ |  | ||||||
|       status = status && |  | ||||||
|           fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|       size_t l; |  | ||||||
|       const char *s = luaL_checklstring(L, arg, &l); |  | ||||||
|       status = status && (fwrite(s, sizeof(char), l, f) == l); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return pushresult(L, status, NULL); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_write (lua_State *L) { |  | ||||||
|   return g_write(L, getiofile(L, IO_OUTPUT), 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int f_write (lua_State *L) { |  | ||||||
|   return g_write(L, tofile(L), 2); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int f_seek (lua_State *L) { |  | ||||||
|   static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; |  | ||||||
|   static const char *const modenames[] = {"set", "cur", "end", NULL}; |  | ||||||
|   FILE *f = tofile(L); |  | ||||||
|   int op = luaL_checkoption(L, 2, "cur", modenames); |  | ||||||
|   long offset = luaL_optlong(L, 3, 0); |  | ||||||
|   op = fseek(f, offset, mode[op]); |  | ||||||
|   if (op) |  | ||||||
|     return pushresult(L, 0, NULL);  /* error */ |  | ||||||
|   else { |  | ||||||
|     lua_pushinteger(L, ftell(f)); |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int f_setvbuf (lua_State *L) { |  | ||||||
|   static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; |  | ||||||
|   static const char *const modenames[] = {"no", "full", "line", NULL}; |  | ||||||
|   FILE *f = tofile(L); |  | ||||||
|   int op = luaL_checkoption(L, 2, NULL, modenames); |  | ||||||
|   lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); |  | ||||||
|   int res = setvbuf(f, NULL, mode[op], sz); |  | ||||||
|   return pushresult(L, res == 0, NULL); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int io_flush (lua_State *L) { |  | ||||||
|   return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int f_flush (lua_State *L) { |  | ||||||
|   return pushresult(L, fflush(tofile(L)) == 0, NULL); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const luaL_Reg iolib[] = { |  | ||||||
|   {"close", io_close}, |  | ||||||
|   {"flush", io_flush}, |  | ||||||
|   {"input", io_input}, |  | ||||||
|   {"lines", io_lines}, |  | ||||||
|   {"open", io_open}, |  | ||||||
|   {"output", io_output}, |  | ||||||
|   {"popen", io_popen}, |  | ||||||
|   {"read", io_read}, |  | ||||||
|   {"tmpfile", io_tmpfile}, |  | ||||||
|   {"type", io_type}, |  | ||||||
|   {"write", io_write}, |  | ||||||
|   {NULL, NULL} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const luaL_Reg flib[] = { |  | ||||||
|   {"close", io_close}, |  | ||||||
|   {"flush", f_flush}, |  | ||||||
|   {"lines", f_lines}, |  | ||||||
|   {"read", f_read}, |  | ||||||
|   {"seek", f_seek}, |  | ||||||
|   {"setvbuf", f_setvbuf}, |  | ||||||
|   {"write", f_write}, |  | ||||||
|   {"__gc", io_gc}, |  | ||||||
|   {"__tostring", io_tostring}, |  | ||||||
|   {NULL, NULL} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void createmeta (lua_State *L) { |  | ||||||
|   luaL_newmetatable(L, LUA_FILEHANDLE);  /* create metatable for file handles */ |  | ||||||
|   lua_pushvalue(L, -1);  /* push metatable */ |  | ||||||
|   lua_setfield(L, -2, "__index");  /* metatable.__index = metatable */ |  | ||||||
|   luaL_register(L, NULL, flib);  /* file methods */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { |  | ||||||
|   *newfile(L) = f; |  | ||||||
|   if (k > 0) { |  | ||||||
|     lua_pushvalue(L, -1); |  | ||||||
|     lua_rawseti(L, LUA_ENVIRONINDEX, k); |  | ||||||
|   } |  | ||||||
|   lua_setfield(L, -2, fname); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaopen_io (lua_State *L) { |  | ||||||
|   createmeta(L); |  | ||||||
|   /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ |  | ||||||
|   lua_createtable(L, 2, 1); |  | ||||||
|   lua_replace(L, LUA_ENVIRONINDEX); |  | ||||||
|   /* open library */ |  | ||||||
|   luaL_register(L, LUA_IOLIBNAME, iolib); |  | ||||||
|   /* create (and set) default files */ |  | ||||||
|   createstdfile(L, stdin, IO_INPUT, "stdin"); |  | ||||||
|   createstdfile(L, stdout, IO_OUTPUT, "stdout"); |  | ||||||
|   createstdfile(L, stderr, 0, "stderr"); |  | ||||||
|   /* create environment for 'popen' */ |  | ||||||
|   lua_getfield(L, -1, "popen"); |  | ||||||
|   lua_createtable(L, 0, 1); |  | ||||||
|   lua_pushcfunction(L, io_pclose); |  | ||||||
|   lua_setfield(L, -2, "__close"); |  | ||||||
|   lua_setfenv(L, -2); |  | ||||||
|   lua_pop(L, 1);  /* pop 'popen' */ |  | ||||||
|   /* set default close function */ |  | ||||||
|   lua_pushcfunction(L, io_fclose); |  | ||||||
|   lua_setfield(L, LUA_ENVIRONINDEX, "__close"); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										460
									
								
								src/lua/llex.c
									
									
									
									
									
								
							
							
						
						
									
										460
									
								
								src/lua/llex.c
									
									
									
									
									
								
							| @@ -1,460 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: llex.c,v 2.19 2006/02/06 18:28:16 roberto Exp $ |  | ||||||
| ** Lexical Analyzer |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <ctype.h> |  | ||||||
| #include <locale.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define llex_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "ldo.h" |  | ||||||
| #include "llex.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lparser.h" |  | ||||||
| #include "lstate.h" |  | ||||||
| #include "lstring.h" |  | ||||||
| #include "lzio.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define next(ls) (ls->current = zgetc(ls->z)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define currIsNewline(ls)	(ls->current == '\n' || ls->current == '\r') |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* ORDER RESERVED */ |  | ||||||
| const char *const luaX_tokens [] = { |  | ||||||
|     "and", "break", "do", "else", "elseif", |  | ||||||
|     "end", "false", "for", "function", "if", |  | ||||||
|     "in", "local", "nil", "not", "or", "repeat", |  | ||||||
|     "return", "then", "true", "until", "while", |  | ||||||
|     "..", "...", "==", ">=", "<=", "~=", |  | ||||||
|     "<number>", "<name>", "<string>", "<eof>", |  | ||||||
|     NULL |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define save_and_next(ls) (save(ls, ls->current), next(ls)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void save (LexState *ls, int c) { |  | ||||||
|   Mbuffer *b = ls->buff; |  | ||||||
|   if (b->n + 1 > b->buffsize) { |  | ||||||
|     size_t newsize; |  | ||||||
|     if (b->buffsize >= MAX_SIZET/2) |  | ||||||
|       luaX_lexerror(ls, "lexical element too long", 0); |  | ||||||
|     newsize = b->buffsize * 2; |  | ||||||
|     luaZ_resizebuffer(ls->L, b, newsize); |  | ||||||
|   } |  | ||||||
|   b->buffer[b->n++] = cast(char, c); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaX_init (lua_State *L) { |  | ||||||
|   int i; |  | ||||||
|   for (i=0; i<NUM_RESERVED; i++) { |  | ||||||
|     TString *ts = luaS_new(L, luaX_tokens[i]); |  | ||||||
|     luaS_fix(ts);  /* reserved words are never collected */ |  | ||||||
|     lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN); |  | ||||||
|     ts->tsv.reserved = cast_byte(i+1);  /* reserved word */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define MAXSRC          80 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| const char *luaX_token2str (LexState *ls, int token) { |  | ||||||
|   if (token < FIRST_RESERVED) { |  | ||||||
|     lua_assert(token == cast(unsigned char, token)); |  | ||||||
|     return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : |  | ||||||
|                               luaO_pushfstring(ls->L, "%c", token); |  | ||||||
|   } |  | ||||||
|   else |  | ||||||
|     return luaX_tokens[token-FIRST_RESERVED]; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *txtToken (LexState *ls, int token) { |  | ||||||
|   switch (token) { |  | ||||||
|     case TK_NAME: |  | ||||||
|     case TK_STRING: |  | ||||||
|     case TK_NUMBER: |  | ||||||
|       save(ls, '\0'); |  | ||||||
|       return luaZ_buffer(ls->buff); |  | ||||||
|     default: |  | ||||||
|       return luaX_token2str(ls, token); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaX_lexerror (LexState *ls, const char *msg, int token) { |  | ||||||
|   char buff[MAXSRC]; |  | ||||||
|   luaO_chunkid(buff, getstr(ls->source), MAXSRC); |  | ||||||
|   msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); |  | ||||||
|   if (token) |  | ||||||
|     luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token)); |  | ||||||
|   luaD_throw(ls->L, LUA_ERRSYNTAX); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaX_syntaxerror (LexState *ls, const char *msg) { |  | ||||||
|   luaX_lexerror(ls, msg, ls->t.token); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| TString *luaX_newstring (LexState *ls, const char *str, size_t l) { |  | ||||||
|   lua_State *L = ls->L; |  | ||||||
|   TString *ts = luaS_newlstr(L, str, l); |  | ||||||
|   TValue *o = luaH_setstr(L, ls->fs->h, ts);  /* entry for `str' */ |  | ||||||
|   if (ttisnil(o)) |  | ||||||
|     setbvalue(o, 1);  /* make sure `str' will not be collected */ |  | ||||||
|   return ts; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void inclinenumber (LexState *ls) { |  | ||||||
|   int old = ls->current; |  | ||||||
|   lua_assert(currIsNewline(ls)); |  | ||||||
|   next(ls);  /* skip `\n' or `\r' */ |  | ||||||
|   if (currIsNewline(ls) && ls->current != old) |  | ||||||
|     next(ls);  /* skip `\n\r' or `\r\n' */ |  | ||||||
|   if (++ls->linenumber >= MAX_INT) |  | ||||||
|     luaX_syntaxerror(ls, "chunk has too many lines"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { |  | ||||||
|   ls->decpoint = '.'; |  | ||||||
|   ls->L = L; |  | ||||||
|   ls->lookahead.token = TK_EOS;  /* no look-ahead token */ |  | ||||||
|   ls->z = z; |  | ||||||
|   ls->fs = NULL; |  | ||||||
|   ls->linenumber = 1; |  | ||||||
|   ls->lastline = 1; |  | ||||||
|   ls->source = source; |  | ||||||
|   luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER);  /* initialize buffer */ |  | ||||||
|   next(ls);  /* read first char */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** ======================================================= |  | ||||||
| ** LEXICAL ANALYZER |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int check_next (LexState *ls, const char *set) { |  | ||||||
|   if (!strchr(set, ls->current)) |  | ||||||
|     return 0; |  | ||||||
|   save_and_next(ls); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void buffreplace (LexState *ls, char from, char to) { |  | ||||||
|   size_t n = luaZ_bufflen(ls->buff); |  | ||||||
|   char *p = luaZ_buffer(ls->buff); |  | ||||||
|   while (n--) |  | ||||||
|     if (p[n] == from) p[n] = to; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void trydecpoint (LexState *ls, SemInfo *seminfo) { |  | ||||||
|   /* format error: try to update decimal point separator */ |  | ||||||
|   struct lconv *cv = localeconv(); |  | ||||||
|   char old = ls->decpoint; |  | ||||||
|   ls->decpoint = (cv ? cv->decimal_point[0] : '.'); |  | ||||||
|   buffreplace(ls, old, ls->decpoint);  /* try updated decimal separator */ |  | ||||||
|   if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { |  | ||||||
|     /* format error with correct decimal point: no more options */ |  | ||||||
|     buffreplace(ls, ls->decpoint, '.');  /* undo change (for error message) */ |  | ||||||
|     luaX_lexerror(ls, "malformed number", TK_NUMBER); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* LUA_NUMBER */ |  | ||||||
| static void read_numeral (LexState *ls, SemInfo *seminfo) { |  | ||||||
|   lua_assert(isdigit(ls->current)); |  | ||||||
|   do { |  | ||||||
|     save_and_next(ls); |  | ||||||
|   } while (isdigit(ls->current) || ls->current == '.'); |  | ||||||
|   if (check_next(ls, "Ee"))  /* `E'? */ |  | ||||||
|     check_next(ls, "+-");  /* optional exponent sign */ |  | ||||||
|   while (isalnum(ls->current) || ls->current == '_') |  | ||||||
|     save_and_next(ls); |  | ||||||
|   save(ls, '\0'); |  | ||||||
|   buffreplace(ls, '.', ls->decpoint);  /* follow locale for decimal point */ |  | ||||||
|   if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r))  /* format error? */ |  | ||||||
|     trydecpoint(ls, seminfo); /* try to update decimal point separator */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int skip_sep (LexState *ls) { |  | ||||||
|   int count = 0; |  | ||||||
|   int s = ls->current; |  | ||||||
|   lua_assert(s == '[' || s == ']'); |  | ||||||
|   save_and_next(ls); |  | ||||||
|   while (ls->current == '=') { |  | ||||||
|     save_and_next(ls); |  | ||||||
|     count++; |  | ||||||
|   } |  | ||||||
|   return (ls->current == s) ? count : (-count) - 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { |  | ||||||
|   int cont = 0; |  | ||||||
|   (void)(cont);  /* avoid warnings when `cont' is not used */ |  | ||||||
|   save_and_next(ls);  /* skip 2nd `[' */ |  | ||||||
|   if (currIsNewline(ls))  /* string starts with a newline? */ |  | ||||||
|     inclinenumber(ls);  /* skip it */ |  | ||||||
|   for (;;) { |  | ||||||
|     switch (ls->current) { |  | ||||||
|       case EOZ: |  | ||||||
|         luaX_lexerror(ls, (seminfo) ? "unfinished long string" : |  | ||||||
|                                    "unfinished long comment", TK_EOS); |  | ||||||
|         break;  /* to avoid warnings */ |  | ||||||
| #if defined(LUA_COMPAT_LSTR) |  | ||||||
|       case '[': { |  | ||||||
|         if (skip_sep(ls) == sep) { |  | ||||||
|           save_and_next(ls);  /* skip 2nd `[' */ |  | ||||||
|           cont++; |  | ||||||
| #if LUA_COMPAT_LSTR == 1 |  | ||||||
|           if (sep == 0) |  | ||||||
|             luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); |  | ||||||
| #endif |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| #endif |  | ||||||
|       case ']': { |  | ||||||
|         if (skip_sep(ls) == sep) { |  | ||||||
|           save_and_next(ls);  /* skip 2nd `]' */ |  | ||||||
| #if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 |  | ||||||
|           cont--; |  | ||||||
|           if (sep == 0 && cont >= 0) break; |  | ||||||
| #endif |  | ||||||
|           goto endloop; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case '\n': |  | ||||||
|       case '\r': { |  | ||||||
|         save(ls, '\n'); |  | ||||||
|         inclinenumber(ls); |  | ||||||
|         if (!seminfo) luaZ_resetbuffer(ls->buff);  /* avoid wasting space */ |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       default: { |  | ||||||
|         if (seminfo) save_and_next(ls); |  | ||||||
|         else next(ls); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } endloop: |  | ||||||
|   if (seminfo) |  | ||||||
|     seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), |  | ||||||
|                                      luaZ_bufflen(ls->buff) - 2*(2 + sep)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void read_string (LexState *ls, int del, SemInfo *seminfo) { |  | ||||||
|   save_and_next(ls); |  | ||||||
|   while (ls->current != del) { |  | ||||||
|     switch (ls->current) { |  | ||||||
|       case EOZ: |  | ||||||
|         luaX_lexerror(ls, "unfinished string", TK_EOS); |  | ||||||
|         continue;  /* to avoid warnings */ |  | ||||||
|       case '\n': |  | ||||||
|       case '\r': |  | ||||||
|         luaX_lexerror(ls, "unfinished string", TK_STRING); |  | ||||||
|         continue;  /* to avoid warnings */ |  | ||||||
|       case '\\': { |  | ||||||
|         int c; |  | ||||||
|         next(ls);  /* do not save the `\' */ |  | ||||||
|         switch (ls->current) { |  | ||||||
|           case 'a': c = '\a'; break; |  | ||||||
|           case 'b': c = '\b'; break; |  | ||||||
|           case 'f': c = '\f'; break; |  | ||||||
|           case 'n': c = '\n'; break; |  | ||||||
|           case 'r': c = '\r'; break; |  | ||||||
|           case 't': c = '\t'; break; |  | ||||||
|           case 'v': c = '\v'; break; |  | ||||||
|           case '\n':  /* go through */ |  | ||||||
|           case '\r': save(ls, '\n'); inclinenumber(ls); continue; |  | ||||||
|           case EOZ: continue;  /* will raise an error next loop */ |  | ||||||
|           default: { |  | ||||||
|             if (!isdigit(ls->current)) |  | ||||||
|               save_and_next(ls);  /* handles \\, \", \', and \? */ |  | ||||||
|             else {  /* \xxx */ |  | ||||||
|               int i = 0; |  | ||||||
|               c = 0; |  | ||||||
|               do { |  | ||||||
|                 c = 10*c + (ls->current-'0'); |  | ||||||
|                 next(ls); |  | ||||||
|               } while (++i<3 && isdigit(ls->current)); |  | ||||||
|               if (c > UCHAR_MAX) |  | ||||||
|                 luaX_lexerror(ls, "escape sequence too large", TK_STRING); |  | ||||||
|               save(ls, c); |  | ||||||
|             } |  | ||||||
|             continue; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         save(ls, c); |  | ||||||
|         next(ls); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       default: |  | ||||||
|         save_and_next(ls); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   save_and_next(ls);  /* skip delimiter */ |  | ||||||
|   seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, |  | ||||||
|                                    luaZ_bufflen(ls->buff) - 2); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int llex (LexState *ls, SemInfo *seminfo) { |  | ||||||
|   luaZ_resetbuffer(ls->buff); |  | ||||||
|   for (;;) { |  | ||||||
|     switch (ls->current) { |  | ||||||
|       case '\n': |  | ||||||
|       case '\r': { |  | ||||||
|         inclinenumber(ls); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case '-': { |  | ||||||
|         next(ls); |  | ||||||
|         if (ls->current != '-') return '-'; |  | ||||||
|         /* else is a comment */ |  | ||||||
|         next(ls); |  | ||||||
|         if (ls->current == '[') { |  | ||||||
|           int sep = skip_sep(ls); |  | ||||||
|           luaZ_resetbuffer(ls->buff);  /* `skip_sep' may dirty the buffer */ |  | ||||||
|           if (sep >= 0) { |  | ||||||
|             read_long_string(ls, NULL, sep);  /* long comment */ |  | ||||||
|             luaZ_resetbuffer(ls->buff); |  | ||||||
|             continue; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         /* else short comment */ |  | ||||||
|         while (!currIsNewline(ls) && ls->current != EOZ) |  | ||||||
|           next(ls); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case '[': { |  | ||||||
|         int sep = skip_sep(ls); |  | ||||||
|         if (sep >= 0) { |  | ||||||
|           read_long_string(ls, seminfo, sep); |  | ||||||
|           return TK_STRING; |  | ||||||
|         } |  | ||||||
|         else if (sep == -1) return '['; |  | ||||||
|         else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING); |  | ||||||
|       } |  | ||||||
|       case '=': { |  | ||||||
|         next(ls); |  | ||||||
|         if (ls->current != '=') return '='; |  | ||||||
|         else { next(ls); return TK_EQ; } |  | ||||||
|       } |  | ||||||
|       case '<': { |  | ||||||
|         next(ls); |  | ||||||
|         if (ls->current != '=') return '<'; |  | ||||||
|         else { next(ls); return TK_LE; } |  | ||||||
|       } |  | ||||||
|       case '>': { |  | ||||||
|         next(ls); |  | ||||||
|         if (ls->current != '=') return '>'; |  | ||||||
|         else { next(ls); return TK_GE; } |  | ||||||
|       } |  | ||||||
|       case '~': { |  | ||||||
|         next(ls); |  | ||||||
|         if (ls->current != '=') return '~'; |  | ||||||
|         else { next(ls); return TK_NE; } |  | ||||||
|       } |  | ||||||
|       case '"': |  | ||||||
|       case '\'': { |  | ||||||
|         read_string(ls, ls->current, seminfo); |  | ||||||
|         return TK_STRING; |  | ||||||
|       } |  | ||||||
|       case '.': { |  | ||||||
|         save_and_next(ls); |  | ||||||
|         if (check_next(ls, ".")) { |  | ||||||
|           if (check_next(ls, ".")) |  | ||||||
|             return TK_DOTS;   /* ... */ |  | ||||||
|           else return TK_CONCAT;   /* .. */ |  | ||||||
|         } |  | ||||||
|         else if (!isdigit(ls->current)) return '.'; |  | ||||||
|         else { |  | ||||||
|           read_numeral(ls, seminfo); |  | ||||||
|           return TK_NUMBER; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       case EOZ: { |  | ||||||
|         return TK_EOS; |  | ||||||
|       } |  | ||||||
|       default: { |  | ||||||
|         if (isspace(ls->current)) { |  | ||||||
|           lua_assert(!currIsNewline(ls)); |  | ||||||
|           next(ls); |  | ||||||
|           continue; |  | ||||||
|         } |  | ||||||
|         else if (isdigit(ls->current)) { |  | ||||||
|           read_numeral(ls, seminfo); |  | ||||||
|           return TK_NUMBER; |  | ||||||
|         } |  | ||||||
|         else if (isalpha(ls->current) || ls->current == '_') { |  | ||||||
|           /* identifier or reserved word */ |  | ||||||
|           TString *ts; |  | ||||||
|           do { |  | ||||||
|             save_and_next(ls); |  | ||||||
|           } while (isalnum(ls->current) || ls->current == '_'); |  | ||||||
|           ts = luaX_newstring(ls, luaZ_buffer(ls->buff), |  | ||||||
|                                   luaZ_bufflen(ls->buff)); |  | ||||||
|           if (ts->tsv.reserved > 0)  /* reserved word? */ |  | ||||||
|             return ts->tsv.reserved - 1 + FIRST_RESERVED; |  | ||||||
|           else { |  | ||||||
|             seminfo->ts = ts; |  | ||||||
|             return TK_NAME; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|           int c = ls->current; |  | ||||||
|           next(ls); |  | ||||||
|           return c;  /* single-char tokens (+ - / ...) */ |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaX_next (LexState *ls) { |  | ||||||
|   ls->lastline = ls->linenumber; |  | ||||||
|   if (ls->lookahead.token != TK_EOS) {  /* is there a look-ahead token? */ |  | ||||||
|     ls->t = ls->lookahead;  /* use this one */ |  | ||||||
|     ls->lookahead.token = TK_EOS;  /* and discharge it */ |  | ||||||
|   } |  | ||||||
|   else |  | ||||||
|     ls->t.token = llex(ls, &ls->t.seminfo);  /* read next token */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaX_lookahead (LexState *ls) { |  | ||||||
|   lua_assert(ls->lookahead.token == TK_EOS); |  | ||||||
|   ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,81 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: llex.h,v 1.57 2005/12/07 15:43:05 roberto Exp $ |  | ||||||
| ** Lexical Analyzer |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef llex_h |  | ||||||
| #define llex_h |  | ||||||
|  |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lzio.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define FIRST_RESERVED	257 |  | ||||||
|  |  | ||||||
| /* maximum length of a reserved word */ |  | ||||||
| #define TOKEN_LEN	(sizeof("function")/sizeof(char)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| * WARNING: if you change the order of this enumeration, |  | ||||||
| * grep "ORDER RESERVED" |  | ||||||
| */ |  | ||||||
| enum RESERVED { |  | ||||||
|   /* terminal symbols denoted by reserved words */ |  | ||||||
|   TK_AND = FIRST_RESERVED, TK_BREAK, |  | ||||||
|   TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, |  | ||||||
|   TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, |  | ||||||
|   TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, |  | ||||||
|   /* other terminal symbols */ |  | ||||||
|   TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, |  | ||||||
|   TK_NAME, TK_STRING, TK_EOS |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /* number of reserved words */ |  | ||||||
| #define NUM_RESERVED	(cast(int, TK_WHILE-FIRST_RESERVED+1)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* array with token `names' */ |  | ||||||
| LUAI_DATA const char *const luaX_tokens []; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef union { |  | ||||||
|   lua_Number r; |  | ||||||
|   TString *ts; |  | ||||||
| } SemInfo;  /* semantics information */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct Token { |  | ||||||
|   int token; |  | ||||||
|   SemInfo seminfo; |  | ||||||
| } Token; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct LexState { |  | ||||||
|   int current;  /* current character (charint) */ |  | ||||||
|   int linenumber;  /* input line counter */ |  | ||||||
|   int lastline;  /* line of last token `consumed' */ |  | ||||||
|   Token t;  /* current token */ |  | ||||||
|   Token lookahead;  /* look ahead token */ |  | ||||||
|   struct FuncState *fs;  /* `FuncState' is private to the parser */ |  | ||||||
|   struct lua_State *L; |  | ||||||
|   ZIO *z;  /* input stream */ |  | ||||||
|   Mbuffer *buff;  /* buffer for tokens */ |  | ||||||
|   TString *source;  /* current source name */ |  | ||||||
|   char decpoint;  /* locale decimal point */ |  | ||||||
| } LexState; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUAI_FUNC void luaX_init (lua_State *L); |  | ||||||
| LUAI_FUNC void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, |  | ||||||
|                               TString *source); |  | ||||||
| LUAI_FUNC TString *luaX_newstring (LexState *LS, const char *str, size_t l); |  | ||||||
| LUAI_FUNC void luaX_next (LexState *ls); |  | ||||||
| LUAI_FUNC void luaX_lookahead (LexState *ls); |  | ||||||
| LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token); |  | ||||||
| LUAI_FUNC void luaX_syntaxerror (LexState *ls, const char *s); |  | ||||||
| LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,128 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: llimits.h,v 1.69 2005/12/27 17:12:00 roberto Exp $ |  | ||||||
| ** Limits, basic types, and some other `installation-dependent' definitions |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef llimits_h |  | ||||||
| #define llimits_h |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <limits.h> |  | ||||||
| #include <stddef.h> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef LUAI_UINT32 lu_int32; |  | ||||||
|  |  | ||||||
| typedef LUAI_UMEM lu_mem; |  | ||||||
|  |  | ||||||
| typedef LUAI_MEM l_mem; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* chars used as small naturals (so that `char' is reserved for characters) */ |  | ||||||
| typedef unsigned char lu_byte; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define MAX_SIZET	((size_t)(~(size_t)0)-2) |  | ||||||
|  |  | ||||||
| #define MAX_LUMEM	((lu_mem)(~(lu_mem)0)-2) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define MAX_INT (INT_MAX-2)  /* maximum value of an int (-2 for safety) */ |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** conversion of pointer to integer |  | ||||||
| ** this is for hashing only; there is no problem if the integer |  | ||||||
| ** cannot hold the whole pointer value |  | ||||||
| */ |  | ||||||
| #define IntPoint(p)  ((unsigned int)(lu_mem)(p)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* type to ensure maximum alignment */ |  | ||||||
| typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* result of a `usual argument conversion' over lua_Number */ |  | ||||||
| typedef LUAI_UACNUMBER l_uacNumber; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* internal assertions for in-house debugging */ |  | ||||||
| #ifdef lua_assert |  | ||||||
|  |  | ||||||
| #define check_exp(c,e)		(lua_assert(c), (e)) |  | ||||||
| #define api_check(l,e)		lua_assert(e) |  | ||||||
|  |  | ||||||
| #else |  | ||||||
|  |  | ||||||
| #define lua_assert(c)		((void)0) |  | ||||||
| #define check_exp(c,e)		(e) |  | ||||||
| #define api_check		luai_apicheck |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifndef UNUSED |  | ||||||
| #define UNUSED(x)	((void)(x))	/* to avoid warnings */ |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifndef cast |  | ||||||
| #define cast(t, exp)	((t)(exp)) |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #define cast_byte(i)	cast(lu_byte, (i)) |  | ||||||
| #define cast_num(i)	cast(lua_Number, (i)) |  | ||||||
| #define cast_int(i)	cast(int, (i)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** type for virtual-machine instructions |  | ||||||
| ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) |  | ||||||
| */ |  | ||||||
| typedef lu_int32 Instruction; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* maximum stack for a Lua function */ |  | ||||||
| #define MAXSTACK	250 |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* minimum size for the string table (must be power of 2) */ |  | ||||||
| #ifndef MINSTRTABSIZE |  | ||||||
| #define MINSTRTABSIZE	32 |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* minimum size for string buffer */ |  | ||||||
| #ifndef LUA_MINBUFFER |  | ||||||
| #define LUA_MINBUFFER	32 |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifndef lua_lock |  | ||||||
| #define lua_lock(L)     ((void) 0)  |  | ||||||
| #define lua_unlock(L)   ((void) 0) |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef luai_threadyield |  | ||||||
| #define luai_threadyield(L)     {lua_unlock(L); lua_lock(L);} |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** macro to control inclusion of some hard tests on stack reallocation |  | ||||||
| */  |  | ||||||
| #ifndef HARDSTACKTESTS |  | ||||||
| #define condhardstacktests(x)	((void)0) |  | ||||||
| #else |  | ||||||
| #define condhardstacktests(x)	x |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,263 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lmathlib.c,v 1.67 2005/08/26 17:36:32 roberto Exp $ |  | ||||||
| ** Standard mathematical library |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <math.h> |  | ||||||
|  |  | ||||||
| #define lmathlib_c |  | ||||||
| #define LUA_LIB |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lauxlib.h" |  | ||||||
| #include "lualib.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #undef PI |  | ||||||
| #define PI (3.14159265358979323846) |  | ||||||
| #define RADIANS_PER_DEGREE (PI/180.0) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int math_abs (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, fabs(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_sin (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, sin(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_sinh (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, sinh(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_cos (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, cos(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_cosh (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, cosh(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_tan (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, tan(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_tanh (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, tanh(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_asin (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, asin(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_acos (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, acos(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_atan (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, atan(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_atan2 (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_ceil (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, ceil(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_floor (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, floor(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_fmod (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_modf (lua_State *L) { |  | ||||||
|   double ip; |  | ||||||
|   double fp = modf(luaL_checknumber(L, 1), &ip); |  | ||||||
|   lua_pushnumber(L, ip); |  | ||||||
|   lua_pushnumber(L, fp); |  | ||||||
|   return 2; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_sqrt (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, sqrt(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_pow (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_log (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, log(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_log10 (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, log10(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_exp (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, exp(luaL_checknumber(L, 1))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_deg (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_rad (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_frexp (lua_State *L) { |  | ||||||
|   int e; |  | ||||||
|   lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e)); |  | ||||||
|   lua_pushinteger(L, e); |  | ||||||
|   return 2; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int math_ldexp (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int math_min (lua_State *L) { |  | ||||||
|   int n = lua_gettop(L);  /* number of arguments */ |  | ||||||
|   lua_Number dmin = luaL_checknumber(L, 1); |  | ||||||
|   int i; |  | ||||||
|   for (i=2; i<=n; i++) { |  | ||||||
|     lua_Number d = luaL_checknumber(L, i); |  | ||||||
|     if (d < dmin) |  | ||||||
|       dmin = d; |  | ||||||
|   } |  | ||||||
|   lua_pushnumber(L, dmin); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int math_max (lua_State *L) { |  | ||||||
|   int n = lua_gettop(L);  /* number of arguments */ |  | ||||||
|   lua_Number dmax = luaL_checknumber(L, 1); |  | ||||||
|   int i; |  | ||||||
|   for (i=2; i<=n; i++) { |  | ||||||
|     lua_Number d = luaL_checknumber(L, i); |  | ||||||
|     if (d > dmax) |  | ||||||
|       dmax = d; |  | ||||||
|   } |  | ||||||
|   lua_pushnumber(L, dmax); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int math_random (lua_State *L) { |  | ||||||
|   /* the `%' avoids the (rare) case of r==1, and is needed also because on |  | ||||||
|      some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ |  | ||||||
|   lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX; |  | ||||||
|   switch (lua_gettop(L)) {  /* check number of arguments */ |  | ||||||
|     case 0: {  /* no arguments */ |  | ||||||
|       lua_pushnumber(L, r);  /* Number between 0 and 1 */ |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case 1: {  /* only upper limit */ |  | ||||||
|       int u = luaL_checkint(L, 1); |  | ||||||
|       luaL_argcheck(L, 1<=u, 1, "interval is empty"); |  | ||||||
|       lua_pushnumber(L, floor(r*u)+1);  /* int between 1 and `u' */ |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case 2: {  /* lower and upper limits */ |  | ||||||
|       int l = luaL_checkint(L, 1); |  | ||||||
|       int u = luaL_checkint(L, 2); |  | ||||||
|       luaL_argcheck(L, l<=u, 2, "interval is empty"); |  | ||||||
|       lua_pushnumber(L, floor(r*(u-l+1))+l);  /* int between `l' and `u' */ |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     default: return luaL_error(L, "wrong number of arguments"); |  | ||||||
|   } |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int math_randomseed (lua_State *L) { |  | ||||||
|   srand(luaL_checkint(L, 1)); |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const luaL_Reg mathlib[] = { |  | ||||||
|   {"abs",   math_abs}, |  | ||||||
|   {"acos",  math_acos}, |  | ||||||
|   {"asin",  math_asin}, |  | ||||||
|   {"atan2", math_atan2}, |  | ||||||
|   {"atan",  math_atan}, |  | ||||||
|   {"ceil",  math_ceil}, |  | ||||||
|   {"cosh",   math_cosh}, |  | ||||||
|   {"cos",   math_cos}, |  | ||||||
|   {"deg",   math_deg}, |  | ||||||
|   {"exp",   math_exp}, |  | ||||||
|   {"floor", math_floor}, |  | ||||||
|   {"fmod",   math_fmod}, |  | ||||||
|   {"frexp", math_frexp}, |  | ||||||
|   {"ldexp", math_ldexp}, |  | ||||||
|   {"log10", math_log10}, |  | ||||||
|   {"log",   math_log}, |  | ||||||
|   {"max",   math_max}, |  | ||||||
|   {"min",   math_min}, |  | ||||||
|   {"modf",   math_modf}, |  | ||||||
|   {"pow",   math_pow}, |  | ||||||
|   {"rad",   math_rad}, |  | ||||||
|   {"random",     math_random}, |  | ||||||
|   {"randomseed", math_randomseed}, |  | ||||||
|   {"sinh",   math_sinh}, |  | ||||||
|   {"sin",   math_sin}, |  | ||||||
|   {"sqrt",  math_sqrt}, |  | ||||||
|   {"tanh",   math_tanh}, |  | ||||||
|   {"tan",   math_tan}, |  | ||||||
|   {NULL, NULL} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Open math library |  | ||||||
| */ |  | ||||||
| LUALIB_API int luaopen_math (lua_State *L) { |  | ||||||
|   luaL_register(L, LUA_MATHLIBNAME, mathlib); |  | ||||||
|   lua_pushnumber(L, PI); |  | ||||||
|   lua_setfield(L, -2, "pi"); |  | ||||||
|   lua_pushnumber(L, HUGE_VAL); |  | ||||||
|   lua_setfield(L, -2, "huge"); |  | ||||||
| #if defined(LUA_COMPAT_MOD) |  | ||||||
|   lua_getfield(L, -1, "fmod"); |  | ||||||
|   lua_setfield(L, -2, "mod"); |  | ||||||
| #endif |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,86 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lmem.c,v 1.70 2005/12/26 13:35:47 roberto Exp $ |  | ||||||
| ** Interface to Memory Manager |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <stddef.h> |  | ||||||
|  |  | ||||||
| #define lmem_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "ldebug.h" |  | ||||||
| #include "ldo.h" |  | ||||||
| #include "lmem.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lstate.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** About the realloc function: |  | ||||||
| ** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); |  | ||||||
| ** (`osize' is the old size, `nsize' is the new size) |  | ||||||
| ** |  | ||||||
| ** Lua ensures that (ptr == NULL) iff (osize == 0). |  | ||||||
| ** |  | ||||||
| ** * frealloc(ud, NULL, 0, x) creates a new block of size `x' |  | ||||||
| ** |  | ||||||
| ** * frealloc(ud, p, x, 0) frees the block `p' |  | ||||||
| ** (in this specific case, frealloc must return NULL). |  | ||||||
| ** particularly, frealloc(ud, NULL, 0, 0) does nothing |  | ||||||
| ** (which is equivalent to free(NULL) in ANSI C) |  | ||||||
| ** |  | ||||||
| ** frealloc returns NULL if it cannot create or reallocate the area |  | ||||||
| ** (any reallocation to an equal or smaller size cannot fail!) |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define MINSIZEARRAY	4 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, |  | ||||||
|                      int limit, const char *errormsg) { |  | ||||||
|   void *newblock; |  | ||||||
|   int newsize; |  | ||||||
|   if (*size >= limit/2) {  /* cannot double it? */ |  | ||||||
|     if (*size >= limit)  /* cannot grow even a little? */ |  | ||||||
|       luaG_runerror(L, errormsg); |  | ||||||
|     newsize = limit;  /* still have at least one free place */ |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     newsize = (*size)*2; |  | ||||||
|     if (newsize < MINSIZEARRAY) |  | ||||||
|       newsize = MINSIZEARRAY;  /* minimum size */ |  | ||||||
|   } |  | ||||||
|   newblock = luaM_reallocv(L, block, *size, newsize, size_elems); |  | ||||||
|   *size = newsize;  /* update only when everything else is OK */ |  | ||||||
|   return newblock; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void *luaM_toobig (lua_State *L) { |  | ||||||
|   luaG_runerror(L, "memory allocation error: block too big"); |  | ||||||
|   return NULL;  /* to avoid warnings */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** generic allocation routine. |  | ||||||
| */ |  | ||||||
| void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   lua_assert((osize == 0) == (block == NULL)); |  | ||||||
|   block = (*g->frealloc)(g->ud, block, osize, nsize); |  | ||||||
|   if (block == NULL && nsize > 0) |  | ||||||
|     luaD_throw(L, LUA_ERRMEM); |  | ||||||
|   lua_assert((nsize == 0) == (block == NULL)); |  | ||||||
|   g->totalbytes = (g->totalbytes - osize) + nsize; |  | ||||||
|   return block; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,49 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lmem.h,v 1.31 2005/04/25 19:24:10 roberto Exp $ |  | ||||||
| ** Interface to Memory Manager |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef lmem_h |  | ||||||
| #define lmem_h |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <stddef.h> |  | ||||||
|  |  | ||||||
| #include "llimits.h" |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #define MEMERRMSG	"not enough memory" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define luaM_reallocv(L,b,on,n,e) \ |  | ||||||
| 	((cast(size_t, (n)+1) <= MAX_SIZET/(e)) ?  /* +1 to avoid warnings */ \ |  | ||||||
| 		luaM_realloc_(L, (b), (on)*(e), (n)*(e)) : \ |  | ||||||
| 		luaM_toobig(L)) |  | ||||||
|  |  | ||||||
| #define luaM_freemem(L, b, s)	luaM_realloc_(L, (b), (s), 0) |  | ||||||
| #define luaM_free(L, b)		luaM_realloc_(L, (b), sizeof(*(b)), 0) |  | ||||||
| #define luaM_freearray(L, b, n, t)   luaM_reallocv(L, (b), n, 0, sizeof(t)) |  | ||||||
|  |  | ||||||
| #define luaM_malloc(L,t)	luaM_realloc_(L, NULL, 0, (t)) |  | ||||||
| #define luaM_new(L,t)		cast(t *, luaM_malloc(L, sizeof(t))) |  | ||||||
| #define luaM_newvector(L,n,t) \ |  | ||||||
| 		cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) |  | ||||||
|  |  | ||||||
| #define luaM_growvector(L,v,nelems,size,t,limit,e) \ |  | ||||||
|           if ((nelems)+1 > (size)) \ |  | ||||||
|             ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) |  | ||||||
|  |  | ||||||
| #define luaM_reallocvector(L, v,oldn,n,t) \ |  | ||||||
|    ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, |  | ||||||
|                                                           size_t size); |  | ||||||
| LUAI_FUNC void *luaM_toobig (lua_State *L); |  | ||||||
| LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, |  | ||||||
|                                size_t size_elem, int limit, |  | ||||||
|                                const char *errormsg); |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| @@ -1,667 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: loadlib.c,v 1.51 2005/12/29 15:32:11 roberto Exp $ |  | ||||||
| ** Dynamic library loader for Lua |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| ** |  | ||||||
| ** This module contains an implementation of loadlib for Unix systems |  | ||||||
| ** that have dlfcn, an implementation for Darwin (Mac OS X), an |  | ||||||
| ** implementation for Windows, and a stub for other systems. |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define loadlib_c |  | ||||||
| #define LUA_LIB |  | ||||||
|  |  | ||||||
| #include "lauxlib.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lua.h" |  | ||||||
| #include "lualib.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* environment variables that hold the search path for packages */ |  | ||||||
| #define LUA_PATH	"LUA_PATH" |  | ||||||
| #define LUA_CPATH	"LUA_CPATH" |  | ||||||
|  |  | ||||||
| /* prefix for open functions in C libraries */ |  | ||||||
| #define LUA_POF		"luaopen_" |  | ||||||
|  |  | ||||||
| /* separator for open functions in C libraries */ |  | ||||||
| #define LUA_OFSEP	"_" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define LIBPREFIX	"LOADLIB: " |  | ||||||
|  |  | ||||||
| #define POF		LUA_POF |  | ||||||
| #define LIB_FAIL	"open" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* error codes for ll_loadfunc */ |  | ||||||
| #define ERRLIB		1 |  | ||||||
| #define ERRFUNC		2 |  | ||||||
|  |  | ||||||
| #define setprogdir(L)		((void)0) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void ll_unloadlib (void *lib); |  | ||||||
| static void *ll_load (lua_State *L, const char *path); |  | ||||||
| static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #if defined(LUA_DL_DLOPEN) |  | ||||||
| /* |  | ||||||
| ** {======================================================================== |  | ||||||
| ** This is an implementation of loadlib based on the dlfcn interface. |  | ||||||
| ** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, |  | ||||||
| ** NetBSD, AIX 4.2, HPUX 11, and  probably most other Unix flavors, at least |  | ||||||
| ** as an emulation layer on top of native functions. |  | ||||||
| ** ========================================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #include <dlfcn.h> |  | ||||||
|  |  | ||||||
| static void ll_unloadlib (void *lib) { |  | ||||||
|   dlclose(lib); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void *ll_load (lua_State *L, const char *path) { |  | ||||||
|   void *lib = dlopen(path, RTLD_NOW); |  | ||||||
|   if (lib == NULL) lua_pushstring(L, dlerror()); |  | ||||||
|   return lib; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { |  | ||||||
|   lua_CFunction f = (lua_CFunction)dlsym(lib, sym); |  | ||||||
|   if (f == NULL) lua_pushstring(L, dlerror()); |  | ||||||
|   return f; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #elif defined(LUA_DL_DLL) |  | ||||||
| /* |  | ||||||
| ** {====================================================================== |  | ||||||
| ** This is an implementation of loadlib for Windows using native functions. |  | ||||||
| ** ======================================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #include <windows.h> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #undef setprogdir |  | ||||||
|  |  | ||||||
| static void setprogdir (lua_State *L) { |  | ||||||
|   char buff[MAX_PATH + 1]; |  | ||||||
|   char *lb; |  | ||||||
|   DWORD nsize = sizeof(buff)/sizeof(char); |  | ||||||
|   DWORD n = GetModuleFileName(NULL, buff, nsize); |  | ||||||
|   if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) |  | ||||||
|     luaL_error(L, "unable to get ModuleFileName"); |  | ||||||
|   else { |  | ||||||
|     *lb = '\0'; |  | ||||||
|     luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); |  | ||||||
|     lua_remove(L, -2);  /* remove original string */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void pusherror (lua_State *L) { |  | ||||||
|   int error = GetLastError(); |  | ||||||
|   char buffer[128]; |  | ||||||
|   if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, |  | ||||||
|       NULL, error, 0, buffer, sizeof(buffer), NULL)) |  | ||||||
|     lua_pushstring(L, buffer); |  | ||||||
|   else |  | ||||||
|     lua_pushfstring(L, "system error %d\n", error); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void ll_unloadlib (void *lib) { |  | ||||||
|   FreeLibrary((HINSTANCE)lib); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void *ll_load (lua_State *L, const char *path) { |  | ||||||
|   HINSTANCE lib = LoadLibrary(path); |  | ||||||
|   if (lib == NULL) pusherror(L); |  | ||||||
|   return lib; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { |  | ||||||
|   lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); |  | ||||||
|   if (f == NULL) pusherror(L); |  | ||||||
|   return f; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #elif defined(LUA_DL_DYLD) |  | ||||||
| /* |  | ||||||
| ** {====================================================================== |  | ||||||
| ** Native Mac OS X / Darwin Implementation |  | ||||||
| ** ======================================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #include <mach-o/dyld.h> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Mac appends a `_' before C function names */ |  | ||||||
| #undef POF |  | ||||||
| #define POF	"_" LUA_POF |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void pusherror (lua_State *L) { |  | ||||||
|   const char *err_str; |  | ||||||
|   const char *err_file; |  | ||||||
|   NSLinkEditErrors err; |  | ||||||
|   int err_num; |  | ||||||
|   NSLinkEditError(&err, &err_num, &err_file, &err_str); |  | ||||||
|   lua_pushstring(L, err_str); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *errorfromcode (NSObjectFileImageReturnCode ret) { |  | ||||||
|   switch (ret) { |  | ||||||
|     case NSObjectFileImageInappropriateFile: |  | ||||||
|       return "file is not a bundle"; |  | ||||||
|     case NSObjectFileImageArch: |  | ||||||
|       return "library is for wrong CPU type"; |  | ||||||
|     case NSObjectFileImageFormat: |  | ||||||
|       return "bad format"; |  | ||||||
|     case NSObjectFileImageAccess: |  | ||||||
|       return "cannot access file"; |  | ||||||
|     case NSObjectFileImageFailure: |  | ||||||
|     default: |  | ||||||
|       return "unable to load library"; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void ll_unloadlib (void *lib) { |  | ||||||
|   NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void *ll_load (lua_State *L, const char *path) { |  | ||||||
|   NSObjectFileImage img; |  | ||||||
|   NSObjectFileImageReturnCode ret; |  | ||||||
|   /* this would be a rare case, but prevents crashing if it happens */ |  | ||||||
|   if(!_dyld_present()) { |  | ||||||
|     lua_pushliteral(L, "dyld not present"); |  | ||||||
|     return NULL; |  | ||||||
|   } |  | ||||||
|   ret = NSCreateObjectFileImageFromFile(path, &img); |  | ||||||
|   if (ret == NSObjectFileImageSuccess) { |  | ||||||
|     NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | |  | ||||||
|                        NSLINKMODULE_OPTION_RETURN_ON_ERROR); |  | ||||||
|     NSDestroyObjectFileImage(img); |  | ||||||
|     if (mod == NULL) pusherror(L); |  | ||||||
|     return mod; |  | ||||||
|   } |  | ||||||
|   lua_pushstring(L, errorfromcode(ret)); |  | ||||||
|   return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { |  | ||||||
|   NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); |  | ||||||
|   if (nss == NULL) { |  | ||||||
|     lua_pushfstring(L, "symbol " LUA_QS " not found", sym); |  | ||||||
|     return NULL; |  | ||||||
|   } |  | ||||||
|   return (lua_CFunction)NSAddressOfSymbol(nss); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #else |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** Fallback for other systems |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #undef LIB_FAIL |  | ||||||
| #define LIB_FAIL	"absent" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define DLMSG	"dynamic libraries not enabled; check your Lua installation" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void ll_unloadlib (void *lib) { |  | ||||||
|   (void)lib;  /* to avoid warnings */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void *ll_load (lua_State *L, const char *path) { |  | ||||||
|   (void)path;  /* to avoid warnings */ |  | ||||||
|   lua_pushliteral(L, DLMSG); |  | ||||||
|   return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { |  | ||||||
|   (void)lib; (void)sym;  /* to avoid warnings */ |  | ||||||
|   lua_pushliteral(L, DLMSG); |  | ||||||
|   return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void **ll_register (lua_State *L, const char *path) { |  | ||||||
|   void **plib; |  | ||||||
|   lua_pushfstring(L, "%s%s", LIBPREFIX, path); |  | ||||||
|   lua_gettable(L, LUA_REGISTRYINDEX);  /* check library in registry? */ |  | ||||||
|   if (!lua_isnil(L, -1))  /* is there an entry? */ |  | ||||||
|     plib = (void **)lua_touserdata(L, -1); |  | ||||||
|   else {  /* no entry yet; create one */ |  | ||||||
|     lua_pop(L, 1); |  | ||||||
|     plib = (void **)lua_newuserdata(L, sizeof(const void *)); |  | ||||||
|     *plib = NULL; |  | ||||||
|     luaL_getmetatable(L, "_LOADLIB"); |  | ||||||
|     lua_setmetatable(L, -2); |  | ||||||
|     lua_pushfstring(L, "%s%s", LIBPREFIX, path); |  | ||||||
|     lua_pushvalue(L, -2); |  | ||||||
|     lua_settable(L, LUA_REGISTRYINDEX); |  | ||||||
|   } |  | ||||||
|   return plib; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** __gc tag method: calls library's `ll_unloadlib' function with the lib |  | ||||||
| ** handle |  | ||||||
| */ |  | ||||||
| static int gctm (lua_State *L) { |  | ||||||
|   void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); |  | ||||||
|   if (*lib) ll_unloadlib(*lib); |  | ||||||
|   *lib = NULL;  /* mark library as closed */ |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { |  | ||||||
|   void **reg = ll_register(L, path); |  | ||||||
|   if (*reg == NULL) *reg = ll_load(L, path); |  | ||||||
|   if (*reg == NULL) |  | ||||||
|     return ERRLIB;  /* unable to load library */ |  | ||||||
|   else { |  | ||||||
|     lua_CFunction f = ll_sym(L, *reg, sym); |  | ||||||
|     if (f == NULL) |  | ||||||
|       return ERRFUNC;  /* unable to find function */ |  | ||||||
|     lua_pushcfunction(L, f); |  | ||||||
|     return 0;  /* return function */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int ll_loadlib (lua_State *L) { |  | ||||||
|   const char *path = luaL_checkstring(L, 1); |  | ||||||
|   const char *init = luaL_checkstring(L, 2); |  | ||||||
|   int stat = ll_loadfunc(L, path, init); |  | ||||||
|   if (stat == 0)  /* no errors? */ |  | ||||||
|     return 1;  /* return the loaded function */ |  | ||||||
|   else {  /* error; error message is on stack top */ |  | ||||||
|     lua_pushnil(L); |  | ||||||
|     lua_insert(L, -2); |  | ||||||
|     lua_pushstring(L, (stat == ERRLIB) ?  LIB_FAIL : "init"); |  | ||||||
|     return 3;  /* return nil, error message, and where */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** 'require' function |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int readable (const char *filename) { |  | ||||||
|   FILE *f = fopen(filename, "r");  /* try to open file */ |  | ||||||
|   if (f == NULL) return 0;  /* open failed */ |  | ||||||
|   fclose(f); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *pushnexttemplate (lua_State *L, const char *path) { |  | ||||||
|   const char *l; |  | ||||||
|   while (*path == *LUA_PATHSEP) path++;  /* skip separators */ |  | ||||||
|   if (*path == '\0') return NULL;  /* no more templates */ |  | ||||||
|   l = strchr(path, *LUA_PATHSEP);  /* find next separator */ |  | ||||||
|   if (l == NULL) l = path + strlen(path); |  | ||||||
|   lua_pushlstring(L, path, l - path);  /* template */ |  | ||||||
|   return l; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *findfile (lua_State *L, const char *name, |  | ||||||
|                                            const char *pname) { |  | ||||||
|   const char *path; |  | ||||||
|   name = luaL_gsub(L, name, ".", LUA_DIRSEP); |  | ||||||
|   lua_getfield(L, LUA_ENVIRONINDEX, pname); |  | ||||||
|   path = lua_tostring(L, -1); |  | ||||||
|   if (path == NULL) |  | ||||||
|     luaL_error(L, LUA_QL("package.%s") " must be a string", pname); |  | ||||||
|   lua_pushstring(L, "");  /* error accumulator */ |  | ||||||
|   while ((path = pushnexttemplate(L, path)) != NULL) { |  | ||||||
|     const char *filename; |  | ||||||
|     filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); |  | ||||||
|     if (readable(filename))  /* does file exist and is readable? */ |  | ||||||
|       return filename;  /* return that file name */ |  | ||||||
|     lua_pop(L, 2);  /* remove path template and file name */  |  | ||||||
|     luaO_pushfstring(L, "\n\tno file " LUA_QS, filename); |  | ||||||
|     lua_concat(L, 2); |  | ||||||
|   } |  | ||||||
|   return NULL;  /* not found */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void loaderror (lua_State *L, const char *filename) { |  | ||||||
|   luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", |  | ||||||
|                 lua_tostring(L, 1), filename, lua_tostring(L, -1)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int loader_Lua (lua_State *L) { |  | ||||||
|   const char *filename; |  | ||||||
|   const char *name = luaL_checkstring(L, 1); |  | ||||||
|   filename = findfile(L, name, "path"); |  | ||||||
|   if (filename == NULL) return 1;  /* library not found in this path */ |  | ||||||
|   if (luaL_loadfile(L, filename) != 0) |  | ||||||
|     loaderror(L, filename); |  | ||||||
|   return 1;  /* library loaded successfully */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *mkfuncname (lua_State *L, const char *modname) { |  | ||||||
|   const char *funcname; |  | ||||||
|   const char *mark = strchr(modname, *LUA_IGMARK); |  | ||||||
|   if (mark) modname = mark + 1; |  | ||||||
|   funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); |  | ||||||
|   funcname = lua_pushfstring(L, POF"%s", funcname); |  | ||||||
|   lua_remove(L, -2);  /* remove 'gsub' result */ |  | ||||||
|   return funcname; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int loader_C (lua_State *L) { |  | ||||||
|   const char *funcname; |  | ||||||
|   const char *name = luaL_checkstring(L, 1); |  | ||||||
|   const char *filename = findfile(L, name, "cpath"); |  | ||||||
|   if (filename == NULL) return 1;  /* library not found in this path */ |  | ||||||
|   funcname = mkfuncname(L, name); |  | ||||||
|   if (ll_loadfunc(L, filename, funcname) != 0) |  | ||||||
|     loaderror(L, filename); |  | ||||||
|   return 1;  /* library loaded successfully */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int loader_Croot (lua_State *L) { |  | ||||||
|   const char *funcname; |  | ||||||
|   const char *filename; |  | ||||||
|   const char *name = luaL_checkstring(L, 1); |  | ||||||
|   const char *p = strchr(name, '.'); |  | ||||||
|   int stat; |  | ||||||
|   if (p == NULL) return 0;  /* is root */ |  | ||||||
|   lua_pushlstring(L, name, p - name); |  | ||||||
|   filename = findfile(L, lua_tostring(L, -1), "cpath"); |  | ||||||
|   if (filename == NULL) return 1;  /* root not found */ |  | ||||||
|   funcname = mkfuncname(L, name); |  | ||||||
|   if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { |  | ||||||
|     if (stat != ERRFUNC) loaderror(L, filename);  /* real error */ |  | ||||||
|     luaO_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, |  | ||||||
|                         name, filename); |  | ||||||
|     return 1;  /* function not found */ |  | ||||||
|   } |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int loader_preload (lua_State *L) { |  | ||||||
|   const char *name = luaL_checkstring(L, 1); |  | ||||||
|   lua_getfield(L, LUA_ENVIRONINDEX, "preload"); |  | ||||||
|   if (!lua_istable(L, -1)) |  | ||||||
|     luaL_error(L, LUA_QL("package.preload") " must be a table"); |  | ||||||
|   lua_getfield(L, -1, name); |  | ||||||
|   if (lua_isnil(L, -1))  /* not found? */ |  | ||||||
|     luaO_pushfstring(L, "\n\tno field package.preload['%s']", name); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const int sentinel_ = 0; |  | ||||||
| #define sentinel	((void *)&sentinel_) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int ll_require (lua_State *L) { |  | ||||||
|   const char *name = luaL_checkstring(L, 1); |  | ||||||
|   int i; |  | ||||||
|   lua_settop(L, 1);  /* _LOADED table will be at index 2 */ |  | ||||||
|   lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); |  | ||||||
|   lua_getfield(L, 2, name); |  | ||||||
|   if (lua_toboolean(L, -1)) {  /* is it there? */ |  | ||||||
|     if (lua_touserdata(L, -1) == sentinel)  /* check loops */ |  | ||||||
|       luaL_error(L, "loop or previous error loading module " LUA_QS, name); |  | ||||||
|     return 1;  /* package is already loaded */ |  | ||||||
|   } |  | ||||||
|   /* else must load it; iterate over available loaders */ |  | ||||||
|   lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); |  | ||||||
|   if (!lua_istable(L, -1)) |  | ||||||
|     luaL_error(L, LUA_QL("package.loaders") " must be a table"); |  | ||||||
|   lua_pushstring(L, "");  /* error message accumulator */ |  | ||||||
|   for (i=1; ; i++) { |  | ||||||
|     lua_rawgeti(L, -2, i);  /* get a loader */ |  | ||||||
|     if (lua_isnil(L, -1)) |  | ||||||
|       luaL_error(L, "module " LUA_QS " not found:%s", |  | ||||||
|                     name, lua_tostring(L, -2)); |  | ||||||
|     lua_pushstring(L, name); |  | ||||||
|     lua_call(L, 1, 1);  /* call it */ |  | ||||||
|     if (lua_isfunction(L, -1))  /* did it find module? */ |  | ||||||
|       break;  /* module loaded successfully */ |  | ||||||
|     else if (lua_isstring(L, -1))  /* loader returned error message? */ |  | ||||||
|       lua_concat(L, 2);  /* accumulate it */ |  | ||||||
|     else |  | ||||||
|       lua_pop(L, 1); |  | ||||||
|   } |  | ||||||
|   lua_pushlightuserdata(L, sentinel); |  | ||||||
|   lua_setfield(L, 2, name);  /* _LOADED[name] = sentinel */ |  | ||||||
|   lua_pushstring(L, name);  /* pass name as argument to module */ |  | ||||||
|   lua_call(L, 1, 1);  /* run loaded module */ |  | ||||||
|   if (!lua_isnil(L, -1))  /* non-nil return? */ |  | ||||||
|     lua_setfield(L, 2, name);  /* _LOADED[name] = returned value */ |  | ||||||
|   lua_getfield(L, 2, name); |  | ||||||
|   if (lua_touserdata(L, -1) == sentinel) {   /* module did not set a value? */ |  | ||||||
|     lua_pushboolean(L, 1);  /* use true as result */ |  | ||||||
|     lua_pushvalue(L, -1);  /* extra copy to be returned */ |  | ||||||
|     lua_setfield(L, 2, name);  /* _LOADED[name] = true */ |  | ||||||
|   } |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** 'module' function |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|    |  | ||||||
|  |  | ||||||
| static void setfenv (lua_State *L) { |  | ||||||
|   lua_Debug ar; |  | ||||||
|   lua_getstack(L, 1, &ar); |  | ||||||
|   lua_getinfo(L, "f", &ar); |  | ||||||
|   lua_pushvalue(L, -2); |  | ||||||
|   lua_setfenv(L, -2); |  | ||||||
|   lua_pop(L, 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void dooptions (lua_State *L, int n) { |  | ||||||
|   int i; |  | ||||||
|   for (i = 2; i <= n; i++) { |  | ||||||
|     lua_pushvalue(L, i);  /* get option (a function) */ |  | ||||||
|     lua_pushvalue(L, -2);  /* module */ |  | ||||||
|     lua_call(L, 1, 0); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void modinit (lua_State *L, const char *modname) { |  | ||||||
|   const char *dot; |  | ||||||
|   lua_pushvalue(L, -1); |  | ||||||
|   lua_setfield(L, -2, "_M");  /* module._M = module */ |  | ||||||
|   lua_pushstring(L, modname); |  | ||||||
|   lua_setfield(L, -2, "_NAME"); |  | ||||||
|   dot = strrchr(modname, '.');  /* look for last dot in module name */ |  | ||||||
|   if (dot == NULL) dot = modname; |  | ||||||
|   else dot++; |  | ||||||
|   /* set _PACKAGE as package name (full module name minus last part) */ |  | ||||||
|   lua_pushlstring(L, modname, dot - modname); |  | ||||||
|   lua_setfield(L, -2, "_PACKAGE"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int ll_module (lua_State *L) { |  | ||||||
|   const char *modname = luaL_checkstring(L, 1); |  | ||||||
|   int loaded = lua_gettop(L) + 1;  /* index of _LOADED table */ |  | ||||||
|   lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); |  | ||||||
|   lua_getfield(L, loaded, modname);  /* get _LOADED[modname] */ |  | ||||||
|   if (!lua_istable(L, -1)) {  /* not found? */ |  | ||||||
|     lua_pop(L, 1);  /* remove previous result */ |  | ||||||
|     /* try global variable (and create one if it does not exist) */ |  | ||||||
|     if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) |  | ||||||
|       return luaL_error(L, "name conflict for module " LUA_QS, modname); |  | ||||||
|     lua_pushvalue(L, -1); |  | ||||||
|     lua_setfield(L, loaded, modname);  /* _LOADED[modname] = new table */ |  | ||||||
|   } |  | ||||||
|   /* check whether table already has a _NAME field */ |  | ||||||
|   lua_getfield(L, -1, "_NAME"); |  | ||||||
|   if (!lua_isnil(L, -1))  /* is table an initialized module? */ |  | ||||||
|     lua_pop(L, 1); |  | ||||||
|   else {  /* no; initialize it */ |  | ||||||
|     lua_pop(L, 1); |  | ||||||
|     modinit(L, modname); |  | ||||||
|   } |  | ||||||
|   lua_pushvalue(L, -1); |  | ||||||
|   setfenv(L); |  | ||||||
|   dooptions(L, loaded - 1); |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int ll_seeall (lua_State *L) { |  | ||||||
|   luaL_checktype(L, 1, LUA_TTABLE); |  | ||||||
|   if (!lua_getmetatable(L, 1)) { |  | ||||||
|     lua_createtable(L, 0, 1); /* create new metatable */ |  | ||||||
|     lua_pushvalue(L, -1); |  | ||||||
|     lua_setmetatable(L, 1); |  | ||||||
|   } |  | ||||||
|   lua_pushvalue(L, LUA_GLOBALSINDEX); |  | ||||||
|   lua_setfield(L, -2, "__index");  /* mt.__index = _G */ |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* auxiliary mark (for internal use) */ |  | ||||||
| #define AUXMARK		"\1" |  | ||||||
|  |  | ||||||
| static void setpath (lua_State *L, const char *fieldname, const char *envname, |  | ||||||
|                                    const char *def) { |  | ||||||
|   const char *path = getenv(envname); |  | ||||||
|   if (path == NULL)  /* no environment variable? */ |  | ||||||
|     lua_pushstring(L, def);  /* use default */ |  | ||||||
|   else { |  | ||||||
|     /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ |  | ||||||
|     path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, |  | ||||||
|                               LUA_PATHSEP AUXMARK LUA_PATHSEP); |  | ||||||
|     luaL_gsub(L, path, AUXMARK, def); |  | ||||||
|     lua_remove(L, -2); |  | ||||||
|   } |  | ||||||
|   setprogdir(L); |  | ||||||
|   lua_setfield(L, -2, fieldname); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const luaL_Reg pk_funcs[] = { |  | ||||||
|   {"loadlib", ll_loadlib}, |  | ||||||
|   {"seeall", ll_seeall}, |  | ||||||
|   {NULL, NULL} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const luaL_Reg ll_funcs[] = { |  | ||||||
|   {"module", ll_module}, |  | ||||||
|   {"require", ll_require}, |  | ||||||
|   {NULL, NULL} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const lua_CFunction loaders[] = |  | ||||||
|   {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaopen_package (lua_State *L) { |  | ||||||
|   int i; |  | ||||||
|   /* create new type _LOADLIB */ |  | ||||||
|   luaL_newmetatable(L, "_LOADLIB"); |  | ||||||
|   lua_pushcfunction(L, gctm); |  | ||||||
|   lua_setfield(L, -2, "__gc"); |  | ||||||
|   /* create `package' table */ |  | ||||||
|   luaL_register(L, LUA_LOADLIBNAME, pk_funcs); |  | ||||||
| #if defined(LUA_COMPAT_LOADLIB)  |  | ||||||
|   lua_getfield(L, -1, "loadlib"); |  | ||||||
|   lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); |  | ||||||
| #endif |  | ||||||
|   lua_pushvalue(L, -1); |  | ||||||
|   lua_replace(L, LUA_ENVIRONINDEX); |  | ||||||
|   /* create `loaders' table */ |  | ||||||
|   lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1); |  | ||||||
|   /* fill it with pre-defined loaders */ |  | ||||||
|   for (i=0; loaders[i] != NULL; i++) { |  | ||||||
|     lua_pushcfunction(L, loaders[i]); |  | ||||||
|     lua_rawseti(L, -2, i+1); |  | ||||||
|   } |  | ||||||
|   lua_setfield(L, -2, "loaders");  /* put it in field `loaders' */ |  | ||||||
|   setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT);  /* set field `path' */ |  | ||||||
|   setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ |  | ||||||
|   /* store config information */ |  | ||||||
|   lua_pushstring(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" |  | ||||||
|                     LUA_EXECDIR "\n" LUA_IGMARK); |  | ||||||
|   lua_setfield(L, -2, "config"); |  | ||||||
|   /* set field `loaded' */ |  | ||||||
|   luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); |  | ||||||
|   lua_setfield(L, -2, "loaded"); |  | ||||||
|   /* set field `preload' */ |  | ||||||
|   lua_newtable(L); |  | ||||||
|   lua_setfield(L, -2, "preload"); |  | ||||||
|   lua_pushvalue(L, LUA_GLOBALSINDEX); |  | ||||||
|   luaL_register(L, NULL, ll_funcs);  /* open lib into global table */ |  | ||||||
|   lua_pop(L, 1); |  | ||||||
|   return 1;  /* return 'package' table */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,214 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lobject.c,v 2.22 2006/02/10 17:43:52 roberto Exp $ |  | ||||||
| ** Some generic functions over Lua objects |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #include <ctype.h> |  | ||||||
| #include <stdarg.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define lobject_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "ldo.h" |  | ||||||
| #include "lmem.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lstate.h" |  | ||||||
| #include "lstring.h" |  | ||||||
| #include "lvm.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL}; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** converts an integer to a "floating point byte", represented as |  | ||||||
| ** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if |  | ||||||
| ** eeeee != 0 and (xxx) otherwise. |  | ||||||
| */ |  | ||||||
| int luaO_int2fb (unsigned int x) { |  | ||||||
|   int e = 0;  /* expoent */ |  | ||||||
|   while (x >= 16) { |  | ||||||
|     x = (x+1) >> 1; |  | ||||||
|     e++; |  | ||||||
|   } |  | ||||||
|   if (x < 8) return x; |  | ||||||
|   else return ((e+1) << 3) | (cast_int(x) - 8); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* converts back */ |  | ||||||
| int luaO_fb2int (int x) { |  | ||||||
|   int e = (x >> 3) & 31; |  | ||||||
|   if (e == 0) return x; |  | ||||||
|   else return ((x & 7)+8) << (e - 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaO_log2 (unsigned int x) { |  | ||||||
|   static const lu_byte log_2[256] = { |  | ||||||
|     0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, |  | ||||||
|     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, |  | ||||||
|     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, |  | ||||||
|     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, |  | ||||||
|     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, |  | ||||||
|     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, |  | ||||||
|     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, |  | ||||||
|     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 |  | ||||||
|   }; |  | ||||||
|   int l = -1; |  | ||||||
|   while (x >= 256) { l += 8; x >>= 8; } |  | ||||||
|   return l + log_2[x]; |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaO_rawequalObj (const TValue *t1, const TValue *t2) { |  | ||||||
|   if (ttype(t1) != ttype(t2)) return 0; |  | ||||||
|   else switch (ttype(t1)) { |  | ||||||
|     case LUA_TNIL: |  | ||||||
|       return 1; |  | ||||||
|     case LUA_TNUMBER: |  | ||||||
|       return luai_numeq(nvalue(t1), nvalue(t2)); |  | ||||||
|     case LUA_TBOOLEAN: |  | ||||||
|       return bvalue(t1) == bvalue(t2);  /* boolean true must be 1 !! */ |  | ||||||
|     case LUA_TLIGHTUSERDATA: |  | ||||||
|       return pvalue(t1) == pvalue(t2); |  | ||||||
|     default: |  | ||||||
|       lua_assert(iscollectable(t1)); |  | ||||||
|       return gcvalue(t1) == gcvalue(t2); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaO_str2d (const char *s, lua_Number *result) { |  | ||||||
|   char *endptr; |  | ||||||
|   *result = lua_str2number(s, &endptr); |  | ||||||
|   if (endptr == s) return 0;  /* conversion failed */ |  | ||||||
|   if (*endptr == 'x' || *endptr == 'X')  /* maybe an hexadecimal constant? */ |  | ||||||
|     *result = cast_num(strtoul(s, &endptr, 16)); |  | ||||||
|   if (*endptr == '\0') return 1;  /* most common case */ |  | ||||||
|   while (isspace(cast(unsigned char, *endptr))) endptr++; |  | ||||||
|   if (*endptr != '\0') return 0;  /* invalid trailing characters? */ |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void pushstr (lua_State *L, const char *str) { |  | ||||||
|   setsvalue2s(L, L->top, luaS_new(L, str)); |  | ||||||
|   incr_top(L); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* this function handles only `%d', `%c', %f, %p, and `%s' formats */ |  | ||||||
| const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { |  | ||||||
|   int n = 1; |  | ||||||
|   pushstr(L, ""); |  | ||||||
|   for (;;) { |  | ||||||
|     const char *e = strchr(fmt, '%'); |  | ||||||
|     if (e == NULL) break; |  | ||||||
|     setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); |  | ||||||
|     incr_top(L); |  | ||||||
|     switch (*(e+1)) { |  | ||||||
|       case 's': { |  | ||||||
|         const char *s = va_arg(argp, char *); |  | ||||||
|         if (s == NULL) s = "(null)"; |  | ||||||
|         pushstr(L, s); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case 'c': { |  | ||||||
|         char buff[2]; |  | ||||||
|         buff[0] = cast(char, va_arg(argp, int)); |  | ||||||
|         buff[1] = '\0'; |  | ||||||
|         pushstr(L, buff); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case 'd': { |  | ||||||
|         setnvalue(L->top, cast_num(va_arg(argp, int))); |  | ||||||
|         incr_top(L); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case 'f': { |  | ||||||
|         setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); |  | ||||||
|         incr_top(L); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case 'p': { |  | ||||||
|         char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ |  | ||||||
|         sprintf(buff, "%p", va_arg(argp, void *)); |  | ||||||
|         pushstr(L, buff); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case '%': { |  | ||||||
|         pushstr(L, "%"); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       default: { |  | ||||||
|         char buff[3]; |  | ||||||
|         buff[0] = '%'; |  | ||||||
|         buff[1] = *(e+1); |  | ||||||
|         buff[2] = '\0'; |  | ||||||
|         pushstr(L, buff); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     n += 2; |  | ||||||
|     fmt = e+2; |  | ||||||
|   } |  | ||||||
|   pushstr(L, fmt); |  | ||||||
|   luaV_concat(L, n+1, cast_int(L->top - L->base) - 1); |  | ||||||
|   L->top -= n; |  | ||||||
|   return svalue(L->top - 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { |  | ||||||
|   const char *msg; |  | ||||||
|   va_list argp; |  | ||||||
|   va_start(argp, fmt); |  | ||||||
|   msg = luaO_pushvfstring(L, fmt, argp); |  | ||||||
|   va_end(argp); |  | ||||||
|   return msg; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaO_chunkid (char *out, const char *source, size_t bufflen) { |  | ||||||
|   if (*source == '=') { |  | ||||||
|     strncpy(out, source+1, bufflen);  /* remove first char */ |  | ||||||
|     out[bufflen-1] = '\0';  /* ensures null termination */ |  | ||||||
|   } |  | ||||||
|   else {  /* out = "source", or "...source" */ |  | ||||||
|     if (*source == '@') { |  | ||||||
|       size_t l; |  | ||||||
|       source++;  /* skip the `@' */ |  | ||||||
|       bufflen -= sizeof(" '...' "); |  | ||||||
|       l = strlen(source); |  | ||||||
|       strcpy(out, ""); |  | ||||||
|       if (l > bufflen) { |  | ||||||
|         source += (l-bufflen);  /* get last part of file name */ |  | ||||||
|         strcat(out, "..."); |  | ||||||
|       } |  | ||||||
|       strcat(out, source); |  | ||||||
|     } |  | ||||||
|     else {  /* out = [string "string"] */ |  | ||||||
|       size_t len = strcspn(source, "\n\r");  /* stop at first newline */ |  | ||||||
|       bufflen -= sizeof(" [string \"...\"] "); |  | ||||||
|       if (len > bufflen) len = bufflen; |  | ||||||
|       strcpy(out, "[string \""); |  | ||||||
|       if (source[len] != '\0') {  /* must truncate? */ |  | ||||||
|         strncat(out, source, len); |  | ||||||
|         strcat(out, "..."); |  | ||||||
|       } |  | ||||||
|       else |  | ||||||
|         strcat(out, source); |  | ||||||
|       strcat(out, "\"]"); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,381 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lobject.h,v 2.20 2006/01/18 11:37:34 roberto Exp $ |  | ||||||
| ** Type definitions for Lua objects |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifndef lobject_h |  | ||||||
| #define lobject_h |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <stdarg.h> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "llimits.h" |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* tags for values visible from Lua */ |  | ||||||
| #define LAST_TAG	LUA_TTHREAD |  | ||||||
|  |  | ||||||
| #define NUM_TAGS	(LAST_TAG+1) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Extra tags for non-values |  | ||||||
| */ |  | ||||||
| #define LUA_TPROTO	(LAST_TAG+1) |  | ||||||
| #define LUA_TUPVAL	(LAST_TAG+2) |  | ||||||
| #define LUA_TDEADKEY	(LAST_TAG+3) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Union of all collectable objects |  | ||||||
| */ |  | ||||||
| typedef union GCObject GCObject; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Common Header for all collectable objects (in macro form, to be |  | ||||||
| ** included in other objects) |  | ||||||
| */ |  | ||||||
| #define CommonHeader	GCObject *next; lu_byte tt; lu_byte marked |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Common header in struct form |  | ||||||
| */ |  | ||||||
| typedef struct GCheader { |  | ||||||
|   CommonHeader; |  | ||||||
| } GCheader; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Union of all Lua values |  | ||||||
| */ |  | ||||||
| typedef union { |  | ||||||
|   GCObject *gc; |  | ||||||
|   void *p; |  | ||||||
|   lua_Number n; |  | ||||||
|   int b; |  | ||||||
| } Value; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Tagged Values |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #define TValuefields	Value value; int tt |  | ||||||
|  |  | ||||||
| typedef struct lua_TValue { |  | ||||||
|   TValuefields; |  | ||||||
| } TValue; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Macros to test type */ |  | ||||||
| #define ttisnil(o)	(ttype(o) == LUA_TNIL) |  | ||||||
| #define ttisnumber(o)	(ttype(o) == LUA_TNUMBER) |  | ||||||
| #define ttisstring(o)	(ttype(o) == LUA_TSTRING) |  | ||||||
| #define ttistable(o)	(ttype(o) == LUA_TTABLE) |  | ||||||
| #define ttisfunction(o)	(ttype(o) == LUA_TFUNCTION) |  | ||||||
| #define ttisboolean(o)	(ttype(o) == LUA_TBOOLEAN) |  | ||||||
| #define ttisuserdata(o)	(ttype(o) == LUA_TUSERDATA) |  | ||||||
| #define ttisthread(o)	(ttype(o) == LUA_TTHREAD) |  | ||||||
| #define ttislightuserdata(o)	(ttype(o) == LUA_TLIGHTUSERDATA) |  | ||||||
|  |  | ||||||
| /* Macros to access values */ |  | ||||||
| #define ttype(o)	((o)->tt) |  | ||||||
| #define gcvalue(o)	check_exp(iscollectable(o), (o)->value.gc) |  | ||||||
| #define pvalue(o)	check_exp(ttislightuserdata(o), (o)->value.p) |  | ||||||
| #define nvalue(o)	check_exp(ttisnumber(o), (o)->value.n) |  | ||||||
| #define rawtsvalue(o)	check_exp(ttisstring(o), &(o)->value.gc->ts) |  | ||||||
| #define tsvalue(o)	(&rawtsvalue(o)->tsv) |  | ||||||
| #define rawuvalue(o)	check_exp(ttisuserdata(o), &(o)->value.gc->u) |  | ||||||
| #define uvalue(o)	(&rawuvalue(o)->uv) |  | ||||||
| #define clvalue(o)	check_exp(ttisfunction(o), &(o)->value.gc->cl) |  | ||||||
| #define hvalue(o)	check_exp(ttistable(o), &(o)->value.gc->h) |  | ||||||
| #define bvalue(o)	check_exp(ttisboolean(o), (o)->value.b) |  | ||||||
| #define thvalue(o)	check_exp(ttisthread(o), &(o)->value.gc->th) |  | ||||||
|  |  | ||||||
| #define l_isfalse(o)	(ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** for internal debug only |  | ||||||
| */ |  | ||||||
| #define checkconsistency(obj) \ |  | ||||||
|   lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) |  | ||||||
|  |  | ||||||
| #define checkliveness(g,obj) \ |  | ||||||
|   lua_assert(!iscollectable(obj) || \ |  | ||||||
|   ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc))) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Macros to set values */ |  | ||||||
| #define setnilvalue(obj) ((obj)->tt=LUA_TNIL) |  | ||||||
|  |  | ||||||
| #define setnvalue(obj,x) \ |  | ||||||
|   { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; } |  | ||||||
|  |  | ||||||
| #define setpvalue(obj,x) \ |  | ||||||
|   { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; } |  | ||||||
|  |  | ||||||
| #define setbvalue(obj,x) \ |  | ||||||
|   { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; } |  | ||||||
|  |  | ||||||
| #define setsvalue(L,obj,x) \ |  | ||||||
|   { TValue *i_o=(obj); \ |  | ||||||
|     i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \ |  | ||||||
|     checkliveness(G(L),i_o); } |  | ||||||
|  |  | ||||||
| #define setuvalue(L,obj,x) \ |  | ||||||
|   { TValue *i_o=(obj); \ |  | ||||||
|     i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \ |  | ||||||
|     checkliveness(G(L),i_o); } |  | ||||||
|  |  | ||||||
| #define setthvalue(L,obj,x) \ |  | ||||||
|   { TValue *i_o=(obj); \ |  | ||||||
|     i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \ |  | ||||||
|     checkliveness(G(L),i_o); } |  | ||||||
|  |  | ||||||
| #define setclvalue(L,obj,x) \ |  | ||||||
|   { TValue *i_o=(obj); \ |  | ||||||
|     i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \ |  | ||||||
|     checkliveness(G(L),i_o); } |  | ||||||
|  |  | ||||||
| #define sethvalue(L,obj,x) \ |  | ||||||
|   { TValue *i_o=(obj); \ |  | ||||||
|     i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \ |  | ||||||
|     checkliveness(G(L),i_o); } |  | ||||||
|  |  | ||||||
| #define setptvalue(L,obj,x) \ |  | ||||||
|   { TValue *i_o=(obj); \ |  | ||||||
|     i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \ |  | ||||||
|     checkliveness(G(L),i_o); } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define setobj(L,obj1,obj2) \ |  | ||||||
|   { const TValue *o2=(obj2); TValue *o1=(obj1); \ |  | ||||||
|     o1->value = o2->value; o1->tt=o2->tt; \ |  | ||||||
|     checkliveness(G(L),o1); } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** different types of sets, according to destination |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| /* from stack to (same) stack */ |  | ||||||
| #define setobjs2s	setobj |  | ||||||
| /* to stack (not from same stack) */ |  | ||||||
| #define setobj2s	setobj |  | ||||||
| #define setsvalue2s	setsvalue |  | ||||||
| #define sethvalue2s	sethvalue |  | ||||||
| #define setptvalue2s	setptvalue |  | ||||||
| /* from table to same table */ |  | ||||||
| #define setobjt2t	setobj |  | ||||||
| /* to table */ |  | ||||||
| #define setobj2t	setobj |  | ||||||
| /* to new object */ |  | ||||||
| #define setobj2n	setobj |  | ||||||
| #define setsvalue2n	setsvalue |  | ||||||
|  |  | ||||||
| #define setttype(obj, tt) (ttype(obj) = (tt)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define iscollectable(o)	(ttype(o) >= LUA_TSTRING) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef TValue *StkId;  /* index to stack elements */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** String headers for string table |  | ||||||
| */ |  | ||||||
| typedef union TString { |  | ||||||
|   L_Umaxalign dummy;  /* ensures maximum alignment for strings */ |  | ||||||
|   struct { |  | ||||||
|     CommonHeader; |  | ||||||
|     lu_byte reserved; |  | ||||||
|     unsigned int hash; |  | ||||||
|     size_t len; |  | ||||||
|   } tsv; |  | ||||||
| } TString; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define getstr(ts)	cast(const char *, (ts) + 1) |  | ||||||
| #define svalue(o)       getstr(tsvalue(o)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef union Udata { |  | ||||||
|   L_Umaxalign dummy;  /* ensures maximum alignment for `local' udata */ |  | ||||||
|   struct { |  | ||||||
|     CommonHeader; |  | ||||||
|     struct Table *metatable; |  | ||||||
|     struct Table *env; |  | ||||||
|     size_t len; |  | ||||||
|   } uv; |  | ||||||
| } Udata; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Function Prototypes |  | ||||||
| */ |  | ||||||
| typedef struct Proto { |  | ||||||
|   CommonHeader; |  | ||||||
|   TValue *k;  /* constants used by the function */ |  | ||||||
|   Instruction *code; |  | ||||||
|   struct Proto **p;  /* functions defined inside the function */ |  | ||||||
|   int *lineinfo;  /* map from opcodes to source lines */ |  | ||||||
|   struct LocVar *locvars;  /* information about local variables */ |  | ||||||
|   TString **upvalues;  /* upvalue names */ |  | ||||||
|   TString  *source; |  | ||||||
|   int sizeupvalues; |  | ||||||
|   int sizek;  /* size of `k' */ |  | ||||||
|   int sizecode; |  | ||||||
|   int sizelineinfo; |  | ||||||
|   int sizep;  /* size of `p' */ |  | ||||||
|   int sizelocvars; |  | ||||||
|   int linedefined; |  | ||||||
|   int lastlinedefined; |  | ||||||
|   GCObject *gclist; |  | ||||||
|   lu_byte nups;  /* number of upvalues */ |  | ||||||
|   lu_byte numparams; |  | ||||||
|   lu_byte is_vararg; |  | ||||||
|   lu_byte maxstacksize; |  | ||||||
| } Proto; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* masks for new-style vararg */ |  | ||||||
| #define VARARG_HASARG		1 |  | ||||||
| #define VARARG_ISVARARG		2 |  | ||||||
| #define VARARG_NEEDSARG		4 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct LocVar { |  | ||||||
|   TString *varname; |  | ||||||
|   int startpc;  /* first point where variable is active */ |  | ||||||
|   int endpc;    /* first point where variable is dead */ |  | ||||||
| } LocVar; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Upvalues |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| typedef struct UpVal { |  | ||||||
|   CommonHeader; |  | ||||||
|   TValue *v;  /* points to stack or to its own value */ |  | ||||||
|   union { |  | ||||||
|     TValue value;  /* the value (when closed) */ |  | ||||||
|     struct {  /* double linked list (when open) */ |  | ||||||
|       struct UpVal *prev; |  | ||||||
|       struct UpVal *next; |  | ||||||
|     } l; |  | ||||||
|   } u; |  | ||||||
| } UpVal; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Closures |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #define ClosureHeader \ |  | ||||||
| 	CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \ |  | ||||||
| 	struct Table *env |  | ||||||
|  |  | ||||||
| typedef struct CClosure { |  | ||||||
|   ClosureHeader; |  | ||||||
|   lua_CFunction f; |  | ||||||
|   TValue upvalue[1]; |  | ||||||
| } CClosure; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct LClosure { |  | ||||||
|   ClosureHeader; |  | ||||||
|   struct Proto *p; |  | ||||||
|   UpVal *upvals[1]; |  | ||||||
| } LClosure; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef union Closure { |  | ||||||
|   CClosure c; |  | ||||||
|   LClosure l; |  | ||||||
| } Closure; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define iscfunction(o)	(ttype(o) == LUA_TFUNCTION && clvalue(o)->c.isC) |  | ||||||
| #define isLfunction(o)	(ttype(o) == LUA_TFUNCTION && !clvalue(o)->c.isC) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Tables |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| typedef union TKey { |  | ||||||
|   struct { |  | ||||||
|     TValuefields; |  | ||||||
|     struct Node *next;  /* for chaining */ |  | ||||||
|   } nk; |  | ||||||
|   TValue tvk; |  | ||||||
| } TKey; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct Node { |  | ||||||
|   TValue i_val; |  | ||||||
|   TKey i_key; |  | ||||||
| } Node; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct Table { |  | ||||||
|   CommonHeader; |  | ||||||
|   lu_byte flags;  /* 1<<p means tagmethod(p) is not present */  |  | ||||||
|   lu_byte lsizenode;  /* log2 of size of `node' array */ |  | ||||||
|   struct Table *metatable; |  | ||||||
|   TValue *array;  /* array part */ |  | ||||||
|   Node *node; |  | ||||||
|   Node *lastfree;  /* any free position is before this position */ |  | ||||||
|   GCObject *gclist; |  | ||||||
|   int sizearray;  /* size of `array' array */ |  | ||||||
| } Table; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** `module' operation for hashing (size is always a power of 2) |  | ||||||
| */ |  | ||||||
| #define lmod(s,size) \ |  | ||||||
| 	(check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1))))) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define twoto(x)	(1<<(x)) |  | ||||||
| #define sizenode(t)	(twoto((t)->lsizenode)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define luaO_nilobject		(&luaO_nilobject_) |  | ||||||
|  |  | ||||||
| LUAI_DATA const TValue luaO_nilobject_; |  | ||||||
|  |  | ||||||
| #define ceillog2(x)	(luaO_log2((x)-1) + 1) |  | ||||||
|  |  | ||||||
| LUAI_FUNC int luaO_log2 (unsigned int x); |  | ||||||
| LUAI_FUNC int luaO_int2fb (unsigned int x); |  | ||||||
| LUAI_FUNC int luaO_fb2int (int x); |  | ||||||
| LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2); |  | ||||||
| LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result); |  | ||||||
| LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, |  | ||||||
|                                                        va_list argp); |  | ||||||
| LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); |  | ||||||
| LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| @@ -1,102 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lopcodes.c,v 1.37 2005/11/08 19:45:36 roberto Exp $ |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define lopcodes_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "lopcodes.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* ORDER OP */ |  | ||||||
|  |  | ||||||
| const char *const luaP_opnames[NUM_OPCODES+1] = { |  | ||||||
|   "MOVE", |  | ||||||
|   "LOADK", |  | ||||||
|   "LOADBOOL", |  | ||||||
|   "LOADNIL", |  | ||||||
|   "GETUPVAL", |  | ||||||
|   "GETGLOBAL", |  | ||||||
|   "GETTABLE", |  | ||||||
|   "SETGLOBAL", |  | ||||||
|   "SETUPVAL", |  | ||||||
|   "SETTABLE", |  | ||||||
|   "NEWTABLE", |  | ||||||
|   "SELF", |  | ||||||
|   "ADD", |  | ||||||
|   "SUB", |  | ||||||
|   "MUL", |  | ||||||
|   "DIV", |  | ||||||
|   "MOD", |  | ||||||
|   "POW", |  | ||||||
|   "UNM", |  | ||||||
|   "NOT", |  | ||||||
|   "LEN", |  | ||||||
|   "CONCAT", |  | ||||||
|   "JMP", |  | ||||||
|   "EQ", |  | ||||||
|   "LT", |  | ||||||
|   "LE", |  | ||||||
|   "TEST", |  | ||||||
|   "TESTSET", |  | ||||||
|   "CALL", |  | ||||||
|   "TAILCALL", |  | ||||||
|   "RETURN", |  | ||||||
|   "FORLOOP", |  | ||||||
|   "FORPREP", |  | ||||||
|   "TFORLOOP", |  | ||||||
|   "SETLIST", |  | ||||||
|   "CLOSE", |  | ||||||
|   "CLOSURE", |  | ||||||
|   "VARARG", |  | ||||||
|   NULL |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) |  | ||||||
|  |  | ||||||
| const lu_byte luaP_opmodes[NUM_OPCODES] = { |  | ||||||
| /*       T  A    B       C     mode		   opcode	*/ |  | ||||||
|   opmode(0, 1, OpArgR, OpArgN, iABC) 		/* OP_MOVE */ |  | ||||||
|  ,opmode(0, 1, OpArgK, OpArgN, iABx)		/* OP_LOADK */ |  | ||||||
|  ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_LOADBOOL */ |  | ||||||
|  ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_LOADNIL */ |  | ||||||
|  ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_GETUPVAL */ |  | ||||||
|  ,opmode(0, 1, OpArgK, OpArgN, iABx)		/* OP_GETGLOBAL */ |  | ||||||
|  ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_GETTABLE */ |  | ||||||
|  ,opmode(0, 0, OpArgK, OpArgN, iABx)		/* OP_SETGLOBAL */ |  | ||||||
|  ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_SETUPVAL */ |  | ||||||
|  ,opmode(0, 0, OpArgK, OpArgK, iABC)		/* OP_SETTABLE */ |  | ||||||
|  ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_NEWTABLE */ |  | ||||||
|  ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_SELF */ |  | ||||||
|  ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_ADD */ |  | ||||||
|  ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_SUB */ |  | ||||||
|  ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MUL */ |  | ||||||
|  ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_DIV */ |  | ||||||
|  ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MOD */ |  | ||||||
|  ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_POW */ |  | ||||||
|  ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_UNM */ |  | ||||||
|  ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_NOT */ |  | ||||||
|  ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_LEN */ |  | ||||||
|  ,opmode(0, 1, OpArgR, OpArgR, iABC)		/* OP_CONCAT */ |  | ||||||
|  ,opmode(0, 0, OpArgR, OpArgN, iAsBx)		/* OP_JMP */ |  | ||||||
|  ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_EQ */ |  | ||||||
|  ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LT */ |  | ||||||
|  ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LE */ |  | ||||||
|  ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TEST */ |  | ||||||
|  ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TESTSET */ |  | ||||||
|  ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_CALL */ |  | ||||||
|  ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_TAILCALL */ |  | ||||||
|  ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_RETURN */ |  | ||||||
|  ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORLOOP */ |  | ||||||
|  ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORPREP */ |  | ||||||
|  ,opmode(1, 0, OpArgN, OpArgU, iABC)		/* OP_TFORLOOP */ |  | ||||||
|  ,opmode(0, 0, OpArgU, OpArgU, iABC)		/* OP_SETLIST */ |  | ||||||
|  ,opmode(0, 0, OpArgN, OpArgN, iABC)		/* OP_CLOSE */ |  | ||||||
|  ,opmode(0, 1, OpArgU, OpArgN, iABx)		/* OP_CLOSURE */ |  | ||||||
|  ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_VARARG */ |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| @@ -1,268 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lopcodes.h,v 1.124 2005/12/02 18:42:08 roberto Exp $ |  | ||||||
| ** Opcodes for Lua virtual machine |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef lopcodes_h |  | ||||||
| #define lopcodes_h |  | ||||||
|  |  | ||||||
| #include "llimits.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /*=========================================================================== |  | ||||||
|   We assume that instructions are unsigned numbers. |  | ||||||
|   All instructions have an opcode in the first 6 bits. |  | ||||||
|   Instructions can have the following fields: |  | ||||||
| 	`A' : 8 bits |  | ||||||
| 	`B' : 9 bits |  | ||||||
| 	`C' : 9 bits |  | ||||||
| 	`Bx' : 18 bits (`B' and `C' together) |  | ||||||
| 	`sBx' : signed Bx |  | ||||||
|  |  | ||||||
|   A signed argument is represented in excess K; that is, the number |  | ||||||
|   value is the unsigned value minus K. K is exactly the maximum value |  | ||||||
|   for that argument (so that -max is represented by 0, and +max is |  | ||||||
|   represented by 2*max), which is half the maximum for the corresponding |  | ||||||
|   unsigned argument. |  | ||||||
| ===========================================================================*/ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| enum OpMode {iABC, iABx, iAsBx};  /* basic instruction format */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** size and position of opcode arguments. |  | ||||||
| */ |  | ||||||
| #define SIZE_C		9 |  | ||||||
| #define SIZE_B		9 |  | ||||||
| #define SIZE_Bx		(SIZE_C + SIZE_B) |  | ||||||
| #define SIZE_A		8 |  | ||||||
|  |  | ||||||
| #define SIZE_OP		6 |  | ||||||
|  |  | ||||||
| #define POS_OP		0 |  | ||||||
| #define POS_A		(POS_OP + SIZE_OP) |  | ||||||
| #define POS_C		(POS_A + SIZE_A) |  | ||||||
| #define POS_B		(POS_C + SIZE_C) |  | ||||||
| #define POS_Bx		POS_C |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** limits for opcode arguments. |  | ||||||
| ** we use (signed) int to manipulate most arguments, |  | ||||||
| ** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) |  | ||||||
| */ |  | ||||||
| #if SIZE_Bx < LUAI_BITSINT-1 |  | ||||||
| #define MAXARG_Bx        ((1<<SIZE_Bx)-1) |  | ||||||
| #define MAXARG_sBx        (MAXARG_Bx>>1)         /* `sBx' is signed */ |  | ||||||
| #else |  | ||||||
| #define MAXARG_Bx        MAX_INT |  | ||||||
| #define MAXARG_sBx        MAX_INT |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define MAXARG_A        ((1<<SIZE_A)-1) |  | ||||||
| #define MAXARG_B        ((1<<SIZE_B)-1) |  | ||||||
| #define MAXARG_C        ((1<<SIZE_C)-1) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* creates a mask with `n' 1 bits at position `p' */ |  | ||||||
| #define MASK1(n,p)	((~((~(Instruction)0)<<n))<<p) |  | ||||||
|  |  | ||||||
| /* creates a mask with `n' 0 bits at position `p' */ |  | ||||||
| #define MASK0(n,p)	(~MASK1(n,p)) |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** the following macros help to manipulate instructions |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #define GET_OPCODE(i)	(cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0))) |  | ||||||
| #define SET_OPCODE(i,o)	((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ |  | ||||||
| 		((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP)))) |  | ||||||
|  |  | ||||||
| #define GETARG_A(i)	(cast(int, ((i)>>POS_A) & MASK1(SIZE_A,0))) |  | ||||||
| #define SETARG_A(i,u)	((i) = (((i)&MASK0(SIZE_A,POS_A)) | \ |  | ||||||
| 		((cast(Instruction, u)<<POS_A)&MASK1(SIZE_A,POS_A)))) |  | ||||||
|  |  | ||||||
| #define GETARG_B(i)	(cast(int, ((i)>>POS_B) & MASK1(SIZE_B,0))) |  | ||||||
| #define SETARG_B(i,b)	((i) = (((i)&MASK0(SIZE_B,POS_B)) | \ |  | ||||||
| 		((cast(Instruction, b)<<POS_B)&MASK1(SIZE_B,POS_B)))) |  | ||||||
|  |  | ||||||
| #define GETARG_C(i)	(cast(int, ((i)>>POS_C) & MASK1(SIZE_C,0))) |  | ||||||
| #define SETARG_C(i,b)	((i) = (((i)&MASK0(SIZE_C,POS_C)) | \ |  | ||||||
| 		((cast(Instruction, b)<<POS_C)&MASK1(SIZE_C,POS_C)))) |  | ||||||
|  |  | ||||||
| #define GETARG_Bx(i)	(cast(int, ((i)>>POS_Bx) & MASK1(SIZE_Bx,0))) |  | ||||||
| #define SETARG_Bx(i,b)	((i) = (((i)&MASK0(SIZE_Bx,POS_Bx)) | \ |  | ||||||
| 		((cast(Instruction, b)<<POS_Bx)&MASK1(SIZE_Bx,POS_Bx)))) |  | ||||||
|  |  | ||||||
| #define GETARG_sBx(i)	(GETARG_Bx(i)-MAXARG_sBx) |  | ||||||
| #define SETARG_sBx(i,b)	SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define CREATE_ABC(o,a,b,c)	((cast(Instruction, o)<<POS_OP) \ |  | ||||||
| 			| (cast(Instruction, a)<<POS_A) \ |  | ||||||
| 			| (cast(Instruction, b)<<POS_B) \ |  | ||||||
| 			| (cast(Instruction, c)<<POS_C)) |  | ||||||
|  |  | ||||||
| #define CREATE_ABx(o,a,bc)	((cast(Instruction, o)<<POS_OP) \ |  | ||||||
| 			| (cast(Instruction, a)<<POS_A) \ |  | ||||||
| 			| (cast(Instruction, bc)<<POS_Bx)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Macros to operate RK indices |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| /* this bit 1 means constant (0 means register) */ |  | ||||||
| #define BITRK		(1 << (SIZE_B - 1)) |  | ||||||
|  |  | ||||||
| /* test whether value is a constant */ |  | ||||||
| #define ISK(x)		((x) & BITRK) |  | ||||||
|  |  | ||||||
| /* gets the index of the constant */ |  | ||||||
| #define INDEXK(r)	((int)(r) & ~BITRK) |  | ||||||
|  |  | ||||||
| #define MAXINDEXRK	(BITRK - 1) |  | ||||||
|  |  | ||||||
| /* code a constant index as a RK value */ |  | ||||||
| #define RKASK(x)	((x) | BITRK) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** invalid register that fits in 8 bits |  | ||||||
| */ |  | ||||||
| #define NO_REG		MAXARG_A |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** R(x) - register |  | ||||||
| ** Kst(x) - constant (in constant table) |  | ||||||
| ** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x) |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** grep "ORDER OP" if you change these enums |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| typedef enum { |  | ||||||
| /*---------------------------------------------------------------------- |  | ||||||
| name		args	description |  | ||||||
| ------------------------------------------------------------------------*/ |  | ||||||
| OP_MOVE,/*	A B	R(A) := R(B)					*/ |  | ||||||
| OP_LOADK,/*	A Bx	R(A) := Kst(Bx)					*/ |  | ||||||
| OP_LOADBOOL,/*	A B C	R(A) := (Bool)B; if (C) pc++			*/ |  | ||||||
| OP_LOADNIL,/*	A B	R(A) := ... := R(B) := nil			*/ |  | ||||||
| OP_GETUPVAL,/*	A B	R(A) := UpValue[B]				*/ |  | ||||||
|  |  | ||||||
| OP_GETGLOBAL,/*	A Bx	R(A) := Gbl[Kst(Bx)]				*/ |  | ||||||
| OP_GETTABLE,/*	A B C	R(A) := R(B)[RK(C)]				*/ |  | ||||||
|  |  | ||||||
| OP_SETGLOBAL,/*	A Bx	Gbl[Kst(Bx)] := R(A)				*/ |  | ||||||
| OP_SETUPVAL,/*	A B	UpValue[B] := R(A)				*/ |  | ||||||
| OP_SETTABLE,/*	A B C	R(A)[RK(B)] := RK(C)				*/ |  | ||||||
|  |  | ||||||
| OP_NEWTABLE,/*	A B C	R(A) := {} (size = B,C)				*/ |  | ||||||
|  |  | ||||||
| OP_SELF,/*	A B C	R(A+1) := R(B); R(A) := R(B)[RK(C)]		*/ |  | ||||||
|  |  | ||||||
| OP_ADD,/*	A B C	R(A) := RK(B) + RK(C)				*/ |  | ||||||
| OP_SUB,/*	A B C	R(A) := RK(B) - RK(C)				*/ |  | ||||||
| OP_MUL,/*	A B C	R(A) := RK(B) * RK(C)				*/ |  | ||||||
| OP_DIV,/*	A B C	R(A) := RK(B) / RK(C)				*/ |  | ||||||
| OP_MOD,/*	A B C	R(A) := RK(B) % RK(C)				*/ |  | ||||||
| OP_POW,/*	A B C	R(A) := RK(B) ^ RK(C)				*/ |  | ||||||
| OP_UNM,/*	A B	R(A) := -R(B)					*/ |  | ||||||
| OP_NOT,/*	A B	R(A) := not R(B)				*/ |  | ||||||
| OP_LEN,/*	A B	R(A) := length of R(B)				*/ |  | ||||||
|  |  | ||||||
| OP_CONCAT,/*	A B C	R(A) := R(B).. ... ..R(C)			*/ |  | ||||||
|  |  | ||||||
| OP_JMP,/*	sBx	pc+=sBx					*/ |  | ||||||
|  |  | ||||||
| OP_EQ,/*	A B C	if ((RK(B) == RK(C)) ~= A) then pc++		*/ |  | ||||||
| OP_LT,/*	A B C	if ((RK(B) <  RK(C)) ~= A) then pc++  		*/ |  | ||||||
| OP_LE,/*	A B C	if ((RK(B) <= RK(C)) ~= A) then pc++  		*/ |  | ||||||
|  |  | ||||||
| OP_TEST,/*	A C	if not (R(A) <=> C) then pc++			*/  |  | ||||||
| OP_TESTSET,/*	A B C	if (R(B) <=> C) then R(A) := R(B) else pc++	*/  |  | ||||||
|  |  | ||||||
| OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ |  | ||||||
| OP_TAILCALL,/*	A B C	return R(A)(R(A+1), ... ,R(A+B-1))		*/ |  | ||||||
| OP_RETURN,/*	A B	return R(A), ... ,R(A+B-2)	(see note)	*/ |  | ||||||
|  |  | ||||||
| OP_FORLOOP,/*	A sBx	R(A)+=R(A+2); |  | ||||||
| 			if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/ |  | ||||||
| OP_FORPREP,/*	A sBx	R(A)-=R(A+2); pc+=sBx				*/ |  | ||||||
|  |  | ||||||
| OP_TFORLOOP,/*	A C	R(A+3), ... ,R(A+3+C) := R(A)(R(A+1), R(A+2));  |  | ||||||
|                         if R(A+3) ~= nil then { pc++; R(A+2)=R(A+3); }	*/  |  | ||||||
| OP_SETLIST,/*	A B C	R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B	*/ |  | ||||||
|  |  | ||||||
| OP_CLOSE,/*	A 	close all variables in the stack up to (>=) R(A)*/ |  | ||||||
| OP_CLOSURE,/*	A Bx	R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))	*/ |  | ||||||
|  |  | ||||||
| OP_VARARG/*	A B	R(A), R(A+1), ..., R(A+B-1) = vararg		*/ |  | ||||||
| } OpCode; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define NUM_OPCODES	(cast(int, OP_VARARG) + 1) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /*=========================================================================== |  | ||||||
|   Notes: |  | ||||||
|   (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, |  | ||||||
|       and can be 0: OP_CALL then sets `top' to last_result+1, so |  | ||||||
|       next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. |  | ||||||
|  |  | ||||||
|   (*) In OP_VARARG, if (B == 0) then use actual number of varargs and |  | ||||||
|       set top (like in OP_CALL with C == 0). |  | ||||||
|  |  | ||||||
|   (*) In OP_RETURN, if (B == 0) then return up to `top' |  | ||||||
|  |  | ||||||
|   (*) In OP_SETLIST, if (B == 0) then B = `top'; |  | ||||||
|       if (C == 0) then next `instruction' is real C |  | ||||||
|  |  | ||||||
|   (*) For comparisons, A specifies what condition the test should accept |  | ||||||
|       (true or false). |  | ||||||
|  |  | ||||||
|   (*) All `skips' (pc++) assume that next instruction is a jump |  | ||||||
| ===========================================================================*/ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** masks for instruction properties. The format is: |  | ||||||
| ** bits 0-1: op mode |  | ||||||
| ** bits 2-3: C arg mode |  | ||||||
| ** bits 4-5: B arg mode |  | ||||||
| ** bit 6: instruction set register A |  | ||||||
| ** bit 7: operator is a test |  | ||||||
| */   |  | ||||||
|  |  | ||||||
| enum OpArgMask { |  | ||||||
|   OpArgN,  /* argument is not used */ |  | ||||||
|   OpArgU,  /* argument is used */ |  | ||||||
|   OpArgR,  /* argument is a register or a jump offset */ |  | ||||||
|   OpArgK   /* argument is a constant or register/constant */ |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES]; |  | ||||||
|  |  | ||||||
| #define getOpMode(m)	(cast(enum OpMode, luaP_opmodes[m] & 3)) |  | ||||||
| #define getBMode(m)	(cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3)) |  | ||||||
| #define getCMode(m)	(cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3)) |  | ||||||
| #define testAMode(m)	(luaP_opmodes[m] & (1 << 6)) |  | ||||||
| #define testTMode(m)	(luaP_opmodes[m] & (1 << 7)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUAI_DATA const char *const luaP_opnames[NUM_OPCODES+1];  /* opcode names */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* number of list items to accumulate before a SETLIST instruction */ |  | ||||||
| #define LFIELDS_PER_FLUSH	50 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
							
								
								
									
										238
									
								
								src/lua/loslib.c
									
									
									
									
									
								
							
							
						
						
									
										238
									
								
								src/lua/loslib.c
									
									
									
									
									
								
							| @@ -1,238 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: loslib.c,v 1.17 2006/01/27 13:54:31 roberto Exp $ |  | ||||||
| ** Standard Operating System library |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <errno.h> |  | ||||||
| #include <locale.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
| #include <time.h> |  | ||||||
|  |  | ||||||
| #define loslib_c |  | ||||||
| #define LUA_LIB |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lauxlib.h" |  | ||||||
| #include "lualib.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int os_pushresult (lua_State *L, int i, const char *filename) { |  | ||||||
|   int en = errno;  /* calls to Lua API may change this value */ |  | ||||||
|   if (i) { |  | ||||||
|     lua_pushboolean(L, 1); |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     lua_pushnil(L); |  | ||||||
|     if (filename) |  | ||||||
|       lua_pushfstring(L, "%s: %s", filename, strerror(en)); |  | ||||||
|     else |  | ||||||
|       lua_pushfstring(L, "%s", strerror(en)); |  | ||||||
|     lua_pushinteger(L, en); |  | ||||||
|     return 3; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int os_execute (lua_State *L) { |  | ||||||
|   lua_pushinteger(L, system(luaL_optstring(L, 1, NULL))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int os_remove (lua_State *L) { |  | ||||||
|   const char *filename = luaL_checkstring(L, 1); |  | ||||||
|   return os_pushresult(L, remove(filename) == 0, filename); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int os_rename (lua_State *L) { |  | ||||||
|   const char *fromname = luaL_checkstring(L, 1); |  | ||||||
|   const char *toname = luaL_checkstring(L, 2); |  | ||||||
|   return os_pushresult(L, rename(fromname, toname) == 0, fromname); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int os_tmpname (lua_State *L) { |  | ||||||
|   char buff[LUA_TMPNAMBUFSIZE]; |  | ||||||
|   int err; |  | ||||||
|   lua_tmpnam(buff, err); |  | ||||||
|   if (err) |  | ||||||
|     return luaL_error(L, "unable to generate a unique filename"); |  | ||||||
|   lua_pushstring(L, buff); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int os_getenv (lua_State *L) { |  | ||||||
|   lua_pushstring(L, getenv(luaL_checkstring(L, 1)));  /* if NULL push nil */ |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int os_clock (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** Time/Date operations |  | ||||||
| ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, |  | ||||||
| **   wday=%w+1, yday=%j, isdst=? } |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| static void setfield (lua_State *L, const char *key, int value) { |  | ||||||
|   lua_pushinteger(L, value); |  | ||||||
|   lua_setfield(L, -2, key); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void setboolfield (lua_State *L, const char *key, int value) { |  | ||||||
|   if (value < 0)  /* undefined? */ |  | ||||||
|     return;  /* does not set field */ |  | ||||||
|   lua_pushboolean(L, value); |  | ||||||
|   lua_setfield(L, -2, key); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int getboolfield (lua_State *L, const char *key) { |  | ||||||
|   int res; |  | ||||||
|   lua_getfield(L, -1, key); |  | ||||||
|   res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); |  | ||||||
|   lua_pop(L, 1); |  | ||||||
|   return res; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int getfield (lua_State *L, const char *key, int d) { |  | ||||||
|   int res; |  | ||||||
|   lua_getfield(L, -1, key); |  | ||||||
|   if (lua_isnumber(L, -1)) |  | ||||||
|     res = (int)lua_tointeger(L, -1); |  | ||||||
|   else { |  | ||||||
|     if (d < 0) |  | ||||||
|       return luaL_error(L, "field " LUA_QS " missing in date table", key); |  | ||||||
|     res = d; |  | ||||||
|   } |  | ||||||
|   lua_pop(L, 1); |  | ||||||
|   return res; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int os_date (lua_State *L) { |  | ||||||
|   const char *s = luaL_optstring(L, 1, "%c"); |  | ||||||
|   time_t t = lua_isnoneornil(L, 2) ? time(NULL) : |  | ||||||
|                                      (time_t)luaL_checknumber(L, 2); |  | ||||||
|   struct tm *stm; |  | ||||||
|   if (*s == '!') {  /* UTC? */ |  | ||||||
|     stm = gmtime(&t); |  | ||||||
|     s++;  /* skip `!' */ |  | ||||||
|   } |  | ||||||
|   else |  | ||||||
|     stm = localtime(&t); |  | ||||||
|   if (stm == NULL)  /* invalid date? */ |  | ||||||
|     lua_pushnil(L); |  | ||||||
|   else if (strcmp(s, "*t") == 0) { |  | ||||||
|     lua_createtable(L, 0, 9);  /* 9 = number of fields */ |  | ||||||
|     setfield(L, "sec", stm->tm_sec); |  | ||||||
|     setfield(L, "min", stm->tm_min); |  | ||||||
|     setfield(L, "hour", stm->tm_hour); |  | ||||||
|     setfield(L, "day", stm->tm_mday); |  | ||||||
|     setfield(L, "month", stm->tm_mon+1); |  | ||||||
|     setfield(L, "year", stm->tm_year+1900); |  | ||||||
|     setfield(L, "wday", stm->tm_wday+1); |  | ||||||
|     setfield(L, "yday", stm->tm_yday+1); |  | ||||||
|     setboolfield(L, "isdst", stm->tm_isdst); |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     char b[256]; |  | ||||||
|     if (strftime(b, sizeof(b), s, stm)) |  | ||||||
|       lua_pushstring(L, b); |  | ||||||
|     else |  | ||||||
|       return luaL_error(L, LUA_QL("date") " format too long"); |  | ||||||
|   } |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int os_time (lua_State *L) { |  | ||||||
|   time_t t; |  | ||||||
|   if (lua_isnoneornil(L, 1))  /* called without args? */ |  | ||||||
|     t = time(NULL);  /* get current time */ |  | ||||||
|   else { |  | ||||||
|     struct tm ts; |  | ||||||
|     luaL_checktype(L, 1, LUA_TTABLE); |  | ||||||
|     lua_settop(L, 1);  /* make sure table is at the top */ |  | ||||||
|     ts.tm_sec = getfield(L, "sec", 0); |  | ||||||
|     ts.tm_min = getfield(L, "min", 0); |  | ||||||
|     ts.tm_hour = getfield(L, "hour", 12); |  | ||||||
|     ts.tm_mday = getfield(L, "day", -1); |  | ||||||
|     ts.tm_mon = getfield(L, "month", -1) - 1; |  | ||||||
|     ts.tm_year = getfield(L, "year", -1) - 1900; |  | ||||||
|     ts.tm_isdst = getboolfield(L, "isdst"); |  | ||||||
|     t = mktime(&ts); |  | ||||||
|   } |  | ||||||
|   if (t == (time_t)(-1)) |  | ||||||
|     lua_pushnil(L); |  | ||||||
|   else |  | ||||||
|     lua_pushnumber(L, (lua_Number)t); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int os_difftime (lua_State *L) { |  | ||||||
|   lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), |  | ||||||
|                              (time_t)(luaL_optnumber(L, 2, 0)))); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int os_setlocale (lua_State *L) { |  | ||||||
|   static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, |  | ||||||
|                       LC_NUMERIC, LC_TIME}; |  | ||||||
|   static const char *const catnames[] = {"all", "collate", "ctype", "monetary", |  | ||||||
|      "numeric", "time", NULL}; |  | ||||||
|   const char *l = lua_tostring(L, 1); |  | ||||||
|   int op = luaL_checkoption(L, 2, "all", catnames); |  | ||||||
|   luaL_argcheck(L, l || lua_isnoneornil(L, 1), 1, "string expected"); |  | ||||||
|   lua_pushstring(L, setlocale(cat[op], l)); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int os_exit (lua_State *L) { |  | ||||||
|   exit(luaL_optint(L, 1, EXIT_SUCCESS)); |  | ||||||
|   return 0;  /* to avoid warnings */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static const luaL_Reg syslib[] = { |  | ||||||
|   {"clock",     os_clock}, |  | ||||||
|   {"date",      os_date}, |  | ||||||
|   {"difftime",  os_difftime}, |  | ||||||
|   {"execute",   os_execute}, |  | ||||||
|   {"exit",      os_exit}, |  | ||||||
|   {"getenv",    os_getenv}, |  | ||||||
|   {"remove",    os_remove}, |  | ||||||
|   {"rename",    os_rename}, |  | ||||||
|   {"setlocale", os_setlocale}, |  | ||||||
|   {"time",      os_time}, |  | ||||||
|   {"tmpname",   os_tmpname}, |  | ||||||
|   {NULL, NULL} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaopen_os (lua_State *L) { |  | ||||||
|   luaL_register(L, LUA_OSLIBNAME, syslib); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										1336
									
								
								src/lua/lparser.c
									
									
									
									
									
								
							
							
						
						
									
										1336
									
								
								src/lua/lparser.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,83 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lparser.h,v 1.56 2005/10/03 14:02:40 roberto Exp $ |  | ||||||
| ** Lua Parser |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef lparser_h |  | ||||||
| #define lparser_h |  | ||||||
|  |  | ||||||
| #include "llimits.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "ltable.h" |  | ||||||
| #include "lzio.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Expression descriptor |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| typedef enum { |  | ||||||
|   VVOID,	/* no value */ |  | ||||||
|   VNIL, |  | ||||||
|   VTRUE, |  | ||||||
|   VFALSE, |  | ||||||
|   VK,		/* info = index of constant in `k' */ |  | ||||||
|   VKNUM,	/* nval = numerical value */ |  | ||||||
|   VLOCAL,	/* info = local register */ |  | ||||||
|   VUPVAL,       /* info = index of upvalue in `upvalues' */ |  | ||||||
|   VGLOBAL,	/* info = index of table; aux = index of global name in `k' */ |  | ||||||
|   VINDEXED,	/* info = table register; aux = index register (or `k') */ |  | ||||||
|   VJMP,		/* info = instruction pc */ |  | ||||||
|   VRELOCABLE,	/* info = instruction pc */ |  | ||||||
|   VNONRELOC,	/* info = result register */ |  | ||||||
|   VCALL,	/* info = instruction pc */ |  | ||||||
|   VVARARG	/* info = instruction pc */ |  | ||||||
| } expkind; |  | ||||||
|  |  | ||||||
| typedef struct expdesc { |  | ||||||
|   expkind k; |  | ||||||
|   union { |  | ||||||
|     struct { int info, aux; } s; |  | ||||||
|     lua_Number nval; |  | ||||||
|   } u; |  | ||||||
|   int t;  /* patch list of `exit when true' */ |  | ||||||
|   int f;  /* patch list of `exit when false' */ |  | ||||||
| } expdesc; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct upvaldesc { |  | ||||||
|   lu_byte k; |  | ||||||
|   lu_byte info; |  | ||||||
| } upvaldesc; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| struct BlockCnt;  /* defined in lparser.c */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* state needed to generate code for a given function */ |  | ||||||
| typedef struct FuncState { |  | ||||||
|   Proto *f;  /* current function header */ |  | ||||||
|   Table *h;  /* table to find (and reuse) elements in `k' */ |  | ||||||
|   struct FuncState *prev;  /* enclosing function */ |  | ||||||
|   struct LexState *ls;  /* lexical state */ |  | ||||||
|   struct lua_State *L;  /* copy of the Lua state */ |  | ||||||
|   struct BlockCnt *bl;  /* chain of current blocks */ |  | ||||||
|   int pc;  /* next position to code (equivalent to `ncode') */ |  | ||||||
|   int lasttarget;   /* `pc' of last `jump target' */ |  | ||||||
|   int jpc;  /* list of pending jumps to `pc' */ |  | ||||||
|   int freereg;  /* first free register */ |  | ||||||
|   int nk;  /* number of elements in `k' */ |  | ||||||
|   int np;  /* number of elements in `p' */ |  | ||||||
|   short nlocvars;  /* number of elements in `locvars' */ |  | ||||||
|   lu_byte nactvar;  /* number of active local variables */ |  | ||||||
|   upvaldesc upvalues[LUAI_MAXUPVALUES];  /* upvalues */ |  | ||||||
|   unsigned short actvar[LUAI_MAXVARS];  /* declared-variable stack */ |  | ||||||
| } FuncState; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, |  | ||||||
|                                             const char *name); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
							
								
								
									
										214
									
								
								src/lua/lstate.c
									
									
									
									
									
								
							
							
						
						
									
										214
									
								
								src/lua/lstate.c
									
									
									
									
									
								
							| @@ -1,214 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lstate.c,v 2.35 2005/10/06 20:46:25 roberto Exp $ |  | ||||||
| ** Global State |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <stddef.h> |  | ||||||
|  |  | ||||||
| #define lstate_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "ldebug.h" |  | ||||||
| #include "ldo.h" |  | ||||||
| #include "lfunc.h" |  | ||||||
| #include "lgc.h" |  | ||||||
| #include "llex.h" |  | ||||||
| #include "lmem.h" |  | ||||||
| #include "lstate.h" |  | ||||||
| #include "lstring.h" |  | ||||||
| #include "ltable.h" |  | ||||||
| #include "ltm.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define state_size(x)	(sizeof(x) + LUAI_EXTRASPACE) |  | ||||||
| #define fromstate(l)	(cast(lu_byte *, (l)) - LUAI_EXTRASPACE) |  | ||||||
| #define tostate(l)   (cast(lua_State *, cast(lu_byte *, l) + LUAI_EXTRASPACE)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Main thread combines a thread state and the global state |  | ||||||
| */ |  | ||||||
| typedef struct LG { |  | ||||||
|   lua_State l; |  | ||||||
|   global_State g; |  | ||||||
| } LG; |  | ||||||
|    |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void stack_init (lua_State *L1, lua_State *L) { |  | ||||||
|   /* initialize CallInfo array */ |  | ||||||
|   L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); |  | ||||||
|   L1->ci = L1->base_ci; |  | ||||||
|   L1->size_ci = BASIC_CI_SIZE; |  | ||||||
|   L1->end_ci = L1->base_ci + L1->size_ci - 1; |  | ||||||
|   /* initialize stack array */ |  | ||||||
|   L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); |  | ||||||
|   L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; |  | ||||||
|   L1->top = L1->stack; |  | ||||||
|   L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; |  | ||||||
|   /* initialize first ci */ |  | ||||||
|   L1->ci->func = L1->top; |  | ||||||
|   setnilvalue(L1->top++);  /* `function' entry for this `ci' */ |  | ||||||
|   L1->base = L1->ci->base = L1->top; |  | ||||||
|   L1->ci->top = L1->top + LUA_MINSTACK; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void freestack (lua_State *L, lua_State *L1) { |  | ||||||
|   luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo); |  | ||||||
|   luaM_freearray(L, L1->stack, L1->stacksize, TValue); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** open parts that may cause memory-allocation errors |  | ||||||
| */ |  | ||||||
| static void f_luaopen (lua_State *L, void *ud) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   UNUSED(ud); |  | ||||||
|   stack_init(L, L);  /* init stack */ |  | ||||||
|   sethvalue(L, gt(L), luaH_new(L, 0, 2));  /* table of globals */ |  | ||||||
|   sethvalue(L, registry(L), luaH_new(L, 0, 2));  /* registry */ |  | ||||||
|   luaS_resize(L, MINSTRTABSIZE);  /* initial size of string table */ |  | ||||||
|   luaT_init(L); |  | ||||||
|   luaX_init(L); |  | ||||||
|   luaS_fix(luaS_newliteral(L, MEMERRMSG)); |  | ||||||
|   g->GCthreshold = 4*g->totalbytes; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void preinit_state (lua_State *L, global_State *g) { |  | ||||||
|   G(L) = g; |  | ||||||
|   L->stack = NULL; |  | ||||||
|   L->stacksize = 0; |  | ||||||
|   L->errorJmp = NULL; |  | ||||||
|   L->hook = NULL; |  | ||||||
|   L->hookmask = 0; |  | ||||||
|   L->basehookcount = 0; |  | ||||||
|   L->allowhook = 1; |  | ||||||
|   resethookcount(L); |  | ||||||
|   L->openupval = NULL; |  | ||||||
|   L->size_ci = 0; |  | ||||||
|   L->nCcalls = 0; |  | ||||||
|   L->status = 0; |  | ||||||
|   L->base_ci = L->ci = NULL; |  | ||||||
|   L->savedpc = NULL; |  | ||||||
|   L->errfunc = 0; |  | ||||||
|   setnilvalue(gt(L)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void close_state (lua_State *L) { |  | ||||||
|   global_State *g = G(L); |  | ||||||
|   luaF_close(L, L->stack);  /* close all upvalues for this thread */ |  | ||||||
|   luaC_freeall(L);  /* collect all objects */ |  | ||||||
|   lua_assert(g->rootgc == obj2gco(L)); |  | ||||||
|   lua_assert(g->strt.nuse == 0); |  | ||||||
|   luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); |  | ||||||
|   luaZ_freebuffer(L, &g->buff); |  | ||||||
|   freestack(L, L); |  | ||||||
|   lua_assert(g->totalbytes == sizeof(LG)); |  | ||||||
|   (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| lua_State *luaE_newthread (lua_State *L) { |  | ||||||
|   lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); |  | ||||||
|   luaC_link(L, obj2gco(L1), LUA_TTHREAD); |  | ||||||
|   preinit_state(L1, G(L)); |  | ||||||
|   stack_init(L1, L);  /* init stack */ |  | ||||||
|   setobj2n(L, gt(L1), gt(L));  /* share table of globals */ |  | ||||||
|   L1->hookmask = L->hookmask; |  | ||||||
|   L1->basehookcount = L->basehookcount; |  | ||||||
|   L1->hook = L->hook; |  | ||||||
|   resethookcount(L1); |  | ||||||
|   lua_assert(iswhite(obj2gco(L1))); |  | ||||||
|   return L1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaE_freethread (lua_State *L, lua_State *L1) { |  | ||||||
|   luaF_close(L1, L1->stack);  /* close all upvalues for this thread */ |  | ||||||
|   lua_assert(L1->openupval == NULL); |  | ||||||
|   luai_userstatefree(L1); |  | ||||||
|   freestack(L, L1); |  | ||||||
|   luaM_freemem(L, fromstate(L1), state_size(lua_State)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { |  | ||||||
|   int i; |  | ||||||
|   lua_State *L; |  | ||||||
|   global_State *g; |  | ||||||
|   void *l = (*f)(ud, NULL, 0, state_size(LG)); |  | ||||||
|   if (l == NULL) return NULL; |  | ||||||
|   L = tostate(l); |  | ||||||
|   g = &((LG *)L)->g; |  | ||||||
|   L->next = NULL; |  | ||||||
|   L->tt = LUA_TTHREAD; |  | ||||||
|   g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); |  | ||||||
|   L->marked = luaC_white(g); |  | ||||||
|   set2bits(L->marked, FIXEDBIT, SFIXEDBIT); |  | ||||||
|   preinit_state(L, g); |  | ||||||
|   g->frealloc = f; |  | ||||||
|   g->ud = ud; |  | ||||||
|   g->mainthread = L; |  | ||||||
|   g->uvhead.u.l.prev = &g->uvhead; |  | ||||||
|   g->uvhead.u.l.next = &g->uvhead; |  | ||||||
|   g->GCthreshold = 0;  /* mark it as unfinished state */ |  | ||||||
|   g->strt.size = 0; |  | ||||||
|   g->strt.nuse = 0; |  | ||||||
|   g->strt.hash = NULL; |  | ||||||
|   setnilvalue(registry(L)); |  | ||||||
|   luaZ_initbuffer(L, &g->buff); |  | ||||||
|   g->panic = NULL; |  | ||||||
|   g->gcstate = GCSpause; |  | ||||||
|   g->rootgc = obj2gco(L); |  | ||||||
|   g->sweepstrgc = 0; |  | ||||||
|   g->sweepgc = &g->rootgc; |  | ||||||
|   g->gray = NULL; |  | ||||||
|   g->grayagain = NULL; |  | ||||||
|   g->weak = NULL; |  | ||||||
|   g->tmudata = NULL; |  | ||||||
|   g->totalbytes = sizeof(LG); |  | ||||||
|   g->gcpause = LUAI_GCPAUSE; |  | ||||||
|   g->gcstepmul = LUAI_GCMUL; |  | ||||||
|   g->gcdept = 0; |  | ||||||
|   for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL; |  | ||||||
|   if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { |  | ||||||
|     /* memory allocation error: free partial state */ |  | ||||||
|     close_state(L); |  | ||||||
|     L = NULL; |  | ||||||
|   } |  | ||||||
|   else |  | ||||||
|     luai_userstateopen(L); |  | ||||||
|   return L; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void callallgcTM (lua_State *L, void *ud) { |  | ||||||
|   UNUSED(ud); |  | ||||||
|   luaC_callGCTM(L);  /* call GC metamethods for all udata */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUA_API void lua_close (lua_State *L) { |  | ||||||
|   L = G(L)->mainthread;  /* only the main thread can be closed */ |  | ||||||
|   luai_userstateclose(L); |  | ||||||
|   lua_lock(L); |  | ||||||
|   luaF_close(L, L->stack);  /* close all upvalues for this thread */ |  | ||||||
|   luaC_separateudata(L, 1);  /* separate udata that have GC metamethods */ |  | ||||||
|   L->errfunc = 0;  /* no error function during GC metamethods */ |  | ||||||
|   do {  /* repeat until no more errors */ |  | ||||||
|     L->ci = L->base_ci; |  | ||||||
|     L->base = L->top = L->ci->base; |  | ||||||
|     L->nCcalls = 0; |  | ||||||
|   } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); |  | ||||||
|   lua_assert(G(L)->tmudata == NULL); |  | ||||||
|   close_state(L); |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										168
									
								
								src/lua/lstate.h
									
									
									
									
									
								
							
							
						
						
									
										168
									
								
								src/lua/lstate.h
									
									
									
									
									
								
							| @@ -1,168 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lstate.h,v 2.24 2006/02/06 18:27:59 roberto Exp $ |  | ||||||
| ** Global State |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef lstate_h |  | ||||||
| #define lstate_h |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "ltm.h" |  | ||||||
| #include "lzio.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| struct lua_longjmp;  /* defined in ldo.c */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* table of globals */ |  | ||||||
| #define gt(L)	(&L->l_gt) |  | ||||||
|  |  | ||||||
| /* registry */ |  | ||||||
| #define registry(L)	(&G(L)->l_registry) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* extra stack space to handle TM calls and some other extras */ |  | ||||||
| #define EXTRA_STACK   5 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define BASIC_CI_SIZE           8 |  | ||||||
|  |  | ||||||
| #define BASIC_STACK_SIZE        (2*LUA_MINSTACK) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct stringtable { |  | ||||||
|   GCObject **hash; |  | ||||||
|   lu_int32 nuse;  /* number of elements */ |  | ||||||
|   int size; |  | ||||||
| } stringtable; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** informations about a call |  | ||||||
| */ |  | ||||||
| typedef struct CallInfo { |  | ||||||
|   StkId base;  /* base for this function */ |  | ||||||
|   StkId func;  /* function index in the stack */ |  | ||||||
|   StkId	top;  /* top for this function */ |  | ||||||
|   const Instruction *savedpc; |  | ||||||
|   int nresults;  /* expected number of results from this function */ |  | ||||||
|   int tailcalls;  /* number of tail calls lost under this entry */ |  | ||||||
| } CallInfo; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define curr_func(L)	(clvalue(L->ci->func)) |  | ||||||
| #define ci_func(ci)	(clvalue((ci)->func)) |  | ||||||
| #define f_isLua(ci)	(!ci_func(ci)->c.isC) |  | ||||||
| #define isLua(ci)	(ttisfunction((ci)->func) && f_isLua(ci)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** `global state', shared by all threads of this state |  | ||||||
| */ |  | ||||||
| typedef struct global_State { |  | ||||||
|   stringtable strt;  /* hash table for strings */ |  | ||||||
|   lua_Alloc frealloc;  /* function to reallocate memory */ |  | ||||||
|   void *ud;         /* auxiliary data to `frealloc' */ |  | ||||||
|   lu_byte currentwhite; |  | ||||||
|   lu_byte gcstate;  /* state of garbage collector */ |  | ||||||
|   int sweepstrgc;  /* position of sweep in `strt' */ |  | ||||||
|   GCObject *rootgc;  /* list of all collectable objects */ |  | ||||||
|   GCObject **sweepgc;  /* position of sweep in `rootgc' */ |  | ||||||
|   GCObject *gray;  /* list of gray objects */ |  | ||||||
|   GCObject *grayagain;  /* list of objects to be traversed atomically */ |  | ||||||
|   GCObject *weak;  /* list of weak tables (to be cleared) */ |  | ||||||
|   GCObject *tmudata;  /* last element of list of userdata to be GC */ |  | ||||||
|   Mbuffer buff;  /* temporary buffer for string concatentation */ |  | ||||||
|   lu_mem GCthreshold; |  | ||||||
|   lu_mem totalbytes;  /* number of bytes currently allocated */ |  | ||||||
|   lu_mem estimate;  /* an estimate of number of bytes actually in use */ |  | ||||||
|   lu_mem gcdept;  /* how much GC is `behind schedule' */ |  | ||||||
|   int gcpause;  /* size of pause between successive GCs */ |  | ||||||
|   int gcstepmul;  /* GC `granularity' */ |  | ||||||
|   lua_CFunction panic;  /* to be called in unprotected errors */ |  | ||||||
|   TValue l_registry; |  | ||||||
|   struct lua_State *mainthread; |  | ||||||
|   UpVal uvhead;  /* head of double-linked list of all open upvalues */ |  | ||||||
|   struct Table *mt[NUM_TAGS];  /* metatables for basic types */ |  | ||||||
|   TString *tmname[TM_N];  /* array with tag-method names */ |  | ||||||
| } global_State; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** `per thread' state |  | ||||||
| */ |  | ||||||
| struct lua_State { |  | ||||||
|   CommonHeader; |  | ||||||
|   lu_byte status; |  | ||||||
|   StkId top;  /* first free slot in the stack */ |  | ||||||
|   StkId base;  /* base of current function */ |  | ||||||
|   global_State *l_G; |  | ||||||
|   CallInfo *ci;  /* call info for current function */ |  | ||||||
|   const Instruction *savedpc;  /* `savedpc' of current function */ |  | ||||||
|   StkId stack_last;  /* last free slot in the stack */ |  | ||||||
|   StkId stack;  /* stack base */ |  | ||||||
|   CallInfo *end_ci;  /* points after end of ci array*/ |  | ||||||
|   CallInfo *base_ci;  /* array of CallInfo's */ |  | ||||||
|   int stacksize; |  | ||||||
|   int size_ci;  /* size of array `base_ci' */ |  | ||||||
|   unsigned short nCcalls;  /* number of nested C calls */ |  | ||||||
|   lu_byte hookmask; |  | ||||||
|   lu_byte allowhook; |  | ||||||
|   int basehookcount; |  | ||||||
|   int hookcount; |  | ||||||
|   lua_Hook hook; |  | ||||||
|   TValue l_gt;  /* table of globals */ |  | ||||||
|   TValue env;  /* temporary place for environments */ |  | ||||||
|   GCObject *openupval;  /* list of open upvalues in this stack */ |  | ||||||
|   GCObject *gclist; |  | ||||||
|   struct lua_longjmp *errorJmp;  /* current error recover point */ |  | ||||||
|   ptrdiff_t errfunc;  /* current error handling function (stack index) */ |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define G(L)	(L->l_G) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Union of all collectable objects |  | ||||||
| */ |  | ||||||
| union GCObject { |  | ||||||
|   GCheader gch; |  | ||||||
|   union TString ts; |  | ||||||
|   union Udata u; |  | ||||||
|   union Closure cl; |  | ||||||
|   struct Table h; |  | ||||||
|   struct Proto p; |  | ||||||
|   struct UpVal uv; |  | ||||||
|   struct lua_State th;  /* thread */ |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* macros to convert a GCObject into a specific value */ |  | ||||||
| #define rawgco2ts(o)	check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) |  | ||||||
| #define gco2ts(o)	(&rawgco2ts(o)->tsv) |  | ||||||
| #define rawgco2u(o)	check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) |  | ||||||
| #define gco2u(o)	(&rawgco2u(o)->uv) |  | ||||||
| #define gco2cl(o)	check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) |  | ||||||
| #define gco2h(o)	check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) |  | ||||||
| #define gco2p(o)	check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) |  | ||||||
| #define gco2uv(o)	check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) |  | ||||||
| #define ngcotouv(o) \ |  | ||||||
| 	check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv)) |  | ||||||
| #define gco2th(o)	check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) |  | ||||||
|  |  | ||||||
| /* macro to convert any Lua object into a GCObject */ |  | ||||||
| #define obj2gco(v)	(cast(GCObject *, (v))) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUAI_FUNC lua_State *luaE_newthread (lua_State *L); |  | ||||||
| LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| @@ -1,111 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lstring.c,v 2.8 2005/12/22 16:19:56 roberto Exp $ |  | ||||||
| ** String table (keeps all strings handled by Lua) |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define lstring_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lmem.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lstate.h" |  | ||||||
| #include "lstring.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaS_resize (lua_State *L, int newsize) { |  | ||||||
|   GCObject **newhash; |  | ||||||
|   stringtable *tb; |  | ||||||
|   int i; |  | ||||||
|   if (G(L)->gcstate == GCSsweepstring) |  | ||||||
|     return;  /* cannot resize during GC traverse */ |  | ||||||
|   newhash = luaM_newvector(L, newsize, GCObject *); |  | ||||||
|   tb = &G(L)->strt; |  | ||||||
|   for (i=0; i<newsize; i++) newhash[i] = NULL; |  | ||||||
|   /* rehash */ |  | ||||||
|   for (i=0; i<tb->size; i++) { |  | ||||||
|     GCObject *p = tb->hash[i]; |  | ||||||
|     while (p) {  /* for each node in the list */ |  | ||||||
|       GCObject *next = p->gch.next;  /* save next */ |  | ||||||
|       unsigned int h = gco2ts(p)->hash; |  | ||||||
|       int h1 = lmod(h, newsize);  /* new position */ |  | ||||||
|       lua_assert(cast_int(h%newsize) == lmod(h, newsize)); |  | ||||||
|       p->gch.next = newhash[h1];  /* chain it */ |  | ||||||
|       newhash[h1] = p; |  | ||||||
|       p = next; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   luaM_freearray(L, tb->hash, tb->size, TString *); |  | ||||||
|   tb->size = newsize; |  | ||||||
|   tb->hash = newhash; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static TString *newlstr (lua_State *L, const char *str, size_t l, |  | ||||||
|                                        unsigned int h) { |  | ||||||
|   TString *ts; |  | ||||||
|   stringtable *tb; |  | ||||||
|   if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) |  | ||||||
|     luaM_toobig(L); |  | ||||||
|   ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString))); |  | ||||||
|   ts->tsv.len = l; |  | ||||||
|   ts->tsv.hash = h; |  | ||||||
|   ts->tsv.marked = luaC_white(G(L)); |  | ||||||
|   ts->tsv.tt = LUA_TSTRING; |  | ||||||
|   ts->tsv.reserved = 0; |  | ||||||
|   memcpy(ts+1, str, l*sizeof(char)); |  | ||||||
|   ((char *)(ts+1))[l] = '\0';  /* ending 0 */ |  | ||||||
|   tb = &G(L)->strt; |  | ||||||
|   h = lmod(h, tb->size); |  | ||||||
|   ts->tsv.next = tb->hash[h];  /* chain new entry */ |  | ||||||
|   tb->hash[h] = obj2gco(ts); |  | ||||||
|   tb->nuse++; |  | ||||||
|   if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) |  | ||||||
|     luaS_resize(L, tb->size*2);  /* too crowded */ |  | ||||||
|   return ts; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { |  | ||||||
|   GCObject *o; |  | ||||||
|   unsigned int h = cast(unsigned int, l);  /* seed */ |  | ||||||
|   size_t step = (l>>5)+1;  /* if string is too long, don't hash all its chars */ |  | ||||||
|   size_t l1; |  | ||||||
|   for (l1=l; l1>=step; l1-=step)  /* compute hash */ |  | ||||||
|     h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); |  | ||||||
|   for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; |  | ||||||
|        o != NULL; |  | ||||||
|        o = o->gch.next) { |  | ||||||
|     TString *ts = rawgco2ts(o); |  | ||||||
|     if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { |  | ||||||
|       /* string may be dead */ |  | ||||||
|       if (isdead(G(L), o)) changewhite(o); |  | ||||||
|       return ts; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return newlstr(L, str, l, h);  /* not found */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { |  | ||||||
|   Udata *u; |  | ||||||
|   if (s > MAX_SIZET - sizeof(Udata)) |  | ||||||
|     luaM_toobig(L); |  | ||||||
|   u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata))); |  | ||||||
|   u->uv.marked = luaC_white(G(L));  /* is not finalized */ |  | ||||||
|   u->uv.tt = LUA_TUSERDATA; |  | ||||||
|   u->uv.len = s; |  | ||||||
|   u->uv.metatable = NULL; |  | ||||||
|   u->uv.env = e; |  | ||||||
|   /* chain it on udata list (after main thread) */ |  | ||||||
|   u->uv.next = G(L)->mainthread->next; |  | ||||||
|   G(L)->mainthread->next = obj2gco(u); |  | ||||||
|   return u; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lstring.h,v 1.43 2005/04/25 19:24:10 roberto Exp $ |  | ||||||
| ** String table (keep all strings handled by Lua) |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef lstring_h |  | ||||||
| #define lstring_h |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "lgc.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lstate.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define sizestring(s)	(sizeof(union TString)+((s)->len+1)*sizeof(char)) |  | ||||||
|  |  | ||||||
| #define sizeudata(u)	(sizeof(union Udata)+(u)->len) |  | ||||||
|  |  | ||||||
| #define luaS_new(L, s)	(luaS_newlstr(L, s, strlen(s))) |  | ||||||
| #define luaS_newliteral(L, s)	(luaS_newlstr(L, "" s, \ |  | ||||||
|                                  (sizeof(s)/sizeof(char))-1)) |  | ||||||
|  |  | ||||||
| #define luaS_fix(s)	l_setbit((s)->tsv.marked, FIXEDBIT) |  | ||||||
|  |  | ||||||
| LUAI_FUNC void luaS_resize (lua_State *L, int newsize); |  | ||||||
| LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e); |  | ||||||
| LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,863 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lstrlib.c,v 1.130 2005/12/29 15:32:11 roberto Exp $ |  | ||||||
| ** Standard library for string operations and pattern-matching |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <ctype.h> |  | ||||||
| #include <stddef.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define lstrlib_c |  | ||||||
| #define LUA_LIB |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lauxlib.h" |  | ||||||
| #include "lualib.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* macro to `unsign' a character */ |  | ||||||
| #define uchar(c)        ((unsigned char)(c)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int str_len (lua_State *L) { |  | ||||||
|   size_t l; |  | ||||||
|   luaL_checklstring(L, 1, &l); |  | ||||||
|   lua_pushinteger(L, l); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { |  | ||||||
|   /* relative string position: negative means back from end */ |  | ||||||
|   return (pos>=0) ? pos : (ptrdiff_t)len+pos+1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int str_sub (lua_State *L) { |  | ||||||
|   size_t l; |  | ||||||
|   const char *s = luaL_checklstring(L, 1, &l); |  | ||||||
|   ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); |  | ||||||
|   ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); |  | ||||||
|   if (start < 1) start = 1; |  | ||||||
|   if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; |  | ||||||
|   if (start <= end) |  | ||||||
|     lua_pushlstring(L, s+start-1, end-start+1); |  | ||||||
|   else lua_pushliteral(L, ""); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int str_reverse (lua_State *L) { |  | ||||||
|   size_t l; |  | ||||||
|   luaL_Buffer b; |  | ||||||
|   const char *s = luaL_checklstring(L, 1, &l); |  | ||||||
|   luaL_buffinit(L, &b); |  | ||||||
|   while (l--) luaL_addchar(&b, s[l]); |  | ||||||
|   luaL_pushresult(&b); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int str_lower (lua_State *L) { |  | ||||||
|   size_t l; |  | ||||||
|   size_t i; |  | ||||||
|   luaL_Buffer b; |  | ||||||
|   const char *s = luaL_checklstring(L, 1, &l); |  | ||||||
|   luaL_buffinit(L, &b); |  | ||||||
|   for (i=0; i<l; i++) |  | ||||||
|     luaL_addchar(&b, tolower(uchar(s[i]))); |  | ||||||
|   luaL_pushresult(&b); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int str_upper (lua_State *L) { |  | ||||||
|   size_t l; |  | ||||||
|   size_t i; |  | ||||||
|   luaL_Buffer b; |  | ||||||
|   const char *s = luaL_checklstring(L, 1, &l); |  | ||||||
|   luaL_buffinit(L, &b); |  | ||||||
|   for (i=0; i<l; i++) |  | ||||||
|     luaL_addchar(&b, toupper(uchar(s[i]))); |  | ||||||
|   luaL_pushresult(&b); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int str_rep (lua_State *L) { |  | ||||||
|   size_t l; |  | ||||||
|   luaL_Buffer b; |  | ||||||
|   const char *s = luaL_checklstring(L, 1, &l); |  | ||||||
|   int n = luaL_checkint(L, 2); |  | ||||||
|   luaL_buffinit(L, &b); |  | ||||||
|   while (n-- > 0) |  | ||||||
|     luaL_addlstring(&b, s, l); |  | ||||||
|   luaL_pushresult(&b); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int str_byte (lua_State *L) { |  | ||||||
|   size_t l; |  | ||||||
|   const char *s = luaL_checklstring(L, 1, &l); |  | ||||||
|   ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); |  | ||||||
|   ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); |  | ||||||
|   int n, i; |  | ||||||
|   if (posi <= 0) posi = 1; |  | ||||||
|   if ((size_t)pose > l) pose = l; |  | ||||||
|   if (posi > pose) return 0;  /* empty interval; return no values */ |  | ||||||
|   n = (int)(pose -  posi + 1); |  | ||||||
|   if (posi + n <= pose)  /* overflow? */ |  | ||||||
|     luaL_error(L, "string slice too long"); |  | ||||||
|   luaL_checkstack(L, n, "string slice too long"); |  | ||||||
|   for (i=0; i<n; i++) |  | ||||||
|     lua_pushinteger(L, uchar(s[posi+i-1])); |  | ||||||
|   return n; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int str_char (lua_State *L) { |  | ||||||
|   int n = lua_gettop(L);  /* number of arguments */ |  | ||||||
|   int i; |  | ||||||
|   luaL_Buffer b; |  | ||||||
|   luaL_buffinit(L, &b); |  | ||||||
|   for (i=1; i<=n; i++) { |  | ||||||
|     int c = luaL_checkint(L, i); |  | ||||||
|     luaL_argcheck(L, uchar(c) == c, i, "invalid value"); |  | ||||||
|     luaL_addchar(&b, uchar(c)); |  | ||||||
|   } |  | ||||||
|   luaL_pushresult(&b); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int writer (lua_State *L, const void* b, size_t size, void* B) { |  | ||||||
|   (void)L; |  | ||||||
|   luaL_addlstring((luaL_Buffer*) B, (const char *)b, size); |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int str_dump (lua_State *L) { |  | ||||||
|   luaL_Buffer b; |  | ||||||
|   luaL_checktype(L, 1, LUA_TFUNCTION); |  | ||||||
|   lua_settop(L, 1); |  | ||||||
|   luaL_buffinit(L,&b); |  | ||||||
|   if (lua_dump(L, writer, &b) != 0) |  | ||||||
|     luaL_error(L, "unable to dump given function"); |  | ||||||
|   luaL_pushresult(&b); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** PATTERN MATCHING |  | ||||||
| ** ======================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define CAP_UNFINISHED	(-1) |  | ||||||
| #define CAP_POSITION	(-2) |  | ||||||
|  |  | ||||||
| typedef struct MatchState { |  | ||||||
|   const char *src_init;  /* init of source string */ |  | ||||||
|   const char *src_end;  /* end (`\0') of source string */ |  | ||||||
|   lua_State *L; |  | ||||||
|   int level;  /* total number of captures (finished or unfinished) */ |  | ||||||
|   struct { |  | ||||||
|     const char *init; |  | ||||||
|     ptrdiff_t len; |  | ||||||
|   } capture[LUA_MAXCAPTURES]; |  | ||||||
| } MatchState; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define L_ESC		'%' |  | ||||||
| #define SPECIALS	"^$*+?.([%-" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int check_capture (MatchState *ms, int l) { |  | ||||||
|   l -= '1'; |  | ||||||
|   if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) |  | ||||||
|     return luaL_error(ms->L, "invalid capture index"); |  | ||||||
|   return l; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int capture_to_close (MatchState *ms) { |  | ||||||
|   int level = ms->level; |  | ||||||
|   for (level--; level>=0; level--) |  | ||||||
|     if (ms->capture[level].len == CAP_UNFINISHED) return level; |  | ||||||
|   return luaL_error(ms->L, "invalid pattern capture"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *classend (MatchState *ms, const char *p) { |  | ||||||
|   switch (*p++) { |  | ||||||
|     case L_ESC: { |  | ||||||
|       if (*p == '\0') |  | ||||||
|         luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); |  | ||||||
|       return p+1; |  | ||||||
|     } |  | ||||||
|     case '[': { |  | ||||||
|       if (*p == '^') p++; |  | ||||||
|       do {  /* look for a `]' */ |  | ||||||
|         if (*p == '\0') |  | ||||||
|           luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); |  | ||||||
|         if (*(p++) == L_ESC && *p != '\0') |  | ||||||
|           p++;  /* skip escapes (e.g. `%]') */ |  | ||||||
|       } while (*p != ']'); |  | ||||||
|       return p+1; |  | ||||||
|     } |  | ||||||
|     default: { |  | ||||||
|       return p; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int match_class (int c, int cl) { |  | ||||||
|   int res; |  | ||||||
|   switch (tolower(cl)) { |  | ||||||
|     case 'a' : res = isalpha(c); break; |  | ||||||
|     case 'c' : res = iscntrl(c); break; |  | ||||||
|     case 'd' : res = isdigit(c); break; |  | ||||||
|     case 'l' : res = islower(c); break; |  | ||||||
|     case 'p' : res = ispunct(c); break; |  | ||||||
|     case 's' : res = isspace(c); break; |  | ||||||
|     case 'u' : res = isupper(c); break; |  | ||||||
|     case 'w' : res = isalnum(c); break; |  | ||||||
|     case 'x' : res = isxdigit(c); break; |  | ||||||
|     case 'z' : res = (c == 0); break; |  | ||||||
|     default: return (cl == c); |  | ||||||
|   } |  | ||||||
|   return (islower(cl) ? res : !res); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int matchbracketclass (int c, const char *p, const char *ec) { |  | ||||||
|   int sig = 1; |  | ||||||
|   if (*(p+1) == '^') { |  | ||||||
|     sig = 0; |  | ||||||
|     p++;  /* skip the `^' */ |  | ||||||
|   } |  | ||||||
|   while (++p < ec) { |  | ||||||
|     if (*p == L_ESC) { |  | ||||||
|       p++; |  | ||||||
|       if (match_class(c, uchar(*p))) |  | ||||||
|         return sig; |  | ||||||
|     } |  | ||||||
|     else if ((*(p+1) == '-') && (p+2 < ec)) { |  | ||||||
|       p+=2; |  | ||||||
|       if (uchar(*(p-2)) <= c && c <= uchar(*p)) |  | ||||||
|         return sig; |  | ||||||
|     } |  | ||||||
|     else if (uchar(*p) == c) return sig; |  | ||||||
|   } |  | ||||||
|   return !sig; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int singlematch (int c, const char *p, const char *ep) { |  | ||||||
|   switch (*p) { |  | ||||||
|     case '.': return 1;  /* matches any char */ |  | ||||||
|     case L_ESC: return match_class(c, uchar(*(p+1))); |  | ||||||
|     case '[': return matchbracketclass(c, p, ep-1); |  | ||||||
|     default:  return (uchar(*p) == c); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *match (MatchState *ms, const char *s, const char *p); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *matchbalance (MatchState *ms, const char *s, |  | ||||||
|                                    const char *p) { |  | ||||||
|   if (*p == 0 || *(p+1) == 0) |  | ||||||
|     luaL_error(ms->L, "unbalanced pattern"); |  | ||||||
|   if (*s != *p) return NULL; |  | ||||||
|   else { |  | ||||||
|     int b = *p; |  | ||||||
|     int e = *(p+1); |  | ||||||
|     int cont = 1; |  | ||||||
|     while (++s < ms->src_end) { |  | ||||||
|       if (*s == e) { |  | ||||||
|         if (--cont == 0) return s+1; |  | ||||||
|       } |  | ||||||
|       else if (*s == b) cont++; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return NULL;  /* string ends out of balance */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *max_expand (MatchState *ms, const char *s, |  | ||||||
|                                  const char *p, const char *ep) { |  | ||||||
|   ptrdiff_t i = 0;  /* counts maximum expand for item */ |  | ||||||
|   while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep)) |  | ||||||
|     i++; |  | ||||||
|   /* keeps trying to match with the maximum repetitions */ |  | ||||||
|   while (i>=0) { |  | ||||||
|     const char *res = match(ms, (s+i), ep+1); |  | ||||||
|     if (res) return res; |  | ||||||
|     i--;  /* else didn't match; reduce 1 repetition to try again */ |  | ||||||
|   } |  | ||||||
|   return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *min_expand (MatchState *ms, const char *s, |  | ||||||
|                                  const char *p, const char *ep) { |  | ||||||
|   for (;;) { |  | ||||||
|     const char *res = match(ms, s, ep+1); |  | ||||||
|     if (res != NULL) |  | ||||||
|       return res; |  | ||||||
|     else if (s<ms->src_end && singlematch(uchar(*s), p, ep)) |  | ||||||
|       s++;  /* try with one more repetition */ |  | ||||||
|     else return NULL; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *start_capture (MatchState *ms, const char *s, |  | ||||||
|                                     const char *p, int what) { |  | ||||||
|   const char *res; |  | ||||||
|   int level = ms->level; |  | ||||||
|   if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); |  | ||||||
|   ms->capture[level].init = s; |  | ||||||
|   ms->capture[level].len = what; |  | ||||||
|   ms->level = level+1; |  | ||||||
|   if ((res=match(ms, s, p)) == NULL)  /* match failed? */ |  | ||||||
|     ms->level--;  /* undo capture */ |  | ||||||
|   return res; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *end_capture (MatchState *ms, const char *s, |  | ||||||
|                                   const char *p) { |  | ||||||
|   int l = capture_to_close(ms); |  | ||||||
|   const char *res; |  | ||||||
|   ms->capture[l].len = s - ms->capture[l].init;  /* close capture */ |  | ||||||
|   if ((res = match(ms, s, p)) == NULL)  /* match failed? */ |  | ||||||
|     ms->capture[l].len = CAP_UNFINISHED;  /* undo capture */ |  | ||||||
|   return res; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *match_capture (MatchState *ms, const char *s, int l) { |  | ||||||
|   size_t len; |  | ||||||
|   l = check_capture(ms, l); |  | ||||||
|   len = ms->capture[l].len; |  | ||||||
|   if ((size_t)(ms->src_end-s) >= len && |  | ||||||
|       memcmp(ms->capture[l].init, s, len) == 0) |  | ||||||
|     return s+len; |  | ||||||
|   else return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *match (MatchState *ms, const char *s, const char *p) { |  | ||||||
|   init: /* using goto's to optimize tail recursion */ |  | ||||||
|   switch (*p) { |  | ||||||
|     case '(': {  /* start capture */ |  | ||||||
|       if (*(p+1) == ')')  /* position capture? */ |  | ||||||
|         return start_capture(ms, s, p+2, CAP_POSITION); |  | ||||||
|       else |  | ||||||
|         return start_capture(ms, s, p+1, CAP_UNFINISHED); |  | ||||||
|     } |  | ||||||
|     case ')': {  /* end capture */ |  | ||||||
|       return end_capture(ms, s, p+1); |  | ||||||
|     } |  | ||||||
|     case L_ESC: { |  | ||||||
|       switch (*(p+1)) { |  | ||||||
|         case 'b': {  /* balanced string? */ |  | ||||||
|           s = matchbalance(ms, s, p+2); |  | ||||||
|           if (s == NULL) return NULL; |  | ||||||
|           p+=4; goto init;  /* else return match(ms, s, p+4); */ |  | ||||||
|         } |  | ||||||
|         case 'f': {  /* frontier? */ |  | ||||||
|           const char *ep; char previous; |  | ||||||
|           p += 2; |  | ||||||
|           if (*p != '[') |  | ||||||
|             luaL_error(ms->L, "missing " LUA_QL("[") " after " |  | ||||||
|                                LUA_QL("%%f") " in pattern"); |  | ||||||
|           ep = classend(ms, p);  /* points to what is next */ |  | ||||||
|           previous = (s == ms->src_init) ? '\0' : *(s-1); |  | ||||||
|           if (matchbracketclass(uchar(previous), p, ep-1) || |  | ||||||
|              !matchbracketclass(uchar(*s), p, ep-1)) return NULL; |  | ||||||
|           p=ep; goto init;  /* else return match(ms, s, ep); */ |  | ||||||
|         } |  | ||||||
|         default: { |  | ||||||
|           if (isdigit(uchar(*(p+1)))) {  /* capture results (%0-%9)? */ |  | ||||||
|             s = match_capture(ms, s, uchar(*(p+1))); |  | ||||||
|             if (s == NULL) return NULL; |  | ||||||
|             p+=2; goto init;  /* else return match(ms, s, p+2) */ |  | ||||||
|           } |  | ||||||
|           goto dflt;  /* case default */ |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     case '\0': {  /* end of pattern */ |  | ||||||
|       return s;  /* match succeeded */ |  | ||||||
|     } |  | ||||||
|     case '$': { |  | ||||||
|       if (*(p+1) == '\0')  /* is the `$' the last char in pattern? */ |  | ||||||
|         return (s == ms->src_end) ? s : NULL;  /* check end of string */ |  | ||||||
|       else goto dflt; |  | ||||||
|     } |  | ||||||
|     default: dflt: {  /* it is a pattern item */ |  | ||||||
|       const char *ep = classend(ms, p);  /* points to what is next */ |  | ||||||
|       int m = s<ms->src_end && singlematch(uchar(*s), p, ep); |  | ||||||
|       switch (*ep) { |  | ||||||
|         case '?': {  /* optional */ |  | ||||||
|           const char *res; |  | ||||||
|           if (m && ((res=match(ms, s+1, ep+1)) != NULL)) |  | ||||||
|             return res; |  | ||||||
|           p=ep+1; goto init;  /* else return match(ms, s, ep+1); */ |  | ||||||
|         } |  | ||||||
|         case '*': {  /* 0 or more repetitions */ |  | ||||||
|           return max_expand(ms, s, p, ep); |  | ||||||
|         } |  | ||||||
|         case '+': {  /* 1 or more repetitions */ |  | ||||||
|           return (m ? max_expand(ms, s+1, p, ep) : NULL); |  | ||||||
|         } |  | ||||||
|         case '-': {  /* 0 or more repetitions (minimum) */ |  | ||||||
|           return min_expand(ms, s, p, ep); |  | ||||||
|         } |  | ||||||
|         default: { |  | ||||||
|           if (!m) return NULL; |  | ||||||
|           s++; p=ep; goto init;  /* else return match(ms, s+1, ep); */ |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *lmemfind (const char *s1, size_t l1, |  | ||||||
|                                const char *s2, size_t l2) { |  | ||||||
|   if (l2 == 0) return s1;  /* empty strings are everywhere */ |  | ||||||
|   else if (l2 > l1) return NULL;  /* avoids a negative `l1' */ |  | ||||||
|   else { |  | ||||||
|     const char *init;  /* to search for a `*s2' inside `s1' */ |  | ||||||
|     l2--;  /* 1st char will be checked by `memchr' */ |  | ||||||
|     l1 = l1-l2;  /* `s2' cannot be found after that */ |  | ||||||
|     while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { |  | ||||||
|       init++;   /* 1st char is already checked */ |  | ||||||
|       if (memcmp(init, s2+1, l2) == 0) |  | ||||||
|         return init-1; |  | ||||||
|       else {  /* correct `l1' and `s1' to try again */ |  | ||||||
|         l1 -= init-s1; |  | ||||||
|         s1 = init; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     return NULL;  /* not found */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void push_onecapture (MatchState *ms, int i, const char *s, |  | ||||||
|                                                     const char *e) { |  | ||||||
|   if (i >= ms->level) { |  | ||||||
|     if (i == 0)  /* ms->level == 0, too */ |  | ||||||
|       lua_pushlstring(ms->L, s, e - s);  /* add whole match */ |  | ||||||
|     else |  | ||||||
|       luaL_error(ms->L, "invalid capture index"); |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     ptrdiff_t l = ms->capture[i].len; |  | ||||||
|     if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); |  | ||||||
|     if (l == CAP_POSITION) |  | ||||||
|       lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); |  | ||||||
|     else |  | ||||||
|       lua_pushlstring(ms->L, ms->capture[i].init, l); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int push_captures (MatchState *ms, const char *s, const char *e) { |  | ||||||
|   int i; |  | ||||||
|   int nlevels = (ms->level == 0 && s) ? 1 : ms->level; |  | ||||||
|   luaL_checkstack(ms->L, nlevels, "too many captures"); |  | ||||||
|   for (i = 0; i < nlevels; i++) |  | ||||||
|     push_onecapture(ms, i, s, e); |  | ||||||
|   return nlevels;  /* number of strings pushed */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int str_find_aux (lua_State *L, int find) { |  | ||||||
|   size_t l1, l2; |  | ||||||
|   const char *s = luaL_checklstring(L, 1, &l1); |  | ||||||
|   const char *p = luaL_checklstring(L, 2, &l2); |  | ||||||
|   ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; |  | ||||||
|   if (init < 0) init = 0; |  | ||||||
|   else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; |  | ||||||
|   if (find && (lua_toboolean(L, 4) ||  /* explicit request? */ |  | ||||||
|       strpbrk(p, SPECIALS) == NULL)) {  /* or no special characters? */ |  | ||||||
|     /* do a plain search */ |  | ||||||
|     const char *s2 = lmemfind(s+init, l1-init, p, l2); |  | ||||||
|     if (s2) { |  | ||||||
|       lua_pushinteger(L, s2-s+1); |  | ||||||
|       lua_pushinteger(L, s2-s+l2); |  | ||||||
|       return 2; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     MatchState ms; |  | ||||||
|     int anchor = (*p == '^') ? (p++, 1) : 0; |  | ||||||
|     const char *s1=s+init; |  | ||||||
|     ms.L = L; |  | ||||||
|     ms.src_init = s; |  | ||||||
|     ms.src_end = s+l1; |  | ||||||
|     do { |  | ||||||
|       const char *res; |  | ||||||
|       ms.level = 0; |  | ||||||
|       if ((res=match(&ms, s1, p)) != NULL) { |  | ||||||
|         if (find) { |  | ||||||
|           lua_pushinteger(L, s1-s+1);  /* start */ |  | ||||||
|           lua_pushinteger(L, res-s);   /* end */ |  | ||||||
|           return push_captures(&ms, NULL, 0) + 2; |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|           return push_captures(&ms, s1, res); |  | ||||||
|       } |  | ||||||
|     } while (s1++ < ms.src_end && !anchor); |  | ||||||
|   } |  | ||||||
|   lua_pushnil(L);  /* not found */ |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int str_find (lua_State *L) { |  | ||||||
|   return str_find_aux(L, 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int str_match (lua_State *L) { |  | ||||||
|   return str_find_aux(L, 0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int gmatch_aux (lua_State *L) { |  | ||||||
|   MatchState ms; |  | ||||||
|   size_t ls; |  | ||||||
|   const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); |  | ||||||
|   const char *p = lua_tostring(L, lua_upvalueindex(2)); |  | ||||||
|   const char *src; |  | ||||||
|   ms.L = L; |  | ||||||
|   ms.src_init = s; |  | ||||||
|   ms.src_end = s+ls; |  | ||||||
|   for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); |  | ||||||
|        src <= ms.src_end; |  | ||||||
|        src++) { |  | ||||||
|     const char *e; |  | ||||||
|     ms.level = 0; |  | ||||||
|     if ((e = match(&ms, src, p)) != NULL) { |  | ||||||
|       lua_Integer newstart = e-s; |  | ||||||
|       if (e == src) newstart++;  /* empty match? go at least one position */ |  | ||||||
|       lua_pushinteger(L, newstart); |  | ||||||
|       lua_replace(L, lua_upvalueindex(3)); |  | ||||||
|       return push_captures(&ms, src, e); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return 0;  /* not found */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int gmatch (lua_State *L) { |  | ||||||
|   luaL_checkstring(L, 1); |  | ||||||
|   luaL_checkstring(L, 2); |  | ||||||
|   lua_settop(L, 2); |  | ||||||
|   lua_pushinteger(L, 0); |  | ||||||
|   lua_pushcclosure(L, gmatch_aux, 3); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int gfind_nodef (lua_State *L) { |  | ||||||
|   return luaL_error(L, LUA_QL("string.gfind") " was renamed to " |  | ||||||
|                        LUA_QL("string.gmatch")); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, |  | ||||||
|                                                    const char *e) { |  | ||||||
|   size_t l, i; |  | ||||||
|   const char *news = lua_tolstring(ms->L, 3, &l); |  | ||||||
|   for (i = 0; i < l; i++) { |  | ||||||
|     if (news[i] != L_ESC) |  | ||||||
|       luaL_addchar(b, news[i]); |  | ||||||
|     else { |  | ||||||
|       i++;  /* skip ESC */ |  | ||||||
|       if (!isdigit(uchar(news[i]))) |  | ||||||
|         luaL_addchar(b, news[i]); |  | ||||||
|       else if (news[i] == '0') |  | ||||||
|           luaL_addlstring(b, s, e - s); |  | ||||||
|       else { |  | ||||||
|         push_onecapture(ms, news[i] - '1', s, e); |  | ||||||
|         luaL_addvalue(b);  /* add capture to accumulated result */ |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, |  | ||||||
|                                                        const char *e) { |  | ||||||
|   lua_State *L = ms->L; |  | ||||||
|   switch (lua_type(L, 3)) { |  | ||||||
|     case LUA_TNUMBER: |  | ||||||
|     case LUA_TSTRING: { |  | ||||||
|       add_s(ms, b, s, e); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     case LUA_TFUNCTION: { |  | ||||||
|       int n; |  | ||||||
|       lua_pushvalue(L, 3); |  | ||||||
|       n = push_captures(ms, s, e); |  | ||||||
|       lua_call(L, n, 1); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case LUA_TTABLE: { |  | ||||||
|       push_onecapture(ms, 0, s, e); |  | ||||||
|       lua_gettable(L, 3); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     default: { |  | ||||||
|       luaL_argerror(L, 3, "string/function/table expected");  |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   if (!lua_toboolean(L, -1)) {  /* nil or false? */ |  | ||||||
|     lua_pop(L, 1); |  | ||||||
|     lua_pushlstring(L, s, e - s);  /* keep original text */ |  | ||||||
|   } |  | ||||||
|   else if (!lua_isstring(L, -1)) |  | ||||||
|     luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1));  |  | ||||||
|   luaL_addvalue(b);  /* add result to accumulator */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int str_gsub (lua_State *L) { |  | ||||||
|   size_t srcl; |  | ||||||
|   const char *src = luaL_checklstring(L, 1, &srcl); |  | ||||||
|   const char *p = luaL_checkstring(L, 2); |  | ||||||
|   int max_s = luaL_optint(L, 4, srcl+1); |  | ||||||
|   int anchor = (*p == '^') ? (p++, 1) : 0; |  | ||||||
|   int n = 0; |  | ||||||
|   MatchState ms; |  | ||||||
|   luaL_Buffer b; |  | ||||||
|   luaL_buffinit(L, &b); |  | ||||||
|   ms.L = L; |  | ||||||
|   ms.src_init = src; |  | ||||||
|   ms.src_end = src+srcl; |  | ||||||
|   while (n < max_s) { |  | ||||||
|     const char *e; |  | ||||||
|     ms.level = 0; |  | ||||||
|     e = match(&ms, src, p); |  | ||||||
|     if (e) { |  | ||||||
|       n++; |  | ||||||
|       add_value(&ms, &b, src, e); |  | ||||||
|     } |  | ||||||
|     if (e && e>src) /* non empty match? */ |  | ||||||
|       src = e;  /* skip it */ |  | ||||||
|     else if (src < ms.src_end) |  | ||||||
|       luaL_addchar(&b, *src++); |  | ||||||
|     else break; |  | ||||||
|     if (anchor) break; |  | ||||||
|   } |  | ||||||
|   luaL_addlstring(&b, src, ms.src_end-src); |  | ||||||
|   luaL_pushresult(&b); |  | ||||||
|   lua_pushinteger(L, n);  /* number of substitutions */ |  | ||||||
|   return 2; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ |  | ||||||
| #define MAX_ITEM	512 |  | ||||||
| /* valid flags in a format specification */ |  | ||||||
| #define FLAGS	"-+ #0" |  | ||||||
| /* |  | ||||||
| ** maximum size of each format specification (such as '%-099.99d') |  | ||||||
| ** (+10 accounts for %99.99x plus margin of error) |  | ||||||
| */ |  | ||||||
| #define MAX_FORMAT	(sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { |  | ||||||
|   size_t l; |  | ||||||
|   const char *s = luaL_checklstring(L, arg, &l); |  | ||||||
|   luaL_addchar(b, '"'); |  | ||||||
|   while (l--) { |  | ||||||
|     switch (*s) { |  | ||||||
|       case '"': case '\\': case '\n': { |  | ||||||
|         luaL_addchar(b, '\\'); |  | ||||||
|         luaL_addchar(b, *s); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case '\0': { |  | ||||||
|         luaL_addlstring(b, "\\000", 4); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       default: { |  | ||||||
|         luaL_addchar(b, *s); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     s++; |  | ||||||
|   } |  | ||||||
|   luaL_addchar(b, '"'); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { |  | ||||||
|   const char *p = strfrmt; |  | ||||||
|   while (strchr(FLAGS, *p)) p++;  /* skip flags */ |  | ||||||
|   if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) |  | ||||||
|     luaL_error(L, "invalid format (repeated flags)"); |  | ||||||
|   if (isdigit(uchar(*p))) p++;  /* skip width */ |  | ||||||
|   if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */ |  | ||||||
|   if (*p == '.') { |  | ||||||
|     p++; |  | ||||||
|     if (isdigit(uchar(*p))) p++;  /* skip precision */ |  | ||||||
|     if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */ |  | ||||||
|   } |  | ||||||
|   if (isdigit(uchar(*p))) |  | ||||||
|     luaL_error(L, "invalid format (width or precision too long)"); |  | ||||||
|   *(form++) = '%'; |  | ||||||
|   strncpy(form, strfrmt, p - strfrmt + 1); |  | ||||||
|   form += p - strfrmt + 1; |  | ||||||
|   *form = '\0'; |  | ||||||
|   return p; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void addintlen (char *form) { |  | ||||||
|   size_t l = strlen(form); |  | ||||||
|   char spec = form[l - 1]; |  | ||||||
|   strcpy(form + l - 1, LUA_INTFRMLEN); |  | ||||||
|   form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; |  | ||||||
|   form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int str_format (lua_State *L) { |  | ||||||
|   int arg = 1; |  | ||||||
|   size_t sfl; |  | ||||||
|   const char *strfrmt = luaL_checklstring(L, arg, &sfl); |  | ||||||
|   const char *strfrmt_end = strfrmt+sfl; |  | ||||||
|   luaL_Buffer b; |  | ||||||
|   luaL_buffinit(L, &b); |  | ||||||
|   while (strfrmt < strfrmt_end) { |  | ||||||
|     if (*strfrmt != L_ESC) |  | ||||||
|       luaL_addchar(&b, *strfrmt++); |  | ||||||
|     else if (*++strfrmt == L_ESC) |  | ||||||
|       luaL_addchar(&b, *strfrmt++);  /* %% */ |  | ||||||
|     else { /* format item */ |  | ||||||
|       char form[MAX_FORMAT];  /* to store the format (`%...') */ |  | ||||||
|       char buff[MAX_ITEM];  /* to store the formatted item */ |  | ||||||
|       arg++; |  | ||||||
|       strfrmt = scanformat(L, strfrmt, form); |  | ||||||
|       switch (*strfrmt++) { |  | ||||||
|         case 'c': { |  | ||||||
|           sprintf(buff, form, (int)luaL_checknumber(L, arg)); |  | ||||||
|           break; |  | ||||||
|         } |  | ||||||
|         case 'd':  case 'i': { |  | ||||||
|           addintlen(form); |  | ||||||
|           sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); |  | ||||||
|           break; |  | ||||||
|         } |  | ||||||
|         case 'o':  case 'u':  case 'x':  case 'X': { |  | ||||||
|           addintlen(form); |  | ||||||
|           sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); |  | ||||||
|           break; |  | ||||||
|         } |  | ||||||
|         case 'e':  case 'E': case 'f': |  | ||||||
|         case 'g': case 'G': { |  | ||||||
|           sprintf(buff, form, (double)luaL_checknumber(L, arg)); |  | ||||||
|           break; |  | ||||||
|         } |  | ||||||
|         case 'q': { |  | ||||||
|           addquoted(L, &b, arg); |  | ||||||
|           continue;  /* skip the 'addsize' at the end */ |  | ||||||
|         } |  | ||||||
|         case 's': { |  | ||||||
|           size_t l; |  | ||||||
|           const char *s = luaL_checklstring(L, arg, &l); |  | ||||||
|           if (!strchr(form, '.') && l >= 100) { |  | ||||||
|             /* no precision and string is too long to be formatted; |  | ||||||
|                keep original string */ |  | ||||||
|             lua_pushvalue(L, arg); |  | ||||||
|             luaL_addvalue(&b); |  | ||||||
|             continue;  /* skip the `addsize' at the end */ |  | ||||||
|           } |  | ||||||
|           else { |  | ||||||
|             sprintf(buff, form, s); |  | ||||||
|             break; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         default: {  /* also treat cases `pnLlh' */ |  | ||||||
|           return luaL_error(L, "invalid option to " LUA_QL("format")); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       luaL_addlstring(&b, buff, strlen(buff)); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   luaL_pushresult(&b); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const luaL_Reg strlib[] = { |  | ||||||
|   {"byte", str_byte}, |  | ||||||
|   {"char", str_char}, |  | ||||||
|   {"dump", str_dump}, |  | ||||||
|   {"find", str_find}, |  | ||||||
|   {"format", str_format}, |  | ||||||
|   {"gfind", gfind_nodef}, |  | ||||||
|   {"gmatch", gmatch}, |  | ||||||
|   {"gsub", str_gsub}, |  | ||||||
|   {"len", str_len}, |  | ||||||
|   {"lower", str_lower}, |  | ||||||
|   {"match", str_match}, |  | ||||||
|   {"rep", str_rep}, |  | ||||||
|   {"reverse", str_reverse}, |  | ||||||
|   {"sub", str_sub}, |  | ||||||
|   {"upper", str_upper}, |  | ||||||
|   {NULL, NULL} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void createmetatable (lua_State *L) { |  | ||||||
|   lua_createtable(L, 0, 1);  /* create metatable for strings */ |  | ||||||
|   lua_pushliteral(L, "");  /* dummy string */ |  | ||||||
|   lua_pushvalue(L, -2); |  | ||||||
|   lua_setmetatable(L, -2);  /* set string metatable */ |  | ||||||
|   lua_pop(L, 1);  /* pop dummy string */ |  | ||||||
|   lua_pushvalue(L, -2);  /* string library... */ |  | ||||||
|   lua_setfield(L, -2, "__index");  /* ...is the __index metamethod */ |  | ||||||
|   lua_pop(L, 1);  /* pop metatable */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Open string library |  | ||||||
| */ |  | ||||||
| LUALIB_API int luaopen_string (lua_State *L) { |  | ||||||
|   luaL_register(L, LUA_STRLIBNAME, strlib); |  | ||||||
| #if defined(LUA_COMPAT_GFIND) |  | ||||||
|   lua_getfield(L, -1, "gmatch"); |  | ||||||
|   lua_setfield(L, -2, "gfind"); |  | ||||||
| #endif |  | ||||||
|   createmetatable(L); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										588
									
								
								src/lua/ltable.c
									
									
									
									
									
								
							
							
						
						
									
										588
									
								
								src/lua/ltable.c
									
									
									
									
									
								
							| @@ -1,588 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: ltable.c,v 2.32 2006/01/18 11:49:02 roberto Exp $ |  | ||||||
| ** Lua tables (hash) |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Implementation of tables (aka arrays, objects, or hash tables). |  | ||||||
| ** Tables keep its elements in two parts: an array part and a hash part. |  | ||||||
| ** Non-negative integer keys are all candidates to be kept in the array |  | ||||||
| ** part. The actual size of the array is the largest `n' such that at |  | ||||||
| ** least half the slots between 0 and n are in use. |  | ||||||
| ** Hash uses a mix of chained scatter table with Brent's variation. |  | ||||||
| ** A main invariant of these tables is that, if an element is not |  | ||||||
| ** in its main position (i.e. the `original' position that its hash gives |  | ||||||
| ** to it), then the colliding element is in its own main position. |  | ||||||
| ** Hence even when the load factor reaches 100%, performance remains good. |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #include <math.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define ltable_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "ldebug.h" |  | ||||||
| #include "ldo.h" |  | ||||||
| #include "lgc.h" |  | ||||||
| #include "lmem.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lstate.h" |  | ||||||
| #include "ltable.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** max size of array part is 2^MAXBITS |  | ||||||
| */ |  | ||||||
| #if LUAI_BITSINT > 26 |  | ||||||
| #define MAXBITS		26 |  | ||||||
| #else |  | ||||||
| #define MAXBITS		(LUAI_BITSINT-2) |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #define MAXASIZE	(1 << MAXBITS) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define hashpow2(t,n)      (gnode(t, lmod((n), sizenode(t)))) |  | ||||||
|    |  | ||||||
| #define hashstr(t,str)  hashpow2(t, (str)->tsv.hash) |  | ||||||
| #define hashboolean(t,p)        hashpow2(t, p) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** for some types, it is better to avoid modulus by power of 2, as |  | ||||||
| ** they tend to have many 2 factors. |  | ||||||
| */ |  | ||||||
| #define hashmod(t,n)	(gnode(t, ((n) % ((sizenode(t)-1)|1)))) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define hashpointer(t,p)	hashmod(t, IntPoint(p)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** number of ints inside a lua_Number |  | ||||||
| */ |  | ||||||
| #define numints		cast_int(sizeof(lua_Number)/sizeof(int)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define dummynode		(&dummynode_) |  | ||||||
|  |  | ||||||
| static const Node dummynode_ = { |  | ||||||
|   {{NULL}, LUA_TNIL},  /* value */ |  | ||||||
|   {{{NULL}, LUA_TNIL, NULL}}  /* key */ |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** hash for lua_Numbers |  | ||||||
| */ |  | ||||||
| static Node *hashnum (const Table *t, lua_Number n) { |  | ||||||
|   unsigned int a[numints]; |  | ||||||
|   int i; |  | ||||||
|   n += 1;  /* normalize number (avoid -0) */ |  | ||||||
|   lua_assert(sizeof(a) <= sizeof(n)); |  | ||||||
|   memcpy(a, &n, sizeof(a)); |  | ||||||
|   for (i = 1; i < numints; i++) a[0] += a[i]; |  | ||||||
|   return hashmod(t, a[0]); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** returns the `main' position of an element in a table (that is, the index |  | ||||||
| ** of its hash value) |  | ||||||
| */ |  | ||||||
| static Node *mainposition (const Table *t, const TValue *key) { |  | ||||||
|   switch (ttype(key)) { |  | ||||||
|     case LUA_TNUMBER: |  | ||||||
|       return hashnum(t, nvalue(key)); |  | ||||||
|     case LUA_TSTRING: |  | ||||||
|       return hashstr(t, rawtsvalue(key)); |  | ||||||
|     case LUA_TBOOLEAN: |  | ||||||
|       return hashboolean(t, bvalue(key)); |  | ||||||
|     case LUA_TLIGHTUSERDATA: |  | ||||||
|       return hashpointer(t, pvalue(key)); |  | ||||||
|     default: |  | ||||||
|       return hashpointer(t, gcvalue(key)); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** returns the index for `key' if `key' is an appropriate key to live in |  | ||||||
| ** the array part of the table, -1 otherwise. |  | ||||||
| */ |  | ||||||
| static int arrayindex (const TValue *key) { |  | ||||||
|   if (ttisnumber(key)) { |  | ||||||
|     lua_Number n = nvalue(key); |  | ||||||
|     int k; |  | ||||||
|     lua_number2int(k, n); |  | ||||||
|     if (luai_numeq(cast_num(k), n)) |  | ||||||
|       return k; |  | ||||||
|   } |  | ||||||
|   return -1;  /* `key' did not match some condition */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** returns the index of a `key' for table traversals. First goes all |  | ||||||
| ** elements in the array part, then elements in the hash part. The |  | ||||||
| ** beginning of a traversal is signalled by -1. |  | ||||||
| */ |  | ||||||
| static int findindex (lua_State *L, Table *t, StkId key) { |  | ||||||
|   int i; |  | ||||||
|   if (ttisnil(key)) return -1;  /* first iteration */ |  | ||||||
|   i = arrayindex(key); |  | ||||||
|   if (0 < i && i <= t->sizearray)  /* is `key' inside array part? */ |  | ||||||
|     return i-1;  /* yes; that's the index (corrected to C) */ |  | ||||||
|   else { |  | ||||||
|     Node *n = mainposition(t, key); |  | ||||||
|     do {  /* check whether `key' is somewhere in the chain */ |  | ||||||
|       /* key may be dead already, but it is ok to use it in `next' */ |  | ||||||
|       if (luaO_rawequalObj(key2tval(n), key) || |  | ||||||
|             (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && |  | ||||||
|              gcvalue(gkey(n)) == gcvalue(key))) { |  | ||||||
|         i = cast_int(n - gnode(t, 0));  /* key index in hash table */ |  | ||||||
|         /* hash elements are numbered after array ones */ |  | ||||||
|         return i + t->sizearray; |  | ||||||
|       } |  | ||||||
|       else n = gnext(n); |  | ||||||
|     } while (n); |  | ||||||
|     luaG_runerror(L, "invalid key to " LUA_QL("next"));  /* key not found */ |  | ||||||
|     return 0;  /* to avoid warnings */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaH_next (lua_State *L, Table *t, StkId key) { |  | ||||||
|   int i = findindex(L, t, key);  /* find original element */ |  | ||||||
|   for (i++; i < t->sizearray; i++) {  /* try first array part */ |  | ||||||
|     if (!ttisnil(&t->array[i])) {  /* a non-nil value? */ |  | ||||||
|       setnvalue(key, cast_num(i+1)); |  | ||||||
|       setobj2s(L, key+1, &t->array[i]); |  | ||||||
|       return 1; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   for (i -= t->sizearray; i < sizenode(t); i++) {  /* then hash part */ |  | ||||||
|     if (!ttisnil(gval(gnode(t, i)))) {  /* a non-nil value? */ |  | ||||||
|       setobj2s(L, key, key2tval(gnode(t, i))); |  | ||||||
|       setobj2s(L, key+1, gval(gnode(t, i))); |  | ||||||
|       return 1; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return 0;  /* no more elements */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {============================================================= |  | ||||||
| ** Rehash |  | ||||||
| ** ============================================================== |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int computesizes (int nums[], int *narray) { |  | ||||||
|   int i; |  | ||||||
|   int twotoi;  /* 2^i */ |  | ||||||
|   int a = 0;  /* number of elements smaller than 2^i */ |  | ||||||
|   int na = 0;  /* number of elements to go to array part */ |  | ||||||
|   int n = 0;  /* optimal size for array part */ |  | ||||||
|   for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) { |  | ||||||
|     if (nums[i] > 0) { |  | ||||||
|       a += nums[i]; |  | ||||||
|       if (a > twotoi/2) {  /* more than half elements present? */ |  | ||||||
|         n = twotoi;  /* optimal size (till now) */ |  | ||||||
|         na = a;  /* all elements smaller than n will go to array part */ |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     if (a == *narray) break;  /* all elements already counted */ |  | ||||||
|   } |  | ||||||
|   *narray = n; |  | ||||||
|   lua_assert(*narray/2 <= na && na <= *narray); |  | ||||||
|   return na; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int countint (const TValue *key, int *nums) { |  | ||||||
|   int k = arrayindex(key); |  | ||||||
|   if (0 < k && k <= MAXASIZE) {  /* is `key' an appropriate array index? */ |  | ||||||
|     nums[ceillog2(k)]++;  /* count as such */ |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
|   else |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int numusearray (const Table *t, int *nums) { |  | ||||||
|   int lg; |  | ||||||
|   int ttlg;  /* 2^lg */ |  | ||||||
|   int ause = 0;  /* summation of `nums' */ |  | ||||||
|   int i = 1;  /* count to traverse all array keys */ |  | ||||||
|   for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) {  /* for each slice */ |  | ||||||
|     int lc = 0;  /* counter */ |  | ||||||
|     int lim = ttlg; |  | ||||||
|     if (lim > t->sizearray) { |  | ||||||
|       lim = t->sizearray;  /* adjust upper limit */ |  | ||||||
|       if (i > lim) |  | ||||||
|         break;  /* no more elements to count */ |  | ||||||
|     } |  | ||||||
|     /* count elements in range (2^(lg-1), 2^lg] */ |  | ||||||
|     for (; i <= lim; i++) { |  | ||||||
|       if (!ttisnil(&t->array[i-1])) |  | ||||||
|         lc++; |  | ||||||
|     } |  | ||||||
|     nums[lg] += lc; |  | ||||||
|     ause += lc; |  | ||||||
|   } |  | ||||||
|   return ause; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int numusehash (const Table *t, int *nums, int *pnasize) { |  | ||||||
|   int totaluse = 0;  /* total number of elements */ |  | ||||||
|   int ause = 0;  /* summation of `nums' */ |  | ||||||
|   int i = sizenode(t); |  | ||||||
|   while (i--) { |  | ||||||
|     Node *n = &t->node[i]; |  | ||||||
|     if (!ttisnil(gval(n))) { |  | ||||||
|       ause += countint(key2tval(n), nums); |  | ||||||
|       totaluse++; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   *pnasize += ause; |  | ||||||
|   return totaluse; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void setarrayvector (lua_State *L, Table *t, int size) { |  | ||||||
|   int i; |  | ||||||
|   luaM_reallocvector(L, t->array, t->sizearray, size, TValue); |  | ||||||
|   for (i=t->sizearray; i<size; i++) |  | ||||||
|      setnilvalue(&t->array[i]); |  | ||||||
|   t->sizearray = size; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void setnodevector (lua_State *L, Table *t, int size) { |  | ||||||
|   int lsize; |  | ||||||
|   if (size == 0) {  /* no elements to hash part? */ |  | ||||||
|     t->node = cast(Node *, dummynode);  /* use common `dummynode' */ |  | ||||||
|     lsize = 0; |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     int i; |  | ||||||
|     lsize = ceillog2(size); |  | ||||||
|     if (lsize > MAXBITS) |  | ||||||
|       luaG_runerror(L, "table overflow"); |  | ||||||
|     size = twoto(lsize); |  | ||||||
|     t->node = luaM_newvector(L, size, Node); |  | ||||||
|     for (i=0; i<size; i++) { |  | ||||||
|       Node *n = gnode(t, i); |  | ||||||
|       gnext(n) = NULL; |  | ||||||
|       setnilvalue(gkey(n)); |  | ||||||
|       setnilvalue(gval(n)); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   t->lsizenode = cast_byte(lsize); |  | ||||||
|   t->lastfree = gnode(t, size);  /* all positions are free */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void resize (lua_State *L, Table *t, int nasize, int nhsize) { |  | ||||||
|   int i; |  | ||||||
|   int oldasize = t->sizearray; |  | ||||||
|   int oldhsize = t->lsizenode; |  | ||||||
|   Node *nold = t->node;  /* save old hash ... */ |  | ||||||
|   if (nasize > oldasize)  /* array part must grow? */ |  | ||||||
|     setarrayvector(L, t, nasize); |  | ||||||
|   /* create new hash part with appropriate size */ |  | ||||||
|   setnodevector(L, t, nhsize);   |  | ||||||
|   if (nasize < oldasize) {  /* array part must shrink? */ |  | ||||||
|     t->sizearray = nasize; |  | ||||||
|     /* re-insert elements from vanishing slice */ |  | ||||||
|     for (i=nasize; i<oldasize; i++) { |  | ||||||
|       if (!ttisnil(&t->array[i])) |  | ||||||
|         setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]); |  | ||||||
|     } |  | ||||||
|     /* shrink array */ |  | ||||||
|     luaM_reallocvector(L, t->array, oldasize, nasize, TValue); |  | ||||||
|   } |  | ||||||
|   /* re-insert elements from hash part */ |  | ||||||
|   for (i = twoto(oldhsize) - 1; i >= 0; i--) { |  | ||||||
|     Node *old = nold+i; |  | ||||||
|     if (!ttisnil(gval(old))) |  | ||||||
|       setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); |  | ||||||
|   } |  | ||||||
|   if (nold != dummynode) |  | ||||||
|     luaM_freearray(L, nold, twoto(oldhsize), Node);  /* free old array */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaH_resizearray (lua_State *L, Table *t, int nasize) { |  | ||||||
|   int nsize = (t->node == dummynode) ? 0 : sizenode(t); |  | ||||||
|   resize(L, t, nasize, nsize); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void rehash (lua_State *L, Table *t, const TValue *ek) { |  | ||||||
|   int nasize, na; |  | ||||||
|   int nums[MAXBITS+1];  /* nums[i] = number of keys between 2^(i-1) and 2^i */ |  | ||||||
|   int i; |  | ||||||
|   int totaluse; |  | ||||||
|   for (i=0; i<=MAXBITS; i++) nums[i] = 0;  /* reset counts */ |  | ||||||
|   nasize = numusearray(t, nums);  /* count keys in array part */ |  | ||||||
|   totaluse = nasize;  /* all those keys are integer keys */ |  | ||||||
|   totaluse += numusehash(t, nums, &nasize);  /* count keys in hash part */ |  | ||||||
|   /* count extra key */ |  | ||||||
|   nasize += countint(ek, nums); |  | ||||||
|   totaluse++; |  | ||||||
|   /* compute new size for array part */ |  | ||||||
|   na = computesizes(nums, &nasize); |  | ||||||
|   /* resize the table to new computed sizes */ |  | ||||||
|   resize(L, t, nasize, totaluse - na); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** }============================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| Table *luaH_new (lua_State *L, int narray, int nhash) { |  | ||||||
|   Table *t = luaM_new(L, Table); |  | ||||||
|   luaC_link(L, obj2gco(t), LUA_TTABLE); |  | ||||||
|   t->metatable = NULL; |  | ||||||
|   t->flags = cast_byte(~0); |  | ||||||
|   /* temporary values (kept only if some malloc fails) */ |  | ||||||
|   t->array = NULL; |  | ||||||
|   t->sizearray = 0; |  | ||||||
|   t->lsizenode = 0; |  | ||||||
|   t->node = cast(Node *, dummynode); |  | ||||||
|   setarrayvector(L, t, narray); |  | ||||||
|   setnodevector(L, t, nhash); |  | ||||||
|   return t; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaH_free (lua_State *L, Table *t) { |  | ||||||
|   if (t->node != dummynode) |  | ||||||
|     luaM_freearray(L, t->node, sizenode(t), Node); |  | ||||||
|   luaM_freearray(L, t->array, t->sizearray, TValue); |  | ||||||
|   luaM_free(L, t); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static Node *getfreepos (Table *t) { |  | ||||||
|   while (t->lastfree-- > t->node) { |  | ||||||
|     if (ttisnil(gkey(t->lastfree))) |  | ||||||
|       return t->lastfree; |  | ||||||
|   } |  | ||||||
|   return NULL;  /* could not find a free place */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** inserts a new key into a hash table; first, check whether key's main  |  | ||||||
| ** position is free. If not, check whether colliding node is in its main  |  | ||||||
| ** position or not: if it is not, move colliding node to an empty place and  |  | ||||||
| ** put new key in its main position; otherwise (colliding node is in its main  |  | ||||||
| ** position), new key goes to an empty position.  |  | ||||||
| */ |  | ||||||
| static TValue *newkey (lua_State *L, Table *t, const TValue *key) { |  | ||||||
|   Node *mp = mainposition(t, key); |  | ||||||
|   if (!ttisnil(gval(mp)) || mp == dummynode) { |  | ||||||
|     Node *othern; |  | ||||||
|     Node *n = getfreepos(t);  /* get a free place */ |  | ||||||
|     if (n == NULL) {  /* cannot find a free place? */ |  | ||||||
|       rehash(L, t, key);  /* grow table */ |  | ||||||
|       return luaH_set(L, t, key);  /* re-insert key into grown table */ |  | ||||||
|     } |  | ||||||
|     lua_assert(n != dummynode); |  | ||||||
|     othern = mainposition(t, key2tval(mp)); |  | ||||||
|     if (othern != mp) {  /* is colliding node out of its main position? */ |  | ||||||
|       /* yes; move colliding node into free position */ |  | ||||||
|       while (gnext(othern) != mp) othern = gnext(othern);  /* find previous */ |  | ||||||
|       gnext(othern) = n;  /* redo the chain with `n' in place of `mp' */ |  | ||||||
|       *n = *mp;  /* copy colliding node into free pos. (mp->next also goes) */ |  | ||||||
|       gnext(mp) = NULL;  /* now `mp' is free */ |  | ||||||
|       setnilvalue(gval(mp)); |  | ||||||
|     } |  | ||||||
|     else {  /* colliding node is in its own main position */ |  | ||||||
|       /* new node will go into free position */ |  | ||||||
|       gnext(n) = gnext(mp);  /* chain new position */ |  | ||||||
|       gnext(mp) = n; |  | ||||||
|       mp = n; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; |  | ||||||
|   luaC_barriert(L, t, key); |  | ||||||
|   lua_assert(ttisnil(gval(mp))); |  | ||||||
|   return gval(mp); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** search function for integers |  | ||||||
| */ |  | ||||||
| const TValue *luaH_getnum (Table *t, int key) { |  | ||||||
|   /* (1 <= key && key <= t->sizearray) */ |  | ||||||
|   if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) |  | ||||||
|     return &t->array[key-1]; |  | ||||||
|   else { |  | ||||||
|     lua_Number nk = cast_num(key); |  | ||||||
|     Node *n = hashnum(t, nk); |  | ||||||
|     do {  /* check whether `key' is somewhere in the chain */ |  | ||||||
|       if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) |  | ||||||
|         return gval(n);  /* that's it */ |  | ||||||
|       else n = gnext(n); |  | ||||||
|     } while (n); |  | ||||||
|     return luaO_nilobject; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** search function for strings |  | ||||||
| */ |  | ||||||
| const TValue *luaH_getstr (Table *t, TString *key) { |  | ||||||
|   Node *n = hashstr(t, key); |  | ||||||
|   do {  /* check whether `key' is somewhere in the chain */ |  | ||||||
|     if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) |  | ||||||
|       return gval(n);  /* that's it */ |  | ||||||
|     else n = gnext(n); |  | ||||||
|   } while (n); |  | ||||||
|   return luaO_nilobject; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** main search function |  | ||||||
| */ |  | ||||||
| const TValue *luaH_get (Table *t, const TValue *key) { |  | ||||||
|   switch (ttype(key)) { |  | ||||||
|     case LUA_TNIL: return luaO_nilobject; |  | ||||||
|     case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); |  | ||||||
|     case LUA_TNUMBER: { |  | ||||||
|       int k; |  | ||||||
|       lua_Number n = nvalue(key); |  | ||||||
|       lua_number2int(k, n); |  | ||||||
|       if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ |  | ||||||
|         return luaH_getnum(t, k);  /* use specialized version */ |  | ||||||
|       /* else go through */ |  | ||||||
|     } |  | ||||||
|     default: { |  | ||||||
|       Node *n = mainposition(t, key); |  | ||||||
|       do {  /* check whether `key' is somewhere in the chain */ |  | ||||||
|         if (luaO_rawequalObj(key2tval(n), key)) |  | ||||||
|           return gval(n);  /* that's it */ |  | ||||||
|         else n = gnext(n); |  | ||||||
|       } while (n); |  | ||||||
|       return luaO_nilobject; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { |  | ||||||
|   const TValue *p = luaH_get(t, key); |  | ||||||
|   t->flags = 0; |  | ||||||
|   if (p != luaO_nilobject) |  | ||||||
|     return cast(TValue *, p); |  | ||||||
|   else { |  | ||||||
|     if (ttisnil(key)) luaG_runerror(L, "table index is nil"); |  | ||||||
|     else if (ttisnumber(key) && luai_numisnan(nvalue(key))) |  | ||||||
|       luaG_runerror(L, "table index is NaN"); |  | ||||||
|     return newkey(L, t, key); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| TValue *luaH_setnum (lua_State *L, Table *t, int key) { |  | ||||||
|   const TValue *p = luaH_getnum(t, key); |  | ||||||
|   if (p != luaO_nilobject) |  | ||||||
|     return cast(TValue *, p); |  | ||||||
|   else { |  | ||||||
|     TValue k; |  | ||||||
|     setnvalue(&k, cast_num(key)); |  | ||||||
|     return newkey(L, t, &k); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| TValue *luaH_setstr (lua_State *L, Table *t, TString *key) { |  | ||||||
|   const TValue *p = luaH_getstr(t, key); |  | ||||||
|   if (p != luaO_nilobject) |  | ||||||
|     return cast(TValue *, p); |  | ||||||
|   else { |  | ||||||
|     TValue k; |  | ||||||
|     setsvalue(L, &k, key); |  | ||||||
|     return newkey(L, t, &k); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int unbound_search (Table *t, unsigned int j) { |  | ||||||
|   unsigned int i = j;  /* i is zero or a present index */ |  | ||||||
|   j++; |  | ||||||
|   /* find `i' and `j' such that i is present and j is not */ |  | ||||||
|   while (!ttisnil(luaH_getnum(t, j))) { |  | ||||||
|     i = j; |  | ||||||
|     j *= 2; |  | ||||||
|     if (j > cast(unsigned int, MAX_INT)) {  /* overflow? */ |  | ||||||
|       /* table was built with bad purposes: resort to linear search */ |  | ||||||
|       i = 1; |  | ||||||
|       while (!ttisnil(luaH_getnum(t, i))) i++; |  | ||||||
|       return i - 1; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   /* now do a binary search between them */ |  | ||||||
|   while (j - i > 1) { |  | ||||||
|     unsigned int m = (i+j)/2; |  | ||||||
|     if (ttisnil(luaH_getnum(t, m))) j = m; |  | ||||||
|     else i = m; |  | ||||||
|   } |  | ||||||
|   return i; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Try to find a boundary in table `t'. A `boundary' is an integer index |  | ||||||
| ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). |  | ||||||
| */ |  | ||||||
| int luaH_getn (Table *t) { |  | ||||||
|   unsigned int j = t->sizearray; |  | ||||||
|   if (j > 0 && ttisnil(&t->array[j - 1])) { |  | ||||||
|     /* there is a boundary in the array part: (binary) search for it */ |  | ||||||
|     unsigned int i = 0; |  | ||||||
|     while (j - i > 1) { |  | ||||||
|       unsigned int m = (i+j)/2; |  | ||||||
|       if (ttisnil(&t->array[m - 1])) j = m; |  | ||||||
|       else i = m; |  | ||||||
|     } |  | ||||||
|     return i; |  | ||||||
|   } |  | ||||||
|   /* else must find a boundary in hash part */ |  | ||||||
|   else if (t->node == dummynode)  /* hash part is empty? */ |  | ||||||
|     return j;  /* that is easy... */ |  | ||||||
|   else return unbound_search(t, j); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #if defined(LUA_DEBUG) |  | ||||||
|  |  | ||||||
| Node *luaH_mainposition (const Table *t, const TValue *key) { |  | ||||||
|   return mainposition(t, key); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int luaH_isdummy (Node *n) { return n == dummynode; } |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,40 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: ltable.h,v 2.10 2006/01/10 13:13:06 roberto Exp $ |  | ||||||
| ** Lua tables (hash) |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef ltable_h |  | ||||||
| #define ltable_h |  | ||||||
|  |  | ||||||
| #include "lobject.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define gnode(t,i)	(&(t)->node[i]) |  | ||||||
| #define gkey(n)		(&(n)->i_key.nk) |  | ||||||
| #define gval(n)		(&(n)->i_val) |  | ||||||
| #define gnext(n)	((n)->i_key.nk.next) |  | ||||||
|  |  | ||||||
| #define key2tval(n)	(&(n)->i_key.tvk) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUAI_FUNC const TValue *luaH_getnum (Table *t, int key); |  | ||||||
| LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key); |  | ||||||
| LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); |  | ||||||
| LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key); |  | ||||||
| LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); |  | ||||||
| LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); |  | ||||||
| LUAI_FUNC Table *luaH_new (lua_State *L, int narray, int lnhash); |  | ||||||
| LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize); |  | ||||||
| LUAI_FUNC void luaH_free (lua_State *L, Table *t); |  | ||||||
| LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); |  | ||||||
| LUAI_FUNC int luaH_getn (Table *t); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #if defined(LUA_DEBUG) |  | ||||||
| LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); |  | ||||||
| LUAI_FUNC int luaH_isdummy (Node *n); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,278 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: ltablib.c,v 1.38 2005/10/23 17:38:15 roberto Exp $ |  | ||||||
| ** Library for Table Manipulation |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <stddef.h> |  | ||||||
|  |  | ||||||
| #define ltablib_c |  | ||||||
| #define LUA_LIB |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lauxlib.h" |  | ||||||
| #include "lualib.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define aux_getn(L,n)	(luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int foreachi (lua_State *L) { |  | ||||||
|   int i; |  | ||||||
|   int n = aux_getn(L, 1); |  | ||||||
|   luaL_checktype(L, 2, LUA_TFUNCTION); |  | ||||||
|   for (i=1; i <= n; i++) { |  | ||||||
|     lua_pushvalue(L, 2);  /* function */ |  | ||||||
|     lua_pushinteger(L, i);  /* 1st argument */ |  | ||||||
|     lua_rawgeti(L, 1, i);  /* 2nd argument */ |  | ||||||
|     lua_call(L, 2, 1); |  | ||||||
|     if (!lua_isnil(L, -1)) |  | ||||||
|       return 1; |  | ||||||
|     lua_pop(L, 1);  /* remove nil result */ |  | ||||||
|   } |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int foreach (lua_State *L) { |  | ||||||
|   luaL_checktype(L, 1, LUA_TTABLE); |  | ||||||
|   luaL_checktype(L, 2, LUA_TFUNCTION); |  | ||||||
|   lua_pushnil(L);  /* first key */ |  | ||||||
|   while (lua_next(L, 1)) { |  | ||||||
|     lua_pushvalue(L, 2);  /* function */ |  | ||||||
|     lua_pushvalue(L, -3);  /* key */ |  | ||||||
|     lua_pushvalue(L, -3);  /* value */ |  | ||||||
|     lua_call(L, 2, 1); |  | ||||||
|     if (!lua_isnil(L, -1)) |  | ||||||
|       return 1; |  | ||||||
|     lua_pop(L, 2);  /* remove value and result */ |  | ||||||
|   } |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int maxn (lua_State *L) { |  | ||||||
|   lua_Number max = 0; |  | ||||||
|   luaL_checktype(L, 1, LUA_TTABLE); |  | ||||||
|   lua_pushnil(L);  /* first key */ |  | ||||||
|   while (lua_next(L, 1)) { |  | ||||||
|     lua_pop(L, 1);  /* remove value */ |  | ||||||
|     if (lua_type(L, -1) == LUA_TNUMBER) { |  | ||||||
|       lua_Number v = lua_tonumber(L, -1); |  | ||||||
|       if (v > max) max = v; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   lua_pushnumber(L, max); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int getn (lua_State *L) { |  | ||||||
|   lua_pushinteger(L, aux_getn(L, 1)); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int setn (lua_State *L) { |  | ||||||
|   luaL_checktype(L, 1, LUA_TTABLE); |  | ||||||
| #ifndef luaL_setn |  | ||||||
|   luaL_setn(L, 1, luaL_checkint(L, 2)); |  | ||||||
| #else |  | ||||||
|   luaL_error(L, LUA_QL("setn") " is obsolete"); |  | ||||||
| #endif |  | ||||||
|   lua_pushvalue(L, 1); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int tinsert (lua_State *L) { |  | ||||||
|   int e = aux_getn(L, 1) + 1;  /* first empty element */ |  | ||||||
|   int pos;  /* where to insert new element */ |  | ||||||
|   switch (lua_gettop(L)) { |  | ||||||
|     case 2: {  /* called with only 2 arguments */ |  | ||||||
|       pos = e;  /* insert new element at the end */ |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     case 3: { |  | ||||||
|       int i; |  | ||||||
|       pos = luaL_checkint(L, 2);  /* 2nd argument is the position */ |  | ||||||
|       if (pos > e) e = pos;  /* `grow' array if necessary */ |  | ||||||
|       for (i = e; i > pos; i--) {  /* move up elements */ |  | ||||||
|         lua_rawgeti(L, 1, i-1); |  | ||||||
|         lua_rawseti(L, 1, i);  /* t[i] = t[i-1] */ |  | ||||||
|       } |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|     default: { |  | ||||||
|       return luaL_error(L, "wrong number of arguments to " LUA_QL("insert")); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   luaL_setn(L, 1, e);  /* new size */ |  | ||||||
|   lua_rawseti(L, 1, pos);  /* t[pos] = v */ |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int tremove (lua_State *L) { |  | ||||||
|   int e = aux_getn(L, 1); |  | ||||||
|   int pos = luaL_optint(L, 2, e); |  | ||||||
|   if (e == 0) return 0;  /* table is `empty' */ |  | ||||||
|   luaL_setn(L, 1, e - 1);  /* t.n = n-1 */ |  | ||||||
|   lua_rawgeti(L, 1, pos);  /* result = t[pos] */ |  | ||||||
|   for ( ;pos<e; pos++) { |  | ||||||
|     lua_rawgeti(L, 1, pos+1); |  | ||||||
|     lua_rawseti(L, 1, pos);  /* t[pos] = t[pos+1] */ |  | ||||||
|   } |  | ||||||
|   lua_pushnil(L); |  | ||||||
|   lua_rawseti(L, 1, e);  /* t[e] = nil */ |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int tconcat (lua_State *L) { |  | ||||||
|   luaL_Buffer b; |  | ||||||
|   size_t lsep; |  | ||||||
|   int i, last; |  | ||||||
|   const char *sep = luaL_optlstring(L, 2, "", &lsep); |  | ||||||
|   luaL_checktype(L, 1, LUA_TTABLE); |  | ||||||
|   i = luaL_optint(L, 3, 1); |  | ||||||
|   last = luaL_opt(L, luaL_checkint, 4, luaL_getn(L, 1)); |  | ||||||
|   luaL_buffinit(L, &b); |  | ||||||
|   for (; i <= last; i++) { |  | ||||||
|     lua_rawgeti(L, 1, i); |  | ||||||
|     luaL_argcheck(L, lua_isstring(L, -1), 1, "table contains non-strings"); |  | ||||||
|     luaL_addvalue(&b); |  | ||||||
|     if (i != last) |  | ||||||
|       luaL_addlstring(&b, sep, lsep); |  | ||||||
|   } |  | ||||||
|   luaL_pushresult(&b); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================== |  | ||||||
| ** Quicksort |  | ||||||
| ** (based on `Algorithms in MODULA-3', Robert Sedgewick; |  | ||||||
| **  Addison-Wesley, 1993.) |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void set2 (lua_State *L, int i, int j) { |  | ||||||
|   lua_rawseti(L, 1, i); |  | ||||||
|   lua_rawseti(L, 1, j); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int sort_comp (lua_State *L, int a, int b) { |  | ||||||
|   if (!lua_isnil(L, 2)) {  /* function? */ |  | ||||||
|     int res; |  | ||||||
|     lua_pushvalue(L, 2); |  | ||||||
|     lua_pushvalue(L, a-1);  /* -1 to compensate function */ |  | ||||||
|     lua_pushvalue(L, b-2);  /* -2 to compensate function and `a' */ |  | ||||||
|     lua_call(L, 2, 1); |  | ||||||
|     res = lua_toboolean(L, -1); |  | ||||||
|     lua_pop(L, 1); |  | ||||||
|     return res; |  | ||||||
|   } |  | ||||||
|   else  /* a < b? */ |  | ||||||
|     return lua_lessthan(L, a, b); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void auxsort (lua_State *L, int l, int u) { |  | ||||||
|   while (l < u) {  /* for tail recursion */ |  | ||||||
|     int i, j; |  | ||||||
|     /* sort elements a[l], a[(l+u)/2] and a[u] */ |  | ||||||
|     lua_rawgeti(L, 1, l); |  | ||||||
|     lua_rawgeti(L, 1, u); |  | ||||||
|     if (sort_comp(L, -1, -2))  /* a[u] < a[l]? */ |  | ||||||
|       set2(L, l, u);  /* swap a[l] - a[u] */ |  | ||||||
|     else |  | ||||||
|       lua_pop(L, 2); |  | ||||||
|     if (u-l == 1) break;  /* only 2 elements */ |  | ||||||
|     i = (l+u)/2; |  | ||||||
|     lua_rawgeti(L, 1, i); |  | ||||||
|     lua_rawgeti(L, 1, l); |  | ||||||
|     if (sort_comp(L, -2, -1))  /* a[i]<a[l]? */ |  | ||||||
|       set2(L, i, l); |  | ||||||
|     else { |  | ||||||
|       lua_pop(L, 1);  /* remove a[l] */ |  | ||||||
|       lua_rawgeti(L, 1, u); |  | ||||||
|       if (sort_comp(L, -1, -2))  /* a[u]<a[i]? */ |  | ||||||
|         set2(L, i, u); |  | ||||||
|       else |  | ||||||
|         lua_pop(L, 2); |  | ||||||
|     } |  | ||||||
|     if (u-l == 2) break;  /* only 3 elements */ |  | ||||||
|     lua_rawgeti(L, 1, i);  /* Pivot */ |  | ||||||
|     lua_pushvalue(L, -1); |  | ||||||
|     lua_rawgeti(L, 1, u-1); |  | ||||||
|     set2(L, i, u-1); |  | ||||||
|     /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */ |  | ||||||
|     i = l; j = u-1; |  | ||||||
|     for (;;) {  /* invariant: a[l..i] <= P <= a[j..u] */ |  | ||||||
|       /* repeat ++i until a[i] >= P */ |  | ||||||
|       while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { |  | ||||||
|         if (i>u) luaL_error(L, "invalid order function for sorting"); |  | ||||||
|         lua_pop(L, 1);  /* remove a[i] */ |  | ||||||
|       } |  | ||||||
|       /* repeat --j until a[j] <= P */ |  | ||||||
|       while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { |  | ||||||
|         if (j<l) luaL_error(L, "invalid order function for sorting"); |  | ||||||
|         lua_pop(L, 1);  /* remove a[j] */ |  | ||||||
|       } |  | ||||||
|       if (j<i) { |  | ||||||
|         lua_pop(L, 3);  /* pop pivot, a[i], a[j] */ |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       set2(L, i, j); |  | ||||||
|     } |  | ||||||
|     lua_rawgeti(L, 1, u-1); |  | ||||||
|     lua_rawgeti(L, 1, i); |  | ||||||
|     set2(L, u-1, i);  /* swap pivot (a[u-1]) with a[i] */ |  | ||||||
|     /* a[l..i-1] <= a[i] == P <= a[i+1..u] */ |  | ||||||
|     /* adjust so that smaller half is in [j..i] and larger one in [l..u] */ |  | ||||||
|     if (i-l < u-i) { |  | ||||||
|       j=l; i=i-1; l=i+2; |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|       j=i+1; i=u; u=j-2; |  | ||||||
|     } |  | ||||||
|     auxsort(L, j, i);  /* call recursively the smaller one */ |  | ||||||
|   }  /* repeat the routine for the larger one */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int sort (lua_State *L) { |  | ||||||
|   int n = aux_getn(L, 1); |  | ||||||
|   luaL_checkstack(L, 40, "");  /* assume array is smaller than 2^40 */ |  | ||||||
|   if (!lua_isnoneornil(L, 2))  /* is there a 2nd argument? */ |  | ||||||
|     luaL_checktype(L, 2, LUA_TFUNCTION); |  | ||||||
|   lua_settop(L, 2);  /* make sure there is two arguments */ |  | ||||||
|   auxsort(L, 1, n); |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* }====================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const luaL_Reg tab_funcs[] = { |  | ||||||
|   {"concat", tconcat}, |  | ||||||
|   {"foreach", foreach}, |  | ||||||
|   {"foreachi", foreachi}, |  | ||||||
|   {"getn", getn}, |  | ||||||
|   {"maxn", maxn}, |  | ||||||
|   {"insert", tinsert}, |  | ||||||
|   {"remove", tremove}, |  | ||||||
|   {"setn", setn}, |  | ||||||
|   {"sort", sort}, |  | ||||||
|   {NULL, NULL} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUALIB_API int luaopen_table (lua_State *L) { |  | ||||||
|   luaL_register(L, LUA_TABLIBNAME, tab_funcs); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,75 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: ltm.c,v 2.8 2006/01/10 12:50:00 roberto Exp $ |  | ||||||
| ** Tag methods |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define ltm_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lstate.h" |  | ||||||
| #include "lstring.h" |  | ||||||
| #include "ltable.h" |  | ||||||
| #include "ltm.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| const char *const luaT_typenames[] = { |  | ||||||
|   "nil", "boolean", "userdata", "number", |  | ||||||
|   "string", "table", "function", "userdata", "thread", |  | ||||||
|   "proto", "upval" |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaT_init (lua_State *L) { |  | ||||||
|   static const char *const luaT_eventname[] = {  /* ORDER TM */ |  | ||||||
|     "__index", "__newindex", |  | ||||||
|     "__gc", "__mode", "__eq", |  | ||||||
|     "__add", "__sub", "__mul", "__div", "__mod", |  | ||||||
|     "__pow", "__unm", "__len", "__lt", "__le", |  | ||||||
|     "__concat", "__call" |  | ||||||
|   }; |  | ||||||
|   int i; |  | ||||||
|   for (i=0; i<TM_N; i++) { |  | ||||||
|     G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]); |  | ||||||
|     luaS_fix(G(L)->tmname[i]);  /* never collect these names */ |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** function to be used with macro "fasttm": optimized for absence of |  | ||||||
| ** tag methods |  | ||||||
| */ |  | ||||||
| const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { |  | ||||||
|   const TValue *tm = luaH_getstr(events, ename); |  | ||||||
|   lua_assert(event <= TM_EQ); |  | ||||||
|   if (ttisnil(tm)) {  /* no tag method? */ |  | ||||||
|     events->flags |= cast_byte(1u<<event);  /* cache this fact */ |  | ||||||
|     return NULL; |  | ||||||
|   } |  | ||||||
|   else return tm; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { |  | ||||||
|   Table *mt; |  | ||||||
|   switch (ttype(o)) { |  | ||||||
|     case LUA_TTABLE: |  | ||||||
|       mt = hvalue(o)->metatable; |  | ||||||
|       break; |  | ||||||
|     case LUA_TUSERDATA: |  | ||||||
|       mt = uvalue(o)->metatable; |  | ||||||
|       break; |  | ||||||
|     default: |  | ||||||
|       mt = G(L)->mt[ttype(o)]; |  | ||||||
|   } |  | ||||||
|   return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,54 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: ltm.h,v 2.6 2005/06/06 13:30:25 roberto Exp $ |  | ||||||
| ** Tag methods |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef ltm_h |  | ||||||
| #define ltm_h |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "lobject.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| * WARNING: if you change the order of this enumeration, |  | ||||||
| * grep "ORDER TM" |  | ||||||
| */ |  | ||||||
| typedef enum { |  | ||||||
|   TM_INDEX, |  | ||||||
|   TM_NEWINDEX, |  | ||||||
|   TM_GC, |  | ||||||
|   TM_MODE, |  | ||||||
|   TM_EQ,  /* last tag method with `fast' access */ |  | ||||||
|   TM_ADD, |  | ||||||
|   TM_SUB, |  | ||||||
|   TM_MUL, |  | ||||||
|   TM_DIV, |  | ||||||
|   TM_MOD, |  | ||||||
|   TM_POW, |  | ||||||
|   TM_UNM, |  | ||||||
|   TM_LEN, |  | ||||||
|   TM_LT, |  | ||||||
|   TM_LE, |  | ||||||
|   TM_CONCAT, |  | ||||||
|   TM_CALL, |  | ||||||
|   TM_N		/* number of elements in the enum */ |  | ||||||
| } TMS; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define gfasttm(g,et,e) ((et) == NULL ? NULL : \ |  | ||||||
|   ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) |  | ||||||
|  |  | ||||||
| #define fasttm(l,et,e)	gfasttm(G(l), et, e) |  | ||||||
|  |  | ||||||
| LUAI_DATA const char *const luaT_typenames[]; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); |  | ||||||
| LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, |  | ||||||
|                                                        TMS event); |  | ||||||
| LUAI_FUNC void luaT_init (lua_State *L); |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
							
								
								
									
										377
									
								
								src/lua/lua.c
									
									
									
									
									
								
							
							
						
						
									
										377
									
								
								src/lua/lua.c
									
									
									
									
									
								
							| @@ -1,377 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lua.c,v 1.157 2005/12/29 16:23:32 roberto Exp $ |  | ||||||
| ** Lua stand-alone interpreter |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <signal.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define lua_c |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lauxlib.h" |  | ||||||
| #include "lualib.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static lua_State *globalL = NULL; |  | ||||||
|  |  | ||||||
| static const char *progname = LUA_PROGNAME; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void lstop (lua_State *L, lua_Debug *ar) { |  | ||||||
|   (void)ar;  /* unused arg. */ |  | ||||||
|   lua_sethook(L, NULL, 0, 0); |  | ||||||
|   luaL_error(L, "interrupted!"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void laction (int i) { |  | ||||||
|   signal(i, SIG_DFL); /* if another SIGINT happens before lstop, |  | ||||||
|                               terminate process (default action) */ |  | ||||||
|   lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void print_usage (void) { |  | ||||||
|   fprintf(stderr, |  | ||||||
|   "usage: %s [options] [script [args]].\n" |  | ||||||
|   "Available options are:\n" |  | ||||||
|   "  -e stat  execute string " LUA_QL("stat") "\n" |  | ||||||
|   "  -l name  require library " LUA_QL("name") "\n" |  | ||||||
|   "  -i       enter interactive mode after executing " LUA_QL("script") "\n" |  | ||||||
|   "  -v       show version information\n" |  | ||||||
|   "  --       stop handling options\n" |  | ||||||
|   "  -        execute stdin and stop handling options\n" |  | ||||||
|   , |  | ||||||
|   progname); |  | ||||||
|   fflush(stderr); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void l_message (const char *pname, const char *msg) { |  | ||||||
|   if (pname) fprintf(stderr, "%s: ", pname); |  | ||||||
|   fprintf(stderr, "%s\n", msg); |  | ||||||
|   fflush(stderr); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int report (lua_State *L, int status) { |  | ||||||
|   if (status && !lua_isnil(L, -1)) { |  | ||||||
|     const char *msg = lua_tostring(L, -1); |  | ||||||
|     if (msg == NULL) msg = "(error object is not a string)"; |  | ||||||
|     l_message(progname, msg); |  | ||||||
|     lua_pop(L, 1); |  | ||||||
|   } |  | ||||||
|   return status; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int traceback (lua_State *L) { |  | ||||||
|   lua_getfield(L, LUA_GLOBALSINDEX, "debug"); |  | ||||||
|   if (!lua_istable(L, -1)) { |  | ||||||
|     lua_pop(L, 1); |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
|   lua_getfield(L, -1, "traceback"); |  | ||||||
|   if (!lua_isfunction(L, -1)) { |  | ||||||
|     lua_pop(L, 2); |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
|   lua_pushvalue(L, 1);  /* pass error message */ |  | ||||||
|   lua_pushinteger(L, 2);  /* skip this function and traceback */ |  | ||||||
|   lua_call(L, 2, 1);  /* call debug.traceback */ |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int docall (lua_State *L, int narg, int clear) { |  | ||||||
|   int status; |  | ||||||
|   int base = lua_gettop(L) - narg;  /* function index */ |  | ||||||
|   lua_pushcfunction(L, traceback);  /* push traceback function */ |  | ||||||
|   lua_insert(L, base);  /* put it under chunk and args */ |  | ||||||
|   signal(SIGINT, laction); |  | ||||||
|   status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); |  | ||||||
|   signal(SIGINT, SIG_DFL); |  | ||||||
|   lua_remove(L, base);  /* remove traceback function */ |  | ||||||
|   /* force a complete garbage collection in case of errors */ |  | ||||||
|   if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); |  | ||||||
|   return status; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void print_version (void) { |  | ||||||
|   l_message(NULL, LUA_VERSION "  " LUA_COPYRIGHT); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int getargs (lua_State *L, char **argv, int n) { |  | ||||||
|   int narg; |  | ||||||
|   int i; |  | ||||||
|   int argc = 0; |  | ||||||
|   while (argv[argc]) argc++;  /* count total number of arguments */ |  | ||||||
|   narg = argc - (n + 1);  /* number of arguments to the script */ |  | ||||||
|   luaL_checkstack(L, narg + 3, "too many arguments to script"); |  | ||||||
|   for (i=n+1; i < argc; i++) |  | ||||||
|     lua_pushstring(L, argv[i]); |  | ||||||
|   lua_createtable(L, narg, n + 1); |  | ||||||
|   for (i=0; i < argc; i++) { |  | ||||||
|     lua_pushstring(L, argv[i]); |  | ||||||
|     lua_rawseti(L, -2, i - n); |  | ||||||
|   } |  | ||||||
|   return narg; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int dofile (lua_State *L, const char *name) { |  | ||||||
|   int status = luaL_loadfile(L, name) || docall(L, 0, 1); |  | ||||||
|   return report(L, status); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int dostring (lua_State *L, const char *s, const char *name) { |  | ||||||
|   int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1); |  | ||||||
|   return report(L, status); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int dolibrary (lua_State *L, const char *name) { |  | ||||||
|   lua_getglobal(L, "require"); |  | ||||||
|   lua_pushstring(L, name); |  | ||||||
|   return report(L, lua_pcall(L, 1, 0, 0)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const char *get_prompt (lua_State *L, int firstline) { |  | ||||||
|   const char *p; |  | ||||||
|   lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); |  | ||||||
|   p = lua_tostring(L, -1); |  | ||||||
|   if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); |  | ||||||
|   lua_pop(L, 1);  /* remove global */ |  | ||||||
|   return p; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int incomplete (lua_State *L, int status) { |  | ||||||
|   if (status == LUA_ERRSYNTAX) { |  | ||||||
|     size_t lmsg; |  | ||||||
|     const char *msg = lua_tolstring(L, -1, &lmsg); |  | ||||||
|     const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1); |  | ||||||
|     if (strstr(msg, LUA_QL("<eof>")) == tp) { |  | ||||||
|       lua_pop(L, 1); |  | ||||||
|       return 1; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return 0;  /* else... */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int pushline (lua_State *L, int firstline) { |  | ||||||
|   char buffer[LUA_MAXINPUT]; |  | ||||||
|   char *b = buffer; |  | ||||||
|   size_t l; |  | ||||||
|   const char *prmt = get_prompt(L, firstline); |  | ||||||
|   if (lua_readline(L, b, prmt) == 0) |  | ||||||
|     return 0;  /* no input */ |  | ||||||
|   l = strlen(b); |  | ||||||
|   if (l > 0 && b[l-1] == '\n')  /* line ends with newline? */ |  | ||||||
|     b[l-1] = '\0';  /* remove it */ |  | ||||||
|   if (firstline && b[0] == '=')  /* first line starts with `=' ? */ |  | ||||||
|     lua_pushfstring(L, "return %s", b+1);  /* change it to `return' */ |  | ||||||
|   else |  | ||||||
|     lua_pushstring(L, b); |  | ||||||
|   lua_freeline(L, b); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int loadline (lua_State *L) { |  | ||||||
|   int status; |  | ||||||
|   lua_settop(L, 0); |  | ||||||
|   if (!pushline(L, 1)) |  | ||||||
|     return -1;  /* no input */ |  | ||||||
|   for (;;) {  /* repeat until gets a complete line */ |  | ||||||
|     status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); |  | ||||||
|     if (!incomplete(L, status)) break;  /* cannot try to add lines? */ |  | ||||||
|     if (!pushline(L, 0))  /* no more input? */ |  | ||||||
|       return -1; |  | ||||||
|     lua_pushliteral(L, "\n");  /* add a new line... */ |  | ||||||
|     lua_insert(L, -2);  /* ...between the two lines */ |  | ||||||
|     lua_concat(L, 3);  /* join them */ |  | ||||||
|   } |  | ||||||
|   lua_saveline(L, 1); |  | ||||||
|   lua_remove(L, 1);  /* remove line */ |  | ||||||
|   return status; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void dotty (lua_State *L) { |  | ||||||
|   int status; |  | ||||||
|   const char *oldprogname = progname; |  | ||||||
|   progname = NULL; |  | ||||||
|   while ((status = loadline(L)) != -1) { |  | ||||||
|     if (status == 0) status = docall(L, 0, 0); |  | ||||||
|     report(L, status); |  | ||||||
|     if (status == 0 && lua_gettop(L) > 0) {  /* any result to print? */ |  | ||||||
|       lua_getglobal(L, "print"); |  | ||||||
|       lua_insert(L, 1); |  | ||||||
|       if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) |  | ||||||
|         l_message(progname, lua_pushfstring(L, |  | ||||||
|                                "error calling " LUA_QL("print") " (%s)", |  | ||||||
|                                lua_tostring(L, -1))); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   lua_settop(L, 0);  /* clear stack */ |  | ||||||
|   fputs("\n", stdout); |  | ||||||
|   fflush(stdout); |  | ||||||
|   progname = oldprogname; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int handle_script (lua_State *L, char **argv, int n) { |  | ||||||
|   int status; |  | ||||||
|   const char *fname; |  | ||||||
|   int narg = getargs(L, argv, n);  /* collect arguments */ |  | ||||||
|   lua_setglobal(L, "arg"); |  | ||||||
|   fname = argv[n]; |  | ||||||
|   if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)  |  | ||||||
|     fname = NULL;  /* stdin */ |  | ||||||
|   status = luaL_loadfile(L, fname); |  | ||||||
|   lua_insert(L, -(narg+1)); |  | ||||||
|   if (status == 0) |  | ||||||
|     status = docall(L, narg, 0); |  | ||||||
|   else |  | ||||||
|     lua_pop(L, narg);       |  | ||||||
|   return report(L, status); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int collectargs (char **argv, int *pi, int *pv, int *pe) { |  | ||||||
|   int i; |  | ||||||
|   for (i = 1; argv[i] != NULL; i++) { |  | ||||||
|     if (argv[i][0] != '-')  /* not an option? */ |  | ||||||
|         return i; |  | ||||||
|     switch (argv[i][1]) {  /* option */ |  | ||||||
|       case '-': return (argv[i+1] != NULL ? i+1 : 0); |  | ||||||
|       case '\0': return i; |  | ||||||
|       case 'i': *pi = 1;  /* go through */ |  | ||||||
|       case 'v': *pv = 1; break; |  | ||||||
|       case 'e': *pe = 1;  /* go through */ |  | ||||||
|       case 'l': |  | ||||||
|         if (argv[i][2] == '\0') { |  | ||||||
|           i++; |  | ||||||
|           if (argv[i] == NULL) return -1; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|       default: return -1;  /* invalid option */ |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int runargs (lua_State *L, char **argv, int n) { |  | ||||||
|   int i; |  | ||||||
|   for (i = 1; i < n; i++) { |  | ||||||
|     if (argv[i] == NULL) continue; |  | ||||||
|     lua_assert(argv[i][0] == '-'); |  | ||||||
|     switch (argv[i][1]) {  /* option */ |  | ||||||
|       case 'e': { |  | ||||||
|         const char *chunk = argv[i] + 2; |  | ||||||
|         if (*chunk == '\0') chunk = argv[++i]; |  | ||||||
|         lua_assert(chunk != NULL); |  | ||||||
|         if (dostring(L, chunk, "=(command line)") != 0) |  | ||||||
|           return 1; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       case 'l': { |  | ||||||
|         const char *filename = argv[i] + 2; |  | ||||||
|         if (*filename == '\0') filename = argv[++i]; |  | ||||||
|         lua_assert(filename != NULL); |  | ||||||
|         if (dolibrary(L, filename)) |  | ||||||
|           return 1;  /* stop if file fails */ |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       default: break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int handle_luainit (lua_State *L) { |  | ||||||
|   const char *init = getenv("LUA_INIT"); |  | ||||||
|   if (init == NULL) return 0;  /* status OK */ |  | ||||||
|   else if (init[0] == '@') |  | ||||||
|     return dofile(L, init+1); |  | ||||||
|   else |  | ||||||
|     return dostring(L, init, "=LUA_INIT"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| struct Smain { |  | ||||||
|   int argc; |  | ||||||
|   char **argv; |  | ||||||
|   int status; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int pmain (lua_State *L) { |  | ||||||
|   struct Smain *s = (struct Smain *)lua_touserdata(L, 1); |  | ||||||
|   char **argv = s->argv; |  | ||||||
|   int script; |  | ||||||
|   int has_i = 0, has_v = 0, has_e = 0; |  | ||||||
|   globalL = L; |  | ||||||
|   if (argv[0] && argv[0][0]) progname = argv[0]; |  | ||||||
|   lua_gc(L, LUA_GCSTOP, 0);  /* stop collector during initialization */ |  | ||||||
|   luaL_openlibs(L);  /* open libraries */ |  | ||||||
|   lua_gc(L, LUA_GCRESTART, 0); |  | ||||||
|   s->status = handle_luainit(L); |  | ||||||
|   if (s->status != 0) return 0; |  | ||||||
|   script = collectargs(argv, &has_i, &has_v, &has_e); |  | ||||||
|   if (script < 0) {  /* invalid args? */ |  | ||||||
|     print_usage(); |  | ||||||
|     s->status = 1; |  | ||||||
|     return 0; |  | ||||||
|   } |  | ||||||
|   if (has_v) print_version(); |  | ||||||
|   s->status = runargs(L, argv, (script > 0) ? script : s->argc); |  | ||||||
|   if (s->status != 0) return 0; |  | ||||||
|   if (script) |  | ||||||
|     s->status = handle_script(L, argv, script); |  | ||||||
|   if (s->status != 0) return 0; |  | ||||||
|   if (has_i) |  | ||||||
|     dotty(L); |  | ||||||
|   else if (script == 0 && !has_e && !has_v) { |  | ||||||
|     if (lua_stdin_is_tty()) { |  | ||||||
|       print_version(); |  | ||||||
|       dotty(L); |  | ||||||
|     } |  | ||||||
|     else dofile(L, NULL);  /* executes stdin as a file */ |  | ||||||
|   } |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int main (int argc, char **argv) { |  | ||||||
|   int status; |  | ||||||
|   struct Smain s; |  | ||||||
|   lua_State *L = lua_open();  /* create state */ |  | ||||||
|   if (L == NULL) { |  | ||||||
|     l_message(argv[0], "cannot create state: not enough memory"); |  | ||||||
|     return EXIT_FAILURE; |  | ||||||
|   } |  | ||||||
|   s.argc = argc; |  | ||||||
|   s.argv = argv; |  | ||||||
|   status = lua_cpcall(L, &pmain, &s); |  | ||||||
|   report(L, status); |  | ||||||
|   lua_close(L); |  | ||||||
|   return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										384
									
								
								src/lua/lua.h
									
									
									
									
									
								
							
							
						
						
									
										384
									
								
								src/lua/lua.h
									
									
									
									
									
								
							| @@ -1,384 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lua.h,v 1.216 2006/01/10 12:50:13 roberto Exp $ |  | ||||||
| ** Lua - An Extensible Extension Language |  | ||||||
| ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) |  | ||||||
| ** See Copyright Notice at the end of this file |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifndef lua_h |  | ||||||
| #define lua_h |  | ||||||
|  |  | ||||||
| #include <stdarg.h> |  | ||||||
| #include <stddef.h> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "luaconf.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define LUA_VERSION	"Lua 5.1" |  | ||||||
| #define LUA_VERSION_NUM	501 |  | ||||||
| #define LUA_COPYRIGHT	"Copyright (C) 1994-2006 Lua.org, PUC-Rio" |  | ||||||
| #define LUA_AUTHORS 	"R. Ierusalimschy, L. H. de Figueiredo & W. Celes" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* mark for precompiled code (`<esc>Lua') */ |  | ||||||
| #define	LUA_SIGNATURE	"\033Lua" |  | ||||||
|  |  | ||||||
| /* option for multiple returns in `lua_pcall' and `lua_call' */ |  | ||||||
| #define LUA_MULTRET	(-1) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** pseudo-indices |  | ||||||
| */ |  | ||||||
| #define LUA_REGISTRYINDEX	(-10000) |  | ||||||
| #define LUA_ENVIRONINDEX	(-10001) |  | ||||||
| #define LUA_GLOBALSINDEX	(-10002) |  | ||||||
| #define lua_upvalueindex(i)	(LUA_GLOBALSINDEX-(i)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* thread status; 0 is OK */ |  | ||||||
| #define LUA_YIELD	1 |  | ||||||
| #define LUA_ERRRUN	2 |  | ||||||
| #define LUA_ERRSYNTAX	3 |  | ||||||
| #define LUA_ERRMEM	4 |  | ||||||
| #define LUA_ERRERR	5 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef struct lua_State lua_State; |  | ||||||
|  |  | ||||||
| typedef int (*lua_CFunction) (lua_State *L); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** functions that read/write blocks when loading/dumping Lua chunks |  | ||||||
| */ |  | ||||||
| typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); |  | ||||||
|  |  | ||||||
| typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** prototype for memory-allocation functions |  | ||||||
| */ |  | ||||||
| typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** basic types |  | ||||||
| */ |  | ||||||
| #define LUA_TNONE		(-1) |  | ||||||
|  |  | ||||||
| #define LUA_TNIL		0 |  | ||||||
| #define LUA_TBOOLEAN		1 |  | ||||||
| #define LUA_TLIGHTUSERDATA	2 |  | ||||||
| #define LUA_TNUMBER		3 |  | ||||||
| #define LUA_TSTRING		4 |  | ||||||
| #define LUA_TTABLE		5 |  | ||||||
| #define LUA_TFUNCTION		6 |  | ||||||
| #define LUA_TUSERDATA		7 |  | ||||||
| #define LUA_TTHREAD		8 |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* minimum Lua stack available to a C function */ |  | ||||||
| #define LUA_MINSTACK	20 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** generic extra include file |  | ||||||
| */ |  | ||||||
| #if defined(LUA_USER_H) |  | ||||||
| #include LUA_USER_H |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* type of numbers in Lua */ |  | ||||||
| typedef LUA_NUMBER lua_Number; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* type for integer functions */ |  | ||||||
| typedef LUA_INTEGER lua_Integer; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** state manipulation |  | ||||||
| */ |  | ||||||
| LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); |  | ||||||
| LUA_API void       (lua_close) (lua_State *L); |  | ||||||
| LUA_API lua_State *(lua_newthread) (lua_State *L); |  | ||||||
|  |  | ||||||
| LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** basic stack manipulation |  | ||||||
| */ |  | ||||||
| LUA_API int   (lua_gettop) (lua_State *L); |  | ||||||
| LUA_API void  (lua_settop) (lua_State *L, int idx); |  | ||||||
| LUA_API void  (lua_pushvalue) (lua_State *L, int idx); |  | ||||||
| LUA_API void  (lua_remove) (lua_State *L, int idx); |  | ||||||
| LUA_API void  (lua_insert) (lua_State *L, int idx); |  | ||||||
| LUA_API void  (lua_replace) (lua_State *L, int idx); |  | ||||||
| LUA_API int   (lua_checkstack) (lua_State *L, int sz); |  | ||||||
|  |  | ||||||
| LUA_API void  (lua_xmove) (lua_State *from, lua_State *to, int n); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** access functions (stack -> C) |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| LUA_API int             (lua_isnumber) (lua_State *L, int idx); |  | ||||||
| LUA_API int             (lua_isstring) (lua_State *L, int idx); |  | ||||||
| LUA_API int             (lua_iscfunction) (lua_State *L, int idx); |  | ||||||
| LUA_API int             (lua_isuserdata) (lua_State *L, int idx); |  | ||||||
| LUA_API int             (lua_type) (lua_State *L, int idx); |  | ||||||
| LUA_API const char     *(lua_typename) (lua_State *L, int tp); |  | ||||||
|  |  | ||||||
| LUA_API int            (lua_equal) (lua_State *L, int idx1, int idx2); |  | ||||||
| LUA_API int            (lua_rawequal) (lua_State *L, int idx1, int idx2); |  | ||||||
| LUA_API int            (lua_lessthan) (lua_State *L, int idx1, int idx2); |  | ||||||
|  |  | ||||||
| LUA_API lua_Number      (lua_tonumber) (lua_State *L, int idx); |  | ||||||
| LUA_API lua_Integer     (lua_tointeger) (lua_State *L, int idx); |  | ||||||
| LUA_API int             (lua_toboolean) (lua_State *L, int idx); |  | ||||||
| LUA_API const char     *(lua_tolstring) (lua_State *L, int idx, size_t *len); |  | ||||||
| LUA_API size_t          (lua_objlen) (lua_State *L, int idx); |  | ||||||
| LUA_API lua_CFunction   (lua_tocfunction) (lua_State *L, int idx); |  | ||||||
| LUA_API void	       *(lua_touserdata) (lua_State *L, int idx); |  | ||||||
| LUA_API lua_State      *(lua_tothread) (lua_State *L, int idx); |  | ||||||
| LUA_API const void     *(lua_topointer) (lua_State *L, int idx); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** push functions (C -> stack) |  | ||||||
| */ |  | ||||||
| LUA_API void  (lua_pushnil) (lua_State *L); |  | ||||||
| LUA_API void  (lua_pushnumber) (lua_State *L, lua_Number n); |  | ||||||
| LUA_API void  (lua_pushinteger) (lua_State *L, lua_Integer n); |  | ||||||
| LUA_API void  (lua_pushlstring) (lua_State *L, const char *s, size_t l); |  | ||||||
| LUA_API void  (lua_pushstring) (lua_State *L, const char *s); |  | ||||||
| LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, |  | ||||||
|                                                       va_list argp); |  | ||||||
| LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); |  | ||||||
| LUA_API void  (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); |  | ||||||
| LUA_API void  (lua_pushboolean) (lua_State *L, int b); |  | ||||||
| LUA_API void  (lua_pushlightuserdata) (lua_State *L, void *p); |  | ||||||
| LUA_API int   (lua_pushthread) (lua_State *L); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** get functions (Lua -> stack) |  | ||||||
| */ |  | ||||||
| LUA_API void  (lua_gettable) (lua_State *L, int idx); |  | ||||||
| LUA_API void  (lua_getfield) (lua_State *L, int idx, const char *k); |  | ||||||
| LUA_API void  (lua_rawget) (lua_State *L, int idx); |  | ||||||
| LUA_API void  (lua_rawgeti) (lua_State *L, int idx, int n); |  | ||||||
| LUA_API void  (lua_createtable) (lua_State *L, int narr, int nrec); |  | ||||||
| LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); |  | ||||||
| LUA_API int   (lua_getmetatable) (lua_State *L, int objindex); |  | ||||||
| LUA_API void  (lua_getfenv) (lua_State *L, int idx); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** set functions (stack -> Lua) |  | ||||||
| */ |  | ||||||
| LUA_API void  (lua_settable) (lua_State *L, int idx); |  | ||||||
| LUA_API void  (lua_setfield) (lua_State *L, int idx, const char *k); |  | ||||||
| LUA_API void  (lua_rawset) (lua_State *L, int idx); |  | ||||||
| LUA_API void  (lua_rawseti) (lua_State *L, int idx, int n); |  | ||||||
| LUA_API int   (lua_setmetatable) (lua_State *L, int objindex); |  | ||||||
| LUA_API int   (lua_setfenv) (lua_State *L, int idx); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** `load' and `call' functions (load and run Lua code) |  | ||||||
| */ |  | ||||||
| LUA_API void  (lua_call) (lua_State *L, int nargs, int nresults); |  | ||||||
| LUA_API int   (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); |  | ||||||
| LUA_API int   (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); |  | ||||||
| LUA_API int   (lua_load) (lua_State *L, lua_Reader reader, void *dt, |  | ||||||
|                                         const char *chunkname); |  | ||||||
|  |  | ||||||
| LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** coroutine functions |  | ||||||
| */ |  | ||||||
| LUA_API int  (lua_yield) (lua_State *L, int nresults); |  | ||||||
| LUA_API int  (lua_resume) (lua_State *L, int narg); |  | ||||||
| LUA_API int  (lua_status) (lua_State *L); |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** garbage-collection function and options |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #define LUA_GCSTOP		0 |  | ||||||
| #define LUA_GCRESTART		1 |  | ||||||
| #define LUA_GCCOLLECT		2 |  | ||||||
| #define LUA_GCCOUNT		3 |  | ||||||
| #define LUA_GCCOUNTB		4 |  | ||||||
| #define LUA_GCSTEP		5 |  | ||||||
| #define LUA_GCSETPAUSE		6 |  | ||||||
| #define LUA_GCSETSTEPMUL	7 |  | ||||||
|  |  | ||||||
| LUA_API int (lua_gc) (lua_State *L, int what, int data); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** miscellaneous functions |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| LUA_API int   (lua_error) (lua_State *L); |  | ||||||
|  |  | ||||||
| LUA_API int   (lua_next) (lua_State *L, int idx); |  | ||||||
|  |  | ||||||
| LUA_API void  (lua_concat) (lua_State *L, int n); |  | ||||||
|  |  | ||||||
| LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); |  | ||||||
| LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /*  |  | ||||||
| ** =============================================================== |  | ||||||
| ** some useful macros |  | ||||||
| ** =============================================================== |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #define lua_pop(L,n)		lua_settop(L, -(n)-1) |  | ||||||
|  |  | ||||||
| #define lua_newtable(L)		lua_createtable(L, 0, 0) |  | ||||||
|  |  | ||||||
| #define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) |  | ||||||
|  |  | ||||||
| #define lua_pushcfunction(L,f)	lua_pushcclosure(L, (f), 0) |  | ||||||
|  |  | ||||||
| #define lua_strlen(L,i)		lua_objlen(L, (i)) |  | ||||||
|  |  | ||||||
| #define lua_isfunction(L,n)	(lua_type(L, (n)) == LUA_TFUNCTION) |  | ||||||
| #define lua_istable(L,n)	(lua_type(L, (n)) == LUA_TTABLE) |  | ||||||
| #define lua_islightuserdata(L,n)	(lua_type(L, (n)) == LUA_TLIGHTUSERDATA) |  | ||||||
| #define lua_isnil(L,n)		(lua_type(L, (n)) == LUA_TNIL) |  | ||||||
| #define lua_isboolean(L,n)	(lua_type(L, (n)) == LUA_TBOOLEAN) |  | ||||||
| #define lua_isthread(L,n)	(lua_type(L, (n)) == LUA_TTHREAD) |  | ||||||
| #define lua_isnone(L,n)		(lua_type(L, (n)) == LUA_TNONE) |  | ||||||
| #define lua_isnoneornil(L, n)	(lua_type(L, (n)) <= 0) |  | ||||||
|  |  | ||||||
| #define lua_pushliteral(L, s)	\ |  | ||||||
| 	lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) |  | ||||||
|  |  | ||||||
| #define lua_setglobal(L,s)	lua_setfield(L, LUA_GLOBALSINDEX, (s)) |  | ||||||
| #define lua_getglobal(L,s)	lua_getfield(L, LUA_GLOBALSINDEX, (s)) |  | ||||||
|  |  | ||||||
| #define lua_tostring(L,i)	lua_tolstring(L, (i), NULL) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** compatibility macros and functions |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #define lua_open()	luaL_newstate() |  | ||||||
|  |  | ||||||
| #define lua_getregistry(L)	lua_pushvalue(L, LUA_REGISTRYINDEX) |  | ||||||
|  |  | ||||||
| #define lua_getgccount(L)	lua_gc(L, LUA_GCCOUNT, 0) |  | ||||||
|  |  | ||||||
| #define lua_Chunkreader		lua_Reader |  | ||||||
| #define lua_Chunkwriter		lua_Writer |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {====================================================================== |  | ||||||
| ** Debug API |  | ||||||
| ** ======================================================================= |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Event codes |  | ||||||
| */ |  | ||||||
| #define LUA_HOOKCALL	0 |  | ||||||
| #define LUA_HOOKRET	1 |  | ||||||
| #define LUA_HOOKLINE	2 |  | ||||||
| #define LUA_HOOKCOUNT	3 |  | ||||||
| #define LUA_HOOKTAILRET 4 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Event masks |  | ||||||
| */ |  | ||||||
| #define LUA_MASKCALL	(1 << LUA_HOOKCALL) |  | ||||||
| #define LUA_MASKRET	(1 << LUA_HOOKRET) |  | ||||||
| #define LUA_MASKLINE	(1 << LUA_HOOKLINE) |  | ||||||
| #define LUA_MASKCOUNT	(1 << LUA_HOOKCOUNT) |  | ||||||
|  |  | ||||||
| typedef struct lua_Debug lua_Debug;  /* activation record */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Functions to be called by the debuger in specific events */ |  | ||||||
| typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar); |  | ||||||
| LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); |  | ||||||
| LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n); |  | ||||||
| LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n); |  | ||||||
| LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n); |  | ||||||
| LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n); |  | ||||||
|  |  | ||||||
| LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count); |  | ||||||
| LUA_API lua_Hook lua_gethook (lua_State *L); |  | ||||||
| LUA_API int lua_gethookmask (lua_State *L); |  | ||||||
| LUA_API int lua_gethookcount (lua_State *L); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| struct lua_Debug { |  | ||||||
|   int event; |  | ||||||
|   const char *name;	/* (n) */ |  | ||||||
|   const char *namewhat;	/* (n) `global', `local', `field', `method' */ |  | ||||||
|   const char *what;	/* (S) `Lua', `C', `main', `tail' */ |  | ||||||
|   const char *source;	/* (S) */ |  | ||||||
|   int currentline;	/* (l) */ |  | ||||||
|   int nups;		/* (u) number of upvalues */ |  | ||||||
|   int linedefined;	/* (S) */ |  | ||||||
|   int lastlinedefined;	/* (S) */ |  | ||||||
|   char short_src[LUA_IDSIZE]; /* (S) */ |  | ||||||
|   /* private part */ |  | ||||||
|   int i_ci;  /* active function */ |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /* }====================================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /****************************************************************************** |  | ||||||
| * Copyright (C) 1994-2006 Lua.org, PUC-Rio.  All rights reserved. |  | ||||||
| * |  | ||||||
| * Permission is hereby granted, free of charge, to any person obtaining |  | ||||||
| * a copy of this software and associated documentation files (the |  | ||||||
| * "Software"), to deal in the Software without restriction, including |  | ||||||
| * without limitation the rights to use, copy, modify, merge, publish, |  | ||||||
| * distribute, sublicense, and/or sell copies of the Software, and to |  | ||||||
| * permit persons to whom the Software is furnished to do so, subject to |  | ||||||
| * the following conditions: |  | ||||||
| * |  | ||||||
| * The above copyright notice and this permission notice shall be |  | ||||||
| * included in all copies or substantial portions of the Software. |  | ||||||
| * |  | ||||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |  | ||||||
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |  | ||||||
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |  | ||||||
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |  | ||||||
| * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |  | ||||||
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |  | ||||||
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |  | ||||||
| ******************************************************************************/ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
							
								
								
									
										196
									
								
								src/lua/luac.c
									
									
									
									
									
								
							
							
						
						
									
										196
									
								
								src/lua/luac.c
									
									
									
									
									
								
							| @@ -1,196 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: luac.c,v 1.52 2005/11/11 14:03:13 lhf Exp $ |  | ||||||
| ** Lua compiler (saves bytecodes to files; also list bytecodes) |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #include <errno.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define luac_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
| #include "lauxlib.h" |  | ||||||
|  |  | ||||||
| #include "ldo.h" |  | ||||||
| #include "lfunc.h" |  | ||||||
| #include "lmem.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lopcodes.h" |  | ||||||
| #include "lstring.h" |  | ||||||
| #include "lundump.h" |  | ||||||
|  |  | ||||||
| #define PROGNAME	"luac"		/* default program name */ |  | ||||||
| #define	OUTPUT		PROGNAME ".out"	/* default output file */ |  | ||||||
|  |  | ||||||
| static int listing=0;			/* list bytecodes? */ |  | ||||||
| static int dumping=1;			/* dump bytecodes? */ |  | ||||||
| static int stripping=0;			/* strip debug information? */ |  | ||||||
| static char Output[]={ OUTPUT };	/* default output file name */ |  | ||||||
| static const char* output=Output;	/* actual output file name */ |  | ||||||
| static const char* progname=PROGNAME;	/* actual program name */ |  | ||||||
|  |  | ||||||
| static void fatal(const char* message) |  | ||||||
| { |  | ||||||
|  fprintf(stderr,"%s: %s\n",progname,message); |  | ||||||
|  exit(EXIT_FAILURE); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void cannot(const char* what) |  | ||||||
| { |  | ||||||
|  fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno)); |  | ||||||
|  exit(EXIT_FAILURE); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void usage(const char* message) |  | ||||||
| { |  | ||||||
|  if (*message=='-') |  | ||||||
|   fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message); |  | ||||||
|  else |  | ||||||
|   fprintf(stderr,"%s: %s\n",progname,message); |  | ||||||
|  fprintf(stderr, |  | ||||||
|  "usage: %s [options] [filenames].\n" |  | ||||||
|  "Available options are:\n" |  | ||||||
|  "  -        process stdin\n" |  | ||||||
|  "  -l       list\n" |  | ||||||
|  "  -o name  output to file " LUA_QL("name") " (default is \"%s\")\n" |  | ||||||
|  "  -p       parse only\n" |  | ||||||
|  "  -s       strip debug information\n" |  | ||||||
|  "  -v       show version information\n" |  | ||||||
|  "  --       stop handling options\n", |  | ||||||
|  progname,Output); |  | ||||||
|  exit(EXIT_FAILURE); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #define	IS(s)	(strcmp(argv[i],s)==0) |  | ||||||
|  |  | ||||||
| static int doargs(int argc, char* argv[]) |  | ||||||
| { |  | ||||||
|  int i; |  | ||||||
|  if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0]; |  | ||||||
|  for (i=1; i<argc; i++) |  | ||||||
|  { |  | ||||||
|   if (*argv[i]!='-')			/* end of options; keep it */ |  | ||||||
|    break; |  | ||||||
|   else if (IS("--"))			/* end of options; skip it */ |  | ||||||
|   { |  | ||||||
|    ++i; |  | ||||||
|    break; |  | ||||||
|   } |  | ||||||
|   else if (IS("-"))			/* end of options; use stdin */ |  | ||||||
|    break; |  | ||||||
|   else if (IS("-l"))			/* list */ |  | ||||||
|    ++listing; |  | ||||||
|   else if (IS("-o"))			/* output file */ |  | ||||||
|   { |  | ||||||
|    output=argv[++i]; |  | ||||||
|    if (output==NULL || *output==0) usage(LUA_QL("-o") " needs argument"); |  | ||||||
|    if (IS("-")) output=NULL; |  | ||||||
|   } |  | ||||||
|   else if (IS("-p"))			/* parse only */ |  | ||||||
|    dumping=0; |  | ||||||
|   else if (IS("-s"))			/* strip debug information */ |  | ||||||
|    stripping=1; |  | ||||||
|   else if (IS("-v"))			/* show version */ |  | ||||||
|   { |  | ||||||
|    printf("%s  %s\n",LUA_VERSION,LUA_COPYRIGHT); |  | ||||||
|    if (argc==2) exit(EXIT_SUCCESS); |  | ||||||
|   } |  | ||||||
|   else					/* unknown option */ |  | ||||||
|    usage(argv[i]); |  | ||||||
|  } |  | ||||||
|  if (i==argc && (listing || !dumping)) |  | ||||||
|  { |  | ||||||
|   dumping=0; |  | ||||||
|   argv[--i]=Output; |  | ||||||
|  } |  | ||||||
|  return i; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #define toproto(L,i) (clvalue(L->top+(i))->l.p) |  | ||||||
|  |  | ||||||
| static Proto* combine(lua_State* L, int n) |  | ||||||
| { |  | ||||||
|  if (n==1) |  | ||||||
|   return toproto(L,-1); |  | ||||||
|  else |  | ||||||
|  { |  | ||||||
|   int i,pc; |  | ||||||
|   Proto* f=luaF_newproto(L); |  | ||||||
|   setptvalue2s(L,L->top,f); incr_top(L); |  | ||||||
|   f->source=luaS_newliteral(L,"=(" PROGNAME ")"); |  | ||||||
|   f->maxstacksize=1; |  | ||||||
|   pc=2*n+1; |  | ||||||
|   f->code=luaM_newvector(L,pc,Instruction); |  | ||||||
|   f->sizecode=pc; |  | ||||||
|   f->p=luaM_newvector(L,n,Proto*); |  | ||||||
|   f->sizep=n; |  | ||||||
|   pc=0; |  | ||||||
|   for (i=0; i<n; i++) |  | ||||||
|   { |  | ||||||
|    f->p[i]=toproto(L,i-n-1); |  | ||||||
|    f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i); |  | ||||||
|    f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1); |  | ||||||
|   } |  | ||||||
|   f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0); |  | ||||||
|   return f; |  | ||||||
|  } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int writer(lua_State* L, const void* p, size_t size, void* u) |  | ||||||
| { |  | ||||||
|  UNUSED(L); |  | ||||||
|  return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| struct Smain { |  | ||||||
|  int argc; |  | ||||||
|  char** argv; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| static int pmain(lua_State* L) |  | ||||||
| { |  | ||||||
|  struct Smain* s = (struct Smain*)lua_touserdata(L, 1); |  | ||||||
|  int argc=s->argc; |  | ||||||
|  char** argv=s->argv; |  | ||||||
|  Proto* f; |  | ||||||
|  int i; |  | ||||||
|  if (!lua_checkstack(L,argc)) fatal("too many input files"); |  | ||||||
|  for (i=0; i<argc; i++) |  | ||||||
|  { |  | ||||||
|   const char* filename=IS("-") ? NULL : argv[i]; |  | ||||||
|   if (luaL_loadfile(L,filename)!=0) fatal(lua_tostring(L,-1)); |  | ||||||
|  } |  | ||||||
|  f=combine(L,argc); |  | ||||||
|  if (listing) luaU_print(f,listing>1); |  | ||||||
|  if (dumping) |  | ||||||
|  { |  | ||||||
|   FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); |  | ||||||
|   if (D==NULL) cannot("open"); |  | ||||||
|   lua_lock(L); |  | ||||||
|   luaU_dump(L,f,writer,D,stripping); |  | ||||||
|   lua_unlock(L); |  | ||||||
|   if (ferror(D)) cannot("write"); |  | ||||||
|   if (fclose(D)) cannot("close"); |  | ||||||
|  } |  | ||||||
|  return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int main(int argc, char* argv[]) |  | ||||||
| { |  | ||||||
|  lua_State* L; |  | ||||||
|  struct Smain s; |  | ||||||
|  int i=doargs(argc,argv); |  | ||||||
|  argc-=i; argv+=i; |  | ||||||
|  if (argc<=0) usage("no input files given"); |  | ||||||
|  L=lua_open(); |  | ||||||
|  if (L==NULL) fatal("not enough memory for state"); |  | ||||||
|  s.argc=argc; |  | ||||||
|  s.argv=argv; |  | ||||||
|  if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1)); |  | ||||||
|  lua_close(L); |  | ||||||
|  return EXIT_SUCCESS; |  | ||||||
| } |  | ||||||
| @@ -1,736 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: luaconf.h,v 1.81 2006/02/10 17:44:06 roberto Exp $ |  | ||||||
| ** Configuration file for Lua |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifndef lconfig_h |  | ||||||
| #define lconfig_h |  | ||||||
|  |  | ||||||
| #include <limits.h> |  | ||||||
| #include <stddef.h> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** ================================================================== |  | ||||||
| ** Search for "@@" to find all configurable definitions. |  | ||||||
| ** =================================================================== |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_ANSI controls the use of non-ansi features. |  | ||||||
| ** CHANGE it (define it) if you want Lua to avoid the use of any |  | ||||||
| ** non-ansi feature or library. |  | ||||||
| */ |  | ||||||
| #if defined(__STRICT_ANSI__) |  | ||||||
| #define LUA_ANSI |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #if !defined(LUA_ANSI) && defined(_WIN32) |  | ||||||
| #define LUA_WIN |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #if defined(LUA_USE_LINUX) |  | ||||||
| #define LUA_USE_POSIX |  | ||||||
| #define LUA_USE_DLOPEN		/* needs an extra library: -ldl */ |  | ||||||
| #define LUA_USE_READLINE	/* needs some extra libraries */ |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #if defined(LUA_USE_MACOSX) |  | ||||||
| #define LUA_USE_POSIX |  | ||||||
| #define LUA_DL_DYLD		/* does not need extra library */ |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_USE_POSIX includes all functionallity listed as X/Open System |  | ||||||
| @* Interfaces Extension (XSI). |  | ||||||
| ** CHANGE it (define it) if your system is XSI compatible. |  | ||||||
| */ |  | ||||||
| #if defined(LUA_USE_POSIX) |  | ||||||
| #define LUA_USE_MKSTEMP |  | ||||||
| #define LUA_USE_ISATTY |  | ||||||
| #define LUA_USE_POPEN |  | ||||||
| #define LUA_USE_ULONGJMP |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for |  | ||||||
| @* Lua libraries. |  | ||||||
| @@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for |  | ||||||
| @* C libraries. |  | ||||||
| ** CHANGE them if your machine has a non-conventional directory |  | ||||||
| ** hierarchy or if you want to install your libraries in |  | ||||||
| ** non-conventional directories. |  | ||||||
| */ |  | ||||||
| #if defined(_WIN32) |  | ||||||
| /* |  | ||||||
| ** In Windows, any exclamation mark ('!') in the path is replaced by the |  | ||||||
| ** path of the directory of the executable file of the current process. |  | ||||||
| */ |  | ||||||
| #define LUA_LDIR	"!\\lua\\" |  | ||||||
| #define LUA_CDIR	"!\\" |  | ||||||
| #define LUA_PATH_DEFAULT  \ |  | ||||||
| 		".\\?.lua;"  LUA_LDIR"?.lua;"  LUA_LDIR"?\\init.lua;" \ |  | ||||||
| 		             LUA_CDIR"?.lua;"  LUA_CDIR"?\\init.lua" |  | ||||||
| #define LUA_CPATH_DEFAULT \ |  | ||||||
| 	".\\?.dll;"  LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll" |  | ||||||
|  |  | ||||||
| #else |  | ||||||
| #define LUA_ROOT	"/usr/local/" |  | ||||||
| #define LUA_LDIR	LUA_ROOT "share/lua/5.1/" |  | ||||||
| #define LUA_CDIR	LUA_ROOT "lib/lua/5.1/" |  | ||||||
| #define LUA_PATH_DEFAULT  \ |  | ||||||
| 		"./?.lua;"  LUA_LDIR"?.lua;"  LUA_LDIR"?/init.lua;" \ |  | ||||||
| 		            LUA_CDIR"?.lua;"  LUA_CDIR"?/init.lua" |  | ||||||
| #define LUA_CPATH_DEFAULT \ |  | ||||||
| 	"./?.so;"  LUA_CDIR"?.so;" LUA_CDIR"loadall.so" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_DIRSEP is the directory separator (for submodules). |  | ||||||
| ** CHANGE it if your machine does not use "/" as the directory separator |  | ||||||
| ** and is not Windows. (On Windows Lua automatically uses "\".) |  | ||||||
| */ |  | ||||||
| #if defined(_WIN32) |  | ||||||
| #define LUA_DIRSEP	"\\" |  | ||||||
| #else |  | ||||||
| #define LUA_DIRSEP	"/" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_PATHSEP is the character that separates templates in a path. |  | ||||||
| @@ LUA_PATH_MARK is the string that marks the substitution points in a |  | ||||||
| @* template. |  | ||||||
| @@ LUA_EXECDIR in a Windows path is replaced by the executable's |  | ||||||
| @* directory. |  | ||||||
| @@ LUA_IGMARK is a mark to ignore all before it when bulding the |  | ||||||
| @* luaopen_ function name. |  | ||||||
| ** CHANGE them if for some reason your system cannot use those |  | ||||||
| ** characters. (E.g., if one of those characters is a common character |  | ||||||
| ** in file/directory names.) Probably you do not need to change them. |  | ||||||
| */ |  | ||||||
| #define LUA_PATHSEP	";" |  | ||||||
| #define LUA_PATH_MARK	"?" |  | ||||||
| #define LUA_EXECDIR	"!" |  | ||||||
| #define LUA_IGMARK	"-" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. |  | ||||||
| ** CHANGE that if ptrdiff_t is not adequate on your machine. (On most |  | ||||||
| ** machines, ptrdiff_t gives a good choice between int or long.) |  | ||||||
| */ |  | ||||||
| #define LUA_INTEGER	ptrdiff_t |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_API is a mark for all core API functions. |  | ||||||
| @@ LUALIB_API is a mark for all standard library functions. |  | ||||||
| ** CHANGE them if you need to define those functions in some special way. |  | ||||||
| ** For instance, if you want to create one Windows DLL with the core and |  | ||||||
| ** the libraries, you may want to use the following definition (define |  | ||||||
| ** LUA_BUILD_AS_DLL to get it). |  | ||||||
| */ |  | ||||||
| #if defined(LUA_BUILD_AS_DLL) |  | ||||||
|  |  | ||||||
| #if defined(LUA_CORE) || defined(LUA_LIB) |  | ||||||
| #define LUA_API __declspec(dllexport) |  | ||||||
| #else |  | ||||||
| #define LUA_API __declspec(dllimport) |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #else |  | ||||||
|  |  | ||||||
| #define LUA_API		extern |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| /* more often than not the libs go together with the core */ |  | ||||||
| #define LUALIB_API	LUA_API |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAI_FUNC is a mark for all extern functions that are not to be |  | ||||||
| @* exported to outside modules. |  | ||||||
| @@ LUAI_DATA is a mark for all extern (const) variables that are not to |  | ||||||
| @* be exported to outside modules. |  | ||||||
| ** CHANGE them if you need to mark them in some special way. Elf/gcc |  | ||||||
| ** (versions 3.2 and later) mark them as "hidden" to optimize access |  | ||||||
| ** when Lua is compiled as a shared library. |  | ||||||
| */ |  | ||||||
| #if defined(luaall_c) |  | ||||||
| #define LUAI_FUNC	static |  | ||||||
| #define LUAI_DATA	/* empty */ |  | ||||||
|  |  | ||||||
| #elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ |  | ||||||
|       defined(__ELF__) |  | ||||||
| #define LUAI_FUNC	__attribute__((visibility("hidden"))) extern |  | ||||||
| #define LUAI_DATA	LUAI_FUNC |  | ||||||
|  |  | ||||||
| #else |  | ||||||
| #define LUAI_FUNC	extern |  | ||||||
| #define LUAI_DATA	extern |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_QL describes how error messages quote program elements. |  | ||||||
| ** CHANGE it if you want a different appearance. |  | ||||||
| */ |  | ||||||
| #define LUA_QL(x)	"'" x "'" |  | ||||||
| #define LUA_QS		LUA_QL("%s") |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_IDSIZE gives the maximum size for the description of the source |  | ||||||
| @* of a function in debug information. |  | ||||||
| ** CHANGE it if you want a different size. |  | ||||||
| */ |  | ||||||
| #define LUA_IDSIZE	60 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {================================================================== |  | ||||||
| ** Stand-alone configuration |  | ||||||
| ** =================================================================== |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #if defined(lua_c) || defined(luaall_c) |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that |  | ||||||
| @* is, whether we're running lua interactively). |  | ||||||
| ** CHANGE it if you have a better definition for non-POSIX/non-Windows |  | ||||||
| ** systems. |  | ||||||
| */ |  | ||||||
| #if defined(LUA_USE_ISATTY) |  | ||||||
| #include <unistd.h> |  | ||||||
| #define lua_stdin_is_tty()	isatty(0) |  | ||||||
| #elif defined(LUA_WIN) |  | ||||||
| #include <io.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #define lua_stdin_is_tty()	_isatty(_fileno(stdin)) |  | ||||||
| #else |  | ||||||
| #define lua_stdin_is_tty()	1  /* assume stdin is a tty */ |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_PROMPT is the default prompt used by stand-alone Lua. |  | ||||||
| @@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua. |  | ||||||
| ** CHANGE them if you want different prompts. (You can also change the |  | ||||||
| ** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.) |  | ||||||
| */ |  | ||||||
| #define LUA_PROMPT		"> " |  | ||||||
| #define LUA_PROMPT2		">> " |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_PROGNAME is the default name for the stand-alone Lua program. |  | ||||||
| ** CHANGE it if your stand-alone interpreter has a different name and |  | ||||||
| ** your system is not able to detect that name automatically. |  | ||||||
| */ |  | ||||||
| #define LUA_PROGNAME		"lua" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_MAXINPUT is the maximum length for an input line in the |  | ||||||
| @* stand-alone interpreter. |  | ||||||
| ** CHANGE it if you need longer lines. |  | ||||||
| */ |  | ||||||
| #define LUA_MAXINPUT	512 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ lua_readline defines how to show a prompt and then read a line from |  | ||||||
| @* the standard input. |  | ||||||
| @@ lua_saveline defines how to "save" a read line in a "history". |  | ||||||
| @@ lua_freeline defines how to free a line read by lua_readline. |  | ||||||
| ** CHANGE them if you want to improve this functionality (e.g., by using |  | ||||||
| ** GNU readline and history facilities). |  | ||||||
| */ |  | ||||||
| #if defined(LUA_USE_READLINE) |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <readline/readline.h> |  | ||||||
| #include <readline/history.h> |  | ||||||
| #define lua_readline(L,b,p)	((void)L, ((b)=readline(p)) != NULL) |  | ||||||
| #define lua_saveline(L,idx) \ |  | ||||||
| 	if (lua_strlen(L,idx) > 0)  /* non-empty line? */ \ |  | ||||||
| 	  add_history(lua_tostring(L, idx));  /* add it to history */ |  | ||||||
| #define lua_freeline(L,b)	((void)L, free(b)) |  | ||||||
| #else |  | ||||||
| #define lua_readline(L,b,p)	\ |  | ||||||
| 	((void)L, fputs(p, stdout), fflush(stdout),  /* show prompt */ \ |  | ||||||
| 	fgets(b, LUA_MAXINPUT, stdin) != NULL)  /* get line */ |  | ||||||
| #define lua_saveline(L,idx)	{ (void)L; (void)idx; } |  | ||||||
| #define lua_freeline(L,b)	{ (void)L; (void)b; } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| /* }================================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles |  | ||||||
| @* as a percentage. |  | ||||||
| ** CHANGE it if you want the GC to run faster or slower (higher values |  | ||||||
| ** mean larger pauses which mean slower collection.) You can also change |  | ||||||
| ** this value dynamically. |  | ||||||
| */ |  | ||||||
| #define LUAI_GCPAUSE	200  /* 200% (wait memory to double before next GC) */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAI_GCMUL defines the default speed of garbage collection relative to |  | ||||||
| @* memory allocation as a percentage. |  | ||||||
| ** CHANGE it if you want to change the granularity of the garbage |  | ||||||
| ** collection. (Higher values mean coarser collections. 0 represents |  | ||||||
| ** infinity, where each step performs a full collection.) You can also |  | ||||||
| ** change this value dynamically. |  | ||||||
| */ |  | ||||||
| #define LUAI_GCMUL	200 /* GC runs 'twice the speed' of memory allocation */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_COMPAT_GETN controls compatibility with old getn behavior. |  | ||||||
| ** CHANGE it (define it) if you want exact compatibility with the |  | ||||||
| ** behavior of setn/getn in Lua 5.0. |  | ||||||
| */ |  | ||||||
| #undef LUA_COMPAT_GETN |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib. |  | ||||||
| ** CHANGE it to undefined as soon as you do not need a global 'loadlib' |  | ||||||
| ** function (the function is still available as 'package.loadlib'). |  | ||||||
| */ |  | ||||||
| #undef LUA_COMPAT_LOADLIB |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_COMPAT_VARARG controls compatibility with old vararg feature. |  | ||||||
| ** CHANGE it to undefined as soon as your programs use only '...' to |  | ||||||
| ** access vararg parameters (instead of the old 'arg' table). |  | ||||||
| */ |  | ||||||
| #define LUA_COMPAT_VARARG |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_COMPAT_MOD controls compatibility with old math.mod function. |  | ||||||
| ** CHANGE it to undefined as soon as your programs use 'math.fmod' or |  | ||||||
| ** the new '%' operator instead of 'math.mod'. |  | ||||||
| */ |  | ||||||
| #define LUA_COMPAT_MOD |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_COMPAT_LSTR controls compatibility with old long string nesting |  | ||||||
| @* facility. |  | ||||||
| ** CHANGE it to 2 if you want the old behaviour, or undefine it to turn |  | ||||||
| ** off the advisory error when nesting [[...]]. |  | ||||||
| */ |  | ||||||
| #define LUA_COMPAT_LSTR		1 |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name. |  | ||||||
| ** CHANGE it to undefined as soon as you rename 'string.gfind' to |  | ||||||
| ** 'string.gmatch'. |  | ||||||
| */ |  | ||||||
| #define LUA_COMPAT_GFIND |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib' |  | ||||||
| @* behavior. |  | ||||||
| ** CHANGE it to undefined as soon as you replace to 'luaL_registry' |  | ||||||
| ** your uses of 'luaL_openlib' |  | ||||||
| */ |  | ||||||
| #define LUA_COMPAT_OPENLIB |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ luai_apicheck is the assert macro used by the Lua-C API. |  | ||||||
| ** CHANGE luai_apicheck if you want Lua to perform some checks in the |  | ||||||
| ** parameters it gets from API calls. This may slow down the interpreter |  | ||||||
| ** a bit, but may be quite useful when debugging C code that interfaces |  | ||||||
| ** with Lua. A useful redefinition is to use assert.h. |  | ||||||
| */ |  | ||||||
| #if defined(LUA_USE_APICHECK) |  | ||||||
| #include <assert.h> |  | ||||||
| #define luai_apicheck(L,o)	{ (void)L; assert(o); } |  | ||||||
| #else |  | ||||||
| #define luai_apicheck(L,o)	{ (void)L; } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAI_BITSINT defines the number of bits in an int. |  | ||||||
| ** CHANGE here if Lua cannot automatically detect the number of bits of |  | ||||||
| ** your machine. Probably you do not need to change this. |  | ||||||
| */ |  | ||||||
| /* avoid overflows in comparison */ |  | ||||||
| #if INT_MAX-20 < 32760 |  | ||||||
| #define LUAI_BITSINT	16 |  | ||||||
| #elif INT_MAX > 2147483640L |  | ||||||
| /* int has at least 32 bits */ |  | ||||||
| #define LUAI_BITSINT	32 |  | ||||||
| #else |  | ||||||
| #error "you must define LUA_BITSINT with number of bits in an integer" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAI_UINT32 is an unsigned integer with at least 32 bits. |  | ||||||
| @@ LUAI_INT32 is an signed integer with at least 32 bits. |  | ||||||
| @@ LUAI_UMEM is an unsigned integer big enough to count the total |  | ||||||
| @* memory used by Lua. |  | ||||||
| @@ LUAI_MEM is a signed integer big enough to count the total memory |  | ||||||
| @* used by Lua. |  | ||||||
| ** CHANGE here if for some weird reason the default definitions are not |  | ||||||
| ** good enough for your machine. (The definitions in the 'else' |  | ||||||
| ** part always works, but may waste space on machines with 64-bit |  | ||||||
| ** longs.) Probably you do not need to change this. |  | ||||||
| */ |  | ||||||
| #if LUAI_BITSINT >= 32 |  | ||||||
| #define LUAI_UINT32	unsigned int |  | ||||||
| #define LUAI_INT32	int |  | ||||||
| #define LUAI_MAXINT32	INT_MAX |  | ||||||
| #define LUAI_UMEM	size_t |  | ||||||
| #define LUAI_MEM	ptrdiff_t |  | ||||||
| #else |  | ||||||
| /* 16-bit ints */ |  | ||||||
| #define LUAI_UINT32	unsigned long |  | ||||||
| #define LUAI_INT32	long |  | ||||||
| #define LUAI_MAXINT32	LONG_MAX |  | ||||||
| #define LUAI_UMEM	unsigned long |  | ||||||
| #define LUAI_MEM	long |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAI_MAXCALLS limits the number of nested calls. |  | ||||||
| ** CHANGE it if you need really deep recursive calls. This limit is |  | ||||||
| ** arbitrary; its only purpose is to stop infinite recursion before |  | ||||||
| ** exhausting memory. |  | ||||||
| */ |  | ||||||
| #define LUAI_MAXCALLS	20000 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function |  | ||||||
| @* can use. |  | ||||||
| ** CHANGE it if you need lots of (Lua) stack space for your C |  | ||||||
| ** functions. This limit is arbitrary; its only purpose is to stop C |  | ||||||
| ** functions to consume unlimited stack space. |  | ||||||
| */ |  | ||||||
| #define LUAI_MAXCSTACK	2048 |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {================================================================== |  | ||||||
| ** CHANGE (to smaller values) the following definitions if your system |  | ||||||
| ** has a small C stack. (Or you may want to change them to larger |  | ||||||
| ** values if your system has a large C stack and these limits are |  | ||||||
| ** too rigid for you.) Some of these constants control the size of |  | ||||||
| ** stack-allocated arrays used by the compiler or the interpreter, while |  | ||||||
| ** others limit the maximum number of recursive calls that the compiler |  | ||||||
| ** or the interpreter can perform. Values too large may cause a C stack |  | ||||||
| ** overflow for some forms of deep constructs. |  | ||||||
| ** =================================================================== |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and |  | ||||||
| @* syntactical nested non-terminals in a program. |  | ||||||
| */ |  | ||||||
| #define LUAI_MAXCCALLS		200 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAI_MAXVARS is the maximum number of local variables per function |  | ||||||
| @* (must be smaller than 250). |  | ||||||
| */ |  | ||||||
| #define LUAI_MAXVARS		200 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAI_MAXUPVALUES is the maximum number of upvalues per function |  | ||||||
| @* (must be smaller than 250). |  | ||||||
| */ |  | ||||||
| #define LUAI_MAXUPVALUES	60 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. |  | ||||||
| */ |  | ||||||
| #define LUAL_BUFFERSIZE		BUFSIZ |  | ||||||
|  |  | ||||||
| /* }================================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** {================================================================== |  | ||||||
| @@ LUA_NUMBER is the type of numbers in Lua. |  | ||||||
| ** CHANGE the following definitions only if you want to build Lua |  | ||||||
| ** with a number type different from double. You may also need to |  | ||||||
| ** change lua_number2int & lua_number2integer. |  | ||||||
| ** =================================================================== |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #define LUA_NUMBER_DOUBLE |  | ||||||
| #define LUA_NUMBER	double |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAI_UACNUMBER is the result of an 'usual argument conversion' |  | ||||||
| @* over a number. |  | ||||||
| */ |  | ||||||
| #define LUAI_UACNUMBER	double |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_NUMBER_SCAN is the format for reading numbers. |  | ||||||
| @@ LUA_NUMBER_FMT is the format for writing numbers. |  | ||||||
| @@ lua_number2str converts a number to a string. |  | ||||||
| @@ LUAI_MAXNUMBER2STR is maximum size of previous conversion. |  | ||||||
| @@ lua_str2number converts a string to a number. |  | ||||||
| */ |  | ||||||
| #define LUA_NUMBER_SCAN		"%lf" |  | ||||||
| #define LUA_NUMBER_FMT		"%.14g" |  | ||||||
| #define lua_number2str(s,n)	sprintf((s), LUA_NUMBER_FMT, (n)) |  | ||||||
| #define LUAI_MAXNUMBER2STR	32 /* 16 digits, sign, point, and \0 */ |  | ||||||
| #define lua_str2number(s,p)	strtod((s), (p)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ The luai_num* macros define the primitive operations over numbers. |  | ||||||
| */ |  | ||||||
| #if defined(LUA_CORE) |  | ||||||
| #include <math.h> |  | ||||||
| #define luai_numadd(a,b)	((a)+(b)) |  | ||||||
| #define luai_numsub(a,b)	((a)-(b)) |  | ||||||
| #define luai_nummul(a,b)	((a)*(b)) |  | ||||||
| #define luai_numdiv(a,b)	((a)/(b)) |  | ||||||
| #define luai_nummod(a,b)	((a) - floor((a)/(b))*(b)) |  | ||||||
| #define luai_numpow(a,b)	(pow(a,b)) |  | ||||||
| #define luai_numunm(a)		(-(a)) |  | ||||||
| #define luai_numeq(a,b)		((a)==(b)) |  | ||||||
| #define luai_numlt(a,b)		((a)<(b)) |  | ||||||
| #define luai_numle(a,b)		((a)<=(b)) |  | ||||||
| #define luai_numisnan(a)	(!luai_numeq((a), (a))) |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ lua_number2int is a macro to convert lua_Number to int. |  | ||||||
| @@ lua_number2integer is a macro to convert lua_Number to lua_Integer. |  | ||||||
| ** CHANGE them if you know a faster way to convert a lua_Number to |  | ||||||
| ** int (with any rounding method and without throwing errors) in your |  | ||||||
| ** system. In Pentium machines, a naive typecast from double to int |  | ||||||
| ** in C is extremely slow, so any alternative is worth trying. |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| /* On a Pentium, resort to a trick */ |  | ||||||
| #if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \ |  | ||||||
|     (defined(__i386) || defined (_M_IX86) || defined(__i386__)) |  | ||||||
| union luai_Cast { double l_d; long l_l; }; |  | ||||||
| #define lua_number2int(i,d) \ |  | ||||||
|   { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; } |  | ||||||
| #define lua_number2integer(i,n)		lua_number2int(i, n) |  | ||||||
|  |  | ||||||
| /* this option always works, but may be slow */ |  | ||||||
| #else |  | ||||||
| #define lua_number2int(i,d)	((i)=(int)(d)) |  | ||||||
| #define lua_number2integer(i,d)	((i)=(lua_Integer)(d)) |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| /* }================================================================== */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment. |  | ||||||
| ** CHANGE it if your system requires alignments larger than double. (For |  | ||||||
| ** instance, if your system supports long doubles and they must be |  | ||||||
| ** aligned in 16-byte boundaries, then you should add long double in the |  | ||||||
| ** union.) Probably you do not need to change this. |  | ||||||
| */ |  | ||||||
| #define LUAI_USER_ALIGNMENT_T	union { double u; void *s; long l; } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAI_THROW/LUAI_TRY define how Lua does exception handling. |  | ||||||
| ** CHANGE them if you prefer to use longjmp/setjmp even with C++ |  | ||||||
| ** or if want/don't to use _longjmp/_setjmp instead of regular |  | ||||||
| ** longjmp/setjmp. By default, Lua handles errors with exceptions when |  | ||||||
| ** compiling as C++ code, with _longjmp/_setjmp when asked to use them, |  | ||||||
| ** and with longjmp/setjmp otherwise. |  | ||||||
| */ |  | ||||||
| #if defined(__cplusplus) |  | ||||||
| /* C++ exceptions */ |  | ||||||
| #define LUAI_THROW(L,c)	throw(c) |  | ||||||
| #define LUAI_TRY(L,c,a)	try { a } catch(...) \ |  | ||||||
| 	{ if ((c)->status == 0) (c)->status = -1; } |  | ||||||
| #define luai_jmpbuf	int  /* dummy variable */ |  | ||||||
|  |  | ||||||
| #elif defined(LUA_USE_ULONGJMP) |  | ||||||
| /* in Unix, try _longjmp/_setjmp (more efficient) */ |  | ||||||
| #define LUAI_THROW(L,c)	_longjmp((c)->b, 1) |  | ||||||
| #define LUAI_TRY(L,c,a)	if (_setjmp((c)->b) == 0) { a } |  | ||||||
| #define luai_jmpbuf	jmp_buf |  | ||||||
|  |  | ||||||
| #else |  | ||||||
| /* default handling with long jumps */ |  | ||||||
| #define LUAI_THROW(L,c)	longjmp((c)->b, 1) |  | ||||||
| #define LUAI_TRY(L,c,a)	if (setjmp((c)->b) == 0) { a } |  | ||||||
| #define luai_jmpbuf	jmp_buf |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_MAXCAPTURES is the maximum number of captures that a pattern |  | ||||||
| @* can do during pattern-matching. |  | ||||||
| ** CHANGE it if you need more captures. This limit is arbitrary. |  | ||||||
| */ |  | ||||||
| #define LUA_MAXCAPTURES		32 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ lua_tmpnam is the function that the OS library uses to create a |  | ||||||
| @* temporary name. |  | ||||||
| @@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam. |  | ||||||
| ** CHANGE them if you have an alternative to tmpnam (which is considered |  | ||||||
| ** insecure) or if you want the original tmpnam anyway.  By default, Lua |  | ||||||
| ** uses tmpnam except when POSIX is available, where it uses mkstemp. |  | ||||||
| */ |  | ||||||
| #if defined(loslib_c) || defined(luaall_c) |  | ||||||
|  |  | ||||||
| #if defined(LUA_USE_MKSTEMP) |  | ||||||
| #include <unistd.h> |  | ||||||
| #define LUA_TMPNAMBUFSIZE	32 |  | ||||||
| #define lua_tmpnam(b,e)	{ \ |  | ||||||
| 	strcpy(b, "/tmp/lua_XXXXXX"); \ |  | ||||||
| 	e = mkstemp(b); \ |  | ||||||
| 	if (e != -1) close(e); \ |  | ||||||
| 	e = (e == -1); } |  | ||||||
|  |  | ||||||
| #else |  | ||||||
| #define LUA_TMPNAMBUFSIZE	L_tmpnam |  | ||||||
| #define lua_tmpnam(b,e)		{ e = (tmpnam(b) == NULL); } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ lua_popen spawns a new process connected to the current one through |  | ||||||
| @* the file streams. |  | ||||||
| ** CHANGE it if you have a way to implement it in your system. |  | ||||||
| */ |  | ||||||
| #if defined(LUA_USE_POPEN) |  | ||||||
|  |  | ||||||
| #define lua_popen(L,c,m)	((void)L, popen(c,m)) |  | ||||||
| #define lua_pclose(L,file)	((void)L, (pclose(file) != -1)) |  | ||||||
|  |  | ||||||
| #elif defined(LUA_WIN) |  | ||||||
|  |  | ||||||
| #define lua_popen(L,c,m)	((void)L, _popen(c,m)) |  | ||||||
| #define lua_pclose(L,file)	((void)L, (_pclose(file) != -1)) |  | ||||||
|  |  | ||||||
| #else |  | ||||||
|  |  | ||||||
| #define lua_popen(L,c,m)	((void)((void)c, m),  \ |  | ||||||
| 		luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) |  | ||||||
| #define lua_pclose(L,file)		((void)((void)L, file), 0) |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_DL_* define which dynamic-library system Lua should use. |  | ||||||
| ** CHANGE here if Lua has problems choosing the appropriate |  | ||||||
| ** dynamic-library system for your platform (either Windows' DLL, Mac's |  | ||||||
| ** dyld, or Unix's dlopen). If your system is some kind of Unix, there |  | ||||||
| ** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for |  | ||||||
| ** it.  To use dlopen you also need to adapt the src/Makefile (probably |  | ||||||
| ** adding -ldl to the linker options), so Lua does not select it |  | ||||||
| ** automatically.  (When you change the makefile to add -ldl, you must |  | ||||||
| ** also add -DLUA_USE_DLOPEN.) |  | ||||||
| ** If you do not want any kind of dynamic library, undefine all these |  | ||||||
| ** options. |  | ||||||
| ** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD. |  | ||||||
| */ |  | ||||||
| #if defined(LUA_USE_DLOPEN) |  | ||||||
| #define LUA_DL_DLOPEN |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #if defined(LUA_WIN) |  | ||||||
| #define LUA_DL_DLL |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State |  | ||||||
| @* (the data goes just *before* the lua_State pointer). |  | ||||||
| ** CHANGE (define) this if you really need that. This value must be |  | ||||||
| ** a multiple of the maximum alignment required for your machine. |  | ||||||
| */ |  | ||||||
| #define LUAI_EXTRASPACE		0 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ luai_userstate* allow user-specific actions on threads. |  | ||||||
| ** CHANGE them if you defined LUAI_EXTRASPACE and need to do something |  | ||||||
| ** extra when a thread is created/deleted/resumed/yielded. |  | ||||||
| */ |  | ||||||
| #define luai_userstateopen(L)		((void)L) |  | ||||||
| #define luai_userstateclose(L)		((void)L) |  | ||||||
| #define luai_userstatethread(L,L1)	((void)L) |  | ||||||
| #define luai_userstatefree(L)		((void)L) |  | ||||||
| #define luai_userstateresume(L,n)	((void)L) |  | ||||||
| #define luai_userstateyield(L,n)	((void)L) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| @@ LUA_INTFRMLEN is the length modifier for integer conversions |  | ||||||
| @* in 'string.format'. |  | ||||||
| @@ LUA_INTFRM_T is the integer type correspoding to the previous length |  | ||||||
| @* modifier. |  | ||||||
| ** CHANGE them if your system supports long long or does not support long. |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #if defined(LUA_USELONGLONG) |  | ||||||
|  |  | ||||||
| #define LUA_INTFRMLEN		"ll" |  | ||||||
| #define LUA_INTFRM_T		long long |  | ||||||
|  |  | ||||||
| #else |  | ||||||
|  |  | ||||||
| #define LUA_INTFRMLEN		"l" |  | ||||||
| #define LUA_INTFRM_T		long |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* =================================================================== */ |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Local configuration. You can use this space to add your redefinitions |  | ||||||
| ** without modifying the main part of the file. |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| @@ -1,53 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lualib.h,v 1.36 2005/12/27 17:12:00 roberto Exp $ |  | ||||||
| ** Lua standard libraries |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifndef lualib_h |  | ||||||
| #define lualib_h |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Key to file-handle type */ |  | ||||||
| #define LUA_FILEHANDLE		"FILE*" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define LUA_COLIBNAME	"coroutine" |  | ||||||
| LUALIB_API int (luaopen_base) (lua_State *L); |  | ||||||
|  |  | ||||||
| #define LUA_TABLIBNAME	"table" |  | ||||||
| LUALIB_API int (luaopen_table) (lua_State *L); |  | ||||||
|  |  | ||||||
| #define LUA_IOLIBNAME	"io" |  | ||||||
| LUALIB_API int (luaopen_io) (lua_State *L); |  | ||||||
|  |  | ||||||
| #define LUA_OSLIBNAME	"os" |  | ||||||
| LUALIB_API int (luaopen_os) (lua_State *L); |  | ||||||
|  |  | ||||||
| #define LUA_STRLIBNAME	"string" |  | ||||||
| LUALIB_API int (luaopen_string) (lua_State *L); |  | ||||||
|  |  | ||||||
| #define LUA_MATHLIBNAME	"math" |  | ||||||
| LUALIB_API int (luaopen_math) (lua_State *L); |  | ||||||
|  |  | ||||||
| #define LUA_DBLIBNAME	"debug" |  | ||||||
| LUALIB_API int (luaopen_debug) (lua_State *L); |  | ||||||
|  |  | ||||||
| #define LUA_LOADLIBNAME	"package" |  | ||||||
| LUALIB_API int (luaopen_package) (lua_State *L); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* open all previous libraries */ |  | ||||||
| LUALIB_API void (luaL_openlibs) (lua_State *L);  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifndef lua_assert |  | ||||||
| #define lua_assert(x)	((void)0) |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,223 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lundump.c,v 1.60 2006/02/16 15:53:49 lhf Exp $ |  | ||||||
| ** load precompiled Lua chunks |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define lundump_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "ldebug.h" |  | ||||||
| #include "ldo.h" |  | ||||||
| #include "lfunc.h" |  | ||||||
| #include "lmem.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lstring.h" |  | ||||||
| #include "lundump.h" |  | ||||||
| #include "lzio.h" |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|  lua_State* L; |  | ||||||
|  ZIO* Z; |  | ||||||
|  Mbuffer* b; |  | ||||||
|  const char* name; |  | ||||||
| } LoadState; |  | ||||||
|  |  | ||||||
| #ifdef LUAC_TRUST_BINARIES |  | ||||||
| #define IF(c,s) |  | ||||||
| #else |  | ||||||
| #define IF(c,s)		if (c) error(S,s) |  | ||||||
|  |  | ||||||
| static void error(LoadState* S, const char* why) |  | ||||||
| { |  | ||||||
|  luaO_pushfstring(S->L,"%s: %s in precompiled chunk",S->name,why); |  | ||||||
|  luaD_throw(S->L,LUA_ERRSYNTAX); |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #define LoadMem(S,b,n,size)	LoadBlock(S,b,(n)*(size)) |  | ||||||
| #define	LoadByte(S)		(lu_byte)LoadChar(S) |  | ||||||
| #define LoadVar(S,x)		LoadMem(S,&x,1,sizeof(x)) |  | ||||||
| #define LoadVector(S,b,n,size)	LoadMem(S,b,n,size) |  | ||||||
|  |  | ||||||
| static void LoadBlock(LoadState* S, void* b, size_t size) |  | ||||||
| { |  | ||||||
|  size_t r=luaZ_read(S->Z,b,size); |  | ||||||
|  IF (r!=0, "unexpected end"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int LoadChar(LoadState* S) |  | ||||||
| { |  | ||||||
|  char x; |  | ||||||
|  LoadVar(S,x); |  | ||||||
|  return x; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int LoadInt(LoadState* S) |  | ||||||
| { |  | ||||||
|  int x; |  | ||||||
|  LoadVar(S,x); |  | ||||||
|  IF (x<0, "bad integer"); |  | ||||||
|  return x; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static lua_Number LoadNumber(LoadState* S) |  | ||||||
| { |  | ||||||
|  lua_Number x; |  | ||||||
|  LoadVar(S,x); |  | ||||||
|  return x; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static TString* LoadString(LoadState* S) |  | ||||||
| { |  | ||||||
|  size_t size; |  | ||||||
|  LoadVar(S,size); |  | ||||||
|  if (size==0) |  | ||||||
|   return NULL; |  | ||||||
|  else |  | ||||||
|  { |  | ||||||
|   char* s=luaZ_openspace(S->L,S->b,size); |  | ||||||
|   LoadBlock(S,s,size); |  | ||||||
|   return luaS_newlstr(S->L,s,size-1);		/* remove trailing '\0' */ |  | ||||||
|  } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void LoadCode(LoadState* S, Proto* f) |  | ||||||
| { |  | ||||||
|  int n=LoadInt(S); |  | ||||||
|  f->code=luaM_newvector(S->L,n,Instruction); |  | ||||||
|  f->sizecode=n; |  | ||||||
|  LoadVector(S,f->code,n,sizeof(Instruction)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static Proto* LoadFunction(LoadState* S, TString* p); |  | ||||||
|  |  | ||||||
| static void LoadConstants(LoadState* S, Proto* f) |  | ||||||
| { |  | ||||||
|  int i,n; |  | ||||||
|  n=LoadInt(S); |  | ||||||
|  f->k=luaM_newvector(S->L,n,TValue); |  | ||||||
|  f->sizek=n; |  | ||||||
|  for (i=0; i<n; i++) setnilvalue(&f->k[i]); |  | ||||||
|  for (i=0; i<n; i++) |  | ||||||
|  { |  | ||||||
|   TValue* o=&f->k[i]; |  | ||||||
|   int t=LoadChar(S); |  | ||||||
|   switch (t) |  | ||||||
|   { |  | ||||||
|    case LUA_TNIL: |  | ||||||
|    	setnilvalue(o); |  | ||||||
| 	break; |  | ||||||
|    case LUA_TBOOLEAN: |  | ||||||
|    	setbvalue(o,LoadChar(S)); |  | ||||||
| 	break; |  | ||||||
|    case LUA_TNUMBER: |  | ||||||
| 	setnvalue(o,LoadNumber(S)); |  | ||||||
| 	break; |  | ||||||
|    case LUA_TSTRING: |  | ||||||
| 	setsvalue2n(S->L,o,LoadString(S)); |  | ||||||
| 	break; |  | ||||||
|    default: |  | ||||||
| 	IF (1, "bad constant"); |  | ||||||
| 	break; |  | ||||||
|   } |  | ||||||
|  } |  | ||||||
|  n=LoadInt(S); |  | ||||||
|  f->p=luaM_newvector(S->L,n,Proto*); |  | ||||||
|  f->sizep=n; |  | ||||||
|  for (i=0; i<n; i++) f->p[i]=NULL; |  | ||||||
|  for (i=0; i<n; i++) f->p[i]=LoadFunction(S,f->source); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void LoadDebug(LoadState* S, Proto* f) |  | ||||||
| { |  | ||||||
|  int i,n; |  | ||||||
|  n=LoadInt(S); |  | ||||||
|  f->lineinfo=luaM_newvector(S->L,n,int); |  | ||||||
|  f->sizelineinfo=n; |  | ||||||
|  LoadVector(S,f->lineinfo,n,sizeof(int)); |  | ||||||
|  n=LoadInt(S); |  | ||||||
|  f->locvars=luaM_newvector(S->L,n,LocVar); |  | ||||||
|  f->sizelocvars=n; |  | ||||||
|  for (i=0; i<n; i++) f->locvars[i].varname=NULL; |  | ||||||
|  for (i=0; i<n; i++) |  | ||||||
|  { |  | ||||||
|   f->locvars[i].varname=LoadString(S); |  | ||||||
|   f->locvars[i].startpc=LoadInt(S); |  | ||||||
|   f->locvars[i].endpc=LoadInt(S); |  | ||||||
|  } |  | ||||||
|  n=LoadInt(S); |  | ||||||
|  f->upvalues=luaM_newvector(S->L,n,TString*); |  | ||||||
|  f->sizeupvalues=n; |  | ||||||
|  for (i=0; i<n; i++) f->upvalues[i]=NULL; |  | ||||||
|  for (i=0; i<n; i++) f->upvalues[i]=LoadString(S); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static Proto* LoadFunction(LoadState* S, TString* p) |  | ||||||
| { |  | ||||||
|  Proto* f=luaF_newproto(S->L); |  | ||||||
|  setptvalue2s(S->L,S->L->top,f); incr_top(S->L); |  | ||||||
|  f->source=LoadString(S); if (f->source==NULL) f->source=p; |  | ||||||
|  f->linedefined=LoadInt(S); |  | ||||||
|  f->lastlinedefined=LoadInt(S); |  | ||||||
|  f->nups=LoadByte(S); |  | ||||||
|  f->numparams=LoadByte(S); |  | ||||||
|  f->is_vararg=LoadByte(S); |  | ||||||
|  f->maxstacksize=LoadByte(S); |  | ||||||
|  LoadCode(S,f); |  | ||||||
|  LoadConstants(S,f); |  | ||||||
|  LoadDebug(S,f); |  | ||||||
|  IF (!luaG_checkcode(f), "bad code"); |  | ||||||
|  S->L->top--; |  | ||||||
|  return f; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void LoadHeader(LoadState* S) |  | ||||||
| { |  | ||||||
|  char h[LUAC_HEADERSIZE]; |  | ||||||
|  char s[LUAC_HEADERSIZE]; |  | ||||||
|  luaU_header(h); |  | ||||||
|  LoadBlock(S,s,LUAC_HEADERSIZE); |  | ||||||
|  IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** load precompiled chunk |  | ||||||
| */ |  | ||||||
| Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) |  | ||||||
| { |  | ||||||
|  LoadState S; |  | ||||||
|  if (*name=='@' || *name=='=') |  | ||||||
|   S.name=name+1; |  | ||||||
|  else if (*name==LUA_SIGNATURE[0]) |  | ||||||
|   S.name="binary string"; |  | ||||||
|  else |  | ||||||
|   S.name=name; |  | ||||||
|  S.L=L; |  | ||||||
|  S.Z=Z; |  | ||||||
|  S.b=buff; |  | ||||||
|  LoadHeader(&S); |  | ||||||
|  return LoadFunction(&S,luaS_newliteral(L,"=?")); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| * make header |  | ||||||
| */ |  | ||||||
| void luaU_header (char* h) |  | ||||||
| { |  | ||||||
|  int x=1; |  | ||||||
|  memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1); |  | ||||||
|  h+=sizeof(LUA_SIGNATURE)-1; |  | ||||||
|  *h++=(char)LUAC_VERSION; |  | ||||||
|  *h++=(char)LUAC_FORMAT; |  | ||||||
|  *h++=(char)*(char*)&x;				/* endianness */ |  | ||||||
|  *h++=(char)sizeof(int); |  | ||||||
|  *h++=(char)sizeof(size_t); |  | ||||||
|  *h++=(char)sizeof(Instruction); |  | ||||||
|  *h++=(char)sizeof(lua_Number); |  | ||||||
|  *h++=(char)(((lua_Number)0.5)==0);		/* is lua_Number integral? */ |  | ||||||
| } |  | ||||||
| @@ -1,36 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lundump.h,v 1.40 2005/11/11 14:03:13 lhf Exp $ |  | ||||||
| ** load precompiled Lua chunks |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef lundump_h |  | ||||||
| #define lundump_h |  | ||||||
|  |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lzio.h" |  | ||||||
|  |  | ||||||
| /* load one chunk; from lundump.c */ |  | ||||||
| LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); |  | ||||||
|  |  | ||||||
| /* make header; from lundump.c */ |  | ||||||
| LUAI_FUNC void luaU_header (char* h); |  | ||||||
|  |  | ||||||
| /* dump one chunk; from ldump.c */ |  | ||||||
| LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip); |  | ||||||
|  |  | ||||||
| #ifdef luac_c |  | ||||||
| /* print one chunk; from print.c */ |  | ||||||
| LUAI_FUNC void luaU_print (const Proto* f, int full); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| /* for header of binary files -- this is Lua 5.1 */ |  | ||||||
| #define LUAC_VERSION		0x51 |  | ||||||
|  |  | ||||||
| /* for header of binary files -- this is the official format */ |  | ||||||
| #define LUAC_FORMAT		0 |  | ||||||
|  |  | ||||||
| /* size of header of binary files */ |  | ||||||
| #define LUAC_HEADERSIZE		12 |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
							
								
								
									
										762
									
								
								src/lua/lvm.c
									
									
									
									
									
								
							
							
						
						
									
										762
									
								
								src/lua/lvm.c
									
									
									
									
									
								
							| @@ -1,762 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lvm.c,v 2.62 2006/01/23 19:51:43 roberto Exp $ |  | ||||||
| ** Lua virtual machine |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define lvm_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "ldebug.h" |  | ||||||
| #include "ldo.h" |  | ||||||
| #include "lfunc.h" |  | ||||||
| #include "lgc.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lopcodes.h" |  | ||||||
| #include "lstate.h" |  | ||||||
| #include "lstring.h" |  | ||||||
| #include "ltable.h" |  | ||||||
| #include "ltm.h" |  | ||||||
| #include "lvm.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* limit for table tag-method chains (to avoid loops) */ |  | ||||||
| #define MAXTAGLOOP	100 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| const TValue *luaV_tonumber (const TValue *obj, TValue *n) { |  | ||||||
|   lua_Number num; |  | ||||||
|   if (ttisnumber(obj)) return obj; |  | ||||||
|   if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { |  | ||||||
|     setnvalue(n, num); |  | ||||||
|     return n; |  | ||||||
|   } |  | ||||||
|   else |  | ||||||
|     return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaV_tostring (lua_State *L, StkId obj) { |  | ||||||
|   if (!ttisnumber(obj)) |  | ||||||
|     return 0; |  | ||||||
|   else { |  | ||||||
|     char s[LUAI_MAXNUMBER2STR]; |  | ||||||
|     lua_Number n = nvalue(obj); |  | ||||||
|     lua_number2str(s, n); |  | ||||||
|     setsvalue2s(L, obj, luaS_new(L, s)); |  | ||||||
|     return 1; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void traceexec (lua_State *L, const Instruction *pc) { |  | ||||||
|   lu_byte mask = L->hookmask; |  | ||||||
|   const Instruction *oldpc = L->savedpc; |  | ||||||
|   L->savedpc = pc; |  | ||||||
|   if (mask > LUA_MASKLINE) {  /* instruction-hook set? */ |  | ||||||
|     if (L->hookcount == 0) { |  | ||||||
|       resethookcount(L); |  | ||||||
|       luaD_callhook(L, LUA_HOOKCOUNT, -1); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   if (mask & LUA_MASKLINE) { |  | ||||||
|     Proto *p = ci_func(L->ci)->l.p; |  | ||||||
|     int npc = pcRel(pc, p); |  | ||||||
|     int newline = getline(p, npc); |  | ||||||
|     /* call linehook when enter a new function, when jump back (loop), |  | ||||||
|        or when enter a new line */ |  | ||||||
|     if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) |  | ||||||
|       luaD_callhook(L, LUA_HOOKLINE, newline); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void callTMres (lua_State *L, StkId res, const TValue *f, |  | ||||||
|                         const TValue *p1, const TValue *p2) { |  | ||||||
|   ptrdiff_t result = savestack(L, res); |  | ||||||
|   setobj2s(L, L->top, f);  /* push function */ |  | ||||||
|   setobj2s(L, L->top+1, p1);  /* 1st argument */ |  | ||||||
|   setobj2s(L, L->top+2, p2);  /* 2nd argument */ |  | ||||||
|   luaD_checkstack(L, 3); |  | ||||||
|   L->top += 3; |  | ||||||
|   luaD_call(L, L->top - 3, 1); |  | ||||||
|   res = restorestack(L, result); |  | ||||||
|   L->top--; |  | ||||||
|   setobjs2s(L, res, L->top); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void callTM (lua_State *L, const TValue *f, const TValue *p1, |  | ||||||
|                     const TValue *p2, const TValue *p3) { |  | ||||||
|   setobj2s(L, L->top, f);  /* push function */ |  | ||||||
|   setobj2s(L, L->top+1, p1);  /* 1st argument */ |  | ||||||
|   setobj2s(L, L->top+2, p2);  /* 2nd argument */ |  | ||||||
|   setobj2s(L, L->top+3, p3);  /* 3th argument */ |  | ||||||
|   luaD_checkstack(L, 4); |  | ||||||
|   L->top += 4; |  | ||||||
|   luaD_call(L, L->top - 4, 0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { |  | ||||||
|   int loop; |  | ||||||
|   for (loop = 0; loop < MAXTAGLOOP; loop++) { |  | ||||||
|     const TValue *tm; |  | ||||||
|     if (ttistable(t)) {  /* `t' is a table? */ |  | ||||||
|       Table *h = hvalue(t); |  | ||||||
|       const TValue *res = luaH_get(h, key); /* do a primitive get */ |  | ||||||
|       if (!ttisnil(res) ||  /* result is no nil? */ |  | ||||||
|           (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ |  | ||||||
|         setobj2s(L, val, res); |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|       /* else will try the tag method */ |  | ||||||
|     } |  | ||||||
|     else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) |  | ||||||
|       luaG_typeerror(L, t, "index"); |  | ||||||
|     if (ttisfunction(tm)) { |  | ||||||
|       callTMres(L, val, tm, t, key); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     t = tm;  /* else repeat with `tm' */  |  | ||||||
|   } |  | ||||||
|   luaG_runerror(L, "loop in gettable"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { |  | ||||||
|   int loop; |  | ||||||
|   for (loop = 0; loop < MAXTAGLOOP; loop++) { |  | ||||||
|     const TValue *tm; |  | ||||||
|     if (ttistable(t)) {  /* `t' is a table? */ |  | ||||||
|       Table *h = hvalue(t); |  | ||||||
|       TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ |  | ||||||
|       if (!ttisnil(oldval) ||  /* result is no nil? */ |  | ||||||
|           (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ |  | ||||||
|         setobj2t(L, oldval, val); |  | ||||||
|         luaC_barriert(L, h, val); |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|       /* else will try the tag method */ |  | ||||||
|     } |  | ||||||
|     else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) |  | ||||||
|       luaG_typeerror(L, t, "index"); |  | ||||||
|     if (ttisfunction(tm)) { |  | ||||||
|       callTM(L, tm, t, key, val); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     t = tm;  /* else repeat with `tm' */  |  | ||||||
|   } |  | ||||||
|   luaG_runerror(L, "loop in settable"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, |  | ||||||
|                        StkId res, TMS event) { |  | ||||||
|   const TValue *tm = luaT_gettmbyobj(L, p1, event);  /* try first operand */ |  | ||||||
|   if (ttisnil(tm)) |  | ||||||
|     tm = luaT_gettmbyobj(L, p2, event);  /* try second operand */ |  | ||||||
|   if (!ttisfunction(tm)) return 0; |  | ||||||
|   callTMres(L, res, tm, p1, p2); |  | ||||||
|   return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, |  | ||||||
|                                   TMS event) { |  | ||||||
|   const TValue *tm1 = fasttm(L, mt1, event); |  | ||||||
|   const TValue *tm2; |  | ||||||
|   if (tm1 == NULL) return NULL;  /* no metamethod */ |  | ||||||
|   if (mt1 == mt2) return tm1;  /* same metatables => same metamethods */ |  | ||||||
|   tm2 = fasttm(L, mt2, event); |  | ||||||
|   if (tm2 == NULL) return NULL;  /* no metamethod */ |  | ||||||
|   if (luaO_rawequalObj(tm1, tm2))  /* same metamethods? */ |  | ||||||
|     return tm1; |  | ||||||
|   return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, |  | ||||||
|                          TMS event) { |  | ||||||
|   const TValue *tm1 = luaT_gettmbyobj(L, p1, event); |  | ||||||
|   const TValue *tm2; |  | ||||||
|   if (ttisnil(tm1)) return -1;  /* no metamethod? */ |  | ||||||
|   tm2 = luaT_gettmbyobj(L, p2, event); |  | ||||||
|   if (!luaO_rawequalObj(tm1, tm2))  /* different metamethods? */ |  | ||||||
|     return -1; |  | ||||||
|   callTMres(L, L->top, tm1, p1, p2); |  | ||||||
|   return !l_isfalse(L->top); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int l_strcmp (const TString *ls, const TString *rs) { |  | ||||||
|   const char *l = getstr(ls); |  | ||||||
|   size_t ll = ls->tsv.len; |  | ||||||
|   const char *r = getstr(rs); |  | ||||||
|   size_t lr = rs->tsv.len; |  | ||||||
|   for (;;) { |  | ||||||
|     int temp = strcoll(l, r); |  | ||||||
|     if (temp != 0) return temp; |  | ||||||
|     else {  /* strings are equal up to a `\0' */ |  | ||||||
|       size_t len = strlen(l);  /* index of first `\0' in both strings */ |  | ||||||
|       if (len == lr)  /* r is finished? */ |  | ||||||
|         return (len == ll) ? 0 : 1; |  | ||||||
|       else if (len == ll)  /* l is finished? */ |  | ||||||
|         return -1;  /* l is smaller than r (because r is not finished) */ |  | ||||||
|       /* both strings longer than `len'; go on comparing (after the `\0') */ |  | ||||||
|       len++; |  | ||||||
|       l += len; ll -= len; r += len; lr -= len; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { |  | ||||||
|   int res; |  | ||||||
|   if (ttype(l) != ttype(r)) |  | ||||||
|     return luaG_ordererror(L, l, r); |  | ||||||
|   else if (ttisnumber(l)) |  | ||||||
|     return luai_numlt(nvalue(l), nvalue(r)); |  | ||||||
|   else if (ttisstring(l)) |  | ||||||
|     return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; |  | ||||||
|   else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) |  | ||||||
|     return res; |  | ||||||
|   return luaG_ordererror(L, l, r); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int lessequal (lua_State *L, const TValue *l, const TValue *r) { |  | ||||||
|   int res; |  | ||||||
|   if (ttype(l) != ttype(r)) |  | ||||||
|     return luaG_ordererror(L, l, r); |  | ||||||
|   else if (ttisnumber(l)) |  | ||||||
|     return luai_numle(nvalue(l), nvalue(r)); |  | ||||||
|   else if (ttisstring(l)) |  | ||||||
|     return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; |  | ||||||
|   else if ((res = call_orderTM(L, l, r, TM_LE)) != -1)  /* first try `le' */ |  | ||||||
|     return res; |  | ||||||
|   else if ((res = call_orderTM(L, r, l, TM_LT)) != -1)  /* else try `lt' */ |  | ||||||
|     return !res; |  | ||||||
|   return luaG_ordererror(L, l, r); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { |  | ||||||
|   const TValue *tm; |  | ||||||
|   lua_assert(ttype(t1) == ttype(t2)); |  | ||||||
|   switch (ttype(t1)) { |  | ||||||
|     case LUA_TNIL: return 1; |  | ||||||
|     case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); |  | ||||||
|     case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2);  /* true must be 1 !! */ |  | ||||||
|     case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); |  | ||||||
|     case LUA_TUSERDATA: { |  | ||||||
|       if (uvalue(t1) == uvalue(t2)) return 1; |  | ||||||
|       tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, |  | ||||||
|                          TM_EQ); |  | ||||||
|       break;  /* will try TM */ |  | ||||||
|     } |  | ||||||
|     case LUA_TTABLE: { |  | ||||||
|       if (hvalue(t1) == hvalue(t2)) return 1; |  | ||||||
|       tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); |  | ||||||
|       break;  /* will try TM */ |  | ||||||
|     } |  | ||||||
|     default: return gcvalue(t1) == gcvalue(t2); |  | ||||||
|   } |  | ||||||
|   if (tm == NULL) return 0;  /* no TM? */ |  | ||||||
|   callTMres(L, L->top, tm, t1, t2);  /* call TM */ |  | ||||||
|   return !l_isfalse(L->top); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaV_concat (lua_State *L, int total, int last) { |  | ||||||
|   do { |  | ||||||
|     StkId top = L->base + last + 1; |  | ||||||
|     int n = 2;  /* number of elements handled in this pass (at least 2) */ |  | ||||||
|     if (!tostring(L, top-2) || !tostring(L, top-1)) { |  | ||||||
|       if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) |  | ||||||
|         luaG_concaterror(L, top-2, top-1); |  | ||||||
|     } else if (tsvalue(top-1)->len > 0) {  /* if len=0, do nothing */ |  | ||||||
|       /* at least two string values; get as many as possible */ |  | ||||||
|       size_t tl = tsvalue(top-1)->len; |  | ||||||
|       char *buffer; |  | ||||||
|       int i; |  | ||||||
|       /* collect total length */ |  | ||||||
|       for (n = 1; n < total && tostring(L, top-n-1); n++) { |  | ||||||
|         size_t l = tsvalue(top-n-1)->len; |  | ||||||
|         if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); |  | ||||||
|         tl += l; |  | ||||||
|       } |  | ||||||
|       buffer = luaZ_openspace(L, &G(L)->buff, tl); |  | ||||||
|       tl = 0; |  | ||||||
|       for (i=n; i>0; i--) {  /* concat all strings */ |  | ||||||
|         size_t l = tsvalue(top-i)->len; |  | ||||||
|         memcpy(buffer+tl, svalue(top-i), l); |  | ||||||
|         tl += l; |  | ||||||
|       } |  | ||||||
|       setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); |  | ||||||
|     } |  | ||||||
|     total -= n-1;  /* got `n' strings to create 1 new */ |  | ||||||
|     last -= n-1; |  | ||||||
|   } while (total > 1);  /* repeat until only 1 result left */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void Arith (lua_State *L, StkId ra, const TValue *rb, |  | ||||||
|                    const TValue *rc, TMS op) { |  | ||||||
|   TValue tempb, tempc; |  | ||||||
|   const TValue *b, *c; |  | ||||||
|   if ((b = luaV_tonumber(rb, &tempb)) != NULL && |  | ||||||
|       (c = luaV_tonumber(rc, &tempc)) != NULL) { |  | ||||||
|     lua_Number nb = nvalue(b), nc = nvalue(c); |  | ||||||
|     switch (op) { |  | ||||||
|       case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; |  | ||||||
|       case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; |  | ||||||
|       case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; |  | ||||||
|       case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; |  | ||||||
|       case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; |  | ||||||
|       case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; |  | ||||||
|       case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; |  | ||||||
|       default: lua_assert(0); break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   else if (!call_binTM(L, rb, rc, ra, op)) |  | ||||||
|     luaG_aritherror(L, rb, rc); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** some macros for common tasks in `luaV_execute' |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #define runtime_check(L, c)	{ if (!(c)) break; } |  | ||||||
|  |  | ||||||
| #define RA(i)	(base+GETARG_A(i)) |  | ||||||
| /* to be used after possible stack reallocation */ |  | ||||||
| #define RB(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) |  | ||||||
| #define RC(i)	check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) |  | ||||||
| #define RKB(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ |  | ||||||
| 	ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) |  | ||||||
| #define RKC(i)	check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ |  | ||||||
| 	ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) |  | ||||||
| #define KBx(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define dojump(L,pc,i)	{(pc) += (i); luai_threadyield(L);} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define Protect(x)	{ L->savedpc = pc; {x;}; base = L->base; } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define arith_op(op,tm) { \ |  | ||||||
|         TValue *rb = RKB(i); \ |  | ||||||
|         TValue *rc = RKC(i); \ |  | ||||||
|         if (ttisnumber(rb) && ttisnumber(rc)) { \ |  | ||||||
|           lua_Number nb = nvalue(rb), nc = nvalue(rc); \ |  | ||||||
|           setnvalue(ra, op(nb, nc)); \ |  | ||||||
|         } \ |  | ||||||
|         else \ |  | ||||||
|           Protect(Arith(L, ra, rb, rc, tm)); \ |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaV_execute (lua_State *L, int nexeccalls) { |  | ||||||
|   LClosure *cl; |  | ||||||
|   StkId base; |  | ||||||
|   TValue *k; |  | ||||||
|   const Instruction *pc; |  | ||||||
|  reentry:  /* entry point */ |  | ||||||
|   pc = L->savedpc; |  | ||||||
|   cl = &clvalue(L->ci->func)->l; |  | ||||||
|   base = L->base; |  | ||||||
|   k = cl->p->k; |  | ||||||
|   /* main loop of interpreter */ |  | ||||||
|   for (;;) { |  | ||||||
|     const Instruction i = *pc++; |  | ||||||
|     StkId ra; |  | ||||||
|     if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && |  | ||||||
|         (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { |  | ||||||
|       traceexec(L, pc); |  | ||||||
|       if (L->status == LUA_YIELD) {  /* did hook yield? */ |  | ||||||
|         L->savedpc = pc - 1; |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|       base = L->base; |  | ||||||
|     } |  | ||||||
|     /* warning!! several calls may realloc the stack and invalidate `ra' */ |  | ||||||
|     ra = RA(i); |  | ||||||
|     lua_assert(base == L->base && L->base == L->ci->base); |  | ||||||
|     lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); |  | ||||||
|     lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); |  | ||||||
|     switch (GET_OPCODE(i)) { |  | ||||||
|       case OP_MOVE: { |  | ||||||
|         setobjs2s(L, ra, RB(i)); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_LOADK: { |  | ||||||
|         setobj2s(L, ra, KBx(i)); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_LOADBOOL: { |  | ||||||
|         setbvalue(ra, GETARG_B(i)); |  | ||||||
|         if (GETARG_C(i)) pc++;  /* skip next instruction (if C) */ |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_LOADNIL: { |  | ||||||
|         TValue *rb = RB(i); |  | ||||||
|         do { |  | ||||||
|           setnilvalue(rb--); |  | ||||||
|         } while (rb >= ra); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_GETUPVAL: { |  | ||||||
|         int b = GETARG_B(i); |  | ||||||
|         setobj2s(L, ra, cl->upvals[b]->v); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_GETGLOBAL: { |  | ||||||
|         TValue g; |  | ||||||
|         TValue *rb = KBx(i); |  | ||||||
|         sethvalue(L, &g, cl->env); |  | ||||||
|         lua_assert(ttisstring(rb)); |  | ||||||
|         Protect(luaV_gettable(L, &g, rb, ra)); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_GETTABLE: { |  | ||||||
|         Protect(luaV_gettable(L, RB(i), RKC(i), ra)); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_SETGLOBAL: { |  | ||||||
|         TValue g; |  | ||||||
|         sethvalue(L, &g, cl->env); |  | ||||||
|         lua_assert(ttisstring(KBx(i))); |  | ||||||
|         Protect(luaV_settable(L, &g, KBx(i), ra)); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_SETUPVAL: { |  | ||||||
|         UpVal *uv = cl->upvals[GETARG_B(i)]; |  | ||||||
|         setobj(L, uv->v, ra); |  | ||||||
|         luaC_barrier(L, uv, ra); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_SETTABLE: { |  | ||||||
|         Protect(luaV_settable(L, ra, RKB(i), RKC(i))); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_NEWTABLE: { |  | ||||||
|         int b = GETARG_B(i); |  | ||||||
|         int c = GETARG_C(i); |  | ||||||
|         sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); |  | ||||||
|         Protect(luaC_checkGC(L)); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_SELF: { |  | ||||||
|         StkId rb = RB(i); |  | ||||||
|         setobjs2s(L, ra+1, rb); |  | ||||||
|         Protect(luaV_gettable(L, rb, RKC(i), ra)); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_ADD: { |  | ||||||
|         arith_op(luai_numadd, TM_ADD); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_SUB: { |  | ||||||
|         arith_op(luai_numsub, TM_SUB); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_MUL: { |  | ||||||
|         arith_op(luai_nummul, TM_MUL); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_DIV: { |  | ||||||
|         arith_op(luai_numdiv, TM_DIV); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_MOD: { |  | ||||||
|         arith_op(luai_nummod, TM_MOD); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_POW: { |  | ||||||
|         arith_op(luai_numpow, TM_POW); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_UNM: { |  | ||||||
|         TValue *rb = RB(i); |  | ||||||
|         if (ttisnumber(rb)) { |  | ||||||
|           lua_Number nb = nvalue(rb); |  | ||||||
|           setnvalue(ra, luai_numunm(nb)); |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|           Protect(Arith(L, ra, rb, rb, TM_UNM)); |  | ||||||
|         } |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_NOT: { |  | ||||||
|         int res = l_isfalse(RB(i));  /* next assignment may change this value */ |  | ||||||
|         setbvalue(ra, res); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_LEN: { |  | ||||||
|         const TValue *rb = RB(i); |  | ||||||
|         switch (ttype(rb)) { |  | ||||||
|           case LUA_TTABLE: { |  | ||||||
|             setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); |  | ||||||
|             break; |  | ||||||
|           } |  | ||||||
|           case LUA_TSTRING: { |  | ||||||
|             setnvalue(ra, cast_num(tsvalue(rb)->len)); |  | ||||||
|             break; |  | ||||||
|           } |  | ||||||
|           default: {  /* try metamethod */ |  | ||||||
|             Protect( |  | ||||||
|               if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) |  | ||||||
|                 luaG_typeerror(L, rb, "get length of"); |  | ||||||
|             ) |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_CONCAT: { |  | ||||||
|         int b = GETARG_B(i); |  | ||||||
|         int c = GETARG_C(i); |  | ||||||
|         Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); |  | ||||||
|         setobjs2s(L, RA(i), base+b); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_JMP: { |  | ||||||
|         dojump(L, pc, GETARG_sBx(i)); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_EQ: { |  | ||||||
|         TValue *rb = RKB(i); |  | ||||||
|         TValue *rc = RKC(i); |  | ||||||
|         Protect( |  | ||||||
|           if (equalobj(L, rb, rc) == GETARG_A(i)) |  | ||||||
|             dojump(L, pc, GETARG_sBx(*pc)); |  | ||||||
|         ) |  | ||||||
|         pc++; |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_LT: { |  | ||||||
|         Protect( |  | ||||||
|           if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) |  | ||||||
|             dojump(L, pc, GETARG_sBx(*pc)); |  | ||||||
|         ) |  | ||||||
|         pc++; |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_LE: { |  | ||||||
|         Protect( |  | ||||||
|           if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) |  | ||||||
|             dojump(L, pc, GETARG_sBx(*pc)); |  | ||||||
|         ) |  | ||||||
|         pc++; |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_TEST: { |  | ||||||
|         if (l_isfalse(ra) != GETARG_C(i)) |  | ||||||
|           dojump(L, pc, GETARG_sBx(*pc)); |  | ||||||
|         pc++; |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_TESTSET: { |  | ||||||
|         TValue *rb = RB(i); |  | ||||||
|         if (l_isfalse(rb) != GETARG_C(i)) { |  | ||||||
|           setobjs2s(L, ra, rb); |  | ||||||
|           dojump(L, pc, GETARG_sBx(*pc)); |  | ||||||
|         } |  | ||||||
|         pc++; |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_CALL: { |  | ||||||
|         int b = GETARG_B(i); |  | ||||||
|         int nresults = GETARG_C(i) - 1; |  | ||||||
|         if (b != 0) L->top = ra+b;  /* else previous instruction set top */ |  | ||||||
|         L->savedpc = pc; |  | ||||||
|         switch (luaD_precall(L, ra, nresults)) { |  | ||||||
|           case PCRLUA: { |  | ||||||
|             nexeccalls++; |  | ||||||
|             goto reentry;  /* restart luaV_execute over new Lua function */ |  | ||||||
|           } |  | ||||||
|           case PCRC: { |  | ||||||
|             /* it was a C function (`precall' called it); adjust results */ |  | ||||||
|             if (nresults >= 0) L->top = L->ci->top; |  | ||||||
|             base = L->base; |  | ||||||
|             continue; |  | ||||||
|           } |  | ||||||
|           default: { |  | ||||||
|             return;  /* yield */ |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       case OP_TAILCALL: { |  | ||||||
|         int b = GETARG_B(i); |  | ||||||
|         if (b != 0) L->top = ra+b;  /* else previous instruction set top */ |  | ||||||
|         L->savedpc = pc; |  | ||||||
|         lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); |  | ||||||
|         switch (luaD_precall(L, ra, LUA_MULTRET)) { |  | ||||||
|           case PCRLUA: { |  | ||||||
|             /* tail call: put new frame in place of previous one */ |  | ||||||
|             CallInfo *ci = L->ci - 1;  /* previous frame */ |  | ||||||
|             int aux; |  | ||||||
|             StkId func = ci->func; |  | ||||||
|             StkId pfunc = (ci+1)->func;  /* previous function index */ |  | ||||||
|             if (L->openupval) luaF_close(L, ci->base); |  | ||||||
|             L->base = ci->base = ci->func + ((ci+1)->base - pfunc); |  | ||||||
|             for (aux = 0; pfunc+aux < L->top; aux++)  /* move frame down */ |  | ||||||
|               setobjs2s(L, func+aux, pfunc+aux); |  | ||||||
|             ci->top = L->top = func+aux;  /* correct top */ |  | ||||||
|             lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); |  | ||||||
|             ci->savedpc = L->savedpc; |  | ||||||
|             ci->tailcalls++;  /* one more call lost */ |  | ||||||
|             L->ci--;  /* remove new frame */ |  | ||||||
|             goto reentry; |  | ||||||
|           } |  | ||||||
|           case PCRC: {  /* it was a C function (`precall' called it) */ |  | ||||||
|             base = L->base; |  | ||||||
|             continue; |  | ||||||
|           } |  | ||||||
|           default: { |  | ||||||
|             return;  /* yield */ |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       case OP_RETURN: { |  | ||||||
|         int b = GETARG_B(i); |  | ||||||
|         if (b != 0) L->top = ra+b-1; |  | ||||||
|         if (L->openupval) luaF_close(L, base); |  | ||||||
|         L->savedpc = pc; |  | ||||||
|         b = luaD_poscall(L, ra); |  | ||||||
|         if (--nexeccalls == 0)  /* was previous function running `here'? */ |  | ||||||
|           return;  /* no: return */ |  | ||||||
|         else {  /* yes: continue its execution */ |  | ||||||
|           if (b) L->top = L->ci->top; |  | ||||||
|           lua_assert(isLua(L->ci)); |  | ||||||
|           lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL); |  | ||||||
|           goto reentry; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       case OP_FORLOOP: { |  | ||||||
|         lua_Number step = nvalue(ra+2); |  | ||||||
|         lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ |  | ||||||
|         lua_Number limit = nvalue(ra+1); |  | ||||||
|         if (luai_numlt(0, step) ? luai_numle(idx, limit) |  | ||||||
|                                 : luai_numle(limit, idx)) { |  | ||||||
|           dojump(L, pc, GETARG_sBx(i));  /* jump back */ |  | ||||||
|           setnvalue(ra, idx);  /* update internal index... */ |  | ||||||
|           setnvalue(ra+3, idx);  /* ...and external index */ |  | ||||||
|         } |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_FORPREP: { |  | ||||||
|         const TValue *init = ra; |  | ||||||
|         const TValue *plimit = ra+1; |  | ||||||
|         const TValue *pstep = ra+2; |  | ||||||
|         L->savedpc = pc;  /* next steps may throw errors */ |  | ||||||
|         if (!tonumber(init, ra)) |  | ||||||
|           luaG_runerror(L, LUA_QL("for") " initial value must be a number"); |  | ||||||
|         else if (!tonumber(plimit, ra+1)) |  | ||||||
|           luaG_runerror(L, LUA_QL("for") " limit must be a number"); |  | ||||||
|         else if (!tonumber(pstep, ra+2)) |  | ||||||
|           luaG_runerror(L, LUA_QL("for") " step must be a number"); |  | ||||||
|         setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); |  | ||||||
|         dojump(L, pc, GETARG_sBx(i)); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_TFORLOOP: { |  | ||||||
|         StkId cb = ra + 3;  /* call base */ |  | ||||||
|         setobjs2s(L, cb+2, ra+2); |  | ||||||
|         setobjs2s(L, cb+1, ra+1); |  | ||||||
|         setobjs2s(L, cb, ra); |  | ||||||
|         L->top = cb+3;  /* func. + 2 args (state and index) */ |  | ||||||
|         Protect(luaD_call(L, cb, GETARG_C(i))); |  | ||||||
|         L->top = L->ci->top; |  | ||||||
|         cb = RA(i) + 3;  /* previous call may change the stack */ |  | ||||||
|         if (!ttisnil(cb)) {  /* continue loop? */ |  | ||||||
|           setobjs2s(L, cb-1, cb);  /* save control variable */ |  | ||||||
|           dojump(L, pc, GETARG_sBx(*pc));  /* jump back */ |  | ||||||
|         } |  | ||||||
|         pc++; |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_SETLIST: { |  | ||||||
|         int n = GETARG_B(i); |  | ||||||
|         int c = GETARG_C(i); |  | ||||||
|         int last; |  | ||||||
|         Table *h; |  | ||||||
|         if (n == 0) { |  | ||||||
|           n = cast_int(L->top - ra) - 1; |  | ||||||
|           L->top = L->ci->top; |  | ||||||
|         } |  | ||||||
|         if (c == 0) c = cast_int(*pc++); |  | ||||||
|         runtime_check(L, ttistable(ra)); |  | ||||||
|         h = hvalue(ra); |  | ||||||
|         last = ((c-1)*LFIELDS_PER_FLUSH) + n; |  | ||||||
|         if (last > h->sizearray)  /* needs more space? */ |  | ||||||
|           luaH_resizearray(L, h, last);  /* pre-alloc it at once */ |  | ||||||
|         for (; n > 0; n--) { |  | ||||||
|           TValue *val = ra+n; |  | ||||||
|           setobj2t(L, luaH_setnum(L, h, last--), val); |  | ||||||
|           luaC_barriert(L, h, val); |  | ||||||
|         } |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_CLOSE: { |  | ||||||
|         luaF_close(L, ra); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_CLOSURE: { |  | ||||||
|         Proto *p; |  | ||||||
|         Closure *ncl; |  | ||||||
|         int nup, j; |  | ||||||
|         p = cl->p->p[GETARG_Bx(i)]; |  | ||||||
|         nup = p->nups; |  | ||||||
|         ncl = luaF_newLclosure(L, nup, cl->env); |  | ||||||
|         ncl->l.p = p; |  | ||||||
|         for (j=0; j<nup; j++, pc++) { |  | ||||||
|           if (GET_OPCODE(*pc) == OP_GETUPVAL) |  | ||||||
|             ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)]; |  | ||||||
|           else { |  | ||||||
|             lua_assert(GET_OPCODE(*pc) == OP_MOVE); |  | ||||||
|             ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         setclvalue(L, ra, ncl); |  | ||||||
|         Protect(luaC_checkGC(L)); |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|       case OP_VARARG: { |  | ||||||
|         int b = GETARG_B(i) - 1; |  | ||||||
|         int j; |  | ||||||
|         CallInfo *ci = L->ci; |  | ||||||
|         int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1; |  | ||||||
|         if (b == LUA_MULTRET) { |  | ||||||
|           Protect(luaD_checkstack(L, n)); |  | ||||||
|           ra = RA(i);  /* previous call may change the stack */ |  | ||||||
|           b = n; |  | ||||||
|           L->top = ra + n; |  | ||||||
|         } |  | ||||||
|         for (j = 0; j < b; j++) { |  | ||||||
|           if (j < n) { |  | ||||||
|             setobjs2s(L, ra + j, ci->base - n + j); |  | ||||||
|           } |  | ||||||
|           else { |  | ||||||
|             setnilvalue(ra + j); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,36 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lvm.h,v 2.5 2005/08/22 18:54:49 roberto Exp $ |  | ||||||
| ** Lua virtual machine |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef lvm_h |  | ||||||
| #define lvm_h |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "ldo.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "ltm.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o))) |  | ||||||
|  |  | ||||||
| #define tonumber(o,n)	(ttype(o) == LUA_TNUMBER || \ |  | ||||||
|                          (((o) = luaV_tonumber(o,n)) != NULL)) |  | ||||||
|  |  | ||||||
| #define equalobj(L,o1,o2) \ |  | ||||||
| 	(ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); |  | ||||||
| LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); |  | ||||||
| LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n); |  | ||||||
| LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj); |  | ||||||
| LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key, |  | ||||||
|                                             StkId val); |  | ||||||
| LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key, |  | ||||||
|                                             StkId val); |  | ||||||
| LUAI_FUNC void luaV_execute (lua_State *L, int nexeccalls); |  | ||||||
| LUAI_FUNC void luaV_concat (lua_State *L, int total, int last); |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,82 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lzio.c,v 1.31 2005/06/03 20:15:29 roberto Exp $ |  | ||||||
| ** a generic input stream interface |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #define lzio_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "llimits.h" |  | ||||||
| #include "lmem.h" |  | ||||||
| #include "lstate.h" |  | ||||||
| #include "lzio.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaZ_fill (ZIO *z) { |  | ||||||
|   size_t size; |  | ||||||
|   lua_State *L = z->L; |  | ||||||
|   const char *buff; |  | ||||||
|   lua_unlock(L); |  | ||||||
|   buff = z->reader(L, z->data, &size); |  | ||||||
|   lua_lock(L); |  | ||||||
|   if (buff == NULL || size == 0) return EOZ; |  | ||||||
|   z->n = size - 1; |  | ||||||
|   z->p = buff; |  | ||||||
|   return char2int(*(z->p++)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int luaZ_lookahead (ZIO *z) { |  | ||||||
|   if (z->n == 0) { |  | ||||||
|     if (luaZ_fill(z) == EOZ) |  | ||||||
|       return EOZ; |  | ||||||
|     else { |  | ||||||
|       z->n++;  /* luaZ_fill removed first byte; put back it */ |  | ||||||
|       z->p--; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return char2int(*z->p); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { |  | ||||||
|   z->L = L; |  | ||||||
|   z->reader = reader; |  | ||||||
|   z->data = data; |  | ||||||
|   z->n = 0; |  | ||||||
|   z->p = NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* --------------------------------------------------------------- read --- */ |  | ||||||
| size_t luaZ_read (ZIO *z, void *b, size_t n) { |  | ||||||
|   while (n) { |  | ||||||
|     size_t m; |  | ||||||
|     if (luaZ_lookahead(z) == EOZ) |  | ||||||
|       return n;  /* return number of missing bytes */ |  | ||||||
|     m = (n <= z->n) ? n : z->n;  /* min. between n and z->n */ |  | ||||||
|     memcpy(b, z->p, m); |  | ||||||
|     z->n -= m; |  | ||||||
|     z->p += m; |  | ||||||
|     b = (char *)b + m; |  | ||||||
|     n -= m; |  | ||||||
|   } |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* ------------------------------------------------------------------------ */ |  | ||||||
| char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { |  | ||||||
|   if (n > buff->buffsize) { |  | ||||||
|     if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; |  | ||||||
|     luaZ_resizebuffer(L, buff, n); |  | ||||||
|   } |  | ||||||
|   return buff->buffer; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,67 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: lzio.h,v 1.21 2005/05/17 19:49:15 roberto Exp $ |  | ||||||
| ** Buffered streams |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifndef lzio_h |  | ||||||
| #define lzio_h |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "lmem.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define EOZ	(-1)			/* end of stream */ |  | ||||||
|  |  | ||||||
| typedef struct Zio ZIO; |  | ||||||
|  |  | ||||||
| #define char2int(c)	cast(int, cast(unsigned char, (c))) |  | ||||||
|  |  | ||||||
| #define zgetc(z)  (((z)->n--)>0 ?  char2int(*(z)->p++) : luaZ_fill(z)) |  | ||||||
|  |  | ||||||
| typedef struct Mbuffer { |  | ||||||
|   char *buffer; |  | ||||||
|   size_t n; |  | ||||||
|   size_t buffsize; |  | ||||||
| } Mbuffer; |  | ||||||
|  |  | ||||||
| #define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) |  | ||||||
|  |  | ||||||
| #define luaZ_buffer(buff)	((buff)->buffer) |  | ||||||
| #define luaZ_sizebuffer(buff)	((buff)->buffsize) |  | ||||||
| #define luaZ_bufflen(buff)	((buff)->n) |  | ||||||
|  |  | ||||||
| #define luaZ_resetbuffer(buff) ((buff)->n = 0) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define luaZ_resizebuffer(L, buff, size) \ |  | ||||||
| 	(luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \ |  | ||||||
| 	(buff)->buffsize = size) |  | ||||||
|  |  | ||||||
| #define luaZ_freebuffer(L, buff)	luaZ_resizebuffer(L, buff, 0) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); |  | ||||||
| LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, |  | ||||||
|                                         void *data); |  | ||||||
| LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n);	/* read next n bytes */ |  | ||||||
| LUAI_FUNC int luaZ_lookahead (ZIO *z); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* --------- Private Part ------------------ */ |  | ||||||
|  |  | ||||||
| struct Zio { |  | ||||||
|   size_t n;			/* bytes still unread */ |  | ||||||
|   const char *p;		/* current position in buffer */ |  | ||||||
|   lua_Reader reader; |  | ||||||
|   void* data;			/* additional data */ |  | ||||||
|   lua_State *L;			/* Lua state (for reader) */ |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| LUAI_FUNC int luaZ_fill (ZIO *z); |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
							
								
								
									
										224
									
								
								src/lua/print.c
									
									
									
									
									
								
							
							
						
						
									
										224
									
								
								src/lua/print.c
									
									
									
									
									
								
							| @@ -1,224 +0,0 @@ | |||||||
| /* |  | ||||||
| ** $Id: print.c,v 1.54 2006/01/11 22:49:27 lhf Exp $ |  | ||||||
| ** print bytecodes |  | ||||||
| ** See Copyright Notice in lua.h |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #include <ctype.h> |  | ||||||
| #include <stdio.h> |  | ||||||
|  |  | ||||||
| #define luac_c |  | ||||||
| #define LUA_CORE |  | ||||||
|  |  | ||||||
| #include "ldebug.h" |  | ||||||
| #include "lobject.h" |  | ||||||
| #include "lopcodes.h" |  | ||||||
| #include "lundump.h" |  | ||||||
|  |  | ||||||
| #define PrintFunction	luaU_print |  | ||||||
|  |  | ||||||
| #define Sizeof(x)	((int)sizeof(x)) |  | ||||||
| #define VOID(p)		((const void*)(p)) |  | ||||||
|  |  | ||||||
| static void PrintString(const Proto* f, int n) |  | ||||||
| { |  | ||||||
|  const char* s=svalue(&f->k[n]); |  | ||||||
|  putchar('"'); |  | ||||||
|  for (; *s; s++) |  | ||||||
|  { |  | ||||||
|   switch (*s) |  | ||||||
|   { |  | ||||||
|    case '"': printf("\\\""); break; |  | ||||||
|    case '\a': printf("\\a"); break; |  | ||||||
|    case '\b': printf("\\b"); break; |  | ||||||
|    case '\f': printf("\\f"); break; |  | ||||||
|    case '\n': printf("\\n"); break; |  | ||||||
|    case '\r': printf("\\r"); break; |  | ||||||
|    case '\t': printf("\\t"); break; |  | ||||||
|    case '\v': printf("\\v"); break; |  | ||||||
|    default:	if (isprint((unsigned char)*s)) |  | ||||||
|    			printf("%c",*s); |  | ||||||
| 		else |  | ||||||
| 			printf("\\%03u",(unsigned char)*s); |  | ||||||
|   } |  | ||||||
|  } |  | ||||||
|  putchar('"'); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void PrintConstant(const Proto* f, int i) |  | ||||||
| { |  | ||||||
|  const TValue* o=&f->k[i]; |  | ||||||
|  switch (ttype(o)) |  | ||||||
|  { |  | ||||||
|   case LUA_TNIL: |  | ||||||
| 	printf("nil"); |  | ||||||
| 	break; |  | ||||||
|   case LUA_TBOOLEAN: |  | ||||||
| 	printf(bvalue(o) ? "true" : "false"); |  | ||||||
| 	break; |  | ||||||
|   case LUA_TNUMBER: |  | ||||||
| 	printf(LUA_NUMBER_FMT,nvalue(o)); |  | ||||||
| 	break; |  | ||||||
|   case LUA_TSTRING: |  | ||||||
| 	PrintString(f,i); |  | ||||||
| 	break; |  | ||||||
|   default:				/* cannot happen */ |  | ||||||
| 	printf("? type=%d",ttype(o)); |  | ||||||
| 	break; |  | ||||||
|  } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void PrintCode(const Proto* f) |  | ||||||
| { |  | ||||||
|  const Instruction* code=f->code; |  | ||||||
|  int pc,n=f->sizecode; |  | ||||||
|  for (pc=0; pc<n; pc++) |  | ||||||
|  { |  | ||||||
|   Instruction i=code[pc]; |  | ||||||
|   OpCode o=GET_OPCODE(i); |  | ||||||
|   int a=GETARG_A(i); |  | ||||||
|   int b=GETARG_B(i); |  | ||||||
|   int c=GETARG_C(i); |  | ||||||
|   int bx=GETARG_Bx(i); |  | ||||||
|   int sbx=GETARG_sBx(i); |  | ||||||
|   int line=getline(f,pc); |  | ||||||
|   printf("\t%d\t",pc+1); |  | ||||||
|   if (line>0) printf("[%d]\t",line); else printf("[-]\t"); |  | ||||||
|   printf("%-9s\t",luaP_opnames[o]); |  | ||||||
|   switch (getOpMode(o)) |  | ||||||
|   { |  | ||||||
|    case iABC: |  | ||||||
|     printf("%d",a); |  | ||||||
|     if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (-1-INDEXK(b)) : b); |  | ||||||
|     if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c); |  | ||||||
|     break; |  | ||||||
|    case iABx: |  | ||||||
|     if (getBMode(o)==OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx); |  | ||||||
|     break; |  | ||||||
|    case iAsBx: |  | ||||||
|     if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); |  | ||||||
|     break; |  | ||||||
|   } |  | ||||||
|   switch (o) |  | ||||||
|   { |  | ||||||
|    case OP_LOADK: |  | ||||||
|     printf("\t; "); PrintConstant(f,bx); |  | ||||||
|     break; |  | ||||||
|    case OP_GETUPVAL: |  | ||||||
|    case OP_SETUPVAL: |  | ||||||
|     printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b]) : "-"); |  | ||||||
|     break; |  | ||||||
|    case OP_GETGLOBAL: |  | ||||||
|    case OP_SETGLOBAL: |  | ||||||
|     printf("\t; %s",svalue(&f->k[bx])); |  | ||||||
|     break; |  | ||||||
|    case OP_GETTABLE: |  | ||||||
|    case OP_SELF: |  | ||||||
|     if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); } |  | ||||||
|     break; |  | ||||||
|    case OP_SETTABLE: |  | ||||||
|    case OP_ADD: |  | ||||||
|    case OP_SUB: |  | ||||||
|    case OP_MUL: |  | ||||||
|    case OP_DIV: |  | ||||||
|    case OP_POW: |  | ||||||
|    case OP_EQ: |  | ||||||
|    case OP_LT: |  | ||||||
|    case OP_LE: |  | ||||||
|     if (ISK(b) || ISK(c)) |  | ||||||
|     { |  | ||||||
|      printf("\t; "); |  | ||||||
|      if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-"); |  | ||||||
|      printf(" "); |  | ||||||
|      if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-"); |  | ||||||
|     } |  | ||||||
|     break; |  | ||||||
|    case OP_JMP: |  | ||||||
|    case OP_FORLOOP: |  | ||||||
|    case OP_FORPREP: |  | ||||||
|     printf("\t; to %d",sbx+pc+2); |  | ||||||
|     break; |  | ||||||
|    case OP_CLOSURE: |  | ||||||
|     printf("\t; %p",VOID(f->p[bx])); |  | ||||||
|     break; |  | ||||||
|    case OP_SETLIST: |  | ||||||
|     if (c==0) printf("\t; %d",(int)code[++pc]); |  | ||||||
|     else printf("\t; %d",c); |  | ||||||
|     break; |  | ||||||
|    default: |  | ||||||
|     break; |  | ||||||
|   } |  | ||||||
|   printf("\n"); |  | ||||||
|  } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #define SS(x)	(x==1)?"":"s" |  | ||||||
| #define S(x)	x,SS(x) |  | ||||||
|  |  | ||||||
| static void PrintHeader(const Proto* f) |  | ||||||
| { |  | ||||||
|  const char* s=getstr(f->source); |  | ||||||
|  if (*s=='@' || *s=='=') |  | ||||||
|   s++; |  | ||||||
|  else if (*s==LUA_SIGNATURE[0]) |  | ||||||
|   s="(bstring)"; |  | ||||||
|  else |  | ||||||
|   s="(string)"; |  | ||||||
|  printf("\n%s <%s:%d,%d> (%d instruction%s, %d bytes at %p)\n", |  | ||||||
|  	(f->linedefined==0)?"main":"function",s, |  | ||||||
| 	f->linedefined,f->lastlinedefined, |  | ||||||
| 	S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f)); |  | ||||||
|  printf("%d%s param%s, %d slot%s, %d upvalue%s, ", |  | ||||||
| 	f->numparams,f->is_vararg?"+":"",SS(f->numparams), |  | ||||||
| 	S(f->maxstacksize),S(f->nups)); |  | ||||||
|  printf("%d local%s, %d constant%s, %d function%s\n", |  | ||||||
| 	S(f->sizelocvars),S(f->sizek),S(f->sizep)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void PrintConstants(const Proto* f) |  | ||||||
| { |  | ||||||
|  int i,n=f->sizek; |  | ||||||
|  printf("constants (%d) for %p:\n",n,VOID(f)); |  | ||||||
|  for (i=0; i<n; i++) |  | ||||||
|  { |  | ||||||
|   printf("\t%d\t",i+1); |  | ||||||
|   PrintConstant(f,i); |  | ||||||
|   printf("\n"); |  | ||||||
|  } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void PrintLocals(const Proto* f) |  | ||||||
| { |  | ||||||
|  int i,n=f->sizelocvars; |  | ||||||
|  printf("locals (%d) for %p:\n",n,VOID(f)); |  | ||||||
|  for (i=0; i<n; i++) |  | ||||||
|  { |  | ||||||
|   printf("\t%d\t%s\t%d\t%d\n", |  | ||||||
|   i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); |  | ||||||
|  } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void PrintUpvalues(const Proto* f) |  | ||||||
| { |  | ||||||
|  int i,n=f->sizeupvalues; |  | ||||||
|  printf("upvalues (%d) for %p:\n",n,VOID(f)); |  | ||||||
|  if (f->upvalues==NULL) return; |  | ||||||
|  for (i=0; i<n; i++) |  | ||||||
|  { |  | ||||||
|   printf("\t%d\t%s\n",i,getstr(f->upvalues[i])); |  | ||||||
|  } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void PrintFunction(const Proto* f, int full) |  | ||||||
| { |  | ||||||
|  int i,n=f->sizep; |  | ||||||
|  PrintHeader(f); |  | ||||||
|  PrintCode(f); |  | ||||||
|  if (full) |  | ||||||
|  { |  | ||||||
|   PrintConstants(f); |  | ||||||
|   PrintLocals(f); |  | ||||||
|   PrintUpvalues(f); |  | ||||||
|  } |  | ||||||
|  for (i=0; i<n; i++) PrintFunction(f->p[i],full); |  | ||||||
| } |  | ||||||
| @@ -1,20 +0,0 @@ | |||||||
| LuaSocket 2.0 license |  | ||||||
| Copyright <20> 2004-2005 Diego Nehab |  | ||||||
|  |  | ||||||
| Permission is hereby granted, free of charge, to any person obtaining a |  | ||||||
| copy of this software and associated documentation files (the "Software"), |  | ||||||
| to deal in the Software without restriction, including without limitation |  | ||||||
| the rights to use, copy, modify, merge, publish, distribute, sublicense, |  | ||||||
| and/or sell copies of the Software, and to permit persons to whom the |  | ||||||
| Software is furnished to do so, subject to the following conditions: |  | ||||||
|  |  | ||||||
| The above copyright notice and this permission notice shall be included in |  | ||||||
| all copies or substantial portions of the Software. |  | ||||||
|  |  | ||||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |  | ||||||
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |  | ||||||
| DEALINGS IN THE SOFTWARE. |  | ||||||
| @@ -1,149 +0,0 @@ | |||||||
| /*=========================================================================*\ |  | ||||||
| * Auxiliar routines for class hierarchy manipulation |  | ||||||
| * LuaSocket toolkit |  | ||||||
| * |  | ||||||
| * RCS ID: $Id: auxiliar.c,v 1.14 2005/10/07 04:40:59 diego Exp $ |  | ||||||
| \*=========================================================================*/ |  | ||||||
| #include <string.h> |  | ||||||
| #include <stdio.h> |  | ||||||
|  |  | ||||||
| #include "auxiliar.h" |  | ||||||
|  |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Exported functions |  | ||||||
| \*=========================================================================*/ |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Initializes the module |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| int auxiliar_open(lua_State *L) { |  | ||||||
|     (void) L; |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Creates a new class with given methods |  | ||||||
| * Methods whose names start with __ are passed directly to the metatable. |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| void auxiliar_newclass(lua_State *L, const char *classname, luaL_reg *func) { |  | ||||||
|     luaL_newmetatable(L, classname); /* mt */ |  | ||||||
|     /* create __index table to place methods */ |  | ||||||
|     lua_pushstring(L, "__index");    /* mt,"__index" */ |  | ||||||
|     lua_newtable(L);                 /* mt,"__index",it */  |  | ||||||
|     /* put class name into class metatable */ |  | ||||||
|     lua_pushstring(L, "class");      /* mt,"__index",it,"class" */ |  | ||||||
|     lua_pushstring(L, classname);    /* mt,"__index",it,"class",classname */ |  | ||||||
|     lua_rawset(L, -3);               /* mt,"__index",it */ |  | ||||||
|     /* pass all methods that start with _ to the metatable, and all others |  | ||||||
|      * to the index table */ |  | ||||||
|     for (; func->name; func++) {     /* mt,"__index",it */ |  | ||||||
|         lua_pushstring(L, func->name); |  | ||||||
|         lua_pushcfunction(L, func->func); |  | ||||||
|         lua_rawset(L, func->name[0] == '_' ? -5: -3); |  | ||||||
|     } |  | ||||||
|     lua_rawset(L, -3);               /* mt */ |  | ||||||
|     lua_pop(L, 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Prints the value of a class in a nice way |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| int auxiliar_tostring(lua_State *L) { |  | ||||||
|     char buf[32]; |  | ||||||
|     if (!lua_getmetatable(L, 1)) goto error; |  | ||||||
|     lua_pushstring(L, "__index"); |  | ||||||
|     lua_gettable(L, -2); |  | ||||||
|     if (!lua_istable(L, -1)) goto error; |  | ||||||
|     lua_pushstring(L, "class"); |  | ||||||
|     lua_gettable(L, -2); |  | ||||||
|     if (!lua_isstring(L, -1)) goto error; |  | ||||||
|     sprintf(buf, "%p", lua_touserdata(L, 1)); |  | ||||||
|     lua_pushfstring(L, "%s: %s", lua_tostring(L, -1), buf); |  | ||||||
|     return 1; |  | ||||||
| error: |  | ||||||
|     lua_pushstring(L, "invalid object passed to 'auxiliar.c:__tostring'"); |  | ||||||
|     lua_error(L); |  | ||||||
|     return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Insert class into group |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| void auxiliar_add2group(lua_State *L, const char *classname, const char *groupname) { |  | ||||||
|     luaL_getmetatable(L, classname); |  | ||||||
|     lua_pushstring(L, groupname); |  | ||||||
|     lua_pushboolean(L, 1); |  | ||||||
|     lua_rawset(L, -3); |  | ||||||
|     lua_pop(L, 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Make sure argument is a boolean |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| int auxiliar_checkboolean(lua_State *L, int objidx) { |  | ||||||
|     if (!lua_isboolean(L, objidx)) |  | ||||||
|         luaL_typerror(L, objidx, lua_typename(L, LUA_TBOOLEAN)); |  | ||||||
|     return lua_toboolean(L, objidx); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Return userdata pointer if object belongs to a given class, abort with  |  | ||||||
| * error otherwise |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) { |  | ||||||
|     void *data = auxiliar_getclassudata(L, classname, objidx); |  | ||||||
|     if (!data) { |  | ||||||
|         char msg[45]; |  | ||||||
|         sprintf(msg, "%.35s expected", classname); |  | ||||||
|         luaL_argerror(L, objidx, msg); |  | ||||||
|     } |  | ||||||
|     return data; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Return userdata pointer if object belongs to a given group, abort with  |  | ||||||
| * error otherwise |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) { |  | ||||||
|     void *data = auxiliar_getgroupudata(L, groupname, objidx); |  | ||||||
|     if (!data) { |  | ||||||
|         char msg[45]; |  | ||||||
|         sprintf(msg, "%.35s expected", groupname); |  | ||||||
|         luaL_argerror(L, objidx, msg); |  | ||||||
|     } |  | ||||||
|     return data; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Set object class |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| void auxiliar_setclass(lua_State *L, const char *classname, int objidx) { |  | ||||||
|     luaL_getmetatable(L, classname); |  | ||||||
|     if (objidx < 0) objidx--; |  | ||||||
|     lua_setmetatable(L, objidx); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Get a userdata pointer if object belongs to a given group. Return NULL  |  | ||||||
| * otherwise |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) { |  | ||||||
|     if (!lua_getmetatable(L, objidx)) |  | ||||||
|         return NULL; |  | ||||||
|     lua_pushstring(L, groupname); |  | ||||||
|     lua_rawget(L, -2); |  | ||||||
|     if (lua_isnil(L, -1)) { |  | ||||||
|         lua_pop(L, 2); |  | ||||||
|         return NULL; |  | ||||||
|     } else { |  | ||||||
|         lua_pop(L, 2); |  | ||||||
|         return lua_touserdata(L, objidx); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Get a userdata pointer if object belongs to a given class. Return NULL  |  | ||||||
| * otherwise |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) { |  | ||||||
|     return luaL_checkudata(L, objidx, classname); |  | ||||||
| } |  | ||||||
| @@ -1,48 +0,0 @@ | |||||||
| #ifndef AUXILIAR_H |  | ||||||
| #define AUXILIAR_H |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Auxiliar routines for class hierarchy manipulation |  | ||||||
| * LuaSocket toolkit (but completely independent of other LuaSocket modules) |  | ||||||
| * |  | ||||||
| * A LuaSocket class is a name associated with Lua metatables. A LuaSocket  |  | ||||||
| * group is a name associated with a class. A class can belong to any number  |  | ||||||
| * of groups. This module provides the functionality to: |  | ||||||
| * |  | ||||||
| *   - create new classes  |  | ||||||
| *   - add classes to groups  |  | ||||||
| *   - set the class of objects |  | ||||||
| *   - check if an object belongs to a given class or group |  | ||||||
| *   - get the userdata associated to objects |  | ||||||
| *   - print objects in a pretty way |  | ||||||
| * |  | ||||||
| * LuaSocket class names follow the convention <module>{<class>}. Modules |  | ||||||
| * can define any number of classes and groups. The module tcp.c, for |  | ||||||
| * example, defines the classes tcp{master}, tcp{client} and tcp{server} and |  | ||||||
| * the groups tcp{client,server} and tcp{any}. Module functions can then |  | ||||||
| * perform type-checking on their arguments by either class or group. |  | ||||||
| * |  | ||||||
| * LuaSocket metatables define the __index metamethod as being a table. This |  | ||||||
| * table has one field for each method supported by the class, and a field |  | ||||||
| * "class" with the class name. |  | ||||||
| * |  | ||||||
| * The mapping from class name to the corresponding metatable and the |  | ||||||
| * reverse mapping are done using lauxlib.  |  | ||||||
| * |  | ||||||
| * RCS ID: $Id: auxiliar.h,v 1.9 2005/10/07 04:40:59 diego Exp $ |  | ||||||
| \*=========================================================================*/ |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
| #include "lauxlib.h" |  | ||||||
|  |  | ||||||
| int auxiliar_open(lua_State *L); |  | ||||||
| void auxiliar_newclass(lua_State *L, const char *classname, luaL_reg *func); |  | ||||||
| void auxiliar_add2group(lua_State *L, const char *classname, const char *group); |  | ||||||
| void auxiliar_setclass(lua_State *L, const char *classname, int objidx); |  | ||||||
| void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx); |  | ||||||
| void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx); |  | ||||||
| void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx); |  | ||||||
| void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx); |  | ||||||
| int auxiliar_checkboolean(lua_State *L, int objidx); |  | ||||||
| int auxiliar_tostring(lua_State *L); |  | ||||||
|  |  | ||||||
| #endif /* AUXILIAR_H */ |  | ||||||
| @@ -1,263 +0,0 @@ | |||||||
| /*=========================================================================*\ |  | ||||||
| * Input/Output interface for Lua programs |  | ||||||
| * LuaSocket toolkit |  | ||||||
| * |  | ||||||
| * RCS ID: $Id: buffer.c,v 1.27 2005/10/07 04:40:59 diego Exp $ |  | ||||||
| \*=========================================================================*/ |  | ||||||
| #include "lua.h" |  | ||||||
| #include "lauxlib.h" |  | ||||||
|  |  | ||||||
| #include "buffer.h" |  | ||||||
|  |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Internal function prototypes |  | ||||||
| \*=========================================================================*/ |  | ||||||
| static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b); |  | ||||||
| static int recvline(p_buffer buf, luaL_Buffer *b); |  | ||||||
| static int recvall(p_buffer buf, luaL_Buffer *b); |  | ||||||
| static int buffer_get(p_buffer buf, const char **data, size_t *count); |  | ||||||
| static void buffer_skip(p_buffer buf, size_t count); |  | ||||||
| static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent); |  | ||||||
|  |  | ||||||
| /* min and max macros */ |  | ||||||
| #ifndef MIN |  | ||||||
| #define MIN(x, y) ((x) < (y) ? x : y) |  | ||||||
| #endif |  | ||||||
| #ifndef MAX |  | ||||||
| #define MAX(x, y) ((x) > (y) ? x : y) |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Exported functions |  | ||||||
| \*=========================================================================*/ |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Initializes module |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| int buffer_open(lua_State *L) { |  | ||||||
|     (void) L; |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Initializes C structure |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| void buffer_init(p_buffer buf, p_io io, p_timeout tm) { |  | ||||||
| 	buf->first = buf->last = 0; |  | ||||||
|     buf->io = io; |  | ||||||
|     buf->tm = tm; |  | ||||||
|     buf->received = buf->sent = 0; |  | ||||||
|     buf->birthday = timeout_gettime(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * object:getstats() interface |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| int buffer_meth_getstats(lua_State *L, p_buffer buf) { |  | ||||||
|     lua_pushnumber(L, buf->received); |  | ||||||
|     lua_pushnumber(L, buf->sent); |  | ||||||
|     lua_pushnumber(L, timeout_gettime() - buf->birthday); |  | ||||||
|     return 3; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * object:setstats() interface |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| int buffer_meth_setstats(lua_State *L, p_buffer buf) { |  | ||||||
|     buf->received = (long) luaL_optnumber(L, 2, buf->received); |  | ||||||
|     buf->sent = (long) luaL_optnumber(L, 3, buf->sent); |  | ||||||
|     if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4); |  | ||||||
|     lua_pushnumber(L, 1); |  | ||||||
|     return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * object:send() interface |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| int buffer_meth_send(lua_State *L, p_buffer buf) { |  | ||||||
|     int top = lua_gettop(L); |  | ||||||
|     /*p_timeout tm = timeout_markstart(buf->tm);*/ |  | ||||||
|     int err = IO_DONE; |  | ||||||
|     size_t size = 0, sent = 0; |  | ||||||
|     const char *data = luaL_checklstring(L, 2, &size); |  | ||||||
|     long start = (long) luaL_optnumber(L, 3, 1); |  | ||||||
|     long end = (long) luaL_optnumber(L, 4, -1); |  | ||||||
|     if (start < 0) start = (long) (size+start+1); |  | ||||||
|     if (end < 0) end = (long) (size+end+1); |  | ||||||
|     if (start < 1) start = (long) 1; |  | ||||||
|     if (end > (long) size) end = (long) size; |  | ||||||
|     if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent); |  | ||||||
|     /* check if there was an error */ |  | ||||||
|     if (err != IO_DONE) { |  | ||||||
|         lua_pushnil(L); |  | ||||||
|         lua_pushstring(L, buf->io->error(buf->io->ctx, err)); |  | ||||||
|         lua_pushnumber(L, sent+start-1); |  | ||||||
|     } else { |  | ||||||
|         lua_pushnumber(L, sent+start-1); |  | ||||||
|         lua_pushnil(L); |  | ||||||
|         lua_pushnil(L); |  | ||||||
|     } |  | ||||||
| #ifdef LUASOCKET_DEBUG |  | ||||||
|     /* push time elapsed during operation as the last return value */ |  | ||||||
|     lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm)); |  | ||||||
| #endif |  | ||||||
|     return lua_gettop(L) - top; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * object:receive() interface |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| int buffer_meth_receive(lua_State *L, p_buffer buf) { |  | ||||||
|     int err = IO_DONE, top = lua_gettop(L); |  | ||||||
|     /*p_timeout tm = timeout_markstart(buf->tm);*/ |  | ||||||
|     luaL_Buffer b; |  | ||||||
|     size_t size; |  | ||||||
|     const char *part = luaL_optlstring(L, 3, "", &size); |  | ||||||
|     /* initialize buffer with optional extra prefix |  | ||||||
|      * (useful for concatenating previous partial results) */ |  | ||||||
|     luaL_buffinit(L, &b); |  | ||||||
|     luaL_addlstring(&b, part, size); |  | ||||||
|     /* receive new patterns */ |  | ||||||
|     if (!lua_isnumber(L, 2)) { |  | ||||||
|         const char *p= luaL_optstring(L, 2, "*l"); |  | ||||||
|         if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b); |  | ||||||
|         else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); |  | ||||||
|         else luaL_argcheck(L, 0, 2, "invalid receive pattern"); |  | ||||||
|         /* get a fixed number of bytes (minus what was already partially |  | ||||||
|          * received) */ |  | ||||||
|     } else err = recvraw(buf, (size_t) lua_tonumber(L, 2)-size, &b); |  | ||||||
|     /* check if there was an error */ |  | ||||||
|     if (err != IO_DONE) { |  | ||||||
|         /* we can't push anyting in the stack before pushing the |  | ||||||
|          * contents of the buffer. this is the reason for the complication */ |  | ||||||
|         luaL_pushresult(&b); |  | ||||||
|         lua_pushstring(L, buf->io->error(buf->io->ctx, err)); |  | ||||||
|         lua_pushvalue(L, -2); |  | ||||||
|         lua_pushnil(L); |  | ||||||
|         lua_replace(L, -4); |  | ||||||
|     } else { |  | ||||||
|         luaL_pushresult(&b); |  | ||||||
|         lua_pushnil(L); |  | ||||||
|         lua_pushnil(L); |  | ||||||
|     } |  | ||||||
| #ifdef LUASOCKET_DEBUG |  | ||||||
|     /* push time elapsed during operation as the last return value */ |  | ||||||
|     lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm)); |  | ||||||
| #endif |  | ||||||
|     return lua_gettop(L) - top; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Determines if there is any data in the read buffer |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| int buffer_isempty(p_buffer buf) { |  | ||||||
|     return buf->first >= buf->last; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Internal functions |  | ||||||
| \*=========================================================================*/ |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Sends a block of data (unbuffered) |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| #define STEPSIZE 8192 |  | ||||||
| static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) { |  | ||||||
|     p_io io = buf->io; |  | ||||||
|     p_timeout tm = buf->tm; |  | ||||||
|     size_t total = 0; |  | ||||||
|     int err = IO_DONE; |  | ||||||
|     while (total < count && err == IO_DONE) { |  | ||||||
|         size_t done; |  | ||||||
|         size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE; |  | ||||||
|         err = io->send(io->ctx, data+total, step, &done, tm); |  | ||||||
|         total += done; |  | ||||||
|     } |  | ||||||
|     *sent = total; |  | ||||||
|     buf->sent += total; |  | ||||||
|     return err; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Reads a fixed number of bytes (buffered) |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) { |  | ||||||
|     int err = IO_DONE; |  | ||||||
|     size_t total = 0; |  | ||||||
|     while (total < wanted && err == IO_DONE) { |  | ||||||
|         size_t count; const char *data; |  | ||||||
|         err = buffer_get(buf, &data, &count); |  | ||||||
|         count = MIN(count, wanted - total); |  | ||||||
|         luaL_addlstring(b, data, count); |  | ||||||
|         buffer_skip(buf, count); |  | ||||||
|         total += count; |  | ||||||
|     } |  | ||||||
|     return err; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Reads everything until the connection is closed (buffered) |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| static int recvall(p_buffer buf, luaL_Buffer *b) { |  | ||||||
|     int err = IO_DONE; |  | ||||||
|     while (err == IO_DONE) { |  | ||||||
|         const char *data; size_t count; |  | ||||||
|         err = buffer_get(buf, &data, &count); |  | ||||||
|         luaL_addlstring(b, data, count); |  | ||||||
|         buffer_skip(buf, count); |  | ||||||
|     } |  | ||||||
|     if (err == IO_CLOSED) return IO_DONE; |  | ||||||
|     else return err; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Reads a line terminated by a CR LF pair or just by a LF. The CR and LF |  | ||||||
| * are not returned by the function and are discarded from the buffer |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| static int recvline(p_buffer buf, luaL_Buffer *b) { |  | ||||||
|     int err = IO_DONE; |  | ||||||
|     while (err == IO_DONE) { |  | ||||||
|         size_t count, pos; const char *data; |  | ||||||
|         err = buffer_get(buf, &data, &count); |  | ||||||
|         pos = 0; |  | ||||||
|         while (pos < count && data[pos] != '\n') { |  | ||||||
|             /* we ignore all \r's */ |  | ||||||
|             if (data[pos] != '\r') luaL_putchar(b, data[pos]); |  | ||||||
|             pos++; |  | ||||||
|         } |  | ||||||
|         if (pos < count) { /* found '\n' */ |  | ||||||
|             buffer_skip(buf, pos+1); /* skip '\n' too */ |  | ||||||
|             break; /* we are done */ |  | ||||||
|         } else /* reached the end of the buffer */ |  | ||||||
|             buffer_skip(buf, pos); |  | ||||||
|     } |  | ||||||
|     return err; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Skips a given number of bytes from read buffer. No data is read from the |  | ||||||
| * transport layer |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| static void buffer_skip(p_buffer buf, size_t count) { |  | ||||||
|     buf->received += count; |  | ||||||
|     buf->first += count; |  | ||||||
|     if (buffer_isempty(buf)) |  | ||||||
|         buf->first = buf->last = 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Return any data available in buffer, or get more data from transport layer |  | ||||||
| * if buffer is empty |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| static int buffer_get(p_buffer buf, const char **data, size_t *count) { |  | ||||||
|     int err = IO_DONE; |  | ||||||
|     p_io io = buf->io; |  | ||||||
|     p_timeout tm = buf->tm; |  | ||||||
|     if (buffer_isempty(buf)) { |  | ||||||
|         size_t got; |  | ||||||
|         err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm); |  | ||||||
|         buf->first = 0; |  | ||||||
|         buf->last = got; |  | ||||||
|     } |  | ||||||
|     *count = buf->last - buf->first; |  | ||||||
|     *data = buf->data + buf->first; |  | ||||||
|     return err; |  | ||||||
| } |  | ||||||
| @@ -1,47 +0,0 @@ | |||||||
| #ifndef BUF_H |  | ||||||
| #define BUF_H  |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Input/Output interface for Lua programs |  | ||||||
| * LuaSocket toolkit |  | ||||||
| * |  | ||||||
| * Line patterns require buffering. Reading one character at a time involves |  | ||||||
| * too many system calls and is very slow. This module implements the |  | ||||||
| * LuaSocket interface for input/output on connected objects, as seen by  |  | ||||||
| * Lua programs.  |  | ||||||
| * |  | ||||||
| * Input is buffered. Output is *not* buffered because there was no simple |  | ||||||
| * way of making sure the buffered output data would ever be sent. |  | ||||||
| * |  | ||||||
| * The module is built on top of the I/O abstraction defined in io.h and the |  | ||||||
| * timeout management is done with the timeout.h interface. |  | ||||||
| * |  | ||||||
| * RCS ID: $Id: buffer.h,v 1.12 2005/10/07 04:40:59 diego Exp $ |  | ||||||
| \*=========================================================================*/ |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "io.h" |  | ||||||
| #include "timeout.h" |  | ||||||
|  |  | ||||||
| /* buffer size in bytes */ |  | ||||||
| #define BUF_SIZE 8192 |  | ||||||
|  |  | ||||||
| /* buffer control structure */ |  | ||||||
| typedef struct t_buffer_ { |  | ||||||
|     double birthday;        /* throttle support info: creation time, */ |  | ||||||
|     size_t sent, received;  /* bytes sent, and bytes received */ |  | ||||||
|     p_io io;                /* IO driver used for this buffer */ |  | ||||||
|     p_timeout tm;           /* timeout management for this buffer */ |  | ||||||
| 	size_t first, last;     /* index of first and last bytes of stored data */ |  | ||||||
| 	char data[BUF_SIZE];    /* storage space for buffer data */ |  | ||||||
| } t_buffer; |  | ||||||
| typedef t_buffer *p_buffer; |  | ||||||
|  |  | ||||||
| int buffer_open(lua_State *L); |  | ||||||
| void buffer_init(p_buffer buf, p_io io, p_timeout tm); |  | ||||||
| int buffer_meth_send(lua_State *L, p_buffer buf); |  | ||||||
| int buffer_meth_receive(lua_State *L, p_buffer buf); |  | ||||||
| int buffer_meth_getstats(lua_State *L, p_buffer buf); |  | ||||||
| int buffer_meth_setstats(lua_State *L, p_buffer buf); |  | ||||||
| int buffer_isempty(p_buffer buf); |  | ||||||
|  |  | ||||||
| #endif /* BUF_H */ |  | ||||||
| @@ -1,97 +0,0 @@ | |||||||
| /* |  | ||||||
| ** Compat-5.1 |  | ||||||
| ** Copyright Kepler Project 2004-2005 (http://www.keplerproject.org/compat) |  | ||||||
| ** $Id: compat-5.1.c,v 1.12 2005/07/08 18:25:52 carregal Exp $ |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <string.h> |  | ||||||
| #include "lua.h" |  | ||||||
| #include "lauxlib.h" |  | ||||||
| #include "compat51.h" |  | ||||||
|  |  | ||||||
| static void getfield(lua_State *L, int idx, const char *name) { |  | ||||||
|     const char *end = strchr(name, '.'); |  | ||||||
|     lua_pushvalue(L, idx); |  | ||||||
|     while (end) { |  | ||||||
|         lua_pushlstring(L, name, end - name); |  | ||||||
|         lua_gettable(L, -2); |  | ||||||
|         lua_remove(L, -2); |  | ||||||
|         if (lua_isnil(L, -1)) return; |  | ||||||
|         name = end+1; |  | ||||||
|         end = strchr(name, '.'); |  | ||||||
|     } |  | ||||||
|     lua_pushstring(L, name); |  | ||||||
|     lua_gettable(L, -2); |  | ||||||
|     lua_remove(L, -2); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void setfield(lua_State *L, int idx, const char *name) { |  | ||||||
|     const char *end = strchr(name, '.'); |  | ||||||
|     lua_pushvalue(L, idx); |  | ||||||
|     while (end) { |  | ||||||
|         lua_pushlstring(L, name, end - name); |  | ||||||
|         lua_gettable(L, -2); |  | ||||||
|         /* create table if not found */ |  | ||||||
|         if (lua_isnil(L, -1)) { |  | ||||||
|             lua_pop(L, 1); |  | ||||||
|             lua_newtable(L); |  | ||||||
|             lua_pushlstring(L, name, end - name); |  | ||||||
|             lua_pushvalue(L, -2); |  | ||||||
|             lua_settable(L, -4); |  | ||||||
|         } |  | ||||||
|         lua_remove(L, -2); |  | ||||||
|         name = end+1; |  | ||||||
|         end = strchr(name, '.'); |  | ||||||
|     } |  | ||||||
|     lua_pushstring(L, name); |  | ||||||
|     lua_pushvalue(L, -3); |  | ||||||
|     lua_settable(L, -3); |  | ||||||
|     lua_pop(L, 2); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| LUALIB_API void luaL_module(lua_State *L, const char *libname, |  | ||||||
|                               const luaL_reg *l, int nup) { |  | ||||||
|   if (libname) { |  | ||||||
|     getfield(L, LUA_GLOBALSINDEX, libname);  /* check whether lib already exists */ |  | ||||||
|     if (lua_isnil(L, -1)) {  |  | ||||||
|       int env, ns; |  | ||||||
|       lua_pop(L, 1); /* get rid of nil */ |  | ||||||
|       lua_pushliteral(L, "require"); |  | ||||||
|       lua_gettable(L, LUA_GLOBALSINDEX); /* look for require */ |  | ||||||
|       lua_getfenv(L, -1); /* getfenv(require) */ |  | ||||||
|       lua_remove(L, -2); /* remove function require */ |  | ||||||
|       env = lua_gettop(L); |  | ||||||
|  |  | ||||||
|       lua_newtable(L); /* create namespace for lib */ |  | ||||||
|       ns = lua_gettop(L); |  | ||||||
|       getfield(L, env, "package.loaded"); /* get package.loaded table */ |  | ||||||
|       if (lua_isnil(L, -1)) { /* create package.loaded table */ |  | ||||||
|           lua_pop(L, 1); /* remove previous result */ |  | ||||||
|           lua_newtable(L); |  | ||||||
|           lua_pushvalue(L, -1); |  | ||||||
|           setfield(L, env, "package.loaded"); |  | ||||||
|       } |  | ||||||
|       else if (!lua_istable(L, -1)) |  | ||||||
|         luaL_error(L, "name conflict for library `%s'", libname); |  | ||||||
|       lua_pushstring(L, libname); |  | ||||||
|       lua_pushvalue(L, ns);  |  | ||||||
|       lua_settable(L, -3); /* package.loaded[libname] = ns */ |  | ||||||
|       lua_pop(L, 1); /* get rid of package.loaded table */ |  | ||||||
|       lua_pushvalue(L, ns); /* copy namespace */ |  | ||||||
|       setfield(L, LUA_GLOBALSINDEX, libname); |  | ||||||
|       lua_remove (L, env); /* remove env */ |  | ||||||
|     } |  | ||||||
|     lua_insert(L, -(nup+1));  /* move library table to below upvalues */ |  | ||||||
|   } |  | ||||||
|   for (; l->name; l++) { |  | ||||||
|     int i; |  | ||||||
|     lua_pushstring(L, l->name); |  | ||||||
|     for (i=0; i<nup; i++)  /* copy upvalues to the top */ |  | ||||||
|       lua_pushvalue(L, -(nup+1)); |  | ||||||
|     lua_pushcclosure(L, l->func, nup); |  | ||||||
|     lua_settable(L, -(nup+3)); |  | ||||||
|   } |  | ||||||
|   lua_pop(L, nup);  /* remove upvalues */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| /* |  | ||||||
| ** Compat-5.1 |  | ||||||
| ** Copyright Kepler Project 2004-2005 (http://www.keplerproject.org/compat/) |  | ||||||
| ** $Id: compat-5.1.h,v 1.7 2005/07/08 18:25:52 carregal Exp $ |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef COMPAT_H |  | ||||||
|  |  | ||||||
| LUALIB_API void luaL_module(lua_State *L, const char *libname, |  | ||||||
|                                        const luaL_reg *l, int nup); |  | ||||||
| #define luaL_openlib luaL_module |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,235 +0,0 @@ | |||||||
| -- |  | ||||||
| -- Compat-5.1 |  | ||||||
| -- Copyright Kepler Project 2004-2005 (http://www.keplerproject.org/compat) |  | ||||||
| -- According to Lua 5.1 |  | ||||||
| -- $Id: compat-5.1.lua,v 1.19 2005/07/05 19:12:00 tomas Exp $ |  | ||||||
| -- |  | ||||||
|  |  | ||||||
| _COMPAT51 = "Compat-5.1 R4" |  | ||||||
|  |  | ||||||
| local LUA_DIRSEP = '/' |  | ||||||
| local LUA_OFSEP = '_' |  | ||||||
| local OLD_LUA_OFSEP = '' |  | ||||||
| local POF = 'luaopen_' |  | ||||||
|  |  | ||||||
| local assert, error, getfenv, ipairs, loadfile, loadlib, pairs, setfenv, setmetatable, type = assert, error, getfenv, ipairs, loadfile, loadlib, pairs, setfenv, setmetatable, type |  | ||||||
| local format, gfind, gsub = string.format, string.gfind, string.gsub |  | ||||||
|  |  | ||||||
| -- |  | ||||||
| -- avoid overwriting the package table if it's already there |  | ||||||
| -- |  | ||||||
| package = package or {} |  | ||||||
|  |  | ||||||
| package.path = LUA_PATH or os.getenv("LUA_PATH") or |  | ||||||
|              ("./?.lua;" .. |  | ||||||
|               "/usr/local/share/lua/5.0/?.lua;" .. |  | ||||||
|               "/usr/local/share/lua/5.0/?/?.lua;" .. |  | ||||||
|               "/usr/local/share/lua/5.0/?/init.lua" ) |  | ||||||
|   |  | ||||||
| package.cpath = os.getenv("LUA_CPATH") or |  | ||||||
|              "./?.so;" .. |  | ||||||
|              "./l?.so;" .. |  | ||||||
|              "/usr/local/lib/lua/5.0/?.so;" .. |  | ||||||
|              "/usr/local/lib/lua/5.0/l?.so" |  | ||||||
|  |  | ||||||
| -- |  | ||||||
| -- make sure require works with standard libraries |  | ||||||
| -- |  | ||||||
| package.loaded = package.loaded or {} |  | ||||||
| package.loaded.string = string |  | ||||||
| package.loaded.math = math |  | ||||||
| package.loaded.io = io |  | ||||||
| package.loaded.os = os |  | ||||||
| package.loaded.table = table  |  | ||||||
| package.loaded.base = _G |  | ||||||
| package.loaded.coroutine = coroutine |  | ||||||
|  |  | ||||||
| -- |  | ||||||
| -- avoid overwriting the package.preload table if it's already there |  | ||||||
| -- |  | ||||||
| package.preload = package.preload or {} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| -- |  | ||||||
| -- auxiliar function to read "nested globals" |  | ||||||
| -- |  | ||||||
| local function getfield (t, f) |  | ||||||
|   assert (type(f)=="string", "not a valid field name ("..tostring(f)..")") |  | ||||||
|   for w in gfind(f, "[%w_]+") do |  | ||||||
|     if not t then return nil end |  | ||||||
|     t = rawget(t, w) |  | ||||||
|   end |  | ||||||
|   return t |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| -- |  | ||||||
| -- auxiliar function to write "nested globals" |  | ||||||
| -- |  | ||||||
| local function setfield (t, f, v) |  | ||||||
|   for w in gfind(f, "([%w_]+)%.") do |  | ||||||
|     t[w] = t[w] or {} -- create table if absent |  | ||||||
|     t = t[w]            -- get the table |  | ||||||
|   end |  | ||||||
|   local w = gsub(f, "[%w_]+%.", "")   -- get last field name |  | ||||||
|   t[w] = v            -- do the assignment |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| -- |  | ||||||
| -- looks for a file `name' in given path |  | ||||||
| -- |  | ||||||
| local function search (path, name) |  | ||||||
|   for c in gfind(path, "[^;]+") do |  | ||||||
|     c = gsub(c, "%?", name) |  | ||||||
|     local f = io.open(c) |  | ||||||
|     if f then   -- file exist? |  | ||||||
|       f:close() |  | ||||||
|       return c |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
|   return nil    -- file not found |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| -- |  | ||||||
| -- check whether library is already loaded |  | ||||||
| -- |  | ||||||
| local function loader_preload (name) |  | ||||||
|   assert (type(name) == "string", format ( |  | ||||||
|     "bad argument #1 to `require' (string expected, got %s)", type(name))) |  | ||||||
|   if type(package.preload) ~= "table" then |  | ||||||
|     error ("`package.preload' must be a table") |  | ||||||
|   end |  | ||||||
|   return package.preload[name] |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| -- |  | ||||||
| -- C library loader |  | ||||||
| -- |  | ||||||
| local function loader_C (name) |  | ||||||
|   assert (type(name) == "string", format ( |  | ||||||
|     "bad argument #1 to `require' (string expected, got %s)", type(name))) |  | ||||||
|   local fname = gsub (name, "%.", LUA_DIRSEP) |  | ||||||
|   fname = search (package.cpath, fname) |  | ||||||
|   if not fname then |  | ||||||
|     return false |  | ||||||
|   end |  | ||||||
|   local funcname = POF .. gsub (name, "%.", LUA_OFSEP) |  | ||||||
|   local f, err = loadlib (fname, funcname) |  | ||||||
|   if not f then |  | ||||||
|     funcname = POF .. gsub (name, "%.", OLD_LUA_OFSEP) |  | ||||||
|     f, err = loadlib (fname, funcname) |  | ||||||
|     if not f then |  | ||||||
|       error (format ("error loading package `%s' (%s)", name, err)) |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
|   return f |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| -- |  | ||||||
| -- Lua library loader |  | ||||||
| -- |  | ||||||
| local function loader_Lua (name) |  | ||||||
|   assert (type(name) == "string", format ( |  | ||||||
|     "bad argument #1 to `require' (string expected, got %s)", type(name))) |  | ||||||
|   local path = LUA_PATH |  | ||||||
|   if not path then |  | ||||||
|     path = assert (package.path, "`package.path' must be a string") |  | ||||||
|   end |  | ||||||
|   local fname = gsub (name, "%.", LUA_DIRSEP) |  | ||||||
|   fname = search (path, fname) |  | ||||||
|   if not fname then |  | ||||||
|     return false |  | ||||||
|   end |  | ||||||
|   local f, err = loadfile (fname) |  | ||||||
|   if not f then |  | ||||||
|     error (format ("error loading package `%s' (%s)", name, err)) |  | ||||||
|   end |  | ||||||
|   return f |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| -- create `loaders' table |  | ||||||
| package.loaders = package.loaders or { loader_preload, loader_C, loader_Lua, } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| -- |  | ||||||
| -- iterate over available loaders |  | ||||||
| -- |  | ||||||
| local function load (name, loaders) |  | ||||||
|   -- iterate over available loaders |  | ||||||
|   assert (type (loaders) == "table", "`package.loaders' must be a table") |  | ||||||
|   for i, loader in ipairs (loaders) do |  | ||||||
|     local f = loader (name) |  | ||||||
|     if f then |  | ||||||
|       return f |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
|   error (format ("package `%s' not found", name)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| -- |  | ||||||
| -- new require |  | ||||||
| -- |  | ||||||
| function _G.require (name) |  | ||||||
|   assert (type(name) == "string", format ( |  | ||||||
|     "bad argument #1 to `require' (string expected, got %s)", type(name))) |  | ||||||
|   local p = loaded[name] -- is it there? |  | ||||||
|   if p then |  | ||||||
|     return p |  | ||||||
|   end |  | ||||||
|   -- first mark it as loaded |  | ||||||
|   loaded[name] = true |  | ||||||
|   -- load and run init function |  | ||||||
|   local actual_arg = _G.arg |  | ||||||
|   _G.arg = { name } |  | ||||||
|   local res = load(name, loaders)(name) |  | ||||||
|   if res then  |  | ||||||
|     loaded[name] = res -- store result |  | ||||||
|   end |  | ||||||
|   _G.arg = actual_arg |  | ||||||
|   -- return value should be in loaded[name] |  | ||||||
|   return loaded[name] |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| -- |  | ||||||
| -- new module function |  | ||||||
| -- |  | ||||||
| function _G.module (name) |  | ||||||
|   local _G = getfenv(0)       -- simulate C function environment |  | ||||||
|   local ns = getfield(_G, name)         -- search for namespace |  | ||||||
|   if not ns then |  | ||||||
|     ns = {}                             -- create new namespace |  | ||||||
|     setfield(_G, name, ns) |  | ||||||
|   elseif type(ns) ~= "table" then |  | ||||||
|     error("name conflict for module `"..name.."'") |  | ||||||
|   end |  | ||||||
|   if not ns._NAME then |  | ||||||
|     ns._NAME = name |  | ||||||
|     ns._M = ns |  | ||||||
|     ns._PACKAGE = gsub(name, "[^.]*$", "") |  | ||||||
|   end |  | ||||||
|   setmetatable(ns, {__index = _G}) |  | ||||||
|   loaded[name] = ns |  | ||||||
|   setfenv(2, ns) |  | ||||||
|   return ns |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| -- |  | ||||||
| -- define functions' environments |  | ||||||
| -- |  | ||||||
| local env = { |  | ||||||
| 	loaded = package.loaded, |  | ||||||
| 	loaders = package.loaders, |  | ||||||
| 	package = package, |  | ||||||
| 	_G = _G, |  | ||||||
| } |  | ||||||
| for i, f in ipairs { _G.module, _G.require, load, loader_preload, loader_C, loader_Lua, } do |  | ||||||
|   setfenv (f, env) |  | ||||||
| end |  | ||||||
| @@ -1,99 +0,0 @@ | |||||||
| /*=========================================================================*\ |  | ||||||
| * Simple exception support |  | ||||||
| * LuaSocket toolkit |  | ||||||
| * |  | ||||||
| * RCS ID: $Id: except.c,v 1.8 2005/09/29 06:11:41 diego Exp $ |  | ||||||
| \*=========================================================================*/ |  | ||||||
| #include <stdio.h> |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
| #include "lauxlib.h" |  | ||||||
|  |  | ||||||
| #include "except.h" |  | ||||||
|  |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Internal function prototypes. |  | ||||||
| \*=========================================================================*/ |  | ||||||
| static int global_protect(lua_State *L); |  | ||||||
| static int global_newtry(lua_State *L); |  | ||||||
| static int protected_(lua_State *L); |  | ||||||
| static int finalize(lua_State *L); |  | ||||||
| static int do_nothing(lua_State *L); |  | ||||||
|  |  | ||||||
| /* except functions */ |  | ||||||
| static luaL_reg func[] = { |  | ||||||
|     {"newtry",    global_newtry}, |  | ||||||
|     {"protect",   global_protect}, |  | ||||||
|     {NULL,        NULL} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Try factory |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| static void wrap(lua_State *L) { |  | ||||||
|     lua_newtable(L); |  | ||||||
|     lua_pushnumber(L, 1); |  | ||||||
|     lua_pushvalue(L, -3); |  | ||||||
|     lua_settable(L, -3); |  | ||||||
|     lua_insert(L, -2); |  | ||||||
|     lua_pop(L, 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int finalize(lua_State *L) { |  | ||||||
|     if (!lua_toboolean(L, 1)) { |  | ||||||
|         lua_pushvalue(L, lua_upvalueindex(1)); |  | ||||||
|         lua_pcall(L, 0, 0, 0); |  | ||||||
|         lua_settop(L, 2); |  | ||||||
|         wrap(L); |  | ||||||
|         lua_error(L); |  | ||||||
|         return 0; |  | ||||||
|     } else return lua_gettop(L); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int do_nothing(lua_State *L) {  |  | ||||||
|     (void) L; |  | ||||||
|     return 0;  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int global_newtry(lua_State *L) { |  | ||||||
|     lua_settop(L, 1); |  | ||||||
|     if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing); |  | ||||||
|     lua_pushcclosure(L, finalize, 1); |  | ||||||
|     return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Protect factory |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| static int unwrap(lua_State *L) { |  | ||||||
|     if (lua_istable(L, -1)) { |  | ||||||
|         lua_pushnumber(L, 1); |  | ||||||
|         lua_gettable(L, -2); |  | ||||||
|         lua_pushnil(L); |  | ||||||
|         lua_insert(L, -2); |  | ||||||
|         return 1; |  | ||||||
|     } else return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int protected_(lua_State *L) { |  | ||||||
|     lua_pushvalue(L, lua_upvalueindex(1)); |  | ||||||
|     lua_insert(L, 1); |  | ||||||
|     if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) { |  | ||||||
|         if (unwrap(L)) return 2; |  | ||||||
|         else lua_error(L); |  | ||||||
|         return 0; |  | ||||||
|     } else return lua_gettop(L); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int global_protect(lua_State *L) { |  | ||||||
|     lua_pushcclosure(L, protected_, 1); |  | ||||||
|     return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Init module |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| int except_open(lua_State *L) { |  | ||||||
|     luaL_openlib(L, NULL, func, 0); |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| #ifndef EXCEPT_H |  | ||||||
| #define EXCEPT_H |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Exception control |  | ||||||
| * LuaSocket toolkit (but completely independent from other modules) |  | ||||||
| * |  | ||||||
| * This provides support for simple exceptions in Lua. During the |  | ||||||
| * development of the HTTP/FTP/SMTP support, it became aparent that |  | ||||||
| * error checking was taking a substantial amount of the coding. These |  | ||||||
| * function greatly simplify the task of checking errors. |  | ||||||
| * |  | ||||||
| * The main idea is that functions should return nil as its first return |  | ||||||
| * value when it finds an error, and return an error message (or value) |  | ||||||
| * following nil. In case of success, as long as the first value is not nil, |  | ||||||
| * the other values don't matter. |  | ||||||
| * |  | ||||||
| * The idea is to nest function calls with the "try" function. This function |  | ||||||
| * checks the first value, and calls "error" on the second if the first is |  | ||||||
| * nil. Otherwise, it returns all values it received.  |  | ||||||
| * |  | ||||||
| * The protect function returns a new function that behaves exactly like the |  | ||||||
| * function it receives, but the new function doesn't throw exceptions: it |  | ||||||
| * returns nil followed by the error message instead. |  | ||||||
| * |  | ||||||
| * With these two function, it's easy to write functions that throw |  | ||||||
| * exceptions on error, but that don't interrupt the user script.  |  | ||||||
| * |  | ||||||
| * RCS ID: $Id: except.h,v 1.2 2005/09/29 06:11:41 diego Exp $ |  | ||||||
| \*=========================================================================*/ |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| int except_open(lua_State *L); |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,280 +0,0 @@ | |||||||
| ----------------------------------------------------------------------------- |  | ||||||
| -- FTP support for the Lua language |  | ||||||
| -- LuaSocket toolkit. |  | ||||||
| -- Author: Diego Nehab |  | ||||||
| -- RCS ID: $Id: ftp.lua,v 1.42 2005/11/22 08:33:29 diego Exp $ |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
|  |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| -- Declare module and import dependencies |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| local base = _G |  | ||||||
| local table = require("table") |  | ||||||
| local string = require("string") |  | ||||||
| local math = require("math") |  | ||||||
| local socket = require("socket") |  | ||||||
| local url = require("socket.url") |  | ||||||
| local tp = require("socket.tp") |  | ||||||
| local ltn12 = require("ltn12") |  | ||||||
| module("socket.ftp") |  | ||||||
|  |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| -- Program constants |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| -- timeout in seconds before the program gives up on a connection |  | ||||||
| TIMEOUT = 60 |  | ||||||
| -- default port for ftp service |  | ||||||
| PORT = 21 |  | ||||||
| -- this is the default anonymous password. used when no password is |  | ||||||
| -- provided in url. should be changed to your e-mail. |  | ||||||
| USER = "ftp" |  | ||||||
| PASSWORD = "anonymous@anonymous.org" |  | ||||||
|  |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| -- Low level FTP API |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| local metat = { __index = {} } |  | ||||||
|  |  | ||||||
| function open(server, port, create) |  | ||||||
|     local tp = socket.try(tp.connect(server, port or PORT, create, TIMEOUT)) |  | ||||||
|     local f = base.setmetatable({ tp = tp }, metat) |  | ||||||
|     -- make sure everything gets closed in an exception |  | ||||||
|     f.try = socket.newtry(function() f:close() end) |  | ||||||
|     return f |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:portconnect() |  | ||||||
|     self.try(self.server:settimeout(TIMEOUT)) |  | ||||||
|     self.data = self.try(self.server:accept()) |  | ||||||
|     self.try(self.data:settimeout(TIMEOUT)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:pasvconnect() |  | ||||||
|     self.data = self.try(socket.tcp()) |  | ||||||
|     self.try(self.data:settimeout(TIMEOUT)) |  | ||||||
|     self.try(self.data:connect(self.pasvt.ip, self.pasvt.port)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:login(user, password) |  | ||||||
|     self.try(self.tp:command("user", user or USER)) |  | ||||||
|     local code, reply = self.try(self.tp:check{"2..", 331}) |  | ||||||
|     if code == 331 then |  | ||||||
|         self.try(self.tp:command("pass", password or PASSWORD)) |  | ||||||
|         self.try(self.tp:check("2..")) |  | ||||||
|     end |  | ||||||
|     return 1 |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:pasv() |  | ||||||
|     self.try(self.tp:command("pasv")) |  | ||||||
|     local code, reply = self.try(self.tp:check("2..")) |  | ||||||
|     local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" |  | ||||||
|     local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) |  | ||||||
|     self.try(a and b and c and d and p1 and p2, reply) |  | ||||||
|     self.pasvt = { |  | ||||||
|         ip = string.format("%d.%d.%d.%d", a, b, c, d), |  | ||||||
|         port = p1*256 + p2 |  | ||||||
|     } |  | ||||||
|     if self.server then |  | ||||||
|         self.server:close() |  | ||||||
|         self.server = nil |  | ||||||
|     end |  | ||||||
|     return self.pasvt.ip, self.pasvt.port |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:port(ip, port) |  | ||||||
|     self.pasvt = nil |  | ||||||
|     if not ip then |  | ||||||
|         ip, port = self.try(self.tp:getcontrol():getsockname()) |  | ||||||
|         self.server = self.try(socket.bind(ip, 0)) |  | ||||||
|         ip, port = self.try(self.server:getsockname()) |  | ||||||
|         self.try(server:settimeout(TIMEOUT)) |  | ||||||
|     end |  | ||||||
|     local pl = math.mod(port, 256) |  | ||||||
|     local ph = (port - pl)/256 |  | ||||||
|     local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",") |  | ||||||
|     self.try(self.tp:command("port", arg)) |  | ||||||
|     self.try(self.tp:check("2..")) |  | ||||||
|     return 1 |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:send(sendt) |  | ||||||
|     self.try(self.pasvt or self.server, "need port or pasv first") |  | ||||||
|     -- if there is a pasvt table, we already sent a PASV command |  | ||||||
|     -- we just get the data connection into self.data |  | ||||||
|     if self.pasvt then self:pasvconnect() end |  | ||||||
|     -- get the transfer argument and command |  | ||||||
|     local argument = sendt.argument or |  | ||||||
|         url.unescape(string.gsub(sendt.path or "", "^[/\\]", "")) |  | ||||||
|     if argument == "" then argument = nil end |  | ||||||
|     local command = sendt.command or "stor" |  | ||||||
|     -- send the transfer command and check the reply |  | ||||||
|     self.try(self.tp:command(command, argument)) |  | ||||||
|     local code, reply = self.try(self.tp:check{"2..", "1.."}) |  | ||||||
|     -- if there is not a a pasvt table, then there is a server |  | ||||||
|     -- and we already sent a PORT command |  | ||||||
|     if not self.pasvt then self:portconnect() end |  | ||||||
|     -- get the sink, source and step for the transfer |  | ||||||
|     local step = sendt.step or ltn12.pump.step |  | ||||||
|     local checkstep = function(src, snk) |  | ||||||
|         -- check status in control connection while downloading |  | ||||||
|         local readyt = socket.select(readt, nil, 0) |  | ||||||
|         if readyt[tp] then self.try(self.tp:check("2..")) end |  | ||||||
|         return step(src, snk) |  | ||||||
|     end |  | ||||||
|     local sink = socket.sink("close-when-done", self.data) |  | ||||||
|     -- transfer all data and check error |  | ||||||
|     self.try(ltn12.pump.all(sendt.source, sink, checkstep)) |  | ||||||
|     if string.find(code, "1..") then self.try(self.tp:check("2..")) end |  | ||||||
|     -- done with data connection |  | ||||||
|     self.data:close() |  | ||||||
|     -- find out how many bytes were sent |  | ||||||
|     local sent = socket.skip(1, self.data:getstats()) |  | ||||||
|     self.data = nil |  | ||||||
|     return sent |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:receive(recvt) |  | ||||||
|     self.try(self.pasvt or self.server, "need port or pasv first") |  | ||||||
|     if self.pasvt then self:pasvconnect() end |  | ||||||
|     local argument = recvt.argument or |  | ||||||
|         url.unescape(string.gsub(recvt.path or "", "^[/\\]", "")) |  | ||||||
|     if argument == "" then argument = nil end |  | ||||||
|     local command = recvt.command or "retr" |  | ||||||
|     self.try(self.tp:command(command, argument)) |  | ||||||
|     local code = self.try(self.tp:check{"1..", "2.."}) |  | ||||||
|     if not self.pasvt then self:portconnect() end |  | ||||||
|     local source = socket.source("until-closed", self.data) |  | ||||||
|     local step = recvt.step or ltn12.pump.step |  | ||||||
|     self.try(ltn12.pump.all(source, recvt.sink, step)) |  | ||||||
|     if string.find(code, "1..") then self.try(self.tp:check("2..")) end |  | ||||||
|     self.data:close() |  | ||||||
|     self.data = nil |  | ||||||
|     return 1 |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:cwd(dir) |  | ||||||
|     self.try(self.tp:command("cwd", dir)) |  | ||||||
|     self.try(self.tp:check(250)) |  | ||||||
|     return 1 |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:type(type) |  | ||||||
|     self.try(self.tp:command("type", type)) |  | ||||||
|     self.try(self.tp:check(200)) |  | ||||||
|     return 1 |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:greet() |  | ||||||
|     local code = self.try(self.tp:check{"1..", "2.."}) |  | ||||||
|     if string.find(code, "1..") then self.try(self.tp:check("2..")) end |  | ||||||
|     return 1 |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:quit() |  | ||||||
|     self.try(self.tp:command("quit")) |  | ||||||
|     self.try(self.tp:check("2..")) |  | ||||||
|     return 1 |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:close() |  | ||||||
|     if self.data then self.data:close() end |  | ||||||
|     if self.server then self.server:close() end |  | ||||||
|     return self.tp:close() |  | ||||||
| end |  | ||||||
|  |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| -- High level FTP API |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| function override(t) |  | ||||||
|     if t.url then |  | ||||||
|         u = url.parse(t.url) |  | ||||||
|         for i,v in base.pairs(t) do |  | ||||||
|             u[i] = v |  | ||||||
|         end |  | ||||||
|         return u |  | ||||||
|     else return t end |  | ||||||
| end |  | ||||||
|  |  | ||||||
| local function tput(putt) |  | ||||||
|     putt = override(putt) |  | ||||||
|     socket.try(putt.host, "missing hostname") |  | ||||||
|     local f = open(putt.host, putt.port, putt.create) |  | ||||||
|     f:greet() |  | ||||||
|     f:login(putt.user, putt.password) |  | ||||||
|     if putt.type then f:type(putt.type) end |  | ||||||
|     f:pasv() |  | ||||||
|     local sent = f:send(putt) |  | ||||||
|     f:quit() |  | ||||||
|     f:close() |  | ||||||
|     return sent |  | ||||||
| end |  | ||||||
|  |  | ||||||
| local default = { |  | ||||||
| 	path = "/", |  | ||||||
| 	scheme = "ftp" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| local function parse(u) |  | ||||||
|     local t = socket.try(url.parse(u, default)) |  | ||||||
|     socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'") |  | ||||||
|     socket.try(t.host, "missing hostname") |  | ||||||
|     local pat = "^type=(.)$" |  | ||||||
|     if t.params then |  | ||||||
|         t.type = socket.skip(2, string.find(t.params, pat)) |  | ||||||
|         socket.try(t.type == "a" or t.type == "i", |  | ||||||
|             "invalid type '" .. t.type .. "'") |  | ||||||
|     end |  | ||||||
|     return t |  | ||||||
| end |  | ||||||
|  |  | ||||||
| local function sput(u, body) |  | ||||||
|     local putt = parse(u) |  | ||||||
|     putt.source = ltn12.source.string(body) |  | ||||||
|     return tput(putt) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| put = socket.protect(function(putt, body) |  | ||||||
|     if base.type(putt) == "string" then return sput(putt, body) |  | ||||||
|     else return tput(putt) end |  | ||||||
| end) |  | ||||||
|  |  | ||||||
| local function tget(gett) |  | ||||||
|     gett = override(gett) |  | ||||||
|     socket.try(gett.host, "missing hostname") |  | ||||||
|     local f = open(gett.host, gett.port, gett.create) |  | ||||||
|     f:greet() |  | ||||||
|     f:login(gett.user, gett.password) |  | ||||||
|     if gett.type then f:type(gett.type) end |  | ||||||
|     f:pasv() |  | ||||||
|     f:receive(gett) |  | ||||||
|     f:quit() |  | ||||||
|     return f:close() |  | ||||||
| end |  | ||||||
|  |  | ||||||
| local function sget(u) |  | ||||||
|     local gett = parse(u) |  | ||||||
|     local t = {} |  | ||||||
|     gett.sink = ltn12.sink.table(t) |  | ||||||
|     tget(gett) |  | ||||||
|     return table.concat(t) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| command = socket.protect(function(cmdt) |  | ||||||
|     cmdt = override(cmdt) |  | ||||||
|     socket.try(cmdt.host, "missing hostname") |  | ||||||
|     socket.try(cmdt.command, "missing command") |  | ||||||
|     local f = open(cmdt.host, cmdt.port, cmdt.create) |  | ||||||
|     f:greet() |  | ||||||
|     f:login(cmdt.user, cmdt.password) |  | ||||||
|     f.try(f.tp:command(cmdt.command, cmdt.argument)) |  | ||||||
|     if cmdt.check then f.try(f.tp:check(cmdt.check)) end |  | ||||||
|     f:quit() |  | ||||||
|     return f:close() |  | ||||||
| end) |  | ||||||
|  |  | ||||||
| get = socket.protect(function(gett) |  | ||||||
|     if base.type(gett) == "string" then return sget(gett) |  | ||||||
|     else return tget(gett) end |  | ||||||
| end) |  | ||||||
|  |  | ||||||
| @@ -1,326 +0,0 @@ | |||||||
| ----------------------------------------------------------------------------- |  | ||||||
| -- HTTP/1.1 client support for the Lua language. |  | ||||||
| -- LuaSocket toolkit. |  | ||||||
| -- Author: Diego Nehab |  | ||||||
| -- RCS ID: $Id: http.lua,v 1.63 2005/11/22 08:33:29 diego Exp $ |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
|  |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| -- Declare module and import dependencies |  | ||||||
| ------------------------------------------------------------------------------- |  | ||||||
| local socket = require("socket") |  | ||||||
| local url = require("socket.url") |  | ||||||
| local ltn12 = require("ltn12") |  | ||||||
| local mime = require("mime") |  | ||||||
| local string = require("string") |  | ||||||
| local base = _G |  | ||||||
| local table = require("table") |  | ||||||
| module("socket.http") |  | ||||||
|  |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| -- Program constants |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| -- connection timeout in seconds |  | ||||||
| TIMEOUT = 60 |  | ||||||
| -- default port for document retrieval |  | ||||||
| PORT = 80 |  | ||||||
| -- user agent field sent in request |  | ||||||
| USERAGENT = socket._VERSION |  | ||||||
|  |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| -- Reads MIME headers from a connection, unfolding where needed |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| local function receiveheaders(sock, headers) |  | ||||||
|     local line, name, value, err |  | ||||||
|     headers = headers or {} |  | ||||||
|     -- get first line |  | ||||||
|     line, err = sock:receive() |  | ||||||
|     if err then return nil, err end |  | ||||||
|     -- headers go until a blank line is found |  | ||||||
|     while line ~= "" do |  | ||||||
|         -- get field-name and value |  | ||||||
|         name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)")) |  | ||||||
|         if not (name and value) then return nil, "malformed reponse headers" end |  | ||||||
|         name = string.lower(name) |  | ||||||
|         -- get next line (value might be folded) |  | ||||||
|         line, err  = sock:receive() |  | ||||||
|         if err then return nil, err end |  | ||||||
|         -- unfold any folded values |  | ||||||
|         while string.find(line, "^%s") do |  | ||||||
|             value = value .. line |  | ||||||
|             line = sock:receive() |  | ||||||
|             if err then return nil, err end |  | ||||||
|         end |  | ||||||
|         -- save pair in table |  | ||||||
|         if headers[name] then headers[name] = headers[name] .. ", " .. value |  | ||||||
|         else headers[name] = value end |  | ||||||
|     end |  | ||||||
|     return headers |  | ||||||
| end |  | ||||||
|  |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| -- Extra sources and sinks |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| socket.sourcet["http-chunked"] = function(sock, headers) |  | ||||||
|     return base.setmetatable({ |  | ||||||
|         getfd = function() return sock:getfd() end, |  | ||||||
|         dirty = function() return sock:dirty() end |  | ||||||
|     }, { |  | ||||||
|         __call = function() |  | ||||||
|             -- get chunk size, skip extention |  | ||||||
|             local line, err = sock:receive() |  | ||||||
|             if err then return nil, err end |  | ||||||
|             local size = base.tonumber(string.gsub(line, ";.*", ""), 16) |  | ||||||
|             if not size then return nil, "invalid chunk size" end |  | ||||||
|             -- was it the last chunk? |  | ||||||
|             if size > 0 then |  | ||||||
|                 -- if not, get chunk and skip terminating CRLF |  | ||||||
|                 local chunk, err, part = sock:receive(size) |  | ||||||
|                 if chunk then sock:receive() end |  | ||||||
|                 return chunk, err |  | ||||||
|             else |  | ||||||
|                 -- if it was, read trailers into headers table |  | ||||||
|                 headers, err = receiveheaders(sock, headers) |  | ||||||
|                 if not headers then return nil, err end |  | ||||||
|             end |  | ||||||
|         end |  | ||||||
|     }) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| socket.sinkt["http-chunked"] = function(sock) |  | ||||||
|     return base.setmetatable({ |  | ||||||
|         getfd = function() return sock:getfd() end, |  | ||||||
|         dirty = function() return sock:dirty() end |  | ||||||
|     }, { |  | ||||||
|         __call = function(self, chunk, err) |  | ||||||
|             if not chunk then return sock:send("0\r\n\r\n") end |  | ||||||
|             local size = string.format("%X\r\n", string.len(chunk)) |  | ||||||
|             return sock:send(size ..  chunk .. "\r\n") |  | ||||||
|         end |  | ||||||
|     }) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| -- Low level HTTP API |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| local metat = { __index = {} } |  | ||||||
|  |  | ||||||
| function open(host, port, create) |  | ||||||
|     -- create socket with user connect function, or with default |  | ||||||
|     local c = socket.try(create or socket.tcp)() |  | ||||||
|     local h = base.setmetatable({ c = c }, metat) |  | ||||||
|     -- create finalized try |  | ||||||
|     h.try = socket.newtry(function() h:close() end) |  | ||||||
|     -- set timeout before connecting |  | ||||||
|     h.try(c:settimeout(TIMEOUT)) |  | ||||||
|     h.try(c:connect(host, port or PORT)) |  | ||||||
|     -- here everything worked |  | ||||||
|     return h |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:sendrequestline(method, uri) |  | ||||||
|     local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri) |  | ||||||
|     return self.try(self.c:send(reqline)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:sendheaders(headers) |  | ||||||
|     local h = "\r\n" |  | ||||||
|     for i, v in base.pairs(headers) do |  | ||||||
|         h = i .. ": " .. v .. "\r\n" .. h |  | ||||||
|     end |  | ||||||
|     self.try(self.c:send(h)) |  | ||||||
|     return 1 |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:sendbody(headers, source, step) |  | ||||||
|     source = source or ltn12.source.empty() |  | ||||||
|     step = step or ltn12.pump.step |  | ||||||
|     -- if we don't know the size in advance, send chunked and hope for the best |  | ||||||
|     local mode = "http-chunked" |  | ||||||
|     if headers["content-length"] then mode = "keep-open" end |  | ||||||
|     return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:receivestatusline() |  | ||||||
|     local status = self.try(self.c:receive()) |  | ||||||
|     local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)")) |  | ||||||
|     return self.try(base.tonumber(code), status) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:receiveheaders() |  | ||||||
|     return self.try(receiveheaders(self.c)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:receivebody(headers, sink, step) |  | ||||||
|     sink = sink or ltn12.sink.null() |  | ||||||
|     step = step or ltn12.pump.step |  | ||||||
|     local length = base.tonumber(headers["content-length"]) |  | ||||||
|     local t = headers["transfer-encoding"] -- shortcut |  | ||||||
|     local mode = "default" -- connection close |  | ||||||
|     if t and t ~= "identity" then mode = "http-chunked" |  | ||||||
|     elseif base.tonumber(headers["content-length"]) then mode = "by-length" end |  | ||||||
|     return self.try(ltn12.pump.all(socket.source(mode, self.c, length), |  | ||||||
|         sink, step)) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function metat.__index:close() |  | ||||||
|     return self.c:close() |  | ||||||
| end |  | ||||||
|  |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| -- High level HTTP API |  | ||||||
| ----------------------------------------------------------------------------- |  | ||||||
| local function adjusturi(reqt) |  | ||||||
|     local u = reqt |  | ||||||
|     -- if there is a proxy, we need the full url. otherwise, just a part. |  | ||||||
|     if not reqt.proxy and not PROXY then |  | ||||||
|         u = { |  | ||||||
|            path = socket.try(reqt.path, "invalid path 'nil'"), |  | ||||||
|            params = reqt.params, |  | ||||||
|            query = reqt.query, |  | ||||||
|            fragment = reqt.fragment |  | ||||||
|         } |  | ||||||
|     end |  | ||||||
|     return url.build(u) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| local function adjustproxy(reqt) |  | ||||||
|     local proxy = reqt.proxy or PROXY |  | ||||||
|     if proxy then |  | ||||||
|         proxy = url.parse(proxy) |  | ||||||
|         return proxy.host, proxy.port or 3128 |  | ||||||
|     else |  | ||||||
|         return reqt.host, reqt.port |  | ||||||
|     end |  | ||||||
| end |  | ||||||
|  |  | ||||||
| local function adjustheaders(headers, host) |  | ||||||
|     -- default headers |  | ||||||
|     local lower = { |  | ||||||
|         ["user-agent"] = USERAGENT, |  | ||||||
|         ["host"] = host, |  | ||||||
|         ["connection"] = "close, TE", |  | ||||||
|         ["te"] = "trailers" |  | ||||||
|     } |  | ||||||
|     -- override with user headers |  | ||||||
|     for i,v in base.pairs(headers or lower) do |  | ||||||
|         lower[string.lower(i)] = v |  | ||||||
|     end |  | ||||||
|     return lower |  | ||||||
| end |  | ||||||
|  |  | ||||||
| -- default url parts |  | ||||||
| local default = { |  | ||||||
|     host = "", |  | ||||||
|     port = PORT, |  | ||||||
|     path ="/", |  | ||||||
|     scheme = "http" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| local function adjustrequest(reqt) |  | ||||||
|     -- parse url if provided |  | ||||||
|     local nreqt = reqt.url and url.parse(reqt.url, default) or {} |  | ||||||
|     local t = url.parse(reqt.url, default) |  | ||||||
|     -- explicit components override url |  | ||||||
|     for i,v in base.pairs(reqt) do nreqt[i] = v end |  | ||||||
|     socket.try(nreqt.host, "invalid host '" .. base.tostring(nreqt.host) .. "'") |  | ||||||
|     -- compute uri if user hasn't overriden |  | ||||||
|     nreqt.uri = reqt.uri or adjusturi(nreqt) |  | ||||||
|     -- ajust host and port if there is a proxy |  | ||||||
|     nreqt.host, nreqt.port = adjustproxy(nreqt) |  | ||||||
|     -- adjust headers in request |  | ||||||
|     nreqt.headers = adjustheaders(nreqt.headers, nreqt.host) |  | ||||||
|     return nreqt |  | ||||||
| end |  | ||||||
|  |  | ||||||
| local function shouldredirect(reqt, code, headers) |  | ||||||
|     return headers.location and |  | ||||||
|            string.gsub(headers.location, "%s", "") ~= "" and |  | ||||||
|            (reqt.redirect ~= false) and |  | ||||||
|            (code == 301 or code == 302) and |  | ||||||
|            (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") |  | ||||||
|            and (not reqt.nredirects or reqt.nredirects < 5) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| local function shouldauthorize(reqt, code) |  | ||||||
|     -- if there has been an authorization attempt, it must have failed |  | ||||||
|     if reqt.headers and reqt.headers["authorization"] then return nil end |  | ||||||
|     -- if last attempt didn't fail due to lack of authentication, |  | ||||||
|     -- or we don't have authorization information, we can't retry |  | ||||||
|     return code == 401 and reqt.user and reqt.password |  | ||||||
| end |  | ||||||
|  |  | ||||||
| local function shouldreceivebody(reqt, code) |  | ||||||
|     if reqt.method == "HEAD" then return nil end |  | ||||||
|     if code == 204 or code == 304 then return nil end |  | ||||||
|     if code >= 100 and code < 200 then return nil end |  | ||||||
|     return 1 |  | ||||||
| end |  | ||||||
|  |  | ||||||
| -- forward declarations |  | ||||||
| local trequest, tauthorize, tredirect |  | ||||||
|  |  | ||||||
| function tauthorize(reqt) |  | ||||||
|     local auth = "Basic " ..  (mime.b64(reqt.user .. ":" .. reqt.password)) |  | ||||||
|     reqt.headers["authorization"] = auth |  | ||||||
|     return trequest(reqt) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function tredirect(reqt, location) |  | ||||||
|     local result, code, headers, status = trequest { |  | ||||||
|         -- the RFC says the redirect URL has to be absolute, but some |  | ||||||
|         -- servers do not respect that |  | ||||||
|         url = url.absolute(reqt, location), |  | ||||||
|         source = reqt.source, |  | ||||||
|         sink = reqt.sink, |  | ||||||
|         headers = reqt.headers, |  | ||||||
|         proxy = reqt.proxy, |  | ||||||
|         nredirects = (reqt.nredirects or 0) + 1, |  | ||||||
|         connect = reqt.connect |  | ||||||
|     } |  | ||||||
|     -- pass location header back as a hint we redirected |  | ||||||
|     headers.location = headers.location or location |  | ||||||
|     return result, code, headers, status |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function trequest(reqt) |  | ||||||
|     reqt = adjustrequest(reqt) |  | ||||||
|     local h = open(reqt.host, reqt.port, reqt.create) |  | ||||||
|     h:sendrequestline(reqt.method, reqt.uri) |  | ||||||
|     h:sendheaders(reqt.headers) |  | ||||||
|     if reqt.source then h:sendbody(reqt.headers, reqt.source, reqt.step) end |  | ||||||
|     local code, headers, status |  | ||||||
|     code, status = h:receivestatusline() |  | ||||||
|     headers = h:receiveheaders() |  | ||||||
|     if shouldredirect(reqt, code, headers) then |  | ||||||
|         h:close() |  | ||||||
|         return tredirect(reqt, headers.location) |  | ||||||
|     elseif shouldauthorize(reqt, code) then |  | ||||||
|         h:close() |  | ||||||
|         return tauthorize(reqt) |  | ||||||
|     elseif shouldreceivebody(reqt, code) then |  | ||||||
|         h:receivebody(headers, reqt.sink, reqt.step) |  | ||||||
|     end |  | ||||||
|     h:close() |  | ||||||
|     return 1, code, headers, status |  | ||||||
| end |  | ||||||
|  |  | ||||||
| local function srequest(u, body) |  | ||||||
|     local t = {} |  | ||||||
|     local reqt = { |  | ||||||
|         url = u, |  | ||||||
|         sink = ltn12.sink.table(t) |  | ||||||
|     } |  | ||||||
|     if body then |  | ||||||
|         reqt.source = ltn12.source.string(body) |  | ||||||
|         reqt.headers = { ["content-length"] = string.len(body) } |  | ||||||
|         reqt.method = "POST" |  | ||||||
|     end |  | ||||||
|     local code, headers, status = socket.skip(1, trequest(reqt)) |  | ||||||
|     return table.concat(t), code, headers, status |  | ||||||
| end |  | ||||||
|  |  | ||||||
| request = socket.protect(function(reqt, body) |  | ||||||
|     if base.type(reqt) == "string" then return srequest(reqt, body) |  | ||||||
|     else return trequest(reqt) end |  | ||||||
| end) |  | ||||||
| @@ -1,281 +0,0 @@ | |||||||
| /*=========================================================================*\ |  | ||||||
| * Internet domain functions |  | ||||||
| * LuaSocket toolkit |  | ||||||
| * |  | ||||||
| * RCS ID: $Id: inet.c,v 1.28 2005/10/07 04:40:59 diego Exp $ |  | ||||||
| \*=========================================================================*/ |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <string.h> |  | ||||||
|  |  | ||||||
| #include "lua.h" |  | ||||||
| #include "lauxlib.h" |  | ||||||
|  |  | ||||||
| #include "inet.h" |  | ||||||
|  |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Internal function prototypes. |  | ||||||
| \*=========================================================================*/ |  | ||||||
| static int inet_global_toip(lua_State *L); |  | ||||||
| static int inet_global_tohostname(lua_State *L); |  | ||||||
| static void inet_pushresolved(lua_State *L, struct hostent *hp); |  | ||||||
| static int inet_global_gethostname(lua_State *L); |  | ||||||
|  |  | ||||||
| /* DNS functions */ |  | ||||||
| static luaL_reg func[] = { |  | ||||||
|     { "toip", inet_global_toip }, |  | ||||||
|     { "tohostname", inet_global_tohostname }, |  | ||||||
|     { "gethostname", inet_global_gethostname}, |  | ||||||
|     { NULL, NULL} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Exported functions |  | ||||||
| \*=========================================================================*/ |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Initializes module |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| int inet_open(lua_State *L) |  | ||||||
| { |  | ||||||
|     lua_pushstring(L, "dns"); |  | ||||||
|     lua_newtable(L); |  | ||||||
|     luaL_openlib(L, NULL, func, 0); |  | ||||||
|     lua_settable(L, -3); |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Global Lua functions |  | ||||||
| \*=========================================================================*/ |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Returns all information provided by the resolver given a host name |  | ||||||
| * or ip address |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| static int inet_gethost(const char *address, struct hostent **hp) { |  | ||||||
|     struct in_addr addr; |  | ||||||
|     if (inet_aton(address, &addr)) |  | ||||||
|         return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp); |  | ||||||
|     else  |  | ||||||
|         return socket_gethostbyname(address, hp); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Returns all information provided by the resolver given a host name |  | ||||||
| * or ip address |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| static int inet_global_tohostname(lua_State *L) { |  | ||||||
|     const char *address = luaL_checkstring(L, 1); |  | ||||||
|     struct hostent *hp = NULL;  |  | ||||||
|     int err = inet_gethost(address, &hp); |  | ||||||
|     if (err != IO_DONE) { |  | ||||||
|         lua_pushnil(L); |  | ||||||
|         lua_pushstring(L, socket_hoststrerror(err)); |  | ||||||
|         return 2; |  | ||||||
|     } |  | ||||||
|     lua_pushstring(L, hp->h_name); |  | ||||||
|     inet_pushresolved(L, hp); |  | ||||||
|     return 2; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Returns all information provided by the resolver given a host name |  | ||||||
| * or ip address |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| static int inet_global_toip(lua_State *L) |  | ||||||
| { |  | ||||||
|     const char *address = luaL_checkstring(L, 1); |  | ||||||
|     struct hostent *hp = NULL;  |  | ||||||
|     int err = inet_gethost(address, &hp); |  | ||||||
|     if (err != IO_DONE) { |  | ||||||
|         lua_pushnil(L); |  | ||||||
|         lua_pushstring(L, socket_hoststrerror(err)); |  | ||||||
|         return 2; |  | ||||||
|     } |  | ||||||
|     lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr))); |  | ||||||
|     inet_pushresolved(L, hp); |  | ||||||
|     return 2; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Gets the host name |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| static int inet_global_gethostname(lua_State *L) |  | ||||||
| { |  | ||||||
|     char name[257]; |  | ||||||
|     name[256] = '\0'; |  | ||||||
|     if (gethostname(name, 256) < 0) { |  | ||||||
|         lua_pushnil(L); |  | ||||||
|         lua_pushstring(L, "gethostname failed"); |  | ||||||
|         return 2; |  | ||||||
|     } else { |  | ||||||
|         lua_pushstring(L, name); |  | ||||||
|         return 1; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Lua methods |  | ||||||
| \*=========================================================================*/ |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Retrieves socket peer name |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| int inet_meth_getpeername(lua_State *L, p_socket ps) |  | ||||||
| { |  | ||||||
|     struct sockaddr_in peer; |  | ||||||
|     socklen_t peer_len = sizeof(peer); |  | ||||||
|     if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { |  | ||||||
|         lua_pushnil(L); |  | ||||||
|         lua_pushstring(L, "getpeername failed"); |  | ||||||
|     } else { |  | ||||||
|         lua_pushstring(L, inet_ntoa(peer.sin_addr)); |  | ||||||
|         lua_pushnumber(L, ntohs(peer.sin_port)); |  | ||||||
|     } |  | ||||||
|     return 2; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Retrieves socket local name |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| int inet_meth_getsockname(lua_State *L, p_socket ps) |  | ||||||
| { |  | ||||||
|     struct sockaddr_in local; |  | ||||||
|     socklen_t local_len = sizeof(local); |  | ||||||
|     if (getsockname(*ps, (SA *) &local, &local_len) < 0) { |  | ||||||
|         lua_pushnil(L); |  | ||||||
|         lua_pushstring(L, "getsockname failed"); |  | ||||||
|     } else { |  | ||||||
|         lua_pushstring(L, inet_ntoa(local.sin_addr)); |  | ||||||
|         lua_pushnumber(L, ntohs(local.sin_port)); |  | ||||||
|     } |  | ||||||
|     return 2; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Internal functions |  | ||||||
| \*=========================================================================*/ |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Passes all resolver information to Lua as a table |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| static void inet_pushresolved(lua_State *L, struct hostent *hp) |  | ||||||
| { |  | ||||||
|     char **alias; |  | ||||||
|     struct in_addr **addr; |  | ||||||
|     int i, resolved; |  | ||||||
|     lua_newtable(L); resolved = lua_gettop(L); |  | ||||||
|     lua_pushstring(L, "name"); |  | ||||||
|     lua_pushstring(L, hp->h_name); |  | ||||||
|     lua_settable(L, resolved); |  | ||||||
|     lua_pushstring(L, "ip"); |  | ||||||
|     lua_pushstring(L, "alias"); |  | ||||||
|     i = 1; |  | ||||||
|     alias = hp->h_aliases; |  | ||||||
|     lua_newtable(L); |  | ||||||
|     if (alias) { |  | ||||||
|         while (*alias) { |  | ||||||
|             lua_pushnumber(L, i); |  | ||||||
|             lua_pushstring(L, *alias); |  | ||||||
|             lua_settable(L, -3); |  | ||||||
|             i++; alias++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     lua_settable(L, resolved); |  | ||||||
|     i = 1; |  | ||||||
|     lua_newtable(L); |  | ||||||
|     addr = (struct in_addr **) hp->h_addr_list; |  | ||||||
|     if (addr) { |  | ||||||
|         while (*addr) { |  | ||||||
|             lua_pushnumber(L, i); |  | ||||||
|             lua_pushstring(L, inet_ntoa(**addr)); |  | ||||||
|             lua_settable(L, -3); |  | ||||||
|             i++; addr++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     lua_settable(L, resolved); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Tries to create a new inet socket |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| const char *inet_trycreate(p_socket ps, int type) { |  | ||||||
|     return socket_strerror(socket_create(ps, AF_INET, type, 0)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Tries to connect to remote address (address, port) |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| const char *inet_tryconnect(p_socket ps, const char *address,  |  | ||||||
|         unsigned short port, p_timeout tm) |  | ||||||
| { |  | ||||||
|     struct sockaddr_in remote; |  | ||||||
|     int err; |  | ||||||
|     memset(&remote, 0, sizeof(remote)); |  | ||||||
|     remote.sin_family = AF_INET; |  | ||||||
|     remote.sin_port = htons(port); |  | ||||||
| 	if (strcmp(address, "*")) { |  | ||||||
|         if (!inet_aton(address, &remote.sin_addr)) { |  | ||||||
|             struct hostent *hp = NULL; |  | ||||||
|             struct in_addr **addr; |  | ||||||
|             err = socket_gethostbyname(address, &hp); |  | ||||||
|             if (err != IO_DONE) return socket_hoststrerror(err); |  | ||||||
|             addr = (struct in_addr **) hp->h_addr_list; |  | ||||||
|             memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); |  | ||||||
|         } |  | ||||||
|     } else remote.sin_family = AF_UNSPEC; |  | ||||||
|     err = socket_connect(ps, (SA *) &remote, sizeof(remote), tm); |  | ||||||
|     return socket_strerror(err); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Tries to bind socket to (address, port) |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| const char *inet_trybind(p_socket ps, const char *address, unsigned short port) |  | ||||||
| { |  | ||||||
|     struct sockaddr_in local; |  | ||||||
|     int err; |  | ||||||
|     memset(&local, 0, sizeof(local)); |  | ||||||
|     /* address is either wildcard or a valid ip address */ |  | ||||||
|     local.sin_addr.s_addr = htonl(INADDR_ANY); |  | ||||||
|     local.sin_port = htons(port); |  | ||||||
|     local.sin_family = AF_INET; |  | ||||||
|     if (strcmp(address, "*") && !inet_aton(address, &local.sin_addr)) { |  | ||||||
|         struct hostent *hp = NULL; |  | ||||||
|         struct in_addr **addr; |  | ||||||
|         err = socket_gethostbyname(address, &hp); |  | ||||||
|         if (err != IO_DONE) return socket_hoststrerror(err); |  | ||||||
|         addr = (struct in_addr **) hp->h_addr_list; |  | ||||||
|         memcpy(&local.sin_addr, *addr, sizeof(struct in_addr)); |  | ||||||
|     } |  | ||||||
|     err = socket_bind(ps, (SA *) &local, sizeof(local)); |  | ||||||
|     if (err != IO_DONE) socket_destroy(ps); |  | ||||||
|     return socket_strerror(err);  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Some systems do not provide this so that we provide our own. It's not |  | ||||||
| * marvelously fast, but it works just fine. |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| #ifdef INET_ATON |  | ||||||
| int inet_aton(const char *cp, struct in_addr *inp) |  | ||||||
| { |  | ||||||
|     unsigned int a = 0, b = 0, c = 0, d = 0; |  | ||||||
|     int n = 0, r; |  | ||||||
|     unsigned long int addr = 0; |  | ||||||
|     r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n); |  | ||||||
|     if (r == 0 || n == 0) return 0; |  | ||||||
|     cp += n; |  | ||||||
|     if (*cp) return 0; |  | ||||||
|     if (a > 255 || b > 255 || c > 255 || d > 255) return 0; |  | ||||||
|     if (inp) { |  | ||||||
|         addr += a; addr <<= 8; |  | ||||||
|         addr += b; addr <<= 8; |  | ||||||
|         addr += c; addr <<= 8; |  | ||||||
|         addr += d; |  | ||||||
|         inp->s_addr = htonl(addr); |  | ||||||
|     } |  | ||||||
|     return 1; |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,42 +0,0 @@ | |||||||
| #ifndef INET_H  |  | ||||||
| #define INET_H  |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Internet domain functions |  | ||||||
| * LuaSocket toolkit |  | ||||||
| * |  | ||||||
| * This module implements the creation and connection of internet domain |  | ||||||
| * sockets, on top of the socket.h interface, and the interface of with the |  | ||||||
| * resolver.  |  | ||||||
| * |  | ||||||
| * The function inet_aton is provided for the platforms where it is not |  | ||||||
| * available. The module also implements the interface of the internet |  | ||||||
| * getpeername and getsockname functions as seen by Lua programs. |  | ||||||
| * |  | ||||||
| * The Lua functions toip and tohostname are also implemented here. |  | ||||||
| * |  | ||||||
| * RCS ID: $Id: inet.h,v 1.16 2005/10/07 04:40:59 diego Exp $ |  | ||||||
| \*=========================================================================*/ |  | ||||||
| #include "lua.h" |  | ||||||
| #include "socket.h" |  | ||||||
| #include "timeout.h" |  | ||||||
|  |  | ||||||
| #ifdef _WIN32 |  | ||||||
| #define INET_ATON |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| int inet_open(lua_State *L); |  | ||||||
|  |  | ||||||
| const char *inet_trycreate(p_socket ps, int type); |  | ||||||
| const char *inet_tryconnect(p_socket ps, const char *address,  |  | ||||||
|         unsigned short port, p_timeout tm); |  | ||||||
| const char *inet_trybind(p_socket ps, const char *address,  |  | ||||||
|         unsigned short port); |  | ||||||
|  |  | ||||||
| int inet_meth_getpeername(lua_State *L, p_socket ps); |  | ||||||
| int inet_meth_getsockname(lua_State *L, p_socket ps); |  | ||||||
|  |  | ||||||
| #ifdef INET_ATON |  | ||||||
| int inet_aton(const char *cp, struct in_addr *inp); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #endif /* INET_H */ |  | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| /*=========================================================================*\ |  | ||||||
| * Input/Output abstraction |  | ||||||
| * LuaSocket toolkit |  | ||||||
| * |  | ||||||
| * RCS ID: $Id: io.c,v 1.6 2005/09/29 06:11:41 diego Exp $ |  | ||||||
| \*=========================================================================*/ |  | ||||||
| #include "io.h" |  | ||||||
|  |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Exported functions |  | ||||||
| \*=========================================================================*/ |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * Initializes C structure |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx) { |  | ||||||
|     io->send = send; |  | ||||||
|     io->recv = recv; |  | ||||||
|     io->error = error; |  | ||||||
|     io->ctx = ctx; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*-------------------------------------------------------------------------*\ |  | ||||||
| * I/O error strings |  | ||||||
| \*-------------------------------------------------------------------------*/ |  | ||||||
| const char *io_strerror(int err) { |  | ||||||
|     switch (err) { |  | ||||||
|         case IO_DONE: return NULL; |  | ||||||
|         case IO_CLOSED: return "closed"; |  | ||||||
|         case IO_TIMEOUT: return "timeout"; |  | ||||||
|         default: return "unknown error";  |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,67 +0,0 @@ | |||||||
| #ifndef IO_H |  | ||||||
| #define IO_H |  | ||||||
| /*=========================================================================*\ |  | ||||||
| * Input/Output abstraction |  | ||||||
| * LuaSocket toolkit |  | ||||||
| * |  | ||||||
| * This module defines the interface that LuaSocket expects from the |  | ||||||
| * transport layer for streamed input/output. The idea is that if any |  | ||||||
| * transport implements this interface, then the buffer.c functions |  | ||||||
| * automatically work on it. |  | ||||||
| * |  | ||||||
| * The module socket.h implements this interface, and thus the module tcp.h |  | ||||||
| * is very simple. |  | ||||||
| * |  | ||||||
| * RCS ID: $Id: io.h,v 1.11 2005/10/07 04:40:59 diego Exp $ |  | ||||||
| \*=========================================================================*/ |  | ||||||
| #include <stdio.h> |  | ||||||
| #include "lua.h" |  | ||||||
|  |  | ||||||
| #include "timeout.h" |  | ||||||
|  |  | ||||||
| /* IO error codes */ |  | ||||||
| enum { |  | ||||||
|     IO_DONE = 0,        /* operation completed successfully */ |  | ||||||
|     IO_TIMEOUT = -1,    /* operation timed out */ |  | ||||||
|     IO_CLOSED = -2,     /* the connection has been closed */ |  | ||||||
| 	IO_UNKNOWN = -3 |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /* interface to error message function */ |  | ||||||
| typedef const char *(*p_error) ( |  | ||||||
|     void *ctx,          /* context needed by send */ |  | ||||||
|     int err             /* error code */ |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| /* interface to send function */ |  | ||||||
| typedef int (*p_send) ( |  | ||||||
|     void *ctx,          /* context needed by send */ |  | ||||||
|     const char *data,   /* pointer to buffer with data to send */ |  | ||||||
|     size_t count,       /* number of bytes to send from buffer */ |  | ||||||
|     size_t *sent,       /* number of bytes sent uppon return */ |  | ||||||
|     p_timeout tm        /* timeout control */ |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| /* interface to recv function */ |  | ||||||
| typedef int (*p_recv) ( |  | ||||||
|     void *ctx,          /* context needed by recv */ |  | ||||||
|     char *data,         /* pointer to buffer where data will be writen */ |  | ||||||
|     size_t count,       /* number of bytes to receive into buffer */ |  | ||||||
|     size_t *got,        /* number of bytes received uppon return */ |  | ||||||
|     p_timeout tm        /* timeout control */ |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| /* IO driver definition */ |  | ||||||
| typedef struct t_io_ { |  | ||||||
|     void *ctx;          /* context needed by send/recv */ |  | ||||||
|     p_send send;        /* send function pointer */ |  | ||||||
|     p_recv recv;        /* receive function pointer */ |  | ||||||
|     p_error error;      /* strerror function */ |  | ||||||
| } t_io; |  | ||||||
| typedef t_io *p_io; |  | ||||||
|  |  | ||||||
| void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx); |  | ||||||
| const char *io_strerror(int err); |  | ||||||
|  |  | ||||||
| #endif /* IO_H */ |  | ||||||
|  |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user