v05i019: grabchars, get keystrokes directly from user
Dan Smith "vote early and often..."
daniel at unicom.UUCP
Fri Oct 28 13:08:03 AEST 1988
Posting-number: Volume 5, Issue 19
Submitted-by: "Dan Smith "vote early and often..."" <daniel at unicom.UUCP>
Archive-name: grabchars
"grabchars" gets one or more keystrokes from the user, without
requiring them to hit return. It was written to make shell scripts
(doesn't matter what type) more interactive.
I know that it works fine on Suns running SUN OS 3.2-3.5,
and a Vax 11/750 running Mt. Xinu 4.3 BSD.
You'll find uses for this in all sorts of places. The prime
candidate is in your .login file, it's easy to use this to select different
options. I've provided a "demo" csh script which runs through many of the
options. See the README for more...
dan
dan smith, island graphics, marin co, ca| +1 (415) 491 1000(W), 332 FAST(H)
4000 civic center dr, san rafael 94903 | dis: they're solely my opinions
daniel at island.uu.net {ucbvax!ucbcad,sun}!island!daniel pacbell!unicom!daniel
I'd rather have Roosevelt in a wheelchair, than Reagan & Bush on a horse -Jesse
#! /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
# TODO
# Makefile
# grabchars.c
# patchlevel.h
# grabchars.1
# demo
# This archive created: Wed Oct 26 21:08:10 1988
# By: Dan Smith "vote early and often..." ()
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'README'" '(2463 characters)'
if test -f 'README'
then
echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
"grabchars" gets one or more keystrokes from the user, without
requiring them to hit return. It was written to make shell scripts
(doesn't matter what type) more interactive.
I know that it works fine on Suns running SUN OS 3.2-3.5,
and a Vax 11/750 running Mt. Xinu 4.3 BSD. You should be able to type
"make depend", followed by "make" or "make install". I haven't tried
this on a Sys V machine. If you do, and it works, let me know. You will
need getopt (3) to compile this program. If you're not sure if you
have this, try "nm /lib/libc.a | grep getopt". Get a Public Domain
version if you don't (write me if you get really stuck, I have it).
You'll find uses for this in all sorts of places. The prime
candidate is in your .login file, it's easy to use this to select different
options. I've provided a "demo" csh script which runs through many of the
options.
If you make any changes, *please* send me diffs!
This is in the public domain, don't make money off of it,
and don't pretend you wrote it, and I'll be happy :-)
Have fun!
dan
Usage rundown:
grabchars gets one keystroke
grabchars -c<valid characters> only <valid chars> are returned
grabchars -e output to stderr instead of stdout
grabchars -p<prompt> prompt to help user
grabchars -q<prompt> prompt to help user (through stderr)
grabchars -n<number> number of characters to read
grabchars -t<seconds> timeout after <seconds>
examples: (values to arguments can be in the same word or the next one)
grabchars -caeiou or
grabchars -c aeiou get one of the vowels
grabchars -c i get the letter 'i'
grabchars '-penter a letter ' print the prompt "enter a letter "
grabchars '-qenter a letter ' print the prompt ('q' for question)
"enter a letter " through stderr...
grabchars -n4 get four characters
grabchars -t2 timeout after two seconds
print a prompt and grab three characters...
grabchars -p 'enter three characters >> ' -n 3
get two numbers with a ten second timeout...
grabchars -c 0123456789 -n2 -t10
note that arguments like "-n4" or "-n 4" are handled the same way
grabchars -h will give a usage screen...
dan smith, island graphics, marin co, ca| +1 (415) 491 1000(W), 332 FAST(H)
4000 civic center dr, san rafael 94903 | dis: they're solely my opinions
daniel at island.uu.net {ucbvax!ucbcad,sun}!island!daniel pacbell!unicom!daniel
I'd rather have Roosevelt in a wheelchair, than Reagan & Bush on a horse -Jesse
SHAR_EOF
fi
echo shar: "extracting 'TODO'" '(496 characters)'
if test -f 'TODO'
then
echo shar: "will not over-write existing file 'TODO'"
else
cat << \SHAR_EOF > 'TODO'
TODO file...
add "-s" option (silent)
so that we can just work off of the return value... this is cinchy,
I just haven't gotten to it yet, but I want to get this out.
add support for arrow keys and other special keys...
I have the code for this in my "phonemail" program (to be
posted soon). I'm not sure what would constitute reasonable
return values (have negative values? values greater than 128?)
Is there a canonical return value list for keyboard events?
Thatzit for now...
SHAR_EOF
fi
echo shar: "extracting 'Makefile'" '(2122 characters)'
if test -f 'Makefile'
then
echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
# Makefile for grabchars
#
# 10/88 dan smith, daniel at island.uu.net
#
SRCS = grabchars.c
OBJS = grabchars.c
HDRS = patchlevel.h
DESTBIN = /usr/public/bin
DESTMAN = /usr/public/man/man1
CC = cc
CFLAGS = -O
.c.o:
$(CC) -c $(CFLAGS) $(DEFS) $*.c
all: grabchars
grabchars: $(OBJS)
touch grabchars
mv grabchars grabchars.old
@echo starting...
$(CC) $(CFLAGS) $(OBJS) -o grabchars
@echo done...
pgrind:
@echo pgrinding out sources...
lpq $(PRINTER)
pgrind $(SRCS) $(HDRS) Makefile
shar:
@echo bundling up grabchars for transit...
shar -v README TODO Makefile $(SRCS) $(HDRS) grabchars.1 demo > sendme
clean:
touch $(OBJS) grabchars grabchars.old
- /bin/rm $(OBJS) grabchars grabchars.old
install: grabchars
- cp grabchars $(DESTBIN)
- cp grabchars.1 $(DESTMAN)
@echo formatting man page...
man grabchars
depend:
@echo making dependencies...
sed -n '1,/^# lines after this point/p' Makefile >.depends &&\
cc -M $(SRCS) >> .depends && mv .depends Makefile
tags: $(SRCS)
ctags $(SRCS)
# lines after this point produced with cc -M, leave this line here
grabchars.o: grabchars.c
grabchars.o: /usr/include/stdio.h
grabchars.o: /usr/include/signal.h
grabchars.o: /usr/include/sgtty.h
grabchars.o: /usr/include/sys/ioctl.h
grabchars.o: /usr/include/sys/ttychars.h
grabchars.o: /usr/include/sys/ttydev.h
grabchars.o: /usr/include/ctype.h
grabchars.o: /usr/include/string.h
grabchars.o: grabchars.c
grabchars.o: /usr/include/stdio.h
grabchars.o: /usr/include/signal.h
grabchars.o: /usr/include/sgtty.h
grabchars.o: /usr/include/sys/ioctl.h
grabchars.o: /usr/include/sys/ttychars.h
grabchars.o: /usr/include/sys/ttydev.h
grabchars.o: /usr/include/ctype.h
grabchars.o: /usr/include/string.h
grabchars.o: /usr/include/strings.h
grabchars.o: grabchars.c
grabchars.o: /usr/include/stdio.h
grabchars.o: /usr/include/signal.h
grabchars.o: /usr/include/sgtty.h
grabchars.o: /usr/include/sys/ioctl.h
grabchars.o: /usr/include/sys/ttychars.h
grabchars.o: /usr/include/sys/ttydev.h
grabchars.o: /usr/include/ctype.h
grabchars.o: /usr/include/string.h
grabchars.o: /usr/include/strings.h
SHAR_EOF
fi
echo shar: "extracting 'grabchars.c'" '(4787 characters)'
if test -f 'grabchars.c'
then
echo shar: "will not over-write existing file 'grabchars.c'"
else
cat << \SHAR_EOF > 'grabchars.c'
/*
** grabchars.c - get characters directly from the user
**
** October 23, 1988, Dan Smith (daniel at island.uu.net)
**
** This program grabs characters from the user as they are
** typed in, without having to wait for the return key to
** be pressed. Among other things, this allows shell scripts
** to be written with highly interactive menus...
**
** Usage rundown:
**
** grabchars gets one keystroke
** grabchars -c<valid characters> only <valid chars> are returned
** grabchars -e output to stderr instead of stdout
** grabchars -p<prompt> prompt to help user
** grabchars -q<prompt> prompt to help user (through stderr)
** grabchars -n<number> number of characters to read
** grabchars -t<seconds> timeout after <seconds>
**
** examples: (values to arguments can be in the same word or the next one)
**
** grabchars -caeiou or
** grabchars -c aeiou get one of the vowels
** grabchars -c i get the letter 'i'
** grabchars '-penter a letter ' print the prompt "enter a letter "
** grabchars '-qenter a letter ' print the prompt ('q' for question)
** "enter a letter " through stderr...
** grabchars -n4 get four characters
** grabchars -t2 timeout after two seconds
**
** print a prompt and grab three characters...
** grabchars -p 'enter three characters >> ' -n 3
**
** get two numbers with a ten second timeout...
** grabchars -c 0123456789 -n2 -t10
**
** note that arguments like "-n4" or "-n 4" are handled the same way
*/
#include <stdio.h>
#include <signal.h>
#include <sgtty.h>
#include <ctype.h>
#include <string.h>
struct sgttyb orig, new;
int exit_stat;
char *usage_statement[] = {
"usage:",
"grabchars gets one keystroke",
" -c<valid characters> only <valid chars> are returned",
" -e output to stderr instead of stdout",
" -p<prompt> prompt to help user",
" -q<prompt> prompt to help user (through stderr)",
" -n<number> number of characters to read",
" -t<seconds> timeout after <seconds>",
" ",
"examples: (values to arguments can be in the same word or the next one)",
" ",
"grabchars -caeiou or",
"grabchars -c aeiou get one of the vowels",
"grabchars -c i get the letter 'i'",
" ",
"grabchars '-penter a letter ' print the prompt \"enter a letter \"",
"grabchars -n4 get four characters",
"grabchars -t2 timeout after two seconds",
" ",
"print a prompt and grab three characters...",
"grabchars -p 'enter three characters >> ' -n 3",
0
};
main (argc, argv)
int argc;
char **argv;
{
extern int optind, opterr;
extern char *optarg;
int how_many = 1, check_flag = 0;
int i;
int timeout;
char ch;
char comarg;
char valid_chars[128];
FILE *outfile = stdout;
int lets_go (), overtime ();
/* handle the outside world */
signal (SIGINT, lets_go);
signal (SIGTSTP, lets_go);
signal (SIGQUIT, lets_go);
alarm (0);
opterr = 0;
exit_stat = -1; /* if we're interrupted, exit with this status */
while ((comarg = getopt (argc, argv, "ec:n:p:q:t:")) != EOF) {
switch (comarg) {
case 'c':
check_flag = 1;
strcpy (valid_chars, optarg);
break;
case 'e':
outfile = stderr;
break;
case 'n':
how_many = atoi (optarg);
if (how_many <= 0) {
fprintf (stderr, "number of characters to read must be greater than zero\n");
exit (-1);
}
break;
case 'p':
fprintf (stdout, "%s", optarg);
break;
case 'q':
fprintf (stderr, "%s", optarg);
break;
case 't':
timeout = atoi (optarg);
if (timeout <= 0) {
fprintf (stderr, "number of seconds to timeout must be greater than zero\n");
exit (-1);
}
/*
** we must have some valid time >0 seconds to
** get here, so we'll set an alarm...
*/
signal (SIGALRM, overtime);
alarm ((unsigned int) timeout);
break;
/*
** I bet I could leave out "default", but
** I also bet that all getopt () routines
** are not created equal, so in it stays!
*/
case '?':
default:
i = 0;
while (usage_statement[i])
puts (usage_statement[i++]);
exit (-1);
}
}
/* play havoc with the terminal :-) */
ioctl (0, TIOCGETP, &orig);
new = orig;
new.sg_flags &= ~ECHO;
new.sg_flags |= CBREAK;
ioctl (0, TIOCSETP, &new);
for (i = 0; i < how_many; i++) {
ch = getchar ();
if (check_flag)
if ( ! (any (ch, valid_chars))) {
i--;
continue;
}
putc (ch, outfile);
}
exit_stat = i;
lets_go ();
}
/*
** something's up with the user...give a useful exit status so
** we can ask things like "do you need help?"
*/
int overtime ()
{
exit_stat = -2;
lets_go ();
}
/* clean up and get out of here... */
int lets_go ()
{
ioctl (0, TIOCSETP, &orig);
exit (exit_stat);
}
/*
** do any chars "s" match 'c'?
*/
any (c, s)
register int c;
register char *s;
{
while (*s)
if (*s++ == c)
return (1);
return (0);
}
SHAR_EOF
fi
echo shar: "extracting 'patchlevel.h'" '(21 characters)'
if test -f 'patchlevel.h'
then
echo shar: "will not over-write existing file 'patchlevel.h'"
else
cat << \SHAR_EOF > 'patchlevel.h'
#define PATCHLEVEL 0
SHAR_EOF
fi
echo shar: "extracting 'grabchars.1'" '(3009 characters)'
if test -f 'grabchars.1'
then
echo shar: "will not over-write existing file 'grabchars.1'"
else
cat << \SHAR_EOF > 'grabchars.1'
''' Man page for grabchars, uses Larry Wall's "patch" man page as
''' a template.
.de Sh
.br
.ne 5
.PP
\fB\\$1\fR
.PP
..
.de Sp
.if t .sp .5v
.if n .sp
..
'''
''' Set up \*(-- to give an unbreakable dash;
''' string Tr holds user defined translation string.
''' Bell System Logo is used as a dummy character.
'''
.ie n \{\
.tr \(bs-\*(Tr
.ds -- \(bs-
.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch
.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch
.ds L" ""
.ds R" ""
.ds L' '
.ds R' '
'br\}
.el\{\
.ds -- \(em\|
.tr \*(Tr
.ds L" ``
.ds R" ''
.ds L' `
.ds R' '
'br\}
.TH GRABCHARS 1 LOCAL
.SH NAME
grabchars - get keystrokes directly from user
.SH SYNOPSIS
.B grabchars
[options]
.SH DESCRIPTION
.I Grabchars
gets characters from the user as they are
typed in, without having to wait for the return key to
be pressed. Among other things, this allows shell scripts
to be written with highly interactive menus.
.PP
By default,
.I grabchars
will obtain one character from stdin, echo that character to stdout,
and return with a status of one; meaning one character read.
.TP 5
.B \-c<valid characters>
Only characters in
.I <valid characters>
are accepted. All other characters are ignored.
.TP 5
.B \-e
Output goes to
.I stderr
rather than
.I stdout.
.TP 5
.B \-p<prompt>
Sets up a prompt for the user. See
.I EXAMPLES.
.TP 5
.B \-q<prompt>
Sets up a prompt for the user, except it is printed to
.I stderr
rather than
.I stdout.
.TP 5
.B \-n<number>
Number of characters to read. By default,
.I grabchars
looks for one character.
.TP 5
.B \-t<seconds>
Time to allow the user to respond. By default, the user
can take as long as he or she wants to. The timeout option allows
you to write shell scripts where you can offer some assistance
if it's obvious that the user might be stuck.
.SH EXAMPLES
.TP 5
.B grabchars
gets one keystroke
.TP 5
.B grabchars \-caeiou
get one of the vowels
.TP 5
.B grabchars -c i
get the letter 'i'
.TP 5
.B grabchars '\-penter a letter '
print the prompt "enter a letter "
.TP 5
.B grabchars '\-qenter a letter '
print the prompt ('q' for question) "enter a letter " through
.I stderr.
.TP 5
.B grabchars \-n4
get four characters.
.TP 5
.B grabchars \-t2
timeout after two seconds.
.TP 5
.B grabchars \-n3 \-p 'initials: '
print a prompt and grab three characters.
.TP 5
.B grabchars \-c 0123456789 \-n2 \-t10
get two numbers with a ten second timeout.
.PP
note that arguments like "-n4" or "-n 4" are handled the same way
.SH SEE ALSO
csh(1) and sh(1)
for syntax of
.I csh
and
.I sh
scripts, respectively.
See "The Unix Csh Field Guide", by Gail and Paul Anderson (Prentice Hall),
for an excellent tour of csh and good examples of writing csh scripts.
.SH DIAGNOSTICS
.I
Grabchars
returns
.B \-2
if it times out, or
.B \-1
if it gives a usage statement. Otherwise, it
returns the number of characters successfully read.
.SH AUTHOR
.nf
Dan Smith (daniel at island.uu.net or {ucbvax!ucbcad,well,sun}!island!daniel)
SHAR_EOF
fi
echo shar: "extracting 'demo'" '(1412 characters)'
if test -f 'demo'
then
echo shar: "will not over-write existing file 'demo'"
else
cat << \SHAR_EOF > 'demo'
#!/bin/csh -f
clear
cat << GUMBY
Grabchars demo...
get one character with "grabchars"
GUMBY
grabchars
echo " status returned was $status"
cat << POKEY
grab a vowel with "grabchars -caeiou"
Type something that isn't a vowel at first...
POKEY
grabchars -caeiou
echo " status returned was $status"
cat << WILMA
prompt the user with "grabchars -p 'give me any character >> '"
WILMA
grabchars -p 'give me any character >> '
echo " status returned was $status"
cat << FRED
prompt through stderr with "grabchars -q 'give me any character >> '",
so that we can set the variable "user_char"...
FRED
set user_char=`grabchars -q 'give me any character >> '`
echo " status returned was $status"
echo '$user_char = '$user_char
cat << BETTY
enter three characters... "grabchars -n3"
BETTY
grabchars -n3
echo " status returned was $status"
cat << BARNEY
enter 10 characters within 3 seconds... "grabchars -n10 -t3"
BARNEY
grabchars -n10 -t3
set really_typed=$status
if ($really_typed == 10) then
echo 'hey\! you got 10\!?'
else
echo " $really_typed returned...means that grabchars timed out..."
endif
cat << PEBBLES
The last one... get two numbers with a ten second timeout...
trying "grabchars -c 0123456789 -n2 -t10 -p 'give me 2 numbers >> '
PEBBLES
grabchars -c 0123456789 -n2 -t10 -p 'give me 2 numbers >> '
echo " status returned was $status"
echo ""
echo test/demo done...enjoy\!
SHAR_EOF
chmod +x 'demo'
fi
exit 0
# End of shell archive
More information about the Comp.sources.misc
mailing list