Permalink
Cannot retrieve contributors at this time
// php2go functions | |
package php2go | |
import ( | |
"archive/zip" | |
"bytes" | |
"crypto/md5" | |
"crypto/sha1" | |
"encoding/base64" | |
"encoding/binary" | |
"encoding/csv" | |
"encoding/hex" | |
"encoding/json" | |
"fmt" | |
"hash/crc32" | |
"html" | |
"io" | |
"io/ioutil" | |
"math" | |
"math/rand" | |
"net" | |
"net/url" | |
"os" | |
"os/exec" | |
"path/filepath" | |
"reflect" | |
"runtime" | |
"strconv" | |
"strings" | |
"syscall" | |
"time" | |
"unicode" | |
"unicode/utf8" | |
) | |
//////////// Date/Time Functions //////////// | |
// Time time() | |
func Time() int64 { | |
return time.Now().Unix() | |
} | |
// Strtotime strtotime() | |
// Strtotime("02/01/2006 15:04:05", "02/01/2016 15:04:05") == 1451747045 | |
// Strtotime("3 04 PM", "8 41 PM") == -62167144740 | |
func Strtotime(format, strtime string) (int64, error) { | |
t, err := time.Parse(format, strtime) | |
if err != nil { | |
return 0, err | |
} | |
return t.Unix(), nil | |
} | |
// Date date() | |
// Date("02/01/2006 15:04:05 PM", 1524799394) | |
func Date(format string, timestamp int64) string { | |
return time.Unix(timestamp, 0).Format(format) | |
} | |
// Checkdate checkdate() | |
// Validate a Gregorian date | |
func Checkdate(month, day, year int) bool { | |
if month < 1 || month > 12 || day < 1 || day > 31 || year < 1 || year > 32767 { | |
return false | |
} | |
switch month { | |
case 4, 6, 9, 11: | |
if day > 30 { | |
return false | |
} | |
case 2: | |
// leap year | |
if year%4 == 0 && (year%100 != 0 || year%400 == 0) { | |
if day > 29 { | |
return false | |
} | |
} else if day > 28 { | |
return false | |
} | |
} | |
return true | |
} | |
// Sleep sleep() | |
func Sleep(t int64) { | |
time.Sleep(time.Duration(t) * time.Second) | |
} | |
// Usleep usleep() | |
func Usleep(t int64) { | |
time.Sleep(time.Duration(t) * time.Microsecond) | |
} | |
//////////// String Functions //////////// | |
// Strpos strpos() | |
func Strpos(haystack, needle string, offset int) int { | |
length := len(haystack) | |
if length == 0 || offset > length || -offset > length { | |
return -1 | |
} | |
if offset < 0 { | |
offset += length | |
} | |
pos := strings.Index(haystack[offset:], needle) | |
if pos == -1 { | |
return -1 | |
} | |
return pos + offset | |
} | |
// Stripos stripos() | |
func Stripos(haystack, needle string, offset int) int { | |
length := len(haystack) | |
if length == 0 || offset > length || -offset > length { | |
return -1 | |
} | |
haystack = haystack[offset:] | |
if offset < 0 { | |
offset += length | |
} | |
pos := strings.Index(strings.ToLower(haystack), strings.ToLower(needle)) | |
if pos == -1 { | |
return -1 | |
} | |
return pos + offset | |
} | |
// Strrpos strrpos() | |
func Strrpos(haystack, needle string, offset int) int { | |
pos, length := 0, len(haystack) | |
if length == 0 || offset > length || -offset > length { | |
return -1 | |
} | |
if offset < 0 { | |
haystack = haystack[:offset+length+1] | |
} else { | |
haystack = haystack[offset:] | |
} | |
pos = strings.LastIndex(haystack, needle) | |
if offset > 0 && pos != -1 { | |
pos += offset | |
} | |
return pos | |
} | |
// Strripos strripos() | |
func Strripos(haystack, needle string, offset int) int { | |
pos, length := 0, len(haystack) | |
if length == 0 || offset > length || -offset > length { | |
return -1 | |
} | |
if offset < 0 { | |
haystack = haystack[:offset+length+1] | |
} else { | |
haystack = haystack[offset:] | |
} | |
pos = strings.LastIndex(strings.ToLower(haystack), strings.ToLower(needle)) | |
if offset > 0 && pos != -1 { | |
pos += offset | |
} | |
return pos | |
} | |
// StrReplace str_replace() | |
func StrReplace(search, replace, subject string, count int) string { | |
return strings.Replace(subject, search, replace, count) | |
} | |
// Strtoupper strtoupper() | |
func Strtoupper(str string) string { | |
return strings.ToUpper(str) | |
} | |
// Strtolower strtolower() | |
func Strtolower(str string) string { | |
return strings.ToLower(str) | |
} | |
// Ucfirst ucfirst() | |
func Ucfirst(str string) string { | |
for _, v := range str { | |
u := string(unicode.ToUpper(v)) | |
return u + str[len(u):] | |
} | |
return "" | |
} | |
// Lcfirst lcfirst() | |
func Lcfirst(str string) string { | |
for _, v := range str { | |
u := string(unicode.ToLower(v)) | |
return u + str[len(u):] | |
} | |
return "" | |
} | |
// Ucwords ucwords() | |
func Ucwords(str string) string { | |
return strings.Title(str) | |
} | |
// Substr substr() | |
func Substr(str string, start uint, length int) string { | |
if start < 0 || length < -1 { | |
return str | |
} | |
switch { | |
case length == -1: | |
return str[start:] | |
case length == 0: | |
return "" | |
} | |
end := int(start) + length | |
if end > len(str) { | |
end = len(str) | |
} | |
return str[start:end] | |
} | |
// Strrev strrev() | |
func Strrev(str string) string { | |
runes := []rune(str) | |
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 { | |
runes[i], runes[j] = runes[j], runes[i] | |
} | |
return string(runes) | |
} | |
// ParseStr parse_str() | |
// f1=m&f2=n -> map[f1:m f2:n] | |
// f[a]=m&f[b]=n -> map[f:map[a:m b:n]] | |
// f[a][a]=m&f[a][b]=n -> map[f:map[a:map[a:m b:n]]] | |
// f[]=m&f[]=n -> map[f:[m n]] | |
// f[a][]=m&f[a][]=n -> map[f:map[a:[m n]]] | |
// f[][]=m&f[][]=n -> map[f:[map[]]] // Currently does not support nested slice. | |
// f=m&f[a]=n -> error // This is not the same as PHP. | |
// a .[[b=c -> map[a___[b:c] | |
func ParseStr(encodedString string, result map[string]interface{}) error { | |
// build nested map. | |
var build func(map[string]interface{}, []string, interface{}) error | |
build = func(result map[string]interface{}, keys []string, value interface{}) error { | |
length := len(keys) | |
// trim '," | |
key := strings.Trim(keys[0], "'\"") | |
if length == 1 { | |
result[key] = value | |
return nil | |
} | |
// The end is slice. like f[], f[a][] | |
if keys[1] == "" && length == 2 { | |
// todo nested slice | |
if key == "" { | |
return nil | |
} | |
val, ok := result[key] | |
if !ok { | |
result[key] = []interface{}{value} | |
return nil | |
} | |
children, ok := val.([]interface{}) | |
if !ok { | |
return fmt.Errorf("expected type '[]interface{}' for key '%s', but got '%T'", key, val) | |
} | |
result[key] = append(children, value) | |
return nil | |
} | |
// The end is slice + map. like f[][a] | |
if keys[1] == "" && length > 2 && keys[2] != "" { | |
val, ok := result[key] | |
if !ok { | |
result[key] = []interface{}{} | |
val = result[key] | |
} | |
children, ok := val.([]interface{}) | |
if !ok { | |
return fmt.Errorf("expected type '[]interface{}' for key '%s', but got '%T'", key, val) | |
} | |
if l := len(children); l > 0 { | |
if child, ok := children[l-1].(map[string]interface{}); ok { | |
if _, ok := child[keys[2]]; !ok { | |
_ = build(child, keys[2:], value) | |
return nil | |
} | |
} | |
} | |
child := map[string]interface{}{} | |
_ = build(child, keys[2:], value) | |
result[key] = append(children, child) | |
return nil | |
} | |
// map. like f[a], f[a][b] | |
val, ok := result[key] | |
if !ok { | |
result[key] = map[string]interface{}{} | |
val = result[key] | |
} | |
children, ok := val.(map[string]interface{}) | |
if !ok { | |
return fmt.Errorf("expected type 'map[string]interface{}' for key '%s', but got '%T'", key, val) | |
} | |
return build(children, keys[1:], value) | |
} | |
// split encodedString. | |
parts := strings.Split(encodedString, "&") | |
for _, part := range parts { | |
pos := strings.Index(part, "=") | |
if pos <= 0 { | |
continue | |
} | |
key, err := url.QueryUnescape(part[:pos]) | |
if err != nil { | |
return err | |
} | |
for key[0] == ' ' { | |
key = key[1:] | |
} | |
if key == "" || key[0] == '[' { | |
continue | |
} | |
value, err := url.QueryUnescape(part[pos+1:]) | |
if err != nil { | |
return err | |
} | |
// split into multiple keys | |
var keys []string | |
left := 0 | |
for i, k := range key { | |
if k == '[' && left == 0 { | |
left = i | |
} else if k == ']' { | |
if left > 0 { | |
if len(keys) == 0 { | |
keys = append(keys, key[:left]) | |
} | |
keys = append(keys, key[left+1:i]) | |
left = 0 | |
if i+1 < len(key) && key[i+1] != '[' { | |
break | |
} | |
} | |
} | |
} | |
if len(keys) == 0 { | |
keys = append(keys, key) | |
} | |
// first key | |
first := "" | |
for i, chr := range keys[0] { | |
if chr == ' ' || chr == '.' || chr == '[' { | |
first += "_" | |
} else { | |
first += string(chr) | |
} | |
if chr == '[' { | |
first += keys[0][i+1:] | |
break | |
} | |
} | |
keys[0] = first | |
// build nested map | |
if err := build(result, keys, value); err != nil { | |
return err | |
} | |
} | |
return nil | |
} | |
// NumberFormat number_format() | |
// decimals: Sets the number of decimal points. | |
// decPoint: Sets the separator for the decimal point. | |
// thousandsSep: Sets the thousands separator. | |
func NumberFormat(number float64, decimals uint, decPoint, thousandsSep string) string { | |
neg := false | |
if number < 0 { | |
number = -number | |
neg = true | |
} | |
dec := int(decimals) | |
// Will round off | |
str := fmt.Sprintf("%."+strconv.Itoa(dec)+"F", number) | |
prefix, suffix := "", "" | |
if dec > 0 { | |
prefix = str[:len(str)-(dec+1)] | |
suffix = str[len(str)-dec:] | |
} else { | |
prefix = str | |
} | |
sep := []byte(thousandsSep) | |
n, l1, l2 := 0, len(prefix), len(sep) | |
// thousands sep num | |
c := (l1 - 1) / 3 | |
tmp := make([]byte, l2*c+l1) | |
pos := len(tmp) - 1 | |
for i := l1 - 1; i >= 0; i, n, pos = i-1, n+1, pos-1 { | |
if l2 > 0 && n > 0 && n%3 == 0 { | |
for j := range sep { | |
tmp[pos] = sep[l2-j-1] | |
pos-- | |
} | |
} | |
tmp[pos] = prefix[i] | |
} | |
s := string(tmp) | |
if dec > 0 { | |
s += decPoint + suffix | |
} | |
if neg { | |
s = "-" + s | |
} | |
return s | |
} | |
// ChunkSplit chunk_split() | |
func ChunkSplit(body string, chunklen uint, end string) string { | |
if end == "" { | |
end = "\r\n" | |
} | |
runes, erunes := []rune(body), []rune(end) | |
l := uint(len(runes)) | |
if l <= 1 || l < chunklen { | |
return body + end | |
} | |
ns := make([]rune, 0, len(runes)+len(erunes)) | |
var i uint | |
for i = 0; i < l; i += chunklen { | |
if i+chunklen > l { | |
ns = append(ns, runes[i:]...) | |
} else { | |
ns = append(ns, runes[i:i+chunklen]...) | |
} | |
ns = append(ns, erunes...) | |
} | |
return string(ns) | |
} | |
// StrWordCount str_word_count() | |
func StrWordCount(str string) []string { | |
return strings.Fields(str) | |
} | |
// Wordwrap wordwrap() | |
func Wordwrap(str string, width uint, br string, cut bool) string { | |
strlen := len(str) | |
brlen := len(br) | |
linelen := int(width) | |
if strlen == 0 { | |
return "" | |
} | |
if brlen == 0 { | |
panic("break string cannot be empty") | |
} | |
if linelen == 0 && cut { | |
panic("can't force cut when width is zero") | |
} | |
current, laststart, lastspace := 0, 0, 0 | |
var ns []byte | |
for current = 0; current < strlen; current++ { | |
if str[current] == br[0] && current+brlen < strlen && str[current:current+brlen] == br { | |
ns = append(ns, str[laststart:current+brlen]...) | |
current += brlen - 1 | |
lastspace = current + 1 | |
laststart = lastspace | |
} else if str[current] == ' ' { | |
if current-laststart >= linelen { | |
ns = append(ns, str[laststart:current]...) | |
ns = append(ns, br[:]...) | |
laststart = current + 1 | |
} | |
lastspace = current | |
} else if current-laststart >= linelen && cut && laststart >= lastspace { | |
ns = append(ns, str[laststart:current]...) | |
ns = append(ns, br[:]...) | |
laststart = current | |
lastspace = current | |
} else if current-laststart >= linelen && laststart < lastspace { | |
ns = append(ns, str[laststart:lastspace]...) | |
ns = append(ns, br[:]...) | |
lastspace++ | |
laststart = lastspace | |
} | |
} | |
if laststart != current { | |
ns = append(ns, str[laststart:current]...) | |
} | |
return string(ns) | |
} | |
// Strlen strlen() | |
func Strlen(str string) int { | |
return len(str) | |
} | |
// MbStrlen mb_strlen() | |
func MbStrlen(str string) int { | |
return utf8.RuneCountInString(str) | |
} | |
// StrRepeat str_repeat() | |
func StrRepeat(input string, multiplier int) string { | |
return strings.Repeat(input, multiplier) | |
} | |
// Strstr strstr() | |
func Strstr(haystack string, needle string) string { | |
if needle == "" { | |
return "" | |
} | |
idx := strings.Index(haystack, needle) | |
if idx == -1 { | |
return "" | |
} | |
return haystack[idx+len([]byte(needle))-1:] | |
} | |
// Strtr strtr() | |
// | |
// If the parameter length is 1, type is: map[string]string | |
// Strtr("baab", map[string]string{"ab": "01"}) will return "ba01" | |
// If the parameter length is 2, type is: string, string | |
// Strtr("baab", "ab", "01") will return "1001", a => 0; b => 1. | |
func Strtr(haystack string, params ...interface{}) string { | |
ac := len(params) | |
if ac == 1 { | |
pairs := params[0].(map[string]string) | |
length := len(pairs) | |
if length == 0 { | |
return haystack | |
} | |
oldnew := make([]string, length*2) | |
for o, n := range pairs { | |
if o == "" { | |
return haystack | |
} | |
oldnew = append(oldnew, o, n) | |
} | |
return strings.NewReplacer(oldnew...).Replace(haystack) | |
} else if ac == 2 { | |
from := params[0].(string) | |
to := params[1].(string) | |
trlen, lt := len(from), len(to) | |
if trlen > lt { | |
trlen = lt | |
} | |
if trlen == 0 { | |
return haystack | |
} | |
str := make([]uint8, len(haystack)) | |
var xlat [256]uint8 | |
var i int | |
var j uint8 | |
if trlen == 1 { | |
for i = 0; i < len(haystack); i++ { | |
if haystack[i] == from[0] { | |
str[i] = to[0] | |
} else { | |
str[i] = haystack[i] | |
} | |
} | |
return string(str) | |
} | |
// trlen != 1 | |
for { | |
xlat[j] = j | |
if j++; j == 0 { | |
break | |
} | |
} | |
for i = 0; i < trlen; i++ { | |
xlat[from[i]] = to[i] | |
} | |
for i = 0; i < len(haystack); i++ { | |
str[i] = xlat[haystack[i]] | |
} | |
return string(str) | |
} | |
return haystack | |
} | |
// StrShuffle str_shuffle() | |
func StrShuffle(str string) string { | |
runes := []rune(str) | |
r := rand.New(rand.NewSource(time.Now().UnixNano())) | |
s := make([]rune, len(runes)) | |
for i, v := range r.Perm(len(runes)) { | |
s[i] = runes[v] | |
} | |
return string(s) | |
} | |
// Trim trim() | |
func Trim(str string, characterMask ...string) string { | |
if len(characterMask) == 0 { | |
return strings.TrimSpace(str) | |
} | |
return strings.Trim(str, characterMask[0]) | |
} | |
// Ltrim ltrim() | |
func Ltrim(str string, characterMask ...string) string { | |
if len(characterMask) == 0 { | |
return strings.TrimLeftFunc(str, unicode.IsSpace) | |
} | |
return strings.TrimLeft(str, characterMask[0]) | |
} | |
// Rtrim rtrim() | |
func Rtrim(str string, characterMask ...string) string { | |
if len(characterMask) == 0 { | |
return strings.TrimRightFunc(str, unicode.IsSpace) | |
} | |
return strings.TrimRight(str, characterMask[0]) | |
} | |
// Explode explode() | |
func Explode(delimiter, str string) []string { | |
return strings.Split(str, delimiter) | |
} | |
// Chr chr() | |
func Chr(ascii int) string { | |
return string(ascii) | |
} | |
// Ord ord() | |
func Ord(char string) int { | |
r, _ := utf8.DecodeRune([]byte(char)) | |
return int(r) | |
} | |
// Nl2br nl2br() | |
// \n\r, \r\n, \r, \n | |
func Nl2br(str string, isXhtml bool) string { | |
r, n, runes := '\r', '\n', []rune(str) | |
var br []byte | |
if isXhtml { | |
br = []byte("<br />") | |
} else { | |
br = []byte("<br>") | |
} | |
skip := false | |
length := len(runes) | |
var buf bytes.Buffer | |
for i, v := range runes { | |
if skip { | |
skip = false | |
continue | |
} | |
switch v { | |
case n, r: | |
if (i+1 < length) && (v == r && runes[i+1] == n) || (v == n && runes[i+1] == r) { | |
buf.Write(br) | |
skip = true | |
continue | |
} | |
buf.Write(br) | |
default: | |
buf.WriteRune(v) | |
} | |
} | |
return buf.String() | |
} | |
// JSONDecode json_decode() | |
func JSONDecode(data []byte, val interface{}) error { | |
return json.Unmarshal(data, val) | |
} | |
// JSONEncode json_encode() | |
func JSONEncode(val interface{}) ([]byte, error) { | |
return json.Marshal(val) | |
} | |
// Addslashes addslashes() | |
func Addslashes(str string) string { | |
var buf bytes.Buffer | |
for _, char := range str { | |
switch char { | |
case '\'', '"', '\\': | |
buf.WriteRune('\\') | |
} | |
buf.WriteRune(char) | |
} | |
return buf.String() | |
} | |
// Stripslashes stripslashes() | |
func Stripslashes(str string) string { | |
var buf bytes.Buffer | |
l, skip := len(str), false | |
for i, char := range str { | |
if skip { | |
skip = false | |
} else if char == '\\' { | |
if i+1 < l && str[i+1] == '\\' { | |
skip = true | |
} | |
continue | |
} | |
buf.WriteRune(char) | |
} | |
return buf.String() | |
} | |
// Quotemeta quotemeta() | |
func Quotemeta(str string) string { | |
var buf bytes.Buffer | |
for _, char := range str { | |
switch char { | |
case '.', '+', '\\', '(', '$', ')', '[', '^', ']', '*', '?': | |
buf.WriteRune('\\') | |
} | |
buf.WriteRune(char) | |
} | |
return buf.String() | |
} | |
// Htmlentities htmlentities() | |
func Htmlentities(str string) string { | |
return html.EscapeString(str) | |
} | |
// HTMLEntityDecode html_entity_decode() | |
func HTMLEntityDecode(str string) string { | |
return html.UnescapeString(str) | |
} | |
// Md5 md5() | |
func Md5(str string) string { | |
hash := md5.New() | |
hash.Write([]byte(str)) | |
return hex.EncodeToString(hash.Sum(nil)) | |
} | |
// Md5File md5_file() | |
func Md5File(path string) (string, error) { | |
data, err := ioutil.ReadFile(path) | |
if err != nil { | |
return "", err | |
} | |
hash := md5.New() | |
hash.Write([]byte(data)) | |
return hex.EncodeToString(hash.Sum(nil)), nil | |
} | |
// Sha1 sha1() | |
func Sha1(str string) string { | |
hash := sha1.New() | |
hash.Write([]byte(str)) | |
return hex.EncodeToString(hash.Sum(nil)) | |
} | |
// Sha1File sha1_file() | |
func Sha1File(path string) (string, error) { | |
data, err := ioutil.ReadFile(path) | |
if err != nil { | |
return "", err | |
} | |
hash := sha1.New() | |
hash.Write([]byte(data)) | |
return hex.EncodeToString(hash.Sum(nil)), nil | |
} | |
// Crc32 crc32() | |
func Crc32(str string) uint32 { | |
return crc32.ChecksumIEEE([]byte(str)) | |
} | |
// Levenshtein levenshtein() | |
// costIns: Defines the cost of insertion. | |
// costRep: Defines the cost of replacement. | |
// costDel: Defines the cost of deletion. | |
func Levenshtein(str1, str2 string, costIns, costRep, costDel int) int { | |
var maxLen = 255 | |
l1 := len(str1) | |
l2 := len(str2) | |
if l1 == 0 { | |
return l2 * costIns | |
} | |
if l2 == 0 { | |
return l1 * costDel | |
} | |
if l1 > maxLen || l2 > maxLen { | |
return -1 | |
} | |
p1 := make([]int, l2+1) | |
p2 := make([]int, l2+1) | |
var c0, c1, c2 int | |
var i1, i2 int | |
for i2 := 0; i2 <= l2; i2++ { | |
p1[i2] = i2 * costIns | |
} | |
for i1 = 0; i1 < l1; i1++ { | |
p2[0] = p1[0] + costDel | |
for i2 = 0; i2 < l2; i2++ { | |
if str1[i1] == str2[i2] { | |
c0 = p1[i2] | |
} else { | |
c0 = p1[i2] + costRep | |
} | |
c1 = p1[i2+1] + costDel | |
if c1 < c0 { | |
c0 = c1 | |
} | |
c2 = p2[i2] + costIns | |
if c2 < c0 { | |
c0 = c2 | |
} | |
p2[i2+1] = c0 | |
} | |
tmp := p1 | |
p1 = p2 | |
p2 = tmp | |
} | |
c0 = p1[l2] | |
return c0 | |
} | |
// SimilarText similar_text() | |
func SimilarText(first, second string, percent *float64) int { | |
var similarText func(string, string, int, int) int | |
similarText = func(str1, str2 string, len1, len2 int) int { | |
var sum, max int | |
pos1, pos2 := 0, 0 | |
// Find the longest segment of the same section in two strings | |
for i := 0; i < len1; i++ { | |
for j := 0; j < len2; j++ { | |
for l := 0; (i+l < len1) && (j+l < len2) && (str1[i+l] == str2[j+l]); l++ { | |
if l+1 > max { | |
max = l + 1 | |
pos1 = i | |
pos2 = j | |
} | |
} | |
} | |
} | |
if sum = max; sum > 0 { | |
if pos1 > 0 && pos2 > 0 { | |
sum += similarText(str1, str2, pos1, pos2) | |
} | |
if (pos1+max < len1) && (pos2+max < len2) { | |
s1 := []byte(str1) | |
s2 := []byte(str2) | |
sum += similarText(string(s1[pos1+max:]), string(s2[pos2+max:]), len1-pos1-max, len2-pos2-max) | |
} | |
} | |
return sum | |
} | |
l1, l2 := len(first), len(second) | |
if l1+l2 == 0 { | |
return 0 | |
} | |
sim := similarText(first, second, l1, l2) | |
if percent != nil { | |
*percent = float64(sim*200) / float64(l1+l2) | |
} | |
return sim | |
} | |
// Soundex soundex() | |
// Calculate the soundex key of a string. | |
func Soundex(str string) string { | |
if str == "" { | |
panic("str: cannot be an empty string") | |
} | |
table := [26]rune{ | |
// A, B, C, D | |
'0', '1', '2', '3', | |
// E, F, G | |
'0', '1', '2', | |
// H | |
'0', | |
// I, J, K, L, M, N | |
'0', '2', '2', '4', '5', '5', | |
// O, P, Q, R, S, T | |
'0', '1', '2', '6', '2', '3', | |
// U, V | |
'0', '1', | |
// W, X | |
'0', '2', | |
// Y, Z | |
'0', '2', | |
} | |
last, code, small := -1, 0, 0 | |
sd := make([]rune, 4) | |
// build soundex string | |
for i := 0; i < len(str) && small < 4; i++ { | |
// ToUpper | |
char := str[i] | |
if char < '\u007F' && 'a' <= char && char <= 'z' { | |
code = int(char - 'a' + 'A') | |
} else { | |
code = int(char) | |
} | |
if code >= 'A' && code <= 'Z' { | |
if small == 0 { | |
sd[small] = rune(code) | |
small++ | |
last = int(table[code-'A']) | |
} else { | |
code = int(table[code-'A']) | |
if code != last { | |
if code != 0 { | |
sd[small] = rune(code) | |
small++ | |
} | |
last = code | |
} | |
} | |
} | |
} | |
// pad with "0" | |
for ; small < 4; small++ { | |
sd[small] = '0' | |
} | |
return string(sd) | |
} | |
//////////// URL Functions //////////// | |
// ParseURL parse_url() | |
// Parse a URL and return its components | |
// -1: all; 1: scheme; 2: host; 4: port; 8: user; 16: pass; 32: path; 64: query; 128: fragment | |
func ParseURL(str string, component int) (map[string]string, error) { | |
u, err := url.Parse(str) | |
if err != nil { | |
return nil, err | |
} | |
if component == -1 { | |
component = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | |
} | |
var components = make(map[string]string) | |
if (component & 1) == 1 { | |
components["scheme"] = u.Scheme | |
} | |
if (component & 2) == 2 { | |
components["host"] = u.Hostname() | |
} | |
if (component & 4) == 4 { | |
components["port"] = u.Port() | |
} | |
if (component & 8) == 8 { | |
components["user"] = u.User.Username() | |
} | |
if (component & 16) == 16 { | |
components["pass"], _ = u.User.Password() | |
} | |
if (component & 32) == 32 { | |
components["path"] = u.Path | |
} | |
if (component & 64) == 64 { | |
components["query"] = u.RawQuery | |
} | |
if (component & 128) == 128 { | |
components["fragment"] = u.Fragment | |
} | |
return components, nil | |
} | |
// URLEncode urlencode() | |
func URLEncode(str string) string { | |
return url.QueryEscape(str) | |
} | |
// URLDecode urldecode() | |
func URLDecode(str string) (string, error) { | |
return url.QueryUnescape(str) | |
} | |
// Rawurlencode rawurlencode() | |
func Rawurlencode(str string) string { | |
return strings.Replace(url.QueryEscape(str), "+", "%20", -1) | |
} | |
// Rawurldecode rawurldecode() | |
func Rawurldecode(str string) (string, error) { | |
return url.QueryUnescape(strings.Replace(str, "%20", "+", -1)) | |
} | |
// HTTPBuildQuery http_build_query() | |
func HTTPBuildQuery(queryData url.Values) string { | |
return queryData.Encode() | |
} | |
// Base64Encode base64_encode() | |
func Base64Encode(str string) string { | |
return base64.StdEncoding.EncodeToString([]byte(str)) | |
} | |
// Base64Decode base64_decode() | |
func Base64Decode(str string) (string, error) { | |
switch len(str) % 4 { | |
case 2: | |
str += "==" | |
case 3: | |
str += "=" | |
} | |
data, err := base64.StdEncoding.DecodeString(str) | |
if err != nil { | |
return "", err | |
} | |
return string(data), nil | |
} | |
//////////// Array(Slice/Map) Functions //////////// | |
// ArrayFill array_fill() | |
func ArrayFill(startIndex int, num uint, value interface{}) map[int]interface{} { | |
m := make(map[int]interface{}) | |
var i uint | |
for i = 0; i < num; i++ { | |
m[startIndex] = value | |
startIndex++ | |
} | |
return m | |
} | |
// ArrayFlip array_flip() | |
func ArrayFlip(m map[interface{}]interface{}) map[interface{}]interface{} { | |
n := make(map[interface{}]interface{}) | |
for i, v := range m { | |
n[v] = i | |
} | |
return n | |
} | |
// ArrayKeys array_keys() | |
func ArrayKeys(elements map[interface{}]interface{}) []interface{} { | |
i, keys := 0, make([]interface{}, len(elements)) | |
for key := range elements { | |
keys[i] = key | |
i++ | |
} | |
return keys | |
} | |
// ArrayValues array_values() | |
func ArrayValues(elements map[interface{}]interface{}) []interface{} { | |
i, vals := 0, make([]interface{}, len(elements)) | |
for _, val := range elements { | |
vals[i] = val | |
i++ | |
} | |
return vals | |
} | |
// ArrayMerge array_merge() | |
func ArrayMerge(ss ...[]interface{}) []interface{} { | |
n := 0 | |
for _, v := range ss { | |
n += len(v) | |
} | |
s := make([]interface{}, 0, n) | |
for _, v := range ss { | |
s = append(s, v...) | |
} | |
return s | |
} | |
// ArrayChunk array_chunk() | |
func ArrayChunk(s []interface{}, size int) [][]interface{} { | |
if size < 1 { | |
panic("size: cannot be less than 1") | |
} | |
length := len(s) | |
chunks := int(math.Ceil(float64(length) / float64(size))) | |
var n [][]interface{} | |
for i, end := 0, 0; chunks > 0; chunks-- { | |
end = (i + 1) * size | |
if end > length { | |
end = length | |
} | |
n = append(n, s[i*size:end]) | |
i++ | |
} | |
return n | |
} | |
// ArrayPad array_pad() | |
func ArrayPad(s []interface{}, size int, val interface{}) []interface{} { | |
if size == 0 || (size > 0 && size < len(s)) || (size < 0 && size > -len(s)) { | |
return s | |
} | |
n := size | |
if size < 0 { | |
n = -size | |
} | |
n -= len(s) | |
tmp := make([]interface{}, n) | |
for i := 0; i < n; i++ { | |
tmp[i] = val | |
} | |
if size > 0 { | |
return append(s, tmp...) | |
} | |
return append(tmp, s...) | |
} | |
// ArraySlice array_slice() | |
func ArraySlice(s []interface{}, offset, length uint) []interface{} { | |
if offset > uint(len(s)) { | |
panic("offset: the offset is less than the length of s") | |
} | |
end := offset + length | |
if end < uint(len(s)) { | |
return s[offset:end] | |
} | |
return s[offset:] | |
} | |
// ArrayRand array_rand() | |
func ArrayRand(elements []interface{}) []interface{} { | |
r := rand.New(rand.NewSource(time.Now().UnixNano())) | |
n := make([]interface{}, len(elements)) | |
for i, v := range r.Perm(len(elements)) { | |
n[i] = elements[v] | |
} | |
return n | |
} | |
// ArrayColumn array_column() | |
func ArrayColumn(input map[string]map[string]interface{}, columnKey string) []interface{} { | |
columns := make([]interface{}, 0, len(input)) | |
for _, val := range input { | |
if v, ok := val[columnKey]; ok { | |
columns = append(columns, v) | |
} | |
} | |
return columns | |
} | |
// ArrayPush array_push() | |
// Push one or more elements onto the end of slice | |
func ArrayPush(s *[]interface{}, elements ...interface{}) int { | |
*s = append(*s, elements...) | |
return len(*s) | |
} | |
// ArrayPop array_pop() | |
// Pop the element off the end of slice | |
func ArrayPop(s *[]interface{}) interface{} { | |
if len(*s) == 0 { | |
return nil | |
} | |
ep := len(*s) - 1 | |
e := (*s)[ep] | |
*s = (*s)[:ep] | |
return e | |
} | |
// ArrayUnshift array_unshift() | |
// Prepend one or more elements to the beginning of a slice | |
func ArrayUnshift(s *[]interface{}, elements ...interface{}) int { | |
*s = append(elements, *s...) | |
return len(*s) | |
} | |
// ArrayShift array_shift() | |
// Shift an element off the beginning of slice | |
func ArrayShift(s *[]interface{}) interface{} { | |
if len(*s) == 0 { | |
return nil | |
} | |
f := (*s)[0] | |
*s = (*s)[1:] | |
return f | |
} | |
// ArrayKeyExists array_key_exists() | |
func ArrayKeyExists(key interface{}, m map[interface{}]interface{}) bool { | |
_, ok := m[key] | |
return ok | |
} | |
// ArrayCombine array_combine() | |
func ArrayCombine(s1, s2 []interface{}) map[interface{}]interface{} { | |
if len(s1) != len(s2) { | |
panic("the number of elements for each slice isn't equal") | |
} | |
m := make(map[interface{}]interface{}, len(s1)) | |
for i, v := range s1 { | |
m[v] = s2[i] | |
} | |
return m | |
} | |
// ArrayReverse array_reverse() | |
func ArrayReverse(s []interface{}) []interface{} { | |
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { | |
s[i], s[j] = s[j], s[i] | |
} | |
return s | |
} | |
// Implode implode() | |
func Implode(glue string, pieces []string) string { | |
var buf bytes.Buffer | |
l := len(pieces) | |
for _, str := range pieces { | |
buf.WriteString(str) | |
if l--; l > 0 { | |
buf.WriteString(glue) | |
} | |
} | |
return buf.String() | |
} | |
// InArray in_array() | |
// haystack supported types: slice, array or map | |
func InArray(needle interface{}, haystack interface{}) bool { | |
val := reflect.ValueOf(haystack) | |
switch val.Kind() { | |
case reflect.Slice, reflect.Array: | |
for i := 0; i < val.Len(); i++ { | |
if reflect.DeepEqual(needle, val.Index(i).Interface()) { | |
return true | |
} | |
} | |
case reflect.Map: | |
for _, k := range val.MapKeys() { | |
if reflect.DeepEqual(needle, val.MapIndex(k).Interface()) { | |
return true | |
} | |
} | |
default: | |
panic("haystack: haystack type muset be slice, array or map") | |
} | |
return false | |
} | |
//////////// Mathematical Functions //////////// | |
// Abs abs() | |
func Abs(number float64) float64 { | |
return math.Abs(number) | |
} | |
// Rand rand() | |
// Range: [0, 2147483647] | |
func Rand(min, max int) int { | |
if min > max { | |
panic("min: min cannot be greater than max") | |
} | |
// PHP: getrandmax() | |
if int31 := 1<<31 - 1; max > int31 { | |
panic("max: max can not be greater than " + strconv.Itoa(int31)) | |
} | |
if min == max { | |
return min | |
} | |
r := rand.New(rand.NewSource(time.Now().UnixNano())) | |
return r.Intn(max+1-min) + min | |
} | |
// Round round() | |
func Round(value float64) float64 { | |
return math.Floor(value + 0.5) | |
} | |
// Floor floor() | |
func Floor(value float64) float64 { | |
return math.Floor(value) | |
} | |
// Ceil ceil() | |
func Ceil(value float64) float64 { | |
return math.Ceil(value) | |
} | |
// Pi pi() | |
func Pi() float64 { | |
return math.Pi | |
} | |
// Max max() | |
func Max(nums ...float64) float64 { | |
if len(nums) < 2 { | |
panic("nums: the nums length is less than 2") | |
} | |
max := nums[0] | |
for i := 1; i < len(nums); i++ { | |
max = math.Max(max, nums[i]) | |
} | |
return max | |
} | |
// Min min() | |
func Min(nums ...float64) float64 { | |
if len(nums) < 2 { | |
panic("nums: the nums length is less than 2") | |
} | |
min := nums[0] | |
for i := 1; i < len(nums); i++ { | |
min = math.Min(min, nums[i]) | |
} | |
return min | |
} | |
// Decbin decbin() | |
func Decbin(number int64) string { | |
return strconv.FormatInt(number, 2) | |
} | |
// Bindec bindec() | |
func Bindec(str string) (string, error) { | |
i, err := strconv.ParseInt(str, 2, 0) | |
if err != nil { | |
return "", err | |
} | |
return strconv.FormatInt(i, 10), nil | |
} | |
// Hex2bin hex2bin() | |
func Hex2bin(data string) (string, error) { | |
i, err := strconv.ParseInt(data, 16, 0) | |
if err != nil { | |
return "", err | |
} | |
return strconv.FormatInt(i, 2), nil | |
} | |
// Bin2hex bin2hex() | |
func Bin2hex(str string) (string, error) { | |
i, err := strconv.ParseInt(str, 2, 0) | |
if err != nil { | |
return "", err | |
} | |
return strconv.FormatInt(i, 16), nil | |
} | |
// Dechex dechex() | |
func Dechex(number int64) string { | |
return strconv.FormatInt(number, 16) | |
} | |
// Hexdec hexdec() | |
func Hexdec(str string) (int64, error) { | |
return strconv.ParseInt(str, 16, 0) | |
} | |
// Decoct decoct() | |
func Decoct(number int64) string { | |
return strconv.FormatInt(number, 8) | |
} | |
// Octdec Octdec() | |
func Octdec(str string) (int64, error) { | |
return strconv.ParseInt(str, 8, 0) | |
} | |
// BaseConvert base_convert() | |
func BaseConvert(number string, frombase, tobase int) (string, error) { | |
i, err := strconv.ParseInt(number, frombase, 0) | |
if err != nil { | |
return "", err | |
} | |
return strconv.FormatInt(i, tobase), nil | |
} | |
// IsNan is_nan() | |
func IsNan(val float64) bool { | |
return math.IsNaN(val) | |
} | |
//////////// Directory/Filesystem Functions //////////// | |
// Stat stat() | |
func Stat(filename string) (os.FileInfo, error) { | |
return os.Stat(filename) | |
} | |
// Pathinfo pathinfo() | |
// -1: all; 1: dirname; 2: basename; 4: extension; 8: filename | |
// Usage: | |
// Pathinfo("/home/go/path/src/php2go/php2go.go", 1|2|4|8) | |
func Pathinfo(path string, options int) map[string]string { | |
if options == -1 { | |
options = 1 | 2 | 4 | 8 | |
} | |
info := make(map[string]string) | |
if (options & 1) == 1 { | |
info["dirname"] = filepath.Dir(path) | |
} | |
if (options & 2) == 2 { | |
info["basename"] = filepath.Base(path) | |
} | |
if ((options & 4) == 4) || ((options & 8) == 8) { | |
basename := "" | |
if (options & 2) == 2 { | |
basename, _ = info["basename"] | |
} else { | |
basename = filepath.Base(path) | |
} | |
p := strings.LastIndex(basename, ".") | |
filename, extension := "", "" | |
if p > 0 { | |
filename, extension = basename[:p], basename[p+1:] | |
} else if p == -1 { | |
filename = basename | |
} else if p == 0 { | |
extension = basename[p+1:] | |
} | |
if (options & 4) == 4 { | |
info["extension"] = extension | |
} | |
if (options & 8) == 8 { | |
info["filename"] = filename | |
} | |
} | |
return info | |
} | |
// FileExists file_exists() | |
func FileExists(filename string) bool { | |
_, err := os.Stat(filename) | |
if err != nil && os.IsNotExist(err) { | |
return false | |
} | |
return true | |
} | |
// IsFile is_file() | |
func IsFile(filename string) bool { | |
_, err := os.Stat(filename) | |
if err != nil && os.IsNotExist(err) { | |
return false | |
} | |
return true | |
} | |
// IsDir is_dir() | |
func IsDir(filename string) (bool, error) { | |
fd, err := os.Stat(filename) | |
if err != nil { | |
return false, err | |
} | |
fm := fd.Mode() | |
return fm.IsDir(), nil | |
} | |
// FileSize filesize() | |
func FileSize(filename string) (int64, error) { | |
info, err := os.Stat(filename) | |
if err != nil && os.IsNotExist(err) { | |
return 0, err | |
} | |
return info.Size(), nil | |
} | |
// FilePutContents file_put_contents() | |
func FilePutContents(filename string, data string, mode os.FileMode) error { | |
return ioutil.WriteFile(filename, []byte(data), mode) | |
} | |
// FileGetContents file_get_contents() | |
func FileGetContents(filename string) (string, error) { | |
data, err := ioutil.ReadFile(filename) | |
return string(data), err | |
} | |
// Unlink unlink() | |
func Unlink(filename string) error { | |
return os.Remove(filename) | |
} | |
// Delete delete() | |
func Delete(filename string) error { | |
return os.Remove(filename) | |
} | |
// Copy copy() | |
func Copy(source, dest string) (bool, error) { | |
fd1, err := os.Open(source) | |
if err != nil { | |
return false, err | |
} | |
defer fd1.Close() | |
fd2, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE, 0644) | |
if err != nil { | |
return false, err | |
} | |
defer fd2.Close() | |
_, e := io.Copy(fd2, fd1) | |
if e != nil { | |
return false, e | |
} | |
return true, nil | |
} | |
// IsReadable is_readable() | |
func IsReadable(filename string) bool { | |
_, err := syscall.Open(filename, syscall.O_RDONLY, 0) | |
if err != nil { | |
return false | |
} | |
return true | |
} | |
// IsWriteable is_writeable() | |
func IsWriteable(filename string) bool { | |
_, err := syscall.Open(filename, syscall.O_WRONLY, 0) | |
if err != nil { | |
return false | |
} | |
return true | |
} | |
// Rename rename() | |
func Rename(oldname, newname string) error { | |
return os.Rename(oldname, newname) | |
} | |
// Touch touch() | |
func Touch(filename string) (bool, error) { | |
fd, err := os.OpenFile(filename, os.O_RDONLY|os.O_CREATE, 0666) | |
if err != nil { | |
return false, err | |
} | |
fd.Close() | |
return true, nil | |
} | |
// Mkdir mkdir() | |
func Mkdir(filename string, mode os.FileMode) error { | |
return os.Mkdir(filename, mode) | |
} | |
// Getcwd getcwd() | |
func Getcwd() (string, error) { | |
dir, err := os.Getwd() | |
return dir, err | |
} | |
// Realpath realpath() | |
func Realpath(path string) (string, error) { | |
return filepath.Abs(path) | |
} | |
// Basename basename() | |
func Basename(path string) string { | |
return filepath.Base(path) | |
} | |
// Chmod chmod() | |
func Chmod(filename string, mode os.FileMode) bool { | |
return os.Chmod(filename, mode) == nil | |
} | |
// Chown chown() | |
func Chown(filename string, uid, gid int) bool { | |
return os.Chown(filename, uid, gid) == nil | |
} | |
// Fclose fclose() | |
func Fclose(handle *os.File) error { | |
return handle.Close() | |
} | |
// Filemtime filemtime() | |
func Filemtime(filename string) (int64, error) { | |
fd, err := os.Open(filename) | |
if err != nil { | |
return 0, err | |
} | |
defer fd.Close() | |
fileinfo, err := fd.Stat() | |
if err != nil { | |
return 0, err | |
} | |
return fileinfo.ModTime().Unix(), nil | |
} | |
// Fgetcsv fgetcsv() | |
func Fgetcsv(handle *os.File, length int, delimiter rune) ([][]string, error) { | |
reader := csv.NewReader(handle) | |
reader.Comma = delimiter | |
// TODO length limit | |
return reader.ReadAll() | |
} | |
// Glob glob() | |
func Glob(pattern string) ([]string, error) { | |
return filepath.Glob(pattern) | |
} | |
//////////// Variable handling Functions //////////// | |
// Empty empty() | |
func Empty(val interface{}) bool { | |
if val == nil { | |
return true | |
} | |
v := reflect.ValueOf(val) | |
switch v.Kind() { | |
case reflect.String, reflect.Array: | |
return v.Len() == 0 | |
case reflect.Map, reflect.Slice: | |
return v.Len() == 0 || v.IsNil() | |
case reflect.Bool: | |
return !v.Bool() | |
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | |
return v.Int() == 0 | |
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | |
return v.Uint() == 0 | |
case reflect.Float32, reflect.Float64: | |
return v.Float() == 0 | |
case reflect.Interface, reflect.Ptr: | |
return v.IsNil() | |
} | |
return reflect.DeepEqual(val, reflect.Zero(v.Type()).Interface()) | |
} | |
// IsNumeric is_numeric() | |
// Numeric strings consist of optional sign, any number of digits, optional decimal part and optional exponential part. | |
// Thus +0123.45e6 is a valid numeric value. | |
// In PHP hexadecimal (e.g. 0xf4c3b00c) is not supported, but IsNumeric is supported. | |
func IsNumeric(val interface{}) bool { | |
switch val.(type) { | |
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: | |
return true | |
case float32, float64, complex64, complex128: | |
return true | |
case string: | |
str := val.(string) | |
if str == "" { | |
return false | |
} | |
// Trim any whitespace | |
str = strings.TrimSpace(str) | |
if str[0] == '-' || str[0] == '+' { | |
if len(str) == 1 { | |
return false | |
} | |
str = str[1:] | |
} | |
// hex | |
if len(str) > 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X') { | |
for _, h := range str[2:] { | |
if !((h >= '0' && h <= '9') || (h >= 'a' && h <= 'f') || (h >= 'A' && h <= 'F')) { | |
return false | |
} | |
} | |
return true | |
} | |
// 0-9, Point, Scientific | |
p, s, l := 0, 0, len(str) | |
for i, v := range str { | |
if v == '.' { // Point | |
if p > 0 || s > 0 || i+1 == l { | |
return false | |
} | |
p = i | |
} else if v == 'e' || v == 'E' { // Scientific | |
if i == 0 || s > 0 || i+1 == l { | |
return false | |
} | |
s = i | |
} else if v < '0' || v > '9' { | |
return false | |
} | |
} | |
return true | |
} | |
return false | |
} | |
//////////// Program execution Functions //////////// | |
// Exec exec() | |
// returnVar, 0: succ; 1: fail | |
// Return the last line from the result of the command. | |
// command format eg: | |
// "ls -a" | |
// "/bin/bash -c \"ls -a\"" | |
func Exec(command string, output *[]string, returnVar *int) string { | |
q := rune(0) | |
parts := strings.FieldsFunc(command, func(r rune) bool { | |
switch { | |
case r == q: | |
q = rune(0) | |
return false | |
case q != rune(0): | |
return false | |
case unicode.In(r, unicode.Quotation_Mark): | |
q = r | |
return false | |
default: | |
return unicode.IsSpace(r) | |
} | |
}) | |
// remove the " and ' on both sides | |
for i, v := range parts { | |
f, l := v[0], len(v) | |
if l >= 2 && (f == '"' || f == '\'') { | |
parts[i] = v[1 : l-1] | |
} | |
} | |
cmd := exec.Command(parts[0], parts[1:]...) | |
out, err := cmd.CombinedOutput() | |
if err != nil { | |
*returnVar = 1 | |
return "" | |
} | |
*returnVar = 0 | |
*output = strings.Split(strings.TrimRight(string(out), "\n"), "\n") | |
if l := len(*output); l > 0 { | |
return (*output)[l-1] | |
} | |
return "" | |
} | |
// System system() | |
// returnVar, 0: succ; 1: fail | |
// Returns the last line of the command output on success, and "" on failure. | |
func System(command string, returnVar *int) string { | |
*returnVar = 0 | |
var stdBuf bytes.Buffer | |
var err, err1, err2, err3 error | |
// split command | |
q := rune(0) | |
parts := strings.FieldsFunc(command, func(r rune) bool { | |
switch { | |
case r == q: | |
q = rune(0) | |
return false | |
case q != rune(0): | |
return false | |
case unicode.In(r, unicode.Quotation_Mark): | |
q = r | |
return false | |
default: | |
return unicode.IsSpace(r) | |
} | |
}) | |
// remove the " and ' on both sides | |
for i, v := range parts { | |
f, l := v[0], len(v) | |
if l >= 2 && (f == '"' || f == '\'') { | |
parts[i] = v[1 : l-1] | |
} | |
} | |
cmd := exec.Command(parts[0], parts[1:]...) | |
stdoutIn, _ := cmd.StdoutPipe() | |
stderrIn, _ := cmd.StderrPipe() | |
stdout := io.MultiWriter(os.Stdout, &stdBuf) | |
stderr := io.MultiWriter(os.Stderr, &stdBuf) | |
err = cmd.Start() | |
if err != nil { | |
*returnVar = 1 | |
return "" | |
} | |
go func() { | |
_, err1 = io.Copy(stdout, stdoutIn) | |
}() | |
go func() { | |
_, err2 = io.Copy(stderr, stderrIn) | |
}() | |
err3 = cmd.Wait() | |
if err1 != nil || err2 != nil || err3 != nil { | |
if err1 != nil { | |
fmt.Println(err1) | |
} | |
if err2 != nil { | |
fmt.Println(err2) | |
} | |
if err3 != nil { | |
fmt.Println(err3) | |
} | |
*returnVar = 1 | |
return "" | |
} | |
if output := strings.TrimRight(stdBuf.String(), "\n"); output != "" { | |
pos := strings.LastIndex(output, "\n") | |
if pos == -1 { | |
return output | |
} | |
return output[pos+1:] | |
} | |
return "" | |
} | |
// Passthru passthru() | |
// returnVar, 0: succ; 1: fail | |
func Passthru(command string, returnVar *int) { | |
q := rune(0) | |
parts := strings.FieldsFunc(command, func(r rune) bool { | |
switch { | |
case r == q: | |
q = rune(0) | |
return false | |
case q != rune(0): | |
return false | |
case unicode.In(r, unicode.Quotation_Mark): | |
q = r | |
return false | |
default: | |
return unicode.IsSpace(r) | |
} | |
}) | |
// remove the " and ' on both sides | |
for i, v := range parts { | |
f, l := v[0], len(v) | |
if l >= 2 && (f == '"' || f == '\'') { | |
parts[i] = v[1 : l-1] | |
} | |
} | |
cmd := exec.Command(parts[0], parts[1:]...) | |
cmd.Stdout = os.Stdout | |
cmd.Stderr = os.Stderr | |
err := cmd.Run() | |
if err != nil { | |
*returnVar = 1 | |
fmt.Println(err) | |
} else { | |
*returnVar = 0 | |
} | |
} | |
//////////// Network Functions //////////// | |
// Gethostname gethostname() | |
func Gethostname() (string, error) { | |
return os.Hostname() | |
} | |
// Gethostbyname gethostbyname() | |
// Get the IPv4 address corresponding to a given Internet host name | |
func Gethostbyname(hostname string) (string, error) { | |
ips, err := net.LookupIP(hostname) | |
if ips != nil { | |
for _, v := range ips { | |
if v.To4() != nil { | |
return v.String(), nil | |
} | |
} | |
return "", nil | |
} | |
return "", err | |
} | |
// Gethostbynamel gethostbynamel() | |
// Get a list of IPv4 addresses corresponding to a given Internet host name | |
func Gethostbynamel(hostname string) ([]string, error) { | |
ips, err := net.LookupIP(hostname) | |
if ips != nil { | |
var ipstrs []string | |
for _, v := range ips { | |
if v.To4() != nil { | |
ipstrs = append(ipstrs, v.String()) | |
} | |
} | |
return ipstrs, nil | |
} | |
return nil, err | |
} | |
// Gethostbyaddr gethostbyaddr() | |
// Get the Internet host name corresponding to a given IP address | |
func Gethostbyaddr(ipAddress string) (string, error) { | |
names, err := net.LookupAddr(ipAddress) | |
if names != nil { | |
return strings.TrimRight(names[0], "."), nil | |
} | |
return "", err | |
} | |
// IP2long ip2long() | |
// IPv4 | |
func IP2long(ipAddress string) uint32 { | |
ip := net.ParseIP(ipAddress) | |
if ip == nil { | |
return 0 | |
} | |
return binary.BigEndian.Uint32(ip.To4()) | |
} | |
// Long2ip long2ip() | |
// IPv4 | |
func Long2ip(properAddress uint32) string { | |
ipByte := make([]byte, 4) | |
binary.BigEndian.PutUint32(ipByte, properAddress) | |
ip := net.IP(ipByte) | |
return ip.String() | |
} | |
//////////// Misc. Functions //////////// | |
// Echo echo | |
func Echo(args ...interface{}) { | |
fmt.Print(args...) | |
} | |
// Uniqid uniqid() | |
func Uniqid(prefix string) string { | |
now := time.Now() | |
return fmt.Sprintf("%s%08x%05x", prefix, now.Unix(), now.UnixNano()%0x100000) | |
} | |
// Exit exit() | |
func Exit(status int) { | |
os.Exit(status) | |
} | |
// Die die() | |
func Die(status int) { | |
os.Exit(status) | |
} | |
// Getenv getenv() | |
func Getenv(varname string) string { | |
return os.Getenv(varname) | |
} | |
// Putenv putenv() | |
// The setting, like "FOO=BAR" | |
func Putenv(setting string) error { | |
s := strings.Split(setting, "=") | |
if len(s) != 2 { | |
panic("setting: invalid") | |
} | |
return os.Setenv(s[0], s[1]) | |
} | |
// MemoryGetUsage memory_get_usage() | |
// return in bytes | |
func MemoryGetUsage(realUsage bool) uint64 { | |
stat := new(runtime.MemStats) | |
runtime.ReadMemStats(stat) | |
return stat.Alloc | |
} | |
// VersionCompare version_compare() | |
// The possible operators are: <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne respectively. | |
// special version strings these are handled in the following order, | |
// (any string not found) < dev < alpha = a < beta = b < RC = rc < # < pl = p | |
// Usage: | |
// VersionCompare("1.2.3-alpha", "1.2.3RC7", '>=') | |
// VersionCompare("1.2.3-beta", "1.2.3pl", 'lt') | |
// VersionCompare("1.1_dev", "1.2any", 'eq') | |
func VersionCompare(version1, version2, operator string) bool { | |
var vcompare func(string, string) int | |
var canonicalize func(string) string | |
var special func(string, string) int | |
// version compare | |
vcompare = func(origV1, origV2 string) int { | |
if origV1 == "" || origV2 == "" { | |
if origV1 == "" && origV2 == "" { | |
return 0 | |
} | |
if origV1 == "" { | |
return -1 | |
} | |
return 1 | |
} | |
ver1, ver2, compare := "", "", 0 | |
if origV1[0] == '#' { | |
ver1 = origV1 | |
} else { | |
ver1 = canonicalize(origV1) | |
} | |
if origV2[0] == '#' { | |
ver2 = origV2 | |
} else { | |
ver2 = canonicalize(origV2) | |
} | |
n1, n2 := 0, 0 | |
for { | |
p1, p2 := "", "" | |
n1 = strings.IndexByte(ver1, '.') | |
if n1 == -1 { | |
p1, ver1 = ver1[:], "" | |
} else { | |
p1, ver1 = ver1[:n1], ver1[n1+1:] | |
} | |
n2 = strings.IndexByte(ver2, '.') | |
if n2 == -1 { | |
p2, ver2 = ver2, "" | |
} else { | |
p2, ver2 = ver2[:n2], ver2[n2+1:] | |
} | |
if (p1[0] >= '0' && p1[0] <= '9') && (p2[0] >= '0' && p2[0] <= '9') { // all is digit | |
l1, _ := strconv.Atoi(p1) | |
l2, _ := strconv.Atoi(p2) | |
if l1 > l2 { | |
compare = 1 | |
} else if l1 == l2 { | |
compare = 0 | |
} else { | |
compare = -1 | |
} | |
} else if !(p1[0] >= '0' && p1[0] <= '9') && !(p2[0] >= '0' && p2[0] <= '9') { // all digit | |
compare = special(p1, p2) | |
} else { // part is digit | |
if p1[0] >= '0' && p1[0] <= '9' { // is digit | |
compare = special("#N#", p2) | |
} else { | |
compare = special(p1, "#N#") | |
} | |
} | |
if compare != 0 || n1 == -1 || n2 == -1 { | |
break | |
} | |
} | |
if compare == 0 { | |
if ver1 != "" { | |
if ver1[0] >= '0' && ver1[0] <= '9' { | |
compare = 1 | |
} else { | |
compare = vcompare(ver1, "#N#") | |
} | |
} else if ver2 != "" { | |
if ver2[0] >= '0' && ver2[0] <= '9' { | |
compare = -1 | |
} else { | |
compare = vcompare("#N#", ver2) | |
} | |
} | |
} | |
return compare | |
} | |
// canonicalize | |
canonicalize = func(version string) string { | |
ver := []byte(version) | |
l := len(ver) | |
if l == 0 { | |
return "" | |
} | |
var buf = make([]byte, l*2) | |
j := 0 | |
for i, v := range ver { | |
next := uint8(0) | |
if i+1 < l { // Have the next one | |
next = ver[i+1] | |
} | |
if v == '-' || v == '_' || v == '+' { // replace '-', '_', '+' to '.' | |
if j > 0 && buf[j-1] != '.' { | |
buf[j] = '.' | |
j++ | |
} | |
} else if (next > 0) && | |
(!(next >= '0' && next <= '9') && (v >= '0' && v <= '9')) || | |
(!(v >= '0' && v <= '9') && (next >= '0' && next <= '9')) { // Insert '.' before and after a non-digit | |
buf[j] = v | |
j++ | |
if v != '.' && next != '.' { | |
buf[j] = '.' | |
j++ | |
} | |
continue | |
} else if !((v >= '0' && v <= '9') || | |
(v >= 'a' && v <= 'z') || (v >= 'A' && v <= 'Z')) { // Non-letters and numbers | |
if j > 0 && buf[j-1] != '.' { | |
buf[j] = '.' | |
j++ | |
} | |
} else { | |
buf[j] = v | |
j++ | |
} | |
} | |
return string(buf[:j]) | |
} | |
// compare special version forms | |
special = func(form1, form2 string) int { | |
found1, found2, len1, len2 := -1, -1, len(form1), len(form2) | |
// (Any string not found) < dev < alpha = a < beta = b < RC = rc < # < pl = p | |
forms := map[string]int{ | |
"dev": 0, | |
"alpha": 1, | |
"a": 1, | |
"beta": 2, | |
"b": 2, | |
"RC": 3, | |
"rc": 3, | |
"#": 4, | |
"pl": 5, | |
"p": 5, | |
} | |
for name, order := range forms { | |
if len1 < len(name) { | |
continue | |
} | |
if strings.Compare(form1[:len(name)], name) == 0 { | |
found1 = order | |
break | |
} | |
} | |
for name, order := range forms { | |
if len2 < len(name) { | |
continue | |
} | |
if strings.Compare(form2[:len(name)], name) == 0 { | |
found2 = order | |
break | |
} | |
} | |
if found1 == found2 { | |
return 0 | |
} else if found1 > found2 { | |
return 1 | |
} else { | |
return -1 | |
} | |
} | |
compare := vcompare(version1, version2) | |
switch operator { | |
case "<", "lt": | |
return compare == -1 | |
case "<=", "le": | |
return compare != 1 | |
case ">", "gt": | |
return compare == 1 | |
case ">=", "ge": | |
return compare != -1 | |
case "==", "=", "eq": | |
return compare == 0 | |
case "!=", "<>", "ne": | |
return compare != 0 | |
default: | |
panic("operator: invalid") | |
} | |
} | |
// ZipOpen zip_open() | |
func ZipOpen(filename string) (*zip.ReadCloser, error) { | |
return zip.OpenReader(filename) | |
} | |
// Pack pack() | |
func Pack(order binary.ByteOrder, data interface{}) (string, error) { | |
buf := new(bytes.Buffer) | |
err := binary.Write(buf, order, data) | |
if err != nil { | |
return "", err | |
} | |
return buf.String(), nil | |
} | |
// Unpack unpack() | |
func Unpack(order binary.ByteOrder, data string) (interface{}, error) { | |
var result []byte | |
r := bytes.NewReader([]byte(data)) | |
err := binary.Read(r, order, &result) | |
if err != nil { | |
return nil, err | |
} | |
return result, nil | |
} | |
// Ternary Ternary expression | |
// max := Ternary(a > b, a, b).(int) | |
func Ternary(condition bool, trueVal, falseVal interface{}) interface{} { | |
if condition { | |
return trueVal | |
} | |
return falseVal | |
} |