tchrist@convex.COM (Tom Christiansen) (10/27/90)
In article <8215:Oct2521:30:3890@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >In article <1990Oct25.075856.4923@robobar.co.uk> ronald@robobar.co.uk (Ronald S H Khoo) writes: >> perror(name); >> fprintf(stderr, "%s: error opening %s (see error message above)\n", >> progname, name); > >Correct but ugly. As long as you have an array sys_errlist[] with the >messages, you can just copy errno into a variable and use that. To skip >coding most of the common idioms you might snarf err.c from the pty >package. Note that POSIX doesn't really want you looking at perror. You should use strerror() to be compliant. Some POSIX systems do let you look at sys_errlist, but strictly conforming ones won't. The problem with fprintf() unjustly mucking with errno can be cleaned up a little by having isatty() resent errno to its previous value if it returns ENOTTY. I see no reason for putc to set ENOTTY; it's not relevant and confusing. This may cause a bunch of programs to print "Error 0" or "Not a system error" if you've changed sys_errlist[0] to say that, but so what? They all used to say "Not a typewriter", which was worse, because they confuse end-users by calling perror() inappropriately and getting spurious warnings. (One user actually once asked why he had to use a typewriter to send mail to a (non-existent) user before I made the aforementioned changes.) Here is a brief but evil package that could be made far more portable by using varargs, int sprintf(), and strerror; this should work as is on a non-POSIX paranoid, straight BSD system. The MESG macro helps the perror problem a bit. Use -DBSD=42, -DBSD=43, or -DBSD=44, depending on what flavor of sysexits.h you have. --tom #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # die.h # die.c # This archive created: Fri Oct 26 13:06:28 1990 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'die.h'" '(1193 characters)' if test -f 'die.h' then echo shar: "will not over-write existing file 'die.h'" else sed 's/^ X//' << \SHAR_EOF > 'die.h' X#ifndef FILE X#include <stdio.h> X#endif X X#ifndef EX_OK X#include <sysexits.h> X#endif X X X#ifdef MAIN X# define VAR(name,value) name = value X#else X# define VAR(name,value) extern name X#endif X XVAR( char Assert_Mask[], "Assertion botched <%s> in file \"%s\" @ line %d\n" ); X XVAR( char *program, "Unknown Program") ; /* set to basename(argv[0]) */ X Xchar _msg_errbuf[50]; X Xextern int errno, sys_nerr; Xextern char *sys_errlist[]; X X/* current error message */ X#define EMSG (errno < sys_nerr ? sys_errlist[errno] : DUNNO(errno)) X#define DUNNO(ERR) sprintf(_msg_errbuf, "unknown system error %d", ERR) Xextern char *sprintf (); X X/* system call succeeds or i die */ XVAR( char Failed_Syscall [], "syscall \"%s\" failed: %s"); X#define GOOD_SYS(Z) if (Z < 0) die (EX_OSERR, Failed_Syscall, "Z", EMSG) X X/* better assert */ X#ifndef FAST_AND_LOOSE X# define _assert(EXPR) \ X { if (!(EXPR)) { \ X fprintf( stderr, Assert_Mask, "EXPR", __FILE__, __LINE__); \ X abort(); /* generate core dump */ \ X } \ X } X# define assert(EXPR) _assert(EXPR) X#else X# define _assert(EXPR) X# define assert(EXPR) X#endif !FAST_AND_LOOSE X SHAR_EOF if test 1193 -ne "`wc -c < 'die.h'`" then echo shar: "error transmitting 'die.h'" '(should have been 1193 characters)' fi chmod 664 'die.h' fi echo shar: "extracting 'die.c'" '(1963 characters)' if test -f 'die.c' then echo shar: "will not over-write existing file 'die.c'" else sed 's/^ X//' << \SHAR_EOF > 'die.c' X#define MAIN X#include "die.h" X X/* X * die function. first argument should be a legit exit status X * out of sysexits.h; the rest should be arguments as you would X * give to printf(), ie, string format followed by optional arguments. X * X * note that you should bind (char *) program to your name X * X * here are examples: X X extern char *program; X program = rindex(*argv,'/'); X program = program ? program+1 : *argv; X X if (argc != 2) X die (EX_USAGE, "wanted one and only one argument"); X X if (!lock(lock_file)) X die (EX_TEMPFAIL, "couldn't secure lock on %s", lock_file); X X if (stat (USERS_FILE, &stat_info)) X die (EX_NOINPUT, "stat failed on %s: %s", USERS_FILE, EMSG); X X if ((buf = malloc ( (u_int) stat_info.st_size)) == 0) X die (EX_OSERR, "malloc(%d) failed: %s", stat_info.st_size, EMSG); X X if ((fd = open (USERS_FILE, O_RDONLY)) < 0) X die (EX_NOINPUT, "absurd error opening %s: %s", USERS_FILE, EMSG); X X if ((got = read (fd, buf, stat_info.st_size)) != stat_info.st_size) X die (EX_IOERR, "only read %d (not %d) from %s: %s", X got, stat_info_st.size, USERS_FILE, EMSG); X X * X * note also that the EMSG macro is the string of the current system error X * message, if you want to use it. this is the same as %m in syslog(). X * see below for required extern declarations if you wish to use EMSG. X */ X X/* VARARGS2 */ Xdie (status, fmt, args) X int status; X char *fmt; X int args; /* convenient lie */ X{ X X#if BSD == 42 /* { */ X assert(status >= EX_OK && status <= EX_NOPERM); X#else X#if BSD == 43 /* { */ X assert(status >= EX_OK && status <= EX_CONFIG); X#else X#if BSD >= 44 /* { */ X assert(status >= EX_OK && status <= EX__MAX); X#endif /* 44 } */ X#endif /* 43 } */ X#endif /* 42 } */ X X/* X * sigh; wish there were an EX_MAXEXIT to check against. X */ X X fprintf(stderr, "%s: ", program ? program : "unknown program"); X _doprnt(fmt, &args, stderr); X putc('\n', stderr); X X exit(status); X} SHAR_EOF if test 1963 -ne "`wc -c < 'die.c'`" then echo shar: "error transmitting 'die.c'" '(should have been 1963 characters)' fi chmod 664 'die.c' fi exit 0 # End of shell archive