Hi.
Mr Coffee asked for a pretty print function some time ago.
With the handy string functions like LEFT(), Right(), Center(), Format(),
and so on there is not much demand for such a function.
In *xenix the printf() and sprintf() functions are widely used though.
So I wrote a simple implementation of some of sprintf 's functionality.
Please suggest improvements. I haven't got time to respond daily though.
I used "classic" rexx. Would an oo approach be better?
In case your mail folds the lines inadvertantly, I put "/*R*/" in pos
80-84.
Use that to fix alignment.
---- snippet below ------------------------------------
-- rexx
/*R*/
signal on novalue
/*R*/
trace o
/*R*/
/*R*/
tdate.1 = '2007-10-01'; ttime.1 = '07.15' ; ttemp.1 = 5;
/*R*/
tdate.2 = '2007-10-02'; ttime.2 = '07.14' ; ttemp.2 = 8;
/*R*/
tdate.3 = '2007-10-03'; ttime.3 = '07.01' ; ttemp.3 = 11;
/*R*/
tdate.4 = '2007-10-04'; ttime.4 = '07.14' ; ttemp.4 = 6;
/*R*/
tdate.5 = '2007-10-05'; ttime.5 = '07.00' ; ttemp.5 = 5;
/*R*/
tdate.6 = '2007-10-06'; ttime.6 = '06.48' ; ttemp.6 = 2;
/*R*/
tdate.7 = '2007-10-07'; ttime.7 = '07.15' ; ttemp.7 = -1.5;
/*R*/
tdate.8 = '2007-10-08'; ttime.8 = '07.14' ; ttemp.8 = -2.5;
/*R*/
tdate.9 = '2007-10-09'; ttime.9 = '07.21' ; ttemp.9 = +3.599;
/*R*/
tdate.0 = 9
/*R*/
/*R*/
/*R*/
say sprintf("%-10s %5s %s", "Date", "Time", "Temperature")
/*R*/
say sprintf("%-10s %5s %s", "----", "----", "-----------")
/*R*/
/*R*/
do ix = 1 to tdate.0
/*R*/
if ix = 7 then weekday = "Sunday"; else weekday = ""
/*R*/
say sprintf("%s %s %3.1f C %s", tdate.ix , ttime.ix, ttemp.ix, weekday )
/*R*/
end
/*R*/
/*R*/
exit 0
/*R*/
-- ---------------------------------------------------------------
/*R*/
sprintf: procedure
/*R*/
/*R*/
/*
/*R*/
see Unix/C/perl sprintf documentation for general usage
/*R*/
/*R*/
Implemented datatypes
/*R*/
d integer
/*R*/
f float fixed decimal
/*R*/
s string
/*R*/
defualt none
/*R*/
/*R*/
Implemented width modifiers
/*R*/
n length of element
/*R*/
n1.n2 n1 = length before decimal point including +/- default length
/*R*/
n2= number of decimal places default zero
/*R*/
decimals will be rounded to n2 positions
/*R*/
/*R*/
Implemented modifiers
/*R*/
%% is "%"
/*R*/
+ prefix postive number with "+" and right adjust
/*R*/
+ right adjust string
/*R*/
- left justify number
/*R*/
- left adjust string
/*R*/
0 right adjust zero fill for numbers and strings
/*R*/
default for strings "as is"
/*R*/
default for numbers is right adjust
/*R*/
*/
/*R*/
/*R*/
types = 'dfs' -- case sensitive
/*R*/
modifiers = "+-0"
/*R*/
/*R*/
-- limited to 12 arguments presently
/*R*/
-- how to change this to unlimited ???
/*R*/
use arg fmstring, arg.1, arg.2, arg.3, arg.4, arg.5, arg.6,
/*R*/
, arg.7, arg.8, arg.9, arg.10, arg.11, arg.12
/*R*/
/*R*/
org_fmstring = fmstring
/*R*/
/*R*/
-- handle any %% in format string '19'x is off keyboard (in most
countries??) /*R*/
fmstring = CHANGESTR("%%",fmstring,'19'x)
/*R*/
/*R*/
-- loop over "%" in fmstring
/*R*/
aix = 0
/*R*/
do while pos("%",fmstring) > 0
/*R*/
parse value fmstring with part1 '%' fmstring
/*R*/
aix = aix + 1
/*R*/
/*R*/
-- the first pos in fmstring is a modifier[+-0],
/*R*/
-- a width [n[.n]] or a type [dfs] in this order
/*R*/
if POS(SUBSTR(fmstring,1,1),modifiers) > 0 then do
/*R*/
modifier = SUBSTR(fmstring,1,1)
/*R*/
fmstring = SUBSTR(fmstring,2)
/*R*/
end
/*R*/
else
/*R*/
modifier = ""
/*R*/
/*R*/
-- is there anything before types [dfs]
/*R*/
-- loop over types and find the first data type modifier postition
/*R*/
nextpos = 9999
/*R*/
do ix = 1 to LENGTH(types)
/*R*/
type = SUBSTR(types,ix,1)
/*R*/
wpos = POS(type,fmstring)
/*R*/
if wpos > 0 ,
/*R*/
& wpos < nextpos then
/*R*/
nextpos = wpos
/*R*/
end
/*R*/
if nextpos < 1,
/*R*/
| nextpos = 9999 then
/*R*/
do
/*R*/
return "Unknown type format:" org_fmstring
/*R*/
end
/*R*/
else
/*R*/
do
/*R*/
thistype = SUBSTR(fmstring,nextpos,1)
/*R*/
if nextpos > 1 then
/*R*/
do
/*R*/
width = SUBSTR(fmstring,1,nextpos -1)
/*R*/
end
/*R*/
else
/*R*/
do
/*R*/
width = MIN(LENGTH(arg.aix),POS('.',arg.aix))
/*R*/
if width = 0 then
/*R*/
width = LENGTH(arg.aix)
/*R*/
if thistype = 'd',
/*R*/
& modifier = '+' then
/*R*/
width = width +1
/*R*/
end
/*R*/
fmstring = SUBSTR(fmstring,nextpos+1)
/*R*/
end
/*R*/
/*R*/
parse value width with length '.' decimals
/*R*/
if length = "" then
/*R*/
length = MIN(LENGTH(arg.aix),POS('.',arg.aix))
/*R*/
if decimals = "" then
/*R*/
decimals = 0
/*R*/
/*R*/
select
/*R*/
------------------------------ handle strings
/*R*/
when thistype = 's' then
/*R*/
do
/*R*/
select
/*R*/
when modifier = '+' then
/*R*/
arg.aix = RIGHT(arg.aix,length)
/*R*/
when modifier = '-' then
/*R*/
arg.aix = LEFT(arg.aix,length)
/*R*/
when modifier = '0' then
/*R*/
arg.aix = RIGHT(arg.aix,length,'0')
/*R*/
otherwise
/*R*/
arg.aix = SUBSTR(arg.aix,1,length)
/*R*/
end
/*R*/
end
/*R*/
------------------------------ handle Integers
/*R*/
when thistype = 'd' then
/*R*/
do
/*R*/
if VERIFY(arg.aix,"+-0123456789") = 0 then do
/*R*/
arg.aix = STRIP(arg.aix,"L",0)
/*R*/
select
/*R*/
when modifier = '+' then
/*R*/
if arg.aix > 0 then
/*R*/
arg.aix = RIGHT('+' || arg.aix, length+1)
/*R*/
else
/*R*/
arg.aix = RIGHT(arg.aix, length+1)
/*R*/
when modifier = '-' then
/*R*/
arg.aix =RIGHT(arg.aix, length+1)
/*R*/
when modifier = '0' then
/*R*/
if arg.aix > 0 then
/*R*/
arg.aix = RIGHT(arg.aix,length,'0')
/*R*/
else
/*R*/
-- Numeric digits may influence outcome here
/*R*/
arg.aix = "-"||RIGHT(-arg.aix,length-1,'0')
/*R*/
otherwise
/*R*/
arg.aix = RIGHT(arg.aix, length)
/*R*/
end
/*R*/
end
/*R*/
end
/*R*/
------------------------------ handle real numbers
/*R*/
when thistype = 'f' then
/*R*/
do
/*R*/
if VERIFY(arg.aix,"+-.0123456789") = 0 then do
/*R*/
-- remove Leading/Trailing zeroes if any
/*R*/
arg.aix = STRIP(arg.aix,"B",0)
/*R*/
-- add a decimal point if missing
/*R*/
if decimals > 0,
/*R*/
& POS('.',arg.aix) = 0 then
/*R*/
do
/*R*/
arg.aix = arg.aix||".0"
/*R*/
end
/*R*/
/*R*/
-- remove "+" if present
/*R*/
arg.arg.ix = CHANGESTR('+',arg.aix,'')
/*R*/
/*R*/
-- round the decimals if necessary
/*R*/
parse value arg.aix with . '.' decimalnumbers
/*R*/
if decimals < LENGTH(decimalnumbers) then
/*R*/
arg.aix = roundup(arg.aix,decimals)
/*R*/
/*R*/
-- add zeroes to end of decimals if needed
/*R*/
if decimals > LENGTH(decimalnumbers) then
/*R*/
arg.aix = arg.aix||LEFT('0',decimals-LENGTH(decimalnumbers),'0')
/*R*/
/*R*/
select
/*R*/
when modifier = '+' then
/*R*/
if arg.aix > 0 then
/*R*/
arg.aix = RIGHT('+'||strip(arg.aix),length+decimals+1)
/*R*/
else
/*R*/
arg.aix = RIGHT(strip(arg.aix),length+decimals+1)
/*R*/
when modifier = '-' then
/*R*/
if arg.aix > 0 then
/*R*/
arg.aix = LEFT(arg.aix,length+decimals+1)
/*R*/
else
/*R*/
arg.aix = LEFT(arg.aix,length+decimals+1)
/*R*/
when modifier = '0' then
/*R*/
if arg.aix > 0 then
/*R*/
do
/*R*/
arg.aix = CHANGESTR(" ",RIGHT(arg.aix,length+decimals+1),"0")
/*R*/
end
/*R*/
else do
/*R*/
arg.aix = CHANGESTR("-",arg.aix," ")
/*R*/
arg.aix = CHANGESTR(" ",right(arg.aix,length+decimals+1,),"0")
/*R*/
arg.aix = OVERLAY("-",arg.aix,1,1)
/*R*/
end
/*R*/
otherwise -- no modifier default is right adjust
/*R*/
if arg.aix > 0 then
/*R*/
arg.aix = RIGHT(strip(arg.aix),length+decimals+1)
/*R*/
else
/*R*/
arg.aix = RIGHT(strip(arg.aix),length+decimals+1)
/*R*/
end --select
/*R*/
end -- if VERIFY
/*R*/
end --do
/*R*/
end -- select
/*R*/
fmstring = part1 || arg.aix || fmstring
/*R*/
end -- do while POS("%",fmstring) > 0
/*R*/
/*R*/
-- handle any %% in format string
/*R*/
fmstring = CHANGESTR('19'x,fmstring,"%")
/*R*/
/*R*/
return fmstring
/*R*/
-- --------------------------------------------------
/*R*/
roundup: procedure
/*R*/
-- round number to decimals decimal places
/*R*/
use arg number, decimals
/*R*/
/*R*/
ln = LENGTH(number)
/*R*/
saved = digits()
/*R*/
if ln > saved then
/*R*/
numeric digits ln
/*R*/
/*R*/
parse value number with whole '.' rest
/*R*/
roundwith = "0."||RIGHT("5",decimals+1,"0")
/*R*/
number = number + roundwith
/*R*/
parse value number with whole '.' rest
/*R*/
/*R*/
number = whole||.||SUBSTR(rest,1,decimals)
/*R*/
number = 1 + number - 1
/*R*/
/*R*/
if ln > saved then
/*R*/
numeric digits saved
/*R*/
/*R*/
return number
/*R*/
--- end of snippet ----------------------------------
/dg
|
|
0
|
|
|
|
Reply
|
Dan
|
11/2/2007 8:49:06 PM |
|
| Dan van Ginhoven wrote:
| Hi.
|
| Mr Coffee asked for a pretty print function some time ago.
| With the handy string functions like LEFT(), Right(), Center(), Format(),
| and so on there is not much demand for such a function.
|
| In *xenix the printf() and sprintf() functions are widely used though.
| So I wrote a simple implementation of some of sprintf 's functionality.
| Please suggest improvements. I haven't got time to respond daily though.
|
| I used "classic" rexx. Would an oo approach be better?
Your code is not "classic" REXX.
-----[-----snipped-----]-----
| sprintf: procedure
| -- limited to 12 arguments presently
| -- how to change this to unlimited ???
| use arg fmstring, arg.1, arg.2, arg.3, arg.4, arg.5, arg.6,
| , arg.7, arg.8, arg.9, arg.10, arg.11, arg.12
arg fmstring
arg.=''
nargs=arg()-1 /*contains # of args not counting fmstring*/
do j=1 to nargs
arg.j=arg(j+1)
end
_____________________________________________________Gerard S.
|
|
0
|
|
|
|
Reply
|
Gerard
|
11/3/2007 12:11:57 AM
|
|
On Nov 2, 8:49 pm, "Dan van Ginhoven" <danfa...@hotmail.com> wrote:
Hi Dan,
looks good! I'm not a *xenix user, but I do have experience of a
language that includes a cut down version of sprintf. I believe that
%s should return the entire string.
I had to change your line
> say sprintf("%s %s %3.1f C %s", tdate.ix , ttime.ix, ttemp.ix, weekday )
to
say sprintf("%s %5s %3.1f C %s", tdate.ix , ttime.ix, ttemp.ix,
weekday )
in order to prevent truncation of the time after the decimal point.
Keep up the good work.
As for providing an OO version, just for information: Rick sort of
threw down a challenge to us to write a java-style formatting class
for ooRexx - I don't know whether anyone has yet taken up that
challenge.
Jon
|
|
0
|
|
|
|
Reply
|
Sahananda
|
11/4/2007 8:55:35 AM
|
|
| Jon Sahananda wrote:
|> Dan van Ginhoven wrote:
| Hi Dan,
|
| looks good! I'm not a *xenix user, but I do have experience of a
| language that includes a cut down version of sprintf. I believe that
| %s should return the entire string.
|
| I had to change your line
|> say sprintf("%s %s %3.1f C %s", tdate.ix , ttime.ix, ttemp.ix, weekday )
| to
| say sprintf("%s %5s %3.1f C %s", tdate.ix , ttime.ix, ttemp.ix,
| weekday )
| in order to prevent truncation of the time after the decimal point.
|
| Keep up the good work.
|
| As for providing an OO version, just for information: Rick sort of
| threw down a challenge to us to write a java-style formatting class
| for ooRexx - I don't know whether anyone has yet taken up that
| challenge.
Yes, I also noticed the trucation of strings (to the
length of the digits up to the decimal point).
In the following snippet of your code:
====================================================
select
------------------------------ handle strings
when thistype = 's' then
do
select
when modifier = '+' then
arg.aix = RIGHT(arg.aix,length)
when modifier = '-' then
arg.aix = LEFT(arg.aix,length)
when modifier = '0' then
arg.aix = RIGHT(arg.aix,length,'0')
otherwise
arg.aix = SUBSTR(arg.aix,1,length)
end
end
====================================================
I changed it to:
----------------------------------------------------
select /* handle strings.*/
when thistype=='s' then
select
when modifier=='+' then arg.aix=right(arg.aix,length)
when modifier=='-' then arg.aix= left(arg.aix,length)
when modifier==0 then arg.aix=right(arg.aix,length,0)
otherwise arg.aix= left(arg.aix,length)
end
----------------------------------------------------
I changed the comparators from equal to exactly equal,
eliminated the DO --- END,
change the last SUBSTR to LEFT,
and combined\ the WHEN --- THEN clauses to one line,
and did some further text alignment.
You can now see that WHEN MODIFIER is a minus sign,
it's the same as the OTHERWISE clause, so it's now:
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
select /* handle strings.*/
when thistype=='s' then
select
when modifier=='+' then arg.aix=right(arg.aix,length)
when modifier==0 then arg.aix=right(arg.aix,length,0)
otherwise arg.aix= left(arg.aix,length)
end
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
I also changed the following snippet of your code from:
===============================================================
otherwise -- no modifier default is right adjust
if arg.aix > 0 then
arg.aix = RIGHT(strip(arg.aix),length+decimals+1)
else
arg.aix = RIGHT(strip(arg.aix),length+decimals+1)
===============================================================
to:
-------------------------------------------------------------------
/*no modifier default is right adjust.*/
otherwise arg.aix=right(strip(arg.aix),length+decimals+1)
-------------------------------------------------------------------
I hope that wasn't a coding error.
Likewise, I also changed all examples in your REXX code
from xxx=substr(yyy,1,length)
to xxx=left(yyy,length)
I deleted the somewhat confusting syntax of the ommited third
argument in:
arg.aix = CHANGESTR(" ",right(arg.aix,length+decimals+1,),"0")
If now looks like:
arg.aix=changestr(" ",right(arg.aix,length+decimals+1),0)
Note that several statements that use CHANGESTR can be changed
from:
arg.aix =changestr(' ',right(arg.aix,length+decimals+1),0)
arg.aix =changestr(' ',right(arg.aix,length+decimals+1),0)
fmstring=changestr('19'x,fmstring,"%") /*handle any %% in format string*/
to the use of the TRANSLATE built-in function which is faster.
I also change the preamble of the SPRINTF procedure to:
=========================================================================
sprintf: procedure
/*----------------------------------------------------------------------+
| see Unix/C/perl sprintf documentation for general usage |
| Implemented datatypes |
| d integer |
| f float fixed decimal |
| s string |
| default none |
| |
| Implemented width modifiers |
| n length of element |
| n1.n2 |
| n1=length before decimal point including +/- default length|
| n2=number of decimal places default zero |
| decimals will be rounded to n2 positions |
| |
| Implemented modifiers |
| %% is "%" |
| + prefix postive number with "+" and right adjust |
| + right adjust string |
| - left justify number |
| - left adjust string |
| 0 right adjust zero fill for numbers and strings |
| default for strings "as is" |
| default for numbers is right adjust |
+----------------------------------------------------------------------*/
types ='dfs'
modifiers="+-0"
parse arg fmstring
org_fmstring=fmstring
arg.=
do j=1 to arg()-1
arg.j=arg(j+1)
end
=========================================================================
making the comments much easier to scan and also making the ARG.
variables now limitless.
I also made a lot of other simple changes, but I don't want to turn this
into a tome longer than the original posting. ___________________Gerard S.
|
|
0
|
|
|
|
Reply
|
Gerard
|
11/4/2007 3:47:08 PM
|
|
| Dan van Ginhoven wrote:
| Hi.
|
| Mr Coffee asked for a pretty print function some time ago.
| With the handy string functions like LEFT(), Right(), Center(), Format(),
| and so on there is not much demand for such a function.
|
| In *xenix the printf() and sprintf() functions are widely used though.
| So I wrote a simple implementation of some of sprintf 's functionality.
| Please suggest improvements. I haven't got time to respond daily though.
----snipped----
I looked at your ROUNDUP procedure (below):
====================================================
roundup: procedure
-- round number to decimals decimal places
use arg number, decimals
ln = LENGTH(number)
saved = digits()
if ln > saved then
numeric digits ln
parse value number with whole '.' rest
roundwith = "0."||RIGHT("5",decimals+1,"0")
number = number + roundwith
parse value number with whole '.' rest
number = whole||.||SUBSTR(rest,1,decimals)
number = 1 + number - 1
if ln > saved then
numeric digits saved
return number
===================================================
and reduced it to this:
---------------------------------------------------
roundup: procedure; parse arg n,ddd /*round N to DDD decimal places.*/
if length(n)>digits() then numeric digits length(n)
n=n+'0.'||right(5,ddd+1,0)
parse var n whole '.' rest
return whole'.'left(rest,1,ddd)+0
---------------------------------------------------
Is there any reason that you can't use the FORMAT
bif to accomplish the same thing (with added sign
preservation)? ______________________________Gerard S.
|
|
0
|
|
|
|
Reply
|
Gerard
|
11/4/2007 5:01:09 PM
|
|
| Dan van Ginhoven wrote:
| Hi.
|
| Mr Coffee asked for a pretty print function some time ago.
| With the handy string functions like LEFT(), Right(), Center(), Format(),
| and so on there is not much demand for such a function.
|
| In *xenix the printf() and sprintf() functions are widely used though.
| So I wrote a simple implementation of some of sprintf 's functionality.
| Please suggest improvements. I haven't got time to respond daily though.
-----[-----snipped------]-----
| -- remove "+" if present
| arg.arg.ix = CHANGESTR('+',arg.aix,'')
what did you really intend here as the
ARG.ARG.IX is never used elsewhere ?
Perhaps: arg.aix = ... _______________Gerard S.
|
|
0
|
|
|
|
Reply
|
Gerard
|
11/4/2007 5:52:26 PM
|
|
Hi Gerald!
About roundup.
Yes.I had trouble to make FORMAT() respect and use numeric settings.
Format turned numbers with more than 9 figures into E-format.
Now when I try to repeat the error it works OK.
Probably had some other bug when I tested it.
/dg
"Gerard Schildberger" <Gerard46@rrt.net> wrote in message
news:472dfa72$1@news.702com.net...
> | Dan van Ginhoven wrote:
> | Hi.
> |
> | Mr Coffee asked for a pretty print function some time ago.
> | With the handy string functions like LEFT(), Right(), Center(),
Format(),
> | and so on there is not much demand for such a function.
> |
> | In *xenix the printf() and sprintf() functions are widely used though.
> | So I wrote a simple implementation of some of sprintf 's functionality.
> | Please suggest improvements. I haven't got time to respond daily though.
>
> ----snipped----
>
> I looked at your ROUNDUP procedure (below):
>
> ====================================================
> roundup: procedure
> -- round number to decimals decimal places
> use arg number, decimals
>
> ln = LENGTH(number)
> saved = digits()
> if ln > saved then
> numeric digits ln
>
> parse value number with whole '.' rest
> roundwith = "0."||RIGHT("5",decimals+1,"0")
> number = number + roundwith
> parse value number with whole '.' rest
>
> number = whole||.||SUBSTR(rest,1,decimals)
> number = 1 + number - 1
>
> if ln > saved then
> numeric digits saved
>
> return number
> ===================================================
>
> and reduced it to this:
>
> ---------------------------------------------------
> roundup: procedure; parse arg n,ddd /*round N to DDD decimal places.*/
> if length(n)>digits() then numeric digits length(n)
> n=n+'0.'||right(5,ddd+1,0)
> parse var n whole '.' rest
> return whole'.'left(rest,1,ddd)+0
> ---------------------------------------------------
>
>
> Is there any reason that you can't use the FORMAT
> bif to accomplish the same thing (with added sign
> preservation)? ______________________________Gerard S.
>
>
>
>
|
|
0
|
|
|
|
Reply
|
Dan
|
11/4/2007 8:20:36 PM
|
|
| Dan van Ginhoven wrote:
| About roundup.
|
| Yes.I had trouble to make FORMAT() respect and use numeric settings.
| Format turned numbers with more than 9 figures into E-format.
| Now when I try to repeat the error it works OK.
| Probably had some other bug when I tested it.
| /dg
What if you would just set NUMERIC DIGITS 2000
(or some such number that would conceivably be used
as a maximum, presumably for a printout or screen
display)? _____________________________________Gerard S.
The only places it would effect performance is in the
few additions in the ROUNDUP procedure.
|> Gerard Schildberger wrote:
-----[snipped]-----
|> Is there any reason that you can't use the FORMAT
|> bif to accomplish the same thing (with added sign
|> preservation)? ______________________________Gerard S.
|
|
0
|
|
|
|
Reply
|
Gerard
|
11/4/2007 9:52:10 PM
|
|
| Jon Sahananda wrote:
|> Dan van Ginhoven wrote:
| Hi Dan,
|
| looks good! I'm not a *xenix user, but I do have experience of a
| language that includes a cut down version of sprintf. I believe that
| %s should return the entire string.
----[----snipped----]----
I fixed the problem of %s not returning the whole string (it was
finding a decimal point in the string and using that length instead).
I also re-worked most (well, ok, all) of the code, using shorter
REXX variables to make the logic fit on a single line. I removed
roughly 100 statements from the orignal code. I also removed
defaults if the default was specified or was used as a placeholder,
i.e.: xxx=right(yyy,10,)
I was having trouble visualizing the major DO loop, so I added
a prefix loop indicator (in the form of a REXX comment).
I also added a DO loop index (#) instead of incrmenting it manualy
in the code (AIX). ARG.AIX is now known as @.#
I also made each of the XTYPEs parsers into subroutines to make
the code much easier to read and you can get an overview much
simplier. I imagine you can change the code back to use the
original REXX variable names. _______________________________Gerard S.
=======================================================================
/**/ trace o; signal on novalue
tdate.1='2007-10-01'; ttime.1=07.15; ttemp.1= 5
tdate.2='2007-10-02'; ttime.2=07.14; ttemp.2= 8
tdate.3='2007-10-03'; ttime.3=07.01; ttemp.3= 11
tdate.4='2007-10-04'; ttime.4=07.14; ttemp.4= 6
tdate.5='2007-10-05'; ttime.5=07.00; ttemp.5= 5
tdate.6='2007-10-06'; ttime.6=06.48; ttemp.6= 2
tdate.7='2007-10-07'; ttime.7=07.15; ttemp.7= -1.5
tdate.8='2007-10-08'; ttime.8=07.14; ttemp.8= -2.5
tdate.9='2007-10-09'; ttime.9=07.21; ttemp.9= +3.599
tdate.0=9
say sprintf("%-10s %+9s %6s %s", ' date ',"dayofweek"," time", 'temperature')
say sprintf("%-10s %+9s %6s %s", '----------',"---------","-----", '-----------')
if 'f0'x==0 then degc='a1'x /*if EBCDIC, then use x'a1'. */
degc='f8'x /*if ASCII, then use x'f8'. */
degc=degc'C' /*append C to the degree symbol*/
do j=1 to tdate.0
_=j//7
select /*calc DayOfWeek, this is data dependent.*/
when _==0 then weekday='Sunday'
when _==1 then weekday='Monday'
when _==2 then weekday='Tuesday'
when _==3 then weekday='Wednesday'
when _==4 then weekday='Thursday'
when _==5 then weekday='Friday'
when _==6 then weekday='Saturday'
end
say sprintf("%-10s %+9s %6s %5.1f" degc,tdate.j,weekday,ttime.j,ttemp.j)
end
exit 0
sprintf: procedure; parse arg y
/*----------------------------------------------------------------------+
| see Unix/C/perl sprintf documentation for general usage|
| Implemented datatypes |
| d integer |
| f float fixed decimal |
| s string |
| default none |
| |
| Implemented width modifiers |
| n length of element |
| n1.n2 |
| n1=length before decimal point including +|- default length|
| n2=number of decimal places, default zero |
| decimals will be rounded to n2 positions |
| |
| Implemented modifiers |
| %% is "%" |
| + prefix postive number with "+" and right adjust |
| + right adjust string |
| - left justify number |
| - left adjust string |
| 0 right adjust zero fill for numbers and strings |
| default for strings "as is" |
| default for numbers is right adjust |
+----------------------------------------------------------------------*/
/* handle any %% in format string. */
/* '19'x isn't on keyboards in most countries*/
y=changestr("%%",y,'19'x)
@.='' /*nullify all @. (args)*/
types ='dfs' /*this is case sensitive.*/
modifiers='+-0'
do j=1 to arg() /*tokenize all possible arguments, no limit. */
@.j=arg(j+1) /*assign the argument to an array element. */
w.j=length(@.j) /*also, compute the length of the argument. */
end
/*#*/ do #=1 while pos('%',y)\==0 /*process each % in y.*/
/*#*/ parse var y part1 '%' y
/*#*/
/*#*/ /*the 1st pos in y is a modifier[+-0], a */
/*#*/ /*width [n[.n]] or a type [dfs] in this order.*/
/*#*/ mof=''
/*#*/ if pos(left(y,1),modifiers)\==0 then parse var y mof 2 y
/*#*/ nextpos=99999
/*#*/
/*#*/ /*is there anything before types [dfs] ? */
/*#*/ /*loop over types & find the 1st data type modifier pos.*/
/*#*/
/*#*/ do jj=1 to length(types)
/*#*/ _=pos(substr(types,jj,1),y)
/*#*/ if _\==0 & _<nextpos then nextpos=_
/*#*/ end
/*#*/
/*#*/ if nextpos==0 then return 'Unknown type format:' arg(1)
/*#*/ xtype=substr(y,nextpos,1)
/*#*/
/*#*/ if nextpos>1 then width=left(y,nextpos-1)
/*#*/ else do
/*#*/ if xtype=='s' then width=w.#
/*#*/ else width=min(w.#,pos('.',@.#))
/*#*/ if xtype=='d' & mof=='+' then width=width+1
/*#*/ end
/*#*/
/*#*/ y=substr(y,nextpos+1)
/*#*/ parse var width len '.' decs
/*#*/ if len=='' then len=min(w.#,pos('.',@.#))
/*#*/ if decs=='' then decs=0
/*#*/
/*#*/ select
/*#*/ when xtype=='s' then @.#=sprintf_s()
/*#*/ when xtype=='d' then @.#=sprintf_d()
/*#*/ when xtype=='f' then @.#=sprintf_f()
/*#*/ end
/*#*/
/*#*/ y=part1 || @.# || y
/*#*/ end
y=translate(y,'%',"19"x) /*handle any %% in format string*/
return y
sprintf_s: /*--------------------------------------------------strings*/
if mof=='+' then return right(@.#,len)
if mof==0 then return right(@.#,len,0)
return left(@.#,len)
sprintf_d: /*-------------------------------------------------integers*/
if verify(@.#,'+-0123456789')\==0 then return @.#
@.#=strip(@.#,'L',0)
if mof=='+' then if @.#>0 then return right('+'@.#,len+1)
else return right(@.#,len+1)
if mof=='-' then return right(@.#,len+1)
if mof==0 then if @.#>0 then return right(@.#,len,0)
else return @.#='-'right(-@.#,len-1,0)
return right(@.#,len)
sprintf_f: /*----------------------------------------------------reals*/
if verify(@.#,'+-.0123456789')\==0 then return @.#
@.#=strip(@.#,,0) /*remove leading/trail zeroes if any*/
if decs>0 & pos('.',@.#)==0 then @.#=@.#'.0' /*no period? Add one*/
@.#=strip(@.#,'L',"+") /*remove leading + if present.*/
parse var @.# '.' dn
if decs<length(dn) then @.#=roundup(@.#,decs) /*round if necessary.*/
if decs>length(dn) then @.#=@.#||left(0,decs-length(dn),0) /*append 0s*/
if mof=='+' then if @.#>0 then return right('+'strip(@.#),len+decs+1)
else return right(strip(@.#),len+decs+1)
if mof=='-' then if @.#>0 then return left(@.#,len+decs+1)
else return left(@.#,len+decs+1)
if mof==0 then if @.#>0 then return translate(right(@.#,len+decs+1),0)
else return sprintf_o()
return right(strip(@.#),len+decs+1) /*no mod, right justify.*/
sprintf_o: @.#=translate(@.#,,'_') /*trans underbars to blanks.*/
@.#=right(@.#,len+dec+1,0) /*add leading zeroes. */
return overlay('-',@.#) /*leading char to a minus. */
roundup: procedure; parse arg n,ddd /*round N to DDD decimal places.*/
if length(n)>digits() then numeric digits length(n)
n=n+'0.'right(5,ddd+1,0); parse var n whole '.' fract
return whole'.'left(fract,1,ddd)+0
==========================================================================
|
|
0
|
|
|
|
Reply
|
Gerard
|
11/5/2007 2:49:57 AM
|
|
In Message-ID:<472e847a@news.702com.net>,
"Gerard Schildberger" <Gerard46@rrt.net> wrote:
>if 'f0'x==0 then degc='a1'x /*if EBCDIC, then use x'a1'. */
> degc='f8'x /*if ASCII, then use x'f8'. */
I like this technique for the program to decide EBCDIC vs.
ASCII. But aren't you missing an "else"?
--
Arthur T. - ar23hur "at" intergate "dot" com
Looking for a z/OS (IBM mainframe) systems programmer position
|
|
0
|
|
|
|
Reply
|
Arthur
|
11/5/2007 3:11:21 AM
|
|
| Arthur T. wrote:
|> Gerard Schildberger wrote:
|
|>if 'f0'x==0 then degc='a1'x /*if EBCDIC, then use x'a1'. */
|> degc='f8'x /*if ASCII, then use x'f8'. */
| I like this technique for the program to decide EBCDIC vs.
| ASCII. But aren't you missing an "else"?
To quote many a REXX programm, "oh crap!" __________________Gerard S.
|
|
0
|
|
|
|
Reply
|
Gerard
|
11/5/2007 5:50:21 AM
|
|
Thanks Gerard!
You have done a great job ( and had all the fun I hope).
I had to change your variable names @, and #
since oorexx does not include these in Symbol names.
I don't agree with the need to have as few lines as possible, unless I 'm on
a mainframe editor.
Personaly I'd rather have a greater readability, adding blank lines and so
on.
Again, thanks!
/dg
|
|
0
|
|
|
|
Reply
|
Dan
|
11/5/2007 5:43:53 PM
|
|
| Dan van Ginhoven:
| Thanks Gerard!
|
| You have done a great job ( and had all the fun I hope).
|
| I had to change your variable names @, and #
| since oorexx does not include these in Symbol names.
|
| I don't agree with the need to have as few lines as possible, unless I 'm on
| a mainframe editor.
| Personaly I'd rather have a greater readability, adding blank lines and so
| on.
|
| Again, thanks!
I didn't reduce the number of lines just for the sake of
reduction, but to get more code on a "screen" so I could
get a better visualize the overall code flow, for a lack
of a better term. I use a PC (with KEDIT) with a 50x80
screen.
In my version of KEDIT, that's the maximum screen size
that is supported. Bummer. I also don't have a printer,
so making a hardcopy is out. It's the screen viewing
or nothing.
By making the REXX variables shorter, I was able to
condense a lot of
IF ... THEN DO ... END ELSE DO ... END statements
to fewer lines, especially where the DO ... END was
just one REXX clause, or the REXX clause followed the
THEN on the next line (same with the ELSE clause).
It's more different to follow someone else's logic than
if I had originaly written the code, so I had a steeper
steeper learning curve to come up to speed. That was
one main reason that I broken part of the parsing into
subroutines. In my old(er) age, the amount of code I
can "hold" in my head is getting more and more
miniscule, soon I will be down to holding parts of a
clause, heaven help me if it continues on another line.
Now that I understand (I think I do, that is) what the
code is doing and how it's doing it, I could go back
and make the variable names more descriptive and add a
lot more white space everywhere (not to mention block
style comments, sometimes called flower boxes).
It was a fun project. _____________________________Gerard S.
|
|
0
|
|
|
|
Reply
|
Gerard
|
11/5/2007 7:25:49 PM
|
|
Hello G.
I did a few changes to your code.
1. I saved the original string y:
errmsg = y
2. In order to have an error message in
select
when xtype == 's' then arg.ix = sprintf_s()
when xtype == 'd' then arg.ix = sprintf_d()
when xtype == 'f' then arg.ix = sprintf_f()
otherwise return "invalid modifier in" errmsg --DG
end
3. I added one line for the case when there is no length modifier and no
decimalpoint (Integer)
y = substr(y,nextpos+1)
parse var width len '.' decs
if len == '' then len=min(w.ix,pos('.',arg.ix))
if len == 0 then len=length(arg.ix) --DG
if decs == '' then decs=0
4. At the end of sprintf_f: translate needed tableo, tablei
if mof == 0 then if arg.ix > 0 then return
translate(right(arg.ix,len+decs+1),'0',' ') --DG
else return sprintf_o()
5. A few changes here
sprintf_o:
arg.ix = strip(translate(arg.ix,,'-')) --DG (not underscore)
/* trans minus to blanks and strip spaces*/
arg.ix = right(arg.ix,len + decs + 1,0) --DG decs replaced dec /*
add leading zeroes. */
return overlay('-',arg.ix)
/* leading char to a minus. */
6. in sprintf_d:
if mof == 0 then if arg.ix > 0 then return right(arg.ix,len,0)
else return '-'right(-arg.ix,len-1,0) --DG
removed arg.ix =
Tested with the below variations, it works OK:
say "------------------------------------------------------------"
say " 1 2 3 4 5 6"
say "1234+6789+1234+6789+1234+6789+1234+6789+1234+6789+1234+6789+"
say sprintf("%%+3s<%+3s>", "abcdefg")
say sprintf("%%+13s<%+13s>", "abcdefg")
say sprintf("%%-3s<%-3s>", "abcdefg")
say sprintf("%%-13s<%-13s>", "abcdefg")
say sprintf("%%013s<%013s>", "abcdefg")
say " "
say sprintf("%%d <%d>",4096)
say sprintf("%%d <%d>",-4096)
say sprintf("%%+d <%+d>",4096)
say sprintf("%%+d <%+d>",-4096)
say sprintf("%%3d <%3d>",00004096)
say sprintf("%%16d <%16d>",1234567890123456)
say sprintf("%%8d <%8d>",4096)
say sprintf("%%08d <%08d>",4096)
say sprintf("%%08d <%08d>",-4096) -- 1
say sprintf("%%-8d <%-8d>",4096)
say sprintf("%%-8d <%-8d>",-4096)
say sprintf("%%0d <%0d>",4096)
say sprintf("%%0d <%0d>",-4096)
say " "
say "------------------------------------------------------------"
say " 1 2 3 4 5 6"
say "1234+6789+1234+6789+1234+6789+1234+6789+1234+6789+1234+6789+"
say sprintf("%%f :%f",4096.1024)
say sprintf("%%f :%f",4096.599)
say sprintf("%%6.1f :%6.1f",4096.1024)
say sprintf("%%6.6f :%6.6f",4096.1024)
say sprintf("%%+6.6f :%+6.6f",4096.1024)
say sprintf("%%-6.6f :%-6.6f",-4096.1024)
say sprintf("%%+6.6f :%+6.6f",124096.1024)
say sprintf("%%-6.6f :%-6.6f",-124096.1024)
say sprintf("%%010.6f :%010.6f",6789.1024)
say sprintf("%%010.6f :%010.6f",-6789.1024)
say sprintf("%%+7.6f :%+7.6f",123456.1024)
say sprintf("%%+7.6f :%+7.6f",-123456.1024)
say sprintf("%%+7.2f :%+7.2f",-123456.4555)
say sprintf("%%+7.2f :%+7.2g",-123456.4555) /* invalid modifier */
/dg
|
|
0
|
|
|
|
Reply
|
Dan
|
11/5/2007 8:01:42 PM
|
|
| Dan van Ginhoven wrotea:
| Hello G.
|
| I did a few changes to your code.
|
| 1. I saved the original string y:
| errmsg = y
(see below).
| 2. In order to have an error message in
| select
| when xtype == 's' then arg.ix = sprintf_s()
| when xtype == 'd' then arg.ix = sprintf_d()
| when xtype == 'f' then arg.ix = sprintf_f()
| otherwise return "invalid modifier in" errmsg --DG
| end
There is no need to "save" the original string Y as it can be
referenced as ARG(1) ______________________________Gerard S.
| 3. I added one line for the case when there is no length modifier and no
| decimalpoint (Integer)
| y = substr(y,nextpos+1)
| parse var width len '.' decs
| if len == '' then len=min(w.ix,pos('.',arg.ix))
| if len == 0 then len=length(arg.ix) --DG
| if decs == '' then decs=0
|
| 4. At the end of sprintf_f: translate needed tableo, tablei
It only needs one of them, if any of tableo or tableei (but not
both) is ommitted, blanks are assumed. __________________Gerard S.
| if mof == 0 then if arg.ix > 0 then return
| translate(right(arg.ix,len+decs+1),'0',' ') --DG
| else return sprintf_o()
|
| 5. A few changes here
| sprintf_o:
| arg.ix = strip(translate(arg.ix,,'-')) --DG (not underscore)
Another case of bad (old) eyes. Well, it was close (but no cigar).
| /* trans minus to blanks and strip spaces*/
| arg.ix = right(arg.ix,len + decs + 1,0) --DG decs replaced dec /*
| add leading zeroes. */
| return overlay('-',arg.ix)
| /* leading char to a minus. */
|
| 6. in sprintf_d:
| if mof == 0 then if arg.ix > 0 then return right(arg.ix,len,0)
| else return '-'right(-arg.ix,len-1,0) --DG
| removed arg.ix =
|
| Tested with the below variations, it works OK:
| say "------------------------------------------------------------"
| say " 1 2 3 4 5 6"
| say "1234+6789+1234+6789+1234+6789+1234+6789+1234+6789+1234+6789+"
| say sprintf("%%+3s<%+3s>", "abcdefg")
| say sprintf("%%+13s<%+13s>", "abcdefg")
| say sprintf("%%-3s<%-3s>", "abcdefg")
| say sprintf("%%-13s<%-13s>", "abcdefg")
| say sprintf("%%013s<%013s>", "abcdefg")
| say " "
| say sprintf("%%d <%d>",4096)
| say sprintf("%%d <%d>",-4096)
| say sprintf("%%+d <%+d>",4096)
| say sprintf("%%+d <%+d>",-4096)
| say sprintf("%%3d <%3d>",00004096)
| say sprintf("%%16d <%16d>",1234567890123456)
| say sprintf("%%8d <%8d>",4096)
| say sprintf("%%08d <%08d>",4096)
| say sprintf("%%08d <%08d>",-4096) -- 1
| say sprintf("%%-8d <%-8d>",4096)
| say sprintf("%%-8d <%-8d>",-4096)
| say sprintf("%%0d <%0d>",4096)
| say sprintf("%%0d <%0d>",-4096)
|
| say " "
| say "------------------------------------------------------------"
| say " 1 2 3 4 5 6"
| say "1234+6789+1234+6789+1234+6789+1234+6789+1234+6789+1234+6789+"
| say sprintf("%%f :%f",4096.1024)
| say sprintf("%%f :%f",4096.599)
| say sprintf("%%6.1f :%6.1f",4096.1024)
| say sprintf("%%6.6f :%6.6f",4096.1024)
| say sprintf("%%+6.6f :%+6.6f",4096.1024)
| say sprintf("%%-6.6f :%-6.6f",-4096.1024)
| say sprintf("%%+6.6f :%+6.6f",124096.1024)
| say sprintf("%%-6.6f :%-6.6f",-124096.1024)
| say sprintf("%%010.6f :%010.6f",6789.1024)
| say sprintf("%%010.6f :%010.6f",-6789.1024)
| say sprintf("%%+7.6f :%+7.6f",123456.1024)
| say sprintf("%%+7.6f :%+7.6f",-123456.1024)
| say sprintf("%%+7.2f :%+7.2f",-123456.4555)
| say sprintf("%%+7.2f :%+7.2g",-123456.4555) /* invalid modifier */
|
|
0
|
|
|
|
Reply
|
Gerard
|
11/5/2007 8:34:34 PM
|
|
....
And 7.
Your version of Roundup does not round but truncate the decimals.
and it does not handle zero decimals.
No solution.
Bedtime.
/dg
|
|
0
|
|
|
|
Reply
|
Dan
|
11/5/2007 8:55:42 PM
|
|
>And 7.
> Your version of Roundup does not round but truncate the decimals.
8. Rounding XOR truncating won't do, try sprintf("%1.1f %1.1f",1.25,1.35)
which fails with Format()-like rounding XOR Left()-like truncating.
The output should read "1.2 1.4".
9. Why *s*printf(), it's printf() formatting.
10. Why sprintf() numbers the original sprintf() cannot store?
---
|
|
0
|
|
|
|
Reply
|
spamgate
|
11/5/2007 11:59:49 PM
|
|
> try sprintf("%1.1f %1.1f",1.25,1.35)
Snafu. Try this instead:
This should sprint 7.32:
f=7.325
sprintf("%1.2f",f)
This should sprint 7.33:
f=7.32501
sprintf("%1.2f",f)
---
|
|
0
|
|
|
|
Reply
|
spamgate
|
11/6/2007 12:49:42 AM
|
|
|
17 Replies
197 Views
(page loaded in 0.178 seconds)
Similiar Articles: Removing insignificant decimal characters? - comp.lang.php ...What I can't grog is how to make the insignificant .00 to not print. The way I read the sprintf ... 22/7 = 3.1429 > 22/11 = 2 > > $result = 22/7; > > > Pretty neat. Regex to match a numerical IP range - comp.lang.perl.misc ...Its workings are not at all that obvious and its pretty ... [99-110, 180, 182] . *' ); print "Testing Ip range ... if ( defined $1 ) { die sprintf( $msg, 'quad ... filling left side of string - comp.lang.awkYou need printf() or sprintf(), depending on what you do with the padded number. ... But I need to use the variable in comparing function not in printing. So with the set ... Tessellation of irregular shapes - comp.soft-sys.matlabOK, it's pretty easy but in case you have trouble with your code ... numCircles, 2) = col; circleData(numCircles, 3) = radius; % Print it out. message = sprintf ... fread and float - comp.soft-sys.matlab... you mean the actual bit-banging itself, that's pretty ... doc sprintf % '%x' might be of interest ... Default Decimal separator for float parsing and printing ... nth day of the year? - comp.lang.awkBEGIN{d="2005 11 24 0 0 0"; print strftime("%j", mktime ... 2) Around here, in c.l.a., GAWK is pretty much the ... 3) { y = y - 1 m = m + 12 } ymd = sprintf("%d ... How to extract pixel values of a colored image into an array and ...Hi all I am pretty new in Matlab. Plz help me with the ... map); > > > % Give it a caption. > > caption =3D sprintf ... Then, Print, image ... extract pixel values ... inch to millimeter in matlab - comp.soft-sys.matlab... the original poster should > multiply by 254, sprintf ... new user of Matlab, so I guess this one should be pretty ... Print to PDF - comp.soft-sys.matlab ... Hi, I'm starting ... How do I create a Multi-page Invoice - comp.databases.filemaker ...> Hi, In Filemaker, you can print invoices that will ... In the create function I tried, str = sprintf('Overplot ... This pretty well needs to be done using Access ... ptr versus const ptr& - comp.lang.c++.moderatedOne final note: boost::intrusive_ptr does pretty much all that your pointer does and ... crash before the assertion, it might not crash at all, your assertion might print ... How to write a degree sign - comp.lang.fortranAlthough nowadays people use pretty much what suits them ... of read(..., POS=...) - comp.lang.fortran ..... sprintf ... degree' character - comp.unix.solaris ... How to print ... Pretty print - Virtual building 8It tries to pretty print the data on a single line. In the context of this function, if the strings built by the function "sprintf" (see below) contain newlines or ... sprintf now available - Application Forum at ObjectMix.comsprintf now available - REXX . This is a discussion on sprintf now available ... Pretty print sprintf() 7/28/2012 10:49:18 PM
|