*BSD News Article 55601


Return to BSD News archive

Newsgroups: comp.bugs.2bsd
Path: euryale.cc.adfa.oz.au!newshost.anu.edu.au!harbinger.cc.monash.edu.au!news.mel.connect.com.au!yarrina.connect.com.au!news.mel.aone.net.au!news.internetMCI.com!darwin.sura.net!blaze.cs.jhu.edu!boingo.amil.jhu.edu!europa.chnt.gtegsc.com!wlbr!sms
From: sms@wlv.iipo.gtegsc.com (Steven M. Schultz)
Subject: qterm - a better 'tset' (#279)
Sender: news@wlbr.iipo.gtegsc.com (Steven M. Schultz)
Organization: GTE Government Systems, Thousand Oaks CA USA
Message-ID: <DIFHF4.CE5@wlbr.iipo.gtegsc.com>
X-Nntp-Posting-Host: wlv.iipo.gtegsc.com
Date: Wed, 22 Nov 1995 04:49:51 GMT
Lines: 2707

Subject: qterm - a better 'tset' (#279)
Index:	local/qterm 2.11BSD

Description:
	From the contributor, Robin Birch <robin@falstaf.demon.co.uk>:
	
	"Here is a noddy terminal query program that is a little brighter 
	than tset ...  I got it off a tools cd that O'Reilly published some 
	time ago.  Cheers."

Repeat-By:
	N/A

Fix:
	Included below is a shar archive containing a small patch to
	/VERSION and the shar archive of the qterm program itself.

	Cut where indicated, saving to a file (/tmp/279).  Then:

		sh /tmp/279
		sh /tmp/qterm.shar
		cd /usr/src/local/qterm
		make
		make install
		make clean
		patch -p0 < /tmp/p.279
		rm /tmp/279 /tmp/p.279 /tmp/qterm.shar

	The README file and man page should be self explanatory.

	This and previous 2.11BSD updates may be obtained via anonymous
	FTP to the host 'NS.IIPO.GTEGSC.COM' in the directory /pub/2.11BSD.

========================cut 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:
#	/tmp/p.279
#	/tmp/qterm.shar
# This archive created: Tue Nov 21 20:31:38 1995
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f '/tmp/p.279'
then
	echo shar: "will not over-write existing file '/tmp/p.279'"
else
sed 's/^Y//' << \SHAR_EOF > '/tmp/p.279'
Y*** /VERSION.old	Tue Nov 21 19:55:22 1995
Y--- /VERSION	Tue Nov 21 20:28:28 1995
Y***************
Y*** 1,4 ****
Y! Current Patch Level: 278
Y  
Y  2.11 BSD
Y  ============
Y--- 1,4 ----
Y! Current Patch Level: 279
Y  
Y  2.11 BSD
Y  ============
SHAR_EOF
fi
if test -f '/tmp/qterm.shar'
then
	echo shar: "will not over-write existing file '/tmp/qterm.shar'"
else
sed 's/^Y//' << \SHAR_EOF > '/tmp/qterm.shar'
Y#! /bin/sh
Y# This is a shell archive, meaning:
Y# 1. Remove everything above the #! /bin/sh line.
Y# 2. Save the resulting text in a file.
Y# 3. Execute the file with /bin/sh (not csh) to create:
Y#	/usr/src/local/qterm
Y# This archive created: Tue Nov 21 20:31:07 1995
Yexport PATH; PATH=/bin:/usr/bin:$PATH
Yif test ! -d '/usr/src/local/qterm'
Ythen
Y	mkdir '/usr/src/local/qterm'
Yfi
Ycd '/usr/src/local/qterm'
Yif test -f 'README'
Ythen
Y	echo shar: "will not over-write existing file 'README'"
Yelse
Ysed 's/^X//' << \SHAR_EOF > 'README'
YX
YX		Q T E R M  -  Q U E R Y   T E R M I N A L
YX
YX			    Version 5.0
YX
YXQterm is a program that queries terminals to find out what kind of
YXterminal is responding.  It is useful to automagically define your
YXterminal type.  It prints the name of the terminal (compatible,
YXhopefully, with a termcap/terminfo name) such as "vt100" to standard
YXoutput.  See the manual for details.
YX
YXThe major changes in these version of qterm is a re-write of command
YXline parsing and the options qterm accepts.  I've written a new,
YX"generic" command line parsing package called "options" which is
YXincluded as part of this distribution of qterm.  (See the options.3
YXman page for details on programming with the options package.)  Qterm
YXnow has a totally new set of (hopefully) clear and concise options.
YXThe old command line options are still accepted if qterm is compiled
YXwith OPT_COMPAT defined (see Makefile).  WARNING: Some of the old
YXoptions conflict with the new options.  i.e.  If OPT_COMPAT is
YXdefined, "qterm -file foo" does not do what you think it will.  This
YXis parsed as "qterm -f ile foo".
YX
YXQterm was written under 4.[23] BSD and will probably run without
YXmodification on other Berkeley Unix systems.  This version has also
YXbeen tested under UTS 2.1 which is a System V.3 derivative.  It was
YXcompiled with "USG5" defined and setting $(LIBS) to "-lPW".  (See
YXMakefile for more info).  It should work on other System V platforms.
YX
YXIt has been running at one point or another here at USC on:
YX
YX	Sun-3, Sun-4, Sun386i's under SunOS 3.X, 4.0, 4.0.3, 4.1, 4.1.1
YX	Alliant's under Concentrix 3.X, 4.X, 5.X
YX	IBM RT's under ACIS 4.2 and 4.3
YX	DEC VAX & DEC RISC under Ultrix 2.2, 3.1, 4.0, 4.1
YX	4.[23]BSD (VAX)
YX	4.3BSD [MORE/bsd] (HP)
YX	Amdahl UTS (System V.3) 2.1
YX
YXIf you have Internet access, the latest and greatest version of qterm
YXis available from "usc.edu" via anonymous ftp in the file
YX/pub/qterm.shar.  I update this file whenever there are any changes,
YXso it's bound to be newer than a copy from any other source.
YX
YX
YXMichael A. Cooper, University Computing Services, U of Southern California
YX  INTERNET: mcooper@usc.edu	            PHONE: 213-740-2957
YX  UUCP: ...!uunet!usc!mcooper              BITNET: mcooper@gamera
YSHAR_EOF
Ychmod 644 'README'
Yfi
Yif test -f 'qtermtab'
Ythen
Y	echo shar: "will not over-write existing file 'qtermtab'"
Yelse
Ysed 's/^X//' << \SHAR_EOF > 'qtermtab'
YX#
YX# $Header: /am/sol/src/common/usc/bin/qterm/RCS/qtermtab,v 5.0 90/12/15 18:30:49 mcooper Release $
YX#
YX# QtermTab - Query terminal table for qterm(1).
YX#
YX#SendStr ReceiveStr		TermName	FullTermName
YX#
YX^[Z	^[[?1;0c     		vt100    	Base vt100
YX^[Z	^[[?1;1c     		vt100   	vt100 with STP
YX^[Z	^[[?1;2c     		vt100   	ANSI/VT100 Clone
YX^[Z	^[[?1;3c     		vt100    	vt100 with AVO and STP
YX^[Z	^[[?1;4c     		vt100    	vt100 with GPO
YX^[Z	^[[?1;5c     		vt100    	vt100 with GPO and STP
YX^[Z	^[[?1;6c     		vt100    	vt100 with GPO and AVO
YX^[Z	^[[?1;7c     		vt100    	vt100 with GPO, STP, and AVO
YX^[Z     ^[[?6;2c                vt100           Uniterm vt100 Emulator
YX^[Z	^[/K          		h29	 	Zenith z29 in zenith mode
YX^[Z	^[/Z          		vt52	 	Generic vt52
YX^[Z	^[[0n         		vt100    	AT&T Unix PC 7300
YX^[Z	^[[62;1;2;6;8c		f220     	Freedom 220 DEC clone
YX^[Z	^[[=1;1c     		avt-4p-s 	Concept with 4 pages memory
YX^[Z	^[[=1;2c     		avt-8p-s 	Concept with 8 pages memory
YX^[Z	^[[?10c       		la120	 	DEC Writer III
YX^[Z	^[[?12;7;0;102c 	vt125	 	DEC Pro 350 in vt125 mode
YX^[Z	^[[?12c       		vt100    	Concept from Pro 350/UNIX
YX^[Z	^[[?1;11c    		cit101e  	CIE CIT-101 Enhanced w/Graphics
YX^[Z	^[[?62;1;2;6;7;8;9c 	vt220   	DEC VT220
YX^[Z	^[[?62;1;2;6;7;8c	vt100		Amiga Handshake
YX^[Z	^[[?62;1;4;6;7;8;9;15c	vt200-sb	Microvax II VMS
YX^[Z	^[[?63;1;2;6;7;8c 	tvi9220  	TeleVideo 9220
YX^[Z	^[[?6c        		vt100  	 	Generic vt100
YX^[Z	^[[?8;8;6c		att630		AT&T 630 MTG
YX^[Z	^[[?8c        		vt100    	TeleVideo 970
YX^[Z	^[[?;c        		vt100    	Concept From Pro 350/UNIX
YX^[Z	^[[?l;0c     		vt100    	AT&T Unix PC 7300
YX^[Z	^[iB0         		h29	 	Zenith z29 in zenith mode
YX#^[Z	^[[?1;11c    		xt100+   	Northern Tech LANPARSCOPE
YX############################################################################
YX#
YX# Enable at your own risk
YX#
YX#^[\040		50		wyse50		Wyse 50 Terminal
YX#^[i0		^[iB0		z29		Zenith z29
YX#
YX# HP terminals
YX#
YX#^[*s1\^	2621^J		hp2621		Hewlett-Packard HP-2621
YX#^[*s1\^	2621A^J		hp2621a		Hewlett-Packard HP-2621A
YX#^[*s1\^	2621B^J		hp2621b		Hewlett-Packard HP-2621B
YX#^[*s1\^	2621K^J		hp2621k		Hewlett-Packard HP-2621K
YX#^[*s1\^	2621K45^J	hp2621k45	Hewlett-Packard HP-2621K45
YX#^[*s1\^	2621NL^J	hp2621nl	Hewlett-Packard HP-2621NL
YX#^[*s1\^	2621NT^J	hp2621nt	Hewlett-Packard HP-2621NT
YX#^[*s1\^	2621P^J		hp2621p		Hewlett-Packard HP-2621P
YX#^[*s1\^	2621WL^J	hp2621wl	Hewlett-Packard HP-2621WL
YX#^[*s1\^	2622^J		hp2622		Hewlett-Packard HP-2622
YX#^[*s1\^	2622A^J		hp2622a		Hewlett-Packard HP-2622A
YX#^[*s1\^	2622P^J		hp2622p		Hewlett-Packard HP-2622P
YX#^[*s1\^	2626^J		hp2626		Hewlett-Packard HP-2626
YX#^[*s1\^	2626A^J		hp2626a		Hewlett-Packard HP-2626A
YX#^[*s1\^	2626P^J		hp2626p		Hewlett-Packard HP-2626P
YX#^[*s1\^	2640^J		hp2640		Hewlett-Packard HP-2640
YX#^[*s1\^	2640A^J		hp2640a		Hewlett-Packard HP-2640A
YX#^[*s1\^	2640B^J		hp2640b		Hewlett-Packard HP-2640B
YX#^[*s1\^	2644A^J		hp2644a		Hewlett-Packard HP-2644A
YX#^[*s1\^	2645^J		hp2645		Hewlett-Packard HP-2645
YX#^[*s1\^	2645A^J		hp2645a		Hewlett-Packard HP-2645A
YX#^[*s1\^	2645NP^J	hp2645np	Hewlett-Packard HP-2645NP
YX#^[*s1\^	2647^J		hp2647		Hewlett-Packard HP-2647
YX#^[*s1\^	2647A^J		hp2647a		Hewlett-Packard HP-2647A
YX#^[*s1\^	2648^J		hp2648		Hewlett-Packard HP-2648
YX#^[*s1\^	2648A^J		hp2648a		Hewlett-Packard HP-2648A
YX############################################################################
YSHAR_EOF
Ychmod 644 'qtermtab'
Yfi
Yif test -f 'Makefile'
Ythen
Y	echo shar: "will not over-write existing file 'Makefile'"
Yelse
Ysed 's/^X//' << \SHAR_EOF > 'Makefile'
YX#
YX# Copyright (c) 1990 Michael A. Cooper.
YX# This software may be freely distributed provided it is not sold for 
YX# profit and the author is credited appropriately.
YX#
YX# $Header: /src/common/usc/bin/qterm/RCS/Makefile,v 5.1 1991/02/20 02:31:50 mcooper Exp $
YX#
YX# Makefile for QTerm
YX#
YX
YX#
YX# DIR is the main/top-level directory.
YX# If you change DIR, run "make reconfig".
YX#
YXDIR = /usr/local
YX
YX#
YX# BIN is were the "qterm" binary gets installed.
YX#
YXBIN = $(DIR)
YX
YX#
YX# MAN is the directory where the "qterm.1" man page goes.
YX#
YXMAN = $(DIR)/man/cat1
YX
YX#
YX# TABFILE should be set to the location you want the qterm table
YX# file placed in.
YX#
YXTABFILE = $(DIR)/lib/qtermtab
YX
YX#
YX# Add "-DUSG5" to DEFS below, if your system is Unix System V.
YX# Add "-DHAS_VARARGS" if your system supports varargs.
YX# Add "-DOPT_COMPAT" if you want compatibility with old command line options.
YX#
YXDEFS 	= -DTABFILE=\"$(TABFILE)\" -DOPT_COMPAT -DHAS_VARARGS
YX
YX#
YX# On some System V systems you will need to add "-lPW" to LIBS.
YX#
YXLIBS	= -lc
YX
YX
YXCONFIGFILES	= Makefile qterm.1 options.3
YXCFILES 		= qterm.c options.c
YXHFILES		= qterm.h options.h
YXOBJS 		= qterm.o options.o
YXCFLAGS 		= -O $(DEFS)
YXLD		= ld
YXLDFLAGS		= -i
YX
YX.c.o :
YX	$(CC) $(CFLAGS) -c $<
YX
YXall:	qterm qterm.0
YX
YXqterm: $(OBJS) $(HFILES)
YX	$(LD) $(LDFLAGS) /lib/crt0.o -o qterm $(OBJS) $(LIBS)
YX
YXreconfig:
YX	-@for i in $(CONFIGFILES); do \
YX                echo ReConfiguring $$i...;\
YX		sed "s;/usr/local;$(DIR);g" < $$i > $$i.tmp;\
YX		mv -f $$i.tmp $$i;\
YX        done
YX
YX$(OBJS): $(HFILES)
YX
YXqterm.0:
YX	/usr/man/manroff qterm.1 > qterm.0
YX
YXshar:
YX	shar README qtermtab $(CONFIGFILES) $(CFILES) $(HFILES) > qterm.shar
YX
YXclean:
YX	rm -f *.o core log *~ \#* qterm qterm.shar o qterm.0
YX
YX#
YX# Install target for BSD machines.
YX#
YXinstall: qterm qterm.0 qtermtab
YX	install -c -m 755 qterm $(BIN)
YX	install -c -m 644 qterm.0 $(MAN)
YX	install -c -m 644 qtermtab $(TABFILE)
YX
YX#
YX# Install target for System V machines.
YX#
YXinstall.usg5: qterm qterm.1 qtermtab
YX	cp qterm $(BIN); chmod 755 $(BIN)/qterm
YX	cp qterm.1 $(MAN); chmod 644 $(MAN)/qterm.1
YX	cp qtermtab $(TABFILE); chmod 644 $(TABFILE)
YSHAR_EOF
Ychmod 644 'Makefile'
Yfi
Yif test -f 'qterm.1'
Ythen
Y	echo shar: "will not over-write existing file 'qterm.1'"
Yelse
Ysed 's/^X//' << \SHAR_EOF > 'qterm.1'
YX.\"
YX.\" Copyright (c) 1990 Michael A. Cooper.
YX.\" This software may be freely distributed provided it is not sold for 
YX.\" profit and the author is credited appropriately.
YX.\"
YX.\" $Header: /am/sol/src/common/usc/bin/qterm/RCS/qterm.1,v 5.0 90/12/15 18:30:38 mcooper Release $
YX.\"
YX.TH QTERM 1 "6 November 1990"
YX.ds ]W USC-UCS
YX.SH NAME
YXqterm \- Query Terminal
YX.SH SYNOPSIS
YXqterm 
YX[
YX.B +|\-alt
YX] [
YX.B +|\-always
YX] [
YX.B +|\-longname
YX] [
YX.B +|\-quiet
YX] [
YX.B +|\-sent
YX] [
YX.B +|\-timeout
YX] [
YX.B +|\-usrtab
YX] [
YX.B +|\-watch
YX] [
YX.B +|\-systab
YX] [
YX.B \-wait
YX.I interval
YX] [
YX.B \-file
YX.I tabfile
YX]
YX.SH DESCRIPTION
YX.I Qterm
YXis used to query a terminal to determine its name.
YXThis is done by sending a special sequence to the terminal,
YXreading in a response, and comparing it against a table of possible
YXresponses.
YXThe ``name'' printed to standard output should be one found in
YXthe
YX.I termcap(5)
YX(or
YX.I terminfo(5)
YXfor System V systems)
YXdatabase.
YX.PP
YXFor 
YX.I csh(1) 
YXusers,
YXputting a line in your 
YX.I .login 
YXfile such as:
YX.sp 1
YX.in +.5i
YXsetenv TERM `qterm`
YX.in -.5i
YX.sp 1
YXshould automagically set your terminal type.
YXFor 
YX.I sh(1)
YXusers, putting these lines in your 
YX.I .profile 
YXfile should set your terminal type:
YX.sp 1
YX.in +.5i
YXTERM=`qterm`
YX.br
YXexport TERM
YX.in -.5i
YX.sp 1
YX.LP
YXBy default,
YX.B qterm
YXuses the system tab file
YX.I /usr/local/lib/qtermtab
YXto obtain information for querying terminals.
YX.SH OPTIONS
YX.IP \fB+alt\fP
YXUse the alternate string ``<ESCAPE>[c'' when asking the terminal to
YXidentify itself.  This string is recognized by most ANSI compatible
YXterminals.
YX.IP \fB\-alt\fP
YXDon't use the alternate string, but the string found in the
YX.B tabfile
YXbeing used.
YXThis is the default.
YX.IP \fB+always\fP
YXAlways send the terminal query string.
YXNormally the query string is only sent if it differs from
YXthe last string sent.
YX.IP \fB-always\fP
YXOnly send the terminal query string if it differs from the last
YXstring sent.
YXThis is the default.
YX.IP "\fB\-file \fItabfile\fP"
YXUse
YX.I <tabfile>
YXto find information for querying the terminal.
YX.IP \fB+longname\fP
YXPrint only the long (verbose) terminal name.
YX.IP \fB\-longname\fP
YXDon't print the long (verbose) terminal name.
YXThis is the default.
YX.IP \fB+quiet\fP
YXBe quiet and only print the terminal name to standard output.
YX.IP \fB\-quiet\fP
YXDon't be quiet and only print the terminal name to standard output.
YXThis is the default.
YX.IP \fB+watch\fP
YXWatch the characters sent and recieved to the terminal.
YX.IP \fB\-watch\fP
YXDon't watch the characters sent and recieved to the terminal.
YXThis is the default.
YX.IP \fB+timeout\fP
YXWait for timeout when listening for response string.
YXThis is useful if the first entry in a qtermtab doesn't have
YXa response string with an ending character that is common
YXwith the rest of the qtermtab entries.
YX.IP \fB\-timeout\fP
YXDisable waiting for timeout when listening for response string.
YXThis is the default.
YX.IP \fB+usrtab\fP
YXUse 
YX.B $HOME/.qtermtab
YXto find information for querying the terminal.
YX.IP \fB\-usrtab\fP
YXDon't use
YX.B $HOME/.qtermtab
YXto find information for querying the terminal.
YXThis is the default.
YX.IP \fB+sent\fP
YXDisplay the final response sent from
YXthe terminal in a ``nice'' fashion.
YX.IP \fB-sent\fP
YXDon't display the final response sent from the terminal.
YXThis is the default.
YX.IP \fB+systab\fP
YXUse 
YX.B /usr/local/lib/qtermtab
YXto find information for querying the terminal.
YXThis is the default
YX.IP \fB\-systab\fP
YXDon't use
YXsystem tab file
YXto find information for querying the terminal.
YX.IP "\fB\-wait \fIinterval\fP"
YXSet the wait (timeout) period to 
YX.I interval
YX(in seconds).
YX.SH "QTERMTAB"
YXThe format of the file
YX$HOME/.qtermtab
YXand 
YX.I qterm's
YXsystem tab file
YX.I /usr/local/lib/qtermtab,
YXconsists of four fields each seperated by white space (tabs and/or spaces).
YXThe first field is the string that should be used to query the terminal.
YXThe second field is the string to expect in response to the query.
YXThe third field is the terminal name (compatible with 
YX.I termcap(5))
YXto print to standard output.
YXThe fourth field is optional and may contain a description of the exact
YXmanufacturer and model name of the terminal to be used in a message
YXprinted to standard error.
YX.PP
YXBlank lines or lines starting with the character ``#''
YXare ignored and may be used as comment lines.
YXA character preceeded by a ``^'' is taken to mean the 
YX.I control
YXcharacter.  (i.e. ``^['' is interpretted as an <ESCAPE>).
YXBoth the send and receive (first and second) fields may contain
YXoctal values preceeded by a `\\'.
YX(i.e. <ESCAPE> can be represented by `\\033'.)
YX.PP
YXThe ``expect'' (second) field
YXcan be a regular expression denoted by a leading backslash (`\\').
YXi.e. "^[[123" matches the string "^[[123", whereas "^[\\[123]" matches
YX"^[1" or "^[2" or "^[3".
YXSee 
YX.I ed(1)
YXfor regular expression information.
YX.PP
YXBelow is a sample file:
YX.sp 2
YX.nf
YX	#
YX	# QTerm File
YX	#
YX	^[Z\0\0\0\0\0^[[?1;1c\0\0\0\0\0vt100\0\0\0\0\0A vt100 with STP
YX	^[Z\0\0\0\0\0^[[?1;2c\0\0\0\0\0vt100\0\0\0\0\0ANSI/VT100 Clone
YX	^[Z\0\0\0\0\0^[[?1;3c\0\0\0\0\0vt100\0\0\0\0\0A vt100 with AVO and STP
YX	^[Z\0\0\0\0\0^[[?1;4c\0\0\0\0\0vt100\0\0\0\0\0A vt100 with GPO
YX	^[Z\0\0\0\0\0^[iBO\0\0\0\0\0\0\0\0z29\0\0\0\0\0\0\0Zenith in Zenith Mode
YX.fi
YX.sp
YX.SH AUTHOR
YXMichael A. Cooper, 
YX.br
YXUniversity Computing Services, 
YX.br
YXUniversity of Southern California.
YX.SH FILES
YX.ta \w'/usr/local/lib/qtermtab\ \ \ 'u
YX/usr/local/lib/qtermtab	\- System table
YX.br
YX$HOME/.qtermtab	\- User's table
YX.br
YX/etc/termcap	\- termcap(5) database
YX.SH SEE ALSO
YXcsh(1), ed(1), sh(1), termcap(5)
YX.SH DIAGNOSTICS
YX.IP "\fITerminal not recognized - defaults to dumb.\fP"
YX.I QTerm
YXdid not receive a response from the terminal, or the response
YXdid not match any that 
YX.I qterm 
YXhas stored internally.  Use the \+watch option to check to see which
YXis the case.
YX.SH BUGS
YXMany terminals do not send a response at all.
YSHAR_EOF
Ychmod 644 'qterm.1'
Yfi
Yif test -f 'options.3'
Ythen
Y	echo shar: "will not over-write existing file 'options.3'"
Yelse
Ysed 's/^X//' << \SHAR_EOF > 'options.3'
YX.\"
YX.\" Copyright (c) 1990 Michael A. Cooper.
YX.\" This software may be freely distributed provided it is not sold for 
YX.\" profit and the author is credited appropriately.
YX.\"
YX.\" $Header: /src/common/usc/lib/libgen/RCS/options.3,v 1.4 1991/02/22 02:30:06 mcooper Exp $
YX.\"
YX.TH PARSEOPTIONS 3 "30 October 1990"
YX.ds ]W USC-UCS
YX.SH NAME
YXParseOptions, UsageOptions, HelpOptions, Num_Opts \- Parse command line options
YX.SH SYNOPSIS
YX.LP
YX.nf
YX.ft B
YX#include "/usr/local/include/options.h"
YX.ft
YX.fi
YX.LP
YX.nf
YX.ft B
YXint ParseOptions(options, num_options, argc, argv)
YXOptionDescRec *options;
YXint num_options;
YXint argc;
YXchar **argv;
YX.ft
YX.fi
YX.LP
YX.nf
YX.ft B
YXvoid UsageOptions(options, num_options, badoption)
YXOptionDescRec *options;
YXint num_options;
YXchar *badoption;
YX.ft
YX.fi
YX.LP
YX.nf
YX.ft B
YXvoid HelpOptions(options, num_options, message)
YXOptionDescRec *options;
YXint num_options;
YXchar **message;
YX.ft
YX.fi
YX.LP
YX.nf
YX.ft B
YXint Num_Opts(options)
YXOptionDescRec *options;
YX.ft
YX.fi
YX.LP
YX.nf
YX.ft B
YXextern char *OptionChars;
YXextern char *ProgramName;
YX.ft
YX.fi
YX.SH DESCRIPTION
YX.LP
YX.BR ParseOptions(\|)
YXparses a given set of options found in
YX.B argv.
YXThe
YX.B argc
YXparameter is the count of the number of string pointers
YXin 
YX.B argv.
YXBoth 
YX.B argc
YXand
YX.B argv
YXare typically passed directly from a
YX.B main(\|)
YXfunction.
YXThe
YX.B argv
YXparameter should contain an array of strings that
YXneed to be parsed.
YX.B ParseOptions(\|)
YXreturns the number of entries in
YX.B argv
YXthat were successfully parsed or -1 upon error.
YX.LP
YXThe
YX.B options
YXstructure should contain a valid description list of options.
YXThe type
YX.B OptionDescRec
YXis defined as the following in the
YX.B "options.h"
YXheader file:
YX.RS
YX.LP
YX.nf
YX.ft B
YXtypedef struct {
YX    char      *option;     /* Option string in argv */
YX    int       flags;       /* Flag bits */
YX    int       (*cvtarg)(); /* Function to convert argument */
YX    caddr_t   valp;        /* Variable to set */
YX    caddr_t   value;       /* Default value to provide */
YX    char      *usage;      /* Usage message */
YX    char      *desc;       /* Description message */
YX} OptionDescRec, *OptionDescList;
YX.ft R
YX.fi
YX.RE
YX.LP
YXThe order of
YX.I options
YXis important because
YXthe first partial match found in
YX.I options 
YXis used.
YXThis allows abbreviations (except if the option is a
YX.I StickArg
YX[see below]).
YXFor instance, a user may specify only "\-n" for "\-number" provided
YXthat "\-n" is unique to
YX.I options
YXor that "\-number" is placed before any other "\-n*" options in
YX.I options.
YX.LP
YXThe
YX.I option
YXmember of
YX.B OptionDescRec
YXis the string name of the option.
YXThis is typically something like
YX.RS
YX.ft B
YX.nf
YX.sp
YX"\-c"
YX"+c"
YX"\-file"
YX.fi
YX.sp
YX.ft
YX.RE
YXThe first character of 
YX.I option
YXis special.  It must be one of the characters know to be the
YXstart of an option.
YXThe default list of starting option characters is "\-+".
YXThis indicates that an option can start with either a "\-" or
YXa "+".  This list of characters may be changed by setting
YXthe variable
YX.B OptionChars
YXto point to a string of custom starting option characters.
YX.LP
YXThe
YX.I flags
YXmember is used to set bits to describe how an option
YXis to be interpreted.
YXValid flags are defined in the
YX.I "options.h"
YXheader file:
YX.RS
YX.IP NoArg
YXNo argument for this option.  
YXUse the value in 
YX.I OptionDescRec.value 
YXto set the value in the
YX.I valp
YXmember of 
YX.B OptionDescRec.
YX.IP IsArg
YXValue is the option string itself.
YX.IP SepArg
YXValue is in next argument in argv.
YX.IP StickyArg
YXValue is the characters immediately following 
YXthe option.
YX.IP SkipArg
YXIgnore this option and the next argument in argv.
YX.IP SkipLine
YXIgnore this option and the rest of argv.
YX.IP SkipNArgs
YXIgnore this option and the next 
YX.I OptionDescRes.value 
YXarguments in argv.
YX.IP ArgHidden
YXDon't show this option in usage or help messages.
YX.RE
YX.LP
YXThe next member of
YX.B OptionDescRec
YXis
YX.I cvtarg.
YXThis should be a pointer to a function that knows how to
YXconvert the given argument into the correct type.
YXThe predefined functions are as follows:
YX.RS
YX.IP OptBool
YXConverts a boolean.
YX.IP OptInt
YXConverts an integer.
YX.IP OptShort
YXConverts a short.
YX.IP OptLong
YXConverts a long.
YX.IP OptStr
YXConverts a string.
YX.RE
YX.LP
YXThe
YX.I valp
YXmember should be a pointer
YXto the variable that needs to be set.
YX.I valp
YXshould accept whatever type
YX.I cvtarg
YXis expected to return.
YX.LP
YXThe
YX.I value
YXmember should contain a default value to
YXbe used if no value is given for an option or
YXthis type of option does not require an argument
YX(according to the 
YX.I flags
YXbits).
YXIf 
YX.I value 
YXis
YX.B NULL
YXthen an argument for this option
YXis optional.
YX.LP
YX.I usage
YXis used to build usage and help messages.
YXIt should be a string containing a description of any arguments
YXthat may be used for this option.
YXThe option string itself should not be a part of 
YX.I usage.
YXThe 
YX.B UsageOptions(\|)
YXand 
YX.B HelpOptions(\|)
YXfunctions combine the
YX.I option
YXfield with
YX.I usage
YXand interpret the
YX.I flags
YXbits to build a usage string.
YXIf this field is 
YX.B NULL,
YXthen just the
YX.I option
YXfield itself is used for usage and help messages.
YX.LP
YXThe
YX.I desc
YXmember is used to build a help message for this option.
YXThis should be a string containing a brief description on what this
YXoption does.
YX.LP
YXThe
YX.B num_options
YXparameter should be the number of 
YX.B OptionDescRec's
YXfound in 
YX.B options.
YXThe function
YX.BR Num_Opts(\|)
YXwill return the number of 
YX.B OptionDescRec's.
YX.LP
YXThe
YX.B UsageOptions(\|)
YXfunction
YXprints a usage message.
YXIf
YX.I badoption
YXis not 
YX.B NULL, 
YXthen an initial message is displayed indicating that 
YX.I badoption
YXis not a valid option.
YX.LP
YXThe
YX.B HelpOptions(\|)
YXfunction
YXprints a nicely formatted message describing all options.
YXIf
YX.I message
YXis not 
YX.B NULL
YXit is taken to be a message that is displayed in the output of
YXa "\-help" option.
YX.SH EXAMPLE
YX.LP
YXHere is an example program:
YX.nf
YX.sp
YX.ft B
YX#include "options.h"
YX
YXchar *filename = NULL;
YXint number = \-1;
YXint foo = \-1;
YXint I = \-1;
YXlong L = \-1;
YXshort S = \-1;
YX
YXOptionDescRec opts[] = {
YX    {"\-foo",	NoArg,		OptBool, (caddr_t) &foo,	"0",
YX     (char *)NULL,	"Disable foo bar"},
YX    {"+foo",	NoArg,		OptBool, (caddr_t) &foo,       	"1",
YX     (char *)NULL,	"Enable foo bar"},
YX    {"\-I",	StickyArg,	OptInt, (caddr_t) &I,		(caddr_t) NULL,
YX     (char *)NULL,	"Set value of I"},
YX    {"\-L",	StickyArg,	OptLong, (caddr_t) &L,		(caddr_t) NULL,
YX     (char *)NULL,	"Set value of L"},
YX    {"\-S",	SepArg,		OptShort, (caddr_t) &S,		(caddr_t) NULL,
YX     (char *)NULL,	"Set value of S"},
YX    {"\-C",	StickyArg,	OptStr, (caddr_t) &filename,	(caddr_t) NULL,
YX     (char *)NULL,	"Alternate file to use"},
YX    {"\-number",	SepArg, 	OptInt, (caddr_t) &number,	"66",
YX     "interval",	NULL},
YX    {"\-file",	SepArg, 	OptStr, (caddr_t) &filename,	(caddr_t) NULL,
YX     "filename",	"Specify alternate file to use"},
YX};
YX
YXmain(argc, argv)
YX     int argc;
YX     char **argv;
YX{
YX    int c;
YX
YX    c = ParseOptions(opts, Num_Opts(opts), argc, argv);
YX    printf("Count = %d of %d\n", c, argc);
YX}
YX.ft
YX.fi
YX.SH "RETURN VALUES"
YX.B ParseOptions(\|)
YXreturns the number of arguments parsed or -1 upon error.
YX.SH NOTES
YX.LP
YXThe
YX.I \-help
YXoption is automatically built into 
YX.B ParseOptions(\|).
YX.LP
YXAll error messages are sent to 
YX.B stderr.
YX.LP
YXAn option may be both 
YX.I StickyArg
YXand
YX.I SepArg.
YXIf both are set for one option, preference is given to
YX.I SepArg
YXparsing.
YXAlso, no appreviations are allowed.
YX.SH AUTHOR
YXMichael A. Cooper, 
YX.br
YXUniversity Computing Services, 
YX.br
YXUniversity of Southern California.
YSHAR_EOF
Ychmod 644 'options.3'
Yfi
Yif test -f 'qterm.c'
Ythen
Y	echo shar: "will not over-write existing file 'qterm.c'"
Yelse
Ysed 's/^X//' << \SHAR_EOF > 'qterm.c'
YX#ifndef lint
YXstatic char *RCSid = "$Header: /src/common/usc/bin/qterm/RCS/qterm.c,v 5.4 1991/03/21 02:09:40 mcooper Exp $";
YX#endif
YX
YX/*
YX * Copyright (c) 1990 Michael A. Cooper.
YX * This software may be freely distributed provided it is not sold for 
YX * profit and the author is credited appropriately.
YX */
YX
YX/*
YX *------------------------------------------------------------------
YX *
YX * $Source: /src/common/usc/bin/qterm/RCS/qterm.c,v $
YX * $Revision: 5.4 $
YX * $Date: 1991/03/21 02:09:40 $
YX * $State: Exp $
YX * $Author: mcooper $
YX * $Locker:  $
YX *
YX *------------------------------------------------------------------
YX *
YX * Michael A. Cooper
YX * Research and Development Group
YX * University Computing Services 
YX * University of Southern California
YX * (mcooper@usc.edu)
YX *
YX *------------------------------------------------------------------
YX *
YX * $Log: qterm.c,v $
YX * Revision 5.4  1991/03/21  02:09:40  mcooper
YX * Fix memory buffer problem with some C
YX * compilers.  (tp@vtold.vtol.fi)
YX *
YX * Revision 5.3  1991/03/16  05:36:30  mcooper
YX * Fix casting of (char) NULL problem.
YX *
YX * Revision 5.2  1991/03/12  00:46:24  mcooper
YX * Change CMASK to CHAR_CMASK to avoid conflict
YX * under AIX 3.1.
YX *
YX * Revision 5.1  1991/02/20  02:23:33  mcooper
YX * Cleanup #ifdef USG5 as part of port
YX * to UTS 2.1 (System V.3).
YX *
YX * Revision 5.0  1990/12/15  18:30:41  mcooper
YX * Version 5.
YX *
YX * Revision 4.13  90/12/15  18:14:23  mcooper
YX * Add copywrite.
YX * 
YX * Revision 4.12  90/11/13  16:00:03  mcooper
YX * Convert OptInt's to OptBool's where needed.
YX * 
YX * Revision 4.11  90/11/13  15:38:28  mcooper
YX * Make OLD_SepArg include both
YX * SepArg and StickyArg.
YX * 
YX * Revision 4.10  90/11/08  15:41:08  mcooper
YX * Make sure qt_fullname is not 0 length.
YX * 
YX * Revision 4.9  90/11/08  13:02:06  mcooper
YX * Fix bug that closes the tty when an error
YX * occurs during command line parsing.
YX * 
YX * Revision 4.8  90/11/06  13:19:40  mcooper
YX * Changed command line options to new 
YX * longer names.
YX * 
YX * Revision 4.7  90/11/05  17:09:30  mcooper
YX * Update option help messages and option names
YX * to be more mnemonic.
YX * 
YX * Revision 4.6  90/11/05  16:44:35  mcooper
YX * - Converted to use new ParseOptions() for
YX *   command line parsing.
YX * - Major de-linting.
YX * - Convert dprintf() to use varargs (if
YX *   HAS_VARARGS is defined).
YX * - Lots of misc. cleanup.
YX * 
YX * Revision 4.5  89/10/20  22:50:49  mcooper
YX * Changed code indention to current local
YX * standard of 4.  (This should also mess up
YX * everybody trying to do diff's from older versions!)
YX * 
YX * Revision 4.4  89/10/20  14:03:48  mcooper
YX * Fixed command line parsing of "-f -q".
YX * 
YX * Revision 4.3  88/06/16  19:43:46  mcooper
YX * - Added -T flag to wait until timeout when
YX *   listening for response string.  This solves
YX *   problem when the first entry in a table
YX *   doesn't have a response string with a
YX *   common ending character to look for.
YX * - Added -I flag for "intense" query mode.
YX * - Cleaned up debugging a bit.
YX * 
YX * Revision 4.2  88/06/08  15:30:53  mcooper
YX * Cleanup pass including removing
YX * extraneous debugging messages.
YX * 
YX * Revision 4.1  88/04/25  13:24:38  mcooper
YX * Added -S option to print send and recieve
YX * strings as they are sent and recieved as
YX * suggested by David W. Sanderson
YX * (dws@attunix.att.com).
YX * 
YX * Revision 4.0  88/03/08  19:30:59  mcooper
YX * Version 4.
YX * 
YX * Revision 3.7  88/03/08  19:28:32  mcooper
YX * Major rewrite.
YX * 
YX * Revision 3.6  88/03/08  15:31:35  mcooper
YX * General cleanup time.
YX * 
YX * Revision 3.5  88/03/08  13:59:39  mcooper
YX * - Catch signals and fix terminal modes.
YX * - Don't allow alarm times of 0.
YX * - Support for HP-UX machines and cleaner
YX *   listen() code from Zenon Fortuna, 
YX *   HP-UX Support, Hewlett-Packard Vienna.
YX * 
YX * Revision 3.4  87/10/07  15:16:17  mcooper
YX * - Beautify code a bit.
YX * - Add -w <N> option to set the wait time.
YX * 
YX * Revision 3.3  87/08/24  19:25:32  mcooper
YX * The following based on code from Frank Crawford 
YX * <frank@teti.qhtours.OZ>:
YX * - Use $TERM as output string when the terminal
YX *   type is not known instead of "dumb".
YX * - Regular Expressions are now supported.  RE are
YX *   started with a leading `\'.
YX * - Octal values may now be used in send/recieve strings.
YX * 
YX * Revision 3.1  87/08/03  15:21:07  mcooper
YX * As pointed out by Scott H. Robinson <shr@cetus.ece.cmu.edu>,
YX * the -F switch does work.  Problem was that it never read
YX * in the ~/.qterm file.
YX * 
YX * Revision 3.0  87/06/30  19:07:59  mcooper
YX * Release of version 3.
YX * 
YX * Revision 2.4  87/04/29  19:28:35  mcooper
YX * In readtabfile() we now do special
YX * things when opening "file" fails
YX * depending on the bequiet flag.
YX * 
YX * Revision 2.3  87/04/29  13:11:37  mcooper
YX * - No more "internal" table.  The master
YX *   table is read from a file (TABFILE).
YX *   This makes ~/.qterm stuff much cleaner.
YX * - Error handling for qtermtab files is
YX *   much more informative now.
YX * - More things I can't remember.
YX * 
YX * Revision 2.2  87/03/05  21:01:28  mcooper
YX * Fixed system V compiler problem.
YX * 
YX * Revision 2.1  87/03/01  19:43:22  mcooper
YX * Be more intelligent about the size of 
YX * the default terminal table.
YX * 
YX * Revision 2.0  87/03/01  19:20:00  mcooper
YX * General cleanup.
YX * 
YX *------------------------------------------------------------------
YX */
YX
YX
YX/*
YX * qterm - Query Terminal
YX *
YX * qterm is used to query a terminal to determine the name of the terminal.
YX * This is done by sending a fairly universal string "\33Z" to the terminal,
YX * reading in a response, and comparing it against a master table of responses
YX * and names.  The "name" printed to standard output should be one found in
YX * the termcap(5) database.
YX *
YX * Putting a line in your ".login" file such as:
YX *
YX *	setenv TERM `qterm`
YX *
YX * or the following lines in your ".profile" file:
YX *
YX *	TERM=`qterm`
YX *	export TERM
YX *
YX * will set your terminal type automagically.
YX * 
YX * If you add a terminal to the master table, please also send me a copy
YX * so that I may put it into my version.
YX *
YX * Michael Cooper
YX * Internet: 	mcooper@usc.edu
YX * UUCP: 	...!rutgers!usc!mcooper
YX * BITNET:	mcooper@gamera
YX */
YX
YX#include <stdio.h>
YX#include <ctype.h>
YX#include <pwd.h>
YX#include <signal.h>
YX#include <sys/ioctl.h>
YX#include <setjmp.h>
YX#ifdef USG5
YX# include <termio.h>
YX#else /*USG5*/
YX# include <sys/file.h>
YX# include <sgtty.h>
YX#endif /*USG5*/
YX#include "qterm.h"
YX#include "options.h"
YX#ifdef HAS_VARARGS
YX#include <varargs.h>
YX#endif /*HAS_VARARGS*/
YX
YX#ifdef USG5
YXstruct termio _ntty, _otty;
YX#else
YXstruct sgttyb _tty;
YX#endif
YXint _tty_ch = 2;
YXchar recvbuf[SIZE];
YXchar *progname;
YXchar *termfile = NULL;
YX
YXint debug = FALSE;		/* Debug mode */
YXint use_alt_str = FALSE;	/* Alternate string */
YXint towait = FALSE;		/* Time out wait flag */
YXint always_send = FALSE;	/* Intense query mode */
YXint longname = FALSE;		/* Print long terminal name */
YXint sent_chars = FALSE;		/* Print strings sent from the terminal */
YXint watch_chars = FALSE;	/* Watch strings as they are sent and recv. */
YXint quiet = FALSE;		/* Quiet mode */
YXint do_usrtabfile = FALSE;	/* Use user's own .qtermtab file */
YXint do_systabfile = TRUE;	/* Use the system's qterm tab file */
YXint almwait = WAIT;		/* Wait (timeout) interval */
YX
YX/*
YX * Old options should not be visable in help and usage messages.
YX */
YX#ifdef OPT_COMPAT
YX#define OLD_NoArg	NoArg|ArgHidden
YX#define OLD_SepArg	SepArg|StickyArg|ArgHidden
YX#define fFLAG 		"-f"
YX#define FFLAG		"-F"
YX#endif
YX
YX/*
YX * Command line options table.
YX */
YXOptionDescRec opts[] = {
YX#ifdef OPT_COMPAT
YX    {"-a", 	OLD_NoArg,	OptInt,	(caddr_t) &use_alt_str,		"1",
YX	 (char *)NULL,	"Use alternate query string"},
YX    {"-s",	OLD_NoArg,	OptInt,	(caddr_t) &sent_chars,		"1",
YX	 (char *)NULL,	"Display the characters the terminal sent"},
YX    {"-t", ArgHidden|OLD_NoArg,	OptInt,	(caddr_t) &sent_chars,		"1",
YX	 (char *)NULL,	"Display the characters the terminal sent"},
YX    {"-I",	OLD_NoArg,	OptInt,	(caddr_t) &always_send,		"1",
YX	 (char *)NULL,	"Always send the terminal query string"},
YX    {"-T",	OLD_NoArg,	OptInt,	(caddr_t) &towait,		"1",
YX	 (char *)NULL,	"Enable time out wait"},
YX    {"-S",	OLD_NoArg,	OptInt,	(caddr_t) &watch_chars,		"1",
YX	 (char *)NULL,	"Print strings as they are sent and received"},
YX    {"-q",	OLD_NoArg,	OptInt,	(caddr_t) &quiet,		"1",
YX	 (char *)NULL,	"Enable quite mode"},
YX    {"-f",	OLD_SepArg,	OptStr,	(caddr_t) &termfile,  fFLAG,
YX	 "<tabfile>",  "Try <tabfile>, then ~/.qtermtab, then system tabfile"},
YX    {"-F",	OLD_SepArg,	OptStr,	(caddr_t) &termfile,  FFLAG,
YX	 "<tabfile>",	"Try <tabfile>, then ~/.qtermtab"},
YX    {"-l",	OLD_NoArg,	OptInt,	(caddr_t) &longname,		"1",
YX	 (char *)NULL,	"Output only the long (verbose) terminal name"},
YX    {"-d", 	OLD_NoArg,	OptInt,	(caddr_t) &debug,		"1",
YX	 (char *)NULL,	"Enable debug mode"},
YX    {"-w",	OLD_SepArg,	OptInt,	(caddr_t) &almwait,	    __ NULL,
YX	 "<interval>",	"Wait (timeout) period (in seconds)"},
YX#endif /*OPT_COMPAT*/
YX    {"+alt", 	NoArg,		OptBool, (caddr_t) &use_alt_str,	"1",
YX	 (char *)NULL,	"Use alternate query string"},
YX    {"-alt", 	NoArg,		OptBool, (caddr_t) &use_alt_str,	"0",
YX	 (char *)NULL,	"Don't use alternate query string"},
YX    {"+always",	NoArg,		OptBool, (caddr_t) &always_send,	"1",
YX	 (char *)NULL,	"Always send the terminal query string"},
YX    {"-always",	NoArg,		OptBool, (caddr_t) &always_send,	"0",
YX	 (char *)NULL,	"Don't always send the terminal query string"},
YX    {"-file",	SepArg,		OptStr,	(caddr_t) &termfile,  	    __ NULL,
YX	 "<tabfile>",   "Use <tabfile> to query terminal"},
YX    {"+longname",NoArg,		OptBool, (caddr_t) &longname,		"1",
YX	 (char *)NULL,	"Output only the long (verbose) terminal name"},
YX    {"-longname",NoArg,		OptBool, (caddr_t) &longname,		"0",
YX	 (char *)NULL,	"Don't output the long (verbose) terminal name"},
YX    {"+quiet",	NoArg,		OptBool, (caddr_t) &quiet,		"1",
YX	 (char *)NULL,	"Enable quiet mode"},
YX    {"-quiet",	NoArg,		OptBool, (caddr_t) &quiet,		"0",
YX	 (char *)NULL,	"Disable quiet mode"},
YX    {"+sent",	NoArg,		OptBool, (caddr_t) &sent_chars,		"1",
YX	 (char *)NULL,	"Display the characters the terminal sent"},
YX    {"-sent",	NoArg,		OptBool, (caddr_t) &sent_chars,		"0",
YX	 (char *)NULL,	"Don't display the characters the terminal sent"},
YX    {"+timeout",NoArg,		OptBool, (caddr_t) &towait,		"1",
YX	 (char *)NULL,	"Enable time out wait"},
YX    {"-timeout",NoArg,		OptBool, (caddr_t) &towait,		"0",
YX	 (char *)NULL,	"Disable time out wait"},
YX    {"+usrtab",	NoArg,		OptBool, (caddr_t) &do_usrtabfile,	"1",
YX	 (char *)NULL,	"Enable using ~/.qtermtab"},
YX    {"-usrtab",	NoArg,		OptBool, (caddr_t) &do_usrtabfile,	"0",
YX	 (char *)NULL,	"Disable using ~/.qtermtab"},
YX    {"-wait",	SepArg,		OptInt,	(caddr_t) &almwait,	    __ NULL,
YX	 "<interval>",	"Wait (timeout) period (in seconds)"},
YX    {"+watch",	NoArg,		OptBool, (caddr_t) &watch_chars,	"1",
YX	 (char *)NULL,	"Watch the characters sent and recieved"},
YX    {"-watch",	NoArg,		OptBool, (caddr_t) &watch_chars,	"0",
YX	 (char *)NULL,	"Don't watch the characters sent and recieved"},
YX    {"+systab",	NoArg,		OptBool, (caddr_t) &do_usrtabfile,	"1",
YX	 (char *)NULL,	"Enable using system qtermtab file"},
YX    {"-systab",	NoArg,		OptBool, (caddr_t) &do_systabfile,	"0",
YX	 (char *)NULL,	"Disable using system qtermtab file"},
YX    {"-debug", ArgHidden|NoArg,	OptInt,	(caddr_t) &debug,		"1",
YX	 (char *)NULL,	"Enable debug mode"},
YX};
YX
YXFILE *fopen();
YXchar *decode();
YXchar *getenv();
YXchar *malloc();
YXchar *re_comp();
YXchar *strcat();
YXchar *xmalloc();
YXint alarm();
YXint found = FALSE;
YXint modes_set = FALSE;
YXjmp_buf env;
YXstruct termtable *compare();
YXstruct passwd *getpwuid();
YXvoid catch();
YXvoid done();
YXvoid dprintf();
YXvoid exit();
YXvoid myperror();
YXvoid mktable();
YXvoid notrecognized();
YXvoid proctab();
YXvoid wakeup();
YX#ifdef USG5
YXchar *regcmp();
YX#endif /* USG5 */
YX
YXmain(argc, argv)
YX     int argc;
YX     char **argv;
YX{
YX    config(argc, argv);
YX    setmodes();
YX    mktable();
YX    proctab((struct termtable *)NULL);
YX    resetmodes();
YX    
YX    if (!found) {
YX	notrecognized();
YX    }
YX
YX    exit(0);
YX}
YX
YX/*
YX * Config() - Perform configuration operations.
YX */
YXconfig(argc, argv)
YX     int argc;
YX     char **argv;
YX{
YX    progname = argv[0];
YX
YX    /*
YX     * Parse command line args
YX     */
YX    if (ParseOptions(opts, Num_Opts(opts), argc, argv) < 0) {
YX	done(1);
YX	/*NOTREACHED*/
YX    }
YX
YX    /*
YX     * Check results of command line parsing and perform any
YX     * needed post processing.
YX     */
YX
YX    if (longname)
YX	quiet = TRUE;
YX
YX    if (almwait == 0) {
YX	(void) fprintf(stderr, 
YX		      "%s: Alarm (wait) time must be greater than 0.\n",
YX		       progname);
YX	done(1);
YX	/*NOTREACHED*/
YX    }
YX
YX#ifdef OPT_COMPAT
YX    /*
YX     * Kludgy stuff to be backwards compatable for command line options.
YX     */
YX    if (termfile) {
YX	if (strcmp(termfile, fFLAG) == 0) {
YX	    do_usrtabfile = TRUE;
YX	    do_systabfile = TRUE;
YX	    termfile = NULL;
YX	} else if (strcmp(termfile, FFLAG) == 0) {
YX	    do_usrtabfile = TRUE;
YX	    do_systabfile = FALSE;
YX	    termfile = NULL;
YX	}
YX    }
YX#endif /*OPT_COMPAT*/
YX
YX    dprintf("[ %s debug mode enabled ]\n\n", progname);
YX}
YX
YX/*
YX * Set signal catches and terminal modes
YX */
YXsetmodes()
YX{
YX    if (!isatty(0)) {
YX	(void) fprintf(stderr, "%s: Not a tty.\n", progname);
YX	done(0);
YX	/*NOTREACHED*/
YX    }
YX    
YX    /*
YX     * Set output buffers
YX     */
YX    setbuf(stdout, (char *)0);
YX    if (debug)
YX	setbuf(stderr, (char *)0);
YX    
YX    /*
YX     * Cleanup terminal modes & such if we are killed
YX     */
YX    (void) signal(SIGINT, catch);
YX    (void) signal(SIGHUP, catch);
YX    (void) signal(SIGTERM, catch);
YX    
YX    /*
YX     * Set terminal modes
YX     */
YX#ifdef USG5
YX    if (ioctl(_tty_ch, TCGETA, &_otty) < 0)
YX#else
YX    if (ioctl(_tty_ch, TIOCGETP, &_tty) < 0)
YX#endif /* USG5 */
YX    {
YX	myperror("gtty");
YX	done(1);
YX	/*NOTREACHED*/
YX    }
YX#ifdef USG5
YX    _ntty = _otty;
YX#endif /* USG5 */
YX
YX    if (crmode() < 0) {
YX	myperror("crmode");
YX	done(1);
YX	/*NOTREACHED*/
YX    }
YX    
YX    if (noecho() < 0) {
YX	myperror("noecho");
YX	done(1);
YX	/*NOTREACHED*/
YX    }
YX    modes_set = TRUE;
YX}
YX
YX/*
YX * Reset terminal modes
YX */
YXresetmodes()
YX{
YX    if (modes_set) {
YX	(void) nocrmode();
YX	(void) echo();
YX    }
YX}
YX
YX/*
YX * Print info about terminal structure t.
YX */
YXprinfo(t, what)
YX     struct termtable *t;
YX     int what;
YX{
YX    int len = 0;
YX    int st = FALSE;
YX    
YX    if (t && t->qt_termname && (recvbuf[0] != (char) NULL)) {
YX	if (debug || sent_chars) {
YX	    len = strlen(recvbuf);
YX	    (void) fprintf(stderr, "%s received %d character%s:", 
YX			   progname, len, (len == 1) ? "" : "s");
YX	    (void) fprintf(stderr, " %s\n", decode(recvbuf));
YX	}
YX	
YX	if (!quiet) {
YX	    (void) fprintf(stderr, "Terminal recognized as %s", 
YX			   t->qt_termname);
YX	    if (t->qt_fullname && t->qt_fullname[0])
YX		(void) fprintf(stderr, " (%s)\n", t->qt_fullname);
YX	    else
YX		(void) fprintf(stderr, "\n");
YX	}
YX	
YX	if (longname) {
YX	    if (t->qt_fullname && t->qt_fullname[0])
YX		(void) printf("%s\n", t->qt_fullname);
YX	    else
YX		(void) fprintf(stderr, "%s: No full terminal name for %s.\n",
YX			       progname, t->qt_termname);
YX	} else {
YX	    (void) printf("%s\n", t->qt_termname);
YX	}
YX	
YX	found = TRUE;
YX	done(0);
YX	/*NOTREACHED*/
YX    } else {
YX	found = FALSE;
YX	
YX	if (what) {
YX	    notrecognized();
YX	    done(1);
YX	    /*NOTREACHED*/
YX	}
YX    }
YX    
YX    return(st);
YX}
YX
YX/*
YX * compare - actually compare what we received against the table.
YX */
YXstruct termtable *compare(str)
YX     char *str;
YX{
YX#ifdef USG5
YX    register char *reexp;
YX#endif /* USG5 */
YX    register struct termtable *t;
YX    char buf[BUFSIZ];
YX
YX    dprintf("compare %s\n", (str && str[0]) ? decode(str) : "nothing");
YX    (void) alarm((unsigned)0);
YX    
YX    if (strlen(str) == 0)
YX	return(NULL);
YX    
YX    for (t = termtab; t != NULL; t = t->nxt) {
YX	dprintf("  with %s ", decode(t->qt_recvstr));
YX	(void) sprintf(buf, "^%s$", t->qt_recvstr);
YX	
YX#ifdef USG5
YX	if ((reexp = regcmp(buf, NULL)) == NULL) {
YX#else
YX	if (re_comp((char *)buf) != NULL) {
YX#endif /* USG5 */
YX	    (void) fprintf(stderr, "%s: bad regular expression: \"%s\"\n", 
YX			   progname, t->qt_recvstr);
YX	    done(1);
YX	    /*NOTREACHED*/
YX	}
YX
YX#ifdef USG5
YX	if (regex(reexp, str) != NULL) {
YX#else
YX	if (re_exec(str) == 1) {
YX#endif /* USG5 */
YX	    found = TRUE;
YX	    dprintf("\tOK\n");
YX	    return(t);
YX	}
YX
YX	dprintf("\tNOPE\n");
YX#ifdef USG5
YX	(void) free(reexp);
YX#endif /* USG5 */
YX    }
YX    found = FALSE;
YX
YX    return(NULL);
YX}
YX
YX/*
YX * getch - read in a character at a time.
YX */
YXgetch()
YX{
YX    char c;
YX    
YX    (void) read(0, &c, 1);
YX    
YX    return(c & CHAR_MASK);
YX}
YX
YX/*
YX * decode - print str in a readable fashion
YX */
YXchar *decode(str)
YX     char *str;
YX{
YX    register int len;
YX    static char buf[BUFSIZ];
YX    char tmp[10];
YX    
YX    if (!str)
YX      return("(null)");
YX    
YX    (void) strcpy(buf, "");
YX    while (*str) {
YX	if (*str == ESC) {
YX	    (void) strcat(buf, "<esc> ");
YX	} else if ((*str <= 33) || (*str >= 127)) {
YX	    (void) sprintf(tmp,"\\%#o ", (unsigned) *str);
YX	    (void) strcat(buf, tmp);
YX	} else {
YX	    (void) sprintf(tmp,"%c ", *str);
YX	    (void) strcat(buf, tmp);
YX	}
YX	++str;
YX    }
YX    
YX    len = strlen(buf);
YX    if (len && buf[len - 1] == ' ') {
YX	buf[len - 1] = (char) NULL;
YX    }
YX    
YX    return(buf);
YX}
YX
YX/*
YX * Make a termtab table
YX */
YXvoid mktable()
YX{
YX    char file[BUFSIZ];
YX    struct passwd *pwd;
YX    char *home;
YX
YX    dprintf("[ initilizing term table... ]\n");
YX    
YX    if (termfile != NULL) {
YX	(void) readtabfile(termfile, FALSE);
YX    }
YX
YX    if (do_usrtabfile) {
YX	/*
YX	 * Try to read the user's own table
YX	 */
YX	if ((home = getenv("HOME")) == NULL) {
YX	    if ((pwd = getpwuid(getuid())) == NULL) {
YX		(void) fprintf(stderr, 
YX			       "%s: Cannot find user info for uid %d.\n",
YX			       progname, getuid());
YX		done(1);
YX		/*NOTREACHED*/
YX	    }
YX	    home = pwd->pw_dir;
YX	}
YX
YX	(void) sprintf(file, "%s/%s", home, USRFILE);
YX	if (readtabfile(file, TRUE) < 0) {
YX	    (void) sprintf(file, "%s/%s", home, OLDUSRFILE);
YX	    (void) readtabfile(file, TRUE);
YX	}
YX    }
YX    
YX    if (do_systabfile)
YX	(void) readtabfile(TABFILE, FALSE);
YX    
YX    dprintf("[ mktable done ]\n");
YX}
YX
YXint readtabfile(file, bequiet)
YX     char *file;
YX     int bequiet;
YX{
YX    static int line = 0;
YX    char lbuf[4][BUFSIZ];
YX    char buf[BUFSIZ];
YX    FILE *fd;
YX    char *p, *fixctl();
YX    char *errmsg = NULL;
YX    struct termtable *t;
YX    
YX    if ((fd = fopen(file, "r")) == NULL) {
YX	if (bequiet) {
YX	    dprintf("[ tab file '%s' can not read ]\n", file);
YX	    return(-1);
YX	}
YX	myperror(file);
YX	done(1);
YX	/*NOTREACHED*/
YX    }
YX
YX    dprintf("[ Read tab file '%s' ]\n", file);
YX
YX    line = 0;
YX    while (fgets(buf, sizeof(buf), fd)) {
YX	++line;
YX	
YX	if (buf[0] == '#' || buf[0] == '\n')
YX	    continue;
YX	
YX	lbuf[0][0] = lbuf[1][0] = lbuf[2][0] = lbuf[3][0] = (char) NULL;
YX	
YX	(void) sscanf(buf, "%s%s%s\t%[^\n]", 
YX		      lbuf[0], lbuf[1], lbuf[2], lbuf[3]);
YX	
YX	if (lbuf[0][0] == (char) NULL)
YX	    continue;
YX	
YX	if (lbuf[1][0] == (char) NULL)
YX	    errmsg = "receive string";
YX	
YX	if (lbuf[2][0] == (char) NULL)
YX	    errmsg = "terminal name";
YX	
YX	if (errmsg) {
YX	    (void) fprintf(stderr, "%s: Line %d of %s: Error parsing %s.\n", 
YX			   progname, line, file, errmsg);
YX	    done(1);
YX	    /*NOTREACHED*/
YX	}
YX	
YX	t = (struct termtable *) xmalloc(sizeof(struct termtable));
YX	
YX	if (use_alt_str)
YX	    p = fixctl(ALTSEND, 0);
YX	else
YX	    p = fixctl(lbuf[0], 0);
YX	
YX	t->qt_sendstr = (char *) xmalloc(strlen(p)+1);
YX	(void) strcpy(t->qt_sendstr, p);
YX	
YX	p = fixctl(lbuf[1], 1);
YX	t->qt_recvstr = (char *) xmalloc(strlen(p)+1);
YX	(void) strcpy(t->qt_recvstr, p);
YX	
YX	t->qt_termname = (char *) xmalloc(strlen(lbuf[2])+1);
YX	(void) strcpy(t->qt_termname, lbuf[2]);
YX	
YX	t->qt_fullname = (char *) xmalloc(strlen(lbuf[3])+1);
YX	(void) strcpy(t->qt_fullname, lbuf[3]);
YX	
YX	dprintf("\n  Send String = %s\n", decode(t->qt_sendstr));
YX	dprintf("Expect String = %s\n", decode(t->qt_recvstr));
YX	dprintf("     Terminal = '%s'\n", t->qt_termname);
YX	dprintf("    Full Name = '%s'\n", t->qt_fullname);
YX	
YX	(void) addterm(t);
YX    }
YX    
YX    return(0);
YX}
YX
YX/*
YX * Add termtab (n) entry to main termtab.
YX */
YXint addterm(n)
YX     struct termtable *n;
YX{
YX    register struct termtable *t;
YX    
YX    if (!n)
YX      return(-1);
YX    
YX    n->nxt = NULL;
YX    
YX    if (termtab == NULL) {
YX	termtab = n;
YX    } else {
YX	t = termtab;
YX	while(t && t->nxt)
YX	  t = t->nxt;
YX	t->nxt = n;
YX    }
YX    
YX    return(0);
YX}
YX
YX/*
YX * Listen for a response.
YX */
YXvoid qterm_listen(q)
YX     struct termtable *q;
YX{
YX    static int i, len;
YX    register char c;
YX    char end;
YX    
YX    (void) alarm((unsigned)0);
YX    (void) strcpy(recvbuf, "");
YX    i = 0;
YX    
YX    len = strlen(q->qt_recvstr);
YX    
YX    if (len) {
YX	end = q->qt_recvstr[len - 1];
YX    } else {
YX	end = 'c'; /* Fairly standard ANSI default */
YX    }
YX    
YX    dprintf("\nlisten for %s\t [ len = %d, end = `%c' ]\n", 
YX	    decode(q->qt_recvstr), len, end);
YX    
YX    /*
YX     * If we don't get an initial character, bounce out
YX     * of here and finish with done(0).
YX     */
YX    if (setjmp(env)) {
YX	if (found) {
YX	    done(0);
YX	    /*NOTREACHED*/
YX	}
YX	(void) fflush(stdin);
YX	proctab(q->nxt);
YX    } else {
YX	(void) signal(SIGALRM, wakeup);
YX	(void) alarm((unsigned)almwait);
YX	recvbuf[0] = getch();
YX	(void) alarm((unsigned)0);
YX    }
YX    
YX    /*
YX     * Read in remaining response.  Loop until ending character
YX     * is received or until alarm goes off.  If towait is set,
YX     * then let alarm go off.
YX     */
YX    for (i = 1, c = -1; (!towait && (c != end)) || towait; ) {
YX	if (setjmp(env))  {
YX	    recvbuf[i] = (char) NULL;
YX	    return;
YX	} else {
YX	    (void) signal(SIGALRM, wakeup);
YX	    (void) alarm((unsigned)almwait);
YX	    c = getch();
YX	    (void) alarm((unsigned)0);
YX	}
YX	recvbuf[i++] = c;
YX    }
YX    recvbuf[i] = (char) NULL;
YX    
YX    dprintf("listen done.  read %d chars.\n\n", i);
YX}
YX
YX/*
YX * Print a message since we didn't recognize this terminal.
YX */
YXvoid notrecognized()
YX{
YX    char *envterm;
YX    
YX    if ((envterm = getenv("TERM")) == NULL)
YX	envterm = "dumb";
YX    
YX    if (!quiet)
YX	(void) fprintf(stderr, 
YX		       "Terminal NOT recognized - defaults to \"%s\".\n",
YX		       envterm);
YX    
YX    puts(envterm);
YX}
YX
YX/*
YX * Process entries in the termtable.
YX */
YXvoid proctab(t)
YX     struct termtable *t;
YX{
YX    int st = FALSE;
YX    static int firsttime = TRUE;
YX    static struct termtable *lastt;
YX    
YX    dprintf("\n[ Processing entries ] \n");
YX    
YX    if (firsttime) {
YX	t = termtab;
YX	lastt = NULL;
YX    }
YX    
YX    while ((!found || do_usrtabfile) && t && t->qt_sendstr && !st) {
YX	/*
YX	 * If this is our first time or the sendstr is the same as
YX	 * last time, don't send it again.
YX	 */
YX	if (always_send || firsttime || lastt == NULL || 
YX	    strcmp(t->qt_sendstr, lastt->qt_sendstr) != 0) {
YX	    
YX	    if (firsttime)
YX		firsttime = FALSE;
YX	    
YX	    if (watch_chars)
YX		(void) printf("Send: %s\n", decode(t->qt_sendstr));
YX
YX	    (void) fflush(stdin);
YX	    (void) fprintf(stderr, "%s", t->qt_sendstr);
YX	    (void) fflush(stderr);
YX	    
YX	    lastt = t;
YX	    (void) qterm_listen(t);
YX	    
YX	    if (watch_chars)
YX		(void) printf("\tRead: %s\n", decode(recvbuf));
YX	}
YX	
YX	st = prinfo(compare(recvbuf), FALSE);
YX	
YX	lastt = t;
YX	t = t->nxt;
YX    }
YX    
YX    if (!found)
YX	notrecognized();
YX    
YX    done(0);
YX    /*NOTREACHED*/
YX}
YX
YXchar *fixctl(str, rex)
YX     char *str;
YX     int rex;
YX{
YX    register int i;
YX    static char buf[BUFSIZ];
YX    
YX    for (i = 0; str && *str; ) {
YX	switch (*str) {
YX	    
YX	  case '\\':
YX	    if (isdigit(*++str)) {
YX		buf[i] = 0;
YX		while (isdigit(*str))
YX		    buf[i] = (char) (((int)buf[i] * 8) + 
YX				     (int)*str++ - (int) '0');
YX		i++;
YX	    } else
YX		buf[i++] = *str++;
YX	    continue;
YX	    
YX	  case '^':
YX	    switch (*++str) {
YX	      case '?':
YX		buf[i++] = '\177';
YX		break;
YX	      default:
YX		buf[i++] = *str & 037;
YX		break;
YX	    }
YX	    break;
YX	    
YX	    /* Special R.E. symbols */
YX	  case '[':
YX	  case '*':
YX	  case '.':
YX	  case '$':
YX	  case '{':
YX	  case '(':
YX	    if (rex)
YX	      buf[i++] = '\\';
YX	    
YX	  default:
YX	    buf[i++] = *str;
YX	}
YX	*++str;
YX    }
YX    
YX    buf[i] = (char) NULL;
YX    
YX    return(buf);
YX}
YX
YX/*
YX * xmalloc - Do a malloc with error checking.
YX */
YXchar *xmalloc(size)
YX     int size;
YX{
YX    char *p;
YX    
YX    if ((p = malloc((unsigned) size)) == NULL) {
YX	myperror("malloc");
YX	done(1);
YX	/*NOTREACHED*/
YX    }
YX    
YX    return(p);
YX}
YX
YX#ifdef HAS_VARARGS
YXvoid dprintf(va_alist)
YX     va_dcl
YX{
YX    va_list args;
YX    char *fmt;
YX
YX    if (!debug)
YX	return;
YX
YX    va_start(args);
YX    fmt = (char *) va_arg(args, char *);
YX    (void) vprintf(fmt, args);
YX    va_end(args());
YX    (void) fflush(stdout);
YX}
YX
YX#else /*HAS_VARARGS*/
YX
YXvoid dprintf(fmt, a1, a2, a3, a4, a5, a6)
YX     char *fmt;
YX{
YX    if (!debug)
YX	return;
YX
YX    (void) printf(fmt, a1, a2, a3, a4, a5, a6);
YX    (void) fflush(stdout);
YX}
YX#endif /*HAS_VARARGS*/
YX
YX/*
YX * Catch kill signals and cleanup.
YX */
YXvoid catch()
YX{
YX    done(2);
YX    /*NOTREACHED*/
YX}
YX
YXvoid wakeup()
YX{
YX    dprintf("wakeup called\n");
YX    longjmp(env, 1);
YX}
YX
YXvoid myperror(msg)
YX     char *msg;
YX{
YX    (void) fprintf(stderr, "%s: ", progname);
YX    perror(msg);
YX}
YX
YX/*
YX * Reset terminal and exit with status s.
YX */
YXvoid done(s)
YX     int s;
YX{
YX    resetmodes();
YX    exit(s);
YX}
YSHAR_EOF
Ychmod 644 'qterm.c'
Yfi
Yif test -f 'options.c'
Ythen
Y	echo shar: "will not over-write existing file 'options.c'"
Yelse
Ysed 's/^X//' << \SHAR_EOF > 'options.c'
YX/*
YX * Copyright (c) 1990 Michael A. Cooper.
YX * This software may be freely distributed provided it is not sold for 
YX * profit and the author is credited appropriately.
YX */
YX
YX#ifndef lint
YXstatic char *RCSid = "$Header: /am/sol/src/common/usc/lib/libgen/RCS/options.c,v 1.13 90/12/15 18:13:28 mcooper Exp $";
YX#endif
YX
YX/*
YX * $Log:	options.c,v $
YX * Revision 1.13  90/12/15  18:13:28  mcooper
YX * Add copywrite notice.
YX * 
YX * Revision 1.12  90/12/15  17:51:46  mcooper
YX * Add #ifdef HAS_VARARGS around include for <varargs>.
YX * 
YX * Revision 1.11  90/11/13  16:39:28  mcooper
YX * Add #ifdef HAS_VARARGS for systems without
YX * varargs.
YX * 
YX * Revision 1.10  90/11/13  15:28:01  mcooper
YX * - Add OptBool cvtarg routine.
YX * - Print default values in HelpOptions() 
YX *   when appropriate.
YX * 
YX * Revision 1.9  90/11/13  15:19:00  mcooper
YX * Added supported for options being both
YX * SepArg and StickyArg.
YX * 
YX * Revision 1.8  90/10/30  21:02:31  mcooper
YX * Need to exit() if -help is specified.
YX * 
YX * Revision 1.7  90/10/30  20:24:33  mcooper
YX * Fixed bug in UsageString().
YX * 
YX * Revision 1.6  90/10/30  19:53:05  mcooper
YX * Cleaned up some NeXT cc and lint stuff.
YX * 
YX * Revision 1.5  90/10/30  19:45:31  mcooper
YX * Remove unneeded paramter to HelpOptions().
YX * 
YX * Revision 1.4  90/10/29  14:47:42  mcooper
YX * Added real function UsageString() to
YX * handle formating usage option strings.
YX * 
YX * Revision 1.3  90/10/29  14:17:00  mcooper
YX * Allow options to be abbreviated 
YX * (for all non StickArg options).
YX * 
YX * Revision 1.2  90/10/26  15:56:11  mcooper
YX * - Fix bug in SepArg code that ate arguments.
YX * - Cleanup help message.
YX * - Add ArgHidden code.
YX * 
YX * Revision 1.1  90/10/26  14:42:51  mcooper
YX * Initial revision
YX * 
YX */
YX
YX/*
YX * Functions to parse options.
YX */
YX
YX#include "options.h"
YX#ifdef HAS_VARARGS
YX#include <varargs.h>
YX#endif
YX
YXchar *OptionChars = "-+";	/* Default option switching characters */
YXchar *ProgramName = NULL;	/* Name of this program */
YXchar *UsageString();
YXstatic int isopt();
YXstatic int suppress_help_msg = 0;
YXchar *strcat();
YX
YX/*
YX * ParseOptions - Parse options found in argv using "options".
YX *		  Returns the number of options parsed if there
YX *		  were no errors.  Returns -1 if an error occurs.
YX */
YXint ParseOptions(options, num_options, argc, argv)
YX     OptionDescRec *options;
YX     int num_options;
YX     int argc;
YX     char **argv;
YX{
YX    OptionDescRec *opt;
YX    register int x;
YX    char *p;
YX
YX    if (ProgramName == NULL)
YX	ProgramName = argv[0];
YX
YX#ifdef OPTION_DEBUG
YX    (void) printf("Option list is:\n");
YX    for (x = 0; x < num_options; ++x) {
YX	opt = &options[x];
YX	(void) printf("%s\n", opt->option);
YX    }
YX
YX    (void) printf("Arguments (%d):", argc);
YX    for (x = 0; x < argc; ++x) {
YX	(void) printf(" %s", argv[x]);
YX    }
YX    (void) printf("\n");
YX#endif /* OPTION_DEBUG */
YX
YX    for (x = 1; x < argc; ++x) {
YX	if (strcmp(HELPSTR, argv[x]) == 0) {
YX	    HelpOptions(options, num_options, (char **)NULL);
YX	    exit(0);
YX	}
YX
YX	opt = FindOption(options, num_options, argv[x]);
YX	if (opt == NULL) {
YX	    if (isopt(argv[x])) { /* this was suppose to be an option */
YX		UsageOptions(options, num_options, argv[x]);
YX		return(-1);
YX	    } else { /* must be end of options */
YX		break;
YX	    }
YX	}
YX
YX	if (opt->flags & NoArg) {
YX	    if (!(*opt->cvtarg)(opt, opt->value, FALSE)) {
YX		UsageOptions(options, num_options, opt->option);
YX		return(-1);
YX	    }
YX	} else if (opt->flags & IsArg) {
YX	    if (!(*opt->cvtarg)(opt, opt->option, FALSE)) {
YX		UsageOptions(options, num_options, opt->option);
YX		return(-1);
YX	    }
YX	} else if ((opt->flags & StickyArg) && (opt->flags & SepArg)) {
YX	    p = (char *) &argv[x][strlen(opt->option)];
YX	    if (!*p) {		/*** SepArg ***/
YX		if (x + 1 >= argc || isopt(argv[x+1])) {
YX		    if (opt->value == (caddr_t) NULL) {
YX			UserError("%s: Option requires an argument.", argv[x]);
YX			UsageOptions(options, num_options, opt->option);
YX			return(-1);
YX		    }
YX		    p = opt->value;
YX		} else {
YX		    p = argv[++x];
YX		}
YX	    }
YX	    if (!(*opt->cvtarg)(opt, p, TRUE)) {
YX		UsageOptions(options, num_options, opt->option);
YX		return(-1);
YX	    }
YX	} else if (opt->flags & StickyArg) {
YX	    p = (char *) &argv[x][strlen(opt->option)];
YX	    if (!*p) {
YX		if (opt->value == (caddr_t) NULL) {
YX		    UserError("%s: Option requires an argument.", argv[x]);
YX		    UsageOptions(options, num_options, opt->option);
YX		    return(-1);
YX		} else {
YX		    p = opt->value;
YX		}
YX	    }
YX	    if (!(*opt->cvtarg)(opt, p, TRUE)) {
YX		UsageOptions(options, num_options, opt->option);
YX		return(-1);
YX	    }
YX	} else if (opt->flags & SepArg) {
YX	    if (x + 1 >= argc || isopt(argv[x+1])) {
YX		if (opt->value == (caddr_t) NULL) {
YX		    UserError("%s: Option requires an argument.", argv[x]);
YX		    UsageOptions(options, num_options, opt->option);
YX		    return(-1);
YX		} else {
YX		    p = opt->value;
YX		}
YX	    } else {
YX		p = argv[++x];
YX	    }
YX	    if (!(*opt->cvtarg)(opt, p, TRUE)) {
YX		UsageOptions(options, num_options, opt->option);
YX		return(-1);
YX	    }
YX	} else if (opt->flags & SkipArg) {
YX	    x += 2;
YX	} else if (opt->flags & SkipLine) {
YX	    return(x);
YX	} else if (opt->flags & SkipNArgs) {
YX	    if (opt->value) {
YX		x += atoi(opt->value);
YX	    } else {
YX		UserError("Internal Error: No 'value' set for SkipNArgs.");
YX		return(-1);
YX	    }
YX	} else {
YX	    UserError("Internal Error: Unknown argument type for option '%s'.",
YX		     opt->option);
YX	    return(-1);
YX	}
YX    }
YX
YX    return(x);
YX}
YX
YX/*
YX * FindOption - Find "option" in "options".  Returns NULL if not found.
YX */
YXOptionDescRec *FindOption(options, num_options, option)
YX     OptionDescRec *options;
YX     int num_options;
YX     char *option;
YX{
YX    OptionDescRec *opt;
YX    register int x;
YX
YX    for (x = 0; x < num_options; ++x) {
YX	opt = &options[x];
YX	if (opt->flags & StickyArg) {
YX	    if (strncmp(option, opt->option, strlen(opt->option)) == 0)
YX		return(opt);
YX	} else {
YX	    if (strncmp(option, opt->option, strlen(option)) == 0)
YX		return(opt);
YX	}
YX    }
YX
YX    return(NULL);
YX}
YX
YX/*
YX * isopt - Is "str" an option string?  Compare first char of str against
YX *	   list of option switch characters.  Returns TRUE if it is an option.
YX */
YXstatic int isopt(str)
YX     char *str;
YX{
YX    register char *p;
YX
YX    for (p = OptionChars; p && *p; *++p) {
YX	if (*str == *p) {
YX	    return(TRUE);
YX	}
YX    }
YX
YX    return(FALSE);
YX}
YX
YX/*
YX * UsageOptions - Print a usage message based on "options".
YX */
YXvoid UsageOptions(options, num_opts, badOption)
YX     OptionDescRec *options;
YX     int num_opts;
YX     char *badOption;
YX{
YX    OptionDescRec *opt;
YX    char *optstr;
YX    register int x;
YX    int col, len;
YX
YX    if (badOption) 
YX	(void) fprintf (stderr, "%s:  bad command line option \"%s\"\r\n\n",
YX			ProgramName, badOption);
YX
YX    (void) fprintf (stderr, "usage:  %s", ProgramName);
YX    col = 8 + strlen(ProgramName);
YX    for (x = 0; x < num_opts; x++) {
YX	opt = &options[x];
YX	if (opt->flags & ArgHidden)
YX	    continue;
YX	optstr = UsageString(opt);
YX	len = strlen(optstr) + 3;	/* space [ string ] */
YX	if (col + len > 79) {
YX	    (void) fprintf (stderr, "\r\n   ");  /* 3 spaces */
YX	    col = 3;
YX	}
YX	(void) fprintf (stderr, " [%s]", optstr);
YX	col += len;
YX    }
YX
YX    if (suppress_help_msg)
YX	(void) fprintf(stderr, "\r\n\n");
YX    else
YX	(void) fprintf(stderr, 
YX		       "\r\n\nType \"%s %s\" for a full description.\r\n\n",
YX		       ProgramName, HELPSTR);
YX}
YX
YX/*
YX * HelpOptions - Print a nice help/usage message based on options.
YX */
YXvoid HelpOptions(options, num_opts, message)
YX     OptionDescRec *options;
YX     int num_opts;
YX     char **message;
YX{
YX    OptionDescRec *opt;
YX    register int x;
YX    char **cpp;
YX
YX    suppress_help_msg = 1;
YX    UsageOptions(options, num_opts, (char *)NULL);
YX    suppress_help_msg = 0;
YX
YX    (void) fprintf (stderr, "where options include:\n");
YX    for (x = 0; x < num_opts; x++) {
YX	opt = &options[x];
YX	if (opt->flags & ArgHidden)
YX	    continue;
YX	(void) fprintf (stderr, "    %-28s %s\n", UsageString(opt), 
YX		 (opt->desc) ? opt->desc : "");
YX	if (opt->value && opt->cvtarg != OptBool)
YX	    (void) fprintf (stderr, "    %-28s [ Default value is %s ]\n", 
YX			    "", opt->value);
YX    }
YX
YX    if (message) {
YX	(void) putc ('\n', stderr);
YX	for (cpp = message; *cpp; cpp++) {
YX	    (void) fputs (*cpp, stderr);
YX	    (void) putc ('\n', stderr);
YX	}
YX	(void) putc ('\n', stderr);
YX    }
YX}
YX
YX/*
YX * UserError - Print a user error.
YX */
YX#ifdef HAS_VARARGS
YXvoid UserError(va_alist)
YX     va_dcl
YX{
YX    va_list args;
YX    char *fmt;
YX
YX    va_start(args);
YX    if (ProgramName)
YX	(void) fprintf(stderr, "%s: ", ProgramName);
YX    fmt = (char *) va_arg(args, char *);
YX    (void) vfprintf(stderr, fmt, args);
YX    va_end(args);
YX    (void) fprintf(stderr, "\n");
YX}
YX#else
YXvoid UserError(fmt, a1, a2, a3, a4, a5, a6)
YX     char *fmt;
YX{
YX    if (ProgramName)
YX	(void) fprintf(stderr, "%s: ", ProgramName);
YX    (void) fprintf(stderr, fmt, a1, a2, a3, a4, a5, a6);
YX    (void) fprintf(stderr, "\n");
YX}
YX#endif
YX
YXOptBool(opt, value, docopy)
YX     OptionDescRec *opt;
YX     caddr_t value;
YX     int docopy; /*ARGSUSED*/
YX{
YX    char *vpp;
YX
YX    *(int *) opt->valp = (int) strtol(value, &vpp, 0);
YX    if (*vpp) {
YX	UserError("Invalid integer argument for '%s'.", opt->option);
YX	return(FALSE);
YX    } else {
YX	return(TRUE);
YX    }
YX}
YX
YXOptInt(opt, value, docopy)
YX     OptionDescRec *opt;
YX     caddr_t value;
YX     int docopy; /*ARGSUSED*/
YX{
YX    char *vpp;
YX
YX    *(int *) opt->valp = (int) strtol(value, &vpp, 0);
YX    if (*vpp) {
YX	UserError("Invalid integer argument for '%s'.", opt->option);
YX	return(FALSE);
YX    } else {
YX	return(TRUE);
YX    }
YX}
YX
YXOptShort(opt, value, docopy)
YX     OptionDescRec *opt;
YX     caddr_t value;
YX     int docopy; /*ARGSUSED*/
YX{
YX    char *vpp;
YX
YX    *(short *) opt->valp = (short) strtol(value, &vpp, 0);
YX    if (*vpp) {
YX	UserError("Invalid integer argument for '%s'.", opt->option);
YX	return(FALSE);
YX    } else {
YX	return(TRUE);
YX    }
YX}
YX
YXOptLong(opt, value, docopy)
YX     OptionDescRec *opt;
YX     caddr_t value;
YX     int docopy; /*ARGSUSED*/
YX{
YX    char *vpp;
YX
YX    *(long *) opt->valp = (long) strtol(value, &vpp, 0);
YX    if (*vpp) {
YX	UserError("Invalid integer argument for '%s'.", opt->option);
YX	return(FALSE);
YX    } else {
YX	return(TRUE);
YX    }
YX}
YX
YXOptStr(opt, value, docopy)
YX     OptionDescRec *opt;
YX     caddr_t value;
YX     int docopy;
YX{
YX    char *p;
YX
YX    if (docopy) {
YX	if ((p = (char *) malloc((unsigned)strlen(value)+1)) == NULL) {
YX	    UserError("Cannot malloc memory: %s", SYSERR);
YX	    return(FALSE);
YX	}
YX	(void) strcpy(p, value);
YX    } else {
YX	p = value;
YX    }
YX
YX    *(char **) opt->valp = p;
YX
YX    return(TRUE);
YX}
YX
YXstatic char *UsageString(opt)
YX     OptionDescRec *opt;
YX{
YX    static char buf[BUFSIZ], buf2[BUFSIZ];
YX
YX    (void) sprintf(buf, opt->option);
YX    (void) strcpy(buf2, "");
YX    if (opt->usage) {
YX	(void) sprintf(buf2, "%s%s%s%s",
YX		       ((opt->flags & StickyArg) && 
YX			!((opt->flags & StickyArg) && (opt->flags & SepArg))) 
YX		       ? "" : " ",
YX		       (opt->value) ? "[" : "",
YX		       opt->usage,
YX		       (opt->value) ? "]" : ""
YX		       );
YX    }
YX    (void) strcat(buf, buf2);
YX
YX    return(buf);
YX}
YSHAR_EOF
Ychmod 644 'options.c'
Yfi
Yif test -f 'qterm.h'
Ythen
Y	echo shar: "will not over-write existing file 'qterm.h'"
Yelse
Ysed 's/^X//' << \SHAR_EOF > 'qterm.h'
YX/*
YX * Copyright (c) 1990 Michael A. Cooper.
YX * This software may be freely distributed provided it is not sold for 
YX * profit and the author is credited appropriately.
YX */
YX
YX/*
YX * $Header: /src/common/usc/bin/qterm/RCS/qterm.h,v 5.1 1991/03/12 00:46:24 mcooper Exp $
YX *------------------------------------------------------------------
YX *
YX * $Source: /src/common/usc/bin/qterm/RCS/qterm.h,v $
YX * $Revision: 5.1 $
YX * $Date: 1991/03/12 00:46:24 $
YX * $State: Exp $
YX * $Author: mcooper $
YX * $Locker:  $
YX *
YX *------------------------------------------------------------------
YX *
YX * Michael A. Cooper
YX * Research and Development Group
YX * University Computing Services 
YX * University of Southern California
YX * (mcooper@usc.edu)
YX *
YX *------------------------------------------------------------------
YX * $Log: qterm.h,v $
YX * Revision 5.1  1991/03/12  00:46:24  mcooper
YX * - Changed CMASK to CHAR_CMASK to avoid conflict
YX *   under AIX 3.1.
YX * - Expand tabs.
YX *
YX * Revision 5.0	 1990/12/15  18:30:45  mcooper
YX * Version 5.
YX *
YX * Revision 4.1	 90/12/15  18:14:27  mcooper
YX * Add copywrite.
YX * 
YX * Revision 4.0	 88/03/08  19:31:23  mcooper
YX * Version 4.
YX * 
YX * Revision 3.2	 88/03/08  19:28:52  mcooper
YX * Major rewrite.
YX * 
YX * Revision 3.1	 88/03/08  15:32:16  mcooper
YX * Changed around user's qtermtab
YX * file names.
YX * 
YX * Revision 3.0	 87/06/30  19:09:04  mcooper
YX * Release of version 3.
YX * 
YX * Revision 2.4	 87/06/30  19:02:28  mcooper
YX * WAIT changed to 2 for slow systems.
YX * 
YX *------------------------------------------------------------------
YX */
YX
YX
YX
YX#ifndef TABFILE
YX# define TABFILE	"/usr/local/lib/qtermtab" /* Default qtermtab file */
YX#endif
YX#define USRFILE		".qtermtab"		/* User's qtermtab file */
YX#define OLDUSRFILE	".qterm"		/* Old user qtermtab file */
YX#define ALTSEND		"\033[c"		/* Alternate query string */
YX#define WAIT		2			/* Timeout (in seconds) */
YX#define SIZE		512			/* Receive buffer size */
YX#define CHAR_MASK	0377			/* Character mask */
YX#define ESC		'\033'			/* ESCAPE */
YX
YX#ifdef TRUE
YX#undef TRUE
YX#endif
YX#ifdef FALSE
YX#undef FALSE
YX#endif
YX#define TRUE		1
YX#define FALSE		0
YX
YX#ifdef USG5
YX# define crmode()	(_ntty.c_lflag &= ~ICANON,\
YX			_ntty.c_cc[VMIN] = 1, _ntty.c_cc[VTIME] = 0,\
YX			ioctl(_tty_ch, TCSETAF, &_ntty))
YX# define nocrmode()	(_ntty.c_lflag |= ICANON,\
YX			_ntty.c_cc[VMIN] = _otty.c_cc[VMIN],\
YX			_ntty.c_cc[VTIME] = _otty.c_cc[VTIME],\
YX			ioctl(_tty_ch, TCSETAF, &_ntty))
YX# define echo()		(_ntty.c_lflag |= ECHO,\
YX			ioctl(_tty_ch, TCSETAF, &_ntty))
YX# define noecho()	(_ntty.c_lflag &= ~ECHO,\
YX			ioctl(_tty_ch, TCSETAF, &_ntty))
YX#else /* !USG5 */
YX# define crmode()	(_tty.sg_flags |= CBREAK,\
YX			ioctl(_tty_ch, TIOCSETP, &_tty))
YX# define nocrmode()	(_tty.sg_flags &= ~CBREAK,\
YX			ioctl(_tty_ch, TIOCSETP, &_tty))
YX# define echo()		(_tty.sg_flags |= ECHO,	  \
YX			ioctl(_tty_ch, TIOCSETP, &_tty))
YX# define noecho()	(_tty.sg_flags &= ~ECHO,  \
YX			ioctl(_tty_ch, TIOCSETP, &_tty))
YX#endif /* USG5 */
YX
YX/*
YX * Terminal table structure
YX */
YXstruct termtable {
YX    char		*qt_sendstr;	/* String to send to terminal */
YX    char		*qt_recvstr;	/* String expected in response */
YX    char		*qt_termname;	/* Terminal name */
YX    char		*qt_fullname;	/* Full terminal name & description */
YX    struct termtable    *nxt;		/* Next structure */
YX};
YXstruct termtable *termtab = NULL;
YSHAR_EOF
Ychmod 644 'qterm.h'
Yfi
Yif test -f 'options.h'
Ythen
Y	echo shar: "will not over-write existing file 'options.h'"
Yelse
Ysed 's/^X//' << \SHAR_EOF > 'options.h'
YX/*
YX * Copyright (c) 1990 Michael A. Cooper.
YX * This software may be freely distributed provided it is not sold for 
YX * profit and the author is credited appropriately.
YX */
YX
YX/*
YX * $Header: /am/sol/src/common/usc/lib/libgen/RCS/options.h,v 1.7 90/12/15 18:13:30 mcooper Exp $
YX *
YX * $Log:	options.h,v $
YX * Revision 1.7  90/12/15  18:13:30  mcooper
YX * Add copywrite notice.
YX * 
YX * Revision 1.6  90/11/13  15:28:39  mcooper
YX * Add OptBool cvtarg routine.
YX * 
YX * Revision 1.5  90/10/29  19:34:03  mcooper
YX * Fixed comment for NoArg.
YX * 
YX * Revision 1.4  90/10/29  18:48:43  mcooper
YX * Cleanup some comments.
YX * 
YX * Revision 1.3  90/10/29  14:47:29  mcooper
YX * UsageString is now a real function.
YX * 
YX * Revision 1.2  90/10/26  15:55:44  mcooper
YX * Add defines for "__" and ArgHidden.
YX * 
YX * Revision 1.1  90/10/26  14:42:53  mcooper
YX * Initial revision
YX * 
YX */
YX
YX
YX#include <stdio.h>
YX#include <sys/types.h>
YX#include <sys/errno.h>
YX
YX#define Num_Opts(o)	(sizeof(o)/sizeof(OptionDescRec))
YX#define HELPSTR		"-help"
YX#define __		(caddr_t)
YX
YX#ifndef SYSERR
YX#define SYSERR		sys_errlist[errno]
YX#endif
YX#ifndef TRUE
YX#define TRUE	1
YX#endif
YX#ifndef FALSE
YX#define FALSE	0
YX#endif
YX
YX/*
YX * Values for OptionDescRec.flags.
YX */
YX#define NoArg		0x001	/* No argument for this option.  Use
YX				   OptionDescRec.value. */
YX#define IsArg		0x002	/* Value is the option string itself */
YX#define SepArg		0x004	/* Value is in next argument in argv */
YX#define StickyArg	0x008	/* Value is characters immediately following 
YX				   option */
YX#define SkipArg		0x010	/* Ignore this option and the next argument in 
YX				   argv */
YX#define SkipLine	0x020	/* Ignore this option and the rest of argv */
YX#define SkipNArgs	0x040	/* Ignore this option and the next 
YX				   OptionDescRes.value arguments in argv */
YX#define ArgHidden	0x080	/* Don't show in usage or help messages */
YX
YX/*
YX * Option description record.
YX */
YXtypedef struct {
YX    char	*option;		/* Option string in argv	    */
YX    int		 flags;			/* Flag bits			    */
YX    int		(*cvtarg)();		/* Function to convert argument     */
YX    caddr_t	 valp;			/* Variable to set		    */
YX    caddr_t	 value;			/* Default value to provide	    */
YX    char	*usage;			/* Usage message		    */
YX    char	*desc;			/* Description message		    */
YX} OptionDescRec, *OptionDescList;
YX
YXvoid UsageOptions();
YXvoid HelpOptions();
YXvoid UserError();
YXint ParseOptions();
YXOptionDescRec *FindOption();
YX
YXint OptBool();
YXint OptInt();
YXint OptLong();
YXint OptShort();
YXint OptStr();
YX
YXextern char *OptionChars;
YXextern int errno;
YXextern char *sys_errlist[];
YXextern long strtol();
YXextern char *malloc();
YXextern char *strcpy();
YSHAR_EOF
Ychmod 644 'options.h'
Yfi
Ychmod 755 .
Ycd ..
Yexit 0
Y#	End of shell archive
SHAR_EOF
fi
exit 0
#	End of shell archive