Error Handling
Netpbm Programming Library Errors
As part of Netpbm’s mission to make writing graphics programs
quick and
easy, Netpbm recognizes that no programmer likes to deal
with error
conditions. Therefore, very few Netpbm programming library
functions returnerror information. There are no return codes to check. If for
some reason a
function can’t do what was asked of it, it doesn’t return at
all.
Netpbm’s response to encountering an error is called "throwing
an error."
The typical way a Netpbm function throws an error (for exam‐
ple, when you
attempt to open a non‐existent file with pm_openr()) is that
the function
writes an error message to the Standard Error file and then
causes the
program to terminate with an exit() system call. The function
doesn’t do any
explicit cleanup, because everything a library function sets
up gets cleaned
up by normal process termination.
In many cases, that simply isn’t acceptable. If you’re call‐
ing Netpbm
functions from inside a server program, you’d want the program
to recognize
that the immediate task failed, but keep running to do other
work.
So as an alternative, you can replace that program exit with a
longjmp
instead. A longjmp is a classic Unix exception handling con‐
cept. See the
documentation of the standard C library setjmp() and longjmp()functions.
In short, you identify a point in your programs for execution
to hyperjump
to from whatever depths of whatever functions it may be in at
the time it
detects an exception. That hyperjump is called a longjmp. The
longjmp
unwinds the stack and puts the program in the same state
as if the
subroutines had returned all the way up to the function that
contains the
jump point. A longjmp does not in itself undo things
like memory
allocations. But when you have a Netpbm function do a longjmp,
it also
cleans up everything it started.
To select this form of throwing an error, use the pm_setjmp‐
buf() function.
This alternative is not available before Netpbm 10.27 (March
2005).
Issuing of the error message is a separate thing. Regardless
of whether a
library routine exits the program or executes a longjmp, it
issues an error
message first.
You can customize the error message behavior too. By default,
a Netpbm
function issues an error message by writing it to the Standard
Error file,
formatted into a single line with the program name prefixed.
But you can
register your own error message function to run in‐
stead withpm_setErrorMsgFn().
pm_setjmpbuf()pm_setjmpbuf() sets up the process so that when future calls
to the Netpbm
programming library throw an error, they execute a longjmp
instead of
causing the process to exit as they would by default.
This is not analogous to setjmp(). You do a setjmp() first,
then tell the
Netpbm programming library with pm_setjmpbuf() to use the re‐
sult.
Example:
#include <setjmp.h>
#include <pam.h>
jmp_buf jmpbuf;
int rc;
rc = setjmp(jmpbuf);
if (rc == 0) {
struct pam pam;
pm_setjmpbuf(&jmpbuf);
pnm_readpam(stdin, &pam, PAM_STRUCT_SIZE(tuple_type));
printf("pnm_readpam() succeeded!0);
} else {
printf("pnm_readpam() failed. You should have seen "
"messages to Standard Error telling you why.0);
}
This example should look really strange to you if you haven’t
read the
documentation of setjmp(). Remember that there is a hyperjump
such that the
program is executing the pnm_readpam() and then suddenly is
returning a
second time from the setjmp()!
Even pm_error() works this way ‐‐ if you set up a
longjmp withpm_setjmpbuf() and then call pm_error(), pm_error() will, af‐
ter issuing yourerror message, execute the longjmp.
pm_setjmpbuf() was new in Netpbm 10.27 (March 2005). Before
that, Netpbm
programming library functions always throw an error by exiting
the program.User Detected Errors
The Netpbm programming library provides a function for you to
throw an error
explicitly: pm_error(). pm_error() does nothing but throw an
error, and does
so the same way any Netpbm library function you call would.
pm_error() is
more convenient than most standard C facilities for handling
errors.
If you don’t want to throw an error, but just want to issue
an error
message, use pm_errormsg(). It issues the message in the
same way aspm_error() but returns normally instead of longjmping or ex‐
iting the
program.
Note that libnetpbm distinguishes between an error mes‐
sage and an
informational message (use pm_errormsg() for the former;
pm_message() for
the latter). The only practical difference is which user mes‐
sage function it
calls. So if you don’t register any user message function, you
won’t see any
difference, but a program is still more maintainable and easi‐
er to read when
you use the appropriate one of these.
pm_error()
Overview
void pm_error( char * fmt, ... );
Example
if (argc‐1 < 3)
pm_error("You must specify at least 3 arguments. "
"You specified" only %d", argc‐1);
pm_error() is a printf() style routine that simply throws an
error. It
issues an error message exactly like pm_errormsg() would in
the process.pm_errormsg()
Overview
void pm_errormsg( char * fmt, ... );
Example
if (rc = ‐1)
pm_errormsg("Could not open file. errno=%d", errno);
return ‐1;
pm_errormsg() is a printf() style routine that issues an errormessage. By
default, it writes the message to Standard Error, but you can
register a
user error message routine to be called instead, and that
might do something
such as write the message into a log file. See pm_setuser‐
errormsgfn.
There is very little advantage to using this over traditional
C services,
but it issues a message in the same way as libnetpbm library
functions do,
so the common handling might be valuable.
Note that the arguments specify the message text, not any for‐
matting of it.
Formatting is handled by pm_errormsg(). So don’t put any new‐
lines or tabs in
it.
pm_setusererrormsgfn()
Overview
void pm_setusererrormsgfn(pm_usererrormsgfn * function);
Example
static pm_usererrormsgfn logfilewrite;
static void
logfilewrite(const char * const msg) {
fprintf(myerrorlog, "Netpbm error: %s", msg);
}
pm_setusererrormsgfn(&logfilewrite);
pm_errormsg("Message for the error log");
pm_setusererrormsg() registers a handler for error messages,
called a usererror message routine. Any library function that wants to is‐
sue an error
message in the future will call that function with the mes‐
sage as an
argument.
The argument the user error message routine gets is English
text designed
for human reading. It is just the text of the message; there
is no attempt
at formatting in it (so you won’t see any newline or tab char‐
acters).
You can remove the user error message routine, so that the li‐
brary issues
future error messages in its default way (write to Standard
Error) by
specifying a null pointer for function.
The user error message routine does not handle informational
messages. It
handles only error messages. See pm_setusermessagefn().
Error Handling In Netpbm Programs
Most Netpbm programs respond to encountering an error by issu‐
ing a message
describing the error to the Standard Error file and then exit‐
ing with exit
status 1.
Netpbm programs generally do not follow the Unix convention of
very terseerror messages. Conventional Unix programs produce error mes‐
sages as if they
had to pay by the word. Netpbm programs tend to give a com‐
plete description
of the problem in human‐parseable English. These messages are
often many
terminal lines long.