Codebase list lua-systemd / 06479f5
New upstream version 0~git20160517 Sophie Brun 7 years ago
38 changed file(s) with 7652 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 *.o
1 *.so
2 *.rock
0 The MIT License (MIT)
1
2 Copyright (c) 2014 Daurnimator
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
0 # [Systemd](http://freedesktop.org/wiki/Software/systemd/) for Lua.
1
2 This library is for working with systemd from scripts and daemons written in Lua.
3
4 Where necessary, the low level `libsystemd` functions have been bound in C.
5 Higher level functions with more idiomatic lua semantics are written in Lua on top of these C primitives.
6
7 Compatible with Lua 5.1, 5.2 and 5.3 (thanks [compat-5.3](https://github.com/keplerproject/lua-compat-5.3)).
8
9
10 # Status
11
12 Waiting for API to stabilise before making an initial release.
13
14
15 ## Todo
16
17 - [x] [Notify](http://www.freedesktop.org/software/systemd/man/sd_notify.html) - Notify service manager about start-up completion and other daemon status changes
18 - [x] [ID128](http://www.freedesktop.org/software/systemd/man/sd-id128.html) - APIs for processing 128-bit IDs
19 - [x] [Journal](http://www.freedesktop.org/software/systemd/man/sd-journal.html)
20 - [x] [Journal Writing](http://www.freedesktop.org/software/systemd/man/sd_journal_sendv.html)
21 - [x] [Journal Reading](http://www.freedesktop.org/software/systemd/man/sd_journal_next.html)
22 - [x] [Journal Change Notification](http://www.freedesktop.org/software/systemd/man/sd_journal_get_fd.html)
23 - [x] [Login](http://www.freedesktop.org/software/systemd/man/sd-login.html)
24 - [x] [PID/Peer Information](http://www.freedesktop.org/software/systemd/man/sd_pid_get_session.html)
25 - [x] [User State](http://www.freedesktop.org/software/systemd/man/sd_uid_get_state.html)
26 - [x] [Session Information](http://www.freedesktop.org/software/systemd/man/sd_session_is_active.html)
27 - [x] [Seat Information](http://www.freedesktop.org/software/systemd/man/sd_seat_get_active.html)
28 - [x] [Login Monitoring](http://www.freedesktop.org/software/systemd/man/sd_login_monitor.html) - Monitor login sessions, seats, users and virtual machines/containers
29 - [ ] Unit Control - Requires use of [dbus API](http://www.freedesktop.org/wiki/Software/systemd/dbus/)
30
31
32 # Installation
33
34 lua-systemd is on luarocks: https://luarocks.org/modules/daurnimator/systemd
35
36 Install via luarocks: `luarocks install --server=http://luarocks.org/manifests/daurnimator systemd`
37
38
39 # Usage
40
41 ## Bound from C
42
43 All functions return `nil, error_message [, errno]` in case of error.
44
45 C | Lua | Comments
46 -----------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------|----------------------------------------
47 [`SD_LISTEN_FDS_START`](http://www.freedesktop.org/software/systemd/man/SD_LISTEN_FDS_START.html) | `systemd.daemon.LISTEN_FDS_START` |
48 [`sd_notify()`](http://www.freedesktop.org/software/systemd/man/sd_notify.html) | `systemd.daemon.notify()` |
49 [`sd_pid_notify()`](http://www.freedesktop.org/software/systemd/man/sd_pid_notify.html) | `systemd.daemon.pid_notify()` |
50 [`sd_pid_notify_with_fds()`](http://www.freedesktop.org/software/systemd/man/sd_pid_notify_with_fds.html) | `systemd.daemon.pid_notify_with_fds()` |
51 [`sd_booted()`](http://www.freedesktop.org/software/systemd/man/sd_booted.html) | `systemd.daemon.booted()` |
52 [`sd_listen_fds()`](http://www.freedesktop.org/software/systemd/man/sd_listen_fds.html) | `systemd.daemon.listen_fds()` |
53 [`sd_journal_sendv()`](http://www.freedesktop.org/software/systemd/man/sd_journal_sendv.html) | `systemd.journal.sendv()` |
54 [`sd_journal_perror()`](http://www.freedesktop.org/software/systemd/man/sd_journal_perror.html) | `systemd.journal.perror()` |
55 [`sd_journal_stream_fd()`](http://www.freedesktop.org/software/systemd/man/sd_journal_stream_fd.html) | `systemd.journal.stream_fd()` | On success, returns a Lua `file` object instead of raw file descriptor
56 [`SD_JOURNAL_LOCAL_ONLY`](http://www.freedesktop.org/software/systemd/man/SD_JOURNAL_LOCAL_ONLY.html) | `systemd.journal.OPEN.LOCAL_ONLY` |
57 [`SD_JOURNAL_RUNTIME_ONLY`](http://www.freedesktop.org/software/systemd/man/SD_JOURNAL_RUNTIME_ONLY.html) | `systemd.journal.OPEN.RUNTIME_ONLY` |
58 [`SD_JOURNAL_SYSTEM`](http://www.freedesktop.org/software/systemd/man/SD_JOURNAL_SYSTEM.html) | `systemd.journal.OPEN.SYSTEM` |
59 [`SD_JOURNAL_CURRENT_USER`](http://www.freedesktop.org/software/systemd/man/SD_JOURNAL_CURRENT_USER.html) | `systemd.journal.OPEN.CURRENT_USER` |
60 [`sd_journal_open()`](http://www.freedesktop.org/software/systemd/man/sd_journal_open.html) | `systemd.journal.open()` |
61 [`sd_journal_open_directory()`](http://www.freedesktop.org/software/systemd/man/sd_journal_open_directory.html) | `systemd.journal.open_directory()` |
62 [`sd_journal_open_files()`](http://www.freedesktop.org/software/systemd/man/sd_journal_open_files.html) | `systemd.journal.open_files()` |
63 [`sd_journal_open_container()`](http://www.freedesktop.org/software/systemd/man/sd_journal_open_container.html) | `systemd.journal.open_container()` |
64 [`sd_journal_close()`](http://www.freedesktop.org/software/systemd/man/sd_journal_close.html) | | Bound as `__gc` metamethod on journal objects
65 [`sd_journal_get_cutoff_realtime_usec()`](http://www.freedesktop.org/software/systemd/man/sd_journal_get_cutoff_realtime_usec.html) | `my_journal:get_cutoff_realtime_usec()` |
66 [`sd_journal_get_cutoff_monotonic_usec()`](http://www.freedesktop.org/software/systemd/man/sd_journal_get_cutoff_monotonic_usec.html) | `my_journal:get_cutoff_monotonic_usec()` |
67 [`sd_journal_get_usage()`](http://www.freedesktop.org/software/systemd/man/sd_journal_get_usage.html) | `my_journal:get_usage()` |
68 [`sd_journal_next()`](http://www.freedesktop.org/software/systemd/man/sd_journal_next.html) | `my_journal:next()` |
69 [`sd_journal_next_skip()`](http://www.freedesktop.org/software/systemd/man/sd_journal_next_skip.html) | `my_journal:next_skip()` |
70 [`sd_journal_previous()`](http://www.freedesktop.org/software/systemd/man/sd_journal_previous.html) | `my_journal:previous()` |
71 [`sd_journal_previous_skip()`](http://www.freedesktop.org/software/systemd/man/sd_journal_previous_skip.html) | `my_journal:previous_skip()` |
72 [`sd_journal_seek_head()`](http://www.freedesktop.org/software/systemd/man/sd_journal_seek_head.html) | `my_journal:seek_head()` |
73 [`sd_journal_seek_tail()`](http://www.freedesktop.org/software/systemd/man/sd_journal_seek_tail.html) | `my_journal:seek_tail()` |
74 [`sd_journal_seek_monotonic_usec()`](http://www.freedesktop.org/software/systemd/man/sd_journal_seek_monotonic_usec.html) | `my_journal:seek_monotonic_usec()` |
75 [`sd_journal_seek_realtime_usec()`](http://www.freedesktop.org/software/systemd/man/sd_journal_seek_realtime_usec.html) | `my_journal:seek_realtime_usec()` |
76 [`sd_journal_seek_cursor()`](http://www.freedesktop.org/software/systemd/man/sd_journal_seek_cursor.html) | `my_journal:seek_cursor()` |
77 [`sd_journal_get_cursor()`](http://www.freedesktop.org/software/systemd/man/sd_journal_get_cursor.html) | `my_journal:get_cursor()` |
78 [`sd_journal_test_cursor()`](http://www.freedesktop.org/software/systemd/man/sd_journal_test_cursor.html) | `my_journal:test_cursor()` |
79 [`sd_journal_get_realtime_usec()`](http://www.freedesktop.org/software/systemd/man/sd_journal_get_realtime_usec.html) | `my_journal:get_realtime_usec()` |
80 [`sd_journal_get_monotonic_usec()`](http://www.freedesktop.org/software/systemd/man/sd_journal_get_monotonic_usec.html) | `my_journal:get_monotonic_usec()` |
81 [`sd_journal_get_data()`](http://www.freedesktop.org/software/systemd/man/sd_journal_get_data.html) | `my_journal:get_data()` |
82 [`sd_journal_enumerate_data()`](http://www.freedesktop.org/software/systemd/man/sd_journal_enumerate_data.html) | `my_journal:enumerate_data()` |
83 [`sd_journal_restart_data()`](http://www.freedesktop.org/software/systemd/man/sd_journal_restart_data.html) | `my_journal:restart_data()` |
84 [`sd_journal_query_unique()`](http://www.freedesktop.org/software/systemd/man/sd_journal_query_unique.html) | `my_journal:query_unique()` |
85 [`sd_journal_enumerate_unique()`](http://www.freedesktop.org/software/systemd/man/sd_journal_enumerate_unique.html) | `my_journal:enumerate_unique()` |
86 [`sd_journal_restart_unique()`](http://www.freedesktop.org/software/systemd/man/sd_journal_restart_unique.html) | `my_journal:restart_unique()` |
87 [`sd_journal_set_data_threshold()`](http://www.freedesktop.org/software/systemd/man/sd_journal_set_data_threshold.html) | `my_journal:set_data_threshold()` |
88 [`sd_journal_get_data_threshold()`](http://www.freedesktop.org/software/systemd/man/sd_journal_get_data_threshold.html) | `my_journal:get_data_threshold()` |
89 [`sd_journal_add_match()`](http://www.freedesktop.org/software/systemd/man/sd_journal_add_match.html) | `my_journal:add_match()` |
90 [`sd_journal_add_disjunction()`](http://www.freedesktop.org/software/systemd/man/sd_journal_add_disjunction.html) | `my_journal:add_disjunction()` |
91 [`sd_journal_add_conjunction()`](http://www.freedesktop.org/software/systemd/man/sd_journal_add_conjunction.html) | `my_journal:add_conjunction()` |
92 [`sd_journal_flush_matches()`](http://www.freedesktop.org/software/systemd/man/sd_journal_flush_matches.html) | `my_journal:flush_matches()` |
93 [`SD_JOURNAL_NOP`](http://www.freedesktop.org/software/systemd/man/SD_JOURNAL_NOP.html) | `systemd.journal.WAKEUP.NOP` |
94 [`SD_JOURNAL_APPEND`](http://www.freedesktop.org/software/systemd/man/SD_JOURNAL_APPEND.html) | `systemd.journal.WAKEUP.APPEND` |
95 [`SD_JOURNAL_INVALIDATE`](http://www.freedesktop.org/software/systemd/man/SD_JOURNAL_INVALIDATE.html) | `systemd.journal.WAKEUP.INVALIDATE` |
96 [`sd_journal_get_fd()`](http://www.freedesktop.org/software/systemd/man/sd_journal_get_fd.html) | `my_journal:get_fd()` |
97 [`sd_journal_get_events()`](http://www.freedesktop.org/software/systemd/man/sd_journal_get_events.html) | `my_journal:get_events()` |
98 [`sd_journal_get_timeout()`](http://www.freedesktop.org/software/systemd/man/sd_journal_get_timeout.html) | `my_journal:get_timeout()` | Returns `false` if timeout isn't available, otherwise returns value in seconds
99 [`sd_journal_process()`](http://www.freedesktop.org/software/systemd/man/sd_journal_process.html) | `my_journal:process()` |
100 [`sd_journal_wait()`](http://www.freedesktop.org/software/systemd/man/sd_journal_wait.html) | `my_journal:wait()` | `timeout` is in seconds instead of microseconds
101 [`sd_journal_reliable_fd()`](http://www.freedesktop.org/software/systemd/man/sd_journal_reliable_fd.html) | `my_journal:reliable_fd()` |
102 [`sd_id128_randomize()`](http://www.freedesktop.org/software/systemd/man/sd_id128_randomize.html) | `systemd.id128.randomize()` | Also available as `randomise` for any non-americans out there
103 [`sd_id128_from_string()`](http://www.freedesktop.org/software/systemd/man/sd_id128_from_string.html) | `systemd.id128.from_string()` |
104 [`sd_id128_get_machine()`](http://www.freedesktop.org/software/systemd/man/sd_id128_get_machine.html) | `systemd.id128.get_machine()` |
105 [`sd_id128_get_boot()`](http://www.freedesktop.org/software/systemd/man/sd_id128_get_boot.html) | `systemd.id128.get_boot()` |
106 [`sd_id128_to_string()`](http://www.freedesktop.org/software/systemd/man/sd_id128_to_string.html) | `my_id128:to_string()` | Also available as `__tostring` metamethod: `tostring(my_id128_t)`
107 [`sd_id128_equal()`](http://www.freedesktop.org/software/systemd/man/sd_id128_equal.html) | `id128_a == id128_b` | Bound as `__eq` metamethod
108 [`sd_journal_get_catalog_for_message_id()`](http://www.freedesktop.org/software/systemd/man/sd_journal_get_catalog_for_message_id.html) | `my_id128:get_catalog()` |
109 [`sd_get_seats()`](http://www.freedesktop.org/software/systemd/man/sd_get_seats.html) | `systemd.login.get_seats()` |
110 [`sd_get_sessions()`](http://www.freedesktop.org/software/systemd/man/sd_get_sessions.html) | `systemd.login.get_sessions()` |
111 [`sd_get_uids()`](http://www.freedesktop.org/software/systemd/man/sd_get_uids.html) | `systemd.login.get_uids()` |
112 [`sd_get_machine_names()`](http://www.freedesktop.org/software/systemd/man/sd_get_machine_names.html) | `systemd.login.get_machine_names()` |
113 [`sd_pid_get_session()`](http://www.freedesktop.org/software/systemd/man/sd_pid_get_session.html) | `systemd.login.pid_get_session()` |
114 [`sd_pid_get_unit()`](http://www.freedesktop.org/software/systemd/man/sd_pid_get_unit.html) | `systemd.login.pid_get_unit()` |
115 [`sd_pid_get_user_unit()`](http://www.freedesktop.org/software/systemd/man/sd_pid_get_user_unit.html) | `systemd.login.pid_get_user_unit()` |
116 [`sd_pid_get_owner_uid()`](http://www.freedesktop.org/software/systemd/man/sd_pid_get_owner_uid.html) | `systemd.login.pid_get_owner_uid()` |
117 [`sd_pid_get_machine_name()`](http://www.freedesktop.org/software/systemd/man/sd_pid_get_machine_name.html) | `systemd.login.pid_get_machine_name()` |
118 [`sd_pid_get_slice()`](http://www.freedesktop.org/software/systemd/man/sd_pid_get_slice.html) | `systemd.login.pid_get_slice()` |
119 [`sd_pid_get_user_slice()`](http://www.freedesktop.org/software/systemd/man/sd_pid_get_user_slice.html) | `systemd.login.pid_get_user_slice()` |
120 [`sd_peer_get_session()`](http://www.freedesktop.org/software/systemd/man/sd_peer_get_session.html) | `systemd.login.peer_get_session()` |
121 [`sd_peer_get_unit()`](http://www.freedesktop.org/software/systemd/man/sd_peer_get_unit.html) | `systemd.login.peer_get_unit()` |
122 [`sd_peer_get_user_unit()`](http://www.freedesktop.org/software/systemd/man/sd_peer_get_user_unit.html) | `systemd.login.peer_get_user_unit()` |
123 [`sd_peer_get_owner_uid()`](http://www.freedesktop.org/software/systemd/man/sd_peer_get_owner_uid.html) | `systemd.login.peer_get_owner_uid()` |
124 [`sd_peer_get_machine_name()`](http://www.freedesktop.org/software/systemd/man/sd_peer_get_machine_name.html) | `systemd.login.peer_get_machine_name()` |
125 [`sd_peer_get_slice()`](http://www.freedesktop.org/software/systemd/man/sd_peer_get_slice.html) | `systemd.login.peer_get_slice()` |
126 [`sd_peer_get_user_slice()`](http://www.freedesktop.org/software/systemd/man/sd_peer_get_user_slice.html) | `systemd.login.peer_get_user_slice()` |
127 [`sd_uid_get_state()`](http://www.freedesktop.org/software/systemd/man/sd_uid_get_state.html) | `systemd.login.uid_get_state()` |
128 [`sd_uid_is_on_seat()`](http://www.freedesktop.org/software/systemd/man/sd_uid_is_on_seat.html) | `systemd.login.uid_is_on_seat()` |
129 [`sd_uid_get_sessions()`](http://www.freedesktop.org/software/systemd/man/sd_uid_get_sessions.html) | `systemd.login.uid_get_sessions()` |
130 [`sd_uid_get_seats()`](http://www.freedesktop.org/software/systemd/man/sd_uid_get_seats.html) | `systemd.login.uid_get_seats()` |
131 [`sd_uid_get_display()`](http://www.freedesktop.org/software/systemd/man/sd_uid_get_display.html) | `systemd.login.uid_get_display()` |
132 [`sd_session_is_active()`](http://www.freedesktop.org/software/systemd/man/sd_session_is_active.html) | `systemd.login.session_is_active()` |
133 [`sd_session_is_remote()`](http://www.freedesktop.org/software/systemd/man/sd_session_is_remote.html) | `systemd.login.session_is_remote()` |
134 [`sd_session_get_state()`](http://www.freedesktop.org/software/systemd/man/sd_session_get_state.html) | `systemd.login.session_get_state()` |
135 [`sd_session_get_uid()`](http://www.freedesktop.org/software/systemd/man/sd_session_get_uid.html) | `systemd.login.session_get_uid()` |
136 [`sd_session_get_seat()`](http://www.freedesktop.org/software/systemd/man/sd_session_get_seat.html) | `systemd.login.session_get_seat()` |
137 [`sd_session_get_service()`](http://www.freedesktop.org/software/systemd/man/sd_session_get_service.html) | `systemd.login.session_get_service()` |
138 [`sd_session_get_type()`](http://www.freedesktop.org/software/systemd/man/sd_session_get_type.html) | `systemd.login.session_get_type()` |
139 [`sd_session_get_class()`](http://www.freedesktop.org/software/systemd/man/sd_session_get_class.html) | `systemd.login.session_get_class()` |
140 [`sd_session_get_desktop()`](http://www.freedesktop.org/software/systemd/man/sd_session_get_desktop.html) | `systemd.login.session_get_desktop()` |
141 [`sd_session_get_display()`](http://www.freedesktop.org/software/systemd/man/sd_session_get_display.html) | `systemd.login.session_get_display()` |
142 [`sd_session_get_remote_host()`](http://www.freedesktop.org/software/systemd/man/sd_session_get_remote_host.html) | `systemd.login.session_get_remote_host()`|
143 [`sd_session_get_remote_user()`](http://www.freedesktop.org/software/systemd/man/sd_session_get_remote_user.html) | `systemd.login.session_get_remote_user()`|
144 [`sd_session_get_tty()`](http://www.freedesktop.org/software/systemd/man/sd_session_get_tty.html) | `systemd.login.session_get_tty()` |
145 [`sd_session_get_vt()`](http://www.freedesktop.org/software/systemd/man/sd_session_get_vt.html) | `systemd.login.session_get_vt()` |
146 [`sd_seat_get_active()`](http://www.freedesktop.org/software/systemd/man/sd_seat_get_active.html) | `systemd.login.seat_get_active()` | On success, returns `session, uid`
147 [`sd_seat_get_sessions()`](http://www.freedesktop.org/software/systemd/man/sd_seat_get_sessions.html) | `systemd.login.seat_get_sessions()` | On success, returns `sessions, uids`
148 [`sd_seat_can_multi_session()`](http://www.freedesktop.org/software/systemd/man/sd_seat_can_multi_session.html) | `systemd.login.seat_can_multi_session()` |
149 [`sd_seat_can_tty()`](http://www.freedesktop.org/software/systemd/man/sd_seat_can_tty.html) | `systemd.login.seat_can_tty()` |
150 [`sd_seat_can_graphical()`](http://www.freedesktop.org/software/systemd/man/sd_seat_can_graphical.html) | `systemd.login.seat_can_graphical()` |
151 [`sd_machine_get_class()`](http://www.freedesktop.org/software/systemd/man/sd_machine_get_class.html) | `systemd.login.machine_get_class()` |
152 [`sd_machine_get_ifindices()`](http://www.freedesktop.org/software/systemd/man/sd_machine_get_ifindices.html) | `systemd.login.machine_get_ifindices()` |
153 [`sd_login_monitor_new()`](http://www.freedesktop.org/software/systemd/man/sd_login_monitor_new.html) | `systemd.login.monitor()` |
154 [`sd_login_monitor_unref()`](http://www.freedesktop.org/software/systemd/man/sd_login_monitor_unref.html) | | Bound as `__gc` metamethod on monitor objects
155 [`sd_login_monitor_flush()`](http://www.freedesktop.org/software/systemd/man/sd_login_monitor_flush.html) | `my_login_monitor:flush()` |
156 [`sd_login_monitor_get_fd()`](http://www.freedesktop.org/software/systemd/man/sd_login_monitor_get_fd.html) | `my_login_monitor:get_fd()` |
157 [`sd_login_monitor_get_events()`](http://www.freedesktop.org/software/systemd/man/sd_login_monitor_get_events.html) | `my_login_monitor:get_events()` |
158 [`sd_login_monitor_get_timeout()`](http://www.freedesktop.org/software/systemd/man/sd_login_monitor_get_timeout.html) | `my_login_monitor:get_timeout()` | Returns `false` if timeout isn't available, otherwise returns value in seconds
159
160
161 ## Misc extras
162
163 ### `systemd.daemon.notifyt(tbl)` and `systemd.daemon.pid_notifyt(tbl)`
164
165 Like `notify`, but takes a lua table instead of a newline delimited list.
166 Numbers will be coerced to strings.
167
168 ```lua
169 notifyt { READY = 1, STATUS = "Server now accepting connections", WATCHDOG = 1 }
170 ```
171
172
173 ### `interval = systemd.daemon.watchdog_enabled()`
174
175 Returns the watchdog interval (in seconds) if there is one set otherwise returns `false`.
176
177 You should call `kick_dog` or `notify("WATCHDOG=1")` every half of this interval.
178
179 Similar functionality to [`sd_watchdog_enabled()`](http://www.freedesktop.org/software/systemd/man/sd_watchdog_enabled.html)
180
181
182 ### `systemd.daemon.kick_dog()`
183
184 Tells systemd to update the watchdog timestamp.
185 This should be called on an interval.
186
187
188 ### `systemd.journal.LOG`
189
190 Table containing the `syslog(3)` priority constants: `EMERG`, `ALERT`, `CRIT`, `ERR`, `WARNING`, `NOTICE`, `INFO`, `DEBUG`
191
192 Useful as the second argument to `systemd.journal.streamfd()`
193
194
195 ### `systemd.journal.print(priority, fmt_string, ...)`
196
197 Same argument signature as C, but written in lua on top of `sendv()` and `string.format()`
198
199
200 ### `systemd.journal.sendt(tbl)`
201
202 Log a message to the journal with the key/value pairs from `tbl`
203
204 ```lua
205 systemd.journal.sendt {
206 SYSLOG_IDENTIFIER = "identifier" ;
207 SYSLOG_FACILITY = "facility" ;
208 PRIORITY = systemd.journal.LOG.ERR ;
209 MESSAGE = "something happended!" ;
210 MY_CUSTOM_FIELD = "extra detail.";
211 }
212 ```
213
214
215 ### `value = my_journal:get(field)`
216
217 Returns the given field from the current journal entry (which may be `nil`)
218
219 Throws a lua error on failure.
220
221
222 ### `my_journal:each_data()`
223
224 A valid lua iterator that enumerates through field, value pairs.
225
226 ```lua
227 for field, value in my_journal:each_data() do
228 print(field, value)
229 end
230 ```
231
232 Throws a lua error on failure.
233
234
235 ### `my_journal:each_unique(field_name)`
236
237 A valid lua iterator that enumerates through unique field values.
238
239 ```lua
240 -- Print each different `_SYSTEMD_UNIT`
241 for value in my_journal:each_unique("_SYSTEMD_UNIT") do
242 print(value)
243 end
244 ```
245
246 Throws a lua error on failure.
247
248
249 ### `t = my_journal:to_table()`
250
251 Converts the current journal entry to a lua table.
252
253 Includes [Address Fields](http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html#Address%20Fields):
254 - `__CURSOR`
255 - `__REALTIME_TIMESTAMP`
256 - `__MONOTONIC_TIMESTAMP`
257
258
259 ### `text = my_journal:get_catalog()`
260
261 Looks up the current journal entry's `MESSAGE_ID` in the [message catalog](http://www.freedesktop.org/wiki/Software/systemd/catalog/).
262 Substitutes the templated fields (between `@` symbols) with values from this journal entry.
263
264 Returns:
265 - the filled out catalogue entry as a string
266 - `false` if `MESSAGE_ID` is not set, or does not exist in the catalogue
267 - `nil, err_msg, errno` in case of failure.
268
269 Same functionality as [`sd_journal_get_catalog()`](http://www.freedesktop.org/software/systemd/man/sd_journal_get_catalog.html).
270
271
272 ### `systemd.messages`
273
274 A table of well-known message ids as `id128` objects.
275
276 Taken from [`sd-messages.h`](http://cgit.freedesktop.org/systemd/systemd/tree/src/systemd/sd-messages.h?id=HEAD)
0 #!/usr/bin/env lua
1 --[[
2 This program acts like journalctl --list-boots
3 ]]
4 local sj = require "systemd.journal"
5 local j = assert(sj.open())
6
7 local t = {}
8 local n = 0
9 for boot_id in j:each_unique("_BOOT_ID") do
10 local boot_info = {
11 id = boot_id;
12 }
13 n = n + 1
14 t[n] = boot_info
15
16 -- We need to find the first and last entries for each boot
17 assert(j:add_match("_BOOT_ID="..boot_id))
18
19 assert(j:seek_head())
20 assert(j:next())
21 boot_info.head = j:get_realtime_usec()
22
23 assert(j:seek_tail())
24 assert(j:previous())
25 boot_info.tail = j:get_realtime_usec()
26
27 j:flush_matches()
28 end
29
30 table.sort(t, function(a,b) return a.head < b.head end)
31
32 local d_width = math.floor(math.log(n, 10))+2
33 for i=1, n do
34 local boot_info = t[i]
35 io.write(string.format("%"..d_width.."d %s %s—%s\n",
36 i-n, boot_info.id,
37 os.date("%a %Y-%m-%d %H:%M:%S %Z", boot_info.head/1e6),
38 os.date("%a %Y-%m-%d %H:%M:%S %Z", boot_info.tail/1e6)
39 ))
40 end
0 local journal = require "systemd.journal"
1
2 function log(severity, msg, level)
3 local info = debug.getinfo((level or 1)+1, "nlS")
4 if info.currentline == -1 then
5 info.currentline = nil
6 end
7 return assert(journal.sendt{
8 CODE_FILE = info.short_src;
9 CODE_FUNC = info.name;
10 CODE_LINE = info.currentline;
11 PRIORITY = journal.LOG[severity:upper()] or 5;
12 MESSAGE = msg;
13 })
14 end
0 #!/usr/bin/env lua
1 --[[
2 This program acts like `journalctl --new-id128`
3 ]]
4
5 local id128 = require "systemd.id128"
6
7 local myuuid = tostring(assert(id128.randomise()))
8
9 io.write(table.concat({
10 "As string:",
11 myuuid,
12 "",
13 "As UUID:",
14 myuuid:gsub("(........)(....)(....)(....)(........)", "%1-%2-%3-%4-%5"),
15 "",
16 "As macro:",
17 "#define MESSAGE_XYZ SD_ID128_MAKE(" .. myuuid:gsub("(..)", "%1,"):sub(1,-2) .. ")",
18 "",
19 "As Python constant:",
20 ">>> import uuid",
21 ">>> MESSAGE_XYZ = uuid.UUID('" .. myuuid .. "')",
22 ""
23 },"\n"))
24
0 #!/usr/bin/env lua
1 --[[
2 This script will tail your journal.
3 Output will be in json format.
4
5 Uses the cqueues library (see http://25thandclement.com/~william/projects/cqueues.html)
6 ]]
7
8 local cqueues = require "cqueues"
9 local bit = require "bit32"
10 local json = require "dkjson"
11 local sj = require "systemd.journal"
12
13 local j = assert(sj.open())
14 assert(j:seek_tail())
15 assert(j:previous())
16
17 -- Wrap the journal object with an object that implements the cqueues.poll interface
18 local wrap_journal do
19 local methods = {}
20 function methods:pollfd()
21 return self.j:get_fd()
22 end
23 function methods:events()
24 local mask = self.j:get_events()
25 local events = ""
26 if bit.band(mask, 1) ~= 0 then
27 events = events .. "r"
28 end
29 if bit.band(mask, 4) ~= 0 then
30 events = events .. "w"
31 end
32 return events
33 end
34 function methods:timeout()
35 local m = self.j:get_timeout()
36 if type(m) == "number" then
37 local now = cqueues.monotime()
38 return m - now;
39 end
40 end
41 local mt = {
42 __index = function(t,k)
43 local f = methods[k]
44 if f ~= nil then return f end
45 -- Delegate to original journal methods
46 local f = t.j[k]
47 if type(f) == "function" then
48 -- Need to make sure the correct 'self' is passed through
49 return function(o, ...)
50 if o == t then
51 o = t.j
52 end
53 return f(o, ...)
54 end
55 end
56 end;
57 }
58 function wrap_journal(j)
59 return setmetatable({j = j}, mt)
60 end
61 end
62 local w = wrap_journal(j)
63
64 local q = cqueues.new()
65 q:wrap(function()
66 while true do
67 local a = cqueues.poll(w)
68 if a and a:process() ~= sj.WAKEUP.NOP then
69 while a:next() do
70 local t = assert(a:to_table())
71 print(json.encode(t))
72 end
73 end
74 end
75 end)
76 assert(q:loop())
0 #include "lua.h"
1 #include "lauxlib.h"
2 #include "compat-5.3.h"
3
4 #include <errno.h> /* ENOTSUP */
5 #include <sys/types.h> /* pid_t */
6
7 #include <systemd/sd-daemon.h>
8
9 #include "util.c"
10
11
12 shim_weak_stub_declare(int, sd_booted, (), -ENOTSUP)
13 shim_weak_stub_declare(int, sd_notify, (int unset_environment, const char *state), -ENOTSUP)
14 shim_weak_stub_declare(int, sd_pid_notify, (pid_t pid, int unset_environment, const char *state), -ENOTSUP)
15 shim_weak_stub_declare(int, sd_pid_notify_with_fds, (pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds), -ENOTSUP)
16 shim_weak_stub_declare(int, sd_listen_fds, (int unset_environment), -ENOTSUP)
17
18 static int handle_notify_result (lua_State *L, int err) {
19 if (err > 0) {
20 lua_pushboolean(L, 1);
21 return 1;
22 } else if (err == 0) {
23 lua_pushnil(L);
24 lua_pushliteral(L, "NOTIFY_SOCKET not set");
25 return 2;
26 } else {
27 return handle_error(L, -err);
28 }
29 }
30
31 static int notify (lua_State *L) {
32 int unset_environment = lua_toboolean(L, 1);
33 const char *state = luaL_checkstring(L, 2);
34 return handle_notify_result(L, shim_weak_stub(sd_notify)(unset_environment, state));
35 }
36
37 static int pid_notify (lua_State *L) {
38 pid_t pid = luaL_checkinteger(L, 1);
39 int unset_environment = lua_toboolean(L, 2);
40 const char *state = luaL_checkstring(L, 3);
41 return handle_notify_result(L, shim_weak_stub(sd_pid_notify)(pid, unset_environment, state));
42 }
43
44 static int pid_notify_with_fds (lua_State *L) {
45 pid_t pid = luaL_checkinteger(L, 1);
46 int unset_environment = lua_toboolean(L, 2);
47 const char *state = luaL_checkstring(L, 3);
48 int *fds;
49 unsigned n_fds;
50 unsigned i;
51 luaL_checktype(L, 4, LUA_TTABLE);
52 n_fds = lua_rawlen(L, 4);
53 fds = lua_newuserdata(L, n_fds*sizeof(int));
54 for (i=0; i < n_fds; i++) {
55 lua_rawgeti(L, 4, i+1);
56 luaL_argcheck(L, lua_type(L, -1) == LUA_TNUMBER && lua_isinteger(L, -1), 4, "expected array of file descritors (integers)");
57 fds[i] = lua_tointeger(L, -1);
58 lua_settop(L, 5);
59 }
60 return handle_notify_result(L, shim_weak_stub(sd_pid_notify_with_fds)(pid, unset_environment, state, fds, n_fds));
61 }
62
63 static int booted (lua_State *L) {
64 int booted = shim_weak_stub(sd_booted)();
65 if (booted >= 0) {
66 lua_pushboolean(L, booted);
67 return 1;
68 } else {
69 return handle_error(L, -booted);
70 }
71 }
72
73 static int listen_fds (lua_State *L) {
74 int unset_environment = lua_toboolean(L, 1);
75 int n_descriptors = shim_weak_stub(sd_listen_fds)(unset_environment);
76 if (n_descriptors < 0) {
77 return handle_error(L, -n_descriptors);
78 }
79 lua_pushinteger(L, n_descriptors);
80 return 1;
81 }
82
83 int luaopen_systemd_daemon_core (lua_State *L) {
84 lua_newtable(L);
85 /* 209 */
86 set_func_if_symbol_exists("sd_notify", L, notify, "notify");
87 set_func_if_symbol_exists("sd_booted", L, booted, "booted");
88 set_func_if_symbol_exists("sd_listen_fds", L, listen_fds, "listen_fds");
89 /* 214 */
90 set_func_if_symbol_exists("sd_pid_notify", L, pid_notify, "pid_notify");
91 /* 219 */
92 set_func_if_symbol_exists("sd_pid_notify_with_fds", L, pid_notify_with_fds, "pid_notify_with_fds");
93
94 lua_pushnumber(L, SD_LISTEN_FDS_START); lua_setfield(L, -2, "LISTEN_FDS_START");
95
96 return 1;
97 }
0 local c = require "systemd.daemon.core"
1
2 -- Wrap notify functions with versions that take tables
3 -- this lets you write `notifyt { READY=1, STATE="awesome!" }`
4 local function pack_state(t)
5 local state = { }
6 for k, v in pairs(t) do
7 state[#state+1] = k.."="..v
8 end
9 return table.concat(state, "\n")
10 end
11 function c.notifyt(t)
12 return c.notify(false, pack_state(t))
13 end
14 function c.pid_notifyt(pid, t)
15 return c.pid_notify(pid, false, pack_state(t))
16 end
17
18 -- Get our own pid in pure lua.
19 local function get_pid()
20 local fd, err, n = io.open "/proc/self/stat"
21 if fd == nil then return nil, err, n end
22 local pid = fd:read "*n"
23 fd:close()
24 return pid
25 end
26
27 -- sd_watchdog_enabled in pure lua.
28 -- returns watchdog interval
29 function c.watchdog_enabled(unset_environment)
30 if unset_environment then error("unset not supported", 2) end
31
32 local pid = os.getenv "WATCHDOG_PID"
33 if not pid then return false end
34 pid = tonumber(pid)
35 if pid ~= get_pid() then return false end
36
37 local usec = os.getenv "WATCHDOG_USEC"
38 usec = tonumber(usec)
39 if usec == nil then return nil, "invalid interval" end
40 return usec/1e6
41 end
42
43 function c.kick_dog()
44 return c.notify(false, "WATCHDOG=1")
45 end
46
47 return c
0 #include "lua.h"
1 #include "lauxlib.h"
2 #include "compat-5.3.h"
3
4 #include <systemd/sd-id128.h>
5
6 #include "util.c"
7 #include "id128.h"
8 #include "messages.h"
9
10
11 static int randomize (lua_State *L) {
12 sd_id128_t *ret = lua_newuserdata(L, sizeof(sd_id128_t));
13 int err = sd_id128_randomize(ret);
14 if (err < 0) return handle_error(L, -err);
15 luaL_setmetatable(L, ID128_METATABLE);
16 return 1;
17 }
18
19 static int from_string (lua_State *L) {
20 size_t l;
21 const char *s = luaL_checklstring(L, 1, &l);
22 if (l != 32 && l != 37) return luaL_argerror(L, 1, "string must be 32 hex characters or a 37 character formatted RFC UUID");
23 sd_id128_t *ret = lua_newuserdata(L, sizeof(sd_id128_t));
24 int err = sd_id128_from_string(s, ret);
25 if (err < 0) return handle_error(L, -err);
26 luaL_setmetatable(L, ID128_METATABLE);
27 return 1;
28 }
29
30 static int get_machine (lua_State *L) {
31 sd_id128_t *ret = lua_newuserdata(L, sizeof(sd_id128_t));
32 int err = sd_id128_get_machine(ret);
33 if (err < 0) return handle_error(L, -err);
34 luaL_setmetatable(L, ID128_METATABLE);
35 return 1;
36 }
37
38 static int get_boot (lua_State *L) {
39 sd_id128_t *ret = lua_newuserdata(L, sizeof(sd_id128_t));
40 int err = sd_id128_get_boot(ret);
41 if (err < 0) return handle_error(L, -err);
42 luaL_setmetatable(L, ID128_METATABLE);
43 return 1;
44 }
45
46 static int equal (lua_State *L) {
47 sd_id128_t *a = luaL_checkudata(L, 1, ID128_METATABLE);
48 sd_id128_t *b = luaL_checkudata(L, 2, ID128_METATABLE);
49 lua_pushboolean(L, sd_id128_equal(*a, *b));
50 return 1;
51 }
52
53 static int to_string (lua_State *L) {
54 sd_id128_t *a = luaL_checkudata(L, 1, ID128_METATABLE);
55 char s[33];
56 sd_id128_to_string(*a, s);
57 lua_pushlstring(L, s, 32);
58 return 1;
59 }
60
61 int luaopen_systemd_id128_core (lua_State *L) {
62 static const luaL_Reg lib[] = {
63 {"randomize", randomize},
64 {"from_string", from_string},
65 {"get_machine", get_machine},
66 {"get_boot", get_boot},
67 {NULL, NULL}
68 };
69 luaL_newlib(L, lib);
70
71 static const luaL_Reg meta[] = {
72 {"__eq", equal},
73 {"__tostring", to_string},
74 {NULL, NULL}
75 };
76
77 static const luaL_Reg methods[] = {
78 {"to_string", to_string},
79 {"get_catalog", journal_get_catalog_for_message_id},
80 {NULL, NULL}
81 };
82
83 if (luaL_newmetatable(L, ID128_METATABLE)) {
84 luaL_newlib(L, methods);
85 lua_setfield(L, -2, "__index");
86 luaL_setfuncs(L, meta, 0);
87 }
88 /* Expose id128 methods */
89 lua_getfield(L, -1, "__index");
90 lua_setfield(L, -3, "ID128_METHODS");
91
92 lua_pop(L, 1);
93
94 return 1;
95 }
0 #include "lua.h"
1 #include "lauxlib.h"
2
3 #include <systemd/sd-id128.h>
4
5
6 #define ID128_METATABLE "ID128"
7
8 static sd_id128_t check_id128_t (lua_State *L, int arg) {
9 sd_id128_t boot_id;
10 switch(lua_type(L, arg)) {
11 case LUA_TUSERDATA:
12 return *(sd_id128_t*)luaL_checkudata(L, arg, ID128_METATABLE);
13 case LUA_TSTRING:
14 luaL_argcheck(L, sd_id128_from_string(lua_tostring(L, arg), &boot_id) == 0, arg, "string is not a valid id128");
15 return boot_id;
16 default:
17 luaL_argerror(L, arg, lua_pushfstring(L, "id128 expected, got %s", luaL_typename(L, arg)));
18 /* unreachable */
19 }
20 }
21
22 int luaopen_systemd_id128_core (lua_State *L);
0 local c = require "systemd.id128.core"
1 local methods = c.ID128_METHODS
2
3 c.randomise = c.randomize
4
5 return c
0 return {
1 daemon = require "systemd.daemon" ;
2 id128 = require "systemd.id128" ;
3 journal = require "systemd.journal" ;
4 login = require "systemd.login" ;
5 messages = require "systemd.messages" ;
6 }
0 #include "lua.h"
1 #include "lauxlib.h"
2 #include "compat-5.3.h"
3
4 #include <stdlib.h> /* free */
5 #include <stdio.h> /* FILE, fdopen, fclose */
6 #include <stdint.h> /* uint64_t */
7 #include <sys/uio.h> /* struct iovec */
8 #include <errno.h>
9
10 #define SD_JOURNAL_SUPPRESS_LOCATION
11 #include <systemd/sd-journal.h>
12
13 #include "util.c"
14 #include "journal.h"
15 #include "id128.h"
16
17
18 static int handle_log_result (lua_State *L, int err) {
19 if (err == 0) {
20 lua_pushboolean(L, 1);
21 return 1;
22 } else {
23 return handle_error(L, -err);
24 }
25 }
26
27 static int sendv (lua_State *L) {
28 int res;
29 size_t i, n;
30 struct iovec *iov;
31 luaL_checktype(L, 1, LUA_TTABLE);
32 n = lua_rawlen(L, 1);
33 iov = lua_newuserdata(L, n*sizeof(struct iovec)); /* allocate via lua so we get free cleanup */
34 for (i=0; i<n; i++) {
35 lua_rawgeti(L, 1, i+1);
36 /* Make sure value is a string, we do **not** want automatic coercion */
37 if (lua_type(L, -1) != LUA_TSTRING) {
38 return luaL_argerror(L, 1, "non-string table entry");
39 }
40 iov[i].iov_base = (void*)lua_tolstring(L, -1, &iov[i].iov_len);
41 lua_pop(L, 1);
42 }
43 res = sd_journal_sendv(iov, n);
44 return handle_log_result(L, res);
45 }
46
47 static int _perror (lua_State *L) {
48 const char *message = luaL_checkstring(L, 1);
49 return handle_log_result(L, sd_journal_perror(message));
50 }
51
52 /* From http://www.lua.org/source/5.2/liolib.c.html#io_fclose */
53 static int io_fclose (lua_State *L) {
54 luaL_Stream *p = (luaL_Stream *)luaL_checkudata(L, 1, LUA_FILEHANDLE);
55 FILE *pf = p->f;
56 int res = fclose(pf);
57 return luaL_fileresult(L, (res == 0), NULL);
58 }
59
60 static int stream_fd (lua_State *L) {
61 int fd;
62 const char *identifier = luaL_checkstring(L, 1);
63 int priority = luaL_checkinteger(L, 2);
64 int level_prefix = lua_toboolean(L, 3); /* Optional arg, defaults to false */
65 luaL_Stream *p = (luaL_Stream *)lua_newuserdata(L, sizeof(luaL_Stream));
66 p->closef = NULL; /* create a `closed' file handle before opening file, in case of errors */
67 luaL_setmetatable(L, LUA_FILEHANDLE);
68 fd = sd_journal_stream_fd(identifier, priority, level_prefix);
69 if (fd < 0) return handle_error(L, -fd);
70 p->f = fdopen(fd, "w");
71 if (!p->f) return handle_error(L, errno);
72 p->closef = &io_fclose;
73 return 1;
74 }
75
76 static int journal_open (lua_State *L) {
77 int err;
78 int flags = luaL_optinteger(L, 1, 0);
79 sd_journal **j = lua_newuserdata(L, sizeof(sd_journal*));
80 err = sd_journal_open(j, flags);
81 if (err != 0) return handle_error(L, -err);
82 luaL_setmetatable(L, JOURNAL_METATABLE);
83 return 1;
84 }
85
86 static int journal_open_directory (lua_State *L) {
87 int err;
88 const char *path = luaL_checkstring(L, 1);
89 int flags = luaL_optinteger(L, 2, 0);
90 sd_journal **j = lua_newuserdata(L, sizeof(sd_journal*));
91 err = sd_journal_open_directory(j, path, flags);
92 if (err != 0) return handle_error(L, -err);
93 luaL_setmetatable(L, JOURNAL_METATABLE);
94 return 1;
95 }
96
97 static int journal_open_files (lua_State *L) {
98 int err;
99 sd_journal **j;
100 const char **paths;
101 size_t len;
102 int flags;
103 luaL_checktype(L, 1, LUA_TTABLE);
104 lua_settop(L, 2);
105 len = lua_rawlen(L, 1);
106 paths = lua_newuserdata(L, sizeof(const char*)*(len+1));
107 paths[len] = NULL;
108 for (; len>0; len--) {
109 lua_rawgeti(L, 1, len);
110 paths[len-1] = luaL_checkstring(L, -1);
111 lua_pop(L, 1);
112 }
113 flags = luaL_optinteger(L, 2, 0);
114 j = lua_newuserdata(L, sizeof(sd_journal*));
115 err = sd_journal_open_files(j, paths, flags);
116 if (err != 0) return handle_error(L, -err);
117 luaL_setmetatable(L, JOURNAL_METATABLE);
118 return 1;
119 }
120
121 static int journal_open_container (lua_State *L) {
122 int err;
123 const char *machine = luaL_checkstring(L, 1);
124 int flags = luaL_optinteger(L, 2, 0);
125 sd_journal **j = lua_newuserdata(L, sizeof(sd_journal*));
126 err = sd_journal_open_container(j, machine, flags);
127 if (err != 0) return handle_error(L, -err);
128 luaL_setmetatable(L, JOURNAL_METATABLE);
129 return 1;
130 }
131
132 static int journal_close (lua_State *L) {
133 sd_journal **jp = luaL_checkudata(L, 1, JOURNAL_METATABLE);
134 if (*jp != NULL) {
135 sd_journal_close(*jp);
136 *jp = NULL;
137 }
138 return 0;
139 }
140
141 static sd_journal* check_journal(lua_State *L, int index) {
142 sd_journal **jp = luaL_checkudata(L, index, JOURNAL_METATABLE);
143 if (*jp == NULL) luaL_error(L, "Invalid journal handle");
144 return *jp;
145 }
146
147 static int journal_tostring (lua_State *L) {
148 sd_journal *j = check_journal(L, 1);
149 lua_pushfstring(L, "%s: %p", JOURNAL_METATABLE, j);
150 return 1;
151 }
152
153 static int journal_get_cutoff_realtime_usec (lua_State *L) {
154 sd_journal *j = check_journal(L, 1);
155 uint64_t from;
156 uint64_t to;
157 int err = sd_journal_get_cutoff_realtime_usec(j, &from, &to);
158 if (err < 0) return handle_error(L, -err);
159 else if (err == 0) {
160 lua_pushboolean(L, 0);
161 return 1;
162 } else {
163 lua_pushuint64(L, from);
164 lua_pushuint64(L, to);
165 return 2;
166 }
167 }
168
169 static int journal_get_cutoff_monotonic_usec (lua_State *L) {
170 sd_journal *j = check_journal(L, 1);
171 sd_id128_t boot_id = check_id128_t(L, 2);
172 uint64_t from;
173 uint64_t to;
174 int err = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &from, &to);
175 if (err < 0) return handle_error(L, -err);
176 else if (err == 0) {
177 lua_pushboolean(L, 0);
178 return 1;
179 } else {
180 lua_pushuint64(L, from);
181 lua_pushuint64(L, to);
182 return 2;
183 }
184 }
185
186 static int journal_get_usage (lua_State *L) {
187 sd_journal *j = check_journal(L, 1);
188 uint64_t bytes;
189 int err = sd_journal_get_usage(j, &bytes);
190 if (err != 0) return handle_error(L, -err);
191 lua_pushuint64(L, bytes);
192 return 1;
193 }
194
195 static int journal_next (lua_State *L) {
196 sd_journal *j = check_journal(L, 1);
197 int err = sd_journal_next(j);
198 if (err < 0) return handle_error(L, -err);
199 lua_pushboolean(L, err);
200 return 1;
201 }
202
203 static int journal_next_skip (lua_State *L) {
204 sd_journal *j = check_journal(L, 1);
205 uint64_t skip = luaL_checkuint64(L, 2);
206 int err = sd_journal_next_skip(j, skip);
207 if (err < 0) return handle_error(L, -err);
208 lua_pushinteger(L, err);
209 return 1;
210 }
211
212 static int journal_previous (lua_State *L) {
213 sd_journal *j = check_journal(L, 1);
214 int err = sd_journal_previous(j);
215 if (err < 0) return handle_error(L, -err);
216 lua_pushboolean(L, err);
217 return 1;
218 }
219
220 static int journal_previous_skip (lua_State *L) {
221 sd_journal *j = check_journal(L, 1);
222 uint64_t skip = luaL_checkuint64(L, 2);
223 int err = sd_journal_previous_skip(j, skip);
224 if (err < 0) return handle_error(L, -err);
225 lua_pushinteger(L, err);
226 return 1;
227 }
228
229 static int journal_seek_head (lua_State *L) {
230 sd_journal *j = check_journal(L, 1);
231 int err = sd_journal_seek_head(j);
232 if (err != 0) return handle_error(L, -err);
233 lua_pushboolean(L, 1);
234 return 1;
235 }
236
237 static int journal_seek_tail (lua_State *L) {
238 sd_journal *j = check_journal(L, 1);
239 int err = sd_journal_seek_tail(j);
240 if (err != 0) return handle_error(L, -err);
241 lua_pushboolean(L, 1);
242 return 1;
243 }
244
245 static int journal_seek_monotonic_usec (lua_State *L) {
246 sd_journal *j = check_journal(L, 1);
247 sd_id128_t boot_id = check_id128_t(L, 2);
248 uint64_t usec = luaL_checkuint64(L, 3);
249 int err = sd_journal_seek_monotonic_usec(j, boot_id, usec);
250 if (err != 0) return handle_error(L, -err);
251 lua_pushboolean(L, 1);
252 return 1;
253 }
254
255 static int journal_seek_realtime_usec (lua_State *L) {
256 sd_journal *j = check_journal(L, 1);
257 uint64_t usec = luaL_checkuint64(L, 2);
258 int err = sd_journal_seek_realtime_usec(j, usec);
259 if (err != 0) return handle_error(L, -err);
260 lua_pushboolean(L, 1);
261 return 1;
262 }
263
264 static int journal_seek_cursor (lua_State *L) {
265 sd_journal *j = check_journal(L, 1);
266 const char *cursor = luaL_checkstring(L, 2);
267 int err = sd_journal_seek_cursor(j, cursor);
268 if (err != 0) return handle_error(L, -err);
269 lua_pushboolean(L, 1);
270 return 1;
271 }
272
273 static int journal_get_cursor (lua_State *L) {
274 sd_journal *j = check_journal(L, 1);
275 char *cursor;
276 int err = sd_journal_get_cursor(j, &cursor);
277 if (err != 0) return handle_error(L, -err);
278 lua_pushstring(L, cursor);
279 free(cursor);
280 return 1;
281 }
282
283 static int journal_test_cursor (lua_State *L) {
284 sd_journal *j = check_journal(L, 1);
285 const char *cursor = luaL_checkstring(L, 2);
286 int err = sd_journal_test_cursor(j, cursor);
287 if (err < 0) return handle_error(L, -err);
288 lua_pushboolean(L, err);
289 return 1;
290 }
291
292 static int journal_get_realtime_usec (lua_State *L) {
293 sd_journal *j = check_journal(L, 1);
294 uint64_t usec;
295 int err = sd_journal_get_realtime_usec(j, &usec);
296 if (err != 0) return handle_error(L, -err);
297 lua_pushuint64(L, usec);
298 return 1;
299 }
300
301 static int journal_get_monotonic_usec (lua_State *L) {
302 sd_journal *j = check_journal(L, 1);
303 uint64_t usec;
304 sd_id128_t *boot_id = lua_newuserdata(L, sizeof(sd_id128_t));
305 int err = sd_journal_get_monotonic_usec(j, &usec, boot_id);
306 if (err != 0) return handle_error(L, -err);
307 lua_pushuint64(L, usec);
308 lua_insert(L, 2); /* put below boot_id */
309 luaL_setmetatable(L, ID128_METATABLE);
310 return 2;
311 }
312
313 static int journal_get_data (lua_State *L) {
314 sd_journal *j = check_journal(L, 1);
315 const char *field = luaL_checkstring(L, 2);
316 const void *data;
317 size_t length;
318 int err = sd_journal_get_data(j, field, &data, &length);
319 if (err == -ENOENT) {
320 lua_pushboolean(L, 0);
321 lua_pushnil(L);
322 return 2;
323 } else if (err != 0) {
324 return handle_error(L, -err);
325 } else {
326 lua_pushboolean(L, 1);
327 lua_pushlstring(L, data, length);
328 return 2;
329 }
330 }
331
332 static int journal_enumerate_data (lua_State *L) {
333 sd_journal *j = check_journal(L, 1);
334 const void *data;
335 size_t length;
336 int err = sd_journal_enumerate_data(j, &data, &length);
337 if (err < 0) return handle_error(L, -err);
338 else if (err == 0) {
339 lua_pushboolean(L, 0);
340 lua_pushnil(L);
341 } else {
342 lua_pushboolean(L, 1);
343 lua_pushlstring(L, data, length);
344 }
345 return 2;
346 }
347
348 static int journal_restart_data (lua_State *L) {
349 sd_journal *j = check_journal(L, 1);
350 sd_journal_restart_data(j);
351 return 0;
352 }
353
354 static int journal_query_unique (lua_State *L) {
355 sd_journal *j = check_journal(L, 1);
356 const char *field = luaL_checkstring(L, 2);
357 int err = sd_journal_query_unique(j, field);
358 if (err != 0) return handle_error(L, -err);
359 lua_pushboolean(L, 1);
360 return 1;
361 }
362
363 static int journal_enumerate_unique (lua_State *L) {
364 sd_journal *j = check_journal(L, 1);
365 const void *data;
366 size_t length;
367 int err = sd_journal_enumerate_unique(j, &data, &length);
368 if (err < 0) return handle_error(L, -err);
369 else if (err == 0) {
370 lua_pushboolean(L, 0);
371 lua_pushnil(L);
372 } else {
373 lua_pushboolean(L, 1);
374 lua_pushlstring(L, data, length);
375 }
376 return 2;
377 }
378
379 static int journal_restart_unique (lua_State *L) {
380 sd_journal *j = check_journal(L, 1);
381 sd_journal_restart_unique(j);
382 return 0;
383 }
384
385 static int journal_set_data_threshold (lua_State *L) {
386 sd_journal *j = check_journal(L, 1);
387 size_t sz = luaL_optinteger(L, 2, 0);
388 int err = sd_journal_set_data_threshold(j, sz);
389 if (err != 0) return handle_error(L, -err);
390 lua_pushboolean(L, 1);
391 return 1;
392 }
393
394 static int journal_get_data_threshold (lua_State *L) {
395 sd_journal *j = check_journal(L, 1);
396 size_t sz;
397 int err = sd_journal_get_data_threshold(j, &sz);
398 if (err != 0) return handle_error(L, -err);
399 lua_pushinteger(L, sz);
400 return 1;
401 }
402
403 static int journal_add_match (lua_State *L) {
404 sd_journal *j = check_journal(L, 1);
405 size_t size;
406 const char *data = luaL_checklstring(L, 2, &size);
407 int err = sd_journal_add_match(j, data, size);
408 if (err != 0) return handle_error(L, -err);
409 lua_pushboolean(L, 1);
410 return 1;
411 }
412
413 static int journal_add_disjunction (lua_State *L) {
414 sd_journal *j = check_journal(L, 1);
415 int err = sd_journal_add_disjunction(j);
416 if (err != 0) return handle_error(L, -err);
417 lua_pushboolean(L, 1);
418 return 1;
419 }
420
421 static int journal_add_conjunction (lua_State *L) {
422 sd_journal *j = check_journal(L, 1);
423 int err = sd_journal_add_conjunction(j);
424 if (err != 0) return handle_error(L, -err);
425 lua_pushboolean(L, 1);
426 return 1;
427 }
428
429 static int journal_flush_matches (lua_State *L) {
430 sd_journal *j = check_journal(L, 1);
431 sd_journal_flush_matches(j);
432 lua_pushboolean(L, 1);
433 return 1;
434 }
435
436 static int journal_get_fd (lua_State *L) {
437 sd_journal *j = check_journal(L, 1);
438 int err = sd_journal_get_fd(j);
439 if (err < 0) return handle_error(L, -err);
440 lua_pushinteger(L, err);
441 return 1;
442 }
443
444 static int journal_get_events (lua_State *L) {
445 sd_journal *j = check_journal(L, 1);
446 int err = sd_journal_get_events(j);
447 if (err < 0) return handle_error(L, -err);
448 lua_pushinteger(L, err);
449 return 1;
450 }
451
452 static int journal_get_timeout (lua_State *L) {
453 sd_journal *j = check_journal(L, 1);
454 uint64_t timeout_usec;
455 int err = sd_journal_get_timeout(j, &timeout_usec);
456 if (err < 0) return handle_error(L, -err);
457 if ((err == 0) || (timeout_usec == (uint64_t) -1)) {
458 /* local file; no timeout needed */
459 lua_pushboolean(L, 0);
460 } else {
461 lua_pushnumber(L, ((double)timeout_usec)/1000000);
462 }
463 return 1;
464 }
465
466 static int journal_process (lua_State *L) {
467 sd_journal *j = check_journal(L, 1);
468 int err = sd_journal_process(j);
469 if (err < 0) return handle_error(L, -err);
470 lua_pushinteger(L, err);
471 return 1;
472 }
473
474 static int journal_wait (lua_State *L) {
475 sd_journal *j = check_journal(L, 1);
476 uint64_t timeout_usec;
477 int err;
478 if (lua_isnoneornil(L, 2)) { /* default to infinite wait */
479 timeout_usec = -1;
480 } else {
481 timeout_usec = luaL_checknumber(L, 2) * 1000000;
482 }
483 err = sd_journal_wait(j, timeout_usec);
484 if (err < 0) return handle_error(L, -err);
485 lua_pushinteger(L, err);
486 return 1;
487 }
488
489 static int journal_reliable_fd (lua_State *L) {
490 sd_journal *j = check_journal(L, 1);
491 int err = sd_journal_reliable_fd(j);
492 if (err < 0) return handle_error(L, -err);
493 lua_pushboolean(L, err);
494 return 1;
495 }
496
497
498 static const luaL_Reg journal_methods[] = {
499 {"get_cutoff_realtime_usec", journal_get_cutoff_realtime_usec},
500 {"get_cutoff_monotonic_usec", journal_get_cutoff_monotonic_usec},
501 {"get_usage", journal_get_usage},
502 {"next", journal_next},
503 {"next_skip", journal_next_skip},
504 {"previous", journal_previous},
505 {"previous_skip", journal_previous_skip},
506 {"seek_head", journal_seek_head},
507 {"seek_tail", journal_seek_tail},
508 {"seek_monotonic_usec", journal_seek_monotonic_usec},
509 {"seek_realtime_usec", journal_seek_realtime_usec},
510 {"seek_cursor", journal_seek_cursor},
511 {"get_cursor", journal_get_cursor},
512 {"test_cursor", journal_test_cursor},
513 {"get_realtime_usec", journal_get_realtime_usec},
514 {"get_monotonic_usec", journal_get_monotonic_usec},
515 {"get_data", journal_get_data},
516 {"enumerate_data", journal_enumerate_data},
517 {"restart_data", journal_restart_data},
518 {"query_unique", journal_query_unique},
519 {"enumerate_unique", journal_enumerate_unique},
520 {"restart_unique", journal_restart_unique},
521 {"set_data_threshold", journal_set_data_threshold},
522 {"get_data_threshold", journal_get_data_threshold},
523 {"add_match", journal_add_match},
524 {"add_disjunction", journal_add_disjunction},
525 {"add_conjunction", journal_add_conjunction},
526 {"flush_matches", journal_flush_matches},
527 {"get_fd", journal_get_fd},
528 {"get_events", journal_get_events},
529 {"get_timeout", journal_get_timeout},
530 {"process", journal_process},
531 {"wait", journal_wait},
532 {"reliable_fd", journal_reliable_fd},
533 {NULL, NULL}
534 };
535
536 int luaopen_systemd_journal_core (lua_State *L) {
537 static const luaL_Reg lib[] = {
538 {"sendv", sendv},
539 {"perror", _perror},
540 {"stream_fd", stream_fd},
541 {"open", journal_open},
542 {"open_directory", journal_open_directory},
543 {"open_files", journal_open_files},
544 {"open_container", journal_open_container},
545 {NULL, NULL}
546 };
547
548 /* ensure ID128_METATABLE is loaded */
549 luaL_requiref(L, "systemd.id128.core", luaopen_systemd_id128_core, 0);
550
551 luaL_newlib(L, lib);
552
553 /* Even with compat-5.2, Lua 5.1 doesn't have an easy way to make your own file objects */
554 /* Set up function environment for stream_fd for 5.1 so handle gets closed correctly */
555 #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM == 501
556 lua_getfield(L, -1, "stream_fd");
557 lua_createtable(L, 0, 1);
558 lua_pushcfunction(L, &io_fclose);
559 lua_setfield(L, -2, "__close");
560 lua_setfenv(L, -2);
561 lua_pop(L, 1);
562 #endif
563
564 lua_createtable(L, 0, 3);
565 lua_pushnumber(L, SD_JOURNAL_NOP); lua_setfield(L, -2, "NOP");
566 lua_pushnumber(L, SD_JOURNAL_APPEND); lua_setfield(L, -2, "APPEND");
567 lua_pushnumber(L, SD_JOURNAL_INVALIDATE); lua_setfield(L, -2, "INVALIDATE");
568 lua_setfield(L, -2, "WAKEUP");
569
570 if (luaL_newmetatable(L, JOURNAL_METATABLE) != 0) {
571 lua_pushcfunction(L, journal_close);
572 lua_setfield(L, -2, "__gc");
573 lua_pushcfunction(L, journal_tostring);
574 lua_setfield(L, -2, "__tostring");
575 luaL_newlib(L, journal_methods);
576 lua_setfield(L, -2, "__index");
577 }
578 /* Expose journal methods */
579 lua_getfield(L, -1, "__index");
580 lua_setfield(L, -3, "JOURNAL_METHODS");
581
582 lua_pop(L, 1);
583
584 lua_createtable(L, 0, 4);
585 lua_pushnumber(L, SD_JOURNAL_LOCAL_ONLY); lua_setfield(L, -2, "LOCAL_ONLY");
586 lua_pushnumber(L, SD_JOURNAL_RUNTIME_ONLY); lua_setfield(L, -2, "RUNTIME_ONLY");
587 lua_pushnumber(L, SD_JOURNAL_SYSTEM); lua_setfield(L, -2, "SYSTEM");
588 lua_pushnumber(L, SD_JOURNAL_CURRENT_USER); lua_setfield(L, -2, "CURRENT_USER");
589 lua_setfield(L, -2, "OPEN");
590
591 return 1;
592 }
0 #include "lua.h"
1
2 #define JOURNAL_METATABLE "sd_journal"
3
4 int luaopen_systemd_journal_core (lua_State *L);
0 local id128 = require "systemd.id128"
1
2 local c = require "systemd.journal.core"
3 local methods = c.JOURNAL_METHODS
4
5 local function strip_field_name(str)
6 return str:match("=(.*)$")
7 end
8
9 local function split_field(str)
10 return str:match("^([^=]*)=(.*)$")
11 end
12
13 c.LOG = {
14 EMERG = 0;
15 ALERT = 1;
16 CRIT = 2;
17 ERR = 3;
18 WARNING = 4;
19 NOTICE = 5;
20 INFO = 6;
21 DEBUG = 7;
22 }
23
24 function c.print(priority, ...)
25 return c.sendv {
26 "PRIORITY=" .. priority;
27 "MESSAGE=" .. string.format(...);
28 }
29 end
30
31 function c.sendt(m)
32 local t = { }
33 for k, v in pairs(m) do
34 t[#t+1] = k .. "=" .. v
35 end
36 return c.sendv(t)
37 end
38
39 function methods:get(field)
40 local ok, res, code = self:get_data(field)
41 if ok then
42 return strip_field_name(res)
43 elseif ok == false then
44 return nil
45 else
46 error(res, 2);
47 end
48 end
49
50 local function next_field(self)
51 local ok, res = self:enumerate_data()
52 if ok then
53 return split_field(res)
54 elseif ok == false then
55 return nil
56 else
57 error(res, 2)
58 end
59 end
60 function methods:each_data()
61 self:restart_data()
62 return next_field, self
63 end
64
65 local function next_unique(self)
66 local ok, res = self:enumerate_unique()
67 if ok then
68 return strip_field_name(res)
69 elseif ok == false then
70 return nil
71 else
72 error(res, 2)
73 end
74 end
75 function methods:each_unique(field)
76 self:restart_unique()
77 assert(self:query_unique(field))
78 return next_unique, self
79 end
80
81 -- Converts the current journal entry to a lua table
82 -- Includes __ prefixed "Address Fields"
83 function methods:to_table()
84 local t = {
85 __CURSOR = self:get_cursor();
86 __REALTIME_TIMESTAMP = self:get_realtime_usec();
87 __MONOTONIC_TIMESTAMP = self:get_monotonic_usec();
88 }
89 for field, value in self:each_data() do
90 t[field] = value
91 end
92 return t
93 end
94
95 function methods:get_catalog()
96 local ok, err, errno = self:get_data "MESSAGE_ID"
97 if ok == nil then
98 return nil, err, errno
99 elseif ok == false then
100 return false
101 else
102 local message_id = err:match("=(.*)$")
103 if message_id == nil then return false end
104 local message_id = id128.from_string(message_id)
105 local text = message_id:get_catalog()
106 if not text then return false end
107 local t = self:to_table()
108 text = text:gsub("@([^@]-)@", t)
109 return text
110 end
111 end
112
113 return c
0 #include "lua.h"
1 #include "lauxlib.h"
2 #include "compat-5.3.h"
3
4 #include <stdlib.h> /* free */
5 #include <stdint.h> /* uint64_t */
6 #include <sys/types.h> /* pid_t */
7 #include <errno.h> /* ENOTSUP */
8
9 #include <systemd/sd-login.h>
10
11 #include "util.c"
12 #include "login.h"
13
14
15 shim_weak_stub_declare(int, sd_pid_get_session, (pid_t pid, char **session), -ENOTSUP);
16 shim_weak_stub_declare(int, sd_pid_get_owner_uid, (pid_t pid, uid_t *uid), -ENOTSUP);
17 shim_weak_stub_declare(int, sd_pid_get_unit, (pid_t pid, char **unit), -ENOTSUP);
18 shim_weak_stub_declare(int, sd_pid_get_user_unit, (pid_t pid, char **unit), -ENOTSUP);
19 shim_weak_stub_declare(int, sd_pid_get_machine_name, (pid_t pid, char **machine), -ENOTSUP);
20 shim_weak_stub_declare(int, sd_pid_get_slice, (pid_t pid, char **slice), -ENOTSUP);
21 shim_weak_stub_declare(int, sd_pid_get_user_slice, (pid_t pid, char **slice), -ENOTSUP);
22 shim_weak_stub_declare(int, sd_pid_get_cgroup, (pid_t pid, char **cgroup), -ENOTSUP);
23 shim_weak_stub_declare(int, sd_peer_get_session, (int fd, char **session), -ENOTSUP);
24 shim_weak_stub_declare(int, sd_peer_get_owner_uid, (int fd, uid_t *uid), -ENOTSUP);
25 shim_weak_stub_declare(int, sd_peer_get_unit, (int fd, char **unit), -ENOTSUP);
26 shim_weak_stub_declare(int, sd_peer_get_user_unit, (int fd, char **unit), -ENOTSUP);
27 shim_weak_stub_declare(int, sd_peer_get_machine_name, (int fd, char **machine), -ENOTSUP);
28 shim_weak_stub_declare(int, sd_peer_get_slice, (int fd, char **slice), -ENOTSUP);
29 shim_weak_stub_declare(int, sd_peer_get_user_slice, (int fd, char **slice), -ENOTSUP);
30 shim_weak_stub_declare(int, sd_peer_get_cgroup, (int fd, char **cgroup), -ENOTSUP);
31 shim_weak_stub_declare(int, sd_uid_get_state, (uid_t uid, char **state), -ENOTSUP);
32 shim_weak_stub_declare(int, sd_uid_get_display, (uid_t uid, char **session), -ENOTSUP);
33 shim_weak_stub_declare(int, sd_uid_is_on_seat, (uid_t uid, int require_active, const char *seat), -ENOTSUP);
34 shim_weak_stub_declare(int, sd_uid_get_sessions, (uid_t uid, int require_active, char ***sessions), -ENOTSUP);
35 shim_weak_stub_declare(int, sd_uid_get_seats, (uid_t uid, int require_active, char ***seats), -ENOTSUP);
36 shim_weak_stub_declare(int, sd_session_is_active, (const char *session), -ENOTSUP);
37 shim_weak_stub_declare(int, sd_session_is_remote, (const char *session), -ENOTSUP);
38 shim_weak_stub_declare(int, sd_session_get_state, (const char *session, char **state), -ENOTSUP);
39 shim_weak_stub_declare(int, sd_session_get_uid, (const char *session, uid_t *uid), -ENOTSUP);
40 shim_weak_stub_declare(int, sd_session_get_seat, (const char *session, char **seat), -ENOTSUP);
41 shim_weak_stub_declare(int, sd_session_get_service, (const char *session, char **service), -ENOTSUP);
42 shim_weak_stub_declare(int, sd_session_get_type, (const char *session, char **type), -ENOTSUP);
43 shim_weak_stub_declare(int, sd_session_get_class, (const char *session, char **clazz), -ENOTSUP);
44 shim_weak_stub_declare(int, sd_session_get_desktop, (const char *session, char **desktop), -ENOTSUP);
45 shim_weak_stub_declare(int, sd_session_get_display, (const char *session, char **display), -ENOTSUP);
46 shim_weak_stub_declare(int, sd_session_get_remote_host, (const char *session, char **remote_host), -ENOTSUP);
47 shim_weak_stub_declare(int, sd_session_get_remote_user, (const char *session, char **remote_user), -ENOTSUP);
48 shim_weak_stub_declare(int, sd_session_get_tty, (const char *session, char **display), -ENOTSUP);
49 shim_weak_stub_declare(int, sd_session_get_vt, (const char *session, unsigned *vtnr), -ENOTSUP);
50 shim_weak_stub_declare(int, sd_seat_get_active, (const char *seat, char **session, uid_t *uid), -ENOTSUP);
51 shim_weak_stub_declare(int, sd_seat_get_sessions, (const char *seat, char ***sessions, uid_t **uid, unsigned *n_uids), -ENOTSUP);
52 shim_weak_stub_declare(int, sd_seat_can_multi_session, (const char *seat), -ENOTSUP);
53 shim_weak_stub_declare(int, sd_seat_can_tty, (const char *seat), -ENOTSUP);
54 shim_weak_stub_declare(int, sd_seat_can_graphical, (const char *seat), -ENOTSUP);
55 shim_weak_stub_declare(int, sd_machine_get_class, (const char *machine, char **clazz), -ENOTSUP);
56 shim_weak_stub_declare(int, sd_machine_get_ifindices, (const char *machine, int **ifindices), -ENOTSUP);
57 shim_weak_stub_declare(int, sd_get_seats, (char ***seats), -ENOTSUP);
58 shim_weak_stub_declare(int, sd_get_sessions, (char ***sessions), -ENOTSUP);
59 shim_weak_stub_declare(int, sd_get_uids, (uid_t **users), -ENOTSUP);
60 shim_weak_stub_declare(int, sd_get_machine_names, (char ***machines), -ENOTSUP);
61 shim_weak_stub_declare(int, sd_login_monitor_new, (const char *category, sd_login_monitor** ret), -ENOTSUP);
62 shim_weak_stub_declare(sd_login_monitor*, sd_login_monitor_unref, (sd_login_monitor *m), NULL);
63 shim_weak_stub_declare(int, sd_login_monitor_flush, (sd_login_monitor *m), -ENOTSUP);
64 shim_weak_stub_declare(int, sd_login_monitor_get_fd, (sd_login_monitor *m), -ENOTSUP);
65 shim_weak_stub_declare(int, sd_login_monitor_get_events, (sd_login_monitor *m), -ENOTSUP);
66 shim_weak_stub_declare(int, sd_login_monitor_get_timeout, (sd_login_monitor *m, uint64_t *timeout_usec), -ENOTSUP);
67
68 static void push_array_of_strings (lua_State *L, char **strings, int n) {
69 int i;
70 lua_createtable(L, n, 0);
71 if (strings != NULL) {
72 for (i=0; i<n; i++) {
73 lua_pushstring(L, strings[i]);
74 free(strings[i]);
75 lua_rawseti(L, -2, i+1);
76 }
77 free(strings);
78 }
79 }
80
81 static void push_array_of_uids (lua_State *L, uid_t *uids, int n) {
82 int i;
83 lua_createtable(L, n, 0);
84 if (uids != NULL) {
85 for (i=0; i<n; i++) {
86 lua_pushinteger(L, uids[i]);
87 lua_rawseti(L, -2, i+1);
88 }
89 free(uids);
90 }
91 }
92
93 static int get_seats (lua_State *L) {
94 char **seats;
95 int n = shim_weak_stub(sd_get_seats)(&seats);
96 if (n < 0) return handle_error(L, -n);
97 push_array_of_strings(L, seats, n);
98 return 1;
99 }
100
101 static int get_sessions (lua_State *L) {
102 char **sessions;
103 int n = shim_weak_stub(sd_get_sessions)(&sessions);
104 if (n < 0) return handle_error(L, -n);
105 push_array_of_strings(L, sessions, n);
106 return 1;
107 }
108
109 static int get_uids (lua_State *L) {
110 uid_t *users;
111 int n = shim_weak_stub(sd_get_uids)(&users);
112 if (n < 0) return handle_error(L, -n);
113 push_array_of_uids(L, users, n);
114 return 1;
115 }
116
117 static int get_machine_names (lua_State *L) {
118 char **machines;
119 int n = shim_weak_stub(sd_get_machine_names)(&machines);
120 if (n < 0) return handle_error(L, -n);
121 push_array_of_strings(L, machines, n);
122 return 1;
123 }
124
125 static int pid_get_session (lua_State *L) {
126 pid_t pid = luaL_checkinteger(L, 1);
127 char *session;
128 int n = shim_weak_stub(sd_pid_get_session)(pid, &session);
129 if (n < 0) return handle_error(L, -n);
130 lua_pushstring(L, session);
131 free(session);
132 return 1;
133 }
134
135 static int pid_get_unit (lua_State *L) {
136 pid_t pid = luaL_checkinteger(L, 1);
137 char *unit;
138 int n = shim_weak_stub(sd_pid_get_unit)(pid, &unit);
139 if (n < 0) return handle_error(L, -n);
140 lua_pushstring(L, unit);
141 free(unit);
142 return 1;
143 }
144
145 static int pid_get_user_unit (lua_State *L) {
146 pid_t pid = luaL_checkinteger(L, 1);
147 char *unit;
148 int n = shim_weak_stub(sd_pid_get_user_unit)(pid, &unit);
149 if (n < 0) return handle_error(L, -n);
150 lua_pushstring(L, unit);
151 free(unit);
152 return 1;
153 }
154
155 static int pid_get_owner_uid (lua_State *L) {
156 pid_t pid = luaL_checkinteger(L, 1);
157 uid_t user;
158 int n = shim_weak_stub(sd_pid_get_owner_uid)(pid, &user);
159 if (n < 0) return handle_error(L, -n);
160 lua_pushinteger(L, user);
161 return 1;
162 }
163
164 static int pid_get_machine_name (lua_State *L) {
165 pid_t pid = luaL_checkinteger(L, 1);
166 char *machine;
167 int n = shim_weak_stub(sd_pid_get_machine_name)(pid, &machine);
168 if (n < 0) return handle_error(L, -n);
169 lua_pushstring(L, machine);
170 free(machine);
171 return 1;
172 }
173
174 static int pid_get_slice (lua_State *L) {
175 pid_t pid = luaL_checkinteger(L, 1);
176 char *slice;
177 int n = shim_weak_stub(sd_pid_get_slice)(pid, &slice);
178 if (n < 0) return handle_error(L, -n);
179 lua_pushstring(L, slice);
180 free(slice);
181 return 1;
182 }
183
184 static int pid_get_user_slice (lua_State *L) {
185 pid_t pid = luaL_checkinteger(L, 1);
186 char *slice;
187 int n = shim_weak_stub(sd_pid_get_user_slice)(pid, &slice);
188 if (n < 0) return handle_error(L, -n);
189 lua_pushstring(L, slice);
190 free(slice);
191 return 1;
192 }
193
194 static int pid_get_cgroup (lua_State *L) {
195 pid_t pid = luaL_checkinteger(L, 1);
196 char *cgroup;
197 int n = shim_weak_stub(sd_pid_get_cgroup)(pid, &cgroup);
198 if (n < 0) return handle_error(L, -n);
199 lua_pushstring(L, cgroup);
200 free(cgroup);
201 return 1;
202 }
203
204 static int peer_get_session (lua_State *L) {
205 int fd = luaL_checkinteger(L, 1);
206 char *session;
207 int n = shim_weak_stub(sd_peer_get_session)(fd, &session);
208 if (n < 0) return handle_error(L, -n);
209 lua_pushstring(L, session);
210 free(session);
211 return 1;
212 }
213
214 static int peer_get_unit (lua_State *L) {
215 int fd = luaL_checkinteger(L, 1);
216 char *unit;
217 int n = shim_weak_stub(sd_peer_get_unit)(fd, &unit);
218 if (n < 0) return handle_error(L, -n);
219 lua_pushstring(L, unit);
220 free(unit);
221 return 1;
222 }
223
224 static int peer_get_user_unit (lua_State *L) {
225 int fd = luaL_checkinteger(L, 1);
226 char *unit;
227 int n = shim_weak_stub(sd_peer_get_user_unit)(fd, &unit);
228 if (n < 0) return handle_error(L, -n);
229 lua_pushstring(L, unit);
230 free(unit);
231 return 1;
232 }
233
234 static int peer_get_owner_uid (lua_State *L) {
235 int fd = luaL_checkinteger(L, 1);
236 uid_t user;
237 int n = shim_weak_stub(sd_peer_get_owner_uid)(fd, &user);
238 if (n < 0) return handle_error(L, -n);
239 lua_pushinteger(L, user);
240 return 1;
241 }
242
243 static int peer_get_machine_name (lua_State *L) {
244 int fd = luaL_checkinteger(L, 1);
245 char *machine;
246 int n = shim_weak_stub(sd_peer_get_machine_name)(fd, &machine);
247 if (n < 0) return handle_error(L, -n);
248 lua_pushstring(L, machine);
249 free(machine);
250 return 1;
251 }
252
253 static int peer_get_slice (lua_State *L) {
254 int fd = luaL_checkinteger(L, 1);
255 char *slice;
256 int n = shim_weak_stub(sd_peer_get_slice)(fd, &slice);
257 if (n < 0) return handle_error(L, -n);
258 lua_pushstring(L, slice);
259 free(slice);
260 return 1;
261 }
262
263 static int peer_get_user_slice (lua_State *L) {
264 int fd = luaL_checkinteger(L, 1);
265 char *slice;
266 int n = shim_weak_stub(sd_peer_get_user_slice)(fd, &slice);
267 if (n < 0) return handle_error(L, -n);
268 lua_pushstring(L, slice);
269 free(slice);
270 return 1;
271 }
272
273 static int peer_get_cgroup (lua_State *L) {
274 int fd = luaL_checkinteger(L, 1);
275 char *cgroup;
276 int n = shim_weak_stub(sd_peer_get_cgroup)(fd, &cgroup);
277 if (n < 0) return handle_error(L, -n);
278 lua_pushstring(L, cgroup);
279 free(cgroup);
280 return 1;
281 }
282
283 static int uid_get_state (lua_State *L) {
284 uid_t uid = luaL_checkinteger(L, 1);
285 char *state;
286 int err = shim_weak_stub(sd_uid_get_state)(uid, &state);
287 if (err < 0) return handle_error(L, -err);
288 lua_pushstring(L, state);
289 free(state);
290 return 1;
291 }
292
293 static int uid_get_seats (lua_State *L) {
294 uid_t uid = luaL_checkinteger(L, 1);
295 int require_active = (luaL_checktype(L, 2, LUA_TBOOLEAN), lua_toboolean(L, 2));
296 char **seats;
297 int err = shim_weak_stub(sd_uid_get_seats)(uid, require_active, &seats);
298 if (err < 0) return handle_error(L, -err);
299 push_array_of_strings(L, seats, err);
300 return 1;
301 }
302
303 static int uid_is_on_seat (lua_State *L) {
304 uid_t uid = luaL_checkinteger(L, 1);
305 int require_active = (luaL_checktype(L, 2, LUA_TBOOLEAN), lua_toboolean(L, 2));
306 const char *seat = luaL_checkstring(L, 3);
307 int err = shim_weak_stub(sd_uid_is_on_seat)(uid, require_active, seat);
308 if (err < 0) return handle_error(L, -err);
309 lua_pushboolean(L, err);
310 return 1;
311 }
312
313 static int uid_get_sessions (lua_State *L) {
314 uid_t uid = luaL_checkinteger(L, 1);
315 int require_active = (luaL_checktype(L, 2, LUA_TBOOLEAN), lua_toboolean(L, 2));
316 char ** sessions;
317 int err = shim_weak_stub(sd_uid_get_sessions)(uid, require_active, &sessions);
318 if (err < 0) return handle_error(L, -err);
319 push_array_of_strings(L, sessions, err);
320 return 1;
321 }
322
323 static int uid_get_display (lua_State *L) {
324 uid_t uid = luaL_checkinteger(L, 1);
325 char *session;
326 int err = shim_weak_stub(sd_uid_get_display)(uid, &session);
327 if (err < 0) return handle_error(L, -err);
328 lua_pushstring(L, session);
329 free(session);
330 return 1;
331 }
332
333 static int session_is_active (lua_State *L) {
334 const char *session = luaL_checkstring(L, 1);
335 int err = shim_weak_stub(sd_session_is_active)(session);
336 if (err < 0) return handle_error(L, -err);
337 lua_pushboolean(L, err);
338 return 1;
339 }
340
341 static int session_is_remote (lua_State *L) {
342 const char *session = luaL_checkstring(L, 1);
343 int err = shim_weak_stub(sd_session_is_remote)(session);
344 if (err < 0) return handle_error(L, -err);
345 lua_pushboolean(L, err);
346 return 1;
347 }
348
349 static int session_get_state (lua_State *L) {
350 const char *session = luaL_checkstring(L, 1);
351 char *state;
352 int err = shim_weak_stub(sd_session_get_state)(session, &state);
353 if (err < 0) return handle_error(L, -err);
354 lua_pushstring(L, state);
355 free(state);
356 return 1;
357 }
358
359 static int session_get_uid (lua_State *L) {
360 const char *session = luaL_checkstring(L, 1);
361 uid_t uid;
362 int err = shim_weak_stub(sd_session_get_uid)(session, &uid);
363 if (err < 0) return handle_error(L, -err);
364 lua_pushinteger(L, uid);
365 return 1;
366 }
367
368 static int session_get_seat (lua_State *L) {
369 const char *session = luaL_checkstring(L, 1);
370 char *seat;
371 int err = shim_weak_stub(sd_session_get_seat)(session, &seat);
372 if (err < 0) return handle_error(L, -err);
373 lua_pushstring(L, seat);
374 free(seat);
375 return 1;
376 }
377
378 static int session_get_service (lua_State *L) {
379 const char *session = luaL_checkstring(L, 1);
380 char *service;
381 int err = shim_weak_stub(sd_session_get_service)(session, &service);
382 if (err < 0) return handle_error(L, -err);
383 lua_pushstring(L, service);
384 free(service);
385 return 1;
386 }
387
388 static int session_get_type (lua_State *L) {
389 const char *session = luaL_checkstring(L, 1);
390 char *type;
391 int err = shim_weak_stub(sd_session_get_type)(session, &type);
392 if (err < 0) return handle_error(L, -err);
393 lua_pushstring(L, type);
394 free(type);
395 return 1;
396 }
397
398 static int session_get_class (lua_State *L) {
399 const char *session = luaL_checkstring(L, 1);
400 char *clazz;
401 int err = shim_weak_stub(sd_session_get_class)(session, &clazz);
402 if (err < 0) return handle_error(L, -err);
403 lua_pushstring(L, clazz);
404 free(clazz);
405 return 1;
406 }
407
408 static int session_get_desktop (lua_State *L) {
409 const char *session = luaL_checkstring(L, 1);
410 char *desktop;
411 int err = shim_weak_stub(sd_session_get_desktop)(session, &desktop);
412 if (err < 0) return handle_error(L, -err);
413 lua_pushstring(L, desktop);
414 free(desktop);
415 return 1;
416 }
417
418 static int session_get_display (lua_State *L) {
419 const char *session = luaL_checkstring(L, 1);
420 char *display;
421 int err = shim_weak_stub(sd_session_get_display)(session, &display);
422 if (err < 0) return handle_error(L, -err);
423 lua_pushstring(L, display);
424 free(display);
425 return 1;
426 }
427
428 static int session_get_remote_host (lua_State *L) {
429 const char *session = luaL_checkstring(L, 1);
430 char *remote_host;
431 int err = shim_weak_stub(sd_session_get_remote_host)(session, &remote_host);
432 if (err < 0) return handle_error(L, -err);
433 lua_pushstring(L, remote_host);
434 free(remote_host);
435 return 1;
436 }
437
438 static int session_get_remote_user (lua_State *L) {
439 const char *session = luaL_checkstring(L, 1);
440 char *remote_user;
441 int err = shim_weak_stub(sd_session_get_remote_user)(session, &remote_user);
442 if (err < 0) return handle_error(L, -err);
443 lua_pushstring(L, remote_user);
444 free(remote_user);
445 return 1;
446 }
447
448 static int session_get_tty (lua_State *L) {
449 const char *session = luaL_checkstring(L, 1);
450 char *display;
451 int err = shim_weak_stub(sd_session_get_tty)(session, &display);
452 if (err < 0) return handle_error(L, -err);
453 lua_pushstring(L, display);
454 free(display);
455 return 1;
456 }
457
458 static int session_get_vt (lua_State *L) {
459 const char *session = luaL_checkstring(L, 1);
460 unsigned vtnr;
461 int err = shim_weak_stub(sd_session_get_vt)(session, &vtnr);
462 if (err < 0) return handle_error(L, -err);
463 lua_pushinteger(L, vtnr);
464 return 1;
465 }
466
467 static int seat_get_active (lua_State *L) {
468 const char *seat = luaL_optstring(L, 1, NULL);
469 char *session;
470 uid_t uid;
471 int err = shim_weak_stub(sd_seat_get_active)(seat, &session, &uid);
472 if (err < 0) return handle_error(L, -err);
473 lua_pushstring(L, session);
474 lua_pushinteger(L, uid);
475 return 2;
476 }
477
478 static int seat_get_sessions (lua_State *L) {
479 const char *seat = luaL_optstring(L, 1, NULL);
480 char **sessions;
481 uid_t *uid;
482 unsigned n_uids;
483 int err = shim_weak_stub(sd_seat_get_sessions)(seat, &sessions, &uid, &n_uids);
484 if (err < 0) return handle_error(L, -err);
485 push_array_of_strings(L, sessions, err);
486 push_array_of_uids(L, uid, n_uids);
487 return 2;
488 }
489
490 static int seat_can_multi_session (lua_State *L) {
491 const char *seat = luaL_optstring(L, 1, NULL);
492 int err = shim_weak_stub(sd_seat_can_multi_session)(seat);
493 if (err < 0) return handle_error(L, -err);
494 lua_pushboolean(L, err);
495 return 1;
496 }
497
498 static int seat_can_tty (lua_State *L) {
499 const char *seat = luaL_optstring(L, 1, NULL);
500 int err = shim_weak_stub(sd_seat_can_tty)(seat);
501 if (err < 0) return handle_error(L, -err);
502 lua_pushboolean(L, err);
503 return 1;
504 }
505
506 static int seat_can_graphical (lua_State *L) {
507 const char *seat = luaL_optstring(L, 1, NULL);
508 int err = shim_weak_stub(sd_seat_can_graphical)(seat);
509 if (err < 0) return handle_error(L, -err);
510 lua_pushboolean(L, err);
511 return 1;
512 }
513
514 static int machine_get_class (lua_State *L) {
515 const char *machine = luaL_checkstring(L, 1);
516 char *clazz;
517 int err = shim_weak_stub(sd_machine_get_class)(machine, &clazz);
518 if (err < 0) return handle_error(L, -err);
519 lua_pushstring(L, clazz);
520 free(clazz);
521 return 1;
522 }
523
524 static int machine_get_ifindices (lua_State *L) {
525 const char *machine = luaL_checkstring(L, 1);
526 int *ifindices;
527 int i;
528 int err = shim_weak_stub(sd_machine_get_ifindices)(machine, &ifindices);
529 if (err < 0) return handle_error(L, -err);
530 lua_createtable(L, err, 0);
531 if (ifindices != NULL) {
532 for (i=0; i<err; i++) {
533 lua_pushinteger(L, ifindices[i]);
534 lua_rawseti(L, -2, i+1);
535 }
536 free(ifindices);
537 }
538 return 1;
539 }
540
541 /* sd_login_monitor */
542
543 static sd_login_monitor* check_monitor(lua_State *L, int index) {
544 sd_login_monitor **mp = luaL_checkudata(L, index, MONITOR_METATABLE);
545 if (*mp == NULL) luaL_error(L, "Invalid monitor handle");
546 return *mp;
547 }
548
549 static int monitor_unref (lua_State *L) {
550 sd_login_monitor **mp = luaL_checkudata(L, 1, MONITOR_METATABLE);
551 if (*mp != NULL) {
552 shim_weak_stub(sd_login_monitor_unref)(*mp);
553 *mp = NULL;
554 }
555 return 0;
556 }
557
558 static int monitor_new (lua_State *L) {
559 const char* category = luaL_optstring(L, 1, NULL);
560 sd_login_monitor** ret = lua_newuserdata(L, sizeof(sd_login_monitor*));
561 int err = shim_weak_stub(sd_login_monitor_new)(category, ret);
562 if (err < 0) return handle_error(L, -err);
563 luaL_setmetatable(L, MONITOR_METATABLE);
564 return 1;
565 }
566
567 static int monitor_tostring (lua_State *L) {
568 sd_login_monitor *m = check_monitor(L, 1);
569 lua_pushfstring(L, "%s: %p", MONITOR_METATABLE, m);
570 return 1;
571 }
572
573 static int monitor_flush (lua_State *L) {
574 sd_login_monitor *m = check_monitor(L, 1);
575 int err = shim_weak_stub(sd_login_monitor_flush)(m);
576 if (err < 0) return handle_error(L, -err);
577 lua_pushboolean(L, 1);
578 return 1;
579 }
580
581 static int monitor_get_fd (lua_State *L) {
582 sd_login_monitor *m = check_monitor(L, 1);
583 int err = shim_weak_stub(sd_login_monitor_get_fd)(m);
584 if (err < 0) return handle_error(L, -err);
585 lua_pushinteger(L, err);
586 return 1;
587 }
588
589 static int monitor_get_events (lua_State *L) {
590 sd_login_monitor *m = check_monitor(L, 1);
591 int err = shim_weak_stub(sd_login_monitor_get_events)(m);
592 if (err < 0) return handle_error(L, -err);
593 lua_pushinteger(L, err);
594 return 1;
595 }
596
597 static int monitor_get_timeout (lua_State *L) {
598 sd_login_monitor *m = check_monitor(L, 1);
599 uint64_t timeout_usec;
600 int err = shim_weak_stub(sd_login_monitor_get_timeout)(m, &timeout_usec);
601 if (err < 0) return handle_error(L, -err);
602 if ((err == 0) || (timeout_usec == (uint64_t) -1)) {
603 lua_pushboolean(L, 0);
604 } else {
605 lua_pushnumber(L, ((double)timeout_usec)/1000000);
606 }
607 return 1;
608 }
609
610 int luaopen_systemd_login_core (lua_State *L) {
611 lua_newtable(L);
612 /* 209 */
613 if (symbol_exists("sd_monitor_new") && symbol_exists("sd_login_monitor_unref")) {
614 if (luaL_newmetatable(L, MONITOR_METATABLE) != 0) {
615 lua_newtable(L);
616 set_func_if_symbol_exists("sd_monitor_flush", L, monitor_flush, "flush");
617 set_func_if_symbol_exists("sd_monitor_get_fd", L, monitor_get_fd, "get_fd");
618 set_func_if_symbol_exists("sd_monitor_get_events", L, monitor_get_events,"get_events");
619 set_func_if_symbol_exists("sd_monitor_get_timeout", L, monitor_get_timeout, "get_timeout");
620 lua_setfield(L, -2, "__index");
621 lua_pushcfunction(L, monitor_unref);
622 lua_setfield(L, -2, "__gc");
623 lua_pushcfunction(L, monitor_tostring);
624 lua_setfield(L, -2, "__tostring");
625 }
626 /* Expose monitor methods */
627 lua_getfield(L, -1, "__index");
628 lua_setfield(L, -3, "MONITOR_METHODS");
629 lua_pop(L, 1);
630
631 set_func(L, monitor_new, "monitor");
632 }
633
634 set_func_if_symbol_exists("sd_pid_get_session", L, pid_get_session, "pid_get_session");
635 set_func_if_symbol_exists("sd_pid_get_unit", L, pid_get_unit, "pid_get_unit");
636 set_func_if_symbol_exists("sd_pid_get_user_unit", L, pid_get_user_unit, "pid_get_user_unit");
637 set_func_if_symbol_exists("sd_pid_get_owner_uid", L, pid_get_owner_uid, "pid_get_owner_uid");
638 set_func_if_symbol_exists("sd_pid_get_machine_name", L, pid_get_machine_name, "pid_get_machine_name");
639 set_func_if_symbol_exists("sd_pid_get_slice", L, pid_get_slice, "pid_get_slice");
640
641 set_func_if_symbol_exists("sd_uid_get_state", L, uid_get_state, "uid_get_state");
642 set_func_if_symbol_exists("sd_uid_is_on_seat", L, uid_is_on_seat, "uid_is_on_seat");
643 set_func_if_symbol_exists("sd_uid_get_sessions", L, uid_get_sessions, "uid_get_sessions");
644 set_func_if_symbol_exists("sd_uid_get_seats", L, uid_get_seats, "uid_get_seats");
645
646 set_func_if_symbol_exists("sd_session_is_active", L, session_is_active, "session_is_active");
647 set_func_if_symbol_exists("sd_session_is_remote", L, session_is_remote, "session_is_remote");
648 set_func_if_symbol_exists("sd_session_get_state", L, session_get_state, "session_get_state");
649 set_func_if_symbol_exists("sd_session_get_uid", L, session_get_uid, "session_get_uid");
650 set_func_if_symbol_exists("sd_session_get_seat", L, session_get_seat, "session_get_seat");
651 set_func_if_symbol_exists("sd_session_get_service", L, session_get_service, "session_get_service");
652 set_func_if_symbol_exists("sd_session_get_type", L, session_get_type, "session_get_type");
653 set_func_if_symbol_exists("sd_session_get_class", L, session_get_class, "session_get_class");
654 set_func_if_symbol_exists("sd_session_get_display", L, session_get_display, "session_get_display");
655 set_func_if_symbol_exists("sd_session_get_remote_host", L, session_get_remote_host, "session_get_remote_host");
656 set_func_if_symbol_exists("sd_session_get_remote_user", L, session_get_remote_user, "session_get_remote_user");
657 set_func_if_symbol_exists("sd_session_get_tty", L, session_get_tty, "session_get_tty");
658 set_func_if_symbol_exists("sd_session_get_vt", L, session_get_vt, "session_get_vt");
659
660 set_func_if_symbol_exists("sd_seat_get_active", L, seat_get_active, "seat_get_active");
661 set_func_if_symbol_exists("sd_seat_get_sessions", L, seat_get_sessions, "seat_get_sessions");
662 set_func_if_symbol_exists("sd_seat_can_multi_session", L, seat_can_multi_session, "seat_can_multi_session");
663 set_func_if_symbol_exists("sd_seat_can_tty", L, seat_can_tty, "seat_can_tty");
664 set_func_if_symbol_exists("sd_seat_can_graphical", L, seat_can_graphical, "seat_can_graphical");
665
666 set_func_if_symbol_exists("sd_get_seats", L, get_seats, "get_seats");
667 set_func_if_symbol_exists("sd_get_sessions", L, get_sessions, "get_sessions");
668 set_func_if_symbol_exists("sd_get_uids", L, get_uids, "get_uids");
669 set_func_if_symbol_exists("sd_get_machine_names", L, get_machine_names, "get_machine_names");
670 /* 211 */
671 set_func_if_symbol_exists("sd_machine_get_class", L, machine_get_class, "machine_get_class");
672 set_func_if_symbol_exists("sd_peer_get_session", L, peer_get_session, "peer_get_session");
673 set_func_if_symbol_exists("sd_peer_get_owner_uid", L, peer_get_owner_uid, "peer_get_owner_uid");
674 set_func_if_symbol_exists("sd_peer_get_unit", L, peer_get_unit, "peer_get_unit");
675 set_func_if_symbol_exists("sd_peer_get_user_unit", L, peer_get_user_unit, "peer_get_user_unit");
676 set_func_if_symbol_exists("sd_peer_get_machine_name", L, peer_get_machine_name, "peer_get_machine_name");
677 set_func_if_symbol_exists("sd_peer_get_slice", L, peer_get_slice, "peer_get_slice");
678 /* 213 */
679 set_func_if_symbol_exists("sd_sd_uid_get_display", L, uid_get_display, "sd_uid_get_display");
680 /* 216 */
681 set_func_if_symbol_exists("sd_machine_get_ifindices", L, machine_get_ifindices, "machine_get_ifindices");
682 /* 217 */
683 set_func_if_symbol_exists("sd_session_get_desktop", L, session_get_desktop, "session_get_desktop");
684 /* 220 */
685 set_func_if_symbol_exists("sd_pid_get_user_slice", L, pid_get_user_slice, "pid_get_user_slice");
686 set_func_if_symbol_exists("sd_peer_get_user_slice", L, peer_get_user_slice, "peer_get_user_slice");
687 /* 226 */
688 set_func_if_symbol_exists("sd_pid_get_cgroup", L, pid_get_cgroup, "pid_get_cgroup");
689 set_func_if_symbol_exists("sd_peer_get_cgroup", L, peer_get_cgroup, "peer_get_cgroup");
690
691 return 1;
692 }
0 #include "lua.h"
1
2 #define MONITOR_METATABLE "sd_login_monitor"
3
4 int luaopen_systemd_login_core (lua_State *L);
0 local c = require "systemd.login.core"
1
2 return c
0 #include "lua.h"
1
2 #include <stdlib.h> /* free */
3 #include <errno.h> /* ENOENT */
4
5 #include <systemd/sd-journal.h>
6
7 #include "util.c"
8 #include "messages.h"
9 #include "id128.h"
10
11
12 int journal_get_catalog_for_message_id (lua_State *L) {
13 sd_id128_t id = check_id128_t(L, 1);
14 char *ret;
15 int err = sd_journal_get_catalog_for_message_id(id, &ret);
16 if (err == -ENOENT) {
17 lua_pushboolean(L, 0);
18 return 1;
19 } else if (err != 0) {
20 return handle_error(L, -err);
21 } else {
22 lua_pushstring(L, ret);
23 free(ret);
24 return 1;
25 }
26 }
0 #include "lua.h"
1
2 __attribute__((visibility("hidden"))) int journal_get_catalog_for_message_id (lua_State *L);
0 --[[
1 This module gives aliases for some common well known message ids.
2 The aliases are taken from `sd_messages.h`.
3
4 Information about these message ids can be found in the system catalog in /usr/lib/systemd/catalog/
5 ]]
6
7 local id128 = require "systemd.id128"
8
9 local messages = {}
10
11 messages.JOURNAL_START = id128.from_string "f77379a8490b408bbe5f6940505a777b"
12 messages.JOURNAL_STOP = id128.from_string "d93fb3c9c24d451a97cea615ce59c00b"
13 messages.JOURNAL_DROPPED = id128.from_string "a596d6fe7bfa4994828e72309e95d61e"
14 messages.JOURNAL_MISSED = id128.from_string "e9bf28e6e834481bb6f48f548ad13606"
15 messages.JOURNAL_USAGE = id128.from_string "ec387f577b844b8fa948f33cad9a75e6"
16
17 messages.COREDUMP = id128.from_string "fc2e22bc6ee647b6b90729ab34a250b1"
18
19 messages.SESSION_START = id128.from_string "8d45620c1a4348dbb17410da57c60c66"
20 messages.SESSION_STOP = id128.from_string "3354939424b4456d9802ca8333ed424a"
21 messages.SEAT_START = id128.from_string "fcbefc5da23d428093f97c82a9290f7b"
22 messages.SEAT_STOP = id128.from_string "e7852bfe46784ed0accde04bc864c2d5"
23 messages.MACHINE_START = id128.from_string "24d8d4452573402496068381a6312df2"
24 messages.MACHINE_STOP = id128.from_string "58432bd3bace477cb514b56381b8a758"
25
26 messages.TIME_CHANGE = id128.from_string "c7a787079b354eaaa9e77b371893cd27"
27 messages.TIMEZONE_CHANGE = id128.from_string "45f82f4aef7a4bbf942ce861d1f20990"
28
29 messages.STARTUP_FINISHED = id128.from_string "b07a249cd024414a82dd00cd181378ff"
30
31 messages.SLEEP_START = id128.from_string "6bbd95ee977941e497c48be27c254128"
32 messages.SLEEP_STOP = id128.from_string "8811e6df2a8e40f58a94cea26f8ebf14"
33
34 messages.SHUTDOWN = id128.from_string "98268866d1d54a499c4e98921d93bc40"
35
36 messages.UNIT_STARTING = id128.from_string "7d4958e842da4a758f6c1cdc7b36dcc5"
37 messages.UNIT_STARTED = id128.from_string "39f53479d3a045ac8e11786248231fbf"
38 messages.UNIT_STOPPING = id128.from_string "de5b426a63be47a7b6ac3eaac82e2f6f"
39 messages.UNIT_STOPPED = id128.from_string "9d1aaa27d60140bd96365438aad20286"
40 messages.UNIT_FAILED = id128.from_string "be02cf6855d2428ba40df7e9d022f03d"
41 messages.UNIT_RELOADING = id128.from_string "d34d037fff1847e6ae669a370e694725"
42 messages.UNIT_RELOADED = id128.from_string "7b05ebc668384222baa8881179cfda54"
43
44 messages.SPAWN_FAILED = id128.from_string "641257651c1b4ec9a8624d7a40a9e1e7"
45
46 messages.FORWARD_SYSLOG_MISSED = id128.from_string "0027229ca0644181a76c4e92458afa2e"
47
48 messages.OVERMOUNTING = id128.from_string "1dee0369c7fc4736b7099b38ecb46ee7"
49
50 messages.LID_OPENED = id128.from_string "b72ea4a2881545a0b50e200e55b9b06f"
51 messages.LID_CLOSED = id128.from_string "b72ea4a2881545a0b50e200e55b9b070"
52 messages.SYSTEM_DOCKED = id128.from_string "f5f416b862074b28927a48c3ba7d51ff"
53 messages.SYSTEM_UNDOCKED = id128.from_string "51e171bd585248568110144c517cca53"
54 messages.POWER_KEY = id128.from_string "b72ea4a2881545a0b50e200e55b9b071"
55 messages.SUSPEND_KEY = id128.from_string "b72ea4a2881545a0b50e200e55b9b072"
56 messages.HIBERNATE_KEY = id128.from_string "b72ea4a2881545a0b50e200e55b9b073"
57
58 messages.CONFIG_ERROR = id128.from_string "c772d24e9a884cbeb9ea12625c306c01"
59
60 messages.BOOTCHART = id128.from_string "9f26aa562cf440c2b16c773d0479b518"
61
62 return messages
0 #include "lua.h"
1 #include "lauxlib.h" /* luaL_checknumber */
2
3 #include <string.h> /* strerror */
4 #include <dlfcn.h> /* dlsym, dlerror */
5
6
7 static int handle_error(lua_State *L, int err) {
8 lua_pushnil(L);
9 lua_pushstring(L, strerror(err));
10 lua_pushinteger(L, err);
11 return 3;
12 }
13
14 #ifndef lua_pushuint64
15 #define lua_pushuint64 lua_pushnumber
16 #endif
17
18 #ifndef luaL_checkuint64
19 #define luaL_checkuint64 luaL_checknumber
20 #endif
21
22 /* This hack is required as lua always passes RTLD_NOW to dlopen
23 * Without this loading lua-systemd would fail with an error about undefined symbols
24 * e.g. sd_machine_get_ifindices missing on a system running systemd 213
25 *
26 * To ensure graceful fallback we have to have some indirection via a function pointer.
27 */
28 #define shim_weak_stub_name(symbol) symbol ## _stub
29 #define shim_weak_stub(symbol) symbol ## _pointer
30 #define shim_weak_stub_declare(ret_type, symbol, args, val) \
31 static ret_type (*shim_weak_stub(symbol)) args; \
32 static ret_type shim_weak_stub_name(symbol) args { return val; } \
33 __attribute__((constructor)) static void initialize_ ## symbol() { \
34 if ((shim_weak_stub(symbol) = dlsym(RTLD_DEFAULT, #symbol)) == NULL) { \
35 shim_weak_stub(symbol) = shim_weak_stub_name(symbol); \
36 } \
37 }
38
39 #define symbol_exists(name) (dlsym(RTLD_DEFAULT, name) != NULL || dlerror() == NULL)
40 #define set_func(L, func, name) (lua_pushcclosure(L, func, 0), lua_setfield(L, -2, name))
41 #define set_func_if_symbol_exists(symbol, L, func, name) if (symbol_exists(symbol)) set_func(L, func, name)
0 package = "systemd"
1 version = "scm-0"
2 source = {
3 url = "git://github.com/daurnimator/lua-systemd"
4 }
5 description = {
6 summary = "Lua bindings to systemd",
7 homepage = "https://github.com/daurnimator/lua-systemd",
8 license = "MIT/X11"
9 }
10 dependencies = {
11 "lua >= 5.0, < 5.4"
12 }
13 build = {
14 type = "builtin",
15 modules = {
16 ["systemd.init"] = "src/init.lua",
17 ["systemd.daemon"] = "src/daemon.lua",
18 ["systemd"] = {
19 sources = {
20 "src/daemon.c",
21 "src/id128.c",
22 "src/messages.c",
23 "src/journal.c",
24 "src/login.c",
25 "vendor/compat-5.3/c-api/compat-5.3.c",
26 },
27 defines = { "_GNU_SOURCE" }, -- for RTLD_DEFAULT
28 libraries = { "systemd" },
29 incdirs = { "vendor/compat-5.3/c-api/" }
30 },
31 ["systemd.id128"] = "src/id128.lua",
32 ["systemd.journal"] = "src/journal.lua",
33 ["systemd.login"] = "src/login.lua",
34 ["systemd.messages"] = "src/messages.lua"
35 }
36 }
0 # generated files
1 *.so
2 *.dll
3 *.o
4 *.obj
5 HISTO
6
7 # vim temporaries
8 .*.swp
9
0 The MIT License (MIT)
1
2 Copyright (c) 2015 Kepler Project.
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 the Software, and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0 # lua-compat-5.3
1
2 Lua-5.3-style APIs for Lua 5.2 and 5.1.
3
4 ## What is it
5
6 This is a small module that aims to make it easier to write code
7 in a Lua-5.3-style that is compatible with Lua 5.1, Lua 5.2, and Lua
8 5.3. This does *not* make Lua 5.2 (or even Lua 5.1) entirely
9 compatible with Lua 5.3, but it brings the API closer to that of Lua
10 5.3.
11
12 It includes:
13
14 * _For writing Lua_: The Lua module `compat53`, which can be require'd
15 from Lua scripts and run in Lua 5.1, 5.2, and 5.3, including a
16 backport of the `utf8` module, the 5.3 `table` module, and the
17 string packing functions straight from the Lua 5.3 sources.
18 * _For writing C_: A C header and file which can be linked to your
19 Lua module written in C, providing some functions from the C API
20 of Lua 5.3 that do not exist in Lua 5.2 or 5.1, making it easier to
21 write C code that compiles with all three versions of liblua.
22
23 ## How to use it
24
25 ### Lua module
26
27 ```lua
28 require("compat53")
29 ```
30
31 `compat53` makes changes to your global environment and does not return
32 a meaningful return value, so the usual idiom of storing the return of
33 `require` in a local variable makes no sense.
34
35 When run under Lua 5.3, this module does nothing.
36
37 When run under Lua 5.2 or 5.1, it replaces some of your standard
38 functions and adds new ones to bring your environment closer to that
39 of Lua 5.3. It also tries to load the backported `utf8`, `table`, and
40 string packing modules automatically. If unsuccessful, pure Lua
41 versions of the new `table` functions are used as a fallback, and
42 [Roberto's struct library][1] is tried for string packing.
43
44 ### C code
45
46 There are two ways of adding the C API compatibility functions/macros to
47 your project:
48 * If `COMPAT53_PREFIX` is *not* `#define`d, `compat-5.3.h` `#include`s
49 `compat-5.3.c`, and all functions are made `static`. You don't have to
50 compile/link/add `compat-5.3.c` yourself. This is useful for one-file
51 projects.
52 * If `COMPAT53_PREFIX` is `#define`d, all exported functions are renamed
53 behind the scenes using this prefix to avoid linker conflicts with other
54 code using this package. This doesn't change the way you call the
55 compatibility functions in your code. You have to compile and link
56 `compat-5.3.c` to your project yourself. You can change the way the
57 functions are exported using the `COMPAT53_API` macro (e.g. if you need
58 some `__declspec` magic).
59
60 ## What's implemented
61
62 ### Lua
63
64 * the `utf8` module backported from the Lua 5.3 sources
65 * `string.pack`, `string.packsize`, and `string.unpack` from the Lua
66 5.3 sources or from the `struct` module. (`struct` is not 100%
67 compatible to Lua 5.3's string packing!)
68 * `math.maxinteger` and `math.mininteger`, `math.tointeger`, `math.type`,
69 and `math.ult`
70 * `ipairs` respects `__index` metamethod
71 * `table.move`
72 * `table` library respects metamethods
73
74 For Lua 5.1 additionally:
75 * `load` and `loadfile` accept `mode` and `env` parameters
76 * `table.pack` and `table.unpack`
77 * string patterns may contain embedded zeros
78 * `string.rep` accepts `sep` argument
79 * `string.format` calls `tostring` on arguments for `%s`
80 * `math.log` accepts base argument
81 * `xpcall` takes additional arguments
82 * `pcall` and `xpcall` can execute functions that yield
83 * `pairs` respects `__pairs` metamethod
84 * `rawlen` (but `#` still doesn't respect `__len` for tables)
85 * `package.searchers` as alias for `package.loaders`
86 * `package.searchpath`
87 * `coroutine` functions dealing with the main coroutine
88 * `coroutine.create` accepts functions written in C
89 * return code of `os.execute`
90 * `io.write` and `file:write` return file handle
91 * `io.lines` and `file:lines` accept format arguments (like `io.read`)
92 * `debug.setmetatable` returns object
93 * `debug.getuservalue` and `debug.setuservalue`
94
95 ### C
96
97 * `lua_KContext`
98 * `lua_KFunction`
99 * `lua_dump` (extra `strip` parameter, ignored)
100 * `lua_getfield` (return value)
101 * `lua_geti` and `lua_seti`
102 * `lua_getglobal` (return value)
103 * `lua_getmetafield` (return value)
104 * `lua_gettable` (return value)
105 * `lua_getuservalue` and `lua_setuservalue` (limited compatibility)
106 * `lua_isinteger`
107 * `lua_numbertointeger`
108 * `lua_callk` and `lua_pcallk` (limited compatibility)
109 * `lua_rawget` and `lua_rawgeti` (return values)
110 * `lua_rawgetp` and `lua_rawsetp`
111 * `luaL_requiref` (now checks `package.loaded` first)
112 * `lua_rotate`
113 * `lua_stringtonumber`
114
115 For Lua 5.1 additionally:
116 * `LUA_OK`
117 * `LUA_OP*` macros for `lua_arith` and `lua_compare`
118 * `lua_Unsigned`
119 * `luaL_Stream`
120 * `LUA_FILEHANDLE`
121 * `lua_absindex`
122 * `lua_arith`
123 * `lua_compare`
124 * `lua_len`, `lua_rawlen`, and `luaL_len`
125 * `lua_copy`
126 * `lua_pushglobaltable`
127 * `luaL_testudata`
128 * `luaL_setfuncs`, `luaL_newlibtable`, and `luaL_newlib`
129 * `luaL_setmetatable`
130 * `luaL_getsubtable`
131 * `luaL_traceback`
132 * `luaL_fileresult`
133 * `luaL_checkversion` (with empty body, only to avoid compile errors)
134 * `luaL_tolstring`
135 * `luaL_buffinitsize`, `luaL_prepbuffsize`, and `luaL_pushresultsize`
136 * `lua_pushunsigned`, `lua_tounsignedx`, `lua_tounsigned`,
137 `luaL_checkunsigned`, `luaL_optunsigned`, if
138 `LUA_COMPAT_APIINTCASTS` is defined.
139
140 ## What's not implemented
141
142 * bit operators
143 * integer division operator
144 * utf8 escape sequences
145 * 64 bit integers
146 * `coroutine.isyieldable`
147 * Lua 5.1: `_ENV`, `goto`, labels, ephemeron tables, etc. See
148 [`lua-compat-5.2`][2] for a detailed list.
149 * the following C API functions/macros:
150 * `lua_isyieldable`
151 * `lua_getextraspace`
152 * `lua_arith` (new operators missing)
153 * `lua_push(v)fstring` (new formats missing)
154 * `lua_upvalueid` (5.1)
155 * `lua_upvaluejoin` (5.1)
156 * `lua_version` (5.1)
157 * `lua_yieldk` (5.1)
158 * `luaL_execresult` (5.1)
159 * `luaL_loadbufferx` (5.1)
160 * `luaL_loadfilex` (5.1)
161
162 ### Yieldable C functions
163
164 The emulation of `lua_(p)callk` for previous Lua versions is not 100%
165 perfect, because the continuation functions in Lua 5.2 have different
166 signatures than the ones in Lua 5.3 (and Lua 5.1 doesn't have
167 continuation functions at all). But with the help of a small macro the
168 same code can be used for all three Lua versions (the 5.1 version
169 won't support yielding though).
170
171 Original Lua 5.3 code (example adapted from the Lua 5.3 manual):
172
173 ```C
174 static int k (lua_State *L, int status, lua_KContext ctx) {
175 ... /* code 2 */
176 }
177
178 int original_function (lua_State *L) {
179 ... /* code 1 */
180 return k(L, lua_pcallk(L, n, m, h, ctx2, k), ctx1);
181 }
182 ```
183
184 Portable version:
185
186 ```C
187 LUA_KFUNCTION( k ) {
188 ... /* code 2; parameters L, status, and ctx available here */
189 }
190
191 int original_function (lua_State *L) {
192 ... /* code 1 */
193 return k(L, lua_pcallk(L, n, m, h, ctx2, k), ctx1);
194 }
195 ```
196
197 ## See also
198
199 * For Lua-5.2-style APIs under Lua 5.1, see [lua-compat-5.2][2],
200 which also is the basis for most of the code in this project.
201 * For Lua-5.1-style APIs under Lua 5.0, see [Compat-5.1][3]
202
203 ## Credits
204
205 This package contains code written by:
206
207 * [The Lua Team](http://www.lua.org)
208 * Philipp Janda ([@siffiejoe](http://github.com/siffiejoe))
209 * Tomás Guisasola Gorham ([@tomasguisasola](http://github.com/tomasguisasola))
210 * Hisham Muhammad ([@hishamhm](http://github.com/hishamhm))
211 * Renato Maia ([@renatomaia](http://github.com/renatomaia))
212
213
214 [1]: http://www.inf.puc-rio.br/~roberto/struct/
215 [2]: http://github.com/keplerproject/lua-compat-5.2/
216 [3]: http://keplerproject.org/compat/
217
0 #include <stddef.h>
1 #include <stdlib.h>
2 #include <string.h>
3 #include <ctype.h>
4 #include <errno.h>
5 #include <lua.h>
6 #include <lauxlib.h>
7 #include "compat-5.3.h"
8
9 /* don't compile it again if it already is included via compat53.h */
10 #ifndef COMPAT53_C_
11 #define COMPAT53_C_
12
13
14
15 /* definitions for Lua 5.1 only */
16 #if defined( LUA_VERSION_NUM ) && LUA_VERSION_NUM == 501
17
18
19 COMPAT53_API int lua_absindex (lua_State *L, int i) {
20 if (i < 0 && i > LUA_REGISTRYINDEX)
21 i += lua_gettop(L) + 1;
22 return i;
23 }
24
25
26 static void compat53_call_lua (lua_State *L, char const code[], size_t len,
27 int nargs, int nret) {
28 lua_rawgetp(L, LUA_REGISTRYINDEX, (void*)code);
29 if (lua_type(L, -1) != LUA_TFUNCTION) {
30 lua_pop(L, 1);
31 if (luaL_loadbuffer(L, code, len, "=none"))
32 lua_error(L);
33 lua_pushvalue(L, -1);
34 lua_rawsetp(L, LUA_REGISTRYINDEX, (void*)code);
35 }
36 lua_insert(L, -nargs-1);
37 lua_call(L, nargs, nret);
38 }
39
40
41 static const char compat53_arith_code[] =
42 "local op,a,b=...\n"
43 "if op==0 then return a+b\n"
44 "elseif op==1 then return a-b\n"
45 "elseif op==2 then return a*b\n"
46 "elseif op==3 then return a/b\n"
47 "elseif op==4 then return a%b\n"
48 "elseif op==5 then return a^b\n"
49 "elseif op==6 then return -a\n"
50 "end\n";
51
52 COMPAT53_API void lua_arith (lua_State *L, int op) {
53 if (op < LUA_OPADD || op > LUA_OPUNM)
54 luaL_error(L, "invalid 'op' argument for lua_arith");
55 luaL_checkstack(L, 5, "not enough stack slots");
56 if (op == LUA_OPUNM)
57 lua_pushvalue(L, -1);
58 lua_pushnumber(L, op);
59 lua_insert(L, -3);
60 compat53_call_lua(L, compat53_arith_code,
61 sizeof(compat53_arith_code)-1, 3, 1);
62 }
63
64
65 static const char compat53_compare_code[] =
66 "local a,b=...\n"
67 "return a<=b\n";
68
69 COMPAT53_API int lua_compare (lua_State *L, int idx1, int idx2, int op) {
70 int result = 0;
71 switch (op) {
72 case LUA_OPEQ:
73 return lua_equal(L, idx1, idx2);
74 case LUA_OPLT:
75 return lua_lessthan(L, idx1, idx2);
76 case LUA_OPLE:
77 luaL_checkstack(L, 5, "not enough stack slots");
78 idx1 = lua_absindex(L, idx1);
79 idx2 = lua_absindex(L, idx2);
80 lua_pushvalue(L, idx1);
81 lua_pushvalue(L, idx2);
82 compat53_call_lua(L, compat53_compare_code,
83 sizeof(compat53_compare_code)-1, 2, 1);
84 result = lua_toboolean(L, -1);
85 lua_pop(L, 1);
86 return result;
87 default:
88 luaL_error(L, "invalid 'op' argument for lua_compare");
89 }
90 return 0;
91 }
92
93
94 COMPAT53_API void lua_copy (lua_State *L, int from, int to) {
95 int abs_to = lua_absindex(L, to);
96 luaL_checkstack(L, 1, "not enough stack slots");
97 lua_pushvalue(L, from);
98 lua_replace(L, abs_to);
99 }
100
101
102 COMPAT53_API void lua_len (lua_State *L, int i) {
103 switch (lua_type(L, i)) {
104 case LUA_TSTRING: /* fall through */
105 case LUA_TTABLE:
106 if (!luaL_callmeta(L, i, "__len"))
107 lua_pushnumber(L, (int)lua_objlen(L, i));
108 break;
109 case LUA_TUSERDATA:
110 if (luaL_callmeta(L, i, "__len"))
111 break;
112 /* maybe fall through */
113 default:
114 luaL_error(L, "attempt to get length of a %s value",
115 lua_typename(L, lua_type(L, i)));
116 }
117 }
118
119
120 COMPAT53_API int lua_rawgetp (lua_State *L, int i, const void *p) {
121 int abs_i = lua_absindex(L, i);
122 lua_pushlightuserdata(L, (void*)p);
123 lua_rawget(L, abs_i);
124 return lua_type(L, -1);
125 }
126
127 COMPAT53_API void lua_rawsetp (lua_State *L, int i, const void *p) {
128 int abs_i = lua_absindex(L, i);
129 luaL_checkstack(L, 1, "not enough stack slots");
130 lua_pushlightuserdata(L, (void*)p);
131 lua_insert(L, -2);
132 lua_rawset(L, abs_i);
133 }
134
135
136 COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum) {
137 lua_Integer n = lua_tointeger(L, i);
138 if (isnum != NULL) {
139 *isnum = (n != 0 || lua_isnumber(L, i));
140 }
141 return n;
142 }
143
144
145 COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum) {
146 lua_Number n = lua_tonumber(L, i);
147 if (isnum != NULL) {
148 *isnum = (n != 0 || lua_isnumber(L, i));
149 }
150 return n;
151 }
152
153
154 COMPAT53_API void luaL_checkversion (lua_State *L) {
155 (void)L;
156 }
157
158
159 COMPAT53_API int luaL_getsubtable (lua_State *L, int i, const char *name) {
160 int abs_i = lua_absindex(L, i);
161 luaL_checkstack(L, 3, "not enough stack slots");
162 lua_pushstring(L, name);
163 lua_gettable(L, abs_i);
164 if (lua_istable(L, -1))
165 return 1;
166 lua_pop(L, 1);
167 lua_newtable(L);
168 lua_pushstring(L, name);
169 lua_pushvalue(L, -2);
170 lua_settable(L, abs_i);
171 return 0;
172 }
173
174
175 COMPAT53_API int luaL_len (lua_State *L, int i) {
176 int res = 0, isnum = 0;
177 luaL_checkstack(L, 1, "not enough stack slots");
178 lua_len(L, i);
179 res = (int)lua_tointegerx(L, -1, &isnum);
180 lua_pop(L, 1);
181 if (!isnum)
182 luaL_error(L, "object length is not a number");
183 return res;
184 }
185
186
187 COMPAT53_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
188 luaL_checkstack(L, nup+1, "too many upvalues");
189 for (; l->name != NULL; l++) { /* fill the table with given functions */
190 int i;
191 lua_pushstring(L, l->name);
192 for (i = 0; i < nup; i++) /* copy upvalues to the top */
193 lua_pushvalue(L, -(nup + 1));
194 lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */
195 lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */
196 }
197 lua_pop(L, nup); /* remove upvalues */
198 }
199
200
201 COMPAT53_API void luaL_setmetatable (lua_State *L, const char *tname) {
202 luaL_checkstack(L, 1, "not enough stack slots");
203 luaL_getmetatable(L, tname);
204 lua_setmetatable(L, -2);
205 }
206
207
208 COMPAT53_API void *luaL_testudata (lua_State *L, int i, const char *tname) {
209 void *p = lua_touserdata(L, i);
210 luaL_checkstack(L, 2, "not enough stack slots");
211 if (p == NULL || !lua_getmetatable(L, i))
212 return NULL;
213 else {
214 int res = 0;
215 luaL_getmetatable(L, tname);
216 res = lua_rawequal(L, -1, -2);
217 lua_pop(L, 2);
218 if (!res)
219 p = NULL;
220 }
221 return p;
222 }
223
224
225 COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
226 if (!luaL_callmeta(L, idx, "__tostring")) {
227 int t = lua_type(L, idx);
228 switch (t) {
229 case LUA_TNIL:
230 lua_pushliteral(L, "nil");
231 break;
232 case LUA_TSTRING:
233 case LUA_TNUMBER:
234 lua_pushvalue(L, idx);
235 break;
236 case LUA_TBOOLEAN:
237 if (lua_toboolean(L, idx))
238 lua_pushliteral(L, "true");
239 else
240 lua_pushliteral(L, "false");
241 break;
242 default:
243 lua_pushfstring(L, "%s: %p", lua_typename(L, t),
244 lua_topointer(L, idx));
245 break;
246 }
247 }
248 return lua_tolstring(L, -1, len);
249 }
250
251
252 #if !defined(COMPAT53_IS_LUAJIT)
253 static int compat53_countlevels (lua_State *L) {
254 lua_Debug ar;
255 int li = 1, le = 1;
256 /* find an upper bound */
257 while (lua_getstack(L, le, &ar)) { li = le; le *= 2; }
258 /* do a binary search */
259 while (li < le) {
260 int m = (li + le)/2;
261 if (lua_getstack(L, m, &ar)) li = m + 1;
262 else le = m;
263 }
264 return le - 1;
265 }
266
267 static int compat53_findfield (lua_State *L, int objidx, int level) {
268 if (level == 0 || !lua_istable(L, -1))
269 return 0; /* not found */
270 lua_pushnil(L); /* start 'next' loop */
271 while (lua_next(L, -2)) { /* for each pair in table */
272 if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */
273 if (lua_rawequal(L, objidx, -1)) { /* found object? */
274 lua_pop(L, 1); /* remove value (but keep name) */
275 return 1;
276 }
277 else if (compat53_findfield(L, objidx, level - 1)) { /* try recursively */
278 lua_remove(L, -2); /* remove table (but keep name) */
279 lua_pushliteral(L, ".");
280 lua_insert(L, -2); /* place '.' between the two names */
281 lua_concat(L, 3);
282 return 1;
283 }
284 }
285 lua_pop(L, 1); /* remove value */
286 }
287 return 0; /* not found */
288 }
289
290 static int compat53_pushglobalfuncname (lua_State *L, lua_Debug *ar) {
291 int top = lua_gettop(L);
292 lua_getinfo(L, "f", ar); /* push function */
293 lua_pushvalue(L, LUA_GLOBALSINDEX);
294 if (compat53_findfield(L, top + 1, 2)) {
295 lua_copy(L, -1, top + 1); /* move name to proper place */
296 lua_pop(L, 2); /* remove pushed values */
297 return 1;
298 }
299 else {
300 lua_settop(L, top); /* remove function and global table */
301 return 0;
302 }
303 }
304
305 static void compat53_pushfuncname (lua_State *L, lua_Debug *ar) {
306 if (*ar->namewhat != '\0') /* is there a name? */
307 lua_pushfstring(L, "function " LUA_QS, ar->name);
308 else if (*ar->what == 'm') /* main? */
309 lua_pushliteral(L, "main chunk");
310 else if (*ar->what == 'C') {
311 if (compat53_pushglobalfuncname(L, ar)) {
312 lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1));
313 lua_remove(L, -2); /* remove name */
314 }
315 else
316 lua_pushliteral(L, "?");
317 }
318 else
319 lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
320 }
321
322 #define COMPAT53_LEVELS1 12 /* size of the first part of the stack */
323 #define COMPAT53_LEVELS2 10 /* size of the second part of the stack */
324
325 COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1,
326 const char *msg, int level) {
327 lua_Debug ar;
328 int top = lua_gettop(L);
329 int numlevels = compat53_countlevels(L1);
330 int mark = (numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2) ? COMPAT53_LEVELS1 : 0;
331 if (msg) lua_pushfstring(L, "%s\n", msg);
332 lua_pushliteral(L, "stack traceback:");
333 while (lua_getstack(L1, level++, &ar)) {
334 if (level == mark) { /* too many levels? */
335 lua_pushliteral(L, "\n\t..."); /* add a '...' */
336 level = numlevels - COMPAT53_LEVELS2; /* and skip to last ones */
337 }
338 else {
339 lua_getinfo(L1, "Slnt", &ar);
340 lua_pushfstring(L, "\n\t%s:", ar.short_src);
341 if (ar.currentline > 0)
342 lua_pushfstring(L, "%d:", ar.currentline);
343 lua_pushliteral(L, " in ");
344 compat53_pushfuncname(L, &ar);
345 lua_concat(L, lua_gettop(L) - top);
346 }
347 }
348 lua_concat(L, lua_gettop(L) - top);
349 }
350
351
352 COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
353 int en = errno; /* calls to Lua API may change this value */
354 if (stat) {
355 lua_pushboolean(L, 1);
356 return 1;
357 }
358 else {
359 lua_pushnil(L);
360 if (fname)
361 lua_pushfstring(L, "%s: %s", fname, strerror(en));
362 else
363 lua_pushstring(L, strerror(en));
364 lua_pushnumber(L, (lua_Number)en);
365 return 3;
366 }
367 }
368 #endif /* not COMPAT53_IS_LUAJIT */
369
370
371 COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B) {
372 /* make it crash if used via pointer to a 5.1-style luaL_Buffer */
373 B->b.p = NULL;
374 B->b.L = NULL;
375 B->b.lvl = 0;
376 /* reuse the buffer from the 5.1-style luaL_Buffer though! */
377 B->ptr = B->b.buffer;
378 B->capacity = LUAL_BUFFERSIZE;
379 B->nelems = 0;
380 B->L2 = L;
381 }
382
383
384 COMPAT53_API char *luaL_prepbuffsize (luaL_Buffer_53 *B, size_t s) {
385 if (B->capacity - B->nelems < s) { /* needs to grow */
386 char* newptr = NULL;
387 size_t newcap = B->capacity * 2;
388 if (newcap - B->nelems < s)
389 newcap = B->nelems + s;
390 if (newcap < B->capacity) /* overflow */
391 luaL_error(B->L2, "buffer too large");
392 newptr = lua_newuserdata(B->L2, newcap);
393 memcpy(newptr, B->ptr, B->nelems);
394 if (B->ptr != B->b.buffer)
395 lua_replace(B->L2, -2); /* remove old buffer */
396 B->ptr = newptr;
397 B->capacity = newcap;
398 }
399 return B->ptr+B->nelems;
400 }
401
402
403 COMPAT53_API void luaL_addlstring (luaL_Buffer_53 *B, const char *s, size_t l) {
404 memcpy(luaL_prepbuffsize(B, l), s, l);
405 luaL_addsize(B, l);
406 }
407
408
409 COMPAT53_API void luaL_addvalue (luaL_Buffer_53 *B) {
410 size_t len = 0;
411 const char *s = lua_tolstring(B->L2, -1, &len);
412 if (!s)
413 luaL_error(B->L2, "cannot convert value to string");
414 if (B->ptr != B->b.buffer)
415 lua_insert(B->L2, -2); /* userdata buffer must be at stack top */
416 luaL_addlstring(B, s, len);
417 lua_remove(B->L2, B->ptr != B->b.buffer ? -2 : -1);
418 }
419
420
421 void luaL_pushresult (luaL_Buffer_53 *B) {
422 lua_pushlstring(B->L2, B->ptr, B->nelems);
423 if (B->ptr != B->b.buffer)
424 lua_replace(B->L2, -2); /* remove userdata buffer */
425 }
426
427
428 #endif /* Lua 5.1 */
429
430
431
432 /* definitions for Lua 5.1 and Lua 5.2 */
433 #if defined( LUA_VERSION_NUM ) && LUA_VERSION_NUM <= 502
434
435
436 COMPAT53_API int lua_geti (lua_State *L, int index, lua_Integer i) {
437 index = lua_absindex(L, index);
438 lua_pushinteger(L, i);
439 lua_gettable(L, index);
440 return lua_type(L, -1);
441 }
442
443
444 COMPAT53_API int lua_isinteger (lua_State *L, int index) {
445 if (lua_type(L, index) == LUA_TNUMBER) {
446 lua_Number n = lua_tonumber(L, index);
447 lua_Integer i = lua_tointeger(L, index);
448 if (i == n)
449 return 1;
450 }
451 return 0;
452 }
453
454
455 static void compat53_reverse (lua_State *L, int a, int b) {
456 for (; a < b; ++a, --b) {
457 lua_pushvalue(L, a);
458 lua_pushvalue(L, b);
459 lua_replace(L, a);
460 lua_replace(L, b);
461 }
462 }
463
464
465 COMPAT53_API void lua_rotate (lua_State *L, int idx, int n) {
466 int n_elems = 0;
467 idx = lua_absindex(L, idx);
468 n_elems = lua_gettop(L)-idx+1;
469 if (n < 0)
470 n += n_elems;
471 if ( n > 0 && n < n_elems) {
472 luaL_checkstack(L, 2, "not enough stack slots available");
473 n = n_elems - n;
474 compat53_reverse(L, idx, idx+n-1);
475 compat53_reverse(L, idx+n, idx+n_elems-1);
476 compat53_reverse(L, idx, idx+n_elems-1);
477 }
478 }
479
480
481 COMPAT53_API void lua_seti (lua_State *L, int index, lua_Integer i) {
482 luaL_checkstack(L, 1, "not enough stack slots available");
483 index = lua_absindex(L, index);
484 lua_pushinteger(L, i);
485 lua_insert(L, -2);
486 lua_settable(L, index);
487 }
488
489
490 #if !defined(lua_str2number)
491 # define lua_str2number(s, p) strtod(s, p)
492 #endif
493
494 COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s) {
495 char* endptr;
496 lua_Number n = lua_str2number(s, &endptr);
497 if (endptr != s) {
498 while (*endptr != '\0' && isspace((unsigned char)*endptr))
499 ++endptr;
500 if (*endptr == '\0') {
501 lua_pushnumber(L, n);
502 return endptr - s + 1;
503 }
504 }
505 return 0;
506 }
507
508
509 COMPAT53_API void luaL_requiref (lua_State *L, const char *modname,
510 lua_CFunction openf, int glb) {
511 luaL_checkstack(L, 3, "not enough stack slots available");
512 lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
513 if (lua_getfield(L, -1, modname) == LUA_TNIL) {
514 lua_pop(L, 1);
515 lua_pushcfunction(L, openf);
516 lua_pushstring(L, modname);
517 lua_call(L, 1, 1);
518 lua_pushvalue(L, -1);
519 lua_setfield(L, -3, modname);
520 }
521 if (glb) {
522 lua_pushvalue(L, -1);
523 lua_setglobal(L, modname);
524 }
525 lua_replace(L, -2);
526 }
527
528
529 #endif /* Lua 5.1 and 5.2 */
530
531
532 #endif /* COMPAT53_C_ */
533
534
535 /*********************************************************************
536 * This file contains parts of Lua 5.2's and Lua 5.3's source code:
537 *
538 * Copyright (C) 1994-2014 Lua.org, PUC-Rio.
539 *
540 * Permission is hereby granted, free of charge, to any person obtaining
541 * a copy of this software and associated documentation files (the
542 * "Software"), to deal in the Software without restriction, including
543 * without limitation the rights to use, copy, modify, merge, publish,
544 * distribute, sublicense, and/or sell copies of the Software, and to
545 * permit persons to whom the Software is furnished to do so, subject to
546 * the following conditions:
547 *
548 * The above copyright notice and this permission notice shall be
549 * included in all copies or substantial portions of the Software.
550 *
551 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
552 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
553 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
554 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
555 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
556 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
557 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
558 *********************************************************************/
559
0 #ifndef COMPAT53_H_
1 #define COMPAT53_H_
2
3 #include <stddef.h>
4 #include <limits.h>
5 #include <string.h>
6 #include <lua.h>
7 #include <lauxlib.h>
8 #include <lualib.h>
9
10
11 #if defined(COMPAT53_PREFIX)
12 /* - change the symbol names of functions to avoid linker conflicts
13 * - compat-5.3.c needs to be compiled (and linked) separately
14 */
15 # if !defined(COMPAT53_API)
16 # define COMPAT53_API extern
17 # endif
18 # undef COMPAT53_INCLUDE_SOURCE
19 #else /* COMPAT53_PREFIX */
20 /* - make all functions static and include the source.
21 * - don't mess with the symbol names of functions
22 * - compat-5.3.c doesn't need to be compiled (and linked) separately
23 */
24 # define COMPAT53_PREFIX lua
25 # undef COMPAT53_API
26 # if defined(__GNUC__) || defined(__clang__)
27 # define COMPAT53_API __attribute__((__unused__)) static
28 # else
29 # define COMPAT53_API static
30 # endif
31 # define COMPAT53_INCLUDE_SOURCE
32 #endif /* COMPAT53_PREFIX */
33
34 #define COMPAT53_CONCAT_HELPER(a, b) a##b
35 #define COMPAT53_CONCAT(a, b) COMPAT53_CONCAT_HELPER(a, b)
36
37
38
39 /* declarations for Lua 5.1 */
40 #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501
41
42 /* XXX not implemented:
43 * lua_arith (new operators)
44 * lua_upvalueid
45 * lua_upvaluejoin
46 * lua_version
47 * lua_yieldk
48 * luaL_execresult
49 * luaL_loadbufferx
50 * luaL_loadfilex
51 */
52
53 /* PUC-Rio Lua uses lconfig_h as include guard for luaconf.h,
54 * LuaJIT uses luaconf_h. If you use PUC-Rio's include files
55 * but LuaJIT's library, you will need to define the macro
56 * COMPAT53_IS_LUAJIT yourself! */
57 #if !defined(COMPAT53_IS_LUAJIT) && defined(luaconf_h)
58 # define COMPAT53_IS_LUAJIT
59 #endif
60
61 #define LUA_OK 0
62 #define LUA_OPADD 0
63 #define LUA_OPSUB 1
64 #define LUA_OPMUL 2
65 #define LUA_OPDIV 3
66 #define LUA_OPMOD 4
67 #define LUA_OPPOW 5
68 #define LUA_OPUNM 6
69 #define LUA_OPEQ 0
70 #define LUA_OPLT 1
71 #define LUA_OPLE 2
72
73 typedef struct luaL_Stream {
74 FILE *f;
75 /* The following field is for LuaJIT which adds a uint32_t field
76 * to file handles. */
77 #if INT_MAX > 2147483640L
78 unsigned int type;
79 #else
80 unsigned long type;
81 #endif
82 lua_CFunction closef;
83 } luaL_Stream;
84
85 typedef size_t lua_Unsigned;
86
87 typedef struct luaL_Buffer_53 {
88 luaL_Buffer b; /* make incorrect code crash! */
89 char *ptr;
90 size_t nelems;
91 size_t capacity;
92 lua_State *L2;
93 } luaL_Buffer_53;
94 #define luaL_Buffer luaL_Buffer_53
95
96 #define lua_absindex COMPAT53_CONCAT(COMPAT53_PREFIX, _absindex)
97 COMPAT53_API int lua_absindex (lua_State *L, int i);
98
99 #define lua_arith COMPAT53_CONCAT(COMPAT53_PREFIX, _arith)
100 COMPAT53_API void lua_arith (lua_State *L, int op);
101
102 #define lua_compare COMPAT53_CONCAT(COMPAT53_PREFIX, _compare)
103 COMPAT53_API int lua_compare (lua_State *L, int idx1, int idx2, int op);
104
105 #define lua_copy COMPAT53_CONCAT(COMPAT53_PREFIX, _copy)
106 COMPAT53_API void lua_copy (lua_State *L, int from, int to);
107
108 #define lua_getuservalue(L, i) \
109 (lua_getfenv(L, i), lua_type(L, -1))
110 #define lua_setuservalue(L, i) \
111 (luaL_checktype(L, -1, LUA_TTABLE), lua_setfenv(L, i))
112
113 #define lua_len COMPAT53_CONCAT(COMPAT53_PREFIX, _len)
114 COMPAT53_API void lua_len (lua_State *L, int i);
115
116 #define luaL_newlibtable(L, l) \
117 (lua_createtable(L, 0, sizeof(l)/sizeof(*(l))-1))
118 #define luaL_newlib(L, l) \
119 (luaL_newlibtable(L, l), luaL_register(L, NULL, l))
120
121 #define lua_pushglobaltable(L) \
122 lua_pushvalue(L, LUA_GLOBALSINDEX)
123
124 #define lua_rawgetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawgetp)
125 COMPAT53_API int lua_rawgetp (lua_State *L, int i, const void *p);
126
127 #define lua_rawsetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawsetp)
128 COMPAT53_API void lua_rawsetp(lua_State *L, int i, const void *p);
129
130 #define lua_rawlen(L, i) lua_objlen(L, i)
131
132 #define lua_tointegerx COMPAT53_CONCAT(COMPAT53_PREFIX, _tointegerx)
133 COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum);
134
135 #define lua_tonumberx COMPAT53_CONCAT(COMPAT53_PREFIX, _tonumberx)
136 COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum);
137
138 #define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion)
139 COMPAT53_API void luaL_checkversion (lua_State *L);
140
141 #define luaL_getsubtable COMPAT53_CONCAT(COMPAT53_PREFIX, L_getsubtable)
142 COMPAT53_API int luaL_getsubtable (lua_State* L, int i, const char *name);
143
144 #define luaL_len COMPAT53_CONCAT(COMPAT53_PREFIX, L_len)
145 COMPAT53_API int luaL_len (lua_State *L, int i);
146
147 #define luaL_setfuncs COMPAT53_CONCAT(COMPAT53_PREFIX, L_setfuncs)
148 COMPAT53_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
149
150 #define luaL_setmetatable COMPAT53_CONCAT(COMPAT53_PREFIX, L_setmetatable)
151 COMPAT53_API void luaL_setmetatable (lua_State *L, const char *tname);
152
153 #define luaL_testudata COMPAT53_CONCAT(COMPAT53_PREFIX, L_testudata)
154 COMPAT53_API void *luaL_testudata (lua_State *L, int i, const char *tname);
155
156 #define luaL_tolstring COMPAT53_CONCAT(COMPAT53_PREFIX, L_tolstring)
157 COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len);
158
159 #if !defined(COMPAT53_IS_LUAJIT)
160 #define luaL_traceback COMPAT53_CONCAT(COMPAT53_PREFIX, L_traceback)
161 COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level);
162
163 #define luaL_fileresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_fileresult)
164 COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname);
165 #endif /* COMPAT53_IS_LUAJIT */
166
167 #define lua_callk(L, na, nr, ctx, cont) \
168 ((void)(ctx), (void)(cont), lua_call(L, na, nr))
169 #define lua_pcallk(L, na, nr, err, ctx, cont) \
170 ((void)(ctx), (void)(cont), lua_pcall(L, na, nr, err))
171
172 #define luaL_buffinit COMPAT53_CONCAT(COMPAT53_PREFIX, _buffinit_53)
173 COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B);
174
175 #define luaL_prepbuffsize COMPAT53_CONCAT(COMPAT53_PREFIX, _prepbufsize_53)
176 COMPAT53_API char *luaL_prepbuffsize (luaL_Buffer_53 *B, size_t s);
177
178 #define luaL_addlstring COMPAT53_CONCAT(COMPAT53_PREFIX, _addlstring_53)
179 COMPAT53_API void luaL_addlstring (luaL_Buffer_53 *B, const char *s, size_t l);
180
181 #define luaL_addvalue COMPAT53_CONCAT(COMPAT53_PREFIX, _addvalue_53)
182 COMPAT53_API void luaL_addvalue (luaL_Buffer_53 *B);
183
184 #define luaL_pushresult COMPAT53_CONCAT(COMPAT53_PREFIX, _pushresult_53)
185 COMPAT53_API void luaL_pushresult (luaL_Buffer_53 *B);
186
187 #undef luaL_buffinitsize
188 #define luaL_buffinitsize(L, B, s) \
189 (luaL_buffinit(L, B), luaL_prepbuffsize(B, s))
190
191 #undef luaL_prepbuffer
192 #define luaL_prepbuffer(B) \
193 luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
194
195 #undef luaL_addchar
196 #define luaL_addchar(B, c) \
197 ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize(B, 1)), \
198 ((B)->ptr[(B)->nelems++] = (c)))
199
200 #undef luaL_addsize
201 #define luaL_addsize(B, s) \
202 ((B)->nelems += (s))
203
204 #undef luaL_addstring
205 #define luaL_addstring(B, s) \
206 luaL_addlstring(B, s, strlen(s))
207
208 #undef luaL_pushresultsize
209 #define luaL_pushresultsize(B, s) \
210 (luaL_addsize(B, s), luaL_pushresult(B))
211
212 #if defined(LUA_COMPAT_APIINTCASTS)
213 #define lua_pushunsigned(L, n) \
214 lua_pushinteger(L, (lua_Integer)(n))
215 #define lua_tounsignedx(L, i, is) \
216 ((lua_Unsigned)lua_tointegerx(L, i, is))
217 #define lua_tounsigned(L, i) \
218 lua_tounsignedx(L, i, NULL)
219 #define luaL_checkunsigned(L, a) \
220 ((lua_Unsigned)luaL_checkinteger(L, a))
221 #define luaL_optunsigned(L, a, d) \
222 ((lua_Unsigned)luaL_optinteger(L, a, (lua_Integer)(d)))
223 #endif
224
225 #endif /* Lua 5.1 only */
226
227
228
229 /* declarations for Lua 5.1 and 5.2 */
230 #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 502
231
232 typedef int lua_KContext;
233
234 typedef int (*lua_KFunction)(lua_State *L, int status, lua_KContext ctx);
235
236 #define lua_dump(L, w, d, s) \
237 ((void)(s), lua_dump(L, w, d))
238
239 #define lua_getfield(L, i, k) \
240 (lua_getfield(L, i, k), lua_type(L, -1))
241
242 #define lua_gettable(L, i) \
243 (lua_gettable(L, i), lua_type(L, -1))
244
245 #define lua_geti COMPAT53_CONCAT(COMPAT53_PREFIX, _geti)
246 COMPAT53_API int lua_geti (lua_State *L, int index, lua_Integer i);
247
248 #define lua_isinteger COMPAT53_CONCAT(COMPAT53_PREFIX, _isinteger)
249 COMPAT53_API int lua_isinteger (lua_State *L, int index);
250
251 #define lua_numbertointeger(n, p) \
252 ((*(p) = (lua_Integer)(n)), 1)
253
254 #define lua_rawget(L, i) \
255 (lua_rawget(L, i), lua_type(L, -1))
256
257 #define lua_rawgeti(L, i, n) \
258 (lua_rawgeti(L, i, n), lua_type(L, -1))
259
260 #define lua_rotate COMPAT53_CONCAT(COMPAT53_PREFIX, _rotate)
261 COMPAT53_API void lua_rotate (lua_State *L, int idx, int n);
262
263 #define lua_seti COMPAT53_CONCAT(COMPAT53_PREFIX, _seti)
264 COMPAT53_API void lua_seti (lua_State *L, int index, lua_Integer i);
265
266 #define lua_strtonum COMPAT53_CONCAT(COMPAT53_PREFIX, _stringtonumber)
267 COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s);
268
269 #define luaL_getmetafield(L, o, e) \
270 (luaL_getmetafield(L, o, e) ? lua_type(L, -1) : LUA_TNIL)
271
272 #define luaL_requiref COMPAT53_CONCAT(COMPAT53_PREFIX, L_requiref_53)
273 COMPAT53_API void luaL_requiref (lua_State *L, const char *modname,
274 lua_CFunction openf, int glb );
275
276 #endif /* Lua 5.1 and Lua 5.2 */
277
278
279
280 /* declarations for Lua 5.2 */
281 #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 502
282
283 /* XXX not implemented:
284 * lua_isyieldable
285 * lua_getextraspace
286 * lua_arith (new operators)
287 * lua_pushfstring (new formats)
288 */
289
290 #define lua_getglobal(L, n) \
291 (lua_getglobal(L, n), lua_type(L, -1))
292
293 #define lua_getuservalue(L, i) \
294 (lua_getuservalue(L, i), lua_type(L, -1))
295
296 #define lua_rawgetp(L, i, p) \
297 (lua_rawgetp(L, i, p), lua_type(L, -1))
298
299 #define LUA_KFUNCTION(_name) \
300 static int (_name)(lua_State *L, int status, lua_KContext ctx); \
301 static int (_name ## _52)(lua_State *L) { \
302 lua_KContext ctx; \
303 int status = lua_getctx(L, &ctx); \
304 return (_name)(L, status, ctx); \
305 } \
306 static int (_name)(lua_State *L, int status, lua_KContext ctx)
307
308 #define lua_pcallk(L, na, nr, err, ctx, cont) \
309 lua_pcallk(L, na, nr, err, ctx, cont ## _52)
310
311 #define lua_callk(L, na, nr, ctx, cont) \
312 lua_callk(L, na, nr, ctx, cont ## _52)
313
314 #define lua_yieldk(L, nr, ctx, cont) \
315 lua_yieldk(L, nr, ctx, cont ## _52)
316
317 #ifdef lua_call
318 # undef lua_call
319 # define lua_call(L, na, nr) \
320 (lua_callk)(L, na, nr, 0, NULL)
321 #endif
322
323 #ifdef lua_pcall
324 # undef lua_pcall
325 # define lua_pcall(L, na, nr, err) \
326 (lua_pcallk)(L, na, nr, err, 0, NULL)
327 #endif
328
329 #ifdef lua_yield
330 # undef lua_yield
331 # define lua_yield(L, nr) \
332 (lua_yieldk)(L, nr, 0, NULL)
333 #endif
334
335 #endif /* Lua 5.2 only */
336
337
338
339 /* other Lua versions */
340 #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 || LUA_VERSION_NUM > 503
341
342 # error "unsupported Lua version (i.e. not Lua 5.1, 5.2, or 5.3)"
343
344 #endif /* other Lua versions except 5.1, 5.2, and 5.3 */
345
346
347
348 /* helper macro for defining continuation functions (for every version
349 * *except* Lua 5.2) */
350 #ifndef LUA_KFUNCTION
351 #define LUA_KFUNCTION(_name) \
352 static int (_name)(lua_State *L, int status, lua_KContext ctx)
353 #endif
354
355
356 #if defined(COMPAT53_INCLUDE_SOURCE)
357 # include "compat-5.3.c"
358 #endif
359
360
361 #endif /* COMPAT53_H_ */
362
0 local lua_version = _VERSION:sub(-3)
1
2 if lua_version < "5.3" then
3 -- local aliases for commonly used functions
4 local type, select, error = type, select, error
5
6 -- select the most powerful getmetatable function available
7 local gmt = type(debug) == "table" and debug.getmetatable or
8 getmetatable or function() return false end
9
10 -- type checking functions
11 local checkinteger -- forward declararation
12
13 local function argcheck(cond, i, f, extra)
14 if not cond then
15 error("bad argument #"..i.." to '"..f.."' ("..extra..")", 0)
16 end
17 end
18
19 local function checktype(x, t, i, f)
20 local xt = type(x)
21 if xt ~= t then
22 error("bad argument #"..i.." to '"..f.."' ("..t..
23 " expected, got "..xt..")", 0)
24 end
25 end
26
27
28 -- load utf8 library
29 local utf8_ok, utf8lib = pcall(require, "compat53.utf8")
30 if utf8_ok then
31 utf8 = utf8lib
32 package.loaded["utf8"] = utf8lib
33 if lua_version == "5.1" then
34 utf8lib.charpattern = "[%z\1-\127\194-\244][\128-\191]*"
35 end
36 end
37
38
39 -- load table library
40 local table_ok, tablib = pcall(require, "compat53.table")
41 if table_ok then
42 for k,v in pairs(tablib) do
43 table[k] = v
44 end
45 end
46
47
48 -- load string packing functions
49 local str_ok, strlib = pcall(require, "compat53.string")
50 if str_ok then
51 for k,v in pairs(strlib) do
52 string[k] = v
53 end
54 end
55
56
57 -- try Roberto's struct module for string packing/unpacking if
58 -- compat53.string is unavailable
59 if not str_ok then
60 local struct_ok, struct = pcall(require, "struct")
61 if struct_ok then
62 string.pack = struct.pack
63 string.packsize = struct.size
64 string.unpack = struct.unpack
65 end
66 end
67
68
69 -- update math library
70 do
71 local maxint, minint = 1, 0
72
73 while maxint+1 > maxint and 2*maxint > maxint do
74 maxint = maxint * 2
75 end
76 if 2*maxint <= maxint then
77 maxint = 2*maxint-1
78 minint = -maxint-1
79 else
80 maxint = maxint
81 minint = -maxint
82 end
83 math.maxinteger = maxint
84 math.mininteger = minint
85
86 function math.tointeger(n)
87 if type(n) == "number" and n <= maxint and n >= minint and n % 1 == 0 then
88 return n
89 end
90 return nil
91 end
92
93 function math.type(n)
94 if type(n) == "number" then
95 if n <= maxint and n >= minint and n % 1 == 0 then
96 return "integer"
97 else
98 return "float"
99 end
100 else
101 return nil
102 end
103 end
104
105 function checkinteger(x, i, f)
106 local t = type(x)
107 if t ~= "number" then
108 error("bad argument #"..i.." to '"..f..
109 "' (number expected, got "..t..")", 0)
110 elseif x > maxint or x < minint or x % 1 ~= 0 then
111 error("bad argument #"..i.." to '"..f..
112 "' (number has no integer representation)", 0)
113 else
114 return x
115 end
116 end
117
118 function math.ult(m, n)
119 m = checkinteger(m, "1", "math.ult")
120 n = checkinteger(n, "2", "math.ult")
121 if m >= 0 and n < 0 then
122 return true
123 elseif m < 0 and n >= 0 then
124 return false
125 else
126 return m < n
127 end
128 end
129 end
130
131
132 -- ipairs should respect __index metamethod
133 do
134 local _ipairs = ipairs
135 local function ipairs_iterator(st, var)
136 var = var + 1
137 local val = st[var]
138 if val ~= nil then
139 return var, st[var]
140 end
141 end
142 function ipairs(t)
143 if gmt(t) ~= nil then -- t has metatable
144 return ipairs_iterator, t, 0
145 else
146 return _ipairs(t)
147 end
148 end
149 end
150
151
152 -- update table library (if C module not available)
153 if not table_ok then
154 local table_concat = table.concat
155 function table.concat(list, sep, i, j)
156 local mt = gmt(list)
157 if type(mt) == "table" and type(mt.__len) == "function" then
158 local src = list
159 list, i, j = {}, i or 1, j or mt.__len(src)
160 for k = i, j do
161 list[k] = src[k]
162 end
163 end
164 return table_concat(list, sep, i, j)
165 end
166
167 local table_insert = table.insert
168 function table.insert(list, ...)
169 local mt = gmt(list)
170 local has_mt = type(mt) == "table"
171 local has_len = has_mt and type(mt.__len) == "function"
172 if has_mt and (has_len or mt.__index or mt.__newindex) then
173 local e = (has_len and mt.__len(list) or #list)+1
174 local nargs, pos, value = select('#', ...), ...
175 if nargs == 1 then
176 pos, value = e, pos
177 elseif nargs == 2 then
178 pos = checkinteger(pos, "2", "table.insert")
179 argcheck(1 <= pos and pos <= e, "2", "table.insert",
180 "position out of bounds" )
181 else
182 error("wrong number of arguments to 'insert'", 0)
183 end
184 for i = e-1, pos, -1 do
185 list[i+1] = list[i]
186 end
187 list[pos] = value
188 else
189 return table_insert(list, ...)
190 end
191 end
192
193 function table.move(a1, f, e, t, a2)
194 a2 = a2 or a1
195 f = checkinteger(f, "2", "table.move")
196 argcheck(f > 0, "2", "table.move",
197 "initial position must be positive")
198 e = checkinteger(e, "3", "table.move")
199 t = checkinteger(t, "4", "table.move")
200 if e >= f then
201 local m, n, d = 0, e-f, 1
202 if t > f then m, n, d = n, m, -1 end
203 for i = m, n, d do
204 a2[t+i] = a1[f+i]
205 end
206 end
207 return a2
208 end
209
210 local table_remove = table.remove
211 function table.remove(list, pos)
212 local mt = gmt(list)
213 local has_mt = type(mt) == "table"
214 local has_len = has_mt and type(mt.__len) == "function"
215 if has_mt and (has_len or mt.__index or mt.__newindex) then
216 local e = (has_len and mt.__len(list) or #list)
217 pos = pos ~= nil and checkinteger(pos, "2", "table.remove") or e
218 if pos ~= e then
219 argcheck(1 <= pos and pos <= e+1, "2", "table.remove",
220 "position out of bounds" )
221 end
222 local result = list[pos]
223 while pos < e do
224 list[pos] = list[pos+1]
225 pos = pos + 1
226 end
227 list[pos] = nil
228 return result
229 else
230 return table_remove(list, pos)
231 end
232 end
233
234 do
235 local function pivot(list, cmp, a, b)
236 local m = b - a
237 if m > 2 then
238 local c = a + (m-m%2)/2
239 local x, y, z = list[a], list[b], list[c]
240 if not cmp(x, y) then
241 x, y, a, b = y, x, b, a
242 end
243 if not cmp(y, z) then
244 y, z, b, c = z, y, c, b
245 end
246 if not cmp(x, y) then
247 x, y, a, b = y, x, b, a
248 end
249 return b, y
250 else
251 return b, list[b]
252 end
253 end
254
255 local function lt_cmp(a, b)
256 return a < b
257 end
258
259 local function qsort(list, cmp, b, e)
260 if b < e then
261 local i, j, k, val = b, e, pivot(list, cmp, b, e)
262 while i < j do
263 while i < j and cmp(list[i], val) do
264 i = i + 1
265 end
266 while i < j and not cmp(list[j], val) do
267 j = j - 1
268 end
269 if i < j then
270 list[i], list[j] = list[j], list[i]
271 if i == k then k = j end -- update pivot position
272 i, j = i+1, j-1
273 end
274 end
275 if i ~= k and not cmp(list[i], val) then
276 list[i], list[k] = val, list[i]
277 k = i -- update pivot position
278 end
279 qsort(list, cmp, b, i == k and i-1 or i)
280 return qsort(list, cmp, i+1, e)
281 end
282 end
283
284 local table_sort = table.sort
285 function table.sort(list, cmp)
286 local mt = gmt(list)
287 local has_mt = type(mt) == "table"
288 local has_len = has_mt and type(mt.__len) == "function"
289 if has_len then
290 cmp = cmp or lt_cmp
291 local len = mt.__len(list)
292 return qsort(list, cmp, 1, len)
293 else
294 return table_sort(list, cmp)
295 end
296 end
297 end
298
299 local table_unpack = lua_version == "5.1" and unpack or table.unpack
300 local function unpack_helper(list, i, j, ...)
301 if j < i then
302 return ...
303 else
304 return unpack_helper(list, i, j-1, list[j], ...)
305 end
306 end
307 function table.unpack(list, i, j)
308 local mt = gmt(list)
309 local has_mt = type(mt) == "table"
310 local has_len = has_mt and type(mt.__len) == "function"
311 if has_mt and (has_len or mt.__index) then
312 i, j = i or 1, j or (has_len and mt.__len(list)) or #list
313 return unpack_helper(list, i, j)
314 else
315 return table_unpack(list, i, j)
316 end
317 end
318 end -- update table library
319
320
321
322 -- bring Lua 5.1 (and LuaJIT) up to speed with Lua 5.2
323 if lua_version == "5.1" then
324 -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag)
325 local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ"
326 local is_luajit52 = is_luajit and
327 #setmetatable({}, { __len = function() return 1 end }) == 1
328
329
330 -- table that maps each running coroutine to the coroutine that resumed it
331 -- this is used to build complete tracebacks when "coroutine-friendly" pcall
332 -- is used.
333 local pcall_previous = {}
334 local pcall_callOf = {}
335 local xpcall_running = {}
336 local coroutine_running = coroutine.running
337
338 -- handle debug functions
339 if type(debug) == "table" then
340
341 if not is_luajit52 then
342 local _G, package = _G, package
343 local debug_setfenv = debug.setfenv
344 function debug.setuservalue(obj, value)
345 if type(obj) ~= "userdata" then
346 error("bad argument #1 to 'setuservalue' (userdata expected, got "..
347 type(obj)..")", 2)
348 end
349 if value == nil then value = _G end
350 if type(value) ~= "table" then
351 error("bad argument #2 to 'setuservalue' (table expected, got "..
352 type(value)..")", 2)
353 end
354 return debug_setfenv(obj, value)
355 end
356
357 local debug_getfenv = debug.getfenv
358 function debug.getuservalue(obj)
359 if type(obj) ~= "userdata" then
360 return nil
361 else
362 local v = debug_getfenv(obj)
363 if v == _G or v == package then
364 return nil
365 end
366 return v
367 end
368 end
369
370 local debug_setmetatable = debug.setmetatable
371 function debug.setmetatable(value, tab)
372 debug_setmetatable(value, tab)
373 return value
374 end
375 end -- not luajit with compat52 enabled
376
377 if not is_luajit then
378 local debug_getinfo = debug.getinfo
379 local function calculate_trace_level(co, level)
380 if level ~= nil then
381 for out = 1, 1/0 do
382 local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "")
383 if info == nil then
384 local max = out-1
385 if level <= max then
386 return level
387 end
388 return nil, level-max
389 end
390 end
391 end
392 return 1
393 end
394
395 local stack_pattern = "\nstack traceback:"
396 local stack_replace = ""
397 local debug_traceback = debug.traceback
398 function debug.traceback(co, msg, level)
399 local lvl
400 local nilmsg
401 if type(co) ~= "thread" then
402 co, msg, level = coroutine_running(), co, msg
403 end
404 if msg == nil then
405 msg = ""
406 nilmsg = true
407 elseif type(msg) ~= "string" then
408 return msg
409 end
410 if co == nil then
411 msg = debug_traceback(msg, level or 1)
412 else
413 local xpco = xpcall_running[co]
414 if xpco ~= nil then
415 lvl, level = calculate_trace_level(xpco, level)
416 if lvl then
417 msg = debug_traceback(xpco, msg, lvl)
418 else
419 msg = msg..stack_pattern
420 end
421 lvl, level = calculate_trace_level(co, level)
422 if lvl then
423 local trace = debug_traceback(co, "", lvl)
424 msg = msg..trace:gsub(stack_pattern, stack_replace)
425 end
426 else
427 co = pcall_callOf[co] or co
428 lvl, level = calculate_trace_level(co, level)
429 if lvl then
430 msg = debug_traceback(co, msg, lvl)
431 else
432 msg = msg..stack_pattern
433 end
434 end
435 co = pcall_previous[co]
436 while co ~= nil do
437 lvl, level = calculate_trace_level(co, level)
438 if lvl then
439 local trace = debug_traceback(co, "", lvl)
440 msg = msg..trace:gsub(stack_pattern, stack_replace)
441 end
442 co = pcall_previous[co]
443 end
444 end
445 if nilmsg then
446 msg = msg:gsub("^\n", "")
447 end
448 msg = msg:gsub("\n\t%(tail call%): %?", "\000")
449 msg = msg:gsub("\n\t%.%.%.\n", "\001\n")
450 msg = msg:gsub("\n\t%.%.%.$", "\001")
451 msg = msg:gsub("(%z+)\001(%z+)", function(some, other)
452 return "\n\t(..."..#some+#other.."+ tail call(s)...)"
453 end)
454 msg = msg:gsub("\001(%z+)", function(zeros)
455 return "\n\t(..."..#zeros.."+ tail call(s)...)"
456 end)
457 msg = msg:gsub("(%z+)\001", function(zeros)
458 return "\n\t(..."..#zeros.."+ tail call(s)...)"
459 end)
460 msg = msg:gsub("%z+", function(zeros)
461 return "\n\t(..."..#zeros.." tail call(s)...)"
462 end)
463 msg = msg:gsub("\001", function(zeros)
464 return "\n\t..."
465 end)
466 return msg
467 end
468 end -- is not luajit
469 end -- debug table available
470
471
472 if not is_luajit52 then
473 local _pairs = pairs
474 function pairs(t)
475 local mt = gmt(t)
476 if type(mt) == "table" and type(mt.__pairs) == "function" then
477 return mt.__pairs(t)
478 else
479 return _pairs(t)
480 end
481 end
482 end
483
484
485 if not is_luajit then
486 local function check_mode(mode, prefix)
487 local has = { text = false, binary = false }
488 for i = 1,#mode do
489 local c = mode:sub(i, i)
490 if c == "t" then has.text = true end
491 if c == "b" then has.binary = true end
492 end
493 local t = prefix:sub(1, 1) == "\27" and "binary" or "text"
494 if not has[t] then
495 return "attempt to load a "..t.." chunk (mode is '"..mode.."')"
496 end
497 end
498
499 local setfenv = setfenv
500 local _load, _loadstring = load, loadstring
501 function load(ld, source, mode, env)
502 mode = mode or "bt"
503 local chunk, msg
504 if type( ld ) == "string" then
505 if mode ~= "bt" then
506 local merr = check_mode(mode, ld)
507 if merr then return nil, merr end
508 end
509 chunk, msg = _loadstring(ld, source)
510 else
511 local ld_type = type(ld)
512 if ld_type ~= "function" then
513 error("bad argument #1 to 'load' (function expected, got "..
514 ld_type..")", 2)
515 end
516 if mode ~= "bt" then
517 local checked, merr = false, nil
518 local function checked_ld()
519 if checked then
520 return ld()
521 else
522 checked = true
523 local v = ld()
524 merr = check_mode(mode, v or "")
525 if merr then return nil end
526 return v
527 end
528 end
529 chunk, msg = _load(checked_ld, source)
530 if merr then return nil, merr end
531 else
532 chunk, msg = _load(ld, source)
533 end
534 end
535 if not chunk then
536 return chunk, msg
537 end
538 if env ~= nil then
539 setfenv(chunk, env)
540 end
541 return chunk
542 end
543
544 loadstring = load
545
546 local _loadfile = loadfile
547 local io_open = io.open
548 function loadfile(file, mode, env)
549 mode = mode or "bt"
550 if mode ~= "bt" then
551 local f = io_open(file, "rb")
552 if f then
553 local prefix = f:read(1)
554 f:close()
555 if prefix then
556 local merr = check_mode(mode, prefix)
557 if merr then return nil, merr end
558 end
559 end
560 end
561 local chunk, msg = _loadfile(file)
562 if not chunk then
563 return chunk, msg
564 end
565 if env ~= nil then
566 setfenv(chunk, env)
567 end
568 return chunk
569 end
570 end -- not luajit
571
572
573 if not is_luajit52 then
574 function rawlen(v)
575 local t = type(v)
576 if t ~= "string" and t ~= "table" then
577 error("bad argument #1 to 'rawlen' (table or string expected)", 2)
578 end
579 return #v
580 end
581 end
582
583
584 if not is_luajit52 then
585 local os_execute = os.execute
586 function os.execute(cmd)
587 local code = os_execute(cmd)
588 -- Lua 5.1 does not report exit by signal.
589 if code == 0 then
590 return true, "exit", code
591 else
592 return nil, "exit", code/256 -- only correct on POSIX!
593 end
594 end
595 end
596
597
598 if not table_ok and not is_luajit52 then
599 table.pack = function(...)
600 return { n = select('#', ...), ... }
601 end
602 end
603
604
605 local main_coroutine = coroutine.create(function() end)
606
607 local _pcall = pcall
608 local coroutine_create = coroutine.create
609 function coroutine.create(func)
610 local success, result = _pcall(coroutine_create, func)
611 if not success then
612 if type(func) ~= "function" then
613 error("bad argument #1 (function expected)", 0)
614 end
615 result = coroutine_create(function(...) return func(...) end)
616 end
617 return result
618 end
619
620 local pcall_mainOf = {}
621
622 if not is_luajit52 then
623 function coroutine.running()
624 local co = coroutine_running()
625 if co then
626 return pcall_mainOf[co] or co, false
627 else
628 return main_coroutine, true
629 end
630 end
631 end
632
633 local coroutine_yield = coroutine.yield
634 function coroutine.yield(...)
635 local co, flag = coroutine_running()
636 if co and not flag then
637 return coroutine_yield(...)
638 else
639 error("attempt to yield from outside a coroutine", 0)
640 end
641 end
642
643 if not is_luajit then
644 local coroutine_resume = coroutine.resume
645 function coroutine.resume(co, ...)
646 if co == main_coroutine then
647 return false, "cannot resume non-suspended coroutine"
648 else
649 return coroutine_resume(co, ...)
650 end
651 end
652
653 local coroutine_status = coroutine.status
654 function coroutine.status(co)
655 local notmain = coroutine_running()
656 if co == main_coroutine then
657 return notmain and "normal" or "running"
658 else
659 return coroutine_status(co)
660 end
661 end
662
663 local function pcall_results(current, call, success, ...)
664 if coroutine_status(call) == "suspended" then
665 return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...)))
666 end
667 if pcall_previous then
668 pcall_previous[call] = nil
669 local main = pcall_mainOf[call]
670 if main == current then current = nil end
671 pcall_callOf[main] = current
672 end
673 pcall_mainOf[call] = nil
674 return success, ...
675 end
676 local function pcall_exec(current, call, ...)
677 local main = pcall_mainOf[current] or current
678 pcall_mainOf[call] = main
679 if pcall_previous then
680 pcall_previous[call] = current
681 pcall_callOf[main] = call
682 end
683 return pcall_results(current, call, coroutine_resume(call, ...))
684 end
685 local coroutine_create52 = coroutine.create
686 local function pcall_coroutine(func)
687 if type(func) ~= "function" then
688 local callable = func
689 func = function (...) return callable(...) end
690 end
691 return coroutine_create52(func)
692 end
693 function pcall(func, ...)
694 local current = coroutine_running()
695 if not current then return _pcall(func, ...) end
696 return pcall_exec(current, pcall_coroutine(func), ...)
697 end
698
699 local _tostring = tostring
700 local function xpcall_catch(current, call, msgh, success, ...)
701 if not success then
702 xpcall_running[current] = call
703 local ok, result = _pcall(msgh, ...)
704 xpcall_running[current] = nil
705 if not ok then
706 return false, "error in error handling (".._tostring(result)..")"
707 end
708 return false, result
709 end
710 return true, ...
711 end
712 local _xpcall = xpcall
713 local _unpack = unpack
714 function xpcall(f, msgh, ...)
715 local current = coroutine_running()
716 if not current then
717 local args, n = { ... }, select('#', ...)
718 return _xpcall(function() return f(_unpack(args, 1, n)) end, msgh)
719 end
720 local call = pcall_coroutine(f)
721 return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...))
722 end
723 end -- not luajit
724
725
726 if not is_luajit then
727 local math_log = math.log
728 math.log = function(x, base)
729 if base ~= nil then
730 return math_log(x)/math_log(base)
731 else
732 return math_log(x)
733 end
734 end
735 end
736
737
738 local package = package
739 if not is_luajit then
740 local io_open = io.open
741 local table_concat = table.concat
742 function package.searchpath(name, path, sep, rep)
743 sep = (sep or "."):gsub("(%p)", "%%%1")
744 rep = (rep or package.config:sub(1, 1)):gsub("(%%)", "%%%1")
745 local pname = name:gsub(sep, rep):gsub("(%%)", "%%%1")
746 local msg = {}
747 for subpath in path:gmatch("[^;]+") do
748 local fpath = subpath:gsub("%?", pname)
749 local f = io_open(fpath, "r")
750 if f then
751 f:close()
752 return fpath
753 end
754 msg[#msg+1] = "\n\tno file '" .. fpath .. "'"
755 end
756 return nil, table_concat(msg)
757 end
758 end
759
760 local p_index = { searchers = package.loaders }
761 local rawset = rawset
762 setmetatable(package, {
763 __index = p_index,
764 __newindex = function(p, k, v)
765 if k == "searchers" then
766 rawset(p, "loaders", v)
767 p_index.searchers = v
768 else
769 rawset(p, k, v)
770 end
771 end
772 })
773
774
775 local string_gsub = string.gsub
776 local function fix_pattern(pattern)
777 return (string_gsub(pattern, "%z", "%%z"))
778 end
779
780 local string_find = string.find
781 function string.find(s, pattern, ...)
782 return string_find(s, fix_pattern(pattern), ...)
783 end
784
785 local string_gmatch = string.gmatch
786 function string.gmatch(s, pattern)
787 return string_gmatch(s, fix_pattern(pattern))
788 end
789
790 function string.gsub(s, pattern, ...)
791 return string_gsub(s, fix_pattern(pattern), ...)
792 end
793
794 local string_match = string.match
795 function string.match(s, pattern, ...)
796 return string_match(s, fix_pattern(pattern), ...)
797 end
798
799 if not is_luajit then
800 local string_rep = string.rep
801 function string.rep(s, n, sep)
802 if sep ~= nil and sep ~= "" and n >= 2 then
803 return s .. string_rep(sep..s, n-1)
804 else
805 return string_rep(s, n)
806 end
807 end
808 end
809
810 if not is_luajit then
811 local string_format = string.format
812 do
813 local addqt = {
814 ["\n"] = "\\\n",
815 ["\\"] = "\\\\",
816 ["\""] = "\\\""
817 }
818
819 local function addquoted(c)
820 return addqt[c] or string_format("\\%03d", c:byte())
821 end
822
823 local _unpack = unpack
824 function string.format(fmt, ...)
825 local args, n = { ... }, select('#', ...)
826 local i = 0
827 local function adjust_fmt(lead, mods, kind)
828 if #lead % 2 == 0 then
829 i = i + 1
830 if kind == "s" then
831 args[i] = tostring(args[i])
832 elseif kind == "q" then
833 args[i] = '"'..string_gsub(args[i], "[%z%c\\\"\n]", addquoted)..'"'
834 return lead.."%"..mods.."s"
835 end
836 end
837 end
838 fmt = string_gsub(fmt, "(%%*)%%([%d%.%-%+%# ]*)(%a)", adjust_fmt)
839 return string_format(fmt, _unpack(args, 1, n))
840 end
841 end
842 end
843
844
845 local io_open = io.open
846 local io_write = io.write
847 local io_output = io.output
848 function io.write(...)
849 local res, msg, errno = io_write(...)
850 if res then
851 return io_output()
852 else
853 return nil, msg, errno
854 end
855 end
856
857 if not is_luajit then
858 local lines_iterator
859 do
860 local function helper( st, var_1, ... )
861 if var_1 == nil then
862 if st.doclose then st.f:close() end
863 if (...) ~= nil then
864 error((...), 2)
865 end
866 end
867 return var_1, ...
868 end
869
870 local _unpack = unpack
871 function lines_iterator(st)
872 return helper(st, st.f:read(_unpack(st, 1, st.n)))
873 end
874 end
875
876 local valid_format = { ["*l"] = true, ["*n"] = true, ["*a"] = true }
877
878 local io_input = io.input
879 function io.lines(fname, ...)
880 local doclose, file, msg
881 if fname ~= nil then
882 doclose, file, msg = true, io_open(fname, "r")
883 if not file then error(msg, 2) end
884 else
885 doclose, file = false, io_input()
886 end
887 local st = { f=file, doclose=doclose, n=select('#', ...), ... }
888 for i = 1, st.n do
889 if type(st[i]) ~= "number" and not valid_format[st[i]] then
890 error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2)
891 end
892 end
893 return lines_iterator, st
894 end
895
896 do
897 local io_stdout = io.stdout
898 local io_type = io.type
899 local file_meta = gmt(io_stdout)
900 if type(file_meta) == "table" and type(file_meta.__index) == "table" then
901 local file_write = file_meta.__index.write
902 file_meta.__index.write = function(self, ...)
903 local res, msg, errno = file_write(self, ...)
904 if res then
905 return self
906 else
907 return nil, msg, errno
908 end
909 end
910
911 file_meta.__index.lines = function(self, ...)
912 if io_type(self) == "closed file" then
913 error("attempt to use a closed file", 2)
914 end
915 local st = { f=self, doclose=false, n=select('#', ...), ... }
916 for i = 1, st.n do
917 if type(st[i]) ~= "number" and not valid_format[st[i]] then
918 error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2)
919 end
920 end
921 return lines_iterator, st
922 end
923 end
924 end
925 end -- not luajit
926
927
928 end -- lua 5.1
929
930 end -- lua < 5.3
931
932 -- vi: set expandtab softtabstop=3 shiftwidth=3 :
0 /*
1 ** $Id: lprefix.h,v 1.2 2014/12/29 16:54:13 roberto Exp $
2 ** Definitions for Lua code that must come before any other header file
3 ** See Copyright Notice in lua.h
4 */
5
6 #ifndef lprefix_h
7 #define lprefix_h
8
9
10 /*
11 ** Allows POSIX/XSI stuff
12 */
13 #if !defined(LUA_USE_C89) /* { */
14
15 #if !defined(_XOPEN_SOURCE)
16 #define _XOPEN_SOURCE 600
17 #elif _XOPEN_SOURCE == 0
18 #undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */
19 #endif
20
21 /*
22 ** Allows manipulation of large files in gcc and some other compilers
23 */
24 #if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS)
25 #define _LARGEFILE_SOURCE 1
26 #define _FILE_OFFSET_BITS 64
27 #endif
28
29 #endif /* } */
30
31
32 /*
33 ** Windows stuff
34 */
35 #if defined(_WIN32) /* { */
36
37 #if !defined(_CRT_SECURE_NO_WARNINGS)
38 #define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */
39 #endif
40
41 #endif /* } */
42
43
44 /* COMPAT53 adaptation */
45 #include "c-api/compat-5.3.h"
46
47 #undef LUAMOD_API
48 #define LUAMOD_API extern
49
50 #ifdef lutf8lib_c
51 # define luaopen_utf8 luaopen_compat53_utf8
52 # include <stdarg.h>
53 /* we don't support the %U format string of lua_pushfstring!
54 * code below adapted from the Lua 5.3 sources:
55 */
56 static const char *compat53_utf8_escape (lua_State* L, ...) {
57 long x = 0;
58 va_list argp;
59 va_start(argp, L);
60 x = (long)va_arg(argp, long);
61 va_end(argp);
62 if (x < 0x80) { /* ASCII */
63 char c = (char)x;
64 lua_pushlstring(L, &c, 1);
65 } else {
66 char buff[8] = { 0 };
67 unsigned int mfb = 0x3f;
68 int n = 1;
69 do {
70 buff[8 - (n++)] = (char)(0x80|(x & 0x3f));
71 x >>= 6;
72 mfb >>= 1;
73 } while (x > mfb);
74 buff[8-n] = (char)((~mfb << 1) | x);
75 lua_pushlstring(L, buff+8-n, n);
76 }
77 return lua_tostring(L, -1);
78 }
79 # define lua_pushfstring(L, fmt, l) \
80 compat53_utf8_escape(L, l)
81 #endif
82
83 #ifdef ltablib_c
84 # define luaopen_table luaopen_compat53_table
85 /* lua_rawgeti in compat53.h is implemented as a macro, so the
86 * function signature doesn't match when you use a function pointer
87 */
88 static int compat53_rawgeti (lua_State *L, int i, lua_Integer n) {
89 return lua_rawgeti(L, i, n);
90 }
91 # undef lua_rawgeti
92 # define lua_rawgeti compat53_rawgeti
93 static void compat53_rawseti (lua_State *L, int i, lua_Integer n) {
94 lua_rawseti(L, i, (int)n);
95 }
96 # undef lua_rawseti
97 # define lua_rawseti compat53_rawseti
98 #endif /* ltablib_c */
99
100 #ifdef lstrlib_c
101 /* move the string library open function out of the way (we only take
102 * the string packing functions)!
103 */
104 # define luaopen_string luaopen_string_XXX
105 /* used in string.format implementation, which we don't use: */
106 # ifndef LUA_INTEGER_FRMLEN
107 # define LUA_INTEGER_FRMLEN ""
108 # define LUA_NUMBER_FRMLEN ""
109 # endif
110 # if LUA_VERSION_NUM < 503
111 /* lstrlib assumes that lua_Integer and lua_Unsigned have the same
112 * size, so we use the unsigned equivalent of ptrdiff_t! */
113 # define lua_Unsigned size_t
114 # endif
115 static int str_pack (lua_State *L);
116 static int str_packsize (lua_State *L);
117 static int str_unpack (lua_State *L);
118 LUAMOD_API int luaopen_compat53_string (lua_State *L) {
119 luaL_Reg const funcs[] = {
120 { "pack", str_pack },
121 { "packsize", str_packsize },
122 { "unpack", str_unpack },
123 { NULL, NULL }
124 };
125 luaL_newlib(L, funcs);
126 return 1;
127 }
128 /* make luaopen_string(_XXX) static, so it (and all other referenced
129 * string functions) won't be included in the resulting dll
130 * (hopefully).
131 */
132 # undef LUAMOD_API
133 # define LUAMOD_API static
134 #endif /* lstrlib.c */
135
136 #endif
137
0 /*
1 ** $Id: lstrlib.c,v 1.221 2014/12/11 14:03:07 roberto Exp $
2 ** Standard library for string operations and pattern-matching
3 ** See Copyright Notice in lua.h
4 */
5
6 #define lstrlib_c
7 #define LUA_LIB
8
9 #include "lprefix.h"
10
11
12 #include <ctype.h>
13 #include <limits.h>
14 #include <stddef.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18
19 #include "lua.h"
20
21 #include "lauxlib.h"
22 #include "lualib.h"
23
24
25 /*
26 ** maximum number of captures that a pattern can do during
27 ** pattern-matching. This limit is arbitrary.
28 */
29 #if !defined(LUA_MAXCAPTURES)
30 #define LUA_MAXCAPTURES 32
31 #endif
32
33
34 /* macro to 'unsign' a character */
35 #define uchar(c) ((unsigned char)(c))
36
37
38 /*
39 ** Some sizes are better limited to fit in 'int', but must also fit in
40 ** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.)
41 */
42 #define MAXSIZE \
43 (sizeof(size_t) < sizeof(int) ? (~(size_t)0) : (size_t)(INT_MAX))
44
45
46
47
48 static int str_len (lua_State *L) {
49 size_t l;
50 luaL_checklstring(L, 1, &l);
51 lua_pushinteger(L, (lua_Integer)l);
52 return 1;
53 }
54
55
56 /* translate a relative string position: negative means back from end */
57 static lua_Integer posrelat (lua_Integer pos, size_t len) {
58 if (pos >= 0) return pos;
59 else if (0u - (size_t)pos > len) return 0;
60 else return (lua_Integer)len + pos + 1;
61 }
62
63
64 static int str_sub (lua_State *L) {
65 size_t l;
66 const char *s = luaL_checklstring(L, 1, &l);
67 lua_Integer start = posrelat(luaL_checkinteger(L, 2), l);
68 lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l);
69 if (start < 1) start = 1;
70 if (end > (lua_Integer)l) end = l;
71 if (start <= end)
72 lua_pushlstring(L, s + start - 1, (size_t)(end - start + 1));
73 else lua_pushliteral(L, "");
74 return 1;
75 }
76
77
78 static int str_reverse (lua_State *L) {
79 size_t l, i;
80 luaL_Buffer b;
81 const char *s = luaL_checklstring(L, 1, &l);
82 char *p = luaL_buffinitsize(L, &b, l);
83 for (i = 0; i < l; i++)
84 p[i] = s[l - i - 1];
85 luaL_pushresultsize(&b, l);
86 return 1;
87 }
88
89
90 static int str_lower (lua_State *L) {
91 size_t l;
92 size_t i;
93 luaL_Buffer b;
94 const char *s = luaL_checklstring(L, 1, &l);
95 char *p = luaL_buffinitsize(L, &b, l);
96 for (i=0; i<l; i++)
97 p[i] = tolower(uchar(s[i]));
98 luaL_pushresultsize(&b, l);
99 return 1;
100 }
101
102
103 static int str_upper (lua_State *L) {
104 size_t l;
105 size_t i;
106 luaL_Buffer b;
107 const char *s = luaL_checklstring(L, 1, &l);
108 char *p = luaL_buffinitsize(L, &b, l);
109 for (i=0; i<l; i++)
110 p[i] = toupper(uchar(s[i]));
111 luaL_pushresultsize(&b, l);
112 return 1;
113 }
114
115
116 static int str_rep (lua_State *L) {
117 size_t l, lsep;
118 const char *s = luaL_checklstring(L, 1, &l);
119 lua_Integer n = luaL_checkinteger(L, 2);
120 const char *sep = luaL_optlstring(L, 3, "", &lsep);
121 if (n <= 0) lua_pushliteral(L, "");
122 else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */
123 return luaL_error(L, "resulting string too large");
124 else {
125 size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep;
126 luaL_Buffer b;
127 char *p = luaL_buffinitsize(L, &b, totallen);
128 while (n-- > 1) { /* first n-1 copies (followed by separator) */
129 memcpy(p, s, l * sizeof(char)); p += l;
130 if (lsep > 0) { /* empty 'memcpy' is not that cheap */
131 memcpy(p, sep, lsep * sizeof(char));
132 p += lsep;
133 }
134 }
135 memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */
136 luaL_pushresultsize(&b, totallen);
137 }
138 return 1;
139 }
140
141
142 static int str_byte (lua_State *L) {
143 size_t l;
144 const char *s = luaL_checklstring(L, 1, &l);
145 lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l);
146 lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l);
147 int n, i;
148 if (posi < 1) posi = 1;
149 if (pose > (lua_Integer)l) pose = l;
150 if (posi > pose) return 0; /* empty interval; return no values */
151 n = (int)(pose - posi + 1);
152 if (posi + n <= pose) /* arithmetic overflow? */
153 return luaL_error(L, "string slice too long");
154 luaL_checkstack(L, n, "string slice too long");
155 for (i=0; i<n; i++)
156 lua_pushinteger(L, uchar(s[posi+i-1]));
157 return n;
158 }
159
160
161 static int str_char (lua_State *L) {
162 int n = lua_gettop(L); /* number of arguments */
163 int i;
164 luaL_Buffer b;
165 char *p = luaL_buffinitsize(L, &b, n);
166 for (i=1; i<=n; i++) {
167 lua_Integer c = luaL_checkinteger(L, i);
168 luaL_argcheck(L, uchar(c) == c, i, "value out of range");
169 p[i - 1] = uchar(c);
170 }
171 luaL_pushresultsize(&b, n);
172 return 1;
173 }
174
175
176 static int writer (lua_State *L, const void *b, size_t size, void *B) {
177 (void)L;
178 luaL_addlstring((luaL_Buffer *) B, (const char *)b, size);
179 return 0;
180 }
181
182
183 static int str_dump (lua_State *L) {
184 luaL_Buffer b;
185 int strip = lua_toboolean(L, 2);
186 luaL_checktype(L, 1, LUA_TFUNCTION);
187 lua_settop(L, 1);
188 luaL_buffinit(L,&b);
189 if (lua_dump(L, writer, &b, strip) != 0)
190 return luaL_error(L, "unable to dump given function");
191 luaL_pushresult(&b);
192 return 1;
193 }
194
195
196
197 /*
198 ** {======================================================
199 ** PATTERN MATCHING
200 ** =======================================================
201 */
202
203
204 #define CAP_UNFINISHED (-1)
205 #define CAP_POSITION (-2)
206
207
208 typedef struct MatchState {
209 int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
210 const char *src_init; /* init of source string */
211 const char *src_end; /* end ('\0') of source string */
212 const char *p_end; /* end ('\0') of pattern */
213 lua_State *L;
214 int level; /* total number of captures (finished or unfinished) */
215 struct {
216 const char *init;
217 ptrdiff_t len;
218 } capture[LUA_MAXCAPTURES];
219 } MatchState;
220
221
222 /* recursive function */
223 static const char *match (MatchState *ms, const char *s, const char *p);
224
225
226 /* maximum recursion depth for 'match' */
227 #if !defined(MAXCCALLS)
228 #define MAXCCALLS 200
229 #endif
230
231
232 #define L_ESC '%'
233 #define SPECIALS "^$*+?.([%-"
234
235
236 static int check_capture (MatchState *ms, int l) {
237 l -= '1';
238 if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
239 return luaL_error(ms->L, "invalid capture index %%%d", l + 1);
240 return l;
241 }
242
243
244 static int capture_to_close (MatchState *ms) {
245 int level = ms->level;
246 for (level--; level>=0; level--)
247 if (ms->capture[level].len == CAP_UNFINISHED) return level;
248 return luaL_error(ms->L, "invalid pattern capture");
249 }
250
251
252 static const char *classend (MatchState *ms, const char *p) {
253 switch (*p++) {
254 case L_ESC: {
255 if (p == ms->p_end)
256 luaL_error(ms->L, "malformed pattern (ends with '%%')");
257 return p+1;
258 }
259 case '[': {
260 if (*p == '^') p++;
261 do { /* look for a ']' */
262 if (p == ms->p_end)
263 luaL_error(ms->L, "malformed pattern (missing ']')");
264 if (*(p++) == L_ESC && p < ms->p_end)
265 p++; /* skip escapes (e.g. '%]') */
266 } while (*p != ']');
267 return p+1;
268 }
269 default: {
270 return p;
271 }
272 }
273 }
274
275
276 static int match_class (int c, int cl) {
277 int res;
278 switch (tolower(cl)) {
279 case 'a' : res = isalpha(c); break;
280 case 'c' : res = iscntrl(c); break;
281 case 'd' : res = isdigit(c); break;
282 case 'g' : res = isgraph(c); break;
283 case 'l' : res = islower(c); break;
284 case 'p' : res = ispunct(c); break;
285 case 's' : res = isspace(c); break;
286 case 'u' : res = isupper(c); break;
287 case 'w' : res = isalnum(c); break;
288 case 'x' : res = isxdigit(c); break;
289 case 'z' : res = (c == 0); break; /* deprecated option */
290 default: return (cl == c);
291 }
292 return (islower(cl) ? res : !res);
293 }
294
295
296 static int matchbracketclass (int c, const char *p, const char *ec) {
297 int sig = 1;
298 if (*(p+1) == '^') {
299 sig = 0;
300 p++; /* skip the '^' */
301 }
302 while (++p < ec) {
303 if (*p == L_ESC) {
304 p++;
305 if (match_class(c, uchar(*p)))
306 return sig;
307 }
308 else if ((*(p+1) == '-') && (p+2 < ec)) {
309 p+=2;
310 if (uchar(*(p-2)) <= c && c <= uchar(*p))
311 return sig;
312 }
313 else if (uchar(*p) == c) return sig;
314 }
315 return !sig;
316 }
317
318
319 static int singlematch (MatchState *ms, const char *s, const char *p,
320 const char *ep) {
321 if (s >= ms->src_end)
322 return 0;
323 else {
324 int c = uchar(*s);
325 switch (*p) {
326 case '.': return 1; /* matches any char */
327 case L_ESC: return match_class(c, uchar(*(p+1)));
328 case '[': return matchbracketclass(c, p, ep-1);
329 default: return (uchar(*p) == c);
330 }
331 }
332 }
333
334
335 static const char *matchbalance (MatchState *ms, const char *s,
336 const char *p) {
337 if (p >= ms->p_end - 1)
338 luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')");
339 if (*s != *p) return NULL;
340 else {
341 int b = *p;
342 int e = *(p+1);
343 int cont = 1;
344 while (++s < ms->src_end) {
345 if (*s == e) {
346 if (--cont == 0) return s+1;
347 }
348 else if (*s == b) cont++;
349 }
350 }
351 return NULL; /* string ends out of balance */
352 }
353
354
355 static const char *max_expand (MatchState *ms, const char *s,
356 const char *p, const char *ep) {
357 ptrdiff_t i = 0; /* counts maximum expand for item */
358 while (singlematch(ms, s + i, p, ep))
359 i++;
360 /* keeps trying to match with the maximum repetitions */
361 while (i>=0) {
362 const char *res = match(ms, (s+i), ep+1);
363 if (res) return res;
364 i--; /* else didn't match; reduce 1 repetition to try again */
365 }
366 return NULL;
367 }
368
369
370 static const char *min_expand (MatchState *ms, const char *s,
371 const char *p, const char *ep) {
372 for (;;) {
373 const char *res = match(ms, s, ep+1);
374 if (res != NULL)
375 return res;
376 else if (singlematch(ms, s, p, ep))
377 s++; /* try with one more repetition */
378 else return NULL;
379 }
380 }
381
382
383 static const char *start_capture (MatchState *ms, const char *s,
384 const char *p, int what) {
385 const char *res;
386 int level = ms->level;
387 if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures");
388 ms->capture[level].init = s;
389 ms->capture[level].len = what;
390 ms->level = level+1;
391 if ((res=match(ms, s, p)) == NULL) /* match failed? */
392 ms->level--; /* undo capture */
393 return res;
394 }
395
396
397 static const char *end_capture (MatchState *ms, const char *s,
398 const char *p) {
399 int l = capture_to_close(ms);
400 const char *res;
401 ms->capture[l].len = s - ms->capture[l].init; /* close capture */
402 if ((res = match(ms, s, p)) == NULL) /* match failed? */
403 ms->capture[l].len = CAP_UNFINISHED; /* undo capture */
404 return res;
405 }
406
407
408 static const char *match_capture (MatchState *ms, const char *s, int l) {
409 size_t len;
410 l = check_capture(ms, l);
411 len = ms->capture[l].len;
412 if ((size_t)(ms->src_end-s) >= len &&
413 memcmp(ms->capture[l].init, s, len) == 0)
414 return s+len;
415 else return NULL;
416 }
417
418
419 static const char *match (MatchState *ms, const char *s, const char *p) {
420 if (ms->matchdepth-- == 0)
421 luaL_error(ms->L, "pattern too complex");
422 init: /* using goto's to optimize tail recursion */
423 if (p != ms->p_end) { /* end of pattern? */
424 switch (*p) {
425 case '(': { /* start capture */
426 if (*(p + 1) == ')') /* position capture? */
427 s = start_capture(ms, s, p + 2, CAP_POSITION);
428 else
429 s = start_capture(ms, s, p + 1, CAP_UNFINISHED);
430 break;
431 }
432 case ')': { /* end capture */
433 s = end_capture(ms, s, p + 1);
434 break;
435 }
436 case '$': {
437 if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */
438 goto dflt; /* no; go to default */
439 s = (s == ms->src_end) ? s : NULL; /* check end of string */
440 break;
441 }
442 case L_ESC: { /* escaped sequences not in the format class[*+?-]? */
443 switch (*(p + 1)) {
444 case 'b': { /* balanced string? */
445 s = matchbalance(ms, s, p + 2);
446 if (s != NULL) {
447 p += 4; goto init; /* return match(ms, s, p + 4); */
448 } /* else fail (s == NULL) */
449 break;
450 }
451 case 'f': { /* frontier? */
452 const char *ep; char previous;
453 p += 2;
454 if (*p != '[')
455 luaL_error(ms->L, "missing '[' after '%%f' in pattern");
456 ep = classend(ms, p); /* points to what is next */
457 previous = (s == ms->src_init) ? '\0' : *(s - 1);
458 if (!matchbracketclass(uchar(previous), p, ep - 1) &&
459 matchbracketclass(uchar(*s), p, ep - 1)) {
460 p = ep; goto init; /* return match(ms, s, ep); */
461 }
462 s = NULL; /* match failed */
463 break;
464 }
465 case '0': case '1': case '2': case '3':
466 case '4': case '5': case '6': case '7':
467 case '8': case '9': { /* capture results (%0-%9)? */
468 s = match_capture(ms, s, uchar(*(p + 1)));
469 if (s != NULL) {
470 p += 2; goto init; /* return match(ms, s, p + 2) */
471 }
472 break;
473 }
474 default: goto dflt;
475 }
476 break;
477 }
478 default: dflt: { /* pattern class plus optional suffix */
479 const char *ep = classend(ms, p); /* points to optional suffix */
480 /* does not match at least once? */
481 if (!singlematch(ms, s, p, ep)) {
482 if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */
483 p = ep + 1; goto init; /* return match(ms, s, ep + 1); */
484 }
485 else /* '+' or no suffix */
486 s = NULL; /* fail */
487 }
488 else { /* matched once */
489 switch (*ep) { /* handle optional suffix */
490 case '?': { /* optional */
491 const char *res;
492 if ((res = match(ms, s + 1, ep + 1)) != NULL)
493 s = res;
494 else {
495 p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */
496 }
497 break;
498 }
499 case '+': /* 1 or more repetitions */
500 s++; /* 1 match already done */
501 /* go through */
502 case '*': /* 0 or more repetitions */
503 s = max_expand(ms, s, p, ep);
504 break;
505 case '-': /* 0 or more repetitions (minimum) */
506 s = min_expand(ms, s, p, ep);
507 break;
508 default: /* no suffix */
509 s++; p = ep; goto init; /* return match(ms, s + 1, ep); */
510 }
511 }
512 break;
513 }
514 }
515 }
516 ms->matchdepth++;
517 return s;
518 }
519
520
521
522 static const char *lmemfind (const char *s1, size_t l1,
523 const char *s2, size_t l2) {
524 if (l2 == 0) return s1; /* empty strings are everywhere */
525 else if (l2 > l1) return NULL; /* avoids a negative 'l1' */
526 else {
527 const char *init; /* to search for a '*s2' inside 's1' */
528 l2--; /* 1st char will be checked by 'memchr' */
529 l1 = l1-l2; /* 's2' cannot be found after that */
530 while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
531 init++; /* 1st char is already checked */
532 if (memcmp(init, s2+1, l2) == 0)
533 return init-1;
534 else { /* correct 'l1' and 's1' to try again */
535 l1 -= init-s1;
536 s1 = init;
537 }
538 }
539 return NULL; /* not found */
540 }
541 }
542
543
544 static void push_onecapture (MatchState *ms, int i, const char *s,
545 const char *e) {
546 if (i >= ms->level) {
547 if (i == 0) /* ms->level == 0, too */
548 lua_pushlstring(ms->L, s, e - s); /* add whole match */
549 else
550 luaL_error(ms->L, "invalid capture index %%%d", i + 1);
551 }
552 else {
553 ptrdiff_t l = ms->capture[i].len;
554 if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
555 if (l == CAP_POSITION)
556 lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
557 else
558 lua_pushlstring(ms->L, ms->capture[i].init, l);
559 }
560 }
561
562
563 static int push_captures (MatchState *ms, const char *s, const char *e) {
564 int i;
565 int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
566 luaL_checkstack(ms->L, nlevels, "too many captures");
567 for (i = 0; i < nlevels; i++)
568 push_onecapture(ms, i, s, e);
569 return nlevels; /* number of strings pushed */
570 }
571
572
573 /* check whether pattern has no special characters */
574 static int nospecials (const char *p, size_t l) {
575 size_t upto = 0;
576 do {
577 if (strpbrk(p + upto, SPECIALS))
578 return 0; /* pattern has a special character */
579 upto += strlen(p + upto) + 1; /* may have more after \0 */
580 } while (upto <= l);
581 return 1; /* no special chars found */
582 }
583
584
585 static int str_find_aux (lua_State *L, int find) {
586 size_t ls, lp;
587 const char *s = luaL_checklstring(L, 1, &ls);
588 const char *p = luaL_checklstring(L, 2, &lp);
589 lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls);
590 if (init < 1) init = 1;
591 else if (init > (lua_Integer)ls + 1) { /* start after string's end? */
592 lua_pushnil(L); /* cannot find anything */
593 return 1;
594 }
595 /* explicit request or no special characters? */
596 if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) {
597 /* do a plain search */
598 const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp);
599 if (s2) {
600 lua_pushinteger(L, s2 - s + 1);
601 lua_pushinteger(L, s2 - s + lp);
602 return 2;
603 }
604 }
605 else {
606 MatchState ms;
607 const char *s1 = s + init - 1;
608 int anchor = (*p == '^');
609 if (anchor) {
610 p++; lp--; /* skip anchor character */
611 }
612 ms.L = L;
613 ms.matchdepth = MAXCCALLS;
614 ms.src_init = s;
615 ms.src_end = s + ls;
616 ms.p_end = p + lp;
617 do {
618 const char *res;
619 ms.level = 0;
620 lua_assert(ms.matchdepth == MAXCCALLS);
621 if ((res=match(&ms, s1, p)) != NULL) {
622 if (find) {
623 lua_pushinteger(L, s1 - s + 1); /* start */
624 lua_pushinteger(L, res - s); /* end */
625 return push_captures(&ms, NULL, 0) + 2;
626 }
627 else
628 return push_captures(&ms, s1, res);
629 }
630 } while (s1++ < ms.src_end && !anchor);
631 }
632 lua_pushnil(L); /* not found */
633 return 1;
634 }
635
636
637 static int str_find (lua_State *L) {
638 return str_find_aux(L, 1);
639 }
640
641
642 static int str_match (lua_State *L) {
643 return str_find_aux(L, 0);
644 }
645
646
647 static int gmatch_aux (lua_State *L) {
648 MatchState ms;
649 size_t ls, lp;
650 const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
651 const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp);
652 const char *src;
653 ms.L = L;
654 ms.matchdepth = MAXCCALLS;
655 ms.src_init = s;
656 ms.src_end = s+ls;
657 ms.p_end = p + lp;
658 for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
659 src <= ms.src_end;
660 src++) {
661 const char *e;
662 ms.level = 0;
663 lua_assert(ms.matchdepth == MAXCCALLS);
664 if ((e = match(&ms, src, p)) != NULL) {
665 lua_Integer newstart = e-s;
666 if (e == src) newstart++; /* empty match? go at least one position */
667 lua_pushinteger(L, newstart);
668 lua_replace(L, lua_upvalueindex(3));
669 return push_captures(&ms, src, e);
670 }
671 }
672 return 0; /* not found */
673 }
674
675
676 static int gmatch (lua_State *L) {
677 luaL_checkstring(L, 1);
678 luaL_checkstring(L, 2);
679 lua_settop(L, 2);
680 lua_pushinteger(L, 0);
681 lua_pushcclosure(L, gmatch_aux, 3);
682 return 1;
683 }
684
685
686 static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
687 const char *e) {
688 size_t l, i;
689 lua_State *L = ms->L;
690 const char *news = lua_tolstring(L, 3, &l);
691 for (i = 0; i < l; i++) {
692 if (news[i] != L_ESC)
693 luaL_addchar(b, news[i]);
694 else {
695 i++; /* skip ESC */
696 if (!isdigit(uchar(news[i]))) {
697 if (news[i] != L_ESC)
698 luaL_error(L, "invalid use of '%c' in replacement string", L_ESC);
699 luaL_addchar(b, news[i]);
700 }
701 else if (news[i] == '0')
702 luaL_addlstring(b, s, e - s);
703 else {
704 push_onecapture(ms, news[i] - '1', s, e);
705 luaL_tolstring(L, -1, NULL); /* if number, convert it to string */
706 lua_remove(L, -2); /* remove original value */
707 luaL_addvalue(b); /* add capture to accumulated result */
708 }
709 }
710 }
711 }
712
713
714 static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
715 const char *e, int tr) {
716 lua_State *L = ms->L;
717 switch (tr) {
718 case LUA_TFUNCTION: {
719 int n;
720 lua_pushvalue(L, 3);
721 n = push_captures(ms, s, e);
722 lua_call(L, n, 1);
723 break;
724 }
725 case LUA_TTABLE: {
726 push_onecapture(ms, 0, s, e);
727 lua_gettable(L, 3);
728 break;
729 }
730 default: { /* LUA_TNUMBER or LUA_TSTRING */
731 add_s(ms, b, s, e);
732 return;
733 }
734 }
735 if (!lua_toboolean(L, -1)) { /* nil or false? */
736 lua_pop(L, 1);
737 lua_pushlstring(L, s, e - s); /* keep original text */
738 }
739 else if (!lua_isstring(L, -1))
740 luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1));
741 luaL_addvalue(b); /* add result to accumulator */
742 }
743
744
745 static int str_gsub (lua_State *L) {
746 size_t srcl, lp;
747 const char *src = luaL_checklstring(L, 1, &srcl);
748 const char *p = luaL_checklstring(L, 2, &lp);
749 int tr = lua_type(L, 3);
750 lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1);
751 int anchor = (*p == '^');
752 lua_Integer n = 0;
753 MatchState ms;
754 luaL_Buffer b;
755 luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
756 tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
757 "string/function/table expected");
758 luaL_buffinit(L, &b);
759 if (anchor) {
760 p++; lp--; /* skip anchor character */
761 }
762 ms.L = L;
763 ms.matchdepth = MAXCCALLS;
764 ms.src_init = src;
765 ms.src_end = src+srcl;
766 ms.p_end = p + lp;
767 while (n < max_s) {
768 const char *e;
769 ms.level = 0;
770 lua_assert(ms.matchdepth == MAXCCALLS);
771 e = match(&ms, src, p);
772 if (e) {
773 n++;
774 add_value(&ms, &b, src, e, tr);
775 }
776 if (e && e>src) /* non empty match? */
777 src = e; /* skip it */
778 else if (src < ms.src_end)
779 luaL_addchar(&b, *src++);
780 else break;
781 if (anchor) break;
782 }
783 luaL_addlstring(&b, src, ms.src_end-src);
784 luaL_pushresult(&b);
785 lua_pushinteger(L, n); /* number of substitutions */
786 return 2;
787 }
788
789 /* }====================================================== */
790
791
792
793 /*
794 ** {======================================================
795 ** STRING FORMAT
796 ** =======================================================
797 */
798
799 /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
800 #define MAX_ITEM 512
801
802 /* valid flags in a format specification */
803 #define FLAGS "-+ #0"
804
805 /*
806 ** maximum size of each format specification (such as "%-099.99d")
807 ** (+2 for length modifiers; +10 accounts for %99.99x plus margin of error)
808 */
809 #define MAX_FORMAT (sizeof(FLAGS) + 2 + 10)
810
811
812 static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
813 size_t l;
814 const char *s = luaL_checklstring(L, arg, &l);
815 luaL_addchar(b, '"');
816 while (l--) {
817 if (*s == '"' || *s == '\\' || *s == '\n') {
818 luaL_addchar(b, '\\');
819 luaL_addchar(b, *s);
820 }
821 else if (*s == '\0' || iscntrl(uchar(*s))) {
822 char buff[10];
823 if (!isdigit(uchar(*(s+1))))
824 sprintf(buff, "\\%d", (int)uchar(*s));
825 else
826 sprintf(buff, "\\%03d", (int)uchar(*s));
827 luaL_addstring(b, buff);
828 }
829 else
830 luaL_addchar(b, *s);
831 s++;
832 }
833 luaL_addchar(b, '"');
834 }
835
836 static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
837 const char *p = strfrmt;
838 while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
839 if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char))
840 luaL_error(L, "invalid format (repeated flags)");
841 if (isdigit(uchar(*p))) p++; /* skip width */
842 if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
843 if (*p == '.') {
844 p++;
845 if (isdigit(uchar(*p))) p++; /* skip precision */
846 if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
847 }
848 if (isdigit(uchar(*p)))
849 luaL_error(L, "invalid format (width or precision too long)");
850 *(form++) = '%';
851 memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char));
852 form += p - strfrmt + 1;
853 *form = '\0';
854 return p;
855 }
856
857
858 /*
859 ** add length modifier into formats
860 */
861 static void addlenmod (char *form, const char *lenmod) {
862 size_t l = strlen(form);
863 size_t lm = strlen(lenmod);
864 char spec = form[l - 1];
865 strcpy(form + l - 1, lenmod);
866 form[l + lm - 1] = spec;
867 form[l + lm] = '\0';
868 }
869
870
871 static int str_format (lua_State *L) {
872 int top = lua_gettop(L);
873 int arg = 1;
874 size_t sfl;
875 const char *strfrmt = luaL_checklstring(L, arg, &sfl);
876 const char *strfrmt_end = strfrmt+sfl;
877 luaL_Buffer b;
878 luaL_buffinit(L, &b);
879 while (strfrmt < strfrmt_end) {
880 if (*strfrmt != L_ESC)
881 luaL_addchar(&b, *strfrmt++);
882 else if (*++strfrmt == L_ESC)
883 luaL_addchar(&b, *strfrmt++); /* %% */
884 else { /* format item */
885 char form[MAX_FORMAT]; /* to store the format ('%...') */
886 char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */
887 int nb = 0; /* number of bytes in added item */
888 if (++arg > top)
889 luaL_argerror(L, arg, "no value");
890 strfrmt = scanformat(L, strfrmt, form);
891 switch (*strfrmt++) {
892 case 'c': {
893 nb = sprintf(buff, form, (int)luaL_checkinteger(L, arg));
894 break;
895 }
896 case 'd': case 'i':
897 case 'o': case 'u': case 'x': case 'X': {
898 lua_Integer n = luaL_checkinteger(L, arg);
899 addlenmod(form, LUA_INTEGER_FRMLEN);
900 nb = sprintf(buff, form, n);
901 break;
902 }
903 #if defined(LUA_USE_AFORMAT)
904 case 'a': case 'A':
905 #endif
906 case 'e': case 'E': case 'f':
907 case 'g': case 'G': {
908 addlenmod(form, LUA_NUMBER_FRMLEN);
909 nb = sprintf(buff, form, luaL_checknumber(L, arg));
910 break;
911 }
912 case 'q': {
913 addquoted(L, &b, arg);
914 break;
915 }
916 case 's': {
917 size_t l;
918 const char *s = luaL_tolstring(L, arg, &l);
919 if (!strchr(form, '.') && l >= 100) {
920 /* no precision and string is too long to be formatted;
921 keep original string */
922 luaL_addvalue(&b);
923 break;
924 }
925 else {
926 nb = sprintf(buff, form, s);
927 lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
928 break;
929 }
930 }
931 default: { /* also treat cases 'pnLlh' */
932 return luaL_error(L, "invalid option '%%%c' to 'format'",
933 *(strfrmt - 1));
934 }
935 }
936 luaL_addsize(&b, nb);
937 }
938 }
939 luaL_pushresult(&b);
940 return 1;
941 }
942
943 /* }====================================================== */
944
945
946 /*
947 ** {======================================================
948 ** PACK/UNPACK
949 ** =======================================================
950 */
951
952
953 /* value used for padding */
954 #if !defined(LUA_PACKPADBYTE)
955 #define LUA_PACKPADBYTE 0x00
956 #endif
957
958 /* maximum size for the binary representation of an integer */
959 #define MAXINTSIZE 16
960
961 /* number of bits in a character */
962 #define NB CHAR_BIT
963
964 /* mask for one character (NB 1's) */
965 #define MC ((1 << NB) - 1)
966
967 /* size of a lua_Integer */
968 #define SZINT ((int)sizeof(lua_Integer))
969
970
971 /* dummy union to get native endianness */
972 static const union {
973 int dummy;
974 char little; /* true iff machine is little endian */
975 } nativeendian = {1};
976
977
978 /* dummy structure to get native alignment requirements */
979 struct cD {
980 char c;
981 union { double d; void *p; lua_Integer i; lua_Number n; } u;
982 };
983
984 #define MAXALIGN (offsetof(struct cD, u))
985
986
987 /*
988 ** Union for serializing floats
989 */
990 typedef union Ftypes {
991 float f;
992 double d;
993 lua_Number n;
994 char buff[5 * sizeof(lua_Number)]; /* enough for any float type */
995 } Ftypes;
996
997
998 /*
999 ** information to pack/unpack stuff
1000 */
1001 typedef struct Header {
1002 lua_State *L;
1003 int islittle;
1004 int maxalign;
1005 } Header;
1006
1007
1008 /*
1009 ** options for pack/unpack
1010 */
1011 typedef enum KOption {
1012 Kint, /* signed integers */
1013 Kuint, /* unsigned integers */
1014 Kfloat, /* floating-point numbers */
1015 Kchar, /* fixed-length strings */
1016 Kstring, /* strings with prefixed length */
1017 Kzstr, /* zero-terminated strings */
1018 Kpadding, /* padding */
1019 Kpaddalign, /* padding for alignment */
1020 Knop /* no-op (configuration or spaces) */
1021 } KOption;
1022
1023
1024 /*
1025 ** Read an integer numeral from string 'fmt' or return 'df' if
1026 ** there is no numeral
1027 */
1028 static int digit (int c) { return '0' <= c && c <= '9'; }
1029
1030 static int getnum (const char **fmt, int df) {
1031 if (!digit(**fmt)) /* no number? */
1032 return df; /* return default value */
1033 else {
1034 int a = 0;
1035 do {
1036 a = a*10 + (*((*fmt)++) - '0');
1037 } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10);
1038 return a;
1039 }
1040 }
1041
1042
1043 /*
1044 ** Read an integer numeral and raises an error if it is larger
1045 ** than the maximum size for integers.
1046 */
1047 static int getnumlimit (Header *h, const char **fmt, int df) {
1048 int sz = getnum(fmt, df);
1049 if (sz > MAXINTSIZE || sz <= 0)
1050 luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
1051 sz, MAXINTSIZE);
1052 return sz;
1053 }
1054
1055
1056 /*
1057 ** Initialize Header
1058 */
1059 static void initheader (lua_State *L, Header *h) {
1060 h->L = L;
1061 h->islittle = nativeendian.little;
1062 h->maxalign = 1;
1063 }
1064
1065
1066 /*
1067 ** Read and classify next option. 'size' is filled with option's size.
1068 */
1069 static KOption getoption (Header *h, const char **fmt, int *size) {
1070 int opt = *((*fmt)++);
1071 *size = 0; /* default */
1072 switch (opt) {
1073 case 'b': *size = sizeof(char); return Kint;
1074 case 'B': *size = sizeof(char); return Kuint;
1075 case 'h': *size = sizeof(short); return Kint;
1076 case 'H': *size = sizeof(short); return Kuint;
1077 case 'l': *size = sizeof(long); return Kint;
1078 case 'L': *size = sizeof(long); return Kuint;
1079 case 'j': *size = sizeof(lua_Integer); return Kint;
1080 case 'J': *size = sizeof(lua_Integer); return Kuint;
1081 case 'T': *size = sizeof(size_t); return Kuint;
1082 case 'f': *size = sizeof(float); return Kfloat;
1083 case 'd': *size = sizeof(double); return Kfloat;
1084 case 'n': *size = sizeof(lua_Number); return Kfloat;
1085 case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint;
1086 case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
1087 case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
1088 case 'c':
1089 *size = getnum(fmt, -1);
1090 if (*size == -1)
1091 luaL_error(h->L, "missing size for format option 'c'");
1092 return Kchar;
1093 case 'z': return Kzstr;
1094 case 'x': *size = 1; return Kpadding;
1095 case 'X': return Kpaddalign;
1096 case ' ': break;
1097 case '<': h->islittle = 1; break;
1098 case '>': h->islittle = 0; break;
1099 case '=': h->islittle = nativeendian.little; break;
1100 case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break;
1101 default: luaL_error(h->L, "invalid format option '%c'", opt);
1102 }
1103 return Knop;
1104 }
1105
1106
1107 /*
1108 ** Read, classify, and fill other details about the next option.
1109 ** 'psize' is filled with option's size, 'notoalign' with its
1110 ** alignment requirements.
1111 ** Local variable 'size' gets the size to be aligned. (Kpadal option
1112 ** always gets its full alignment, other options are limited by
1113 ** the maximum alignment ('maxalign'). Kchar option needs no alignment
1114 ** despite its size.
1115 */
1116 static KOption getdetails (Header *h, size_t totalsize,
1117 const char **fmt, int *psize, int *ntoalign) {
1118 KOption opt = getoption(h, fmt, psize);
1119 int align = *psize; /* usually, alignment follows size */
1120 if (opt == Kpaddalign) { /* 'X' gets alignment from following option */
1121 if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0)
1122 luaL_argerror(h->L, 1, "invalid next option for option 'X'");
1123 }
1124 if (align <= 1 || opt == Kchar) /* need no alignment? */
1125 *ntoalign = 0;
1126 else {
1127 if (align > h->maxalign) /* enforce maximum alignment */
1128 align = h->maxalign;
1129 if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */
1130 luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
1131 *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
1132 }
1133 return opt;
1134 }
1135
1136
1137 /*
1138 ** Pack integer 'n' with 'size' bytes and 'islittle' endianness.
1139 ** The final 'if' handles the case when 'size' is larger than
1140 ** the size of a Lua integer, correcting the extra sign-extension
1141 ** bytes if necessary (by default they would be zeros).
1142 */
1143 static void packint (luaL_Buffer *b, lua_Unsigned n,
1144 int islittle, int size, int neg) {
1145 char *buff = luaL_prepbuffsize(b, size);
1146 int i;
1147 buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */
1148 for (i = 1; i < size; i++) {
1149 n >>= NB;
1150 buff[islittle ? i : size - 1 - i] = (char)(n & MC);
1151 }
1152 if (neg && size > SZINT) { /* negative number need sign extension? */
1153 for (i = SZINT; i < size; i++) /* correct extra bytes */
1154 buff[islittle ? i : size - 1 - i] = (char)MC;
1155 }
1156 luaL_addsize(b, size); /* add result to buffer */
1157 }
1158
1159
1160 /*
1161 ** Copy 'size' bytes from 'src' to 'dest', correcting endianness if
1162 ** given 'islittle' is different from native endianness.
1163 */
1164 static void copywithendian (volatile char *dest, volatile const char *src,
1165 int size, int islittle) {
1166 if (islittle == nativeendian.little) {
1167 while (size-- != 0)
1168 *(dest++) = *(src++);
1169 }
1170 else {
1171 dest += size - 1;
1172 while (size-- != 0)
1173 *(dest--) = *(src++);
1174 }
1175 }
1176
1177
1178 static int str_pack (lua_State *L) {
1179 luaL_Buffer b;
1180 Header h;
1181 const char *fmt = luaL_checkstring(L, 1); /* format string */
1182 int arg = 1; /* current argument to pack */
1183 size_t totalsize = 0; /* accumulate total size of result */
1184 initheader(L, &h);
1185 lua_pushnil(L); /* mark to separate arguments from string buffer */
1186 luaL_buffinit(L, &b);
1187 while (*fmt != '\0') {
1188 int size, ntoalign;
1189 KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
1190 totalsize += ntoalign + size;
1191 while (ntoalign-- > 0)
1192 luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */
1193 arg++;
1194 switch (opt) {
1195 case Kint: { /* signed integers */
1196 lua_Integer n = luaL_checkinteger(L, arg);
1197 if (size < SZINT) { /* need overflow check? */
1198 lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1);
1199 luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow");
1200 }
1201 packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0));
1202 break;
1203 }
1204 case Kuint: { /* unsigned integers */
1205 lua_Integer n = luaL_checkinteger(L, arg);
1206 if (size < SZINT) /* need overflow check? */
1207 luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)),
1208 arg, "unsigned overflow");
1209 packint(&b, (lua_Unsigned)n, h.islittle, size, 0);
1210 break;
1211 }
1212 case Kfloat: { /* floating-point options */
1213 volatile Ftypes u;
1214 char *buff = luaL_prepbuffsize(&b, size);
1215 lua_Number n = luaL_checknumber(L, arg); /* get argument */
1216 if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */
1217 else if (size == sizeof(u.d)) u.d = (double)n;
1218 else u.n = n;
1219 /* move 'u' to final result, correcting endianness if needed */
1220 copywithendian(buff, u.buff, size, h.islittle);
1221 luaL_addsize(&b, size);
1222 break;
1223 }
1224 case Kchar: { /* fixed-size string */
1225 size_t len;
1226 const char *s = luaL_checklstring(L, arg, &len);
1227 luaL_argcheck(L, len == (size_t)size, arg, "wrong length");
1228 luaL_addlstring(&b, s, size);
1229 break;
1230 }
1231 case Kstring: { /* strings with length count */
1232 size_t len;
1233 const char *s = luaL_checklstring(L, arg, &len);
1234 luaL_argcheck(L, size >= (int)sizeof(size_t) ||
1235 len < ((size_t)1 << (size * NB)),
1236 arg, "string length does not fit in given size");
1237 packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */
1238 luaL_addlstring(&b, s, len);
1239 totalsize += len;
1240 break;
1241 }
1242 case Kzstr: { /* zero-terminated string */
1243 size_t len;
1244 const char *s = luaL_checklstring(L, arg, &len);
1245 luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros");
1246 luaL_addlstring(&b, s, len);
1247 luaL_addchar(&b, '\0'); /* add zero at the end */
1248 totalsize += len + 1;
1249 break;
1250 }
1251 case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* go through */
1252 case Kpaddalign: case Knop:
1253 arg--; /* undo increment */
1254 break;
1255 }
1256 }
1257 luaL_pushresult(&b);
1258 return 1;
1259 }
1260
1261
1262 static int str_packsize (lua_State *L) {
1263 Header h;
1264 const char *fmt = luaL_checkstring(L, 1); /* format string */
1265 size_t totalsize = 0; /* accumulate total size of result */
1266 initheader(L, &h);
1267 while (*fmt != '\0') {
1268 int size, ntoalign;
1269 KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
1270 size += ntoalign; /* total space used by option */
1271 luaL_argcheck(L, totalsize <= MAXSIZE - size, 1,
1272 "format result too large");
1273 totalsize += size;
1274 switch (opt) {
1275 case Kstring: /* strings with length count */
1276 case Kzstr: /* zero-terminated string */
1277 luaL_argerror(L, 1, "variable-length format");
1278 break;
1279 default: break;
1280 }
1281 }
1282 lua_pushinteger(L, (lua_Integer)totalsize);
1283 return 1;
1284 }
1285
1286
1287 /*
1288 ** Unpack an integer with 'size' bytes and 'islittle' endianness.
1289 ** If size is smaller than the size of a Lua integer and integer
1290 ** is signed, must do sign extension (propagating the sign to the
1291 ** higher bits); if size is larger than the size of a Lua integer,
1292 ** it must check the unread bytes to see whether they do not cause an
1293 ** overflow.
1294 */
1295 static lua_Integer unpackint (lua_State *L, const char *str,
1296 int islittle, int size, int issigned) {
1297 lua_Unsigned res = 0;
1298 int i;
1299 int limit = (size <= SZINT) ? size : SZINT;
1300 for (i = limit - 1; i >= 0; i--) {
1301 res <<= NB;
1302 res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i];
1303 }
1304 if (size < SZINT) { /* real size smaller than lua_Integer? */
1305 if (issigned) { /* needs sign extension? */
1306 lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1);
1307 res = ((res ^ mask) - mask); /* do sign extension */
1308 }
1309 }
1310 else if (size > SZINT) { /* must check unread bytes */
1311 int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC;
1312 for (i = limit; i < size; i++) {
1313 if ((unsigned char)str[islittle ? i : size - 1 - i] != mask)
1314 luaL_error(L, "%d-byte integer does not fit into Lua Integer", size);
1315 }
1316 }
1317 return (lua_Integer)res;
1318 }
1319
1320
1321 static int str_unpack (lua_State *L) {
1322 Header h;
1323 const char *fmt = luaL_checkstring(L, 1);
1324 size_t ld;
1325 const char *data = luaL_checklstring(L, 2, &ld);
1326 size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1;
1327 int n = 0; /* number of results */
1328 luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
1329 initheader(L, &h);
1330 while (*fmt != '\0') {
1331 int size, ntoalign;
1332 KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign);
1333 if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld)
1334 luaL_argerror(L, 2, "data string too short");
1335 pos += ntoalign; /* skip alignment */
1336 /* stack space for item + next position */
1337 luaL_checkstack(L, 2, "too many results");
1338 n++;
1339 switch (opt) {
1340 case Kint:
1341 case Kuint: {
1342 lua_Integer res = unpackint(L, data + pos, h.islittle, size,
1343 (opt == Kint));
1344 lua_pushinteger(L, res);
1345 break;
1346 }
1347 case Kfloat: {
1348 volatile Ftypes u;
1349 lua_Number num;
1350 copywithendian(u.buff, data + pos, size, h.islittle);
1351 if (size == sizeof(u.f)) num = (lua_Number)u.f;
1352 else if (size == sizeof(u.d)) num = (lua_Number)u.d;
1353 else num = u.n;
1354 lua_pushnumber(L, num);
1355 break;
1356 }
1357 case Kchar: {
1358 lua_pushlstring(L, data + pos, size);
1359 break;
1360 }
1361 case Kstring: {
1362 size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0);
1363 luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short");
1364 lua_pushlstring(L, data + pos + size, len);
1365 pos += len; /* skip string */
1366 break;
1367 }
1368 case Kzstr: {
1369 size_t len = (int)strlen(data + pos);
1370 lua_pushlstring(L, data + pos, len);
1371 pos += len + 1; /* skip string plus final '\0' */
1372 break;
1373 }
1374 case Kpaddalign: case Kpadding: case Knop:
1375 n--; /* undo increment */
1376 break;
1377 }
1378 pos += size;
1379 }
1380 lua_pushinteger(L, pos + 1); /* next position */
1381 return n + 1;
1382 }
1383
1384 /* }====================================================== */
1385
1386
1387 static const luaL_Reg strlib[] = {
1388 {"byte", str_byte},
1389 {"char", str_char},
1390 {"dump", str_dump},
1391 {"find", str_find},
1392 {"format", str_format},
1393 {"gmatch", gmatch},
1394 {"gsub", str_gsub},
1395 {"len", str_len},
1396 {"lower", str_lower},
1397 {"match", str_match},
1398 {"rep", str_rep},
1399 {"reverse", str_reverse},
1400 {"sub", str_sub},
1401 {"upper", str_upper},
1402 {"pack", str_pack},
1403 {"packsize", str_packsize},
1404 {"unpack", str_unpack},
1405 {NULL, NULL}
1406 };
1407
1408
1409 static void createmetatable (lua_State *L) {
1410 lua_createtable(L, 0, 1); /* table to be metatable for strings */
1411 lua_pushliteral(L, ""); /* dummy string */
1412 lua_pushvalue(L, -2); /* copy table */
1413 lua_setmetatable(L, -2); /* set table as metatable for strings */
1414 lua_pop(L, 1); /* pop dummy string */
1415 lua_pushvalue(L, -2); /* get string library */
1416 lua_setfield(L, -2, "__index"); /* metatable.__index = string */
1417 lua_pop(L, 1); /* pop metatable */
1418 }
1419
1420
1421 /*
1422 ** Open string library
1423 */
1424 LUAMOD_API int luaopen_string (lua_State *L) {
1425 luaL_newlib(L, strlib);
1426 createmetatable(L);
1427 return 1;
1428 }
1429
0 /*
1 ** $Id: ltablib.c,v 1.79 2014/11/02 19:19:04 roberto Exp $
2 ** Library for Table Manipulation
3 ** See Copyright Notice in lua.h
4 */
5
6 #define ltablib_c
7 #define LUA_LIB
8
9 #include "lprefix.h"
10
11
12 #include <limits.h>
13 #include <stddef.h>
14
15 #include "lua.h"
16
17 #include "lauxlib.h"
18 #include "lualib.h"
19
20
21
22 /*
23 ** Structure with table-access functions
24 */
25 typedef struct {
26 int (*geti) (lua_State *L, int idx, lua_Integer n);
27 void (*seti) (lua_State *L, int idx, lua_Integer n);
28 } TabA;
29
30
31 /*
32 ** Check that 'arg' has a table and set access functions in 'ta' to raw
33 ** or non-raw according to the presence of corresponding metamethods.
34 */
35 static void checktab (lua_State *L, int arg, TabA *ta) {
36 ta->geti = NULL; ta->seti = NULL;
37 if (lua_getmetatable(L, arg)) {
38 lua_pushliteral(L, "__index"); /* 'index' metamethod */
39 if (lua_rawget(L, -2) != LUA_TNIL)
40 ta->geti = lua_geti;
41 lua_pushliteral(L, "__newindex"); /* 'newindex' metamethod */
42 if (lua_rawget(L, -3) != LUA_TNIL)
43 ta->seti = lua_seti;
44 lua_pop(L, 3); /* pop metatable plus both metamethods */
45 }
46 if (ta->geti == NULL || ta->seti == NULL) {
47 luaL_checktype(L, arg, LUA_TTABLE); /* must be table for raw methods */
48 if (ta->geti == NULL) ta->geti = lua_rawgeti;
49 if (ta->seti == NULL) ta->seti = lua_rawseti;
50 }
51 }
52
53
54 #define aux_getn(L,n,ta) (checktab(L, n, ta), luaL_len(L, n))
55
56
57 #if defined(LUA_COMPAT_MAXN)
58 static int maxn (lua_State *L) {
59 lua_Number max = 0;
60 luaL_checktype(L, 1, LUA_TTABLE);
61 lua_pushnil(L); /* first key */
62 while (lua_next(L, 1)) {
63 lua_pop(L, 1); /* remove value */
64 if (lua_type(L, -1) == LUA_TNUMBER) {
65 lua_Number v = lua_tonumber(L, -1);
66 if (v > max) max = v;
67 }
68 }
69 lua_pushnumber(L, max);
70 return 1;
71 }
72 #endif
73
74
75 static int tinsert (lua_State *L) {
76 TabA ta;
77 lua_Integer e = aux_getn(L, 1, &ta) + 1; /* first empty element */
78 lua_Integer pos; /* where to insert new element */
79 switch (lua_gettop(L)) {
80 case 2: { /* called with only 2 arguments */
81 pos = e; /* insert new element at the end */
82 break;
83 }
84 case 3: {
85 lua_Integer i;
86 pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */
87 luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
88 for (i = e; i > pos; i--) { /* move up elements */
89 (*ta.geti)(L, 1, i - 1);
90 (*ta.seti)(L, 1, i); /* t[i] = t[i - 1] */
91 }
92 break;
93 }
94 default: {
95 return luaL_error(L, "wrong number of arguments to 'insert'");
96 }
97 }
98 (*ta.seti)(L, 1, pos); /* t[pos] = v */
99 return 0;
100 }
101
102
103 static int tremove (lua_State *L) {
104 TabA ta;
105 lua_Integer size = aux_getn(L, 1, &ta);
106 lua_Integer pos = luaL_optinteger(L, 2, size);
107 if (pos != size) /* validate 'pos' if given */
108 luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds");
109 (*ta.geti)(L, 1, pos); /* result = t[pos] */
110 for ( ; pos < size; pos++) {
111 (*ta.geti)(L, 1, pos + 1);
112 (*ta.seti)(L, 1, pos); /* t[pos] = t[pos + 1] */
113 }
114 lua_pushnil(L);
115 (*ta.seti)(L, 1, pos); /* t[pos] = nil */
116 return 1;
117 }
118
119
120 static int tmove (lua_State *L) {
121 TabA ta;
122 lua_Integer f = luaL_checkinteger(L, 2);
123 lua_Integer e = luaL_checkinteger(L, 3);
124 lua_Integer t = luaL_checkinteger(L, 4);
125 int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */
126 /* the following restriction avoids several problems with overflows */
127 luaL_argcheck(L, f > 0, 2, "initial position must be positive");
128 if (e >= f) { /* otherwise, nothing to move */
129 lua_Integer n, i;
130 ta.geti = (luaL_getmetafield(L, 1, "__index") == LUA_TNIL)
131 ? (luaL_checktype(L, 1, LUA_TTABLE), lua_rawgeti)
132 : lua_geti;
133 ta.seti = (luaL_getmetafield(L, tt, "__newindex") == LUA_TNIL)
134 ? (luaL_checktype(L, tt, LUA_TTABLE), lua_rawseti)
135 : lua_seti;
136 n = e - f + 1; /* number of elements to move */
137 if (t > f) {
138 for (i = n - 1; i >= 0; i--) {
139 (*ta.geti)(L, 1, f + i);
140 (*ta.seti)(L, tt, t + i);
141 }
142 }
143 else {
144 for (i = 0; i < n; i++) {
145 (*ta.geti)(L, 1, f + i);
146 (*ta.seti)(L, tt, t + i);
147 }
148 }
149 }
150 lua_pushvalue(L, tt); /* return "to table" */
151 return 1;
152 }
153
154
155 static void addfield (lua_State *L, luaL_Buffer *b, TabA *ta, lua_Integer i) {
156 (*ta->geti)(L, 1, i);
157 if (!lua_isstring(L, -1))
158 luaL_error(L, "invalid value (%s) at index %d in table for 'concat'",
159 luaL_typename(L, -1), i);
160 luaL_addvalue(b);
161 }
162
163
164 static int tconcat (lua_State *L) {
165 TabA ta;
166 luaL_Buffer b;
167 size_t lsep;
168 lua_Integer i, last;
169 const char *sep = luaL_optlstring(L, 2, "", &lsep);
170 checktab(L, 1, &ta);
171 i = luaL_optinteger(L, 3, 1);
172 last = luaL_opt(L, luaL_checkinteger, 4, luaL_len(L, 1));
173 luaL_buffinit(L, &b);
174 for (; i < last; i++) {
175 addfield(L, &b, &ta, i);
176 luaL_addlstring(&b, sep, lsep);
177 }
178 if (i == last) /* add last value (if interval was not empty) */
179 addfield(L, &b, &ta, i);
180 luaL_pushresult(&b);
181 return 1;
182 }
183
184
185 /*
186 ** {======================================================
187 ** Pack/unpack
188 ** =======================================================
189 */
190
191 static int pack (lua_State *L) {
192 int i;
193 int n = lua_gettop(L); /* number of elements to pack */
194 lua_createtable(L, n, 1); /* create result table */
195 lua_insert(L, 1); /* put it at index 1 */
196 for (i = n; i >= 1; i--) /* assign elements */
197 lua_rawseti(L, 1, i);
198 lua_pushinteger(L, n);
199 lua_setfield(L, 1, "n"); /* t.n = number of elements */
200 return 1; /* return table */
201 }
202
203
204 static int unpack (lua_State *L) {
205 TabA ta;
206 lua_Integer i, e;
207 lua_Unsigned n;
208 checktab(L, 1, &ta);
209 i = luaL_optinteger(L, 2, 1);
210 e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
211 if (i > e) return 0; /* empty range */
212 n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */
213 if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n)))
214 return luaL_error(L, "too many results to unpack");
215 do { /* must have at least one element */
216 (*ta.geti)(L, 1, i); /* push arg[i..e] */
217 } while (i++ < e);
218
219 return (int)n;
220 }
221
222 /* }====================================================== */
223
224
225
226 /*
227 ** {======================================================
228 ** Quicksort
229 ** (based on 'Algorithms in MODULA-3', Robert Sedgewick;
230 ** Addison-Wesley, 1993.)
231 ** =======================================================
232 */
233
234
235 static void set2 (lua_State *L, TabA *ta, int i, int j) {
236 (*ta->seti)(L, 1, i);
237 (*ta->seti)(L, 1, j);
238 }
239
240 static int sort_comp (lua_State *L, int a, int b) {
241 if (!lua_isnil(L, 2)) { /* function? */
242 int res;
243 lua_pushvalue(L, 2);
244 lua_pushvalue(L, a-1); /* -1 to compensate function */
245 lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */
246 lua_call(L, 2, 1);
247 res = lua_toboolean(L, -1);
248 lua_pop(L, 1);
249 return res;
250 }
251 else /* a < b? */
252 return lua_compare(L, a, b, LUA_OPLT);
253 }
254
255 static void auxsort (lua_State *L, TabA *ta, int l, int u) {
256 while (l < u) { /* for tail recursion */
257 int i, j;
258 /* sort elements a[l], a[(l+u)/2] and a[u] */
259 (*ta->geti)(L, 1, l);
260 (*ta->geti)(L, 1, u);
261 if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
262 set2(L, ta, l, u); /* swap a[l] - a[u] */
263 else
264 lua_pop(L, 2);
265 if (u-l == 1) break; /* only 2 elements */
266 i = (l+u)/2;
267 (*ta->geti)(L, 1, i);
268 (*ta->geti)(L, 1, l);
269 if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */
270 set2(L, ta, i, l);
271 else {
272 lua_pop(L, 1); /* remove a[l] */
273 (*ta->geti)(L, 1, u);
274 if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */
275 set2(L, ta, i, u);
276 else
277 lua_pop(L, 2);
278 }
279 if (u-l == 2) break; /* only 3 elements */
280 (*ta->geti)(L, 1, i); /* Pivot */
281 lua_pushvalue(L, -1);
282 (*ta->geti)(L, 1, u-1);
283 set2(L, ta, i, u-1);
284 /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
285 i = l; j = u-1;
286 for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
287 /* repeat ++i until a[i] >= P */
288 while ((*ta->geti)(L, 1, ++i), sort_comp(L, -1, -2)) {
289 if (i>=u) luaL_error(L, "invalid order function for sorting");
290 lua_pop(L, 1); /* remove a[i] */
291 }
292 /* repeat --j until a[j] <= P */
293 while ((*ta->geti)(L, 1, --j), sort_comp(L, -3, -1)) {
294 if (j<=l) luaL_error(L, "invalid order function for sorting");
295 lua_pop(L, 1); /* remove a[j] */
296 }
297 if (j<i) {
298 lua_pop(L, 3); /* pop pivot, a[i], a[j] */
299 break;
300 }
301 set2(L, ta, i, j);
302 }
303 (*ta->geti)(L, 1, u-1);
304 (*ta->geti)(L, 1, i);
305 set2(L, ta, u-1, i); /* swap pivot (a[u-1]) with a[i] */
306 /* a[l..i-1] <= a[i] == P <= a[i+1..u] */
307 /* adjust so that smaller half is in [j..i] and larger one in [l..u] */
308 if (i-l < u-i) {
309 j=l; i=i-1; l=i+2;
310 }
311 else {
312 j=i+1; i=u; u=j-2;
313 }
314 auxsort(L, ta, j, i); /* call recursively the smaller one */
315 } /* repeat the routine for the larger one */
316 }
317
318 static int sort (lua_State *L) {
319 TabA ta;
320 int n = (int)aux_getn(L, 1, &ta);
321 luaL_checkstack(L, 50, ""); /* assume array is smaller than 2^50 */
322 if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
323 luaL_checktype(L, 2, LUA_TFUNCTION);
324 lua_settop(L, 2); /* make sure there are two arguments */
325 auxsort(L, &ta, 1, n);
326 return 0;
327 }
328
329 /* }====================================================== */
330
331
332 static const luaL_Reg tab_funcs[] = {
333 {"concat", tconcat},
334 #if defined(LUA_COMPAT_MAXN)
335 {"maxn", maxn},
336 #endif
337 {"insert", tinsert},
338 {"pack", pack},
339 {"unpack", unpack},
340 {"remove", tremove},
341 {"move", tmove},
342 {"sort", sort},
343 {NULL, NULL}
344 };
345
346
347 LUAMOD_API int luaopen_table (lua_State *L) {
348 luaL_newlib(L, tab_funcs);
349 #if defined(LUA_COMPAT_UNPACK)
350 /* _G.unpack = table.unpack */
351 lua_getfield(L, -1, "unpack");
352 lua_setglobal(L, "unpack");
353 #endif
354 return 1;
355 }
356
0 /*
1 ** $Id: lutf8lib.c,v 1.13 2014/11/02 19:19:04 roberto Exp $
2 ** Standard library for UTF-8 manipulation
3 ** See Copyright Notice in lua.h
4 */
5
6 #define lutf8lib_c
7 #define LUA_LIB
8
9 #include "lprefix.h"
10
11
12 #include <assert.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include "lua.h"
17
18 #include "lauxlib.h"
19 #include "lualib.h"
20
21 #define MAXUNICODE 0x10FFFF
22
23 #define iscont(p) ((*(p) & 0xC0) == 0x80)
24
25
26 /* from strlib */
27 /* translate a relative string position: negative means back from end */
28 static lua_Integer u_posrelat (lua_Integer pos, size_t len) {
29 if (pos >= 0) return pos;
30 else if (0u - (size_t)pos > len) return 0;
31 else return (lua_Integer)len + pos + 1;
32 }
33
34
35 /*
36 ** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid.
37 */
38 static const char *utf8_decode (const char *o, int *val) {
39 static unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF};
40 const unsigned char *s = (const unsigned char *)o;
41 unsigned int c = s[0];
42 unsigned int res = 0; /* final result */
43 if (c < 0x80) /* ascii? */
44 res = c;
45 else {
46 int count = 0; /* to count number of continuation bytes */
47 while (c & 0x40) { /* still have continuation bytes? */
48 int cc = s[++count]; /* read next byte */
49 if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
50 return NULL; /* invalid byte sequence */
51 res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
52 c <<= 1; /* to test next bit */
53 }
54 res |= ((c & 0x7F) << (count * 5)); /* add first byte */
55 if (count > 3 || res > MAXUNICODE || res <= limits[count])
56 return NULL; /* invalid byte sequence */
57 s += count; /* skip continuation bytes read */
58 }
59 if (val) *val = res;
60 return (const char *)s + 1; /* +1 to include first byte */
61 }
62
63
64 /*
65 ** utf8len(s [, i [, j]]) --> number of characters that start in the
66 ** range [i,j], or nil + current position if 's' is not well formed in
67 ** that interval
68 */
69 static int utflen (lua_State *L) {
70 int n = 0;
71 size_t len;
72 const char *s = luaL_checklstring(L, 1, &len);
73 lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len);
74 lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len);
75 luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2,
76 "initial position out of string");
77 luaL_argcheck(L, --posj < (lua_Integer)len, 3,
78 "final position out of string");
79 while (posi <= posj) {
80 const char *s1 = utf8_decode(s + posi, NULL);
81 if (s1 == NULL) { /* conversion error? */
82 lua_pushnil(L); /* return nil ... */
83 lua_pushinteger(L, posi + 1); /* ... and current position */
84 return 2;
85 }
86 posi = s1 - s;
87 n++;
88 }
89 lua_pushinteger(L, n);
90 return 1;
91 }
92
93
94 /*
95 ** codepoint(s, [i, [j]]) -> returns codepoints for all characters
96 ** that start in the range [i,j]
97 */
98 static int codepoint (lua_State *L) {
99 size_t len;
100 const char *s = luaL_checklstring(L, 1, &len);
101 lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len);
102 lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len);
103 int n;
104 const char *se;
105 luaL_argcheck(L, posi >= 1, 2, "out of range");
106 luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range");
107 if (posi > pose) return 0; /* empty interval; return no values */
108 n = (int)(pose - posi + 1);
109 if (posi + n <= pose) /* (lua_Integer -> int) overflow? */
110 return luaL_error(L, "string slice too long");
111 luaL_checkstack(L, n, "string slice too long");
112 n = 0;
113 se = s + pose;
114 for (s += posi - 1; s < se;) {
115 int code;
116 s = utf8_decode(s, &code);
117 if (s == NULL)
118 return luaL_error(L, "invalid UTF-8 code");
119 lua_pushinteger(L, code);
120 n++;
121 }
122 return n;
123 }
124
125
126 static void pushutfchar (lua_State *L, int arg) {
127 lua_Integer code = luaL_checkinteger(L, arg);
128 luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range");
129 lua_pushfstring(L, "%U", (long)code);
130 }
131
132
133 /*
134 ** utfchar(n1, n2, ...) -> char(n1)..char(n2)...
135 */
136 static int utfchar (lua_State *L) {
137 int n = lua_gettop(L); /* number of arguments */
138 if (n == 1) /* optimize common case of single char */
139 pushutfchar(L, 1);
140 else {
141 int i;
142 luaL_Buffer b;
143 luaL_buffinit(L, &b);
144 for (i = 1; i <= n; i++) {
145 pushutfchar(L, i);
146 luaL_addvalue(&b);
147 }
148 luaL_pushresult(&b);
149 }
150 return 1;
151 }
152
153
154 /*
155 ** offset(s, n, [i]) -> index where n-th character counting from
156 ** position 'i' starts; 0 means character at 'i'.
157 */
158 static int byteoffset (lua_State *L) {
159 size_t len;
160 const char *s = luaL_checklstring(L, 1, &len);
161 lua_Integer n = luaL_checkinteger(L, 2);
162 lua_Integer posi = (n >= 0) ? 1 : len + 1;
163 posi = u_posrelat(luaL_optinteger(L, 3, posi), len);
164 luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3,
165 "position out of range");
166 if (n == 0) {
167 /* find beginning of current byte sequence */
168 while (posi > 0 && iscont(s + posi)) posi--;
169 }
170 else {
171 if (iscont(s + posi))
172 luaL_error(L, "initial position is a continuation byte");
173 if (n < 0) {
174 while (n < 0 && posi > 0) { /* move back */
175 do { /* find beginning of previous character */
176 posi--;
177 } while (posi > 0 && iscont(s + posi));
178 n++;
179 }
180 }
181 else {
182 n--; /* do not move for 1st character */
183 while (n > 0 && posi < (lua_Integer)len) {
184 do { /* find beginning of next character */
185 posi++;
186 } while (iscont(s + posi)); /* (cannot pass final '\0') */
187 n--;
188 }
189 }
190 }
191 if (n == 0) /* did it find given character? */
192 lua_pushinteger(L, posi + 1);
193 else /* no such character */
194 lua_pushnil(L);
195 return 1;
196 }
197
198
199 static int iter_aux (lua_State *L) {
200 size_t len;
201 const char *s = luaL_checklstring(L, 1, &len);
202 lua_Integer n = lua_tointeger(L, 2) - 1;
203 if (n < 0) /* first iteration? */
204 n = 0; /* start from here */
205 else if (n < (lua_Integer)len) {
206 n++; /* skip current byte */
207 while (iscont(s + n)) n++; /* and its continuations */
208 }
209 if (n >= (lua_Integer)len)
210 return 0; /* no more codepoints */
211 else {
212 int code;
213 const char *next = utf8_decode(s + n, &code);
214 if (next == NULL || iscont(next))
215 return luaL_error(L, "invalid UTF-8 code");
216 lua_pushinteger(L, n + 1);
217 lua_pushinteger(L, code);
218 return 2;
219 }
220 }
221
222
223 static int iter_codes (lua_State *L) {
224 luaL_checkstring(L, 1);
225 lua_pushcfunction(L, iter_aux);
226 lua_pushvalue(L, 1);
227 lua_pushinteger(L, 0);
228 return 3;
229 }
230
231
232 /* pattern to match a single UTF-8 character */
233 #define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*"
234
235
236 static struct luaL_Reg funcs[] = {
237 {"offset", byteoffset},
238 {"codepoint", codepoint},
239 {"char", utfchar},
240 {"len", utflen},
241 {"codes", iter_codes},
242 /* placeholders */
243 {"charpattern", NULL},
244 {NULL, NULL}
245 };
246
247
248 LUAMOD_API int luaopen_utf8 (lua_State *L) {
249 luaL_newlib(L, funcs);
250 lua_pushliteral(L, UTF8PATT);
251 lua_setfield(L, -2, "charpattern");
252 return 1;
253 }
254
0 package = "compat53"
1 version = "0.1-1"
2 source = {
3 url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.1.zip",
4 dir = "lua-compat-5.3-0.1",
5 }
6 description = {
7 summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1",
8 detailed = [[
9 This is a small module that aims to make it easier to write Lua
10 code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1.
11 It does *not* make Lua 5.2 (or even 5.1) entirely compatible
12 with Lua 5.3, but it brings the API closer to that of Lua 5.3.
13 ]],
14 homepage = "https://github.com/keplerproject/lua-compat-5.3",
15 license = "MIT"
16 }
17 dependencies = {
18 "lua >= 5.1, < 5.4",
19 --"struct" -- make Roberto's struct module optional
20 }
21 build = {
22 type = "builtin",
23 modules = {
24 ["compat53"] = "compat53.lua",
25 ["compat53.utf8"] = "lutf8lib.c",
26 ["compat53.table"] = "ltablib.c",
27 ["compat53.string"] = "lstrlib.c",
28 }
29 }
30
0 package = "compat53"
1 version = "scm-0"
2 source = {
3 url = "https://github.com/keplerproject/lua-compat-5.3/archive/master.zip",
4 dir = "lua-compat-5.3-master",
5 }
6 description = {
7 summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1",
8 detailed = [[
9 This is a small module that aims to make it easier to write Lua
10 code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1.
11 It does *not* make Lua 5.2 (or even 5.1) entirely compatible
12 with Lua 5.3, but it brings the API closer to that of Lua 5.3.
13 ]],
14 homepage = "https://github.com/keplerproject/lua-compat-5.3",
15 license = "MIT"
16 }
17 dependencies = {
18 "lua >= 5.1, < 5.4",
19 --"struct" -- make Roberto's struct module optional
20 }
21 build = {
22 type = "builtin",
23 modules = {
24 ["compat53"] = "compat53.lua",
25 ["compat53.utf8"] = "lutf8lib.c",
26 ["compat53.table"] = "ltablib.c",
27 ["compat53.string"] = "lstrlib.c",
28 }
29 }
30
0 #!/usr/bin/env lua
1
2 local F, tproxy, writefile, noprint, ___
3 do
4 local type, unpack = type, table.unpack or unpack
5 local assert, io = assert, io
6 function F(...)
7 local args, n = { ... }, select('#', ...)
8 for i = 1, n do
9 local t = type(args[i])
10 if t ~= "string" and t ~= "number" and t ~= "boolean" then
11 args[i] = t
12 end
13 end
14 return unpack(args, 1, n)
15 end
16 function tproxy(t)
17 return setmetatable({}, {
18 __index = t,
19 __newindex = t,
20 __len = function() return #t end,
21 }), t
22 end
23 function writefile(name, contents, bin)
24 local f = assert(io.open(name, bin and "wb" or "w"))
25 f:write(contents)
26 f:close()
27 end
28 function noprint() end
29 local sep = ("="):rep(70)
30 function ___()
31 print(sep)
32 end
33 end
34
35 local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2")
36 if jit then V = "jit" end
37
38 print( "testing Lua API ..." )
39 package.path = "../?.lua;"..package.path
40 package.cpath = "./?-"..V..".so;./?-"..V..".dll;./?.so;./?.dll"
41 require("compat53")
42
43 ___''
44 do
45 local t = setmetatable( {}, { __index = { 1, false, "three" } } )
46 for i,v in ipairs(t) do
47 print("ipairs", i, v)
48 end
49 end
50
51
52 ___''
53 do
54 local p, t = tproxy{ "a", "b", "c" }
55 print("table.concat", table.concat(p))
56 print("table.concat", table.concat(p, ",", 2))
57 print("table.concat", table.concat(p, ".", 1, 2))
58 print("table.concat", table.concat(t))
59 print("table.concat", table.concat(t, ",", 2))
60 print("table.concat", table.concat(t, ".", 1, 2))
61 end
62
63
64 ___''
65 do
66 local p, t = tproxy{ "a", "b", "c" }
67 table.insert(p, "d")
68 print("table.insert", next(p), t[4])
69 table.insert(p, 1, "z")
70 print("table.insert", next(p), t[1], t[2])
71 table.insert(p, 2, "y")
72 print("table.insert", next(p), t[1], t[2], p[3])
73 t = { "a", "b", "c" }
74 table.insert(t, "d")
75 print("table.insert", t[1], t[2], t[3], t[4])
76 table.insert(t, 1, "z")
77 print("table.insert", t[1], t[2], t[3], t[4], t[5])
78 table.insert(t, 2, "y")
79 print("table.insert", t[1], t[2], t[3], t[4], t[5])
80 end
81
82
83 ___''
84 do
85 local ps, s = tproxy{ "a", "b", "c", "d" }
86 local pd, d = tproxy{ "A", "B", "C", "D" }
87 table.move(ps, 1, 4, 1, pd)
88 print("table.move", next(pd), d[1], d[2], d[3], d[4])
89 pd, d = tproxy{ "A", "B", "C", "D" }
90 table.move(ps, 2, 4, 1, pd)
91 print("table.move", next(pd), d[1], d[2], d[3], d[4])
92 pd, d = tproxy{ "A", "B", "C", "D" }
93 table.move(ps, 2, 3, 4, pd)
94 print("table.move", next(pd), d[1], d[2], d[3], d[4], d[5])
95 table.move(ps, 2, 4, 1)
96 print("table.move", next(ps), s[1], s[2], s[3], s[4])
97 ps, s = tproxy{ "a", "b", "c", "d" }
98 table.move(ps, 2, 3, 4)
99 print("table.move", next(ps), s[1], s[2], s[3], s[4], s[5])
100 s = { "a", "b", "c", "d" }
101 d = { "A", "B", "C", "D" }
102 table.move(s, 1, 4, 1, d)
103 print("table.move", d[1], d[2], d[3], d[4])
104 d = { "A", "B", "C", "D" }
105 table.move(s, 2, 4, 1, d)
106 print("table.move", d[1], d[2], d[3], d[4])
107 d = { "A", "B", "C", "D" }
108 table.move(s, 2, 3, 4, d)
109 print("table.move", d[1], d[2], d[3], d[4], d[5])
110 table.move(s, 2, 4, 1)
111 print("table.move", s[1], s[2], s[3], s[4])
112 s = { "a", "b", "c", "d" }
113 table.move(s, 2, 3, 4)
114 print("table.move", s[1], s[2], s[3], s[4], s[5])
115 end
116
117
118 ___''
119 do
120 local p, t = tproxy{ "a", "b", "c", "d", "e" }
121 print("table.remove", table.remove(p))
122 print("table.remove", next(p), t[1], t[2], t[3], t[4], t[5])
123 print("table.remove", table.remove(p, 1))
124 print("table.remove", next(p), t[1], t[2], t[3], t[4])
125 print("table.remove", table.remove(p, 2))
126 print("table.remove", next(p), t[1], t[2], t[3])
127 print("table.remove", table.remove(p, 3))
128 print("table.remove", next(p), t[1], t[2], t[3])
129 p, t = tproxy{}
130 print("table.remove", table.remove(p))
131 print("table.remove", next(p), next(t))
132 t = { "a", "b", "c", "d", "e" }
133 print("table.remove", table.remove(t))
134 print("table.remove", t[1], t[2], t[3], t[4], t[5])
135 print("table.remove", table.remove(t, 1))
136 print("table.remove", t[1], t[2], t[3], t[4])
137 print("table.remove", table.remove(t, 2))
138 print("table.remove", t[1], t[2], t[3])
139 print("table.remove", table.remove(t, 3))
140 print("table.remove", t[1], t[2], t[3])
141 t = {}
142 print("table.remove", table.remove(t))
143 print("table.remove", next(t))
144 end
145
146 ___''
147 do
148 local p, t = tproxy{ 3, 1, 5, 2, 8, 5, 2, 9, 7, 4 }
149 table.sort(p)
150 print("table.sort", next(p))
151 for i,v in ipairs(t) do
152 print("table.sort", i, v)
153 end
154 table.sort(p)
155 print("table.sort", next(p))
156 for i,v in ipairs(t) do
157 print("table.sort", i, v)
158 end
159 p, t = tproxy{ 9, 8, 7, 6, 5, 4, 3, 2, 1 }
160 table.sort(p)
161 print("table.sort", next(p))
162 for i,v in ipairs(t) do
163 print("table.sort", i, v)
164 end
165 table.sort(p, function(a, b) return a > b end)
166 print("table.sort", next(p))
167 for i,v in ipairs(t) do
168 print("table.sort", i, v)
169 end
170 p, t = tproxy{ 1, 1, 1, 1, 1 }
171 print("table.sort", next(p))
172 for i,v in ipairs(t) do
173 print("table.sort", i, v)
174 end
175 t = { 3, 1, 5, 2, 8, 5, 2, 9, 7, 4 }
176 table.sort(t)
177 for i,v in ipairs(t) do
178 print("table.sort", i, v)
179 end
180 table.sort(t, function(a, b) return a > b end)
181 for i,v in ipairs(t) do
182 print("table.sort", i, v)
183 end
184 end
185
186
187 ___''
188 do
189 local p, t = tproxy{ "a", "b", "c" }
190 print("table.unpack", table.unpack(p))
191 print("table.unpack", table.unpack(p, 2))
192 print("table.unpack", table.unpack(p, 1, 2))
193 print("table.unpack", table.unpack(t))
194 print("table.unpack", table.unpack(t, 2))
195 print("table.unpack", table.unpack(t, 1, 2))
196 end
197
198
199 ___''
200 print("math.maxinteger", math.maxinteger+1 > math.maxinteger)
201 print("math.mininteger", math.mininteger-1 < math.mininteger)
202
203
204 ___''
205 print("math.tointeger", math.tointeger(0))
206 print("math.tointeger", math.tointeger(math.pi))
207 print("math.tointeger", math.tointeger("hello"))
208 print("math.tointeger", math.tointeger(math.maxinteger+2.0))
209 print("math.tointeger", math.tointeger(math.mininteger*2.0))
210
211
212 ___''
213 print("math.type", math.type(0))
214 print("math.type", math.type(math.pi))
215 print("math.type", math.type("hello"))
216
217
218 ___''
219 print("math.ult", math.ult(1, 2), math.ult(2, 1))
220 print("math.ult", math.ult(-1, 2), math.ult(2, -1))
221 print("math.ult", math.ult(-1, -2), math.ult(-2, -1))
222 print("math.ult", pcall(math.ult, "x", 2))
223 print("math.ult", pcall(math.ult, 1, 2.1))
224 ___''
225
226
227 print("testing Lua API for Lua 5.1 ...")
228
229 ___''
230 print("debug.getuservalue()", F(debug.getuservalue(false)))
231 print("debug.setuservalue()", pcall(function()
232 debug.setuservalue(false, {})
233 end))
234 print("debug.setmetatable()", F(debug.setmetatable({}, {})))
235
236
237 ___''
238 do
239 local t = setmetatable({}, {
240 __pairs = function() return pairs({ a = "a" }) end,
241 })
242 for k,v in pairs(t) do
243 print("pairs()", k, v)
244 end
245 end
246
247
248 ___''
249 do
250 local code = "print('hello world')\n"
251 local badcode = "print('blub\n"
252 print("load()", pcall(function() load(true) end))
253 print("load()", F(load(badcode)))
254 print("load()", F(load(code)))
255 print("load()", F(load(code, "[L]")))
256 print("load()", F(load(code, "[L]", "b")))
257 print("load()", F(load(code, "[L]", "t")))
258 print("load()", F(load(code, "[L]", "bt")))
259 local f = load(code, "[L]", "bt", {})
260 print("load()", pcall(f))
261 f = load(code, "[L]", "bt", { print = noprint })
262 print("load()", pcall(f))
263 local bytecode = string.dump(f)
264 print("load()", F(load(bytecode)))
265 print("load()", F(load(bytecode, "[L]")))
266 print("load()", F(load(bytecode, "[L]", "b")))
267 print("load()", F(load(bytecode, "[L]", "t")))
268 print("load()", F(load(bytecode, "[L]", "bt")))
269 f = load(bytecode, "[L]", "bt", {})
270 print("load()", pcall(f))
271 f = load(bytecode, "[L]", "bt", { print = noprint })
272 print("load()", pcall(f))
273 local function make_loader(code)
274 local mid = math.floor( #code/2 )
275 local array = { code:sub(1, mid), code:sub(mid+1) }
276 local i = 0
277 return function()
278 i = i + 1
279 return array[i]
280 end
281 end
282 print("load()", F(load(make_loader(badcode))))
283 print("load()", F(load(make_loader(code))))
284 print("load()", F(load(make_loader(code), "[L]")))
285 print("load()", F(load(make_loader(code), "[L]", "b")))
286 print("load()", F(load(make_loader(code), "[L]", "t")))
287 print("load()", F(load(make_loader(code), "[L]", "bt")))
288 f = load(make_loader(code), "[L]", "bt", {})
289 print("load()", pcall(f))
290 f = load(make_loader(code), "[L]", "bt", { print = noprint })
291 print("load()", pcall(f))
292 print("load()", F(load(make_loader(bytecode))))
293 print("load()", F(load(make_loader(bytecode), "[L]")))
294 print("load()", F(load(make_loader(bytecode), "[L]", "b")))
295 print("load()", F(load(make_loader(bytecode), "[L]", "t")))
296 print("load()", F(load(make_loader(bytecode), "[L]", "bt")))
297 f = load(make_loader(bytecode), "[L]", "bt", {})
298 print("load()", pcall(f))
299 f = load(make_loader(bytecode), "[L]", "bt", { print = noprint })
300 print("load()", pcall(f))
301 writefile("good.lua", code)
302 writefile("bad.lua", badcode)
303 writefile("good.luac", bytecode, true)
304 print("loadfile()", F(loadfile("bad.lua")))
305 print("loadfile()", F(loadfile("good.lua")))
306 print("loadfile()", F(loadfile("good.lua", "b")))
307 print("loadfile()", F(loadfile("good.lua", "t")))
308 print("loadfile()", F(loadfile("good.lua", "bt")))
309 f = loadfile("good.lua", "bt", {})
310 print("loadfile()", pcall(f))
311 f = loadfile("good.lua", "bt", { print = noprint })
312 print("loadfile()", pcall(f))
313 print("loadfile()", F(loadfile("good.luac")))
314 print("loadfile()", F(loadfile("good.luac", "b")))
315 print("loadfile()", F(loadfile("good.luac", "t")))
316 print("loadfile()", F(loadfile("good.luac", "bt")))
317 f = loadfile("good.luac", "bt", {})
318 print("loadfile()", pcall(f))
319 f = loadfile("good.luac", "bt", { print = noprint })
320 print("loadfile()", pcall(f))
321 os.remove("good.lua")
322 os.remove("bad.lua")
323 os.remove("good.luac")
324 end
325
326
327 ___''
328 do
329 local function func(throw)
330 if throw then
331 error("argh")
332 else
333 return 1, 2, 3
334 end
335 end
336 local function tb(err) return "|"..err.."|" end
337 print("xpcall()", xpcall(func, debug.traceback, false))
338 print("xpcall()", xpcall(func, debug.traceback, true))
339 print("xpcall()", xpcall(func, tb, true))
340 local function func2(cb)
341 print("xpcall()", xpcall(cb, debug.traceback, "str"))
342 end
343 local function func3(cb)
344 print("pcall()", pcall(cb, "str"))
345 end
346 local function cb(arg)
347 coroutine.yield(2)
348 return arg
349 end
350 local c = coroutine.wrap(func2)
351 print("xpcall()", c(cb))
352 print("xpcall()", c())
353 local c = coroutine.wrap(func3)
354 print("pcall()", c(cb))
355 print("pcall()", c())
356 end
357
358
359 ___''
360 do
361 local t = setmetatable({ 1 }, { __len = function() return 5 end })
362 print("rawlen()", rawlen(t), rawlen("123"))
363 end
364
365
366 ___''
367 print("os.execute()", os.execute("exit 1"))
368 io.flush()
369 print("os.execute()", os.execute("echo 'hello world!'"))
370 io.flush()
371 print("os.execute()", os.execute("no_such_file"))
372
373
374 ___''
375 do
376 local t = table.pack("a", nil, "b", nil)
377 print("table.(un)pack()", t.n, table.unpack(t, 1, t.n))
378 end
379
380
381 ___''
382 do
383 print("coroutine.running()", F(coroutine.wrap(function()
384 return coroutine.running()
385 end)()))
386 print("coroutine.running()", F(coroutine.running()))
387 local main_co, co1, co2 = coroutine.running()
388 -- coroutine.yield
389 print("coroutine.yield()", pcall(function()
390 coroutine.yield(1, 2, 3)
391 end))
392 print("coroutine.yield()", coroutine.wrap(function()
393 coroutine.yield(1, 2, 3)
394 end)())
395 print("coroutine.resume()", coroutine.resume(main_co, 1, 2, 3))
396 co1 = coroutine.create(function(a, b, c)
397 print("coroutine.resume()", a, b, c)
398 return a, b, c
399 end)
400 print("coroutine.resume()", coroutine.resume(co1, 1, 2, 3))
401 co1 = coroutine.create(function()
402 print("coroutine.status()", "[co1] main is", coroutine.status(main_co))
403 print("coroutine.status()", "[co1] co2 is", coroutine.status(co2))
404 end)
405 co2 = coroutine.create(function()
406 print("coroutine.status()", "[co2] main is", coroutine.status(main_co))
407 print("coroutine.status()", "[co2] co2 is", coroutine.status(co2))
408 coroutine.yield()
409 coroutine.resume(co1)
410 end)
411 print("coroutine.status()", coroutine.status(main_co))
412 print("coroutine.status()", coroutine.status(co2))
413 coroutine.resume(co2)
414 print("coroutine.status()", F(coroutine.status(co2)))
415 coroutine.resume(co2)
416 print("coroutine.status()", F(coroutine.status(co2)))
417 end
418
419
420 ___''
421 print("math.log()", math.log(1000))
422 print("math.log()", math.log(1000, 10))
423
424
425 ___''
426 do
427 local path, prefix = "./?.lua;?/init.lua;../?.lua", "package.searchpath()"
428 print(prefix, package.searchpath("no.such.module", path))
429 print(prefix, package.searchpath("no.such.module", ""))
430 print(prefix, package.searchpath("compat52", path))
431 print(prefix, package.searchpath("no:such:module", path, ":", "|"))
432 end
433
434
435 ___''
436 do
437 local function mod_func() return {} end
438 local function my_searcher(name)
439 if name == "my.module" then
440 print("package.searchers", "my.module found")
441 return mod_func
442 end
443 end
444 local function my_searcher2(name)
445 if name == "my.module" then
446 print("package.searchers", "my.module found 2")
447 return mod_func
448 end
449 end
450 table.insert(package.searchers, my_searcher)
451 require("my.module")
452 package.loaded["my.module"] = nil
453 local new_s = { my_searcher2 }
454 for i,f in ipairs(package.searchers) do
455 new_s[i+1] = f
456 end
457 package.searchers = new_s
458 require("my.module")
459 end
460
461
462 ___''
463 do
464 print("string.find()", ("abc\0abc\0abc"):find("[^a\0]+"))
465 print("string.find()", ("abc\0abc\0abc"):find("%w+\0", 5))
466 for x in ("abc\0def\0ghi"):gmatch("[^\0]+") do
467 print("string.gmatch()", x)
468 end
469 for x in ("abc\0def\0ghi"):gmatch("%w*\0") do
470 print("string.gmatch()", #x)
471 end
472 print("string.gsub()", ("abc\0def\0ghi"):gsub("[\0]", "X"))
473 print("string.gsub()", ("abc\0def\0ghi"):gsub("%w*\0", "X"))
474 print("string.gsub()", ("abc\0def\0ghi"):gsub("%A", "X"))
475 print("string.match()", ("abc\0abc\0abc"):match("([^\0a]+)"))
476 print("string.match()", #("abc\0abc\0abc"):match(".*\0"))
477 print("string.rep()", string.rep("a", 0))
478 print("string.rep()", string.rep("b", 1))
479 print("string.rep()", string.rep("c", 4))
480 print("string.rep()", string.rep("a", 0, "|"))
481 print("string.rep()", string.rep("b", 1, "|"))
482 print("string.rep()", string.rep("c", 4, "|"))
483 local _tostring = tostring
484 function tostring(v)
485 if type(v) == "number" then
486 return "(".._tostring(v)..")"
487 else
488 return _tostring(v)
489 end
490 end
491 print("string.format()", string.format("%q", "\"\\\0000\0010\r0\n0\t0\""))
492 print("string.format()", string.format("%12.3fx%%sxx%.6s", 3.1, {}))
493 print("string.format()", string.format("%-3f %%%s %%s", 3.1, true))
494 print("string.format()", string.format("% 3.2g %%d %%%s", 3.1, nil))
495 print("string.format()", string.format("%+3d %%d %%%%%10.6s", 3, io.stdout))
496 print("string.format()", pcall(function()
497 print("string.format()", string.format("%d %%s", {}))
498 end))
499 tostring = _tostring
500 end
501
502
503 ___''
504 do
505 print("io.write()", io.type(io.write("hello world\n")))
506 local f = assert(io.tmpfile())
507 print("file:write()", io.type(f:write("hello world\n")))
508 f:close()
509 end
510
511
512 ___''
513 do
514 writefile("data.txt", "123 18.8 hello world\ni'm here\n")
515 for a,b in io.lines("test.lua", 2, "*l") do
516 print("io.lines()", a, b)
517 break
518 end
519 for l in io.lines("test.lua") do
520 print("io.lines()", l)
521 break
522 end
523 for n1,n2,rest in io.lines("data.txt", "*n", "*n", "*a") do
524 print("io.lines()", n1, n2, rest)
525 end
526 for l in io.lines("data.txt") do
527 print("io.lines()", l)
528 end
529 print("io.lines()", pcall(function()
530 for l in io.lines("data.txt", "*x") do print(l) end
531 end))
532 print("io.lines()", pcall(function()
533 for l in io.lines("no_such_file.txt") do print(l) end
534 end))
535 local f = assert(io.open("test.lua", "r"))
536 for a,b in f:lines(2, "*l") do
537 print("file:lines()", a, b)
538 break
539 end
540 f:close()
541 f = assert(io.open("data.txt", "r"))
542 for n1,n2,rest in f:lines("*n", "*n", "*a") do
543 print("file:lines()", n1, n2, rest)
544 end
545 f:close()
546 f = assert(io.open("data.txt", "r"))
547 for l in f:lines() do
548 print("file:lines()", l)
549 end
550 f:close()
551 print("file:lines()", pcall(function()
552 for l in f:lines() do print(l) end
553 end))
554 print("file:lines()", pcall(function()
555 local f = assert(io.open("data.txt", "r"))
556 for l in f:lines("*l", "*x") do print(l) end
557 f:close()
558 end))
559 os.remove("data.txt")
560 end
561 ___''
562
563
564 print("testing C API ...")
565 local mod = require("testmod")
566 ___''
567 print(mod.isinteger(1))
568 print(mod.isinteger(0))
569 print(mod.isinteger(1234567))
570 print(mod.isinteger(12.3))
571 print(mod.isinteger(math.huge))
572 print(mod.isinteger(math.sqrt(-1)))
573
574
575 ___''
576 print(mod.rotate(1, 1, 2, 3, 4, 5, 6))
577 print(mod.rotate(-1, 1, 2, 3, 4, 5, 6))
578 print(mod.rotate(4, 1, 2, 3, 4, 5, 6))
579 print(mod.rotate(-4, 1, 2, 3, 4, 5, 6))
580
581
582 ___''
583 print(mod.strtonum("+123"))
584 print(mod.strtonum(" 123 "))
585 print(mod.strtonum("-1.23"))
586 print(mod.strtonum(" 123 abc"))
587 print(mod.strtonum("jkl"))
588
589
590 ___''
591 local a, b, c = mod.requiref()
592 print( type(a), type(b), type(c),
593 a.boolean, b.boolean, c.boolean,
594 type(requiref1), type(requiref2), type(requiref3))
595
596 ___''
597 local proxy, backend = {}, {}
598 setmetatable(proxy, { __index = backend, __newindex = backend })
599 print(rawget(proxy, 1), rawget(backend, 1))
600 print(mod.getseti(proxy, 1))
601 print(rawget(proxy, 1), rawget(backend, 1))
602 print(mod.getseti(proxy, 1))
603 print(rawget(proxy, 1), rawget(backend, 1))
604
605 -- tests for Lua 5.1
606 ___''
607 print(mod.tonumber(12))
608 print(mod.tonumber("12"))
609 print(mod.tonumber("0"))
610 print(mod.tonumber(false))
611 print(mod.tonumber("error"))
612
613 ___''
614 print(mod.tointeger(12))
615 print(mod.tointeger("12"))
616 print(mod.tointeger("0"))
617 print( "aaa" )
618 print(mod.tointeger(math.pi))
619 print( "bbb" )
620 print(mod.tointeger(false))
621 print(mod.tointeger("error"))
622
623 ___''
624 print(mod.len("123"))
625 print(mod.len({ 1, 2, 3}))
626 print(pcall(mod.len, true))
627 local ud, meta = mod.newproxy()
628 meta.__len = function() return 5 end
629 print(mod.len(ud))
630 meta.__len = function() return true end
631 print(pcall(mod.len, ud))
632
633 ___''
634 print(mod.copy(true, "string", {}, 1))
635
636 ___''
637 print(mod.rawxetp())
638 print(mod.rawxetp("I'm back"))
639
640 ___''
641 print(F(mod.globals()), mod.globals() == _G)
642
643 ___''
644 local t = {}
645 print(F(mod.subtable(t)))
646 local x, msg = mod.subtable(t)
647 print(F(x, msg, x == t.xxx))
648
649 ___''
650 print(F(mod.udata()))
651 print(mod.udata("nosuchtype"))
652
653 ___''
654 print(F(mod.uservalue()))
655
656 ___''
657 print(mod.getupvalues())
658
659 ___''
660 print(mod.absindex("hi", true))
661
662 ___''
663 print(mod.arith(2, 1))
664 print(mod.arith(3, 5))
665
666 ___''
667 print(mod.compare(1, 1))
668 print(mod.compare(2, 1))
669 print(mod.compare(1, 2))
670
671 ___''
672 print(mod.tolstring("string"))
673 local t = setmetatable({}, {
674 __tostring = function(v) return "mytable" end
675 })
676 print(mod.tolstring(t))
677 local t = setmetatable({}, {
678 __tostring = function(v) return nil end
679 })
680 print(pcall(mod.tolstring, t))
681
682 ___''
683 print(mod.buffer())
684 ___''
685
0 #include <stdio.h>
1 #include <lua.h>
2 #include <lauxlib.h>
3 #include "compat-5.3.h"
4
5
6 static int test_isinteger (lua_State *L) {
7 lua_pushboolean(L, lua_isinteger(L, 1));
8 return 1;
9 }
10
11
12 static int test_rotate (lua_State *L) {
13 int r = luaL_checkint(L, 1);
14 int n = lua_gettop(L)-1;
15 luaL_argcheck(L, (r < 0 ? -r : r) <= n, 1, "not enough arguments");
16 lua_rotate(L, 2, r);
17 return n;
18 }
19
20
21 static int test_str2num (lua_State *L) {
22 const char *s = luaL_checkstring(L, 1);
23 size_t len = lua_stringtonumber(L, s);
24 if (len == 0)
25 lua_pushnumber(L, 0);
26 lua_pushinteger(L, (lua_Integer)len);
27 return 2;
28 }
29
30
31 static int my_mod (lua_State *L ) {
32 lua_newtable(L);
33 lua_pushboolean(L, 1);
34 lua_setfield(L, -2, "boolean");
35 return 1;
36 }
37
38 static int test_requiref (lua_State *L) {
39 lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
40 lua_newtable(L);
41 lua_pushboolean(L, 0);
42 lua_setfield(L, -2, "boolean");
43 lua_setfield(L, -2, "requiref3");
44 lua_pop(L, 1);
45 luaL_requiref(L, "requiref1", my_mod, 0);
46 luaL_requiref(L, "requiref2", my_mod, 1);
47 luaL_requiref(L, "requiref3", my_mod, 1);
48 return 3;
49 }
50
51 static int test_getseti (lua_State *L) {
52 lua_Integer k = luaL_checkinteger(L, 2);
53 lua_Integer n = 0;
54 if (lua_geti(L, 1, k) == LUA_TNUMBER) {
55 n = lua_tointeger(L, -1);
56 } else {
57 lua_pop(L, 1);
58 lua_pushinteger(L, n);
59 }
60 lua_pushinteger(L, n+1);
61 lua_seti(L, 1, k);
62 return 1;
63 }
64
65
66 /* additional tests for Lua5.1 */
67 #define NUP 3
68
69 static int test_newproxy (lua_State *L) {
70 lua_settop(L, 0);
71 lua_newuserdata(L, 0);
72 lua_newtable(L);
73 lua_pushvalue(L, -1);
74 lua_pushboolean(L, 1);
75 lua_setfield(L, -2, "__gc");
76 lua_setmetatable(L, -3);
77 return 2;
78 }
79
80 static int test_absindex (lua_State *L) {
81 int i = 1;
82 for (i = 1; i <= NUP; ++i)
83 lua_pushvalue(L, lua_absindex(L, lua_upvalueindex(i)));
84 lua_pushvalue(L, lua_absindex(L, LUA_REGISTRYINDEX));
85 lua_pushstring(L, lua_typename(L, lua_type(L, lua_absindex(L, -1))));
86 lua_replace(L, lua_absindex(L, -2));
87 lua_pushvalue(L, lua_absindex(L, -2));
88 lua_pushvalue(L, lua_absindex(L, -4));
89 lua_pushvalue(L, lua_absindex(L, -6));
90 i += 3;
91 lua_pushvalue(L, lua_absindex(L, 1));
92 lua_pushvalue(L, lua_absindex(L, 2));
93 lua_pushvalue(L, lua_absindex(L, 3));
94 i += 3;
95 return i;
96 }
97
98 static int test_arith (lua_State *L) {
99 lua_settop(L, 2);
100 lua_pushvalue(L, 1);
101 lua_pushvalue(L, 2);
102 lua_arith(L, LUA_OPADD);
103 lua_pushvalue(L, 1);
104 lua_pushvalue(L, 2);
105 lua_arith(L, LUA_OPSUB);
106 lua_pushvalue(L, 1);
107 lua_pushvalue(L, 2);
108 lua_arith(L, LUA_OPMUL);
109 lua_pushvalue(L, 1);
110 lua_pushvalue(L, 2);
111 lua_arith(L, LUA_OPDIV);
112 lua_pushvalue(L, 1);
113 lua_pushvalue(L, 2);
114 lua_arith(L, LUA_OPMOD);
115 lua_pushvalue(L, 1);
116 lua_pushvalue(L, 2);
117 lua_arith(L, LUA_OPPOW);
118 lua_pushvalue(L, 1);
119 lua_arith(L, LUA_OPUNM);
120 return lua_gettop(L)-2;
121 }
122
123 static int test_compare (lua_State *L) {
124 luaL_checknumber(L, 1);
125 luaL_checknumber(L, 2);
126 lua_settop(L, 2);
127 lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPEQ));
128 lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPLT));
129 lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPLE));
130 return 3;
131 }
132
133 static int test_globals (lua_State *L) {
134 lua_pushglobaltable(L);
135 return 1;
136 }
137
138 static int test_tonumber (lua_State *L) {
139 int isnum = 0;
140 lua_Number n = lua_tonumberx(L, 1, &isnum);
141 if (!isnum)
142 lua_pushnil(L);
143 else
144 lua_pushnumber(L, n);
145 return 1;
146 }
147
148 static int test_tointeger (lua_State *L) {
149 int isnum = 0;
150 lua_Integer n = lua_tointegerx(L, 1, &isnum);
151 if (!isnum)
152 lua_pushnil(L);
153 else
154 lua_pushinteger(L, n);
155 return 1;
156 }
157
158 static int test_len (lua_State *L) {
159 luaL_checkany(L, 1);
160 lua_len(L, 1);
161 lua_pushinteger(L, luaL_len(L, 1));
162 return 2;
163 }
164
165 static int test_copy (lua_State *L) {
166 int args = lua_gettop(L);
167 if (args >= 2) {
168 int i = 0;
169 for (i = args-1; i > 0; --i)
170 lua_copy(L, args, i);
171 }
172 return args;
173 }
174
175 /* need an address */
176 static char const dummy = 0;
177
178 static int test_rawxetp (lua_State *L) {
179 if (lua_gettop(L) > 0)
180 lua_pushvalue(L, 1);
181 else
182 lua_pushliteral(L, "hello again");
183 lua_rawsetp(L, LUA_REGISTRYINDEX, &dummy);
184 lua_settop(L, 0);
185 lua_rawgetp(L, LUA_REGISTRYINDEX, &dummy);
186 return 1;
187 }
188
189 static int test_udata (lua_State *L) {
190 const char *tname = luaL_optstring(L, 1, "utype1");
191 void *u1 = lua_newuserdata(L, 1);
192 int u1pos = lua_gettop(L);
193 void *u2 = lua_newuserdata(L, 1);
194 int u2pos = lua_gettop(L);
195 luaL_newmetatable(L, "utype1");
196 luaL_newmetatable(L, "utype2");
197 lua_pop(L, 2);
198 luaL_setmetatable(L, "utype2");
199 lua_pushvalue(L, u1pos);
200 luaL_setmetatable(L, "utype1");
201 lua_pop(L, 1);
202 (void)u1;
203 (void)u2;
204 lua_pushlightuserdata(L, luaL_testudata(L, u1pos, tname));
205 lua_pushlightuserdata(L, luaL_testudata(L, u2pos, tname));
206 return 2;
207 }
208
209 static int test_subtable (lua_State *L) {
210 luaL_checktype(L, 1, LUA_TTABLE);
211 lua_settop(L, 1);
212 if (luaL_getsubtable(L, 1, "xxx")) {
213 lua_pushliteral(L, "oldtable");
214 } else {
215 lua_pushliteral(L, "newtable");
216 }
217 return 2;
218 }
219
220 static int test_uservalue (lua_State *L) {
221 void *udata = lua_newuserdata(L, 1);
222 int ui = lua_gettop(L);
223 lua_newtable(L);
224 lua_setuservalue(L, ui);
225 lua_getuservalue(L, ui);
226 (void)udata;
227 return 1;
228 }
229
230 static int test_upvalues (lua_State *L) {
231 int i = 1;
232 for (i = 1; i <= NUP; ++i)
233 lua_pushvalue(L, lua_upvalueindex(i));
234 return NUP;
235 }
236
237 static int test_tolstring (lua_State *L) {
238 size_t len = 0;
239 luaL_tolstring(L, 1, &len);
240 lua_pushinteger(L, (int)len);
241 return 2;
242 }
243
244 static int test_buffer (lua_State *L) {
245 luaL_Buffer b;
246 char *p = luaL_buffinitsize(L, &b, LUAL_BUFFERSIZE+1);
247 p[0] = 'a';
248 p[1] = 'b';
249 luaL_addsize(&b, 2);
250 luaL_addstring(&b, "c");
251 lua_pushliteral(L, "d");
252 luaL_addvalue(&b);
253 luaL_addchar(&b, 'e');
254 luaL_pushresult(&b);
255 return 1;
256 }
257
258
259 static const luaL_Reg funcs[] = {
260 { "isinteger", test_isinteger },
261 { "rotate", test_rotate },
262 { "strtonum", test_str2num },
263 { "requiref", test_requiref },
264 { "getseti", test_getseti },
265 { "newproxy", test_newproxy },
266 { "arith", test_arith },
267 { "compare", test_compare },
268 { "tonumber", test_tonumber },
269 { "tointeger", test_tointeger },
270 { "len", test_len },
271 { "copy", test_copy },
272 { "rawxetp", test_rawxetp },
273 { "subtable", test_subtable },
274 { "udata", test_udata },
275 { "uservalue", test_uservalue },
276 { "globals", test_globals },
277 { "tolstring", test_tolstring },
278 { "buffer", test_buffer },
279 { NULL, NULL }
280 };
281
282 static const luaL_Reg more_funcs[] = {
283 { "getupvalues", test_upvalues },
284 { "absindex", test_absindex },
285 { NULL, NULL }
286 };
287
288
289 int luaopen_testmod (lua_State *L) {
290 int i = 1;
291 luaL_newlib(L, funcs);
292 for (i = 1; i <= NUP; ++i)
293 lua_pushnumber(L, i);
294 luaL_setfuncs(L, more_funcs, NUP);
295 return 1;
296 }
297