2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Edward Wang at The University of California, Berkeley.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * @(#)README 8.1 (Berkeley) 6/6/93
43 BYTE_ORDER (used only in ww.h)
44 It should already be defined in machine/endian.h.
45 The code knows about BIG_ENDIAN, LITTLE_ENDIAN, and PDP_ENDIAN.
46 It only cares about byte order in words, so PDP_ENDIAN
47 is the same as LITTLE_ENDIAN.
49 If you don't have Posix termios, then define this.
51 Even if you have Posix termios, define this if the MIN and TIME
52 feature in noncanonical mode doesn't work correctly.
54 Ok, there's another one, STR_DEBUG. It turns on consistency checks
55 in the string allocator. It's been left on since performace doesn't
56 seem to suffer. There's an abort() somewhere when an inconsistency
57 is found. It hasn't happened in years.
59 The file local.h contains locally tunable constants.
61 The makefile used to be updated with mkmf; it has been changed
62 at various times to use cpp -M and, currently, mkdep. The only library
65 Window, as is, only runs on 4.3 (or later) machines.
67 On 4.2 machines, at least these modifications must be done:
69 delete uses of window size ioctls: TIOCGWINSZ, TIOCSWINSZ,
73 #define FD_ZERO(s) (*(s) = 0)
74 #define FD_SET(b, s) (*(s) |= 1 << (b))
75 #define FD_ISSET(b, s) (*(s) & 1 << (b))
77 #define sigmask(s) (1 << (s) - 1)
80 A few notes about the internals:
82 The window package. Windows are opened by calling wwopen().
83 Wwwrite() is the primitive for writing to windows. Wwputc(), wwputs(),
84 and wwprintf() are also supported. Some of the outputs to windows are
85 delayed. Wwupdate() updates the terminal to match the internal screen
86 buffer. Wwspawn() spawns a child process on the other end of a window,
87 with its environment tailored to the window. Visible windows are
88 doubly linked in the order of their overlap. Wwadd() inserts a window
89 into the list at a given place. Wwdelete() deletes it. Windows not in
90 the list are not visible, though wwwrite() still works. Window was
91 written before the days of X and Sunview, so some of the terminology
94 Most functions return -1 on error. Wwopen() returns the null
95 pointer. An error number is saved in wwerrno. Wwerror() returns an
96 error string based on wwerrno suitable for printing.
98 The terminal drivers perform all output to the physical terminal,
99 including special functions like character and line insertion and
100 deletion. The window package keeps a list of known terminals. At
101 initialization time, the terminal type is matched against the list to
102 find the right terminal driver to use. The last driver, the generic
103 driver, matches all terminals and uses the termcap database. The
104 interface between the window package the terminal driver is the `tt'
105 structure. It contains pointers to functions to perform special
106 functions and terminal output, as well as flags about the
107 characteristics of the terminal. Most of these ideas are borrowed
108 from the Maryland window package, which in turn is based on Goslin's
111 The IO system is semi-synchronous. Terminal input is signal
112 driven, and everything else is done synchronously with a single
113 select(). It is roughly event-driven, though not in a clean way.
115 Normally, in both conversation mode and command mode, window
116 sleeps in a select() in wwiomux() waiting for data from the
117 pseudo-terminals. At the same time, terminal input causes SIGIO which
118 is caught by wwrint(). The select() returns when at least one of the
119 pseudo-terminals becomes ready for reading.
121 Wwrint() is the interrupt handler for tty input. It reads input
122 into a linear buffer accessed through four pointers:
124 +-------+--------------+----------------+
125 | empty | data | empty |
126 +-------+--------------+----------------+
129 wwib wwibp wwibq wwibe
131 Wwrint() appends characters at the end and increments wwibq (*wwibq++
132 = c), and characters are taken off the buffer at wwibp using the
133 wwgetc() and wwpeekc() macros. As is the convention in C, wwibq
134 and wwibe point to one position beyond the end. In addition,
135 wwrint() will do a longjmp(wwjmpbuf) if wwsetjmp is true. This is
136 used by wwiomux() to interrupt the select() which would otherwise
137 resume after the interrupt. (Actually, I hear this is not true,
138 but the longjmp feature is used to avoid a race condition as well.
139 Anyway, it means I didn't have to depend on a feature in a
140 daily-changing kernel, but that's another story.) The macro
141 wwinterrupt() returns true if the input buffer is non-empty.
142 Wwupdate(), wwwrite(), and wwiomux() check this condition and will
143 return at the first convenient opportunity when it becomes true.
144 In the case of wwwrite(), the flag ww_nointr in the window structure
145 overrides this. This feature allows the user to interrupt lengthy
146 outputs safely. The structure of the input buffer is designed to
147 avoid race conditions without blocking interrupts.
149 Actually, wwsetjmp and wwinterrupt() are part of a software
150 interrupt scheme used by the two interrupt catchers wwrint() and
151 wwchild(). Asserting the interrupt lets the synchronous parts of
152 the program know that there's an interesting asynchronous condition
153 (i.e., got a keyboard character, or a child process died) that they
154 might want to process before anything else. The synchronous routines
155 can check for this condition with wwinterrupt() or by arranging
156 that a longjmp() be done.
158 Wwiomux() copies pseudo-terminal output into their corresponding
159 windows. Without anything to do, it blocks in a select(), waiting for
160 read ready on pseudo-terminals. Reads are done into per-window buffers
161 in the window structures. When there is at least one buffer non-empty,
162 wwiomux() finds the top most of these windows and writes it using
163 wwwrite(). Then the process is repeated. A non-blocking select() is
164 done after a wwwrite() to pick up any output that may have come in
165 during the write, which may take a long time. Specifically, we use
166 this to stop output or flush buffer when a pseudo-terminal tells us to
167 (we use pty packet mode). The select() blocks only when all of the
168 windows' buffers are empty. A wwupdate() is done prior to this, which
169 is the only time the screen is guaranteed to be completely up to date.
170 Wwiomux() loops until wwinterrupt() becomes true.
172 The top level routine for all this is mloop(). In conversation
173 mode, it simply calls wwiomux(), which only returns when input is
174 available. The input buffer is then written to the pseudo-terminal of
175 the current window. If the escape character is found in the input,
176 command mode is entered. Otherwise, the process is repeated. In
177 command mode, control is transferred to docmd() which returns only when
178 conversation mode is reentered. Docmd() and other command processing
179 routines typically wait for input in a loop:
181 while (wwpeekc() < 0)
184 When the loop terminates, wwgetc() is used to read the input buffer.
186 Output to the physical terminal is handled by the lowest level
187 routines of the window package, in the files ttoutput.c and tt.h. The
188 standard IO package is not used, to get better control over buffering
189 and to use non-blocking reads in wwrint(). The buffer size is set to
190 approximately one second of output time, based on the baudrate.
192 The result of all this complexity is faster response time,
193 especially in output stopping and flushing. Wwwrite() checks
194 wwinterrupt() after every line. It also calls wwupdate() for each line
195 it writes. The output buffer is limited to one second of output time.
196 Thus, there is usually only a delay of one to two lines plus one second
197 after a ^C or ^S. Also, commands that produce lengthy output can be
198 aborted without actually showing all of it on the terminal. (Try the
199 '?' command followed by escape immediately.)