From 1d28f07a7e99b787938f41388e16b1b1fd3258d5 Mon Sep 17 00:00:00 2001 From: Alessandro Proto Date: Thu, 6 Apr 2023 21:14:44 +0200 Subject: [PATCH] Add support to FILE:read("n") --- Capy64/Runtime/Objects/FileHandle.cs | 122 ++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/Capy64/Runtime/Objects/FileHandle.cs b/Capy64/Runtime/Objects/FileHandle.cs index f44ce81..4a1cbfe 100644 --- a/Capy64/Runtime/Objects/FileHandle.cs +++ b/Capy64/Runtime/Objects/FileHandle.cs @@ -17,6 +17,7 @@ using Capy64.API; using KeraLua; using System; using System.IO; +using System.Linq; namespace Capy64.Runtime.Objects; @@ -133,7 +134,16 @@ public class FileHandle : IComponent private static bool ReadNumber(Lua L, Stream stream) { - return false; + var str = ReadNumberHelper.ReadNumber(stream); + if (L.StringToNumber(str)) + { + return true; + } + else + { + L.PushNil(); + return false; + } } private static bool ReadLine(Lua L, Stream stream, bool chop) @@ -352,4 +362,114 @@ public class FileHandle : IComponent return 0; } + + private static class ReadNumberHelper + { + static bool isdigit(char c) + { + return "0123456789" + .Contains(c, StringComparison.CurrentCultureIgnoreCase); + } + + static bool isxdigit(char c) + { + return "0123456789abcdef" + .Contains(c, StringComparison.CurrentCultureIgnoreCase); + } + + static bool isspace(char c) + { + return new char[] { + ' ', + '\n', + '\t', + '\v', + '\f', + '\r', + }.Contains(c); + } + + static bool nextc(RN rn) + { + if (rn.n >= 200) // buffer overflow? + { + rn.buff[0] = '\0'; // invalidate result + return false; // fail + } + else + { + rn.buff[rn.n] = rn.c; // save current char + rn.n++; + rn.c = (char)rn.f.ReadByte(); // read next one + return true; + } + } + + static bool test2(RN rn, string set) + { + if (rn.c == set[0] || rn.c == set[1]) + { + return nextc(rn); + } + return false; + } + + static int readdigits(RN rn, bool hex) + { + int count = 0; + while ((hex ? isxdigit(rn.c) : isdigit(rn.c)) && nextc(rn)) + count++; + return count; + } + + + /// + /// https://www.lua.org/source/5.4/liolib.c.html#read_number + /// + /// + /// + public static string ReadNumber(Stream stream) + { + RN rn = new() + { + buff = new char[201] + }; + + int count = 0; + bool hex = false; + string decp = ".."; + rn.f = stream; + rn.n = 0; + + do + { + rn.c = (char)rn.f.ReadByte(); + } while (isspace(rn.c)); /* skip spaces */ + + test2(rn, "+-"); /* optional sign */ + if (test2(rn, "00")) + { + if (test2(rn, "xX")) hex = true; /* numeral is hexadecimal */ + else count = 1; /* count initial '0' as a valid digit */ + } + count += readdigits(rn, hex); // integral part + if (test2(rn, decp)) // decimal point? + count += readdigits(rn, hex); // fractional part + if (count > 0 && test2(rn, (hex ? "pP" : "eE"))) + { /* exponent mark? */ + test2(rn, "-+"); /* exponent sign */ + readdigits(rn, false); /* exponent digits */ + } + rn.f.Position += -1; + return new string(rn.buff); + } + + public class RN + { + public Stream f; + public char c; + public int n; + public char[] buff; + } + } }