|  |  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_namevariable 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_namecopies the filename component ofpathinto
the exported data,program_name.   Thexstrdupfunction
just callsstrdup, butaborts 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));
}
 | 
 
 |