/* vi: set tabstop=4 shiftwidth=4 */ /* * $Id: error.c,v 2.1 2005/06/17 20:48:15 schweikh Exp $ */ /*@ignore@*/ #ifndef _POSIX_SOURCE # define _POSIX_SOURCE 1 #endif /*@end@*/ #include #include #include #include #include #include "shutup.h" #include "error.h" /*@-ptrarith@*/ /*@-redecl@*/ /*@-predboolint -statictrans -globstate@*/ /* * progname is a short string prepended to error messages. */ /*@i1@*/ static char *progname = "(program name not assigned)"; #if MALLOC_DEBUG static FILE *debug; #endif long alloc_free = 0; /* # alloc minus # free */ static void err_doit (int, const char *, va_list ap) /*@globals progname,stderr,fileSystem,errno@*/ /*@modifies *stderr,fileSystem,ap,errno@*/; char * program_name (void) { return progname; } /* * Checked fprintf: do fprintf and exit if it failed * (probably due to an I/O or "no space on device" error). */ void cfprintf (FILE *fp, const char *fmt, ...) { va_list ap; va_start (ap, fmt); if (vfprintf (fp, fmt, ap) < 0) { err_sys ("fprintf failed for format `%s'", fmt); } va_end (ap); } /* * write program name to a stream and return * a pointer to static memory with the name. */ char * err_progname (FILE * fp) { if (fp != NULL) { check_sys (fflush (fp) == 0); cfprintf (fp, "%s", progname); check_sys (fflush (fp) == 0); } return progname; } void set_progname (char *argv0, char *def) { if (argv0 == NULL || argv0[0] == '\0') { progname = def; } else { char *p = strrchr (argv0, '/'); /* p + 1 um '/' übergehen */ progname = p == NULL ? argv0 : p + 1; } #if MALLOC_DEBUG debug = fopen (DEBUG_FILE, "w"); check_sys (debug != NULL); #endif } /* * Nonfatal error related to a system call. Print a message and return. */ void err_ret (const char *fmt, ...) { va_list ap; va_start (ap, fmt); err_doit (1, fmt, ap); va_end (ap); } /* * Fatal error related to a system call. Print a message and exit(). */ void err_sys (const char *fmt, ...) { va_list ap; va_start (ap, fmt); err_doit (1, fmt, ap); va_end (ap); exit (EXIT_FAILURE); } /* * Fatal error related to a system call. Print a message and dump core. */ void err_dump (const char *fmt, ...) { va_list ap; va_start (ap, fmt); err_doit (1, fmt, ap); va_end (ap); abort (); /*@NOTREACHED@*/ exit (EXIT_FAILURE); /* should never get here */ } /* * Nonfatal error unrelated to a system call. Print a message and return. */ void err_msg (const char *fmt, ...) { va_list ap; va_start (ap, fmt); err_doit (0, fmt, ap); va_end (ap); } /* * Fatal error unrelated to a system call. Print a message and exit(). */ void err_quit (const char *fmt, ...) { va_list ap; va_start (ap, fmt); err_doit (0, fmt, ap); va_end (ap); exit (EXIT_FAILURE); } static void err_doit (int errnoflag, const char *fmt, va_list ap) { int errno_save = errno; Fflush (stdout); Fprintf (stderr, "%s: ", progname); Vfprintf (stderr, fmt, ap); if (errnoflag != 0) { Fputc (':', stderr); Fputc (' ', stderr); errno = errno_save; perror (NULL); } else { Fputc ('\n', stderr); } Fflush (NULL); } void /*@unused@*//*@printflike@*/ warn (int flags, const char *fmt,...) { int errno_save = errno; va_list ap; va_start (ap, fmt); check_sys (fflush (NULL) == 0); cfprintf (stderr, "%s: ", progname); check_sys (vfprintf (stderr, fmt, ap) >= 0); if (flags & E_PERROR) { errno = errno_save; perror (" "); } else { check_sys (fputc ('\n', stderr) != EOF); } check_sys (fflush (stderr) == 0); } void /*@unused@*//*@printflike@*/ error (int flags, const char *fmt,...) { int errno_save = errno; va_list ap; va_start (ap, fmt); check_sys (fflush (NULL) == 0); cfprintf (stderr, "%s: ", progname); check_sys (vfprintf (stderr, fmt, ap) >= 0); if (flags & E_PERROR) { errno = errno_save; perror (" "); } else { check_sys (fputc ('\n', stderr) != EOF); } check_sys (fflush (stderr) == 0); if (flags & E_ABORT) abort (); else exit (EXIT_FAILURE); } /*@-compdef@*/ void * #if MALLOC_DEBUG xxmalloc (size_t s, char *file, int line) { void *p = malloc (s); if (p == NULL) error (0, "malloc(%lu)", (unsigned long) s); cfprintf (debug, "a %p %s:%d %lu\n", (void *) p, file, line, (unsigned long) s); ++alloc_free; return p; } #else /* !MALLOC_DEBUG */ xxmalloc (size_t s) { void *p = malloc (s); if (p == NULL) error (0, "malloc(%lu)", (unsigned long) s); ++alloc_free; return p; } #endif /*@only@*/ void * #if MALLOC_DEBUG xxcalloc (size_t n, size_t s, char *file, int line) { void *p = calloc (n, s); if (p == NULL) error (0, "calloc(%lu, %lu)", (unsigned long) n, (unsigned long) s); cfprintf (debug, "a %p %s:%d %lu\n", (void *) p, file, line, (unsigned long) n * s); ++alloc_free; return p; } #else /* !MALLOC_DEBUG */ xxcalloc (size_t n, size_t s) { void *p = calloc (n, s); if (p == NULL) error (0, "calloc(%lu, %lu)", (unsigned long) n, (unsigned long) s); ++alloc_free; return p; } #endif /* * realloc hat 3 Arbeitsweisen: * 1. realloc (0, s) wie malloc (s) * 2. realloc (oldp, 0) wie free (oldp) * 3. realloc (oldp, s) resize */ void * #if MALLOC_DEBUG xxrealloc (void *oldp, size_t newsize, char *file, int line) { void *newp; if (oldp != NULL) { --alloc_free; cfprintf (debug, "f %p %s:%d\n", (void *) oldp, file, line); } newp = realloc (oldp, newsize); if (newsize == 0) /* free */ return (void *) 1; /* dummy; nicht NULL wg lclint */ if (newp == NULL) error (0, "realloc(%lu)", (unsigned long) newsize); cfprintf (debug, "a %p %s:%d %lu\n", (void *) newp, file, line, (unsigned long) newsize); ++alloc_free; return newp; } #else /* !MALLOC_DEBUG */ xxrealloc (void *oldp, size_t newsize) { void *newp; if (oldp != NULL) --alloc_free; newp = realloc (oldp, newsize); if (newsize == 0) /* free */ return (void *) 1; /* dummy; nicht NULL wg lclint */ if (newp == NULL) error (0, "realloc(%lu)", (unsigned long) newsize); ++alloc_free; return newp; } #endif /*@-nullpass@*/ void #if MALLOC_DEBUG xxfree (void *p, char *file, int line) { if (p == NULL) { cfprintf (debug, "f NULL %s:%d\n", file, line); return; } cfprintf (debug, "f %p %s:%d\n", (void *) p, file, line); --alloc_free; free (p); } #else /* !MALLOC_DEBUG */ xxfree (void *p) { if (p != NULL) { --alloc_free; free (p); } } #endif