tech-misc archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: alx-0008 - Standardize strtoi(3) and strtou(3) from NetBSD



Hi Paul,

On Wed, Mar 19, 2025 at 12:27:07PM -0700, Paul Eggert wrote:
> On 2025-03-18 17:15, Bruno Haible wrote:
> > If you don't want to do that, I can only repeat what I said in the previous
> > mail: The proposal*does not achieve the goal* of avoiding the most common
> > programmer mistakes. For a robust API, the success test should*only* involve
> > testing the returned 'status', nothing else.
> 
> This was my initial reaction as well. Although strtol has real problems, the
> proposed interface is even more complicated and confusing and I suspect that
> in practice it'd be misused even more often than strtol is.

Please comment on the subthread where Bruno mentioned a number of places
in gnulib and gettext where you use strtoul(3).  I found there a few
bugs, plus some ways to just simplify with strtou(3).

The concerns about the case where one doesn't want to check ERANGE but
wants to check ENOTSUP need justification.  I suspect it's rather
missing error handling in that code.

I've never seen code calling strtoi/u(3) that wants that.

> I suggest starting from scratch.

I'm doing that in shadow-utils and liba2i, but I don't feel ready for
standardization yet.  In particular, I have two competing APIs in my
head.

> In particular, use a functional style, with
> no side effects (no pointers-to-results). Just return the result you want,
> as a struct, and keep the struct simple. Two struct components should
> suffice: the scanned numeric value and a success/error indicator.

That's going to complicate usage significantly.

If I had invented strtoi/u(3) myself, I would have used errno instead of
the *status parameter, but I don't feel too strongly about it to scrape
that API.

Regarding my APIs that are under development, here are the two
alternatives:

	int
	alt_1(typename T,
	    T *n, QChar *s, QChar **_Nullable endp, int base, T min, T max);


	if (alt_1(time_t, &time, s, NULL, 0, now, later) == -1)
		err(1, "alt_1");

which returns 0 on success, or -1 on error and sets errno on error, so
usual libc behavior.

	QChar *
	alt_2(typename T,
	    T *n, QChar *s, int base, T min, T max);


	errno = 0;
	alt_2(time_t, &time, s, 0, now, later);
	if (errno != 0)
		err(1, "alt_2");

which guarantees not setting errno on success, and sets it on error.
It always returns 'end' (instead of having the output parameter *endp).

Each one has benefits and drawbacks.  But the number we do want it as an
output parameter, since it gives us type safety: if you pass something
of a type other than the one specified in the first parameter, you get a
compiler error.

I'm still undecided which one I prefer.  So far, we're using alt_1 in
shadow-utils.  Feel free to comment about them.  If you have any idea
that will simplify usage or improve type safety, please present it, and
show how the API would look like, and an example of use.

But, these APIs are implemented in terms of strtoi/u(3), so even if we
want to eventually get these APIs, we'd benefit of standardizing the
NetBSD ones now, which will allow easier deployment of my wrappers.


Have a lovely night!
Alex

-- 
<https://www.alejandro-colomar.es/>

Attachment: signature.asc
Description: PGP signature



Home | Main Index | Thread Index | Old Index