svn commit: r285552 - head/usr.bin/xargs

Bruce Evans brde at optusnet.com.au
Wed Jul 15 08:01:21 UTC 2015


On Tue, 14 Jul 2015, Ian Lepore wrote:

> On Tue, 2015-07-14 at 13:44 -0700, Xin Li wrote:
>> On 07/14/15 13:29, Garrett Cooper wrote:
>>> On Jul 14, 2015, at 12:16, Baptiste Daroussin <bapt at FreeBSD.org>
>>> wrote:
>>>
>>>> Author: bapt Date: Tue Jul 14 19:16:14 2015 New Revision: 285552
>>>> URL: https://svnweb.freebsd.org/changeset/base/285552
>>>>
>>>> Log: Convert atoi(3) to stronum(3) which allows to arguments and
>>>> report proper errors to the users
>>>
>>> Is strtonum preferred over strtoll, etc?

No, but it is better than atoi() and expand_number() (except it uses
the long long abomination, like strtoll()).

>> strtonum(3) is a wrapper of strtoll() and provides more functionality
>> like range checking, so I think the answer would be yes.

It intentionally provides less functionality except for the range checking,
so as to try to be easier to use.

> Except if we convert all our tools that take numbers on the command line
> to use strtonum() then peoples' existing scripts and other automation
> that passes 0xWhatever numbers suddenly stop working.  strtonum() seems
> to be about 2/3 of a good idea.

1/3 io a good idea.

Bugs in it start with its name:
- it uses the reserved namespace
- it uses up a good name for a bad API

Bugs in its API include too much weakening of strtol(), etc:
- no support for bases other than 10.  This is the most annoying one.
   With the strtol() family, you get this support automatically by not
   forcing base 10.  Changing the type requires using another member
   of the strtol() family.  That is still possible with strtonum() by
   just not using it in complicated cases.
- no support for unsigned numbers
- no support for a mixture of signed and unsigned numbers (with e.g.
   a signed lower limit and an unsigned upper limit).  This can be
   built out of strtoul() but is complicated.  Applications like dd
   need this.
- no support for floating point.  Most numbers can be represented using
   floating point, support for floating point is not wanted for an atoi()
   replacement, and extra args to specify the format are also not wanted.
- no support even for large signed numbers.  The API hasn't caught up
   with C99 yet.  It uses the long long abomination instead of intmax_t.
   This is the most annoying design error.  With the strtol() family,
   you get intmax_t support automatically by using strtoimax() for
   everything, However, error handling is slightly more complicated with
   the general type.

BTW, it is unclear if POSIX even allows non-decimal or large args
in utilities, even in ones like dd where natural arg values are
multiples of powers of 2.  Portable shell scripts certainly shouldn't
use large non-decimal args.  This is a bug in POSIX.

Other bugs in its API include it being quite complicated to use despite
one of its reasons for existence being to be easier to use than the
strtol() family.

A drop-in replacement for atoi() would probably be named xatoi() and
do the same as atoi() except print a message and exit on error.  (The
behaviour of atoi() on error is only undefined in some cases, so atoi()
cannot exit on all errors.)  The message for this cannot be
context-specific, so xatoi() can't handle errors as well as a program
that actually checks for errors from atoi().  (The value of errno after
an error is unspecified, so checking it is nonsense, but the nonsense
usually works.)

strtonum()'s unease of use starts with the existence of its errstr
parameter.  This parameter is a bit like strtol()'s endptr parameter.
Often you don't need this parameter and have to fill it in with NULL
or a dummy pointer.  Actually using it requires further complications.

Unease of use continues with strtonum() having the same problem as
xatoi() with generating a context-specific errror messages.  strtonum()
can and does only return an error string that depends only on the error
type.  This string is quite short (shorter than ones returned by
strerror()).  strtonum() also sets errno.  Unfortunately, errno alone
is not enough to encode the error type, since the ERANGE errno must
be split into 2 types.  strtonum() has its errstr to do little more
than this splitting.  Then to actually use errstr, you have to either
accept its error description or parse it to turn it into your
context-specific description.  The latter would take more code than
using strtol() directly.

My main idea for a better API is a variadic one where only one parameter
other than the string is required:

     intmax_t strtonum(const char *nptr, const char *flags, ...)

where the usual case is simple but the general one is complicated.
The simplest case has flags "" and no more args.  This might give
xatoi().  The next level of complications is to either tell
strtonum() the messages that it should print before exiting, or
tell it to return an error string or code that is easy to print
yourself before existing.  It seems difficult to do either of
these without large code that would lose most of the advantages
of the wrapper.

Bruce


More information about the svn-src-all mailing list