OpenDNSSEC-enforcer  1.4.6
message.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 /*+
28  * message.c - Message Functions
29  *
30  * Abstract:
31  * The message module outputs error messages to the stdout.
32  *
33  * Modules register their message text and message code ranges with this
34  * module. When invoked, this module searches all the registered code
35  * ranges for one containing the status code in question, and takes the
36  * appropriate action.
37 -*/
38 
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <string.h>
42 
43 #include "ksm/message.h"
44 #include "ksm/string_util.h"
45 
46 #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
47 #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
48 
50 int m_numblocks = 0; /* Count of code blocks */
51 
52 
53 /*+
54  * MsgInit - Initialize Message Processing
55  *
56  * Description:
57  * Initialises the message module.
58  *
59  * Arguments:
60  * None.
61 -*/
62 
63 void MsgInit(void)
64 {
65  m_codeblock = NULL;
66  m_numblocks = 0;
67 
68  return;
69 }
70 
71 
72 
73 /*+
74  * MsgDefaultOutput
75  *
76  * Description:
77  * Default output function; outputs a line of text to stdout.
78  *
79  * Arguments:
80  * const char* text
81  * Text to output.
82 -*/
83 
84 void MsgDefaultOutput(const char* text)
85 {
86  printf("%s\n", text);
87 
88  return;
89 }
90 
91 
92 
93 /*+
94  * MsgNoOutput - Produce No Output
95  *
96  * Description:
97  * Null output function; does not output anything.
98  *
99  * Arguments:
100  * const char* text
101  * Text (not) to output.
102 -*/
103 
104 void MsgNoOutput(const char* text)
105 {
106  /* Unused parameter*/
107  (void)text;
108 
109  return;
110 }
111 
112 
113 
114 /*+
115  * MsgRegister - Register Status Codes
116  *
117  * Description:
118  * Registers a block of status codes (and associated text) with the message
119  * module.
120  *
121  * Arguments:
122  * int min
123  * Minimum status code value in the range.
124  *
125  * int max
126  * Maximum status code value in the range.
127  *
128  * const char** message
129  * List of messages for each code. message[0] corresponds to
130  * a value of "min", message 1 to "min + 1" etc. There should be
131  * (max - min + 1) entries in this list.
132  *
133  * If a message entry is NULL, default text will be used.
134  *
135  * MSG_OUTPUT_FUNCTION output
136  * Output function used to output the text when MsgLog is called.
137  * If NULL, the default function (which outputs to stdout) will be
138  * used.
139 -*/
140 
141 void MsgRegister(int min, int max, const char** message,
142  MSG_OUTPUT_FUNCTION output)
143 {
144  if (m_numblocks == 0) {
145  m_codeblock = MemCalloc(1, sizeof(MSG_CODEBLOCK));
146  }
147  else {
148  m_codeblock = MemRealloc(m_codeblock,
149  (m_numblocks + 1) * sizeof(MSG_CODEBLOCK));
150  }
151 
152  /*
153  * Fill in the code block. On the principle of "being liberal with what
154  * you accept", allow the caller to get max and min confused.
155  */
156 
157  m_codeblock[m_numblocks].min = MIN(min, max);
158  m_codeblock[m_numblocks].max = MAX(min, max);
159  m_codeblock[m_numblocks].message = message;
160  m_codeblock[m_numblocks].output = output ? output : MsgDefaultOutput;
161 
162  ++m_numblocks;
163 
164  return;
165 }
166 
167 
168 
169 /*+
170  * MsgFindCodeBlock - Find Code Block
171  *
172  * Description:
173  * Local function used to locate the code block for a particular status
174  * code.
175  *
176  * Arguments:
177  * int status
178  * Status code for which the block is sought.
179  *
180  * Returns:
181  * int
182  * Index into the code block array of the appropriate block, or -1
183  * if no block contains that status code.
184 -*/
185 
186 int MsgFindCodeBlock(int status)
187 {
188  int block = -1; /* Returned code block */
189  int i; /* Loop counter */
190 
191  for (i = 0; i < m_numblocks; ++i) {
192  if ((status >= m_codeblock[i].min) && (status <= m_codeblock[i].max)) {
193  block = i;
194  break;
195  }
196  }
197 
198  return block;
199 }
200 
201 
202 
203 /*+
204  * MsgText - Return Error Message Text
205  *
206  * Description:
207  * Returns message text associated with the status code.
208  *
209  * Arguments:
210  * int status
211  * Status code. If one of the registered message codes, the
212  * corresponding text will be returned, otherwise it will be the text
213  * returned by strerror.
214  *
215  * Returns:
216  * const char*
217  * Pointer to the message text. This is a pointer to internal
218  * memory, and should not be modified or freed by the caller.
219  *
220  * Note that this could be NULL if strerror() felt so inclined.
221 -*/
222 
223 const char* MsgText(int status)
224 {
225  int block; /* Code block associated with the message */
226  const char* text = NULL; /* Returned message */
227 
228  block = MsgFindCodeBlock(status);
229  if (block >= 0) {
230  text = m_codeblock[block].message[status - m_codeblock[block].min];
231  }
232 
233  if (text == NULL) {
234  text = strerror(status);
235  }
236 
237  return text;
238 }
239 
240 
241 
242 /*+
243  * MsgGetOutput - Get Current Output Function
244  *
245  * Description:
246  * Returns the current output function for a particular status code range.
247  *
248  * Arguments:
249  * int status
250  * Status code within the specified range.
251  *
252  * Returns:
253  * MSG_OUTPUT_FUNCTION
254  * Pointer to the current output function. NULL if the code is not
255  * recognised.
256 -*/
257 
259 {
260  int block; /* Block number */
261  MSG_OUTPUT_FUNCTION output = NULL; /* Returned function */
262 
263  /* Locate the output function */
264 
265  block = MsgFindCodeBlock(status);
266  if (block != -1) {
267  output = m_codeblock[block].output;
268  }
269 
270  return output;
271 }
272 
273 
274 
275 /*+
276  * MsgSetOutput - Set Current Output Function
277  *
278  * Description:
279  * Sets the current output function for a particular status code range.
280  *
281  * Arguments:
282  * int status
283  * Status code within the specified range.
284  *
285  * MSG_OUTPUT_FUNCTION output
286  * Output function. If NULL, the default output function (which
287  * outputs to stdout) will be used.
288 -*/
289 
290 void MsgSetOutput(int status, MSG_OUTPUT_FUNCTION output)
291 {
292  int block; /* Block number */
293 
294  /* Locate the output function */
295 
296  block = MsgFindCodeBlock(status);
297  if (block != -1) {
298  m_codeblock[block].output = output ? output : MsgDefaultOutput;
299  }
300 
301  return;
302 }
303 
304 
305 
306 /*+
307  * MsgLog - Log Message
308  *
309  * Description:
310  * Obtains the message text, substitutes any parameters, and uses the
311  * output function associated with that status code to output it.
312  *
313  * Note that it uses an internal buffer to expand the message, so there is
314  * a 4096-byte limit on the size of the message output.
315  *
316  * Arguments:
317  * int status
318  * Status code used to access a format string that is the used to
319  * format the remaining arguments.
320  *
321  * ...
322  * Arguments for the format string.
323  *
324  * Returns:
325  * int
326  * Always identical to the status passed in. This allows constructs
327  * of the form:
328  *
329  * return MsgLog(error_number...)
330  *
331  * ... which both reports the stored error and returns the error number
332  * to the caller.
333  */
334 
335 int MsgLog(int status, ...)
336 {
337  va_list ap; /* Variable arguments */
338  int retstat; /* Return status */
339 
340  va_start(ap, status);
341  retstat = MsgLogAp(status, ap);
342  va_end(ap);
343 
344  return retstat;
345 }
346 
347 
348 
349 /*+
350  * MsgLogAp - Log Message With Variable Arguments
351  *
352  * Description:
353  * See MsgLog.
354  *
355  * This function is used when the variable arguments are in the form of
356  * a variable argument list.
357  *
358  * Arguments:
359  * int status
360  * Status code. This is a format string that is used to format
361  * the remaining arguments.
362  *
363  * va_list ap
364  * Arguments for the format
365  *
366  * Returns:
367  * int
368  * See MsgLog.
369  */
370 
371 int MsgLogAp(int status, va_list ap)
372 {
373  char buffer[4096]; /* Buffer to store the text */
374  const char* message; /* Message string */
375  MSG_OUTPUT_FUNCTION output = NULL;
376 
377  /* Locate the text for the message and use it to format the text */
378 
379  message = MsgText(status);
380  if (message) {
381  vsnprintf(buffer, sizeof(buffer), message, ap);
382  buffer[sizeof(buffer) - 1] = '\0'; /* Ensure trailing NULL */
383 
384  output = MsgGetOutput(status);
385  }
386  else {
387  snprintf(buffer, sizeof(buffer), "?????: unknown message number %d", status);
388  output = MsgDefaultOutput;
389  }
390 
391  /* If a function is available, use it to output the error */
392 
393  if (output) {
394  (*output)(buffer);
395  }
396 
397  return status;
398 }
399 
400 
401 /*+
402  * MsgRundown - Rundown Message Module
403  *
404  * Description:
405  * Frees up any resources allocated to the message module and resets it to
406  * the initial conditions.
407  *
408  * Arguments:
409  * None.
410 -*/
411 
412 void MsgRundown(void)
413 {
414  if (m_codeblock) {
415  MemFree(m_codeblock);
416  m_codeblock = NULL;
417  }
418 
419  m_numblocks = 0;
420 
421  return;
422 }
423 
424 
void * MemCalloc(size_t nmemb, size_t size)
Definition: memory.c:68
int MsgLogAp(int status, va_list ap)
Definition: message.c:371
const char * MsgText(int status)
Definition: message.c:223
#define max(x, y)
MSG_OUTPUT_FUNCTION MsgGetOutput(int status)
Definition: message.c:258
int MsgFindCodeBlock(int status)
Definition: message.c:186
#define min(x, y)
void * MemRealloc(void *ptr, size_t size)
Definition: memory.c:79
#define MemFree(ptr)
Definition: memory.h:48
void(* MSG_OUTPUT_FUNCTION)(const char *text)
Definition: message.h:46
void MsgRegister(int min, int max, const char **message, MSG_OUTPUT_FUNCTION output)
Definition: message.c:141
void MsgDefaultOutput(const char *text)
Definition: message.c:84
#define MIN(X, Y)
Definition: message.c:47
void MsgRundown(void)
Definition: message.c:412
#define MAX(X, Y)
Definition: message.c:46
int MsgLog(int status,...)
Definition: message.c:335
MSG_OUTPUT_FUNCTION output
Definition: message.h:52
const char ** message
Definition: message.h:51
void MsgSetOutput(int status, MSG_OUTPUT_FUNCTION output)
Definition: message.c:290
void MsgNoOutput(const char *text)
Definition: message.c:104
int m_numblocks
Definition: message.c:50
void MsgInit(void)
Definition: message.c:63
MSG_CODEBLOCK * m_codeblock
Definition: message.c:49