1*42954Sbostic/*- 2*42954Sbostic * Copyright (c) 1990 The Regents of the University of California. 333514Sbostic * All rights reserved. 433514Sbostic * 5*42954Sbostic * This code is derived from software contributed to Berkeley by 6*42954Sbostic * Edward Wang at The University of California, Berkeley. 733514Sbostic * 8*42954Sbostic * %sccs.include.redist.c% 9*42954Sbostic * 10*42954Sbostic * @(#)README 3.13 (Berkeley) 06/06/90 1118742Sedward */ 1218742Sedward 1316284SedwardCompilation notes: 1415556Sedward 1516398Sedward There is only one compiler option: 1616284Sedward 1736258Sedward BYTE_ORDER (used only in ww.h) 1836258Sedward It should already be defined in machine/endian.h. 1936258Sedward The code knows about BIG_ENDIAN, LITTLE_ENDIAN, and PDP_ENDIAN. 2036258Sedward It only cares about byte order in words, so PDP_ENDIAN 2136258Sedward is the same as LITTLE_ENDIAN. 2215556Sedward 2332343Sedward Ok, there's another one, STR_DEBUG. It turns on consistency checks 2432343Sedward in the string allocator. It's been left on since performace doesn't 2532343Sedward seem to suffer. There's an abort() somewhere when an inconsistency 2632343Sedward is found. It hasn't happened in years. 2732343Sedward 2816398Sedward The file local.h contains locally tunable constants. 2915556Sedward 3032343Sedward The makefile used to be updated with mkmf; it has been changed 3132343Sedwardat various times to use cpp -M and, currently, mkdep. The only library 3232343Sedwardit needs is termcap. 3315556Sedward 3429718Sedward Window, as is, only runs on 4.3 machines. 3515556Sedward 3629718Sedward On 4.2 machines, at least these modifications must be done: 3715556Sedward 3829718Sedward delete uses of window size ioctls: TIOCGWINSZ, TIOCSWINSZ, 3929718Sedward struct winsize 4029718Sedward add to ww.h 4129718Sedward typedef int fd_set; 4229718Sedward #define FD_ZERO(s) (*(s) = 0) 4329718Sedward #define FD_SET(b, s) (*(s) |= 1 << (b)) 4429718Sedward #define FD_ISSET(b, s) (*(s) & 1 << (b)) 4529718Sedward add to ww.h 4629718Sedward #define sigmask(s) (1 << (s) - 1) 4729718Sedward 4829718Sedward 4916284SedwardA few notes about the internals: 5016284Sedward 5116284Sedward The window package. Windows are opened by calling wwopen(). 5216284SedwardWwwrite() is the primitive for writing to windows. Wwputc(), wwputs(), 5316284Sedwardand wwprintf() are also supported. Some of the outputs to windows are 5416284Sedwarddelayed. Wwupdate() updates the terminal to match the internal screen 5516284Sedwardbuffer. Wwspawn() spawns a child process on the other end of a window, 5632343Sedwardwith its environment tailored to the window. Visible windows are 5716284Sedwarddoubly linked in the order of their overlap. Wwadd() inserts a window 5816535Sedwardinto the list at a given place. Wwdelete() deletes it. Windows not in 5932343Sedwardthe list are not visible, though wwwrite() still works. Window was 6032343Sedwardwritten before the days of X and Sunview, so some of the terminology 6132343Sedwardis not standard. 6216284Sedward 6316284Sedward Most functions return -1 on error. Wwopen() returns the null 6416535Sedwardpointer. An error number is saved in wwerrno. Wwerror() returns an 6516535Sedwarderror string based on wwerrno suitable for printing. 6616284Sedward 6716284Sedward The terminal drivers perform all output to the physical terminal, 6816284Sedwardincluding special functions like character and line insertion and 6916284Sedwarddeletion. The window package keeps a list of known terminals. At 7016284Sedwardinitialization time, the terminal type is matched against the list to 7116284Sedwardfind the right terminal driver to use. The last driver, the generic 7216284Sedwarddriver, matches all terminals and uses the termcap database. The 7316284Sedwardinterface between the window package the terminal driver is the `tt' 7416284Sedwardstructure. It contains pointers to functions to perform special 7516284Sedwardfunctions and terminal output, as well as flags about the 7632343Sedwardcharacteristics of the terminal. Most of these ideas are borrowed 7732343Sedwardfrom the Maryland window package, which in turn is based on Goslin's 7832343SedwardEmacs. 7916284Sedward 8016535Sedward The IO system is semi-synchronous. Terminal input is signal 8116535Sedwarddriven, and everything else is done synchronously with a single 8232343Sedwardselect(). It is roughly event-driven, though not in a clean way. 8316284Sedward 8416535Sedward Normally, in both conversation mode and command mode, window 8516535Sedwardsleeps in a select() in wwiomux() waiting for data from the 8616535Sedwardpseudo-terminals. At the same time, terminal input causes SIGIO which 8716535Sedwardis caught by wwrint(). The select() returns when at least one of the 8816535Sedwardpseudo-terminals becomes ready for reading. 8916284Sedward 9016535Sedward Wwrint() is the interrupt handler for tty input. It reads input 9116535Sedwardinto a linear buffer accessed through four pointers: 9216284Sedward 9316284Sedward +-------+--------------+----------------+ 9416284Sedward | empty | data | empty | 9516284Sedward +-------+--------------+----------------+ 9616284Sedward ^ ^ ^ ^ 9716284Sedward | | | | 9816284Sedward wwib wwibp wwibq wwibe 9916284Sedward 10032343SedwardWwrint() appends characters at the end and increments wwibq (*wwibq++ 10132343Sedward= c), and characters are taken off the buffer at wwibp using the 10232343Sedwardwwgetc() and wwpeekc() macros. As is the convention in C, wwibq 10332343Sedwardand wwibe point to one position beyond the end. In addition, 10432343Sedwardwwrint() will do a longjmp(wwjmpbuf) if wwsetjmp is true. This is 10532343Sedwardused by wwiomux() to interrupt the select() which would otherwise 10632343Sedwardresume after the interrupt. (Actually, I hear this is not true, 10732343Sedwardbut the longjmp feature is used to avoid a race condition as well. 10832343SedwardAnyway, it means I didn't have to depend on a feature in a 10932343Sedwarddaily-changing kernel, but that's another story.) The macro 11032343Sedwardwwinterrupt() returns true if the input buffer is non-empty. 11132343SedwardWwupdate(), wwwrite(), and wwiomux() check this condition and will 11232343Sedwardreturn at the first convenient opportunity when it becomes true. 11332343SedwardIn the case of wwwrite(), the flag ww_nointr in the window structure 11432343Sedwardoverrides this. This feature allows the user to interrupt lengthy 11532343Sedwardoutputs safely. The structure of the input buffer is designed to 11632343Sedwardavoid race conditions without blocking interrupts. 11716284Sedward 11832343Sedward Actually, wwsetjmp and wwinterrupt() are part of a software 11932343Sedwardinterrupt scheme used by the two interrupt catchers wwrint() and 12032343Sedwardwwchild(). Asserting the interrupt lets the synchronous parts of 12132343Sedwardthe program know that there's an interesting asynchronous condition 12232343Sedward(i.e., got a keyboard character, or a child process died) that they 12332343Sedwardmight want to process before anything else. The synchronous routines 12432343Sedwardcan check for this condition with wwinterrupt() or by arranging 12532343Sedwardthat a longjmp() be done. 12632343Sedward 12732343Sedward Wwiomux() copies pseudo-terminal output into their corresponding 12816284Sedwardwindows. Without anything to do, it blocks in a select(), waiting for 12916284Sedwardread ready on pseudo-terminals. Reads are done into per-window buffers 13016284Sedwardin the window structures. When there is at least one buffer non-empty, 13116284Sedwardwwiomux() finds the top most of these windows and writes it using 13216535Sedwardwwwrite(). Then the process is repeated. A non-blocking select() is 13316535Sedwarddone after a wwwrite() to pick up any output that may have come in 13416535Sedwardduring the write, which may take a long time. Specifically, we use 13516535Sedwardthis to stop output or flush buffer when a pseudo-terminal tells us to 13616535Sedward(we use pty packet mode). The select() blocks only when all of the 13716535Sedwardwindows' buffers are empty. A wwupdate() is done prior to this, which 13816535Sedwardis the only time the screen is guaranteed to be completely up to date. 13916535SedwardWwiomux() loops until wwinterrupt() becomes true. 14016284Sedward 14116535Sedward The top level routine for all this is mloop(). In conversation 14216535Sedwardmode, it simply calls wwiomux(), which only returns when input is 14316535Sedwardavailable. The input buffer is then written to the pseudo-terminal of 14416535Sedwardthe current window. If the escape character is found in the input, 14516535Sedwardcommand mode is entered. Otherwise, the process is repeated. In 14616535Sedwardcommand mode, control is transferred to docmd() which returns only when 14716535Sedwardconversation mode is reentered. Docmd() and other command processing 14816535Sedwardroutines typically wait for input in a loop: 14916284Sedward 15016535Sedward while (wwpeekc() < 0) 15116284Sedward wwiomux(); 15216284Sedward 15316535SedwardWhen the loop terminates, wwgetc() is used to read the input buffer. 15416284Sedward 15516284Sedward Output to the physical terminal is handled by the lowest level 15616284Sedwardroutines of the window package, in the files ttoutput.c and tt.h. The 15716535Sedwardstandard IO package is not used, to get better control over buffering 15816535Sedwardand to use non-blocking reads in wwrint(). The buffer size is set to 15916284Sedwardapproximately one second of output time, based on the baudrate. 16016284Sedward 16116284Sedward The result of all this complexity is faster response time, 16216284Sedwardespecially in output stopping and flushing. Wwwrite() checks 16316284Sedwardwwinterrupt() after every line. It also calls wwupdate() for each line 16416284Sedwardit writes. The output buffer is limited to one second of output time. 16516284SedwardThus, there is usually only a delay of one to two lines plus one second 16616284Sedwardafter a ^C or ^S. Also, commands that produce lengthy output can be 16716284Sedwardaborted without actually showing all of it on the terminal. (Try the 16816535Sedward'?' command followed by escape immediately.) 169