home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume7
/
tm
/
tm.c
< prev
Wrap
C/C++ Source or Header
|
1989-07-02
|
6KB
|
196 lines
/* thisterm terminal emulator
By Troy Rollo 1989
The thisterm terminal emulator is a minimum terminal
emulator for the apollo domains. This version has only
two control sequences:
Ctrl-L (ascii 0xc) clears the screen (pad)
An escape character followed by x+' ', y+' ' moves
to the given location in the pad.
Additional control sequences can be created by modifying
the xfread routine. The ones already installed can, of course
be modified.
Thisterm uses the pseudo tty device entries /dev/ptypb and
/dev/ttypb. An improved version would start at [pt]typ0 and work
up towards [pt]typf, allowing more than one thisterm
terminal emulator to run at once. It might also remove borders,
and use pad_$set_full_window and the current scale factor to
set the size of the window to match the size of the pseudo
screen.
avenger@runx.ips.oz.au
s8730679@spectrum.eecs.unsw.oz.au (sometimes)
8730679@elec70a.eecs.unsw.oz.au (sometimes)
troy_rollo@712.502@fidogate.fido.oz.au (can't reply)
*/
#include <netdb.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <apollo/base.h>
#include <apollo/pad.h>
#include <apollo/error.h>
#define COLUMNS 80
#define ROWS 25
/* I think fd2p is a relic from a previous life. This program evolved
from an rexec patron */
int fd2p = 1;
status_$t status;
stream_$sk_t sk = {
0l,
0l,
0l
};
/* Hmm... interesting... I don't actually use argc or argv */
main(int argc, char **argv)
{
char c[256];
int cc;
int n;
int pn, pid;
int rem, proc;
/* put the pad in raw mode. This is a requirement for any terminal
emulator */
pad_$raw(1, &status);
/* Now open the master side of the pseudo tty */
rem=open("/dev/ptypb", O_RDWR);
/* And the slave side */
proc=open("/dev/ttypb", O_RDWR);
if (rem==-1 || proc==-1)
/* Complain if unable to open either - probably should
try to find another one */
exit(1);
if((pid=fork())==-1) {
fprintf(stderr, "%s: can't fork\n", argv[0]);
exit(1);
}
if (pid==0) {
/* This process lives on the slave side of the pseudo tty
Make the pseudo tty stdin, stdout and stderr */
close(0);
close(1);
close(2);
dup(proc);
dup(proc);
dup(proc);
close(proc);
close(rem);
/* I use ksh - you might prefer another shell */
execl("/bin/ksh", "ksh", "-i", 0);
}
close(proc);
/* Close the slave side so that when the last slave side process dies
or closes its last file descriptor we hear about it on the master side */
if ((pn=fork())==-1) {
fprintf(stderr, "%s: Can't fork\n", argv[0]);
kill(pid,9);
exit(1);
}
/* Create a frame to allow the cursor to roam around the pseudo screen */
pad_$create_frame(1, COLUMNS, ROWS, &status);
/* The parent reads on the master side (output of the slace side) until
there are no more processes writing on the pseudo tty. At this point
it enters a suicide pact - killing the child with a machine gun (signal
9) and dieing itself.
Intil it dies, the slave side transfers all stdin to the pseudo tty */
if (pn!=0) {
while (xfread(rem) !=-1);
pad_$cooked(1, &status);
pad_$delete_frame(1, &status);
kill(pn, 9);
exit(0);
}
else {
while ((n=read(0, c, 255)) != 0)
write(rem, c, n);
}
}
/* xfread reads from the pseudo tty, and decides what to do about the output.
It's fairly straight forward - checks for any specified control character.
There is a bug in the newline sequence - if the user presses the page up or
shift-uparrow keys, you can't get back on the current frame.... perhaps these
keys should be redefined within the region of the pad.
Some enhancements might be:
A partial screen clearing option.
Scroll forward and back on demand.
Changing font (perhaps loading an inverse font and using it for highlight.
the following fonts could also prove useful as built-ins:
italics
bold
times_roman
as well as a pure graphics font (say, a 7x1 font with each character
representing a sequence of pixels in a vertical line)
This routine doesn't return until there are no more slaves using the pseudo
tty
*/
int xfread(f)
int f;
{
char b;
short x, y;
long line, eof;
short xo, yo;
while (kread(f,&b)!=-1)
if (b=='\033') {
kread(f,&b);
x=(short) (b-' '+1);
kread(f,&b);
y=(short) (b-' '+1);
pad_$inq_view(1, 1, &line, &eof, &xo, &yo, &status);
pad_$move(1,pad_$absolute,x,y+yo-1,&status);
write(1,"\0",2);
}
else if (b=='\014') {
pad_$clear_frame(1, sk, &status);
write(1,"\0",2);
}
else {
write(1,&b,1);
if (b=='\n') {
pad_$inq_view(1, 1, &line, &eof, &xo, &yo, &status);
pad_$inq_position(1, &x, &y, &status);
if (y-yo+1==25) {
pad_$set_view(1, 1, line, 1, yo+2, &status);
pad_$create_frame(1, COLUMNS, ROWS, &status);
}
}
}
return (-1);
}
/* A buffered read - returns 1 on success, -1 on failure (just to be difficult for
anybody using it as the argument to if! And also for compatibility with the
values returned by Domain/IX
returns one character at a time, buffering them in a static 2048 byte buffer.
interesting things would happen if two different files were used as arguments
int different parts of the program, but it's probably not worth fixing */
int kread(file, buffer)
int file;
char *buffer;
{
static char BIGBUF[2048];
static int bbcnt = 0;
static int bbptr = 0;
if (bbptr>=bbcnt) {
bbcnt=read(file, BIGBUF, 2048);
if (bbcnt==-1)
return(-1);
bbptr=0;
}
*buffer=BIGBUF[bbptr];
++bbptr;
return(1);
}