-
Notifications
You must be signed in to change notification settings - Fork 72
/
Copy pathformat.ahk
75 lines (73 loc) · 3.16 KB
/
format.ahk
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
; AutoHotkey v2 alpha
; format(format_string, ...)
; Equivalent to format_v(format_string, Array(...))
format(f, v*) {
return format_v(f, v)
}
; format_v(format_string, values)
; - format_string:
; String of literal text and placeholders, as described below.
; - values:
; Array or map of values to insert into the format string.
;
; Placeholder format: "{" id ":" format "}"
; - id:
; Numeric or string literal identifying the value in the parameter
; list. For example, {1} is values[1] and {foo} is values["foo"].
; - format:
; A format specifier as accepted by printf but excluding the
; leading "%". See "Format Specification Fields" at MSDN:
; http://msdn.microsoft.com/en-us/library/56e442dc.aspx
; The "*" width specifier is not supported, and there may be other
; limitations.
;
; Examples:
; MsgBox % format("0x{1:X}", 4919)
; MsgBox % format("Computation took {2:.9f} {1}", "seconds", 3.2001e-5)
; MsgBox % format_v("chmod {mode:o} {file}", {mode: 511, file: "myfile"})
;
format_v(f, v)
{
local out, arg, i, j, s, m, key, buf, c, type, p, O_
out := "" ; To make #Warn happy.
VarSetCapacity(arg, 8), j := 1, VarSetCapacity(s, StrLen(f)*2.4) ; Arbitrary estimate (120% * size of Unicode char).
O_ := A_AhkVersion >= "2" ? "" : "O)" ; Seems useful enough to support v1.
while i := RegExMatch(f, O_ "\{((\w+)(?::([^*`%{}]*([scCdiouxXeEfgGaAp])))?|[{}])\}", m, j) ; For each {placeholder}.
{
out .= SubStr(f, j, i-j) ; Append the delimiting literal text.
j := i + m.Len[0] ; Calculate next search pos.
if (m.1 = "{" || m.1 = "}") { ; {{} or {}}.
out .= m.2
continue
}
key := m.2+0="" ? m.2 : m.2+0 ; +0 to convert to pure number.
if !v.HasKey(key) {
out .= m.0 ; Append original {} string to show the error.
continue
}
if m.3 = "" {
out .= v[key] ; No format specifier, so just output the value.
continue
}
if (type := m.4) = "s"
NumPut((p := v.GetAddress(key)) ? p : &(s := v[key] ""), arg)
else if InStr("cdioux", type) ; Integer types.
NumPut(v[key], arg, "int64") ; 64-bit in case of something like {1:I64i}.
else if InStr("efga", type) ; Floating-point types.
NumPut(v[key], arg, "double")
else if (type = "p") ; Pointer type.
NumPut(v[key], arg)
else { ; Note that this doesn't catch errors like "{1:si}".
out .= m.0 ; Output m unaltered to show the error.
continue
}
; MsgBox % "key=" key ",fmt=" m.3 ",typ=" m.4 . (m.4="s" ? ",str=" NumGet(arg) ";" (&s) : "")
if (c := DllCall("msvcrt\_vscwprintf", "wstr", "`%" m.3, "ptr", &arg, "cdecl")) >= 0 ; Determine required buffer size.
&& DllCall("msvcrt\_vsnwprintf", "wstr", buf, "ptr", VarSetCapacity(buf, ++c*2)//2, "wstr", "`%" m.3, "ptr", &arg, "cdecl") >= 0 { ; Format string into buf.
out .= buf ; Append formatted string.
continue
}
}
out .= SubStr(f, j) ; Append remainder of format string.
return out
}