[comp.unix.wizards] error messages

rbj@icst-cmr.arpa (Root Boy Jim) (01/07/87)

> as mentioned in previous articles, when you enter the command 'make love'
> on unix, the error message is 'don't know how to make love. stop.'

Some of you will remember that TECO when executed as `MAKE' with a file
name of `LOVE' would say `Not War?' before entering input mode. Yow!

	(Root Boy) Jim Cottrell		<rbj@icst-cmr.arpa>
	My nose feels like a bad Ronald Reagan movie...

P.S. I guess that's what happens when you don't `Just Say No'.

bernsten@phoenix.Princeton.EDU (Dan Bernstein) (04/03/89)

I don't know about System V, but under BSD systems, including <errno.h>
gives you not only perror() but a sys_errlist[] of error message texts.
So how about this error message facility:

  static char unknownerr[32];

  char *err(errno)
  int errno;
  {
   if (errno < 0 || errno >= sys_nerr)
    {
     (void) sprintf(unknownerr,"Unknown error number %d",errno);
     return(unknownerr);
    }
   else
     return(sys_errlist[errno]);
  }

This is not a high-level routine, nor should it be. Instead of
attempting to build the generality of printf() into the error
message printer, I just reference err(errno) and use printf()
or sprintf() as usual. Why rebuild what's already there?

Some say that the error message facility should automatically print the
program name for you, and others say that the wave of ANSI/the future
is to include info/warning/verybad/fatal/endoftheworld; I'm happy with

    fprintf(stderr,"%s: cannot open %s: %s\n",progname,fn,err(errno))
or
    fprintf(stderr,"%s: endoftheworld: cannot open %s: %s\n",
	    progname,fn,err(errno))

(here progname is (argv[0] ? argv[0] : "Unknown program name")).

Along the same philosophy that motivates err(): if I ever found a need
to specify info/warning/fatal dynamically, I would much rather have a
function errlev() that returned a string based on a numeric input, and
continue using printf() at the top, than write a new errmsg() routine
for the occasion. I think this is the same philosophy behind a lot of
UNIX: combine little programs and functions to do big work.

---Dan Bernstein, bernsten@phoenix.princeton.edu

chris@mimsy.UUCP (Chris Torek) (04/03/89)

In article <7555@phoenix.Princeton.EDU> bernsten@phoenix.Princeton.EDU
(Dan Bernstein) writes:
>  char *err(errno)
>  int errno;
>  {
>   if ...
[compressed]
>   else
>     return(sys_errlist[errno]);
>  }

This function is in the pANS, where it is called `strerror'.  (The
implementation details---sys_errlist[], etc.---are not, but the function
that does what the one above does is called strerror.)

A slightly shorter test for the error number is

	if ((unsigned)errno >= sys_nerr)
		<out of range>
	else
		<in range; use sys_errlist>

>This is not a high-level routine, nor should it be. Instead of
>attempting to build the generality of printf() into the error
>message printer, I just reference err(errno) and use printf()
>or sprintf() as usual. Why rebuild what's already there?

Having an error printer that also exits is more convenient.  Since
the latter is cheap (using vfprintf), why not provide both?  I have
the function

	error(int exitcode, int err, char *fmt, ...)

in our C library.  It prints to stderr the program name (hidden away in
the external `_argv0', set by /lib/crt0.o), the string given by fmt+...,
appends strerror(err < 0 ? errno : err) if err != 0, appends a newline,
and then does an exit(exitcode) if exitcode != 0.  (err is almost always
given as -1, and should perhaps be replaced with a boolean.  If you want
something fancier, strerror() is there.)  It is very handy:

	if (argc < 2)
		error(2, 0, "usage: %s filename", argv[0]);
	if ((fd = open(argv[1], mode)) < 0)
		error(1, -1, "cannot open %s", argv[1]);
	...

Without it, you need

	extern int errno;

	if (argc < 2) {
		(void) fprintf(stderr, "%s: usage: %s filename\n",
		    argv[0], argv[0]);
		exit(2);
	}
	if ((fd = open(argv[1], mode)) < 0) {
		(void) fprintf(stderr, "%s: cannot open %s: %s\n",
		    argv[0], argv[1], strerror(errno));
		exit(1);
	}

The difference is small, but significant (somewhat like using E-
notation for large floating point numbers---1.14E75 is easier to
read and write than 1140000000...000).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

guy@auspex.auspex.com (Guy Harris) (04/04/89)

>I don't know about System V, but under BSD systems, including <errno.h>
>gives you not only perror() but a sys_errlist[] of error message texts.

This dates back long before BSD; it's a V7ism, and present in any modern
UNIX worthy of the name. 

>  char *err(errno)

Call it "strerror" instead - the ANSI C draft does.

>Some say that the error message facility should automatically print the
>program name for you, and others say that the wave of ANSI/the future
>is to include info/warning/verybad/fatal/endoftheworld;

I don't know about the wave of the future, but the (draft) ANSI C
standard says nothing about info/warning/...; POSIX P1003.1, which at
least at one point touted itself as a draft American National Standard -
although the final P1003.1 doesn't do so - says nothing about it either,
so I don't think it's the wave of ANSI.

It may show up in S5R4, but if so it'll probably let you turn off stuff
such as that if you don't want to see it.