goer@ellis.uchicago.edu (Richard L. Goerwitz) (12/21/90)
---- Cut Here and feed the following to sh ---- #!/bin/sh # this is itlib.02 (part 2 of a multipart archive) # do not concatenate these parts, unpack them in order with /bin/sh # file itlib.icn continued # if test ! -r _shar_seq_.tmp; then echo 'Please unpack part 1 first!' exit 1 fi (read Scheck if test "$Scheck" != 2; then echo Please unpack part "$Scheck" next! exit 1 else exit 0 fi ) < _shar_seq_.tmp || exit 1 if test ! -f _shar_wnt_.tmp; then echo 'x - still skipping itlib.icn' else echo 'x - continuing file itlib.icn' sed 's/^X//' << 'SHAR_EOF' >> 'itlib.icn' && X Xend X X X Xprocedure Decode(s) X X # Does things like turn ^ plus a letter into a genuine control X # character. X X new_s := "" X X s ? { X X while new_s ||:= tab(upto('\\^')) do { X chr := move(1) X if chr == "\\" then { X new_s ||:= { X case chr2 := move(1) of { X "\\" : "\\" X "^" : "^" X "E" : "\e" X "b" : "\b" X "f" : "\f" X "n" : "\n" X "r" : "\r" X "t" : "\t" X default : { X if any(&digits,chr2) then { X char(integer("8r"||chr2||move(2 to 0 by -1))) | X er("Decode","bad termcap entry",3) X } X else chr2 X } X } X } X } X else new_s ||:= char(ord(map(move(1),&lcase,&ucase)) - 64) X } X new_s ||:= tab(0) X } X X return new_s X Xend X X X Xprocedure igoto(cm,col,line) X X local colline, range, increment, str, outstr, chr, x, y X X if col > (tc_table["co"]) | line > (tc_table["li"]) then { X colline := string(\col) || "," || string(\line) | string(\col|line) X range := "(" || tc_table["co"]-1 || "," || tc_table["li"]-1 || ")" X er("igoto",colline || " out of range " || (\range|""),9) X } X X # Use the Iconish 1;1 upper left corner & not the C-ish 0 offsets X increment := -1 X outstr := "" X X cm ? { X while outstr ||:= tab(find("%")) do { X tab(match("%")) X chr := move(1) X if case chr of { X "." : outstr ||:= char(line + increment) X "+" : outstr ||:= char(line + ord(move(1)) + increment) X "d" : { X str := string(line + increment) X outstr ||:= right(str, integer(tab(any('23'))), "0") | str X } X } X then line :=: col X else { X case chr of { X "n" : line := ixor(line,96) & col := ixor(col,96) X "i" : increment := 0 X "r" : line :=: col X "%" : outstr ||:= "%" X "B" : line := ior(ishift(line / 10, 4), line % 10) X ">" : { X x := move(1); y := move(1) X line > ord(x) & line +:= ord(y) X &null X } X } | er("goto","bad termcap entry",5) X } X } X return outstr || tab(0) X } X Xend X X X Xprocedure iputs(cp, affcnt) X X local baud_rates, char_rates, i, delay, PC X static num_chars, char_times X # global tty_speed X X initial { X num_chars := &digits ++ '.' X char_times := table() X # Baud rates in decimal, not octal (as in termio.h) X baud_rates := [0,7,8,9,10,11,12,13,14,15] X char_rates := [0,333,166,83,55,41,20,10,10,10] X every i := 1 to *baud_rates do { X char_times[baud_rates[i]] := char_rates[i] X } X } X X type(cp) == "string" | X er("iputs","you can't iputs() a non-string value!",10) X X cp ? { X delay := tab(many(num_chars)) X if ="*" then { X delay *:= \affcnt | X er("iputs","affected line count missing",6) X } X writes(tab(0)) X } X X if (\delay, tty_speed ~= 0) then { X PC := tc_table["pc"] | "\000" X char_time := char_times[tty_speed] | (return "speed error") X delay := (delay * char_time) + (char_time / 2) X every 1 to delay by 10 X do writes(PC) X } X X return X Xend X X X Xprocedure getspeed() X X local stty_g, stty_output, c_cflag, o_speed X X stty_g := open("/bin/stty -g 2>&1","pr") | X er("getspeed","Can't access your stty command.",4) X stty_output := !stty_g X close(stty_g) X X \stty_output ? { X # tab to the third field of the output of the stty -g cmd X tab(find(":")+1) & tab(find(":")+1) & X c_cflag := integer("16r"||tab(find(":"))) X } | er("getspeed","Unable to unwind your stty -g output.",4) X X o_speed := iand(15,c_cflag) X return o_speed X Xend SHAR_EOF echo 'File itlib.icn is complete' && true || echo 'restore of itlib.icn failed' rm -f _shar_wnt_.tmp fi # ============= iscreen.icn ============== if test -f 'iscreen.icn' -a X"$1" != X"-c"; then echo 'x - skipping iscreen.icn (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting iscreen.icn (Text)' sed 's/^X//' << 'SHAR_EOF' > 'iscreen.icn' && X############################################################################ X# X# Name: iscreen.icn X# X# Title: Icon screen functions X# X# Author: Richard L. Goerwitz X# X# Version: 1.12 X# X############################################################################ X# X# This and future version of iscreen are placed in the public domain - RLG X# X############################################################################ X# X# This file contains some rudimentary screen functions for use with X# itlib.icn (termlib-like routines for Icon). X# X# clear() - clears the screen (tries several methods) X# emphasize() - initiates emphasized mode X# normal(mode) - resets to normal mode; if mode is null, X# or "b," normal() assumes you were in emphasize mode, X# otherwise you are assumed to have been in underline mode X# message(s) - displays message s on 2nd-to-last line X# underline() - initiates underline mode X# status_line(s,s2,p) - draws status line s on the 3rd-to-last X# screen line; if s is too short for the terminal, s2 is used; X# if p is nonnull then it either centers, left-, or right-justi- X# fies, depending on the value, "c," "l," or "r." X# X############################################################################ X# X# Requires: UNIX X# X# Links: itlib.icn (or your OS-specific port of itlib) X# X# See also: boldface.icn X# X############################################################################ X X Xprocedure clear() X X # Clears the screen. Tries several methods. X X if not iputs(getval("cl")) X then iputs(igoto(getval("cm"),1,1)) X if not iputs(getval("cd")) X then { X every i := 1 to getval("li") do { X iputs(igoto(getval("cm"),1,i)) X iputs(getval("ce")) X } X iputs(igoto(getval("cm"),1,1)) X } X return X Xend X X X Xprocedure emphasize() X X static bold_str, cookie_str X initial { X if bold_str := getval("so") X then cookie_str := repl(getval("bc") | "\b", getval("sg")) X else { X if bold_str := getval("us") X then cookie_str := repl(getval("bc") | "\b", getval("ug")) X } X } X X iputs(\bold_str) X iputs(\cookie_str) X return X Xend X X X Xprocedure underline() X X static underline_str, cookie_str X initial { X if underline_str := getval("us") X then cookie_str := repl(getval("bc") | "\b", getval("sg")) X } X X iputs(\underline_str) X iputs(\cookie_str) X return X Xend X X X Xprocedure normal(mode) X X static UN_bold_str, bold_cookie_str, X UN_underline_str, underline_cookie_str X initial { X X if UN_bold_str := getval("se") then X bold_cookie_str := repl(getval("bc") | "\b", getval("sg")) X else { X UN_bold_str := getval("ue") X bold_cookie_str := repl(getval("bc")|"\b", getval("ug")) X } X if UN_underline_str := getval("ue") then X underline_cookie_str := repl(getval("bc")|"\b", getval("ug")) X } X X if /mode | (mode == "b") then { X iputs(\UN_bold_str) X iputs(\bold_cookie_str) X return X } X X iputs(\UN_underline_str) X iputs(\underline_cookie_str) X return X Xend X X X Xprocedure status_line(s,s2,p) X X # Writes a status line on the terminal's third-to-last line X # The only necessary argument is s. S2 (optional) is used X # for extra narrow screens. In other words, by specifying X # s2 you give status_line an alternate, shorter status string X # to display, in case the terminal isn't wide enough to sup- X # port s. If p is nonnull, then the status line is either X # centered (if equal to "c"), left justified ("l"), or right X # justified ("r"). X X local width X X /s := "" X width := getval("co") X if *s > width then { X (*s2 < width, s := \s2) | X er("status_line","Your terminal is too narrow.",4) X } X case \p of { X "c" : s := center(s,width-1) X "l" : s := left(s,width-1) X "r" : s := right(s,width-1) X default: stop("status_line: Unknown option "||string(p),4) X } X X iputs(igoto(getval("cm"), 1, getval("li")-2)) X emphasize(); writes(s); iputs(getval("ce")) X normal() X return X Xend X X X Xprocedure message(s) X X # Display prompt s on the second-to-last line of the screen. X # I hate to use the last line, due to all the problems with X # automatic scrolling. X X /s := "" X normal() X iputs(igoto(getval("cm"), 1, getval("li")-1)) X writes(s[1:getval("co")] | s) X iputs(getval("ce")) X return X Xend SHAR_EOF true || echo 'restore of iscreen.icn failed' rm -f _shar_wnt_.tmp fi # ============= itlibdos.icn ============== if test -f 'itlibdos.icn' -a X"$1" != X"-c"; then echo 'x - skipping itlibdos.icn (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting itlibdos.icn (Text)' sed 's/^X//' << 'SHAR_EOF' > 'itlibdos.icn' && X########################################################################## X# X# Name: itlibdos.icn X# X# Title: Icon termlib-type tools (MS-DOS version) X# X# Author: Richard L. Goerwitz X# X# Version: 1.12 X# X########################################################################### X# X# I place this and future versions of itlibdos in the public domain - RLG X# X########################################################################### X# X# The following library represents a series of rough functional X# equivalents to the standard Unix low-level termcap routines. They X# are not meant as exact termlib clones. Nor are they enhanced to X# take care of magic cookie terminals, terminals that use \D in their X# termcap entries, or, in short, anything I felt would not affect my X# normal, day-to-day work with ANSI and vt100 terminals. X# X# Requires: An MS-DOS platform & co-expressions. The MS-DOS version X# is a port of the Unix version. Software you write for this library X# can be made to run under Unix simply by substituting the Unix ver- X# sion of this library. See below for additional notes on how to use X# this MS-DOS port. X# X# setname(term) X# Use only if you wish to initialize itermlib for a terminal X# other than what your current environment specifies. "Term" is the X# name of the termcap entry to use. Normally this initialization is X# done automatically, and need not concern the user. X# X# getval(id) X# Works something like tgetnum, tgetflag, and tgetstr. In the X# spirit of Icon, all three have been collapsed into one routine. X# Integer valued caps are returned as integers, strings as strings, X# and flags as records (if a flag is set, then type(flag) will return X# "true"). Absence of a given capability is signalled by procedure X# failure. X# X# igoto(cm,destcol,destline) - NB: default 1 offset (*not* zero)! X# Analogous to tgoto. "Cm" is the cursor movement command for X# the current terminal, as obtained via getval("cm"). Igoto() X# returns a string which, when output via iputs, will cause the X# cursor to move to column "destcol" and line "destline." Column and X# line are always calculated using a *one* offset. This is far more X# Iconish than the normal zero offset used by tgoto. If you want to X# go to the first square on your screen, then include in your program X# "iputs(igoto(getval("cm"),1,1))." X# X# iputs(cp,affcnt) X# Equivalent to tputs. "Cp" is a string obtained via getval(), X# or, in the case of "cm," via igoto(getval("cm"),x,y). Affcnt is a X# count of affected lines. It is only relevant for terminals which X# specify proportional (starred) delays in their termcap entries. X# X# Notes on the MS-DOS version: X# There are two basic reasons for using the I/O routines X# contained in this package. First, by using a set of generalized X# routines, your code will become much more readable. Secondly, by X# using a high level interface, you can avoid the cardinal X# programming error of hard coding things like screen length and X# escape codes into your programs. X# To use this collection of programs, you must do two things. X# First, you must add the line "device=ansi.sys" (or the name of some X# other driver, like zansi.sys, nansi.sys, or nnansi.sys [=new X# nansi.sys]) to your config.sys file. Secondly, you must add two X# lines to your autoexec.bat file: 1) "set TERM=ansi-mono" and 2) X# "set TERMCAP=\location\termcap." The purpose of setting the TERM X# variable is to tell this program what driver you are using. If you X# have a color system, use "ansi-color" instead of "ansi-mono," and X# if you are using nansi or zansi instead of vanilla ansi, use one of X# these names instead of the "ansi" (e.g. "zansi-mono"). The purpose X# of setting TERMCAP is to make it possible to determine where the X# termcap file is located. The termcap file (which should have been X# packed with this library as termcap.dos) is a short database of all X# the escape sequences used by the various terminal drivers. Set X# TERMCAP so that it reflects the location of this file (which should X# be renamed as termcap, for the sake of consistency with the Unix X# version). Naturally, you must change "\location\" above to reflect X# the correct path on your system. X# Although I make no pretense here of providing here a complete X# introduction to the format of the termcap database file, it will be X# useful, I think, to explain a few basic facts about how to use this X# program in conjunction with it. If, say, you want to clear the X# screen, add the line, X# X# iputs(getval("cl")) X# X# to your program. The function iputs() outputs screen control X# sequences. Getval retrieves a specific sequence from the termcap X# file. The string "cl" is the symbol used in the termcap file to X# mark the code used to clear the screen. By executing the X# expression "iputs(getval("cl"))," you are 1) looking up the "cl" X# (clear) code in the termcap database entry for your terminal, and X# the 2) outputting that sequence to the screen. X# Some other useful termcap symbols are "ce" (clear to end of X# line), "ho" (go to the top left square on the screen), "so" (begin X# standout mode), and "se" (end standout mode). To output a X# boldfaced string, str, to the screen, you would write - X# X# iputs(getval("so")) X# writes(str) X# iputs(getval("se")) X# X# You could write "iputs(getval("so") || str || getval("se")), but X# this would only work for DOS. Some Unix terminals require padding, X# and iputs() handles them specially. Normally you should not worry X# about Unix quirks under DOS. It is in general wise, though, to X# separate out screen control sequences, and output them via iputs(). X# It is also heartily to be recommended that MS-DOS programmers X# try not to assume that everyone will be using a 25-line screen. X# Some terminals are 24-line. Some 43. Some have variable window X# sizes. If you want to put a status line on, say, the 2nd-to-last X# line of the screen, then determine what that line is by executing X# "getval("li")." The termcap database holds not only string-valued X# sequences, but numeric ones as well. The value of "li" tells you X# how many lines the terminal has (compare "co," which will tell you X# how many columns). To go to the beginning of the second-to-last X# line on the screen, type in: X# X# iputs(igoto(getval("cm"), 1, getval("li")-1)) X# X# The "cm" capability is a special capability, and needs to be output X# via igoto(cm,x,y), where cm is the sequence telling your computer X# to move the cursor to a specified spot, x is the column, and y is X# the row. The expression "getval("li")-1" will return the number of X# the second-to-last line on your screen. X# X########################################################################## X# X# Requires: MS-DOS, coexpressions X# X# See also: iscreen.icn (a set of companion utilities) X# X########################################################################## X X Xglobal tc_table Xrecord true() X X Xprocedure check_features() X X local in_params, line X X initial { X find("ms-dos",map(&features)) | X er("check_features","MS-DOS system required",1) X find("o-expres",&features) | X er("check_features","co-expressions not implemented - &$#!",1) X } X X return X Xend X X X Xprocedure setname(name) X X # Sets current terminal type to "name" and builds a new termcap X # capability database (residing in tc_table). Fails if unable to X # find a termcap entry for terminal type "name." If you want it X # to terminate with an error message under these circumstances, X # comment out "| fail" below, and uncomment the er() line. X X #tc_table is global X X check_features() X X tc_table := maketc_table(getentry(name)) | fail X # er("setname","no termcap entry found for "||name,3) X return X Xend X X X Xprocedure getname() X X # Getname() first checks to be sure we're running under DOS, and, X # if so, tries to figure out what the current terminal type is, X # checking the value of the environment variable TERM, and if this X # is unsuccessful, defaulting to "mono." X X local term, tset_output X X check_features() X term := getenv("TERM") | "mono" X X return \term | X er("getname","can't seem to determine your terminal type",1) X Xend X X X Xprocedure er(func,msg,errnum) X X # short error processing utility X write(&errout,func,": ",msg) X exit(errnum) X Xend X X X Xprocedure getentry(name, termcap_string) X X # "Name" designates the current terminal type. Getentry() scans X # the current environment for the variable TERMCAP. If the X # TERMCAP string represents a termcap entry for a terminal of type X # "name," then getentry() returns the TERMCAP string. Otherwise, X # getentry() will check to see if TERMCAP is a file name. If so, X # getentry() will scan that file for an entry corresponding to X # "name." If the TERMCAP string does not designate a filename, X # getentry() will look through ./termcap for the correct entry. X # Whatever the input file, if an entry for terminal "name" is X # found, getentry() returns that entry. Otherwise, getentry() X # fails. X X local f, getline, line, nm, ent1, ent2 X X /termcap_string := getenv("TERMCAP") X X if \termcap_string ? (not match("\\"), pos(0) | tab(find("|")+1), =name) X then return termcap_string X else { X X # The logic here probably isn't clear. The idea is to try to use X # the termcap environment variable successively as 1) a termcap en- X # try and then 2) as a termcap file. If neither works, 3) go to X # the ./termcap file. The else clause here does 2 and, if ne- X # cessary, 3. The "\termcap_string ? (not match..." expression X # handles 1. X X if find("\\",\termcap_string) X then f := open(termcap_string) X /f := open("termcap") | X er("getentry","I can't access your termcap file",1) X X getline := create read_file(f) X X while line := @getline do { X if line ? (pos(1) | tab(find("|")+1), =name, any(':|')) then { X entry := "" X while (\line | @getline) ? { X if entry ||:= 1(tab(find(":")+1), pos(0)) SHAR_EOF true || echo 'restore of itlibdos.icn failed' fi echo 'End of part 2' echo 'File itlibdos.icn is continued in part 3' echo 3 > _shar_seq_.tmp exit 0