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