# # $Id: format.icn,v 1.1 2004/02/12 17:07:55 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) 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) 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 /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) 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) 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) 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