allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (08/08/89)
Posting-number: Volume 7, Issue 54 Submitted-by: s8730679@spectrum.eecs.unsw.oz.au ( The Inquisitor ) Archive-name: tm I wrote this program after becoming frustrated at the regular failure on the part of the apollo vt100 emulator to come up. It is a simple terminal emulator which is sufficient to run vn. Hack crashes under it and there are bugs, but it is the shell of a decent emulator. Troy Rollo avenger@runx.ips.oz.au s8730679@spectrum.eecs.unsw.oz.au 8730679@elec70a.eecs.unsw.oz.au troy_rollo@712.502@fidogate.fido.oz.au #! /bin/sh # This is a shell archive. Remove anything before this line, then # unpack it by saving it in a file and typing "sh file". (Files # unpacked will be owned by you and have default permissions.) # # This archive contains: # README Makefile termcap tm.c echo x - README cat > "README" << '//E*O*F README//' 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. To use this, first run thisterm, then set the environment variables: MORE=-c TERM=this TERMCAP=your_termcap_path 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) //E*O*F README// echo x - Makefile cat > "Makefile" << '//E*O*F Makefile//' # Makefile for thisterm # Very easy: thisterm: tm.c cc -o thisterm tm.c //E*O*F Makefile// echo x - termcap cat > "termcap" << '//E*O*F termcap//' # # Termcap file for my news reading emulator # # run tm, then set: # # MORE=-c # TERM=this # TERMCAP=$HOME/termcap # th|this|this emulator:\ :cm=\E%r%+ %+ :cl=\14:li#25:co#80:bs: //E*O*F termcap// echo x - tm.c cat > "tm.c" << '//E*O*F tm.c//' /* 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); } //E*O*F tm.c// exit 0