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  //