github.com/yuin/gopher-lua@v1.1.2-0.20231212122839-2348fd042596/oslib.go (about) 1 package lua 2 3 import ( 4 "io/ioutil" 5 "os" 6 "strings" 7 "time" 8 ) 9 10 var startedAt time.Time 11 12 func init() { 13 startedAt = time.Now() 14 } 15 16 func getIntField(L *LState, tb *LTable, key string, v int) int { 17 ret := tb.RawGetString(key) 18 19 switch lv := ret.(type) { 20 case LNumber: 21 return int(lv) 22 case LString: 23 slv := string(lv) 24 slv = strings.TrimLeft(slv, " ") 25 if strings.HasPrefix(slv, "0") && !strings.HasPrefix(slv, "0x") && !strings.HasPrefix(slv, "0X") { 26 // Standard lua interpreter only support decimal and hexadecimal 27 slv = strings.TrimLeft(slv, "0") 28 if slv == "" { 29 return 0 30 } 31 } 32 if num, err := parseNumber(slv); err == nil { 33 return int(num) 34 } 35 default: 36 return v 37 } 38 39 return v 40 } 41 42 func getBoolField(L *LState, tb *LTable, key string, v bool) bool { 43 ret := tb.RawGetString(key) 44 if lb, ok := ret.(LBool); ok { 45 return bool(lb) 46 } 47 return v 48 } 49 50 func OpenOs(L *LState) int { 51 osmod := L.RegisterModule(OsLibName, osFuncs) 52 L.Push(osmod) 53 return 1 54 } 55 56 var osFuncs = map[string]LGFunction{ 57 "clock": osClock, 58 "difftime": osDiffTime, 59 "execute": osExecute, 60 "exit": osExit, 61 "date": osDate, 62 "getenv": osGetEnv, 63 "remove": osRemove, 64 "rename": osRename, 65 "setenv": osSetEnv, 66 "setlocale": osSetLocale, 67 "time": osTime, 68 "tmpname": osTmpname, 69 } 70 71 func osClock(L *LState) int { 72 L.Push(LNumber(float64(time.Now().Sub(startedAt)) / float64(time.Second))) 73 return 1 74 } 75 76 func osDiffTime(L *LState) int { 77 L.Push(LNumber(L.CheckInt64(1) - L.CheckInt64(2))) 78 return 1 79 } 80 81 func osExecute(L *LState) int { 82 var procAttr os.ProcAttr 83 procAttr.Files = []*os.File{os.Stdin, os.Stdout, os.Stderr} 84 cmd, args := popenArgs(L.CheckString(1)) 85 args = append([]string{cmd}, args...) 86 process, err := os.StartProcess(cmd, args, &procAttr) 87 if err != nil { 88 L.Push(LNumber(1)) 89 return 1 90 } 91 92 ps, err := process.Wait() 93 if err != nil || !ps.Success() { 94 L.Push(LNumber(1)) 95 return 1 96 } 97 L.Push(LNumber(0)) 98 return 1 99 } 100 101 func osExit(L *LState) int { 102 L.Close() 103 os.Exit(L.OptInt(1, 0)) 104 return 1 105 } 106 107 func osDate(L *LState) int { 108 t := time.Now() 109 isUTC := false 110 cfmt := "%c" 111 if L.GetTop() >= 1 { 112 cfmt = L.CheckString(1) 113 if strings.HasPrefix(cfmt, "!") { 114 cfmt = strings.TrimLeft(cfmt, "!") 115 isUTC = true 116 } 117 if L.GetTop() >= 2 { 118 t = time.Unix(L.CheckInt64(2), 0) 119 } 120 if isUTC { 121 t = t.UTC() 122 } 123 if strings.HasPrefix(cfmt, "*t") { 124 ret := L.NewTable() 125 ret.RawSetString("year", LNumber(t.Year())) 126 ret.RawSetString("month", LNumber(t.Month())) 127 ret.RawSetString("day", LNumber(t.Day())) 128 ret.RawSetString("hour", LNumber(t.Hour())) 129 ret.RawSetString("min", LNumber(t.Minute())) 130 ret.RawSetString("sec", LNumber(t.Second())) 131 ret.RawSetString("wday", LNumber(t.Weekday()+1)) 132 // TODO yday & dst 133 ret.RawSetString("yday", LNumber(0)) 134 ret.RawSetString("isdst", LFalse) 135 L.Push(ret) 136 return 1 137 } 138 } 139 L.Push(LString(strftime(t, cfmt))) 140 return 1 141 } 142 143 func osGetEnv(L *LState) int { 144 v := os.Getenv(L.CheckString(1)) 145 if len(v) == 0 { 146 L.Push(LNil) 147 } else { 148 L.Push(LString(v)) 149 } 150 return 1 151 } 152 153 func osRemove(L *LState) int { 154 err := os.Remove(L.CheckString(1)) 155 if err != nil { 156 L.Push(LNil) 157 L.Push(LString(err.Error())) 158 return 2 159 } else { 160 L.Push(LTrue) 161 return 1 162 } 163 } 164 165 func osRename(L *LState) int { 166 err := os.Rename(L.CheckString(1), L.CheckString(2)) 167 if err != nil { 168 L.Push(LNil) 169 L.Push(LString(err.Error())) 170 return 2 171 } else { 172 L.Push(LTrue) 173 return 1 174 } 175 } 176 177 func osSetLocale(L *LState) int { 178 // setlocale is not supported 179 L.Push(LFalse) 180 return 1 181 } 182 183 func osSetEnv(L *LState) int { 184 err := os.Setenv(L.CheckString(1), L.CheckString(2)) 185 if err != nil { 186 L.Push(LNil) 187 L.Push(LString(err.Error())) 188 return 2 189 } else { 190 L.Push(LTrue) 191 return 1 192 } 193 } 194 195 func osTime(L *LState) int { 196 if L.GetTop() == 0 { 197 L.Push(LNumber(time.Now().Unix())) 198 } else { 199 lv := L.CheckAny(1) 200 if lv == LNil { 201 L.Push(LNumber(time.Now().Unix())) 202 } else { 203 tbl, ok := lv.(*LTable) 204 if !ok { 205 L.TypeError(1, LTTable) 206 } 207 sec := getIntField(L, tbl, "sec", 0) 208 min := getIntField(L, tbl, "min", 0) 209 hour := getIntField(L, tbl, "hour", 12) 210 day := getIntField(L, tbl, "day", -1) 211 month := getIntField(L, tbl, "month", -1) 212 year := getIntField(L, tbl, "year", -1) 213 isdst := getBoolField(L, tbl, "isdst", false) 214 t := time.Date(year, time.Month(month), day, hour, min, sec, 0, time.Local) 215 // TODO dst 216 if false { 217 print(isdst) 218 } 219 L.Push(LNumber(t.Unix())) 220 } 221 } 222 return 1 223 } 224 225 func osTmpname(L *LState) int { 226 file, err := ioutil.TempFile("", "") 227 if err != nil { 228 L.RaiseError("unable to generate a unique filename") 229 } 230 file.Close() 231 os.Remove(file.Name()) // ignore errors 232 L.Push(LString(file.Name())) 233 return 1 234 } 235 236 //