[comp.lang.c] Accessing argc & argv from a functi

ftw@datacube.UUCP (07/17/87)

mikel@flmis06.UUCP writes:
> /* ---------- "Accessing argc & argv from a functi" ---------- */
> I recently ran accross an interresting question.

> How does one get at argc and argv (and possibly envp) from a function?
> Without declaring it in main first, and then passing a pointer (global
> or not)! Assume you don't have control over what happens in main. Can
> you still get at the argument vector?
> -- 
> 				Mikel Manitius @ AT&T Network Operations
> 				mikel@codas.att.com.uucp | attmail!mikel

The environment pointer can either be passed through as the third argument
to main(), as you mention, or can be accessed (in a lot of implementations
but perhaps not all) by the following declaration:

extern char *environ;

in either the function where you need it, or globally.  This is usually how
the getenv() function is implemented.

Speaking of getenv(), if you want the definition of a single environment
variable, you can use this:

char *path;
   .
   .
   .
path = getenv("PATH");

which searches through the string pointed to by "environ" to find something
of the form "PATH=", and returns a pointer to the char following the "=".

This all makes a few assumptions about how your libraries (and OS) maintain
environment variables, but I have not seen many that didn't work this way.

As for argc and argv:  they are usually gathered by the runtime startup
code which will push them on the stack before the runtime startup calls
your main() function.  Note also the the runtime startup will push the
environment pointer before calling main().  There is usually no way to
get at "argv" and "argc" without declaring them as arguments to main().

One "cheap and dirty" thing you could do though is to get the value for
environ and walk back up the stack.  You would stop when you finish walking
over the program name.  This way, you could possibly re-build argc and
argv without passing them through main(). (Why do I hear LOTS of groaning
in the background?? ;-))  Of course, this is *VERY* non-portable and
assumes a great deal about the ordering of objects on the stack.

Hope this helps...


			Farrell

aglew@ccvaxa.UUCP (07/18/87)

/* Written 12:56 pm  Jul 16, 1987 by mikel@flmis06.ATT.COM in ccvaxa:comp.lang.c */
>/* ---------- "Accessing argc & argv from a functi" ---------- */
>I recently ran accross an interresting question.
>
>How does one get at argc and argv (and possibly envp) from a function?
>Without declaring it in main first, and then passing a pointer (global
>or not)! Assume you don't have control over what happens in main. Can
>you still get at the argument vector?
>-- 
>				Mikel Manitius @ AT&T Network Operations
>				mikel@codas.att.com.uucp | attmail!mikel
>/* End of text from ccvaxa:comp.lang.c */

In standard C you cannot get access to argv/argc/envp without doing work
in main().

At McGill I modified crt0 to put argc/argv/envp into globals Argc/Argv/Envp,
as well as passing them to main(). This was useful for a family of debug
and error routines, that told you what command was executing when they
died. der Mouse Parker took this up and may still have it.

I have always thought that perror(str) was silly - sometimes I want
str to be the command name, sometimes the command plus all arguments...

I would like to do the same thing where I now work...

henry@utzoo.UUCP (Henry Spencer) (07/19/87)

> Speaking of getenv(), if you want the definition of a single environment
> variable, you can use this:
> 
> char *path;
> /* ... */
> path = getenv("PATH");
> 
> which searches through the string pointed to by "environ" to find something
> of the form "PATH=", and returns a pointer to the char following the "=".

This is not quite right.  The correct form is:

char *path;
/* ... */
path = getenv("PATH");
if (path == NULL)
	[deal with the situation as appropriate]

This is not just me being pedantic; all too often such checks are omitted.
-- 
Support sustained spaceflight: fight |  Henry Spencer @ U of Toronto Zoology
the soi-disant "Planetary Society"!  | {allegra,ihnp4,decvax,utai}!utzoo!henry

peter@sugar.UUCP (Peter da Silva) (07/22/87)

In article <28700015@ccvaxa>, aglew@ccvaxa.UUCP writes:
> In standard C you cannot get access to argv/argc/envp without doing work
> in main().

getenv()? putenv()? execl()? execv()? execlp()? execvp()?
-- 
-- Peter da Silva `-_-' ...!seismo!soma!uhnix1!sugar!peter (I said, NO PHOTOS!)

mikel@flmis06.ATT.COM (Mikel Manitius) (07/28/87)

> In article <28700015@ccvaxa>, aglew@ccvaxa.UUCP writes:
>> In standard C you cannot get access to argv/argc/envp without doing work
>> in main().
> 
> getenv()? putenv()? execl()? execv()? execlp()? execvp()?
> -- 
> -- Peter da Silva

Well, I think we may have lost track of the initial problem.

Sure, all of the above access the enviorment in one way or another.

However I am still looking for a way to get at "argc" and "argv" from
a function when I don't have access to "main". getenv() and putenv()
gets it from somewhere...

As far as the rest of the above mentioned functions, you will need to
have the args (or at least create your own) first, before you can pass
them on...
-- 
				Mikel Manitius @ AT&T Network Operations
				mikel@codas.att.com.uucp | attmail!mikel

guy%gorodish@Sun.COM (Guy Harris) (07/28/87)

> >> In standard C you cannot get access to argv/argc/envp without doing work
> >> in main().
> > 
> > getenv()? putenv()? execl()? execv()? execlp()? execvp()?
> 
> Sure, all of the above access the enviorment in one way or another.
> 
> However I am still looking for a way to get at "argc" and "argv" from
> a function when I don't have access to "main". getenv() and putenv()
> gets it from somewhere...

No, "getenv" and "putenv" get at *envp*; they don't look at "argv" or "argc"
at all.  In UNIX C implementations, at least, there is a global
variable "environ", to which the value of "envp" is assigned by the C
startup code.

Note, however, that if we're truly talking about "standard" C, there
isn't even a guarantee that "argv", "argc", or "envp" even *exist*!
According to the current ANSI C draft, in a "freestanding
environment" (where the C program may be run "without any benefit of
an operating system"), "the name and type of the function called at
program startup are implementation-defined".

In a "hosted environment", the function in question is called "main";
I infer from the description that the function is guaranteed to be
called with two arguments, "argc" and "argv" (it says the function
can be defined with no parameters, or with the usual two parameters,
which I assume means either is valid in any hosted environment).  The
"envp" argument is listed only in Appendix A, under "Common
extensions".

> As far as the rest of the above mentioned functions, you will need to
> have the args (or at least create your own) first, before you can pass
> them on...

Arguments yes, environment no.  Those routines get the environment
from "environ".
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com

rwhite@nu3b2.UUCP (Robert C. White Jr.) (07/29/87)

In article <39@flmis06.ATT.COM>, mikel@flmis06.ATT.COM (Mikel Manitius) writes:
> Well, I think we may have lost track of the initial problem.
> 
> Sure, all of the above access the enviorment in one way or another.
> 
> However I am still looking for a way to get at "argc" and "argv" from
> a function when I don't have access to "main". getenv() and putenv()
> gets it from somewhere...

If you have access to the runtime stuff, you can kludge the runtime to put
the argv and argc in some global variable you can find.

The best solution is to have a module initalization routine [init of some
sort] which the user must call from main, which will extract the array
of pointers address, and store it in you own modules global space.

once you use setenv, the envp argument passed to main is no longer valid.

nomatter how you slice it the pointer to argv will HAVE to be passed
somewhare.

Robert.

njh@root.co.uk (Nigel Horne) (07/30/87)

In article <39@flmis06.ATT.COM> mikel@flmis06.ATT.COM (Mikel Manitius) writes:
>
>However I am still looking for a way to get at "argc" and "argv" from
>a function when I don't have access to "main". getenv() and putenv()
>gets it from somewhere...

getopt().

-Nigel
-- 
--
Nigel Horne, Divisional Director, Root Technical Systems.
<njh@root.co.uk>	G1ITH	Fax:	(01) 726 8158
Phone:	+44 1 606 7799 Telex:	885995 ROOT G	BT Gold: CQQ173

hunt@spar.SPAR.SLB.COM (Neil Hunt) (07/31/87)

In article <1130@nu3b2.UUCP> rwhite@nu3b2.UUCP (Robert C. White Jr.) writes:
>In article <39@flmis06.ATT.COM>, mikel@flmis06.ATT.COM (Mikel Manitius) writes:
>> However I am still looking for a way to get at "argc" and "argv" from
>> a function when I don't have access to "main". getenv() and putenv()
>> gets it from somewhere...
>
>If you have access to the runtime stuff, you can kludge the runtime to put
>the argv and argc in some global variable you can find.
>
>nomatter how you slice it the pointer to argv will HAVE to be passed
>somewhare.
>

Depends how portable you have to be !

        ************************************************************
        **********************   WARNING   *************************
        ************************************************************
        *                                                          *
        * The following comments and program examples could be     *
        * hazardous to your health and sanity.                     *
        *                                                          *
        * Please fasten your seatbelts and disable lint.           *
        *                                                          *
        ************************************************************

If you know something about the compiler and machine, you can access
the run time stack and access arguments of previous functions
as you will ! For example, I am using a SUN, with the SUN C compiler.
I know that the stack is organised as follows:

	-----------------------	Stack frame for func1
	paramN-1
	..
	param1
	param0
	return_address
	frame_pointer  <-+
	local_var0       |
	local_var1       |
	...              |
	local_varN-1     |
	-----------------+-----	Stack frame for func2 called from func1
	paramN-1         |
	..               |
	param1           |
	param0           |
	return_address   |
	frame_pointer *--+	/* points to previous frame pointer. */
	local_var_0
	local_var_1
	...
	local_var_N-1
	-----------------------

	etc.

Now from a function called from main, take the address of the first
parameter (param0 in func2), subtract 2 * sizeof(pointer) = 8 bytes
from this address, and you have a current frame pointer.
Indirect the frame pointer, and you have the frame pointer of the
function which called you, in this case, main. Knowing that the parameters
are passed at addresses 2,3,.. above the frame pointer, you can
now obtain the parameters to the previous function.

The following program demonstrates:

-------------------------------------------------------------------------
main(argc, argv, envp)
int argc;
char **argv;
char **envp;
{
	/*
	 * Print the args values for reference.
	 */
	printf("%x %x %x\n", argc, argv, envp);

	/*
	 * Call a function.
	 */
	test(0);
}

test(arg)
int arg;
{
	char *frame_pointer;
	char *prev_frame_pointer;
	int argc;
	char **argv;
	char **envp;

	/*
	 * Obtain a frame pointer,
	 * indirect to previous frame (called from main)
	 * Obtain main's parameters from mains frame pointer.
	 */
	frame_pointer = ((char *)&arg) - 8;
	prev_frame_pointer = *((char **)frame_pointer);
	argc = (*(int *)(prev_frame_pointer+8));
	argv = (*(char ***)(prev_frame_pointer+12));
	envp = (*(char ***)(prev_frame_pointer+16));

	/*
	 * Print main's args for reference.
	 */
	printf("%x %x %x\n", argc, argv, envp);
}
-------------------------------------------------------------------------
% test
1 efffba0 efffba8
1 efffba0 efffba8

% test this is a test with real args
8 efffb64 efffb88
8 efffb64 efffb88

How about that !!

If your function which needs to access the args to main is buried deeper
than one call, you will have to indirect frame_pointer more times.
If you do not know how many times, you can find out by looking at the
return addresses to see which frame belongs to a function which
will return to an address within the range of _main and the next function.
The example below demonstrates:

-------------------------------------------------------------------------
main(argc, argv, envp)
int argc;
char **argv;
char **envp;
{
	/*
	 * Print args for reference.
	 */
	printf("%x %x %x\n", argc, argv, envp);

	test();
}

test()
{
	/*
	 * Print range of return addresses to main.
	 */
	printf("  Address %x <= main < %x\n", main, test);

	/*
	 * Call deeper on the stack.
	 * Can place arbitrary recursion here !
	 */
	test_deeper(0);
}

test_deeper(arg)
int arg;
{
	char *frame_pointer;
	char *prev_frame_pointer;
	char *return_address;
	int argc;
	char **argv;
	char **envp;

	/*
	 * Get the current frame pointer.
	 */
	frame_pointer = ((char *)&arg) - 8;

	for( ; ; )
	{
		/*
		 * Check return address of this frame,
		 * see if it is within range of main,
		 */
		return_address = *((char **)(frame_pointer + 4));
		printf("  Return address = %x\n", return_address);
		if(return_address < (char *)main)
			exit(-1);
		if(return_address < (char *)test)
			break;

		/*
		 * Go up another frame in the call stack.
		 */
		frame_pointer = *((char **)frame_pointer);
		printf("  Going back up one more level at %x\n",
		  frame_pointer);
	}

	/*
	 * Obtain main's frame pointer and args.
	 */
	prev_frame_pointer = *((char **)frame_pointer);

	argc = (*(int *)(prev_frame_pointer+8));
	argv = (*(char ***)(prev_frame_pointer+12));
	envp = (*(char ***)(prev_frame_pointer+16));

	printf("%x %x %x\n", argc, argv, envp);
}
-------------------------------------------------------------------------

% test
1 efffba0 efffba8
  Address 20a0 <= main < 20d4
  Return address = 2104
  Going back up one more level at efffb80
  Return address = 20d0
1 efffba0 efffba8

% test this is another test
5 efffb7c efffb94
  Address 20a0 <= main < 20d4
  Return address = 2104
  Going back up one more level at efffb5c
  Return address = 20d0
5 efffb7c efffb94

One final thing to note: if the original main function changes the values
of argc, argv or envp (as in argv++ for example) then you will get the
changed value of those variables, just as if you were still in the main
program.

Don't you love what you can do in C ?

Neil/.

PS:	% lint test.c
	test.c(51): warning: questionable conversion of function pointer
	test.c(53): warning: questionable conversion of function pointer
	printf returns value which is always ignored

	Wow ! I expected at least a core dump from lint.

jv@mhres.mh.nl (Johan Vromans) (07/31/87)

In article <382@root44.co.uk>, njh@root.co.uk (Nigel Horne) writes:
> In article <39@flmis06.ATT.COM> mikel@flmis06.ATT.COM (Mikel Manitius) writes:
> >
> >However I am still looking for a way to get at "argc" and "argv" from
> >a function when I don't have access to "main". getenv() and putenv()
> >gets it from somewhere...
> 
> getopt().
> 

You loose:

	getopt (argc, argv, optstring)
	int argc; char *argv[]; char *optstring;

See: SVID.



-- 
Johan Vromans                           | jv@mh.nl via mcvax and seismo
Multihouse N.V., Gouda, the Netherlands | uucp: ..{seismo!}mcvax!mh.nl!jv
"It is better to light a candle than to curse the darkness"

jfh@killer.UUCP (The Beach Bum) (08/01/87)

In article <39@flmis06.ATT.COM>, mikel@flmis06.ATT.COM (Mikel Manitius) writes:
> > In article <28700015@ccvaxa>, aglew@ccvaxa.UUCP writes:
> >> In standard C you cannot get access to argv/argc/envp without doing work
> >> in main().
> 
> Well, I think we may have lost track of the initial problem.
> 
> However I am still looking for a way to get at "argc" and "argv" from
> a function when I don't have access to "main". getenv() and putenv()
> gets it from somewhere...
> 
> As far as the rest of the above mentioned functions, you will need to
> have the args (or at least create your own) first, before you can pass
> them on...
if one looks at the code for /lib/crt0.o (and friends on unix, god
only knows what on Messy-DOS :-) you will see that the run-time start
up code saves the address of the environment there.  why not just add
a few lines to do the dirty work there?  (the answer is of course,
how many of us have the source to /lib/crt0.o :-(.

ms-dos is one up here.  my understanding is that most C compilers for
ms-dos include the source to the startup routine, which happens to
be written in C for the machines i've seen.  has anyone written a
public domain C startup that also is written in C and only needs
alittle munging on?

(you are not going to hear me utter the word `disassemble' at any
time in this discussions ...)

- john
-- 
John F. Haugh II		HECI Exploration Co. Inc.
UUCP:	...!ihnp4!killer!jfh	11910 Greenville Ave, Suite 600
"Don't Have an Oil Well?"	Dallas, TX. 75243
" ... Then Buy One!"		(214) 231-0993

gwyn@brl-smoke.ARPA (Doug Gwyn ) (08/02/87)

In article <1260@killer.UUCP> jfh@killer.UUCP (The Beach Bum) writes:
>has anyone written a public domain C startup that also is written in C ...

That is not in general possible.  The C startup routines that
I maintain are all inherently different, and furthermore they
cannot be written in C.

Why do people think they need this?  I've never felt the need for it.

aglew@ccvaxa.UUCP (08/04/87)

>The solution is to get the source for main() and modify it, or do something
>that doesn't involve the arguments, e.g. pass the information you are
>looking for in the environment, in a file, etc.  You never did get around
>to explaining what it is you *really* want to do, or why you are modifying
>subroutines' sources but don't have source to main().

I don't know what the original writer was trying to do, but I've often
wanted to get argv from deep down inside a program, without modifying
main, etc.

I write a lot of library routines. Some of them find it necessary to
print error messages, or even abort the program. I think that, it in
environment where there may be a lot of processes running about, it is
nice to know what command died, and even its arguments. I don't like
having to tell the users of my routines to arrange to put these somewhere.

So, for example, I like to be able to simply plug

	if( jhgjhgjh )
		errorf("my library has a problem\n")

and, optionally, get a message like

     	comand arg1 arg2 arg3
		my library has a problem

from it.

Since my home system has shared libraries, I occasionally like plugging things
like this into libc, replacing a standard function, without bothering to
go and modify main.

A special application: I use shared libraries to collect stats on a running
system. I like knowing which commands with what arguments are the most
extreme cases - eg. who processes the longest string.

mouse@mcgill-vision.UUCP (der Mouse) (08/05/87)

In article <28700015@ccvaxa>, aglew@ccvaxa.UUCP quotes:
>> How does one get at argc and argv from a function?
and writes:
> At McGill I modified crt0 to put argc/argv/envp into globals
> Argc/Argv/Envp, as well as passing them to main().  [...].  der Mouse
> Parker took this up and may still have it.

Well, I took up the concept; I didn't see enough of Krazy Glew's code
to steal, and I picked different names for the globals [of course :-(],
argcnt and argvec (I figured "environ" was good enough for envp).

> I have always thought that perror(str) was silly - sometimes I want
> str to be the command name, sometimes the command plus all
> arguments...

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
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].

					der Mouse

				(mouse@mcgill-vision.uucp)

hunt@spar.SPAR.SLB.COM (Neil Hunt) (08/06/87)

I have thought of another (rather silly) way to obtain the
arguments to a program without having access to main:  :-)

Set up a command which uses ps to obtain the long listing of
all processes, egrep the line containing the current PID obtained
from getpid, pipe it through the stream editor using a script
to throw away the useless parts of the ps listing, leaving just the
args, and stick the whole lot into a file:

	sprintf(str, "ps -uwww | egrep %d | sed -f com > /tmp/args", getpid());

Execute the command pipe using system:

	system(str);

Now open and read the file, and obtain the original args (which will not
change even if your program screws up its stack and scribbles over everything).

This method while slow, might be interesting for printing a fatal error message
with some attribution.

Neil/.

gwyn@brl-smoke.ARPA (Doug Gwyn ) (08/13/87)

In article <853@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes:
>Wish perror() were printflike, ...

The new strerror() function will hand you a string to use as you wish.
Currently, people index into sys_errlist[], but strerror() improves
the packaging.

alastair@geovision.UUCP (Alastair Mayer) (08/14/87)

In article <274@spar.SPAR.SLB.COM> hunt@spar.UUCP (Neil Hunt) writes:
>I have thought of another (rather silly) way to obtain the
>arguments to a program without having access to main:  :-)
>
> [.. do a ps and grep out the PID.. ]
>args, and stick the whole lot into a file:
>
>	sprintf(str, "ps -uwww | egrep %d | sed -f com > /tmp/args", getpid());
>
>Execute the command pipe using system:
>
>	system(str);
>
>Now open and read the file, and obtain the original args (which will not
>change even if your program screws up its stack and scribbles over everything).

This is similar to a method I suggested to a co-worker who needed
to do the same thing.  The refinement you missed avoids the use of a
temporary file and the need to open that file.   Just use popen(3), which
is analgous to fopen(3) except that a command is given instead of the
filename.  E.g:
	your example:  sprintf(str, ..etc..)
                   system(str);
				   /* following implied by your msg */
                   fp = fopen("/tmp/args","r");
                   fscanf(fp, ..etc..);
                   fclose(fp);

    using popen:   sprintf(str, ..etc..)
                   fp = popen(str,"r");  /* combines system and fopen, sort of*/
                   fscanf(fp, ..etc..);
                   pclose(fp);

This implies Unix (or some other implementation that supports popen(3))
but so does your version.   And of course, that [fp]open succeeded
should be checked before attempting the fscanf in real code.
-- 
 Alastair JW Mayer     BIX: al
                      UUCP: ...!utzoo!dciem!nrcaer!cognos!geovision!alastair

Let's build a base on the Moon on our way to the asteroids - forget Mars.

root@hobbes.UUCP (John Plocher) (08/21/87)

+---- der Mouse writes the following in article <853@mcgill-vision.UUCP> ----
| aglew@ccvaxa.UUCP quotes:
| >> How does one get at argc and argv from a function?
| and writes:
| > At McGill I modified crt0 to put argc/argv/envp into globals
| Well, I took up the concept
+----

Acchh - Pffft!

int argc;
char **argv;

main(ac,av)
{
    argc = ac;
    argv = av;

    ...
}

foo() { if (argc != 2) usage(); }

Why hardcode crt0?  What does that buy you over this?  At least this
is portable, doccumented (no black magic done by the startup routine)...
-- 
John Plocher uwvax!geowhiz!uwspan!plocher  plocher%uwspan.UUCP@uwvax.CS.WISC.EDU

mouse@mcgill-vision.UUCP (09/07/87)

[various people, >> = me]
>>>> How does one get at argc and argv from a function?
>>> At McGill I modified crt0 to put argc/argv/envp into globals
>> Well, I took up the concept

[root@hobbes.UUCP (John Plocher) in <185@hobbes.UUCP>]
> Acchh - Pffft!

> int argc; char **argv;
> main(ac,av) { argc = ac; argv = av; .... }
> foo() { if (argc != 2) usage(); }

> Why hardcode crt0?  What does that buy you over this?

It buys you the capability of writing a routine which accesses the
arguments without needing support from main().  Try explaining to your
beginning C programmer why his error messages get turned into
segmentation violation coredumps because he didn't put a couple of
magic assignments at the beginning of main()....ie, library routine
packages can access the argument vector and wrap it all up and hide it.

					der Mouse

				(mouse@mcgill-vision.uucp)

root@hobbes.UUCP (John Plocher) (09/19/87)

+---- der Mouse writes in <884@mcgill-vision.UUCP> ----
| [root@hobbes.UUCP (John Plocher) in <185@hobbes.UUCP>]    ( me :-)
| > int argc; char **argv;
| > main(ac,av) { argc = ac; argv = av; .... }
| > foo() { if (argc != 2) usage(); }
| 
| > Why hardcode crt0?  What does that buy you over this?
| 
| It buys you the capability of writing a routine which accesses the
| arguments without needing support from main().  Try explaining to your
| beginning C programmer ...
+----

Why not do something like I have done:
	In the public readable file /etc/default/c there exists a
    boilerplate C program which has the appropriate RCS header info,
    #include <stdio.h>, getopt(), and argc/v/envp decls already there.
    Needless to say, it is heavily commented.
	The default .exrc for people has a macro which is attached to
    the ',' key which reads this file and then unmaps the ',' key...

    (there are also files for f77, make, header files, pascal...)

and then let people know about their avaliability WHEN TEACHING the
language!  "To get you started programming C there is a sample C program
avaliable which you should use to get started.  Don't worry right now if
you don't understand everything in the file, we will be covering all of the
stuff in this course..."

If they already know about argc/v then they SHOULD understand where they
come from!  If they don't know about it, why are they using the feature? 
I mean, if I tried to use Sys5's shared memory without knowing what I was
doing I would run into problems too!  Sometimes it is all right to learn
from experience :-)

Isn't the question really one of proper training?  That is, where does one
put the effort, education (argc/v) or handholding (library access).  There
are tradeoffs, but the first way is "portable" to other implementations of C
while the second one is very site specific.

If one wanted to make the arguments avaliable w/o going thru main() then I
agree that you could just make crt0 put them into static locations, BUT would
anyone use that feature?  Would you?  No, you (and I) know about argc/v and
how to use them.  The beginning C pgmr would soon learn the "right" way also,
and use *it*.

-- 
John Plocher uwvax!geowhiz!uwspan!plocher  plocher%uwspan.UUCP@uwvax.CS.WISC.EDU