Summary
###########################################################################
File: getchlib.icn
Subject: Procedures for getch for UNIX
Author: Richard L. Goerwitz
Date: May 2, 2001
###########################################################################
This file is in the public domain.
###########################################################################
Version: 1.14
###########################################################################
Implementing getch() is a much, much more complex affair under UNIX
than it is under, say, MS-DOS. This library represents one,
solution to the problem - one which can be run as a library, and
need not be compiled into the run-time system. Note that it will
not work on all systems. In particular, certain Suns (with a
screwy stty command) and the NeXT 1.0 OS (lacking the -g option for
stty) do not run getchlib properly. See the bugs section below for
workarounds.
Four basic utilities are included here:
getch() - waits until a keystroke is available &
returns it without displaying it on the screen
getche() - same as getch() only with echo
getse(s) - like getche() only for strings. The optional
argument s gives getse() something to start with. Use this
if, say, you want to read single characters in cbreak mode,
but get more input if the character read is the first part
of a longer command. If the user backspaces over everything
that has been input, getse() fails. Returns on \r or \n.
reset_tty() - absolutely vital routine for putting the cur-
rent tty line back into cooked mode; call it before exiting
or you will find yourself with a locked-up terminal; use it
also if you must temporarily restore the terminal to cooked
mode
Note that getse() *must* be used in place of read(&input) if you
are planning on using getch() or getche(), since read(&input)
assumes a tty with "sane" settings.
Warning: The routines below do not do any sophisticated output
processing. As noted above, they also put your tty line in raw
mode. I know, I know: "Raw is overkill - use cbreak." But in
a world that includes SysV, one must pick a lowest common denomi-
nator. And no, icanon != cbreak.
BUGS: These routines will not work on systems that do not imple-
ment the -g option for the stty command. The NeXT workstation is
an example of such a system. Tisk, tisk. If you are on a BSD
system where the network configuration makes stty | more impossible,
then substitute /usr/5bin/stty (or whatever your system calls the
System V stty command) for /bin/stty in this file. If you have no
SysV stty command online, then you can try replacing every instance
of "stty -g 2>&1" below with "stty -g 2>&1 1> /dev/tty" or
something similar.
###########################################################################
Example program:
The following program is a simple file viewer. To run, it
needs to be linked with itlib.icn, iscreen.icn, and this file
(getchlib.icn).
procedure main(a)
# Simple pager/file searcher for UNIX systems. Must be linked
# with itlib.icn and iscreen.icn.
local intext, c, s
# Open input file
intext := open(a[1],"r") | {
write(&errout,"Can't open input file.")
exit(1)
}
# Initialize screen
clear()
print_screen(intext) | exit(0)
# Prompt & read input
repeat {
iputs(igoto(getval("cm"), 1, getval("li")))
emphasize()
writes("More? (y/n or /search):")
write_ce(" ")
case c := getche() of {
"y" : print_screen(intext) | break
" " : print_screen(intext) | break
"n" : break
"q" : break
"/" : {
iputs(igoto(getval("cm"), 1, getval("li")))
emphasize()
writes("Enter search string:")
write_ce(" ")
pattern := GetMoreInput()
/pattern | "" == pattern & next
# For more complex patterns, use findre() (IPL findre.icn)
if not find(pattern, s := !intext) then {
iputs(igoto(getval("cm"), 1, getval("li")))
emphasize()
write_ce("String not found.")
break
}
else print_screen(intext, s) | break
}
}
}
reset_tty()
write()
exit(0)
end
procedure GetMoreInput(c)
local input_string
static BS
initial BS := getval("bc") | "\b"
/c := ""
if any('\n\r', chr := getch())
then return c
else {
chr == BS & fail
writes(chr)
input_string := getse(c || chr) | fail
if any('\n\r', input_string)
then fail else (return input_string)
}
end
procedure print_screen(f,s)
if /s then
begin := 1
# Print top line, if one is supplied
else {
iputs(igoto(getval("cm"), 1, 1))
write_ce(s ? tab(getval("co") | 0))
begin := 2
}
# Fill the screen with lines from f; clear and fail on EOF.
every i := begin to getval("li") - 1 do {
iputs(igoto(getval("cm"), 1, i))
if not write_ce(read(f) ? tab(getval("co") | 0)) then {
# Clear remaining lines on the screen.
every j := i to getval("li") do {
iputs(igoto(getval("cm"), 1, j))
iputs(getval("ce"))
}
iputs(igoto(getval("cm"), 1, i))
fail
}
}
return
end
procedure write_ce(s)
normal()
iputs(getval("ce")) |
writes(repl(" ",getval("co") - *s))
writes(s)
return
end
###########################################################################
Requires: UNIX
###########################################################################
Links: itlib
###########################################################################
Procedures:
change_tty_mode, getch, getche, getse, reset_tty, setup_tty
Records:
termio_struct
Global variables:
c_cc, current_mode
Links:
itlib.icn
This file is part of the (main) package.
Source code.
change_tty_mode(switch)
getch()
getche()
getse(s)
reset_tty()
setup_tty()
termio_struct(vintr, vquit, verase, vkill)
c_cc
current_mode -- what mode are we in, raw or cooked?
This page produced by UniDoc on 2021/04/15 @ 23:59:54.