#
# $Id: format.icn,v 1.2 2006-07-10 13:43:32 rparlett Exp $
#
# This file is in the public domain.
#
# Author: Robert Parlett (parlett@dial.pipex.com)
#
package util
#
# Convert a string to an integer.
# @param base The base to use for the conversion (default is 16).
#
procedure format_string_to_int(subject, base)
local n, digs, s, c
n := 0
/base := 16
digs := "0123456789abcdef"[1:base + 1] | fail
s := ::string(subject) | fail
every c := !::map(s) do
n := base * n + ::find(c, digs) - 1 | fail
return n
end
#
# Convert an integer to a string.
#
# @param base The desired base of the result.
# @param p The minimum width of the result, padding with zeroes
# @ if necessary.
#
procedure format_int_to_string(subject, base, p)
local s, n, digs
s := ""
/base := 16
/p := 1
n := ::integer(subject) | fail
digs := "0123456789ABCDEF"[1:base + 1] | fail
while n > 0 do {
s := digs[n % base + 1] || s
n /:= base
}
if p > *s then
s := ::repl("0", p - *s) || s
return s
end
#
# Convert a numeric to a string.
#
# @param p The number of decimal places to produce (default 4).
# @param f A cset of flags. If c contains {'e'} then the output is
# @ in scientific notation. If c contains {','} then commas
# @ are introduced into the non-fractional part of the number;
# @ if c contains {'+'} then a leading + is added to positive
# @ numbers.
# @
#
procedure format_numeric_to_string(subject, p, f)
local n1, s, t, lim, d, zs, dig, i, n, sig_digs
/f := ''
n := ::numeric(subject) | fail
sig_digs := 16 - 2
/p := 4
n1 := ::abs(n)
if not ::any(f, "e") & ::type(n1) == "integer" then
s := ::string(n1) || ::repl("0", p)
else {
t := format_norm(n1)
lim := if ::any(f, "e") then p else p + t[2]
if lim >= -1 then {
s := ""
d := t[1]
if lim > sig_digs then {
zs := ::repl("0", lim - sig_digs)
lim := sig_digs
}
every 0 to lim do {
s ||:= dig := ::integer(d)
d := (d - dig) * 10.0
}
if ::integer(d) >= 5 then {
(every i := *s to 1 by -1 do
if s[i] := 10 > s[i] + 1 then break
else s[i] := 0
) | { # need to add 1 to left of s
s := "1" || s
if ::any(f, "e") then {
s[-1] := ""
t[2] +:= 1
}
}
}
s ||:= \zs
s := ::repl("0", 0 < p + 1 - *s) || s
}
else s := ::repl("0", p + 1)
}
if ::any(f, ",") then
every s[*s - p - 3 to 1 by -3] ||:= ","
if p > 0 then {
s[-p - 1] ||:= "."
if ::any(f, "s"| "z") then {
"0" ~== s[i := *s to *s - p + 1 by -1]
s[i + 1 : 0] := if ::any(f, "s") then
::repl(" ", *s - i)
else ""
}
}
if n < 0 & ::upto('123456789', s) then
s := "-" || s
else
if ::any(f, "+") then
s := "+" || s
return if ::any(f, "e") then
s || "E" || (if t[2] < 0 then "-" else "+") ||
::right(::abs(t[2]), 3, "0")
else s
end
procedure format_norm(n)
local m, e, ve
static pwr
initial pwr := [1e1, 1e2, 1e4, 1e8, 1e16, 1e32]
if n = 0.0 then
return [0.0, 0]
m := if n < 1.0 then 1.0 / n else n
e := 0
if not(pwr[1 + (ve := 1 to *pwr)] > m) then {
while m /:= (m >= pwr[ve]) do
e +:= 2 ^ (ve - 1)
ve -:= 1
}
# invariant : 1 <= m < pwr[1 + ve] & m * 10 ^ e = m0
while m >= 10.0 do {
if m /:= (m >= pwr[ve]) then
e +:= 2 ^ (ve - 1)
ve -:= 1
}
if n < 1.0 then {
e := -e
if m := 10.0 / (1.0 ~= m) then
e -:= 1
}
return [m, e]
end
#
# Remove escape sequences from the subject.
#
procedure format_unescape(subject)
local s, res, ch
s := ::string(subject) | fail
res := ""
s ? {
repeat {
res ||:= ::tab(::upto('\\') | 0)
if ::pos(0) then
break
::move(1)
if ::any('01234567') then
res ||:= ::char(format_string_to_int(::move(3), 8))
else if ="x" then
res ||:= ::char(format_string_to_int(::move(2), 16))
else if ="^" then
res ||:= ::char(::map(::move(1)) + 1 - ::ord("a"))
else {
ch := ::move(1) | "\""
res ||:= case ch of {
"z" : ""
"n" : "\n"
"l" : "\l"
"b" : "\b"
"d" : "\d"
"e" : "\e"
"r" : "\r"
"t" : "\t"
"v" : "\v"
"f" : "\f"
"w" : " "
"s" : "\s"
default : ch
}
}
}
}
return res
end
#
# Add escape sequences to the subject.
#
procedure format_escape(subject)
local s, res, ch
static printable
initial
printable := ::cset(&ascii[33:128]) -- '\\'
s := ::string(subject) | fail
res := ""
s ? {
repeat {
res ||:= ::tab(::many(printable))
if ::pos(0) then
break
ch := ::move(1)
res ||:= case ch of {
"\n" : "\\n"
"\l" : "\\l"
"\b" : "\\b"
"\d" : "\\d"
"\e" : "\\e"
"\r" : "\\r"
"\t" : "\\t"
"\v" : "\\v"
"\f" : "\\f"
"\\" : "\\\\"
default : "\\x" || format_int_to_string(::ord(ch), 16, 2)
}
}
}
return res
end
#
# Convert the subject integer into words, eg 231 to "Two Hundred and Thirty-One"
#
procedure format_int_to_words(subject)
local n, s, i, m
static small, tens, pwr10, pwr10num
initial {
small := ["One", "Two", "Three", "Four", "Five", "Six",
"Seven", "Eight", "Nine", "Ten", "Eleven",
"Twelve", "Thirteen", "Fourteen", "Fifteen",
"Sixteen", "Seventeen", "Eighteen", "Nineteen"]
tens := ["Ten", "Twenty", "Thirty", "Forty", "Fifty", "Sixty",
"Seventy", "Eighty", "Ninety"]
pwr10 := ["Million", "Thousand", "Hundred"]
pwr10num := [1000000, 1000, 100]
}
n := ::integer(subject) | fail
s := ""
every i := 1 to *pwr10num do
if (m := n / pwr10num[i]) > 0 then {
if *s > 0 then
s ||:= " "
s ||:= format_int_to_words(m) || " " || pwr10[i]
n %:= pwr10num[i]
}
if n = 0 then {
if *s = 0 then
s := "Zero"
} else {
if *s > 0 then
s ||:= " and "
if n < 20 then
s ||:= small[n]
else {
s ||:= tens[n / 10]
if n % 10 > 0 then
s ||:= "-" || small[n % 10]
}
}
return s
end
This page produced by UniDoc on 2021/04/15 @ 23:59:43.