printf.exe: Arithmetic and Programming

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

printf.exe: Arithmetic and Programming

#1 Post by Aacini » 25 Jul 2016 19:26

I recently remembered a new .exe auxiliary program I completed a couple months ago, so I decided to post it now. It is called printf.exe and is a double-purpose program: emulate the printf C function in order to show formatted output of strings and numbers, and evaluate arithmetic expressions of 32/64-bits integers and floating point numbers. This program don't really emulate printf C function, but it is just a wrapper for it: the program take the parameters and accomodate they in the stack that is used to invoke any Windows API function; then, just invoke the Windows C run-time printf function.

To evaluate arithmetic operations I used the same stack and just get the numbers from it, perform the operation in RPN (postfix) notation and store the result back in the stack! For example: printf "format" 1 2 3 have 3 numeric parameters: 1, 2 and 3; and printf "format" 1 2 3 + 4 have also 3 numeric parameters: 1, 5 (the sum of 2+3) and 4. 8) This scheme makes possible that the program be not too complex; as a matter of fact, the most complicated part was the reading of numbers and its conversion into the appropriate internal format (I also just copied the floating point routines from another larger project I am currently developing). :P

In order to successfully use this program you must comprehend that printf.exe is a strongly typed application. The C printf function is very strict in the types of the arguments indicated in the format specification string vs. the real type of the parameters: if these types not match, or there are more format specifications than parameters, the result is "unpredictable" (as the documentation said), so non sense results may be displayed or even a Windows run-time error may occur.

This restriction is automatically transferred into printf.exe program, because it just invoke the exact same function. However, this strict rule is also applied in the arithmetic operations! You must give first one or two numbers with a given type (integer or float) and then an operator that match the type of previous numbers; this point not only means that there are two separate sets of operators for integer and floating-point numbers, but that even in certain integer operations the numbers must be both of 64-bits, both of 32-bits, or the first one 64-bits and the second one 32-bits! :shock: This is done to perform the operations in the exact same way they are achieved in the CPU, so no previous nor posterior conversions be necessary. Of course, all these rules imply that printf.exe program is somewhat difficult to use at first, but if the program would be designed to be more tolerant and perform type conversions automatically (like many compilers and interpreters) the resulting program would be much larger and complex, and I never would started to write it. :(

You may download printf.exe auxiliary program and the two next companion files from this printf.zip attached file:
printf.zip
(9.25 KiB) Downloaded 1081 times
This is printf.txt:

Code: Select all

Emulates printf C run-time function; evaluates RPN arithmetic expressions.

    printf "format specification" {number [operator]|'c'|"string"|variable} ...

This program is a wrapper for the C run-time printf function described at
https://msdn.microsoft.com/en-us/library/wc7014hz.aspx
so all specifications and requirements described at that site apply.

Additionally, this program evaluates arithmetic expressions in RPN.


The first parameter is a standard printf format specification given as
"string literal" or in a Batch variable. This is a quick reference guide of it:

                 %[flags][width][.precision][size]type
                   -+ 0#  -----  ----------  ---- cCdiouxXeEfgGaAps
Insert "ll"        - | left align                 c | character
in [size]          + | insert + sign if positive  C | wide (16 bits) Character
for 64-bits          | insert space for + sign    d | integer (Decimal)
"long-long"        0 | zero pad                   i | Integer = d
integers.          # | insert . in g type, or     o | integer (Octal)
                     | insert 0|0x in o|x types   u | integer (Unsigned)
                                                  x | integer (hexadecimal)
[width]  Minimum/total width (no truncate):       X | integer (HEXADECIMAL)
printf "%05i" 3  =  "00003"                       e | double  ([-]d.ddddeñddd)
                                                  E | double  (like e, with E)
[.precision]  Maximum width (truncate/round):     f | double  ([-]ddd.dddddd)
printf "%.4f" 3.141592654 = "3.1416"              g | double  (shorter of f|e)
                                                  G | double  (like g, with E)
An asterisk in place of width and/or precision    a | double  ([-]0xh.hhhpñddd)
get its value from the next (int) parameter:      A | double  (like a, with P)
printf "%0*i" 5 3  =  "00003"                     p | string  (address in hex)
printf "%0*.*f" 8 4 3.141592654 = "003.1416"      s | string

String literals can not include embedded quotes, but Batch variables can.
Standard control characters \n \r \t \a \b are valid in string literals only;
to insert control characters in a format specification stored in a variable,
use %c format with the Ascii code of the character given as int. For example:
   printf "Line one\n\t\tLine two\n"
   set "format=Line one%c%c%cLine two%c"
   printf format       10 9 9        10


The parameters after the first one can be of one of these types:
- A number, if it start in digit or minus sign.
- A character, if it is enclosed in apostrophes (managed as a 32-bits integer).
- A string literal, if it is enclosed in quotes.
- A string Batch variable otherwise.

Numbers are converted into one of the following sub-types:
- A double-precision 64-bits floating-point number if it includes a decimal
  point or an exponent of ten greater than 0 (standard floating-point format).
- A "long-long" 64-bits integer number if its value exceed the maximum of a
  32-bits integer one, or if the number ends in "ll" size specification.
- A 32-bits integer number otherwise.
An integer number may be given in the standard octal/hexadecimal notation;
the largest integer may have: {18 decimal|16 hexadecimal|21 octal} digits.

--> If the format specifications does not match the type of the parameters,
    or there are more specifications than parameters, this program may fail.


Arithmetic operations in Reverse Polish Notation (RPN) may be evaluated via
two *separate sets* of operations for integer and floating-point numbers.
Reference: https://en.wikipedia.org/wiki/Reverse_Polish_notation
You may learn RPN at: http://www.hpmuseum.org/rpn.htm
or in this extensive tutorial: http://hansklav.home.xs4all.nl/rpn/index.html


Most integer operations works on 64-bits numbers. One-operand operators:
! BoolNot, ~ BitNot, _ ChngSign, $ Signum, ] Store, [ Recall, @ Dup, ? Random.
Two-operands operators: + Add, - Subtract, * Multiply, / Quotient, % Remainder,
< Min, > Max, << BitSHL, >> BitSHR, & BitAnd, | BitOr, ^ BitXor, # Exchange.

The * operator multiply two 32-bits numbers and produce a 64-bits result.
In / % << >> operators the second operand must be a 32-bits number. Quotient
and Remainder produce a 32-bits result; if the divisor is zero, these operators
return the high or low 32-bits part of the number, respectively. If "u" letter
is added after * / % << >> operators, an unsigned operation is performed.
The ? operator enter a random number between 0 and 32767 as a 32-Bits number.

To convert a 32-bits number to a 64-bits one, multiply it by 1:
printf "Random as 32-bits: %i. Random as 64-bits: %lli.\n"  ?  ? 1 *
To convert a 64-bits number to a 32-bits one, get its remainder by 0:
printf "Random as 64-bits: %lli, and as 32-bits: %i.\n"  ? 1 *  @  0 %


Floating-point functions operate float numbers *only*. One-operand functions:
NOT, CHS, ABS, SIGN, INT, FRAC, INV, X^2, SQRT; SIN, COS, TAN, ASIN, ACOS, ATAN
(in radians), to DEGrees, to RADians; LN, LOG, EXP, EXPT; DUP, STO.   RCL, PI.
Two-operands functions: ADD, SUB, MUL, DIV, MOD, POW, MAX, MIN, XCHG.   CLST.

Float operations use the FPU stack, so a run-time error is never issued: the
"special values" defined in IEEE 754 floating-point specification are returned.
Reference: https://en.wikipedia.org/wiki/Floating_point#Special_values
FRAC, TAN, ASIN, ACOS, ATAN, LN, LOG, EXP, EXPT require one empty FPU register.


--> If numbers and operator types don't match (32-bits int/64-bits int/float),
    or there are not enough numbers for an operation, this program will fail.


A couple simple examples:
printf "3 plus 5 = %lli, 3 minus 5 = %lli\n"  3ll 5ll +  3ll 5ll -
printf  "The result of (4+5)/(6+7) is: %f\n"  4. 5. Add 6. 7. Add Div

The $ Signum operator used after a subtract allows to perform comparisons:
%A%ll %B%ll - $  = -1 if A < B, 0 if A == B, 1 if A > B. After that:
     1ll + !     =  1 if A < B, 0 if A >= B; OR
     1ll - !     =  1 if A > B, 0 if A <= B.
%A%ll %B%ll - !  =  1 if A == B, 0 if A != B.

If the [.precision] part in a string format is zero, the string parameter is
not shown. This part can be calculated and passed to a format specification via
an asterisk, so another string can be conditionally shown, like a message. Note
that Remainder by zero is used to convert a 64-bits number to a 32-bits one:
set /A A=%random%, B=%random%
printf "%i is%.*s less %i" %A%  %A%ll %B%ll - $ 1ll - ! 0 % 4 * 0 % " not"  %B%

More examples on most operators/functions are shown in:  printf-Examples.bat


==> Remember: One-character operators works on integer numbers; three letters
              functions works on floating-point numbers. Do NOT mix they!


At end, the total number of characters shown is returned in ERRORLEVEL.
If an error is found, a negative value is returned this way:

-1 = printf function internal error
-2 = Closing quote/apostrophe missing or bad placed
-3 = Number wrong or too large
-4 = Invalid operator
-5 = Invalid function or undefined variable

This is printf-Examples.bat:

Code: Select all

@echo off
setlocal

rem Show several examples on printf.exe auxiliary program usage
rem Antonio Perez Ayala

rem Do NOT use 'more' on the output of this Batch file

mode CON: COLS=80 LINES=200
set "prompt=%~D0\> "
cls
echo on

rem Example session on printf.exe program features.

printf "A char: %%c, a string: %%s, an int: %%i, a float: %%f\n"  ^
                                 'X'       "Hello"         123      456.789

rem The format specification may be stored in a variable, with quotes,
rem but in this case the standard control characters can not be used:
set "format=A char: '%%c', a string: "%%s", an int: %%i, a float: %%f%%c"
printf format 'X' "Hello" 123 456.789  10

rem Characters are managed as 32-bits integers:
printf "Ascii code of '%%c' is %%i, char. of code %%i is '%%c'" 'A' 'A' 97 97

rem Management of 64-bits "long-long" integers:
printf "Wrong: int1: %%i, long-long1: %%i, long-long2: %%i, int2: %%i\n"  ^
                              123      9876543210           456ll       789
printf "Right: int1: %%i, long-long1: %%lli, long-long2: %%lli, int2: %%i\n"  ^
                          123        9876543210             456ll       789

rem Large integers and octal/hexadecimal notations:
printf "Dec: %%lld, Hex: %%lld, Oct: %%lld\n"  ^
                                    123456789012345678        0x123456789ABCDEF0    0123456712345671234567

rem Octal/hexadecimal output formats:
printf "Dec: %%lld, Hex: %%#llX, Oct: %%#llo\n"  ^
                                  123456789012345678       0x123456789ABCDEF0       0123456712345671234567

rem Largest signed and unsigned 64-bits integer numbers:
printf "Largest positive: %%lld, largest unsigned: %%llu\n"  ^
                                 0x7FFFFFFFFFFFFFFF      0xFFFFFFFFFFFFFFFF

rem Some examples of Reverse Polish Notation expressions:

printf "Number: %%lli, result: %%lli, number: %%lli"  12ll  34ll 56ll +  78ll

printf "Change sign of %%lli is equal to BitNOT the number plus 1: %%lli\n"  ^
                         12345ll                @ ~               1ll     +
printf "Max positive product: %%lli (%%#llX)\n" 0x7FFFFFFF 0x7FFFFFFF * @
printf "Max unsigned product: %%llu (%%#llX)\n" 0xFFFFFFFF 0xFFFFFFFF *u @
printf "%%lli divided by %%i is %%i plus %%i in remainder\n"  ^
                   123456789012345 ]     100000  [ 100000 /  [ 100000 %%

for /F "tokens=3" %%a in ('dir') do @set "free=%%a"
set "free=%free:,=%"
echo The free space on disk is:
printf "%%lld B = %%lld KB (+%%lldB) = %%lld MB (+%%lldKB) = %%lld GB (+%%lldMB)\n"  ^
%free%ll ] [ 0x3FFll ^& [ 10 ^>^> ] # [ 0x3FFll ^& [ 10 ^>^> ] # [ 10 ^>^> [ 0x3FFll ^&

rem Trick to avoid to escape all those special characters:
set "format=The free space on disk is:%%c%%lld B = %%lld KB (+%%lldB) = %%lld MB (+%%lldKB) = %%lld GB (+%%lldMB)%%c"
for /F "delims=" %%a in ("printf format 10 %free%ll ] [ 0x3FFll & [ 10 >> ] # [ 0x3FFll & [ 10 >> ] # [ 10 >> [ 0x3FFll & 10") do %%a

rem Example taken from:
rem http://stackoverflow.com/questions/35767361/
rem a-number-is-both-greater-and-less-than-another-in-a-windows-batch-file
set bakfilesize=399502220288
set freespace=463777075200
printf "baksize is %%.*s%%.*s\n" %bakfilesize% %freespace% - $ 1ll - ! ]  ^
   0 %% 6 * 0 %% "larger" [ ! 0 %% 16 * 0 %% "smaller or equal"

rem =======================
rem Floating point examples

printf "The result of (4+5)/(6+7) is: %%f\n"  4. 5. Add 6. 7. Add Div

printf "Square root(2)=%%f, Cubic root(64)=%%g, e=%%f, Sin(30)=%%g\n"  ^
                               2. Sqrt     64. 3. Inv Pow  1. Exp   30. Rad Sin

set /A X=4,Y=3
printf "Rectangular (X=%%i, Y=%%i) is Polar (Angle=%%g, Magnitude=%%g)\n"  ^
        %X% %Y%    %Y%. %X%. Div ATan Deg    %X%. X^^2 %Y%. X^^2 Add Sqrt

rem Some special values of the IEEE 754 floating-point specification:
printf "Minus zero: %%g, Infinite: %%g, NotANumber: %%g\n"  ^
                                   -1. 0. Mul     1. 0. Div        -2. Sqrt

rem Up to 8 floating-point numbers can be entered in the FPU stack:
printf "Enter 8 numbers: %%g %%g %%g %%g %%g %%g %%g %%g\n"  ^
                                                    1. 2. 3. 4. 5. 6. 7. 8.

rem If more numbers are entered, a FPU stack *error condition* happen:
printf "Enter 9 numbers: %%g %%g %%g %%g %%g %%g %%g %%g %%g\n"  ^
                                                 1. 2. 3. 4. 5. 6. 7. 8. 9.

rem ... or if the 8th number have a fractional part or exponent NEQ 0:
rem (because in this case an additional Power function must be performed)
printf "8th number use Pow function: %%g %%g %%g %%g %%g %%g %%g %%g\n"  ^
                                                    1. 2. 3. 4. 5. 6. 7. 8.5

rem The next functions cause the same error when the stack is full:
rem (because they use one additional FPU register to achieve its result)
rem     Frac, Tan, ASin, ACos, ATan, Ln, Log, Exp, ExpT
printf "Frac on 7th number OK: %%g %%g %%g %%g %%g %%g %%g\n"  ^
                                                       1. 2. 3. 4. 5. 6. 7.5 Frac
printf "Frac on 8th number fail: %%g %%g %%g %%g %%g %%g %%g %%g\n"  ^
                                                    1. 2. 3. 4. 5. 6. 7. 8.5 Frac

rem In order to *display* more numbers, use CLST (CLearSTack) function:
printf "Display 10 numbers: %%g %%g %%g %%g %%g %%g %%g %%g %%g %%g\n"  ^
                                              1. 2. 3. 4. 5. 6. 7. CLST 8.5 9. 10.
Enjoy it!!! :D :mrgreen:

---------------------------------------------------------------------

A completely new version of printf.exe is here! The new printf.exe version 2.11 have A LOT of new and useful features. The 64 bits integer numbers have been eliminated so the creation of arithmetic expressions is much simpler now, with just 32-bits integers (and the same floating point numbers). The new printf 2.11 have now character strings management, so it can be used to generate a new set of text-based results. The most important point though is that printf 2.11 now has scripting capabilities based on the simplest programming scheme that still provides the same functionality as modern structured programming languages.

You can review and download the new printf.exe version 2.11 from this link.

Antonio

aGerman
Expert
Posts: 4654
Joined: 22 Jan 2010 18:01
Location: Germany

Re: printf.exe: Show formatted output AND evaluate arithmetic expressions!

#2 Post by aGerman » 26 Jul 2016 16:28

Wow :!: That's great Antonio. I fear the RPN is a worry to me :lol: Nevermind. I'll try to learn it ...

Regards
aGerman

lazna
Posts: 53
Joined: 27 Dec 2012 10:54

Re: printf.exe: Show formatted output AND evaluate arithmetic expressions!

#3 Post by lazna » 06 May 2022 03:32

Need to convert HEX string to ascii, is this tool usable for such purpose? Now employing powershell, but its too slow

thanks

AR Coding
Posts: 53
Joined: 02 May 2021 21:16

Re: printf.exe: Show formatted output AND evaluate arithmetic expressions!

#4 Post by AR Coding » 06 May 2022 16:06

You can do it in pure batch
example: Capital "A"

Code: Select all

set hex=41
set /a num=0x%hex%
call cmd /c exit /b %num%
set char=%=exitCodeASCII%
echo %char%

lazna
Posts: 53
Joined: 27 Dec 2012 10:54

Re: printf.exe: Show formatted output AND evaluate arithmetic expressions!

#5 Post by lazna » 08 May 2022 04:34

this is ineffective for long strings, parsing network packets which could contain a hundreds of characters

Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: printf.exe: Show formatted output AND evaluate arithmetic expressions!

#6 Post by Aacini » 08 May 2022 09:05

Perhaps if you post a sample of your input data we could help you better. However, I suggest you to post a new topic because printf.exe is intended to print arithmetic expressions, not strings...

lazna
Posts: 53
Joined: 27 Dec 2012 10:54

Re: printf.exe: Show formatted output AND evaluate arithmetic expressions!

#7 Post by lazna » 08 May 2022 09:34

thanks. Found xxd.exe in the meantime, which do the job well

echo %hex_string% | xxd.exe -r -p

https://sourceforge.net/projects/xxd-for-windows/

lazna
Posts: 53
Joined: 27 Dec 2012 10:54

Re: printf.exe: Show formatted output AND evaluate arithmetic expressions!

#8 Post by lazna » 03 Aug 2022 04:15

Dealing with RRDTool on windows reading `rrdtool fetch` command which outputting numbers in "scientific notation". Found such link https://www.unix.com/302949386-post1.html when trying to convert if to human readable numbers, but AWK have problems with doublequotes escaping on windows. But when I see the AWK script there is a printf functuons utilized, it came to my mind if printf.exe cound not ne used for such task. is it possible at all? If yes, could someone provide an example, please?

rrdtool fetch output example:

Code: Select all

1436528100: 1.1250047849e+06 3.1314646692e+06
1436528400: 1.3876584112e+06 2.9220966787e+06
1436528700: 1.3133471637e+06 3.1660403672e+06
1436529000: 9.4883384335e+05 2.9144044545e+06
1436529300: 9.1177325293e+05 3.1121635913e+06
1436529600: 1.2453337586e+06 2.9249713178e+06
1436529900: 1.1314101180e+06 3.7632825058e+06
1436530200: 1.1444321559e+06 3.8615344208e+06
1436530500: 1.2826847139e+06 4.2649438309e+06
1436530800: 1.1904438758e+06 4.5972507903e+06
1436531100: 1.0910768134e+06 4.2025452739e+06

Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: printf.exe: Show formatted output AND evaluate arithmetic expressions!

#9 Post by Aacini » 03 Aug 2022 09:19

Mmmm... You should be clearer in your problem description. If this is the input file, what output do you want? If this is the output file, what is the input? Sorry, I haven not RRDTool nor understand what "AWK have problems with doublequotes escaping on windows" means...

EDIT: Something like this, perhaps?

Code: Select all

C:\Users\Antonio\Documents\ASMB\MASM32 Assembler for Windows
> for /F "tokens=1-3 delims=: " %a in (rrdtoolOut.txt) do @printf "%s,%8.2f,%8.2f \n" "%a" %b %c
1436528100,1125004.78,3131464.67
1436528400,1387658.41,2922096.68
1436528700,1313347.16,3166040.37
1436529000,948833.84,2914404.45
1436529300,911773.25,3112163.59
1436529600,1245333.76,2924971.32
1436529900,1131410.12,3763282.51
1436530200,1144432.16,3861534.42
1436530500,1282684.71,4264943.83
1436530800,1190443.88,4597250.79
1436531100,1091076.81,4202545.27
If this is what you want, then we understand in a very different way what "human readable numbers" means!!! :shock:

Antonio

lazna
Posts: 53
Joined: 27 Dec 2012 10:54

Re: printf.exe: Show formatted output AND evaluate arithmetic expressions!

#10 Post by lazna » 03 Aug 2022 12:01

Sorry for unclear question, expect you check the link i post. RRDTool produce number in "scientific notation" and in link I post someone convert it utilizing AWK software, but its windows usage have problems with way how windows using doublequotes.

Thanks for answer. I am able to process data in FOR loop, but have just zero experinces with mathematical expressions. So only help I need is with printf parameters. Am I reading it right, so this part

Code: Select all

"%s,%8.2f,%8.2f"
specify how to translate it and

Code: Select all

%a %b %c
part are "input data"? If I have more columns of same data type on input, its multiplying

Code: Select all

%8,2f
part is enough?

Another question is rounding, could printf.exe perform rounding of decimal points?

lazna
Posts: 53
Joined: 27 Dec 2012 10:54

Re: printf.exe: Show formatted output AND evaluate arithmetic expressions!

#11 Post by lazna » 03 Aug 2022 12:28

Aacini wrote:
03 Aug 2022 09:19
If this is what you want, then we understand in a very different way what "human readable numbers" means!!!
OK, replacing word "human" with words "uneducated creature"

lazna
Posts: 53
Joined: 27 Dec 2012 10:54

Re: printf.exe: Show formatted output AND evaluate arithmetic expressions!

#12 Post by lazna » 03 Aug 2022 12:45

One more question:

Some items of RRDtool output look

Code: Select all

-1.#IND000000e+000
, while I am googling for IND, found this is equivalent for NaN which means something like "no data", could printf somehow silently skip it, or should I construct

Code: Select all

if not %%a==-1.#IND000000e+000 ....
in for loop code to prevent printf error?

Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: printf.exe: Show formatted output AND evaluate arithmetic expressions!

#13 Post by Aacini » 04 Aug 2022 05:58

lazna wrote:
03 Aug 2022 12:01
Sorry for unclear question, expect you check the link i post. RRDTool produce number in "scientific notation" and in link I post someone convert it utilizing AWK software, but its windows usage have problems with way how windows using doublequotes.

Thanks for answer. I am able to process data in FOR loop, but have just zero experinces with mathematical expressions. So only help I need is with printf parameters. Am I reading it right, so this part

Code: Select all

"%s,%8.2f,%8.2f"
specify how to translate it and

Code: Select all

%a %b %c
part are "input data"?
Yes. The printf.exe documentation file specify:
printf.txt wrote: printf "format specification" {number [operator]|'c'|"string"|variable} ...

The first parameter is a standard printf format specification given as "string literal" or in a Batch variable.

The parameters after the first one can be of one of these types:
- A number, if it start in digit or minus sign.
- A character, if it is enclosed in apostrophes (managed as a 32-bits integer).
- A string literal, if it is enclosed in quotes.
- A string Batch variable otherwise.
lazna wrote:
03 Aug 2022 12:01
If I have more columns of same data type on input, its multiplying

Code: Select all

%8,2f
part is enough?
Yes, but the number of "%" specifications and data items must be the same. The printf.exe documentation file specify:
printf.txt wrote: --> If the format specifications does not match the type of the parameters,
or there are more specifications than parameters, this program may fail.
If there are more data items than format specifications, the extra items are not displayed.
lazna wrote:
03 Aug 2022 12:01
Another question is rounding, could printf.exe perform rounding of decimal points?
Yes. From your example data and my example output:

Code: Select all

1436529600: 1.2453337586e+06 2.9249713178e+06

1436529600,1245333.76,2924971.32
If you have more questions, there are a lot examples and further links in the printf.exe documentation.

Antonio

lazna
Posts: 53
Joined: 27 Dec 2012 10:54

Re: printf.exe: Show formatted output AND evaluate arithmetic expressions!

#14 Post by lazna » 05 Aug 2022 08:40

Thanks for reply, I will try read documentation more carefully next time, but i have to say: its not easy for me :-/

here is a script I wrote with your kind help, do you have idea why I got GUI err msg 'printf.exe has stopped working' on each iteration?

Code: Select all

@echo off & setlocal ENABLEDELAYEDEXPANSION
::
:: This script translate output of command 'rrdtool fetch' to non-scientific
:: (human readable) numbers format. Its purpose is to help debug rrd database
:: creation/updates from windows console.
::
:: Usage: rrd_fetch.cmd <filename> <seconds>
:: <filename> specify name of your RRD database file [path is specified in variable]
:: <seconds> parameter specify time period you want to display data for 
::
:: Script requires date.exe [rename to edate.exe here to avoid conflict with windows
:: date command] utility from Gnuwin package, fprint.exe and rrdtool.exe
:: Check following links:
::
:: http://gnuwin32.sourceforge.net/downlinks/coreutils-bin-zip.php
:: https://www.dostips.com/forum/viewtopic.php?f=3&t=7312#p48055
:: https://github.com/oetiker/rrdtool-1.x/releases
::
set "rrdtool=C:\Inetpub\monitoring_test\utilities\rrdtool\rrdtool.exe"
set "rrdfile=X:\RRD\DEVICES\%~1"
::
set "item=%%8.2f"
::
if "%~1"=="" (
			echo Parameter missing
			exit /B
			)
::
REM == Read data sources counts from given RRD file ============================
for /f %%a in ('
			%rrdtool% info %rrdfile% ^| findstr /B "ds[" ^| find /C "ds"
			') do (
REM == Set data sources total count, minus one compensate inital 'set item=' ===
			set /a "ds_cnt=(%%~a/8)-1"
			)
::
REM == Generate fprint pattern according to data sources count ================= 
for /l %%A in (1,1,%ds_cnt%) do set "items=!items!, %%8.2f"
::
for /F "skip=1 tokens=1-5 delims=: " %%a in ('
			%rrdtool% fetch %rrdfile% AVERAGE -s -%~2s -e now
			') do (
REM == Compuate time from RRD timestamp ========================================
			for /f %%a in ('edate "+%%H:%%M:%%S" -d@%%~a') do set "datetime=%%~a"
REM == Replace possible NaN/IND by zero value ================================== 
			if "%%~b"=="-1.#IND000000e+000" (set "b=0.000000000e+000") else (set "b=%%~b")
			if "%%~c"=="-1.#IND000000e+000" (set "c=0.000000000e+000") else (set "c=%%~c")
			if "%%~d"=="-1.#IND000000e+000" (set "d=0.000000000e+000") else (set "d=%%~d")
			if "%%~e"=="-1.#IND000000e+000" (set "e=0.000000000e+000") else (set "e=%%~e")
			if "%%~f"=="-1.#IND000000e+000" (set "f=0.000000000e+000") else (set "f=%%~f")
			if "%%~g"=="-1.#IND000000e+000" (set "g=0.000000000e+000") else (set "g=%%~g")
			if "%%~h"=="-1.#IND000000e+000" (set "h=0.000000000e+000") else (set "h=%%~h")
			if "%%~i"=="-1.#IND000000e+000" (set "i=0.000000000e+000") else (set "i=%%~i")
			if "%%~j"=="-1.#IND000000e+000" (set "j=0.000000000e+000") else (set "j=%%~j")
			if "%%~k"=="-1.#IND000000e+000" (set "k=0.000000000e+000") else (set "k=%%~k")
			if "%%~l"=="-1.#IND000000e+000" (set "l=0.000000000e+000") else (set "l=%%~l")
REM == Print human readable time =============================================== 
			<nul set /p= !datetime!
REM == Print data itself translated from 'acientific notation' =================
			@printf.exe "%%8.2f%items% \n" !b! !c! !d! !e! !f! !g! !h! !i! !j! !k! !l!
			)
exit /B
If someone want to experiment, 'rrdtool fetch' output is here:

Code: Select all

1659706800: -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000
1659707100: -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000
1659707400: -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000
1659707700: -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000
1659708000: -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000
1659708300: -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000
1659708600: -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000
1659708900: -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000
1659709200: -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000
1659709500: -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000
1659709800: -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000 -1.#IND000000e+000

Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: printf.exe: Show formatted output AND evaluate arithmetic expressions!

#15 Post by Aacini » 05 Aug 2022 12:05

I am afraid I don't understand what your posted code is supposed to do. It seems you count the number of lines from "rrdtool info" output that begin with "ds[" string in order to know the number of columns in the "rrdtool fetch" output, but you have not posted the "info" output file, so I can only guess (and I can't do any test on this).

The "printf.exe has stopped working" message is usually displayed when there is an error in the printf format string. In your code you initialized set "item=%%8.2f". Later you count the number of data minus one to compensate for the initial %8.2f format, but when you use the %items% format, you put this line:

Code: Select all

@printf.exe "%%8.2f%items% \n" !b! !c! !d! !e! !f! !g! !h! !i! !j! !k! !l!
... that is, you insert an additional "%%8.2f" format before "%items%" value! This means that there is one format specification more than data items...

This is my version of a program that converts "-1.#IND000000e+000" values to zero:

Code: Select all

@echo off
setlocal EnableDelayedExpansion

rem Count the number of data columns in the first line of the file, minus one
set "ds_cnt=-1"
set /P "line=" < rrdtoolFetchOutput.txt
for %%a in (%line%) do set /A "ds_cnt+=1"

rem Generate printf format
set "format=%%s:"
for /L %%i in (1,1,%ds_cnt%) do set "format=!format!  %%8.2f"

rem Show the file
for /F "delims=" %%a in (rrdtoolFetchOutput.txt) do (
   set "line=%%a"
   rem Enclose first value between quotes
   set "line="!line::="!"
   rem Convert all "-1.#IND000000e+000" values to "0.0000000000e+000"
   set "line=!line:-1.#IND=0.0000!"
   printf "%format%\n" !line!
)
Output:

Code: Select all

1659706800:      0.00      0.00      0.00      0.00      0.00
1659707100:      0.00      0.00      0.00      0.00      0.00
1659707400:      0.00      0.00      0.00      0.00      0.00
1659707700:      0.00      0.00      0.00      0.00      0.00
1659708000:      0.00      0.00      0.00      0.00      0.00
1659708300:      0.00      0.00      0.00      0.00      0.00
1659708600:      0.00      0.00      0.00      0.00      0.00
1659708900:      0.00      0.00      0.00      0.00      0.00
1659709200:      0.00      0.00      0.00      0.00      0.00
1659709500:      0.00      0.00      0.00      0.00      0.00
1659709800:      0.00      0.00      0.00      0.00      0.00
NOTE: For me (and for many programmers and other computer-related people) the term "human readable form" is the opposite to "machine readable form". Translate to "human readable form" usually implies to read data in binary form and convert it to an ASCII string. Your problem is just convert the format from scientific notation to fixed point...

Antonio

Post Reply