[comp.lang.perl] curses in perl

henkp@ruuinf.cs.ruu.nl (Henk P. Penning) (05/07/90)

I've written some software which gives (almost) full curses
functionality to perl. It consists of two parts.
First, a perl library 'cterm.pl' which defines (in perl) all curses
functions and constants on your system. Second, a C program 'cterm'
which runs as a separate process and controls the terminal (window).
Subroutines in cterm.pl (like &addstr($str)) send commands through a pipe
to cterm. Cterm updates the terminal. In some cases (like getch()),
cterm passes results back to to the perl application through an other pipe.

It works for me, maybe it works for you too. The following perl program
should put an informative message on the middle of your screen.

do 'cterm.pl' || die "$0 can't include cterm.pl\n" ;
&startCterm(@ARGV) ; 
&initscr ; &nonl ; &cbreak ; &noecho ;
$japh = 'just another perl hacker' ;
&mvaddstr(int($LINES/2),int(($COLS-length($japh))/2),$japh) ;
&mvaddstr($LINES-1,0,'hit any key to continue ') ;
&refresh ;
&getchR ;
&clear ;
&move(0,0) ;
&refresh() ;
&endwin ;
&finishCterm ;

Since there exist many versions of curses, I've tried to make the software
adaptable to local circumstances. SYSV systems seem to have a richer curses
than Suns or BSD systems, but cterm should work on both.

In this message I've included the cterm man-page which tells all about
usage and installation. Read it and, if you are still interested,
drop me (henkp@cs.ruu.nl) a message and I'll mail you the stuff (50K).

					===  HenkP  ===

Henk P. Penning, Dept of Computer Science, Utrecht University.
Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands.
Telephone: +31-30-534106
e-mail   : henkp@cs.ruu.nl (uucp to hp4nl!ruuinf!henkp)

---- snip ---- snip ---- snip ---- snip ---- snip ---- snip ----

.TH CTERM 1 "" "Department of Computer Science, RUU"
.SH NAME
cterm, cterm.pl \- curses terminal emulation (for perl)
.SH SYNOPSIS
.B cterm
.I in out
[
.I options
] [
.I logfile
[
.I loglevel
] ]

.B cterm.pl
.SH DESCRIPTION
.PP
.B Cterm
emulates a curses terminal.
On filedescriptor
.I in
it expects curses functions+arguments in the format described below.
On filedescriptor
.IR out,
some functions (like getch()) pass back results.
Cterm should only be forked by other programs after the proper pipes have
been set up.

There are currently no documented
.I options
(see also the section on undocumented features).

As optional arguments to cterm, the name of a
.I logfile
and a
.I loglevel
may be specified.
Loglevel 0 only logs strings provided by the application through
the curses extension
.BR ctermlog(str) .
Loglevel 1 logs all curses functions, arguments and results
handled by cterm.
Loglevel 2 shows even more intestines.
Default is loglevel 0.

Cterm exits in a controlled fashion when it receives signal SIGINT or SIGPIPE.

.B Cterm.pl
is a library of perl subroutines that provides easy interaction with cterm.
Cterm.pl defines perl-counterparts for almost all curses functions,
tables with curses defined constants,
and subroutines for starting and finishing cterm.

.SH Communication between cterm.pl and cterm

The cterm.pl subroutine
.B &startCterm()
sets up two (pair of) pipes, forks and execs cterm.
In the parent (perl application) STDIN and STDOUT are redirected to the pipes.
In the child (cterm) the pipes are connected to filedescriptors
.I out
and
.IR in .
Subroutine
.B &finishCterm()
finishes cterm and restores STDIN and STDOUT again.

For the pupose of communication between cterm.pl and cterm,
each curses function supported in the interface is given a number.
A curses routine in cterm.pl prints this number on STDOUT
followed by its parameters, each on a new line.
When results are required they are read in from STDIN and
returned to the caller.
Cterm reads the numbers from
.I in
and calls appropriate functions which in turn read arguments from
.I in
and perform the required curses functions.
Results are written to
.IR out .

Cterm always flushes
.I out
after writing results to it.
Cterm.pl can be used with $|=0 in applications.
All curses subroutines in cterm.pl that need to return results,
flush STDOUT before reading the results from STDIN.
This implies for instance that the screen always gets up to date
when user input is requested.
A curses extension
.B frefresh
(flush/refresh) does a normal refresh but also flushes STDOUT when
.B $flushOn
is set.
If you always use frefresh you can set $flushOn in parts
of the application where you are willing to pay the price for
a higher flush-rate in order to get a more accurate presentation.
With subroutine
.B &curFlush()
the user can actively flush STDOUT.

In order to access curses defined constants, cterm.pl defines two tables:
.B %curcon
and
.BR %curkey .
Associative array %curcon contains entries like
('KEY_UP',259) and ('A_BLINK',1024),
so curses constants (as strings) map to their value.
Associative array %curkey contains the inverse of %curcon
restricted to KEY-codes.
So, for example, $curkey{259} = 'KEY_UP' if $curcon{'KEY_UP'} = 259.
The contents of %curcon and %curkey differ from system to system.
They are created during installation.
The KEY-associations (KEY_TAB,9) and (KEY_RET,13) are always defined.

Variables
.BR $LINES ,
.BR $COLS ,
.B $stdscr
and
.B $curscr
are set by &initscr.

.SH Arguments and results, representation

Like in curses, in cterm.pl characters are really integers.
So, for instance,
.B &addch(c)
should be provided with an integer and
.B &getch
supplies one.

Windows are really pointers in curses.
Since mixing pointers and integers is potentially dangerous
(espcially printing and reading them in again)
an indirection is introduced.
Cterm stores the result of curses functions returning windows
in a table and returns the index in the table to cterm.pl.
When curses returns window NULL, cterm returns -1.
Subroutine
.B &delwin(win)
deletes the window and the entry in the table.
Subroutine
.B &initscr
clears the table and sets variables
.B $stdscr
and
.BR $curscr.

String arguments are printed on STDOUT as they are handed to cterm.pl.
Things break if a string contains a newline character
because cterm will get out of sync.
No mechanism was implemented to check and/or repair synchronization.

Curses subroutines in cterm.pl return values by result
and not by modifying parameters.
The 'return-parameters' may be omitted in the call.
This implies that for instance
.B getyx
should be called like '($a,$b) = &getyx($win)',
although in C one would write 'getyx(win,a,b)'.
The same holds for the
.B getstr
function family.

Curses subroutines in cterm.pl don't check their parameters,
they just pass 'em on.

.SH Using cterm

Cterm is started up with
.B &startCterm()
and finished with 
.BR &finishCterm .
In addition to proper values for
.I in
and
.IR out ,
all arguments of startCterm are passed as arguments to the exec'ed cterm.
So, if cterm logging is required, the name of the logfile
should be passed as an argument to startCterm.
If cterm should log internals too, an integer loglevel greater than 0
should be passed as well.
Variable
.B $ctermPid
holds the pid of the forked cterm process.
Since cterm only performs curses calls, one usually has to go through
the customary proceedings: &initscr ; &nonl ; &cbreak ; &noecho.
Subroutine endwin() should be called before finishing cterm.
.br
If the perl application does not call finishCterm before exit'ing,
as in the case of a runtime error, cterm can't reset the terminal
and hangs.
This is a nuisance.
When
.B &safeCterm
is called before &startCterm, cterm will be exec'ed in the parent process.
This has the advantage that cterm wil always cleanup when the
perl application suddenly dies.
The disadvantage is that the application has no control over the terminal
after &finishCterm because the shell takes over when cterm exits.
It should be used while developing that part of the application that
runs between &startCterm and &finishCterm.

Subroutine
.B ch2str(c)
takes an integer argument
.I c
and, depending on its value,
returns a string consisting of the correspondig ASCII character,
or a string like 'KEY_LEFT' or 'KEY_HOME' if
.I c
is a KEY-code in curses,
or the argument otherwise.
The subroutine
.B getchint()
is defined as
.BR ch2str(&getch()) .
The KEY-associations (KEY_TAB,9) and (KEY_RET,13) are always defined.

Subroutine
.B clrreg(top,bot)
clears the screen from lines
.I top
to
.IR bot .
Subroutine
.B wclrreg(win,top,bot)
clears window
.I win
from
.I top
to
.IR bot .

Subroutine
.B ctermlog(str)
adds string
.I str
to the cterm logfile if one was specified in &startCterm().

Associative array
.B %curcon
maps curses constants (as strings) to their (integer) values.
The contents of %curcon is determined by the installer.

Associative array
.B %curkey
maps curses KEY-codes (as strings) to their integer values.
It is the inverse of %curcon restricted to keys matching /^KEY/.
The contents of %curkey is determined by the installer.

Associative array
.B %curfun
maps curses functions (as strings) in the cterm interface
to a string listing their parameters and results (if any).
Table %curfun can be used to determine if a curses function is available.
The installer determines which functions are supported in the interface.

Function
.B edit(str,curpos,y,x,xlen,rep)
returns
.B (str,quitkey)
and constitutes a local edit mode of cterm.
The subroutine allows one to edit a string (initially
.IR str ).
It shows (part of) the string in an edit window
in line
.I y
using
.I xlen
columns, starting from column
.IR x .
The initial cursor position in
.I str
is
.IR curpos .
Edit-mode is left and the resulting string returned to the caller
when a 'special' is typed in.
The set of 'special' characters can be specified as follows.
Function
.B editreset()
clears the set.
Function
.B editq(chint)
adds a character (supply an int) to the set.
The 'special' character (really an int)
which caused edit() to leave is returned to the caller too.
.br
Edit facilities are limited.
Arrow-left and arrow-right work if keypad is enabled.
Typing in 'Kill' (as defined by curses killchar())
will delete the character pointed to by the cursor.
Typing in 'Erase' (as defined by curses erasechar())
will delete the character left of the cursor.
When the cursor points to the first character in
.I str
and 'Erase' is typed in, 
.I str
will be swapped with an initially empty save-buffer.
It can be used to present a user with a default wich he/she
can edit or discard by typing 'Erase'.
Printable ASCII characters are inserted.
All others are rejected.
.br
Argument
.I rep
must be a string of four characters.
They are used by edit to indicate which part of
.I str
is shown on the screen.
One of the first two characters in
.I rep
is shown in the first column of the edit window.
One of the last two characters in
.I rep
is shown in the last column of the edit window.
Edit can only use
.I xlen-2
columns to present (part of)
.IR str .
For the sake of simplicity, let us assume that
.IR rep ='[<>]'.
If lenght(\fIstr\fP)<=\fIxlen-2\fP, then
.I str
is shown on the screen like '[\fIstr\fP]'.
If lenght(\fIstr\fP)>\fIxlen-2\fP, then
only a substring
.I sub
of
.I str
can be shown on the screen.
If
.I sub
is a prefix of
.I str
then it is shown like '[\fIsub\fP>'.
If it is a suffix it is shown like '<\fIsub\fP]'.
It is shown like '<\fIsub\fP>' otherwise.
.br
The cursor position will be held at the middle of the edit window
if
.I sub
is neither a prefix nor a suffix of
.IR str .
.br
Subroutine
.B wedit(win,str,curpos,y,x,xlen,rep)
does edit() in a window.

Subroutine
.B editreset()
clears the set of 'special' characters (see edit()).

Subroutine
.B editq(chint)
adds a character (supply an int)
.I chint
to the set of 'special' characters (see edit()).

Subroutine
.B endwin()
flushes STDOUT.

Subroutine
.B frefresh()
does a refresh.
STDOUT is flushed if
.B $flushOn
is set.

Function
.B getstr(str)
should be called like '$str = &getstr',
mvgetstr(str) should be called like '$str = &mvgetstr($y,$x)',
and mvwgetstr, wgetstr likewise.

Function
.B getyx
should be called like '($a,$b) = &getyx($win)'.

Function
.B getchR()
and
.B wgetchR(win)
act like getch() but redraw the screen if ^L is entered.
They do getch's until a non-^L is found.

Subroutine
.B initscr()
sets $LINES and $COLS and
forgets about all windows except stdscr and curscr.

Subroutine
.B refresh()
does not flush STDOUT (see also &frefresh()).

Subroutine
.B show(str,curpos,y,x,xlen,rep)
shows
.I str
on the screen like edit initially would.
It is handy in applications that are to be independent of the value of COLS.
.br
Subroutine
.B wshow(win,str,curpos,y,x,xlen,rep)
does show() in a window.

.SH Omissions and limitations
Implementations of curses differ a lot.
A few curses functions that are available on some
systems are not supported in this distribution.
Some were documented as obsolete, some are meaningless in this application.
The ones which take a variable number of arguments don't fit
the interface model and can be done in perl more easily anyway.
Some are left out because the author was unable to understand what
they were supposed to do.
Use %curfun to find out which curses functions are supported in the interface.

Which constants go in %curcon and %curkey is determined by the installer.

As distributed, the size of the window table is 100.
The size of the set of 'special' characters for edit() is 1000.
Strings passed to cterm shouldn't be larger than 10K.

.SH Installation
Edit the 'Makefile' in the source directory.
Define BINDIR to be a directory were exec usually looks for executables.
Define PERLLIB to be a directory where perl's do-statement
looks for libraries to include.
The Makefile variables EDIT_LEFT, EDIT_RIGHT and BEEP are passed to edit.c.
They are used in edit().
When user input equals EDIT_LEFT (EDIT_RIGHT), edit() moves the
cursor left (right).
If your curses recognizes arrow-keys, define EDIT_LEFT (EDIT_RIGHT) to
whatever curses getch() returns if the user types in arrow-left (arrow-right).
If not, define EDIT_LEFT as 2 (^B for Back)
and EDIT_RIGHT as 6 (^F for Forward).
You may also comment them out entirely.
.br
BEEP is the function that is used to signal edit errors to the user.
Set it to 'beep' (sound bell) if your curses supports it.
Set it to 'mybeep' if you have nothing better.
It writes ^G to stderr.
You may want to change the implementation of 'mybeep' in cursesX.c.
Function 'nobeep' is defined and does nothing.
It is used if you don't define BEEP.

Run 'make' to generate the necessary stuff.
Don't worry about warnings from 'curcon.mk'.
They simply mean that not all the curses constants suggested
in 'curcon.in' are available on your system.
You might want to try the perl programs 'try1' and 'try2' before
installing.
Arguments to try1 and try2 are passed to startCterm and thus to cterm.

Running 'make install' will copy the stuff to the designated directories.
Running 'make clean' will remove temporaries.
Running 'make realclean' will remove all generated stuff.

The author has tried to make the system adaptable to local conditions.
There are two files that the installer can modify.
.br
The file
.B cdefs.in
is the input for cdefs.mk which generates the interface between
cterm and cterm.pl: cdefs.c and cdefs.pl.
It contains one line for each curses function which is supported in the
interface.
It specifies the name of the function and the parameters that are
to be passed from cterm.pl to cterm, and in some cases the results
that are to be passed back.
If your curses doesn't support some of them, simply comment them
out ('#' in the first column).
If there is a problem with something in the 'extensions' or 'extra's',
please contact the author.
Create your own minicurses if you think it is all too baroque.
The file
.B cdefs.in.SUN
contains a stripped version of cdefs.in that runs on SunOs.4.0.3.
.br
The file
.B curcon.in
is the input for curcon.mk which generates curcon.c which
defines th contents of %curcon and %curkey in file curcon.pl.
Curcon.in is a wishlist.
Comment out constants that are not defined and add others that are.
As distributed, 10 function keys are defined in the way they should be
on some systems.

If you want to add functionality, define more functions in cdefs.in.
Look at other functions and cdefs.types to see how parameters and results
are to be specified.
If you define a function, add an implementation for it in cursesX.c.
For an example, look at
.IR clrreg .
Function initscr() calls initCursesX().
This is the place to put initialisation stuff for curses additions.

.SH "Author's note"
I developed cterm as part of a perl project called 'jinx'.
Jinx is a simple, not-quite-relational database system.
It seemed more practical to have a weak implementation of 'full curses'
in stead of a strong, tested implementation of an ad hoc subset of curses.
In jinx I have sofar used only some of the curses facilities.
The newwin and subwin stuff has not been tried a lot.
I've never tried to set up a multi-terminal application.
I want to get it right though, so complaints will be honored.
.br
For the future I have a wishlist.
I would like to also have sockets for communication available.
I have never used sockets before so I don't see any problems.
A simple synchronisation mechanism would be easy to implement,
but I never have problems in that area.
I guess I don't know how serious the newlines-in-strings problem is.
It should be possible to tell cterm how to handle signals while it runs.
Cterm should more often be able to reset the terminal.
.br
Thanks go to Piet van Oostrum (piet@cs.ruu.nl) for his harsh criticism
and willingness to discuss technicalities.

.SH Undocumented features

If you supply option
.BR -X ,
typing ^X to getchR (and wgetchR) will get you IO statistics in line 0.
Use it to see how much setting $flushOn or $| are costing you
in context switches.
The curses extension quitcterm makes cterm quit.
It is used by finishCterm.

.SH AUTHOR
Henk P. Penning (henkp@cs.ruu.nl), Department of Computer Science,
Utrecht University, the Netherlands.
-- 
Henk P. Penning, Dept of Computer Science, Utrecht University.
Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands.
Telephone: +31-30-534106
e-mail   : henkp@cs.ruu.nl (uucp to hp4nl!ruuinf!henkp)

henkp@ruuinf.cs.ruu.nl (Henk P. Penning) (06/15/90)

Recently I posted the man page of my cterm software.
The package allows (almost) full curses functionality in Perl applications.
No changes to Perl are needed (of course).
The curses stuff is handled in a separate, forked process.

Some 20 people asked for the software. I've received no complaints,
so I think I can post the package now. Here it is.

I've changed one thing since the posting of the man page,
The 'no-newlines-in-strings' constraint is relaxed to 'no-$;-in-strings'.
Also I have learned that ATT-curses (which is much better than BSD-curses)
is available on SUNs if you use the SYSV C compiler (/usr/5bin/cc).
The man page is changed accordingly.

The software is ftp'able from sol.cs.ruu.nl (131.211.80.5) in
file 'pub/UNIX/cterm.shar.Z'. You can also send a message to
'mail-server@cs.ruu.nl' (or hp4nl!ruuinf!mail-server) with the
body 'send UNIX/cterm.shar.Z'. The UUEncoded file will be mailed to you.

				  ===  HenkP  ===

Henk P. Penning, Dept of Computer Science, Utrecht University.
Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands.
Telephone: +31-30-534106
e-mail   : henkp@cs.ruu.nl (uucp to hp4nl!ruuinf!henkp)

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  Makefile cdefs.in cdefs.in.SUN cdefs.mk cdefs.types
#   cterm.1 cterm.c cterm.pl curcon.in curcon.mk cursesX.c cursesX.h
#   defs.h edit.c try1 try2
# Wrapped by henkp@ruuinf on Thu May 17 00:53:20 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(1490 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# names of programs used and compiler flags
X
XCC=gcc
XCFLAGS=-O
XLFLAGS=-lcurses
XNROFF=nroff
XTROFF=lroff
XPERL=perl
X
X# directories where the stuff gets installed
X
XBINDIR=/usr/staff/bin
XBINMODE=755
XPERLLIB=/usr/staff/lib/nrex
XLIBMODE=755
X
X# constants used by edit.c
X
XEDIT_RIGHT=-DEDIT_RIGHT=KEY_RIGHT
XEDIT_LEFT=-DEDIT_LEFT=KEY_LEFT
XBEEP=-DBEEP=beep
X
X# no editing beyond this line
X
XPLS=cterm.pl cdefs.pl curcon.pl
XOBJ=cterm.o cursesX.o cdefs.o edit.o
X
Xall: cterm curcon.pl
Xcterm: cterm.o cursesX.o edit.o cdefs.o
X	${CC} ${CFLAGS} -o cterm cterm.o cursesX.o edit.o cdefs.o ${LFLAGS}
Xcterm.o: cterm.c defs.h
X	${CC} ${CFLAGS} -c cterm.c
XcursesX.o: cursesX.c cursesX.h defs.h
X	${CC} ${CFLAGS} -c cursesX.c
Xcdefs.o: cdefs.c cursesX.h defs.h
X	${CC} ${CFLAGS} -c cdefs.c
Xedit.o: edit.c defs.h
X	${CC} ${CFLAGS} ${EDIT_RIGHT} ${EDIT_LEFT} ${BEEP} -c edit.c
Xcdefs.c: cdefs.in
X	${PERL} cdefs.mk
Xcurcon.pl: curcon
X	./curcon > curcon.pl
Xcurcon: curcon.c
X	${CC} ${CFLAGS} -o curcon curcon.c
Xcurcon.c: curcon.in
X	${PERL} curcon.mk
Xcterm.1.nr: cterm.1
X	${NROFF} -man cterm.1 > cterm.1.nr
Xcterm.1.tr: cterm.1
X	${TROFF} -man cterm.1 > cterm.1.tr
Xinstall: all
X	cp cterm ${BINDIR}
X	chmod ${BINMODE} ${BINDIR}/cterm
X	cp ${PLS} ${PERLLIB}
X	cd ${PERLLIB} ; chmod ${LIBMODE} ${PLS}
X	@echo 'install man page by hand'
Xman: cterm.1.tr cterm.1.nr
Xclean:
X	rm -f ${OBJ} core cdefs.c curcon.c curcon
Xrealclean: clean
X	rm -f cterm cdefs.pl curcon.pl cterm.1.nr cterm.1.tr
Xshar: realclean
X	rm -f cterm.shar
X	shar -o cterm.shar *
END_OF_FILE
if test 1490 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'cdefs.in' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cdefs.in'\"
else
echo shar: Extracting \"'cdefs.in'\" \(2563 characters\)
sed "s/^X//" >'cdefs.in' <<'END_OF_FILE'
X# BEGIN unsupported
X# delay_output ms
X# del_term
X# gettmode
X# mvprintw
X# mvscanw
X# mvwprintw
X# mvwscanw
X# newterm
X# printw
X# putp
X# scanw
X# setterm
X# setupterm
X# set_term
X# set_curterm
X# tgetent
X# tgetflag
X# tgetnum
X# tgetstr
X# tgoto
X# tparm
X# tputs
X# traceoff
X# traceon
X# vidattr
X# vidputs
X# END unsupported
X
X# BEGIN extensions
XgetLINES RETURN resint
XgetCOLS RETURN resint
Xedit str curpos y x xlen rep RETURN str resint
Xwedit win str curpos y x xlen rep RETURN str resint
Xshow str curpos y x xlen rep
Xwshow win str curpos y x xlen rep
Xeditq chint
Xeditreset
Xctermlog str
Xquitcterm FLUSH
X# END extensions
X
X# BEGIN extra's
XgetchR RETURN resint
XwgetchR win RETURN resint
Xclrreg top bot
Xwclrreg win top bot
X# END extra's
X
X# BEGIN curses
Xaddch ch
Xaddstr str
Xattroff attrs
Xattron attrs
Xattrset attrs
Xbaudrate RETURN resint
Xbeep
Xbox win vert hor
Xcbreak
Xclear
Xclearok win flag
Xclrtobot
Xclrtoeol
Xdelch
Xdeleteln
Xdelwin delw
Xdoupdate
Xdraino ms
Xecho
Xendwin FLUSH
Xerase
Xerasechar RETURN resint
Xfixterm
Xflash
Xflushinp
Xgetch RETURN resint
Xgetstr &str RETURN str
Xgetyx win &y &x RETURN y x
Xhas_ic RETURN resint
Xhas_il RETURN resint
Xidlok win flag
Xinch RETURN resint
Xinitscr
Xinsch ch
Xinsertln
Xintrflush win flag
Xkeypad win flag
Xkillchar RETURN resint
Xleaveok win flag
Xlongname RETURN resstr
Xmeta win flag RETURN resint
Xmove y x
Xmvaddch y x ch
Xmvaddstr y x str
Xmvcur oldrow oldcol newrow newcol
Xmvdelch y x
Xmvgetch y x RETURN resint
Xmvgetstr y x &str RETURN str
Xmvinch y x RETURN resint
Xmvinsch y x ch
Xmvwaddch win y x ch
Xmvwaddstr win y x str
Xmvwdelch win y x
Xmvwgetch win y x RETURN resint
Xmvwgetstr win y x &str RETURN str
Xmvwin win y x
Xmvwinch win y x RETURN resint
Xmvwinsch win y x ch
Xnapms ms
Xnewpad num_lines num_cols RETURN reswin
Xnewwin num_lines num_cols y x RETURN reswin
Xnl
Xnocbreak
Xnodelay win flag
Xnoecho
Xnonl
Xnoraw
Xoverlay win1 win2
Xoverwrite win1 win2
Xpnoutrefresh pad pminrow pmincol sminrow smincol smaxrow smaxcol
Xprefresh pad pminrow pmincol sminrow smincol smaxrow smaxcol
Xraw
Xrefresh
Xresetterm
Xresetty
Xsaveterm
Xsavetty
Xscroll win
Xscrollok win flag
Xsetscrreg top bot
Xstandend
Xstandout
Xsubwin win num_lines num_cols y x RETURN reswin
Xtouchwin win
Xtypeahead fd
Xunctrl chint RETURN resstr
Xwaddch win ch
Xwaddstr win str
Xwattroff win attrs
Xwattron win attrs
Xwattrset win attrs
Xwclear win
Xwclrtobot win
Xwclrtoeol win
Xwdelch win
Xwdeleteln win
Xwerase win
Xwgetch win RETURN resint
Xwgetstr win &str RETURN str
Xwinch win RETURN resint
Xwinsch win ch
Xwinsertln win
Xwmove win y x
Xwnoutrefresh win
Xwrefresh win
Xwsetscrreg win top bot
Xwstandend win
Xwstandout win
X# END curses
END_OF_FILE
if test 2563 -ne `wc -c <'cdefs.in'`; then
    echo shar: \"'cdefs.in'\" unpacked with wrong size!
fi
# end of 'cdefs.in'
fi
if test -f 'cdefs.in.SUN' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cdefs.in.SUN'\"
else
echo shar: Extracting \"'cdefs.in.SUN'\" \(2608 characters\)
sed "s/^X//" >'cdefs.in.SUN' <<'END_OF_FILE'
X# BEGIN unsupported
X# delay_output ms
X# del_term
X# gettmode
X# mvprintw
X# mvscanw
X# mvwprintw
X# mvwscanw
X# newterm
X# printw
X# putp
X# scanw
X# setterm
X# setupterm
X# set_term
X# set_curterm
X# tgetent
X# tgetflag
X# tgetnum
X# tgetstr
X# tgoto
X# tparm
X# tputs
X# traceoff
X# traceon
X# vidattr
X# vidputs
X# END unsupported
X
X# BEGIN extensions
XgetLINES RETURN resint
XgetCOLS RETURN resint
Xedit str curpos y x xlen rep RETURN str resint
Xwedit win str curpos y x xlen rep RETURN str resint
Xshow str curpos y x xlen rep
Xwshow win str curpos y x xlen rep
Xeditq chint
Xeditreset
Xctermlog str
Xquitcterm FLUSH
X# END extensions
X
X# BEGIN extra's
XgetchR RETURN resint
XwgetchR win RETURN resint
Xclrreg top bot
Xwclrreg win top bot
X# END extra's
X
X# BEGIN curses
Xaddch ch
Xaddstr str
X# attroff attrs
X# attron attrs
X# attrset attrs
Xbaudrate RETURN resint
X# beeb
Xbox win vert hor
Xcbreak
Xclear
Xclearok win flag
Xclrtobot
Xclrtoeol
Xdelch
Xdeleteln
Xdelwin delw
X# doupdate
X# draino ms
Xecho
Xendwin FLUSH
Xerase
Xerasechar RETURN resint
X# fixterm
X# flash
Xgetch RETURN resint
Xgetstr &str RETURN str
Xgetyx win &y &x RETURN y x
X# has_ic RETURN resint
X# has_il RETURN resint
Xidlok win flag
Xinch RETURN resint
Xinitscr
Xinsch ch
Xinsertln
X# intrflush win flag
X# keypad win flag
Xkillchar RETURN resint
Xleaveok win flag
Xlongname RETURN resstr
X# meta win flag RETURN resint
Xmove y x
Xmvaddch y x ch
Xmvaddstr y x str
Xmvcur oldrow oldcol newrow newcol
Xmvdelch y x
Xmvgetch y x RETURN resint
Xmvgetstr y x &str RETURN str
Xmvinch y x RETURN resint
Xmvinsch y x ch
Xmvwaddch win y x ch
Xmvwaddstr win y x str
Xmvwdelch win y x
Xmvwgetch win y x RETURN resint
Xmvwgetstr win y x &str RETURN str
Xmvwin win y x
Xmvwinch win y x RETURN resint
Xmvwinsch win y x ch
X# napms ms
X# newpad num_lines num_cols RETURN reswin
Xnewwin num_lines num_cols y x RETURN reswin
Xnl
Xnocbreak
X# nodelay win flag
Xnoecho
Xnonl
Xnoraw
Xoverlay win1 win2
Xoverwrite win1 win2
X# pnoutrefresh pad pminrow pmincol sminrow smincol smaxrow smaxcol
X# prefresh pad pminrow pmincol sminrow smincol smaxrow smaxcol
Xraw
Xrefresh
X# resetterm
Xresetty
X# saveterm
Xsavetty
Xscroll win
Xscrollok win flag
X# setscrreg top bot
Xstandend
Xstandout
Xsubwin win num_lines num_cols y x RETURN reswin
Xtouchwin win
X# typeahead fd
Xunctrl chint RETURN resstr
Xwaddch win ch
Xwaddstr win str
X# wattroff win attrs
X# wattron win attrs
X# wattrset win attrs
Xwclear win
Xwclrtobot win
Xwclrtoeol win
Xwdelch win
Xwdeleteln win
Xwerase win
Xwgetch win RETURN resint
Xwgetstr win &str RETURN str
Xwinch win RETURN resint
Xwinsch win ch
Xwinsertln win
Xwmove win y x
X# wnoutrefresh win
Xwrefresh win
X# wsetscrreg win top bot
Xwstandend win
Xwstandout win
X# END curses
END_OF_FILE
if test 2608 -ne `wc -c <'cdefs.in.SUN'`; then
    echo shar: \"'cdefs.in.SUN'\" unpacked with wrong size!
fi
# end of 'cdefs.in.SUN'
fi
if test -f 'cdefs.mk' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cdefs.mk'\"
else
echo shar: Extracting \"'cdefs.mk'\" \(4900 characters\)
sed "s/^X//" >'cdefs.mk' <<'END_OF_FILE'
X#! /local/bin/perl
X
Xdo 'cdefs.types' ;
X
Xunlink('cdefs.c') ;
Xunlink('cdefs.pl') ;
Xopen(STDIN,'cdefs.in') || die 'can\'t open cdefs.in' ; 
Xopen(C,'>cdefs.c')     || die 'can\'t write cdefs.c' ;
Xopen(P,'>cdefs.pl')    || die 'can\'t write cdefs.pl' ;
X
X$curdef = '0' ;
X$sep = "\\034" ;
X
Xprint C "#include <stdio.h>\n" ;
Xprint C "#include <curses.h>\n" ;
Xprint C "#include \"cursesX.h\"\n" ;
Xprint C "#include \"defs.h\"\n" ;
Xprint C "\n" ;
Xfor ( sort keys %type )
X  { if ( $type{$_} eq 'int' )
X      { print C "static int $_ ;\n" ; }
X    elsif ( $type{$_} eq 'char' )
X      { print C "static char $_ ;\n" ; }
X    elsif ( $type{$_} eq 'str' )
X      { print C "static char $_\[BUFSIZE] ;\n" ; }
X    elsif ( $type{$_} eq 'win' )
X      { print C "static WINDOW *$_ ;\n" ; }
X  }
Xprint C "static int res ;\n" ;
Xprint C "\n" ;
X
Xwhile ( $_ = <STDIN> )
X  { chop ;
X    next if $_ =~ /^[ \t]*$/ || /^#/ ;
X    @ret = () ;
X    @arg = () ;
X    $varargs = 0 ;
X    $arg = '' ;
X    $body = '' ;
X    $form = '' ;
X    @_ = split ;
X    $func = shift @_ ;
X    push(@func,$func) ;
X    print C "void do_$func() {\n" ;
X    print C "  addlogs(LOGCURS1,\"$func\") ;\n" ;
X    print P "# $_\n" ;
X    print P "\$curfun{'$func'} = '$_' ;\n" ;
X    print P "sub $func {\n" ;
X    $form = "$curdef$sep" ;
X    for ( $i = 0 ; $i <= $#_ ; $i++ )
X      { $arg = $_[$i] ;
X	if ( $type{$arg} eq 'char' )
X          { $form .= "%c$sep" ;
X            print C "  $arg = nextChr() ;\n" ;
X	  }
X	elsif ( $type{$arg} eq 'str' )
X          { $form .= "%s$sep" ;
X            print C "  strcpy($arg,nextStr()) ;\n" ;
X	  }
X	elsif ( $type{$arg} eq 'int' )
X          { $form .= "%d$sep" ;
X            print C "  $arg = nextInt() ;\n" ;
X	  }
X	elsif ( $type{$arg} eq 'win' )
X          { $form .= "%d$sep" ;
X            print C "  $arg = windows[nextInt()] ;\n" ;
X	  }
X	elsif ( $type{$arg} eq 'var' )
X          { $arg =~ s/^&(.*)/$1/ ;
X	    $varargs++ ;
X	  }
X	elsif ( $arg eq 'RETURN' )
X	  { @ret = @_[$i+1..$#_] ;
X	    last ;
X	  }
X	elsif ( $arg eq 'FLUSH' )
X	  { last ; }
X	else
X	  { print "unknown argument $arg in $_\n" ; }
X	push(@arg,$arg) ;
X      }
X
X    if ( $#arg - $varargs < 0 )
X      { print P "  print(\"$form\") ;\n" ; }
X    elsif ( $#arg - $varargs == 0 )
X      { print P "  printf(\"$form\",\$_[0]) ;\n" ; }
X    else
X      { print P "  printf(\"$form\",\@_) ;\n" ; }
X
X    if ( $#ret >= 0 )
X      { print P '  local($', join(',$',@ret), ") ;\n" ; }
X
X    if ( $func eq 'initscr' )
X      { print C "  initscr() ;\n" ;
X	print C "  hasWin = 1 ;\n" ;
X	print C "  initWindows() ;\n" ;
X	print C "  saveWindow(stdscr) ;\n" ;
X	print C "  saveWindow(curscr) ;\n" ;
X	print C "  initCursesX() ;\n" ;
X	$body .= "  \$stdscr = 0 ;\n" ;
X	$body .= "  \$curscr = 1 ;\n" ;
X	$body .= "  \$LINES = &getLINES ;\n" ;
X	$body .= "  \$COLS = &getCOLS ;\n" ;
X      }
X    elsif ( $func eq 'endwin' )
X      { print C "  endwin() ;\n" ;
X	print C "  hasWin = 0 ;\n" ;
X        $body .= "  &curFlush ;\n" ;
X      }
X    elsif ( $func eq 'delwin' )
X      { print C "  win = windows[$arg] ;\n" ;
X        print C "  unsaveWindow($arg) ;\n" ;
X        print C "  delwin(win) ;\n" ;
X      }
X    elsif ( $arg eq 'RETURN' )
X      { $body .= "  &curFlush ;\n" ;
X	@res = grep(/^res(int|str|win)$/,@ret) ;
X        if ( $#res > 0 )
X	  { print "$_ : you may specify res... only once\n" ; }
X        elsif ( $#res == 0 )
X	  { if ( $type{$res[0]} eq 'str' )
X	      { print C "  strcpy($res[0],$func(". join(',',@arg) . ")) ;\n" ; }
X	    else
X	      { print C "  $res[0] = $func(". join(',',@arg) . ") ;\n" ; }
X	  }
X	else
X	  { print C "  $func(". join(',',@arg) . ") ;\n" ; }
X        for $ret ( @ret )
X	  { $body .= "  \$$ret = <STDIN> ; chop(\$$ret) ;\n" ;
X	    if ( $type{$ret} eq 'str' )
X	      { print C "  fprintf(OUT,\"%s\\n\",$ret) ;\n" ;
X	        print C "  addlogss(LOGCURS1," ;
X		print C "\"do_$func prints OUT\",$ret) ;\n" ;
X	      }
X	    elsif ( $type{$ret} eq 'win' )
X	      { print C "  res = saveWindow($ret) ;\n" ;
X	        print C "  fprintf(OUT,\"%d\\n\",res) ;\n" ;
X	        print C "  addlogsn(LOGCURS1," ;
X		print C "\"do_$func prints OUT\",res) ;\n" ;
X	      }
X	    elsif ( $type{$ret} eq 'int' )
X	      { print C "  fprintf(OUT,\"%d\\n\",$ret) ;\n" ;
X	        print C "  addlogsn(LOGCURS1," ;
X		print C "\"do_$func prints OUT\",$ret) ;\n" ;
X	      }
X	    else
X	      { print "I have no type for $ret\n" ; }
X	  }
X	print C "  fflush(OUT) ;\n" ;
X        $body .= '  return $'. join(', $',@ret) . "  ;\n" ;
X      }
X    elsif ( $arg eq 'FLUSH' )
X      { $body .= "  &curFlush ;\n" ;
X        print C "  $func(". join(',',@arg) . ") ;\n" ;
X      }
X    else
X      { print C "  $func(". join(',',@arg) . ") ;\n" ; }
X
X    print P $body, "}\n" ;
X    print C "}\n" ;
X    $curdef++ ;
X  }
X
Xprint P "\n1 ;\n" ;
X
Xprint C "void (*(funtab[$curdef]))() ;\n" ;
Xprint C "void init_funtab() {\n" ;
X$i = 0 ;
Xfor $func ( @func )
X  { print C "  funtab[$i] = do_$func ;\n" ;
X    $i++ ;
X  }
Xprint C "}\n" ;
END_OF_FILE
if test 4900 -ne `wc -c <'cdefs.mk'`; then
    echo shar: \"'cdefs.mk'\" unpacked with wrong size!
fi
chmod +x 'cdefs.mk'
# end of 'cdefs.mk'
fi
if test -f 'cdefs.types' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cdefs.types'\"
else
echo shar: Extracting \"'cdefs.types'\" \(1134 characters\)
sed "s/^X//" >'cdefs.types' <<'END_OF_FILE'
X$type{'win'}       = 'win' ;
X$type{'win1'}      = 'win' ;
X$type{'win2'}      = 'win' ;
X$type{'reswin'}    = 'win' ;
X$type{'resint'}    = 'int' ;
X$type{'delw'}      = 'int' ;
X$type{'curpos'}    = 'int' ;
X$type{'x'}         = 'int' ;
X$type{'y'}         = 'int' ;
X$type{'attrs'}     = 'int' ;
X$type{'flag'}      = 'int' ;
X$type{'xlen'}      = 'int' ;
X$type{'ms'}        = 'int' ;
X$type{'fd'}        = 'int' ;
X$type{'pad'}       = 'int' ;
X$type{'top'}       = 'int' ;
X$type{'bot'}       = 'int' ;
X$type{'pminrow'}   = 'int' ;
X$type{'pmincol'}   = 'int' ;
X$type{'sminrow'}   = 'int' ;
X$type{'smincol'}   = 'int' ;
X$type{'smaxrow'}   = 'int' ;
X$type{'smaxcol'}   = 'int' ;
X$type{'oldrow'}    = 'int' ;
X$type{'oldcol'}    = 'int' ;
X$type{'newrow'}    = 'int' ;
X$type{'newcol'}    = 'int' ;
X$type{'num_lines'} = 'int' ;
X$type{'num_cols'}  = 'int' ;
X$type{'chint'}     = 'int' ;
X$type{'ch'}        = 'char' ;
X$type{'vert'}      = 'char' ;
X$type{'hor'}       = 'char' ;
X$type{'str'}       = 'str' ;
X$type{'rep'}       = 'str' ;
X$type{'resstr'}    = 'str' ;
X$type{'&str'}      = 'var' ;
X$type{'&y'}        = 'var' ;
X$type{'&x'}        = 'var' ;
END_OF_FILE
if test 1134 -ne `wc -c <'cdefs.types'`; then
    echo shar: \"'cdefs.types'\" unpacked with wrong size!
fi
# end of 'cdefs.types'
fi
if test -f 'cterm.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cterm.1'\"
else
echo shar: Extracting \"'cterm.1'\" \(16725 characters\)
sed "s/^X//" >'cterm.1' <<'END_OF_FILE'
X.TH CTERM 1 "" "Department of Computer Science, RUU"
X.SH NAME
Xcterm, cterm.pl \- curses terminal emulation (for perl)
X.SH SYNOPSIS
X.B cterm
X.I in out
X[
X.I options
X] [
X.I logfile
X[
X.I loglevel
X] ]
X
X.B cterm.pl
X.SH DESCRIPTION
X.PP
X.B Cterm
Xemulates a curses terminal.
XOn filedescriptor
X.I in
Xit expects curses functions+arguments in the format described below.
XOn filedescriptor
X.IR out,
Xsome functions (like getch()) pass back results.
XCterm should only be forked by other programs after the proper pipes have
Xbeen set up.
X
XThere are currently no documented
X.I options
X(see also the section on undocumented features).
X
XAs optional arguments to cterm, the name of a
X.I logfile
Xand a
X.I loglevel
Xmay be specified.
XLoglevel 0 only logs strings provided by the application through
Xthe curses extension
X.BR ctermlog(str) .
XLoglevel 1 logs all curses functions, arguments and results
Xhandled by cterm.
XLoglevel 2 shows even more intestines.
XDefault is loglevel 0.
X
XCterm exits in a controlled fashion when it receives signal SIGINT or SIGPIPE.
X
X.B Cterm.pl
Xis a library of perl subroutines that provides easy interaction with cterm.
XCterm.pl defines perl-counterparts for almost all curses functions,
Xtables with curses defined constants,
Xand subroutines for starting and finishing cterm.
X
X.SH Communication between cterm.pl and cterm
X
XThe cterm.pl subroutine
X.B &startCterm()
Xsets up two (pair of) pipes, forks and execs cterm.
XIn the parent (perl application) STDIN and STDOUT are redirected to the pipes.
XIn the child (cterm) the pipes are connected to filedescriptors
X.I out
Xand
X.IR in .
XSubroutine
X.B &finishCterm()
Xfinishes cterm and restores STDIN and STDOUT again.
X
XFor the pupose of communication between cterm.pl and cterm,
Xeach curses function supported in the interface is given a number.
XA curses routine in cterm.pl prints this number on STDOUT
Xfollowed by its parameters.
XFunction numbers and parameters are separated by character 034
X(ASCII FS), the default value for
X.BR $; .
XWhen results are required they are read in from STDIN and
Xreturned to the caller.
XCterm reads the numbers from
X.I in
Xand calls appropriate functions which in turn read arguments from
X.I in
Xand perform the required curses functions.
XResults are written to
X.IR out ,
Xeach on a new line.
X
XCterm always flushes
X.I out
Xafter writing results to it.
XCterm.pl can be used with $|=0 in applications.
XAll curses subroutines in cterm.pl that need to return results,
Xflush STDOUT before reading the results from STDIN.
XThis implies for instance that the screen always gets up to date
Xwhen user input is requested.
XA curses extension
X.B frefresh
X(flush/refresh) does a normal refresh but also flushes STDOUT when
X.B $flushOn
Xis set.
XIf you always use frefresh you can set $flushOn in parts
Xof the application where you are willing to pay the price for
Xa higher flush-rate in order to get a more accurate presentation.
XWith subroutine
X.B &curFlush()
Xthe user can actively flush STDOUT.
X
XIn order to access curses defined constants, cterm.pl defines two tables:
X.B %curcon
Xand
X.BR %curkey .
XAssociative array %curcon contains entries like
X('KEY_UP',259) and ('A_BLINK',1024),
Xso curses constants (as strings) map to their value.
XAssociative array %curkey contains the inverse of %curcon
Xrestricted to KEY-codes.
XSo, for example, $curkey{259} = 'KEY_UP' if $curcon{'KEY_UP'} = 259.
XThe contents of %curcon and %curkey differ from system to system.
XThey are created during installation.
XThe KEY-associations (KEY_TAB,9) and (KEY_RET,13) are always defined.
X
XVariables
X.BR $LINES ,
X.BR $COLS ,
X.B $stdscr
Xand
X.B $curscr
Xare set by &initscr.
X
X.SH Arguments and results, representation
X
XLike in curses, in cterm.pl characters are really integers.
XSo, for instance,
X.B &addch(c)
Xshould be provided with an integer and
X.B &getch
Xsupplies one.
X
XWindows are really pointers in curses.
XSince mixing pointers and integers is potentially dangerous
X(espcially printing and reading them in again)
Xan indirection is introduced.
XCterm stores the result of curses functions returning windows
Xin a table and returns the index in the table to cterm.pl.
XWhen curses returns window NULL, cterm returns -1.
XSubroutine
X.B &delwin(win)
Xdeletes the window and the entry in the table.
XSubroutine
X.B &initscr
Xclears the table and sets variables
X.B $stdscr
Xand
X.BR $curscr.
X
XString arguments are printed on STDOUT as they are handed to cterm.pl.
XThings break if a string contains character 034 (ASCII FS)
Xbecause cterm will get out of sync.
XNo mechanism was implemented to check and/or repair synchronization.
X
XCurses subroutines in cterm.pl return values by result
Xand not by modifying parameters.
XThe 'return-parameters' may be omitted in the call.
XThis implies that for instance
X.B getyx
Xshould be called like '($a,$b) = &getyx($win)',
Xalthough in C one would write 'getyx(win,a,b)'.
XThe same holds for the
X.B getstr
Xfunction family.
X
XCurses subroutines in cterm.pl don't check their parameters,
Xthey just pass 'em on.
X
X.SH Using cterm
X
XCterm is started up with
X.B &startCterm()
Xand finished with 
X.BR &finishCterm .
XIn addition to proper values for
X.I in
Xand
X.IR out ,
Xall arguments of startCterm are passed as arguments to the exec'ed cterm.
XSo, if cterm logging is required, the name of the logfile
Xshould be passed as an argument to startCterm.
XIf cterm should log internals too, an integer loglevel greater than 0
Xshould be passed as well.
XVariable
X.B $ctermPid
Xholds the pid of the forked cterm process.
XSince cterm only performs curses calls, one usually has to go through
Xthe customary proceedings: &initscr ; &nonl ; &cbreak ; &noecho.
XSubroutine endwin() should be called before finishing cterm.
X.br
XIf the perl application does not call finishCterm before exit'ing,
Xas in the case of a runtime error, cterm can't reset the terminal
Xand hangs.
XThis is a nuisance.
XWhen
X.B &safeCterm
Xis called before &startCterm, cterm will be exec'ed in the parent process.
XThis has the advantage that cterm wil always cleanup when the
Xperl application suddenly dies.
XThe disadvantage is that the application has no control over the terminal
Xafter &finishCterm because the shell takes over when cterm exits.
XIt should be used while developing that part of the application that
Xruns between &startCterm and &finishCterm.
X
XSubroutine
X.B ch2str(c)
Xtakes an integer argument
X.I c
Xand, depending on its value,
Xreturns a string consisting of the correspondig ASCII character,
Xor a string like 'KEY_LEFT' or 'KEY_HOME' if
X.I c
Xis a KEY-code in curses,
Xor the argument otherwise.
XThe subroutine
X.B getchint()
Xis defined as
X.BR ch2str(&getch()) .
XThe KEY-associations (KEY_TAB,9) and (KEY_RET,13) are always defined.
X
XSubroutine
X.B clrreg(top,bot)
Xclears the screen from lines
X.I top
Xto
X.IR bot .
XSubroutine
X.B wclrreg(win,top,bot)
Xclears window
X.I win
Xfrom
X.I top
Xto
X.IR bot .
X
XSubroutine
X.B ctermlog(str)
Xadds string
X.I str
Xto the cterm logfile if one was specified in &startCterm().
X
XAssociative array
X.B %curcon
Xmaps curses constants (as strings) to their (integer) values.
XThe contents of %curcon is determined by the installer.
X
XAssociative array
X.B %curkey
Xmaps curses KEY-codes (as strings) to their integer values.
XIt is the inverse of %curcon restricted to keys matching /^KEY/.
XThe contents of %curkey is determined by the installer.
X
XAssociative array
X.B %curfun
Xmaps curses functions (as strings) in the cterm interface
Xto a string listing their parameters and results (if any).
XTable %curfun can be used to determine if a curses function is available.
XThe installer determines which functions are supported in the interface.
X
XFunction
X.B edit(str,curpos,y,x,xlen,rep)
Xreturns
X.B (str,quitkey)
Xand constitutes a local edit mode of cterm.
XThe subroutine allows one to edit a string (initially
X.IR str ).
XIt shows (part of) the string in an edit window
Xin line
X.I y
Xusing
X.I xlen
Xcolumns, starting from column
X.IR x .
XThe initial cursor position in
X.I str
Xis
X.IR curpos .
XEdit-mode is left and the resulting string returned to the caller
Xwhen a 'special' is typed in.
XThe set of 'special' characters can be specified as follows.
XFunction
X.B editreset()
Xclears the set.
XFunction
X.B editq(chint)
Xadds a character (supply an int) to the set.
XThe 'special' character (really an int)
Xwhich caused edit() to leave is returned to the caller too.
X.br
XEdit facilities are limited.
XArrow-left and arrow-right work if keypad is enabled.
XTyping in 'Kill' (as defined by curses killchar())
Xwill delete the character pointed to by the cursor.
XTyping in 'Erase' (as defined by curses erasechar())
Xwill delete the character left of the cursor.
XWhen the cursor points to the first character in
X.I str
Xand 'Erase' is typed in, 
X.I str
Xwill be swapped with an initially empty save-buffer.
XIt can be used to present a user with a default wich he/she
Xcan edit or discard by typing 'Erase'.
XPrintable ASCII characters are inserted.
XAll others are rejected.
X.br
XArgument
X.I rep
Xmust be a string of four characters.
XThey are used by edit to indicate which part of
X.I str
Xis shown on the screen.
XOne of the first two characters in
X.I rep
Xis shown in the first column of the edit window.
XOne of the last two characters in
X.I rep
Xis shown in the last column of the edit window.
XEdit can only use
X.I xlen-2
Xcolumns to present (part of)
X.IR str .
XFor the sake of simplicity, let us assume that
X.IR rep ='[<>]'.
XIf lenght(\fIstr\fP)<=\fIxlen-2\fP, then
X.I str
Xis shown on the screen like '[\fIstr\fP]'.
XIf lenght(\fIstr\fP)>\fIxlen-2\fP, then
Xonly a substring
X.I sub
Xof
X.I str
Xcan be shown on the screen.
XIf
X.I sub
Xis a prefix of
X.I str
Xthen it is shown like '[\fIsub\fP>'.
XIf it is a suffix it is shown like '<\fIsub\fP]'.
XIt is shown like '<\fIsub\fP>' otherwise.
X.br
XThe cursor position will be held at the middle of the edit window
Xif
X.I sub
Xis neither a prefix nor a suffix of
X.IR str .
X.br
XSubroutine
X.B wedit(win,str,curpos,y,x,xlen,rep)
Xdoes edit() in a window.
X
XSubroutine
X.B editreset()
Xclears the set of 'special' characters (see edit()).
X
XSubroutine
X.B editq(chint)
Xadds a character (supply an int)
X.I chint
Xto the set of 'special' characters (see edit()).
X
XSubroutine
X.B endwin()
Xflushes STDOUT.
X
XSubroutine
X.B frefresh()
Xdoes a refresh.
XSTDOUT is flushed if
X.B $flushOn
Xis set.
X
XFunction
X.B getstr(str)
Xshould be called like '$str = &getstr',
Xmvgetstr(str) should be called like '$str = &mvgetstr($y,$x)',
Xand mvwgetstr, wgetstr likewise.
X
XFunction
X.B getyx
Xshould be called like '($a,$b) = &getyx($win)'.
X
XFunction
X.B getchR()
Xand
X.B wgetchR(win)
Xact like getch() but redraw the screen if ^L is entered.
XThey do getch's until a non-^L is found.
X
XSubroutine
X.B initscr()
Xsets $LINES and $COLS and
Xforgets about all windows except stdscr and curscr.
X
XSubroutine
X.B refresh()
Xdoes not flush STDOUT (see also &frefresh()).
X
XSubroutine
X.B show(str,curpos,y,x,xlen,rep)
Xshows
X.I str
Xon the screen like edit initially would.
XIt is handy in applications that are to be independent of the value of COLS.
X.br
XSubroutine
X.B wshow(win,str,curpos,y,x,xlen,rep)
Xdoes show() in a window.
X
X.SH Omissions and limitations
XImplementations of curses differ a lot.
XA few curses functions that are available on some
Xsystems are not supported in this distribution.
XSome were documented as obsolete, some are meaningless in this application.
XThe ones which take a variable number of arguments don't fit
Xthe interface model and can be done in perl more easily anyway.
XSome are left out because the author was unable to understand what
Xthey were supposed to do.
XUse %curfun to find out which curses functions are supported in the interface.
X
XWhich constants go in %curcon and %curkey is determined by the installer.
X
XAs distributed, the size of the window table is 100.
XThe size of the set of 'special' characters for edit() is 1000.
XStrings passed to cterm shouldn't be larger than 10K.
X
X.SH Installation
XEdit the 'Makefile' in the source directory.
XDefine BINDIR to be a directory were exec usually looks for executables.
XDefine PERLLIB to be a directory where perl's do-statement
Xlooks for libraries to include.
XThe Makefile variables EDIT_LEFT, EDIT_RIGHT and BEEP are passed to edit.c.
XThey are used in edit().
XWhen user input equals EDIT_LEFT (EDIT_RIGHT), edit() moves the
Xcursor left (right).
XIf your curses recognizes arrow-keys, define EDIT_LEFT (EDIT_RIGHT) to
Xwhatever curses getch() returns if the user types in arrow-left (arrow-right).
XIf not, define EDIT_LEFT as 2 (^B for Back)
Xand EDIT_RIGHT as 6 (^F for Forward).
XYou may also comment them out entirely.
X.br
XBEEP is the function that is used to signal edit errors to the user.
XSet it to 'beep' (sound bell) if your curses supports it.
XSet it to 'mybeep' if you have nothing better.
XIt writes ^G to stderr.
XYou may want to change the implementation of 'mybeep' in cursesX.c.
XFunction 'nobeep' is defined and does nothing.
XIt is used if you don't define BEEP.
X
XRun 'make' to generate the necessary stuff.
XDon't worry about warnings from 'curcon.mk'.
XThey simply mean that not all the curses constants suggested
Xin 'curcon.in' are available on your system.
XYou might want to try the perl programs 'try1' and 'try2' before
Xinstalling.
XArguments to try1 and try2 are passed to startCterm and thus to cterm.
X
XRunning 'make install' will copy the stuff to the designated directories.
XRunning 'make clean' will remove temporaries.
XRunning 'make realclean' will remove all generated stuff.
X
XThe author has tried to make the system adaptable to local conditions.
XThere are two files that the installer can modify.
X.br
XThe file
X.B cdefs.in
Xis the input for cdefs.mk which generates the interface between
Xcterm and cterm.pl: cdefs.c and cdefs.pl.
XIt contains one line for each curses function which is supported in the
Xinterface.
XIt specifies the name of the function and the parameters that are
Xto be passed from cterm.pl to cterm, and in some cases the results
Xthat are to be passed back.
XIf your curses doesn't support some of them, simply comment them
Xout ('#' in the first column).
XIf there is a problem with something in the 'extensions' or 'extra's',
Xplease contact the author.
XCreate your own minicurses if you think it is all too baroque.
XOn a Sun, try to use the SYSV C compiler (/usr/5bin/cc on my sun).
XIt provides a better curses.
XThe file
X.B cdefs.in.SUN
Xcontains a severely stripped version of cdefs.in that makes cterm run on
Xmy standard SunOs.4.0.3 C compiler.
X.br
XThe file
X.B curcon.in
Xis the input for curcon.mk which generates curcon.c which
Xdefines the contents of %curcon and %curkey in file curcon.pl.
XCurcon.in is a wishlist.
XComment out constants that are not defined and add others that are.
XAs distributed, 10 function keys are defined in the way they should be
Xon some systems.
X
XIf you want to add functionality, define more functions in cdefs.in.
XLook at other functions and cdefs.types to see how parameters and results
Xare to be specified.
XIf you define a function, add an implementation for it in cursesX.c.
XFor an example, look at
X.IR clrreg .
XFunction initscr() calls initCursesX().
XThis is the place to put initialisation stuff for curses additions.
X
X.SH "Author's note"
XI developed cterm as part of a perl project called 'jinx'.
XJinx is a simple, not-quite-relational database system.
XIt seemed more practical to have a weak implementation of 'full curses'
Xin stead of a strong, tested implementation of an ad hoc subset of curses.
XIn jinx I have sofar used only some of the curses facilities.
XThe newwin and subwin stuff has not been tried a lot.
XI've never tried to set up a multi-terminal application.
XI want to get it right though, so complaints will be honored.
X.br
XFor the future I have a wishlist.
XI would like to also have sockets for communication available.
XI have never used sockets before so I don't see any problems.
XA simple synchronisation mechanism would be easy to implement,
Xbut I never have problems in that area.
XI guess I don't know how serious the FS-in-strings problem is.
XIt should be possible to tell cterm how to handle signals while it runs.
XCterm should more often be able to reset the terminal.
X.br
XThanks go to Piet van Oostrum (piet@cs.ruu.nl) for his harsh criticism
Xand willingness to discuss technicalities.
X
X.SH Undocumented features
X
XIf you supply option
X.BR -X ,
Xtyping ^X to getchR (and wgetchR) will get you IO statistics in line 0.
XUse it to see how much setting $flushOn or $| are costing you
Xin context switches.
XThe curses extension quitcterm makes cterm quit.
XIt is used by finishCterm.
X
X.SH BUGS
X
XAs explained above, arguments of subroutines in cterm.pl
Xshould never contain ASCII character 034 (FS).
XFS is used as a separator on the info stream from cterm.pl to cterm.
X
X.SH AUTHOR
XHenk P. Penning (henkp@cs.ruu.nl), Department of Computer Science,
XUtrecht University, the Netherlands.
END_OF_FILE
if test 16725 -ne `wc -c <'cterm.1'`; then
    echo shar: \"'cterm.1'\" unpacked with wrong size!
fi
# end of 'cterm.1'
fi
if test -f 'cterm.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cterm.c'\"
else
echo shar: Extracting \"'cterm.c'\" \(4646 characters\)
sed "s/^X//" >'cterm.c' <<'END_OF_FILE'
X#include <curses.h>
X#include "cursesX.h"
X#include <signal.h>
X#include <stdio.h>
X#include "defs.h"
X
XFILE *OUT ;
XWINDOW *windows[MAXNUMWINDOWS] ;
Xint optX = 0, hasWin = 0 ;
X
Xstatic int hasOUT = 0 ;
Xstatic FILE *LOG ;
Xstatic int in = -1, out = -1 ;
Xstatic int n, loglevel = -1 ;
Xstatic char com[BUFSIZE], buf[BUFSIZE] ;
Xstatic int comSize = 0, bufSize = 0, bufhead = 0, buftail = 0 ;
Xstatic int numread = 0, numreads = 0 ;
Xstatic char outstr[1024] ;
X
XcurStat()
X{ int n,i,y,x ;
X  char s[80] ;
X
X  sprintf(s,"reads %d, read %d, average %d",numreads,numread,numread/numreads) ;
X  getyx(stdscr,y,x) ;
X  mvinsch(0,0,'|') ;
X  for (i=strlen(s)-1 ; i>=0 ; i--)
X    { mvinsch(0,0,s[i]) ; }
X  move(y,x) ;
X  refresh() ;
X}
X
Xvoid redraw()
X{ int i ;
X
X  for ( i = 0 ; i < MAXNUMWINDOWS ; i++ )
X    if ( ( windows[i] != NULL ) && ( windows[i] != curscr ) )
X      { clearok(windows[i],1) ;
X        wrefresh(windows[i]) ;
X      }
X}
X
Xvoid addlogs(level,s)
Xint level ;
Xchar *s ;
X{ if ( level <= loglevel )
X    { fprintf(LOG,"%s\n",s) ;
X      fflush(LOG) ;
X    }
X}
X
Xvoid addlogsn(level,s,n)
Xint level ;
Xchar *s ;
Xint n ;
X{ if ( level <= loglevel )
X    { fprintf(LOG,"%s %d\n",s,n) ;
X      fflush(LOG) ;
X    }
X}
X
Xvoid addlogss(level,s1,s2)
Xint level ;
Xchar *s1, *s2 ;
X{ if ( level <= loglevel )
X    { fprintf(LOG,"%s %s\n",s1,s2) ;
X      fflush(LOG) ;
X    }
X}
X
Xvoid quit()
X{ addlogs(LOGCURS1,"quit") ;
X  if ( hasWin ) { addlogs(LOGCURS1,"endwin") ; endwin() ; }
X  if ( hasOUT ) fclose(OUT) ; else close(out) ;
X  addlogs(LOGCURS1,"gone") ;
X  exit(1) ;
X}
X
Xvoid sig_quit()
X{ addlogs(LOGCURS1,"sig_quit") ;
X  quit() ;
X}
X
Xint incMod(x,y) int *x, y ; { *x = ((*x)+1) % y ; return(*x) ; }
X
Xint isemptyq() { return(bufSize == 0) ; }
X
Xvoid enqueue(c)
Xchar c ;
X{ buf[buftail] = c ; bufSize++ ; incMod(&buftail,BUFSIZE) ; }
X
Xint dequeue()
X{ char c ;
X  c = buf[bufhead] ; bufSize-- ; incMod(&bufhead,BUFSIZE) ; return(c) ;
X}
X
Xint getCom()
X{ int res, c, i, found ;
X  char row[BUFSIZE2] ;
X  char mes[100] ;
X
X  res = 1 ;
X  found = 0 ;
X  comSize = 0 ;
X
X  do { c = 'x' ;
X       while ( ( !isemptyq() ) && ( (c = dequeue()) != SEP ) )
X	 { com[comSize++] = c ; }
X       if (c == SEP)
X	 { com[comSize] = 0 ;
X	   found = 1 ;
X	 }
X       else
X	 { res = read(in,row,BUFSIZE2) ;
X	   if (res < 0)
X	     { addlogs(LOGCURS1,"read error") ;
X	       quit() ;
X	     }
X	   if ( res )
X             { numread += res ;
X	       numreads++ ;
X	       for (i=0 ; i<res ; i++)
X                 { enqueue(row[i]) ; }
X             }
X	   else
X	     { addlogs(LOGCURS1,"read 0 chars") ;
X	       found = 1 ;
X	     }
X	 }
X     }
X  while ( ! found ) ;
X
X  addlogs(LOGCURS2,com) ;
X
X  return(res) ;
X}
X
Xint nextInt()
X{ int n ;
X  if ( ! getCom() ) quit() ;
X  sscanf(com,"%d",&n) ;
X  addlogsn(LOGCURS1,"nextInt",n) ;
X  return(n) ;
X}
X
Xint nextCom()
X{ int n ;
X  if ( ! getCom() ) quit() ;
X  sscanf(com,"%d",&n) ;
X  addlogsn(LOGCURS2,"nextCom",n) ;
X  return(n) ;
X}
X
Xint nextChr()
X{ int c = 0 ;
X  if ( ! getCom() ) quit() ;
X  addlogsn(LOGCURS1,"nextChr",com[0]) ;
X  return(com[0]) ;
X}
X
Xchar *nextStr()
X{ if ( ! getCom() ) quit() ;
X  addlogss(LOGCURS1,"nextStr",com) ;
X  return(&(com[0])) ;
X}
X
Xvoid initWindows()
X{ int i ;
X  for ( i = 0 ; i < MAXNUMWINDOWS ; i++ )
X    { windows[i] = NULL ; }
X}
X
Xvoid unsaveWindow(i) int i ; { windows[i] = NULL ; }
X
Xint saveWindow(w)
XWINDOW *w ;
X{ int i ;
X  for ( i = 0 ; i < MAXNUMWINDOWS && windows[i] != NULL ; i++ ) { ; }
X  if ( i < MAXNUMWINDOWS )
X   { windows[i] = w ; return(i) ; }
X  else
X    { delwin(w) ; return(-1) ; }
X}
X
Xmain(argc,argv)
Xint argc ;
Xchar **argv ;
X{ int c ;
X  char *prog ;
X
X  prog = argv[0] ; argv++ ; argc-- ;
X
X  if ( argc < 2 )
X    { fprintf(stderr,"Usage: %s in out [options] [logfile [level]]\n",prog) ; 
X      exit(1) ;
X    } 
X  else
X    { in  = atoi(*argv) ; argc-- ; argv++ ;
X      out = atoi(*argv) ; argc-- ; argv++ ;
X    }
X
X  while ( ( argc > 0 ) && ( argv[0][0] == '-' ) )
X    { switch ( argv[0][1] ) {
X      case 'X' : optX = 1 ;
X		 break ;
X      case 0   : fprintf(stderr,"unknown option %s\n", "-") ; 
X	         exit(1) ;
X		 break ;
X      default  : fprintf(stderr,"unknown option %c\n", argv[0][1]) ; 
X	         exit(1) ;
X		 break ;
X      }
X      argc-- ; argv++ ;
X    }
X
X  if ( argc > 0 )
X    { LOG = fopen(*argv,"w") ;
X      if ( LOG == NULL )
X	{ fprintf(stderr,"cannot open log file %s\n", *argv) ; 
X	  exit(1) ;
X	} 
X      argc-- ; argv++ ;
X    }
X  if ( argc > 0 )
X    { loglevel = atoi(*argv) ; }
X  else
X    { loglevel = 0 ; } 
X
X  signal(SIGINT,sig_quit) ;
X  signal(SIGPIPE,sig_quit) ;
X
X  OUT = fdopen (out,"w") ; hasOUT++ ;
X
X  addlogsn(LOGCURS1,"option X",optX) ;
X
X  init_funtab() ;
X
X  while (1)
X    { n = nextCom() ;
X      (*(funtab[n]))() ;
X    }
X
X}
END_OF_FILE
if test 4646 -ne `wc -c <'cterm.c'`; then
    echo shar: \"'cterm.c'\" unpacked with wrong size!
fi
# end of 'cterm.c'
fi
if test -f 'cterm.pl' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cterm.pl'\"
else
echo shar: Extracting \"'cterm.pl'\" \(1958 characters\)
sed "s/^X//" >'cterm.pl' <<'END_OF_FILE'
X#! /local/bin/perl
X
Xdo 'cdefs.pl'  || die "cterm.pl can't include cdefs.pl\n" ;
Xdo 'curcon.pl' || die "cterm.pl can't include curcon.pl\n" ;
X
Xsub curFlush
X  { $oldpipe = $| ;
X    $| = 1 ;
X    print "" ;
X    $| = $oldpipe ;
X  }
X
Xsub frefresh { &refresh ; &curFlush if $flushOn ; }
X
Xsub ch2str
X  { local($c) = shift ;
X    if ( (31 < $c) && ($c < 128) )
X      { return(sprintf("%c", $c)) ; }
X    elsif ( defined $curkey{$c} )
X      { return($curkey{$c}) ; }
X    else
X      { return($c) ; }
X  }
X
Xsub getchint { return &ch2str(&getch) ; }
X
Xsub safeCterm { $safeCterm = 1 ; }
X
Xsub startCterm
X  { pipe(CURIN,PERLOUT) || die "cterm.pl can\'t create pipe CURIN/PERLOUT" ; 
X    pipe(PERLIN,CUROUT) || die "cterm.pl can\'t create pipe PERLIN/CUROUT" ; 
X
X    $ctermPid = fork ;
X
X    if ( $safeCterm ? ( $ctermPid != 0 ) : ( $ctermPid == 0 ) )
X      { close(PERLIN)  || die "cterm.pl can\'t close PERLIN" ;
X        close(PERLOUT) || die "cterm.pl can\'t close PERLOUT" ;
X        exec('cterm',fileno(CURIN),fileno(CUROUT),@_) ;
X        die 'cterm.pl can\'t exec cterm' ;
X      }
X    else
X      { close(CURIN)  || die "cterm.pl can\'t close CURIN" ;
X        close(CUROUT) || die "cterm.pl can\'t close CUROUT" ;
X        open(SAVESTDIN, "<&STDIN")  || die 'cterm.pl can\'t save STDIN' ;
X        open(SAVESTDOUT,">&STDOUT") || die 'cterm.pl can\'t save STDOUT' ;
X        open(STDIN, "<&PERLIN")     || die 'cterm.pl can\'t redirect STDIN' ;
X        open(STDOUT,">&PERLOUT")    || die 'cterm.pl can\'t redirect STDOUT' ;
X	$preCtermPipe = $| ;
X	$preCtermSelect = select(STDOUT) ;
X        $| = 0 ;
X	$flushOn = 0 ;
X      }
X  }
X
Xsub finishCterm
X  { &quitcterm ;
X    close(PERLOUT) ;
X    sleep 1 ;
X    close(PERLIN) ;
X    open(STDIN, "<&SAVESTDIN")  || die 'cterm.pl can\'t reredirect STDIN' ;
X    open(STDOUT,">&SAVESTDOUT") || die 'cterm.pl can\'t reredirect STDOUT' ;
X    close(SAVESTDIN) ;
X    close(SAVESTDOUT) ;
X    select($preCtermSelect) ;
X    $| = $preCtermPipe ;
X  }
X
X1;
END_OF_FILE
if test 1958 -ne `wc -c <'cterm.pl'`; then
    echo shar: \"'cterm.pl'\" unpacked with wrong size!
fi
chmod +x 'cterm.pl'
# end of 'cterm.pl'
fi
if test -f 'curcon.in' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'curcon.in'\"
else
echo shar: Extracting \"'curcon.in'\" \(1085 characters\)
sed "s/^X//" >'curcon.in' <<'END_OF_FILE'
XTRUE
XFALSE
XOK
XERR
XA_STANDOUT
XA_UNDERLINE
XA_REVERSE
XA_BLINK
XA_DIM
XA_BOLD
XA_ALTCHARSET
XA_INVIS
XA_PROTECT
XA_NORMAL
XA_ATTRIBUTES
XA_CHARTEXT
XKEY_BREAK
XKEY_DOWN
XKEY_UP
XKEY_LEFT
XKEY_RIGHT
XKEY_HOME
XKEY_BACKSPACE
XKEY_F0
XKEY_F(1)
XKEY_F(2)
XKEY_F(3)
XKEY_F(4)
XKEY_F(5)
XKEY_F(6)
XKEY_F(7)
XKEY_F(8)
XKEY_F(9)
XKEY_DL
XKEY_IL
XKEY_DC
XKEY_IC
XKEY_EIC
XKEY_CLEAR
XKEY_EOS
XKEY_EOL
XKEY_SF
XKEY_SR
XKEY_NPAGE
XKEY_PPAGE
XKEY_STAB
XKEY_CTAB
XKEY_CATAB
XKEY_ENTER
XKEY_SRESET
XKEY_RESET
XKEY_PRINT
XKEY_LL
XKEY_A1
XKEY_A3
XKEY_B2
XKEY_C1
XKEY_C3
XKEY_BTAB
XKEY_BEG
XKEY_CANCEL
XKEY_CLOSE
XKEY_COMMAND
XKEY_COPY
XKEY_CREATE
XKEY_END
XKEY_EXIT
XKEY_FIND
XKEY_HELP
XKEY_MARK
XKEY_MESSAGE
XKEY_MOVE
XKEY_NEXT
XKEY_OPEN
XKEY_OPTIONS
XKEY_PREVIOUS
XKEY_REDO
XKEY_REFERENCE
XKEY_REFRESH
XKEY_REPLACE
XKEY_RESTART
XKEY_RESUME
XKEY_SAVE
XKEY_SBEG
XKEY_SCANCEL
XKEY_SCOMMAND
XKEY_SCOPY
XKEY_SCREATE
XKEY_SDC
XKEY_SDL
XKEY_SELECT
XKEY_SEND
XKEY_SEOL
XKEY_SEXIT
XKEY_SFIND
XKEY_SHELP
XKEY_SHOME
XKEY_SIC
XKEY_SLEFT
XKEY_SMESSAGE
XKEY_SMOVE
XKEY_SNEXT
XKEY_SOPTIONS
XKEY_SPREVIOUS
XKEY_SPRINT
XKEY_SREDO
XKEY_SREPLACE
XKEY_SRIGHT
XKEY_SRSUME
XKEY_SSAVE
XKEY_SSUSPEND
XKEY_SUNDO
XKEY_SUSPEND
XKEY_UNDO
END_OF_FILE
if test 1085 -ne `wc -c <'curcon.in'`; then
    echo shar: \"'curcon.in'\" unpacked with wrong size!
fi
# end of 'curcon.in'
fi
if test -f 'curcon.mk' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'curcon.mk'\"
else
echo shar: Extracting \"'curcon.mk'\" \(936 characters\)
sed "s/^X//" >'curcon.mk' <<'END_OF_FILE'
X#! /local/bin/perl
X
Xopen(STDIN,'curcon.in')  || die "can't open curcon\n" ;
Xopen(STDOUT,'>curcon.c') || die "can't create curcon.c\n" ;
X
Xprint "#include <curses.h>\n" ;
Xprint "#include <stdio.h>\n" ;
Xprint "\n" ;
Xprint "main() {\n" ;
X
Xwhile ( $_ = <STDIN> )
X  { chop ;
X    next if $_ =~ /^[ \t]*$/ || $_ =~ /^#/ ;
X    $arg = ( /^(.*)\(.*\)/ ) ? $1 : $_ ;
X    print "#ifdef $arg\n" ;
X    print "  printf(\"\$curcon{'$_'} = %d ;\\n\",$_) ;\n" ;
X    if ( $_ =~ /^KEY/ )
X      { print "  printf(\"\$curkey{%d} = '$_' ;\\n\",$_) ;\n" ; }
X    print "#else\n" ;
X      { print "  fprintf(stderr,\"warning: no definition for $_\\n\") ;\n" ; }
X    print "#endif\n" ;
X  }
X
Xprint "  printf(\"\$curcon{'KEY_RET'} = %d ;\\n\",13) ;\n" ;
Xprint "  printf(\"\$curkey{13} = 'KEY_RET' ;\\n\") ;\n" ;
Xprint "  printf(\"\$curcon{'KEY_TAB'} = %d ;\\n\",9) ;\n" ;
Xprint "  printf(\"\$curkey{9} = 'KEY_TAB' ;\\n\") ;\n" ;
Xprint "  exit(0) ;\n" ;
Xprint "}\n" ;
END_OF_FILE
if test 936 -ne `wc -c <'curcon.mk'`; then
    echo shar: \"'curcon.mk'\" unpacked with wrong size!
fi
chmod +x 'curcon.mk'
# end of 'curcon.mk'
fi
if test -f 'cursesX.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cursesX.c'\"
else
echo shar: Extracting \"'cursesX.c'\" \(1951 characters\)
sed "s/^X//" >'cursesX.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <curses.h>
X#include "cursesX.h"
X#include "defs.h"
X
Xvoid initCursesX()
X{ /* called by do_initscr ; */
X  ;
X}
X
Xint getLINES() { return(LINES) ; }
Xint getCOLS()  { return(COLS) ; }
X
Xint wgetchR(w)
XWINDOW *w ;
X{ int x,y,c ;
X  for ( c = wgetch(w)
X      ; ( c == REDRAW_INT ) || ( optX && ( c == OPTX_INT ) )
X      ; c = wgetch(w)
X      )
X    { if ( c == REDRAW_INT )
X	{ getyx(w,y,x) ;
X	  redraw() ;
X          wmove(w,y,x) ;
X	  wrefresh(w) ;
X	}
X      else if ( c == OPTX_INT )
X	{ curStat() ; }
X    }
X  return(c) ;
X}
X
Xint getchR()
X{ return(wgetchR(stdscr)) ; }
X
Xvoid quitcterm()
X{ quit() ;
X}
X
Xvoid wshow (win,line,cp,ystart,xstart,xlen,rep)
XWINDOW *win ;
Xchar *line ;
Xint cp, ystart,xstart,xlen ;
Xchar *rep ;
X{ showline(line,cp,win,ystart,xstart,xlen,rep) ;
X}
X
Xvoid show (line,cp,ystart,xstart,xlen,rep)
Xchar *line ;
Xint cp, ystart,xstart,xlen ;
Xchar *rep ;
X{ showline(line,cp,stdscr,ystart,xstart,xlen,rep) ;
X}
X
Xint wedit (win,line,curpos,ystart,xstart,xlen,rep)
XWINDOW *win ;
Xchar *line ;
Xint curpos, ystart, xstart, xlen ;
Xchar *rep ;
X{ int c ;
X  c = editline (line,BUFSIZE,&curpos,win,ystart,xstart,xlen,rep) ;
X  addlogsn(LOGCURS2,"wedit returns",c) ;
X  return( c ) ;
X}
X
Xint edit (line,curpos,ystart,xstart,xlen,rep)
Xchar *line ;
Xint curpos, ystart, xstart, xlen ;
Xchar *rep ;
X{ int c ;
X  c = editline (line,BUFSIZE,&curpos,stdscr,ystart,xstart,xlen,rep) ;
X  addlogsn(LOGCURS2,"edit returns",c) ;
X  return( c ) ;
X}
X
Xvoid mybeep() { fprintf(stderr,"%c",7) ; }
Xvoid nobeep() { ; }
X
Xvoid wclrreg(w,top,bot)
XWINDOW *w ;
Xint top,bot ;
X{ int i ;
X  for ( i = top ; i <= bot ; i++ )
X    { wmove(w,i,0) ;
X      wclrtoeol(w) ;
X    }
X}
X
Xvoid clrreg(top,bot)
Xint top,bot ;
X{ wclrreg(stdscr,top,bot) ; }
X
Xvoid ctermlog(s) char *s ; { addlogss(LOGAPPL,"LOG",s) ; }
X
Xint editq(n)      int n ;   { return(addQuitEdit(n)) ; }
Xvoid editreset()            { emptyQuitEdit() ; }
Xvoid curnop()               { ; }
Xvoid curflush()             { ; }
END_OF_FILE
if test 1951 -ne `wc -c <'cursesX.c'`; then
    echo shar: \"'cursesX.c'\" unpacked with wrong size!
fi
# end of 'cursesX.c'
fi
if test -f 'cursesX.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cursesX.h'\"
else
echo shar: Extracting \"'cursesX.h'\" \(374 characters\)
sed "s/^X//" >'cursesX.h' <<'END_OF_FILE'
Xextern int wgetchR() ;
Xextern void show() ;
Xextern void wshow() ;
Xextern int edit() ;
Xextern int wedit() ;
Xextern void quitcterm() ;
Xextern void ctermlog() ;
Xextern int editq() ;
Xextern void editreset() ;
Xextern void curnop() ;
Xextern void curflush() ;
Xextern void wclrreg() ;
Xextern void clrreg() ;
Xextern void mybeep() ;
Xextern void nobeep() ;
Xextern void initCursesX() ;
END_OF_FILE
if test 374 -ne `wc -c <'cursesX.h'`; then
    echo shar: \"'cursesX.h'\" unpacked with wrong size!
fi
# end of 'cursesX.h'
fi
if test -f 'defs.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'defs.h'\"
else
echo shar: Extracting \"'defs.h'\" \(592 characters\)
sed "s/^X//" >'defs.h' <<'END_OF_FILE'
X#define BUFSIZE 20480
X#define BUFSIZE2 10240
X#define SEP 28
X
X#define MAXNUMWINDOWS 100
X#define MAXQUITEDIT 1000
X#define REDRAW_INT '\014'
X#define OPTX_INT '\030'
X
X#define LOGAPPL   0
X#define LOGCURS1  1
X#define LOGCURS2  2
X
Xextern FILE *OUT ;
Xextern WINDOW *windows[] ;
Xextern int optX, hasWin ;
X
Xextern int saveWindow() ;
Xextern void unsaveWindow() ;
Xextern void initWindows() ;
Xextern void redraw() ;
X
Xextern char *nextStr()  ;
Xextern int nextChr() ;
Xextern int nextInt()  ;
X
Xextern void emptyQuitEdit() ;
Xextern int addQuitEdit() ;
Xextern int inQuitEdit() ;
X
Xextern void (*(funtab[]))() ;
END_OF_FILE
if test 592 -ne `wc -c <'defs.h'`; then
    echo shar: \"'defs.h'\" unpacked with wrong size!
fi
# end of 'defs.h'
fi
if test -f 'edit.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'edit.c'\"
else
echo shar: Extracting \"'edit.c'\" \(4335 characters\)
sed "s/^X//" >'edit.c' <<'END_OF_FILE'
X#include <curses.h>
X#include "cursesX.h"
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include "defs.h"
X
X#ifndef BEEP
X#define BEEP nobeep
X#endif
X
Xstatic int Erase = 0, Kill = 0, initialized = 0 ;
Xstatic int quitEdit[MAXQUITEDIT], quitEditSize = 0 ;
X
Xstatic char save[BUFSIZE], temp[BUFSIZE] ;
X
Xvoid initEdit()
X{ Erase = erasechar() ;
X  Kill = killchar() ;
X}
X
Xvoid emptyQuitEdit() { quitEditSize = 0 ; }
X
Xint addQuitEdit(n)
Xint n ;
X{ if ( quitEditSize >= MAXQUITEDIT )
X    return(0) ;
X  quitEdit[quitEditSize++] = n ;
X  return(1) ;
X}
X
Xint inQuitEdit(n)
Xint n ;
X{ int i ;
X  for ( i = 0 ; i < quitEditSize ; i++ )
X    if ( quitEdit[i] == n )
X      return(1) ;
X  return(0) ;
X}
X
Xvoid showline (line,cp,win,ystart,xstart,xlen,rep)
Xchar *line ;
Xint cp ;
XWINDOW* win ;
Xint ystart,xstart,xlen ;
Xchar rep[4] ;
X{ int ll = strlen(line) ;
X  int i, h = xlen/2 ;
X  char lc, lo, ro, rc ;
X
X  lc = rep[0] ;
X  lo = rep[1] ;
X  ro = rep[2] ;
X  rc = rep[3] ;
X
X  wmove(win,ystart,xstart) ;
X
X  if ( (ll <= xlen) && (cp < xlen) )
X    { waddch(win,lc) ;
X      for (i=0 ; i<=ll-1 ; i++)
X	waddch(win,line[i]) ;
X      for (i=ll ; i<xlen ; i++)
X	waddch(win,' ') ;
X      waddch(win,rc) ;
X      wmove(win,ystart,xstart+1+cp) ;
X    }
X  else if ( (ll == xlen) && (cp == xlen) )
X    { waddch(win,lo) ;
X      for (i=1 ; i<=ll-1 ; i++)
X	waddch(win,line[i]) ;
X      waddch(win,' ') ;
X      waddch(win,rc) ;
X      wmove(win,ystart,xstart+1+cp-1) ;
X    }
X  else /* ll > xlen */
X  if ( cp < h+1 )
X    { waddch(win,lc) ;
X      for (i=0 ; i<xlen ; i++)
X	waddch(win,line[i]) ;
X      waddch(win,ro) ;
X      wmove(win,ystart,xstart+1+cp) ;
X    }
X  else if ( cp < ll-xlen+h )
X    { waddch(win,lo) ;
X      for (i=cp-h ; i<=cp-h+xlen-1 ; i++)
X	waddch(win,line[i]) ;
X      waddch(win,ro) ;
X      wmove(win,ystart,xstart+1+h) ;
X    }
X  else if ( cp < ll )
X    { waddch(win,lo) ;
X      for (i=ll-xlen ; i<=ll-1 ; i++)
X	waddch(win,line[i]) ;
X      waddch(win,rc) ;
X      wmove(win,ystart,xstart+1+cp-ll+xlen) ;
X    }
X  else /* cp == ll */
X    { waddch(win,lo) ;
X      for (i=ll-xlen+1 ; i<=ll-1 ; i++)
X	waddch(win,line[i]) ;
X      waddch(win,' ') ;
X      waddch(win,rc) ;
X      wmove(win,ystart,xstart+1+xlen-1) ;
X    }
X  wrefresh(win) ;
X}
X
Xvoid doCurRight(ll,cp)
Xint *ll,*cp ;
X{ if ( *cp < *ll )
X    (*cp)++ ;
X  else
X    BEEP() ;
X}
X
Xvoid doCurLeft(ll,cp)
Xint *ll,*cp ;
X{ if ( *cp > 0 )
X    (*cp)-- ;
X  else
X    BEEP() ;
X}
X
XdoErase(line,ll,cp)
Xchar *line ;
Xint *ll,*cp ;
X{ int i ; 
X
X  if (*ll == 0 || *cp == 0)
X    { strcpy(temp,line) ;
X      strcpy(line,save) ;
X      strcpy(save,temp) ;
X      *ll = strlen(line) ;
X      *cp = 0 ;
X    }
X  else
X    { for (i=(*cp)-1 ; i<*ll ; i++)
X        line[i] = line[i+1] ;
X      (*ll)-- ;
X      (*cp)-- ;
X    }
X}
X
Xvoid doDel(line,ll,cp)
Xchar *line ;
Xint *ll,*cp ;
X{ int i ; 
X  
X  if (*ll == 0)
X    BEEP() ;
X  if (*cp == *ll)
X    doCurLeft(ll,cp) ;
X  else
X    { for (i = *cp ; i < *ll ; i++)
X        line[i] = line[i+1] ;
X      (*ll)-- ;
X      if ( *cp > *ll )
X        *cp = *ll ;
X    }
X}
X
Xvoid doInsert(line,maxlinelen,ll,cp,c)
Xchar *line ;
Xint *ll, *cp, c ;
X{ int i ;
X
X  if (*ll > maxlinelen)
X    BEEP() ;
X  else
X    for (i = *ll ; i >= *cp ; i--)
X      line[i+1] = line[i] ;
X    line[*cp] = c ;
X    (*cp)++ ;
X    (*ll)++ ;
X}
X
Xvoid editCom (line,maxLineLen,linelen,curpos,c)
Xchar *line ;
Xint maxLineLen, *linelen, *curpos ;
Xint c ;
X{ if ( c == Kill )
X    doDel(line,linelen,curpos) ;
X  else if ( c == Erase )
X    doErase(line,linelen,curpos) ;
X#ifdef EDIT_RIGHT
X  else if ( c == EDIT_RIGHT )
X    doCurRight(linelen,curpos) ;
X#endif
X#ifdef EDIT_LEFT
X  else if ( c == EDIT_LEFT )
X    doCurLeft(linelen,curpos) ;
X#endif
X  else if ( (c < 32) || (c > 127) )
X    BEEP() ;
X  else
X    doInsert(line,maxLineLen,linelen,curpos,c) ;
X}
X
Xint editline (line,maxlinelen,curpos,win,ystart,xstart,xlen,rep)
Xchar *line ;
Xint maxlinelen, *curpos ;
XWINDOW *win ;
Xint ystart, xstart, xlen ;
Xchar *rep ;
X{ int linelen = strlen(line) ;
X  int c ;
X
X  if ( ! initialized ) { initEdit() ; initialized = 1 ; }
X
X  strcpy(save,"") ;
X
X  showline(line,*curpos,win,ystart,xstart,xlen,rep) ;
X
X  for ( c=wgetchR(win)
X      ; ( c != EOF) && ( ! inQuitEdit(c) )
X      ; c=wgetchR(win)
X      )
X    { editCom(line,maxlinelen,&linelen,curpos,c) ;
X      showline(line,*curpos,win,ystart,xstart,xlen,rep) ;
X    }
X
X  showline(line,0,win,ystart,xstart,xlen,rep) ;
X  return(c) ;
X}
END_OF_FILE
if test 4335 -ne `wc -c <'edit.c'`; then
    echo shar: \"'edit.c'\" unpacked with wrong size!
fi
# end of 'edit.c'
fi
if test -f 'try1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'try1'\"
else
echo shar: Extracting \"'try1'\" \(448 characters\)
sed "s/^X//" >'try1' <<'END_OF_FILE'
X
X# cterm example application
X# usage: perl try1
X# 'perl try1 LOG 1' will produce a cterm logfile LOG.
X
Xdo 'cterm.pl' || die "$0 can't include cterm.pl\n" ;
X&startCterm(@ARGV) ; 
X&initscr ; &nonl ; &cbreak ; &noecho ;
X$japh = "just another perl hacker" ;
X&mvaddstr(int($LINES/2),int(($COLS-length($japh))/2),$japh) ;
X&mvaddstr($LINES-1,0,'hit any key to continue ') ;
X&refresh ;
X&getchR ;
X&clear ;
X&move(0,0) ;
X&refresh() ;
X&endwin ;
X&finishCterm ;
END_OF_FILE
if test 448 -ne `wc -c <'try1'`; then
    echo shar: \"'try1'\" unpacked with wrong size!
fi
chmod +x 'try1'
# end of 'try1'
fi
if test -f 'try2' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'try2'\"
else
echo shar: Extracting \"'try2'\" \(1043 characters\)
sed "s/^X//" >'try2' <<'END_OF_FILE'
Xdo 'cterm.pl' || die "$0 can't include cterm.pl\n" ;
X
X&startCterm(@ARGV) ;
X
X&initscr ; &nonl ; &cbreak ; &noecho ;
X&leaveok($stdscr,0) ; &refresh ;
X&keypad($stdscr,1) if defined $curfun{'keypad'} ;
X
X&editq($curcon{'KEY_UP'}) if defined $curcon{'KEY_UP'} ;
X&editq($curcon{'KEY_DOWN'}) if defined $curcon{'KEY_DOWN'} ;
X&editq($curcon{'KEY_RET'}) ;
X
X$japh = 'just another perl hacker' ;
X$len = length($japh) ;
X
X$win = &newwin(5,$len+4,int($LINES/2)-2,int(($COLS-$len)/2)-2) ;
X&box($win,ord('|'),ord('-')) ;
X&mvwaddstr($win,2,2,$japh) ;
X&wrefresh($win) ;
X
X&mvaddstr(2,4,'quit edit mode by KEY_RET, KEY_DOWN or KEY_UP') ;
X
X($string,$quitKey) = &edit('hello world',0,4,4,20,'|<>|') ;
X
X$killchar = &killchar ;
X$erasechar = &erasechar ;
X
X&endwin ;
X&finishCterm ;
X
X$quitKey = &ch2str($quitKey) ;
X
Xprint "hello again, cterm is gone, we are back in perl\n" ;
Xprint "edit returned ($string,$quitKey)\n" ;
Xprint "cterm used:\n" ;
Xprint "LINES:     $LINES\n" ;
Xprint "COLS:      $COLS\n" ;
Xprint "killchar:  $killchar\n" ;
Xprint "erasechar: $erasechar\n" ;
END_OF_FILE
if test 1043 -ne `wc -c <'try2'`; then
    echo shar: \"'try2'\" unpacked with wrong size!
fi
chmod +x 'try2'
# end of 'try2'
fi
echo shar: End of shell archive.
exit 0
-- 
Henk P. Penning, Dept of Computer Science, Utrecht University.
Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands.
Telephone: +31-30-534106
e-mail   : henkp@cs.ruu.nl (uucp to hp4nl!ruuinf!henkp)