|
9.2.1.1 Error Management
A good place to start with any project design is the error management
facility. In Sic I will use a simple group of functions to display
simple error messages. Here is `sic/error.h':
|
#ifndef SIC_ERROR_H
#define SIC_ERROR_H 1
#include <sic/common.h>
BEGIN_C_DECLS
extern const char *program_name;
extern void set_program_name (const char *argv0);
extern void sic_warning (const char *message);
extern void sic_error (const char *message);
extern void sic_fatal (const char *message);
END_C_DECLS
#endif /* !SIC_ERROR_H */
|
This header file follows the principles set out in 9.1.2 C Header Files.
I am storing the program_name variable in the library that uses
it, so that I can be sure that the library will build on architectures
that don't allow undefined symbols in libraries(12).
Keeping those preprocessor macro definitions designed to aid code
portability together (in a single file), is a good way to maintain the
readability of the rest of the code. For this project I will put that
code in `common.h':
|
#ifndef SIC_COMMON_H
#define SIC_COMMON_H 1
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#if STDC_HEADERS
# include <stdlib.h>
# include <string.h>
#elif HAVE_STRINGS_H
# include <strings.h>
#endif /*STDC_HEADERS*/
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#if HAVE_ERRNO_H
# include <errno.h>
#endif /*HAVE_ERRNO_H*/
#ifndef errno
/* Some systems #define this! */
extern int errno;
#endif
#endif /* !SIC_COMMON_H */
|
You may recognise some snippets of code from the Autoconf manual here---
in particular the inclusion of the project `config.h', which will
be generated shortly. Notice that I have been careful to conditionally
include any headers which are not guaranteed to exist on every
architecture. The rule of thumb here is that only `stdio.h' is
ubiquitous (though I have never heard of a machine that has no
`sys/types.h'). You can find more details of some of these in
section `Existing Tests' in The GNU Autoconf Manual.
Here is a little more code from `common.h':
|
#ifndef EXIT_SUCCESS
# define EXIT_SUCCESS 0
# define EXIT_FAILURE 1
#endif
|
The implementation of the error handling functions goes in
`error.c' and is very straightforward:
|
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include "common.h"
#include "error.h"
static void error (int exit_status, const char *mode,
const char *message);
static void
error (int exit_status, const char *mode, const char *message)
{
fprintf (stderr, "%s: %s: %s.\n", program_name, mode, message);
if (exit_status >= 0)
exit (exit_status);
}
void
sic_warning (const char *message)
{
error (-1, "warning", message);
}
void
sic_error (const char *message)
{
error (-1, "ERROR", message);
}
void
sic_fatal (const char *message)
{
error (EXIT_FAILURE, "FATAL", message);
}
|
I also need a definition of program_name ;
set_program_name copies the filename component of path into
the exported data, program_name . The xstrdup function
just calls strdup , but abort s if there is not enough
memory to make the copy:
|
const char *program_name = NULL;
void
set_program_name (const char *path)
{
if (!program_name)
program_name = xstrdup (basename (path));
}
|
|