Pastey (std/text.e) - format function proposal for revision
- Posted by cargoan
Jan 11, 2015
public function format(sequence format_pattern, object arg_list = {})
sequence result
integer in_token
integer tch
integer i
integer tend
integer cap
integer align
integer psign
integer msign
integer zfill
integer bwz
integer spacer
integer alt
integer width
integer decs
integer pos
integer argn
integer argl
integer trimming
integer hexout
integer binout
integer tsep
integer istext
object prevargv
object currargv
sequence idname
object envsym
object envvar
integer ep
-- added ---------------------------------------------------------------------------------------
integer pflag
integer count
-- ---------------------------------------------------------------------------------------------
if atom(arg_list) then
arg_list = {arg_list}
end if
result = ""
in_token = 0
i = 0
tend = 0
argl = 0
spacer = 0
prevargv = 0
while i < length(format_pattern) do
i += 1
tch = format_pattern[i]
if not in_token then
if tch = '[' then
in_token = 1
tend = 0
cap = 0
align = 0
psign = 0
msign = 0
zfill = 0
bwz = 0
spacer = 0
alt = 0
width = 0
decs = -1
argn = 0
hexout = 0
binout = 0
trimming = 0
tsep = 0
istext = 0
idname = ""
envvar = ""
envsym = ""
else
result &= tch
end if
else
switch tch do
case ']' then
in_token = 0
tend = i
case '[' then
result &= tch
while i < length(format_pattern) do
i += 1
if format_pattern[i] = ']' then
in_token = 0
tend = 0
exit
end if
end while
case 'w', 'u', 'l' then
cap = tch
case 'b' then
bwz = 1
case 's' then
spacer = 1
case 't' then
trimming = 1
case 'z' then
zfill = 1
case 'X' then
hexout = 1
case 'B' then
binout = 1
case 'c', '<', '>' then
align = tch
case '+' then
psign = 1
case '(' then
msign = 1
case '?' then
alt = 1
case 'T' then
istext = 1
case ':' then
while i < length(format_pattern) do
i += 1
tch = format_pattern[i]
pos = find(tch, "0123456789")
if pos = 0 then
i -= 1
exit
end if
width = width * 10 + pos - 1
if width = 0 then
zfill = '0'
end if
end while
case '.' then
decs = 0
while i < length(format_pattern) do
i += 1
tch = format_pattern[i]
pos = find(tch, "0123456789")
if pos = 0 then
i -= 1
exit
end if
decs = decs * 10 + pos - 1
end while
case '{' then
-- Use a named argument.
integer sp
sp = i + 1
i = sp
while i < length(format_pattern) do
if format_pattern[i] = '}' then
exit
end if
if format_pattern[i] = ']' then
exit
end if
i += 1
end while
idname = trim(format_pattern[sp .. i-1]) & '='
if format_pattern[i] = ']' then
i -= 1
end if
for j = 1 to length(arg_list) do
if sequence(arg_list[j]) then
if search:begins(idname, arg_list[j]) then
if argn = 0 then
argn = j
exit
end if
end if
end if
if j = length(arg_list) then
idname = ""
argn = -1
end if
end for
case '%' then
-- Use the environment symbol
integer sp
sp = i + 1
i = sp
while i < length(format_pattern) do
if format_pattern[i] = '%' then
exit
end if
if format_pattern[i] = ']' then
exit
end if
i += 1
end while
envsym = trim(format_pattern[sp .. i-1])
if format_pattern[i] = ']' then
i -= 1
end if
envvar = getenv(envsym)
argn = -1
if atom(envvar) then
envvar = ""
end if
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' then
if argn = 0 then
i -= 1
while i < length(format_pattern) do
i += 1
tch = format_pattern[i]
pos = find(tch, "0123456789")
if pos = 0 then
i -= 1
exit
end if
argn = argn * 10 + pos - 1
end while
end if
case ',' then
if i < length(format_pattern) then
i +=1
tsep = format_pattern[i]
end if
case else
-- ignore it
end switch
if tend > 0 then
-- Time to replace the token.
sequence argtext = ""
if argn = 0 then
argn = argl + 1
end if
argl = argn
if argn < 1 or argn > length(arg_list) then
if length(envvar) > 0 then
argtext = envvar
currargv = envvar
else
argtext = ""
currargv =""
end if
else
if string(arg_list[argn]) then
if length(idname) > 0 then
argtext = arg_list[argn][length(idname) + 1 .. $]
else
argtext = arg_list[argn]
end if
elsif integer(arg_list[argn])
-- for consistent formatting, we need to test in case of 64-bit euphoria
-- changed -------------------------------------------------------------------------------------
-- and arg_list[argn] <= 0x3fff_fff -- ???
and arg_list[argn] <= 0x3fff_ffff
-- ---------------------------------------------------------------------------------------------
and arg_list[argn] >= -0x4000_0000 then
if istext then
argtext = {and_bits(0xFFFF_FFFF, math:abs(arg_list[argn]))}
elsif bwz != 0 and arg_list[argn] = 0 then
argtext = repeat(' ', width)
elsif binout = 1 then
argtext = stdseq:reverse( convert:int_to_bits(arg_list[argn], 32)) + '0'
-- added ---------------------------------------------------------------------------------------
if zfill != 0 and width > 0 then
if width > length(argtext) then
argtext = repeat('0', width - length(argtext)) & argtext
end if
else
count = 1
while count < length(argtext) and argtext[count] = '0' do
count += 1
end while
argtext = argtext[count .. $]
end if
-- removed -------------------------------------------------------------------------------------
-- for ib = 1 to length(argtext) do
-- if argtext[ib] = '1' then
-- argtext = argtext[ib .. $]
-- exit
-- end if
-- end for
-- ---------------------------------------------------------------------------------------------
elsif hexout = 0 then
argtext = sprintf("%d", arg_list[argn])
if zfill != 0 and width > 0 then
if argtext[1] = '-' then
if width > length(argtext) then
argtext = '-' & repeat('0', width - length(argtext)) & argtext[2..$]
end if
else
if width > length(argtext) then
argtext = repeat('0', width - length(argtext)) & argtext
end if
end if
end if
if arg_list[argn] > 0 then
if psign then
if zfill = 0 then
argtext = '+' & argtext
elsif argtext[1] = '0' then
argtext[1] = '+'
end if
end if
elsif arg_list[argn] < 0 then
if msign then
if zfill = 0 then
argtext = '(' & argtext[2..$] & ')'
else
if argtext[2] = '0' then
argtext = '(' & argtext[3..$] & ')'
else
-- Don't need the '(' prefix as its just going to
-- be trunctated to fit the requested width.
argtext = argtext[2..$] & ')'
end if
end if
end if
end if
else
argtext = sprintf("%x", arg_list[argn])
if zfill != 0 and width > 0 then
if width > length(argtext) then
argtext = repeat('0', width - length(argtext)) & argtext
end if
end if
end if
elsif atom(arg_list[argn]) then
if istext then
argtext = {and_bits(0xFFFF_FFFF, math:abs(floor(arg_list[argn])))}
else
if hexout then
argtext = sprintf("%x", arg_list[argn])
if zfill != 0 and width > 0 then
if width > length(argtext) then
argtext = repeat('0', width - length(argtext)) & argtext
end if
end if
else
argtext = trim(sprintf("%15.15g", arg_list[argn]))
-- Remove any leading 0 after e+
while ep != 0 with entry do
argtext = remove(argtext, ep+2)
entry
ep = match("e+0", argtext)
end while
if zfill != 0 and width > 0 then
if width > length(argtext) then
if argtext[1] = '-' then
argtext = '-' & repeat('0', width - length(argtext)) & argtext[2..$]
else
argtext = repeat('0', width - length(argtext)) & argtext
end if
end if
end if
if arg_list[argn] > 0 then
if psign then
if zfill = 0 then
argtext = '+' & argtext
elsif argtext[1] = '0' then
argtext[1] = '+'
end if
end if
elsif arg_list[argn] < 0 then
if msign then
if zfill = 0 then
argtext = '(' & argtext[2..$] & ')'
else
if argtext[2] = '0' then
argtext = '(' & argtext[3..$] & ')'
else
argtext = argtext[2..$] & ')'
end if
end if
end if
end if
end if
end if
else
if alt != 0 and length(arg_list[argn]) = 2 then
object tempv
if atom(prevargv) then
if prevargv != 1 then
tempv = arg_list[argn][1]
else
tempv = arg_list[argn][2]
end if
else
if length(prevargv) = 0 then
tempv = arg_list[argn][1]
else
tempv = arg_list[argn][2]
end if
end if
if string(tempv) then
argtext = tempv
elsif integer(tempv) then
if istext then
argtext = {and_bits(0xFFFF_FFFF, math:abs(tempv))}
elsif bwz != 0 and tempv = 0 then
argtext = repeat(' ', width)
else
argtext = sprintf("%d", tempv)
end if
elsif atom(tempv) then
if istext then
argtext = {and_bits(0xFFFF_FFFF, math:abs(floor(tempv)))}
elsif bwz != 0 and tempv = 0 then
argtext = repeat(' ', width)
else
argtext = trim(sprintf("%15.15g", tempv))
end if
else
argtext = pretty:pretty_sprint( tempv,
{2,0,1,1000,"%d","%.1