[mod.computers.masscomp] top for the masscomp part 2 of 3

sob@soma.UUCP (Stan Barber) (09/30/86)

#! /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:
#	README
#	Changes
#	top.man
#	sigconv.awk
#	Makefile
#	getopt.c
# This archive created: Mon Sep 29 16:14:15 1986
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'README'" '(5259 characters)'
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
This file contains a few comments about "top", version 2.0

"top" is a program that will give continual reports about the state of the
system, including a list of the top cpu using processes.  It requires read
access to the memory files "/dev/kmem" and "/dev/mem" as well as the system
image "/vmunix".  Some installations have these files protected from general
access.  These sites would have to install this program in the same way that
programs such as "ps" are installed.

CAVEAT:  version 2.0 of top has internal commands that kill and renice
processes.  DO NOT INSTALL TOP AS A SETUID PROGRAM, or you will open up a
big security hole since top makes no process ownership checks on its own.
Note that it is still safe to install top as a set group-id program, since
group-id has no bearing on who can renice or send signals to what processes.

There are a few things that need to be checked before compiling the program:

The most important item is the internal hash table size.  This size is
defined in the program with the preprocessor variable "Table_size".  This
constant MUST be larger than the number of lines in the file /etc/passwd.
It is advisable that this number be about twice the number of lines, and
that it be a prime number (since it dictates the size of the hash table).
Make sure this is checked before compilation.  Its definition exists in
the file "top.local.h", but it is also settable in the Makefile.

Several other things are set in "top.local.h", including the file names
used for certain system files ("/vmunix", "/dev/kmem", etc.).  Although I
don't expect those to vary much, they are put there for convenience.
Another parameter in this file is "Nominal_TOPN".  This will be discussed
in the next paragraph.

There are two preprocessor variables that are defined at compile time by
the makefile.  These are "Default_TOPN" and "Default_DELAY".  Their values
are the defaults used for the top number of processes to be displayed and
the number of seconds to delay between displays, respectively.  They are
set by the Makefile variables "TOPN" and "DELAY", respectively.  These
constants are preset as follows:  TOPN=10, DELAY=5.  These can be
overridden by either changing the Makefile or by specifying the change on
the make command line (with something like "make TOPN=15").  Version 2 of
top understands an "infinite" value for the number of processes to
display.  Such a value indicates that top should display as much as will
fill the screen.  To specify a Default_TOPN of infinity, set TOPN equal
to -1.  Version 2 also understands the difference between an intelligent
terminal and a dumb terminal (such as a hardcopy device or a file).
Typically, a default of infinity would not be desirable on a dumb
terminal, so the value of "Nominal_TOPN" is used when (1) Default_TOPN is
infinity and (2) the output device is a dumb terminal or a file.  The
value for this preprocessor variable is set in "top.local.h" and can also
be set from the "make" command line.  In the distribution, it is set to 18.

By default, the makefile will make a "top" for one of the following
systems:  Berkeley 4.2, Sun Unix (version 1.1 and higher), and Pyramid
Unix.  Previous versions of top fully supported Berkeley 4.1 Unix.  This
support has waned in version 2, and is not guaranteed to even work.  If
you really must give it a try, you can change the makefile variable
"CFLAGS" to make a 4.1 "top".  Instructions for doing this can be found in
"Makefile".

The file "bzero.c" contains a function that will zero a block of memory on
a VAX.  This is only needed for Berkeley 4.1, since 4.2 has a bzero
defined in the C run time library.  If you are strange enough to be
running 4.1 on something besides a VAX, you will have to replace this
routine with one that will work on your machine.  If you don't know a
quick way to do it, then writing a simple loop will suffice.  "Bzero"
takes two arguments:  a pointer to the buffer to zero, and the number of
bytes to zero.

There are also several parameters in the makefile that control
installation.  These should be altered to suit the desires and needs of
individual sites.

Version 2.0 still only supports standard 4.2 and Sun and Pyramid
architectures.  I attempted to add sufficient changes to make top work on
a Masscomp, but found the number of required changes to be overwhelming.
Feel free to alter top to make it run on whatever funny architecture you
have.  I also encourage you to send those changes back to me at the
address below.  But, if the number of changes is high, I will be reluctant
to include the changes in the next version of top.  As an example, there
were only 10 modifications required for the Sun version (and all changes
were trivial), and just 4 changes were needed for the Pyramid.

If you make any kind of change to "top" that you feel would be beneficial
to others who use this program, or if you find and fix a bug, please send
me the change.

Enjoy!

                                William LeFebvre
				Department of Computer Science
				Rice University
                                ARPANet address: <phil@Rice.edu>

				U.S. Mail address:
				    William LeFebvre
				    P.O. Box 1892
				    Department of Computer Science
				    Houston, TX  77251
SHAR_EOF
fi
echo shar: "extracting 'Changes'" '(6805 characters)'
if test -f 'Changes'
then
	echo shar: "will not over-write existing file 'Changes'"
else
cat << \SHAR_EOF > 'Changes'
Thu Sep  4 1986 - wnl (2.0, at last)
	This is the version that will (hopefully) get released to the
	world as top 2.0.
	Added the "r" and "k" commands for renice and kill, respectively.
	This required adding a way to handle system call errors, and the
	addition of the "e" command.  Help screen and manual page were
	changed to reflect this change.  Changed all "#ifdef SUN" directives
	to "#ifdef sun", and changed all "#ifdef PYRAMID" directives to
	"#ifdef pyr".  As much as I hate those choices of preprocessor
	names (they too easily conflict with real variable names), it does
	make automatic compilation possible---people don't have to change
	the Makefile anymore for specific machines.  The manual page was
	changed to automatically incorporate the defaults as set in the
	Makefile (including an infinite value for TOPN) and the way the
	manual page is generated by the Makefile was changed to make
	maintenance of this information automatic.

Mon Jul 28 1986 - wnl (still pre 2.0)
	Real close now.  I put in a new definition for the macro "pagetok"
	that does an explicit shift of a constant expression involving
	PGSHIFT.  Appropriate checks are made if PGSHIFT is to small.
	"pagetok" is now used exclusively everywhere to convert kernel
	clicks to kilobytes.  I added a full blown interactive mode with
	the ability to change some of the runtime parameters (how many to
	display, time delay, etc.) while top is running.  I also
	incorporated a few ideas from the net:  control characters in the
	command name are replaced with '?'; the '-S' option makes the
	swapper and pager visible; options have been added to control the
	number of displays produced (this makes it easier to make
	performance snapshots with top).  I have also added the notion of
	"infinite" values for number of processes and number of displays.
	I fixed a long-standing bug in the uid to username mapping code
	that was only aggravated on the pyramids:  it was an ill-defined
	expression (akin to i = i++).  I tweaked the proc_compar routine
	for qsort slightly so that stopped processes were more likely to
	show up.  Manual page was updated to reflect all changes
	noticeable to the user.

Tue Jul  1 1986 - wnl (pre 2.0 -- 1.9999?)
	In the process of major revamping on the way to version 2.0.
	I have completely done away with curses by adding my own screen
	management routines in a separate file (screen.c).  The rationale
	for this is that top knows a whole lot more about what is and is
	not redundant on the screen and can compare simple integer values
	where curses would have to compare strings.  This has turned out
	to be a very big win speed-wise.  The proc_compar routine for
	sorting has been rewritten to include several more keys.  I
	decided this was necessary when I noticed that the "top" process
	itself kept disappearing off the top 10 list on a Sun-3.  All the
	processes had the same percentage (0%) and the sort wasn't really
	doing anything worthwhile.  I changed the expression that computes
	memory usage to use the ctob macro instead of just assuming that
	pages were 512 bytes.  More work still needs to be done before
	this version is usable.  I changed options-processing to use
	getopt and added appropriate incantations to the Makefile.

Wed Feb 20 1985 - wnl (still 1.8)
	Put in the ifdef FOUR_ONE statements to make top still compilable
	on a 4.1 system.  Apparently, there are some users out there that
	need this functionality.  Oh well.  I don't guarantee any of it,
	since I can't test it.  Made appropriate changes to README and
	final installation related changes to Makefile.

Sat Feb  2 1985 - wnl (1.8)
	Removed all the ifdef FOUR_TWO statements and made "top" into a
	4.2 only program.  If someone really wants to still run it on 4.1,
	then they can do all the work.  We don't have a 4.1 machine
	anymore, so I don't even know if the thing still works under 4.1.
	Cleaned up the Makefile and the README.  Added installation rules
	to the Makefile, as requested by several sites.  Fixed a very
	obscure divide-by-zero bug.  Added a second "key" to the qsort
	comparison function (proc_compar) so that comparisons are based on
	cpu ticks if the percentages are equal (provided by Jonathon
	Feiber at Sun).

Tue Dec 11 1984 - wnl (1.7)
	Added the virtual and real memory status line to the header area
	(provided by Jonathon Feiber at Sun)

Tue Nov 20 1984 - wnl (1.6)
	Added an "exit" if sbrk's fail.  Added changes from Jonathon
	Feiber at Sun:  ifdef SUN to make top work on Suns (they don't use
	doubles in the proc structure), register declarations, check for
	getting a user structure that has disappeared since the proc array
	was read (it used to die, now it just shows the process as swapped).

Tue Nov 13 1984 - wnl (1.5)
	If the number of displayable processes ("active_procs") was less
	than the number of requested processes ("topn"), top would
	segmentation fault.  This bug has been fixed.  Thanks to Prentiss
	Riddle at ut-sally for pointing out the existence of this bug.

Tue Oct 23 1984 - wnl (1.4)
	Finally fixed the hash table bug that caused processes owned by
	root to sometimes appear with either no name or a different name
	that had UID 0 (such as "operator").  Removed all the ifdef DEBUG
	blocks to make top ready for distribution to the real world.

Sun Apr  8 1984 - wnl (still 1.3)
	Made some slight changes to the display format.  It now looks more
	aesthetically pleasing.  Added some preprocessor constants so that
	the two defaults (number of processes and seconds of delay) easier
	to change.

Thu Apr  5 1984 - wnl (1.3)
	Changed the order in which things are done at initialization time.
	This way, if an error occurs before starting the main loop, curses
	will never get started.  Also changed other error handlers so that
	endwin() is called before any flavor of exit.  Specifying a number
	of processes that is more than the screen can handle is no longer
	fatal.  It displays a warning message and pretends the user
	specified the maximum for the screen.  Finally cured all the TSTP
	blues (well, almost all).  I removed my TSTP handler and convinced
	the system to always use the one that curses sets up.  Turns out
	that "sleep" was stepping all over it during a pause.  So, I don't
	use sleep anymore.  The only problem that remains with it now is
	redrawing the old display before updating it after a pause.

Tue Apr  3 1984 - wnl (from 1.0 to 1.2)
	I changed the format of the TIME column from just "seconds" to
	"minutes:seconds".  I also made pausing work correctly.  Screen
	redraws with an up to date display.  For compatibility with 4.2, I
	changed the name of the "zero" function to "bzero".  The makefile
	has been altered to handle versions for 4.1 and 4.2, and README
	has been updated to reflect these recent changes.
SHAR_EOF
fi
echo shar: "extracting 'top.man'" '(7861 characters)'
if test -f 'top.man'
then
	echo shar: "will not over-write existing file 'top.man'"
else
cat << \SHAR_EOF > 'top.man'
.\" NOTE:  changes to the manual page for "top" should be made in the
.\"        file "top.man" and NOT in the file "top.1".
.TH TOP 1 Local
.UC 4
.SH NAME
top \- display and update information about the top cpu processes
.SH SYNOPSIS
.B top
[
.B \-Sbinu
] [
.BI \-d count
] [
.BI \-s time
] [
.I number
]
.SH DESCRIPTION
.\" This defines appropriate quote strings for nroff and troff
.ds lq \&"
.ds rq \&"
.if t .ds lq ``
.if t .ds rq ''
.\" Just in case these number registers aren't set yet...
.if \nN==0 .nr N 10
.if \nD==0 .nr D 5
.I Top
displays the top
.if !\nN==-1 \nN
processes on the system and periodically updates this information.
.if \nN==-1 \
\{\
If standard output is an intelligent terminal (see below) then
as many processes as will fit on the terminal screen are displayed
by default.  Otherwise, a good number of them are shown (around 20).
.\}
Raw cpu percentage is used to rank the processes.  If
.I number
is given, then the top
.I number
processes will be displayed instead of the default.
.PP
.I Top
makes a distinction between terminals that support advanced capabilities
and those that do not.  This
distinction affects the choice of defaults for certain options.  In the
remainder of this document, an \*(lqintelligent\*(rq terminal is one that
supports cursor addressing, clear screen, and clear to end of line.
Conversely, a \*(lqdumb\*(rq terminal is one that does not support such
features.  If the output of
.I top
is redirected to a file, it acts as if it were being run on a dumb
terminal.
.SH OPTIONS
.TP
.B \-S
Show system processes in the display.  Normally, system processes such as
the pager and the swapper are not shown.  This option makes them visible.
.TP
.B \-b
Use \*(lqbatch\*(rq mode.  In this mode, all input from the terminal is
ignored.  Interrupt characters (such as ^C and ^\e) still have an effect.
This is the default on a dumb terminal, or when the output is not a terminal.
.TP
.B \-i
Use \*(lqinteractive\*(rq mode.  In this mode, any input is immediately
read for processing.  See the section on \*(lqInteractive Mode\*(rq
for an explanation of
which keys perform what functions.  After the command is processed, the
screen will immediately be updated, even if the command was not
understood.  This mode is the default when standard output is an
intelligent terminal.
.TP
.B \-n
Use \*(lqnon-interactive\*(rq mode.  This is indentical to \*(lqbatch\*(rq
mode.
.TP
.B \-u
Do not take the time to map uid numbers to usernames.  Normally,
.I top
will read as much of the file \*(lq/etc/passwd\*(rq as is necessary to map
all the user id numbers it encounters into login names.  This option
disables all that, while possibly decreasing execution time.  The uid
numbers are displayed instead of the names.
.TP
.BI \-d count
Show only
.I count
displays, then exit.  A display is considered to be one update of the
screen.  This option allows the user to select the number of displays he
wants to see before
.I top
automatically exits.  For intelligent terminals, no upper limit
is set.  The default is 1 for dumb terminals.
.TP
.BI \-s time
Set the delay between screen updates to
.I time
seconds.  The default delay between updates is \nD seconds.
.PP
Both
.I count
and
.I number
fields can be specified as \*(lqinfinite\*(rq, indicating that they can
stretch as far as possible.  This is accomplished by using any proper
prefix of the keywords
\*(lqinfinity\*(rq,
\*(lqmaximum\*(rq,
or
\*(lqall\*(rq.
The default for
.I count
on an intelligent terminal is, in fact,
.BI infinity .
.SH "INTERACTIVE MODE"
When
.I top
is running in \*(lqinteractive mode\*(rq, it reads commands from the
terminal and acts upon them accordingly.  In this mode, the terminal is
put in \*(lqCBREAK\*(rq, so that a character will be
processed as soon as it is typed.  Almost always, a key will be
pressed when
.I top
is between displays; that is, while it is waiting for
.I time
seconds to elapse.  If this is the case, the command will be
processed and the display will be updated immediately thereafter
(reflecting any changes that the command may have specified).  This
happens even if the command was incorrect.  If a key is pressed while 
.I top
is in the middle of updating the display, it will finish the update and
then process the command.  Some commands require additional information,
and the user will be prompted accordingly.  While typing this information
in, the user's erase and kill keys (as set up by the command
.IR stty )
are recognized, and a newline terminates the input.
.PP
These commands are currently recognized (^L refers to control-L):
.TP
.B ^L
Redraw the screen.
.IP "\fBh\fP\ or\ \fB?\fP"
Display a summary of the commands (help screen).
.TP
.B q
Quit
.IR top.
.TP
.B d
Change the number of displays to show (prompt for new number).
Remember that the next display counts as one, so typing
.B d1
will make
.I top
show one final display and then immediately exit.
.TP
.B n or #
Change the number of processes to display (prompt for new number).
.TP
.B s
Change the number of seconds to delay between displays
(prompt for new number).
.TP
.B k
Send a signal (\*(lqkill\*(rq by default) to a list of processes.  This
acts similarly to the command
.IR kill (1)).
.TP
.B r
Change the priority (the \*(lqnice\*(rq) of a list of processes.
This acts similarly to the command
.IR renice (8)).
.TP
.B e
Display a list of system errors (if any) generated by the last
.BR k ill
or
.BR r enice
command.
.SH "THE DISPLAY"
The top few lines of the display show general information
about the state of the system, including
the last process id assigned to a process,
the three load averages,
the current time,
the number of existing processes,
the number of processes in each state
(sleeping, ABANDONED, running, starting, zombies, and stopped),
and a percentage of time spent in each of the processor states
(user, nice, system, and idle).
It also includes the amount of virtual and real memory in use
(with the amount of memory considered \*(lqactive\*(rq in parentheses) and
the amount of free memory.
.PP
The remainder of the screen displays information about individual
processes.  This display is similar in spirit to
.IR ps (1)
but it is not exactly the same.  PID is the process id, USERNAME is the name
of the process's owner (if
.B \-u
is specified, a UID column will be substituted for USERNAME),
PRI is the current priority of the process,
NICE is the nice amount (in the range \-20 to 20),
SIZE is the total size of the process (text, data, and stack),
RES is the current amount of resident memory (both SIZE and RES are
given in kilobytes),
STATE is the current state (one of \*(lqsleep\*(rq, \*(lqWAIT\*(rq,
\*(lqrun\*(rq, \*(lqidl\*(rq, \*(lqzomb\*(rq, or \*(lqstop\*(rq),
TIME is the number of system and user cpu seconds that the process has used,
WCPU is the weighted cpu percentage (this is the same value that
.IR ps (1)
displays as CPU),
CPU is the raw percentage and is the field that is sorted to determine
the order of the processes, and
COMMAND is the name of the command that the process is currently running
(if the process is swapped out, this column is marked \*(lq<swapped>\*(rq).
.SH NOTES
The \*(lqABANDONED\*(rq state (known in the kernel as \*(lqSWAIT\*(rq) was
abandoned, thus the name.  A process should never end up in this state.
.SH AUTHOR
William LeFebvre, Rice University graduate student
.SH FILES
.DT
/dev/kmem		kernel memory
.br
/dev/mem		physical memory
.br
/etc/passwd		used to map uid numbers to user names
.br
/vmunix		system image
.SH BUGS
The command name for swapped processes should be tracked down, but this
would make the program run slower.
.PP
As with
.IR ps (1),
things can change while
.I top
is collecting information for an update.  The picture it gives is only a
close approximation to reality.
.SH "SEE ALSO"
kill(1),
ps(1),
stty(1),
mem(4),
renice(8)
SHAR_EOF
fi
echo shar: "extracting 'sigconv.awk'" '(439 characters)'
if test -f 'sigconv.awk'
then
	echo shar: "will not over-write existing file 'sigconv.awk'"
else
cat << \SHAR_EOF > 'sigconv.awk'
BEGIN		{
		    print "/* This file was automatically generated */"
		    print "/* by the awk script \"sigconv.awk\".      */\n"
		    print "struct sigdesc {"
		    print "    char *name;"
		    print "    int  number;"
		    print "};\n"
		    print "struct sigdesc sigdesc[] = {"
		}

/^#define[ \t][ \t]*SIG[A-Z]/	{
				    printf "    \"%s\",\t%2d,\n", \
					substr($2, 4), $3
				}

END				{
				    print "    NULL,\t 0\n};"
				}
SHAR_EOF
fi
echo shar: "extracting 'Makefile'" '(3194 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
# Makefile for "top", a top 10 process display for Unix
#
# This makefile is for top, version 2.0
#
# Written by William LeFebvre, Rice University graduate student

# installation information:
#	OWNER	- name (or uid) for the installed executable's owner
#	GROUP	- group name (or gid) for the installed executable's group
#	MODE	- mode for the installed executable (should start with a 0)
#	BINDIR	- directory where the executable should live
#	MANDIR	- directory where the manual page should live
#	MAN	- troff macros for manual pages
#	TROFF	- most appropriate troff command

OWNER  = phil
GROUP  = staff
MODE   = 755
BINDIR = /usr/local
MANDIR = /usr/man/manl
MAN    = man
TROFF  = troff

# Values for the two defaults in "top":
#	TOPN	- default number of processes to display
#	DELAY	- default delay between updates
#
# set TOPN to -1 to indicate infinity (so that top will display as many
# as the screen will hold).

TOPN = 10
DELAY = 5

TABLE =
# Top maintains an internal hash table for translating uid to username.
# This hash table must be big enough to hold every name in /etc/passwd.
# It is possible, but not necessary, to specify the hash table size in
# this Makefile.  Just uncomment the following line and provide a number.
#TABLE = -DTable_size=

HEADERFILES = boolean.h layout.h screen.h top.h top.local.h masscomp.h bzero.c
DOCFILES = README Changes top.man sigconv.awk Makefile getopt.c
SRCFILES = top.c commands.c display.c kernel.c screen.c 

TARFILES = $(HEADERFILES) $(DOCFILES) $(SRCFILES)

OBJS = top.o commands.o display.o kernel.o screen.o getopt.o

# Top uses the preprocessor variables "sun" and "pyr" for specific changes
# required by Suns and Pyramids.  No changes to "CFLAGS" are required for
# these architectres.
CFLAGS = -O
# To make a version for 4.1, comment out the previous line and
# uncomment the following two lines:
#CFLAGS = -DFOUR_ONE -O
#OBJS = top.o commands.o display.o kernel.o screen.o getopt.o bzero.o
# use this definition of cc on pyramid or masscomp
CC = ucb cc

all: top top.1

top: $(OBJS)
	$(CC) $(CFLAGS) -o top $(OBJS) -ltermcap -lm

top.o: top.c Makefile
	$(CC) -c $(CFLAGS) $(TABLE) -DDefault_TOPN=$(TOPN) -DDefault_DELAY=$(DELAY) top.c

# include file dependencies
top.o: boolean.h layout.h screen.h top.h top.local.h masscomp.h
commands.o: sigdesc.h
display.o: boolean.h layout.h screen.h top.h masscomp.h
kernel.o: top.local.h masscomp.h
screen.o: boolean.h screen.h

# automatically built include file
sigdesc.h: sigconv.awk /usr/include/signal.h
	awk -f sigconv.awk /usr/include/signal.h >sigdesc.h

# top.1 is built by combining the actual text with the default information
top.1: top.man Makefile
	echo '.nr N' $(TOPN) > top.1
	echo '.nr D' $(DELAY) >>top.1
	cat top.man >>top.1

top.cat: top.1
	nroff -$(MAN) top.1 | cat -s >top.cat

troff: top.1
	$(TROFF) -man top.1

tar:
	rm -f top.tar
	tar cvf top.tar $(TARFILES)

shar:
	rm -f top1.shar top2.shar top3.shar
	shar -v $(HEADERFILES) > top1.shar
	shar -v $(SRCFILES) > top2.shar
	shar -v $(DOCFILES) > top3.shar

clean:
	rm -f *.o top top.cat top.tar top.1 core

install: top top.1
	install -s -o $(OWNER) -m $(MODE) -g $(GROUP) top $(BINDIR)
	install -c top.1 $(MANDIR)
SHAR_EOF
fi
echo shar: "extracting 'getopt.c'" '(1259 characters)'
if test -f 'getopt.c'
then
	echo shar: "will not over-write existing file 'getopt.c'"
else
cat << \SHAR_EOF > 'getopt.c'
/*LINTLIBRARY*/
#define NULL	0
#define EOF	(-1)
#define ERR(s, c)	if(opterr){\
	extern int strlen(), write();\
	char errbuf[2];\
	errbuf[0] = c; errbuf[1] = '\n';\
	(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
	(void) write(2, s, (unsigned)strlen(s));\
	(void) write(2, errbuf, 2);}

#define strchr index

extern int strcmp();
extern char *strchr();

int	opterr = 1;
int	optind = 1;
int	optopt;
char	*optarg;

int
getopt(argc, argv, opts)
int	argc;
char	**argv, *opts;
{
	static int sp = 1;
	register int c;
	register char *cp;

	if(sp == 1)
		if(optind >= argc ||
		   argv[optind][0] != '-' || argv[optind][1] == '\0')
			return(EOF);
		else if(strcmp(argv[optind], "--") == NULL) {
			optind++;
			return(EOF);
		}
	optopt = c = argv[optind][sp];
	if(c == ':' || (cp=strchr(opts, c)) == NULL) {
		ERR(": unknown option, -", c);
		if(argv[optind][++sp] == '\0') {
			optind++;
			sp = 1;
		}
		return('?');
	}
	if(*++cp == ':') {
		if(argv[optind][sp+1] != '\0')
			optarg = &argv[optind++][sp+1];
		else if(++optind >= argc) {
			ERR(": argument missing for -", c);
			sp = 1;
			return('?');
		} else
			optarg = argv[optind++];
		sp = 1;
	} else {
		if(argv[optind][++sp] == '\0') {
			sp = 1;
			optind++;
		}
		optarg = NULL;
	}
	return(c);
}
SHAR_EOF
fi
exit 0
#	End of shell archive