[comp.lang.c] Lint question

andrew@teletron.UUCP (Andrew Scott) (09/15/87)

I've noticed something odd while working with pointers to functions.
Specifically, I have a chunk of code which is simulating a function
call.  The code pushes a return address onto the "stack" (declared as
an integer array) like so:

	void foo()
	{
		/* do some stuff */
	}

	void push()
	{
		extern int *stack_ptr;

		*(--stack_ptr) = (int) foo;
	}


Lint returns the following messages:

	(10)  operands of CAST have incompatible types
	(10)  operands of = have incompatible types


However, lint is happy if I declare `foo' as:

	int foo()
	{
		/* do some stuff */
	}

In either case, the compiler says nothing and produces the intended code result.
Is my version of lint broken?  I would have thought that a cast from a function
pointer to an integer would be the same thing for any function, no matter what
type value it returns (including void).

	Andrew

pts@watt.acc.Virginia.EDU (Paul T. Shannon) (01/10/89)

I've been following the lint discussion, and decided it was high
time for me to use lint myself.  Here's a question for style experts:
Lint complains: 

function returns value which is always ignored
    fprintf	    printf

Is it bad style to use these functions without also checking the 
returned value?

gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/10/89)

In article <491@babbage.acc.virginia.edu> pts@watt.acc.Virginia.EDU (Paul T. Shannon) writes:
>function returns value which is always ignored
>    fprintf	    printf
>Is it bad style to use these functions without also checking the 
>returned value?

Since these functions can, and at times do, fail, in a robust program
you should indeed test their return values and take proper error-
recovery actions.  The one possible exception is
	(void)fprintf(stderr, "...: operation failed\n");
because if a write to the standard error output fails, you may have just
exhausted your error-recovery resources and can do no better anyway.
(What are you going to do, complain about THAT failure on stderr?)

Note the use of a (void) cast to explicitly discard an unused
function value.  This should not be done lightly; if properly used,
it indicates that the programmer realized that the function returns
a value but that it is not necessary in this particular instance to
use the value.  This will shut lint up, but that should not be the
prime motivation for using the cast!

peter@ficc.uu.net (Peter da Silva) (01/10/89)

In article <9322@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes:
> The one possible exception is
> 	(void)fprintf(stderr, "...: operation failed\n");
> because if a write to the standard error output fails, you may have just
> exhausted your error-recovery resources and can do no better anyway.
> (What are you going to do, complain about THAT failure on stderr?)

	if(fprintf(stderr, "...: operation failed\n") == FAIL) {
		if(!(fp = fopen("/dev/tty", "w"))) {
			if(!(fp = fopen("/dev/console", "w"))) {
				chdir("/tmp");
				abort();
			}
		}
		(void)fprintf(fp, "...: operation failed\n");
		fclose(fp);
	}

And to be totally safe, use open()...

Not entirely smiley. There are programs that don't have 0, 1, and 2 open
for lengths of time. Like, a modem callback program...
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.
Work: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180.   `-_-'
Home: bigtex!texbell!sugar!peter, peter@sugar.uu.net.                 'U`
Opinions may not represent the policies of FICC or the Xenix Support group.

bill@twwells.uucp (T. William Wells) (01/10/89)

In article <491@babbage.acc.virginia.edu> pts@watt.acc.Virginia.EDU (Paul T. Shannon) writes:
: I've been following the lint discussion, and decided it was high
: time for me to use lint myself.  Here's a question for style experts:
: Lint complains:
:
: function returns value which is always ignored
:     fprintf       printf
:
: Is it bad style to use these functions without also checking the
: returned value?

The return values of the printf family functions are not very
consistently defined. Because of this, one should never use their
return value.  You have to do the checking of printf before the
printf executes, i.e., either at the time you write the code or in
the code itself before the printf executes. (Except that I/O errors
need to be checked sometime after a flush has need done.  But that is
another can of worms entirely, caused by standard I/O buffering.)

I just ignore the lint message. On the other hand, if it said that
the function values were *sometimes* ignored, I'd go hunting for the
portability problem caused by using the return value.

---
Bill
{ uunet!proxftl | novavax } !twwells!bill

dwp@k.gp.cs.cmu.edu (Doug Philips) (01/11/89)

gwyn@smoke.BRL.MIL (Doug Gwyn ) writes:
:Note the use of a (void) cast to explicitly discard an unused
:function value.  This should not be done lightly; if properly used,
:it indicates that the programmer realized that the function returns
:a value but that it is not necessary in this particular instance to
:use the value.  This will shut lint up, but that should not be the
:prime motivation for using the cast!

Actually, my prime motivation for using it IS to shut up lint.
Strcpy and strcat return values that I almost never care about.  Lint
doesn't understand the "return value for the convenience of sometimes
having it" notion.  Perhaps this is a candidate for another SLM like
'vstrcat'?? ;-)

-- 
Doug Philips                  "All that is gold does not glitter,
Carnegie-Mellon University       Not all those who wander are lost..."
dwp@cs.cmu.edu                     -J.R.R. Tolkien
-- 

djones@megatest.UUCP (Dave Jones) (01/11/89)

 In article <9322@smoke.BRL.MIL), gwyn@smoke.BRL.MIL (Doug Gwyn ) writes:
) The one possible exception is
) 	(void)fprintf(stderr, "...: operation failed\n");
) because if a write to the standard error output fails, you may have just
) exhausted your error-recovery resources and can do no better anyway.
) (What are you going to do, complain about THAT failure on stderr?)
) 


Nope.  But under Unix, I'll complain on file-descriptor 2, if I think
that might help.

gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/11/89)

In article <2679@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:
>	if(fprintf(stderr, "...: operation failed\n") == FAIL) {
>		if(!(fp = fopen("/dev/tty", "w"))) {
>			if(!(fp = fopen("/dev/console", "w"))) {

Not really, because if somebody has redirected stderr it is probably
for a good reason, and such policy should not be overridden by an
application that doesn't know what's going on outside.  Blathering
on the console is particularly obnoxious in most cases.

gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/11/89)

In article <1172@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes:
>Nope.  But under Unix, I'll complain on file-descriptor 2, if I think
>that might help.

On UNIX, if stderr is not associated with FD 2, you would probably
be making a mistake to scribble on FD 2.

ftw@masscomp.UUCP (Farrell Woods) (01/11/89)

In article <491@babbage.acc.virginia.edu> pts@watt.acc.Virginia.EDU (Paul T. Shannon) writes:
>I've been following the lint discussion, and decided it was high
>time for me to use lint myself.  Here's a question for style experts:
>Lint complains: 
>
>function returns value which is always ignored
>    fprintf	    printf
>
>Is it bad style to use these functions without also checking the 
>returned value?

Since the printf() family of functions is writing something to somewhere,
they return the number of bytes written (and -1 if they failed).  If you
want to ignore the return value and be in style (;-)), you can use a void
cast:

	(void)printf(....);

This signals that you are explicitly ignoring the returned value.


-- 
Farrell T. Woods				Voice: (508) 692-6200 x2471
MASSCOMP Operating Systems Group		Internet: ftw@masscomp.com
1 Technology Way				uucp: {backbones}!masscomp!ftw
Westford, MA 01886				OS/2: Half an operating system

guy@auspex.UUCP (Guy Harris) (01/12/89)

>The return values of the printf family functions are not very
>consistently defined. Because of this, one should never use their
>return value.

More correctly:

	There exist at least two definitions of the return values
	of the printf family functions.  Because of this, you should
	only use their return value if you know your software will be
	built only in environments where one particular definition
	is in effect.

	The System V definition has them returning the number of
	characters printed on success, or EOF on failure, and this
	is also the definition in the current dpANS.  Thus, this
	definition will become more common in the future; eventually,
	most, if not all, systems will use this definition.  Even UNIX
	systems that "started with 4BSD" often have environments in
	which this definition is used.

peter@ficc.uu.net (Peter da Silva) (01/12/89)

In article <9332@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes:
> In article <2679@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:
> >	if(fprintf(stderr, "...: operation failed\n") == FAIL) {
> >		if(!(fp = fopen("/dev/tty", "w"))) {
> >			if(!(fp = fopen("/dev/console", "w"))) {

> Not really, because if somebody has redirected stderr it is probably
> for a good reason, and such policy should not be overridden by an
> application that doesn't know what's going on outside.  Blathering
> on the console is particularly obnoxious in most cases.

You're right. I should probably have included a reference to "/dev/smiley"
in there. Blathering to "/dev/tty" is a different matter. If you can't open
/dev/tty, then something is pretty wrong. What happens if you do this:

	fclose(stdin); fclose(stdout); fclose(stderr);
	setpgrp();
	if(!(fp = fopen("/dev/tty", "w+"))) {
		...
	}

But for an application (like a modem callback program) that DOES know what's
going on outside might be perfectly justified in blathering on the console.
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.
Work: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180.   `-_-'
Home: bigtex!texbell!sugar!peter, peter@sugar.uu.net.                 'U`
Opinions may not represent the policies of FICC or the Xenix Support group.

maujt@warwick.ac.uk (Richard J Cox) (01/13/89)

In article <317@twwells.uucp> bill@twwells.UUCP (T. William Wells) writes:
>In article <491@babbage.acc.virginia.edu> pts@watt.acc.Virginia.EDU (Paul T. Shannon) writes:
>: function returns value which is always ignored
>:     fprintf       printf
>:
>: Is it bad style to use these functions without also checking the
>: returned value?
>
>The return values of the printf family functions are not very
>consistently defined. Because of this, one should never use their
>return value.  You have to do the checking of printf before the


There are situations where you have to check the return values.
e.g. when fprinting to a pipe or socket, in this case the process at
the other end of the pipe may have died, and in this case the fprintf
_will_fail_. This was causing a major bug in a program I wrote, and
it was in pure desperation I checked the return value.

- RC

/*--------------------------------------------------------------------------*/
JANET:  maujt@uk.ac.warwick.cu     BITNET:  maujt%uk.ac.warwick.cu@UKACRL
ARPA:   maujt@cu.warwick.ac.uk	   UUCP:    maujt%cu.warwick.ac.uk@ukc.uucp
Richard Cox, 84 St. Georges Rd, Coventry, CV1 2DL; UK PHONE: (0203) 520995

maujt@warwick.ac.uk (Richard J Cox) (01/13/89)

In article <2679@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:
>In article <9322@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes:
>
>Not entirely smiley. There are programs that don't have 0, 1, and 2 open
>for lengths of time. Like, a modem callback program...

Or any daemon, especially where you have a daemon fprintf'ing to sockets,
connected to processes that may have died.....

- RC

/*--------------------------------------------------------------------------*/
JANET:  maujt@uk.ac.warwick.cu     BITNET:  maujt%uk.ac.warwick.cu@UKACRL
ARPA:   maujt@cu.warwick.ac.uk	   UUCP:    maujt%cu.warwick.ac.uk@ukc.uucp
Richard Cox, 84 St. Georges Rd, Coventry, CV1 2DL; UK PHONE: (0203) 520995

henry@utzoo.uucp (Henry Spencer) (01/16/89)

In article <491@babbage.acc.virginia.edu> pts@watt.acc.Virginia.EDU (Paul T. Shannon) writes:
>function returns value which is always ignored
>    fprintf	    printf
>
>Is it bad style to use these functions without also checking the 
>returned value?

A troublesome point.  Although in general one should always check the
return values from functions that might fail, printf is a singularly
annoying case of a function that could fail but very rarely does, and
is a pain to check -- especially since the type of its returned value
is not portable among current Unixes.  My own inclination is to list
it in the "utter paranoia" category, to be checked if something crucial
is at stake (e.g. loss of user data), and to assume that otherwise the
failure is likely to be noticed without explicit attention.

Stdio is a glaring example of a library package that would benefit
greatly from a better error-handling mechanism.
-- 
"God willing, we will return." |     Henry Spencer at U of Toronto Zoology
-Eugene Cernan, the Moon, 1972 | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

bet@dukeac.UUCP (Bennett Todd) (01/17/89)

>Lint complains: 
>
>function returns value which is always ignored
>    fprintf	    printf
>
>Is it bad style to use these functions without also checking the 
>returned value?

*All* possible error routines should be checked, with only one exception that
I know of:

	if (fatal failure) {
		(void) fprintf(stderr, "suitable error message");
		exit(error_level);
	}

There's no point in checking for an error writing to stderr, since you
couldn't report it anyway, and all you are going to do is exit.

I found that wrapping suitable error checking and disposal around every last
function call got tedious, fast. So, I started a library of routines (up to 20
now; I add more as needed) which are simply wrappers around system calls
(section 2 UPM) and library routines (section 3 UPM) which check the status of
the called routine, and if it failed, print a suitable message and exit. So,
in the usual case (seems to be better than 90% of the time) I just use the
efunc_name() routine and am done with it. For example, ewrite() and efwrite()
are of type void, whereas efopen() is of type FILE * and guaranteed to return
a valid FILE pointer (or not come back at all). As long as I was inserting my
own layer between my code and stdio, I added as a frill cacheing filenames in
eopen() and efopen(), for use in diagnostic messages. Also, emalloc() prepends
and appends validation signatures to each allocated unit, which erealloc() and
efree() check. So, diagnostics are delivered as soon as possible after you
corrupt the malloc arena. This sort of approach makes life much easier for me
in writing and debugging programs.

-Bennett
bet@orion.mc.duke.edu

geoff@warwick.UUCP (Geoff Rimmer) (01/17/89)

In article <1989Jan16.080743.2424@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes:

>    [...]
>printf ...
>is a pain to check -- especially since the type of its returned value
>is not portable among current Unixes.  

I thought that problem was only with sprintf, where on some systems it
returns the string it has just produced, and on others the number of
characters written to the string.  I understood that both printf and
fprintf return int (# chars printed) on every system.

cat > /usr/include/std/flame-inviter.h
Please correct me if I'm wrong.
^D

#include <std/flame-inviter>

Geoff

	------------------------------------------------------------
	Geoff Rimmer, Computer Science, Warwick University, England.
			geoff@uk.ac.warwick.emerald

	"Well I think it's rubbish.  I'm going to vomit."
	"I can think of no higher compliment."

		- Filthy Rich and Catflap, 1986.
	------------------------------------------------------------

chip@ateng.ateng.com (Chip Salzenberg) (01/18/89)

According to henry@utzoo.uucp (Henry Spencer):
>[...] printf is a singularly
>annoying case of a function that could fail but very rarely does, and
>is a pain to check -- especially since the type of its returned value
>is not portable among current Unixes.

One portable solution would be an occasional test of ferror(stdout).
-- 
Chip Salzenberg             <chip@ateng.com> or <uunet!ateng!chip>
A T Engineering             Me?  Speak for my company?  Surely you jest!
	  "It's no good.  They're tapping the lines."

jcbst3@cisunx.UUCP (James C. Benz) (01/18/89)

In article <9322@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>you should indeed test their return values and take proper error-
>recovery actions.  The one possible exception is
>	(void)fprintf(stderr, "...: operation failed\n");
>because if a write to the standard error output fails, you may have just

Okay, so where does one find out what error codes are returned from these
stdio functions?  The UNIX (AT&T 3B2) manuals I have say nothing in printf(3S)
about error codes, and stdio(3S) says "Individual function descriptions 
describe the possible error conditions"  Sounds like Catch 22 to me.

guy@auspex.UUCP (Guy Harris) (01/18/89)

>Okay, so where does one find out what error codes are returned from these
>stdio functions?  The UNIX (AT&T 3B2) manuals I have say nothing in printf(3S)
>about error codes,

If by "error codes" you mean something like "errno" codes,
"printf"-family routines don't return them, but then *no* UNIX routine I
know of returns one - they all "return" them by setting "errno".  The
section 2 manual pages explicitly list values to which "errno" will be
set (although the lists are quite often incomplete); unfortunately, most
section 3 manual pages don't.  By and large, you can probably expect
that they can return any of the ones "read" or "write" can return
("write" in the case of "printf", for example), and that they *may*
return any of the others. 

If you mean "how can I test to see if they got an error *at all*,"
the AT&T 3B2 S5R3 manual says:

	Each function returns the number of characters transmitted (not
	counting the \0 in the case of "sprintf"), or a negative value
	if an output error is encountered.

in the first paragraph; perhaps earlier documentation didn't say this. 
The dpANS (or is it a pANS now?) says basically the same thing.  Some
older versions of UNIX, and some other versions of UNIX, or environments
within those vesrions, that maintain compatibility with those older
versions, have different return values (0 on success, -1 on error), but
over time those versions will most likely adopt the dpANS conventions.

gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/19/89)

In article <15024@cisunx.UUCP> jcbst3@unix.cis.pittsburgh.edu (James C. Benz) writes:
>Okay, so where does one find out what error codes are returned from these
>stdio functions?  The UNIX (AT&T 3B2) manuals I have say nothing in printf(3S)
>about error codes, and stdio(3S) says "Individual function descriptions 
>describe the possible error conditions"  Sounds like Catch 22 to me.

I don't know what you mean by "error codes".  The printf(3S) description
in the SVR3.0 PRM clearly states that the *printf() functions return the
number of characters transmitted, or a negative number in case of error.
(Happens that the negative number is -1, but you're not supposed to know
that.)  As with all UNIX system service-related operations, if some
system call failed, the extern int "errno" is set to hold one of the
error numbers described in the introduction to section 2 of the manual.
However, library functions such as printf(3S) can fail for reasons other
than system call failure, and even a successful printf(3S) may have
generated a system call failure on the way (typically a failed ioctl(2)
invocation to determine whether the stream is associated with a terminal),
so it is unwise to rely on the contents of errno to tell you anything
meaningful about the causes of printf(3S) errors.  Just consider them
"mysterious failures" and take appropriate recovery steps.

bph@buengc.BU.EDU (Blair P. Houghton) (01/20/89)

In article <1188@dukeac.UUCP> bet@dukeac.UUCP (Bennett Todd) writes:
>*All* possible error routines should be checked, with only one exception that
>I know of:
>
>	if (fatal failure) {
>		(void) fprintf(stderr, "suitable error message");
>		exit(error_level);
>	}
>
>There's no point in checking for an error writing to stderr, since you
>couldn't report it anyway, and all you are going to do is exit.

Howsabout if the poor return from fprintf indicates that stderr is
missing, and you therefore specify logging the unreportable errors
to a file?

				--Blair

gvr@cs.brown.edu (George V. Reilly) (03/14/90)

Given the following code, lint complains:
	point.c(33): warning: evaluation order for ``dx'' undefined

The complaint turns out to be caused by the subexpression
	(dx *= dx)

Surely, the parenthesization and comma operators make the whole
expression well defined?

=========================================================================
typedef struct {
   int x, y;
} Point;


/* ----------------------------------------------------------------------
 * 
 *   closest_point():  Return the index of point |pt| within
 * point-table |table| of size |n|.  Return -1 on error.
 * 
 * ----------------------------------------------------------------------
 */

int
closest_point(pt, table, n)
   Point	pt;
   Point	table[];
   int		n;
{
   register int	min = MAXINT, dist, dx, dy, result = -1, x, y;

   x = pt.x; y = pt.y;
   while (--n >= 0) {
      /* Ugly but efficient test for proximity */
      if (((dx = table[n].x - x), ((dx *= dx) < min))  &&
	  ((dy = table[n].y - y), ((dist = dx + dy*dy) < min))) {
	 result = n; min = dist;
      }
   }
   return (result);
}
=========================================================================

________________
George V. Reilly			gvr@cs.brown.edu
uunet!brunix!gvr   gvr@browncs.bitnet	Box 1910, Brown U, Prov, RI 02912

CMH117@psuvm.psu.edu (Charles Hannum) (03/14/90)

In article <32699@brunix.UUCP>, gvr@cs.brown.edu (George V. Reilly) says:
>
>      if (((dx = table[n].x - x), ((dx *= dx) < min))  &&
            ^^^^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^
The C compiler could calculate these expressions in any way it damned well
feels like it.  This is not defined in the ANSI C standard, mainly because
it would screw up optimizing compilers to have limits on the order of
evaluation when not necessary.


Virtually,
- Charles Martin Hannum II       "Klein bottle for sale ... inquire within."
    (That's Charles to you!)     "To life immortal!"
  cmh117@psuvm.{bitnet,psu.edu}  "No noozzzz izzz netzzzsnoozzzzz..."
  c9h@psuecl.{bitnet,psu.edu}    "Mem'ry, all alone in the moonlight ..."

utility@quiche.cs.mcgill.ca (Ronald BODKIN) (03/15/90)

In article <90072.232413CMH117@psuvm.psu.edu> CMH117@psuvm.psu.edu (Charles Hannum) writes:
>>      if (((dx = table[n].x - x), ((dx *= dx) < min))  &&

>The C compiler could calculate these expressions in any way it damned well
>feels like it.  This is not defined in the ANSI C standard...

	So, in general, the expression a, b does not define an order of
operations?  I had assumed that writing a, b allowed sequential
operations to be performed in computing expressions (great for macros).
	Ron

CMH117@psuvm.psu.edu (Charles Hannum) (03/15/90)

In article <90072.232413CMH117@psuvm.psu.edu>, Charles Hannum
<CMH117@psuvm.psu.edu> says:
>
>In article <32699@brunix.UUCP>, gvr@cs.brown.edu (George V. Reilly) says:
>>
>>      if (((dx = table[n].x - x), ((dx *= dx) < min))  &&
>            ^^^^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^
>The C compiler could calculate these expressions in any way it damned well
>feels like it.  This is not defined in the ANSI C standard, mainly because
>it would screw up optimizing compilers to have limits on the order of
>evaluation when not necessary.

Okay.  It looks like I was wrong about this.

NOW QUIT SENDING ME HATE MAIL!!!


Virtually,
- Charles Martin Hannum II       "Klein bottle for sale ... inquire within."
    (That's Charles to you!)     "To life immortal!"
  cmh117@psuvm.{bitnet,psu.edu}  "No noozzzz izzz netzzzsnoozzzzz..."
  c9h@psuecl.{bitnet,psu.edu}    "Mem'ry, all alone in the moonlight ..."

sanders@sanders.austin.ibm.com (Tony Sanders) (03/16/90)

In article <90072.232413CMH117@psuvm.psu.edu> CMH117@psuvm.psu.edu (Charles Hannum) writes:
>
>In article <32699@brunix.UUCP>, gvr@cs.brown.edu (George V. Reilly) says:
>>
>>      if (((dx = table[n].x - x), ((dx *= dx) < min))  &&
>            ^^^^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^
>The C compiler could calculate these expressions in any way it damned well
>feels like it.  This is not defined in the ANSI C standard, mainly because
>it would screw up optimizing compilers to have limits on the order of
>evaluation when not necessary.
Not so fast!  The only place where comma order is undefined is in
function calls.  The comma OPERATOR has left to right evaluation order.
Anyway, this problem isn't related at all to the comma operator anyway,
read on.

The problem lies not in the (self admited) ugly if statement but in the
use of "dx *= dx" itself.  For example a simple "r = (x*=x);" will also
complain of evaluation order undefined (with my lint).  While "r = (x=x*x);"
slips by lint without a word (as it should).

Sounds like a lint bug to me.

As ugly as the if statement was, it is prefectly legal code.
If you want the code to lint clean just change the "dx*=dx" to "dx=dx*dx".

However, I higly suggest rethinking the problem and make the code "cleaner".

-- sanders                          The 11th commandment: "Thou shalt use lint"
For every message of the day, a new improved message will arise to overcome it.
Reply-To: cs.utexas.edu!ibmaus!auschs!sanders.austin.ibm.com!sanders     (ugh!)