[comp.misc] "Invalid null command"

rcd@ico.isc.com (Dick Dunn) (04/02/91)

Bourne shell users, accustomed to creating or emptying a file with a
command like:
	>splot
or rewinding a tape with:
	</dev/mt0
are occasionally annoyed to find that csh rejects this syntax with the
confusing message "Invalid null command".  (It is confusing because there
is no such thing as a *valid* null command; attempts to find one will only
end in frustration.)

This can be solved as follows:
	touch /bin/IEFBR14
	chmod 755 IEFBR14
The name is chosen for historical relevance, since most of us who still
use the Bourne shell are Luddites or recidivists anyway.  Of course,
	IEFBR14 >splot
seems a bit naked without some slashes and an EXEC PGM=, but that's the
way these modern systems are...

Some folks may note a more-than-coincidental resemblance between this
version of IEFBR14 and older versions of /bin/true.  So it is, but our
example lacks the sophistication of the modern System V "true" command,
which is now 9 lines long and includes
	- an entirely superfluous :
	- five lines of copyright notice (so don't y'all go trying to use
	  empty files any more; AT&T owns the copyright)
	- a #ident--which, of course, is meaningless to the shell, but
	  reveals the interesting fact that we're now up to version 2.3
	  of a formerly-empty file

However, the preceding was only for illustration anyway.  Nobody wants a
dirty old shell script for the null command; it should of course be a C
program for efficiency.  So here we have the first cut at IEFBR14.c:
	main()
	{
	}
This also serves only for illustration; it is historically accurate in that
it contains the same bug as IBM's original IEFBR14.  (It may be of some
interest that IEFBR14 proved the old CS aphorism "Every program contains
at least one bug and can be shortened by one instruction" at the inductive
limit:  It was a single instruction which didn't work...but I digress...) 
Here's the first correction:
	main()
	{
		exit(0);
	}
But to make this proper in today's brave new world, we need <stdlib.h>.
Also, for formality's sake and international propriety, we should add the
normally-obligatory setlocale() call (actually not necessary--this may be
the *only* program for which that's true--but it's hard to pass up poking
fun at a requirement to set a default explicitly), and this in turn
requires <locale.h>.  OK, so here's the penultimate version of IEFBR14.c,
our properly ANSI and internationalized (unless I screwed up) program-to-
do-nothing:

	#include <stdlib.h>
	#include <locale.h>

	#ifndef	lint
	static char *sccsid = "%W% - %E%";
	#endif

	/*ARGSUSED*/
	main(argc,argv)
	int	argc;
	char	**argv;
	{
		setlocale(LC_ALL, "");
		exit(0);
	}

To create the final version, all you need is your local draconian
corporate screenful of copyright notice and disclaimer.
-- 
Dick Dunn     rcd@ico.isc.com -or- ico!rcd       Boulder, CO   (303)449-2870
   The Official Colorado State Vegetable is now the "state legislator".

trt@rti.rti.org (Thomas Truscott) (04/03/91)

The IEFBR14 posting is one of those pleasant surprises on Usenet,
a must-have program for the thoughtful programmer's toolchest.
But it included neither Makefile nor man page, was that an oversight?

Alas IEFBR14.c seems to have portability problems.
A proposed revision is included below.
I am no language-lawyer, and am uncertain if main's value must be
declared (int, or void?), or whether one must declare
function arguments that are unused.
But I am confident that a few more revisions will yield a marvel,
a trophy even for Ritchie himself!
	Tom Truscott
----------------
(Revised lines preceded with '**')

**	#if defined(vms)
**	/* avoid VMS install-specific problems */
**	#include stdlib.h
**	#include locale.h
**	#else
	#include <stdlib.h>
	#include <locale.h>
**	#endif

**	/* System-specific exit status (K&R 2nd Ed, page 252) */
**	#if !defined(EXIT_SUCCESS)
**	/* Should print a warning here, but cannot in ANSI C */
**	#define EXIT_SUCCESS 0
**	#endif
	
	#ifndef	lint
	static char *sccsid = "%W% - %E%";
	#endif
	
	/*ARGSUSED*/
**	main(int argc, char *argv[], char *envp[])
	{
		setlocale(LC_ALL, "");
**		exit(EXIT_SUCCESS);
**		/* NOTREACHED */
	}

monardo@cshl.org (Pat Monardo) (04/03/91)

In article <1991Apr2.005620.11434@ico.isc.com> rcd@ico.isc.com (Dick Dunn) writes:
>
>Bourne shell users, accustomed to creating or emptying a file with a
>command like:
>	>splot
>or rewinding a tape with:
>	</dev/mt0
>are occasionally annoyed to find that csh rejects this syntax with the
>confusing message "Invalid null command".  (It is confusing because there
>is no such thing as a *valid* null command; attempts to find one will only
> end in frustration.)
;
i.e. a null command is valid if followed by a semicolon.

hahn@nas.nasa.gov (Jonathan Hahn) (04/03/91)

In article <1991Apr2.005620.11434@ico.isc.com> rcd@ico.isc.com (Dick Dunn) writes:
>
>Bourne shell users, accustomed to creating or emptying a file with a
>command like:
>	>splot
>are occasionally annoyed to find that csh rejects this syntax with the
>confusing message "Invalid null command".  (It is confusing because there
>is no such thing as a *valid* null command; attempts to find one will only
>end in frustration.)
>
>This can be solved as follows:
>	touch /bin/IEFBR14
>	chmod 755 IEFBR14

>Dick Dunn     rcd@ico.isc.com -or- ico!rcd       Boulder, CO   (303)449-2870

I realize that some or all of this article may have been intended to be
tongue-in-cheek.  Be that as it may, for those concerned about efficiency
all the methods mentioned involved a lot of overhead (i.e. system calls)
which could be elliminated by using the following alias:

	alias \> 'echo>'

This allows

	>splot

to behave as it does in the Bourne shell, and doesn't require a fork because
"echo" is a csh built-in.

-jonathan hahn
--
hahn@gigantor.nas.nasa.gov				wk: (415) 604-4360
..!ames!amelia!hahn					hm: (408) 736-7014

barmar@think.com (Barry Margolin) (04/03/91)

In article <1991Apr2.212348.8565@nas.nasa.gov> hahn@gigantor.nas.nasa.gov (Jonathan Hahn) writes:
>	alias \> 'echo>'
>
>This allows
>
>	>splot
>
>to behave as it does in the Bourne shell, and doesn't require a fork because
>"echo" is a csh built-in.

Actually, it should be

	alias \> 'echo -n >'

Otherwise you'll write a newline to splot, rather than just truncating it.
--
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

tom@sco.COM (Tom Kelly) (04/03/91)

In article <1991Apr2.005620.11434@ico.isc.com> rcd@ico.isc.com (Dick Dunn)
pedantically derives the C version of good old IEFBR14.  In that spirit,
here are some pedantic comments:

First try:

>	main()
>	{
>	}
 ...

>Here's the first correction:
>	main()
>	{
>		exit(0);
>	}
>But to make this proper in today's brave new world, we need <stdlib.h>.

Actually, no you don't.  The ANSI C Standard, Section 2.1.2.2
"Hosted Environment", subparagraph titled "Program termination" says:

	A return from the initial call to the main function is equivalent
	to calling the exit function with the value returned by the
	main function as its argument ... [Jan 11 '88 draft]

So, we can replace "exit(0)" with "return(0)".

>Also, for formality's sake and international propriety, we should add the
>normally-obligatory setlocale() call (actually not necessary--this may be
>the *only* program for which that's true--but it's hard to pass up poking
>fun at a requirement to set a default explicitly), and this in turn
>requires <locale.h>.  OK, so here's the penultimate version of IEFBR14.c,
>our properly ANSI and internationalized (unless I screwed up) program-to-
>do-nothing:
>
>	#include <stdlib.h>
>	#include <locale.h>
>
>	#ifndef	lint
>	static char *sccsid = "%W% - %E%";
>	#endif
>
>	/*ARGSUSED*/
>	main(argc,argv)
>	int	argc;
>	char	**argv;
>	{
>		setlocale(LC_ALL, "");
>		exit(0);
>	}

Not really.  Section 4.4.1.1 says:

	At program startup, the equivalent of "setlocale(LC_ALL, "C")"
	is executed.

This is the responsibility of the implementation, (e.g., done by crt0)
so there is a well-defined default locale.  Since this program produces no
locale-dependent output, there is no need to change the locale from the
default.

Furthermore, the declaration of main could be "int main(void)":

	#ifndef	lint
	static char *sccsid = "%W% - %E%";
	#endif

	int
	main(void)
	{
		return(0);
	}


That doesn't look quite so bad.  Unfortunately, it is not strictly
conforming, because the termination status is implementation defined.
This is because the committee could not agree that a return (or exit)
value of zero means "success"; there are systems on which this is not
true.  [I won't say more, they know where I live].  So, we have
to change "return(0)" to "return(EXIT_SUCCESS)", which, tragically,
requires "#include <stdlib.h>".  But this is not required if you
only want to run on Unix (and _probably_ POSIX-conforming systems).

>To create the final version, all you need is your local draconian
>corporate screenful of copyright notice and disclaimer.

You forgot the 40 pounds of paperwork to get it included in the
release ...

Tom Kelly  (416) 922-1937
SCO Canada, Inc. (formerly HCR) 130 Bloor St. W., Toronto, Ontario, Canada
{utzoo, utcsri, uunet}!scocan!tom or tom@sco.com

rbj@uunet.UU.NET (Root Boy Jim) (04/04/91)

In article <PPDuZ1w164w@dogface>  writes:
?rcd@ico.isc.com (Dick Dunn) writes:
?> [users] are occasionally annoyed to find that csh rejects this syntax
?> with the confusing message "Invalid null command".
?
?What about
?	cat /dev/null > splot
?to create an empty file?  Not as, umm, Rube Goldberg-ish as your program,
?though.

OVERKILL! There is a builtin command, `:' which works nicely,
and is even easy to type. To empty a file, type :>file
-- 
		[rbj@uunet 1] stty sane
		unknown mode: sane

hahn@nas.nasa.gov (Jonathan Hahn) (04/04/91)

In article <1991Apr2.235854.24295@Think.COM> barmar@think.com (Barry Margolin) writes:
>In article <1991Apr2.212348.8565@nas.nasa.gov> hahn@gigantor.nas.nasa.gov (Jonathan Hahn) writes:
>>	alias \> 'echo>'
>Actually, it should be
>
>	alias \> 'echo -n >'
>
>Otherwise you'll write a newline to splot, rather than just truncating it.
>--
>Barry Margolin, Thinking Machines Corp.

Well, no.  You're thinking of the Bourne shell echo.  We were talking about
emulating the Bourne shell ">" command in the C shell.  The echo in the
C shell doesn't behave as you describe.  (Or at least it doesn't in the
dozen or so csh implementations at this site.)

-jonathan hahn
--
hahn@gigantor.nas.nasa.gov				wk: (415) 604-4360
..!ames!amelia!hahn					hm: (408) 736-7014

diamond@jit345.swstokyo.dec.com (Norman Diamond) (04/04/91)

In article <1991Apr4.021327.10922@nas.nasa.gov> hahn@gigantor.nas.nasa.gov (Jonathan Hahn) writes:
>In article <1991Apr2.235854.24295@Think.COM> barmar@think.com (Barry Margolin) writes:
>>In article <1991Apr2.212348.8565@nas.nasa.gov> hahn@gigantor.nas.nasa.gov (Jonathan Hahn) writes:
>>>	alias \> 'echo>'
>>Actually, it should be
>>	alias \> 'echo -n >'
>>Otherwise you'll write a newline to splot, rather than just truncating it.
>Well, no.  You're thinking of the Bourne shell echo.  We were talking about
>emulating the Bourne shell ">" command in the C shell.  The echo in the
>C shell doesn't behave as you describe.

Mr. Hahn is right.  Mr. Margolin, it seems you did a "man csh", instead of
trying it out to see what it does.  If the developers of csh don't RTFM,
why should you?

Attention world, if you RTFM, you get what you deserve.  :-S (sarcasm)
--
Norman Diamond       diamond@tkov50.enet.dec.com
If this were the company's opinion, I wouldn't be allowed to post it.

suitti@ima.isc.com (Stephen Uitti) (04/05/91)

In article <1991Apr2.005620.11434@ico.isc.com> rcd@ico.isc.com (Dick Dunn) writes:
> ...description of history leading to IEFBR14.c:
>	#include <stdlib.h>
>	#include <locale.h>
>
>	#ifndef	lint
>	static char *sccsid = "%W% - %E%";
>	#endif
>
>	/*ARGSUSED*/
>	main(argc,argv)
>	int	argc;
>	char	**argv;
>	{
>		setlocale(LC_ALL, "");
>		exit(0);
>	}
>
>To create the final version, all you need is your local draconian
>corporate screenful of copyright notice and disclaimer.

I did this exercise some years back.  My version allowed links
"true" and "false", and would return the appropriate value.  It
required one disk block, and ran faster in many cases than the
shell version.  Running faster was a feature.  As I recall, I was
chastised, because it was not considered as portable.  Yet, it
compiles and runs on the Mac without modification.

Stephen.
suitti@ima.isc.com
"We Americans want peace, and it is now evident that we must be
prepared to demand it.  For other peoples have wanted peace, and
the peace they received was the peace of death." - the Most Rev.
Francis J. Spellman, Archbishop of New York.  22 September, 1940

tom@sco.COM (Tom Kelly) (04/07/91)

In a recent article, I suggested some changes to Dick Dunn's ANSI C version
of IEFBR14.  I originally suggested that exit(0) could be replaced
by return(0), and the setlocale() could be dropped, eliminating the need
for include files.  But then I said that return(0) was non portable;
it had to be EXIT_SUCCESS, which required an include file.

Apparently, Gordon Burditt (gordon@sneaky.lonestar.org) can read
better than I can, since he pointed out in mail that the section on exit()
in the C standard makes a special case for zero as successful
termination.  So:

int
main(void)
{
	return 0;
}

is all you need for IEFBR14.

As penance, I suppose I should read the standard again, but
I've already lost as much hair as I can afford.

Tom Kelly  (416) 922-1937
SCO Canada, Inc. (formerly HCR) 130 Bloor St. W., Toronto, Ontario, Canada
{utzoo, utcsri, uunet}!scocan!tom or tom@sco.com