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 const int MULTRET = -1;
public const int MINSTACK = 20;
public const int MAXLENNUM = 200;
}

View file

@ -16,8 +16,11 @@
using Capy64.API;
using KeraLua;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using static Capy64.Runtime.Constants;
namespace Capy64.Runtime.Objects;
@ -134,7 +137,7 @@ public class FileHandle : IComponent
private static bool ReadNumber(Lua L, Stream stream)
{
var str = ReadNumberHelper.ReadNumber(stream);
var str = ReadHelper.ReadNumber(stream);
if (L.StringToNumber(str))
{
return true;
@ -197,53 +200,66 @@ public class FileHandle : IComponent
return 2;
}
var nargs = L.GetTop() - 1;
if (nargs == 0)
{
L.PushString("l");
nargs = 1;
return G_Read(L, stream, 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;
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
{
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);
switch (mode)
{
case 'n':
success = ReadNumber(L, stream);
case 'n': // number
success = ReadNumber(L, f);
break;
case 'l':
success = ReadLine(L, stream, true);
case 'l': // line
success = ReadLine(L, f, true);
break;
case 'L':
success = ReadLine(L, stream, false);
case 'L': // line with end-of-line
success = ReadLine(L, f, false);
break;
case 'a':
ReadAll(L, stream);
success = true;
case 'a': // file
ReadAll(L, f); // read entire file
success = true; // always success
break;
default:
return L.ArgumentError(i, "invalid format");
return L.ArgumentError(n, "invalid format");
}
}
}
}
if (!success)
{
L.Pop(1);
L.PushNil();
}
}
return nargs;
return n - first;
}
private static int L_Write(IntPtr state)
@ -278,7 +294,6 @@ public class FileHandle : IComponent
private static int L_Lines(IntPtr state)
{
return 0;
var L = Lua.FromIntPtr(state);
var maxargn = 250;
@ -289,11 +304,51 @@ public class FileHandle : IComponent
L.PushInteger(n);
L.PushBoolean(false);
L.Rotate(2, 3);
L.PushCClosure(null, 3 + n); // todo
L.PushCClosure(IO_ReadLine, 3 + n);
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)
{
var L = Lua.FromIntPtr(state);
@ -363,7 +418,7 @@ public class FileHandle : IComponent
return 0;
}
private static class ReadNumberHelper
private static class ReadHelper
{
static bool isdigit(char c)
{
@ -389,6 +444,12 @@ public class FileHandle : IComponent
}.Contains(c);
}
static bool test_eof(Lua L, Stream f)
{
L.PushString("");
return f.Position != f.Length;
}
static bool nextc(RN rn)
{
if (rn.n >= 200) // buffer overflow?