[comp.sys.ibm.pc.programmer] MKS argv code

lfk@athena.mit.edu (Lee F Kolakowski) (07/09/90)

Here is what I use to get the arguments from the MKS shell. This is
for the MS-C compiler. I don't know about TC. It should work if TCs
startup puts all the environment into the startup variable *env[].

I have yet to figure out how to use the glob they supply.

This works under the shell and under DOS if the wild card expander in
linked in.


Frank Kolakowski 

======================================================================
|lfk@athena.mit.edu                     ||      Lee F. Kolakowski    |
|lfk@eastman2.mit.edu                   ||	M.I.T.		     |
|kolakowski@wccf.mit.edu                ||	Dept of Chemistry    |
|lfk@mbio.med.upenn.edu		        ||	Room 18-506	     |
|lfk@hx.lcs.mit.edu                     ||	77 Massachusetts Ave.|
|AT&T:  1-617-253-1866                  ||	Cambridge, MA 02139  |
|--------------------------------------------------------------------|
|                         #include <woes.h>         		     |
|		           One-Liner Here!                           |
======================================================================


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	readme
#	skeleton.c
#	etc.h
# This archive created: Sun Jul 08 19:24:38 1990
export PATH; PATH=/bin:$PATH
if test -f 'readme'
then
	echo shar: will not over-write existing file "'readme'"
else
cat << \SHAR_EOF > 'readme'
In this c file is the code I use to get the arguments from the MKS shell.
MKS puts all the arguments expanded in the environment. Each argument
is preceeded by a '~'. For eample:

$ set | grep "^~"
~jove
~readme

finally they put the full path of the executable in the environment as
follows

$ set | grep "^_"
_=c:/bin/jove.exe

So all you have to do is add to main()'s parameters

void main ( int argc, char *argv[], char *env[] ) 
                |          |             ^environment table
                |          ^argument list
                ^contains argument count

and then use the code provided here in your applications that run under
the MKS shell.

There is one small gotcha. If you start a process under the shell,
which spawns a process, the second process cannot get its arguments
from the environment because the shell do not put then there. SO, in
that case you have to use the args provided by your startup code. To
test for this just compare your startups argv[0] with the _=value. 

So here is a simple test program that I use as the skeleton for most of
my c code. If you compile it with -DMKS you can start it under the
shell like this:

$ skeleton /bin/* (112 entries)
Using shell supplied args
Process...../bin/asa.exe......done
[ lots deleted ]
Process...../bin/zcat.exe......done

Under normal DOS (command.com) or when you shell out of your editor:
!skeleton /bin/*
Using startup supplied args
Process...../bin/*......done 
tool: can't access '/bin/*' not a readable file 

Note I used /bin/* and '*' under dos expands to files with no
extension and there are none.

so you have to remember to use *.*
!skeleton /bin/*.*
Using startup supplied args
Process...../bin/ASA.EXE......done
[ lots deleted ]
Process...../bin/ZCAT.EXE......done

SHAR_EOF
fi # end of overwriting check
if test -f 'skeleton.c'
then
	echo shar: will not over-write existing file "'skeleton.c'"
else
cat << \SHAR_EOF > 'skeleton.c'
/* This is a skeleton file for the generation of arguments and the
 * parsing of command line options.
 *
 * If you want to be able to get the arguments pre-parsed from the
 * MKS shell, define MKS.
 *
 * Lee F. Kolakowski, Jr.
 * 20 Reyem Street
 * Waltham, MA 02154
 */
/* DEFINES */
#define MKS

/* INCLUDES */ 
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <etc.h>

/* ANSI Prototypes */
void process(char *filename);
void die(char *fmt,...);
void warn(char *fmt,...);

/* GLOBAL VARIABLES */
char	*progname = "tool";
char	*usage = "Usage: tool [-v] [-o fname] [-ln] [filenames...]";
int		lpp;
char	*ofname;
bool	verbose = FALSE;

/* Main */
int
main(int argc, char *argv[], char *env[])
{
	char	*opt;
    struct stat filestat;
#ifdef MKS
	int z = 0;
	int ARGC = 0;
    char **tmp;
	char *env_name;
#	define MAXARGS 500		/* This means 500 items on the command line */
	if (!(tmp = (char **)malloc(sizeof(char *)*(MAXARGS+1)))) {
		fprintf(stderr, "%s: can't allocate space for arguments\n",progname);
		exit(1);
	}
	for ( z = 0 ; env[z] != NULL; z++) {	/* loop through environment */
		if (*env[z] == '~') {	/* testing for entries begining with '~' */
			*++env[z];			/* increment pointer to delete '~' */
			tmp[ARGC++] = env[z];	/* add it to our new array */
			if (z >= MAXARGS) {
				fprintf(stderr, "%s: can't handle any more arguments\n", progname);
				goto list;
			}
		}
		else if (*env[z] == '_') {	/* testing for entries begining with _ */
			*++env[z] ; *++env[z];	/* move past the '_' and the '=' */
			env_name = env[z];	/* copy the name */
		}
	}
list:
	if ( STREQ( (char *) argv[0] , env_name ) ) {	/* test name against startup args */
		/* environment arguments meant for this program */
#	ifdef DEBUG
		printf("Using shell supplied args\n");
#	endif
		argc = ARGC;
	    tmp[ARGC] = NULL;    /* the terminal NULL */
		argv = tmp;
	}
#	ifdef DEBUG
	else 
		printf("Using startup supplied args\n");
#	endif /* debug */
#endif /* MKS */


/* Parse command line manually (faster than getopt) */
nextarg:
	while (--argc > 0 && *(opt = *++argv) == '-') {
		while (*++opt != '\0')
			switch (*opt) {
				case 'v' :	verbose++; break;
				case 'o' :	ofname = getarg(opt); goto nextarg;
				case 'l' :	lpp = atoi(getarg(opt)); goto nextarg;
				default  :	die("unknown option '%c'.  %s", *opt, usage);
							exit(FAILURE);

			}

		/*
		 * an arg of "-" starts list of files, usually interpreted as
		 * stdin 
		 */
		if (opt - *argv == 1)	/* believe it or not, this catches '-' */
			break;
	}


/* Do the Stuff of the program */
	do {
		/* test state of *argv */
		if( (!stat(*argv, &filestat)) && ((filestat.st_mode & S_IFMT) == S_IFDIR) )
			warn("can't process '%s' a directory\n", *argv);
		else if ( access(*argv, READ) != 0 ) {
			warn("can't access '%s' not a readable file\n", *argv);
		}
		else if (argc && freopen(*argv, "r", stdin) == NULL) {
			die("can't open '%s'\n", *argv);
		}

		if (ofname && freopen(ofname, "w", stdout) == NULL) {
			die("can't create %s\n", ofname);
		}
		process(*argv);
		printf("done\n");
	} while (++argv, --argc > 0);
	return (SUCCESS);	
}

void process(char *filename)
{
	printf("Process.....%s......", filename);
	return;
}

void die(char *fmt,...)
{
	va_list	ap;

	va_start(ap, fmt);
	fprintf(stderr, "%s: ", progname);
	vfprintf(stderr, fmt, ap);
	exit(FAILURE);
}

void warn(char *fmt,...)
{
	va_list	ap;

	va_start(ap, fmt);
	fprintf(stderr, "%s: ", progname);
	vfprintf(stderr, fmt, ap);
}

SHAR_EOF
fi # end of overwriting check
if test -f 'etc.h'
then
	echo shar: will not over-write existing file "'etc.h'"
else
cat << \SHAR_EOF > 'etc.h'
/*
 * etc.h
 * useful definitions
 */

#ifndef etc
#define etc

/* Common Types */

typedef short	fchar;				/* Either input char, or EOF, which is int */
typedef char	tbool;				/* Flag, tested only for zero || non-zero */
typedef unsigned short	bits;		/* Data type for doing bit operations */
typedef enum { NO , YES } bool;		/* Boolean, TRUE || FALSE */

/* Constants */
#define FALSE	NO
#define TRUE	YES
#define FAILURE	1	/* error exit code */
#define SUCCESS	0	/* successful exit, opposite of FAILURE */
enum FILEATTRIB { EXIST, WRITE = 2, READ = 4, READ_WRITE = 6 }; 

#ifndef SYSV_STRINGS
#	define SYSV_STRINGS
#	include <string.h>
#	define index	strchr
#	define rindex	strrchr
#else
/* what ever */
#endif

/* Macros */
/*
 * getarg() - return a pointer to a parameter for a command-line switch
 * "-sBLAH"  returns a pointer to "BLAH"
 * "-s BLAH" also returns a pointer to "BLAH"
 * "-s<no-more-args>" returns a pointer to an empty string
 */
#define getarg(p) (p[1] ? &p[1] : (argc>1 ? (--argc,*(++argv)) : ""))
#define STREQ(a,b)	( strcmp( (a), (b) ) == 0 )

#endif /* etc */
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0
--

Frank Kolakowski 

======================================================================
|lfk@athena.mit.edu                     ||      Lee F. Kolakowski    |
|lfk@eastman2.mit.edu                   ||	M.I.T.		     |
|kolakowski@wccf.mit.edu                ||	Dept of Chemistry    |
|lfk@mbio.med.upenn.edu		        ||	Room 18-506	     |
|lfk@hx.lcs.mit.edu                     ||	77 Massachusetts Ave.|
|AT&T:  1-617-253-1866                  ||	Cambridge, MA 02139  |
|--------------------------------------------------------------------|
|                         #include <woes.h>         		     |
|		           One-Liner Here!                           |
======================================================================