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