-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathgstring.go
133 lines (115 loc) · 3.67 KB
/
gstring.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package gstring
import (
"fmt"
"io"
)
var defaultFormat = []rune("%s")
// Receives format string in gstring format and map of arguments and translates
// them to format and arguments compatible with standard golang formatting.
func gformat(format string, args map[string]interface{}) (string, []interface{}) {
// holder for new format string - capacity as length of provided string
// should be enough not to resize during appending, since expected length
// of new format is smaller then provided one (names are removed)
var new_format = make([]rune, 0, len(format))
// flag that indicates if current place in format string in inside { }
var in_format = false
// flag that indicates if current place is format string in inside { } and after :
var in_args = false
var previousChar rune
// temp slice for holding name in current format
var current_name_runes = make([]rune, 0, 10)
// temp slice for holding args in current format
var current_args_runes = make([]rune, 0, 10)
var new_format_params []interface{}
for i, ch := range format {
if i > 0 {
previousChar = rune(format[i-1])
}
switch ch {
case '{':
if in_format && previousChar == '{' {
in_format = false
new_format = append(new_format, ch)
break
}
in_format = true
case '}':
if !in_format {
if previousChar == '}' {
new_format = append(new_format, ch)
break
}
// what to do if not in_format and only single } appears?
break
}
if in_format {
if len(current_args_runes) > 0 {
// append formatting arguments to new_format directly
new_format = append(new_format, current_args_runes...)
} else {
// if no arguments are supplied, use default ones
new_format = append(new_format, defaultFormat...)
}
// reset format args for new iteration
current_args_runes = current_args_runes[0:0]
}
var name string
if len(current_name_runes) == 0 {
name = "EMPTY_PLACEHOLDER"
} else {
name = string(current_name_runes)
}
// reset name runes for next iteration
current_name_runes = current_name_runes[0:0]
// get value from provided args and append it to new_format_args
val, ok := args[name]
if !ok {
val = fmt.Sprintf("%%MISSING=%s", name)
}
new_format_params = append(new_format_params, val)
// reset flags
in_format = false
in_args = false
case ':':
if in_format {
in_args = true
}
default:
if in_format {
if in_args {
current_args_runes = append(current_args_runes, ch)
} else {
current_name_runes = append(current_name_runes, ch)
}
} else {
new_format = append(new_format, ch)
}
}
}
return string(new_format), new_format_params
}
// interface similar to "fmt" package
// Errorm returns error instance with formatted error message.
// This is same as fmt.Errorf, but uses gstring formatting.
func Errorm(format string, args map[string]interface{}) error {
f, a := gformat(format, args)
return fmt.Errorf(f, a...)
}
// Fprintm writes formatted string to provided writer.
// This is same as fmt.Fprintf, but uses gstring formatting.
func Fprintm(w io.Writer, format string, args map[string]interface{}) (n int, err error) {
f, a := gformat(format, args)
return fmt.Fprintf(w, f, a...)
}
// Printf prints formatted string to stdout.
// This is same as fmt.Printf, but uses gstring formatting.
func Printm(format string, args map[string]interface{}) (n int, err error) {
f, a := gformat(format, args)
return fmt.Printf(f, a...)
}
// Sprintf returns formatted string.
// This is same as fmt.Sprintf, but uses gstring formatting.
func Sprintm(format string, args map[string]interface{}) string {
f, a := gformat(format, args)
return fmt.Sprintf(f, a...)
}