summary refs log tree commit diff
path: root/liberror.html
blob: 23a365288ab3143b4688a3708c4730deaf663951 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.3//EN">
<html>
<head>
<title>Netpbm User Manual</title>
</head>
<body>
<h1>Error Handling</h1>

<h2 id="error">Netpbm Programming Library Errors</h2>

<p>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 return error 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.

<p>Netpbm's response to encountering an error is called "throwing
an error."

<p>The typical way a Netpbm function throws an error (for example,
when you attempt to open a non-existent file with <b>pm_openr()</b>)
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.

<p>In many cases, that simply isn't acceptable.  If you're calling
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.

<p>So as an alternative, you can replace that program exit with a
longjmp instead.  A longjmp is a classic Unix exception handling
concept.  See the documentation of the standard C library
<b>setjmp()</b> and <b>longjmp()</b> functions.

<p>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.

<p>To select this form of throwing an error, use the
<b>pm_setjmpbuf()</b> function.  This alternative is not available
before Netpbm 10.27 (March 2005).

<p>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.

<p>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 instead with
<b>pm_setusererrormsgfn()</b>.


<h3 id="pm_setjmpbuf">pm_setjmpbuf()</h3>

<p>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.

<p>This is <em>not</em> analogous to <b>setjmp()</b>.  You do a
setjmp() first, then tell the Netpbm programming library with
<b>pm_setjmpbuf()</b> to use the result.

<p>Example:

<pre>
<code>
  #include &lt;setjmp.h&gt;
  #include &lt;netpbm/pam.h&gt;

  jmp_buf jmpbuf;
  int rc;

  rc = setjmp(jmpbuf);
  if (rc == 0) {
    struct pam pam;
    pm_setjmpbuf(&amp;jmpbuf);
    
    pnm_readpam(stdin, &amp;pam, PAM_STRUCT_SIZE(tuple_type));

    printf("pnm_readpam() succeeded!\n");

  } else {
    printf("pnm_readpam() failed.  You should have seen "
           "messages to Standard Error telling you why.\n");
  }
</code>
</pre>

<p>This example should look really strange to you if you haven't read
the documentation of <b>setjmp()</b>.  Remember that there is a
hyperjump such that the program is executing the <b>pnm_readpam()</b>
and then suddenly is returning a second time from the setjmp()!

<p>Even <b>pm_error()</b> works this way -- if you set up a longjmp with
<b>pm_setjmpbuf()</b> and then call <b>pm_error()</b>, <b>pm_error()</b>
will, after issuing your error message, execute the longjmp.


<p><b>pm_setjmpbuf()</b> was new in Netpbm 10.27 (March 2005).  Before
that, Netpbm programming library functions always throw an error by
exiting the program.


<h2>User Detected Errors</h2>

<p>The Netpbm programming library provides a function for you to throw
an error explicitly: <b>pm_error()</b>.  <b>pm_error()</b> does
nothing but throw an error, and does so the same way any Netpbm
library function you call would.  <b>pm_error()</b> is more convenient
than most standard C facilities for handling errors.

<p>If you don't want to throw an error, but just want to issue an
error message, use <b>pm_errormsg()</b>.  It issues the message in the
same way as <b>pm_error()</b> but returns normally instead of longjmping
or exiting the program.  

<p>Note that <b>libnetpbm</b> distinguishes between an error message
and an informational message (use <b>pm_errormsg()</b> for the former;
<b>pm_message()</b> for the latter).  The only practical difference is
which user message 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 easier to read when you use the
appropriate one of these.


<h3 id="pm_error">pm_error()</h3>

<h4>Overview</h4>

<p>
<b>void pm_error(</b>
<b>char *</b> <i>fmt</i><b>,</b>
<b>... );</b>

<h4>Example</h4>

<pre>
<code>
if (argc-1 &lt; 3)
    pm_error("You must specify at least 3 arguments.  "
             "You specified" only %d", argc-1);
</code>
</pre>

<p><b>pm_error()</b> is a <b>printf()</b> style routine that 
simply throws an error.  It issues an error message exactly like
<b>pm_errormsg()</b> would in the process.


<h3 id="pm_errormsg">pm_errormsg()</h3>

<h4>Overview</h4>

<p>
<b>void pm_errormsg(</b>
<b>char *</b> <i>fmt</i><b>,</b>
<b>... );</b>

<h4>Example</h4>

<pre>
<code>
if (rc = -1)
    pm_errormsg("Could not open file.  errno=%d", errno);
    return -1;
</code>
</pre>

<p><b>pm_errormsg()</b> is a <b>printf()</b> style routine that 
issues an error message.  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 <a href="#pm_setusererrormsgfn"><b>pm_setusererrormsgfn</b></a>.

<p>There is very little advantage to using this over traditional C
services, but it issues a message in the same way as <b>libnetpbm</b>
library functions do, so the common handling might be valuable.

<p>Note that the arguments specify the message text, not any formatting
of it.  Formatting is handled by <b>pm_errormsg()</b>.  So don't put any
newlines or tabs in it.


<h3 id="pm_setusererrormsgfn">pm_setusererrormsgfn()</h3>

<h4>Overview</h4>

<p>
<b>void pm_setusererrormsgfn(pm_usererrormsgfn *</b> <i>function</i><b>);</b>

<h4>Example</h4>

<pre>
<code>
    static pm_usererrormsgfn logfilewrite;

    static void
    logfilewrite(const char * const msg) {
        fprintf(myerrorlog, "Netpbm error: %s", msg);
    }

    pm_setusererrormsgfn(&amp;logfilewrite);
    
    pm_errormsg("Message for the error log");
</code>
</pre>

<p><b>pm_setusererrormsgfn()</b> registers a handler for error messages,
called a user error message routine.  Any library function that wants
to issue an error message in the future will call that function with
the message as an argument.

<p>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
characters).

<p>You can remove the user error message routine, so that the library
issues future error messages in its default way (write to Standard Error)
by specifying a null pointer for <i>function</i>.

<p>The user error message routine does not handle informational messages.
It handles only error messages.  See <a href="libpm.html#message">
<b>pm_setusermessagefn()</b></a>.


<h2>Error Handling In Netpbm Programs</h2>

<p>Most Netpbm programs respond to encountering an error by issuing a
message describing the error to the Standard Error file and then
exiting with exit status 1.

<p>Netpbm programs generally do not follow the Unix convention of very
terse error messages.  Conventional Unix programs produce error
messages as if they had to pay by the word.  Netpbm programs tend to
give a complete description of the problem in human-parseable English.
These messages are often many terminal lines long.

</body>
</html>