[mod.sources] v07i011: Getopt program for scripts

sources-request@mirror.UUCP (08/28/86)

Submitted by: Rich $alz (mirror!rs)
Mod.sources: Volume 7, Issue 11
Archive-name: getoptprog

#!/bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# Wrapped by mirror!rs on Thu Aug 28 12:55:41 EDT 1986

# Exit status; set to 1 on "wc" errors or if would overwrite.
STATUS=0
# Contents:  README Makefile getopt.1 getopt.c
 
echo x - README
if test -f README ; then
    echo README exists, putting output in $$README
    OUT=$$README
    STATUS=1
else
    OUT=README
fi
sed 's/^XX//' > $OUT <<'@//E*O*F README//'
XXThis quick throw-off is a public-domain implementation of the USG
XXgetopt program.  Not to be confused with the library routine, this
XXprogram helps scripts parse their options/flags/arguments.

XXAfter unpacking, tweak the Makefile as appropriate and run make.  Copy
XXthe examples from the manpage into separate files as verify that they
XXwork ok.  Do a "make install".  For your final examination, convert
XXlint to use this program.  I write more Makefiles for mod.sources
XXsubmissions than I care to, and sometimes I get tired of it; I
XXapologize for the terseness of the one here.

XXIf you don't have getopt(3) in your C run-time library, snip it off
XXthe tail of the source file, and add it, or make it easily, publicly,
XXavailable in some other way.
XX	/Rich $alz
@//E*O*F README//
chmod u=rw,g=rw,o=rw $OUT
 
echo x - Makefile
if test -f Makefile ; then
    echo Makefile exists, putting output in $$Makefile
    OUT=$$Makefile
    STATUS=1
else
    OUT=Makefile
fi
sed 's/^XX//' > $OUT <<'@//E*O*F Makefile//'
XX# Pick one
XXCFLAGS	= -O -DINDEX=index
XX#CFLAGS	= -O -DINDEX=strchr
XX# Pick one
XXM	= /usr/man/man1/getopt.1
XX#M	= /usr/man/u_man/man1/getopt.1#  Is this path right?
XX# Where executable ends up; don't forget the trailing /
XXD	= /bin/

XXgetopt:		getopt.c
XX	$(CC) $(CFLAGS) -o getopt getopt.c
XXinstall:	getopt
XX	cp getopt $Dgetopt
XX	strip $Dgetopt
XX	cp getopt.1 $M
@//E*O*F Makefile//
chmod u=rw,g=rw,o=rw $OUT
 
echo x - getopt.1
if test -f getopt.1 ; then
    echo getopt.1 exists, putting output in $$getopt.1
    OUT=$$getopt.1
    STATUS=1
else
    OUT=getopt.1
fi
sed 's/^XX//' > $OUT <<'@//E*O*F getopt.1//'
XX.TH GETOPT 1 LOCAL
XX.SH NAME
XXgetopt \- format flags for shell scripts
XX.SH SYNOPSIS
XX.B getopt
XXflag_spec argument ...
XX.SH DESCRIPTION
XX.I Getopt
XXis a program intended to be called by scripts to ``canonicalize'' their
XXarguments before processing them, just as the
XX.IR getopt (3)
XXroutine does for C programs.
XX(This need for scripts is usually most noticeable in the way
XX.IR lint (1)
XXhandles the
XX.B \-n
XXflag.)
XX.PP
XXThe following two examples provide the initial parsing for a script
XXwhich takes two flags,
XX.B \-a
XXand
XX.BR \-b ,
XXthe second of which takes an argument.
XX.RS
XX.ta +4n +4n +4n +4n
XX.nf
XX# For /bin/csh...
XXset argv = (`getopt "ab:" $*`)
XXif ( $status ) then
XX	echo "Read the documentation and try again." >/dev/tty
XX	exit 1
XXendif
XXset Aflag=0
XXset Name=NONE
XXwhile "$1" != "--"
XX	switch ("$1")
XX		case '-a':
XX			set Aflag=1
XX			breaksw
XX		case '-b':
XX			shift
XX			set Name=$1
XX			breaksw
XX	endsw
XX	shift
XXend
XXshift
XXecho Aflag=$Aflag / Name=$Name / Remaining args are $*

XX# For /bin/sh...
XXset -- `getopt "d:s" $@`
XXif test $? != 0 ; then
XX	echo "Read the documentation and try again."
XX	exit 1
XXfi
XXAflag=0
XXName=NONE
XXfor f
XXdo
XX	case "$f" in
XX		-a)	Aflag=1
XX			;;
XX		-b)	shift
XX			Name=$2
XX			;;
XX		--)	break
XX			;;
XX	esac
XX	shift
XXdone
XXshift
XXecho Aflag=$Aflag / Name=$Name / Remaining args are $*
XX.fi
XX.RE
XX.SH DIAGNOSTICS
XXThe program burps the standard
XX.IR getopt (3)
XXdiagnostics to standard error, and exits with a non-zero status if an
XXerror occurs.
XXIt is arguable wrong that the diagnostics imply that the program
XXis named ``getopt'' rather than the real name of the script.
XXIt is undeniably AT&T\-compatible to do this, however.
XX.SH "SEE ALSO"
XXcsh(1), sh(1), getopt(3)
XX.SH AUTHOR
XX.nf
XXRich $alz
XXMirror Systems
XX(mirror!rs, rs@mirror.TMC.COM)
@//E*O*F getopt.1//
chmod u=rw,g=rw,o=rw $OUT
 
echo x - getopt.c
if test -f getopt.c ; then
    echo getopt.c exists, putting output in $$getopt.c
    OUT=$$getopt.c
    STATUS=1
else
    OUT=getopt.c
fi
sed 's/^XX//' > $OUT <<'@//E*O*F getopt.c//'
XX/*
XX**  GETOPT PROGRAM AND LIBRARY ROUTINE
XX**
XX**  I wrote main() and AT&T wrote getopt() and we both put our efforts into
XX**  the public domain via mod.sources.
XX**	Rich $alz
XX**	Mirror Systems
XX**	(mirror!rs, rs@mirror.TMC.COM)
XX**	August 10, 1986
XX*/

XX#include <stdio.h>


XX#ifndef INDEX
XX#define INDEX index
XX#endif


XXextern char	*INDEX();
XXextern int	 optind;
XXextern char	*optarg;


XXmain(ac, av)
XX    register int	 ac;
XX    register char 	*av[];
XX{
XX    register char 	*flags;
XX    register int	 c;

XX    /* Check usage. */
XX    if (ac < 2) {
XX	fprintf(stderr, "usage: %s flag-specification arg-list\n", av[0]);
XX	exit(2);
XX    }

XX    /* Play games; remember the flags (first argument), then splice
XX       them out so it looks like a "standard" command vector. */
XX    flags = av[1];
XX    av[1] = av[0];
XX    av++;
XX    ac--;

XX    /* Print flags. */
XX    while ((c = getopt(ac, av, flags)) != EOF) {
XX	if (c == '?')
XX	    exit(1);
XX	/* We assume that shells collapse multiple spaces in `` expansion. */
XX	printf("-%c %s ", c, INDEX(flags, c)[1] == ':' ? optarg : "");
XX    }

XX    /* End of flags; print rest of options. */
XX    printf("-- ");
XX    for (av += optind; *av; av++)
XX	printf("%s ", *av);
XX    exit(0);
XX}
XX
XX/*
XX**  This is the public-domain AT&T getopt(3) code.  I added the
XX**  #ifndef stuff because I include <stdio.h> for the program;
XX**  getopt, per se, doesn't need it.  I also added the INDEX/index
XX**  hack (the original used strchr, of course).  And, note that
XX**  technically the casts in the write(2) calls shouldn't be there.
XX*/

XX#ifndef NULL
XX#define NULL	0
XX#endif
XX#ifndef EOF
XX#define EOF	(-1)
XX#endif
XX#ifndef INDEX
XX#define INDEX index
XX#endif


XX#define ERR(s, c)	if(opterr){\
XX	extern int strlen(), write();\
XX	char errbuf[2];\
XX	errbuf[0] = c; errbuf[1] = '\n';\
XX	(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
XX	(void) write(2, s, (unsigned)strlen(s));\
XX	(void) write(2, errbuf, 2);}

XXextern int strcmp();
XXextern char *INDEX();

XXint	opterr = 1;
XXint	optind = 1;
XXint	optopt;
XXchar	*optarg;

XXint
XXgetopt(argc, argv, opts)
XXint	argc;
XXchar	**argv, *opts;
XX{
XX	static int sp = 1;
XX	register int c;
XX	register char *cp;

XX	if(sp == 1)
XX		if(optind >= argc ||
XX		   argv[optind][0] != '-' || argv[optind][1] == '\0')
XX			return(EOF);
XX		else if(strcmp(argv[optind], "--") == NULL) {
XX			optind++;
XX			return(EOF);
XX		}
XX	optopt = c = argv[optind][sp];
XX	if(c == ':' || (cp=INDEX(opts, c)) == NULL) {
XX		ERR(": illegal option -- ", c);
XX		if(argv[optind][++sp] == '\0') {
XX			optind++;
XX			sp = 1;
XX		}
XX		return('?');
XX	}
XX	if(*++cp == ':') {
XX		if(argv[optind][sp+1] != '\0')
XX			optarg = &argv[optind++][sp+1];
XX		else if(++optind >= argc) {
XX			ERR(": option requires an argument -- ", c);
XX			sp = 1;
XX			return('?');
XX		} else
XX			optarg = argv[optind++];
XX		sp = 1;
XX	} else {
XX		if(argv[optind][++sp] == '\0') {
XX			sp = 1;
XX			optind++;
XX		}
XX		optarg = NULL;
XX	}
XX	return(c);
XX}
@//E*O*F getopt.c//
chmod u=rw,g=rw,o=rw $OUT
 
echo Inspecting for damage in transit...
temp=/tmp/sharin$$; dtemp=/tmp/sharout$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
      15     127     756 README
      15      54     348 Makefile
      90     292    1707 getopt.1
     139     436    2832 getopt.c
     259     909    5643 total
!!!
wc  README Makefile getopt.1 getopt.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if test -s $dtemp ; then
    echo "Ouch [diff of wc output]:"
    cat $dtemp
    STATUS=1
elif test $STATUS = 0 ; then
    echo "No problems found."
else
    echo "WARNING -- PROBLEMS WERE FOUND..."
fi
exit $STATUS