Compare commits

...

331 Commits

Author SHA1 Message Date
Cloud Wu
6a54fe8293 1.0.0 rc4 2016-06-13 15:13:17 +08:00
Cloud Wu
2020ce3c9c update jemalloc to 4.2.1 2016-06-13 15:08:33 +08:00
云风
2557559d5c Merge pull request #512 from cloudwu/createindex
add createindexes , for detail see pr #511
2016-06-13 13:12:57 +08:00
Cloud Wu
bb0143e476 add some assert 2016-06-13 12:29:01 +08:00
Cloud Wu
fd2c814fe0 default key ascending 2016-06-13 12:13:02 +08:00
Cloud Wu
bd3d9b70ec change arg name 2016-06-13 12:05:52 +08:00
Cloud Wu
ee1a218870 typo 2016-06-13 12:01:54 +08:00
Cloud Wu
84ee3da79a add mongo.createIndexs, and fix the bug in old API createIndex. For detail, see PR #511 2016-06-13 11:55:31 +08:00
云风
fdee7de36d Merge pull request #509 from dpull/master
重新设计debug.lua接口
2016-06-12 16:41:18 +08:00
dpull
bf5b74b6ca 重新设计debug.lua接口 2016-06-12 16:29:47 +08:00
Cloud Wu
d9b0347741 don't close fd twice 2016-06-12 15:07:56 +08:00
Cloud Wu
9546537256 debug console support simple http 2016-06-12 14:51:18 +08:00
Cloud Wu
f84fe84b96 update userlog 2016-06-12 13:48:53 +08:00
Cloud Wu
ea9bc53261 reopen log file when recv signal HUP 2016-06-12 13:40:23 +08:00
Cloud Wu
0edb839c95 Lua 5.3.3 released 2016-06-07 09:43:43 +08:00
Cloud Wu
b8bb327f98 make coroutine_pool weak would be better 2016-06-06 16:23:39 +08:00
cloudwu
27d69334ee Merge pull request #506 from rickone/master
Update socketchannel.lua
2016-06-05 01:07:42 +08:00
rickone
838e63ab62 Update socketchannel.lua
request的时候可能会连接失败,这时raise的不是socket_error,上层处理不太统一。
2016-06-04 16:26:07 +08:00
Cloud Wu
ba264700dc update jemalloc to 4.2.0 2016-05-31 09:36:21 +08:00
Cloud Wu
e00ad7ab79 update to lua 5.3.3 rc3 2016-05-31 09:30:21 +08:00
Cloud Wu
de176b735f update to lua 5.3.3 rc2 2016-05-19 13:16:19 +08:00
cloudwu
cc3e985834 Merge pull request #502 from pigparadise/cloudwu
lua_bson的encode方法增加对有自定义__pairs的table的支持
2016-05-19 13:19:21 +08:00
LiuYang
3b5f45eea2 lua_bson的encode方法增加对有自定义__pairs的table的支持 2016-05-19 13:10:33 +08:00
cloudwu
c3056b04c1 Merge pull request #498 from asanosoyokaze/patch-1
add vararg for INFO debug console command
2016-05-16 19:35:02 +08:00
David Feng
58755a6772 add vararg for INFO debug console command 2016-05-16 18:57:40 +08:00
Cloud Wu
1cf976c4e4 add debug console command : ping 2016-05-13 09:46:44 +08:00
Cloud Wu
5be836527c bugfix issue #494 2016-05-11 22:02:10 +08:00
Cloud Wu
e9f397945d bugfix issue #494 2016-05-10 16:59:34 +08:00
Cloud Wu
78df0b8161 refine code 2016-05-09 19:16:29 +08:00
cloudwu
db17245005 Merge pull request #493 from chenkete/master
修复redis auth操作没有进行compose_message的bug,该bug导致skynet连接twemproxy时,auth失败
2016-05-09 19:17:56 +08:00
chenkete
4edb586077 修复redis auth操作没有进行compose_message的bug,该bug导致skynet连接twemproxy时,auth失败 2016-05-09 17:16:37 +08:00
Cloud Wu
ed1a8313f4 1.0.0 rc3 2016-05-09 10:06:32 +08:00
Cloud Wu
c450b7b5d7 update jemaloc to 4.1.1 2016-05-09 09:56:30 +08:00
Cloud Wu
56846b7dda new script to check deadloop service 2016-05-09 09:47:01 +08:00
Cloud Wu
fb232cc43e update lua to 5.3.3 rc1 2016-05-09 09:45:40 +08:00
Cloud Wu
a5c79cc4bd move skynet.memlimit from skynet.manager to skynet 2016-05-07 09:23:01 +08:00
Cloud Wu
4b96ade660 support sandbox memory limit 2016-05-06 23:40:44 +08:00
Cloud Wu
76d1e6fa1f memory warning 2016-05-06 20:37:51 +08:00
Cloud Wu
a6299a0748 optimize skynet.error 2016-05-06 20:10:11 +08:00
Cloud Wu
6cc558bb82 output Exit when new service exit 2016-05-06 19:45:50 +08:00
Cloud Wu
84b08bf286 detect console fd closed 2016-05-06 19:37:16 +08:00
Cloud Wu
4ada09b93c add pcall in launcher 2016-05-06 14:06:38 +08:00
Cloud Wu
2862568eca typo in history 2016-04-29 16:25:12 +08:00
cloudwu
ed2e16a346 Merge pull request #491 from asanosoyokaze/patch-go
skynet.pcall support vararg; sharedata loader can use custom args
2016-04-27 21:44:59 +08:00
David Feng
45d46b9072 skynet.pcall support vararg; sharedata loader can use custom args 2016-04-27 20:53:05 +08:00
Cloud Wu
4924c6d30b Merge branch 'master' of github.com:cloudwu/skynet 2016-04-20 22:35:29 +08:00
Cloud Wu
6b2eb80188 fix #487 2016-04-20 22:35:01 +08:00
cloudwu
298e4baf0e Merge pull request #485 from dpull/patch-1
给dbgcmd增加扩展性
2016-04-20 10:24:54 +08:00
Cloud Wu
c5fb93823a update sproto, fix bug in sproto.default 2016-04-20 10:11:55 +08:00
Acai
f238113677 给dbgcmd增加扩展性
我们项目增加了一个dbgcmd的指令,主要用于热更新,但在升级skynet版本时,需要记得合并这个差异,感觉挺挫的。

但现有的debug.lua并不利于扩展,于是呢,我想通过给debug.lua增加一个upvalue来解决这个问题。

其实也是解决的挺挫的 :)
2016-04-19 21:11:31 +08:00
Cloud Wu
f56d777cc2 for compatible 2016-04-18 12:05:46 +08:00
Cloud Wu
b124d4c1b8 skynet.getenv can return empty string 2016-04-18 11:55:39 +08:00
cloudwu
4fe098713f Merge pull request #483 from t0350/master
bugfix, error when use lua apicheck
2016-04-08 10:34:45 +08:00
caijietao
146f8ea09d bugfix, error when use lua apicheck 2016-04-08 10:29:34 +08:00
Cloud Wu
69b5bd8c13 update sproto. support encode empty table 2016-04-07 10:12:30 +08:00
cloudwu
dd7e962c94 Merge pull request #480 from rickone/master
Update redis.lua
2016-04-01 14:33:10 +08:00
rickone
5332021086 Update redis.lua
exec执行时其中一条出错,看不到错误信息
2016-04-01 12:39:09 +08:00
Cloud Wu
8de3149485 request global name from master, see issue #476 2016-04-01 10:22:57 +08:00
cloudwu
e3fee604e1 Merge pull request #478 from xjdrew/skynet_init
skynet.init按照顺序初始化
2016-03-31 17:51:29 +08:00
xjdrew
dd152fc910 skynet.init按照顺序初始化 2016-03-31 17:33:47 +08:00
Cloud Wu
c4b45acae3 sproto: check args 2016-03-29 12:34:55 +08:00
cloudwu
cf50a582f2 Merge pull request #474 from felixonmars/patch-1
Improve some English in README
2016-03-24 17:53:00 +08:00
Felix Yan
ca5e855c34 Improve some English in README 2016-03-24 17:48:43 +08:00
Cloud Wu
13d1d9fc9d update jemalloc to 4.1.0 2016-03-24 16:29:00 +08:00
Cloud Wu
242ff32bca lua 5.3.2 bugfix 2/3 2016-03-24 16:19:06 +08:00
cloudwu
ba451c1cd2 Merge pull request #465 from mrvon/master
skynet.coroutine
2016-03-11 15:28:56 +08:00
dennis
e5490522ce this line is useless 2016-03-09 17:50:33 +08:00
dennis
ae717c3e7d Merge remote-tracking branch 'upstream/master' 2016-03-09 17:48:16 +08:00
cloudwu
1a7df9108a Merge pull request #463 from great90/master
delete unused local variable
2016-03-08 11:34:25 +08:00
great90
7771e180ec delete unused local variable
delete unused local variable table "udp_socket"
2016-03-08 11:25:59 +08:00
great90
82bbb1c944 Merge pull request #3 from cloudwu/master
release rc2
2016-03-08 11:21:18 +08:00
Cloud Wu
cbf22ac9f3 release rc2 2016-03-07 11:46:30 +08:00
great90
bacaf10f1b Merge pull request #2 from cloudwu/master
update from cloudwu
2016-03-02 09:08:40 +08:00
Cloud Wu
8f7fa6a562 merge sproto 2016-02-25 14:40:24 +08:00
cloudwu
7b96eb28eb Merge pull request #455 from niuys/patch-2
error deal for query containing multi statement
2016-02-22 16:15:51 +08:00
snail
14ccf96eb0 error deal for query containing multi statement
A query may execute multi sql statements.If an error occurs for any sql, the result should return the error info.
2016-02-22 11:23:35 +08:00
dennis
6303886b8c Merge remote-tracking branch 'upstream/master' 2016-02-15 10:12:09 +08:00
Cloud Wu
ea8557296b fix issue #450 2016-02-13 19:20:07 +08:00
cloudwu
2a821fb62a Merge pull request #445 from DavidFeng/patch
fix
2016-01-27 13:55:14 +08:00
David Feng
d982009260 fix 2016-01-27 10:35:48 +08:00
cloudwu
a3f028ee3d Merge pull request #444 from DavidFeng/patch-1
修复调试模块调试结束后定时器没有取消的问题
2016-01-22 11:05:04 +08:00
David Feng
d34b092cdd remotedebug.lua call skynet.timeout() only in debug hook
定时器在debug结束后没有取消。
2016-01-22 10:28:03 +08:00
David Feng
77f4071191 remove unused local variables 2016-01-22 10:26:13 +08:00
cloudwu
653b29145d Merge pull request #442 from DavidFeng/patch-2
change socket.write to socketdriver.send
2016-01-20 22:05:23 +08:00
David Feng
96e0a4e3cc change socket.write to socketdriver.send
这样改过之后可以直接调试使用了gate服务的模块。
因为gate服务注册了socket类型的消息,所以不能和socket模块一块使用;而debug模块只使用到了socket模块的write函数,所以这样修改后对debug的功能并没有影响,但改过之后就可以调试gate服务了。
2016-01-20 19:24:58 +08:00
Cloud Wu
1da92850a0 bugfix: dispatch local global message queue 2016-01-19 17:14:52 +08:00
Cloud Wu
9747cf9aee don't assert here 2016-01-19 16:16:18 +08:00
Cloud Wu
7f45b3fd10 correct maxsz 2016-01-13 13:13:31 +08:00
cloudwu
217ab47577 Merge pull request #435 from niuys/patch-1
reduce needless 'add_string' call
2016-01-11 15:56:52 +08:00
snail
532f47444b reduce needless 'add_string' call
Short strings in lua proto are reused most of the time. The string in SSM may be added by one service and used by other service,  there is no need to call `add_string`,which will call 'new_string' first.
2016-01-11 15:06:51 +08:00
Cloud Wu
24f9ee1560 work thread for channel may not create if you never connect 2016-01-08 18:34:45 +08:00
Cloud Wu
d7a76c7c72 If no content-length, read all. see issue #431 2016-01-07 16:01:17 +08:00
Cloud Wu
c175d66e23 remove unused function 2016-01-06 16:55:15 +08:00
dennis
30cbcfd013 Merge remote-tracking branch 'upstream/master' 2016-01-06 15:57:42 +08:00
Cloud Wu
05003e3e2a sproto.attach also need ud 2016-01-05 17:51:48 +08:00
Cloud Wu
64c2cb1b51 sproto dispatch support ud 2016-01-05 16:06:20 +08:00
cloudwu
7f0e4eac8a Merge pull request #428 from fztcjjl/master
fix comment error
2016-01-04 16:07:50 +08:00
Cloud Wu
141a4d0992 lua 5.3.2 bugfix,see http://lua-users.org/lists/lua-l/2016-01/msg00000.html 2016-01-04 16:01:03 +08:00
fztcjjl
645ce72e7e fix comment error 2016-01-04 14:55:28 +08:00
cloudwu
fca4d67a43 Merge pull request #425 from DeanHH/patch-1
Update skynet_mq.c
2016-01-01 00:08:23 +08:00
DeanHH
014cbb9676 Update skynet_mq.c
Comment error:-)
2015-12-31 17:31:08 +08:00
Dennis
a39e822184 Merge pull request #1 from cloudwu/master
update from origin
2015-12-30 09:51:58 +08:00
Cloud Wu
a3a7d129ab V1.0.0 RC 2015-12-28 13:55:01 +08:00
cloudwu
2e69370594 Merge pull request #418 from m2q1n9/master
fix a debug_console error
2015-12-28 00:15:29 +08:00
m2q1n9
bcdfcde72f fix code indent 2015-12-27 22:38:58 +08:00
Cloud Wu
0c4ea81709 EAGAIN and EWOULDBLOCK may be not the same value, see issue #420 2015-12-27 19:31:32 +08:00
m2q1n9
b9ad559992 fix a debug_console error 2015-12-25 17:24:50 +08:00
Cloud Wu
f0ac66787e socket channel connect should wait for last closing 2015-12-23 20:22:46 +08:00
Cloud Wu
5a1b2e51f7 exit dispatch_by_order when close channel 2015-12-23 19:55:42 +08:00
Cloud Wu
7acf6d8767 remove unused varargs 2015-12-18 23:28:55 +08:00
Cloud Wu
20610723a1 add debug api to show current service c memory 2015-12-17 22:13:51 +08:00
Cloud Wu
9d6bde01a3 profile support skynet coroutine 2015-12-17 20:41:02 +08:00
Cloud Wu
4a80a75fd6 skynet.coroutine.status may return blocked 2015-12-17 17:11:54 +08:00
Cloud Wu
872491e968 Add skynet.coroutine module 2015-12-17 16:25:24 +08:00
cloudwu
41252e8c21 Merge pull request #414 from DavidFeng/patch-1
fix typo
2015-12-17 16:16:38 +08:00
David Feng
a9fc577560 fix typo
fix a little mistake
2015-12-17 15:53:39 +08:00
Cloud Wu
4f8427a23f close socket when sp_add failed 2015-12-17 10:04:38 +08:00
cloudwu
8ff5bcb372 Merge pull request #410 from kezhuw/bugfix_dangling_c_pointer_to_lua_string
Fix dangling c pointer to lua string value
2015-12-15 00:56:40 +08:00
Kezhu Wang
bfe8eeb4b3 Fix dangling c pointer to lua string value
Lua string object referenced by C pointer from lua_tolstring() was
removed from stack by lua_settop(L,0).

Lua 5.3 Reference Manual says:

> Because Lua has garbage collection, there is no guarantee that the
> pointer returned by lua_tolstring will be valid after the
> corresponding Lua value is removed from the stack.

That is it.

Introduced in commit 9937081854.
2015-12-14 16:16:37 +08:00
Cloud Wu
ccb9cdbc9d update sproto schema 2015-12-14 12:25:26 +08:00
cloudwu
4006faac29 Merge pull request #407 from linse073/patch-3
loginserver.lua中的launch_slave的lua消息处理函数的return问题
2015-12-08 13:31:16 +08:00
linse073
03617f23a1 loginserver.lua中的launch_slave的lua消息处理函数的return问题
之前可能是我没有表述清楚,这两个return我猜想是不是手误加上去的,因为之前都没有见过需要在消息处理函数里面return skynet.ret调用的结果,实际去掉后测试也是没有问题的,和是不是两次pcall的调用应该是没有关系的。
2015-12-07 21:00:19 +08:00
Cloud Wu
d4d188541f add socket.close_fd 2015-12-06 16:48:28 +08:00
Cloud Wu
3a2766dd0e return results, see pr #403 2015-12-04 10:47:30 +08:00
Cloud Wu
1431f55d28 update readme 2015-12-03 15:37:43 +08:00
cloudwu
22c0d3ab73 Merge pull request #396 from niuys/patch-6
close file handle clearly
2015-12-01 21:52:38 +08:00
snail
940a7ac58c close file handle clearly
Although 'f'  would be closed after collected, maybe it's better to close it clearly
2015-12-01 20:17:03 +08:00
Cloud Wu
05605e62a9 core.querytype doesn't raise error, see issue #395 2015-12-01 17:09:32 +08:00
Cloud Wu
3a527f0a66 update lua to 5.3.2 2015-11-30 20:31:56 +08:00
Cloud Wu
e47a4921fa bugfix. remote publish first, see issue #391 2015-11-27 18:13:50 +08:00
Cloud Wu
c180036bed use async dns resolve in httpc, and dns resolve cache by ttl. see about issue #253 2015-11-25 13:09:41 +08:00
Cloud Wu
d35388581f big number in sproto 2015-11-23 16:12:57 +08:00
Cloud Wu
2c3f3ac3c6 more sproto wire protocol examples 2015-11-23 12:47:29 +08:00
cloudwu
09670ee733 Merge pull request #383 from DavidFeng/patch-1
fix typo
2015-11-22 19:39:30 +08:00
David Feng
fbbda08bb2 fix typo 2015-11-21 15:36:25 +08:00
Cloud Wu
0f454fe248 Merge branch 'master' of github.com:cloudwu/skynet 2015-11-19 22:51:55 +08:00
Cloud Wu
91c720ad6f add assert for socket fd reuse 2015-11-19 22:51:43 +08:00
Cloud Wu
3335ea11d7 dummy luaS_expandshr 2015-11-19 21:02:46 +08:00
Cloud Wu
8d83881808 use CLOCK_MONOTONIC maybe better 2015-11-18 10:19:51 +08:00
Cloud Wu
f4437948ca fix Issue #377 2015-11-16 22:42:44 +08:00
Cloud Wu
2252409eaa add skynet_now() for 64bit time 2015-11-16 19:48:38 +08:00
Cloud Wu
87bc0815f6 bugfix: add lightuserdata 2015-11-13 17:28:02 +08:00
Cloud Wu
30859a1244 make cache 2015-11-13 13:25:33 +08:00
Cloud Wu
107be7ee8c rewrite redis driver , avoid table.concat 2015-11-13 12:30:46 +08:00
Cloud Wu
86d9d52308 Merge branch 'gitfancode-master' 2015-11-13 11:05:09 +08:00
Cloud Wu
9982cb6652 Merge branch 'master' of https://github.com/gitfancode/skynet into gitfancode-master 2015-11-13 11:04:51 +08:00
Cloud Wu
ce50c47c2b socket.send support strings table 2015-11-13 11:04:02 +08:00
xiefan
34d9b5555d reds pipeline v2(support function as pipeline params)
fix a bug & add function as pipeline params
2015-11-13 08:16:47 +08:00
xiefan
85062632bb Merge remote-tracking branch 'cloudwu/master' 2015-11-13 08:14:49 +08:00
xiefan
d2396f9d20 Revert "redis pipeline"
This reverts commit 471aecd708.
2015-11-13 08:10:33 +08:00
xiefan
471aecd708 redis pipeline
redis pipeline
2015-11-12 20:45:19 +08:00
Cloud Wu
d283d7fcaa check close return value 2015-11-12 18:34:50 +08:00
Cloud Wu
b72f0921d4 remove unused local function 2015-11-12 16:21:44 +08:00
Cloud Wu
6be649c5cb Merge branch 'master' of github.com:cloudwu/skynet 2015-11-12 15:42:05 +08:00
Cloud Wu
5edde990d6 bugfix: skynet.fork use table.pack to pack table 2015-11-12 15:41:41 +08:00
cloudwu
77813b446c Merge pull request #374 from huanzai/master
Update lua-netpack.c
2015-11-12 12:08:49 +08:00
huanzai
7138144a68 Update lua-netpack.c
当长度等于0x10000时,read_size读出的值为0
2015-11-12 11:15:50 +08:00
Cloud Wu
fa729d593b lua alloc use raw allocator 2015-11-12 10:53:14 +08:00
Cloud Wu
9f3baf2ee3 fix issue #372 2015-11-11 15:06:10 +08:00
Cloud Wu
7521fe0530 socket.shutdown abandon unsend buffer now, see issue #371 2015-11-11 10:44:50 +08:00
Cloud Wu
c28ae25c70 release 1.0.0 beta 2015-11-10 12:19:04 +08:00
Cloud Wu
9382454bcd update jemalloc to 4.0.4 2015-11-10 12:12:42 +08:00
Cloud Wu
d83fc0c00f sproto support all integer representation 2015-11-02 19:50:51 +08:00
云风
31340cf346 Merge pull request #369 from kexiao8/patch-1
repeated “struct table" of line 19
2015-11-01 19:27:16 +08:00
kexiao8
d1b26a60eb repeated “struct table" of line 19 2015-10-31 17:43:33 +08:00
Cloud Wu
ac4d51b779 bugfix issue #368 2015-10-29 11:22:26 +08:00
云风
0efab15f45 Merge pull request #366 from fztcjjl/master
add a callback for mysql auth
2015-10-28 20:49:44 +08:00
Cloud Wu
0199ba1382 sharedata support filename string 2015-10-28 17:37:06 +08:00
Cloud Wu
935863f434 report connect failed reason 2015-10-28 16:12:01 +08:00
Cloud Wu
13d920e185 body may contain ascii 0, see issue #365 2015-10-27 15:40:15 +08:00
Cloud Wu
a4af35f442 fix issue #364 2015-10-27 14:00:25 +08:00
云风
b1060478f7 Merge pull request #363 from nbwk1988/master
add hmac_md5
2015-10-27 11:39:55 +08:00
nbwk1988
1999a03ff7 优化hmac 2015-10-27 10:44:23 +08:00
nbwk1988
f5740e00b1 add hmac_md5
add hmac_md5
2015-10-26 16:12:10 +08:00
fztcjjl
1653b3213a add a callback for mysql auth 2015-10-24 06:37:25 +08:00
fztcjjl
fe3954fb04 add a callback for mysql auth 2015-10-24 01:35:16 +08:00
great90
716ecccaed Merge pull request #1 from cloudwu/master
update skynet
2015-10-23 14:33:54 +08:00
Cloud Wu
26cbebfcfd verify callback overflow 2015-10-21 12:58:57 +08:00
Cloud Wu
2d27df6f46 change name 2015-10-15 14:08:01 +08:00
Cloud Wu
bab91a3067 bugfix: don't use global wait_response 2015-10-15 14:01:50 +08:00
Cloud Wu
c1c032eab4 bugfix: socketchannel order mode may blocked. (used by redis driver) 2015-10-14 20:12:30 +08:00
Cloud Wu
7486e53232 avoid circular reference while encodeing bson 2015-10-14 15:44:09 +08:00
Cloud Wu
9aaa35ef14 avoid lua stack overflow 2015-10-14 15:24:51 +08:00
Cloud Wu
d2f2e299d5 call socket.abandon while auth error, see issue #355 2015-10-12 14:40:42 +08:00
Cloud Wu
d7e4e43a1b use spinlock macro 2015-10-12 13:07:09 +08:00
Cloud Wu
878110f9f7 add codecache.mode() 2015-10-12 12:29:19 +08:00
云风
60692e58dc Merge pull request #354 from xjdrew/bugfix_warning
bugfix: remove Wformat warning
2015-10-10 15:55:14 +03:00
xjdrew
515326dadc bugfix: remove Wformat warning 2015-10-10 18:39:42 +08:00
云风
4ee59edc44 Merge pull request #352 from xjdrew/gate
gate: application could control when to start receiving data
2015-10-09 05:05:33 +03:00
xjdrew
8dd9923cf6 gate: application could control when to start receiving data 2015-10-08 16:55:29 +08:00
Cloud Wu
8c1011c503 Add sproto:exist_type and sproto:exist_proto 2015-10-08 15:30:15 +08:00
Cloud Wu
8924b86ad7 check empty group, See pr #351 2015-10-08 15:15:35 +08:00
云风
14bc029864 Merge pull request #348 from xjdrew/unused_code
removte unused code
2015-10-05 05:17:29 +03:00
Cloud Wu
79e73d907e add target update3rd 2015-10-05 10:09:22 +08:00
Cloud Wu
3a06dcf534 update jemalloc to 4.0.3 2015-10-05 10:05:36 +08:00
Cloud Wu
97fd5053c9 update lpeg to 1.0.0 2015-10-05 09:56:12 +08:00
云风
3a3159d429 Merge pull request #347 from zhengfangxin/master
delete two clear_closed_event call
2015-10-05 04:51:22 +03:00
xjdrew
97ff6afc84 removte unused code 2015-09-29 17:29:33 +08:00
zhengfangxin
cb9feb34bd delete two no need call clear_closed_event 2015-09-26 21:03:38 +08:00
云风
48f79fe6d4 Merge pull request #345 from great90/master
从check_wsz发送的SKYNET_SOCKET_TYPE_WARNING消息会assert失败,导致coredump
2015-09-22 09:37:54 +08:00
great90
63942496fd 从check_wsz发送的SKYNET_SOCKET_TYPE_WARNING消息会assert失败,导致coredump 2015-09-21 23:50:18 +08:00
云风
bf9fc0c7e9 Merge pull request #343 from bingo235/master
gateserver close
2015-09-21 12:59:30 +08:00
bingo
325452a242 Signed-off-by: bingo <heidan725@qq.com> 2015-09-21 11:21:36 +08:00
Cloud Wu
752a501f68 bugfix: remove DONTCOPY tag from type 2015-09-21 10:40:09 +08:00
Cloud Wu
008351573a raise error when DH param is 0 2015-09-18 14:13:16 +08:00
Cloud Wu
00dbf6e996 DH key exchange can't be 0 , avoid attack 2015-09-18 14:10:12 +08:00
Cloud Wu
8cc5638f14 Merge branch 'master' of github.com:cloudwu/skynet 2015-09-15 14:52:44 +08:00
Cloud Wu
b8f419eb69 more error message for socket, and close listen socket when reach limit of open files. See Issue #339 2015-09-15 14:52:30 +08:00
云风
8f284e2d7f Merge pull request #340 from sanikoyes/Pr-missing-exitshr
add missing luaS_exitshr call
2015-09-14 18:05:56 +08:00
sanikoyes
846d55eaef add missing luaS_exitshr call 2015-09-14 18:03:04 +08:00
Cloud Wu
6c33f7bc44 see pr #332 2015-09-04 12:14:09 +08:00
Cloud Wu
7797de85b4 bugfix: See PR #332 2015-08-31 16:36:57 +08:00
云风
7ec452c782 Merge pull request #332 from niuys/patch-4
'response' not released
2015-08-30 22:08:37 +08:00
snail
7f9c3c8c9a local function is better
local function is the same as " local a; a = function"
2015-08-30 18:17:41 +08:00
snail
bad3472124 'response' not released
'response' not released after src service died, and defined error.
2015-08-30 16:47:34 +08:00
Cloud Wu
4f665d2469 init global string table, See issue #331 2015-08-30 12:13:23 +08:00
Cloud Wu
633e5fbe32 fix issue #331 2015-08-29 15:24:24 +08:00
云风
c1c5cd39e5 Merge pull request #328 from cloudwu/shrtbl
global shared string table
2015-08-27 21:16:47 +08:00
云风
03f5da6bb5 Merge pull request #329 from niuys/patch-3
uncomplete buffer not free
2015-08-27 18:15:12 +08:00
snail
1bfddda435 uncomplete buffer not free
'uncomplete' buffer not freed in clear
2015-08-27 18:04:56 +08:00
Cloud Wu
9b0e496afe minor amend 2015-08-27 13:49:31 +08:00
Cloud Wu
010d1c1d4f avoid dead loop 2015-08-24 11:50:40 +08:00
Cloud Wu
eb587c63d3 fix issue #327 2015-08-21 19:42:09 +08:00
Cloud Wu
bb6d5d826e add TString struct size 2015-08-21 15:59:51 +08:00
Cloud Wu
9acce94464 disable lua apicheck 2015-08-21 13:55:43 +08:00
Cloud Wu
c0862d8445 add global share string table 2015-08-21 13:52:04 +08:00
Cloud Wu
1b53e6e28d Release alpha 10 2015-08-17 11:21:20 +08:00
云风
77bdfb2ceb Merge pull request #325 from cloudwu/pthreadlock
add pthread lock
2015-08-17 10:25:36 +08:00
Cloud Wu
2583af26d7 add cluster.register and cluster.query 2015-08-14 23:22:00 +08:00
Cloud Wu
a38a3140dd error when send to address 0 2015-08-14 17:32:59 +08:00
Cloud Wu
bf8f9b8654 add pthread lock 2015-08-13 21:00:20 +08:00
Cloud Wu
0ce9921c25 remove unused sz 2015-08-12 21:16:02 +08:00
Cloud Wu
adc39705f3 remove unused netpack c api 2015-08-12 20:56:29 +08:00
Cloud Wu
a4f827a48d use string for msgserver request 2015-08-12 14:53:36 +08:00
Cloud Wu
7547126570 bugfix: memory leak , See Issue #323 2015-08-12 12:03:52 +08:00
Cloud Wu
926b44ddf6 remove unused parm 2015-08-11 14:09:16 +08:00
Cloud Wu
d3771edc9d The cluster message never great than 64K now 2015-08-11 14:04:15 +08:00
Cloud Wu
947727e33a add new socket message WARNING 2015-08-11 13:21:24 +08:00
云风
27148981d5 Merge pull request #320 from cloudwu/multipart
Multipart
2015-08-11 11:17:22 +08:00
Cloud Wu
6fa436e8ff add core.intcommand , See Issue #321 2015-08-10 22:06:36 +08:00
Cloud Wu
2935ba3521 Release alpha9 2015-08-10 16:17:55 +08:00
云风
5c8ea6f09f Merge pull request #318 from felixdae/cloud
not work with telnet due to \r\n
2015-08-08 16:45:21 +08:00
felixdae
c16ae57639 not work with telnet due to \r\n 2015-08-07 18:52:50 +08:00
云风
1c7d44fd4d Merge pull request #316 from niuys/patch-2
'hotfix' code cannot use '_ENV'
2015-08-07 16:14:13 +08:00
云风
ca7e38137d Merge pull request #317 from chuenlungwang/multipart
Packing multipart req number first byte is 1
2015-08-07 16:07:25 +08:00
BITMAN
5936d3616c Packing multipart req number first byte is 1 2015-08-07 13:51:10 +08:00
snail
e9cfdba22a 'hotfix' code cannot use '_ENV'
If there's no global variable or function used in any interface of a snax service,the upvalue "_ENV" for 'hotfix' is not set. This modify is not  complete, it depend's on the 'collect_uv' method having upvalue '_ENV',maybe other good method to get upvalue index of '_ENV'.
2015-08-07 10:38:57 +08:00
Cloud Wu
3156661e0b bugfix: response function for socket channel 2015-08-06 20:00:48 +08:00
Cloud Wu
b4048a8eab bugfix: typo 2015-08-05 16:42:05 +08:00
Cloud Wu
aff73cbed7 Increase message size 16M(24bit) limit to 56bit on 64bit arch 2015-08-05 12:23:35 +08:00
Cloud Wu
b5244b96aa cluster rpc support large package 2015-08-04 17:56:17 +08:00
Cloud Wu
704b016f2c bugfix: inc session before get channel 2015-08-04 17:51:35 +08:00
Cloud Wu
3b48beb428 bson bugfix 2015-07-30 15:41:17 +08:00
Cloud Wu
4cbead28d5 skynet.dispatch can replace old func 2015-07-29 16:12:49 +08:00
Cloud Wu
b3f966bcaa bugfix: multicast chan gc 2015-07-29 16:10:38 +08:00
Cloud Wu
7b54e37d12 Merge branch 'master' of github.com:cloudwu/skynet 2015-07-24 17:58:06 +08:00
Cloud Wu
e87ac18b84 expand lua stack first 2015-07-24 17:50:42 +08:00
云风
05af87ce8e Merge pull request #311 from jintiao/patch-1
fix "make cleanall" on macosx
2015-07-24 17:45:41 +08:00
jintiao
0ee61de22c skip jemalloc clean if jemalloc's makefile was missing 2015-07-24 00:48:24 +08:00
Cloud Wu
1da8a6b38d lazy init debug command 2015-07-23 18:35:29 +08:00
Cloud Wu
b2d8237363 improve unregister protocol error report 2015-07-23 18:23:47 +08:00
Cloud Wu
39f9a96b6c add cmemory.info() returns a table of c memory info 2015-07-23 16:47:35 +08:00
Cloud Wu
588c4a3508 bugfix 2015-07-22 16:49:25 +08:00
Cloud Wu
d6734890e0 Merge branch 'master' of github.com:cloudwu/skynet 2015-07-22 15:53:19 +08:00
Cloud Wu
4ebb139c2b bugfix: free message when cluster not connected 2015-07-22 15:52:26 +08:00
云风
20476d2280 Merge pull request #308 from jsenter/patch-1
Update cdummy.lua
2015-07-21 15:20:56 +08:00
Cloud Wu
3131bca6ef Merge branch 'master' of github.com:cloudwu/skynet 2015-07-21 11:31:41 +08:00
Cloud Wu
3f91484791 user log service 2015-07-21 11:31:27 +08:00
LiBei
a0ecd51230 Update cdummy.lua
误定义全局变量
2015-07-21 11:12:55 +08:00
云风
dba1db9cc4 Merge pull request #304 from JiessieDawn/master
sharedata serialization bugfix
2015-07-13 14:13:48 +08:00
cxj
538414408d sharedata serialization bugfix 2015-07-13 13:04:09 +08:00
云风
4cf05fb2e7 Merge pull request #303 from JiessieDawn/master
sproto optimize
2015-07-11 20:36:39 +08:00
cxj
d9ad981c8c sproto optimize, malloc newchunk and return directly if sz >= CHUNK_SIZE in pool_alloc, do not replace current chunk if sz >= p->current_used in pool_alloc, more safety checking 2015-07-10 20:21:07 +08:00
云风
21c941fe63 Merge pull request #302 from sanikoyes/Pr-optimize-sproto-lunpack
Pr-optimize-sproto-unpack
2015-07-09 18:24:06 +08:00
sanikoyes
ea2437e138 lunpack optimize, do not unpack twice if r <= osz 2015-07-09 18:07:32 +08:00
Cloud Wu
86bbc9c701 off by 1 error 2015-07-07 12:11:16 +08:00
Cloud Wu
95e1d9f45f Merge branch 'master' of github.com:cloudwu/skynet 2015-07-03 10:58:53 +08:00
Cloud Wu
55cf9375fc asterisk(*) should be once or not at all 2015-07-03 10:58:40 +08:00
云风
654f732cd5 Merge pull request #300 from sanikoyes/Pr-fix-login-client
Pr-fix-login-client
2015-07-03 10:28:24 +08:00
sanikoyes
d4023c8b63 fix invalid fd after reconnected, used in unpack_f 2015-07-02 16:25:10 +08:00
云风
375f8606b4 Merge pull request #298 from JiessieDawn/master
support sharedata serialization
2015-07-02 15:04:49 +08:00
cxj
d17e6f59fe add sharedata lua serialization test 2015-07-02 15:02:11 +08:00
cxj
a77d36911d change wb_table to call wb_table_metapairs for keeping consistent style 2015-07-02 14:47:50 +08:00
cxj
4352dc4047 Merge branch 'master' of https://github.com/cloudwu/skynet 2015-07-02 13:56:55 +08:00
cxj
172356be19 fix lua-seric.c wb_table 2015-07-02 13:51:03 +08:00
Cloud Wu
08dabd51c8 fix issue #299 2015-07-02 12:17:18 +08:00
cxj
bd55a58515 support sharedata serialization 2015-07-01 16:54:20 +08:00
Cloud Wu
b646a1b8a3 fix login example 2015-07-01 12:51:20 +08:00
Cloud Wu
6b312fa09a update readme 2015-07-01 11:35:05 +08:00
Cloud Wu
dad66010cd sproto bugfix, see sproto issue 34 for detail 2015-06-30 15:05:49 +08:00
Cloud Wu
27ae0a7500 release alpha 8 2015-06-29 11:11:32 +08:00
Cloud Wu
6001d9c2eb raise error message from response function, See issue #295 2015-06-26 14:33:33 +08:00
Cloud Wu
728abeaeb8 can't write to listen fd, See issue #294 2015-06-25 19:28:42 +08:00
Cloud Wu
2fa130997f fix atom inc 2015-06-24 19:50:45 +08:00
Cloud Wu
8c57ec192a Merge branch 'master' of github.com:cloudwu/skynet 2015-06-24 18:58:24 +08:00
Cloud Wu
0fb2b21ed5 use atom inc for object id counter 2015-06-24 18:57:47 +08:00
云风
1fd2c3de81 Merge pull request #292 from leeonix/master
修改Makefile,添加lua的清理
2015-06-24 11:12:05 +08:00
Cloud Wu
f3536bfc53 not use raw api, fix Issue #293 2015-06-24 10:27:37 +08:00
leeonix
57999456ef modify Makefile and add lua clean
modify service-src/service_gate.c space to tab
2015-06-20 11:29:56 +08:00
Cloud Wu
35b35f686c bugfix: Issue #291 2015-06-19 13:22:40 +08:00
Cloud Wu
5d9142110e patch lua_clonefunction 2015-06-18 17:39:37 +08:00
Cloud Wu
2086e13a46 hack lua to support signal 2015-06-17 22:12:48 +08:00
Cloud Wu
f36b173155 update to lua 5.3.1 2015-06-17 22:06:11 +08:00
Cloud Wu
7fa1d548ed bugfix: don't call skynet_free directly when send failed 2015-06-16 10:56:28 +08:00
Cloud Wu
039235b3a3 lock before set quit flag 2015-06-09 21:46:37 +08:00
Cloud Wu
57d43a588e Check quit flag before pthread_cond_wait 2015-06-09 20:00:20 +08:00
Cloud Wu
8214c53891 release alpha7 2015-06-08 10:31:00 +08:00
Cloud Wu
5e642b15a4 Merge branch 'master' of github.com:cloudwu/skynet 2015-06-07 12:39:33 +08:00
Cloud Wu
ac093c7142 fix memory leak, see Issue #290 2015-06-07 12:38:55 +08:00
云风
01dcc45827 Merge pull request #289 from harrywong/typo-patch
typo in type of variable
2015-06-05 23:02:16 +08:00
Harry
d3ac522dc6 typo in type of variable 2015-06-05 19:04:43 +08:00
Cloud Wu
55d0d57d5c skynet.fork returns the coroutine, see Issue #287 2015-06-04 16:06:21 +08:00
Cloud Wu
1fec2e6063 sep size may greater than buffer node, See Issue #286 2015-06-03 09:42:49 +08:00
Cloud Wu
cc4756de35 fix Issue #285 2015-06-02 11:52:55 +08:00
Cloud Wu
7fb109dbb0 See Issue #284 2015-06-01 10:57:30 +08:00
Cloud Wu
7f578be649 bugfix: Issue #283 2015-06-01 10:42:29 +08:00
Cloud Wu
69946d75c5 add config.logservice for user defined log service 2015-05-30 22:17:53 +08:00
Cloud Wu
24f6994b50 close uncomplete when socket disconnect, see Issue #280 2015-05-29 21:11:02 +08:00
Cloud Wu
07dbfd8651 add underscore 2015-05-28 16:18:56 +08:00
Cloud Wu
ca50a5f518 dns support underscore 2015-05-28 16:10:19 +08:00
Cloud Wu
b8c54cbac2 skynet.kill move into skynet.manager 2015-05-27 21:17:43 +08:00
Cloud Wu
3a2c43e9e0 set nodelay in clusterd, Issue #278 2015-05-27 14:54:26 +08:00
Cloud Wu
205824ab12 use LUA_API instead of extern 2015-05-26 16:05:31 +08:00
云风
4ac047b274 Merge pull request #277 from xiyanxiyan10/master
调整格式
2015-05-23 17:02:37 +08:00
xiyanxiyan10
987a90af8b 调整格式 2015-05-23 16:35:15 +08:00
Cloud Wu
250531c9a7 bugfix: sproto.default 2015-05-22 20:51:00 +08:00
Cloud Wu
7b471ae27d snax service support cluster 2015-05-20 16:13:11 +08:00
云风
4f93054f3a Merge pull request #275 from ximenpo/master
console服务增加启动snax服务功能
2015-05-20 15:43:55 +08:00
ximenpo
65fad89794 console服务增加启动snax服务功能
输入:
svc  -> 用snlua启动svc服务
snax svc -> 用snax启动svc服务
2015-05-20 15:14:28 +08:00
云风
286c0f2c23 Merge pull request #273 from flashjay/patch-4
Update lua-crypt.c
2015-05-19 11:41:14 +08:00
HuaYang Huang
de57064b96 Update lua-crypt.c
添加 static 避免可能导致的链接冲突
2015-05-18 23:05:24 +08:00
184 changed files with 7039 additions and 3139 deletions

View File

@@ -1,4 +1,10 @@
HISTORY for LPeg 0.12
HISTORY for LPeg 1.0
* Changes from version 0.12 to 1.0
---------------------------------
+ group "names" can be any Lua value
+ some bugs fixed
+ other small improvements
* Changes from version 0.11 to 0.12
---------------------------------

View File

@@ -1,5 +1,5 @@
/*
** $Id: lpcap.c,v 1.5 2014/12/12 16:58:47 roberto Exp $
** $Id: lpcap.c,v 1.6 2015/06/15 16:09:57 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/
@@ -126,7 +126,7 @@ static Capture *findback (CapState *cs, Capture *cap) {
continue; /* opening an enclosing capture: skip and get previous */
if (captype(cap) == Cgroup) {
getfromktable(cs, cap->idx); /* get group name */
if (lua_equal(L, -2, -1)) { /* right group? */
if (lp_equal(L, -2, -1)) { /* right group? */
lua_pop(L, 2); /* remove reference name and group name */
return cap;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lpcap.h,v 1.1 2013/03/21 20:25:12 roberto Exp $
** $Id: lpcap.h,v 1.2 2015/02/27 17:13:17 roberto Exp $
*/
#if !defined(lpcap_h)
@@ -18,7 +18,7 @@ typedef enum CapKind {
typedef struct Capture {
const char *s; /* subject position */
short idx; /* extra info about capture (group name, arg index, etc.) */
unsigned short idx; /* extra info (group name, arg index, etc.) */
byte kind; /* kind of capture */
byte siz; /* size of full capture + 1 (0 = not a full capture) */
} Capture;

View File

@@ -1,5 +1,5 @@
/*
** $Id: lpcode.c,v 1.21 2014/12/12 17:01:29 roberto Exp $
** $Id: lpcode.c,v 1.23 2015/06/12 18:36:47 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/
@@ -431,11 +431,11 @@ typedef struct CompileState {
/*
** code generation is recursive; 'opt' indicates that the code is
** being generated under a 'IChoice' operator jumping to its end
** (that is, the match is "optional").
** 'tt' points to a previous test protecting this code. 'fl' is
** the follow set of the pattern.
** code generation is recursive; 'opt' indicates that the code is being
** generated as the last thing inside an optional pattern (so, if that
** code is optional too, it can reuse the 'IChoice' already in place for
** the outer pattern). 'tt' points to a previous test protecting this
** code (or NOINST). 'fl' is the follow set of the pattern.
*/
static void codegen (CompileState *compst, TTree *tree, int opt, int tt,
const Charset *fl);
@@ -638,13 +638,13 @@ static void codebehind (CompileState *compst, TTree *tree) {
/*
** Choice; optimizations:
** - when p1 is headfail
** - when first(p1) and first(p2) are disjoint; than
** - when p1 is headfail or
** when first(p1) and first(p2) are disjoint, than
** a character not in first(p1) cannot go to p1, and a character
** in first(p1) cannot go to p2 (at it is not in first(p2)).
** (The optimization is not valid if p1 accepts the empty string,
** as then there is no character at all...)
** - when p2 is empty and opt is true; a IPartialCommit can resuse
** - when p2 is empty and opt is true; a IPartialCommit can reuse
** the Choice already active in the stack.
*/
static void codechoice (CompileState *compst, TTree *p1, TTree *p2, int opt,
@@ -671,7 +671,7 @@ static void codechoice (CompileState *compst, TTree *p1, TTree *p2, int opt,
}
else {
/* <p1 / p2> ==
test(fail(p1)) -> L1; choice L1; <p1>; commit L2; L1: <p2>; L2: */
test(first(p1)) -> L1; choice L1; <p1>; commit L2; L1: <p2>; L2: */
int pcommit;
int test = codetestset(compst, &cs1, e1);
int pchoice = addoffsetinst(compst, IChoice);
@@ -759,7 +759,7 @@ static void coderep (CompileState *compst, TTree *tree, int opt,
/* L1: test (fail(p1)) -> L2; <p>; jmp L1; L2: */
int jmp;
int test = codetestset(compst, &st, 0);
codegen(compst, tree, opt, test, fullset);
codegen(compst, tree, 0, test, fullset);
jmp = addoffsetinst(compst, IJmp);
jumptohere(compst, test);
jumptothere(compst, jmp, test);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lpcode.h,v 1.6 2013/11/28 14:56:02 roberto Exp $
** $Id: lpcode.h,v 1.7 2015/06/12 18:24:45 roberto Exp $
*/
#if !defined(lpcode_h)
@@ -24,7 +24,15 @@ int sizei (const Instruction *i);
#define PEnullable 0
#define PEnofail 1
/*
** nofail(t) implies that 't' cannot fail with any input
*/
#define nofail(t) checkaux(t, PEnofail)
/*
** (not nullable(t)) implies 't' cannot match without consuming
** something
*/
#define nullable(t) checkaux(t, PEnullable)
#define fixedlen(t) fixedlenx(t, 0, 0)

View File

@@ -10,7 +10,7 @@
</head>
<body>
<!-- $Id: lpeg.html,v 1.72 2014/12/12 17:11:35 roberto Exp $ -->
<!-- $Id: lpeg.html,v 1.75 2015/09/28 17:17:41 roberto Exp $ -->
<div id="container">
@@ -22,7 +22,7 @@
</div>
<div id="product_name"><big><strong>LPeg</strong></big></div>
<div id="product_description">
Parsing Expression Grammars For Lua, version 0.12
Parsing Expression Grammars For Lua, version 1.0
</div>
</div> <!-- id="product" -->
@@ -195,13 +195,16 @@ Returns a string with the running version of LPeg.
<h3><a name="f-setstack"></a><code>lpeg.setmaxstack (max)</code></h3>
<p>
Sets the maximum size for the backtrack stack used by LPeg to
Sets a limit for the size of the backtrack stack used by LPeg to
track calls and choices.
(The default limit is 400.)
Most well-written patterns need little backtrack levels and
therefore you seldom need to change this maximum;
but a few useful patterns may need more space.
Before changing this maximum you should try to rewrite your
therefore you seldom need to change this limit;
before changing it you should try to rewrite your
pattern to avoid the need for extra space.
Nevertheless, a few useful patterns may overflow.
Also, with recursive grammars,
subjects with deep recursion may also need larger limits.
</p>
@@ -682,7 +685,8 @@ argument given in the call to <code>lpeg.match</code>.
Creates a <em>back capture</em>.
This pattern matches the empty string and
produces the values produced by the <em>most recent</em>
<a href="#cap-g">group capture</a> named <code>name</code>.
<a href="#cap-g">group capture</a> named <code>name</code>
(where <code>name</code> can be any Lua value).
</p>
<p>
@@ -762,7 +766,8 @@ Creates a <em>group capture</em>.
It groups all values returned by <code>patt</code>
into a single capture.
The group may be anonymous (if no name is given)
or named with the given name.
or named with the given name
(which can be any non-nil Lua value).
</p>
<p>
@@ -1375,13 +1380,13 @@ and the new term for each repetition.
<h2><a name="download"></a>Download</h2>
<p>LPeg
<a href="http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-0.12.1.tar.gz">source code</a>.</p>
<a href="http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.0.tar.gz">source code</a>.</p>
<h2><a name="license">License</a></h2>
<p>
Copyright &copy; 2014 Lua.org, PUC-Rio.
Copyright &copy; 2007-2015 Lua.org, PUC-Rio.
</p>
<p>
Permission is hereby granted, free of charge,
@@ -1419,7 +1424,7 @@ THE SOFTWARE.
<div id="about">
<p><small>
$Id: lpeg.html,v 1.72 2014/12/12 17:11:35 roberto Exp $
$Id: lpeg.html,v 1.75 2015/09/28 17:17:41 roberto Exp $
</small></p>
</div> <!-- id="about" -->

View File

@@ -1,5 +1,5 @@
/*
** $Id: lpprint.c,v 1.7 2013/04/12 16:29:49 roberto Exp $
** $Id: lpprint.c,v 1.9 2015/06/15 16:09:57 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/
@@ -52,7 +52,7 @@ static void printjmp (const Instruction *op, const Instruction *p) {
}
static void printinst (const Instruction *op, const Instruction *p) {
void printinst (const Instruction *op, const Instruction *p) {
const char *const names[] = {
"any", "char", "set",
"testany", "testchar", "testset",
@@ -221,10 +221,10 @@ void printtree (TTree *tree, int ident) {
void printktable (lua_State *L, int idx) {
int n, i;
lua_getfenv(L, idx);
lua_getuservalue(L, idx);
if (lua_isnil(L, -1)) /* no ktable? */
return;
n = lua_objlen(L, -1);
n = lua_rawlen(L, -1);
printf("[");
for (i = 1; i <= n; i++) {
printf("%d = ", i);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lpprint.h,v 1.1 2013/03/21 20:25:12 roberto Exp $
** $Id: lpprint.h,v 1.2 2015/06/12 18:18:08 roberto Exp $
*/
@@ -18,6 +18,7 @@ void printtree (TTree *tree, int ident);
void printktable (lua_State *L, int idx);
void printcharset (const byte *st);
void printcaplist (Capture *cap, Capture *limit);
void printinst (const Instruction *op, const Instruction *p);
#else

View File

@@ -1,5 +1,5 @@
/*
** $Id: lptree.c,v 1.13 2014/12/12 16:59:10 roberto Exp $
** $Id: lptree.c,v 1.21 2015/09/28 17:01:25 roberto Exp $
** Copyright 2013, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/
@@ -126,6 +126,189 @@ static void finalfix (lua_State *L, int postable, TTree *g, TTree *t) {
}
/*
** {===================================================================
** KTable manipulation
**
** - The ktable of a pattern 'p' can be shared by other patterns that
** contain 'p' and no other constants. Because of this sharing, we
** should not add elements to a 'ktable' unless it was freshly created
** for the new pattern.
**
** - The maximum index in a ktable is USHRT_MAX, because trees and
** patterns use unsigned shorts to store those indices.
** ====================================================================
*/
/*
** Create a new 'ktable' to the pattern at the top of the stack.
*/
static void newktable (lua_State *L, int n) {
lua_createtable(L, n, 0); /* create a fresh table */
lua_setuservalue(L, -2); /* set it as 'ktable' for pattern */
}
/*
** Add element 'idx' to 'ktable' of pattern at the top of the stack;
** Return index of new element.
** If new element is nil, does not add it to table (as it would be
** useless) and returns 0, as ktable[0] is always nil.
*/
static int addtoktable (lua_State *L, int idx) {
if (lua_isnil(L, idx)) /* nil value? */
return 0;
else {
int n;
lua_getuservalue(L, -1); /* get ktable from pattern */
n = lua_rawlen(L, -1);
if (n >= USHRT_MAX)
luaL_error(L, "too many Lua values in pattern");
lua_pushvalue(L, idx); /* element to be added */
lua_rawseti(L, -2, ++n);
lua_pop(L, 1); /* remove 'ktable' */
return n;
}
}
/*
** Return the number of elements in the ktable at 'idx'.
** In Lua 5.2/5.3, default "environment" for patterns is nil, not
** a table. Treat it as an empty table. In Lua 5.1, assumes that
** the environment has no numeric indices (len == 0)
*/
static int ktablelen (lua_State *L, int idx) {
if (!lua_istable(L, idx)) return 0;
else return lua_rawlen(L, idx);
}
/*
** Concatentate the contents of table 'idx1' into table 'idx2'.
** (Assume that both indices are negative.)
** Return the original length of table 'idx2' (or 0, if no
** element was added, as there is no need to correct any index).
*/
static int concattable (lua_State *L, int idx1, int idx2) {
int i;
int n1 = ktablelen(L, idx1);
int n2 = ktablelen(L, idx2);
if (n1 + n2 > USHRT_MAX)
luaL_error(L, "too many Lua values in pattern");
if (n1 == 0) return 0; /* nothing to correct */
for (i = 1; i <= n1; i++) {
lua_rawgeti(L, idx1, i);
lua_rawseti(L, idx2 - 1, n2 + i); /* correct 'idx2' */
}
return n2;
}
/*
** When joining 'ktables', constants from one of the subpatterns must
** be renumbered; 'correctkeys' corrects their indices (adding 'n'
** to each of them)
*/
static void correctkeys (TTree *tree, int n) {
if (n == 0) return; /* no correction? */
tailcall:
switch (tree->tag) {
case TOpenCall: case TCall: case TRunTime: case TRule: {
if (tree->key > 0)
tree->key += n;
break;
}
case TCapture: {
if (tree->key > 0 && tree->cap != Carg && tree->cap != Cnum)
tree->key += n;
break;
}
default: break;
}
switch (numsiblings[tree->tag]) {
case 1: /* correctkeys(sib1(tree), n); */
tree = sib1(tree); goto tailcall;
case 2:
correctkeys(sib1(tree), n);
tree = sib2(tree); goto tailcall; /* correctkeys(sib2(tree), n); */
default: assert(numsiblings[tree->tag] == 0); break;
}
}
/*
** Join the ktables from p1 and p2 the ktable for the new pattern at the
** top of the stack, reusing them when possible.
*/
static void joinktables (lua_State *L, int p1, TTree *t2, int p2) {
int n1, n2;
lua_getuservalue(L, p1); /* get ktables */
lua_getuservalue(L, p2);
n1 = ktablelen(L, -2);
n2 = ktablelen(L, -1);
if (n1 == 0 && n2 == 0) /* are both tables empty? */
lua_pop(L, 2); /* nothing to be done; pop tables */
else if (n2 == 0 || lp_equal(L, -2, -1)) { /* 2nd table empty or equal? */
lua_pop(L, 1); /* pop 2nd table */
lua_setuservalue(L, -2); /* set 1st ktable into new pattern */
}
else if (n1 == 0) { /* first table is empty? */
lua_setuservalue(L, -3); /* set 2nd table into new pattern */
lua_pop(L, 1); /* pop 1st table */
}
else {
lua_createtable(L, n1 + n2, 0); /* create ktable for new pattern */
/* stack: new p; ktable p1; ktable p2; new ktable */
concattable(L, -3, -1); /* from p1 into new ktable */
concattable(L, -2, -1); /* from p2 into new ktable */
lua_setuservalue(L, -4); /* new ktable becomes 'p' environment */
lua_pop(L, 2); /* pop other ktables */
correctkeys(t2, n1); /* correction for indices from p2 */
}
}
/*
** copy 'ktable' of element 'idx' to new tree (on top of stack)
*/
static void copyktable (lua_State *L, int idx) {
lua_getuservalue(L, idx);
lua_setuservalue(L, -2);
}
/*
** merge 'ktable' from 'stree' at stack index 'idx' into 'ktable'
** from tree at the top of the stack, and correct corresponding
** tree.
*/
static void mergektable (lua_State *L, int idx, TTree *stree) {
int n;
lua_getuservalue(L, -1); /* get ktables */
lua_getuservalue(L, idx);
n = concattable(L, -1, -2);
lua_pop(L, 2); /* remove both ktables */
correctkeys(stree, n);
}
/*
** Create a new 'ktable' to the pattern at the top of the stack, adding
** all elements from pattern 'p' (if not 0) plus element 'idx' to it.
** Return index of new element.
*/
static int addtonewktable (lua_State *L, int p, int idx) {
newktable(L, 1);
if (p)
mergektable(L, p, NULL);
return addtoktable(L, idx);
}
/* }====================================================== */
/*
** {======================================================
** Tree generation
@@ -155,7 +338,7 @@ static Pattern *getpattern (lua_State *L, int idx) {
static int getsize (lua_State *L, int idx) {
return (lua_objlen(L, idx) - sizeof(Pattern)) / sizeof(TTree) + 1;
return (lua_rawlen(L, idx) - sizeof(Pattern)) / sizeof(TTree) + 1;
}
@@ -168,12 +351,16 @@ static TTree *gettree (lua_State *L, int idx, int *len) {
/*
** create a pattern
** create a pattern. Set its uservalue (the 'ktable') equal to its
** metatable. (It could be any empty sequence; the metatable is at
** hand here, so we use it.)
*/
static TTree *newtree (lua_State *L, int len) {
size_t size = (len - 1) * sizeof(TTree) + sizeof(Pattern);
Pattern *p = (Pattern *)lua_newuserdata(L, size);
luaL_getmetatable(L, PATTERN_T);
lua_pushvalue(L, -1);
lua_setuservalue(L, -3);
lua_setmetatable(L, -2);
p->code = NULL; p->codesize = 0;
return p->tree;
@@ -206,35 +393,6 @@ static TTree *seqaux (TTree *tree, TTree *sib, int sibsize) {
}
/*
** Add element 'idx' to 'ktable' of pattern at the top of the stack;
** create new 'ktable' if necessary. Return index of new element.
** If new element is nil, does not add it to table (as it would be
** useless) and returns 0, as ktable[0] is always nil.
*/
static int addtoktable (lua_State *L, int idx) {
if (idx == 0) /* no actual value to insert? */
return 0;
else {
int n;
lua_getfenv(L, -1); /* get ktable from pattern */
n = lua_objlen(L, -1);
if (n == 0) { /* is it empty/non-existent? */
lua_pop(L, 1); /* remove it */
lua_createtable(L, 1, 0); /* create a fresh table */
lua_pushvalue(L, -1); /* make a copy */
lua_setfenv(L, -3); /* set it as 'ktable' for pattern */
}
if (!lua_isnil(L, idx)) { /* non-nil value? */
lua_pushvalue(L, idx); /* element to be added */
lua_rawseti(L, -2, ++n);
}
lua_pop(L, 1); /* remove 'ktable' */
return n;
}
}
/*
** Build a sequence of 'n' nodes, each with tag 'tag' and 'u.n' got
** from the array 's' (or 0 if array is NULL). (TSeq is binary, so it
@@ -310,7 +468,7 @@ static TTree *getpatt (lua_State *L, int idx, int *len) {
case LUA_TFUNCTION: {
tree = newtree(L, 2);
tree->tag = TRunTime;
tree->key = addtoktable(L, idx);
tree->key = addtonewktable(L, 0, idx);
sib1(tree)->tag = TTrue;
break;
}
@@ -325,123 +483,6 @@ static TTree *getpatt (lua_State *L, int idx, int *len) {
}
/*
** Return the number of elements in the ktable of pattern at 'idx'.
** In Lua 5.2, default "environment" for patterns is nil, not
** a table. Treat it as an empty table. In Lua 5.1, assumes that
** the environment has no numeric indices (len == 0)
*/
static int ktablelen (lua_State *L, int idx) {
if (!lua_istable(L, idx)) return 0;
else return lua_objlen(L, idx);
}
/*
** Concatentate the contents of table 'idx1' into table 'idx2'.
** (Assume that both indices are negative.)
** Return the original length of table 'idx2'
*/
static int concattable (lua_State *L, int idx1, int idx2) {
int i;
int n1 = ktablelen(L, idx1);
int n2 = ktablelen(L, idx2);
if (n1 == 0) return 0; /* nothing to correct */
for (i = 1; i <= n1; i++) {
lua_rawgeti(L, idx1, i);
lua_rawseti(L, idx2 - 1, n2 + i); /* correct 'idx2' */
}
return n2;
}
/*
** Make a merge of ktables from p1 and p2 the ktable for the new
** pattern at the top of the stack.
*/
static int joinktables (lua_State *L, int p1, int p2) {
int n1, n2;
lua_getfenv(L, p1); /* get ktables */
lua_getfenv(L, p2);
n1 = ktablelen(L, -2);
n2 = ktablelen(L, -1);
if (n1 == 0 && n2 == 0) { /* are both tables empty? */
lua_pop(L, 2); /* nothing to be done; pop tables */
return 0; /* nothing to correct */
}
if (n2 == 0 || lua_equal(L, -2, -1)) { /* second table is empty or equal? */
lua_pop(L, 1); /* pop 2nd table */
lua_setfenv(L, -2); /* set 1st ktable into new pattern */
return 0; /* nothing to correct */
}
if (n1 == 0) { /* first table is empty? */
lua_setfenv(L, -3); /* set 2nd table into new pattern */
lua_pop(L, 1); /* pop 1st table */
return 0; /* nothing to correct */
}
else {
lua_createtable(L, n1 + n2, 0); /* create ktable for new pattern */
/* stack: new p; ktable p1; ktable p2; new ktable */
concattable(L, -3, -1); /* from p1 into new ktable */
concattable(L, -2, -1); /* from p2 into new ktable */
lua_setfenv(L, -4); /* new ktable becomes p env */
lua_pop(L, 2); /* pop other ktables */
return n1; /* correction for indices from p2 */
}
}
static void correctkeys (TTree *tree, int n) {
if (n == 0) return; /* no correction? */
tailcall:
switch (tree->tag) {
case TOpenCall: case TCall: case TRunTime: case TRule: {
if (tree->key > 0)
tree->key += n;
break;
}
case TCapture: {
if (tree->key > 0 && tree->cap != Carg && tree->cap != Cnum)
tree->key += n;
break;
}
default: break;
}
switch (numsiblings[tree->tag]) {
case 1: /* correctkeys(sib1(tree), n); */
tree = sib1(tree); goto tailcall;
case 2:
correctkeys(sib1(tree), n);
tree = sib2(tree); goto tailcall; /* correctkeys(sib2(tree), n); */
default: assert(numsiblings[tree->tag] == 0); break;
}
}
/*
** copy 'ktable' of element 'idx' to new tree (on top of stack)
*/
static void copyktable (lua_State *L, int idx) {
lua_getfenv(L, idx);
lua_setfenv(L, -2);
}
/*
** merge 'ktable' from rule at stack index 'idx' into 'ktable'
** from tree at the top of the stack, and correct corresponding
** tree.
*/
static void mergektable (lua_State *L, int idx, TTree *rule) {
int n;
lua_getfenv(L, -1); /* get ktables */
lua_getfenv(L, idx);
n = concattable(L, -1, -2);
lua_pop(L, 2); /* remove both ktables */
correctkeys(rule, n);
}
/*
** create a new tree, whith a new root and one sibling.
** Sibling must be on the Lua stack, at index 1.
@@ -470,7 +511,7 @@ static TTree *newroot2sib (lua_State *L, int tag) {
tree->u.ps = 1 + s1;
memcpy(sib1(tree), tree1, s1 * sizeof(TTree));
memcpy(sib2(tree), tree2, s2 * sizeof(TTree));
correctkeys(sib2(tree), joinktables(L, 1, 2));
joinktables(L, 1, sib2(tree), 2);
return tree;
}
@@ -599,7 +640,7 @@ static int lp_sub (lua_State *L) {
sib1(tree)->tag = TNot; /* ...not... */
memcpy(sib1(sib1(tree)), t2, s2 * sizeof(TTree)); /* ...t2 */
memcpy(sib2(tree), t1, s1 * sizeof(TTree)); /* ... and t1 */
correctkeys(sib1(tree), joinktables(L, 1, 2));
joinktables(L, 1, sib1(tree), 2);
}
return 1;
}
@@ -640,7 +681,7 @@ static int lp_behind (lua_State *L) {
TTree *tree;
TTree *tree1 = getpatt(L, 1, NULL);
int n = fixedlen(tree1);
luaL_argcheck(L, n > 0, 1, "pattern may not have fixed length");
luaL_argcheck(L, n >= 0, 1, "pattern may not have fixed length");
luaL_argcheck(L, !hascaptures(tree1), 1, "pattern have captures");
luaL_argcheck(L, n <= MAXBEHIND, 1, "pattern too long to look behind");
tree = newroot1sib(L, TBehind);
@@ -655,7 +696,7 @@ static int lp_behind (lua_State *L) {
static int lp_V (lua_State *L) {
TTree *tree = newleaf(L, TOpenCall);
luaL_argcheck(L, !lua_isnoneornil(L, 1), 1, "non-nil value expected");
tree->key = addtoktable(L, 1);
tree->key = addtonewktable(L, 0, 1);
return 1;
}
@@ -668,7 +709,7 @@ static int lp_V (lua_State *L) {
static int capture_aux (lua_State *L, int cap, int labelidx) {
TTree *tree = newroot1sib(L, TCapture);
tree->cap = cap;
tree->key = addtoktable(L, labelidx);
tree->key = (labelidx == 0) ? 0 : addtonewktable(L, 1, labelidx);
return 1;
}
@@ -676,10 +717,9 @@ static int capture_aux (lua_State *L, int cap, int labelidx) {
/*
** Fill a tree with an empty capture, using an empty (TTrue) sibling.
*/
static TTree *auxemptycap (lua_State *L, TTree *tree, int cap, int idx) {
static TTree *auxemptycap (TTree *tree, int cap) {
tree->tag = TCapture;
tree->cap = cap;
tree->key = addtoktable(L, idx);
sib1(tree)->tag = TTrue;
return tree;
}
@@ -688,8 +728,18 @@ static TTree *auxemptycap (lua_State *L, TTree *tree, int cap, int idx) {
/*
** Create a tree for an empty capture
*/
static TTree *newemptycap (lua_State *L, int cap, int idx) {
return auxemptycap(L, newtree(L, 2), cap, idx);
static TTree *newemptycap (lua_State *L, int cap) {
return auxemptycap(newtree(L, 2), cap);
}
/*
** Create a tree for an empty capture with an associated Lua value
*/
static TTree *newemptycapkey (lua_State *L, int cap, int idx) {
TTree *tree = auxemptycap(newtree(L, 2), cap);
tree->key = addtonewktable(L, 0, idx);
return tree;
}
@@ -728,10 +778,8 @@ static int lp_tablecapture (lua_State *L) {
static int lp_groupcapture (lua_State *L) {
if (lua_isnoneornil(L, 2))
return capture_aux(L, Cgroup, 0);
else {
luaL_checkstring(L, 2);
else
return capture_aux(L, Cgroup, 2);
}
}
@@ -747,14 +795,14 @@ static int lp_simplecapture (lua_State *L) {
static int lp_poscapture (lua_State *L) {
newemptycap(L, Cposition, 0);
newemptycap(L, Cposition);
return 1;
}
static int lp_argcapture (lua_State *L) {
int n = (int)luaL_checkinteger(L, 1);
TTree *tree = newemptycap(L, Carg, 0);
TTree *tree = newemptycap(L, Carg);
tree->key = n;
luaL_argcheck(L, 0 < n && n <= SHRT_MAX, 1, "invalid argument index");
return 1;
@@ -762,8 +810,8 @@ static int lp_argcapture (lua_State *L) {
static int lp_backref (lua_State *L) {
luaL_checkstring(L, 1);
newemptycap(L, Cbackref, 1);
luaL_checkany(L, 1);
newemptycapkey(L, Cbackref, 1);
return 1;
}
@@ -777,9 +825,10 @@ static int lp_constcapture (lua_State *L) {
if (n == 0) /* no values? */
newleaf(L, TTrue); /* no capture */
else if (n == 1)
newemptycap(L, Cconst, 1); /* single constant capture */
newemptycapkey(L, Cconst, 1); /* single constant capture */
else { /* create a group capture with all values */
TTree *tree = newtree(L, 1 + 3 * (n - 1) + 2);
newktable(L, n); /* create a 'ktable' for new tree */
tree->tag = TCapture;
tree->cap = Cgroup;
tree->key = 0;
@@ -787,10 +836,12 @@ static int lp_constcapture (lua_State *L) {
for (i = 1; i <= n - 1; i++) {
tree->tag = TSeq;
tree->u.ps = 3; /* skip TCapture and its sibling */
auxemptycap(L, sib1(tree), Cconst, i);
auxemptycap(sib1(tree), Cconst);
sib1(tree)->key = addtoktable(L, i);
tree = sib2(tree);
}
auxemptycap(L, tree, Cconst, i);
auxemptycap(tree, Cconst);
tree->key = addtoktable(L, i);
}
return 1;
}
@@ -800,7 +851,7 @@ static int lp_matchtime (lua_State *L) {
TTree *tree;
luaL_checktype(L, 2, LUA_TFUNCTION);
tree = newroot1sib(L, TRunTime);
tree->key = addtoktable(L, 2);
tree->key = addtonewktable(L, 1, 2);
return 1;
}
@@ -857,7 +908,7 @@ static int collectrules (lua_State *L, int arg, int *totalsize) {
lua_pushnil(L); /* prepare to traverse grammar table */
while (lua_next(L, arg) != 0) {
if (lua_tonumber(L, -2) == 1 ||
lua_equal(L, -2, postab + 1)) { /* initial rule? */
lp_equal(L, -2, postab + 1)) { /* initial rule? */
lua_pop(L, 1); /* remove value (keep key for lua_next) */
continue;
}
@@ -934,36 +985,40 @@ static int verifyerror (lua_State *L, int *passed, int npassed) {
/*
** Check whether a rule can be left recursive; raise an error in that
** case; otherwise return 1 iff pattern is nullable. Assume ktable at
** the top of the stack.
** case; otherwise return 1 iff pattern is nullable.
** The return value is used to check sequences, where the second pattern
** is only relevant if the first is nullable.
** Parameter 'nb' works as an accumulator, to allow tail calls in
** choices. ('nb' true makes function returns true.)
** Assume ktable at the top of the stack.
*/
static int verifyrule (lua_State *L, TTree *tree, int *passed, int npassed,
int nullable) {
int nb) {
tailcall:
switch (tree->tag) {
case TChar: case TSet: case TAny:
case TFalse:
return nullable; /* cannot pass from here */
return nb; /* cannot pass from here */
case TTrue:
case TBehind: /* look-behind cannot have calls */
return 1;
case TNot: case TAnd: case TRep:
/* return verifyrule(L, sib1(tree), passed, npassed, 1); */
tree = sib1(tree); nullable = 1; goto tailcall;
tree = sib1(tree); nb = 1; goto tailcall;
case TCapture: case TRunTime:
/* return verifyrule(L, sib1(tree), passed, npassed); */
/* return verifyrule(L, sib1(tree), passed, npassed, nb); */
tree = sib1(tree); goto tailcall;
case TCall:
/* return verifyrule(L, sib2(tree), passed, npassed); */
/* return verifyrule(L, sib2(tree), passed, npassed, nb); */
tree = sib2(tree); goto tailcall;
case TSeq: /* only check 2nd child if first is nullable */
case TSeq: /* only check 2nd child if first is nb */
if (!verifyrule(L, sib1(tree), passed, npassed, 0))
return nullable;
/* else return verifyrule(L, sib2(tree), passed, npassed); */
return nb;
/* else return verifyrule(L, sib2(tree), passed, npassed, nb); */
tree = sib2(tree); goto tailcall;
case TChoice: /* must check both children */
nullable = verifyrule(L, sib1(tree), passed, npassed, nullable);
/* return verifyrule(L, sib2(tree), passed, npassed, nullable); */
nb = verifyrule(L, sib1(tree), passed, npassed, nb);
/* return verifyrule(L, sib2(tree), passed, npassed, nb); */
tree = sib2(tree); goto tailcall;
case TRule:
if (npassed >= MAXRULES)
@@ -1006,7 +1061,7 @@ static void verifygrammar (lua_State *L, TTree *grammar) {
*/
static void initialrulename (lua_State *L, TTree *grammar, int frule) {
if (sib1(grammar)->key == 0) { /* initial rule is not referenced? */
int n = lua_objlen(L, -1) + 1; /* index for name */
int n = lua_rawlen(L, -1) + 1; /* index for name */
lua_pushvalue(L, frule); /* rule's name */
lua_rawseti(L, -2, n); /* ktable was on the top of the stack */
sib1(grammar)->key = n;
@@ -1022,9 +1077,9 @@ static TTree *newgrammar (lua_State *L, int arg) {
luaL_argcheck(L, n <= MAXRULES, arg, "grammar has too many rules");
g->tag = TGrammar; g->u.n = n;
lua_newtable(L); /* create 'ktable' */
lua_setfenv(L, -2);
lua_setuservalue(L, -2);
buildgrammar(L, g, frule, n);
lua_getfenv(L, -1); /* get 'ktable' for new tree */
lua_getuservalue(L, -1); /* get 'ktable' for new tree */
finalfix(L, frule - 1, g, sib1(g));
initialrulename(L, g, frule);
verifygrammar(L, g);
@@ -1038,7 +1093,7 @@ static TTree *newgrammar (lua_State *L, int arg) {
static Instruction *prepcompile (lua_State *L, Pattern *p, int idx) {
lua_getfenv(L, idx); /* push 'ktable' (may be used by 'finalfix') */
lua_getuservalue(L, idx); /* push 'ktable' (may be used by 'finalfix') */
finalfix(L, 0, NULL, p->tree);
lua_pop(L, 1); /* remove 'ktable' */
return compile(L, p);
@@ -1049,7 +1104,7 @@ static int lp_printtree (lua_State *L) {
TTree *tree = getpatt(L, 1, NULL);
int c = lua_toboolean(L, 2);
if (c) {
lua_getfenv(L, 1); /* push 'ktable' (may be used by 'finalfix') */
lua_getuservalue(L, 1); /* push 'ktable' (may be used by 'finalfix') */
finalfix(L, 0, NULL, tree);
lua_pop(L, 1); /* remove 'ktable' */
}
@@ -1102,7 +1157,7 @@ static int lp_match (lua_State *L) {
int ptop = lua_gettop(L);
lua_pushnil(L); /* initialize subscache */
lua_pushlightuserdata(L, capture); /* initialize caplistidx */
lua_getfenv(L, 1); /* initialize penvidx */
lua_getuservalue(L, 1); /* initialize penvidx */
r = match(L, s, s + i, s + l, code, capture, ptop);
if (r == NULL) {
lua_pushnil(L);
@@ -1119,8 +1174,12 @@ static int lp_match (lua_State *L) {
** =======================================================
*/
/* maximum limit for stack size */
#define MAXLIM (INT_MAX / 100)
static int lp_setmax (lua_State *L) {
luaL_optinteger(L, 1, -1);
lua_Integer lim = luaL_checkinteger(L, 1);
luaL_argcheck(L, 0 < lim && lim <= MAXLIM, 1, "out of range");
lua_settop(L, 1);
lua_setfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX);
return 0;
@@ -1144,8 +1203,7 @@ static int lp_type (lua_State *L) {
int lp_gc (lua_State *L) {
Pattern *p = getpattern(L, 1);
if (p->codesize > 0)
realloccode(L, p, 0);
realloccode(L, p, 0); /* delete code block */
return 0;
}
@@ -1228,8 +1286,8 @@ int luaopen_lpeg (lua_State *L) {
luaL_newmetatable(L, PATTERN_T);
lua_pushnumber(L, MAXBACK); /* initialize maximum backtracking */
lua_setfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX);
luaL_register(L, NULL, metareg);
luaL_register(L, "lpeg", pattreg);
luaL_setfuncs(L, metareg, 0);
luaL_newlib(L, pattreg);
lua_pushvalue(L, -1);
lua_setfield(L, -3, "__index");
return 1;

View File

@@ -1,7 +1,7 @@
/*
** $Id: lptypes.h,v 1.10 2014/12/12 17:11:35 roberto Exp $
** $Id: lptypes.h,v 1.14 2015/09/28 17:17:41 roberto Exp $
** LPeg - PEG pattern matching for Lua
** Copyright 2007-2014, Lua.org & PUC-Rio (see 'lpeg.html' for license)
** Copyright 2007-2015, Lua.org & PUC-Rio (see 'lpeg.html' for license)
** written by Roberto Ierusalimschy
*/
@@ -19,7 +19,7 @@
#include "lua.h"
#define VERSION "0.12.1"
#define VERSION "1.0.0"
#define PATTERN_T "lpeg-pattern"
@@ -27,31 +27,31 @@
/*
** compatibility with Lua 5.2
** compatibility with Lua 5.1
*/
#if (LUA_VERSION_NUM >= 502)
#if (LUA_VERSION_NUM == 501)
#undef lua_equal
#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
#define lp_equal lua_equal
#undef lua_getfenv
#define lua_getfenv lua_getuservalue
#undef lua_setfenv
#define lua_setfenv lua_setuservalue
#define lua_getuservalue lua_getfenv
#define lua_setuservalue lua_setfenv
#undef lua_objlen
#define lua_objlen lua_rawlen
#define lua_rawlen lua_objlen
#undef luaL_register
#define luaL_register(L,n,f) \
{ if ((n) == NULL) luaL_setfuncs(L,f,0); else luaL_newlib(L,f); }
#define luaL_setfuncs(L,f,n) luaL_register(L,NULL,f)
#define luaL_newlib(L,f) luaL_register(L,"lpeg",f)
#endif
#if !defined(lp_equal)
#define lp_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
#endif
/* default maximum size for call/backtrack stack */
#if !defined(MAXBACK)
#define MAXBACK 100
#define MAXBACK 400
#endif

View File

@@ -1,5 +1,5 @@
/*
** $Id: lpvm.c,v 1.5 2013/04/12 16:29:49 roberto Exp $
** $Id: lpvm.c,v 1.6 2015/09/28 17:01:25 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/
@@ -18,7 +18,7 @@
/* initial size for call/backtrack stack */
#if !defined(INITBACK)
#define INITBACK 100
#define INITBACK MAXBACK
#endif
@@ -70,7 +70,7 @@ static Stack *doublestack (lua_State *L, Stack **stacklimit, int ptop) {
max = lua_tointeger(L, -1); /* maximum allowed size */
lua_pop(L, 1);
if (n >= max) /* already at maximum size? */
luaL_error(L, "too many pending calls/choices");
luaL_error(L, "backtrack stack overflow (current limit is %d)", max);
newn = 2 * n; /* new size */
if (newn > max) newn = max;
newstack = (Stack *)lua_newuserdata(L, newn * sizeof(Stack));

View File

@@ -10,7 +10,7 @@
</head>
<body>
<!-- $Id: re.html,v 1.21 2013/03/28 20:43:30 roberto Exp $ -->
<!-- $Id: re.html,v 1.23 2015/09/28 17:17:41 roberto Exp $ -->
<div id="container">
@@ -296,7 +296,7 @@ it would be useful if each table had
a <code>tag</code> field telling what non terminal
that table represents.
We can add such a tag using
<a href="lpeg.html/#cap-g">named group captures</a>:
<a href="lpeg.html#cap-g">named group captures</a>:
</p>
<pre class="example">
x = re.compile[[
@@ -450,7 +450,7 @@ print(re.match(p, p)) -- a self description must match itself
<h2><a name="license">License</a></h2>
<p>
Copyright &copy; 2008-2010 Lua.org, PUC-Rio.
Copyright &copy; 2008-2015 Lua.org, PUC-Rio.
</p>
<p>
Permission is hereby granted, free of charge,
@@ -488,7 +488,7 @@ THE SOFTWARE.
<div id="about">
<p><small>
$Id: re.html,v 1.21 2013/03/28 20:43:30 roberto Exp $
$Id: re.html,v 1.23 2015/09/28 17:17:41 roberto Exp $
</small></p>
</div> <!-- id="about" -->

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env lua5.1
#!/usr/bin/env lua
-- $Id: test.lua,v 1.105 2014/12/12 17:00:39 roberto Exp $
-- $Id: test.lua,v 1.109 2015/09/28 17:01:25 roberto Exp $
-- require"strict" -- just to be pedantic
@@ -16,9 +16,6 @@ local unpack = rawget(table, "unpack") or unpack
local loadstring = rawget(_G, "loadstring") or load
-- most tests here do not need much stack space
m.setmaxstack(5)
local any = m.P(1)
local space = m.S" \t\n"^0
@@ -291,6 +288,13 @@ assert(m.match(m.P"ab"^-1 - "c", "abcd") == 3)
p = ('Aa' * ('Bb' * ('Cc' * m.P'Dd'^0)^0)^0)^-1
assert(p:match("AaBbCcDdBbCcDdDdDdBb") == 21)
-- bug in 0.12.2
-- p = { ('ab' ('c' 'ef'?)*)? }
p = m.C(('ab' * ('c' * m.P'ef'^-1)^0)^-1)
s = "abcefccefc"
assert(s == p:match(s))
pi = "3.14159 26535 89793 23846 26433 83279 50288 41971 69399 37510"
@@ -352,6 +356,11 @@ checkeq(t, {hi = 10, ho = 20})
t = p:match'abc'
checkeq(t, {hi = 10, ho = 20, 'a', 'b', 'c'})
-- non-string group names
p = m.Ct(m.Cg(1, print) * m.Cg(1, 23.5) * m.Cg(1, io))
t = p:match('abcdefghij')
assert(t[print] == 'a' and t[23.5] == 'b' and t[io] == 'c')
-- test for error messages
local function checkerr (msg, f, ...)
@@ -388,6 +397,25 @@ p = m.P { (m.P {m.P'abc'} + 'ayz') * m.V'y'; y = m.P'x' }
assert(p:match('abcx') == 5 and p:match('ayzx') == 5 and not p:match'abc')
do
-- large dynamic Cc
local lim = 2^16 - 1
local c = 0
local function seq (n)
if n == 1 then c = c + 1; return m.Cc(c)
else
local m = math.floor(n / 2)
return seq(m) * seq(n - m)
end
end
p = m.Ct(seq(lim))
t = p:match('')
assert(t[lim] == lim)
checkerr("too many", function () p = p / print end)
checkerr("too many", seq, lim + 1)
end
-- tests for non-pattern as arguments to pattern functions
p = { ('a' * m.V(1))^-1 } * m.P'b' * { 'a' * m.V(2); m.V(1)^-1 }
@@ -575,9 +603,9 @@ assert(not p:match(string.rep("011", 10001)))
-- this grammar does need backtracking info.
local lim = 10000
p = m.P{ '0' * m.V(1) + '0' }
checkerr("too many pending", m.match, p, string.rep("0", lim))
checkerr("stack overflow", m.match, p, string.rep("0", lim))
m.setmaxstack(2*lim)
checkerr("too many pending", m.match, p, string.rep("0", lim))
checkerr("stack overflow", m.match, p, string.rep("0", lim))
m.setmaxstack(2*lim + 4)
assert(m.match(p, string.rep("0", lim)) == lim + 1)
@@ -586,7 +614,7 @@ p = m.P{ ('a' * m.V(1))^0 * 'b' + 'c' }
m.setmaxstack(200)
assert(p:match(string.rep('a', 180) .. 'c' .. string.rep('b', 180)) == 362)
m.setmaxstack(5) -- restore original limit
m.setmaxstack(100) -- restore low limit
-- tests for optional start position
assert(m.match("a", "abc", 1))
@@ -718,6 +746,10 @@ t = {m.match(m.Cc(nil,nil,4) * m.Cc(nil,3) * m.Cc(nil, nil) / g / g, "")}
t1 = {1,1,nil,nil,4,nil,3,nil,nil}
for i=1,10 do assert(t[i] == t1[i]) end
-- bug in 0.12.2: ktable with only nil could be eliminated when joining
-- with a pattern without ktable
assert((m.P"aaa" * m.Cc(nil)):match"aaa" == nil)
t = {m.match((m.C(1) / function (x) return x, x.."x" end)^0, "abc")}
checkeq(t, {"a", "ax", "b", "bx", "c", "cx"})
@@ -925,6 +957,13 @@ p = m.Cg(m.C(1) * m.C(1), "k") * m.Ct(m.Cb("k"))
t = p:match("ab")
checkeq(t, {"a", "b"})
p = m.P(true)
for i = 1, 10 do p = p * m.Cg(1, i) end
for i = 1, 10 do
local p = p * m.Cb(i)
assert(p:match('abcdefghij') == string.sub('abcdefghij', i, i))
end
t = {}
function foo (p) t[#t + 1] = p; return p .. "x" end

View File

@@ -19,7 +19,7 @@ SYSCFLAGS=
SYSLDFLAGS=
SYSLIBS=
MYCFLAGS=
MYCFLAGS=-I../../skynet-src
MYLDFLAGS=
MYLIBS=
MYOBJS=
@@ -130,68 +130,68 @@ solaris:
# DO NOT DELETE
lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \
ltable.h lundump.h lvm.h
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \
ltable.h lundump.h lvm.h
lauxlib.o: lauxlib.c lprefix.h lua.h luaconf.h lauxlib.h
lbaselib.o: lbaselib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lbitlib.o: lbitlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lcode.o: lcode.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
ldo.h lgc.h lstring.h ltable.h lvm.h
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
ldo.h lgc.h lstring.h ltable.h lvm.h
lcorolib.o: lcorolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lctype.o: lctype.c lprefix.h lctype.h lua.h luaconf.h llimits.h
ldblib.o: ldblib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ldebug.o: ldebug.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \
ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h
lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \
ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h
ldo.o: ldo.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \
lparser.h lstring.h ltable.h lundump.h lvm.h
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \
lparser.h lstring.h ltable.h lundump.h lvm.h
ldump.o: ldump.c lprefix.h lua.h luaconf.h lobject.h llimits.h lstate.h \
ltm.h lzio.h lmem.h lundump.h
ltm.h lzio.h lmem.h lundump.h
lfunc.o: lfunc.c lprefix.h lua.h luaconf.h lfunc.h lobject.h llimits.h \
lgc.h lstate.h ltm.h lzio.h lmem.h
lgc.h lstate.h ltm.h lzio.h lmem.h
lgc.o: lgc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
linit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h
liolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldo.h \
lobject.h lstate.h ltm.h lzio.h lmem.h lgc.h llex.h lparser.h lstring.h \
ltable.h
llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \
lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lgc.h llex.h lparser.h \
lstring.h ltable.h
lmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lmem.o: lmem.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h
loadlib.o: loadlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lobject.o: lobject.c lprefix.h lua.h luaconf.h lctype.h llimits.h \
ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \
lvm.h
ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \
lvm.h
lopcodes.o: lopcodes.c lprefix.h lopcodes.h llimits.h lua.h luaconf.h
loslib.o: loslib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lparser.o: lparser.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
ldo.h lfunc.h lstring.h lgc.h ltable.h
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
ldo.h lfunc.h lstring.h lgc.h ltable.h
lstate.o: lstate.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h \
lstring.h ltable.h
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h \
lstring.h ltable.h
lstring.o: lstring.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h
lstrlib.o: lstrlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ltable.o: ltable.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
ltablib.o: ltablib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ltm.o: ltm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h ltable.h lvm.h
llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h ltable.h lvm.h
lua.o: lua.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
luac.o: luac.c lprefix.h lua.h luaconf.h lauxlib.h lobject.h llimits.h \
lstate.h ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h
lstate.h ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h
lundump.o: lundump.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \
lundump.h
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \
lundump.h
lutf8lib.o: lutf8lib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lvm.o: lvm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \
ltable.h lvm.h
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \
ltable.h lvm.h
lzio.o: lzio.c lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \
lobject.h ltm.h lzio.h
lobject.h ltm.h lzio.h
# (end of Makefile)

View File

@@ -1,5 +1,6 @@
This is a modify version of lua 5.3.0 (http://www.lua.org/ftp/lua-5.3.0.tar.gz) .
For detail : http://lua-users.org/lists/lua-l/2014-03/msg00489.html
This is a modify version of lua 5.3.2 (http://www.lua.org/ftp/lua-5.3.2.tar.gz) .
For detail ,
Shared Proto : http://lua-users.org/lists/lua-l/2014-03/msg00489.html
Shared short string table : http://blog.codingnow.com/2015/08/lua_vm_share_string.html
Signal for debug use : http://blog.codingnow.com/2015/03/skynet_signal.html

View File

@@ -1,5 +1,5 @@
/*
** $Id: lapi.c,v 2.244 2014/12/26 14:43:45 roberto Exp $
** $Id: lapi.c,v 2.259 2016/02/29 14:27:14 roberto Exp $
** Lua API
** See Copyright Notice in lua.h
*/
@@ -52,29 +52,29 @@ const char lua_ident[] =
/* test for valid but not pseudo index */
#define isstackindex(i, o) (isvalid(o) && !ispseudo(i))
#define api_checkvalidindex(o) api_check(isvalid(o), "invalid index")
#define api_checkvalidindex(l,o) api_check(l, isvalid(o), "invalid index")
#define api_checkstackindex(i, o) \
api_check(isstackindex(i, o), "index not in the stack")
#define api_checkstackindex(l, i, o) \
api_check(l, isstackindex(i, o), "index not in the stack")
static TValue *index2addr (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
TValue *o = ci->func + idx;
api_check(idx <= ci->top - (ci->func + 1), "unacceptable index");
api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index");
if (o >= L->top) return NONVALIDVALUE;
else return o;
}
else if (!ispseudo(idx)) { /* negative index */
api_check(idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
return L->top + idx;
}
else if (idx == LUA_REGISTRYINDEX)
return &G(L)->l_registry;
else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx;
api_check(idx <= MAXUPVAL + 1, "upvalue index too large");
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
if (ttislcf(ci->func)) /* light C function? */
return NONVALIDVALUE; /* it has no upvalues */
else {
@@ -99,7 +99,7 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
int res;
CallInfo *ci = L->ci;
lua_lock(L);
api_check(n >= 0, "negative 'n'");
api_check(L, n >= 0, "negative 'n'");
if (L->stack_last - L->top > n) /* stack large enough? */
res = 1; /* yes; check is OK */
else { /* no; need to grow stack */
@@ -121,11 +121,12 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
if (from == to) return;
lua_lock(to);
api_checknelems(from, n);
api_check(G(from) == G(to), "moving among independent states");
api_check(to->ci->top - to->top >= n, "not enough elements to move");
api_check(from, G(from) == G(to), "moving among independent states");
api_check(from, to->ci->top - to->top >= n, "stack overflow");
from->top -= n;
for (i = 0; i < n; i++) {
setobj2s(to, to->top++, from->top + i);
setobj2s(to, to->top, from->top + i);
to->top++; /* stack already checked by previous 'api_check' */
}
lua_unlock(to);
}
@@ -160,7 +161,7 @@ LUA_API const lua_Number *lua_version (lua_State *L) {
LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || ispseudo(idx))
? idx
: cast_int(L->top - L->ci->func + idx);
: cast_int(L->top - L->ci->func) + idx;
}
@@ -173,13 +174,13 @@ LUA_API void lua_settop (lua_State *L, int idx) {
StkId func = L->ci->func;
lua_lock(L);
if (idx >= 0) {
api_check(idx <= L->stack_last - (func + 1), "new top too large");
api_check(L, idx <= L->stack_last - (func + 1), "new top too large");
while (L->top < (func + 1) + idx)
setnilvalue(L->top++);
L->top = (func + 1) + idx;
}
else {
api_check(-(idx+1) <= (L->top - (func + 1)), "invalid new top");
api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
L->top += idx+1; /* 'subtract' index (index is negative) */
}
lua_unlock(L);
@@ -209,8 +210,8 @@ LUA_API void lua_rotate (lua_State *L, int idx, int n) {
lua_lock(L);
t = L->top - 1; /* end of stack segment being rotated */
p = index2addr(L, idx); /* start of segment */
api_checkstackindex(idx, p);
api_check((n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
api_checkstackindex(L, idx, p);
api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
reverse(L, p, m); /* reverse the prefix with length 'n' */
reverse(L, m + 1, t); /* reverse the suffix */
@@ -224,7 +225,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
lua_lock(L);
fr = index2addr(L, fromidx);
to = index2addr(L, toidx);
api_checkvalidindex(to);
api_checkvalidindex(L, to);
setobj(L, to, fr);
if (isupvalue(toidx)) /* function upvalue? */
luaC_barrier(L, clCvalue(L->ci->func), fr);
@@ -256,7 +257,7 @@ LUA_API int lua_type (lua_State *L, int idx) {
LUA_API const char *lua_typename (lua_State *L, int t) {
UNUSED(L);
api_check(LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag");
api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag");
return ttypename(t);
}
@@ -306,7 +307,7 @@ LUA_API void lua_arith (lua_State *L, int op) {
else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1);
setobjs2s(L, L->top, L->top - 1);
L->top++;
api_incr_top(L);
}
/* first operand at top - 2, second at top - 1; result go to top - 2 */
luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2);
@@ -326,7 +327,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); break;
case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break;
case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break;
default: api_check(0, "invalid option");
default: api_check(L, 0, "invalid option");
}
}
lua_unlock(L);
@@ -378,20 +379,22 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
return NULL;
}
lua_lock(L); /* 'luaO_tostring' may create a new string */
luaO_tostring(L, o);
luaC_checkGC(L);
o = index2addr(L, idx); /* previous call may reallocate the stack */
luaO_tostring(L, o);
lua_unlock(L);
}
if (len != NULL) *len = tsvalue(o)->len;
if (len != NULL)
*len = vslen(o);
return svalue(o);
}
LUA_API size_t lua_rawlen (lua_State *L, int idx) {
StkId o = index2addr(L, idx);
switch (ttnov(o)) {
case LUA_TSTRING: return tsvalue(o)->len;
switch (ttype(o)) {
case LUA_TSHRSTR: return tsvalue(o)->shrlen;
case LUA_TLNGSTR: return tsvalue(o)->u.lnglen;
case LUA_TUSERDATA: return uvalue(o)->len;
case LUA_TTABLE: return luaH_getn(hvalue(o));
default: return 0;
@@ -432,9 +435,8 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
case LUA_TCCL: return clCvalue(o);
case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o)));
case LUA_TTHREAD: return thvalue(o);
case LUA_TUSERDATA:
case LUA_TLIGHTUSERDATA:
return lua_touserdata(L, idx);
case LUA_TUSERDATA: return getudatamem(uvalue(o));
case LUA_TLIGHTUSERDATA: return pvalue(o);
default: return NULL;
}
}
@@ -470,33 +472,37 @@ LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
}
/*
** Pushes on the stack a string with given length. Avoid using 's' when
** 'len' == 0 (as 's' can be NULL in that case), due to later use of
** 'memcmp' and 'memcpy'.
*/
LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts;
lua_lock(L);
luaC_checkGC(L);
ts = luaS_newlstr(L, s, len);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
setsvalue2s(L, L->top, ts);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
return getstr(ts);
}
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
if (s == NULL) {
lua_pushnil(L);
return NULL;
}
lua_lock(L);
if (s == NULL)
setnilvalue(L->top);
else {
TString *ts;
lua_lock(L);
luaC_checkGC(L);
ts = luaS_new(L, s);
setsvalue2s(L, L->top, ts);
api_incr_top(L);
lua_unlock(L);
return getstr(ts);
s = getstr(ts); /* internal copy's address */
}
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
return s;
}
@@ -504,8 +510,8 @@ LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,
va_list argp) {
const char *ret;
lua_lock(L);
luaC_checkGC(L);
ret = luaO_pushvfstring(L, fmt, argp);
luaC_checkGC(L);
lua_unlock(L);
return ret;
}
@@ -515,10 +521,10 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
const char *ret;
va_list argp;
lua_lock(L);
luaC_checkGC(L);
va_start(argp, fmt);
ret = luaO_pushvfstring(L, fmt, argp);
va_end(argp);
luaC_checkGC(L);
lua_unlock(L);
return ret;
}
@@ -532,8 +538,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
else {
CClosure *cl;
api_checknelems(L, n);
api_check(n <= MAXUPVAL, "upvalue index too large");
luaC_checkGC(L);
api_check(L, n <= MAXUPVAL, "upvalue index too large");
cl = luaF_newCclosure(L, n);
cl->f = fn;
L->top -= n;
@@ -544,6 +549,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
setclCvalue(L, L->top, cl);
}
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
}
@@ -579,18 +585,30 @@ LUA_API int lua_pushthread (lua_State *L) {
*/
LUA_API int lua_getglobal (lua_State *L, const char *name) {
Table *reg = hvalue(&G(L)->l_registry);
const TValue *gt; /* global table */
lua_lock(L);
gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
setsvalue2s(L, L->top++, luaS_new(L, name));
luaV_gettable(L, gt, L->top - 1, L->top - 1);
static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot;
TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
setobj2s(L, L->top, slot);
api_incr_top(L);
}
else {
setsvalue2s(L, L->top, str);
api_incr_top(L);
luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
}
lua_unlock(L);
return ttnov(L->top - 1);
}
LUA_API int lua_getglobal (lua_State *L, const char *name) {
Table *reg = hvalue(&G(L)->l_registry);
lua_lock(L);
return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
}
LUA_API int lua_gettable (lua_State *L, int idx) {
StkId t;
lua_lock(L);
@@ -602,24 +620,25 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
LUA_API int lua_getfield (lua_State *L, int idx, const char *k) {
StkId t;
lua_lock(L);
t = index2addr(L, idx);
setsvalue2s(L, L->top, luaS_new(L, k));
api_incr_top(L);
luaV_gettable(L, t, L->top - 1, L->top - 1);
lua_unlock(L);
return ttnov(L->top - 1);
return auxgetstr(L, index2addr(L, idx), k);
}
LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
StkId t;
const TValue *slot;
lua_lock(L);
t = index2addr(L, idx);
setivalue(L->top, n);
api_incr_top(L);
luaV_gettable(L, t, L->top - 1, L->top - 1);
if (luaV_fastget(L, t, n, slot, luaH_getint)) {
setobj2s(L, L->top, slot);
api_incr_top(L);
}
else {
setivalue(L->top, n);
api_incr_top(L);
luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
}
lua_unlock(L);
return ttnov(L->top - 1);
}
@@ -629,7 +648,7 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
StkId t;
lua_lock(L);
t = index2addr(L, idx);
api_check(ttistable(t), "table expected");
api_check(L, ttistable(t), "table expected");
setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1));
lua_unlock(L);
return ttnov(L->top - 1);
@@ -640,7 +659,7 @@ LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) {
StkId t;
lua_lock(L);
t = index2addr(L, idx);
api_check(ttistable(t), "table expected");
api_check(L, ttistable(t), "table expected");
setobj2s(L, L->top, luaH_getint(hvalue(t), n));
api_incr_top(L);
lua_unlock(L);
@@ -653,7 +672,7 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
TValue k;
lua_lock(L);
t = index2addr(L, idx);
api_check(ttistable(t), "table expected");
api_check(L, ttistable(t), "table expected");
setpvalue(&k, cast(void *, p));
setobj2s(L, L->top, luaH_get(hvalue(t), &k));
api_incr_top(L);
@@ -665,12 +684,12 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t;
lua_lock(L);
luaC_checkGC(L);
t = luaH_new(L);
sethvalue(L, L->top, t);
api_incr_top(L);
if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec);
luaC_checkGC(L);
lua_unlock(L);
}
@@ -706,7 +725,7 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) {
StkId o;
lua_lock(L);
o = index2addr(L, idx);
api_check(ttisfulluserdata(o), "full userdata expected");
api_check(L, ttisfulluserdata(o), "full userdata expected");
getuservalue(L, uvalue(o), L->top);
api_incr_top(L);
lua_unlock(L);
@@ -718,17 +737,29 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) {
** set functions (stack -> Lua)
*/
/*
** t[k] = value at the top of the stack (where 'k' is a string)
*/
static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot;
TString *str = luaS_new(L, k);
api_checknelems(L, 1);
if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1))
L->top--; /* pop value */
else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
api_incr_top(L);
luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
L->top -= 2; /* pop value and key */
}
lua_unlock(L); /* lock done by caller */
}
LUA_API void lua_setglobal (lua_State *L, const char *name) {
Table *reg = hvalue(&G(L)->l_registry);
const TValue *gt; /* global table */
lua_lock(L);
api_checknelems(L, 1);
gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
setsvalue2s(L, L->top++, luaS_new(L, name));
luaV_settable(L, gt, L->top - 1, L->top - 2);
L->top -= 2; /* pop value and key */
lua_unlock(L);
lua_lock(L); /* unlock done in 'auxsetstr' */
auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
}
@@ -744,40 +775,40 @@ LUA_API void lua_settable (lua_State *L, int idx) {
LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
StkId t;
lua_lock(L);
api_checknelems(L, 1);
t = index2addr(L, idx);
setsvalue2s(L, L->top++, luaS_new(L, k));
luaV_settable(L, t, L->top - 1, L->top - 2);
L->top -= 2; /* pop value and key */
lua_unlock(L);
lua_lock(L); /* unlock done in 'auxsetstr' */
auxsetstr(L, index2addr(L, idx), k);
}
LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
StkId t;
const TValue *slot;
lua_lock(L);
api_checknelems(L, 1);
t = index2addr(L, idx);
setivalue(L->top++, n);
luaV_settable(L, t, L->top - 1, L->top - 2);
L->top -= 2; /* pop value and key */
if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1))
L->top--; /* pop value */
else {
setivalue(L->top, n);
api_incr_top(L);
luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
L->top -= 2; /* pop value and key */
}
lua_unlock(L);
}
LUA_API void lua_rawset (lua_State *L, int idx) {
StkId o;
Table *t;
TValue *slot;
lua_lock(L);
api_checknelems(L, 2);
o = index2addr(L, idx);
api_check(ttistable(o), "table expected");
t = hvalue(o);
setobj2t(L, luaH_set(L, t, L->top-2), L->top-1);
invalidateTMcache(t);
luaC_barrierback(L, t, L->top-1);
api_check(L, ttistable(o), "table expected");
slot = luaH_set(L, hvalue(o), L->top - 2);
setobj2t(L, slot, L->top - 1);
invalidateTMcache(hvalue(o));
luaC_barrierback(L, hvalue(o), L->top-1);
L->top -= 2;
lua_unlock(L);
}
@@ -785,14 +816,12 @@ LUA_API void lua_rawset (lua_State *L, int idx) {
LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
StkId o;
Table *t;
lua_lock(L);
api_checknelems(L, 1);
o = index2addr(L, idx);
api_check(ttistable(o), "table expected");
t = hvalue(o);
luaH_setint(L, t, n, L->top - 1);
luaC_barrierback(L, t, L->top-1);
api_check(L, ttistable(o), "table expected");
luaH_setint(L, hvalue(o), n, L->top - 1);
luaC_barrierback(L, hvalue(o), L->top-1);
L->top--;
lua_unlock(L);
}
@@ -800,16 +829,15 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
StkId o;
Table *t;
TValue k;
TValue k, *slot;
lua_lock(L);
api_checknelems(L, 1);
o = index2addr(L, idx);
api_check(ttistable(o), "table expected");
t = hvalue(o);
api_check(L, ttistable(o), "table expected");
setpvalue(&k, cast(void *, p));
setobj2t(L, luaH_set(L, t, &k), L->top - 1);
luaC_barrierback(L, t, L->top - 1);
slot = luaH_set(L, hvalue(o), &k);
setobj2t(L, slot, L->top - 1);
luaC_barrierback(L, hvalue(o), L->top - 1);
L->top--;
lua_unlock(L);
}
@@ -824,7 +852,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
if (ttisnil(L->top - 1))
mt = NULL;
else {
api_check(ttistable(L->top - 1), "table expected");
api_check(L, ttistable(L->top - 1), "table expected");
mt = hvalue(L->top - 1);
}
switch (ttnov(obj)) {
@@ -860,7 +888,7 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
o = index2addr(L, idx);
api_check(ttisfulluserdata(o), "full userdata expected");
api_check(L, ttisfulluserdata(o), "full userdata expected");
setuservalue(L, uvalue(o), L->top - 1);
luaC_barrier(L, gcvalue(o), L->top - 1);
L->top--;
@@ -874,7 +902,7 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) {
#define checkresults(L,na,nr) \
api_check((nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
"results from function overflow current stack size")
@@ -882,19 +910,19 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
lua_KContext ctx, lua_KFunction k) {
StkId func;
lua_lock(L);
api_check(k == NULL || !isLua(L->ci),
api_check(L, k == NULL || !isLua(L->ci),
"cannot use continuations inside hooks");
api_checknelems(L, nargs+1);
api_check(L->status == LUA_OK, "cannot do calls on non-normal thread");
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults);
func = L->top - (nargs+1);
if (k != NULL && L->nny == 0) { /* need to prepare continuation? */
L->ci->u.c.k = k; /* save continuation */
L->ci->u.c.ctx = ctx; /* save context */
luaD_call(L, func, nresults, 1); /* do the call */
luaD_call(L, func, nresults); /* do the call */
}
else /* no continuation or no yieldable */
luaD_call(L, func, nresults, 0); /* just do the call */
luaD_callnoyield(L, func, nresults); /* just do the call */
adjustresults(L, nresults);
lua_unlock(L);
}
@@ -912,7 +940,7 @@ struct CallS { /* data to 'f_call' */
static void f_call (lua_State *L, void *ud) {
struct CallS *c = cast(struct CallS *, ud);
luaD_call(L, c->func, c->nresults, 0);
luaD_callnoyield(L, c->func, c->nresults);
}
@@ -923,16 +951,16 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
int status;
ptrdiff_t func;
lua_lock(L);
api_check(k == NULL || !isLua(L->ci),
api_check(L, k == NULL || !isLua(L->ci),
"cannot use continuations inside hooks");
api_checknelems(L, nargs+1);
api_check(L->status == LUA_OK, "cannot do calls on non-normal thread");
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults);
if (errfunc == 0)
func = 0;
else {
StkId o = index2addr(L, errfunc);
api_checkstackindex(errfunc, o);
api_checkstackindex(L, errfunc, o);
func = savestack(L, o);
}
c.func = L->top - (nargs+1); /* function to be called */
@@ -950,7 +978,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
L->errfunc = func;
setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */
ci->callstatus |= CIST_YPCALL; /* function can do error recovery */
luaD_call(L, c.func, nresults, 1); /* do the call */
luaD_call(L, c.func, nresults); /* do the call */
ci->callstatus &= ~CIST_YPCALL;
L->errfunc = ci->u.c.old_errfunc;
status = LUA_OK; /* if it is here, there were no errors */
@@ -984,11 +1012,9 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
return status;
}
static Proto * cloneproto (lua_State *L, const Proto *src) {
void cloneproto (lua_State *L, Proto *f, const Proto *src) {
/* copy constants and nested proto */
int i,n;
Proto *f = luaF_newproto(L, src->sp);
n = src->sp->sizek;
f->k=luaM_newvector(L,n,TValue);
for (i=0; i<n; i++) setnilvalue(&f->k[i]);
@@ -996,7 +1022,7 @@ static Proto * cloneproto (lua_State *L, const Proto *src) {
const TValue *s=&src->k[i];
TValue *o=&f->k[i];
if (ttisstring(s)) {
TString * str = luaS_newlstr(L,svalue(s),tsvalue(s)->len);
TString * str = luaS_clonestring(L,tsvalue(s));
setsvalue2n(L,o,str);
} else {
setobj(L,o,s);
@@ -1006,9 +1032,9 @@ static Proto * cloneproto (lua_State *L, const Proto *src) {
f->p=luaM_newvector(L,n,struct Proto *);
for (i=0; i<n; i++) f->p[i]=NULL;
for (i=0; i<n; i++) {
f->p[i]=cloneproto(L, src->p[i]);
f->p[i]= luaF_newproto(L, src->p[i]->sp);
cloneproto(L, f->p[i], src->p[i]);
}
return f;
}
LUA_API void lua_clonefunction (lua_State *L, const void * fp) {
@@ -1022,9 +1048,10 @@ LUA_API void lua_clonefunction (lua_State *L, const void * fp) {
return;
}
cl = luaF_newLclosure(L,f->nupvalues);
cl->p = cloneproto(L, f->p);
setclLvalue(L,L->top,cl);
api_incr_top(L);
cl->p = luaF_newproto(L, f->p->sp);
cloneproto(L, cl->p, f->p);
luaF_initupvals(L, cl);
if (cl->nupvalues >= 1) { /* does it have an upvalue? */
@@ -1092,7 +1119,7 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
}
case LUA_GCSTEP: {
l_mem debt = 1; /* =1 to signal that it did an actual step */
int oldrunning = g->gcrunning;
lu_byte oldrunning = g->gcrunning;
g->gcrunning = 1; /* allow GC to run */
if (data == 0) {
luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */
@@ -1150,7 +1177,7 @@ LUA_API int lua_next (lua_State *L, int idx) {
int more;
lua_lock(L);
t = index2addr(L, idx);
api_check(ttistable(t), "table expected");
api_check(L, ttistable(t), "table expected");
more = luaH_next(L, hvalue(t), L->top - 1);
if (more) {
api_incr_top(L);
@@ -1166,7 +1193,6 @@ LUA_API void lua_concat (lua_State *L, int n) {
lua_lock(L);
api_checknelems(L, n);
if (n >= 2) {
luaC_checkGC(L);
luaV_concat(L, n);
}
else if (n == 0) { /* push empty string */
@@ -1174,6 +1200,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
api_incr_top(L);
}
/* else n == 1; nothing to do */
luaC_checkGC(L);
lua_unlock(L);
}
@@ -1209,10 +1236,10 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {
LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
Udata *u;
lua_lock(L);
luaC_checkGC(L);
u = luaS_newudata(L, size);
setuvalue(L, L->top, u);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
return getudatamem(u);
}
@@ -1282,9 +1309,9 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {
LClosure *f;
StkId fi = index2addr(L, fidx);
api_check(ttisLclosure(fi), "Lua function expected");
api_check(L, ttisLclosure(fi), "Lua function expected");
f = clLvalue(fi);
api_check((1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
api_check(L, (1 <= n && n <= f->p->sp->sizeupvalues), "invalid upvalue index");
if (pf) *pf = f;
return &f->upvals[n - 1]; /* get its upvalue pointer */
}
@@ -1298,11 +1325,11 @@ LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) {
}
case LUA_TCCL: { /* C closure */
CClosure *f = clCvalue(fi);
api_check(1 <= n && n <= f->nupvalues, "invalid upvalue index");
api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index");
return &f->upvalue[n - 1];
}
default: {
api_check(0, "closure expected");
api_check(L, 0, "closure expected");
return NULL;
}
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lapi.h,v 2.8 2014/07/15 21:26:50 roberto Exp $
** $Id: lapi.h,v 2.9 2015/03/06 19:49:50 roberto Exp $
** Auxiliary functions from Lua API
** See Copyright Notice in lua.h
*/
@@ -11,13 +11,13 @@
#include "llimits.h"
#include "lstate.h"
#define api_incr_top(L) {L->top++; api_check(L->top <= L->ci->top, \
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
"stack overflow");}
#define adjustresults(L,nres) \
{ if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
#define api_checknelems(L,n) api_check((n) < (L->top - L->ci->func), \
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
"not enough elements in the stack")

View File

@@ -1,5 +1,5 @@
/*
** $Id: lauxlib.c,v 1.279 2014/12/14 18:32:26 roberto Exp $
** $Id: lauxlib.c,v 1.286 2016/01/08 15:33:09 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -17,7 +17,8 @@
#include <string.h>
/* This file uses only the official API of Lua.
/*
** This file uses only the official API of Lua.
** Any function declared here could be written as an application function.
*/
@@ -33,8 +34,8 @@
*/
#define LEVELS1 12 /* size of the first part of the stack */
#define LEVELS2 10 /* size of the second part of the stack */
#define LEVELS1 10 /* size of the first part of the stack */
#define LEVELS2 11 /* size of the second part of the stack */
@@ -107,7 +108,7 @@ static void pushfuncname (lua_State *L, lua_Debug *ar) {
}
static int countlevels (lua_State *L) {
static int lastlevel (lua_State *L) {
lua_Debug ar;
int li = 1, le = 1;
/* find an upper bound */
@@ -126,14 +127,16 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
const char *msg, int level) {
lua_Debug ar;
int top = lua_gettop(L);
int numlevels = countlevels(L1);
int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;
if (msg) lua_pushfstring(L, "%s\n", msg);
int last = lastlevel(L1);
int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1;
if (msg)
lua_pushfstring(L, "%s\n", msg);
luaL_checkstack(L, 10, NULL);
lua_pushliteral(L, "stack traceback:");
while (lua_getstack(L1, level++, &ar)) {
if (level == mark) { /* too many levels? */
if (n1-- == 0) { /* too many levels? */
lua_pushliteral(L, "\n\t..."); /* add a '...' */
level = numlevels - LEVELS2; /* and skip to last ones */
level = last - LEVELS2 + 1; /* and skip to last ones */
}
else {
lua_getinfo(L1, "Slnt", &ar);
@@ -196,6 +199,10 @@ static void tag_error (lua_State *L, int arg, int tag) {
}
/*
** The use of 'lua_pushfstring' ensures this function does not
** need reserved stack space when called.
*/
LUALIB_API void luaL_where (lua_State *L, int level) {
lua_Debug ar;
if (lua_getstack(L, level, &ar)) { /* check function at level */
@@ -205,10 +212,15 @@ LUALIB_API void luaL_where (lua_State *L, int level) {
return;
}
}
lua_pushliteral(L, ""); /* else, no information available... */
lua_pushfstring(L, ""); /* else, no information available... */
}
/*
** Again, the use of 'lua_pushvfstring' ensures this function does
** not need reserved stack space when called. (At worst, it generates
** an error with "stack overflow" instead of the given message.)
*/
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
@@ -286,10 +298,10 @@ LUALIB_API int luaL_execresult (lua_State *L, int stat) {
*/
LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
if (luaL_getmetatable(L, tname)) /* name already in use? */
if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */
return 0; /* leave previous value on top, but return 0 */
lua_pop(L, 1);
lua_newtable(L); /* create metatable */
lua_createtable(L, 0, 2); /* create metatable */
lua_pushstring(L, tname);
lua_setfield(L, -2, "__name"); /* metatable.__name = tname */
lua_pushvalue(L, -1);
@@ -347,10 +359,15 @@ LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,
}
/*
** Ensures the stack has at least 'space' extra slots, raising an error
** if it cannot fulfill the request. (The error handling needs a few
** extra slots to format the error message. In case of an error without
** this extra space, Lua will generate the same 'stack overflow' error,
** but without 'msg'.)
*/
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
/* keep some extra space to run error routines, if needed */
const int extra = LUA_MINSTACK;
if (!lua_checkstack(L, space + extra)) {
if (!lua_checkstack(L, space)) {
if (msg)
luaL_error(L, "stack overflow (%s)", msg);
else
@@ -435,6 +452,47 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg,
** =======================================================
*/
/* userdata to box arbitrary data */
typedef struct UBox {
void *box;
size_t bsize;
} UBox;
static void *resizebox (lua_State *L, int idx, size_t newsize) {
void *ud;
lua_Alloc allocf = lua_getallocf(L, &ud);
UBox *box = (UBox *)lua_touserdata(L, idx);
void *temp = allocf(ud, box->box, box->bsize, newsize);
if (temp == NULL && newsize > 0) { /* allocation error? */
resizebox(L, idx, 0); /* free buffer */
luaL_error(L, "not enough memory for buffer allocation");
}
box->box = temp;
box->bsize = newsize;
return temp;
}
static int boxgc (lua_State *L) {
resizebox(L, 1, 0);
return 0;
}
static void *newbox (lua_State *L, size_t newsize) {
UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox));
box->box = NULL;
box->bsize = 0;
if (luaL_newmetatable(L, "LUABOX")) { /* creating metatable? */
lua_pushcfunction(L, boxgc);
lua_setfield(L, -2, "__gc"); /* metatable.__gc = boxgc */
}
lua_setmetatable(L, -2);
return resizebox(L, -1, newsize);
}
/*
** check whether buffer is using a userdata on the stack as a temporary
** buffer
@@ -455,11 +513,12 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
if (newsize < B->n || newsize - B->n < sz)
luaL_error(L, "buffer too large");
/* create larger buffer */
newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char));
/* move content to new buffer */
memcpy(newbuff, B->b, B->n * sizeof(char));
if (buffonstack(B))
lua_remove(L, -2); /* remove old buffer */
newbuff = (char *)resizebox(L, -1, newsize);
else { /* no buffer yet */
newbuff = (char *)newbox(L, newsize);
memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */
}
B->b = newbuff;
B->size = newsize;
}
@@ -468,9 +527,11 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
char *b = luaL_prepbuffsize(B, l);
memcpy(b, s, l * sizeof(char));
luaL_addsize(B, l);
if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */
char *b = luaL_prepbuffsize(B, l);
memcpy(b, s, l * sizeof(char));
luaL_addsize(B, l);
}
}
@@ -482,8 +543,10 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
lua_State *L = B->L;
lua_pushlstring(L, B->b, B->n);
if (buffonstack(B))
lua_remove(L, -2); /* remove old buffer */
if (buffonstack(B)) {
resizebox(L, -2, 0); /* delete old buffer */
lua_remove(L, -2); /* remove its header from the stack */
}
}
@@ -605,7 +668,7 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
static int skipBOM (LoadF *lf) {
const char *p = "\xEF\xBB\xBF"; /* Utf8 BOM mark */
const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
int c;
lf->n = 0;
do {
@@ -630,7 +693,7 @@ static int skipcomment (LoadF *lf, int *cp) {
if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */
c = getc(lf->f);
} while (c != EOF && c != '\n') ;
} while (c != EOF && c != '\n');
*cp = getc(lf->f); /* skip end-of-line, if present */
return 1; /* there was a comment */
}
@@ -972,29 +1035,28 @@ LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) {
// use clonefunction
#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {}
#define UNLOCK(q) __sync_lock_release(&(q)->lock);
#include "spinlock.h"
struct codecache {
int lock;
struct spinlock lock;
lua_State *L;
};
static struct codecache CC = { 0 , NULL };
static struct codecache CC;
static void
clearcache() {
if (CC.L == NULL)
return;
LOCK(&CC)
SPIN_LOCK(&CC)
lua_close(CC.L);
CC.L = luaL_newstate();
UNLOCK(&CC)
SPIN_UNLOCK(&CC)
}
static void
init() {
CC.lock = 0;
SPIN_INIT(&CC);
CC.L = luaL_newstate();
}
@@ -1002,13 +1064,13 @@ static const void *
load(const char *key) {
if (CC.L == NULL)
return NULL;
LOCK(&CC)
SPIN_LOCK(&CC)
lua_State *L = CC.L;
lua_pushstring(L, key);
lua_rawget(L, LUA_REGISTRYINDEX);
const void * result = lua_touserdata(L, -1);
lua_pop(L, 1);
UNLOCK(&CC)
SPIN_UNLOCK(&CC)
return result;
}
@@ -1018,7 +1080,7 @@ save(const char *key, const void * proto) {
lua_State *L;
const void * result = NULL;
LOCK(&CC)
SPIN_LOCK(&CC)
if (CC.L == NULL) {
init();
L = CC.L;
@@ -1036,17 +1098,66 @@ save(const char *key, const void * proto) {
lua_pop(L,2);
}
}
UNLOCK(&CC)
SPIN_UNLOCK(&CC)
return result;
}
#define CACHE_OFF 0
#define CACHE_EXIST 1
#define CACHE_ON 2
static int cache_key = 0;
static int cache_level(lua_State *L) {
int t = lua_rawgetp(L, LUA_REGISTRYINDEX, &cache_key);
int r = lua_tointeger(L, -1);
lua_pop(L,1);
if (t == LUA_TNUMBER) {
return r;
}
return CACHE_ON;
}
static int cache_mode(lua_State *L) {
static const char * lst[] = {
"OFF",
"EXIST",
"ON",
NULL,
};
if (lua_isnoneornil(L,1)) {
int t = lua_rawgetp(L, LUA_REGISTRYINDEX, &cache_key);
int r = lua_tointeger(L, -1);
if (t == LUA_TNUMBER) {
if (r < 0 || r >= CACHE_ON) {
r = CACHE_ON;
}
} else {
r = CACHE_ON;
}
lua_pushstring(L, lst[r]);
return 1;
}
int t = luaL_checkoption(L, 1, "OFF" , lst);
lua_pushinteger(L, t);
lua_rawsetp(L, LUA_REGISTRYINDEX, &cache_key);
return 0;
}
LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
const char *mode) {
int level = cache_level(L);
if (level == CACHE_OFF) {
return luaL_loadfilex_(L, filename, mode);
}
const void * proto = load(filename);
if (proto) {
lua_clonefunction(L, proto);
return LUA_OK;
}
if (level == CACHE_EXIST) {
return luaL_loadfilex_(L, filename, mode);
}
lua_State * eL = luaL_newstate();
if (eL == NULL) {
lua_pushliteral(L, "New state failed");
@@ -1083,6 +1194,7 @@ cache_clear(lua_State *L) {
LUAMOD_API int luaopen_cache(lua_State *L) {
luaL_Reg l[] = {
{ "clear", cache_clear },
{ "mode", cache_mode },
{ NULL, NULL },
};
luaL_newlib(L,l);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lauxlib.h,v 1.128 2014/10/29 16:11:17 roberto Exp $
** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -65,7 +65,7 @@ LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
/* pre-defined references */
/* predefined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)

View File

@@ -1,5 +1,5 @@
/*
** $Id: lbaselib.c,v 1.309 2014/12/10 12:26:42 roberto Exp $
** $Id: lbaselib.c,v 1.313 2016/04/11 19:18:40 roberto Exp $
** Basic library
** See Copyright Notice in lua.h
*/
@@ -55,7 +55,7 @@ static const char *b_str2int (const char *s, int base, lua_Integer *pn) {
return NULL;
do {
int digit = (isdigit((unsigned char)*s)) ? *s - '0'
: toupper((unsigned char)*s) - 'A' + 10;
: (toupper((unsigned char)*s) - 'A') + 10;
if (digit >= base) return NULL; /* invalid numeral */
n = n * base + digit;
s++;
@@ -86,8 +86,8 @@ static int luaB_tonumber (lua_State *L) {
const char *s;
lua_Integer n = 0; /* to avoid warnings */
lua_Integer base = luaL_checkinteger(L, 2);
luaL_checktype(L, 1, LUA_TSTRING); /* before 'luaL_checklstring'! */
s = luaL_checklstring(L, 1, &l);
luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */
s = lua_tolstring(L, 1, &l);
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
if (b_str2int(s, (int)base, &n) == s + l) {
lua_pushinteger(L, n);
@@ -102,8 +102,8 @@ static int luaB_tonumber (lua_State *L) {
static int luaB_error (lua_State *L) {
int level = (int)luaL_optinteger(L, 2, 1);
lua_settop(L, 1);
if (lua_isstring(L, 1) && level > 0) { /* add extra information? */
luaL_where(L, level);
if (lua_type(L, 1) == LUA_TSTRING && level > 0) {
luaL_where(L, level); /* add extra information */
lua_pushvalue(L, 1);
lua_concat(L, 2);
}
@@ -198,12 +198,10 @@ static int luaB_collectgarbage (lua_State *L) {
}
/*
** This function has all type names as upvalues, to maximize performance.
*/
static int luaB_type (lua_State *L) {
luaL_checkany(L, 1);
lua_pushvalue(L, lua_upvalueindex(lua_type(L, 1) + 1));
int t = lua_type(L, 1);
luaL_argcheck(L, t != LUA_TNONE, 1, "value expected");
lua_pushstring(L, lua_typename(L, t));
return 1;
}
@@ -243,18 +241,7 @@ static int luaB_pairs (lua_State *L) {
/*
** Traversal function for 'ipairs' for raw tables
*/
static int ipairsaux_raw (lua_State *L) {
lua_Integer i = luaL_checkinteger(L, 2) + 1;
luaL_checktype(L, 1, LUA_TTABLE);
lua_pushinteger(L, i);
return (lua_rawgeti(L, 1, i) == LUA_TNIL) ? 1 : 2;
}
/*
** Traversal function for 'ipairs' for tables with metamethods
** Traversal function for 'ipairs'
*/
static int ipairsaux (lua_State *L) {
lua_Integer i = luaL_checkinteger(L, 2) + 1;
@@ -264,18 +251,15 @@ static int ipairsaux (lua_State *L) {
/*
** This function will use either 'ipairsaux' or 'ipairsaux_raw' to
** traverse a table, depending on whether the table has metamethods
** that can affect the traversal.
** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
** (The given "table" may not be a table.)
*/
static int luaB_ipairs (lua_State *L) {
lua_CFunction iter = (luaL_getmetafield(L, 1, "__index") != LUA_TNIL)
? ipairsaux : ipairsaux_raw;
#if defined(LUA_COMPAT_IPAIRS)
return pairsmeta(L, "__ipairs", 1, iter);
return pairsmeta(L, "__ipairs", 1, ipairsaux);
#else
luaL_checkany(L, 1);
lua_pushcfunction(L, iter); /* iteration function */
lua_pushcfunction(L, ipairsaux); /* iteration function */
lua_pushvalue(L, 1); /* state */
lua_pushinteger(L, 0); /* initial value */
return 3;
@@ -490,9 +474,9 @@ static const luaL_Reg base_funcs[] = {
{"setmetatable", luaB_setmetatable},
{"tonumber", luaB_tonumber},
{"tostring", luaB_tostring},
{"type", luaB_type},
{"xpcall", luaB_xpcall},
/* placeholders */
{"type", NULL},
{"_G", NULL},
{"_VERSION", NULL},
{NULL, NULL}
@@ -500,7 +484,6 @@ static const luaL_Reg base_funcs[] = {
LUAMOD_API int luaopen_base (lua_State *L) {
int i;
/* open lib into global table */
lua_pushglobaltable(L);
luaL_setfuncs(L, base_funcs, 0);
@@ -510,11 +493,6 @@ LUAMOD_API int luaopen_base (lua_State *L) {
/* set global _VERSION */
lua_pushliteral(L, LUA_VERSION);
lua_setfield(L, -2, "_VERSION");
/* set function 'type' with proper upvalues */
for (i = 0; i < LUA_NUMTAGS; i++) /* push all type names as upvalues */
lua_pushstring(L, lua_typename(L, i));
lua_pushcclosure(L, luaB_type, LUA_NUMTAGS);
lua_setfield(L, -2, "type");
return 1;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lbitlib.c,v 1.28 2014/11/02 19:19:04 roberto Exp $
** $Id: lbitlib.c,v 1.30 2015/11/11 19:08:09 roberto Exp $
** Standard library for bitwise operations
** See Copyright Notice in lua.h
*/
@@ -19,6 +19,10 @@
#if defined(LUA_COMPAT_BITLIB) /* { */
#define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
#define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i))
/* number of bits to consider in a number */
#if !defined(LUA_NBITS)
#define LUA_NBITS 32
@@ -46,14 +50,14 @@ static lua_Unsigned andaux (lua_State *L) {
int i, n = lua_gettop(L);
lua_Unsigned r = ~(lua_Unsigned)0;
for (i = 1; i <= n; i++)
r &= luaL_checkunsigned(L, i);
r &= checkunsigned(L, i);
return trim(r);
}
static int b_and (lua_State *L) {
lua_Unsigned r = andaux(L);
lua_pushunsigned(L, r);
pushunsigned(L, r);
return 1;
}
@@ -69,8 +73,8 @@ static int b_or (lua_State *L) {
int i, n = lua_gettop(L);
lua_Unsigned r = 0;
for (i = 1; i <= n; i++)
r |= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
r |= checkunsigned(L, i);
pushunsigned(L, trim(r));
return 1;
}
@@ -79,15 +83,15 @@ static int b_xor (lua_State *L) {
int i, n = lua_gettop(L);
lua_Unsigned r = 0;
for (i = 1; i <= n; i++)
r ^= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
r ^= checkunsigned(L, i);
pushunsigned(L, trim(r));
return 1;
}
static int b_not (lua_State *L) {
lua_Unsigned r = ~luaL_checkunsigned(L, 1);
lua_pushunsigned(L, trim(r));
lua_Unsigned r = ~checkunsigned(L, 1);
pushunsigned(L, trim(r));
return 1;
}
@@ -104,23 +108,23 @@ static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) {
else r <<= i;
r = trim(r);
}
lua_pushunsigned(L, r);
pushunsigned(L, r);
return 1;
}
static int b_lshift (lua_State *L) {
return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkinteger(L, 2));
return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2));
}
static int b_rshift (lua_State *L) {
return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkinteger(L, 2));
return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2));
}
static int b_arshift (lua_State *L) {
lua_Unsigned r = luaL_checkunsigned(L, 1);
lua_Unsigned r = checkunsigned(L, 1);
lua_Integer i = luaL_checkinteger(L, 2);
if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1))))
return b_shift(L, r, -i);
@@ -128,19 +132,19 @@ static int b_arshift (lua_State *L) {
if (i >= LUA_NBITS) r = ALLONES;
else
r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */
lua_pushunsigned(L, r);
pushunsigned(L, r);
return 1;
}
}
static int b_rot (lua_State *L, lua_Integer d) {
lua_Unsigned r = luaL_checkunsigned(L, 1);
lua_Unsigned r = checkunsigned(L, 1);
int i = d & (LUA_NBITS - 1); /* i = d % NBITS */
r = trim(r);
if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */
r = (r << i) | (r >> (LUA_NBITS - i));
lua_pushunsigned(L, trim(r));
pushunsigned(L, trim(r));
return 1;
}
@@ -175,23 +179,22 @@ static int fieldargs (lua_State *L, int farg, int *width) {
static int b_extract (lua_State *L) {
int w;
lua_Unsigned r = trim(luaL_checkunsigned(L, 1));
lua_Unsigned r = trim(checkunsigned(L, 1));
int f = fieldargs(L, 2, &w);
r = (r >> f) & mask(w);
lua_pushunsigned(L, r);
pushunsigned(L, r);
return 1;
}
static int b_replace (lua_State *L) {
int w;
lua_Unsigned r = trim(luaL_checkunsigned(L, 1));
lua_Unsigned v = luaL_checkunsigned(L, 2);
lua_Unsigned r = trim(checkunsigned(L, 1));
lua_Unsigned v = trim(checkunsigned(L, 2));
int f = fieldargs(L, 3, &w);
int m = mask(w);
v &= m; /* erase bits outside given width */
r = (r & ~(m << f)) | (v << f);
lua_pushunsigned(L, r);
lua_Unsigned m = mask(w);
r = (r & ~(m << f)) | ((v & m) << f);
pushunsigned(L, r);
return 1;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
** $Id: lcode.h,v 1.63 2013/12/30 20:47:58 roberto Exp $
** $Id: lcode.h,v 1.64 2016/01/05 16:22:37 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -40,7 +40,8 @@ typedef enum BinOpr {
typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
#define getcode(fs,e) ((fs)->f->sp->code[(e)->u.info])
/* get (pointer to) instruction of given 'expdesc' */
#define getinstruction(fs,e) ((fs)->f->sp->code[(e)->u.info])
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)

View File

@@ -1,5 +1,5 @@
/*
** $Id: lcorolib.c,v 1.9 2014/11/02 19:19:04 roberto Exp $
** $Id: lcorolib.c,v 1.10 2016/04/11 19:19:55 roberto Exp $
** Coroutine Library
** See Copyright Notice in lua.h
*/
@@ -75,7 +75,7 @@ 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? */
if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */
luaL_where(L, 1); /* add extra info */
lua_insert(L, -2);
lua_concat(L, 2);

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldblib.c,v 1.148 2015/01/02 12:52:22 roberto Exp $
** $Id: ldblib.c,v 1.151 2015/11/23 11:29:43 roberto Exp $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
@@ -27,6 +27,17 @@
static const int HOOKKEY = 0;
/*
** If L1 != L, L1 can be in any state, and therefore there are no
** guarantees about its stack space; any push in L1 must be
** checked.
*/
static void checkstack (lua_State *L, lua_State *L1, int n) {
if (L != L1 && !lua_checkstack(L1, n))
luaL_error(L, "stack overflow");
}
static int db_getregistry (lua_State *L) {
lua_pushvalue(L, LUA_REGISTRYINDEX);
return 1;
@@ -127,12 +138,16 @@ static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
/*
** Calls 'lua_getinfo' and collects all results in a new table.
** L1 needs stack space for an optional input (function) plus
** two optional outputs (function and line table) from function
** 'lua_getinfo'.
*/
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, "flnStu");
checkstack(L, L1, 3);
if (lua_isfunction(L, arg + 1)) { /* info about a function? */
options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */
lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */
@@ -190,6 +205,7 @@ static int db_getlocal (lua_State *L) {
int level = (int)luaL_checkinteger(L, arg + 1);
if (!lua_getstack(L1, level, &ar)) /* out of range? */
return luaL_argerror(L, arg+1, "level out of range");
checkstack(L, L1, 1);
name = lua_getlocal(L1, &ar, nvar);
if (name) {
lua_xmove(L1, L, 1); /* move local value */
@@ -216,6 +232,7 @@ static int db_setlocal (lua_State *L) {
return luaL_argerror(L, arg+1, "level out of range");
luaL_checkany(L, arg+3);
lua_settop(L, arg+3);
checkstack(L, L1, 1);
lua_xmove(L, L1, 1);
name = lua_setlocal(L1, &ar, nvar);
if (name == NULL)
@@ -350,6 +367,7 @@ static int db_sethook (lua_State *L) {
lua_pushvalue(L, -1);
lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */
}
checkstack(L, L1, 1);
lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */
lua_pushvalue(L, arg + 1); /* value (hook function) */
lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */
@@ -370,6 +388,7 @@ static int db_gethook (lua_State *L) {
lua_pushliteral(L, "external hook");
else { /* hook table must exist */
lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
checkstack(L, L1, 1);
lua_pushthread(L1); lua_xmove(L1, L, 1);
lua_rawget(L, -2); /* 1st result = hooktable[L1] */
lua_remove(L, -2); /* remove hook table */

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldebug.c,v 2.110 2015/01/02 12:52:22 roberto Exp $
** $Id: ldebug.c,v 2.120 2016/03/31 19:01:21 roberto Exp $
** Debug Interface
** See Copyright Notice in lua.h
*/
@@ -34,6 +34,10 @@
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL)
/* Active Lua function (given call info) */
#define ci_func(ci) (clLvalue((ci)->func))
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
@@ -65,7 +69,13 @@ static void swapextra (lua_State *L) {
/*
** this function can be called asynchronous (e.g. during a signal)
** This function can be called asynchronously (e.g. during a signal).
** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by
** 'resethookcount') are for debug only, and it is no problem if they
** get arbitrary values (causes at most one wrong hook call). 'hookmask'
** is an atomic value. We assume that pointers are atomic too (e.g., gcc
** ensures that for all platforms where it runs). Moreover, 'hook' is
** always checked before being called (see 'luaD_hook').
*/
LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
if (func == NULL || mask == 0) { /* turn off hooks? */
@@ -114,7 +124,7 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
static const char *upvalname (Proto *p, int uv) {
TString *s = check_exp(uv < p->sizeupvalues, p->sp->upvalues[uv].name);
TString *s = check_exp(uv < p->sp->sizeupvalues, p->sp->upvalues[uv].name);
if (s == NULL) return "?";
else return getstr(s);
}
@@ -122,7 +132,7 @@ static const char *upvalname (Proto *p, int uv) {
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
int nparams = clLvalue(ci->func)->p->sp->numparams;
if (n >= ci->u.l.base - ci->func - nparams)
if (n >= cast_int(ci->u.l.base - ci->func) - nparams)
return NULL; /* no such vararg */
else {
*pos = ci->func + nparams + n;
@@ -168,7 +178,7 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0);
}
else { /* active function; get information through 'ar' */
StkId pos = 0; /* to avoid warnings */
StkId pos = NULL; /* to avoid warnings */
name = findlocal(L, ar->i_ci, n, &pos);
if (name) {
setobj2s(L, L->top, pos);
@@ -182,7 +192,7 @@ 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) {
StkId pos = 0; /* to avoid warnings */
StkId pos = NULL; /* to avoid warnings */
const char *name;
lua_lock(L);
swapextra(L);
@@ -295,7 +305,7 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
if (*what == '>') {
ci = NULL;
func = L->top - 1;
api_check(ttisfunction(func), "function expected");
api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */
L->top--; /* pop function */
}
@@ -554,7 +564,7 @@ static const char *varinfo (lua_State *L, const TValue *o) {
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
const char *t = objtypename(o);
const char *t = luaT_objtypename(L, o);
luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
}
@@ -586,28 +596,25 @@ l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
const char *t1 = objtypename(p1);
const char *t2 = objtypename(p2);
if (t1 == t2)
const char *t1 = luaT_objtypename(L, p1);
const char *t2 = luaT_objtypename(L, p2);
if (strcmp(t1, t2) == 0)
luaG_runerror(L, "attempt to compare two %s values", t1);
else
luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
}
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(ci);
TString *src = ci_func(ci)->p->sp->source;
if (src)
luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
else { /* no source available; use "?" instead */
buff[0] = '?'; buff[1] = '\0';
}
luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
/* add src:line information to 'msg' */
const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
int line) {
char buff[LUA_IDSIZE];
if (src)
luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
else { /* no source available; use "?" instead */
buff[0] = '?'; buff[1] = '\0';
}
return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
}
@@ -617,17 +624,21 @@ l_noret luaG_errormsg (lua_State *L) {
setobjs2s(L, L->top, L->top - 1); /* move argument */
setobjs2s(L, L->top - 1, errfunc); /* push function */
L->top++; /* assume EXTRA_STACK */
luaD_call(L, L->top - 2, 1, 0); /* call it */
luaD_callnoyield(L, L->top - 2, 1); /* call it */
}
luaD_throw(L, LUA_ERRRUN);
}
l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
CallInfo *ci = L->ci;
const char *msg;
va_list argp;
va_start(argp, fmt);
addinfo(L, luaO_pushvfstring(L, fmt, argp));
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp);
if (isLua(ci)) /* if Lua function, add source:line information */
luaG_addinfo(L, msg, ci_func(ci)->p->sp->source, currentline(ci));
luaG_errormsg(L);
}
@@ -635,9 +646,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
void luaG_traceexec (lua_State *L) {
CallInfo *ci = L->ci;
lu_byte mask = L->hookmask;
int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0);
int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
if (counthook)
resethookcount(L); /* reset count */
else if (!(mask & LUA_MASKLINE))
return; /* no line hook and count != 0; nothing to be done */
if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
return; /* do not call hook again (VM yielded, so it did not move) */

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldebug.h,v 2.12 2014/11/10 14:46:05 roberto Exp $
** $Id: ldebug.h,v 2.14 2015/05/22 17:45:56 roberto Exp $
** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h
*/
@@ -17,9 +17,6 @@
#define resethookcount(L) (L->hookcount = L->basehookcount)
/* Active Lua function (given call info) */
#define ci_func(ci) (clLvalue((ci)->func))
LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
const char *opname);
@@ -33,6 +30,8 @@ LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1,
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
const TValue *p2);
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
TString *src, int line);
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
LUAI_FUNC void luaG_traceexec (lua_State *L);

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldo.c,v 2.135 2014/11/11 17:13:39 roberto Exp $
** $Id: ldo.c,v 2.151 2015/12/16 16:40:07 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -150,6 +150,11 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
/* }====================================================== */
/*
** {==================================================================
** Stack reallocation
** ===================================================================
*/
static void correctstack (lua_State *L, TValue *oldstack) {
CallInfo *ci;
UpVal *up;
@@ -221,17 +226,30 @@ void luaD_shrinkstack (lua_State *L) {
luaE_freeCI(L); /* free all CIs (list grew because of an error) */
else
luaE_shrinkCI(L); /* shrink list */
if (inuse > LUAI_MAXSTACK || /* still handling stack overflow? */
goodsize >= L->stacksize) /* would grow instead of shrink? */
condmovestack(L); /* don't change stack (change only for debugging) */
else
if (inuse <= LUAI_MAXSTACK && /* not handling stack overflow? */
goodsize < L->stacksize) /* trying to shrink? */
luaD_reallocstack(L, goodsize); /* shrink it */
else
condmovestack(L,,); /* don't change stack (change only for debugging) */
}
void luaD_inctop (lua_State *L) {
luaD_checkstack(L, 1);
L->top++;
}
/* }================================================================== */
/*
** Call a hook for the given event. Make sure there is a hook to be
** called. (Both 'L->hook' and 'L->hookmask', which triggers this
** function, can be changed asynchronously by signals.)
*/
void luaD_hook (lua_State *L, int event, int line) {
lua_Hook hook = L->hook;
if (hook && L->allowhook) {
if (hook && L->allowhook) { /* make sure there is a hook */
CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top);
ptrdiff_t ci_top = savestack(L, ci->top);
@@ -273,15 +291,15 @@ static StkId adjust_varargs (lua_State *L, SharedProto *p, int actual) {
int i;
int nfixargs = p->numparams;
StkId base, fixed;
lua_assert(actual >= nfixargs);
/* move fixed parameters to final position */
luaD_checkstack(L, p->maxstacksize); /* check again for new 'base' */
fixed = L->top - actual; /* first fixed argument */
base = L->top; /* final position of first argument */
for (i=0; i<nfixargs; i++) {
for (i = 0; i < nfixargs && i < actual; i++) {
setobjs2s(L, L->top++, fixed + i);
setnilvalue(fixed + i);
setnilvalue(fixed + i); /* erase original copy (for GC) */
}
for (; i < nfixargs; i++)
setnilvalue(L->top++); /* complete missing arguments */
return base;
}
@@ -308,70 +326,75 @@ static void tryfuncTM (lua_State *L, StkId func) {
#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
/* macro to check stack size, preserving 'p' */
#define checkstackp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
luaC_checkGC(L), /* stack grow uses memory */ \
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
/*
** returns true if function has been executed (C function)
** Prepares a function call: checks the stack, creates a new CallInfo
** entry, fills in the relevant information, calls hook if needed.
** If function is a C function, does the call, too. (Otherwise, leave
** the execution ('luaV_execute') to the caller, to allow stackless
** calls.) Returns true iff function has been executed (C function).
*/
int luaD_precall (lua_State *L, StkId func, int nresults) {
lua_CFunction f;
CallInfo *ci;
int n; /* number of arguments (Lua) or returns (C) */
ptrdiff_t funcr = savestack(L, func);
switch (ttype(func)) {
case LUA_TCCL: /* C closure */
f = clCvalue(func)->f;
goto Cfunc;
case LUA_TLCF: /* light C function */
f = fvalue(func);
goto Cfunc;
case LUA_TCCL: { /* C closure */
f = clCvalue(func)->f;
Cfunc:
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
Cfunc: {
int n; /* number of returns */
checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = restorestack(L, funcr);
ci->func = func;
ci->top = L->top + LUA_MINSTACK;
lua_assert(ci->top <= L->stack_last);
ci->callstatus = 0;
luaC_checkGC(L); /* stack grow uses memory */
if (L->hookmask & LUA_MASKCALL)
luaD_hook(L, LUA_HOOKCALL, -1);
lua_unlock(L);
n = (*f)(L); /* do the actual call */
lua_lock(L);
api_checknelems(L, n);
luaD_poscall(L, L->top - n);
luaD_poscall(L, ci, L->top - n, n);
return 1;
}
case LUA_TLCL: { /* Lua function: prepare its call */
StkId base;
SharedProto *p = clLvalue(func)->p->sp;
n = cast_int(L->top - func) - 1; /* number of real arguments */
luaD_checkstack(L, p->maxstacksize);
for (; n < p->numparams; n++)
setnilvalue(L->top++); /* complete missing arguments */
if (!p->is_vararg) {
func = restorestack(L, funcr);
int n = cast_int(L->top - func) - 1; /* number of real arguments */
int fsize = p->maxstacksize; /* frame size */
checkstackp(L, fsize, func);
if (p->is_vararg != 1) { /* do not use vararg? */
for (; n < p->numparams; n++)
setnilvalue(L->top++); /* complete missing arguments */
base = func + 1;
}
else {
else
base = adjust_varargs(L, p, n);
func = restorestack(L, funcr); /* previous call can change stack */
}
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = func;
ci->u.l.base = base;
ci->top = base + p->maxstacksize;
L->top = ci->top = base + fsize;
lua_assert(ci->top <= L->stack_last);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus = CIST_LUA;
L->top = ci->top;
luaC_checkGC(L); /* stack grow uses memory */
if (L->hookmask & LUA_MASKCALL)
callhook(L, ci);
return 0;
}
default: { /* not a function */
luaD_checkstack(L, 1); /* ensure space for metamethod */
func = restorestack(L, funcr); /* previous call may change stack */
checkstackp(L, 1, func); /* ensure space for metamethod */
tryfuncTM(L, func); /* try to get '__call' metamethod */
return luaD_precall(L, func, nresults); /* now it must be a function */
}
@@ -379,10 +402,57 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
}
int luaD_poscall (lua_State *L, StkId firstResult) {
/*
** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'.
** Handle most typical cases (zero results for commands, one result for
** expressions, multiple results for tail calls/single parameters)
** separated.
*/
static int moveresults (lua_State *L, const TValue *firstResult, StkId res,
int nres, int wanted) {
switch (wanted) { /* handle typical cases separately */
case 0: break; /* nothing to move */
case 1: { /* one result needed */
if (nres == 0) /* no results? */
firstResult = luaO_nilobject; /* adjust with nil */
setobjs2s(L, res, firstResult); /* move it to proper place */
break;
}
case LUA_MULTRET: {
int i;
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstResult + i);
L->top = res + nres;
return 0; /* wanted == LUA_MULTRET */
}
default: {
int i;
if (wanted <= nres) { /* enough results? */
for (i = 0; i < wanted; i++) /* move wanted results to correct place */
setobjs2s(L, res + i, firstResult + i);
}
else { /* not enough results; use all of them plus nils */
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstResult + i);
for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(res + i);
}
break;
}
}
L->top = res + wanted; /* top points after the last result */
return 1;
}
/*
** Finishes a function call: calls hook if necessary, removes CallInfo,
** moves current number of results to proper place; returns 0 iff call
** wanted multiple (variable number of) results.
*/
int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
StkId res;
int wanted, i;
CallInfo *ci = L->ci;
int wanted = ci->nresults;
if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
if (L->hookmask & LUA_MASKRET) {
ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
@@ -392,15 +462,24 @@ int luaD_poscall (lua_State *L, StkId firstResult) {
L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
}
res = ci->func; /* res == final position of 1st result */
wanted = ci->nresults;
L->ci = ci = ci->previous; /* back to caller */
/* 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 */
L->ci = ci->previous; /* back to caller */
/* move results to proper place */
return moveresults(L, firstResult, res, nres, wanted);
}
/*
** Check appropriate error for stack overflow ("regular" overflow or
** overflow while handling stack overflow). If 'nCalls' is larger than
** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but
** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to
** allow overflow handling to work)
*/
static void stackerror (lua_State *L) {
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 */
}
@@ -410,21 +489,25 @@ int luaD_poscall (lua_State *L, StkId firstResult) {
** 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, int allowyield) {
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 (!allowyield) L->nny++;
void luaD_call (lua_State *L, StkId func, int nResults) {
if (++L->nCcalls >= LUAI_MAXCCALLS)
stackerror(L);
if (!luaD_precall(L, func, nResults)) /* is a Lua function? */
luaV_execute(L); /* call it */
if (!allowyield) L->nny--;
L->nCcalls--;
}
/*
** Similar to 'luaD_call', but does not allow yields during the call
*/
void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
L->nny++;
luaD_call(L, func, nResults);
L->nny--;
}
/*
** Completes the execution of an interrupted C function, calling its
** continuation function.
@@ -449,7 +532,7 @@ static void finishCcall (lua_State *L, int status) {
lua_lock(L);
api_checknelems(L, n);
/* finish 'luaD_precall' */
luaD_poscall(L, L->top - n);
luaD_poscall(L, ci, L->top - n, n);
}
@@ -533,7 +616,8 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
*/
static void resume (lua_State *L, void *ud) {
int nCcalls = L->nCcalls;
StkId firstArg = cast(StkId, ud);
int n = *(cast(int*, ud)); /* number of arguments */
StkId firstArg = L->top - n; /* first argument */
CallInfo *ci = L->ci;
if (nCcalls >= LUAI_MAXCCALLS)
resume_error(L, "C stack overflow", firstArg);
@@ -553,14 +637,13 @@ static void resume (lua_State *L, void *ud) {
luaV_execute(L); /* just continue running Lua code */
else { /* 'common' yield */
if (ci->u.c.k != NULL) { /* does it have a continuation function? */
int n;
lua_unlock(L);
n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */
lua_lock(L);
api_checknelems(L, n);
firstArg = L->top - n; /* yield results come from continuation */
}
luaD_poscall(L, firstArg); /* finish 'luaD_precall' */
luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */
}
unroll(L, NULL); /* run continuation */
}
@@ -570,13 +653,13 @@ static void resume (lua_State *L, void *ud) {
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
int status;
int oldnny = L->nny; /* save "number of non-yieldable" calls */
unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */
lua_lock(L);
luai_userstateresume(L, nargs);
L->nCcalls = (from) ? from->nCcalls + 1 : 1;
L->nny = 0; /* allow yields */
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
status = luaD_rawrunprotected(L, resume, L->top - nargs);
status = luaD_rawrunprotected(L, resume, &nargs);
if (status == -1) /* error calling 'lua_resume'? */
status = LUA_ERRRUN;
else { /* continue running after recoverable errors */
@@ -619,7 +702,7 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
L->status = LUA_YIELD;
ci->extra = savestack(L, ci->func); /* save current 'func' */
if (isLua(ci)) { /* inside a hook? */
api_check(k == NULL, "hooks cannot continue after yielding");
api_check(L, k == NULL, "hooks cannot continue after yielding");
}
else {
if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
@@ -684,13 +767,13 @@ static void f_parser (lua_State *L, void *ud) {
int c = zgetc(p->z); /* read first character */
if (c == LUA_SIGNATURE[0]) {
checkmode(L, p->mode, "binary");
cl = luaU_undump(L, p->z, &p->buff, p->name);
cl = luaU_undump(L, p->z, p->name);
}
else {
checkmode(L, p->mode, "text");
cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
}
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
lua_assert(cl->nupvalues == cl->p->sp->sizeupvalues);
luaF_initupvals(L, cl);
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldo.h,v 2.21 2014/10/25 11:50:46 roberto Exp $
** $Id: ldo.h,v 2.29 2015/12/21 13:02:14 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -13,11 +13,21 @@
#include "lzio.h"
#define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \
luaD_growstack(L, n); else condmovestack(L);
/*
** Macro to check stack size and grow stack if needed. Parameters
** 'pre'/'pos' allow the macro to preserve a pointer into the
** stack across reallocations, doing the work only when needed.
** 'condmovestack' is used in heavy tests to force a stack reallocation
** at every check.
*/
#define luaD_checkstackaux(L,n,pre,pos) \
if (L->stack_last - L->top <= (n)) \
{ pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); }
/* In general, 'pre'/'pos' are empty (nothing to save) */
#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)
#define incr_top(L) {L->top++; luaD_checkstack(L,0);}
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
#define restorestack(L,n) ((TValue *)((char *)L->stack + (n)))
@@ -30,14 +40,16 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
const char *mode);
LUAI_FUNC void luaD_hook (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,
int allowyield);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (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 int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult,
int nres);
LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
LUAI_FUNC void luaD_growstack (lua_State *L, int n);
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
LUAI_FUNC void luaD_inctop (lua_State *L);
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldump.c,v 2.34 2014/11/02 19:19:04 roberto Exp $
** $Id: ldump.c,v 2.37 2015/10/08 15:53:49 roberto Exp $
** save precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -38,7 +38,7 @@ typedef struct {
static void DumpBlock (const void *b, size_t size, DumpState *D) {
if (D->status == 0) {
if (D->status == 0 && size > 0) {
lua_unlock(D->L);
D->status = (*D->writer)(D->L, b, size, D->data);
lua_lock(D->L);
@@ -74,14 +74,15 @@ static void DumpString (const TString *s, DumpState *D) {
if (s == NULL)
DumpByte(0, D);
else {
size_t size = s->len + 1; /* include trailing '\0' */
size_t size = tsslen(s) + 1; /* include trailing '\0' */
const char *str = getstr(s);
if (size < 0xFF)
DumpByte(cast_int(size), D);
else {
DumpByte(0xFF, D);
DumpVar(size, D);
}
DumpVector(getstr(s), size - 1, D); /* no need to save '\0' */
DumpVector(str, size - 1, D); /* no need to save '\0' */
}
}

View File

@@ -127,6 +127,7 @@ Proto *luaF_newproto (lua_State *L, SharedProto *sp) {
return f;
}
static void freesharedproto (lua_State *L, SharedProto *f) {
if (f == NULL || G(L) != f->l_G)
return;
@@ -137,7 +138,6 @@ static void freesharedproto (lua_State *L, SharedProto *f) {
luaM_free(L, f);
}
void luaF_freeproto (lua_State *L, Proto *f) {
luaM_freearray(L, f->p, f->sp->sizep);
luaM_freearray(L, f->k, f->sp->sizek);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lfunc.h,v 2.14 2014/06/19 18:27:20 roberto Exp $
** $Id: lfunc.h,v 2.15 2015/01/13 15:49:11 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@@ -22,6 +22,13 @@
#define isintwups(L) (L->twups != L)
/*
** maximum number of upvalues in a closure (both C and Lua). (Value
** must fit in a VM register.)
*/
#define MAXUPVAL 255
/*
** Upvalues for Lua closures
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lgc.c,v 2.201 2014/12/20 13:58:15 roberto Exp $
** $Id: lgc.c,v 2.212 2016/03/31 19:02:03 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -83,8 +83,13 @@
#define markvalue(g,o) { checkconsistency(o); \
if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
#define markobject(g,t) \
{ if ((t) && iswhite(t)) reallymarkobject(g, obj2gco(t)); }
#define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); }
/*
** mark an object that can be NULL (either because it is really optional,
** or it was stripped as debug info, or inside an uncompleted structure)
*/
#define markobjectN(g,t) { if (t) markobject(g,t); }
static void reallymarkobject (global_State *g, GCObject *o);
@@ -109,8 +114,13 @@ static void reallymarkobject (global_State *g, GCObject *o);
/*
** if key is not marked, mark its entry as dead (therefore removing it
** from the table)
** If key is not marked, mark its entry as dead. This allows key to be
** collected, but keeps its entry in the table. A dead node is needed
** when Lua looks up for a key (it may be part of a chain) and when
** traversing a weak table (key might be removed from the table during
** traversal). Other places never manipulate dead keys, because its
** associated nil value is enough to signal that the entry is logically
** empty.
*/
static void removeentry (Node *n) {
lua_assert(ttisnil(gval(n)));
@@ -183,7 +193,8 @@ void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) {
void luaC_fix (lua_State *L, GCObject *o) {
global_State *g = G(L);
lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */
if (g->allgc != o)
return; /* if object is not 1st in 'allgc' list, it is in global short string table */
white2gray(o); /* they will be gray forever */
g->allgc = o->next; /* remove object from 'allgc' list */
o->next = g->fixedgc; /* link it to 'fixedgc' list */
@@ -226,15 +237,19 @@ static void reallymarkobject (global_State *g, GCObject *o) {
reentry:
white2gray(o);
switch (o->tt) {
case LUA_TSHRSTR:
case LUA_TSHRSTR: {
gray2black(o);
g->GCmemtrav += sizelstring(gco2ts(o)->shrlen);
break;
}
case LUA_TLNGSTR: {
gray2black(o);
g->GCmemtrav += sizestring(gco2ts(o));
g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen);
break;
}
case LUA_TUSERDATA: {
TValue uvalue;
markobject(g, gco2u(o)->metatable); /* mark its metatable */
markobjectN(g, gco2u(o)->metatable); /* mark its metatable */
gray2black(o);
g->GCmemtrav += sizeudata(gco2u(o));
getuservalue(g->mainthread, gco2u(o), &uvalue);
@@ -275,7 +290,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
static void markmt (global_State *g) {
int i;
for (i=0; i < LUA_NUMTAGS; i++)
markobject(g, g->mt[i]);
markobjectN(g, g->mt[i]);
}
@@ -437,7 +452,7 @@ static void traversestrongtable (global_State *g, Table *h) {
static lu_mem traversetable (global_State *g, Table *h) {
const char *weakkey, *weakvalue;
const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
markobject(g, h->metatable);
markobjectN(g, h->metatable);
if (mode && ttisstring(mode) && /* is there a weak mode? */
((weakkey = strchr(svalue(mode), 'k')),
(weakvalue = strchr(svalue(mode), 'v')),
@@ -460,27 +475,36 @@ static int marksharedproto (global_State *g, SharedProto *f) {
int i;
if (g != f->l_G)
return 0;
markobject(g, f->source);
markobjectN(g, f->source);
for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */
markobject(g, f->upvalues[i].name);
markobjectN(g, f->upvalues[i].name);
for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
markobject(g, f->locvars[i].varname);
markobjectN(g, f->locvars[i].varname);
return sizeof(Instruction) * f->sizecode +
sizeof(int) * f->sizelineinfo +
sizeof(LocVar) * f->sizelocvars +
sizeof(Upvaldesc) * f->sizeupvalues;
}
/*
** Traverse a prototype. (While a prototype is being build, its
** arrays can be larger than needed; the extra slots are filled with
** NULL, so the use of 'markobjectN')
*/
static int traverseproto (global_State *g, Proto *f) {
int i;
int i,nk,np;
if (f->cache && iswhite(f->cache))
f->cache = NULL; /* allow cache to be collected */
for (i = 0; i < f->sp->sizek; i++) /* mark literals */
if (f->sp == NULL)
return sizeof(Proto);
nk = (f->k == NULL) ? 0 : f->sp->sizek;
np = (f->p == NULL) ? 0 : f->sp->sizep;
for (i = 0; i < nk; i++) /* mark literals */
markvalue(g, &f->k[i]);
for (i = 0; i < f->sp->sizep; i++) /* mark nested protos */
markobject(g, f->p[i]);
return sizeof(Proto) + sizeof(Proto *) * f->sp->sizep +
sizeof(TValue) * f->sp->sizek +
for (i = 0; i < np; i++) /* mark nested protos */
markobjectN(g, f->p[i]);
return sizeof(Proto) + sizeof(Proto *) * np +
sizeof(TValue) * nk +
marksharedproto(g, f->sp);
}
@@ -500,7 +524,7 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) {
*/
static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
int i;
markobject(g, cl->p); /* mark its prototype */
markobjectN(g, cl->p); /* mark its prototype */
for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */
UpVal *uv = cl->upvals[i];
if (uv != NULL) {
@@ -534,7 +558,8 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
}
else if (g->gckind != KGC_EMERGENCY)
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
return (sizeof(lua_State) + sizeof(TValue) * th->stacksize);
return (sizeof(lua_State) + sizeof(TValue) * th->stacksize +
sizeof(CallInfo) * th->nci);
}
@@ -695,9 +720,10 @@ static void freeobj (lua_State *L, GCObject *o) {
case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
case LUA_TSHRSTR:
luaS_remove(L, gco2ts(o)); /* remove it from hash table */
/* go through */
luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen));
break;
case LUA_TLNGSTR: {
luaM_freemem(L, o, sizestring(gco2ts(o)));
luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen));
break;
}
default: lua_assert(0);
@@ -739,14 +765,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
/*
** sweep a list until a live object (or end of list)
*/
static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
static GCObject **sweeptolive (lua_State *L, GCObject **p) {
GCObject **old = p;
int i = 0;
do {
i++;
p = sweeplist(L, p, 1);
} while (p == old);
if (n) *n += i;
return p;
}
@@ -760,12 +783,11 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
*/
/*
** If possible, free concatenation buffer and shrink string table
** If possible, shrink string table
*/
static void checkSizes (lua_State *L, global_State *g) {
if (g->gckind != KGC_EMERGENCY) {
l_mem olddebt = g->GCdebt;
luaZ_freebuffer(L, &g->buff); /* free concatenation buffer */
if (g->strt.nuse < g->strt.size / 4) /* string table too big? */
luaS_resize(L, g->strt.size / 2); /* shrink it a little */
g->GCestimate += g->GCdebt - olddebt; /* update estimate */
@@ -788,7 +810,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) {
UNUSED(ud);
luaD_call(L, L->top - 2, 0, 0);
luaD_callnoyield(L, L->top - 2, 0);
}
@@ -842,10 +864,10 @@ static int runafewfinalizers (lua_State *L) {
/*
** call all pending finalizers
*/
static void callallpendingfinalizers (lua_State *L, int propagateerrors) {
static void callallpendingfinalizers (lua_State *L) {
global_State *g = G(L);
while (g->tobefnz)
GCTM(L, propagateerrors);
GCTM(L, 0);
}
@@ -895,7 +917,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
if (issweepphase(g)) {
makewhite(g, o); /* "sweep" object 'o' */
if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */
g->sweepgc = sweeptolive(L, g->sweepgc, NULL); /* change 'sweepgc' */
g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */
}
/* search for pointer pointing to 'o' */
for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }
@@ -937,19 +959,16 @@ static void setpause (global_State *g) {
/*
** Enter first sweep phase.
** The call to 'sweeptolive' makes pointer point to an object inside
** the list (instead of to the header), so that the real sweep do not
** need to skip objects created between "now" and the start of the real
** sweep.
** Returns how many objects it swept.
** The call to 'sweeplist' tries to make pointer point to an object
** inside the list (instead of to the header), so that the real sweep do
** not need to skip objects created between "now" and the start of the
** real sweep.
*/
static int entersweep (lua_State *L) {
static void entersweep (lua_State *L) {
global_State *g = G(L);
int n = 0;
g->gcstate = GCSswpallgc;
lua_assert(g->sweepgc == NULL);
g->sweepgc = sweeptolive(L, &g->allgc, &n);
return n;
g->sweepgc = sweeplist(L, &g->allgc, 1);
}
@@ -957,7 +976,7 @@ void luaC_freeallobjects (lua_State *L) {
global_State *g = G(L);
separatetobefnz(g, 1); /* separate all objects with finalizers */
lua_assert(g->finobj == NULL);
callallpendingfinalizers(L, 0);
callallpendingfinalizers(L);
lua_assert(g->tobefnz == NULL);
g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
g->gckind = KGC_NORMAL;
@@ -1008,6 +1027,7 @@ static l_mem atomic (lua_State *L) {
/* clear values from resurrected weak tables */
clearvalues(g, g->weak, origweak);
clearvalues(g, g->allweak, origall);
luaS_clearcache(g);
g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
work += g->GCmemtrav; /* complete counting */
return work; /* estimate of memory marked by 'atomic' */
@@ -1049,12 +1069,11 @@ static lu_mem singlestep (lua_State *L) {
}
case GCSatomic: {
lu_mem work;
int sw;
propagateall(g); /* make sure gray list is empty */
work = atomic(L); /* work is what was traversed by 'atomic' */
sw = entersweep(L);
entersweep(L);
g->GCestimate = gettotalbytes(g); /* first estimate */;
return work + sw * GCSWEEPCOST;
return work;
}
case GCSswpallgc: { /* sweep "regular" objects */
return sweepstep(L, g, GCSswpfinobj, &g->finobj);
@@ -1104,9 +1123,12 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
static l_mem getdebt (global_State *g) {
l_mem debt = g->GCdebt;
int stepmul = g->gcstepmul;
debt = (debt / STEPMULADJ) + 1;
debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
return debt;
if (debt <= 0) return 0; /* minimal debt */
else {
debt = (debt / STEPMULADJ) + 1;
debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
return debt;
}
}
/*

View File

@@ -1,5 +1,5 @@
/*
** $Id: lgc.h,v 2.86 2014/10/25 11:50:46 roberto Exp $
** $Id: lgc.h,v 2.91 2015/12/21 13:02:14 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -101,26 +101,35 @@
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
#define luaC_condGC(L,c) \
{if (G(L)->GCdebt > 0) {c;}; condchangemem(L);}
#define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);)
/*
** Does one step of collection when debt becomes positive. 'pre'/'pos'
** allows some adjustments to be done only when needed. macro
** 'condchangemem' is used only for heavy tests (forcing a full
** GC cycle on every opportunity)
*/
#define luaC_condGC(L,pre,pos) \
{ if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \
condchangemem(L,pre,pos); }
/* more often than not, 'pre'/'pos' are empty */
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
#define luaC_barrier(L,p,v) { \
if (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) \
luaC_barrier_(L,obj2gco(p),gcvalue(v)); }
#define luaC_barrier(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
#define luaC_barrierback(L,p,v) { \
if (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) \
luaC_barrierback_(L,p); }
#define luaC_barrierback(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrierback_(L,p) : cast_void(0))
#define luaC_objbarrier(L,p,o) { \
if (isblack(p) && iswhite(o)) \
luaC_barrier_(L,obj2gco(p),obj2gco(o)); }
#define luaC_objbarrier(L,p,o) ( \
(isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
#define luaC_upvalbarrier(L,uv) \
{ if (iscollectable((uv)->v) && !upisopen(uv)) \
luaC_upvalbarrier_(L,uv); }
#define luaC_upvalbarrier(L,uv) ( \
(iscollectable((uv)->v) && !upisopen(uv)) ? \
luaC_upvalbarrier_(L,uv) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);

View File

@@ -1,5 +1,5 @@
/*
** $Id: liolib.c,v 2.142 2015/01/02 12:50:28 roberto Exp $
** $Id: liolib.c,v 2.149 2016/05/02 14:03:19 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
@@ -23,18 +23,24 @@
#include "lualib.h"
#if !defined(l_checkmode)
/*
** Check whether 'mode' matches '[rwa]%+?b?'.
** Change this macro to accept other modes for 'fopen' besides
** the standard ones.
*/
#if !defined(l_checkmode)
/* accepted extensions to 'mode' in 'fopen' */
#if !defined(L_MODEEXT)
#define L_MODEEXT "b"
#endif
/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */
#define l_checkmode(mode) \
(*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \
(*mode != '+' || ++mode) && /* skip if char is '+' */ \
(*mode != 'b' || ++mode) && /* skip if char is 'b' */ \
(*mode == '\0'))
(*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ \
(strspn(mode, L_MODEEXT) == strlen(mode)))
#endif
@@ -176,7 +182,7 @@ static FILE *tofile (lua_State *L) {
/*
** 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.
** handle is in a consistent state.
*/
static LStream *newprefile (lua_State *L) {
LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream));
@@ -318,8 +324,15 @@ static int io_output (lua_State *L) {
static int io_readline (lua_State *L);
/*
** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit
** in the limit for upvalues of a closure)
*/
#define MAXARGLINE 250
static void aux_lines (lua_State *L, int toclose) {
int n = lua_gettop(L) - 1; /* number of arguments to read */
luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments");
lua_pushinteger(L, n); /* number of arguments to read */
lua_pushboolean(L, toclose); /* close/not close file when finished */
lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */
@@ -362,14 +375,17 @@ static int io_lines (lua_State *L) {
/* maximum length of a numeral */
#define MAXRN 200
#if !defined (L_MAXLENNUM)
#define L_MAXLENNUM 200
#endif
/* auxiliary structure used by 'read_number' */
typedef struct {
FILE *f; /* file being read */
int c; /* current character (look ahead) */
int n; /* number of elements in buffer 'buff' */
char buff[MAXRN + 1]; /* +1 for ending '\0' */
char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */
} RN;
@@ -377,7 +393,7 @@ typedef struct {
** Add current char to buffer (if not out of space) and read next one
*/
static int nextc (RN *rn) {
if (rn->n >= MAXRN) { /* buffer overflow? */
if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */
rn->buff[0] = '\0'; /* invalidate result */
return 0; /* fail */
}
@@ -390,10 +406,10 @@ static int nextc (RN *rn) {
/*
** Accept current char if it is in 'set' (of size 1 or 2)
** Accept current char if it is in 'set' (of size 2)
*/
static int test2 (RN *rn, const char *set) {
if (rn->c == set[0] || (rn->c == set[1] && rn->c != '\0'))
if (rn->c == set[0] || rn->c == set[1])
return nextc(rn);
else return 0;
}
@@ -410,12 +426,6 @@ static int readdigits (RN *rn, int hex) {
}
/* access to locale "radix character" (decimal point) */
#if !defined(l_getlocaledecpoint)
#define l_getlocaledecpoint() (localeconv()->decimal_point[0])
#endif
/*
** Read a number: first reads a valid prefix of a numeral into a buffer.
** Then it calls 'lua_stringtonumber' to check whether the format is
@@ -425,13 +435,14 @@ static int read_number (lua_State *L, FILE *f) {
RN rn;
int count = 0;
int hex = 0;
char decp[2] = ".";
char decp[2];
rn.f = f; rn.n = 0;
decp[0] = l_getlocaledecpoint(); /* get decimal point from locale */
decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */
decp[1] = '.'; /* always accept a dot */
l_lockfile(rn.f);
do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */
test2(&rn, "-+"); /* optional signal */
if (test2(&rn, "0")) {
if (test2(&rn, "00")) {
if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */
else count = 1; /* count initial '0' as a valid digit */
}
@@ -457,7 +468,7 @@ static int read_number (lua_State *L, FILE *f) {
static int test_eof (lua_State *L, FILE *f) {
int c = getc(f);
ungetc(c, f); /* no-op when c == EOF */
lua_pushlstring(L, NULL, 0);
lua_pushliteral(L, "");
return (c != EOF);
}
@@ -467,7 +478,7 @@ static int read_line (lua_State *L, FILE *f, int chop) {
int c = '\0';
luaL_buffinit(L, &b);
while (c != EOF && c != '\n') { /* repeat until end of line */
char *buff = luaL_prepbuffer(&b); /* pre-allocate buffer */
char *buff = luaL_prepbuffer(&b); /* preallocate buffer */
int i = 0;
l_lockfile(f); /* no memory errors can happen inside the lock */
while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n')
@@ -488,7 +499,7 @@ static void read_all (lua_State *L, FILE *f) {
luaL_Buffer b;
luaL_buffinit(L, &b);
do { /* read file in chunks of LUAL_BUFFERSIZE bytes */
char *p = luaL_prepbuffsize(&b, LUAL_BUFFERSIZE);
char *p = luaL_prepbuffer(&b);
nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f);
luaL_addsize(&b, nr);
} while (nr == LUAL_BUFFERSIZE);

View File

@@ -1,5 +1,5 @@
/*
** $Id: llex.c,v 2.89 2014/11/14 16:06:09 roberto Exp $
** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -16,6 +16,7 @@
#include "lua.h"
#include "lctype.h"
#include "ldebug.h"
#include "ldo.h"
#include "lgc.h"
#include "llex.h"
@@ -68,7 +69,7 @@ static void save (LexState *ls, int c) {
void luaX_init (lua_State *L) {
int i;
TString *e = luaS_new(L, LUA_ENV); /* create env name */
TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */
luaC_fix(L, obj2gco(e)); /* never collect this name */
for (i=0; i<NUM_RESERVED; i++) {
TString *ts = luaS_new(L, luaX_tokens[i]);
@@ -106,9 +107,7 @@ static const char *txtToken (LexState *ls, int token) {
static l_noret lexerror (LexState *ls, const char *msg, int token) {
char buff[LUA_IDSIZE];
luaO_chunkid(buff, getstr(ls->source), LUA_IDSIZE);
msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg);
msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber);
if (token)
luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token));
luaD_throw(ls->L, LUA_ERRSYNTAX);
@@ -163,7 +162,6 @@ static void inclinenumber (LexState *ls) {
void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
int firstchar) {
ls->t.token = 0;
ls->decpoint = '.';
ls->L = L;
ls->current = firstchar;
ls->lookahead.token = TK_EOS; /* no look-ahead token */
@@ -172,7 +170,7 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
ls->linenumber = 1;
ls->lastline = 1;
ls->source = source;
ls->envn = luaS_new(L, LUA_ENV); /* get env name */
ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
}
@@ -208,42 +206,6 @@ static int check_next2 (LexState *ls, const char *set) {
}
/*
** change all characters 'from' in buffer to 'to'
*/
static void buffreplace (LexState *ls, char from, char to) {
if (from != to) {
size_t n = luaZ_bufflen(ls->buff);
char *p = luaZ_buffer(ls->buff);
while (n--)
if (p[n] == from) p[n] = to;
}
}
#if !defined(l_getlocaledecpoint)
#define l_getlocaledecpoint() (localeconv()->decimal_point[0])
#endif
#define buff2num(b,o) (luaO_str2num(luaZ_buffer(b), o) != 0)
/*
** in case of format error, try to change decimal point separator to
** the one defined in the current locale and check again
*/
static void trydecpoint (LexState *ls, TValue *o) {
char old = ls->decpoint;
ls->decpoint = l_getlocaledecpoint();
buffreplace(ls, old, ls->decpoint); /* try new decimal separator */
if (!buff2num(ls->buff, o)) {
/* format error with correct decimal point: no more options */
buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
lexerror(ls, "malformed number", TK_FLT);
}
}
/* LUA_NUMBER */
/*
** this function is quite liberal in what it accepts, as 'luaO_str2num'
@@ -267,9 +229,8 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) {
else break;
}
save(ls, '\0');
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
if (!buff2num(ls->buff, &obj)) /* format error? */
trydecpoint(ls, &obj); /* try to update decimal point separator */
if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */
lexerror(ls, "malformed number", TK_FLT);
if (ttisinteger(&obj)) {
seminfo->i = ivalue(&obj);
return TK_INT;
@@ -283,8 +244,9 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) {
/*
** skip a sequence '[=*[' or ']=*]' and return its number of '='s or
** -1 if sequence is malformed
** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return
** its number of '='s; otherwise, return a negative number (-1 iff there
** are no '='s after initial bracket)
*/
static int skip_sep (LexState *ls) {
int count = 0;
@@ -501,8 +463,9 @@ static int llex (LexState *ls, SemInfo *seminfo) {
read_long_string(ls, seminfo, sep);
return TK_STRING;
}
else if (sep == -1) return '[';
else lexerror(ls, "invalid long string delimiter", TK_STRING);
else if (sep != -1) /* '[=...' missing second bracket */
lexerror(ls, "invalid long string delimiter", TK_STRING);
return '[';
}
case '=': {
next(ls);

View File

@@ -1,5 +1,5 @@
/*
** $Id: llex.h,v 1.78 2014/10/29 15:38:24 roberto Exp $
** $Id: llex.h,v 1.79 2016/05/02 14:02:12 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -69,7 +69,6 @@ typedef struct LexState {
struct Dyndata *dyd; /* dynamic structures used by the parser */
TString *source; /* current source name */
TString *envn; /* environment variable name */
char decpoint; /* locale decimal point */
} LexState;

View File

@@ -1,5 +1,5 @@
/*
** $Id: llimits.h,v 1.125 2014/12/19 13:30:23 roberto Exp $
** $Id: llimits.h,v 1.141 2015/11/19 19:16:22 roberto Exp $
** Limits, basic types, and some other 'installation-dependent' definitions
** See Copyright Notice in lua.h
*/
@@ -52,11 +52,11 @@ typedef unsigned char lu_byte;
/*
** conversion of pointer to integer:
** conversion of pointer to unsigned integer:
** this is for hashing only; there is no problem if the integer
** cannot hold the whole pointer value
*/
#define point2int(p) ((unsigned int)((size_t)(p) & UINT_MAX))
#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX))
@@ -64,7 +64,13 @@ typedef unsigned char lu_byte;
#if defined(LUAI_USER_ALIGNMENT_T)
typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
#else
typedef union { double u; void *s; lua_Integer i; long l; } L_Umaxalign;
typedef union {
lua_Number n;
double u;
void *s;
lua_Integer i;
long l;
} L_Umaxalign;
#endif
@@ -78,7 +84,7 @@ typedef LUAI_UACINT l_uacInt;
#if defined(lua_assert)
#define check_exp(c,e) (lua_assert(c), (e))
/* to avoid problems with conditions too long */
#define lua_longassert(c) { if (!(c)) lua_assert(0); }
#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0))
#else
#define lua_assert(c) ((void)0)
#define check_exp(c,e) (e)
@@ -88,22 +94,20 @@ typedef LUAI_UACINT l_uacInt;
/*
** assertion for checking API calls
*/
#if defined(LUA_USE_APICHECK)
#include <assert.h>
#define luai_apicheck(e) assert(e)
#else
#define luai_apicheck(e) lua_assert(e)
#if !defined(luai_apicheck)
#define luai_apicheck(l,e) lua_assert(e)
#endif
#define api_check(e,msg) luai_apicheck((e) && msg)
#define api_check(l,e,msg) luai_apicheck(l,(e) && msg)
/* macro to avoid warnings about unused variables */
#if !defined(UNUSED)
#define UNUSED(x) ((void)(x)) /* to avoid warnings */
#define UNUSED(x) ((void)(x))
#endif
/* type casts (a macro highlights casts in the code) */
#define cast(t, exp) ((t)(exp))
#define cast_void(i) cast(void, (i))
@@ -149,11 +153,6 @@ typedef LUAI_UACINT l_uacInt;
#define LUAI_MAXCCALLS 200
#endif
/*
** maximum number of upvalues in a closure (both C and Lua). (Value
** must fit in an unsigned char.)
*/
#define MAXUPVAL UCHAR_MAX
/*
@@ -168,10 +167,36 @@ typedef unsigned long Instruction;
/*
** Maximum length for short strings, that is, strings that are
** internalized. (Cannot be smaller than reserved words or tags for
** metamethods, as these strings must be internalized;
** #("function") = 8, #("__newindex") = 10.)
*/
#if !defined(LUAI_MAXSHORTLEN)
#define LUAI_MAXSHORTLEN 40
#endif
/* minimum size for the string table (must be power of 2) */
/*
** Initial size for the string table (must be power of 2).
** The Lua core alone registers ~50 strings (reserved words +
** metaevent keys + a few others). Libraries would typically add
** a few dozens more.
*/
#if !defined(MINSTRTABSIZE)
#define MINSTRTABSIZE 64 /* minimum size for "predefined" strings */
#define MINSTRTABSIZE 128
#endif
/*
** Size of cache for strings in the API. 'N' is the number of
** sets (better be a prime) and "M" is the size of each set (M == 1
** makes a direct cache.)
*/
#if !defined(STRCACHE_N)
#define STRCACHE_N 53
#define STRCACHE_M 2
#endif
@@ -181,11 +206,19 @@ typedef unsigned long Instruction;
#endif
/*
** macros that are executed whenever program enters the Lua core
** ('lua_lock') and leaves the core ('lua_unlock')
*/
#if !defined(lua_lock)
#define lua_lock(L) ((void) 0)
#define lua_unlock(L) ((void) 0)
#endif
/*
** macro executed during Lua functions at points where the
** function can yield.
*/
#if !defined(luai_threadyield)
#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
#endif
@@ -222,21 +255,69 @@ typedef unsigned long Instruction;
/*
** The luai_num* macros define the primitive operations over numbers.
*/
/* floor division (defined as 'floor(a/b)') */
#if !defined(luai_numidiv)
#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b)))
#endif
/* float division */
#if !defined(luai_numdiv)
#define luai_numdiv(L,a,b) ((a)/(b))
#endif
/*
** modulo: defined as 'a - floor(a/b)*b'; this definition gives NaN when
** 'b' is huge, but the result should be 'a'. 'fmod' gives the result of
** 'a - trunc(a/b)*b', and therefore must be corrected when 'trunc(a/b)
** ~= floor(a/b)'. That happens when the division has a non-integer
** negative result, which is equivalent to the test below.
*/
#if !defined(luai_nummod)
#define luai_nummod(L,a,b,m) \
{ (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); }
#endif
/* exponentiation */
#if !defined(luai_numpow)
#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b))
#endif
/* the others are quite standard operations */
#if !defined(luai_numadd)
#define luai_numadd(L,a,b) ((a)+(b))
#define luai_numsub(L,a,b) ((a)-(b))
#define luai_nummul(L,a,b) ((a)*(b))
#define luai_numunm(L,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
/*
** macro to control inclusion of some hard tests on stack reallocation
*/
#if !defined(HARDSTACKTESTS)
#define condmovestack(L) ((void)0)
#define condmovestack(L,pre,pos) ((void)0)
#else
/* realloc stack keeping its size */
#define condmovestack(L) luaD_reallocstack((L), (L)->stacksize)
#define condmovestack(L,pre,pos) \
{ int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_); pos; }
#endif
#if !defined(HARDMEMTESTS)
#define condchangemem(L) condmovestack(L)
#define condchangemem(L,pre,pos) ((void)0)
#else
#define condchangemem(L) \
((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1)))
#define condchangemem(L,pre,pos) \
{ if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } }
#endif
#endif

View File

@@ -1,5 +1,5 @@
/*
** $Id: lmathlib.c,v 1.114 2014/12/27 20:32:26 roberto Exp $
** $Id: lmathlib.c,v 1.117 2015/10/02 15:39:23 roberto Exp $
** Standard mathematical library
** See Copyright Notice in lua.h
*/
@@ -39,7 +39,7 @@
static int math_abs (lua_State *L) {
if (lua_isinteger(L, 1)) {
lua_Integer n = lua_tointeger(L, 1);
if (n < 0) n = (lua_Integer)(0u - n);
if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n);
lua_pushinteger(L, n);
}
else
@@ -183,6 +183,9 @@ static int math_log (lua_State *L) {
res = l_mathop(log)(x);
else {
lua_Number base = luaL_checknumber(L, 2);
#if !defined(LUA_USE_C89)
if (base == 2.0) res = l_mathop(log2)(x); else
#endif
if (base == 10.0) res = l_mathop(log10)(x);
else res = l_mathop(log)(x)/l_mathop(log)(base);
}
@@ -270,7 +273,7 @@ static int math_random (lua_State *L) {
static int math_randomseed (lua_State *L) {
l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1));
(void)rand(); /* discard first value to avoid undesirable correlations */
(void)l_rand(); /* discard first value to avoid undesirable correlations */
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lmem.c,v 1.89 2014/11/02 19:33:33 roberto Exp $
** $Id: lmem.c,v 1.91 2015/03/06 19:45:54 roberto Exp $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
@@ -85,10 +85,11 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
#endif
newblock = (*g->frealloc)(g->ud, block, osize, nsize);
if (newblock == NULL && nsize > 0) {
api_check( nsize > realosize,
"realloc cannot fail when shrinking a block");
luaC_fullgc(L, 1); /* try to free some memory... */
newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
lua_assert(nsize > realosize); /* cannot fail when shrinking a block */
if (g->version) { /* is state fully built? */
luaC_fullgc(L, 1); /* try to free some memory... */
newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
}
if (newblock == NULL)
luaD_throw(L, LUA_ERRMEM);
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: loadlib.c,v 1.124 2015/01/05 13:51:39 roberto Exp $
** $Id: loadlib.c,v 1.127 2015/11/23 11:30:45 roberto Exp $
** Dynamic library loader for Lua
** See Copyright Notice in lua.h
**
@@ -14,6 +14,7 @@
#include "lprefix.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -136,8 +137,8 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym);
#include <dlfcn.h>
/*
** Macro to covert pointer to void* to pointer to function. This cast
** is undefined according to ISO C, but POSIX assumes that it must work.
** Macro to convert pointer-to-void* to pointer-to-function. This cast
** is undefined according to ISO C, but POSIX assumes that it works.
** (The '__extension__' in gnu compilers is only to avoid warnings.)
*/
#if defined(__GNUC__)
@@ -731,7 +732,7 @@ static void createsearcherstable (lua_State *L) {
int i;
/* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
/* fill it with pre-defined searchers */
/* fill it with predefined searchers */
for (i=0; searchers[i] != NULL; i++) {
lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */
lua_pushcclosure(L, searchers[i], 1);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lobject.c,v 2.101 2014/12/26 14:43:45 roberto Exp $
** $Id: lobject.c,v 2.111 2016/05/20 14:07:48 roberto Exp $
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
@@ -10,6 +10,8 @@
#include "lprefix.h"
#include <locale.h>
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -39,8 +41,12 @@ LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT};
int luaO_int2fb (unsigned int x) {
int e = 0; /* exponent */
if (x < 8) return x;
while (x >= 0x10) {
x = (x+1) >> 1;
while (x >= (8 << 4)) { /* coarse steps */
x = (x + 0xf) >> 4; /* x = ceil(x / 16) */
e += 4;
}
while (x >= (8 << 1)) { /* fine steps */
x = (x + 1) >> 1; /* x = ceil(x / 2) */
e++;
}
return ((e+1) << 3) | (cast_int(x) - 8);
@@ -49,14 +55,15 @@ int luaO_int2fb (unsigned int x) {
/* converts back */
int luaO_fb2int (int x) {
int e = (x >> 3) & 0x1f;
if (e == 0) return x;
else return ((x & 7) + 8) << (e - 1);
return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1);
}
/*
** Computes ceil(log2(x))
*/
int luaO_ceillog2 (unsigned int x) {
static const lu_byte log_2[256] = {
static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */
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,
@@ -149,13 +156,13 @@ void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2,
}
/* could not perform raw operation; try metamethod */
lua_assert(L != NULL); /* should not fail when folding (compile time) */
luaT_trybinTM(L, p1, p2, res, cast(TMS, op - LUA_OPADD + TM_ADD));
luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD));
}
int luaO_hexavalue (int c) {
if (lisdigit(c)) return c - '0';
else return ltolower(c) - 'a' + 10;
else return (ltolower(c) - 'a') + 10;
}
@@ -172,9 +179,8 @@ static int isneg (const char **s) {
** Lua's implementation for 'lua_strx2number'
** ===================================================================
*/
#if !defined(lua_strx2number)
#include <math.h>
#if !defined(lua_strx2number)
/* maximum number of significant digits to read (to avoid overflows
even with single floats) */
@@ -185,21 +191,22 @@ static int isneg (const char **s) {
** C99 specification for 'strtod'
*/
static lua_Number lua_strx2number (const char *s, char **endptr) {
int dot = lua_getlocaledecpoint();
lua_Number r = 0.0; /* result (accumulator) */
int sigdig = 0; /* number of significant digits */
int nosigdig = 0; /* number of non-significant digits */
int e = 0; /* exponent correction */
int neg; /* 1 if number is negative */
int dot = 0; /* true after seen a dot */
int hasdot = 0; /* true after seen a dot */
*endptr = cast(char *, s); /* nothing is valid yet */
while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
neg = isneg(&s); /* check signal */
if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */
return 0.0; /* invalid format (no '0x') */
for (s += 2; ; s++) { /* skip '0x' and read numeral */
if (*s == '.') {
if (dot) break; /* second dot? stop loop */
else dot = 1;
if (*s == dot) {
if (hasdot) break; /* second dot? stop loop */
else hasdot = 1;
}
else if (lisxdigit(cast_uchar(*s))) {
if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */
@@ -207,7 +214,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */
r = (r * cast_num(16.0)) + luaO_hexavalue(*s);
else e++; /* too many digits; ignore, but still count for exponent */
if (dot) e--; /* decimal digit? correct exponent */
if (hasdot) e--; /* decimal digit? correct exponent */
}
else break; /* neither a dot nor a digit */
}
@@ -236,20 +243,59 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
/* }====================================================== */
static const char *l_str2d (const char *s, lua_Number *result) {
/* maximum length of a numeral */
#if !defined (L_MAXLENNUM)
#define L_MAXLENNUM 200
#endif
static const char *l_str2dloc (const char *s, lua_Number *result, int mode) {
char *endptr;
if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */
return NULL;
else if (strpbrk(s, "xX")) /* hex? */
*result = lua_strx2number(s, &endptr);
else
*result = lua_str2number(s, &endptr);
if (endptr == s) return 0; /* nothing recognized */
while (lisspace(cast_uchar(*endptr))) endptr++;
return (*endptr == '\0' ? endptr : NULL); /* OK if no trailing characters */
*result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */
: lua_str2number(s, &endptr);
if (endptr == s) return NULL; /* nothing recognized? */
while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */
return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */
}
/*
** Convert string 's' to a Lua number (put in 'result'). Return NULL
** on fail or the address of the ending '\0' on success.
** 'pmode' points to (and 'mode' contains) special things in the string:
** - 'x'/'X' means an hexadecimal numeral
** - 'n'/'N' means 'inf' or 'nan' (which should be rejected)
** - '.' just optimizes the search for the common case (nothing special)
** This function accepts both the current locale or a dot as the radix
** mark. If the convertion fails, it may mean number has a dot but
** locale accepts something else. In that case, the code copies 's'
** to a buffer (because 's' is read-only), changes the dot to the
** current locale radix mark, and tries to convert again.
*/
static const char *l_str2d (const char *s, lua_Number *result) {
const char *endptr;
const char *pmode = strpbrk(s, ".xXnN");
int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;
if (mode == 'n') /* reject 'inf' and 'nan' */
return NULL;
endptr = l_str2dloc(s, result, mode); /* try to convert */
if (endptr == NULL) { /* failed? may be a different locale */
char buff[L_MAXLENNUM + 1];
char *pdot = strchr(s, '.');
if (strlen(s) > L_MAXLENNUM || pdot == NULL)
return NULL; /* string too long or no dot; fail */
strcpy(buff, s); /* copy string to buffer */
buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */
endptr = l_str2dloc(buff, result, mode); /* try again */
if (endptr != NULL)
endptr = s + (endptr - buff); /* make relative to 's' */
}
return endptr;
}
#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10)
#define MAXLASTD cast_int(LUA_MAXINTEGER % 10)
static const char *l_str2int (const char *s, lua_Integer *result) {
lua_Unsigned a = 0;
int empty = 1;
@@ -266,7 +312,10 @@ static const char *l_str2int (const char *s, lua_Integer *result) {
}
else { /* decimal */
for (; lisdigit(cast_uchar(*s)); s++) {
a = a * 10 + *s - '0';
int d = *s - '0';
if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */
return NULL; /* do not accept it (as integer) */
a = a * 10 + d;
empty = 0;
}
}
@@ -290,7 +339,7 @@ size_t luaO_str2num (const char *s, TValue *o) {
}
else
return 0; /* conversion failed */
return (e - s + 1); /* success; return string size */
return (e - s) + 1; /* success; return string size */
}
@@ -324,12 +373,12 @@ void luaO_tostring (lua_State *L, StkId obj) {
size_t len;
lua_assert(ttisnumber(obj));
if (ttisinteger(obj))
len = lua_integer2str(buff, ivalue(obj));
len = lua_integer2str(buff, sizeof(buff), ivalue(obj));
else {
len = lua_number2str(buff, fltvalue(obj));
len = lua_number2str(buff, sizeof(buff), fltvalue(obj));
#if !defined(LUA_COMPAT_FLOATSTRING)
if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */
buff[len++] = '.';
buff[len++] = lua_getlocaledecpoint();
buff[len++] = '0'; /* adds '.0' to result */
}
#endif
@@ -339,27 +388,29 @@ void luaO_tostring (lua_State *L, StkId obj) {
static void pushstr (lua_State *L, const char *str, size_t l) {
setsvalue2s(L, L->top++, luaS_newlstr(L, str, l));
setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
luaD_inctop(L);
}
/* this function handles only '%d', '%c', '%f', '%p', and '%s'
conventional formats, plus Lua-specific '%I' and '%U' */
/*
** this function handles only '%d', '%c', '%f', '%p', and '%s'
conventional formats, plus Lua-specific '%I' and '%U'
*/
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
int n = 0;
for (;;) {
const char *e = strchr(fmt, '%');
if (e == NULL) break;
luaD_checkstack(L, 2); /* fmt + item */
pushstr(L, fmt, e - fmt);
switch (*(e+1)) {
case 's': {
case 's': { /* zero-terminated string */
const char *s = va_arg(argp, char *);
if (s == NULL) s = "(null)";
pushstr(L, s, strlen(s));
break;
}
case 'c': {
case 'c': { /* an 'int' as a character */
char buff = cast(char, va_arg(argp, int));
if (lisprint(cast_uchar(buff)))
pushstr(L, &buff, 1);
@@ -367,28 +418,28 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
luaO_pushfstring(L, "<\\%d>", cast_uchar(buff));
break;
}
case 'd': {
setivalue(L->top++, va_arg(argp, int));
case 'd': { /* an 'int' */
setivalue(L->top, va_arg(argp, int));
goto top2str;
}
case 'I': { /* a 'lua_Integer' */
setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt)));
goto top2str;
}
case 'f': { /* a 'lua_Number' */
setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber)));
top2str: /* convert the top element to a string */
luaD_inctop(L);
luaO_tostring(L, L->top - 1);
break;
}
case 'I': {
setivalue(L->top++, cast(lua_Integer, va_arg(argp, l_uacInt)));
luaO_tostring(L, L->top - 1);
break;
}
case 'f': {
setfltvalue(L->top++, cast_num(va_arg(argp, l_uacNumber)));
luaO_tostring(L, L->top - 1);
break;
}
case 'p': {
case 'p': { /* a pointer */
char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */
int l = sprintf(buff, "%p", va_arg(argp, void *));
int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *));
pushstr(L, buff, l);
break;
}
case 'U': {
case 'U': { /* an 'int' as a UTF-8 sequence */
char buff[UTF8BUFFSZ];
int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long)));
pushstr(L, buff + UTF8BUFFSZ - l, l);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lobject.h,v 2.106 2015/01/05 13:52:37 roberto Exp $
** $Id: lobject.h,v 2.116 2015/11/03 18:33:10 roberto Exp $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
@@ -19,8 +19,8 @@
/*
** Extra tags for non-values
*/
#define LUA_TPROTO LUA_NUMTAGS
#define LUA_TDEADKEY (LUA_NUMTAGS+1)
#define LUA_TPROTO LUA_NUMTAGS /* function prototypes */
#define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */
/*
** number of all possible tags (including LUA_TNONE but excluding DEADKEY)
@@ -35,8 +35,6 @@
** bit 6: whether value is collectable
*/
#define VARBITS (3 << 4)
/*
** LUA_TFUNCTION variants:
@@ -90,22 +88,32 @@ struct GCObject {
/*
** Union of all Lua values
*/
typedef union Value Value;
/*
** Tagged Values. This is the basic representation of values in Lua,
** an actual value plus a tag with its type.
*/
/*
** Union of all Lua values
*/
typedef union Value {
GCObject *gc; /* collectable objects */
void *p; /* light userdata */
int b; /* booleans */
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
} Value;
#define TValuefields Value value_; int tt_
typedef struct lua_TValue TValue;
typedef struct lua_TValue {
TValuefields;
} TValue;
/* macro defining a nil value */
@@ -179,9 +187,9 @@ typedef struct lua_TValue TValue;
/* Macros for internal tests */
#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt)
#define checkliveness(g,obj) \
#define checkliveness(L,obj) \
lua_longassert(!iscollectable(obj) || \
(righttt(obj) && !isdead(g,gcvalue(obj))))
(righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)))))
/* Macros to set values */
@@ -190,9 +198,15 @@ typedef struct lua_TValue TValue;
#define setfltvalue(obj,x) \
{ TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); }
#define chgfltvalue(obj,x) \
{ TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); }
#define setivalue(obj,x) \
{ TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); }
#define chgivalue(obj,x) \
{ TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); }
#define setnilvalue(obj) settt_(obj, LUA_TNIL)
#define setfvalue(obj,x) \
@@ -211,32 +225,32 @@ typedef struct lua_TValue TValue;
#define setsvalue(L,obj,x) \
{ TValue *io = (obj); TString *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \
checkliveness(G(L),io); }
checkliveness(L,io); }
#define setuvalue(L,obj,x) \
{ TValue *io = (obj); Udata *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \
checkliveness(G(L),io); }
checkliveness(L,io); }
#define setthvalue(L,obj,x) \
{ TValue *io = (obj); lua_State *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \
checkliveness(G(L),io); }
checkliveness(L,io); }
#define setclLvalue(L,obj,x) \
{ TValue *io = (obj); LClosure *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \
checkliveness(G(L),io); }
checkliveness(L,io); }
#define setclCvalue(L,obj,x) \
{ TValue *io = (obj); CClosure *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \
checkliveness(G(L),io); }
checkliveness(L,io); }
#define sethvalue(L,obj,x) \
{ TValue *io = (obj); Table *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \
checkliveness(G(L),io); }
checkliveness(L,io); }
#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)
@@ -244,7 +258,7 @@ typedef struct lua_TValue TValue;
#define setobj(L,obj1,obj2) \
{ TValue *io1=(obj1); *io1 = *(obj2); \
(void)L; checkliveness(G(L),io1); }
(void)L; checkliveness(L,io1); }
/*
@@ -260,12 +274,13 @@ typedef struct lua_TValue TValue;
#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
/* to table (define it as an expression to be used in macros) */
#define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1)))
@@ -276,21 +291,6 @@ typedef struct lua_TValue TValue;
*/
union Value {
GCObject *gc; /* collectable objects */
void *p; /* light userdata */
int b; /* booleans */
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
};
struct lua_TValue {
TValuefields;
};
typedef TValue *StkId; /* index to stack elements */
@@ -303,9 +303,12 @@ typedef TValue *StkId; /* index to stack elements */
typedef struct TString {
CommonHeader;
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
lu_byte shrlen; /* length for short strings */
unsigned int hash;
size_t len; /* number of characters in string */
struct TString *hnext; /* linked list for hash table */
union {
size_t lnglen; /* length for long strings */
struct TString *hnext; /* linked list for hash table */
} u;
} TString;
@@ -322,13 +325,19 @@ typedef union UTString {
** Get the actual string (array of bytes) from a 'TString'.
** (Access to 'extra' ensures that value is really a 'TString'.)
*/
#define getaddrstr(ts) (cast(char *, (ts)) + sizeof(UTString))
#define getstr(ts) \
check_exp(sizeof((ts)->extra), cast(const char*, getaddrstr(ts)))
check_exp(sizeof((ts)->extra), cast(char *, (ts)) + sizeof(UTString))
/* get the actual string (array of bytes) from a Lua value */
#define svalue(o) getstr(tsvalue(o))
/* get string length from 'TString *s' */
#define tsslen(s) ((s)->tt == LUA_TSHRSTR ? (s)->shrlen : (s)->u.lnglen)
/* get string length from 'TValue *o' */
#define vslen(o) tsslen(tsvalue(o))
/*
** Header for userdata; memory area follows the end of this structure
@@ -361,14 +370,14 @@ typedef union UUdata {
#define setuservalue(L,u,o) \
{ const TValue *io=(o); Udata *iu = (u); \
iu->user_ = io->value_; iu->ttuv_ = io->tt_; \
checkliveness(G(L),io); }
iu->user_ = io->value_; iu->ttuv_ = rttype(io); \
checkliveness(L,io); }
#define getuservalue(L,u,o) \
{ TValue *io=(o); const Udata *iu = (u); \
io->value_ = iu->user_; io->tt_ = iu->ttuv_; \
checkliveness(G(L),io); }
io->value_ = iu->user_; settt_(io, iu->ttuv_); \
checkliveness(L,io); }
/*
@@ -376,7 +385,7 @@ typedef union UUdata {
*/
typedef struct Upvaldesc {
TString *name; /* upvalue name (for debug information) */
lu_byte instack; /* whether it is in stack */
lu_byte instack; /* whether it is in stack (register) */
lu_byte idx; /* index of upvalue (in stack or in outer function's list) */
} Upvaldesc;
@@ -391,21 +400,20 @@ typedef struct LocVar {
int endpc; /* first point where variable is dead */
} LocVar;
typedef struct SharedProto {
lu_byte numparams; /* number of fixed parameters */
lu_byte is_vararg;
lu_byte maxstacksize; /* maximum stack used by this function */
lu_byte is_vararg; /* 2: declared vararg; 1: uses vararg */
lu_byte maxstacksize; /* number of registers needed by this function */
int sizeupvalues; /* size of 'upvalues' */
int sizek; /* size of 'k' */
int sizecode;
int sizelineinfo;
int sizep; /* size of 'p' */
int sizelocvars;
int linedefined;
int lastlinedefined;
int linedefined; /* debug information */
int lastlinedefined; /* debug information */
void *l_G; /* global state belongs to */
Instruction *code;
Instruction *code; /* opcodes */
int *lineinfo; /* map from opcodes to source lines (debug information) */
LocVar *locvars; /* information about local variables (debug information) */
Upvaldesc *upvalues; /* upvalue information */
@@ -420,7 +428,7 @@ typedef struct Proto {
struct SharedProto *sp;
TValue *k; /* constants used by the function */
struct Proto **p; /* functions defined inside the function */
struct LClosure *cache; /* last created closure with this prototype */
struct LClosure *cache; /* last-created closure with this prototype */
GCObject *gclist;
} Proto;
@@ -481,7 +489,7 @@ typedef union TKey {
#define setnodekey(L,key,obj) \
{ TKey *k_=(key); const TValue *io_=(obj); \
k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \
(void)L; checkliveness(G(L),io_); }
(void)L; checkliveness(L,io_); }
typedef struct Node {

View File

@@ -1,5 +1,5 @@
/*
** $Id: loslib.c,v 1.54 2014/12/26 14:46:07 roberto Exp $
** $Id: loslib.c,v 1.64 2016/04/18 13:06:55 roberto Exp $
** Standard Operating System library
** See Copyright Notice in lua.h
*/
@@ -22,23 +22,42 @@
#include "lualib.h"
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
/*
** list of valid conversion specifiers for the 'strftime' function
** {==================================================================
** List of valid conversion specifiers for the 'strftime' function;
** options are grouped by length; group of length 2 start with '||'.
** ===================================================================
*/
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
#if defined(LUA_USE_C89)
#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" }
/* options for ANSI C 89 */
#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
/* options for ISO C 99 and POSIX */
#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy"
/* options for Windows */
#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y"
#if defined(LUA_USE_WINDOWS)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
#elif defined(LUA_USE_C89)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
#else /* C99 specification */
#define LUA_STRFTIMEOPTIONS \
{ "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \
"E", "cCxXyY", \
"O", "deHImMSuUVwWy" }
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
#endif
#endif /* } */
/* }================================================================== */
/*
** {==================================================================
** Configuration for time-related stuff
** ===================================================================
*/
#if !defined(l_time_t) /* { */
/*
@@ -46,20 +65,51 @@
*/
#define l_timet lua_Integer
#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t))
#define l_checktime(L,a) ((time_t)luaL_checkinteger(L,a))
static time_t l_checktime (lua_State *L, int arg) {
lua_Integer t = luaL_checkinteger(L, arg);
luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds");
return (time_t)t;
}
#endif /* } */
#if !defined(lua_tmpnam) /* { */
#if !defined(l_gmtime) /* { */
/*
** By default, Lua uses tmpnam except when POSIX is available, where it
** uses mkstemp.
** By default, Lua uses gmtime/localtime, except when POSIX is available,
** where it uses gmtime_r/localtime_r
*/
#if defined(LUA_USE_POSIX) /* { */
#define l_gmtime(t,r) gmtime_r(t,r)
#define l_localtime(t,r) localtime_r(t,r)
#else /* }{ */
/* ISO C definitions */
#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t))
#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t))
#endif /* } */
#endif /* } */
/* }================================================================== */
/*
** {==================================================================
** Configuration for 'tmpnam':
** By default, Lua uses tmpnam except when POSIX is available, where
** it uses mkstemp.
** ===================================================================
*/
#if !defined(lua_tmpnam) /* { */
#if defined(LUA_USE_POSIX) /* { */
#include <unistd.h>
#define LUA_TMPNAMBUFSIZE 32
@@ -83,31 +133,10 @@
#endif /* } */
#endif /* } */
/* }================================================================== */
#if !defined(l_gmtime) /* { */
/*
** By default, Lua uses gmtime/localtime, except when POSIX is available,
** where it uses gmtime_r/localtime_r
*/
#if defined(LUA_USE_POSIX) /* { */
#define l_gmtime(t,r) gmtime_r(t,r)
#define l_localtime(t,r) localtime_r(t,r)
#else /* }{ */
/* ISO C definitions */
#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t))
#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t))
#endif /* } */
#endif /* } */
static int os_execute (lua_State *L) {
const char *cmd = luaL_optstring(L, 1, NULL);
@@ -177,6 +206,23 @@ static void setboolfield (lua_State *L, const char *key, int value) {
lua_setfield(L, -2, key);
}
/*
** Set all fields from structure 'tm' in the table on top of the stack
*/
static void setallfields (lua_State *L, struct tm *stm) {
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);
}
static int getboolfield (lua_State *L, const char *key) {
int res;
res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
@@ -185,36 +231,42 @@ static int getboolfield (lua_State *L, const char *key) {
}
static int getfield (lua_State *L, const char *key, int d) {
int res, isnum;
lua_getfield(L, -1, key);
res = (int)lua_tointegerx(L, -1, &isnum);
if (!isnum) {
if (d < 0)
/* maximum value for date fields (to avoid arithmetic overflows with 'int') */
#if !defined(L_MAXDATEFIELD)
#define L_MAXDATEFIELD (INT_MAX / 2)
#endif
static int getfield (lua_State *L, const char *key, int d, int delta) {
int isnum;
int t = lua_getfield(L, -1, key); /* get field and its type */
lua_Integer res = lua_tointegerx(L, -1, &isnum);
if (!isnum) { /* field is not an integer? */
if (t != LUA_TNIL) /* some other value? */
return luaL_error(L, "field '%s' is not an integer", key);
else if (d < 0) /* absent field; no default? */
return luaL_error(L, "field '%s' missing in date table", key);
res = d;
}
else {
if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))
return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta;
}
lua_pop(L, 1);
return res;
return (int)res;
}
static const char *checkoption (lua_State *L, const char *conv, char *buff) {
static const char *const options[] = LUA_STRFTIMEOPTIONS;
unsigned int i;
for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) {
if (*conv != '\0' && strchr(options[i], *conv) != NULL) {
buff[1] = *conv;
if (*options[i + 1] == '\0') { /* one-char conversion specifier? */
buff[2] = '\0'; /* end buffer */
return conv + 1;
}
else if (*(conv + 1) != '\0' &&
strchr(options[i + 1], *(conv + 1)) != NULL) {
buff[2] = *(conv + 1); /* valid two-char conversion specifier */
buff[3] = '\0'; /* end buffer */
return conv + 2;
}
const char *option;
int oplen = 1;
for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) {
if (*option == '|') /* next block? */
oplen++; /* next length */
else if (memcmp(conv, option, oplen) == 0) { /* match? */
memcpy(buff, conv, oplen); /* copy valid option to buffer */
buff[oplen] = '\0';
return conv + oplen; /* return next item */
}
}
luaL_argerror(L, 1,
@@ -223,6 +275,10 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) {
}
/* maximum size for an individual 'strftime' item */
#define SIZETIMEFMT 250
static int os_date (lua_State *L) {
const char *s = luaL_optstring(L, 1, "%c");
time_t t = luaL_opt(L, l_checktime, 2, time(NULL));
@@ -234,33 +290,25 @@ static int os_date (lua_State *L) {
else
stm = l_localtime(&t, &tmr);
if (stm == NULL) /* invalid date? */
lua_pushnil(L);
else if (strcmp(s, "*t") == 0) {
luaL_error(L, "time result cannot be represented in this installation");
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);
setallfields(L, stm);
}
else {
char cc[4];
char cc[4]; /* buffer for individual conversion specifiers */
luaL_Buffer b;
cc[0] = '%';
luaL_buffinit(L, &b);
while (*s) {
if (*s != '%') /* no conversion specifier? */
if (*s != '%') /* not a conversion specifier? */
luaL_addchar(&b, *s++);
else {
size_t reslen;
char buff[200]; /* should be big enough for any conversion result */
s = checkoption(L, s + 1, cc);
reslen = strftime(buff, sizeof(buff), cc, stm);
luaL_addlstring(&b, buff, reslen);
char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
s = checkoption(L, s + 1, cc + 1); /* copy specifier to 'cc' */
reslen = strftime(buff, SIZETIMEFMT, cc, stm);
luaL_addsize(&b, reslen);
}
}
luaL_pushresult(&b);
@@ -277,28 +325,27 @@ static int os_time (lua_State *L) {
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_sec = getfield(L, "sec", 0, 0);
ts.tm_min = getfield(L, "min", 0, 0);
ts.tm_hour = getfield(L, "hour", 12, 0);
ts.tm_mday = getfield(L, "day", -1, 0);
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);
setallfields(L, &ts); /* update fields with normalized values */
}
if (t != (time_t)(l_timet)t)
luaL_error(L, "time result cannot be represented in this Lua instalation");
else if (t == (time_t)(-1))
lua_pushnil(L);
else
l_pushtime(L, t);
if (t != (time_t)(l_timet)t || t == (time_t)(-1))
luaL_error(L, "time result cannot be represented in this installation");
l_pushtime(L, t);
return 1;
}
static int os_difftime (lua_State *L) {
double res = difftime((l_checktime(L, 1)), (l_checktime(L, 2)));
lua_pushnumber(L, (lua_Number)res);
time_t t1 = l_checktime(L, 1);
time_t t2 = l_checktime(L, 2);
lua_pushnumber(L, (lua_Number)difftime(t1, t2));
return 1;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lparser.c,v 2.147 2014/12/27 20:31:43 roberto Exp $
** $Id: lparser.c,v 2.153 2016/05/13 19:10:16 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -165,7 +165,8 @@ static int registerlocalvar (LexState *ls, TString *varname) {
int oldsize = f->sizelocvars;
luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
LocVar, SHRT_MAX, "local variables");
while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
while (oldsize < f->sizelocvars)
f->locvars[oldsize++].varname = NULL;
f->locvars[fs->nlocvars].varname = varname;
luaC_objbarrier(ls->L, fp, varname);
return fs->nlocvars++;
@@ -232,7 +233,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
Upvaldesc, MAXUPVAL, "upvalues");
while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;
while (oldsize < f->sizeupvalues)
f->upvalues[oldsize++].name = NULL;
f->upvalues[fs->nups].instack = (v->k == VLOCAL);
f->upvalues[fs->nups].idx = cast_byte(v->u.info);
f->upvalues[fs->nups].name = name;
@@ -257,7 +259,8 @@ static int searchvar (FuncState *fs, TString *n) {
*/
static void markupval (FuncState *fs, int level) {
BlockCnt *bl = fs->bl;
while (bl->nactvar > level) bl = bl->previous;
while (bl->nactvar > level)
bl = bl->previous;
bl->upval = 1;
}
@@ -266,27 +269,26 @@ static void markupval (FuncState *fs, int level) {
Find variable with given name 'n'. If it is an upvalue, add this
upvalue into all intermediate functions.
*/
static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
if (fs == NULL) /* no more levels? */
return VVOID; /* default is global */
init_exp(var, VVOID, 0); /* default is global */
else {
int v = searchvar(fs, n); /* look up locals at current level */
if (v >= 0) { /* found? */
init_exp(var, VLOCAL, v); /* variable is local */
if (!base)
markupval(fs, v); /* local will be used as an upval */
return VLOCAL;
}
else { /* not found as local at current level; try upvalues */
int idx = searchupvalue(fs, n); /* try existing upvalues */
if (idx < 0) { /* not found? */
if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */
return VVOID; /* not found; is a global */
singlevaraux(fs->prev, n, var, 0); /* try upper levels */
if (var->k == VVOID) /* not found? */
return; /* it is a global */
/* else was LOCAL or UPVAL */
idx = newupvalue(fs, n, var); /* will be a new upvalue */
}
init_exp(var, VUPVAL, idx);
return VUPVAL;
init_exp(var, VUPVAL, idx); /* new or old upvalue */
}
}
}
@@ -295,10 +297,11 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
static void singlevar (LexState *ls, expdesc *var) {
TString *varname = str_checkname(ls);
FuncState *fs = ls->fs;
if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */
singlevaraux(fs, varname, var, 1);
if (var->k == VVOID) { /* global name? */
expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k == VLOCAL || var->k == VUPVAL);
lua_assert(var->k != VVOID); /* this one must exist */
codestring(ls, &key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */
}
@@ -501,7 +504,8 @@ static Proto *addprototype (LexState *ls) {
if (fs->np >= f->sp->sizep) {
int oldsize = f->sp->sizep;
luaM_growvector(L, f->p, fs->np, f->sp->sizep, Proto *, MAXARG_Bx, "functions");
while (oldsize < f->sp->sizep) f->p[oldsize++] = NULL;
while (oldsize < f->sp->sizep)
f->p[oldsize++] = NULL;
}
f->p[fs->np++] = clp = luaF_newproto(L, NULL);
luaC_objbarrier(L, f, clp);
@@ -763,7 +767,7 @@ static void parlist (LexState *ls) {
}
case TK_DOTS: { /* param -> '...' */
luaX_next(ls);
f->is_vararg = 1;
f->is_vararg = 2; /* declared vararg */
break;
}
default: luaX_syntaxerror(ls, "<name> or '...' expected");
@@ -959,6 +963,7 @@ static void simpleexp (LexState *ls, expdesc *v) {
FuncState *fs = ls->fs;
check_condition(ls, fs->f->sp->is_vararg,
"cannot use '...' outside a vararg function");
fs->f->sp->is_vararg = 1; /* function actually uses vararg */
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
break;
}
@@ -1228,7 +1233,7 @@ static void labelstat (LexState *ls, TString *label, int line) {
checkrepeated(fs, ll, label); /* check for repeated labels */
checknext(ls, TK_DBCOLON); /* skip double colon */
/* create new entry for this label */
l = newlabelentry(ls, ll, label, line, fs->pc);
l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));
skipnoopstat(ls); /* skip other no-op statements */
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */
@@ -1496,7 +1501,7 @@ static void exprstat (LexState *ls) {
}
else { /* stat -> func */
check_condition(ls, v.v.k == VCALL, "syntax error");
SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */
SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */
}
}
@@ -1513,8 +1518,8 @@ static void retstat (LexState *ls) {
if (hasmultret(e.k)) {
luaK_setmultret(fs, &e);
if (e.k == VCALL && nret == 1) { /* tail call? */
SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);
lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);
}
first = fs->nactvar;
nret = LUA_MULTRET; /* return all values */
@@ -1596,7 +1601,7 @@ static void statement (LexState *ls) {
break;
}
}
lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
lua_assert(ls->fs->f->sp->maxstacksize >= ls->fs->freereg &&
ls->fs->freereg >= ls->fs->nactvar);
ls->fs->freereg = ls->fs->nactvar; /* free registers */
leavelevel(ls);
@@ -1613,7 +1618,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
BlockCnt bl;
expdesc v;
open_func(ls, fs, &bl);
fs->f->sp->is_vararg = 1; /* main function is always vararg */
fs->f->sp->is_vararg = 2; /* main function is always declared vararg */
init_exp(&v, VLOCAL, 0); /* create and... */
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
luaX_next(ls); /* read first token */
@@ -1629,10 +1634,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */
incr_top(L);
luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */
sethvalue(L, L->top, lexstate.h); /* anchor it */
incr_top(L);
luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L, NULL);
funcstate.f->sp->source = luaS_new(L, name); /* create and anchor TString */
lua_assert(iswhite(funcstate.f)); /* do not need barrier here */

View File

@@ -1,5 +1,5 @@
/*
** $Id: lparser.h,v 1.74 2014/10/25 11:50:46 roberto Exp $
** $Id: lparser.h,v 1.76 2015/12/30 18:16:13 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -13,25 +13,38 @@
/*
** Expression descriptor
** Expression and variable descriptor.
** Code generation for variables and expressions can be delayed to allow
** optimizations; An 'expdesc' structure describes a potentially-delayed
** variable/expression. It has a description of its "main" value plus a
** list of conditional jumps that can also produce its value (generated
** by short-circuit operators 'and'/'or').
*/
/* kinds of variables/expressions */
typedef enum {
VVOID, /* no value */
VNIL,
VTRUE,
VFALSE,
VK, /* info = index of constant in 'k' */
VKFLT, /* nval = numerical float value */
VKINT, /* nval = numerical integer value */
VNONRELOC, /* info = result register */
VLOCAL, /* info = local register */
VUPVAL, /* info = index of upvalue in 'upvalues' */
VINDEXED, /* t = table register/upvalue; idx = index R/K */
VJMP, /* info = instruction pc */
VRELOCABLE, /* info = instruction pc */
VCALL, /* info = instruction pc */
VVARARG /* info = instruction pc */
VVOID, /* when 'expdesc' describes the last expression a list,
this kind means an empty list (so, no expression) */
VNIL, /* constant nil */
VTRUE, /* constant true */
VFALSE, /* constant false */
VK, /* constant in 'k'; info = index of constant in 'k' */
VKFLT, /* floating constant; nval = numerical float value */
VKINT, /* integer constant; nval = numerical integer value */
VNONRELOC, /* expression has its value in a fixed register;
info = result register */
VLOCAL, /* local variable; info = local register */
VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
VINDEXED, /* indexed variable;
ind.vt = whether 't' is register or upvalue;
ind.t = table register or upvalue;
ind.idx = key's R/K index */
VJMP, /* expression is a test/comparison;
info = pc of corresponding jump instruction */
VRELOCABLE, /* expression can put result in any register;
info = instruction pc */
VCALL, /* expression is a function call; info = instruction pc */
VVARARG /* vararg expression; info = instruction pc */
} expkind;
@@ -41,14 +54,14 @@ typedef enum {
typedef struct expdesc {
expkind k;
union {
lua_Integer ival; /* for VKINT */
lua_Number nval; /* for VKFLT */
int info; /* for generic use */
struct { /* for indexed variables (VINDEXED) */
short idx; /* index (R/K) */
lu_byte t; /* table (register or upvalue) */
lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
} ind;
int info; /* for generic use */
lua_Number nval; /* for VKFLT */
lua_Integer ival; /* for VKINT */
} u;
int t; /* patch list of 'exit when true' */
int f; /* patch list of 'exit when false' */

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstate.c,v 2.127 2014/11/02 19:33:33 roberto Exp $
** $Id: lstate.c,v 2.133 2015/11/13 12:16:51 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -37,9 +37,6 @@
#endif
#define MEMERRMSG "not enough memory"
/*
** a macro to help the creation of a unique random seed when a state is
** created; the seed is used to randomize hashes.
@@ -79,7 +76,7 @@ typedef struct LG {
*/
#define addbuff(b,p,e) \
{ size_t t = cast(size_t, e); \
memcpy(buff + p, &t, sizeof(t)); p += sizeof(t); }
memcpy(b + p, &t, sizeof(t)); p += sizeof(t); }
static unsigned int makeseed (lua_State *L) {
char buff[4 * sizeof(size_t)];
@@ -96,10 +93,14 @@ static unsigned int makeseed (lua_State *L) {
/*
** set GCdebt to a new value keeping the value (totalbytes + GCdebt)
** invariant
** invariant (and avoiding underflows in 'totalbytes')
*/
void luaE_setdebt (global_State *g, l_mem debt) {
g->totalbytes -= (debt - g->GCdebt);
l_mem tb = gettotalbytes(g);
lua_assert(tb > 0);
if (debt < tb - MAX_LMEM)
debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */
g->totalbytes = tb - debt;
g->GCdebt = debt;
}
@@ -110,6 +111,7 @@ CallInfo *luaE_extendCI (lua_State *L) {
L->ci->next = ci;
ci->previous = L->ci;
ci->next = NULL;
L->nci++;
return ci;
}
@@ -124,6 +126,7 @@ void luaE_freeCI (lua_State *L) {
while ((ci = next) != NULL) {
next = ci->next;
luaM_free(L, ci);
L->nci--;
}
}
@@ -133,13 +136,14 @@ void luaE_freeCI (lua_State *L) {
*/
void luaE_shrinkCI (lua_State *L) {
CallInfo *ci = L->ci;
while (ci->next != NULL) { /* while there is 'next' */
CallInfo *next2 = ci->next->next; /* next's next */
if (next2 == NULL) break;
luaM_free(L, ci->next); /* remove next */
CallInfo *next2; /* next's next */
/* while there are two nexts */
while (ci->next != NULL && (next2 = ci->next->next) != NULL) {
luaM_free(L, ci->next); /* free next */
L->nci--;
ci->next = next2; /* remove 'next' from the list */
next2->previous = ci;
ci = next2;
ci = next2; /* keep next's next */
}
}
@@ -169,6 +173,7 @@ static void freestack (lua_State *L) {
return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L);
lua_assert(L->nci == 0);
luaM_freearray(L, L->stack, L->stacksize); /* free stack array */
}
@@ -200,12 +205,9 @@ static void f_luaopen (lua_State *L, void *ud) {
UNUSED(ud);
stack_init(L, L); /* init stack */
init_registry(L, g);
luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
luaS_init(L);
luaT_init(L);
luaX_init(L);
/* pre-create memory-error message */
g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */
g->gcrunning = 1; /* allow gc */
g->version = lua_version(NULL);
luai_userstateopen(L);
@@ -220,6 +222,7 @@ static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g;
L->stack = NULL;
L->ci = NULL;
L->nci = 0;
L->stacksize = 0;
L->twups = L; /* thread has no upvalues */
L->errorJmp = NULL;
@@ -243,7 +246,6 @@ static void close_state (lua_State *L) {
if (g->version) /* closing a fully built state? */
luai_userstateclose(L);
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
luaZ_freebuffer(L, &g->buff);
freestack(L);
lua_assert(gettotalbytes(g) == sizeof(LG));
(*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */
@@ -312,7 +314,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->strt.size = g->strt.nuse = 0;
g->strt.hash = NULL;
setnilvalue(&g->l_registry);
luaZ_initbuffer(L, &g->buff);
g->panic = NULL;
g->version = NULL;
g->gcstate = GCSpause;

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstate.h,v 2.119 2014/10/30 18:53:28 roberto Exp $
** $Id: lstate.h,v 2.130 2015/12/16 16:39:38 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -33,6 +33,15 @@
struct lua_longjmp; /* defined in ldo.c */
/*
** Atomic type (relative to signals) to better ensure that 'lua_sethook'
** is thread safe
*/
#if !defined(l_signalT)
#include <signal.h>
#define l_signalT sig_atomic_t
#endif
/* extra stack space to handle TM calls and some other extras */
#define EXTRA_STACK 5
@@ -89,8 +98,8 @@ typedef struct CallInfo {
#define CIST_OAH (1<<0) /* original value of 'allowhook' */
#define CIST_LUA (1<<1) /* call is running a Lua function */
#define CIST_HOOKED (1<<2) /* call is running a debug hook */
#define CIST_REENTRY (1<<3) /* call is running on same invocation of
luaV_execute of previous call */
#define CIST_FRESH (1<<3) /* call is running on a fresh invocation
of luaV_execute */
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
#define CIST_TAIL (1<<5) /* call was tail called */
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
@@ -109,7 +118,7 @@ typedef struct CallInfo {
typedef struct global_State {
lua_Alloc frealloc; /* function to reallocate memory */
void *ud; /* auxiliary data to 'frealloc' */
lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */
l_mem totalbytes; /* number of bytes currently allocated - GCdebt */
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
lu_mem GCmemtrav; /* memory traversed by the GC */
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
@@ -131,7 +140,6 @@ typedef struct global_State {
GCObject *tobefnz; /* list of userdata to be GC */
GCObject *fixedgc; /* list of objects not to be collected */
struct lua_State *twups; /* list of threads with open upvalues */
Mbuffer buff; /* temporary buffer for string concatenation */
unsigned int gcfinnum; /* number of finalizers to call in each GC step */
int gcpause; /* size of pause between successive GCs */
int gcstepmul; /* GC 'granularity' */
@@ -141,6 +149,7 @@ typedef struct global_State {
TString *memerrmsg; /* memory-error message */
TString *tmname[TM_N]; /* array with tag-method names */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
} global_State;
@@ -149,6 +158,7 @@ typedef struct global_State {
*/
struct lua_State {
CommonHeader;
unsigned short nci; /* number of items in 'ci' list */
lu_byte status;
StkId top; /* first free slot in the stack */
global_State *l_G;
@@ -161,14 +171,14 @@ struct lua_State {
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
lua_Hook hook;
volatile lua_Hook hook;
ptrdiff_t errfunc; /* current error handling function (stack index) */
int stacksize;
int basehookcount;
int hookcount;
unsigned short nny; /* number of non-yieldable calls in stack */
unsigned short nCcalls; /* number of nested C calls */
lu_byte hookmask;
l_signalT hookmask;
lu_byte allowhook;
};
@@ -211,7 +221,7 @@ union GCUnion {
/* actual number of total bytes allocated */
#define gettotalbytes(g) ((g)->totalbytes + (g)->GCdebt)
#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt)
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstring.c,v 2.45 2014/11/02 19:19:04 roberto Exp $
** $Id: lstring.c,v 2.56 2015/11/23 11:32:51 roberto Exp $
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -22,6 +22,8 @@
#include "lstring.h"
#define MEMERRMSG "not enough memory"
/*
** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to
@@ -36,24 +38,33 @@
** equality for long strings
*/
int luaS_eqlngstr (TString *a, TString *b) {
size_t len = a->len;
size_t len = a->u.lnglen;
lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR);
return (a == b) || /* same instance or... */
((len == b->len) && /* equal length and ... */
((len == b->u.lnglen) && /* equal length and ... */
(memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
}
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
unsigned int h = seed ^ cast(unsigned int, l);
size_t l1;
size_t step = (l >> LUAI_HASHLIMIT) + 1;
for (l1 = l; l1 >= step; l1 -= step)
h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1]));
for (; l >= step; l -= step)
h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
return h;
}
unsigned int luaS_hashlongstr (TString *ts) {
lua_assert(ts->tt == LUA_TLNGSTR);
if (ts->extra == 0) { /* no hash? */
ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash);
ts->extra = 1; /* now it has its hash */
}
return ts->hash;
}
/*
** resizes the string table
*/
@@ -69,9 +80,9 @@ void luaS_resize (lua_State *L, int newsize) {
TString *p = tb->hash[i];
tb->hash[i] = NULL;
while (p) { /* for each node in the list */
TString *hnext = p->hnext; /* save next */
TString *hnext = p->u.hnext; /* save next */
unsigned int h = lmod(p->hash, newsize); /* new position */
p->hnext = tb->hash[h]; /* chain it */
p->u.hnext = tb->hash[h]; /* chain it */
tb->hash[h] = p;
p = hnext;
}
@@ -85,23 +96,57 @@ void luaS_resize (lua_State *L, int newsize) {
}
/*
** Clear API string cache. (Entries cannot be empty, so fill them with
** a non-collectable string.)
*/
void luaS_clearcache (global_State *g) {
int i, j;
for (i = 0; i < STRCACHE_N; i++)
for (j = 0; j < STRCACHE_M; j++) {
if (iswhite(g->strcache[i][j])) /* will entry be collected? */
g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */
}
}
/*
** Initialize the string table and the string cache
*/
void luaS_init (lua_State *L) {
global_State *g = G(L);
int i, j;
luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
/* pre-create memory-error message */
g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */
for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */
for (j = 0; j < STRCACHE_M; j++)
g->strcache[i][j] = g->memerrmsg;
}
/*
** creates a new string object
*/
static TString *createstrobj (lua_State *L, const char *str, size_t l,
int tag, unsigned int h) {
static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
TString *ts;
GCObject *o;
size_t totalsize; /* total size of TString object */
totalsize = sizelstring(l);
o = luaC_newobj(L, tag, totalsize);
ts = gco2ts(o);
ts->len = l;
ts->hash = h;
ts->extra = 0;
memcpy(getaddrstr(ts), str, l * sizeof(char));
getaddrstr(ts)[l] = '\0'; /* ending 0 */
getstr(ts)[l] = '\0'; /* ending 0 */
return ts;
}
TString *luaS_createlngstrobj (lua_State *L, size_t l) {
TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed);
ts->u.lnglen = l;
return ts;
}
@@ -110,8 +155,8 @@ void luaS_remove (lua_State *L, TString *ts) {
stringtable *tb = &G(L)->strt;
TString **p = &tb->hash[lmod(ts->hash, tb->size)];
while (*p != ts) /* find previous element */
p = &(*p)->hnext;
*p = (*p)->hnext; /* remove element from its list */
p = &(*p)->u.hnext;
*p = (*p)->u.hnext; /* remove element from its list */
tb->nuse--;
}
@@ -119,13 +164,13 @@ void luaS_remove (lua_State *L, TString *ts) {
/*
** checks whether short string exists and reuses it or creates a new one
*/
static TString *internshrstr (lua_State *L, const char *str, size_t l) {
static TString *queryshrstr (lua_State *L, const char *str, size_t l, unsigned int h) {
TString *ts;
global_State *g = G(L);
unsigned int h = luaS_hash(str, l, g->seed);
TString **list = &g->strt.hash[lmod(h, g->strt.size)];
for (ts = *list; ts != NULL; ts = ts->hnext) {
if (l == ts->len &&
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
for (ts = *list; ts != NULL; ts = ts->u.hnext) {
if (l == ts->shrlen &&
(memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
/* found! */
if (isdead(g, ts)) /* dead (but not collected yet)? */
@@ -133,17 +178,27 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
return ts;
}
}
return NULL;
}
static TString *addshrstr (lua_State *L, const char *str, size_t l, unsigned int h) {
TString *ts;
global_State *g = G(L);
TString **list = &g->strt.hash[lmod(h, g->strt.size)];
if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) {
luaS_resize(L, g->strt.size * 2);
list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */
}
ts = createstrobj(L, str, l, LUA_TSHRSTR, h);
ts->hnext = *list;
ts = createstrobj(L, l, LUA_TSHRSTR, h);
memcpy(getstr(ts), str, l * sizeof(char));
ts->shrlen = cast_byte(l);
ts->u.hnext = *list;
*list = ts;
g->strt.nuse++;
return ts;
}
static TString *internshrstr (lua_State *L, const char *str, size_t l);
/*
** new string (with explicit length)
@@ -152,18 +207,36 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
if (l <= LUAI_MAXSHORTLEN) /* short string? */
return internshrstr(L, str, l);
else {
if (l + 1 > (MAX_SIZE - sizeof(TString))/sizeof(char))
TString *ts;
if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char))
luaM_toobig(L);
return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed);
ts = luaS_createlngstrobj(L, l);
memcpy(getstr(ts), str, l * sizeof(char));
return ts;
}
}
/*
** new zero-terminated string
** Create or reuse a zero-terminated string, first checking in the
** cache (using the string address as a key). The cache can contain
** only zero-terminated strings, so it is safe to use 'strcmp' to
** check hits.
*/
TString *luaS_new (lua_State *L, const char *str) {
return luaS_newlstr(L, str, strlen(str));
unsigned int i = point2uint(str) % STRCACHE_N; /* hash */
int j;
TString **p = G(L)->strcache[i];
for (j = 0; j < STRCACHE_M; j++) {
if (strcmp(str, getstr(p[j])) == 0) /* hit? */
return p[j]; /* that is it */
}
/* normal route */
for (j = STRCACHE_M - 1; j > 0; j--)
p[j] = p[j - 1]; /* move out last element */
/* new element is first in the list */
p[0] = luaS_newlstr(L, str, strlen(str));
return p[0];
}
@@ -180,3 +253,217 @@ Udata *luaS_newudata (lua_State *L, size_t s) {
return u;
}
/*
* global shared table
*/
#include "rwlock.h"
#include "atomic.h"
#include <stdlib.h>
#define SHRSTR_SLOT 0x10000
#define HASH_NODE(h) ((h) % SHRSTR_SLOT)
#define getaddrstr(ts) (cast(char *, (ts)) + sizeof(UTString))
struct shrmap_slot {
struct rwlock lock;
TString *str;
};
struct shrmap {
struct shrmap_slot h[SHRSTR_SLOT];
int n;
};
static struct shrmap SSM;
LUA_API void
luaS_initshr() {
struct shrmap * s = &SSM;
int i;
for (i=0;i<SHRSTR_SLOT;i++) {
rwlock_init(&s->h[i].lock);
}
}
LUA_API void
luaS_exitshr() {
int i;
for (i=0;i<SHRSTR_SLOT;i++) {
TString *str = SSM.h[i].str;
while (str) {
TString * next = str->u.hnext;
free(str);
str = next;
}
}
}
static TString *
query_string(unsigned int h, const char *str, lu_byte l) {
struct shrmap_slot *s = &SSM.h[HASH_NODE(h)];
rwlock_rlock(&s->lock);
TString *ts = s->str;
while (ts) {
if (ts->hash == h &&
ts->shrlen == l &&
memcmp(str, ts+1, l) == 0) {
break;
}
ts = ts->u.hnext;
}
rwlock_runlock(&s->lock);
return ts;
}
static TString *
query_ptr(TString *t) {
unsigned int h = t->hash;
struct shrmap_slot *s = &SSM.h[HASH_NODE(h)];
rwlock_rlock(&s->lock);
TString *ts = s->str;
while (ts) {
if (ts == t)
break;
ts = ts->u.hnext;
}
rwlock_runlock(&s->lock);
return ts;
}
static TString *
new_string(unsigned int h, const char *str, lu_byte l) {
size_t sz = sizelstring(l);
TString *ts = malloc(sz);
memset(ts, 0, sz);
ts->tt = LUA_TSHRSTR;
ts->hash = h;
ts->shrlen = l;
memcpy(ts+1, str, l);
return ts;
}
static TString *
add_string(unsigned int h, const char *str, lu_byte l) {
TString * tmp = new_string(h, str, l);
struct shrmap_slot *s = &SSM.h[HASH_NODE(h)];
rwlock_wlock(&s->lock);
TString *ts = s->str;
while (ts) {
if (ts->hash == h &&
ts->shrlen == l &&
memcmp(str, ts+1, l) == 0) {
break;
}
ts = ts->u.hnext;
}
if (ts == NULL) {
ts = tmp;
ts->u.hnext = s->str;
s->str = ts;
tmp = NULL;
}
rwlock_wunlock(&s->lock);
if (tmp) {
// string is create by other thread, so free tmp
free(tmp);
}
return ts;
}
static TString *
internshrstr (lua_State *L, const char *str, size_t l) {
TString *ts;
global_State *g = G(L);
unsigned int h = luaS_hash(str, l, g->seed);
unsigned int h0;
// lookup global state of this L first
ts = queryshrstr (L, str, l, h);
if (ts)
return ts;
// lookup SSM again
h0 = luaS_hash(str, l, 0);
ts = query_string(h0, str, l);
if (ts)
return ts;
// If SSM.n greate than 0, add it to SSM
if (SSM.n > 0) {
ATOM_DEC(&SSM.n);
return add_string(h0, str, l);
}
// Else add it to global state (local)
return addshrstr (L, str, l, h);
}
LUA_API void
luaS_expandshr(int n) {
ATOM_ADD(&SSM.n, n);
}
LUAI_FUNC TString *
luaS_clonestring(lua_State *L, TString *ts) {
unsigned int h;
int l;
const char * str = getaddrstr(ts);
global_State *g = G(L);
TString *result;
if (ts->tt == LUA_TLNGSTR)
return luaS_newlstr(L, str, ts->u.lnglen);
// look up global state of this L first
l = ts->shrlen;
h = luaS_hash(str, l, g->seed);
result = queryshrstr (L, str, l, h);
if (result)
return result;
// look up SSM by ptr
result = query_ptr(ts);
if (result)
return result;
h = luaS_hash(str, l, 0);
result = query_string(h, str, l);
if (result)
return result;
// ts is not in SSM, so recalc hash, and add it to SSM
return add_string(h, str, l);
}
struct slotinfo {
int len;
int size;
};
static void
getslot(struct shrmap_slot *s, struct slotinfo *info) {
memset(info, 0, sizeof(*info));
rwlock_rlock(&s->lock);
TString *ts = s->str;
while (ts) {
++info->len;
info->size += sizelstring(ts->shrlen);
ts = ts->u.hnext;
}
rwlock_runlock(&s->lock);
}
LUA_API int
luaS_shrinfo(lua_State *L) {
struct slotinfo total;
struct slotinfo tmp;
memset(&total, 0, sizeof(total));
int i;
int len = 0;
for (i=0;i<SHRSTR_SLOT;i++) {
struct shrmap_slot *s = &SSM.h[i];
getslot(s, &tmp);
len += tmp.len;
if (tmp.len > total.len) {
total.len = tmp.len;
}
total.size += tmp.size;
}
lua_pushinteger(L, len);
lua_pushinteger(L, total.size);
lua_pushinteger(L, total.len);
lua_pushinteger(L, SSM.n);
return 4;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstring.h,v 1.56 2014/07/18 14:46:47 roberto Exp $
** $Id: lstring.h,v 1.61 2015/11/03 15:36:01 roberto Exp $
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -13,7 +13,6 @@
#define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char))
#define sizestring(s) sizelstring((s)->len)
#define sizeludata(l) (sizeof(union UUdata) + (l))
#define sizeudata(u) sizeludata((u)->len)
@@ -35,12 +34,23 @@
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts);
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
LUAI_FUNC void luaS_clearcache (global_State *g);
LUAI_FUNC void luaS_init (lua_State *L);
LUAI_FUNC void luaS_remove (lua_State *L, TString *ts);
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s);
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
#define ENABLE_SHORT_STRING_TABLE
LUA_API void luaS_initshr();
LUA_API void luaS_exitshr();
LUA_API void luaS_expandshr(int n);
LUAI_FUNC TString *luaS_clonestring(lua_State *L, TString *);
LUA_API int luaS_shrinfo(lua_State *L);
#endif

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstrlib.c,v 1.221 2014/12/11 14:03:07 roberto Exp $
** $Id: lstrlib.c,v 1.251 2016/05/20 14:13:21 roberto Exp $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
@@ -11,7 +11,9 @@
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <locale.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -25,7 +27,8 @@
/*
** maximum number of captures that a pattern can do during
** pattern-matching. This limit is arbitrary.
** pattern-matching. This limit is arbitrary, but must fit in
** an unsigned char.
*/
#if !defined(LUA_MAXCAPTURES)
#define LUA_MAXCAPTURES 32
@@ -40,8 +43,10 @@
** Some sizes are better limited to fit in 'int', but must also fit in
** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.)
*/
#define MAX_SIZET ((size_t)(~(size_t)0))
#define MAXSIZE \
(sizeof(size_t) < sizeof(int) ? (~(size_t)0) : (size_t)(INT_MAX))
(sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX))
@@ -70,7 +75,7 @@ static int str_sub (lua_State *L) {
if (start < 1) start = 1;
if (end > (lua_Integer)l) end = l;
if (start <= end)
lua_pushlstring(L, s + start - 1, (size_t)(end - start + 1));
lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1);
else lua_pushliteral(L, "");
return 1;
}
@@ -149,9 +154,9 @@ static int str_byte (lua_State *L) {
if (posi < 1) posi = 1;
if (pose > (lua_Integer)l) pose = l;
if (posi > pose) return 0; /* empty interval; return no values */
n = (int)(pose - posi + 1);
if (posi + n <= pose) /* arithmetic overflow? */
if (pose - posi >= INT_MAX) /* arithmetic overflow? */
return luaL_error(L, "string slice too long");
n = (int)(pose - posi) + 1;
luaL_checkstack(L, n, "string slice too long");
for (i=0; i<n; i++)
lua_pushinteger(L, uchar(s[posi+i-1]));
@@ -207,12 +212,12 @@ static int str_dump (lua_State *L) {
typedef struct MatchState {
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
const char *src_init; /* init of source string */
const char *src_end; /* end ('\0') of source string */
const char *p_end; /* end ('\0') of pattern */
lua_State *L;
int level; /* total number of captures (finished or unfinished) */
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
unsigned char level; /* total number of captures (finished or unfinished) */
struct {
const char *init;
ptrdiff_t len;
@@ -499,7 +504,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
}
case '+': /* 1 or more repetitions */
s++; /* 1 match already done */
/* go through */
/* FALLTHROUGH */
case '*': /* 0 or more repetitions */
s = max_expand(ms, s, p, ep);
break;
@@ -554,7 +559,7 @@ static void push_onecapture (MatchState *ms, int i, const char *s,
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);
lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);
else
lua_pushlstring(ms->L, ms->capture[i].init, l);
}
@@ -583,6 +588,22 @@ static int nospecials (const char *p, size_t l) {
}
static void prepstate (MatchState *ms, lua_State *L,
const char *s, size_t ls, const char *p, size_t lp) {
ms->L = L;
ms->matchdepth = MAXCCALLS;
ms->src_init = s;
ms->src_end = s + ls;
ms->p_end = p + lp;
}
static void reprepstate (MatchState *ms) {
ms->level = 0;
lua_assert(ms->matchdepth == MAXCCALLS);
}
static int str_find_aux (lua_State *L, int find) {
size_t ls, lp;
const char *s = luaL_checklstring(L, 1, &ls);
@@ -598,8 +619,8 @@ static int str_find_aux (lua_State *L, int find) {
/* do a plain search */
const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp);
if (s2) {
lua_pushinteger(L, s2 - s + 1);
lua_pushinteger(L, s2 - s + lp);
lua_pushinteger(L, (s2 - s) + 1);
lua_pushinteger(L, (s2 - s) + lp);
return 2;
}
}
@@ -610,18 +631,13 @@ static int str_find_aux (lua_State *L, int find) {
if (anchor) {
p++; lp--; /* skip anchor character */
}
ms.L = L;
ms.matchdepth = MAXCCALLS;
ms.src_init = s;
ms.src_end = s + ls;
ms.p_end = p + lp;
prepstate(&ms, L, s, ls, p, lp);
do {
const char *res;
ms.level = 0;
lua_assert(ms.matchdepth == MAXCCALLS);
reprepstate(&ms);
if ((res=match(&ms, s1, p)) != NULL) {
if (find) {
lua_pushinteger(L, s1 - s + 1); /* start */
lua_pushinteger(L, (s1 - s) + 1); /* start */
lua_pushinteger(L, res - s); /* end */
return push_captures(&ms, NULL, 0) + 2;
}
@@ -645,29 +661,25 @@ static int str_match (lua_State *L) {
}
/* state for 'gmatch' */
typedef struct GMatchState {
const char *src; /* current position */
const char *p; /* pattern */
const char *lastmatch; /* end of last match */
MatchState ms; /* match state */
} GMatchState;
static int gmatch_aux (lua_State *L) {
MatchState ms;
size_t ls, lp;
const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp);
GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3));
const char *src;
ms.L = L;
ms.matchdepth = MAXCCALLS;
ms.src_init = s;
ms.src_end = s+ls;
ms.p_end = p + lp;
for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
src <= ms.src_end;
src++) {
gm->ms.L = L;
for (src = gm->src; src <= gm->ms.src_end; src++) {
const char *e;
ms.level = 0;
lua_assert(ms.matchdepth == MAXCCALLS);
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);
reprepstate(&gm->ms);
if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) {
gm->src = gm->lastmatch = e;
return push_captures(&gm->ms, src, e);
}
}
return 0; /* not found */
@@ -675,10 +687,14 @@ static int gmatch_aux (lua_State *L) {
static int gmatch (lua_State *L) {
luaL_checkstring(L, 1);
luaL_checkstring(L, 2);
lua_settop(L, 2);
lua_pushinteger(L, 0);
size_t ls, lp;
const char *s = luaL_checklstring(L, 1, &ls);
const char *p = luaL_checklstring(L, 2, &lp);
GMatchState *gm;
lua_settop(L, 2); /* keep them on closure to avoid being collected */
gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState));
prepstate(&gm->ms, L, s, ls, p, lp);
gm->src = s; gm->p = p; gm->lastmatch = NULL;
lua_pushcclosure(L, gmatch_aux, 3);
return 1;
}
@@ -745,12 +761,13 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
static int str_gsub (lua_State *L) {
size_t srcl, lp;
const char *src = luaL_checklstring(L, 1, &srcl);
const char *p = luaL_checklstring(L, 2, &lp);
int tr = lua_type(L, 3);
lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1);
const char *src = luaL_checklstring(L, 1, &srcl); /* subject */
const char *p = luaL_checklstring(L, 2, &lp); /* pattern */
const char *lastmatch = NULL; /* end of last match */
int tr = lua_type(L, 3); /* replacement type */
lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */
int anchor = (*p == '^');
lua_Integer n = 0;
lua_Integer n = 0; /* replacement count */
MatchState ms;
luaL_Buffer b;
luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
@@ -760,25 +777,18 @@ static int str_gsub (lua_State *L) {
if (anchor) {
p++; lp--; /* skip anchor character */
}
ms.L = L;
ms.matchdepth = MAXCCALLS;
ms.src_init = src;
ms.src_end = src+srcl;
ms.p_end = p + lp;
prepstate(&ms, L, src, srcl, p, lp);
while (n < max_s) {
const char *e;
ms.level = 0;
lua_assert(ms.matchdepth == MAXCCALLS);
e = match(&ms, src, p);
if (e) {
reprepstate(&ms); /* (re)prepare state for new match */
if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
n++;
add_value(&ms, &b, src, e, tr);
add_value(&ms, &b, src, e, tr); /* add replacement to buffer */
src = lastmatch = e;
}
if (e && e>src) /* non empty match? */
src = e; /* skip it */
else if (src < ms.src_end)
else if (src < ms.src_end) /* otherwise, skip one character */
luaL_addchar(&b, *src++);
else break;
else break; /* end of subject */
if (anchor) break;
}
luaL_addlstring(&b, src, ms.src_end-src);
@@ -797,35 +807,116 @@ static int str_gsub (lua_State *L) {
** =======================================================
*/
/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
#define MAX_ITEM \
(sizeof(lua_Number) <= 4 ? 150 : sizeof(lua_Number) <= 8 ? 450 : 5050)
#if !defined(lua_number2strx) /* { */
/*
** Hexadecimal floating-point formatter
*/
#include <math.h>
#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char))
/*
** Number of bits that goes into the first digit. It can be any value
** between 1 and 4; the following definition tries to align the number
** to nibble boundaries by making what is left after that first digit a
** multiple of 4.
*/
#define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1)
/*
** Add integer part of 'x' to buffer and return new 'x'
*/
static lua_Number adddigit (char *buff, int n, lua_Number x) {
lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */
int d = (int)dd;
buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */
return x - dd; /* return what is left */
}
static int num2straux (char *buff, int sz, lua_Number x) {
if (x != x || x == HUGE_VAL || x == -HUGE_VAL) /* inf or NaN? */
return l_sprintf(buff, sz, LUA_NUMBER_FMT, x); /* equal to '%g' */
else if (x == 0) { /* can be -0... */
/* create "0" or "-0" followed by exponent */
return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", x);
}
else {
int e;
lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */
int n = 0; /* character count */
if (m < 0) { /* is number negative? */
buff[n++] = '-'; /* add signal */
m = -m; /* make it positive */
}
buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */
m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */
e -= L_NBFD; /* this digit goes before the radix point */
if (m > 0) { /* more digits? */
buff[n++] = lua_getlocaledecpoint(); /* add radix point */
do { /* add as many digits as needed */
m = adddigit(buff, n++, m * 16);
} while (m > 0);
}
n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */
lua_assert(n < sz);
return n;
}
}
static int lua_number2strx (lua_State *L, char *buff, int sz,
const char *fmt, lua_Number x) {
int n = num2straux(buff, sz, x);
if (fmt[SIZELENMOD] == 'A') {
int i;
for (i = 0; i < n; i++)
buff[i] = toupper(uchar(buff[i]));
}
else if (fmt[SIZELENMOD] != 'a')
luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
return n;
}
#endif /* } */
/*
** Maximum size of each formatted item. This maximum size is produced
** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.',
** and '\0') + number of decimal digits to represent maxfloat (which
** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra
** expenses", such as locale-dependent stuff)
*/
#define MAX_ITEM (120 + l_mathlim(MAX_10_EXP))
/* valid flags in a format specification */
#define FLAGS "-+ #0"
/*
** maximum size of each format specification (such as "%-099.99d")
** (+2 for length modifiers; +10 accounts for %99.99x plus margin of error)
*/
#define MAX_FORMAT (sizeof(FLAGS) + 2 + 10)
#define MAX_FORMAT 32
static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
size_t l;
const char *s = luaL_checklstring(L, arg, &l);
static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
luaL_addchar(b, '"');
while (l--) {
while (len--) {
if (*s == '"' || *s == '\\' || *s == '\n') {
luaL_addchar(b, '\\');
luaL_addchar(b, *s);
}
else if (*s == '\0' || iscntrl(uchar(*s))) {
else if (iscntrl(uchar(*s))) {
char buff[10];
if (!isdigit(uchar(*(s+1))))
sprintf(buff, "\\%d", (int)uchar(*s));
l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s));
else
sprintf(buff, "\\%03d", (int)uchar(*s));
l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s));
luaL_addstring(b, buff);
}
else
@@ -835,6 +926,57 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
luaL_addchar(b, '"');
}
/*
** Ensures the 'buff' string uses a dot as the radix character.
*/
static void checkdp (char *buff, int nb) {
if (memchr(buff, '.', nb) == NULL) { /* no dot? */
char point = lua_getlocaledecpoint(); /* try locale point */
char *ppoint = memchr(buff, point, nb);
if (ppoint) *ppoint = '.'; /* change it to a dot */
}
}
static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
switch (lua_type(L, arg)) {
case LUA_TSTRING: {
size_t len;
const char *s = lua_tolstring(L, arg, &len);
addquoted(b, s, len);
break;
}
case LUA_TNUMBER: {
char *buff = luaL_prepbuffsize(b, MAX_ITEM);
int nb;
if (!lua_isinteger(L, arg)) { /* float? */
lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */
nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n);
checkdp(buff, nb); /* ensure it uses a dot */
}
else { /* integers */
lua_Integer n = lua_tointeger(L, arg);
const char *format = (n == LUA_MININTEGER) /* corner case? */
? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */
: LUA_INTEGER_FMT; /* else use default format */
nb = l_sprintf(buff, MAX_ITEM, format, n);
}
luaL_addsize(b, nb);
break;
}
case LUA_TNIL: case LUA_TBOOLEAN: {
luaL_tolstring(L, arg, NULL);
luaL_addvalue(b);
break;
}
default: {
luaL_argerror(L, arg, "value has no literal form");
}
}
}
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
const char *p = strfrmt;
while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
@@ -850,8 +992,8 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
if (isdigit(uchar(*p)))
luaL_error(L, "invalid format (width or precision too long)");
*(form++) = '%';
memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char));
form += p - strfrmt + 1;
memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
form += (p - strfrmt) + 1;
*form = '\0';
return p;
}
@@ -892,49 +1034,55 @@ static int str_format (lua_State *L) {
strfrmt = scanformat(L, strfrmt, form);
switch (*strfrmt++) {
case 'c': {
nb = sprintf(buff, form, (int)luaL_checkinteger(L, arg));
nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg));
break;
}
case 'd': case 'i':
case 'o': case 'u': case 'x': case 'X': {
lua_Integer n = luaL_checkinteger(L, arg);
addlenmod(form, LUA_INTEGER_FRMLEN);
nb = sprintf(buff, form, n);
nb = l_sprintf(buff, MAX_ITEM, form, n);
break;
}
#if defined(LUA_USE_AFORMAT)
case 'a': case 'A':
#endif
addlenmod(form, LUA_NUMBER_FRMLEN);
nb = lua_number2strx(L, buff, MAX_ITEM, form,
luaL_checknumber(L, arg));
break;
case 'e': case 'E': case 'f':
case 'g': case 'G': {
addlenmod(form, LUA_NUMBER_FRMLEN);
nb = sprintf(buff, form, luaL_checknumber(L, arg));
nb = l_sprintf(buff, MAX_ITEM, form, luaL_checknumber(L, arg));
break;
}
case 'q': {
addquoted(L, &b, arg);
addliteral(L, &b, arg);
break;
}
case 's': {
size_t l;
const char *s = luaL_tolstring(L, arg, &l);
if (!strchr(form, '.') && l >= 100) {
/* no precision and string is too long to be formatted;
keep original string */
luaL_addvalue(&b);
break;
}
if (form[2] == '\0') /* no modifiers? */
luaL_addvalue(&b); /* keep entire string */
else {
nb = sprintf(buff, form, s);
lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
break;
luaL_argcheck(L, l == strlen(s), arg, "string contains zeros");
if (!strchr(form, '.') && l >= 100) {
/* no precision and string is too long to be formatted */
luaL_addvalue(&b); /* keep entire string */
}
else { /* format the string into 'buff' */
nb = l_sprintf(buff, MAX_ITEM, form, s);
lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
}
}
break;
}
default: { /* also treat cases 'pnLlh' */
return luaL_error(L, "invalid option '%%%c' to 'format'",
*(strfrmt - 1));
}
}
lua_assert(nb < MAX_ITEM);
luaL_addsize(&b, nb);
}
}
@@ -953,8 +1101,8 @@ static int str_format (lua_State *L) {
/* value used for padding */
#if !defined(LUA_PACKPADBYTE)
#define LUA_PACKPADBYTE 0x00
#if !defined(LUAL_PACKPADBYTE)
#define LUAL_PACKPADBYTE 0x00
#endif
/* maximum size for the binary representation of an integer */
@@ -1191,7 +1339,7 @@ static int str_pack (lua_State *L) {
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
totalsize += ntoalign + size;
while (ntoalign-- > 0)
luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */
luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
arg++;
switch (opt) {
case Kint: { /* signed integers */
@@ -1226,8 +1374,11 @@ static int str_pack (lua_State *L) {
case Kchar: { /* fixed-size string */
size_t len;
const char *s = luaL_checklstring(L, arg, &len);
luaL_argcheck(L, len == (size_t)size, arg, "wrong length");
luaL_addlstring(&b, s, size);
luaL_argcheck(L, len <= (size_t)size, arg,
"string longer than given size");
luaL_addlstring(&b, s, len); /* add string */
while (len++ < (size_t)size) /* pad extra space */
luaL_addchar(&b, LUAL_PACKPADBYTE);
break;
}
case Kstring: { /* strings with length count */
@@ -1250,7 +1401,7 @@ static int str_pack (lua_State *L) {
totalsize += len + 1;
break;
}
case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* go through */
case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */
case Kpaddalign: case Knop:
arg--; /* undo increment */
break;
@@ -1277,7 +1428,7 @@ static int str_packsize (lua_State *L) {
case Kstring: /* strings with length count */
case Kzstr: /* zero-terminated string */
luaL_argerror(L, 1, "variable-length format");
break;
/* call never return, but to avoid warnings: *//* FALLTHROUGH */
default: break;
}
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltable.c,v 2.100 2015/01/05 13:52:37 roberto Exp $
** $Id: ltable.c,v 2.117 2015/11/19 19:16:22 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -14,8 +14,8 @@
** 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.
** part. The actual size of the array is the largest 'n' such that
** more than half the slots between 1 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
@@ -23,9 +23,7 @@
** Hence even when the load factor reaches 100%, performance remains good.
*/
#include <float.h>
#include <math.h>
#include <string.h>
#include <limits.h>
#include "lua.h"
@@ -71,7 +69,7 @@
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
#define hashpointer(t,p) hashmod(t, point2int(p))
#define hashpointer(t,p) hashmod(t, point2uint(p))
#define dummynode (&dummynode_)
@@ -85,31 +83,33 @@ static const Node dummynode_ = {
/*
** Checks whether a float has a value representable as a lua_Integer
** (and does the conversion if so)
** Hash for floating-point numbers.
** The main computation should be just
** n = frexp(n, &i); return (n * INT_MAX) + i
** but there are some numerical subtleties.
** In a two-complement representation, INT_MAX does not has an exact
** representation as a float, but INT_MIN does; because the absolute
** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the
** absolute value of the product 'frexp * -INT_MIN' is smaller or equal
** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when
** adding 'i'; the use of '~u' (instead of '-u') avoids problems with
** INT_MIN.
*/
static int numisinteger (lua_Number x, lua_Integer *p) {
if ((x) == l_floor(x)) /* integral value? */
return lua_numbertointeger(x, p); /* try as an integer */
else return 0;
}
/*
** hash for floating-point numbers
*/
static Node *hashfloat (const Table *t, lua_Number n) {
#if !defined(l_hashfloat)
static int l_hashfloat (lua_Number n) {
int i;
n = l_mathop(frexp)(n, &i) * cast_num(INT_MAX - DBL_MAX_EXP);
i += cast_int(n);
if (i < 0) {
if (cast(unsigned int, i) == 0u - i) /* use unsigned to avoid overflows */
i = 0; /* handle INT_MIN */
i = -i; /* must be a positive value */
lua_Integer ni;
n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN);
if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */
lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL));
return 0;
}
else { /* normal case */
unsigned int u = cast(unsigned int, i) + cast(unsigned int, ni);
return cast_int(u <= cast(unsigned int, INT_MAX) ? u : ~u);
}
return hashmod(t, i);
}
#endif
/*
@@ -121,17 +121,11 @@ static Node *mainposition (const Table *t, const TValue *key) {
case LUA_TNUMINT:
return hashint(t, ivalue(key));
case LUA_TNUMFLT:
return hashfloat(t, fltvalue(key));
return hashmod(t, l_hashfloat(fltvalue(key)));
case LUA_TSHRSTR:
return hashstr(t, tsvalue(key));
case LUA_TLNGSTR: {
TString *s = tsvalue(key);
if (s->extra == 0) { /* no hash? */
s->hash = luaS_hash(getstr(s), s->len, s->hash);
s->extra = 1; /* now it has its hash */
}
return hashstr(t, tsvalue(key));
}
case LUA_TLNGSTR:
return hashpow2(t, luaS_hashlongstr(tsvalue(key)));
case LUA_TBOOLEAN:
return hashboolean(t, bvalue(key));
case LUA_TLIGHTUSERDATA:
@@ -139,6 +133,7 @@ static Node *mainposition (const Table *t, const TValue *key) {
case LUA_TLCF:
return hashpointer(t, fvalue(key));
default:
lua_assert(!ttisdeadkey(key));
return hashpointer(t, gcvalue(key));
}
}
@@ -219,28 +214,29 @@ int luaH_next (lua_State *L, Table *t, StkId key) {
/*
** Compute the optimal size for the array part of table 't'. 'nums' is a
** "count array" where 'nums[i]' is the number of integers in the table
** between 2^(i - 1) + 1 and 2^i. Put in '*narray' the optimal size, and
** return the number of elements that will go to that part.
** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of
** integer keys in the table and leaves with the number of keys that
** will go to the array part; return the optimal size.
*/
static unsigned int computesizes (unsigned int nums[], unsigned int *narray) {
static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
int i;
unsigned int twotoi; /* 2^i */
unsigned int twotoi; /* 2^i (candidate for optimal size) */
unsigned int a = 0; /* number of elements smaller than 2^i */
unsigned int na = 0; /* number of elements to go to array part */
unsigned int n = 0; /* optimal size for array part */
for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) {
unsigned int optimal = 0; /* optimal size for array part */
/* loop while keys can fill more than half of total size */
for (i = 0, twotoi = 1; *pna > twotoi / 2; 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 up to 'n' will go to array part */
optimal = twotoi; /* optimal size (till now) */
na = a; /* all elements up to 'optimal' will go to array part */
}
}
if (a == *narray) break; /* all elements already counted */
}
*narray = n;
lua_assert(*narray/2 <= na && na <= *narray);
return na;
lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal);
*pna = na;
return optimal;
}
@@ -255,6 +251,11 @@ static int countint (const TValue *key, unsigned int *nums) {
}
/*
** Count keys in array part of table 't': Fill 'nums[i]' with
** number of keys that will go into corresponding slice and return
** total number of non-nil keys.
*/
static unsigned int numusearray (const Table *t, unsigned int *nums) {
int lg;
unsigned int ttlg; /* 2^lg */
@@ -281,8 +282,7 @@ static unsigned int numusearray (const Table *t, unsigned int *nums) {
}
static int numusehash (const Table *t, unsigned int *nums,
unsigned int *pnasize) {
static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {
int totaluse = 0; /* total number of elements */
int ause = 0; /* elements added to 'nums' (can go to array part) */
int i = sizenode(t);
@@ -293,7 +293,7 @@ static int numusehash (const Table *t, unsigned int *nums,
totaluse++;
}
}
*pnasize += ause;
*pna += ause;
return totaluse;
}
@@ -363,7 +363,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
}
}
if (!isdummy(nold))
luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old array */
luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old hash */
}
@@ -376,21 +376,22 @@ void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) {
** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i
*/
static void rehash (lua_State *L, Table *t, const TValue *ek) {
unsigned int nasize, na;
unsigned int asize; /* optimal size for array part */
unsigned int na; /* number of keys in the array part */
unsigned int nums[MAXABITS + 1];
int i;
int totaluse;
for (i = 0; i <= MAXABITS; 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 */
na = numusearray(t, nums); /* count keys in array part */
totaluse = na; /* all those keys are integer keys */
totaluse += numusehash(t, nums, &na); /* count keys in hash part */
/* count extra key */
nasize += countint(ek, nums);
na += countint(ek, nums);
totaluse++;
/* compute new size for array part */
na = computesizes(nums, &nasize);
asize = computesizes(nums, &na);
/* resize the table to new computed sizes */
luaH_resize(L, t, nasize, totaluse - na);
luaH_resize(L, t, asize, totaluse - na);
}
@@ -443,14 +444,13 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
TValue aux;
if (ttisnil(key)) luaG_runerror(L, "table index is nil");
else if (ttisfloat(key)) {
lua_Number n = fltvalue(key);
lua_Integer k;
if (luai_numisnan(n))
luaG_runerror(L, "table index is NaN");
if (numisinteger(n, &k)) { /* index is int? */
if (luaV_tointeger(key, &k, 0)) { /* index is int? */
setivalue(&aux, k);
key = &aux; /* insert it as an integer */
}
else if (luai_numisnan(fltvalue(key)))
luaG_runerror(L, "table index is NaN");
}
mp = mainposition(t, key);
if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */
@@ -458,7 +458,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
Node *f = getfreepos(t); /* get a free place */
if (f == NULL) { /* cannot find a free place? */
rehash(L, t, key); /* grow table */
/* whatever called 'newkey' takes care of TM cache and GC barrier */
/* whatever called 'newkey' takes care of TM cache */
return luaH_set(L, t, key); /* insert key into grown table */
}
lua_assert(!isdummy(f));
@@ -496,7 +496,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
*/
const TValue *luaH_getint (Table *t, lua_Integer key) {
/* (1 <= key && key <= t->sizearray) */
if (l_castS2U(key - 1) < t->sizearray)
if (l_castS2U(key) - 1 < t->sizearray)
return &t->array[key - 1];
else {
Node *n = hashint(t, key);
@@ -508,7 +508,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
if (nx == 0) break;
n += nx;
}
};
}
return luaO_nilobject;
}
}
@@ -517,7 +517,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
/*
** search function for short strings
*/
const TValue *luaH_getstr (Table *t, TString *key) {
const TValue *luaH_getshortstr (Table *t, TString *key) {
Node *n = hashstr(t, key);
lua_assert(key->tt == LUA_TSHRSTR);
for (;;) { /* check whether 'key' is somewhere in the chain */
@@ -526,11 +526,41 @@ const TValue *luaH_getstr (Table *t, TString *key) {
return gval(n); /* that's it */
else {
int nx = gnext(n);
if (nx == 0) break;
if (nx == 0)
return luaO_nilobject; /* not found */
n += nx;
}
};
return luaO_nilobject;
}
}
/*
** "Generic" get version. (Not that generic: not valid for integers,
** which may be in array part, nor for floats with integral values.)
*/
static const TValue *getgeneric (Table *t, const TValue *key) {
Node *n = mainposition(t, key);
for (;;) { /* check whether 'key' is somewhere in the chain */
if (luaV_rawequalobj(gkey(n), key))
return gval(n); /* that's it */
else {
int nx = gnext(n);
if (nx == 0)
return luaO_nilobject; /* not found */
n += nx;
}
}
}
const TValue *luaH_getstr (Table *t, TString *key) {
if (key->tt == LUA_TSHRSTR)
return luaH_getshortstr(t, key);
else { /* for long strings, use generic case */
TValue ko;
setsvalue(cast(lua_State *, NULL), &ko, key);
return getgeneric(t, &ko);
}
}
@@ -539,28 +569,17 @@ const TValue *luaH_getstr (Table *t, TString *key) {
*/
const TValue *luaH_get (Table *t, const TValue *key) {
switch (ttype(key)) {
case LUA_TSHRSTR: return luaH_getstr(t, tsvalue(key));
case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key));
case LUA_TNUMINT: return luaH_getint(t, ivalue(key));
case LUA_TNIL: return luaO_nilobject;
case LUA_TNUMFLT: {
lua_Integer k;
if (numisinteger(fltvalue(key), &k)) /* index is int? */
if (luaV_tointeger(key, &k, 0)) /* index is int? */
return luaH_getint(t, k); /* use specialized version */
/* else go through */
}
default: {
Node *n = mainposition(t, key);
for (;;) { /* check whether 'key' is somewhere in the chain */
if (luaV_rawequalobj(gkey(n), key))
return gval(n); /* that's it */
else {
int nx = gnext(n);
if (nx == 0) break;
n += nx;
}
};
return luaO_nilobject;
}
/* else... */
} /* FALLTHROUGH */
default:
return getgeneric(t, key);
}
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltable.h,v 2.20 2014/09/04 18:15:29 roberto Exp $
** $Id: ltable.h,v 2.21 2015/11/03 15:47:30 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -18,6 +18,10 @@
/* 'const' to avoid wrong writings that can mess up field 'next' */
#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk))
/*
** writable version of 'gkey'; allows updates to individual fields,
** but not to the whole (which has incompatible type)
*/
#define wgkey(n) (&(n)->i_key.nk)
#define invalidateTMcache(t) ((t)->flags = 0)
@@ -31,6 +35,7 @@
LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
TValue *value);
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key);

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltablib.c,v 1.79 2014/11/02 19:19:04 roberto Exp $
** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $
** Library for Table Manipulation
** See Copyright Notice in lua.h
*/
@@ -12,6 +12,7 @@
#include <limits.h>
#include <stddef.h>
#include <string.h>
#include "lua.h"
@@ -19,40 +20,42 @@
#include "lualib.h"
/*
** Structure with table-access functions
** Operations that an object must define to mimic a table
** (some functions only need some of them)
*/
typedef struct {
int (*geti) (lua_State *L, int idx, lua_Integer n);
void (*seti) (lua_State *L, int idx, lua_Integer n);
} TabA;
#define TAB_R 1 /* read */
#define TAB_W 2 /* write */
#define TAB_L 4 /* length */
#define TAB_RW (TAB_R | TAB_W) /* read/write */
/*
** Check that 'arg' has a table and set access functions in 'ta' to raw
** or non-raw according to the presence of corresponding metamethods.
*/
static void checktab (lua_State *L, int arg, TabA *ta) {
ta->geti = NULL; ta->seti = NULL;
if (lua_getmetatable(L, arg)) {
lua_pushliteral(L, "__index"); /* 'index' metamethod */
if (lua_rawget(L, -2) != LUA_TNIL)
ta->geti = lua_geti;
lua_pushliteral(L, "__newindex"); /* 'newindex' metamethod */
if (lua_rawget(L, -3) != LUA_TNIL)
ta->seti = lua_seti;
lua_pop(L, 3); /* pop metatable plus both metamethods */
}
if (ta->geti == NULL || ta->seti == NULL) {
luaL_checktype(L, arg, LUA_TTABLE); /* must be table for raw methods */
if (ta->geti == NULL) ta->geti = lua_rawgeti;
if (ta->seti == NULL) ta->seti = lua_rawseti;
}
#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n))
static int checkfield (lua_State *L, const char *key, int n) {
lua_pushstring(L, key);
return (lua_rawget(L, -n) != LUA_TNIL);
}
#define aux_getn(L,n,ta) (checktab(L, n, ta), luaL_len(L, n))
/*
** Check that 'arg' either is a table or can behave like one (that is,
** has a metatable with the required metamethods)
*/
static void checktab (lua_State *L, int arg, int what) {
if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */
int n = 1; /* number of elements to pop */
if (lua_getmetatable(L, arg) && /* must have metatable */
(!(what & TAB_R) || checkfield(L, "__index", ++n)) &&
(!(what & TAB_W) || checkfield(L, "__newindex", ++n)) &&
(!(what & TAB_L) || checkfield(L, "__len", ++n))) {
lua_pop(L, n); /* pop metatable and tested metamethods */
}
else
luaL_checktype(L, arg, LUA_TTABLE); /* force an error */
}
}
#if defined(LUA_COMPAT_MAXN)
@@ -74,8 +77,7 @@ static int maxn (lua_State *L) {
static int tinsert (lua_State *L) {
TabA ta;
lua_Integer e = aux_getn(L, 1, &ta) + 1; /* first empty element */
lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */
lua_Integer pos; /* where to insert new element */
switch (lua_gettop(L)) {
case 2: { /* called with only 2 arguments */
@@ -87,8 +89,8 @@ static int tinsert (lua_State *L) {
pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */
luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
for (i = e; i > pos; i--) { /* move up elements */
(*ta.geti)(L, 1, i - 1);
(*ta.seti)(L, 1, i); /* t[i] = t[i - 1] */
lua_geti(L, 1, i - 1);
lua_seti(L, 1, i); /* t[i] = t[i - 1] */
}
break;
}
@@ -96,65 +98,67 @@ static int tinsert (lua_State *L) {
return luaL_error(L, "wrong number of arguments to 'insert'");
}
}
(*ta.seti)(L, 1, pos); /* t[pos] = v */
lua_seti(L, 1, pos); /* t[pos] = v */
return 0;
}
static int tremove (lua_State *L) {
TabA ta;
lua_Integer size = aux_getn(L, 1, &ta);
lua_Integer size = aux_getn(L, 1, TAB_RW);
lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */
luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds");
(*ta.geti)(L, 1, pos); /* result = t[pos] */
lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) {
(*ta.geti)(L, 1, pos + 1);
(*ta.seti)(L, 1, pos); /* t[pos] = t[pos + 1] */
lua_geti(L, 1, pos + 1);
lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */
}
lua_pushnil(L);
(*ta.seti)(L, 1, pos); /* t[pos] = nil */
lua_seti(L, 1, pos); /* t[pos] = nil */
return 1;
}
/*
** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever
** possible, copy in increasing order, which is better for rehashing.
** "possible" means destination after original range, or smaller
** than origin, or copying to another table.
*/
static int tmove (lua_State *L) {
TabA ta;
lua_Integer f = luaL_checkinteger(L, 2);
lua_Integer e = luaL_checkinteger(L, 3);
lua_Integer t = luaL_checkinteger(L, 4);
int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */
/* the following restriction avoids several problems with overflows */
luaL_argcheck(L, f > 0, 2, "initial position must be positive");
checktab(L, 1, TAB_R);
checktab(L, tt, TAB_W);
if (e >= f) { /* otherwise, nothing to move */
lua_Integer n, i;
ta.geti = (luaL_getmetafield(L, 1, "__index") == LUA_TNIL)
? (luaL_checktype(L, 1, LUA_TTABLE), lua_rawgeti)
: lua_geti;
ta.seti = (luaL_getmetafield(L, tt, "__newindex") == LUA_TNIL)
? (luaL_checktype(L, tt, LUA_TTABLE), lua_rawseti)
: lua_seti;
luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3,
"too many elements to move");
n = e - f + 1; /* number of elements to move */
if (t > f) {
for (i = n - 1; i >= 0; i--) {
(*ta.geti)(L, 1, f + i);
(*ta.seti)(L, tt, t + i);
luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4,
"destination wrap around");
if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) {
for (i = 0; i < n; i++) {
lua_geti(L, 1, f + i);
lua_seti(L, tt, t + i);
}
}
else {
for (i = 0; i < n; i++) {
(*ta.geti)(L, 1, f + i);
(*ta.seti)(L, tt, t + i);
for (i = n - 1; i >= 0; i--) {
lua_geti(L, 1, f + i);
lua_seti(L, tt, t + i);
}
}
}
lua_pushvalue(L, tt); /* return "to table" */
lua_pushvalue(L, tt); /* return destination table */
return 1;
}
static void addfield (lua_State *L, luaL_Buffer *b, TabA *ta, lua_Integer i) {
(*ta->geti)(L, 1, i);
static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
lua_geti(L, 1, i);
if (!lua_isstring(L, -1))
luaL_error(L, "invalid value (%s) at index %d in table for 'concat'",
luaL_typename(L, -1), i);
@@ -163,21 +167,19 @@ static void addfield (lua_State *L, luaL_Buffer *b, TabA *ta, lua_Integer i) {
static int tconcat (lua_State *L) {
TabA ta;
luaL_Buffer b;
lua_Integer last = aux_getn(L, 1, TAB_R);
size_t lsep;
lua_Integer i, last;
const char *sep = luaL_optlstring(L, 2, "", &lsep);
checktab(L, 1, &ta);
i = luaL_optinteger(L, 3, 1);
last = luaL_opt(L, luaL_checkinteger, 4, luaL_len(L, 1));
lua_Integer i = luaL_optinteger(L, 3, 1);
last = luaL_optinteger(L, 4, last);
luaL_buffinit(L, &b);
for (; i < last; i++) {
addfield(L, &b, &ta, i);
addfield(L, &b, i);
luaL_addlstring(&b, sep, lsep);
}
if (i == last) /* add last value (if interval was not empty) */
addfield(L, &b, &ta, i);
addfield(L, &b, i);
luaL_pushresult(&b);
return 1;
}
@@ -195,7 +197,7 @@ static int pack (lua_State *L) {
lua_createtable(L, n, 1); /* create result table */
lua_insert(L, 1); /* put it at index 1 */
for (i = n; i >= 1; i--) /* assign elements */
lua_rawseti(L, 1, i);
lua_seti(L, 1, i);
lua_pushinteger(L, n);
lua_setfield(L, 1, "n"); /* t.n = number of elements */
return 1; /* return table */
@@ -203,20 +205,17 @@ static int pack (lua_State *L) {
static int unpack (lua_State *L) {
TabA ta;
lua_Integer i, e;
lua_Unsigned n;
checktab(L, 1, &ta);
i = luaL_optinteger(L, 2, 1);
e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
lua_Integer i = luaL_optinteger(L, 2, 1);
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
if (i > e) return 0; /* empty range */
n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */
if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n)))
return luaL_error(L, "too many results to unpack");
do { /* must have at least one element */
(*ta.geti)(L, 1, i); /* push arg[i..e] */
} while (i++ < e);
for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */
lua_geti(L, 1, i);
}
lua_geti(L, 1, e); /* push last element */
return (int)n;
}
@@ -233,97 +232,191 @@ static int unpack (lua_State *L) {
*/
static void set2 (lua_State *L, TabA *ta, int i, int j) {
(*ta->seti)(L, 1, i);
(*ta->seti)(L, 1, j);
/* type for array indices */
typedef unsigned int IdxT;
/*
** Produce a "random" 'unsigned int' to randomize pivot choice. This
** macro is used only when 'sort' detects a big imbalance in the result
** of a partition. (If you don't want/need this "randomness", ~0 is a
** good choice.)
*/
#if !defined(l_randomizePivot) /* { */
#include <time.h>
/* size of 'e' measured in number of 'unsigned int's */
#define sof(e) (sizeof(e) / sizeof(unsigned int))
/*
** Use 'time' and 'clock' as sources of "randomness". Because we don't
** know the types 'clock_t' and 'time_t', we cannot cast them to
** anything without risking overflows. A safe way to use their values
** is to copy them to an array of a known type and use the array values.
*/
static unsigned int l_randomizePivot (void) {
clock_t c = clock();
time_t t = time(NULL);
unsigned int buff[sof(c) + sof(t)];
unsigned int i, rnd = 0;
memcpy(buff, &c, sof(c) * sizeof(unsigned int));
memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int));
for (i = 0; i < sof(buff); i++)
rnd += buff[i];
return rnd;
}
#endif /* } */
/* arrays larger than 'RANLIMIT' may use randomized pivots */
#define RANLIMIT 100u
static void set2 (lua_State *L, IdxT i, IdxT j) {
lua_seti(L, 1, i);
lua_seti(L, 1, j);
}
/*
** Return true iff value at stack index 'a' is less than the value at
** index 'b' (according to the order of the sort).
*/
static int sort_comp (lua_State *L, int a, int b) {
if (!lua_isnil(L, 2)) { /* function? */
if (lua_isnil(L, 2)) /* no function? */
return lua_compare(L, a, b, LUA_OPLT); /* a < b */
else { /* function */
int res;
lua_pushvalue(L, 2);
lua_pushvalue(L, 2); /* push function */
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);
lua_call(L, 2, 1); /* call function */
res = lua_toboolean(L, -1); /* get result */
lua_pop(L, 1); /* pop result */
return res;
}
else /* a < b? */
return lua_compare(L, a, b, LUA_OPLT);
}
static void auxsort (lua_State *L, TabA *ta, int l, int u) {
while (l < u) { /* for tail recursion */
int i, j;
/* sort elements a[l], a[(l+u)/2] and a[u] */
(*ta->geti)(L, 1, l);
(*ta->geti)(L, 1, u);
if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
set2(L, ta, l, u); /* swap a[l] - a[u] */
/*
** Does the partition: Pivot P is at the top of the stack.
** precondition: a[lo] <= P == a[up-1] <= a[up],
** so it only needs to do the partition from lo + 1 to up - 2.
** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up]
** returns 'i'.
*/
static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
IdxT i = lo; /* will be incremented before first use */
IdxT j = up - 1; /* will be decremented before first use */
/* loop invariant: a[lo .. i] <= P <= a[j .. up] */
for (;;) {
/* next loop: repeat ++i while a[i] < P */
while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {
if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */
luaL_error(L, "invalid order function for sorting");
lua_pop(L, 1); /* remove a[i] */
}
/* after the loop, a[i] >= P and a[lo .. i - 1] < P */
/* next loop: repeat --j while P < a[j] */
while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {
if (j < i) /* j < i but a[j] > P ?? */
luaL_error(L, "invalid order function for sorting");
lua_pop(L, 1); /* remove a[j] */
}
/* after the loop, a[j] <= P and a[j + 1 .. up] >= P */
if (j < i) { /* no elements out of place? */
/* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */
lua_pop(L, 1); /* pop a[j] */
/* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */
set2(L, up - 1, i);
return i;
}
/* otherwise, swap a[i] - a[j] to restore invariant and repeat */
set2(L, i, j);
}
}
/*
** Choose an element in the middle (2nd-3th quarters) of [lo,up]
** "randomized" by 'rnd'
*/
static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
IdxT r4 = (up - lo) / 4; /* range/4 */
IdxT p = rnd % (r4 * 2) + (lo + r4);
lua_assert(lo + r4 <= p && p <= up - r4);
return p;
}
/*
** QuickSort algorithm (recursive function)
*/
static void auxsort (lua_State *L, IdxT lo, IdxT up,
unsigned int rnd) {
while (lo < up) { /* loop for tail recursion */
IdxT p; /* Pivot index */
IdxT n; /* to be used later */
/* sort elements 'lo', 'p', and 'up' */
lua_geti(L, 1, lo);
lua_geti(L, 1, up);
if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */
set2(L, lo, up); /* swap a[lo] - a[up] */
else
lua_pop(L, 2);
if (u-l == 1) break; /* only 2 elements */
i = (l+u)/2;
(*ta->geti)(L, 1, i);
(*ta->geti)(L, 1, l);
if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */
set2(L, ta, i, l);
lua_pop(L, 2); /* remove both values */
if (up - lo == 1) /* only 2 elements? */
return; /* already sorted */
if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */
p = (lo + up)/2; /* middle element is a good pivot */
else /* for larger intervals, it is worth a random pivot */
p = choosePivot(lo, up, rnd);
lua_geti(L, 1, p);
lua_geti(L, 1, lo);
if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */
set2(L, p, lo); /* swap a[p] - a[lo] */
else {
lua_pop(L, 1); /* remove a[l] */
(*ta->geti)(L, 1, u);
if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */
set2(L, ta, i, u);
lua_pop(L, 1); /* remove a[lo] */
lua_geti(L, 1, up);
if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */
set2(L, p, up); /* swap a[up] - a[p] */
else
lua_pop(L, 2);
}
if (u-l == 2) break; /* only 3 elements */
(*ta->geti)(L, 1, i); /* Pivot */
lua_pushvalue(L, -1);
(*ta->geti)(L, 1, u-1);
set2(L, ta, 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 ((*ta->geti)(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 ((*ta->geti)(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, ta, i, j);
}
(*ta->geti)(L, 1, u-1);
(*ta->geti)(L, 1, i);
set2(L, ta, 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;
if (up - lo == 2) /* only 3 elements? */
return; /* already sorted */
lua_geti(L, 1, p); /* get middle element (Pivot) */
lua_pushvalue(L, -1); /* push Pivot */
lua_geti(L, 1, up - 1); /* push a[up - 1] */
set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */
p = partition(L, lo, up);
/* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */
if (p - lo < up - p) { /* lower interval is smaller? */
auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */
n = p - lo; /* size of smaller interval */
lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */
}
else {
j=i+1; i=u; u=j-2;
auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */
n = up - p; /* size of smaller interval */
up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */
}
auxsort(L, ta, j, i); /* call recursively the smaller one */
} /* repeat the routine for the larger one */
if ((up - lo) / 128 > n) /* partition too imbalanced? */
rnd = l_randomizePivot(); /* try a new randomization */
} /* tail call auxsort(L, lo, up, rnd) */
}
static int sort (lua_State *L) {
TabA ta;
int n = (int)aux_getn(L, 1, &ta);
luaL_checkstack(L, 50, ""); /* assume array is smaller than 2^50 */
if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
luaL_checktype(L, 2, LUA_TFUNCTION);
lua_settop(L, 2); /* make sure there are two arguments */
auxsort(L, &ta, 1, n);
lua_Integer n = aux_getn(L, 1, TAB_RW);
if (n > 1) { /* non-trivial interval? */
luaL_argcheck(L, n < INT_MAX, 1, "array too big");
if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */
lua_settop(L, 2); /* make sure there are two arguments */
auxsort(L, 1, (IdxT)n, 0);
}
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltm.c,v 2.33 2014/11/21 12:15:57 roberto Exp $
** $Id: ltm.c,v 2.37 2016/02/26 19:20:15 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -57,7 +57,7 @@ void luaT_init (lua_State *L) {
** tag methods
*/
const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
const TValue *tm = luaH_getstr(events, ename);
const TValue *tm = luaH_getshortstr(events, ename);
lua_assert(event <= TM_EQ);
if (ttisnil(tm)) { /* no tag method? */
events->flags |= cast_byte(1u<<event); /* cache this fact */
@@ -79,20 +79,41 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
default:
mt = G(L)->mt[ttnov(o)];
}
return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject);
return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject);
}
/*
** Return the name of the type of an object. For tables and userdata
** with metatable, use their '__name' metafield, if present.
*/
const char *luaT_objtypename (lua_State *L, const TValue *o) {
Table *mt;
if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) ||
(ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) {
const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name"));
if (ttisstring(name)) /* is '__name' a string? */
return getstr(tsvalue(name)); /* use it as type name */
}
return ttypename(ttnov(o)); /* else use standard type name */
}
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, TValue *p3, int hasres) {
ptrdiff_t result = savestack(L, p3);
setobj2s(L, L->top++, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, L->top++, p1); /* 1st argument */
setobj2s(L, L->top++, p2); /* 2nd argument */
StkId func = L->top;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
L->top += 3;
if (!hasres) /* no result? 'p3' is third argument */
setobj2s(L, L->top++, p3); /* 3rd argument */
/* metamethod may yield only when called from Lua code */
luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci));
if (isLua(L->ci))
luaD_call(L, func, hasres);
else
luaD_callnoyield(L, func, hasres);
if (hasres) { /* if has result, move it to its place */
p3 = restorestack(L, result);
setobjs2s(L, p3, --L->top);
@@ -117,6 +138,7 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
switch (event) {
case TM_CONCAT:
luaG_concaterror(L, p1, p2);
/* call never returns, but to avoid warnings: *//* FALLTHROUGH */
case TM_BAND: case TM_BOR: case TM_BXOR:
case TM_SHL: case TM_SHR: case TM_BNOT: {
lua_Number dummy;
@@ -124,8 +146,8 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
luaG_tointerror(L, p1, p2);
else
luaG_opinterror(L, p1, p2, "perform bitwise operation on");
/* else go through */
}
/* calls never return, but to avoid warnings: *//* FALLTHROUGH */
default:
luaG_opinterror(L, p1, p2, "perform arithmetic on");
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltm.h,v 2.21 2014/10/25 11:50:46 roberto Exp $
** $Id: ltm.h,v 2.22 2016/02/26 19:20:15 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -51,11 +51,12 @@ typedef enum {
#define fasttm(l,et,e) gfasttm(G(l), et, e)
#define ttypename(x) luaT_typenames_[(x) + 1]
#define objtypename(x) ttypename(ttnov(x))
LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS];
LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);
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);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lua.c,v 1.222 2014/11/11 19:41:27 roberto Exp $
** $Id: lua.c,v 1.226 2015/08/14 19:11:20 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
@@ -18,6 +18,7 @@
#include "lauxlib.h"
#include "lualib.h"
#include "lstring.h"
#if !defined(LUA_PROMPT)
@@ -80,9 +81,7 @@
#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_rawlen(L,idx) > 0) /* non-empty line? */ \
add_history(lua_tostring(L, idx)); /* add it to history */
#define lua_saveline(L,line) ((void)L, add_history(line))
#define lua_freeline(L,b) ((void)L, free(b))
#else /* }{ */
@@ -90,7 +89,7 @@
#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_saveline(L,line) { (void)L; (void)line; }
#define lua_freeline(L,b) { (void)L; (void)b; }
#endif /* } */
@@ -315,31 +314,31 @@ static int pushline (lua_State *L, int firstline) {
lua_pop(L, 1); /* remove prompt */
l = strlen(b);
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
b[l-1] = '\0'; /* remove it */
b[--l] = '\0'; /* remove it */
if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */
lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */
else
lua_pushstring(L, b);
lua_pushlstring(L, b, l);
lua_freeline(L, b);
return 1;
}
/*
** Try to compile line on the stack as 'return <line>'; on return, stack
** Try to compile line on the stack as 'return <line>;'; on return, stack
** has either compiled chunk or original line (if compilation failed).
*/
static int addreturn (lua_State *L) {
int status;
size_t len; const char *line;
lua_pushliteral(L, "return ");
lua_pushvalue(L, -2); /* duplicate line */
lua_concat(L, 2); /* new line is "return ..." */
line = lua_tolstring(L, -1, &len);
if ((status = luaL_loadbuffer(L, line, len, "=stdin")) == LUA_OK)
lua_remove(L, -3); /* remove original line */
const char *line = lua_tostring(L, -1); /* original line */
const char *retline = lua_pushfstring(L, "return %s;", line);
int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin");
if (status == LUA_OK) {
lua_remove(L, -2); /* remove modified line */
if (line[0] != '\0') /* non empty? */
lua_saveline(L, line); /* keep history */
}
else
lua_pop(L, 2); /* remove result from 'luaL_loadbuffer' and new line */
lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */
return status;
}
@@ -352,8 +351,10 @@ static int multiline (lua_State *L) {
size_t len;
const char *line = lua_tolstring(L, 1, &len); /* get what it has */
int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */
if (!incomplete(L, status) || !pushline(L, 0))
if (!incomplete(L, status) || !pushline(L, 0)) {
lua_saveline(L, line); /* keep history */
return status; /* cannot or should not try to add continuation line */
}
lua_pushliteral(L, "\n"); /* add newline... */
lua_insert(L, -2); /* ...between the two lines */
lua_concat(L, 3); /* join them */
@@ -374,7 +375,6 @@ static int loadline (lua_State *L) {
return -1; /* no input */
if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */
status = multiline(L); /* try as command, maybe with continuation lines */
lua_saveline(L, 1); /* keep history */
lua_remove(L, 1); /* remove line from the stack */
lua_assert(lua_gettop(L) == 1);
return status;
@@ -482,14 +482,14 @@ static int collectargs (char **argv, int *first) {
args |= has_E;
break;
case 'i':
args |= has_i; /* goes through (-i implies -v) */
args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */
case 'v':
if (argv[i][2] != '\0') /* extra characters after 1st? */
return has_error; /* invalid option */
args |= has_v;
break;
case 'e':
args |= has_e; /* go through */
args |= has_e; /* FALLTHROUGH */
case 'l': /* both options need an argument */
if (argv[i][2] == '\0') { /* no concatenated argument? */
i++; /* try next 'argv' */
@@ -513,17 +513,16 @@ static int collectargs (char **argv, int *first) {
static int runargs (lua_State *L, char **argv, int n) {
int i;
for (i = 1; i < n; i++) {
int status;
int option = argv[i][1];
lua_assert(argv[i][0] == '-'); /* already checked */
if (option == 'e' || option == 'l') {
int status;
const char *extra = argv[i] + 2; /* both options need an argument */
if (*extra == '\0') extra = argv[++i];
lua_assert(extra != NULL);
if (option == 'e')
status = dostring(L, extra, "=(command line)");
else
status = dolibrary(L, extra);
status = (option == 'e')
? dostring(L, extra, "=(command line)")
: dolibrary(L, extra);
if (status != LUA_OK) return 0;
}
}
@@ -594,7 +593,9 @@ static int pmain (lua_State *L) {
int main (int argc, char **argv) {
int status, result;
lua_State *L = luaL_newstate(); /* create state */
lua_State *L;
luaS_initshr(); /* init global short string table */
L = luaL_newstate(); /* create state */
if (L == NULL) {
l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE;
@@ -606,6 +607,7 @@ int main (int argc, char **argv) {
result = lua_toboolean(L, -1); /* get result */
report(L, status);
lua_close(L);
luaS_exitshr();
return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lua.h,v 1.325 2014/12/26 17:24:27 roberto Exp $
** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
@@ -19,11 +19,11 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "3"
#define LUA_VERSION_NUM 503
#define LUA_VERSION_RELEASE "0"
#define LUA_VERSION_RELEASE "3"
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2015 Lua.org, PUC-Rio"
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2016 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -35,9 +35,11 @@
/*
** pseudo-indices
** Pseudo-indices
** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
** space after that to help overflow detection)
*/
#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX
#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
@@ -282,6 +284,7 @@ LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip);
LUA_API void (lua_clonefunction) (lua_State *L, const void *eL);
/*
** coroutine functions
*/
@@ -357,11 +360,10 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
#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_pushliteral(L, s) lua_pushstring(L, "" s)
#define lua_pushglobaltable(L) \
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
@@ -460,12 +462,12 @@ struct lua_Debug {
/* Add by skynet */
extern lua_State * skynet_sig_L;
LUA_API lua_State * skynet_sig_L;
LUA_API void (lua_checksig_)(lua_State *L);
#define lua_checksig(L) if (skynet_sig_L) { lua_checksig_(L); }
/******************************************************************************
* Copyright (C) 1994-2015 Lua.org, PUC-Rio.
* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

View File

@@ -1,5 +1,5 @@
/*
** $Id: luac.c,v 1.72 2015/01/06 03:09:13 lhf Exp $
** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $
** Lua compiler (saves bytecodes to files; also lists bytecodes)
** See Copyright Notice in lua.h
*/
@@ -21,6 +21,7 @@
#include "lobject.h"
#include "lstate.h"
#include "lundump.h"
#include "lstring.h"
static void PrintFunction(const Proto* f, int full);
#define luaU_print PrintFunction
@@ -195,6 +196,7 @@ int main(int argc, char* argv[])
int i=doargs(argc,argv);
argc-=i; argv+=i;
if (argc<=0) usage("no input files given");
luaS_initshr();
L=luaL_newstate();
if (L==NULL) fatal("cannot create state: not enough memory");
lua_pushcfunction(L,&pmain);
@@ -206,7 +208,7 @@ int main(int argc, char* argv[])
}
/*
** $Id: print.c,v 1.76 2015/01/05 16:12:50 lhf Exp $
** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $
** print bytecodes
** See Copyright Notice in lua.h
*/
@@ -226,7 +228,7 @@ int main(int argc, char* argv[])
static void PrintString(const TString* ts)
{
const char* s=getstr(ts);
size_t i,n=ts->len;
size_t i,n=tsslen(ts);
printf("%c",'"');
for (i=0; i<n; i++)
{
@@ -287,9 +289,8 @@ static void PrintConstant(const Proto* f, int i)
static void PrintCode(const Proto* f)
{
const SharedProto *sp = f->sp;
const Instruction* code=sp->code;
int pc,n=sp->sizecode;
const Instruction* code=f->sp->code;
int pc,n=f->sp->sizecode;
for (pc=0; pc<n; pc++)
{
Instruction i=code[pc];

View File

@@ -1,5 +1,5 @@
/*
** $Id: luaconf.h,v 1.238 2014/12/29 13:27:55 roberto Exp $
** $Id: luaconf.h,v 1.255 2016/05/01 20:06:09 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
@@ -96,10 +96,8 @@
/*
@@ LUA_INT_INT / LUA_INT_LONG / LUA_INT_LONGLONG defines the type for
** Lua integers.
@@ LUA_REAL_FLOAT / LUA_REAL_DOUBLE / LUA_REAL_LONGDOUBLE defines
** the type for Lua floats.
@@ LUA_INT_TYPE defines the type for Lua integers.
@@ LUA_FLOAT_TYPE defines the type for Lua floats.
** Lua should work fine with any mix of these options (if supported
** by your C compiler). The usual configurations are 64-bit integers
** and 'double' (the default), 32-bit integers and 'float' (for
@@ -107,32 +105,47 @@
** compliant with C99, which may not have support for 'long long').
*/
/* predefined options for LUA_INT_TYPE */
#define LUA_INT_INT 1
#define LUA_INT_LONG 2
#define LUA_INT_LONGLONG 3
/* predefined options for LUA_FLOAT_TYPE */
#define LUA_FLOAT_FLOAT 1
#define LUA_FLOAT_DOUBLE 2
#define LUA_FLOAT_LONGDOUBLE 3
#if defined(LUA_32BITS) /* { */
/*
** 32-bit integers and 'float'
*/
#if LUAI_BITSINT >= 32 /* use 'int' if big enough */
#define LUA_INT_INT
#define LUA_INT_TYPE LUA_INT_INT
#else /* otherwise use 'long' */
#define LUA_INT_LONG
#define LUA_INT_TYPE LUA_INT_LONG
#endif
#define LUA_REAL_FLOAT
#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
#elif defined(LUA_C89_NUMBERS) /* }{ */
/*
** largest types available for C89 ('long' and 'double')
*/
#define LUA_INT_LONG
#define LUA_REAL_DOUBLE
#define LUA_INT_TYPE LUA_INT_LONG
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
#endif /* } */
#else /* }{ */
/*
** default configuration for 64-bit Lua ('long long' and 'double')
*/
#define LUA_INT_LONGLONG
#define LUA_REAL_DOUBLE
#if !defined(LUA_INT_TYPE)
#define LUA_INT_TYPE LUA_INT_LONGLONG
#endif
#endif /* } */
#if !defined(LUA_FLOAT_TYPE)
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
#endif
/* }================================================================== */
@@ -155,7 +168,7 @@
** non-conventional directories.
*/
#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#if defined(_WIN32) /* { */
#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.
@@ -300,20 +313,15 @@
*/
#define LUA_COMPAT_APIINTCASTS
/*
@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a
@@ a float mark ('.0').
** This macro is not on by default even in compatibility mode,
** because this is not really an incompatibility.
*/
/* #define LUA_COMPAT_FLOATSTRING */
#endif /* } */
#if defined(LUA_COMPAT_5_1) /* { */
/* Incompatibilities from 5.2 -> 5.3 */
#define LUA_COMPAT_MATHLIB
#define LUA_COMPAT_APIINTCASTS
/*
@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'.
** You can replace it with 'table.unpack'.
@@ -373,6 +381,15 @@
#endif /* } */
/*
@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a
@@ a float mark ('.0').
** This macro is not on by default even in compatibility mode,
** because this is not really an incompatibility.
*/
/* #define LUA_COMPAT_FLOATSTRING */
/* }================================================================== */
@@ -380,77 +397,31 @@
/*
** {==================================================================
** Configuration for Numbers.
** Change these definitions if no predefined LUA_REAL_* / LUA_INT_*
** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
** satisfy your needs.
** ===================================================================
*/
/*
@@ LUA_NUMBER is the floating-point type used by Lua.
**
@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
@@ over a floating number.
**
@@ l_mathlim(x) corrects limit name 'x' to the proper float type
** by prefixing it with one of FLT/DBL/LDBL.
@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
@@ LUA_NUMBER_FMT is the format for writing floats.
@@ lua_number2str converts a float to a string.
**
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
**
@@ l_floor takes the floor of a float.
@@ lua_str2number converts a decimal numeric string to a number.
*/
#if defined(LUA_REAL_FLOAT) /* { single float */
#define LUA_NUMBER float
#define LUAI_UACNUMBER double
#define LUA_NUMBER_FRMLEN ""
#define LUA_NUMBER_FMT "%.7g"
#define l_mathop(op) op##f
#define lua_str2number(s,p) strtof((s), (p))
#elif defined(LUA_REAL_LONGDOUBLE) /* }{ long double */
#define LUA_NUMBER long double
#define LUAI_UACNUMBER long double
#define LUA_NUMBER_FRMLEN "L"
#define LUA_NUMBER_FMT "%.19Lg"
#define l_mathop(op) op##l
#define lua_str2number(s,p) strtold((s), (p))
#elif defined(LUA_REAL_DOUBLE) /* }{ double */
#define LUA_NUMBER double
#define LUAI_UACNUMBER double
#define LUA_NUMBER_FRMLEN ""
#define LUA_NUMBER_FMT "%.14g"
#define l_mathop(op) op
#define lua_str2number(s,p) strtod((s), (p))
#else /* }{ */
#error "numeric real type not defined"
#endif /* } */
/* The following definitions are good for most cases here */
#define l_floor(x) (l_mathop(floor)(x))
#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n))
#define lua_number2str(s,sz,n) l_sprintf((s), sz, LUA_NUMBER_FMT, (n))
/*
@@ lua_numbertointeger converts a float number to an integer, or
@@ -466,45 +437,60 @@
(*(p) = (LUA_INTEGER)(n), 1))
/*
@@ The luai_num* macros define the primitive operations over numbers.
** They should work for any size of floating numbers.
*/
/* now the variable definitions */
/* the following operations need the math library */
#if defined(lobject_c) || defined(lvm_c)
#include <math.h>
#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
/* floor division (defined as 'floor(a/b)') */
#define luai_numidiv(L,a,b) ((void)L, l_mathop(floor)(luai_numdiv(L,a,b)))
#define LUA_NUMBER float
/*
** module: defined as 'a - floor(a/b)*b'; the previous definition gives
** NaN when 'b' is huge, but the result should be 'a'. 'fmod' gives the
** result of 'a - trunc(a/b)*b', and therefore must be corrected when
** 'trunc(a/b) ~= floor(a/b)'. That happens when the division has a
** non-integer negative result, which is equivalent to the test below
*/
#define luai_nummod(L,a,b,m) \
{ (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); }
#define l_mathlim(n) (FLT_##n)
/* exponentiation */
#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b))
#define LUAI_UACNUMBER double
#endif
#define LUA_NUMBER_FRMLEN ""
#define LUA_NUMBER_FMT "%.7g"
#define l_mathop(op) op##f
#define lua_str2number(s,p) strtof((s), (p))
#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */
#define LUA_NUMBER long double
#define l_mathlim(n) (LDBL_##n)
#define LUAI_UACNUMBER long double
#define LUA_NUMBER_FRMLEN "L"
#define LUA_NUMBER_FMT "%.19Lg"
#define l_mathop(op) op##l
#define lua_str2number(s,p) strtold((s), (p))
#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */
#define LUA_NUMBER double
#define l_mathlim(n) (DBL_##n)
#define LUAI_UACNUMBER double
#define LUA_NUMBER_FRMLEN ""
#define LUA_NUMBER_FMT "%.14g"
#define l_mathop(op) op
#define lua_str2number(s,p) strtod((s), (p))
#else /* }{ */
#error "numeric float type not defined"
#endif /* } */
/* these are quite standard operations */
#if defined(LUA_CORE)
#define luai_numadd(L,a,b) ((a)+(b))
#define luai_numsub(L,a,b) ((a)-(b))
#define luai_nummul(L,a,b) ((a)*(b))
#define luai_numdiv(L,a,b) ((a)/(b))
#define luai_numunm(L,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
/*
@@ -525,7 +511,7 @@
/* The following definitions are good for most cases here */
#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
#define lua_integer2str(s,n) sprintf((s), LUA_INTEGER_FMT, (n))
#define lua_integer2str(s,sz,n) l_sprintf((s), sz, LUA_INTEGER_FMT, (n))
#define LUAI_UACINT LUA_INTEGER
@@ -538,7 +524,7 @@
/* now the variable definitions */
#if defined(LUA_INT_INT) /* { int */
#if LUA_INT_TYPE == LUA_INT_INT /* { int */
#define LUA_INTEGER int
#define LUA_INTEGER_FRMLEN ""
@@ -546,7 +532,7 @@
#define LUA_MAXINTEGER INT_MAX
#define LUA_MININTEGER INT_MIN
#elif defined(LUA_INT_LONG) /* }{ long */
#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */
#define LUA_INTEGER long
#define LUA_INTEGER_FRMLEN "l"
@@ -554,8 +540,9 @@
#define LUA_MAXINTEGER LONG_MAX
#define LUA_MININTEGER LONG_MIN
#elif defined(LUA_INT_LONGLONG) /* }{ long long */
#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */
/* use presence of macro LLONG_MAX as proxy for C99 compliance */
#if defined(LLONG_MAX) /* { */
/* use ISO C99 stuff */
@@ -592,28 +579,40 @@
/*
** {==================================================================
** Dependencies with C99
** Dependencies with C99 and other C details
** ===================================================================
*/
/*
@@ lua_strx2number converts an hexadecimal numeric string to a number.
** In C99, 'strtod' does both conversions. Otherwise, you can
** leave 'lua_strx2number' undefined and Lua will provide its own
** implementation.
@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.
** (All uses in Lua have only one format item.)
*/
#if !defined(LUA_USE_C89)
#define lua_strx2number(s,p) lua_str2number(s,p)
#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i)
#else
#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i))
#endif
/*
@@ LUA_USE_AFORMAT allows '%a'/'%A' specifiers in 'string.format'
** Enable it if the C function 'printf' supports these specifiers.
** (C99 demands it and Windows also supports it.)
@@ lua_strx2number converts an hexadecimal numeric string to a number.
** In C99, 'strtod' does that conversion. Otherwise, you can
** leave 'lua_strx2number' undefined and Lua will provide its own
** implementation.
*/
#if !defined(LUA_USE_C89) || defined(LUA_USE_WINDOWS)
#define LUA_USE_AFORMAT
#if !defined(LUA_USE_C89)
#define lua_strx2number(s,p) lua_str2number(s,p)
#endif
/*
@@ lua_number2strx converts a float to an hexadecimal numeric string.
** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
** provide its own implementation.
*/
#if !defined(LUA_USE_C89)
#define lua_number2strx(L,b,sz,f,n) ((void)L, l_sprintf(b,sz,f,n))
#endif
@@ -642,12 +641,50 @@
#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
__STDC_VERSION__ >= 199901L
#include <stdint.h>
#if defined (INTPTR_MAX) /* even in C99 this type is optional */
#if defined(INTPTR_MAX) /* even in C99 this type is optional */
#undef LUA_KCONTEXT
#define LUA_KCONTEXT intptr_t
#endif
#endif
/*
@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point).
** Change that if you do not want to use C locales. (Code using this
** macro must include header 'locale.h'.)
*/
#if !defined(lua_getlocaledecpoint)
#define lua_getlocaledecpoint() (localeconv()->decimal_point[0])
#endif
/* }================================================================== */
/*
** {==================================================================
** Language Variations
** =====================================================================
*/
/*
@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some
** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from
** numbers to strings. Define LUA_NOCVTS2N to turn off automatic
** coercion from strings to numbers.
*/
/* #define LUA_NOCVTN2S */
/* #define LUA_NOCVTS2N */
/*
@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
** Define it as a help when debugging C code.
*/
#if defined(LUA_USE_APICHECK)
#include <assert.h>
#define luai_apicheck(l,e) assert(e)
#endif
/* }================================================================== */
@@ -671,9 +708,6 @@
#define LUAI_MAXSTACK 15000
#endif
/* reserve some space for error handling */
#define LUAI_FIRSTPSEUDOIDX (-LUAI_MAXSTACK - 1000)
/*
@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
@@ -691,20 +725,18 @@
#define LUA_IDSIZE 60
/*
@@ LUAI_MAXSHORTLEN is the maximum length for short strings, that is,
** strings that are internalized. (Cannot be smaller than reserved words
** or tags for metamethods, as these strings must be internalized;
** #("function") = 8, #("__newindex") = 10.)
*/
#define LUAI_MAXSHORTLEN 40
/*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
** CHANGE it if it uses too much C-stack space.
** CHANGE it if it uses too much C-stack space. (For long double,
** 'string.format("%.99f", 1e4932)' needs ~5030 bytes, so a
** smaller buffer would force a memory allocation for each call to
** 'string.format'.)
*/
#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
#if defined(LUA_FLOAT_LONGDOUBLE)
#define LUAL_BUFFERSIZE 8192
#else
#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
#endif
/* }================================================================== */

View File

@@ -1,5 +1,5 @@
/*
** $Id: lundump.c,v 2.41 2014/11/02 19:19:04 roberto Exp $
** $Id: lundump.c,v 2.44 2015/11/02 16:09:30 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -32,7 +32,6 @@
typedef struct {
lua_State *L;
ZIO *Z;
Mbuffer *b;
const char *name;
} LoadState;
@@ -92,10 +91,15 @@ static TString *LoadString (LoadState *S) {
LoadVar(S, size);
if (size == 0)
return NULL;
else {
char *s = luaZ_openspace(S->L, S->b, --size);
LoadVector(S, s, size);
return luaS_newlstr(S->L, s, size);
else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */
char buff[LUAI_MAXSHORTLEN];
LoadVector(S, buff, size);
return luaS_newlstr(S->L, buff, size);
}
else { /* long string */
TString *ts = luaS_createlngstrobj(S->L, size);
LoadVector(S, getstr(ts), size); /* load directly in final place */
return ts;
}
}
@@ -252,8 +256,7 @@ static void checkHeader (LoadState *S) {
/*
** load precompiled chunk
*/
LClosure *luaU_undump(lua_State *L, ZIO *Z, Mbuffer *buff,
const char *name) {
LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
LoadState S;
LClosure *cl;
if (*name == '@' || *name == '=')
@@ -264,14 +267,13 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, Mbuffer *buff,
S.name = name;
S.L = L;
S.Z = Z;
S.b = buff;
checkHeader(&S);
cl = luaF_newLclosure(L, LoadByte(&S));
setclLvalue(L, L->top, cl);
incr_top(L);
luaD_inctop(L);
cl->p = luaF_newproto(L, NULL);
LoadFunction(&S, cl->p, NULL);
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
lua_assert(cl->nupvalues == cl->p->sp->sizeupvalues);
luai_verifycode(L, buff, cl->p);
return cl;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lundump.h,v 1.44 2014/06/19 18:27:20 roberto Exp $
** $Id: lundump.h,v 1.45 2015/09/08 15:41:05 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -23,8 +23,7 @@
#define LUAC_FORMAT 0 /* this is the official format */
/* load one chunk; from lundump.c */
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff,
const char* name);
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name);
/* dump one chunk; from ldump.c */
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,

View File

@@ -1,5 +1,5 @@
/*
** $Id: lutf8lib.c,v 1.13 2014/11/02 19:19:04 roberto Exp $
** $Id: lutf8lib.c,v 1.15 2015/03/28 19:16:55 roberto Exp $
** Standard library for UTF-8 manipulation
** See Copyright Notice in lua.h
*/
@@ -11,6 +11,7 @@
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -37,7 +38,7 @@ static lua_Integer u_posrelat (lua_Integer pos, size_t len) {
** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid.
*/
static const char *utf8_decode (const char *o, int *val) {
static unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF};
static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF};
const unsigned char *s = (const unsigned char *)o;
unsigned int c = s[0];
unsigned int res = 0; /* final result */
@@ -106,9 +107,9 @@ static int codepoint (lua_State *L) {
luaL_argcheck(L, posi >= 1, 2, "out of range");
luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range");
if (posi > pose) return 0; /* empty interval; return no values */
n = (int)(pose - posi + 1);
if (posi + n <= pose) /* (lua_Integer -> int) overflow? */
if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */
return luaL_error(L, "string slice too long");
n = (int)(pose - posi) + 1;
luaL_checkstack(L, n, "string slice too long");
n = 0;
se = s + pose;
@@ -234,7 +235,7 @@ static int iter_codes (lua_State *L) {
#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*"
static struct luaL_Reg funcs[] = {
static const luaL_Reg funcs[] = {
{"offset", byteoffset},
{"codepoint", codepoint},
{"char", utfchar},
@@ -248,7 +249,7 @@ static struct luaL_Reg funcs[] = {
LUAMOD_API int luaopen_utf8 (lua_State *L) {
luaL_newlib(L, funcs);
lua_pushliteral(L, UTF8PATT);
lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1);
lua_setfield(L, -2, "charpattern");
return 1;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lvm.c,v 2.232 2014/12/27 20:30:38 roberto Exp $
** $Id: lvm.c,v 2.268 2016/02/05 19:59:14 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -9,8 +9,9 @@
#include "lprefix.h"
#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -30,23 +31,42 @@
#include "lvm.h"
/*
** You can define LUA_FLOORN2I if you want to convert floats to integers
** by flooring them (instead of raising an error if they are not
** integral values)
*/
#if !defined(LUA_FLOORN2I)
#define LUA_FLOORN2I 0
#endif
/* limit for table tag-method chains (to avoid loops) */
#define MAXTAGLOOP 2000
/*
** 'l_intfitsf' checks whether a given integer can be converted to a
** float without rounding. Used in comparisons. Left undefined if
** all integers fit in a float precisely.
*/
#if !defined(l_intfitsf)
/* number of bits in the mantissa of a float */
#define NBM (l_mathlim(MANT_DIG))
/*
** Check whether some integers may not fit in a float, that is, whether
** (maxinteger >> NBM) > 0 (that implies (1 << NBM) <= maxinteger).
** (The shifts are done in parts to avoid shifting by more than the size
** of an integer. In a worst case, NBM == 113 for long double and
** sizeof(integer) == 32.)
*/
#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \
>> (NBM - (3 * (NBM / 4)))) > 0
#define l_intfitsf(i) \
(-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM))
#endif
#endif
/* Add by skynet */
lua_State * skynet_sig_L = NULL;
LUA_API void
LUA_API void
lua_checksig_(lua_State *L) {
if (skynet_sig_L == G(L)->mainthread) {
skynet_sig_L = NULL;
@@ -55,24 +75,6 @@ lua_checksig_(lua_State *L) {
}
}
/*
** Similar to 'tonumber', but does not attempt to convert strings and
** ensure correct precision (no extra bits). Used in comparisons.
*/
static int tofloat (const TValue *obj, lua_Number *n) {
if (ttisfloat(obj)) *n = fltvalue(obj);
else if (ttisinteger(obj)) {
volatile lua_Number x = cast_num(ivalue(obj)); /* avoid extra precision */
*n = x;
}
else {
*n = 0; /* to avoid warnings */
return 0;
}
return 1;
}
/*
** Try to convert a value to a float. The float case is already handled
** by the macro 'tonumber'.
@@ -84,7 +86,7 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
return 1;
}
else if (cvt2num(obj) && /* string convertible to number? */
luaO_str2num(svalue(obj), &v) == tsvalue(obj)->len + 1) {
luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
*n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */
return 1;
}
@@ -99,7 +101,7 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
** mode == 1: takes the floor of the number
** mode == 2: takes the ceil of the number
*/
static int tointeger_aux (const TValue *obj, lua_Integer *p, int mode) {
int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
TValue v;
again:
if (ttisfloat(obj)) {
@@ -117,7 +119,7 @@ static int tointeger_aux (const TValue *obj, lua_Integer *p, int mode) {
return 1;
}
else if (cvt2num(obj) &&
luaO_str2num(svalue(obj), &v) == tsvalue(obj)->len + 1) {
luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
obj = &v;
goto again; /* convert result from 'luaO_str2num' to an integer */
}
@@ -125,14 +127,6 @@ static int tointeger_aux (const TValue *obj, lua_Integer *p, int mode) {
}
/*
** try to convert a value to an integer
*/
int luaV_tointeger_ (const TValue *obj, lua_Integer *p) {
return tointeger_aux(obj, p, LUA_FLOORN2I);
}
/*
** Try to convert a 'for' limit to an integer, preserving the
** semantics of the loop.
@@ -151,11 +145,11 @@ int luaV_tointeger_ (const TValue *obj, lua_Integer *p) {
static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
int *stopnow) {
*stopnow = 0; /* usually, let loops run */
if (!tointeger_aux(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */
if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */
lua_Number n; /* try to convert to float */
if (!tonumber(obj, &n)) /* cannot convert to float? */
return 0; /* not a number */
if (n > 0) { /* if true, float is larger than max integer */
if (luai_numlt(0, n)) { /* if true, float is larger than max integer */
*p = LUA_MAXINTEGER;
if (step < 0) *stopnow = 1;
}
@@ -169,75 +163,88 @@ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
/*
** Main function for table access (invoking metamethods if needed).
** Compute 'val = t[key]'
** Finish the table access 'val = t[key]'.
** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to
** t[k] entry (which must be nil).
*/
void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
const TValue *slot) {
int loop; /* counter to avoid infinite loops */
const TValue *tm; /* metamethod */
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 not nil? */
(tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
setobj2s(L, val, res); /* result is the raw get */
if (slot == NULL) { /* 't' is not a table? */
lua_assert(!ttistable(t));
tm = luaT_gettmbyobj(L, t, TM_INDEX);
if (ttisnil(tm))
luaG_typeerror(L, t, "index"); /* no metamethod */
/* else will try the metamethod */
}
else { /* 't' is a table */
lua_assert(ttisnil(slot));
tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */
if (tm == NULL) { /* no metamethod? */
setnilvalue(val); /* result is nil */
return;
}
/* else will try metamethod */
/* else will try the metamethod */
}
else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
luaG_typeerror(L, t, "index"); /* no metamethod */
if (ttisfunction(tm)) { /* metamethod is a function */
luaT_callTM(L, tm, t, key, val, 1);
if (ttisfunction(tm)) { /* is metamethod a function? */
luaT_callTM(L, tm, t, key, val, 1); /* call it */
return;
}
t = tm; /* else repeat access over 'tm' */
t = tm; /* else try to access 'tm[key]' */
if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */
setobj2s(L, val, slot); /* done */
return;
}
/* else repeat (tail call 'luaV_finishget') */
}
luaG_runerror(L, "gettable chain too long; possible loop");
luaG_runerror(L, "'__index' chain too long; possible loop");
}
/*
** Main function for table assignment (invoking metamethods if needed).
** Compute 't[key] = val'
** Finish a table assignment 't[key] = val'.
** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points
** to the entry 't[key]', or to 'luaO_nilobject' if there is no such
** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset'
** would have done the job.)
*/
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *slot) {
int loop; /* counter to avoid infinite loops */
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (ttistable(t)) { /* 't' is a table? */
Table *h = hvalue(t);
TValue *oldval = cast(TValue *, luaH_get(h, key));
/* if previous value is not nil, there must be a previous entry
in the table; a metamethod has no relevance */
if (!ttisnil(oldval) ||
/* previous value is nil; must check the metamethod */
((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL &&
/* no metamethod; is there a previous entry in the table? */
(oldval != luaO_nilobject ||
/* no previous entry; must create one. (The next test is
always true; we only need the assignment.) */
(oldval = luaH_newkey(L, h, key), 1)))) {
const TValue *tm; /* '__newindex' metamethod */
if (slot != NULL) { /* is 't' a table? */
Table *h = hvalue(t); /* save 't' table */
lua_assert(ttisnil(slot)); /* old value must be nil */
tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
if (tm == NULL) { /* no metamethod? */
if (slot == luaO_nilobject) /* no previous entry? */
slot = luaH_newkey(L, h, key); /* create one */
/* no metamethod and (now) there is an entry with given key */
setobj2t(L, oldval, val); /* assign new value to that entry */
setobj2t(L, cast(TValue *, slot), val); /* set its new value */
invalidateTMcache(h);
luaC_barrierback(L, h, val);
return;
}
/* else will try the metamethod */
}
else /* not a table; check metamethod */
else { /* not a table; check metamethod */
if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
luaG_typeerror(L, t, "index");
}
/* try the metamethod */
if (ttisfunction(tm)) {
luaT_callTM(L, tm, t, key, val, 0);
return;
}
t = tm; /* else repeat assignment over 'tm' */
if (luaV_fastset(L, t, key, slot, luaH_get, val))
return; /* done */
/* else loop */
}
luaG_runerror(L, "settable chain too long; possible loop");
luaG_runerror(L, "'__newindex' chain too long; possible loop");
}
@@ -250,9 +257,9 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
*/
static int l_strcmp (const TString *ls, const TString *rs) {
const char *l = getstr(ls);
size_t ll = ls->len;
size_t ll = tsslen(ls);
const char *r = getstr(rs);
size_t lr = rs->len;
size_t lr = tsslen(rs);
for (;;) { /* for each segment */
int temp = strcoll(l, r);
if (temp != 0) /* not equal? */
@@ -271,16 +278,103 @@ static int l_strcmp (const TString *ls, const TString *rs) {
}
/*
** Check whether integer 'i' is less than float 'f'. If 'i' has an
** exact representation as a float ('l_intfitsf'), compare numbers as
** floats. Otherwise, if 'f' is outside the range for integers, result
** is trivial. Otherwise, compare them as integers. (When 'i' has no
** float representation, either 'f' is "far away" from 'i' or 'f' has
** no precision left for a fractional part; either way, how 'f' is
** truncated is irrelevant.) When 'f' is NaN, comparisons must result
** in false.
*/
static int LTintfloat (lua_Integer i, lua_Number f) {
#if defined(l_intfitsf)
if (!l_intfitsf(i)) {
if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */
return 1; /* f >= maxint + 1 > i */
else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */
return (i < cast(lua_Integer, f)); /* compare them as integers */
else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */
return 0;
}
#endif
return luai_numlt(cast_num(i), f); /* compare them as floats */
}
/*
** Check whether integer 'i' is less than or equal to float 'f'.
** See comments on previous function.
*/
static int LEintfloat (lua_Integer i, lua_Number f) {
#if defined(l_intfitsf)
if (!l_intfitsf(i)) {
if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */
return 1; /* f >= maxint + 1 > i */
else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */
return (i <= cast(lua_Integer, f)); /* compare them as integers */
else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */
return 0;
}
#endif
return luai_numle(cast_num(i), f); /* compare them as floats */
}
/*
** Return 'l < r', for numbers.
*/
static int LTnum (const TValue *l, const TValue *r) {
if (ttisinteger(l)) {
lua_Integer li = ivalue(l);
if (ttisinteger(r))
return li < ivalue(r); /* both are integers */
else /* 'l' is int and 'r' is float */
return LTintfloat(li, fltvalue(r)); /* l < r ? */
}
else {
lua_Number lf = fltvalue(l); /* 'l' must be float */
if (ttisfloat(r))
return luai_numlt(lf, fltvalue(r)); /* both are float */
else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */
return 0; /* NaN < i is always false */
else /* without NaN, (l < r) <--> not(r <= l) */
return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */
}
}
/*
** Return 'l <= r', for numbers.
*/
static int LEnum (const TValue *l, const TValue *r) {
if (ttisinteger(l)) {
lua_Integer li = ivalue(l);
if (ttisinteger(r))
return li <= ivalue(r); /* both are integers */
else /* 'l' is int and 'r' is float */
return LEintfloat(li, fltvalue(r)); /* l <= r ? */
}
else {
lua_Number lf = fltvalue(l); /* 'l' must be float */
if (ttisfloat(r))
return luai_numle(lf, fltvalue(r)); /* both are float */
else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */
return 0; /* NaN <= i is always false */
else /* without NaN, (l <= r) <--> not(r < l) */
return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */
}
}
/*
** Main operation less than; return 'l < r'.
*/
int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
int res;
lua_Number nl, nr;
if (ttisinteger(l) && ttisinteger(r)) /* both operands are integers? */
return (ivalue(l) < ivalue(r));
else if (tofloat(l, &nl) && tofloat(r, &nr)) /* both are numbers? */
return luai_numlt(nl, nr);
if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */
return LTnum(l, r);
else if (ttisstring(l) && ttisstring(r)) /* both are strings? */
return l_strcmp(tsvalue(l), tsvalue(r)) < 0;
else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */
@@ -290,18 +384,20 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
/*
** Main operation less than or equal to; return 'l <= r'.
** Main operation less than or equal to; return 'l <= r'. If it needs
** a metamethod and there is no '__le', try '__lt', based on
** l <= r iff !(r < l) (assuming a total order). If the metamethod
** yields during this substitution, the continuation has to know
** about it (to negate the result of r<l); bit CIST_LEQ in the call
** status keeps that information.
*/
int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
int res;
lua_Number nl, nr;
if (ttisinteger(l) && ttisinteger(r)) /* both operands are integers? */
return (ivalue(l) <= ivalue(r));
else if (tofloat(l, &nl) && tofloat(r, &nr)) /* both are numbers? */
return luai_numle(nl, nr);
if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */
return LEnum(l, r);
else if (ttisstring(l) && ttisstring(r)) /* both are strings? */
return l_strcmp(tsvalue(l), tsvalue(r)) <= 0;
else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* first try 'le' */
else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* try 'le' */
return res;
else { /* try 'lt': */
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
@@ -314,9 +410,8 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
}
/*
** Main operation for equality of Lua values; return 't1 == t2'.
** Main operation for equality of Lua values; return 't1 == t2'.
** L == NULL means raw equality (no metamethods)
*/
int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
@@ -325,10 +420,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER)
return 0; /* only numbers can be equal with different variants */
else { /* two numbers with different variants */
lua_Number n1, n2; /* compare them as floats */
lua_assert(ttisnumber(t1) && ttisnumber(t2));
cast_void(tofloat(t1, &n1)); cast_void(tofloat(t2, &n2));
return luai_numeq(n1, n2);
lua_Integer i1, i2; /* compare them as integers */
return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2);
}
}
/* values have same type and same variant */
@@ -371,6 +464,19 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
#define tostring(L,o) \
(ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1)))
#define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0)
/* copy strings in stack from top - n up to top - 1 to buffer */
static void copy2buff (StkId top, int n, char *buff) {
size_t tl = 0; /* size already copied */
do {
size_t l = vslen(top - n); /* length of string being copied */
memcpy(buff + tl, svalue(top - n), l * sizeof(char));
tl += l;
} while (--n > 0);
}
/*
** Main operation for concatenation: concat 'total' values in the stack,
** from 'L->top - total' up to 'L->top - 1'.
@@ -382,32 +488,32 @@ void luaV_concat (lua_State *L, int total) {
int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1))
luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT);
else if (tsvalue(top-1)->len == 0) /* second operand is empty? */
else if (isemptystr(top - 1)) /* second operand is empty? */
cast_void(tostring(L, top - 2)); /* result is first operand */
else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) {
else if (isemptystr(top - 2)) { /* first operand is an empty string? */
setobjs2s(L, top - 2, top - 1); /* result is second op. */
}
else {
/* at least two non-empty string values; get as many as possible */
size_t tl = tsvalue(top-1)->len;
char *buffer;
int i;
/* collect total length */
for (i = 1; i < total && tostring(L, top-i-1); i++) {
size_t l = tsvalue(top-i-1)->len;
size_t tl = vslen(top - 1);
TString *ts;
/* collect total length and number of strings */
for (n = 1; n < total && tostring(L, top - n - 1); n++) {
size_t l = vslen(top - n - 1);
if (l >= (MAX_SIZE/sizeof(char)) - tl)
luaG_runerror(L, "string length overflow");
tl += l;
}
buffer = luaZ_openspace(L, &G(L)->buff, tl);
tl = 0;
n = i;
do { /* copy all strings to buffer */
size_t l = tsvalue(top-i)->len;
memcpy(buffer+tl, svalue(top-i), l * sizeof(char));
tl += l;
} while (--i > 0);
setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); /* create result */
if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
char buff[LUAI_MAXSHORTLEN];
copy2buff(top, n, buff); /* copy strings to buffer */
ts = luaS_newlstr(L, buff, tl);
}
else { /* long string; copy strings directly to final result */
ts = luaS_createlngstrobj(L, tl);
copy2buff(top, n, getstr(ts));
}
setsvalue2s(L, top - n, ts); /* create result */
}
total -= n-1; /* got 'n' strings to create 1 new */
L->top -= n-1; /* popped 'n' strings and pushed one */
@@ -420,7 +526,7 @@ void luaV_concat (lua_State *L, int total) {
*/
void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
const TValue *tm;
switch (ttnov(rb)) {
switch (ttype(rb)) {
case LUA_TTABLE: {
Table *h = hvalue(rb);
tm = fasttm(L, h->metatable, TM_LEN);
@@ -428,8 +534,12 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
setivalue(ra, luaH_getn(h)); /* else primitive len */
return;
}
case LUA_TSTRING: {
setivalue(ra, tsvalue(rb)->len);
case LUA_TSHRSTR: {
setivalue(ra, tsvalue(rb)->shrlen);
return;
}
case LUA_TLNGSTR: {
setivalue(ra, tsvalue(rb)->u.lnglen);
return;
}
default: { /* try metamethod */
@@ -465,7 +575,7 @@ lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) {
/*
** Integer modulus; return 'm % n'. (Assume that C '%' with
** Integer modulus; return 'm % n'. (Assume that C '%' with
** negative operands follows C99 behavior. See previous comment
** about luaV_div.)
*/
@@ -624,27 +734,20 @@ void luaV_finishOp (lua_State *L) {
** some macros for common tasks in 'luaV_execute'
*/
#if !defined luai_runtimecheck
#define luai_runtimecheck(L, c) /* void */
#endif
#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) \
(k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++)))
/* execute a jump instruction */
#define dojump(ci,i,e) \
{ int a = GETARG_A(i); \
if (a > 0) luaF_close(L, ci->u.l.base + a - 1); \
if (a != 0) luaF_close(L, ci->u.l.base + a - 1); \
ci->u.l.savedpc += GETARG_sBx(i) + e; }
/* for test instructions, execute the jump instruction that follows it */
@@ -654,38 +757,58 @@ void luaV_finishOp (lua_State *L) {
#define Protect(x) { {x;}; base = ci->u.l.base; }
#define checkGC(L,c) \
Protect( luaC_condGC(L,{L->top = (c); /* limit of live values */ \
luaC_step(L); \
L->top = ci->top;}) /* restore top */ \
luai_threadyield(L); )
{ luaC_condGC(L, L->top = (c), /* limit of live values */ \
Protect(L->top = ci->top)); /* restore top */ \
luai_threadyield(L); }
/* fetch an instruction and prepare its execution */
#define vmfetch() { \
i = *(ci->u.l.savedpc++); \
if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \
Protect(luaG_traceexec(L)); \
ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
lua_assert(base == ci->u.l.base); \
lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \
}
#define vmdispatch(o) switch(o)
#define vmcase(l) case l:
#define vmbreak break
/*
** copy of 'luaV_gettable', but protecting the call to potential
** metamethod (which can reallocate the stack)
*/
#define gettableProtected(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else Protect(luaV_finishget(L,t,k,v,slot)); }
/* same for 'luaV_settable' */
#define settableProtected(L,t,k,v) { const TValue *slot; \
if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
Protect(luaV_finishset(L,t,k,v,slot)); }
void luaV_execute (lua_State *L) {
CallInfo *ci = L->ci;
LClosure *cl;
TValue *k;
StkId base;
ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */
newframe: /* reentry point when frame changes (call/return) */
lua_assert(ci == L->ci);
cl = clLvalue(ci->func);
k = cl->p->k;
base = ci->u.l.base;
cl = clLvalue(ci->func); /* local reference to function's closure */
k = cl->p->k; /* local reference to function's constant table */
base = ci->u.l.base; /* local copy of function's base */
/* main loop of interpreter */
for (;;) {
Instruction i = *(ci->u.l.savedpc++);
Instruction i;
StkId ra;
if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
(--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
Protect(luaG_traceexec(L));
}
/* WARNING: several calls may realloc the stack and invalidate 'ra' */
ra = RA(i);
lua_assert(base == ci->u.l.base);
lua_assert(base <= L->top && L->top < L->stack + L->stacksize);
vmfetch();
vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) {
setobjs2s(L, ra, RB(i));
@@ -721,17 +844,22 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_GETTABUP) {
int b = GETARG_B(i);
Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra));
TValue *upval = cl->upvals[GETARG_B(i)]->v;
TValue *rc = RKC(i);
gettableProtected(L, upval, rc, ra);
vmbreak;
}
vmcase(OP_GETTABLE) {
Protect(luaV_gettable(L, RB(i), RKC(i), ra));
StkId rb = RB(i);
TValue *rc = RKC(i);
gettableProtected(L, rb, rc, ra);
vmbreak;
}
vmcase(OP_SETTABUP) {
int a = GETARG_A(i);
Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i)));
TValue *upval = cl->upvals[GETARG_A(i)]->v;
TValue *rb = RKB(i);
TValue *rc = RKC(i);
settableProtected(L, upval, rb, rc);
vmbreak;
}
vmcase(OP_SETUPVAL) {
@@ -741,7 +869,9 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_SETTABLE) {
Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
TValue *rb = RKB(i);
TValue *rc = RKC(i);
settableProtected(L, ra, rb, rc);
vmbreak;
}
vmcase(OP_NEWTABLE) {
@@ -755,12 +885,18 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_SELF) {
const TValue *aux;
StkId rb = RB(i);
setobjs2s(L, ra+1, rb);
Protect(luaV_gettable(L, rb, RKC(i), ra));
TValue *rc = RKC(i);
TString *key = tsvalue(rc); /* key must be a string */
setobjs2s(L, ra + 1, rb);
if (luaV_fastget(L, rb, key, aux, luaH_getstr)) {
setobj2s(L, ra, aux);
}
else Protect(luaV_finishget(L, rb, rc, ra, aux));
vmbreak;
}
vmcase(OP_ADD) {
vmcase(OP_ADD) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
lua_Number nb; lua_Number nc;
@@ -944,8 +1080,8 @@ void luaV_execute (lua_State *L) {
StkId rb;
L->top = base + c + 1; /* mark the end of concat operands */
Protect(luaV_concat(L, c - b + 1));
ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */
rb = b + base;
ra = RA(i); /* 'luaV_concat' may invoke TMs and move the stack */
rb = base + b;
setobjs2s(L, ra, rb);
checkGC(L, (ra >= rb ? ra + 1 : rb));
L->top = ci->top; /* restore top */
@@ -960,7 +1096,7 @@ void luaV_execute (lua_State *L) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
Protect(
if (cast_int(luaV_equalobj(L, rb, rc)) != GETARG_A(i))
if (luaV_equalobj(L, rb, rc) != GETARG_A(i))
ci->u.l.savedpc++;
else
donextjump(ci);
@@ -1008,12 +1144,12 @@ void luaV_execute (lua_State *L) {
lua_checksig(L);
if (b != 0) L->top = ra+b; /* else previous instruction set top */
if (luaD_precall(L, ra, nresults)) { /* C function? */
if (nresults >= 0) L->top = ci->top; /* adjust results */
base = ci->u.l.base;
if (nresults >= 0)
L->top = ci->top; /* adjust results */
Protect((void)0); /* update 'base' */
}
else { /* Lua function */
ci = L->ci;
ci->callstatus |= CIST_REENTRY;
goto newframe; /* restart luaV_execute over new Lua function */
}
vmbreak;
@@ -1023,8 +1159,9 @@ void luaV_execute (lua_State *L) {
lua_checksig(L);
if (b != 0) L->top = ra+b; /* else previous instruction set top */
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
if (luaD_precall(L, ra, LUA_MULTRET)) /* C function? */
base = ci->u.l.base;
if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */
Protect((void)0); /* update 'base' */
}
else {
/* tail call: put called frame (n) in place of caller one (o) */
CallInfo *nci = L->ci; /* called frame */
@@ -1044,17 +1181,16 @@ void luaV_execute (lua_State *L) {
oci->u.l.savedpc = nci->u.l.savedpc;
oci->callstatus |= CIST_TAIL; /* function was tail called */
ci = L->ci = oci; /* remove new frame */
lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize);
lua_assert(L->top == oci->u.l.base + getproto(ofunc)->sp->maxstacksize);
goto newframe; /* restart luaV_execute over new Lua function */
}
vmbreak;
}
vmcase(OP_RETURN) {
int b = GETARG_B(i);
if (b != 0) L->top = ra+b-1;
if (cl->p->sp->sizep > 0) luaF_close(L, base);
b = luaD_poscall(L, ra);
if (!(ci->callstatus & CIST_REENTRY)) /* 'ci' still the called one */
b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */
return; /* external invocation: return */
else { /* invocation via reentry: continue execution */
ci = L->ci;
@@ -1067,11 +1203,11 @@ void luaV_execute (lua_State *L) {
vmcase(OP_FORLOOP) {
if (ttisinteger(ra)) { /* integer loop? */
lua_Integer step = ivalue(ra + 2);
lua_Integer idx = ivalue(ra) + step; /* increment index */
lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */
lua_Integer limit = ivalue(ra + 1);
if ((0 < step) ? (idx <= limit) : (limit <= idx)) {
ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
setivalue(ra, idx); /* update internal index... */
chgivalue(ra, idx); /* update internal index... */
setivalue(ra + 3, idx); /* ...and external index */
}
}
@@ -1082,7 +1218,7 @@ void luaV_execute (lua_State *L) {
if (luai_numlt(0, step) ? luai_numle(idx, limit)
: luai_numle(limit, idx)) {
ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
setfltvalue(ra, idx); /* update internal index... */
chgfltvalue(ra, idx); /* update internal index... */
setfltvalue(ra + 3, idx); /* ...and external index */
}
}
@@ -1099,7 +1235,7 @@ void luaV_execute (lua_State *L) {
/* all values are integer */
lua_Integer initv = (stopnow ? 0 : ivalue(init));
setivalue(plimit, ilimit);
setivalue(init, initv - ivalue(pstep));
setivalue(init, intop(-, initv, ivalue(pstep)));
}
else { /* try making all values floats */
lua_Number ninit; lua_Number nlimit; lua_Number nstep;
@@ -1122,7 +1258,7 @@ void luaV_execute (lua_State *L) {
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), 1));
Protect(luaD_call(L, cb, GETARG_C(i)));
L->top = ci->top;
i = *(ci->u.l.savedpc++); /* go to next instruction */
ra = RA(i);
@@ -1148,11 +1284,10 @@ void luaV_execute (lua_State *L) {
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);
c = GETARG_Ax(*ci->u.l.savedpc++);
}
luai_runtimecheck(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-allocate it at once */
luaH_resizearray(L, h, last); /* preallocate it at once */
for (; n > 0; n--) {
TValue *val = ra+n;
luaH_setint(L, h, last--, val);
@@ -1172,23 +1307,21 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_VARARG) {
int b = GETARG_B(i) - 1;
int b = GETARG_B(i) - 1; /* required results */
int j;
int n = cast_int(base - ci->func) - cl->p->sp->numparams - 1;
if (n < 0) /* less arguments than parameters? */
n = 0; /* no vararg arguments */
if (b < 0) { /* B == 0? */
b = n; /* get all var. arguments */
Protect(luaD_checkstack(L, n));
ra = RA(i); /* previous call may change the stack */
L->top = ra + n;
}
for (j = 0; j < b; j++) {
if (j < n) {
setobjs2s(L, ra + j, base - n + j);
}
else {
setnilvalue(ra + j);
}
}
for (j = 0; j < b && j < n; j++)
setobjs2s(L, ra + j, base - n + j);
for (; j < b; j++) /* complete required results with nil */
setnilvalue(ra + j);
vmbreak;
}
vmcase(OP_EXTRAARG) {

View File

@@ -1,5 +1,5 @@
/*
** $Id: lvm.h,v 2.34 2014/08/01 17:24:02 roberto Exp $
** $Id: lvm.h,v 2.40 2016/01/05 16:07:21 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -27,26 +27,81 @@
#endif
/*
** You can define LUA_FLOORN2I if you want to convert floats to integers
** by flooring them (instead of raising an error if they are not
** integral values)
*/
#if !defined(LUA_FLOORN2I)
#define LUA_FLOORN2I 0
#endif
#define tonumber(o,n) \
(ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
#define tointeger(o,i) \
(ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger_(o,i))
(ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))
#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2)
/*
** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise,
** return 0 (meaning it will have to check metamethod) with 'slot'
** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).
** 'f' is the raw get function to use.
*/
#define luaV_fastget(L,t,k,slot,f) \
(!ttistable(t) \
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
: (slot = f(hvalue(t), k), /* else, do raw access */ \
!ttisnil(slot))) /* result not nil? */
/*
** standard implementation for 'gettable'
*/
#define luaV_gettable(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else luaV_finishget(L,t,k,v,slot); }
/*
** Fast track for set table. If 't' is a table and 't[k]' is not nil,
** call GC barrier, do a raw 't[k]=v', and return true; otherwise,
** return false with 'slot' equal to NULL (if 't' is not a table) or
** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro
** returns true, there is no need to 'invalidateTMcache', because the
** call is not creating a new entry.
*/
#define luaV_fastset(L,t,k,slot,f,v) \
(!ttistable(t) \
? (slot = NULL, 0) \
: (slot = f(hvalue(t), k), \
ttisnil(slot) ? 0 \
: (luaC_barrierback(L, hvalue(t), v), \
setobj2t(L, cast(TValue *,slot), v), \
1)))
#define luaV_settable(L,t,k,v) { const TValue *slot; \
if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
luaV_finishset(L,t,k,v,slot); }
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
LUAI_FUNC int luaV_tointeger_ (const TValue *obj, lua_Integer *p);
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 int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);
LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishOp (lua_State *L);
LUAI_FUNC void luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lzio.c,v 1.36 2014/11/02 19:19:04 roberto Exp $
** $Id: lzio.c,v 1.37 2015/09/08 15:41:05 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/
@@ -66,13 +66,3 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) {
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;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lzio.h,v 1.30 2014/12/19 17:26:14 roberto Exp $
** $Id: lzio.h,v 1.31 2015/09/08 15:41:05 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/
@@ -44,7 +44,6 @@ typedef struct Mbuffer {
#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 */

View File

@@ -1,3 +1,106 @@
v1.0.0-rc4 (2016-6-13)
-----------
* Update lua to 5.3.3
* Update jemalloc to 4.2.1
* Add debug console command ping
* Lua bson support __pairs
* Add mongo.createIndexes and fix bug in old mongo.createIndex
* Handle signal HUP to reopen log file (for logrotate)
v1.0.0-rc3 (2016-5-9)
-----------
* Update jemalloc 4.1.1
* Update lua 5.3.3 rc1
* Update sproto to support encoding empty table
* Make skynet.init stable (keep order)
* skynet.getenv can return empty string
* Add lua VM memory warning
* lua VM support memory limit
* skynet.pcall suport varargs
* Bugfix : Global name query
* Bugfix : snax.queryglobal
v1.0.0-rc2 (2016-3-7)
-----------
* Fix a bug in lua 5.3.2
* Update sproto (fix bugs and add ud for package)
* Fix a bug in http
* Fix a bug in harbor
* Fix a bug in socket channel
* Enhance remote debugger
v1.0.0-rc (2015-12-28)
-----------
* Update to lua 5.3.2
* Add skynet.coroutine lib
* Add new debug api to show c memory used
* httpc can use async dns query
* Redis driver support pipeline
* socket.send support string table, and rewrite redis driver
* socket.shutdown would abandon unsend buffer
* Improve some sproto api
* c memory doesn't count the memory allocated by lua vm
* some other bugfix (In multicast, socketchannel, etc)
v1.0.0-beta (2015-11-10)
-----------
* Improve and fix bug for sproto
* Add global short string pool for lua vm
* Add code cache mode
* Add a callback for mysql auth
* Add hmac_md5
* Sharedata support filename as a string
* Fix a bug in socket.httpc
* Fix a lua stack overflow bug in lua bson
* Fix a socketchannel bug may block the data steam
* Avoid dead loop when sending message to the service exiting
* Fix memory leak in netpack
* Improve DH key exchange implement
* Minor fix for socket
* Minor fix for multicast
* Update jemalloc to 4.0.4
* Update lpeg to 1.0.0
v1.0.0-alpha10 (2015-8-17)
-----------
* Remove the size limit of cluster RPC message.
* Remove the size limit of local message.
* Add cluster.query and clsuter.register.
* Add an option of pthread mutex lock.
* Add skynet.core.intcommand to optimize skynet.sleep etc.
* Fix a memory leak bug in lua shared proto.
* snax.msgserver use string instead of lightuserdata/size.
* Remove some unused api in netpack.
* Raise error when skynet.send to 0.
v1.0.0-alpha9 (2015-8-10)
-----------
* Improve lua serialization , support pairs metamethod.
* Bugfix : sproto (See commits log of sproto)
* Add user log service support (In config)
* Other minor bugfix (See commits log)
v1.0.0-alpha8 (2015-6-29)
-----------
* Update lua 5.3.1
* Bugfix: skynet exit issue
* Bugfix: timer race condition
* Use atom increment in bson object id
* remove assert when write to a listen fd
* sproto encode doesn't use raw table api
v1.0.0-alpha7 (2015-6-8)
-----------
* console support launch snax service
* Add cluster.snax
* Add nodelay in clusterd
* Merge sproto bugfix patch
* Move some skynet api into skynet.manager
* DNS support underscore
* Add logservice in config file for user defined log service
* skynet.fork returns coroutine
* Fix a few of bugs , see the commits log
v1.0.0-alpha6 (2015-5-18)
-----------
* bugfix: httpc.get

View File

@@ -5,7 +5,8 @@ CSERVICE_PATH ?= cservice
SKYNET_BUILD_PATH ?= .
CFLAGS = -g -O2 -Wall -I$(LUA_INC) $(MYCFLAGS)
CFLAGS = -g -O2 -Wall -I$(LUA_INC) $(MYCFLAGS)
# CFLAGS += -DUSE_PTHREAD_LOCK
# lua
@@ -23,7 +24,7 @@ JEMALLOC_INC := 3rd/jemalloc/include/jemalloc
all : jemalloc
.PHONY : jemalloc
.PHONY : jemalloc update3rd
MALLOC_STATICLIB := $(JEMALLOC_STATICLIB)
@@ -38,6 +39,9 @@ $(JEMALLOC_STATICLIB) : 3rd/jemalloc/Makefile
jemalloc : $(MALLOC_STATICLIB)
update3rd :
rm -rf 3rd/jemalloc && git submodule update --init
# skynet
CSERVICE = snlua logger gate harbor
@@ -79,7 +83,7 @@ $(LUA_CLIB_PATH)/socketdriver.so : lualib-src/lua-socket.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src -Iservice-src
$(LUA_CLIB_PATH)/bson.so : lualib-src/lua-bson.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@ -Iskynet-src
$(LUA_CLIB_PATH)/mongo.so : lualib-src/lua-mongo.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src
@@ -109,7 +113,7 @@ $(LUA_CLIB_PATH)/crypt.so : lualib-src/lua-crypt.c lualib-src/lsha1.c | $(LUA_CL
$(CC) $(CFLAGS) $(SHARED) $^ -o $@
$(LUA_CLIB_PATH)/sharedata.so : lualib-src/lua-sharedata.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
$(LUA_CLIB_PATH)/stm.so : lualib-src/lua-stm.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
@@ -124,12 +128,15 @@ $(LUA_CLIB_PATH)/mysqlaux.so : lualib-src/lua-mysqlaux.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@
$(LUA_CLIB_PATH)/debugchannel.so : lualib-src/lua-debugchannel.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
clean :
rm -f $(SKYNET_BUILD_PATH)/skynet $(CSERVICE_PATH)/*.so $(LUA_CLIB_PATH)/*.so
cleanall: clean
ifneq (,$(wildcard 3rd/jemalloc/Makefile))
cd 3rd/jemalloc && $(MAKE) clean
endif
cd 3rd/lua && $(MAKE) clean
rm -f $(LUA_STATICLIB)

View File

@@ -1,6 +1,6 @@
## Build
For linux, install autoconf first for jemalloc
For Linux, install autoconf first for jemalloc:
```
git clone https://github.com/cloudwu/skynet.git
@@ -8,31 +8,33 @@ cd skynet
make 'PLATFORM' # PLATFORM can be linux, macosx, freebsd now
```
Or you can :
Or you can:
```
export PLAT=linux
make
```
For freeBSD , use gmake instead of make .
For FreeBSD , use gmake instead of make.
## Test
Run these in different console
Run these in different consoles:
```
./skynet examples/config # Launch first skynet node (Gate server) and a skynet-master (see config for standalone option)
./3rd/lua/lua examples/client.lua # Launch a client, and try to input hello.
```
## About Lua
## About Lua version
Skynet now use Lua 5.3.0 final, http://www.lua.org/ftp/lua-5.3.0.tar.gz
Skynet now uses a modified version of lua 5.3.3 ( http://www.lua.org/ftp/lua-5.3.3.tar.gz ) .
You can also use the other official Lua version , edit the makefile by yourself .
For details: http://lua-users.org/lists/lua-l/2014-03/msg00489.html
## How To (in Chinese)
You can also use official Lua versions, just edit the Makefile by yourself.
## How To Use (Sorry, Only in Chinese now)
* Read Wiki https://github.com/cloudwu/skynet/wiki
* The FAQ in wiki https://github.com/cloudwu/skynet/wiki/FAQ

View File

@@ -4,6 +4,7 @@ local socket = require "socket"
local sproto = require "sproto"
local sprotoloader = require "sprotoloader"
local WATCHDOG
local host
local send_request
@@ -26,6 +27,10 @@ function REQUEST:handshake()
return { msg = "Welcome to skynet, I will send heartbeat every 5 sec." }
end
function REQUEST:quit()
skynet.call(WATCHDOG, "lua", "close", client_fd)
end
local function request(name, args, response)
local f = assert(REQUEST[name])
local r = f(args)
@@ -62,7 +67,10 @@ skynet.register_protocol {
end
}
function CMD.start(gate, fd)
function CMD.start(conf)
local fd = conf.client
local gate = conf.gate
WATCHDOG = conf.watchdog
-- slot 1,2 set at main.lua
host = sprotoloader.load(1):host "package"
send_request = host:attach(sprotoloader.load(2))
@@ -77,6 +85,11 @@ function CMD.start(gate, fd)
skynet.call(gate, "lua", "forward", fd)
end
function CMD.disconnect()
-- todo: do something before exit
skynet.exit()
end
skynet.start(function()
skynet.dispatch("lua", function(_,_, command, ...)
local f = CMD[command]

View File

@@ -0,0 +1,30 @@
local skynet = require "skynet"
local list = {}
local function timeout_check(ti)
if not next(list) then
return
end
skynet.sleep(ti) -- sleep 10 sec
for k,v in pairs(list) do
skynet.error("timout",ti,k,v)
end
end
skynet.start(function()
skynet.error("ping all")
local list_ret = skynet.call(".launcher", "lua", "LIST")
for addr, desc in pairs(list_ret) do
list[addr] = desc
skynet.fork(function()
skynet.call(addr,"debug","INFO")
list[addr] = nil
end)
end
skynet.sleep(0)
timeout_check(100)
timeout_check(400)
timeout_check(500)
skynet.exit()
end)

View File

@@ -104,7 +104,11 @@ while true do
dispatch_package()
local cmd = socket.readstdin()
if cmd then
send_request("get", { what = cmd })
if cmd == "quit" then
send_request("quit")
else
send_request("get", { what = cmd })
end
else
socket.usleep(100)
end

View File

@@ -1,14 +1,19 @@
local skynet = require "skynet"
local cluster = require "cluster"
require "skynet.manager" -- import skynet.name
local snax = require "snax"
skynet.start(function()
local sdb = skynet.newservice("simpledb")
skynet.name(".simpledb", sdb)
print(skynet.call(".simpledb", "lua", "SET", "a", "foobar"))
print(skynet.call(".simpledb", "lua", "SET", "b", "foobar2"))
print(skynet.call(".simpledb", "lua", "GET", "a"))
print(skynet.call(".simpledb", "lua", "GET", "b"))
-- register name "sdb" for simpledb, you can use cluster.query() later.
-- See cluster2.lua
cluster.register("sdb", sdb)
print(skynet.call(sdb, "lua", "SET", "a", "foobar"))
print(skynet.call(sdb, "lua", "SET", "b", "foobar2"))
print(skynet.call(sdb, "lua", "GET", "a"))
print(skynet.call(sdb, "lua", "GET", "b"))
cluster.open "db"
cluster.open "db2"
-- unique snax service
snax.uniqueservice "pingserver"
end)

View File

@@ -2,8 +2,20 @@ local skynet = require "skynet"
local cluster = require "cluster"
skynet.start(function()
local proxy = cluster.proxy("db", ".simpledb")
print(skynet.call(proxy, "lua", "GET", "a"))
print(cluster.call("db", ".simpledb", "GET", "a"))
print(cluster.call("db2", ".simpledb", "GET", "b"))
-- query name "sdb" of cluster db.
local sdb = cluster.query("db", "sdb")
print("db.sbd=",sdb)
local proxy = cluster.proxy("db", sdb)
local largekey = string.rep("X", 128*1024)
local largevalue = string.rep("R", 100 * 1024)
print(skynet.call(proxy, "lua", "SET", largekey, largevalue))
local v = skynet.call(proxy, "lua", "GET", largekey)
assert(largevalue == v)
print(cluster.call("db", sdb, "GET", "a"))
print(cluster.call("db2", sdb, "GET", "b"))
-- test snax service
local pingserver = cluster.snax("db", "pingserver")
print(pingserver.req.ping "hello")
end)

View File

@@ -6,4 +6,5 @@ bootstrap = "snlua bootstrap" -- The service for bootstrap
luaservice = "./service/?.lua;./test/?.lua;./examples/?.lua"
lualoader = "lualib/loader.lua"
cpath = "./cservice/?.so"
cluster = "./examples/clustername.lua"
cluster = "./examples/clustername.lua"
snax = "./test/?.lua"

View File

@@ -6,4 +6,5 @@ bootstrap = "snlua bootstrap" -- The service for bootstrap
luaservice = "./service/?.lua;./test/?.lua;./examples/?.lua"
lualoader = "lualib/loader.lua"
cpath = "./cservice/?.so"
cluster = "./examples/clustername.lua"
cluster = "./examples/clustername.lua"
snax = "./test/?.lua"

15
examples/config.userlog Normal file
View File

@@ -0,0 +1,15 @@
root = "./"
thread = 8
logger = "userlog"
logservice = "snlua"
logpath = "."
harbor = 0
start = "main" -- main script
bootstrap = "snlua bootstrap" -- The service for bootstrap
luaservice = root.."service/?.lua;"..root.."test/?.lua;"..root.."examples/?.lua"
lualoader = "lualib/loader.lua"
-- preload = "./examples/preload.lua" -- run preload.lua before every lua service run
snax = root.."examples/?.lua;"..root.."test/?.lua"
-- snax_interface_g = "snax_g"
cpath = root.."cservice/?.so"
-- daemon = "./skynet.pid"

View File

@@ -131,7 +131,7 @@ local text = "echo"
local index = 1
print("connect")
local fd = assert(socket.connect("127.0.0.1", 8888))
fd = assert(socket.connect("127.0.0.1", 8888))
last = ""
local handshake = string.format("%s@%s#%s:%d", crypt.base64encode(token.user), crypt.base64encode(token.server),crypt.base64encode(subid) , index)
@@ -151,7 +151,7 @@ socket.close(fd)
index = index + 1
print("connect again")
local fd = assert(socket.connect("127.0.0.1", 8888))
fd = assert(socket.connect("127.0.0.1", 8888))
last = ""
local handshake = string.format("%s@%s#%s:%d", crypt.base64encode(token.user), crypt.base64encode(token.server),crypt.base64encode(subid) , index)

View File

@@ -17,7 +17,8 @@ function server.login_handler(uid, secret)
end
internal_id = internal_id + 1
local username = msgserver.username(uid, internal_id, servername)
local id = internal_id -- don't use internal_id directly
local username = msgserver.username(uid, id, servername)
-- you can use a pool to alloc new agent
local agent = skynet.newservice "msgagent"
@@ -25,11 +26,11 @@ function server.login_handler(uid, secret)
username = username,
agent = agent,
uid = uid,
subid = internal_id,
subid = id,
}
-- trash subid (no used)
skynet.call(agent, "lua", "login", uid, internal_id, secret)
skynet.call(agent, "lua", "login", uid, id, secret)
users[uid] = u
username_map[username] = u
@@ -37,7 +38,7 @@ function server.login_handler(uid, secret)
msgserver.login(username, secret)
-- you should return unique subid
return internal_id
return id
end
-- call by agent
@@ -73,9 +74,9 @@ function server.disconnect_handler(username)
end
-- call by self (when recv a request from client)
function server.request_handler(username, msg, sz)
function server.request_handler(username, msg)
local u = username_map[username]
return skynet.tostring(skynet.rawcall(u.agent, "client", msg, sz))
return skynet.tostring(skynet.rawcall(u.agent, "client", msg))
end
-- call by self (when gate open)

View File

@@ -19,7 +19,7 @@ function server.auth_handler(token)
user = crypt.base64decode(user)
server = crypt.base64decode(server)
password = crypt.base64decode(password)
assert(password == "password")
assert(password == "password", "Invalid password")
return server, user
end

View File

@@ -46,7 +46,7 @@ skynet.start(function()
end)
skynet.dispatch("client", function(_,_, msg)
-- the simple ehco service
-- the simple echo service
skynet.sleep(10) -- sleep a while
skynet.ret(msg)
end)

View File

@@ -4,7 +4,7 @@ local sprotoloader = require "sprotoloader"
local max_client = 64
skynet.start(function()
print("Server start")
skynet.error("Server start")
skynet.uniqueservice("protoloader")
local console = skynet.newservice("console")
skynet.newservice("debug_console",8000)
@@ -15,7 +15,6 @@ skynet.start(function()
maxclient = max_client,
nodelay = true,
})
print("Watchdog listen on ", 8888)
skynet.error("Watchdog listen on", 8888)
skynet.exit()
end)

View File

@@ -30,6 +30,8 @@ set 3 {
}
}
quit 4 {}
]]
proto.s2c = sprotoparser.parse [[

View File

@@ -37,6 +37,16 @@ skynet.start(function()
skynet.error(string.format("b[%d]=%s", k,v))
end
-- test lua serialization
local s = skynet.packstring(obj)
local nobj = skynet.unpack(s)
for k,v in pairs(nobj) do
skynet.error(string.format("nobj[%s]=%s", k,v))
end
for k,v in ipairs(nobj.b) do
skynet.error(string.format("nobj.b[%d]=%s", k,v))
end
for i = 1, 5 do
skynet.sleep(100)
skynet.error("second " ..i)

25
examples/userlog.lua Normal file
View File

@@ -0,0 +1,25 @@
local skynet = require "skynet"
require "skynet.manager"
skynet.register_protocol {
name = "text",
id = skynet.PTYPE_TEXT,
unpack = skynet.tostring,
dispatch = function(_, address, msg)
print(string.format(":%08x(%.2f): %s", address, skynet.time(), msg))
end
}
skynet.register_protocol {
name = "SYSTEM",
id = skynet.PTYPE_SYSTEM,
unpack = function(...) return ... end,
dispatch = function()
-- reopen signal
print("SIGHUP")
end
}
skynet.start(function()
skynet.register ".logger"
end)

View File

@@ -9,14 +9,16 @@ local agent = {}
function SOCKET.open(fd, addr)
skynet.error("New client from : " .. addr)
agent[fd] = skynet.newservice("agent")
skynet.call(agent[fd], "lua", "start", gate, fd)
skynet.call(agent[fd], "lua", "start", { gate = gate, client = fd, watchdog = skynet.self() })
end
local function close_agent(fd)
local a = agent[fd]
agent[fd] = nil
if a then
skynet.kill(a)
agent[fd] = nil
skynet.call(gate, "lua", "kick", fd)
-- disconnect never return
skynet.send(a, "lua", "disconnect")
end
end
@@ -30,6 +32,11 @@ function SOCKET.error(fd, msg)
close_agent(fd)
end
function SOCKET.warning(fd, size)
-- size K bytes havn't send out in fd
print("socket warning", fd, size)
end
function SOCKET.data(fd, msg)
end
@@ -37,6 +44,10 @@ function CMD.start(conf)
skynet.call(gate, "lua", "open" , conf)
end
function CMD.close(fd)
close_agent(fd)
end
skynet.start(function()
skynet.dispatch("lua", function(session, source, cmd, subcmd, ...)
if cmd == "socket" then

View File

@@ -8,9 +8,12 @@
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "atomic.h"
#define DEFAULT_CAP 64
#define MAX_NUMBER 1024
// avoid circular reference while encodeing
#define MAX_DEPTH 128
#define BSON_REAL 1
#define BSON_STRING 2
@@ -235,7 +238,7 @@ write_double(struct bson *b, lua_Number d) {
}
}
static void pack_dict(lua_State *L, struct bson *b, bool array);
static void pack_dict(lua_State *L, struct bson *b, bool array, int depth);
static inline void
append_key(struct bson *bs, int type, const char *key, size_t sz) {
@@ -243,12 +246,16 @@ append_key(struct bson *bs, int type, const char *key, size_t sz) {
write_string(bs, key, sz);
}
static inline int
is_32bit(int64_t v) {
return v >= INT32_MIN && v <= INT32_MAX;
}
static void
append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) {
if (lua_isinteger(L, -1)) {
int64_t i = lua_tointeger(L, -1);
int si = i >> 31;
if (si == 0 || si == -1) {
if (is_32bit(i)) {
append_key(bs, BSON_INT32, key, sz);
write_int32(bs, i);
} else {
@@ -263,7 +270,7 @@ append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) {
}
static void
append_table(struct bson *bs, lua_State *L, const char *key, size_t sz) {
append_table(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth) {
size_t len = lua_rawlen(L, -1);
bool isarray = false;
if (len > 0) {
@@ -279,7 +286,7 @@ append_table(struct bson *bs, lua_State *L, const char *key, size_t sz) {
} else {
append_key(bs, BSON_DOCUMENT, key, sz);
}
pack_dict(L, bs, isarray);
pack_dict(L, bs, isarray, depth);
}
static void
@@ -292,7 +299,7 @@ write_binary(struct bson *b, const void * buffer, size_t sz) {
}
static void
append_one(struct bson *bs, lua_State *L, const char *key, size_t sz) {
append_one(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth) {
int vt = lua_type(L,-1);
switch(vt) {
case LUA_TNUMBER:
@@ -380,7 +387,7 @@ append_one(struct bson *bs, lua_State *L, const char *key, size_t sz) {
break;
}
case LUA_TTABLE:
append_table(bs, L, key, sz);
append_table(bs, L, key, sz, depth+1);
break;
case LUA_TBOOLEAN:
append_key(bs, BSON_BOOLEAN, key, sz);
@@ -402,51 +409,97 @@ bson_numstr( char *str, unsigned int i ) {
}
static void
pack_dict(lua_State *L, struct bson *b, bool isarray) {
pack_dict_data(lua_State *L, struct bson *b, bool isarray, int depth, int kt) {
char numberkey[32];
const char * key = NULL;
size_t sz;
if (isarray) {
if (kt != LUA_TNUMBER) {
luaL_error(L, "Invalid array key type : %s", lua_typename(L, kt));
return;
}
sz = bson_numstr(numberkey, (unsigned int)lua_tointeger(L,-2)-1);
key = numberkey;
append_one(b, L, key, sz, depth);
lua_pop(L,1);
} else {
switch(kt) {
case LUA_TNUMBER:
// copy key, don't change key type
lua_pushvalue(L,-2);
lua_insert(L,-2);
key = lua_tolstring(L,-2,&sz);
append_one(b, L, key, sz, depth);
lua_pop(L,2);
break;
case LUA_TSTRING:
key = lua_tolstring(L,-2,&sz);
append_one(b, L, key, sz, depth);
lua_pop(L,1);
break;
default:
luaL_error(L, "Invalid key type : %s", lua_typename(L, kt));
return;
}
}
}
static void
pack_simple_dict(lua_State *L, struct bson *b, bool isarray, int depth) {
if (depth > MAX_DEPTH) {
luaL_error(L, "Too depth while encoding bson");
}
luaL_checkstack(L, 16, NULL); // reserve enough stack space to pack table
int length = reserve_length(b);
lua_pushnil(L);
while(lua_next(L,-2) != 0) {
int kt = lua_type(L, -2);
char numberkey[32];
const char * key = NULL;
size_t sz;
if (isarray) {
if (kt != LUA_TNUMBER) {
luaL_error(L, "Invalid array key type : %s", lua_typename(L, kt));
return;
}
sz = bson_numstr(numberkey, (unsigned int)lua_tointeger(L,-2)-1);
key = numberkey;
pack_dict_data(L, b, isarray, depth, kt);
}
write_byte(b,0);
write_length(b, b->size - length, length);
}
append_one(b, L, key, sz);
lua_pop(L,1);
} else {
switch(kt) {
case LUA_TNUMBER:
// copy key, don't change key type
lua_pushvalue(L,-2);
lua_insert(L,-2);
key = lua_tolstring(L,-2,&sz);
append_one(b, L, key, sz);
lua_pop(L,2);
break;
case LUA_TSTRING:
key = lua_tolstring(L,-2,&sz);
append_one(b, L, key, sz);
lua_pop(L,1);
break;
default:
luaL_error(L, "Invalid key type : %s", lua_typename(L, kt));
return;
}
static void
pack_meta_dict(lua_State *L, struct bson *b, bool isarray, int depth) {
if (depth > MAX_DEPTH) {
luaL_error(L, "Too depth while encoding bson");
}
luaL_checkstack(L, 16, NULL); // reserve enough stack space to pack table
int length = reserve_length(b);
lua_pushvalue(L, -2); // push meta_obj
lua_call(L, 1, 3); // call __pairs_func => next_func, t_data, first_k
for(;;) {
lua_pushvalue(L, -2); // copy data
lua_pushvalue(L, -2); // copy k
lua_copy(L, -5, -3); // copy next_func replace old_k
lua_call(L, 2, 2); // call next_func
int kt = lua_type(L, -2);
if (kt == LUA_TNIL) {
lua_pop(L, 4); // pop all k, v, next_func, obj
break;
}
pack_dict_data(L, b, isarray, depth, kt);
}
write_byte(b,0);
write_length(b, b->size - length, length);
}
static void
pack_ordered_dict(lua_State *L, struct bson *b, int n) {
pack_dict(lua_State *L, struct bson *b, bool isarray, int depth) {
if (luaL_getmetafield(L, -1, "__pairs") != LUA_TNIL) {
pack_meta_dict(L, b, isarray, depth);
} else {
pack_simple_dict(L, b, isarray, depth);
}
}
static void
pack_ordered_dict(lua_State *L, struct bson *b, int n, int depth) {
int length = reserve_length(b);
int i;
for (i=0;i<n;i+=2) {
@@ -456,7 +509,7 @@ pack_ordered_dict(lua_State *L, struct bson *b, int n) {
luaL_error(L, "Argument %d need a string", i+1);
}
lua_pushvalue(L, i+2);
append_one(b, L, key, sz);
append_one(b, L, key, sz, depth);
lua_pop(L,1);
}
write_byte(b,0);
@@ -490,6 +543,7 @@ make_object(lua_State *L, int type, const void * ptr, size_t len) {
static void
unpack_dict(lua_State *L, struct bson_reader *br, bool array) {
luaL_checkstack(L, 16, NULL); // reserve enough stack space to unpack table
int sz = read_int32(L, br);
const void * bytes = read_bytes(L, br, sz-5);
struct bson_reader t = { bytes, sz-5 };
@@ -841,7 +895,7 @@ lencode(lua_State *L) {
bson_create(&b);
lua_settop(L,1);
luaL_checktype(L, 1, LUA_TTABLE);
pack_dict(L, &b, false);
pack_dict(L, &b, false, 0);
void * ud = lua_newuserdata(L, b.size);
memcpy(ud, b.ptr, b.size);
bson_destroy(&b);
@@ -857,7 +911,7 @@ lencode_order(lua_State *L) {
if (n%2 != 0) {
return luaL_error(L, "Invalid ordered dict");
}
pack_ordered_dict(L, &b, n);
pack_ordered_dict(L, &b, n, 0);
lua_settop(L,1);
void * ud = lua_newuserdata(L, b.size);
memcpy(ud, b.ptr, b.size);
@@ -1135,15 +1189,17 @@ lobjectid(lua_State *L) {
}
} else {
time_t ti = time(NULL);
// old_counter is a static var, use atom inc.
uint32_t id = ATOM_FINC(&oid_counter);
oid[2] = (ti>>24) & 0xff;
oid[3] = (ti>>16) & 0xff;
oid[4] = (ti>>8) & 0xff;
oid[5] = ti & 0xff;
memcpy(oid+6 , oid_header, 5);
oid[11] = (oid_counter>>16) & 0xff;
oid[12] = (oid_counter>>8) & 0xff;
oid[13] = oid_counter & 0xff;
++oid_counter;
oid[11] = (id>>16) & 0xff;
oid[12] = (id>>8) & 0xff;
oid[13] = id & 0xff;
}
lua_pushlstring( L, (const char *)oid, 14);

View File

@@ -128,11 +128,8 @@ lusleep(lua_State *L) {
#define QUEUE_SIZE 1024
#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {}
#define UNLOCK(q) __sync_lock_release(&(q)->lock);
struct queue {
int lock;
pthread_mutex_t lock;
int head;
int tail;
char * queue[QUEUE_SIZE];
@@ -153,7 +150,7 @@ readline_stdin(void * arg) {
memcpy(str, tmp, n);
str[n] = 0;
LOCK(q);
pthread_mutex_lock(&q->lock);
q->queue[q->tail] = str;
if (++q->tail >= QUEUE_SIZE) {
@@ -163,7 +160,7 @@ readline_stdin(void * arg) {
// queue overflow
exit(1);
}
UNLOCK(q);
pthread_mutex_unlock(&q->lock);
}
return NULL;
}
@@ -171,16 +168,16 @@ readline_stdin(void * arg) {
static int
lreadstdin(lua_State *L) {
struct queue *q = lua_touserdata(L, lua_upvalueindex(1));
LOCK(q);
pthread_mutex_lock(&q->lock);
if (q->head == q->tail) {
UNLOCK(q);
pthread_mutex_unlock(&q->lock);
return 0;
}
char * str = q->queue[q->head];
if (++q->head >= QUEUE_SIZE) {
q->head = 0;
}
UNLOCK(q);
pthread_mutex_unlock(&q->lock);
lua_pushstring(L, str);
free(str);
return 1;
@@ -201,6 +198,7 @@ luaopen_clientsocket(lua_State *L) {
struct queue * q = lua_newuserdata(L, sizeof(*q));
memset(q, 0, sizeof(*q));
pthread_mutex_init(&q->lock, NULL);
lua_pushcclosure(L, lreadstdin, 1);
lua_setfield(L, -2, "readstdin");

View File

@@ -1,6 +1,7 @@
#include <lua.h>
#include <lauxlib.h>
#include <string.h>
#include <assert.h>
#include "skynet.h"
@@ -15,7 +16,8 @@
uint32_t next_session
*/
#define TEMP_LENGTH 0x10007
#define TEMP_LENGTH 0x8200
#define MULTI_PART 0x8000
static void
fill_uint32(uint8_t * buf, uint32_t n) {
@@ -26,30 +28,75 @@ fill_uint32(uint8_t * buf, uint32_t n) {
}
static void
fill_header(lua_State *L, uint8_t *buf, int sz, void *msg) {
if (sz >= 0x10000) {
skynet_free(msg);
luaL_error(L, "request message is too long %d", sz);
}
fill_header(lua_State *L, uint8_t *buf, int sz) {
assert(sz < 0x10000);
buf[0] = (sz >> 8) & 0xff;
buf[1] = sz & 0xff;
}
static void
packreq_number(lua_State *L, int session, void * msg, size_t sz) {
/*
The request package :
size <= 0x8000 (32K) and address is id
WORD sz+9
BYTE 0
DWORD addr
DWORD session
PADDING msg(sz)
size > 0x8000 and address is id
DWORD 13
BYTE 1 ; multireq
DWORD addr
DWORD session
DWORD sz
size <= 0x8000 (32K) and address is string
WORD sz+6+namelen
BYTE 0x80
BYTE namelen
STRING name
DWORD session
PADDING msg(sz)
size > 0x8000 and address is string
DWORD 10 + namelen
BYTE 0x81
BYTE namelen
STRING name
DWORD session
DWORD sz
multi req
WORD sz + 5
BYTE 2/3 ; 2:multipart, 3:multipart end
DWORD SESSION
PADDING msgpart(sz)
*/
static int
packreq_number(lua_State *L, int session, void * msg, uint32_t sz) {
uint32_t addr = (uint32_t)lua_tointeger(L,1);
uint8_t buf[TEMP_LENGTH];
fill_header(L, buf, sz+9, msg);
buf[2] = 0;
fill_uint32(buf+3, addr);
fill_uint32(buf+7, (uint32_t)session);
memcpy(buf+11,msg,sz);
if (sz < MULTI_PART) {
fill_header(L, buf, sz+9);
buf[2] = 0;
fill_uint32(buf+3, addr);
fill_uint32(buf+7, (uint32_t)session);
memcpy(buf+11,msg,sz);
lua_pushlstring(L, (const char *)buf, sz+11);
lua_pushlstring(L, (const char *)buf, sz+11);
return 0;
} else {
int part = (sz - 1) / MULTI_PART + 1;
fill_header(L, buf, 13);
buf[2] = 1;
fill_uint32(buf+3, addr);
fill_uint32(buf+7, (uint32_t)session);
fill_uint32(buf+11, sz);
lua_pushlstring(L, (const char *)buf, 15);
return part;
}
}
static void
packreq_string(lua_State *L, int session, void * msg, size_t sz) {
static int
packreq_string(lua_State *L, int session, void * msg, uint32_t sz) {
size_t namelen = 0;
const char *name = lua_tolstring(L, 1, &namelen);
if (name == NULL || namelen < 1 || namelen > 255) {
@@ -58,13 +105,53 @@ packreq_string(lua_State *L, int session, void * msg, size_t sz) {
}
uint8_t buf[TEMP_LENGTH];
fill_header(L, buf, sz+5+namelen, msg);
buf[2] = (uint8_t)namelen;
memcpy(buf+3, name, namelen);
fill_uint32(buf+3+namelen, (uint32_t)session);
memcpy(buf+7+namelen,msg,sz);
if (sz < MULTI_PART) {
fill_header(L, buf, sz+6+namelen);
buf[2] = 0x80;
buf[3] = (uint8_t)namelen;
memcpy(buf+4, name, namelen);
fill_uint32(buf+4+namelen, (uint32_t)session);
memcpy(buf+8+namelen,msg,sz);
lua_pushlstring(L, (const char *)buf, sz+7+namelen);
lua_pushlstring(L, (const char *)buf, sz+8+namelen);
return 0;
} else {
int part = (sz - 1) / MULTI_PART + 1;
fill_header(L, buf, 10+namelen);
buf[2] = 0x81;
buf[3] = (uint8_t)namelen;
memcpy(buf+4, name, namelen);
fill_uint32(buf+4+namelen, (uint32_t)session);
fill_uint32(buf+8+namelen, sz);
lua_pushlstring(L, (const char *)buf, 12+namelen);
return part;
}
}
static void
packreq_multi(lua_State *L, int session, void * msg, uint32_t sz) {
uint8_t buf[TEMP_LENGTH];
int part = (sz - 1) / MULTI_PART + 1;
int i;
char *ptr = msg;
for (i=0;i<part;i++) {
uint32_t s;
if (sz > MULTI_PART) {
s = MULTI_PART;
buf[2] = 2;
} else {
s = sz;
buf[2] = 3; // the last multi part
}
fill_header(L, buf, s+5);
fill_uint32(buf+3, (uint32_t)session);
memcpy(buf+7, ptr, s);
lua_pushlstring(L, (const char *)buf, s+7);
lua_rawseti(L, -2, i+1);
sz -= s;
ptr += s;
}
}
static int
@@ -73,23 +160,33 @@ lpackrequest(lua_State *L) {
if (msg == NULL) {
return luaL_error(L, "Invalid request message");
}
size_t sz = (size_t)luaL_checkinteger(L,4);
uint32_t sz = (uint32_t)luaL_checkinteger(L,4);
int session = luaL_checkinteger(L,2);
if (session <= 0) {
skynet_free(msg);
return luaL_error(L, "Invalid request session %d", session);
}
int addr_type = lua_type(L,1);
int multipak;
if (addr_type == LUA_TNUMBER) {
packreq_number(L, session, msg, sz);
multipak = packreq_number(L, session, msg, sz);
} else {
packreq_string(L, session, msg, sz);
multipak = packreq_string(L, session, msg, sz);
}
int current_session = session;
if (++session < 0) {
session = 1;
}
skynet_free(msg);
lua_pushinteger(L, session);
return 2;
if (multipak) {
lua_createtable(L, multipak, 0);
packreq_multi(L, current_session, msg, sz);
skynet_free(msg);
return 3;
} else {
skynet_free(msg);
return 2;
}
}
/*
@@ -98,6 +195,7 @@ lpackrequest(lua_State *L) {
uint32_t or string addr
int session
string msg
boolean padding
*/
static inline uint32_t
@@ -106,44 +204,122 @@ unpack_uint32(const uint8_t * buf) {
}
static int
unpackreq_number(lua_State *L, const uint8_t * buf, size_t sz) {
unpackreq_number(lua_State *L, const uint8_t * buf, int sz) {
if (sz < 9) {
return luaL_error(L, "Invalid cluster message");
return luaL_error(L, "Invalid cluster message (size=%d)", sz);
}
uint32_t address = unpack_uint32(buf+1);
uint32_t session = unpack_uint32(buf+5);
lua_pushinteger(L, (uint32_t)address);
lua_pushinteger(L, (uint32_t)session);
lua_pushinteger(L, address);
lua_pushinteger(L, session);
lua_pushlstring(L, (const char *)buf+9, sz-9);
return 3;
}
static int
unpackreq_string(lua_State *L, const uint8_t * buf, size_t sz) {
size_t namesz = buf[0];
if (sz < namesz + 5) {
return luaL_error(L, "Invalid cluster message");
unpackmreq_number(lua_State *L, const uint8_t * buf, int sz) {
if (sz != 13) {
return luaL_error(L, "Invalid cluster message size %d (multi req must be 13)", sz);
}
lua_pushlstring(L, (const char *)buf+1, namesz);
uint32_t session = unpack_uint32(buf + namesz + 1);
uint32_t address = unpack_uint32(buf+1);
uint32_t session = unpack_uint32(buf+5);
uint32_t size = unpack_uint32(buf+9);
lua_pushinteger(L, address);
lua_pushinteger(L, session);
lua_pushinteger(L, size);
lua_pushboolean(L, 1); // padding multi part
return 4;
}
static int
unpackmreq_part(lua_State *L, const uint8_t * buf, int sz) {
if (sz < 5) {
return luaL_error(L, "Invalid cluster multi part message");
}
int padding = (buf[0] == 2);
uint32_t session = unpack_uint32(buf+1);
lua_pushboolean(L, 0); // no address
lua_pushinteger(L, session);
lua_pushlstring(L, (const char *)buf+5, sz-5);
lua_pushboolean(L, padding);
return 4;
}
static int
unpackreq_string(lua_State *L, const uint8_t * buf, int sz) {
if (sz < 2) {
return luaL_error(L, "Invalid cluster message (size=%d)", sz);
}
size_t namesz = buf[1];
if (sz < namesz + 6) {
return luaL_error(L, "Invalid cluster message (size=%d)", sz);
}
lua_pushlstring(L, (const char *)buf+2, namesz);
uint32_t session = unpack_uint32(buf + namesz + 2);
lua_pushinteger(L, (uint32_t)session);
lua_pushlstring(L, (const char *)buf+1+namesz+4, sz - namesz - 5);
lua_pushlstring(L, (const char *)buf+2+namesz+4, sz - namesz - 6);
return 3;
}
static int
unpackmreq_string(lua_State *L, const uint8_t * buf, int sz) {
if (sz < 2) {
return luaL_error(L, "Invalid cluster message (size=%d)", sz);
}
size_t namesz = buf[1];
if (sz < namesz + 10) {
return luaL_error(L, "Invalid cluster message (size=%d)", sz);
}
lua_pushlstring(L, (const char *)buf+2, namesz);
uint32_t session = unpack_uint32(buf + namesz + 2);
uint32_t size = unpack_uint32(buf + namesz + 6);
lua_pushinteger(L, session);
lua_pushinteger(L, size);
lua_pushboolean(L, 1); // padding multipart
return 4;
}
static int
lunpackrequest(lua_State *L) {
size_t sz;
const char *msg = luaL_checklstring(L,1,&sz);
if (msg[0] == 0) {
size_t ssz;
const char *msg = luaL_checklstring(L,1,&ssz);
int sz = (int)ssz;
switch (msg[0]) {
case 0:
return unpackreq_number(L, (const uint8_t *)msg, sz);
} else {
case 1:
return unpackmreq_number(L, (const uint8_t *)msg, sz);
case 2:
case 3:
return unpackmreq_part(L, (const uint8_t *)msg, sz);
case '\x80':
return unpackreq_string(L, (const uint8_t *)msg, sz);
case '\x81':
return unpackmreq_string(L, (const uint8_t *)msg, sz);
default:
return luaL_error(L, "Invalid req package type %d", msg[0]);
}
}
/*
DWORD session
BYTE type
0: error
1: ok
2: multi begin
3: multi part
4: multi end
PADDING msg
type = 0, error msg
type = 1, msg
type = 2, DWORD size
type = 3/4, msg
*/
/*
int session
boolean ok
@@ -162,16 +338,56 @@ lpackresponse(lua_State *L) {
if (lua_type(L,3) == LUA_TSTRING) {
msg = (void *)lua_tolstring(L, 3, &sz);
if (sz > 0x1000) {
sz = 0x1000;
}
} else {
msg = lua_touserdata(L,3);
sz = (size_t)luaL_checkinteger(L, 4);
}
if (!ok) {
if (sz > MULTI_PART) {
// truncate the error msg if too long
sz = MULTI_PART;
}
} else {
if (sz > MULTI_PART) {
// return
int part = (sz - 1) / MULTI_PART + 1;
lua_createtable(L, part+1, 0);
uint8_t buf[TEMP_LENGTH];
// multi part begin
fill_header(L, buf, 9);
fill_uint32(buf+2, session);
buf[6] = 2;
fill_uint32(buf+7, (uint32_t)sz);
lua_pushlstring(L, (const char *)buf, 11);
lua_rawseti(L, -2, 1);
char * ptr = msg;
int i;
for (i=0;i<part;i++) {
int s;
if (sz > MULTI_PART) {
s = MULTI_PART;
buf[6] = 3;
} else {
s = sz;
buf[6] = 4;
}
fill_header(L, buf, s+5);
fill_uint32(buf+2, session);
memcpy(buf+7,ptr,s);
lua_pushlstring(L, (const char *)buf, s+7);
lua_rawseti(L, -2, i+2);
sz -= s;
ptr += s;
}
return 1;
}
}
uint8_t buf[TEMP_LENGTH];
fill_header(L, buf, sz+5, msg);
fill_header(L, buf, sz+5);
fill_uint32(buf+2, session);
buf[6] = ok;
memcpy(buf+7,msg,sz);
@@ -186,6 +402,7 @@ lpackresponse(lua_State *L) {
return integer session
boolean ok
string msg
boolean padding
*/
static int
lunpackresponse(lua_State *L) {
@@ -196,10 +413,66 @@ lunpackresponse(lua_State *L) {
}
uint32_t session = unpack_uint32((const uint8_t *)buf);
lua_pushinteger(L, (lua_Integer)session);
lua_pushboolean(L, buf[4]);
lua_pushlstring(L, buf+5, sz-5);
switch(buf[4]) {
case 0: // error
lua_pushboolean(L, 0);
lua_pushlstring(L, buf+5, sz-5);
return 3;
case 1: // ok
case 4: // multi end
lua_pushboolean(L, 1);
lua_pushlstring(L, buf+5, sz-5);
return 3;
case 2: // multi begin
if (sz != 9) {
return 0;
}
sz = unpack_uint32((const uint8_t *)buf+5);
lua_pushboolean(L, 1);
lua_pushinteger(L, sz);
lua_pushboolean(L, 1);
return 4;
case 3: // multi part
lua_pushboolean(L, 1);
lua_pushlstring(L, buf+5, sz-5);
lua_pushboolean(L, 1);
return 4;
default:
return 0;
}
}
return 3;
static int
lconcat(lua_State *L) {
if (!lua_istable(L,1))
return 0;
if (lua_geti(L,1,1) != LUA_TNUMBER)
return 0;
int sz = lua_tointeger(L,-1);
lua_pop(L,1);
char * buff = skynet_malloc(sz);
int idx = 2;
int offset = 0;
while(lua_geti(L,1,idx) == LUA_TSTRING) {
size_t s;
const char * str = lua_tolstring(L, -1, &s);
if (s+offset > sz) {
skynet_free(buff);
return 0;
}
memcpy(buff+offset, str, s);
lua_pop(L,1);
offset += s;
++idx;
}
if (offset != sz) {
skynet_free(buff);
return 0;
}
// buff/sz will send to other service, See clusterd.lua
lua_pushlightuserdata(L, buff);
lua_pushinteger(L, sz);
return 2;
}
int
@@ -209,6 +482,7 @@ luaopen_cluster_core(lua_State *L) {
{ "unpackrequest", lunpackrequest },
{ "packresponse", lpackresponse },
{ "unpackresponse", lunpackresponse },
{ "concat", lconcat },
{ NULL, NULL },
};
luaL_checkversion(L);

View File

@@ -10,7 +10,7 @@
/* the eight DES S-boxes */
uint32_t SB1[64] = {
static uint32_t SB1[64] = {
0x01010400, 0x00000000, 0x00010000, 0x01010404,
0x01010004, 0x00010404, 0x00000004, 0x00010000,
0x00000400, 0x01010400, 0x01010404, 0x00000400,
@@ -338,8 +338,13 @@ static int
lrandomkey(lua_State *L) {
char tmp[8];
int i;
char x = 0;
for (i=0;i<8;i++) {
tmp[i] = random() & 0xff;
x ^= tmp[i];
}
if (x==0) {
tmp[0] |= 1; // avoid 0
}
lua_pushlstring(L, tmp, 8);
return 1;
@@ -718,8 +723,11 @@ static int
ldhsecret(lua_State *L) {
uint32_t x[2], y[2];
read64(L, x, y);
uint64_t r = powmodp((uint64_t)x[0] | (uint64_t)x[1]<<32,
(uint64_t)y[0] | (uint64_t)y[1]<<32);
uint64_t xx = (uint64_t)x[0] | (uint64_t)x[1]<<32;
uint64_t yy = (uint64_t)y[0] | (uint64_t)y[1]<<32;
if (xx == 0 || yy == 0)
return luaL_error(L, "Can't be 0");
uint64_t r = powmodp(xx, yy);
push64(L, r);
@@ -739,7 +747,11 @@ ldhexchange(lua_State *L) {
xx[0] = x[0] | x[1]<<8 | x[2]<<16 | x[3]<<24;
xx[1] = x[4] | x[5]<<8 | x[6]<<16 | x[7]<<24;
uint64_t r = powmodp(5, (uint64_t)xx[0] | (uint64_t)xx[1]<<32);
uint64_t x64 = (uint64_t)xx[0] | (uint64_t)xx[1]<<32;
if (x64 == 0)
return luaL_error(L, "Can't be 0");
uint64_t r = powmodp(5, x64);
push64(L, r);
return 1;
}
@@ -873,7 +885,12 @@ int lhmac_sha1(lua_State *L);
int
luaopen_crypt(lua_State *L) {
luaL_checkversion(L);
srandom(time(NULL));
static int init = 0;
if (!init) {
// Don't need call srandom more than once.
init = 1 ;
srandom(time(NULL));
}
luaL_Reg l[] = {
{ "hashkey", lhashkey },
{ "randomkey", lrandomkey },

View File

@@ -4,10 +4,9 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "spinlock.h"
#define METANAME "debugchannel"
#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {}
#define UNLOCK(q) __sync_lock_release(&(q)->lock);
struct command {
struct command * next;
@@ -15,7 +14,7 @@ struct command {
};
struct channel {
int lock;
struct spinlock lock;
int ref;
struct command * head;
struct command * tail;
@@ -26,6 +25,7 @@ channel_new() {
struct channel * c = malloc(sizeof(*c));
memset(c, 0 , sizeof(*c));
c->ref = 1;
SPIN_INIT(c)
return c;
}
@@ -33,21 +33,21 @@ channel_new() {
static struct channel *
channel_connect(struct channel *c) {
struct channel * ret = NULL;
LOCK(c)
SPIN_LOCK(c)
if (c->ref == 1) {
++c->ref;
ret = c;
}
UNLOCK(c)
SPIN_UNLOCK(c)
return ret;
}
static struct channel *
channel_release(struct channel *c) {
LOCK(c)
SPIN_LOCK(c)
--c->ref;
if (c->ref > 0) {
UNLOCK(c)
SPIN_UNLOCK(c)
return c;
}
// never unlock while reference is 0
@@ -59,6 +59,9 @@ channel_release(struct channel *c) {
free(p);
p = next;
}
SPIN_UNLOCK(c)
SPIN_DESTROY(c)
free(c);
return NULL;
}
@@ -66,9 +69,9 @@ channel_release(struct channel *c) {
static struct command *
channel_read(struct channel *c, double timeout) {
struct command * ret = NULL;
LOCK(c)
SPIN_LOCK(c)
if (c->head == NULL) {
UNLOCK(c)
SPIN_UNLOCK(c)
int ti = (int)(timeout * 100000);
usleep(ti);
return NULL;
@@ -78,7 +81,7 @@ channel_read(struct channel *c, double timeout) {
if (c->head == NULL) {
c->tail = NULL;
}
UNLOCK(c)
SPIN_UNLOCK(c)
return ret;
}
@@ -89,14 +92,14 @@ channel_write(struct channel *c, const char * s, size_t sz) {
cmd->sz = sz;
cmd->next = NULL;
memcpy(cmd+1, s, sz);
LOCK(c)
SPIN_LOCK(c)
if (c->tail == NULL) {
c->head = c->tail = cmd;
} else {
c->tail->next = cmd;
c->tail = cmd;
}
UNLOCK(c)
SPIN_UNLOCK(c)
}
struct channel_box {

View File

@@ -2,6 +2,7 @@
#include <lauxlib.h>
#include "malloc_hook.h"
#include "luashrtbl.h"
static int
ltotal(lua_State *L) {
@@ -33,6 +34,19 @@ ldump(lua_State *L) {
return 0;
}
static int
lexpandshrtbl(lua_State *L) {
int n = luaL_checkinteger(L, 1);
luaS_expandshr(n);
return 0;
}
static int
lcurrent(lua_State *L) {
lua_pushinteger(L, malloc_current_memory());
return 1;
}
int
luaopen_memory(lua_State *L) {
luaL_checkversion(L);
@@ -42,6 +56,10 @@ luaopen_memory(lua_State *L) {
{ "block", lblock },
{ "dumpinfo", ldumpinfo },
{ "dump", ldump },
{ "info", dump_mem_lua },
{ "ssinfo", luaS_shrinfo },
{ "ssexpand", lexpandshrtbl },
{ "current", lcurrent },
{ NULL, NULL },
};

View File

@@ -5,6 +5,8 @@
#include <stdint.h>
#include <string.h>
#include "atomic.h"
struct mc_package {
int reference;
uint32_t size;
@@ -116,7 +118,7 @@ static int
mc_closelocal(lua_State *L) {
struct mc_package *pack = lua_touserdata(L,1);
int ref = __sync_sub_and_fetch(&pack->reference, 1);
int ref = ATOM_DEC(&pack->reference);
if (ref <= 0) {
skynet_free(pack->data);
skynet_free(pack);

View File

@@ -19,6 +19,7 @@
#define TYPE_ERROR 3
#define TYPE_OPEN 4
#define TYPE_CLOSE 5
#define TYPE_WARNING 6
/*
Each package is uint16 + data , uint16 (serialized in big-endian) is the number of bytes comprising the data .
@@ -48,6 +49,7 @@ struct queue {
static void
clear_list(struct uncomplete * uc) {
while (uc) {
skynet_free(uc->pack.buffer);
void * tmp = uc;
uc = uc->next;
skynet_free(tmp);
@@ -210,6 +212,16 @@ push_more(lua_State *L, int fd, uint8_t *buffer, int size) {
}
}
static void
close_uncomplete(lua_State *L, int fd) {
struct queue *q = lua_touserdata(L,1);
struct uncomplete * uc = find_uncomplete(q, fd);
if (uc) {
skynet_free(uc->pack.buffer);
skynet_free(uc);
}
}
static int
filter_data_(lua_State *L, int fd, uint8_t * buffer, int size) {
struct queue *q = lua_touserdata(L,1);
@@ -343,6 +355,8 @@ lfilter(lua_State *L) {
// ignore listen fd connect
return 1;
case SKYNET_SOCKET_TYPE_CLOSE:
// no more data in fd (message->id)
close_uncomplete(L, message->id);
lua_pushvalue(L, lua_upvalueindex(TYPE_CLOSE));
lua_pushinteger(L, message->id);
return 3;
@@ -353,10 +367,17 @@ lfilter(lua_State *L) {
pushstring(L, buffer, size);
return 4;
case SKYNET_SOCKET_TYPE_ERROR:
// no more data in fd (message->id)
close_uncomplete(L, message->id);
lua_pushvalue(L, lua_upvalueindex(TYPE_ERROR));
lua_pushinteger(L, message->id);
pushstring(L, buffer, size);
return 4;
case SKYNET_SOCKET_TYPE_WARNING:
lua_pushvalue(L, lua_upvalueindex(TYPE_WARNING));
lua_pushinteger(L, message->id);
lua_pushinteger(L, message->ud);
return 4;
default:
// never get here
return 1;
@@ -414,7 +435,7 @@ static int
lpack(lua_State *L) {
size_t len;
const char * ptr = tolstring(L, &len, 1);
if (len > 0x10000) {
if (len >= 0x10000) {
return luaL_error(L, "Invalid size (too long) of data : %d", (int)len);
}
@@ -428,57 +449,6 @@ lpack(lua_State *L) {
return 2;
}
static int
lpack_string(lua_State *L) {
uint8_t tmp[SMALLSTRING+2];
size_t len;
uint8_t *buffer;
const char * ptr = tolstring(L, &len, 1);
if (len > 0x10000) {
return luaL_error(L, "Invalid size (too long) of data : %d", (int)len);
}
if (len <= SMALLSTRING) {
buffer = tmp;
} else {
buffer = lua_newuserdata(L, len + 2);
}
write_size(buffer, len);
memcpy(buffer+2, ptr, len);
lua_pushlstring(L, (const char *)buffer, len+2);
return 1;
}
static int
lpack_padding(lua_State *L) {
uint8_t tmp[SMALLSTRING+2];
size_t content_sz;
uint8_t *buffer;
const char * ptr = tolstring(L, &content_sz, 2);
size_t cookie_sz = 0;
const char * cookie = luaL_checklstring(L,1,&cookie_sz);
size_t len = cookie_sz + content_sz;
if (len > 0x10000) {
return luaL_error(L, "Invalid size (too long) of data : %d", (int)len);
}
if (len <= SMALLSTRING) {
buffer = tmp;
} else {
buffer = lua_newuserdata(L, len + 2);
}
write_size(buffer, len);
memcpy(buffer+2, ptr, content_sz);
memcpy(buffer+2+content_sz, cookie, cookie_sz);
lua_pushlstring(L, (const char *)buffer, len+2);
return 1;
}
static int
ltostring(lua_State *L) {
void * ptr = lua_touserdata(L, 1);
@@ -486,19 +456,8 @@ ltostring(lua_State *L) {
if (ptr == NULL) {
lua_pushliteral(L, "");
} else {
if (lua_isnumber(L, 3)) {
int offset = lua_tointeger(L, 3);
if (offset < 0) {
return luaL_error(L, "Invalid offset %d", offset);
}
if (offset > size) {
offset = size;
}
lua_pushlstring(L, (const char *)ptr + offset, size-offset);
} else {
lua_pushlstring(L, (const char *)ptr, size);
skynet_free(ptr);
}
lua_pushlstring(L, (const char *)ptr, size);
skynet_free(ptr);
}
return 1;
}
@@ -509,8 +468,6 @@ luaopen_netpack(lua_State *L) {
luaL_Reg l[] = {
{ "pop", lpop },
{ "pack", lpack },
{ "pack_string", lpack_string },
{ "pack_padding", lpack_padding },
{ "clear", lclear },
{ "tostring", ltostring },
{ NULL, NULL },
@@ -523,8 +480,9 @@ luaopen_netpack(lua_State *L) {
lua_pushliteral(L, "error");
lua_pushliteral(L, "open");
lua_pushliteral(L, "close");
lua_pushliteral(L, "warning");
lua_pushcclosure(L, lfilter, 5);
lua_pushcclosure(L, lfilter, 6);
lua_setfield(L, -2, "filter");
return 1;

View File

@@ -1,3 +1,4 @@
#include <stdio.h>
#include <lua.h>
#include <lauxlib.h>
@@ -11,6 +12,8 @@
#define NANOSEC 1000000000
#define MICROSEC 1000000
// #define DEBUG_LOG
static double
get_time() {
#if !defined(__APPLE__)
@@ -47,7 +50,11 @@ diff_time(double start) {
static int
lstart(lua_State *L) {
lua_pushthread(L);
if (lua_type(L,1) == LUA_TTHREAD) {
lua_settop(L,1);
} else {
lua_pushthread(L);
}
lua_rawget(L, lua_upvalueindex(2));
if (!lua_isnil(L, -1)) {
return luaL_error(L, "Thread %p start profile more than once", lua_topointer(L, 1));
@@ -57,7 +64,11 @@ lstart(lua_State *L) {
lua_rawset(L, lua_upvalueindex(2));
lua_pushthread(L);
lua_pushnumber(L, get_time());
double ti = get_time();
#ifdef DEBUG_LOG
fprintf(stderr, "PROFILE [%p] start\n", L);
#endif
lua_pushnumber(L, ti);
lua_rawset(L, lua_upvalueindex(1));
return 0;
@@ -65,9 +76,15 @@ lstart(lua_State *L) {
static int
lstop(lua_State *L) {
lua_pushthread(L);
if (lua_type(L,1) == LUA_TTHREAD) {
lua_settop(L,1);
} else {
lua_pushthread(L);
}
lua_rawget(L, lua_upvalueindex(1));
luaL_checktype(L, -1, LUA_TNUMBER);
if (lua_type(L, -1) != LUA_TNUMBER) {
return luaL_error(L, "Call profile.start() before profile.stop()");
}
double ti = diff_time(lua_tonumber(L, -1));
lua_pushthread(L);
lua_rawget(L, lua_upvalueindex(2));
@@ -81,14 +98,20 @@ lstop(lua_State *L) {
lua_pushnil(L);
lua_rawset(L, lua_upvalueindex(2));
lua_pushnumber(L, ti + total_time);
total_time += ti;
lua_pushnumber(L, total_time);
#ifdef DEBUG_LOG
fprintf(stderr, "PROFILE [%p] stop (%lf / %lf)\n", L, ti, total_time);
#endif
return 1;
}
static int
lresume(lua_State *L) {
lua_pushvalue(L,1);
timing_resume(lua_State *L) {
#ifdef DEBUG_LOG
lua_State *from = lua_tothread(L, -1);
#endif
lua_rawget(L, lua_upvalueindex(2));
if (lua_isnil(L, -1)) { // check total time
lua_pop(L,1);
@@ -96,6 +119,9 @@ lresume(lua_State *L) {
lua_pop(L,1);
lua_pushvalue(L,1);
double ti = get_time();
#ifdef DEBUG_LOG
fprintf(stderr, "PROFILE [%p] resume\n", from);
#endif
lua_pushnumber(L, ti);
lua_rawset(L, lua_upvalueindex(1)); // set start time
}
@@ -106,8 +132,25 @@ lresume(lua_State *L) {
}
static int
lyield(lua_State *L) {
lua_pushthread(L);
lresume(lua_State *L) {
lua_pushvalue(L,1);
return timing_resume(L);
}
static int
lresume_co(lua_State *L) {
luaL_checktype(L, 2, LUA_TTHREAD);
lua_rotate(L, 2, -1);
return timing_resume(L);
}
static int
timing_yield(lua_State *L) {
#ifdef DEBUG_LOG
lua_State *from = lua_tothread(L, -1);
#endif
lua_rawget(L, lua_upvalueindex(2)); // check total time
if (lua_isnil(L, -1)) {
lua_pop(L,1);
@@ -120,7 +163,11 @@ lyield(lua_State *L) {
double starttime = lua_tonumber(L, -1);
lua_pop(L,1);
ti += diff_time(starttime);
double diff = diff_time(starttime);
ti += diff;
#ifdef DEBUG_LOG
fprintf(stderr, "PROFILE [%p] yield (%lf/%lf)\n", from, diff, ti);
#endif
lua_pushthread(L);
lua_pushnumber(L, ti);
@@ -132,6 +179,21 @@ lyield(lua_State *L) {
return co_yield(L);
}
static int
lyield(lua_State *L) {
lua_pushthread(L);
return timing_yield(L);
}
static int
lyield_co(lua_State *L) {
luaL_checktype(L, 1, LUA_TTHREAD);
lua_rotate(L, 1, -1);
return timing_yield(L);
}
int
luaopen_profile(lua_State *L) {
luaL_checkversion(L);
@@ -140,6 +202,8 @@ luaopen_profile(lua_State *L) {
{ "stop", lstop },
{ "resume", lresume },
{ "yield", lyield },
{ "resume_co", lresume_co },
{ "yield_co", lyield_co },
{ NULL, NULL },
};
luaL_newlibtable(L,l);
@@ -154,7 +218,7 @@ luaopen_profile(lua_State *L) {
lua_setmetatable(L, -3);
lua_setmetatable(L, -3);
lua_pushnil(L);
lua_pushnil(L); // cfunction (coroutine.resume or coroutine.yield)
luaL_setfuncs(L,l,3);
int libtable = lua_gettop(L);
@@ -166,20 +230,33 @@ luaopen_profile(lua_State *L) {
if (co_resume == NULL)
return luaL_error(L, "Can't get coroutine.resume");
lua_pop(L,1);
lua_getfield(L, libtable, "resume");
lua_pushcfunction(L, co_resume);
lua_setupvalue(L, -2, 3);
lua_pop(L,1);
lua_getfield(L, libtable, "resume_co");
lua_pushcfunction(L, co_resume);
lua_setupvalue(L, -2, 3);
lua_pop(L,1);
lua_getfield(L, -1, "yield");
lua_CFunction co_yield = lua_tocfunction(L, -1);
if (co_yield == NULL)
return luaL_error(L, "Can't get coroutine.yield");
lua_pop(L,1);
lua_getfield(L, libtable, "yield");
lua_pushcfunction(L, co_yield);
lua_setupvalue(L, -2, 3);
lua_pop(L,1);
lua_getfield(L, libtable, "yield_co");
lua_pushcfunction(L, co_yield);
lua_setupvalue(L, -2, 3);
lua_pop(L,1);
lua_settop(L, libtable);

View File

@@ -254,14 +254,41 @@ wb_table_hash(lua_State *L, struct write_block * wb, int index, int depth, int a
wb_nil(wb);
}
static void
wb_table_metapairs(lua_State *L, struct write_block *wb, int index, int depth) {
uint8_t n = COMBINE_TYPE(TYPE_TABLE, 0);
wb_push(wb, &n, 1);
lua_pushvalue(L, index);
lua_call(L, 1, 3);
for(;;) {
lua_pushvalue(L, -2);
lua_pushvalue(L, -2);
lua_copy(L, -5, -3);
lua_call(L, 2, 2);
int type = lua_type(L, -2);
if (type == LUA_TNIL) {
lua_pop(L, 4);
break;
}
pack_one(L, wb, -2, depth);
pack_one(L, wb, -1, depth);
lua_pop(L, 1);
}
wb_nil(wb);
}
static void
wb_table(lua_State *L, struct write_block *wb, int index, int depth) {
luaL_checkstack(L, LUA_MINSTACK, NULL);
if (index < 0) {
index = lua_gettop(L) + index + 1;
}
int array_size = wb_table_array(L, wb, index, depth);
wb_table_hash(L, wb, index, depth, array_size);
if (luaL_getmetafield(L, index, "__pairs") != LUA_TNIL) {
wb_table_metapairs(L, wb, index, depth);
} else {
int array_size = wb_table_array(L, wb, index, depth);
wb_table_hash(L, wb, index, depth, array_size);
}
}
static void
@@ -524,7 +551,7 @@ seri(lua_State *L, struct block *b, int len) {
}
int
_luaseri_unpack(lua_State *L) {
luaseri_unpack(lua_State *L) {
if (lua_isnoneornil(L,1)) {
return 0;
}
@@ -545,7 +572,7 @@ _luaseri_unpack(lua_State *L) {
return luaL_error(L, "deserialize null pointer");
}
lua_settop(L,0);
lua_settop(L,1);
struct read_block rb;
rball_init(&rb, buffer, len);
@@ -564,11 +591,11 @@ _luaseri_unpack(lua_State *L) {
// Need not free buffer
return lua_gettop(L);
return lua_gettop(L) - 1;
}
int
_luaseri_pack(lua_State *L) {
luaseri_pack(lua_State *L) {
struct block temp;
temp.next = NULL;
struct write_block wb;

View File

@@ -3,7 +3,7 @@
#include <lua.h>
int _luaseri_pack(lua_State *L);
int _luaseri_unpack(lua_State *L);
int luaseri_pack(lua_State *L);
int luaseri_unpack(lua_State *L);
#endif

View File

@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "atomic.h"
#define KEYTYPE_INTEGER 0
#define KEYTYPE_STRING 1
@@ -35,8 +36,6 @@ struct node {
uint8_t nocolliding; // 0 means colliding slot
};
struct table;
struct state {
int dirty;
int ref;
@@ -376,6 +375,7 @@ pconv(lua_State *L) {
static void
convert_stringmap(struct context *ctx, struct table *tbl) {
lua_State *L = ctx->L;
lua_checkstack(L, ctx->string_index + LUA_MINSTACK);
lua_settop(L, ctx->string_index + 1);
lua_pushvalue(L, 1);
struct state * s = lua_newuserdata(L, sizeof(*s));
@@ -662,7 +662,7 @@ releaseobj(lua_State *L) {
struct ctrl *c = lua_touserdata(L, 1);
struct table *tbl = c->root;
struct state *s = lua_touserdata(tbl->L, 1);
__sync_fetch_and_sub(&s->ref, 1);
ATOM_DEC(&s->ref);
c->root = NULL;
c->update = NULL;
@@ -673,7 +673,7 @@ static int
lboxconf(lua_State *L) {
struct table * tbl = get_table(L,1);
struct state * s = lua_touserdata(tbl->L, 1);
__sync_fetch_and_add(&s->ref, 1);
ATOM_INC(&s->ref);
struct ctrl * c = lua_newuserdata(L, sizeof(*c));
c->root = tbl;
@@ -718,7 +718,7 @@ static int
lincref(lua_State *L) {
struct table *tbl = get_table(L,1);
struct state * s = lua_touserdata(tbl->L, 1);
int ref = __sync_add_and_fetch(&s->ref, 1);
int ref = ATOM_INC(&s->ref);
lua_pushinteger(L , ref);
return 1;
@@ -728,7 +728,7 @@ static int
ldecref(lua_State *L) {
struct table *tbl = get_table(L,1);
struct state * s = lua_touserdata(tbl->L, 1);
int ref = __sync_sub_and_fetch(&s->ref, 1);
int ref = ATOM_DEC(&s->ref);
lua_pushinteger(L , ref);
return 1;

Some files were not shown because too many files have changed in this diff Show More