xref: /original-bsd/usr.bin/window/README (revision d919d844)
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley.  The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 *	@(#)README	3.11 (Berkeley) 07/09/88
18 */
19
20Compilation notes:
21
22     There is only one compiler option:
23
24	vax		use Vax byte order (found in ww.h)
25			Actually MIPSEL is also little-endian.
26			Anyway, they should already be defined in the
27			preprocessor.
28			If neither is defined, big-endian is assumed.
29
30     Ok, there's another one, STR_DEBUG.  It turns on consistency checks
31     in the string allocator.  It's been left on since performace doesn't
32     seem to suffer.  There's an abort() somewhere when an inconsistency
33     is found.  It hasn't happened in years.
34
35     The file local.h contains locally tunable constants.
36
37     The makefile used to be updated with mkmf; it has been changed
38at various times to use cpp -M and, currently, mkdep.  The only library
39it needs is termcap.
40
41     Window, as is, only runs on 4.3 machines.
42
43     On 4.2 machines, at least these modifications must be done:
44
45	delete uses of window size ioctls: TIOCGWINSZ, TIOCSWINSZ,
46		struct winsize
47	add to ww.h
48		typedef int fd_set;
49		#define FD_ZERO(s) (*(s) = 0)
50		#define FD_SET(b, s) (*(s) |= 1 << (b))
51		#define FD_ISSET(b, s) (*(s) & 1 << (b))
52	add to ww.h
53		#define sigmask(s) (1 << (s) - 1)
54
55
56A few notes about the internals:
57
58     The window package.  Windows are opened by calling wwopen().
59Wwwrite() is the primitive for writing to windows.  Wwputc(), wwputs(),
60and wwprintf() are also supported.  Some of the outputs to windows are
61delayed.  Wwupdate() updates the terminal to match the internal screen
62buffer.  Wwspawn() spawns a child process on the other end of a window,
63with its environment tailored to the window.  Visible windows are
64doubly linked in the order of their overlap.  Wwadd() inserts a window
65into the list at a given place.  Wwdelete() deletes it.  Windows not in
66the list are not visible, though wwwrite() still works.  Window was
67written before the days of X and Sunview, so some of the terminology
68is not standard.
69
70     Most functions return -1 on error.  Wwopen() returns the null
71pointer.  An error number is saved in wwerrno.  Wwerror() returns an
72error string based on wwerrno suitable for printing.
73
74     The terminal drivers perform all output to the physical terminal,
75including special functions like character and line insertion and
76deletion.  The window package keeps a list of known terminals.  At
77initialization time, the terminal type is matched against the list to
78find the right terminal driver to use.  The last driver, the generic
79driver, matches all terminals and uses the termcap database.  The
80interface between the window package the terminal driver is the `tt'
81structure.  It contains pointers to functions to perform special
82functions and terminal output, as well as flags about the
83characteristics of the terminal.  Most of these ideas are borrowed
84from the Maryland window package, which in turn is based on Goslin's
85Emacs.
86
87     The IO system is semi-synchronous.  Terminal input is signal
88driven, and everything else is done synchronously with a single
89select().  It is roughly event-driven, though not in a clean way.
90
91     Normally, in both conversation mode and command mode, window
92sleeps in a select() in wwiomux() waiting for data from the
93pseudo-terminals.  At the same time, terminal input causes SIGIO which
94is caught by wwrint().  The select() returns when at least one of the
95pseudo-terminals becomes ready for reading.
96
97     Wwrint() is the interrupt handler for tty input.  It reads input
98into a linear buffer accessed through four pointers:
99
100	+-------+--------------+----------------+
101	| empty |    data      |   empty	|
102	+-------+--------------+----------------+
103	^	^		^		 ^
104	|	|		|		 |
105       wwib    wwibp	       wwibq		wwibe
106
107Wwrint() appends characters at the end and increments wwibq (*wwibq++
108= c), and characters are taken off the buffer at wwibp using the
109wwgetc() and wwpeekc() macros.  As is the convention in C, wwibq
110and wwibe point to one position beyond the end.  In addition,
111wwrint() will do a longjmp(wwjmpbuf) if wwsetjmp is true.  This is
112used by wwiomux() to interrupt the select() which would otherwise
113resume after the interrupt.  (Actually, I hear this is not true,
114but the longjmp feature is used to avoid a race condition as well.
115Anyway, it means I didn't have to depend on a feature in a
116daily-changing kernel, but that's another story.) The macro
117wwinterrupt() returns true if the input buffer is non-empty.
118Wwupdate(), wwwrite(), and wwiomux() check this condition and will
119return at the first convenient opportunity when it becomes true.
120In the case of wwwrite(), the flag ww_nointr in the window structure
121overrides this.  This feature allows the user to interrupt lengthy
122outputs safely.  The structure of the input buffer is designed to
123avoid race conditions without blocking interrupts.
124
125     Actually, wwsetjmp and wwinterrupt() are part of a software
126interrupt scheme used by the two interrupt catchers wwrint() and
127wwchild().  Asserting the interrupt lets the synchronous parts of
128the program know that there's an interesting asynchronous condition
129(i.e., got a keyboard character, or a child process died) that they
130might want to process before anything else.  The synchronous routines
131can check for this condition with wwinterrupt() or by arranging
132that a longjmp() be done.
133
134     Wwiomux() copies pseudo-terminal output into their corresponding
135windows.  Without anything to do, it blocks in a select(), waiting for
136read ready on pseudo-terminals.  Reads are done into per-window buffers
137in the window structures.  When there is at least one buffer non-empty,
138wwiomux() finds the top most of these windows and writes it using
139wwwrite().  Then the process is repeated.  A non-blocking select() is
140done after a wwwrite() to pick up any output that may have come in
141during the write, which may take a long time.  Specifically, we use
142this to stop output or flush buffer when a pseudo-terminal tells us to
143(we use pty packet mode).  The select() blocks only when all of the
144windows' buffers are empty.  A wwupdate() is done prior to this, which
145is the only time the screen is guaranteed to be completely up to date.
146Wwiomux() loops until wwinterrupt() becomes true.
147
148     The top level routine for all this is mloop().  In conversation
149mode, it simply calls wwiomux(), which only returns when input is
150available.  The input buffer is then written to the pseudo-terminal of
151the current window.  If the escape character is found in the input,
152command mode is entered.  Otherwise, the process is repeated.  In
153command mode, control is transferred to docmd() which returns only when
154conversation mode is reentered.  Docmd() and other command processing
155routines typically wait for input in a loop:
156
157	while (wwpeekc() < 0)
158		wwiomux();
159
160When the loop terminates, wwgetc() is used to read the input buffer.
161
162     Output to the physical terminal is handled by the lowest level
163routines of the window package, in the files ttoutput.c and tt.h.  The
164standard IO package is not used, to get better control over buffering
165and to use non-blocking reads in wwrint().  The buffer size is set to
166approximately one second of output time, based on the baudrate.
167
168     The result of all this complexity is faster response time,
169especially in output stopping and flushing.  Wwwrite() checks
170wwinterrupt() after every line.  It also calls wwupdate() for each line
171it writes.  The output buffer is limited to one second of output time.
172Thus, there is usually only a delay of one to two lines plus one second
173after a ^C or ^S.  Also, commands that produce lengthy output can be
174aborted without actually showing all of it on the terminal.  (Try the
175'?' command followed by escape immediately.)
176