OperatingSystemLibrary.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. using Lua.Standard.Internal;
  2. namespace Lua.Standard;
  3. public sealed class OperatingSystemLibrary
  4. {
  5. public static readonly OperatingSystemLibrary Instance = new();
  6. public OperatingSystemLibrary()
  7. {
  8. Functions =
  9. [
  10. new("os", "clock", Clock),
  11. new("os", "date", Date),
  12. new("os", "difftime", DiffTime),
  13. new("os", "execute", Execute),
  14. new("os", "exit", Exit),
  15. new("os", "getenv", GetEnv),
  16. new("os", "remove", Remove),
  17. new("os", "rename", Rename),
  18. new("os", "setlocale", SetLocale),
  19. new("os", "time", Time),
  20. new("os", "tmpname", TmpName),
  21. ];
  22. }
  23. public readonly LibraryFunction[] Functions;
  24. public ValueTask<int> Clock(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  25. {
  26. return new(context.Return(context.State.OsEnvironment.GetTotalProcessorTime()));
  27. }
  28. public ValueTask<int> Date(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  29. {
  30. var format = context.HasArgument(0)
  31. ? context.GetArgument<string>(0).AsSpan()
  32. : "%c".AsSpan();
  33. DateTime now;
  34. if (context.HasArgument(1))
  35. {
  36. var time = context.GetArgument<double>(1);
  37. now = DateTimeHelper.FromUnixTime(time);
  38. }
  39. else
  40. {
  41. now = context.State.OsEnvironment.GetCurrentUtcTime();
  42. }
  43. var isDst = false;
  44. if (format[0] == '!')
  45. {
  46. format = format[1..];
  47. }
  48. else
  49. {
  50. var offset = context.State.OsEnvironment.GetLocalTimeZoneOffset();
  51. now += offset;
  52. isDst = now.IsDaylightSavingTime();
  53. }
  54. if (format is "*t")
  55. {
  56. var table = new LuaTable
  57. {
  58. ["year"] = now.Year,
  59. ["month"] = now.Month,
  60. ["day"] = now.Day,
  61. ["hour"] = now.Hour,
  62. ["min"] = now.Minute,
  63. ["sec"] = now.Second,
  64. ["wday"] = (int)now.DayOfWeek + 1,
  65. ["yday"] = now.DayOfYear,
  66. ["isdst"] = isDst
  67. };
  68. return new(context.Return(table));
  69. }
  70. else
  71. {
  72. return new(context.Return(DateTimeHelper.StrFTime(context.Thread, format, now)));
  73. }
  74. }
  75. public ValueTask<int> DiffTime(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  76. {
  77. var t2 = context.GetArgument<double>(0);
  78. var t1 = context.GetArgument<double>(1);
  79. return new(context.Return(t2 - t1));
  80. }
  81. public ValueTask<int> Execute(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  82. {
  83. // os.execute(command) is not supported
  84. if (context.HasArgument(0))
  85. {
  86. throw new NotSupportedException("os.execute(command) is not supported");
  87. }
  88. else
  89. {
  90. return new(context.Return(false));
  91. }
  92. }
  93. public async ValueTask<int> Exit(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  94. {
  95. // Ignore 'close' parameter
  96. int exitCode = 0;
  97. if (context.HasArgument(0))
  98. {
  99. var code = context.Arguments[0];
  100. if (code.TryRead<bool>(out var b))
  101. {
  102. exitCode = b ? 0 : 1;
  103. }
  104. else if (code.TryRead<int>(out var d))
  105. {
  106. exitCode = d;
  107. }
  108. else
  109. {
  110. LuaRuntimeException.BadArgument(context.Thread, 1, LuaValueType.Nil, code.Type);
  111. }
  112. }
  113. await context.State.OsEnvironment.Exit(exitCode, cancellationToken);
  114. throw new InvalidOperationException("Unreachable code.. reached.");
  115. }
  116. public ValueTask<int> GetEnv(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  117. {
  118. var variable = context.GetArgument<string>(0);
  119. return new(context.Return(context.State.OsEnvironment.GetEnvironmentVariable(variable) ?? LuaValue.Nil));
  120. }
  121. public async ValueTask<int> Remove(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  122. {
  123. var fileName = context.GetArgument<string>(0);
  124. try
  125. {
  126. await context.State.FileSystem.Remove(fileName, cancellationToken);
  127. return context.Return(true);
  128. }
  129. catch (IOException ex)
  130. {
  131. return context.Return(LuaValue.Nil, ex.Message, ex.HResult);
  132. }
  133. }
  134. public async ValueTask<int> Rename(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  135. {
  136. var oldName = context.GetArgument<string>(0);
  137. var newName = context.GetArgument<string>(1);
  138. try
  139. {
  140. await context.State.FileSystem.Rename(oldName, newName, cancellationToken);
  141. return context.Return(true);
  142. }
  143. catch (IOException ex)
  144. {
  145. return context.Return(LuaValue.Nil, ex.Message, ex.HResult);
  146. }
  147. }
  148. public ValueTask<int> SetLocale(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  149. {
  150. // os.setlocale is not supported (always return nil)
  151. return new(context.Return(LuaValue.Nil));
  152. }
  153. public ValueTask<int> Time(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  154. {
  155. if (context.HasArgument(0))
  156. {
  157. var table = context.GetArgument<LuaTable>(0);
  158. var date = DateTimeHelper.ParseTimeTable(context.Thread, table);
  159. return new(context.Return(DateTimeHelper.GetUnixTime(date)));
  160. }
  161. else
  162. {
  163. return new(context.Return(DateTimeHelper.GetUnixTime(context.State.OsEnvironment.GetCurrentUtcTime())));
  164. }
  165. }
  166. public ValueTask<int> TmpName(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  167. {
  168. return new(context.Return(context.State.FileSystem.GetTempFileName()));
  169. }
  170. }