ref: 9df81ed24b6326058a4038fd4984ff150617a6b2
parent: 6f5ac74ad23e4ad8288fef156385ea2586d2d8fb
author: Ori Bernstein <[email protected]>
date: Sat Jun 21 09:20:34 EDT 2014
Add support for padded strings. Feeping Creaturinm.
--- a/libstd/chartype.myr
+++ b/libstd/chartype.myr
@@ -9,6 +9,8 @@
pkg std =
/* predicates */
const isalpha : (c : char -> bool)
+ const isdigit : (c : char -> bool)
+ const isxdigit : (c : char -> bool)
const isnum : (c : char -> bool)
const isalnum : (c : char -> bool)
const isspace : (c : char -> bool)
@@ -1097,6 +1099,14 @@
;;
;;
-> false
+}
+
+const isdigit = {c
+ -> c >= '0' && c <= '9'
+}
+
+const isxdigit = {c
+ -> c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F'
}
const isnum = {c
--- a/libstd/extremum.myr
+++ b/libstd/extremum.myr
@@ -1,6 +1,7 @@
pkg std =
generic min : (a : @a::numeric, b : @a::numeric -> @a::numeric)
generic max : (a : @a::numeric, b : @a::numeric -> @a::numeric)
+ generic clamp : (a : @a::numeric, min : @a::numeric, max : @a::numeric -> @a::numeric)
;;
generic min = {a, b
@@ -18,3 +19,14 @@
-> b
;;
}
+
+generic clamp = {a, min, max
+ if a < min
+ -> min
+ elif a > max
+ -> max
+ else
+ -> a
+ ;;
+}
+
--- a/libstd/fmt.myr
+++ b/libstd/fmt.myr
@@ -5,6 +5,7 @@
use "utf.use"
use "varargs.use"
use "extremum.use"
+use "chartype.use"
/*
printf-like functions. These use a different syntax from the C printf,
@@ -85,13 +86,11 @@
const digitchars = [
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
]
-generic intfmt = {buf : byte[:], bits : @a::(integral,numeric), base, signed
+generic intfmt = {buf : byte[:], bits : @a::(integral,numeric), base, signed, padto, padfill
var isneg
var val
var b : char[32]
- var i
- var j
- var n
+ var i, j, n, npad
n = 0
i = 0
@@ -113,11 +112,22 @@
val /= base
i++
;;
+
+ npad = clamp(padto - i, 0, padto)
n = 0
- if isneg
+ for j = 0; j < min(npad, buf.len); j++
+ if n >= buf.len
+ break
+ ;;
+ n += encode(buf[n:], padfill)
+ ;;
+ if isneg && n < buf.len
n += encode(buf[n:], '-')
;;
for j = i; j != 0; j--
+ if n >= buf.len
+ break
+ ;;
n += encode(buf[n:], b[j - 1])
;;
-> n
@@ -128,8 +138,9 @@
const bfmtv = {buf, fmt, ap
var c
var n
+ var padto
var base
- var signed
+ var signed, padfill
var s_val : byte[:]
var t_val : bool
var b_val : int8, ub_val : uint8
@@ -146,7 +157,9 @@
(c, fmt) = striter(fmt)
if c == '%'
base = 10
+ padto = 0
signed = true
+ padfill = ' '
(c, fmt) = striter(fmt)
/* modifiers */
if fmt.len > 0
@@ -159,19 +172,34 @@
| 'u':
(c, fmt) = striter(fmt)
signed = false
+ | '0':
+ (c, fmt) = striter(fmt)
+ padfill = '0'
;;
+ if isdigit(c)
+ /*
+ We can't get a 0 on the first iteration, since
+ that was matched above. So, no special checks
+ for nonzero on the first iteration.
+ */
+ padto = 0
+ while isdigit(c)
+ padto = padto*10 + charval(c, 10)
+ (c, fmt) = striter(fmt)
+ ;;
+ ;;
;;
/* format specifiers */
match c
| 's':
(s_val, ap) = vanext(ap)
- n += strfmt(buf[n:], s_val)
+ n += strfmt(buf[n:], s_val, padto, padfill)
| 't':
(t_val, ap) = vanext(ap)
- n += boolfmt(buf[n:], t_val)
+ n += boolfmt(buf[n:], t_val, padto, padfill)
| 'f':
(f_val, ap) = vanext(ap)
- n += floatfmt(buf[n:], f_val, 0, 0)
+ n += floatfmt(buf[n:], f_val, 0, 0, padto, padfill)
/* FIXME: float casts are currently broken
| 'F':
(F_val, ap) = vanext(ap)
@@ -181,42 +209,42 @@
| 'b':
if signed
(b_val, ap) = vanext(ap)
- n += intfmt(buf[n:], b_val, base, signed)
+ n += intfmt(buf[n:], b_val, base, signed, padto, padfill)
else
(ub_val, ap) = vanext(ap)
- n += intfmt(buf[n:], ub_val, base, signed)
+ n += intfmt(buf[n:], ub_val, base, signed, padto, padfill)
;;
| 'w':
if signed
(w_val, ap) = vanext(ap)
- n += intfmt(buf[n:], w_val, base, signed)
+ n += intfmt(buf[n:], w_val, base, signed, padto, padfill)
else
(uw_val, ap) = vanext(ap)
- n += intfmt(buf[n:], uw_val, base, signed)
+ n += intfmt(buf[n:], uw_val, base, signed, padto, padfill)
;;
| 'i':
if signed
(i_val, ap) = vanext(ap)
- n += intfmt(buf[n:], i_val, base, signed)
+ n += intfmt(buf[n:], i_val, base, signed, padto, padfill)
else
(ui_val, ap) = vanext(ap)
- n += intfmt(buf[n:], ui_val, base, signed)
+ n += intfmt(buf[n:], ui_val, base, signed, padto, padfill)
;;
| 'l':
if signed
(l_val, ap) = vanext(ap)
- n += intfmt(buf[n:], l_val, base, signed)
+ n += intfmt(buf[n:], l_val, base, signed, padto, padfill)
else
(ul_val, ap) = vanext(ap)
- n += intfmt(buf[n:], ul_val, base, signed)
+ n += intfmt(buf[n:], ul_val, base, signed, padto, padfill)
;;
| 'z':
(z_val, ap) = vanext(ap)
- n += intfmt(buf[n:], z_val castto(int64), base, signed)
+ n += intfmt(buf[n:], z_val castto(int64), base, signed, padto, padfill)
| 'p':
(p_val, ap) = vanext(ap)
- n += intfmt(buf[n:], p_val castto(int64), 16, false)
+ n += intfmt(buf[n:], p_val castto(int64), 16, false, padto, padfill)
| 'c': (c_val, ap) = vanext(ap)
n += encode(buf[n:], c_val)
| _:
@@ -229,16 +257,21 @@
-> n
}
-const strfmt = {buf, str
- var i
-
+const strfmt = {buf, str, padto, padfill
+ var i, n, npad
+
+ n = 0
+ npad = clamp(padto - str.len, 0, padto)
+ for i = 0; i < padto - str.len; i++
+ n += encode(buf[n:], padfill)
+ ;;
for i = 0; i < min(str.len, buf.len); i++
- buf[i] = str[i]
+ buf[n++] = str[i]
;;
- -> i
+ -> n
}
-const boolfmt = {buf, val
+const boolfmt = {buf, val, padto, padfill
var s
if val
@@ -246,7 +279,7 @@
else
s = "false"
;;
- -> strfmt(buf, s)
+ -> strfmt(buf, s, padto, padfill)
}
/*
@@ -258,7 +291,7 @@
2 => print until maxdigits produced, paddding with zeros.
*/
-const floatfmt = {buf, val, mode, maxdigits
+const floatfmt = {buf, val, mode, maxdigits, padto, padfill
var i
var n
/*
@@ -268,15 +301,15 @@
/* handle 0 specially to avoid special cases */
if val == 0.0
- n = strfmt(buf, "0.0")
+ n = strfmt(buf, "0.0", padto, padfill)
if mode == 0 && maxdigits > 2
for i = 1; i < maxdigits; i++
- n += strfmt(buf[n:], "0")
+ n += strfmt(buf[n:], "0", padto, padfill)
;;
;;
-> n
;;
- -> strfmt(buf, "floats not implemented")
+ -> strfmt(buf, "floats not implemented", padto, padfill)
}
--- /dev/null
+++ b/test/data/stdfmtpad-expected
@@ -1,0 +1,4 @@
+ abcd
+00000bdcae
+ 10
+0000000010
--- /dev/null
+++ b/test/stdfmtpad.myr
@@ -1,0 +1,8 @@
+use std
+
+const main = {
+ std.put("%10s\n", "abcd")
+ std.put("%010s\n", "bdcae")
+ std.put("%10i\n", 10)
+ std.put("%010i\n", 10)
+}
--- a/test/tests
+++ b/test/tests
@@ -125,6 +125,7 @@
B strfind C
B strjoin C
B stdslcp C
+B stdfmtpad C
B bigint C
B exporttrait
# B local-labels E 10 ## BUGGERED