using System; using System.Collections.Generic; using System.Linq; using System.Text; using MoonSharp.Interpreter.Execution; namespace MoonSharp.Interpreter.CoreLib.IO { /// /// Abstract class implementing a file Lua userdata. Methods are meant to be called by Lua code. /// public abstract class FileUserDataBase : RefIdObject { public DynValue lines(ScriptExecutionContext executionContext, CallbackArguments args) { List readLines = new List(); DynValue readValue = null; do { readValue = read(executionContext, args); readLines.Add(readValue); } while (readValue.IsNotNil()); return DynValue.FromObject(executionContext.GetScript(), readLines.Select(s => s)); } public DynValue read(ScriptExecutionContext executionContext, CallbackArguments args) { if (args.Count == 0) { string str = ReadLine(); if (str == null) return DynValue.Nil; str = str.TrimEnd('\n', '\r'); return DynValue.NewString(str); } else { List rets = new List(); for (int i = 0; i < args.Count; i++) { DynValue v; if (args[i].Type == DataType.Number) { if (Eof()) return DynValue.Nil; int howmany = (int)args[i].Number; string str = ReadBuffer(howmany); v = DynValue.NewString(str); } else { string opt = args.AsType(i, "read", DataType.String, false).String; if (Eof()) { v = opt.StartsWith("*a") ? DynValue.NewString("") : DynValue.Nil; } else if (opt.StartsWith("*n")) { double? d = ReadNumber(); if (d.HasValue) v = DynValue.NewNumber(d.Value); else v = DynValue.Nil; } else if (opt.StartsWith("*a")) { string str = ReadToEnd(); v = DynValue.NewString(str); } else if (opt.StartsWith("*l")) { string str = ReadLine(); str = str.TrimEnd('\n', '\r'); v = DynValue.NewString(str); } else if (opt.StartsWith("*L")) { string str = ReadLine(); str = str.TrimEnd('\n', '\r'); str += "\n"; v = DynValue.NewString(str); } else { throw ScriptRuntimeException.BadArgument(i, "read", "invalid option"); } } rets.Add(v); } return DynValue.NewTuple(rets.ToArray()); } } public DynValue write(ScriptExecutionContext executionContext, CallbackArguments args) { try { for (int i = 0; i < args.Count; i++) { //string str = args.AsStringUsingMeta(executionContext, i, "file:write"); string str = args.AsType(i, "write", DataType.String, false).String; Write(str); } return UserData.Create(this); } catch (ScriptRuntimeException) { throw; } catch (Exception ex) { return DynValue.NewTuple(DynValue.Nil, DynValue.NewString(ex.Message)); } } public DynValue close(ScriptExecutionContext executionContext, CallbackArguments args) { try { string msg = Close(); if (msg == null) return DynValue.True; else return DynValue.NewTuple(DynValue.Nil, DynValue.NewString(msg)); } catch (ScriptRuntimeException) { throw; } catch (Exception ex) { return DynValue.NewTuple(DynValue.Nil, DynValue.NewString(ex.Message)); } } double? ReadNumber() { string chr = ""; while (!Eof()) { char c = Peek(); if (char.IsWhiteSpace(c)) { ReadBuffer(1); } else if (IsNumericChar(c, chr)) { ReadBuffer(1); chr += c; } else break; } double d; if (double.TryParse(chr, out d)) { return d; } else { return null; } } private bool IsNumericChar(char c, string numAsFar) { if (char.IsDigit(c)) return true; if (c == '-') return numAsFar.Length == 0; if (c == '.') return !numAsFar.Contains('.'); if (c == 'E' || c == 'e') return !(numAsFar.Contains('E') || numAsFar.Contains('e')); return false; } protected abstract bool Eof(); protected abstract string ReadLine(); protected abstract string ReadBuffer(int p); protected abstract string ReadToEnd(); protected abstract char Peek(); protected abstract void Write(string value); protected internal abstract bool isopen(); protected abstract string Close(); public abstract bool flush(); public abstract long seek(string whence, long offset); public abstract bool setvbuf(string mode); public override string ToString() { if (isopen()) return string.Format("file ({0:X8})", base.ReferenceID); else return "file (closed)"; } } }