[comp.lang.c] perror

peter@sugar.UUCP (Peter da Silva) (08/20/87)

> I know what you mean.  Well over half of all the calls to perror() I
> write look like perror((char *)0); because the prefix is more
                         ^^^^^^^^^ Bad practice.
> complicated than a single string, so I have fprintf(stderr,....);
> before the perror().  Wish perror() were printflike, perhaps like
> syslog() - syslog() accepts a printf format, except that %m means
> insert sys_errlst[errno].

You shouldn't pass null to perror. It's not guaranteed to work. It might
even crash you.

It's easy enough to do this:

	extern int errno;
	extern char **sys_errlst;

	fprintf(stderr, "%this, %that: %s\n", this, that, sys_errlst[errno]);
-- 
-- Peter da Silva `-_-' ...!seismo!soma!uhnix1!sugar!peter (I said, NO PHOTOS!)

levy@ttrdc.UUCP (Daniel R. Levy) (08/24/87)

In article <518@sugar.UUCP>, peter@sugar.UUCP (Peter da Silva) writes:
> You shouldn't pass null to perror. It's not guaranteed to work. It might
> even crash you.
> 
> It's easy enough to do this:
> 
> 	extern int errno;
> 	extern char **sys_errlst;

	/* Better:  */	extern char *sys_errlist[];
					     ^

	Note that "extern char **sys_errlst" would declare the location
	sys_errlst as containing a pointer to pointer to char, whereas
	"extern char *sys_errlist[]" declares the location sys_errlist
	as (more or less; purists will not agree) containing the first
	member of an array of pointer to char.  The results you get
	from trying to interchange the two in an extern declaration are
	surprising, to say the least.


> 
> 	fprintf(stderr, "%this, %that: %s\n", this, that, sys_errlst[errno]);

Note too that errno is not guaranteed to lie within the valid range of
sys_errlist.  sys_errlist is defined from errno==0 to errno==sys_nerr-1.

Perhaps a STRERR() macro would be helpful:

	extern int errno, sys_nerr;	/* declare these at the top */
	extern char *sys_errlist[];	/* of your module */

#define STRERR()	((errno >=0 && errno < sys_nerr) ? \
				sys_errlist[errno] : "Unknown error")

	...

	fprintf(stderr,"%this, %that: %s\n", this, that, STRERR());
	...

> -- Peter da Silva `-_-' ...!seismo!soma!uhnix1!sugar!peter (I said, NO PHOTOS!)

-- 
|------------Dan Levy------------|  Path: ..!{akgua,homxb,ihnp4,ltuxa,mvuxa,
|         an Engihacker @        |		vax135}!ttrdc!ttrda!levy
| AT&T Computer Systems Division |  Disclaimer:  i am not a Yvel Nad
|--------Skokie, Illinois--------|

boyd@necisa.ho.necisa.oz (Boyd Roberts) (07/03/90)

perror(3) is good, but this is better:

    char	*
    sysmess()
    {
	extern int	errno;
	extern int	sys_nerr;
	extern char	*sys_errlist[];

	if (errno < 0 || errno >= sys_nerr)
	    return "Unknown error";

	return sys_errlist[errno];
    }

    void
    could_not(what, with)
    register char    *what;
    register char    *with;
    {
	fprintf(stderr, "%s: Could not %s \"%s\". %s\n", my_name, what, with, sysmess());
	exit(1);
	/* NOTREACHED*/
    }

So then we go:

    if ((fd = open(file, O_RDONLY)) == -1)
    {
	could_not("open", file);
	/* NOTREACHED */
    }

Of course, my_name is:

char	*my_name;

And main() goes:

	if ((my_name = strrchr(argv[0], '/')) == NULLSTR || *++my_name == '\0')
		my_name = argv[0];


Boyd Roberts			boyd@necisa.ho.necisa.oz.au

``When the going gets wierd, the weird turn pro...''

meissner@osf.org (Michael Meissner) (07/03/90)

In article <1792@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd
Roberts) writes:

| perror(3) is good, but this is better:
| 
|     char	*
|     sysmess()
|     {
| 	extern int	errno;
| 	extern int	sys_nerr;
| 	extern char	*sys_errlist[];
| 
| 	if (errno < 0 || errno >= sys_nerr)
| 	    return "Unknown error";
| 
| 	return sys_errlist[errno];
|     }
| 
|     void
|     could_not(what, with)
|     register char    *what;
|     register char    *with;
|     {
| 	fprintf(stderr, "%s: Could not %s \"%s\". %s\n", my_name, what, with, sysmess());
| 	exit(1);
| 	/* NOTREACHED*/
|     }
| 
| So then we go:
| 
|     if ((fd = open(file, O_RDONLY)) == -1)
|     {
| 	could_not("open", file);
| 	/* NOTREACHED */
|     }
| 
| Of course, my_name is:
| 
| char	*my_name;
| 
| And main() goes:
| 
| 	if ((my_name = strrchr(argv[0], '/')) == NULLSTR || *++my_name == '\0')
| 		my_name = argv[0];
| 
| 
| Boyd Roberts			boyd@necisa.ho.necisa.oz.au
| 
| ``When the going gets wierd, the weird turn pro...''

You probably should use the ANSI name (strerror), and support the use
of old UNIX with sys_errlst and new ANSI with strerror, via:

#include <errno.h>
#ifndef BSD_STRINGS_H
#include <string.h>
#endif

#ifndef HAVE_STRERROR
char *
strerror(e)
{
  extern int	errno;
  extern int	sys_nerr;
  extern char	*sys_errlist[];

  if (e < 0 || e >= sys_nerr)
      return "Unknown error";

  return sys_errlist[e];
}
#endif

void
could_not(what, with)
register char    *what;
register char    *with;
{
  fprintf(stderr, "%s: Could not %s \"%s\". %s\n", my_name, what, with,
	  strerror(errno));
  exit(1);
  /* NOTREACHED*/
}


Not all non-UNIX systems have sys_errlist, and as internationalization
becomes more important, I would expect that people will soon want the
error messages to be presented in the user's native language.  You
also have the problem that old binaries using sys_errlist don't get
new error message strings without relinking.
--
Michael Meissner	email: meissner@osf.org		phone: 617-621-8861
Open Software Foundation, 11 Cambridge Center, Cambridge, MA

Do apple growers tell their kids money doesn't grow on bushes?

peter@ficc.ferranti.com (Peter da Silva) (07/03/90)

In article <1792@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes:
> perror(3) is good, but this is better:

[ lots of code deleted ]

Yep, that's probably better than perror by itself. You should probably call
"sysmess" "strerror" and wrap it in a "#ifndef __STDC__" (or a macro derived
from __STDC__), but that's a nitpick supreme. But one thing:

> 	if ((my_name = strrchr(argv[0], '/')) == NULLSTR || *++my_name == '\0')
> 		my_name = argv[0];

First, this is needlessly obscure. Second, it modifies argv[0], which is not
ps-friendly on UNIX.

How about:

	my_name = strrchr(argv[0], '/');
	if(my_name)
		my_name++;
	else
		my_name = argv[0];
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.
<peter@ficc.ferranti.com>

boyd@necisa.ho.necisa.oz (Boyd Roberts) (07/06/90)

In article <5XE49LB@xds13.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes:
> But one thing:
>
>> 	if ((my_name = strrchr(argv[0], '/')) == NULLSTR || *++my_name == '\0')
>> 		my_name = argv[0];
>
>First, this is needlessly obscure. Second, it modifies argv[0], which is not
>ps-friendly on UNIX.
>

1: `my_name' is modified.  It _points_ into argv[0]!  argv[0] is _not_ modified!

2: `ps' on UNIX doesn't necessarily look at the user processes stack!

3: Sure, it's not ANSI, it's C!


Boyd Roberts			boyd@necisa.ho.necisa.oz.au

``When the going gets wierd, the weird turn pro...''

peter@ficc.ferranti.com (Peter da Silva) (07/06/90)

Looks like I entered warp drive with my brain disengaged...

In article <1795@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes:
> In article <5XE49LB@xds13.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes:
> >> 	if ((my_name = strrchr(argv[0], '/')) == NULLSTR || *++my_name == '\0')
> >> 		my_name = argv[0];

> >First, this is needlessly obscure. Second, it modifies argv[0], which is not
> >ps-friendly on UNIX.

> 1: `my_name' is modified.  It _points_ into argv[0]!  argv[0] is _not_ modified!

You're right. I misinterpreted the expression. Which supports my first point:
to wit that it's needlessly obscure.
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.
<peter@ficc.ferranti.com>

Sm@bhpese.oz.au (Scott Merrilees) (07/07/90)

peter@ficc.ferranti.com (Peter da Silva) writes:
>In article <1792@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes:
>> 	if ((my_name = strrchr(argv[0], '/')) == NULLSTR || *++my_name == '\0')
>> 		my_name = argv[0];
>First, this is needlessly obscure. Second, it modifies argv[0], which is not
>ps-friendly on UNIX.
Obscure?  Sm thinks about flamefest ... but decides against it.
>
>How about:
>	my_name = strrchr(argv[0], '/');
>	if(my_name)
>		my_name++;
>	else
>		my_name = argv[0];
>-- 

When I looked at Boyd's, I thought it was needlessly verbose, but then I
saw that it does one more check than the below fragment that I use, which I
like because it fits neatly onto one line.

	prog = (prog = strrchr(*argv, '/')) == (char *)0 ? *argv : ++prog;

I've never come across the need for the *++my_name == '\0' check, has
anybody else?  Boyd?

Also, argv is not modified, only my_name.

Sm
-- 
Scott Merrilees, BHP Information Technology, Newcastle, Australia
Internet: Sm@bhpese.oz.au                    Phone: +61 49 402132

boyd@necisa.ho.necisa.oz (Boyd Roberts) (07/08/90)

In article <1990Jul7.020719.14239@bhpese.oz.au> Sm@bhpese.oz.au (Scott Merrilees) writes:
>
>I've never come across the need for the *++my_name == '\0' check, has
>anybody else?  Boyd?
>

Well, I haven't seen it, but it can happen.

But, the day someone goes...

    p = "/bin/junk/";

    execl(p, p, ..., (char *)0);

Or:

    $ /bin/junk/ ...

I don't want my messages to say:

    : Could not save "the world".  Not owner

The philosophy of ``it'll never* happen, so don't code for it'' is _wrong_.


Boyd Roberts			boyd@necisa.ho.necisa.oz.au

``When the going gets wierd, the weird turn pro...''

* never  == low probability, but still possible

boyd@necisa.ho.necisa.oz (Boyd Roberts) (07/08/90)

In article <+5H4EF6@ficc.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes:
>
>You're right. I misinterpreted the expression. Which supports my first point:
>to wit that it's needlessly obscure.

You _cannot_ be serious?  ``Needlessly obscure'' --  it's your view, not mine.


Boyd Roberts			boyd@necisa.ho.necisa.oz.au

``When the going gets wierd, the weird turn pro...''

Sm@bhpese.oz.au (Scott Merrilees) (07/09/90)

boyd@necisa.ho.necisa.oz (Boyd Roberts) writes:

>In article <1990Jul7.020719.14239@bhpese.oz.au> Sm@bhpese.oz.au (Scott Merrilees) writes:
>>I've never come across the need for the *++my_name == '\0' check, has
>>anybody else?  Boyd?

>Well, I haven't seen it, but it can happen.

>The philosophy of ``it'll never* happen, so don't code for it'' is _wrong_.
I agree, but was mainly wondering if you had been bitten, and thus started
checking for this.  Looks like I'll need to rethink my one-liner, damn!

Sm
-- 
Scott Merrilees, BHP Information Technology, Newcastle, Australia
Internet: Sm@bhpese.oz.au                    Phone: +61 49 402132

levy@mtcchi.uucp (2656-Daniel R. Levy(0000000)0000) (07/11/90)

henry@zoo.toronto.edu (Henry Spencer) writes:

>In article <JID4B=4@ficc.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes:
>>While picking nits, how about doing it right. There's really no excuse for
>>not calling perror...

>Yes there is:  it doesn't do what I want, which is a more informative
>message about the high-level nature of the problem.  A major reason why
>perror() doesn't get used is that it is simply too inflexible:  it takes
>too much extra work to put together a useful message, since that generally
>requires assembling an argument string out of pieces.  

Even worse, if it's done with what would seem the logical choice for
formatting strings, sprintf, depending on the stdio library (if it does
something silly like a write() to an illegal file descriptor) errno
might get altered before the call to perror().

>One often wants
>more information than just the filename and the error code.  Something
>like the Kernighan&Pike error() function is vastly more useful, but alas,
>not everyone has it.  If you're willing to rely on ANSI C facilities (or
>imitations of same, e.g. my old strings package), then strerror() can
>be used to get much the same effect.

Why lean on special functions?  It can be done simply and easily (at
least under UNIX environments) with a #define.

extern int errno;
extern int sys_nerr;
extern char *sys_errlist[];

#define sys_err		(errno < 0 || errno >= sys_nerr ? \
				"unknown error" : sys_errlist[errno])


	...
	if (stat(fname,&s) == -1) {
		(void) fprintf(stderr,"can't stat %s: %s\n",fname,sys_err);
		exit(1);
	}
	...
-- 
 Daniel R. Levy * Memorex Telex * Naperville IL * ..!uunet!tellab5!mtcchi!levy
So far as I can remember, there is not one      ... therefore be ye as shrewd
word in the Gospels in praise of intelligence.  as serpents and harmless as
-- Bertrand Russell [Berkeley UNIX fortune]     doves -- God [Matthew 10:16]