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