github.com/rhettli/gopher-lua@v0.0.0-20200830072439-712e2f816099/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 func strftime(t time.Time, cfmt string) string { 108 sc := newFlagScanner('%', "", "", cfmt) 109 for c, eos := sc.Next(); !eos; c, eos = sc.Next() { 110 if !sc.ChangeFlag { 111 if sc.HasFlag { 112 if v, ok := cDateFlagToGo[c]; ok { 113 sc.AppendString(t.Format(v)) 114 } else { 115 switch c { 116 case 'w': 117 sc.AppendString(fmt.Sprint(int(t.Weekday()))) 118 default: 119 sc.AppendChar('%') 120 sc.AppendChar(c) 121 } 122 } 123 sc.HasFlag = false 124 } else { 125 sc.AppendChar(c) 126 } 127 } 128 } 129 130 return sc.String() 131 } 132 133 func isInteger(v LNumber) bool { 134 return float64(v) == float64(int64(v)) 135 //_, frac := math.Modf(float64(v)) 136 //return frac == 0.0 137 } 138 139 func isArrayKey(v LNumber) bool { 140 return isInteger(v) && v < LNumber(int((^uint(0))>>1)) && v > LNumber(0) && v < LNumber(MaxArrayIndex) 141 } 142 143 func parseNumber(number string) (LNumber, error) { 144 var value LNumber 145 number = strings.Trim(number, " \t\n") 146 if v, err := strconv.ParseInt(number, 0, LNumberBit); err != nil { 147 if v2, err2 := strconv.ParseFloat(number, LNumberBit); err2 != nil { 148 return LNumber(0), err2 149 } else { 150 value = LNumber(v2) 151 } 152 } else { 153 value = LNumber(v) 154 } 155 return value, nil 156 } 157 158 func popenArgs(arg string) (string, []string) { 159 cmd := "/bin/sh" 160 args := []string{"-c"} 161 if LuaOS == "windows" { 162 cmd = "C:\\Windows\\system32\\cmd.exe" 163 args = []string{"/c"} 164 } 165 args = append(args, arg) 166 return cmd, args 167 } 168 169 func isGoroutineSafe(lv LValue) bool { 170 switch v := lv.(type) { 171 case *LFunction, *LUserData, *LState: 172 return false 173 case *LTable: 174 return v.Metatable == LNil 175 default: 176 return true 177 } 178 } 179 180 func readBufioSize(reader *bufio.Reader, size int64) ([]byte, error, bool) { 181 result := []byte{} 182 read := int64(0) 183 var err error 184 var n int 185 for read != size { 186 buf := make([]byte, size-read) 187 n, err = reader.Read(buf) 188 if err != nil { 189 break 190 } 191 read += int64(n) 192 result = append(result, buf[:n]...) 193 } 194 e := err 195 if e != nil && e == io.EOF { 196 e = nil 197 } 198 199 return result, e, len(result) == 0 && err == io.EOF 200 } 201 202 func readBufioLine(reader *bufio.Reader) ([]byte, error, bool) { 203 result := []byte{} 204 var buf []byte 205 var err error 206 var isprefix bool = true 207 for isprefix { 208 buf, isprefix, err = reader.ReadLine() 209 if err != nil { 210 break 211 } 212 result = append(result, buf...) 213 } 214 e := err 215 if e != nil && e == io.EOF { 216 e = nil 217 } 218 219 return result, e, len(result) == 0 && err == io.EOF 220 } 221 222 func int2Fb(val int) int { 223 e := 0 224 x := val 225 for x >= 16 { 226 x = (x + 1) >> 1 227 e++ 228 } 229 if x < 8 { 230 return x 231 } 232 return ((e + 1) << 3) | (x - 8) 233 } 234 235 func strCmp(s1, s2 string) int { 236 len1 := len(s1) 237 len2 := len(s2) 238 for i := 0; ; i++ { 239 c1 := -1 240 if i < len1 { 241 c1 = int(s1[i]) 242 } 243 c2 := -1 244 if i != len2 { 245 c2 = int(s2[i]) 246 } 247 switch { 248 case c1 < c2: 249 return -1 250 case c1 > c2: 251 return +1 252 case c1 < 0: 253 return 0 254 } 255 } 256 } 257 258 func unsafeFastStringToReadOnlyBytes(s string) (bs []byte) { 259 sh := (*reflect.StringHeader)(unsafe.Pointer(&s)) 260 bh := (*reflect.SliceHeader)(unsafe.Pointer(&bs)) 261 bh.Data = sh.Data 262 bh.Cap = sh.Len 263 bh.Len = sh.Len 264 return 265 }