using Lua.Standard.Internal; namespace Lua.Standard; public sealed class OperatingSystemLibrary { public static readonly OperatingSystemLibrary Instance = new(); public OperatingSystemLibrary() { Functions = [ new("os", "clock", Clock), new("os", "date", Date), new("os", "difftime", DiffTime), new("os", "execute", Execute), new("os", "exit", Exit), new("os", "getenv", GetEnv), new("os", "remove", Remove), new("os", "rename", Rename), new("os", "setlocale", SetLocale), new("os", "time", Time), new("os", "tmpname", TmpName), ]; } public readonly LibraryFunction[] Functions; public ValueTask Clock(LuaFunctionExecutionContext context, CancellationToken cancellationToken) { return new(context.Return(context.State.OsEnvironment.GetTotalProcessorTime())); } public ValueTask Date(LuaFunctionExecutionContext context, CancellationToken cancellationToken) { var format = context.HasArgument(0) ? context.GetArgument(0).AsSpan() : "%c".AsSpan(); DateTime now; if (context.HasArgument(1)) { var time = context.GetArgument(1); now = DateTimeHelper.FromUnixTime(time); } else { now = context.State.OsEnvironment.GetCurrentUtcTime(); } var isDst = false; if (format[0] == '!') { format = format[1..]; } else { var offset = context.State.OsEnvironment.GetLocalTimeZoneOffset(); now += offset; isDst = now.IsDaylightSavingTime(); } if (format is "*t") { var table = new LuaTable { ["year"] = now.Year, ["month"] = now.Month, ["day"] = now.Day, ["hour"] = now.Hour, ["min"] = now.Minute, ["sec"] = now.Second, ["wday"] = (int)now.DayOfWeek + 1, ["yday"] = now.DayOfYear, ["isdst"] = isDst }; return new(context.Return(table)); } else { return new(context.Return(DateTimeHelper.StrFTime(context.Thread, format, now))); } } public ValueTask DiffTime(LuaFunctionExecutionContext context, CancellationToken cancellationToken) { var t2 = context.GetArgument(0); var t1 = context.GetArgument(1); return new(context.Return(t2 - t1)); } public ValueTask Execute(LuaFunctionExecutionContext context, CancellationToken cancellationToken) { // os.execute(command) is not supported if (context.HasArgument(0)) { throw new NotSupportedException("os.execute(command) is not supported"); } else { return new(context.Return(false)); } } public async ValueTask Exit(LuaFunctionExecutionContext context, CancellationToken cancellationToken) { // Ignore 'close' parameter int exitCode = 0; if (context.HasArgument(0)) { var code = context.Arguments[0]; if (code.TryRead(out var b)) { exitCode = b ? 0 : 1; } else if (code.TryRead(out var d)) { exitCode = d; } else { LuaRuntimeException.BadArgument(context.Thread, 1, LuaValueType.Nil, code.Type); } } await context.State.OsEnvironment.Exit(exitCode, cancellationToken); throw new InvalidOperationException("Unreachable code.. reached."); } public ValueTask GetEnv(LuaFunctionExecutionContext context, CancellationToken cancellationToken) { var variable = context.GetArgument(0); return new(context.Return(context.State.OsEnvironment.GetEnvironmentVariable(variable) ?? LuaValue.Nil)); } public async ValueTask Remove(LuaFunctionExecutionContext context, CancellationToken cancellationToken) { var fileName = context.GetArgument(0); try { await context.State.FileSystem.Remove(fileName, cancellationToken); return context.Return(true); } catch (IOException ex) { return context.Return(LuaValue.Nil, ex.Message, ex.HResult); } } public async ValueTask Rename(LuaFunctionExecutionContext context, CancellationToken cancellationToken) { var oldName = context.GetArgument(0); var newName = context.GetArgument(1); try { await context.State.FileSystem.Rename(oldName, newName, cancellationToken); return context.Return(true); } catch (IOException ex) { return context.Return(LuaValue.Nil, ex.Message, ex.HResult); } } public ValueTask SetLocale(LuaFunctionExecutionContext context, CancellationToken cancellationToken) { // os.setlocale is not supported (always return nil) return new(context.Return(LuaValue.Nil)); } public ValueTask Time(LuaFunctionExecutionContext context, CancellationToken cancellationToken) { if (context.HasArgument(0)) { var table = context.GetArgument(0); var date = DateTimeHelper.ParseTimeTable(context.Thread, table); return new(context.Return(DateTimeHelper.GetUnixTime(date))); } else { return new(context.Return(DateTimeHelper.GetUnixTime(context.State.OsEnvironment.GetCurrentUtcTime()))); } } public ValueTask TmpName(LuaFunctionExecutionContext context, CancellationToken cancellationToken) { return new(context.Return(context.State.FileSystem.GetTempFileName())); } }