github.com/xmx/lua@v0.0.0-20230324063450-8a298e091302/utils.go (about) 1 package lua 2 3 import ( 4 "bufio" 5 "fmt" 6 "io" 7 "reflect" 8 "strconv" 9 "strings" 10 "time" 11 "unsafe" 12 ) 13 14 func intMin(a, b int) int { 15 if a < b { 16 return a 17 } else { 18 return b 19 } 20 } 21 22 func intMax(a, b int) int { 23 if a > b { 24 return a 25 } else { 26 return b 27 } 28 } 29 30 func defaultFormat(v interface{}, f fmt.State, c rune) { 31 buf := make([]string, 0, 10) 32 buf = append(buf, "%") 33 for i := 0; i < 128; i++ { 34 if f.Flag(i) { 35 buf = append(buf, string(rune(i))) 36 } 37 } 38 39 if w, ok := f.Width(); ok { 40 buf = append(buf, strconv.Itoa(w)) 41 } 42 if p, ok := f.Precision(); ok { 43 buf = append(buf, "."+strconv.Itoa(p)) 44 } 45 buf = append(buf, string(c)) 46 format := strings.Join(buf, "") 47 fmt.Fprintf(f, format, v) 48 } 49 50 type flagScanner struct { 51 flag byte 52 start string 53 end string 54 buf []byte 55 str string 56 Length int 57 Pos int 58 HasFlag bool 59 ChangeFlag bool 60 } 61 62 func newFlagScanner(flag byte, start, end, str string) *flagScanner { 63 return &flagScanner{flag, start, end, make([]byte, 0, len(str)), str, len(str), 0, false, false} 64 } 65 66 func (fs *flagScanner) AppendString(str string) { fs.buf = append(fs.buf, str...) } 67 68 func (fs *flagScanner) AppendChar(ch byte) { fs.buf = append(fs.buf, ch) } 69 70 func (fs *flagScanner) String() string { return string(fs.buf) } 71 72 func (fs *flagScanner) Next() (byte, bool) { 73 c := byte('\000') 74 fs.ChangeFlag = false 75 if fs.Pos == fs.Length { 76 if fs.HasFlag { 77 fs.AppendString(fs.end) 78 } 79 return c, true 80 } else { 81 c = fs.str[fs.Pos] 82 if c == fs.flag { 83 if fs.Pos < (fs.Length-1) && fs.str[fs.Pos+1] == fs.flag { 84 fs.HasFlag = false 85 fs.AppendChar(fs.flag) 86 fs.Pos += 2 87 return fs.Next() 88 } else if fs.Pos != fs.Length-1 { 89 if fs.HasFlag { 90 fs.AppendString(fs.end) 91 } 92 fs.AppendString(fs.start) 93 fs.ChangeFlag = true 94 fs.HasFlag = true 95 } 96 } 97 } 98 fs.Pos++ 99 return c, false 100 } 101 102 var cDateFlagToGo = map[byte]string{ 103 'a': "mon", 'A': "Monday", 'b': "Jan", 'B': "January", 'c': "02 Jan 06 15:04 MST", 'd': "02", 104 'F': "2006-01-02", 'H': "15", 'I': "03", 'm': "01", 'M': "04", 'p': "PM", 'P': "pm", 'S': "05", 105 'x': "15/04/05", 'X': "15:04:05", 'y': "06", 'Y': "2006", 'z': "-0700", 'Z': "MST", 106 } 107 108 func strftime(t time.Time, cfmt string) string { 109 sc := newFlagScanner('%', "", "", cfmt) 110 for c, eos := sc.Next(); !eos; c, eos = sc.Next() { 111 if !sc.ChangeFlag { 112 if sc.HasFlag { 113 if v, ok := cDateFlagToGo[c]; ok { 114 sc.AppendString(t.Format(v)) 115 } else { 116 switch c { 117 case 'w': 118 sc.AppendString(fmt.Sprint(int(t.Weekday()))) 119 default: 120 sc.AppendChar('%') 121 sc.AppendChar(c) 122 } 123 } 124 sc.HasFlag = false 125 } else { 126 sc.AppendChar(c) 127 } 128 } 129 } 130 131 return sc.String() 132 } 133 134 func isInteger(v LNumber) bool { 135 return float64(v) == float64(int64(v)) 136 //_, frac := math.Modf(float64(v)) 137 //return frac == 0.0 138 } 139 140 func isArrayKey(v LNumber) bool { 141 return isInteger(v) && v < LNumber(int((^uint(0))>>1)) && v > LNumber(0) && v < LNumber(MaxArrayIndex) 142 } 143 144 func parseNumber(number string) (LNumber, error) { 145 var value LNumber 146 number = strings.Trim(number, " \t\n") 147 if v, err := strconv.ParseInt(number, 0, LNumberBit); err != nil { 148 if v2, err2 := strconv.ParseFloat(number, LNumberBit); err2 != nil { 149 return LNumber(0), err2 150 } else { 151 value = LNumber(v2) 152 } 153 } else { 154 value = LNumber(v) 155 } 156 return value, nil 157 } 158 159 func popenArgs(arg string) (string, []string) { 160 cmd := "/bin/sh" 161 args := []string{"-c"} 162 if LuaOS == "windows" { 163 cmd = "C:\\Windows\\system32\\cmd.exe" 164 args = []string{"/c"} 165 } 166 args = append(args, arg) 167 return cmd, args 168 } 169 170 func isGoroutineSafe(lv LValue) bool { 171 switch v := lv.(type) { 172 case *LFunction, *LUserData, *LState: 173 return false 174 case *LTable: 175 return v.Metatable == LNil 176 default: 177 return true 178 } 179 } 180 181 func readBufioSize(reader *bufio.Reader, size int64) ([]byte, error, bool) { 182 result := []byte{} 183 read := int64(0) 184 var err error 185 var n int 186 for read != size { 187 buf := make([]byte, size-read) 188 n, err = reader.Read(buf) 189 if err != nil { 190 break 191 } 192 read += int64(n) 193 result = append(result, buf[:n]...) 194 } 195 e := err 196 if e != nil && e == io.EOF { 197 e = nil 198 } 199 200 return result, e, len(result) == 0 && err == io.EOF 201 } 202 203 func readBufioLine(reader *bufio.Reader) ([]byte, error, bool) { 204 result := []byte{} 205 var buf []byte 206 var err error 207 var isprefix bool = true 208 for isprefix { 209 buf, isprefix, err = reader.ReadLine() 210 if err != nil { 211 break 212 } 213 result = append(result, buf...) 214 } 215 e := err 216 if e != nil && e == io.EOF { 217 e = nil 218 } 219 220 return result, e, len(result) == 0 && err == io.EOF 221 } 222 223 func int2Fb(val int) int { 224 e := 0 225 x := val 226 for x >= 16 { 227 x = (x + 1) >> 1 228 e++ 229 } 230 if x < 8 { 231 return x 232 } 233 return ((e + 1) << 3) | (x - 8) 234 } 235 236 func strCmp(s1, s2 string) int { 237 len1 := len(s1) 238 len2 := len(s2) 239 for i := 0; ; i++ { 240 c1 := -1 241 if i < len1 { 242 c1 = int(s1[i]) 243 } 244 c2 := -1 245 if i != len2 { 246 c2 = int(s2[i]) 247 } 248 switch { 249 case c1 < c2: 250 return -1 251 case c1 > c2: 252 return +1 253 case c1 < 0: 254 return 0 255 } 256 } 257 } 258 259 func unsafeFastStringToReadOnlyBytes(s string) (bs []byte) { 260 sh := (*reflect.StringHeader)(unsafe.Pointer(&s)) 261 bh := (*reflect.SliceHeader)(unsafe.Pointer(&bs)) 262 bh.Data = sh.Data 263 bh.Cap = sh.Len 264 bh.Len = sh.Len 265 return 266 }