diff options
-rw-r--r-- | manual/stdio.texi | 74 | ||||
-rw-r--r-- | stdio-common/printf_size.c | 4 | ||||
-rw-r--r-- | stdio-common/tst-printfsz.c | 66 |
3 files changed, 142 insertions, 2 deletions
diff --git a/manual/stdio.texi b/manual/stdio.texi index dd8555478a..97c3f581d1 100644 --- a/manual/stdio.texi +++ b/manual/stdio.texi @@ -1968,6 +1968,7 @@ The facilities of this section are declared in the header file to @code{register_printf_function}. * Printf Extension Example:: How to define a @code{printf} handler function. +* Predefined Printf Handlers:: Predefined @code{printf} handlers. @end menu @strong{Portability Note:} The ability to extend the syntax of @@ -2212,6 +2213,79 @@ The output produced by this program looks like: |<Widget 0xffeffb7c: mywidget> | @end smallexample +@node Predefined Printf Handlers +@subsection Predefined @code{printf} Handlers + +The GNU libc also contains a concrete and useful application of the +@code{printf} handler extension. There are two functions available +which implement a special way to print floating-point numbers. + +@comment printf.h +@comment GNU +@deftypefun int printf_size (FILE *@var{fp}, const struct printf_info *@var{info}, const void *const *@var{args}) +Print a given floating point number as for the format @code{%f} except +that there is a postfix character indicating the divisor for the +number to make this less than 1000. There are two possible divisors: +powers of 1024 or powers to 1000. Which one is used depends on the +format character specified while registered this handler. If the +character is of lower case, 1024 is used. For upper case characters, +1000 is used. + +The postfix tag corresponds to bytes, kilobytes, megabytes, gigabytes, +etc. The full table is: + +@multitable {' '} {2^10 (1024)} {zetta} {Upper} {10^24 (1000)} +@item low @tab Multiplier @tab From @tab Upper @tab Multiplier +@item ' ' @tab 1 @tab @tab ' ' @tab 1 +@item k @tab 2^10 (1024) @tab kilo @tab K @tab 10^3 (1000) +@item m @tab 2^20 @tab mega @tab M @tab 10^6 +@item g @tab 2^30 @tab giga @tab G @tab 10^9 +@item t @tab 2^40 @tab tera @tab T @tab 10^12 +@item p @tab 2^50 @tab peta @tab P @tab 10^15 +@item e @tab 2^60 @tab exa @tab E @tab 10^18 +@item z @tab 2^70 @tab zetta @tab Z @tab 10^21 +@item y @tab 2^80 @tab yotta @tab Y @tab 10^24 +@end multitable + +The default precision is 3, i.e., 1024 is printed with a lower-case +format character as if it were @code{%.3fk} and will yield @code{1.000k}. +@end deftypefun + +Due to the requirements of @code{register_printf_function} we must also +provide the function which return information about the arguments. + +@comment printf.h +@comment GNU +@deftypefun int printf_size_info (const struct printf_info *@var{info}, size_t @var{n}, int *@var{argtypes}) +This function will return in @var{argtypes} the information about the +used parameters in the way the @code{vfprintf} implementation expects +it. The format always takes one argument. +@end deftypefun + +To use these functions both functions must be registered with a call like + +@smallexample +register_printf_function ('B', printf_size, printf_size_info); +@end smallexample + +Here we register the functions to print numbers as powers of 1000 since +the format character @code{'B'} is an upper-case characeter. If we +would additionally use @code{'b'} in a line like + +@smallexample +register_printf_function ('b', printf_size, printf_size_info); +@end smallexample + +@noindent +we could also print using power of 1024. Please note that all what is +different in these both lines in the format specifier. The +@code{printf_size} function knows about the difference of low and upper +case format specifiers. + +The use of @code{'B'} and @code{'b'} is no coincidence. Rather it is +the preferred way to use this functionality since it is available on +some other systems also available using the format specifiers. + @node Formatted Input @section Formatted Input diff --git a/stdio-common/printf_size.c b/stdio-common/printf_size.c index 0184269181..6a870127af 100644 --- a/stdio-common/printf_size.c +++ b/stdio-common/printf_size.c @@ -96,8 +96,8 @@ printf_size (FILE *fp, const struct printf_info *info, const void *const *args) /* Units for the both formats. */ static const char units[2][8] = { - " kmgtps", /* For binary format. */ - " KMGTPS" /* For decimal format. */ + " kmgtpezy", /* For binary format. */ + " KMGTPEZY" /* For decimal format. */ }; const char *tag = units[isupper (info->spec) != 0]; int divisor = isupper (info->spec) ? 1000 : 1024; diff --git a/stdio-common/tst-printfsz.c b/stdio-common/tst-printfsz.c new file mode 100644 index 0000000000..fed829c012 --- /dev/null +++ b/stdio-common/tst-printfsz.c @@ -0,0 +1,66 @@ +/* Based on code by Larry McVoy <lm@neteng.engr.sgi.com>. */ +#include <printf.h> +#include <stdio.h> + +#define V 12345678.12345678 + + +int +main (int argc, char *argv[]) +{ + char buf[1024]; + int result = 0; + + /* Register the printf handlers. */ + register_printf_function ('b', printf_size, printf_size_info); + register_printf_function ('B', printf_size, printf_size_info); + + + sprintf (buf, "%g %b %B %.0b %.0B %.1b %.1B %8.0b %08.0B", + V, 1025., V, V, V, V, V, V, V, V); + fputs (buf, stdout); + if (strcmp (buf, "\ +1.23457e+07 1.001k 12.346M 12m 12M 11.8m 12.3M 12m 0000012M")) + { + result = 1; + fputs (" -> WRONG\n", stdout); + } + else + fputs (" -> OK\n", stdout); + + sprintf (buf, "%b|%B|%-20.2b|%-10.0b|%-10.8b|%-10.2B|", + V, V, V, V, V, V, V, V, V, V, V); + fputs (buf, stdout); + if (strcmp (buf, "\ +11.774m|12.346M|11.77m |12m |11.77375614m|12.35M |")) + { + result = 1; + fputs (" -> WRONG\n", stdout); + } + else + fputs (" -> OK\n", stdout); + + sprintf (buf, "%#.0B %*.0b %10.*b %*.*B %10.2B", + V, 2, V, 2, V, 10, 2, V, V); + fputs (buf, stdout); + if (strcmp (buf, "12.M 12m 11.77m 12.35M 12.35M")) + { + result = 1; + fputs (" -> WRONG\n", stdout); + } + else + fputs (" -> OK\n", stdout); + + sprintf (buf, "%6B %6.1B %b %B %b %B", + V, V, 1000.0, 1000.0, 1024.0, 1024.0); + fputs (buf, stdout); + if (strcmp (buf, "12.346M 12.3M 1000.000 1.000K 1.000k 1.024K")) + { + result = 1; + fputs (" -> WRONG\n", stdout); + } + else + fputs (" -> OK\n", stdout); + + return result; +} |