Case Study

I now introduce a case study of a real-world function manual, in particular the manual for the strtonum function, which is an extension to the C Standard Library found in OpenBSD. The original file may be viewed on-line at src/lib/libc/stdlib/strtonum.3, file version 1.14.

In this case study, I've chosen a manual with some bad behaviour — not broken, but bad. This is intentional to show how real-world manuals deviate from recommended forms. I'll explicitly note each instance of bad behaviour as we explore the manual's contents.

.\"    $​OpenBSD: strtonum.3,v 1.14 2007/05/31 19:19:31 jmc Exp $
.\"
.\" Copyright (c) 2004 Ted Unangst
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

This is the standard comment header to manual files in OpenBSD. Indeed, most distributed manuals begin with a copyright notice, then a license. The $​OpenBSD$ line is automatically updated by the revision control system, cvs, whenever an update to the file is committed. The line following is the copyright message, and following that is the text form of the ISC license.

.Dd $​Mdocdate: May 31 2007 $
.Dt STRTONUM 3
.Os

These three standard macros establish the last modified date, manual title (same as the single documented function but capitalised), manual category 3 (functions), and the default operating system. The $​Mdocdate$ line, like the $​OpenBSD$ line, is automatically updated by cvs whenever the document is committed to the source repository.

.Sh NAME
.Nm strtonum
.Nd "reliably convert string value to an integer"

Declares a single documented function, strtonum, and its purpose. The quotations within the Nd macro are superfluous: like Qq macro studied earlier, Nd accepts an arbitrary number of arguments to format. Quotation, in grouping these as one argument, serves little but to pass in whitespace (there is no special whitespace to pass in).

.Sh SYNOPSIS
.Fd #include <stdlib.h>
.Ft long long
.Fo strtonum
.Fa "const char *nptr"
.Fa "long long minval"
.Fa "long long maxval"
.Fa "const char **errstr"
.Fc

This declares the function prototype and calling syntax. First, let's examine the new Fd macro. The use of this macro for a header inclusion is obsolete: new manuals should always use In. This makes it easier for parsers to understand a header file — and possibly link to it — instead of being a generic preprocessor statement. The re-written form would begin as follows:

.Sh SYNOPSIS
.In stdlib.h

Moving along, we see that each function argument includes its name (e.g., nptr and minval). While not common in header file prototypes, this allows later references of function invocation in the manual to refer back to the prototype for type and context information. In the previous section, we discussed the relevance of quotation with Fa: the same is done here.

While we could have used Fn, it would have created an overly long input line. Using Fn instead of Fo is purely a matter of convenience and has no effect on parsing or formatting.

.Sh DESCRIPTION
The
.Fn strtonum
function converts the string in
.Fa nptr
to a
.Li long long
value.

In the SYNOPSIS, the Fa included the full type information. Here, however, we use Fa with just its name, nptr. We could have done the same in the SYNOPSIS, but the C language includes all type information in its prototypes.

The Li macro here isn't good practise: since the long long refers to a type, it should be of type Vt. This behaviour — using a presentation macro instead of a semantic one — is a holder from legacy manual forms that are purely presentational. If you find yourself applying a style, think twice whether it's a good idea!

The
.Fn strtonum
function was designed to facilitate safe, robust programming
and overcome the shortcomings of the
.Xr atoi 3
and
.Xr strtol 3
family of interfaces.
.Pp
The string may begin with an arbitrary amount of whitespace
(as determined by
.Xr isspace 3 )
followed by a single optional
.Ql +
or
.Ql -
sign.
.Pp
The remainder of the string is converted to a
.Li long long
value according to base 10.
.Pp
The value obtained is then checked against the provided
.Fa minval
and
.Fa maxval
bounds.
If
.Fa errstr
is non-null,
.Fn strtonum
stores an error string in
.Fa *errstr
indicating the failure.

The remainder of the DESCRIPTION section has completely captured the calling syntax and behaviour of the function. The usage of Ql macro is simply to set aside non-alphanumeric letters from the regular stream of text.

.Sh RETURN VALUES
The
.Fn strtonum
function returns the result of the conversion,
unless the value would exceed the provided bounds or is invalid.
On error, 0 is returned,
.Va errno
is set, and
.Fa errstr
will point to an error message.
.Fa *errstr
will be set to
.Dv NULL
on success;
this fact can be used to differentiate
a successful return of 0 from an error.

Since this function returns a rather tricky error message, it's necessary to describe the effects of both the return value and the passed-in arguments.

.Sh EXAMPLES
Using
.Fn strtonum
correctly is meant to be simpler than the alternative functions.
.Bd -literal -offset indent
int iterations;
const char *errstr;

iterations = strtonum(optarg, 1, 64, &errstr);
if (errstr)
    errx(1, "number of iterations is %s: %s", errstr, optarg);
.Ed
.Pp
The above example will guarantee that the value of iterations is between
1 and 64 (inclusive).

Many manual readers jump directly to the EXAMPLES section to gain an understanding of your function. Thus, not only must the example compile and run, it must also demonstrate as many parts of the function as possible. In the case of strtonum, an error condition and a non-error condition are documented. However, the header file inclusion(s) are missing, which may mislead readers. In particular, the non-standard errx function requires the err.h header file.

.Sh ERRORS
.Bl -tag -width Er
.It Bq Er ERANGE
The given string was out of range.
.It Bq Er EINVAL
The given string did not consist solely of digit characters.
.It Bq Er EINVAL
.Ar minval
was larger than
.Ar maxval .
.El
.Pp
If an error occurs,
.Fa errstr
will be set to one of the following strings:
.Pp
.Bl -tag -width "too largeXX" -compact
.It too large
The result was larger than the provided maximum value.
.It too small
The result was smaller than the provided minimum value.
.It invalid
The string did not consist solely of digit characters.
.El

The ERRORS section will be rigorously covered in the section on System Calls. In brief, since the errno global error variable is set, each possible value must be documented in a list using the Er macro. These are always enclosed within Bq.

Furthermore, the error string in errstr must also be documented.

.Sh SEE ALSO
.Xr atof 3 ,
.Xr atoi 3 ,
.Xr atol 3 ,
.Xr atoll 3 ,
.Xr sscanf 3 ,
.Xr strtod 3 ,
.Xr strtol 3 ,
.Xr strtoul 3

This section collects all references to other manuals made elsewhere in this manual, then adds more for completion. Note that the entries are alphabetically sorted.

.Sh STANDARDS
.Fn strtonum
is an
.Ox
extension.
The existing alternatives, such as
.Xr atoi 3
and
.Xr strtol 3 ,
are either impossible or difficult to use safely.
.Sh HISTORY
The
.Fn strtonum
function first appeared in
.Ox 3.6 .

Since this function is included in OpenBSD's C Standard Library, the fact that the function is not standard must absolutely be documented. In this, the Ox macro indicates the OpenBSD operating system (each BSD UNIX operating system has its own macro).

Last edited by $Author: kristaps $ on $Date: 2011/11/05 16:50:11 $. Copyright © 2011, Kristaps Dzonsons. CC BY-SA.