aboutsummaryrefslogtreecommitdiff
path: root/compat53.lua
diff options
context:
space:
mode:
authorPhilipp Janda <siffiejoe@gmx.net>2015-04-11 17:09:37 +0200
committerPhilipp Janda <siffiejoe@gmx.net>2015-04-11 17:09:37 +0200
commitddeb3f7a1e25667694eaf3c8bf639b66d6809cb4 (patch)
treea02b62ce9ad9135dd8dc6aab13940e96ea87dcfe /compat53.lua
parentba8686d6af119fc7ecf734a2d2b6e319c8d74df5 (diff)
downloadlua-compat-5.3-ddeb3f7a1e25667694eaf3c8bf639b66d6809cb4.tar.gz
lua-compat-5.3-ddeb3f7a1e25667694eaf3c8bf639b66d6809cb4.tar.bz2
lua-compat-5.3-ddeb3f7a1e25667694eaf3c8bf639b66d6809cb4.zip
split compat53 Lua module into separate modules that do/don't modify the global env
Diffstat (limited to 'compat53.lua')
-rw-r--r--compat53.lua933
1 files changed, 0 insertions, 933 deletions
diff --git a/compat53.lua b/compat53.lua
deleted file mode 100644
index 84ef101..0000000
--- a/compat53.lua
+++ /dev/null
@@ -1,933 +0,0 @@
1local lua_version = _VERSION:sub(-3)
2
3if lua_version < "5.3" then
4 -- local aliases for commonly used functions
5 local type, select, error = type, select, error
6
7 -- select the most powerful getmetatable function available
8 local gmt = type(debug) == "table" and debug.getmetatable or
9 getmetatable or function() return false end
10
11 -- type checking functions
12 local checkinteger -- forward declararation
13
14 local function argcheck(cond, i, f, extra)
15 if not cond then
16 error("bad argument #"..i.." to '"..f.."' ("..extra..")", 0)
17 end
18 end
19
20 local function checktype(x, t, i, f)
21 local xt = type(x)
22 if xt ~= t then
23 error("bad argument #"..i.." to '"..f.."' ("..t..
24 " expected, got "..xt..")", 0)
25 end
26 end
27
28
29 -- load utf8 library
30 local utf8_ok, utf8lib = pcall(require, "compat53.utf8")
31 if utf8_ok then
32 utf8 = utf8lib
33 package.loaded["utf8"] = utf8lib
34 if lua_version == "5.1" then
35 utf8lib.charpattern = "[%z\1-\127\194-\244][\128-\191]*"
36 end
37 end
38
39
40 -- load table library
41 local table_ok, tablib = pcall(require, "compat53.table")
42 if table_ok then
43 for k,v in pairs(tablib) do
44 table[k] = v
45 end
46 end
47
48
49 -- load string packing functions
50 local str_ok, strlib = pcall(require, "compat53.string")
51 if str_ok then
52 for k,v in pairs(strlib) do
53 string[k] = v
54 end
55 end
56
57
58 -- try Roberto's struct module for string packing/unpacking if
59 -- compat53.string is unavailable
60 if not str_ok then
61 local struct_ok, struct = pcall(require, "struct")
62 if struct_ok then
63 string.pack = struct.pack
64 string.packsize = struct.size
65 string.unpack = struct.unpack
66 end
67 end
68
69
70 -- update math library
71 do
72 local maxint, minint = 1, 0
73
74 while maxint+1 > maxint and 2*maxint > maxint do
75 maxint = maxint * 2
76 end
77 if 2*maxint <= maxint then
78 maxint = 2*maxint-1
79 minint = -maxint-1
80 else
81 maxint = maxint
82 minint = -maxint
83 end
84 math.maxinteger = maxint
85 math.mininteger = minint
86
87 function math.tointeger(n)
88 if type(n) == "number" and n <= maxint and n >= minint and n % 1 == 0 then
89 return n
90 end
91 return nil
92 end
93
94 function math.type(n)
95 if type(n) == "number" then
96 if n <= maxint and n >= minint and n % 1 == 0 then
97 return "integer"
98 else
99 return "float"
100 end
101 else
102 return nil
103 end
104 end
105
106 function checkinteger(x, i, f)
107 local t = type(x)
108 if t ~= "number" then
109 error("bad argument #"..i.." to '"..f..
110 "' (number expected, got "..t..")", 0)
111 elseif x > maxint or x < minint or x % 1 ~= 0 then
112 error("bad argument #"..i.." to '"..f..
113 "' (number has no integer representation)", 0)
114 else
115 return x
116 end
117 end
118
119 function math.ult(m, n)
120 m = checkinteger(m, "1", "math.ult")
121 n = checkinteger(n, "2", "math.ult")
122 if m >= 0 and n < 0 then
123 return true
124 elseif m < 0 and n >= 0 then
125 return false
126 else
127 return m < n
128 end
129 end
130 end
131
132
133 -- ipairs should respect __index metamethod
134 do
135 local _ipairs = ipairs
136 local function ipairs_iterator(st, var)
137 var = var + 1
138 local val = st[var]
139 if val ~= nil then
140 return var, st[var]
141 end
142 end
143 function ipairs(t)
144 if gmt(t) ~= nil then -- t has metatable
145 return ipairs_iterator, t, 0
146 else
147 return _ipairs(t)
148 end
149 end
150 end
151
152
153 -- update table library (if C module not available)
154 if not table_ok then
155 local table_concat = table.concat
156 function table.concat(list, sep, i, j)
157 local mt = gmt(list)
158 if type(mt) == "table" and type(mt.__len) == "function" then
159 local src = list
160 list, i, j = {}, i or 1, j or mt.__len(src)
161 for k = i, j do
162 list[k] = src[k]
163 end
164 end
165 return table_concat(list, sep, i, j)
166 end
167
168 local table_insert = table.insert
169 function table.insert(list, ...)
170 local mt = gmt(list)
171 local has_mt = type(mt) == "table"
172 local has_len = has_mt and type(mt.__len) == "function"
173 if has_mt and (has_len or mt.__index or mt.__newindex) then
174 local e = (has_len and mt.__len(list) or #list)+1
175 local nargs, pos, value = select('#', ...), ...
176 if nargs == 1 then
177 pos, value = e, pos
178 elseif nargs == 2 then
179 pos = checkinteger(pos, "2", "table.insert")
180 argcheck(1 <= pos and pos <= e, "2", "table.insert",
181 "position out of bounds" )
182 else
183 error("wrong number of arguments to 'insert'", 0)
184 end
185 for i = e-1, pos, -1 do
186 list[i+1] = list[i]
187 end
188 list[pos] = value
189 else
190 return table_insert(list, ...)
191 end
192 end
193
194 function table.move(a1, f, e, t, a2)
195 a2 = a2 or a1
196 f = checkinteger(f, "2", "table.move")
197 argcheck(f > 0, "2", "table.move",
198 "initial position must be positive")
199 e = checkinteger(e, "3", "table.move")
200 t = checkinteger(t, "4", "table.move")
201 if e >= f then
202 local m, n, d = 0, e-f, 1
203 if t > f then m, n, d = n, m, -1 end
204 for i = m, n, d do
205 a2[t+i] = a1[f+i]
206 end
207 end
208 return a2
209 end
210
211 local table_remove = table.remove
212 function table.remove(list, pos)
213 local mt = gmt(list)
214 local has_mt = type(mt) == "table"
215 local has_len = has_mt and type(mt.__len) == "function"
216 if has_mt and (has_len or mt.__index or mt.__newindex) then
217 local e = (has_len and mt.__len(list) or #list)
218 pos = pos ~= nil and checkinteger(pos, "2", "table.remove") or e
219 if pos ~= e then
220 argcheck(1 <= pos and pos <= e+1, "2", "table.remove",
221 "position out of bounds" )
222 end
223 local result = list[pos]
224 while pos < e do
225 list[pos] = list[pos+1]
226 pos = pos + 1
227 end
228 list[pos] = nil
229 return result
230 else
231 return table_remove(list, pos)
232 end
233 end
234
235 do
236 local function pivot(list, cmp, a, b)
237 local m = b - a
238 if m > 2 then
239 local c = a + (m-m%2)/2
240 local x, y, z = list[a], list[b], list[c]
241 if not cmp(x, y) then
242 x, y, a, b = y, x, b, a
243 end
244 if not cmp(y, z) then
245 y, z, b, c = z, y, c, b
246 end
247 if not cmp(x, y) then
248 x, y, a, b = y, x, b, a
249 end
250 return b, y
251 else
252 return b, list[b]
253 end
254 end
255
256 local function lt_cmp(a, b)
257 return a < b
258 end
259
260 local function qsort(list, cmp, b, e)
261 if b < e then
262 local i, j, k, val = b, e, pivot(list, cmp, b, e)
263 while i < j do
264 while i < j and cmp(list[i], val) do
265 i = i + 1
266 end
267 while i < j and not cmp(list[j], val) do
268 j = j - 1
269 end
270 if i < j then
271 list[i], list[j] = list[j], list[i]
272 if i == k then k = j end -- update pivot position
273 i, j = i+1, j-1
274 end
275 end
276 if i ~= k and not cmp(list[i], val) then
277 list[i], list[k] = val, list[i]
278 k = i -- update pivot position
279 end
280 qsort(list, cmp, b, i == k and i-1 or i)
281 return qsort(list, cmp, i+1, e)
282 end
283 end
284
285 local table_sort = table.sort
286 function table.sort(list, cmp)
287 local mt = gmt(list)
288 local has_mt = type(mt) == "table"
289 local has_len = has_mt and type(mt.__len) == "function"
290 if has_len then
291 cmp = cmp or lt_cmp
292 local len = mt.__len(list)
293 return qsort(list, cmp, 1, len)
294 else
295 return table_sort(list, cmp)
296 end
297 end
298 end
299
300 local table_unpack = lua_version == "5.1" and unpack or table.unpack
301 local function unpack_helper(list, i, j, ...)
302 if j < i then
303 return ...
304 else
305 return unpack_helper(list, i, j-1, list[j], ...)
306 end
307 end
308 function table.unpack(list, i, j)
309 local mt = gmt(list)
310 local has_mt = type(mt) == "table"
311 local has_len = has_mt and type(mt.__len) == "function"
312 if has_mt and (has_len or mt.__index) then
313 i, j = i or 1, j or (has_len and mt.__len(list)) or #list
314 return unpack_helper(list, i, j)
315 else
316 return table_unpack(list, i, j)
317 end
318 end
319 end -- update table library
320
321
322
323 -- bring Lua 5.1 (and LuaJIT) up to speed with Lua 5.2
324 if lua_version == "5.1" then
325 -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag)
326 local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ"
327 local is_luajit52 = is_luajit and
328 #setmetatable({}, { __len = function() return 1 end }) == 1
329
330
331 -- table that maps each running coroutine to the coroutine that resumed it
332 -- this is used to build complete tracebacks when "coroutine-friendly" pcall
333 -- is used.
334 local pcall_previous = {}
335 local pcall_callOf = {}
336 local xpcall_running = {}
337 local coroutine_running = coroutine.running
338
339 -- handle debug functions
340 if type(debug) == "table" then
341
342 if not is_luajit52 then
343 local _G, package = _G, package
344 local debug_setfenv = debug.setfenv
345 function debug.setuservalue(obj, value)
346 if type(obj) ~= "userdata" then
347 error("bad argument #1 to 'setuservalue' (userdata expected, got "..
348 type(obj)..")", 2)
349 end
350 if value == nil then value = _G end
351 if type(value) ~= "table" then
352 error("bad argument #2 to 'setuservalue' (table expected, got "..
353 type(value)..")", 2)
354 end
355 return debug_setfenv(obj, value)
356 end
357
358 local debug_getfenv = debug.getfenv
359 function debug.getuservalue(obj)
360 if type(obj) ~= "userdata" then
361 return nil
362 else
363 local v = debug_getfenv(obj)
364 if v == _G or v == package then
365 return nil
366 end
367 return v
368 end
369 end
370
371 local debug_setmetatable = debug.setmetatable
372 function debug.setmetatable(value, tab)
373 debug_setmetatable(value, tab)
374 return value
375 end
376 end -- not luajit with compat52 enabled
377
378 if not is_luajit then
379 local debug_getinfo = debug.getinfo
380 local function calculate_trace_level(co, level)
381 if level ~= nil then
382 for out = 1, 1/0 do
383 local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "")
384 if info == nil then
385 local max = out-1
386 if level <= max then
387 return level
388 end
389 return nil, level-max
390 end
391 end
392 end
393 return 1
394 end
395
396 local stack_pattern = "\nstack traceback:"
397 local stack_replace = ""
398 local debug_traceback = debug.traceback
399 function debug.traceback(co, msg, level)
400 local lvl
401 local nilmsg
402 if type(co) ~= "thread" then
403 co, msg, level = coroutine_running(), co, msg
404 end
405 if msg == nil then
406 msg = ""
407 nilmsg = true
408 elseif type(msg) ~= "string" then
409 return msg
410 end
411 if co == nil then
412 msg = debug_traceback(msg, level or 1)
413 else
414 local xpco = xpcall_running[co]
415 if xpco ~= nil then
416 lvl, level = calculate_trace_level(xpco, level)
417 if lvl then
418 msg = debug_traceback(xpco, msg, lvl)
419 else
420 msg = msg..stack_pattern
421 end
422 lvl, level = calculate_trace_level(co, level)
423 if lvl then
424 local trace = debug_traceback(co, "", lvl)
425 msg = msg..trace:gsub(stack_pattern, stack_replace)
426 end
427 else
428 co = pcall_callOf[co] or co
429 lvl, level = calculate_trace_level(co, level)
430 if lvl then
431 msg = debug_traceback(co, msg, lvl)
432 else
433 msg = msg..stack_pattern
434 end
435 end
436 co = pcall_previous[co]
437 while co ~= nil do
438 lvl, level = calculate_trace_level(co, level)
439 if lvl then
440 local trace = debug_traceback(co, "", lvl)
441 msg = msg..trace:gsub(stack_pattern, stack_replace)
442 end
443 co = pcall_previous[co]
444 end
445 end
446 if nilmsg then
447 msg = msg:gsub("^\n", "")
448 end
449 msg = msg:gsub("\n\t%(tail call%): %?", "\000")
450 msg = msg:gsub("\n\t%.%.%.\n", "\001\n")
451 msg = msg:gsub("\n\t%.%.%.$", "\001")
452 msg = msg:gsub("(%z+)\001(%z+)", function(some, other)
453 return "\n\t(..."..#some+#other.."+ tail call(s)...)"
454 end)
455 msg = msg:gsub("\001(%z+)", function(zeros)
456 return "\n\t(..."..#zeros.."+ tail call(s)...)"
457 end)
458 msg = msg:gsub("(%z+)\001", function(zeros)
459 return "\n\t(..."..#zeros.."+ tail call(s)...)"
460 end)
461 msg = msg:gsub("%z+", function(zeros)
462 return "\n\t(..."..#zeros.." tail call(s)...)"
463 end)
464 msg = msg:gsub("\001", function(zeros)
465 return "\n\t..."
466 end)
467 return msg
468 end
469 end -- is not luajit
470 end -- debug table available
471
472
473 if not is_luajit52 then
474 local _pairs = pairs
475 function pairs(t)
476 local mt = gmt(t)
477 if type(mt) == "table" and type(mt.__pairs) == "function" then
478 return mt.__pairs(t)
479 else
480 return _pairs(t)
481 end
482 end
483 end
484
485
486 if not is_luajit then
487 local function check_mode(mode, prefix)
488 local has = { text = false, binary = false }
489 for i = 1,#mode do
490 local c = mode:sub(i, i)
491 if c == "t" then has.text = true end
492 if c == "b" then has.binary = true end
493 end
494 local t = prefix:sub(1, 1) == "\27" and "binary" or "text"
495 if not has[t] then
496 return "attempt to load a "..t.." chunk (mode is '"..mode.."')"
497 end
498 end
499
500 local setfenv = setfenv
501 local _load, _loadstring = load, loadstring
502 function load(ld, source, mode, env)
503 mode = mode or "bt"
504 local chunk, msg
505 if type( ld ) == "string" then
506 if mode ~= "bt" then
507 local merr = check_mode(mode, ld)
508 if merr then return nil, merr end
509 end
510 chunk, msg = _loadstring(ld, source)
511 else
512 local ld_type = type(ld)
513 if ld_type ~= "function" then
514 error("bad argument #1 to 'load' (function expected, got "..
515 ld_type..")", 2)
516 end
517 if mode ~= "bt" then
518 local checked, merr = false, nil
519 local function checked_ld()
520 if checked then
521 return ld()
522 else
523 checked = true
524 local v = ld()
525 merr = check_mode(mode, v or "")
526 if merr then return nil end
527 return v
528 end
529 end
530 chunk, msg = _load(checked_ld, source)
531 if merr then return nil, merr end
532 else
533 chunk, msg = _load(ld, source)
534 end
535 end
536 if not chunk then
537 return chunk, msg
538 end
539 if env ~= nil then
540 setfenv(chunk, env)
541 end
542 return chunk
543 end
544
545 loadstring = load
546
547 local _loadfile = loadfile
548 local io_open = io.open
549 function loadfile(file, mode, env)
550 mode = mode or "bt"
551 if mode ~= "bt" then
552 local f = io_open(file, "rb")
553 if f then
554 local prefix = f:read(1)
555 f:close()
556 if prefix then
557 local merr = check_mode(mode, prefix)
558 if merr then return nil, merr end
559 end
560 end
561 end
562 local chunk, msg = _loadfile(file)
563 if not chunk then
564 return chunk, msg
565 end
566 if env ~= nil then
567 setfenv(chunk, env)
568 end
569 return chunk
570 end
571 end -- not luajit
572
573
574 if not is_luajit52 then
575 function rawlen(v)
576 local t = type(v)
577 if t ~= "string" and t ~= "table" then
578 error("bad argument #1 to 'rawlen' (table or string expected)", 2)
579 end
580 return #v
581 end
582 end
583
584
585 if not is_luajit52 then
586 local os_execute = os.execute
587 function os.execute(cmd)
588 local code = os_execute(cmd)
589 -- Lua 5.1 does not report exit by signal.
590 if code == 0 then
591 return true, "exit", code
592 else
593 return nil, "exit", code/256 -- only correct on POSIX!
594 end
595 end
596 end
597
598
599 if not table_ok and not is_luajit52 then
600 table.pack = function(...)
601 return { n = select('#', ...), ... }
602 end
603 end
604
605
606 local main_coroutine = coroutine.create(function() end)
607
608 local _pcall = pcall
609 local coroutine_create = coroutine.create
610 function coroutine.create(func)
611 local success, result = _pcall(coroutine_create, func)
612 if not success then
613 if type(func) ~= "function" then
614 error("bad argument #1 (function expected)", 0)
615 end
616 result = coroutine_create(function(...) return func(...) end)
617 end
618 return result
619 end
620
621 local pcall_mainOf = {}
622
623 if not is_luajit52 then
624 function coroutine.running()
625 local co = coroutine_running()
626 if co then
627 return pcall_mainOf[co] or co, false
628 else
629 return main_coroutine, true
630 end
631 end
632 end
633
634 local coroutine_yield = coroutine.yield
635 function coroutine.yield(...)
636 local co, flag = coroutine_running()
637 if co and not flag then
638 return coroutine_yield(...)
639 else
640 error("attempt to yield from outside a coroutine", 0)
641 end
642 end
643
644 if not is_luajit then
645 local coroutine_resume = coroutine.resume
646 function coroutine.resume(co, ...)
647 if co == main_coroutine then
648 return false, "cannot resume non-suspended coroutine"
649 else
650 return coroutine_resume(co, ...)
651 end
652 end
653
654 local coroutine_status = coroutine.status
655 function coroutine.status(co)
656 local notmain = coroutine_running()
657 if co == main_coroutine then
658 return notmain and "normal" or "running"
659 else
660 return coroutine_status(co)
661 end
662 end
663
664 local function pcall_results(current, call, success, ...)
665 if coroutine_status(call) == "suspended" then
666 return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...)))
667 end
668 if pcall_previous then
669 pcall_previous[call] = nil
670 local main = pcall_mainOf[call]
671 if main == current then current = nil end
672 pcall_callOf[main] = current
673 end
674 pcall_mainOf[call] = nil
675 return success, ...
676 end
677 local function pcall_exec(current, call, ...)
678 local main = pcall_mainOf[current] or current
679 pcall_mainOf[call] = main
680 if pcall_previous then
681 pcall_previous[call] = current
682 pcall_callOf[main] = call
683 end
684 return pcall_results(current, call, coroutine_resume(call, ...))
685 end
686 local coroutine_create52 = coroutine.create
687 local function pcall_coroutine(func)
688 if type(func) ~= "function" then
689 local callable = func
690 func = function (...) return callable(...) end
691 end
692 return coroutine_create52(func)
693 end
694 function pcall(func, ...)
695 local current = coroutine_running()
696 if not current then return _pcall(func, ...) end
697 return pcall_exec(current, pcall_coroutine(func), ...)
698 end
699
700 local _tostring = tostring
701 local function xpcall_catch(current, call, msgh, success, ...)
702 if not success then
703 xpcall_running[current] = call
704 local ok, result = _pcall(msgh, ...)
705 xpcall_running[current] = nil
706 if not ok then
707 return false, "error in error handling (".._tostring(result)..")"
708 end
709 return false, result
710 end
711 return true, ...
712 end
713 local _xpcall = xpcall
714 local _unpack = unpack
715 function xpcall(f, msgh, ...)
716 local current = coroutine_running()
717 if not current then
718 local args, n = { ... }, select('#', ...)
719 return _xpcall(function() return f(_unpack(args, 1, n)) end, msgh)
720 end
721 local call = pcall_coroutine(f)
722 return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...))
723 end
724 end -- not luajit
725
726
727 if not is_luajit then
728 local math_log = math.log
729 math.log = function(x, base)
730 if base ~= nil then
731 return math_log(x)/math_log(base)
732 else
733 return math_log(x)
734 end
735 end
736 end
737
738
739 local package = package
740 if not is_luajit then
741 local io_open = io.open
742 local table_concat = table.concat
743 function package.searchpath(name, path, sep, rep)
744 sep = (sep or "."):gsub("(%p)", "%%%1")
745 rep = (rep or package.config:sub(1, 1)):gsub("(%%)", "%%%1")
746 local pname = name:gsub(sep, rep):gsub("(%%)", "%%%1")
747 local msg = {}
748 for subpath in path:gmatch("[^;]+") do
749 local fpath = subpath:gsub("%?", pname)
750 local f = io_open(fpath, "r")
751 if f then
752 f:close()
753 return fpath
754 end
755 msg[#msg+1] = "\n\tno file '" .. fpath .. "'"
756 end
757 return nil, table_concat(msg)
758 end
759 end
760
761 local p_index = { searchers = package.loaders }
762 local rawset = rawset
763 setmetatable(package, {
764 __index = p_index,
765 __newindex = function(p, k, v)
766 if k == "searchers" then
767 rawset(p, "loaders", v)
768 p_index.searchers = v
769 else
770 rawset(p, k, v)
771 end
772 end
773 })
774
775
776 local string_gsub = string.gsub
777 local function fix_pattern(pattern)
778 return (string_gsub(pattern, "%z", "%%z"))
779 end
780
781 local string_find = string.find
782 function string.find(s, pattern, ...)
783 return string_find(s, fix_pattern(pattern), ...)
784 end
785
786 local string_gmatch = string.gmatch
787 function string.gmatch(s, pattern)
788 return string_gmatch(s, fix_pattern(pattern))
789 end
790
791 function string.gsub(s, pattern, ...)
792 return string_gsub(s, fix_pattern(pattern), ...)
793 end
794
795 local string_match = string.match
796 function string.match(s, pattern, ...)
797 return string_match(s, fix_pattern(pattern), ...)
798 end
799
800 if not is_luajit then
801 local string_rep = string.rep
802 function string.rep(s, n, sep)
803 if sep ~= nil and sep ~= "" and n >= 2 then
804 return s .. string_rep(sep..s, n-1)
805 else
806 return string_rep(s, n)
807 end
808 end
809 end
810
811 if not is_luajit then
812 local string_format = string.format
813 do
814 local addqt = {
815 ["\n"] = "\\\n",
816 ["\\"] = "\\\\",
817 ["\""] = "\\\""
818 }
819
820 local function addquoted(c)
821 return addqt[c] or string_format("\\%03d", c:byte())
822 end
823
824 local _unpack = unpack
825 function string.format(fmt, ...)
826 local args, n = { ... }, select('#', ...)
827 local i = 0
828 local function adjust_fmt(lead, mods, kind)
829 if #lead % 2 == 0 then
830 i = i + 1
831 if kind == "s" then
832 args[i] = tostring(args[i])
833 elseif kind == "q" then
834 args[i] = '"'..string_gsub(args[i], "[%z%c\\\"\n]", addquoted)..'"'
835 return lead.."%"..mods.."s"
836 end
837 end
838 end
839 fmt = string_gsub(fmt, "(%%*)%%([%d%.%-%+%# ]*)(%a)", adjust_fmt)
840 return string_format(fmt, _unpack(args, 1, n))
841 end
842 end
843 end
844
845
846 local io_open = io.open
847 local io_write = io.write
848 local io_output = io.output
849 function io.write(...)
850 local res, msg, errno = io_write(...)
851 if res then
852 return io_output()
853 else
854 return nil, msg, errno
855 end
856 end
857
858 if not is_luajit then
859 local lines_iterator
860 do
861 local function helper( st, var_1, ... )
862 if var_1 == nil then
863 if st.doclose then st.f:close() end
864 if (...) ~= nil then
865 error((...), 2)
866 end
867 end
868 return var_1, ...
869 end
870
871 local _unpack = unpack
872 function lines_iterator(st)
873 return helper(st, st.f:read(_unpack(st, 1, st.n)))
874 end
875 end
876
877 local valid_format = { ["*l"] = true, ["*n"] = true, ["*a"] = true }
878
879 local io_input = io.input
880 function io.lines(fname, ...)
881 local doclose, file, msg
882 if fname ~= nil then
883 doclose, file, msg = true, io_open(fname, "r")
884 if not file then error(msg, 2) end
885 else
886 doclose, file = false, io_input()
887 end
888 local st = { f=file, doclose=doclose, n=select('#', ...), ... }
889 for i = 1, st.n do
890 if type(st[i]) ~= "number" and not valid_format[st[i]] then
891 error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2)
892 end
893 end
894 return lines_iterator, st
895 end
896
897 do
898 local io_stdout = io.stdout
899 local io_type = io.type
900 local file_meta = gmt(io_stdout)
901 if type(file_meta) == "table" and type(file_meta.__index) == "table" then
902 local file_write = file_meta.__index.write
903 file_meta.__index.write = function(self, ...)
904 local res, msg, errno = file_write(self, ...)
905 if res then
906 return self
907 else
908 return nil, msg, errno
909 end
910 end
911
912 file_meta.__index.lines = function(self, ...)
913 if io_type(self) == "closed file" then
914 error("attempt to use a closed file", 2)
915 end
916 local st = { f=self, doclose=false, n=select('#', ...), ... }
917 for i = 1, st.n do
918 if type(st[i]) ~= "number" and not valid_format[st[i]] then
919 error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2)
920 end
921 end
922 return lines_iterator, st
923 end
924 end
925 end
926 end -- not luajit
927
928
929 end -- lua 5.1
930
931end -- lua < 5.3
932
933-- vi: set expandtab softtabstop=3 shiftwidth=3 :