/**************************************************************************** * myperror() myerror() - variadic/varargs functions to call perror() * * These take a standard printf()-style format string and arguments. * The functions ensure that errno is not changed before perror() is called. * No buffers are used (no overflow possible); output is directly to stderr. * The format strings must not be NULL or empty. * * Use: myerror(format [,args...]); - this one exits * myperror(format [,args...]); - this one does not exit * * e.g. myerror("Cannot open file '%s' for reading", filename); * myerror("Cannot connect to host '%s' port %d", host, portno ); * myperror("Please try another name: '%s'", filename); * * Read: * http://www.gnu.org/software/libc/manual/html_node/Variadic-Functions.html * See the NOTES in "man errno" about saving errno across printf * * License: GNU Public License (GPL) version 2 or later * * Author: -Ian! D. Allen - idallen@idallen.ca - www.idallen.com **************************************************************************** */ #include #include #include #include #include #include #include #include "myerror.h" static void vmyperror(char *fmt, va_list ap); /* Call perror() with a printf()-style varargs argument list */ void myperror(char *fmt, ...){ va_list ap; assert(fmt != NULL && *fmt != '\0');/* must have a non-empty format */ va_start(ap, fmt); vmyperror(fmt,ap); /* call the helper function */ va_end(ap); } /* This function is the same as myperror(), except that it exit()s */ void myerror(char *fmt, ...){ va_list ap; assert(fmt != NULL && *fmt != '\0');/* must have a non-empty format */ va_start(ap, fmt); vmyperror(fmt, ap); /* call the helper function */ va_end(ap); exit(1); /*NOTREACHED*/ } /* Helper function used for the common code in the above functions. * Takes a va_list pointer (not a varargs list of arguments). * If fmt ends in a newline, need to also put the program name in front of * the perror() message, otherwise let perror() message go on same line. */ static void vmyperror(char *fmt, va_list ap){ extern char *progname; /* set to argv[0] in main() */ char *pnewline; /* pointer into fmt string */ int save = errno; /* save errno across other syscalls */ fprintf(stderr,"%s: ", progname); /* may alter errno */ vfprintf(stderr, fmt, ap); /* may alter errno */ errno = save; /* restore saved value for perror() */ /* If fmt is not empty and ends in a newline, add progname */ pnewline = strchr(fmt,'\0'); perror( (pnewline > fmt && pnewline[-1] == '\n') ? progname : " " ); } /****************************************************************************/ /****************************************************************************/ /* This is a stub main() program to test the above functions. */ #define MAIN_DEFINED 1 #ifdef MAIN_DEFINED #include #include #include char *progname; /* global set to contain pointer to program name */ int main(int argc, char **argv){ /* make sure the program name is there - no null pointers */ progname = (argv != NULL && argv[0] != NULL && argv[0][0] != '\0') ? argv[0] : "UNKNOWN PROGRAM NAME"; read(99,0,0); /* cause a syscall error */ /* generate a message without a newline; no exit */ myperror("Hello %s this is my %dst message", "Ian", 1); open("/",1); /* cause a syscall error */ /* generate a message with a newline; function exits */ myerror("Hello %s this is my %dnd message.\n", "Ian", 2); assert(0); /*NOTREACHED*/ } #endif