unofficial mirror of libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* printf %b
@ 2020-04-25 13:33 Alejandro Colomar via Libc-alpha
  2020-04-26  0:54 ` Jonathan Nieder via Libc-alpha
  0 siblings, 1 reply; 4+ messages in thread
From: Alejandro Colomar via Libc-alpha @ 2020-04-25 13:33 UTC (permalink / raw
  To: libc-alpha

Hi all,

In my personal library, about a year ago, I wrote a function to register 
the ``b`` and ``B`` conversion specifiers using 
``register_printf_specifier()``.

They work the closest possible to ``o``, ``u``, ``x`` & ``X``:

  - All "flag characters" behave as in ``x``, ``X`` (or as close as 
possible, while being meaningful).
  - "Field width" and "precision" behave as in ``x``, ``X`` (or as close 
as possible, while being meaningful).
  - All "length modifiers" that are valid on ``o``, ``u``, ``x``, ``X`` 
are valid.
  - There are some flags that override others in the case of ``o``, 
``u``, ``x``, ``X``. Those behaviours have been kept the same.
  - I decided that the ``'`` flag character, which normally should group 
the output in thousands in decimal numbers, and is ignored in 
hexadecimal numbers, would be more meaningful here if it grouped nibbles 
(half bytes), and instead of using the locale for thousands separator, 
it should use ``_``.

Basically, from reading the documentation for other conversion 
specifiers, one should have a good idea of how it works.

Here's the source code:

https://github.com/alejandro-colomar/libalx/blob/master/src/base/stdio/printf/b.c

I did some testing, and it works as expected.  It is interesting to show 
how it works:

.. code-block:: c

	#include <stddef.h>
	#include <stdint.h>
	#include <stdio.h>
	#include <string.h>

	#include <libalx/base/stdio/printf/b.h>


	int main(void)
	{
		int len;
		char buff[BUFSIZ];

		alx_printf_b_init();

		snprintf(buff, 30, "Hey, %i == %#b :)\n", 5, 5);
		printf("%s", buff);
		printf("\n");

		printf("....----....----....----....----\n");
		len = printf("%llb;\n", 0x5Ellu);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%lB;\n", 0x5Elu);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%b;\n", 0x5Eu);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%hB;\n", 0x5Eu);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%hhb;\n", 0x5Eu);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%jb;\n", (uintmax_t)0x5E);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%zb;\n", (size_t)0x5E);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%#b;\n", 0x5Eu);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#B;\n", 0x5Eu);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%10b;\n", 0x5Eu);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%010b;\n", 0x5Eu);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%.10b;\n", 0x5Eu);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%-10B;\n", 0x5Eu);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%'B;\n", 0x5Eu);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		printf("....----....----....----....----\n");
		len = printf("%#16.12b;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%-#'20.12b;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'020B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%#020B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'020B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%020B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%#021B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'021B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%021B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%#022B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'022B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%022B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%#023B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'023B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%023B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%-#'19.11b;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'019B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#019B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%'019B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%019B;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#016b;\n", 0xAB);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		printf("....----....----....----....----\n");
		len = printf("%'010B;\n", 0xB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'010B;\n", 0xB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'010B;\n", 0x1B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'010B;\n", 0x1B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'010B;\n", 0x2B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'010B;\n", 0x2B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'010B;\n", 0x4B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'010B;\n", 0x4B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'010B;\n", 0x8B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'010B;\n", 0x8B);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%'010B;\n", 0xB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'010B;\n", 0xB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'011B;\n", 0xB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'011B;\n", 0xB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'012B;\n", 0xB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'012B;\n", 0xB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'013B;\n", 0xB);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'013B;\n", 0xB);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%'010B;\n", 0x1B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'010B;\n", 0x1B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'011B;\n", 0x1B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'011B;\n", 0x1B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'012B;\n", 0x1B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'012B;\n", 0x1B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'013B;\n", 0x1B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'013B;\n", 0x1B);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%'010B;\n", 0x2B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'010B;\n", 0x2B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'011B;\n", 0x2B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'011B;\n", 0x2B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'012B;\n", 0x2B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'012B;\n", 0x2B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'013B;\n", 0x2B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'013B;\n", 0x2B);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%'010B;\n", 0x4B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'010B;\n", 0x4B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'011B;\n", 0x4B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'011B;\n", 0x4B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'012B;\n", 0x4B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'012B;\n", 0x4B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'013B;\n", 0x4B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'013B;\n", 0x4B);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");
		len = printf("%'010B;\n", 0x8B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'010B;\n", 0x8B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'011B;\n", 0x8B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'011B;\n", 0x8B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'012B;\n", 0x8B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'012B;\n", 0x8B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%'013B;\n", 0x8B);
		printf("%i\n", len - strlen(";\n"));
		len = printf("%#'013B;\n", 0x8B);
		printf("%i\n", len - strlen(";\n"));
		printf("....----....----....----....----\n");

		return 0;
	}

And the results:

::

	Hey, 5 == 0b101 :)

	....----....----....----....----
	11111111111111000000000000000000000000001011110;
	47
	11111111111111000000000000000000000000001011110;
	47
	1011110;
	7
	1011110;
	7
	1011110;
	7
	11111111111111000000000000000000000000001011110;
	47
	11111111111111000000000000000000000000001011110;
	47
	....----....----....----....----
	0b1011110;
	9
	0B1011110;
	9
	....----....----....----....----
	   1011110;
	10
	0001011110;
	10
	0001011110;
	10
	....----....----....----....----
	1011110   ;
	10
	....----....----....----....----
	101_1110;
	8
	....----....----....----....----
	....----....----....----....----
	  0b000010101011;
	16
	0b0000_1010_1011    ;
	20
	0B000_0000_1010_1011;
	20
	....----....----....----....----
	0B000000000010101011;
	20
	0_0000_0000_1010_1011;
	21
	00000000000010101011;
	20
	....----....----....----....----
	0B0000000000010101011;
	21
	0_0000_0000_1010_1011;
	21
	000000000000010101011;
	21
	....----....----....----....----
	0B00000000000010101011;
	22
	00_0000_0000_1010_1011;
	22
	0000000000000010101011;
	22
	....----....----....----....----
	0B000000000000010101011;
	23
	000_0000_0000_1010_1011;
	23
	00000000000000010101011;
	23
	....----....----....----....----
	0b000_1010_1011    ;
	19
	0B00_0000_1010_1011;
	19
	0B00000000010101011;
	19
	....----....----....----....----
	0000_0000_1010_1011;
	19
	0000000000010101011;
	19
	0b00000010101011;
	16
	....----....----....----....----
	....----....----....----....----
	0_0000_1011;
	11
	0B000_1011;
	10
	0_0001_1011;
	11
	0B001_1011;
	10
	0_0010_1011;
	11
	0B010_1011;
	10
	0_0100_1011;
	11
	0B100_1011;
	10
	0_1000_1011;
	11
	0B1000_1011;
	11
	....----....----....----....----
	0_0000_1011;
	11
	0B000_1011;
	10
	0_0000_1011;
	11
	0B0000_1011;
	11
	00_0000_1011;
	12
	0B0_0000_1011;
	13
	000_0000_1011;
	13
	0B0_0000_1011;
	13
	....----....----....----....----
	0_0001_1011;
	11
	0B001_1011;
	10
	0_0001_1011;
	11
	0B0001_1011;
	11
	00_0001_1011;
	12
	0B0_0001_1011;
	13
	000_0001_1011;
	13
	0B0_0001_1011;
	13
	....----....----....----....----
	0_0010_1011;
	11
	0B010_1011;
	10
	0_0010_1011;
	11
	0B0010_1011;
	11
	00_0010_1011;
	12
	0B0_0010_1011;
	13
	000_0010_1011;
	13
	0B0_0010_1011;
	13
	....----....----....----....----
	0_0100_1011;
	11
	0B100_1011;
	10
	0_0100_1011;
	11
	0B0100_1011;
	11
	00_0100_1011;
	12
	0B0_0100_1011;
	13
	000_0100_1011;
	13
	0B0_0100_1011;
	13
	....----....----....----....----
	0_1000_1011;
	11
	0B1000_1011;
	11
	0_1000_1011;
	11
	0B1000_1011;
	11
	00_1000_1011;
	12
	0B0_1000_1011;
	13
	000_1000_1011;
	13
	0B0_1000_1011;
	13
	....----....----....----....----


I would like to add this feature to glibc, if you are interested in it.
I have been reading through the glibc source code, and I guess the only 
file I should modify is ``stdio-common/vfprintf-internal.c`` (correct me 
if I'm missing something).

How should I document the new feature?  Which files should I modify for 
that?

This is the first time I step into glibc code seriously, so I don't have 
any experience in how the library is organized at all.  Please tell me 
which steps should I follow to write this patch.

After this, I would like to write another patch for the ``scanf`` family 
of functions, but that's future.

		Alex.

P.S.:  Please CC me as I'm not subscribed to this mailing list.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: printf %b
  2020-04-25 13:33 printf %b Alejandro Colomar via Libc-alpha
@ 2020-04-26  0:54 ` Jonathan Nieder via Libc-alpha
  2020-04-26  2:29   ` Alejandro Colomar via Libc-alpha
  0 siblings, 1 reply; 4+ messages in thread
From: Jonathan Nieder via Libc-alpha @ 2020-04-26  0:54 UTC (permalink / raw
  To: Alejandro Colomar; +Cc: libc-alpha

Hi!

Alejandro Colomar wrote:

> In my personal library, about a year ago, I wrote a function to register the
> ``b`` and ``B`` conversion specifiers using ``register_printf_specifier()``.
>
> They work the closest possible to ``o``, ``u``, ``x`` & ``X``:

You left out the key detail up here, that it writes a number in
binary. :)

The printf command line utility uses %b for something else: it prints
its argument as an expanded string, with backslashes interpolated.
For example, "foo\\tbar" becomes "foo	bar".  I think this is enough
reason not to use %b for something else in libc out of the box.  Of
course, particular programs registering a printf specifier are a
separate story.

That said, I don't want to discourage a potential glibc contributor.
For what it's worth, glibc's printf code is pretty messy and I would
be very happy to review a proposal for cleaning it up.

Thanks and hope that helps,
Jonathan

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: printf %b
  2020-04-26  0:54 ` Jonathan Nieder via Libc-alpha
@ 2020-04-26  2:29   ` Alejandro Colomar via Libc-alpha
  2020-04-26 19:18     ` Alejandro Colomar via Libc-alpha
  0 siblings, 1 reply; 4+ messages in thread
From: Alejandro Colomar via Libc-alpha @ 2020-04-26  2:29 UTC (permalink / raw
  To: Jonathan Nieder; +Cc: libc-alpha



On 4/26/20 2:54 AM, Jonathan Nieder wrote:
> Hi!
> 
> Alejandro Colomar wrote:
> 
>> In my personal library, about a year ago, I wrote a function to register the
>> ``b`` and ``B`` conversion specifiers using ``register_printf_specifier()``.
>>
>> They work the closest possible to ``o``, ``u``, ``x`` & ``X``:
> 
> You left out the key detail up here, that it writes a number in
> binary. :)

Yup, I forgot the main point :)

> 
> The printf command line utility uses %b for something else: it prints
> its argument as an expanded string, with backslashes interpolated.
> For example, "foo\\tbar" becomes "foo	bar".  I think this is enough
> reason not to use %b for something else in libc out of the box.  Of

Hmmm.  Good point.  Maybe, given that binary doesn't have letters such 
as hex does, we don't need both ``%b`` and ``%B``.  We could have just 
``%B`` (if it isn't already taken by some other thing) and use it for 
binary.

> course, particular programs registering a printf specifier are a
> separate story.
> 
> That said, I don't want to discourage a potential glibc contributor.
> For what it's worth, glibc's printf code is pretty messy and I would
> be very happy to review a proposal for cleaning it up.

I can try.  I do agree that it is messy; maybe too much for me to 
understand it.

> 
> Thanks and hope that helps,
> Jonathan


Thank you very much.

		Alex.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: printf %b
  2020-04-26  2:29   ` Alejandro Colomar via Libc-alpha
@ 2020-04-26 19:18     ` Alejandro Colomar via Libc-alpha
  0 siblings, 0 replies; 4+ messages in thread
From: Alejandro Colomar via Libc-alpha @ 2020-04-26 19:18 UTC (permalink / raw
  To: libc-alpha

On 4/26/20 4:29 AM, Alejandro Colomar wrote:
 > Hmmm.  Good point.  Maybe, given that binary doesn't have letters such
 > as hex does, we don't need both ``%b`` and ``%B``.  We could have just
 > ``%B`` (if it isn't already taken by some other thing) and use it for
 > binary.

I have written the patch to add ``%B`` (not ``%b``) for binary.  I added
a few tests to ``stdio-common/tst-printf.c``, which work fine.  I also
compiled the extensive test that I had for my library, with the new
glibc, and it worked also fine.

Issues:

  - Not yet implemented:  Separator for nibbles. (If I implement this, I
    would like to also implement it for hex bytes).
  - GCC 9 doesn't know of this specifier, so in the tests I had to
    disable that diagnostic.  When GCC accepts it, those pragmas should
    be removed.
  - ``stdio-common/tst-printfsz.c`` registers ``%B`` for something else
    (it uses ``register_printf_function()``, so it overwrites the
    specifier, and shouldn't cause any problems at all).

TODO (I will do them ASAP (when I know howto, actually)):

  - Documentation (both glibc and man 3 printf).
  - patch GCC to accept the new specifier.

I had some problems following the `contribution checklist`_:

_`contribution checklist`: 
https://sourceware.org/glibc/wiki/Contribution%20checklist

  - ``find . -name ChangeLog`` shows nothing to me:

::

	$ find . -name ChangeLog
	$ find . |grep ChangeLog
	./ChangeLog.old
	./ChangeLog.old/ChangeLog.ports-m68k
	./ChangeLog.old/ChangeLog.9
	./ChangeLog.old/ChangeLog.4
	./ChangeLog.old/ChangeLog.13
	./ChangeLog.old/ChangeLog.ports-tile
	./ChangeLog.old/ChangeLog.5
	./ChangeLog.old/ChangeLog.ports-arm
	./ChangeLog.old/ChangeLog.16
	./ChangeLog.old/ChangeLog.localedata
	./ChangeLog.old/ChangeLog.8
	./ChangeLog.old/ChangeLog.ports-microblaze
	./ChangeLog.old/ChangeLog.ports-aarch64
	./ChangeLog.old/ChangeLog.ports-am33
	./ChangeLog.old/ChangeLog.ports-mips
	./ChangeLog.old/ChangeLog.ports-aix
	./ChangeLog.old/ChangeLog.nptl_db
	./ChangeLog.old/ChangeLog.ports-hppa
	./ChangeLog.old/ChangeLog.6
	./ChangeLog.old/ChangeLog.14
	./ChangeLog.old/ChangeLog.1
	./ChangeLog.old/ChangeLog.ports-powerpc
	./ChangeLog.old/ChangeLog.nptl
	./ChangeLog.old/ChangeLog.7
	./ChangeLog.old/ChangeLog.19
	./ChangeLog.old/ChangeLog.15
	./ChangeLog.old/ChangeLog.2
	./ChangeLog.old/ChangeLog.ports
	./ChangeLog.old/ChangeLog.18
	./ChangeLog.old/ChangeLog.libidn
	./ChangeLog.old/ChangeLog.12
	./ChangeLog.old/ChangeLog.11
	./ChangeLog.old/ChangeLog.ports-ia64
	./ChangeLog.old/ChangeLog.20
	./ChangeLog.old/ChangeLog.ports-cris
	./ChangeLog.old/ChangeLog.ports-linux-generic
	./ChangeLog.old/ChangeLog.ports-alpha
	./ChangeLog.old/ChangeLog.10
	./ChangeLog.old/ChangeLog.17
	./ChangeLog.old/ChangeLog.3

  - I couldn't create an account on http://patchwork.sourceware.org/
    because that link is broken (500 Internal server error).

Regards,
		Alex.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-04-26 19:18 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-04-25 13:33 printf %b Alejandro Colomar via Libc-alpha
2020-04-26  0:54 ` Jonathan Nieder via Libc-alpha
2020-04-26  2:29   ` Alejandro Colomar via Libc-alpha
2020-04-26 19:18     ` Alejandro Colomar via Libc-alpha

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).