Add f:lines()

This commit is contained in:
Alessandro Proto 2023-04-07 17:18:52 +02:00
parent 1d28f07a7e
commit 4b21daa095
2 changed files with 104 additions and 41 deletions

View file

@ -18,4 +18,6 @@ namespace Capy64.Runtime;
public class Constants public class Constants
{ {
public const int MULTRET = -1; public const int MULTRET = -1;
public const int MINSTACK = 20;
public const int MAXLENNUM = 200;
} }

View file

@ -16,8 +16,11 @@
using Capy64.API; using Capy64.API;
using KeraLua; using KeraLua;
using System; using System;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using static Capy64.Runtime.Constants;
namespace Capy64.Runtime.Objects; namespace Capy64.Runtime.Objects;
@ -134,7 +137,7 @@ public class FileHandle : IComponent
private static bool ReadNumber(Lua L, Stream stream) private static bool ReadNumber(Lua L, Stream stream)
{ {
var str = ReadNumberHelper.ReadNumber(stream); var str = ReadHelper.ReadNumber(stream);
if (L.StringToNumber(str)) if (L.StringToNumber(str))
{ {
return true; return true;
@ -197,53 +200,66 @@ public class FileHandle : IComponent
return 2; return 2;
} }
var nargs = L.GetTop() - 1; return G_Read(L, stream, 1);
if (nargs == 0)
{
L.PushString("l");
nargs = 1;
} }
for (int i = 2; i <= nargs + 1; i++) private static int G_Read(Lua L, Stream f, int first)
{ {
var nargs = L.GetTop() - 1;
int n;
bool success; bool success;
if (L.Type(i) == LuaType.Number)
if (nargs == 0) // no arguments?
{ {
success = ReadChars(L, stream, (int)L.ToNumber(2)); success = ReadLine(L, f, true);
n = first + 1; // to return 1 result
} }
else else
{ {
var p = L.CheckString(i); // ensure stack space for all results and for auxlib's buffer
L.CheckStack(nargs + MINSTACK, "too many arguments");
success = true;
for (n = first; (nargs-- > 0) && success; n++)
{
if (L.Type(n) == LuaType.Number)
{
var l = (int)L.CheckInteger(n);
success = (l == 0) ? f.Position == f.Length : ReadChars(L, f, l);
}
else
{
var p = L.CheckString(n);
var mode = CheckMode(p); var mode = CheckMode(p);
switch (mode) switch (mode)
{ {
case 'n': case 'n': // number
success = ReadNumber(L, stream); success = ReadNumber(L, f);
break; break;
case 'l': case 'l': // line
success = ReadLine(L, stream, true); success = ReadLine(L, f, true);
break; break;
case 'L': case 'L': // line with end-of-line
success = ReadLine(L, stream, false); success = ReadLine(L, f, false);
break; break;
case 'a': case 'a': // file
ReadAll(L, stream); ReadAll(L, f); // read entire file
success = true; success = true; // always success
break; break;
default: default:
return L.ArgumentError(i, "invalid format"); return L.ArgumentError(n, "invalid format");
} }
} }
}
}
if (!success) if (!success)
{ {
L.Pop(1); L.Pop(1);
L.PushNil(); L.PushNil();
} }
}
return nargs; return n - first;
} }
private static int L_Write(IntPtr state) private static int L_Write(IntPtr state)
@ -278,7 +294,6 @@ public class FileHandle : IComponent
private static int L_Lines(IntPtr state) private static int L_Lines(IntPtr state)
{ {
return 0;
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
var maxargn = 250; var maxargn = 250;
@ -289,11 +304,51 @@ public class FileHandle : IComponent
L.PushInteger(n); L.PushInteger(n);
L.PushBoolean(false); L.PushBoolean(false);
L.Rotate(2, 3); L.Rotate(2, 3);
L.PushCClosure(null, 3 + n); // todo L.PushCClosure(IO_ReadLine, 3 + n);
return 1; return 1;
} }
private static int IO_ReadLine(IntPtr state)
{
var L = Lua.FromIntPtr(state);
var stream = ObjectManager.ToObject<Stream>(L, Lua.UpValueIndex(1), false);
int i;
int n = (int)L.ToInteger(Lua.UpValueIndex(2));
if (stream is null)
{
return L.Error("file is already closed");
}
L.SetTop(1);
L.CheckStack(n, "too many arguments");
for (i = 1; i <= n; i++)
{
L.PushCopy(Lua.UpValueIndex(3 + i));
}
n = G_Read(L, stream, 2);
Debug.Assert(n > 0);
if (L.ToBoolean(-n))
{
return n;
}
else
{
if (n > 1)
{
return L.Error(L.ToString(-n + 1));
}
if (L.ToBoolean(Lua.UpValueIndex(3)))
{
L.SetTop(0);
L.PushCopy(Lua.UpValueIndex(1));
stream.Close();
}
}
return 0;
}
private static int L_Flush(IntPtr state) private static int L_Flush(IntPtr state)
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
@ -363,7 +418,7 @@ public class FileHandle : IComponent
return 0; return 0;
} }
private static class ReadNumberHelper private static class ReadHelper
{ {
static bool isdigit(char c) static bool isdigit(char c)
{ {
@ -389,6 +444,12 @@ public class FileHandle : IComponent
}.Contains(c); }.Contains(c);
} }
static bool test_eof(Lua L, Stream f)
{
L.PushString("");
return f.Position != f.Length;
}
static bool nextc(RN rn) static bool nextc(RN rn)
{ {
if (rn.n >= 200) // buffer overflow? if (rn.n >= 200) // buffer overflow?