1package lua
2
3import (
4	"bufio"
5	"fmt"
6	"io"
7	"reflect"
8	"strconv"
9	"strings"
10	"time"
11	"unsafe"
12)
13
14func intMin(a, b int) int {
15	if a < b {
16		return a
17	} else {
18		return b
19	}
20}
21
22func intMax(a, b int) int {
23	if a > b {
24		return a
25	} else {
26		return b
27	}
28}
29
30func 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
50type 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
62func 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
66func (fs *flagScanner) AppendString(str string) { fs.buf = append(fs.buf, str...) }
67
68func (fs *flagScanner) AppendChar(ch byte) { fs.buf = append(fs.buf, ch) }
69
70func (fs *flagScanner) String() string { return string(fs.buf) }
71
72func (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
102var 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
107func 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
133func isInteger(v LNumber) bool {
134	return float64(v) == float64(int64(v))
135	//_, frac := math.Modf(float64(v))
136	//return frac == 0.0
137}
138
139func isArrayKey(v LNumber) bool {
140	return isInteger(v) && v < LNumber(int((^uint(0))>>1)) && v > LNumber(0) && v < LNumber(MaxArrayIndex)
141}
142
143func 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
158func 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
169func 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
180func 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
202func 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
222func 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
235func 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
258func 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}
266