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

Alejandro Colomar alx at kernel.org
Wed Mar 19 16:25:40 UTC 2025


Hi Thorsten,

On Wed, Mar 19, 2025 at 04:56:32PM +0100, Thorsten Glaser wrote:
> On Tue, 18 Mar 2025, Alejandro Colomar wrote:
> 
> >> To address this adoption problem, how about changing these function to
> >> generic functions (in the sense of <tgmath.h>)? In such a way that
> >>     strtoi (n, &end, base, LONG_MIN, LONG_MAX, &status)
> >> is known to return a 'long' rather than 'intmax_t', and
> >>     strtoi (n, &end, base, INT_MIN, INT_MAX, &status)
> 
> That, and especially…

Please propose an implementation of the overload-selectinging macro, and
clarify how this should work:

	n = strto*(s, NULL, 0, SHRT_MIN, UINT_MAX, &status);

Do we use typeof(min + max)?  Which is the type to use?

Also, aren't you worried about going inventive in the standard?  I feel
safer with this old API than one invented now.

> >I have designed a better API, through a type-generic macro:
> >
> >	int
> >	a2i(typename T, T *restrict n, QChar *s,
> >	    QChar *_Optional *restrict endp, int base,
> >	    T min, T max);
> […]
> 
> … this is a nightmare. This effectively will prevent people from
> adding that to systems that do not use C2y as primary/only target
> yet, and mixing code.

That macro can be implemented with C11.  Here's the implementation I
wrote for shadow-utils, which we've been using and distributing for a
year already:

	#define a2i(TYPE, n, s, ...)                                                  \
	(                                                                             \
		_Generic((void (*)(TYPE, typeof(s))) 0,                               \
			void (*)(short,              const char *):  a2sh_c,          \
			void (*)(short,              const void *):  a2sh_c,          \
			void (*)(short,              char *):        a2sh_nc,         \
			void (*)(short,              void *):        a2sh_nc,         \
			void (*)(int,                const char *):  a2si_c,          \
			void (*)(int,                const void *):  a2si_c,          \
			void (*)(int,                char *):        a2si_nc,         \
			void (*)(int,                void *):        a2si_nc,         \
			void (*)(long,               const char *):  a2sl_c,          \
			void (*)(long,               const void *):  a2sl_c,          \
			void (*)(long,               char *):        a2sl_nc,         \
			void (*)(long,               void *):        a2sl_nc,         \
			void (*)(long long,          const char *):  a2sll_c,         \
			void (*)(long long,          const void *):  a2sll_c,         \
			void (*)(long long,          char *):        a2sll_nc,        \
			void (*)(long long,          void *):        a2sll_nc,        \
			void (*)(unsigned short,     const char *):  a2uh_c,          \
			void (*)(unsigned short,     const void *):  a2uh_c,          \
			void (*)(unsigned short,     char *):        a2uh_nc,         \
			void (*)(unsigned short,     void *):        a2uh_nc,         \
			void (*)(unsigned int,       const char *):  a2ui_c,          \
			void (*)(unsigned int,       const void *):  a2ui_c,          \
			void (*)(unsigned int,       char *):        a2ui_nc,         \
			void (*)(unsigned int,       void *):        a2ui_nc,         \
			void (*)(unsigned long,      const char *):  a2ul_c,          \
			void (*)(unsigned long,      const void *):  a2ul_c,          \
			void (*)(unsigned long,      char *):        a2ul_nc,         \
			void (*)(unsigned long,      void *):        a2ul_nc,         \
			void (*)(unsigned long long, const char *):  a2ull_c,         \
			void (*)(unsigned long long, const void *):  a2ull_c,         \
			void (*)(unsigned long long, char *):        a2ull_nc,        \
			void (*)(unsigned long long, void *):        a2ull_nc         \
		)(n, s, __VA_ARGS__)                                                  \
	)

And here's the definition of one of the overloads:

	int
	a2sl_nc(long *restrict n, char *s,
	    char **restrict endp, int base, long min, long max)
	{
		int  status;

		*n = strtoi(s, endp, base, min, max, &status);
		if (status != 0) {
			errno = status;
			return -1;
		}
		return 0;
	}

> (Besides, a2i is a too generic name.)

I named it like atoi(3), just replacing s/to/2/.  It is just as generic
as the name of the APIs it intends to supersede.

> bye,
> //mirabilos
> PS: Please don’t Cc me explicitly on this thread.

Ok.  Have a lovely day!
Alex

-- 
<https://www.alejandro-colomar.es/>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/libbsd/attachments/20250319/96056593/attachment.sig>


More information about the libbsd mailing list