summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING339
-rw-r--r--ChangeLog409
-rw-r--r--FAQ253
-rw-r--r--INSTALL110
-rw-r--r--Makefile2
-rw-r--r--Makefile.in253
-rw-r--r--NEWS80
-rw-r--r--NEWS.3.5119
-rw-r--r--NEWS.3.648
-rw-r--r--README102
-rw-r--r--acls.c545
-rw-r--r--acls.h89
-rw-r--r--ansi.c2511
-rw-r--r--ansi.h116
-rw-r--r--attacher.c815
-rw-r--r--comm.c223
-rw-r--r--comm.h.dist177
-rw-r--r--comm.sh77
-rw-r--r--config.h.in466
-rwxr-xr-xconfigure3257
-rw-r--r--configure.in1033
-rw-r--r--display.c1937
-rw-r--r--display.h222
-rw-r--r--doc/FAQ253
-rw-r--r--doc/Makefile.in54
-rw-r--r--doc/fdpat.ps6501
-rwxr-xr-xdoc/install.sh119
-rw-r--r--doc/screen.13349
-rw-r--r--doc/screen.info167
-rw-r--r--doc/screen.info-11514
-rw-r--r--doc/screen.info-21255
-rw-r--r--doc/screen.info-31381
-rw-r--r--doc/screen.info-4375
-rw-r--r--doc/screen.texinfo4061
-rw-r--r--etc/etcscreenrc95
-rwxr-xr-xetc/mkinstalldirs35
-rwxr-xr-xetc/newsyntax64
-rw-r--r--etc/screenrc124
-rwxr-xr-xetc/toolcheck44
-rw-r--r--extern.h315
-rw-r--r--fileio.c760
-rw-r--r--help.c857
-rw-r--r--image.h106
-rw-r--r--input.c291
-rwxr-xr-xinstall.sh119
-rw-r--r--kmapdef.c.dist130
-rw-r--r--loadav.c249
-rw-r--r--mark.c1320
-rw-r--r--mark.h47
-rw-r--r--misc.c468
-rw-r--r--os.h480
-rw-r--r--osdef.h.in182
-rw-r--r--osdef.sh46
-rw-r--r--overlay.h68
-rw-r--r--patchlevel.h237
-rw-r--r--process.c3777
-rw-r--r--pty.c331
-rw-r--r--putenv.c213
-rw-r--r--rcs.h46
-rw-r--r--resize.c750
-rw-r--r--screen.c2605
-rw-r--r--screen.h251
-rw-r--r--search.c336
-rw-r--r--socket.c1190
-rw-r--r--tek.patch79
-rw-r--r--term.c257
-rw-r--r--term.h.dist237
-rw-r--r--term.sh166
-rw-r--r--termcap.c1272
-rw-r--r--terminfo/8bits17
-rw-r--r--terminfo/README19
-rw-r--r--terminfo/checktc.c204
-rw-r--r--terminfo/sco.mail65
-rw-r--r--terminfo/screencap21
-rw-r--r--terminfo/screeninfo.src48
-rw-r--r--terminfo/test.txt603
-rw-r--r--terminfo/tetris.c20
-rw-r--r--tty.c.dist1025
-rw-r--r--tty.sh862
-rw-r--r--utmp.c800
-rw-r--r--window.c1118
-rw-r--r--window.h233
82 files changed, 54794 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..13c9d42
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..2256d80
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,409 @@
+30.10.94
+
+This is a quick overview of screen's life story. But it is not up
+to date. You'll find more details about the revision history in
+patchlevel.h and newer changes are only documented there.
+
+31.7.93 -- 3.5.1
+================
+
+* writelock, number, paste with arg, at, zombie and wall commands added.
+
+* Access Control Lists and more multi-user support added.
+
+* select and setenv commands enhanced.
+
+* socket.c: motorola bugfix.
+
+* configure.in: --srcdir support.
+
+* configure.in: recognize alpha and SUNOS3 correctly.
+
+* doc/screen.texinfo: Documentation by Jason Merrill.
+
+13.05.93 -- 3.3.3
+=================
+
+* defautonuke, silence commands added.
+
+* exec command added.
+
+* hardcopydir, logdir commands added.
+
+* Made a superb configure script.
+
+* BROKEN_PIPE, SOCK_NOT_IN_FS added for braindamaged systems.
+
+* multi display, multi user support.
+
+* process command. CS, CE switch cursorkeycap in application mode.
+
+* lockprg pow_detaches on SIGHUP
+
+* ins_reg copy_reg commands.
+
+* new screenrc syntax.
+
+* split up screen.c and ansi.c
+
+21.10.92 -- 3.2.9
+================
+
+* ChangeLog: replaces CHANGES and is in GNUish format.
+
+* Makefile (CFLAGS, M_CFLAGS, LIBS, OPTIONS): moved user config here,
+ merged all Makefiles, GNUified
+
+* socket.c (FindSocket): ignoring bad files in $SCREENDIR
+
+* config/config.linux: ported.
+
+* utmp.c, exec.c, loadav.c: split apart from screen.c/fileio.c
+
+15.07.92 -- 3.2.8
+=================
+
+* ansi.c (WriteString): automatic character set switching for 8bit support
+
+3.2.3-3.2.7
+===========
+
+* concept changes: Display structure, Multi attacher
+
+...
+
+3.2.2
+=====
+
+* screen.c (main): -m option, "_M_ake always new session", ignore $STY
+
+* screen.c (main): -Ssessionname
+* fileio.c (RcLine): ^A:sessionname give your session a nicer name.
+
+* screen.c (main): supporting detached startup via screen -d -m -Ssockname
+
+* fileio.c (stripdev): moved, could not compile
+
+* overlay.h: "stackable overlay concept"
+
+* search.c: vi-like / and ? search AND emacs-like ^S and ^R incremental search
+ in scrollback
+
+* mark.c: I meant BSDI not BSD
+
+* concept change: struct display and struct newwin introduced.
+
+* screen.c (main): -v option prints version.
+
+* screen.c (MakeWindow): ^A:screen /dev/ttya opens a character device
+ instead of forking ShellProg with a pty pair.
+
+3.2.0
+=====
+
+Ultrix port
+
+Irix 3.3 SGI port
+
+shadow password suite supported
+
+data loss on stdin overflow fixed
+
+"refresh off" keyword added.
+
+3.1.1
+------
+
+Screen is now under the GNU copyleft license. See file COPYING.
+
+command line option -A. $LINES, $COLUMNS improved.
+
+C-A : vbellwait <sec>
+
+XENIX support (Ronald Khoo)
+
+SYSV has uname() instead of gethostname().
+
+hpux has setresuid.
+
+ClearScreen now saves image to scrollback buffer.
+
+mips has setenv.
+
+numerous bugfixes.
+
+3.1 finally released version.
+=============================
+
+3.0.99: last minute changes:
+----------------------------
+
+MIPS support (J{rvinen Markku)
+
+SVR4 support (Marc Boucher)
+
+secopen() secfopen() calls replace stat/access/open.
+C-a : echo improved.
+'register int'
+
+Changes up to Screen 3.0 Patchlevel 7
+=====================================
+
+Better terminfo support: Screen now checks if a termcap/info
+entry which the name "screen.$TERM" does exist. Look in the
+"VIRTUAL TERMINAL" section of the manual for more details.
+
+Many security improvements.
+
+ScrollRegion() bug fixed which caused slow scrolling if AL
+or DL was used.
+
+Pyramid and Ultrix support added. (Tim and Larry)
+
+ENVIRONMENT support.
+ /local/etc/screenrc checks for $SYSSCREENRC
+ $HOME/.screenrc checks for $ISCREENRC and $SCREENRC
+ /local/screens checks for $ISCREENDIR and $SCREENDIR
+ .screenrc understands ${VAR} and $VAR .
+
+screen 3.0 Patchlevel 6
+=======================
+
+.screenrc:
+ screen now only opens the windows you explicitly ask for. if you
+ specify none, you still get one window, of course.
+
+screen 3.0. Patchlevel 5
+========================
+
+Ansi prototyping by Christos.
+
+copy mode: CTRL-U / CTRL-D exchanged. code cleanup.
+
+changes to screen 3.0 patchlevel 4
+==================================
+
+markkeys "string"
+ allows to rebind the keys used in copy/history mode.
+ string is made up of pairs "<oldchar>=<newchar>" which are separated
+ by a colon. Oldchar and newchar are either single ascii characters,
+ or the two character sequence ^x, where x is an ascii character, or
+ a 3 digit octal value prepended with '\'. the string "\040=.:^M=q"
+ rebinds '.' to set marks, and the return rey will abort copy mode.
+
+set scrollback 100
+ resizes the scrollback history buffer to 100 lines. a default of 50
+ is installed.
+
+A Howard Chu like scrollback history is installed. Many vi-like keys
+ are added to the copy mode. The '?' key reports on cursor position.
+
+screen 3.0 Patchlevel 3
+=======================
+
+WriteString fixed, it did kill the display variable.
+
+Yet another LP bugfix.
+
+non vt100 semi-graphics character support.
+
+waynes patch fixed
+
+screen 3.0 Patchlevel 2
+=======================
+
+wayne patches cursor motion outside scrollregions.
+
+.screenrc
+ monitor on|off
+
+changes in Screen 3.0 Patchlevel 1
+==================================
+
+screen -wipe
+
+^A : set vbell_msg "Wuff Wuff"
+
+Thousand enhancements: help resizible, copy'n'paste in main
+ socket loop, and no more '\0' hackin'. :WS=\E8;%d;%dt:
+
+screen can now resize windows under sunview.
+
+^A : set crlf on|off
+ effects markroutine join.
+
+screen learned about sized windows under X
+
+screen -ls (-d) -q
+ quiet option. We count the number of detached (attached) sessions and set
+ a return value of 10+n. The -q option inhibits all startup
+ warnings/messages. i.e. screen -R -q may return with code 12 or higher
+ or start a new/old session.
+
+pow_detach_msg "text string"
+ new command, allows messages, terminal reset, etc. on logout caused
+ by pow_detach.
+
+^A : learned a new keyword "set":
+ commands like "login on" , "vbell off", ... affect the default for
+ windows to be created. But commands like "set login off" affect
+ the actual setting of this window. and not the default.
+ such commands may be bound to keys. example:
+ bind 'O' set login off
+ is valid in your .screenrc as well as typed at the ':' prompt.
+ a bonus is ":set all" which is synonym to ":help".
+ At the Colon prompt also KeyNames can be entered, alothough that makes
+ not always sense.
+
+^A x uses a builtin lockprg, if
+ a) we don't find our lockprg, or
+ b) user supplies us with the environmet variable LOCKPRG set to "builtin"
+ the builtin locks until your login password is typed. on systems using
+ "shadow password files" you are prompted for a password.
+
+markroutine can append joined.
+
+screen removes the "controlling tty" from utmp while ptys are attached.
+
+markroutine performs CR+NL when '\n' is pressed
+
+screen may die quietly, when no TERMCAP entry for "screen" is
+found, and screen is run under X-windows
+
+_SEQUENT_ marks sequent386_ptx
+
+screen runs now under SunOS4.1.1 (we need setsid()!).
+
+bug in SetForeWindow fixed.
+
+rare markroutine bug fixed.
+
+we dont open every file the attacher tells us.
+
+we have now our wonderful "Wuff, Wuff" visual_bell
+
+we have now the interprocess-communication-buffer. secure version.
+
+'^A =' removes the interprocess-communication-buffer.
+
+markroutine as in 2.1
+
+markroutine: 'a' toggles append mode,
+ '>' like ' ', but immediately WriteFile(DUMP_EXCHANGE) then.
+ 'A' like ' ', but first switch to append mode.
+
+.screenrc understands "screen 2:faui09 rlogin faui09 -l jnweiger"
+ and "password none"
+ and "vbell [on|off]"
+
+'^A :' allows .screenrc commands "online".
+
+screen now receives new $TERM from attacher, when it is reattached
+
+MakeClientSocket() fifo version does now test for access.
+
+.screenrc learns "hardstatus {on|off}"
+
+termcap's VB is used for vbell if available.
+
+Attach() code rewritten:
+ screen now lists socket directory, if it does not find a suitable socket
+ screen -d [host.tty] detaches a running screen.
+
+screen -[ls|list]
+ list all sockets that we find in our sockdir
+
+when the socket has been removed, send a SIGCHLD to the poor SCREEN
+process and it will try to recover. then try a 'screen -r' again.
+all the socket stuff lives now in an extra file.
+
+Major changes in version 2.4:
+=============================
+
+* Test version that presents the erlangen extensions from 2.0 in a 2.3
+ screen.
+
+* window resize support
+
+* screen locking C-a x
+
+* support for SYSV
+
+* password protection
+
+* copy & paste across screens
+
+* remote detach and power detach
+
+Major changes in version 2.3:
+
+* Terminal emulation has been significantly enhanced and bugfixed.
+
+* We now fully update the last character on the screen for true auto-
+ margin terminals, though there may be some delay before the character
+ can be safely added to the screen. If your terminal has character
+ insert it will be used to shorten the delay.
+
+* Added the "termcap" .screenrc command to tweak your terminal's termcap
+ entry AND to customize the termcap generated for the virtual terminals.
+ See also the -L and -O command-line options, and the SCREENCAP environ-
+ ment variable.
+
+* Fixed screen's character handling when detached or suspended to NOT block
+ the child processes in their windows -- output continues to be processed
+ in the background.
+
+* Added a.k.a.s (window-name aliases) that allow you to customize the
+ window-information line, including being able to change the name on-
+ the-fly to reflect what's currently running in the window (see the
+ -k option, shellaka command, and ALSO KNOWN AS discussion in the doc).
+
+* Added the ability to log the output of a window to a file (see the
+ "C-a H" (log) command).
+
+* Flow-control can now be set for each window and switched interactively
+ (see the "flow" command, -f option, and FLOW CONTROL discussion).
+
+* Individual windows can be included or excluded from mention in the
+ /etc/utmp file (see the "login" command and -l option).
+
+* Added an activity monitor, which allows you to have a window watched for
+ the start of any output and alert you when it occurs (see the "C-a M"
+ (monitor) command).
+
+* Enhanced the information in the window-information line to keep track of
+ windows that have: logging turned on '(L)'; beeped in the background '!';
+ became active while being monitored '@' (see the "C-a w" (windows) command).
+
+* Added an on-line help display that lists all the commands and their
+ key bindings (see the "C-a ?" (help) command).
+
+* Extended handling of the beep message (and also the new activity message)
+ to allow '~' to specify a literal beep (see the "beep" and "activity"
+ .screenrc commands).
+
+* You can now set the default action on receipt of a hangup signal: detach
+ or terminate (see the "autodetach" .screenrc command).
+
+* Routing of characters to their virtual terminals has been enhanced to
+ not drop characters nor (in rare circumstances) hang up screen.
+
+* The NFS compatibility has been enhanced.
+
+Major changes in version 2.0a:
+
+* Screen allows you to `detach' the "screen" session from the physical
+ terminal and resume it at a later point in time (possibly on a
+ different terminal or in a different login session).
+
+ To get an impression of this functionality do the following:
+
+ - call "screen" and create a couple of windows
+ - type Control-A Control-D (screen terminates; you are back
+ in the shell)
+ - call "screen -r" to resume the detached screen
+
+* Screen supports multiple character sets and the ISO 2022 control
+ functions to designate and switch between character sets.
+ This allows you, for instance, to make use of the VT100 graphics
+ character set or national character sets.
diff --git a/FAQ b/FAQ
new file mode 100644
index 0000000..6c9c8af
--- /dev/null
+++ b/FAQ
@@ -0,0 +1,253 @@
+ jw 21.10.93
+ 05.05.94
+
+ screen: frequently asked questions -- known problems -- unimplemented bugs
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+
+Q: Why is it impossible to download a file with Kermit/sz/rz when
+ screen is running? Do I need to set some special variables?
+
+A: Screen always interprets control-sequences sent by the
+ applications and translates/optimizes them for the current
+ terminal type. Screen always parses the user input for its
+ escape character (CTRL-A). Both are basic screen features and
+ cannot be switched off. Even if it were possible to switch
+ screen into a completely transparent mode, you could never switch
+ between windows, while kermit/sz/rz is downloading a file. You
+ must wait til the end as kermit/sz/rz will not transmit your
+ input during a file transfer and as kermit/sz/rz would be very
+ confused if screen switched away the window containing the
+ other kermit/sz/rz. Simply detach your screen session for each
+ file transfer and start the transfer program only from the shell
+ where you started screen.
+
+Q: I am using screen with a YYY terminal, which supports the XXX
+ graphic language. I am very happy with it, except one thing: I
+ cannot render graphics into screen windows.
+
+A: You are out of luck there. Screen provides a fixed set of escape
+ sequences in order to make it possible to switch terminal types.
+ Screen has to know exactly what the escape sequences do to the
+ terminal because it must hold an image in memory. Otherwise
+ screen could not restore the image if you switch to another
+ window. Because of this you have to change screens escape
+ sequence parser (ansi.c) to pass the XXX graphics sequences to
+ the terminal. Of course the graphics will be lost if you switch
+ to another window. Screen will only honour graphics sequences
+ that are demanded by an overwhelming majority.
+
+Q: For some unknown reason, the fifo in /tmp/screens/S-myname is
+ gone, and i can't resume my screen session. Is there a way to
+ recreate the fifo?
+
+A: Screen checks the fifo/socket whenever it receives a SIGCHLD
+ signal. If missing, the fifo/socket is recreated then. If screen
+ is running non set-uid the user can issue a 'kill -CHLD
+ screenpid' directly (it is -CHILD on some systems). Screenpid is
+ the process-id of the screen process found in a 'ps -x' listing.
+ But usually this won't work, as screen should be installed set-
+ uid root. In this case you will not be able to send it a signal,
+ but the kernel will. It does so, whenever a child of screen
+ changes its state. Find the process-id (shellpid below) of the
+ "least important" shell running inside screen. The try 'kill
+ -STOP shellpid'. If the fifo/socket does not reappear, destroy
+ the shell process. You sacrify one shell to save the rest. If
+ nothing works, please do not forget to remove all processes
+ running in the lost screen session.
+
+Q: When you start "screen" a page of text comes up to start you
+ off. Is there a way to get rid of this text as a command line
+ argument or by using a switch of some sort.
+
+A: Just put the following line in your ~/.screenrc:
+ startup_message off
+ Many peole ask this, although it is in the man page, too :-)
+
+Q: Start "screen emacs" and run emacs function suspend-emacs
+ (ctrl-z). The window containing emacs vanishes.
+
+A: This is a known bug. Unfortunatly there is no easy fix
+ because this is specified in the POSIX standard. When a new
+ window is created Screen opens up a new session because the
+ window has to get the pty as a controlling terminal (a
+ session can only have one controlling terminal). With the
+ setsid() call the process also creates a new process
+ group. This process group is orphaned, because there is no
+ process in the session which is not in the process
+ group. Now if the process group leader (i.e. your program)
+ gets a TTIN/TTOU/TSTP, POSIX states that the kernel must
+ send a KILL signal to the process group because there is no
+ one left to continue the process. Even if screen would
+ try to restart the program, that would be after it received the
+ KILL signal which cannot be caught or ignored.
+
+ tromey@klab.caltech.edu (Tom Tromey): I've noticed this exact
+ same problem. I put this in my .emacs file. It seems to work:
+
+ ;; If running under screen, disable C-z.
+ (if (and (getenv "STY") (not window-system))
+ (global-unset-key "\C-z"))
+
+Q: Screen gets the terminal size wrong and messes up.
+
+A: Before you start screen: Check with 'stty -a' what the terminal
+ driver thinks about rows and columns. Check the environment
+ variables LINES and COLUMNS. Then from within screen check with
+ the info command (CTRL-A i) what size screen thinks your terminal
+ is. If correcting tty driver setting and environment variables
+ does not help, look up the terminal capability definition. First
+ the TERMCAP environment variable. If this is not set, look up the
+ terminals name as defined in the environment variable TERM in
+ /etc/termcap or in the terminfo database with untic or infocmp.
+ There may be :li=...: and :co=...: or even :ll=...: entries
+ (cols#... and lines#... when it's terminfo) defined incorrectly.
+ Either construct your own TERMCAP environment variables with
+ correct settings, use screens terminfo/termcap command in your
+ .screenrc file or have the database corrected by the system
+ administrator.
+
+Q: Screen messes up the terminal output when I use my favourite ap-
+ plication. Setting the terminal size does not help.
+
+A: Probably you got the termcap/terminfo entries wrong. Fixing this
+ is a three stage procedure. First, find out if terminfo or
+ termcap is used. If your system only has /etc/termcap,
+ but not /usr/lib/terminfo/... then you are using termcap.
+ Easy. But if your system has both, then it depends how the appli-
+ cation and how screen were linked. Beware, if your applica-
+ tion runs on another host via rlogin, telnet or the like, you
+ should check the terminfo/termcap databases there. If you cannot
+ tell if terminfo or termcap is used (or you just want to be
+ save), the do all steps in stage 3 in parallel for both
+ systems (on all envolved hosts). Second: Understand the basic
+ rules how screen does its terminal emulation. When screen is
+ started or reattached, it relies on the TERM environment variable
+ to correctly reflect the terminal type you have physically
+ in front of you. And the entry should either exist in the system
+ terminfo/termcap database or be specified via the TERMCAP en-
+ vironment variable (if screen is using the termcap system). On
+ the other end, screen understands one set of control codes. It
+ relies on the application using these codes. This means applica-
+ tions that run under screen must be able to adapt their con-
+ trol codes to screen. The application should use the TERM vari-
+ able and termcap or terminfo library to find out how to drive
+ its terminal. When running under screen, the terminal is virtual
+ and is only defined by the set of control codes that screen
+ understands. The TERM variable is automatically set to
+ "screen" and the "screen"-entries should exist in the data-
+ bases. If your application uses hardcoded control codes rather
+ than a database, you are on your own. Hint: The codes under-
+ stood by screen are a superset of the very common definition
+ named "vt100". Look at the documentation of screen. The
+ codes are listed there. Third: Have the entry "screen" in-
+ stalled on all hosts or make sure you can live with "vt100".
+ Check the codes sent by your application, when the TERM variable
+ is set to "screen". Do not try to set the TERM variable inside
+ screen to anything other than "screen" or "vt100" or compati-
+ ble. Thus your application can drive screen correctly. Also take
+ care that a good entry is installed for your physical terminal
+ that screen has to drive. Even if the entry was good enough
+ for your application to drive the terminal directly, screen may
+ find flaws, as it tries to use other capabilities while op-
+ timizing the screen output. The screenrc commands
+ "termcap" and/or "terminfo" may help to fine-tune capabilities
+ without calling the supervisor to change the database.
+
+Q: I cannot configure screen. Sed does not work.
+
+A: The regular expressions used in our configure scrip are too
+ complicated for GNU sed version 2.03. In this regard it is bug
+ compatible with Ultrix 3.1 "sed": GNU sed version 2.03 dumps
+ core with our configure script. Try an older release. E.g. from
+ ftp.uni-erlangen.de:/pub/utilities/screen/sed-2.02b.tar.gz
+
+Q: When reattaching a session from a different Workstation, the
+ DISPLAY environment variable should be updated. Even ``CTLR-A
+ : setenv DISPLAY newhost:0'' does not work as expected.
+
+A: Under unix every process has its own environment. The environ-
+ ment of the SCREEN process can be changed with the `setenv' com-
+ mand. This however cannot affect the environment of the
+ shells or applications already running under screen. Subsequently
+ spawned processes will reflect the changes. One should be aware
+ of this problem when running applications from very old shells.
+ Screen is a means for keeping processes alive.
+
+Q: About once every 5 times I ran the program, rather than getting
+ a "screen," I got someone elses IRC output/input.
+
+A: What probably happened is that an IRC process was left running on
+ a pseudo tty in such a way that the kernel thought the tty was
+ available for reallocation. You can fix this behaviour by
+ applying the SunOS 4.1.x tty jumbo patch (100513-04).
+
+Q: Screen compiled on SunOS 5.3 cannot reattach a detached session.
+
+A: You are using /usr/ucb/cc, this compiler is wrong. Actually it
+ links with a C-library that mis-interprets dirent. Try again
+ with /opt/SUNWspro/bin/cc!
+
+Q: The "talk" command does not work when Screen is active.
+
+A: Talk and several other programs rely on entries in the Utmp-
+ Database (/etc/utmp). On some systems this Database is world
+ writable, on others it is not. If it is not, screen must be
+ installed with the appropriate permissions (user or group s-bit)
+ just like any program that uses PTYs (rlogin, xterm, ...). When
+ screen cannot write to utmp, you will see messages on you display
+ which do not belong to any screen window.
+ When screen can update utmp, it is not guaranteed that it does as
+ you expect. First this depends on the config.h file defining
+ UTMPOK, LOGINDEFAULT, and perhaps CAREFULUTMP. Second it depends
+ on the screenrc files (system wide and per user), if utmp entries
+ are done. Third, you can control whether windows are logged in
+ with screens ``login'' command.
+
+Q: Seteuid() does not work as expected in AIX. Attempting a multi-
+ user-attach results in a screen-panic: "seteuid: not owner".
+
+A: This is not a screen problem. According to Kay Nettle
+ (pkn@cs.utexas.edu) you need the AIX patch PTF 423674.
+
+Q: When I type cd directory (any directory or just blank) from
+ within one of the windows in screen, the whole thing just freezes
+ up.
+
+A: You display the current working directory in xterm's title bar,
+ This may be caused by hardcoded ESC-sequences in the shell prompt
+ or in an cd alias. In Xterm the coding is
+ ESC ] n ; string_to_display ^G
+ where n = 1, 2, 3 selects the location of the displayed string.
+ Screen misinterprets this as the ansi operating system comment
+ sequence:
+ ESC ] osc_string
+ and waits (according to ansi) for the string terminator
+ ESC \
+ Screen versions after 3.5.12 may provide a workaround.
+
+Q: Mesg or biff cannot be turned on or off while running screen.
+
+A: Screen failed to change the owner of the pty it uses. You need to
+ install screen setuid-root. See the file INSTALL for details.
+
+Q: The cursor left key deletes the characters instead of just moving the
+ cursor. A redisplay (^Al) brings everything back.
+
+A: Your terminal emulator treats the backspace as "destructive". You
+ can probably change this somewhere in the setup. We can't think
+ of a reason why anybody would want a destructive backspace, but
+ if you really must have it, add the lines
+ termcap <TERM> 'bc@:bs@'
+ terminfo <TERM> 'bc@:bs@'
+ to your ~/.screenrc (replace <TERM> with the terminal type your
+ emulator uses).
+
+Q: I have an old SysV OS (like Motorola SysV68) and sometimes screen
+ doesn't reset the attributes correctly. A redisplay (^Al) doesn't
+ make things better.
+
+A: The libcurses library has a bug if attributes are cleared with
+ the special ue/se capabilities. As a workaround (other than upgrading
+ your system) modify 'rmul' (and 'rmso'?) in screen's terminfo entry:
+ rmul=\E[m, rmso=\E[m
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..d382078
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,110 @@
+Installation of screen3.6 jw 9.04.95
+
+
+0.) This instruction is quite lengthy
+-------------------------------------
+.. and there are still important items near the end. Start here:
+Unpack. Screen comes as a compressed tar archive. You need gzip to
+uncompress. And... well, you probably already managed that step,
+when you are reading this.
+
+For general documentation on the coding and usage standards this
+distributions follows, see the GNU standards document on
+prep.ai.mit.edu:pub/gnu/standards.*, especially the `Makefile
+Conventions', `Configuration', and `User Interfaces' sections.
+
+
+1.) configure & config.status
+-----------------------------
+Run configure. This should create a reasonable Makefile and a config.h file
+suited for your machine. Rename config.status to reflect the architecture
+(hostname) where it was built. To reconfigure quickly for that architecture
+just run that config.status file.
+If this process fails, try to find out what configure did do and what it
+should have checked. Mail me.
+Actually the initial Makefile that comes with the distribution just runs
+configure -- thus you can start by typing 'make' right after unpacking.
+You will be prompted to run 'make' again, which will really make screen.
+
+2.) Makefile & config.h
+-----------------------
+Look through the Makefile & user configuration section in config.h and check
+pathnames. Change them to suit your installation requirements. Usually
+sysadmins discuss the location of SOCKDIR, whether it should be in /tmp or
+not. At least it must be on a filesystem that supports sockets/fifos.
+SOCKDIR must not point into an AFS (Andrew File System) mounted directory.
+If you are uncrertain about your NFS implementation, use a UFS directory for
+SOCKDIR. Personally, I favour a users home directory and recommend the the
+/tmp/ area.
+The path for ETCSCREENRC may also need to be adapted.
+
+3.) how to actually compile
+---------------------------
+Run 'make'. Screen should compile without too many warnings :)
+The creation of term.h, comm.h, tty.c or osdef.h may fail on some machines
+for some odd reason. (E.g. the sed under SCO-unix is known to be
+case-insensitive and breaks term.h) If so, please mail a short description
+of the problem to screen@uni-erlangen.de and use the files ending in .dist
+as a replacement (or in case of osdef.h retry with an empty file).
+You can then try 'make install' (if you dare).
+
+4.) where to install
+--------------------
+You may well run screen from your private binary directory and with a
+private socket directory like $HOME/.screen. But to have a full featured
+screen and (from a users point of view) more secure pty's you should
+consult a system administrator and discuss installing screen setuid-root
+in some globally accessible directory like /usr/local/bin.
+
+Consider this, when deciding whether you install screen setuid-root:
+- On some machines root priviliges are required to open pty's.
+- Pty's should be owned by the user, so that she can do chmod to prevent
+ intrudor attacks. The PTYs used by screen will remain world read-writable
+ if screen is not installed setuid-root.
+- Some commands only work properly when the pty is owned by the user.
+ These include mesg and biff.
+- The ^At feature may need to lseek and read the kernel file to retrieve
+ the load average.
+- On most machines utmp slots can only be created/manipulated with root
+ privileges. Users will appear to be logged on the primary terminal
+ instead of the screen windows, if screen is not installed setuid-root.
+- Multi-user screen sessions are only allowed when screen has a root-s-bit.
+- If screen sockets of multiple users are kept in one directory (e.g.
+ /tmp/screens), this directory must be world writeable when screen is not
+ installed setuid-root. Any user can remove or abuse any socket then.
+
+
+5.) doc/screen.1 & doc/screen.texinfo
+-------------------------------------
+The man page doc/screen.1 should go to /usr/local/man/man1, or some similar
+directory. It should format nicely with nroff -man. If it does not, then
+try removing extra dots with: sed -e 's/^\.\././' < screen.1 | nroff -man
+The info page doc/screen.texinfo contains basically the same information as
+the man-page, we may have missed one or another thing in one of the files.
+If so, mail me.
+
+6.) etc/screenrc & etc/etcscreenrc
+----------------------------------
+The files screenrc and etc/etcscreenrc are instructive samples that
+demonstrate what can/should be done from your private .screenrc and from
+$ETCSCREENRC -- do not just copy them. Read them. Look through the
+etcscreenrc file for system wide defaults that you like to set. e.g.
+autodetach off, startup_message off, vbell on, ...aak
+Since version 3.2.15 the screenrc file syntax changed slightly. All rc files
+from previous versions should be run through the newsyntax script that comes
+with this package.
+If and only if you want to install screen as a console multiplexer, look
+at the *.sample files and what 'make cscreen' suggests.
+
+7.) terminfo/screeninfo.src & terminfo/screencap
+------------------------------------------------
+Every now and then we update the termcap/terminfo entries for screen.
+E.g. keycodes were added in 3.6.0 -- thus you check that your termcap/terminfo
+database is up to date. See the README in the terminfo subdirectory.
+
+8.) have fun
+------------
+To get an idea what the basic screen commands are, read the file README.
+Request snail mail address for liquid and solid donations. :-)
+
+Juergen Weigert. (screen@uni-erlangen.de)
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..9458230
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
+install all Makefiles and config:
+ sh ./configure
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..f9fc599
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,253 @@
+#
+# Makefile template for screen
+#
+# See machine dependant config.h for more configuration options.
+#
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+# Where to install screen.
+
+prefix = /usr/local
+exec_prefix = $(prefix)
+
+# don't forget to change mandir and infodir in doc/Makefile.
+bindir = $(exec_prefix)/bin
+
+VERSION = @VERSION@
+
+ETCSCREENRC = `sed < config.h -n -e '/define ETCSCREENRC/s/^.*"\([^"]*\)"/\1/p'`
+
+CC = @CC@
+CFLAGS = -O
+LDFLAGS =
+LIBS = @LIBS@
+
+CPP_DEPEND=/lib/cpp -MM
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+AWK = @AWK@
+
+### Chose some debug configuration options:
+# -DDEBUG
+# Turn on really heavy debug output. This is written to
+# /tmp/debug/screen.{front,back} Look at these files and quote
+# questionable sections when sending bug-reports to the author.
+# -DTMPTEST
+# Change the socket directory to a location that does not interfere
+# with the (suid-root) installed screen version. Use that in
+# combination with -DDEBUG
+# -DDUMPSHADOW
+# With shadow-pw screen would never dump core. Use this option if you
+# still want to have a core. Use only for debugging.
+# -DFORKDEBUG
+# Swap roles of father and son when forking the SCREEN process.
+# Useful only for debugging.
+OPTIONS=
+#OPTIONS= -DDEBUG -DTMPTEST
+
+SHELL=/bin/sh
+
+CFILES= screen.c ansi.c fileio.c mark.c misc.c resize.c socket.c \
+ search.c tty.c term.c window.c utmp.c loadav.c putenv.c help.c \
+ termcap.c input.c attacher.c pty.c process.c display.c comm.c \
+ kmapdef.c acls.c
+OFILES= screen.o ansi.o fileio.o mark.o misc.o resize.o socket.o \
+ search.o tty.o term.o window.o utmp.o loadav.o putenv.o help.o \
+ termcap.o input.o attacher.o pty.o process.o display.o comm.o \
+ kmapdef.o acls.o
+
+all: screen screen.info
+
+screen: $(OFILES)
+ $(CC) $(LDFLAGS) -o $@ $(OFILES) $(LIBS)
+
+.c.o:
+ $(CC) -c -I. -I$(srcdir) $(M_CFLAGS) $(DEFS) $(OPTIONS) $(CFLAGS) $<
+
+install_bin: screen
+ $(INSTALL_PROGRAM) screen $(bindir)/screen-$(VERSION)
+ -chown root $(bindir)/screen-$(VERSION) && chmod 4755 $(bindir)/screen-$(VERSION)
+# This doesn't work if $(bindir)/screen is a symlink
+ -if [ -f $(bindir)/screen ] && [ ! -f $(bindir)/screen.old ]; then mv $(bindir)/screen $(bindir)/screen.old; fi
+ rm -f $(bindir)/screen
+ ln -s screen-$(VERSION) $(bindir)/screen
+
+install: installdirs install_bin
+ cd doc ; $(MAKE) install
+ -tic ${srcdir}/terminfo/screeninfo.src
+# Better do this by hand. E.g. under RCS...
+# cat ${srcdir}/terminfo/screencap >> /etc/termcap
+ @echo "termcap entry (${srcdir}/terminfo/screencap) should be installed manually."
+ @echo "You may also want to install $(srcdir)/etc/etcscreenrc in" $(ETCSCREENRC)
+
+installdirs:
+# Path leading to ETCSCREENRC and Socketdirectory not checked.
+ $(srcdir)/etc/mkinstalldirs $(bindir)
+ cd doc ; $(MAKE) installdirs
+
+uninstall:
+ rm -f $(bindir)/screen-$(VERSION)
+ rm -f $(bindir)/screen
+ -mv $(bindir)/screen.old $(bindir)/screen
+ rm -f $(ETCSCREENRC)
+ cd doc; $(MAKE) uninstall
+
+shadow:
+ mkdir shadow;
+ cd shadow; ln -s ../*.[ch] ../*.in ../*.sh ../configure ../doc ../terminfo .
+ rm -f shadow/term.h shadow/tty.c shadow/comm.h shadow/osdef.h
+
+term.h: term.c term.sh
+ AWK=$(AWK) srcdir=$(srcdir) sh $(srcdir)/term.sh
+
+kmapdef.c: term.h
+
+tty.c: tty.sh
+ sh $(srcdir)/tty.sh tty.c
+
+comm.h: comm.c comm.sh config.h
+ AWK=$(AWK) CC="$(CC) $(CFLAGS)" srcdir=${srcdir} sh $(srcdir)/comm.sh
+
+osdef.h: osdef.sh config.h osdef.h.in
+ CC="$(CC) $(CFLAGS)" srcdir=${srcdir} sh $(srcdir)/osdef.sh
+
+docs:
+ cd doc; $(MAKE) dvi screen.info
+
+dvi info screen.info:
+ -cd doc; $(MAKE) $@
+
+mostlyclean:
+ rm -f $(OFILES) screen
+
+clean celan: mostlyclean
+ rm -f tty.c term.h comm.h osdef.h
+
+# Delete all files from the current directory that are created by
+# configuring or building the program.
+# building of term.h/comm.h requires awk. Keep it in the distribution
+# we keep config.h, as this file knows where 'make dist' finds the ETCSCREENRC.
+distclean: mostlyclean
+ rm -f screen-$(VERSION).tar screen-$(VERSION).TZ
+ rm -f config.status Makefile
+ rm -f osdef.h doc/Makefile
+ echo "install all Makefiles and config:" > Makefile
+ echo " sh ./configure" >> Makefile
+
+# Delete everything from the current directory that can be
+# reconstructed with this Makefile.
+realclean: distclean
+ rm -f tty.c term.h comm.h
+ rm -f config.h
+
+TAGS: $(CFILES)
+ ctags $(CFILES) *.h
+ ctags -e $(CFILES) *.h
+
+dist: screen-$(VERSION).tar.gz
+
+screen-$(VERSION).tar: term.h comm.h tty.c kmapdef.c
+ -rm -rf dist
+ mkdir dist
+ mkdir dist/screen-$(VERSION)
+ ln acls.h ansi.h display.h extern.h mark.h os.h overlay.h \
+ patchlevel.h rcs.h screen.h window.h image.h \
+ osdef.h.in term.sh tty.sh comm.sh osdef.sh \
+ acls.c ansi.c attacher.c comm.c display.c window.c fileio.c help.c \
+ input.c loadav.c mark.c misc.c process.c pty.c putenv.c \
+ screen.c search.c socket.c term.c termcap.c utmp.c resize.c \
+ ChangeLog COPYING INSTALL NEWS* install.sh \
+ dist/screen-$(VERSION)
+ ln configure.in configure dist/screen-$(VERSION)
+ sed -e 's@"/local/screens@"/tmp/screens@' -e 's@"/local@"/usr/local@g' < config.h.in > dist/screen-$(VERSION)/config.h.in
+ sed -e 's@[ ]/local@ /usr/local@g' -e 's/^CFLAGS = -g/CFLAGS = -O/' < Makefile.in > dist/screen-$(VERSION)/Makefile.in
+ ln term.h dist/screen-$(VERSION)/term.h.dist
+ ln comm.h dist/screen-$(VERSION)/comm.h.dist
+ ln tty.c dist/screen-$(VERSION)/tty.c.dist
+ ln kmapdef.c dist/screen-$(VERSION)/kmapdef.c.dist
+ ln README dist/screen-$(VERSION)/README
+ ln tek.patch dist/screen-$(VERSION)/tek.patch
+ mkdir dist/screen-$(VERSION)/terminfo
+ cd terminfo; ln 8bits README checktc.c sco.mail screencap \
+ screeninfo.src test.txt tetris.c \
+ ../dist/screen-$(VERSION)/terminfo
+ mkdir dist/screen-$(VERSION)/etc
+ cd etc; ln * ../dist/screen-$(VERSION)/etc
+ sed -e 's/^startup/#startup/' -e 's/^autodetach/#autodetach/' < $(ETCSCREENRC) > dist/screen-$(VERSION)/etc/etcscreenrc
+ cp $(HOME)/.screenrc dist/screen-$(VERSION)/etc/screenrc
+ mkdir dist/screen-$(VERSION)/doc
+ sed -e 's@/local/emacs@/usr/local@g' < doc/Makefile.in > dist/screen-$(VERSION)/doc/Makefile.in
+ cd doc; ln FAQ screen.1 screen.texinfo fdpat.ps \
+ ../dist/screen-$(VERSION)/doc
+ cd doc; if test -f screen.info; then ln screen.info* \
+ ../dist/screen-$(VERSION)/doc; fi
+ cd dist/screen-$(VERSION)/doc; ln -s ../install.sh .
+ cd dist/screen-$(VERSION); ln -s doc/FAQ .
+ echo "install all Makefiles and config:" > dist/screen-$(VERSION)/Makefile
+ echo " sh ./configure" >> dist/screen-$(VERSION)/Makefile
+ cd dist; tar chf ../screen-$(VERSION).tar screen-$(VERSION)
+ rm -rf dist
+
+screen-$(VERSION).tar.gz: screen-$(VERSION).tar
+ gzip -f screen-$(VERSION).tar
+
+# Perform self-tests (if any).
+check:
+
+lint:
+ lint -I. $(CFILES)
+
+saber:
+ #load $(CFLAGS) screen.c ansi.c $(LIBS)
+
+mdepend: $(CFILES) term.h
+ @rm -f DEPEND ; \
+ for i in ${CFILES} ; do \
+ echo "$$i" ; \
+ echo `echo "$$i" | sed -e 's/.c$$/.o/'`": $$i" `\
+ cc -E $$i |\
+ grep '^# .*"\./.*\.h"' |\
+ sort -t'"' -u +1 -2 |\
+ sed -e 's/.*"\.\/\(.*\)".*/\1/'\
+ ` >> DEPEND ; \
+ done
+
+
+depend: $(CFILES) term.h
+ cp Makefile Makefile~
+ sed -e '/\#\#\# Dependencies/q' < Makefile > tmp_make
+ for i in $(CFILES); do echo $$i; $(CPP_DEPEND) $$i >> tmp_make; done
+ mv tmp_make Makefile
+
+screen.o socket.o: Makefile
+
+### Dependencies:
+screen.o: screen.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h patchlevel.h rcs.h screen.h term.h window.h
+ansi.o: ansi.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+fileio.o: fileio.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+mark.o: mark.c acls.h ansi.h comm.h config.h display.h extern.h image.h mark.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+misc.o: misc.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+resize.o: resize.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+socket.o: socket.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+search.o: search.c acls.h ansi.h comm.h config.h display.h extern.h image.h mark.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+tty.o: tty.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+term.o: term.c rcs.h term.h
+window.o: window.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+utmp.o: utmp.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+loadav.o: loadav.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+putenv.o: putenv.c config.h rcs.h
+help.o: help.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+termcap.o: termcap.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+input.o: input.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+attacher.o: attacher.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+pty.o: pty.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+process.o: process.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+display.o: display.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
+comm.o: comm.c acls.h comm.h config.h rcs.h
+kmapdef.o: kmapdef.c config.h
+acls.o: acls.c acls.h ansi.h comm.h config.h display.h extern.h image.h os.h osdef.h overlay.h rcs.h screen.h term.h window.h
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..0224ff3
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,80 @@
+
+ ----------------------------
+ What's new in screen-3.7 ?
+ ----------------------------
+
+* Color support. Screen understands the following capabilities:
+ AF (setaf) = Set foreground color (ANSI compatible)
+ AB (setab) = Set background color (ANSI compatible)
+ AX = Does understand ANSI set default fg/bg color
+ (\E[39m / \E[49m)
+ The tweaks for the color xterm would be:
+ termcap xterm 'AF=\E[3%dm:AB=\E[4%dm'
+ terminfo xterm 'AF=\E[3%p1%dm:AB=\E[4%p1%dm'
+ Caution: Screen exposes a bug in X11R6 color xterm. Either use the
+ patch ftp.uni-erlangen.de:pub/utilities/screen/color_xterm_patch
+ or a clean rewrite of xterm: rxvt.
+
+* Resize code completely rewritten. Long lines now get rewrapped,
+ no information gets lost when a window is narrowed and widened. This
+ affects both the visible window and its scrollback buffer. It is a
+ big improvement for the latter. In previous versions the scrollback
+ buffer was clipped when the window narrowed and padded with
+ whitespace when it widened.
+
+* Input handling changed. The command key can now be a prefix
+ of a function key sequence (hello wyse users :) )
+
+* An empty argument to the escape command is allowed to disable
+ command key processing. This is only allowed if some key
+ is bound to the "command" command. This example makes F1 the
+ new command key and allows the previous command key (usually ^A)
+ to be typed directly:
+ bindkey -k k1 command
+ escape ""
+
+* New 'digraph' command (bound to ^A^V)
+ ^A^Va" or ^A^V0344 input an a-umlaut
+ This helps if you want to work in an ISO-latin1 environment but your
+ terminal's keyboard lacks a some of the more special characters.
+
+* activity/bell message strings can now include the window title
+ and the current date/time:
+ %t - title
+ %n - number (a single % still works)
+ %d - day
+ %D - weekday name
+ %m - month
+ %M - month name
+ %y - year (2 digit)
+ %Y - year (4 digit)
+ %w - hour:minutes (24h format)
+ %W - hour:minutes (12h format)
+ %s - seconds
+ %a - am/pm
+ %A - AM/PM
+ Please do not use a single '%' character for window titles any more.
+ It is obsoleted by '%n' and will vanish in future releases.
+
+* 'defhstatus' command to give every window a default
+ hardstatus line. '^E' is used as a string escape instead of '%'.
+ All the above substitution codes apply, but you must use ^E (octal
+ 005) here, as '%' is likely to appear in automaticaly generated
+ hardstatus lines. Try 'defhstatus "Screen: window ^E (^Et)"'.
+
+* In screenrc files and colon command mode: Input parser changed to
+ also understand caret notation ('^') to mean "Control-" (as in
+ the ^E example above).
+
+* "logdir" command changed to "logfile". You can now specify the
+ filename instead of the directory. The same directives as
+ understood by the activity/bell messages can be used.
+ The default is "screenlog.%n".
+
+* Special terminfo workaround make delay processing work for
+ the first time! If you had trouble with padding, then try again.
+
+* New incomprehensible capability XC added to specify character
+ translation depending on the terminal type. See the manual for
+ more details and examples.
+
diff --git a/NEWS.3.5 b/NEWS.3.5
new file mode 100644
index 0000000..d0d1970
--- /dev/null
+++ b/NEWS.3.5
@@ -0,0 +1,119 @@
+
+ ----------------------------
+ What's new in screen-3.5 ?
+ ----------------------------
+
+
+* Texinfo manpage! Thanks to Jason Merrill.
+
+* Screen now has a very large 'configure' script. If you have
+ problems with the resulting configuration please send mail to
+ screen@uni-erlangen.de.
+
+* Stackable overlay planes.
+ All commands are available even if you work with an overlay. Thus
+ you can be in copy/paste mode on several windows!
+
+* Unification of key bindings and screen commands. All keys now generate
+ commands.
+
+* Screen now reads/writes only in asyncronous mode.
+
+* Ansi parser speedup code resulting in much faster output of text.
+
+* Changed the rc file syntax. Commands now directly affect the current
+ window. The default settings are changed with 'def...' commands.
+ The 'set' keyword no longer exists.
+ Please run the 'newsyntax' script on your old screenrc files!
+
+* Emacs style isearch added to copy mode. Try ^A ESC ^R screen ^R ^R
+ to locate the last three occurences of the word 'screen' in the
+ history buffer.
+
+* New command 'silence'. Alarms the user whenever there was inactivity
+ for a specified amount of time on a certain window.
+ Useful if you want to wait for a compilation to end.
+
+* Much better margin handling:
+ Screen now handles autowrapped lines correctly in the redisplay and
+ copy/paste functions.
+
+* New commands for pastebuffer management:
+ 'copy_reg' copies the pastebuffer to a register,
+ 'ins_reg' pastes a register,
+ 'register' fills a register with a string,
+ 'process' stuffs a register into strings input queue.
+
+* Autonuke feature. Flush the output buffer if the window gets
+ cleared. Enable this with 'autonuke on'.
+
+* Modifications to save memory: Empty attribute and font lines don't
+ get allocated. This is very useful if you have a lage scrollback.
+
+* Multi display support:
+ You can now attach from more than one terminal to a session with
+ the '-x' option.
+
+* New option '-S' to specify socket name.
+
+* Experimental multiuser support added:
+ You can start screen in multiuser Mode by prepending the socket
+ name with a '/' (or by the command 'multiuser on').
+ If another user wants to attach to the screen session, he can do
+ this by prepending the socketname with 'screenuser/'.
+ Of course he must be in the access control list for a successful
+ attach (see the acladd/acldel command).
+
+* Extension to the 'screen' command: You can now specify tty lines
+ instead of programs. This can be used for console management.
+ Added the command 'break' to send a break to the tty line.
+ Not really a new feature, but terminal initialisation now works
+ on suns.
+
+* Input/output filters added. This has been implemented to allow the
+ user to configure an open tty line, but got soon exended to allow
+ all sorts of filters. For more information read the explanation
+ of the 'exec' command in the man page and check the 'fdpat.ps'
+ document.
+
+* Screen can now be started detached (screen -d -m -S sockname).
+ This is usefull if you want to start screen in your /etc/rc file
+ (e.g. as a console multiplexer)
+
+* Console grabbing added ('console on' command).
+
+* Windows can now be selected by akas, too. (Per default bound to the
+ >'< key.)
+
+* New terminal capabiliteise CS/CE for cursorkey control.
+
+* setenv/unsetenv commands added.
+
+* Expansion of environment variables ($VAR) and terminal capabilities
+ ($:TC:) in the screenrc files and detach messages.
+ Example: pow_detach_msg "Session of \$LOGNAME \$:cr:\$:nl:ended."
+
+* New commands:
+ 'hardcopydir' and 'logdir' to change the output directories,
+ 'partial' and 'allpartial' to make screen only refresh the line
+ containing the cursor if a window is selected (useful for slow
+ modem connections).
+
+* Cleanup of the provided termcap/terminfo file. Please install
+ the new one!
+
+* The program 'terminfo/checktc.c' does a visual check of a
+ termcap/terminfo entry. Please try it before calling screen and
+ in a screen session.
+
+* LOTS of bugfixes and code cleanup.
+
+Thanks to all the beta testers who helped porting screen to at least
+the following platforms: Ultrix, SunOS, Solaris, BSD43, linux, NEWSOS,
+Irix, OSF/1, Harris CX/UX, hpux, dynix/ptx, AIX.
+And even more thanks to the brave who attempted to use the 'exec'
+command features.
+
+ Donnate patches, bugreports, suggestions, money, beer & pizza to
+ screen@uni-erlangen.de
+
diff --git a/NEWS.3.6 b/NEWS.3.6
new file mode 100644
index 0000000..6d4360f
--- /dev/null
+++ b/NEWS.3.6
@@ -0,0 +1,48 @@
+
+ ----------------------------
+ What's new in screen-3.6 ?
+ ----------------------------
+
+* Input translation! This makes the vt100 emulation complete.
+ As an addition it is now possible to bind any command to any
+ (function-) key. See the man page for more details (bindkey
+ command).
+
+* Status line support. Each window can have a different status line.
+ Use the ANSI APC string to set the status line, i.e.:
+ <ESC>_<status string><ESC>\
+ (For convenience the xterm sequence is also accepted.)
+ You may want to add
+ termcap * '' ':hs:ts=\E_:fs=\E\\:ds=\E_\E\\:'
+ terminfo * '' ':hs:ts=\E_:fs=\E\\:ds=\E_\E\\:'
+ to your ~/.screenrc to make screen advertise the hardstatus
+ support.
+
+* Zombie feature added. Windows now may generate a message (with a
+ timestamp) if they die and stay around until the user presses
+ a key.
+
+* New paste syntax: Paste can now concatenate registers and paste
+ either on screen or in anouther register.
+ This makes the old "ins_reg", "copy_reg" commands obsolete.
+
+* More architecures supported. Screen now runs on AIX3.2.5,
+ Solaris, NeXT and some other exotic platforms.
+
+* Kanji support added. Screen understands JIS, EUC and SJIS coding.
+ This is an experimental feature.
+
+* GR charset switching (ISO 2022) implemented. Can be enabled with
+ the "gr" command.
+
+* C1 sequences implemented (see the "c1" command).
+
+* Tek support from Xiaoguang Zhang. Apply tek.patch if you want to
+ make screen pass tek sequences.
+
+* List of new commands:
+ bindkey, c1, command, defc1, defgr, defkanji, gr, kanji, mapdefault,
+ mapnotnext, maptimeout, pastefont, printcmd, readreg, stuff, zombie
+
+* Lots of other bugs fixed.
+
diff --git a/README b/README
new file mode 100644
index 0000000..362674f
--- /dev/null
+++ b/README
@@ -0,0 +1,102 @@
+
+ [If you just got the screen package, it pays to read the file INSTALL]
+ [This intro only describes the most common features to get you started]
+
+
+Short introduction to screen (Version 3.6.0) lvirden 8-8-93
+
+ [note that this intro only describes the most common screen features]
+
+Send bugreports, fixes, enhancements, t-shirts, money, beer & pizza to
+ screen@uni-erlangen.de
+
+iscreen provides you with an ANSI/vt100 terminal emulator, which can multiplex
+up to 10 pseudo-terminals. On startup, it executes $SHELL in window 0.
+Then it reads $HOME/.screenrc to learn configuration, keybindings, and
+possibly open more windows.
+
+ C-a ? (help) Show all keybindings.
+
+ C-a c (screen) Create new windows.
+
+ C-a SPACE (next) Advance to next window (with wraparound).
+
+ C-a C-a (other) Toggle between the current and previously
+ displayed windows.
+
+ C-a 0 (select n) Switch to window n=0 ... 9.
+ ...
+ C-a 9
+
+ C-a w (windows) Show a list of window names in the status line.
+
+ C-a a (meta) Send a literal C-a/C-s/C-q to the
+ C-a s (xoff) process in the window.
+ C-a q (xon) For instance, emacs uses C-a and C-s.
+
+ C-a l (redisplay) Redraw this window.
+
+ C-a W (width) Toggle between 80 & 132 columns mode.
+
+ C-a L (login) Try to toggle the window's utmp-slot.
+
+ C-a z (suspend) Suspend the whole screen session.
+
+ C-a x (lockscreen) Execute /usr/bin/lock, $LOCKCMD or a
+ built-in terminal lock.
+
+ C-a H (log) Log stdout of window n to screenlog.n.
+
+ C-a C-[ (copy) Start copy mode. Move cursor with h,j,k,l.
+ Set 2 marks with SPACE or y. Abort with ESC.
+ (C-[ is ESC.) Preceeding second mark with
+ an a appends the text to the copy buffer.
+
+ C-a C-] (paste) Output copy buffer to current window's stdin.
+
+ C-a < (readbuf) Read the copy buffer from /tmp/screen-exchange.
+ C-a > (writebuf) Write the copy buffer to /tmp/screen-exchange.
+
+ C-a d (detach) Detach screen. All processes continue and may
+ spool output to their pty's, but screen
+ disconnects from your terminal.
+
+ C-a D D (pow_detach) Power detach. Disconnect like C-a d but also
+ kill the parent shell.
+
+ C-a K (kill) Kill a window and send SIGHUP to its process
+ group. Per default this would be C-a C-k,
+ but it is redefined in the demo .screenrc
+ (think of killing a whole line in emacs).
+
+ C-a : (colon) Online configuration change.
+
+See the man page or TeXinfo manual for many more keybindings and commands.
+
+screen -r [pid.tty.host|tty.host]
+ Reattach to a specific detached session. The terminal emulator
+ reconfigures according to your $TERMCAP or $TERM settings.
+ When you have multiple screens detached, you must supply the session
+ name.
+
+screen -R reattaches to a detached session or (if none) creates a new
+ session.
+
+screen -d [pid.tty.host|tty.host]
+ Detach a screen session remotely. Has the same effect as typing 'C-a d'
+ on the controlling terminal. 'screen -D' will power-detach.
+
+screen -list
+screen -ls
+screen -wipe
+ Show all available sessions and their status. Use -wipe to remove
+ DEAD sessions.
+
+ If sockets are missing, you may send a SIGCHLD to its 'SCREEN'
+ process and the process will re-establish the socket (think of
+ someone cleaning /tmp thoroughly).
+
+screen -h 200
+ Starts a new screen session and sets the number of lines in the scrollback
+ buffer to 200. The default is 100 lines.
+
diff --git a/acls.c b/acls.c
new file mode 100644
index 0000000..f13e13c
--- /dev/null
+++ b/acls.c
@@ -0,0 +1,545 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+#include "rcs.h"
+RCS_ID("$Id: acls.c,v 1.12 1994/05/31 12:31:21 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+
+#include "config.h"
+#include "screen.h" /* includes acls.h */
+#include "extern.h"
+
+
+/************************************************************************
+ * user managing code, this does not really belong into the acl stuff *
+ ************************************************************************/
+
+extern struct comm comms[];
+extern struct win *windows, *wtab[];
+extern struct display *display, *displays;
+struct user *users;
+
+#ifdef MULTIUSER
+/* record given user ids here */
+static AclBits userbits;
+
+/* rights a new unknown user will have on windows and cmds */
+static char default_w_bit[ACL_BITS_PER_WIN] =
+{
+ 1, /* EXEC */
+ 1, /* WRITE */
+ 1 /* READ */
+};
+
+static char default_c_bit[ACL_BITS_PER_CMD] =
+{
+ 1 /* EXEC */
+};
+
+/* rights of all users per newly created window */
+static AclBits default_w_userbits[ACL_BITS_PER_WIN];
+
+/*
+static AclBits default_c_userbits[ACL_BITS_PER_CMD];
+*/
+
+static int maxusercount = 0;
+
+static int GrowBitfield __P((AclBits *, int, int, int));
+
+
+
+static int
+GrowBitfield(bfp, len, delta, defaultbit)
+AclBits *bfp;
+int len, delta, defaultbit;
+{
+ AclBits n, o = *bfp;
+ int i;
+
+ if (!(n = (AclBits)calloc(1, (unsigned long)(&ACLBYTE((char *)0, len + delta + 1)))))
+ return -1;
+ for (i = 0; i < (len + delta); i++)
+ {
+ if (((i < len) && (ACLBIT(i) & ACLBYTE(o, i))) ||
+ ((i >= len) && (defaultbit)))
+ ACLBYTE(n, i) |= ACLBIT(i);
+ }
+ if (len)
+ free((char *)o);
+ *bfp = n;
+ return 0;
+}
+
+#endif /* MULTIUSER */
+
+/*
+ * Returns an nonzero Address. Its contents is either a User-ptr,
+ * or NULL which may be replaced by a User-ptr to create the entry.
+ */
+struct user **
+FindUserPtr(name)
+char *name;
+{
+ struct user **u;
+
+ for (u = &users; *u; u = &(*u)->u_next)
+ if (!strcmp((*u)->u_name, name))
+ break;
+#ifdef MULTIUSER
+ debug3("FindUserPtr %s %sfound, id %d\n", name, (*u)?"":"not ",
+ (*u)?(*u)->id:-1);
+#else
+ debug2("FindUserPtr %s %sfound\n", name, (*u)?"":"not ");
+#endif
+ return u;
+}
+
+int DefaultEsc = Ctrl('a');
+int DefaultMetaEsc = 'a';
+
+/*
+ * Add a new user. His password may be NULL or "" if none.
+ * He has no rights.
+ */
+int
+UserAdd(name, pass, up)
+char *name, *pass;
+struct user **up;
+{
+ if (!up)
+ up = FindUserPtr(name);
+ if (*up)
+ return 1; /* he is already there */
+ *up = (struct user *)calloc(1, sizeof(struct user));
+ if (!*up)
+ return -1; /* he still does not exist */
+#ifdef COPY_PASTE
+ (*up)->u_copybuffer = NULL;
+ (*up)->u_copylen = 0;
+#endif
+ (*up)->u_Esc = DefaultEsc;
+ (*up)->u_MetaEsc = DefaultMetaEsc;
+ strncpy((*up)->u_name, name, 20);
+ if (pass)
+ strncpy((*up)->u_password, pass, 20);
+
+#ifdef MULTIUSER
+ /* now find an unused index */
+ for ((*up)->id = 0; (*up)->id < maxusercount; (*up)->id++)
+ if (!(ACLBIT((*up)->id) & ACLBYTE(userbits, (*up)->id)))
+ break;
+ debug2("UserAdd %s id %d\n", name, (*up)->id);
+ if ((*up)->id == maxusercount)
+ {
+ int i, j;
+ struct win *w;
+
+ debug2("growing all bitfields %d += %d\n", maxusercount, USER_CHUNK);
+ /* the bitfields are full, grow a chunk */
+ /* first, the used_uid_indicator: */
+ if (GrowBitfield(&userbits, maxusercount, USER_CHUNK, 0))
+ {
+ free((char *)*up); *up = NULL; return -1;
+ }
+ /* second, default command bits */
+ /* (only if we generate commands dynamically) */
+/*
+ for (j = 0; j < ACL_BITS_PER_CMD; j++)
+ if (GrowBitfield(&default_c_userbits[j], maxusercount, USER_CHUNK,
+ default_c_bit[j]))
+ {
+ free((char *)*up); *up = NULL; return -1;
+ }
+*/
+ /* third, the bits for each commands */
+ for (i = 0; i <= RC_LAST; i++)
+ for (j = 0; j < ACL_BITS_PER_CMD; j++)
+ if (GrowBitfield(&comms[i].userbits[j], maxusercount, USER_CHUNK,
+ default_c_bit[j]))
+ {
+ free((char *)*up); *up = NULL; return -1;
+ }
+ /* fourth, default window and bits */
+ for (j = 0; j < ACL_BITS_PER_WIN; j++)
+ if (GrowBitfield(&default_w_userbits[j], maxusercount, USER_CHUNK,
+ default_w_bit[j]))
+ {
+ free((char *)*up); *up = NULL; return -1;
+ }
+ /* fifth, the bits for each window */
+ for (w = windows; w; w = w->w_next)
+ for (j = 0; j < ACL_BITS_PER_WIN; j++)
+ if (GrowBitfield(&w->w_userbits[j], maxusercount, USER_CHUNK,
+ default_w_bit[j]))
+ {
+ free((char *)*up); *up = NULL; return -1;
+ }
+ maxusercount += USER_CHUNK;
+ }
+ ACLBYTE(userbits, (*up)->id) |= ACLBIT((*up)->id);
+ /* user id 0 is the session creator, he has all rights */
+ if ((*up)->id == 0)
+ AclSetPerm(*up, "+rwx", "#?");
+#else /* MULTIUSER */
+ debug1("UserAdd %s\n", name);
+#endif /* MULTIUSER */
+ return 0;
+}
+
+/* change user's password */
+int
+UserSetPass(name, pass, up)
+char *name, *pass;
+struct user **up;
+{
+ if (!up)
+ up = FindUserPtr(name);
+ if (!*up)
+ return UserAdd(name, pass, up);
+ strncpy((*up)->u_password, pass ? pass : "", 20);
+ (*up)->u_password[20] = '\0';
+ return 0;
+}
+
+/*
+ * Remove a user from the list.
+ * Destroy all his permissions and completely detach him from the session.
+ */
+int
+UserDel(name, up)
+char *name;
+struct user **up;
+{
+ struct user *u;
+ struct display *old, *next;
+
+ if (!up)
+ up = FindUserPtr(name);
+ if ((u = *up) == 0)
+ return -1; /* he who does not exist cannot be removed */
+ old = display;
+ for (display = displays; display; display = next)
+ {
+ next = display->d_next;
+ if (D_user != u)
+ continue;
+ if (display == old)
+ old = 0;
+ Detach(D_REMOTE);
+ }
+ display = old;
+ *up = u->u_next;
+#ifdef MULTIUSER
+ ACLBYTE(userbits, u->id) &= ~ACLBIT(u->id);
+ /* restore the bits in his slot to default: */
+ AclSetPerm(u, default_w_bit[ACL_READ] ? "+r" : "-r", "#");
+ AclSetPerm(u, default_w_bit[ACL_WRITE]? "+w" : "-w", "#");
+ AclSetPerm(u, default_w_bit[ACL_EXEC] ? "+x" : "-x", "#");
+ AclSetPerm(u, default_c_bit[ACL_EXEC] ? "+x" : "-x", "?");
+#endif
+ debug1("FREEING user structure for %s\n", u->u_name);
+#ifdef COPY_PASTE
+ UserFreeCopyBuffer(u);
+#endif
+ free((char *)u);
+ return 0;
+}
+
+
+#ifdef COPY_PASTE
+
+/*
+ * returns 0 if the copy buffer was really deleted.
+ * Also removes any references into the users copybuffer
+ */
+int
+UserFreeCopyBuffer(u)
+struct user *u;
+{
+ struct win *w;
+
+ if (!u->u_copybuffer)
+ return 1;
+ for (w = windows; w; w = w->w_next)
+ {
+ if (w->w_pasteptr >= u->u_copybuffer &&
+ w->w_pasteptr - u->u_copybuffer < u->u_copylen)
+ {
+ if (w->w_pastebuf)
+ free(w->w_pastebuf);
+ w->w_pastebuf = 0;
+ w->w_pasteptr = 0;
+ w->w_pastelen = 0;
+ }
+ }
+ free(u->u_copybuffer);
+ D_user->u_copylen = 0;
+ u->u_copybuffer = NULL;
+ return 0;
+}
+
+#endif /* COPY_PASTE */
+
+/************************************************************************
+ * end of user managing code *
+ ************************************************************************/
+
+
+#ifdef MULTIUSER
+
+extern char *multi; /* username */
+
+/* This gives the users default rights to the new window */
+int
+NewWindowAcl(w)
+struct win *w;
+{
+ int i, j;
+
+ debug1("NewWindowAcl default_w_userbits for window %d\n", w->w_number);
+ for (j = 0; j < ACL_BITS_PER_WIN; j++)
+ {
+ /* we start with len 0 for the new bitfield size and add maxusercount */
+ if (GrowBitfield(&w->w_userbits[j], 0, maxusercount, 0))
+ {
+ while (--j >= 0)
+ free((char *)w->w_userbits[j]);
+ return -1;
+ }
+ for (i = 0; i < maxusercount; i++)
+ if (ACLBIT(i) & ACLBYTE(default_w_userbits[j], i))
+ ACLBYTE(w->w_userbits[j], i) |= ACLBIT(i);
+ }
+ return 0;
+}
+
+/* if mode starts with '-' we remove the users exec bit for cmd */
+int
+AclSetPermCmd(u, mode, cmd)
+struct user *u;
+char *mode;
+struct comm *cmd;
+{
+ int neg = 0;
+
+ if (!multi)
+ return 0;
+ debug3("AclSetPermCmd %s %s %s\n", u->u_name, mode, cmd->name);
+ while (*mode)
+ {
+ switch (*mode++)
+ {
+ case '-':
+ neg = 1;
+ continue;
+ case '+':
+ neg = 0;
+ continue;
+ case 'e':
+ case 'x':
+ if (neg)
+ ACLBYTE(cmd->userbits[ACL_EXEC], u->id) &= ~ACLBIT(u->id);
+ else
+ ACLBYTE(cmd->userbits[ACL_EXEC], u->id) |= ACLBIT(u->id);
+ break;
+ case 'r':
+ case 'w':
+ break;
+ default:
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* mode strings of the form +rwx -w+rx r -wx are parsed and evaluated */
+/*
+ * aclchg nerd -w+w 2
+ * releases a writelock on window 2 held by user nerd.
+ */
+int
+AclSetPermWin(u, mode, win)
+struct user *u;
+char *mode;
+struct win *win;
+{
+ int neg = 0;
+ int bit;
+
+ if (!multi)
+ return 0;
+ debug3("AclSetPermWin %s %s %d\n", u->u_name, mode, win->w_number);
+ while (*mode)
+ {
+ switch (*mode++)
+ {
+ case '-':
+ neg = 1;
+ continue;
+ case '+':
+ neg = 0;
+ continue;
+ case 'r':
+ bit = ACL_READ;
+ break;
+ case 'w':
+ bit = ACL_WRITE;
+ break;
+ case 'x':
+ bit = ACL_EXEC;
+ break;
+ default:
+ return -1;
+ }
+ if (neg)
+ ACLBYTE(win->w_userbits[bit], u->id) &= ~ACLBIT(u->id);
+ else
+ ACLBYTE(win->w_userbits[bit], u->id) |= ACLBIT(u->id);
+ if ((win->w_wlockuser == u) && neg && (bit == ACL_WRITE))
+ {
+ debug2("%s lost writelock on win %d\n", u->u_name, win->w_number);
+ win->w_wlockuser = NULL;
+ if (win->w_wlock == WLOCK_ON)
+ win->w_wlock = WLOCK_AUTO;
+ }
+ }
+ return 0;
+}
+
+/* string is broken down into comand and window names, mode applies */
+int
+AclSetPerm(u, mode, s)
+struct user *u;
+char *mode, *s;
+{
+ struct win *w;
+ int i;
+ char *p, ch;
+
+ while (*s)
+ {
+ switch (*s)
+ {
+ case '*': /* all windows and all commands */
+ return AclSetPerm(u, mode, "#?");
+ case '#': /* all windows */
+ for (w = windows; w; w = w->w_next)
+ AclSetPermWin(u, mode, w);
+ s++;
+ break;
+ case '?': /* all commands */
+ for (i = 0; i <= RC_LAST; i++)
+ AclSetPermCmd(u, mode, &comms[i]);
+ s++;
+ break;
+ default:
+ for (p = s; *p && *p != ' ' && *p != '\t' && *p != ','; p++)
+ ;
+ if ((ch = *p) != 0)
+ *p++ = '\0';
+ if ((i = FindCommnr(s)) != RC_ILLEGAL)
+ AclSetPermCmd(u, mode, &comms[i]);
+ else if (((i = WindowByNoN(s)) >= 0) && wtab[i])
+ AclSetPermWin(u, mode, wtab[i]);
+ else
+ /* checking group name */
+ return -1;
+ if (ch)
+ p[-1] = ch;
+ s = p;
+ }
+ }
+ return 0;
+}
+
+#if 0
+void
+AclWinSwap(a, b)
+int a, b;
+{
+ int a_bit = 0, b_bit = 0;
+ AclGroupList **g;
+ AclBits p;
+
+ debug2("acl lists swapping windows %d and %d\n", a, b);
+
+ for (g = &aclgrouproot; *g; g = &(*g)->next)
+ {
+ p = (*g)->group->winbits;
+ /* see if there was a bit for window a. zap it */
+ if (a >= 0)
+ if ((a_bit = ACLBIT(a) & ACLBYTE(p, a)))
+ ACLBYTE(p, a) &= ~ACLBIT(a);
+ /* see if there was a bit for window b. zap it */
+ if (b >= 0)
+ if ((b_bit = ACLBIT(b) & ACLBYTE(p, b)))
+ ACLBYTE(p, b) &= ~ACLBIT(b);
+ /* b may cause a set */
+ if (b_bit && a >= 0)
+ ACLBYTE(p, a) |= ACLBIT(a);
+ /* a may cause b set */
+ if (a_bit && b >= 0)
+ ACLBYTE(p, b) |= ACLBIT(b);
+ }
+}
+#else
+void
+AclWinSwap(a, b)
+int a, b;
+{
+ debug2("AclWinSwap(%d, %d) DUMMY\n", a, b);
+}
+#endif
+
+int
+AclCheckPermWin(u, mode, w)
+struct user *u;
+int mode;
+struct win *w;
+{
+ if (!multi)
+ return 0;
+ if (mode < 0 || mode >= ACL_BITS_PER_WIN)
+ return -1;
+ debug3("AclCheckPermWin(%s, %d, %d) = ", u->u_name, mode, w->w_number);
+ debug1("%d\n", !(ACLBYTE(w->w_userbits[mode], u->id) & ACLBIT(u->id)));
+ return !(ACLBYTE(w->w_userbits[mode], u->id) & ACLBIT(u->id));
+}
+
+int
+AclCheckPermCmd(u, mode, c)
+struct user *u;
+int mode;
+struct comm *c;
+{
+ if (!multi)
+ return 0;
+ if (mode < 0 || mode >= ACL_BITS_PER_CMD)
+ return -1;
+ debug3("AclCheckPermCmd(%s %d %s) = ", u->u_name, mode, c->name);
+ debug1("%d\n", !(ACLBYTE(c->userbits[mode], u->id) & ACLBIT(u->id)));
+ return !(ACLBYTE(c->userbits[mode], u->id) & ACLBIT(u->id));
+}
+
+#endif /* MULTIUSER */
diff --git a/acls.h b/acls.h
new file mode 100644
index 0000000..3cbd583
--- /dev/null
+++ b/acls.h
@@ -0,0 +1,89 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ * RCS_ID("$Id: acl.h,v 1.7 1993/07/30 01:24:06 jnweiger Exp $ FAU")
+ */
+
+#ifdef MULTIUSER
+
+/* three known bits: */
+#define ACL_EXEC 0
+#define ACL_WRITE 1
+#define ACL_READ 2
+
+#define ACL_BITS_PER_CMD 1 /* for comm.h */
+#define ACL_BITS_PER_WIN 3 /* for window.h */
+
+#define USER_CHUNK 8
+
+#define ACLBYTE(data, w) ((data)[(w) >> 3])
+#define ACLBIT(w) (0x80 >> ((w) & 7))
+
+typedef unsigned char * AclBits;
+
+/* a bitfield for windows and one for commands */
+typedef struct
+{
+ char name[20 + 1];
+ AclBits wins, cmds;
+} AclGroup;
+
+/*
+ * An AclGroupList is a chaind list of pointers to AclGroups.
+ * Each user has such a list to reference groups he is in.
+ * The aclgrouproot anchors all AclGroups. Delete and create
+ * groups there.
+ */
+typedef struct grouplist
+{
+ AclGroup *group;
+ struct grouplist *next;
+} AclGroupList;
+
+#endif
+
+/***************
+ * ==> user.h
+ */
+
+/*
+ * A User has a list of groups, and points to other users.
+ * users is the User entry of the session owner (creator)
+ * and anchors all other users. Add/Delete users there.
+ */
+typedef struct user
+{
+ struct user *u_next;
+ char u_name[20+1]; /* login name how he showed up */
+ char u_password[20+1]; /* his password (may be zero length). */
+ int u_detachwin; /* the window where he last detached */
+ int u_Esc, u_MetaEsc; /* the users screen escape character */
+#ifdef COPY_PASTE
+ char *u_copybuffer;
+ int u_copylen;
+#endif
+#ifdef MULTIUSER
+ int id; /* a uniq index in the bitfields. */
+#endif
+} User;
+
+extern int DefaultEsc, DefaultMetaEsc;
+
diff --git a/ansi.c b/ansi.c
new file mode 100644
index 0000000..3edbc81
--- /dev/null
+++ b/ansi.c
@@ -0,0 +1,2511 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: ansi.c,v 1.22 1994/05/31 12:31:25 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+#include <signal.h>
+#include <fcntl.h>
+#ifndef sun /* we want to know about TIOCPKT. */
+# include <sys/ioctl.h>
+#endif
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+
+extern struct win *windows; /* linked list of all windows */
+extern struct win *fore;
+extern struct display *display, *displays;
+
+extern int force_vt;
+extern int all_norefresh; /* => display */
+extern int ZombieKey_destroy, ZombieKey_resurrect;
+extern int real_uid, real_gid;
+extern time_t Now;
+extern struct NewWindow nwin_default; /* for ResetWindow() */
+extern int nversion;
+
+int Z0width, Z1width; /* widths for Z0/Z1 switching */
+
+static struct win *curr; /* window we are working on */
+static int rows, cols; /* window size of the curr window */
+
+int visual_bell = 0;
+int use_hardstatus = 1;
+char *printcmd = 0;
+
+char *blank; /* line filled with spaces */
+char *null; /* line filled with '\0' */
+
+struct mline mline_old;
+struct mline mline_blank;
+struct mline mline_null;
+
+struct mchar mchar_null;
+struct mchar mchar_blank = {' ' /* , 0, 0, ... */};
+struct mchar mchar_so = {' ', A_SO /* , 0, 0, ... */};
+
+static void WinProcess __P((char **, int *));
+static void WinRedisplayLine __P((int, int, int, int));
+static void WinClearLine __P((int, int, int));
+static int WinRewrite __P((int, int, int, int));
+static void WinSetCursor __P((void));
+static int WinResize __P((int, int));
+static void WinRestore __P((void));
+static int Special __P((int));
+static void DoESC __P((int, int));
+static void DoCSI __P((int, int));
+static void SetChar __P((int));
+static void StartString __P((enum string_t));
+static void SaveChar __P((int));
+static void PrintStart __P((void));
+static void PrintChar __P((int));
+static void PrintFlush __P((void));
+static void DesignateCharset __P((int, int));
+static void MapCharset __P((int));
+static void MapCharsetR __P((int));
+static void SaveCursor __P((void));
+static void RestoreCursor __P((void));
+static void BackSpace __P((void));
+static void Return __P((void));
+static void LineFeed __P((int));
+static void ReverseLineFeed __P((void));
+static void InsertAChar __P((int));
+static void InsertChar __P((int));
+static void DeleteChar __P((int));
+static void DeleteLine __P((int));
+static void InsertLine __P((int));
+static void ScrollUpMap __P((int));
+static void ScrollDownMap __P((int));
+static void Scroll __P((char *, int, int, char *));
+static void ForwardTab __P((void));
+static void BackwardTab __P((void));
+static void ClearScreen __P((void));
+static void ClearFromBOS __P((void));
+static void ClearToEOS __P((void));
+static void ClearFullLine __P((void));
+static void ClearToEOL __P((void));
+static void ClearFromBOL __P((void));
+static void ClearInLine __P((int, int, int));
+static void CursorRight __P((int));
+static void CursorUp __P((int));
+static void CursorDown __P((int));
+static void CursorLeft __P((int));
+static void ASetMode __P((int));
+static void SelectRendition __P((void));
+static void RestorePosRendition __P((void));
+static void FillWithEs __P((void));
+static void UpdateLine __P((struct mline *, int, int, int ));
+static void FindAKA __P((void));
+static void Report __P((char *, int, int));
+static void FixLine __P((void));
+static void ScrollRegion __P((int));
+static void CheckLP __P((int));
+#ifdef COPY_PASTE
+static void AddLineToHist __P((struct win *, struct mline *));
+#endif
+
+
+/*
+ * The window layer functions
+ */
+
+struct LayFuncs WinLf =
+{
+ WinProcess,
+ 0,
+ WinRedisplayLine,
+ WinClearLine,
+ WinRewrite,
+ WinSetCursor,
+ WinResize,
+ WinRestore
+};
+
+static void
+WinProcess(bufpp, lenp)
+char **bufpp;
+int *lenp;
+{
+ int addlf, l2 = 0, f, *ilen, l = *lenp;
+ char *ibuf, *p, *buf = *bufpp;
+
+ fore = D_fore;
+ /* if w_wlock is set, only one user may write, else we check acls */
+ if (fore->w_ptyfd < 0)
+ {
+ while ((*lenp)-- > 0)
+ {
+ f = *(*bufpp)++;
+ if (f == ZombieKey_destroy)
+ {
+ debug2("Turning undead: %d(%s)\n", fore->w_number, fore->w_title);
+ KillWindow(fore);
+ l2--;
+ break;
+ }
+ if (f == ZombieKey_resurrect)
+ {
+ SetCurr(fore);
+
+ debug1("Resurrecting Zombie: %d\n", fore->w_number);
+ LineFeed(2);
+ RemakeWindow(fore);
+ l2++;
+ break;
+ }
+ }
+ if (!l2)
+ {
+ char b1[10], b2[10];
+
+ b1[AddXChar(b1, ZombieKey_destroy)] = '\0';
+ b2[AddXChar(b2, ZombieKey_resurrect)] = '\0';
+ Msg(0, "Press %s to destroy or %s to resurrect window", b1, b2);
+ }
+ *bufpp += *lenp;
+ *lenp = 0;
+ return;
+ }
+#ifdef MULTIUSER
+ if ((fore->w_wlock == WLOCK_OFF) ?
+ AclCheckPermWin(D_user, ACL_WRITE, fore) :
+ (D_user != fore->w_wlockuser))
+ {
+ SetCurr(fore);
+ Special('\007');
+ *bufpp += *lenp;
+ *lenp = 0;
+ return;
+ }
+#endif /* MULTIUSER */
+#ifdef PSEUDOS
+ if (W_UWP(fore))
+ {
+ /* we send the user input to our pseudowin */
+ ibuf = fore->w_pwin->p_inbuf; ilen = &fore->w_pwin->p_inlen;
+ f = sizeof(fore->w_pwin->p_inbuf) - *ilen;
+ }
+ else
+#endif /* PSEUDOS */
+ {
+ /* we send the user input to the window */
+ ibuf = fore->w_inbuf; ilen = &fore->w_inlen;
+ f = sizeof(fore->w_inbuf) - *ilen;
+ }
+
+ buf = *bufpp;
+
+ while (l)
+ {
+ l2 = l;
+ addlf = 0;
+ if (fore->w_autolf)
+ {
+ for (p = buf; l2; p++, l2--)
+ if (*p == '\r')
+ {
+ l2--;
+ addlf = 1;
+ break;
+ }
+ l2 = l - l2;
+ }
+ if (l2 + addlf > f)
+ {
+ debug1("Yuck! pty buffer full (%d chars missing). lets beep\n", l - f);
+ SetCurr(fore);
+ Special('\007');
+ l = l2 = f;
+ addlf = 0;
+ }
+ if (l2 > 0)
+ {
+ bcopy(buf, ibuf + *ilen, l2);
+ *ilen += l2;
+ f -= l2;
+ buf += l2;
+ l -= l2;
+ if (f && addlf)
+ {
+ ibuf[(*ilen)++] = '\n';
+ f--;
+ }
+ }
+ }
+ *bufpp += *lenp;
+ *lenp = 0;
+}
+
+static void
+WinRedisplayLine(y, from, to, isblank)
+int y, from, to, isblank;
+{
+ if (y < 0)
+ return;
+ fore = D_fore;
+ DisplayLine(isblank ? &mline_blank : &mline_null, &fore->w_mlines[y],
+ y, from, to);
+}
+
+static int
+WinRewrite(y, x1, x2, doit)
+int y, x1, x2, doit;
+{
+ register int cost, dx;
+ register char *p, *f, *i;
+#ifdef COLOR
+ register char *c;
+#endif
+
+ fore = D_fore;
+ dx = x2 - x1;
+ if (doit)
+ {
+ i = fore->w_mlines[y].image + x1;
+ while (dx-- > 0)
+ PUTCHAR(*i++);
+ return 0;
+ }
+ p = fore->w_mlines[y].attr + x1;
+ f = fore->w_mlines[y].font + x1;
+#ifdef COLOR
+ c = fore->w_mlines[y].color + x1;
+#endif
+
+ cost = dx = x2 - x1;
+ if (D_insert)
+ cost += D_EIcost + D_IMcost;
+ while(dx-- > 0)
+ {
+#ifdef COLOR
+ if (*p++ != D_rend.attr || *f++ != D_rend.font || *c++ != D_rend.color)
+ return EXPENSIVE;
+#else
+ if (*p++ != D_rend.attr || *f++ != D_rend.font)
+ return EXPENSIVE;
+#endif
+ }
+ return cost;
+}
+
+static void
+WinClearLine(y, xs, xe)
+int y, xs, xe;
+{
+ fore = D_fore;
+ DisplayLine(&fore->w_mlines[y], &mline_blank, y, xs, xe);
+}
+
+static void
+WinSetCursor()
+{
+ fore = D_fore;
+ GotoPos(fore->w_x, fore->w_y);
+}
+
+static int
+WinResize(wi, he)
+int wi, he;
+{
+ fore = D_fore;
+ if (fore)
+ ChangeWindowSize(fore, wi, he, fore->w_histheight);
+ return 0;
+}
+
+static void
+WinRestore()
+{
+ fore = D_fore;
+ ChangeScrollRegion(fore->w_top, fore->w_bot);
+ KeypadMode(fore->w_keypad);
+ CursorkeysMode(fore->w_cursorkeys);
+ SetFlow(fore->w_flow & FLOW_NOW);
+ InsertMode(fore->w_insert);
+ ReverseVideo(fore->w_revvid);
+ CursorVisibility(fore->w_curinv ? -1 : fore->w_curvvis);
+ fore->w_active = 1;
+}
+
+/*
+ * Activate - make fore window active
+ * norefresh = -1 forces a refresh, disregard all_norefresh then.
+ */
+void
+Activate(norefresh)
+int norefresh;
+{
+ debug1("Activate(%d)\n", norefresh);
+ if (display == 0)
+ return;
+ if (D_status)
+ {
+ Msg(0, "%s", ""); /* wait till mintime (keep gcc quiet) */
+ RemoveStatus();
+ }
+ fore = D_fore;
+ if (fore)
+ {
+ ASSERT(fore->w_display == display);
+ fore->w_active = D_layfn == &WinLf;
+ if (fore->w_monitor != MON_OFF)
+ fore->w_monitor = MON_ON;
+ fore->w_bell = BELL_OFF;
+ if (ResizeDisplay(fore->w_width, fore->w_height))
+ {
+ debug2("Cannot resize from (%d,%d)", D_width, D_height);
+ debug2(" to (%d,%d) -> resize window\n", fore->w_width, fore->w_height);
+ DoResize(D_width, D_height);
+ }
+ }
+ Redisplay(norefresh + all_norefresh);
+}
+
+void
+ResetWindow(p)
+register struct win *p;
+{
+ register int i;
+
+ p->w_wrap = nwin_default.wrap;
+ p->w_origin = 0;
+ p->w_insert = 0;
+ p->w_revvid = 0;
+ p->w_curinv = 0;
+ p->w_curvvis = 0;
+ p->w_autolf = 0;
+ p->w_keypad = 0;
+ p->w_cursorkeys = 0;
+ p->w_top = 0;
+ p->w_bot = p->w_height - 1;
+ p->w_saved = 0;
+ p->w_x = p->w_y = 0;
+ p->w_state = LIT;
+ p->w_StringType = NONE;
+ bzero(p->w_tabs, p->w_width);
+ for (i = 8; i < p->w_width; i += 8)
+ p->w_tabs[i] = 1;
+ p->w_rend = mchar_null;
+ ResetCharsets(p);
+}
+
+#ifdef KANJI
+static char *kanjicharsets[3] = {
+ "BBBB02", /* jis */
+ "\002IBB01", /* euc */
+ "BIBB01" /* sjis */
+};
+#endif
+
+void
+ResetCharsets(p)
+register struct win *p;
+{
+ p->w_gr = nwin_default.gr;
+ p->w_c1 = nwin_default.c1;
+ SetCharsets(p, "BBBB02");
+ if (nwin_default.charset)
+ SetCharsets(p, nwin_default.charset);
+#ifdef KANJI
+ if (p->w_kanji)
+ {
+ p->w_gr = 1;
+ if (p->w_kanji == SJIS)
+ p->w_c1 = 0;
+ SetCharsets(p, kanjicharsets[p->w_kanji]);
+ }
+#endif
+}
+
+void
+SetCharsets(p, s)
+struct win *p;
+char *s;
+{
+ int i;
+
+ for (i = 0; i < 4 && *s; i++, s++)
+ if (*s != '.')
+ p->w_charsets[i] = ((*s == 'B') ? ASCII : *s);
+ if (*s && *s++ != '.')
+ p->w_Charset = s[-1] - '0';
+ if (*s && *s != '.')
+ p->w_CharsetR = *s - '0';
+ p->w_ss = 0;
+ p->w_FontL = p->w_charsets[p->w_Charset];
+ p->w_FontR = p->w_charsets[p->w_CharsetR];
+}
+
+static void
+FixLine()
+{
+ struct mline *ml = &curr->w_mlines[curr->w_y];
+ if (curr->w_rend.attr && ml->attr == null)
+ {
+ if ((ml->attr = (char *)malloc(curr->w_width + 1)) == 0)
+ {
+ ml->attr = null;
+ curr->w_rend.attr = 0;
+ Msg(0, "Warning: no space for attr - turned off");
+ }
+ bzero(ml->attr, curr->w_width + 1);
+ }
+ if ((curr->w_FontL || curr->w_FontR) && ml->font == null)
+ {
+ if ((ml->font = (char *)malloc(curr->w_width + 1)) == 0)
+ {
+ ml->font = null;
+ curr->w_FontL = curr->w_charsets[curr->w_ss ? curr->w_ss : curr->w_Charset] = 0;
+ curr->w_FontR = curr->w_charsets[curr->w_ss ? curr->w_ss : curr->w_CharsetR] = 0;
+ curr->w_rend.font = 0;
+ Msg(0, "Warning: no space for font - turned off");
+ }
+ bzero(ml->font, curr->w_width + 1);
+ }
+#ifdef COLOR
+ if (curr->w_rend.color && ml->color == null)
+ {
+ if ((ml->color = (char *)malloc(curr->w_width + 1)) == 0)
+ {
+ ml->color = null;
+ curr->w_rend.color = 0;
+ Msg(0, "Warning: no space for color - turned off");
+ }
+ bzero(ml->color, curr->w_width + 1);
+ }
+#endif
+}
+
+
+/*
+ * Here comes the vt100 emulator
+ */
+void
+WriteString(wp, buf, len)
+struct win *wp;
+register char *buf;
+register int len;
+{
+ register int c, font;
+
+ if (!len)
+ return;
+ if (wp->w_logfp != NULL)
+ if ((int)fwrite(buf, len, 1, wp->w_logfp) < 1)
+ {
+ Msg(errno, "Error writing logfile");
+ fclose(wp->w_logfp);
+ wp->w_logfp = NULL;
+ }
+ /*
+ * SetCurr() here may prevent output, as it may set display = 0
+ */
+ SetCurr(wp);
+ if (display)
+ {
+ if (D_status && !(use_hardstatus && D_HS))
+ RemoveStatus();
+ }
+ else
+ {
+ if (curr->w_tstamp.seconds)
+ curr->w_tstamp.lastio = Now;
+
+ if (curr->w_monitor == MON_ON || curr->w_monitor == MON_DONE)
+ {
+ debug2("ACTIVITY %d %d\n", curr->w_monitor, curr->w_bell);
+ curr->w_monitor = MON_FOUND;
+ }
+ }
+
+ do
+ {
+ c = (unsigned char)*buf++;
+ curr->w_rend.font = curr->w_FontL; /* Default: GL */
+
+ /* The next part is only for speedup
+ * (therefore no mchars are used) */
+ if (curr->w_state == LIT &&
+#ifdef KANJI
+ curr->w_FontL != KANJI && curr->w_FontL != KANA && !curr->w_mbcs &&
+#endif
+ c >= ' ' &&
+ ((c & 0x80) == 0 || ((c >= 0xa0 || !curr->w_c1) && !curr->w_gr)) &&
+ !curr->w_insert && !curr->w_ss && curr->w_x < cols - 1)
+ {
+ register int currx;
+ register char *imp, *atp, *fop, at, fo;
+#ifdef COLOR
+ register char *cop, co;
+#endif
+ register char **xtable = 0;
+ register char *c0tab = 0;
+
+ if (c == '\177')
+ continue;
+ FixLine();
+ currx = curr->w_x;
+ imp = curr->w_mlines[curr->w_y].image + currx;
+ atp = curr->w_mlines[curr->w_y].attr + currx;
+ fop = curr->w_mlines[curr->w_y].font + currx;
+ at = curr->w_rend.attr;
+ fo = curr->w_rend.font;
+#ifdef COLOR
+ cop = curr->w_mlines[curr->w_y].color + currx;
+ co = curr->w_rend.color;
+#endif
+ if (display)
+ {
+ if (D_x != currx || D_y != curr->w_y)
+ GotoPos(currx, curr->w_y);
+ /* This is not SetRendition because the compiler would
+ * not use registers if at/fo/co would be an mchar */
+ if (at != D_rend.attr)
+ SetAttr(at);
+#ifdef COLOR
+ if (co != D_rend.color)
+ SetColor(co);
+#endif
+ if (fo != D_rend.font)
+ SetFont(fo);
+ if (D_insert)
+ InsertMode(0);
+ if (D_xtable)
+ xtable = D_xtable[(int)(unsigned char)D_rend.font];
+ if (D_rend.font == '0')
+ c0tab = D_c0_tab;
+ }
+ while (currx < cols - 1)
+ {
+ if (display)
+ {
+ if (xtable && xtable[c])
+ AddStr(xtable[c]);
+ else if (c0tab)
+ AddChar(c0tab[c]);
+ else
+ AddChar(c);
+ }
+ *imp++ = c;
+ *atp++ = at;
+ *fop++ = fo;
+#ifdef COLOR
+ *cop++ = co;
+#endif
+ currx++;
+skip: if (--len == 0)
+ break;
+ c = (unsigned char)*buf++;
+ if (c == '\177')
+ goto skip;
+ if (c < ' ' || ((c & 0x80) && ((c < 0xa0 && curr->w_c1) || curr->w_gr)))
+ break;
+ }
+ curr->w_x = currx;
+ if (display)
+ D_x = currx;
+ if (len == 0)
+ break;
+ }
+ /* end of speedup code */
+
+ tryagain:
+ switch (curr->w_state)
+ {
+ case PRIN:
+ switch (c)
+ {
+ case '\033':
+ curr->w_state = PRINESC;
+ break;
+ default:
+ PrintChar(c);
+ }
+ break;
+ case PRINESC:
+ switch (c)
+ {
+ case '[':
+ curr->w_state = PRINCSI;
+ break;
+ default:
+ PrintChar('\033');
+ PrintChar(c);
+ curr->w_state = PRIN;
+ }
+ break;
+ case PRINCSI:
+ switch (c)
+ {
+ case '4':
+ curr->w_state = PRIN4;
+ break;
+ default:
+ PrintChar('\033');
+ PrintChar('[');
+ PrintChar(c);
+ curr->w_state = PRIN;
+ }
+ break;
+ case PRIN4:
+ switch (c)
+ {
+ case 'i':
+ curr->w_state = LIT;
+ PrintFlush();
+ if (curr->w_pdisplay && curr->w_pdisplay->d_printfd >= 0)
+ {
+ close(curr->w_pdisplay->d_printfd);
+ curr->w_pdisplay->d_printfd = -1;
+ }
+ curr->w_pdisplay = 0;
+ break;
+ default:
+ PrintChar('\033');
+ PrintChar('[');
+ PrintChar('4');
+ PrintChar(c);
+ curr->w_state = PRIN;
+ }
+ break;
+ case ASTR:
+ if (c == 0)
+ break;
+ if (c == '\033')
+ {
+ curr->w_state = STRESC;
+ break;
+ }
+ /* special xterm hack: accept SetStatus sequence. Yucc! */
+ if (!(curr->w_StringType == OSC && c < ' ' && c != '\005'))
+ if (!curr->w_c1 || c != ('\\' ^ 0xc0))
+ {
+ SaveChar(c);
+ break;
+ }
+ c = '\\';
+ /* FALLTHROUGH */
+ case STRESC:
+ switch (c)
+ {
+ case '\\':
+ curr->w_state = LIT;
+ *curr->w_stringp = '\0';
+ switch (curr->w_StringType)
+ {
+ case OSC: /* special xterm compatibility hack */
+ if (curr->w_stringp - curr->w_string < 2 ||
+ curr->w_string[0] < '0' ||
+ curr->w_string[0] > '2' ||
+ curr->w_string[1] != ';')
+ break;
+ curr->w_stringp -= 2;
+ if (curr->w_stringp > curr->w_string)
+ bcopy(curr->w_string + 2, curr->w_string, curr->w_stringp - curr->w_string);
+ *curr->w_stringp = '\0';
+ /* FALLTHROUGH */
+ case APC:
+ if (curr->w_hstatus)
+ {
+ if (strcmp(curr->w_hstatus, curr->w_string) == 0)
+ break; /* not changed */
+ free(curr->w_hstatus);
+ curr->w_hstatus = 0;
+ }
+ if (curr->w_string != curr->w_stringp)
+ curr->w_hstatus = SaveStr(curr->w_string);
+ if (display)
+ RefreshStatus();
+ break;
+ case GM:
+ {
+ struct display *old = display;
+ for (display = displays; display; display = display->d_next)
+ if (display != old)
+ MakeStatus(curr->w_string);
+ display = old;
+ }
+ /*FALLTHROUGH*/
+ case PM:
+ if (!display)
+ break;
+ MakeStatus(curr->w_string);
+ if (D_status && !(use_hardstatus && D_HS) && len > 1)
+ {
+ curr->w_outlen = len - 1;
+ bcopy(buf, curr->w_outbuf, curr->w_outlen);
+ return;
+ }
+ break;
+ case DCS:
+ if (display)
+ AddStr(curr->w_string);
+ break;
+ case AKA:
+ if (curr->w_title == curr->w_akabuf && !*curr->w_string)
+ break;
+ ChangeAKA(curr, curr->w_string, 20);
+ if (!*curr->w_string)
+ curr->w_autoaka = curr->w_y + 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case '\033':
+ SaveChar('\033');
+ break;
+ default:
+ curr->w_state = ASTR;
+ SaveChar('\033');
+ SaveChar(c);
+ break;
+ }
+ break;
+ case ESC:
+ switch (c)
+ {
+ case '[':
+ curr->w_NumArgs = 0;
+ curr->w_intermediate = 0;
+ bzero((char *) curr->w_args, MAXARGS * sizeof(int));
+ curr->w_state = CSI;
+ break;
+ case ']':
+ StartString(OSC);
+ break;
+ case '_':
+ StartString(APC);
+ break;
+ case 'P':
+ StartString(DCS);
+ break;
+ case '^':
+ StartString(PM);
+ break;
+ case '!':
+ StartString(GM);
+ break;
+ case '"':
+ case 'k':
+ StartString(AKA);
+ break;
+ default:
+ if (Special(c))
+ {
+ curr->w_state = LIT;
+ break;
+ }
+ debug1("not special. c = %x\n", c);
+ if (c >= ' ' && c <= '/')
+ {
+ if (curr->w_intermediate)
+#ifdef KANJI
+ if (curr->w_intermediate == '$')
+ c |= '$' << 8;
+ else
+#endif
+ c = -1;
+ curr->w_intermediate = c;
+ }
+ else if (c >= '0' && c <= '~')
+ {
+ DoESC(c, curr->w_intermediate);
+ curr->w_state = LIT;
+ }
+ else
+ {
+ curr->w_state = LIT;
+ goto tryagain;
+ }
+ }
+ break;
+ case CSI:
+ switch (c)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (curr->w_NumArgs < MAXARGS)
+ {
+ curr->w_args[curr->w_NumArgs] =
+ 10 * curr->w_args[curr->w_NumArgs] + (c - '0');
+ }
+ break;
+ case ';':
+ case ':':
+ curr->w_NumArgs++;
+ break;
+ default:
+ if (Special(c))
+ break;
+ if (c >= '@' && c <= '~')
+ {
+ curr->w_NumArgs++;
+ DoCSI(c, curr->w_intermediate);
+ if (curr->w_state != PRIN)
+ curr->w_state = LIT;
+ }
+ else if ((c >= ' ' && c <= '/') || (c >= '<' && c <= '?'))
+ curr->w_intermediate = curr->w_intermediate ? -1 : c;
+ else
+ {
+ curr->w_state = LIT;
+ goto tryagain;
+ }
+ }
+ break;
+ case LIT:
+ default:
+ if (c < ' ')
+ {
+ if (c == '\033')
+ {
+ curr->w_intermediate = 0;
+ curr->w_state = ESC;
+ if (display && D_lp_missing && (D_CIC || D_IC || D_IM))
+ UpdateLine(&mline_blank, D_bot, cols - 2, cols - 1);
+ if (curr->w_autoaka < 0)
+ curr->w_autoaka = 0;
+ }
+ else
+ Special(c);
+ break;
+ }
+ if (c >= 0x80 && c < 0xa0 && curr->w_c1)
+ {
+ switch (c)
+ {
+ case 0xc0 ^ 'D':
+ case 0xc0 ^ 'E':
+ case 0xc0 ^ 'H':
+ case 0xc0 ^ 'M':
+ case 0xc0 ^ 'N':
+ case 0xc0 ^ 'O':
+ DoESC(c ^ 0xc0, 0);
+ break;
+ case 0xc0 ^ '[':
+ if (display && D_lp_missing && (D_CIC || D_IC || D_IM))
+ UpdateLine(&mline_blank, D_bot, cols - 2, cols - 1);
+ if (curr->w_autoaka < 0)
+ curr->w_autoaka = 0;
+ curr->w_NumArgs = 0;
+ curr->w_intermediate = 0;
+ bzero((char *) curr->w_args, MAXARGS * sizeof(int));
+ curr->w_state = CSI;
+ break;
+ case 0xc0 ^ 'P':
+ StartString(DCS);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ font = curr->w_rend.font = (c >= 0x80 ? curr->w_FontR : curr->w_FontL);
+#ifdef KANJI
+ if (font == KANA && curr->w_kanji == SJIS && curr->w_mbcs == 0)
+ {
+ /* Lets see if it is the first byte of a kanji */
+ debug1("%x may be first of SJIS\n", c);
+ if ((0x81 <= c && c <= 0x9f) || (0xe0 <= c && c <= 0xef))
+ {
+ debug("YES!\n");
+ curr->w_mbcs = c;
+ break;
+ }
+ }
+ if (font == KANJI || curr->w_mbcs)
+ {
+ int t = c;
+ if (curr->w_mbcs == 0)
+ {
+ curr->w_mbcs = c;
+ break;
+ }
+ if (curr->w_x == cols - 1)
+ {
+ curr->w_x += curr->w_wrap ? 1 : -1;
+ debug1("Patched w_x to %d\n", curr->w_x);
+ }
+ c = curr->w_mbcs;
+ if (font != KANJI)
+ {
+ debug2("SJIS !! %x %x\n", c, t);
+ if (0x40 <= t && t <= 0xfc && t != 0x7f)
+ {
+ if (c <= 0x9f) c = (c - 0x81) * 2 + 0x21;
+ else c = (c - 0xc1) * 2 + 0x21;
+ if (t <= 0x7e) t -= 0x1f;
+ else if (t <= 0x9e) t -= 0x20;
+ else t -= 0x7e, c++;
+ curr->w_rend.font = KANJI;
+ }
+ else
+ {
+ /* Incomplete shift-jis - skip first byte */
+ c = t;
+ t = 0;
+ }
+ debug2("SJIS after %x %x\n", c, t);
+ }
+ curr->w_mbcs = t;
+ }
+ kanjiloop:
+#endif
+ if (curr->w_gr)
+ {
+ c &= 0x7f;
+ if (c < ' ') /* this is ugly but kanji support */
+ goto tryagain; /* prevents nicer programming */
+ }
+ if (c == '\177')
+ break;
+ if (display)
+ SetRendition(&curr->w_rend);
+ if (curr->w_x < cols - 1)
+ {
+ if (curr->w_insert)
+ InsertAChar(c);
+ else
+ {
+ if (display)
+ PUTCHAR(c);
+ SetChar(c);
+ curr->w_x++;
+ }
+ }
+ else if (curr->w_x == cols - 1)
+ {
+ if (display && curr->w_wrap && (D_CLP || !force_vt || D_COP))
+ {
+ RAW_PUTCHAR(c); /* don't care about D_insert */
+ SetChar(c);
+ curr->w_x++;
+ if (D_AM && !D_CLP)
+ {
+ SetChar(0);
+ LineFeed(0); /* terminal auto-wrapped */
+ }
+ }
+ else
+ {
+ if (display)
+ {
+ if (D_CLP || curr->w_y != D_bot)
+ {
+ RAW_PUTCHAR(c);
+ GotoPos(curr->w_x, curr->w_y);
+ }
+ else
+ CheckLP(c);
+ }
+ SetChar(c);
+ if (curr->w_wrap)
+ curr->w_x++;
+ }
+ }
+ else /* curr->w_x > cols - 1 */
+ {
+ SetChar(0); /* we wrapped */
+ if (curr->w_insert)
+ {
+ LineFeed(2); /* cr+lf, handle LP */
+ InsertAChar(c);
+ }
+ else
+ {
+ if (display && D_AM && D_x != cols) /* write char again */
+ {
+ SetRenditionMline(&curr->w_mlines[curr->w_y], cols - 1);
+ RAW_PUTCHAR(curr->w_mlines[curr->w_y].image[cols - 1]);
+ SetRendition(&curr->w_rend);
+ if (curr->w_y == D_bot)
+ D_lp_missing = 0; /* just wrote it */
+ }
+ LineFeed((display == 0 || D_AM) ? 0 : 2);
+ if (display)
+ PUTCHAR(c);
+ SetChar(c);
+ curr->w_x = 1;
+ }
+ }
+#ifdef KANJI
+ if (curr->w_mbcs)
+ {
+ c = curr->w_mbcs;
+ curr->w_mbcs = 0;
+ goto kanjiloop; /* what a hack! */
+ }
+#endif
+ if (curr->w_ss)
+ {
+ curr->w_FontL = curr->w_charsets[curr->w_Charset];
+ curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
+ SetFont(curr->w_FontL);
+ curr->w_ss = 0;
+ }
+ break;
+ }
+ }
+ while (--len);
+ curr->w_outlen = 0;
+ if (curr->w_state == PRIN)
+ PrintFlush();
+}
+
+static int
+Special(c)
+register int c;
+{
+ switch (c)
+ {
+ case '\b':
+ BackSpace();
+ return 1;
+ case '\r':
+ Return();
+ return 1;
+ case '\n':
+ if (curr->w_autoaka)
+ FindAKA();
+ LineFeed(1);
+ return 1;
+ case '\007':
+ if (display == 0)
+ curr->w_bell = BELL_ON;
+ else
+ {
+ if (!visual_bell)
+ PutStr(D_BL);
+ else
+ {
+ if (!D_VB)
+ curr->w_bell = BELL_VISUAL;
+ else
+ PutStr(D_VB);
+ }
+ }
+ return 1;
+ case '\t':
+ ForwardTab();
+ return 1;
+ case '\017': /* SI */
+ MapCharset(G0);
+ return 1;
+ case '\016': /* SO */
+ MapCharset(G1);
+ return 1;
+ }
+ return 0;
+}
+
+static void
+DoESC(c, intermediate)
+int c, intermediate;
+{
+ debug2("DoESC: %x - inter = %x\n", c, intermediate);
+ switch (intermediate)
+ {
+ case 0:
+ switch (c)
+ {
+ case 'E':
+ LineFeed(2);
+ break;
+ case 'D':
+ LineFeed(1);
+ break;
+ case 'M':
+ ReverseLineFeed();
+ break;
+ case 'H':
+ curr->w_tabs[curr->w_x] = 1;
+ break;
+ case 'Z': /* jph: Identify as VT100 */
+ Report("\033[?%d;%dc", 1, 2);
+ break;
+ case '7':
+ SaveCursor();
+ break;
+ case '8':
+ RestoreCursor();
+ break;
+ case 'c':
+ ClearScreen();
+ ResetWindow(curr);
+ SetRendition(&mchar_null);
+ InsertMode(0);
+ KeypadMode(0);
+ CursorkeysMode(0);
+ ChangeScrollRegion(0, rows - 1);
+ break;
+ case '=':
+ KeypadMode(curr->w_keypad = 1);
+#ifndef TIOCPKT
+ NewAutoFlow(curr, 0);
+#endif /* !TIOCPKT */
+ break;
+ case '>':
+ KeypadMode(curr->w_keypad = 0);
+#ifndef TIOCPKT
+ NewAutoFlow(curr, 1);
+#endif /* !TIOCPKT */
+ break;
+ case 'n': /* LS2 */
+ MapCharset(G2);
+ break;
+ case 'o': /* LS3 */
+ MapCharset(G3);
+ break;
+ case '~':
+ MapCharsetR(G1); /* LS1R */
+ break;
+ case '}':
+ MapCharsetR(G2); /* LS2R */
+ break;
+ case '|':
+ MapCharsetR(G3); /* LS3R */
+ break;
+ case 'N': /* SS2 */
+ if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G2]
+ || curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G2])
+ curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G2];
+ else
+ curr->w_ss = 0;
+ break;
+ case 'O': /* SS3 */
+ if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G3]
+ || curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G3])
+ curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G3];
+ else
+ curr->w_ss = 0;
+ break;
+ case 'g': /* VBELL, private screen sequence */
+ if (display == 0)
+ curr->w_bell = BELL_ON;
+ else if (!D_VB)
+ curr->w_bell = BELL_VISUAL;
+ else
+ PutStr(D_VB);
+ break;
+ }
+ break;
+ case '#':
+ switch (c)
+ {
+ case '8':
+ FillWithEs();
+ break;
+ }
+ break;
+ case '(':
+ DesignateCharset(c, G0);
+ break;
+ case ')':
+ DesignateCharset(c, G1);
+ break;
+ case '*':
+ DesignateCharset(c, G2);
+ break;
+ case '+':
+ DesignateCharset(c, G3);
+ break;
+#ifdef KANJI
+/*
+ * ESC $ ( Fn: invoke multi-byte charset, Fn, to G0
+ * ESC $ Fn: same as above. (old sequence)
+ * ESC $ ) Fn: invoke multi-byte charset, Fn, to G1
+ * ESC $ * Fn: invoke multi-byte charset, Fn, to G2
+ * ESC $ + Fn: invoke multi-byte charset, Fn, to G3
+ */
+ case '$':
+ case '$'<<8 | '(':
+ DesignateCharset(c & 037, G0);
+ break;
+ case '$'<<8 | ')':
+ DesignateCharset(c & 037, G1);
+ break;
+ case '$'<<8 | '*':
+ DesignateCharset(c & 037, G2);
+ break;
+ case '$'<<8 | '+':
+ DesignateCharset(c & 037, G3);
+ break;
+#endif
+ }
+}
+
+static void
+DoCSI(c, intermediate)
+int c, intermediate;
+{
+ register int i, a1 = curr->w_args[0], a2 = curr->w_args[1];
+
+ if (curr->w_NumArgs > MAXARGS)
+ curr->w_NumArgs = MAXARGS;
+ switch (intermediate)
+ {
+ case 0:
+ switch (c)
+ {
+ case 'H':
+ case 'f':
+ if (a1 < 1)
+ a1 = 1;
+ if (curr->w_origin)
+ a1 += curr->w_top;
+ if (a1 > rows)
+ a1 = rows;
+ if (a2 < 1)
+ a2 = 1;
+ if (a2 > cols)
+ a2 = cols;
+ GotoPos(--a2, --a1);
+ curr->w_x = a2;
+ curr->w_y = a1;
+ if (curr->w_autoaka)
+ curr->w_autoaka = a1 + 1;
+ break;
+ case 'J':
+ if (a1 < 0 || a1 > 2)
+ a1 = 0;
+ switch (a1)
+ {
+ case 0:
+ ClearToEOS();
+ break;
+ case 1:
+ ClearFromBOS();
+ break;
+ case 2:
+ ClearScreen();
+ GotoPos(curr->w_x, curr->w_y);
+ break;
+ }
+ break;
+ case 'K':
+ if (a1 < 0 || a1 > 2)
+ a1 %= 3;
+ switch (a1)
+ {
+ case 0:
+ ClearToEOL();
+ break;
+ case 1:
+ ClearFromBOL();
+ break;
+ case 2:
+ ClearFullLine();
+ break;
+ }
+ break;
+ case 'A':
+ CursorUp(a1 ? a1 : 1);
+ break;
+ case 'B':
+ CursorDown(a1 ? a1 : 1);
+ break;
+ case 'C':
+ CursorRight(a1 ? a1 : 1);
+ break;
+ case 'D':
+ CursorLeft(a1 ? a1 : 1);
+ break;
+ case 'm':
+ SelectRendition();
+ break;
+ case 'g':
+ if (a1 == 0)
+ curr->w_tabs[curr->w_x] = 0;
+ else if (a1 == 3)
+ bzero(curr->w_tabs, cols);
+ break;
+ case 'r':
+ if (!a1)
+ a1 = 1;
+ if (!a2)
+ a2 = rows;
+ if (a1 < 1 || a2 > rows || a1 >= a2)
+ break;
+ curr->w_top = a1 - 1;
+ curr->w_bot = a2 - 1;
+ ChangeScrollRegion(curr->w_top, curr->w_bot);
+ if (curr->w_origin)
+ {
+ GotoPos(0, curr->w_top);
+ curr->w_y = curr->w_top;
+ curr->w_x = 0;
+ }
+ else
+ {
+ GotoPos(0, 0);
+ curr->w_y = curr->w_x = 0;
+ }
+ break;
+ case 's':
+ SaveCursor();
+ break;
+ case 't':
+ if (a1 != 8)
+ break;
+ a1 = curr->w_args[2];
+ if (a1 < 1)
+ a1 = curr->w_width;
+ if (a2 < 1)
+ a2 = curr->w_height;
+ if (display && D_CWS == NULL)
+ {
+ a2 = curr->w_height;
+ if (D_CZ0 == NULL || (a1 != Z0width && a1 != Z1width))
+ a1 = curr->w_width;
+ }
+ if (a1 == curr->w_width && a2 == curr->w_height)
+ break;
+ ChangeWindowSize(curr, a1, a2, curr->w_histheight);
+ SetCurr(curr);
+ if (display)
+ Activate(0);
+ break;
+ case 'u':
+ RestoreCursor();
+ break;
+ case 'I':
+ if (!a1)
+ a1 = 1;
+ while (a1--)
+ ForwardTab();
+ break;
+ case 'Z':
+ if (!a1)
+ a1 = 1;
+ while (a1--)
+ BackwardTab();
+ break;
+ case 'L':
+ InsertLine(a1 ? a1 : 1);
+ break;
+ case 'M':
+ DeleteLine(a1 ? a1 : 1);
+ break;
+ case 'P':
+ DeleteChar(a1 ? a1 : 1);
+ break;
+ case '@':
+ InsertChar(a1 ? a1 : 1);
+ break;
+ case 'h':
+ ASetMode(1);
+ break;
+ case 'l':
+ ASetMode(0);
+ break;
+ case 'i':
+ if (display && a1 == 5)
+ PrintStart();
+ break;
+ case 'n':
+ if (a1 == 5) /* Report terminal status */
+ Report("\033[0n", 0, 0);
+ else if (a1 == 6) /* Report cursor position */
+ Report("\033[%d;%dR", curr->w_y + 1, curr->w_x + 1);
+ break;
+ case 'c': /* Identify as VT100 */
+ if (a1 == 0)
+ Report("\033[?%d;%dc", 1, 2);
+ break;
+ case 'x': /* decreqtparm */
+ if (a1 == 0 || a1 == 1)
+ Report("\033[%d;1;1;112;112;1;0x", a1 + 2, 0);
+ break;
+ case 'p': /* obscure code from a 97801 term */
+ if (a1 == 6 || a1 == 7)
+ {
+ curr->w_curinv = 7 - a1;
+ CursorVisibility(curr->w_curinv ? -1 : curr->w_curvvis);
+ }
+ break;
+ case 'S': /* obscure code from a 97801 term */
+ ScrollRegion(a1 ? a1 : 1);
+ break;
+ case 'T': /* obscure code from a 97801 term */
+ ScrollRegion(a1 ? -a1 : -1);
+ break;
+ }
+ break;
+ case '?':
+ for (a2 = 0; a2 < curr->w_NumArgs; a2++)
+ {
+ a1 = curr->w_args[a2];
+ debug2("\\E[?%d%c\n",a1,c);
+ if (c != 'h' && c != 'l')
+ break;
+ i = (c == 'h');
+ switch (a1)
+ {
+ case 1: /* CKM: cursor key mode */
+ CursorkeysMode(curr->w_cursorkeys = i);
+#ifndef TIOCPKT
+ NewAutoFlow(curr, !i);
+#endif /* !TIOCPKT */
+ break;
+ case 2: /* ANM: ansi/vt52 mode */
+ if (i)
+ {
+#ifdef KANJI
+ if (curr->w_kanji)
+ break;
+#endif
+ curr->w_charsets[0] = curr->w_charsets[1] =
+ curr->w_charsets[2] = curr->w_charsets[2] =
+ curr->w_FontL = curr->w_FontR = ASCII;
+ curr->w_Charset = 0;
+ curr->w_CharsetR = 2;
+ curr->w_ss = 0;
+ }
+ break;
+ case 3: /* COLM: column mode */
+ i = (i ? Z0width : Z1width);
+ if (curr->w_width != i && (display == 0 || (D_CZ0 || D_CWS)))
+ {
+ ChangeWindowSize(curr, i, curr->w_height, curr->w_histheight);
+ SetCurr(curr); /* update rows/cols */
+ if (display)
+ Activate(0);
+ }
+ break;
+ /* case 4: SCLM: scrolling mode */
+ case 5: /* SCNM: screen mode */
+ /* This should be reverse video.
+ * Because it is used in some termcaps to emulate
+ * a visual bell we do this hack here.
+ * (screen uses \Eg as special vbell sequence)
+ */
+ if (i)
+ ReverseVideo(1);
+ else
+ {
+ if (display && D_CVR)
+ ReverseVideo(0);
+ else
+ if (curr->w_revvid)
+ {
+ if (display && D_VB)
+ PutStr(D_VB);
+ else
+ curr->w_bell = BELL_VISUAL;
+ }
+ }
+ curr->w_revvid = i;
+ break;
+ case 6: /* OM: origin mode */
+ if ((curr->w_origin = i) != 0)
+ {
+ curr->w_y = curr->w_top;
+ curr->w_x = 0;
+ }
+ else
+ curr->w_y = curr->w_x = 0;
+ if (display)
+ GotoPos(curr->w_x, curr->w_y);
+ break;
+ case 7: /* AWM: auto wrap mode */
+ curr->w_wrap = i;
+ break;
+ /* case 8: ARM: auto repeat mode */
+ /* case 9: INLM: interlace mode */
+ /* case 10: EDM: edit mode */
+ /* case 11: LTM: line transmit mode */
+ /* case 13: SCFDM: space compression / field delimiting */
+ /* case 14: TEM: transmit execution mode */
+ /* case 16: EKEM: edit key execution mode */
+ case 25: /* TCEM: text cursor enable mode */
+ curr->w_curinv = !i;
+ CursorVisibility(curr->w_curinv ? -1 : curr->w_curvvis);
+ break;
+ /* case 40: 132 col enable */
+ /* case 42: NRCM: 7bit NRC character mode */
+ /* case 44: margin bell enable */
+ }
+ }
+ break;
+ case '>':
+ switch (c)
+ {
+ case 'c': /* secondary DA */
+ if (a1 == 0)
+ Report("\033[>%d;%d;0c", 83, nversion); /* 83 == 'S' */
+ break;
+ }
+ break;
+ }
+}
+
+
+/*
+ * Store char in mline. Be sure, that w_Font is set correctly!
+ */
+
+static void
+SetChar(c)
+register int c;
+{
+ register struct win *p = curr;
+ register struct mline *ml;
+
+ FixLine();
+ ml = &p->w_mlines[p->w_y];
+ p->w_rend.image = c;
+ copy_mchar2mline(&p->w_rend, ml, p->w_x);
+}
+
+static void
+StartString(type)
+enum string_t type;
+{
+ curr->w_StringType = type;
+ curr->w_stringp = curr->w_string;
+ curr->w_state = ASTR;
+}
+
+static void
+SaveChar(c)
+int c;
+{
+ if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
+ curr->w_state = LIT;
+ else
+ *(curr->w_stringp)++ = c;
+}
+
+static void
+PrintStart()
+{
+ int pi[2];
+
+ if (printcmd == 0 && D_PO == 0)
+ return;
+ curr->w_pdisplay = display;
+ curr->w_stringp = curr->w_string;
+ curr->w_state = PRIN;
+ if (printcmd == 0 || curr->w_pdisplay->d_printfd >= 0)
+ return;
+ if (pipe(pi))
+ {
+ Msg(errno, "printing pipe");
+ return;
+ }
+ switch (fork())
+ {
+ case -1:
+ Msg(errno, "printing fork");
+ return;
+ case 0:
+ close(0);
+ dup(pi[0]);
+ closeallfiles(0);
+ if (setuid(real_uid) || setgid(real_gid))
+ _exit(1);
+#ifdef SIGPIPE
+ signal(SIGPIPE, SIG_DFL);
+#endif
+ execl("/bin/sh", "sh", "-c", printcmd, 0);
+ _exit(1);
+ default:
+ break;
+ }
+ close(pi[0]);
+ curr->w_pdisplay->d_printfd = pi[1];
+}
+
+static void
+PrintChar(c)
+int c;
+{
+ if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
+ PrintFlush();
+ *(curr->w_stringp)++ = c;
+}
+
+static void
+PrintFlush()
+{
+ struct display *odisp = display;
+
+ display = curr->w_pdisplay;
+ if (display && printcmd)
+ {
+ char *bp = curr->w_string;
+ int len = curr->w_stringp - curr->w_string;
+ int r;
+ while (len && display->d_printfd >= 0)
+ {
+ r = write(display->d_printfd, bp, len);
+ if (r <= 0)
+ {
+ Msg(errno, "printing aborted");
+ close(display->d_printfd);
+ display->d_printfd = -1;
+ break;
+ }
+ bp += r;
+ len -= r;
+ }
+ }
+ else if (display && curr->w_stringp > curr->w_string)
+ {
+ PutStr(D_PO);
+ AddStrn(curr->w_string, curr->w_stringp - curr->w_string);
+ PutStr(D_PF);
+ Flush();
+ }
+ curr->w_stringp = curr->w_string;
+ display = odisp;
+}
+
+
+void
+NewAutoFlow(win, on)
+struct win *win;
+int on;
+{
+ debug1("NewAutoFlow: %d\n", on);
+ SetCurr(win);
+ if (win->w_flow & FLOW_AUTOFLAG)
+ win->w_flow = FLOW_AUTOFLAG | (FLOW_AUTO|FLOW_NOW) * on;
+ else
+ win->w_flow = (win->w_flow & ~FLOW_AUTO) | FLOW_AUTO * on;
+ if (display)
+ SetFlow(win->w_flow & FLOW_NOW);
+}
+
+static void
+DesignateCharset(c, n)
+int c, n;
+{
+ curr->w_ss = 0;
+#ifdef KANJI
+ if (c == ('@' & 037))
+ c = KANJI;
+#endif
+ if (c == 'B' || c == 'J')
+ c = ASCII;
+ if (curr->w_charsets[n] != c)
+ {
+ curr->w_charsets[n] = c;
+ if (curr->w_Charset == n)
+ SetFont(curr->w_FontL = c);
+ if (curr->w_CharsetR == n)
+ curr->w_FontR = c;
+ }
+}
+
+static void
+MapCharset(n)
+int n;
+{
+ curr->w_ss = 0;
+ if (curr->w_Charset != n)
+ {
+ curr->w_Charset = n;
+ SetFont(curr->w_FontL = curr->w_charsets[n]);
+ }
+}
+
+static void
+MapCharsetR(n)
+int n;
+{
+ curr->w_ss = 0;
+ if (curr->w_CharsetR != n)
+ {
+ curr->w_CharsetR = n;
+ curr->w_FontR = curr->w_charsets[n];
+ }
+ curr->w_gr = 1;
+}
+
+static void
+SaveCursor()
+{
+ curr->w_saved = 1;
+ curr->w_Saved_x = curr->w_x;
+ curr->w_Saved_y = curr->w_y;
+ curr->w_SavedRend= curr->w_rend;
+ curr->w_SavedCharset = curr->w_Charset;
+ curr->w_SavedCharsetR = curr->w_CharsetR;
+ bcopy((char *) curr->w_charsets, (char *) curr->w_SavedCharsets,
+ 4 * sizeof(int));
+}
+
+static void
+RestoreCursor()
+{
+ if (curr->w_saved)
+ {
+ GotoPos(curr->w_Saved_x, curr->w_Saved_y);
+ curr->w_x = curr->w_Saved_x;
+ curr->w_y = curr->w_Saved_y;
+ curr->w_rend = curr->w_SavedRend;
+ bcopy((char *) curr->w_SavedCharsets, (char *) curr->w_charsets,
+ 4 * sizeof(int));
+ curr->w_Charset = curr->w_SavedCharset;
+ curr->w_CharsetR = curr->w_SavedCharsetR;
+ curr->w_ss = 0;
+ curr->w_FontL = curr->w_charsets[curr->w_Charset];
+ curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
+ SetRendition(&curr->w_rend);
+ }
+}
+
+static void
+BackSpace()
+{
+ if (curr->w_x > 0)
+ {
+ curr->w_x--;
+ }
+ else if (curr->w_wrap && curr->w_y > 0)
+ {
+ curr->w_x = cols - 1;
+ curr->w_y--;
+ }
+ if (display)
+ GotoPos(curr->w_x, curr->w_y);
+}
+
+static void
+Return()
+{
+ if (curr->w_x > 0)
+ {
+ curr->w_x = 0;
+ if (display)
+ GotoPos(curr->w_x, curr->w_y);
+ }
+}
+
+static void
+LineFeed(out_mode)
+int out_mode;
+{
+ /* out_mode: 0=cr+lf no-output, 1=lf, 2=cr+lf */
+ if (out_mode != 1)
+ curr->w_x = 0;
+ if (curr->w_y != curr->w_bot) /* Don't scroll */
+ {
+ if (curr->w_y < rows-1)
+ curr->w_y++;
+ if (out_mode && display)
+ GotoPos(curr->w_x, curr->w_y);
+ return;
+ }
+ ScrollUpMap(1);
+ if (curr->w_autoaka > 1)
+ curr->w_autoaka--;
+ if (out_mode && display)
+ {
+ ScrollV(0, curr->w_top, cols - 1, curr->w_bot, 1);
+ GotoPos(curr->w_x, curr->w_y);
+ }
+}
+
+static void
+ReverseLineFeed()
+{
+ if (curr->w_y == curr->w_top)
+ {
+ ScrollDownMap(1);
+ if (!display)
+ return;
+ ScrollV(0, curr->w_top, cols - 1, curr->w_bot, -1);
+ GotoPos(curr->w_x, curr->w_y);
+ }
+ else if (curr->w_y > 0)
+ CursorUp(1);
+}
+
+static void
+InsertAChar(c)
+int c;
+{
+ register int y = curr->w_y, x = curr->w_x;
+
+ if (x == cols)
+ x--;
+ save_mline(&curr->w_mlines[y], cols);
+ if (cols - x - 1 > 0)
+ bcopy_mline(&curr->w_mlines[y], x, x + 1, cols - x - 1);
+ SetChar(c);
+ curr->w_x = x + 1;
+ if (!display)
+ return;
+ if (D_CIC || D_IC || D_IM)
+ {
+ InsertMode(curr->w_insert);
+ INSERTCHAR(c);
+ if (y == D_bot)
+ D_lp_missing = 0;
+ }
+ else
+ UpdateLine(&mline_old, y, x, cols - 1);
+}
+
+static void
+InsertChar(n)
+int n;
+{
+ register int y = curr->w_y, x = curr->w_x;
+
+ if (n <= 0)
+ return;
+ if (x == cols)
+ x--;
+ save_mline(&curr->w_mlines[y], cols);
+ if (n >= cols - x)
+ n = cols - x;
+ else
+ bcopy_mline(&curr->w_mlines[y], x, x + n, cols - x - n);
+
+ ClearInLine(y, x, x + n - 1);
+ if (!display)
+ return;
+ ScrollH(y, x, curr->w_width - 1, -n, &mline_old);
+ GotoPos(x, y);
+}
+
+static void
+DeleteChar(n)
+int n;
+{
+ register int y = curr->w_y, x = curr->w_x;
+
+ if (x == cols)
+ x--;
+ save_mline(&curr->w_mlines[y], cols);
+
+ if (n >= cols - x)
+ n = cols - x;
+ else
+ bcopy_mline(&curr->w_mlines[y], x + n, x, cols - x - n);
+ ClearInLine(y, cols - n, cols - 1);
+ if (!display)
+ return;
+ ScrollH(y, x, curr->w_width - 1, n, &mline_old);
+ GotoPos(x, y);
+}
+
+static void
+DeleteLine(n)
+int n;
+{
+ register int old = curr->w_top;
+
+ if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
+ return;
+ if (n > curr->w_bot - curr->w_y + 1)
+ n = curr->w_bot - curr->w_y + 1;
+ curr->w_top = curr->w_y;
+ ScrollUpMap(n);
+ curr->w_top = old;
+ if (!display)
+ return;
+ ScrollV(0, curr->w_y, cols - 1, curr->w_bot, n);
+ GotoPos(curr->w_x, curr->w_y);
+}
+
+static void
+InsertLine(n)
+int n;
+{
+ register int old = curr->w_top;
+
+ if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
+ return;
+ if (n > curr->w_bot - curr->w_y + 1)
+ n = curr->w_bot - curr->w_y + 1;
+ curr->w_top = curr->w_y;
+ ScrollDownMap(n);
+ curr->w_top = old;
+ if (!display)
+ return;
+ ScrollV(0, curr->w_y, cols - 1, curr->w_bot, -n);
+ GotoPos(curr->w_x, curr->w_y);
+}
+
+static void
+ScrollRegion(n)
+int n;
+{
+ if (n > 0)
+ ScrollUpMap(n);
+ else
+ ScrollDownMap(-n);
+ if (!display)
+ return;
+ ScrollV(0, curr->w_top, cols - 1, curr->w_bot, n);
+ GotoPos(curr->w_x, curr->w_y);
+}
+
+static void
+ScrollUpMap(n)
+int n;
+{
+ char tmp[256 * sizeof(struct mline)];
+ register int i, cnt1, cnt2;
+ struct mline *ml;
+#ifdef COPY_PASTE
+ register int ii;
+#endif
+
+ i = curr->w_top + n;
+ cnt1 = n * sizeof(struct mline);
+ cnt2 = (curr->w_bot - i + 1) * sizeof(struct mline);
+#ifdef COPY_PASTE
+ for(ii = curr->w_top; ii < i; ii++)
+ AddLineToHist(curr, &curr->w_mlines[ii]);
+#endif
+ ml = curr->w_mlines + i;
+ for (i = n; i; --i)
+ {
+ --ml;
+ clear_mline(ml, 0, cols + 1);
+ }
+ Scroll((char *) ml, cnt1, cnt2, tmp);
+}
+
+static void
+ScrollDownMap(n)
+int n;
+{
+ char tmp[256 * sizeof(struct mline)];
+ register int i, cnt1, cnt2;
+ struct mline *ml;
+
+ i = curr->w_top;
+ cnt1 = (curr->w_bot - i - n + 1) * sizeof(struct mline);
+ cnt2 = n * sizeof(struct mline);
+ ml = curr->w_mlines + i;
+ Scroll((char *) ml, cnt1, cnt2, tmp);
+ for (i = n; i; --i)
+ {
+ clear_mline(ml, 0, cols + 1);
+ ml++;
+ }
+}
+
+static void
+Scroll(cp, cnt1, cnt2, tmp)
+char *cp, *tmp;
+int cnt1, cnt2;
+{
+ if (!cnt1 || !cnt2)
+ return;
+ if (cnt1 <= cnt2)
+ {
+ bcopy(cp, tmp, cnt1);
+ bcopy(cp + cnt1, cp, cnt2);
+ bcopy(tmp, cp + cnt2, cnt1);
+ }
+ else
+ {
+ bcopy(cp + cnt1, tmp, cnt2);
+ bcopy(cp, cp + cnt2, cnt1);
+ bcopy(tmp, cp, cnt2);
+ }
+}
+
+static void
+ForwardTab()
+{
+ register int x = curr->w_x;
+
+ if (x == cols)
+ {
+ LineFeed(2);
+ x = 0;
+ }
+ if (curr->w_tabs[x] && x < cols - 1)
+ x++;
+ while (x < cols - 1 && !curr->w_tabs[x])
+ x++;
+ GotoPos(x, curr->w_y);
+ curr->w_x = x;
+}
+
+static void
+BackwardTab()
+{
+ register int x = curr->w_x;
+
+ if (curr->w_tabs[x] && x > 0)
+ x--;
+ while (x > 0 && !curr->w_tabs[x])
+ x--;
+ GotoPos(x, curr->w_y);
+ curr->w_x = x;
+}
+
+static void
+ClearScreen()
+{
+ register int i;
+ register struct mline *ml = curr->w_mlines;
+
+ for (i = 0; i < rows; ++i)
+ {
+#ifdef COPY_PASTE
+ AddLineToHist(curr, ml);
+#endif
+ clear_mline(ml, 0, cols + 1);
+ ml++;
+ }
+ if (display)
+ ClearDisplay();
+}
+
+static void
+ClearFromBOS()
+{
+ register int n, y = curr->w_y, x = curr->w_x;
+
+ if (display)
+ Clear(0, 0, 0, cols - 1, x, y, 1);
+ for (n = 0; n < y; ++n)
+ ClearInLine(n, 0, cols - 1);
+ ClearInLine(y, 0, x);
+ RestorePosRendition();
+}
+
+static void
+ClearToEOS()
+{
+ register int n, y = curr->w_y, x = curr->w_x;
+
+ if (x == 0 && y == 0)
+ {
+ ClearScreen();
+ return;
+ }
+ if (display)
+ Clear(x, y, 0, cols - 1, cols - 1, rows - 1, 1);
+ ClearInLine(y, x, cols - 1);
+ for (n = y + 1; n < rows; n++)
+ ClearInLine(n, 0, cols - 1);
+ RestorePosRendition();
+}
+
+static void
+ClearFullLine()
+{
+ register int y = curr->w_y;
+
+ if (display)
+ Clear(0, y, 0, cols - 1, cols - 1, y, 1);
+ ClearInLine(y, 0, cols - 1);
+ RestorePosRendition();
+}
+
+static void
+ClearToEOL()
+{
+ register int y = curr->w_y, x = curr->w_x;
+
+ if (display)
+ Clear(x, y, 0, cols - 1, cols - 1, y, 1);
+ ClearInLine(y, x, cols - 1);
+ RestorePosRendition();
+}
+
+static void
+ClearFromBOL()
+{
+ register int y = curr->w_y, x = curr->w_x;
+
+ if (display)
+ Clear(0, y, 0, cols - 1, x, y, 1);
+ ClearInLine(y, 0, x);
+ RestorePosRendition();
+}
+
+static void
+ClearInLine(y, x1, x2)
+int y, x1, x2;
+{
+ register int n;
+
+ if (x1 == cols)
+ x1--;
+ if (x2 == cols - 1)
+ x2++;
+ if ((n = x2 - x1 + 1) != 0)
+ clear_mline(&curr->w_mlines[y], x1, n);
+}
+
+static void
+CursorRight(n)
+register int n;
+{
+ register int x = curr->w_x;
+
+ if (x == cols)
+ {
+ LineFeed(2);
+ x = 0;
+ }
+ if ((curr->w_x += n) >= cols)
+ curr->w_x = cols - 1;
+ GotoPos(curr->w_x, curr->w_y);
+}
+
+static void
+CursorUp(n)
+register int n;
+{
+ if (curr->w_y < curr->w_top) /* if above scrolling rgn, */
+ {
+ if ((curr->w_y -= n) < 0) /* ignore its limits */
+ curr->w_y = 0;
+ }
+ else
+ if ((curr->w_y -= n) < curr->w_top)
+ curr->w_y = curr->w_top;
+ GotoPos(curr->w_x, curr->w_y);
+}
+
+static void
+CursorDown(n)
+register int n;
+{
+ if (curr->w_y > curr->w_bot) /* if below scrolling rgn, */
+ {
+ if ((curr->w_y += n) > rows - 1) /* ignore its limits */
+ curr->w_y = rows - 1;
+ }
+ else
+ if ((curr->w_y += n) > curr->w_bot)
+ curr->w_y = curr->w_bot;
+ GotoPos(curr->w_x, curr->w_y);
+}
+
+static void
+CursorLeft(n)
+register int n;
+{
+ if ((curr->w_x -= n) < 0)
+ curr->w_x = 0;
+ GotoPos(curr->w_x, curr->w_y);
+}
+
+static void
+ASetMode(on)
+int on;
+{
+ register int i;
+
+ for (i = 0; i < curr->w_NumArgs; ++i)
+ {
+ switch (curr->w_args[i])
+ {
+ case 4:
+ curr->w_insert = on;
+ InsertMode(on);
+ break;
+ case 20:
+ curr->w_autolf = on;
+ break;
+ case 34:
+ curr->w_curvvis = !on;
+ CursorVisibility(curr->w_curinv ? -1 : curr->w_curvvis);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static char rendlist[] =
+{
+ (1 << NATTR), A_BD, A_DI, A_SO, A_US, A_BL, 0, A_RV, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, ~(A_BD|A_SO|A_DI), ~A_SO, ~A_US, ~A_BL, 0, ~A_RV
+};
+
+static void
+SelectRendition()
+{
+ register int j, i = 0, a = curr->w_rend.attr;
+#ifdef COLOR
+ register int c = curr->w_rend.color;
+#endif
+
+ do
+ {
+ j = curr->w_args[i];
+#ifdef COLOR
+ if (j >= 30 && j <= 39)
+ c = (c & 0xf0) | (39 - j);
+ else if (j >= 40 && j <= 49)
+ c = (c & 0x0f) | ((49 - j) << 4);
+ if (j == 0)
+ c = 0;
+#endif
+ if (j < 0 || j >= (sizeof(rendlist)/sizeof(*rendlist)))
+ continue;
+ j = rendlist[j];
+ if (j & (1 << NATTR))
+ a &= j;
+ else
+ a |= j;
+ }
+ while (++i < curr->w_NumArgs);
+ if (curr->w_rend.attr != a)
+ SetAttr(curr->w_rend.attr = a);
+#ifdef COLOR
+ if (curr->w_rend.color != c)
+ SetColor(curr->w_rend.color = c);
+#endif
+}
+
+static void
+FillWithEs()
+{
+ register int i;
+ register char *p, *ep;
+
+ curr->w_y = curr->w_x = 0;
+ for (i = 0; i < rows; ++i)
+ {
+ clear_mline(&curr->w_mlines[i], 0, cols + 1);
+ p = curr->w_mlines[i].image;
+ ep = p + cols;
+ while (p < ep)
+ *p++ = 'E';
+ }
+ if (display)
+ Redisplay(0);
+}
+
+
+static void
+UpdateLine(oml, y, from, to)
+struct mline *oml;
+int from, to, y;
+{
+ ASSERT(display);
+ DisplayLine(oml, &curr->w_mlines[y], y, from, to);
+ RestorePosRendition();
+}
+
+
+static void
+CheckLP(n_ch)
+int n_ch;
+{
+ register int x;
+ register struct mline *ml;
+
+ ASSERT(display);
+ ml = &curr->w_mlines[D_bot];
+ x = cols - 1;
+
+ curr->w_rend.image = n_ch;
+
+ D_lpchar = curr->w_rend;
+ D_lp_missing = 0;
+
+ if (cmp_mchar_mline(&curr->w_rend, ml, x))
+ return;
+ if (!cmp_mchar(&mchar_blank, &curr->w_rend)) /* is new not blank */
+ D_lp_missing = 1;
+ if (!cmp_mchar_mline(&mchar_blank, ml, x)) /* is old char not blank? */
+ {
+ /* old char not blank, new blank, try to delete */
+ if (D_UT)
+ SetRendition(&mchar_null);
+ if (D_CE)
+ PutStr(D_CE);
+ else if (D_DC)
+ PutStr(D_DC);
+ else if (D_CDC)
+ CPutStr(D_CDC, 1);
+ else
+ D_lp_missing = 1;
+ }
+}
+
+/*
+ * Ugly autoaka hack support:
+ * ChangeAKA() sets a new aka
+ * FindAKA() searches for an autoaka match
+ */
+
+void
+ChangeAKA(p, s, l)
+struct win *p;
+char *s;
+int l;
+{
+ if (l > 20)
+ l = 20;
+ strncpy(p->w_akachange, s, l);
+ p->w_akachange[l] = 0;
+ p->w_title = p->w_akachange;
+ if (p->w_akachange != p->w_akabuf)
+ if (p->w_akachange[0] == 0 || p->w_akachange[-1] == ':')
+ p->w_title = p->w_akabuf + strlen(p->w_akabuf) + 1;
+
+ /* yucc */
+ if (p->w_hstatus)
+ {
+ display = p->w_display;
+ if (display)
+ RefreshStatus();
+ }
+}
+
+static void
+FindAKA()
+{
+ register char *cp, *line;
+ register struct win *wp = curr;
+ register int len = strlen(wp->w_akabuf);
+ int y;
+
+ y = (wp->w_autoaka > 0 && wp->w_autoaka <= wp->w_height) ? wp->w_autoaka - 1 : wp->w_y;
+ cols = wp->w_width;
+ try_line:
+ cp = line = wp->w_mlines[y].image;
+ if (wp->w_autoaka > 0 && *wp->w_akabuf != '\0')
+ {
+ for (;;)
+ {
+ if (cp - line >= cols - len)
+ {
+ if (++y == wp->w_autoaka && y < rows)
+ goto try_line;
+ return;
+ }
+ if (strncmp(cp, wp->w_akabuf, len) == 0)
+ break;
+ cp++;
+ }
+ cp += len;
+ }
+ for (len = cols - (cp - line); len && *cp == ' '; len--, cp++)
+ ;
+ if (len)
+ {
+ if (wp->w_autoaka > 0 && (*cp == '!' || *cp == '%' || *cp == '^'))
+ wp->w_autoaka = -1;
+ else
+ wp->w_autoaka = 0;
+ line = cp;
+ while (len && *cp != ' ')
+ {
+ if (*cp++ == '/')
+ line = cp;
+ len--;
+ }
+ ChangeAKA(wp, line, cp - line);
+ }
+ else
+ wp->w_autoaka = 0;
+}
+
+void
+SetCurr(wp)
+struct win *wp;
+{
+ curr = wp;
+ if (curr == 0)
+ return;
+ cols = curr->w_width;
+ rows = curr->w_height;
+ display = curr->w_active ? curr->w_display : 0;
+}
+
+static void
+RestorePosRendition()
+{
+ if (!display)
+ return;
+ GotoPos(curr->w_x, curr->w_y);
+ SetRendition(&curr->w_rend);
+}
+
+/* Send a terminal report as if it were typed. */
+static void
+Report(fmt, n1, n2)
+char *fmt;
+int n1, n2;
+{
+ register int len;
+ char rbuf[40];
+
+ sprintf(rbuf, fmt, n1, n2);
+ len = strlen(rbuf);
+
+ if ((unsigned)(curr->w_inlen + len) <= sizeof(curr->w_inbuf))
+ {
+ bcopy(rbuf, curr->w_inbuf + curr->w_inlen, len);
+ curr->w_inlen += len;
+ }
+}
+
+#ifdef COPY_PASTE
+static void
+AddLineToHist(wp, ml)
+struct win *wp;
+struct mline *ml;
+{
+ register char *q, *o;
+ struct mline *hml;
+
+ if (wp->w_histheight == 0)
+ return;
+ hml = &wp->w_hlines[wp->w_histidx];
+ q = ml->image; ml->image = hml->image; hml->image = q;
+
+ q = ml->attr; o = hml->attr; hml->attr = q; ml->attr = null;
+ if (o != null)
+ free(o);
+
+ q = ml->font; o = hml->font; hml->font = q; ml->font = null;
+ if (o != null)
+ free(o);
+
+#ifdef COLOR
+ q = ml->color; o = hml->color; hml->color = q; ml->color = null;
+ if (o != null)
+ free(o);
+#endif
+
+ if (++wp->w_histidx >= wp->w_histheight)
+ wp->w_histidx = 0;
+}
+#endif
+
diff --git a/ansi.h b/ansi.h
new file mode 100644
index 0000000..1746f28
--- /dev/null
+++ b/ansi.h
@@ -0,0 +1,116 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ * $Id: ansi.h,v 1.6 1994/05/31 12:31:28 mlschroe Exp $ FAU
+ */
+
+#define NATTR 6
+
+#define ATTR_DI 0 /* Dim mode */
+#define ATTR_US 1 /* Underscore mode */
+#define ATTR_BD 2 /* Bold mode */
+#define ATTR_RV 3 /* Reverse mode */
+#define ATTR_SO 4 /* Standout mode */
+#define ATTR_BL 5 /* Blinking */
+
+#define A_DI (1<<ATTR_DI)
+#define A_US (1<<ATTR_US)
+#define A_BD (1<<ATTR_BD)
+#define A_RV (1<<ATTR_RV)
+#define A_SO (1<<ATTR_SO)
+#define A_BL (1<<ATTR_BL)
+#define A_MAX (1<<(NATTR-1))
+
+#define ATYP_M (1<<0)
+#define ATYP_S (1<<1)
+#define ATYP_U (1<<2)
+
+/*
+ * Parser state
+ */
+enum state_t
+{
+ LIT, /* Literal input */
+ ESC, /* Start of escape sequence */
+ ASTR, /* Start of control string */
+ STRESC, /* ESC seen in control string */
+ CSI, /* Reading arguments in "CSI Pn ;...*/
+ PRIN, /* Printer mode */
+ PRINESC, /* ESC seen in printer mode */
+ PRINCSI, /* CSI seen in printer mode */
+ PRIN4 /* CSI 4 seen in printer mode */
+};
+
+enum string_t
+{
+ NONE,
+ DCS, /* Device control string */
+ OSC, /* Operating system command */
+ APC, /* Application program command */
+ /* - used for status change */
+ PM, /* Privacy message */
+ AKA, /* title for current screen */
+ GM, /* Global message to every display */
+ STATUS /* User hardstatus line */
+};
+
+/*
+ * Types of movement used by GotoPos()
+ */
+enum move_t {
+ M_NONE,
+ M_UP,
+ M_CUP,
+ M_DO,
+ M_CDO,
+ M_LE,
+ M_CLE,
+ M_RI,
+ M_CRI,
+ M_RW,
+ M_CR /* CR and rewrite */
+};
+
+#define EXPENSIVE 1000
+
+#define G0 0
+#define G1 1
+#define G2 2
+#define G3 3
+
+#define ASCII 0
+
+#ifdef TOPSTAT
+#define STATLINE (0)
+#else
+#define STATLINE (D_height-1)
+#endif
+
+#ifdef KANJI
+
+#undef KANJI
+#define KANJI ('B' & 037)
+#define KANA 'I'
+
+#define EUC 1
+#define SJIS 2
+
+#endif
diff --git a/attacher.c b/attacher.c
new file mode 100644
index 0000000..d0b330d
--- /dev/null
+++ b/attacher.c
@@ -0,0 +1,815 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: attacher.c,v 1.8 1994/05/31 12:31:32 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+
+#include <pwd.h>
+
+static sigret_t AttacherSigInt __P(SIGPROTOARG);
+#ifdef PASSWORD
+static void trysend __P((int, struct msg *, char *));
+#endif
+#if defined(SIGWINCH) && defined(TIOCGWINSZ)
+static sigret_t AttacherWinch __P(SIGPROTOARG);
+#endif
+#ifdef LOCK
+static sigret_t DoLock __P(SIGPROTOARG);
+static void LockTerminal __P((void));
+static sigret_t LockHup __P(SIGPROTOARG);
+static void screen_builtin_lck __P((void));
+#endif
+#ifdef DEBUG
+static sigret_t AttacherChld __P(SIGPROTOARG);
+#endif
+
+extern int real_uid, real_gid, eff_uid, eff_gid;
+extern char *SockName, *SockMatch, SockPath[];
+extern struct passwd *ppp;
+extern char *attach_tty, *attach_term, *LoginName;
+extern int xflag, dflag, rflag, quietflag, adaptflag;
+extern struct mode attach_Mode;
+extern int MasterPid;
+extern int nethackflag;
+
+#ifdef MULTIUSER
+extern char *multi;
+extern int multiattach, multi_uid, own_uid;
+extern int tty_mode, tty_oldmode;
+# ifndef USE_SETEUID
+static int multipipe[2];
+# endif
+#endif
+
+
+
+/*
+ * Send message to a screen backend.
+ * returns 1 if we could attach one, or 0 if none.
+ * Understands MSG_ATTACH, MSG_DETACH, MSG_POW_DETACH
+ * MSG_CONT, MSG_WINCH and nothing else!
+ */
+
+int
+Attach(how)
+int how;
+{
+ int n, lasts;
+ struct msg m;
+ struct stat st;
+ char *s;
+
+ debug2("Attach: how=%d, tty=%s\n", how, attach_tty);
+#ifdef MULTIUSER
+# ifndef USE_SETEUID
+ while ((how == MSG_ATTACH || how == MSG_CONT) && multiattach)
+ {
+ int ret;
+
+ if (pipe(multipipe))
+ Panic(errno, "pipe");
+ if (chmod(attach_tty, 0666))
+ Panic(errno, "chmod %s", attach_tty);
+ tty_oldmode = tty_mode;
+ eff_uid = -1; /* make UserContext fork */
+ real_uid = multi_uid;
+ if ((ret = UserContext()) <= 0)
+ {
+ char dummy;
+ eff_uid = 0;
+ real_uid = own_uid;
+ if (ret < 0)
+ Panic(errno, "UserContext");
+ close(multipipe[1]);
+ read(multipipe[0], &dummy, 1);
+ if (tty_oldmode >= 0)
+ {
+ chmod(attach_tty, tty_oldmode);
+ tty_oldmode = -1;
+ }
+ ret = UserStatus();
+#ifdef LOCK
+ if (ret == SIG_LOCK)
+ LockTerminal();
+ else
+#endif
+#ifdef SIGTSTP
+ if (ret == SIG_STOP)
+ kill(getpid(), SIGTSTP);
+ else
+#endif
+ if (ret == SIG_POWER_BYE)
+ {
+ int ppid;
+ setuid(real_uid);
+ setgid(real_gid);
+ if ((ppid = getppid()) > 1)
+ Kill(ppid, SIGHUP);
+ exit(0);
+ }
+ else
+ exit(ret);
+ dflag = 0;
+#ifdef MULTI
+ xflag = 1;
+#endif
+ how = MSG_ATTACH;
+ continue;
+ }
+ close(multipipe[0]);
+ eff_uid = real_uid;
+ break;
+ }
+# else /* USE_SETEUID */
+ if ((how == MSG_ATTACH || how == MSG_CONT) && multiattach)
+ {
+ real_uid = multi_uid;
+ eff_uid = own_uid;
+ xseteuid(multi_uid);
+ xseteuid(own_uid);
+ if (chmod(attach_tty, 0666))
+ Panic(errno, "chmod %s", attach_tty);
+ tty_oldmode = tty_mode;
+ }
+# endif /* USE_SETEUID */
+#endif /* MULTIUSER */
+
+ bzero((char *) &m, sizeof(m));
+ m.type = how;
+ strcpy(m.m_tty, attach_tty);
+
+ if (how == MSG_WINCH)
+ {
+ if ((lasts = MakeClientSocket(0)) >= 0)
+ {
+ write(lasts, (char *)&m, sizeof(m));
+ close(lasts);
+ }
+ return 0;
+ }
+
+ if (how == MSG_CONT)
+ {
+ if ((lasts = MakeClientSocket(0)) < 0)
+ {
+ Panic(0, "Sorry, cannot contact session \"%s\" again.\r\n",
+ SockName);
+ }
+ }
+ else
+ {
+ n = FindSocket(&lasts, (int *)0, SockMatch);
+ switch (n)
+ {
+ case 0:
+ if (rflag == 2)
+ return 0;
+ if (quietflag)
+ eexit(10);
+ Panic(0, SockMatch && *SockMatch ? "There is no screen to be %sed matching %s." : "There is no screen to be %sed.",
+ xflag ? "attach" :
+ dflag ? "detach" :
+ "resum", SockMatch);
+ /* NOTREACHED */
+ case 1:
+ break;
+ default:
+ if (quietflag)
+ eexit(10 + n);
+ Panic(0, "Type \"screen [-d] -r [pid.]tty.host\" to resume one of them.");
+ /* NOTREACHED */
+ }
+ }
+ /*
+ * Go in UserContext. Advantage is, you can kill your attacher
+ * when things go wrong. Any disadvantages? jw.
+ * Do this before the attach to prevent races!
+ */
+#ifdef MULTIUSER
+ if (!multiattach)
+#endif
+ setuid(real_uid);
+#if defined(MULTIUSER) && defined(USE_SETEUID)
+ else
+ xseteuid(real_uid); /* multi_uid, allow backend to send signals */
+#endif
+ setgid(real_gid);
+ eff_uid = real_uid;
+ eff_gid = real_gid;
+
+ debug2("Attach: uid %d euid %d\n", getuid(), geteuid());
+ MasterPid = 0;
+ for (s = SockName; *s; s++)
+ {
+ if (*s > '9' || *s < '0')
+ break;
+ MasterPid = 10 * MasterPid + (*s - '0');
+ }
+ debug1("Attach decided, it is '%s'\n", SockPath);
+ debug1("Attach found MasterPid == %d\n", MasterPid);
+ if (stat(SockPath, &st) == -1)
+ Panic(errno, "stat %s", SockPath);
+ if ((st.st_mode & 0600) != 0600)
+ Panic(0, "Socket is in wrong mode (%03o)", st.st_mode);
+ if ((dflag || !xflag) && (st.st_mode & 0700) != (dflag ? 0700 : 0600))
+ Panic(0, "That screen is %sdetached.", dflag ? "already " : "not ");
+#ifdef REMOTE_DETACH
+ if (dflag &&
+ (how == MSG_ATTACH || how == MSG_DETACH || how == MSG_POW_DETACH))
+ {
+ m.m.detach.dpid = getpid();
+ strncpy(m.m.detach.duser, LoginName, sizeof(m.m.detach.duser) - 1);
+ m.m.detach.duser[sizeof(m.m.detach.duser) - 1] = 0;
+# ifdef POW_DETACH
+ if (dflag == 2)
+ m.type = MSG_POW_DETACH;
+ else
+# endif
+ m.type = MSG_DETACH;
+ if (write(lasts, (char *) &m, sizeof(m)) != sizeof(m))
+ Panic(errno, "write");
+ close(lasts);
+ if (how != MSG_ATTACH)
+ return 0; /* we detached it. jw. */
+ sleep(1); /* we dont want to overrun our poor backend. jw. */
+ if ((lasts = MakeClientSocket(0)) == -1)
+ Panic(0, "Cannot contact screen again. Sigh.");
+ m.type = how;
+ }
+#endif
+ ASSERT(how == MSG_ATTACH || how == MSG_CONT);
+ strcpy(m.m.attach.envterm, attach_term);
+ debug1("attach: sending %d bytes... ", (int)sizeof(m));
+
+ strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1);
+ m.m.attach.auser[sizeof(m.m.attach.auser) - 1] = 0;
+ m.m.attach.apid = getpid();
+ m.m.attach.adaptflag = adaptflag;
+ m.m.attach.lines = m.m.attach.columns = 0;
+ if ((s = getenv("LINES")))
+ m.m.attach.lines = atoi(s);
+ if ((s = getenv("COLUMNS")))
+ m.m.attach.columns = atoi(s);
+
+#ifdef PASSWORD
+ if (how == MSG_ATTACH || how == MSG_CONT)
+ trysend(lasts, &m, m.m.attach.password);
+ else
+#endif
+ {
+ if (write(lasts, (char *) &m, sizeof(m)) != sizeof(m))
+ Panic(errno, "write");
+ close(lasts);
+ }
+ debug1("Attach(%d): sent\n", m.type);
+#ifdef MULTIUSER
+ if (multi && (how == MSG_ATTACH || how == MSG_CONT))
+ {
+# ifndef PASSWORD
+ pause();
+# endif
+# ifndef USE_SETEUID
+ close(multipipe[1]);
+# else
+ xseteuid(own_uid);
+ if (tty_oldmode >= 0)
+ if (chmod(attach_tty, tty_oldmode))
+ Panic(errno, "chmod %s", attach_tty);
+ tty_oldmode = -1;
+ xseteuid(real_uid);
+# endif
+ }
+#endif
+ rflag = 0;
+ return 1;
+}
+
+
+#ifdef PASSWORD
+
+static trysendstatok, trysendstatfail;
+
+static sigret_t
+trysendok SIGDEFARG
+{
+ trysendstatok = 1;
+}
+
+static sigret_t
+trysendfail SIGDEFARG
+{
+# ifdef SYSVSIGS
+ signal(SIG_PW_FAIL, trysendfail);
+# endif /* SYSVSIGS */
+ trysendstatfail = 1;
+}
+
+static char screenpw[9];
+
+static void
+trysend(fd, m, pwto)
+int fd;
+struct msg *m;
+char *pwto;
+{
+ char *npw = NULL;
+ sigret_t (*sighup)__P(SIGPROTOARG);
+ sigret_t (*sigusr1)__P(SIGPROTOARG);
+ int tries;
+
+ sigusr1 = signal(SIG_PW_OK, trysendok);
+ sighup = signal(SIG_PW_FAIL, trysendfail);
+ for (tries = 0; ; )
+ {
+ strcpy(pwto, screenpw);
+ trysendstatok = trysendstatfail = 0;
+ if (write(fd, (char *) m, sizeof(*m)) != sizeof(*m))
+ Panic(errno, "write");
+ close(fd);
+ while (trysendstatok == 0 && trysendstatfail == 0)
+ pause();
+ if (trysendstatok)
+ {
+ signal(SIG_PW_OK, sigusr1);
+ signal(SIG_PW_FAIL, sighup);
+ if (trysendstatfail)
+ kill(getpid(), SIG_PW_FAIL);
+ return;
+ }
+ if (++tries > 1 || (npw = getpass("Screen Password:")) == 0 || *npw == 0)
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Panic(0, "The guard slams the door in your face.");
+ else
+#endif
+ Panic(0, "Password incorrect.");
+ }
+ strncpy(screenpw, npw, 8);
+ if ((fd = MakeClientSocket(0)) == -1)
+ Panic(0, "Cannot contact screen again. Sigh.");
+ }
+}
+#endif /* PASSWORD */
+
+
+#ifdef DEBUG
+static int AttacherPanic;
+
+static sigret_t
+AttacherChld SIGDEFARG
+{
+ AttacherPanic=1;
+ SIGRETURN;
+}
+#endif
+
+/*
+ * the frontend's Interrupt handler
+ * we forward SIGINT to the poor backend
+ */
+static sigret_t
+AttacherSigInt SIGDEFARG
+{
+ signal(SIGINT, AttacherSigInt);
+ Kill(MasterPid, SIGINT);
+ SIGRETURN;
+}
+
+/*
+ * Unfortunatelly this is also the SIGHUP handler, so we have to
+ * check, if the backend is already detached.
+ */
+
+sigret_t
+AttacherFinit SIGDEFARG
+{
+ struct stat statb;
+ struct msg m;
+ int s;
+
+ debug("AttacherFinit();\n");
+ signal(SIGHUP, SIG_IGN);
+ /* Check if signal comes from backend */
+ if (stat(SockPath, &statb) == 0 && (statb.st_mode & 0777) != 0600)
+ {
+ debug("Detaching backend!\n");
+ bzero((char *) &m, sizeof(m));
+ strcpy(m.m_tty, attach_tty);
+ debug1("attach_tty is %s\n", attach_tty);
+ m.m.detach.dpid = getpid();
+ m.type = MSG_HANGUP;
+ if ((s = MakeClientSocket(0)) >= 0)
+ {
+ write(s, (char *)&m, sizeof(m));
+ close(s);
+ }
+ }
+#ifdef MULTIUSER
+ if (tty_oldmode >= 0)
+ {
+ setuid(own_uid);
+ chmod(attach_tty, tty_oldmode);
+ }
+#endif
+ exit(0);
+ SIGRETURN;
+}
+
+#ifdef POW_DETACH
+static sigret_t
+AttacherFinitBye SIGDEFARG
+{
+ int ppid;
+ debug("AttacherFintBye()\n");
+#if defined(MULTIUSER) && !defined(USE_SETEUID)
+ if (multiattach)
+ exit(SIG_POWER_BYE);
+#endif
+#ifdef MULTIUSER
+ setuid(own_uid);
+#else
+ setuid(real_uid);
+#endif
+ setgid(real_gid);
+ /* we don't want to disturb init (even if we were root), eh? jw */
+ if ((ppid = getppid()) > 1)
+ Kill(ppid, SIGHUP); /* carefully say good bye. jw. */
+ exit(0);
+ SIGRETURN;
+}
+#endif
+
+static int SuspendPlease;
+
+static sigret_t
+SigStop SIGDEFARG
+{
+ debug("SigStop()\n");
+ SuspendPlease = 1;
+ SIGRETURN;
+}
+
+#ifdef LOCK
+static int LockPlease;
+
+static sigret_t
+DoLock SIGDEFARG
+{
+# ifdef SYSVSIGS
+ signal(SIG_LOCK, DoLock);
+# endif
+ debug("DoLock()\n");
+ LockPlease = 1;
+ SIGRETURN;
+}
+#endif
+
+#if defined(SIGWINCH) && defined(TIOCGWINSZ)
+static int SigWinchPlease;
+
+static sigret_t
+AttacherWinch SIGDEFARG
+{
+ debug("AttacherWinch()\n");
+ SigWinchPlease = 1;
+ SIGRETURN;
+}
+#endif
+
+
+/*
+ * Attacher loop - no return
+ */
+
+void
+Attacher()
+{
+ signal(SIGHUP, AttacherFinit);
+ signal(SIG_BYE, AttacherFinit);
+#ifdef POW_DETACH
+ signal(SIG_POWER_BYE, AttacherFinitBye);
+#endif
+#ifdef LOCK
+ signal(SIG_LOCK, DoLock);
+#endif
+ signal(SIGINT, AttacherSigInt);
+#ifdef BSDJOBS
+ signal(SIG_STOP, SigStop);
+#endif
+#if defined(SIGWINCH) && defined(TIOCGWINSZ)
+ signal(SIGWINCH, AttacherWinch);
+#endif
+#ifdef DEBUG
+ signal(SIGCHLD, AttacherChld);
+#endif
+ debug("attacher: going for a nap.\n");
+ dflag = 0;
+#ifdef MULTI
+ xflag = 1;
+#endif
+ for (;;)
+ {
+#ifdef DEBUG
+ sleep(1);
+ if (kill(MasterPid, 0) < 0 && errno != EPERM)
+ {
+ debug1("attacher: Panic! MasterPid %d does not exist.\n", MasterPid);
+ AttacherPanic++;
+ }
+#else
+ pause();
+#endif
+/*
+ debug("attacher: ding!\n");
+*/
+#ifdef DEBUG
+ if (AttacherPanic)
+ {
+ fcntl(0, F_SETFL, 0);
+ SetTTY(0, &attach_Mode);
+ printf("\nSuddenly the Dungeon collapses!! - You die...\n");
+ eexit(1);
+ }
+#endif
+#ifdef BSDJOBS
+ if (SuspendPlease)
+ {
+ SuspendPlease = 0;
+#if defined(MULTIUSER) && !defined(USE_SETEUID)
+ if (multiattach)
+ exit(SIG_STOP);
+#endif
+ signal(SIGTSTP, SIG_DFL);
+ debug("attacher: killing myself SIGTSTP\n");
+ kill(getpid(), SIGTSTP);
+ debug("attacher: continuing from stop\n");
+ signal(SIG_STOP, SigStop);
+ (void) Attach(MSG_CONT);
+ }
+#endif
+#ifdef LOCK
+ if (LockPlease)
+ {
+ LockPlease = 0;
+#if defined(MULTIUSER) && !defined(USE_SETEUID)
+ if (multiattach)
+ exit(SIG_LOCK);
+#endif
+ LockTerminal();
+# ifdef SYSVSIGS
+ signal(SIG_LOCK, DoLock);
+# endif
+ (void) Attach(MSG_CONT);
+ }
+#endif /* LOCK */
+#if defined(SIGWINCH) && defined(TIOCGWINSZ)
+ if (SigWinchPlease)
+ {
+ SigWinchPlease = 0;
+# ifdef SYSVSIGS
+ signal(SIGWINCH, AttacherWinch);
+# endif
+ (void) Attach(MSG_WINCH);
+ }
+#endif /* SIGWINCH */
+ }
+}
+
+#ifdef LOCK
+
+/* ADDED by Rainer Pruy 10/15/87 */
+/* POLISHED by mls. 03/10/91 */
+
+static char LockEnd[] = "Welcome back to screen !!\n";
+
+static sigret_t
+LockHup SIGDEFARG
+{
+ int ppid = getppid();
+#ifdef MULTIUSER
+ setuid(own_uid);
+#else
+ setuid(real_uid);
+#endif
+ setgid(real_gid);
+ if (ppid > 1)
+ Kill(ppid, SIGHUP);
+ exit(0);
+}
+
+static void
+LockTerminal()
+{
+ char *prg;
+ int sig, pid;
+ sigret_t (*sigs[NSIG])__P(SIGPROTOARG);
+
+ for (sig = 1; sig < NSIG; sig++)
+ sigs[sig] = signal(sig, SIG_IGN);
+ signal(SIGHUP, LockHup);
+ printf("\n");
+
+ prg = getenv("LOCKPRG");
+ if (prg && strcmp(prg, "builtin") && !access(prg, X_OK))
+ {
+ signal(SIGCHLD, SIG_DFL);
+ debug1("lockterminal: '%s' seems executable, execl it!\n", prg);
+ if ((pid = fork()) == 0)
+ {
+ /* Child */
+#ifdef MULTIUSER
+ setuid(own_uid);
+#else
+ setuid(real_uid); /* this should be done already */
+#endif
+ setgid(real_gid);
+ closeallfiles(0); /* important: /etc/shadow may be open */
+ execl(prg, "SCREEN-LOCK", NULL);
+ exit(errno);
+ }
+ if (pid == -1)
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(errno, "Cannot fork terminal - lock failed");
+ else
+#endif
+ Msg(errno, "Cannot lock terminal - fork failed");
+ }
+ else
+ {
+#ifdef BSDWAIT
+ union wait wstat;
+#else
+ int wstat;
+#endif
+ int wret;
+
+#ifdef hpux
+ signal(SIGCHLD, SIG_DFL);
+#endif
+ errno = 0;
+ while (((wret = wait(&wstat)) != pid) ||
+ ((wret == -1) && (errno == EINTR))
+ )
+ errno = 0;
+
+ if (errno)
+ {
+ Msg(errno, "Lock");
+ sleep(2);
+ }
+ else if (WTERMSIG(wstat) != 0)
+ {
+ fprintf(stderr, "Lock: %s: Killed by signal: %d%s\n", prg,
+ WTERMSIG(wstat), WIFCORESIG(wstat) ? " (Core dumped)" : "");
+ sleep(2);
+ }
+ else if (WEXITSTATUS(wstat))
+ {
+ debug2("Lock: %s: return code %d\n", prg, WEXITSTATUS(wstat));
+ }
+ else
+ printf(LockEnd);
+ }
+ }
+ else
+ {
+ if (prg)
+ {
+ debug1("lockterminal: '%s' seems NOT executable, we use our builtin\n", prg);
+ }
+ else
+ {
+ debug("lockterminal: using buitin.\n");
+ }
+ screen_builtin_lck();
+ }
+ /* reset signals */
+ for (sig = 1; sig < NSIG; sig++)
+ {
+ if (sigs[sig] != (sigret_t(*)__P(SIGPROTOARG)) -1)
+ signal(sig, sigs[sig]);
+ }
+} /* LockTerminal */
+
+/* -- original copyright by Luigi Cannelloni 1985 (luigi@faui70.UUCP) -- */
+static void
+screen_builtin_lck()
+{
+ char fullname[100], *cp1, message[BUFSIZ];
+ char *pass, mypass[9];
+
+#ifdef undef
+ /* get password entry */
+ if ((ppp = getpwuid(real_uid)) == NULL)
+ {
+ fprintf(stderr, "screen_builtin_lck: No passwd entry.\007\n");
+ sleep(2);
+ return;
+ }
+ if (!isatty(0))
+ {
+ fprintf(stderr, "screen_builtin_lck: Not a tty.\007\n");
+ sleep(2);
+ return;
+ }
+#endif
+ pass = ppp->pw_passwd;
+ if (pass == 0 || *pass == 0)
+ {
+ if ((pass = getpass("Key: ")))
+ {
+ strncpy(mypass, pass, 8);
+ mypass[8] = 0;
+ if (*mypass == 0)
+ return;
+ if ((pass = getpass("Again: ")))
+ {
+ if (strcmp(mypass, pass))
+ {
+ fprintf(stderr, "Passwords don't match.\007\n");
+ sleep(2);
+ return;
+ }
+ }
+ }
+ if (pass == 0)
+ {
+ fprintf(stderr, "Getpass error.\007\n");
+ sleep(2);
+ return;
+ }
+ pass = 0;
+ }
+
+ debug("screen_builtin_lck looking in gcos field\n");
+ strcpy(fullname, ppp->pw_gecos);
+ if ((cp1 = index(fullname, ',')) != NULL)
+ *cp1 = '\0';
+ if ((cp1 = index(fullname, '&')) != NULL)
+ {
+ sprintf(cp1, "%s", ppp->pw_name);
+ if (*cp1 >= 'a' && *cp1 <= 'z')
+ *cp1 -= 'a' - 'A';
+ }
+
+ sprintf(message, "Screen used by %s <%s>.\nPassword:\007",
+ fullname, ppp->pw_name);
+
+ /* loop here to wait for correct password */
+ for (;;)
+ {
+ debug("screen_builtin_lck awaiting password\n");
+ errno = 0;
+ if ((cp1 = getpass(message)) == NULL)
+ {
+ AttacherFinit(SIGARG);
+ /* NOTREACHED */
+ }
+ debug3("getpass(%d): %x == %s\n", errno, (unsigned int)cp1, cp1);
+ if (pass)
+ {
+ if (!strncmp(crypt(cp1, pass), pass, strlen(pass)))
+ break;
+ }
+ else
+ {
+ if (!strcmp(cp1, mypass))
+ break;
+ }
+ debug("screen_builtin_lck: NO!!!!!\n");
+ }
+ debug("password ok.\n");
+}
+
+#endif /* LOCK */
diff --git a/comm.c b/comm.c
new file mode 100644
index 0000000..a676cb6
--- /dev/null
+++ b/comm.c
@@ -0,0 +1,223 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: comm.c,v 1.10 1993/11/30 19:28:07 mlschroe Exp $ FAU")
+
+#include "config.h"
+#include "acls.h"
+#include "comm.h"
+
+/* Must be in alpha order ! */
+
+struct comm comms[RC_LAST + 1] =
+{
+#ifdef MULTIUSER
+ { "acladd", ARGS_ONE },
+ { "aclchg", ARGS_THREE },
+ { "acldel", ARGS_ONE },
+ { "aclgrp", ARGS_ONE },
+#endif
+ { "activity", ARGS_ONE },
+ { "aka", NEED_FORE|ARGS_ZEROONE }, /* TO BE REMOVED */
+ { "allpartial", NEED_DISPLAY|ARGS_ONE },
+ { "at", NEED_DISPLAY|ARGS_TWO|ARGS_ORMORE },
+ { "autodetach", ARGS_ONE },
+#ifdef AUTO_NUKE
+ { "autonuke", NEED_DISPLAY|ARGS_ONE },
+#endif
+ { "bell", ARGS_ZEROONE },
+ { "bell_msg", ARGS_ZEROONE },
+ { "bind", ARGS_ONE|ARGS_ORMORE },
+#ifdef MAPKEYS
+ { "bindkey", ARGS_ZERO|ARGS_ORMORE },
+#endif
+ { "break", NEED_FORE|ARGS_ZEROONE },
+#ifdef COPY_PASTE
+ { "bufferfile", ARGS_ZEROONE },
+#endif
+ { "c1", NEED_FORE|ARGS_ZEROONE },
+ { "charset", NEED_FORE|ARGS_ONE },
+ { "chdir", ARGS_ZEROONE },
+ { "clear", NEED_FORE|ARGS_ZERO },
+#ifdef MULTI
+ { "clone", NEED_DISPLAY|ARGS_ONE|ARGS_ORMORE },
+#endif
+ { "colon", NEED_DISPLAY|ARGS_ZERO },
+ { "command", NEED_DISPLAY|ARGS_ZERO },
+ { "console", NEED_FORE|ARGS_ZEROONE },
+#ifdef COPY_PASTE
+ { "copy", NEED_FORE|ARGS_ZERO },
+ { "crlf", ARGS_ONE },
+#endif
+ { "debug", ARGS_ZEROONE },
+#ifdef AUTO_NUKE
+ { "defautonuke", ARGS_ONE },
+#endif
+ { "defc1", ARGS_ONE },
+ { "defcharset", ARGS_ZEROONE },
+ { "defescape", ARGS_ONE },
+ { "defflow", ARGS_ONETWO },
+ { "defgr", ARGS_ONE },
+ { "defhstatus", ARGS_ZEROONE },
+#ifdef KANJI
+ { "defkanji", ARGS_ONE },
+#endif
+#if defined(UTMPOK) && defined(LOGOUTOK)
+ { "deflogin", ARGS_ONE },
+#endif
+ { "defmode", ARGS_ONE },
+ { "defmonitor", ARGS_ONE },
+ { "defobuflimit", ARGS_ONE },
+#ifdef COPY_PASTE
+ { "defscrollback", ARGS_ONE },
+#endif
+ { "defwrap", ARGS_ONE },
+ { "defwritelock", ARGS_ONE },
+ { "detach", NEED_DISPLAY|ARGS_ZERO },
+ { "digraph", NEED_DISPLAY|ARGS_ZEROONE },
+ { "displays", NEED_DISPLAY|ARGS_ZERO },
+ { "dumptermcap", NEED_FORE|ARGS_ZERO },
+ { "echo", ARGS_ONETWO },
+ { "escape", NEED_DISPLAY|ARGS_ONE },
+#ifdef PSEUDOS
+ { "exec", NEED_FORE|ARGS_ZERO|ARGS_ORMORE },
+#endif
+ { "flow", NEED_FORE|ARGS_ZEROONE },
+ { "gr", NEED_FORE|ARGS_ZEROONE },
+ { "hardcopy", NEED_FORE|ARGS_ZERO },
+ { "hardcopy_append", ARGS_ONE },
+ { "hardcopydir", ARGS_ONE },
+ { "hardstatus", NEED_DISPLAY|ARGS_ZEROONE },
+ { "height", NEED_DISPLAY|ARGS_ZEROONE },
+ { "help", NEED_DISPLAY|ARGS_ZERO },
+#ifdef COPY_PASTE
+ { "history", NEED_FORE|ARGS_ZERO },
+#endif
+ { "info", NEED_DISPLAY|ARGS_ZERO },
+#ifdef KANJI
+ { "kanji", NEED_FORE|ARGS_ONETWO },
+#endif
+ { "kill", NEED_FORE|ARGS_ZERO },
+ { "lastmsg", NEED_DISPLAY|ARGS_ZERO },
+ { "license", NEED_DISPLAY|ARGS_ZERO },
+#ifdef LOCK
+ { "lockscreen", NEED_DISPLAY|ARGS_ZERO },
+#endif
+ { "log", NEED_FORE|ARGS_ZEROONE },
+ { "logfile", ARGS_ZEROONE },
+#if defined(UTMPOK) && defined(LOGOUTOK)
+ { "login", NEED_FORE|ARGS_ZEROONE },
+#endif
+#ifdef MAPKEYS
+ { "mapdefault", NEED_DISPLAY|ARGS_ZERO },
+ { "mapnotnext", NEED_DISPLAY|ARGS_ZERO },
+ { "maptimeout", ARGS_ZEROONE },
+#endif
+#ifdef COPY_PASTE
+ { "markkeys", ARGS_ONE },
+#endif
+ { "meta", NEED_DISPLAY|ARGS_ZERO },
+ { "monitor", NEED_FORE|ARGS_ZEROONE },
+ { "msgminwait", ARGS_ONE },
+ { "msgwait", ARGS_ONE },
+#ifdef MULTIUSER
+ { "multiuser", ARGS_ONE },
+#endif
+#ifdef NETHACK
+ { "nethack", ARGS_ONE },
+#endif
+ { "next", NEED_DISPLAY|NEED_FORE|ARGS_ZERO },
+ { "number", NEED_FORE|ARGS_ZEROONE },
+ { "obuflimit", NEED_DISPLAY|ARGS_ZEROONE },
+ { "other", NEED_DISPLAY|NEED_FORE|ARGS_ZERO },
+ { "partial", NEED_FORE|ARGS_ZEROONE },
+#ifdef PASSWORD
+ { "password", ARGS_ZEROONE },
+#endif
+#ifdef COPY_PASTE
+ { "paste", NEED_DISPLAY|ARGS_ZEROONETWO },
+ { "pastefont", ARGS_ZEROONE },
+#endif
+ { "pow_break", NEED_FORE|ARGS_ZEROONE },
+#ifdef POW_DETACH
+ { "pow_detach", NEED_DISPLAY|ARGS_ZERO },
+ { "pow_detach_msg", ARGS_ZEROONE },
+#endif
+ { "prev", NEED_DISPLAY|NEED_FORE|ARGS_ZERO },
+ { "printcmd", ARGS_ZEROONE },
+ { "process", NEED_DISPLAY|ARGS_ZEROONE },
+ { "quit", ARGS_ZERO },
+#ifdef COPY_PASTE
+ { "readbuf", NEED_DISPLAY|ARGS_ZERO },
+#endif
+ { "readreg", ARGS_ZEROONETWO },
+ { "redisplay", NEED_DISPLAY|ARGS_ZERO },
+ { "register", ARGS_TWO },
+#ifdef COPY_PASTE
+ { "removebuf", ARGS_ZERO },
+#endif
+ { "reset", NEED_FORE|ARGS_ZERO },
+ { "screen", ARGS_ZERO|ARGS_ORMORE },
+#ifdef COPY_PASTE
+ { "scrollback", NEED_FORE|ARGS_ONE },
+#endif
+ { "select", ARGS_ZEROONE },
+ { "sessionname", ARGS_ZEROONE },
+ { "setenv", ARGS_ZEROONETWO },
+ { "shell", ARGS_ONE },
+ { "shellaka", ARGS_ONE }, /* TO BE REMOVED */
+ { "shelltitle", ARGS_ONE },
+ { "silence", NEED_FORE|ARGS_ZEROONE },
+ { "silencewait", ARGS_ONE },
+ { "sleep", ARGS_ONE },
+ { "slowpaste", ARGS_ONE },
+ { "sorendition", ARGS_ZEROONETWO },
+ { "startup_message", ARGS_ONE },
+ { "stuff", NEED_DISPLAY|ARGS_ONE },
+#ifdef BSDJOBS
+ { "suspend", NEED_DISPLAY|ARGS_ZERO },
+#endif
+ { "term", ARGS_ONE },
+ { "termcap", ARGS_TWOTHREE },
+ { "termcapinfo", ARGS_TWOTHREE },
+ { "terminfo", ARGS_TWOTHREE },
+ { "time", ARGS_ZERO },
+ { "title", NEED_FORE|ARGS_ZEROONE },
+ { "unsetenv", ARGS_ONE },
+ { "vbell", ARGS_ZEROONE },
+ { "vbell_msg", ARGS_ZEROONE },
+ { "vbellwait", ARGS_ONE },
+ { "version", ARGS_ZERO },
+ { "wall", NEED_DISPLAY|ARGS_ONE|ARGS_ORMORE },
+ { "width", NEED_DISPLAY|ARGS_ZEROONE },
+ { "windows", NEED_DISPLAY|ARGS_ZERO },
+ { "wrap", NEED_FORE|ARGS_ZEROONE },
+#ifdef COPY_PASTE
+ { "writebuf", NEED_DISPLAY|ARGS_ZERO },
+#endif
+ { "writelock", NEED_FORE|ARGS_ZEROONE },
+ { "xoff", NEED_DISPLAY|ARGS_ZERO },
+ { "xon", NEED_DISPLAY|ARGS_ZERO },
+ { "zombie", ARGS_ZEROONE }
+};
diff --git a/comm.h.dist b/comm.h.dist
new file mode 100644
index 0000000..bbe0052
--- /dev/null
+++ b/comm.h.dist
@@ -0,0 +1,177 @@
+/*
+ * This file is automagically created from comm.c -- DO NOT EDIT
+ */
+
+struct comm
+{
+ char *name;
+ int flags;
+#ifdef MULTIUSER
+ AclBits userbits[ACL_BITS_PER_CMD];
+#endif
+};
+
+#define ARGS_MASK (3)
+
+#define ARGS_ZERO (0)
+#define ARGS_ONE (1)
+#define ARGS_TWO (2)
+#define ARGS_THREE (3)
+
+#define ARGS_PLUSONE (1<<2)
+#define ARGS_PLUSTWO (1<<3)
+#define ARGS_ORMORE (1<<4)
+
+#define NEED_FORE (1<<5) /* this command needs a fore window */
+#define NEED_DISPLAY (1<<6) /* this command needs a display */
+
+#define ARGS_ZEROONE (ARGS_ZERO|ARGS_PLUSONE)
+#define ARGS_ONETWO (ARGS_ONE |ARGS_PLUSONE)
+#define ARGS_TWOTHREE (ARGS_TWO |ARGS_PLUSONE)
+#define ARGS_ZEROTWO (ARGS_ZERO|ARGS_PLUSTWO)
+#define ARGS_ZEROONETWO (ARGS_ZERO|ARGS_PLUSONE|ARGS_PLUSTWO)
+
+struct action
+{
+ int nr;
+ char **args;
+};
+
+#define RC_ILLEGAL -1
+
+#define RC_ACLADD 0
+#define RC_ACLCHG 1
+#define RC_ACLDEL 2
+#define RC_ACLGRP 3
+#define RC_ACTIVITY 4
+#define RC_AKA 5
+#define RC_ALLPARTIAL 6
+#define RC_AT 7
+#define RC_AUTODETACH 8
+#define RC_AUTONUKE 9
+#define RC_BELL 10
+#define RC_BELL_MSG 11
+#define RC_BIND 12
+#define RC_BINDKEY 13
+#define RC_BREAK 14
+#define RC_BUFFERFILE 15
+#define RC_C1 16
+#define RC_CHARSET 17
+#define RC_CHDIR 18
+#define RC_CLEAR 19
+#define RC_CLONE 20
+#define RC_COLON 21
+#define RC_COMMAND 22
+#define RC_CONSOLE 23
+#define RC_COPY 24
+#define RC_CRLF 25
+#define RC_DEBUG 26
+#define RC_DEFAUTONUKE 27
+#define RC_DEFC1 28
+#define RC_DEFCHARSET 29
+#define RC_DEFESCAPE 30
+#define RC_DEFFLOW 31
+#define RC_DEFGR 32
+#define RC_DEFHSTATUS 33
+#define RC_DEFKANJI 34
+#define RC_DEFLOGIN 35
+#define RC_DEFMODE 36
+#define RC_DEFMONITOR 37
+#define RC_DEFOBUFLIMIT 38
+#define RC_DEFSCROLLBACK 39
+#define RC_DEFWRAP 40
+#define RC_DEFWRITELOCK 41
+#define RC_DETACH 42
+#define RC_DIGRAPH 43
+#define RC_DISPLAYS 44
+#define RC_DUMPTERMCAP 45
+#define RC_ECHO 46
+#define RC_ESCAPE 47
+#define RC_EXEC 48
+#define RC_FLOW 49
+#define RC_GR 50
+#define RC_HARDCOPY 51
+#define RC_HARDCOPY_APPEND 52
+#define RC_HARDCOPYDIR 53
+#define RC_HARDSTATUS 54
+#define RC_HEIGHT 55
+#define RC_HELP 56
+#define RC_HISTORY 57
+#define RC_INFO 58
+#define RC_KANJI 59
+#define RC_KILL 60
+#define RC_LASTMSG 61
+#define RC_LICENSE 62
+#define RC_LOCKSCREEN 63
+#define RC_LOG 64
+#define RC_LOGFILE 65
+#define RC_LOGIN 66
+#define RC_MAPDEFAULT 67
+#define RC_MAPNOTNEXT 68
+#define RC_MAPTIMEOUT 69
+#define RC_MARKKEYS 70
+#define RC_META 71
+#define RC_MONITOR 72
+#define RC_MSGMINWAIT 73
+#define RC_MSGWAIT 74
+#define RC_MULTIUSER 75
+#define RC_NETHACK 76
+#define RC_NEXT 77
+#define RC_NUMBER 78
+#define RC_OBUFLIMIT 79
+#define RC_OTHER 80
+#define RC_PARTIAL 81
+#define RC_PASSWORD 82
+#define RC_PASTE 83
+#define RC_PASTEFONT 84
+#define RC_POW_BREAK 85
+#define RC_POW_DETACH 86
+#define RC_POW_DETACH_MSG 87
+#define RC_PREV 88
+#define RC_PRINTCMD 89
+#define RC_PROCESS 90
+#define RC_QUIT 91
+#define RC_READBUF 92
+#define RC_READREG 93
+#define RC_REDISPLAY 94
+#define RC_REGISTER 95
+#define RC_REMOVEBUF 96
+#define RC_RESET 97
+#define RC_SCREEN 98
+#define RC_SCROLLBACK 99
+#define RC_SELECT 100
+#define RC_SESSIONNAME 101
+#define RC_SETENV 102
+#define RC_SHELL 103
+#define RC_SHELLAKA 104
+#define RC_SHELLTITLE 105
+#define RC_SILENCE 106
+#define RC_SILENCEWAIT 107
+#define RC_SLEEP 108
+#define RC_SLOWPASTE 109
+#define RC_SORENDITION 110
+#define RC_STARTUP_MESSAGE 111
+#define RC_STUFF 112
+#define RC_SUSPEND 113
+#define RC_TERM 114
+#define RC_TERMCAP 115
+#define RC_TERMCAPINFO 116
+#define RC_TERMINFO 117
+#define RC_TIME 118
+#define RC_TITLE 119
+#define RC_UNSETENV 120
+#define RC_VBELL 121
+#define RC_VBELL_MSG 122
+#define RC_VBELLWAIT 123
+#define RC_VERSION 124
+#define RC_WALL 125
+#define RC_WIDTH 126
+#define RC_WINDOWS 127
+#define RC_WRAP 128
+#define RC_WRITEBUF 129
+#define RC_WRITELOCK 130
+#define RC_XOFF 131
+#define RC_XON 132
+#define RC_ZOMBIE 133
+
+#define RC_LAST 133
diff --git a/comm.sh b/comm.sh
new file mode 100644
index 0000000..9aa0a20
--- /dev/null
+++ b/comm.sh
@@ -0,0 +1,77 @@
+#! /bin/sh
+
+if test -z "$AWK"; then
+ AWK=awk
+fi
+if test -z "$CC"; then
+ CC=cc
+fi
+if test -z "$srcdir"; then
+ srcdir=.
+fi
+
+rm -f comm.h
+cat << EOF > comm.h
+/*
+ * This file is automagically created from comm.c -- DO NOT EDIT
+ */
+
+struct comm
+{
+ char *name;
+ int flags;
+#ifdef MULTIUSER
+ AclBits userbits[ACL_BITS_PER_CMD];
+#endif
+};
+
+#define ARGS_MASK (3)
+
+#define ARGS_ZERO (0)
+#define ARGS_ONE (1)
+#define ARGS_TWO (2)
+#define ARGS_THREE (3)
+
+#define ARGS_PLUSONE (1<<2)
+#define ARGS_PLUSTWO (1<<3)
+#define ARGS_ORMORE (1<<4)
+
+#define NEED_FORE (1<<5) /* this command needs a fore window */
+#define NEED_DISPLAY (1<<6) /* this command needs a display */
+
+#define ARGS_ZEROONE (ARGS_ZERO|ARGS_PLUSONE)
+#define ARGS_ONETWO (ARGS_ONE |ARGS_PLUSONE)
+#define ARGS_TWOTHREE (ARGS_TWO |ARGS_PLUSONE)
+#define ARGS_ZEROTWO (ARGS_ZERO|ARGS_PLUSTWO)
+#define ARGS_ZEROONETWO (ARGS_ZERO|ARGS_PLUSONE|ARGS_PLUSTWO)
+
+struct action
+{
+ int nr;
+ char **args;
+};
+
+#define RC_ILLEGAL -1
+
+EOF
+$AWK < ${srcdir}/comm.c >> comm.h '
+/^ [{] ".*/ { if (old > $2) {
+ printf("***ERROR: %s <= %s !!!\n\n", $2, old);
+ exit 1;
+ }
+ old = $2;
+ }
+'
+$CC -E -I. -I${srcdir} ${srcdir}/comm.c > comm.cpp
+sed < comm.cpp \
+ -n \
+ -e '/^ *{ "/y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \
+ -e '/^ *{ "/s/^ *{ "\([^"]*\)".*/\1/p' \
+| $AWK '
+/.*/ { printf "#define RC_%s %d\n",$0,i++;
+ }
+END { printf "\n#define RC_LAST %d\n",i-1;
+ }
+' >> comm.h
+chmod a-w comm.h
+rm -f comm.cpp
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..2d79d57
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,466 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************
+ * $Id: config.h.in,v 1.12 1994/05/31 12:31:36 mlschroe Exp $ FAU
+ */
+
+
+
+
+
+/**********************************************************************
+ *
+ * User Configuration Section
+ */
+
+
+
+/*
+ * Define SOCKDIR to be the directory to contain the named sockets
+ * screen creates. This should be in a common subdirectory, such as
+ * /usr/local or /tmp. It makes things a little more secure if you
+ * choose a directory which is not writable by everyone or where the
+ * "sticky" bit is on, but this isn't required.
+ * If SOCKDIR is not defined screen will put the named sockets in
+ * the user's home directory. Notice that this can cause you problems
+ * if some user's HOME directories are NFS-mounted and don't support
+ * named sockets.
+ * Screen will name the subdirectories "S-$USER" (e.g /tmp/S-davison).
+ * Do not define TMPTEST unless it's for debugging purpose.
+ */
+
+#ifndef TMPTEST
+# define SOCKDIR "/tmp/screens"
+#else
+# define SOCKDIR "/tmp/testscreens"
+#endif
+
+/*
+ * Screen sources two startup files. First a global file with a path
+ * specified here, second your local $HOME/.screenrc
+ * Don't define this, if you don't want it.
+ */
+#ifndef ETCSCREENRC
+# define ETCSCREENRC "/usr/local/etc/screenrc"
+#endif
+
+/*
+ * Screen can look for the environment variable $SYSSCREENRC and -if it
+ * exists- load the file specified in that variable as global screenrc.
+ * If you want to enable this feature, define ALLOW_SYSSCREENRC to one (1).
+ * Otherwise ETCSCREENRC is always loaded.
+ */
+#define ALLOW_SYSSCREENRC 1
+
+/*
+ * define PTYMODE if you do not like the default of 0622, which allows
+ * public write to your pty.
+ * define PTYGROUP to some numerical group-id if you do not want the
+ * tty to be in "your" group.
+ * Note, screen is unable to change mode or group of the pty if it
+ * is not installed with sufficient privilege. (e.g. set-uid-root)
+ */
+#undef PTYMODE
+#undef PTYGROUP
+
+/*
+ * If screen is NOT installed set-uid root, screen can provide tty
+ * security by exclusively locking the ptys. While this keeps other
+ * users from opening your ptys, it also keeps your own subprocesses
+ * from being able to open /dev/tty. Define LOCKPTY to add this
+ * exclusive locking.
+ */
+#undef LOCKPTY
+
+/*
+ * If you'd rather see the status line on the first line of your
+ * terminal rather than the last, define TOPSTAT.
+ */
+#undef TOPSTAT
+
+/*
+ * here come the erlangen extensions to screen:
+ * define LOCK if you want to use a lock program for a screenlock.
+ * define PASSWORD for secure reattach of your screen.
+ * define COPY_PASTE to use the famous hacker's treasure zoo.
+ * define POW_DETACH to have a detach_and_logout key.
+ * define REMOTE_DETACH (-d option) to move screen between terminals.
+ * define AUTO_NUKE to enable Tim MacKenzies clear screen nuking
+ * define PSEUDOS to allow window input/output filtering
+ * define MULTI to allow multiple attaches.
+ * define MULTIUSER to allow other users attach to your session
+ * (if they are in the acl, of course)
+ * (jw)
+ */
+#undef SIMPLESCREEN
+#ifndef SIMPLESCREEN
+# define LOCK
+# define PASSWORD
+# define COPY_PASTE
+# define REMOTE_DETACH
+# define POW_DETACH
+# define AUTO_NUKE
+# define PSEUDOS
+# define MULTI
+# define MULTIUSER
+# define MAPKEYS
+# define COLOR
+#endif /* SIMPLESCREEN */
+#define KANJI
+
+/*
+ * As error messages are mostly meaningless to the user, we
+ * try to throw out phrases that are somewhat more familiar
+ * to ...well, at least familiar to us NetHack players.
+ */
+#ifndef NONETHACK
+# define NETHACK
+#endif /* NONETHACK */
+
+/*
+ * If screen is installed with permissions to update /etc/utmp (such
+ * as if it is installed set-uid root), define UTMPOK.
+ */
+#define UTMPOK
+
+/* Set LOGINDEFAULT to one (1)
+ * if you want entries added to /etc/utmp by default, else set it to
+ * zero (0).
+ * LOGINDEFAULT will be one (1) whenever LOGOUTOK is undefined!
+ */
+#define LOGINDEFAULT 1
+
+/* Set LOGOUTOK to one (1)
+ * if you want the user to be able to log her/his windows out.
+ * (Meaning: They are there, but not visible in /etc/utmp).
+ * Disabling this feature only makes sense if you have a secure /etc/utmp
+ * database.
+ * Negative examples: suns usually have a world writable utmp file,
+ * xterm and script will run perfectly without s-bit.
+ * If LOGOUTOK is undefined and UTMPOK is defined, all windows are initially
+ * and permanently logged in.
+ */
+#define LOGOUTOK 1
+
+
+/*
+ * If UTMPOK is defined and your system (incorrectly) counts logins by
+ * counting non-null entries in /etc/utmp (instead of counting non-null
+ * entries with no hostname that are not on a pseudo tty), define USRLIMIT
+ * to have screen put an upper-limit on the number of entries to write
+ * into /etc/utmp. This helps to keep you from exceeding a limited-user
+ * license.
+ */
+#undef USRLIMIT
+
+
+/*
+ * Some terminals, e.g. Wyse 120, use a bitfield to select attributes.
+ * This doesn't work with the standard so/ul/m? terminal entries,
+ * because they will cancel each other out.
+ * On TERMINFO machines, "sa" (sgr) may work. If you want screen
+ * to switch attributes only with sgr, define USE_SGR.
+ * This is *not* recomended, do this only if you must.
+ */
+#undef USE_SGR
+
+
+/**********************************************************************
+ *
+ * End of User Configuration Section
+ *
+ * Rest of this file is modified by 'configure'
+ * Change at your own risk!
+ *
+ */
+
+/*
+ * Some defines to identify special unix variants
+ */
+#ifndef SVR4
+#undef SVR4
+#endif
+
+/* #ifndef __osf__ */
+#ifndef MIPS
+#undef MIPS
+#endif
+/* #endif */
+
+#ifndef OSX
+#undef OSX
+#endif
+
+#ifndef ISC
+#undef ISC
+#endif
+
+#ifndef sysV68
+#undef sysV68
+#endif
+
+#ifndef _POSIX_SOURCE
+#undef _POSIX_SOURCE
+#endif
+
+/*
+ * Define POSIX if your system supports IEEE Std 1003.1-1988 (POSIX).
+ */
+#undef POSIX
+
+/*
+ * Define BSDJOBS if you have BSD-style job control (both process
+ * groups and a tty that deals correctly with them).
+ */
+#undef BSDJOBS
+
+/*
+ * Define TERMIO if you have struct termio instead of struct sgttyb.
+ * This is usually the case for SVID systems, where BSD uses sgttyb.
+ * POSIX systems should define this anyway, even though they use
+ * struct termios.
+ */
+#undef TERMIO
+
+/*
+ * Define CYTERMIO if you have cyrillic termio modes.
+ */
+#undef CYTERMIO
+
+/*
+ * Define TERMINFO if your machine emulates the termcap routines
+ * with the terminfo database.
+ * Thus the .screenrc file is parsed for
+ * the command 'terminfo' and not 'termcap'.
+ */
+#undef TERMINFO
+
+/*
+ * If your library does not define ospeed, define this.
+ */
+#undef NEED_OSPEED
+
+/*
+ * Define SYSV if your machine is SYSV complient (Sys V, HPUX, A/UX)
+ */
+#ifndef SYSV
+#undef SYSV
+#endif
+
+/*
+ * Define SIGVOID if your signal handlers return void. On older
+ * systems, signal returns int, but on newer ones, it returns void.
+ */
+#undef SIGVOID
+
+/*
+ * Define USESIGSET if you have sigset for BSD 4.1 reliable signals.
+ */
+#undef USESIGSET
+
+/*
+ * Define SYSVSIGS if signal handlers must be reinstalled after
+ * they have been called.
+ */
+#undef SYSVSIGS
+
+/*
+ * Define BSDWAIT if your system defines a 'union wait' in <sys/wait.h>
+ *
+ * Only allow BSDWAIT i.e. wait3 on nonposix systems, since
+ * posix implies wait(3) and waitpid(3). vdlinden@fwi.uva.nl
+ *
+ */
+#ifndef POSIX
+#undef BSDWAIT
+#endif
+
+/*
+ * On RISCOS we prefer wait2() over wait3(). rouilj@sni-usa.com
+ */
+#ifdef BSDWAIT
+#undef USE_WAIT2
+#endif
+
+/*
+ * Define DIRENT if your system has <dirent.h> instead of <sys/dir.h>
+ */
+#undef DIRENT
+
+/*
+ * If your system has getutent(), pututline(), etc. to write to the
+ * utmp file, define GETUTENT.
+ */
+#undef GETUTENT
+
+/*
+ * Define UTHOST if the utmp file has a host field.
+ */
+#undef UTHOST
+
+/*
+ * If ttyslot() breaks getlogin() by returning indexes to utmp entries
+ * of type DEAD_PROCESS, then our getlogin() replacement should be
+ * selected by defining BUGGYGETLOGIN.
+ */
+#undef BUGGYGETLOGIN
+
+/*
+ * If your system has the calls setreuid() and setregid(),
+ * define HAVE_SETREUID. Otherwise screen will use a forked process to
+ * safely create output files without retaining any special privileges.
+ * (Output logging will be disabled, however.)
+ */
+#undef HAVE_SETREUID
+
+/*
+ * If your system supports BSD4.4's seteuid() and setegid(), define
+ * HAVE_SETEUID.
+ */
+#undef HAVE_SETEUID
+
+/*
+ * If you want the "time" command to display the current load average
+ * define LOADAV. Maybe you must install screen with the needed
+ * privileges to read /dev/kmem.
+ * Note that NLIST_ stuff is only checked, when getloadavg() is not available.
+ */
+#undef LOADAV
+
+#undef LOADAV_NUM
+#undef LOADAV_TYPE
+#undef LOADAV_SCALE
+#undef LOADAV_GETLOADAVG
+#undef LOADAV_UNIX
+#undef LOADAV_AVENRUN
+
+#undef NLIST_DECLARED
+#undef NLIST_STRUCT
+#undef NLIST_NAME_UNION
+
+/*
+ * If your system has the new format /etc/ttys (like 4.3 BSD) and the
+ * getttyent(3) library functions, define GETTTYENT.
+ */
+#undef GETTTYENT
+
+/*
+ * Define USEBCOPY if the bcopy/memcpy from your system's C library
+ * supports the overlapping of source and destination blocks. When
+ * undefined, screen uses its own (probably slower) version of bcopy().
+ *
+ * SYSV machines may have a working memcpy() -- Oh, this is
+ * quite unlikely. Tell me if you see one. (Juergen)
+ * But then, memmove() should work, if at all available.
+ */
+#undef USEBCOPY
+#undef USEMEMCPY
+#undef USEMEMMOVE
+
+/*
+ * If your system has vsprintf() and requires the use of the macros in
+ * "varargs.h" to use functions with variable arguments,
+ * define USEVARARGS.
+ */
+#undef USEVARARGS
+
+/*
+ * If your system has strerror() define this.
+ */
+#undef HAVE_STRERROR
+
+/*
+ * If the select return value doesn't treat a descriptor that is
+ * usable for reading and writing as two hits, define SELECT_BROKEN.
+ */
+#undef SELECT_BROKEN
+
+/*
+ * Define this if your system supports named pipes.
+ */
+#undef NAMEDPIPE
+
+/*
+ * Define this if your system exits select() immediatly if a pipe is
+ * opened read-only and no writer has opened it.
+ */
+#undef BROKEN_PIPE
+
+/*
+ * Define this if the unix-domain socket implementation doesn't
+ * create a socket in the filesystem.
+ */
+#undef SOCK_NOT_IN_FS
+
+/*
+ * If your system has setenv() and unsetenv() define USESETENV
+ */
+#undef USESETENV
+
+/*
+ * If your system does not come with a setenv()/putenv()/getenv()
+ * functions, you may bring in our own code by defining NEEDPUTENV.
+ */
+#undef NEEDPUTENV
+
+/*
+ * If the passwords are stored in a shadow file and you want the
+ * builtin lock to work properly, define SHADOWPW.
+ */
+#undef SHADOWPW
+
+/*
+ * If you are on a SYS V machine that restricts filename length to 14
+ * characters, you may need to enforce that by setting NAME_MAX to 14
+ */
+#undef NAME_MAX /* KEEP_UNDEF_HERE override system value */
+#undef NAME_MAX
+
+/*
+ * define NEED_RENAME if your system doesn't have a rename() function
+ */
+#undef NEED_RENAME
+
+/*
+ * define HAVE__EXIT if your system has the _exit() call.
+ */
+#undef HAVE__EXIT
+
+/*
+ * define HAVE_LSTAT if your system has symlinks and the lstat() call.
+ */
+#undef HAVE_LSTAT
+
+/*
+ * define HAVE_DEV_PTC if you have a /dev/ptc character special
+ * device.
+ */
+#undef HAVE_DEV_PTC
+
+/*
+ * define PTYRANGE0 and or PTYRANGE1 if you want to adapt screen
+ * to unusual environments. E.g. For SunOs the defaults are "qpr" and
+ * "0123456789abcdef". For SunOs 4.1.2
+ * #define PTYRANGE0 "pqrstuvwxyzPQRST"
+ * is recommended by Dan Jacobson.
+ */
+#undef PTYRANGE0
+#undef PTYRANGE1
+
diff --git a/configure b/configure
new file mode 100755
index 0000000..4ab7d58
--- /dev/null
+++ b/configure
@@ -0,0 +1,3257 @@
+#!/bin/sh
+# From configure.in Revision: 1.17
+#!/bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 1.11
+# Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+# This configure script is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as published
+# by the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This script is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Save the original args to write them into config.status later.
+configure_args="$*"
+
+# Only options that might do something get documented.
+ac_usage="Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+--build=BUILD configure for building on BUILD [BUILD=HOST]
+--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+--exec-prefix=PREFIX install host dependent files in PREFIX [/usr/local]
+--help print this message
+--host=HOST configure for HOST [guessed]
+--prefix=PREFIX install host independent files in PREFIX [/usr/local]
+--quiet, --silent do not print \`checking for...' messages
+--srcdir=DIR find the sources in DIR [configure dir or ..]
+--target=TARGET configure for TARGET [TARGET=HOST]
+--verbose print results of checks
+--version print the version of autoconf that created configure
+--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+--x-includes=DIR X include files are in DIR
+--x-libraries=DIR X library files are in DIR"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+exec_prefix=
+host=NONE
+no_create=
+nonopt=NONE
+norecursion=
+prefix=
+program_prefix=
+program_suffix=
+program_transform_name=
+silent=
+srcdir=
+target=NONE
+verbose=
+x_includes=
+x_libraries=
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ # Accept (but ignore some of) the important Cygnus configure
+ # options, so we can diagnose typos.
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ case "$ac_option" in
+
+ -build | --build | --buil | --bui | --bu | --b)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=* | --b=*)
+ build="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that aren't valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ echo "configure: $ac_feature: invalid feature name" >&2; exit 1
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that aren't valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ echo "configure: $ac_feature: invalid feature name" >&2; exit 1
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ # For backward compatibility, recognize -exec-prefix and --exec_prefix.
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ with_gas=yes ;; # Obsolete; use --with-gas.
+
+ -help | --help | --hel | --he)
+ cat << EOF
+$ac_usage
+EOF
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ with_fp=no ;; # Obsolete; use --without-fp.
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -norecursion | --norecursion | --norecursio | --norecursi \
+ | --norecurs | --norecur | --norecu | --norec | --nore | --nor)
+ norecursion=yes ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 1.11"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that aren't valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ echo "configure: $ac_package: invalid package name" >&2; exit 1
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that aren't valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ echo "configure: $ac_package: invalid package name" >&2; exit 1
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x) with_x=yes ;; # Obsolete; use --with-x.
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) echo "configure: $ac_option: invalid option; use --help to show usage" >&2; exit 1
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" >&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ echo "configure: can only configure for one host and one target at a time" >&2; exit 1
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ echo "configure: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" >&2; exit 1
+fi
+
+trap 'rm -fr conftest* confdefs* core $ac_clean_files; exit 1' 1 2 15
+trap 'rm -fr confdefs* $ac_clean_files' 0
+
+# Save the original args if we used an alternate arg parser.
+ac_configure_temp="${configure_args-$*}"
+# Strip out --no-create and --norecursion so they don't pile up.
+configure_args=
+for ac_arg in $ac_configure_temp; do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -norecursion | --norecursion | --norecursio | --norecursi \
+ | --norecurs | --norecur | --norecu | --norec | --nore | --nor) ;;
+ *) configure_args="$configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+if test "${LC_ALL+set}" = 'set'; then LC_ALL=C; export LC_ALL; fi
+if test "${LANG+set}" = 'set'; then LANG=C; export LANG; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=screen.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then `..'.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test x$ac_srcdir_defaulted = xyes; then
+ echo "configure: can not find sources in ${ac_confdir} or .." >&2; exit 1
+ else
+ echo "configure: can not find sources in ${srcdir}" >&2; exit 1
+ fi
+fi
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='${CPP}'
+ac_compile='${CC-cc} $CFLAGS $LDFLAGS conftest.${ac_ext} -o conftest $LIBS >/dev/null 2>&1'
+
+
+
+
+
+rev=`sed < ${srcdir}/patchlevel.h -n -e '/#define REV/s/#define REV *//p'`
+vers=`sed < ${srcdir}/patchlevel.h -n -e '/#define VERS/s/#define VERS *//p'`
+pat=`sed < ${srcdir}/patchlevel.h -n -e '/#define PATCHLEVEL/s/#define PATCHLEVEL *//p'`
+VERSION="$rev.$vers.$pat"
+test -n "$silent" || echo "this is screen version $VERSION"
+
+if test -z "$prefix"
+then
+ test -n "$silent" || echo "checking for gzip to derive installation directory prefix"
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="$IFS:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test $ac_dir != . && test -f $ac_dir/gzip; then
+ # Not all systems have dirname.
+ prefix=`echo $ac_dir|sed 's%/[^/][^/]*$%%'`
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -n "$verbose" && echo " chose installation directory prefix ${prefix}"
+fi
+
+
+if test -z "$CC"; then
+ # Extract the first word of `gcc', so it can be a program name with args.
+ set ac_dummy gcc; ac_word=$2
+ test -n "$silent" || echo "checking for $ac_word"
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+test -z "$CC" && CC="cc"
+test -n "$CC" && test -n "$verbose" && echo " setting CC to $CC"
+
+# Find out if we are using GNU C, under whatever name.
+cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes
+#endif
+EOF
+${CC-cc} -E conftest.c > conftest.out 2>&1
+if egrep yes conftest.out >/dev/null 2>&1; then
+ GCC=1 # For later tests.
+fi
+rm -f conftest*
+
+test -n "$silent" || echo "checking how to run the C preprocessor"
+if test -z "$CPP"; then
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and ``${CC-cc}'' will simply confuse
+ # make. It must be expanded now.
+ CPP="${CC-cc} -E"
+ cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <stdio.h>
+Syntax Error
+EOF
+# Some shells (Coherent) do redirections in the wrong order, so need
+# the parens.
+ac_err=`eval "($ac_cpp conftest.${ac_ext} >/dev/null) 2>&1"`
+if test -z "$ac_err"; then
+ :
+else
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <stdio.h>
+Syntax Error
+EOF
+# Some shells (Coherent) do redirections in the wrong order, so need
+# the parens.
+ac_err=`eval "($ac_cpp conftest.${ac_ext} >/dev/null) 2>&1"`
+if test -z "$ac_err"; then
+ :
+else
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+test -n "$verbose" && echo " setting CPP to $CPP"
+
+if test -n "$GCC"; then
+ test -n "$silent" || echo "checking whether -traditional is needed"
+ ac_pattern="Autoconf.*'x'"
+ ac_prog='#include <sgtty.h>
+Autoconf TIOCGETP'
+ cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+$ac_prog
+EOF
+eval "$ac_cpp conftest.${ac_ext} > conftest.out 2>&1"
+if egrep "$ac_pattern" conftest.out >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_need_trad=1
+
+fi
+rm -f conftest*
+
+
+ if test -z "$ac_need_trad"; then
+ ac_prog='#include <termio.h>
+Autoconf TCGETA'
+ cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+$ac_prog
+EOF
+eval "$ac_cpp conftest.${ac_ext} > conftest.out 2>&1"
+if egrep "$ac_pattern" conftest.out >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_need_trad=1
+
+fi
+rm -f conftest*
+
+ fi
+ test -n "$ac_need_trad" && CC="$CC -traditional"
+fi
+
+test -n "$silent" || echo "checking for POSIXized ISC"
+if test -d /etc/conf/kconfig.d &&
+ grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
+then
+ ISC=1 # If later tests want to check for ISC.
+
+{
+test -n "$verbose" && \
+echo " defining _POSIX_SOURCE"
+echo "#define" _POSIX_SOURCE "1" >> confdefs.h
+DEFS="$DEFS -D_POSIX_SOURCE=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}_POSIX_SOURCE\${ac_dB}_POSIX_SOURCE\${ac_dC}1\${ac_dD}
+\${ac_uA}_POSIX_SOURCE\${ac_uB}_POSIX_SOURCE\${ac_uC}1\${ac_uD}
+\${ac_eA}_POSIX_SOURCE\${ac_eB}_POSIX_SOURCE\${ac_eC}1\${ac_eD}
+"
+}
+
+ if test -n "$GCC"; then
+ CC="$CC -posix"
+ else
+ CC="$CC -Xp"
+ fi
+fi
+
+
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+main(){exit(0);}
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ :
+else
+ echo "configure: Can't run the compiler - sorry" >&2; exit 1
+fi
+rm -fr conftest*
+
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+main()
+{
+ int __something_strange_();
+ __something_strange_(0);
+}
+
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ echo "configure: Your compiler does not set the exit status - sorry" >&2; exit 1
+
+fi
+rm -fr conftest*
+
+for ac_prog in mawk gawk nawk awk
+do
+if test -z "$AWK"; then
+ # Extract the first word of `$ac_prog', so it can be a program name with args.
+ set ac_dummy $ac_prog; ac_word=$2
+ test -n "$silent" || echo "checking for $ac_word"
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ AWK="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+
+test -n "$AWK" && test -n "$verbose" && echo " setting AWK to $AWK"
+
+test -n "$AWK" && break
+done
+
+
+# Make sure to not get the incompatible SysV /etc/install and
+# /usr/sbin/install, which might be in PATH before a BSD-like install,
+# or the SunOS /usr/etc/install directory, or the AIX /bin/install,
+# or the AFS install, which mishandles nonexistent args, or
+# /usr/ucb/install on SVR4, which tries to use the nonexistent group
+# `staff', or /sbin/install on IRIX which has incompatible command-line
+# syntax. Sigh.
+#
+# On most BSDish systems install is in /usr/bin, not /usr/ucb
+# anyway.
+# This turns out not to be true, so the mere pathname isn't an indication
+# of whether the program works. What we really need is a set of tests for
+# the install program to see if it actually works in all the required ways.
+#
+# Avoid using ./install, which might have been erroneously created
+# by make from ./install.sh.
+if test -z "${INSTALL}"; then
+ test -n "$silent" || echo "checking for a BSD compatible install"
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ case "$ac_dir" in
+ ''|.|/etc|/sbin|/usr/sbin|/usr/etc|/usr/afsws/bin|/usr/ucb) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ for ac_prog in installbsd scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ # OSF/1 installbsd also uses dspmsg, but is usable.
+ :
+ else
+ INSTALL="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_ifs"
+fi
+
+if test -z "$INSTALL"; then
+ # As a last resort, use the slow shell script.
+ for ac_dir in ${srcdir} ${srcdir}/.. ${srcdir}/../..; do
+ if test -f $ac_dir/install.sh; then
+ INSTALL="$ac_dir/install.sh -c"; break
+ fi
+ done
+fi
+if test -z "$INSTALL"; then
+ echo "configure: can not find install.sh in ${srcdir} or ${srcdir}/.. or ${srcdir}/../.." >&2; exit 1
+fi
+test -n "$verbose" && echo " setting INSTALL to $INSTALL"
+
+# Use test -z because SunOS4 sh mishandles ${INSTALL_PROGRAM-'${INSTALL}'}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+test -n "$verbose" && echo " setting INSTALL_PROGRAM to $INSTALL_PROGRAM"
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+test -n "$verbose" && echo " setting INSTALL_DATA to $INSTALL_DATA"
+
+
+if test -f etc/toolcheck; then
+test -n "$silent" || echo "checking for buggy tools"
+sh etc/toolcheck
+fi
+
+if test -n "$ISC"; then
+
+{
+test -n "$verbose" && \
+echo " defining ISC"
+echo "#define" ISC "1" >> confdefs.h
+DEFS="$DEFS -DISC=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}ISC\${ac_dB}ISC\${ac_dC}1\${ac_dD}
+\${ac_uA}ISC\${ac_uB}ISC\${ac_uC}1\${ac_uD}
+\${ac_eA}ISC\${ac_eB}ISC\${ac_eC}1\${ac_eD}
+"
+}
+ LIBS="$LIBS -linet"
+fi
+
+
+if test -f /sysV68 ; then
+
+{
+test -n "$verbose" && \
+echo " defining sysV68"
+echo "#define" sysV68 "1" >> confdefs.h
+DEFS="$DEFS -DsysV68=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}sysV68\${ac_dB}sysV68\${ac_dC}1\${ac_dD}
+\${ac_uA}sysV68\${ac_uB}sysV68\${ac_uC}1\${ac_uD}
+\${ac_eA}sysV68\${ac_eB}sysV68\${ac_eC}1\${ac_eD}
+"
+}
+
+fi
+
+test -n "$silent" || echo "checking for MIPS"
+if test -f /lib/libmld.a || test -f /usr/lib/libmld.a || test -f /usr/lib/cmplrs/cc/libmld.a; then
+test -f /bin/mx || LIBS="$LIBS -lmld" # for nlist. But not on alpha.
+if test -r /dev/ptc; then
+
+{
+test -n "$verbose" && \
+echo " defining MIPS"
+echo "#define" MIPS "1" >> confdefs.h
+DEFS="$DEFS -DMIPS=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}MIPS\${ac_dB}MIPS\${ac_dC}1\${ac_dD}
+\${ac_uA}MIPS\${ac_uB}MIPS\${ac_uC}1\${ac_uD}
+\${ac_eA}MIPS\${ac_eB}MIPS\${ac_eC}1\${ac_eD}
+"
+}
+
+test -n "$silent" || echo "checking for wait3"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { wait3();; return 0; }
+EOF
+if eval $ac_compile; then
+ :
+else
+ rm -rf conftest*
+ test -n "$silent" || echo "checking for wait2"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { wait2();; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining USE_WAIT2"
+echo "#define" USE_WAIT2 "1" >> confdefs.h
+DEFS="$DEFS -DUSE_WAIT2=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}USE_WAIT2\${ac_dB}USE_WAIT2\${ac_dC}1\${ac_dD}
+\${ac_uA}USE_WAIT2\${ac_uB}USE_WAIT2\${ac_uC}1\${ac_uD}
+\${ac_eA}USE_WAIT2\${ac_eB}USE_WAIT2\${ac_eC}1\${ac_eD}
+"
+}
+ LIBS="$LIBS -lbsd" ; CC="$CC -I/usr/include/bsd"
+
+
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+fi
+fi
+
+test -n "$silent" || echo "checking for Ultrix"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#if defined(ultrix) || defined(__ultrix)
+ yes
+#endif
+
+EOF
+eval "$ac_cpp conftest.${ac_ext} > conftest.out 2>&1"
+if egrep "yes" conftest.out >/dev/null 2>&1; then
+ rm -rf conftest*
+ ULTRIX=1
+
+fi
+rm -f conftest*
+
+
+if test -f /usr/lib/libpyr.a ; then
+oldlibs="$LIBS"
+LIBS="$LIBS -lpyr"
+test -n "$silent" || echo "checking for Pyramid OSX"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { open_controlling_pty("");; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining OSX"
+echo "#define" OSX "1" >> confdefs.h
+DEFS="$DEFS -DOSX=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}OSX\${ac_dB}OSX\${ac_dC}1\${ac_dD}
+\${ac_uA}OSX\${ac_uB}OSX\${ac_uC}1\${ac_uD}
+\${ac_eA}OSX\${ac_eB}OSX\${ac_eC}1\${ac_eD}
+"
+}
+
+
+else
+ rm -rf conftest*
+ LIBS="oldlibs"
+fi
+rm -f conftest*
+
+fi
+
+test -n "$silent" || echo "checking for butterfly"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#if defined(butterfly)
+ yes
+#endif
+
+EOF
+eval "$ac_cpp conftest.${ac_ext} > conftest.out 2>&1"
+if egrep "yes" conftest.out >/dev/null 2>&1; then
+ rm -rf conftest*
+ butterfly=1
+
+fi
+rm -f conftest*
+
+
+if test -z "$butterfly"; then
+if test -n "$ULTRIX"; then
+ test -z "$GCC" && CC="$CC -YBSD"
+fi
+test -n "$silent" || echo "checking for POSIX.1"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <sys/types.h>
+#include <unistd.h>
+main () {
+#ifdef _POSIX_VERSION
+ yes
+#endif
+
+EOF
+eval "$ac_cpp conftest.${ac_ext} > conftest.out 2>&1"
+if egrep "yes" conftest.out >/dev/null 2>&1; then
+ rm -rf conftest*
+ test -n "$silent" || echo "- you have a POSIX system"
+{
+test -n "$verbose" && \
+echo " defining POSIX"
+echo "#define" POSIX "1" >> confdefs.h
+DEFS="$DEFS -DPOSIX=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}POSIX\${ac_dB}POSIX\${ac_dC}1\${ac_dD}
+\${ac_uA}POSIX\${ac_uB}POSIX\${ac_uC}1\${ac_uD}
+\${ac_eA}POSIX\${ac_eB}POSIX\${ac_eC}1\${ac_eD}
+"
+}
+ posix=1
+
+fi
+rm -f conftest*
+
+fi
+
+test -n "$silent" || echo "checking for System V"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#include <fcntl.h>
+int main() { return 0; }
+int t() { int x = SIGCHLD | FNDELAY;; return 0; }
+EOF
+if eval $ac_compile; then
+ :
+else
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining SYSV"
+echo "#define" SYSV "1" >> confdefs.h
+DEFS="$DEFS -DSYSV=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}SYSV\${ac_dB}SYSV\${ac_dC}1\${ac_dD}
+\${ac_uA}SYSV\${ac_uB}SYSV\${ac_uC}1\${ac_uD}
+\${ac_eA}SYSV\${ac_eB}SYSV\${ac_eC}1\${ac_eD}
+"
+}
+
+fi
+rm -f conftest*
+
+
+test -n "$silent" || echo "checking for sequent/ptx"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#ifdef _SEQUENT_
+ yes
+#endif
+
+EOF
+eval "$ac_cpp conftest.${ac_ext} > conftest.out 2>&1"
+if egrep "yes" conftest.out >/dev/null 2>&1; then
+ rm -rf conftest*
+ LIBS="$LIBS -lsocket -linet";seqptx=1
+
+fi
+rm -f conftest*
+
+
+oldlibs="$LIBS"
+LIBS="$LIBS -lelf"
+test -n "$silent" || echo "checking for SVR4"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <utmpx.h>
+
+int main() { return 0; }
+int t() { ; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ test -n "$silent" || echo "checking for dwarf.h"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <dwarf.h>
+EOF
+# Some shells (Coherent) do redirections in the wrong order, so need
+# the parens.
+ac_err=`eval "($ac_cpp conftest.${ac_ext} >/dev/null) 2>&1"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining SVR4"
+echo "#define" SVR4 "1" >> confdefs.h
+DEFS="$DEFS -DSVR4=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}SVR4\${ac_dB}SVR4\${ac_dC}1\${ac_dD}
+\${ac_uA}SVR4\${ac_uB}SVR4\${ac_uC}1\${ac_uD}
+\${ac_eA}SVR4\${ac_eB}SVR4\${ac_eC}1\${ac_eD}
+"
+}
+
+{
+test -n "$verbose" && \
+echo " defining BUGGYGETLOGIN"
+echo "#define" BUGGYGETLOGIN "1" >> confdefs.h
+DEFS="$DEFS -DBUGGYGETLOGIN=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}BUGGYGETLOGIN\${ac_dB}BUGGYGETLOGIN\${ac_dC}1\${ac_dD}
+\${ac_uA}BUGGYGETLOGIN\${ac_uB}BUGGYGETLOGIN\${ac_uC}1\${ac_uD}
+\${ac_eA}BUGGYGETLOGIN\${ac_eB}BUGGYGETLOGIN\${ac_eC}1\${ac_eD}
+"
+}
+
+
+else
+ rm -rf conftest*
+ test -n "$silent" || echo "checking for elf.h"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <elf.h>
+EOF
+# Some shells (Coherent) do redirections in the wrong order, so need
+# the parens.
+ac_err=`eval "($ac_cpp conftest.${ac_ext} >/dev/null) 2>&1"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining SVR4"
+echo "#define" SVR4 "1" >> confdefs.h
+DEFS="$DEFS -DSVR4=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}SVR4\${ac_dB}SVR4\${ac_dC}1\${ac_dD}
+\${ac_uA}SVR4\${ac_uB}SVR4\${ac_uC}1\${ac_uD}
+\${ac_eA}SVR4\${ac_eB}SVR4\${ac_eC}1\${ac_eD}
+"
+}
+
+{
+test -n "$verbose" && \
+echo " defining BUGGYGETLOGIN"
+echo "#define" BUGGYGETLOGIN "1" >> confdefs.h
+DEFS="$DEFS -DBUGGYGETLOGIN=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}BUGGYGETLOGIN\${ac_dB}BUGGYGETLOGIN\${ac_dC}1\${ac_dD}
+\${ac_uA}BUGGYGETLOGIN\${ac_uB}BUGGYGETLOGIN\${ac_uC}1\${ac_uD}
+\${ac_eA}BUGGYGETLOGIN\${ac_eB}BUGGYGETLOGIN\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+
+
+else
+ rm -rf conftest*
+ LIBS="$oldlibs"
+fi
+rm -f conftest*
+
+
+
+
+
+test -n "$silent" || echo "checking for BSD job control"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+int main() { return 0; }
+int t() {
+#ifdef POSIX
+tcsetpgrp(0, 0);
+#else
+int x = TIOCSPGRP;
+#ifdef SYSV
+setpgrp();
+#else
+int y = TIOCNOTTY;
+#endif
+#endif
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ test -n "$silent" || echo "- you have jobcontrol"
+{
+test -n "$verbose" && \
+echo " defining BSDJOBS"
+echo "#define" BSDJOBS "1" >> confdefs.h
+DEFS="$DEFS -DBSDJOBS=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}BSDJOBS\${ac_dB}BSDJOBS\${ac_dC}1\${ac_dD}
+\${ac_uA}BSDJOBS\${ac_uB}BSDJOBS\${ac_uC}1\${ac_uD}
+\${ac_eA}BSDJOBS\${ac_eB}BSDJOBS\${ac_eC}1\${ac_eD}
+"
+}
+
+
+else
+ rm -rf conftest*
+ test -n "$silent" || echo "- you don't have jobcontrol"
+fi
+rm -f conftest*
+
+
+test -n "$silent" || echo "checking for setreuid"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+#ifdef __hpux
+setresuid(0, 0, 0);
+#else
+setreuid(0, 0);
+#endif
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining HAVE_SETREUID"
+echo "#define" HAVE_SETREUID "1" >> confdefs.h
+DEFS="$DEFS -DHAVE_SETREUID=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}HAVE_SETREUID\${ac_dB}HAVE_SETREUID\${ac_dC}1\${ac_dD}
+\${ac_uA}HAVE_SETREUID\${ac_uB}HAVE_SETREUID\${ac_uC}1\${ac_uD}
+\${ac_eA}HAVE_SETREUID\${ac_eB}HAVE_SETREUID\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+test -n "$silent" || echo "checking for seteuid"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+#if defined(linux) || defined(NeXT) || defined(_AUX_SOURCE) || defined(AUX) || defined(ultrix) || (defined(sun) && defined(SVR4)) || defined(ISC) || defined(sony_news)
+seteuid_is_broken(0);
+#else
+seteuid(0);
+#endif
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining HAVE_SETEUID"
+echo "#define" HAVE_SETEUID "1" >> confdefs.h
+DEFS="$DEFS -DHAVE_SETEUID=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}HAVE_SETEUID\${ac_dB}HAVE_SETEUID\${ac_dC}1\${ac_dD}
+\${ac_uA}HAVE_SETEUID\${ac_uB}HAVE_SETEUID\${ac_uC}1\${ac_uD}
+\${ac_eA}HAVE_SETEUID\${ac_eB}HAVE_SETEUID\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+
+test -n "$silent" || echo "checking for select"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { select(0, 0, 0, 0, 0);; return 0; }
+EOF
+if eval $ac_compile; then
+ :
+else
+ rm -rf conftest*
+ LIBS="$LIBS -lnet -lnsl"
+test -n "$silent" || echo "checking for select with $LIBS"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { select(0, 0, 0, 0, 0);; return 0; }
+EOF
+if eval $ac_compile; then
+ :
+else
+ rm -rf conftest*
+ echo "configure: !!! no select - no screen" >&2; exit 1
+fi
+rm -f conftest*
+
+
+fi
+rm -f conftest*
+
+
+test -n "$silent" || echo "checking fifos"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+#ifndef S_IFIFO
+#define S_IFIFO 0010000
+#endif
+
+char *fin = "/tmp/conftest$$";
+
+main()
+{
+ struct stat stb;
+ int f;
+
+ (void)alarm(5);
+#ifdef POSIX
+ if (mkfifo(fin, 0777))
+#else
+ if (mknod(fin, S_IFIFO|0777, 0))
+#endif
+ exit(1);
+ if (stat(fin, &stb) || (stb.st_mode & S_IFIFO) != S_IFIFO)
+ exit(1);
+ close(0);
+#ifdef __386BSD__
+ /*
+ * The next test fails under 386BSD, but screen works using fifos.
+ * Fifos in O_RDWR mode are only used for the BROKEN_PIPE case and for
+ * the select() configuration test.
+ */
+ exit(0);
+#endif
+ if (open(fin, O_RDONLY | O_NONBLOCK))
+ exit(1);
+ if (fork() == 0)
+ {
+ close(0);
+ if (open(fin, O_WRONLY | O_NONBLOCK))
+ exit(1);
+ close(0);
+ if (open(fin, O_WRONLY | O_NONBLOCK))
+ exit(1);
+ if (write(0, "TEST", 4) == -1)
+ exit(1);
+ exit(0);
+ }
+ f = 1;
+ if (select(1, &f, 0, 0, 0) == -1)
+ exit(1);
+ exit(0);
+}
+
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ test -n "$silent" || echo "- your fifos are usable";fifo=1
+
+else
+ test -n "$silent" || echo "- your fifos are not usable"
+fi
+rm -fr conftest*
+rm -f /tmp/conftest*
+
+if test -n "$fifo"; then
+test -n "$silent" || echo "checking for broken fifo implementation"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+#ifndef S_IFIFO
+#define S_IFIFO 0010000
+#endif
+
+char *fin = "/tmp/conftest$$";
+
+main()
+{
+ struct timeval tv;
+ int r, x;
+
+#ifdef POSIX
+ if (mkfifo(fin, 0600))
+#else
+ if (mknod(fin, S_IFIFO|0600, 0))
+#endif
+ exit(1);
+ close(0);
+ if (open(fin, O_RDONLY|O_NONBLOCK))
+ exit(1);
+ r = 1;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ if (select(1, &r, 0, 0, &tv))
+ exit(1);
+ exit(0);
+}
+
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ test -n "$silent" || echo "- your implementation is ok"
+
+else
+ test -n "$silent" || echo "- you have a broken implementation"
+{
+test -n "$verbose" && \
+echo " defining BROKEN_PIPE"
+echo "#define" BROKEN_PIPE "1" >> confdefs.h
+DEFS="$DEFS -DBROKEN_PIPE=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}BROKEN_PIPE\${ac_dB}BROKEN_PIPE\${ac_dC}1\${ac_dD}
+\${ac_uA}BROKEN_PIPE\${ac_uB}BROKEN_PIPE\${ac_uC}1\${ac_uD}
+\${ac_eA}BROKEN_PIPE\${ac_eB}BROKEN_PIPE\${ac_eC}1\${ac_eD}
+"
+}
+ fifobr=1
+fi
+rm -fr conftest*
+rm -f /tmp/conftest*
+fi
+
+
+test -n "$silent" || echo "checking sockets"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
+
+char *son = "/tmp/conftest$$";
+
+main()
+{
+ int s1, s2, s3, l;
+ struct sockaddr_un a;
+
+ (void)alarm(5);
+ if ((s1 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ exit(1);
+ a.sun_family = AF_UNIX;
+ strcpy(a.sun_path, son);
+ (void) unlink(son);
+ if (bind(s1, (struct sockaddr *) &a, strlen(son)+2) == -1)
+ exit(1);
+ if (listen(s1, 2))
+ exit(1);
+ if (fork() == 0)
+ {
+ if ((s2 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ kill(getppid(), 3);
+ (void)connect(s2, (struct sockaddr *)&a, strlen(son) + 2);
+ if (write(s2, "HELLO", 5) == -1)
+ kill(getppid(), 3);
+ exit(0);
+ }
+ l = sizeof(a);
+ close(0);
+ if (accept(s1, &a, &l))
+ exit(1);
+ l = 1;
+ if (select(1, &l, 0, 0, 0) == -1)
+ exit(1);
+ exit(0);
+}
+
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ test -n "$silent" || echo "- your sockets are usable";sock=1
+
+else
+ test -n "$silent" || echo "- your sockets are not usable"
+fi
+rm -fr conftest*
+rm -f /tmp/conftest*
+
+if test -n "$sock"; then
+test -n "$silent" || echo "checking socket implementation"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+char *son = "/tmp/conftest$$";
+
+main()
+{
+ int s;
+ struct stat stb;
+ struct sockaddr_un a;
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ exit(0);
+ a.sun_family = AF_UNIX;
+ strcpy(a.sun_path, son);
+ (void) unlink(son);
+ if (bind(s, (struct sockaddr *) &a, strlen(son)+2) == -1)
+ exit(0);
+ if (stat(son, &stb))
+ exit(1);
+ close(s);
+ exit(0);
+}
+
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ test -n "$silent" || echo "- you are normal"
+
+else
+ test -n "$silent" || echo "- unix domain sockets are not kept in the filesystem"
+
+{
+test -n "$verbose" && \
+echo " defining SOCK_NOT_IN_FS"
+echo "#define" SOCK_NOT_IN_FS "1" >> confdefs.h
+DEFS="$DEFS -DSOCK_NOT_IN_FS=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}SOCK_NOT_IN_FS\${ac_dB}SOCK_NOT_IN_FS\${ac_dC}1\${ac_dD}
+\${ac_uA}SOCK_NOT_IN_FS\${ac_uB}SOCK_NOT_IN_FS\${ac_uC}1\${ac_uD}
+\${ac_eA}SOCK_NOT_IN_FS\${ac_eB}SOCK_NOT_IN_FS\${ac_eC}1\${ac_eD}
+"
+}
+ socknofs=1
+fi
+rm -fr conftest*
+rm -f /tmp/conftest*
+fi
+
+
+if test -n "$fifo"; then
+ if test -n "$sock"; then
+ if test -n "$nore"; then
+ test -n "$silent" || echo "- hmmm... better take the fifos"
+
+{
+test -n "$verbose" && \
+echo " defining NAMEDPIPE"
+echo "#define" NAMEDPIPE "1" >> confdefs.h
+DEFS="$DEFS -DNAMEDPIPE=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}NAMEDPIPE\${ac_dB}NAMEDPIPE\${ac_dC}1\${ac_dD}
+\${ac_uA}NAMEDPIPE\${ac_uB}NAMEDPIPE\${ac_uC}1\${ac_uD}
+\${ac_eA}NAMEDPIPE\${ac_eB}NAMEDPIPE\${ac_eC}1\${ac_eD}
+"
+}
+
+ elif test -n "$fifobr"; then
+ test -n "$silent" || echo "- as your fifos are broken lets use the sockets."
+ else
+ test -n "$silent" || echo "- both sockets and fifos usable. let's take fifos."
+
+{
+test -n "$verbose" && \
+echo " defining NAMEDPIPE"
+echo "#define" NAMEDPIPE "1" >> confdefs.h
+DEFS="$DEFS -DNAMEDPIPE=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}NAMEDPIPE\${ac_dB}NAMEDPIPE\${ac_dC}1\${ac_dD}
+\${ac_uA}NAMEDPIPE\${ac_uB}NAMEDPIPE\${ac_uC}1\${ac_uD}
+\${ac_eA}NAMEDPIPE\${ac_eB}NAMEDPIPE\${ac_eC}1\${ac_eD}
+"
+}
+
+ fi
+ else
+ test -n "$silent" || echo "- using named pipes"
+
+{
+test -n "$verbose" && \
+echo " defining NAMEDPIPE"
+echo "#define" NAMEDPIPE "1" >> confdefs.h
+DEFS="$DEFS -DNAMEDPIPE=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}NAMEDPIPE\${ac_dB}NAMEDPIPE\${ac_dC}1\${ac_dD}
+\${ac_uA}NAMEDPIPE\${ac_uB}NAMEDPIPE\${ac_uC}1\${ac_uD}
+\${ac_eA}NAMEDPIPE\${ac_eB}NAMEDPIPE\${ac_eC}1\${ac_eD}
+"
+}
+
+ fi
+elif test -n "$sock"; then
+ test -n "$silent" || echo "- using unix-domain sockets"
+else
+ echo "configure: you have neither usable sockets nor usable pipes -> no screen" >&2; exit 1
+fi
+
+
+test -n "$silent" || echo "checking select return value"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+char *nam = "/tmp/conftest$$";
+
+#ifdef NAMEDPIPE
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+#ifndef S_IFIFO
+#define S_IFIFO 0010000
+#endif
+
+
+main()
+{
+ int l;
+
+#ifdef __FreeBSD__
+/* From Andrew A. Chernov (ache@astral.msk.su):
+ * opening RDWR fifo fails in BSD 4.4, but select return values is
+ * right.
+ */
+ exit(0);
+#endif
+ (void)alarm(5);
+#ifdef POSIX
+ if (mkfifo(nam, 0777))
+#else
+ if (mknod(nam, S_IFIFO|0777, 0))
+#endif
+ exit(1);
+ close(0);
+ if (open(nam, O_RDWR | O_NONBLOCK))
+ exit(1);
+ if (write(0, "TEST", 4) == -1)
+ exit(1);
+
+#else
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+main()
+{
+ int s1, s2, s3, l;
+ struct sockaddr_un a;
+
+ (void)alarm(5);
+ if ((s1 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ exit(1);
+ a.sun_family = AF_UNIX;
+ strcpy(a.sun_path, nam);
+ (void) unlink(nam);
+ if (bind(s1, (struct sockaddr *) &a, strlen(nam)+2) == -1)
+ exit(1);
+ if (listen(s1, 2))
+ exit(1);
+ if (fork() == 0)
+ {
+ if ((s2 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ kill(getppid(), 3);
+ (void)connect(s2, (struct sockaddr *)&a, strlen(nam) + 2);
+ if (write(s2, "HELLO", 5) == -1)
+ kill(getppid(), 3);
+ exit(0);
+ }
+ l = sizeof(a);
+ close(0);
+ if (accept(s1, (struct sockaddr *)&a, &l))
+ exit(1);
+#endif
+
+
+ l = 1;
+ if (select(1, &l, 0, 0, 0) == -1)
+ exit(1);
+ if (select(1, &l, &l, 0, 0) != 2)
+ exit(1);
+ exit(0);
+}
+
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ test -n "$silent" || echo "- select is ok"
+
+else
+ test -n "$silent" || echo "- it is not usable"
+{
+test -n "$verbose" && \
+echo " defining SELECT_BROKEN"
+echo "#define" SELECT_BROKEN "1" >> confdefs.h
+DEFS="$DEFS -DSELECT_BROKEN=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}SELECT_BROKEN\${ac_dB}SELECT_BROKEN\${ac_dC}1\${ac_dD}
+\${ac_uA}SELECT_BROKEN\${ac_uB}SELECT_BROKEN\${ac_uC}1\${ac_uD}
+\${ac_eA}SELECT_BROKEN\${ac_eB}SELECT_BROKEN\${ac_eC}1\${ac_eD}
+"
+}
+
+fi
+rm -fr conftest*
+
+test -n "$silent" || echo "checking for tgetent"
+olibs="$LIBS"
+LIBS="-lcurses $olibs"
+test -n "$silent" || echo "checking for libcurses"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+#ifdef __hpux
+__sorry_hpux_libcurses_is_totally_broken_in_10_10();
+#else
+tgetent((char *)0, (char *)0);
+#endif
+; return 0; }
+EOF
+if eval $ac_compile; then
+ :
+else
+ rm -rf conftest*
+ LIBS="-ltermcap $olibs"
+test -n "$silent" || echo "checking for libtermcap"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { tgetent((char *)0, (char *)0);; return 0; }
+EOF
+if eval $ac_compile; then
+ :
+else
+ rm -rf conftest*
+ LIBS="-ltermlib $olibs"
+test -n "$silent" || echo "checking for libtermlib"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { tgetent((char *)0, (char *)0);; return 0; }
+EOF
+if eval $ac_compile; then
+ :
+else
+ rm -rf conftest*
+ echo "configure: !!! no tgetent - no screen" >&2; exit 1
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+main()
+{
+ exit(strcmp(tgoto("%p1%d", 0, 1), "1") ? 0 : 1);
+}
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ test -n "$silent" || echo "- you use the termcap database"
+
+else
+ test -n "$silent" || echo "- you use the terminfo database"
+{
+test -n "$verbose" && \
+echo " defining TERMINFO"
+echo "#define" TERMINFO "1" >> confdefs.h
+DEFS="$DEFS -DTERMINFO=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}TERMINFO\${ac_dB}TERMINFO\${ac_dC}1\${ac_dD}
+\${ac_uA}TERMINFO\${ac_uB}TERMINFO\${ac_uC}1\${ac_uD}
+\${ac_eA}TERMINFO\${ac_eB}TERMINFO\${ac_eC}1\${ac_eD}
+"
+}
+
+fi
+rm -fr conftest*
+test -n "$silent" || echo "checking for ospeed"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+extern short ospeed;
+int main() { return 0; }
+int t() { ospeed=5;; return 0; }
+EOF
+if eval $ac_compile; then
+ :
+else
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining NEED_OSPEED"
+echo "#define" NEED_OSPEED "1" >> confdefs.h
+DEFS="$DEFS -DNEED_OSPEED=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}NEED_OSPEED\${ac_dB}NEED_OSPEED\${ac_dC}1\${ac_dD}
+\${ac_uA}NEED_OSPEED\${ac_uB}NEED_OSPEED\${ac_uC}1\${ac_uD}
+\${ac_eA}NEED_OSPEED\${ac_eB}NEED_OSPEED\${ac_eC}1\${ac_eD}
+"
+}
+
+fi
+rm -f conftest*
+
+
+test -n "$silent" || echo "checking for /dev/ptc"
+if test -r /dev/ptc; then
+
+{
+test -n "$verbose" && \
+echo " defining HAVE_DEV_PTC"
+echo "#define" HAVE_DEV_PTC "1" >> confdefs.h
+DEFS="$DEFS -DHAVE_DEV_PTC=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}HAVE_DEV_PTC\${ac_dB}HAVE_DEV_PTC\${ac_dC}1\${ac_dD}
+\${ac_uA}HAVE_DEV_PTC\${ac_uB}HAVE_DEV_PTC\${ac_uC}1\${ac_uD}
+\${ac_eA}HAVE_DEV_PTC\${ac_eB}HAVE_DEV_PTC\${ac_eC}1\${ac_eD}
+"
+}
+
+fi
+
+test -n "$silent" || echo "checking for ptyranges"
+if test -d /dev/ptym ; then
+pdir='/dev/ptym'
+else
+pdir='/dev'
+fi
+ptys=`echo $pdir/pty??`
+if test "$ptys" != "$pdir/pty??" ; then
+p0=`echo $ptys | tr ' ' '\012' | sed -e 's/^.*\(.\).$/\1/g' | sort -u | tr -d '\012'`
+p1=`echo $ptys | tr ' ' '\012' | sed -e 's/^.*\(.\)$/\1/g' | sort -u | tr -d '\012'`
+
+{
+test -n "$verbose" && \
+echo " defining" PTYRANGE0 to be "\"$p0\""
+echo "#define" PTYRANGE0 "\"$p0\"" >> confdefs.h
+DEFS="$DEFS -DPTYRANGE0=\"$p0\""
+ac_sed_defs="${ac_sed_defs}\${ac_dA}PTYRANGE0\${ac_dB}PTYRANGE0\${ac_dC}\"$p0\"\${ac_dD}
+\${ac_uA}PTYRANGE0\${ac_uB}PTYRANGE0\${ac_uC}\"$p0\"\${ac_uD}
+\${ac_eA}PTYRANGE0\${ac_eB}PTYRANGE0\${ac_eC}\"$p0\"\${ac_eD}
+"
+}
+
+
+{
+test -n "$verbose" && \
+echo " defining" PTYRANGE1 to be "\"$p1\""
+echo "#define" PTYRANGE1 "\"$p1\"" >> confdefs.h
+DEFS="$DEFS -DPTYRANGE1=\"$p1\""
+ac_sed_defs="${ac_sed_defs}\${ac_dA}PTYRANGE1\${ac_dB}PTYRANGE1\${ac_dC}\"$p1\"\${ac_dD}
+\${ac_uA}PTYRANGE1\${ac_uB}PTYRANGE1\${ac_uC}\"$p1\"\${ac_uD}
+\${ac_eA}PTYRANGE1\${ac_eB}PTYRANGE1\${ac_eC}\"$p1\"\${ac_eD}
+"
+}
+
+fi
+
+test -n "$silent" || echo "checking default tty permissions/group"
+rm -f conftest_grp
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+main()
+{
+ struct stat sb;
+ char *x,*ttyname();
+ int om, m;
+ FILE *fp;
+
+ if (!(x = ttyname(0))) exit(1);
+ if (stat(x, &sb)) exit(1);
+ om = sb.st_mode;
+ if (om & 002) exit(0);
+ m = system("mesg y");
+ if (m == -1 || m == 127) exit(1);
+ if (stat(x, &sb)) exit(1);
+ m = sb.st_mode;
+ if (chmod(x, om)) exit(1);
+ if (m & 002) exit(0);
+ if (sb.st_gid == getgid()) exit(1);
+ if (!(fp=fopen("conftest_grp", "w")))
+ exit(1);
+ fprintf(fp, "%d\n", sb.st_gid);
+ fclose(fp);
+ exit(0);
+}
+
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+
+ if test -f conftest_grp; then
+ ptygrp=`cat conftest_grp`
+ test -n "$silent" || echo "- pty mode: 0620"
+
+{
+test -n "$verbose" && \
+echo " defining" PTYMODE to be "0620"
+echo "#define" PTYMODE "0620" >> confdefs.h
+DEFS="$DEFS -DPTYMODE=0620"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}PTYMODE\${ac_dB}PTYMODE\${ac_dC}0620\${ac_dD}
+\${ac_uA}PTYMODE\${ac_uB}PTYMODE\${ac_uC}0620\${ac_uD}
+\${ac_eA}PTYMODE\${ac_eB}PTYMODE\${ac_eC}0620\${ac_eD}
+"
+}
+
+
+{
+test -n "$verbose" && \
+echo " defining" PTYGROUP to be "$ptygrp"
+echo "#define" PTYGROUP "$ptygrp" >> confdefs.h
+DEFS="$DEFS -DPTYGROUP=$ptygrp"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}PTYGROUP\${ac_dB}PTYGROUP\${ac_dC}$ptygrp\${ac_dD}
+\${ac_uA}PTYGROUP\${ac_uB}PTYGROUP\${ac_uC}$ptygrp\${ac_uD}
+\${ac_eA}PTYGROUP\${ac_eB}PTYGROUP\${ac_eC}$ptygrp\${ac_eD}
+"
+}
+
+ else
+ test -n "$silent" || echo "- ptys are world accessable"
+ fi
+
+
+else
+ test -n "$silent" || echo "- can't determine - assume ptys are world accessable"
+
+fi
+rm -fr conftest*
+rm -f conftest_grp
+
+test -n "$silent" || echo "checking for getutent"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <time.h> /* to get time_t on SCO */
+#include <sys/types.h>
+#if defined(SVR4) && !defined(DGUX)
+#include <utmpx.h>
+#define utmp utmpx
+#else
+#include <utmp.h>
+#endif
+#ifdef __hpux
+#define pututline _pututline
+#endif
+
+int main() { return 0; }
+int t() { int x = DEAD_PROCESS; struct utmp *y = pututline((struct utmp *)0); getutent();; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining GETUTENT"
+echo "#define" GETUTENT "1" >> confdefs.h
+DEFS="$DEFS -DGETUTENT=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}GETUTENT\${ac_dB}GETUTENT\${ac_dC}1\${ac_dD}
+\${ac_uA}GETUTENT\${ac_uB}GETUTENT\${ac_uC}1\${ac_uD}
+\${ac_eA}GETUTENT\${ac_eB}GETUTENT\${ac_eC}1\${ac_eD}
+"
+}
+
+
+else
+ rm -rf conftest*
+ olibs="$LIBS"
+LIBS="$LIBS -lgen"
+test -n "$silent" || echo "checking for getutent with -lgen"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <time.h>
+#include <sys/types.h>
+#if defined(SVR4) && !defined(DGUX)
+#include <utmpx.h>
+#define utmp utmpx
+#else
+#include <utmp.h>
+#endif
+#ifdef __hpux
+#define pututline _pututline
+#endif
+
+int main() { return 0; }
+int t() { int x = DEAD_PROCESS; struct utmp *y = pututline((struct utmp *)0); getutent();; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining GETUTENT"
+echo "#define" GETUTENT "1" >> confdefs.h
+DEFS="$DEFS -DGETUTENT=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}GETUTENT\${ac_dB}GETUTENT\${ac_dC}1\${ac_dD}
+\${ac_uA}GETUTENT\${ac_uB}GETUTENT\${ac_uC}1\${ac_uD}
+\${ac_eA}GETUTENT\${ac_eB}GETUTENT\${ac_eC}1\${ac_eD}
+"
+}
+
+
+else
+ rm -rf conftest*
+ LIBS="$olibs"
+fi
+rm -f conftest*
+
+
+fi
+rm -f conftest*
+
+test -n "$silent" || echo "checking for ut_host"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <time.h>
+#include <sys/types.h>
+#if defined(SVR4) && !defined(DGUX)
+#include <utmpx.h>
+#define utmp utmpx
+#else
+#include <utmp.h>
+#endif
+
+int main() { return 0; }
+int t() { struct utmp u; u.ut_host[0] = 0;; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining UTHOST"
+echo "#define" UTHOST "1" >> confdefs.h
+DEFS="$DEFS -DUTHOST=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}UTHOST\${ac_dB}UTHOST\${ac_dC}1\${ac_dD}
+\${ac_uA}UTHOST\${ac_uB}UTHOST\${ac_uC}1\${ac_uD}
+\${ac_eA}UTHOST\${ac_eB}UTHOST\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+
+
+test -n "$silent" || echo "checking for libutil(s)"
+test -f /usr/lib/libutils.a && LIBS="$LIBS -lutils"
+test -f /usr/lib/libutil.a && LIBS="$LIBS -lutil"
+
+test -n "$silent" || echo "checking for getloadavg"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { getloadavg((double *)0, 0);; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining LOADAV_GETLOADAVG"
+echo "#define" LOADAV_GETLOADAVG "1" >> confdefs.h
+DEFS="$DEFS -DLOADAV_GETLOADAVG=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}LOADAV_GETLOADAVG\${ac_dB}LOADAV_GETLOADAVG\${ac_dC}1\${ac_dD}
+\${ac_uA}LOADAV_GETLOADAVG\${ac_uB}LOADAV_GETLOADAVG\${ac_uC}1\${ac_uD}
+\${ac_eA}LOADAV_GETLOADAVG\${ac_eB}LOADAV_GETLOADAVG\${ac_eC}1\${ac_eD}
+"
+}
+ load=1
+
+else
+ rm -rf conftest*
+ if test -f /usr/lib/libkvm.a ; then
+olibs="$LIBS"
+LIBS="$LIBS -lkvm"
+test -n "$silent" || echo "checking for getloadavg with -lkvm"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { getloadavg((double *)0, 0);; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining LOADAV_GETLOADAVG"
+echo "#define" LOADAV_GETLOADAVG "1" >> confdefs.h
+DEFS="$DEFS -DLOADAV_GETLOADAVG=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}LOADAV_GETLOADAVG\${ac_dB}LOADAV_GETLOADAVG\${ac_dC}1\${ac_dD}
+\${ac_uA}LOADAV_GETLOADAVG\${ac_uB}LOADAV_GETLOADAVG\${ac_uC}1\${ac_uD}
+\${ac_eA}LOADAV_GETLOADAVG\${ac_eB}LOADAV_GETLOADAVG\${ac_eC}1\${ac_eD}
+"
+}
+ load=1
+
+else
+ rm -rf conftest*
+ LIBS="$olibs"
+fi
+rm -f conftest*
+
+fi
+
+fi
+rm -f conftest*
+
+
+if test -z "$load" ; then
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#if defined(NeXT) || defined(apollo) || defined(linux)
+ yes
+#endif
+
+EOF
+eval "$ac_cpp conftest.${ac_ext} > conftest.out 2>&1"
+if egrep "yes" conftest.out >/dev/null 2>&1; then
+ rm -rf conftest*
+ load=1
+
+fi
+rm -f conftest*
+
+fi
+if test -z "$load" ; then
+test -n "$silent" || echo "checking for kernelfile"
+for core in /unix /vmunix /dynix /hp-ux /xelos /dev/ksyms /kernel/unix /kernel/genunix /unicos /mach /netbsd /386bsd /dgux /bsd /stand/vmunix; do
+ if test -f $core || test -c $core; then
+ break
+ fi
+done
+if test ! -f $core && test ! -c $core ; then
+ test -n "$silent" || echo "- no kernelfile found"
+else
+ test -n "$silent" || echo "- using kernelfile '$core'"
+
+{
+test -n "$verbose" && \
+echo " defining" LOADAV_UNIX to be "\"$core\""
+echo "#define" LOADAV_UNIX "\"$core\"" >> confdefs.h
+DEFS="$DEFS -DLOADAV_UNIX=\"$core\""
+ac_sed_defs="${ac_sed_defs}\${ac_dA}LOADAV_UNIX\${ac_dB}LOADAV_UNIX\${ac_dC}\"$core\"\${ac_dD}
+\${ac_uA}LOADAV_UNIX\${ac_uB}LOADAV_UNIX\${ac_uC}\"$core\"\${ac_uD}
+\${ac_eA}LOADAV_UNIX\${ac_eB}LOADAV_UNIX\${ac_eC}\"$core\"\${ac_eD}
+"
+}
+
+ test -n "$silent" || echo "checking for nlist.h"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <nlist.h>
+EOF
+# Some shells (Coherent) do redirections in the wrong order, so need
+# the parens.
+ac_err=`eval "($ac_cpp conftest.${ac_ext} >/dev/null) 2>&1"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining NLIST_STRUCT"
+echo "#define" NLIST_STRUCT "1" >> confdefs.h
+DEFS="$DEFS -DNLIST_STRUCT=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}NLIST_STRUCT\${ac_dB}NLIST_STRUCT\${ac_dC}1\${ac_dD}
+\${ac_uA}NLIST_STRUCT\${ac_uB}NLIST_STRUCT\${ac_uC}1\${ac_uD}
+\${ac_eA}NLIST_STRUCT\${ac_eB}NLIST_STRUCT\${ac_eC}1\${ac_eD}
+"
+}
+
+ test -n "$silent" || echo "checking for n_un in struct nlist"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <nlist.h>
+int main() { return 0; }
+int t() { struct nlist n; n.n_un.n_name = 0;; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining NLIST_NAME_UNION"
+echo "#define" NLIST_NAME_UNION "1" >> confdefs.h
+DEFS="$DEFS -DNLIST_NAME_UNION=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}NLIST_NAME_UNION\${ac_dB}NLIST_NAME_UNION\${ac_dC}1\${ac_dD}
+\${ac_uA}NLIST_NAME_UNION\${ac_uB}NLIST_NAME_UNION\${ac_uC}1\${ac_uD}
+\${ac_eA}NLIST_NAME_UNION\${ac_eB}NLIST_NAME_UNION\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+
+fi
+rm -f conftest*
+
+
+ test -n "$silent" || echo "checking for nlist declaration"
+ cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+#ifdef NLIST_STRUCT
+# include <nlist.h>
+#else
+# include <a.out.h>
+#endif
+
+EOF
+eval "$ac_cpp conftest.${ac_ext} > conftest.out 2>&1"
+if egrep "nlist(( | )( | )*.*\(|\()" conftest.out >/dev/null 2>&1; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining NLIST_DECLARED"
+echo "#define" NLIST_DECLARED "1" >> confdefs.h
+DEFS="$DEFS -DNLIST_DECLARED=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}NLIST_DECLARED\${ac_dB}NLIST_DECLARED\${ac_dC}1\${ac_dD}
+\${ac_uA}NLIST_DECLARED\${ac_uB}NLIST_DECLARED\${ac_uC}1\${ac_uD}
+\${ac_eA}NLIST_DECLARED\${ac_eB}NLIST_DECLARED\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+
+ test -n "$silent" || echo "checking for avenrun symbol"
+ for av in avenrun _avenrun _Loadavg ; do
+ cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+#include <sys/types.h>
+#ifdef NLIST_STRUCT
+#include <nlist.h>
+#else
+#include <a.out.h>
+#endif
+
+#ifdef __sgi
+# if _MIPS_SZLONG == 64
+# define nlist nlist64
+# endif
+#endif
+
+struct nlist nl[2];
+
+main()
+{
+#if !defined(_AUX_SOURCE) && !defined(AUX)
+# ifdef NLIST_NAME_UNION
+ nl[0].n_un.n_name = "$av";
+# else
+ nl[0].n_name = "$av";
+# endif
+#else
+ strncpy(nl[0].n_name, "$av", sizeof(nl[0].n_name));
+#endif
+ nlist(LOADAV_UNIX, nl);
+ if (nl[0].n_value == 0)
+ exit(1);
+ exit(0);
+}
+
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ avensym=$av;break
+
+fi
+rm -fr conftest*
+ done
+ if test -z "$avensym" ; then
+ test -n "$silent" || echo "- no avenrun symbol found"
+ else
+ test -n "$silent" || echo "- using avenrun symbol '$avensym'"
+
+{
+test -n "$verbose" && \
+echo " defining" LOADAV_AVENRUN to be "\"$avensym\""
+echo "#define" LOADAV_AVENRUN "\"$avensym\"" >> confdefs.h
+DEFS="$DEFS -DLOADAV_AVENRUN=\"$avensym\""
+ac_sed_defs="${ac_sed_defs}\${ac_dA}LOADAV_AVENRUN\${ac_dB}LOADAV_AVENRUN\${ac_dC}\"$avensym\"\${ac_dD}
+\${ac_uA}LOADAV_AVENRUN\${ac_uB}LOADAV_AVENRUN\${ac_uC}\"$avensym\"\${ac_uD}
+\${ac_eA}LOADAV_AVENRUN\${ac_eB}LOADAV_AVENRUN\${ac_eC}\"$avensym\"\${ac_eD}
+"
+}
+
+ load=1
+ fi
+fi
+fi
+
+cat > conftest.c <<EOF
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+_CUT_HERE_
+
+#if ((defined(hp300) && !defined(__hpux)) || defined(sun) || (defined(ultrix) && defined(mips)) || defined(_SEQUENT_) || defined(sgi) || defined(SVR4) || defined(sony_news) || defined(__alpha) || defined(_IBMR2) || defined(_AUX_SOURCE) || defined(AUX) || defined(m88k))
+loadtype=long
+# if defined(apollo) || defined(_IBMR2) || defined(_AUX_SOURCE) || defined(AUX)
+loadscale=65536
+# else
+# if defined(FSCALE) && !defined(__osf__)
+# undef FSCALE
+loadscale=FSCALE
+# else
+# ifdef sgi
+loadscale=1024
+loadtype=int
+# else
+# if defined(MIPS) || defined(SVR4) || defined(m88k)
+loadscale=256
+# else /* not MIPS */
+loadscale=1000 /* our default value */
+# endif /* MIPS */
+# endif /* sgi */
+# endif /* not FSCALE */
+# endif /* not apollo */
+#else
+loadtype=double
+loadscale=1
+#endif
+#ifdef alliant
+loadnum=4
+#else
+loadnum=3
+#endif
+
+EOF
+$CPP $DEFS conftest.c 2>/dev/null | sed -e '1,/_CUT_HERE_/d' > conftest.out
+. ./conftest.out
+rm -f conftest*
+
+
+if test -n "$load" ; then
+{
+test -n "$verbose" && \
+echo " defining LOADAV"
+echo "#define" LOADAV "1" >> confdefs.h
+DEFS="$DEFS -DLOADAV=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}LOADAV\${ac_dB}LOADAV\${ac_dC}1\${ac_dD}
+\${ac_uA}LOADAV\${ac_uB}LOADAV\${ac_uC}1\${ac_uD}
+\${ac_eA}LOADAV\${ac_eB}LOADAV\${ac_eC}1\${ac_eD}
+"
+}
+ fi
+if test -n "$loadtype" ; then
+{
+test -n "$verbose" && \
+echo " defining" LOADAV_TYPE to be "$loadtype"
+echo "#define" LOADAV_TYPE "$loadtype" >> confdefs.h
+DEFS="$DEFS -DLOADAV_TYPE=$loadtype"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}LOADAV_TYPE\${ac_dB}LOADAV_TYPE\${ac_dC}$loadtype\${ac_dD}
+\${ac_uA}LOADAV_TYPE\${ac_uB}LOADAV_TYPE\${ac_uC}$loadtype\${ac_uD}
+\${ac_eA}LOADAV_TYPE\${ac_eB}LOADAV_TYPE\${ac_eC}$loadtype\${ac_eD}
+"
+}
+ fi
+if test -n "$loadnum" ; then
+{
+test -n "$verbose" && \
+echo " defining" LOADAV_NUM to be "$loadnum"
+echo "#define" LOADAV_NUM "$loadnum" >> confdefs.h
+DEFS="$DEFS -DLOADAV_NUM=$loadnum"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}LOADAV_NUM\${ac_dB}LOADAV_NUM\${ac_dC}$loadnum\${ac_dD}
+\${ac_uA}LOADAV_NUM\${ac_uB}LOADAV_NUM\${ac_uC}$loadnum\${ac_uD}
+\${ac_eA}LOADAV_NUM\${ac_eB}LOADAV_NUM\${ac_eC}$loadnum\${ac_eD}
+"
+}
+ fi
+if test -n "$loadscale" ; then
+{
+test -n "$verbose" && \
+echo " defining" LOADAV_SCALE to be "$loadscale"
+echo "#define" LOADAV_SCALE "$loadscale" >> confdefs.h
+DEFS="$DEFS -DLOADAV_SCALE=$loadscale"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}LOADAV_SCALE\${ac_dB}LOADAV_SCALE\${ac_dC}$loadscale\${ac_dD}
+\${ac_uA}LOADAV_SCALE\${ac_uB}LOADAV_SCALE\${ac_uC}$loadscale\${ac_uD}
+\${ac_eA}LOADAV_SCALE\${ac_eB}LOADAV_SCALE\${ac_eC}$loadscale\${ac_eD}
+"
+}
+ fi
+
+
+if test -n "$posix" ; then
+
+test -n "$silent" || echo "assuming posix signal definition"
+
+{
+test -n "$verbose" && \
+echo " defining SIGVOID"
+echo "#define" SIGVOID "1" >> confdefs.h
+DEFS="$DEFS -DSIGVOID=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}SIGVOID\${ac_dB}SIGVOID\${ac_dC}1\${ac_dD}
+\${ac_uA}SIGVOID\${ac_uB}SIGVOID\${ac_uC}1\${ac_uD}
+\${ac_eA}SIGVOID\${ac_eB}SIGVOID\${ac_eC}1\${ac_eD}
+"
+}
+
+
+else
+
+test -n "$silent" || echo "checking for return type of signal handlers"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+extern void (*signal ()) ();
+int main() { return 0; }
+int t() { int i;; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining SIGVOID"
+echo "#define" SIGVOID "1" >> confdefs.h
+DEFS="$DEFS -DSIGVOID=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}SIGVOID\${ac_dB}SIGVOID\${ac_dC}1\${ac_dD}
+\${ac_uA}SIGVOID\${ac_uB}SIGVOID\${ac_uC}1\${ac_uD}
+\${ac_eA}SIGVOID\${ac_eB}SIGVOID\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+test -n "$silent" || echo "checking for sigset"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <signal.h>
+
+int main() { return 0; }
+int t() {
+#ifdef SIGVOID
+sigset(0, (void (*)())0);
+#else
+sigset(0, (int (*)())0);
+#endif
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining USESIGSET"
+echo "#define" USESIGSET "1" >> confdefs.h
+DEFS="$DEFS -DUSESIGSET=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}USESIGSET\${ac_dB}USESIGSET\${ac_dC}1\${ac_dD}
+\${ac_uA}USESIGSET\${ac_uB}USESIGSET\${ac_uC}1\${ac_uD}
+\${ac_eA}USESIGSET\${ac_eB}USESIGSET\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+test -n "$silent" || echo "checking signal implementation"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <signal.h>
+
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
+#endif
+#ifdef USESIGSET
+#define signal sigset
+#endif
+
+int got;
+
+#ifdef SIGVOID
+void
+#endif
+hand()
+{
+ got++;
+}
+
+main()
+{
+ /* on hpux we use sigvec to get bsd signals */
+#ifdef __hpux
+ (void)signal(SIGCLD, hand);
+ kill(getpid(), SIGCLD);
+ kill(getpid(), SIGCLD);
+ if (got < 2)
+ exit(1);
+#endif
+ exit(0);
+}
+
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining SYSVSIGS"
+echo "#define" SYSVSIGS "1" >> confdefs.h
+DEFS="$DEFS -DSYSVSIGS=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}SYSVSIGS\${ac_dB}SYSVSIGS\${ac_dC}1\${ac_dD}
+\${ac_uA}SYSVSIGS\${ac_uB}SYSVSIGS\${ac_uC}1\${ac_uD}
+\${ac_eA}SYSVSIGS\${ac_eB}SYSVSIGS\${ac_eC}1\${ac_eD}
+"
+}
+
+fi
+rm -fr conftest*
+
+fi
+
+
+test -n "$silent" || echo "checking for crypt and sec libraries"
+test -f /lib/libcrypt_d.a || test -f /usr/lib/libcrypt_d.a && LIBS="$LIBS -lcrypt_d"
+test -f /lib/libcrypt.a || test -f /usr/lib/libcrypt.a && LIBS="$LIBS -lcrypt"
+test -f /lib/libsec.a || test -f /usr/lib/libsec.a && LIBS="$LIBS -lsec"
+test -f /lib/libshadow.a || test -f /usr/lib/libshadow.a && LIBS="$LIBS -lshadow"
+
+oldlibs="$LIBS"
+LIBS="$LIBS -lsun"
+test -n "$silent" || echo "checking for IRIX sun library"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { ; return 0; }
+EOF
+if eval $ac_compile; then
+ :
+else
+ rm -rf conftest*
+ LIBS="$oldlibs"
+fi
+rm -f conftest*
+
+
+
+test -n "$silent" || echo "checking for wait union"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int main() { return 0; }
+int t() {
+ union wait x;
+ int y;
+#ifdef WEXITSTATUS
+ y = WEXITSTATUS(x);
+#endif
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining BSDWAIT"
+echo "#define" BSDWAIT "1" >> confdefs.h
+DEFS="$DEFS -DBSDWAIT=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}BSDWAIT\${ac_dB}BSDWAIT\${ac_dC}1\${ac_dD}
+\${ac_uA}BSDWAIT\${ac_uB}BSDWAIT\${ac_uC}1\${ac_uD}
+\${ac_eA}BSDWAIT\${ac_eB}BSDWAIT\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+
+if test -z "$butterfly"; then
+test -n "$silent" || echo "checking for termio or termios"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <termio.h>
+EOF
+# Some shells (Coherent) do redirections in the wrong order, so need
+# the parens.
+ac_err=`eval "($ac_cpp conftest.${ac_ext} >/dev/null) 2>&1"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining TERMIO"
+echo "#define" TERMIO "1" >> confdefs.h
+DEFS="$DEFS -DTERMIO=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}TERMIO\${ac_dB}TERMIO\${ac_dC}1\${ac_dD}
+\${ac_uA}TERMIO\${ac_uB}TERMIO\${ac_uC}1\${ac_uD}
+\${ac_eA}TERMIO\${ac_eB}TERMIO\${ac_eC}1\${ac_eD}
+"
+}
+
+
+else
+ rm -rf conftest*
+ if test -n "$posix"; then
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <termios.h>
+EOF
+# Some shells (Coherent) do redirections in the wrong order, so need
+# the parens.
+ac_err=`eval "($ac_cpp conftest.${ac_ext} >/dev/null) 2>&1"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining TERMIO"
+echo "#define" TERMIO "1" >> confdefs.h
+DEFS="$DEFS -DTERMIO=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}TERMIO\${ac_dB}TERMIO\${ac_dC}1\${ac_dD}
+\${ac_uA}TERMIO\${ac_uB}TERMIO\${ac_uC}1\${ac_uD}
+\${ac_eA}TERMIO\${ac_eB}TERMIO\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+fi
+
+fi
+rm -f conftest*
+fi
+
+test -n "$silent" || echo "checking for getspnam"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <shadow.h>
+int main() { return 0; }
+int t() { getspnam("x");; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining SHADOWPW"
+echo "#define" SHADOWPW "1" >> confdefs.h
+DEFS="$DEFS -DSHADOWPW=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}SHADOWPW\${ac_dB}SHADOWPW\${ac_dC}1\${ac_dD}
+\${ac_uA}SHADOWPW\${ac_uB}SHADOWPW\${ac_uC}1\${ac_uD}
+\${ac_eA}SHADOWPW\${ac_eB}SHADOWPW\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+
+test -n "$silent" || echo "checking for getttyent"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { getttyent();; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining GETTTYENT"
+echo "#define" GETTTYENT "1" >> confdefs.h
+DEFS="$DEFS -DGETTTYENT=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}GETTTYENT\${ac_dB}GETTTYENT\${ac_dC}1\${ac_dD}
+\${ac_uA}GETTTYENT\${ac_uB}GETTTYENT\${ac_uC}1\${ac_uD}
+\${ac_eA}GETTTYENT\${ac_eB}GETTTYENT\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+
+test -n "$silent" || echo "checking whether memcpy/memmove/bcopy handles overlapping arguments"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+main() {
+ char buf[10];
+ strcpy(buf, "abcdefghi");
+ bcopy(buf, buf + 2, 3);
+ if (strncmp(buf, "ababcf", 6))
+ exit(1);
+ strcpy(buf, "abcdefghi");
+ bcopy(buf + 2, buf, 3);
+ if (strncmp(buf, "cdedef", 6))
+ exit(1);
+ exit(0); /* libc version works properly. */
+}
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+
+{
+test -n "$verbose" && \
+echo " defining USEBCOPY"
+echo "#define" USEBCOPY "1" >> confdefs.h
+DEFS="$DEFS -DUSEBCOPY=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}USEBCOPY\${ac_dB}USEBCOPY\${ac_dC}1\${ac_dD}
+\${ac_uA}USEBCOPY\${ac_uB}USEBCOPY\${ac_uC}1\${ac_uD}
+\${ac_eA}USEBCOPY\${ac_eB}USEBCOPY\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -fr conftest*
+
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+#define bcopy(s,d,l) memmove(d,s,l)
+main() {
+ char buf[10];
+ strcpy(buf, "abcdefghi");
+ bcopy(buf, buf + 2, 3);
+ if (strncmp(buf, "ababcf", 6))
+ exit(1);
+ strcpy(buf, "abcdefghi");
+ bcopy(buf + 2, buf, 3);
+ if (strncmp(buf, "cdedef", 6))
+ exit(1);
+ exit(0); /* libc version works properly. */
+}
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+
+{
+test -n "$verbose" && \
+echo " defining USEMEMMOVE"
+echo "#define" USEMEMMOVE "1" >> confdefs.h
+DEFS="$DEFS -DUSEMEMMOVE=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}USEMEMMOVE\${ac_dB}USEMEMMOVE\${ac_dC}1\${ac_dD}
+\${ac_uA}USEMEMMOVE\${ac_uB}USEMEMMOVE\${ac_uC}1\${ac_uD}
+\${ac_eA}USEMEMMOVE\${ac_eB}USEMEMMOVE\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -fr conftest*
+
+
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+#define bcopy(s,d,l) memcpy(d,s,l)
+main() {
+ char buf[10];
+ strcpy(buf, "abcdefghi");
+ bcopy(buf, buf + 2, 3);
+ if (strncmp(buf, "ababcf", 6))
+ exit(1);
+ strcpy(buf, "abcdefghi");
+ bcopy(buf + 2, buf, 3);
+ if (strncmp(buf, "cdedef", 6))
+ exit(1);
+ exit(0); /* libc version works properly. */
+}
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+
+{
+test -n "$verbose" && \
+echo " defining USEMEMCPY"
+echo "#define" USEMEMCPY "1" >> confdefs.h
+DEFS="$DEFS -DUSEMEMCPY=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}USEMEMCPY\${ac_dB}USEMEMCPY\${ac_dC}1\${ac_dD}
+\${ac_uA}USEMEMCPY\${ac_uB}USEMEMCPY\${ac_uC}1\${ac_uD}
+\${ac_eA}USEMEMCPY\${ac_eB}USEMEMCPY\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -fr conftest*
+
+test -n "$silent" || echo "checking for long file names"
+(echo 1 > /tmp/conftest9012345) 2>/dev/null
+(echo 2 > /tmp/conftest9012346) 2>/dev/null
+val=`cat /tmp/conftest9012345 2>/dev/null`
+if test -f /tmp/conftest9012345 && test "$val" = 1; then :
+else
+{
+test -n "$verbose" && \
+echo " defining" NAME_MAX to be "14"
+echo "#define" NAME_MAX "14" >> confdefs.h
+DEFS="$DEFS -DNAME_MAX=14"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}NAME_MAX\${ac_dB}NAME_MAX\${ac_dC}14\${ac_dD}
+\${ac_uA}NAME_MAX\${ac_uB}NAME_MAX\${ac_uC}14\${ac_uD}
+\${ac_eA}NAME_MAX\${ac_eB}NAME_MAX\${ac_eC}14\${ac_eD}
+"
+}
+
+fi
+rm -f /tmp/conftest*
+
+test -n "$silent" || echo "checking for vsprintf"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <varargs.h>
+#include <stdio.h>
+int main() { return 0; }
+int t() { vsprintf();; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining USEVARARGS"
+echo "#define" USEVARARGS "1" >> confdefs.h
+DEFS="$DEFS -DUSEVARARGS=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}USEVARARGS\${ac_dB}USEVARARGS\${ac_dC}1\${ac_dD}
+\${ac_uA}USEVARARGS\${ac_uB}USEVARARGS\${ac_uC}1\${ac_uD}
+\${ac_eA}USEVARARGS\${ac_eB}USEVARARGS\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+
+test -n "$silent" || echo "checking for directory library header"
+ac_dir_header=
+if test -z "$ac_dir_header"; then
+ test -n "$silent" || echo "checking for dirent.h"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <sys/types.h>
+#include <dirent.h>
+int main() { return 0; }
+int t() { DIR *dirp = 0;; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining DIRENT"
+echo "#define" DIRENT "1" >> confdefs.h
+DEFS="$DEFS -DDIRENT=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}DIRENT\${ac_dB}DIRENT\${ac_dC}1\${ac_dD}
+\${ac_uA}DIRENT\${ac_uB}DIRENT\${ac_uC}1\${ac_uD}
+\${ac_eA}DIRENT\${ac_eB}DIRENT\${ac_eC}1\${ac_eD}
+"
+}
+ ac_dir_header=dirent.h
+
+fi
+rm -f conftest*
+fi
+if test -z "$ac_dir_header"; then
+ test -n "$silent" || echo "checking for sys/ndir.h"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/ndir.h>
+int main() { return 0; }
+int t() { DIR *dirp = 0;; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining SYSNDIR"
+echo "#define" SYSNDIR "1" >> confdefs.h
+DEFS="$DEFS -DSYSNDIR=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}SYSNDIR\${ac_dB}SYSNDIR\${ac_dC}1\${ac_dD}
+\${ac_uA}SYSNDIR\${ac_uB}SYSNDIR\${ac_uC}1\${ac_uD}
+\${ac_eA}SYSNDIR\${ac_eB}SYSNDIR\${ac_eC}1\${ac_eD}
+"
+}
+ ac_dir_header=sys/ndir.h
+
+fi
+rm -f conftest*
+fi
+if test -z "$ac_dir_header"; then
+ test -n "$silent" || echo "checking for sys/dir.h"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/dir.h>
+int main() { return 0; }
+int t() { DIR *dirp = 0;; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining SYSDIR"
+echo "#define" SYSDIR "1" >> confdefs.h
+DEFS="$DEFS -DSYSDIR=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}SYSDIR\${ac_dB}SYSDIR\${ac_dC}1\${ac_dD}
+\${ac_uA}SYSDIR\${ac_uB}SYSDIR\${ac_uC}1\${ac_uD}
+\${ac_eA}SYSDIR\${ac_eB}SYSDIR\${ac_eC}1\${ac_eD}
+"
+}
+ ac_dir_header=sys/dir.h
+
+fi
+rm -f conftest*
+fi
+if test -z "$ac_dir_header"; then
+ test -n "$silent" || echo "checking for ndir.h"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <sys/types.h>
+#include <ndir.h>
+int main() { return 0; }
+int t() { DIR *dirp = 0;; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining NDIR"
+echo "#define" NDIR "1" >> confdefs.h
+DEFS="$DEFS -DNDIR=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}NDIR\${ac_dB}NDIR\${ac_dC}1\${ac_dD}
+\${ac_uA}NDIR\${ac_uB}NDIR\${ac_uC}1\${ac_uD}
+\${ac_eA}NDIR\${ac_eB}NDIR\${ac_eC}1\${ac_eD}
+"
+}
+ ac_dir_header=ndir.h
+
+fi
+rm -f conftest*
+fi
+
+test -n "$silent" || echo "checking for closedir return value"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_dir_header>
+int closedir(); main() { exit(closedir(opendir(".")) != 0); }
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining VOID_CLOSEDIR"
+echo "#define" VOID_CLOSEDIR "1" >> confdefs.h
+DEFS="$DEFS -DVOID_CLOSEDIR=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}VOID_CLOSEDIR\${ac_dB}VOID_CLOSEDIR\${ac_dC}1\${ac_dD}
+\${ac_uA}VOID_CLOSEDIR\${ac_uB}VOID_CLOSEDIR\${ac_uC}1\${ac_uD}
+\${ac_eA}VOID_CLOSEDIR\${ac_eB}VOID_CLOSEDIR\${ac_eC}1\${ac_eD}
+"
+}
+
+fi
+rm -fr conftest*
+
+test -n "$silent" || echo "checking for Xenix"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+#if defined(M_XENIX) && !defined(M_UNIX)
+ yes
+#endif
+
+EOF
+eval "$ac_cpp conftest.${ac_ext} > conftest.out 2>&1"
+if egrep "yes" conftest.out >/dev/null 2>&1; then
+ rm -rf conftest*
+ XENIX=1
+
+fi
+rm -f conftest*
+
+if test -n "$XENIX"; then
+ LIBS="$LIBS -lx"
+ case "$DEFS" in
+ *SYSNDIR*) ;;
+ *) LIBS="-ldir $LIBS" ;; # Make sure -ldir precedes any -lx.
+ esac
+fi
+
+
+test -n "$silent" || echo "checking for setenv"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { setenv((char *)0,(char *)0);unsetenv((char *)0);; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining USESETENV"
+echo "#define" USESETENV "1" >> confdefs.h
+DEFS="$DEFS -DUSESETENV=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}USESETENV\${ac_dB}USESETENV\${ac_dC}1\${ac_dD}
+\${ac_uA}USESETENV\${ac_uB}USESETENV\${ac_uC}1\${ac_uD}
+\${ac_eA}USESETENV\${ac_eB}USESETENV\${ac_eC}1\${ac_eD}
+"
+}
+
+
+else
+ rm -rf conftest*
+ test -n "$silent" || echo "checking for putenv"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { putenv((char *)0);unsetenv((char *)0);; return 0; }
+EOF
+if eval $ac_compile; then
+ :
+else
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining NEEDPUTENV"
+echo "#define" NEEDPUTENV "1" >> confdefs.h
+DEFS="$DEFS -DNEEDPUTENV=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}NEEDPUTENV\${ac_dB}NEEDPUTENV\${ac_dC}1\${ac_dD}
+\${ac_uA}NEEDPUTENV\${ac_uB}NEEDPUTENV\${ac_uC}1\${ac_uD}
+\${ac_eA}NEEDPUTENV\${ac_eB}NEEDPUTENV\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+
+test -n "$silent" || echo "checking for rename"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { rename(0,0);; return 0; }
+EOF
+if eval $ac_compile; then
+ :
+else
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining NEED_RENAME"
+echo "#define" NEED_RENAME "1" >> confdefs.h
+DEFS="$DEFS -DNEED_RENAME=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}NEED_RENAME\${ac_dB}NEED_RENAME\${ac_dC}1\${ac_dD}
+\${ac_uA}NEED_RENAME\${ac_uB}NEED_RENAME\${ac_uC}1\${ac_uD}
+\${ac_eA}NEED_RENAME\${ac_eB}NEED_RENAME\${ac_eC}1\${ac_eD}
+"
+}
+
+fi
+rm -f conftest*
+
+test -n "$silent" || echo "checking for _exit"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { _exit(0);; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining HAVE__EXIT"
+echo "#define" HAVE__EXIT "1" >> confdefs.h
+DEFS="$DEFS -DHAVE__EXIT=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}HAVE__EXIT\${ac_dB}HAVE__EXIT\${ac_dC}1\${ac_dD}
+\${ac_uA}HAVE__EXIT\${ac_uB}HAVE__EXIT\${ac_uC}1\${ac_uD}
+\${ac_eA}HAVE__EXIT\${ac_eB}HAVE__EXIT\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+test -n "$silent" || echo "checking for lstat"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { lstat(0,0);; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining HAVE_LSTAT"
+echo "#define" HAVE_LSTAT "1" >> confdefs.h
+DEFS="$DEFS -DHAVE_LSTAT=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}HAVE_LSTAT\${ac_dB}HAVE_LSTAT\${ac_dC}1\${ac_dD}
+\${ac_uA}HAVE_LSTAT\${ac_uB}HAVE_LSTAT\${ac_uC}1\${ac_uD}
+\${ac_eA}HAVE_LSTAT\${ac_eB}HAVE_LSTAT\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+test -n "$silent" || echo "checking for strerror"
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() { strerror(0);; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+
+{
+test -n "$verbose" && \
+echo " defining HAVE_STRERROR"
+echo "#define" HAVE_STRERROR "1" >> confdefs.h
+DEFS="$DEFS -DHAVE_STRERROR=1"
+ac_sed_defs="${ac_sed_defs}\${ac_dA}HAVE_STRERROR\${ac_dB}HAVE_STRERROR\${ac_dC}1\${ac_dD}
+\${ac_uA}HAVE_STRERROR\${ac_uB}HAVE_STRERROR\${ac_uC}1\${ac_uD}
+\${ac_eA}HAVE_STRERROR\${ac_eB}HAVE_STRERROR\${ac_eC}1\${ac_eD}
+"
+}
+
+
+fi
+rm -f conftest*
+
+
+test -n "$seqptx" && LIBS="-ltermcap -lc -lsocket -linet -lsec -lseq"
+
+cat > conftest.${ac_ext} <<EOF
+#include "confdefs.h"
+main(){exit(0);}
+EOF
+eval $ac_compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ :
+else
+ echo "configure: Can't run the compiler - internal error. Sorry." >&2; exit 1
+fi
+rm -fr conftest*
+if test -n "$prefix"; then
+
+{
+test -n "$verbose" && \
+echo " defining" ETCSCREENRC to be "\"$prefix/etc/screenrc\""
+echo "#define" ETCSCREENRC "\"$prefix/etc/screenrc\"" >> confdefs.h
+DEFS="$DEFS -DETCSCREENRC=\"$prefix/etc/screenrc\""
+ac_sed_defs="${ac_sed_defs}\${ac_dA}ETCSCREENRC\${ac_dB}ETCSCREENRC\${ac_dC}\"$prefix/etc/screenrc\"\${ac_dD}
+\${ac_uA}ETCSCREENRC\${ac_uB}ETCSCREENRC\${ac_uC}\"$prefix/etc/screenrc\"\${ac_uD}
+\${ac_eA}ETCSCREENRC\${ac_eB}ETCSCREENRC\${ac_eC}\"$prefix/etc/screenrc\"\${ac_eD}
+"
+}
+
+fi
+
+
+# The preferred way to propogate these variables is regular @ substitutions.
+if test -n "$prefix"; then
+ ac_prsub="s%^prefix\\([ ]*\\)=\\([ ]*\\).*$%prefix\\1=\\2$prefix%"
+else
+ prefix=/usr/local
+fi
+if test -n "$exec_prefix"; then
+ ac_prsub="$ac_prsub
+s%^exec_prefix\\([ ]*\\)=\\([ ]*\\).*$%exec_prefix\\1=\\2$exec_prefix%"
+else
+ exec_prefix='${prefix}' # Let make expand it.
+fi
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+# Quote sed substitution magic chars in DEFS.
+cat >conftest.def <<EOF
+$DEFS
+EOF
+ac_escape_ampersand_and_backslash='s%[&\\]%\\&%g'
+DEFS=`sed "$ac_escape_ampersand_and_backslash" <conftest.def`
+rm -f conftest.def
+# Substitute for predefined variables.
+
+trap 'rm -f config.status; exit 1' 1 2 15
+echo creating config.status
+rm -f config.status
+cat > config.status <<EOF
+#!/bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $configure_args
+
+ac_cs_usage="Usage: config.status [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo running \${CONFIG_SHELL-/bin/sh} $0 $configure_args --no-create
+ exec \${CONFIG_SHELL-/bin/sh} $0 $configure_args --no-create ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "config.status generated by autoconf version 1.11"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+trap 'rm -fr Makefile doc/Makefile config.h conftest*; exit 1' 1 2 15
+VERSION='$VERSION'
+CC='$CC'
+CPP='$CPP'
+AWK='$AWK'
+INSTALL='$INSTALL'
+INSTALL_PROGRAM='$INSTALL_PROGRAM'
+INSTALL_DATA='$INSTALL_DATA'
+LIBS='$LIBS'
+srcdir='$srcdir'
+top_srcdir='$top_srcdir'
+prefix='$prefix'
+exec_prefix='$exec_prefix'
+ac_prsub='$ac_prsub'
+ac_vpsub='$ac_vpsub'
+extrasub='$extrasub'
+EOF
+cat >> config.status <<\EOF
+
+ac_given_srcdir=$srcdir
+
+CONFIG_FILES=${CONFIG_FILES-"Makefile doc/Makefile"}
+for ac_file in .. ${CONFIG_FILES}; do if test "x$ac_file" != x..; then
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/$ac_dir"
+ else
+ ac_dir_suffix=
+ fi
+
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dir_suffix"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ comment_str="Generated automatically from `echo $ac_file|sed 's|.*/||'`.in by configure."
+ case "$ac_file" in
+ *.c | *.h | *.C | *.cc | *.m ) echo "/* $comment_str */" > "$ac_file" ;;
+ * ) echo "# $comment_str" > "$ac_file" ;;
+ esac
+ sed -e "
+$ac_prsub
+$ac_vpsub
+$extrasub
+s%@VERSION@%$VERSION%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@AWK@%$AWK%g
+s%@INSTALL@%$INSTALL%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@LIBS@%$LIBS%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@prefix@%$prefix%g
+s%@exec_prefix@%$exec_prefix%g
+s%@DEFS@%-DHAVE_CONFIG_H%" $ac_given_srcdir/${ac_file}.in >> $ac_file
+fi; done
+
+# These sed commands are put into ac_sed_defs when defining a macro.
+# They are broken into pieces to make the sed script easier to manage.
+# They are passed to sed as "A NAME B NAME C VALUE D", where NAME
+# is the cpp macro being defined and VALUE is the value it is being given.
+# Each defining turns into a single global substitution command.
+# Hopefully no one uses "!" as a variable value.
+# Other candidates for the sed separators, like , and @, do get used.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s!^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*!\1#\2'
+ac_dC='\3'
+ac_dD='!g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s!^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)!\1#\2define\3'
+ac_uC=' '
+ac_uD='\4!g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s!^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$!\1#\2define\3'
+ac_eC=' '
+ac_eD='!g'
+rm -f conftest.sed
+EOF
+# Turn off quoting long enough to insert the sed commands.
+rm -f conftest.sh
+cat > conftest.sh <<EOF
+$ac_sed_defs
+EOF
+
+# Break up $ac_sed_defs (now in conftest.sh) because some shells have a limit
+# on the size of here documents.
+
+# Maximum number of lines to put in a single here document.
+ac_max_sh_lines=9
+
+while :
+do
+ # wc gives bogus results for an empty file on some AIX systems.
+ ac_lines=`grep -c . conftest.sh`
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ rm -f conftest.s1 conftest.s2
+ sed ${ac_max_sh_lines}q conftest.sh > conftest.s1 # Like head -9.
+ sed 1,${ac_max_sh_lines}d conftest.sh > conftest.s2 # Like tail +10.
+ # Write a limited-size here document to append to conftest.sed.
+ echo 'cat >> conftest.sed <<CONFEOF' >> config.status
+ cat conftest.s1 >> config.status
+ echo 'CONFEOF' >> config.status
+ rm -f conftest.s1 conftest.sh
+ mv conftest.s2 conftest.sh
+done
+rm -f conftest.sh
+
+# Now back to your regularly scheduled config.status.
+cat >> config.status <<\EOF
+# This sed command replaces #undef's with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it in
+# config.h.
+cat >> conftest.sed <<\CONFEOF
+s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+CONFEOF
+rm -f conftest.h
+# Break up the sed commands because old seds have small limits.
+ac_max_sed_lines=20
+
+CONFIG_HEADERS=${CONFIG_HEADERS-"config.h"}
+for ac_file in .. ${CONFIG_HEADERS}; do if test "x$ac_file" != x..; then
+ echo creating $ac_file
+
+ cp $ac_given_srcdir/$ac_file.in conftest.h1
+ cp conftest.sed conftest.stm
+ while :
+ do
+ ac_lines=`grep -c . conftest.stm`
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ rm -f conftest.s1 conftest.s2 conftest.h2
+ sed ${ac_max_sed_lines}q conftest.stm > conftest.s1 # Like head -20.
+ sed 1,${ac_max_sed_lines}d conftest.stm > conftest.s2 # Like tail +21.
+ sed -f conftest.s1 < conftest.h1 > conftest.h2
+ rm -f conftest.s1 conftest.h1 conftest.stm
+ mv conftest.h2 conftest.h1
+ mv conftest.s2 conftest.stm
+ done
+ rm -f conftest.stm conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.h1 >> conftest.h
+ rm -f conftest.h1
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ # The file exists and we would not be changing it.
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+rm -f conftest.sed
+
+
+
+exit 0
+EOF
+chmod +x config.status
+# Some shells look in PATH for config.status without the "./".
+test -n "$no_create" || ${CONFIG_SHELL-/bin/sh} ./config.status
+
+
+# a hook for preserving undef directive in config.h
+if test -z "$no_create" ; then
+mv config.h conftest
+sed -e 's@^\(.*\)defin.\( .*\) .*/\*\(.*KEEP_UNDEF_HERE\)@\1undef\2 /\*\3@' < conftest > config.h
+rm -f conftest
+fi
+cat >> config.status << EOF
+mv config.h conftest
+sed -e 's@^\(.*\)defin.\( .*\) .*/\*\(.*KEEP_UNDEF_HERE\)@\1undef\2 /\*\3@' < conftest > config.h
+rm -f conftest
+EOF
+
+echo ""
+if test -z "$AWK"; then
+echo "!!! Since you have no awk you must copy the files 'comm.h.dist'"
+echo "!!! and 'term.h.dist' to 'comm.h' and 'term.h'."
+echo "!!! Do _not_ change the user configuration section in config.h!"
+echo "Please check the pathnames in the Makefile."
+else
+echo "Now please check the pathnames in the Makefile and the user"
+echo "configuration section in config.h."
+fi
+echo "Then type 'make' to make screen. Good luck."
+echo ""
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..a655f0a
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,1033 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl $Id: configure.in,v 1.17 1994/05/31 12:31:46 mlschroe Exp $ FAU
+dnl
+dnl Many thanks to David MacKenzie for writing autoconf and
+dnl providing a sample configure.in file for screen.
+dnl
+AC_REVISION($Revision: 1.17 $)dnl
+AC_INIT(screen.c)
+AC_CONFIG_HEADER(config.h)
+
+dnl
+dnl Define some useful macros
+dnl
+define(AC_PROGRAM_SOURCE,
+[AC_REQUIRE([AC_PROG_CPP])AC_PROVIDE([$0])cat > conftest.c <<EOF
+[$1]
+_CUT_HERE_
+[$2]
+EOF
+$CPP $DEFS conftest.c 2>/dev/null | sed -e '1,/_CUT_HERE_/d' > conftest.out
+. ./conftest.out
+rm -f conftest*
+])dnl
+dnl
+define(AC_NOTE,
+[test -n "$silent" || echo "$1"])dnl
+
+dnl
+dnl Extract version from patchlevel.h
+dnl
+rev=`sed < ${srcdir}/patchlevel.h -n -e '/#define REV/s/#define REV *//p'`
+vers=`sed < ${srcdir}/patchlevel.h -n -e '/#define VERS/s/#define VERS *//p'`
+pat=`sed < ${srcdir}/patchlevel.h -n -e '/#define PATCHLEVEL/s/#define PATCHLEVEL *//p'`
+VERSION="$rev.$vers.$pat"
+AC_NOTE(this is screen version $VERSION)
+AC_SUBST(VERSION)
+AC_PREFIX(gzip)
+
+AC_PROG_CC
+AC_PROG_CPP
+AC_GCC_TRADITIONAL
+AC_ISC_POSIX
+
+AC_TEST_PROGRAM(main(){exit(0);},,AC_ERROR(Can't run the compiler - sorry))
+
+AC_TEST_PROGRAM([
+main()
+{
+ int __something_strange_();
+ __something_strange_(0);
+}
+],AC_ERROR(Your compiler does not set the exit status - sorry))
+
+AC_PROG_AWK
+
+AC_PROG_INSTALL
+
+if test -f etc/toolcheck; then
+AC_CHECKING(for buggy tools)
+sh etc/toolcheck
+fi
+
+dnl
+dnl **** special unix variants ****
+dnl
+if test -n "$ISC"; then
+ AC_DEFINE(ISC) LIBS="$LIBS -linet"
+fi
+
+dnl AC_CHECKING(for OSF1)
+dnl if test -f /bin/uname ; then
+dnl if test `/bin/uname` = OSF1 || test -f /osf_boot; then
+dnl AC_DEFINE(OSF1) # this disables MIPS again....
+dnl fi
+dnl fi
+
+if test -f /sysV68 ; then
+AC_DEFINE(sysV68)
+fi
+
+AC_CHECKING(for MIPS)
+if test -f /lib/libmld.a || test -f /usr/lib/libmld.a || test -f /usr/lib/cmplrs/cc/libmld.a; then
+test -f /bin/mx || LIBS="$LIBS -lmld" # for nlist. But not on alpha.
+dnl djm@eng.umd.edu: "... for one thing, it doubles the size of the executable"
+dnl
+if test -r /dev/ptc; then
+AC_DEFINE(MIPS)
+AC_COMPILE_CHECK(wait3, , [wait3();], ,
+AC_COMPILE_CHECK(wait2, , [wait2();],
+dnl John Rouillard (rouilj@sni-usa.com):
+dnl need -I/usr/include/bsd in RISCOS otherwise sockets are broken, no
+dnl job control etc.
+dnl Detect RISCOS if wait2 is present, but not wait3.
+AC_DEFINE(USE_WAIT2) LIBS="$LIBS -lbsd" ; CC="$CC -I/usr/include/bsd"
+))
+fi
+fi
+
+AC_CHECKING(for Ultrix)
+AC_PROGRAM_EGREP(yes,
+[#if defined(ultrix) || defined(__ultrix)
+ yes
+#endif
+], ULTRIX=1)
+
+if test -f /usr/lib/libpyr.a ; then
+oldlibs="$LIBS"
+LIBS="$LIBS -lpyr"
+AC_COMPILE_CHECK(Pyramid OSX,,[open_controlling_pty("");],AC_DEFINE(OSX),LIBS="oldlibs")
+fi
+
+dnl ghazi@caip.rutgers.edu (Kaveh R. Ghazi):
+dnl BBN butterfly is not POSIX, but a MACH BSD system.
+dnl Do not define POSIX and TERMIO.
+AC_CHECKING(for butterfly)
+AC_PROGRAM_EGREP(yes,
+[#if defined(butterfly)
+ yes
+#endif
+], butterfly=1)
+
+if test -z "$butterfly"; then
+if test -n "$ULTRIX"; then
+ test -z "$GCC" && CC="$CC -YBSD"
+fi
+AC_CHECKING(for POSIX.1)
+AC_PROGRAM_EGREP(yes,
+[#include <sys/types.h>
+#include <unistd.h>
+main () {
+#ifdef _POSIX_VERSION
+ yes
+#endif
+], AC_NOTE(- you have a POSIX system) AC_DEFINE(POSIX) posix=1)
+fi
+
+AC_COMPILE_CHECK([System V],
+[#include <sys/types.h>
+#include <signal.h>
+#include <fcntl.h>], [int x = SIGCHLD | FNDELAY;], , AC_DEFINE(SYSV))
+
+AC_CHECKING(for sequent/ptx)
+AC_PROGRAM_EGREP(yes,
+[#ifdef _SEQUENT_
+ yes
+#endif
+], LIBS="$LIBS -lsocket -linet";seqptx=1)
+
+oldlibs="$LIBS"
+LIBS="$LIBS -lelf"
+AC_COMPILE_CHECK(SVR4,[#include <utmpx.h>
+],,
+AC_HEADER_CHECK(dwarf.h, AC_DEFINE(SVR4) AC_DEFINE(BUGGYGETLOGIN),
+AC_HEADER_CHECK(elf.h, AC_DEFINE(SVR4) AC_DEFINE(BUGGYGETLOGIN)))
+,LIBS="$oldlibs")
+
+
+dnl
+dnl **** typedefs ****
+dnl
+dnl AC_CHECKING(for pid_t)
+dnl AC_PROGRAM_EGREP(pid_t,[#include <sys/types.h>
+dnl ],AC_DEFINE(PID_T_DEFINED))
+dnl
+dnl AC_CHECKING(for sig_t)
+dnl AC_PROGRAM_EGREP(sig_t,[#include <sys/types.h>
+dnl #include <signal.h>
+dnl ],AC_DEFINE(SIG_T_DEFINED))
+dnl
+dnl AC_CHECKING(for uid_t)
+dnl AC_PROGRAM_EGREP(uid_t,[#include <sys/types.h>
+dnl ],AC_DEFINE(UID_T_DEFINED))
+
+dnl
+dnl **** Job control ****
+dnl
+
+AC_COMPILE_CHECK([BSD job control],
+[#include <sys/types.h>
+#include <sys/ioctl.h>
+], [
+#ifdef POSIX
+tcsetpgrp(0, 0);
+#else
+int x = TIOCSPGRP;
+#ifdef SYSV
+setpgrp();
+#else
+int y = TIOCNOTTY;
+#endif
+#endif
+], AC_NOTE(- you have jobcontrol) AC_DEFINE(BSDJOBS), AC_NOTE(- you don't have jobcontrol))
+
+dnl
+dnl **** setreuid(), seteuid() ****
+dnl
+AC_COMPILE_CHECK(setreuid, , [
+#ifdef __hpux
+setresuid(0, 0, 0);
+#else
+setreuid(0, 0);
+#endif
+], AC_DEFINE(HAVE_SETREUID))
+dnl
+dnl seteuid() check:
+dnl linux seteuid was broken before V1.1.11
+dnl NeXT, AUX, ISC, and ultrix are still broken (no saved uid support)
+dnl Solaris seteuid doesn't change the saved uid, bad for
+dnl multiuser screen sessions
+AC_COMPILE_CHECK(seteuid, , [
+#if defined(linux) || defined(NeXT) || defined(_AUX_SOURCE) || defined(AUX) || defined(ultrix) || (defined(sun) && defined(SVR4)) || defined(ISC) || defined(sony_news)
+seteuid_is_broken(0);
+#else
+seteuid(0);
+#endif
+], AC_DEFINE(HAVE_SETEUID))
+dnl
+dnl **** select() ****
+dnl
+
+AC_COMPILE_CHECK(select,,[select(0, 0, 0, 0, 0);],,
+LIBS="$LIBS -lnet -lnsl"
+AC_COMPILE_CHECK(select with $LIBS,,[select(0, 0, 0, 0, 0);],,
+AC_ERROR(!!! no select - no screen))
+)
+dnl
+dnl **** FIFO tests ****
+dnl
+
+AC_CHECKING(fifos)
+AC_TEST_PROGRAM([
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+#ifndef S_IFIFO
+#define S_IFIFO 0010000
+#endif
+
+char *fin = "/tmp/conftest$$";
+
+main()
+{
+ struct stat stb;
+ int f;
+
+ (void)alarm(5);
+#ifdef POSIX
+ if (mkfifo(fin, 0777))
+#else
+ if (mknod(fin, S_IFIFO|0777, 0))
+#endif
+ exit(1);
+ if (stat(fin, &stb) || (stb.st_mode & S_IFIFO) != S_IFIFO)
+ exit(1);
+ close(0);
+#ifdef __386BSD__
+ /*
+ * The next test fails under 386BSD, but screen works using fifos.
+ * Fifos in O_RDWR mode are only used for the BROKEN_PIPE case and for
+ * the select() configuration test.
+ */
+ exit(0);
+#endif
+ if (open(fin, O_RDONLY | O_NONBLOCK))
+ exit(1);
+ if (fork() == 0)
+ {
+ close(0);
+ if (open(fin, O_WRONLY | O_NONBLOCK))
+ exit(1);
+ close(0);
+ if (open(fin, O_WRONLY | O_NONBLOCK))
+ exit(1);
+ if (write(0, "TEST", 4) == -1)
+ exit(1);
+ exit(0);
+ }
+ f = 1;
+ if (select(1, &f, 0, 0, 0) == -1)
+ exit(1);
+ exit(0);
+}
+], AC_NOTE(- your fifos are usable);fifo=1,
+AC_NOTE(- your fifos are not usable))
+rm -f /tmp/conftest*
+
+if test -n "$fifo"; then
+AC_CHECKING(for broken fifo implementation)
+AC_TEST_PROGRAM([
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+#ifndef S_IFIFO
+#define S_IFIFO 0010000
+#endif
+
+char *fin = "/tmp/conftest$$";
+
+main()
+{
+ struct timeval tv;
+ int r, x;
+
+#ifdef POSIX
+ if (mkfifo(fin, 0600))
+#else
+ if (mknod(fin, S_IFIFO|0600, 0))
+#endif
+ exit(1);
+ close(0);
+ if (open(fin, O_RDONLY|O_NONBLOCK))
+ exit(1);
+ r = 1;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ if (select(1, &r, 0, 0, &tv))
+ exit(1);
+ exit(0);
+}
+], AC_NOTE(- your implementation is ok),
+AC_NOTE(- you have a broken implementation) AC_DEFINE(BROKEN_PIPE) fifobr=1)
+rm -f /tmp/conftest*
+fi
+
+dnl
+dnl **** SOCKET tests ****
+dnl
+dnl may need LIBS="$LIBS -lsocket" here
+dnl
+
+AC_CHECKING(sockets)
+AC_TEST_PROGRAM([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
+
+char *son = "/tmp/conftest$$";
+
+main()
+{
+ int s1, s2, s3, l;
+ struct sockaddr_un a;
+
+ (void)alarm(5);
+ if ((s1 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ exit(1);
+ a.sun_family = AF_UNIX;
+ strcpy(a.sun_path, son);
+ (void) unlink(son);
+ if (bind(s1, (struct sockaddr *) &a, strlen(son)+2) == -1)
+ exit(1);
+ if (listen(s1, 2))
+ exit(1);
+ if (fork() == 0)
+ {
+ if ((s2 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ kill(getppid(), 3);
+ (void)connect(s2, (struct sockaddr *)&a, strlen(son) + 2);
+ if (write(s2, "HELLO", 5) == -1)
+ kill(getppid(), 3);
+ exit(0);
+ }
+ l = sizeof(a);
+ close(0);
+ if (accept(s1, &a, &l))
+ exit(1);
+ l = 1;
+ if (select(1, &l, 0, 0, 0) == -1)
+ exit(1);
+ exit(0);
+}
+], AC_NOTE(- your sockets are usable);sock=1,
+AC_NOTE(- your sockets are not usable))
+rm -f /tmp/conftest*
+
+if test -n "$sock"; then
+AC_CHECKING(socket implementation)
+AC_TEST_PROGRAM([
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+char *son = "/tmp/conftest$$";
+
+main()
+{
+ int s;
+ struct stat stb;
+ struct sockaddr_un a;
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ exit(0);
+ a.sun_family = AF_UNIX;
+ strcpy(a.sun_path, son);
+ (void) unlink(son);
+ if (bind(s, (struct sockaddr *) &a, strlen(son)+2) == -1)
+ exit(0);
+ if (stat(son, &stb))
+ exit(1);
+ close(s);
+ exit(0);
+}
+],AC_NOTE(- you are normal),
+AC_NOTE(- unix domain sockets are not kept in the filesystem)
+AC_DEFINE(SOCK_NOT_IN_FS) socknofs=1)
+rm -f /tmp/conftest*
+fi
+
+
+dnl
+dnl **** choose sockets or fifos ****
+dnl
+if test -n "$fifo"; then
+ if test -n "$sock"; then
+ if test -n "$nore"; then
+ AC_NOTE(- hmmm... better take the fifos)
+ AC_DEFINE(NAMEDPIPE)
+ elif test -n "$fifobr"; then
+ AC_NOTE(- as your fifos are broken lets use the sockets.)
+ else
+ AC_NOTE(- both sockets and fifos usable. let's take fifos.)
+ AC_DEFINE(NAMEDPIPE)
+ fi
+ else
+ AC_NOTE(- using named pipes, of course)
+ AC_DEFINE(NAMEDPIPE)
+ fi
+elif test -n "$sock"; then
+ AC_NOTE(- using unix-domain sockets, of course)
+else
+ AC_ERROR(you have neither usable sockets nor usable pipes -> no screen)
+fi
+
+dnl
+dnl **** check the select implementation ****
+dnl
+
+AC_CHECKING(select return value)
+AC_TEST_PROGRAM([
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+char *nam = "/tmp/conftest$$";
+
+#ifdef NAMEDPIPE
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+#ifndef S_IFIFO
+#define S_IFIFO 0010000
+#endif
+
+
+main()
+{
+ int l;
+
+#ifdef __FreeBSD__
+/* From Andrew A. Chernov (ache@astral.msk.su):
+ * opening RDWR fifo fails in BSD 4.4, but select return values is
+ * right.
+ */
+ exit(0);
+#endif
+ (void)alarm(5);
+#ifdef POSIX
+ if (mkfifo(nam, 0777))
+#else
+ if (mknod(nam, S_IFIFO|0777, 0))
+#endif
+ exit(1);
+ close(0);
+ if (open(nam, O_RDWR | O_NONBLOCK))
+ exit(1);
+ if (write(0, "TEST", 4) == -1)
+ exit(1);
+
+#else
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+main()
+{
+ int s1, s2, s3, l;
+ struct sockaddr_un a;
+
+ (void)alarm(5);
+ if ((s1 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ exit(1);
+ a.sun_family = AF_UNIX;
+ strcpy(a.sun_path, nam);
+ (void) unlink(nam);
+ if (bind(s1, (struct sockaddr *) &a, strlen(nam)+2) == -1)
+ exit(1);
+ if (listen(s1, 2))
+ exit(1);
+ if (fork() == 0)
+ {
+ if ((s2 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ kill(getppid(), 3);
+ (void)connect(s2, (struct sockaddr *)&a, strlen(nam) + 2);
+ if (write(s2, "HELLO", 5) == -1)
+ kill(getppid(), 3);
+ exit(0);
+ }
+ l = sizeof(a);
+ close(0);
+ if (accept(s1, (struct sockaddr *)&a, &l))
+ exit(1);
+#endif
+
+
+ l = 1;
+ if (select(1, &l, 0, 0, 0) == -1)
+ exit(1);
+ if (select(1, &l, &l, 0, 0) != 2)
+ exit(1);
+ exit(0);
+}
+],AC_NOTE(- select is ok),
+AC_NOTE(- it is not usable) AC_DEFINE(SELECT_BROKEN))
+
+dnl
+dnl **** termcap or terminfo ****
+dnl
+AC_CHECKING(for tgetent)
+olibs="$LIBS"
+LIBS="-lcurses $olibs"
+AC_COMPILE_CHECK(libcurses,,[
+#ifdef __hpux
+__sorry_hpux_libcurses_is_totally_broken_in_10_10();
+#else
+tgetent((char *)0, (char *)0);
+#endif
+],,
+LIBS="-ltermcap $olibs"
+AC_COMPILE_CHECK(libtermcap,,tgetent((char *)0, (char *)0);,,
+LIBS="-ltermlib $olibs"
+AC_COMPILE_CHECK(libtermlib,,tgetent((char *)0, (char *)0);,,
+AC_ERROR(!!! no tgetent - no screen))))
+
+AC_TEST_PROGRAM([
+main()
+{
+ exit(strcmp(tgoto("%p1%d", 0, 1), "1") ? 0 : 1);
+}], AC_NOTE(- you use the termcap database),
+AC_NOTE(- you use the terminfo database) AC_DEFINE(TERMINFO))
+AC_COMPILE_CHECK(ospeed,extern short ospeed;,ospeed=5;,,AC_DEFINE(NEED_OSPEED))
+
+dnl
+dnl **** PTY specific things ****
+dnl
+AC_CHECKING(for /dev/ptc)
+if test -r /dev/ptc; then
+AC_DEFINE(HAVE_DEV_PTC)
+fi
+
+AC_CHECKING(for ptyranges)
+if test -d /dev/ptym ; then
+pdir='/dev/ptym'
+else
+pdir='/dev'
+fi
+ptys=`echo $pdir/pty??`
+if test "$ptys" != "$pdir/pty??" ; then
+p0=`echo $ptys | tr ' ' '\012' | sed -e 's/^.*\(.\).$/\1/g' | sort -u | tr -d '\012'`
+p1=`echo $ptys | tr ' ' '\012' | sed -e 's/^.*\(.\)$/\1/g' | sort -u | tr -d '\012'`
+AC_DEFINE_UNQUOTED(PTYRANGE0,\"$p0\")
+AC_DEFINE_UNQUOTED(PTYRANGE1,\"$p1\")
+fi
+
+dnl **** pty mode/group handling ****
+dnl
+dnl support provided by Luke Mewburn <lm@rmit.edu.au>, 931222
+AC_CHECKING(default tty permissions/group)
+rm -f conftest_grp
+AC_TEST_PROGRAM([
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+main()
+{
+ struct stat sb;
+ char *x,*ttyname();
+ int om, m;
+ FILE *fp;
+
+ if (!(x = ttyname(0))) exit(1);
+ if (stat(x, &sb)) exit(1);
+ om = sb.st_mode;
+ if (om & 002) exit(0);
+ m = system("mesg y");
+ if (m == -1 || m == 127) exit(1);
+ if (stat(x, &sb)) exit(1);
+ m = sb.st_mode;
+ if (chmod(x, om)) exit(1);
+ if (m & 002) exit(0);
+ if (sb.st_gid == getgid()) exit(1);
+ if (!(fp=fopen("conftest_grp", "w")))
+ exit(1);
+ fprintf(fp, "%d\n", sb.st_gid);
+ fclose(fp);
+ exit(0);
+}
+],[
+ if test -f conftest_grp; then
+ ptygrp=`cat conftest_grp`
+ AC_NOTE(- pty mode: 0620, group: $ptygrp)
+ AC_DEFINE(PTYMODE, 0620)
+ AC_DEFINE_UNQUOTED(PTYGROUP,$ptygrp)
+ else
+ AC_NOTE(- ptys are world accessable)
+ fi
+],
+ AC_NOTE(- can't determine - assume ptys are world accessable)
+)
+rm -f conftest_grp
+
+dnl
+dnl **** utmp handling ****
+dnl
+dnl linux has a void pututline, grrr, gcc will error when evaluating it.
+AC_COMPILE_CHECK(getutent, [#include <time.h> /* to get time_t on SCO */
+#include <sys/types.h>
+#if defined(SVR4) && !defined(DGUX)
+#include <utmpx.h>
+#define utmp utmpx
+#else
+#include <utmp.h>
+#endif
+#ifdef __hpux
+#define pututline _pututline
+#endif
+],
+[int x = DEAD_PROCESS; struct utmp *y = pututline((struct utmp *)0); getutent();], AC_DEFINE(GETUTENT),
+olibs="$LIBS"
+LIBS="$LIBS -lgen"
+AC_COMPILE_CHECK(getutent with -lgen, [#include <time.h>
+#include <sys/types.h>
+#if defined(SVR4) && !defined(DGUX)
+#include <utmpx.h>
+#define utmp utmpx
+#else
+#include <utmp.h>
+#endif
+#ifdef __hpux
+#define pututline _pututline
+#endif
+],
+[int x = DEAD_PROCESS; struct utmp *y = pututline((struct utmp *)0); getutent();], AC_DEFINE(GETUTENT), LIBS="$olibs")
+)
+AC_COMPILE_CHECK(ut_host, [#include <time.h>
+#include <sys/types.h>
+#if defined(SVR4) && !defined(DGUX)
+#include <utmpx.h>
+#define utmp utmpx
+#else
+#include <utmp.h>
+#endif
+],[struct utmp u; u.ut_host[0] = 0;], AC_DEFINE(UTHOST))
+
+
+dnl
+dnl **** loadav ****
+dnl
+AC_CHECKING(for libutil(s))
+test -f /usr/lib/libutils.a && LIBS="$LIBS -lutils"
+test -f /usr/lib/libutil.a && LIBS="$LIBS -lutil"
+
+AC_COMPILE_CHECK(getloadavg, , [getloadavg((double *)0, 0);],
+AC_DEFINE(LOADAV_GETLOADAVG) load=1,
+if test -f /usr/lib/libkvm.a ; then
+olibs="$LIBS"
+LIBS="$LIBS -lkvm"
+AC_COMPILE_CHECK(getloadavg with -lkvm, , [getloadavg((double *)0, 0);],
+AC_DEFINE(LOADAV_GETLOADAVG) load=1, LIBS="$olibs")
+fi
+)
+
+if test -z "$load" ; then
+AC_PROGRAM_EGREP(yes,
+[#if defined(NeXT) || defined(apollo) || defined(linux)
+ yes
+#endif
+], load=1)
+fi
+if test -z "$load" ; then
+AC_CHECKING(for kernelfile)
+for core in /unix /vmunix /dynix /hp-ux /xelos /dev/ksyms /kernel/unix /kernel/genunix /unicos /mach /netbsd /386bsd /dgux /bsd /stand/vmunix; do
+ if test -f $core || test -c $core; then
+ break
+ fi
+done
+if test ! -f $core && test ! -c $core ; then
+ AC_NOTE(- no kernelfile found)
+else
+ AC_NOTE(- using kernelfile '$core')
+ AC_DEFINE_UNQUOTED(LOADAV_UNIX,\"$core\")
+ AC_HEADER_CHECK(nlist.h,
+ [AC_DEFINE(NLIST_STRUCT)
+ AC_COMPILE_CHECK(n_un in struct nlist, [#include <nlist.h>],
+ [struct nlist n; n.n_un.n_name = 0;],
+ AC_DEFINE(NLIST_NAME_UNION))])
+
+ AC_CHECKING(for nlist declaration)
+ AC_PROGRAM_EGREP([nlist(( | )( | )*.*\(|\()],[
+#ifdef NLIST_STRUCT
+# include <nlist.h>
+#else
+# include <a.out.h>
+#endif
+],AC_DEFINE(NLIST_DECLARED))
+
+ AC_CHECKING(for avenrun symbol)
+ for av in avenrun _avenrun _Loadavg ; do
+ AC_TEST_PROGRAM([
+#include <sys/types.h>
+#ifdef NLIST_STRUCT
+#include <nlist.h>
+#else
+#include <a.out.h>
+#endif
+
+#ifdef __sgi
+# if _MIPS_SZLONG == 64
+# define nlist nlist64
+# endif
+#endif
+
+struct nlist nl[2];
+
+main()
+{
+#if !defined(_AUX_SOURCE) && !defined(AUX)
+# ifdef NLIST_NAME_UNION
+ nl[0].n_un.n_name = "$av";
+# else
+ nl[0].n_name = "$av";
+# endif
+#else
+ strncpy(nl[0].n_name, "$av", sizeof(nl[0].n_name));
+#endif
+ nlist(LOADAV_UNIX, nl);
+ if (nl[0].n_value == 0)
+ exit(1);
+ exit(0);
+}
+ ],avensym=$av;break)
+ done
+ if test -z "$avensym" ; then
+ AC_NOTE(- no avenrun symbol found)
+ else
+ AC_NOTE(- using avenrun symbol '$avensym')
+ AC_DEFINE_UNQUOTED(LOADAV_AVENRUN,\"$avensym\")
+ load=1
+ fi
+fi
+fi
+
+AC_PROGRAM_SOURCE([
+#include <sys/types.h>
+#include <sys/param.h>
+],[
+#if ((defined(hp300) && !defined(__hpux)) || defined(sun) || (defined(ultrix) && defined(mips)) || defined(_SEQUENT_) || defined(sgi) || defined(SVR4) || defined(sony_news) || defined(__alpha) || defined(_IBMR2) || defined(_AUX_SOURCE) || defined(AUX) || defined(m88k))
+loadtype=long
+# if defined(apollo) || defined(_IBMR2) || defined(_AUX_SOURCE) || defined(AUX)
+loadscale=65536
+# else
+# if defined(FSCALE) && !defined(__osf__)
+# undef FSCALE
+loadscale=FSCALE
+# else
+# ifdef sgi
+loadscale=1024
+loadtype=int
+# else
+# if defined(MIPS) || defined(SVR4) || defined(m88k)
+loadscale=256
+# else /* not MIPS */
+loadscale=1000 /* our default value */
+# endif /* MIPS */
+# endif /* sgi */
+# endif /* not FSCALE */
+# endif /* not apollo */
+#else
+loadtype=double
+loadscale=1
+#endif
+#ifdef alliant
+loadnum=4
+#else
+loadnum=3
+#endif
+])
+
+if test -n "$load" ; then AC_DEFINE(LOADAV) fi
+if test -n "$loadtype" ; then AC_DEFINE_UNQUOTED(LOADAV_TYPE,$loadtype) fi
+if test -n "$loadnum" ; then AC_DEFINE_UNQUOTED(LOADAV_NUM,$loadnum) fi
+if test -n "$loadscale" ; then AC_DEFINE_UNQUOTED(LOADAV_SCALE,$loadscale) fi
+
+
+dnl
+dnl **** signal handling ****
+dnl
+if test -n "$posix" ; then
+
+dnl POSIX has reliable signals with void return type.
+AC_NOTE(assuming posix signal definition)
+AC_DEFINE(SIGVOID)
+
+else
+
+AC_COMPILE_CHECK([return type of signal handlers],
+[#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+extern void (*signal ()) ();], [int i;], AC_DEFINE(SIGVOID))
+AC_COMPILE_CHECK(sigset, [
+#include <sys/types.h>
+#include <signal.h>
+], [
+#ifdef SIGVOID
+sigset(0, (void (*)())0);
+#else
+sigset(0, (int (*)())0);
+#endif
+], AC_DEFINE(USESIGSET))
+AC_CHECKING(signal implementation)
+AC_TEST_PROGRAM([
+#include <sys/types.h>
+#include <signal.h>
+
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
+#endif
+#ifdef USESIGSET
+#define signal sigset
+#endif
+
+int got;
+
+#ifdef SIGVOID
+void
+#endif
+hand()
+{
+ got++;
+}
+
+main()
+{
+ /* on hpux we use sigvec to get bsd signals */
+#ifdef __hpux
+ (void)signal(SIGCLD, hand);
+ kill(getpid(), SIGCLD);
+ kill(getpid(), SIGCLD);
+ if (got < 2)
+ exit(1);
+#endif
+ exit(0);
+}
+],,AC_DEFINE(SYSVSIGS))
+
+fi
+
+dnl
+dnl **** libraries ****
+dnl
+
+AC_CHECKING(for crypt and sec libraries)
+test -f /lib/libcrypt_d.a || test -f /usr/lib/libcrypt_d.a && LIBS="$LIBS -lcrypt_d"
+test -f /lib/libcrypt.a || test -f /usr/lib/libcrypt.a && LIBS="$LIBS -lcrypt"
+test -f /lib/libsec.a || test -f /usr/lib/libsec.a && LIBS="$LIBS -lsec"
+test -f /lib/libshadow.a || test -f /usr/lib/libshadow.a && LIBS="$LIBS -lshadow"
+
+oldlibs="$LIBS"
+LIBS="$LIBS -lsun"
+AC_COMPILE_CHECK(IRIX sun library,,,,LIBS="$oldlibs")
+
+
+dnl
+dnl **** misc things ****
+dnl
+AC_COMPILE_CHECK(wait union,[#include <sys/types.h>
+#include <sys/wait.h>
+],[
+ union wait x;
+ int y;
+#ifdef WEXITSTATUS
+ y = WEXITSTATUS(x);
+#endif
+],AC_DEFINE(BSDWAIT))
+
+if test -z "$butterfly"; then
+AC_CHECKING(for termio or termios)
+AC_TEST_CPP([#include <termio.h>], AC_DEFINE(TERMIO),
+if test -n "$posix"; then
+AC_TEST_CPP([#include <termios.h>], AC_DEFINE(TERMIO))
+fi
+)
+fi
+
+dnl AC_HEADER_CHECK(shadow.h, AC_DEFINE(SHADOWPW))
+AC_COMPILE_CHECK(getspnam, [#include <shadow.h>], [getspnam("x");],
+ AC_DEFINE(SHADOWPW))
+
+AC_COMPILE_CHECK(getttyent, , [getttyent();], AC_DEFINE(GETTTYENT))
+
+AC_CHECKING(whether memcpy/memmove/bcopy handles overlapping arguments)
+AC_TEST_PROGRAM([
+main() {
+ char buf[10];
+ strcpy(buf, "abcdefghi");
+ bcopy(buf, buf + 2, 3);
+ if (strncmp(buf, "ababcf", 6))
+ exit(1);
+ strcpy(buf, "abcdefghi");
+ bcopy(buf + 2, buf, 3);
+ if (strncmp(buf, "cdedef", 6))
+ exit(1);
+ exit(0); /* libc version works properly. */
+}], AC_DEFINE(USEBCOPY))
+
+AC_TEST_PROGRAM([
+#define bcopy(s,d,l) memmove(d,s,l)
+main() {
+ char buf[10];
+ strcpy(buf, "abcdefghi");
+ bcopy(buf, buf + 2, 3);
+ if (strncmp(buf, "ababcf", 6))
+ exit(1);
+ strcpy(buf, "abcdefghi");
+ bcopy(buf + 2, buf, 3);
+ if (strncmp(buf, "cdedef", 6))
+ exit(1);
+ exit(0); /* libc version works properly. */
+}], AC_DEFINE(USEMEMMOVE))
+
+
+AC_TEST_PROGRAM([
+#define bcopy(s,d,l) memcpy(d,s,l)
+main() {
+ char buf[10];
+ strcpy(buf, "abcdefghi");
+ bcopy(buf, buf + 2, 3);
+ if (strncmp(buf, "ababcf", 6))
+ exit(1);
+ strcpy(buf, "abcdefghi");
+ bcopy(buf + 2, buf, 3);
+ if (strncmp(buf, "cdedef", 6))
+ exit(1);
+ exit(0); /* libc version works properly. */
+}], AC_DEFINE(USEMEMCPY))
+
+AC_CHECKING(for long file names)
+(echo 1 > /tmp/conftest9012345) 2>/dev/null
+(echo 2 > /tmp/conftest9012346) 2>/dev/null
+val=`cat /tmp/conftest9012345 2>/dev/null`
+if test -f /tmp/conftest9012345 && test "$val" = 1; then :
+else AC_DEFINE(NAME_MAX, 14)
+fi
+rm -f /tmp/conftest*
+
+AC_COMPILE_CHECK(vsprintf, [#include <varargs.h>
+#include <stdio.h>], [vsprintf();], AC_DEFINE(USEVARARGS))
+
+AC_DIR_HEADER
+AC_XENIX_DIR
+
+AC_COMPILE_CHECK(setenv, , [setenv((char *)0,(char *)0);unsetenv((char *)0);], AC_DEFINE(USESETENV),
+AC_COMPILE_CHECK(putenv, , [putenv((char *)0);unsetenv((char *)0);], ,
+AC_DEFINE(NEEDPUTENV)
+))
+
+AC_COMPILE_CHECK(rename, , [rename(0,0);], , AC_DEFINE(NEED_RENAME))
+AC_COMPILE_CHECK(_exit, , [_exit(0);], AC_DEFINE(HAVE__EXIT))
+AC_COMPILE_CHECK(lstat, , [lstat(0,0);], AC_DEFINE(HAVE_LSTAT))
+AC_COMPILE_CHECK(strerror, ,[strerror(0);], AC_DEFINE(HAVE_STRERROR))
+
+dnl
+dnl **** the end ****
+dnl
+dnl Ptx bug workaround -- insert -lc after -ltermcap
+test -n "$seqptx" && LIBS="-ltermcap -lc -lsocket -linet -lsec -lseq"
+
+AC_TEST_PROGRAM(main(){exit(0);},,AC_ERROR(Can't run the compiler - internal error. Sorry.))
+if test -n "$prefix"; then
+AC_DEFINE_UNQUOTED(ETCSCREENRC,\"$prefix/etc/screenrc\")
+fi
+
+AC_OUTPUT(Makefile doc/Makefile)
+
+# a hook for preserving undef directive in config.h
+if test -z "$no_create" ; then
+mv config.h conftest
+sed -e 's@^\(.*\)defin.\( .*\) .*/\*\(.*KEEP_UNDEF_HERE\)@\1undef\2 /\*\3@' < conftest > config.h
+rm -f conftest
+fi
+cat >> config.status << EOF
+mv config.h conftest
+sed -e 's@^\(.*\)defin.\( .*\) .*/\*\(.*KEEP_UNDEF_HERE\)@\1undef\2 /\*\3@' < conftest > config.h
+rm -f conftest
+EOF
+
+echo ""
+if test -z "$AWK"; then
+echo "!!! Since you have no awk you must copy the files 'comm.h.dist'"
+echo "!!! and 'term.h.dist' to 'comm.h' and 'term.h'."
+echo "!!! Do _not_ change the user configuration section in config.h!"
+echo "Please check the pathnames in the Makefile."
+else
+echo "Now please check the pathnames in the Makefile and the user"
+echo "configuration section in config.h."
+fi
+echo "Then type 'make' to make screen. Good luck."
+echo ""
diff --git a/display.c b/display.c
new file mode 100644
index 0000000..e4cdb1c
--- /dev/null
+++ b/display.c
@@ -0,0 +1,1937 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: display.c,v 1.16 1994/05/31 12:31:50 mlschroe Exp $ FAU")
+
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+
+static void CountChars __P((int));
+static void PutChar __P((int));
+static int BlankResize __P((int, int));
+
+
+extern struct win *windows;
+
+extern int use_hardstatus;
+extern int MsgMinWait;
+extern int Z0width, Z1width;
+extern char *blank, *null;
+extern struct mline mline_blank, mline_null;
+extern struct mchar mchar_null, mchar_blank, mchar_so;
+
+/*
+ * tputs needs this to calculate the padding
+ */
+#ifndef NEED_OSPEED
+extern
+#endif /* NEED_OSPEED */
+short ospeed;
+
+
+struct display *display, *displays;
+
+#ifndef MULTI
+struct display TheDisplay;
+#endif
+
+/*
+ * The default values
+ */
+int defobuflimit = OBUF_MAX;
+#ifdef AUTO_NUKE
+int defautonuke = 0;
+#endif
+
+/*
+ * Default layer management
+ */
+
+void
+DefProcess(bufp, lenp)
+char **bufp;
+int *lenp;
+{
+ *bufp += *lenp;
+ *lenp = 0;
+}
+
+void
+DefRedisplayLine(y, xs, xe, isblank)
+int y, xs, xe, isblank;
+{
+ if (isblank == 0 && y >= 0)
+ DefClearLine(y, xs, xe);
+}
+
+void
+DefClearLine(y, xs, xe)
+int y, xs, xe;
+{
+ DisplayLine(&mline_null, &mline_blank, y, xs, xe);
+}
+
+/*ARGSUSED*/
+int
+DefRewrite(y, xs, xe, doit)
+int y, xs, xe, doit;
+{
+ return EXPENSIVE;
+}
+
+void
+DefSetCursor()
+{
+ GotoPos(0, 0);
+}
+
+/*ARGSUSED*/
+int
+DefResize(wi, he)
+int wi, he;
+{
+ return -1;
+}
+
+void
+DefRestore()
+{
+ InsertMode(0);
+ ChangeScrollRegion(0, D_height - 1);
+ KeypadMode(0);
+ CursorkeysMode(0);
+ CursorVisibility(0);
+ SetRendition(&mchar_null);
+ SetFlow(FLOW_NOW);
+}
+
+/*
+ * Blank layer management
+ */
+
+struct LayFuncs BlankLf =
+{
+ DefProcess,
+ 0,
+ DefRedisplayLine,
+ DefClearLine,
+ DefRewrite,
+ DefSetCursor,
+ BlankResize,
+ DefRestore
+};
+
+struct layer BlankLayer =
+{
+ 0,
+ 0,
+ &BlankLf,
+ 0
+};
+
+/*ARGSUSED*/
+static int
+BlankResize(wi, he)
+int wi, he;
+{
+ return 0;
+}
+
+
+/*
+ * Generate new display
+ */
+
+struct display *
+MakeDisplay(uname, utty, term, fd, pid, Mode)
+char *uname, *utty, *term;
+int fd, pid;
+struct mode *Mode;
+{
+ struct user **u;
+
+ if (!*(u = FindUserPtr(uname)) && UserAdd(uname, (char *)0, u))
+ return 0; /* could not find or add user */
+
+#ifdef MULTI
+ if ((display = (struct display *)malloc(sizeof(*display))) == 0)
+ return 0;
+ bzero((char *) display, sizeof(*display));
+#else
+ if (displays)
+ return 0;
+ display = &TheDisplay;
+#endif
+ display->d_next = displays;
+ displays = display;
+ D_flow = 1;
+ D_nonblock = 0;
+ D_userfd = fd;
+ D_OldMode = *Mode;
+ Resize_obuf(); /* Allocate memory for buffer */
+ D_obufmax = defobuflimit;
+#ifdef AUTO_NUKE
+ D_auto_nuke = defautonuke;
+#endif
+ D_obufp = D_obuf;
+ D_printfd = -1;
+ D_userpid = pid;
+#if defined(POSIX) || defined(TERMIO)
+# ifdef POSIX
+ switch (cfgetospeed(&D_OldMode.tio))
+# else
+ switch (D_OldMode.tio.c_cflag & CBAUD)
+# endif
+ {
+#ifdef B0
+ case B0: D_dospeed = 0; break;
+#endif
+#ifdef B50
+ case B50: D_dospeed = 1; break;
+#endif
+#ifdef B75
+ case B75: D_dospeed = 2; break;
+#endif
+#ifdef B110
+ case B110: D_dospeed = 3; break;
+#endif
+#ifdef B134
+ case B134: D_dospeed = 4; break;
+#endif
+#ifdef B150
+ case B150: D_dospeed = 5; break;
+#endif
+#ifdef B200
+ case B200: D_dospeed = 6; break;
+#endif
+#ifdef B300
+ case B300: D_dospeed = 7; break;
+#endif
+#ifdef B600
+ case B600: D_dospeed = 8; break;
+#endif
+#ifdef B1200
+ case B1200: D_dospeed = 9; break;
+#endif
+#ifdef B1800
+ case B1800: D_dospeed = 10; break;
+#endif
+#ifdef B2400
+ case B2400: D_dospeed = 11; break;
+#endif
+#ifdef B4800
+ case B4800: D_dospeed = 12; break;
+#endif
+#ifdef B9600
+ case B9600: D_dospeed = 13; break;
+#endif
+#ifdef EXTA
+ case EXTA: D_dospeed = 14; break;
+#endif
+#ifdef EXTB
+ case EXTB: D_dospeed = 15; break;
+#endif
+#ifdef B57600
+ case B57600: D_dospeed = 16; break;
+#endif
+#ifdef B115200
+ case B115200: D_dospeed = 17; break;
+#endif
+ default: ;
+ }
+#else /* POSIX || TERMIO */
+ D_dospeed = (short) D_OldMode.m_ttyb.sg_ospeed;
+#endif /* POSIX || TERMIO */
+ debug1("New displays ospeed = %d\n", D_dospeed);
+ strcpy(D_usertty, utty);
+ strcpy(D_termname, term);
+
+ D_user = *u;
+ D_lay = &BlankLayer;
+ D_layfn = BlankLayer.l_layfn;
+ return display;
+}
+
+void
+FreeDisplay()
+{
+ struct win *p;
+#ifdef MULTI
+ struct display *d, **dp;
+#endif
+
+ FreeTransTable();
+ freetty();
+ if (D_tentry)
+ free(D_tentry);
+ D_tentry = 0;
+ D_tcinited = 0;
+#ifdef MULTI
+ for (dp = &displays; (d = *dp) ; dp = &d->d_next)
+ if (d == display)
+ break;
+ ASSERT(d);
+ if (D_status_lastmsg)
+ free(D_status_lastmsg);
+ if (D_obuf)
+ free(D_obuf);
+ *dp = display->d_next;
+ free((char *)display);
+#else /* MULTI */
+ ASSERT(display == displays);
+ ASSERT(display == &TheDisplay);
+ displays = 0;
+#endif /* MULTI */
+ for (p = windows; p; p = p->w_next)
+ {
+ if (p->w_display == display)
+ p->w_display = 0;
+ if (p->w_pdisplay == display)
+ p->w_pdisplay = 0;
+ }
+ display = 0;
+}
+
+/*
+ * if the adaptflag is on, we keep the size of this display, else
+ * we may try to restore our old window sizes.
+ */
+void
+InitTerm(adapt)
+int adapt;
+{
+ ASSERT(display);
+ ASSERT(D_tcinited);
+ D_top = D_bot = -1;
+ PutStr(D_TI);
+ PutStr(D_IS);
+ /* Check for toggle */
+ if (D_IM && strcmp(D_IM, D_EI))
+ PutStr(D_EI);
+ D_insert = 0;
+ /* Check for toggle */
+#ifdef MAPKEYS
+ PutStr(D_KS);
+ PutStr(D_CCS);
+#else
+ if (D_KS && strcmp(D_KS, D_KE))
+ PutStr(D_KE);
+ if (D_CCS && strcmp(D_CCS, D_CCE))
+ PutStr(D_CCE);
+#endif
+ D_keypad = 0;
+ D_cursorkeys = 0;
+ PutStr(D_ME);
+ PutStr(D_EA);
+ PutStr(D_CE0);
+ D_rend = mchar_null;
+ D_atyp = 0;
+ if (adapt == 0)
+ ResizeDisplay(D_defwidth, D_defheight);
+ ChangeScrollRegion(0, D_height - 1);
+ D_x = D_y = 0;
+ Flush();
+ ClearDisplay();
+ debug1("we %swant to adapt all our windows to the display\n",
+ (adapt) ? "" : "don't ");
+ /* In case the size was changed by a init sequence */
+ CheckScreenSize((adapt) ? 2 : 0);
+}
+
+void
+FinitTerm()
+{
+ ASSERT(display);
+ if (D_tcinited)
+ {
+ ResizeDisplay(D_defwidth, D_defheight);
+ DefRestore();
+ SetRendition(&mchar_null);
+#ifdef MAPKEYS
+ PutStr(D_KE);
+ PutStr(D_CCE);
+#endif
+ if (D_hstatus)
+ PutStr(D_DS);
+ D_x = D_y = -1;
+ GotoPos(0, D_height - 1);
+ AddChar('\n');
+ PutStr(D_TE);
+ }
+ Flush();
+}
+
+
+void
+INSERTCHAR(c)
+int c;
+{
+ ASSERT(display);
+ if (!D_insert && D_x < D_width - 1)
+ {
+ if (D_IC || D_CIC)
+ {
+ if (D_IC)
+ PutStr(D_IC);
+ else
+ CPutStr(D_CIC, 1);
+ RAW_PUTCHAR(c);
+ return;
+ }
+ InsertMode(1);
+ if (!D_insert)
+ {
+ RefreshLine(D_y, D_x, D_width-1, 0);
+ return;
+ }
+ }
+ RAW_PUTCHAR(c);
+}
+
+void
+PUTCHAR(c)
+int c;
+{
+ ASSERT(display);
+ if (D_insert && D_x < D_width - 1)
+ InsertMode(0);
+ RAW_PUTCHAR(c);
+}
+
+void
+PUTCHARLP(c)
+int c;
+{
+ if (D_x < D_width - 1)
+ {
+ if (D_insert)
+ InsertMode(0);
+ RAW_PUTCHAR(c);
+ return;
+ }
+ if (D_CLP || D_y != D_bot)
+ {
+ RAW_PUTCHAR(c);
+ return;
+ }
+ D_lp_missing = 1;
+ D_rend.image = c;
+ D_lpchar = D_rend;
+}
+
+/*
+ * RAW_PUTCHAR() is for all text that will be displayed.
+ * NOTE: charset Nr. 0 has a conversion table, but c1, c2, ... don't.
+ */
+
+void
+RAW_PUTCHAR(c)
+int c;
+{
+ ASSERT(display);
+#ifdef KANJI
+ if (D_rend.font == KANJI)
+ {
+ int t = c;
+ if (D_mbcs == 0)
+ {
+ D_mbcs = c;
+ return;
+ }
+ if (D_x == D_width - 1)
+ D_x += D_AM ? 1 : -1;
+ c = D_mbcs;
+ c &= 0x7f;
+ t &= 0x7f;
+ if (D_kanji == EUC)
+ {
+ c |= 0x80;
+ t |= 0x80;
+ }
+ else if (D_kanji == SJIS)
+ {
+ t += (c & 1) ? ((t <= 0x5f) ? 0x1f : 0x20) : 0x7e;
+ c = (c - 0x21) / 2 + ((c < 0x5e) ? 0x81 : 0xc1);
+ }
+ D_mbcs = t;
+ }
+ else if (D_rend.font == KANA)
+ {
+ if (D_kanji == EUC)
+ {
+ AddChar(0x8e); /* SS2 */
+ c |= 0x80;
+ }
+ else if (D_kanji == SJIS)
+ c |= 0x80;
+ }
+ kanjiloop:
+#endif
+ if (D_xtable && D_xtable[(int)(unsigned char)D_rend.font] && D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c])
+ AddStr(D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c]);
+ else
+ AddChar(D_rend.font != '0' ? c : D_c0_tab[(int)(unsigned char)c]);
+
+ if (++D_x >= D_width)
+ {
+ if (D_AM == 0)
+ D_x = D_width - 1;
+ else if (!D_CLP || D_x > D_width)
+ {
+ D_x -= D_width;
+ if (D_y < D_height-1 && D_y != D_bot)
+ D_y++;
+ }
+ }
+#ifdef KANJI
+ if (D_mbcs)
+ {
+ c = D_mbcs;
+ D_mbcs = 0;
+ goto kanjiloop;
+ }
+#endif
+}
+
+static void
+PutChar(c)
+int c;
+{
+ /* this PutChar for ESC-sequences only (AddChar is a macro) */
+ AddChar(c);
+}
+
+void
+PutStr(s)
+char *s;
+{
+ if (display && s)
+ {
+ ospeed = D_dospeed;
+ tputs(s, 1, PutChar);
+ }
+}
+
+void
+CPutStr(s, c)
+char *s;
+int c;
+{
+ if (display && s)
+ {
+ ospeed = D_dospeed;
+ tputs(tgoto(s, 0, c), 1, PutChar);
+ }
+}
+
+
+/* Insert mode is a toggle on some terminals, so we need this hack:
+ */
+void
+InsertMode(on)
+int on;
+{
+ if (display && on != D_insert && D_IM)
+ {
+ D_insert = on;
+ if (D_insert)
+ PutStr(D_IM);
+ else
+ PutStr(D_EI);
+ }
+}
+
+/* ...and maybe keypad application mode is a toggle, too:
+ */
+void
+KeypadMode(on)
+int on;
+{
+#ifdef MAPKEYS
+ if (display)
+ D_keypad = on;
+#else
+ if (display && D_keypad != on && D_KS)
+ {
+ D_keypad = on;
+ if (D_keypad)
+ PutStr(D_KS);
+ else
+ PutStr(D_KE);
+ }
+#endif
+}
+
+void
+CursorkeysMode(on)
+int on;
+{
+#ifdef MAPKEYS
+ if (display)
+ D_cursorkeys = on;
+#else
+ if (display && D_cursorkeys != on && D_CCS)
+ {
+ D_cursorkeys = on;
+ if (D_cursorkeys)
+ PutStr(D_CCS);
+ else
+ PutStr(D_CCE);
+ }
+#endif
+}
+
+void
+ReverseVideo(on)
+int on;
+{
+ if (display && D_revvid != on && D_CVR)
+ {
+ D_revvid = on;
+ if (D_revvid)
+ PutStr(D_CVR);
+ else
+ PutStr(D_CVN);
+ }
+}
+
+void
+CursorVisibility(v)
+int v;
+{
+ if (display && D_curvis != v)
+ {
+ if (D_curvis)
+ PutStr(D_VE); /* do this always, just to be safe */
+ D_curvis = 0;
+ if (v == -1 && D_VI)
+ PutStr(D_VI);
+ else if (v == 1 && D_VS)
+ PutStr(D_VS);
+ else
+ return;
+ D_curvis = v;
+ }
+}
+
+static int StrCost;
+
+/* ARGSUSED */
+static void
+CountChars(c)
+int c;
+{
+ StrCost++;
+}
+
+int
+CalcCost(s)
+register char *s;
+{
+ ASSERT(display);
+ if (!s)
+ return EXPENSIVE;
+ StrCost = 0;
+ ospeed = D_dospeed;
+ tputs(s, 1, CountChars);
+ return StrCost;
+}
+
+void
+GotoPos(x2, y2)
+int x2, y2;
+{
+ register int dy, dx, x1, y1;
+ register int costx, costy;
+ register int m;
+ register char *s;
+ int CMcost;
+ enum move_t xm = M_NONE, ym = M_NONE;
+
+ if (!display)
+ return;
+
+ x1 = D_x;
+ y1 = D_y;
+
+ if (x1 == D_width)
+ if (D_CLP && D_AM)
+ x1 = -1; /* don't know how the terminal treats this */
+ else
+ x1--;
+ if (x2 == D_width)
+ x2--;
+ dx = x2 - x1;
+ dy = y2 - y1;
+ if (dy == 0 && dx == 0)
+ return;
+ if (!D_MS) /* Safe to move ? */
+ SetRendition(&mchar_null);
+ if (y1 < 0 /* don't know the y position */
+ || (y2 > D_bot && y1 <= D_bot) /* have to cross border */
+ || (y2 < D_top && y1 >= D_top)) /* of scrollregion ? */
+ {
+ DoCM:
+ if (D_HO && !x2 && !y2)
+ PutStr(D_HO);
+ else
+ PutStr(tgoto(D_CM, x2, y2));
+ D_x = x2;
+ D_y = y2;
+ return;
+ }
+ /* Calculate CMcost */
+ if (D_HO && !x2 && !y2)
+ s = D_HO;
+ else
+ s = tgoto(D_CM, x2, y2);
+ CMcost = CalcCost(s);
+
+ /* Calculate the cost to move the cursor to the right x position */
+ costx = EXPENSIVE;
+ if (x1 >= 0) /* relativ x positioning only if we know where we are */
+ {
+ if (dx > 0)
+ {
+ if (D_CRI && (dx > 1 || !D_ND))
+ {
+ costx = CalcCost(tgoto(D_CRI, 0, dx));
+ xm = M_CRI;
+ }
+ if ((m = D_NDcost * dx) < costx)
+ {
+ costx = m;
+ xm = M_RI;
+ }
+ /* Speedup: dx <= Rewrite() */
+ if (dx < costx && (m = Rewrite(y1, x1, x2, 0)) < costx)
+ {
+ costx = m;
+ xm = M_RW;
+ }
+ }
+ else if (dx < 0)
+ {
+ if (D_CLE && (dx < -1 || !D_BC))
+ {
+ costx = CalcCost(tgoto(D_CLE, 0, -dx));
+ xm = M_CLE;
+ }
+ if ((m = -dx * D_LEcost) < costx)
+ {
+ costx = m;
+ xm = M_LE;
+ }
+ }
+ else
+ costx = 0;
+ }
+ /* Speedup: Rewrite() >= x2 */
+ if (x2 + D_CRcost < costx && (m = (x2 ? Rewrite(y1, 0, x2, 0) : 0) + D_CRcost) < costx)
+ {
+ costx = m;
+ xm = M_CR;
+ }
+
+ /* Check if it is already cheaper to do CM */
+ if (costx >= CMcost)
+ goto DoCM;
+
+ /* Calculate the cost to move the cursor to the right y position */
+ costy = EXPENSIVE;
+ if (dy > 0)
+ {
+ if (D_CDO && dy > 1) /* DO & NL are always != 0 */
+ {
+ costy = CalcCost(tgoto(D_CDO, 0, dy));
+ ym = M_CDO;
+ }
+ if ((m = dy * ((x2 == 0) ? D_NLcost : D_DOcost)) < costy)
+ {
+ costy = m;
+ ym = M_DO;
+ }
+ }
+ else if (dy < 0)
+ {
+ if (D_CUP && (dy < -1 || !D_UP))
+ {
+ costy = CalcCost(tgoto(D_CUP, 0, -dy));
+ ym = M_CUP;
+ }
+ if ((m = -dy * D_UPcost) < costy)
+ {
+ costy = m;
+ ym = M_UP;
+ }
+ }
+ else
+ costy = 0;
+
+ /* Finally check if it is cheaper to do CM */
+ if (costx + costy >= CMcost)
+ goto DoCM;
+
+ switch (xm)
+ {
+ case M_LE:
+ while (dx++ < 0)
+ PutStr(D_BC);
+ break;
+ case M_CLE:
+ CPutStr(D_CLE, -dx);
+ break;
+ case M_RI:
+ while (dx-- > 0)
+ PutStr(D_ND);
+ break;
+ case M_CRI:
+ CPutStr(D_CRI, dx);
+ break;
+ case M_CR:
+ PutStr(D_CR);
+ D_x = 0;
+ x1 = 0;
+ /* FALLTHROUGH */
+ case M_RW:
+ if (x1 < x2)
+ (void) Rewrite(y1, x1, x2, 1);
+ break;
+ default:
+ break;
+ }
+
+ switch (ym)
+ {
+ case M_UP:
+ while (dy++ < 0)
+ PutStr(D_UP);
+ break;
+ case M_CUP:
+ CPutStr(D_CUP, -dy);
+ break;
+ case M_DO:
+ s = (x2 == 0) ? D_NL : D_DO;
+ while (dy-- > 0)
+ PutStr(s);
+ break;
+ case M_CDO:
+ CPutStr(D_CDO, dy);
+ break;
+ default:
+ break;
+ }
+ D_x = x2;
+ D_y = y2;
+}
+
+void
+ClearDisplay()
+{
+ ASSERT(display);
+ Clear(0, 0, 0, D_width - 1, D_width - 1, D_height - 1, 0);
+}
+
+void
+Clear(x1, y1, xs, xe, x2, y2, uselayfn)
+int x1, y1, xs, xe, x2, y2, uselayfn;
+{
+ int y, xxe;
+
+ ASSERT(display);
+ if (x1 == D_width)
+ x1--;
+ if (x2 == D_width)
+ x2--;
+ if (D_UT) /* Safe to erase ? */
+ SetRendition(&mchar_null);
+ if (D_lp_missing && y1 <= D_bot && xe >= D_width - 1)
+ {
+ if (y2 > D_bot || (y2 == D_bot && x2 >= D_width - 1))
+ D_lp_missing = 0;
+ }
+ if (x2 == D_width - 1 && (xs == 0 || y1 == y2) && xe == D_width - 1 && y2 == D_height - 1)
+ {
+#ifdef AUTO_NUKE
+ if (x1 == 0 && y1 == 0 && D_auto_nuke)
+ NukePending();
+#endif
+ if (x1 == 0 && y1 == 0 && D_CL)
+ {
+ PutStr(D_CL);
+ D_y = D_x = 0;
+ return;
+ }
+ /*
+ * Workaround a hp700/22 terminal bug. Do not use CD where CE
+ * is also appropriate.
+ */
+ if (D_CD && (y1 < y2 || !D_CE))
+ {
+ GotoPos(x1, y1);
+ PutStr(D_CD);
+ return;
+ }
+ }
+ if (x1 == 0 && xs == 0 && (xe == D_width - 1 || y1 == y2) && y1 == 0 && D_CCD)
+ {
+ GotoPos(x1, y1);
+ PutStr(D_CCD);
+ return;
+ }
+ xxe = xe;
+ for (y = y1; y <= y2; y++, x1 = xs)
+ {
+ if (y == y2)
+ xxe = x2;
+ if (x1 == 0 && D_CB && (xxe != D_width - 1 || (D_x == xxe && D_y == y)))
+ {
+ GotoPos(xxe, y);
+ PutStr(D_CB);
+ continue;
+ }
+ if (xxe == D_width - 1 && D_CE)
+ {
+ GotoPos(x1, y);
+ PutStr(D_CE);
+ continue;
+ }
+ if (uselayfn)
+ ClearLine(y, x1, xxe);
+ else
+ DisplayLine(&mline_null, &mline_blank, y, x1, xxe);
+ }
+}
+
+
+/*
+ * if cur_only > 0, we only redisplay current line, as a full refresh is
+ * too expensive over a low baud line.
+ */
+void
+Redisplay(cur_only)
+int cur_only;
+{
+ register int i, stop;
+
+ ASSERT(display);
+ DefRestore();
+ ClearDisplay();
+ stop = D_height;
+ i = 0;
+ if (cur_only > 0 && D_fore)
+ {
+ i = stop = D_fore->w_y;
+ stop++;
+ }
+ else
+ RedisplayLine(-1, 0, D_width - 1, 1);
+ for (; i < stop; i++)
+ RedisplayLine(i, 0, D_width - 1, 1);
+ RefreshStatus();
+ Restore();
+ SetCursor();
+}
+
+
+void
+ScrollH(y, xs, xe, n, oml)
+int y, xs, xe, n;
+struct mline *oml;
+{
+ int i;
+
+ if (n == 0)
+ return;
+ if (xe != D_width - 1)
+ {
+ RefreshLine(y, xs, xe, 0);
+ /* UpdateLine(oml, y, xs, xe); */
+ return;
+ }
+ GotoPos(xs, y);
+ if (D_UT)
+ SetRendition(&mchar_null);
+ if (n > 0)
+ {
+ if (D_CDC && !(n == 1 && D_DC))
+ CPutStr(D_CDC, n);
+ else if (D_DC)
+ {
+ for (i = n; i--; )
+ PutStr(D_DC);
+ }
+ else
+ {
+ RefreshLine(y, xs, xe, 0);
+ /* UpdateLine(oml, y, xs, xe); */
+ return;
+ }
+ }
+ else
+ {
+ if (!D_insert)
+ {
+ if (D_CIC && !(n == -1 && D_IC))
+ CPutStr(D_CIC, -n);
+ else if (D_IC)
+ {
+ for (i = -n; i--; )
+ PutStr(D_IC);
+ }
+ else if (D_IM)
+ {
+ InsertMode(1);
+ for (i = -n; i--; )
+ INSERTCHAR(' ');
+ }
+ else
+ {
+ /* UpdateLine(oml, y, xs, xe); */
+ RefreshLine(y, xs, xe, 0);
+ return;
+ }
+ }
+ else
+ {
+ for (i = -n; i--; )
+ INSERTCHAR(' ');
+ }
+ }
+ if (D_lp_missing && y == D_bot)
+ {
+ if (n > 0)
+ FixLP(D_width - 1 - n, y);
+ D_lp_missing = 0;
+ }
+}
+
+void
+ScrollV(xs, ys, xe, ye, n)
+int xs, ys, xe, ye, n;
+{
+ int i;
+ int up;
+ int oldtop, oldbot;
+ int alok, dlok, aldlfaster;
+ int missy = 0;
+
+ ASSERT(display);
+ if (n == 0)
+ return;
+ if (n >= ye - ys + 1 || -n >= ye - ys + 1)
+ {
+ Clear(xs, ys, xs, xe, xe, ye, 0);
+ return;
+ }
+ if (xs != 0 || xe != D_width - 1)
+ {
+ Redisplay(0);
+ return;
+ }
+
+ if (D_lp_missing)
+ {
+ if (D_bot > ye || D_bot < ys)
+ missy = D_bot;
+ else
+ {
+ missy = D_bot - n;
+ if (missy > ye || missy < ys)
+ D_lp_missing = 0;
+ }
+ }
+
+ up = 1;
+ if (n < 0)
+ {
+ up = 0;
+ n = -n;
+ }
+ if (n >= ye - ys + 1)
+ n = ye - ys + 1;
+
+ oldtop = D_top;
+ oldbot = D_bot;
+ if (D_bot != ye)
+ ChangeScrollRegion(ys, ye);
+ alok = (D_AL || D_CAL || (ye == D_bot && up));
+ dlok = (D_DL || D_CDL || (ye == D_bot && !up));
+ if (D_top != ys && !(alok && dlok))
+ ChangeScrollRegion(ys, ye);
+
+ if (D_lp_missing &&
+ (oldbot != D_bot ||
+ (oldbot == D_bot && up && D_top == ys && D_bot == ye)))
+ {
+ FixLP(D_width - 1, oldbot);
+ if (oldbot == D_bot) /* have scrolled */
+ {
+ if (--n == 0)
+ {
+ ChangeScrollRegion(oldtop, oldbot);
+ return;
+ }
+ }
+ }
+
+ aldlfaster = (n > 1 && ye == D_bot && ((up && D_CDL) || (!up && D_CAL)));
+
+ if (D_UT)
+ SetRendition(&mchar_null);
+ if ((up || D_SR) && D_top == ys && D_bot == ye && !aldlfaster)
+ {
+ if (up)
+ {
+ GotoPos(0, ye);
+ while (n-- > 0)
+ PutStr(D_NL); /* was SF, I think NL is faster */
+ }
+ else
+ {
+ GotoPos(0, ys);
+ while (n-- > 0)
+ PutStr(D_SR);
+ }
+ }
+ else if (alok && dlok)
+ {
+ if (up || ye != D_bot)
+ {
+ GotoPos(0, up ? ys : ye+1-n);
+ if (D_CDL && !(n == 1 && D_DL))
+ CPutStr(D_CDL, n);
+ else
+ for(i = n; i--; )
+ PutStr(D_DL);
+ }
+ if (!up || ye != D_bot)
+ {
+ GotoPos(0, up ? ye+1-n : ys);
+ if (D_CAL && !(n == 1 && D_AL))
+ CPutStr(D_CAL, n);
+ else
+ for(i = n; i--; )
+ PutStr(D_AL);
+ }
+ }
+ else
+ {
+ Redisplay(0);
+ return;
+ }
+ if (D_lp_missing && missy != D_bot)
+ FixLP(D_width - 1, missy);
+ ChangeScrollRegion(oldtop, oldbot);
+ if (D_lp_missing && missy != D_bot)
+ FixLP(D_width - 1, missy);
+}
+
+void
+SetAttr(new)
+register int new;
+{
+ register int i, j, old, typ;
+
+ if (!display || (old = D_rend.attr) == new)
+ return;
+#if defined(TERMINFO) && defined(USE_SGR)
+ debug1("USE_SGR defined, sa is %s\n", D_SA ? D_SA : "undefined");
+ if (D_SA)
+ {
+ char *tparm();
+ SetFont(ASCII);
+ tputs(tparm(D_SA, new & A_SO, new & A_US, new & A_RV, new & A_BL,
+ new & A_DI, new & A_BD, 0 , 0 ,
+ 0), 1, PutChar);
+ D_rend.attr = new;
+ D_atyp = 0;
+# ifdef COLOR
+ if (D_CAF || D_CAB)
+ D_rend.color = 0;
+# endif
+ return;
+ }
+#endif
+ typ = D_atyp;
+ if ((new & old) != old)
+ {
+ if ((typ & ATYP_U))
+ PutStr(D_UE);
+ if ((typ & ATYP_S))
+ PutStr(D_SE);
+ if ((typ & ATYP_M))
+ {
+ PutStr(D_ME);
+#ifdef COLOR
+ /* ansi attrib handling: \E[m resets color, too */
+ if (D_CAF || D_CAB)
+ D_rend.color = 0;
+#endif
+ }
+ old = 0;
+ typ = 0;
+ }
+ old ^= new;
+ for (i = 0, j = 1; old && i < NATTR; i++, j <<= 1)
+ {
+ if ((old & j) == 0)
+ continue;
+ old ^= j;
+ if (D_attrtab[i])
+ {
+ PutStr(D_attrtab[i]);
+ typ |= D_attrtyp[i];
+ }
+ }
+ D_rend.attr = new;
+ D_atyp = typ;
+}
+
+void
+SetFont(new)
+int new;
+{
+ if (!display || D_rend.font == new)
+ return;
+ D_rend.font = new;
+#ifdef KANJI
+ if ((new == KANJI || new == KANA) && D_kanji)
+ return; /* all done in RAW_PUTCHAR */
+#endif
+ if (D_xtable && D_xtable[(int)(unsigned char)new] &&
+ D_xtable[(int)(unsigned char)new][256])
+ {
+ PutStr(D_xtable[(int)(unsigned char)new][256]);
+ return;
+ }
+
+ if (!D_CG0 && new != '0')
+ new = ASCII;
+
+ if (new == ASCII)
+ PutStr(D_CE0);
+#ifdef KANJI
+ else if (new < ' ')
+ {
+ AddStr("\033$");
+ AddChar(new + '@');
+ }
+#endif
+ else
+ CPutStr(D_CS0, new);
+}
+
+#ifdef COLOR
+void
+SetColor(new)
+int new;
+{
+ int of, ob, f, b;
+
+ if (!display || D_rend.color == new)
+ return;
+ of = D_rend.color & 0xf;
+ ob = (D_rend.color >> 4) & 0xf;
+ f = new & 0xf;
+ b = (new >> 4) & 0xf;
+
+ if (!D_CAX && ((f == 0 && f != of) || (b == 0 && b != ob)))
+ {
+ int oattr;
+
+ oattr = D_rend.attr;
+ AddStr("\033[m");
+ D_rend.attr = 0;
+ D_rend.color = 0;
+ of = ob = 0;
+ SetAttr(oattr);
+ }
+ if (D_CAF || D_CAB)
+ {
+ if (f != of)
+ CPutStr(D_CAF, 9 - f);
+ if (b != ob)
+ CPutStr(D_CAB, 9 - b);
+ }
+ D_rend.color = new;
+}
+#endif
+
+void
+SetRendition(mc)
+struct mchar *mc;
+{
+ if (!display)
+ return;
+ if (D_rend.attr != mc->attr)
+ SetAttr(mc->attr);
+#ifdef COLOR
+ if (D_rend.color != mc->color)
+ SetColor(mc->color);
+#endif
+ if (D_rend.font != mc->font)
+ SetFont(mc->font);
+}
+
+void
+SetRenditionMline(ml, x)
+struct mline *ml;
+int x;
+{
+ if (!display)
+ return;
+ if (D_rend.attr != ml->attr[x])
+ SetAttr(ml->attr[x]);
+#ifdef COLOR
+ if (D_rend.color != ml->color[x])
+ SetColor(ml->color[x]);
+#endif
+ if (D_rend.font != ml->font[x])
+ SetFont(ml->font[x]);
+}
+
+void
+MakeStatus(msg)
+char *msg;
+{
+ register char *s, *t;
+ register int max, ti;
+
+ if (!display)
+ return;
+
+ if (!D_tcinited)
+ {
+ debug("tc not inited, just writing msg\n");
+ AddStr(msg);
+ AddStr("\r\n");
+ Flush();
+ return;
+ }
+ if (!use_hardstatus || !D_HS)
+ {
+ max = D_width;
+ if (D_CLP == 0)
+ max--;
+ }
+ else
+ max = D_WS;
+ if (D_status)
+ {
+ if (!D_status_bell)
+ {
+ ti = time((time_t *) 0) - D_status_time;
+ if (ti < MsgMinWait)
+ sleep(MsgMinWait - ti);
+ }
+ RemoveStatus();
+ }
+ for (s = t = msg; *s && t - msg < max; ++s)
+ if (*s == BELL)
+ PutStr(D_BL);
+ else if ((unsigned char)*s >= ' ' && *s != 0177)
+ *t++ = *s;
+ *t = '\0';
+ if (t > msg)
+ {
+ if (t - msg >= D_status_buflen)
+ {
+ char *buf;
+ if (D_status_lastmsg)
+ buf = realloc(D_status_lastmsg, t - msg + 1);
+ else
+ buf = malloc(t - msg + 1);
+ if (buf)
+ {
+ D_status_lastmsg = buf;
+ D_status_buflen = t - msg + 1;
+ }
+ }
+ if (t - msg < D_status_buflen)
+ strcpy(D_status_lastmsg, msg);
+ D_status = 1;
+ D_status_len = t - msg;
+ D_status_lastx = D_x;
+ D_status_lasty = D_y;
+ if (!use_hardstatus || !D_HS)
+ {
+ debug1("using STATLINE %d\n", STATLINE);
+ GotoPos(0, STATLINE);
+ SetRendition(&mchar_so);
+ InsertMode(0);
+ AddStr(msg);
+ D_x = -1;
+ }
+ else
+ {
+ debug("using HS\n");
+ SetRendition(&mchar_null);
+ InsertMode(0);
+ if (D_hstatus)
+ PutStr(D_DS);
+ CPutStr(D_TS, 0);
+ AddStr(msg);
+ PutStr(D_FS);
+ D_hstatus = 1;
+ }
+ Flush();
+ (void) time(&D_status_time);
+ }
+}
+
+void
+RemoveStatus()
+{
+ struct win *p;
+
+ if (!display)
+ return;
+ if (!D_status)
+ return;
+
+ /*
+ * UGLY HACK ALERT - this should NOT be in display.c
+ * We need to find the window that caused an activity or bell
+ * message, to reenable this function there.
+ */
+ for (p = windows; p; p = p->w_next)
+ {
+ if (p->w_display != display)
+ continue;
+ if (p->w_monitor == MON_MSG)
+ {
+ debug1("RemoveStatus clearing monitor win %d\n", p->w_number);
+ p->w_monitor = MON_DONE;
+ }
+ if (p->w_bell == BELL_MSG)
+ {
+ debug1("RemoveStatus clearing bell win %d\n", p->w_number);
+ p->w_bell = BELL_DONE;
+ }
+ }
+ D_status = 0;
+ D_status_bell = 0;
+ if (!use_hardstatus || !D_HS)
+ {
+ GotoPos(0, STATLINE);
+ RefreshLine(STATLINE, 0, D_status_len - 1, 0);
+ GotoPos(D_status_lastx, D_status_lasty);
+ }
+ else
+ {
+ /*
+ SetRendition(&mchar_null);
+ if (D_hstatus)
+ PutStr(D_DS);
+ */
+ RefreshStatus();
+ }
+ SetCursor();
+}
+
+/*
+ * Refreshes the harstatus of the _window_. Shouldn't be here...
+ */
+
+void
+RefreshStatus()
+{
+ char *buf;
+
+ if (D_HS)
+ {
+ SetRendition(&mchar_null);
+ if (D_hstatus)
+ PutStr(D_DS);
+ if (D_fore && D_fore->w_hstatus)
+ {
+ buf = MakeWinMsg(D_fore->w_hstatus, D_fore, '\005');
+ CPutStr(D_TS, 0);
+ if (strlen(buf) > D_WS)
+ AddStrn(buf, D_WS);
+ else
+ AddStr(buf);
+ PutStr(D_FS);
+ D_hstatus = 1;
+ }
+ }
+ else if (D_fore && D_fore->w_hstatus)
+ {
+ buf = MakeWinMsg(D_fore->w_hstatus, D_fore, '\005');
+ Msg(0, "%s", buf);
+ }
+}
+
+void
+RefreshLine(y, from, to, isblank)
+int y, from, to, isblank;
+{
+ ASSERT(display);
+ debug2("RefreshLine %d %d", y, from);
+ debug2(" %d %d\n", to, isblank);
+ if (isblank == 0 && D_CE && to == D_width - 1)
+ {
+ GotoPos(from, y);
+ if (D_UT)
+ SetRendition(&mchar_null);
+ PutStr(D_CE);
+ isblank = 1;
+ }
+ RedisplayLine(y, from, to, isblank);
+}
+
+void
+FixLP(x2, y2)
+register int x2, y2;
+{
+ struct mchar oldrend;
+
+ ASSERT(display);
+ oldrend = D_rend;
+ GotoPos(x2, y2);
+ SetRendition(&D_lpchar);
+ PUTCHAR(D_lpchar.image);
+ D_lp_missing = 0;
+ SetRendition(&oldrend);
+}
+
+void
+DisplayLine(oml, ml, y, from, to)
+struct mline *oml, *ml;
+int from, to, y;
+{
+ register int x;
+ int last2flag = 0, delete_lp = 0;
+
+ ASSERT(display);
+ ASSERT(y >= 0 && y < D_height);
+ ASSERT(from >= 0 && from < D_width);
+ ASSERT(to >= 0 && to < D_width);
+ if (!D_CLP && y == D_bot && to == D_width - 1)
+ if (D_lp_missing || !cmp_mline(oml, ml, to))
+ {
+ if ((D_IC || D_IM) && from < to)
+ {
+ to -= 2;
+ last2flag = 1;
+ D_lp_missing = 0;
+ }
+ else
+ {
+ to--;
+ delete_lp = (D_CE || D_DC || D_CDC);
+ D_lp_missing = !cmp_mchar_mline(&mchar_blank, ml, to);
+ copy_mline2mchar(&D_lpchar, ml, to);
+ }
+ }
+ else
+ to--;
+ for (x = from; x <= to; x++)
+ {
+ if (x || D_x != D_width || D_y != y - 1)
+ {
+ if (x < to || x != D_width - 1 || ml->image[x + 1] == ' ')
+ if (cmp_mline(oml, ml, x))
+ continue;
+ GotoPos(x, y);
+ }
+#ifdef KANJI
+ if (badkanji(ml->font, x))
+ {
+ x--;
+ GotoPos(x, y);
+ }
+#endif
+ SetRenditionMline(ml, x);
+ PUTCHAR(ml->image[x]);
+#ifdef KANJI
+ if (ml->font[x] == KANJI)
+ PUTCHAR(ml->image[++x]);
+#endif
+ }
+ if (to == D_width - 1 && y < D_height - 1 && ml->image[to + 1] == ' ')
+ GotoPos(0, y + 1);
+ if (last2flag)
+ {
+ GotoPos(x, y);
+ SetRenditionMline(ml, x + 1);
+ PUTCHAR(ml->image[x + 1]);
+ GotoPos(x, y);
+ SetRenditionMline(ml, x);
+ INSERTCHAR(ml->image[x]);
+ }
+ else if (delete_lp)
+ {
+ if (D_UT)
+ {
+ SetRendition(&mchar_null);
+ }
+ if (D_DC)
+ PutStr(D_DC);
+ else if (D_CDC)
+ CPutStr(D_CDC, 1);
+ else if (D_CE)
+ PutStr(D_CE);
+ }
+}
+
+void
+SetLastPos(x,y)
+int x,y;
+{
+ ASSERT(display);
+ D_x = x;
+ D_y = y;
+}
+
+int
+ResizeDisplay(wi, he)
+int wi, he;
+{
+ ASSERT(display);
+ debug2("ResizeDisplay: to (%d,%d).\n", wi, he);
+ if (D_width == wi && D_height == he)
+ {
+ debug("ResizeDisplay: No change\n");
+ return 0;
+ }
+ if (D_CWS)
+ {
+ debug("ResizeDisplay: using WS\n");
+ PutStr(tgoto(D_CWS, wi, he));
+ ChangeScreenSize(wi, he, 0);
+ return 0;
+ }
+ else if (D_CZ0 && (wi == Z0width || wi == Z1width))
+ {
+ debug("ResizeDisplay: using Z0/Z1\n");
+ PutStr(wi == Z0width ? D_CZ0 : D_CZ1);
+ ChangeScreenSize(wi, D_height, 0);
+ return (he == D_height) ? 0 : -1;
+ }
+ return -1;
+}
+
+void
+ChangeScrollRegion(newtop, newbot)
+int newtop, newbot;
+{
+ if (display == 0)
+ return;
+ if (D_CS == 0)
+ {
+ D_top = 0;
+ D_bot = D_height - 1;
+ return;
+ }
+ if (D_top == newtop && D_bot == newbot)
+ return;
+ debug2("ChangeScrollRegion: (%d - %d)\n", newtop, newbot);
+ PutStr(tgoto(D_CS, newbot, newtop));
+ D_top = newtop;
+ D_bot = newbot;
+ D_y = D_x = -1; /* Just in case... */
+}
+
+
+/*
+ * Layer creation / removal
+ */
+
+int
+InitOverlayPage(datasize, lf, block)
+int datasize;
+struct LayFuncs *lf;
+int block;
+{
+ char *data;
+ struct layer *newlay;
+
+ RemoveStatus();
+ debug3("Entering new layer display %#x D_fore %#x oldlay %#x\n",
+ (unsigned int)display, (unsigned int)D_fore, (unsigned int)D_lay);
+ if ((newlay = (struct layer *)malloc(sizeof(struct layer))) == 0)
+ {
+ Msg(0, "No memory for layer struct");
+ return -1;
+ }
+ data = 0;
+ if (datasize)
+ {
+ if ((data = malloc(datasize)) == 0)
+ {
+ free((char *)newlay);
+ Msg(0, "No memory for layer data");
+ return -1;
+ }
+ bzero(data, datasize);
+ }
+ newlay->l_layfn = lf;
+ newlay->l_block = block | D_lay->l_block;
+ newlay->l_data = data;
+ newlay->l_next = D_lay;
+ if (D_fore)
+ {
+ D_fore->w_lay = newlay; /* XXX: CHECK */
+ D_fore->w_active = 0; /* XXX: CHECK */
+ }
+ D_lay = newlay;
+ D_layfn = newlay->l_layfn;
+ Restore();
+ return 0;
+}
+
+void
+ExitOverlayPage()
+{
+ struct layer *oldlay;
+
+ debug3("Exiting layer display %#x fore %#x D_lay %#x\n",
+ (unsigned int)display, (unsigned int)D_fore, (unsigned int)D_lay);
+ oldlay = D_lay;
+ if (oldlay->l_data)
+ free(oldlay->l_data);
+ D_lay = oldlay->l_next;
+ D_layfn = D_lay->l_layfn;
+ free((char *)oldlay);
+ if (D_fore)
+ D_fore->w_lay = D_lay; /* XXX: Is this necessary ? */
+ Restore();
+ SetCursor();
+}
+
+
+/*
+ * Output buffering routines
+ */
+
+void
+AddStr(str)
+char *str;
+{
+ register char c;
+
+ ASSERT(display);
+ while ((c = *str++))
+ AddChar(c);
+}
+
+void
+AddStrn(str, n)
+char *str;
+int n;
+{
+ register char c;
+
+ ASSERT(display);
+ while ((c = *str++) && n-- > 0)
+ AddChar(c);
+ while (n-- > 0)
+ AddChar(' ');
+}
+
+void
+Flush()
+{
+ register int l;
+ register char *p;
+
+ ASSERT(display);
+ l = D_obufp - D_obuf;
+ debug1("Flush(): %d\n", l);
+ ASSERT(l + D_obuffree == D_obuflen);
+ if (l == 0)
+ return;
+ if (D_userfd < 0)
+ {
+ D_obuffree += l;
+ D_obufp = D_obuf;
+ return;
+ }
+ p = D_obuf;
+ if (fcntl(D_userfd, F_SETFL, 0))
+ debug1("Warning: BLOCK fcntl failed: %d\n", errno);
+ while (l)
+ {
+ register int wr;
+ wr = write(D_userfd, p, l);
+ if (wr <= 0)
+ {
+ if (errno == EINTR)
+ continue;
+ debug1("Writing to display: %d\n", errno);
+ wr = l;
+ }
+ D_obuffree += wr;
+ p += wr;
+ l -= wr;
+ }
+ D_obuffree += l;
+ D_obufp = D_obuf;
+ if (fcntl(D_userfd, F_SETFL, FNBLOCK))
+ debug1("Warning: NBLOCK fcntl failed: %d\n", errno);
+}
+
+void
+freetty()
+{
+ if (D_userfd >= 0)
+ close(D_userfd);
+ debug1("did freetty %d\n", D_userfd);
+ D_userfd = -1;
+ D_obufp = 0;
+ D_obuffree = 0;
+ if (D_obuf)
+ free(D_obuf);
+ D_obuf = 0;
+ D_obuflen = 0;
+}
+
+/*
+ * Asynchronous output routines by
+ * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
+ */
+
+void
+Resize_obuf()
+{
+ register int ind;
+
+ ASSERT(display);
+ if (D_obuflen && D_obuf)
+ {
+ ind = D_obufp - D_obuf;
+ D_obuflen += GRAIN;
+ D_obuffree += GRAIN;
+ D_obuf = realloc(D_obuf, D_obuflen);
+ }
+ else
+ {
+ ind = 0;
+ D_obuflen = GRAIN;
+ D_obuffree = GRAIN;
+ D_obuf = malloc(D_obuflen);
+ }
+ if (!D_obuf)
+ Panic(0, "Out of memory");
+ D_obufp = D_obuf + ind;
+ debug1("ResizeObuf: resized to %d\n", D_obuflen);
+}
+
+#ifdef AUTO_NUKE
+void
+NukePending()
+{/* Nuke pending output in current display, clear screen */
+ register int len;
+ int oldtop = D_top, oldbot = D_bot;
+ struct mchar oldrend;
+ int oldkeypad = D_keypad, oldcursorkeys = D_cursorkeys;
+ int oldcurvis = D_curvis;
+
+ oldrend = D_rend;
+ len = D_obufp - D_obuf;
+ debug1("NukePending: nuking %d chars\n", len);
+
+ /* Throw away any output that we can... */
+# ifdef POSIX
+ tcflush(D_userfd, TCOFLUSH);
+# else
+# ifdef TCFLSH
+ (void) ioctl(D_userfd, TCFLSH, (char *) 1);
+# endif
+# endif
+
+ D_obufp = D_obuf;
+ D_obuffree += len;
+ D_top = D_bot = -1;
+ PutStr(D_TI);
+ PutStr(D_IS);
+ /* Turn off all attributes. (Tim MacKenzie) */
+ if (D_ME)
+ PutStr(D_ME);
+ else
+ {
+ PutStr(D_SE);
+ PutStr(D_UE);
+ }
+ /* FIXME: reset color! */
+ /* Check for toggle */
+ if (D_IM && strcmp(D_IM, D_EI))
+ PutStr(D_EI);
+ D_insert = 0;
+ /* Check for toggle */
+#ifndef MAPKEYS
+ if (D_KS && strcmp(D_KS, D_KE))
+ PutStr(D_KE);
+ D_keypad = 0;
+ if (D_CCS && strcmp(D_CCS, D_CCE))
+ PutStr(D_CCE);
+ D_cursorkeys = 0;
+#endif
+ PutStr(D_CE0);
+ D_rend = mchar_null;
+ D_atyp = 0;
+ PutStr(D_DS);
+ D_hstatus = 0;
+ PutStr(D_VE);
+ D_curvis = 0;
+ ChangeScrollRegion(oldtop, oldbot);
+ SetRendition(&oldrend);
+ KeypadMode(oldkeypad);
+ CursorkeysMode(oldcursorkeys);
+ CursorVisibility(oldcurvis);
+ if (D_CWS)
+ {
+ debug("ResizeDisplay: using WS\n");
+ PutStr(tgoto(D_CWS, D_width, D_height));
+ }
+ else if (D_CZ0 && (D_width == Z0width || D_width == Z1width))
+ {
+ debug("ResizeDisplay: using Z0/Z1\n");
+ PutStr(D_width == Z0width ? D_CZ0 : D_CZ1);
+ }
+}
+#endif /* AUTO_NUKE */
+
+#ifdef KANJI
+int
+badkanji(f, x)
+char *f;
+int x;
+{
+ int i, j;
+ if (f[x] != KANJI)
+ return 0;
+ for (i = j = 0; i < x; i++)
+ if (*f++ == KANJI)
+ j ^= 1;
+ return j;
+}
+#endif
diff --git a/display.h b/display.h
new file mode 100644
index 0000000..87d0944
--- /dev/null
+++ b/display.h
@@ -0,0 +1,222 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ * $Id: display.h,v 1.9 1994/05/31 12:31:54 mlschroe Exp $ FAU
+ */
+
+
+#ifdef MAPKEYS
+struct kmap
+{
+ char seq[8];
+ char off[8];
+ int nr;
+};
+
+#define KMAP_SEQ ((int)((struct kmap *)0)->seq)
+#define KMAP_OFF ((int)((struct kmap *)0)->off)
+
+#define KMAP_KEYS (T_OCAPS-T_CAPS)
+#define KMAP_AKEYS (T_OCAPS-T_CURSOR)
+#define KMAP_EXT 50
+
+#define KMAP_NOTIMEOUT 0x4000
+
+#endif
+
+struct win; /* forward declaration */
+
+struct display
+{
+ struct display *d_next; /* linked list */
+ struct user *d_user; /* user who owns that display */
+ struct LayFuncs *d_layfn; /* current layer functions */
+ struct layer *d_lay; /* layers on the display */
+ struct win *d_fore; /* pointer to fore window */
+ struct win *d_other; /* pointer to other window */
+ char d_nonblock; /* don't block when d_obufmax reached */
+ char d_termname[20 + 1]; /* $TERM */
+ char *d_tentry; /* buffer for tgetstr */
+ char d_tcinited; /* termcap inited flag */
+ int d_width, d_height; /* width/height of the screen */
+ int d_defwidth, d_defheight; /* default width/height of windows */
+ int d_top, d_bot; /* scrollregion start/end */
+ int d_x, d_y; /* cursor position */
+ struct mchar d_rend; /* current rendition */
+ char d_atyp; /* current attribute types */
+#ifdef KANJI
+ int d_mbcs; /* saved char for multibytes charset */
+ int d_kanji; /* what kanji type the display is */
+#endif
+ int d_insert; /* insert mode flag */
+ int d_keypad; /* application keypad flag */
+ int d_cursorkeys; /* application cursorkeys flag */
+ int d_revvid; /* reverse video */
+ int d_curvis; /* cursor visibility */
+ int d_hstatus; /* hardstatus used */
+ int d_lp_missing; /* last character on bot line missing */
+ struct mchar d_lpchar; /* missing char */
+ time_t d_status_time; /* time of status display */
+ char d_status; /* is status displayed? */
+ char d_status_bell; /* is it only a vbell? */
+ int d_status_len; /* length of status line */
+ char *d_status_lastmsg; /* last displayed message */
+ int d_status_buflen; /* last message buffer len */
+ int d_status_lastx; /* position of the cursor */
+ int d_status_lasty; /* before status was displayed */
+ int d_ESCseen; /* Was the last char an ESC (^a) */
+ int d_userpid; /* pid of attacher */
+ char d_usertty[MAXPATHLEN]; /* tty we are attached to */
+ int d_userfd; /* fd of the tty */
+ struct mode d_OldMode; /* tty mode when screen was started */
+ struct mode d_NewMode; /* New tty mode */
+ int d_flow; /* tty's flow control on/off flag*/
+ char *d_obuf; /* output buffer */
+ int d_obuflen; /* len of buffer */
+ int d_obufmax; /* len where we are blocking the pty */
+ char *d_obufp; /* pointer in buffer */
+ int d_obuffree; /* free bytes in buffer */
+#ifdef AUTO_NUKE
+ int d_auto_nuke; /* autonuke flag */
+#endif
+#ifdef MAPKEYS
+ int d_nseqs; /* number of valid mappings */
+ char *d_seqp; /* pointer into keymap array */
+ int d_seql; /* number of parsed chars */
+ int d_seqruns; /* number of select calls */
+ int d_dontmap; /* do not map next */
+ int d_mapdefault; /* do map next to default */
+ struct kmap d_kmaps[KMAP_KEYS+KMAP_EXT]; /* keymaps */
+#endif
+ union tcu d_tcs[T_N]; /* terminal capabilities */
+ char *d_attrtab[NATTR]; /* attrib emulation table */
+ char d_attrtyp[NATTR]; /* attrib group table */
+ short d_dospeed; /* baudrate of tty */
+ char d_c0_tab[256]; /* conversion for C0 */
+ char ***d_xtable; /* char translation table */
+ int d_UPcost, d_DOcost, d_LEcost, d_NDcost;
+ int d_CRcost, d_IMcost, d_EIcost, d_NLcost;
+ int d_printfd; /* fd for vt100 print sequence */
+#ifdef UTMPOK
+ slot_t d_loginslot; /* offset, where utmp_logintty belongs */
+ struct utmp d_utmp_logintty; /* here the original utmp structure is stored */
+# ifdef _SEQUENT_
+ char d_loginhost[100+1];
+# endif /* _SEQUENT_ */
+#endif
+};
+
+#ifdef MULTI
+# define DISPLAY(x) display->x
+#else
+extern struct display TheDisplay;
+# define DISPLAY(x) TheDisplay.x
+#endif
+
+#define D_user DISPLAY(d_user)
+#define D_username (DISPLAY(d_user) ? DISPLAY(d_user)->u_name : 0)
+#define D_layfn DISPLAY(d_layfn)
+#define D_lay DISPLAY(d_lay)
+#define D_fore DISPLAY(d_fore)
+#define D_other DISPLAY(d_other)
+#define D_nonblock DISPLAY(d_nonblock)
+#define D_termname DISPLAY(d_termname)
+#define D_tentry DISPLAY(d_tentry)
+#define D_tcinited DISPLAY(d_tcinited)
+#define D_width DISPLAY(d_width)
+#define D_height DISPLAY(d_height)
+#define D_defwidth DISPLAY(d_defwidth)
+#define D_defheight DISPLAY(d_defheight)
+#define D_top DISPLAY(d_top)
+#define D_bot DISPLAY(d_bot)
+#define D_x DISPLAY(d_x)
+#define D_y DISPLAY(d_y)
+#define D_rend DISPLAY(d_rend)
+#define D_atyp DISPLAY(d_atyp)
+#define D_mbcs DISPLAY(d_mbcs)
+#define D_kanji DISPLAY(d_kanji)
+#define D_insert DISPLAY(d_insert)
+#define D_keypad DISPLAY(d_keypad)
+#define D_cursorkeys DISPLAY(d_cursorkeys)
+#define D_revvid DISPLAY(d_revvid)
+#define D_curvis DISPLAY(d_curvis)
+#define D_hstatus DISPLAY(d_hstatus)
+#define D_lp_missing DISPLAY(d_lp_missing)
+#define D_lpchar DISPLAY(d_lpchar)
+#define D_status DISPLAY(d_status)
+#define D_status_time DISPLAY(d_status_time)
+#define D_status_bell DISPLAY(d_status_bell)
+#define D_status_len DISPLAY(d_status_len)
+#define D_status_lastmsg DISPLAY(d_status_lastmsg)
+#define D_status_buflen DISPLAY(d_status_buflen)
+#define D_status_lastx DISPLAY(d_status_lastx)
+#define D_status_lasty DISPLAY(d_status_lasty)
+#define D_ESCseen DISPLAY(d_ESCseen)
+#define D_userpid DISPLAY(d_userpid)
+#define D_usertty DISPLAY(d_usertty)
+#define D_userfd DISPLAY(d_userfd)
+#define D_OldMode DISPLAY(d_OldMode)
+#define D_NewMode DISPLAY(d_NewMode)
+#define D_flow DISPLAY(d_flow)
+#define D_obuf DISPLAY(d_obuf)
+#define D_obuflen DISPLAY(d_obuflen)
+#define D_obufmax DISPLAY(d_obufmax)
+#define D_obufp DISPLAY(d_obufp)
+#define D_obuffree DISPLAY(d_obuffree)
+#define D_auto_nuke DISPLAY(d_auto_nuke)
+#define D_nseqs DISPLAY(d_nseqs)
+#define D_seqp DISPLAY(d_seqp)
+#define D_seql DISPLAY(d_seql)
+#define D_seqruns DISPLAY(d_seqruns)
+#define D_dontmap DISPLAY(d_dontmap)
+#define D_mapdefault DISPLAY(d_mapdefault)
+#define D_kmaps DISPLAY(d_kmaps)
+#define D_tcs DISPLAY(d_tcs)
+#define D_attrtab DISPLAY(d_attrtab)
+#define D_attrtyp DISPLAY(d_attrtyp)
+#define D_dospeed DISPLAY(d_dospeed)
+#define D_c0_tab DISPLAY(d_c0_tab)
+#define D_xtable DISPLAY(d_xtable)
+#define D_UPcost DISPLAY(d_UPcost)
+#define D_DOcost DISPLAY(d_DOcost)
+#define D_LEcost DISPLAY(d_LEcost)
+#define D_NDcost DISPLAY(d_NDcost)
+#define D_CRcost DISPLAY(d_CRcost)
+#define D_IMcost DISPLAY(d_IMcost)
+#define D_EIcost DISPLAY(d_EIcost)
+#define D_NLcost DISPLAY(d_NLcost)
+#define D_printfd DISPLAY(d_printfd)
+#define D_loginslot DISPLAY(d_loginslot)
+#define D_utmp_logintty DISPLAY(d_utmp_logintty)
+#define D_loginhost DISPLAY(d_loginhost)
+
+
+#define GRAIN 4096 /* Allocation grain size for output buffer */
+#define OBUF_MAX 256 /* default for obuflimit */
+
+#define OUTPUT_BLOCK_SIZE 256 /* Block size of output to tty */
+
+#define AddChar(c) do { \
+ if (--D_obuffree == 0) \
+ Resize_obuf(); \
+ *D_obufp++ = (c); \
+} while (0)
+
diff --git a/doc/FAQ b/doc/FAQ
new file mode 100644
index 0000000..6c9c8af
--- /dev/null
+++ b/doc/FAQ
@@ -0,0 +1,253 @@
+ jw 21.10.93
+ 05.05.94
+
+ screen: frequently asked questions -- known problems -- unimplemented bugs
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+
+Q: Why is it impossible to download a file with Kermit/sz/rz when
+ screen is running? Do I need to set some special variables?
+
+A: Screen always interprets control-sequences sent by the
+ applications and translates/optimizes them for the current
+ terminal type. Screen always parses the user input for its
+ escape character (CTRL-A). Both are basic screen features and
+ cannot be switched off. Even if it were possible to switch
+ screen into a completely transparent mode, you could never switch
+ between windows, while kermit/sz/rz is downloading a file. You
+ must wait til the end as kermit/sz/rz will not transmit your
+ input during a file transfer and as kermit/sz/rz would be very
+ confused if screen switched away the window containing the
+ other kermit/sz/rz. Simply detach your screen session for each
+ file transfer and start the transfer program only from the shell
+ where you started screen.
+
+Q: I am using screen with a YYY terminal, which supports the XXX
+ graphic language. I am very happy with it, except one thing: I
+ cannot render graphics into screen windows.
+
+A: You are out of luck there. Screen provides a fixed set of escape
+ sequences in order to make it possible to switch terminal types.
+ Screen has to know exactly what the escape sequences do to the
+ terminal because it must hold an image in memory. Otherwise
+ screen could not restore the image if you switch to another
+ window. Because of this you have to change screens escape
+ sequence parser (ansi.c) to pass the XXX graphics sequences to
+ the terminal. Of course the graphics will be lost if you switch
+ to another window. Screen will only honour graphics sequences
+ that are demanded by an overwhelming majority.
+
+Q: For some unknown reason, the fifo in /tmp/screens/S-myname is
+ gone, and i can't resume my screen session. Is there a way to
+ recreate the fifo?
+
+A: Screen checks the fifo/socket whenever it receives a SIGCHLD
+ signal. If missing, the fifo/socket is recreated then. If screen
+ is running non set-uid the user can issue a 'kill -CHLD
+ screenpid' directly (it is -CHILD on some systems). Screenpid is
+ the process-id of the screen process found in a 'ps -x' listing.
+ But usually this won't work, as screen should be installed set-
+ uid root. In this case you will not be able to send it a signal,
+ but the kernel will. It does so, whenever a child of screen
+ changes its state. Find the process-id (shellpid below) of the
+ "least important" shell running inside screen. The try 'kill
+ -STOP shellpid'. If the fifo/socket does not reappear, destroy
+ the shell process. You sacrify one shell to save the rest. If
+ nothing works, please do not forget to remove all processes
+ running in the lost screen session.
+
+Q: When you start "screen" a page of text comes up to start you
+ off. Is there a way to get rid of this text as a command line
+ argument or by using a switch of some sort.
+
+A: Just put the following line in your ~/.screenrc:
+ startup_message off
+ Many peole ask this, although it is in the man page, too :-)
+
+Q: Start "screen emacs" and run emacs function suspend-emacs
+ (ctrl-z). The window containing emacs vanishes.
+
+A: This is a known bug. Unfortunatly there is no easy fix
+ because this is specified in the POSIX standard. When a new
+ window is created Screen opens up a new session because the
+ window has to get the pty as a controlling terminal (a
+ session can only have one controlling terminal). With the
+ setsid() call the process also creates a new process
+ group. This process group is orphaned, because there is no
+ process in the session which is not in the process
+ group. Now if the process group leader (i.e. your program)
+ gets a TTIN/TTOU/TSTP, POSIX states that the kernel must
+ send a KILL signal to the process group because there is no
+ one left to continue the process. Even if screen would
+ try to restart the program, that would be after it received the
+ KILL signal which cannot be caught or ignored.
+
+ tromey@klab.caltech.edu (Tom Tromey): I've noticed this exact
+ same problem. I put this in my .emacs file. It seems to work:
+
+ ;; If running under screen, disable C-z.
+ (if (and (getenv "STY") (not window-system))
+ (global-unset-key "\C-z"))
+
+Q: Screen gets the terminal size wrong and messes up.
+
+A: Before you start screen: Check with 'stty -a' what the terminal
+ driver thinks about rows and columns. Check the environment
+ variables LINES and COLUMNS. Then from within screen check with
+ the info command (CTRL-A i) what size screen thinks your terminal
+ is. If correcting tty driver setting and environment variables
+ does not help, look up the terminal capability definition. First
+ the TERMCAP environment variable. If this is not set, look up the
+ terminals name as defined in the environment variable TERM in
+ /etc/termcap or in the terminfo database with untic or infocmp.
+ There may be :li=...: and :co=...: or even :ll=...: entries
+ (cols#... and lines#... when it's terminfo) defined incorrectly.
+ Either construct your own TERMCAP environment variables with
+ correct settings, use screens terminfo/termcap command in your
+ .screenrc file or have the database corrected by the system
+ administrator.
+
+Q: Screen messes up the terminal output when I use my favourite ap-
+ plication. Setting the terminal size does not help.
+
+A: Probably you got the termcap/terminfo entries wrong. Fixing this
+ is a three stage procedure. First, find out if terminfo or
+ termcap is used. If your system only has /etc/termcap,
+ but not /usr/lib/terminfo/... then you are using termcap.
+ Easy. But if your system has both, then it depends how the appli-
+ cation and how screen were linked. Beware, if your applica-
+ tion runs on another host via rlogin, telnet or the like, you
+ should check the terminfo/termcap databases there. If you cannot
+ tell if terminfo or termcap is used (or you just want to be
+ save), the do all steps in stage 3 in parallel for both
+ systems (on all envolved hosts). Second: Understand the basic
+ rules how screen does its terminal emulation. When screen is
+ started or reattached, it relies on the TERM environment variable
+ to correctly reflect the terminal type you have physically
+ in front of you. And the entry should either exist in the system
+ terminfo/termcap database or be specified via the TERMCAP en-
+ vironment variable (if screen is using the termcap system). On
+ the other end, screen understands one set of control codes. It
+ relies on the application using these codes. This means applica-
+ tions that run under screen must be able to adapt their con-
+ trol codes to screen. The application should use the TERM vari-
+ able and termcap or terminfo library to find out how to drive
+ its terminal. When running under screen, the terminal is virtual
+ and is only defined by the set of control codes that screen
+ understands. The TERM variable is automatically set to
+ "screen" and the "screen"-entries should exist in the data-
+ bases. If your application uses hardcoded control codes rather
+ than a database, you are on your own. Hint: The codes under-
+ stood by screen are a superset of the very common definition
+ named "vt100". Look at the documentation of screen. The
+ codes are listed there. Third: Have the entry "screen" in-
+ stalled on all hosts or make sure you can live with "vt100".
+ Check the codes sent by your application, when the TERM variable
+ is set to "screen". Do not try to set the TERM variable inside
+ screen to anything other than "screen" or "vt100" or compati-
+ ble. Thus your application can drive screen correctly. Also take
+ care that a good entry is installed for your physical terminal
+ that screen has to drive. Even if the entry was good enough
+ for your application to drive the terminal directly, screen may
+ find flaws, as it tries to use other capabilities while op-
+ timizing the screen output. The screenrc commands
+ "termcap" and/or "terminfo" may help to fine-tune capabilities
+ without calling the supervisor to change the database.
+
+Q: I cannot configure screen. Sed does not work.
+
+A: The regular expressions used in our configure scrip are too
+ complicated for GNU sed version 2.03. In this regard it is bug
+ compatible with Ultrix 3.1 "sed": GNU sed version 2.03 dumps
+ core with our configure script. Try an older release. E.g. from
+ ftp.uni-erlangen.de:/pub/utilities/screen/sed-2.02b.tar.gz
+
+Q: When reattaching a session from a different Workstation, the
+ DISPLAY environment variable should be updated. Even ``CTLR-A
+ : setenv DISPLAY newhost:0'' does not work as expected.
+
+A: Under unix every process has its own environment. The environ-
+ ment of the SCREEN process can be changed with the `setenv' com-
+ mand. This however cannot affect the environment of the
+ shells or applications already running under screen. Subsequently
+ spawned processes will reflect the changes. One should be aware
+ of this problem when running applications from very old shells.
+ Screen is a means for keeping processes alive.
+
+Q: About once every 5 times I ran the program, rather than getting
+ a "screen," I got someone elses IRC output/input.
+
+A: What probably happened is that an IRC process was left running on
+ a pseudo tty in such a way that the kernel thought the tty was
+ available for reallocation. You can fix this behaviour by
+ applying the SunOS 4.1.x tty jumbo patch (100513-04).
+
+Q: Screen compiled on SunOS 5.3 cannot reattach a detached session.
+
+A: You are using /usr/ucb/cc, this compiler is wrong. Actually it
+ links with a C-library that mis-interprets dirent. Try again
+ with /opt/SUNWspro/bin/cc!
+
+Q: The "talk" command does not work when Screen is active.
+
+A: Talk and several other programs rely on entries in the Utmp-
+ Database (/etc/utmp). On some systems this Database is world
+ writable, on others it is not. If it is not, screen must be
+ installed with the appropriate permissions (user or group s-bit)
+ just like any program that uses PTYs (rlogin, xterm, ...). When
+ screen cannot write to utmp, you will see messages on you display
+ which do not belong to any screen window.
+ When screen can update utmp, it is not guaranteed that it does as
+ you expect. First this depends on the config.h file defining
+ UTMPOK, LOGINDEFAULT, and perhaps CAREFULUTMP. Second it depends
+ on the screenrc files (system wide and per user), if utmp entries
+ are done. Third, you can control whether windows are logged in
+ with screens ``login'' command.
+
+Q: Seteuid() does not work as expected in AIX. Attempting a multi-
+ user-attach results in a screen-panic: "seteuid: not owner".
+
+A: This is not a screen problem. According to Kay Nettle
+ (pkn@cs.utexas.edu) you need the AIX patch PTF 423674.
+
+Q: When I type cd directory (any directory or just blank) from
+ within one of the windows in screen, the whole thing just freezes
+ up.
+
+A: You display the current working directory in xterm's title bar,
+ This may be caused by hardcoded ESC-sequences in the shell prompt
+ or in an cd alias. In Xterm the coding is
+ ESC ] n ; string_to_display ^G
+ where n = 1, 2, 3 selects the location of the displayed string.
+ Screen misinterprets this as the ansi operating system comment
+ sequence:
+ ESC ] osc_string
+ and waits (according to ansi) for the string terminator
+ ESC \
+ Screen versions after 3.5.12 may provide a workaround.
+
+Q: Mesg or biff cannot be turned on or off while running screen.
+
+A: Screen failed to change the owner of the pty it uses. You need to
+ install screen setuid-root. See the file INSTALL for details.
+
+Q: The cursor left key deletes the characters instead of just moving the
+ cursor. A redisplay (^Al) brings everything back.
+
+A: Your terminal emulator treats the backspace as "destructive". You
+ can probably change this somewhere in the setup. We can't think
+ of a reason why anybody would want a destructive backspace, but
+ if you really must have it, add the lines
+ termcap <TERM> 'bc@:bs@'
+ terminfo <TERM> 'bc@:bs@'
+ to your ~/.screenrc (replace <TERM> with the terminal type your
+ emulator uses).
+
+Q: I have an old SysV OS (like Motorola SysV68) and sometimes screen
+ doesn't reset the attributes correctly. A redisplay (^Al) doesn't
+ make things better.
+
+A: The libcurses library has a bug if attributes are cleared with
+ the special ue/se capabilities. As a workaround (other than upgrading
+ your system) modify 'rmul' (and 'rmso'?) in screen's terminfo entry:
+ rmul=\E[m, rmso=\E[m
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644
index 0000000..ce1930b
--- /dev/null
+++ b/doc/Makefile.in
@@ -0,0 +1,54 @@
+# Makefile for Screen documentation
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = /usr/local
+mandir = $(prefix)/man
+infodir = $(prefix)/info
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+MAKEINFO = makeinfo
+TEXI2DVI = texi2dvi
+
+SHELL = /bin/sh
+
+all: screen.info
+
+dvi screen.dvi: screen.texinfo mostlyclean
+ $(TEXI2DVI) $(srcdir)/screen.texinfo
+
+info screen.info: screen.texinfo
+ $(MAKEINFO) $(srcdir)/screen.texinfo -o screen.info
+
+install: installdirs
+ $(INSTALL_DATA) $(srcdir)/screen.1 $(mandir)/man1/screen.1
+ -$(MAKE) screen.info
+ -if test -f screen.info; then d=.; else d=$(srcdir); fi; \
+ if test -f $$d/screen.info; then \
+ for f in $$d/screen.info*; do $(INSTALL_DATA) $$f $(infodir);done; \
+ if $(SHELL) -c 'install-info --version' >/dev/null 2>&1; then \
+ install-info --infodir=$(infodir) $$d/screen.info; \
+ else true; fi; \
+ fi
+
+uninstall:
+ rm -f $(mandir)/man1/screen.1
+ rm -f $(infodir)/screen.info*
+
+installdirs:
+ $(srcdir)/../etc/mkinstalldirs $(mandir)/man1 $(infodir)
+
+mostlyclean:
+ -rm -f *.cp *.cps *.fn *.fns *.ky *.kys *.pg *.tp *.vr
+ -rm -f *.log *.aux *.toc *~
+
+clean distclean clobber: mostlyclean
+ -rm -f *.dvi
+
+realclean: clean
+ -rm -f *.info*
+
+check installcheck:
+
diff --git a/doc/fdpat.ps b/doc/fdpat.ps
new file mode 100644
index 0000000..6b10099
--- /dev/null
+++ b/doc/fdpat.ps
@@ -0,0 +1,6501 @@
+%!PS-Adobe-2.0 EPSF-1.2
+%%DocumentFonts: Courier Helvetica-Bold Times-Roman
+%%Pages: 1
+%%BoundingBox: 5 34 589 773
+%%EndComments
+
+/arrowHeight 10 def
+/arrowWidth 5 def
+
+/IdrawDict 53 dict def
+IdrawDict begin
+
+/reencodeISO {
+dup dup findfont dup length dict begin
+{ 1 index /FID ne { def }{ pop pop } ifelse } forall
+/Encoding ISOLatin1Encoding def
+currentdict end definefont
+} def
+
+/ISOLatin1Encoding [
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright
+/parenleft/parenright/asterisk/plus/comma/minus/period/slash
+/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon
+/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N
+/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright
+/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m
+/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve
+/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut
+/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar
+/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot
+/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior
+/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine
+/guillemotright/onequarter/onehalf/threequarters/questiondown
+/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla
+/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex
+/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute
+/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis
+/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave
+/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex
+/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis
+/yacute/thorn/ydieresis
+] def
+/Courier reencodeISO def
+/Helvetica-Bold reencodeISO def
+/Times-Roman reencodeISO def
+
+/none null def
+/numGraphicParameters 17 def
+/stringLimit 65535 def
+
+/Begin {
+save
+numGraphicParameters dict begin
+} def
+
+/End {
+end
+restore
+} def
+
+/SetB {
+dup type /nulltype eq {
+pop
+false /brushRightArrow idef
+false /brushLeftArrow idef
+true /brushNone idef
+} {
+/brushDashOffset idef
+/brushDashArray idef
+0 ne /brushRightArrow idef
+0 ne /brushLeftArrow idef
+/brushWidth idef
+false /brushNone idef
+} ifelse
+} def
+
+/SetCFg {
+/fgblue idef
+/fggreen idef
+/fgred idef
+} def
+
+/SetCBg {
+/bgblue idef
+/bggreen idef
+/bgred idef
+} def
+
+/SetF {
+/printSize idef
+/printFont idef
+} def
+
+/SetP {
+dup type /nulltype eq {
+pop true /patternNone idef
+} {
+dup -1 eq {
+/patternGrayLevel idef
+/patternString idef
+} {
+/patternGrayLevel idef
+} ifelse
+false /patternNone idef
+} ifelse
+} def
+
+/BSpl {
+0 begin
+storexyn
+newpath
+n 1 gt {
+0 0 0 0 0 0 1 1 true subspline
+n 2 gt {
+0 0 0 0 1 1 2 2 false subspline
+1 1 n 3 sub {
+/i exch def
+i 1 sub dup i dup i 1 add dup i 2 add dup false subspline
+} for
+n 3 sub dup n 2 sub dup n 1 sub dup 2 copy false subspline
+} if
+n 2 sub dup n 1 sub dup 2 copy 2 copy false subspline
+patternNone not brushLeftArrow not brushRightArrow not and and { ifill } if
+brushNone not { istroke } if
+0 0 1 1 leftarrow
+n 2 sub dup n 1 sub dup rightarrow
+} if
+end
+} dup 0 4 dict put def
+
+/Circ {
+newpath
+0 360 arc
+patternNone not { ifill } if
+brushNone not { istroke } if
+} def
+
+/CBSpl {
+0 begin
+dup 2 gt {
+storexyn
+newpath
+n 1 sub dup 0 0 1 1 2 2 true subspline
+1 1 n 3 sub {
+/i exch def
+i 1 sub dup i dup i 1 add dup i 2 add dup false subspline
+} for
+n 3 sub dup n 2 sub dup n 1 sub dup 0 0 false subspline
+n 2 sub dup n 1 sub dup 0 0 1 1 false subspline
+patternNone not { ifill } if
+brushNone not { istroke } if
+} {
+Poly
+} ifelse
+end
+} dup 0 4 dict put def
+
+/Elli {
+0 begin
+newpath
+4 2 roll
+translate
+scale
+0 0 1 0 360 arc
+patternNone not { ifill } if
+brushNone not { istroke } if
+end
+} dup 0 1 dict put def
+
+/Line {
+0 begin
+2 storexyn
+newpath
+x 0 get y 0 get moveto
+x 1 get y 1 get lineto
+brushNone not { istroke } if
+0 0 1 1 leftarrow
+0 0 1 1 rightarrow
+end
+} dup 0 4 dict put def
+
+/MLine {
+0 begin
+storexyn
+newpath
+n 1 gt {
+x 0 get y 0 get moveto
+1 1 n 1 sub {
+/i exch def
+x i get y i get lineto
+} for
+patternNone not brushLeftArrow not brushRightArrow not and and { ifill } if
+brushNone not { istroke } if
+0 0 1 1 leftarrow
+n 2 sub dup n 1 sub dup rightarrow
+} if
+end
+} dup 0 4 dict put def
+
+/Poly {
+3 1 roll
+newpath
+moveto
+-1 add
+{ lineto } repeat
+closepath
+patternNone not { ifill } if
+brushNone not { istroke } if
+} def
+
+/Rect {
+0 begin
+/t exch def
+/r exch def
+/b exch def
+/l exch def
+newpath
+l b moveto
+l t lineto
+r t lineto
+r b lineto
+closepath
+patternNone not { ifill } if
+brushNone not { istroke } if
+end
+} dup 0 4 dict put def
+
+/Text {
+ishow
+} def
+
+/idef {
+dup where { pop pop pop } { exch def } ifelse
+} def
+
+/ifill {
+0 begin
+gsave
+patternGrayLevel -1 ne {
+fgred bgred fgred sub patternGrayLevel mul add
+fggreen bggreen fggreen sub patternGrayLevel mul add
+fgblue bgblue fgblue sub patternGrayLevel mul add setrgbcolor
+eofill
+} {
+eoclip
+originalCTM setmatrix
+pathbbox /t exch def /r exch def /b exch def /l exch def
+/w r l sub ceiling cvi def
+/h t b sub ceiling cvi def
+/imageByteWidth w 8 div ceiling cvi def
+/imageHeight h def
+bgred bggreen bgblue setrgbcolor
+eofill
+fgred fggreen fgblue setrgbcolor
+w 0 gt h 0 gt and {
+l b translate w h scale
+w h true [w 0 0 h neg 0 h] { patternproc } imagemask
+} if
+} ifelse
+grestore
+end
+} dup 0 8 dict put def
+
+/istroke {
+gsave
+brushDashOffset -1 eq {
+[] 0 setdash
+1 setgray
+} {
+brushDashArray brushDashOffset setdash
+fgred fggreen fgblue setrgbcolor
+} ifelse
+brushWidth setlinewidth
+originalCTM setmatrix
+stroke
+grestore
+} def
+
+/ishow {
+0 begin
+gsave
+fgred fggreen fgblue setrgbcolor
+printFont printSize scalefont setfont
+/descender 0 printFont /FontBBox get 1 get printFont /FontMatrix
+get transform exch pop def
+/vertoffset 1 printSize sub descender sub def {
+0 vertoffset moveto show
+/vertoffset vertoffset printSize sub def
+} forall
+grestore
+end
+} dup 0 2 dict put def
+
+/patternproc {
+0 begin
+/patternByteLength patternString length def
+/patternHeight patternByteLength 8 mul sqrt cvi def
+/patternWidth patternHeight def
+/patternByteWidth patternWidth 8 idiv def
+/imageByteMaxLength imageByteWidth imageHeight mul
+stringLimit patternByteWidth sub min def
+/imageMaxHeight imageByteMaxLength imageByteWidth idiv patternHeight idiv
+patternHeight mul patternHeight max def
+/imageHeight imageHeight imageMaxHeight sub store
+/imageString imageByteWidth imageMaxHeight mul patternByteWidth add string def
+0 1 imageMaxHeight 1 sub {
+/y exch def
+/patternRow y patternByteWidth mul patternByteLength mod def
+/patternRowString patternString patternRow patternByteWidth getinterval def
+/imageRow y imageByteWidth mul def
+0 patternByteWidth imageByteWidth 1 sub {
+/x exch def
+imageString imageRow x add patternRowString putinterval
+} for
+} for
+imageString
+end
+} dup 0 12 dict put def
+
+/min {
+dup 3 2 roll dup 4 3 roll lt { exch } if pop
+} def
+
+/max {
+dup 3 2 roll dup 4 3 roll gt { exch } if pop
+} def
+
+/midpoint {
+0 begin
+/y1 exch def
+/x1 exch def
+/y0 exch def
+/x0 exch def
+x0 x1 add 2 div
+y0 y1 add 2 div
+end
+} dup 0 4 dict put def
+
+/thirdpoint {
+0 begin
+/y1 exch def
+/x1 exch def
+/y0 exch def
+/x0 exch def
+x0 2 mul x1 add 3 div
+y0 2 mul y1 add 3 div
+end
+} dup 0 4 dict put def
+
+/subspline {
+0 begin
+/movetoNeeded exch def
+y exch get /y3 exch def
+x exch get /x3 exch def
+y exch get /y2 exch def
+x exch get /x2 exch def
+y exch get /y1 exch def
+x exch get /x1 exch def
+y exch get /y0 exch def
+x exch get /x0 exch def
+x1 y1 x2 y2 thirdpoint
+/p1y exch def
+/p1x exch def
+x2 y2 x1 y1 thirdpoint
+/p2y exch def
+/p2x exch def
+x1 y1 x0 y0 thirdpoint
+p1x p1y midpoint
+/p0y exch def
+/p0x exch def
+x2 y2 x3 y3 thirdpoint
+p2x p2y midpoint
+/p3y exch def
+/p3x exch def
+movetoNeeded { p0x p0y moveto } if
+p1x p1y p2x p2y p3x p3y curveto
+end
+} dup 0 17 dict put def
+
+/storexyn {
+/n exch def
+/y n array def
+/x n array def
+n 1 sub -1 0 {
+/i exch def
+y i 3 2 roll put
+x i 3 2 roll put
+} for
+} def
+
+%%EndProlog
+
+%%BeginIdrawPrologue
+/arrowhead {
+0 begin
+transform originalCTM itransform
+/taily exch def
+/tailx exch def
+transform originalCTM itransform
+/tipy exch def
+/tipx exch def
+/dy tipy taily sub def
+/dx tipx tailx sub def
+/angle dx 0 ne dy 0 ne or { dy dx atan } { 90 } ifelse def
+gsave
+originalCTM setmatrix
+tipx tipy translate
+angle rotate
+newpath
+arrowHeight neg arrowWidth 2 div moveto
+0 0 lineto
+arrowHeight neg arrowWidth 2 div neg lineto
+patternNone not {
+originalCTM setmatrix
+/padtip arrowHeight 2 exp 0.25 arrowWidth 2 exp mul add sqrt brushWidth mul
+arrowWidth div def
+/padtail brushWidth 2 div def
+tipx tipy translate
+angle rotate
+padtip 0 translate
+arrowHeight padtip add padtail add arrowHeight div dup scale
+arrowheadpath
+ifill
+} if
+brushNone not {
+originalCTM setmatrix
+tipx tipy translate
+angle rotate
+arrowheadpath
+istroke
+} if
+grestore
+end
+} dup 0 9 dict put def
+
+/arrowheadpath {
+newpath
+arrowHeight neg arrowWidth 2 div moveto
+0 0 lineto
+arrowHeight neg arrowWidth 2 div neg lineto
+} def
+
+/leftarrow {
+0 begin
+y exch get /taily exch def
+x exch get /tailx exch def
+y exch get /tipy exch def
+x exch get /tipx exch def
+brushLeftArrow { tipx tipy tailx taily arrowhead } if
+end
+} dup 0 4 dict put def
+
+/rightarrow {
+0 begin
+y exch get /tipy exch def
+x exch get /tipx exch def
+y exch get /taily exch def
+x exch get /tailx exch def
+brushRightArrow { tipx tipy tailx taily arrowhead } if
+end
+} dup 0 4 dict put def
+
+%%EndIdrawPrologue
+
+%I Idraw 10 Grid 8.86154 8.86154
+
+%%Page: 1 1
+
+Begin
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ .959646 0 0 .959646 0 0 ] concat
+/originalCTM matrix currentmatrix def
+
+Begin %I Line
+%I b 65535
+0 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+none SetP %I p n
+%I t
+[ .833333 -0 -0 .833333 -23.3333 378.333 ] concat
+%I
+37 397 764 397 Line
+%I 1
+End
+
+Begin %I Line
+%I b 65535
+0 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+none SetP %I p n
+%I t
+[ .833333 -0 -0 .833333 -23.3333 282.5 ] concat
+%I
+37 397 764 397 Line
+%I 1
+End
+
+Begin %I Line
+%I b 65535
+0 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+none SetP %I p n
+%I t
+[ .833333 -0 -0 .833333 -24.1667 185.833 ] concat
+%I
+37 397 764 397 Line
+%I 1
+End
+
+Begin %I Line
+%I b 65535
+0 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+none SetP %I p n
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -5.83331 ] concat
+%I
+37 397 764 397 Line
+%I 1
+End
+
+Begin %I Line
+%I b 65535
+0 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+none SetP %I p n
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -101.667 ] concat
+%I
+37 397 764 397 Line
+%I 1
+End
+
+Begin %I Line
+%I b 65535
+0 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+none SetP %I p n
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -197.5 ] concat
+%I
+37 397 764 397 Line
+%I 1
+End
+
+Begin %I Line
+%I b 65535
+0 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+none SetP %I p n
+%I t
+[ .833333 -0 -0 .833333 -23.3333 392.5 ] concat
+%I
+37 34 764 34 Line
+%I 1
+End
+
+Begin %I Line
+%I b 65535
+0 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+none SetP %I p n
+%I t
+[ .833333 -0 -0 .833333 -15.8333 2.5 ] concat
+%I
+258 963 258 41 Line
+%I 1
+End
+
+Begin %I Line
+%I b 65535
+0 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+none SetP %I p n
+%I t
+[ .833333 -0 -0 .833333 198.833 3 ] concat
+%I
+258 963 258 41 Line
+%I 1
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 213.667 797 ] concat
+%I
+[
+(Subshell, error back)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 428 797 ] concat
+%I
+[
+(Input echo filter)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 22.8333 704.333 ] concat
+%I
+[
+(Input filter)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 214.833 704.333 ] concat
+%I
+[
+(Input Filter, error back)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 428.833 704.333 ] concat
+%I
+[
+(input filter, error echo)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 214 607.5 ] concat
+%I
+[
+(Output filter)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 428 607.5 ] concat
+%I
+[
+(Error robot)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 15 729.966 ] concat
+%I
+[
+(...)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 15 57.4667 ] concat
+%I
+[
+(...)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 214.167 57.4667 ] concat
+%I
+[
+(...)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 428.333 57.4667 ] concat
+%I
+[
+(...)
+] Text
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 45.8332 ] concat
+%I 5
+161 743
+179 743
+205 743
+205 716
+205 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 45.8332 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 45.8332 ] concat
+%I 2
+55 743
+143 743
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -50.0001 ] concat
+%I 5
+196 707
+196 716
+196 734
+179 734
+161 734
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -50.0001 ] concat
+%I 5
+161 743
+179 743
+205 743
+205 716
+205 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -57.5001 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -50.0001 ] concat
+%I 2
+55 743
+143 743
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -50.0001 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -50.0001 ] concat
+%I 5
+489 760
+471 760
+462 760
+462 752
+462 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 5
+188 707
+188 716
+188 725
+179 725
+161 725
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 5
+196 707
+196 716
+196 734
+179 734
+161 734
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 5
+161 743
+179 743
+205 743
+205 716
+205 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 134.167 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 2
+55 743
+143 743
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -145.833 ] concat
+%I 5
+188 707
+188 716
+188 725
+179 725
+161 725
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -153.333 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 0 -671.666 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 -214.167 -671.666 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 199.166 -671.666 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 5
+444 707
+444 760
+444 778
+471 778
+489 778
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 141.667 ] concat
+%I 5
+196 707
+196 716
+196 734
+179 734
+161 734
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 141.667 ] concat
+%I 5
+161 743
+179 743
+205 743
+205 716
+205 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 134.167 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 141.667 ] concat
+%I 2
+55 743
+143 743
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 141.667 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 428.333 729.966 ] concat
+%I
+[
+(..: .:. .::)
+] Text
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 45.8332 ] concat
+%I 2
+55 743
+143 743
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 30.8334 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 45 ] concat
+%I 5
+444 707
+444 760
+444 778
+471 778
+489 778
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 141.667 ] concat
+%I 5
+196 707
+196 716
+196 734
+179 734
+161 734
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 141.667 ] concat
+%I 5
+161 743
+179 743
+205 743
+205 716
+205 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 141.667 ] concat
+%I 2
+55 743
+143 743
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 141.667 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 134.167 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 175.833 237.5 ] concat
+%I 6
+400 619
+391 619
+365 619
+365 645
+391 645
+489 645
+6 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 141.667 ] concat
+%I 5
+188 707
+188 716
+188 725
+179 725
+161 725
+5 BSpl
+%I 1
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 15 633.3 ] concat
+%I
+[
+(.!.)
+] Text
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 45.8333 ] concat
+%I 5
+188 707
+188 716
+188 725
+179 725
+161 725
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 38.3334 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -237.5 45.8332 ] concat
+%I 5
+453 707
+453 752
+453 769
+471 769
+489 769
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 45.8333 ] concat
+%I 5
+161 743
+179 743
+205 743
+205 716
+205 707
+5 BSpl
+%I 1
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 214.167 633.3 ] concat
+%I
+[
+(.!!)
+] Text
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 45.8332 ] concat
+%I 5
+453 707
+453 752
+453 769
+471 769
+489 769
+5 BSpl
+%I 1
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 214.167 729.966 ] concat
+%I
+[
+(..!)
+] Text
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 45.8332 ] concat
+%I 5
+161 743
+179 743
+205 743
+205 716
+205 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 45.8332 ] concat
+%I 2
+55 743
+143 743
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 45.8334 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 175.833 45.8332 ] concat
+%I 5
+453 707
+453 752
+453 769
+471 769
+489 769
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 175.833 141.667 ] concat
+%I 6
+400 619
+391 619
+365 619
+365 645
+391 645
+489 645
+6 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 45.8333 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 428.333 633.3 ] concat
+%I
+[
+(.!:)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 15 537.466 ] concat
+%I
+[
+(.:!)
+] Text
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -236.667 -50.8333 ] concat
+%I 5
+444 707
+444 760
+444 778
+471 778
+489 778
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -237.5 45.8333 ] concat
+%I 6
+400 619
+391 619
+365 619
+365 645
+391 645
+489 645
+6 BSpl
+%I 1
+End
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t u
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 -214.167 6.10352e-05 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 199.166 7.62939e-05 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 0 -95.8334 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 -214.167 -95.8333 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 199.166 -95.8333 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 214.167 537.466 ] concat
+%I
+[
+(!..)
+] Text
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 189.167 -50 ] concat
+%I 5
+188 707
+188 716
+188 725
+179 725
+161 725
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 1 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 -57.5 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 -50.8333 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 175.833 -50.0001 ] concat
+%I 5
+489 760
+471 760
+462 760
+462 752
+462 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -50 ] concat
+%I 5
+196 707
+196 716
+196 734
+179 734
+161 734
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 1 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -57.5 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -50.8333 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 176.667 -50 ] concat
+%I 5
+444 707
+444 760
+444 778
+471 778
+489 778
+5 BSpl
+%I 1
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 428.333 537.466 ] concat
+%I
+[
+(!.!)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 22 607.5 ] concat
+%I
+[
+(Input echo filter, error back)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 21.1667 510.833 ] concat
+%I
+[
+(Robot)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 15 441.633 ] concat
+%I
+[
+(!!.)
+] Text
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -237.5 -145.833 ] concat
+%I 5
+489 760
+471 760
+462 760
+462 752
+462 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -237.5 -145.833 ] concat
+%I 5
+453 707
+453 752
+453 769
+471 769
+489 769
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -145.833 ] concat
+%I 5
+489 760
+471 760
+462 760
+462 752
+462 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -145.833 ] concat
+%I 5
+453 707
+453 752
+453 769
+471 769
+489 769
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -145.833 ] concat
+%I 5
+444 707
+444 760
+444 778
+471 778
+489 778
+5 BSpl
+%I 1
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 214.167 441.633 ] concat
+%I
+[
+(!!!)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 427.167 510.833 ] concat
+%I
+[
+(Full robot, error echo)
+] Text
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 175.833 -145.833 ] concat
+%I 5
+489 760
+471 760
+462 760
+462 752
+462 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 175.833 -145.833 ] concat
+%I 5
+453 707
+453 752
+453 769
+471 769
+489 769
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -146.667 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 6
+639 388
+630 388
+586 388
+586 433
+631 433
+728 433
+6 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 5
+684 361
+684 379
+684 388
+675 388
+657 388
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 334.167 ] concat
+%I 5
+684 361
+684 379
+684 388
+675 388
+657 388
+5 BSpl
+%I 1
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 428.333 441.633 ] concat
+%I
+[
+(!!:)
+] Text
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -237.5 -241.667 ] concat
+%I 5
+489 760
+471 760
+462 760
+462 752
+462 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -242.5 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 6
+143 273
+134 273
+99 273
+99 309
+134 309
+232 309
+6 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -242.5 ] concat
+%I 5
+196 707
+196 716
+196 734
+179 734
+161 734
+5 BSpl
+%I 1
+End
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 -214.167 -191.667 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 0 -191.667 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 199.166 -191.667 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 15 345.8 ] concat
+%I
+[
+(!:!)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 213.167 510.833 ] concat
+%I
+[
+(Full robot)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 214.167 345.8 ] concat
+%I
+[
+(!:: !:. !.:)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 213.167 415 ] concat
+%I
+[
+(Full robot, out & error echo)
+] Text
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -241.667 ] concat
+%I 5
+489 760
+471 760
+462 760
+462 752
+462 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 -242.5 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 141.667 ] concat
+%I 6
+143 273
+134 273
+99 273
+99 309
+134 309
+232 309
+6 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 -242.5 ] concat
+%I 5
+196 707
+196 716
+196 734
+179 734
+161 734
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -38.3333 -4.16667 ] concat
+%I 5
+471 652
+471 661
+471 679
+454 679
+436 679
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 189.167 -242.5 ] concat
+%I 5
+188 707
+188 716
+188 725
+179 725
+161 725
+5 BSpl
+%I 1
+End
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 199.166 -287.5 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 0 -287.5 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 -214.167 -287.5 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 428.333 345.8 ] concat
+%I
+[
+(:..)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 427.167 415 ] concat
+%I
+[
+(Output echo filter)
+] Text
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -242.5 ] concat
+%I 5
+188 707
+188 716
+188 725
+179 725
+161 725
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -242.5 ] concat
+%I 5
+196 707
+196 716
+196 734
+179 734
+161 734
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -242.5 ] concat
+%I 5
+161 743
+179 743
+205 743
+205 716
+205 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 1 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -242.5 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -249.167 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -242.5 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 199.166 -383.333 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 0 -383.333 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 -214.167 -383.333 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -38.3333 -4.16667 ] concat
+%I 6
+657 484
+649 484
+622 484
+622 457
+649 457
+657 457
+6 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -339.167 ] concat
+%I 5
+196 707
+196 716
+196 734
+179 734
+161 734
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -339.167 ] concat
+%I 5
+161 743
+179 743
+205 743
+205 716
+205 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -345.833 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -339.167 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -451.667 -100.833 ] concat
+%I 6
+657 484
+649 484
+622 484
+622 457
+649 457
+657 457
+6 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -236.667 -338.333 ] concat
+%I 5
+444 707
+444 752
+444 778
+471 778
+489 778
+5 BSpl
+%I 1
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 21.1667 415 ] concat
+%I
+[
+(Full Robot, output echo)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 21.1667 319.167 ] concat
+%I
+[
+(Output echo filter, error back)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 15 249.967 ] concat
+%I
+[
+(:.!)
+] Text
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190 -339.167 ] concat
+%I 5
+196 707
+196 716
+196 734
+179 734
+161 734
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190 -339.167 ] concat
+%I 5
+161 743
+179 743
+205 743
+205 716
+205 707
+5 BSpl
+%I 1
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 427.167 319.167 ] concat
+%I
+[
+(Robot, input echo)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 21.1667 223.333 ] concat
+%I
+[
+(Full robot, input echo)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 427.167 223.333 ] concat
+%I
+[
+(Full robot, input & output echo)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 213.167 223.333 ] concat
+%I
+[
+(Full robot, input & error echo)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 213.167 319.167 ] concat
+%I
+[
+(Full robot, full echo)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 214.167 249.967 ] concat
+%I
+[
+(::: ::. :.:)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 428.333 249.967 ] concat
+%I
+[
+(:!.)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 15 154.133 ] concat
+%I
+[
+(:!!)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 214.167 154.133 ] concat
+%I
+[
+(:!:)
+] Text
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-helvetica-bold-r-*-140-*
+Helvetica-Bold 14 SetF
+%I t
+[ 1.6 0 0 1.6 428.333 154.133 ] concat
+%I
+[
+(::!)
+] Text
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190 -338.333 ] concat
+%I 5
+188 707
+188 716
+188 725
+179 725
+161 725
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -15.8333 .833333 ] concat
+%I 6
+391 353
+382 353
+365 353
+365 336
+382 336
+391 336
+6 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 .833333 ] concat
+%I 6
+400 327
+391 327
+356 327
+356 363
+391 363
+489 362
+6 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 .833364 ] concat
+%I 2
+489 353
+312 353
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 .833364 ] concat
+%I 2
+400 327
+312 327
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -339.167 ] concat
+%I 5
+161 743
+179 743
+205 743
+205 716
+205 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -338.333 ] concat
+%I 5
+188 707
+188 716
+188 725
+179 725
+161 725
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 184.167 .833333 ] concat
+%I 6
+391 353
+382 353
+365 353
+365 336
+382 336
+391 336
+6 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 176.667 .833364 ] concat
+%I 2
+489 353
+312 353
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 175.833 -337.5 ] concat
+%I 5
+453 707
+453 752
+453 769
+471 769
+489 769
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -345.833 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -435 ] concat
+%I 5
+161 743
+179 743
+205 743
+205 716
+205 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -229.167 -95 ] concat
+%I 6
+391 353
+382 353
+365 353
+365 336
+382 336
+391 336
+6 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -236.667 -94.9999 ] concat
+%I 2
+489 353
+312 353
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -237.5 -433.333 ] concat
+%I 5
+453 707
+453 752
+453 769
+471 769
+489 769
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3332 -441.667 ] concat
+%I 2
+143 734
+55 734
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -236.667 -434.166 ] concat
+%I 5
+444 707
+444 752
+444 778
+471 778
+489 778
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190 -435 ] concat
+%I 5
+161 743
+179 743
+205 743
+205 716
+205 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190 -434.167 ] concat
+%I 5
+188 707
+188 716
+188 725
+179 725
+161 725
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -15.8333 -95 ] concat
+%I 6
+391 353
+382 353
+365 353
+365 336
+382 336
+391 336
+6 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -94.9999 ] concat
+%I 2
+489 353
+312 353
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 -94.9999 ] concat
+%I 2
+400 327
+312 327
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -24.1669 -434.166 ] concat
+%I 5
+453 707
+453 752
+453 769
+471 769
+489 769
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 .833333 ] concat
+%I 5
+188 415
+188 460
+188 486
+214 486
+233 486
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 1 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 -338.333 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 1 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 -242.5 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 1 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3332 -145.833 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 1 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3332 -353.333 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 1 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -338.333 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 1 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3332 -434.167 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 1 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3332 -249.167 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 1 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 190.833 -145.833 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 1 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390.833 -145.833 ] concat
+%I 2
+232 778
+55 778
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 389.167 -435 ] concat
+%I 5
+161 743
+179 743
+205 743
+205 716
+205 707
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 183.333 -95 ] concat
+%I 6
+391 353
+382 353
+365 353
+365 336
+382 336
+391 336
+6 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 175.833 -94.9999 ] concat
+%I 2
+489 353
+312 353
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 175.833 -94.9999 ] concat
+%I 2
+400 327
+312 327
+2 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 390 -434.167 ] concat
+%I 5
+196 707
+196 716
+196 734
+179 734
+161 734
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 176.667 -434.167 ] concat
+%I 5
+444 707
+444 760
+444 778
+471 778
+489 778
+5 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 1 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 .833333 ] concat
+%I 2
+728 247
+551 247
+2 BSpl
+%I 1
+End
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 -214.167 -480 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 0 -480 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 199.166 -480 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 199.166 -575.833 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 -0.000432014 -575.833 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b 65535
+1 0 0 [] 0 SetB
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 -214.167 -575.833 ] concat
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 214.167 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+143 716
+161 716
+161 752
+143 752
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 99.8333 758.833 ] concat
+%I
+[
+(P)
+] Text
+End
+
+End %I eop
+
+Begin %I Pict
+%I b u
+%I cfg u
+%I cbg u
+%I f u
+%I p u
+%I t
+[ 1 0 0 1 221.667 -0.000366211 ] concat
+
+Begin %I Poly
+%I b 65535
+2 0 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 -23.3333 141.667 ] concat
+%I 4
+223 752
+241 752
+241 787
+223 787
+4 Poly
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 164 788.416 ] concat
+%I
+[
+(W)
+] Text
+End
+
+End %I eop
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f *-times-medium-r-*-140-*
+Times-Roman 14 SetF
+%I t
+[ 1 0 0 1 344.333 725.833 ] concat
+%I
+[
+(210)
+] Text
+End
+
+End %I eop
+
+Begin %I BSpl
+%I b 65535
+1 0 1 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 125 181.667 ] concat
+%I 6
+222 -5
+213 -5
+169 -5
+169 39
+240 39
+311 39
+6 BSpl
+%I 1
+End
+
+Begin %I BSpl
+%I b 65535
+1 1 0 [] 0 SetB
+%I cfg Black
+0 0 0 SetCFg
+%I cbg White
+1 1 1 SetCBg
+%I p
+1 SetP
+%I t
+[ .833333 -0 -0 .833333 125 181.667 ] concat
+%I 2
+222 39
+134 39
+2 BSpl
+%I 1
+End
+
+Begin %I Text
+%I cfg Black
+0 0 0 SetCFg
+%I f -*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*
+Courier 8 SetF
+%I t
+[ 1 0 0 1 22 797 ] concat
+%I
+[
+(Subshell)
+] Text
+End
+
+End %I eop
+
+showpage
+
+%%Trailer
+
+end
diff --git a/doc/install.sh b/doc/install.sh
new file mode 100755
index 0000000..8c07c50
--- /dev/null
+++ b/doc/install.sh
@@ -0,0 +1,119 @@
+#! /bin/sh
+
+#
+# install - install a program, script, or datafile
+# This comes from X11R5; it is not part of GNU.
+#
+# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+
+instcmd="$mvprog"
+chmodcmd=""
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+fi
+
+if [ x"$dst" = x ]
+then
+ echo "install: no destination specified"
+ exit 1
+fi
+
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+if [ -d $dst ]
+then
+ dst="$dst"/`basename $src`
+fi
+
+# Make a temp file name in the proper directory.
+
+dstdir=`dirname $dst`
+dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+$doit $instcmd $src $dsttmp
+
+# and set any options; do chmod last to preserve setuid bits
+
+if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi
+if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi
+if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi
+if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi
+
+# Now rename the file to the real destination.
+
+$doit $rmcmd $dst
+$doit $mvcmd $dsttmp $dst
+
+
+exit 0
diff --git a/doc/screen.1 b/doc/screen.1
new file mode 100644
index 0000000..558e314
--- /dev/null
+++ b/doc/screen.1
@@ -0,0 +1,3349 @@
+.\" vi:set wm=5
+.TH SCREEN 1 "15 Oct 1995"
+.if n .ds Q \&"
+.if n .ds U \&"
+.if t .ds Q ``
+.if t .ds U ''
+.UC 4
+.SH NAME
+screen \- screen manager with VT100/ANSI terminal emulation
+
+
+.SH SYNOPSIS
+.B screen
+[
+.B \-\fIoptions\fP
+] [
+.B \fIcmd\fP
+[
+.B \fIargs\fP
+] ]
+.br
+.B screen \-r
+[ [\fIpid.\fP]\fItty\fP[\fI.host\fP] ]
+.ta .5i 1.8i
+
+
+.SH DESCRIPTION
+.I Screen
+is a full-screen window manager that
+multiplexes a physical terminal between several processes (typically
+interactive shells).
+Each virtual terminal provides the functions
+of a DEC VT100 terminal and, in addition, several control functions
+from the ANSI X3.64 (ISO 6429) and ISO 2022 standards
+(e.\|g. insert/delete line and support for multiple character sets).
+There is a scrollback history buffer for each virtual terminal and a
+copy-and-paste mechanism that allows moving text regions between
+windows.
+.PP
+When
+.I screen
+is called, it creates a single window with a shell in it (or the specified
+command) and then gets out of your way so that you can use the program as you
+normally would.
+Then, at any time, you can create new (full-screen) windows with other programs
+in them (including more shells), kill existing windows, view a list of
+windows, turn output logging on and off, copy-and-paste text between
+windows, view the scrollback history, switch between windows
+in whatever manner you wish, etc.
+When a program terminates,
+.I screen
+(per default) kills the window that contained it.
+If this window was in the foreground, the display switches to the previous
+window; if none are left,
+.I screen
+exits.
+.PP
+Everything you type is sent to the program running in the current window.
+The only exception to this is the one keystroke that is used to initiate
+a command to the window manager.
+By default, each command begins with a control-a (abbreviated C-a from
+now on), and is followed by one other keystroke.
+The command character and all the key bindings can be fully customized
+to be anything you like, though they are always two characters in length.
+.PP
+The standard way to create a new window is to type \*QC-a c\*U.
+This creates a new window running a shell and switches to that
+window immediately, regardless of the state of the process running
+in the current window.
+Similarly, you can create a new window with a custom command in it by
+first binding the command to a keystroke (in your .screenrc file or at the
+\*QC-a :\*U command line) and
+then using it just like the \*QC-a c\*U command.
+In addition, new windows can be created by running a command like:
+.IP
+screen emacs prog.c
+.PP
+from a shell prompt within a previously created window.
+This will not run another copy of
+.IR screen ,
+but will instead supply the command name and its arguments to the window
+manager (specified in the $STY environment variable) who will use it to
+create the new window.
+The above example would start the emacs editor (editing prog.c) and switch
+to its window.
+.PP
+If \*Q/etc/utmp\*U is writable by
+.IR screen ,
+an appropriate record will be written to this file for each window, and
+removed when the window is terminated.
+This is useful for working with \*Qtalk\*U, \*Qscript\*U, \*Qshutdown\*U,
+\*Qrsend\*U, \*Qsccs\*U and other similar programs that use the utmp
+file to determine who you are. As long as
+.I screen
+is active on your terminal,
+the terminal's own record is removed from the utmp file. See also \*QC-a L\*U.
+
+
+.SH GETTING STARTED
+Before you begin to use
+.I screen
+you'll need to make sure you have correctly selected your terminal type,
+just as you would for any other termcap/terminfo program.
+(You can do this by using
+.IR tset
+for example.)
+.PP
+If you're impatient and want to get started without doing a lot more reading,
+you should remember this one command: \*QC-a ?\*U.
+Typing these two characters will display a list of the available
+.I screen
+commands and their bindings. Each keystroke is discussed in
+the section \*QDEFAULT KEY BINDINGS\*U. The manual section \*QCUSTOMIZATION\*U
+deals with the contents of your .screenrc.
+.PP
+If your terminal is a \*Qtrue\*U auto-margin terminal (it doesn't allow
+the last position on the screen to be updated without scrolling the
+screen) consider to use a version of your terminal's termcap that has
+automatic margins turned \fIoff\fP. This will ensure an accurate and
+optimal update of the screen in all circumstances. Most terminals
+nowadays have \*Qmagic\*U margins (automatic margins plus usable last
+column). This is the VT100 style type and perfectly suited for
+\fIscreen\fP.
+If all you've got is a \*Qtrue\*U auto-margin terminal \fIscreen\fP
+will be content to use it, but updating a character put into the last
+position on the screen may not be possible until the screen scrolls or
+the character is moved into a safe position in some other way. This
+delay can be shortened by using a terminal with insert-character
+capability.
+
+
+.SH "COMMAND-LINE OPTIONS"
+Screen has the following command-line options:
+.TP 5
+.B \-a
+include \fIall\fP capabilities (with some minor exceptions) in each
+window's termcap, even if
+.I screen
+must redraw parts of the display in order to implement a function.
+.TP 5
+.B \-A
+Adapt the sizes of all windows to the size of the current terminal.
+By default,
+.I screen
+tries to restore its old window sizes when attaching to resizable terminals
+(those with \*QWS\*U in its description, e.g. suncmd or some xterm).
+.TP 5
+.BI "\-c " file
+override the default configuration file from \*Q$HOME/.screenrc\*U
+to \fIfile\fP.
+.TP 5
+.BR \-d | \-D " [" \fIpid.tty.host ]
+does not start
+.IR screen ,
+but detaches the elsewhere running
+.I screen
+session. It has the same effect as typing \*QC-a d\*U from
+.I screen's
+controlling terminal. \fB\-D\fP is the equivalent to the power detach key.
+If no session can be detached, this option is ignored.
+The combination \*Qscreen \-D \-r\*U can be used to `transport' the elsewhere
+running session to this terminal and logout there.
+Note: It is a good idea to have the status of your sessions checked by means of
+\*Qscreen \-list\*U.
+.TP 5
+.BI "\-e " xy
+specifies the command character to be \fIx\fP and the character generating a
+literal command character to \fIy\fP (when typed after the command character).
+The default is \*QC-a\*U and `a', which can be specified as \*Q-e^Aa\*U.
+When creating a
+.I screen
+session, this option sets the default command character. In a multiuser
+session all users added will start off with this command character. But
+when attaching to an already running session, this option changes only
+the command character of the attaching user.
+This option is equivalent to either the commands \*Qdefescape\*U or
+\*Qescape\*U respectively.
+.TP 5
+.BR \-f\fP ", " \-fn ", and " \-fa
+turns flow-control on, off, or \*Qautomatic switching mode\*U.
+This can also be defined through the \*Qdefflow\*U .screenrc command.
+.TP 5
+.BI "\-h " num
+Specifies the history scrollback buffer to be \fInum\fP lines high.
+.TP 5
+.B \-i
+will cause the interrupt key (usually C-c) to interrupt the display
+immediately when flow-control is on.
+See the \*Qdefflow\*U .screenrc command for details.
+The use of this option is discouraged.
+.TP 5
+.BR \-l " and " \-ln
+turns login mode on or off (for /etc/utmp updating).
+This can also be defined through the \*Qdeflogin\*U .screenrc command.
+.TP 5
+.BR \-ls " and " \-list
+does not start
+.IR screen ,
+but prints a list of
+.I pid.tty.host
+strings identifying your
+.I screen
+sessions.
+Sessions marked `detached' can be resumed with \*Qscreen -r\*U. Those marked
+`attached' are running and have a controlling terminal. Sessions marked as
+`dead' should be thoroughly checked and removed. Ask your system administrator
+if you are not sure. Remove sessions with the \fB-wipe\fP option.
+.TP 5
+.B \-L
+tells
+.I screen
+your auto-margin terminal has a writable last-position on
+the screen.
+This can also be set in your .screenrc by specifying `LP' in a \*Qtermcap\*U
+command.
+.TP 5
+.B \-m
+causes
+.I screen
+to ignore the $STY environment variable. With \*Qscreen -m\*U creation of
+a new session is enforced, regardless whether
+.I screen
+is called from within another
+.I screen
+session or not.
+.TP 5
+.B \-O
+selects a more optimal output mode for your terminal rather than true VT100
+emulation (only affects auto-margin terminals without `LP').
+This can also be set in your .screenrc by specifying `OP' in a \*Qtermcap\*U
+command.
+.TP 5
+.BR \-r " [" \fIpid.tty.host ]
+resumes a detached
+.I screen
+session.
+No other options (except \*Q-d -r\*U or \*Q-D -r\*U) may be specified, though
+an optional prefix of [\fIpid.\fP]\fItty.host\fP
+may be needed to distinguish between multiple detached
+.I screen
+sessions.
+.TP 5
+.B \-R
+attempts to resume the first detached
+.I screen
+session it finds.
+If successful, all other command-line options are ignored.
+If no detached session exists, starts a new session using the specified
+options, just as if
+.B \-R
+had not been specified. The option is set by default if
+.I screen
+is run as a login-shell.
+.TP 5
+.B \-s
+sets the default shell to the program specified, instead of the value
+in the environment variable $SHELL (or \*Q/bin/sh\*U if not defined).
+This can also be defined through the \*Qshell\*U .screenrc command.
+.TP 5
+.BI "\-S " sessionname
+When creating a new session, this option can be used to specify a
+meaningful name for the session. This name identifies the session for
+\*Qscreen -list\*U and \*Qscreen -r\*U actions. It substitutes the
+default [\fItty.host\fP] suffix.
+.TP 5
+.BI "\-t " name
+sets the title (a.\|k.\|a.) for the default shell or specified program.
+See also the \*Qshelltitle\*U .screenrc command.
+.TP 5
+.B \-v
+Print version number.
+.TP 5
+.B \-wipe
+does the same as \*Qscreen -ls\*U, but removes destroyed sessions instead of
+marking them as `dead'.
+.TP 5
+.B \-x
+Attach to a not detached
+.I screen
+session. (Multi display mode).
+
+
+.SH "DEFAULT KEY BINDINGS"
+.ta 12n 26n
+As mentioned, each
+.I screen
+command consists of a
+\*QC-a\*U followed by one other character.
+For your convenience, all commands that are bound to lower-case letters are
+also bound to their control character counterparts (with the exception
+of \*QC-a a\*U; see below), thus, \*QC-a c\*U as well as \*QC-a C-c\*U can
+be used to create a window. See section \*QCUSTOMIZATION\*U for a description
+of the command.
+.PP
+.TP 26n
+The following table shows the default key bindings:
+.IP "\fBC-a '\fP"
+.PD 0
+.IP "\fBC-a ""\fP (select)"
+.PD
+Prompt for a window name or number to switch to.
+.IP "\fBC-a 0\fP (select 0)"
+.PD 0
+.IP "\fB ... \fP ..."
+.IP "\fBC-a 9\fP (select 9)"
+.PD
+Switch to window number 0 \- 9.
+.IP "\fBC-a C-a\fP (other)"
+Toggle to the window displayed previously.
+Note that this binding defaults to the command character typed twice,
+unless overridden; for instance, if you use the option \*Q\fB\-e]x\fP\*U,
+this command becomes \*Q]]\*U, not \*Q]C-a\*U.
+.IP "\fBC-a a\fP (meta)"
+Send the command character (C-a) to window. See \fIescape\fP command.
+.IP "\fBC-a A\fP (title)"
+Allow the user to enter a name for the current window.
+.IP "\fBC-a b\fP"
+.PD 0
+.IP "\fBC-a C-b\fP (break)"
+.PD
+Send a break to window.
+.IP "\fBC-a B\fP (pow_break)"
+Reopen the terminal line and send a break.
+.IP "\fBC-a c\fP"
+.PD 0
+.IP "\fBC-a C-c\fP (screen)"
+.PD
+Create a new window with a shell and switch to that window.
+.IP "\fBC-a C\fP (clear)"
+Clear the screen.
+.IP "\fBC-a d\fP"
+.PD 0
+.IP "\fBC-a C-d\fP (detach)"
+.PD
+Detach
+.I screen
+from this terminal.
+.IP "\fBC-a D D\fP (pow_detach)"
+Detach and logout.
+.IP "\fBC-a f\fP"
+.PD 0
+.IP "\fBC-a C-f\fP (flow)"
+.PD
+Toggle flow \fIon\fP, \fIoff\fP or \fIauto\fP.
+.IP "\fBC-a C-g\fP (vbell)"
+Toggles
+.I screen's
+visual bell mode.
+.IP "\fBC-a h\fP (hardcopy)"
+.PD
+Write a hardcopy of the current window to the file \*Qhardcopy.\fIn\fP\*U.
+.IP "\fBC-a H\fP (log)"
+Begins/ends logging of the current window to the file \*Qscreenlog.\fIn\fP\*U.
+.IP "\fBC-a i\fP"
+.PD 0
+.IP "\fBC-a C-i\fP (info)"
+.PD
+Show info about this window.
+.IP "\fBC-a k\fP"
+.PD 0
+.IP "\fBC-a C-k\fP (kill)"
+.PD
+Destroy current window.
+.IP "\fBC-a l\fP"
+.PD 0
+.IP "\fBC-a C-l\fP (redisplay)"
+.PD
+Fully refresh current window.
+.IP "\fBC-a L\fP (login)"
+Toggle this windows login slot. Available only if
+.I screen
+is configured to update the utmp database.
+.IP "\fBC-a m\fP"
+.PD 0
+.IP "\fBC-a C-m\fP (lastmsg)"
+.PD
+Repeat the last message displayed in the message line.
+.IP "\fBC-a M\fP (monitor)"
+Toggles monitoring of the current window.
+.IP "\fBC-a space\fP"
+.PD 0
+.IP "\fBC-a n\fP"
+.IP "\fBC-a C-n\fP (next)"
+.PD
+Switch to the next window.
+.IP "\fBC-a N\fP (number)"
+Show the number (and title) of the current window.
+.IP "\fBC-a backspace\fP"
+.PD 0
+.IP "\fBC-a h\fP"
+.IP "\fBC-a p\fP"
+.IP "\fBC-a C-p\fP (prev)"
+.PD
+Switch to the previous window (opposite of \fBC-a n\fP).
+.IP "\fBC-a q\fP"
+.PD 0
+.IP "\fBC-a C-q\fP (xon)"
+.PD
+Send a control-q to the current window.
+.IP "\fBC-a r\fP"
+.PD 0
+.IP "\fBC-a C-r\fP (wrap)"
+.PD
+Toggle the current window's line-wrap setting (turn the current window's
+automatic margins on and off).
+.IP "\fBC-a s\fP"
+.PD 0
+.IP "\fBC-a C-s\fP (xoff)"
+.PD
+Send a control-s to the current window.
+.IP "\fBC-a t\fP"
+.PD 0
+.IP "\fBC-a C-t\fP (time)"
+.PD
+Show system information.
+.IP "\fBC-a v\fP (version)"
+.PD
+Display the version and compilation date.
+.IP "\fBC-a C-v\fP (digraph)"
+.PD
+Enter digraph.
+.IP "\fBC-a w\fP"
+.PD 0
+.IP "\fBC-a C-w\fP (windows)"
+.PD
+Show a list of window.
+.IP "\fBC-a W\fP (width)"
+Toggle 80/132 columns.
+.IP "\fBC-a x\fP"
+.PD 0
+.IP "\fBC-a C-x\fP (lockscreen)"
+.PD
+Lock this terminal.
+.IP "\fBC-a z\fP"
+.PD 0
+.IP "\fBC-a C-z\fP (suspend)"
+.PD
+Suspend
+.IR screen .
+Your system must support BSD-style job-control.
+.IP "\fBC-a Z\fP (reset)"
+Reset the virtual terminal to its \*Qpower-on\*U values.
+.IP "\fBC-a .\fP (dumptermcap)"
+Write out a \*Q.termcap\*U file.
+.IP "\fBC-a ?\fP (help)"
+Show key bindings.
+.IP "\fBC-a C-\e\fP (quit)"
+Kill all windows and terminate
+.IR screen .
+.IP "\fBC-a :\fP (colon)"
+Enter command line mode.
+.IP "\fBC-a [\fP"
+.PD 0
+.IP "\fBC-a C-[\fP"
+.IP "\fBC-a esc\fP (copy)"
+.PD
+Enter copy/scrollback mode.
+.IP "\fBC-a ]\fP (paste .)"
+.PD
+Write the contents of the paste buffer to the stdin queue of the
+current window.
+.IP "\fBC-a {\fP
+.PD 0
+.IP "\fBC-a }\fP (history)"
+.PD
+Copy and paste a previous (command) line.
+.IP "\fBC-a >\fP (writebuf)"
+Write paste buffer to a file.
+.IP "\fBC-a <\fP (readbuf)"
+Reads the screen-exchange file into the paste buffer.
+.IP "\fBC-a =\fP (removebuf)"
+Removes the file used by \fBC-a <\fP and \fPC-a >\fP.
+.IP "\fBC-a ,\fP (license)"
+Shows where
+.I screen
+comes from, where it went to and why you can use it.
+.IP "\fBC-a _\fP (silence)"
+Start/stop monitoring the current window for inactivity.
+
+
+.SH CUSTOMIZATION
+The \*Qsocket directory\*U defaults either to $HOME/.screen or simply to
+/tmp/screens or preferably to /usr/local/screens chosen at compile-time. If
+.I screen
+is installed setuid-root, then the administrator
+should compile
+.I screen
+with an adequate (not NFS mounted) socket directory. If
+.I screen
+is not running setuid-root, the user can specify any mode 777 directory
+in the environment variable $SCREENDIR.
+.PP
+When
+.I screen
+is invoked, it executes initialization commands from the files
+\*Q/usr/local/etc/screenrc\*U and
+\*Q.screenrc\*U in the user's home directory. These are the \*Qprogrammer's
+defaults\*U that can be overridden in the following ways: for the
+global screenrc file
+.I screen
+searches for the environment variable $SYSSCREENRC (this override feature
+may be disabled at compile-time). The user specific
+screenrc file is searched in $ISCREENRC, then $SCREENRC, then $HOME/.iscreenrc
+and finally defaults to $HOME/.screenrc. The command line option \fB-c\fP takes
+precedence over the above user screenrc files.
+.PP
+Commands in these files are used to set options, bind functions to
+keys, and to automatically establish one or more windows at the
+beginning of your
+.I screen
+session.
+Commands are listed one per line, with empty lines being ignored.
+A command's arguments are separated by tabs or spaces, and may be
+surrounded by single or double quotes.
+A `#' turns the rest of the line into a comment, except in quotes.
+Unintelligible lines are warned about and ignored.
+Commands may contain references to environment variables. The
+syntax is the shell-like "$VAR " or "${VAR}". Note that this causes
+incompatibility with previous
+.I screen
+versions, as now the '$'-character has to be protected with '\e' if no
+variable substitution shall be performed. A string in single-quotes is also
+protected from variable substitution.
+.PP
+Customization can also be done 'on-line'. To enter the command mode type
+`C-a :'. Note that commands starting with \*Qdef\*U change default values,
+while others change current settings.
+.PP
+The following commands are available:
+.sp
+.ne 3
+.BI acladd " usernames"
+.PP
+Enable users to fully access this screen session. \fIUsernames\fP can be one
+user or a comma seperated list of users. This command enables to attach to the
+.I screen
+session and performs the equivalent of `aclchg \fIusernames\fP +rwx \&"#?\&"'.
+executed. To add a user with restricted access, use the `aclchg' command below.
+Multi user mode only.
+.sp
+.ne 3
+.BI aclchg " usernames permbits list"
+.PP
+Change permissions for a comma seperated list of users. Permission bits are
+represented as `r', `w' and `x'. Prefixing `+' grants the permission, `-'
+removes it. The third parameter is a comma seperated list of commands and/or
+windows (specified either by number or title). The special list `#' refers to
+all windows, `?' to all commands. if \fIusernames\fP consists of a single `*',
+all known users are affected.
+A command can be executed when the user has the `x' bit for it.
+The user can type input to a window when he has its `w' bit set and no other
+user obtains a writelock for this window.
+Other bits are currently ignored.
+To withdraw the writelock from another user in window 2:
+`aclchg \fIusername\fP -w+w 2'.
+To allow readonly access to the session: `aclchg \fIusername\fP
+-w \&"#\&"'. As soon as a user's name is known to
+.I screen
+he can attach to the session and (per default) has full permissions for all
+command and windows. Execution permission for the acl commands, `at' and others
+should also be removed or the user may be able to regain write permission.
+Multi user mode only.
+.sp
+.ne 3
+.BI acldel " username"
+.PP
+Remove a user from
+.IR screen 's
+access control list. If currently attached, all the
+user's displays are detached from the session. He cannot attach again.
+Multi user mode only.
+.sp
+.ne 3
+.BI activity " message"
+.PP
+When any activity occurs in a background window that is being monitored,
+.I screen
+displays a notification in the message line.
+The notification message can be re-defined by means of the \*Qactivity\*U
+command.
+Each occurrence of `%' in \fImessage\fP is replaced by
+the number of the window in which activity has occurred,
+and each occurrence of `~' is replaced by the definition for bell
+in your termcap (usually an audible bell).
+The default message is
+.sp
+ 'Activity in window %'
+.sp
+Note that monitoring is off for all windows by default, but can be altered
+by use of the \*Qmonitor\*U command (C-a M).
+.sp
+.ne 3
+.BR "allpartial on" | off
+.PP
+If set to on, only the current cursor line is refreshed on window change.
+This affects all windows and is useful for slow terminal lines. The
+previous setting of full/partial refresh for each window is restored
+with \*Qallpartial off\*U. This is a global flag that immediately takes effect
+on all windows overriding the \*Qpartial\*U settings. It does not change the
+default redraw behaviour of newly created windows.
+.sp
+.ne 3
+.BR "at " "[\fIidentifier\fP][" "#\fP|\fP*\fP|\fP%\fP] "
+.IR "command " [ args " ... ]"
+.PP
+Execute a command at other displays or windows as if it had been entered there.
+\*QAt\*U changes the context (the `current window' or `current display'
+setting) of the command. If the first parameter describes a
+non-unique context, the command will be executed multiple times. If the first
+parameter is of the form `\fIidentifier\fP*' then identifier is matched against
+user names. The command is executed once for each display of the selected
+user(s). If the first parameter is of the form `\fIidentifier\fP%' identifier
+is matched against displays. Displays are named after the ttys they
+attach. The prefix `/dev/' or `/dev/tty' may be omitted from the identifier.
+If \fIidentifier\fP has a `#' or nothing appended it is matched against
+window numbers and titles. Omitting an identifier in front of the `#', `*' or
+`%'-character selects all users, displays or windows because a prefix-match is
+performed. Note that on the affected display(s) a short message will describe
+what happened. Caution: Permission is checked for the owners or the
+affected display(s), not for the initiator of the `at' command.
+.sp
+.ne 3
+.BR "autodetach on" | off
+.PP
+Sets whether
+.I screen
+will automatically detach upon hangup, which
+saves all your running programs until they are resumed with a
+.B "screen -r"
+command.
+When turned off, a hangup signal will terminate
+.I screen
+and all the processes it contains. Autodetach is on by default.
+.sp
+.ne 3
+.BR "autonuke on" | off
+.PP
+Sets whether a clear screen sequence should nuke all the output
+that has not been written to the terminal. See also
+\*Qobuflimit\*U.
+.sp
+.ne 3
+.BI "bell " message
+.PP
+When a bell character is sent to a background window,
+.I screen
+displays a notification in the message line.
+The notification message can be re-defined by means of the \*Qbell\*U
+command.
+Each occurrence of `%' in \fImessage\fP is replaced by
+the number of the window to which a bell has been sent,
+and each occurrence of `~' is replaced by the definition for bell
+in your termcap (usually an audible bell).
+The default message is
+.sp
+ 'Bell in window %'
+.sp
+An empty message can be supplied to the \*Qbell\*U command to suppress
+output of a message line (bell "").
+.sp
+.ne 3
+.BI "bind " key
+.RI [ command " [" args ]]
+.PP
+Bind a command to a key.
+By default, most of the commands provided by
+.I screen
+are bound to one or more keys as indicated in the \*QDEFAULT KEY BINDINGS\*U
+section, e.\|g. the
+command to create a new window is bound to \*QC-c\*U and \*Qc\*U.
+The \*Qbind\*U command can be used to redefine the key bindings and to
+define new bindings.
+The \fIkey\fP argument is either a single character, a two-character sequence
+of the form \*Q^x\*U (meaning \*QC-x\*U), a backslash followed by an octal
+number (specifying the ASCII code of the character), or a backslash followed
+by a second character, such as \*Q\e^\*U or \*Q\e\e\*U.
+The argument can also be quoted, if you like.
+If no further argument is given, any previously established binding
+for this key is removed.
+The \fIcommand\fP argument can be any command listed in this section.
+.PP
+Some examples:
+.PP
+.nf
+ bind ' ' windows
+ bind ^f screen telnet foobar
+ bind \e033 screen -ln -t root -h 1000 9 su
+.fi
+.PP
+would bind the space key to the command that displays a list
+of windows (so that the command usually invoked by \*QC-a C-w\*U
+would also be available as \*QC-a space\*U),
+bind \*QC-f\*U to the command \*Qcreate a window with a TELNET
+connection to foobar\*U, and bind \*Qescape\*U to the command
+that creates an non-login window with a.\|k.\|a. \*Qroot\*U in slot #9, with
+a super-user shell and a scrollback buffer of 1000 lines.
+.sp
+.ne 3
+.B bindkey
+.RB [ -d ]
+.RB [ -m ]
+.RB [ -a ]
+.RB [[ -k | -t ]
+.I string
+.RI [ "cmd args" ]]
+.PP
+This command manages screen's input translation tables. Every
+entry in one of the tables tells screen how to react if a certain
+sequence of characters is encountered. There are three tables:
+one that should contain actions programmed by the user, one for
+the default actions used for terminal emulation and one for
+screen's copy mode to do cursor movement. See section
+\*QINPUT TRANSLATION\*U for a list of default key bindings.
+.br
+If the
+.B -d
+option is given, bindkey modifies the default table,
+.B -m
+changes the copy mode table
+and with neither option the user table is selected.
+The argument
+.I string
+is the sequence of characters to which an action is bound. This
+can either be a fixed string or a termcap keyboard capability
+name (selectable with the
+.B -k
+option).
+.br
+Some keys on a VT100 terminal can send a different
+string if application mode is turned on (e.g the cursor keys).
+Such keys have two entries in the translation table. You can
+select the application mode entry by specifying the
+.B -a
+option.
+.br
+The
+.B -t
+option tells screen not to do intercharacter timing. One cannot
+turn off the timing if a termcap capabilty is used.
+.br
+.I Cmd
+can be any of screen's commands with an arbitrary number of
+.IR args .
+If
+.I cmd
+is omitted the keybinding is removed from the table.
+.br
+Here are some examples of keyboard bindings:
+.sp
+.nf
+ bindkey -d
+.fi
+Show all of the default key bindings. The application mode entries
+are marked with [A].
+.sp
+.nf
+ bindkey -k k1 select 1
+.fi
+Make the "F1" key switch to window one.
+.sp
+.nf
+ bindkey -t foo stuff barfoo
+.fi
+Make "foo" an abrevation of the word "barfoo". Timeout is disabled
+so that users can type slowly.
+.sp
+.nf
+ bindkey "\e024" mapdefault
+.fi
+This keybinding makes \*Q^T\*U an escape character for keybindings. If
+you did the above \*Qstuff barfoo\*U binding, you can enter the word
+\*Qfoo\*U by typing \*Q^Tfoo\*U. If you want to insert a \*Q^T\*U
+you have to press the key twice (i.e. escape the escape binding).
+.sp
+.nf
+ bindkey -k F1 command
+.fi
+Make the F11 (not F1!) key an alternative screen
+escape (besides ^A).
+.sp
+.ne 3
+.B break
+.RI [ duration ]
+.PP
+Send a break signal for \fIduration\fP*0.25 seconds to this window.
+Most useful if a character device is
+attached to the window rather than a shell process.
+.sp
+.ne 3
+.B bufferfile
+.RI [ exchange-file ]
+.PP
+Change the filename used for reading and writing with the paste buffer.
+If the optional argument to the \*Qbufferfile\*U command is omitted,
+the default setting (\*Q/tmp/screen-exchange\*U) is reactivated.
+The following example will paste the system's password file into
+the
+.I screen
+window (using the paste buffer, where a copy remains):
+.PP
+.nf
+ C-a : bufferfile /etc/passwd
+ C-a < C-a ]
+ C-a : bufferfile
+.fi
+.sp
+.ne 3
+.BR "c1 " [ on | off ]
+.PP
+Change c1 code processing. \*QC1 on\*U tells screen to treat
+the input characters between 128 and 159 as control functions.
+Such an 8-bit code is normally the same as ESC followed by the
+corresponding 7-bit code. The default setting is to process c1
+codes and can be changed with the \*Qdefc1\*U command.
+Users with fonts that have usable characters in the
+c1 positions may want to turn this off.
+.sp
+.ne 3
+.BI "charset " set
+.PP
+Change the current character set slot designation and charset
+mapping. The first four character of
+.I set
+are treated as charset designators while the fifth and sixth
+character must be in range '0' to '3' and set the GL/GR charset
+mapping. On every position a '.' may be used to indicate that
+the corresponding charset/mapping should not be changed
+(\fIset\fP is padded to six characters internally by appending '.'
+chars). New windows have "BBBB02" as default charset, unless a
+\*Qkanji\*U command is active.
+.br
+The current setting can be viewed with the \*Qinfo\*U command.
+.sp
+.ne 3
+.B chdir
+.RI [ directory ]
+.PP
+Change the \fIcurrent directory\fP of
+.I screen
+to the specified directory or, if called without an argument,
+to your home directory (the value of the environment variable $HOME).
+All windows that are created by means of the \*Qscreen\*U command
+from within \*Q.screenrc\*U or by means of \*QC-a : screen ...\*U
+or \*QC-a c\*U use this as their default directory.
+Without a chdir command, this would be the directory from which
+.I screen
+was invoked.
+Hardcopy and log files are always written to the \fIwindow's\fP default
+directory, \fInot\fP the current directory of the process running in the
+window.
+You can use this command multiple times in your .screenrc to start various
+windows in different default directories, but the last chdir value will
+affect all the windows you create interactively.
+.sp
+.ne 3
+.B clear
+.PP
+Clears the current window and saves its image to the scrollback buffer.
+.sp
+.ne 3
+.B colon
+.PP
+Allows you to enter \*Q.screenrc\*U command lines. Useful
+for on-the-fly modification of key bindings,
+specific window creation and changing settings. Note that the \*Qset\*U
+keyword no longer exists! Usually commands affect the current window rather
+than default settings for future windows. Change defaults with commands
+starting with 'def...'.
+
+If you consider this as the `Ex command mode' of
+.IR screen ,
+you may regard \*QC-a esc\*U (copy mode) as its `Vi command mode'.
+.sp
+.ne 3
+.B command
+.PP
+This command has the same effect as typing the screen escape
+character (^A). It is probably only useful for key bindings.
+See also \*Qbindkey\*U.
+.sp
+.ne 3
+.BR "console " [ on | off ]
+.PP
+Grabs or ungrabs the machines console output to a window.
+.sp
+.ne 3
+.B copy
+.PP
+Enter copy/scrollback mode. This allows you to copy text from the current
+window and its history into the paste buffer. In this mode a vi-like
+`full screen editor' is active:
+.br
+.IR "Movement keys" :
+.br
+.in +4n
+.ti -2n
+\fBh\fP, \fBj\fP, \fBk\fP, \fBl\fP move the cursor line by line or
+column by column.
+.br
+.ti -2n
+\fB0\fP, \fB^\fP and \fB$\fP move to the leftmost column, to the first or last
+non-whitespace character on the line.
+.br
+.ti -2n
+\fBH\fP, \fBM\fP and \fBL\fP move the cursor to the leftmost column
+of the top, center or bottom line of the window.
+.br
+.ti -2n
+\fB+\fP and \fB\-\fP positions one line up and down.
+.br
+.ti -2n
+\fBG\fP moves to the specified absolute line (default: end of buffer).
+.br
+.ti -2n
+\fB|\fP moves to the specified absolute column.
+.br
+.ti -2n
+\fBw\fP, \fBb\fP, \fBe\fP move the cursor word by word.
+.br
+.ti -2n
+\fBC-u\fP and \fBC-d\fP scroll the display up/down by the specified amount of
+lines while preserving the cursor position. (Default: half screen-full).
+.br
+.ti -2n
+\fBC-b\fP and \fBC-f\fP scroll the display up/down a full screen.
+.br
+.ti -2n
+\fBg\fP moves to the beginning of the buffer.
+.br
+.ti -2n
+\fB%\fP jumps to the specified percentage of the buffer.
+.br
+.ti -4n
+
+.IR Note :
+.br
+Emacs style movement keys can be customized by a .screenrc command.
+(E.\|g. markkeys "h=^B:l=^F:$=^E") There is no simple method for a full
+emacs-style keymap, as this involves multi-character codes.
+
+.br
+.ti -4n
+.IR Marking :
+.br
+The copy range is specified by setting two marks. The text between these marks
+will be highlighted. Press
+.br
+.ti -2n
+\fBspace\fP to set the first or second mark
+respectively.
+.br
+.ti -2n
+\fBY\fP and \fBy\fP used to mark one whole line or to mark from
+start of line.
+.br
+.ti -2n
+\fBW\fP marks exactly one word.
+.br
+.ti -4n
+.IR "Repeat count" :
+.br
+Any of these commands can be prefixed with a repeat count number by pressing
+digits
+.br
+.ti -2n
+\fB0\fP..\fB9\fP which
+is taken as a repeat count.
+.br
+Example: \*QC-a C-[ H 10 j 5 Y\*U will copy lines
+11 to 15 into the paste buffer.
+.br
+.ti -4n
+.IR Searching :
+.ti -2n
+\fB/\fP \fIVi\fP-like search forward.
+.ti -2n
+\fB?\fP \fIVi\fP-like search backward.
+.ti -2n
+\fBC-a s\fP \fIEmacs\fP style incremental search forward.
+.ti -2n
+\fBC-r\fP \fIEmacs\fP style reverse i-search.
+.ti -4n
+.IR Specials :
+.br
+There are however some keys that act differently than in
+.IR vi .
+.I Vi
+does not allow one to yank rectangular blocks of text, but
+.I screen
+does. Press
+.br
+.ti -2n
+\fBc\fP or \fBC\fP to set the left or right margin respectively. If no repeat count is
+given, both default to the current cursor position.
+.br
+Example: Try this on a rather full text screen:
+\*QC-a [ M 20 l SPACE c 10 l 5 j C SPACE\*U.
+
+This moves one to the middle line of the screen, moves in 20 columns left,
+marks the beginning of the paste buffer, sets the left column, moves 5 columns
+down, sets the right column, and then marks the end of
+the paste buffer. Now try:
+.br
+\*QC-a [ M 20 l SPACE 10 l 5 j SPACE\*U
+
+and notice the difference in the amount of text copied.
+.br
+.ti -2n
+\fBJ\fP joins lines. It toggles between
+3 modes: lines separated by a newline character (012), lines glued seamless,
+lines separated by a single whitespace. Note that you can prepend the newline
+character with a carriage return character, by issuing a \*Qcrlf on\*U.
+.br
+.ti -2n
+\fBv\fP is for all the
+.I vi
+users with \*Q:set numbers\*U \- it toggles the left margin between column 9
+and 1. Press
+.br
+.ti -2n
+\fBa\fP before the final space key to toggle in append mode. Thus
+the contents of the paste buffer will not be overwritten, but is appended to.
+.br
+.ti -2n
+\fBA\fP toggles in append mode and sets a (second) mark.
+.br
+.ti -2n
+\fB>\fP sets the (second) mark and writes the contents of the paste buffer to
+the screen-exchange file (/tmp/screen-exchange per default) once copy-mode is
+finished.
+.br
+This example demonstrates how to dump the whole scrollback buffer
+to that file: \*QC-A [ g SPACE G $ >\*U.
+.br
+.ti -2n
+\fBC-g\fP gives information about the current line and column.
+.br
+.ti -2n
+\fBx\fP exchanges the first mark and the current cursor position. You
+can use this to adjust an already placed mark.
+.br
+.ti -2n
+\fB@\fP does nothing. Does not even exit copy mode.
+.br
+.ti -2n
+All keys not described here exit copy mode.
+.in -4n
+.sp
+.ne 3
+.B copy_reg
+.RI [ key ]
+.PP
+No longer exists, use \*Qreadreg\*U instead.
+.sp
+.ne 3
+.BR "crlf on" | off
+.PP
+This affects the copying of text regions with the `C-a [' command. If it is set
+to `on', lines will be separated by the two character sequence `CR' - `LF'.
+Otherwise (default) only `LF' is used.
+.sp
+.ne 3
+.BR "debug on" | off
+.PP
+Turns runtime debugging on or off. If
+.I screen
+has been compiled with option -DDEBUG debugging available and is turned on per
+default. Note that this command only affects debugging output from the main
+\*QSCREEN\*U process.
+.sp
+.ne 3
+.BR "defc1 on" | off
+.PP
+Same as the \fBc1\fP command except that the default setting for new
+windows is changed. Initial setting is `on'.
+.sp
+.ne 3
+.BR "defautonuke on" | off
+.PP
+Same as the \fBautonuke\fP command except that the default setting for new displays is changed. Initial setting is `off'.
+Note that you can use the special `AN' terminal capability if you
+want to have a dependency on the terminal type.
+.sp
+.ne 3
+.BR "defcharset " [ \fIset ]
+.PP
+Like the \fBcharset\fP command except that the default setting for
+new windows is changed. Shows current default if called without
+argument.
+.sp
+.ne 3
+.BI "defescape " xy
+.PP
+Set the default command characters. This is equivalent to the
+\*Qescape\*U except that it is useful multiuser sessions only. In a
+multiuser session \*Qescape\*U changes the command character of the
+calling user, where \*Qdefescape\*U changes the default command
+characters for users that will be added later.
+.sp
+.ne 3
+.BR "defflow on" | off | auto
+.RB [ interrupt ]
+.PP
+Same as the \fBflow\fP command except that the default setting for new windows
+is changed. Initial setting is `auto'.
+Specifying \*Qdefflow auto interrupt\*U is the same as the command-line options
+.B \-fa
+and
+.BR \-i .
+.sp
+.ne 3
+.BR "defgr on" | off
+.PP
+Same as the \fBgr\fP command except that the default setting for new
+windows is changed. Initial setting is `off'.
+.sp
+.ne 3
+.BR "defhstatus " [ \fIstatus ]
+.PP
+The hardstatus line that all new windows will get is set to
+.I status\fR.
+This command is useful to make the hardstatus of every window
+display the window number or title or the like.
+.I Status
+may contain the same directives as in the window messages, but
+the directive escape character is '^E' (octal 005) instead of '%'.
+This was done to make a misinterpretion of program generated
+hardstatus lines impossible.
+If the parameter
+.I status
+is omitted, the current default string is displayed.
+Per default the hardstatus line of new windows is empty.
+.sp
+.ne 3
+.BR "defkanji jis" | sjis | euc
+.PP
+Same as the \fBkanji\fP command except that the default setting for new
+windows is changed. Initial setting is `off', i.e. `jis'.
+.sp
+.ne 3
+.BR "deflogin on" | off
+.PP
+Same as the \fBlogin\fP command except that the default setting for new windows
+is changed. This is initialized with `on' as distributed (see config.h.in).
+.sp
+.ne 3
+.BI "defmode " mode
+.PP
+The mode of each newly allocated pseudo-tty is set to \fImode\fP.
+\fIMode\fP is an octal number.
+When no \*Qdefmode\*U command is given, mode 0622 is used.
+.sp
+.ne 3
+.BR "defmonitor on" | off
+.PP
+Same as the \fBmonitor\fP command except that the default setting for new
+windows is changed. Initial setting is `off'.
+.sp
+.ne 3
+.BI "defobuflimit " limit
+.PP
+Same as the \fBobuflimit\fP command except that the default setting for new displays is changed. Initial setting is 256 bytes.
+Note that you can use the special 'OL' terminal capability if you
+want to have a dependency on the terminal type.
+.sp
+.ne 3
+.BI "defscrollback " num
+.PP
+Same as the \fBscrollback\fP command except that the default setting for new
+windows is changed. Initial setting is 100.
+.sp
+.ne 3
+.BR "defwrap on" | off
+.PP
+Same as the \fBwrap\fP command except that the default setting for new
+windows is changed. Initially line-wrap is on and can be toggled with the
+\*Qwrap\*U command (\*QC-a r\*U) or by means of "C-a : wrap on|off".
+.sp
+.ne 3
+.BR "defwritelock on" | off | auto
+.PP
+Same as the \fBwritelock\fP command except that the default setting for new
+windows is changed. Initially writelocks will operate in automatic mode.
+.sp
+.ne 3
+.BR "defzombie " [\fIkeys\fP]
+.PP
+Synonym to the \fBzombie\fP command. Both currently change the default.
+See there.
+.sp
+.ne 3
+.B detach
+.PP
+Detach the
+.I screen
+session (disconnect it from the terminal and put it into the background).
+This returns you to the shell where you invoked
+.IR screen .
+A detached
+.I screen
+can be resumed by invoking
+.I screen
+with the
+.B \-r
+option. (See also section \*QCOMMAND-LINE OPTIONS\*U.)
+.sp
+.ne 3
+.BR "digraph " [ \fIpreset ]
+.PP
+This command prompts the user for a digraph sequence. The next
+two characters typed are looked up in a builtin table and the
+resulting character is inserted in the input stream. For example,
+if the user enters 'a"', an a-umlaut will be inserted. If the
+first character entered is a 0 (zero),
+.I screen
+will treat the following charcters (up to three) as an octal
+number instead. The optional argument
+.I preset
+is treated as user input, thus one can create an \*Qumlaut\*U key.
+For example the command "bindkey ^K digraph '"'" enables the user
+to generate an a-umlaut by typing CTRL-K a.
+.sp
+.ne 3
+.B dumptermcap
+.PP
+Write the termcap entry for the virtual terminal optimized for the currently
+active window to the file \*Q.termcap\*U in the user's
+\*Q$HOME/.screen\*U directory (or wherever
+.I screen
+stores its sockets. See the \*QFILES\*U section below).
+This termcap entry is identical to the value of the environment variable
+$TERMCAP that is set up by
+.I screen
+for each window. For terminfo based systems you will need to run a converter
+like
+.IR captoinfo
+and then compile the entry with
+.IR tic .
+.sp
+.ne 3
+.BR "echo " [ -n ]
+.I message
+.PP
+The echo command may be used to annoy
+.I screen
+users with a 'message of the
+day'. Typically installed in a global /local/etc/screenrc. See also
+\*Qsleep\*U.
+Echo is also useful for online checking of environment variables.
+.sp
+.ne 3
+.BI "escape " xy
+.PP
+Set the command character to \fIx\fP and the character generating a literal
+command character to \fIy\fP (just like in the \-e option).
+Each argument is either a single character, a two-character sequence
+of the form \*Q^x\*U (meaning \*QC-x\*U), a backslash followed by an octal
+number (specifying the ASCII code of the character), or a backslash followed
+by a second character, such as \*Q\e^\*U or \*Q\e\e\*U.
+The default is \*Q^Aa\*U.
+.sp
+.ne 3
+.B exec
+.RI [[ fdpat ]
+.IR "newcommand " [ "args ..." ]]
+.PP
+Run a subprocess (newcommand) in the current window. The flow of data between
+newcommand's stdin/stdout/stderr, the process already running (shell) and
+screen itself (window) is controlled by the filedescriptor pattern fdpat.
+This pattern is basically a three character sequence representing stdin, stdout
+and stderr of newcommand. A dot (.) connects the file descriptor
+to
+.IR screen .
+An exclamation mark (!) causes the file
+descriptor to be connected to the already running process. A colon (:) combines
+both.
+User input will go to newcommand unless newcommand requests the old process'
+output (fdpats first character is `!' or `:') or a pipe (|) is added to
+the end of fdpat.
+.br
+Invoking `exec' without arguments shows name and arguments of the currently
+running subprocess in this window.
+.br
+When a subprocess is running the `kill' command will affect it instead of the
+windows process.
+.br
+Refer to the postscript file `fdpat.ips' for a confusing illustration
+of all 21 possible combinations. Each drawing shows the digits 2,1,0
+representing the three file descriptors of newcommand. The box marked
+`W' is usual pty that has the application-process on its slave side.
+The box marked `P' is the secondary pty that now has
+.I screen
+at its master side.
+.sp
+Abbreviations:
+.br
+Whitespace between the word `exec' and fdpat and the command
+can be omitted. Trailing dots and a fdpat consisting only of dots can be
+omitted. A simple `|' is synonymous for the pattern `!..|'; the word exec can
+be omitted here and can always be replaced by `!'.
+.sp
+Examples:
+.IP
+exec ... /bin/sh
+.br
+exec /bin/sh
+.br
+!/bin/sh
+.PP
+Creates another shell in the same window, while the original shell is still
+running. Output of both shells is displayed and user input is sent to the new
+/bin/sh.
+.IP
+exec !.. stty 19200
+.br
+exec ! stty 19200
+.br
+!!stty 19200
+.PP
+Set the speed of the window's tty. If your stty command operates on stdout, then
+add another `!'.
+.IP
+exec !..| less
+.br
+|less
+.PP
+This adds a pager to the window output. The special character `|' is needed to
+give the user control over the pager although it gets its input from the
+window's process. This works, because
+.I less
+listens on stderr (a behavior that
+.I screen
+would not expect without the `|')
+when its stdin is not a tty.
+.I Less
+versions newer than 177 fail miserably here; good old
+.I pg
+still works.
+.IP
+!:sed -n s/.*Error.*/\e007/p
+.PP
+Sends window output to both, the user and the sed command. The sed inserts an
+additional bell character (oct. 007) to the window output seen by
+.IR screen .
+This will cause "Bell in window x" messages, whenever the string "Error"
+appears in the window.
+.sp
+.ne 3
+.B flow
+.RB [ on | off | "auto\fR]\fP"
+.PP
+Sets the flow-control mode for this window.
+Without parameters it cycles the current window's flow-control setting from
+"automatic" to "on" to "off".
+See the discussion on \*QFLOW-CONTROL\*U later on in this document for full
+details and note, that this is subject to change in future releases.
+Default is set by `defflow'.
+.sp
+.ne 3
+.BR "gr " [ on | off ]
+.PP
+Turn GR charset switching on/off. Whenever screens sees an input
+char with an 8th bit set, it will use the charset stored in the
+GR slot and print the character with the 8th bit stripped. The
+default (see also \*Qdefgr\*U) is not to process GR switching because
+otherwise the ISO88591 charset would not work.
+.sp
+.ne 3
+.B hardcopy
+.PP
+Writes out the currently displayed image to a file \fIhardcopy.n\fP
+in the window's default directory, where \fIn\fP is the number
+of the current window.
+This either appends or overwrites the file if it exists. See below.
+.sp
+.ne 3
+.BR "hardcopy_append on" | off
+.PP
+If set to "on",
+.I screen
+will append to the "hardcopy.n" files created by the command \*QC-a h\*U,
+otherwise these files are overwritten each time.
+Default is `off'.
+.sp
+.ne 3
+.BI "hardcopydir "directory
+.PP
+Defines a directory where hardcopy files will be placed. If unset, hardcopys
+are dumped in
+.IR screen 's
+current working directory.
+.sp
+.ne 3
+.BR "hardstatus " [ on | off ]
+.PP
+Toggles the use of the terminal's hardware status line. If "on",
+.I screen
+will use this facility to display one line messages. Otherwise these messages
+are overlayed in reverse video mode at the display line. Note that the
+hardstatus feature can only be used if the termcap/terminfo capabilities
+"hs", "ts", "fs" and "ds" are set properly. Default is `on' whenever the "hs"
+capability is present.
+.sp
+.ne 3
+.BR "height " [ \fIlines\fP ]
+.PP
+Set the display height to a specified number of lines. When no argument
+is given it toggles between 24 and 42 lines display.
+.sp
+.ne 3
+.B help
+.PP
+Not really a online help, but
+displays a help screen showing you all the key bindings.
+The first pages list all the internal commands followed by their current
+bindings.
+Subsequent pages will display the custom commands, one command per key.
+Press space when you're done reading each page, or return to exit early.
+All other characters are ignored.
+See also \*QDEFAULT KEY BINDINGS\*U section.
+.sp
+.ne 3
+.B history
+.PP
+Usually users work with a shell that allows easy access to previous commands.
+For example csh has the command \*Q!!\*U to repeat the last command executed.
+.I Screen
+allows you to have a primitive way of re-calling \*Qthe command that
+started ...\*U: You just type the first letter of that command, then hit
+`C-a {' and
+.I screen
+tries to find a previous line that matches with the `prompt character'
+to the left of the cursor. This line is pasted into this window's input queue.
+Thus you have a crude command history (made up by the visible window and its
+scrollback buffer).
+.sp
+.ne 3
+.B info
+.PP
+Uses the message line to display some information about the current window:
+the cursor position in the form \*Q(column,row)\*U starting with \*Q(1,1)\*U,
+the terminal width and height plus the size of the scrollback buffer in lines,
+like in \*U(80,24)+50\*U, various flag settings (flow-control, insert mode,
+origin mode, wrap mode, application-keypad mode, output logging, activity
+monitoring and redraw (`+' indicates enabled, `\-' not)),
+the currently active character set (\fIG0\fP, \fIG1\fP, \fIG2\fP,
+or \fIG3\fP), and in square brackets the terminal character sets that are
+currently designated as \fIG0\fP through \fIG3\fP.
+For system information use the \*Qtime\*U command.
+.sp
+.ne 3
+.BR ins_reg " [" \fIkey ]
+.PP
+No longer exists, use \*Qpaste\*U instead.
+.sp
+.ne 3
+.B kanji
+.BR jis | euc | sjis
+.RB [ jis | euc | sjis\fR]
+.PP
+Tell screen how to process kanji input/output. The first argument
+sets the kanji type of the current window. Each window can emulate
+a different type. The optional second parameter tells screen
+how to write the kanji codes to the connected terminal. The preferred
+method of setting the display type is to use the \*QKJ\*U termcap
+entry.
+See also \*Qdefkanji\*U, which changes the default setting of a new
+window.
+.sp
+.ne 3
+.B kill
+.PP
+Kill current window.
+.br
+If there is an `exec' command running then it is killed. Otherwise the process
+(shell) running in the window receives a HANGUP condition, the window structure
+is removed and
+.I screen
+switches to the previously displayed window.
+When the last window is destroyed,
+.I screen
+exits.
+Note:
+.I Emacs
+users should keep this command in mind, when killing a line.
+It is recommended not to use \*QC-a\*U as the
+.I screen
+escape key or to rebind kill to \*QC-a K\*U.
+.sp
+.ne 3
+.B lastmsg
+.PP
+Redisplay the last contents of the message/status line.
+Useful if you're typing when a message appears, because the message goes
+away when you press a key (unless your terminal has a hardware status line).
+Refer to the commands \*Qmsgwait\*U and \*Qmsgminwait\*U for fine tuning.
+.sp
+.ne 3
+.B license
+.PP
+Display the disclaimer page. This is done whenever
+.I screen
+is started without options, which should be often enough. See also
+the \*Qstartup_message\*U command.
+.sp
+.ne 3
+.B lockscreen
+.PP
+Lock this display.
+Call a screenlock program (/local/bin/lck or /usr/bin/lock or a builtin if no
+other is available). Screen does not accept any command keys until this program
+terminates. Meanwhile processes in the windows may continue, as the windows
+are in the `detached' state. The screenlock program may be changed through the
+environment variable $LOCKPRG (which must be set in the shell from which
+.I screen
+is started) and is executed with the user's uid and gid.
+.sp
+.ne 3
+.BR "log " [ on | off ]
+.PP
+Start/stop writing output of the current window to a file
+\*Qscreenlog.\fIn\fP\*U in the window's default directory, where \fIn\fP
+is the number of the current window. This filename can be changed with
+the `logfile' command. If no parameter is given, the state
+of logging is toggled. The session log is appended to the previous contents
+of the file if it already exists. The current contents and the contents
+of the scrollback history are not included in the session log.
+Default is `off'.
+.sp
+.ne 3
+.BI "logfile " filename
+.PP
+Defines the name the logfiles will get. The default is
+\*Qscreenlog.%n\*U.
+.sp
+.ne 3
+.BR "login " [ on | off ]
+.PP
+Adds or removes the entry in the utmp database file for the current window.
+This controls if the window is `logged in'.
+When no parameter is given, the login state of the window is toggled.
+Additionally to that toggle, it is convenient having a `log in' and a `log out'
+key. E.\|g. `bind I login on' and `bind O login off' will map these
+keys to be C-a I and C-a O.
+The default setting (in config.h.in) should be \*Qon\*U for a
+.I screen
+that runs under suid-root.
+Use the \*Qdeflogin\*U command to change the default login state for new
+windows. Both commands are only present when
+.I screen
+has been compiled with utmp support.
+.sp
+.ne 3
+.B mapdefault
+.PP
+Tell screen that the next input character should only be looked up
+in the default bindkey table. See also \*Qbindkey\*U.
+.sp
+.ne 3
+.B mapnotnext
+.PP
+Like mapdefault, but don't even look in the default bindkey table.
+.sp
+.ne 3
+.B maptimeout
+.RI [ timo ]
+.PP
+Set the intercharacter timer for input sequence detection to a timeout
+of
+.I timo
+ms. The default timeout is 300ms. Maptimeout with no arguments shows
+the current setting.
+See also \*Qbindkey\*U.
+.sp
+.ne 3
+.BI "markkeys " string
+.PP
+This is a method of changing the keymap used for copy/history mode.
+The string is made up of \fIoldchar\fP=\fInewchar\fP pairs which are
+separated by `:'. Example: The string \*QB=^B:F=^F\*U will change the
+keys `C-b' and `C-f' to the vi style binding (scroll up/down fill page).
+This happens to be the default binding for `B' and `F'.
+The command \*Qmarkkeys h=^B:l=^F:$=^E\*U would set the mode for an emacs-style
+binding.
+.sp
+.ne 3
+.B meta
+.PP
+Insert the command character (C-a) in the current window's input stream.
+.sp
+.ne 3
+.BR "monitor " [ on | off ]
+.PP
+Toggles activity monitoring of windows.
+When monitoring is turned on and an affected window is switched into the
+background, you will receive the activity notification message in the
+status line at the first sign of output and the window will also be marked
+with an `@' in the window-status display.
+Monitoring is initially off for all windows.
+.sp
+.ne 3
+.BI "msgminwait " sec
+.PP
+Defines the time
+.I screen
+delays a new message when one message is currently displayed.
+The default is 1 second.
+.sp
+.ne 3
+.BI "msgwait " sec
+.PP
+Defines the time a message is displayed if
+.I screen
+is not disturbed by other activity. The default is 5 seconds.
+.sp
+.ne 3
+.BR "multiuser on" | off
+.PP
+Switch between singleuser and multiuser mode. Standard
+.I screen
+operation is singleuser. In multiuser mode the commands `acladd',
+`aclchg' and `acldel'
+can be used to enable (and disable) other users accessing this screen.
+.sp
+.ne 3
+.BR "nethack on" | off
+.PP
+Changes the kind of error messages used by
+.IR screen .
+When you are familiar with the game \*Qnethack\*U, you may enjoy the
+nethack-style messages which will often blur the facts a little, but are
+much funnier to read. Anyway, standard messages often tend to be unclear as
+well.
+.br
+This option is only
+available if
+.I screen
+was compiled with the NETHACK flag defined. The
+default setting is then determined by the presence of the environment
+variable $NETHACKOPTIONS.
+.sp
+.ne 3
+.B next
+.PP
+Switch to the next window.
+This command can be used repeatedly to cycle through the list of windows.
+.sp
+.ne 3
+.BR "number " [ \fIn ]
+.PP
+Change the current windows number. If the given number \fIn\fP is already
+used by another window, both windows exchange their numbers. If no argument is
+specified, the current window number (and title) is shown.
+.sp
+.ne 3
+.BR "obuflimit " [ \fIlimit ]
+.PP
+If the output buffer contains more bytes than the specified limit, no
+more data will be
+read from the windows. The default value is 256. If you have a fast
+display (like xterm), you can set it to some higher value. If no
+argument is specified, the current setting is displayed.
+.sp
+.ne 3
+.B other
+.PP
+Switch to the window displayed previously.
+.sp
+.ne 3
+.BR "partial on" | off
+.PP
+Defines whether the display should be refreshed (as with \fIredisplay\fP) after
+switching to the current window. This command only affects the current window.
+To immediately affect all windows use the \fIallpartial\fP command.
+Default is `off', of course. This default is fixed, as there is currently no
+\fIdefpartial\fP command.
+.sp
+.ne 3
+.BR "password " [ \fIcrypted_pw ]
+.PP
+Present a crypted password in your \*Q.screenrc\*U file and
+.I screen
+will ask
+for it, whenever someone attempts to resume a detached. This is useful
+if you have privileged programs running under
+.I screen
+and you want to protect your session from reattach attempts by another user
+masquerading as your uid (i.e. any superuser.)
+If no crypted password is specified,
+.I screen
+prompts twice for typing a
+password and places its encryption in the paste buffer.
+Default is `none', this disables password checking.
+.sp
+.ne 3
+.BR paste
+.RI [ registers " [" dest_reg ]]
+.PP
+Write the (concatenated) contents of the specified registers to the stdin queue
+of the current window. The register '.' is treated as the
+paste buffer. If no parameter is given the user is prompted for a single
+register to paste.
+The paste buffer can be filled with the \fIcopy\fP, \fIhistory\fP and
+\fIreadbuf\fP commands.
+Other registers can be filled with the \fIregister\fP, \fIreadreg\fP and
+\fIpaste\fP commands.
+If \fIpaste\fP is called with a second argument, the contents of the specified
+registers is pasted into the named destination register rather than
+the window. If '.' is used as the second argument, the displays paste buffer is
+the destination.
+Note, that \*Qpaste\*U uses a wide variety of resources: Whenever a second
+argument is specified no current window is needed. When the source specification
+only contains registers (not the paste buffer) then there need not be a current
+display (terminal attached), as the registers are a global resource. The
+paste buffer exists once for every user.
+.sp
+.ne 3
+.BR "pastefont " [ on | off ]
+.PP
+Tell screen to include font information in the paste buffer. The
+default is not to do so. This command is especially usefull for
+multi character fonts like kanji.
+.sp
+.ne 3
+.B pow_break
+.PP
+Reopen the window's terminal line and send a break condition. See `break'.
+.sp
+.ne 3
+.B pow_detach
+.PP
+Power detach.
+Mainly the same as \fIdetach\fP, but also sends a HANGUP signal to
+the parent process of
+.IR screen .
+CAUTION: This will result in a logout, when
+.I screen
+was started from your login shell.
+.sp
+.ne 3
+.BI "pow_detach_msg " message
+.PP
+The \fImessage\fP specified here is output whenever a `Power detach' was
+performed. It may be used as a replacement for a logout message or to reset
+baud rate, etc.
+.sp
+.ne 3
+.B prev
+.PP
+Switch to the window with the next lower number.
+This command can be used repeatedly to cycle through the list of windows.
+.sp
+.ne 3
+.B printcmd
+.RI [ cmd ]
+.PP
+If
+.I cmd
+is not an empty string, screen will not use the terminal capabilities
+\*Qpo/pf\*U if it detects an ansi print sequence
+.BR "ESC [ 5 i" ,
+but pipe the output into
+.IR cmd .
+This should normally be a command like \*Qlpr\*U or
+\*Q'cat > /tmp/scrprint'\*U.
+.B printcmd
+without a command displays the current setting.
+The ansi sequence
+.B "ESC \e"
+ends printing and closes the pipe.
+.br
+Warning: Be careful with this command! If other user have write
+access to your terminal, they will be able to fire off print commands.
+.sp
+.ne 3
+.BR process " [" \fIkey ]
+.PP
+Stuff the contents of the specified register into \fIscreen\fP's
+input queue. If no argument is given you are prompted for a
+register name. The text is parsed as if it had been typed in from the user's
+keyboard. This command can be used to bind multiple actions to a single key.
+.sp
+.ne 3
+.B quit
+.PP
+Kill all windows and terminate
+.IR screen .
+Note that on VT100-style terminals the keys C-4 and C-\e are identical.
+This makes the default bindings dangerous:
+Be careful not to type C-a C-4 when selecting window no. 4.
+Use the empty bind command (as in \*Qbind '^\e'\*U) to remove a key binding.
+.sp
+.ne 3
+.B readbuf
+.PP
+Reads the contents of the current screen-exchange file into the paste buffer.
+See also \*Qbufferfile\*U command.
+.sp
+.ne 3
+.B readreg
+.RI [ register " [" filename ]]
+.PP
+Does one of two things, dependent on number of arguments: with zero or one
+arguments it it duplicates the paste buffer contents into the register specified
+or entered at the prompt. With two arguments it reads the contents of the named
+file into the register, just as \fIreadbuf\fP reads the screen-exchange file
+into the paste buffer.
+The following example will paste the system's password file into
+the screen window (using register p, where a copy remains):
+.PP
+.nf
+ C-a : readreg p /etc/passwd
+ C-a : paste p
+.fi
+.sp
+.ne 3
+.B redisplay
+.PP
+Redisplay the current window. Needed to get a full redisplay when in
+partial redraw mode.
+.sp
+.ne 3
+.BI "register " "key string"
+.PP
+Save the specified \fIstring\fP to the register \fIkey\fP. See also the
+\*Qpaste\*U command.
+.sp
+.ne 3
+.B "removebuf"
+.PP
+Unlinks the screen-exchange file used by the commands \*Qwritebuf\*U and
+\*Qreadbuf\*U.
+.sp
+.ne 3
+.B "reset"
+.PP
+Reset the virtual terminal to its \*Qpower-on\*U values. Useful when strange
+settings (like scroll regions or graphics character set) are left over from
+an application.
+.sp
+.ne 3
+.B "screen \fP[\fI-opts\fP] [\fIn\fP] [\fIcmd\fP [\fIargs\fP]]"
+.PP
+Establish a new window.
+The flow-control options (\fB\-f\fP, \fB\-fn\fP and \fB\-fa\fP),
+title (a.\|k.\|a.) option (\fB\-t\fP), login options (\fB-l\fP and \fB-ln\fP)
+, terminal type option (\fB-T <term>\fP) and scrollback option (\fB-h\fP <num>)
+may be specified for each command.
+If an optional number \fIn\fP in the range 0..9 is given, the window
+number \fIn\fP is assigned to the newly created window (or, if this
+number is already in-use, the next available number).
+If a command is specified after \*Qscreen\*U, this command (with the given
+arguments) is started in the window; otherwise, a shell is created.
+Thus, if your \*Q.screenrc\*U contains the lines
+.sp
+.nf
+ # example for .screenrc:
+ screen 1
+ screen -fn -t foobar 2 telnet foobar
+.fi
+.sp
+.I screen
+creates a shell window (in window #1) and a window with a TELNET connection
+to the machine foobar (with no flow-control using the title \*Qfoobar\*U
+in window #2). Note, that unlike previous versions of
+.I screen
+no additional default window is created when \*Qscreen\*U commands are
+included in your \*Q.screenrc\*U file. When the initialization is completed,
+.I screen
+switches to the last window specified in your .screenrc file or, if none,
+opens a default window #0.
+.sp
+.ne 3
+.B "scrollback \fP\fInum\fP"
+.PP
+Set the size of the scrollback buffer for the current windows to \fInum\fP
+lines. The default scrollback is 100 lines.
+See also the \*Qdefscrollback\*U command and use \*QC-a i\*U to view the
+current setting.
+.sp
+.ne 3
+.BR "select " [ \fIn ]
+.PP
+Switch to the window with the number \fIn\fP.
+If no window number is specified, you get prompted for an
+identifier. This can be title (alphanumeric window name) or a number.
+When a new window is established, the first available number
+is assigned to this window.
+Thus, the first window can be activated by \*Qselect 0\*U (there can be no more
+than 10 windows present simultaneously unless
+.I screen
+was compiled with a higher MAXWIN setting).
+.sp
+.ne
+.BR "sessionname " [ \fIname ]
+.PP
+Rename the current session. Note, that for \*Qscreen -list\*U the
+name shows up with the process-id prepended. If the argument \*Qname\*U
+is omitted, the name of this session is displayed. Caution: The $STY
+environment variables still reflects the old name. This may result in
+confusion.
+The default is constructed from the tty and host names.
+.sp
+.ne 3
+.B "setenv "
+.RI [ var " [" string ]]
+.PP
+Set the environment variable \fIvar\fP to value \fIstring\fP.
+If only \fIvar\fP is specified, the user will be prompted to enter a value.
+If no parameters are specified, the user will be prompted for both variable
+and value. The environment is inherited by all subsequently forked shells.
+.sp
+.ne 3
+.B "shell \fIcommand\fP"
+.PP
+Set the command to be used to create a new shell.
+This overrides the value of the environment variable $SHELL.
+This is useful if you'd like to run a tty-enhancer which is expecting to
+execute the program specified in $SHELL. If the command begins with
+a '-' character, the shell will be started as a login-shell.
+.sp
+.ne 3
+.B "shelltitle \fItitle\fP"
+.PP
+Set the title for all shells created during startup or by
+the C-A C-c command.
+For details about what a title is, see the discussion
+entitled \*QTITLES (naming windows)\*U.
+.sp
+.ne 3
+.BR "silence " [ on | off "|\fIsec\fP]"
+.PP
+Toggles silence monitoring of windows.
+When silence is turned on and an affected window is switched into the
+background, you will receive the silence notification message in the
+status line after a specified period of inactivity (silence). The default
+timeout can be changed with the `silencewait' command or by specifying a
+number of seconds instead of `on' or `off'.
+Silence is initially off for all windows.
+.sp
+.ne 3
+.BI "silencewait " sec
+.PP
+Define the time that all windows monitored for silence should wait before
+displaying a message. Default 30 seconds.
+.sp
+.ne
+.B "sleep \fP\fInum\fP"
+.PP
+This command will pause the execution of a .screenrc file for \fInum\fP seconds.
+Keyboard activity will end the sleep.
+It may be used to give users a chance to read the messages output by \*Qecho\*U.
+.sp
+.ne 3
+.B "slowpaste \fIusec\fP"
+.PP
+Define the speed at which text is inserted by the paste ("C-a ]") command.
+If the slowpaste value is nonzero text is written character by character.
+.I screen
+will make a pause of \fIusec\fP milliseconds after each single character write
+to allow the application to process its input. Only use slowpaste if your
+underlying system exposes flow control problems while pasting large amounts of
+text.
+.sp
+.ne 3
+.B sorendition
+.RB [ "\fIattr\fR " [ \fIcolor ]]
+.PP
+Change the way screen does highlighting for text marking and printing
+messages.
+.I Attr
+is a hexadecimal number and describes the attributes (inverse,
+underline, ...) the text will get.
+.I Color
+is a 2 digit number and changes the
+forground/background of the highlighted text.
+Some knowledge of screen's internal character representation is
+needed to make the characters appear in the desired way. The default
+is currently 10 99 (standout, default colors).
+.sp
+.ne 3
+.B "startup_message on\fP|\fBoff"
+.PP
+Select whether you want to see the copyright notice during startup.
+Default is `on', as you probably noticed.
+.sp
+.ne 3
+.B stuff
+.I string
+.PP
+Stuff the string
+.I string
+in the input buffer of the current window.
+This is like the \*Qpaste\*U command but with much less overhead.
+You cannot paste
+large buffers with the \*stuff\*U command. It is most useful for key
+bindings. See also \*Qbindkey\*U.
+.sp
+.ne 3
+.B "suspend"
+.PP
+Suspend
+.IR screen .
+The windows are in the `detached' state, while
+.IR screen
+is suspended. This feature relies on the shell being able to do job control.
+.sp
+.ne 3
+.B "term \fIterm\fP"
+.PP
+In each window's environment
+.I screen
+opens, the $TERM variable is set to \*Qscreen\*U by default.
+But when no description for \*Qscreen\*U is installed in the local termcap
+or terminfo data base, you set $TERM to \- say \-
+\*Qvt100\*U. This won't do much harm, as
+.I screen
+is VT100/ANSI compatible.
+The use of the \*Qterm\*U command is discouraged for non-default purpose.
+That is, one may want to specify special $TERM settings (e.g. vt100) for the
+next \*Qscreen rlogin othermachine\*U command. Use the command \*Qscreen -T vt100
+rlogin othermachine\*U rather than setting and resetting the default.
+.sp
+.ne 3
+.BI termcap " term terminal-tweaks"
+.RI [ window-tweaks ]
+.br
+.BI terminfo " term terminal-tweaks"
+.RI [ window-tweaks ]
+.br
+.BI termcapinfo " term terminal-tweaks"
+.RI [ window-tweaks ]
+.PP
+Use this command to modify your terminal's termcap entry without going through
+all the hassles involved in creating a custom termcap entry.
+Plus, you can optionally customize the termcap generated for the windows.
+If your system works with terminfo-database rather than with
+termcap,
+.I screen
+will understand the `terminfo' command, which has the same effects as
+the `termcap' command. Two separate commands are provided, as there are subtle
+syntactic differences, e.g. when parameter interpolation (using `%') is
+required. Note that termcap names of the capabilities have to be used
+with the `terminfo' command.
+.br
+In many cases, where the arguments are valid in both terminfo and termcap
+syntax, you can use the command `termcapinfo', which is just a shorthand
+for a pair of `termcap' and `terminfo' commands with identical arguments.
+.PP
+The first argument specifies which terminal(s) should be affected by this
+definition.
+You can specify multiple terminal names by separating them with `|'s.
+Use `*' to match all terminals and `vt*' to match all terminals that begin
+with \*Qvt\*U.
+.PP
+Each \fItweak\fP argument contains one or more termcap defines (separated
+by `:'s) to be inserted at the start of the appropriate termcap entry,
+enhancing it or overriding existing values.
+The first tweak modifies your terminal's termcap, and contains definitions
+that your terminal uses to perform certain functions.
+Specify a null string to leave this unchanged (e.\|g. '').
+The second (optional) tweak modifies all the window termcaps, and should
+contain definitions that
+.I screen
+understands (see the \*QVIRTUAL TERMINAL\*U
+section).
+.PP
+Some examples:
+.IP
+termcap xterm* LP:hs@
+.PP
+Informs
+.I screen
+that all terminals that begin with `xterm' have firm auto-margins that
+allow the last position on the screen to be updated (LP), but they don't
+really have a status line (no 'hs' \- append `@' to turn entries off).
+Note that we assume `LP' for all terminal names that start with \*Qvt\*U,
+but only if you don't specify a termcap command for that terminal.
+.IP
+termcap vt* LP
+.br
+termcap vt102|vt220 Z0=\eE[?3h:Z1=\eE[?3l
+.PP
+Specifies the firm-margined `LP' capability for all terminals that begin with
+`vt', and the second line will also add the escape-sequences to switch
+into (Z0) and back out of (Z1) 132-character-per-line mode if this is
+a VT102 or VT220.
+(You must specify Z0 and Z1 in your termcap to use the width-changing
+commands.)
+.IP
+termcap vt100 "" l0=PF1:l1=PF2:l2=PF3:l3=PF4
+.PP
+This leaves your vt100 termcap alone and adds the function key labels to
+each window's termcap entry.
+.IP
+termcap h19|z19 am@:im=\eE@:ei=\eEO dc=\eE[P
+.PP
+Takes a h19 or z19 termcap and turns off auto-margins (am@) and enables the
+insert mode (im) and end-insert (ei) capabilities (the `@' in the `im'
+string is after the `=', so it is part of the string).
+Having the `im' and `ei' definitions put into your terminal's termcap will
+cause
+.I screen
+to automatically advertise the character-insert capability in
+each window's termcap.
+Each window will also get the delete-character capability (dc) added to its
+termcap, which
+.I screen
+will translate into a line-update for the terminal
+(we're pretending it doesn't support character deletion).
+.PP
+If you would like to fully specify each window's termcap entry, you should
+instead set the $SCREENCAP variable prior to running
+.IR screen .
+See the discussion on the \*QVIRTUAL TERMINAL\*U in this manual, and the termcap(5)
+man page for more information on termcap definitions.
+.sp
+.ne 3
+.B time
+.PP
+Uses the message line to display the time of day, the host name, and the load
+averages over 1, 5, and 15 minutes (if this is available on your system).
+For window specific information use \*Qinfo\*U.
+.sp
+.ne 3
+.BR "title " [ \fIwindowalias ]
+.PP
+Set the name of the current window to \fIwindowalias\fP. If no name is
+specified,
+.I screen
+prompts for one. This command was known as `aka' in previous
+releases.
+.sp
+.ne 3
+.BI "unsetenv " var
+.PP
+Unset an environment variable.
+.sp
+.ne 3
+.BR "vbell on" | off
+.PP
+If your terminal does not support
+a visual bell, a `vbell-message' is displayed in the status line.
+Sets the visual bell setting for this window. If your terminal does not support
+a visual bell, a `vbell-message' is displayed in the status line.
+Refer to the termcap variable `vb' (terminfo: 'flash').
+.sp
+.ne 3
+.BI "vbell_msg " message
+.PP
+Sets the visual bell message. \fImessage\fP is printed to the status line if
+the window receives a bell character (^G) and vbell is set to \*Qon\*U.
+The default message is \*QWuff, Wuff!!\*U.
+.sp
+.ne 3
+.BI "vbellwait " sec
+.PP
+Define a delay in seconds after each display of
+.IR screen 's
+visual bell message. The default is 1 second.
+.sp
+.ne 3
+.B version
+.PP
+Print the current version and the compile date in the status line.
+.sp
+.ne 3
+.BI "wall " "message"
+.PP
+Write a message to all displays. The message will appear in the terminal's
+status line.
+.sp
+.ne 3
+.BR "width " [ \fInum ]
+.PP
+Toggle the window width between 80 and 132 columns or set it to \fInum\fP
+columns if an argument is specified.
+This requires a capable terminal and the termcap entries \*QZ0\*U and \*QZ1\*U.
+See the \*Qtermcap\*U command for more information.
+.sp
+.ne 3
+.B windows
+.PP
+Uses the message line to display a list of all the windows.
+Each window is listed by number with the name of process that has been
+started in the window (or its title);
+the current window is marked with a `*';
+the previous window is marked with a `-';
+all the windows that are \*Qlogged in\*U are marked with a `$';
+a background window that has received a bell is marked with a `!';
+a background window that is being monitored and has had activity occur
+is marked with an `@';
+a window which has output logging turned on is marked with `(L)';
+windows occupied by other users are marked with `&';
+windows in the zombie state are marked with `Z'.
+If this list is too long to fit on the terminal's status line only the
+portion around the current window is displayed.
+.sp
+.ne 3
+.BR "wrap " [ on | off ]
+.PP
+Sets the line-wrap setting for the current window.
+When line-wrap is on, the second consecutive printable character output at
+the last column of a line will wrap to the start of the following line.
+As an added feature, backspace (^H) will also wrap through the left margin
+to the previous line.
+Default is `on'.
+.sp
+.ne 3
+.B writebuf
+.PP
+Writes the contents of the paste buffer to a public accessible screen-exchange
+file. This is thought of as a primitive means of communication between
+.I screen
+users on the same host. The filename can be set with the \fIbufferfile\fP
+command and defaults to \*Q/tmp/screen-exchange\*U.
+.sp
+.ne 3
+.BR "writelock " [ on | "off\fR|\fBauto\fR]"
+.PP
+In addition to access control lists, not all users may be able to write to
+the same window at once. Per default, writelock is in `auto' mode and
+grants exclusive input permission to the user who is the first to switch
+to the particular window. When he leaves the window, other users may obtain
+the writelock (automatically). The writelock of the current window is disabled
+by the command \*Qwritelock off\*U. If the user issues the command
+\*Qwritelock on\*U he keeps the exclusive write permission while switching
+to other windows.
+.sp
+.ne 3
+.B xoff
+.br
+.B xon
+.PP
+Insert a CTRL-s / CTRL-q character to the stdin queue of the
+current window.
+.sp
+.ne 3
+.BR "zombie " [\fIkeys\fP]
+.br
+.BR "defzombie " [\fIkeys\fP]
+.PP
+Per default
+.I screen
+windows are removed from the window list as soon as
+the windows process (e.g. shell) exits. When a string of two keys is
+specified to the zombie command, `dead' windows will remain in the list.
+The \fBkill\fP kommand may be used to remove such a window. Pressing the
+first key in the dead window has the same effect. When pressing the second
+key, screen will attempt to resurrect the window. The process that was
+initially running in the window will be launched again. Calling \fBzombie\fP
+without parameters will clear the zombie setting, thus making windows disappear
+when their process exits.
+
+As the zombie-setting is manipulated globally for all windows, this command
+should only be called \fBdefzombie\fP. Until we need this as a per window
+setting, the commands \fBzombie\fP and \fBdefzombie\fP are synonymous.
+
+.SH "THE MESSAGE LINE"
+.I Screen
+displays informational messages and other diagnostics in a \fImessage line\fP.
+While this line is distributed to appear at the bottom of the screen,
+it can be defined to appear at the top of the screen during compilation.
+If your terminal has a status line defined in its termcap,
+.I screen
+will use this for displaying its messages, otherwise a line of the
+current screen will
+be temporarily overwritten and output will be momentarily interrupted. The
+message line is automatically removed after a few seconds delay, but it
+can also be removed early (on terminals without a status line) by beginning
+to type.
+.PP
+The message line facility can be used by an application running in
+the current window by means of the ANSI \fIPrivacy message\fP
+control sequence.
+For instance, from within the shell, try something like:
+.IP
+echo '<esc>^Hello world from window '$WINDOW'<esc>\e\e'
+.PP
+where '<esc>' is an \fIescape\fP, '^' is a literal up-arrow,
+and '\e\e' turns into a single backslash.
+
+
+.SH "FLOW-CONTROL"
+Each window has a flow-control setting that determines how
+.I screen
+deals with
+the XON and XOFF characters (and perhaps the interrupt character).
+When flow-control is turned off,
+.I screen
+ignores the XON and XOFF characters,
+which allows the user to send them to the current program by simply typing
+them (useful for the \fIemacs\fP editor, for instance).
+The trade-off is that it will take longer for output from a \*Qnormal\*U
+program to pause in response to an XOFF.
+With flow-control turned on, XON and XOFF characters are used to immediately
+pause the output of the current window.
+You can still send these characters to the current program, but you must use
+the appropriate two-character
+.I screen
+commands (typically \*QC-a q\*U (xon)
+and \*QC-a s\*U (xoff)).
+The xon/xoff commands are also useful for typing C-s and C-q past a terminal
+that intercepts these characters.
+.PP
+Each window has an initial flow-control value set with either the
+.B \-f
+option or the \*Qdefflow\*U .screenrc command. Per default the windows
+are set to automatic flow-switching.
+It can then be toggled between the three states 'fixed on', 'fixed off' and
+'automatic' interactively with the \*Qflow\*U command bound to "C-a f".
+.PP
+The automatic flow-switching mode deals with
+flow control using the TIOCPKT mode (like \*Qrlogin\*U does). If
+the tty driver does not support TIOCPKT,
+.I screen
+tries to find out
+the right mode based on the current setting of the application
+keypad \- when it is enabled, flow-control is turned off and visa versa.
+Of course, you can still manipulate flow-control manually when needed.
+.PP
+If you're running with flow-control enabled and find that pressing the
+interrupt key (usually C-c) does not interrupt the display until another
+6-8 lines have scrolled by, try running
+.I screen
+with the \*Qinterrupt\*U
+option (add the \*Qinterrupt\*U flag to the \*Qflow\*U command in
+your .screenrc, or use the
+.B \-i
+command-line option).
+This causes the output that
+.I screen
+has accumulated from the interrupted program to be flushed.
+One disadvantage is that the virtual terminal's memory contains the
+non-flushed version of the output, which in rare cases can cause
+minor inaccuracies in the output.
+For example, if you switch screens and return, or update the screen
+with \*QC-a l\*U you would see the version of the output you would
+have gotten without \*Qinterrupt\*U being on.
+Also, you might need to turn off flow-control (or use auto-flow mode to turn
+it off automatically) when running a program that expects you to type the
+interrupt character as input, as it is possible to interrupt
+the output of the virtual terminal to your physical terminal when flow-control
+is enabled.
+If this happens, a simple refresh of the screen with \*QC-a l\*U will
+restore it.
+Give each mode a try, and use whichever mode you find more comfortable.
+
+
+.SH "TITLES (naming windows)"
+You can customize each window's name in the window display (viewed with the
+\*Qwindows\*U command (C-a w)) by setting it with one of
+the title commands.
+Normally the name displayed is the actual command name of the program
+created in the window.
+However, it is sometimes useful to distinguish various programs of the same
+name or to change the name on-the-fly to reflect the current state of
+the window.
+.PP
+The default name for all shell windows can be set with the \*Qshelltitle\*U
+command in the .screenrc file, while all other windows are created with
+a \*Qscreen\*U command and thus can have their name set with the
+.B \-t
+option.
+Interactively, there is the title-string escape-sequence
+(<esc>k\fIname\fP<esc>\e) and the \*Qtitle\*U command (C-a A).
+The former can be output from an application to control the window's name
+under software control, and the latter will prompt for a name when typed.
+You can also bind pre-defined names to keys with the \*Qtitle\*U command
+to set things quickly without prompting.
+.PP
+Finally,
+.I screen
+has a shell-specific heuristic that is enabled by setting the window's name
+to \*Q\fIsearch|name\fP\*U and arranging to have a null title escape-sequence
+output as a part of your prompt.
+The \fIsearch\fP portion specifies an end-of-prompt search string, while
+the \fIname\fP portion specifies the default shell name for the window.
+If the \fIname\fP ends in a `:'
+.I screen
+will add what it believes to be the current command running in the window
+to the end of the window's shell name (e.\|g. \*Q\fIname:cmd\fP\*U).
+Otherwise the current command name supersedes the shell name while it is
+running.
+.PP
+Here's how it works: you must modify your shell prompt to output a null
+title-escape-sequence (<esc>k<esc>\e) as a part of your prompt.
+The last part of your prompt must be the same as the string you specified
+for the \fIsearch\fP portion of the title.
+Once this is set up,
+.I screen
+will use the title-escape-sequence to clear the previous command name and
+get ready for the next command.
+Then, when a newline is received from the shell, a search is made for the
+end of the prompt.
+If found, it will grab the first word after the matched string and use it
+as the command name.
+If the command name begins with either '!', '%', or '^'
+.I screen
+will use the first word on the following line (if found) in preference to
+the just-found name.
+This helps csh users get better command names when using job control or
+history recall commands.
+.PP
+Here's some .screenrc examples:
+.IP
+screen -t top 2 nice top
+.PP
+Adding this line to your .screenrc would start a nice-d version of the
+\*Qtop\*U command in window 2 named \*Qtop\*U rather than \*Qnice\*U.
+.sp
+.nf
+ shelltitle '> |csh'
+ screen 1
+.fi
+.sp
+These commands would start a shell with the given shelltitle.
+The title specified is an auto-title that would expect the prompt and
+the typed command to look something like the following:
+.IP
+/usr/joe/src/dir> trn
+.PP
+(it looks after the '> ' for the command name).
+The window status would show the name \*Qtrn\*U while the command was
+running, and revert to \*Qcsh\*U upon completion.
+.IP
+bind R screen -t '% |root:' su
+.PP
+Having this command in your .screenrc would bind the key
+sequence \*QC-a R\*U to the \*Qsu\*U command and give it an
+auto-title name of \*Qroot:\*U.
+For this auto-title to work, the screen could look something
+like this:
+.sp
+.nf
+ % !em
+ emacs file.c
+.fi
+.sp
+Here the user typed the csh history command \*Q!em\*U which ran the
+previously entered \*Qemacs\*U command.
+The window status would show \*Qroot:emacs\*U during the execution
+of the command, and revert to simply \*Qroot:\*U at its completion.
+.PP
+.nf
+ bind o title
+ bind E title ""
+ bind u title (unknown)
+.fi
+.sp
+The first binding doesn't have any arguments, so it would prompt you
+for a title. when you type \*QC-a o\*U.
+The second binding would clear an auto-title's current setting (C-a E).
+The third binding would set the current window's title to \*Q(unknown)\*U
+(C-a u).
+.PP
+One thing to keep in mind when adding a null title-escape-sequence to
+your prompt is that some shells (like the csh) count all the non-control
+characters as part of the prompt's length.
+If these invisible characters aren't a multiple of 8 then backspacing over
+a tab will result in an incorrect display.
+One way to get around this is to use a prompt like this:
+.IP
+set prompt='^[[0000m^[k^[\e% '
+.PP
+The escape-sequence \*Q<esc>[0000m\*U not only normalizes the character
+attributes, but all the zeros round the length of the invisible characters
+up to 8.
+Bash users will probably want to echo the escape sequence in the
+PROMPT_COMMAND:
+.IP
+PROMPT_COMMAND='echo -n -e "\e033k\e033\e134"'
+.PP
+(I used \*Q\134\*U to output a `\e' because of a bug in bash v1.04).
+
+
+.SH "THE VIRTUAL TERMINAL"
+Each window in a
+.I screen
+session emulates a VT100 terminal, with some extra functions added. The
+VT100 emulator is hardcoded, no other terminal types can be emulated.
+.br
+Usually
+.I screen
+tries to emulate as much of the VT100/ANSI standard
+as possible. But if your terminal lacks certain capabilities,
+the emulation may not be complete. In these cases
+.I screen
+has to tell the applications that some of the features
+are missing. This is no problem on machines using termcap,
+because
+.I screen
+can use the $TERMCAP variable to
+customize the standard
+.I screen
+termcap.
+.PP
+But if you do a
+rlogin on another machine or your machine supports only
+terminfo this method fails. Because of this,
+.I screen
+offers a way to deal with these cases.
+Here is how it works:
+.PP
+When
+.I screen
+tries to figure out a terminal name for itself,
+it first looks
+for an entry named \*Qscreen.<term>\*U, where <term> is
+the contents of your $TERM variable.
+If no such entry exists,
+.I screen
+tries \*Qscreen\*U (or \*Qscreen-w\*U if the terminal is wide
+(132 cols or more)).
+If even this entry cannot be found, \*Qvt100\*U is used as a
+substitute.
+.PP
+The idea is that if you have a terminal which doesn't
+support an important feature (e.g. delete char or clear to EOS)
+you can build a new termcap/terminfo entry for
+.I screen
+(named \*Qscreen.<dumbterm>\*U) in which this capability
+has been disabled. If this entry is installed on your
+machines you are able to do
+a rlogin and still keep the correct termcap/terminfo entry.
+The terminal name is put in the $TERM variable
+of all new windows.
+.I Screen
+also sets the $TERMCAP variable reflecting the capabilities
+of the virtual terminal emulated. Notice that, however, on machines
+using the terminfo database this variable has no effect.
+Furthermore, the variable $WINDOW is set to the window number
+of each window.
+.PP
+The actual set of capabilities supported by the virtual terminal
+depends on the capabilities supported by the physical terminal.
+If, for instance, the physical terminal does not support underscore mode,
+.I screen
+does not put the `us' and `ue' capabilities into the window's $TERMCAP
+variable, accordingly.
+However, a minimum number of capabilities must be supported by a
+terminal in order to run
+.IR screen ;
+namely scrolling, clear screen, and direct cursor addressing
+(in addition,
+.I screen
+does not run on hardcopy terminals or on terminals that over-strike).
+.PP
+Also, you can customize the $TERMCAP value used by
+.I screen
+by using the \*Qtermcap\*U .screenrc command, or
+by defining the variable $SCREENCAP prior to startup.
+When the is latter defined, its value will be copied verbatim into each
+window's $TERMCAP variable.
+This can either be the full terminal definition, or a filename where the
+terminal \*Qscreen\*U (and/or \*Qscreen-w\*U) is defined.
+.PP
+Note that
+.I screen
+honors the \*Qterminfo\*U .screenrc command if the system uses the
+terminfo database rather than termcap.
+.PP
+When the boolean `G0' capability is present in the termcap entry
+for the terminal on which
+.I screen
+has been called, the terminal emulation of
+.I screen
+supports multiple character sets.
+This allows an application to make use of, for instance,
+the VT100 graphics character set or national character sets.
+The following control functions from ISO 2022 are supported:
+\fIlock shift G0\fP (\fISI\fP), \fIlock shift G1\fP (\fISO\fP),
+\fIlock shift G2\fP, \fIlock shift G3\fP, \fIsingle shift G2\fP,
+and \fIsingle shift G3\fP.
+When a virtual terminal is created or reset, the ASCII character
+set is designated as \fIG0\fP through \fIG3\fP.
+When the `G0' capability is present,
+.I screen
+evaluates the capabilities
+`S0', `E0', and `C0' if present. `S0' is the sequence the terminal uses
+to enable and start the graphics character set rather than \fISI\fP.
+`E0' is the corresponding replacement for \fISO\fP. `C0' gives a character
+by character translation string that is used during semi-graphics mode. This
+string is built like the `acsc' terminfo capability.
+.PP
+When the `po' and `pf' capabilities are present in the terminal's
+termcap entry, applications running in a
+.I screen
+window can send output to the printer port of the terminal.
+This allows a user to have an application in one window
+sending output to a printer connected to the terminal, while all
+other windows are still active (the printer port is enabled
+and disabled again for each chunk of output).
+As a side-effect, programs running in different windows can
+send output to the printer simultaneously.
+Data sent to the printer is not displayed in the window.
+.PP
+.I Screen
+maintains a hardstatus line for every window. If a window
+gets selected, the display's hardstatus will be updated to match
+the window's hardstatus line. If the display has no hardstatus
+the line will be displayed as a standard screen message.
+The hardstatus line can be changed with the ANSI Application
+Program Command (APC): \*QESC_<string>ESC\e\*U. As a convenience
+for xterm users the sequence \*QESC]0..2;<string>^G\*U is
+also accepted.
+.PP
+Some capabilities are only put into the $TERMCAP
+variable of the virtual terminal if they can be efficiently
+implemented by the physical terminal.
+For instance, `dl' (delete line) is only put into the $TERMCAP
+variable if the terminal supports either delete line itself or
+scrolling regions. Note that this may provoke confusion, when
+the session is reattached on a different terminal, as the value
+of $TERMCAP cannot be modified by parent processes.
+.PP
+The following is a list of control sequences recognized by
+.IR screen .
+\*Q(V)\*U and \*Q(A)\*U indicate VT100-specific and ANSI- or
+ISO-specific functions, respectively.
+.PP
+.ta 22n
+.TP 27
+.B "ESC E"
+Next Line
+.TP 27
+.B "ESC D"
+Index
+.TP 27
+.B "ESC M"
+Reverse Index
+.TP 27
+.B "ESC H"
+Horizontal Tab Set
+.TP 27
+.B "ESC Z"
+Send VT100 Identification String
+.TP 27
+.BR "ESC 7" " (V)"
+Save Cursor and Attributes
+.TP 27
+.BR "ESC 8" " (V)"
+Restore Cursor and Attributes
+.TP 27
+.BR "ESC [s" " (A)"
+Save Cursor and Attributes
+.TP 27
+.BR "ESC [u" " (A)"
+Restore Cursor and Attributes
+.TP 27
+.B "ESC c"
+Reset to Initial State
+.TP 27
+.B "ESC g"
+Visual Bell
+.TP 27
+.B "ESC \fPPn\fB p"
+Cursor Visibility (97801)
+.TP 27
+\h'\w'ESC 'u'Pn = \fB6\fP
+Invisible
+.TP 27
+\h'\w'ESC Pn = 'u'\fB7\fP
+Visible
+.TP 27
+.BR "ESC =" " (V)"
+Application Keypad Mode
+.TP 27
+.BR "ESC >" " (V)"
+Numeric Keypad Mode
+.TP 27
+.BR "ESC # 8" " (V)"
+Fill Screen with E's
+.TP 27
+.BR "ESC \e" " (A)"
+String Terminator
+.TP 27
+.BR "ESC ^" " (A)"
+Privacy Message String (Message Line)
+.TP 27
+.B "ESC !"
+Global Message String (Message Line)
+.TP 27
+.B "ESC k"
+A.\|k.\|a. Definition String
+.TP 27
+.BR "ESC P" " (A)"
+Device Control String.
+Outputs a string directly to the host
+terminal without interpretation.
+.TP 27
+.BR "ESC _" " (A)"
+Application Program Command (Hardstatus)
+.TP 27
+.BR "ESC ]" " (A)"
+Operating System Command (Hardstatus, xterm title hack)
+.TP 27
+.BR "Control-N" " (A)"
+Lock Shift G1 (SO)
+.TP 27
+.BR "Control-O" " (A)"
+Lock Shift G0 (SI)
+.TP 27
+.BR "ESC n" " (A)"
+Lock Shift G2
+.TP 27
+.BR "ESC o" " (A)"
+Lock Shift G3
+.TP 27
+.BR "ESC N" " (A)"
+Single Shift G2
+.TP 27
+.BR "ESC O" " (A)"
+Single Shift G3
+.TP 27
+.BR "ESC ( \fPPcs" " (A)"
+Designate character set as G0
+.TP 27
+.BR "ESC ) \fPPcs" " (A)"
+Designate character set as G1
+.TP 27
+.BR "ESC * \fPPcs" " (A)"
+Designate character set as G2
+.TP 27
+.BR "ESC + \fPPcs" " (A)"
+Designate character set as G3
+.TP 27
+.B "ESC [ \fPPn\fB ; \fPPn\fB H"
+Direct Cursor Addressing
+.TP 27
+.B "ESC [ \fPPn\fB ; \fPPn\fB f"
+Direct Cursor Addressing
+.TP 27
+.B "ESC [ \fPPn\fB J"
+Erase in Display
+.TP 27
+\h'\w'ESC [ 'u'Pn = None or \fB0\fP
+From Cursor to End of Screen
+.TP 27
+\h'\w'ESC [ Pn = 'u'\fB1\fP
+From Beginning of Screen to Cursor
+.TP 27
+\h'\w'ESC [ Pn = 'u'\fB2\fP
+Entire Screen
+.TP 27
+.B "ESC [ \fPPn\fB K"
+Erase in Line
+.TP 27
+\h'\w'ESC [ 'u'Pn = None or \fB0\fP
+From Cursor to End of Line
+.TP 27
+\h'\w'ESC [ Pn = 'u'\fB1\fP
+From Beginning of Line to Cursor
+.TP 27
+\h'\w'ESC [ Pn = 'u'\fB2\fP
+Entire Line
+.TP 27
+.B "ESC [ \fPPn\fB A"
+Cursor Up
+.TP 27
+.B "ESC [ \fPPn\fB B"
+Cursor Down
+.TP 27
+.B "ESC [ \fPPn\fB C"
+Cursor Right
+.TP 27
+.B "ESC [ \fPPn\fB D"
+Cursor Left
+.TP 27
+.B "ESC [ \fPPs\fB ;\fP...\fB; \fPPs\fB m"
+Select Graphic Rendition
+.TP 27
+\h'\w'ESC [ 'u'Ps = None or \fB0\fP
+Default Rendition
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB1\fP
+Bold
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB2\fP (A)
+Faint
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB3\fP (A)
+\fIStandout\fP Mode (ANSI: Italicized)
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB4\fP
+Underlined
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB5\fP
+Blinking
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB7\fP
+Negative Image
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB22\fP (A)
+Normal Intensity
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB23\fP (A)
+\fIStandout\fP Mode off (ANSI: Italicized off)
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB24\fP (A)
+Not Underlined
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB25\fP (A)
+Not Blinking
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB27\fP (A)
+Positive Image
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB30\fP (A)
+Foreground Black
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB31\fP (A)
+Foreground Red
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB32\fP (A)
+Foreground Green
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB33\fP (A)
+Foreground Yellow
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB34\fP (A)
+Foreground Blue
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB35\fP (A)
+Foreground Magenta
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB36\fP (A)
+Foreground Cyan
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB37\fP (A)
+Foreground White
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB39\fP (A)
+Foreground Default
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB40\fP (A)
+Background Black
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB...\fP
+...
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB49\fP (A)
+Background Default
+.TP 27
+.B "ESC [ \fPPn\fB g"
+Tab Clear
+.TP 27
+\h'\w'ESC [ 'u'Pn = None or \fB0\fP
+Clear Tab at Current Position
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB3\fP
+Clear All Tabs
+.TP 27
+.BR "ESC [ \fPPn\fB ; \fPPn\fB r" " (V)"
+Set Scrolling Region
+.TP 27
+.BR "ESC [ \fPPn\fB I" " (A)"
+Horizontal Tab
+.TP 27
+.BR "ESC [ \fPPn\fB Z" " (A)"
+Backward Tab
+.TP 27
+.BR "ESC [ \fPPn\fB L" " (A)"
+Insert Line
+.TP 27
+.BR "ESC [ \fPPn\fB M" " (A)"
+Delete Line
+.TP 27
+.BR "ESC [ \fPPn\fB @" " (A)"
+Insert Character
+.TP 27
+.BR "ESC [ \fPPn\fB P" " (A)"
+Delete Character
+.TP 27
+.B "ESC [ \fPPn\fB S"
+Scroll Scrolling Region Up
+.TP 27
+.B "ESC [ \fPPn\fB T"
+Scroll Scrolling Region Down
+.TP 27
+.B "ESC [ \fPPs\fB ;\fP...\fB; \fPPs\fB h"
+Set Mode
+.TP 27
+.B "ESC [ \fPPs\fB ;\fP...\fB; \fPPs\fB l"
+Reset Mode
+.TP 27
+\h'\w'ESC [ 'u'Ps = \fB4\fP (A)
+Insert Mode
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB20\fP (A)
+\fIAutomatic Linefeed\fP Mode
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB34\fP
+Normal Cursor Visibility
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB?1\fP (V)
+Application Cursor Keys
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB?3\fP (V)
+Change Terminal Width to 132 columns
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB?5\fP (V)
+Reverse Video
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB?6\fP (V)
+\fIOrigin\fP Mode
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB?7\fP (V)
+\fIWrap\fP Mode
+.TP 27
+\h'\w'ESC [ Ps = 'u'\fB?25\fP (V)
+Visible Cursor
+.TP 27
+.BR "ESC [ 5 i" " (A)"
+Start relay to printer (ANSI Media Copy)
+.TP 27
+.BR "ESC [ 4 i" " (A)"
+Stop relay to printer (ANSI Media Copy)
+.TP 27
+.B "ESC [ 8 ; \fPPh\fB ; \fPPw\fB t"
+Resize the window to `Ph' lines and `Pw' columns (SunView special)
+.TP 27
+.B "ESC [ c"
+Send VT100 Identification String
+.TP 27
+.B "ESC [ x"
+Send Terminal Parameter Report
+.TP 27
+.B "ESC [ > c"
+Send VT220 Secondary Device Attributes String
+.TP 27
+.B "ESC [ 6 n"
+Send Cursor Position Report
+
+
+.SH "INPUT TRANSLATION"
+In order to do a full VT100 emulation \fIscreen\fP has to detect
+that a sequence of characters in the input stream was generated
+by a keypress on the user's keyboard and insert the VT100
+style escape sequence. \fIScreen\fP has a very flexible way of doing
+this by making it posible to map arbitrary commands on arbitrary
+sequences of characters. For standard VT100 emulation the command
+will always insert a string in the input buffer of the window
+(see also command \fBstuff\fP in the command table).
+Because the sequences generated by a keypress can
+change after a reattach from a different terminal type, it is
+possible to bind commands to the termcap name of the keys.
+\fIScreen\fP will insert the correct binding after each
+reattach. See the \fBbindkey\fP command for further details on the
+syntax and examples.
+.PP
+Here is the table of the default key bindings. (A) means that the
+command is executed if the keyboard is switched into application
+mode.
+.PP
+.ta 18n 34n 50n
+.nf
+Key name Termcap name Command
+\l'54n'
+.ta 22n 34n 50n
+Cursor up ku stuff \e033[A
+ stuff \e033OA (A)
+Cursor down kd stuff \e033[B
+ stuff \e033OB (A)
+Cursor right kr stuff \e033[C
+ stuff \e033OC (A)
+Cursor left kl stuff \e033[D
+ stuff \e033OD (A)
+Function key 0 k0 stuff \e033[10~
+Function key 1 k1 stuff \e033OP
+Function key 2 k2 stuff \e033OQ
+Function key 3 k3 stuff \e033OR
+Function key 4 k4 stuff \e033OS
+Function key 5 k5 stuff \e033[15~
+Function key 6 k6 stuff \e033[17~
+Function key 7 k7 stuff \e033[18~
+Function key 8 k8 stuff \e033[19~
+Function key 9 k9 stuff \e033[20~
+Function key 10 k; stuff \e033[21~
+Function key 11 F1 stuff \e033[22~
+Function key 12 F2 stuff \e033[23~
+Backspace kb stuff \e010
+Home kh stuff \e033[1~
+End kH stuff \e033[4~
+Insert kI stuff \e033[2~
+Delete kD stuff \e033[3~
+Page up kP stuff \e033[5~
+Page down kN stuff \e033[6~
+Keypad 0 f0 stuff 0
+ stuff \e033Op (A)
+Keypad 1 f1 stuff 1
+ stuff \e033Oq (A)
+Keypad 2 f2 stuff 2
+ stuff \e033Or (A)
+Keypad 3 f3 stuff 3
+ stuff \e033Os (A)
+Keypad 4 f4 stuff 4
+ stuff \e033Ot (A)
+Keypad 5 f5 stuff 5
+ stuff \e033Ou (A)
+Keypad 6 f6 stuff 6
+ stuff \e033Ov (A)
+Keypad 7 f7 stuff 7
+ stuff \e033Ow (A)
+Keypad 8 f8 stuff 8
+ stuff \e033Ox (A)
+Keypad 9 f9 stuff 9
+ stuff \e033Oy (A)
+Keypad + f+ stuff +
+ stuff \e033Ok (A)
+Keypad - f- stuff -
+ stuff \e033Om (A)
+Keypad * f* stuff *
+ stuff \e033Oj (A)
+Keypad / f/ stuff /
+ stuff \e033Oo (A)
+Keypad = fq stuff =
+ stuff \e033OX (A)
+Keypad . f. stuff .
+ stuff \e033On (A)
+Keypad , f, stuff ,
+ stuff \e033Ol (A)
+Keypad enter fe stuff \e015
+ stuff \e033OM (A)
+.fi
+
+
+.SH SPECIAL TERMINAL CAPABILITIES
+The following table describes all terminal capabilities
+that are recognized by \fIscreen\fP and are not in the
+termcap(5) manual.
+You can place these capabilities in your termcap entries (in
+`/etc/termcap') or use them with the commands `termcap', `terminfo' and
+`termcapinfo' in your screenrc files. It is often not possible to place
+these capabilities in the terminfo database.
+.PP
+.ta 5n
+.TP 13
+.BI LP " (bool)"
+Terminal has VT100 style margins (`magic margins'). Note that
+this capability is obsolete because \fIscreen\fP uses the standard 'xn'
+instead.
+.TP 13
+.BI Z0 " (str)"
+Change width to 132 columns.
+.TP 13
+.BI Z1 " (str)"
+Change width to 80 columns.
+.TP 13
+.BI WS " (str)"
+Resize display. This capability has the desired width and height as
+arguments. \fISunView(tm)\fP example: '\eE[8;%d;%dt'.
+.TP 13
+.BI NF " (bool)"
+Terminal doesn't need flow control. Send ^S and ^Q direct to
+the application. Same as 'flow off'. The opposite of this
+capability is 'nx'.
+.TP 13
+.BI G0 " (bool)"
+Terminal can deal with ISO 2022 font selection sequences.
+.TP 13
+.BI S0 " (str)"
+Switch charset 'G0' to the specified charset. Default
+is '\eE(%.'.
+.TP 13
+.BI E0 " (str)"
+Switch charset 'G0' back to standard charset. Default
+is '\eE(B'.
+.TP 13
+.BI C0 " (str)"
+Use the string as a conversion table for font '0'. See
+the 'ac' capability for more details.
+.TP 13
+.BI CS " (str)"
+Switch cursorkeys to application mode.
+.TP 13
+.BI CE " (str)"
+Switch cursorkeys back to normal mode.
+.TP 13
+.BI AN " (bool)"
+Turn on autonuke. See the 'autonuke' command for more details.
+.TP 13
+.BI OL " (num)"
+Set the output buffer limit. See the 'obuflimit' command for more details.
+.TP 13
+.BI KJ " (str)"
+Set the kanji type of the terminal. Valid strings are \*Qjis\*U,
+\*Qeuc\*U and \*Qsjis\*U.
+.TP 13
+.BI AF " (str)"
+Change character forground color in an ANSI conform way. This
+capability will almost always be set to '\eE[3%dm' ('\eE[3%p1%dm'
+on terminfo machines).
+.TP 13
+.BI AB " (str)"
+Same as 'AF', but change background color.
+.TP 13
+.BI AX " (bool)"
+Does understand ANSI set default fg/bg color (\eE[39m / \eE[49m).
+.TP 13
+.BI XC " (str)"
+Describe a translation of characters to strings depending on the
+current font. More details follow in the next section.
+
+.SH CHARACTER TRANSLATION
+\fIScreen\fP has a powerful mechanism to translate characters to arbitrary
+strings depending on the current font and terminal type.
+Use this feature if you want to work with a common standard character
+set (say ISO8851-latin1) even on terminals that scatter the more
+unusual characters over several national language font pages.
+
+Syntax:
+.nf
+ \fBXC=\fP\fI<charset-mapping>\fP{\fB,,\fP\fI<charset-mapping>\fP}
+ \fI<charset-mapping>\fP := \fI<designator><template>\fP{\fB,\fP\fI<mapping>\fP}
+ \fI<mapping>\fP := \fI<char-to-be-mapped><template-arg>\fP
+.fi
+
+The things in braces may be repeated any number of times.
+
+A \fI<charset-mapping>\fP tells \fIscreen\fP how to map characters
+in font \fI<designator>\fP ('B': Ascii, 'A': UK, 'K': german, etc.)
+to strings. Every \fI<mapping>\fP describes to what string a single
+character will be translated. A template mechanism is used, as
+most of the time the codes have a lot in common (for example
+strings to switch to and from another charset). Each occurence
+of '%' in \fI<template>\fP gets substituted with the \fI<template-arg>\fP
+specified together with the character. If your strings are not
+similar at all, then use '%' as a template and place the full
+string in \fI<template-arg>\fP. A quoting mechanism was added to make
+it possible to use a real '%'. The '\e' character quotes the
+special characters '\e', '%', and ','.
+
+Here is an example:
+
+ termcap hp700 'XC=B\eE(K%\eE(B,\e304[,\e326\e\e\e\e,\e334]'
+
+This tells \fIscreen\fP, how to translate ISOlatin1 (charset 'B')
+upper case umlaut characters on a hp700 terminal that has a
+german charset. '\e304' gets translated to '\eE(K[\eE(B' and so on.
+Note that this line gets parsed *three* times before the internal
+lookup table is built, therefore a lot of quoting is needed to
+create a single '\e'.
+
+Another extension was added to allow more emulation: If a mapping
+translates the unquoted '%' char, it will be sent to the terminal
+whenever \fIscreen\fP switches to the corresponding \fI<designator>\fP. In this
+special case the template is assumed to be just '%' because
+the charset switch sequence and the character mappings normaly
+haven't much in common.
+
+This example shows one use of the extension:
+
+ termcap xterm 'XC=K%,%\eE(B,[\e304,\e\e\e\e\e326,]\e334'
+
+Here, a part of the german ('K') charset is emulated on an xterm.
+If \fIscreen\fP has to change to the 'K' charset, '\eE(B' will be sent
+to the terminal, i.e. the ASCII charset is used instead. The
+template is just '%', so the mapping is straightforward: '['
+to '\e304', '\e' to '\e326', and ']' to '\e334'.
+
+.SH ENVIRONMENT
+.PD 0
+.IP COLUMNS 15
+Number of columns on the terminal (overrides termcap entry).
+.IP HOME
+Directory in which to look for .screenrc.
+.IP ISCREENRC
+Alternate user screenrc file.
+.IP LINES
+Number of lines on the terminal (overrides termcap entry).
+.IP LOCKPRG
+Screen lock program.
+.IP NETHACKOPTIONS
+Turns on nethack option.
+.IP PATH
+Used for locating programs to run.
+.IP SCREENCAP
+For customizing a terminal's TERMCAP value.
+.IP SCREENDIR
+Alternate socket directory.
+.IP SCREENRC
+Alternate user screenrc file.
+.IP SHELL
+Default shell program for opening windows (default \*Q/bin/sh\*U).
+.IP STY
+Alternate socket name.
+.IP SYSSCREENRC
+Alternate system screenrc file.
+.IP TERM
+Terminal name.
+.IP TERMCAP
+Terminal description.
+
+
+.SH FILES
+.PD 0
+.IP $SYSSCREENRC 28
+.IP /local/etc/screenrc
+\fIscreen\fP initialization commands
+.IP $ISCREENRC
+.IP $SCREENRC
+.IP $HOME/.iscreenrc
+.IP $HOME/.screenrc
+Read in after /local/etc/screenrc
+.IP $ISCREENDIR/S-<login>
+.IP $SCREENDIR/S-<login>
+.IP /local/screens/S-<login>
+Socket directories (default)
+.IP /usr/tmp/screens/S-<login>
+Alternate socket directories.
+.IP "<socket directory>/.termcap"
+Written by the "termcap" output function
+.IP /usr/tmp/screens/screen-exchange
+or
+.IP /tmp/screen-exchange
+\fIscreen\fP `interprocess communication buffer'
+.IP hardcopy.[0-9]
+Screen images created by the hardcopy function
+.IP screenlog.[0-9]
+Output log files created by the log function
+.IP /usr/lib/terminfo/?/*
+or
+.IP /etc/termcap
+Terminal capability databases
+.IP /etc/utmp
+Login records
+.IP $LOCKPRG
+Program that locks a terminal.
+
+
+.SH "SEE ALSO"
+termcap(5), utmp(5), vi(1), captoinfo(1), tic(1)
+
+
+.SH AUTHORS
+Originally created by Oliver Laumann, this latest version was
+produced by Wayne Davison, Juergen Weigert and Michael Schroeder.
+
+.SH COPYLEFT
+.nf
+Copyright (C) 1993
+ Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+Copyright (C) 1987 Oliver Laumann
+.fi
+.PP
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+.PP
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+.PP
+You should have received a copy of the GNU General Public License
+along with this program (see the file COPYING); if not, write to the
+Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+.SH CONTRIBUTORS
+.nf
+Ken Beal (kbeal@amber.ssd.csd.harris.com),
+Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de),
+Toerless Eckert (eckert@immd4.informatik.uni-erlangen.de),
+Wayne Davison (davison@borland.com),
+Patrick Wolfe (pat@kai.com, kailand!pat),
+Bart Schaefer (schaefer@cse.ogi.edu),
+Nathan Glasser (nathan@brokaw.lcs.mit.edu),
+Larry W. Virden (lvirden@cas.org),
+Howard Chu (hyc@hanauma.jpl.nasa.gov),
+Tim MacKenzie (tym@dibbler.cs.monash.edu.au),
+Markku Jarvinen (mta@{cc,cs,ee}.tut.fi),
+Marc Boucher (marc@CAM.ORG),
+Doug Siebert (dsiebert@isca.uiowa.edu),
+Ken Stillson (stillson@tsfsrv.mitre.org),
+Ian Frechett (frechett@spot.Colorado.EDU),
+Brian Koehmstedt (bpk@gnu.ai.mit.edu),
+Don Smith (djs6015@ultb.isc.rit.edu),
+Frank van der Linden (vdlinden@fwi.uva.nl),
+Martin Schweikert (schweik@cpp.ob.open.de),
+David Vrona (dave@sashimi.lcu.com),
+E. Tye McQueen (tye%spillman.UUCP@uunet.uu.net),
+Matthew Green (mrgreen@mame.mu.oz.au),
+Christopher Williams (cgw@unt.edu),
+Matt Mosley (mattm@access.digex.net),
+Gregory Neil Shapiro (gshapiro@wpi.WPI.EDU).
+.fi
+
+
+.SH VERSION
+This is version 3.7.0. Its roots are a merge of a custom version
+2.3PR7 by Wayne Davison
+and several enhancements to Oliver Laumann's version 2.0. Note that all versions
+numbered 2.x are copyright by Oliver Laumann.
+
+
+.SH BUGS
+.PD
+.IP \(bu 3
+`dm' (delete mode) and `xs' are not handled
+correctly (they are ignored). `xn' is treated as a magic-margin
+indicator.
+.IP \(bu
+.I Screen
+has no clue about double-high or double-wide characters.
+But this is the only area where
+.I vttest
+is allowed to fail.
+.IP \(bu
+It is not possible to change the environment variable $TERMCAP when
+reattaching under a different terminal type.
+.IP \(bu
+The support of terminfo based systems is very limited. Adding extra
+capabilities to $TERMCAP may not have any effects.
+.IP \(bu
+.I Screen
+does not make use of hardware tabs.
+.IP \(bu
+.I Screen
+must be installed as set-uid with owner root in order to be able
+to correctly change the owner of the tty device file for each
+window.
+Special permission may also be required to write the file \*Q/etc/utmp\*U.
+.IP \(bu
+Entries in \*Q/etc/utmp\*U are not removed when
+.I screen
+is killed with SIGKILL.
+This will cause some programs (like "w" or "rwho")
+to advertise that a user is logged on who really isn't.
+.IP \(bu
+.I Screen
+may give a strange warning when your tty has no utmp entry.
+.IP \(bu
+When the modem line was hung up,
+.I screen
+may not automatically detach (or quit)
+unless the device driver is configured to send a HANGUP signal.
+To detach a
+.I screen
+session use the -D or -d command line option.
+.IP \(bu
+A weird imagination is most useful to gain full advantage of all the features.
+.IP \(bu
+Send bugreports, fixes, enhancements, t-shirts, money, beer & pizza to
+.BR screen@uni-erlangen.de .
+
diff --git a/doc/screen.info b/doc/screen.info
new file mode 100644
index 0000000..06243df
--- /dev/null
+++ b/doc/screen.info
@@ -0,0 +1,167 @@
+This is Info file screen.info, produced by Makeinfo-1.55 from the input
+file ./screen.texinfo.
+
+ This file documents the `Screen' virtual terminal manager.
+
+ Copyright (c) 1993 Free Software Foundation, Inc.
+
+ Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+ Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+ Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by the Foundation.
+
+
+Indirect:
+screen.info-1: 873
+screen.info-2: 50135
+screen.info-3: 99940
+screen.info-4: 149859
+
+Tag Table:
+(Indirect)
+Node: Top873
+Node: Overview2756
+Node: Getting Started6129
+Node: Invoking Screen7887
+Node: Customization13559
+Node: Startup Files14046
+Node: Colon15692
+Node: Commands16314
+Node: Default Key Bindings17272
+Node: Command Summary22227
+Node: New Window32611
+Node: Chdir33374
+Node: Screen Command34345
+Node: Setenv35983
+Node: Shell36503
+Node: Term37176
+Node: Selecting37936
+Node: Next and Previous38473
+Node: Other Window38999
+Node: Select39408
+Node: Session Management40011
+Node: Detach40848
+Node: Power Detach42133
+Node: Lock42772
+Node: Multiuser Session43658
+Node: Multiuser44416
+Node: Acladd44803
+Node: Aclchg45298
+Node: Acldel46621
+Node: Wall46954
+Node: Writelock47192
+Node: Session Name48085
+Node: Suspend48632
+Node: Quit48964
+Node: Window Settings49389
+Node: Naming Windows50135
+Node: Title Command51635
+Node: Dynamic Titles51909
+Node: Title Prompts53443
+Node: Title Screenrc54524
+Node: Console56163
+Node: Kill56605
+Node: Login57428
+Node: Mode58247
+Node: Monitor58645
+Node: Windows60056
+Node: Hardstatus61065
+Node: Virtual Terminal62236
+Node: Control Sequences63293
+Node: Input Translation69794
+Node: Digraph74310
+Node: Bell75102
+Node: Clear76940
+Node: Info77143
+Node: Redisplay77969
+Node: Wrap79101
+Node: Reset79852
+Node: Window Size80170
+Node: Character Processing80785
+Node: Copy and Paste83657
+Node: Copy84262
+Node: Line Termination85107
+Node: Scrollback85516
+Node: Copy Mode Keys86005
+Node: Movement86820
+Node: Marking87974
+Node: Repeat count88349
+Node: Searching88663
+Node: Specials88925
+Node: Paste90857
+Node: Registers93418
+Node: Screen-Exchange94424
+Node: History95507
+Node: Subprocess Execution96247
+Node: Exec96611
+Node: Using Exec98201
+Node: Key Binding99940
+Node: Bind100583
+Node: Bind Examples101570
+Node: Command Character102250
+Node: Help103758
+Node: Bindkey104271
+Node: Bindkey Examples105814
+Node: Bindkey Control106699
+Node: Flow Control107296
+Node: Flow Control Summary107872
+Node: Flow110806
+Node: XON/XOFF111580
+Node: Termcap111953
+Node: Window Termcap112810
+Node: Dump Termcap117968
+Node: Termcap Syntax118683
+Node: Termcap Examples120843
+Node: Special Capabilities122884
+Node: Autonuke125348
+Node: Obuflimit125998
+Node: Character Translation126827
+Node: Message Line129438
+Node: Privacy Message130349
+Node: Hardware Status Line130846
+Node: Last Message131475
+Node: Message Wait131902
+Node: Logging132328
+Node: Hardcopy132652
+Node: Log133448
+Node: Startup134196
+Node: echo134603
+Node: sleep135009
+Node: Startup Message135350
+Node: Miscellaneous135623
+Node: At136612
+Node: Break137920
+Node: Debug138323
+Node: License138707
+Node: Nethack138972
+Node: Number139648
+Node: Silence140017
+Node: Time140784
+Node: Version141158
+Node: Zombie141364
+Node: Printcmd142418
+Node: Sorendition143124
+Node: Environment143775
+Node: Files144857
+Node: Credits145983
+Node: Bugs147900
+Node: Known Bugs148370
+Node: Reporting Bugs149859
+Node: Availability150635
+Node: Installation151081
+Node: Socket Directory151471
+Node: Compiling Screen152001
+Node: Concept Index153393
+Node: Command Index155173
+Node: Keystroke Index162058
+
+End Tag Table
diff --git a/doc/screen.info-1 b/doc/screen.info-1
new file mode 100644
index 0000000..6d39c2c
--- /dev/null
+++ b/doc/screen.info-1
@@ -0,0 +1,1514 @@
+This is Info file screen.info, produced by Makeinfo-1.55 from the input
+file ./screen.texinfo.
+
+ This file documents the `Screen' virtual terminal manager.
+
+ Copyright (c) 1993 Free Software Foundation, Inc.
+
+ Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+ Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+ Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by the Foundation.
+
+
+File: screen.info, Node: Top, Next: Overview, Prev: (dir), Up: (dir)
+
+Screen
+******
+
+ This file documents the `Screen' virtual terminal manager, version
+3.7.0.
+
+* Menu:
+
+* Overview:: Preliminary information.
+* Getting Started:: An introduction to `screen'.
+* Invoking Screen:: Command line options for `screen'.
+* Customization:: The `.screenrc' file.
+* Commands:: List all of the commands.
+* New Window:: Running a program in a new window.
+* Selecting:: Selecting a window to display.
+* Session Management:: Suspending or detaching a session.
+* Window Settings:: titles, logging, etc.
+* Virtual Terminal:: Controlling the `screen' VT100 emulation.
+* Copy and Paste:: Exchanging text between windows and sessions.
+* Subprocess Execution:: I/O filtering with `exec'.
+* Key Binding:: Binding commands to keys.
+* Flow Control:: Trap or pass flow control characters.
+* Termcap:: Tweaking your terminal's termcap entry.
+* Message Line:: The `screen' message line.
+* Logging:: Keeping a record of your session.
+* Startup:: Functions only useful at `screen' startup.
+* Miscellaneous:: Various other commands.
+* Environment:: Environment variables used by `screen'.
+* Files:: Files used by `screen'.
+* Credits:: Who's who of `screen'.
+* Bugs:: What to do if you find a bug.
+* Installation:: Getting `screen' running on your system.
+* Concept Index:: Index of concepts.
+* Command Index:: Index of all `screen' commands.
+* Keystroke Index:: Index of default key bindings.
+
+
+File: screen.info, Node: Overview, Next: Getting Started, Prev: Top, Up: Top
+
+Overview
+********
+
+ Screen is a full-screen window manager that multiplexes a physical
+terminal between several processes, typically interactive shells. Each
+virtual terminal provides the functions of the DEC VT100 terminal and,
+in addition, several control functions from the ANSI X3.64 (ISO 6429)
+and ISO 2022 standards (e.g. insert/delete line and support for multiple
+character sets). There is a scrollback history buffer for each virtual
+terminal and a copy-and-paste mechanism that allows the user to move
+text regions between windows.
+
+ When `screen' is called, it creates a single window with a shell in
+it (or the specified command) and then gets out of your way so that you
+can use the program as you normally would. Then, at any time, you can
+create new (full-screen) windows with other programs in them (including
+more shells), kill the current window, view a list of the active
+windows, turn output logging on and off, copy text between windows, view
+the scrollback history, switch between windows, etc. All windows run
+their programs completely independent of each other. Programs continue
+to run when their window is currently not visible and even when the
+whole screen session is detached from the users terminal.
+
+ When a program terminates, `screen' (per default) kills the window
+that contained it. If this window was in the foreground, the display
+switches to the previously displayed window; if none are left, `screen'
+exits.
+
+ Everything you type is sent to the program running in the current
+window. The only exception to this is the one keystroke that is used to
+initiate a command to the window manager. By default, each command
+begins with a control-a (abbreviated `C-a' from now on), and is
+followed by one other keystroke. The command character (*note Command
+Character::.) and all the key bindings (*note Key Binding::.) can be
+fully customized to be anything you like, though they are always two
+characters in length.
+
+ The standard way to create a new window is to type `C-a c'. This
+creates a new window running a shell and switches to that window
+immediately, regardless of the state of the process running in the
+current window. Similarly, you can create a new window with a custom
+command in it by first binding the command to a keystroke (in your
+`.screenrc' file or at the `C-a :' command line) and then using it just
+like the `C-a c' command. In addition, new windows can be created by
+running a command like:
+
+ screen emacs prog.c
+
+from a shell prompt within a previously created window. This will not
+run another copy of `screen', but will instead supply the command name
+and its arguments to the window manager (specified in the $STY
+environment variable) who will use it to create the new window. The
+above example would start the `emacs' editor (editing `prog.c') and
+switch to its window.
+
+ If `/etc/utmp' is writable by `screen', an appropriate record will
+be written to this file for each window, and removed when the window is
+closed. This is useful for working with `talk', `script', `shutdown',
+`rsend', `sccs' and other similar programs that use the utmp file to
+determine who you are. As long as `screen' is active on your terminal,
+the terminal's own record is removed from the utmp file. *Note Login::.
+
+
+File: screen.info, Node: Getting Started, Next: Invoking Screen, Prev: Overview, Up: Top
+
+Getting Started
+***************
+
+ Before you begin to use `screen' you'll need to make sure you have
+correctly selected your terminal type, just as you would for any other
+termcap/terminfo program. (You can do this by using `tset', `qterm',
+or just `set term=mytermtype', for example.)
+
+ If you're impatient and want to get started without doing a lot more
+reading, you should remember this one command: `C-a ?' (*note Key
+Binding::.). Typing these two characters will display a list of the
+available `screen' commands and their bindings. Each keystroke is
+discussed in the section on keystrokes (*note Default Key Bindings::.).
+Another section (*note Customization::.) deals with the contents of your
+`.screenrc'.
+
+ If your terminal is a "true" auto-margin terminal (it doesn't allow
+the last position on the screen to be updated without scrolling the
+screen) consider to use a version of your terminal's termcap that has
+automatic margins turned *off*. This will ensure an accurate and
+optimal update of the screen in all circumstances. Most terminals
+nowadays have "magic" margins (automatic margins plus usable last
+column). This is the VT100 style type and perfectly suited for
+`screen'. If all you've got is a "true" auto-margin terminal `screen'
+will be content to use it, but updating a character put into the last
+position on the screen may not be possible until the screen scrolls or
+the character is moved into a safe position in some other way. This
+delay can be shortened by using a terminal with insert-character
+capability.
+
+ *Note Special Capabilities::, for more information about telling
+`screen' what kind of terminal you have.
+
+
+File: screen.info, Node: Invoking Screen, Next: Customization, Prev: Getting Started, Up: Top
+
+Invoking `Screen'
+*****************
+
+ Screen has the following command-line options:
+
+`-a'
+ Include *all* capabilities (with some minor exceptions) in each
+ window's termcap, even if `screen' must redraw parts of the display
+ in order to implement a function.
+
+`-A'
+ Adapt the sizes of all windows to the size of the display. By
+ default, `screen' may try to restore its old window sizes when
+ attaching to resizable terminals (those with `WS' in their
+ descriptions, e.g. `suncmd' or some varieties of `xterm').
+
+`-c FILE'
+ Use FILE as the user's configuration file instead of the default
+ of `$HOME/.screenrc'.
+
+`-d [PID.SESSIONNAME]'
+`-D [PID.SESSIONNAME]'
+ Do not start `screen', but instead detach a `screen' session
+ running elsewhere (*note Detach::.). `-d' has the same effect as
+ typing `C-a d' from the controlling terminal for the session.
+ `-D' is the equivalent to the power detach key. If no session can
+ be detached, this option is ignored. The combination `screen -D
+ -r' can be used to log out from a remote terminal and transport the
+ session running there to your current terminal. *Note*: It is a
+ good idea to check the status of your sessions with `screen -list'
+ before using this option.
+
+`-e XY'
+ Set the command character to X, and the character generating a
+ literal command character (when typed after the command character)
+ to Y. The defaults are `C-a' and `a', which can be specified as
+ `-e^Aa'. When creating a `screen' session, this option sets the
+ default command caracter. In a multiuser session all users added
+ will start off with this command character. But when attaching to
+ an already running session, this option only changes the command
+ character of the attaching user. This option is equivalent to the
+ commands `defescape' or `escape' respectively. (*note Command
+ Character::.).
+
+`-f'
+`-fn'
+`-fa'
+ Set flow-control to on, off, or automatic switching mode,
+ respectively. This option is equivalent to the `defflow' command
+ (*note Flow Control::.).
+
+`-h NUM'
+ Set the history scrollback buffer to be NUM lines high.
+ Equivalent to the `defscrollback' command (*note Copy::.).
+
+`-i'
+ Cause the interrupt key (usually `C-c') to interrupt the display
+ immediately when flow control is on. This option is equivalent to
+ the `interrupt' argument to the `defflow' command (*note Flow
+ Control::.). Its use is discouraged.
+
+`-l'
+`-ln'
+ Turn login mode on or off (for `/etc/utmp' updating). This option
+ is equivalent to the `deflogin' command (*note Login::.).
+
+`-ls'
+`-list'
+ Do not start `screen', but instead print a list of session
+ identification strings (usually of the form PID.TTY.HOST; *note
+ Session Name::.). Sessions marked `detached' can be resumed with
+ `screen -r'. Those marked `attached' are running and have a
+ controlling terminal. Sessions marked as `dead' should be
+ thoroughly checked and removed. Ask your system administrator if
+ you are not sure why they died. Remove sessions with the `-wipe'
+ option.
+
+`-L'
+ Tell `screen' that your auto-margin terminal allows programs to
+ write to the last column of the last row of the screen without
+ scrolling. This can also be set in your `.screenrc' by specifying
+ `xn' in a `termcap' command (*note Termcap::.).
+
+`-m'
+ Tell `screen' to ignore the `$STY' environment variable. When
+ this option is used, a new session will always be created,
+ regardless of whether `screen' is being called from within another
+ `screen' session or not.
+
+`-r [PID.SESSIONNAME]'
+`-r SESSIONOWNER/[PID.SESSIONNAME]'
+ Resume a detached `screen' session. No other options (except `-d'
+ or `-D') may be specified, though the session name (*note Session
+ Name::.) may be needed to distinguish between multiple detached
+ `screen' sessions. The second form is used to connect to another
+ users screen session which runs in multi-user mode. This indicates
+ that screen should look for sessions in another users directory.
+ This requires setuid-root.
+
+`-R'
+ Resume the first appropriate detached `screen' session. If
+ successful, all other command-line options are ignored. If no
+ detached session exists, start a new session using the specified
+ options, just as if `-R' had not been specified. This option is
+ set by default if screen is run as a login-shell.
+
+`-s PROGRAM'
+ Set the default shell to be PROGRAM. By default, `screen' uses
+ the value of the environment variable `$SHELL', or `/bin/sh' if it
+ is not defined. This option is equivalent to the `shell' command
+ (*note Shell::.).
+
+`-S SESSIONNAME'
+ Set the name of the new session to SESSIONNAME. This option can
+ be used to specify a meaningful name for the session in place of
+ the default TTY.HOST suffix. This name identifies the session for
+ the `screen -list' and `screen -r' commands. This option is
+ equivalent to the `sessionname' command (*note Session Name::.).
+
+`-t NAME'
+ Set the title (name) for the default shell or specified program.
+ This option is equivalent to the `shelltitle' command (*note
+ Shell::.).
+
+`-v'
+ Print the version number.
+
+`-wipe'
+ List available screens like `screen -ls', but remove destroyed
+ sessions instead of marking them as `dead'.
+
+`-x'
+ Attach to a session which is already attached elsewhere
+ (multi-display mode).
+
+
+File: screen.info, Node: Customization, Next: Commands, Prev: Invoking Screen, Up: Top
+
+Customizing `Screen'
+********************
+
+ You can modify the default settings for `screen' to fit your tastes
+either through a personal `.screenrc' file which contains commands to
+be executed at startup, or on the fly using the `colon' command.
+
+* Menu:
+
+* Startup Files:: The `.screenrc' file.
+* Colon:: Entering customization commands interactively.
+
+
+File: screen.info, Node: Startup Files, Next: Colon, Up: Customization
+
+The `.screenrc' file
+====================
+
+ When `screen' is invoked, it executes initialization commands from
+the files `.screenrc' in the user's home directory and
+`/usr/local/etc/screenrc'. These defaults can be overridden in the
+following ways: For the global screenrc file `screen' searches for the
+environment variable `$SYSSCREENRC' (this override feature may be
+disabled at compile-time). The user specific screenrc file is searched
+for in `$SCREENRC', then ``$HOME'/.screenrc'. The command line option
+`-c' specifies which file to use (*note Invoking Screen::.. Commands
+in these files are used to set options, bind commands to keys, and to
+automatically establish one or more windows at the beginning of your
+`screen' session. Commands are listed one per line, with empty lines
+being ignored. A command's arguments are separated by tabs or spaces,
+and may be surrounded by single or double quotes. A `#' turns the rest
+of the line into a comment, except in quotes. Unintelligible lines are
+warned about and ignored. Commands may contain references to
+environment variables. The syntax is the shell-like `$VAR' or
+`${VAR}'. Note that this causes incompatibility with previous `screen'
+versions, as now the '$'-character has to be protected with '\' if no
+variable substitution is intended. A string in single-quotes is also
+protected from variable substitution.
+
+ Two configuration files are shipped as examples with your screen
+distribution: `etc/screenrc' and `etc/etcscreenrc'. They contain a
+number of useful examples for various commands.
+
+
+File: screen.info, Node: Colon, Prev: Startup Files, Up: Customization
+
+Colon
+=====
+
+ Customization can also be done online, with this command:
+
+ - Command: colon
+ (`C-a :')
+ Allows you to enter `.screenrc' command lines. Useful for
+ on-the-fly modification of key bindings, specific window creation
+ and changing settings. Note that the `set' keyword no longer
+ exists, as of version 3.3. Change default settings with commands
+ starting with `def'. You might think of this as the `ex' command
+ mode of `screen', with `copy' as its `vi' command mode (*note Copy
+ and Paste::.).
+
+
+File: screen.info, Node: Commands, Next: New Window, Prev: Customization, Up: Top
+
+Commands
+********
+
+ A command in `screen' can either be bound to a key, invoked from a
+screenrc file, or called from the `colon' prompt (*note
+Customization::.). As of version 3.3, all commands can be bound to
+keys, although some may be less useful than others. For a number of
+real life working examples of the most important commands see the files
+`etc/screenrc' and `etc/etcscreenrc' of your screen distribution.
+
+ In this manual, a command definition looks like this:
+
+- Command: command [-n] ARG1 [ARG2] ...
+ (KEYBINDINGS)
+ This command does something, but I can't remember what.
+
+ An argument in square brackets (`[]') is optional. Many commands
+take an argument of `on' or `off', which is indicated as STATE in the
+definition.
+
+* Menu:
+
+* Default Key Bindings:: `screen' keyboard commands.
+* Command Summary:: List of all commands.
+
+
+File: screen.info, Node: Default Key Bindings, Next: Command Summary, Up: Commands
+
+Default Key Bindings
+====================
+
+ As mentioned previously, each keyboard command consists of a `C-a'
+followed by one other character. For your convenience, all commands
+that are bound to lower-case letters are also bound to their control
+character counterparts (with the exception of `C-a a'; see below).
+Thus, both `C-a c' and `C-a C-c' can be used to create a window.
+
+ The following table shows the default key bindings:
+
+`C-a ''
+`C-a "'
+ (select)
+ Prompt for a window identifier and switch. *Note Selecting::.
+
+`C-a 0...9'
+ (select 0...select 9)
+ Switch to window number 0...9. *Note Selecting::.
+
+`C-a C-a'
+ (other)
+ Toggle to the window displayed previously. *Note Selecting::.
+
+`C-a a'
+ (meta)
+ Send the command character (C-a) to window. See `escape' command.
+ *Note Command Character::.
+
+`C-a A'
+ (title)
+ Allow the user to enter a title for the current window. *Note
+ Naming Windows::.
+
+`C-a b'
+ itemx `C-a C-b' (break)
+ Send a break to the tty. *Note Break::.
+
+`C-a B'
+ (pow_break)
+ Close and reopen the tty-line. *Note Break::.
+
+`C-a c'
+`C-a C-c'
+ (screen)
+ Create a new window with a shell and switch to that window. *Note
+ Screen Command::.
+
+`C-a C'
+ (clear)
+ Clear the screen. *Note Clear::.
+
+`C-a d'
+`C-a C-d'
+ (detach)
+ Detach `screen' from this terminal. *Note Detach::.
+
+`C-a D D'
+ (pow_detach)
+ Detach and logout. *Note Power Detach::.
+
+`C-a f'
+`C-a C-f'
+ (flow)
+ Cycle flow among `on', `off' or `auto'. *Note Flow::.
+
+`C-a C-g'
+ (vbell)
+ Toggle visual bell mode. *Note Bell::.
+
+`C-a h'
+ (hardcopy)
+ Write a hardcopy of the current window to the file "hardcopy.N".
+ *Note Hardcopy::.
+
+`C-a H'
+ (log)
+ Toggle logging of the current window to the file "screenlog.N".
+ *Note Log::.
+
+`C-a i'
+`C-a C-i'
+ (info)
+ Show info about the current window. *Note Info::.
+
+`C-a k'
+`C-a C-k'
+ (kill)
+ Destroy the current window. *Note Kill::.
+
+`C-a l'
+`C-a C-l'
+ (redisplay)
+ Fully refresh the current window. *Note Redisplay::.
+
+`C-a L'
+ (login)
+ Toggle the current window's login state. *Note Login::.
+
+`C-a m'
+`C-a C-m'
+ (lastmsg)
+ Repeat the last message displayed in the message line. *Note Last
+ Message::.
+
+`C-a M'
+ (monitor) Toggle monitoring of the current window. *Note
+ Monitor::.
+
+`C-a SPC'
+`C-a n'
+`C-a C-n'
+ (next)
+ Switch to the next window. *Note Selecting::.
+
+`C-a N'
+ (number)
+ Show the number (and title) of the current window. *Note Number::.
+
+`C-a p'
+`C-a C-p'
+`C-a C-h'
+`C-a BackSpace'
+ (prev)
+ Switch to the previous window (opposite of `C-a n'). *Note
+ Selecting::.
+
+`C-a q'
+`C-a C-q'
+ (xon)
+ Send a ^Q (ASCII XON) to the current window. *Note XON/XOFF::.
+
+`C-a r'
+`C-a C-r'
+ (wrap)
+ Toggle the current window's line-wrap setting (turn the current
+ window's automatic margins on or off). *Note Wrap::.
+
+`C-a s'
+`C-a C-s'
+ (xoff)
+ Send a ^S (ASCII XOFF) to the current window. *Note XON/XOFF::.
+
+`C-a t'
+`C-a C-t'
+ (time)
+ Show the load average and xref. *Note Time::.
+
+`C-a v'
+ (version)
+ Display the version and compilation date. *Note Version::.
+
+`C-a C-v'
+ (digraph)
+ Enter digraph. *Note Digraph::.
+
+`C-a w'
+`C-a C-w'
+ (windows)
+ Show a list of active windows. *Note Windows::.
+
+`C-a W'
+ (width)
+ Toggle between 80 and 132 columns. *Note Window Size::.
+
+`C-a x'
+`C-a C-x'
+ (lockscreen)
+ Lock your terminal. *Note Lock::.
+
+`C-a z'
+`C-a C-z'
+ (suspend)
+ Suspend `screen'. *Note Suspend::.
+
+`C-a Z'
+ (reset)
+ Reset the virtual terminal to its "power-on" values. *Note
+ Reset::.
+
+`C-a .'
+ (dumptermcap)
+ Write out a `.termcap' file. *Note Dump Termcap::.
+
+`C-a ?'
+ (help)
+ Show key bindings. *Note Help::.
+
+`C-a C-\'
+ (quit)
+ Kill all windows and terminate `screen'. *Note Quit::.
+
+`C-a :'
+ (colon)
+ Enter a command line. *Note Colon::.
+
+`C-a ['
+`C-a C-['
+`C-a ESC'
+ (copy)
+ Enter copy/scrollback mode. *Note Copy::.
+
+`C-a ]'
+`C-a C-]'
+ (paste .)
+ Write the contents of the paste buffer to the stdin queue of the
+ current window. *Note Paste::.
+
+`C-a {'
+ (history)
+ Copy and paste a previous (command) line. *Note History::.
+
+`C-a >'
+ (writebuf)
+ Write the paste buffer out to the screen-exchange file. *Note
+ Screen-Exchange::.
+
+`C-a <'
+ (readbuf)
+ Read the screen-exchange file into the paste buffer. *Note
+ Screen-Exchange::.
+
+`C-a ='
+ (removebuf)
+ Delete the screen-exchange file. *Note Screen-Exchange::.
+
+`C-a _'
+ (silence)
+ Start/stop monitoring the current window for inactivity. *Note
+ Silence::,
+
+`C-a ,'
+ (license)
+ Show the copyright page.
+
+
+File: screen.info, Node: Command Summary, Prev: Default Key Bindings, Up: Commands
+
+Command Summary
+===============
+
+`acladd USERNAMES'
+ Allow other users in this session. *Note Multiuser Session::.
+
+`aclchg USERNAMES PERMBITS LIST'
+ Change a user's permissions. *Note Multiuser Session::.
+
+`acldel USERNAME'
+ Disallow other user in this session. *Note Multiuser Session::.
+
+`activity MESSAGE'
+ Set the activity notification message. *Note Monitor::.
+
+`allpartial STATE'
+ Set all windows to partial refresh. *Note Redisplay::.
+
+`at [IDENT][`#'|`*'|`%'] COMMAND [ARGS]'
+ Execute a command at other displays or windows. *Note At::.
+
+`autodetach STATE'
+ Automatically detach the session on SIGHUP. *Note Detach::.
+
+`autonuke STATE'
+ Enable a clear screen to discard unwritten output. *Note
+ Autonuke::.
+
+`bell_msg MESSAGE'
+ Set the bell notification message. *Note Bell::.
+
+`bind KEY [COMMAND [ARGS]]'
+ Bind a command to a key. *Note Bind::.
+
+`bindkey [OPTS] [STRING [CMD ARGS]]'
+ Bind a string to a series of keystrokes. *Note Bindkey::.
+
+`break [DURATION]'
+ Send a break signal to the current window. *Note Break::.
+
+`bufferfile [EXCHANGE-FILE]'
+ Select a file for screen-exchange. *Note Screen-Exchange::.
+
+`c1 [STATE]'
+ Change c1 code processing. *Note Character Processing::.
+
+`charset SET'
+ Change character set slot designation. *Note Character
+ Processing::.
+
+`chdir [DIRECTORY]'
+ Change the current directory for future windows. *Note Chdir::.
+
+`clear'
+ Clear the window screen. *Note Clear::.
+
+`colon'
+ Enter a `screen' command. *Note Colon::.
+
+`command'
+ Simulate the screen escape key. *Note Command Character::.
+
+`console [STATE]'
+ Grab or ungrab console output. *Note Console::.
+
+`copy'
+ Enter copy mode. *Note Copy::.
+
+`copy_reg [KEY]'
+ Removed. Use `paste' instead. *Note Registers::.
+
+`crlf STATE'
+ Select line break behavior for copying. *Note Line Termination::.
+
+`debug STATE'
+ Suppress/allow debugging output. *Note Debug::.
+
+`defautonuke STATE'
+ Select default autonuke behavior. *Note Autonuke::.
+
+`defc1 STATE'
+ Select default c1 processing behavior. *Note Character
+ Processing::.
+
+`defcharset [SET]'
+ Change defaul character set slot designation. *Note Character
+ Processing::.
+
+`defescape XY'
+ Set the default command and `meta' characters. *Note Command
+ Character::.
+
+`defflow FSTATE'
+ Select default flow control behavior. *Note Flow::.
+
+`defgr STATE'
+ Select default GR processing behavior. *Note Character
+ Processing::.
+
+`defhstatus [STATUS]'
+ Select default window hardstatus line. *Note Hardstatus::.
+
+`defkanji WTYPE'
+ Select default GR processing behavior. *Note Character
+ Processing::.
+
+`deflogin STATE'
+ Select default utmp logging behavior. *Note Login::.
+
+`defmode MODE'
+ Select default file mode for ptys. *Note Mode::.
+
+`defmonitor STATE'
+ Select default activity monitoring behavior. *Note Monitor::.
+
+`defobuflimit LIMIT'
+ Select default output buffer limit. *Note Obuflimit::.
+
+`defscrollback NUM'
+ Set default lines of scrollback. *Note Scrollback::.
+
+`defwrap STATE'
+ Set default line-wrapping behavior. *Note Wrap::.
+
+`defwritelock ON|OFF|AUTO'
+ Set default writelock behavior. *Note Multiuser::.
+
+`defzombie [KEYS]'
+ Keep dead windows. *Note Zombie::.
+
+`detach'
+ Disconnect `screen' from the terminal. *Note Detach::.
+
+`digraph'
+ Enter digraph sequence. *Note Digraph::.
+
+`dumptermcap'
+ Write the window's termcap entry to a file. *Note Dump Termcap::.
+
+`echo [-n] MESSAGE'
+ Display a message on startup. *Note Startup::.
+
+`escape XY'
+ Set the command and `meta' characters. *Note Command Character::.
+
+`exec [[FDPAT] COMMAND [ARGS ...]]'
+ Run a subprocess (filter). *Note Exec::.
+
+`flow [FSTATE]'
+ Set flow control behavior. *Note Flow::.
+
+`gr [STATE]'
+ Change GR charset processing. *Note Character Processing::.
+
+`hardcopy'
+ Write out the contents of the current window. *Note Hardcopy::.
+
+`hardcopy_append STATE'
+ Append to hardcopy files. *Note Hardcopy::.
+
+`hardcopydir DIRECTORY'
+ Place, where to dump hardcopy files. *Note Hardcopy::.
+
+`hardstatus [STATE]'
+ Use the hardware status line. *Note Hardware Status Line::.
+
+`height [LINES]'
+ Set display height. *Note Window Size::.
+
+`help'
+ Display current key bindings. *Note Help::.
+
+`history'
+ Find previous command beginning .... *Note History::.
+
+`info'
+ Display terminal settings. *Note Info::.
+
+`ins_reg [KEY]'
+ Removed, use `paste' instead. *Note Registers::.
+
+`kanji WTYPE [DTYPE]'
+ Set the kanji type of a window. *Note Character Processing::.
+
+`kill'
+ Destroy the current window. *Note Kill::.
+
+`lastmsg'
+ Redisplay the last message. *Note Last Message::.
+
+`license'
+ Display licensing information. *Note Startup::.
+
+`lockscreen'
+ Lock the controlling terminal. *Note Lock::.
+
+`log [STATE]'
+ Log all output in the current window. *Note Log::.
+
+`logfile FILENAME'
+ Place where to collect logfiles. *Note Log::.
+
+`login [STATE]'
+ Log the window in `/etc/utmp'. *Note Login::.
+
+`mapdefault'
+ Use only the default mapping table for the next keystroke. *Note
+ Bindkey Control::.
+
+`mapnotnext'
+ Don't try to do keymapping on the next keystroke. *Note Bindkey
+ Control::.
+
+`maptimeout TIMO'
+ Set the intercharacter timeout used for keymapping. *Note Bindkey
+ Control::.
+
+`markkeys STRING'
+ Rebind keys in copy mode. *Note Copy Mode Keys::.
+
+`meta'
+ Insert the command character. *Note Command Character::.
+
+`monitor [STATE]'
+ Monitor activity in window. *Note Monitor::.
+
+`msgminwait SEC'
+ Set minimum message wait. *Note Message Wait::.
+
+`msgwait SEC'
+ Set default message wait. *Note Message Wait::.
+
+`multiuser STATE'
+ Go into single or multi user mode. *Note Multiuser Session::.
+
+`nethack STATE'
+ Use `nethack'-like error messages. *Note Nethack::.
+
+`next'
+ Switch to the next window. *Note Selecting::.
+
+`number [N]'
+ Change/display the current window's number. *Note Number::.
+
+`obuflimit [LIMIT]'
+ Select output buffer limit. *Note Obuflimit::.
+
+`other'
+ Switch to the window you were in last. *Note Selecting::.
+
+`partial STATE'
+ Set window to partial refresh. *Note Redisplay::.
+
+`password [CRYPTED_PW]'
+ Set reattach password. *Note Detach::.
+
+`paste [SRC_REGS [DEST_REG]]'
+ Paste contents of paste buffer or registers somewhere. *Note
+ Paste::.
+
+`pastefont [STATE]'
+ Include font information in the paste buffer. *Note Paste::.
+
+`pow_break'
+ Close and Reopen the window's terminal. *Note Break::.
+
+`pow_detach'
+ Detach and hang up. *Note Power Detach::.
+
+`pow_detach_msg [MESSAGE]'
+ Set message displayed on `pow_detach'. *Note Power Detach::.
+
+`prev'
+ Switch to the previous window. *Note Selecting::.
+
+`printcmd [CMD]'
+ Set a command for VT100 printer port emulation. *Note Printcmd::.
+
+`process [KEY]'
+ Treat a register as input to `screen'. *Note Registers::.
+
+`quit'
+ Kill all windows and exit. *Note Quit::.
+
+`readbuf'
+ Read the paste buffer from the screen-exchange file. *Note
+ Screen-Exchange::.
+
+`readreg [REG [FILE]]'
+ Load a register from paste buffer or file. *Note Registers::.
+
+`redisplay'
+ Redisplay the current window. *Note Redisplay::.
+
+`register KEY STRING'
+ Store a string to a register. *Note Registers::.
+
+`removebuf'
+ Delete the screen-exchange file. *Note Screen-Exchange::.
+
+`reset'
+ Reset the terminal settings for the window. *Note Reset::.
+
+`screen [OPTS] [N] [CMD [ARGS]]'
+ Create a new window. *Note Screen Command::.
+
+`scrollback NUM'
+ Set size of scrollback buffer. *Note Scrollback::.
+
+`select [N]'
+ Switch to a specified window. *Note Selecting::.
+
+`sessionname [NAME]'
+ Name this session. *Note Session Name::.
+
+`setenv [VAR [STRING]]'
+ Set an environment variable for new windows. *Note Setenv::.
+
+`shell COMMAND'
+ Set the default program for new windows. *Note Shell::.
+
+`shelltitle TITLE'
+ Set the default name for new windows. *Note Shell::.
+
+`silence [STATE|SECONDS]'
+ Monitor a window for inactivity. *Note Silence::.
+
+`silencewait SECONDS'
+ Default timeout to trigger an inactivity notify. *Note Silence::.
+
+`sleep NUM'
+ Pause during startup. *Note Startup::.
+
+`slowpaste MSEC'
+ Slow down pasting in windows. *Note Paste::.
+
+`sorendition [ATTR [COLOR]]'
+ Change text highlighting. *Note Sorendition::.
+
+`startup_message STATE'
+ Display copyright notice on startup. *Note Startup::.
+
+`stuff STRING'
+ Stuff a string in the input buffer of a window. *Note Paste::.
+
+`suspend'
+ Put session in background. *Note Suspend::.
+
+`term TERM'
+ Set `$TERM' for new windows. *Note Term::.
+
+`termcap TERM TERMINAL-TWEAKS [WINDOW-TWEAKS]'
+ Tweak termcap entries for best performance. *Note Termcap
+ Syntax::.
+
+`terminfo TERM TERMINAL-TWEAKS [WINDOW-TWEAKS]'
+ Ditto, for terminfo systems. *Note Termcap Syntax::.
+
+`termcapinfo TERM TERMINAL-TWEAKS [WINDOW-TWEAKS]'
+ Ditto, for both systems. *Note Termcap Syntax::.
+
+`time'
+ Display time and load average. *Note Time::.
+
+`title [WINDOWTITLE]'
+ Set the name of the current window. *Note Title Command::.
+
+`unsetenv VAR'
+ Unset environment variable for new windows. *Note Setenv::.
+
+`vbell [STATE]'
+ Use visual bell. *Note Bell::.
+
+`vbell_msg [MESSAGE]'
+ Set vbell message. *Note Bell::.
+
+`vbellwait SEC'
+ Set delay for vbell message. *Note Bell::.
+
+`version'
+ Display `screen' version. *Note Version::.
+
+`wall MESSAGE'
+ Write a message to all displays. *Note Multiuser Session::.
+
+`width [NUM]'
+ Set the width of the window. *Note Window Size::.
+
+`windows'
+ List active windows. *Note Windows::.
+
+`wrap [STATE]'
+ Control line-wrap behavior. *Note Wrap::.
+
+`writebuf'
+ Write paste buffer to screen-exchange file. *Note
+ Screen-Exchange::.
+
+`writelock ON|OFF|AUTO'
+ Grant exclusive write permission. *Note Multiuser Session::.
+
+`xoff'
+ Send an XOFF character. *Note XON/XOFF::.
+
+`xon'
+ Send an XON character. *Note XON/XOFF::.
+
+`zombie [KEYS]'
+ Keep dead windows. *Note Zombie::.
+
+
+File: screen.info, Node: New Window, Next: Selecting, Prev: Commands, Up: Top
+
+New Window
+**********
+
+ This section describes the commands for creating a new window for
+running programs. When a new window is created, the first available
+number from the range 0...9 is assigned to it. There can be no more
+than 10 windows active at any one time unless `screen' was compiled
+with a higher MAXWIN setting.
+
+* Menu:
+
+* Chdir:: Change the working directory for new windows.
+* Screen Command:: Create a new window.
+* Setenv:: Set environment variables for new windows.
+* Shell:: Parameters for shell windows.
+* Term:: Set the terminal type for new windows.
+
+
+File: screen.info, Node: Chdir, Next: Screen Command, Up: New Window
+
+Chdir
+=====
+
+ - Command: chdir [DIRECTORY]
+ (none)
+ Change the current directory of `screen' to the specified directory
+ or, if called without an argument, to your home directory (the
+ value of the environment variable `$HOME'). All windows that are
+ created by means of the `screen' command from within `.screenrc'
+ or by means of `C-a : screen ...' or `C-a c' use this as their
+ default directory. Without a `chdir' command, this would be the
+ directory from which `screen' was invoked. Hardcopy and log files
+ are always written to the *window's* default directory, *not* the
+ current directory of the process running in the window. You can
+ use this command multiple times in your `.screenrc' to start
+ various windows in different default directories, but the last
+ `chdir' value will affect all the windows you create interactively.
+
+
+File: screen.info, Node: Screen Command, Next: Setenv, Prev: Chdir, Up: New Window
+
+Screen Command
+==============
+
+ - Command: screen [OPTS] [N] [CMD [ARGS]]
+ (`C-a c', `C-a C-c')
+ Establish a new window. The flow-control options (`-f', `-fn' and
+ `-fa'), title option (`-t'), login options (`-l' and `-ln') ,
+ terminal type option (`-T TERM') and scrollback option (`-h NUM')
+ may be specified for each command. If an optional number N in the
+ range 0...9 is given, the window number N is assigned to the newly
+ created window (or, if this number is already in-use, the next
+ available number). If a command is specified after `screen', this
+ command (with the given arguments) is started in the window;
+ otherwise, a shell is created.
+
+ If a tty (character special device) name (e.g. `/dev/ttyS0') is
+ specified as cmd, then the window is directly connected to this
+ device. This is similar to the cmd `kermit -l /dev/ttyS0 -c' but
+ saves resources and is more efficient.
+
+ Thus, if your `.screenrc' contains the lines
+
+ # example for .screenrc:
+ screen 1
+ screen -fn -t foobar 2 telnet foobar
+
+`screen' creates a shell window (in window #1) and a window with a
+TELNET connection to the machine foobar (with no flow-control using the
+title `foobar' in window #2). If you do not include any `screen'
+commands in your `.screenrc' file, then `screen' defaults to creating a
+single shell window, number zero. When the initialization is
+completed, `screen' switches to the last window specified in your
+.screenrc file or, if none, it opens default window #0.
+
+
+File: screen.info, Node: Setenv, Next: Shell, Prev: Screen Command, Up: New Window
+
+Setenv
+======
+
+ - Command: setenv VAR STRING
+ (none)
+ Set the environment variable VAR to value STRING. If only VAR is
+ specified, the user will be prompted to enter a value. If no
+ parameters are specified, the user will be prompted for both
+ variable and value. The environment is inherited by all
+ subsequently forked shells.
+
+ - Command: unsetenv VAR
+ (none)
+ Unset an environment variable.
+
+
+File: screen.info, Node: Shell, Next: Term, Prev: Setenv, Up: New Window
+
+Shell
+=====
+
+ - Command: shell COMMAND
+ (none)
+ Set the command to be used to create a new shell. This overrides
+ the value of the environment variable `$SHELL'. This is useful if
+ you'd like to run a tty-enhancer which is expecting to execute the
+ program specified in `$SHELL'. If the command begins with a `-'
+ character, the shell will be started as a login-shell.
+
+ - Command: shelltitle TITLE
+ (none)
+ Set the title for all shells created during startup or by the C-a
+ C-c command. *Note Naming Windows::, for details about what
+ titles are.
+
+
+File: screen.info, Node: Term, Prev: Shell, Up: New Window
+
+Term
+====
+
+ - Command: term TERM
+ (none)
+ In each window `screen' opens, it sets the `$TERM' variable to
+ `screen' by default, unless no description for `screen' is
+ installed in the local termcap or terminfo data base. In that
+ case it pretends that the terminal emulator is `vt100'. This
+ won't do much harm, as `screen' is VT100/ANSI compatible. The use
+ of the `term' command is discouraged for non-default purpose.
+ That is, one may want to specify special `$TERM' settings (e.g.
+ vt100) for the next `screen rlogin othermachine' command. Use the
+ command `screen -T vt100 rlogin othermachine' rather than setting
+ and resetting the default.
+
+
+File: screen.info, Node: Selecting, Next: Session Management, Prev: New Window, Up: Top
+
+Selecting a Window
+******************
+
+ This section describes the commands for switching between windows in
+an `screen' session. The windows are numbered from 0 to 9, and are
+created in that order by default (*note New Window::.).
+
+* Menu:
+
+* Next and Previous:: Forward or back one window.
+* Other Window:: Switch back and forth between two windows.
+* Select:: Specify a particular window.
+
+
+File: screen.info, Node: Next and Previous, Next: Other Window, Up: Selecting
+
+Moving Back and Forth
+=====================
+
+ - Command: next
+ (`C-a SPC', `C-a n', `C-a C-n')
+ Switch to the next window. This command can be used repeatedly to
+ cycle through the list of windows. (On some terminals, C-SPC
+ generates a NUL character, so you must release the control key
+ before pressing space.)
+
+ - Command: prev
+ (`C-a p', `C-a C-p')
+ Switch to the previous window (the opposite of `C-a n').
+
+
+File: screen.info, Node: Other Window, Next: Select, Prev: Next and Previous, Up: Selecting
+
+Other Window
+============
+
+ - Command: other
+ (`C-a C-a')
+ Switch to the last window displayed. Note that this command
+ defaults to the command character typed twice, unless overridden.
+ For instance, if you use the option `-e]x', this command becomes
+ `]]' (*note Command Character::.).
+
+
+File: screen.info, Node: Select, Prev: Other Window, Up: Selecting
+
+Select
+======
+
+ - Command: select [N]
+ (`C-a N', `C-a '', `C-a "')
+ Switch to the window with the number N. If no window number is
+ specified, you get prompted for an identifier. This can be a
+ window name (title) or a number. When a new window is
+ established, the lowest available number is assigned to this
+ window. Thus, the first window can be activated by `select 0';
+ there can be no more than 10 windows present simultaneously
+ (unless screen is compiled with a higher MAXWIN setting).
+
+
+File: screen.info, Node: Session Management, Next: Window Settings, Prev: Selecting, Up: Top
+
+Session Management Commands
+***************************
+
+ Perhaps the most useful feature of `screen' is the way it allows the
+user to move a session between terminals, by detaching and reattaching.
+This also makes life easier for modem users who have to deal with
+unexpected loss of carrier.
+
+* Menu:
+
+* Detach:: Disconnect `screen' from your terminal.
+* Power Detach:: Detach and log out.
+* Lock:: Lock your terminal temporarily.
+* Multiuser Session:: Changing number of allowed users.
+* Session Name:: Rename your session for later reattachment.
+* Suspend:: Suspend your session.
+* Quit:: Terminate your session.
+
+
+File: screen.info, Node: Detach, Next: Power Detach, Up: Session Management
+
+Detach
+======
+
+ - Command: autodetach STATE
+ (none)
+ Sets whether `screen' will automatically detach upon hangup, which
+ saves all your running programs until they are resumed with a
+ `screen -r' command. When turned off, a hangup signal will
+ terminate `screen' and all the processes it contains. Autodetach is
+ on by default.
+
+ - Command: detach
+ (`C-a d', `C-a C-d')
+ Detach the `screen' session (disconnect it from the terminal and
+ put it into the background). A detached `screen' can be resumed by
+ invoking `screen' with the `-r' option. (*note Invoking Screen::.)
+
+ - Command: password [CRYPTED_PW]
+ (none)
+ Present a crypted password in your `.screenrc' file and screen will
+ ask for it, whenever someone attempts to resume a detached
+ session. This is useful, if you have privileged programs running
+ under `screen' and you want to protect your session from reattach
+ attempts by users that managed to assume your uid. (I.e. any
+ superuser.) If no crypted password is specified, screen prompts
+ twice a password and places its encryption in the paste buffer.
+ Default is `none', which disables password checking.
+
+
+File: screen.info, Node: Power Detach, Next: Lock, Prev: Detach, Up: Session Management
+
+Power Detach
+============
+
+ - Command: pow_detach
+ (`C-a D')
+ Mainly the same as `detach', but also sends a HANGUP signal to the
+ parent process of `screen'.
+ *Caution*: This will result in a logout if `screen' was started
+ from your login shell.
+
+ - Command: pow_detach_msg [MESSAGE]
+ (none)
+ The MESSAGE specified here is output whenever a power detach is
+ performed. It may be used as a replacement for a logout message or
+ to reset baud rate, etc. Without parameter, the current message
+ is shown.
+
+
+File: screen.info, Node: Lock, Next: Multiuser Session, Prev: Power Detach, Up: Session Management
+
+Lock
+====
+
+ - Command: lockscreen
+ (`C-a x', `C-a C-x')
+ Call a screenlock program (`/local/bin/lck' or `/usr/bin/lock' or
+ a builtin, if no other is available). Screen does not accept any
+ command keys until this program terminates. Meanwhile processes in
+ the windows may continue, as the windows are in the detached state.
+ The screenlock program may be changed through the environment
+ variable `$LOCKPRG' (which must be set in the shell from which
+ `screen' is started) and is executed with the user's uid and gid.
+
+ Warning: When you leave other shells unlocked and have no password
+ set on `screen', the lock is void: One could easily re-attach from
+ an unlocked shell. This feature should rather be called
+ `lockterminal'.
+
+
+File: screen.info, Node: Multiuser Session, Next: Session Name, Prev: Lock, Up: Session Management
+
+Multiuser Session
+=================
+
+ These commands allow other users to gain access to one single
+`screen' session. When attaching to a multiuser `screen' the
+sessionname is specified as `username/sessionname' to the `-S' command
+line option. `Screen' must be compiled with multiuser support to
+enable features described here.
+
+* Menu:
+
+* Multiuser:: Enable / Disable multiuser mode.
+* Acladd:: Enable a specific user.
+* Aclchg:: Change a users permissions.
+* Acldel:: Disable a specific user.
+* Wall:: Write a message to all users.
+* Writelock:: Grant exclusive window access.
+
+
+File: screen.info, Node: Multiuser, Next: Acladd, Up: Multiuser Session
+
+Multiuser
+---------
+
+ - Command: multiuser STATE
+ (none)
+ Switch between single-user and multi-user mode. Standard screen
+ operation is single-user. In multi-user mode the commands
+ `acladd', `aclchg' and `acldel' can be used to enable (and
+ disable) other users accessing this `screen'.
+
+
+File: screen.info, Node: Acladd, Next: Aclchg, Prev: Multiuser, Up: Multiuser Session
+
+Acladd
+------
+
+ - Command: acladd USERNAMES
+ (none)
+ Enable users to fully access this screen session. USERNAMES can be
+ one user or a comma seperated list of users. This command enables
+ to attach to the `screen' session and performs the equivalent of
+ `aclchg USERNAMES +rwx "#?"'. To add a user with restricted access,
+ use the `aclchg' command below. Multi-user mode only.
+
+
+File: screen.info, Node: Aclchg, Next: Acldel, Prev: Acladd, Up: Multiuser Session
+
+Aclchg
+------
+
+ - Command: aclchg USERNAMES PERMBITS LIST
+ (none)
+ Change permissions for a comma seperated list of users.
+ Permission bits are represented as `r', `w' and `x'. Prefixing
+ `+' grants the permission, `-' removes it. The third parameter is
+ a comma seperated list of commands or windows (specified either by
+ number or title). The special list `#' refers to all windows, `?'
+ to all commands. If USERNAMES consists of a single `*', all known
+ users is affected. A command can be executed when the user has
+ the `x' bit for it. The user can type input to a window when he
+ has its `w' bit set and no other user obtains a writelock for this
+ window. Other bits are currently ignored. To withdraw the
+ writelock from another user in e.g. window 2: `aclchg USERNAME
+ -w+w 2'. To allow readonly access to the session: `aclchg USERNAME
+ -w "#"'. As soon as a user's name is known to screen, he can
+ attach to the session and (per default) has full permissions for
+ all command and windows. Execution permission for the acl
+ commands, `at' and others should also be removed or the user may
+ be able to regain write permission. Multi-user mode only.
+
+
+File: screen.info, Node: Acldel, Next: Wall, Prev: Aclchg, Up: Multiuser Session
+
+Acldel
+------
+
+ - Command: acldel USERNAME
+ (none)
+ Remove a user from screen's access control list. If currently
+ attached, all the user's displays are detached from the session.
+ He cannot attach again. Multi-user mode only.
+
+
+File: screen.info, Node: Wall, Next: Writelock, Prev: Acldel, Up: Multiuser Session
+
+Wall
+----
+
+ - Command: wall MESSAGE
+ (none)
+ Write a message to all displays. The message will appear in the
+ terminal's status line.
+
+
+File: screen.info, Node: Writelock, Prev: Wall, Up: Multiuser Session
+
+Writelock
+---------
+
+ - Command: writelock ON|OFF|AUTO
+ (none)
+ In addition to access control lists, not all users may be able to
+ write to the same window at once. Per default, writelock is in
+ `auto' mode and grants exclusive input permission to the user who
+ is the first to switch to the particular window. When he leaves
+ the window, other users may obtain the writelock (automatically).
+ The writelock of the current window is disabled by the command
+ `writelock off'. If the user issues the command `writelock on' he
+ keeps the exclusive write permission while switching to other
+ windows.
+
+ - Command: defwritelock ON|OFF|AUTO
+ (none)
+ Sets the default writelock behaviour for new windows. Initially
+ all windows will be created with automatic writelocks.
+
+
+File: screen.info, Node: Session Name, Next: Suspend, Prev: Multiuser Session, Up: Session Management
+
+Session Name
+============
+
+ - Command: sessionname [NAME]
+ (none)
+ Rename the current session. Note that for `screen -list' the name
+ shows up with the process-id prepended. If the argument NAME is
+ omitted, the name of this session is displayed.
+ *Caution*: The `$STY' environment variable still reflects the old
+ name. This may result in confusion. The default is constructed
+ from the tty and host names.
+
+
+File: screen.info, Node: Suspend, Next: Quit, Prev: Session Name, Up: Session Management
+
+Suspend
+=======
+
+ - Command: suspend
+ (`C-a z', `C-a C-z')
+ Suspend `screen'. The windows are in the detached state while
+ `screen' is suspended. This feature relies on the parent shell
+ being able to do job control.
+
+
+File: screen.info, Node: Quit, Prev: Suspend, Up: Session Management
+
+Quit
+====
+
+ - Command: quit
+ (`C-a C-\')
+ Kill all windows and terminate `screen'. Note that on VT100-style
+ terminals the keys `C-4' and `C-\' are identical. So be careful
+ not to type `C-a C-4' when selecting window no. 4. Use the empty
+ bind command (as in `bind "^\"') to remove a key binding (*note
+ Key Binding::.).
+
+
+File: screen.info, Node: Window Settings, Next: Virtual Terminal, Prev: Session Management, Up: Top
+
+Window Settings
+***************
+
+ These commands control the way `screen' treats individual windows in
+a session. *Note Virtual Terminal::, for commands to control the
+terminal emulation itself.
+
+* Menu:
+
+* Naming Windows:: Control the name of the window
+* Console:: See the host's console messages
+* Kill:: Destroy an unwanted window
+* Login:: Control `/etc/utmp' logging
+* Mode:: Control the file mode of the pty
+* Monitor:: Watch for activity in a window
+* Windows:: List the active windows
+* Hardstatus:: Set a window's hardstatus line
+
diff --git a/doc/screen.info-2 b/doc/screen.info-2
new file mode 100644
index 0000000..dfeec60
--- /dev/null
+++ b/doc/screen.info-2
@@ -0,0 +1,1255 @@
+This is Info file screen.info, produced by Makeinfo-1.55 from the input
+file ./screen.texinfo.
+
+ This file documents the `Screen' virtual terminal manager.
+
+ Copyright (c) 1993 Free Software Foundation, Inc.
+
+ Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+ Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+ Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by the Foundation.
+
+
+File: screen.info, Node: Naming Windows, Next: Console, Up: Window Settings
+
+Naming Windows (Titles)
+=======================
+
+ You can customize each window's name in the window display (viewed
+with the `windows' command (*note Windows::.) by setting it with one of
+the title commands. Normally the name displayed is the actual command
+name of the program created in the window. However, it is sometimes
+useful to distinguish various programs of the same name or to change
+the name on-the-fly to reflect the current state of the window.
+
+ The default name for all shell windows can be set with the
+`shelltitle' command (*note Shell::.). You can specify the name you
+want for a window with the `-t' option to the `screen' command when the
+window is created (*note Screen Command::.). To change the name after
+the window has been created you can use the title-string escape-sequence
+(`ESC k NAME ESC \') and the `title' command (C-a A). The former can
+be output from an application to control the window's name under
+software control, and the latter will prompt for a name when typed.
+You can also bind predefined names to keys with the `title' command to
+set things quickly without prompting.
+
+* Menu:
+
+* Title Command:: The `title' command.
+* Dynamic Titles:: Make shell windows change titles dynamically.
+* Title Prompts:: Set up your shell prompt for dynamic Titles.
+* Title Screenrc:: Set up Titles in your `.screenrc'.
+
+
+File: screen.info, Node: Title Command, Next: Dynamic Titles, Up: Naming Windows
+
+Title Command
+-------------
+
+ - Command: title [WINDOWTITLE]
+ (`C-a A')
+ Set the name of the current window to WINDOWALIAS. If no name is
+ specified, screen prompts for one.
+
+
+File: screen.info, Node: Dynamic Titles, Next: Title Prompts, Prev: Title Command, Up: Naming Windows
+
+Dynamic Titles
+--------------
+
+ `screen' has a shell-specific heuristic that is enabled by setting
+the window's name to SEARCH|NAME and arranging to have a null title
+escape-sequence output as a part of your prompt. The SEARCH portion
+specifies an end-of-prompt search string, while the NAME portion
+specifies the default shell name for the window. If the NAME ends in a
+`:' `screen' will add what it believes to be the current command
+running in the window to the end of the specified name (e.g. NAME:CMD).
+Otherwise the current command name supersedes the shell name while it
+is running.
+
+ Here's how it works: you must modify your shell prompt to output a
+null title-escape-sequence (ESC k ESC \) as a part of your prompt. The
+last part of your prompt must be the same as the string you specified
+for the SEARCH portion of the title. Once this is set up, `screen'
+will use the title-escape-sequence to clear the previous command name
+and get ready for the next command. Then, when a newline is received
+from the shell, a search is made for the end of the prompt. If found,
+it will grab the first word after the matched string and use it as the
+command name. If the command name begins with `!', `%', or `^',
+`screen' will use the first word on the following line (if found) in
+preference to the just-found name. This helps csh users get more
+accurate titles when using job control or history recall commands.
+
+
+File: screen.info, Node: Title Prompts, Next: Title Screenrc, Prev: Dynamic Titles, Up: Naming Windows
+
+Setting up your prompt for shell titles
+---------------------------------------
+
+ One thing to keep in mind when adding a null title-escape-sequence
+to your prompt is that some shells (like the csh) count all the
+non-control characters as part of the prompt's length. If these
+invisible characters aren't a multiple of 8 then backspacing over a tab
+will result in an incorrect display. One way to get around this is to
+use a prompt like this:
+
+ set prompt='k\% '
+
+ The escape-sequence `' not only normalizes the character
+attributes, but all the zeros round the length of the invisible
+characters up to 8.
+
+ Tcsh handles escape codes in the prompt more intelligently, so you
+can specify your prompt like this:
+
+ set prompt="%{\ek\e\\%}\% "
+
+ Bash users will probably want to echo the escape sequence in the
+PROMPT_COMMAND:
+
+ PROMPT_COMMAND='echo -n -e "\033k\033\134"'
+
+ (I used `\134' to output a `\' because of a bug in v1.04).
+
+
+File: screen.info, Node: Title Screenrc, Prev: Title Prompts, Up: Naming Windows
+
+Setting up shell titles in your `.screenrc'
+-------------------------------------------
+
+ Here are some .screenrc examples:
+
+ screen -t top 2 nice top
+
+ Adding this line to your .screenrc would start a niced version of the
+`top' command in window 2 named `top' rather than `nice'.
+
+ shelltitle '> |csh'
+ screen 1
+
+ This file would start a shell using the given shelltitle. The title
+specified is an auto-title that would expect the prompt and the typed
+command to look something like the following:
+
+ /usr/joe/src/dir> trn
+
+ (it looks after the '> ' for the command name). The window status
+would show the name `trn' while the command was running, and revert to
+`csh' upon completion.
+
+ bind R screen -t '% |root:' su
+
+ Having this command in your .screenrc would bind the key sequence
+`C-a R' to the `su' command and give it an auto-title name of `root:'.
+For this auto-title to work, the screen could look something like this:
+
+ % !em
+ emacs file.c
+
+ Here the user typed the csh history command `!em' which ran the
+previously entered `emacs' command. The window status would show
+`root:emacs' during the execution of the command, and revert to simply
+`root:' at its completion.
+
+ bind o title
+ bind E title ""
+ bind u title (unknown)
+
+ The first binding doesn't have any arguments, so it would prompt you
+for a title when you type `C-a o'. The second binding would clear an
+auto-titles current setting (C-a E). The third binding would set the
+current window's title to `(unknown)' (C-a u).
+
+
+File: screen.info, Node: Console, Next: Kill, Prev: Naming Windows, Up: Window Settings
+
+Console
+=======
+
+ - Command: console [STATE]
+ (none)
+ Grabs or ungrabs the machines console output to a window. When the
+ argument is omitted the current state is displayed. *Note*: Only
+ the owner of `/dev/console' can grab the console output. This
+ command is only available if the host supports the ioctl
+ `TIOCCONS'.
+
+
+File: screen.info, Node: Kill, Next: Login, Prev: Console, Up: Window Settings
+
+Kill
+====
+
+ - Command: kill
+ (`C-a k', `C-a C-k')
+ Kill the current window.
+ If there is an `exec' command running (*note Exec::.) then it is
+ killed. Otherwise the process (e.g. shell) running in the window
+ receives a `HANGUP' condition, the window structure is removed and
+ screen switches to the previously displayed window. When the last
+ window is destroyed, `screen' exits.
+ *Caution*: `emacs' users may find themselves killing their `emacs'
+ session when trying to delete the current line. For this reason,
+ it is probably wise to use a different command character (*note
+ Command Character::.) or rebind `kill' to another key sequence,
+ such as `C-a K' (*note Key Binding::.).
+
+
+File: screen.info, Node: Login, Next: Mode, Prev: Kill, Up: Window Settings
+
+Login
+=====
+
+ - Command: deflogin STATE
+ (none)
+ Same as the `login' command except that the default setting for new
+ windows is changed. This defaults to `on' unless otherwise
+ specified at compile time (*note Installation::.). Both commands
+ are only present when `screen' has been compiled with utmp support.
+
+ - Command: login [STATE]
+ (`C-a L')
+ Adds or removes the entry in `/etc/utmp' for the current window.
+ This controls whether or not the window is "logged in". In
+ addition to this toggle, it is convenient to have "log in" and
+ "log out" keys. For instance, `bind I login on' and `bind O login
+ off' will map these keys to be `C-a I' and `C-a O' (*note Key
+ Binding::.).
+
+
+File: screen.info, Node: Mode, Next: Monitor, Prev: Login, Up: Window Settings
+
+Mode
+====
+
+ - Command: defmode MODE
+ (none)
+ The mode of each newly allocated pseudo-tty is set to MODE. MODE
+ is an octal number as used by chmod(1). Defaults to 0622 for
+ windows which are logged in, 0600 for others (e.g. when `-ln' was
+ specified for creation. *Note Screen Command::).
+
+
+File: screen.info, Node: Monitor, Next: Windows, Prev: Mode, Up: Window Settings
+
+Monitoring
+==========
+
+ - Command: activity MESSAGE
+ (none)
+ When any activity occurs in a background window that is being
+ monitored, `screen' displays a notification in the message line.
+ The notification message can be redefined by means of the
+ `activity' command. Each occurrence of `%' in MESSAGE is replaced
+ by the number of the window in which activity has occurred, and
+ each occurrence of `~' is replaced by the definition for bell in
+ your termcap (usually an audible bell). The default message is
+
+ 'Activity in window %'
+
+ Note that monitoring is off for all windows by default, but can be
+ altered by use of the `monitor' command (`C-a M').
+
+ - Command: defmonitor STATE
+ (none)
+ Same as the `monitor' command except that the default setting for
+ new windows is changed. Initial setting is `off'.
+
+ - Command: monitor [STATE]
+ (`C-a M')
+ Toggles monitoring of the current window. When monitoring is
+ turned on and the affected window is switched into the background,
+ the activity notification message will be displayed in the status
+ line at the first sign of output, and the window will also be
+ marked with an `@' in the window-status display (*note
+ Windows::.). Monitoring defaults to `off' for all windows.
+
+
+File: screen.info, Node: Windows, Next: Hardstatus, Prev: Monitor, Up: Window Settings
+
+Windows
+=======
+
+ - Command: windows
+ (`C-a w', `C-a C-w')
+ Uses the message line to display a list of all the windows. Each
+ window is listed by number with the name of the program running in
+ the window (or its title); the current window is marked with a `*';
+ the previous window is marked with a `-'; all the windows that are
+ logged in are marked with a `$' (*note Login::.); a background
+ window that has received a bell is marked with a `!'; a background
+ window that is being monitored and has had activity occur is
+ marked with an `@' (*note Monitor::.); a window which has output
+ logging turned on is marked with `(L)'; windows occupied by other
+ users are marked with `&'; windows in the zombie state are marked
+ with `Z'. If this list is too long to fit on the terminal's
+ status line only the portion around the current window is
+ displayed.
+
+
+File: screen.info, Node: Hardstatus, Prev: Windows, Up: Window Settings
+
+Hardstatus
+==========
+
+ `Screen' maintains a hardstatus line for every window. If a window
+gets selected, the display's hardstatus will be updated to match the
+window's hardstatus line. If the display has no hardstatus the line
+will be displayed as a standard screen message. The hardstatus line
+can be changed with the ANSI Application Program Command (APC):
+`ESC_<string>ESC\'. As a convenience for xterm users the sequence
+`ESC]0..2;<string>^G' is also accepted.
+
+ - Command: defhstatus
+ (none)
+ The hardstatus line that all new windows will get is set to STATUS.
+ This command is useful to make the hardstatus of every window
+ display the window number or title or the like. STATUS may
+ contain the same directives as in the window messages, but the
+ directive escape character is `^E' (octal 005) instead of `%'.
+ This was done to make a misinterpretion of program generated
+ hardstatus lines impossible. If the parameter STATUS is omitted,
+ the current default string is displayed. Per default the
+ hardstatus line of new windows is empty.
+
+
+File: screen.info, Node: Virtual Terminal, Next: Copy and Paste, Prev: Window Settings, Up: Top
+
+Virtual Terminal
+****************
+
+ Each window in a `screen' session emulates a VT100 terminal, with
+some extra functions added. The VT100 emulator is hardcoded, no other
+terminal types can be emulated. The commands described here modify the
+terminal emulation.
+
+* Menu:
+
+* Control Sequences:: Details of the internal VT100 emulation.
+* Input Translation:: How keystrokes are remapped.
+* Digraph:: Entering digraph sequences.
+* Bell:: Getting your attention.
+* Clear:: Clear the window display.
+* Info:: Terminal emulation statistics.
+* Redisplay:: When the display gets confusing.
+* Wrap:: Automatic margins.
+* Reset:: Recovering from ill-behaved applications.
+* Window Size:: Changing the size of your terminal.
+* Character Processing:: Change the effect of special characters.
+
+
+File: screen.info, Node: Control Sequences, Next: Input Translation, Up: Virtual Terminal
+
+Control Sequences
+=================
+
+ The following is a list of control sequences recognized by `screen'.
+`(V)' and `(A)' indicate VT100-specific and ANSI- or ISO-specific
+functions, respectively.
+
+ ESC E Next Line
+ ESC D Index
+ ESC M Reverse Index
+ ESC H Horizontal Tab Set
+ ESC Z Send VT100 Identification String
+ ESC 7 (V) Save Cursor and Attributes
+ ESC 8 (V) Restore Cursor and Attributes
+ ESC [s (A) Save Cursor and Attributes
+ ESC [u (A) Restore Cursor and Attributes
+ ESC c Reset to Initial State
+ ESC g Visual Bell
+ ESC Pn p Cursor Visibility (97801)
+ Pn = 6 Invisible
+ 7 Visible
+ ESC = (V) Application Keypad Mode
+ ESC > (V) Numeric Keypad Mode
+ ESC # 8 (V) Fill Screen with E's
+ ESC \ (A) String Terminator
+ ESC ^ (A) Privacy Message String (Message Line)
+ ESC ! Global Message String (Message Line)
+ ESC k Title Definition String
+ ESC P (A) Device Control String
+ Outputs a string directly to the host
+ terminal without interpretation.
+ ESC _ (A) Application Program Command (Hardstatus)
+ ESC ] (A) Operating System Command (Hardstatus, xterm
+ title hack)
+ Control-N (A) Lock Shift G1 (SO)
+ Control-O (A) Lock Shift G0 (SI)
+ ESC n (A) Lock Shift G2
+ ESC o (A) Lock Shift G3
+ ESC N (A) Single Shift G2
+ ESC O (A) Single Shift G3
+ ESC ( Pcs (A) Designate character set as G0
+ ESC ) Pcs (A) Designate character set as G1
+ ESC * Pcs (A) Designate character set as G2
+ ESC + Pcs (A) Designate character set as G3
+ ESC [ Pn ; Pn H Direct Cursor Addressing
+ ESC [ Pn ; Pn f Direct Cursor Addressing
+ ESC [ Pn J Erase in Display
+ Pn = None or 0 From Cursor to End of Screen
+ 1 From Beginning of Screen to Cursor
+ 2 Entire Screen
+ ESC [ Pn K Erase in Line
+ Pn = None or 0 From Cursor to End of Line
+ 1 From Beginning of Line to Cursor
+ 2 Entire Line
+ ESC [ Pn A Cursor Up
+ ESC [ Pn B Cursor Down
+ ESC [ Pn C Cursor Right
+ ESC [ Pn D Cursor Left
+ ESC [ Ps ;...; Ps m Select Graphic Rendition
+ Ps = None or 0 Default Rendition
+ 1 Bold
+ 2 (A) Faint
+ 3 (A) Standout Mode (ANSI: Italicized)
+ 4 Underlined
+ 5 Blinking
+ 7 Negative Image
+ 22 (A) Normal Intensity
+ 23 (A) Standout Mode off (ANSI: Italicized off)
+ 24 (A) Not Underlined
+ 25 (A) Not Blinking
+ 27 (A) Positive Image
+ 30 (A) Foreground Black
+ 31 (A) Foreground Red
+ 32 (A) Foreground Green
+ 33 (A) Foreground Yellow
+ 34 (A) Foreground Blue
+ 35 (A) Foreground Magenta
+ 36 (A) Foreground Cyan
+ 37 (A) Foreground White
+ 39 (A) Foreground Default
+ 40 (A) Background Black
+ ... ...
+ 49 (A) Background Default
+ ESC [ Pn g Tab Clear
+ Pn = None or 0 Clear Tab at Current Position
+ 3 Clear All Tabs
+ ESC [ Pn ; Pn r (V) Set Scrolling Region
+ ESC [ Pn I (A) Horizontal Tab
+ ESC [ Pn Z (A) Backward Tab
+ ESC [ Pn L (A) Insert Line
+ ESC [ Pn M (A) Delete Line
+ ESC [ Pn @ (A) Insert Character
+ ESC [ Pn P (A) Delete Character
+ ESC [ Pn S Scroll Scrolling Region Up
+ ESC [ Pn T Scroll Scrolling Region Down
+ ESC [ Ps ;...; Ps h Set Mode
+ ESC [ Ps ;...; Ps l Reset Mode
+ Ps = 4 (A) Insert Mode
+ 20 (A) `Automatic Linefeed' Mode.
+ 34 Normal Cursor Visibility
+ ?1 (V) Application Cursor Keys
+ ?3 (V) Change Terminal Width to 132 columns
+ ?5 (V) Reverse Video
+ ?6 (V) `Origin' Mode
+ ?7 (V) `Wrap' Mode
+ ?25 (V) Visible Cursor
+ ESC [ 5 i (A) Start relay to printer (ANSI Media Copy)
+ ESC [ 4 i (A) Stop relay to printer (ANSI Media Copy)
+ ESC [ 8 ; Ph ; Pw t Resize the window to `Ph' lines and
+ `Pw' columns (SunView special)
+ ESC [ c Send VT100 Identification String
+ ESC [ x (V) Send Terminal Parameter Report
+ ESC [ > c Send Secondary Device Attributes String
+ ESC [ 6 n Send Cursor Position Report
+
+
+File: screen.info, Node: Input Translation, Next: Digraph, Prev: Control Sequences, Up: Virtual Terminal
+
+Input Translation
+=================
+
+ In order to do a full VT100 emulation `screen' has to detect that a
+sequence of characters in the input stream was generated by a keypress
+on the user's keyboard and insert the VT100 style escape sequence.
+`Screen' has a very flexible way of doing this by making it possible to
+map arbitrary commands on arbitrary sequences of characters. For
+standard VT100 emulation the command will always insert a string in the
+input buffer of the window (see also command `stuff', *note Paste::.).
+Because the sequences generated by a keypress can change after a
+reattach from a different terminal type, it is possible to bind
+commands to the termcap name of the keys. `Screen' will insert the
+correct binding after each reattach. *Note Bindkey:: for further
+details on the syntax and examples.
+
+ Here is the table of the default key bindings. (A) means that the
+command is executed if the keyboard is switched into application mode.
+
+ Key name Termcap name Command
+ -----------------------------------------------------
+ Cursor up ku stuff \033[A
+ stuff \033OA (A)
+ Cursor down kd stuff \033[B
+ stuff \033OB (A)
+ Cursor right kr stuff \033[C
+ stuff \033OC (A)
+ Cursor left kl stuff \033[D
+ stuff \033OD (A)
+ Function key 0 k0 stuff \033[10~
+ Function key 1 k1 stuff \033OP
+ Function key 2 k2 stuff \033OQ
+ Function key 3 k3 stuff \033OR
+ Function key 4 k4 stuff \033OS
+ Function key 5 k5 stuff \033[15~
+ Function key 6 k6 stuff \033[17~
+ Function key 7 k7 stuff \033[18~
+ Function key 8 k8 stuff \033[19~
+ Function key 9 k9 stuff \033[20~
+ Function key 10 k; stuff \033[21~
+ Function key 11 F1 stuff \033[22~
+ Function key 12 F2 stuff \033[23~
+ Backspace kb stuff \010
+ Home kh stuff \033[1~
+ End kH stuff \033[4~
+ Insert kI stuff \033[2~
+ Delete kD stuff \033[3~
+ Page up kP stuff \033[5~
+ Page down kN stuff \033[6~
+ Keypad 0 f0 stuff 0
+ stuff \033Op (A)
+ Keypad 1 f1 stuff 1
+ stuff \033Oq (A)
+ Keypad 2 f2 stuff 2
+ stuff \033Or (A)
+ Keypad 3 f3 stuff 3
+ stuff \033Os (A)
+ Keypad 4 f4 stuff 4
+ stuff \033Ot (A)
+ Keypad 5 f5 stuff 5
+ stuff \033Ou (A)
+ Keypad 6 f6 stuff 6
+ stuff \033Ov (A)
+ Keypad 7 f7 stuff 7
+ stuff \033Ow (A)
+ Keypad 8 f8 stuff 8
+ stuff \033Ox (A)
+ Keypad 9 f9 stuff 9
+ stuff \033Oy (A)
+ Keypad + f+ stuff +
+ stuff \033Ok (A)
+ Keypad - f- stuff -
+ stuff \033Om (A)
+ Keypad * f* stuff *
+ stuff \033Oj (A)
+ Keypad / f/ stuff /
+ stuff \033Oo (A)
+ Keypad = fq stuff =
+ stuff \033OX (A)
+ Keypad . f. stuff .
+ stuff \033On (A)
+ Keypad , f, stuff ,
+ stuff \033Ol (A)
+ Keypad enter fe stuff \015
+ stuff \033OM (A)
+
+
+File: screen.info, Node: Digraph, Next: Bell, Prev: Input Translation, Up: Virtual Terminal
+
+Digraph
+=======
+
+ - Command: digraph [PRESET]
+ (none)
+ This command prompts the user for a digraph sequence. The next two
+ characters typed are looked up in a builtin table and the
+ resulting character is inserted in the input stream. For example,
+ if the user enters `a"', an a-umlaut will be inserted. If the
+ first character entered is a 0 (zero), `screen' will treat the
+ following charcters (up to three) as an octal number instead. The
+ optional argument PRESET is treated as user input, thus one can
+ create an "umlaut" key. For example the command `bindkey ^K
+ digraph '"'' enables the user to generate an a-umlaut by typing
+ `CTRL-K a'.
+
+
+File: screen.info, Node: Bell, Next: Clear, Prev: Digraph, Up: Virtual Terminal
+
+Bell
+====
+
+ - Command: bell_msg [MESSAGE]
+ (none)
+ When a bell character is sent to a background window, `screen'
+ displays a notification in the message line. The notification
+ message can be re-defined by means of the `bell' command. Each
+ occurrence of `%' in MESSAGE is replaced by the number of the
+ window to which a bell has been sent, and each occurrence of `~'
+ is replaced by the definition for bell in your termcap (usually an
+ audible bell). The default message is
+
+ 'Bell in window %'
+
+ An empty message can be supplied to the `bell_msg' command to
+ suppress output of a message line (`bell_msg ""').
+
+ - Command: vbell [STATE]
+ (`C-a C-g')
+ Sets or toggles the visual bell setting for the current window. If
+ `vbell' is switched to `on', but your terminal does not support a
+ visual bell, the visual bell message is displayed in the status
+ line when the bell character is received. Visual bell support of
+ a terminal is defined by the termcap variable `vb'. *Note Visual
+ Bell: (termcap)Bell, for more information on visual bells. The
+ equivalent terminfo capability is `flash'.
+
+ Per default, `vbell' is `off', thus the audible bell is used.
+
+ - Command: vbell_msg [MESSAGE]
+ (none)
+ Sets the visual bell message. MESSAGE is printed to the status
+ line if the window receives a bell character (^G), `vbell' is set
+ to `on' and the terminal does not support a visual bell. The
+ default message is `Wuff, Wuff!!'. Without parameter, the current
+ message is shown.
+
+ - Command: vbellwait SEC
+ (none)
+ Define a delay in seconds after each display of `screen' 's visual
+ bell message. The default is 1 second.
+
+
+File: screen.info, Node: Clear, Next: Info, Prev: Bell, Up: Virtual Terminal
+
+Clear
+=====
+
+ - Command: clear
+ (`C-a C')
+ Clears the screen and saves its contents to the scrollback buffer.
+
+
+File: screen.info, Node: Info, Next: Redisplay, Prev: Clear, Up: Virtual Terminal
+
+Info
+====
+
+ - Command: info
+ (`C-a i', `C-a C-i')
+ Uses the message line to display some information about the current
+ window: the cursor position in the form `(COLUMN,ROW)' starting
+ with `(1,1)', the terminal width and height plus the size of the
+ scrollback buffer in lines, like in `(80,24)+50', various flag
+ settings (flow-control, insert mode, origin mode, wrap mode,
+ application-keypad mode, output logging, activity monitoring, and
+ redraw (`+' indicates enabled, `-' not)), the currently active
+ character set (`G0', `G1', `G2', or `G3'), and in square brackets
+ the terminal character sets that are currently designated as `G0'
+ through `G3'. For system information use `time'.
+
+
+File: screen.info, Node: Redisplay, Next: Wrap, Prev: Info, Up: Virtual Terminal
+
+Redisplay
+=========
+
+ - Command: allpartial STATE
+ (none)
+ If set to on, only the current cursor line is refreshed on window
+ change. This affects all windows and is useful for slow terminal
+ lines. The previous setting of full/partial refresh for each
+ window is restored with `allpartial off'. This is a global flag
+ that immediately takes effect on all windows overriding the
+ `partial' settings. It does not change the default redraw
+ behaviour of newly created windows.
+
+ - Command: partial STATE
+ (none)
+ Defines whether the display should be refreshed (as with
+ `redisplay') after switching to the current window. This command
+ only affects the current window. To immediately affect all
+ windows use the `allpartial' command. Default is `off', of
+ course. This default is fixed, as there is currently no
+ `defpartial' command.
+
+ - Command: redisplay
+ (`C-a l', `C-a C-l')
+ Redisplay the current window. Needed to get a full redisplay in
+ partial redraw mode.
+
+
+File: screen.info, Node: Wrap, Next: Reset, Prev: Redisplay, Up: Virtual Terminal
+
+Wrap
+====
+
+ - Command: wrap STATE
+ (`C-a r', `C-a C-r')
+ Sets the line-wrap setting for the current window. When line-wrap
+ is on, the second consecutive printable character output at the
+ last column of a line will wrap to the start of the following
+ line. As an added feature, backspace (^H) will also wrap through
+ the left margin to the previous line. Default is `on'.
+
+ - Command: defwrap STATE
+ (none)
+ Same as the `wrap' command except that the default setting for new
+ windows is changed. Initially line-wrap is on and can be toggled
+ with the `wrap' command (`C-a r') or by means of "C-a : wrap
+ on|off".
+
+
+File: screen.info, Node: Reset, Next: Window Size, Prev: Wrap, Up: Virtual Terminal
+
+Reset
+=====
+
+ - Command: reset
+ (`C-a Z')
+ Reset the virtual terminal to its "power-on" values. Useful when
+ strange settings (like scroll regions or graphics character set)
+ are left over from an application.
+
+
+File: screen.info, Node: Window Size, Next: Character Processing, Prev: Reset, Up: Virtual Terminal
+
+Window Size
+===========
+
+ - Command: width [NUM]
+ (`C-a W')
+ Toggle the window width between 80 and 132 columns, or set it to
+ NUM columns if an argument is specified. This requires a capable
+ terminal and the termcap entries `Z0' and `Z1'. See the `termcap'
+ command (*note Termcap::.), for more information.
+
+ - Command: height [LINES]
+ (none)
+ Set the display height to a specified number of lines. When no
+ argument is given it toggles between 24 and 42 lines display.
+
+
+File: screen.info, Node: Character Processing, Prev: Window Size, Up: Virtual Terminal
+
+Character Processing
+====================
+
+ - Command: c1 [STATE]
+ (none)
+ Change c1 code processing. `c1 on' tells screen to treat the input
+ characters between 128 and 159 as control functions. Such an
+ 8-bit code is normally the same as ESC followed by the
+ corresponding 7-bit code. The default setting is to process c1
+ codes and can be changed with the `defc1' command. Users with
+ fonts that have usable characters in the c1 positions may want to
+ turn this off.
+
+
+ - Command: gr [STATE]
+ (none)
+ Turn GR charset switching on/off. Whenever screens sees an input
+ char with an 8th bit set, it will use the charset stored in the GR
+ slot and print the character with the 8th bit stripped. The
+ default (see also `defgr') is not to process GR switching because
+ otherwise the ISO88591 charset would not work.
+
+ - Command: kanji WTYPE [DTYPE]
+ (none)
+ Tell screen how to process kanji input/output. WTYPE and DTYPE
+ must be one of the strings `jis', `euc' or `sjis'. The first
+ argument sets the kanji type of the current window. Each window
+ can emulate a different type. The optional second parameter tells
+ screen how to write the kanji codes to the connected terminal. The
+ preferred method of setting the display type is to use the `KJ'
+ termcap entry. *Note Special Capabilities::. See also `defkanji',
+ which changes the default setting of a new window.
+
+ - Command: charset SET
+ (none)
+ Change the current character set slot designation and charset
+ mapping. The first four character of SET are treated as charset
+ designators while the fifth and sixth character must be in range
+ `0' to `3' and set the GL/GR charset mapping. On every position a
+ `.' may be used to indicate that the corresponding charset/mapping
+ should not be changed (SET is padded to six characters internally
+ by appending `.' chars). New windows have `BBBB02' as default
+ charset, unless a `kanji' command is active.
+
+ The current setting can be viewed with the *Note Info:: command.
+
+ - Command: defc1 STATE
+ (none)
+ Same as the `c1' command except that the default setting for new
+ windows is changed. Initial setting is `on'.
+
+ - Command: defgr STATE
+ (none)
+ Same as the `gr' command except that the default setting for new
+ windows is changed. Initial setting is `off'.
+
+ - Command: defkanji WTYPE
+ (none)
+ Same as the `kanji' command except that the default setting for
+ new windows is changed. Initial setting is `off', i.e. `jis'.
+
+ - Command: defcharset [SET]
+ Like the `charset' command except that the default setting for new
+ windows is changed. Shows current default if called without
+ argument.
+
+
+File: screen.info, Node: Copy and Paste, Next: Subprocess Execution, Prev: Virtual Terminal, Up: Top
+
+Copy and Paste
+**************
+
+ For those confined to a hardware terminal, these commands provide a
+cut and paste facility more powerful than those provided by most
+windowing systems.
+
+* Menu:
+
+* Copy:: Copy from scrollback to buffer
+* Paste:: Paste from buffer into window
+* Registers:: Longer-term storage
+* Screen-Exchange:: Sharing data between screen users
+* History:: Recalling previous input
+
+
+File: screen.info, Node: Copy, Next: Paste, Up: Copy and Paste
+
+Copying
+=======
+
+ - Command: copy
+ (`C-a [', `C-a C-[', `C-a ESC')
+ Enter copy/scrollback mode. This allows you to copy text from the
+ current window and its history into the paste buffer. In this mode
+ a `vi'-like full screen editor is active, with controls as
+ outlined below.
+
+* Menu:
+
+* Line Termination:: End copied lines with CR/LF
+* Scrollback:: Set the size of the scrollback buffer
+* Copy Mode Keys:: Remap keys in copy mode
+* Movement:: Move around in the scrollback buffer
+* Marking:: Select the text you want
+* Repeat count:: Repeat a command
+* Searching:: Find the text you want
+* Specials:: Other random keys
+
+
+File: screen.info, Node: Line Termination, Next: Scrollback, Up: Copy
+
+CR/LF
+-----
+
+ - Command: crlf [STATE]
+ (none)
+ This affects the copying of text regions with the `C-a [' command.
+ If it is set to `on', lines will be separated by the two character
+ sequence `CR'/`LF'. Otherwise only `LF' is used. `crlf' is off
+ by default. When no parameter is given, the state is toggled.
+
+
+File: screen.info, Node: Scrollback, Next: Copy Mode Keys, Prev: Line Termination, Up: Copy
+
+Scrollback
+----------
+
+ - Command: defscrollback NUM
+ (none)
+ Same as the `scrollback' command except that the default setting
+ for new windows is changed. Defaults to 100.
+
+ - Command: scrollback NUM
+ (none)
+ Set the size of the scrollback buffer for new windows to NUM
+ lines. The default scrollback is 100 lines. Use `C-a i' to view
+ the current setting.
+
+
+File: screen.info, Node: Copy Mode Keys, Next: Movement, Prev: Scrollback, Up: Copy
+
+markkeys
+--------
+
+ - Command: markkeys STRING
+ (none)
+ This is a method of changing the keymap used for copy/history
+ mode. The string is made up of OLDCHAR=NEWCHAR pairs which are
+ separated by `:'. Example: The command `markkeys h=^B:l=^F:$=^E'
+ would set some keys to be more familiar to `emacs' users. If your
+ terminal sends characters, that cause you to abort copy mode, then
+ this command may help by binding these characters to do nothing.
+ The no-op character is `' and is used like this: `markkeys @=L=H'
+ if you do not want to use the `H' or `L' commands any longer. As
+ shown in this example, multiple keys can be assigned to one
+ function in a single statement.
+
+
+File: screen.info, Node: Movement, Next: Marking, Prev: Copy Mode Keys, Up: Copy
+
+Movement Keys
+-------------
+
+`h', `j', `k', `l' move the cursor line by line or column by column.
+
+`0', `^' and `$' move to the leftmost column or to the first or last
+non-whitespace character on the line.
+
+`H', `M' and `L' move the cursor to the leftmost column of the top,
+center or bottom line of the window.
+
+`+' and `-' move the cursor to the leftmost column of the next or
+previous line.
+
+`G' moves to the specified absolute line (default: end of buffer).
+
+`|' moves to the specified absolute column.
+
+`w', `b', `e' move the cursor word by word.
+
+`C-u' and `C-d' scroll the display up/down by the specified amount of
+lines while preserving the cursor position. (Default: half screenfull).
+
+`C-b' and `C-f' move the cursor up/down a full screen.
+
+`g' moves to the beginning of the buffer.
+
+`%' jumps to the specified percentage of the buffer.
+
+ Note that Emacs-style movement keys can be specified by a .screenrc
+command. (`markkeys "h=^B:l=^F:$=^E"') There is no simple method for a
+full emacs-style keymap, however, as this involves multi-character
+codes.
+
+
+File: screen.info, Node: Marking, Next: Repeat count, Prev: Movement, Up: Copy
+
+Marking
+-------
+
+ The copy range is specified by setting two marks. The text between
+these marks will be highlighted. Press `space' to set the first or
+second mark respectively.
+
+`Y' and `y' can be used to mark one whole line or to mark from start of
+line.
+
+`W' marks exactly one word.
+
+
+File: screen.info, Node: Repeat count, Next: Searching, Prev: Marking, Up: Copy
+
+Repeat Count
+------------
+
+ Any command in copy mode can be prefixed with a number (by pressing
+digits `0...9') which is taken as a repeat count. Example: `C-a C-[ H
+10 j 5 Y' will copy lines 11 to 15 into the paste buffer.
+
+
+File: screen.info, Node: Searching, Next: Specials, Prev: Repeat count, Up: Copy
+
+Searching
+---------
+
+`/' `vi'-like search forward.
+
+`?' `vi'-like search backward.
+
+`C-a s' `emacs' style incremental search forward.
+
+`C-r' `emacs' style reverse i-search.
+
+
+File: screen.info, Node: Specials, Prev: Searching, Up: Copy
+
+Specials
+--------
+
+ There are, however, some keys that act differently here from in
+`vi'. `Vi' does not allow to yank rectangular blocks of text, but
+`screen' does. Press
+
+`c' or `C' to set the left or right margin respectively. If no repeat
+count is given, both default to the current cursor position.
+Example: Try this on a rather full text screen: `C-a [ M 20 l SPACE c
+10 l 5 j C SPACE'.
+
+This moves one to the middle line of the screen, moves in 20 columns
+left, marks the beginning of the paste buffer, sets the left column,
+moves 5 columns down, sets the right column, and then marks the end of
+the paste buffer. Now try:
+`C-a [ M 20 l SPACE 10 l 5 j SPACE'
+
+and notice the difference in the amount of text copied.
+
+`J' joins lines. It toggles between 3 modes: lines separated by a
+newline character (012), lines glued seamless, or lines separated by a
+single space. Note that you can prepend the newline character with a
+carriage return character, by issuing a `set crlf on'.
+
+`v' is for all the `vi' users who use `:set numbers' - it toggles the
+left margin between column 9 and 1.
+
+`a' before the final space key turns on append mode. Thus the contents
+of the paste buffer will not be overwritten, but appended to.
+
+`A' turns on append mode and sets a (second) mark.
+
+`>' sets the (second) mark and writes the contents of the paste buffer
+to the screen-exchange file (`/tmp/screen-exchange' per default) once
+copy-mode is finished. *Note Screen-Exchange::.
+This example demonstrates how to dump the whole scrollback buffer to
+that file:
+`C-a [ g SPACE G $ >'.
+
+`C-g' gives information about the current line and column.
+
+`x' exchanges the first mark and the current cursor position. You can
+use this to adjust an already placed mark.
+
+`@' does nothing. Absolutely nothing. Does not even exit copy mode.
+
+All keys not described here exit copy mode.
+
+
+File: screen.info, Node: Paste, Next: Registers, Prev: Copy, Up: Copy and Paste
+
+Paste
+=====
+
+ - Command: paste [REGISTERS [DESTINATION]]
+ (`C-a ]', `C-a C-]')
+ Write the (concatenated) contents of the specified registers to
+ the stdin stream of the current window. The register `.' is
+ treated as the paste buffer. If no parameter is specified the user
+ is prompted to enter a single register. The paste buffer can be
+ filled with the `copy', `history' and `readbuf' commands. Other
+ registers can be filled with the `register', `readreg' and `paste'
+ commands. If `paste' is called with a second argument, the
+ contents of the specified registers is pasted into the named
+ destination register rather than the window. If `.' is used as the
+ second argument, the display's paste buffer is the destination.
+ Note, that `paste' uses a wide variety of resources: Usually both,
+ a current window and a current display are required. But whenever
+ a second argument is specified no current window is needed. When
+ the source specification only contains registers (not the paste
+ buffer) then there need not be a current display (terminal
+ attached), as the registers are a global resource. The paste
+ buffer exists once for every user.
+
+ - Command: pastefont [STATE]
+ Tell screen to include font information in the paste buffer. The
+ default is not to do so. This command is especially usefull for
+ multi character fonts like kanji.
+
+ - Command: slowpaste MSEC
+ (none)
+ Define the speed text is inserted by the `paste' command. If the
+ slowpaste value is nonzero text is written character by character.
+ `screen' will pause for MSEC milliseconds after each write to
+ allow the application to process the input. only use `slowpaste' if
+ your underlying system exposes flow control problems while pasting
+ large amounts of text.
+
+ - Command: readreg [REGISTER [FILENAME]]
+ (none)
+ Does one of two things, dependent on number of arguments: with
+ zero or one arguments it it duplicates the paste buffer contents
+ into the register specified or entered at the prompt. With two
+ arguments it reads the contents of the named file into the
+ register, just as `readbuf' reads the screen-exchange file into
+ the paste buffer. The following example will paste the system's
+ password file into the screen window (using register p, where a
+ copy remains):
+
+ C-a : readreg p /etc/passwd
+ C-a : paste p
+
+
+File: screen.info, Node: Registers, Next: Screen-Exchange, Prev: Paste, Up: Copy and Paste
+
+Registers
+=========
+
+ - Command: copy_reg [KEY]
+ (none)
+ Removed. Use `readreg' instead.
+
+ - Command: ins_reg [KEY]
+ (none)
+ Removed. Use `paste' instead.
+
+ - Command: process [KEY]
+ (none)
+ Stuff the contents of the specified register into the `screen'
+ input queue. If no argument is given you are prompted for a
+ register name. The text is parsed as if it had been typed in from
+ the user's keyboard. This command can be used to bind multiple
+ actions to a single key.
+
+ - Command: register KEY STRING
+ (none)
+ Save the specified STRING to the register KEY.
+
+ - Command: stuff STRING
+ (none)
+ Stuff the string STRING in the input buffer of the current window.
+ This is like the `paste' command, but with much less overhead.
+ You cannot paste large buffers with the `stuff' command. It is most
+ useful for key bindings. *Note Bindkey::
+
+
+
+File: screen.info, Node: Screen-Exchange, Next: History, Prev: Registers, Up: Copy and Paste
+
+Screen-Exchange
+===============
+
+ - Command: bufferfile [EXCHANGE-FILE]
+ (none)
+ Change the filename used for reading and writing with the paste
+ buffer. If the EXCHANGE-FILE parameter is omitted, `screen'
+ reverts to the default of `/tmp/screen-exchange'. The following
+ example will paste the system's password file into the screen
+ window (using the paste buffer, where a copy remains):
+
+ C-a : bufferfile /etc/passwd
+ C-a < C-a ]
+ C-a : bufferfile
+
+ - Command: readbuf
+ (`C-a <')
+ Reads the contents of the current screen-exchange file into the
+ paste buffer.
+
+ - Command: removebuf
+ (`C-a =')
+ Unlinks the screen-exchange file.
+
+ - Command: writebuf
+ (`C-a >')
+ Writes the contents of the paste buffer to a public accessible
+ screen-exchange file. This is thought of as a primitive means of
+ communication between `screen' users on the same host. See also
+ `C-a ESC' (*note Copy::.).
+
+
+File: screen.info, Node: History, Prev: Screen-Exchange, Up: Copy and Paste
+
+History
+=======
+
+ - Command: history
+ (`C-a {')
+ Usually users work with a shell that allows easy access to previous
+ commands. For example, `csh' has the command `!!' to repeat the
+ last command executed. `screen' provides a primitive way of
+ recalling "the command that started ...": You just type the first
+ letter of that command, then hit `C-a {' and `screen' tries to
+ find a previous line that matches with the prompt character to the
+ left of the cursor. This line is pasted into this window's input
+ queue. Thus you have a crude command history (made up by the
+ visible window and its scrollback buffer).
+
+
+File: screen.info, Node: Subprocess Execution, Next: Key Binding, Prev: Copy and Paste, Up: Top
+
+Subprocess Execution
+********************
+
+ Control Input or Output of a window by another filter process. Use
+with care!
+
+* Menu:
+
+* Exec:: The `exec' command syntax.
+* Using Exec:: Weird things that filters can do.
+
+
+File: screen.info, Node: Exec, Next: Using Exec, Up: Subprocess Execution
+
+Exec
+====
+
+ - Command: exec [[FDPAT] NEWCOMMAND [ARGS ... ]]
+ (none)
+ Run a unix subprocess (specified by an executable path NEWCOMMAND
+ and its optional arguments) in the current window. The flow of
+ data between newcommand's stdin/stdout/stderr, the process already
+ running (shell) and screen itself (window) is controlled by the
+ filedescriptor pattern FDPAT. This pattern is basically a three
+ character sequence representing stdin, stdout and stderr of
+ newcommand. A dot (`.') connects the file descriptor to screen. An
+ exclamation mark (`!') causes the file descriptor to be connected
+ to the already running process. A colon (`:') combines both.
+ User input will go to newcommand unless newcommand requests the
+ old process' output (FDPATs first character is `!' or `:') or a
+ pipe symbol (`|') is added to the end of FDPAT.
+ Invoking `exec' without arguments shows name and arguments of the
+ currently running subprocess in this window.
+ When a subprocess is running the `kill' command will affect it
+ instead of the window's process.
+ Refer to the postscript file `doc/fdpat.ps' for a confusing
+ illustration of all 21 possible combinations. Each drawing shows
+ the digits 2, 1, 0 representing the three file descriptors of
+ newcommand. The box marked `W' is usual pty that has the
+ application-process on its slave side. The box marked `P' is the
+ secondary pty that now has screen at its master side.
+
+
+File: screen.info, Node: Using Exec, Prev: Exec, Up: Subprocess Execution
+
+Using Exec
+==========
+
+Abbreviations:
+
+ * Whitespace between the word `exec' and FDPAT and the command name
+ can be omitted.
+
+ * Trailing dots and a FDPAT consisting only of dots can be omitted.
+
+ * A simple `|' is synonymous for the `!..|' pattern.
+
+ * The word `exec' can be omitted when the `|' abbreviation is used.
+
+ * The word `exec' can always be replaced by leading `!'.
+
+Examples:
+
+`!/bin/sh'
+`exec /bin/sh'
+`exec ... /bin/sh'
+ Creates another shell in the same window, while the original shell
+ is still running. Output of both shells is displayed and user
+ input is sent to the new `/bin/sh'.
+
+`!!stty 19200'
+`exec!stty 19200'
+`exec !.. stty 19200'
+ Set the speed of the window's tty. If your stty command operates
+ on stdout, then add another `!'. This is a useful command, when a
+ screen window is directly connected to a serial line that needs to
+ be configured.
+
+`|less'
+`exec !..| less'
+ This adds a pager to the window output. The special character `|'
+ is needed to give the user control over the pager although it gets
+ its input from the window's process. This works, because `less'
+ listens on stderr (a behavior that `screen' would not expect
+ without the `|') when its stdin is not a tty. `Less' versions
+ newer than 177 fail miserably here; good old `pg' still works.
+
+`!:sed -n s/.*Error.*/\007/p'
+ Sends window output to both, the user and the sed command. The sed
+ inserts an additional bell character (oct. 007) to the window
+ output seen by screen. This will cause 'Bell in window x'
+ messages, whenever the string `Error' appears in the window.
+
diff --git a/doc/screen.info-3 b/doc/screen.info-3
new file mode 100644
index 0000000..66f750a
--- /dev/null
+++ b/doc/screen.info-3
@@ -0,0 +1,1381 @@
+This is Info file screen.info, produced by Makeinfo-1.55 from the input
+file ./screen.texinfo.
+
+ This file documents the `Screen' virtual terminal manager.
+
+ Copyright (c) 1993 Free Software Foundation, Inc.
+
+ Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+ Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+ Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by the Foundation.
+
+
+File: screen.info, Node: Key Binding, Next: Flow Control, Prev: Subprocess Execution, Up: Top
+
+Key Binding
+***********
+
+ You may disagree with some of the default bindings (I know I do).
+The `bind' command allows you to redefine them to suit your preferences.
+
+* Menu:
+
+* Bind:: `bind' syntax.
+* Bind Examples:: Using `bind'.
+* Command Character:: The character used to start keyboard commands.
+* Help:: Show current key bindings.
+* Bindkey:: `bindkey' syntax.
+* Bindkey Examples:: Some easy examples.
+* Bindkey Control:: How to control the bindkey mechanism.
+
+
+File: screen.info, Node: Bind, Next: Bind Examples, Up: Key Binding
+
+The `bind' command
+==================
+
+ - Command: bind KEY [COMMAND [ARGS]]
+ (none)
+ Bind a command to a key. The KEY argument is either a single
+ character, a two-character sequence of the form `^x' (meaning
+ `C-x'), a backslash followed by an octal number (specifying the
+ ASCII code of the character), or a backslash followed by a second
+ character, such as `\^' or `\\'. The argument can also be quoted,
+ if you like. If no further argument is given, any previously
+ established binding for this key is removed. The COMMAND argument
+ can be any command (*note Command Index::.).
+
+ By default, most suitable commands are bound to one or more keys
+ (*note Default Key Bindings::.; for instance, the command to
+ create a new window is bound to `C-c' and `c'. The `bind' command
+ can be used to redefine the key bindings and to define new
+ bindings.
+
+
+File: screen.info, Node: Bind Examples, Next: Command Character, Prev: Bind, Up: Key Binding
+
+Examples of the `bind' command
+==============================
+
+Some examples:
+
+ bind ' ' windows
+ bind ^f screen telnet foobar
+ bind \033 screen -ln -t root -h 1000 9 su
+
+would bind the space key to the command that displays a list of windows
+(so that the command usually invoked by `C-a C-w' would also be
+available as `C-a space'), bind `C-f' to the command "create a window
+with a TELNET connection to foobar", and bind ESC to the command that
+creates an non-login window with title `root' in slot #9, with a
+super-user shell and a scrollbackbuffer of 1000 lines.
+
+
+File: screen.info, Node: Command Character, Next: Help, Prev: Bind Examples, Up: Key Binding
+
+Command Character
+=================
+
+ - Command: escape XY
+ (none)
+ Set the command character to X and the character generating a
+ literal command character to Y (just like with the `-e' option).
+ Each argument is either a single character, a two-character
+ sequence of the form `^x' (meaning `C-x'), a backslash followed by
+ an octal number (specifying the ASCII code of the character), or a
+ backslash followed by a second character, such as `\^' or `\\'.
+ The default is `^Aa', but ```' is recommended by one of the
+ authors.
+
+ - Command: defescape XY
+ (none)
+ Set the default command characters. This is equivalent to the
+ command `escape' except that it is useful for multiuser sessions
+ only. In a multiuser session `escape' changes the command
+ character of the calling user, where `defescape' changes the
+ default command characters for users that will be added later.
+
+ - Command: meta
+ (`C-a a')
+ Send the command character (`C-a') to the process in the current
+ window. The keystroke for this command is the second parameter to
+ the `-e' command line switch (*note Invoking Screen::.), or the
+ `escape' .screenrc directive.
+
+ - Command: command
+ (none)
+ This command has the same effect as typing the screen escape
+ character (`C-a'). It is probably only useful for key bindings.
+ *Note Bindkey::.
+
+
+File: screen.info, Node: Help, Next: Bindkey, Prev: Command Character, Up: Key Binding
+
+Help
+====
+
+ - Command: help
+ (`C-a ?')
+ Displays a help screen showing you all the key bindings. The first
+ pages list all the internal commands followed by their bindings.
+ Subsequent pages will display the custom commands, one command per
+ key. Press space when you're done reading each page, or return to
+ exit early. All other characters are ignored. *Note Default Key
+ Bindings::.
+
+
+File: screen.info, Node: Bindkey, Next: Bindkey Examples, Prev: Help, Up: Key Binding
+
+Bindkey
+=======
+
+ - Command: bindkey [OPTS] [STRING [CMD ARGS]]
+ (none)
+ This command manages screen's input translation tables. Every
+ entry in one of the tables tells screen how to react if a certain
+ sequence of characters is encountered. There are three tables: one
+ that should contain actions programmed by the user, one for the
+ default actions used for terminal emulation and one for screen's
+ copy mode to do cursor movement. *Note Input Translation:: for a
+ list of default key bindings.
+
+ If the `-d' option is given, bindkey modifies the default table,
+ `-m' changes the copy mode table and with neither option the user
+ table is selected. The argument `string' is the sequence of
+ characters to which an action is bound. This can either be a fixed
+ tring or a termcap keyboard capability name (selectable with the
+ `-k' option).
+
+ Some keys on a VT100 terminal can send a different string if
+ application mode is turned on (e.g. the cursor keys). Such keys
+ have two entries in the translation table. You can select the
+ application mode entry by specifying the `-a' option.
+
+ The `-t' option tells screen not to do intercharacter timing. One
+ cannot turn off the timing if a termcap capabilty is used.
+
+ `cmd' can be any of screen's commands with an arbitrary number of
+ `args'. If `cmd' is omitted the keybinding is removed from the
+ table.
+
+
+File: screen.info, Node: Bindkey Examples, Next: Bindkey Control, Prev: Bindkey, Up: Key Binding
+
+Bindkey Examples
+================
+
+Here are some examples of keyboard bindings:
+
+ bindkey -d
+
+Show all of the default key bindings. The application mode entries are
+marked with [A].
+
+ bindkey -k k1 select 1
+
+Make the "F1" key switch to window one.
+
+ bindkey -t foo stuff barfoo
+
+Make `foo' an abrevation of the word `barfoo'. Timeout is disabled so
+that users can type slowly.
+
+ bindkey "\024" mapdefault
+
+This keybinding makes `C-t' an escape character for keybindings. If you
+did the above `stuff barfoo' binding, you can enter the word `foo' by
+typing `C-t foo'. If you want to insert a `C-t' you have to press the
+key twice (i.e. escape the escape binding).
+
+ bindkey -k F1 command
+
+Make the F11 (not F1!) key an alternative screen escape (besides `C-a').
+
+
+File: screen.info, Node: Bindkey Control, Prev: Bindkey Examples, Up: Key Binding
+
+Bindkey Control
+===============
+
+ - Command: mapdefault
+ (none)
+ Tell screen that the next input character should only be looked up
+ in the default bindkey table.
+
+ - Command: mapnotnext
+ (none)
+ Like mapdefault, but don't even look in the default bindkey table.
+
+ - Command: maptimeout TIMO
+ (none)
+ Set the intercharacter timer for input sequence detection to a
+ timeout of TIMO ms. The default timeout is 300ms. Maptimeout with
+ no arguments shows the current setting.
+
+
+File: screen.info, Node: Flow Control, Next: Termcap, Prev: Key Binding, Up: Top
+
+Flow Control
+************
+
+ `screen' can trap flow control characters or pass them to the
+program, as you see fit. This is useful when your terminal wants to use
+XON/XOFF flow control and you are running a program which wants to use
+^S/^Q for other purposes (i.e. `emacs').
+
+* Menu:
+
+* Flow Control Summary:: The effect of `screen' flow control
+* Flow:: Setting the flow control behavior
+* XON/XOFF:: Sending XON or XOFF to the window
+
+
+File: screen.info, Node: Flow Control Summary, Next: Flow, Up: Flow Control
+
+About `screen' flow control settings
+====================================
+
+ Each window has a flow-control setting that determines how screen
+deals with the XON and XOFF characters (and perhaps the interrupt
+character). When flow-control is turned off, screen ignores the XON
+and XOFF characters, which allows the user to send them to the current
+program by simply typing them (useful for the `emacs' editor, for
+instance). The trade-off is that it will take longer for output from a
+"normal" program to pause in response to an XOFF. With flow-control
+turned on, XON and XOFF characters are used to immediately pause the
+output of the current window. You can still send these characters to
+the current program, but you must use the appropriate two-character
+screen commands (typically `C-a q' (xon) and `C-a s' (xoff)). The
+xon/xoff commands are also useful for typing C-s and C-q past a
+terminal that intercepts these characters.
+
+ Each window has an initial flow-control value set with either the
+`-f' option or the `defflow' command. By default the windows are set
+to automatic flow-switching. It can then be toggled between the three
+states 'fixed on', 'fixed off' and 'automatic' interactively with the
+`flow' command bound to `C-a f'.
+
+ The automatic flow-switching mode deals with flow control using the
+TIOCPKT mode (like `rlogin' does). If the tty driver does not support
+TIOCPKT, screen tries to determine the right mode based on the current
+setting of the application keypad -- when it is enabled, flow-control
+is turned off and visa versa. Of course, you can still manipulate
+flow-control manually when needed.
+
+ If you're running with flow-control enabled and find that pressing
+the interrupt key (usually C-c) does not interrupt the display until
+another 6-8 lines have scrolled by, try running screen with the
+`interrupt' option (add the `interrupt' flag to the `flow' command in
+your .screenrc, or use the `-i' command-line option). This causes the
+output that `screen' has accumulated from the interrupted program to be
+flushed. One disadvantage is that the virtual terminal's memory
+contains the non-flushed version of the output, which in rare cases can
+cause minor inaccuracies in the output. For example, if you switch
+screens and return, or update the screen with `C-a l' you would see the
+version of the output you would have gotten without `interrupt' being
+on. Also, you might need to turn off flow-control (or use auto-flow
+mode to turn it off automatically) when running a program that expects
+you to type the interrupt character as input, as the `interrupt'
+parameter only takes effect when flow-control is enabled. If your
+program's output is interrupted by mistake, a simple refresh of the
+screen with `C-a l' will restore it. Give each mode a try, and use
+whichever mode you find more comfortable.
+
+
+File: screen.info, Node: Flow, Next: XON/XOFF, Prev: Flow Control Summary, Up: Flow Control
+
+Flow
+====
+
+ - Command: defflow FSTATE [INTERRUPT]
+ (none)
+ Same as the `flow' command except that the default setting for new
+ windows is changed. Initial setting is `auto'. Specifying `flow
+ auto interrupt' has the same effect as the command-line options
+ `-fa' and `-i'. Note that if `interrupt' is enabled, all existing
+ displays are changed immediately to forward interrupt signals.
+
+ - Command: flow [FSTATE]
+ (`C-a f', `C-a C-f')
+ Sets the flow-control mode for this window to FSTATE, which can be
+ `on', `off' or `auto'. Without parameters it cycles the current
+ window's flow-control setting. Default is set by `defflow'.
+
+
+File: screen.info, Node: XON/XOFF, Prev: Flow, Up: Flow Control
+
+XON and XOFF
+============
+
+ - Command: xon
+ (`C-a q', `C-a C-q')
+ Send a ^Q (ASCII XON) to the program in the current window.
+ Redundant if flow control is set to `off' or `auto'.
+
+ - Command: xoff
+ (`C-a s', `C-a C-s')
+ Send a ^S (ASCII XOFF) to the program in the current window.
+
+
+File: screen.info, Node: Termcap, Next: Message Line, Prev: Flow Control, Up: Top
+
+Termcap
+*******
+
+ `screen' demands the most out of your terminal so that it can
+perform its VT100 emulation most efficiently. These functions provide
+means for tweaking the termcap entries for both your physical terminal
+and the one simulated by `screen'.
+
+* Menu:
+
+* Window Termcap:: Choosing a termcap entry for the window.
+* Dump Termcap:: Write out a termcap entry for the window.
+* Termcap Syntax:: The `termcap' and `terminfo' commands.
+* Termcap Examples:: Uses for `termcap'.
+* Special Capabilities:: Non-standard capabilities used by `screen'.
+* Autonuke:: Flush unseen output
+* Obuflimit:: Allow pending output when reading more
+* Character Translation:: Emulating fonts and charsets.
+
+
+File: screen.info, Node: Window Termcap, Next: Dump Termcap, Up: Termcap
+
+Choosing the termcap entry for a window
+=======================================
+
+ Usually `screen' tries to emulate as much of the VT100/ANSI standard
+as possible. But if your terminal lacks certain capabilities the
+emulation may not be complete. In these cases `screen' has to tell the
+applications that some of the features are missing. This is no problem
+on machines using termcap, because `screen' can use the `$TERMCAP'
+variable to customize the standard screen termcap.
+
+ But if you do a rlogin on another machine or your machine supports
+only terminfo this method fails. Because of this `screen' offers a way
+to deal with these cases. Here is how it works:
+
+ When `screen' tries to figure out a terminal name for itself, it
+first looks for an entry named `screen.TERM', where TERM is the
+contents of your `$TERM' variable. If no such entry exists, `screen'
+tries `screen' (or `screen-w', if the terminal is wide (132 cols or
+more)). If even this entry cannot be found, `vt100' is used as a
+substitute.
+
+ The idea is that if you have a terminal which doesn't support an
+important feature (e.g. delete char or clear to EOS) you can build a new
+termcap/terminfo entry for `screen' (named `screen.DUMBTERM') in which
+this capability has been disabled. If this entry is installed on your
+machines you are able to do a rlogin and still keep the correct
+termcap/terminfo entry. The terminal name is put in the `$TERM'
+variable of all new windows. `screen' also sets the `$TERMCAP'
+variable reflecting the capabilities of the virtual terminal emulated.
+Furthermore, the variable `$WINDOW' is set to the window number of each
+window.
+
+ The actual set of capabilities supported by the virtual terminal
+depends on the capabilities supported by the physical terminal. If, for
+instance, the physical terminal does not support underscore mode,
+`screen' does not put the `us' and `ue' capabilities into the window's
+`$TERMCAP' variable, accordingly. However, a minimum number of
+capabilities must be supported by a terminal in order to run `screen';
+namely scrolling, clear screen, and direct cursor addressing (in
+addition, `screen' does not run on hardcopy terminals or on terminals
+that over-strike).
+
+ Also, you can customize the `$TERMCAP' value used by `screen' by
+using the `termcap' command, or by defining the variable `$SCREENCAP'
+prior to startup. When the latter defined, its value will be copied
+verbatim into each window's `$TERMCAP' variable. This can either be
+the full terminal definition, or a filename where the terminal `screen'
+(and/or `screen-w') is defined.
+
+ Note that `screen' honors the `terminfo' command if the system uses
+the terminfo database rather than termcap. On such machines the
+`$TERMCAP' variable has no effect and you must use the `dumptermcap'
+command (*note Dump Termcap::.) and the `tic' program to generate
+terminfo entries for `screen' windows.
+
+ When the boolean `G0' capability is present in the termcap entry for
+the terminal on which `screen' has been called, the terminal emulation
+of `screen' supports multiple character sets. This allows an
+application to make use of, for instance, the VT100 graphics character
+set or national character sets. The following control functions from
+ISO 2022 are supported: `lock shift G0' (`SI'), `lock shift G1' (`SO'),
+`lock shift G2', `lock shift G3', `single shift G2', and `single shift
+G3'. When a virtual terminal is created or reset, the ASCII character
+set is designated as `G0' through `G3'. When the `G0' capability is
+present, screen evaluates the capabilities `S0', `E0', and `C0' if
+present. `S0' is the sequence the terminal uses to enable and start the
+graphics character set rather than `SI'. `E0' is the corresponding
+replacement for `SO'. `C0' gives a character by character translation
+string that is used during semi-graphics mode. This string is built
+like the `acsc' terminfo capability.
+
+ When the `po' and `pf' capabilities are present in the terminal's
+termcap entry, applications running in a `screen' window can send
+output to the printer port of the terminal. This allows a user to have
+an application in one window sending output to a printer connected to
+the terminal, while all other windows are still active (the printer
+port is enabled and disabled again for each chunk of output). As a
+side-effect, programs running in different windows can send output to
+the printer simultaneously. Data sent to the printer is not displayed
+in the window.
+
+ Some capabilities are only put into the `$TERMCAP' variable of the
+virtual terminal if they can be efficiently implemented by the physical
+terminal. For instance, `dl' (delete line) is only put into the
+`$TERMCAP' variable if the terminal supports either delete line itself
+or scrolling regions. Note that this may provoke confusion, when the
+session is reattached on a different terminal, as the value of
+`$TERMCAP' cannot be modified by parent processes. You can force
+`screen' to include all capabilities in `$TERMCAP' with the `-a'
+command-line option (*note Invoking Screen::.).
+
+
+File: screen.info, Node: Dump Termcap, Next: Termcap Syntax, Prev: Window Termcap, Up: Termcap
+
+Write out the window's termcap entry
+====================================
+
+ - Command: dumptermcap
+ (`C-a .')
+ Write the termcap entry for the virtual terminal optimized for the
+ currently active window to the file `.termcap' in the user's
+ `$HOME/.screen' directory (or wherever `screen' stores its
+ sockets. *note Files::.). This termcap entry is identical to the
+ value of the environment variable `$TERMCAP' that is set up by
+ `screen' for each window. For terminfo based systems you will need
+ to run a converter like `captoinfo' and then compile the entry with
+ `tic'.
+
+
+File: screen.info, Node: Termcap Syntax, Next: Termcap Examples, Prev: Dump Termcap, Up: Termcap
+
+The `termcap' command
+=====================
+
+ - Command: termcap TERM TERMINAL-TWEAKS [WINDOW-TWEAKS]
+ - Command: terminfo TERM TERMINAL-TWEAKS [WINDOW-TWEAKS]
+ - Command: termcapinfo TERM TERMINAL-TWEAKS [WINDOW-TWEAKS]
+ (none)
+ Use this command to modify your terminal's termcap entry without
+ going through all the hassles involved in creating a custom
+ termcap entry. Plus, you can optionally customize the termcap
+ generated for the windows. You have to place these commands in
+ one of the screenrc starup files, as they are meaningless once the
+ terminal emulator is booted.
+
+ If your system uses the terminfo database rather than termcap,
+ `screen' will understand the `terminfo' command which has the same
+ effects as the `termcap' command. Two separate commands are
+ provided, as there are subtle syntactic differences, e.g. when
+ parameter interpolation (using `%') is required. Note that the
+ termcap names of the capabilities have to be used with the
+ `terminfo' command.
+
+ In many cases, where the arguments are valid in both terminfo and
+ termcap syntax, you can use the command `termcapinfo', which is
+ just a shorthand for a pair of `termcap' and `terminfo' commands
+ with identical arguments.
+
+ The first argument specifies which terminal(s) should be affected by
+this definition. You can specify multiple terminal names by separating
+them with `|'s. Use `*' to match all terminals and `vt*' to match all
+terminals that begin with `vt'.
+
+ Each TWEAK argument contains one or more termcap defines (separated
+by `:'s) to be inserted at the start of the appropriate termcap entry,
+enhancing it or overriding existing values. The first tweak modifies
+your terminal's termcap, and contains definitions that your terminal
+uses to perform certain functions. Specify a null string to leave this
+unchanged (e.g. ""). The second (optional) tweak modifies all the
+window termcaps, and should contain definitions that screen understands
+(*note Virtual Terminal::.).
+
+
+File: screen.info, Node: Termcap Examples, Next: Special Capabilities, Prev: Termcap Syntax, Up: Termcap
+
+Termcap Examples
+================
+
+ Some examples:
+
+ termcap xterm* xn:hs@
+
+Informs `screen' that all terminals that begin with `xterm' have firm
+auto-margins that allow the last position on the screen to be updated
+(xn), but they don't really have a status line (no 'hs' - append `@' to
+turn entries off). Note that we assume `xn' for all terminal names
+that start with `vt', but only if you don't specify a termcap command
+for that terminal.
+
+ termcap vt* xn
+ termcap vt102|vt220 Z0=\E[?3h:Z1=\E[?3l
+
+Specifies the firm-margined `xn' capability for all terminals that
+begin with `vt', and the second line will also add the escape-sequences
+to switch into (Z0) and back out of (Z1) 132-character-per-line mode if
+this is a VT102 or VT220. (You must specify Z0 and Z1 in your termcap
+to use the width-changing commands.)
+
+ termcap vt100 "" l0=PF1:l1=PF2:l2=PF3:l3=PF4
+
+This leaves your vt100 termcap alone and adds the function key labels to
+each window's termcap entry.
+
+ termcap h19|z19 am@:im=\E@:ei=\EO dc=\E[P
+
+Takes a h19 or z19 termcap and turns off auto-margins (am@) and enables
+the insert mode (im) and end-insert (ei) capabilities (the `@' in the
+`im' string is after the `=', so it is part of the string). Having the
+`im' and `ei' definitions put into your terminal's termcap will cause
+screen to automatically advertise the character-insert capability in
+each window's termcap. Each window will also get the delete-character
+capability (dc) added to its termcap, which screen will translate into
+a line-update for the terminal (we're pretending it doesn't support
+character deletion).
+
+ If you would like to fully specify each window's termcap entry, you
+should instead set the `$SCREENCAP' variable prior to running `screen'.
+*Note Virtual Terminal::, for the details of the `screen' terminal
+emulation. *Note Termcap: (termcap)Top, for more information on
+termcap definitions.
+
+
+File: screen.info, Node: Special Capabilities, Next: Autonuke, Prev: Termcap Examples, Up: Termcap
+
+Special Terminal Capabilities
+=============================
+
+ The following table describes all terminal capabilities that are
+recognized by `screen' and are not in the termcap manual (*note
+Termcap: (termcap)Top.). You can place these capabilities in your
+termcap entries (in `/etc/termcap') or use them with the commands
+`termcap', `terminfo' and `termcapinfo' in your `screenrc' files. It is
+often not possible to place these capabilities in the terminfo database.
+`LP'
+ (bool)
+ Terminal has VT100 style margins (`magic margins'). Note that this
+ capability is obsolete -- `screen' now uses the standard `xn'
+ instead.
+
+`Z0'
+ (str)
+ Change width to 132 columns.
+
+`Z1'
+ (str)
+ Change width to 80 columns.
+
+`WS'
+ (str)
+ Resize display. This capability has the desired width and height as
+ arguments. SunView(tm) example: `\E[8;%d;%dt'.
+
+`NF'
+ (bool)
+ Terminal doesn't need flow control. Send ^S and ^Q direct to the
+ application. Same as `flow off'. The opposite of this capability
+ is `nx'.
+
+`G0'
+ (bool)
+ Terminal can deal with ISO 2022 font selection sequences.
+
+`S0'
+ (str)
+ Switch charset `G0' to the specified charset. Default is `\E(%.'.
+
+`E0'
+ (str)
+ Switch charset `G0' back to standard charset. Default is `\E(B'.
+
+`C0'
+ (str)
+ Use the string as a conversion table for font 0. See the `ac'
+ capability for more details.
+
+`CS'
+ (str)
+ Switch cursor keys to application mode.
+
+`CE'
+ (str)
+ Switch cursor keys to cursor mode.
+
+`AN'
+ (bool)
+ Enable autonuke for displays of this terminal type. (*note
+ Autonuke::.).
+
+`OL'
+ (num)
+ Set the output buffer limit. See the `obuflimit' command (*note
+ Obuflimit::.) for more details.
+
+`KJ'
+ (str)
+ Set the kanji type of the terminal. Valid strings are `jis', `euc'
+ and `sjis'.
+
+`AF'
+ (str)
+ Change character forground color in an ANSI conform way. This
+ capability will almost always be set to `\E[3%dm' (`\E[3%p1%dm' on
+ terminfo machines).
+
+`AB'
+ (str)
+ Same as `AF', but change background color.
+
+`AX'
+ (bool)
+ Does understand ANSI set default fg/bg color (`\E[39m / \E[49m').
+
+`XC'
+ (str)
+ Describe a translation of characters to strings depending on the
+ current font. (*note Character Translation::.).
+
+
+File: screen.info, Node: Autonuke, Next: Obuflimit, Prev: Special Capabilities, Up: Termcap
+
+Autonuke
+========
+
+ - Command: autonuke STATE
+ (none)
+ Sets whether a clear screen sequence should nuke all the output
+ that has not been written to the terminal. *Note Obuflimit::.
+ This property is set per display, not per window.
+
+ - Command: defautonuke STATE
+ (none)
+ Same as the `autonuke' command except that the default setting for
+ new displays is also changed. Initial setting is `off'. Note that
+ you can use the special `AN' terminal capability if you want to
+ have a terminal type dependent setting.
+
+
+File: screen.info, Node: Obuflimit, Next: Character Translation, Prev: Autonuke, Up: Termcap
+
+Obuflimit
+=========
+
+ - Command: obuflimit [LIMIT]
+ (none)
+ If the output buffer contains more bytes than the specified limit,
+ no more data will be read from the windows. The default value is
+ 256. If you have a fast display (like `xterm'), you can set it to
+ some higher value. If no argument is specified, the current
+ setting is displayed. This property is set per display, not per
+ window.
+
+ - Command: defobuflimit LIMIT
+ (none)
+ Same as the `obuflimit' command except that the default setting
+ for new displays is also changed. Initial setting is 256 bytes.
+ Note that you can use the special `OL' terminal capability if you
+ want to have a terminal type dependent limit.
+
+
+File: screen.info, Node: Character Translation, Prev: Obuflimit, Up: Termcap
+
+Character Translation
+=====================
+
+ `Screen' has a powerful mechanism to translate characters to
+arbitrary strings depending on the current font and terminal type. Use
+this feature if you want to work with a common standard character set
+(say ISO8851-latin1) even on terminals that scatter the more unusual
+characters over several national language font pages.
+
+ Syntax:
+
+ XC=<CHARSET-MAPPING>{,,<CHARSET-MAPPING>}
+ <CHARSET-MAPPING> := <DESIGNATOR><TEMPLATE>{,<MAPPING>}
+ <MAPPING> := <CHAR-TO-BE-MAPPED><TEMPLATE-ARG>
+
+ The things in braces may be repeated any number of times.
+
+ A <CHARSET-MAPPING> tells screen how to map characters in font
+<DESIGNATOR> (`B': Ascii, `A': UK, `K': german, etc.) to strings. Every
+<MAPPING> describes to what string a single character will be
+translated. A template mechanism is used, as most of the time the codes
+have a lot in common (for example strings to switch to and from another
+charset). Each occurence of `%' in <TEMPLATE> gets substituted with the
+TEMPLATE-ARG specified together with the character. If your strings are
+not similar at all, then use `%' as a template and place the full
+string in <TEMPLATE-ARG>. A quoting mechanism was added to make it
+possible to use a real `%'. The `\' character quotes the special
+characters `\', `%', and `,'.
+
+ Here is an example:
+
+ termcap hp700 'XC=B\E(K%\E(B,\304[,\326\\\\,\334]'
+
+ This tells `screen', how to translate ISOlatin1 (charset `B') upper
+case umlaut characters on a `hp700' terminal that has a german charset.
+`\304' gets translated to `\E(K[\E(B' and so on. Note that this line
+gets parsed *three* times before the internal lookup table is built,
+therefore a lot of quoting is needed to create a single `\'.
+
+ Another extension was added to allow more emulation: If a mapping
+translates the unquoted `%' char, it will be sent to the terminal
+whenever screen switches to the corresponding <DESIGNATOR>. In this
+special case the template is assumed to be just `%' because the charset
+switch sequence and the character mappings normaly haven't much in
+common.
+
+ This example shows one use of the extension:
+ termcap xterm 'XC=K%,%\E(B,[\304,\\\\\326,]\334'
+
+ Here, a part of the german (`K') charset is emulated on an xterm.
+If screen has to change to the `K' charset, `\E(B' will be sent to the
+terminal, i.e. the ASCII charset is used instead. The template is just
+`%', so the mapping is straightforward: `[' to `\304', `\' to `\326',
+and `]' to `\334'.
+
+
+File: screen.info, Node: Message Line, Next: Logging, Prev: Termcap, Up: Top
+
+The Message Line
+****************
+
+ `screen' displays informational messages and other diagnostics in a
+"message line" at the bottom of the screen. If your terminal has a
+status line defined in its termcap, screen will use this for displaying
+its messages, otherwise the last line of the screen will be temporarily
+overwritten and output will be momentarily interrupted. The message
+line is automatically removed after a few seconds delay, but it can also
+be removed early (on terminals without a status line) by beginning to
+type.
+
+* Menu:
+
+* Privacy Message:: Using the message line from your program.
+* Hardware Status Line:: Use the terminal's hardware status line.
+* Last Message:: Redisplay the last message.
+* Message Wait:: Control how long messages are displayed.
+
+
+File: screen.info, Node: Privacy Message, Next: Hardware Status Line, Up: Message Line
+
+Using the message line from your program
+========================================
+
+ The message line facility can be used by an application running in
+the current window by means of the ANSI "Privacy message" control
+sequence. For instance, from within the shell, try something like:
+
+ echo "^Hello world from window $WINDOW\"
+
+ where `' is ASCII ESC and `^' is a literal caret or up-arrow.
+
+
+File: screen.info, Node: Hardware Status Line, Next: Last Message, Prev: Privacy Message, Up: Message Line
+
+Hardware Status Line
+====================
+
+ - Command: hardstatus [STATE]
+ (none)
+ Toggles the use of the terminal's hardware status line. If `on',
+ `screen' will use this facility to display one line messages.
+ Otherwise these messages are overlayed in reverse video mode at the
+ display line. Note that the hardstatus feature can only be used if
+ the termcap/terminfo capabilities "hs", "ts", "fs" and "ds" are set
+ properly. Default is `on' whenever the "hs" capability is present.
+
+
+File: screen.info, Node: Last Message, Next: Message Wait, Prev: Hardware Status Line, Up: Message Line
+
+Display Last Message
+====================
+
+ - Command: lastmsg
+ (`C-a m', `C-a C-m')
+ Repeat the last message displayed in the message line. Useful if
+ you're typing when a message appears, because (unless your
+ terminal has a hardware status line) the message goes away when
+ you press a key.
+
+
+File: screen.info, Node: Message Wait, Prev: Last Message, Up: Message Line
+
+Message Wait
+============
+
+ - Command: msgminwait SEC
+ (none)
+ Defines the time `screen' delays a new message when another is
+ currently displayed. Defaults to 1 second.
+
+ - Command: msgwait SEC
+ (none)
+ Defines the time a message is displayed, if `screen' is not
+ disturbed by other activity. Defaults to 5 seconds.
+
+
+File: screen.info, Node: Logging, Next: Startup, Prev: Message Line, Up: Top
+
+Logging
+*******
+
+ This section describes the commands for keeping a record of your
+session.
+
+* Menu:
+
+* Hardcopy:: Dump the current screen to a file
+* Log:: Log the output of a window to a file
+
+
+File: screen.info, Node: Hardcopy, Next: Log, Up: Logging
+
+hardcopy
+========
+
+ - Command: hardcopy
+ (`C-a h', `C-a C-h')
+ Writes out the current display contents to the file `hardcopy.N'
+ in the window's default directory, where N is the number of the
+ current window. This either appends or overwrites the file if it
+ exists, as determined by the `hardcopy_append' command.
+
+ - Command: hardcopy_append STATE
+ (none)
+ If set to `on', `screen' will append to the `hardcopy.N' files
+ created by the command `hardcopy'; otherwise, these files are
+ overwritten each time.
+
+ - Command: hardcopydir DIRECTORY
+ (none)
+ Defines a directory where hardcopy files will be placed. If unset
+ hardcopys are dumped in screen's current working directory.
+
+
+File: screen.info, Node: Log, Prev: Hardcopy, Up: Logging
+
+log
+===
+
+ - Command: log [STATE]
+ (`C-a H')
+ Begins/ends logging of the current window to the file
+ `screenlog.N' in the window's default directory, where N is the
+ number of the current window. This filename can be changed with
+ the `logfile' command. If no parameter is given, the logging
+ state is toggled. The session log is appended to the previous
+ contents of the file if it already exists. The current contents
+ and the contents of the scrollback history are not included in the
+ session log. Default is `off'.
+
+ - Command: logfile FILENAME
+ (none)
+ Defines the name the logfiles will get. The default is
+ `screenlog.%n'.
+
+
+File: screen.info, Node: Startup, Next: Miscellaneous, Prev: Logging, Up: Top
+
+Startup
+*******
+
+ This section describes commands which are only useful in the
+`.screenrc' file, for use at startup.
+
+* Menu:
+
+* echo:: Display a message.
+* sleep:: Pause execution of the `.screenrc'.
+* Startup Message:: Control display of the copyright notice.
+
+
+File: screen.info, Node: echo, Next: sleep, Up: Startup
+
+echo
+====
+
+ - Command: echo [-n] MESSAGE
+ (none)
+ The echo command may be used to annoy `screen' users with a
+ 'message of the day'. Typically installed in a global screenrc.
+ The option `-n' may be used to suppress the line feed. See also
+ `sleep'. Echo is also useful for online checking of environment
+ variables.
+
+
+File: screen.info, Node: sleep, Next: Startup Message, Prev: echo, Up: Startup
+
+sleep
+=====
+
+ - Command: sleep NUM
+ (none)
+ This command will pause the execution of a .screenrc file for NUM
+ seconds. Keyboard activity will end the sleep. It may be used to
+ give users a chance to read the messages output by `echo'.
+
+
+File: screen.info, Node: Startup Message, Prev: sleep, Up: Startup
+
+Startup Message
+===============
+
+ - Command: startup_message STATE
+ (none)
+ Select whether you want to see the copyright notice during startup.
+ Default is `on', as you probably noticed.
+
+
+File: screen.info, Node: Miscellaneous, Next: Environment, Prev: Startup, Up: Top
+
+Miscellaneous commands
+**********************
+
+ The commands described here do not fit well under any of the other
+categories.
+
+* Menu:
+
+* At:: Execute a command at other displays or windows.
+* Break:: Send a break signal to the window.
+* Debug:: Suppress/allow debugging output.
+* License:: Display the disclaimer page.
+* Nethack:: Use `nethack'-like error messages.
+* Number:: Change the current window's number.
+* Silence:: Notify on inactivity.
+* Time:: Display the time and load average.
+* Version:: Display the version of `screen'.
+* Zombie:: Keep dead windows.
+* Printcmd:: Set command for VT100 printer port emulation.
+* Sorendition:: Change the text highlighting method.
+
+
+File: screen.info, Node: At, Next: Break, Up: Miscellaneous
+
+At
+==
+
+ - Command: at [IDENTIFIER][#|*|%] COMMAND [ARGS]
+ (none)
+ Execute a command at other displays or windows as if it had been
+ entered there. `At' changes the context (the `current window' or
+ `current display' setting) of the command. If the first parameter
+ describes a non-unique context, the command will be executed
+ multiple times. If the first parameter is of the form
+ `IDENTIFIER*' then identifier is matched against user names. The
+ command is executed once for each display of the selected user(s).
+ If the first parameter is of the form `IDENTIFIER%' identifier is
+ matched against displays. Displays are named after the ttys they
+ attach. The prefix `/dev/' or `/dev/tty' may be omitted from the
+ identifier. If IDENTIFIER has a `#' or nothing appended it is
+ matched against window numbers and titles. Omitting an identifier
+ in front of the `#', `*' or `%' character selects all users,
+ displays or windows because a prefix-match is performed. Note that
+ on the affected display(s) a short message will describe what
+ happened. Caution: Permission is checked for the owners or the
+ affected display(s), not for the initiator of the `at' command.
+
+
+File: screen.info, Node: Break, Next: Debug, Prev: At, Up: Miscellaneous
+
+Break
+=====
+
+ - Command: break [DURATION]
+ (none)
+ Send a break signal for DURATION*0.25 seconds to this window.
+ Most useful if a character device is attached to the window rather
+ than a shell process.
+
+ - Command: pow_break
+ (none)
+ Reopen the window's terminal line and send a break condition.
+
+
+File: screen.info, Node: Debug, Next: License, Prev: Break, Up: Miscellaneous
+
+Debug
+=====
+
+ - Command: debug [ON|OFF]
+ (none)
+ Turns runtime debugging on or off. If `screen' has been compiled
+ with option `-DDEBUG' debugging is available and is turned on per
+ default. Note that this command only affects debugging output
+ from the main `SCREEN' process.
+
+
+File: screen.info, Node: License, Next: Nethack, Prev: Debug, Up: Miscellaneous
+
+License
+=======
+
+ - Command: license
+ (none)
+ Display the disclaimer page. This is done whenever `screen' is
+ started without options, which should be often enough.
+
+
+File: screen.info, Node: Nethack, Next: Number, Prev: License, Up: Miscellaneous
+
+Nethack
+=======
+
+ - Command: nethack STATE
+ (none)
+ Changes the kind of error messages used by `screen'. When you are
+ familiar with the game `nethack', you may enjoy the nethack-style
+ messages which will often blur the facts a little, but are much
+ funnier to read. Anyway, standard messages often tend to be
+ unclear as well.
+
+ This option is only available if `screen' was compiled with the
+ NETHACK flag defined (*note Installation::.). The default setting
+ is then determined by the presence of the environment variable
+ `$NETHACKOPTIONS'.
+
+
+File: screen.info, Node: Number, Next: Silence, Prev: Nethack, Up: Miscellaneous
+
+Number
+======
+
+ - Command: number [N]
+ (`C-a N')
+ Change the current window's number. If the given number N is
+ already used by another window, both windows exchange their
+ numbers. If no argument is specified, the current window number
+ (and title) is shown.
+
+
+File: screen.info, Node: Silence, Next: Time, Prev: Number, Up: Miscellaneous
+
+Silence
+=======
+
+ - Command: silence [STATE|SEC]
+ (none)
+ Toggles silence monitoring of windows. When silence is turned on
+ and an affected window is switched into the background, you will
+ receive the silence notification message in the status line after
+ a specified period of inactivity (silence). The default timeout
+ can be changed with the `silencewait' command or by specifying a
+ number of seconds instead of `on' or `off'. Silence is initially
+ off for all windows.
+
+ - Command: silencewait SECONDS
+ (none)
+ Define the time that all windows monitored for silence should wait
+ before displaying a message. Default is 30 seconds.
+
+
+File: screen.info, Node: Time, Next: Version, Prev: Silence, Up: Miscellaneous
+
+Time
+====
+
+ - Command: time
+ (`C-a t', `C-a C-t')
+ Uses the message line to display the time of day, the host name,
+ and the load averages over 1, 5, and 15 minutes (if this is
+ available on your system). For window-specific information use
+ `info' (*note Info::.).
+
+
+File: screen.info, Node: Version, Next: Zombie, Prev: Time, Up: Miscellaneous
+
+Version
+=======
+
+ - Command: version
+ (`C-a v')
+ Display the version and modification date in the message line.
+
+
+File: screen.info, Node: Zombie, Next: Printcmd, Prev: Version, Up: Miscellaneous
+
+Zombie
+======
+
+ - Command: zombie [KEYX]
+ - Command: defzombie [KEYX]
+ (none)
+ Per default windows are removed from the window list as soon as the
+ windows process (e.g. shell) exits. When a string of two keys is
+ specified to the zombie command, `dead' windows will remain in the
+ list. The `kill' kommand may be used to remove the window.
+ Pressing the first key in the dead window has the same effect.
+ Pressing the second key, however, screen will attempt to resurrect
+ the window. The process that was initially running in the window
+ will be launched again. Calling `zombie' without parameters will
+ clear the zombie setting, thus making windows disappear when the
+ process terminates.
+
+ As the zombie setting is affected globally for all windows, this
+ command should only be called `defzombie'. Until we need this as a
+ per window setting, the commands `zombie' and `defzombie' are
+ synonymous.
+
+
+File: screen.info, Node: Printcmd, Next: Sorendition, Prev: Zombie, Up: Miscellaneous
+
+Printcmd
+========
+
+ - Command: printcmd [CMD]
+ (none)
+ If CMD is not an empty string, screen will not use the terminal
+ capabilities `po/pf' for printing if it detects an ansi print
+ sequence `ESC [ 5 i', but pipe the output into CMD. This should
+ normally be a command like `lpr' or `cat > /tmp/scrprint'.
+ `Printcmd' without an argument displays the current setting. The
+ ansi sequence `ESC \' ends printing and closes the pipe.
+
+ Warning: Be careful with this command! If other user have write
+ access to your terminal, they will be able to fire off print
+ commands.
+
+
+File: screen.info, Node: Sorendition, Prev: Printcmd, Up: Miscellaneous
+
+Sorendition
+===========
+
+ - Command: sorendition [ATTR [COLOR]]
+ (none)
+ Change the way screen does highlighting for text marking and
+ printing messages. ATTR is a hexadecimal number and describes the
+ attributes (inverse, underline, ...) the text will get. COLOR is
+ a 2 digit number and changes the forground/background of the
+ highlighted text. Some knowledge of screen's internal character
+ representation is needed to make the characters appear in the
+ desired way. The default is currently `10 99' (standout, default
+ colors).
+
+
+File: screen.info, Node: Environment, Next: Files, Prev: Miscellaneous, Up: Top
+
+Environment Variables
+*********************
+
+`COLUMNS'
+ Number of columns on the terminal (overrides termcap entry).
+
+`HOME'
+ Directory in which to look for .screenrc.
+
+`ISCREENRC'
+ Alternate user screenrc file.
+
+`LINES'
+ Number of lines on the terminal (overrides termcap entry).
+
+`LOCKPRG'
+ Screen lock program.
+
+`NETHACKOPTIONS'
+ Turns on `nethack' option.
+
+`PATH'
+ Used for locating programs to run.
+
+`SCREENCAP'
+ For customizing a terminal's `TERMCAP' value.
+
+`SCREENDIR'
+ Alternate socket directory.
+
+`SCREENRC'
+ Alternate user screenrc file.
+
+`SHELL'
+ Default shell program for opening windows (default `/bin/sh').
+
+`STY'
+ Alternate socket name. If `screen' is invoked, and the environment
+ variable `STY' is set, then it creates only a window in the
+ running `screen' session rather than starting a new session.
+
+`SYSSCREENRC'
+ Alternate system screenrc file.
+
+`TERM'
+ Terminal name.
+
+`TERMCAP'
+ Terminal description.
+
+
+File: screen.info, Node: Files, Next: Credits, Prev: Environment, Up: Top
+
+Files Referenced
+****************
+
+`.../screen-3.?.??/etc/screenrc'
+`.../screen-3.?.??/etc/etcscreenrc'
+ Examples in the `screen' distribution package for private and
+ global initialization files.
+
+``$SYSSCREENRC''
+`/local/etc/screenrc'
+ `screen' initialization commands
+
+``$ISCREENRC''
+``$SCREENRC''
+``$HOME'/.iscreenrc'
+``$HOME'/.screenrc'
+ Read in after /local/etc/screenrc
+
+``$ISCREENDIR'/S-LOGIN'
+``$SCREENDIR'/S-LOGIN'
+`/local/screens/S-LOGIN'
+ Socket directories (default)
+
+`/usr/tmp/screens/S-LOGIN'
+ Alternate socket directories.
+
+`SOCKET DIRECTORY/.termcap'
+ Written by the `dumptermcap' command
+
+`/usr/tmp/screens/screen-exchange or'
+`/tmp/screen-exchange'
+ `screen' interprocess communication buffer
+
+`hardcopy.[0-9]'
+ Screen images created by the hardcopy command
+
+`screenlog.[0-9]'
+ Output log files created by the log command
+
+`/usr/lib/terminfo/?/* or'
+`/etc/termcap'
+ Terminal capability databases
+
+`/etc/utmp'
+ Login records
+
+``$LOCKPRG''
+ Program for locking the terminal.
+
+
+File: screen.info, Node: Credits, Next: Bugs, Prev: Files, Up: Top
+
+Credits
+*******
+
+Authors
+=======
+
+ Originally created by Oliver Laumann, this latest version was
+produced by Wayne Davison, Juergen Weigert and Michael Schroeder.
+
+Contributors
+============
+
+ Ken Beal (kbeal@amber.ssd.csd.harris.com),
+ Rudolf Koenig (rfkoenig@informatik.uni-erlangen.de),
+ Toerless Eckert (eckert@informatik.uni-erlangen.de),
+ Wayne Davison (davison@borland.com),
+ Patrick Wolfe (pat@kai.com, kailand!pat),
+ Bart Schaefer (schaefer@cse.ogi.edu),
+ Nathan Glasser (nathan@brokaw.lcs.mit.edu),
+ Larry W. Virden (lvirden@cas.org),
+ Howard Chu (hyc@hanauma.jpl.nasa.gov),
+ Tim MacKenzie (tym@dibbler.cs.monash.edu.au),
+ Markku Jarvinen (mta@{cc,cs,ee}.tut.fi),
+ Marc Boucher (marc@CAM.ORG),
+ Doug Siebert (dsiebert@isca.uiowa.edu),
+ Ken Stillson (stillson@tsfsrv.mitre.org),
+ Ian Frechett (frechett@spot.Colorado.EDU),
+ Brian Koehmstedt (bpk@gnu.ai.mit.edu),
+ Don Smith (djs6015@ultb.isc.rit.edu),
+ Frank van der Linden (vdlinden@fwi.uva.nl),
+ Martin Schweikert (schweik@cpp.ob.open.de),
+ David Vrona (dave@sashimi.lcu.com),
+ E. Tye McQueen (tye%spillman.UUCP@uunet.uu.net),
+ Matthew Green (mrgreen@mame.mu.oz.au),
+ Christopher Williams (cgw@unt.edu),
+ Matt Mosley (mattm@access.digex.net),
+ Gregory Neil Shapiro (gshapiro@wpi.WPI.EDU),
+ Jason Merrill (jason@jarthur.Claremont.EDU).
+
+Version
+=======
+
+ This manual describes version 3.7.0 of the `screen' program. Its
+roots are a merge of a custom version 2.3PR7 by Wayne Davison and
+several enhancements to Oliver Laumann's version 2.0. Note that all
+versions numbered 2.x are copyright by Oliver Laumann.
+
+ See also *Note Availability::.
+
+
+File: screen.info, Node: Bugs, Next: Installation, Prev: Credits, Up: Top
+
+Bugs
+****
+
+ Just like any other significant piece of software, `screen' has a
+few bugs and missing features. Please send in a bug report if you have
+found a bug not mentioned here.
+
+* Menu:
+
+* Known Bugs:: Problems we know about.
+* Reporting Bugs:: How to contact the maintainers.
+* Availability:: Where to find the lastest screen version.
+
+
+File: screen.info, Node: Known Bugs, Next: Reporting Bugs, Up: Bugs
+
+Known Bugs
+==========
+
+ * `dm' (delete mode) and `xs' are not handled correctly (they are
+ ignored). `xn' is treated as a magic-margin indicator.
+
+ * `screen' has no clue about double-high or double-wide characters.
+ But this is the only area where `vttest' is allowed to fail.
+
+ * It is not possible to change the environment variable `$TERMCAP'
+ when reattaching under a different terminal type.
+
+ * The support of terminfo based systems is very limited. Adding extra
+ capabilities to `$TERMCAP' may not have any effects.
+
+ * `screen' does not make use of hardware tabs.
+
+ * `screen' must be installed setuid root in order to be able to
+ correctly change the owner of the tty device file for each window.
+ Special permission may also be required to write the file
+ `/etc/utmp'.
+
+ * Entries in `/etc/utmp' are not removed when `screen' is killed
+ with SIGKILL. This will cause some programs (like "w" or "rwho")
+ to advertise that a user is logged on who really isn't.
+
+ * `screen' may give a strange warning when your tty has no utmp
+ entry.
+
+ * When the modem line was hung up, `screen' may not automatically
+ detach (or quit) unless the device driver sends a HANGUP signal.
+ To detach such a `screen' session use the -D or -d command line
+ option.
+
+ * A weird imagination is most useful to gain full advantage of all
+ the features.
+
diff --git a/doc/screen.info-4 b/doc/screen.info-4
new file mode 100644
index 0000000..f466b1a
--- /dev/null
+++ b/doc/screen.info-4
@@ -0,0 +1,375 @@
+This is Info file screen.info, produced by Makeinfo-1.55 from the input
+file ./screen.texinfo.
+
+ This file documents the `Screen' virtual terminal manager.
+
+ Copyright (c) 1993 Free Software Foundation, Inc.
+
+ Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+ Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+ Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by the Foundation.
+
+
+File: screen.info, Node: Reporting Bugs, Next: Availability, Prev: Known Bugs, Up: Bugs
+
+Reporting Bugs
+==============
+
+ If you find a bug in `Screen', please send electronic mail to
+`screen@uni-erlangen.de', and also to `bug-gnu-utils@prep.ai.mit.edu'.
+Include the version number of `Screen' which you are using. Also
+include in your message the hardware and operating system, the compiler
+used to compile, a description of the bug behavior, and the conditions
+that triggered the bug. Please recompile `screen' with the `-DDEBUG
+-DTMPTEST' options enabled, reproduce the bug, and have a look at the
+debug output written to the directory `/tmp/debug'. If necessary quote
+suspect passages from the debug output and show the contents of your
+`config.h' if it matters.
+
+
+File: screen.info, Node: Availability, Prev: Reporting Bugs, Up: Bugs
+
+Availability
+============
+
+ `Screen' is available under the `GNU' copyleft.
+
+ The latest official release of `screen' available via anonymous ftp
+from `prep.ai.mit.edu', `nic.funet.fi' or any other `GNU' distribution
+site. The latest beta testing release of `screen' is available from
+`ftp.uni-erlangen.de (131.188.1.43)', in the directory
+`pub/utilities/screen'.
+
+
+File: screen.info, Node: Installation, Next: Concept Index, Prev: Bugs, Up: Top
+
+Installation
+************
+
+ Since `screen' uses pseudo-ttys, the select system call, and
+UNIX-domain sockets/named pipes, it will not run under a system that
+does not include these features of 4.2 and 4.3 BSD UNIX.
+
+* Menu:
+
+* Socket Directory:: Where screen stores its handle.
+* Compiling Screen::
+
+
+File: screen.info, Node: Socket Directory, Next: Compiling Screen, Up: Installation
+
+Socket Directory
+================
+
+ The socket directory defaults either to `$HOME/.screen' or simply to
+`/tmp/screens' or preferably to `/usr/local/screens' chosen at
+compile-time. If `screen' is installed setuid root, then the
+administrator should compile screen with an adequate (not NFS mounted)
+`SOCKDIR'. If `screen' is not running setuid-root, the user can specify
+any mode 777 directory in the environment variable `$SCREENDIR'.
+
+
+File: screen.info, Node: Compiling Screen, Prev: Socket Directory, Up: Installation
+
+Compiling Screen
+================
+
+ To compile and install screen:
+
+ The `screen' package comes with a `GNU Autoconf' configuration
+script. Before you compile the package run
+
+ `sh ./configure'
+
+ This will create a `config.h' and `Makefile' for your machine. If
+`configure' fails for some reason, then look at the examples and
+comments found in the `Makefile.in' and `config.h.in' templates.
+Rename `config.status' to `config.status.MACHINE' when you want to keep
+configuration data for multiple architectures. Running `sh
+./config.status.MACHINE' recreates your configuration significantly
+faster than rerunning `configure'.
+Read through the "User Configuration" section of `config.h', and verify
+that it suits your needs. A comment near the top of this section
+explains why it's best to install screen setuid to root. Check for the
+place for the global `screenrc'-file and for the socket directory.
+Check the compiler used in `Makefile', the prefix path where to install
+`screen'. Then run
+
+ `make'
+
+ If `make' fails to produce one of the files `term.h', `comm.h' or
+`tty.c', then use `FILENAME.X.dist' instead. For additional
+information about installation of `screen' refer to the file
+`INSTALLATION', coming with this package.
+
+
+File: screen.info, Node: Concept Index, Next: Command Index, Prev: Installation, Up: Top
+
+Concept Index
+*************
+
+* Menu:
+
+* .screenrc: Startup Files.
+* availability: Availability.
+* binding: Key Binding.
+* bug report: Reporting Bugs.
+* bugs: Bugs.
+* capabilities: Special Capabilities.
+* command line options: Invoking Screen.
+* command summary: Command Summary.
+* compiling screen: Compiling Screen.
+* control sequences: Control Sequences.
+* copy and paste: Copy and Paste.
+* customization: Customization.
+* environment: Environment.
+* files: Files.
+* flow control: Flow Control.
+* input translation: Input Translation.
+* installation: Installation.
+* introduction: Getting Started.
+* invoking: Invoking Screen.
+* key binding: Key Binding.
+* marking: Copy.
+* message line: Message Line.
+* multiuser session: Multiuser Session.
+* options: Invoking Screen.
+* overview: Overview.
+* screenrc: Startup Files.
+* scrollback: Copy.
+* socket directory: Socket Directory.
+* terminal capabilities: Special Capabilities.
+* title: Naming Windows.
+
+
+File: screen.info, Node: Command Index, Next: Keystroke Index, Prev: Concept Index, Up: Top
+
+Command Index
+*************
+
+ This is a list of all the commands supported by `screen'.
+
+* Menu:
+
+* acladd: Acladd.
+* aclchg: Aclchg.
+* acldel: Acldel.
+* activity: Monitor.
+* allpartial: Redisplay.
+* at: At.
+* autodetach: Detach.
+* autonuke: Autonuke.
+* bell_msg: Bell.
+* bind: Bind.
+* bindkey: Bindkey.
+* break: Break.
+* bufferfile: Screen-Exchange.
+* c1: Character Processing.
+* charset: Character Processing.
+* chdir: Chdir.
+* clear: Clear.
+* colon: Colon.
+* command: Command Character.
+* console: Console.
+* copy: Copy.
+* copy_reg: Registers.
+* crlf: Line Termination.
+* debug: Debug.
+* defautonuke: Autonuke.
+* defc1: Character Processing.
+* defcharset: Character Processing.
+* defescape: Command Character.
+* defflow: Flow.
+* defgr: Character Processing.
+* defhstatus: Hardstatus.
+* defkanji: Character Processing.
+* deflogin: Login.
+* defmode: Mode.
+* defmonitor: Monitor.
+* defobuflimit: Obuflimit.
+* defscrollback: Scrollback.
+* defwrap: Wrap.
+* defwritelock: Writelock.
+* defzombie: Zombie.
+* detach: Detach.
+* digraph: Digraph.
+* dumptermcap: Dump Termcap.
+* echo: echo.
+* escape: Command Character.
+* exec: Exec.
+* flow: Flow.
+* gr: Character Processing.
+* hardcopy: Hardcopy.
+* hardcopydir: Hardcopy.
+* hardcopy_append: Hardcopy.
+* hardstatus: Hardware Status Line.
+* height: Window Size.
+* help: Help.
+* history: History.
+* info: Info.
+* ins_reg: Registers.
+* kanji: Character Processing.
+* kill: Kill.
+* lastmsg: Last Message.
+* license: License.
+* lockscreen: Lock.
+* log: Log.
+* logfile: Log.
+* login: Login.
+* mapdefault: Bindkey Control.
+* mapnotnext: Bindkey Control.
+* maptimeout: Bindkey Control.
+* markkeys: Copy Mode Keys.
+* meta: Command Character.
+* monitor: Monitor.
+* msgminwait: Message Wait.
+* msgwait: Message Wait.
+* multiuser: Multiuser.
+* nethack: Nethack.
+* next: Next and Previous.
+* number: Number.
+* obuflimit: Obuflimit.
+* other: Other Window.
+* partial: Redisplay.
+* password: Detach.
+* paste: Paste.
+* pastefont: Paste.
+* pow_break: Break.
+* pow_detach: Power Detach.
+* pow_detach_msg: Power Detach.
+* prev: Next and Previous.
+* printcmd: Printcmd.
+* process: Registers.
+* quit: Quit.
+* readbuf: Screen-Exchange.
+* readreg: Paste.
+* redisplay: Redisplay.
+* register: Registers.
+* removebuf: Screen-Exchange.
+* reset: Reset.
+* screen: Screen Command.
+* scrollback: Scrollback.
+* select: Select.
+* sessionname: Session Name.
+* setenv: Setenv.
+* shell: Shell.
+* shelltitle: Shell.
+* silence: Silence.
+* silencewait: Silence.
+* sleep: sleep.
+* slowpaste: Paste.
+* sorendition: Sorendition.
+* startup_message: Startup Message.
+* stuff: Registers.
+* suspend: Suspend.
+* term: Term.
+* termcap: Termcap Syntax.
+* termcapinfo: Termcap Syntax.
+* terminfo: Termcap Syntax.
+* time: Time.
+* title: Title Command.
+* unsetenv: Setenv.
+* vbell: Bell.
+* vbellwait: Bell.
+* vbell_msg: Bell.
+* version: Version.
+* wall: Wall.
+* width: Window Size.
+* windows: Windows.
+* wrap: Wrap.
+* writebuf: Screen-Exchange.
+* writelock: Writelock.
+* xoff: XON/XOFF.
+* xon: XON/XOFF.
+* zombie: Zombie.
+
+
+File: screen.info, Node: Keystroke Index, Prev: Command Index, Up: Top
+
+Keystroke Index
+***************
+
+ This is a list of the default key bindings.
+
+ The leading escape character (*note Command Character::.) has been
+omitted from the key sequences, since it is the same for all bindings.
+
+* Menu:
+
+* ": Select.
+* ': Select.
+* .: Dump Termcap.
+* 0...9: Select.
+* :: Colon.
+* <: Screen-Exchange.
+* =: Screen-Exchange.
+* >: Screen-Exchange.
+* ?: Help.
+* {: History.
+* a: Command Character.
+* A: Title Command.
+* c: Screen Command.
+* C: Clear.
+* C-a: Other Window.
+* C-c: Screen Command.
+* C-d: Detach.
+* C-f: Flow.
+* C-g: Bell.
+* C-h: Hardcopy.
+* C-i: Info.
+* C-k: Kill.
+* C-l: Redisplay.
+* C-m: Last Message.
+* C-n: Next and Previous.
+* C-p: Next and Previous.
+* C-q: XON/XOFF.
+* C-r: Wrap.
+* C-s: XON/XOFF.
+* C-t: Time.
+* C-v: Digraph.
+* C-w: Windows.
+* C-x: Lock.
+* C-z: Suspend.
+* C-[: Copy.
+* C-\: Quit.
+* C-]: Paste.
+* D: Power Detach.
+* d: Detach.
+* ESC: Copy.
+* f: Flow.
+* H: Log.
+* h: Hardcopy.
+* i: Info.
+* k: Kill.
+* L: Login.
+* l: Redisplay.
+* m: Last Message.
+* M: Monitor.
+* N: Number.
+* n: Next and Previous.
+* p: Next and Previous.
+* q: XON/XOFF.
+* r: Wrap.
+* s: XON/XOFF.
+* SPC: Next and Previous.
+* t: Time.
+* v: Version.
+* w: Windows.
+* W: Window Size.
+* x: Lock.
+* Z: Reset.
+* z: Suspend.
+* [: Copy.
+* ]: Paste.
+
+
diff --git a/doc/screen.texinfo b/doc/screen.texinfo
new file mode 100644
index 0000000..a500018
--- /dev/null
+++ b/doc/screen.texinfo
@@ -0,0 +1,4061 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename screen.info
+@settitle Screen User's Manual
+@finalout
+@setchapternewpage odd
+@c %**end of header
+@set version 3.7.0
+
+@c For examples, use a literal escape in info.
+@ifinfo
+@set esc 
+@end ifinfo
+@iftex
+@set esc <ESC>
+@end iftex
+
+@ifinfo
+This file documents the @code{Screen} virtual terminal manager.
+
+Copyright (c) 1993 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end ifinfo
+
+@titlepage
+@title Screen
+@subtitle The virtual terminal manager
+@subtitle for Version @value{version}
+@subtitle Oct 1995
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1993 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end titlepage
+
+@node Top, Overview, (dir), (dir)
+
+@ifinfo
+@top Screen
+This file documents the @code{Screen} virtual terminal manager, version
+@value{version}.
+@end ifinfo
+
+@menu
+* Overview:: Preliminary information.
+* Getting Started:: An introduction to @code{screen}.
+* Invoking Screen:: Command line options for @code{screen}.
+* Customization:: The @file{.screenrc} file.
+* Commands:: List all of the commands.
+* New Window:: Running a program in a new window.
+* Selecting:: Selecting a window to display.
+* Session Management:: Suspending or detaching a session.
+* Window Settings:: titles, logging, etc.
+* Virtual Terminal:: Controlling the @code{screen} VT100 emulation.
+* Copy and Paste:: Exchanging text between windows and sessions.
+* Subprocess Execution:: I/O filtering with @code{exec}.
+* Key Binding:: Binding commands to keys.
+* Flow Control:: Trap or pass flow control characters.
+* Termcap:: Tweaking your terminal's termcap entry.
+* Message Line:: The @code{screen} message line.
+* Logging:: Keeping a record of your session.
+* Startup:: Functions only useful at @code{screen} startup.
+* Miscellaneous:: Various other commands.
+* Environment:: Environment variables used by @code{screen}.
+* Files:: Files used by @code{screen}.
+* Credits:: Who's who of @code{screen}.
+* Bugs:: What to do if you find a bug.
+* Installation:: Getting @code{screen} running on your system.
+* Concept Index:: Index of concepts.
+* Command Index:: Index of all @code{screen} commands.
+* Keystroke Index:: Index of default key bindings.
+@end menu
+
+@node Overview, Getting Started, Top, Top
+@chapter Overview
+@cindex overview
+
+Screen is a full-screen window manager that multiplexes a physical
+terminal between several processes, typically interactive shells. Each
+virtual terminal provides the functions of the DEC VT100 terminal and,
+in addition, several control functions from the ANSI X3.64 (ISO 6429)
+and ISO 2022 standards (e.g. insert/delete line and support for multiple
+character sets). There is a scrollback history buffer for each virtual
+terminal and a copy-and-paste mechanism that allows the user to move
+text regions between windows.
+
+When @code{screen} is called, it creates a single window with a shell in
+it (or the specified command) and then gets out of your way so that you
+can use the program as you normally would. Then, at any time, you can
+create new (full-screen) windows with other programs in them (including
+more shells), kill the current window, view a list of the active
+windows, turn output logging on and off, copy text between windows, view
+the scrollback history, switch between windows, etc. All windows run
+their programs completely independent of each other. Programs continue
+to run when their window is currently not visible and even when the
+whole screen session is detached from the users terminal.
+
+When a program terminates, @code{screen} (per default) kills the window
+that contained it. If this window was in the foreground, the display
+switches to the previously displayed window; if none are left,
+@code{screen} exits.
+
+Everything you type is sent to the program running in the current
+window. The only exception to this is the one keystroke that is used to
+initiate a command to the window manager. By default, each command
+begins with a control-a (abbreviated @kbd{C-a} from now on), and is
+followed by one other keystroke. The command character (@pxref{Command
+Character}) and all the key bindings (@pxref{Key Binding}) can be fully
+customized to be anything you like, though they are always two
+characters in length.
+
+The standard way to create a new window is to type @kbd{C-a c}. This
+creates a new window running a shell and switches to that window
+immediately, regardless of the state of the process running in the
+current window. Similarly, you can create a new window with a custom
+command in it by first binding the command to a keystroke (in your
+@file{.screenrc} file or at the @kbd{C-a :} command line) and then using it
+just like the @kbd{C-a c} command. In addition, new windows can be created by
+running a command like:
+
+@example
+screen emacs prog.c
+@end example
+
+@noindent
+from a shell prompt within a previously created window. This will not
+run another copy of @code{screen}, but will instead supply the command
+name and its arguments to the window manager (specified in the $STY environment
+variable) who will use it to create the new window. The above example would
+start the @code{emacs} editor (editing @file{prog.c}) and switch to its window.
+
+If @file{/etc/utmp} is writable by @code{screen}, an appropriate record
+will be written to this file for each window, and removed when the
+window is closed. This is useful for working with @code{talk},
+@code{script}, @code{shutdown}, @code{rsend}, @code{sccs} and other
+similar programs that use the utmp file to determine who you are. As
+long as @code{screen} is active on your terminal, the terminal's own
+record is removed from the utmp file. @xref{Login}.
+
+@node Getting Started, Invoking Screen, Overview, Top
+@chapter Getting Started
+@cindex introduction
+
+Before you begin to use @code{screen} you'll need to make sure you have
+correctly selected your terminal type, just as you would for any other
+termcap/terminfo program. (You can do this by using @code{tset},
+@code{qterm}, or just @code{set term=mytermtype}, for example.)
+
+If you're impatient and want to get started without doing a lot more
+reading, you should remember this one command: @kbd{C-a ?} (@pxref{Key
+Binding}). Typing these two characters will display a list of the
+available @code{screen} commands and their bindings. Each keystroke is
+discussed in the section on keystrokes (@pxref{Default Key Bindings}).
+Another section (@pxref{Customization}) deals with the contents of your
+@file{.screenrc}.
+
+If your terminal is a ``true'' auto-margin terminal (it doesn't allow
+the last position on the screen to be updated without scrolling the
+screen) consider to use a version of your terminal's termcap that has
+automatic margins turned @emph{off}. This will ensure an accurate
+and optimal update of the screen in all circumstances. Most terminals
+nowadays have ``magic'' margins (automatic margins plus usable last
+column). This is the VT100 style type and perfectly suited for
+@code{screen}.
+If all you've got is a ``true'' auto-margin terminal @code{screen}
+will be content to use it, but updating a character put into the last
+position on the screen may not be possible until the screen scrolls or
+the character is moved into a safe position in some other way. This
+delay can be shortened by using a terminal with insert-character
+capability.
+
+@xref{Special Capabilities}, for more information about telling
+@code{screen} what kind of terminal you have.
+
+@node Invoking Screen, Customization, Getting Started, Top
+@chapter Invoking @code{Screen}
+@cindex invoking
+@cindex options
+@cindex command line options
+
+Screen has the following command-line options:
+
+@table @samp
+@item -a
+Include @emph{all} capabilities (with some minor exceptions) in each
+window's termcap, even if @code{screen} must redraw parts of the display
+in order to implement a function.
+
+@item -A
+Adapt the sizes of all windows to the size of the display. By default,
+@code{screen} may try to restore its old window sizes when attaching to
+resizable terminals (those with @samp{WS} in their descriptions, e.g.
+@code{suncmd} or some varieties of @code{xterm}).
+
+@item -c @var{file}
+Use @var{file} as the user's configuration file instead of the default
+of @file{$HOME/.screenrc}.
+
+@item -d [@var{pid.sessionname}]
+@itemx -D [@var{pid.sessionname}]
+Do not start @code{screen}, but instead detach a @code{screen} session
+running elsewhere (@pxref{Detach}). @samp{-d} has the same effect as
+typing @kbd{C-a d} from the controlling terminal for the session.
+@samp{-D} is the equivalent to the power detach key. If no session can
+be detached, this option is ignored. The combination @code{screen -D
+-r} can be used to log out from a remote terminal and transport the
+session running there to your current terminal.
+@emph{Note}: It is a good idea to check the status of your sessions
+with @code{screen -list} before using this option.
+
+@item -e @var{xy}
+Set the command character to @var{x}, and the character generating a
+literal command character (when typed after the command character) to
+@var{y}. The defaults are @kbd{C-a} and @kbd{a}, which can be specified
+as @samp{-e^Aa}. When creating a @code{screen} session, this option
+sets the default command caracter. In a multiuser session all users
+added will start off with this command character. But when attaching
+to an already running session, this option only changes the command
+character of the attaching user.
+This option is equivalent to the commands @code{defescape} or
+@code{escape} respectively. (@pxref{Command Character}).
+
+@item -f
+@itemx -fn
+@itemx -fa
+Set flow-control to on, off, or automatic switching mode, respectively.
+This option is equivalent to the @code{defflow} command (@pxref{Flow
+Control}).
+
+@item -h @var{num}
+Set the history scrollback buffer to be @var{num} lines high.
+Equivalent to the @code{defscrollback} command (@pxref{Copy}).
+
+@item -i
+Cause the interrupt key (usually @kbd{C-c}) to interrupt the display
+immediately when flow control is on. This option is equivalent to the
+@code{interrupt} argument to the @code{defflow} command (@pxref{Flow
+Control}). Its use is discouraged.
+
+@item -l
+@itemx -ln
+Turn login mode on or off (for @file{/etc/utmp} updating). This option
+is equivalent to the @code{deflogin} command (@pxref{Login}).
+
+@item -ls
+@itemx -list
+Do not start @code{screen}, but instead print a list of session
+identification strings (usually of the form @var{pid.tty.host};
+@pxref{Session Name}). Sessions marked @samp{detached} can be resumed
+with @code{screen -r}. Those marked @samp{attached} are running and
+have a controlling terminal. Sessions marked as @samp{dead} should be
+thoroughly checked and removed. Ask your system administrator if you are
+not sure why they died. Remove sessions with the @samp{-wipe} option.
+
+@item -L
+Tell @code{screen} that your auto-margin terminal allows programs to
+write to the last column of the last row of the screen without
+scrolling. This can also be set in your @file{.screenrc} by specifying
+@samp{xn} in a @code{termcap} command (@pxref{Termcap}).
+
+@item -m
+Tell @code{screen} to ignore the @code{$STY} environment variable. When
+this option is used, a new session will always be created, regardless of
+whether @code{screen} is being called from within another @code{screen}
+session or not.
+
+@item -r [@var{pid.sessionname}]
+@itemx -r @var{sessionowner/[pid.sessionname]}
+Resume a detached @code{screen} session. No other options (except
+@samp{-d} or @samp{-D}) may be specified, though the session name
+(@pxref{Session Name}) may be needed to distinguish between multiple
+detached @code{screen} sessions.
+The second form is used to connect to another users screen session which
+runs in multi-user mode. This indicates that screen should look for
+sessions in another users directory. This requires setuid-root.
+
+@item -R
+Resume the first appropriate detached @code{screen} session. If
+successful, all other command-line options are ignored. If no detached
+session exists, start a new session using the specified options, just as
+if @samp{-R} had not been specified. This option is set by default if
+screen is run as a login-shell.
+
+@item -s @var{program}
+Set the default shell to be @var{program}. By default, @code{screen}
+uses the value of the environment variable @code{$SHELL}, or
+@file{/bin/sh} if it is not defined. This option is equivalent to the
+@code{shell} command (@pxref{Shell}).
+
+@item -S @var{sessionname}
+Set the name of the new session to @var{sessionname}. This option can
+be used to specify a meaningful name for the session in place of the
+default @var{tty.host} suffix. This name identifies the session for the
+@code{screen -list} and @code{screen -r} commands. This option is
+equivalent to the @code{sessionname} command (@pxref{Session Name}).
+
+@item -t @var{name}
+Set the title (name) for the default shell or specified program.
+This option is equivalent to the @code{shelltitle} command
+(@pxref{Shell}).
+
+@item -v
+Print the version number.
+
+@item -wipe
+List available screens like @code{screen -ls}, but remove destroyed
+sessions instead of marking them as @samp{dead}.
+
+@item -x
+Attach to a session which is already attached elsewhere (multi-display
+mode).
+@end table
+
+@node Customization, Commands, Invoking Screen, Top
+@chapter Customizing @code{Screen}
+@cindex customization
+
+You can modify the default settings for @code{screen} to fit your tastes
+either through a personal @file{.screenrc} file which contains commands
+to be executed at startup, or on the fly using the @code{colon} command.
+
+@menu
+* Startup Files:: The @file{.screenrc} file.
+* Colon:: Entering customization commands interactively.
+@end menu
+
+@node Startup Files, Colon, , Customization
+@section The @file{.screenrc} file
+@cindex .screenrc
+@cindex screenrc
+When @code{screen} is invoked, it executes initialization commands from
+the files @file{.screenrc} in the user's home directory and
+@file{/usr/local/etc/screenrc}. These defaults can be overridden in the
+following ways:
+For the global screenrc file @code{screen} searches for the environment
+variable @code{$SYSSCREENRC} (this override feature may be disabled at
+compile-time). The user specific screenrc file is
+searched for in @code{$SCREENRC}, then
+@file{@code{$HOME}/.screenrc}. The command line option @samp{-c}
+specifies which file to use (@pxref{Invoking Screen}. Commands in these
+files are used to set options, bind commands to keys, and to
+automatically establish one or more windows at the beginning of
+your @code{screen} session. Commands are listed one per line, with
+empty lines being ignored. A command's arguments are separated by tabs
+or spaces, and may be surrounded by single or double quotes. A @samp{#}
+turns the rest of the line into a comment, except in quotes.
+Unintelligible lines are warned about and ignored. Commands may contain
+references to environment variables. The syntax is the shell-like
+@code{$VAR} or @code{$@{VAR@}}. Note that this causes incompatibility
+with previous @code{screen} versions, as now the '$'-character has to be
+protected with '\' if no variable substitution is intended. A string in
+single-quotes is also protected from variable substitution.
+
+Two configuration files are shipped as examples with your screen
+distribution: @file{etc/screenrc} and @file{etc/etcscreenrc}. They
+contain a number of useful examples for various commands.
+
+@node Colon, , Startup Files, Customization
+@section Colon
+Customization can also be done online, with this command:
+
+@kindex :
+@deffn Command colon
+(@kbd{C-a :})@*
+Allows you to enter @file{.screenrc} command lines. Useful for
+on-the-fly modification of key bindings, specific window creation and
+changing settings. Note that the @code{set} keyword no longer exists,
+as of version 3.3. Change default settings with commands starting with
+@samp{def}. You might think of this as the @code{ex} command mode of
+@code{screen}, with @code{copy} as its @code{vi} command mode
+(@pxref{Copy and Paste}).
+@end deffn
+
+@node Commands, New Window, Customization, Top
+@chapter Commands
+
+A command in @code{screen} can either be bound to a key, invoked from a
+screenrc file, or called from the @code{colon} prompt
+(@pxref{Customization}). As of version 3.3, all commands can be bound
+to keys, although some may be less useful than others.
+For a number of real life working examples of the most important
+commands see the files @file{etc/screenrc} and @file{etc/etcscreenrc}
+of your screen distribution.
+
+In this manual, a command definition looks like this:
+
+@table @asis
+@item -- Command: command [-n] ARG1 [ARG2] @dots{}
+(@var{keybindings})@*
+This command does something, but I can't remember what.
+@end table
+
+An argument in square brackets (@samp{[]}) is optional. Many commands
+take an argument of @samp{on} or @samp{off}, which is indicated as
+@var{state} in the definition.
+
+@menu
+* Default Key Bindings:: @code{screen} keyboard commands.
+* Command Summary:: List of all commands.
+@end menu
+
+@node Default Key Bindings, Command Summary, , Commands
+@section Default Key Bindings
+
+As mentioned previously, each keyboard command consists of a
+@kbd{C-a} followed by one other character. For your convenience, all
+commands that are bound to lower-case letters are also bound to their
+control character counterparts (with the exception of @kbd{C-a a}; see
+below). Thus, both @kbd{C-a c} and @kbd{C-a C-c} can be used to create
+a window.
+
+The following table shows the default key bindings:
+
+@table @asis
+@item @kbd{C-a '}
+@itemx @kbd{C-a "}
+(select)@*
+Prompt for a window identifier and switch.
+@xref{Selecting}.
+
+@item @kbd{C-a 0@dots{}9}
+(select 0@dots{}select 9)@*
+Switch to window number 0@dots{}9. @xref{Selecting}.
+
+@item @kbd{C-a C-a}
+(other)@*
+Toggle to the window displayed previously. @xref{Selecting}.
+
+@item @kbd{C-a a}
+(meta)@*
+Send the command character (C-a) to window. See @code{escape} command.
+@xref{Command Character}.
+
+@item @kbd{C-a A}
+(title)@*
+Allow the user to enter a title for the current window.
+@xref{Naming Windows}.
+
+@item @kbd{C-a b}
+itemx @kbd{C-a C-b}
+(break)@*
+Send a break to the tty.
+@xref{Break}.
+
+@item @kbd{C-a B}
+(pow_break)@*
+Close and reopen the tty-line.
+@xref{Break}.
+
+@item @kbd{C-a c}
+@itemx @kbd{C-a C-c}
+(screen)@*
+Create a new window with a shell and switch to that window.
+@xref{Screen Command}.
+
+@item @kbd{C-a C}
+(clear)@*
+Clear the screen. @xref{Clear}.
+
+@item @kbd{C-a d}
+@itemx @kbd{C-a C-d}
+(detach)@*
+Detach @code{screen} from this terminal. @xref{Detach}.
+
+@item @kbd{C-a D D}
+(pow_detach)@*
+Detach and logout. @xref{Power Detach}.
+
+@item @kbd{C-a f}
+@itemx @kbd{C-a C-f}
+(flow)@*
+Cycle flow among @samp{on}, @samp{off} or @samp{auto}. @xref{Flow}.
+
+@item @kbd{C-a C-g}
+(vbell)@*
+Toggle visual bell mode. @xref{Bell}.
+
+@item @kbd{C-a h}
+(hardcopy)@*
+Write a hardcopy of the current window to the file ``hardcopy.@var{n}''.
+@xref{Hardcopy}.
+
+@item @kbd{C-a H}
+(log)@*
+Toggle logging of the current window to the file ``screenlog.@var{n}''.
+@xref{Log}.
+
+@item @kbd{C-a i}
+@itemx @kbd{C-a C-i}
+(info)@*
+Show info about the current window. @xref{Info}.
+
+@item @kbd{C-a k}
+@itemx @kbd{C-a C-k}
+(kill)@*
+Destroy the current window. @xref{Kill}.
+
+@item @kbd{C-a l}
+@itemx @kbd{C-a C-l}
+(redisplay)@*
+Fully refresh the current window. @xref{Redisplay}.
+
+@item @kbd{C-a L}
+(login)@*
+Toggle the current window's login state. @xref{Login}.
+
+@item @kbd{C-a m}
+@itemx @kbd{C-a C-m}
+(lastmsg)@*
+Repeat the last message displayed in the message line.
+@xref{Last Message}.
+
+@item @kbd{C-a M}
+(monitor)
+Toggle monitoring of the current window. @xref{Monitor}.
+
+@item @kbd{C-a @key{SPC}}
+@itemx @kbd{C-a n}
+@itemx @kbd{C-a C-n}
+(next)@*
+Switch to the next window. @xref{Selecting}.
+
+@item @kbd{C-a N}
+(number)@*
+Show the number (and title) of the current window. @xref{Number}.
+
+@item @kbd{C-a p}
+@itemx @kbd{C-a C-p}
+@itemx @kbd{C-a C-h}
+@itemx @kbd{C-a @key{BackSpace}}
+(prev)@*
+Switch to the previous window (opposite of @kbd{C-a n}).
+@xref{Selecting}.
+
+@item @kbd{C-a q}
+@itemx @kbd{C-a C-q}
+(xon)@*
+Send a ^Q (ASCII XON) to the current window. @xref{XON/XOFF}.
+
+@item @kbd{C-a r}
+@itemx @kbd{C-a C-r}
+(wrap)@*
+Toggle the current window's line-wrap setting (turn the current window's
+automatic margins on or off). @xref{Wrap}.
+
+@item @kbd{C-a s}
+@itemx @kbd{C-a C-s}
+(xoff)@*
+Send a ^S (ASCII XOFF) to the current window. @xref{XON/XOFF}.
+
+@item @kbd{C-a t}
+@itemx @kbd{C-a C-t}
+(time)@*
+Show the load average and xref. @xref{Time}.
+
+@item @kbd{C-a v}
+(version)@*
+Display the version and compilation date. @xref{Version}.
+
+@item @kbd{C-a C-v}
+(digraph)@*
+Enter digraph. @xref{Digraph}.
+
+@item @kbd{C-a w}
+@itemx @kbd{C-a C-w}
+(windows)@*
+Show a list of active windows. @xref{Windows}.
+
+@item @kbd{C-a W}
+(width)@*
+Toggle between 80 and 132 columns. @xref{Window Size}.
+
+@item @kbd{C-a x}
+@itemx @kbd{C-a C-x}
+(lockscreen)@*
+Lock your terminal. @xref{Lock}.
+
+@item @kbd{C-a z}
+@itemx @kbd{C-a C-z}
+(suspend)@*
+Suspend @code{screen}. @xref{Suspend}.
+
+@item @kbd{C-a Z}
+(reset)@*
+Reset the virtual terminal to its ``power-on'' values.
+@xref{Reset}.
+
+@item @kbd{C-a .}
+(dumptermcap)@*
+Write out a @file{.termcap} file. @xref{Dump Termcap}.
+
+@item @kbd{C-a ?}
+(help)@*
+Show key bindings. @xref{Help}.
+
+@item @kbd{C-a C-\}
+(quit)@*
+Kill all windows and terminate @code{screen}. @xref{Quit}.
+
+@item @kbd{C-a :}
+(colon)@*
+Enter a command line. @xref{Colon}.
+
+@item @kbd{C-a [}
+@itemx @kbd{C-a C-[}
+@itemx @kbd{C-a @key{ESC}}
+(copy)@*
+Enter copy/scrollback mode. @xref{Copy}.
+
+@item @kbd{C-a ]}
+@itemx @kbd{C-a C-]}
+(paste .)@*
+Write the contents of the paste buffer to the stdin queue of the
+current window. @xref{Paste}.
+
+@item @kbd{C-a @{}
+(history)@*
+Copy and paste a previous (command) line. @xref{History}.
+
+@item @kbd{C-a >}
+(writebuf)@*
+Write the paste buffer out to the screen-exchange file.
+@xref{Screen-Exchange}.
+
+@item @kbd{C-a <}
+(readbuf)@*
+Read the screen-exchange file into the paste buffer.
+@xref{Screen-Exchange}.
+
+@item @kbd{C-a =}
+(removebuf)@*
+Delete the screen-exchange file. @xref{Screen-Exchange}.
+
+@item @kbd{C-a _}
+(silence)@*
+Start/stop monitoring the current window for inactivity. @xref{Silence},
+
+@item @kbd{C-a ,}
+(license)@*
+Show the copyright page.
+@end table
+
+@node Command Summary, , Default Key Bindings, Commands
+@section Command Summary
+@cindex command summary
+
+@table @code
+@item acladd @var{usernames}
+Allow other users in this session. @xref{Multiuser Session}.
+@item aclchg @var{usernames permbits list}
+Change a user's permissions. @xref{Multiuser Session}.
+@item acldel @var{username}
+Disallow other user in this session. @xref{Multiuser Session}.
+@item activity @var{message}
+Set the activity notification message. @xref{Monitor}.
+@item allpartial @var{state}
+Set all windows to partial refresh. @xref{Redisplay}.
+@item at @var{[ident][@kbd{#}@var{|}@kbd{*}@var{|}@kbd{%}] command [args]}
+Execute a command at other displays or windows. @xref{At}.
+@item autodetach @var{state}
+Automatically detach the session on SIGHUP. @xref{Detach}.
+@item autonuke @var{state}
+Enable a clear screen to discard unwritten output. @xref{Autonuke}.
+@item bell_msg @var{message}
+Set the bell notification message. @xref{Bell}.
+@item bind @var{key [command [args]]}
+Bind a command to a key. @xref{Bind}.
+@item bindkey @var{[opts] [string [cmd args]]}
+Bind a string to a series of keystrokes. @xref{Bindkey}.
+@item break @var{[duration]}
+Send a break signal to the current window. @xref{Break}.
+@item bufferfile @var{[exchange-file]}
+Select a file for screen-exchange. @xref{Screen-Exchange}.
+@item c1 @var{[state]}
+Change c1 code processing. @xref{Character Processing}.
+@item charset @var{set}
+Change character set slot designation. @xref{Character Processing}.
+@item chdir @var{[directory]}
+Change the current directory for future windows. @xref{Chdir}.
+@item clear
+Clear the window screen. @xref{Clear}.
+@item colon
+Enter a @code{screen} command. @xref{Colon}.
+@item command
+Simulate the screen escape key. @xref{Command Character}.
+@item console @var{[state]}
+Grab or ungrab console output. @xref{Console}.
+@item copy
+Enter copy mode. @xref{Copy}.
+@item copy_reg @var{[key]}
+Removed. Use @code{paste} instead. @xref{Registers}.
+@item crlf @var{state}
+Select line break behavior for copying. @xref{Line Termination}.
+@item debug @var{state}
+Suppress/allow debugging output. @xref{Debug}.
+@item defautonuke @var{state}
+Select default autonuke behavior. @xref{Autonuke}.
+@item defc1 @var{state}
+Select default c1 processing behavior. @xref{Character Processing}.
+@item defcharset @var{[set]}
+Change defaul character set slot designation. @xref{Character Processing}.
+@item defescape @var{xy}
+Set the default command and @code{meta} characters. @xref{Command Character}.
+@item defflow @var{fstate}
+Select default flow control behavior. @xref{Flow}.
+@item defgr @var{state}
+Select default GR processing behavior. @xref{Character Processing}.
+@item defhstatus @var{[status]}
+Select default window hardstatus line. @xref{Hardstatus}.
+@item defkanji @var{wtype}
+Select default GR processing behavior. @xref{Character Processing}.
+@item deflogin @var{state}
+Select default utmp logging behavior. @xref{Login}.
+@item defmode @var{mode}
+Select default file mode for ptys. @xref{Mode}.
+@item defmonitor @var{state}
+Select default activity monitoring behavior. @xref{Monitor}.
+@item defobuflimit @var{limit}
+Select default output buffer limit. @xref{Obuflimit}.
+@item defscrollback @var{num}
+Set default lines of scrollback. @xref{Scrollback}.
+@item defwrap @var{state}
+Set default line-wrapping behavior. @xref{Wrap}.
+@item defwritelock @var{on|off|auto}
+Set default writelock behavior. @xref{Multiuser}.
+@item defzombie @var{[keys]}
+Keep dead windows. @xref{Zombie}.
+@item detach
+Disconnect @code{screen} from the terminal. @xref{Detach}.
+@item digraph
+Enter digraph sequence. @xref{Digraph}.
+@item dumptermcap
+Write the window's termcap entry to a file. @xref{Dump Termcap}.
+@item echo [-n] @var{message}
+Display a message on startup. @xref{Startup}.
+@item escape @var{xy}
+Set the command and @code{meta} characters. @xref{Command Character}.
+@item exec @var{[[fdpat] command [args ...]]}
+Run a subprocess (filter). @xref{Exec}.
+@item flow @var{[fstate]}
+Set flow control behavior. @xref{Flow}.
+@item gr @var{[state]}
+Change GR charset processing. @xref{Character Processing}.
+@item hardcopy
+Write out the contents of the current window. @xref{Hardcopy}.
+@item hardcopy_append @var{state}
+Append to hardcopy files. @xref{Hardcopy}.
+@item hardcopydir @var{directory}
+Place, where to dump hardcopy files. @xref{Hardcopy}.
+@item hardstatus @var{[state]}
+Use the hardware status line. @xref{Hardware Status Line}.
+@item height @var{[lines]}
+Set display height. @xref{Window Size}.
+@item help
+Display current key bindings. @xref{Help}.
+@item history
+Find previous command beginning @dots{}. @xref{History}.
+@item info
+Display terminal settings. @xref{Info}.
+@item ins_reg @var{[key]}
+Removed, use @code{paste} instead. @xref{Registers}.
+@item kanji @var{wtype [dtype]}
+Set the kanji type of a window. @xref{Character Processing}.
+@item kill
+Destroy the current window. @xref{Kill}.
+@item lastmsg
+Redisplay the last message. @xref{Last Message}.
+@item license
+Display licensing information. @xref{Startup}.
+@item lockscreen
+Lock the controlling terminal. @xref{Lock}.
+@item log @var{[state]}
+Log all output in the current window. @xref{Log}.
+@item logfile @var{filename}
+Place where to collect logfiles. @xref{Log}.
+@item login @var{[state]}
+Log the window in @file{/etc/utmp}. @xref{Login}.
+@item mapdefault
+Use only the default mapping table for the next keystroke. @xref{Bindkey Control}.
+@item mapnotnext
+Don't try to do keymapping on the next keystroke. @xref{Bindkey Control}.
+@item maptimeout @var{timo}
+Set the intercharacter timeout used for keymapping. @xref{Bindkey Control}.
+@item markkeys @var{string}
+Rebind keys in copy mode. @xref{Copy Mode Keys}.
+@item meta
+Insert the command character. @xref{Command Character}.
+@item monitor @var{[state]}
+Monitor activity in window. @xref{Monitor}.
+@item msgminwait @var{sec}
+Set minimum message wait. @xref{Message Wait}.
+@item msgwait @var{sec}
+Set default message wait. @xref{Message Wait}.
+@item multiuser @var{state}
+Go into single or multi user mode. @xref{Multiuser Session}.
+@item nethack @var{state}
+Use @code{nethack}-like error messages. @xref{Nethack}.
+@item next
+Switch to the next window. @xref{Selecting}.
+@item number @var{[n]}
+Change/display the current window's number. @xref{Number}.
+@item obuflimit @var{[limit]}
+Select output buffer limit. @xref{Obuflimit}.
+@item other
+Switch to the window you were in last. @xref{Selecting}.
+@item partial @var{state}
+Set window to partial refresh. @xref{Redisplay}.
+@item password @var{[crypted_pw]}
+Set reattach password. @xref{Detach}.
+@item paste @var{[src_regs [dest_reg]]}
+Paste contents of paste buffer or registers somewhere. @xref{Paste}.
+@item pastefont @var{[state]}
+Include font information in the paste buffer. @xref{Paste}.
+@item pow_break
+Close and Reopen the window's terminal. @xref{Break}.
+@item pow_detach
+Detach and hang up. @xref{Power Detach}.
+@item pow_detach_msg @var{[message]}
+Set message displayed on @code{pow_detach}. @xref{Power Detach}.
+@item prev
+Switch to the previous window. @xref{Selecting}.
+@item printcmd @var{[cmd]}
+Set a command for VT100 printer port emulation. @xref{Printcmd}.
+@item process @var{[key]}
+Treat a register as input to @code{screen}. @xref{Registers}.
+@item quit
+Kill all windows and exit. @xref{Quit}.
+@item readbuf
+Read the paste buffer from the screen-exchange file. @xref{Screen-Exchange}.
+@item readreg @var{[reg [file]]}
+Load a register from paste buffer or file. @xref{Registers}.
+@item redisplay
+Redisplay the current window. @xref{Redisplay}.
+@item register @var{key string}
+Store a string to a register. @xref{Registers}.
+@item removebuf
+Delete the screen-exchange file. @xref{Screen-Exchange}.
+@item reset
+Reset the terminal settings for the window. @xref{Reset}.
+@item screen @var{[opts] [n] [cmd [args]]}
+Create a new window. @xref{Screen Command}.
+@item scrollback @var{num}
+Set size of scrollback buffer. @xref{Scrollback}.
+@item select @var{[n]}
+Switch to a specified window. @xref{Selecting}.
+@item sessionname @var{[name]}
+Name this session. @xref{Session Name}.
+@item setenv @var{[var [string]]}
+Set an environment variable for new windows. @xref{Setenv}.
+@item shell @var{command}
+Set the default program for new windows. @xref{Shell}.
+@item shelltitle @var{title}
+Set the default name for new windows. @xref{Shell}.
+@item silence @var{[state|seconds]}
+Monitor a window for inactivity. @xref{Silence}.
+@item silencewait @var{seconds}
+Default timeout to trigger an inactivity notify. @xref{Silence}.
+@item sleep @var{num}
+Pause during startup. @xref{Startup}.
+@item slowpaste @var{msec}
+Slow down pasting in windows. @xref{Paste}.
+@item sorendition @var{[attr [color]]}
+Change text highlighting. @xref{Sorendition}.
+@item startup_message @var{state}
+Display copyright notice on startup. @xref{Startup}.
+@item stuff @var{string}
+Stuff a string in the input buffer of a window. @xref{Paste}.
+@item suspend
+Put session in background. @xref{Suspend}.
+@item term @var{term}
+Set @code{$TERM} for new windows. @xref{Term}.
+@item termcap @var{term terminal-tweaks [window-tweaks]}
+Tweak termcap entries for best performance. @xref{Termcap Syntax}.
+@item terminfo @var{term terminal-tweaks [window-tweaks]}
+Ditto, for terminfo systems. @xref{Termcap Syntax}.
+@item termcapinfo @var{term terminal-tweaks [window-tweaks]}
+Ditto, for both systems. @xref{Termcap Syntax}.
+@item time
+Display time and load average. @xref{Time}.
+@item title @var{[windowtitle]}
+Set the name of the current window. @xref{Title Command}.
+@item unsetenv @var{var}
+Unset environment variable for new windows. @xref{Setenv}.
+@item vbell @var{[state]}
+Use visual bell. @xref{Bell}.
+@item vbell_msg @var{[message]}
+Set vbell message. @xref{Bell}.
+@item vbellwait @var{sec}
+Set delay for vbell message. @xref{Bell}.
+@item version
+Display @code{screen} version. @xref{Version}.
+@item wall @var{message}
+Write a message to all displays. @xref{Multiuser Session}.
+@item width @var{[num]}
+Set the width of the window. @xref{Window Size}.
+@item windows
+List active windows. @xref{Windows}.
+@item wrap @var{[state]}
+Control line-wrap behavior. @xref{Wrap}.
+@item writebuf
+Write paste buffer to screen-exchange file. @xref{Screen-Exchange}.
+@item writelock @var{on|off|auto}
+Grant exclusive write permission. @xref{Multiuser Session}.
+@item xoff
+Send an XOFF character. @xref{XON/XOFF}.
+@item xon
+Send an XON character. @xref{XON/XOFF}.
+@item zombie @var{[keys]}
+Keep dead windows. @xref{Zombie}.
+@end table
+
+@node New Window, Selecting, Commands, Top
+@chapter New Window
+
+This section describes the commands for creating a new window for
+running programs. When a new window is created, the first available
+number from the range 0@dots{}9 is assigned to it. There can be no more
+than 10 windows active at any one time unless @code{screen} was compiled
+with a higher MAXWIN setting.
+
+@menu
+* Chdir:: Change the working directory for new windows.
+* Screen Command:: Create a new window.
+* Setenv:: Set environment variables for new windows.
+* Shell:: Parameters for shell windows.
+* Term:: Set the terminal type for new windows.
+@end menu
+
+@node Chdir, Screen Command, , New Window
+@section Chdir
+@deffn Command chdir [directory]
+(none)@*
+Change the current directory of @code{screen} to the specified directory
+or, if called without an argument, to your home directory (the value of
+the environment variable @code{$HOME}). All windows that are created by means
+of the @code{screen} command from within @file{.screenrc} or by means of
+@kbd{C-a : screen @dots{}} or @kbd{C-a c} use this as their default
+directory. Without a @code{chdir} command, this would be the directory
+from which @code{screen} was invoked. Hardcopy and log files are always
+written to the @emph{window's} default directory, @emph{not} the current
+directory of the process running in the window. You can use this
+command multiple times in your @file{.screenrc} to start various windows
+in different default directories, but the last @code{chdir} value will
+affect all the windows you create interactively.
+@end deffn
+
+@node Screen Command, Setenv, Chdir, New Window
+@section Screen Command
+@kindex c
+@kindex C-c
+@deffn Command screen [opts] [n] [cmd [args]]
+(@kbd{C-a c}, @kbd{C-a C-c})@*
+Establish a new window. The flow-control options (@samp{-f}, @samp{-fn}
+and @samp{-fa}), title option (@samp{-t}), login options
+(@samp{-l} and @samp{-ln}) , terminal type option (@samp{-T @var{term}})
+and scrollback option (@samp{-h @var{num}}) may be specified for each
+command. If an optional number @var{n} in the range 0@dots{}9 is given,
+the window number @var{n} is assigned to the newly created window (or,
+if this number is already in-use, the next available number). If a
+command is specified after @code{screen}, this command (with the given
+arguments) is started in the window; otherwise, a shell is created.
+
+If a tty (character special device) name (e.g. @samp{/dev/ttyS0})
+is specified as cmd, then the window is directly connected to this
+device. This is similar to the cmd @samp{kermit -l /dev/ttyS0 -c} but
+saves resources and is more efficient.
+@end deffn
+
+Thus, if your @file{.screenrc} contains the lines
+
+@example
+# example for .screenrc:
+screen 1
+screen -fn -t foobar 2 telnet foobar
+@end example
+
+@noindent
+@code{screen} creates a shell window (in window #1) and a window with a
+TELNET connection to the machine foobar (with no flow-control using the
+title @samp{foobar} in window #2). If you do not include any
+@code{screen} commands in your @file{.screenrc} file, then @code{screen}
+defaults to creating a single shell window, number zero. When the
+initialization is completed, @code{screen} switches to the last window
+specified in your .screenrc file or, if none, it opens default window
+#0.
+
+@node Setenv, Shell, Screen Command, New Window
+@section Setenv
+@deffn Command setenv var string
+(none)@*
+Set the environment variable @var{var} to value @var{string}.
+If only @var{var} is specified, the user will be prompted to enter a value.
+If no parameters are specified, the user will be prompted for both variable
+and value. The environment is inherited by all subsequently forked shells.
+@end deffn
+
+@deffn Command unsetenv var
+(none)@*
+Unset an environment variable.
+@end deffn
+
+@node Shell, Term, Setenv, New Window
+@section Shell
+@deffn Command shell command
+(none)@*
+Set the command to be used to create a new shell. This overrides the
+value of the environment variable @code{$SHELL}. This is useful if
+you'd like to run a tty-enhancer which is expecting to execute the
+program specified in @code{$SHELL}. If the command begins with
+a @samp{-} character, the shell will be started as a login-shell.
+@end deffn
+
+@deffn Command shelltitle title
+(none)@*
+Set the title for all shells created during startup or by the C-a C-c
+command. @xref{Naming Windows}, for details about what titles are.
+@end deffn
+
+@node Term, , Shell, New Window
+@section Term
+@deffn Command term term
+(none)@*
+In each window @code{screen} opens, it sets the @code{$TERM}
+variable to @samp{screen} by default, unless no description for
+@samp{screen} is installed in the local termcap or terminfo data base.
+In that case it pretends that the terminal emulator is @samp{vt100}.
+This won't do much harm, as @code{screen} is VT100/ANSI compatible. The
+use of the @code{term} command is discouraged for non-default purpose.
+That is, one may want to specify special @code{$TERM} settings (e.g. vt100) for
+the next @code{screen rlogin othermachine} command. Use the command
+@code{screen -T vt100 rlogin othermachine} rather than setting
+and resetting the default.
+@end deffn
+
+@node Selecting, Session Management, New Window, Top
+@chapter Selecting a Window
+
+This section describes the commands for switching between windows in an
+@code{screen} session. The windows are numbered from 0 to 9, and are created
+in that order by default (@pxref{New Window}).
+
+@menu
+* Next and Previous:: Forward or back one window.
+* Other Window:: Switch back and forth between two windows.
+* Select:: Specify a particular window.
+@end menu
+
+@node Next and Previous, Other Window, , Selecting
+@section Moving Back and Forth
+@kindex SPC
+@kindex n
+@kindex C-n
+@deffn Command next
+(@kbd{C-a @key{SPC}}, @kbd{C-a n}, @kbd{C-a C-n})@*
+Switch to the next window. This command can be used repeatedly to
+cycle through the list of windows. (On some terminals, C-@key{SPC}
+generates a NUL character, so you must release the control key before
+pressing space.)
+@end deffn
+
+@kindex p
+@kindex C-p
+@deffn Command prev
+(@kbd{C-a p}, @kbd{C-a C-p})@*
+Switch to the previous window (the opposite of @kbd{C-a n}).
+@end deffn
+
+@node Other Window, Select, Next and Previous, Selecting
+@section Other Window
+@kindex C-a
+@deffn Command other
+(@kbd{C-a C-a})@*
+Switch to the last window displayed. Note that this command
+defaults to the command character typed twice, unless overridden.
+For instance, if you use the option @samp{-e]x},
+this command becomes @kbd{]]} (@pxref{Command Character}).
+@end deffn
+
+@node Select, , Other Window, Selecting
+@section Select
+@kindex 0@dots{}9
+@kindex '
+@kindex "
+@deffn Command select [n]
+(@kbd{C-a @var{n}}, @kbd{C-a '}, @kbd{C-a "})@*
+Switch to the window with the number @var{n}.
+If no window number is specified, you get prompted for an
+identifier. This can be a window name (title) or a number.
+When a new window is established, the lowest available number
+is assigned to this window.
+Thus, the first window can be activated by @code{select 0}; there
+can be no more than 10 windows present simultaneously (unless screen is
+compiled with a higher MAXWIN setting).
+@end deffn
+
+@node Session Management, Window Settings, Selecting, Top
+@chapter Session Management Commands
+
+Perhaps the most useful feature of @code{screen} is the way it allows
+the user to move a session between terminals, by detaching and
+reattaching. This also makes life easier for modem users who have to
+deal with unexpected loss of carrier.
+
+@menu
+* Detach:: Disconnect @code{screen} from your terminal.
+* Power Detach:: Detach and log out.
+* Lock:: Lock your terminal temporarily.
+* Multiuser Session:: Changing number of allowed users.
+* Session Name:: Rename your session for later reattachment.
+* Suspend:: Suspend your session.
+* Quit:: Terminate your session.
+@end menu
+
+@node Detach, Power Detach, , Session Management
+@section Detach
+
+@deffn Command autodetach state
+(none)@*
+Sets whether @code{screen} will automatically detach upon hangup, which
+saves all your running programs until they are resumed with a
+@code{screen -r} command. When turned off, a hangup signal will
+terminate @code{screen} and all the processes it contains. Autodetach is
+on by default.
+@end deffn
+
+@kindex d
+@kindex C-d
+@deffn Command detach
+(@kbd{C-a d}, @kbd{C-a C-d})@*
+Detach the @code{screen} session (disconnect it from the terminal and
+put it into the background). A detached @code{screen} can be resumed by
+invoking @code{screen} with the @code{-r} option. (@pxref{Invoking
+Screen})
+@end deffn
+
+@deffn Command password [crypted_pw]
+(none)@*
+Present a crypted password in your @file{.screenrc} file and screen will
+ask for it, whenever someone attempts to resume a detached session. This
+is useful, if you have privileged programs running under @code{screen}
+and you want to protect your session from reattach attempts by users
+that managed to assume your uid. (I.e. any superuser.) If no crypted
+password is specified, screen prompts twice a password and places its
+encryption in the paste buffer. Default is `none', which disables
+password checking.
+@end deffn
+
+@node Power Detach, Lock, Detach, Session Management
+@section Power Detach
+
+@kindex D
+@deffn Command pow_detach
+(@kbd{C-a D})@*
+Mainly the same as @code{detach}, but also sends a HANGUP signal
+to the parent process of @code{screen}.@*
+@emph{Caution}: This will result in a
+logout if @code{screen} was started from your login shell.
+@end deffn
+
+@deffn Command pow_detach_msg [message]
+(none)@*
+The @var{message} specified here is output whenever a power detach is
+performed. It may be used as a replacement for a logout message or to reset
+baud rate, etc.
+Without parameter, the current message is shown.
+@end deffn
+
+@node Lock, Multiuser Session, Power Detach, Session Management
+@section Lock
+@kindex x
+@kindex C-x
+@deffn Command lockscreen
+(@kbd{C-a x}, @kbd{C-a C-x})@*
+Call a screenlock program (@file{/local/bin/lck} or @file{/usr/bin/lock}
+or a builtin, if no other is available). Screen does not accept any
+command keys until this program terminates. Meanwhile processes in the
+windows may continue, as the windows are in the detached state.
+The screenlock program may be changed through the environment variable
+@code{$LOCKPRG} (which must be set in the shell from which @code{screen}
+is started) and is executed with the user's uid and gid.
+
+Warning: When you leave other shells unlocked and have no password set
+on @code{screen}, the lock is void: One could easily re-attach from an
+unlocked shell. This feature should rather be called
+@code{lockterminal}.
+@end deffn
+
+@node Multiuser Session, Session Name, Lock, Session Management
+@section Multiuser Session
+@cindex multiuser session
+
+These commands allow other users to gain access to one single @code{screen}
+session. When attaching to a multiuser @code{screen} the sessionname is
+specified as @code{username/sessionname} to the @code{-S} command line option.
+@code{Screen} must be compiled with multiuser support to enable features
+described here.
+
+@menu
+* Multiuser:: Enable / Disable multiuser mode.
+* Acladd:: Enable a specific user.
+* Aclchg:: Change a users permissions.
+* Acldel:: Disable a specific user.
+* Wall:: Write a message to all users.
+* Writelock:: Grant exclusive window access.
+@end menu
+
+@node Multiuser, Acladd, , Multiuser Session
+@subsection Multiuser
+@deffn Command multiuser @var{state}
+(none)@*
+Switch between single-user and multi-user mode. Standard screen operation is
+single-user. In multi-user mode the commands @code{acladd}, @code{aclchg} and
+@code{acldel} can be used to enable (and disable) other users accessing this
+@code{screen}.
+@end deffn
+
+@node Acladd, Aclchg, Multiuser, Multiuser Session
+@subsection Acladd
+@deffn Command acladd @var{usernames}
+(none)@*
+Enable users to fully access this screen session. @var{Usernames} can be one
+user or a comma seperated list of users. This command enables to attach to
+the @code{screen} session and performs the equivalent of
+@code{aclchg @var{usernames} +rwx "#?"}. To add a user with restricted access,
+use the @code{aclchg} command below. Multi-user mode only.
+@end deffn
+
+@node Aclchg, Acldel, Acladd, Multiuser Session
+@subsection Aclchg
+@deffn Command aclchg @var{usernames permbits list}
+(none)@*
+Change permissions for a comma seperated list of users.
+Permission bits are represented as @samp{r}, @samp{w} and @samp{x}.
+Prefixing @samp{+} grants the permission, @samp{-} removes it. The third
+parameter is a comma seperated list of commands or windows (specified either
+by number or title). The special list @samp{#} refers to all windows, @samp{?}
+to all commands. If @var{usernames} consists of a single @samp{*}, all
+known users is affected.
+A command can be executed when the user has the @samp{x} bit for it. The user
+can type input to a window when he has its @samp{w} bit set and no other
+user obtains a writelock for this window. Other bits are currently ignored.
+To withdraw the writelock from another user in e.g. window 2:
+@samp{aclchg @var{username} -w+w 2}. To allow readonly access
+to the session: @samp{aclchg @var{username} -w "#"}. As soon as a user's name
+is known to screen, he can attach to the session and (per default) has full
+permissions for all command and windows. Execution permission for the acl
+commands, @code{at} and others should also be removed or the user may be able
+to regain write permission.
+Multi-user mode only.
+@end deffn
+
+@node Acldel, Wall, Aclchg, Multiuser Session
+@subsection Acldel
+@deffn Command acldel @var{username}
+(none)@*
+Remove a user from screen's access control list. If currently attached, all the
+user's displays are detached from the session. He cannot attach again.
+Multi-user mode only.
+@end deffn
+
+@node Wall, Writelock, Acldel, Multiuser Session
+@subsection Wall
+@deffn Command wall @var{message}
+(none)@*
+Write a message to all displays. The message will appear in the terminal's
+status line.
+@end deffn
+
+@node Writelock, , Wall, Multiuser Session
+@subsection Writelock
+@deffn Command writelock @var{on|off|auto}
+(none)@*
+In addition to access control lists, not all users may be able to write to
+the same window at once. Per default, writelock is in @samp{auto} mode and
+grants exclusive input permission to the user who is the first to switch
+to the particular window. When he leaves the window, other users may obtain
+the writelock (automatically). The writelock of the current window is disabled
+by the command @code{writelock off}. If the user issues the command
+@code{writelock on} he keeps the exclusive write permission while switching
+to other windows.
+@end deffn
+
+@deffn Command defwritelock @var{on|off|auto}
+(none)@*
+Sets the default writelock behaviour for new windows. Initially all windows
+will be created with automatic writelocks.
+@end deffn
+
+
+@node Session Name, Suspend, Multiuser Session, Session Management
+@section Session Name
+@deffn Command sessionname [name]
+(none)@*
+Rename the current session. Note that for @code{screen -list} the name
+shows up with the process-id prepended. If the argument @var{name} is
+omitted, the name of this session is displayed.@*
+@emph{Caution}: The @code{$STY}
+environment variable still reflects the old name. This may result in
+confusion. The default is constructed from the tty and host names.
+@end deffn
+
+@node Suspend, Quit, Session Name, Session Management
+@section Suspend
+@kindex z
+@kindex C-z
+@deffn Command suspend
+(@kbd{C-a z}, @kbd{C-a C-z})@*
+Suspend @code{screen}. The windows are in the detached state while
+@code{screen} is suspended. This feature relies on the parent shell
+being able to do job control.
+@end deffn
+
+@node Quit, , Suspend, Session Management
+@section Quit
+@kindex C-\
+@deffn Command quit
+(@kbd{C-a C-\})@*
+Kill all windows and terminate @code{screen}. Note that on VT100-style
+terminals the keys @kbd{C-4} and @kbd{C-\} are identical. So be careful
+not to type @kbd{C-a C-4} when selecting window no. 4. Use the empty
+bind command (as in @code{bind "^\"}) to remove a key binding
+(@pxref{Key Binding}).
+@end deffn
+
+@node Window Settings, Virtual Terminal, Session Management, Top
+@chapter Window Settings
+
+These commands control the way @code{screen} treats individual windows
+in a session. @xref{Virtual Terminal}, for commands to control the
+terminal emulation itself.
+
+@menu
+* Naming Windows:: Control the name of the window
+* Console:: See the host's console messages
+* Kill:: Destroy an unwanted window
+* Login:: Control @file{/etc/utmp} logging
+* Mode:: Control the file mode of the pty
+* Monitor:: Watch for activity in a window
+* Windows:: List the active windows
+* Hardstatus:: Set a window's hardstatus line
+@end menu
+
+@node Naming Windows, Console, , Window Settings
+@section Naming Windows (Titles)
+@cindex title
+
+You can customize each window's name in the window display (viewed with
+the @code{windows} command (@pxref{Windows}) by setting it with
+one of the title commands. Normally the name displayed is the actual
+command name of the program created in the window. However, it is
+sometimes useful to distinguish various programs of the same name or to
+change the name on-the-fly to reflect the current state of the window.
+
+The default name for all shell windows can be set with the
+@code{shelltitle} command (@pxref{Shell}). You can specify the name you
+want for a window with the @samp{-t} option to the @code{screen} command
+when the window is created (@pxref{Screen Command}). To change the name after
+the window has been created you can use the title-string escape-sequence
+(@kbd{@key{ESC} k @var{name} @key{ESC} \}) and the @code{title} command
+(C-a A). The former can be output from an application to control the
+window's name under software control, and the latter will prompt for a
+name when typed. You can also bind predefined names to keys with the
+@code{title} command to set things quickly without prompting.
+
+@menu
+* Title Command:: The @code{title} command.
+* Dynamic Titles:: Make shell windows change titles dynamically.
+* Title Prompts:: Set up your shell prompt for dynamic Titles.
+* Title Screenrc:: Set up Titles in your @file{.screenrc}.
+@end menu
+
+@node Title Command, Dynamic Titles, , Naming Windows
+@subsection Title Command
+@kindex A
+@deffn Command title [windowtitle]
+(@kbd{C-a A})@*
+Set the name of the current window to @var{windowalias}. If no name is
+specified, screen prompts for one.
+@end deffn
+
+@node Dynamic Titles, Title Prompts, Title Command, Naming Windows
+@subsection Dynamic Titles
+@code{screen} has a shell-specific heuristic that is enabled by
+setting the window's name to @var{search|name} and arranging to have a
+null title escape-sequence output as a part of your prompt. The
+@var{search} portion specifies an end-of-prompt search string, while the
+@var{name} portion specifies the default shell name for the window. If
+the @var{name} ends in a @samp{:} @code{screen} will add what it
+believes to be the current command running in the window to the end of
+the specified name (e.g. @var{name:cmd}). Otherwise the current
+command name supersedes the shell name while it is running.
+
+Here's how it works: you must modify your shell prompt to output a null
+title-escape-sequence (@key{ESC} k @key{ESC} \) as a part of your prompt.
+The last part of your prompt must be the same as the string you
+specified for the @var{search} portion of the title. Once this is set
+up, @code{screen} will use the title-escape-sequence to clear the previous
+command name and get ready for the next command. Then, when a newline
+is received from the shell, a search is made for the end of the prompt.
+If found, it will grab the first word after the matched string and use
+it as the command name. If the command name begins with @samp{!},
+@samp{%}, or @samp{^}, @code{screen} will use the first word on the
+following line (if found) in preference to the just-found name. This
+helps csh users get more accurate titles when using job control or
+history recall commands.
+
+@node Title Prompts, Title Screenrc, Dynamic Titles, Naming Windows
+@subsection Setting up your prompt for shell titles
+One thing to keep in mind when adding a null title-escape-sequence to your
+prompt is that some shells (like the csh) count all the non-control
+characters as part of the prompt's length. If these invisible
+characters aren't a multiple of 8 then backspacing over a tab will
+result in an incorrect display. One way to get around this is to use a
+prompt like this:
+
+@example
+set prompt='@value{esc}[0000m@value{esc}k@value{esc}\% '
+@end example
+
+The escape-sequence @samp{@value{esc}[0000m} not only normalizes the
+character attributes, but all the zeros round the length of the
+invisible characters up to 8.
+
+Tcsh handles escape codes in the prompt more intelligently, so you can
+specify your prompt like this:
+
+@example
+set prompt="%@{\ek\e\\%@}\% "
+@end example
+
+Bash users will probably want to echo the escape sequence in the
+PROMPT_COMMAND:
+
+@example
+PROMPT_COMMAND='echo -n -e "\033k\033\134"'
+@end example
+
+(I used @samp{\134} to output a @samp{\} because of a bug in v1.04).
+
+@node Title Screenrc, , Title Prompts, Naming Windows
+@subsection Setting up shell titles in your @file{.screenrc}
+Here are some .screenrc examples:
+
+@example
+screen -t top 2 nice top
+@end example
+
+Adding this line to your .screenrc would start a niced version of the
+@code{top} command in window 2 named @samp{top} rather than @samp{nice}.
+
+@example
+shelltitle '> |csh'
+screen 1
+@end example
+
+This file would start a shell using the given shelltitle. The title
+specified is an auto-title that would expect the prompt and the typed
+command to look something like the following:
+
+@example
+/usr/joe/src/dir> trn
+@end example
+
+(it looks after the '> ' for the command name).
+The window status would show the name @samp{trn} while the command was
+running, and revert to @samp{csh} upon completion.
+
+@example
+bind R screen -t '% |root:' su
+@end example
+
+Having this command in your .screenrc would bind the key sequence
+@kbd{C-a R} to the @code{su} command and give it an auto-title name of
+@samp{root:}. For this auto-title to work, the screen could look
+something like this:
+
+@example
+% !em
+emacs file.c
+@end example
+
+Here the user typed the csh history command @code{!em} which ran the
+previously entered @code{emacs} command. The window status would show
+@samp{root:emacs} during the execution of the command, and revert to
+simply @samp{root:} at its completion.
+
+@example
+bind o title
+bind E title ""
+bind u title (unknown)
+@end example
+
+The first binding doesn't have any arguments, so it would prompt you for
+a title when you type @kbd{C-a o}. The second binding would clear an
+auto-titles current setting (C-a E). The third binding would set the
+current window's title to @samp{(unknown)} (C-a u).
+
+@node Console, Kill, Naming Windows, Window Settings
+@section Console
+@deffn Command console @var{[state]}
+(none)@*
+Grabs or ungrabs the machines console output to a window. When the argument
+is omitted the current state is displayed.
+@emph{Note}: Only the owner of @file{/dev/console} can grab the console
+output. This command is only available if the host supports the ioctl
+@code{TIOCCONS}.
+@end deffn
+
+@node Kill, Login, Console, Window Settings
+@section Kill
+
+@kindex k
+@kindex C-k
+@deffn Command kill
+(@kbd{C-a k}, @kbd{C-a C-k})@*
+Kill the current window.@*
+If there is an @code{exec} command running (@pxref{Exec}) then it is killed.
+Otherwise the process (e.g. shell) running in the window receives a
+@code{HANGUP} condition,
+the window structure is removed and screen switches to the previously
+displayed window. When the last window is destroyed, @code{screen} exits.
+@*
+@emph{Caution}: @code{emacs} users may find themselves killing their
+@code{emacs} session when trying to delete the current line. For this
+reason, it is probably wise to use a different command character
+(@pxref{Command Character}) or rebind @code{kill} to another key
+sequence, such as @kbd{C-a K} (@pxref{Key Binding}).
+@end deffn
+
+@node Login, Mode, Kill, Window Settings
+@section Login
+
+@deffn Command deflogin state
+(none)@*
+Same as the @code{login} command except that the default setting for new
+windows is changed. This defaults to `on' unless otherwise specified at
+compile time (@pxref{Installation}). Both commands are only present when
+@code{screen} has been compiled with utmp support.
+@end deffn
+
+@kindex L
+@deffn Command login [state]
+(@kbd{C-a L})@*
+Adds or removes the entry in @file{/etc/utmp} for the current window.
+This controls whether or not the window is @dfn{logged in}. In addition
+to this toggle, it is convenient to have ``log in'' and ``log out''
+keys. For instance, @code{bind I login on} and @code{bind O
+login off} will map these keys to be @kbd{C-a I} and @kbd{C-a O}
+(@pxref{Key Binding}).
+@end deffn
+
+@node Mode, Monitor, Login, Window Settings
+@section Mode
+@deffn Command defmode mode
+(none)@*
+The mode of each newly allocated pseudo-tty is set to @var{mode}.
+@var{mode} is an octal number as used by chmod(1). Defaults to 0622 for
+windows which are logged in, 0600 for others (e.g. when @code{-ln} was
+specified for creation. @xref{Screen Command}).
+@end deffn
+
+@node Monitor, Windows, Mode, Window Settings
+@section Monitoring
+
+@deffn Command activity message
+(none)@*
+When any activity occurs in a background window that is being monitored,
+@code{screen} displays a notification in the message line. The
+notification message can be redefined by means of the @code{activity}
+command. Each occurrence of @samp{%} in @var{message} is replaced by
+the number of the window in which activity has occurred, and each
+occurrence of @samp{~} is replaced by the definition for bell in your
+termcap (usually an audible bell). The default message is
+
+@example
+'Activity in window %'
+@end example
+
+Note that monitoring is off for all windows by default, but can be altered
+by use of the @code{monitor} command (@kbd{C-a M}).
+@end deffn
+
+@deffn Command defmonitor state
+(none)@*
+Same as the @code{monitor} command except that the default setting for
+new windows is changed. Initial setting is `off'.
+@end deffn
+
+@kindex M
+@deffn Command monitor [state]
+(@kbd{C-a M})@*
+Toggles monitoring of the current window. When monitoring is turned on
+and the affected window is switched into the background, the activity
+notification message will be displayed in the status line at the first
+sign of output, and the window will also be marked with an @samp{@@} in
+the window-status display (@pxref{Windows}). Monitoring defaults to
+@samp{off} for all windows.
+@end deffn
+
+@node Windows, Hardstatus, Monitor, Window Settings
+@section Windows
+@kindex w
+@kindex C-w
+@deffn Command windows
+(@kbd{C-a w}, @kbd{C-a C-w})@*
+Uses the message line to display a list of all the windows. Each
+window is listed by number with the name of the program running in the
+window (or its title); the current window is marked with a @samp{*};
+the previous window is marked with a @samp{-}; all the windows that are
+logged in are marked with a @samp{$} (@pxref{Login}); a background
+window that has received a bell is marked with a @samp{!}; a background
+window that is being monitored and has had activity occur is marked with
+an @samp{@@} (@pxref{Monitor}); a window which has output logging turned
+on is marked with @samp{(L)}; windows occupied by other users are marked with
+@samp{&}; windows in the zombie state are marked with @samp{Z}.
+If this list is too long to fit on the terminal's status line only the
+portion around the current window is displayed.
+@end deffn
+
+@node Hardstatus, , Windows, Window Settings
+@section Hardstatus
+
+@code{Screen} maintains a hardstatus line for every window. If a window
+gets selected, the display's hardstatus will be updated to match
+the window's hardstatus line. If the display has no hardstatus
+the line will be displayed as a standard screen message.
+The hardstatus line can be changed with the ANSI Application
+Program Command (APC): @samp{ESC_<string>ESC\}. As a convenience
+for xterm users the sequence @samp{ESC]0..2;<string>^G} is
+also accepted.
+
+@deffn Command defhstatus
+(none)@*
+The hardstatus line that all new windows will get is set to
+@var{status}.
+This command is useful to make the hardstatus of every window
+display the window number or title or the like. @var{status}
+may contain the same directives as in the window messages, but
+the directive escape character is @samp{^E} (octal 005) instead
+of @samp{%}. This was done to make a misinterpretion of program
+generated hardstatus lines impossible.
+If the parameter @var{status}
+is omitted, the current default string is displayed.
+Per default the hardstatus line of new windows is empty.
+@end deffn
+
+@node Virtual Terminal, Copy and Paste, Window Settings, Top
+@chapter Virtual Terminal
+
+Each window in a @code{screen} session emulates a VT100 terminal, with
+some extra functions added. The VT100 emulator is hardcoded, no other
+terminal types can be emulated.
+The commands described here modify the terminal emulation.
+
+@menu
+* Control Sequences:: Details of the internal VT100 emulation.
+* Input Translation:: How keystrokes are remapped.
+* Digraph:: Entering digraph sequences.
+* Bell:: Getting your attention.
+* Clear:: Clear the window display.
+* Info:: Terminal emulation statistics.
+* Redisplay:: When the display gets confusing.
+* Wrap:: Automatic margins.
+* Reset:: Recovering from ill-behaved applications.
+* Window Size:: Changing the size of your terminal.
+* Character Processing:: Change the effect of special characters.
+@end menu
+
+@node Control Sequences, Input Translation, , Virtual Terminal
+@section Control Sequences
+@cindex control sequences
+The following is a list of control sequences recognized by
+@code{screen}. @samp{(V)} and @samp{(A)} indicate VT100-specific and
+ANSI- or ISO-specific functions, respectively.
+
+@example
+ESC E Next Line
+ESC D Index
+ESC M Reverse Index
+ESC H Horizontal Tab Set
+ESC Z Send VT100 Identification String
+ESC 7 (V) Save Cursor and Attributes
+ESC 8 (V) Restore Cursor and Attributes
+ESC [s (A) Save Cursor and Attributes
+ESC [u (A) Restore Cursor and Attributes
+ESC c Reset to Initial State
+ESC g Visual Bell
+ESC Pn p Cursor Visibility (97801)
+ Pn = 6 Invisible
+ 7 Visible
+ESC = (V) Application Keypad Mode
+ESC > (V) Numeric Keypad Mode
+ESC # 8 (V) Fill Screen with E's
+ESC \ (A) String Terminator
+ESC ^ (A) Privacy Message String (Message Line)
+ESC ! Global Message String (Message Line)
+ESC k Title Definition String
+ESC P (A) Device Control String
+ Outputs a string directly to the host
+ terminal without interpretation.
+ESC _ (A) Application Program Command (Hardstatus)
+ESC ] (A) Operating System Command (Hardstatus, xterm
+ title hack)
+Control-N (A) Lock Shift G1 (SO)
+Control-O (A) Lock Shift G0 (SI)
+ESC n (A) Lock Shift G2
+ESC o (A) Lock Shift G3
+ESC N (A) Single Shift G2
+ESC O (A) Single Shift G3
+ESC ( Pcs (A) Designate character set as G0
+ESC ) Pcs (A) Designate character set as G1
+ESC * Pcs (A) Designate character set as G2
+ESC + Pcs (A) Designate character set as G3
+ESC [ Pn ; Pn H Direct Cursor Addressing
+ESC [ Pn ; Pn f Direct Cursor Addressing
+ESC [ Pn J Erase in Display
+ Pn = None or 0 From Cursor to End of Screen
+ 1 From Beginning of Screen to Cursor
+ 2 Entire Screen
+ESC [ Pn K Erase in Line
+ Pn = None or 0 From Cursor to End of Line
+ 1 From Beginning of Line to Cursor
+ 2 Entire Line
+ESC [ Pn A Cursor Up
+ESC [ Pn B Cursor Down
+ESC [ Pn C Cursor Right
+ESC [ Pn D Cursor Left
+ESC [ Ps ;...; Ps m Select Graphic Rendition
+ Ps = None or 0 Default Rendition
+ 1 Bold
+ 2 (A) Faint
+ 3 (A) @i{Standout} Mode (ANSI: Italicized)
+ 4 Underlined
+ 5 Blinking
+ 7 Negative Image
+ 22 (A) Normal Intensity
+ 23 (A) @i{Standout} Mode off (ANSI: Italicized off)
+ 24 (A) Not Underlined
+ 25 (A) Not Blinking
+ 27 (A) Positive Image
+ 30 (A) Foreground Black
+ 31 (A) Foreground Red
+ 32 (A) Foreground Green
+ 33 (A) Foreground Yellow
+ 34 (A) Foreground Blue
+ 35 (A) Foreground Magenta
+ 36 (A) Foreground Cyan
+ 37 (A) Foreground White
+ 39 (A) Foreground Default
+ 40 (A) Background Black
+ ... ...
+ 49 (A) Background Default
+ESC [ Pn g Tab Clear
+ Pn = None or 0 Clear Tab at Current Position
+ 3 Clear All Tabs
+ESC [ Pn ; Pn r (V) Set Scrolling Region
+ESC [ Pn I (A) Horizontal Tab
+ESC [ Pn Z (A) Backward Tab
+ESC [ Pn L (A) Insert Line
+ESC [ Pn M (A) Delete Line
+ESC [ Pn @@ (A) Insert Character
+ESC [ Pn P (A) Delete Character
+ESC [ Pn S Scroll Scrolling Region Up
+ESC [ Pn T Scroll Scrolling Region Down
+ESC [ Ps ;...; Ps h Set Mode
+ESC [ Ps ;...; Ps l Reset Mode
+ Ps = 4 (A) Insert Mode
+ 20 (A) @samp{Automatic Linefeed} Mode.
+ 34 Normal Cursor Visibility
+ ?1 (V) Application Cursor Keys
+ ?3 (V) Change Terminal Width to 132 columns
+ ?5 (V) Reverse Video
+ ?6 (V) @samp{Origin} Mode
+ ?7 (V) @samp{Wrap} Mode
+ ?25 (V) Visible Cursor
+ESC [ 5 i (A) Start relay to printer (ANSI Media Copy)
+ESC [ 4 i (A) Stop relay to printer (ANSI Media Copy)
+ESC [ 8 ; Ph ; Pw t Resize the window to @samp{Ph} lines and
+ @samp{Pw} columns (SunView special)
+ESC [ c Send VT100 Identification String
+ESC [ x (V) Send Terminal Parameter Report
+ESC [ > c Send Secondary Device Attributes String
+ESC [ 6 n Send Cursor Position Report
+
+@end example
+
+
+@node Input Translation, Digraph, Control Sequences, Virtual Terminal
+@section Input Translation
+@cindex input translation
+In order to do a full VT100 emulation @code{screen} has to detect
+that a sequence of characters in the input stream was generated
+by a keypress on the user's keyboard and insert the VT100
+style escape sequence. @code{Screen} has a very flexible way of doing
+this by making it possible to map arbitrary commands on arbitrary
+sequences of characters. For standard VT100 emulation the command
+will always insert a string in the input buffer of the window
+(see also command @code{stuff}, @pxref{Paste}).
+Because the sequences generated by a keypress can
+change after a reattach from a different terminal type, it is
+possible to bind commands to the termcap name of the keys.
+@code{Screen} will insert the correct binding after each
+reattach. @xref{Bindkey} for further details on the syntax and examples.
+
+Here is the table of the default key bindings. (A) means that the
+command is executed if the keyboard is switched into application
+mode.
+@example
+
+Key name Termcap name Command
+-----------------------------------------------------
+Cursor up ku stuff \033[A
+ stuff \033OA (A)
+Cursor down kd stuff \033[B
+ stuff \033OB (A)
+Cursor right kr stuff \033[C
+ stuff \033OC (A)
+Cursor left kl stuff \033[D
+ stuff \033OD (A)
+Function key 0 k0 stuff \033[10~
+Function key 1 k1 stuff \033OP
+Function key 2 k2 stuff \033OQ
+Function key 3 k3 stuff \033OR
+Function key 4 k4 stuff \033OS
+Function key 5 k5 stuff \033[15~
+Function key 6 k6 stuff \033[17~
+Function key 7 k7 stuff \033[18~
+Function key 8 k8 stuff \033[19~
+Function key 9 k9 stuff \033[20~
+Function key 10 k; stuff \033[21~
+Function key 11 F1 stuff \033[22~
+Function key 12 F2 stuff \033[23~
+Backspace kb stuff \010
+Home kh stuff \033[1~
+End kH stuff \033[4~
+Insert kI stuff \033[2~
+Delete kD stuff \033[3~
+Page up kP stuff \033[5~
+Page down kN stuff \033[6~
+Keypad 0 f0 stuff 0
+ stuff \033Op (A)
+Keypad 1 f1 stuff 1
+ stuff \033Oq (A)
+Keypad 2 f2 stuff 2
+ stuff \033Or (A)
+Keypad 3 f3 stuff 3
+ stuff \033Os (A)
+Keypad 4 f4 stuff 4
+ stuff \033Ot (A)
+Keypad 5 f5 stuff 5
+ stuff \033Ou (A)
+Keypad 6 f6 stuff 6
+ stuff \033Ov (A)
+Keypad 7 f7 stuff 7
+ stuff \033Ow (A)
+Keypad 8 f8 stuff 8
+ stuff \033Ox (A)
+Keypad 9 f9 stuff 9
+ stuff \033Oy (A)
+Keypad + f+ stuff +
+ stuff \033Ok (A)
+Keypad - f- stuff -
+ stuff \033Om (A)
+Keypad * f* stuff *
+ stuff \033Oj (A)
+Keypad / f/ stuff /
+ stuff \033Oo (A)
+Keypad = fq stuff =
+ stuff \033OX (A)
+Keypad . f. stuff .
+ stuff \033On (A)
+Keypad , f, stuff ,
+ stuff \033Ol (A)
+Keypad enter fe stuff \015
+ stuff \033OM (A)
+@end example
+
+@node Digraph, Bell, Input Translation, Virtual Terminal
+@section Digraph
+
+@kindex C-v
+@deffn Command digraph [preset]
+(none)@*
+This command prompts the user for a digraph sequence. The next
+two characters typed are looked up in a builtin table and the
+resulting character is inserted in the input stream. For example,
+if the user enters @samp{a"}, an a-umlaut will be inserted. If the
+first character entered is a 0 (zero), @code{screen}
+will treat the following charcters (up to three) as an octal
+number instead. The optional argument @var{preset}
+is treated as user input, thus one can create an "umlaut" key.
+For example the command @samp{bindkey ^K digraph '"'} enables the user
+to generate an a-umlaut by typing @samp{CTRL-K a}.
+@end deffn
+
+@node Bell, Clear, Digraph, Virtual Terminal
+@section Bell
+
+@deffn Command bell_msg [message]
+(none)@*
+When a bell character is sent to a background window, @code{screen}
+displays a notification in the message line. The notification message
+can be re-defined by means of the @code{bell} command. Each occurrence
+of @samp{%} in @var{message} is replaced by the number of the window to
+which a bell has been sent, and each occurrence of @samp{~} is replaced
+by the definition for bell in your termcap (usually an audible bell).
+The default message is
+
+@example
+'Bell in window %'
+@end example
+
+An empty message can be supplied to the @code{bell_msg} command to suppress
+output of a message line (@code{bell_msg ""}).
+@end deffn
+
+@kindex C-g
+@deffn Command vbell [state]
+(@kbd{C-a C-g})@*
+Sets or toggles the visual bell setting for the current window. If
+@code{vbell} is switched to @samp{on}, but your
+terminal does not support a visual bell, the visual bell message is
+displayed in the status line when the bell character is received.
+Visual bell support of a terminal is
+defined by the termcap variable @code{vb}. @xref{Bell, , Visual Bell,
+termcap, The Termcap Manual}, for more information on visual bells.
+The equivalent terminfo capability is @code{flash}.
+
+Per default, @code{vbell} is @samp{off}, thus the audible bell is used.
+@end deffn
+
+@deffn Command vbell_msg [message]
+(none)@*
+Sets the visual bell message. @var{Message} is printed to the status
+line if the window receives a bell character (^G), @code{vbell} is
+set to @samp{on} and the terminal does not support a visual bell.
+The default message is @samp{Wuff, Wuff!!}.
+Without parameter, the current message is shown.
+@end deffn
+
+@deffn Command vbellwait sec
+(none)@*
+Define a delay in seconds after each display of @code{screen} 's visual
+bell message. The default is 1 second.
+@end deffn
+
+@node Clear, Info, Bell, Virtual Terminal
+@section Clear
+@kindex C
+@deffn Command clear
+(@kbd{C-a C})@*
+Clears the screen and saves its contents to the scrollback buffer.
+@end deffn
+
+@node Info, Redisplay, Clear, Virtual Terminal
+@section Info
+@kindex i
+@kindex C-i
+@deffn Command info
+(@kbd{C-a i}, @kbd{C-a C-i})@*
+Uses the message line to display some information about the current
+window: the cursor position in the form @samp{(@var{column},@var{row})}
+starting with @samp{(1,1)}, the terminal width and height plus the size
+of the scrollback buffer in lines, like in @samp{(80,24)+50}, various
+flag settings (flow-control, insert mode, origin mode, wrap mode,
+application-keypad mode, output logging, activity monitoring, and redraw
+(@samp{+} indicates enabled, @samp{-} not)), the currently active
+character set (@samp{G0}, @samp{G1}, @samp{G2}, or @samp{G3}), and in
+square brackets the terminal character sets that are currently
+designated as @samp{G0} through @samp{G3}. For system information use
+@code{time}.
+@end deffn
+
+@node Redisplay, Wrap, Info, Virtual Terminal
+@section Redisplay
+
+@deffn Command allpartial state
+(none)@*
+If set to on, only the current cursor line is refreshed on window change.
+This affects all windows and is useful for slow terminal lines. The
+previous setting of full/partial refresh for each window is restored
+with @code{allpartial off}. This is a global flag that immediately takes effect
+on all windows overriding the @code{partial} settings. It does not change the
+default redraw behaviour of newly created windows.
+@end deffn
+
+@deffn Command partial state
+(none)@*
+Defines whether the display should be refreshed (as with
+@code{redisplay}) after switching to the current window. This command
+only affects the current window. To immediately affect all windows use the
+@code{allpartial} command. Default is @samp{off}, of course. This default is
+fixed, as there is currently no @code{defpartial} command.
+@end deffn
+
+@kindex l
+@kindex C-l
+@deffn Command redisplay
+(@kbd{C-a l}, @kbd{C-a C-l})@*
+Redisplay the current window. Needed to get a full redisplay in
+partial redraw mode.
+@end deffn
+
+@node Wrap, Reset, Redisplay, Virtual Terminal
+@section Wrap
+
+@kindex r
+@kindex C-r
+@deffn Command wrap state
+(@kbd{C-a r}, @kbd{C-a C-r}) @*
+Sets the line-wrap setting for the current window. When line-wrap is
+on, the second consecutive printable character output at the last column
+of a line will wrap to the start of the following line. As an added
+feature, backspace (^H) will also wrap through the left margin to the
+previous line. Default is @samp{on}.
+@end deffn
+
+@deffn Command defwrap state
+(none) @*
+Same as the @code{wrap} command except that the default setting for new
+windows is changed. Initially line-wrap is on and can be toggled with the
+@code{wrap} command (@kbd{C-a r}) or by means of "C-a : wrap on|off".
+@end deffn
+
+@node Reset, Window Size, Wrap, Virtual Terminal
+@section Reset
+@kindex Z
+@deffn Command reset
+(@kbd{C-a Z})@*
+Reset the virtual terminal to its ``power-on'' values. Useful when strange
+settings (like scroll regions or graphics character set) are left over from
+an application.
+@end deffn
+
+@node Window Size, Character Processing, Reset, Virtual Terminal
+@section Window Size
+@kindex W
+@deffn Command width [num]
+(@kbd{C-a W})@*
+Toggle the window width between 80 and 132 columns, or set it to
+@var{num} columns if an argument is specified. This requires a
+capable terminal and the termcap entries @samp{Z0} and @samp{Z1}. See
+the @code{termcap} command (@pxref{Termcap}), for more information.
+@end deffn
+
+@deffn Command height @var{[lines]}
+(none)@*
+Set the display height to a specified number of lines. When no
+argument is given it toggles between 24 and 42 lines display.
+@end deffn
+
+@node Character Processing, ,Window Size, Virtual Terminal
+@section Character Processing
+
+@deffn Command c1 [state]
+(none)@*
+Change c1 code processing. @samp{c1 on} tells screen to treat
+the input characters between 128 and 159 as control functions.
+Such an 8-bit code is normally the same as ESC followed by the
+corresponding 7-bit code. The default setting is to process c1
+codes and can be changed with the @samp{defc1} command.
+Users with fonts that have usable characters in the
+c1 positions may want to turn this off.
+
+@end deffn
+@deffn Command gr [state]
+(none)@*
+Turn GR charset switching on/off. Whenever screens sees an input
+char with an 8th bit set, it will use the charset stored in the
+GR slot and print the character with the 8th bit stripped. The
+default (see also @samp{defgr}) is not to process GR switching because
+otherwise the ISO88591 charset would not work.
+@end deffn
+
+@deffn Command kanji wtype [dtype]
+(none)@*
+Tell screen how to process kanji input/output. @var{wtype} and
+@var{dtype} must be one of the strings @samp{jis}, @samp{euc} or
+@samp{sjis}. The first argument sets the kanji type of the current
+window. Each window can emulate a different type. The optional second
+parameter tells screen how to write the kanji codes to the
+connected terminal. The preferred method of setting the display type
+is to use the @samp{KJ} termcap entry. @xref{Special Capabilities}.
+See also @samp{defkanji}, which changes the default setting of a new
+window.
+@end deffn
+
+@deffn Command charset set
+(none)@*
+Change the current character set slot designation and charset
+mapping. The first four character of @var{set}
+are treated as charset designators while the fifth and sixth
+character must be in range @samp{0} to @samp{3} and set the GL/GR
+charset mapping. On every position a @samp{.} may be used to indicate
+that the corresponding charset/mapping should not be changed
+(@var{set} is padded to six characters internally by appending
+@samp{.} chars). New windows have @samp{BBBB02} as default
+charset, unless a @samp{kanji} command is active.
+
+The current setting can be viewed with the @xref{Info} command.
+@end deffn
+
+@deffn Command defc1 state
+(none)@*
+Same as the @samp{c1} command except that the default setting for
+new windows is changed. Initial setting is @samp{on}.
+@end deffn
+
+@deffn Command defgr state
+(none)@*
+Same as the @samp{gr} command except that the default setting for
+new windows is changed. Initial setting is @samp{off}.
+@end deffn
+
+@deffn Command defkanji wtype
+(none)@*
+Same as the @samp{kanji} command except that the default setting for
+new windows is changed. Initial setting is @samp{off}, i.e. @samp{jis}.
+@end deffn
+
+@deffn Command defcharset [set]
+Like the @samp{charset} command except that the default setting for
+new windows is changed. Shows current default if called without
+argument.
+@end deffn
+
+@node Copy and Paste, Subprocess Execution, Virtual Terminal, Top
+@chapter Copy and Paste
+@cindex copy and paste
+
+For those confined to a hardware terminal, these commands provide a cut
+and paste facility more powerful than those provided by most windowing
+systems.
+
+@menu
+* Copy:: Copy from scrollback to buffer
+* Paste:: Paste from buffer into window
+* Registers:: Longer-term storage
+* Screen-Exchange:: Sharing data between screen users
+* History:: Recalling previous input
+@end menu
+
+@node Copy, Paste, , Copy and Paste
+@section Copying
+@cindex marking
+@cindex scrollback
+@kindex [
+@kindex C-[
+@kindex ESC
+@deffn Command copy
+(@kbd{C-a [}, @kbd{C-a C-[}, @kbd{C-a @key{ESC}})@*
+Enter copy/scrollback mode. This allows you to copy text from the
+current window and its history into the paste buffer. In this mode a
+@code{vi}-like full screen editor is active, with controls as
+outlined below.
+@end deffn
+
+@menu
+* Line Termination:: End copied lines with CR/LF
+* Scrollback:: Set the size of the scrollback buffer
+* Copy Mode Keys:: Remap keys in copy mode
+* Movement:: Move around in the scrollback buffer
+* Marking:: Select the text you want
+* Repeat count:: Repeat a command
+* Searching:: Find the text you want
+* Specials:: Other random keys
+@end menu
+
+@node Line Termination, Scrollback, , Copy
+@subsection CR/LF
+@deffn Command crlf [state]
+(none)@*
+This affects the copying of text regions with the @kbd{C-a [} command.
+If it is set to @samp{on}, lines will be separated by the two character
+sequence @samp{CR}/@samp{LF}. Otherwise only @samp{LF} is used.
+@code{crlf} is off by default.
+When no parameter is given, the state is toggled.
+@end deffn
+
+@node Scrollback, Copy Mode Keys, Line Termination, Copy
+@subsection Scrollback
+@deffn Command defscrollback num
+(none)@*
+Same as the @code{scrollback} command except that the default setting
+for new windows is changed. Defaults to 100.
+@end deffn
+
+@deffn Command scrollback num
+(none)@*
+Set the size of the scrollback buffer for new windows to @var{num}
+lines. The default scrollback is 100 lines. Use @kbd{C-a i} to view
+the current setting.
+@end deffn
+
+@node Copy Mode Keys, Movement, Scrollback, Copy
+@subsection markkeys
+@deffn Command markkeys string
+(none)@*
+This is a method of changing the keymap used for copy/history mode. The
+string is made up of @var{oldchar}=@var{newchar} pairs which are
+separated by @samp{:}. Example: The command @code{markkeys
+h=^B:l=^F:$=^E} would set some keys to be more familiar to @code{emacs}
+users.
+If your terminal sends characters, that cause you to abort copy mode,
+then this command may help by binding these characters to do nothing.
+The no-op character is `@' and is used like this: @code{markkeys @@=L=H}
+if you do not want to use the `H' or `L' commands any longer.
+As shown in this example, multiple keys can be assigned to one function
+in a single statement.
+@end deffn
+
+@node Movement, Marking, Copy Mode Keys, Copy
+@subsection Movement Keys
+
+@noindent
+@kbd{h}, @kbd{j}, @kbd{k}, @kbd{l} move the cursor line by line or
+column by column.
+
+@noindent
+@kbd{0}, @kbd{^} and @kbd{$} move to the leftmost column or to the first
+or last non-whitespace character on the line.
+
+@noindent
+@kbd{H}, @kbd{M} and @kbd{L} move the cursor to the leftmost column
+of the top, center or bottom line of the window.
+
+@noindent
+@kbd{+} and @kbd{-} move the cursor to the leftmost column of the next
+or previous line.
+
+@noindent
+@kbd{G} moves to the specified absolute line (default: end of buffer).
+
+@noindent
+@kbd{|} moves to the specified absolute column.
+
+@noindent
+@kbd{w}, @kbd{b}, @kbd{e} move the cursor word by word.
+
+@noindent
+@kbd{C-u} and @kbd{C-d} scroll the display up/down by the specified
+amount of lines while preserving the cursor position. (Default: half
+screenfull).
+
+@noindent
+@kbd{C-b} and @kbd{C-f} move the cursor up/down a full screen.
+
+@noindent
+@kbd{g} moves to the beginning of the buffer.
+
+@noindent
+@kbd{%} jumps to the specified percentage of the buffer.
+
+Note that Emacs-style movement keys can be specified by a .screenrc
+command. (@code{markkeys "h=^B:l=^F:$=^E"}) There is no simple method for
+a full emacs-style keymap, however, as this involves multi-character codes.
+
+@node Marking, Repeat count, Movement, Copy
+@subsection Marking
+
+The copy range is specified by setting two marks. The text between these
+marks will be highlighted. Press @kbd{space} to set the first or second
+mark respectively.
+
+@noindent
+@kbd{Y} and @kbd{y} can be used to mark one whole line or to mark from
+start of line.
+
+@noindent
+@kbd{W} marks exactly one word.
+
+@node Repeat count, Searching, Marking, Copy
+@subsection Repeat Count
+
+Any command in copy mode can be prefixed with a number (by pressing
+digits @kbd{0@dots{}9}) which is taken as a repeat count. Example:
+@kbd{C-a C-[ H 10 j 5 Y} will copy lines 11 to 15 into the paste buffer.
+
+@node Searching, Specials, Repeat count, Copy
+@subsection Searching
+
+@noindent
+@kbd{/} @code{vi}-like search forward.
+
+@noindent
+@kbd{?} @code{vi}-like search backward.
+
+@noindent
+@kbd{C-a s} @code{emacs} style incremental search forward.
+
+@noindent
+@kbd{C-r} @code{emacs} style reverse i-search.
+
+@node Specials, , Searching, Copy
+@subsection Specials
+
+There are, however, some keys that act differently here from in
+@code{vi}. @code{Vi} does not allow to yank rectangular blocks of text,
+but @code{screen} does. Press
+
+@noindent
+@kbd{c} or @kbd{C} to set the left or right margin respectively. If no
+repeat count is given, both default to the current cursor position.@*
+Example: Try this on a rather full text screen:
+@kbd{C-a [ M 20 l SPACE c 10 l 5 j C SPACE}.
+
+@noindent
+This moves one to the middle line of the screen, moves in 20 columns left,
+marks the beginning of the paste buffer, sets the left column, moves 5 columns
+down, sets the right column, and then marks the end of
+the paste buffer. Now try:@*
+@kbd{C-a [ M 20 l SPACE 10 l 5 j SPACE}
+
+@noindent
+and notice the difference in the amount of text copied.
+
+@noindent
+@kbd{J} joins lines. It toggles between 3 modes: lines separated by a
+newline character (012), lines glued seamless, or lines separated by a
+single space. Note that you can prepend the newline character with
+a carriage return character, by issuing a @code{set crlf on}.
+
+@noindent
+@kbd{v} is for all the @code{vi} users who use @code{:set numbers} - it
+toggles the left margin between column 9 and 1.
+
+@noindent
+@kbd{a} before the final space key turns on append mode. Thus
+the contents of the paste buffer will not be overwritten, but appended to.
+
+@noindent
+@kbd{A} turns on append mode and sets a (second) mark.
+
+@noindent
+@kbd{>} sets the (second) mark and writes the contents of the paste buffer
+to the screen-exchange file (@file{/tmp/screen-exchange} per default)
+once copy-mode is finished. @xref{Screen-Exchange}.@*
+This example demonstrates how to dump the
+whole scrollback buffer to that file: @*@kbd{C-a [ g SPACE G $ >}.
+
+@noindent
+@kbd{C-g} gives information about the current line and column.
+
+@noindent
+@kbd{x} exchanges the first mark and the current cursor position. You
+can use this to adjust an already placed mark.
+
+@noindent
+@kbd{@@} does nothing. Absolutely nothing. Does not even exit copy
+mode.
+
+@noindent
+All keys not described here exit copy mode.
+
+@node Paste, Registers, Copy, Copy and Paste
+@section Paste
+
+@kindex ]
+@kindex C-]
+@deffn Command paste [registers [destination]]
+(@kbd{C-a ]}, @kbd{C-a C-]})@*
+Write the (concatenated) contents of the specified registers to the stdin
+stream of the current window. The register @samp{.} is treated as the
+paste buffer. If no parameter is specified the user is prompted to enter a
+single register. The paste buffer can be filled with the
+@code{copy}, @code{history} and @code{readbuf} commands.
+Other registers can be filled with the @code{register}, @code{readreg} and
+@code{paste} commands.
+If @code{paste} is called with a second argument, the contents of the specified
+registers is pasted into the named destination register rather than
+the window. If @samp{.} is used as the second argument, the display's paste
+buffer is the destination.
+Note, that @code{paste} uses a wide variety of resources: Usually both, a
+current window and a current display are required. But whenever a second
+argument is specified no current window is needed. When the source specification
+only contains registers (not the paste buffer) then there need not be a current
+display (terminal attached), as the registers are a global resource. The
+paste buffer exists once for every user.
+@end deffn
+
+@deffn Command pastefont [state]
+Tell screen to include font information in the paste buffer. The
+default is not to do so. This command is especially usefull for
+multi character fonts like kanji.
+@end deffn
+
+@deffn Command slowpaste msec
+(none)@*
+Define the speed text is inserted by the @code{paste} command.
+If the slowpaste value is nonzero text is written character by character.
+@code{screen} will pause for @var{msec} milliseconds after each write
+to allow the application to process the input. only use @code{slowpaste} if
+your underlying system exposes flow control problems while pasting large
+amounts of text.
+@end deffn
+
+@deffn Command readreg [register [filename]]
+(none)@*
+Does one of two things, dependent on number of arguments: with zero or one
+arguments it it duplicates the paste buffer contents into the register specified
+or entered at the prompt. With two arguments it reads the contents of the named
+file into the register, just as @code{readbuf} reads the screen-exchange file
+into the paste buffer.
+The following example will paste the system's password file into
+the screen window (using register p, where a copy remains):
+
+@example
+C-a : readreg p /etc/passwd
+C-a : paste p
+@end example
+@end deffn
+
+@node Registers, Screen-Exchange, Paste, Copy and Paste
+@section Registers
+
+@deffn Command copy_reg [key]
+(none)@*
+Removed. Use @code{readreg} instead.
+@end deffn
+
+@deffn Command ins_reg [key]
+(none)@*
+Removed. Use @code{paste} instead.
+@end deffn
+
+@deffn Command process [key]
+(none)@*
+Stuff the contents of the specified register into the @code{screen}
+input queue. If no argument is given you are prompted for a
+register name. The text is parsed as if it had been typed in from the user's
+keyboard. This command can be used to bind multiple actions to a single key.
+@end deffn
+
+@deffn Command register key string
+(none)@*
+Save the specified @var{string} to the register @var{key}.
+@end deffn
+
+@deffn Command stuff string
+(none)@*
+Stuff the string @var{string} in the input buffer of the current window.
+This is like the @code{paste} command, but with much less overhead.
+You cannot paste large buffers with the @code{stuff} command. It is most
+useful for key bindings. @xref{Bindkey}
+
+@end deffn
+
+@node Screen-Exchange, History, Registers, Copy and Paste
+@section Screen-Exchange
+
+@deffn Command bufferfile [exchange-file]
+(none)@*
+Change the filename used for reading and writing with the paste buffer.
+If the @var{exchange-file} parameter is omitted, @code{screen} reverts
+to the default of @file{/tmp/screen-exchange}. The following example
+will paste the system's password file into the screen window (using the
+paste buffer, where a copy remains):
+
+@example
+C-a : bufferfile /etc/passwd
+C-a < C-a ]
+C-a : bufferfile
+@end example
+@end deffn
+
+@kindex <
+@deffn Command readbuf
+(@kbd{C-a <})@*
+Reads the contents of the current screen-exchange file into the paste buffer.
+@end deffn
+
+@kindex =
+@deffn Command removebuf
+(@kbd{C-a =})@*
+Unlinks the screen-exchange file.
+@end deffn
+
+@kindex >
+@deffn Command writebuf
+(@kbd{C-a >})@*
+Writes the contents of the paste buffer to a public accessible
+screen-exchange file. This is thought of as a primitive means of
+communication between @code{screen} users on the same host. See also
+@kbd{C-a @key{ESC}} (@pxref{Copy}).
+@end deffn
+
+@node History, , Screen-Exchange, Copy and Paste
+@section History
+
+@kindex @{
+@deffn Command history
+(@kbd{C-a @{})@*
+Usually users work with a shell that allows easy access to previous
+commands. For example, @code{csh} has the command @code{!!} to repeat
+the last command executed. @code{screen} provides a primitive way of
+recalling ``the command that started @dots{}'': You just type the first
+letter of that command, then hit @kbd{C-a @{} and @code{screen} tries to
+find a previous line that matches with the prompt character to the left
+of the cursor. This line is pasted into this window's input queue. Thus
+you have a crude command history (made up by the visible window and its
+scrollback buffer).
+@end deffn
+
+@node Subprocess Execution, Key Binding, Copy and Paste, Top
+@chapter Subprocess Execution
+Control Input or Output of a window by another filter process.
+Use with care!
+
+@menu
+* Exec:: The @code{exec} command syntax.
+* Using Exec:: Weird things that filters can do.
+@end menu
+
+@node Exec, Using Exec, , Subprocess Execution
+@section Exec
+@deffn Command exec @var{[[fdpat] newcommand [args ... ]]}
+(none)@*
+Run a unix subprocess (specified by an executable path @var{newcommand} and
+its optional arguments) in the current window. The flow of data between
+newcommand's stdin/stdout/stderr, the process already running (shell) and
+screen itself (window) is controlled by the filedescriptor pattern @var{fdpat}.
+This pattern is basically a three character sequence representing stdin, stdout
+and stderr of newcommand. A dot (@code{.}) connects the file descriptor
+to screen. An exclamation mark (@code{!}) causes the file descriptor to be
+connected to the already running process. A colon (@code{:}) combines both.
+@*
+User input will go to newcommand unless newcommand requests the old process'
+output (@var{fdpat}s first character is @samp{!} or @samp{:}) or a pipe symbol
+(@samp{|}) is added to the end of @var{fdpat}.
+@*
+Invoking @code{exec} without arguments shows name and arguments of the currently
+running subprocess in this window.
+@*
+When a subprocess is running the @code{kill} command will affect it instead of
+the window's process.
+@*
+Refer to the postscript file @file{doc/fdpat.ps} for a confusing
+illustration of all 21 possible combinations. Each drawing shows the digits
+2, 1, 0 representing the three file descriptors of newcommand. The box
+marked `W' is usual pty that has the application-process on its slave side.
+The box marked `P' is the secondary pty that now has screen at its master
+side.
+@end deffn
+
+@node Using Exec, , Exec, Subprocess Execution
+@section Using Exec
+@noindent
+Abbreviations:
+
+@itemize @bullet
+@item
+Whitespace between the word @samp{exec} and @var{fdpat} and the command name
+can be omitted.
+
+@item
+Trailing dots and a @var{fdpat} consisting only of dots can be omitted.
+
+@item
+A simple @samp{|} is synonymous for the @samp{!..|} pattern.
+
+@item
+The word @samp{exec} can be omitted when the @samp{|} abbreviation is used.
+
+@item
+The word @samp{exec} can always be replaced by leading @samp{!}.
+@end itemize
+
+@noindent
+Examples:
+
+@table @code
+@item !/bin/sh
+@itemx exec /bin/sh
+@itemx exec ... /bin/sh
+Creates another shell in the same window, while the original shell is still
+running. Output of both shells is displayed and user input is sent to the new
+@file{/bin/sh}.
+
+@item !!stty 19200
+@itemx exec!stty 19200
+@itemx exec !.. stty 19200
+Set the speed of the window's tty. If your stty command operates on stdout, then
+add another @samp{!}. This is a useful command, when a screen window is
+directly connected to a serial line that needs to be configured.
+
+@item |less
+@itemx exec !..| less
+This adds a pager to the window output. The special character @samp{|} is
+needed to give the user control over the pager although it gets its input from
+the window's process. This works, because @samp{less} listens on stderr
+(a behavior that @code{screen} would not expect without the @samp{|})
+when its stdin is not a tty. @code{Less} versions newer than 177 fail miserably
+here; good old @code{pg} still works.
+
+@item !:sed -n s/.*Error.*/\007/p
+Sends window output to both, the user and the sed command. The sed inserts an
+additional bell character (oct. 007) to the window output seen by screen.
+This will cause 'Bell in window x' messages, whenever the string @samp{Error}
+appears in the window.
+@end table
+
+@node Key Binding, Flow Control, Subprocess Execution, Top
+@chapter Key Binding
+@cindex key binding
+@cindex binding
+
+You may disagree with some of the default bindings (I know I do). The
+@code{bind} command allows you to redefine them to suit your
+preferences.
+
+@menu
+* Bind:: @code{bind} syntax.
+* Bind Examples:: Using @code{bind}.
+* Command Character:: The character used to start keyboard commands.
+* Help:: Show current key bindings.
+* Bindkey:: @code{bindkey} syntax.
+* Bindkey Examples:: Some easy examples.
+* Bindkey Control:: How to control the bindkey mechanism.
+@end menu
+
+@node Bind, Bind Examples, , Key Binding
+@section The @code{bind} command
+@deffn Command bind key [command [args]]
+(none)@*
+Bind a command to a key. The @var{key} argument is either a single
+character, a two-character sequence of the form @samp{^x} (meaning
+@kbd{C-x}), a backslash followed by an octal number (specifying the
+ASCII code of the character), or a backslash followed by a second
+character, such as @samp{\^} or @samp{\\}. The argument can also be
+quoted, if you like. If no further argument is given, any previously
+established binding for this key is removed. The @var{command}
+argument can be any command (@pxref{Command Index}).
+
+By default, most suitable commands are bound to one or more keys
+(@pxref{Default Key Bindings}; for instance, the command to create a
+new window is bound to @kbd{C-c} and @kbd{c}. The @code{bind} command
+can be used to redefine the key bindings and to define new bindings.
+@end deffn
+
+@node Bind Examples, Command Character, Bind, Key Binding
+@section Examples of the @code{bind} command
+@noindent
+Some examples:
+
+@example
+bind ' ' windows
+bind ^f screen telnet foobar
+bind \033 screen -ln -t root -h 1000 9 su
+@end example
+
+@noindent
+would bind the space key to the command that displays a list of windows
+(so that the command usually invoked by @kbd{C-a C-w} would also be
+available as @kbd{C-a space}), bind @kbd{C-f} to the command
+``create a window with a TELNET connection to foobar'', and bind
+@key{ESC} to the command that creates an non-login window with title
+@samp{root} in slot #9, with a super-user shell and a scrollbackbuffer
+of 1000 lines.
+
+@node Command Character, Help, Bind Examples, Key Binding
+@section Command Character
+
+@deffn Command escape xy
+(none)@*
+Set the command character to @var{x} and the character generating a
+literal command character to @var{y} (just like with the @samp{-e}
+option). Each argument is either a single character, a two-character
+sequence of the form @samp{^x} (meaning @kbd{C-x}), a backslash followed
+by an octal number (specifying the ASCII code of the character), or a
+backslash followed by a second character, such as @samp{\^} or
+@samp{\\}. The default is @samp{^Aa}, but @samp{``} is recommended by
+one of the authors.
+@end deffn
+
+@deffn Command defescape xy
+(none)@*
+Set the default command characters. This is equivalent to the command
+@code{escape} except that it is useful for multiuser sessions only.
+In a multiuser session
+@code{escape} changes the command character of the calling user, where
+@code{defescape} changes the default command characters for users that
+will be added later.
+@end deffn
+
+@kindex a
+@deffn Command meta
+(@kbd{C-a a})@*
+Send the command character (@kbd{C-a}) to the process in the current
+window. The keystroke for this command is the second parameter to the
+@samp{-e} command line switch (@pxref{Invoking Screen}), or the
+@code{escape} .screenrc directive.
+@end deffn
+
+@deffn Command command
+(none)@*
+This command has the same effect as typing the screen escape character
+(@kbd{C-a}). It is probably only useful for key bindings.
+@xref{Bindkey}.
+@end deffn
+
+@node Help, Bindkey, Command Character, Key Binding
+@section Help
+@kindex ?
+@deffn Command help
+(@kbd{C-a ?})@*
+Displays a help screen showing you all the key bindings. The first
+pages list all the internal commands followed by their bindings.
+Subsequent pages will display the custom commands, one command per key.
+Press space when you're done reading each page, or return to exit early.
+All other characters are ignored.
+@xref{Default Key Bindings}.
+@end deffn
+
+@node Bindkey, Bindkey Examples, Help, Key Binding
+@section Bindkey
+@deffn Command bindkey @var{[opts] [string [cmd args]]}
+(none)@*
+This command manages screen's input translation tables. Every
+entry in one of the tables tells screen how to react if a certain
+sequence of characters is encountered. There are three tables:
+one that should contain actions programmed by the user, one for
+the default actions used for terminal emulation and one for
+screen's copy mode to do cursor movement. @xref{Input Translation}
+for a list of default key bindings.
+
+If the @samp{-d}
+option is given, bindkey modifies the default table, @samp{-m}
+changes the copy mode table and with neither option the user
+table is selected. The argument @samp{string} is the sequence of
+characters to which an action is bound. This can either be a fixed
+tring or a termcap keyboard capability name (selectable with the
+@samp{-k} option).
+
+Some keys on a VT100 terminal can send a different
+string if application mode is turned on (e.g. the cursor keys).
+Such keys have two entries in the translation table. You can
+select the application mode entry by specifying the @samp{-a}
+option.
+
+The @samp{-t} option tells screen not to do intercharacter
+timing. One cannot turn off the timing if a termcap capabilty is
+used.
+
+@samp{cmd} can be any of screen's commands with an arbitrary
+number of @samp{args}. If @samp{cmd} is omitted the keybinding is
+removed from the table.
+@end deffn
+
+@node Bindkey Examples, Bindkey Control,Bindkey, Key Binding
+@section Bindkey Examples
+@noindent
+Here are some examples of keyboard bindings:
+
+@example
+bindkey -d
+@end example
+@noindent
+Show all of the default key bindings. The application mode entries
+are marked with [A].
+
+@example
+bindkey -k k1 select 1
+@end example
+@noindent
+Make the "F1" key switch to window one.
+
+@example
+bindkey -t foo stuff barfoo
+@end example
+@noindent
+Make @samp{foo} an abrevation of the word @samp{barfoo}. Timeout is
+disabled so that users can type slowly.
+
+@example
+bindkey "\024" mapdefault
+@end example
+@noindent
+This keybinding makes @samp{C-t} an escape character for keybindings. If
+you did the above @samp{stuff barfoo} binding, you can enter the word
+@samp{foo} by typing @samp{C-t foo}. If you want to insert a
+@samp{C-t} you have to press the key twice (i.e. escape the escape
+binding).
+
+@example
+bindkey -k F1 command
+@end example
+@noindent
+Make the F11 (not F1!) key an alternative screen
+escape (besides @samp{C-a}).
+
+@node Bindkey Control, , Bindkey Examples, Key Binding
+@section Bindkey Control
+@deffn Command mapdefault
+(none)@*
+Tell screen that the next input character should only be looked up
+in the default bindkey table.
+@end deffn
+@deffn Command mapnotnext
+(none)@*
+Like mapdefault, but don't even look in the default bindkey table.
+@end deffn
+@deffn Command maptimeout timo
+(none)@*
+Set the intercharacter timer for input sequence detection to a timeout
+of @var{timo} ms. The default timeout is 300ms. Maptimeout with no
+arguments shows the current setting.
+@end deffn
+
+@node Flow Control, Termcap, Key Binding, Top
+@chapter Flow Control
+@cindex flow control
+
+@code{screen} can trap flow control characters or pass them to the
+program, as you see fit. This is useful when your terminal wants to use
+XON/XOFF flow control and you are running a program which wants to use
+^S/^Q for other purposes (i.e. @code{emacs}).
+
+@menu
+* Flow Control Summary:: The effect of @code{screen} flow control
+* Flow:: Setting the flow control behavior
+* XON/XOFF:: Sending XON or XOFF to the window
+@end menu
+
+@node Flow Control Summary, Flow, , Flow Control
+@section About @code{screen} flow control settings
+Each window has a flow-control setting that determines how screen deals
+with the XON and XOFF characters (and perhaps the interrupt character).
+When flow-control is turned off, screen ignores the XON and XOFF
+characters, which allows the user to send them to the current program by
+simply typing them (useful for the @code{emacs} editor, for instance).
+The trade-off is that it will take longer for output from a
+``normal'' program to pause in response to an XOFF. With
+flow-control turned on, XON and XOFF characters are used to immediately
+pause the output of the current window. You can still send these
+characters to the current program, but you must use the appropriate
+two-character screen commands (typically @kbd{C-a q} (xon) and @kbd{C-a
+s} (xoff)). The xon/xoff commands are also useful for typing C-s and
+C-q past a terminal that intercepts these characters.
+
+Each window has an initial flow-control value set with either the
+@samp{-f} option or the @code{defflow} command. By default the
+windows are set to automatic flow-switching. It can then be toggled
+between the three states 'fixed on', 'fixed off' and 'automatic'
+interactively with the @code{flow} command bound to @kbd{C-a f}.
+
+The automatic flow-switching mode deals with flow control using the
+TIOCPKT mode (like @code{rlogin} does). If the tty driver does not
+support TIOCPKT, screen tries to determine the right mode based on the
+current setting of the application keypad --- when it is enabled,
+flow-control is turned off and visa versa. Of course, you can still
+manipulate flow-control manually when needed.
+
+If you're running with flow-control enabled and find that pressing the
+interrupt key (usually C-c) does not interrupt the display until another
+6-8 lines have scrolled by, try running screen with the @samp{interrupt}
+option (add the @samp{interrupt} flag to the @code{flow} command in your
+.screenrc, or use the @samp{-i} command-line option). This causes the
+output that @code{screen} has accumulated from the interrupted program
+to be flushed. One disadvantage is that the virtual terminal's memory
+contains the non-flushed version of the output, which in rare cases can
+cause minor inaccuracies in the output. For example, if you switch
+screens and return, or update the screen with @kbd{C-a l} you would see
+the version of the output you would have gotten without @samp{interrupt}
+being on. Also, you might need to turn off flow-control (or use
+auto-flow mode to turn it off automatically) when running a program that
+expects you to type the interrupt character as input, as the
+@samp{interrupt} parameter only takes effect when flow-control is
+enabled. If your program's output is interrupted by mistake, a simple
+refresh of the screen with @kbd{C-a l} will restore it. Give each mode
+a try, and use whichever mode you find more comfortable.
+
+@node Flow, XON/XOFF, Flow Control Summary, Flow Control
+@section Flow
+@deffn Command defflow fstate [interrupt]
+(none)@*
+Same as the @code{flow} command except that the default setting for new
+windows is changed. Initial setting is `auto'.
+Specifying @code{flow auto interrupt} has the same effect as the
+command-line options @samp{-fa} and @samp{-i}.
+Note that if @samp{interrupt} is enabled, all existing displays are
+changed immediately to forward interrupt signals.
+@end deffn
+
+@kindex f
+@kindex C-f
+@deffn Command flow [fstate]
+(@kbd{C-a f}, @kbd{C-a C-f})@*
+Sets the flow-control mode for this window to @var{fstate}, which can be
+@samp{on}, @samp{off} or @samp{auto}.
+Without parameters it cycles the current window's
+flow-control setting. Default is set by `defflow'.
+@end deffn
+
+@node XON/XOFF, , Flow, Flow Control
+@section XON and XOFF
+@kindex q
+@kindex C-q
+@deffn Command xon
+(@kbd{C-a q}, @kbd{C-a C-q})@*
+Send a ^Q (ASCII XON) to the program in the current window. Redundant
+if flow control is set to @samp{off} or @samp{auto}.
+@end deffn
+
+@kindex s
+@kindex C-s
+@deffn Command xoff
+(@kbd{C-a s}, @kbd{C-a C-s})@*
+Send a ^S (ASCII XOFF) to the program in the current window.
+@end deffn
+
+@node Termcap, Message Line, Flow Control, Top
+@chapter Termcap
+
+@code{screen} demands the most out of your terminal so that it can
+perform its VT100 emulation most efficiently. These functions provide
+means for tweaking the termcap entries for both your physical terminal
+and the one simulated by @code{screen}.
+
+@menu
+* Window Termcap:: Choosing a termcap entry for the window.
+* Dump Termcap:: Write out a termcap entry for the window.
+* Termcap Syntax:: The @code{termcap} and @code{terminfo} commands.
+* Termcap Examples:: Uses for @code{termcap}.
+* Special Capabilities:: Non-standard capabilities used by @code{screen}.
+* Autonuke:: Flush unseen output
+* Obuflimit:: Allow pending output when reading more
+* Character Translation:: Emulating fonts and charsets.
+@end menu
+
+@node Window Termcap, Dump Termcap, , Termcap
+@section Choosing the termcap entry for a window
+Usually @code{screen} tries to emulate as much of the VT100/ANSI
+standard as possible. But if your terminal lacks certain capabilities
+the emulation may not be complete. In these cases @code{screen} has to
+tell the applications that some of the features are missing. This is no
+problem on machines using termcap, because @code{screen} can use the
+@code{$TERMCAP} variable to customize the standard screen termcap.
+
+But if you do a rlogin on another machine or your machine supports only
+terminfo this method fails. Because of this @code{screen} offers a way
+to deal with these cases. Here is how it works:
+
+When @code{screen} tries to figure out a terminal name for itself, it
+first looks for an entry named @samp{screen.@var{term}}, where
+@var{term} is the contents of your @code{$TERM} variable. If no such entry
+exists, @code{screen} tries @samp{screen} (or @samp{screen-w}, if the
+terminal is wide (132 cols or more)). If even this entry cannot be
+found, @samp{vt100} is used as a substitute.
+
+The idea is that if you have a terminal which doesn't support an
+important feature (e.g. delete char or clear to EOS) you can build a new
+termcap/terminfo entry for @code{screen} (named
+@samp{screen.@var{dumbterm}}) in which this capability has been
+disabled. If this entry is installed on your machines you are able to
+do a rlogin and still keep the correct termcap/terminfo entry. The
+terminal name is put in the @code{$TERM} variable of all new windows.
+@code{screen} also sets the @code{$TERMCAP} variable reflecting the
+capabilities of the virtual terminal emulated.
+Furthermore, the variable @code{$WINDOW} is set to the window number of each
+window.
+
+The actual set of capabilities supported by the virtual terminal depends
+on the capabilities supported by the physical terminal. If, for
+instance, the physical terminal does not support underscore mode,
+@code{screen} does not put the @samp{us} and @samp{ue} capabilities into
+the window's @code{$TERMCAP} variable, accordingly. However, a minimum number
+of capabilities must be supported by a terminal in order to run
+@code{screen}; namely scrolling, clear screen, and direct cursor
+addressing (in addition, @code{screen} does not run on hardcopy
+terminals or on terminals that over-strike).
+
+Also, you can customize the @code{$TERMCAP} value used by @code{screen} by
+using the @code{termcap} command, or by defining the variable
+@code{$SCREENCAP} prior to startup. When the latter defined, its value will be
+copied verbatim into each window's @code{$TERMCAP} variable. This can either
+be the full terminal definition, or a filename where the terminal
+@samp{screen} (and/or @samp{screen-w}) is defined.
+
+Note that @code{screen} honors the @code{terminfo} command if the system
+uses the terminfo database rather than termcap. On such machines the
+@code{$TERMCAP} variable has no effect and you must use the
+@code{dumptermcap} command (@pxref{Dump Termcap}) and the @code{tic}
+program to generate terminfo entries for @code{screen} windows.
+
+When the boolean @samp{G0} capability is present in the termcap entry
+for the terminal on which @code{screen} has been called, the terminal
+emulation of @code{screen} supports multiple character sets. This
+allows an application to make use of, for instance, the VT100 graphics
+character set or national character sets. The following control
+functions from ISO 2022 are supported: @samp{lock shift G0} (@samp{SI}),
+@samp{lock shift G1} (@samp{SO}), @samp{lock shift G2}, @samp{lock shift
+G3}, @samp{single shift G2}, and @samp{single shift G3}. When a virtual
+terminal is created or reset, the ASCII character set is designated as
+@samp{G0} through @samp{G3}. When the @samp{G0} capability is present,
+screen evaluates the capabilities @samp{S0}, @samp{E0}, and @samp{C0} if
+present. @samp{S0} is the sequence the terminal uses to enable and start
+the graphics character set rather than @samp{SI}. @samp{E0} is the
+corresponding replacement for @samp{SO}. @samp{C0} gives a character by
+character translation string that is used during semi-graphics mode.
+This string is built like the @samp{acsc} terminfo capability.
+
+When the @samp{po} and @samp{pf} capabilities are present in the
+terminal's termcap entry, applications running in a @code{screen} window
+can send output to the printer port of the terminal. This allows a user
+to have an application in one window sending output to a printer
+connected to the terminal, while all other windows are still active (the
+printer port is enabled and disabled again for each chunk of output).
+As a side-effect, programs running in different windows can send output
+to the printer simultaneously. Data sent to the printer is not
+displayed in the window.
+
+Some capabilities are only put into the @code{$TERMCAP} variable of the virtual
+terminal if they can be efficiently implemented by the physical
+terminal. For instance, @samp{dl} (delete line) is only put into the
+@code{$TERMCAP} variable if the terminal supports either delete line itself or
+scrolling regions. Note that this may provoke confusion, when the
+session is reattached on a different terminal, as the value of @code{$TERMCAP}
+cannot be modified by parent processes. You can force @code{screen} to
+include all capabilities in @code{$TERMCAP} with the @samp{-a}
+command-line option (@pxref{Invoking Screen}).
+
+@node Dump Termcap, Termcap Syntax, Window Termcap, Termcap
+@section Write out the window's termcap entry
+@kindex .
+@deffn Command dumptermcap
+(@kbd{C-a .})@*
+Write the termcap entry for the virtual terminal optimized for the
+currently active window to the file @file{.termcap} in the user's
+@file{$HOME/.screen} directory (or wherever @code{screen} stores its
+sockets. @pxref{Files}). This termcap entry is identical to
+the value of the environment variable @code{$TERMCAP} that is set up by
+@code{screen} for each window. For terminfo based systems you will need
+to run a converter like @code{captoinfo} and then compile the entry with
+@code{tic}.
+@end deffn
+
+@node Termcap Syntax, Termcap Examples, Dump Termcap, Termcap
+@section The @code{termcap} command
+@deffn Command termcap term terminal-tweaks [window-tweaks]
+@deffnx Command terminfo term terminal-tweaks [window-tweaks]
+@deffnx Command termcapinfo term terminal-tweaks [window-tweaks]
+(none)@*
+Use this command to modify your terminal's termcap entry without going
+through all the hassles involved in creating a custom termcap entry.
+Plus, you can optionally customize the termcap generated for the
+windows.
+You have to place these commands in one of the screenrc starup files, as
+they are meaningless once the terminal emulator is booted.
+
+If your system uses the terminfo database rather than
+termcap, @code{screen} will understand the @code{terminfo} command which
+has the same effects as the @code{termcap} command. Two separate commands are
+provided, as there are subtle syntactic differences, e.g. when parameter
+interpolation (using @samp{%}) is required. Note that the termcap names of
+the capabilities have to be used with the @code{terminfo} command.
+
+In many cases, where the arguments are valid in both terminfo and termcap
+syntax, you can use the command @code{termcapinfo}, which is just a
+shorthand for a pair of @code{termcap} and @code{terminfo} commands with
+identical arguments.
+@end deffn
+
+The first argument specifies which terminal(s) should be affected by
+this definition. You can specify multiple terminal names by separating
+them with @samp{|}s. Use @samp{*} to match all terminals and @samp{vt*}
+to match all terminals that begin with @samp{vt}.
+
+Each @var{tweak} argument contains one or more termcap defines
+(separated by @samp{:}s) to be inserted at the start of the appropriate
+termcap entry, enhancing it or overriding existing values. The first
+tweak modifies your terminal's termcap, and contains definitions that
+your terminal uses to perform certain functions. Specify a null string
+to leave this unchanged (e.g. ""). The second (optional) tweak modifies
+all the window termcaps, and should contain definitions that screen
+understands (@pxref{Virtual Terminal}).
+
+@node Termcap Examples, Special Capabilities, Termcap Syntax, Termcap
+@section Termcap Examples
+Some examples:
+
+@example
+termcap xterm* xn:hs@@
+@end example
+
+@noindent
+Informs @code{screen} that all terminals that begin with @samp{xterm}
+have firm auto-margins that allow the last position on the screen to be
+updated (xn), but they don't really have a status line (no 'hs' --
+append @samp{@@} to turn entries off). Note that we assume @samp{xn} for
+all terminal names that start with @samp{vt}, but only if you don't
+specify a termcap command for that terminal.
+
+@example
+termcap vt* xn
+termcap vt102|vt220 Z0=\E[?3h:Z1=\E[?3l
+@end example
+
+@noindent
+Specifies the firm-margined @samp{xn} capability for all terminals that
+begin with @samp{vt}, and the second line will also add the
+escape-sequences to switch into (Z0) and back out of (Z1)
+132-character-per-line mode if this is a VT102 or VT220. (You must
+specify Z0 and Z1 in your termcap to use the width-changing commands.)
+
+@example
+termcap vt100 "" l0=PF1:l1=PF2:l2=PF3:l3=PF4
+@end example
+
+@noindent
+This leaves your vt100 termcap alone and adds the function key labels to
+each window's termcap entry.
+
+@example
+termcap h19|z19 am@@:im=\E@@:ei=\EO dc=\E[P
+@end example
+
+@noindent
+Takes a h19 or z19 termcap and turns off auto-margins (am@@) and enables
+the insert mode (im) and end-insert (ei) capabilities (the @samp{@@} in
+the @samp{im} string is after the @samp{=}, so it is part of the
+string). Having the @samp{im} and @samp{ei} definitions put into your
+terminal's termcap will cause screen to automatically advertise the
+character-insert capability in each window's termcap. Each window will
+also get the delete-character capability (dc) added to its termcap,
+which screen will translate into a line-update for the terminal (we're
+pretending it doesn't support character deletion).
+
+If you would like to fully specify each window's termcap entry, you
+should instead set the @code{$SCREENCAP} variable prior to running
+@code{screen}. @xref{Virtual Terminal}, for the details of the
+@code{screen} terminal emulation. @xref{Top, , Termcap, termcap, The
+Termcap Manual}, for more information on termcap definitions.
+
+@node Special Capabilities, Autonuke, Termcap Examples, Termcap
+@section Special Terminal Capabilities
+@cindex terminal capabilities
+@cindex capabilities
+The following table describes all terminal capabilities that are
+recognized by @code{screen} and are not in the termcap manual
+(@pxref{Top, , Termcap, termcap, The Termcap Manual}).
+You can place these capabilities in your termcap entries (in
+@file{/etc/termcap}) or use them with the commands @code{termcap},
+@code{terminfo} and @code{termcapinfo} in your @code{screenrc} files. It is
+often not possible to place these capabilities in the terminfo database.
+@table @samp
+@item LP
+(bool)@*
+Terminal has VT100 style margins (`magic margins'). Note that
+this capability is obsolete --- @code{screen} now uses the standard
+@samp{xn} instead.
+
+@item Z0
+(str)@*
+Change width to 132 columns.
+
+@item Z1
+(str)@*
+Change width to 80 columns.
+
+@item WS
+(str)@*
+Resize display. This capability has the desired width and height as
+arguments. SunView(tm) example: @samp{\E[8;%d;%dt}.
+
+@item NF
+(bool)@*
+Terminal doesn't need flow control. Send ^S and ^Q direct to
+the application. Same as @code{flow off}. The opposite of this
+capability is @samp{nx}.
+
+@item G0
+(bool)@*
+Terminal can deal with ISO 2022 font selection sequences.
+
+@item S0
+(str)@*
+Switch charset @samp{G0} to the specified charset. Default
+is @samp{\E(%.}.
+
+@item E0
+(str)@*
+Switch charset @samp{G0} back to standard charset. Default
+is @samp{\E(B}.
+
+@item C0
+(str)@*
+Use the string as a conversion table for font 0. See
+the @samp{ac} capability for more details.
+
+@item CS
+(str)@*
+Switch cursor keys to application mode.
+
+@item CE
+(str)@*
+Switch cursor keys to cursor mode.
+
+@item AN
+(bool)@*
+Enable autonuke for displays of this terminal type.
+(@pxref{Autonuke}).
+
+@item OL
+(num)@*
+Set the output buffer limit. See the @samp{obuflimit} command
+(@pxref{Obuflimit}) for more details.
+
+@item KJ
+(str)@*
+Set the kanji type of the terminal. Valid strings are @samp{jis},
+@samp{euc} and @samp{sjis}.
+
+@item AF
+(str)@*
+Change character forground color in an ANSI conform way. This
+capability will almost always be set to @samp{\E[3%dm}
+(@samp{\E[3%p1%dm} on terminfo machines).
+
+@item AB
+(str)@*
+Same as @samp{AF}, but change background color.
+
+@item AX
+(bool)@*
+Does understand ANSI set default fg/bg color (@samp{\E[39m / \E[49m}).
+
+@item XC
+(str)@*
+Describe a translation of characters to strings depending on the
+current font. (@pxref{Character Translation}).
+@end table
+
+@node Autonuke, Obuflimit, Special Capabilities, Termcap
+@section Autonuke
+@deffn Command autonuke @var{state}
+(none)@*
+Sets whether a clear screen sequence should nuke all the output
+that has not been written to the terminal. @xref{Obuflimit}.
+This property is set per display, not per window.
+@end deffn
+
+@deffn Command defautonuke @var{state}
+(none)@*
+Same as the @code{autonuke} command except that the default setting for
+new displays is also changed. Initial setting is @code{off}.
+Note that you can use the special @code{AN} terminal capability if you
+want to have a terminal type dependent setting.
+@end deffn
+
+@node Obuflimit, Character Translation, Autonuke, Termcap
+@section Obuflimit
+@deffn Command obuflimit @var{[limit]}
+(none)@*
+If the output buffer contains more bytes than the specified limit, no
+more data will be read from the windows. The default value is 256. If
+you have a fast display (like @code{xterm}), you can set it to some
+higher value. If no argument is specified, the current setting is displayed.
+This property is set per display, not per window.
+@end deffn
+
+@deffn Command defobuflimit @var{limit}
+(none)@*
+Same as the @code{obuflimit} command except that the default setting for new
+displays is also changed. Initial setting is 256 bytes. Note that you can use
+the special @code{OL} terminal capability if you want to have a terminal
+type dependent limit.
+@end deffn
+
+@node Character Translation, , Obuflimit, Termcap
+@section Character Translation
+@code{Screen} has a powerful mechanism to translate characters to
+arbitrary strings depending on the current font and terminal type.
+Use this feature if you want to work with a common standard character
+set (say ISO8851-latin1) even on terminals that scatter the more
+unusual characters over several national language font pages.
+
+Syntax:
+
+@example
+ XC=@var{<charset-mapping>}@{,,@var{<charset-mapping>}@}
+ @var{<charset-mapping>} := @var{<designator>}@var{<template>}@{,@var{<mapping>}@}
+ @var{<mapping>} := @var{<char-to-be-mapped>}@var{<template-arg>}
+@end example
+
+The things in braces may be repeated any number of times.
+
+A @var{<charset-mapping>} tells screen how to map characters
+in font @var{<designator>} (@samp{B}: Ascii, @samp{A}: UK,
+@samp{K}: german, etc.)
+to strings. Every @var{<mapping>} describes to what string a single
+character will be translated. A template mechanism is used, as
+most of the time the codes have a lot in common (for example
+strings to switch to and from another charset). Each occurence
+of @samp{%} in @var{<template>} gets substituted with the
+@var{template-arg}
+specified together with the character. If your strings are not
+similar at all, then use @samp{%} as a template and place the full
+string in @var{<template-arg>}. A quoting mechanism was added to make
+it possible to use a real @samp{%}. The @samp{\} character quotes the
+special characters @samp{\}, @samp{%}, and @samp{,}.
+
+Here is an example:
+
+@example
+ termcap hp700 'XC=B\E(K%\E(B,\304[,\326\\\\,\334]'
+@end example
+
+This tells @code{screen}, how to translate ISOlatin1 (charset @samp{B})
+upper case umlaut characters on a @code{hp700} terminal that has a
+german charset. @samp{\304} gets translated to
+@samp{\E(K[\E(B} and so on.
+Note that this line gets parsed *three* times before the internal
+lookup table is built, therefore a lot of quoting is needed to
+create a single @samp{\}.
+
+Another extension was added to allow more emulation: If a mapping
+translates the unquoted @samp{%} char, it will be sent to the terminal
+whenever screen switches to the corresponding @var{<designator>}.
+In this
+special case the template is assumed to be just @samp{%} because
+the charset switch sequence and the character mappings normaly
+haven't much in common.
+
+This example shows one use of the extension:
+@example
+ termcap xterm 'XC=K%,%\E(B,[\304,\\\\\326,]\334'
+@end example
+
+Here, a part of the german (@samp{K}) charset is emulated on an xterm.
+If screen has to change to the @samp{K} charset, @samp{\E(B} will be
+sent
+to the terminal, i.e. the ASCII charset is used instead. The
+template is just @samp{%}, so the mapping is straightforward:
+@samp{[} to @samp{\304}, @samp{\} to @samp{\326}, and @samp{]} to
+@samp{\334}.
+
+@node Message Line, Logging, Termcap, Top
+@chapter The Message Line
+@cindex message line
+
+@code{screen} displays informational messages and other diagnostics in a
+@dfn{message line} at the bottom of the screen. If your terminal has a
+status line defined in its termcap, screen will use this for displaying
+its messages, otherwise the last line of the screen will be temporarily
+overwritten and output will be momentarily interrupted. The message
+line is automatically removed after a few seconds delay, but it can also
+be removed early (on terminals without a status line) by beginning to
+type.
+
+@menu
+* Privacy Message:: Using the message line from your program.
+* Hardware Status Line:: Use the terminal's hardware status line.
+* Last Message:: Redisplay the last message.
+* Message Wait:: Control how long messages are displayed.
+@end menu
+
+@node Privacy Message, Hardware Status Line, , Message Line
+@section Using the message line from your program
+The message line facility can be used by an application running in the
+current window by means of the ANSI @dfn{Privacy message} control
+sequence. For instance, from within the shell, try something like:
+
+@example
+echo "@value{esc}^Hello world from window $WINDOW@value{esc}\"
+@end example
+
+where @samp{@value{esc}} is ASCII ESC and @samp{^} is a literal caret or
+up-arrow.
+
+@node Hardware Status Line, Last Message, Privacy Message, Message Line
+@section Hardware Status Line
+@deffn Command hardstatus [state]
+(none)@*
+Toggles the use of the terminal's hardware status line. If @samp{on},
+@code{screen} will use this facility to display one line messages.
+Otherwise these messages are overlayed in reverse video mode at the
+display line. Note that the hardstatus feature can only be used if the
+termcap/terminfo capabilities "hs", "ts", "fs" and "ds" are set
+properly. Default is @samp{on} whenever the "hs" capability is present.
+@end deffn
+
+@node Last Message, Message Wait, Hardware Status Line, Message Line
+@section Display Last Message
+@kindex m
+@kindex C-m
+@deffn Command lastmsg
+(@kbd{C-a m}, @kbd{C-a C-m})@*
+Repeat the last message displayed in the message line. Useful if you're
+typing when a message appears, because (unless your terminal has a
+hardware status line) the message goes away when you press a key.
+@end deffn
+
+@node Message Wait, , Last Message, Message Line
+@section Message Wait
+@deffn Command msgminwait sec
+(none)@*
+Defines the time @code{screen} delays a new message when another is
+currently displayed. Defaults to 1 second.
+@end deffn
+
+@deffn Command msgwait sec
+(none)@*
+Defines the time a message is displayed, if @code{screen} is not
+disturbed by other activity. Defaults to 5 seconds.
+@end deffn
+
+@node Logging, Startup, Message Line, Top
+@chapter Logging
+
+This section describes the commands for keeping a record of your session.
+
+@menu
+* Hardcopy:: Dump the current screen to a file
+* Log:: Log the output of a window to a file
+@end menu
+
+@node Hardcopy, Log, , Logging
+@section hardcopy
+@kindex h
+@kindex C-h
+@deffn Command hardcopy
+(@kbd{C-a h}, @kbd{C-a C-h})@*
+Writes out the current display contents to the file @file{hardcopy.@var{n}}
+in the window's default directory, where @var{n} is the number of the
+current window. This either appends or overwrites the file if it
+exists, as determined by the @code{hardcopy_append} command.
+@end deffn
+
+@deffn Command hardcopy_append state
+(none)@*
+If set to @samp{on}, @code{screen} will append to the
+@file{hardcopy.@var{n}} files created by the command @code{hardcopy};
+otherwise, these files are overwritten each time.
+@end deffn
+
+@deffn Command hardcopydir directory
+(none)@*
+Defines a directory where hardcopy files will be placed.
+If unset hardcopys are dumped in screen's current working
+directory.
+@end deffn
+
+@node Log, , Hardcopy, Logging
+@section log
+@kindex H
+@deffn Command log [state]
+(@kbd{C-a H})@*
+Begins/ends logging of the current window to the file
+@file{screenlog.@var{n}} in the window's default directory, where
+@var{n} is the number of the current window.
+This filename can be changed with the @samp{logfile} command.
+If no parameter is given,
+the logging state is toggled. The session log is
+appended to the previous contents of the file if it already exists. The
+current contents and the contents of the scrollback history are not
+included in the session log. Default is @samp{off}.
+@end deffn
+
+@deffn Command logfile filename
+(none)@*
+Defines the name the logfiles will get. The default is @samp{screenlog.%n}.
+@end deffn
+
+@node Startup, Miscellaneous, Logging, Top
+@chapter Startup
+
+This section describes commands which are only useful in the
+@file{.screenrc} file, for use at startup.
+
+@menu
+* echo:: Display a message.
+* sleep:: Pause execution of the @file{.screenrc}.
+* Startup Message:: Control display of the copyright notice.
+@end menu
+
+@node echo, sleep, , Startup
+@section echo
+@deffn Command echo [@t{-n}] message
+(none)@*
+The echo command may be used to annoy @code{screen} users with a
+'message of the day'. Typically installed in a global screenrc.
+The option @samp{-n} may be used to suppress the line feed.
+See also @code{sleep}.
+Echo is also useful for online checking of environment variables.
+@end deffn
+
+@node sleep, Startup Message, echo, Startup
+@section sleep
+@deffn Command sleep num
+(none)@*
+This command will pause the execution of a .screenrc file for @var{num}
+seconds. Keyboard activity will end the sleep. It may be used to give
+users a chance to read the messages output by @code{echo}.
+@end deffn
+
+@node Startup Message, , sleep, Startup
+@section Startup Message
+@deffn Command startup_message state
+(none)@*
+Select whether you want to see the copyright notice during startup.
+Default is @samp{on}, as you probably noticed.
+@end deffn
+
+@node Miscellaneous, Environment, Startup, Top
+@chapter Miscellaneous commands
+
+The commands described here do not fit well under any of the other
+categories.
+
+@menu
+* At:: Execute a command at other displays or windows.
+* Break:: Send a break signal to the window.
+* Debug:: Suppress/allow debugging output.
+* License:: Display the disclaimer page.
+* Nethack:: Use @code{nethack}-like error messages.
+* Number:: Change the current window's number.
+* Silence:: Notify on inactivity.
+* Time:: Display the time and load average.
+* Version:: Display the version of @code{screen}.
+* Zombie:: Keep dead windows.
+* Printcmd:: Set command for VT100 printer port emulation.
+* Sorendition:: Change the text highlighting method.
+@end menu
+
+@node At, Break, , Miscellaneous
+@section At
+@deffn Command at [identifier][#|*|%] command [args]
+(none)@*
+Execute a command at other displays or windows as if it had been entered there.
+@code{At} changes the context (the `current window' or `current display'
+setting) of the command. If the first parameter describes a non-unique context,
+the command will be executed multiple times. If the first parameter is of the
+form @samp{@var{identifier}*} then identifier is matched against user names.
+The command is executed once for each display of the selected user(s).
+If the first parameter is of the form @samp{@var{identifier}%} identifier is
+matched against displays. Displays are named after the ttys they attach. The
+prefix @samp{/dev/} or @samp{/dev/tty} may be omitted from the identifier.
+If @var{identifier} has a @code{#} or nothing appended it is matched against
+window numbers and titles. Omitting an identifier in front of the @code{#},
+@code{*} or @code{%} character selects all users, displays or windows because
+a prefix-match is performed. Note that on the affected display(s) a short
+message will describe what happened. Caution: Permission is checked for the
+owners or the affected display(s), not for the initiator of the `at' command.
+@end deffn
+
+@node Break, Debug, At, Miscellaneous
+@section Break
+@deffn Command break [duration]
+(none)@*
+Send a break signal for @var{duration}*0.25 seconds to this window.
+Most useful if a character device is attached to the window rather than
+a shell process.
+@end deffn
+
+@deffn Command pow_break
+(none)@*
+Reopen the window's terminal line and send a break condition.
+@end deffn
+
+@node Debug, License, Break, Miscellaneous
+@section Debug
+@deffn Command debug [on|off]
+(none)@*
+Turns runtime debugging on or off. If @code{screen} has been compiled with
+option @code{-DDEBUG} debugging is available and is turned on per default.
+Note that this command only affects debugging output from the main
+@samp{SCREEN} process.
+@end deffn
+
+@node License, Nethack, Debug, Miscellaneous
+@section License
+@deffn Command license
+(none)@*
+Display the disclaimer page. This is done whenever @code{screen} is
+started without options, which should be often enough.
+@end deffn
+
+@node Nethack, Number, License, Miscellaneous
+@section Nethack
+@deffn Command nethack state
+(none)@*
+Changes the kind of error messages used by @code{screen}. When you are
+familiar with the game @code{nethack}, you may enjoy the nethack-style
+messages which will often blur the facts a little, but are much funnier
+to read. Anyway, standard messages often tend to be unclear as well.
+
+This option is only available if @code{screen} was compiled with the
+NETHACK flag defined (@pxref{Installation}). The default setting is then
+determined by the presence of the environment variable
+@code{$NETHACKOPTIONS}.
+@end deffn
+
+@node Number, Silence, Nethack, Miscellaneous
+@section Number
+@kindex N
+@deffn Command number @var{[n]}
+(@kbd{C-a N})@*
+Change the current window's number. If the given number @var{n} is already
+used by another window, both windows exchange their numbers. If no argument is
+specified, the current window number (and title) is shown.
+@end deffn
+
+@node Silence, Time, Number, Miscellaneous
+@section Silence
+@deffn Command silence @var{[state|sec]}
+(none)@*
+Toggles silence monitoring of windows. When silence is turned on and an
+affected window is switched into the background, you will receive the
+silence notification message in the status line after a specified period
+of inactivity (silence). The default timeout can be changed with the
+@code{silencewait} command or by specifying a number of seconds instead of
+@code{on} or @code{off}. Silence is initially off for all windows.
+@end deffn
+
+@deffn Command silencewait @var{seconds}
+(none)@*
+Define the time that all windows monitored for silence should wait
+before displaying a message. Default is 30 seconds.
+@end deffn
+
+@node Time, Version, Silence, Miscellaneous
+@section Time
+@kindex t
+@kindex C-t
+@deffn Command time
+(@kbd{C-a t}, @kbd{C-a C-t})@*
+Uses the message line to display the time of day, the host name, and the
+load averages over 1, 5, and 15 minutes (if this is available on your
+system). For window-specific information use @code{info} (@pxref{Info}).
+@end deffn
+
+@node Version, Zombie, Time, Miscellaneous
+@section Version
+@kindex v
+@deffn Command version
+(@kbd{C-a v})@*
+Display the version and modification date in the message line.
+@end deffn
+
+@node Zombie, Printcmd, Version, Miscellaneous
+@section Zombie
+@deffn Command zombie @var{[keyx]}
+@deffnx Command defzombie @var{[keyx]}
+(none)@*
+Per default windows are removed from the window list as soon as the
+windows process (e.g. shell) exits. When a string of two keys is
+specified to the zombie command, `dead' windows will remain in the list.
+The @code{kill} kommand may be used to remove the window. Pressing the first key
+in the dead window has the same effect. Pressing the second key, however,
+screen will attempt to resurrect the window. The process that was initially
+running in the window will be launched again. Calling @code{zombie} without
+parameters will clear the zombie setting, thus making windows disappear when
+the process terminates.
+
+As the zombie setting is affected globally for all windows, this command
+should only be called @code{defzombie}. Until we need this as a per window
+setting, the commands @code{zombie} and @code{defzombie} are synonymous.
+@end deffn
+
+@node Printcmd, Sorendition, Zombie, Miscellaneous
+@section Printcmd
+@deffn Command printcmd @var{[cmd]}
+(none)@*
+If @var{cmd} is not an empty string, screen will not use the terminal
+capabilities @code{po/pf} for printing if it detects an ansi print
+sequence @code{ESC [ 5 i}, but pipe the output into @var{cmd}.
+This should normally be a command like @samp{lpr} or
+@samp{cat > /tmp/scrprint}.
+@code{Printcmd} without an argument displays the current setting.
+The ansi sequence @code{ESC \} ends printing and closes the pipe.
+
+Warning: Be careful with this command! If other user have write
+access to your terminal, they will be able to fire off print commands.
+@end deffn
+
+@node Sorendition, , Printcmd, Miscellaneous
+@section Sorendition
+@deffn Command sorendition @var{[attr [color]]}
+(none)@*
+Change the way screen does highlighting for text marking and printing
+messages.
+@var{attr} is a hexadecimal number and describes the attributes
+(inverse, underline, ...) the text will get. @var{color}
+is a 2 digit number and changes the
+forground/background of the highlighted text.
+Some knowledge of screen's internal character representation is
+needed to make the characters appear in the desired way. The default
+is currently @samp{10 99} (standout, default colors).
+@end deffn
+
+@node Environment, Files, Miscellaneous, Top
+@chapter Environment Variables
+@cindex environment
+
+@table @code
+@item COLUMNS
+Number of columns on the terminal (overrides termcap entry).
+
+@item HOME
+Directory in which to look for .screenrc.
+
+@item ISCREENRC
+Alternate user screenrc file.
+
+@item LINES
+Number of lines on the terminal (overrides termcap entry).
+
+@item LOCKPRG
+Screen lock program.
+
+@item NETHACKOPTIONS
+Turns on @code{nethack} option.
+
+@item PATH
+Used for locating programs to run.
+
+@item SCREENCAP
+For customizing a terminal's @code{TERMCAP} value.
+
+@item SCREENDIR
+Alternate socket directory.
+
+@item SCREENRC
+Alternate user screenrc file.
+
+@item SHELL
+Default shell program for opening windows (default @file{/bin/sh}).
+
+@item STY
+Alternate socket name. If @code{screen} is invoked, and the environment variable
+@code{STY} is set, then it creates only a window in the running @code{screen}
+session rather than starting a new session.
+
+@item SYSSCREENRC
+Alternate system screenrc file.
+
+@item TERM
+Terminal name.
+
+@item TERMCAP
+Terminal description.
+@end table
+
+@node Files, Credits, Environment, Top
+@chapter Files Referenced
+@cindex files
+
+@table @file
+@item .../screen-3.?.??/etc/screenrc
+@itemx .../screen-3.?.??/etc/etcscreenrc
+Examples in the @code{screen} distribution package for private and
+global initialization files.
+
+@item @code{$SYSSCREENRC}
+@itemx /local/etc/screenrc
+@code{screen} initialization commands
+
+@item @code{$ISCREENRC}
+@itemx @code{$SCREENRC}
+@itemx @code{$HOME}/.iscreenrc
+@itemx @code{$HOME}/.screenrc
+Read in after /local/etc/screenrc
+
+@item @code{$ISCREENDIR}/S-@var{login}
+@itemx @code{$SCREENDIR}/S-@var{login}
+
+@item /local/screens/S-@var{login}
+Socket directories (default)
+
+@item /usr/tmp/screens/S-@var{login}
+Alternate socket directories.
+
+@item @var{socket directory}/.termcap
+Written by the @code{dumptermcap} command
+
+@item /usr/tmp/screens/screen-exchange or
+@itemx /tmp/screen-exchange
+@code{screen} interprocess communication buffer
+
+@item hardcopy.[0-9]
+Screen images created by the hardcopy command
+
+@item screenlog.[0-9]
+Output log files created by the log command
+
+@item /usr/lib/terminfo/?/* or
+@itemx /etc/termcap
+Terminal capability databases
+
+@item /etc/utmp
+Login records
+
+@item @code{$LOCKPRG}
+Program for locking the terminal.
+@end table
+
+@node Credits, Bugs, Files, Top
+@chapter Credits
+
+@noindent
+Authors @*
+=======
+
+Originally created by Oliver Laumann, this latest version was
+produced by Wayne Davison, Juergen Weigert and Michael Schroeder.
+
+@noindent
+Contributors @*
+============
+
+@example
+ Ken Beal (kbeal@@amber.ssd.csd.harris.com),
+ Rudolf Koenig (rfkoenig@@informatik.uni-erlangen.de),
+ Toerless Eckert (eckert@@informatik.uni-erlangen.de),
+ Wayne Davison (davison@@borland.com),
+ Patrick Wolfe (pat@@kai.com, kailand!pat),
+ Bart Schaefer (schaefer@@cse.ogi.edu),
+ Nathan Glasser (nathan@@brokaw.lcs.mit.edu),
+ Larry W. Virden (lvirden@@cas.org),
+ Howard Chu (hyc@@hanauma.jpl.nasa.gov),
+ Tim MacKenzie (tym@@dibbler.cs.monash.edu.au),
+ Markku Jarvinen (mta@@@{cc,cs,ee@}.tut.fi),
+ Marc Boucher (marc@@CAM.ORG),
+ Doug Siebert (dsiebert@@isca.uiowa.edu),
+ Ken Stillson (stillson@@tsfsrv.mitre.org),
+ Ian Frechett (frechett@@spot.Colorado.EDU),
+ Brian Koehmstedt (bpk@@gnu.ai.mit.edu),
+ Don Smith (djs6015@@ultb.isc.rit.edu),
+ Frank van der Linden (vdlinden@@fwi.uva.nl),
+ Martin Schweikert (schweik@@cpp.ob.open.de),
+ David Vrona (dave@@sashimi.lcu.com),
+ E. Tye McQueen (tye%spillman.UUCP@@uunet.uu.net),
+ Matthew Green (mrgreen@@mame.mu.oz.au),
+ Christopher Williams (cgw@@unt.edu),
+ Matt Mosley (mattm@@access.digex.net),
+ Gregory Neil Shapiro (gshapiro@@wpi.WPI.EDU),
+ Jason Merrill (jason@@jarthur.Claremont.EDU).
+@end example
+
+@noindent
+Version @*
+=======
+
+This manual describes version @value{version} of the @code{screen}
+program. Its roots are a merge of a custom version 2.3PR7 by Wayne
+Davison and several enhancements to Oliver Laumann's version 2.0.
+Note that all versions numbered 2.x are copyright by Oliver Laumann.
+
+See also @xref{Availability}.
+
+@node Bugs, Installation, Credits, Top
+@chapter Bugs
+@cindex bugs
+
+Just like any other significant piece of software, @code{screen} has a
+few bugs and missing features. Please send in a bug report if you have
+found a bug not mentioned here.
+
+@menu
+* Known Bugs:: Problems we know about.
+* Reporting Bugs:: How to contact the maintainers.
+* Availability:: Where to find the lastest screen version.
+@end menu
+
+@node Known Bugs, Reporting Bugs, , Bugs
+@section Known Bugs
+
+@itemize @bullet
+@item
+@samp{dm} (delete mode) and @samp{xs} are not handled correctly (they
+are ignored). @samp{xn} is treated as a magic-margin indicator.
+
+@item
+@code{screen} has no clue about double-high or double-wide characters.
+But this is the only area where @code{vttest} is allowed to fail.
+
+@item
+It is not possible to change the environment variable @code{$TERMCAP}
+when reattaching under a different terminal type.
+
+@item
+The support of terminfo based systems is very limited. Adding extra
+capabilities to @code{$TERMCAP} may not have any effects.
+
+@item
+@code{screen} does not make use of hardware tabs.
+
+@item
+@code{screen} must be installed setuid root in order to be able to
+correctly change the owner of the tty device file for each window.
+Special permission may also be required to write the file
+@file{/etc/utmp}.
+
+@item
+Entries in @file{/etc/utmp} are not removed when @code{screen} is killed
+with SIGKILL. This will cause some programs (like "w" or "rwho") to
+advertise that a user is logged on who really isn't.
+
+@item
+@code{screen} may give a strange warning when your tty has no utmp
+entry.
+
+@item
+When the modem line was hung up, @code{screen} may not automatically
+detach (or quit) unless the device driver sends a HANGUP signal.
+To detach such a @code{screen} session use the -D or -d command
+line option.
+
+@item
+A weird imagination is most useful to gain full advantage of all the
+features.
+@end itemize
+
+@node Reporting Bugs, Availability, Known Bugs, Bugs
+@section Reporting Bugs
+@cindex bug report
+
+If you find a bug in @code{Screen}, please send electronic mail to
+@w{@samp{screen@@uni-erlangen.de}}, and also to
+@w{@samp{bug-gnu-utils@@prep.ai.mit.edu}}. Include the version number
+of @code{Screen} which you are using. Also include in your message the
+hardware and operating system, the compiler used to compile, a
+description of the bug behavior, and the conditions that triggered the
+bug. Please recompile @code{screen} with the @samp{-DDEBUG -DTMPTEST} options
+enabled, reproduce the bug, and have a look at the debug output written to
+the directory @file{/tmp/debug}. If necessary quote suspect passages from the
+debug output and show the contents of your @file{config.h} if it matters.
+
+@node Availability, , Reporting Bugs, Bugs
+@section Availability
+@cindex availability
+
+@code{Screen} is available under the @code{GNU} copyleft.
+
+The latest official release of @code{screen} available via anonymous
+ftp from @samp{prep.ai.mit.edu}, @samp{nic.funet.fi} or any other
+@code{GNU} distribution site. The latest beta testing release of
+@code{screen} is available from @samp{ftp.uni-erlangen.de
+(131.188.1.43)}, in the directory @file{pub/utilities/screen}.
+
+@node Installation, Concept Index, Bugs, Top
+@chapter Installation
+@cindex installation
+
+Since @code{screen} uses pseudo-ttys, the select system call, and
+UNIX-domain sockets/named pipes, it will not run under a system that
+does not include these features of 4.2 and 4.3 BSD UNIX.
+
+@menu
+* Socket Directory:: Where screen stores its handle.
+* Compiling Screen::
+@end menu
+
+@node Socket Directory,
+@section Socket Directory
+@cindex socket directory
+
+The socket directory defaults either to @file{$HOME/.screen} or simply to
+@file{/tmp/screens} or preferably to @file{/usr/local/screens} chosen at
+compile-time. If @code{screen} is installed
+setuid root, then the administrator should compile screen with an
+adequate (not NFS mounted) @code{SOCKDIR}. If @code{screen} is not
+running setuid-root, the user can specify any mode 777 directory in the
+environment variable @code{$SCREENDIR}.
+
+@node Compiling Screen, , Socket Directory, Installation
+@section Compiling Screen
+@cindex compiling screen
+
+To compile and install screen:
+
+The @code{screen} package comes with a @code{GNU Autoconf} configuration
+script. Before you compile the package run
+
+@center @code{sh ./configure}
+
+This will create a @file{config.h} and @file{Makefile} for your machine.
+If @code{configure} fails for some reason, then look at the examples and
+comments found in the @file{Makefile.in} and @file{config.h.in} templates.
+Rename @file{config.status} to @file{config.status.@var{machine}} when
+you want to keep configuration data for multiple architectures. Running
+@code{sh ./config.status.@var{machine}} recreates your configuration
+significantly faster than rerunning @code{configure}.
+@*
+Read through the "User Configuration" section of @file{config.h}, and verify
+that it suits your needs.
+A comment near the top of this section explains why it's best to
+install screen setuid to root.
+Check for the place for the global @file{screenrc}-file and for the socket
+directory.
+@*
+Check the compiler used in @file{Makefile}, the prefix path where to install
+@code{screen}. Then run
+
+@center @code{make}
+
+If @code{make} fails to produce one of the files @file{term.h}, @file{comm.h}
+or @file{tty.c}, then use @code{@var{filename.x}.dist} instead.
+For additional information about installation of @code{screen} refer to the
+file @file{INSTALLATION}, coming with this package.
+
+@node Concept Index, Command Index, Installation, Top
+@unnumbered Concept Index
+
+@printindex cp
+
+@node Command Index, Keystroke Index, Concept Index, Top
+@unnumbered Command Index
+
+This is a list of all the commands supported by @code{screen}.
+
+@printindex fn
+
+@node Keystroke Index, , Command Index, Top
+@unnumbered Keystroke Index
+
+This is a list of the default key bindings.
+
+The leading escape character (@pxref{Command Character}) has been omitted
+from the key sequences, since it is the same for all bindings.
+
+@printindex ky
+
+@shortcontents
+@contents
+@bye
+
diff --git a/etc/etcscreenrc b/etc/etcscreenrc
new file mode 100644
index 0000000..301d6b9
--- /dev/null
+++ b/etc/etcscreenrc
@@ -0,0 +1,95 @@
+#3.3
+# This is a global screenrc file
+# Install this file as /usr/local/etc/screenrc. See config.h
+#
+# Flaws of termcap and standard settings are done here.
+# Note: This file should not be shared between different hosts.
+# The 'termcap' lines are written in termcap syntax.
+# The syntax for a terminfo based host is slightly different.
+#
+
+#startup_message off
+
+#defflow on # will force screen to process ^S/^Q
+
+deflogin on
+#autodetach off
+
+vbell on
+vbell_msg " Wuff ---- Wuff!! "
+
+# all termcap entries are now duplicated as terminfo entries.
+# only difference should be the slightly modified syntax, and check for
+# terminfo entries, that are already corected in the database.
+#
+# G0 we have a SEMI-GRAPHICS-CHARACTER-MODE
+# WS this sequence resizes our window.
+# cs this sequence changes the scrollregion
+# hs@ we have no hardware statusline. screen will only believe that
+# there is a hardware status line if hs,ts,fs,ds are all set.
+# ts to statusline
+# fs from statusline
+# ds delete statusline
+# al add one line
+# AL add multiple lines
+# dl delete one line
+# DL delete multiple lines
+# ic insert one char (space)
+# IC insert multiple chars
+# nx terminal uses xon/xoff
+
+termcap facit|vt100|xterm LP:G0
+terminfo facit|vt100|xterm LP:G0
+
+#the vt100 description does not mention "dl". *sigh*
+termcap vt100 dl=5\E[M
+terminfo vt100 dl=5\E[M
+
+#facit's "al" / "dl" are buggy if the current / last line
+#contain attributes...
+termcap facit al=\E[L\E[K:AL@:dl@:DL@:cs=\E[%i%d;%dr:ic@
+terminfo facit al=\E[L\E[K:AL@:dl@:DL@:cs=\E[%i%p1%d;%p2%dr:ic@
+
+#make sun termcap/info better
+termcap sun 'up=^K:AL=\E[%dL:DL=\E[%dM:UP=\E[%dA:DO=\E[%dB:LE=\E[%dD:RI=\E[%dC:IC=\E[%d@:WS=1000\E[8;%d;%dt'
+terminfo sun 'up=^K:AL=\E[%p1%dL:DL=\E[%p1%dM:UP=\E[%p1%dA:DO=\E[%p1%dB:LE=\E[%p1%dD:RI=\E[%p1%dC:IC=\E[%p1%d@:WS=\E[8;%p1%d;%p2%dt$<1000>'
+
+#xterm understands both im/ic and doesn't have a status line.
+#Note: Do not specify im and ic in the real termcap/info file as
+#some programs (e.g. vi) will (no,no, may (jw)) not work anymore.
+termcap xterm|fptwist hs@:cs=\E[%i%d;%dr:im=\E[4h:ei=\E[4l
+terminfo xterm|fptwist hs@:cs=\E[%i%p1%d;%p2%dr:im=\E[4h:ei=\E[4l
+
+# Long time I had this in my private screenrc file. But many people
+# seem to want it (jw):
+# we do not want the width to change to 80 characters on startup:
+# on suns, /etc/termcap has :is=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;3;4;6l:
+termcap xterm 'is=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;4;6l'
+terminfo xterm 'is=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;4;6l'
+
+#
+# Do not use xterms alternate window buffer.
+# This one would not add lines to the scrollback buffer.
+#termcap xterm|xterms|xs ti=\E7\E[?47l
+#terminfo xterm|xterms|xs ti=\E7\E[?47l
+
+#make hp700 termcap/info better
+termcap hp700 'Z0=\E[?3h:Z1=\E[?3l:hs:ts=\E[62"p\E[0$~\E[2$~\E[1$}:fs=\E[0}\E[61"p:ds=\E[62"p\E[1$~\E[61"p:ic@'
+terminfo hp700 'Z0=\E[?3h:Z1=\E[?3l:hs:ts=\E[62"p\E[0$~\E[2$~\E[1$}:fs=\E[0}\E[61"p:ds=\E[62"p\E[1$~\E[61"p:ic@'
+
+#wyse-75-42 must have defflow control (xo = "terminal uses xon/xoff")
+#(nowadays: nx = padding doesn't work, have to use xon/off)
+#essential to have it here, as this is a slow terminal.
+termcap wy75-42 nx:xo:Z0=\E[?3h\E[31h:Z1=\E[?3l\E[31h
+terminfo wy75-42 nx:xo:Z0=\E[?3h\E[31h:Z1=\E[?3l\E[31h
+
+#remove some stupid / dangerous key bindings
+bind '^k'
+#bind 'L'
+bind '^\'
+#make them better
+bind '\\' quit
+bind 'K' kill
+bind 'I' login on
+bind 'O' login off
+bind '}' history
diff --git a/etc/mkinstalldirs b/etc/mkinstalldirs
new file mode 100755
index 0000000..0e29377
--- /dev/null
+++ b/etc/mkinstalldirs
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Make directory hierarchy.
+# Written by Noah Friedman <friedman@prep.ai.mit.edu>
+# Public domain.
+
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+errstatus=0
+
+for file in ${1+"$@"} ; do
+ oIFS="${IFS}"
+ # Some sh's can't handle IFS=/ for some reason.
+ IFS='%'
+ set - `echo ${file} | sed -e 's@/@%@g' -e 's@^%@/@'`
+ IFS="${oIFS}"
+
+ pathcomp=''
+
+ for d in ${1+"$@"} ; do
+ pathcomp="${pathcomp}${d}"
+
+ if test ! -d "${pathcomp}"; then
+ echo "mkdir $pathcomp" 1>&2
+ mkdir "${pathcomp}" || errstatus=$?
+ fi
+
+ pathcomp="${pathcomp}/"
+ done
+done
+
+exit $errstatus
+
+# eof
diff --git a/etc/newsyntax b/etc/newsyntax
new file mode 100755
index 0000000..6b5bb03
--- /dev/null
+++ b/etc/newsyntax
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# newsyntax -- update a screenrc file from 3.2 to 3.3 syntax
+#
+# please check all comments after running this script and watch out
+# for funny passages.
+#
+if [ $# != 1 ]; then
+ echo "usage $0 screenrcfile"
+ exit 1;
+fi
+
+#Ultrix 4.2 /bin/sh does not handle "read a < $1"
+#Dean Gaudet <dgaudet@watdragon.uwaterloo.ca>
+exec < $1
+read a
+
+if [ ."$a" = '.#3.3' ]; then
+ echo "$1 already updated"
+ exit 0
+fi
+
+cp $1 $1.old
+echo "#3.3" > $1
+echo "# Do not remove the above line. This screen rc file was updated" >> $1
+echo "# by the newsyntax script." >> $1
+sed < $1.old >> $1 \
+-e 's/\([ #]\)flow/\1defflow/g' \
+-e 's/^flow/defflow/g' \
+-e 's/\([ #]\)set[ ]*defflow/\1flow/g' \
+-e 's/^set[ ]*defflow/flow/g' \
+-e 's/\([ #]\)mode/\1defmode/g' \
+-e 's/^mode/defmode/g' \
+-e 's/\([ #]\)set[ ]*defmode/\1defmode/g' \
+-e 's/^set[ ]*defmode/defmode/g' \
+-e 's/\([ #]\)monitor/\1defmonitor/g' \
+-e 's/^monitor/defmonitor/g' \
+-e 's/\([ #]\)set[ ]*defmonitor/\1monitor/g' \
+-e 's/^set[ ]*defmonitor/monitor/g' \
+-e 's/\([ #]\)login/\1deflogin/g' \
+-e 's/^login/deflogin/g' \
+-e 's/\([ #]\)set[ ]*deflogin/\1login/g' \
+-e 's/^set[ ]*deflogin/login/g' \
+-e 's/\([ #]\)wrap/\1defwrap/g' \
+-e 's/^wrap/defwrap/g' \
+-e 's/\([ #]\)set[ ]*defwrap/\1wrap/g' \
+-e 's/^set[ ]*defwrap/wrap/g' \
+-e 's/\([ #]\)scrollback/\1defscrollback/g' \
+-e 's/^scrollback/defscrollback/g' \
+-e 's/\([ #]\)set[ ]*defscrollback/\1scrollback/g' \
+-e 's/^set[ ]*defscrollback/scrollback/g' \
+-e 's/\([ #]\)refresh/\1allPARtial/g' \
+-e 's/^refresh/allPARtial/g' \
+-e 's/\([ #]\)redraw/\1allPARtial/g' \
+-e 's/^redraw/allPARtial/g' \
+-e 's/\([ #]\)set[ ]*allPARtial/\1PARtial/g' \
+-e 's/^set[ ]*allPARtial/PARtial/g' \
+-e 's/\([ #]\)visualbell/\1vbell/g' \
+-e 's/^visualbell/vbell/g' \
+-e 's/PARtial\([ ]*\)on/partial\1off/g' \
+-e 's/PARtial\([ ]*\)off/partial\1on/g' \
+-e 's/allPARtial/refresh/g' \
+-e 's/^set[ ]//g'
+
diff --git a/etc/screenrc b/etc/screenrc
new file mode 100644
index 0000000..839ad8c
--- /dev/null
+++ b/etc/screenrc
@@ -0,0 +1,124 @@
+#
+# Example of a user's .screenrc file
+#
+
+# This is how one can set a reattach password:
+# password ODSJQf.4IJN7E # "1234"
+
+# no annoying audible bell, please
+vbell on
+
+# detach on hangup
+autodetach on
+
+# don't display the copyright page
+startup_message off
+
+# emulate .logout message
+pow_detach_msg "Screen session of \$LOGNAME \$:cr:\$:nl:ended."
+
+# advertise hardstatus support to $TERMCAP
+# termcapinfo * '' 'hs:ts=\E_:fs=\E\\:ds=\E_\E\\'
+
+# make the shell in every window a login shell
+#shell -$SHELL
+
+# autoaka testing
+# shellaka '> |tcsh'
+# shellaka '$ |sh'
+
+# set every new windows hardstatus line to somenthing descriptive
+# defhstatus "screen: ^E (^Et)"
+
+defscrollback 1000
+
+
+################
+#
+# xterm tweaks
+#
+
+#xterm understands both im/ic and doesn't have a status line.
+#Note: Do not specify im and ic in the real termcap/info file as
+#some programs (e.g. vi) will not work anymore.
+termcap xterm hs@:cs=\E[%i%d;%dr:im=\E[4h:ei=\E[4l
+terminfo xterm hs@:cs=\E[%i%p1%d;%p2%dr:im=\E[4h:ei=\E[4l
+
+#80/132 column switching must be enabled for ^AW to work
+#change init sequence to not switch width
+termcapinfo xterm Z0=\E[?3h:Z1=\E[?3l:is=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;4;6l
+
+# Make the output buffer large for (fast) xterms.
+termcapinfo xterm* OL=10000
+
+# tell screen that xterm can switch to dark background and has function
+# keys.
+termcapinfo xterm 'VR=\E[?5h:VN=\E[?5l'
+termcapinfo xterm 'k1=\E[11~:k2=\E[12~:k3=\E[13~:k4=\E[14~'
+termcapinfo xterm 'kh=\E[1~:kI=\E[2~:kD=\E[3~:kH=\E[4~:kP=\E[5~:kN=\E[6~'
+
+# special xterm hardstatus: use the window title.
+termcapinfo xterm 'hs:ts=\E]2;:fs=\007:ds=\E]0;screen\007'
+
+# our xterm has colors! (rxvt, too)
+termcap xterm 'AF=\E[3%dm:AB=\E[4%dm'
+terminfo xterm 'AF=\E[3%p1%dm:AB=\E[4%p1%dm'
+
+#terminfo xterm 'vb=\E[?5h$<200/>\E[?5l'
+termcapinfo xterm 'vi=\E[?25l:ve=\E[34h\E[?25h:vs=\E[34l'
+
+# emulate part of the 'K' charset
+termcapinfo xterm 'XC=K%,%\E(B,[\304,\\\\\326,]\334,{\344,|\366,}\374,~\337'
+
+################
+#
+# wyse terminals
+#
+
+#wyse-75-42 must have flow control (xo = "terminal uses xon/xoff")
+#essential to have it here, as this is a slow terminal.
+termcapinfo wy75-42 xo:hs@
+
+# New termcap sequences for cursor application mode.
+termcapinfo wy* CS=\E[?1h:CE=\E[?1l:vi=\E[?25l:ve=\E[?25h:VR=\E[?5h:VN=\E[?5l:cb=\E[1K:CD=\E[1J
+
+################
+#
+# other terminals
+#
+
+#make hp700 termcap/info better
+termcapinfo hp700 'Z0=\E[?3h:Z1=\E[?3l:hs:ts=\E[62"p\E[0$~\E[2$~\E[1$}:fs=\E[0}\E[61"p:ds=\E[62"p\E[1$~\E[61"p:ic@'
+
+# Extend the vt100 desciption by some sequences.
+termcap vt100* ms:AL=\E[%dL:DL=\E[%dM:UP=\E[%dA:DO=\E[%dB:LE=\E[%dD:RI=\E[%dC
+terminfo vt100* ms:AL=\E[%p1%dL:DL=\E[%p1%dM:UP=\E[%p1%dA:DO=\E[%p1%dB:LE=\E[%p1%dD:RI=\E[%p1%dC
+
+
+################
+#
+# keybindings
+#
+
+#remove some stupid / dangerous key bindings
+bind k
+bind ^k
+bind .
+bind ^\
+bind \\
+bind ^h
+bind h
+#make them better
+bind '\\' quit
+bind 'K' kill
+bind 'I' login on
+bind 'O' login off
+bind '}' history
+
+# Yet another hack:
+# Prepend/append register [/] to the paste if ^a^] is pressed.
+# This lets me have autoindent mode in vi.
+register [ "\033:se noai\015a"
+register ] "\033:se ai\015a"
+bind ^] paste [.]
+
diff --git a/etc/toolcheck b/etc/toolcheck
new file mode 100755
index 0000000..8fa214f
--- /dev/null
+++ b/etc/toolcheck
@@ -0,0 +1,44 @@
+#!/bin/sh
+# toolcheck -- check for tools that have severe bugs. Good that all the buggy
+# tools identify by version numbers. This is the spirit of GNU :-)
+#
+# 24.7.95 jw.
+
+retval=0
+reply="`sh -version 2>&1 < /dev/null`"
+case "$reply" in
+ GNU*1.14.3*)
+ echo "- sh is '$reply'";
+ echo " CAUTION: This shell has a buggy 'trap' command.";
+ echo " The configure script may fail silently.";
+ retval=1;
+ ;;
+ GNU*1.14.2*|GNU*1.14.4*|GNU*1.13.*)
+ echo "- sh is '$reply' - good.";
+ ;;
+ GNU*) echo "- sh is '$reply' - (buggy again shell?).";
+ ;;
+ *) ;;
+esac
+
+reply="`sed --version 2>&1 < /dev/null`"
+case "$reply" in
+ GNU\ sed\ version\ 2.0[34])
+ echo "- sed is '$reply'";
+ echo " CAUTION: This sed cannot configure screen properly."
+ retval=1;
+ ;;
+ GNU\ sed\ version\ 2.05|GNU\ sed\ version\ 2.03\ kevin)
+ echo "- sed is '$reply' - good.";
+ ;;
+ GNU*) echo "- sed is '$reply'.";
+ ;;
+ *) ;;
+esac
+
+if [ "$retval" != 0 ]; then
+ echo " ***********************************************************"
+ echo " Please fix the above problem before reporting a screen bug!"
+ echo " ***********************************************************"
+fi
+exit $retval
diff --git a/extern.h b/extern.h
new file mode 100644
index 0000000..f218c8a
--- /dev/null
+++ b/extern.h
@@ -0,0 +1,315 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ * $Id: extern.h,v 1.18 1994/05/31 12:31:57 mlschroe Exp $ FAU
+ */
+
+
+/* screen.c */
+extern void main __P((int, char **));
+extern sigret_t SigHup __P(SIGPROTOARG);
+extern void eexit __P((int));
+extern void Detach __P((int));
+extern void Kill __P((int, int));
+#ifdef USEVARARGS
+extern void Msg __P((int, char *, ...))
+# if __GNUC__ > 1
+__attribute__ ((format (printf, 2, 3)))
+# endif
+;
+extern void Panic __P((int, char *, ...))
+# if __GNUC__ > 1
+__attribute__ ((format (printf, 2, 3)))
+# endif
+;
+#else
+extern void Msg __P(());
+extern void Panic __P(());
+#endif
+extern void DisplaySleep __P((int));
+extern void Finit __P((int));
+extern void MakeNewEnv __P((void));
+extern char *MakeWinMsg __P((char *, struct win *, int));
+
+/* ansi.c */
+extern void Activate __P((int));
+extern void ResetWindow __P((struct win *));
+extern void ResetCharsets __P((struct win *));
+extern void WriteString __P((struct win *, char *, int));
+extern void NewAutoFlow __P((struct win *, int));
+extern void Redisplay __P((int));
+extern void SetCurr __P((struct win *));
+extern void ChangeAKA __P((struct win *, char *, int));
+extern void SetCharsets __P((struct win *, char *));
+
+/* fileio.c */
+extern void StartRc __P((char *));
+extern void FinishRc __P((char *));
+extern void RcLine __P((char *));
+extern FILE *secfopen __P((char *, char *));
+extern int secopen __P((char *, int, int));
+extern void WriteFile __P((int));
+extern char *ReadFile __P((char *, int *));
+extern void KillBuffers __P((void));
+extern char *expand_vars __P((char *));
+
+/* tty.c */
+extern int OpenTTY __P((char *));
+extern void InitTTY __P((struct mode *, int));
+extern void GetTTY __P((int, struct mode *));
+extern void SetTTY __P((int, struct mode *));
+extern void SetMode __P((struct mode *, struct mode *));
+extern void SetFlow __P((int));
+extern void SendBreak __P((struct win *, int, int));
+extern int TtyGrabConsole __P((int, int, char *));
+#ifdef DEBUG
+extern void DebugTTY __P((struct mode *));
+#endif /* DEBUG */
+extern int fgtty __P((int));
+extern void brktty __P((int));
+
+/* mark.c */
+extern int GetHistory __P((void));
+extern void MarkRoutine __P((void));
+extern void revto_line __P((int, int, int));
+extern void revto __P((int, int));
+extern int InMark __P((void));
+
+/* search.c */
+extern void Search __P((int));
+extern void ISearch __P((int));
+
+/* input.c */
+extern void inp_setprompt __P((char *, char *));
+extern void Input __P((char *, int, void (*)(), int));
+
+/* help.c */
+extern void exit_with_usage __P((char *));
+extern void display_help __P((void));
+extern void display_copyright __P((void));
+extern void display_displays __P((void));
+extern void display_bindkey __P((char *, struct action *));
+
+/* window.c */
+extern int MakeWindow __P((struct NewWindow *));
+extern int RemakeWindow __P((struct win *));
+extern void FreeWindow __P((struct win *));
+#ifdef PSEUDOS
+extern int winexec __P((char **));
+extern void FreePseudowin __P((struct win *));
+#endif
+#ifdef MULTI
+extern int execclone __P((char **));
+#endif
+extern void nwin_compose __P((struct NewWindow *, struct NewWindow *, struct NewWindow *));
+
+/* utmp.c */
+#ifdef UTMPOK
+extern void InitUtmp __P((void));
+extern void RemoveLoginSlot __P((void));
+extern void RestoreLoginSlot __P((void));
+extern int SetUtmp __P((struct win *));
+extern int RemoveUtmp __P((struct win *));
+#endif /* UTMPOK */
+extern void SlotToggle __P((int));
+#ifdef USRLIMIT
+extern int CountUsers __P((void));
+#endif
+
+/* loadav.c */
+#ifdef LOADAV
+extern void InitLoadav __P((void));
+extern void AddLoadav __P((char *));
+#endif
+
+/* pty.c */
+extern int OpenPTY __P((char **));
+
+/* process.c */
+extern void InitKeytab __P((void));
+extern void ProcessInput __P((char *, int));
+#ifdef MAPKEYS
+extern void ProcessInput2 __P((char *, int));
+#endif
+extern int FindCommnr __P((char *));
+extern void DoCommand __P((char **));
+extern void KillWindow __P((struct win *));
+extern int ReleaseAutoWritelock __P((struct display *, struct win *));
+extern void SetForeWindow __P((struct win *));
+extern int Parse __P((char *, char **));
+extern int ParseEscape __P((struct user *, char *));
+extern void DoScreen __P((char *, char **));
+extern int IsNumColon __P((char *, int, char *, int));
+extern void ShowWindows __P((void));
+extern int WindowByNoN __P((char *));
+#ifdef COPY_PASTE
+extern int CompileKeys __P((char *, char *));
+#endif
+
+/* termcap.c */
+extern int InitTermcap __P((int, int));
+extern char *MakeTermcap __P((int));
+extern char *gettermcapstring __P((char *));
+#ifdef MAPKEYS
+extern int remap __P((int, int));
+extern void CheckEscape __P((void));
+#endif
+extern int CreateTransTable __P((char *));
+extern void FreeTransTable __P((void));
+
+/* attacher.c */
+extern int Attach __P((int));
+extern void Attacher __P((void));
+extern sigret_t AttacherFinit __P(SIGPROTOARG);
+
+/* display.c */
+extern struct display *MakeDisplay __P((char *, char *, char *, int, int, struct mode *));
+extern void FreeDisplay __P((void));
+extern void DefProcess __P((char **, int *));
+extern void DefRedisplayLine __P((int, int, int, int));
+extern void DefClearLine __P((int, int, int));
+extern int DefRewrite __P((int, int, int, int));
+extern void DefSetCursor __P((void));
+extern int DefResize __P((int, int));
+extern void DefRestore __P((void));
+extern void PutStr __P((char *));
+extern void CPutStr __P((char *, int));
+extern void InitTerm __P((int));
+extern void FinitTerm __P((void));
+extern void INSERTCHAR __P((int));
+extern void PUTCHAR __P((int));
+extern void PUTCHARLP __P((int));
+extern void RAW_PUTCHAR __P((int));
+extern void ClearDisplay __P((void));
+extern void Clear __P((int, int, int, int, int, int, int));
+extern void RefreshLine __P((int, int, int, int));
+extern void RefreshStatus __P((void));
+extern void DisplayLine __P((struct mline *, struct mline *, int, int, int));
+
+extern void CDisplayLine __P((struct mline *, int, int, int, int, int));
+extern void FixLP __P((int, int));
+extern void GotoPos __P((int, int));
+extern int CalcCost __P((char *));
+extern void ScrollH __P((int, int, int, int, struct mline *));
+extern void ScrollV __P((int, int, int, int, int));
+extern void ChangeScrollRegion __P((int, int));
+extern void InsertMode __P((int));
+extern void KeypadMode __P((int));
+extern void CursorkeysMode __P((int));
+extern void ReverseVideo __P((int));
+extern void CursorVisibility __P((int));
+extern void SetFont __P((int));
+extern void SetAttr __P((int));
+extern void SetColor __P((int));
+extern void SetRendition __P((struct mchar *));
+extern void SetRenditionMline __P((struct mline *, int));
+extern void MakeStatus __P((char *));
+extern void RemoveStatus __P((void));
+extern void SetLastPos __P((int, int));
+extern int ResizeDisplay __P((int, int));
+extern int InitOverlayPage __P((int, struct LayFuncs *, int));
+extern void ExitOverlayPage __P((void));
+extern void AddStr __P((char *));
+extern void AddStrn __P((char *, int));
+extern void Flush __P((void));
+extern void freetty __P((void));
+extern void Resize_obuf __P((void));
+#ifdef AUTO_NUKE
+extern void NukePending __P((void));
+#endif
+#ifdef KANJI
+extern int badkanji __P((char *, int));
+#endif
+
+/* resize.c */
+extern int ChangeWindowSize __P((struct win *, int, int, int));
+extern void ChangeScreenSize __P((int, int, int));
+extern void CheckScreenSize __P((int));
+extern void DoResize __P((int, int));
+extern char *xrealloc __P((char *, int));
+
+/* socket.c */
+extern int FindSocket __P((int *, int *, char *));
+extern int MakeClientSocket __P((int));
+extern int MakeServerSocket __P((void));
+extern int RecoverSocket __P((void));
+extern int chsock __P((void));
+extern void ReceiveMsg __P(());
+extern void SendCreateMsg __P((char *, struct NewWindow *));
+#ifdef USEVARARGS
+extern void SendErrorMsg __P((char *, ...))
+# if __GNUC__ > 1
+__attribute__ ((format (printf, 1, 2)))
+# endif
+;
+#else
+extern void SendErrorMsg __P(());
+#endif
+
+/* misc.c */
+extern char *SaveStr __P((const char *));
+#ifndef HAVE_STRERROR
+extern char *strerror __P((int));
+#endif
+extern void centerline __P((char *));
+extern char *Filename __P((char *));
+extern char *stripdev __P((char *));
+#ifdef NEED_OWN_BCOPY
+extern void xbcopy __P((char *, char *, int));
+#endif
+extern void bclear __P((char *, int));
+extern void closeallfiles __P((int));
+extern int UserContext __P((void));
+extern void UserReturn __P((int));
+extern int UserStatus __P((void));
+#if defined(POSIX) || defined(hpux)
+extern void (*xsignal __P((int, void (*)SIGPROTOARG))) __P(SIGPROTOARG);
+#endif
+#ifdef NEED_RENAME
+extern int rename __P((char *, char *));
+#endif
+#if defined(HAVE_SETEUID) || defined(HAVE_SETREUID)
+extern void xseteuid __P((int));
+extern void xsetegid __P((int));
+#endif
+extern int AddXChar __P((char *, int));
+extern int AddXChars __P((char *, int, char *));
+
+/* acl.c */
+#ifdef MULTIUSER
+extern int AclInit __P((char *));
+extern int AclSetPass __P((char *, char *));
+extern int AclDelUser __P((char *));
+extern int UserFreeCopyBuffer __P((struct user *));
+extern int AclAddGroup __P((char *));
+extern int AclSetGroupPerm __P((char *, char *));
+extern int AclDelGroup __P((char *));
+extern int AclUserAddGroup __P((char *, char *));
+extern int AclUserDelGroup __P((char *, char *));
+extern int AclCheckPermWin __P((struct user *, int, struct win *));
+extern int AclCheckPermCmd __P((struct user *, int, struct comm *));
+extern int AclSetPerm __P((struct user *, char *, char *));
+extern void AclWinSwap __P((int, int));
+extern int NewWindowAcl __P((struct win *));
+#endif /* MULTIUSER */
+extern struct user **FindUserPtr __P((char *));
+extern int UserAdd __P((char *, char *, struct user **));
+extern int UserDel __P((char *, struct user **));
diff --git a/fileio.c b/fileio.c
new file mode 100644
index 0000000..81d2e81
--- /dev/null
+++ b/fileio.c
@@ -0,0 +1,760 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: fileio.c,v 1.10 1994/05/31 12:32:01 mlschroe Exp $ FAU")
+
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#ifndef SIGINT
+# include <signal.h>
+#endif
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+
+#ifdef NETHACK
+extern nethackflag;
+#endif
+
+extern struct display *display;
+extern struct win *fore;
+extern int real_uid, eff_uid;
+extern int real_gid, eff_gid;
+extern char *extra_incap, *extra_outcap;
+extern char *home, *RcFileName;
+extern char SockPath[], *SockName;
+#ifdef COPY_PASTE
+extern char *BufferFile;
+#endif
+extern int hardcopy_append;
+extern char *hardcopydir;
+
+static char *CatExtra __P((char *, char *));
+
+
+static FILE *fp = NULL;
+char *rc_name;
+
+static char *
+CatExtra(str1, str2)
+register char *str1, *str2;
+{
+ register char *cp;
+ register int len1, len2, add_colon;
+
+ len1 = strlen(str1);
+ if (len1 == 0)
+ return str2;
+ add_colon = (str1[len1 - 1] != ':');
+ if (str2)
+ {
+ len2 = strlen(str2);
+ if ((cp = realloc(str2, (unsigned) len1 + len2 + add_colon + 1)) == NULL)
+ Panic(0, strnomem);
+ bcopy(cp, cp + len1 + add_colon, len2 + 1);
+ }
+ else
+ {
+ if (len1 == 0)
+ return 0;
+ if ((cp = malloc((unsigned) len1 + add_colon + 1)) == NULL)
+ Panic(0, strnomem);
+ cp[len1 + add_colon] = '\0';
+ }
+ bcopy(str1, cp, len1);
+ if (add_colon)
+ cp[len1] = ':';
+
+ return cp;
+}
+
+static char *
+findrcfile(rcfile)
+char *rcfile;
+{
+ static char buf[256];
+ char *rc, *p;
+
+ if (rcfile)
+ {
+ rc = SaveStr(rcfile);
+ debug1("findrcfile: you specified '%s'\n", rcfile);
+ }
+ else
+ {
+ debug("findrcfile: you specified nothing...\n");
+ if ((p = getenv("ISCREENRC")) != NULL && *p != '\0')
+ {
+ debug1(" ... but $ISCREENRC has: '%s'\n", p);
+ rc = SaveStr(p);
+ }
+ else if ((p = getenv("SCREENRC")) != NULL && *p != '\0')
+ {
+ debug1(" ... but $SCREENRC has: '%s'\n", p);
+ rc = SaveStr(p);
+ }
+ else
+ {
+ debug(" ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n");
+ if (strlen(home) > 244)
+ Panic(0, "Rc: home too large");
+ sprintf(buf, "%s/.iscreenrc", home);
+ if (access(buf, R_OK))
+ sprintf(buf, "%s/.screenrc", home);
+ rc = SaveStr(buf);
+ }
+ }
+ return rc;
+}
+
+/*
+ * this will be called twice:
+ * 1) rcfilename = "/etc/screenrc"
+ * 2) rcfilename = RcFileName
+ */
+void
+StartRc(rcfilename)
+char *rcfilename;
+{
+ register int argc, len;
+ register char *p, *cp;
+ char buf[256];
+ char *args[MAXARGS];
+
+
+ /* Special settings for vt100 and others */
+
+ if (display && (!strncmp(D_termname, "vt", 2) || !strncmp(D_termname, "xterm", 5)))
+ extra_incap = CatExtra("xn:f0=\033Op:f1=\033Oq:f2=\033Or:f3=\033Os:f4=\033Ot:f5=\033Ou:f6=\033Ov:f7=\033Ow:f8=\033Ox:f9=\033Oy:f.=\033On:f,=\033Ol:fe=\033OM:f+=\033Ok:f-=\033Om:f*=\033Oj:f/=\033Oo:fq=\033OX", extra_incap);
+
+ rc_name = findrcfile(rcfilename);
+
+ if ((fp = secfopen(rc_name, "r")) == NULL)
+ {
+ if (RcFileName && strcmp(RcFileName, rc_name) == 0)
+ {
+ /*
+ * User explicitly gave us that name,
+ * this is the only case, where we get angry, if we can't read
+ * the file.
+ */
+ debug3("StartRc: '%s','%s', '%s'\n", RcFileName, rc_name, rcfilename);
+ Panic(0, "Unable to open \"%s\".", rc_name);
+ /* NOTREACHED */
+ }
+ debug1("StartRc: '%s' no good. ignored\n", rc_name);
+ Free(rc_name);
+ rc_name = "";
+ return;
+ }
+ while (fgets(buf, sizeof buf, fp) != NULL)
+ {
+ if ((p = rindex(buf, '\n')) != NULL)
+ *p = '\0';
+ if ((argc = Parse(expand_vars(buf), args)) == 0)
+ continue;
+ if (strcmp(args[0], "echo") == 0)
+ {
+ if (!display)
+ continue;
+ if (argc < 2 || (argc == 3 && strcmp(args[1], "-n")) || argc > 3)
+ {
+ Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name);
+ continue;
+ }
+ AddStr(args[argc - 1]);
+ if (argc != 3)
+ {
+ AddStr("\r\n");
+ Flush();
+ }
+ }
+ else if (strcmp(args[0], "sleep") == 0)
+ {
+ if (!display)
+ continue;
+ debug("sleeeeeeep\n");
+ if (argc != 2)
+ {
+ Msg(0, "%s: sleep: one numeric argument expected.", rc_name);
+ continue;
+ }
+ DisplaySleep(atoi(args[1]));
+ }
+#ifdef TERMINFO
+ else if (!strcmp(args[0], "termcapinfo") || !strcmp(args[0], "terminfo"))
+#else
+ else if (!strcmp(args[0], "termcapinfo") || !strcmp(args[0], "termcap"))
+#endif
+ {
+ if (!display)
+ continue;
+ if (argc < 3 || argc > 4)
+ {
+ Msg(0, "%s: %s: incorrect number of arguments.", rc_name, args[0]);
+ continue;
+ }
+ for (p = args[1]; p && *p; p = cp)
+ {
+ if ((cp = index(p, '|')) != 0)
+ *cp++ = '\0';
+ len = strlen(p);
+ if (p[len - 1] == '*')
+ {
+ if (!(len - 1) || !strncmp(p, D_termname, len - 1))
+ break;
+ }
+ else if (!strcmp(p, D_termname))
+ break;
+ }
+ if (!(p && *p))
+ continue;
+ extra_incap = CatExtra(args[2], extra_incap);
+ if (argc == 4)
+ extra_outcap = CatExtra(args[3], extra_outcap);
+ }
+ }
+ fclose(fp);
+ Free(rc_name);
+ rc_name = "";
+}
+
+void
+FinishRc(rcfilename)
+char *rcfilename;
+{
+ char buf[256];
+
+ rc_name = findrcfile(rcfilename);
+
+ if ((fp = secfopen(rc_name, "r")) == NULL)
+ {
+ if (RcFileName && strcmp(RcFileName, rc_name) == 0)
+ {
+ /*
+ * User explicitly gave us that name,
+ * this is the only case, where we get angry, if we can't read
+ * the file.
+ */
+ debug3("FinishRc:'%s','%s','%s'\n", RcFileName, rc_name, rcfilename);
+ Panic(0, "Unable to open \"%s\".", rc_name);
+ /* NOTREACHED */
+ }
+ debug1("FinishRc: '%s' no good. ignored\n", rc_name);
+ Free(rc_name);
+ rc_name = "";
+ return;
+ }
+
+ debug("finishrc is going...\n");
+ while (fgets(buf, sizeof buf, fp) != NULL)
+ RcLine(buf);
+ (void) fclose(fp);
+ Free(rc_name);
+ rc_name = "";
+}
+
+/*
+ * "$HOST blafoo" -> "localhost blafoo"
+ * "${HOST}blafoo" -> "localhostblafoo"
+ * "\$HOST blafoo" -> "$HOST blafoo"
+ * "\\$HOST blafoo" -> "\localhost blafoo"
+ * "'$HOST ${HOST}'" -> "'$HOST ${HOST}'"
+ * "'\$HOST'" -> "'\$HOST'"
+ * "\'$HOST' $HOST" -> "'localhost' $HOST"
+ *
+ * "$:termcapname:" -> "termcapvalue"
+ * "$:terminfoname:" -> "termcapvalue"
+ *
+ * "\101" -> "A"
+ * "^a" -> "\001"
+ */
+char *
+expand_vars(ss)
+char *ss;
+{
+ static char ebuf[2048];
+ register int esize = 2047, vtype, quofl = 0;
+ register char *e = ebuf;
+ register char *s = ss;
+ register char *v;
+ char xbuf[11];
+ int i;
+
+ while (*s && *s != '\0' && *s != '\n' && esize > 0)
+ {
+ if (*s == '\'')
+ quofl ^= 1;
+ if (*s == '$' && !quofl)
+ {
+ char *p, c;
+
+ p = ++s;
+ switch (*s)
+ {
+ case '{':
+ p = ++s;
+ while (*p != '}')
+ if (*p++ == '\0')
+ return ss;
+ vtype = 0; /* env var */
+ break;
+ case ':':
+ p = ++s;
+ while (*p != ':')
+ if (*p++ == '\0')
+ return ss;
+ vtype = 1; /* termcap string */
+ break;
+ default:
+ while (*p != ' ' && *p != '\0' && *p != '\n')
+ p++;
+ vtype = 0; /* env var */
+ }
+ c = *p;
+ debug1("exp: c='%c'\n", c);
+ *p = '\0';
+ if (vtype == 0)
+ {
+ v = xbuf;
+ if (strcmp(s, "TERM") == 0)
+ v = display ? D_termname : "unknown";
+ else if (strcmp(s, "COLUMNS") == 0)
+ sprintf(xbuf, "%d", display ? D_width : -1);
+ else if (strcmp(s, "LINES") == 0)
+ sprintf(xbuf, "%d", display ? D_height : -1);
+ else
+ v = getenv(s);
+ }
+ else
+ v = gettermcapstring(s);
+ if (v)
+ {
+ debug2("exp: $'%s'='%s'\n", s, v);
+ while (*v && esize-- > 0)
+ *e++ = *v++;
+ }
+ else
+ debug1("exp: '%s' not env\n", s); /* '{'-: */
+ if ((*p = c) == '}' || c == ':')
+ p++;
+ s = p;
+ }
+ else if (*s == '^' && !quofl)
+ {
+ s++;
+ i = *s++;
+ if (i == '?')
+ i = '\177';
+ else
+ i &= 0x1f;
+ *e++ = i;
+ esize--;
+ }
+ else
+ {
+ /*
+ * \$, \\$, \\, \\\, \012 are reduced here,
+ * other sequences starting whith \ are passed through.
+ */
+ if (s[0] == '\\' && !quofl)
+ {
+ if (s[1] >= '0' && s[1] <= '7')
+ {
+ s++;
+ i = *s - '0';
+ s++;
+ if (*s >= '0' && *s <= '7')
+ {
+ i = i * 8 + *s - '0';
+ s++;
+ if (*s >= '0' && *s <= '7')
+ {
+ i = i * 8 + *s - '0';
+ s++;
+ }
+ }
+ debug2("expandvars: octal coded character %o (%d)\n", i, i);
+ *e++ = i;
+ esize--;
+ continue;
+ }
+ else
+ {
+ if (s[1] == '$' ||
+ (s[1] == '\\' && s[2] == '$') ||
+ s[1] == '\'' ||
+ (s[1] == '\\' && s[2] == '\'') ||
+ s[1] == '^' ||
+ (s[1] == '\\' && s[2] == '^'))
+ s++;
+ }
+ }
+ *e++ = *s++;
+ esize--;
+ }
+ }
+ if (esize <= 0)
+ Msg(0, "expand_vars: buffer overflow\n");
+ *e = '\0';
+ debug1("expand_var returns '%s'\n", ebuf);
+ return ebuf;
+}
+
+void
+RcLine(ubuf)
+char *ubuf;
+{
+ char *args[MAXARGS], *buf;
+
+ buf = expand_vars(ubuf);
+ if (Parse(buf, args) <= 0)
+ return;
+ DoCommand(args);
+}
+
+void
+WriteFile(dump)
+int dump;
+{
+ /* dump==0: create .termcap,
+ * dump==1: hardcopy,
+ * #ifdef COPY_PASTE
+ * dump==2: BUFFERFILE
+ * #endif COPY_PASTE
+ */
+ register int i, j, k;
+ register char *p;
+ register FILE *f;
+ char fn[1024];
+ char *mode = "w";
+
+ switch (dump)
+ {
+ case DUMP_TERMCAP:
+ i = SockName - SockPath;
+ strncpy(fn, SockPath, i);
+ strcpy(fn + i, ".termcap");
+ break;
+ case DUMP_HARDCOPY:
+ if (hardcopydir)
+ sprintf(fn, "%s/hardcopy.%d", hardcopydir, fore->w_number);
+ else
+ sprintf(fn, "hardcopy.%d", fore->w_number);
+ if (hardcopy_append && !access(fn, W_OK))
+ mode = "a";
+ break;
+#ifdef COPY_PASTE
+ case DUMP_EXCHANGE:
+ sprintf(fn, "%s", BufferFile);
+ umask(0);
+ break;
+#endif
+ }
+
+ debug2("WriteFile(%d) %s\n", dump, fn);
+ if (UserContext() > 0)
+ {
+ debug("Writefile: usercontext\n");
+ if ((f = fopen(fn, mode)) == NULL)
+ {
+ debug2("WriteFile: fopen(%s,\"%s\") failed\n", fn, mode);
+ UserReturn(0);
+ }
+ else
+ {
+ switch (dump)
+ {
+ case DUMP_HARDCOPY:
+ if (*mode == 'a')
+ {
+ putc('>', f);
+ for (j = D_width - 2; j > 0; j--)
+ putc('=', f);
+ fputs("<\n", f);
+ }
+ for (i = 0; i < D_height; i++)
+ {
+ p = fore->w_mlines[i].image;
+ for (k = D_width - 1; k >= 0 && p[k] == ' '; k--)
+ ;
+ for (j = 0; j <= k; j++)
+ putc(p[j], f);
+ putc('\n', f);
+ }
+ break;
+ case DUMP_TERMCAP:
+ if ((p = index(MakeTermcap(fore->w_aflag), '=')) != NULL)
+ {
+ fputs(++p, f);
+ putc('\n', f);
+ }
+ break;
+#ifdef COPY_PASTE
+ case DUMP_EXCHANGE:
+ p = D_user->u_copybuffer;
+ for (i = D_user->u_copylen; i-- > 0; p++)
+ if (*p == '\r' && (i == 0 || p[1] != '\n'))
+ putc('\n', f);
+ else
+ putc(*p, f);
+ break;
+#endif
+ }
+ (void) fclose(f);
+ UserReturn(1);
+ }
+ }
+ if (UserStatus() <= 0)
+ Msg(0, "Cannot open \"%s\"", fn);
+ else
+ {
+ switch (dump)
+ {
+ case DUMP_TERMCAP:
+ Msg(0, "Termcap entry written to \"%s\".", fn);
+ break;
+ case DUMP_HARDCOPY:
+ Msg(0, "Screen image %s to \"%s\".",
+ (*mode == 'a') ? "appended" : "written", fn);
+ break;
+#ifdef COPY_PASTE
+ case DUMP_EXCHANGE:
+ Msg(0, "Copybuffer written to \"%s\".", fn);
+#endif
+ }
+ }
+}
+
+#ifdef COPY_PASTE
+
+/*
+ * returns an allocated buffer which holds a copy of the file named fn.
+ * lenp (if nonzero) points to a location, where the buffer size should be
+ * stored.
+ */
+char *
+ReadFile(fn, lenp)
+char *fn;
+int *lenp;
+{
+ int i, l, size;
+ char c, *bp, *buf;
+ struct stat stb;
+
+ ASSERT(lenp);
+ debug1("ReadFile(%s)\n", fn);
+ if ((i = secopen(fn, O_RDONLY, 0)) < 0)
+ {
+ Msg(errno, "no %s -- no slurp", fn);
+ return NULL;
+ }
+ if (fstat(i, &stb))
+ {
+ Msg(errno, "no good %s -- no slurp", fn);
+ close(i);
+ return NULL;
+ }
+ size = stb.st_size;
+ if ((buf = malloc(size)) == NULL)
+ {
+ close(i);
+ Msg(0, strnomem);
+ return NULL;
+ }
+ errno = 0;
+ if ((l = read(i, buf, size)) != size)
+ {
+ if (l < 0)
+ l = 0;
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(errno, "You choke on your food: %d bytes from %s", l, fn);
+ else
+#endif
+ Msg(errno, "Got only %d bytes from %s", l, fn);
+ close(i);
+ }
+ else
+ {
+ if (read(i, &c, 1) > 0)
+ Msg(0, "Slurped only %d characters (of %d) into buffer - try again",
+ l, size);
+ else
+ Msg(0, "Slurped %d characters into buffer", l);
+ }
+ close(i);
+ *lenp = l;
+ for (bp = buf; l-- > 0; bp++)
+ if (*bp == '\n' && (bp == buf || bp[-1] != '\r'))
+ *bp = '\r';
+ return buf;
+}
+
+void
+KillBuffers()
+{
+ if (UserContext() > 0)
+ UserReturn(unlink(BufferFile) ? errno : 0);
+ errno = UserStatus();
+ Msg(errno, "%s %sremoved", BufferFile, errno ? "not " : "");
+}
+#endif /* COPY_PASTE */
+
+
+/*
+ * (Almost) secure open and fopen...
+ */
+
+FILE *
+secfopen(name, mode)
+char *name;
+char *mode;
+{
+ FILE *fi;
+#ifndef USE_SETEUID
+ int flags, fd;
+#endif
+
+ debug2("secfopen(%s, %s)\n", name, mode);
+#ifdef USE_SETEUID
+ xseteuid(real_uid);
+ xsetegid(real_gid);
+ fi = fopen(name, mode);
+ xseteuid(eff_uid);
+ xsetegid(eff_gid);
+ return fi;
+#else
+ if (eff_uid == real_uid)
+ return fopen(name, mode);
+ if (mode[0] && mode[1] == '+')
+ flags = O_RDWR;
+ else
+ flags = (mode[0] == 'r') ? O_RDONLY : O_WRONLY;
+ if (mode[0] == 'w')
+ flags |= O_CREAT | O_TRUNC;
+ else if (mode[0] == 'a')
+ flags |= O_CREAT | O_APPEND;
+ else if (mode[0] != 'r')
+ {
+ errno = EINVAL;
+ return 0;
+ }
+ if ((fd = secopen(name, flags, 0666)) < 0)
+ return 0;
+ if ((fi = fdopen(fd, mode)) == 0)
+ {
+ close(fd);
+ return 0;
+ }
+ return fi;
+#endif
+}
+
+
+int
+secopen(name, flags, mode)
+char *name;
+int flags;
+int mode;
+{
+ int fd;
+#ifndef USE_SETEUID
+ int q;
+ struct stat stb;
+#endif
+
+ debug3("secopen(%s, 0x%x, 0%03o)\n", name, flags, mode);
+#ifdef USE_SETEUID
+ xseteuid(real_uid);
+ xsetegid(real_gid);
+ fd = open(name, flags, mode);
+ xseteuid(eff_uid);
+ xsetegid(eff_gid);
+ return fd;
+#else
+ if (eff_uid == real_uid)
+ return open(name, flags, mode);
+ /* Truncation/creation is done in UserContext */
+ if ((flags & O_TRUNC) || ((flags & O_CREAT) && access(name, F_OK)))
+ {
+ if (UserContext() > 0)
+ {
+ if ((fd = open(name, flags, mode)) >= 0)
+ {
+ close(fd);
+ UserReturn(0);
+ }
+ if (errno == 0)
+ errno = EACCES;
+ UserReturn(errno);
+ }
+ if ((q = UserStatus()))
+ {
+ if (q > 0)
+ errno = q;
+ return -1;
+ }
+ }
+ if (access(name, F_OK))
+ return -1;
+ if ((fd = open(name, flags & ~(O_TRUNC | O_CREAT), 0)) < 0)
+ return -1;
+ debug("open successful\n");
+ if (fstat(fd, &stb))
+ {
+ close(fd);
+ return -1;
+ }
+ debug("fstat successful\n");
+ if (stb.st_uid != real_uid)
+ {
+ switch (flags & (O_RDONLY | O_WRONLY | O_RDWR))
+ {
+ case O_RDONLY:
+ q = 0004;
+ break;
+ case O_WRONLY:
+ q = 0002;
+ break;
+ default:
+ q = 0006;
+ break;
+ }
+ if ((stb.st_mode & q) != q)
+ {
+ debug1("secopen: permission denied (%03o)\n", stb.st_mode & 07777);
+ close(fd);
+ errno = EACCES;
+ return -1;
+ }
+ }
+ debug1("secopen ok - returning %d\n", fd);
+ return fd;
+#endif
+}
diff --git a/help.c b/help.c
new file mode 100644
index 0000000..5fa31a3
--- /dev/null
+++ b/help.c
@@ -0,0 +1,857 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: help.c,v 1.7 1994/05/31 12:32:04 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+
+#include "config.h"
+
+#include "screen.h"
+#include "extern.h"
+
+char version[40]; /* initialised by main() */
+
+extern struct display *display;
+extern char *noargs[];
+extern struct mchar mchar_null;
+
+
+void
+exit_with_usage(myname)
+char *myname;
+{
+ printf("Use: %s [-opts] [cmd [args]]\n", myname);
+ printf(" or: %s -r [host.tty]\n\nOptions:\n", myname);
+ printf("-a Force all capabilities into each window's termcap.\n");
+ printf("-A -[r|R] Adapt all windows to the new display width & height.\n");
+ printf("-c file Read configuration file instead of '.screenrc'.\n");
+#ifdef REMOTE_DETACH
+ printf("-d (-r) Detach the elsewhere running screen (and reattach here).\n");
+ printf("-D (-r) Detach and logout remote (and reattach here).\n");
+#endif
+ printf("-e xy Change command characters.\n");
+ printf("-f Flow control on, -fn = off, -fa = auto.\n");
+ printf("-h lines Set the size of the scrollback history buffer.\n");
+ printf("-i Interrupt output sooner when flow control is on.\n");
+#if defined(LOGOUTOK) && defined(UTMPOK)
+ printf("-l Login mode on (update %s), -ln = off.\n", UTMPFILE);
+#endif
+ printf("-list or -ls. Do nothing, just list our SockDir.\n");
+ printf("-L Terminal's last character can be safely updated.\n");
+ printf("-m ignore $STY variable, do create a new screen session.\n");
+ printf("-O Choose optimal output rather than exact vt100 emulation.\n");
+ printf("-q Quiet startup. Exits with non-zero return code if unsuccessful.\n");
+ printf("-r Reattach to a detached screen process.\n");
+ printf("-R Reattach if possible, otherwise start a new session.\n");
+ printf("-s shell Shell to execute rather than $SHELL.\n");
+ printf("-S sockname Name this session <pid>.sockname instead of <pid>.<tty>.<host>.\n");
+ printf("-t title Set title. (window's name).\n");
+ printf("-T term Use term as $TERM for windows, rather than \"screen\".\n");
+ printf("-v Print \"Screen version %s\".\n", version);
+ printf("-wipe Do nothing, just clean up SockDir.\n");
+#ifdef MULTI
+ printf("-x Attach to a not detached screen. (Multi display mode).\n");
+#endif /* MULTI */
+ exit(1);
+}
+
+
+/*
+** Here come the help page routines
+*/
+
+extern struct comm comms[];
+extern struct action ktab[];
+
+static void HelpProcess __P((char **, int *));
+static void HelpAbort __P((void));
+static void HelpRedisplayLine __P((int, int, int, int));
+static void HelpSetCursor __P((void));
+static void add_key_to_buf __P((char *, int));
+static int AddAction __P((struct action *, int));
+static int helppage __P((void));
+
+struct helpdata
+{
+ int maxrow, grow, numcols, numrows, num_names;
+ int numskip, numpages;
+ int command_search, command_bindings;
+ int refgrow, refcommand_search;
+ int inter, mcom, mkey;
+ int nact[RC_LAST + 1];
+};
+
+#define MAXKLEN 256
+
+static struct LayFuncs HelpLf =
+{
+ HelpProcess,
+ HelpAbort,
+ HelpRedisplayLine,
+ DefClearLine,
+ DefRewrite,
+ HelpSetCursor,
+ DefResize,
+ DefRestore
+};
+
+
+void
+display_help()
+{
+ int i, n, key, mcom, mkey, l;
+ struct helpdata *helpdata;
+ int used[RC_LAST + 1];
+
+ if (D_height < 6)
+ {
+ Msg(0, "Window height too small for help page");
+ return;
+ }
+ if (InitOverlayPage(sizeof(*helpdata), &HelpLf, 0))
+ return;
+
+ helpdata = (struct helpdata *)D_lay->l_data;
+ helpdata->num_names = helpdata->command_bindings = 0;
+ helpdata->command_search = 0;
+ for (n = 0; n <= RC_LAST; n++)
+ used[n] = 0;
+ mcom = 0;
+ mkey = 0;
+ for (key = 0; key < 256; key++)
+ {
+ n = ktab[key].nr;
+ if (n == RC_ILLEGAL)
+ continue;
+ if (ktab[key].args == noargs)
+ {
+ used[n] += (key <= ' ' || key == 0x7f) ? 3 :
+ (key > 0x7f) ? 5 : 2;
+ }
+ else
+ helpdata->command_bindings++;
+ }
+ for (n = i = 0; n <= RC_LAST; n++)
+ if (used[n])
+ {
+ l = strlen(comms[n].name);
+ if (l > mcom)
+ mcom = l;
+ if (used[n] > mkey)
+ mkey = used[n];
+ helpdata->nact[i++] = n;
+ }
+ debug1("help: %d commands bound to keys with no arguments\n", i);
+ debug2("mcom: %d mkey: %d\n", mcom, mkey);
+ helpdata->num_names = i;
+
+ if (mkey > MAXKLEN)
+ mkey = MAXKLEN;
+ helpdata->numcols = (D_width - !D_CLP)/(mcom + mkey + 1);
+ if (helpdata->numcols == 0)
+ {
+ HelpAbort();
+ Msg(0, "Width too small");
+ return;
+ }
+ helpdata->inter = (D_width - !D_CLP - (mcom + mkey) * helpdata->numcols) / (helpdata->numcols + 1);
+ if (helpdata->inter <= 0)
+ helpdata->inter = 1;
+ debug1("inter: %d\n", helpdata->inter);
+ helpdata->mcom = mcom;
+ helpdata->mkey = mkey;
+ helpdata->numrows = (helpdata->num_names + helpdata->numcols - 1) / helpdata->numcols;
+ debug1("Numrows: %d\n", helpdata->numrows);
+ helpdata->numskip = D_height-5 - (2 + helpdata->numrows);
+ while (helpdata->numskip < 0)
+ helpdata->numskip += D_height-5;
+ helpdata->numskip %= D_height-5;
+ debug1("Numskip: %d\n", helpdata->numskip);
+ if (helpdata->numskip > D_height/3 || helpdata->numskip > helpdata->command_bindings)
+ helpdata->numskip = 1;
+ helpdata->maxrow = 2 + helpdata->numrows + helpdata->numskip + helpdata->command_bindings;
+ helpdata->grow = 0;
+
+ helpdata->numpages = (helpdata->maxrow + D_height-6) / (D_height-5);
+ helppage();
+}
+
+static void
+HelpSetCursor()
+{
+ GotoPos(0, D_height - 1);
+}
+
+static void
+HelpProcess(ppbuf, plen)
+char **ppbuf;
+int *plen;
+{
+ int done = 0;
+
+ GotoPos(0, D_height-1);
+ while (!done && *plen > 0)
+ {
+ switch (**ppbuf)
+ {
+ case ' ':
+ if (helppage() == 0)
+ break;
+ /* FALLTHROUGH */
+ case '\r':
+ case '\n':
+ done = 1;
+ break;
+ default:
+ break;
+ }
+ ++*ppbuf;
+ --*plen;
+ }
+ if (done)
+ HelpAbort();
+}
+
+static void
+HelpAbort()
+{
+ LAY_CALL_UP(Activate(0));
+ ExitOverlayPage();
+}
+
+
+static int
+helppage()
+{
+ struct helpdata *helpdata;
+ int col, crow, n, key;
+ char buf[MAXKLEN], Esc_buf[5], cbuf[256];
+
+ helpdata = (struct helpdata *)D_lay->l_data;
+
+ if (helpdata->grow >= helpdata->maxrow)
+ return -1;
+ helpdata->refgrow = helpdata->grow;
+ helpdata->refcommand_search = helpdata->command_search;
+
+ /* Clear the help screen */
+ SetRendition(&mchar_null);
+ ClearDisplay();
+
+ sprintf(cbuf,"Screen key bindings, page %d of %d.", helpdata->grow / (D_height-5) + 1, helpdata->numpages);
+ centerline(cbuf);
+ AddChar('\n');
+ crow = 2;
+
+ *Esc_buf = '\0';
+ add_key_to_buf(Esc_buf, D_user->u_Esc);
+
+ for (; crow < D_height - 3; crow++)
+ {
+ if (helpdata->grow < 1)
+ {
+ *buf = '\0';
+ add_key_to_buf(buf, D_user->u_MetaEsc);
+ sprintf(cbuf,"Command key: %s Literal %s: %s", Esc_buf, Esc_buf, buf);
+ centerline(cbuf);
+ helpdata->grow++;
+ }
+ else if (helpdata->grow >= 2 && helpdata->grow-2 < helpdata->numrows)
+ {
+ for (col = 0; col < helpdata->numcols && (n = helpdata->numrows * col + (helpdata->grow-2)) < helpdata->num_names; col++)
+ {
+ AddStrn("", helpdata->inter - !col);
+ n = helpdata->nact[n];
+ debug1("help: searching key %d\n", n);
+ buf[0] = '\0';
+ for (key = 0; key < 256; key++)
+ if (ktab[key].nr == n && ktab[key].args == noargs)
+ {
+ strcat(buf, " ");
+ add_key_to_buf(buf, key);
+ }
+ AddStrn(comms[n].name, helpdata->mcom);
+ AddStrn(buf, helpdata->mkey);
+ }
+ AddStr("\r\n");
+ helpdata->grow++;
+ }
+ else if (helpdata->grow-2-helpdata->numrows >= helpdata->numskip
+ && helpdata->grow-2-helpdata->numrows-helpdata->numskip < helpdata->command_bindings)
+ {
+ while ((n = ktab[helpdata->command_search].nr) == RC_ILLEGAL
+ || ktab[helpdata->command_search].args == noargs)
+ {
+ if (++helpdata->command_search >= 256)
+ return -1;
+ }
+ buf[0] = '\0';
+ add_key_to_buf(buf, helpdata->command_search);
+ AddStrn(buf, 4);
+ AddAction(&ktab[helpdata->command_search++], D_width - 5);
+ AddStr("\r\n");
+ helpdata->grow++;
+ }
+ else
+ {
+ AddChar('\n');
+ helpdata->grow++;
+ }
+ }
+ AddChar('\n');
+ sprintf(cbuf,"[Press Space %s Return to end.]",
+ helpdata->grow < helpdata->maxrow ? "for next page;" : "or");
+ centerline(cbuf);
+ SetLastPos(0, D_height-1);
+ return 0;
+}
+
+static int
+AddAction(act, fr)
+struct action *act;
+int fr;
+{
+ char buf[256];
+ int del, l;
+ char *bp, *cp, **pp;
+
+ if (fr <= 0)
+ return 0;
+ l = strlen(comms[act->nr].name);
+
+ if (l + 1 > fr)
+ l = fr - 1;
+ AddStrn(comms[act->nr].name, l);
+ fr -= l + 1;
+ AddChar(fr ? ' ' : '$');
+
+ pp = act->args;
+ while (pp && (cp = *pp) != NULL)
+ {
+ del = 0;
+ bp = buf;
+ if (!*cp || (index(cp, ' ') != NULL))
+ {
+ if (index(cp, '\'') != NULL)
+ *bp++ = del = '"';
+ else
+ *bp++ = del = '\'';
+ }
+ while (*cp && bp < buf + 250)
+ bp += AddXChar(bp, *cp++);
+ if (del)
+ *bp++ = del;
+ *bp = 0;
+ if ((fr -= (bp - buf) + 1) < 0)
+ {
+ fr += bp - buf;
+ if (fr > 0)
+ AddStrn(buf, fr);
+ if (fr == 0)
+ AddChar('$');
+ return 0;
+ }
+ AddStr(buf);
+ pp++;
+ if (*pp)
+ AddChar(fr ? ' ' : '$');
+ }
+ return fr;
+}
+
+static void
+add_key_to_buf(buf, key)
+char *buf;
+int key;
+{
+ debug1("help: key found: %c\n", key);
+ buf += strlen(buf);
+ if (key < 0)
+ sprintf(buf, "unset");
+ else if (key == ' ')
+ sprintf(buf, "sp");
+ else buf[AddXChar(buf, key)] = 0;
+}
+
+
+static void
+HelpRedisplayLine(y, xs, xe, isblank)
+int y, xs, xe, isblank;
+{
+ if (y < 0)
+ {
+ struct helpdata *helpdata;
+
+ helpdata = (struct helpdata *)D_lay->l_data;
+ helpdata->grow = helpdata->refgrow;
+ helpdata->command_search = helpdata->refcommand_search;
+ helppage();
+ return;
+ }
+ if (y != 0 && y != D_height - 1)
+ return;
+ if (isblank)
+ return;
+ Clear(xs, y, xs, xe, xe, y, 0);
+}
+
+
+/*
+**
+** here is all the copyright stuff
+**
+*/
+
+static void CopyrightProcess __P((char **, int *));
+static void CopyrightRedisplayLine __P((int, int, int, int));
+static void CopyrightAbort __P((void));
+static void CopyrightSetCursor __P((void));
+static void copypage __P((void));
+
+struct copydata
+{
+ char *cps, *savedcps; /* position in the message */
+ char *refcps, *refsavedcps; /* backup for redisplaying */
+};
+
+static struct LayFuncs CopyrightLf =
+{
+ CopyrightProcess,
+ CopyrightAbort,
+ CopyrightRedisplayLine,
+ DefClearLine,
+ DefRewrite,
+ CopyrightSetCursor,
+ DefResize,
+ DefRestore
+};
+
+static const char cpmsg[] = "\
+\n\
+Screen version %v\n\
+\n\
+Copyright (c) 1993 Juergen Weigert, Michael Schroeder\n\
+Copyright (c) 1987 Oliver Laumann\n\
+\n\
+This program is free software; you can redistribute it and/or \
+modify it under the terms of the GNU General Public License as published \
+by the Free Software Foundation; either version 2, or (at your option) \
+any later version.\n\
+\n\
+This program is distributed in the hope that it will be useful, \
+but WITHOUT ANY WARRANTY; without even the implied warranty of \
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \
+GNU General Public License for more details.\n\
+\n\
+You should have received a copy of the GNU General Public License \
+along with this program (see the file COPYING); if not, write to the \
+Free Software Foundation, Inc., \
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\
+\n\
+Send bugreports, fixes, enhancements, t-shirts, money, beer & pizza to \
+screen@uni-erlangen.de\n";
+
+
+static void
+CopyrightSetCursor()
+{
+ GotoPos(0, D_height - 1);
+}
+
+static void
+CopyrightProcess(ppbuf, plen)
+char **ppbuf;
+int *plen;
+{
+ int done = 0;
+ struct copydata *copydata;
+
+ copydata = (struct copydata *)D_lay->l_data;
+ GotoPos(0, D_height - 1);
+ while (!done && *plen > 0)
+ {
+ switch (**ppbuf)
+ {
+ case ' ':
+ if (*copydata->cps)
+ {
+ copypage();
+ break;
+ }
+ /* FALLTHROUGH */
+ case '\r':
+ case '\n':
+ CopyrightAbort();
+ done = 1;
+ break;
+ default:
+ break;
+ }
+ ++*ppbuf;
+ --*plen;
+ }
+}
+
+static void
+CopyrightAbort()
+{
+ LAY_CALL_UP(Activate(0));
+ ExitOverlayPage();
+}
+
+void
+display_copyright()
+{
+ struct copydata *copydata;
+
+ if (D_width < 10 || D_height < 5)
+ {
+ Msg(0, "Window size too small for copyright page");
+ return;
+ }
+ if (InitOverlayPage(sizeof(*copydata), &CopyrightLf, 0))
+ return;
+ copydata = (struct copydata *)D_lay->l_data;
+ copydata->cps = (char *)cpmsg;
+ copydata->savedcps = 0;
+ copypage();
+}
+
+static void
+copypage()
+{
+ register char *cps;
+ char *ws;
+ int x, y, l;
+ char cbuf[80];
+ struct copydata *copydata;
+
+ copydata = (struct copydata *)D_lay->l_data;
+ SetRendition(&mchar_null);
+ ClearDisplay();
+ x = y = 0;
+ cps = copydata->cps;
+ copydata->refcps = cps;
+ copydata->refsavedcps = copydata->savedcps;
+ while (*cps && y < D_height - 3)
+ {
+ ws = cps;
+ while (*cps == ' ')
+ cps++;
+ if (strncmp(cps, "%v", 2) == 0)
+ {
+ copydata->savedcps = cps + 2;
+ cps = version;
+ continue;
+ }
+ while (*cps && *cps != ' ' && *cps != '\n')
+ cps++;
+ l = cps - ws;
+ cps = ws;
+ if (l > D_width - 1)
+ l = D_width - 1;
+ if (x && x + l >= D_width - 2)
+ {
+ AddStr("\r\n");
+ x = 0;
+ y++;
+ continue;
+ }
+ if (x)
+ {
+ AddChar(' ');
+ x++;
+ }
+ if (l)
+ AddStrn(ws, l);
+ x += l;
+ cps += l;
+ if (*cps == 0 && copydata->savedcps)
+ {
+ cps = copydata->savedcps;
+ copydata->savedcps = 0;
+ }
+ if (*cps == '\n')
+ {
+ AddStr("\r\n");
+ x = 0;
+ y++;
+ }
+ if (*cps == ' ' || *cps == '\n')
+ cps++;
+ }
+ while (*cps == '\n')
+ cps++;
+ while (y++ < D_height - 2)
+ AddStr("\r\n");
+ sprintf(cbuf,"[Press Space %s Return to end.]",
+ *cps ? "for next page;" : "or");
+ centerline(cbuf);
+ SetLastPos(0, D_height-1);
+ copydata->cps = cps;
+}
+
+static void
+CopyrightRedisplayLine(y, xs, xe, isblank)
+int y, xs, xe, isblank;
+{
+ if (y < 0)
+ {
+ struct copydata *copydata;
+
+ copydata = (struct copydata *)D_lay->l_data;
+ copydata->cps = copydata->refcps;
+ copydata->savedcps = copydata->refsavedcps;
+ copypage();
+ return;
+ }
+ if (y != 0 && y != D_height - 1)
+ return;
+ if (isblank)
+ return;
+ Clear(xs, y, xs, xe, xe, y, 0);
+}
+
+void
+display_displays()
+{
+ /* To be filled in... */
+}
+
+/*
+**
+** The bindkey help page
+**
+*/
+
+#ifdef MAPKEYS
+
+extern char *kmap_extras[];
+extern int kmap_extras_fl[];
+extern struct term term[];
+
+static void BindkeyProcess __P((char **, int *));
+static void BindkeyAbort __P((void));
+static void BindkeyRedisplayLine __P((int, int, int, int));
+static void BindkeySetCursor __P((void));
+static void bindkeypage __P((void));
+
+struct bindkeydata
+{
+ char *title;
+ struct action *tab;
+ int pos;
+ int last;
+ int page;
+ int pages;
+};
+
+static struct LayFuncs BindkeyLf =
+{
+ BindkeyProcess,
+ BindkeyAbort,
+ BindkeyRedisplayLine,
+ DefClearLine,
+ DefRewrite,
+ BindkeySetCursor,
+ DefResize,
+ DefRestore
+};
+
+
+void
+display_bindkey(title, tab)
+char *title;
+struct action *tab;
+{
+ struct bindkeydata *bindkeydata;
+ int i, n;
+
+ if (display == 0)
+ return;
+ if (D_height < 6)
+ {
+ Msg(0, "Window height too small for bindkey page");
+ return;
+ }
+ if (InitOverlayPage(sizeof(*bindkeydata), &BindkeyLf, 0))
+ return;
+
+ bindkeydata = (struct bindkeydata *)D_lay->l_data;
+ bindkeydata->title = title;
+ bindkeydata->tab = tab;
+
+ n = 0;
+ for (i = 0; i < KMAP_KEYS+KMAP_AKEYS+KMAP_EXT; i++)
+ {
+ if (tab[i].nr != RC_ILLEGAL)
+ n++;
+ }
+ bindkeydata->pos = 0;
+ bindkeydata->page = 1;
+ bindkeydata->pages = (n + D_height - 6) / (D_height - 5);
+ if (bindkeydata->pages == 0)
+ bindkeydata->pages = 1;
+ bindkeypage();
+}
+
+static void
+BindkeySetCursor()
+{
+ GotoPos(0, D_height - 1);
+}
+
+static void
+BindkeyAbort()
+{
+ LAY_CALL_UP(Activate(0));
+ ExitOverlayPage();
+}
+
+static void
+bindkeypage()
+{
+ struct bindkeydata *bindkeydata;
+ char tbuf[256];
+ int del, i, ch, y;
+ struct action *act;
+ char *xch, *s, *p;
+
+ bindkeydata = (struct bindkeydata *)D_lay->l_data;
+
+ SetRendition(&mchar_null);
+ ClearDisplay();
+
+ sprintf(tbuf, "%s key bindings, page %d of %d.", bindkeydata->title, bindkeydata->page, bindkeydata->pages);
+ centerline(tbuf);
+ AddChar('\n');
+ y = D_height - 5;
+ for (i = bindkeydata->pos; i < KMAP_KEYS+KMAP_AKEYS+KMAP_EXT && y; i++)
+ {
+ p = tbuf;
+ act = &bindkeydata->tab[i];
+ if (act->nr == RC_ILLEGAL)
+ continue;
+ xch = " ";
+ if (i < KMAP_KEYS)
+ {
+ del = *p++ = ':';
+ s = term[i + T_CAPS].tcname;
+ }
+ else if (i < KMAP_KEYS+KMAP_AKEYS)
+ {
+ del = *p++ = ':';
+ s = term[i + (T_CAPS - T_OCAPS + T_CURSOR)].tcname;
+ xch = "[A]";
+ }
+ else
+ {
+ del = 0;
+ s = kmap_extras[i - (KMAP_KEYS+KMAP_AKEYS)];
+ if (kmap_extras_fl[i - (KMAP_KEYS+KMAP_AKEYS)])
+ xch = "[T]";
+ }
+ while ((ch = *(unsigned char *)s++))
+ p += AddXChar(p, ch);
+ if (del)
+ *p++ = del;
+ *p++ = ' ';
+ while (p < tbuf + 15)
+ *p++ = ' ';
+ sprintf(p, "%s -> ", xch);
+ p += 7;
+ if (p - tbuf > D_width - 1)
+ {
+ tbuf[D_width - 2] = '$';
+ tbuf[D_width - 1] = 0;
+ }
+ AddStr(tbuf);
+ AddAction(act, D_width - 1 - strlen(tbuf));
+ AddStr("\r\n");
+ y--;
+ }
+ y++;
+ while(y--)
+ AddChar('\n');
+ bindkeydata->last = i;
+ sprintf(tbuf,"[Press Space %s Return to end.]", bindkeydata->page < bindkeydata->pages ? "for next page;" : "or");
+ centerline(tbuf);
+ SetLastPos(0, D_height-1);
+}
+
+static void
+BindkeyProcess(ppbuf, plen)
+char **ppbuf;
+int *plen;
+{
+ int done = 0;
+ struct bindkeydata *bindkeydata;
+
+ bindkeydata = (struct bindkeydata *)D_lay->l_data;
+ GotoPos(0, D_height-1);
+ while (!done && *plen > 0)
+ {
+ switch (**ppbuf)
+ {
+ case ' ':
+ if (bindkeydata->page < bindkeydata->pages)
+ {
+ bindkeydata->pos = bindkeydata->last;
+ bindkeydata->page++;
+ bindkeypage();
+ break;
+ }
+ /* FALLTHROUGH */
+ case '\r':
+ case '\n':
+ done = 1;
+ break;
+ default:
+ break;
+ }
+ ++*ppbuf;
+ --*plen;
+ }
+ if (done)
+ BindkeyAbort();
+}
+
+static void
+BindkeyRedisplayLine(y, xs, xe, isblank)
+int y, xs, xe, isblank;
+{
+ if (y < 0)
+ {
+ bindkeypage();
+ return;
+ }
+ if (y != 0 && y != D_height - 1)
+ return;
+ if (isblank)
+ return;
+ Clear(xs, y, xs, xe, xe, y, 0);
+}
+
+#endif
diff --git a/image.h b/image.h
new file mode 100644
index 0000000..dbca3e5
--- /dev/null
+++ b/image.h
@@ -0,0 +1,106 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ * $Id: image.h,v 1.9 1994/05/31 12:31:54 mlschroe Exp $ FAU
+ */
+
+
+#undef IFCOLOR
+
+#ifdef COLOR
+# define IFCOLOR(x) x
+#else
+# define IFCOLOR(x)
+#endif
+
+
+struct mchar {
+ char image;
+ char attr;
+ char font;
+IFCOLOR(char color;)
+};
+
+struct mline {
+ char *image;
+ char *attr;
+ char *font;
+IFCOLOR(char *color;)
+};
+
+
+
+#define save_mline(ml, n) do { \
+ bcopy((ml)->image, mline_old.image, (n)); \
+ bcopy((ml)->attr, mline_old.attr, (n)); \
+ bcopy((ml)->font, mline_old.font, (n)); \
+IFCOLOR(bcopy((ml)->color, mline_old.color, (n)); )\
+} while (0)
+
+#define bcopy_mline(ml, xf, xt, n) do { \
+ bcopy((ml)->image + (xf), (ml)->image + (xt), (n)); \
+ bcopy((ml)->attr + (xf), (ml)->attr + (xt), (n)); \
+ bcopy((ml)->font + (xf), (ml)->font + (xt), (n)); \
+IFCOLOR(bcopy((ml)->color + (xf), (ml)->color + (xt), (n)); )\
+} while (0)
+
+#define clear_mline(ml, x, n) do { \
+ bclear((ml)->image + (x), (n)); \
+ if ((ml)->attr != null) bzero((ml)->attr + (x), (n)); \
+ if ((ml)->font != null) bzero((ml)->font + (x), (n)); \
+IFCOLOR(if ((ml)->color!= null) bzero((ml)->color + (x), (n)); )\
+} while (0)
+
+#define cmp_mline(ml1, ml2, x) ( \
+ (ml1)->image[x] == (ml2)->image[x] \
+ && (ml1)->attr[x] == (ml2)->attr[x] \
+ && (ml1)->font[x] == (ml2)->font[x] \
+IFCOLOR(&& (ml1)->color[x] == (ml2)->color[x] )\
+)
+
+#define cmp_mchar(mc1, mc2) ( \
+ (mc1)->image == (mc2)->image \
+ && (mc1)->attr == (mc2)->attr \
+ && (mc1)->font == (mc2)->font \
+IFCOLOR(&& (mc1)->color == (mc2)->color )\
+)
+
+#define cmp_mchar_mline(mc, ml, x) ( \
+ (mc)->image == (ml)->image[x] \
+ && (mc)->attr == (ml)->attr[x] \
+ && (mc)->font == (ml)->font[x] \
+IFCOLOR(&& (mc)->color == (ml)->color[x] )\
+)
+
+#define copy_mchar2mline(mc, ml, x) do { \
+ (ml)->image[x] = (mc)->image; \
+ (ml)->attr[x] = (mc)->attr; \
+ (ml)->font[x] = (mc)->font; \
+IFCOLOR((ml)->color[x] = (mc)->color; )\
+} while (0)
+
+#define copy_mline2mchar(mc, ml, x) do { \
+ (mc)->image = (ml)->image[x]; \
+ (mc)->attr = (ml)->attr[x]; \
+ (mc)->font = (ml)->font[x]; \
+IFCOLOR((mc)->color = (ml)->color[x]; )\
+} while (0)
+
diff --git a/input.c b/input.c
new file mode 100644
index 0000000..79208e7
--- /dev/null
+++ b/input.c
@@ -0,0 +1,291 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: input.c,v 1.2 1994/05/31 12:32:08 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+
+static void InpProcess __P((char **, int *));
+static void InpAbort __P((void));
+static void InpRedisplayLine __P((int, int, int, int));
+static void InpSetCursor __P((void));
+
+extern struct display *display;
+extern struct mchar mchar_blank, mchar_so;
+
+struct inpdata
+{
+ char inpbuf[101];
+ int inplen;
+ int inpmaxlen;
+ char *inpstring;
+ int inpstringlen;
+ int inpmode;
+ void (*inpfinfunc)();
+};
+
+static struct LayFuncs InpLf =
+{
+ InpProcess,
+ InpAbort,
+ InpRedisplayLine,
+ DefClearLine,
+ DefRewrite,
+ InpSetCursor,
+ DefResize,
+ DefRestore
+};
+
+/*
+** Here is the input routine
+*/
+
+void
+inp_setprompt(p, s)
+char *p, *s;
+{
+ struct inpdata *inpdata;
+
+ inpdata = (struct inpdata *)D_lay->l_data;
+ if (p)
+ {
+ inpdata->inpstringlen = strlen(p);
+ inpdata->inpstring = p;
+ }
+ if (s)
+ {
+ strncpy(inpdata->inpbuf, s, sizeof(inpdata->inpbuf) - 1);
+ inpdata->inpbuf[sizeof(inpdata->inpbuf) - 1] = 0;
+ inpdata->inplen = strlen(inpdata->inpbuf);
+ }
+ RefreshLine(STATLINE, 0, D_width - 1, 0);
+}
+
+/*
+ * We dont use HS status line with Input().
+ * If we would use it, then we should check e_tgetflag("es") if
+ * we are allowed to use esc sequences there.
+ *
+ * mode is an OR of
+ * INP_NOECHO == suppress echoing of characters.
+ * INP_RAW == raw mode. call finfunc after each character typed.
+ */
+void
+Input(istr, len, finfunc, mode)
+char *istr;
+int len;
+void (*finfunc)();
+int mode;
+{
+ int maxlen;
+ struct inpdata *inpdata;
+
+ if (!display)
+ {
+ Msg(0, "Input: cannot interact with user w/o display. Try other form of command\n");
+ return;
+ }
+ if (len > 100)
+ len = 100;
+ if (!(mode & INP_NOECHO))
+ {
+ maxlen = D_width - strlen(istr);
+ if (!D_CLP && STATLINE == D_bot)
+ maxlen--;
+ if (len > maxlen)
+ len = maxlen;
+ }
+ if (len < 0)
+ {
+ Msg(0, "Width %d chars too small", -len);
+ return;
+ }
+ if (InitOverlayPage(sizeof(*inpdata), &InpLf, 1))
+ return;
+ inpdata = (struct inpdata *)D_lay->l_data;
+ inpdata->inpmaxlen = len;
+ inpdata->inpfinfunc = finfunc;
+ inpdata->inplen = 0;
+ inpdata->inpmode = mode;
+ inp_setprompt(istr, (char *)NULL);
+}
+
+static void
+InpSetCursor()
+{
+ struct inpdata *inpdata;
+
+ inpdata = (struct inpdata *)D_lay->l_data;
+ GotoPos(inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inplen), STATLINE);
+}
+
+static void
+InpProcess(ppbuf, plen)
+char **ppbuf;
+int *plen;
+{
+ int len, x;
+ char *pbuf;
+ char ch;
+ struct inpdata *inpdata;
+
+ inpdata = (struct inpdata *)D_lay->l_data;
+
+ GotoPos(inpdata->inpstringlen + (inpdata->inpmode & INP_NOECHO ? 0 : inpdata->inplen), STATLINE);
+ if (ppbuf == 0)
+ {
+ InpAbort();
+ return;
+ }
+ x = inpdata->inpstringlen + inpdata->inplen;
+ len = *plen;
+ pbuf = *ppbuf;
+ while (len)
+ {
+ ch = *pbuf++;
+ len--;
+ if (inpdata->inpmode & INP_EVERY)
+ {
+ inpdata->inpbuf[inpdata->inplen] = ch;
+ inpdata->inpbuf[inpdata->inplen + 1] = ch; /* gross */
+ (*inpdata->inpfinfunc)(inpdata->inpbuf, inpdata->inplen);
+ ch = inpdata->inpbuf[inpdata->inplen];
+ }
+ else if (inpdata->inpmode & INP_RAW)
+ {
+ (*inpdata->inpfinfunc)(&ch, 1); /* raw */
+ if (ch)
+ continue;
+ }
+ if ((unsigned char)ch >= ' ' && ch != 0177 && inpdata->inplen < inpdata->inpmaxlen)
+ {
+ inpdata->inpbuf[inpdata->inplen++] = ch;
+ if (!(inpdata->inpmode & INP_NOECHO))
+ {
+ GotoPos(x, STATLINE);
+ SetRendition(&mchar_so);
+ PUTCHAR(ch);
+ x++;
+ }
+ }
+ else if ((ch == '\b' || ch == 0177) && inpdata->inplen > 0)
+ {
+ inpdata->inplen--;
+ if (!(inpdata->inpmode & 1))
+ {
+ x--;
+ GotoPos(x, STATLINE);
+ SetRendition(&mchar_blank);
+ PUTCHAR(' ');
+ GotoPos(x, STATLINE);
+ }
+ }
+ else if (ch == '\004' || ch == '\003' || ch == '\007' || ch == '\033' ||
+ ch == '\000' || ch == '\n' || ch == '\r')
+ {
+ if (ch != '\033' && ch != '\n' && ch != '\r')
+ inpdata->inplen = 0;
+ inpdata->inpbuf[inpdata->inplen] = 0;
+
+ D_lay->l_data = 0;
+ InpAbort(); /* redisplays... */
+ *ppbuf = pbuf;
+ *plen = len;
+ if ((inpdata->inpmode & INP_RAW) == 0)
+ (*inpdata->inpfinfunc)(inpdata->inpbuf, inpdata->inplen);
+ else
+ (*inpdata->inpfinfunc)(pbuf - 1, 0);
+ free((char *)inpdata);
+ return;
+ }
+ }
+ *ppbuf = pbuf;
+ *plen = len;
+}
+
+static void
+InpAbort()
+{
+ LAY_CALL_UP(RefreshLine(STATLINE, 0, D_width - 1, 0));
+ ExitOverlayPage();
+}
+
+static void
+InpRedisplayLine(y, xs, xe, isblank)
+int y, xs, xe, isblank;
+{
+ int q, r, s, l, v;
+ struct inpdata *inpdata;
+
+ inpdata = (struct inpdata *)D_lay->l_data;
+
+ if (y != STATLINE)
+ {
+ LAY_CALL_UP(RefreshLine(y, xs, xe, isblank));
+ return;
+ }
+ inpdata->inpbuf[inpdata->inplen] = 0;
+ GotoPos(xs, y);
+ q = xs;
+ v = xe - xs + 1;
+ s = 0;
+ r = inpdata->inpstringlen;
+ if (v > 0 && q < r)
+ {
+ SetRendition(&mchar_so);
+ l = v;
+ if (l > r-q)
+ l = r-q;
+ AddStrn(inpdata->inpstring + q - s, l);
+ q += l;
+ v -= l;
+ }
+ s = r;
+ r += inpdata->inplen;
+ if (!(inpdata->inpmode & INP_NOECHO) && v > 0 && q < r)
+ {
+ SetRendition(&mchar_so);
+ l = v;
+ if (l > r-q)
+ l = r-q;
+ AddStrn(inpdata->inpbuf + q - s, l);
+ q += l;
+ v -= l;
+ }
+ s = r;
+ r = D_width;
+ if (!isblank && v > 0 && q < r)
+ {
+ SetRendition(&mchar_blank);
+ l = v;
+ if (l > r-q)
+ l = r-q;
+ AddStrn("", l);
+ q += l;
+ }
+ SetLastPos(q, y);
+}
diff --git a/install.sh b/install.sh
new file mode 100755
index 0000000..8c07c50
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,119 @@
+#! /bin/sh
+
+#
+# install - install a program, script, or datafile
+# This comes from X11R5; it is not part of GNU.
+#
+# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+
+instcmd="$mvprog"
+chmodcmd=""
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+fi
+
+if [ x"$dst" = x ]
+then
+ echo "install: no destination specified"
+ exit 1
+fi
+
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+if [ -d $dst ]
+then
+ dst="$dst"/`basename $src`
+fi
+
+# Make a temp file name in the proper directory.
+
+dstdir=`dirname $dst`
+dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+$doit $instcmd $src $dsttmp
+
+# and set any options; do chmod last to preserve setuid bits
+
+if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi
+if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi
+if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi
+if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi
+
+# Now rename the file to the real destination.
+
+$doit $rmcmd $dst
+$doit $mvcmd $dsttmp $dst
+
+
+exit 0
diff --git a/kmapdef.c.dist b/kmapdef.c.dist
new file mode 100644
index 0000000..943c600
--- /dev/null
+++ b/kmapdef.c.dist
@@ -0,0 +1,130 @@
+/*
+ * This file is automagically created from term.c -- DO NOT EDIT
+ */
+
+#include "config.h"
+
+#ifdef MAPKEYS
+
+char *kmapdef[] = {
+"\033[10~",
+"\033OP",
+"\033OQ",
+"\033OR",
+"\033OS",
+"\033[15~",
+"\033[17~",
+"\033[18~",
+"\033[19~",
+"\033[20~",
+"\033[21~",
+"\033[23~",
+"\033[24~",
+"\010",
+"\033[1~",
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+"\033[3~",
+0,
+0,
+"\033[4~",
+"\033[2~",
+0,
+0,
+"\033[6~",
+"\033[5~",
+0,
+0,
+0,
+0,
+0,
+0,
+"\033[A",
+"\033[B",
+"\033[C",
+"\033[D",
+"0",
+"1",
+"2",
+"3",
+"4",
+"5",
+"6",
+"7",
+"8",
+"9",
+"+",
+"-",
+"*",
+"/",
+"=",
+".",
+",",
+"\015"
+};
+
+char *kmapadef[] = {
+"\033OA",
+"\033OB",
+"\033OC",
+"\033OD",
+"\033Op",
+"\033Oq",
+"\033Or",
+"\033Os",
+"\033Ot",
+"\033Ou",
+"\033Ov",
+"\033Ow",
+"\033Ox",
+"\033Oy",
+"\033Ok",
+"\033Om",
+"\033Oj",
+"\033Oo",
+"\033OX",
+"\033On",
+"\033Ol",
+"\033OM"
+};
+
+char *kmapmdef[] = {
+"g",
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+"\004",
+"G",
+0,
+0,
+0,
+"\006",
+"\002",
+"\025",
+0,
+0,
+0,
+0,
+0,
+"k",
+"j",
+"l",
+"h"
+};
+
+#endif
diff --git a/loadav.c b/loadav.c
new file mode 100644
index 0000000..0e34327
--- /dev/null
+++ b/loadav.c
@@ -0,0 +1,249 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: loadav.c,v 1.5 1994/09/06 17:00:00 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+#include <fcntl.h>
+#ifdef ultrix
+# include <sys/fixpoint.h>
+#endif
+
+/* mach stuff included here to prevent index macro conflict */
+#ifdef NeXT
+# include <sys/version.h>
+# if KERNEL_MAJOR_VERSION > 2
+# include <mach/mach.h>
+# else
+# include <mach.h>
+# endif
+#endif
+
+#include "config.h"
+#include "screen.h"
+
+#include "extern.h"
+
+#ifdef LOADAV
+
+static int GetLoadav __P((void));
+
+static LOADAV_TYPE loadav[LOADAV_NUM];
+static int loadok;
+
+
+
+/***************************************************************/
+
+#if defined(linux) && !defined(LOADAV_DONE)
+#define LOADAV_DONE
+/*
+ * This is the easy way. It relies in /proc being mounted.
+ * For the big and ugly way refer to previous screen version.
+ */
+void
+InitLoadav()
+{
+ loadok = 1;
+}
+
+static int
+GetLoadav()
+{
+ FILE *fp;
+ double d[3];
+ int i;
+
+ if ((fp = secfopen("/proc/loadavg", "r")) == NULL)
+ return 0;
+ fscanf(fp, "%lf %lf %lf\n", d, d + 1, d + 2);
+ fclose(fp);
+ for (i = 0; i < (LOADAV_NUM > 3 ? 3 : LOADAV_NUM); i++)
+ loadav[i] = d[i];
+ return i;
+}
+#endif /* linux */
+
+/***************************************************************/
+
+#if defined(LOADAV_GETLOADAVG) && !defined(LOADAV_DONE)
+#define LOADAV_DONE
+void
+InitLoadav()
+{
+ loadok = 1;
+}
+
+static int
+GetLoadav()
+{
+ return getloadavg(loadav, LOADAV_NUM);
+}
+#endif
+
+/***************************************************************/
+
+#if defined(apollo) && !defined(LOADAV_DONE)
+#define LOADAV_DONE
+void
+InitLoadav()
+{
+ loadok = 1;
+}
+
+static int
+GetLoadav()
+{
+ proc1_$get_loadav(loadav);
+ return LOADAV_NUM;
+}
+#endif
+
+/***************************************************************/
+
+#if defined(NeXT) && !defined(LOADAV_DONE)
+#define LOADAV_DONE
+
+static processor_set_t default_set;
+
+void
+InitLoadav()
+{
+ kern_return_t error;
+
+ error = processor_set_default(host_self(), &default_set);
+ if (error != KERN_SUCCESS)
+ mach_error("Error calling processor_set_default", error);
+ else
+ loadok = 1;
+}
+
+static int
+GetLoadav()
+{
+ unsigned int info_count;
+ struct processor_set_basic_info info;
+ host_t host;
+
+ info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
+ if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, &host, (processor_set_info_t)&info, &info_count) != KERN_SUCCESS)
+ return 0;
+ loadav[0] = (float)info.load_average / LOAD_SCALE;
+ return 1;
+}
+#endif
+
+/***************************************************************/
+
+#if !defined(LOADAV_DONE)
+/*
+ * The old fashion way: open kernel and read avenrun
+ *
+ * Header File includes
+ */
+
+# ifdef NLIST_STRUCT
+# include <nlist.h>
+# else
+# include <a.out.h>
+# endif
+# ifndef NLIST_DECLARED
+extern int nlist __P((char *, struct nlist *));
+# endif
+
+#ifdef __sgi
+# if _MIPS_SZLONG == 64
+# define nlist nlist64
+# endif
+#endif
+
+static struct nlist nl[2];
+static int kmemf;
+
+#ifdef _IBMR2
+# define nlist(u,l) knlist(l,1,sizeof(*l))
+#endif
+
+void
+InitLoadav()
+{
+ debug("Init Kmem...\n");
+ if ((kmemf = open("/dev/kmem", O_RDONLY)) == -1)
+ return;
+# if !defined(_AUX_SOURCE) && !defined(AUX)
+# ifdef NLIST_NAME_UNION
+ nl[0].n_un.n_name = LOADAV_AVENRUN;
+# else
+ nl[0].n_name = LOADAV_AVENRUN;
+# endif
+# else
+ strncpy(nl[0].n_name, LOADAV_AVENRUN, sizeof(nl[0].n_name));
+# endif
+ debug2("Searching in %s for %s\n", LOADAV_UNIX, nl[0].n_name);
+ nlist(LOADAV_UNIX, nl);
+ if (nl[0].n_value == 0)
+ {
+ close(kmemf);
+ return;
+ }
+# ifdef sgi
+ nl[0].n_value &= (unsigned long)-1 >> 1; /* clear upper bit */
+# endif /* sgi */
+ debug1("AvenrunSym found (0x%lx)!!\n", nl[0].n_value);
+ loadok = 1;
+}
+
+static int
+GetLoadav()
+{
+ if (lseek(kmemf, (off_t) nl[0].n_value, 0) == (off_t)-1)
+ return 0;
+ if (read(kmemf, (char *) loadav, sizeof(loadav)) != sizeof(loadav))
+ return 0;
+ return LOADAV_NUM;
+}
+#endif
+
+/***************************************************************/
+
+#ifndef FIX_TO_DBL
+#define FIX_TO_DBL(l) ((double)(l) / LOADAV_SCALE)
+#endif
+
+void
+AddLoadav(p)
+char *p;
+{
+ int i, j;
+ if (loadok == 0)
+ return;
+ j = GetLoadav();
+ for (i = 0; i < j; i++)
+ {
+ sprintf(p, " %2.2f", FIX_TO_DBL(loadav[i]));
+ p += strlen(p);
+ }
+}
+
+#endif /* LOADAV */
diff --git a/mark.c b/mark.c
new file mode 100644
index 0000000..2e84f27
--- /dev/null
+++ b/mark.c
@@ -0,0 +1,1320 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: mark.c,v 1.6 1994/05/31 12:32:15 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+
+#include "config.h"
+#include "screen.h"
+#include "mark.h"
+#include "extern.h"
+
+#ifdef COPY_PASTE
+
+static int is_letter __P((int));
+static void nextword __P((int *, int *, int, int));
+static int linestart __P((int));
+static int lineend __P((int));
+static int rem __P((int, int , int , int , int , char *, int));
+static int eq __P((int, int ));
+static int MarkScrollDownDisplay __P((int));
+static int MarkScrollUpDisplay __P((int));
+
+static void MarkProcess __P((char **, int *));
+static void MarkAbort __P((void));
+static void MarkRedisplayLine __P((int, int, int, int));
+static int MarkRewrite __P((int, int, int, int));
+static void MarkSetCursor __P((void));
+
+extern struct win *fore;
+extern struct display *display;
+extern char *null, *blank;
+extern struct mline mline_blank, mline_null;
+extern struct mchar mchar_so;
+
+#ifdef NETHACK
+extern nethackflag;
+#endif
+
+int pastefont = 1;
+
+static struct LayFuncs MarkLf =
+{
+ MarkProcess,
+ MarkAbort,
+ MarkRedisplayLine,
+ DefClearLine,
+ MarkRewrite,
+ MarkSetCursor,
+ DefResize,
+ DefRestore
+};
+
+int join_with_cr = 0;
+char mark_key_tab[256]; /* this array must be initialised first! */
+
+static struct markdata *markdata;
+
+
+/*
+ * VI like is_letter: 0 - whitespace
+ * 1 - letter
+ * 2 - other
+ */
+static int is_letter(c)
+char c;
+{
+ if ((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ c == '_' || c == '.' ||
+ c == '@' || c == ':' ||
+ c == '%' || c == '!' ||
+ c == '-' || c == '+')
+ /* thus we can catch email-addresses as a word :-) */
+ return 1;
+ else if (c != ' ')
+ return 2;
+ return 0;
+}
+
+static int
+linestart(y)
+int y;
+{
+ register int x;
+ register char *i;
+
+ for (x = markdata->left_mar, i = WIN(y)->image + x; x < D_width - 1; x++)
+ if (*i++ != ' ')
+ break;
+ if (x == D_width - 1)
+ x = markdata->left_mar;
+ return x;
+}
+
+static int
+lineend(y)
+int y;
+{
+ register int x;
+ register char *i;
+
+ for (x = markdata->right_mar, i = WIN(y)->image + x; x >= 0; x--)
+ if (*i-- != ' ')
+ break;
+ if (x < 0)
+ x = markdata->left_mar;
+ return x;
+}
+
+
+/*
+ * nextword calculates the cursor position of the num'th word.
+ * If the cursor is on a word, it counts as the first.
+ * NW_BACK: search backward
+ * NW_ENDOFWORD: find the end of the word
+ * NW_MUSTMOVE: move at least one char
+ */
+
+#define NW_BACK (1<<0)
+#define NW_ENDOFWORD (1<<1)
+#define NW_MUSTMOVE (1<<2)
+
+static void
+nextword(xp, yp, flags, num)
+int *xp, *yp, flags, num;
+{
+ int xx = D_width, yy = fore->w_histheight + D_height;
+ register int sx, oq, q, x, y;
+ struct mline *ml;
+
+ x = *xp;
+ y = *yp;
+ sx = (flags & NW_BACK) ? -1 : 1;
+ if ((flags & NW_ENDOFWORD) && (flags & NW_MUSTMOVE))
+ x += sx;
+ ml = WIN(y);
+ for (oq = -1; ; x += sx, oq = q)
+ {
+ if (x >= xx || x < 0)
+ q = 0;
+ else
+ q = is_letter(ml->image[x]);
+ if (oq >= 0 && oq != q)
+ {
+ if (oq == 0 || !(flags & NW_ENDOFWORD))
+ *xp = x;
+ else
+ *xp = x-sx;
+ *yp = y;
+ if ((!(flags & NW_ENDOFWORD) && q) ||
+ ((flags & NW_ENDOFWORD) && oq))
+ {
+ if (--num <= 0)
+ return;
+ }
+ }
+ if (x == xx)
+ {
+ x = -1;
+ if (++y >= yy)
+ return;
+ ml = WIN(y);
+ }
+ else if (x < 0)
+ {
+ x = xx;
+ if (--y < 0)
+ return;
+ ml = WIN(y);
+ }
+ }
+}
+
+
+/*
+ * y1, y2 are WIN coordinates
+ *
+ * redisplay: 0 - just copy
+ * 1 - redisplay + copy
+ * 2 - count + copy, don't redisplay
+ */
+
+static int
+rem(x1, y1, x2, y2, redisplay, pt, yend)
+int x1, y1, x2, y2, redisplay, yend;
+char *pt;
+{
+ int i, j, from, to, ry, c, cf, font;
+ int l = 0;
+ char *im, *fo;
+ struct mline *ml;
+
+ markdata->second = 0;
+ if (y2 < y1 || ((y2 == y1) && (x2 < x1)))
+ {
+ i = y2;
+ y2 = y1;
+ y1 = i;
+ i = x2;
+ x2 = x1;
+ x1 = i;
+ }
+ ry = y1 - markdata->hist_offset;
+
+ i = y1;
+ if (redisplay != 2 && pt == 0 && ry <0)
+ {
+ i -= ry;
+ ry = 0;
+ }
+ for (; i <= y2; i++, ry++)
+ {
+ if (redisplay != 2 && pt == 0 && ry > yend)
+ break;
+ ml = WIN(i);
+ from = (i == y1) ? x1 : 0;
+ if (from < markdata->left_mar)
+ from = markdata->left_mar;
+ for (to = D_width, im = ml->image + to; to >= 0; to--)
+ if (*im-- != ' ')
+ break;
+ if (i == y2 && x2 < to)
+ to = x2;
+ if (to > markdata->right_mar)
+ to = markdata->right_mar;
+ if (redisplay == 1 && from <= to && ry >=0 && ry <= yend)
+ MarkRedisplayLine(ry, from, to, 0);
+ if (redisplay != 2 && pt == 0) /* don't count/copy */
+ continue;
+ j = from;
+#ifdef KANJI
+ if (badkanji(ml->font, j))
+ j--;
+#endif
+ font = ASCII;
+ for (im = ml->image + j, fo = ml->font + j; j <= to; j++)
+ {
+ cf = *fo++;
+ c = *im++;
+#ifdef KANJI
+ if (cf == KANJI)
+ {
+ int t;
+ t = *im++;
+ fo++;
+ j++;
+ if (pastefont)
+ {
+ if (fore->w_kanji == EUC)
+ {
+ c |= 0x80;
+ t |= 0x80;
+ }
+ else if (fore->w_kanji == SJIS)
+ {
+ t += (c & 1) ? ((t <= 0x5f) ? 0x1f : 0x20) : 0x7e;
+ c = (c - 0x21) / 2 + ((c < 0x5e) ? 0x81 : 0xc1);
+ }
+ else
+ {
+ if (pt)
+ {
+ strcpy(pt, "\033$B");
+ pt += 3;
+ }
+ l += 3;
+ font = KANJI;
+ }
+ }
+ if (pt)
+ *pt++ = c;
+ l++;
+ c = t;
+ }
+ else
+#endif
+ if (pastefont)
+ {
+#ifdef KANJI
+ if (cf == KANA)
+ {
+ if (fore->w_kanji == EUC)
+ {
+ if (pt)
+ *pt++ = 0x8e;
+ l++;
+ c |= 0x80;
+ }
+ else if (fore->w_kanji == SJIS)
+ c |= 0x80;
+ else if (font != KANA)
+ {
+ if (pt)
+ {
+ strcpy(pt, "\033(I");
+ pt += 3;
+ }
+ l += 3;
+ font = KANA;
+ }
+ }
+ else
+#endif
+ {
+ if (cf != font)
+ {
+ if (pt)
+ {
+ strcpy(pt, "\033(");
+ pt[2] = (cf == ASCII) ? 'B' : cf;
+ pt += 3;
+ }
+ l += 3;
+ font = cf;
+ }
+ }
+ }
+ if (pt)
+ *pt++ = c;
+ l++;
+ }
+ if (pastefont && font != ASCII)
+ {
+ if (pt)
+ {
+ strcpy(pt, "\033(B");
+ pt += 3;
+ }
+ l += 3;
+ }
+ if (i != y2 && (to != D_width - 1 || ml->image[to + 1] == ' '))
+ {
+ /*
+ * this code defines, what glues lines together
+ */
+ switch (markdata->nonl)
+ {
+ case 0: /* lines separated by newlines */
+ if (pt)
+ *pt++ = '\r';
+ l++;
+ if (join_with_cr)
+ {
+ if (pt)
+ *pt++ = '\n';
+ l++;
+ }
+ break;
+ case 1: /* nothing to separate lines */
+ break;
+ case 2: /* lines separated by blanks */
+ if (pt)
+ *pt++ = ' ';
+ l++;
+ break;
+ }
+ }
+ }
+ return l;
+}
+
+/* Check if two chars are identical. All digits are treatened
+ * as same. Used for GetHistory()
+ */
+
+static int
+eq(a, b)
+int a, b;
+{
+ if (a == b)
+ return 1;
+ if (a == 0 || b == 0)
+ return 1;
+ if (a <= '9' && a >= '0' && b <= '9' && b >= '0')
+ return 1;
+ return 0;
+}
+
+
+int
+GetHistory() /* return value 1 if u_copybuffer changed */
+{
+ int i = 0, q = 0, xx, yy, x, y;
+ char *linep;
+ struct mline *ml;
+
+ x = fore->w_x;
+ if (x >= D_width)
+ x = D_width - 1;
+ y = fore->w_y + fore->w_histheight;
+ debug2("cursor is at x=%d, y=%d\n", x, y);
+ ml = WIN(y);
+ for (xx = x - 1, linep = ml->image + xx; xx >= 0; xx--)
+ if ((q = *linep--) != ' ' )
+ break;
+ debug3("%c at (%d,%d)\n", q, xx, y);
+ for (yy = y - 1; yy >= 0; yy--)
+ {
+ ml = WIN(yy);
+ linep = ml->image;
+ if (xx < 0 || eq(linep[xx], q))
+ { /* line is matching... */
+ for (i = D_width - 1, linep += i; i >= x; i--)
+ if (*linep-- != ' ')
+ break;
+ if (i >= x)
+ break;
+ }
+ }
+ if (yy < 0)
+ return 0;
+ if (D_user->u_copybuffer != NULL)
+ UserFreeCopyBuffer(D_user);
+ if ((D_user->u_copybuffer = malloc((unsigned) (i - x + 2))) == NULL)
+ {
+ Msg(0, "Not enough memory... Sorry.");
+ return 0;
+ }
+ bcopy(linep - i + x + 1, D_user->u_copybuffer, i - x + 1);
+ D_user->u_copylen = i - x + 1;
+ return 1;
+}
+
+void
+MarkRoutine()
+{
+ int x, y;
+
+ ASSERT(fore->w_active);
+ if (InitOverlayPage(sizeof(*markdata), &MarkLf, 1))
+ return;
+ markdata = (struct markdata *)D_lay->l_data;
+ markdata->second = 0;
+ markdata->rep_cnt = 0;
+ markdata->append_mode = 0;
+ markdata->write_buffer = 0;
+ markdata->nonl = 0;
+ markdata->left_mar = 0;
+ markdata->right_mar = D_width - 1;
+ markdata->hist_offset = fore->w_histheight;
+ x = fore->w_x;
+ y = D2W(fore->w_y);
+ if (x >= D_width)
+ x = D_width - 1;
+
+ GotoPos(x, W2D(y));
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "Welcome to hacker's treasure zoo - Column %d Line %d(+%d) (%d,%d)",
+ x + 1, W2D(y + 1), fore->w_histheight, D_width, D_height);
+ else
+#endif
+ Msg(0, "Copy mode - Column %d Line %d(+%d) (%d,%d)",
+ x + 1, W2D(y + 1), fore->w_histheight, D_width, D_height);
+ markdata->cx = markdata->x1 = x;
+ markdata->cy = markdata->y1 = y;
+}
+
+static void
+MarkSetCursor()
+{
+ markdata = (struct markdata *)D_lay->l_data;
+ fore = D_fore;
+ GotoPos(markdata->cx, W2D(markdata->cy));
+}
+
+static void
+MarkProcess(inbufp,inlenp)
+char **inbufp;
+int *inlenp;
+{
+ char *inbuf, *pt;
+ int inlen;
+ int cx, cy, x2, y2, j, yend;
+ int newcopylen = 0, od;
+ int in_mark;
+ int rep_cnt;
+
+/*
+ char *extrap = 0, extrabuf[100];
+*/
+
+ markdata = (struct markdata *)D_lay->l_data;
+ fore = D_fore;
+ if (inbufp == 0)
+ {
+ MarkAbort();
+ return;
+ }
+
+ GotoPos(markdata->cx, W2D(markdata->cy));
+ inbuf= *inbufp;
+ inlen= *inlenp;
+ pt = inbuf;
+ in_mark = 1;
+ while (in_mark && (inlen /* || extrap */))
+ {
+/*
+ if (extrap)
+ {
+ od = *extrap++;
+ if (*extrap == 0)
+ extrap = 0;
+ }
+ else
+*/
+ {
+ od = mark_key_tab[(unsigned int)*pt++];
+ inlen--;
+ }
+ rep_cnt = markdata->rep_cnt;
+ if (od >= '0' && od <= '9')
+ {
+ if (rep_cnt < 1001 && (od != '0' || rep_cnt != 0))
+ {
+ markdata->rep_cnt = 10 * rep_cnt + od - '0';
+ continue;
+ /*
+ * Now what is that 1001 here? Well, we have a screen with
+ * 25 * 80 = 2000 characters. Movement is at most across the full
+ * screen. This we do with word by word movement, as character by
+ * character movement never steps over line boundaries. The most words
+ * we can place on the screen are 1000 single letter words. Thus 1001
+ * is sufficient. Users with bigger screens never write in single letter
+ * words, as they should be more advanced. jw.
+ * Oh, wrong. We still give even the experienced user a factor of ten.
+ */
+ }
+ }
+ cx = markdata->cx;
+ cy = markdata->cy;
+ switch (od)
+ {
+ case 'x':
+ if (!markdata->second)
+ break;
+ markdata->cx = markdata->x1;
+ markdata->cy = markdata->y1;
+ markdata->x1 = cx;
+ markdata->y1 = cy;
+ revto(markdata->cx, markdata->cy);
+ break;
+ case '\014': /* CTRL-L Redisplay */
+ Redisplay(0);
+ GotoPos(cx, W2D(cy));
+ break;
+ case '\010': /* CTRL-H Backspace */
+ case 'h':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ revto(cx - rep_cnt, cy);
+ break;
+ case '\016': /* CTRL-N */
+ case 'j':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ revto(cx, cy + rep_cnt);
+ break;
+ case '+':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ j = cy + rep_cnt;
+ if (j > fore->w_histheight + D_height - 1)
+ j = fore->w_histheight + D_height - 1;
+ revto(linestart(j), j);
+ break;
+ case '-':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ cy -= rep_cnt;
+ if (cy < 0)
+ cy = 0;
+ revto(linestart(cy), cy);
+ break;
+ case '^':
+ revto(linestart(cy), cy);
+ break;
+ case '\n':
+ revto(markdata->left_mar, cy + 1);
+ break;
+ case 'k':
+ case '\020': /* CTRL-P */
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ revto(cx, cy - rep_cnt);
+ break;
+ case 'l':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ revto(cx + rep_cnt, cy);
+ break;
+ case '\001': /* CTRL-A from tcsh/emacs */
+ case '0':
+ revto(markdata->left_mar, cy);
+ break;
+ case '\004': /* CTRL-D down half screen */
+ if (rep_cnt == 0)
+ rep_cnt = (D_height + 1) >> 1;
+ revto_line(cx, cy + rep_cnt, W2D(cy));
+ break;
+ case '$':
+ revto(lineend(cy), cy);
+ break;
+ case '\022': /* CTRL-R emacs style backwards search */
+ ISearch(-1);
+ in_mark = 0;
+ break;
+ case '\023': /* CTRL-S emacs style search */
+ ISearch(1);
+ in_mark = 0;
+ break;
+ case '\025': /* CTRL-U up half screen */
+ if (rep_cnt == 0)
+ rep_cnt = (D_height + 1) >> 1;
+ revto_line(cx, cy - rep_cnt, W2D(cy));
+ break;
+ case '\007': /* CTRL-G show cursorpos */
+ if (markdata->left_mar == 0 && markdata->right_mar == D_width - 1)
+ Msg(0, "Column %d Line %d(+%d)", cx+1, W2D(cy)+1,
+ markdata->hist_offset);
+ else
+ Msg(0, "Column %d(%d..%d) Line %d(+%d)", cx+1,
+ markdata->left_mar+1, markdata->right_mar+1, W2D(cy)+1, markdata->hist_offset);
+ break;
+ case '\002': /* CTRL-B back one page */
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ rep_cnt *= D_height;
+ revto(cx, cy - rep_cnt);
+ break;
+ case '\006': /* CTRL-F forward one page */
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ rep_cnt *= D_height;
+ revto(cx, cy + rep_cnt);
+ break;
+ case '\005': /* CTRL-E scroll up */
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ rep_cnt = MarkScrollUpDisplay(rep_cnt);
+ if (cy < D2W(0))
+ revto(cx, D2W(0));
+ else
+ GotoPos(cx, W2D(cy));
+ break;
+ case '\031': /* CTRL-Y scroll down */
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ rep_cnt = MarkScrollDownDisplay(rep_cnt);
+ if (cy > D2W(D_height-1))
+ revto(cx, D2W(D_height-1));
+ else
+ GotoPos(cx, W2D(cy));
+ break;
+ case '@':
+ /* it may be usefull to have a key that does nothing */
+ break;
+ case '%':
+ rep_cnt--;
+ /* rep_cnt is a percentage for the history buffer */
+ if (rep_cnt < 0)
+ rep_cnt = 0;
+ if (rep_cnt > 100)
+ rep_cnt = 100;
+ revto_line(markdata->left_mar, (rep_cnt * (fore->w_histheight + D_height)) / 100, (D_height - 1) / 2);
+ break;
+ case 'g':
+ rep_cnt = 1;
+ /* FALLTHROUGH */
+ case 'G':
+ /* rep_cnt is here the WIN line number */
+ if (rep_cnt == 0)
+ rep_cnt = fore->w_histheight + D_height;
+ revto_line(markdata->left_mar, --rep_cnt, (D_height - 1) / 2);
+ break;
+ case 'H':
+ revto(markdata->left_mar, D2W(0));
+ break;
+ case 'M':
+ revto(markdata->left_mar, D2W((D_height - 1) / 2));
+ break;
+ case 'L':
+ revto(markdata->left_mar, D2W(D_height - 1));
+ break;
+ case '|':
+ revto(--rep_cnt, cy);
+ break;
+ case 'w':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ nextword(&cx, &cy, NW_MUSTMOVE, rep_cnt);
+ revto(cx, cy);
+ break;
+ case 'e':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ nextword(&cx, &cy, NW_ENDOFWORD|NW_MUSTMOVE, rep_cnt);
+ revto(cx, cy);
+ break;
+ case 'b':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ nextword(&cx, &cy, NW_BACK|NW_ENDOFWORD|NW_MUSTMOVE, rep_cnt);
+ revto(cx, cy);
+ break;
+ case 'a':
+ markdata->append_mode = 1 - markdata->append_mode;
+ debug1("append mode %d--\n", markdata->append_mode);
+ Msg(0, (markdata->append_mode) ? ":set append" : ":set noappend");
+ break;
+ case 'v':
+ case 'V':
+ /* this sets start column to column 9 for VI :set nu users */
+ if (markdata->left_mar == 8)
+ rep_cnt = 1;
+ else
+ rep_cnt = 9;
+ /* FALLTHROUGH */
+ case 'c':
+ case 'C':
+ /* set start column (c) and end column (C) */
+ if (markdata->second)
+ {
+ rem(markdata->x1, markdata->y1, cx, cy, 1, (char *)0, D_height-1); /* Hack */
+ markdata->second = 1; /* rem turns off second */
+ }
+ rep_cnt--;
+ if (rep_cnt < 0)
+ rep_cnt = cx;
+ if (od != 'C')
+ {
+ markdata->left_mar = rep_cnt;
+ if (markdata->left_mar > markdata->right_mar)
+ markdata->left_mar = markdata->right_mar;
+ }
+ else
+ {
+ markdata->right_mar = rep_cnt;
+ if (markdata->left_mar > markdata->right_mar)
+ markdata->right_mar = markdata->left_mar;
+ }
+ if (markdata->second)
+ {
+ markdata->cx = markdata->x1; markdata->cy = markdata->y1;
+ revto(cx, cy);
+ }
+ if (od == 'v' || od == 'V')
+ Msg(0, (markdata->left_mar != 8) ? ":set nonu" : ":set nu");
+ break;
+ case 'J':
+ /* how do you join lines in VI ? */
+ markdata->nonl = (markdata->nonl + 1) % 3;
+ switch (markdata->nonl)
+ {
+ case 0:
+ if (join_with_cr)
+ Msg(0, "Multiple lines (CR/LF)");
+ else
+ Msg(0, "Multiple lines (LF)");
+ break;
+ case 1:
+ Msg(0, "Lines joined");
+ break;
+ case 2:
+ Msg(0, "Lines joined with blanks");
+ break;
+ }
+ break;
+ case '/':
+ Search(1);
+ in_mark = 0;
+ break;
+ case '?':
+ Search(-1);
+ in_mark = 0;
+ break;
+ case 'n':
+ Search(0);
+ break;
+ case 'y':
+ case 'Y':
+ if (markdata->second == 0)
+ {
+ revto(linestart(cy), cy);
+ markdata->second++;
+ cx = markdata->x1 = markdata->cx;
+ cy = markdata->y1 = markdata->cy;
+ }
+ if (--rep_cnt > 0)
+ revto(cx, cy + rep_cnt);
+ revto(lineend(markdata->cy), markdata->cy);
+ if (od == 'y')
+ break;
+ /* FALLTHROUGH */
+ case 'W':
+ if (od == 'W')
+ {
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ if (!markdata->second)
+ {
+ nextword(&cx, &cy, NW_BACK|NW_ENDOFWORD, 1);
+ revto(cx, cy);
+ markdata->second++;
+ cx = markdata->x1 = markdata->cx;
+ cy = markdata->y1 = markdata->cy;
+ }
+ nextword(&cx, &cy, NW_ENDOFWORD, rep_cnt);
+ revto(cx, cy);
+ }
+ cx = markdata->cx;
+ cy = markdata->cy;
+ /* FALLTHROUGH */
+ case 'A':
+ if (od == 'A')
+ markdata->append_mode = 1;
+ /* FALLTHROUGH */
+ case '>':
+ if (od == '>')
+ markdata->write_buffer = 1;
+ /* FALLTHROUGH */
+ case ' ':
+ case '\r':
+ if (!markdata->second)
+ {
+ markdata->second++;
+ markdata->x1 = cx;
+ markdata->y1 = cy;
+ revto(cx, cy);
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You drop a magic marker - Column %d Line %d",
+ cx+1, W2D(cy)+1);
+ else
+#endif
+ Msg(0, "First mark set - Column %d Line %d", cx+1, W2D(cy)+1);
+ break;
+ }
+ else
+ {
+ int append_mode = markdata->append_mode;
+ int write_buffer = markdata->write_buffer;
+
+ x2 = cx;
+ y2 = cy;
+ newcopylen = rem(markdata->x1, markdata->y1, x2, y2, 2, (char *)0, 0); /* count */
+ if (D_user->u_copybuffer != NULL && !append_mode)
+ UserFreeCopyBuffer(D_user);
+ if (newcopylen > 0)
+ {
+ /* the +3 below is for : cr + lf + \0 */
+ if (D_user->u_copybuffer != NULL)
+ D_user->u_copybuffer = realloc(D_user->u_copybuffer,
+ (unsigned) (D_user->u_copylen + newcopylen + 3));
+ else
+ {
+ D_user->u_copylen = 0;
+ D_user->u_copybuffer = malloc((unsigned) (newcopylen + 3));
+ }
+ if (D_user->u_copybuffer == NULL)
+ {
+ MarkAbort();
+ in_mark = 0;
+ Msg(0, "Not enough memory... Sorry.");
+ D_user->u_copylen = 0;
+ D_user->u_copybuffer = NULL;
+ break;
+ }
+ if (append_mode)
+ {
+ switch (markdata->nonl)
+ {
+ /*
+ * this code defines, what glues lines together
+ */
+ case 0:
+ if (join_with_cr)
+ {
+ D_user->u_copybuffer[D_user->u_copylen] = '\r';
+ D_user->u_copylen++;
+ }
+ D_user->u_copybuffer[D_user->u_copylen] = '\n';
+ D_user->u_copylen++;
+ break;
+ case 1:
+ break;
+ case 2:
+ D_user->u_copybuffer[D_user->u_copylen] = ' ';
+ D_user->u_copylen++;
+ break;
+ }
+ }
+ yend = D_height - 1;
+ if (fore->w_histheight - markdata->hist_offset < D_height)
+ {
+ markdata->second = 0;
+ yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
+ }
+ D_user->u_copylen += rem(markdata->x1, markdata->y1, x2, y2,
+ markdata->hist_offset == fore->w_histheight,
+ D_user->u_copybuffer + D_user->u_copylen, yend);
+ }
+ if (markdata->hist_offset != fore->w_histheight)
+ LAY_CALL_UP(Activate(0));
+ ExitOverlayPage();
+ if (append_mode)
+ Msg(0, "Appended %d characters to buffer",
+ newcopylen);
+ else
+ Msg(0, "Copied %d characters into buffer", D_user->u_copylen);
+ if (write_buffer)
+ WriteFile(DUMP_EXCHANGE);
+ in_mark = 0;
+ break;
+ }
+ default:
+ MarkAbort();
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You escaped the dungeon.");
+ else
+#endif
+ Msg(0, "Copy mode aborted");
+ in_mark = 0;
+ break;
+ }
+ if (in_mark) /* markdata may be freed */
+ markdata->rep_cnt = 0;
+ }
+ *inbufp = pt;
+ *inlenp = inlen;
+}
+
+void revto(tx, ty)
+int tx, ty;
+{
+ revto_line(tx, ty, -1);
+}
+
+/* tx, ty: WINDOW, line: DISPLAY */
+void revto_line(tx, ty, line)
+int tx, ty, line;
+{
+ int fx, fy;
+ int x, y, t, revst, reven, qq, ff, tt, st, en, ce = 0;
+ int ystart = 0, yend = D_height-1;
+ int i, ry;
+ char *wi;
+ struct mline *ml;
+ struct mchar mchar_marked;
+
+ mchar_marked = mchar_so;
+
+ if (tx < 0)
+ tx = 0;
+ else if (tx > D_width - 1)
+ tx = D_width -1;
+ if (ty < 0)
+ ty = 0;
+ else if (ty > fore->w_histheight + D_height - 1)
+ ty = fore->w_histheight + D_height - 1;
+
+ fx = markdata->cx; fy = markdata->cy;
+ markdata->cx = tx; markdata->cy = ty;
+
+ /*
+ * if we go to a position that is currently offscreen
+ * then scroll the screen
+ */
+ i = 0;
+ if (line >= 0 && line < D_height)
+ i = W2D(ty) - line;
+ else if (ty < markdata->hist_offset)
+ i = ty - markdata->hist_offset;
+ else if (ty > markdata->hist_offset + (D_height - 1))
+ i = ty - markdata->hist_offset - (D_height - 1);
+ if (i > 0)
+ yend -= MarkScrollUpDisplay(i);
+ else if (i < 0)
+ ystart += MarkScrollDownDisplay(-i);
+
+ if (markdata->second == 0)
+ {
+ GotoPos(tx, W2D(ty));
+ return;
+ }
+
+ qq = markdata->x1 + markdata->y1 * D_width;
+ ff = fx + fy * D_width; /* "from" offset in WIN coords */
+ tt = tx + ty * D_width; /* "to" offset in WIN coords*/
+
+ if (ff > tt)
+ {
+ st = tt; en = ff;
+ x = tx; y = ty;
+ }
+ else
+ {
+ st = ff; en = tt;
+ x = fx; y = fy;
+ }
+ if (st > qq)
+ {
+ st++;
+ x++;
+ }
+ if (en < qq)
+ en--;
+ if (tt > qq)
+ {
+ revst = qq; reven = tt;
+ }
+ else
+ {
+ revst = tt; reven = qq;
+ }
+ ry = y - markdata->hist_offset;
+ if (ry < ystart)
+ {
+ y += (ystart - ry);
+ x = 0;
+ st = y * D_width;
+ ry = ystart;
+ }
+ ml = WIN(y);
+ for (t = st; t <= en; t++, x++)
+ {
+ if (x >= D_width)
+ {
+ x = 0;
+ y++, ry++;
+ ml = WIN(y);
+ }
+ if (ry > yend)
+ break;
+ if (t == st || x == 0)
+ {
+ wi = ml->image + D_width;
+ for (ce = D_width; ce >= 0; ce--, wi--)
+ if (*wi != ' ')
+ break;
+ }
+ if (x <= ce && x >= markdata->left_mar && x <= markdata->right_mar
+ && (D_CLP || x < D_width-1 || ry < D_bot))
+ {
+#ifdef KANJI
+ if (badkanji(ml->font, x))
+ {
+ t--;
+ x--;
+ }
+#endif
+ GotoPos(x, W2D(y));
+#ifdef KANJI
+ if (t >= revst - (ml->font[x] == KANJI) && t <= reven)
+#else
+ if (t >= revst && t <= reven)
+#endif
+ {
+ if (pastefont)
+ mchar_marked.font = ml->font[x];
+ SetRendition(&mchar_marked);
+ }
+ else
+ SetRenditionMline(ml, x);
+ PUTCHARLP(ml->image[x]);
+#ifdef KANJI
+ if (ml->font[x] == KANJI)
+ {
+ PUTCHARLP(ml->image[++x]);
+ t++;
+ }
+#endif
+ }
+ }
+ GotoPos(tx, W2D(ty));
+}
+
+static void
+MarkAbort()
+{
+ int yend, redisp;
+
+ debug("MarkAbort\n");
+ markdata = (struct markdata *)D_lay->l_data;
+ fore = D_fore;
+ yend = D_height - 1;
+ redisp = markdata->second;
+ if (fore->w_histheight - markdata->hist_offset < D_height)
+ {
+ markdata->second = 0;
+ yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
+ }
+ if (markdata->hist_offset != fore->w_histheight)
+ {
+ LAY_CALL_UP(Activate(0));
+ }
+ else
+ {
+ rem(markdata->x1, markdata->y1, markdata->cx, markdata->cy, redisp, (char *)0, yend);
+ }
+ ExitOverlayPage();
+}
+
+
+static void
+MarkRedisplayLine(y, xs, xe, isblank)
+int y; /* NOTE: y is in DISPLAY coords system! */
+int xs, xe;
+int isblank;
+{
+ int wy, x, i, rm;
+ int sta, sto, cp; /* NOTE: these 3 are in WINDOW coords system */
+ char *wi;
+ struct mline *oml, *ml;
+ struct mchar mchar_marked;
+
+ if (y < 0) /* No special full page handling */
+ return;
+
+ markdata = (struct markdata *)D_lay->l_data;
+ fore = D_fore;
+
+ mchar_marked = mchar_so;
+
+
+ oml = isblank ? &mline_blank : &mline_null;
+ wy = D2W(y);
+ ml = WIN(wy);
+
+ if (markdata->second == 0)
+ {
+ DisplayLine(oml, ml, y, xs, xe);
+ return;
+ }
+
+
+ sta = markdata->y1 * D_width + markdata->x1;
+ sto = markdata->cy * D_width + markdata->cx;
+ if (sta > sto)
+ {
+ i=sta; sta=sto; sto=i;
+ }
+ cp = wy * D_width + xs;
+
+ rm = markdata->right_mar;
+ for (x = D_width, wi = ml->image + D_width; x >= 0; x--, wi--)
+ if (*wi != ' ')
+ break;
+ if (x < rm)
+ rm = x;
+
+ for (x = xs; x <= xe; x++, cp++)
+ if (cp >= sta && x >= markdata->left_mar)
+ break;
+#ifdef KANJI
+ if (badkanji(ml->font, x))
+ x--;
+#endif
+ if (x > xs)
+ DisplayLine(oml, ml, y, xs, x - 1);
+ for (; x <= xe; x++, cp++)
+ {
+ if (cp > sto || x > rm || (!D_CLP && x >= D_width-1 && y == D_bot))
+ break;
+ if (pastefont)
+ mchar_marked.font = ml->font[x];
+ GotoPos(x, y);
+ SetRendition(&mchar_marked);
+ PUTCHARLP(ml->image[x]);
+#ifdef KANJI
+ if (ml->font[x] == KANJI)
+ {
+ PUTCHARLP(ml->image[++x]);
+ cp++;
+ }
+#endif
+ }
+ if (x <= xe)
+ DisplayLine(oml, ml, y, x, xe);
+}
+
+
+/*
+ * This ugly routine is to speed up GotoPos()
+ */
+static int
+MarkRewrite(ry, xs, xe, doit)
+int ry, xs, xe, doit;
+{
+ int dx, x, y, st, en, t, rm;
+ char *i;
+ struct mline *ml;
+ struct mchar mchar_marked;
+
+ mchar_marked = mchar_so;
+
+ markdata = (struct markdata *)D_lay->l_data;
+ fore = D_fore;
+ y = D2W(ry);
+ ml = WIN(y);
+ dx = xe - xs;
+ if (doit)
+ {
+ i = ml->image + xs;
+ while (dx--)
+ PUTCHARLP(*i++);
+ return 0;
+ }
+
+ if (markdata->second == 0)
+ st = en = -1;
+ else
+ {
+ st = markdata->y1 * D_width + markdata->x1;
+ en = markdata->cy * D_width + markdata->cx;
+ if (st > en)
+ {
+ t = st; st = en; en = t;
+ }
+ }
+ t = y * D_width + xs;
+ for (rm = D_width, i = ml->image + D_width; rm >= 0; rm--)
+ if (*i-- != ' ')
+ break;
+ if (rm > markdata->right_mar)
+ rm = markdata->right_mar;
+ x = xs;
+ while (dx--)
+ {
+ if (t >= st && t <= en && x >= markdata->left_mar && x <= rm)
+ {
+ if (pastefont)
+ mchar_marked.font = ml->font[x];
+ if (!cmp_mchar(&D_rend, &mchar_marked))
+ return EXPENSIVE;
+ }
+ else
+ {
+ if (!cmp_mchar_mline(&D_rend, ml, x))
+ return EXPENSIVE;
+ }
+ x++;
+ }
+ return xe - xs;
+}
+
+
+/*
+ * scroll the screen contents up/down.
+ */
+static int MarkScrollUpDisplay(n)
+int n;
+{
+ int i;
+
+ debug1("MarkScrollUpDisplay(%d)\n", n);
+ if (n <= 0)
+ return 0;
+ if (n > fore->w_histheight - markdata->hist_offset)
+ n = fore->w_histheight - markdata->hist_offset;
+ i = (n < D_height) ? n : (D_height);
+ ScrollV(0, 0, D_width - 1, D_height - 1, i);
+ markdata->hist_offset += n;
+ while (i-- > 0)
+ MarkRedisplayLine(D_height - i - 1, 0, D_width - 1, 1);
+ return n;
+}
+
+static int
+MarkScrollDownDisplay(n)
+int n;
+{
+ int i;
+
+ debug1("MarkScrollDownDisplay(%d)\n", n);
+ if (n <= 0)
+ return 0;
+ if (n > markdata->hist_offset)
+ n = markdata->hist_offset;
+ i = (n < D_height) ? n : (D_height);
+ ScrollV(0, 0, D_width - 1, D_height - 1, -i);
+ markdata->hist_offset -= n;
+ while (i-- > 0)
+ MarkRedisplayLine(i, 0, D_width - 1, 1);
+ return n;
+}
+
+int
+InMark()
+{
+ if (display && D_layfn->LayProcess == MarkProcess)
+ return 1;
+ return 0;
+}
+
+#endif /* COPY_PASTE */
diff --git a/mark.h b/mark.h
new file mode 100644
index 0000000..5117569
--- /dev/null
+++ b/mark.h
@@ -0,0 +1,47 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ * $Id: mark.h,v 1.1.1.1 1993/06/16 23:51:13 jnweiger Exp $ FAU
+ */
+
+struct markdata
+{
+ int cx, cy; /* cursor Position in WIN coords*/
+ int x1, y1; /* first mark in WIN coords */
+ int second; /* first mark dropped flag */
+ int left_mar, right_mar, nonl;
+ int rep_cnt; /* number of repeats */
+ int append_mode; /* shall we overwrite or append to copybuffer */
+ int write_buffer; /* shall we do a KEY_WRITE_EXCHANGE right away? */
+ int hist_offset; /* how many lines are on top of the screen */
+ char isstr[100]; /* string we are searching for */
+ int isstrl;
+ char isistr[200]; /* string of chars user has typed */
+ int isistrl;
+ int isdir; /* current search direction */
+ int isstartpos; /* position where isearch was started */
+ int isstartdir; /* direction when isearch was started */
+};
+
+
+#define W2D(y) ((y) - markdata->hist_offset)
+#define D2W(y) ((y) + markdata->hist_offset)
+
diff --git a/misc.c b/misc.c
new file mode 100644
index 0000000..0adfe19
--- /dev/null
+++ b/misc.c
@@ -0,0 +1,468 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: misc.c,v 1.5 1994/05/31 12:32:19 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+#include <signal.h>
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+
+#ifdef SVR4
+# include <sys/resource.h>
+#endif
+
+extern struct display *display;
+extern int eff_uid, real_uid;
+extern int eff_gid, real_gid;
+extern struct mline mline_old;
+extern char *null, *blank;
+
+char *
+SaveStr(str)
+register const char *str;
+{
+ register char *cp;
+
+ if ((cp = malloc(strlen(str) + 1)) == NULL)
+ Panic(0, strnomem);
+ else
+ strcpy(cp, str);
+ return cp;
+}
+
+#ifndef HAVE_STRERROR
+char *
+strerror(err)
+int err;
+{
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+
+ static char er[20];
+ if (err > 0 && err < sys_nerr)
+ return sys_errlist[err];
+ sprintf(er, "Error %d", err);
+ return er;
+}
+#endif
+
+void
+centerline(str)
+char *str;
+{
+ int l, n;
+
+ ASSERT(display);
+ n = strlen(str);
+ if (n > D_width - 1)
+ n = D_width - 1;
+ l = (D_width - 1 - n) / 2;
+ if (l > 0)
+ AddStrn("", l);
+ AddStrn(str, n);
+ AddStr("\r\n");
+}
+
+char *
+Filename(s)
+char *s;
+{
+ register char *p = s;
+
+ if (p)
+ while (*p)
+ if (*p++ == '/')
+ s = p;
+ return s;
+}
+
+char *
+stripdev(nam)
+char *nam;
+{
+#ifdef apollo
+ char *p;
+
+ if (nam == NULL)
+ return NULL;
+ if (p = strstr(nam,"/dev/"))
+ return p + 5;
+#else /* apollo */
+ if (nam == NULL)
+ return NULL;
+# ifdef SVR4
+ /* unixware has /dev/pts012 as synonym for /dev/pts/12 */
+ if (!strncmp(nam, "/dev/pts", 8) && nam[8] >= '0' && nam[8] <= '9')
+ {
+ static char b[13];
+ sprintf(b, "pts/%d", atoi(nam + 8));
+ return b;
+ }
+# endif /* SVR4 */
+ if (strncmp(nam, "/dev/", 5) == 0)
+ return nam + 5;
+#endif /* apollo */
+ return nam;
+}
+
+
+/*
+ * Signal handling
+ */
+
+#ifdef POSIX
+sigret_t (*xsignal(sig, func)) __P(SIGPROTOARG)
+int sig;
+sigret_t (*func) __P(SIGPROTOARG);
+{
+ struct sigaction osa, sa;
+ sa.sa_handler = func;
+ (void)sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ if (sigaction(sig, &sa, &osa))
+ return (sigret_t (*)__P(SIGPROTOARG))-1;
+ return osa.sa_handler;
+}
+
+#else
+# ifdef hpux
+/*
+ * hpux has berkeley signal semantics if we use sigvector,
+ * but not, if we use signal, so we define our own signal() routine.
+ */
+void (*xsignal(sig, func)) __P(SIGPROTOARG)
+int sig;
+void (*func) __P(SIGPROTOARG);
+{
+ struct sigvec osv, sv;
+
+ sv.sv_handler = func;
+ sv.sv_mask = sigmask(sig);
+ sv.sv_flags = SV_BSDSIG;
+ if (sigvector(sig, &sv, &osv) < 0)
+ return (void (*)__P(SIGPROTOARG))(BADSIG);
+ return osv.sv_handler;
+}
+# endif /* hpux */
+#endif /* POSIX */
+
+
+/*
+ * uid/gid handling
+ */
+
+#ifdef HAVE_SETEUID
+
+void
+xseteuid(euid)
+int euid;
+{
+ if (seteuid(euid) == 0)
+ return;
+ seteuid(0);
+ if (seteuid(euid))
+ Panic(errno, "seteuid");
+}
+
+void
+xsetegid(egid)
+int egid;
+{
+ if (setegid(egid))
+ Panic(errno, "setegid");
+}
+
+#else
+# ifdef HAVE_SETREUID
+
+void
+xseteuid(euid)
+int euid;
+{
+ int oeuid;
+
+ oeuid = geteuid();
+ if (oeuid == euid)
+ return;
+ if (getuid() != euid)
+ oeuid = getuid();
+ if (setreuid(oeuid, euid))
+ Panic(errno, "setreuid");
+}
+
+void
+xsetegid(egid)
+int egid;
+{
+ int oegid;
+
+ oegid = getegid();
+ if (oegid == egid)
+ return;
+ if (getgid() != egid)
+ oegid = getgid();
+ if (setregid(oegid, egid))
+ Panic(errno, "setregid");
+}
+
+# endif
+#endif
+
+
+
+#ifdef NEED_OWN_BCOPY
+void
+xbcopy(s1, s2, len)
+register char *s1, *s2;
+register int len;
+{
+ if (s1 < s2 && s2 < s1 + len)
+ {
+ s1 += len;
+ s2 += len;
+ while (len-- > 0)
+ *--s2 = *--s1;
+ }
+ else
+ while (len-- > 0)
+ *s2++ = *s1++;
+}
+#endif /* NEED_OWN_BCOPY */
+
+void
+bclear(p, n)
+char *p;
+int n;
+{
+ bcopy(blank, p, n);
+}
+
+
+void
+Kill(pid, sig)
+int pid, sig;
+{
+ if (pid < 2)
+ return;
+ (void) kill(pid, sig);
+}
+
+void
+closeallfiles(except)
+int except;
+{
+ int f;
+#ifdef SVR4
+ struct rlimit rl;
+
+ if ((getrlimit(RLIMIT_NOFILE, &rl) == 0) && rl.rlim_max != RLIM_INFINITY)
+ f = rl.rlim_max;
+ else
+#endif /* SVR4 */
+#if defined(SYSV) && !defined(ISC)
+ f = NOFILE;
+#else /* SYSV && !ISC */
+ f = getdtablesize();
+#endif /* SYSV && !ISC */
+ while (--f > 2)
+ if (f != except)
+ close(f);
+}
+
+
+
+/*
+ * Security - switch to real uid
+ */
+
+#ifndef USE_SETEUID
+static int UserPID;
+static sigret_t (*Usersigcld)__P(SIGPROTOARG);
+#endif
+static int UserSTAT;
+
+int
+UserContext()
+{
+#ifndef USE_SETEUID
+ if (eff_uid == real_uid && eff_gid == real_gid)
+ return 1;
+ Usersigcld = signal(SIGCHLD, SIG_DFL);
+ debug("UserContext: forking.\n");
+ switch (UserPID = fork())
+ {
+ case -1:
+ Msg(errno, "fork");
+ return -1;
+ case 0:
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+# ifdef BSDJOBS
+ signal(SIGTTIN, SIG_DFL);
+ signal(SIGTTOU, SIG_DFL);
+# endif
+ setuid(real_uid);
+ setgid(real_gid);
+ return 1;
+ default:
+ return 0;
+ }
+#else
+ xseteuid(real_uid);
+ xsetegid(real_gid);
+ return 1;
+#endif
+}
+
+void
+UserReturn(val)
+int val;
+{
+#ifndef USE_SETEUID
+ if (eff_uid == real_uid && eff_gid == real_gid)
+ UserSTAT = val;
+ else
+ _exit(val);
+#else
+ xseteuid(eff_uid);
+ xsetegid(eff_gid);
+ UserSTAT = val;
+#endif
+}
+
+int
+UserStatus()
+{
+#ifndef USE_SETEUID
+ int i;
+# ifdef BSDWAIT
+ union wait wstat;
+# else
+ int wstat;
+# endif
+
+ if (eff_uid == real_uid && eff_gid == real_gid)
+ return UserSTAT;
+ if (UserPID < 0)
+ return -1;
+ while ((errno = 0, i = wait(&wstat)) != UserPID)
+ if (i < 0 && errno != EINTR)
+ break;
+ (void) signal(SIGCHLD, Usersigcld);
+ if (i == -1)
+ return -1;
+ return WEXITSTATUS(wstat);
+#else
+ return UserSTAT;
+#endif
+}
+
+#ifdef NEED_RENAME
+int
+rename (old, new)
+char *old;
+char *new;
+{
+ if (link(old, new) < 0)
+ return -1;
+ return unlink(old);
+}
+#endif
+
+
+int
+AddXChar(buf, ch)
+char *buf;
+int ch;
+{
+ char *p = buf;
+
+ if (ch < ' ' || ch == 0x7f)
+ {
+ *p++ = '^';
+ *p++ = ch ^ 0x40;
+ }
+ else if (ch >= 0x80)
+ {
+ *p++ = '\\';
+ *p++ = (ch >> 6 & 7) + '0';
+ *p++ = (ch >> 3 & 7) + '0';
+ *p++ = (ch >> 0 & 7) + '0';
+ }
+ else
+ *p++ = ch;
+ return p - buf;
+}
+
+int
+AddXChars(buf, len, str)
+char *buf, *str;
+int len;
+{
+ char *p;
+
+ len -= 4; /* longest sequence produced by AddXChar() */
+ for (p = buf; p < buf + len && *str; str++)
+ {
+ if (*str == ' ')
+ *p++ = *str;
+ else
+ p += AddXChar(p, *str);
+ }
+ *p = 0;
+ return p - buf;
+}
+
+
+#ifdef TERMINFO
+/*
+ * This is a replacement for the buggy _delay function from the termcap
+ * emulation of libcurses, which ignores ospeed.
+ */
+int
+_delay(delay, outc)
+register int delay;
+int (*outc)();
+{
+ int pad;
+ extern short ospeed;
+ static short osp2pad[] = {
+ 0,2000,1333,909,743,666,500,333,166,83,55,41,20,10,5,2,1,1
+ };
+
+ if (ospeed <= 0 || ospeed >= sizeof(osp2pad)/sizeof(*osp2pad))
+ return 0;
+ pad =osp2pad[ospeed];
+ delay = (delay + pad / 2) / pad;
+ while (delay-- > 0)
+ (*outc)(0);
+ return 0;
+}
+#endif
+
diff --git a/os.h b/os.h
new file mode 100644
index 0000000..b77df51
--- /dev/null
+++ b/os.h
@@ -0,0 +1,480 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ * $Id: os.h,v 1.10 1994/05/31 12:32:22 mlschroe Exp $ FAU
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/param.h>
+
+
+#if defined(BSDI) || defined(__386BSD__) || defined(_CX_UX) || defined(hpux)
+# include <signal.h>
+#endif /* BSDI || __386BSD__ || _CX_UX */
+
+#ifdef ISC
+# ifdef ENAMETOOLONG
+# undef ENAMETOOLONG
+# endif
+# ifdef ENOTEMPTY
+# undef ENOTEMPTY
+# endif
+# include <sys/bsdtypes.h>
+# include <net/errno.h>
+#endif
+
+#ifdef sun
+# define getpgrp __getpgrp
+# define exit __exit
+#endif
+#ifdef POSIX
+# include <unistd.h>
+# if defined(__STDC__)
+# include <stdlib.h>
+# endif /* __STDC__ */
+#endif /* POSIX */
+#ifdef sun
+# undef getpgrp
+# undef exit
+#endif /* sun */
+
+#ifndef linux /* all done in <errno.h> */
+extern int errno;
+#endif /* linux */
+#ifndef HAVE_STRERROR
+/* No macros, please */
+#undef strerror
+#endif
+
+#ifndef SYSV
+# ifdef NEWSOS
+# define strlen ___strlen___
+# include <strings.h>
+# undef strlen
+# else /* NEWSOS */
+# include <strings.h>
+# endif /* NEWSOS */
+#else /* SYSV */
+# if defined(SVR4) || defined(NEWSOS)
+# define strlen ___strlen___
+# include <string.h>
+# undef strlen
+# ifndef NEWSOS
+ extern size_t strlen(const char *);
+# endif /* NEWSOS */
+# else /* SVR4 */
+# include <string.h>
+# endif /* SVR4 */
+#endif /* SYSV */
+
+#ifdef USEVARARGS
+# if defined(__STDC__)
+# include <stdarg.h>
+# else
+# include <varargs.h>
+# endif
+#endif
+
+#if !defined(sun) && !defined(B43) && !defined(ISC) && !defined(pyr) && !defined(_CX_UX)
+# include <time.h>
+#endif
+#include <sys/time.h>
+
+#if (defined(TIOCGWINSZ) || defined(TIOCSWINSZ)) && defined(M_UNIX)
+# include <sys/stream.h>
+# include <sys/ptem.h>
+#endif
+
+#ifdef SYSV
+# define index strchr
+# define rindex strrchr
+# define bzero(poi,len) memset(poi,0,len)
+# define bcmp memcmp
+# define killpg(pgrp,sig) kill( -(pgrp), sig)
+#else
+# define getcwd(b,l) getwd(b)
+#endif
+
+#ifndef USEBCOPY
+# ifdef USEMEMMOVE
+# define bcopy(s,d,len) memmove(d,s,len)
+# else
+# ifdef USEMEMCPY
+# define bcopy(s,d,len) memcpy(d,s,len)
+# else
+# define NEED_OWN_BCOPY
+# define bcopy xbcopy
+# endif
+# endif
+#endif
+
+#ifdef hpux
+# define setreuid(ruid, euid) setresuid(ruid, euid, -1)
+# define setregid(rgid, egid) setresgid(rgid, egid, -1)
+#endif
+
+#if defined(HAVE_SETEUID) || defined(HAVE_SETREUID)
+# define USE_SETEUID
+#endif
+
+#if !defined(HAVE__EXIT) && !defined(_exit)
+#define _exit(x) exit(x)
+#endif
+
+/*****************************************************************
+ * terminal handling
+ */
+
+#ifdef POSIX
+# include <termios.h>
+# ifdef hpux
+# include <bsdtty.h>
+# endif /* hpux */
+# ifdef NCCS
+# define MAXCC NCCS
+# else
+# define MAXCC 256
+# endif
+#else /* POSIX */
+# ifdef TERMIO
+# include <termio.h>
+# ifdef NCC
+# define MAXCC NCC
+# else
+# define MAXCC 256
+# endif
+# ifdef CYTERMIO
+# include <cytermio.h>
+# endif
+# else /* TERMIO */
+# include <sgtty.h>
+# endif /* TERMIO */
+#endif /* POSIX */
+
+#ifndef VDISABLE
+# ifdef _POSIX_VDISABLE
+# define VDISABLE _POSIX_VDISABLE
+# else
+# define VDISABLE 0377
+# endif /* _POSIX_VDISABLE */
+#endif /* !VDISABLE */
+
+
+/* on sgi, regardless of the stream head's read mode (RNORM/RMSGN/RMSGD)
+ * TIOCPKT mode causes data loss if our buffer is too small (IOSIZE)
+ * to hold the whole packet at first read().
+ * (Marc Boucher)
+ *
+ * matthew green:
+ * TIOCPKT is broken on dgux 5.4.1 generic AViiON mc88100
+ *
+ * Joe Traister: On AIX4, programs like irc won't work if screen
+ * uses TIOCPKT (select fails to return on pty read).
+ */
+#if defined(sgi) || defined(DGUX) || defined(_IBMR2)
+# undef TIOCPKT
+#endif
+
+
+/*****************************************************************
+ * utmp handling
+ */
+
+#ifdef GETUTENT
+ typedef char *slot_t;
+#else
+ typedef int slot_t;
+#endif
+
+#if defined(UTMPOK) || defined(BUGGYGETLOGIN)
+# if defined(SVR4) && !defined(DGUX)
+# include <utmpx.h>
+# define UTMPFILE UTMPX_FILE
+# define utmp utmpx
+# define getutent getutxent
+# define getutid getutxid
+# define getutline getutxline
+# define pututline pututxline
+# define setutent setutxent
+# define endutent endutxent
+# define ut_time ut_xtime
+# else /* SVR4 */
+# include <utmp.h>
+# endif /* SVR4 */
+# ifdef apollo
+ /*
+ * We don't have GETUTENT, so we dig into utmp ourselves.
+ * But we save the permanent filedescriptor and
+ * open utmp just when we need to.
+ * This code supports an unsorted utmp. jw.
+ */
+# define UTNOKEEP
+# endif /* apollo */
+# ifdef linux
+ /* pututline is useless so we do it ourself... */
+# define UT_UNSORTED
+# endif
+
+# ifndef UTMPFILE
+# ifdef UTMP_FILE
+# define UTMPFILE UTMP_FILE
+# else
+# ifdef _PATH_UTMP
+# define UTMPFILE _PATH_UTMP
+# else
+# define UTMPFILE "/etc/utmp"
+# endif /* _PATH_UTMP */
+# endif
+# endif
+
+#endif /* UTMPOK || BUGGYGETLOGIN */
+
+#if !defined(UTMPOK) && defined(USRLIMIT)
+# undef USRLIMIT
+#endif
+
+#ifdef LOGOUTOK
+# ifndef LOGINDEFAULT
+# define LOGINDEFAULT 0
+# endif
+#else
+# ifdef LOGINDEFAULT
+# undef LOGINDEFAULT
+# endif
+# define LOGINDEFAULT 1
+#endif
+
+
+/*****************************************************************
+ * file stuff
+ */
+
+#ifndef F_OK
+#define F_OK 0
+#endif
+#ifndef X_OK
+#define X_OK 1
+#endif
+#ifndef W_OK
+#define W_OK 2
+#endif
+#ifndef R_OK
+#define R_OK 4
+#endif
+
+#ifndef S_IFIFO
+#define S_IFIFO 0010000
+#endif
+#ifndef S_IREAD
+#define S_IREAD 0000400
+#endif
+#ifndef S_IWRITE
+#define S_IWRITE 0000200
+#endif
+#ifndef S_IEXEC
+#define S_IEXEC 0000100
+#endif
+
+#if defined(S_IFIFO) && defined(S_IFMT) && !defined(S_ISFIFO)
+#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
+#endif
+#if defined(S_IFSOCK) && defined(S_IFMT) && !defined(S_ISSOCK)
+#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
+#endif
+#if defined(S_IFCHR) && defined(S_IFMT) && !defined(S_ISCHR)
+#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
+#endif
+#if defined(S_IFDIR) && defined(S_IFMT) && !defined(S_ISDIR)
+#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+
+/*
+ * SunOS 4.1.3: `man 2V open' has only one line that mentions O_NOBLOCK:
+ *
+ * O_NONBLOCK Same as O_NDELAY above.
+ *
+ * on the very same SunOS 4.1.3, I traced the open system call and found
+ * that an open("/dev/ttyy08", O_RDWR|O_NONBLOCK|O_NOCTTY) was blocked,
+ * whereas open("/dev/ttyy08", O_RDWR|O_NDELAY |O_NOCTTY) went through.
+ *
+ * For this simple reason I now favour O_NDELAY. jw. 4.5.95
+ */
+#if defined(sun) && !defined(SVR4)
+# undef O_NONBLOCK
+#endif
+
+#if !defined(O_NONBLOCK) && defined(O_NDELAY)
+# define O_NONBLOCK O_NDELAY
+#endif
+
+#if !defined(FNBLOCK) && defined(FNONBLOCK)
+# define FNBLOCK FNONBLOCK
+#endif
+#if !defined(FNBLOCK) && defined(FNDELAY)
+# define FNBLOCK FNDELAY
+#endif
+#if !defined(FNBLOCK) && defined(O_NONBLOCK)
+# define FNBLOCK O_NONBLOCK
+#endif
+
+#ifndef POSIX
+#undef mkfifo
+#define mkfifo(n,m) mknod(n,S_IFIFO|(m),0)
+#endif
+
+#if !defined(HAVE_LSTAT) && !defined(lstat)
+# define lstat stat
+#endif
+
+/*****************************************************************
+ * signal handling
+ */
+
+#ifdef SIGVOID
+# define SIGRETURN
+# define sigret_t void
+#else
+# define SIGRETURN return 0;
+# define sigret_t int
+#endif
+
+/* Geeeee, reverse it? */
+#if defined(SVR4) || (defined(SYSV) && defined(ISC)) || defined(_AIX) || defined(linux) || defined(ultrix) || defined(__386BSD__) || defined(BSDI) || defined(POSIX) || defined(NeXT)
+# define SIGHASARG
+#endif
+
+#ifdef SIGHASARG
+# define SIGPROTOARG (int)
+# define SIGDEFARG (sigsig) int sigsig;
+# define SIGARG 0
+#else
+# define SIGPROTOARG (void)
+# define SIGDEFARG ()
+# define SIGARG
+#endif
+
+#ifndef SIGCHLD
+#define SIGCHLD SIGCLD
+#endif
+
+#if defined(POSIX) || defined(hpux)
+# define signal xsignal
+#else
+# ifdef USESIGSET
+# define signal sigset
+# endif /* USESIGSET */
+#endif
+
+/* used in screen.c and attacher.c */
+#ifndef NSIG /* kbeal needs these w/o SYSV */
+# define NSIG 32
+#endif /* !NSIG */
+
+
+/*****************************************************************
+ * Wait stuff
+ */
+
+#if (!defined(sysV68) && !defined(M_XENIX)) || defined(NeXT)
+# include <sys/wait.h>
+#endif
+
+#ifndef WTERMSIG
+# ifndef BSDWAIT /* if wait is NOT a union: */
+# define WTERMSIG(status) (status & 0177)
+# else
+# define WTERMSIG(status) status.w_T.w_Termsig
+# endif
+#endif
+
+#ifndef WSTOPSIG
+# ifndef BSDWAIT /* if wait is NOT a union: */
+# define WSTOPSIG(status) ((status >> 8) & 0377)
+# else
+# define WSTOPSIG(status) status.w_S.w_Stopsig
+# endif
+#endif
+
+/* NET-2 uses WCOREDUMP */
+#if defined(WCOREDUMP) && !defined(WIFCORESIG)
+# define WIFCORESIG(status) WCOREDUMP(status)
+#endif
+
+#ifndef WIFCORESIG
+# ifndef BSDWAIT /* if wait is NOT a union: */
+# define WIFCORESIG(status) (status & 0200)
+# else
+# define WIFCORESIG(status) status.w_T.w_Coredump
+# endif
+#endif
+
+#ifndef WEXITSTATUS
+# ifndef BSDWAIT /* if wait is NOT a union: */
+# define WEXITSTATUS(status) ((status >> 8) & 0377)
+# else
+# define WEXITSTATUS(status) status.w_T.w_Retcode
+# endif
+#endif
+
+
+/*****************************************************************
+ * select stuff
+ */
+
+#if defined(M_XENIX) || defined(M_UNIX) || defined(_SEQUENT_)
+#include <sys/select.h> /* for timeval + FD... */
+#endif
+
+/*
+ * SunOS 3.5 - Tom Schmidt - Micron Semiconductor, Inc - 27-Jul-93
+ * tschmidt@vax.micron.com
+ */
+#ifndef FD_SET
+# ifndef SUNOS3
+typedef struct fd_set { int fds_bits[1]; } fd_set;
+# endif
+# define FD_ZERO(fd) ((fd)->fds_bits[0] = 0)
+# define FD_SET(b, fd) ((fd)->fds_bits[0] |= 1 << (b))
+# define FD_ISSET(b, fd) ((fd)->fds_bits[0] & 1 << (b))
+# define FD_SETSIZE 32
+#endif
+
+
+/*****************************************************************
+ * user defineable stuff
+ */
+
+#ifndef TERMCAP_BUFSIZE
+# define TERMCAP_BUFSIZE 2048
+#endif
+
+#ifndef MAXPATHLEN
+# define MAXPATHLEN 1024
+#endif
+
+/*
+ * you may try to vary this value. Use low values if your (VMS) system
+ * tends to choke when pasting. Use high values if you want to test
+ * how many characters your pty's can buffer.
+ */
+#define IOSIZE 4096
+
diff --git a/osdef.h.in b/osdef.h.in
new file mode 100644
index 0000000..d28a401
--- /dev/null
+++ b/osdef.h.in
@@ -0,0 +1,182 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************
+ * $Id: osdef.h.in,v 1.2 1994/05/31 12:32:25 mlschroe Exp $ FAU
+ */
+
+/****************************************************************
+ * Thanks to Christos S. Zoulas (christos@ee.cornell.edu) who
+ * mangled the screen source through 'gcc -Wall'.
+ ****************************************************************
+ */
+
+extern int printf __P((char *, ...));
+extern int fprintf __P((FILE *, char *, ...));
+extern int sprintf __P((char *, char *, ...));
+#if defined(sun) || defined(_SEQUENT_)
+extern int _flsbuf __P((int, FILE *));
+#endif
+#ifdef SYSV
+extern char *strchr __P((char *, int));
+extern char *strrchr __P((char *, int));
+extern char *memset __P((char *, int, int));
+extern int memcmp __P((char *, char *, int));
+#else
+extern char *index __P((char *, int));
+extern char *rindex __P((char *, int));
+extern void bzero __P((char *, int));
+extern int bcmp __P((char *, char *, int));
+extern int killpg __P((int, int));
+#endif
+
+#ifndef USEBCOPY
+# ifdef USEMEMCPY
+extern void memcpy __P((char *, char *, int));
+# else
+# ifdef USEMEMMOVE
+extern void memmove __P((char *, char *, int));
+# else
+extern void bcopy __P((char *, char *, int));
+# endif
+# endif
+#else
+extern void bcopy __P((char *, char *, int));
+#endif
+
+#ifdef BSDWAIT
+struct rusage; /* for wait3 __P */
+union wait; /* for wait3 __P */
+extern int wait3 __P((union wait *, int, struct rusage *));
+#else
+extern int waitpid __P((int, int *, int));
+#endif
+
+extern int getdtablesize __P((void));
+
+#ifdef HAVE_SETREUID
+# ifdef hpux
+extern int setresuid __P((int, int, int));
+extern int setresgid __P((int, int, int));
+# else
+extern int setreuid __P((int, int));
+extern int setregid __P((int, int));
+# endif
+#endif
+#ifdef HAVE_SETEUID
+extern int seteuid __P((int));
+extern int setegid __P((int));
+#endif
+
+extern char *crypt __P((char *, char *));
+extern int putenv __P((char *));
+
+extern int tgetent __P((char *, char *));
+extern int tgetnum __P((char *));
+extern int tgetflag __P((char *));
+extern void tputs __P((char *, int, void (*)(int)));
+extern char *tgoto __P((char *, int, int));
+
+#ifdef POSIX
+extern int setsid __P((void));
+extern int setpgid __P((int, int));
+extern int tcsetpgrp __P((int, int));
+#endif
+extern int ioctl __P((int, int, char *));
+
+extern int kill __P((int, int));
+
+extern int getpid __P((void));
+extern int getuid __P((void));
+extern int geteuid __P((void));
+extern int getgid __P((void));
+extern int getegid __P((void));
+struct passwd; /* for getpwuid __P */
+extern struct passwd *getpwuid __P((int));
+extern struct passwd *getpwnam __P((char *));
+extern int isatty __P((int));
+extern int chown __P((char *, int, int));
+extern int rename __P((char *, char *));
+
+extern int gethostname __P((char *, int));
+extern int lseek __P((int, int, int));
+extern void exit __P((int));
+extern char *getwd __P((char *));
+extern char *getenv __P((char *));
+extern time_t time __P((time_t *));
+
+extern char *getpass __P((char *));
+extern char *getlogin __P((void));
+extern char *ttyname __P((int));
+
+extern int fputs __P((char *, FILE *));
+extern int fwrite __P((char *, int, int, FILE *));
+extern int fflush __P((FILE *));
+extern int fclose __P((FILE *));
+
+extern char *malloc __P((int));
+extern char *realloc __P((char *, int));
+extern void free __P((char *));
+
+#ifdef NAMEDPIPE
+extern int mknod __P((char *, int, int));
+#else
+struct sockaddr; /* for connect __P */
+extern int socket __P((int, int, int));
+extern int connect __P((int, struct sockaddr *, int));
+extern int bind __P((int, struct sockaddr *, int));
+extern int listen __P((int, int));
+extern int accept __P((int, struct sockaddr *, int *));
+#endif
+
+#if defined(UTMPOK) && defined(GETUTENT)
+extern void setutent __P((void));
+#endif
+
+#if defined(sequent) || defined(_SEQUENT_)
+extern int getpseudotty __P((char **, char **));
+#ifdef _SEQUENT_
+extern int fvhangup __P((char *));
+#endif
+#endif
+
+#ifdef USEVARARGS
+extern int vsprintf __P((char *, char *, va_list));
+#endif
+struct timeval; /* for select __P */
+extern int select __P((int, fd_set *, fd_set *, fd_set *, struct timeval *));
+
+extern void unsetenv __P((char *));
+
+# if defined(GETTTYENT) && !defined(GETUTENT) && !defined(UTNOKEEP)
+struct ttyent; /* for getttyent __P */
+extern void setttyent __P((void));
+extern struct ttyent *getttyent __P((void));
+# endif
+
+#ifdef SVR4
+struct rlimit; /* for getrlimit __P */
+extern int getrlimit __P((int, struct rlimit *));
+#endif
+
+struct stat;
+extern int stat __P((char *, struct stat *));
+extern int lstat __P((char *, struct stat *));
+extern int fstat __P((int, struct stat *));
+
diff --git a/osdef.sh b/osdef.sh
new file mode 100644
index 0000000..3ecc4d7
--- /dev/null
+++ b/osdef.sh
@@ -0,0 +1,46 @@
+#! /bin/sh
+
+if test -z "$CC"; then
+ CC=cc
+fi
+if test -z "$srcdir"; then
+ srcdir=.
+fi
+
+sed < $srcdir/osdef.h.in -n -e '/^extern/s@.*[)* ][)* ]*\([^ *]*\) __P.*@/[)*, ]\1[ (]/i\\\
+\\/\\[^a-zA-Z_\\]\1 __P\\/d@p' > osdef1.sed
+cat << EOF > osdef0.c
+#include "config.h"
+#include <sys/types.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#ifdef SHADOWPW
+#include <shadow.h>
+#endif
+#ifndef sun
+#include <sys/ioctl.h>
+#endif
+#ifndef NAMEDPIPE
+#include <sys/socket.h>
+#endif
+#include "os.h"
+#if defined(UTMPOK) && defined (GETTTYENT) && !defined(GETUTENT)
+#include <ttyent.h>
+#endif
+#ifdef SVR4
+# include <sys/resource.h>
+#endif
+EOF
+cat << EOF > osdef2.sed
+1i\\
+/*
+1i\\
+ * This file is automagically created from osdef.sh -- DO NOT EDIT
+1i\\
+ */
+EOF
+$CC -I. -I$srcdir -E osdef0.c | sed -n -f osdef1.sed >> osdef2.sed
+sed -f osdef2.sed < $srcdir/osdef.h.in > osdef.h
+rm osdef0.c osdef1.sed osdef2.sed
diff --git a/overlay.h b/overlay.h
new file mode 100644
index 0000000..62702b5
--- /dev/null
+++ b/overlay.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ * $Id: overlay.h,v 1.3 1994/05/31 12:32:31 mlschroe Exp $ FAU
+ */
+
+/*
+ * This is the overlay structure. It is used to create a seperate
+ * layer over the current windows.
+ */
+
+struct LayFuncs
+{
+ void (*LayProcess) __P((char **, int *));
+ void (*LayAbort) __P((void));
+ void (*LayRedisplayLine) __P((int, int, int, int));
+ void (*LayClearLine) __P((int, int, int));
+ int (*LayRewrite) __P((int, int, int, int));
+ void (*LaySetCursor) __P((void));
+ int (*LayResize) __P((int, int));
+ void (*LayRestore) __P((void));
+};
+
+struct layer
+{
+ struct layer *l_next;
+ int l_block;
+ struct LayFuncs *l_layfn;
+ char *l_data; /* should be void * */
+};
+
+#define Process (*D_layfn->LayProcess)
+#define Abort (*D_layfn->LayAbort)
+#define RedisplayLine (*D_layfn->LayRedisplayLine)
+#define ClearLine (*D_layfn->LayClearLine)
+#define Rewrite (*D_layfn->LayRewrite)
+#define SetCursor (*D_layfn->LaySetCursor)
+#define Resize (*D_layfn->LayResize)
+#define Restore (*D_layfn->LayRestore)
+
+#define LAY_CALL_UP(fn) \
+ { \
+ struct layer *oldlay = D_lay; \
+ D_lay = D_lay->l_next; \
+ D_layfn = D_lay->l_layfn; \
+ fn; \
+ D_lay = oldlay; \
+ D_layfn = D_lay->l_layfn; \
+ }
+
diff --git a/patchlevel.h b/patchlevel.h
new file mode 100644
index 0000000..e7bd579
--- /dev/null
+++ b/patchlevel.h
@@ -0,0 +1,237 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ * $Id: patchlevel.h,v 1.17 1994/05/31 12:32:35 mlschroe Exp $ FAU
+ */
+
+/****************************************************************
+ *
+ * patchlevel.h: Our life story.
+ *
+ * 08.07.91 -- 3.00.01 -wipe and a 'setenv TERM dumb' bugfix.
+ * 17.07.91 -- 3.00.02 another patchlevel by Wayne Davison
+ * 31.07.91 -- 3.00.03 E0, S0, C0 for flexible semi-graphics, nonblocking
+ * window title input and 'C-a :' command input.
+ * 10.08.91 -- 3.00.04 scrollback, markkeys and some bugfixes.
+ * 13.08.91 -- 3.00.05 mark routine improved, ansi prototypes added.
+ * 20.08.91 -- 3.00.06 screen -h, faster GotoPos in overlay, termcap %.
+ * instead of %c
+ * 28.08.91 -- 3.00.07 environment variable support. security. terminfo.
+ * pyramid and ultrix support.
+ * 07.09.91 -- 3.00.99 secopen(), MIPS support, SVR4 support.
+ * 09.09.91 -- 3.01.00 backspace bug fixed.
+ * 03.10.91 -- 3.01.01 ansi.c: null-ptr fixed, CLS now saves to scrollback.
+ * Using setresuid on hpux. Memory leak fixed.
+ * Better GotoPos(). Support for IC. Another resize bug.
+ * Detach() w/o fore crashed. -T and -A(dapt) option.
+ * GNU copyleft.
+ * 19.12.91 -- 3.01.02 flow now really automatic (autoflow killed).
+ * 7 bit restriction removed from WriteString().
+ * 09.01.92 -- 3.01.03 flow reattach bug fixed. VDISCARD bug fixed.
+ * 13.01.92 -- 3.01.04 new flow concept: ^Af toggles now three states
+ * 21.01.92 -- 3.01.05 '^A:screen 11' bug fixed. aflag in DoScreen().
+ * Some code cleanup. attach_tty and display_tty[]
+ * added.
+ * 26.01.92 -- 3.01.06 apollo support, "hardcopy_append on", "bufferfile",
+ * SECURITY PROBLEM cleared..
+ * 28.01.92 -- 3.01.07 screen after su allowed. Pid became part of
+ * SockName. sysvish 14 character restriction considered.
+ * 31.01.92 -- 3.02.00 Ultrix port, Irix 3.3 SGI port, shadow pw support,
+ * data loss on stdin overflow fixed. "refresh off".
+ * 12.02.92 -- 3.02.02 stripdev() moved, -S introduced, bufferfile improved,
+ * ShellProg coredump cleared. SVR4 bugfixes.
+ * I/O code speedup added.
+ * 24.04.92 -- 3.02.03 perfectly stackable overlays. One scrollback per window,
+ * not per display.
+ * 05.05.92 -- 3.02.04 very nasty initialisation bug fixed.
+ * 09.05.92 -- 3.02.05 parsing for $:cl: termcap strings and \012 octal notation
+ * in screenrc file. More structuring. Detached startup
+ * with 'screen -d -m -S...' bugfixed.
+ * 11.05.92 -- 3.02.06 setreuid() bugs cleared, C-a : setenv added.
+ * "xn" capability in TERMCAP needed since "am" is there.
+ * 25.06.92 -- 3.02.07 The multi display test version. Have merci.
+ * 15.07.92 -- 3.02.08 :B8: supports automatic charset switching for 8-bit
+ * 26.09.92 -- 3.02.09 Ported to linux. Ignoring bad files in $SCREENDIR
+ * 22.10.92 -- 3.02.10 screen.c/ansi.c splitted in several pieces.
+ * Better ISearch. Cleanup of loadav.c
+ * 29.10.92 -- 3.02.11 Key mechanism rewritten. New command names.
+ * New iscreenrc syntax.
+ * 02.11.92 -- 3.02.12 'bind g copy_reg' and 'bind x ins_reg' as suggested by
+ * stillson@tsfsrv.mitre.org (Ken Stillson).
+ * 03.11.92 -- 3.02.13 Ported to SunOs 4.1.2. Gulp. Some NULL ptrs fixed and
+ * misc. braindamage fixed.
+ * 03.11.92 -- 3.02.14 Argument number checking, AKA fixed.
+ * 05.11.92 -- 3.02.15 Memory leaks in Detach() and KillWindow() fixed.
+ * Lockprg powerdetaches on SIGHUP.
+ * 12.11.92 -- 3.02.16 Introduced two new termcaps: "CS" and "CE".
+ * (Switch cursorkeys in application mode)
+ * Tim's async output patch.
+ * Fixed an ugly bug in WriteString().
+ * New command: 'process'
+ * 16.11.92 -- 3.02.17 Nuking unsent tty output is now optional, (toxic
+ * ESC radiation).
+ * 30.11.92 -- 3.02.18 Lots of multi display bugs fixed. New layer
+ * function 'Restore'. MULTIUSER code cleanup.
+ * Rudimental acls added for multiuser.
+ * No more error output, when output gives write errors.
+ * 02.12.92 -- 3.02.19 BROKEN_PIPE and SOCK_NOT_IN_FS defines added for
+ * braindead systems. Bug in recover socket code fixed.
+ * Can create windows again from shell.
+ * 22.12.92 -- 3.02.20 Made a superb configure script. STY and break fixed.
+ * 01.02.93 -- 3.02.21 Coredump bug fixed: 8-bit output in background windows.
+ * Console grabbing somewhat more useable.
+ * 23.02.93 -- 3.02.22 Added ^:exec command, but not tested at all.
+ * 23.02.93 -- 3.02.23 Added 'hardcopydir' and 'logdir' commands.
+ * 11.03.93 -- 3.02.24 Prefixed display and window structure elements.
+ * Screen now handles autowrapped lines correctly
+ * in the redisplay and mark function.
+ * 19.03.93 -- 3.03.00 Patched for BSD386. pseudos work.
+ * 31.03.93 -- 3.03.01 Don't allocate so much empty attr and font lines.
+ * 04.04.93 -- 3.03.02 fixed :exec !..| less and :|less, patched BELL_DONE &
+ * ^B/^F. Fixed auto_nuke attribute resetting. Better linux
+ * configure. ^AW shows '&' when window has other attacher.
+ * MAXWIN > 10 patch. KEEP_UNDEF in config.h.in, shellaka
+ * bug fixed. dec alpha port. Solaris port.
+ * 02.05.93 -- 3.03.03 Configure tweaked for sgi. Update environment with
+ * setenv command. Silence on|off, silencewait <sec>,
+ * defautonuke commands added. Manual page updated.
+ * 13.05.93 -- 3.03.04 exit in newsyntax script, finished _CX_UX port.
+ * Texinfo page added by Jason Merrill. Much longish debug
+ * output removed. Select window by title (or number).
+ * 16.06.93 -- 3.04.00 Replaced ^A- by ^A^H to be complementary to ^A SPACE.
+ * Moved into CVS. Yacc.
+ * 28.06.93 -- 3.04.01 Fixed selecting windows with numeric title. Silence
+ * now works without nethackoption set.
+ * 01.07.93 -- 3.04.02 Implementing real acls.
+ * 22.07.93 -- 3.05.00 Fixed SVR4, some multiuser bugs, -- DISTRIBUTED
+ * 05.08.93 -- 3.05.01 ${srcdir} feature added. Shellprog bug fixed.
+ * Motorola reattach bug fixed. Writelock bug fixed.
+ * Copybuffer moved into struct user. Configure.in
+ * uglified for Autoconf1.5. Paste may now have an
+ * argument. Interactive setenv. Right margin bug
+ * fixed. IRIX 5 patches. -- DISTRIBUTED
+ * 13.08.93 -- 3.05.02 ultrix support added. expand_vars removed from
+ * register function. Paste bug fixed.
+ * sysmacros.h now included in pty.c on sgis
+ * Strange hpux hack added for TTYCMP.
+ * Zombie feature improved.
+ * 08.09.93 -- 3.05.03 Makefile and OSF1 fine tuning. Eased attach to
+ * multi sessions. Writelock now obeys acl write
+ * permissions. UserDel() now preserves defaults.
+ * acladd/aclchg syntax improved. Updated
+ * documentation. Bug in at command fixed.
+ * MakeWindow() now obeys perm defaults.
+ * 30.11.93 -- 3.05.04 Kanji support added. New keymap feature:
+ * bindkey and various map commands. GR and C1
+ * flags now define the character processing.
+ * 14.01.94 -- 3.05.05 New FindSocket() code. Nicer socket handling.
+ * 20.01.94 -- 3.05.06 New attribute handling code. NeXT fixes.
+ * 04.02.94 -- 3.05.07 Ugly bug in ScrollH fixed. Keymap defaults.
+ * 13.04.94 -- 3.05.08 Kanji bug fixed. POSIX sigaction support.
+ * os.h cleanup. UTNOKEEP splitted into
+ * UT_CLOSE and UT_UNSORTED. linux no longer
+ * implies UT_CLOSE. "struct display" name
+ * convention change: _d_ to d_ and d_ to D_.
+ * 20.04.94 -- 3.05.09 configure.in ptyrange bug fixed. Upgraded
+ * to autoconf-1.8
+ * 27.04.94 -- 3.05.10 97801 obscure code support. Linux long
+ * password workaround.
+ * 09.05.94 -- 3.05.11 seteuid() support added. Security fixes.
+ * _IBMR2 kludge makes call to sleep obsolete.
+ * Small fixes in uname() code.
+ * 27.07.94 -- 3.05.12 seteuid attacher bug fixed. ks/ke changed
+ * in termcap/info and termcap.c
+ * 27.09.94 -- 3.05.13 defwlock stupidity fixed. MakeTermcap ks/ke
+ * ':' removed. Termcap entry improved.
+ * 05.12.94 -- 3.05.17 SVR4 pty bug fixed, don't update window status
+ * line if not changed, onyx support. Manual
+ * pages updated.
+ * 14.12.94 -- 3.05.18 w_status changed to w_hstatus, it's a #define in
+ * Domain/OS reported by ejackson@iastate.edu.
+ * Screen manpage patches by larry.
+ * Ugly seteuid bug in ForkWindow() fixed.
+ * 20.12.94 -- 3.06.00 Solaris has broken seteuid().
+ * osf loadav patches. -- DISTRIBUTED
+ * 16.01.95 -- 3.06.01 KANJI patch. doc/Makefile.in fixed.
+ * Install now calls doc/Makefile install.
+ * Don't use 'ds' too often, breaks MSkermit.
+ * undef'd LOGOUTOK logs in now.
+ * Ultrix is broken, too (seteuid).
+ * Use \r (not \n) to join lines in pastebuf.
+ * bindkey can now remove sequences.
+ * InitTTY fixed for PLAIN. -- DISTRIBUTED
+ * 04.04.95 -- 3.06.02 Simple ESC-CR fix in the vt100 state machine.
+ * Now compiles again with all extras disabled.
+ * Zombie resurrect added. defc1, defgr, defkanji
+ * added. Screen now replies to a secondary DA
+ * query. Some missing NEED_XXX added in comm.c.
+ * Better default tty permissions/group test.
+ * More AUX support, now compiles with POSIX.
+ * Function keycodes xtermified (F11, F12).
+ * Paste bug fixed (only worked with KANJI).
+ * Check bcopy before memcpy/memmove.
+ * FindSocket code much fixed & improved.
+ * 31.08.95 -- 3.06.03 Color support, digraph command, code
+ * cleanup (struct mchar/mline added).
+ * 13.09.95 -- 3.06.04 SetRendition display check. Solaris unblock
+ * SIGHUP. w_curchar->w_rend, lintified.
+ * Shadow-password code moved and rewritten
+ * (includes sun C2).
+ * 26.09.95 -- 3.06.05 resize code completely rewritten.
+ * Very visible cursor added. vbell sequence
+ * \Eb added. _delay for terminfo libs added
+ * to make the padding work for the first time.
+ * New ProcessInput() makes "command command"
+ * work. '[def]escape ""' clears escape chars.
+ * Changed logdir command to logfile. It now uses
+ * MakeWinMsg() to create the filename.
+ * Updated the manuals.
+ * 28.10.95 -- 3.06.06 Added new 'XC' capability to provide
+ * a method for character translation.
+ * 17.11.95 -- 3.07.00 Added CheckEscape() function.
+ * acl -> acls because of hpux10 nameclash
+ * /stand/vmunix added to kernel list (hpux10)
+ * stripdev changed to translate
+ * /dev/pts<n> to /dev/pts/<n> (unixware)
+ * -lgen added to GETUTENT configure test.
+ * 20.11.95 -- 3.07.01 corrected vbell null ptr reference.
+ * -- DISTRIBUTED
+ * 1.09.96 -- 3.07.02 added #ifdef MAPKEYS for CheckEscape.
+ * etc/toolcheck is now shouting louder.
+ * Touching socket when detach/attach.
+ * Linux tcflush hack. Linux md5 password suport.
+ * USE_SGR support for dumb (wyse) terminals.
+ * "at" and "reset" commands improved.
+ * Now sensitive to broken AIX4 TIOCPKT.
+ * tek patch unapplied.
+ * linux utmp patch: set slot to DEAD_PROCESS.
+ * include signal.h for killpg if hpux10.10.
+ * linux: elf, but no SVR4, check for utmpx.
+ * hpux10.10 libcurses breaks select()!
+ * -- DISTRIBUTED
+ */
+
+#define ORIGIN "FAU"
+#define REV 3
+#define VERS 7
+#define PATCHLEVEL 2
+#define DATE "1-Sep-96"
+#define STATE ""
diff --git a/process.c b/process.c
new file mode 100644
index 0000000..92b9f9e
--- /dev/null
+++ b/process.c
@@ -0,0 +1,3777 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: process.c,v 1.27 1994/05/31 12:32:39 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <fcntl.h>
+#if !defined(sun) && !defined(B43) && !defined(ISC) && !defined(pyr) && !defined(_CX_UX)
+# include <time.h>
+#endif
+#include <sys/time.h>
+#ifndef sun
+#include <sys/ioctl.h>
+#endif
+
+
+#include "config.h"
+
+#ifdef SVR4
+# include <sys/stropts.h>
+#endif
+
+#include "screen.h"
+#include "extern.h"
+
+extern struct comm comms[];
+extern char *rc_name;
+extern char *RcFileName, *home;
+extern char *BellString, *ActivityString, *ShellProg, *ShellArgs[];
+extern char *hardcopydir, *screenlogfile;
+extern char *VisualBellString;
+extern int VBellWait, MsgWait, MsgMinWait, SilenceWait;
+extern char SockPath[], *SockName;
+extern int TtyMode, auto_detach;
+extern int iflag;
+extern int use_hardstatus, visual_bell;
+extern char *printcmd;
+extern int default_startup;
+extern int slowpaste, defobuflimit;
+extern int ZombieKey_destroy;
+extern int ZombieKey_resurrect;
+#ifdef AUTO_NUKE
+extern int defautonuke;
+#endif
+extern int intrc, origintrc; /* display? */
+extern struct NewWindow nwin_default, nwin_undef;
+#ifdef COPY_PASTE
+extern int join_with_cr, pastefont;
+extern char mark_key_tab[];
+extern char *BufferFile;
+#endif
+#ifdef POW_DETACH
+extern char *BufferFile, *PowDetachString;
+#endif
+extern time_t Now;
+#ifdef MAPKEYS
+extern struct term term[]; /* terminal capabilities */
+extern int maptimeout;
+extern char *kmapdef[];
+extern char *kmapadef[];
+extern char *kmapmdef[];
+#endif
+extern struct mchar mchar_so;
+
+
+static int CheckArgNum __P((int, char **));
+static void ClearAction __P((struct action *));
+static int NextWindow __P((void));
+static int PreviousWindow __P((void));
+static int MoreWindows __P((void));
+static void LogToggle __P((int));
+static void ShowTime __P((void));
+static void ShowInfo __P((void));
+static void SwitchWindow __P((int));
+static char **SaveArgs __P((char **));
+static struct win *WindowByName __P((char *));
+static int WindowByNumber __P((char *));
+static void DoAction __P((struct action *, int));
+static int ParseSwitch __P((struct action *, int *));
+static int ParseOnOff __P((struct action *, int *));
+static int ParseSaveStr __P((struct action *act, char **));
+static int ParseNum __P((struct action *act, int *));
+static int ParseWinNum __P((struct action *act, int *));
+static int ParseBase __P((struct action *act, char *, int *, int, char *));
+static char *ParseChar __P((char *, char *));
+static int IsNum __P((char *, int));
+static void InputColon __P((void));
+static void Colonfin __P((char *, int));
+static void InputSelect __P((void));
+static void InputSetenv __P((char *));
+static void InputAKA __P((void));
+static void AKAfin __P((char *, int));
+#ifdef COPY_PASTE
+static void copy_reg_fn __P((char *, int));
+static void ins_reg_fn __P((char *, int));
+#endif
+static void process_fn __P((char *, int));
+#ifdef PASSWORD
+static void pass1 __P((char *, int));
+static void pass2 __P((char *, int));
+#endif
+#ifdef POW_DETACH
+static void pow_detach_fn __P((char *, int));
+#endif
+static void digraph_fn __P((char *, int));
+
+
+
+extern struct display *display, *displays;
+extern struct win *fore, *console_window, *windows;
+extern struct user *users;
+
+extern char screenterm[], HostName[], version[];
+extern struct NewWindow nwin_undef, nwin_default;
+extern struct LayFuncs WinLf;
+extern struct layer BlankLayer;
+
+extern int Z0width, Z1width;
+extern int real_uid, real_gid;
+
+#ifdef NETHACK
+extern int nethackflag;
+#endif
+
+
+struct win *wtab[MAXWIN]; /* window table, should be dynamic */
+
+#ifdef MULTIUSER
+extern char *multi;
+#endif
+#ifdef PASSWORD
+int CheckPassword;
+char Password[30];
+#endif
+
+struct plop plop_tab[MAX_PLOP_DEFS];
+
+#ifndef PTYMODE
+# define PTYMODE 0622
+#endif
+
+int TtyMode = PTYMODE;
+int hardcopy_append = 0;
+int all_norefresh = 0;
+
+struct action ktab[256]; /* command key translation table */
+
+#ifdef MAPKEYS
+struct action umtab[KMAP_KEYS+KMAP_AKEYS+KMAP_EXT];
+struct action dmtab[KMAP_KEYS+KMAP_AKEYS+KMAP_EXT];
+struct action mmtab[KMAP_KEYS+KMAP_AKEYS+KMAP_EXT];
+
+char *kmap_extras[KMAP_EXT];
+int kmap_extras_fl[KMAP_EXT];
+
+#endif
+
+
+static const unsigned char digraphs[][3] = {
+ {'~', '!', 161}, /* ¡ */
+ {'!', '!', 161}, /* ¡ */
+ {'c', '|', 162}, /* ¢ */
+ {'$', '$', 163}, /* £ */
+ {'o', 'x', 164}, /* ¤ */
+ {'Y', '-', 165}, /* ¥ */
+ {'|', '|', 166}, /* ¦ */
+ {'p', 'a', 167}, /* § */
+ {'"', '"', 168}, /* ¨ */
+ {'c', 'O', 169}, /* © */
+ {'a', '-', 170}, /* ª */
+ {'<', '<', 171}, /* « */
+ {'-', ',', 172}, /* ¬ */
+ {'-', '-', 173}, /* ­ */
+ {'r', 'O', 174}, /* ® */
+ {'-', '=', 175}, /* ¯ */
+ {'~', 'o', 176}, /* ° */
+ {'+', '-', 177}, /* ± */
+ {'2', '2', 178}, /* ² */
+ {'3', '3', 179}, /* ³ */
+ {'\'', '\'', 180}, /* ´ */
+ {'j', 'u', 181}, /* µ */
+ {'p', 'p', 182}, /* ¶ */
+ {'~', '.', 183}, /* · */
+ {',', ',', 184}, /* ¸ */
+ {'1', '1', 185}, /* ¹ */
+ {'o', '-', 186}, /* º */
+ {'>', '>', 187}, /* » */
+ {'1', '4', 188}, /* ¼ */
+ {'1', '2', 189}, /* ½ */
+ {'3', '4', 190}, /* ¾ */
+ {'~', '?', 191}, /* ¿ */
+ {'?', '?', 191}, /* ¿ */
+ {'A', '`', 192}, /* À */
+ {'A', '\'', 193}, /* Á */
+ {'A', '^', 194}, /* Â */
+ {'A', '~', 195}, /* Ã */
+ {'A', '"', 196}, /* Ä */
+ {'A', '@', 197}, /* Å */
+ {'A', 'E', 198}, /* Æ */
+ {'C', ',', 199}, /* Ç */
+ {'E', '`', 200}, /* È */
+ {'E', '\'', 201}, /* É */
+ {'E', '^', 202}, /* Ê */
+ {'E', '"', 203}, /* Ë */
+ {'I', '`', 204}, /* Ì */
+ {'I', '\'', 205}, /* Í */
+ {'I', '^', 206}, /* Î */
+ {'I', '"', 207}, /* Ï */
+ {'D', '-', 208}, /* Ð */
+ {'N', '~', 209}, /* Ñ */
+ {'O', '`', 210}, /* Ò */
+ {'O', '\'', 211}, /* Ó */
+ {'O', '^', 212}, /* Ô */
+ {'O', '~', 213}, /* Õ */
+ {'O', '"', 214}, /* Ö */
+ {'/', '\\', 215}, /* × */
+ {'O', '/', 216}, /* Ø */
+ {'U', '`', 217}, /* Ù */
+ {'U', '\'', 218}, /* Ú */
+ {'U', '^', 219}, /* Û */
+ {'U', '"', 220}, /* Ü */
+ {'Y', '\'', 221}, /* Ý */
+ {'I', 'p', 222}, /* Þ */
+ {'s', 's', 223}, /* ß */
+ {'s', '"', 223}, /* ß */
+ {'a', '`', 224}, /* à */
+ {'a', '\'', 225}, /* á */
+ {'a', '^', 226}, /* â */
+ {'a', '~', 227}, /* ã */
+ {'a', '"', 228}, /* ä */
+ {'a', '@', 229}, /* å */
+ {'a', 'e', 230}, /* æ */
+ {'c', ',', 231}, /* ç */
+ {'e', '`', 232}, /* è */
+ {'e', '\'', 233}, /* é */
+ {'e', '^', 234}, /* ê */
+ {'e', '"', 235}, /* ë */
+ {'i', '`', 236}, /* ì */
+ {'i', '\'', 237}, /* í */
+ {'i', '^', 238}, /* î */
+ {'i', '"', 239}, /* ï */
+ {'d', '-', 240}, /* ð */
+ {'n', '~', 241}, /* ñ */
+ {'o', '`', 242}, /* ò */
+ {'o', '\'', 243}, /* ó */
+ {'o', '^', 244}, /* ô */
+ {'o', '~', 245}, /* õ */
+ {'o', '"', 246}, /* ö */
+ {':', '-', 247}, /* ÷ */
+ {'o', '/', 248}, /* ø */
+ {'u', '`', 249}, /* ù */
+ {'u', '\'', 250}, /* ú */
+ {'u', '^', 251}, /* û */
+ {'u', '"', 252}, /* ü */
+ {'y', '\'', 253}, /* ý */
+ {'i', 'p', 254}, /* þ */
+ {'y', '"', 255}, /* y", make poor lint happy*/
+ {'"', '[', 196}, /* Ä */
+ {'"', '\\', 214}, /* Ö */
+ {'"', ']', 220}, /* Ü */
+ {'"', '{', 228}, /* ä */
+ {'"', '|', 246}, /* ö */
+ {'"', '}', 252}, /* ü */
+ {'"', '~', 223} /* ß */
+};
+
+
+char *noargs[1];
+
+void
+InitKeytab()
+{
+ register unsigned int i;
+#ifdef MAPKEYS
+ char *argarr[2];
+#endif
+
+ for (i = 0; i < sizeof(ktab)/sizeof(*ktab); i++)
+ {
+ ktab[i].nr = RC_ILLEGAL;
+ ktab[i].args = noargs;
+ }
+#ifdef MAPKEYS
+ for (i = 0; i < KMAP_KEYS+KMAP_AKEYS+KMAP_EXT; i++)
+ {
+ umtab[i].nr = RC_ILLEGAL;
+ umtab[i].args = noargs;
+ dmtab[i].nr = RC_ILLEGAL;
+ dmtab[i].args = noargs;
+ mmtab[i].nr = RC_ILLEGAL;
+ mmtab[i].args = noargs;
+ }
+ argarr[1] = 0;
+ for (i = 0; i < NKMAPDEF; i++)
+ {
+ if (i + KMAPDEFSTART < T_CAPS)
+ continue;
+ if (i + KMAPDEFSTART >= T_CAPS + KMAP_KEYS)
+ continue;
+ if (kmapdef[i] == 0)
+ continue;
+ argarr[0] = kmapdef[i];
+ dmtab[i + (KMAPDEFSTART - T_CAPS)].nr = RC_STUFF;
+ dmtab[i + (KMAPDEFSTART - T_CAPS)].args = SaveArgs(argarr);
+ }
+ for (i = 0; i < NKMAPADEF; i++)
+ {
+ if (i + KMAPADEFSTART < T_CURSOR)
+ continue;
+ if (i + KMAPADEFSTART >= T_CURSOR + KMAP_AKEYS)
+ continue;
+ if (kmapadef[i] == 0)
+ continue;
+ argarr[0] = kmapadef[i];
+ dmtab[i + (KMAPADEFSTART - T_CURSOR + KMAP_KEYS)].nr = RC_STUFF;
+ dmtab[i + (KMAPADEFSTART - T_CURSOR + KMAP_KEYS)].args = SaveArgs(argarr);
+ }
+ for (i = 0; i < NKMAPMDEF; i++)
+ {
+ if (i + KMAPMDEFSTART < T_CAPS)
+ continue;
+ if (i + KMAPMDEFSTART >= T_CAPS + KMAP_KEYS)
+ continue;
+ if (kmapmdef[i] == 0)
+ continue;
+ argarr[0] = kmapmdef[i];
+ argarr[1] = 0;
+ mmtab[i + (KMAPMDEFSTART - T_CAPS)].nr = RC_STUFF;
+ mmtab[i + (KMAPMDEFSTART - T_CAPS)].args = SaveArgs(argarr);
+ }
+#endif
+
+ ktab['h'].nr = RC_HARDCOPY;
+#ifdef BSDJOBS
+ ktab['z'].nr = ktab[Ctrl('z')].nr = RC_SUSPEND;
+#endif
+ ktab['c'].nr = ktab[Ctrl('c')].nr = RC_SCREEN;
+ ktab[' '].nr = ktab[Ctrl(' ')].nr =
+ ktab['n'].nr = ktab[Ctrl('n')].nr = RC_NEXT;
+ ktab['N'].nr = RC_NUMBER;
+ ktab[Ctrl('h')].nr = ktab[0177].nr = ktab['p'].nr = ktab[Ctrl('p')].nr = RC_PREV;
+ ktab['k'].nr = ktab[Ctrl('k')].nr = RC_KILL;
+ ktab['l'].nr = ktab[Ctrl('l')].nr = RC_REDISPLAY;
+ ktab['w'].nr = ktab[Ctrl('w')].nr = RC_WINDOWS;
+ ktab['v'].nr = RC_VERSION;
+ ktab[Ctrl('v')].nr = RC_DIGRAPH;
+ ktab['q'].nr = ktab[Ctrl('q')].nr = RC_XON;
+ ktab['s'].nr = ktab[Ctrl('s')].nr = RC_XOFF;
+ ktab['t'].nr = ktab[Ctrl('t')].nr = RC_TIME;
+ ktab['i'].nr = ktab[Ctrl('i')].nr = RC_INFO;
+ ktab['m'].nr = ktab[Ctrl('m')].nr = RC_LASTMSG;
+ ktab['A'].nr = RC_TITLE;
+#if defined(UTMPOK) && defined(LOGOUTOK)
+ ktab['L'].nr = RC_LOGIN;
+#endif
+ ktab[','].nr = RC_LICENSE;
+ ktab['W'].nr = RC_WIDTH;
+ ktab['.'].nr = RC_DUMPTERMCAP;
+ ktab[Ctrl('\\')].nr = RC_QUIT;
+ ktab['d'].nr = ktab[Ctrl('d')].nr = RC_DETACH;
+ ktab['r'].nr = ktab[Ctrl('r')].nr = RC_WRAP;
+ ktab['f'].nr = ktab[Ctrl('f')].nr = RC_FLOW;
+ ktab['C'].nr = RC_CLEAR;
+ ktab['Z'].nr = RC_RESET;
+ ktab['H'].nr = RC_LOG;
+ ktab['M'].nr = RC_MONITOR;
+ ktab['?'].nr = RC_HELP;
+ for (i = 0; i < ((MAXWIN < 10) ? MAXWIN : 10); i++)
+ {
+ char *args[2], arg1[10];
+ args[0] = arg1;
+ args[1] = 0;
+ sprintf(arg1, "%d", i);
+ ktab['0' + i].nr = RC_SELECT;
+ ktab['0' + i].args = SaveArgs(args);
+ }
+ ktab[Ctrl('G')].nr = RC_VBELL;
+ ktab[':'].nr = RC_COLON;
+#ifdef COPY_PASTE
+ ktab['['].nr = ktab[Ctrl('[')].nr = RC_COPY;
+ {
+ char *args[2];
+ args[0] = ".";
+ args[1] = NULL;
+ ktab[']'].args = SaveArgs(args);
+ ktab[Ctrl(']')].args = SaveArgs(args);
+ }
+ ktab[']'].nr = ktab[Ctrl(']')].nr = RC_PASTE;
+ ktab['{'].nr = RC_HISTORY;
+ ktab['}'].nr = RC_HISTORY;
+ ktab['>'].nr = RC_WRITEBUF;
+ ktab['<'].nr = RC_READBUF;
+ ktab['='].nr = RC_REMOVEBUF;
+ ktab['\''].nr = ktab['"'].nr = RC_SELECT; /* calling a window by name */
+#endif
+#ifdef POW_DETACH
+ ktab['D'].nr = RC_POW_DETACH;
+#endif
+#ifdef LOCK
+ ktab['x'].nr = ktab[Ctrl('x')].nr = RC_LOCKSCREEN;
+#endif
+ ktab['b'].nr = ktab[Ctrl('b')].nr = RC_BREAK;
+ ktab['B'].nr = RC_POW_BREAK;
+ ktab['_'].nr = RC_SILENCE;
+ if (DefaultEsc >= 0)
+ ktab[DefaultEsc].nr = RC_OTHER;
+ if (DefaultMetaEsc >= 0)
+ ktab[DefaultMetaEsc].nr = RC_META;
+}
+
+static void
+ClearAction(act)
+struct action *act;
+{
+ char **p;
+
+ if (act->nr == RC_ILLEGAL)
+ return;
+ act->nr = RC_ILLEGAL;
+ if (act->args == noargs)
+ return;
+ for (p = act->args; *p; p++)
+ free(*p);
+ free((char *)act->args);
+ act->args = noargs;
+}
+
+
+#ifdef MAPKEYS
+
+/*
+ * This ProcessInput just does the keybindings and passes
+ * everything on to ProcessInput2
+ */
+
+void
+ProcessInput(ibuf, ilen)
+char *ibuf;
+int ilen;
+{
+ int ch, slen;
+ char *s;
+ struct action *act;
+ int i, l;
+
+ if (display == 0 || ilen == 0)
+ return;
+ slen = ilen;
+ s = ibuf;
+ while(ilen-- > 0)
+ {
+ ch = *(unsigned char *)s++;
+ if (D_dontmap)
+ D_dontmap = 0;
+ else if (D_nseqs)
+ for (;;)
+ {
+ if (*(unsigned char *)D_seqp != ch)
+ {
+ l = *((unsigned char *)D_seqp + (KMAP_OFF - KMAP_SEQ));
+ if (l)
+ {
+ D_seqp += sizeof(struct kmap) * l;
+ continue;
+ }
+ if (D_seql)
+ {
+ D_seqp -= D_seql;
+ ProcessInput2(D_seqp, D_seql);
+ D_seql = 0;
+ }
+ D_seqp = D_kmaps[0].seq;
+ D_mapdefault = 0;
+ break;
+ }
+ if (D_seql++ == 0)
+ {
+ /* Finish old stuff */
+ slen -= ilen + 1;
+ ProcessInput2(ibuf, slen);
+ D_seqruns = 0;
+ }
+ ibuf = s;
+ slen = ilen;
+ ch = -1;
+ if (*++D_seqp == 0)
+ {
+ i = (struct kmap *)(D_seqp - D_seql - KMAP_SEQ) - D_kmaps;
+ debug1("Mapping #%d", i);
+ i = D_kmaps[i].nr & ~KMAP_NOTIMEOUT;
+#ifdef DEBUG
+ if (i < KMAP_KEYS)
+ debug1(" - %s", term[i + T_CAPS].tcname);
+#endif
+ if (i >= T_CURSOR - T_CAPS && i < T_KEYPAD - T_CAPS && D_cursorkeys)
+ i += T_OCAPS - T_CURSOR;
+ else if (i >= T_KEYPAD - T_CAPS && i < T_OCAPS - T_CAPS && D_keypad)
+ i += T_OCAPS - T_CURSOR;
+ debug1(" - action %d\n", i);
+ fore = D_fore;
+ act = 0;
+#ifdef COPY_PASTE
+ if (InMark())
+ act = &mmtab[i];
+#endif
+ if ((!act || act->nr == RC_ILLEGAL) && !D_mapdefault)
+ act = &umtab[i];
+ D_mapdefault = 0;
+ if (!act || act->nr == RC_ILLEGAL)
+ act = &dmtab[i];
+ if (act && act->nr != RC_ILLEGAL)
+ DoAction(act, 0);
+ else
+ {
+ D_seqp -= D_seql;
+ ProcessInput2(D_seqp, D_seql);
+ }
+ if (display == 0)
+ return;
+ D_seql = 0;
+ D_seqp = D_kmaps[0].seq;
+ }
+ break;
+ }
+ }
+ ProcessInput2(ibuf, slen);
+}
+
+#else
+# define ProcessInput2 ProcessInput
+#endif
+
+
+/*
+ * Here the screen escape commands are handled, the remaining
+ * chars are passed to the layer's input handler.
+ */
+
+void
+ProcessInput2(ibuf, ilen)
+char *ibuf;
+int ilen;
+{
+ char *s;
+ int ch, slen;
+
+ while (display)
+ {
+ fore = D_fore;
+ slen = ilen;
+ s = ibuf;
+ if (!D_ESCseen)
+ {
+ while (ilen > 0)
+ {
+ if ((unsigned char)*s++ == D_user->u_Esc)
+ break;
+ ilen--;
+ }
+ slen -= ilen;
+ while (slen)
+ Process(&ibuf, &slen);
+ if (--ilen == 0)
+ D_ESCseen = 1;
+ }
+ if (ilen <= 0)
+ return;
+ D_ESCseen = 0;
+ ch = (unsigned char)*s;
+
+ /*
+ * As users have different esc characters, but a common ktab[],
+ * we fold back the users esc and meta-esc key to the Default keys
+ * that can be looked up in the ktab[]. grmbl. jw.
+ * FIXME: make ktab[] a per user thing.
+ */
+ if (ch == D_user->u_Esc)
+ ch = DefaultEsc;
+ else if (ch == D_user->u_MetaEsc)
+ ch = DefaultMetaEsc;
+
+ if (ch >= 0)
+ DoAction(&ktab[ch], ch);
+ ibuf = s + 1;
+ ilen--;
+ }
+}
+
+
+int
+FindCommnr(str)
+char *str;
+{
+ int x, m, l = 0, r = RC_LAST;
+ while (l <= r)
+ {
+ m = (l + r) / 2;
+ x = strcmp(str, comms[m].name);
+ if (x > 0)
+ l = m + 1;
+ else if (x < 0)
+ r = m - 1;
+ else
+ return m;
+ }
+ return RC_ILLEGAL;
+}
+
+static int
+CheckArgNum(nr, args)
+int nr;
+char **args;
+{
+ int i, n;
+ static char *argss[] = {"no", "one", "two", "three"};
+
+ n = comms[nr].flags & ARGS_MASK;
+ for (i = 0; args[i]; i++)
+ ;
+ if (comms[nr].flags & ARGS_ORMORE)
+ {
+ if (i < n)
+ {
+ Msg(0, "%s: %s: at least %s argument%s required", rc_name, comms[nr].name, argss[n], n != 1 ? "s" : "");
+ return -1;
+ }
+ }
+ else if ((comms[nr].flags & ARGS_PLUSONE) && (comms[nr].flags & ARGS_PLUSTWO))
+ {
+ if (i != n && i != n + 1 && i != n + 2)
+ {
+ Msg(0, "%s: %s: %s, %s or %s argument%s required", rc_name,
+ comms[nr].name, argss[n], argss[n + 1], argss[n + 2],
+ n != 0 ? "s" : "");
+ return -1;
+ }
+ }
+ else if (comms[nr].flags & ARGS_PLUSONE)
+ {
+ if (i != n && i != n + 1)
+ {
+ Msg(0, "%s: %s: %s or %s argument%s required", rc_name, comms[nr].name, argss[n], argss[n + 1], n != 0 ? "s" : "");
+ return -1;
+ }
+ }
+ else if (comms[nr].flags & ARGS_PLUSTWO)
+ {
+ if (i != n && i != n + 2)
+ {
+ Msg(0, "%s: %s: %s or %s argument%s required", rc_name,
+ comms[nr].name, argss[n], argss[n + 2], n != 0 ? "s" : "");
+ return -1;
+ }
+ }
+ else if (i != n)
+ {
+ Msg(0, "%s: %s: %s argument%s required", rc_name, comms[nr].name, argss[n], n != 1 ? "s" : "");
+ return -1;
+ }
+ return 0;
+}
+
+/*ARGSUSED*/
+static void
+DoAction(act, key)
+struct action *act;
+int key;
+{
+ int nr = act->nr;
+ char **args = act->args;
+ struct win *p;
+ int i, n, msgok;
+ char *s;
+ char ch;
+
+ if (nr == RC_ILLEGAL)
+ {
+ debug1("key '%c': No action\n", key);
+ return;
+ }
+ n = comms[nr].flags;
+ if ((n & NEED_DISPLAY) && display == 0)
+ {
+ Msg(0, "%s: %s: display required", rc_name, comms[nr].name);
+ return;
+ }
+ if ((n & NEED_FORE) && fore == 0)
+ {
+ Msg(0, "%s: %s: window required", rc_name, comms[nr].name);
+ return;
+ }
+ if (CheckArgNum(nr, args))
+ return;
+#ifdef MULTIUSER
+ if (multi && display)
+ {
+ if (AclCheckPermCmd(D_user, ACL_EXEC, &comms[nr]))
+ return;
+ }
+#endif /* MULTIUSER */
+ msgok = display && !*rc_name;
+ switch(nr)
+ {
+ case RC_SELECT:
+ if (!*args)
+ InputSelect();
+ else if (ParseWinNum(act, &n) == 0)
+ SwitchWindow(n);
+ break;
+#ifdef AUTO_NUKE
+ case RC_DEFAUTONUKE:
+ if (ParseOnOff(act, &defautonuke) == 0 && msgok)
+ Msg(0, "Default autonuke turned %s", defautonuke ? "on" : "off");
+ if (display && *rc_name)
+ D_auto_nuke = defautonuke;
+ break;
+ case RC_AUTONUKE:
+ if (ParseOnOff(act, &D_auto_nuke) == 0 && msgok)
+ Msg(0, "Autonuke turned %s", D_auto_nuke ? "on" : "off");
+ break;
+#endif
+ case RC_DEFOBUFLIMIT:
+ if (ParseNum(act, &defobuflimit) == 0 && msgok)
+ Msg(0, "Default limit set to %d", defobuflimit);
+ if (display && *rc_name)
+ D_obufmax = defobuflimit;
+ break;
+ case RC_OBUFLIMIT:
+ if (*args == 0)
+ Msg(0, "Limit is %d, current buffer size is %d", D_obufmax, D_obuflen);
+ else if (ParseNum(act, &D_obufmax) == 0 && msgok)
+ Msg(0, "Limit set to %d", D_obufmax);
+ break;
+ case RC_DUMPTERMCAP:
+ WriteFile(DUMP_TERMCAP);
+ break;
+ case RC_HARDCOPY:
+ WriteFile(DUMP_HARDCOPY);
+ break;
+ case RC_LOG:
+ n = fore->w_logfp ? 1 : 0;
+ ParseSwitch(act, &n);
+ LogToggle(n);
+ break;
+#ifdef BSDJOBS
+ case RC_SUSPEND:
+ Detach(D_STOP);
+ break;
+#endif
+ case RC_NEXT:
+ if (MoreWindows())
+ SwitchWindow(NextWindow());
+ break;
+ case RC_PREV:
+ if (MoreWindows())
+ SwitchWindow(PreviousWindow());
+ break;
+ case RC_KILL:
+ {
+ char *name;
+
+ n = fore->w_number;
+#ifdef PSEUDOS
+ if (fore->w_pwin)
+ {
+ FreePseudowin(fore);
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You have a sad feeling for a moment...");
+ else
+#endif
+ Msg(0, "Filter removed.");
+ break;
+ }
+#endif
+ name = SaveStr(fore->w_title);
+ KillWindow(fore);
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You destroy poor window %d (%s).", n, name);
+ else
+#endif
+ Msg(0, "Window %d (%s) killed.", n, name);
+ if (name)
+ free(name);
+ break;
+ }
+ case RC_QUIT:
+ Finit(0);
+ /* NOTREACHED */
+ case RC_DETACH:
+ Detach(D_DETACH);
+ break;
+#ifdef POW_DETACH
+ case RC_POW_DETACH:
+ if (key >= 0)
+ {
+ static char buf[2];
+
+ buf[0] = key;
+ Input(buf, 1, pow_detach_fn, INP_RAW);
+ }
+ else
+ Detach(D_POWER); /* detach and kill Attacher's parent */
+ break;
+#endif
+ case RC_DEBUG:
+#ifdef DEBUG
+ if (!*args)
+ {
+ if (dfp)
+ Msg(0, "debugging info is written to %s/", DEBUGDIR);
+ else
+ Msg(0, "debugging is currently off. Use 'debug on' to enable.");
+ break;
+ }
+ if (dfp)
+ {
+ debug("debug: closing debug file.\n");
+ fflush(dfp);
+ fclose(dfp);
+ dfp = NULL;
+ }
+ if (strcmp("off", *args))
+ {
+ char buf[255];
+
+ sprintf(buf, "%s/SCREEN.%d", DEBUGDIR, getpid());
+ if ((dfp = fopen(buf, "a")) == NULL)
+ dfp = stderr;
+ debug("debug: opening debug file.\n");
+ }
+#else
+ Msg(0, "Sorry, screen was compiled without -DDEBUG option.");
+#endif
+ break;
+ case RC_ZOMBIE:
+ {
+ char ch2 = 0;
+
+ if (!(s = *args))
+ {
+ ZombieKey_destroy = 0;
+ break;
+ }
+ if (!(s = ParseChar(s, &ch)) || *s)
+ {
+ if (!s || !(s = ParseChar(s, &ch2)) || *s)
+ {
+ Msg(0, "%s:zombie: one or two characters expected.", rc_name);
+ break;
+ }
+ }
+ ZombieKey_destroy = ch;
+ ZombieKey_resurrect = ch2;
+ break;
+ }
+ case RC_WALL:
+ for (n = 0, s = *args; args[n]; n++)
+ {
+ /* glue the vector together again. Brute force method. */
+ while (*s)
+ s++;
+ while (s < args[n+1])
+ *s++ = ' ';
+ }
+#ifdef MULTIUSER
+ s = D_user->u_name;
+#else
+ s = D_usertty;
+#endif
+ display = NULL; /* a message without display will cause a broadcast */
+ Msg(0, "%s: %s", s, *args);
+ break;
+ case RC_AT:
+ /* where this AT command comes from: */
+#ifdef MULTIUSER
+ s = SaveStr(D_user->u_name);
+#else
+ s = SaveStr(D_usertty);
+#endif
+ n = strlen(args[0]);
+ if (n) n--;
+ /*
+ * the windows/displays loops are quite dangerous here, take extra
+ * care not to trigger landmines. Things may appear/disappear while
+ * we are walking along.
+ */
+ switch (args[0][n])
+ {
+ case '*':
+ {
+ struct display *nd;
+ struct user *u;
+
+ if (!n)
+ u = D_user;
+ else
+ for (u = users; u; u = u->u_next)
+ {
+ debug3("strncmp('%s', '%s', %d)\n", *args, u->u_name, n);
+ if (!strncmp(*args, u->u_name, n))
+ break;
+ }
+ debug1("at all displays of user %s\n", u->u_name);
+ for (display = displays; display; display = nd)
+ {
+ nd = display->d_next;
+ fore = D_fore;
+ if (D_user != u)
+ continue;
+ debug1("AT display %s\n", D_usertty);
+ DoCommand(args + 1);
+ if (display)
+ Msg(0, "command from %s: %s %s",
+ s, args[1], args[2] ? args[2] : "");
+ display = NULL;
+ fore = NULL;
+ }
+ free(s);
+ return;
+ }
+ case '%':
+ {
+ struct display *nd;
+
+ debug1("at display matching '%s'\n", args[0]);
+ for (display = displays; display; display = nd)
+ {
+ nd = display->d_next;
+ fore = D_fore;
+ if (strncmp(args[0], D_usertty, n) &&
+ (strncmp("/dev/", D_usertty, 5) ||
+ strncmp(args[0], D_usertty + 5, n)) &&
+ (strncmp("/dev/tty", D_usertty, 8) ||
+ strncmp(args[0], D_usertty + 8, n)))
+ continue;
+ debug1("AT display %s\n", D_usertty);
+ DoCommand(args + 1);
+ if (display)
+ Msg(0, "command from %s: %s %s",
+ s, args[1], args[2] ? args[2] : "");
+ display = NULL;
+ fore = NULL;
+ }
+ free(s);
+ return;
+ }
+ case '#':
+ n--;
+ /* FALLTHROUGH */
+ default:
+ {
+ struct win *nw;
+ int ch;
+
+ n++;
+ ch = args[0][n];
+ args[0][n] = '\0';
+ if (!*args[0] || (i = WindowByNumber(args[0])) < 0)
+ {
+ args[0][n] = ch; /* must restore string in case of bind */
+ /* try looping over titles */
+ for (fore = windows; fore; fore = nw)
+ {
+ nw = fore->w_next;
+ if (strncmp(args[0], fore->w_title, n))
+ continue;
+ debug2("AT window %d(%s)\n", fore->w_number, fore->w_title);
+ /*
+ * consider this a bug or a feature:
+ * while looping through windows, we have fore AND
+ * display context. This will confuse users who try to
+ * set up loops inside of loops, but often allows to do
+ * what you mean, even when you adress your context wrong.
+ */
+ i = 0;
+ if (fore->w_display)
+ display = fore->w_display;
+ DoCommand(args + 1); /* may destroy our display */
+ if ((fore->w_display))
+ {
+ display = fore->w_display;
+ Msg(0, "command from %s: %s %s",
+ s, args[1], args[2] ? args[2] : "");
+ }
+ }
+ display = NULL;
+ fore = NULL;
+ if (i < 0)
+ Msg(0, "%s: at '%s': no such window.\n", rc_name, args[0]);
+ free(s);
+ return;
+ }
+ else if (i < MAXWIN && (fore = wtab[i]))
+ {
+ args[0][n] = ch; /* must restore string in case of bind */
+ debug2("AT window %d (%s)\n", fore->w_number, fore->w_title);
+ if (fore->w_display)
+ display = fore->w_display;
+ DoCommand(args + 1);
+ if ((display = fore->w_display))
+ Msg(0, "command from %s: %s %s",
+ s, args[1], args[2] ? args[2] : "");
+ display = NULL;
+ fore = NULL;
+ free(s);
+ return;
+ }
+ }
+ }
+ Msg(0, "%s: at [identifier][%%|*|#] command [args]", rc_name);
+ free(s);
+ break;
+#ifdef COPY_PASTE
+ case RC_READREG:
+ /*
+ * Without arguments we prompt for a destination register.
+ * It will receive the copybuffer contents.
+ * This is not done by RC_PASTE, as we prompt for source (not dest)
+ * there.
+ */
+ if ((s = *args) == NULL)
+ {
+ Input("Copy to register:", 1, copy_reg_fn, INP_RAW);
+ break;
+ }
+ if (((s = ParseChar(s, &ch)) == NULL) || *s)
+ {
+ Msg(0, "%s: copyreg: character, ^x, or (octal) \\032 expected.",
+ rc_name);
+ break;
+ }
+ /*
+ * With two arguments we *really* read register contents from file
+ */
+ if (args[1])
+ {
+ if ((s = ReadFile(args[1], &n)))
+ {
+ struct plop *pp = plop_tab + (int)(unsigned char)ch;
+
+ if (pp->buf)
+ free(pp->buf);
+ pp->buf = s;
+ pp->len = n;
+ }
+ }
+ else
+ /*
+ * with one argument we copy the copybuffer into a specified register
+ * This could be done with RC_PASTE too, but is here to be consistent
+ * with the zero argument call.
+ */
+ copy_reg_fn(&ch, 0);
+ break;
+#endif
+ case RC_REGISTER:
+ if ((s = ParseChar(*args, &ch)) == NULL || *s)
+ Msg(0, "%s: register: character, ^x, or (octal) \\032 expected.",
+ rc_name);
+ else
+ {
+ struct plop *plp = plop_tab + (int)(unsigned char)ch;
+
+ if (plp->buf)
+ free(plp->buf);
+ plp->buf = SaveStr(args[1]);
+ plp->len = strlen(plp->buf);
+ }
+ break;
+ case RC_PROCESS:
+ if ((s = *args) == NULL)
+ {
+ Input("Process register:", 1, process_fn, INP_RAW);
+ break;
+ }
+ if ((s = ParseChar(s, &ch)) == NULL || *s)
+ {
+ Msg(0, "%s: process: character, ^x, or (octal) \\032 expected.",
+ rc_name);
+ break;
+ }
+ process_fn(&ch, 0);
+ break;
+ case RC_STUFF:
+ s = *args;
+ n = strlen(s);
+ while(n)
+ Process(&s, &n);
+ break;
+ case RC_REDISPLAY:
+ Activate(-1);
+ break;
+ case RC_WINDOWS:
+ ShowWindows();
+ break;
+ case RC_VERSION:
+ Msg(0, "screen %s", version);
+ break;
+ case RC_TIME:
+ ShowTime();
+ break;
+ case RC_INFO:
+ ShowInfo();
+ break;
+ case RC_COMMAND:
+ if (!D_ESCseen)
+ {
+ D_ESCseen = 1;
+ break;
+ }
+ D_ESCseen = 0;
+ /* FALLTHROUGH */
+ case RC_OTHER:
+ if (MoreWindows())
+ SwitchWindow(D_other ? D_other->w_number : NextWindow());
+ break;
+ case RC_META:
+ if (D_user->u_Esc < 0)
+ break;
+ ch = D_user->u_Esc;
+ s = &ch;
+ n = 1;
+ Process(&s, &n);
+ break;
+ case RC_XON:
+ ch = Ctrl('q');
+ s = &ch;
+ n = 1;
+ Process(&s, &n);
+ break;
+ case RC_XOFF:
+ ch = Ctrl('s');
+ s = &ch;
+ n = 1;
+ Process(&s, &n);
+ break;
+ case RC_POW_BREAK:
+ case RC_BREAK:
+ n = 0;
+ if (*args && ParseNum(act, &n))
+ break;
+ SendBreak(fore, n, nr == RC_POW_BREAK);
+ break;
+#ifdef LOCK
+ case RC_LOCKSCREEN:
+ Detach(D_LOCK);
+ break;
+#endif
+ case RC_WIDTH:
+ if (*args)
+ {
+ if (ParseNum(act, &n))
+ break;
+ }
+ else
+ {
+ if (D_width == Z0width)
+ n = Z1width;
+ else if (D_width == Z1width)
+ n = Z0width;
+ else if (D_width > (Z0width + Z1width) / 2)
+ n = Z0width;
+ else
+ n = Z1width;
+ }
+ if (n <= 0)
+ {
+ Msg(0, "Illegal width");
+ break;
+ }
+ if (n == D_width)
+ break;
+ if (ResizeDisplay(n, D_height) == 0)
+ {
+ DoResize(D_width, D_height);
+ Activate(D_fore ? D_fore->w_norefresh : 0);
+ }
+ else
+ Msg(0, "Your termcap does not specify how to change the terminal's width to %d.", n);
+ break;
+ case RC_HEIGHT:
+ if (*args)
+ {
+ if (ParseNum(act, &n))
+ break;
+ }
+ else
+ {
+#define H0height 42
+#define H1height 24
+ if (D_height == H0height)
+ n = H1height;
+ else if (D_height == H1height)
+ n = H0height;
+ else if (D_height > (H0height + H1height) / 2)
+ n = H0height;
+ else
+ n = H1height;
+ }
+ if (n <= 0)
+ {
+ Msg(0, "Illegal height");
+ break;
+ }
+ if (n == D_height)
+ break;
+ if (ResizeDisplay(D_width, n) == 0)
+ {
+ DoResize(D_width, D_height);
+ Activate(D_fore ? D_fore->w_norefresh : 0);
+ }
+ else
+ Msg(0, "Your termcap does not specify how to change the terminal's height to %d.", n);
+ break;
+ case RC_AKA:
+ case RC_TITLE:
+ if (*args == 0)
+ InputAKA();
+ else
+ ChangeAKA(fore, *args, 20);
+ break;
+ case RC_COLON:
+ InputColon();
+ break;
+ case RC_LASTMSG:
+ if (D_status_lastmsg)
+ Msg(0, "%s", D_status_lastmsg);
+ break;
+ case RC_SCREEN:
+ DoScreen("key", args);
+ break;
+ case RC_WRAP:
+ if (ParseSwitch(act, &fore->w_wrap) == 0 && msgok)
+ Msg(0, "%cwrap", fore->w_wrap ? '+' : '-');
+ break;
+ case RC_FLOW:
+ if (*args)
+ {
+ if (args[0][0] == 'a')
+ {
+ fore->w_flow = (fore->w_flow & FLOW_AUTO) ? FLOW_AUTOFLAG |FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG;
+ }
+ else
+ {
+ if (ParseOnOff(act, &n))
+ break;
+ fore->w_flow = (fore->w_flow & FLOW_AUTO) | n;
+ }
+ }
+ else
+ {
+ if (fore->w_flow & FLOW_AUTOFLAG)
+ fore->w_flow = (fore->w_flow & FLOW_AUTO) | FLOW_NOW;
+ else if (fore->w_flow & FLOW_NOW)
+ fore->w_flow &= ~FLOW_NOW;
+ else
+ fore->w_flow = fore->w_flow ? FLOW_AUTOFLAG|FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG;
+ }
+ SetFlow(fore->w_flow & FLOW_NOW);
+ if (msgok)
+ Msg(0, "%cflow%s", (fore->w_flow & FLOW_NOW) ? '+' : '-',
+ (fore->w_flow & FLOW_AUTOFLAG) ? "(auto)" : "");
+ break;
+ case RC_DEFWRITELOCK:
+ if (args[0][0] == 'a')
+ nwin_default.wlock = WLOCK_AUTO;
+ else
+ {
+ if (ParseOnOff(act, &n))
+ break;
+ nwin_default.wlock = n ? WLOCK_ON : WLOCK_OFF;
+ }
+ break;
+ case RC_WRITELOCK:
+#ifdef MULTIUSER
+ if (*args)
+ {
+ if (args[0][0] == 'a')
+ {
+ fore->w_wlock = WLOCK_AUTO;
+ }
+ else
+ {
+ if (ParseOnOff(act, &n))
+ break;
+ fore->w_wlock = n ? WLOCK_ON : WLOCK_OFF;
+ }
+ /*
+ * user may have permission to change the writelock setting,
+ * but he may never aquire the lock himself without write permission
+ */
+ if (!AclCheckPermWin(D_user, ACL_WRITE, fore))
+ fore->w_wlockuser = D_user;
+ }
+#endif
+ Msg(0, "writelock %s", (fore->w_wlock == WLOCK_AUTO) ? "auto" :
+ ((fore->w_wlock == WLOCK_OFF) ? "off" : "on"));
+ break;
+ case RC_CLEAR:
+ if (fore->w_state == LIT)
+ WriteString(fore, "\033[H\033[J", 6);
+ break;
+ case RC_RESET:
+ fore->w_state = LIT;
+ WriteString(fore, "\033c", 2);
+ break;
+ case RC_MONITOR:
+ n = fore->w_monitor == MON_ON;
+ if (ParseSwitch(act, &n))
+ break;
+ if (n)
+ {
+ fore->w_monitor = MON_ON;
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You feel like someone is watching you...");
+ else
+#endif
+ Msg(0, "Window %d (%s) is now being monitored for all activity.",
+ fore->w_number, fore->w_title);
+ }
+ else
+ {
+ fore->w_monitor = MON_OFF;
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You no longer sense the watcher's presence.");
+ else
+#endif
+ Msg(0, "Window %d (%s) is no longer being monitored for activity.",
+ fore->w_number, fore->w_title);
+ }
+ break;
+ case RC_DISPLAYS:
+ display_displays();
+ break;
+ case RC_HELP:
+ display_help();
+ break;
+ case RC_LICENSE:
+ display_copyright();
+ break;
+#ifdef COPY_PASTE
+ case RC_COPY:
+ if (D_layfn != &WinLf)
+ {
+ Msg(0, "Must be on a window layer");
+ break;
+ }
+ MarkRoutine();
+ break;
+ case RC_HISTORY:
+ {
+ static char *pasteargs[] = {".", 0};
+ if (D_layfn != &WinLf)
+ {
+ Msg(0, "Must be on a window layer");
+ break;
+ }
+ if (GetHistory() == 0)
+ break;
+ if (D_user->u_copybuffer == NULL)
+ break;
+ args = pasteargs;
+ }
+ /*FALLTHROUGH*/
+ case RC_PASTE:
+ {
+ char *ss, *dbuf, dch;
+ int l = 0;
+
+ /*
+ * without args we prompt for one(!) register to be pasted in the window
+ */
+ if ((s = *args) == NULL)
+ {
+ Input("Paste from register:", 1, ins_reg_fn, INP_RAW);
+ break;
+ }
+ /*
+ * with two arguments we paste into a destination register
+ * (no window needed here).
+ */
+ if (args[1] && ((s = ParseChar(args[1], &dch)) == NULL || *s))
+ {
+ Msg(0, "%s: paste destination: character, ^x, or (octal) \\032 expected.",
+ rc_name);
+ break;
+ }
+ /*
+ * measure length of needed buffer
+ */
+ for (ss = s = *args; (ch = *ss); ss++)
+ {
+ if (ch == '.')
+ {
+ if (display)
+ l += D_user->u_copylen;
+ }
+ else
+ l += plop_tab[(int)(unsigned char)ch].len;
+ }
+ if (l == 0)
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "Nothing happens.");
+ else
+#endif
+ Msg(0, "empty buffer");
+ break;
+ }
+ /*
+ * shortcut:
+ * if there is only one source and the destination is a window, then
+ * pass a pointer rather than duplicating the buffer.
+ */
+ if (s[1] == 0 && args[1] == 0)
+ {
+ if (fore == 0)
+ break;
+ fore->w_pasteptr = 0;
+ fore->w_pastelen = 0;
+ if (fore->w_pastebuf)
+ free(fore->w_pastebuf);
+ fore->w_pastebuf = 0; /* this flags we only have a pointer */
+ if (*s == '.')
+ fore->w_pasteptr = D_user->u_copybuffer;
+ else
+ fore->w_pasteptr = plop_tab[(int)(unsigned char)*s].buf;
+ fore->w_pastelen = l;
+ break;
+ }
+ /*
+ * if no shortcut, we construct a buffer
+ */
+ if ((dbuf = (char *)malloc(l)) == 0)
+ {
+ Msg(0, strnomem);
+ break;
+ }
+ l = 0;
+ /*
+ * concatenate all sources into our own buffer, copy buffer is
+ * special and is skipped if no display exists.
+ */
+ for (ss = s; (ch = *ss); ss++)
+ {
+ if (ch == '.')
+ {
+ if (display == 0)
+ continue;
+ bcopy(D_user->u_copybuffer, dbuf + l, D_user->u_copylen);
+ l += D_user->u_copylen;
+ }
+ else
+ {
+ bcopy(plop_tab[(int)(unsigned char)ch].buf, dbuf + l, plop_tab[(int)(unsigned char)ch].len);
+ l += plop_tab[(int)(unsigned char)ch].len;
+ }
+ }
+ /*
+ * when called with one argument we paste our buffer into the window
+ */
+ if (args[1] == 0)
+ {
+ if (fore == 0)
+ {
+ free(dbuf); /* no window? zap our buffer */
+ break;
+ }
+ if (fore->w_pastebuf)
+ free(fore->w_pastebuf);
+ fore->w_pastebuf = dbuf;
+ fore->w_pasteptr = fore->w_pastebuf;
+ fore->w_pastelen = l;
+ }
+ else
+ {
+ /*
+ * we have two arguments, the second is already in dch.
+ * use this as destination rather than the window.
+ */
+ if (dch == '.')
+ {
+ if (display == 0)
+ {
+ free(dbuf);
+ break;
+ }
+ if (D_user->u_copybuffer != NULL)
+ UserFreeCopyBuffer(D_user);
+ D_user->u_copybuffer = dbuf;
+ D_user->u_copylen = l;
+ }
+ else
+ {
+ struct plop *pp = plop_tab + (int)(unsigned char)dch;
+
+ if (pp->buf)
+ free(pp->buf);
+ pp->buf = dbuf;
+ pp->len = l;
+ }
+ }
+ break;
+ }
+ case RC_WRITEBUF:
+ if (D_user->u_copybuffer == NULL)
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "Nothing happens.");
+ else
+#endif
+ Msg(0, "empty buffer");
+ break;
+ }
+ WriteFile(DUMP_EXCHANGE);
+ break;
+ case RC_READBUF:
+ if ((s = ReadFile(BufferFile, &n)))
+ {
+ if (D_user->u_copybuffer)
+ UserFreeCopyBuffer(D_user);
+ D_user->u_copylen = n;
+ D_user->u_copybuffer = s;
+ }
+ break;
+ case RC_REMOVEBUF:
+ KillBuffers();
+ break;
+#endif /* COPY_PASTE */
+ case RC_ESCAPE:
+ if (ParseEscape(display ? D_user : users, *args))
+ {
+ Msg(0, "%s: two characters required after escape.", rc_name);
+ break;
+ }
+ /* Change defescape if only one user. This is because we only
+ * have one ktab.
+ */
+ if (users->u_next)
+ break;
+ /* FALLTHROUGH */
+ case RC_DEFESCAPE:
+ if (ParseEscape((struct user *)0, *args))
+ {
+ Msg(0, "%s: two characters required after defescape.", rc_name);
+ break;
+ }
+#ifdef MAPKEYS
+ CheckEscape();
+#endif
+ break;
+ case RC_CHDIR:
+ s = *args ? *args : home;
+ if (chdir(s) == -1)
+ Msg(errno, "%s", s);
+ break;
+ case RC_SHELL:
+ if (ParseSaveStr(act, &ShellProg) == 0)
+ ShellArgs[0] = ShellProg;
+ break;
+ case RC_HARDCOPYDIR:
+ (void)ParseSaveStr(act, &hardcopydir);
+ break;
+ case RC_LOGFILE:
+ if (*args)
+ if (ParseSaveStr(act, &screenlogfile) || !msgok)
+ break;
+ Msg(0, "logfile is '%s'", screenlogfile);
+ break;
+ case RC_SHELLTITLE:
+ case RC_SHELLAKA:
+ (void)ParseSaveStr(act, &nwin_default.aka);
+ break;
+ case RC_SLEEP:
+ case RC_TERMCAP:
+ case RC_TERMINFO:
+ case RC_TERMCAPINFO:
+ break; /* Already handled */
+ case RC_TERM:
+ s = NULL;
+ if (ParseSaveStr(act, &s))
+ break;
+ if (strlen(s) >= 20)
+ {
+ Msg(0,"%s: term: argument too long ( < 20)", rc_name);
+ free(s);
+ break;
+ }
+ strcpy(screenterm, s);
+ free(s);
+ debug1("screenterm set to %s\n", screenterm);
+ MakeTermcap(display == 0);
+ debug("new termcap made\n");
+ break;
+ case RC_ECHO:
+ if (msgok)
+ {
+ /*
+ * D_user typed ^A:echo... well, echo isn't FinishRc's job,
+ * but as he wanted to test us, we show good will
+ */
+ if (*args && (args[1] == 0 || (strcmp(args[1], "-n") == 0 && args[2] == 0)))
+ Msg(0, "%s", args[1] ? args[1] : *args);
+ else
+ Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name);
+ }
+ break;
+ case RC_BELL:
+ case RC_BELL_MSG:
+ if (*args == 0)
+ {
+ char buf[256];
+ AddXChars(buf, sizeof(buf), BellString);
+ Msg(0, "bell_msg is '%s'", buf);
+ break;
+ }
+ (void)ParseSaveStr(act, &BellString);
+ break;
+#ifdef COPY_PASTE
+ case RC_BUFFERFILE:
+ if (*args == 0)
+ BufferFile = SaveStr(DEFAULT_BUFFERFILE);
+ else if (ParseSaveStr(act, &BufferFile))
+ break;
+ if (msgok)
+ Msg(0, "Bufferfile is now '%s'\n", BufferFile);
+ break;
+#endif
+ case RC_ACTIVITY:
+ (void)ParseSaveStr(act, &ActivityString);
+ break;
+#ifdef POW_DETACH
+ case RC_POW_DETACH_MSG:
+ if (*args == 0)
+ {
+ char buf[256];
+ AddXChars(buf, sizeof(buf), PowDetachString);
+ Msg(0, "pow_detach_msg is '%s'", buf);
+ break;
+ }
+ (void)ParseSaveStr(act, &PowDetachString);
+ break;
+#endif
+#if defined(UTMPOK) && defined(LOGOUTOK)
+ case RC_LOGIN:
+ n = fore->w_slot != (slot_t)-1;
+ if (ParseSwitch(act, &n) == 0)
+ SlotToggle(n);
+ break;
+ case RC_DEFLOGIN:
+ (void)ParseOnOff(act, &nwin_default.lflag);
+ break;
+#endif
+ case RC_DEFFLOW:
+ if (args[0] && args[1] && args[1][0] == 'i')
+ {
+ iflag = 1;
+ if ((intrc == VDISABLE) && (origintrc != VDISABLE))
+ {
+#if defined(TERMIO) || defined(POSIX)
+ intrc = D_NewMode.tio.c_cc[VINTR] = origintrc;
+ D_NewMode.tio.c_lflag |= ISIG;
+#else /* TERMIO || POSIX */
+ intrc = D_NewMode.m_tchars.t_intrc = origintrc;
+#endif /* TERMIO || POSIX */
+
+ if (display)
+ SetTTY(D_userfd, &D_NewMode);
+ }
+ }
+ if (args[0] && args[0][0] == 'a')
+ nwin_default.flowflag = FLOW_AUTOFLAG;
+ else
+ (void)ParseOnOff(act, &nwin_default.flowflag);
+ break;
+ case RC_DEFWRAP:
+ (void)ParseOnOff(act, &nwin_default.wrap);
+ break;
+ case RC_DEFC1:
+ (void)ParseOnOff(act, &nwin_default.c1);
+ break;
+ case RC_DEFGR:
+ (void)ParseOnOff(act, &nwin_default.gr);
+ break;
+ case RC_DEFMONITOR:
+ if (ParseOnOff(act, &n) == 0)
+ nwin_default.monitor = (n == 0) ? MON_OFF : MON_ON;
+ break;
+ case RC_HARDSTATUS:
+ RemoveStatus();
+ (void)ParseSwitch(act, &use_hardstatus);
+ break;
+ case RC_CONSOLE:
+ n = (console_window != 0);
+ if (ParseSwitch(act, &n))
+ break;
+ if (TtyGrabConsole(fore->w_ptyfd, n, rc_name))
+ break;
+ if (n == 0)
+ Msg(0, "%s: releasing console %s", rc_name, HostName);
+ else if (console_window)
+ Msg(0, "%s: stealing console %s from window %d (%s)", rc_name,
+ HostName, console_window->w_number, console_window->w_title);
+ else
+ Msg(0, "%s: grabbing console %s", rc_name, HostName);
+ console_window = n ? fore : 0;
+ break;
+ case RC_ALLPARTIAL:
+ if (ParseOnOff(act, &all_norefresh))
+ break;
+ if (!all_norefresh && fore)
+ Activate(-1);
+ if (msgok)
+ Msg(0, all_norefresh ? "No refresh on window change!\n" :
+ "Window specific refresh\n");
+ break;
+ case RC_PARTIAL:
+ (void)ParseSwitch(act, &n);
+ fore->w_norefresh = n;
+ break;
+ case RC_VBELL:
+ if (ParseSwitch(act, &visual_bell) || !msgok)
+ break;
+ if (visual_bell == 0)
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "Suddenly you can't see your bell!");
+ else
+#endif
+ Msg(0, "switched to audible bell.");
+ }
+ else
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "Your bell is no longer invisible.");
+ else
+#endif
+ Msg(0, "switched to visual bell.");
+ }
+ break;
+ case RC_VBELLWAIT:
+ if (ParseNum(act, &VBellWait) == 0 && msgok)
+ Msg(0, "vbellwait set to %d seconds", VBellWait);
+ break;
+ case RC_MSGWAIT:
+ if (ParseNum(act, &MsgWait) == 0 && msgok)
+ Msg(0, "msgwait set to %d seconds", MsgWait);
+ break;
+ case RC_MSGMINWAIT:
+ if (ParseNum(act, &MsgMinWait) == 0 && msgok)
+ Msg(0, "msgminwait set to %d seconds", MsgMinWait);
+ break;
+ case RC_SILENCEWAIT:
+ if ((ParseNum(act, &SilenceWait) == 0) && msgok)
+ {
+ if (SilenceWait < 1)
+ SilenceWait = 1;
+ for (p = windows; p; p = p->w_next)
+ if (p->w_tstamp.seconds)
+ p->w_tstamp.seconds = SilenceWait;
+ Msg(0, "silencewait set to %d seconds", SilenceWait);
+ }
+ break;
+ case RC_NUMBER:
+ if (*args == 0)
+ Msg(0, "This is window %d (%s).\n", fore->w_number, fore->w_title);
+ else
+ {
+ int old = fore->w_number;
+
+ if (ParseNum(act, &n) || n >= MAXWIN)
+ break;
+ p = wtab[n];
+ wtab[n] = fore;
+ fore->w_number = n;
+ wtab[old] = p;
+ if (p)
+ p->w_number = old;
+#ifdef MULTIUSER
+ AclWinSwap(old, n);
+#endif
+ /* yucc */
+ if (fore->w_hstatus)
+ {
+ display = fore->w_display;
+ if (display)
+ RefreshStatus();
+ }
+ }
+ break;
+ case RC_SILENCE:
+ n = fore->w_tstamp.seconds != 0;
+ i = SilenceWait;
+ if (args[0] &&
+ (args[0][0] == '-' || (args[0][0] >= '0' && args[0][0] <= '9')))
+ {
+ if (ParseNum(act, &i))
+ break;
+ n = i;
+ }
+ else if (ParseSwitch(act, &n))
+ break;
+ if (n)
+ {
+ fore->w_tstamp.lastio = time(0);
+ fore->w_tstamp.seconds = i;
+ if (!msgok)
+ break;
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You feel like someone is waiting for %d sec. silence...",
+ fore->w_tstamp.seconds);
+ else
+#endif
+ Msg(0, "Window %d (%s) is now being monitored for %d sec. silence.",
+ fore->w_number, fore->w_title, fore->w_tstamp.seconds);
+ }
+ else
+ {
+ fore->w_tstamp.lastio = (time_t)0;
+ fore->w_tstamp.seconds = 0;
+ if (!msgok)
+ break;
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You no longer sense the watcher's silence.");
+ else
+#endif
+ Msg(0, "Window %d (%s) is no longer being monitored for silence.",
+ fore->w_number, fore->w_title);
+ }
+ break;
+#ifdef COPY_PASTE
+ case RC_DEFSCROLLBACK:
+ (void)ParseNum(act, &nwin_default.histheight);
+ break;
+ case RC_SCROLLBACK:
+ (void)ParseNum(act, &n);
+ ChangeWindowSize(fore, fore->w_width, fore->w_height, n);
+ if (msgok)
+ Msg(0, "scrollback set to %d", fore->w_histheight);
+ break;
+#endif
+ case RC_SESSIONNAME:
+ if (*args == 0)
+ Msg(0, "This session is named '%s'\n", SockName);
+ else
+ {
+ char buf[MAXPATHLEN];
+
+ s = NULL;
+ if (ParseSaveStr(act, &s))
+ break;
+ if (!*s || strlen(s) > MAXPATHLEN - 13)
+ {
+ Msg(0, "%s: bad session name '%s'\n", rc_name, s);
+ free(s);
+ break;
+ }
+ sprintf(buf, "%s", SockPath);
+ sprintf(buf + (SockName - SockPath), "%d.%s", (int)getpid(), s);
+ free(s);
+ if ((access(buf, F_OK) == 0) || (errno != ENOENT))
+ {
+ Msg(0, "%s: inappropriate path: '%s'.", rc_name, buf);
+ break;
+ }
+ if (rename(SockPath, buf))
+ {
+ Msg(errno, "%s: failed to rename(%s, %s)", rc_name, SockPath, buf);
+ break;
+ }
+ debug2("rename(%s, %s) done\n", SockPath, buf);
+ sprintf(SockPath, "%s", buf);
+ MakeNewEnv();
+ }
+ break;
+ case RC_SETENV:
+ if (!args[0] || !args[1])
+ {
+ debug1("RC_SETENV arguments missing: %s\n", args[0] ? args[0] : "");
+ InputSetenv(args[0]);
+ }
+ else
+#ifndef USESETENV
+ {
+ char *buf;
+ int l;
+
+ if ((buf = (char *)malloc((l = strlen(args[0])) +
+ strlen(args[1]) + 2)) == NULL)
+ {
+ Msg(0, strnomem);
+ break;
+ }
+ strcpy(buf, args[0]);
+ buf[l] = '=';
+ strcpy(buf + l + 1, args[1]);
+ putenv(buf);
+# ifdef NEEDPUTENV
+ /*
+ * we use our own putenv(), knowing that it does a malloc()
+ * the string space, we can free our buf now.
+ */
+ free(buf);
+# else /* NEEDSETENV */
+ /*
+ * For all sysv-ish systems that link a standard putenv()
+ * the string-space buf is added to the environment and must not
+ * be freed, or modified.
+ * We are sorry to say that memory is lost here, when setting
+ * the same variable again and again.
+ */
+# endif /* NEEDSETENV */
+ }
+#else /* USESETENV */
+# if defined(linux) || defined(__convex__) || (BSD >= 199103)
+ setenv(args[0], args[1], 0);
+# else
+ setenv(args[0], args[1]);
+# endif /* linux || convex || BSD >= 199103 */
+#endif /* USESETENV */
+ MakeNewEnv();
+ break;
+ case RC_UNSETENV:
+ unsetenv(*args);
+ MakeNewEnv();
+ break;
+ case RC_SLOWPASTE:
+ if (ParseNum(act, &slowpaste) == 0 && msgok)
+ Msg(0, "slowpaste set to %d milliseconds", slowpaste);
+ break;
+#ifdef COPY_PASTE
+ case RC_MARKKEYS:
+ s = NULL;
+ if (ParseSaveStr(act, &s))
+ break;
+ if (CompileKeys(s, mark_key_tab))
+ {
+ Msg(0, "%s: markkeys: syntax error.", rc_name);
+ free(s);
+ break;
+ }
+ debug1("markkeys %s\n", *args);
+ free(s);
+ break;
+ case RC_PASTEFONT:
+ if (ParseSwitch(act, &pastefont) == 0 && msgok)
+ Msg(0, "Will %spaste font settings", pastefont ? "" : "not ");
+ break;
+ case RC_CRLF:
+ (void)ParseOnOff(act, &join_with_cr);
+ break;
+#endif
+#ifdef NETHACK
+ case RC_NETHACK:
+ (void)ParseOnOff(act, &nethackflag);
+ break;
+#endif
+ case RC_HARDCOPY_APPEND:
+ (void)ParseOnOff(act, &hardcopy_append);
+ break;
+ case RC_VBELL_MSG:
+ if (*args == 0)
+ {
+ char buf[256];
+ AddXChars(buf, sizeof(buf), VisualBellString);
+ Msg(0, "vbell_msg is '%s'", buf);
+ break;
+ }
+ (void)ParseSaveStr(act, &VisualBellString);
+ debug1(" new vbellstr '%s'\n", VisualBellString);
+ break;
+ case RC_DEFMODE:
+ if (ParseBase(act, *args, &n, 8, "oct"))
+ break;
+ if (n < 0 || n > 0777)
+ {
+ Msg(0, "%s: mode: Invalid tty mode %o", rc_name, n);
+ break;
+ }
+ TtyMode = n;
+ if (msgok)
+ Msg(0, "Ttymode set to %03o", TtyMode);
+ break;
+ case RC_AUTODETACH:
+ (void)ParseOnOff(act, &auto_detach);
+ break;
+ case RC_STARTUP_MESSAGE:
+ (void)ParseOnOff(act, &default_startup);
+ break;
+#ifdef PASSWORD
+ case RC_PASSWORD:
+ CheckPassword = 1;
+ if (*args)
+ {
+ strncpy(Password, *args, sizeof(Password) - 1);
+ if (!strcmp(Password, "none"))
+ CheckPassword = 0;
+ }
+ else
+ {
+ if (display == 0)
+ {
+ debug("prompting for password on no display???\n");
+ break;
+ }
+ Input("New screen password:", sizeof(Password) - 1, pass1,
+ INP_NOECHO);
+ }
+ break;
+#endif /* PASSWORD */
+ case RC_BIND:
+ if ((s = ParseChar(*args, &ch)) == NULL || *s)
+ {
+ Msg(0, "%s: bind: character, ^x, or (octal) \\032 expected.",
+ rc_name);
+ break;
+ }
+ n = (unsigned char)ch;
+ ClearAction(&ktab[n]);
+ if (args[1])
+ {
+ if ((i = FindCommnr(args[1])) == RC_ILLEGAL)
+ {
+ Msg(0, "%s: bind: unknown command '%s'", rc_name, args[1]);
+ break;
+ }
+ if (CheckArgNum(i, args + 2))
+ break;
+ ktab[n].nr = i;
+ if (args[2])
+ ktab[n].args = SaveArgs(args + 2);
+ }
+ break;
+#ifdef MAPKEYS
+ case RC_BINDKEY:
+ {
+ struct action *newact;
+ int newnr, fl = 0, kf = 0, af = 0, df = 0, mf = 0;
+ struct display *odisp = display;
+ int used = 0;
+
+ for (; *args && **args == '-'; args++)
+ {
+ if (strcmp(*args, "-t") == 0)
+ fl = KMAP_NOTIMEOUT;
+ else if (strcmp(*args, "-k") == 0)
+ kf = 1;
+ else if (strcmp(*args, "-a") == 0)
+ af = 1;
+ else if (strcmp(*args, "-d") == 0)
+ df = 1;
+ else if (strcmp(*args, "-m") == 0)
+ mf = 1;
+ else if (strcmp(*args, "--") == 0)
+ {
+ args++;
+ break;
+ }
+ else
+ {
+ Msg(0, "%s: bindkey: invalid option %s", rc_name, *args);
+ return;
+ }
+ }
+ if (df && mf)
+ {
+ Msg(0, "%s: bindkey: -d does not work with -m", rc_name);
+ break;
+ }
+ if (*args == 0)
+ {
+ if (mf)
+ display_bindkey("Copy mode", mmtab);
+ else if (df)
+ display_bindkey("Default", dmtab);
+ else
+ display_bindkey("User", umtab);
+ break;
+ }
+ if (kf == 0)
+ {
+ if (af)
+ {
+ Msg(0, "%s: bindkey: -a only works with -k", rc_name);
+ break;
+ }
+ for (i = 0; i < KMAP_EXT; i++)
+ if (kmap_extras[i] == 0)
+ {
+ if (args[1])
+ break;
+ }
+ else
+ if (strcmp(kmap_extras[i], *args) == 0)
+ break;
+ if (i == KMAP_EXT)
+ {
+ Msg(0, args[1] ? "%s: bindkey: no more room for keybinding" : "%s: bindkey: keybinding not found", rc_name);
+ break;
+ }
+ if (df == 0 && dmtab[i + KMAP_KEYS + KMAP_AKEYS].nr != RC_ILLEGAL)
+ used = 1;
+ if (mf == 0 && mmtab[i + KMAP_KEYS + KMAP_AKEYS].nr != RC_ILLEGAL)
+ used = 1;
+ if ((df || mf) && umtab[i + KMAP_KEYS + KMAP_AKEYS].nr != RC_ILLEGAL)
+ used = 1;
+ i += KMAP_KEYS + KMAP_AKEYS;
+ }
+ else
+ {
+ for (i = T_CAPS; i < T_OCAPS; i++)
+ if (strcmp(term[i].tcname, *args) == 0)
+ break;
+ if (i == T_OCAPS)
+ {
+ Msg(0, "%s: bindkey: unknown key '%s'", rc_name, *args);
+ break;
+ }
+ if (af && i >= T_CURSOR && i < T_OCAPS)
+ i -= T_CURSOR - KMAP_KEYS;
+ else
+ i -= T_CAPS;
+ }
+ newact = df ? &dmtab[i] : mf ? &mmtab[i] : &umtab[i];
+ ClearAction(newact);
+ if (args[1])
+ {
+ if ((newnr = FindCommnr(args[1])) == RC_ILLEGAL)
+ {
+ Msg(0, "%s: bindkey: unknown command '%s'", rc_name, args[1]);
+ break;
+ }
+ if (CheckArgNum(newnr, args + 2))
+ break;
+ newact->nr = newnr;
+ if (args[2])
+ newact->args = SaveArgs(args + 2);
+ if (kf == 0 && args[1])
+ {
+ if (kmap_extras[i - (KMAP_KEYS+KMAP_AKEYS)])
+ free(kmap_extras[i - (KMAP_KEYS+KMAP_AKEYS)]);
+ kmap_extras[i - (KMAP_KEYS+KMAP_AKEYS)] = SaveStr(*args);
+ kmap_extras_fl[i - (KMAP_KEYS+KMAP_AKEYS)] = fl;
+ }
+ }
+ for (display = displays; display; display = display->d_next)
+ remap(i, args[1] ? 1 : 0);
+ if (kf == 0 && !args[1])
+ {
+ i -= KMAP_KEYS + KMAP_AKEYS;
+ if (!used && kmap_extras[i])
+ {
+ free(kmap_extras[i]);
+ kmap_extras[i] = 0;
+ kmap_extras_fl[i] = 0;
+ }
+ }
+ display = odisp;
+ }
+ break;
+ case RC_MAPTIMEOUT:
+ if (*args)
+ {
+ if (ParseNum(act, &n))
+ break;
+ if (n < 0 || n >= 1000)
+ {
+ Msg(0, "%s: maptimeout: illegal time %d", rc_name, n);
+ break;
+ }
+ maptimeout = n * 1000;
+ }
+ if (*args == 0 || msgok)
+ Msg(0, "maptimeout is %dms", maptimeout/1000);
+ break;
+ case RC_MAPNOTNEXT:
+ D_dontmap = 1;
+ break;
+ case RC_MAPDEFAULT:
+ D_mapdefault = 1;
+ break;
+#endif
+#ifdef MULTIUSER
+ case RC_ACLCHG:
+ case RC_ACLADD:
+ {
+ struct user **u;
+
+ if (args[0][0] == '*' && args[0][1] == '\0' && args[1] && args[2])
+ {
+ for (u = &users; *u; u = &(*u)->u_next)
+ AclSetPerm(*u, args[1], args[2]);
+ break;
+ }
+ do
+ {
+ for (s = args[0]; *s && *s != ' ' && *s != '\t' && *s != ','; s++)
+ ;
+ *s ? (*s++ = '\0') : (*s = '\0');
+ u = FindUserPtr(args[0]);
+ UserAdd(args[0], (char *)0, u);
+ if (args[1] && args[2])
+ AclSetPerm(*u, args[1], args[2]);
+ else
+ AclSetPerm(*u, "+rwx", "#?");
+ } while (*(args[0] = s));
+ break;
+ }
+ case RC_ACLDEL:
+ {
+ if (UserDel(args[0], (struct user **)0))
+ break;
+ if (msgok)
+ Msg(0, "%s removed from acl database", args[0]);
+ break;
+ }
+ case RC_ACLGRP:
+ {
+ break;
+ }
+ case RC_MULTIUSER:
+ if (ParseOnOff(act, &n))
+ break;
+ multi = n ? "" : 0;
+ chsock();
+ if (msgok)
+ Msg(0, "Multiuser mode %s", multi ? "enabled" : "disabled");
+ break;
+#endif /* MULTIUSER */
+#ifdef PSEUDOS
+ case RC_EXEC:
+ winexec(args);
+ break;
+#endif
+#ifdef MULTI
+ case RC_CLONE:
+ execclone(args);
+ break;
+#endif
+ case RC_GR:
+ if (ParseSwitch(act, &fore->w_gr) == 0 && msgok)
+ Msg(0, "Will %suse GR", fore->w_gr ? "" : "not ");
+ break;
+ case RC_C1:
+ if (ParseSwitch(act, &fore->w_c1) == 0 && msgok)
+ Msg(0, "Will %suse C1", fore->w_c1 ? "" : "not ");
+ break;
+#ifdef KANJI
+ case RC_KANJI:
+ for (i = 0; i < 2; i++)
+ {
+ if (args[i] == 0)
+ break;
+ if (strcmp(args[i], "jis") == 0 || strcmp(args[i], "off") == 0)
+ n = 0;
+ else if (strcmp(args[i], "euc") == 0)
+ n = EUC;
+ else if (strcmp(args[i], "sjis") == 0)
+ n = SJIS;
+ else
+ {
+ Msg(0, "kanji: illegal argument (%s)", args[i]);
+ break;
+ }
+ if (i == 0)
+ fore->w_kanji = n;
+ else
+ D_kanji = n;
+ }
+ if (fore)
+ ResetCharsets(fore);
+ break;
+ case RC_DEFKANJI:
+ if (strcmp(*args, "jis") == 0 || strcmp(*args, "off") == 0)
+ n = 0;
+ else if (strcmp(*args, "euc") == 0)
+ n = EUC;
+ else if (strcmp(*args, "sjis") == 0)
+ n = SJIS;
+ else
+ {
+ Msg(0, "defkanji: illegal argument (%s)", *args);
+ break;
+ }
+ nwin_default.kanji = n;
+ break;
+#endif
+ case RC_PRINTCMD:
+ if (*args)
+ {
+ if (printcmd)
+ free(printcmd);
+ printcmd = 0;
+ if (**args)
+ printcmd = SaveStr(*args);
+ }
+ if (*args == 0 || msgok)
+ if (printcmd)
+ Msg(0, "using '%s' as print command", printcmd);
+ else
+ Msg(0, "using termcap entries for printing");
+ break;
+ case RC_DIGRAPH:
+ Input("Enter digraph: ", 10, digraph_fn, INP_EVERY);
+ if (*args && **args)
+ {
+ s = *args;
+ n = strlen(s);
+ Process(&s, &n);
+ }
+ break;
+ case RC_DEFHSTATUS:
+ if (*args == 0)
+ {
+ char buf[256];
+ *buf = 0;
+ if (nwin_default.hstatus)
+ AddXChars(buf, sizeof(buf), nwin_default.hstatus);
+ Msg(0, "default hstatus is '%s'", buf);
+ break;
+ }
+ (void)ParseSaveStr(act, &nwin_default.hstatus);
+ if (*nwin_default.hstatus == 0)
+ {
+ free(nwin_default.hstatus);
+ nwin_default.hstatus = 0;
+ }
+ break;
+ case RC_DEFCHARSET:
+ case RC_CHARSET:
+ if (*args == 0)
+ {
+ char buf[256];
+ *buf = 0;
+ if (nwin_default.charset)
+ AddXChars(buf, sizeof(buf), nwin_default.charset);
+ Msg(0, "default charset is '%s'", buf);
+ break;
+ }
+ n = strlen(*args);
+ if (n == 0 || n > 6)
+ {
+ Msg(0, "%s: %s: string has illegal size.", rc_name, comms[nr].name);
+ break;
+ }
+ if (n > 4 && (
+ ((args[0][4] < '0' || args[0][4] > '3') && args[0][4] != '.') ||
+ ((args[0][5] < '0' || args[0][5] > '3') && args[0][5] && args[0][5] != '.')))
+ {
+ Msg(0, "%s: %s: illegal mapping number.", rc_name, comms[nr].name);
+ break;
+ }
+ if (nr == RC_CHARSET)
+ {
+ SetCharsets(fore, *args);
+ break;
+ }
+ if (nwin_default.charset)
+ free(nwin_default.charset);
+ nwin_default.charset = SaveStr(*args);
+ break;
+ case RC_SORENDITION:
+ i = mchar_so.attr;
+ if (*args && **args)
+ {
+ if (ParseBase(act, *args, &i, 16, "hex"))
+ break;
+ if (i < 0 || i >= (1 << NATTR))
+ {
+ Msg(0, "sorendition: bad standout attributes");
+ break;
+ }
+ }
+#ifdef COLOR
+ n = mchar_so.color;
+ if (*args && args[1])
+ {
+ if (ParseBase(act, args[1], &n, 16, "hex"))
+ break;
+ if (n < 0 || n > 0x99 || (n & 15) > 9)
+ {
+ Msg(0, "sorendition: bad standout color");
+ break;
+ }
+ n = 0x99 - n;
+ }
+ mchar_so.attr = i;
+ mchar_so.color = n;
+ Msg(0, "Standout attributes 0x%02x color 0x%02x", (unsigned char)mchar_so.attr, 0x99 - (unsigned char)mchar_so.color);
+#else
+ mchar_so.attr = i;
+ Msg(0, "Standout attributes 0x%02x", (unsigned char)mchar_so.attr);
+#endif
+ break;
+ default:
+ break;
+ }
+}
+
+void
+DoCommand(argv)
+char **argv;
+{
+ struct action act;
+
+ if ((act.nr = FindCommnr(*argv)) == RC_ILLEGAL)
+ {
+ Msg(0, "%s: unknown command '%s'", rc_name, *argv);
+ return;
+ }
+ act.args = argv + 1;
+ DoAction(&act, -1);
+}
+
+static char **
+SaveArgs(args)
+char **args;
+{
+ register char **ap, **pp;
+ register int argc = 0;
+
+ while (args[argc])
+ argc++;
+ if ((pp = ap = (char **) malloc((unsigned) (argc + 1) * sizeof(char **))) == 0)
+ Panic(0, strnomem);
+ while (argc--)
+ *pp++ = SaveStr(*args++);
+ *pp = 0;
+ return ap;
+}
+
+int
+Parse(buf, args)
+char *buf, **args;
+{
+ register char *p = buf, **ap = args;
+ register int delim, argc;
+
+ argc = 0;
+ for (;;)
+ {
+ while (*p && (*p == ' ' || *p == '\t'))
+ ++p;
+ if (argc == 0)
+ {
+ /*
+ * Expand hardcoded shortcuts.
+ * This should not be done here, cause multiple commands per
+ * line or prefixed commands won't be recognized.
+ * But as spaces between shortcut character and arguments
+ * can be ommited this expansion affects tokenisation and
+ * should be done here. Hmmm. jw.
+ */
+ switch (*p)
+ {
+ case '@':
+ *ap++ = "at";
+ /*
+ * If comments were removed before this shortcut expanded,
+ * we wouldn't need this hack.
+ */
+ if (p[1] == '#')
+ *p = '\\';
+ while (*(++p) == ' ' || *p == '\t')
+ ;
+ argc++;
+ break;
+#ifdef PSEUDOS
+ case '!':
+ case '|':
+ *ap++ = "exec";
+ if (*p == '!')
+ p++;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ argc++;
+ break;
+#endif
+ }
+ }
+ if (*p == '\0' || *p == '#')
+ {
+ *p = '\0';
+ args[argc] = 0;
+ return argc;
+ }
+ if (*p == '\\' && p[1] == '#')
+ p++;
+ if (++argc >= MAXARGS)
+ {
+ Msg(0, "%s: too many tokens.", rc_name);
+ return 0;
+ }
+ delim = 0;
+ if (*p == '"' || *p == '\'')
+ delim = *p++;
+ *ap++ = p;
+ while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t')))
+ ++p;
+ if (*p == '\0')
+ {
+ if (delim)
+ {
+ Msg(0, "%s: Missing quote.", rc_name);
+ return 0;
+ }
+ }
+ else
+ *p++ = '\0';
+ }
+}
+
+int
+ParseEscape(u, p)
+struct user *u;
+char *p;
+{
+ unsigned char buf[2];
+ int e, me;
+
+#ifdef MAPKEYS
+ if (*p == 0)
+ e = me = -1;
+ else
+#endif
+ {
+ if ((p = ParseChar(p, (char *)buf)) == NULL ||
+ (p = ParseChar(p, (char *)buf+1)) == NULL || *p)
+ return -1;
+ e = buf[0];
+ me = buf[1];
+ }
+ if (u)
+ {
+ u->u_Esc = e;
+ u->u_MetaEsc = me;
+ }
+ else
+ {
+ if (users)
+ {
+ if (DefaultEsc >= 0)
+ ClearAction(&ktab[DefaultEsc]);
+ if (DefaultMetaEsc >= 0)
+ ClearAction(&ktab[DefaultMetaEsc]);
+ }
+ DefaultEsc = e;
+ DefaultMetaEsc = me;
+ if (users)
+ {
+ if (DefaultEsc >= 0)
+ {
+ ClearAction(&ktab[DefaultEsc]);
+ ktab[DefaultEsc].nr = RC_OTHER;
+ }
+ if (DefaultMetaEsc >= 0)
+ {
+ ClearAction(&ktab[DefaultMetaEsc]);
+ ktab[DefaultMetaEsc].nr = RC_META;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+ParseSwitch(act, var)
+struct action *act;
+int *var;
+{
+ if (*act->args == 0)
+ {
+ *var ^= 1;
+ return 0;
+ }
+ return ParseOnOff(act, var);
+}
+
+static int
+ParseOnOff(act, var)
+struct action *act;
+int *var;
+{
+ register int num = -1;
+ char **args = act->args;
+
+ if (args[1] == 0)
+ {
+ if (strcmp(args[0], "on") == 0)
+ num = 1;
+ else if (strcmp(args[0], "off") == 0)
+ num = 0;
+ }
+ if (num < 0)
+ {
+ Msg(0, "%s: %s: invalid argument. Give 'on' or 'off'", rc_name, comms[act->nr].name);
+ return -1;
+ }
+ *var = num;
+ return 0;
+}
+
+static int
+ParseSaveStr(act, var)
+struct action *act;
+char **var;
+{
+ char **args = act->args;
+ if (*args == 0 || args[1])
+ {
+ Msg(0, "%s: %s: one argument required.", rc_name, comms[act->nr].name);
+ return -1;
+ }
+ if (*var)
+ free(*var);
+ *var = SaveStr(*args);
+ return 0;
+}
+
+static int
+ParseNum(act, var)
+struct action *act;
+int *var;
+{
+ int i;
+ char *p, **args = act->args;
+
+ p = *args;
+ if (p == 0 || *p == 0 || args[1])
+ {
+ Msg(0, "%s: %s: invalid argument. Give one argument.",
+ rc_name, comms[act->nr].name);
+ return -1;
+ }
+ i = 0;
+ while (*p)
+ {
+ if (*p >= '0' && *p <= '9')
+ i = 10 * i + (*p - '0');
+ else
+ {
+ Msg(0, "%s: %s: invalid argument. Give numeric argument.",
+ rc_name, comms[act->nr].name);
+ return -1;
+ }
+ p++;
+ }
+ debug1("ParseNum got %d\n", i);
+ *var = i;
+ return 0;
+}
+
+static struct win *
+WindowByName(s)
+char *s;
+{
+ struct win *p;
+
+ for (p = windows; p; p = p->w_next)
+ if (!strcmp(p->w_title, s))
+ return p;
+ for (p = windows; p; p = p->w_next)
+ if (!strncmp(p->w_title, s, strlen(s)))
+ return p;
+ return 0;
+}
+
+static int
+WindowByNumber(str)
+char *str;
+{
+ int i;
+ char *s;
+
+ for (i = 0, s = str; *s; s++)
+ {
+ if (*s < '0' || *s > '9')
+ break;
+ i = i * 10 + (*s - '0');
+ }
+ return *s ? -1 : i;
+}
+
+/*
+ * Get window number from Name or Number string.
+ * Numbers are tried first, then names, a prefix match suffices.
+ * Be careful when assigning numeric strings as WindowTitles.
+ */
+int
+WindowByNoN(str)
+char *str;
+{
+ int i;
+ struct win *p;
+
+ if ((i = WindowByNumber(str)) < 0 || i >= MAXWIN)
+ {
+ if ((p = WindowByName(str)))
+ return p->w_number;
+ return -1;
+ }
+ return i;
+}
+
+static int
+ParseWinNum(act, var)
+struct action *act;
+int *var;
+{
+ char **args = act->args;
+ int i = 0;
+
+ if (*args == 0 || args[1])
+ {
+ Msg(0, "%s: %s: one argument required.", rc_name, comms[act->nr].name);
+ return -1;
+ }
+
+ i = WindowByNoN(*args);
+ if (i < 0)
+ {
+ Msg(0, "%s: %s: invalid argument. Give window number or name.",
+ rc_name, comms[act->nr].name);
+ return -1;
+ }
+ debug1("ParseWinNum got %d\n", i);
+ *var = i;
+ return 0;
+}
+
+
+static int
+ParseBase(act, p, var, base, bname)
+struct action *act;
+char *p;
+int *var;
+int base;
+char *bname;
+{
+ int i = 0;
+ int c;
+
+ if (*p == 0)
+ {
+ Msg(0, "%s: %s: empty argument.", rc_name, comms[act->nr].name);
+ return -1;
+ }
+ while ((c = *p++))
+ {
+ if (c >= 'a' && c <= 'z')
+ c -= 'a' - 'A';
+ if (c >= 'A' && c <= 'Z')
+ c -= 'A' - ('0' + 10);
+ c -= '0';
+ if (c < 0 || c >= base)
+ {
+ Msg(0, "%s: %s: argument is not %s.", rc_name, comms[act->nr].name, bname);
+ return -1;
+ }
+ i = base * i + c;
+ }
+ debug1("ParseBase got %d\n", i);
+ *var = i;
+ return 0;
+}
+
+static char *
+ParseChar(p, cp)
+char *p, *cp;
+{
+ if (*p == 0)
+ return 0;
+ if (*p == '^')
+ {
+ if (*++p == '?')
+ *cp = '\177';
+ else if (*p >= '@')
+ *cp = Ctrl(*p);
+ else
+ return 0;
+ ++p;
+ }
+ else if (*p == '\\' && *++p <= '7' && *p >= '0')
+ {
+ *cp = 0;
+ do
+ *cp = *cp * 8 + *p - '0';
+ while (*++p <= '7' && *p >= '0');
+ }
+ else
+ *cp = *p++;
+ return p;
+}
+
+
+static int
+IsNum(s, base)
+register char *s;
+register int base;
+{
+ for (base += '0'; *s; ++s)
+ if (*s < '0' || *s > base)
+ return 0;
+ return 1;
+}
+
+int
+IsNumColon(s, base, p, psize)
+int base, psize;
+char *s, *p;
+{
+ char *q;
+ if ((q = rindex(s, ':')) != NULL)
+ {
+ strncpy(p, q + 1, psize - 1);
+ p[psize - 1] = '\0';
+ *q = '\0';
+ }
+ else
+ *p = '\0';
+ return IsNum(s, base);
+}
+
+static void
+SwitchWindow(n)
+int n;
+{
+ struct win *p;
+
+ debug1("SwitchWindow %d\n", n);
+ if (display == 0)
+ return;
+ if (n < 0 || n >= MAXWIN || (p = wtab[n]) == 0)
+ {
+ ShowWindows();
+ return;
+ }
+ if (p == D_fore)
+ {
+ Msg(0, "This IS window %d (%s).", n, p->w_title);
+ return;
+ }
+ if (p->w_display)
+ {
+ Msg(0, "Window %d (%s) is on another display (%s@%s).", n, p->w_title,
+ p->w_display->d_user->u_name, p->w_display->d_usertty);
+ return;
+ }
+ SetForeWindow(p);
+ Activate(fore->w_norefresh);
+}
+
+/*
+ * returns 0, if the lock really has been released
+ */
+int
+ReleaseAutoWritelock(dis, w)
+struct display *dis;
+struct win *w;
+{
+ /* release auto writelock when user has no other display here */
+ if (w->w_wlock == WLOCK_AUTO && w->w_wlockuser == D_user)
+ {
+ struct display *d;
+
+ for (d = displays; d; d = d->d_next)
+ if ((d != display) && (d->d_fore == w))
+ break;
+ debug3("%s %s autolock on win %d\n",
+ D_user->u_name, d?"keeps":"releases", w->w_number);
+ if (!d)
+ {
+ w->w_wlockuser = NULL;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+void
+SetForeWindow(wi)
+struct win *wi;
+{
+ struct win *p, **pp;
+ struct layer *l;
+ /*
+ * If we come from another window, make it inactive.
+ */
+ if (display)
+ {
+ fore = D_fore;
+ if (fore)
+ {
+ ReleaseAutoWritelock(display, fore);
+ /* deactivate old window. */
+ if (fore->w_tstamp.seconds)
+ fore->w_tstamp.lastio = Now;
+ D_other = fore;
+ fore->w_active = 0;
+ fore->w_display = 0;
+ }
+ else
+ {
+ /* put all the display layers on the window. */
+ for (l = D_lay; l; l = l->l_next)
+ if (l->l_next == &BlankLayer)
+ {
+ l->l_next = wi->w_lay;
+ wi->w_lay = D_lay;
+ for (l = D_lay; l != wi->w_lay; l = l->l_next)
+ l->l_block |= wi->w_lay->l_block;
+ break;
+ }
+ }
+ D_fore = wi;
+ if (D_other == wi)
+ D_other = 0;
+ D_lay = wi->w_lay;
+ D_layfn = D_lay->l_layfn;
+ if ((wi->w_wlock == WLOCK_AUTO) &&
+#ifdef MULTIUSER
+ !AclCheckPermWin(D_user, ACL_WRITE, wi) &&
+#endif
+ !wi->w_wlockuser)
+ {
+ debug2("%s obtained auto writelock for window %d\n",
+ D_user->u_name, wi->w_number);
+ wi->w_wlockuser = D_user;
+ }
+ }
+ fore = wi;
+ fore->w_display = display;
+ if (!fore->w_lay)
+ fore->w_active = 1;
+ /*
+ * Place the window at the head of the most-recently-used list.
+ */
+ for (pp = &windows; (p = *pp); pp = &p->w_next)
+ if (p == wi)
+ break;
+ ASSERT(p);
+ *pp = p->w_next;
+ p->w_next = windows;
+ windows = p;
+}
+
+static int
+NextWindow()
+{
+ register struct win **pp;
+ int n = fore ? fore->w_number : 0;
+
+ for (pp = wtab + n + 1; pp != wtab + n; pp++)
+ {
+ if (pp == wtab + MAXWIN)
+ pp = wtab;
+ if (*pp)
+ break;
+ }
+ return pp - wtab;
+}
+
+static int
+PreviousWindow()
+{
+ register struct win **pp;
+ int n = fore ? fore->w_number : MAXWIN - 1;
+
+ for (pp = wtab + n - 1; pp != wtab + n; pp--)
+ {
+ if (pp < wtab)
+ pp = wtab + MAXWIN - 1;
+ if (*pp)
+ break;
+ }
+ return pp - wtab;
+}
+
+static int
+MoreWindows()
+{
+ if (windows && windows->w_next)
+ return 1;
+ if (fore == 0)
+ {
+ Msg(0, "No window available");
+ return 0;
+ }
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You cannot escape from window %d!", fore->w_number);
+ else
+#endif
+ Msg(0, "No other window.");
+ return 0;
+}
+
+void
+KillWindow(wi)
+struct win *wi;
+{
+ struct win **pp, *p;
+
+ display = wi->w_display;
+ if (display)
+ {
+ if (wi == D_fore)
+ {
+ RemoveStatus();
+ if (D_lay != &wi->w_winlay)
+ ExitOverlayPage();
+ D_fore = 0;
+ D_lay = &BlankLayer;
+ D_layfn = BlankLayer.l_layfn;
+ }
+ }
+
+ for (pp = &windows; (p = *pp); pp = &p->w_next)
+ if (p == wi)
+ break;
+ ASSERT(p);
+ *pp = p->w_next;
+ /*
+ * Remove window from linked list.
+ */
+ wi->w_inlen = 0;
+ wtab[wi->w_number] = 0;
+ FreeWindow(wi);
+ /*
+ * If the foreground window disappeared check the head of the linked list
+ * of windows for the most recently used window. If no window is alive at
+ * all, exit.
+ */
+ if (display && D_fore)
+ return;
+ if (windows == 0)
+ Finit(0);
+ SwitchWindow(windows->w_number);
+}
+
+static void
+LogToggle(on)
+int on;
+{
+ char buf[1024];
+
+ if ((fore->w_logfp != 0) == on)
+ {
+ if (display && !*rc_name)
+ Msg(0, "You are %s logging.", on ? "already" : "not");
+ return;
+ }
+ strncpy(buf, MakeWinMsg(screenlogfile, fore, '%'), 1023);
+ buf[1023] = 0;
+ if (fore->w_logfp != NULL)
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You put away your scroll of logging named \"%s\".", buf);
+ else
+#endif
+ Msg(0, "Logfile \"%s\" closed.", buf);
+ fclose(fore->w_logfp);
+ fore->w_logfp = NULL;
+ return;
+ }
+ if ((fore->w_logfp = secfopen(buf, "a")) == NULL)
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You don't seem to have a scroll of logging named \"%s\".", buf);
+ else
+#endif
+ Msg(errno, "Error opening logfile \"%s\"", buf);
+ return;
+ }
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You %s your scroll of logging named \"%s\".",
+ ftell(fore->w_logfp) ? "add to" : "start writing on", buf);
+ else
+#endif
+ Msg(0, "%s logfile \"%s\"", ftell(fore->w_logfp) ? "Appending to" : "Creating", buf);
+}
+
+void
+ShowWindows()
+{
+ char buf[1024];
+ register char *s, *ss;
+ register struct win **pp, *p;
+ register char *cmd;
+
+ ASSERT(display);
+ s = ss = buf;
+ for (pp = wtab; pp < wtab + MAXWIN; pp++)
+ {
+ if ((p = *pp) == 0)
+ continue;
+
+ cmd = p->w_title;
+ if (s - buf + strlen(cmd) > sizeof(buf) - 6)
+ break;
+ if (s > buf)
+ {
+ *s++ = ' ';
+ *s++ = ' ';
+ }
+ sprintf(s, "%d", p->w_number);
+ s += strlen(s);
+ if (p == fore)
+ {
+ ss = s;
+ *s++ = '*';
+ }
+ else if (p == D_other)
+ *s++ = '-';
+ if (p->w_display && p->w_display != display)
+ *s++ = '&';
+ if (p->w_monitor == MON_DONE || p->w_monitor == MON_MSG)
+ *s++ = '@';
+ if (p->w_bell == BELL_DONE || p->w_bell == BELL_MSG)
+ *s++ = '!';
+#ifdef UTMPOK
+ if (p->w_slot != (slot_t) 0 && p->w_slot != (slot_t) -1)
+ *s++ = '$';
+#endif
+ if (p->w_logfp != NULL)
+ {
+ strcpy(s, "(L)");
+ s += 3;
+ }
+ if (p->w_ptyfd < 0)
+ *s++ = 'Z';
+ *s++ = ' ';
+ strcpy(s, cmd);
+ s += strlen(s);
+ if (p == fore)
+ {
+ /*
+ * this is usually done by Activate(), but when looking
+ * on your current window, you may get annoyed, as there is still
+ * that temporal '!' and '@' displayed.
+ * So we remove that after displaying it once.
+ */
+ p->w_bell = BELL_OFF;
+ if (p->w_monitor != MON_OFF)
+ p->w_monitor = MON_ON;
+ }
+ }
+ *s++ = ' ';
+ *s = '\0';
+ if (ss - buf > D_width / 2)
+ {
+ ss -= D_width / 2;
+ if (s - ss < D_width)
+ {
+ ss = s - D_width;
+ if (ss < buf)
+ ss = buf;
+ }
+ }
+ else
+ ss = buf;
+ Msg(0, "%s", ss);
+}
+
+
+static void
+ShowTime()
+{
+ char buf[512];
+ struct tm *tp;
+ time_t now;
+
+ (void) time(&now);
+ tp = localtime(&now);
+ sprintf(buf, "%2d:%02d:%02d %s", tp->tm_hour, tp->tm_min, tp->tm_sec,
+ HostName);
+#ifdef LOADAV
+ AddLoadav(buf + strlen(buf));
+#endif /* LOADAV */
+ Msg(0, "%s", buf);
+}
+
+static void
+ShowInfo()
+{
+ char buf[512], *p;
+ register struct win *wp = fore;
+ register int i;
+
+ if (wp == 0)
+ {
+ Msg(0, "(%d,%d)/(%d,%d) no window", D_x + 1, D_y + 1, D_width, D_height);
+ return;
+ }
+#ifdef COPY_PASTE
+ sprintf(buf, "(%d,%d)/(%d,%d)+%d %c%sflow %cins %corg %cwrap %capp %clog %cmon %cr",
+#else
+ sprintf(buf, "(%d,%d)/(%d,%d) %c%sflow %cins %corg %cwrap %capp %clog %cmon %cr",
+#endif
+ wp->w_x + 1, wp->w_y + 1, wp->w_width, wp->w_height,
+#ifdef COPY_PASTE
+ wp->w_histheight,
+#endif
+ (wp->w_flow & FLOW_NOW) ? '+' : '-',
+ (wp->w_flow & FLOW_AUTOFLAG) ? "" : ((wp->w_flow & FLOW_AUTO) ? "(+)" : "(-)"),
+ wp->w_insert ? '+' : '-', wp->w_origin ? '+' : '-',
+ wp->w_wrap ? '+' : '-', wp->w_keypad ? '+' : '-',
+ (wp->w_logfp != NULL) ? '+' : '-',
+ (wp->w_monitor != MON_OFF) ? '+' : '-',
+ wp->w_norefresh ? '-' : '+');
+ if (D_CC0 || (D_CS0 && *D_CS0))
+ {
+ p = buf + strlen(buf);
+ if (wp->w_gr)
+ sprintf(p++, " G%c%c [", wp->w_Charset + '0', wp->w_CharsetR + '0');
+ else
+ sprintf(p, " G%c [", wp->w_Charset + '0');
+ p += 5;
+ for (i = 0; i < 4; i++)
+ {
+ if (wp->w_charsets[i] == ASCII)
+ *p++ = 'B';
+ else if (wp->w_charsets[i] >= ' ')
+ *p++ = wp->w_charsets[i];
+ else
+ {
+ *p++ = '^';
+ *p++ = wp->w_charsets[i] ^ 0x40;
+ }
+ }
+ *p++ = ']';
+#ifdef KANJI
+ strcpy(p, wp->w_kanji == EUC ? " euc" : wp->w_kanji == SJIS ? " sjis" : "");
+ p += strlen(p);
+#endif
+ *p = 0;
+ }
+ Msg(0, "%s", buf);
+}
+
+
+static void
+AKAfin(buf, len)
+char *buf;
+int len;
+{
+ ASSERT(display);
+ if (len && fore)
+ ChangeAKA(fore, buf, 20);
+}
+
+static void
+InputAKA()
+{
+ Input("Set window's title to: ", 20, AKAfin, INP_COOKED);
+}
+
+static void
+Colonfin(buf, len)
+char *buf;
+int len;
+{
+ if (len)
+ RcLine(buf);
+}
+
+static void
+InputColon()
+{
+ Input(":", 100, Colonfin, INP_COOKED);
+}
+
+static void
+SelectFin(buf, len)
+char *buf;
+int len;
+{
+ int n;
+
+ if (!len || !display)
+ return;
+ if ((n = WindowByNoN(buf)) < 0)
+ return;
+ SwitchWindow(n);
+}
+
+static void
+InputSelect()
+{
+ Input("Switch to window: ", 20, SelectFin, INP_COOKED);
+}
+
+static char setenv_var[31];
+
+
+static void
+SetenvFin1(buf, len)
+char *buf;
+int len;
+{
+ if (!len || !display)
+ return;
+ InputSetenv(buf);
+}
+
+static void
+SetenvFin2(buf, len)
+char *buf;
+int len;
+{
+ struct action act;
+ char *args[3];
+
+ if (!len || !display)
+ return;
+ act.nr = RC_SETENV;
+ args[0] = setenv_var;
+ args[1] = buf;
+ args[2] = NULL;
+ act.args = args;
+ debug2("SetenvFin2: setenv '%s' '%s'\n", setenv_var, buf);
+ DoAction(&act, -1);
+}
+
+static void
+InputSetenv(arg)
+char *arg;
+{
+ static char setenv_buf[80]; /* need to be static here, cannot be freed */
+
+ if (arg)
+ {
+ strncpy(setenv_var, arg, 30);
+ sprintf(setenv_buf, "Enter value for %s: ", arg);
+ Input(setenv_buf, 30, SetenvFin2, INP_COOKED);
+ }
+ else
+ Input("Setenv: Enter variable name: ", 30, SetenvFin1, INP_COOKED);
+}
+
+void
+DoScreen(fn, av)
+char *fn, **av;
+{
+ struct NewWindow nwin;
+ register int num;
+ char buf[20];
+ char termbuf[25];
+
+ nwin = nwin_undef;
+ termbuf[0] = '\0';
+ while (av && *av && av[0][0] == '-')
+ {
+ if (av[0][1] == '-')
+ {
+ av++;
+ break;
+ }
+ switch (av[0][1])
+ {
+ case 'f':
+ switch (av[0][2])
+ {
+ case 'n':
+ case '0':
+ nwin.flowflag = FLOW_NOW * 0;
+ break;
+ case 'y':
+ case '1':
+ case '\0':
+ nwin.flowflag = FLOW_NOW * 1;
+ break;
+ case 'a':
+ nwin.flowflag = FLOW_AUTOFLAG;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 'k':
+ case 't':
+ if (av[0][2])
+ nwin.aka = &av[0][2];
+ else if (*++av)
+ nwin.aka = *av;
+ else
+ --av;
+ break;
+ case 'T':
+ if (av[0][2])
+ nwin.term = &av[0][2];
+ else if (*++av)
+ nwin.term = *av;
+ else
+ --av;
+ break;
+ case 'h':
+ if (av[0][2])
+ nwin.histheight = atoi(av[0] + 2);
+ else if (*++av)
+ nwin.histheight = atoi(*av);
+ else
+ --av;
+ break;
+#ifdef LOGOUTOK
+ case 'l':
+ switch (av[0][2])
+ {
+ case 'n':
+ case '0':
+ nwin.lflag = 0;
+ break;
+ case 'y':
+ case '1':
+ case '\0':
+ nwin.lflag = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+#endif
+ case 'a':
+ nwin.aflag = 1;
+ break;
+ case 'M':
+ nwin.monitor = MON_ON;
+ break;
+ default:
+ Msg(0, "%s: screen: invalid option -%c.", fn, av[0][1]);
+ break;
+ }
+ ++av;
+ }
+ num = 0;
+ if (av && *av && IsNumColon(*av, 10, buf, sizeof(buf)))
+ {
+ if (*buf != '\0')
+ nwin.aka = buf;
+ num = atoi(*av);
+ if (num < 0 || num > MAXWIN - 1)
+ {
+ Msg(0, "%s: illegal screen number %d.", fn, num);
+ num = 0;
+ }
+ nwin.StartAt = num;
+ ++av;
+ }
+ if (av && *av)
+ {
+ nwin.args = av;
+ if (!nwin.aka)
+ nwin.aka = Filename(*av);
+ }
+ MakeWindow(&nwin);
+}
+
+#ifdef COPY_PASTE
+/*
+ * CompileKeys must be called before Markroutine is first used.
+ * to initialise the keys with defaults, call CompileKeys(NULL, mark_key_tab);
+ *
+ * s is an ascii string in a termcap-like syntax. It looks like
+ * "j=u:k=d:l=r:h=l: =.:" and so on...
+ * this example rebinds the cursormovement to the keys u (up), d (down),
+ * l (left), r (right). placing a mark will now be done with ".".
+ */
+int
+CompileKeys(s, array)
+char *s, *array;
+{
+ int i;
+ unsigned char key, value;
+
+ if (!s || !*s)
+ {
+ for (i = 0; i < 256; i++)
+ array[i] = i;
+ return 0;
+ }
+ debug1("CompileKeys: '%s'\n", s);
+ while (*s)
+ {
+ s = ParseChar(s, (char *) &key);
+ if (!s || *s != '=')
+ return -1;
+ do
+ {
+ s = ParseChar(++s, (char *) &value);
+ if (!s)
+ return -1;
+ array[value] = key;
+ }
+ while (*s == '=');
+ if (!*s)
+ break;
+ if (*s++ != ':')
+ return -1;
+ }
+ return 0;
+}
+#endif /* COPY_PASTE */
+
+/*
+ * Asynchronous input functions
+ */
+
+#ifdef POW_DETACH
+static void
+pow_detach_fn(buf, len)
+char *buf;
+int len;
+{
+ if (len)
+ {
+ *buf = 0;
+ return;
+ }
+ if (ktab[(int)(unsigned char)*buf].nr != RC_POW_DETACH)
+ {
+ if (display)
+ write(D_userfd, "\007", 1);
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "The blast of disintegration whizzes by you!");
+#endif
+ }
+ else
+ Detach(D_POWER);
+}
+#endif /* POW_DETACH */
+
+#ifdef COPY_PASTE
+static void
+copy_reg_fn(buf, len)
+char *buf;
+int len;
+{
+ struct plop *pp = plop_tab + (int)(unsigned char)*buf;
+
+ if (len)
+ {
+ *buf = 0;
+ return;
+ }
+ if (pp->buf)
+ free(pp->buf);
+ if ((pp->buf = (char *)malloc(D_user->u_copylen)) == NULL)
+ {
+ Msg(0, strnomem);
+ return;
+ }
+ bcopy(D_user->u_copybuffer, pp->buf, D_user->u_copylen);
+ pp->len = D_user->u_copylen;
+ Msg(0, "Copied %d characters into register %c", D_user->u_copylen, *buf);
+}
+
+static void
+ins_reg_fn(buf, len)
+char *buf;
+int len;
+{
+ struct plop *pp = plop_tab + (int)(unsigned char)*buf;
+
+
+ if (!fore)
+ return; /* Input() should not call us w/o fore, but you never know... */
+ if (*buf == '.')
+ Msg(0, "ins_reg_fn: Warning: pasting real register '.'!");
+ if (len)
+ {
+ *buf = 0;
+ return;
+ }
+ if (pp->buf)
+ {
+ if (fore->w_pastebuf)
+ free(fore->w_pastebuf);
+ fore->w_pastebuf = 0;
+ fore->w_pasteptr = pp->buf;
+ fore->w_pastelen = pp->len;
+ return;
+ }
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "Nothing happens.");
+ else
+#endif
+ Msg(0, "Empty register.");
+}
+#endif /* COPY_PASTE */
+
+static void
+process_fn(buf, len)
+char *buf;
+int len;
+{
+ struct plop *pp = plop_tab + (int)(unsigned char)*buf;
+
+ if (len)
+ {
+ *buf = 0;
+ return;
+ }
+ if (pp->buf)
+ {
+ ProcessInput(pp->buf, pp->len);
+ return;
+ }
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "Nothing happens.");
+ else
+#endif
+ Msg(0, "Empty register.");
+}
+
+
+#ifdef PASSWORD
+
+/* ARGSUSED */
+static void
+pass1(buf, len)
+char *buf;
+int len;
+{
+ strncpy(Password, buf, sizeof(Password) - 1);
+ Input("Retype new password:", sizeof(Password) - 1, pass2, 1);
+}
+
+/* ARGSUSED */
+static void
+pass2(buf, len)
+char *buf;
+int len;
+{
+ int st;
+ char salt[2];
+
+ if (buf == 0 || strcmp(Password, buf))
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "[ Passwords don't match - your armor crumbles away ]");
+ else
+#endif /* NETHACK */
+ Msg(0, "[ Passwords don't match - checking turned off ]");
+ CheckPassword = 0;
+ }
+ if (Password[0] == '\0')
+ {
+ Msg(0, "[ No password - no secure ]");
+ CheckPassword = 0;
+ }
+ for (st = 0; st < 2; st++)
+ salt[st] = 'A' + (int)((time(0) >> 6 * st) % 26);
+ strncpy(Password, crypt(Password, salt), sizeof(Password) - 1);
+ if (CheckPassword)
+ {
+#ifdef COPY_PASTE
+ if (D_user->u_copybuffer)
+ UserFreeCopyBuffer(D_user);
+ D_user->u_copylen = strlen(Password);
+ if ((D_user->u_copybuffer = (char *) malloc(D_user->u_copylen + 1)) == NULL)
+ {
+ Msg(0, strnomem);
+ D_user->u_copylen = 0;
+ }
+ else
+ {
+ strcpy(D_user->u_copybuffer, Password);
+ Msg(0, "[ Password moved into copybuffer ]");
+ }
+#else /* COPY_PASTE */
+ Msg(0, "[ Crypted password is \"%s\" ]", Password);
+#endif /* COPY_PASTE */
+ }
+ if (buf)
+ bzero(buf, strlen(buf));
+}
+#endif /* PASSWORD */
+
+static void
+digraph_fn(buf, len)
+char *buf;
+int len;
+{
+ int ch, i, x;
+
+ ch = buf[len];
+ if (ch)
+ {
+ if (ch < ' ' || ch == '\177')
+ return;
+ if (len && *buf == '0')
+ {
+ if (ch < '0' || ch > '7')
+ {
+ buf[len] = '\001'; /* ignore */
+ return;
+ }
+ if (len == 3)
+ buf[len] = '\n';
+ return;
+ }
+ if (len == 1)
+ buf[len] = '\n';
+ return;
+ }
+ buf[len] = buf[len + 1]; /* gross */
+ len++;
+ if (len < 2)
+ return;
+ if (buf[0] == '0')
+ {
+ x = 0;
+ for (i = 1; i < len; i++)
+ {
+ if (buf[i] < '0' || buf[i] > '7')
+ break;
+ x = x * 8 | (buf[i] - '0');
+ }
+ }
+ else
+ {
+ for (i = 0; i < sizeof(digraphs)/sizeof(*digraphs); i++)
+ if ((digraphs[i][0] == (unsigned char)buf[0] && digraphs[i][1] == (unsigned char)buf[1]) ||
+ (digraphs[i][0] == (unsigned char)buf[1] && digraphs[i][1] == (unsigned char)buf[0]))
+ break;
+ if (i == sizeof(digraphs)/sizeof(*digraphs))
+ {
+ Msg(0, "Unknown digraph");
+ return;
+ }
+ x = digraphs[i][2];
+ }
+ i = 1;
+ *buf = x;
+ while(i)
+ Process(&buf, &i);
+}
diff --git a/pty.c b/pty.c
new file mode 100644
index 0000000..b2d43a5
--- /dev/null
+++ b/pty.c
@@ -0,0 +1,331 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: pty.c,v 1.6 1994/05/31 12:32:44 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "config.h"
+#include "screen.h"
+
+#ifndef sun
+#include <sys/ioctl.h>
+#endif
+
+#if defined(sun) && defined(LOCKPTY) && !defined(TIOCEXCL)
+#include <sys/ttold.h>
+#endif
+
+#ifdef ISC
+# include <sys/tty.h>
+# include <sys/sioctl.h>
+# include <sys/pty.h>
+#endif
+
+#ifdef sgi
+# include <sys/sysmacros.h>
+#endif /* sgi */
+
+#include "extern.h"
+
+/*
+ * if no PTYRANGE[01] is in the config file, we pick a default
+ */
+#ifndef PTYRANGE0
+# define PTYRANGE0 "qpr"
+#endif
+#ifndef PTYRANGE1
+# define PTYRANGE1 "0123456789abcdef"
+#endif
+
+extern int eff_uid;
+
+/* used for opening a new pty-pair: */
+static char PtyName[32], TtyName[32];
+
+#if !(defined(sequent) || defined(_SEQUENT_) || defined(SVR4))
+# ifdef hpux
+static char PtyProto[] = "/dev/ptym/ptyXY";
+static char TtyProto[] = "/dev/pty/ttyXY";
+# else
+static char PtyProto[] = "/dev/ptyXY";
+static char TtyProto[] = "/dev/ttyXY";
+# endif /* hpux */
+#endif
+
+static void initpty __P((int));
+
+/*
+ * Open all ptys with O_NOCTTY, just to be on the safe side
+ * (RISCos mips breaks otherwise)
+ */
+#ifndef O_NOCTTY
+# define O_NOCTTY 0
+#endif
+
+/***************************************************************/
+
+static void
+initpty(f)
+int f;
+{
+#ifdef POSIX
+ tcflush(f, TCIOFLUSH);
+#else
+# ifdef TIOCFLUSH
+ (void) ioctl(f, TIOCFLUSH, (char *) 0);
+# endif
+#endif
+#ifdef LOCKPTY
+ (void) ioctl(f, TIOCEXCL, (char *) 0);
+#endif
+}
+
+/***************************************************************/
+
+#if defined(OSX) && !defined(PTY_DONE)
+#define PTY_DONE
+int
+OpenPTY(ttyn)
+char **ttyn;
+{
+ register int f;
+ if ((f = open_controlling_pty(TtyName)) < 0)
+ return -1;
+ initpty(f);
+ *ttyn = TtyName;
+ return f;
+#endif
+
+/***************************************************************/
+
+#if (defined(sequent) || defined(_SEQUENT_)) && !defined(PTY_DONE)
+#define PTY_DONE
+int
+OpenPTY(ttyn)
+char **ttyn;
+{
+ char *m, *s;
+ register int f;
+
+ if ((f = getpseudotty(&s, &m)) < 0)
+ return -1;
+#ifdef _SEQUENT_
+ fvhangup(s);
+#endif
+ strncpy(PtyName, m, sizeof(PtyName));
+ strncpy(TtyName, s, sizeof(TtyName));
+ initpty(f);
+ *ttyn = TtyName;
+ return f;
+}
+#endif
+
+/***************************************************************/
+
+#if defined(__sgi) && !defined(PTY_DONE)
+#define PTY_DONE
+int
+OpenPTY(ttyn)
+char **ttyn;
+{
+ int f;
+ char *name;
+ sigret_t (*sigcld)__P(SIGPROTOARG);
+
+ /*
+ * SIGCHLD set to SIG_DFL for _getpty() because it may fork() and
+ * exec() /usr/adm/mkpts
+ */
+ sigcld = signal(SIGCHLD, SIG_DFL);
+ name = _getpty(&f, O_RDWR | O_NONBLOCK, 0600, 0);
+ signal(SIGCHLD, sigcld);
+
+ if (name == 0)
+ return -1;
+ initpty(f);
+ *ttyn = name;
+ return f;
+}
+#endif
+
+/***************************************************************/
+
+#if defined(MIPS) && defined(HAVE_DEV_PTC) && !defined(PTY_DONE)
+#define PTY_DONE
+int
+OpenPTY(ttyn)
+char **ttyn;
+{
+ register int f;
+ struct stat buf;
+
+ strcpy(PtyName, "/dev/ptc");
+ if ((f = open(PtyName, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0)
+ return -1;
+ if (fstat(f, &buf) < 0)
+ {
+ close(f);
+ return -1;
+ }
+ sprintf(TtyName, "/dev/ttyq%d", minor(buf.st_rdev));
+ initpty(f);
+ *ttyn = TtyName;
+ return f;
+}
+#endif
+
+/***************************************************************/
+
+#if defined(SVR4) && !defined(PTY_DONE)
+#define PTY_DONE
+int
+OpenPTY(ttyn)
+char **ttyn;
+{
+ register int f;
+ char *m, *ptsname();
+ int unlockpt __P((int)), grantpt __P((int));
+ sigret_t (*sigcld)__P(SIGPROTOARG);
+
+ strcpy(PtyName, "/dev/ptmx");
+ if ((f = open(PtyName, O_RDWR | O_NOCTTY)) == -1)
+ return -1;
+
+ /*
+ * SIGCHLD set to SIG_DFL for grantpt() because it fork()s and
+ * exec()s pt_chmod
+ */
+ sigcld = signal(SIGCHLD, SIG_DFL);
+ if ((m = ptsname(f)) == NULL || grantpt(f) || unlockpt(f))
+ {
+ signal(SIGCHLD, sigcld);
+ close(f);
+ return -1;
+ }
+ signal(SIGCHLD, sigcld);
+ strncpy(TtyName, m, sizeof(TtyName));
+ initpty(f);
+ *ttyn = TtyName;
+ return f;
+}
+#endif
+
+/***************************************************************/
+
+#if defined(_AIX) && defined(HAVE_DEV_PTC) && !defined(PTY_DONE)
+#define PTY_DONE
+
+#ifdef _IBMR2
+int aixhack = -1;
+#endif
+
+int
+OpenPTY(ttyn)
+char **ttyn;
+{
+ register int f;
+
+ /* a dumb looking loop replaced by mycrofts code: */
+ strcpy (PtyName, "/dev/ptc");
+ if ((f = open (PtyName, O_RDWR | O_NOCTTY)) < 0)
+ return -1;
+ strncpy(TtyName, ttyname(f), sizeof(TtyName));
+ if (eff_uid && access(TtyName, R_OK | W_OK))
+ {
+ close(f);
+ return -1;
+ }
+ initpty(f);
+# ifdef _IBMR2
+ if (aixhack >= 0)
+ close(aixhack);
+ if ((aixhack = open(TtyName, O_RDWR | O_NOCTTY)) < 0)
+ {
+ close(f);
+ return -1;
+ }
+# endif
+ *ttyn = TtyName;
+ return f;
+}
+#endif
+
+/***************************************************************/
+
+#ifndef PTY_DONE
+int
+OpenPTY(ttyn)
+char **ttyn;
+{
+ register char *p, *q, *l, *d;
+ register int f;
+
+ debug("OpenPTY: Using BSD style ptys.\n");
+ strcpy(PtyName, PtyProto);
+ strcpy(TtyName, TtyProto);
+ for (p = PtyName; *p != 'X'; p++)
+ ;
+ for (q = TtyName; *q != 'X'; q++)
+ ;
+ for (l = PTYRANGE0; (*p = *l) != '\0'; l++)
+ {
+ for (d = PTYRANGE1; (p[1] = *d) != '\0'; d++)
+ {
+ debug1("OpenPTY tries '%s'\n", PtyName);
+ if ((f = open(PtyName, O_RDWR | O_NOCTTY)) == -1)
+ continue;
+ q[0] = *l;
+ q[1] = *d;
+ if (eff_uid && access(TtyName, R_OK | W_OK))
+ {
+ close(f);
+ continue;
+ }
+#if defined(sun) && defined(TIOCGPGRP) && !defined(SUNOS3)
+ /* Hack to ensure that the slave side of the pty is
+ * unused. May not work in anything other than SunOS4.1
+ */
+ {
+ int pgrp;
+
+ /* tcgetpgrp does not work (uses TIOCGETPGRP)! */
+ if (ioctl(f, TIOCGPGRP, (char *)&pgrp) != -1 || errno != EIO)
+ {
+ close(f);
+ continue;
+ }
+ }
+#endif
+ initpty(f);
+ *ttyn = TtyName;
+ return f;
+ }
+ }
+ return -1;
+}
+#endif
diff --git a/putenv.c b/putenv.c
new file mode 100644
index 0000000..728cd4c
--- /dev/null
+++ b/putenv.c
@@ -0,0 +1,213 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+/*
+ * putenv -- put value into environment
+ *
+ * Usage: i = putenv (string)
+ * int i;
+ * char *string;
+ *
+ * where string is of the form <name>=<value>.
+ * If "value" is 0, then "name" will be deleted from the environment.
+ * Putenv returns 0 normally, -1 on error (not enough core for malloc).
+ *
+ * Putenv may need to add a new name into the environment, or to
+ * associate a value longer than the current value with a particular
+ * name. So, to make life simpler, putenv() copies your entire
+ * environment into the heap (i.e. malloc()) from the stack
+ * (i.e. where it resides when your process is initiated) the first
+ * time you call it.
+ *
+ * HISTORY
+ * 3-Sep-91 Michael Schroeder (mlschroe). Modified to behave as
+ * as putenv.
+ * 16-Aug-91 Tim MacKenzie (tym) at Monash University. Modified for
+ * use in screen (iScreen) (ignores final int parameter)
+ * 14-Oct-85 Michael Mauldin (mlm) at Carnegie-Mellon University
+ * Ripped out of CMU lib for Rob-O-Matic portability
+ * 20-Nov-79 Steven Shafer (sas) at Carnegie-Mellon University
+ * Created for VAX. Too bad Bell Labs didn't provide this. It's
+ * unfortunate that you have to copy the whole environment onto the
+ * heap, but the bookkeeping-and-not-so-much-copying approach turns
+ * out to be much hairier. So, I decided to do the simple thing,
+ * copying the entire environment onto the heap the first time you
+ * call putenv(), then doing realloc() uniformly later on.
+ */
+#include "rcs.h"
+RCS_ID("$Id: putenv.c,v 1.1.1.1 1993/06/16 23:51:15 jnweiger Exp $ FAU")
+
+#include "config.h"
+
+#ifdef NEEDPUTENV
+
+#if defined(__STDC__)
+# define __P(a) a
+#else
+# define __P(a) ()
+#endif
+
+char *malloc __P((int));
+char *realloc __P((char *, int));
+void free __P((char *));
+int sprintf __P((char *, char *, ...));
+
+#define EXTRASIZE 5 /* increment to add to env. size */
+
+static int envsize = -1; /* current size of environment */
+extern char **environ; /* the global which is your env. */
+
+static int findenv(); /* look for a name in the env. */
+static int newenv(); /* copy env. from stack to heap */
+static int moreenv(); /* incr. size of env. */
+
+int
+unsetenv(name)
+char *name;
+{
+ register int i;
+
+ if (envsize < 0)
+ { /* first time putenv called */
+ if (newenv() < 0) /* copy env. to heap */
+ return -1;
+ }
+ i = findenv(name);
+ if (i < 0)
+ return 0; /* Already here */
+
+ free(environ[i]);
+ if (envsize > 0)
+ envsize--;
+ for (; environ[i]; i++)
+ environ[i] = environ[i+1];
+ return 0; /* Already here */
+}
+
+int
+putenv(string)
+char *string;
+{
+ register int i;
+ register char *p;
+
+ if (envsize < 0)
+ { /* first time putenv called */
+ if (newenv() < 0) /* copy env. to heap */
+ return -1;
+ }
+
+ i = findenv(string); /* look for name in environment */
+
+ if (i < 0)
+ { /* name must be added */
+ for (i = 0; environ[i]; i++);
+ if (i >= (envsize - 1))
+ { /* need new slot */
+ if (moreenv() < 0)
+ return -1;
+ }
+ p = malloc(strlen(string) + 1);
+ if (p == 0) /* not enough core */
+ return -1;
+ environ[i + 1] = 0; /* new end of env. */
+ }
+ else
+ { /* name already in env. */
+ p = realloc(environ[i], strlen(string) + 1);
+ if (p == 0)
+ return -1;
+ }
+ sprintf(p, "%s", string); /* copy into env. */
+ environ[i] = p;
+
+ return 0;
+}
+
+static int
+findenv(name)
+char *name;
+{
+ register char *namechar, *envchar;
+ register int i, found;
+
+ found = 0;
+ for (i = 0; environ[i] && !found; i++)
+ {
+ envchar = environ[i];
+ namechar = name;
+ while (*namechar && *namechar != '=' && (*namechar == *envchar))
+ {
+ namechar++;
+ envchar++;
+ }
+ found = ((*namechar == '\0' || *namechar == '=') && *envchar == '=');
+ }
+ return found ? i - 1 : -1;
+}
+
+static int
+newenv()
+{
+ register char **env, *elem;
+ register int i, esize;
+
+ for (i = 0; environ[i]; i++)
+ ;
+ esize = i + EXTRASIZE + 1;
+ env = (char **)malloc(esize * sizeof (elem));
+ if (env == 0)
+ return -1;
+
+ for (i = 0; environ[i]; i++)
+ {
+ elem = malloc(strlen(environ[i]) + 1);
+ if (elem == 0)
+ return -1;
+ env[i] = elem;
+ strcpy(elem, environ[i]);
+ }
+
+ env[i] = 0;
+ environ = env;
+ envsize = esize;
+ return 0;
+}
+
+static int
+moreenv()
+{
+ register int esize;
+ register char **env;
+
+ esize = envsize + EXTRASIZE;
+ env = (char **)realloc((char *)environ, esize * sizeof (*env));
+ if (env == 0)
+ return -1;
+ environ = env;
+ envsize = esize;
+ return 0;
+}
+
+#endif /* NEEDPUTENV */
+
diff --git a/rcs.h b/rcs.h
new file mode 100644
index 0000000..2f69cd3
--- /dev/null
+++ b/rcs.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ * $Id: rcs.h,v 1.1.1.1 1993/06/16 23:51:16 jnweiger Exp $ FAU
+ */
+
+/*
+ * rcs.h
+ *
+ * jw 9.2.92
+ **************************************************
+ * RCS_ID("$Id: rcs.h,v 1.1.1.1 1993/06/16 23:51:16 jnweiger Exp $ FAU");
+ */
+
+#ifndef __RCS_H__
+# define __RCS_H__
+
+# if !defined(lint)
+# ifdef __GNUC__
+# define RCS_ID(id) static char *rcs_id() { return rcs_id(id); }
+# else
+# define RCS_ID(id) static char *rcs_id = id;
+# endif /* !__GNUC__ */
+# else
+# define RCS_ID(id) /* Nothing */
+# endif /* !lint */
+
+#endif /* __RCS_H__ */
diff --git a/resize.c b/resize.c
new file mode 100644
index 0000000..9a21c81
--- /dev/null
+++ b/resize.c
@@ -0,0 +1,750 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: resize.c,v 1.5 1994/05/31 12:32:47 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+#include <signal.h>
+#ifndef sun
+#include <sys/ioctl.h>
+#endif
+
+#ifdef ISC
+# include <sys/tty.h>
+# include <sys/sioctl.h>
+# include <sys/pty.h>
+#endif
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+
+static void CheckMaxSize __P((int));
+static void FreeMline __P((struct mline *));
+static int AllocMline __P((struct mline *ml, int));
+static void MakeBlankLine __P((char *, int));
+
+extern struct display *display, *displays;
+extern char *blank, *null;
+extern struct mline mline_blank, mline_null, mline_old;
+extern struct win *windows;
+extern int Z0width, Z1width;
+
+#ifdef NETHACK
+extern int nethackflag;
+#endif
+
+#if defined(TIOCGWINSZ) || defined(TIOCSWINSZ)
+ struct winsize glwz;
+#endif
+
+static struct mline mline_zero = {
+ (char *)0,
+ (char *)0,
+ (char *)0
+#ifdef COLOR
+ ,(char *)0
+#endif
+};
+
+/*
+ * ChangeFlag: 0: try to modify no window
+ * 1: modify fore (and try to modify no D_other) + redisplay
+ * 2: modify all windows
+ *
+ * Note: Activate() is only called if change_flag == 1
+ * i.e. on a WINCH event
+ */
+
+void
+CheckScreenSize(change_flag)
+int change_flag;
+{
+ int wi, he;
+ struct win *p;
+ struct layer *oldlay;
+
+ if (display == 0)
+ {
+ debug("CheckScreenSize: No display -> no check.\n");
+ return;
+ }
+ oldlay = D_lay;
+#ifdef TIOCGWINSZ
+ if (ioctl(D_userfd, TIOCGWINSZ, (char *)&glwz) != 0)
+ {
+ debug2("CheckScreenSize: ioctl(%d, TIOCGWINSZ) errno %d\n", D_userfd, errno);
+ wi = D_CO;
+ he = D_LI;
+ }
+ else
+ {
+ wi = glwz.ws_col;
+ he = glwz.ws_row;
+ if (wi == 0)
+ wi = D_CO;
+ if (he == 0)
+ he = D_LI;
+ }
+#else
+ wi = D_CO;
+ he = D_LI;
+#endif
+
+ debug2("CheckScreenSize: screen is (%d,%d)\n", wi, he);
+
+ if (change_flag == 2)
+ {
+ debug("Trying to adapt all windows (-A)\n");
+ for (p = windows; p; p = p->w_next)
+ if (p->w_display == 0 || p->w_display == display)
+ ChangeWindowSize(p, wi, he, p->w_histheight);
+ }
+ if (D_width == wi && D_height == he)
+ {
+ debug("CheckScreenSize: No change -> return.\n");
+ return;
+ }
+ ChangeScreenSize(wi, he, change_flag);
+ if (change_flag == 1)
+ Activate(D_fore ? D_fore->w_norefresh : 0);
+ if (D_lay != oldlay)
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "KAABLAMM!!! You triggered a land mine!");
+ else
+#endif
+ Msg(0, "Aborted because of window size change.");
+ }
+}
+
+void
+ChangeScreenSize(wi, he, change_fore)
+int wi, he;
+int change_fore;
+{
+ struct win *p;
+ int wwi;
+
+ if (D_width == wi && D_height == he)
+ {
+ debug("ChangeScreenSize: no change\n");
+ return;
+ }
+ debug2("ChangeScreenSize from (%d,%d) ", D_width, D_height);
+ debug3("to (%d,%d) (change_fore: %d)\n",wi, he, change_fore);
+ D_width = wi;
+ D_height = he;
+
+ CheckMaxSize(wi);
+ if (D_CWS)
+ {
+ D_defwidth = D_CO;
+ D_defheight = D_LI;
+ }
+ else
+ {
+ if (D_CZ0 && (wi == Z0width || wi == Z1width) &&
+ (D_CO == Z0width || D_CO == Z1width))
+ D_defwidth = D_CO;
+ else
+ D_defwidth = wi;
+ D_defheight = he;
+ }
+ debug2("Default size: (%d,%d)\n", D_defwidth, D_defheight);
+ if (change_fore)
+ DoResize(wi, he);
+ if (D_CWS == NULL && displays->d_next == 0)
+ {
+ /* adapt all windows - to be removed ? */
+ for (p = windows; p; p = p->w_next)
+ {
+ debug1("Trying to change window %d.\n", p->w_number);
+ wwi = wi;
+ if (D_CZ0 && (wi == Z0width || wi == Z1width))
+ {
+ if (p->w_width > (Z0width + Z1width) / 2)
+ wwi = Z0width;
+ else
+ wwi = Z1width;
+ }
+ ChangeWindowSize(p, wwi, he, p->w_histheight);
+ }
+ }
+}
+
+void
+DoResize(wi, he)
+int wi, he;
+{
+ struct layer *oldlay;
+ int q = 0;
+
+ for(;;)
+ {
+ oldlay = D_lay;
+ for (; D_lay; D_lay = D_lay->l_next)
+ {
+ D_layfn = D_lay->l_layfn;
+ if ((q = Resize(wi, he)))
+ break;
+ }
+ D_lay = oldlay;
+ D_layfn = D_lay->l_layfn;
+ if (q == 0)
+ break;
+ ExitOverlayPage();
+ }
+}
+
+
+static void
+FreeMline(ml)
+struct mline *ml;
+{
+ if (ml->image)
+ free(ml->image);
+ if (ml->attr && ml->attr != null)
+ free(ml->attr);
+ if (ml->font && ml->font != null)
+ free(ml->font);
+#ifdef COLOR
+ if (ml->color && ml->color != null)
+ free(ml->color);
+#endif
+ *ml = mline_zero;
+}
+
+static int
+AllocMline(ml, w)
+struct mline *ml;
+int w;
+{
+ ml->image = malloc(w);
+ ml->attr = null;
+ ml->font = null;
+#ifdef COLOR
+ ml->color = null;
+#endif
+ if (ml->image == 0)
+ return -1;
+ return 0;
+}
+
+
+static int
+BcopyMline(mlf, xf, mlt, xt, l, w)
+struct mline *mlf, *mlt;
+int xf, xt, l, w;
+{
+ int r = 0;
+
+ bcopy(mlf->image + xf, mlt->image + xt, l);
+ if (mlf->attr != null && mlt->attr == null)
+ {
+ if ((mlt->attr = malloc(w)) == 0)
+ mlt->attr = null, r = -1;
+ bzero(mlt->attr, w);
+ }
+ if (mlt->attr != null)
+ bcopy(mlf->attr + xf, mlt->attr + xt, l);
+ if (mlf->font != null && mlt->font == null)
+ {
+ if ((mlt->font = malloc(w)) == 0)
+ mlt->font = null, r = -1;
+ bzero(mlt->font, w);
+ }
+ if (mlt->font != null)
+ bcopy(mlf->font + xf, mlt->font + xt, l);
+#ifdef COLOR
+ if (mlf->color != null && mlt->color == null)
+ {
+ if ((mlt->color = malloc(w)) == 0)
+ mlt->color = null, r = -1;
+ bzero(mlt->color, w);
+ }
+ if (mlt->color != null)
+ bcopy(mlf->color + xf, mlt->color + xt, l);
+#endif
+ return r;
+}
+
+
+static int maxwidth;
+
+static void
+CheckMaxSize(wi)
+int wi;
+{
+ char *oldnull = null;
+ struct win *p;
+ int i;
+ struct mline *ml;
+
+ wi = ((wi + 1) + 255) & ~255;
+ if (wi <= maxwidth)
+ return;
+ maxwidth = wi;
+ debug1("New maxwidth: %d\n", maxwidth);
+ if (blank == 0)
+ blank = malloc((unsigned) maxwidth);
+ else
+ blank = xrealloc(blank, maxwidth);
+ if (null == 0)
+ null = malloc((unsigned) maxwidth);
+ else
+ null = xrealloc(null, maxwidth);
+ if (mline_old.image == 0)
+ mline_old.image = malloc((unsigned) maxwidth);
+ else
+ mline_old.image = xrealloc(mline_old.image, maxwidth);
+ if (mline_old.attr == 0)
+ mline_old.attr = malloc((unsigned) maxwidth);
+ else
+ mline_old.attr = xrealloc(mline_old.attr, maxwidth);
+ if (mline_old.font == 0)
+ mline_old.font = malloc((unsigned) maxwidth);
+ else
+ mline_old.font = xrealloc(mline_old.font, maxwidth);
+#ifdef COLOR
+ if (mline_old.color == 0)
+ mline_old.color = malloc((unsigned) maxwidth);
+ else
+ mline_old.color = xrealloc(mline_old.color, maxwidth);
+ if (!(blank && null && mline_old.image && mline_old.attr
+ && mline_old.font && mline_old.color))
+ {
+ Panic(0, "Out of memory -> Game over!!");
+ /*NOTREACHED*/
+ }
+#else
+ if (!(blank && null && mline_old.image && mline_old.attr
+ && mline_old.font))
+ {
+ Panic(0, "Out of memory -> Game over!!");
+ /*NOTREACHED*/
+ }
+#endif
+ MakeBlankLine(blank, maxwidth);
+ bzero(null, maxwidth);
+
+ mline_blank.image = blank;
+ mline_blank.attr = null;
+ mline_blank.font = null;
+ mline_null.image = null;
+ mline_null.attr = null;
+ mline_null.font = null;
+#ifdef COLOR
+ mline_blank.color = null;
+ mline_null.color = null;
+#endif
+
+ /* We have to run through all windows to substitute
+ * the null references.
+ */
+ for (p = windows; p; p = p->w_next)
+ {
+ ml = p->w_mlines;
+ for (i = 0; i < p->w_height; i++, ml++)
+ {
+ if (ml->attr == oldnull)
+ ml->attr = null;
+ if (ml->font == oldnull)
+ ml->font = null;
+#ifdef COLOR
+ if (ml->color== oldnull)
+ ml->color= null;
+#endif
+ }
+#ifdef COPY_PASTE
+ ml = p->w_hlines;
+ for (i = 0; i < p->w_histheight; i++, ml++)
+ {
+ if (ml->attr == oldnull)
+ ml->attr = null;
+ if (ml->font == oldnull)
+ ml->font = null;
+# ifdef COLOR
+ if (ml->color== oldnull)
+ ml->color= null;
+# endif
+ }
+#endif
+ }
+}
+
+
+char *
+xrealloc(mem, len)
+char *mem;
+int len;
+{
+ register char *nmem;
+
+ if ((nmem = realloc(mem, len)))
+ return nmem;
+ free(mem);
+ return (char *)0;
+}
+
+static void
+MakeBlankLine(p, n)
+register char *p;
+register int n;
+{
+ while (n--)
+ *p++ = ' ';
+}
+
+
+
+
+#ifdef COPY_PASTE
+
+#define OLDWIN(y) ((y < p->w_histheight) \
+ ? &p->w_hlines[(p->w_histidx + y) % p->w_histheight] \
+ : &p->w_mlines[y - p->w_histheight])
+
+#define NEWWIN(y) ((y < hi) ? &nhlines[y] : &nmlines[y - hi])
+
+#else
+
+#define OLDWIN(y) (&p->w_mlines[y])
+#define NEWWIN(y) (&nmlines[y])
+
+#endif
+
+
+int
+ChangeWindowSize(p, wi, he, hi)
+struct win *p;
+int wi, he, hi;
+{
+ struct mline *mlf = 0, *mlt = 0, *ml, *nmlines, *nhlines;
+ int fy, ty, l, lx, lf, lt, yy, oty, addone;
+ int ncx, ncy, naka, t;
+
+ if (wi == 0)
+ he = hi = 0;
+
+ if (p->w_width == wi && p->w_height == he && p->w_histheight == hi)
+ {
+ debug("ChangeWindowSize: No change.\n");
+ return 0;
+ }
+
+ CheckMaxSize(wi);
+
+ /* just in case ... */
+ if (wi && (p->w_width != wi || p->w_height != he) && p->w_lay != &p->w_winlay)
+ {
+ debug("ChangeWindowSize: No resize because of overlay?\n");
+ return -1;
+ }
+
+ debug("ChangeWindowSize");
+ debug3(" from (%d,%d)+%d", p->w_width, p->w_height, p->w_histheight);
+ debug3(" to(%d,%d)+%d\n", wi, he, hi);
+
+ fy = p->w_histheight + p->w_height - 1;
+ ty = hi + he - 1;
+
+ nmlines = nhlines = 0;
+ ncx = 0;
+ ncy = 0;
+ naka = 0;
+
+ if (wi)
+ {
+ if (wi != p->w_width || he != p->w_height)
+ {
+ if ((nmlines = (struct mline *)calloc(he, sizeof(struct mline))) == 0)
+ {
+ KillWindow(p);
+ Msg(0, strnomem);
+ return -1;
+ }
+ }
+ else
+ {
+ debug1("image stays the same: %d lines\n", he);
+ nmlines = p->w_mlines;
+ fy -= he;
+ ty -= he;
+ ncx = p->w_x;
+ ncy = p->w_y;
+ naka = p->w_autoaka;
+ }
+ }
+#ifdef COPY_PASTE
+ if (hi)
+ {
+ if ((nhlines = (struct mline *)calloc(hi, sizeof(struct mline))) == 0)
+ {
+ Msg(0, "No memory for history buffer - turned off");
+ hi = 0;
+ ty = he - 1;
+ }
+ }
+#endif
+
+ /* special case: cursor is at magic margin position */
+ addone = 0;
+ if (p->w_width && p->w_x == p->w_width)
+ {
+ debug2("Special addone case: %d %d\n", p->w_x, p->w_y);
+ addone = 1;
+ p->w_x--;
+ }
+
+ debug2("fy %d ty %d\n", fy, ty);
+ if (fy >= 0)
+ mlf = OLDWIN(fy);
+ if (ty >= 0)
+ mlt = NEWWIN(ty);
+
+ while (fy >= 0 && ty >= 0)
+ {
+ if (p->w_width == wi)
+ {
+ /* here is a simple shortcut: just copy over */
+ *mlt = *mlf;
+ *mlf = mline_zero;
+ if (fy == p->w_y + p->w_histheight)
+ {
+ ncx = p->w_x + addone;
+ ncy = ty - hi >= 0 ? ty - hi : 0;
+ }
+ if (p->w_autoaka > 0 && fy == p->w_autoaka - 1 + p->w_histheight)
+ naka = ty - hi >= 0 ? 1 + ty - hi : 0;
+ if (--fy >= 0)
+ mlf = OLDWIN(fy);
+ if (--ty >= 0)
+ mlt = NEWWIN(ty);
+ continue;
+ }
+
+ /* calculate lenght */
+ for (l = p->w_width - 1; l > 0; l--)
+ if (mlf->image[l] != ' ' || mlf->attr[l])
+ break;
+ if (fy == p->w_y + p->w_histheight && l < p->w_x)
+ l = p->w_x; /* cursor is non blank */
+ l++;
+ lf = l;
+
+ /* add wrapped lines to length */
+ for (yy = fy - 1; yy >= 0; yy--)
+ {
+ ml = OLDWIN(yy);
+ if (ml->image[p->w_width] == ' ')
+ break;
+ l += p->w_width;
+ }
+
+ /* rewrap lines */
+ lt = (l - 1) % wi + 1; /* lf is set above */
+ oty = ty;
+ while (l > 0 && fy >= 0 && ty >= 0)
+ {
+ lx = lt > lf ? lf : lt;
+ if (mlt->image == 0)
+ {
+ if (AllocMline(mlt, wi + 1))
+ goto nomem;
+ MakeBlankLine(mlt->image + lt, wi - lt);
+ mlt->image[wi] = ((oty == ty) ? ' ' : 0);
+ }
+ if (BcopyMline(mlf, lf - lx, mlt, lt - lx, lx, wi + 1))
+ goto nomem;
+
+ /* did we copy the cursor ? */
+ if (fy == p->w_y + p->w_histheight && lf - lx <= p->w_x && lf > p->w_x)
+ {
+ ncx = p->w_x + lt - lf + addone;
+ ncy = ty - hi >= 0 ? ty - hi : 0;
+ }
+ /* did we copy autoaka line ? */
+ if (p->w_autoaka > 0 && fy == p->w_autoaka - 1 + p->w_histheight && lf - lx <= 0)
+ naka = ty - hi >= 0 ? 1 + ty - hi : 0;
+
+ lf -= lx;
+ lt -= lx;
+ l -= lx;
+ if (lf == 0)
+ {
+ FreeMline(mlf);
+ lf = p->w_width;
+ if (--fy >= 0)
+ mlf = OLDWIN(fy);
+ }
+ if (lt == 0)
+ {
+ lt = wi;
+ if (--ty >= 0)
+ mlt = NEWWIN(ty);
+ }
+ }
+ ASSERT(l != 0 || fy == yy);
+ }
+ while (fy >= 0)
+ {
+ FreeMline(mlf);
+ if (--fy >= 0)
+ mlf = OLDWIN(fy);
+ }
+ while (ty >= 0)
+ {
+ if (AllocMline(mlt, wi + 1))
+ goto nomem;
+ MakeBlankLine(mlt->image, wi + 1);
+ if (--ty >= 0)
+ mlt = NEWWIN(ty);
+ }
+
+#ifdef DEBUG
+ if (nmlines != p->w_mlines)
+ for (fy = 0; fy < p->w_height + p->w_histheight; fy++)
+ {
+ ml = OLDWIN(fy);
+ ASSERT(ml->image == 0);
+ }
+#endif
+
+ if (p->w_mlines && p->w_mlines != nmlines)
+ free((char *)p->w_mlines);
+ p->w_mlines = nmlines;
+#ifdef COPY_PASTE
+ if (p->w_hlines && p->w_hlines != nhlines)
+ free((char *)p->w_hlines);
+ p->w_hlines = nhlines;
+#endif
+ nmlines = nhlines = 0;
+
+ /* change tabs */
+ if (p->w_width != wi)
+ {
+ if (wi)
+ {
+ if (p->w_tabs == 0)
+ {
+ /* tabs get wi+1 because 0 <= x <= wi */
+ p->w_tabs = malloc((unsigned) wi + 1);
+ t = 8;
+ }
+ else
+ {
+ p->w_tabs = xrealloc(p->w_tabs, wi + 1);
+ t = p->w_width;
+ }
+ if (p->w_tabs == 0)
+ {
+ nomem:
+ if (nmlines)
+ {
+ for (ty = he + hi - 1; ty >= 0; ty--)
+ {
+ mlt = NEWWIN(ty);
+ FreeMline(mlt);
+ }
+ if (nmlines && p->w_mlines != nmlines)
+ free((char *)nmlines);
+#ifdef COPY_PASTE
+ if (nhlines && p->w_hlines != nhlines)
+ free((char *)nhlines);
+#endif
+ }
+ KillWindow(p);
+ Msg(0, strnomem);
+ return -1;
+ }
+ for (t = (t + 7) & 8; t < wi; t += 8)
+ p->w_tabs[t] = 1;
+ }
+ else
+ {
+ if (p->w_tabs)
+ free(p->w_tabs);
+ p->w_tabs = 0;
+ }
+ }
+
+ /* Change w_Saved_y - this is only an estimate... */
+ p->w_Saved_y += ncy - p->w_y;
+
+ p->w_x = ncx;
+ p->w_y = ncy;
+ if (p->w_autoaka > 0)
+ p->w_autoaka = naka;
+
+ /* do sanity checks */
+ if (p->w_x > wi)
+ p->w_x = wi;
+ if (p->w_y >= he)
+ p->w_y = he - 1;
+ if (p->w_Saved_x > wi)
+ p->w_Saved_x = wi;
+ if (p->w_Saved_y < 0)
+ p->w_Saved_y = 0;
+ if (p->w_Saved_y >= he)
+ p->w_Saved_y = he - 1;
+
+ /* reset scrolling region */
+ p->w_top = 0;
+ p->w_bot = he - 1;
+
+ /* signal new size to window */
+#ifdef TIOCSWINSZ
+ if (wi && (p->w_width != wi || p->w_height != he) && p->w_ptyfd >= 0 && p->w_pid)
+ {
+ glwz.ws_col = wi;
+ glwz.ws_row = he;
+ debug("Setting pty winsize.\n");
+ if (ioctl(p->w_ptyfd, TIOCSWINSZ, (char *)&glwz))
+ debug2("SetPtySize: errno %d (fd:%d)\n", errno, p->w_ptyfd);
+ }
+#endif /* TIOCSWINSZ */
+
+ /* store new size */
+ p->w_width = wi;
+ p->w_height = he;
+#ifdef COPY_PASTE
+ p->w_histidx = 0;
+ p->w_histheight = hi;
+#endif
+
+#ifdef DEBUG
+ /* Test if everything was ok */
+ for (fy = 0; fy < p->w_height + p->w_histheight; fy++)
+ {
+ ml = OLDWIN(fy);
+ ASSERT(ml->image);
+ for (l = 0; l < p->w_width; l++)
+ ASSERT((unsigned char)ml->image[l] >= ' ');
+ }
+#endif
+ return 0;
+}
+
diff --git a/screen.c b/screen.c
new file mode 100644
index 0000000..fcb11e4
--- /dev/null
+++ b/screen.c
@@ -0,0 +1,2605 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: screen.c,v 1.23 1994/05/31 12:32:51 mlschroe Exp $ FAU")
+
+
+#include <sys/types.h>
+#include <ctype.h>
+
+#include <fcntl.h>
+
+#ifdef sgi
+# include <sys/sysmacros.h>
+#endif
+
+#include <sys/stat.h>
+#ifndef sun
+# include <sys/ioctl.h>
+#endif
+
+#ifndef SIGINT
+# include <signal.h>
+#endif
+
+#include "config.h"
+
+#ifdef SVR4
+# include <sys/stropts.h>
+#endif
+
+#if defined(SYSV) && !defined(ISC)
+# include <sys/utsname.h>
+#endif
+
+#if defined(sequent) || defined(SVR4)
+# include <sys/resource.h>
+#endif /* sequent || SVR4 */
+
+#ifdef ISC
+# include <sys/tty.h>
+# include <sys/sioctl.h>
+# include <sys/pty.h>
+#endif /* ISC */
+
+#if (defined(AUX) || defined(_AUX_SOURCE)) && defined(POSIX)
+# include <compat.h>
+#endif
+
+#include "screen.h"
+
+#include "patchlevel.h"
+
+/*
+ * At the moment we only need the real password if the
+ * builtin lock is used. Therefore disable SHADOWPW if
+ * we do not really need it (kind of security thing).
+ */
+#ifndef LOCK
+# undef SHADOWPW
+#endif
+
+#include <pwd.h>
+#ifdef SHADOWPW
+# include <shadow.h>
+#endif /* SHADOWPW */
+
+
+#ifdef DEBUG
+FILE *dfp;
+#endif
+
+
+extern char *blank, *null, Term[], screenterm[], **environ, Termcap[];
+int force_vt = 1, assume_LP = 0;
+int VBellWait, MsgWait, MsgMinWait, SilenceWait;
+
+extern struct plop plop_tab[];
+extern struct user *users;
+extern struct display *displays, *display;
+extern struct layer BlankLayer;
+
+/* tty.c */
+extern int intrc;
+
+
+extern int use_hardstatus;
+#ifdef COPY_PASTE
+extern char mark_key_tab[];
+#endif
+extern char version[];
+extern char DefaultShell[];
+
+
+char *ShellProg;
+char *ShellArgs[2];
+
+extern struct NewWindow nwin_undef, nwin_default, nwin_options;
+
+static void SigChldHandler __P((void));
+static sigret_t SigChld __P(SIGPROTOARG);
+static sigret_t SigInt __P(SIGPROTOARG);
+static sigret_t CoreDump __P(SIGPROTOARG);
+static sigret_t FinitHandler __P(SIGPROTOARG);
+static void DoWait __P((void));
+static void WindowDied __P((struct win *));
+
+
+int nversion; /* numerical version, used for secondary DA */
+
+/* the attacher */
+struct passwd *ppp;
+char *attach_tty;
+char *attach_term;
+char *LoginName;
+struct mode attach_Mode;
+
+char SockPath[MAXPATHLEN];
+char *SockName, *SockMatch; /* SockName is pointer in SockPath */
+int ServerSocket = -1;
+
+char **NewEnv = NULL;
+
+char *RcFileName = NULL;
+extern char Esc;
+char *home;
+
+char *screenlogfile;
+char *hardcopydir = NULL;
+char *BellString;
+char *VisualBellString;
+char *ActivityString;
+#ifdef COPY_PASTE
+char *BufferFile;
+#endif
+#ifdef POW_DETACH
+char *PowDetachString;
+#endif
+int auto_detach = 1;
+int iflag, rflag, dflag, lsflag, quietflag, wipeflag, xflag;
+int adaptflag;
+
+time_t Now;
+
+#ifdef MULTIUSER
+char *multi;
+char *multi_home;
+int multi_uid;
+int own_uid;
+int multiattach;
+int tty_mode;
+int tty_oldmode = -1;
+#endif
+
+char HostName[MAXSTR];
+int MasterPid;
+int real_uid, real_gid, eff_uid, eff_gid;
+int default_startup;
+int slowpaste;
+int ZombieKey_destroy, ZombieKey_resurrect;
+
+#ifdef NETHACK
+int nethackflag = 0;
+#endif
+#ifdef MAPKEYS
+int maptimeout = 300000;
+#endif
+
+
+struct win *fore;
+struct win *windows;
+struct win *console_window;
+
+
+
+/*
+ * Do this last
+ */
+#include "extern.h"
+
+
+#ifdef NETHACK
+char strnomem[] = "Who was that Maude person anyway?";
+#else
+char strnomem[] = "Out of memory.";
+#endif
+
+
+static int InterruptPlease;
+static int GotSigChld;
+
+
+static void
+mkfdsets(rp, wp)
+fd_set *rp, *wp;
+{
+ register struct win *p;
+
+ FD_ZERO(rp);
+ FD_ZERO(wp);
+ for (display = displays; display; display = display->d_next)
+ {
+ if (D_obufp != D_obuf)
+ FD_SET(D_userfd, wp);
+
+ FD_SET(D_userfd, rp); /* Do that always */
+
+ /* read from terminal if there is room in the destination buffer
+ *
+ * Removed, so we can always input a command sequence
+ *
+ * if (D_fore == 0)
+ * continue;
+ * if (W_UWP(D_fore))
+ * {
+ * check pseudowin buffer
+ * if (D_fore->w_pwin->p_inlen < sizeof(D_fore->w_pwin->p_inbuf))
+ * FD_SET(D_userfd, rp);
+ * }
+ * else
+ * {
+ * check window buffer
+ * if (D_fore->w_inlen < sizeof(D_fore->w_inbuf))
+ * FD_SET(D_userfd, rp);
+ * }
+ */
+ }
+ for (p = windows; p; p = p->w_next)
+ {
+ if (p->w_ptyfd < 0)
+ continue;
+#ifdef COPY_PASTE
+ if (p->w_pastelen)
+ {
+ /* paste to win/pseudo */
+# ifdef PSEUDOS
+ FD_SET(W_UWP(p) ? p->w_pwin->p_ptyfd : p->w_ptyfd, wp);
+# else
+ FD_SET(p->w_ptyfd, wp);
+# endif
+ }
+#endif
+ /* query window buffer */
+ if (p->w_inlen > 0)
+ FD_SET(p->w_ptyfd, wp);
+#ifdef PSEUDOS
+ /* query pseudowin buffer */
+ if (p->w_pwin && p->w_pwin->p_inlen > 0)
+ FD_SET(p->w_pwin->p_ptyfd, wp);
+#endif
+
+ display = p->w_display;
+ if (p->w_active && D_status && !D_status_bell && !(use_hardstatus && D_HS))
+ continue;
+ if (p->w_outlen > 0)
+ continue;
+ if (p->w_lay->l_block)
+ continue;
+ /*
+ * Don't accept input from window or pseudowin if there is to much
+ * output pending on display .
+ */
+ if (p->w_active && (D_obufp - D_obuf) > D_obufmax)
+ {
+ debug1("too much output pending, window %d\n", p->w_number);
+ continue;
+ }
+#ifdef PSEUDOS
+ if (W_RW(p))
+ {
+ /* Check free space if we stuff window output in pseudo */
+ if (p->w_pwin && W_WTOP(p) && (p->w_pwin->p_inlen >= sizeof(p->w_pwin->p_inbuf)))
+ {
+ debug2("pseudowin %d buffer full (%d bytes)\n", p->w_number, p->w_pwin->p_inlen);
+ }
+ else
+ FD_SET(p->w_ptyfd, rp);
+ }
+ if (W_RP(p))
+ {
+ /* Check free space if we stuff pseudo output in window */
+ if (W_PTOW(p) && p->w_inlen >= sizeof(p->w_inbuf))
+ {
+ debug2("window %d buffer full (%d bytes)\n", p->w_number, p->w_inlen);
+ }
+ else
+ FD_SET(p->w_pwin->p_ptyfd, rp);
+ }
+#else /* PSEUDOS */
+ FD_SET(p->w_ptyfd, rp);
+#endif /* PSEUDOS */
+ }
+ FD_SET(ServerSocket, rp);
+}
+
+void
+main(ac, av)
+int ac;
+char **av;
+{
+ register int n, len;
+ register struct win *p;
+ char *ap;
+ char *av0;
+ char socknamebuf[2 * MAXSTR];
+ fd_set r, w;
+ int mflag = 0;
+ struct timeval tv;
+ int nsel;
+ char buf[IOSIZE], *myname = (ac == 0) ? "screen" : av[0];
+ char *SockDir;
+ struct stat st;
+ int buflen, tmp;
+#ifdef _MODE_T /* (jw) */
+ mode_t oumask;
+#else
+ int oumask;
+#endif
+#if defined(SYSV) && !defined(ISC)
+ struct utsname utsnam;
+#endif
+ struct NewWindow nwin;
+ int detached = 0; /* start up detached */
+ struct display *ndisplay;
+#ifdef MULTIUSER
+ char *sockp;
+#endif
+#ifdef MAPKEYS
+ int kmaptimeout;
+#endif
+
+#if (defined(AUX) || defined(_AUX_SOURCE)) && defined(POSIX)
+ setcompat(COMPAT_POSIX|COMPAT_BSDPROT); /* turn on seteuid support */
+#endif
+#if defined(sun) && defined(SVR4)
+ {
+ /* Solaris' login blocks SIGHUP! This is _very bad_ */
+ sigset_t sset;
+ sigemptyset(&sset);
+ sigprocmask(SIG_SETMASK, &sset, 0);
+ }
+#endif
+
+ /*
+ * First, close all unused descriptors
+ * (otherwise, we might have problems with the select() call)
+ */
+ closeallfiles(0);
+#ifdef DEBUG
+ {
+ char buf[255];
+
+ sprintf(buf, "%s/screen.%d", DEBUGDIR, getpid());
+ (void) mkdir(DEBUGDIR, 0777);
+ if ((dfp = fopen(buf, "w")) == NULL)
+ dfp = stderr;
+ else
+ (void) chmod(buf, 0666);
+ }
+#endif
+ sprintf(version, "%d.%.2d.%.2d%s (%s) %s", REV, VERS,
+ PATCHLEVEL, STATE, ORIGIN, DATE);
+ nversion = REV * 10000 + VERS * 100 + PATCHLEVEL;
+ debug2("-- screen debug started %s (%s)\n", *av, version);
+#ifdef POSIX
+ debug("POSIX\n");
+#endif
+#ifdef TERMIO
+ debug("TERMIO\n");
+#endif
+#ifdef SYSV
+ debug("SYSV\n");
+#endif
+#ifdef SYSVSIGS
+ debug("SYSVSIGS\n");
+#endif
+#ifdef NAMEDPIPE
+ debug("NAMEDPIPE\n");
+#endif
+#if defined(SIGWINCH) && defined(TIOCGWINSZ)
+ debug("Window changing enabled\n");
+#endif
+#ifdef HAVE_SETREUID
+ debug("SETREUID\n");
+#endif
+#ifdef HAVE_SETEUID
+ debug("SETEUID\n");
+#endif
+#ifdef hpux
+ debug("hpux\n");
+#endif
+#ifdef USEBCOPY
+ debug("USEBCOPY\n");
+#endif
+#ifdef UTMPOK
+ debug("UTMPOK\n");
+#endif
+#ifdef LOADAV
+ debug("LOADAV\n");
+#endif
+#ifdef NETHACK
+ debug("NETHACK\n");
+#endif
+#ifdef TERMINFO
+ debug("TERMINFO\n");
+#endif
+#ifdef SHADOWPW
+ debug("SHADOWPW\n");
+#endif
+#ifdef NAME_MAX
+ debug1("NAME_MAX = %d\n", NAME_MAX);
+#endif
+
+ BellString = SaveStr("Bell in window %");
+ VisualBellString = SaveStr(" Wuff, Wuff!! ");
+ ActivityString = SaveStr("Activity in window %");
+ screenlogfile = SaveStr("screenlog.%n");
+#ifdef COPY_PASTE
+ BufferFile = SaveStr(DEFAULT_BUFFERFILE);
+#endif
+ ShellProg = NULL;
+#ifdef POW_DETACH
+ PowDetachString = 0;
+#endif
+ default_startup = (ac > 1) ? 0 : 1;
+ adaptflag = 0;
+ slowpaste = 0;
+ VBellWait = VBELLWAIT;
+ MsgWait = MSGWAIT;
+ MsgMinWait = MSGMINWAIT;
+ SilenceWait = SILENCEWAIT;
+#ifdef COPY_PASTE
+ CompileKeys((char *)NULL, mark_key_tab);
+#endif
+ nwin = nwin_undef;
+ nwin_options = nwin_undef;
+
+ av0 = *av;
+ /* if this is a login screen, assume -R */
+ if (*av0 == '-')
+ {
+ rflag = 2;
+#ifdef MULTI
+ xflag = 1;
+#endif
+ ShellProg = SaveStr(DefaultShell); /* to prevent nasty circles */
+ }
+ while (ac > 0)
+ {
+ ap = *++av;
+ if (--ac > 0 && *ap == '-')
+ {
+ if (ap[1] == '-' && ap[2] == 0)
+ {
+ av++;
+ ac--;
+ break;
+ }
+ switch (ap[1])
+ {
+ case 'a':
+ nwin_options.aflag = 1;
+ break;
+ case 'A':
+ adaptflag = 1;
+ break;
+ case 'c':
+ if (ap[2])
+ RcFileName = ap + 2;
+ else
+ {
+ if (--ac == 0)
+ exit_with_usage(myname);
+ RcFileName = *++av;
+ }
+ break;
+ case 'e':
+ if (ap[2])
+ ap += 2;
+ else
+ {
+ if (--ac == 0)
+ exit_with_usage(myname);
+ ap = *++av;
+ }
+ if (ParseEscape((struct user *)0, ap))
+ Panic(0, "Two characters are required with -e option.");
+ break;
+ case 'f':
+ switch (ap[2])
+ {
+ case 'n':
+ case '0':
+ nwin_options.flowflag = FLOW_NOW * 0;
+ break;
+ case 'y':
+ case '1':
+ case '\0':
+ nwin_options.flowflag = FLOW_NOW * 1;
+ break;
+ case 'a':
+ nwin_options.flowflag = FLOW_AUTOFLAG;
+ break;
+ default:
+ exit_with_usage(myname);
+ }
+ break;
+ case 'h':
+ if (ap[2])
+ nwin_options.histheight = atoi(ap + 2);
+ else
+ {
+ if (--ac == 0)
+ exit_with_usage(myname);
+ nwin_options.histheight = atoi(*++av);
+ }
+ if (nwin_options.histheight < 0)
+ exit_with_usage(myname);
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ case 't': /* title is a synonym for AkA */
+ case 'k':
+ if (ap[2])
+ nwin_options.aka = ap + 2;
+ else
+ {
+ if (--ac == 0)
+ exit_with_usage(myname);
+ nwin_options.aka = *++av;
+ }
+ break;
+ case 'l':
+ switch (ap[2])
+ {
+ case 'n':
+ case '0':
+ nwin_options.lflag = 0;
+ break;
+ case 'y':
+ case '1':
+ case '\0':
+ nwin_options.lflag = 1;
+ break;
+ case 's':
+ case 'i':
+ lsflag = 1;
+ if (ac > 1)
+ {
+ SockMatch = *++av;
+ ac--;
+ }
+ break;
+ default:
+ exit_with_usage(myname);
+ }
+ break;
+ case 'w':
+ lsflag = 1;
+ wipeflag = 1;
+ break;
+ case 'L':
+ assume_LP = 1;
+ break;
+ case 'm':
+ mflag = 1;
+ break;
+ case 'O':
+ force_vt = 0;
+ break;
+ case 'T':
+ if (ap[2])
+ {
+ if (strlen(ap+2) < 20)
+ strcpy(screenterm, ap + 2);
+ }
+ else
+ {
+ if (--ac == 0)
+ exit_with_usage(myname);
+ if (strlen(*++av) < 20)
+ strcpy(screenterm, *av);
+ }
+ nwin_options.term = screenterm;
+ break;
+ case 'q':
+ quietflag = 1;
+ break;
+ case 'r':
+ case 'R':
+#ifdef MULTI
+ case 'x':
+#endif
+ if (ap[2])
+ {
+ SockMatch = ap + 2;
+ if (ac != 1)
+ exit_with_usage(myname);
+ }
+ else if (ac > 1 && *av[1] != '-')
+ {
+ SockMatch = *++av;
+ ac--;
+ }
+#ifdef MULTI
+ if (ap[1] == 'x')
+ xflag = 1;
+ else
+#endif
+ rflag = (ap[1] == 'r') ? 1 : 2;
+ break;
+#ifdef REMOTE_DETACH
+ case 'd':
+ dflag = 1;
+ /* FALLTHROUGH */
+ case 'D':
+ if (!dflag)
+ dflag = 2;
+ if (ap[2])
+ SockMatch = ap + 2;
+ if (ac == 2)
+ {
+ if (*av[1] != '-')
+ {
+ SockMatch = *++av;
+ ac--;
+ }
+ }
+ break;
+#endif
+ case 's':
+ if (ap[2])
+ {
+ if (ShellProg)
+ free(ShellProg);
+ ShellProg = SaveStr(ap + 2);
+ }
+ else
+ {
+ if (--ac == 0)
+ exit_with_usage(myname);
+ if (ShellProg)
+ free(ShellProg);
+ ShellProg = SaveStr(*++av);
+ }
+ debug1("ShellProg: '%s'\n", ShellProg);
+ break;
+ case 'S':
+ if (ap[2])
+ SockMatch = ap + 2;
+ else
+ {
+ if (--ac == 0)
+ exit_with_usage(myname);
+ SockMatch = *++av;
+ if (!*SockMatch)
+ exit_with_usage(myname);
+ }
+ break;
+ case 'v':
+ Panic(0, "Screen version %s", version);
+ /* NOTREACHED */
+ default:
+ exit_with_usage(myname);
+ }
+ }
+ else
+ break;
+ }
+ if (dflag && mflag && SockMatch && !(rflag || xflag))
+ detached = 1;
+ nwin = nwin_options;
+ if (ac)
+ nwin.args = av;
+ real_uid = getuid();
+ real_gid = getgid();
+ eff_uid = geteuid();
+ eff_gid = getegid();
+ if (eff_uid != real_uid)
+ {
+ /* if running with s-bit, we must install a special signal
+ * handler routine that resets the s-bit, so that we get a
+ * core file anyway.
+ */
+#ifdef SIGBUS /* OOPS, linux has no bus errors ??? */
+ signal(SIGBUS, CoreDump);
+#endif /* SIGBUS */
+ signal(SIGSEGV, CoreDump);
+ }
+
+ /* make the write() calls return -1 on all errors */
+#ifdef SIGXFSZ
+ /*
+ * Ronald F. Guilmette, Oct 29 '94, bug-gnu-utils@prep.ai.mit.edu:
+ * It appears that in System V Release 4, UNIX, if you are writing
+ * an output file and you exceed the currently set file size limit,
+ * you _don't_ just get the call to `write' returning with a
+ * failure code. Rather, you get a signal called `SIGXFSZ' which,
+ * if neither handled nor ignored, will cause your program to crash
+ * with a core dump.
+ */
+ signal(SIGXFSZ, SIG_IGN);
+#endif
+#ifdef SIGPIPE
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ if (!ShellProg)
+ {
+ register char *sh;
+
+ sh = getenv("SHELL");
+ ShellProg = SaveStr(sh ? sh : DefaultShell);
+ }
+ ShellArgs[0] = ShellProg;
+#ifdef NETHACK
+ nethackflag = (getenv("NETHACKOPTIONS") != NULL);
+#endif
+
+#ifdef MULTIUSER
+ own_uid = multi_uid = real_uid;
+ if (SockMatch && (sockp = index(SockMatch, '/')))
+ {
+ if (eff_uid)
+ Panic(0, "Must run suid root for multiuser support.");
+ *sockp = 0;
+ multi = SockMatch;
+ SockMatch = sockp + 1;
+ if (*multi)
+ {
+ struct passwd *mppp;
+ if ((mppp = getpwnam(multi)) == (struct passwd *)0)
+ Panic(0, "Cannot identify account '%s'.", multi);
+ multi_uid = mppp->pw_uid;
+ multi_home = SaveStr(mppp->pw_dir);
+# ifdef MULTI
+ if (rflag || lsflag)
+ {
+ xflag = 1;
+ rflag = 0;
+ }
+# endif
+ detached = 0;
+ multiattach = 1;
+ }
+ }
+ if (SockMatch && *SockMatch == 0)
+ SockMatch = 0;
+#endif /* MULTIUSER */
+
+ if ((LoginName = getlogin()) && LoginName[0] != '\0')
+ {
+ if ((ppp = getpwnam(LoginName)) != (struct passwd *) 0)
+ if (ppp->pw_uid != real_uid)
+ ppp = (struct passwd *) 0;
+ }
+ if (ppp == 0)
+ {
+ if ((ppp = getpwuid(real_uid)) == 0)
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Panic(0, "An alarm sounds through the dungeon...\nWarning, the kops are coming.");
+ else
+#endif
+ Panic(0, "getpwuid() can't identify your account!");
+ exit(1);
+ }
+ LoginName = ppp->pw_name;
+ }
+ /* Do password sanity check..., allow ##user for SUN_C2 security */
+#ifdef SHADOWPW
+pw_try_again:
+#endif
+ n = 0;
+ if (ppp->pw_passwd[0] == '#' && ppp->pw_passwd[1] == '#' &&
+ strcmp(ppp->pw_passwd + 2, ppp->pw_name) == 0)
+ n = 13;
+ for (; n < 13; n++)
+ {
+ char c = ppp->pw_passwd[n];
+ if (!(c == '.' || c == '/' ||
+ (c >= '0' && c <= '9') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z')))
+ break;
+ }
+#ifdef SHADOWPW
+ /* try to determine real password */
+ {
+ static struct spwd *sss;
+ if (n < 13 && sss == 0)
+ {
+ sss = getspnam(ppp->pw_name);
+ if (sss)
+ {
+ ppp->pw_passwd = SaveStr(sss->sp_pwdp);
+ endspent(); /* this should delete all buffers ... */
+ goto pw_try_again;
+ }
+ endspent(); /* this should delete all buffers ... */
+ }
+ }
+#endif
+ if (n < 13)
+ ppp->pw_passwd = 0;
+#ifdef linux
+ if (ppp->pw_passwd && strlen(ppp->pw_passwd) == 13 + 11)
+ ppp->pw_passwd[13] = 0; /* beware of linux's long passwords */
+#endif
+
+ home = getenv("HOME");
+#if !defined(SOCKDIR) && defined(MULTIUSER)
+ if (multi && !multiattach)
+ {
+ if (home && strcmp(home, ppp->pw_dir))
+ Panic(0, "$HOME must match passwd entry for multiuser screens.");
+ }
+#endif
+ if (home == 0 || *home == '\0')
+ home = ppp->pw_dir;
+ if (strlen(LoginName) > 20)
+ Panic(0, "LoginName too long - sorry.");
+ if (strlen(home) > MAXPATHLEN - 25)
+ Panic(0, "$HOME too long - sorry.");
+
+ if (!detached && !lsflag)
+ {
+ /* ttyname implies isatty */
+ if (!(attach_tty = ttyname(0)))
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Panic(0, "You must play from a terminal.");
+ else
+#endif
+ Panic(0, "Must be connected to a terminal.");
+ exit(1);
+ }
+ if (strlen(attach_tty) >= MAXPATHLEN)
+ Panic(0, "TtyName too long - sorry.");
+ if (stat(attach_tty, &st))
+ Panic(errno, "Cannot access '%s'", attach_tty);
+#ifdef MULTIUSER
+ tty_mode = st.st_mode & 0777;
+#endif
+ if ((n = secopen(attach_tty, O_RDWR, 0)) < 0)
+ Panic(0, "Cannot open '%s' - please check.", attach_tty);
+ close(n);
+ debug1("attach_tty is %s\n", attach_tty);
+ if ((attach_term = getenv("TERM")) == 0 || *attach_term == 0)
+ Panic(0, "Please set a terminal type.");
+ if (strlen(attach_term) > sizeof(D_termname) - 1)
+ Panic(0, "$TERM too long - sorry.");
+ GetTTY(0, &attach_Mode);
+#ifdef DEBUGGGGGGGGGGGGGGG
+ DebugTTY(&attach_Mode);
+#endif /* DEBUG */
+ }
+
+#ifdef _MODE_T
+ oumask = umask(0); /* well, unsigned never fails? jw. */
+#else
+ if ((oumask = umask(0)) == -1)
+ Panic(errno, "Cannot change umask to zero");
+#endif
+ if ((SockDir = getenv("ISCREENDIR")) == NULL)
+ SockDir = getenv("SCREENDIR");
+ if (SockDir)
+ {
+ if (strlen(SockDir) >= MAXPATHLEN - 1)
+ Panic(0, "Ridiculously long $(I)SCREENDIR - try again.");
+#ifdef MULTIUSER
+ if (multi)
+ Panic(0, "No $(I)SCREENDIR with multi screens, please.");
+#endif
+ }
+#ifdef MULTIUSER
+ if (multiattach)
+ {
+# ifndef SOCKDIR
+ sprintf(SockPath, "%s/.iscreen", multi_home);
+ SockDir = SockPath;
+# else
+ SockDir = SOCKDIR;
+ sprintf(SockPath, "%s/S-%s", SockDir, multi);
+# endif
+ }
+ else
+#endif
+ {
+#ifndef SOCKDIR
+ if (SockDir == 0)
+ {
+ sprintf(SockPath, "%s/.iscreen", home);
+ SockDir = SockPath;
+ }
+#endif
+ if (SockDir)
+ {
+ if (access(SockDir, F_OK))
+ {
+ debug1("SockDir '%s' missing ...\n", SockDir);
+ if (UserContext() > 0)
+ {
+ if (mkdir(SockDir, 0700))
+ UserReturn(0);
+ UserReturn(1);
+ }
+ if (UserStatus() <= 0)
+ Panic(0, "Cannot make directory '%s'.", SockDir);
+ }
+ if (SockDir != SockPath)
+ strcpy(SockPath, SockDir);
+ }
+#ifdef SOCKDIR
+ else
+ {
+ SockDir = SOCKDIR;
+ if (lstat(SockDir, &st))
+ {
+ if (mkdir(SockDir, eff_uid ? 0777 : 0755) == -1)
+ Panic(errno, "Cannot make directory '%s'", SockDir);
+ }
+ else
+ {
+ if (!S_ISDIR(st.st_mode))
+ Panic(0, "'%s' must be a directory.", SockDir);
+ if (eff_uid == 0 && st.st_uid != eff_uid)
+ Panic(0, "Directory '%s' must be owned by root.", SockDir);
+ n = eff_uid ? 0777 : 0755;
+ if ((st.st_mode & 0777) != n)
+ Panic(0, "Directory '%s' must have mode %03o.", SockDir, n);
+ }
+ sprintf(SockPath, "%s/S-%s", SockDir, LoginName);
+ if (access(SockPath, F_OK))
+ {
+ if (mkdir(SockPath, 0700) == -1)
+ Panic(errno, "Cannot make directory '%s'", SockPath);
+ (void) chown(SockPath, real_uid, real_gid);
+ }
+ }
+#endif
+ }
+
+ if (stat(SockPath, &st) == -1)
+ Panic(errno, "Cannot access %s", SockPath);
+ if (!S_ISDIR(st.st_mode))
+ Panic(0, "%s is not a directory.", SockPath);
+#ifdef MULTIUSER
+ if (multi)
+ {
+ if (st.st_uid != multi_uid)
+ Panic(0, "%s is not the owner of %s.", multi, SockPath);
+ }
+ else
+#endif
+ {
+ if (st.st_uid != real_uid)
+ Panic(0, "You are not the owner of %s.", SockPath);
+ }
+ if ((st.st_mode & 0777) != 0700)
+ Panic(0, "Directory %s must have mode 700.", SockPath);
+ SockName = SockPath + strlen(SockPath) + 1;
+ *SockName = 0;
+ (void) umask(oumask);
+ debug2("SockPath: %s SockMatch: %s\n", SockPath, SockMatch ? SockMatch : "NULL");
+
+#if defined(SYSV) && !defined(ISC)
+ if (uname(&utsnam) == -1)
+ Panic(errno, "uname");
+ strncpy(HostName, utsnam.nodename, sizeof(utsnam.nodename) < MAXSTR ? sizeof(utsnam.nodename) : MAXSTR - 1);
+ HostName[sizeof(utsnam.nodename) < MAXSTR ? sizeof(utsnam.nodename) : MAXSTR - 1] = '\0';
+#else
+ (void) gethostname(HostName, MAXSTR);
+ HostName[MAXSTR - 1] = '\0';
+#endif
+ if ((ap = index(HostName, '.')) != NULL)
+ *ap = '\0';
+
+ if (lsflag)
+ {
+ int i, fo;
+
+#ifdef MULTIUSER
+ if (multi)
+ real_uid = multi_uid;
+#endif
+ setuid(real_uid);
+ setgid(real_gid);
+ eff_uid = real_uid;
+ eff_gid = real_gid;
+ i = FindSocket((int *)NULL, &fo, SockMatch);
+ if (quietflag)
+ exit(10 + i);
+ if (fo == 0)
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Panic(0, "This room is empty (%s).\n", SockPath);
+ else
+#endif /* NETHACK */
+ Panic(0, "No Sockets found in %s.\n", SockPath);
+ }
+ Panic(0, "%d Socket%s in %s.\n", fo, fo > 1 ? "s" : "", SockPath);
+ /* NOTREACHED */
+ }
+ signal(SIG_BYE, AttacherFinit); /* prevent races */
+ if (rflag || xflag)
+ {
+ debug("screen -r: - is there anybody out there?\n");
+ if (Attach(MSG_ATTACH))
+ {
+ Attacher();
+ /* NOTREACHED */
+ }
+ debug("screen -r: backend not responding -- still crying\n");
+ }
+ else if (dflag && !mflag)
+ {
+ (void) Attach(MSG_DETACH);
+ Msg(0, "[%s %sdetached.]\n", SockName, (dflag > 1 ? "power " : ""));
+ eexit(0);
+ /* NOTREACHED */
+ }
+ if (!SockMatch && !mflag)
+ {
+ register char *sty;
+
+ if ((sty = getenv("STY")) != 0 && *sty != '\0')
+ {
+ setuid(real_uid);
+ setgid(real_gid);
+ eff_uid = real_uid;
+ eff_gid = real_gid;
+ nwin_options.args = av;
+ SendCreateMsg(sty, &nwin);
+ exit(0);
+ /* NOTREACHED */
+ }
+ }
+ nwin_compose(&nwin_default, &nwin_options, &nwin_default);
+ switch (MasterPid = fork())
+ {
+ case -1:
+ Panic(errno, "fork");
+ /* NOTREACHED */
+#ifdef FORKDEBUG
+ default:
+ break;
+ case 0:
+ MasterPid = getppid();
+#else
+ case 0:
+ break;
+ default:
+#endif
+ if (detached)
+ exit(0);
+ if (SockMatch)
+ sprintf(socknamebuf, "%d.%s", MasterPid, SockMatch);
+ else
+ sprintf(socknamebuf, "%d.%s.%s", MasterPid, stripdev(attach_tty), HostName);
+ for (ap = socknamebuf; *ap; ap++)
+ if (*ap == '/')
+ *ap = '-';
+#ifdef NAME_MAX
+ if (strlen(socknamebuf) > NAME_MAX)
+ socknamebuf[NAME_MAX] = 0;
+#endif
+ sprintf(SockPath + strlen(SockPath), "/%s", socknamebuf);
+ setuid(real_uid);
+ setgid(real_gid);
+ eff_uid = real_uid;
+ eff_gid = real_gid;
+ Attacher();
+ /* NOTREACHED */
+ }
+
+ ap = av0 + strlen(av0) - 1;
+ while (ap >= av0)
+ {
+ if (!strncmp("screen", ap, 6))
+ {
+ strncpy(ap, "SCREEN", 6); /* name this process "SCREEN-BACKEND" */
+ break;
+ }
+ ap--;
+ }
+ if (ap < av0)
+ *av0 = 'S';
+
+#ifdef DEBUG
+ {
+ char buf[256];
+
+ if (dfp && dfp != stderr)
+ fclose(dfp);
+ sprintf(buf, "%s/SCREEN.%d", DEBUGDIR, getpid());
+ if ((dfp = fopen(buf, "w")) == NULL)
+ dfp = stderr;
+ else
+ (void) chmod(buf, 0666);
+ }
+#endif
+ if (!detached)
+ {
+ /* reopen tty. must do this, because fd 0 may be RDONLY */
+ if ((n = secopen(attach_tty, O_RDWR, 0)) < 0)
+ Panic(0, "Cannot reopen '%s' - please check.", attach_tty);
+ }
+ else
+ n = -1;
+ freopen("/dev/null", "r", stdin);
+ freopen("/dev/null", "w", stdout);
+#ifdef DEBUG
+ if (dfp != stderr)
+#endif
+ freopen("/dev/null", "w", stderr);
+ debug("-- screen.back debug started\n");
+
+ /*
+ * This guarantees that the session owner is listed, even when we
+ * start detached. From now on we should not refer to 'LoginName'
+ * any more, use users->u_name instead.
+ */
+ if (UserAdd(LoginName, (char *)0, (struct user **)0) < 0)
+ Panic(0, "Could not create user info");
+ if (!detached)
+ {
+#ifdef FORKDEBUG
+ if (MakeDisplay(LoginName, attach_tty, attach_term, n, MasterPid, &attach_Mode) == 0)
+#else
+ if (MakeDisplay(LoginName, attach_tty, attach_term, n, getppid(), &attach_Mode) == 0)
+#endif
+ Panic(0, "Could not alloc display");
+ }
+
+ if (SockMatch)
+ {
+ /* user started us with -S option */
+ sprintf(socknamebuf, "%d.%s", (int)getpid(), SockMatch);
+ }
+ else
+ {
+ sprintf(socknamebuf, "%d.%s.%s", (int)getpid(), stripdev(attach_tty),
+ HostName);
+ }
+ for (ap = socknamebuf; *ap; ap++)
+ if (*ap == '/')
+ *ap = '-';
+#ifdef NAME_MAX
+ if (strlen(socknamebuf) > NAME_MAX)
+ {
+ debug2("Socketname %s truncated to %d chars\n", socknamebuf, NAME_MAX);
+ socknamebuf[NAME_MAX] = 0;
+ }
+#endif
+ sprintf(SockPath + strlen(SockPath), "/%s", socknamebuf);
+
+ ServerSocket = MakeServerSocket();
+ InitKeytab();
+#ifdef ETCSCREENRC
+# ifdef ALLOW_SYSSCREENRC
+ if ((ap = getenv("SYSSCREENRC")))
+ StartRc(ap);
+ else
+# endif
+ StartRc(ETCSCREENRC);
+#endif
+ StartRc(RcFileName);
+# ifdef UTMPOK
+# ifndef UTNOKEEP
+ InitUtmp();
+# endif /* UTNOKEEP */
+# endif /* UTMPOK */
+ if (display)
+ {
+ if (InitTermcap(0, 0))
+ {
+ debug("Could not init termcap - exiting\n");
+ fcntl(D_userfd, F_SETFL, 0); /* Flush sets FNBLOCK */
+ freetty();
+ if (D_userpid)
+ Kill(D_userpid, SIG_BYE);
+ eexit(1);
+ }
+ InitTerm(0);
+#ifdef UTMPOK
+ RemoveLoginSlot();
+#endif
+ }
+ else
+ MakeTermcap(1);
+
+#ifdef LOADAV
+ InitLoadav();
+#endif /* LOADAV */
+ MakeNewEnv();
+ signal(SIGHUP, SigHup);
+ signal(SIGINT, FinitHandler);
+ signal(SIGQUIT, FinitHandler);
+ signal(SIGTERM, FinitHandler);
+#ifdef BSDJOBS
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+#endif
+ if (display)
+ {
+ brktty(D_userfd);
+ SetMode(&D_OldMode, &D_NewMode);
+ /* Note: SetMode must be called _before_ FinishRc. */
+ SetTTY(D_userfd, &D_NewMode);
+ if (fcntl(D_userfd, F_SETFL, FNBLOCK))
+ Msg(errno, "Warning: NBLOCK fcntl failed");
+ }
+ else
+ brktty(-1); /* just try */
+#ifdef ETCSCREENRC
+# ifdef ALLOW_SYSSCREENRC
+ if ((ap = getenv("SYSSCREENRC")))
+ FinishRc(ap);
+ else
+# endif
+ FinishRc(ETCSCREENRC);
+#endif
+ FinishRc(RcFileName);
+
+ debug2("UID %d EUID %d\n", getuid(), geteuid());
+ if (windows == NULL)
+ {
+ debug("We open one default window, as screenrc did not specify one.\n");
+ if (MakeWindow(&nwin) == -1)
+ {
+ Msg(0, "Sorry, could not find a PTY.");
+ sleep(5);
+ Finit(0);
+ /* NOTREACHED */
+ }
+ }
+ if (display && default_startup)
+ display_copyright();
+ signal(SIGCHLD, SigChld);
+ signal(SIGINT, SigInt);
+ tv.tv_usec = 0;
+ if (rflag == 2)
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "I can't seem to find a... Hey, wait a minute! Here comes a screen now.");
+ else
+#endif
+ Msg(0, "New screen...");
+ rflag = 0;
+ }
+
+ Now = time((time_t *)0);
+
+ for (;;)
+ {
+ tv.tv_sec = 0;
+ /*
+ * check for silence
+ */
+ for (p = windows; p; p = p->w_next)
+ {
+ int time_left;
+
+ if (p->w_tstamp.seconds == 0)
+ continue;
+ debug1("checking silence win %d\n", p->w_number);
+ time_left = p->w_tstamp.lastio + p->w_tstamp.seconds - Now;
+ if (time_left > 0)
+ {
+ if (tv.tv_sec == 0 || time_left < tv.tv_sec)
+ tv.tv_sec = time_left;
+ }
+ else
+ {
+ for (display = displays; display; display = display->d_next)
+ if (p != D_fore)
+ Msg(0, "Window %d: silence for %d seconds",
+ p->w_number, p->w_tstamp.seconds);
+ p->w_tstamp.lastio = Now;
+ }
+ }
+
+ /*
+ * check to see if message line should be removed
+ */
+ for (display = displays; display; display = display->d_next)
+ {
+ int time_left;
+
+ if (D_status == 0)
+ continue;
+ debug("checking status...\n");
+ time_left = D_status_time + (D_status_bell?VBellWait:MsgWait) - Now;
+ if (time_left > 0)
+ {
+ if (tv.tv_sec == 0 || time_left < tv.tv_sec)
+ tv.tv_sec = time_left;
+ debug(" not yet.\n");
+ }
+ else
+ {
+ debug(" removing now.\n");
+ RemoveStatus();
+ }
+ }
+ /*
+ * check to see if a mapping timeout should happen
+ */
+#ifdef MAPKEYS
+ kmaptimeout = 0;
+ tv.tv_usec = 0;
+ for (display = displays; display; display = display->d_next)
+ if (D_seql)
+ {
+ int j;
+ struct kmap *km;
+
+ km = (struct kmap *)(D_seqp - D_seql - KMAP_SEQ);
+ j = *(D_seqp - 1 + (KMAP_OFF - KMAP_SEQ));
+ if (j == 0)
+ j = D_nseqs - (km - D_kmaps);
+ for (; j; km++, j--)
+ if (km->nr & KMAP_NOTIMEOUT)
+ break;
+ if (j)
+ continue;
+ tv.tv_sec = 0;
+ tv.tv_usec = maptimeout;
+ kmaptimeout = 1;
+ break;
+ }
+#endif
+ /*
+ * check for I/O on all available I/O descriptors
+ */
+#ifdef DEBUG
+ if (tv.tv_sec)
+ debug1("select timeout %d seconds\n", (int)tv.tv_sec);
+#endif
+ mkfdsets(&r, &w);
+ if (GotSigChld && !tv.tv_sec)
+ {
+ SigChldHandler();
+ continue;
+ }
+ if ((nsel = select(FD_SETSIZE, &r, &w, (fd_set *)0, (tv.tv_sec || tv.tv_usec) ? &tv : (struct timeval *) 0)) < 0)
+ {
+ debug1("Bad select - errno %d\n", errno);
+#if defined(sgi) && defined(SVR4)
+ /* Ugly workaround for braindead IRIX5.2 select.
+ * read() should return EIO, not select()!
+ */
+ if (errno == EIO)
+ {
+ debug("IRIX5.2 workaround: searching for bad display\n");
+ for (display = displays; display; )
+ {
+ FD_ZERO(&r);
+ FD_ZERO(&w);
+ FD_SET(D_userfd, &r);
+ FD_SET(D_userfd, &w);
+ tv.tv_sec = tv.tv_usec = 0;
+ if (select(FD_SETSIZE, &r, &w, (fd_set *)0, &tv) == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ SigHup(SIGARG);
+ break;
+ }
+ display = display->d_next;
+ }
+ }
+ else
+#endif
+ if (errno != EINTR)
+ Panic(errno, "select");
+ errno = 0;
+ nsel = 0;
+ }
+#ifdef MAPKEYS
+ else
+ for (display = displays; display; display = display->d_next)
+ {
+ if (D_seql == 0)
+ continue;
+ if ((nsel == 0 && kmaptimeout) || D_seqruns++ * 50000 > maptimeout)
+ {
+ debug1("Flushing map sequence (%d runs)\n", D_seqruns);
+ fore = D_fore;
+ D_seqp -= D_seql;
+ ProcessInput2(D_seqp, D_seql);
+ D_seqp = D_kmaps[0].seq;
+ D_seql = 0;
+ }
+ }
+#endif
+#ifdef SELECT_BROKEN
+ /*
+ * Sequents select emulation counts an descriptor which is
+ * readable and writeable only as one. waaaaa.
+ */
+ if (nsel)
+ nsel = 2 * FD_SETSIZE;
+#endif
+ if (GotSigChld && !tv.tv_sec)
+ {
+ SigChldHandler();
+ continue;
+ }
+ if (InterruptPlease)
+ {
+ debug("Backend received interrupt\n");
+ if (fore)
+ {
+ char ibuf;
+ ibuf = intrc;
+#ifdef PSEUDOS
+ write(W_UWP(fore) ? fore->w_pwin->p_ptyfd : fore->w_ptyfd,
+ &ibuf, 1);
+ debug1("Backend wrote interrupt to %d", fore->w_number);
+ debug1("%s\n", W_UWP(fore) ? " (pseudowin)" : "");
+#else
+ write(fore->w_ptyfd, &ibuf, 1);
+ debug1("Backend wrote interrupt to %d\n", fore->w_number);
+#endif
+ }
+ InterruptPlease = 0;
+ }
+
+ /*
+ * Process a client connect attempt and message
+ */
+ if (nsel && FD_ISSET(ServerSocket, &r))
+ {
+ nsel--;
+ debug("Knock - knock!\n");
+ ReceiveMsg();
+ continue;
+ }
+
+ /*
+ * Write the (already processed) user input to the window
+ * descriptors first. We do not want to choke, if he types fast.
+ */
+ if (nsel)
+ {
+ for (p = windows; p; p = p->w_next)
+ {
+ int pastefd = -1;
+
+ if (p->w_ptyfd < 0)
+ continue;
+#ifdef COPY_PASTE
+ if (p->w_pastelen)
+ {
+ /*
+ * Write the copybuffer contents first, if any.
+ */
+#ifdef PSEUDOS
+ pastefd = W_UWP(p) ? p->w_pwin->p_ptyfd : p->w_ptyfd;
+#else
+ pastefd = p->w_ptyfd;
+#endif
+ if (FD_ISSET(pastefd, &w))
+ {
+ debug1("writing pastebuffer (%d)\n", p->w_pastelen);
+ len = write(pastefd, p->w_pasteptr,
+ (slowpaste > 0) ? 1 :
+ (p->w_pastelen > IOSIZE ?
+ IOSIZE : p->w_pastelen));
+ if (len < 0) /* Problems... window is dead */
+ p->w_pastelen = 0;
+ if (len > 0)
+ {
+ p->w_pasteptr += len;
+ p->w_pastelen -= len;
+ }
+ debug1("%d bytes pasted\n", len);
+ if (p->w_pastelen == 0)
+ {
+ if (p->w_pastebuf)
+ free(p->w_pastebuf);
+ p->w_pastebuf = 0;
+ p->w_pasteptr = 0;
+ pastefd = -1;
+ }
+ if (slowpaste > 0)
+ {
+ struct timeval t;
+
+ debug1("slowpaste %d\n", slowpaste);
+ t.tv_sec = (long) (slowpaste / 1000);
+ t.tv_usec = (long) ((slowpaste % 1000) * 1000);
+ select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
+ }
+ if (--nsel == 0)
+ break;
+ }
+ }
+#endif
+
+#ifdef PSEUDOS
+ if (p->w_pwin && p->w_pwin->p_inlen > 0)
+ {
+ /* stuff w_pwin->p_inbuf into pseudowin */
+ tmp = p->w_pwin->p_ptyfd;
+ if (tmp != pastefd && FD_ISSET(tmp, &w))
+ {
+ if ((len = write(tmp, p->w_pwin->p_inbuf,
+ p->w_pwin->p_inlen)) > 0)
+ {
+ if ((p->w_pwin->p_inlen -= len))
+ bcopy(p->w_pwin->p_inbuf + len, p->w_pwin->p_inbuf,
+ p->w_pwin->p_inlen);
+ }
+ if (--nsel == 0)
+ break;
+ }
+ }
+#endif
+ if (p->w_inlen > 0)
+ {
+ /* stuff w_inbuf buffer into window */
+ tmp = p->w_ptyfd;
+ if (tmp != pastefd && FD_ISSET(tmp, &w))
+ {
+ if ((len = write(tmp, p->w_inbuf, p->w_inlen)) > 0)
+ {
+ if ((p->w_inlen -= len))
+ bcopy(p->w_inbuf + len, p->w_inbuf, p->w_inlen);
+ }
+ if (--nsel == 0)
+ break;
+ }
+ }
+ }
+ }
+
+ Now = time((time_t *)0);
+
+ if (nsel)
+ {
+ for (display = displays; display; display = ndisplay)
+ {
+ int maxlen;
+
+ ndisplay = display->d_next;
+ /*
+ * stuff D_obuf into user's tty
+ */
+ if (FD_ISSET(D_userfd, &w))
+ {
+ int size = OUTPUT_BLOCK_SIZE;
+
+ len = D_obufp - D_obuf;
+ if (len < size)
+ size = len;
+ ASSERT(len >= 0);
+ size = write(D_userfd, D_obuf, size);
+ if (size >= 0)
+ {
+ len -= size;
+ if (len)
+ {
+ bcopy(D_obuf + size, D_obuf, len);
+ debug2("ASYNC: wrote %d - remaining %d\n", size, len);
+ }
+ D_obufp -= size;
+ D_obuffree += size;
+ }
+ else
+ {
+ if (errno != EINTR)
+# ifdef EWOULDBLOCK
+ if (errno != EWOULDBLOCK)
+# endif
+ Msg(errno, "Error writing output to display");
+ }
+ if (--nsel == 0)
+ break;
+ }
+ /*
+ * O.k. All streams are fed, now look what comes back
+ * to us. First of all: user input.
+ */
+ if (! FD_ISSET(D_userfd, &r))
+ continue;
+ if (D_status && !(use_hardstatus && D_HS))
+ RemoveStatus();
+ if (D_fore == 0)
+ maxlen = IOSIZE;
+ else
+ {
+#ifdef PSEUDOS
+ if (W_UWP(D_fore))
+ maxlen = sizeof(D_fore->w_pwin->p_inbuf) - D_fore->w_pwin->p_inlen;
+ else
+#endif
+ maxlen = sizeof(D_fore->w_inbuf) - D_fore->w_inlen;
+ }
+ if (maxlen > IOSIZE)
+ maxlen = IOSIZE;
+ if (maxlen <= 0)
+ maxlen = 1; /* Allow one char for command keys */
+ buflen = read(D_userfd, buf, maxlen);
+ if (buflen < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ debug1("Read error: %d - SigHup()ing!\n", errno);
+ SigHup(SIGARG);
+ sleep(1);
+ }
+ else if (buflen == 0)
+ {
+ debug("Found EOF - SigHup()ing!\n");
+ SigHup(SIGARG);
+ sleep(1);
+ }
+ else
+ {
+ /* This refills inbuf or p_inbuf */
+ ProcessInput(buf, buflen);
+ }
+ if (--nsel == 0)
+ break;
+ }
+ }
+
+ /*
+ * Read and process the output from the window descriptors
+ */
+ for (p = windows; p; p = p->w_next)
+ {
+ if (p->w_lay->l_block)
+ continue;
+ display = p->w_display;
+ if (p->w_outlen)
+ WriteString(p, p->w_outbuf, p->w_outlen);
+ else if (p->w_ptyfd >= 0)
+ {
+#ifdef PSEUDOS
+ /* gather pseudowin output */
+ if (W_RP(p) && nsel && FD_ISSET(p->w_pwin->p_ptyfd, &r))
+ {
+ nsel--;
+ n = 0;
+ if (W_PTOW(p))
+ {
+ /* Window wants a copy of the pseudowin output */
+ tmp = sizeof(p->w_inbuf) - p->w_inlen;
+ ASSERT(tmp > 0);
+ n++;
+ }
+ else
+ tmp = IOSIZE;
+ if ((len = read(p->w_pwin->p_ptyfd, buf, tmp)) <= 0)
+ {
+ if (errno != EINTR)
+#ifdef EWOULDBLOCK
+ if (errno != EWOULDBLOCK)
+#endif
+ {
+ debug2("Window %d: pseudowin read error (errno %d) -- removing pseudowin\n", p->w_number, len ? errno : 0);
+ FreePseudowin(p);
+ }
+ }
+/* HERE WE ASSUME THAT THERE IS NO PACKET MODE ON PSEUDOWINS */
+ else
+ {
+ if (n)
+ {
+ bcopy(buf, p->w_inbuf + p->w_inlen, len);
+ p->w_inlen += len;
+ }
+ WriteString(p, buf, len);
+ }
+ }
+#endif /* PSEUDOS */
+ /* gather window output */
+ if (nsel && FD_ISSET(p->w_ptyfd, &r))
+ {
+ nsel--;
+#ifdef PSEUDOS
+ n = 0;
+ ASSERT(W_RW(p));
+ if (p->w_pwin && W_WTOP(p))
+ {
+ /* Pseudowin wants a copy of the window output */
+ tmp = sizeof(p->w_pwin->p_inbuf) - p->w_pwin->p_inlen;
+ ASSERT(tmp > 0);
+ n++;
+ }
+ else
+#endif
+ tmp = IOSIZE;
+ if ((len = read(p->w_ptyfd, buf, tmp)) <= 0)
+ {
+ if (errno == EINTR)
+ continue;
+#ifdef EWOULDBLOCK
+ if (errno == EWOULDBLOCK)
+ continue;
+#endif
+ debug2("Window %d: read error (errno %d) - killing window\n", p->w_number, len ? errno : 0);
+ WindowDied(p);
+ nsel = 0; /* KillWindow may change window order */
+ break; /* so we just break */
+ }
+#ifdef TIOCPKT
+ if ((p->w_t.flags & TTY_FLAG_PLAIN) == 0)
+ {
+ if (buf[0])
+ {
+ debug1("PAKET %x\n", buf[0]);
+ if (buf[0] & TIOCPKT_NOSTOP)
+ NewAutoFlow(p, 0);
+ if (buf[0] & TIOCPKT_DOSTOP)
+ NewAutoFlow(p, 1);
+ }
+ if (len > 1)
+ {
+#ifdef PSEUDOS
+ if (n)
+ {
+ bcopy(buf + 1,
+ p->w_pwin->p_inbuf + p->w_pwin->p_inlen,
+ len - 1);
+ p->w_pwin->p_inlen += len - 1;
+ }
+#endif
+ WriteString(p, buf + 1, len - 1);
+ }
+ }
+ else
+#endif /* TIOCPKT */
+ {
+ if (len > 0)
+ {
+#ifdef PSEUDOS
+ if (n)
+ {
+ bcopy(buf, p->w_pwin->p_inbuf + p->w_pwin->p_inlen,
+ len);
+ p->w_pwin->p_inlen += len;
+ }
+#endif
+ WriteString(p, buf, len);
+ }
+ }
+ }
+ }
+ if (p->w_bell == BELL_ON)
+ {
+ p->w_bell = BELL_MSG;
+ for (display = displays; display; display = display->d_next)
+ Msg(0, "%s", MakeWinMsg(BellString, p, '%'));
+ if (p->w_monitor == MON_FOUND)
+ p->w_monitor = MON_DONE;
+ }
+ else if (p->w_bell == BELL_VISUAL)
+ {
+ if (display && !D_status_bell)
+ {
+ /*
+ * Stop the '!' appearing in the ^A^W display if it is an
+ * active at the time of the bell. (Tim MacKenzie)
+ */
+ p->w_bell = BELL_OFF;
+ Msg(0, VisualBellString);
+ if (D_status)
+ D_status_bell = 1;
+ }
+ }
+ if (p->w_monitor == MON_FOUND)
+ {
+ p->w_monitor = MON_MSG;
+ for (display = displays; display; display = display->d_next)
+ Msg(0, "%s", MakeWinMsg(ActivityString, p, '%'));
+ }
+ }
+#if defined(DEBUG) && !defined(SELECT_BROKEN)
+ if (nsel)
+ debug1("*** Left over nsel: %d\n", nsel);
+#endif
+ }
+ /* NOTREACHED */
+}
+
+static void
+WindowDied(p)
+struct win *p;
+{
+ if (ZombieKey_destroy)
+ {
+ char buf[100], *s;
+ time_t now;
+
+ (void) time(&now);
+ s = ctime(&now);
+ if (s && *s)
+ s[strlen(s) - 1] = '\0';
+ debug3("window %d (%s) going into zombie state fd %d",
+ p->w_number, p->w_title, p->w_ptyfd);
+#ifdef UTMPOK
+ RemoveUtmp(p);
+#endif
+ (void) chmod(p->w_tty, 0666);
+ (void) chown(p->w_tty, 0, 0);
+ close(p->w_ptyfd);
+ p->w_ptyfd = -1;
+ /* zap saved utmp as the slot may change */
+ bzero((char *)&p->w_savut, sizeof(p->w_savut));
+ p->w_pid = 0;
+ ResetWindow(p);
+ p->w_y = p->w_bot;
+ sprintf(buf, "\n\r=== Window terminated (%s) ===", s ? s : "?");
+ WriteString(p, buf, strlen(buf));
+ }
+ else
+ KillWindow(p);
+}
+
+static void
+SigChldHandler()
+{
+ struct stat st;
+ while (GotSigChld)
+ {
+ GotSigChld = 0;
+ DoWait();
+#ifdef SYSVSIGS
+ signal(SIGCHLD, SigChld);
+#endif
+ }
+ if (stat(SockPath, &st) == -1)
+ {
+ debug1("SigChldHandler: Yuck! cannot stat '%s'\n", SockPath);
+ if (!RecoverSocket())
+ {
+ debug("SCREEN cannot recover from corrupt Socket, bye\n");
+ Finit(1);
+ }
+ else
+ debug1("'%s' reconstructed\n", SockPath);
+ }
+ else
+ debug2("SigChldHandler: stat '%s' o.k. (%03o)\n", SockPath, st.st_mode);
+}
+
+static sigret_t
+SigChld SIGDEFARG
+{
+ debug("SigChld()\n");
+ GotSigChld = 1;
+ SIGRETURN;
+}
+
+sigret_t
+SigHup SIGDEFARG
+{
+ if (display == 0)
+ return;
+ debug("SigHup()\n");
+ if (D_userfd >= 0)
+ {
+ close(D_userfd);
+ D_userfd = -1;
+ }
+ if (auto_detach || displays->d_next)
+ Detach(D_DETACH);
+ else
+ Finit(0);
+ SIGRETURN;
+}
+
+/*
+ * the backend's Interrupt handler
+ * we cannot insert the intrc directly, as we never know
+ * if fore is valid.
+ */
+static sigret_t
+SigInt SIGDEFARG
+{
+#if HAZARDOUS
+ char buf[1];
+
+ debug("SigInt()\n");
+ *buf = (char) intrc;
+ if (fore)
+ fore->w_inlen = 0;
+ if (fore)
+ write(fore->w_ptyfd, buf, 1);
+#else
+ signal(SIGINT, SigInt);
+ debug("SigInt() careful\n");
+ InterruptPlease = 1;
+#endif
+ SIGRETURN;
+}
+
+static sigret_t
+CoreDump SIGDEFARG
+{
+ struct display *disp;
+ char buf[80];
+
+#if defined(SYSVSIGS) && defined(SIGHASARG)
+ signal(sigsig, SIG_IGN);
+#endif
+ setgid(getgid());
+ setuid(getuid());
+ unlink("core");
+#ifdef SIGHASARG
+ sprintf(buf, "\r\n[screen caught signal %d.%s]\r\n", sigsig,
+#else
+ sprintf(buf, "\r\n[screen caught a fatal signal.%s]\r\n",
+#endif
+#if defined(SHADOWPW) && !defined(DEBUG) && !defined(DUMPSHADOW)
+ ""
+#else /* SHADOWPW && !DEBUG */
+ " (core dumped)"
+#endif /* SHADOWPW && !DEBUG */
+ );
+ for (disp = displays; disp; disp = disp->d_next)
+ {
+ fcntl(disp->d_userfd, F_SETFL, 0);
+ write(disp->d_userfd, buf, strlen(buf));
+ Kill(disp->d_userpid, SIG_BYE);
+ }
+#if defined(SHADOWPW) && !defined(DEBUG) && !defined(DUMPSHADOW)
+ Kill(getpid(), SIGKILL);
+ eexit(11);
+#else /* SHADOWPW && !DEBUG */
+ abort();
+#endif /* SHADOWPW && !DEBUG */
+ SIGRETURN;
+}
+
+static void
+DoWait()
+{
+ register int pid;
+ struct win *p, *next;
+#ifdef BSDWAIT
+ union wait wstat;
+#else
+ int wstat;
+#endif
+
+#ifdef BSDJOBS
+# ifndef BSDWAIT
+ while ((pid = waitpid(-1, &wstat, WNOHANG | WUNTRACED)) > 0)
+# else
+# ifdef USE_WAIT2
+ /*
+ * From: rouilj@sni-usa.com (John Rouillard)
+ * note that WUNTRACED is not documented to work, but it is defined in
+ * /usr/include/sys/wait.h, so it may work
+ */
+ while ((pid = wait2(&wstat, WNOHANG | WUNTRACED )) > 0)
+# else /* USE_WAIT2 */
+ while ((pid = wait3(&wstat, WNOHANG | WUNTRACED, (struct rusage *) 0)) > 0)
+# endif /* USE_WAIT2 */
+# endif
+#else /* BSDJOBS */
+ while ((pid = wait(&wstat)) < 0)
+ if (errno != EINTR)
+ break;
+ if (pid > 0)
+#endif /* BSDJOBS */
+ {
+ for (p = windows; p; p = next)
+ {
+ next = p->w_next;
+ if (pid == p->w_pid)
+ {
+#ifdef BSDJOBS
+ if (WIFSTOPPED(wstat))
+ {
+ debug3("Window %d pid %d: WIFSTOPPED (sig %d)\n", p->w_number, p->w_pid, WSTOPSIG(wstat));
+#ifdef SIGTTIN
+ if (WSTOPSIG(wstat) == SIGTTIN)
+ {
+ Msg(0, "Suspended (tty input)");
+ continue;
+ }
+#endif
+#ifdef SIGTTOU
+ if (WSTOPSIG(wstat) == SIGTTOU)
+ {
+ Msg(0, "Suspended (tty output)");
+ continue;
+ }
+#endif
+ /* Try to restart process */
+# ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You regain consciousness.");
+ else
+# endif /* NETHACK */
+ Msg(0, "Child has been stopped, restarting.");
+ if (killpg(p->w_pid, SIGCONT))
+ kill(p->w_pid, SIGCONT);
+ }
+ else
+#endif
+ {
+ WindowDied(p);
+ }
+ break;
+ }
+#ifdef PSEUDOS
+ if (p->w_pwin && pid == p->w_pwin->p_pid)
+ {
+ debug2("pseudo of win Nr %d died. pid == %d\n", p->w_number, p->w_pwin->p_pid);
+ FreePseudowin(p);
+ break;
+ }
+#endif
+ }
+ if (p == 0)
+ {
+ debug1("pid %d not found - hope that's ok\n", pid);
+ }
+ }
+}
+
+
+static sigret_t
+FinitHandler SIGDEFARG
+{
+#ifdef SIGHASARG
+ debug1("FinitHandler called, sig %d.\n", sigsig);
+#else
+ debug("FinitHandler called.\n");
+#endif
+ Finit(1);
+ SIGRETURN;
+}
+
+void
+Finit(i)
+int i;
+{
+ struct win *p, *next;
+
+ signal(SIGCHLD, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ debug1("Finit(%d);\n", i);
+ for (p = windows; p; p = next)
+ {
+ next = p->w_next;
+ FreeWindow(p);
+ }
+ if (ServerSocket != -1)
+ {
+ debug1("we unlink(%s)\n", SockPath);
+#ifdef USE_SETEUID
+ xseteuid(real_uid);
+ xsetegid(real_gid);
+#endif
+ (void) unlink(SockPath);
+#ifdef USE_SETEUID
+ xseteuid(eff_uid);
+ xsetegid(eff_gid);
+#endif
+ }
+ for (display = displays; display; display = display->d_next)
+ {
+ if (D_status)
+ RemoveStatus();
+ FinitTerm();
+#ifdef UTMPOK
+ RestoreLoginSlot();
+#endif
+ AddStr("[screen is terminating]\r\n");
+ Flush();
+ SetTTY(D_userfd, &D_OldMode);
+ fcntl(D_userfd, F_SETFL, 0);
+ freetty();
+ Kill(D_userpid, SIG_BYE);
+ }
+ /*
+ * we _cannot_ call eexit(i) here,
+ * instead of playing with the Socket above. Sigh.
+ */
+ exit(i);
+}
+
+void
+eexit(e)
+int e;
+{
+ debug("eexit\n");
+ if (ServerSocket != -1)
+ {
+ debug1("we unlink(%s)\n", SockPath);
+ setuid(real_uid);
+ setgid(real_gid);
+ (void) unlink(SockPath);
+ }
+ exit(e);
+}
+
+
+/*
+ * Detach now has the following modes:
+ * D_DETACH SIG_BYE detach backend and exit attacher
+ * D_STOP SIG_STOP stop attacher (and detach backend)
+ * D_REMOTE SIG_BYE remote detach -- reattach to new attacher
+ * D_POWER SIG_POWER_BYE power detach -- attacher kills his parent
+ * D_REMOTE_POWER SIG_POWER_BYE remote power detach -- both
+ * D_LOCK SIG_LOCK lock the attacher
+ * (jw)
+ * we always remove our utmp slots. (even when "lock" or "stop")
+ * Note: Take extra care here, we may be called by interrupt!
+ */
+void
+Detach(mode)
+int mode;
+{
+ int sign = 0, pid;
+#ifdef UTMPOK
+ struct win *p;
+#endif
+
+ if (display == 0)
+ return;
+ signal(SIGHUP, SIG_IGN);
+ debug1("Detach(%d)\n", mode);
+ if (D_status)
+ RemoveStatus();
+ FinitTerm();
+ switch (mode)
+ {
+ case D_DETACH:
+ AddStr("[detached]\r\n");
+ sign = SIG_BYE;
+ break;
+#ifdef BSDJOBS
+ case D_STOP:
+ sign = SIG_STOP;
+ break;
+#endif
+#ifdef REMOTE_DETACH
+ case D_REMOTE:
+ AddStr("[remote detached]\r\n");
+ sign = SIG_BYE;
+ break;
+#endif
+#ifdef POW_DETACH
+ case D_POWER:
+ AddStr("[power detached]\r\n");
+ if (PowDetachString)
+ {
+ AddStr(expand_vars(PowDetachString));
+ AddStr("\r\n");
+ }
+ sign = SIG_POWER_BYE;
+ break;
+#ifdef REMOTE_DETACH
+ case D_REMOTE_POWER:
+ AddStr("[remote power detached]\r\n");
+ if (PowDetachString)
+ {
+ AddStr(expand_vars(PowDetachString));
+ AddStr("\r\n");
+ }
+ sign = SIG_POWER_BYE;
+ break;
+#endif
+#endif
+ case D_LOCK:
+ ClearDisplay();
+ sign = SIG_LOCK;
+ /* tell attacher to lock terminal with a lockprg. */
+ break;
+ }
+#ifdef UTMPOK
+ if (displays->d_next == 0)
+ {
+ for (p = windows; p; p = p->w_next)
+ if (p->w_slot != (slot_t) -1)
+ {
+ RemoveUtmp(p);
+ /*
+ * Set the slot to 0 to get the window
+ * logged in again.
+ */
+ p->w_slot = (slot_t) 0;
+ }
+ if (console_window)
+ {
+ if (TtyGrabConsole(console_window->w_ptyfd, 0, "detach"))
+ {
+ debug("could not release console - killing window\n");
+ KillWindow(console_window);
+ display = displays;
+ }
+ }
+ }
+ RestoreLoginSlot();
+#endif
+ if (D_fore)
+ {
+ ReleaseAutoWritelock(display, D_fore);
+ if (D_fore->w_tstamp.seconds)
+ D_fore->w_tstamp.lastio = Now;
+ D_fore->w_active = 0;
+ D_fore->w_display = 0;
+ D_lay = &BlankLayer;
+ D_layfn = D_lay->l_layfn;
+ D_user->u_detachwin = D_fore->w_number;
+ }
+ while (D_lay != &BlankLayer)
+ ExitOverlayPage();
+ if (D_userfd >= 0)
+ {
+ Flush();
+ SetTTY(D_userfd, &D_OldMode);
+ fcntl(D_userfd, F_SETFL, 0);
+ }
+ pid = D_userpid;
+ debug2("display: %#x displays: %#x\n", (unsigned int)display, (unsigned int)displays);
+ FreeDisplay();
+ if (displays == 0)
+ /* Flag detached-ness */
+ (void) chsock();
+ /*
+ * tell father to father what to do. We do that after we
+ * freed the tty, thus getty feels more comfortable on hpux
+ * if it was a power detach.
+ */
+ Kill(pid, sign);
+ debug2("Detach: Signal %d to Attacher(%d)!\n", sign, pid);
+ debug("Detach returns, we are successfully detached.\n");
+ signal(SIGHUP, SigHup);
+}
+
+static int
+IsSymbol(e, s)
+register char *e, *s;
+{
+ register int l;
+
+ l = strlen(s);
+ return strncmp(e, s, l) == 0 && e[l] == '=';
+}
+
+void
+MakeNewEnv()
+{
+ register char **op, **np;
+ static char stybuf[MAXSTR];
+
+ for (op = environ; *op; ++op)
+ ;
+ if (NewEnv)
+ free((char *)NewEnv);
+ NewEnv = np = (char **) malloc((unsigned) (op - environ + 7 + 1) * sizeof(char **));
+ if (!NewEnv)
+ Panic(0, strnomem);
+ sprintf(stybuf, "STY=%s", strlen(SockName) <= MAXSTR - 5 ? SockName : "?");
+ *np++ = stybuf; /* NewEnv[0] */
+ *np++ = Term; /* NewEnv[1] */
+ np++; /* room for SHELL */
+#ifdef TIOCSWINSZ
+ np += 2; /* room for TERMCAP and WINDOW */
+#else
+ np += 4; /* room for TERMCAP WINDOW LINES COLUMNS */
+#endif
+
+ for (op = environ; *op; ++op)
+ {
+debug1("MakeNewEnv: %s\n", *op);
+ if (!IsSymbol(*op, "TERM") && !IsSymbol(*op, "TERMCAP")
+ && !IsSymbol(*op, "STY") && !IsSymbol(*op, "WINDOW")
+ && !IsSymbol(*op, "SCREENCAP") && !IsSymbol(*op, "SHELL")
+ && !IsSymbol(*op, "LINES") && !IsSymbol(*op, "COLUMNS")
+ )
+ *np++ = *op;
+ }
+ *np = 0;
+}
+
+void
+#ifdef USEVARARGS
+/*VARARGS2*/
+# if defined(__STDC__)
+Msg(int err, char *fmt, ...)
+# else /* __STDC__ */
+Msg(err, fmt, va_alist)
+int err;
+char *fmt;
+va_dcl
+# endif /* __STDC__ */
+{
+ static va_list ap;
+#else /* USEVARARRGS */
+/*VARARGS2*/
+Msg(err, fmt, p1, p2, p3, p4, p5, p6)
+int err;
+char *fmt;
+unsigned long p1, p2, p3, p4, p5, p6;
+{
+#endif /* USEVARARRGS */
+ char buf[MAXPATHLEN*2];
+ char *p = buf;
+
+#ifdef USEVARARGS
+# if defined(__STDC__)
+ va_start(ap, fmt);
+# else /* __STDC__ */
+ va_start(ap);
+# endif /* __STDC__ */
+ (void) vsprintf(p, fmt, ap);
+ va_end(ap);
+#else /* USEVARARRGS */
+ sprintf(p, fmt, p1, p2, p3, p4, p5, p6);
+#endif /* USEVARARRGS */
+ if (err)
+ {
+ p += strlen(p);
+ sprintf(p, ": %s", strerror(err));
+ }
+ debug2("Msg('%s') (%#x);\n", buf, (unsigned int)display);
+ if (display)
+ MakeStatus(buf);
+ else if (displays)
+ {
+ for (display = displays; display; display = display->d_next)
+ MakeStatus(buf);
+ }
+ else
+ printf("%s\r\n", buf);
+}
+
+void
+#ifdef USEVARARGS
+/*VARARGS2*/
+# if defined(__STDC__)
+Panic(int err, char *fmt, ...)
+# else /* __STDC__ */
+Panic(err, fmt, va_alist)
+int err;
+char *fmt;
+va_dcl
+# endif /* __STDC__ */
+{
+ static va_list ap;
+#else /* USEVARARRGS */
+/*VARARGS2*/
+Panic(err, fmt, p1, p2, p3, p4, p5, p6)
+int err;
+char *fmt;
+unsigned long p1, p2, p3, p4, p5, p6;
+{
+#endif /* USEVARARRGS */
+ char buf[MAXPATHLEN*2];
+ char *p = buf;
+
+#ifdef USEVARARGS
+# if defined(__STDC__)
+ va_start(ap, fmt);
+# else /* __STDC__ */
+ va_start(ap);
+# endif /* __STDC__ */
+ (void) vsprintf(p, fmt, ap);
+ va_end(ap);
+#else /* USEVARARRGS */
+ sprintf(p, fmt, p1, p2, p3, p4, p5, p6);
+#endif /* USEVARARRGS */
+ if (err)
+ {
+ p += strlen(p);
+ sprintf(p, ": %s", strerror(err));
+ }
+ debug1("Panic('%s');\n", buf);
+ if (displays == 0)
+ printf("%s\r\n", buf);
+ else
+ for (display = displays; display; display = display->d_next)
+ {
+ if (D_status)
+ RemoveStatus();
+ FinitTerm();
+ Flush();
+#ifdef UTMPOK
+ RestoreLoginSlot();
+#endif
+ SetTTY(D_userfd, &D_OldMode);
+ fcntl(D_userfd, F_SETFL, 0);
+ write(D_userfd, buf, strlen(buf));
+ write(D_userfd, "\n", 1);
+ freetty();
+ if (D_userpid)
+ Kill(D_userpid, SIG_BYE);
+ }
+#ifdef MULTIUSER
+ if (tty_oldmode >= 0)
+ {
+# ifdef USE_SETEUID
+ if (setuid(own_uid))
+ xseteuid(own_uid); /* XXX: may be a loop. sigh. */
+# else
+ setuid(own_uid);
+# endif
+ debug1("Panic: changing back modes from %s\n", attach_tty);
+ chmod(attach_tty, tty_oldmode);
+ }
+#endif
+ eexit(1);
+}
+
+
+/*
+ * '^' is allowed as an escape mechanism for control characters. jw.
+ *
+ * Added time insertion using ideas/code from /\ndy Jones
+ * (andy@lingua.cltr.uq.OZ.AU) - thanks a lot!
+ *
+ */
+
+static const char days[] = "SunMonTueWedThuFriSat";
+static const char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+
+char *
+MakeWinMsg(s, win, esc)
+register char *s;
+struct win *win;
+int esc;
+{
+ static char buf[MAXSTR];
+ register char *p = buf;
+ register int ctrl;
+ time_t now;
+ struct tm *tm;
+ int l;
+
+ tm = 0;
+ ctrl = 0;
+ for (; *s && (l = buf + MAXSTR - 1 - p) > 0; s++, p++, l--)
+ {
+ *p = *s;
+ if (ctrl)
+ {
+ ctrl = 0;
+ if (*s != '^' && *s >= 64)
+ *p &= 0x1f;
+ continue;
+ }
+ if (*s != esc)
+ {
+ if (esc == '%')
+ {
+ switch (*s)
+ {
+ case '~':
+ *p = BELL;
+ break;
+ case '^':
+ ctrl = 1;
+ *p-- = '^';
+ break;
+ default:
+ break;
+ }
+ }
+ continue;
+ }
+ if (s[1] == esc) /* double escape ? */
+ {
+ s++;
+ continue;
+ }
+ switch (s[1])
+ {
+ case 'd': case 'D': case 'm': case 'M': case 'y': case 'Y':
+ case 'a': case 'A': case 's': case 'w': case 'W':
+ s++;
+ if (l < 4)
+ break;
+ if (tm == 0)
+ {
+ (void)time(&now);
+ tm = localtime(&now);
+ }
+ switch (*s)
+ {
+ case 'd':
+ sprintf(p, "%02d", tm->tm_mday % 100);
+ break;
+ case 'D':
+ sprintf(p, "%3.3s", days + 3 * tm->tm_wday);
+ break;
+ case 'm':
+ sprintf(p, "%02d", tm->tm_mon + 1);
+ break;
+ case 'M':
+ sprintf(p, "%3.3s", months + 3 * tm->tm_mon);
+ break;
+ case 'y':
+ sprintf(p, "%02d", tm->tm_year % 100);
+ break;
+ case 'Y':
+ sprintf(p, "%04d", tm->tm_year + 1900);
+ break;
+ case 'a':
+ sprintf(p, tm->tm_hour >= 12 ? "pm" : "am");
+ break;
+ case 'A':
+ sprintf(p, tm->tm_hour >= 12 ? "PM" : "AM");
+ break;
+ case 's':
+ sprintf(p, "%02d", tm->tm_sec);
+ break;
+ case 'w':
+ sprintf(p, "%2d:%02d", tm->tm_hour, tm->tm_min);
+ break;
+ case 'W':
+ sprintf(p, "%2d:%02d", (tm->tm_hour + 11) % 12 + 1, tm->tm_min);
+ break;
+ default:
+ break;
+ }
+ p += strlen(p) - 1;
+ break;
+ case 't':
+ if (strlen(win->w_title) < l)
+ {
+ strcpy(p, win->w_title);
+ p += strlen(p) - 1;
+ }
+ /* FALLTHROUGH */
+ s++;
+ break;
+ case 'n':
+ s++;
+ /* FALLTHROUGH */
+ default:
+ if (l > 10)
+ {
+ sprintf(p, "%d", win->w_number);
+ p += strlen(p) - 1;
+ }
+ break;
+ }
+ }
+ *p = '\0';
+ return buf;
+}
+
+void
+DisplaySleep(n)
+int n;
+{
+ char buf;
+ fd_set r;
+ struct timeval t;
+
+ if (!display)
+ {
+ debug("DisplaySleep has no display sigh\n");
+ sleep(n);
+ return;
+ }
+ t.tv_usec = 0;
+ t.tv_sec = n;
+ FD_ZERO(&r);
+ FD_SET(D_userfd, &r);
+ if (select(FD_SETSIZE, &r, (fd_set *)0, (fd_set *)0, &t) > 0)
+ {
+ debug("display activity stopped sleep\n");
+ read(D_userfd, &buf, 1);
+ }
+ debug1("DisplaySleep(%d) ending\n", n);
+}
+
diff --git a/screen.h b/screen.h
new file mode 100644
index 0000000..ba9040b
--- /dev/null
+++ b/screen.h
@@ -0,0 +1,251 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ * $Id: screen.h,v 1.12 1994/05/31 12:32:54 mlschroe Exp $ FAU
+ */
+
+#include "os.h"
+
+#if defined(__STDC__)
+# ifndef __P
+# define __P(a) a
+# endif
+#else
+# ifndef __P
+# define __P(a) ()
+# endif
+# define const
+#endif
+
+#include "osdef.h"
+
+#include "ansi.h"
+#include "acls.h"
+#include "comm.h"
+#include "overlay.h"
+#include "term.h"
+
+
+#ifdef DEBUG
+# define DEBUGDIR "/tmp/debug"
+# define debug(x) {if(dfp){fprintf(dfp,x);fflush(dfp);}}
+# define debug1(x,a) {if(dfp){fprintf(dfp,x,a);fflush(dfp);}}
+# define debug2(x,a,b) {if(dfp){fprintf(dfp,x,a,b);fflush(dfp);}}
+# define debug3(x,a,b,c) {if(dfp){fprintf(dfp,x,a,b,c);fflush(dfp);}}
+ extern FILE *dfp;
+#else
+# define debug(x) {}
+# define debug1(x,a) {}
+# define debug2(x,a,b) {}
+# define debug3(x,a,b,c) {}
+#endif
+
+#ifndef DEBUG
+# define NOASSERT
+#endif
+
+#ifndef NOASSERT
+# if defined(__STDC__)
+# define ASSERT(lousy_cpp) {if (!(lousy_cpp)) {debug2("ASSERT("#lousy_cpp")ion failed file %s line %d\n", __FILE__, __LINE__);abort();}}
+# else
+# define ASSERT(lousy_cpp) {if (!(lousy_cpp)) {debug2("ASSERT(lousy_cpp)ion failed file %s line %d\n", __FILE__, __LINE__);abort();}}
+# endif
+#else
+# define ASSERT(lousy_cpp) {;}
+#endif
+
+/* here comes my own Free: jw. */
+#define Free(a) {if ((a) == 0) abort(); else free((void *)(a)); (a)=0;}
+
+#define Ctrl(c) ((c)&037)
+
+#define MAXSTR 256
+#define MAXARGS 64
+#define MSGWAIT 5
+#define MSGMINWAIT 1
+#define SILENCEWAIT 30
+
+/*
+ * if a nasty user really wants to try a history of 3000 lines on all 10
+ * windows, he will allocate 8 MegaBytes of memory, which is quite enough.
+ */
+#define MAXHISTHEIGHT 3000
+#define DEFAULTHISTHEIGHT 100
+#define DEFAULT_BUFFERFILE "/tmp/screen-exchange"
+
+#define TTY_FLAG_PLAIN 0x01
+
+struct tty_attr
+{
+ int flags; /* a PLAIN tty or a process behind */
+};
+
+struct mode
+{
+#ifdef POSIX
+ struct termios tio;
+# ifdef hpux
+ struct ltchars m_ltchars;
+# endif /* hpux */
+#else /* POSIX */
+# ifdef TERMIO
+ struct termio tio;
+# ifdef CYTERMIO
+ int m_mapkey;
+ int m_mapscreen;
+ int m_backspace;
+# endif
+# else /* TERMIO */
+ struct sgttyb m_ttyb;
+ struct tchars m_tchars;
+ struct ltchars m_ltchars;
+ int m_ldisc;
+ int m_lmode;
+# endif /* TERMIO */
+#if defined(KANJI) && defined(TIOCKSET) && defined(KM_ASCII) && defined(KM_SYSSJIS)
+ struct jtchars m_jtchars;
+ int m_knjmode;
+# endif
+#endif /* POSIX */
+};
+
+#include "image.h"
+#include "display.h"
+#include "window.h"
+
+/*
+ * Parameters for the Detach() routine
+ */
+#define D_DETACH 0
+#define D_STOP 1
+#define D_REMOTE 2
+#define D_POWER 3
+#define D_REMOTE_POWER 4
+#define D_LOCK 5
+
+/*
+ * Here are the messages the attacher sends to the backend
+ */
+#define MSG_CREATE 0
+#define MSG_ERROR 1
+#define MSG_ATTACH 2
+#define MSG_CONT 3
+#define MSG_DETACH 4
+#define MSG_POW_DETACH 5
+#define MSG_WINCH 6
+#define MSG_HANGUP 7
+
+struct msg
+{
+ int type;
+ char m_tty[MAXPATHLEN]; /* ttyname */
+ union
+ {
+ struct
+ {
+ int lflag;
+ int aflag;
+ int flowflag;
+ int hheight; /* size of scrollback buffer */
+ int nargs;
+ char line[MAXPATHLEN];
+ char dir[MAXPATHLEN];
+ char screenterm[20]; /* is screen really "screen" ? */
+ }
+ create;
+ struct
+ {
+ char auser[20 + 1]; /* username */
+ int apid; /* pid of frontend */
+ int adaptflag; /* adapt window size? */
+ int lines, columns; /* display size */
+ char password[20];
+ char envterm[20 + 1]; /* terminal type */
+ }
+ attach;
+ struct
+ {
+ char duser[20 + 1]; /* username */
+ char password[20];
+ int dpid; /* pid of frontend */
+ }
+ detach;
+ char message[MAXPATHLEN * 2];
+ } m;
+};
+
+/*
+ * And the signals the attacher receives from the backend
+ */
+#define SIG_BYE SIGHUP
+#define SIG_POWER_BYE SIGUSR1
+#define SIG_LOCK SIGUSR2
+#define SIG_STOP SIGTSTP
+#define SIG_PW_OK SIGUSR1
+#define SIG_PW_FAIL SIG_BYE
+
+
+#define BELL (Ctrl('g'))
+#define VBELLWAIT 1 /* No. of seconds a vbell will be displayed */
+
+#define BELL_OFF 0 /* No bell has occurred in the window */
+#define BELL_ON 1 /* A bell has occurred, but user not yet notified */
+#define BELL_MSG 2 /* A bell has occured, user sees a message */
+#define BELL_DONE 3 /* A bell has occured, user has been notified */
+#define BELL_VISUAL 4 /* A bell has occured in fore win, notify him visually */
+
+#define MON_OFF 0 /* Monitoring is off in the window */
+#define MON_ON 1 /* No activity has occurred in the window */
+#define MON_FOUND 2 /* Activity has occured, but user not yet notified */
+#define MON_MSG 3 /* Activity has occured, user sees a message */
+#define MON_DONE 4 /* Activity has occured, user has been notified */
+
+#define DUMP_TERMCAP 0 /* WriteFile() options */
+#define DUMP_HARDCOPY 1
+#define DUMP_EXCHANGE 2
+
+extern char strnomem[];
+
+/*
+ * line modes used by Input()
+ */
+#define INP_COOKED 0
+#define INP_NOECHO 1
+#define INP_RAW 2
+#define INP_EVERY 4
+
+
+#ifdef MULTIUSER
+struct acl
+{
+ struct acl *next;
+ char *name;
+};
+#endif
+
+/* register list */
+#define MAX_PLOP_DEFS 256
+struct plop
+{
+ char *buf;
+ int len;
+};
+
diff --git a/search.c b/search.c
new file mode 100644
index 0000000..fa87ffe
--- /dev/null
+++ b/search.c
@@ -0,0 +1,336 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: search.c,v 1.2 1994/05/31 12:32:57 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+
+#include "config.h"
+#include "screen.h"
+#include "mark.h"
+#include "extern.h"
+
+#ifdef COPY_PASTE
+
+extern struct win *fore;
+extern struct display *display;
+
+/********************************************************************
+ * VI style Search
+ */
+
+static int matchword __P((char *, int, int, int));
+static void searchend __P((char *, int));
+static void backsearchend __P((char *, int));
+
+void
+Search(dir)
+int dir;
+{
+ struct markdata *markdata;
+ if (dir == 0)
+ {
+ markdata = (struct markdata *)D_lay->l_data;
+ if (markdata->isdir > 0)
+ searchend((char *)0, 0);
+ else if (markdata->isdir < 0)
+ backsearchend((char *)0, 0);
+ else
+ Msg(0, "No previous pattern");
+ }
+ else
+ Input((dir > 0 ? "/" : "?"), sizeof(markdata->isstr)-1, (dir > 0 ? searchend : backsearchend), INP_COOKED);
+}
+
+static void
+searchend(buf, len)
+char *buf;
+int len;
+{
+ int x = 0, sx, ex, y;
+ struct markdata *markdata;
+
+ markdata = (struct markdata *)D_lay->l_data;
+ markdata->isdir = 1;
+ if (len)
+ strcpy(markdata->isstr, buf);
+ sx = markdata->cx + 1;
+ ex = D_width - 1;
+ for (y = markdata->cy; y < fore->w_histheight + D_height; y++, sx = 0)
+ {
+ if ((x = matchword(markdata->isstr, y, sx, ex)) >= 0)
+ break;
+ }
+ if (y >= fore->w_histheight + D_height)
+ {
+ GotoPos(markdata->cx, W2D(markdata->cy));
+ Msg(0, "Pattern not found");
+ }
+ else
+ revto(x, y);
+}
+
+static void
+backsearchend(buf, len)
+char *buf;
+int len;
+{
+ int sx, ex, x = -1, y;
+ struct markdata *markdata;
+
+ markdata = (struct markdata *)D_lay->l_data;
+ markdata->isdir = -1;
+ if (len)
+ strcpy(markdata->isstr, buf);
+ ex = markdata->cx - 1;
+ for (y = markdata->cy; y >= 0; y--, ex = D_width - 1)
+ {
+ sx = 0;
+ while ((sx = matchword(markdata->isstr, y, sx, ex)) >= 0)
+ x = sx++;
+ if (x >= 0)
+ break;
+ }
+ if (y < 0)
+ {
+ GotoPos(markdata->cx, W2D(markdata->cy));
+ Msg(0, "Pattern not found");
+ }
+ else
+ revto(x, y);
+}
+
+static int
+matchword(pattern, y, sx, ex)
+char *pattern;
+int y, sx, ex;
+{
+ char *ip, *ipe, *cp, *pp;
+ struct mline *ml;
+
+ ml = WIN(y);
+ ip = ml->image + sx;
+ ipe = ml->image + D_width;
+ for (;sx <= ex; sx++)
+ {
+ cp = ip++;
+ pp = pattern;
+ while (*cp++ == *pp++)
+ if (*pp == 0)
+ return sx;
+ else if (cp == ipe)
+ break;
+ }
+ return -1;
+}
+
+
+/********************************************************************
+ * Emacs style ISearch
+ */
+
+static char *isprompts[] = {
+ "I-search backward: ", "failing I-search backward: ",
+ "I-search: ", "failing I-search: "
+};
+
+
+static int is_redo __P((struct markdata *));
+static void is_process __P((char *, int));
+static int is_bm __P((char *, int, int, int, int));
+
+
+static int
+is_bm(str, l, p, end, dir)
+char *str;
+int l, p, end, dir;
+{
+ int tab[256];
+ int i, q;
+ char *s, c;
+ int w = D_width;
+
+ debug2("is_bm: searching for %s len %d\n", str, l);
+ debug3("start at %d end %d dir %d\n", p, end, dir);
+ if (p < 0 || p + l > end)
+ return -1;
+ if (l == 0)
+ return p;
+ if (dir < 0)
+ str += l - 1;
+ for (i = 0; i < 256; i++)
+ tab[i] = l * dir;
+ for (i = 0; i < l - 1; i++, str += dir)
+ tab[(int)(unsigned char) *str] = (l - 1 - i) * dir;
+ if (dir > 0)
+ p += l - 1;
+ debug1("first char to match: %c\n", *str);
+ while (p >= 0 && p < end)
+ {
+ q = p;
+ s = str;
+ for (i = 0;;)
+ {
+ c = (WIN(q / w))->image[q % w];
+ if (i == 0)
+ p += tab[(int)(unsigned char) c];
+ if (c != *s)
+ break;
+ q -= dir;
+ s -= dir;
+ if (++i == l)
+ return q + (dir > 0 ? 1 : -l);
+ }
+ }
+ return -1;
+}
+
+
+/*ARGSUSED*/
+static void
+is_process(p, n)
+char *p;
+int n;
+{
+ int pos, x, y, dir;
+ struct markdata *markdata;
+
+ if (n == 0)
+ return;
+ markdata = (struct markdata *)D_lay->l_next->l_data;
+ ASSERT(p);
+
+ pos = markdata->cx + markdata->cy * D_width;
+ GotoPos(markdata->cx, W2D(markdata->cy));
+
+ switch (*p)
+ {
+ case '\007': /* CTRL-G */
+ pos = markdata->isstartpos;
+ /*FALLTHROUGH*/
+ case '\033': /* ESC */
+ *p = 0;
+ break;
+ case '\013': /* CTRL-K */
+ case '\027': /* CTRL-W */
+ markdata->isistrl = 1;
+ /*FALLTHROUGH*/
+ case '\b':
+ case '\177':
+ if (markdata->isistrl == 0)
+ return;
+ markdata->isistrl--;
+ pos = is_redo(markdata);
+ *p = '\b';
+ break;
+ case '\023': /* CTRL-S */
+ case '\022': /* CTRL-R */
+ if (markdata->isistrl >= sizeof(markdata->isistr))
+ return;
+ dir = (*p == '\023') ? 1 : -1;
+ pos += dir;
+ if (markdata->isdir == dir && markdata->isistrl == 0)
+ {
+ strcpy(markdata->isistr, markdata->isstr);
+ markdata->isistrl = markdata->isstrl = strlen(markdata->isstr);
+ break;
+ }
+ markdata->isdir = dir;
+ markdata->isistr[markdata->isistrl++] = *p;
+ break;
+ default:
+ if (*p < ' ' || markdata->isistrl >= sizeof(markdata->isistr)
+ || markdata->isstrl >= sizeof(markdata->isstr) - 1)
+ return;
+ markdata->isstr[markdata->isstrl++] = *p;
+ markdata->isistr[markdata->isistrl++] = *p;
+ markdata->isstr[markdata->isstrl] = 0;
+ debug2("New char: %c - left %d\n", *p, (int)sizeof(markdata->isistr) - markdata->isistrl);
+ }
+ if (*p && *p != '\b')
+ pos = is_bm(markdata->isstr, markdata->isstrl, pos, D_width * (fore->w_histheight + D_height), markdata->isdir);
+ if (pos >= 0)
+ {
+ x = pos % D_width;
+ y = pos / D_width;
+ LAY_CALL_UP
+ (
+ RefreshLine(STATLINE, 0, D_width - 1, 0);
+ revto(x, y);
+ if (W2D(markdata->cy) == STATLINE)
+ revto_line(markdata->cx, markdata->cy, STATLINE > 0 ? STATLINE - 1 : 1);
+ );
+ }
+ if (*p)
+ inp_setprompt(isprompts[markdata->isdir + (pos < 0) + 1], markdata->isstrl ? markdata->isstr : "");
+ GotoPos(markdata->cx, W2D(markdata->cy));
+}
+
+static int
+is_redo(markdata)
+struct markdata *markdata;
+{
+ int i, pos, npos, dir;
+ char c;
+
+ npos = pos = markdata->isstartpos;
+ dir = markdata->isstartdir;
+ markdata->isstrl = 0;
+ for (i = 0; i < markdata->isistrl; i++)
+ {
+ c = markdata->isistr[i];
+ if (c == '\022') /* ^R */
+ pos += (dir = -1);
+ else if (c == '\023') /* ^S */
+ pos += (dir = 1);
+ else
+ markdata->isstr[markdata->isstrl++] = c;
+ if (pos >= 0)
+ {
+ npos = is_bm(markdata->isstr, markdata->isstrl, pos, D_width * (fore->w_histheight + D_height), dir);
+ if (npos >= 0)
+ pos = npos;
+ }
+ }
+ markdata->isstr[markdata->isstrl] = 0;
+ markdata->isdir = dir;
+ return npos;
+}
+
+void
+ISearch(dir)
+int dir;
+{
+ struct markdata *markdata;
+ markdata = (struct markdata *)D_lay->l_data;
+ markdata->isdir = markdata->isstartdir = dir;
+ markdata->isstartpos = markdata->cx + markdata->cy * D_width;
+ markdata->isistrl = markdata->isstrl = 0;
+ if (W2D(markdata->cy) == STATLINE)
+ revto_line(markdata->cx, markdata->cy, STATLINE > 0 ? STATLINE - 1 : 1);
+ Input(isprompts[dir + 1], sizeof(markdata->isstr) - 1, is_process, INP_RAW);
+ GotoPos(markdata->cx, W2D(markdata->cy));
+}
+
+#endif /* COPY_PASTE */
diff --git a/socket.c b/socket.c
new file mode 100644
index 0000000..ca8f327
--- /dev/null
+++ b/socket.c
@@ -0,0 +1,1190 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: socket.c,v 1.23 1994/05/31 12:33:00 mlschroe Exp $ FAU")
+
+#include "config.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#if !defined(NAMEDPIPE)
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+
+#ifndef SIGINT
+# include <signal.h>
+#endif
+
+#include "screen.h"
+
+#ifdef DIRENT
+# include <dirent.h>
+#else
+# include <sys/dir.h>
+# define dirent direct
+#endif
+
+#include "extern.h"
+
+static int CheckPid __P((int));
+static void ExecCreate __P((struct msg *));
+#if defined(_SEQUENT_) && !defined(NAMEDPIPE)
+# define connect sconnect /* _SEQUENT_ has braindamaged connect */
+static int sconnect __P((int, struct sockaddr *, int));
+#endif
+
+
+extern char *RcFileName, *extra_incap, *extra_outcap;
+extern int ServerSocket, real_uid, real_gid, eff_uid, eff_gid;
+extern int dflag, iflag, rflag, lsflag, quietflag, wipeflag, xflag;
+extern char *attach_tty, *LoginName, HostName[];
+extern struct display *display, *displays;
+extern struct win *fore, *wtab[], *console_window, *windows;
+extern struct NewWindow nwin_undef;
+#ifdef NETHACK
+extern nethackflag;
+#endif
+#ifdef MULTIUSER
+extern char *multi;
+#endif
+
+#ifdef PASSWORD
+extern int CheckPassword;
+extern char Password[];
+#endif
+extern char *getenv();
+
+extern char SockPath[];
+
+#ifdef MULTIUSER
+# define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0) | (multi ? 1 : 0))
+#else
+# define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0))
+#endif
+
+
+/*
+ * Socket directory manager
+ *
+ * fdp: pointer to store the first good socket.
+ * nfoundp: pointer to store the number of sockets found.
+ * match: string to match socket name.
+ *
+ * The socket directory must be in SockPath!
+ *
+ * Returns: number of good sockets.
+ *
+ * The first good socket is stored in fdp and its name is
+ * appended to SockPath.
+ * If none exists or fdp is NULL SockPath is not changed.
+ *
+ */
+
+int
+FindSocket(fdp, nfoundp, match)
+int *fdp;
+int *nfoundp;
+char *match;
+{
+ DIR *dirp;
+ struct dirent *dp;
+ struct stat st;
+ int mode;
+ int sdirlen;
+ int matchlen = 0;
+ char *name, *n;
+ int firsts = -1, s;
+ char *firstn = 0;
+ int nfound = 0, ngood = 0, ndead = 0, nwipe = 0;
+ struct sent
+ {
+ struct sent *next;
+ int mode;
+ char *name;
+ } *slist, **slisttail, *sent, *nsent;
+
+ if (match)
+ {
+ matchlen = strlen(match);
+#ifdef NAME_MAX
+ if (matchlen > NAME_MAX)
+ matchlen = NAME_MAX;
+#endif
+ }
+
+ /*
+ * SockPath contains the socket directory.
+ * At the end of FindSocket the socket name will be appended to it.
+ * Thus FindSocket() can only be called once!
+ */
+ sdirlen = strlen(SockPath);
+
+#ifdef USE_SETEUID
+ xseteuid(real_uid);
+ xsetegid(real_gid);
+#endif
+
+ if ((dirp = opendir(SockPath)) == 0)
+ Panic(errno, "Cannot opendir %s\n", SockPath);
+
+ slist = 0;
+ slisttail = &slist;
+ while ((dp = readdir(dirp)))
+ {
+ name = dp->d_name;
+ debug1("- %s\n", name);
+ if (*name == 0 || *name == '.')
+ continue;
+ if (matchlen)
+ {
+ n = name;
+ /* if we don't want to match digits swip them */
+ if ((*match <= '0' || *match > '9') && (*n > '0' && *n <= '9'))
+ {
+ while (*n >= '0' && *n <= '9')
+ n++;
+ if (*n == '.')
+ n++;
+ }
+ /* the tty prefix is optional */
+ if (strncmp(match, "tty", 3) && strncmp(n, "tty", 3) == 0)
+ n += 3;
+ if (strncmp(match, n, matchlen))
+ continue;
+ debug1(" -> matched %s\n", match);
+ }
+ sprintf(SockPath + sdirlen, "/%s", name);
+
+ if (stat(SockPath, &st))
+ continue;
+
+#ifndef SOCK_NOT_IN_FS
+# ifdef NAMEDPIPE
+# ifdef S_ISFIFO
+ if (!S_ISFIFO(st.st_mode))
+ continue;
+# endif
+# else
+# ifdef S_ISSOCK
+ if (!S_ISSOCK(st.st_mode))
+ continue;
+# endif
+# endif
+#endif
+
+ if (st.st_uid != real_uid)
+ continue;
+ mode = st.st_mode & 0777;
+ debug1(" has mode 0%03o\n", mode);
+#ifdef MULTIUSER
+ if (multi && ((mode & 0677) != 0601))
+ continue;
+#endif
+ debug(" store it.\n");
+ if ((sent = (struct sent *)malloc(sizeof(struct sent))) == 0)
+ continue;
+ sent->next = 0;
+ sent->name = SaveStr(name);
+ sent->mode = mode;
+ *slisttail = sent;
+ slisttail = &sent->next;
+ nfound++;
+ s = MakeClientSocket(0);
+#ifdef USE_SETEUID
+ /* MakeClientSocket sets ids back to eff */
+ xseteuid(real_uid);
+ xsetegid(real_gid);
+#endif
+ if (s == -1)
+ {
+ sent->mode = -3;
+ /* Unreachable - it is dead if we detect that it's local
+ * or we specified a match
+ */
+ n = name + strlen(name) - 1;
+ while (n != name && *n != '.')
+ n--;
+ if (matchlen || (*n == '.' && n[1] && strncmp(HostName, n + 1, strlen(n + 1)) == 0))
+ {
+ ndead++;
+ sent->mode = -1;
+ if (wipeflag)
+ {
+ if (unlink(SockPath) == 0)
+ {
+ sent->mode = -2;
+ nwipe++;
+ }
+ }
+ }
+ continue;
+ }
+ /* Shall we connect ? */
+ mode &= 0776;
+
+ /*
+ * mode 600: socket is detached.
+ * mode 700: socket is attached.
+ * xflag implies rflag here.
+ *
+ * fail, when socket mode mode is not 600 or 700
+ * fail, when we want to detach, but it already is.
+ * fail, when we only want to attach, but mode 700 and not xflag.
+ * fail, if none of dflag, rflag, xflag is set.
+ */
+ if ((mode != 0700 && mode != 0600) ||
+ (dflag && mode == 0600) ||
+ (!dflag && rflag && mode == 0700 && !xflag) ||
+ (!dflag && !rflag && !xflag))
+ {
+ close(s);
+ continue;
+ }
+ ngood++;
+ if (fdp && firsts == -1)
+ {
+ firsts = s;
+ firstn = sent->name;
+ }
+ else
+ close(s);
+ }
+ (void)closedir(dirp);
+ if (nfound && (lsflag || ngood != 1) && !quietflag)
+ {
+ switch(ngood)
+ {
+ case 0:
+#ifdef NETHACK
+ if (nethackflag)
+ printf(lsflag ? "Your inventory:\n" : "Nothing fitting exists in the game:\n");
+ else
+#endif
+ printf(nfound > 1 ? "There are screens on:\n" : "There is a screen on:\n");
+ break;
+ case 1:
+#ifdef NETHACK
+ if (nethackflag)
+ printf(nfound > 1 ? "Prove thyself worthy or perish:\n" : "You see here a good looking screen:\n");
+ else
+#endif
+ printf(nfound > 1 ? "There are several screens on:\n" : "There is a possible screen on:\n");
+ break;
+ default:
+#ifdef NETHACK
+ if (nethackflag)
+ printf("You may wish for a screen, what do you want?\n");
+ else
+#endif
+ printf("There are several screens on:\n");
+ }
+ for (sent = slist; sent; sent = sent->next)
+ {
+ switch (sent->mode)
+ {
+ case 0700:
+ printf("\t%s\t(Attached)\n", sent->name);
+ break;
+ case 0600:
+ printf("\t%s\t(Detached)\n", sent->name);
+ break;
+#ifdef MULTIUSER
+ case 0701:
+ printf("\t%s\t(Multi, attached)\n", sent->name);
+ break;
+ case 0601:
+ printf("\t%s\t(Multi, detached)\n", sent->name);
+ break;
+#endif
+ case -1:
+ /* No trigraphs, please */
+ printf("\t%s\t(Dead ?%c?)\n", sent->name, '?');
+ break;
+ case -2:
+ printf("\t%s\t(Removed)\n", sent->name);
+ break;
+ case -3:
+ printf("\t%s\t(Unreachable)\n", sent->name);
+ break;
+ }
+ }
+ }
+ if (ndead && !quietflag)
+ {
+ if (wipeflag)
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ printf("You hear%s distant explosion%s.\n",
+ ndead > 1 ? "" : " a", ndead > 1 ? "s" : "");
+ else
+#endif
+ printf("%d socket%s wiped out.\n", nwipe, ndead > 1 ? "s" : "");
+ }
+ else
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ printf("The dead screen%s touch%s you. Try 'screen -wipe'.\n",
+ ndead > 1 ? "s" : "", ndead > 1 ? "" : "es");
+ else
+#endif
+ printf("Remove dead screens with 'screen -wipe'.\n");
+ }
+ }
+ if (firsts != -1)
+ {
+ sprintf(SockPath + sdirlen, "/%s", firstn);
+ *fdp = firsts;
+ }
+ else
+ SockPath[sdirlen] = 0;
+ for (sent = slist; sent; sent = nsent)
+ {
+ nsent = sent->next;
+ free(sent->name);
+ free((char *)sent);
+ }
+#ifdef USE_SETEUID
+ xseteuid(eff_uid);
+ xsetegid(eff_gid);
+#endif
+ if (nfoundp)
+ *nfoundp = nfound - nwipe;
+ return ngood;
+}
+
+
+/*
+**
+** Socket/pipe create routines
+**
+*/
+
+#ifdef NAMEDPIPE
+
+int
+MakeServerSocket()
+{
+ register int s;
+ struct stat st;
+
+# ifdef USE_SETEUID
+ xseteuid(real_uid);
+ xsetegid(real_gid);
+# endif
+ if ((s = open(SockPath, O_WRONLY | O_NONBLOCK)) >= 0)
+ {
+ debug("huii, my fifo already exists??\n");
+ if (quietflag)
+ {
+ Kill(D_userpid, SIG_BYE);
+ eexit(11);
+ }
+ Msg(0, "There is already a screen running on %s.", Filename(SockPath));
+ if (stat(SockPath, &st) == -1)
+ Panic(errno, "stat");
+ if (st.st_uid != real_uid)
+ Panic(0, "Unfortunatelly you are not its owner.");
+ if ((st.st_mode & 0700) == 0600)
+ Panic(0, "To resume it, use \"screen -r\"");
+ else
+ Panic(0, "It is not detached.");
+ /* NOTREACHED */
+ }
+# ifdef USE_SETEUID
+ (void) unlink(SockPath);
+ if (mkfifo(SockPath, SOCKMODE))
+ Panic(0, "mkfifo %s failed", SockPath);
+# ifdef BROKEN_PIPE
+ if ((s = open(SockPath, O_RDWR | O_NONBLOCK, 0)) < 0)
+# else
+ if ((s = open(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
+# endif
+ Panic(errno, "open fifo %s", SockPath);
+ xseteuid(eff_uid);
+ xsetegid(eff_gid);
+ return s;
+# else /* !USE_SETEUID */
+ if (UserContext() > 0)
+ {
+ (void) unlink(SockPath);
+ UserReturn(mkfifo(SockPath, SOCKMODE));
+ }
+ if (UserStatus())
+ Panic(0, "mkfifo %s failed", SockPath);
+# ifdef BROKEN_PIPE
+ if ((s = secopen(SockPath, O_RDWR | O_NONBLOCK, 0)) < 0)
+# else
+ if ((s = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
+# endif
+ Panic(errno, "open fifo %s", SockPath);
+ return s;
+# endif /* !USE_SETEUID */
+}
+
+
+int
+MakeClientSocket(err)
+int err;
+{
+ register int s = 0;
+
+ if ((s = secopen(SockPath, O_WRONLY | O_NONBLOCK, 0)) >= 0)
+ {
+ (void) fcntl(s, F_SETFL, 0);
+ return s;
+ }
+ if (err)
+ Msg(errno, "%s", SockPath);
+ debug2("MakeClientSocket() open %s failed (%d)\n", SockPath, errno);
+ return -1;
+}
+
+
+#else /* NAMEDPIPE */
+
+
+int
+MakeServerSocket()
+{
+ register int s;
+ struct sockaddr_un a;
+ struct stat st;
+
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ Panic(errno, "socket");
+ a.sun_family = AF_UNIX;
+ strcpy(a.sun_path, SockPath);
+# ifdef USE_SETEUID
+ xseteuid(real_uid);
+ xsetegid(real_gid);
+# endif
+ if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) != -1)
+ {
+ debug("oooooh! socket already is alive!\n");
+ if (quietflag)
+ {
+ Kill(D_userpid, SIG_BYE);
+ /*
+ * oh, well. nobody receives that return code. papa
+ * dies by signal.
+ */
+ eexit(11);
+ }
+ Msg(0, "There is already a screen running on %s.", Filename(SockPath));
+ if (stat(SockPath, &st) == -1)
+ Panic(errno, "stat");
+ if (st.st_uid != real_uid)
+ Panic(0, "Unfortunatelly you are not its owner.");
+ if ((st.st_mode & 0700) == 0600)
+ Panic(0, "To resume it, use \"screen -r\"");
+ else
+ Panic(0, "It is not detached.");
+ /* NOTREACHED */
+ }
+#if defined(m88k) || defined(sysV68)
+ close(s); /* we get bind: Invalid argument if this is not done */
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ Panic(errno, "reopen socket");
+#endif
+ (void) unlink(SockPath);
+ if (bind(s, (struct sockaddr *) & a, strlen(SockPath) + 2) == -1)
+ Panic(errno, "bind (%s)", SockPath);
+#ifdef SOCK_NOT_IN_FS
+ {
+ int f;
+ if ((f = secopen(SockPath, O_RDWR | O_CREAT, SOCKMODE)) < 0)
+ Panic(errno, "shadow socket open");
+ close(f);
+ }
+#else
+ chmod(SockPath, SOCKMODE);
+# ifndef USE_SETEUID
+ chown(SockPath, real_uid, real_gid);
+# endif
+#endif /* SOCK_NOT_IN_FS */
+ if (listen(s, 5) == -1)
+ Panic(errno, "listen");
+# ifdef F_SETOWN
+ fcntl(s, F_SETOWN, getpid());
+ debug1("Serversocket owned by %d\n", fcntl(s, F_GETOWN, 0));
+# endif /* F_SETOWN */
+# ifdef USE_SETEUID
+ xseteuid(eff_uid);
+ xsetegid(eff_gid);
+# endif
+ return s;
+}
+
+int
+MakeClientSocket(err)
+int err;
+{
+ register int s;
+ struct sockaddr_un a;
+
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ Panic(errno, "socket");
+ a.sun_family = AF_UNIX;
+ strcpy(a.sun_path, SockPath);
+# ifdef USE_SETEUID
+ xseteuid(real_uid);
+ xsetegid(real_gid);
+# else
+ if (access(SockPath, W_OK))
+ {
+ if (err)
+ Msg(errno, "%s", SockPath);
+ debug2("MakeClientSocket: access(%s): %d.\n", SockPath, errno);
+ close(s);
+ return -1;
+ }
+# endif
+ if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) == -1)
+ {
+ if (err)
+ Msg(errno, "%s: connect", SockPath);
+ debug("MakeClientSocket: connect failed.\n");
+ close(s);
+ s = -1;
+ }
+# ifdef USE_SETEUID
+ xseteuid(eff_uid);
+ xsetegid(eff_gid);
+# endif
+ return s;
+}
+#endif /* NAMEDPIPE */
+
+
+/*
+**
+** Message send and receive routines
+**
+*/
+
+void
+SendCreateMsg(sty, nwin)
+char *sty;
+struct NewWindow *nwin;
+{
+ int s;
+ struct msg m;
+ register char *p;
+ register int len, n;
+ char **av = nwin->args;
+
+#ifdef NAME_MAX
+ if (strlen(sty) > NAME_MAX)
+ sty[NAME_MAX] = 0;
+#endif
+ sprintf(SockPath + strlen(SockPath), "/%s", sty);
+ if ((s = MakeClientSocket(1)) == -1)
+ exit(1);
+ debug1("SendCreateMsg() to '%s'\n", SockPath);
+ bzero((char *)&m, sizeof(m));
+ m.type = MSG_CREATE;
+ strcpy(m.m_tty, attach_tty);
+ p = m.m.create.line;
+ n = 0;
+ if (nwin->args != nwin_undef.args)
+ for (av = nwin->args; *av && n < MAXARGS - 1; ++av, ++n)
+ {
+ len = strlen(*av) + 1;
+ if (p + len >= m.m.create.line + MAXPATHLEN - 1)
+ break;
+ strcpy(p, *av);
+ p += len;
+ }
+ if (nwin->aka != nwin_undef.aka && p + strlen(nwin->aka) + 1 < m.m.create.line + MAXPATHLEN)
+ strcpy(p, nwin->aka);
+ else
+ *p = '\0';
+ m.m.create.nargs = n;
+ m.m.create.aflag = nwin->aflag;
+ m.m.create.flowflag = nwin->flowflag;
+ m.m.create.lflag = nwin->lflag;
+ m.m.create.hheight = nwin->histheight;
+ if (getcwd(m.m.create.dir, sizeof(m.m.create.dir)) == 0)
+ {
+ Msg(errno, "getcwd");
+ return;
+ }
+ if (nwin->term != nwin_undef.term)
+ strncpy(m.m.create.screenterm, nwin->term, 19);
+ m.m.create.screenterm[19] = '\0';
+ debug1("SendCreateMsg writing '%s'\n", m.m.create.line);
+ if (write(s, (char *) &m, sizeof m) != sizeof m)
+ Msg(errno, "write");
+ close(s);
+}
+
+void
+#ifdef USEVARARGS
+/*VARARGS1*/
+# if defined(__STDC__)
+SendErrorMsg(char *fmt, ...)
+# else /* __STDC__ */
+SendErrorMsg(fmt, va_alist)
+char *fmt;
+va_dcl
+# endif /* __STDC__ */
+{ /* } */
+ static va_list ap;
+#else /* USEVARARGS */
+/*VARARGS1*/
+SendErrorMsg(fmt, p1, p2, p3, p4, p5, p6)
+char *fmt;
+unsigned long p1, p2, p3, p4, p5, p6;
+{
+#endif /* USEVARARGS */
+ register int s;
+ struct msg m;
+
+#ifdef USEVARARGS
+# if defined(__STDC__)
+ va_start(ap, fmt);
+# else /* __STDC__ */
+ va_start(ap);
+# endif /* __STDC__ */
+ (void) vsprintf(m.m.message, fmt, ap);
+ va_end(ap);
+#else /* USEVARARGS */
+ sprintf(m.m.message, fmt, p1, p2, p3, p4, p5, p6);
+#endif /* USEVARARGS */
+ debug1("SendErrorMsg: '%s'\n", m.m.message);
+ if (display == 0)
+ return;
+ s = MakeClientSocket(0);
+ m.type = MSG_ERROR;
+ strcpy(m.m_tty, D_usertty);
+ debug1("SendErrorMsg(): writing to '%s'\n", SockPath);
+ (void) write(s, (char *) &m, sizeof m);
+ close(s);
+ sleep(2);
+}
+
+
+#ifdef PASSWORD
+static int
+CheckPasswd(pwd, pid, utty)
+int pid;
+char *pwd, *utty;
+{
+ if (CheckPassword && *Password &&
+ strncmp(crypt(pwd, (strlen(Password) > 1) ? Password : "JW"), Password, strlen(Password)))
+ {
+ if (*pwd)
+ {
+# ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "'%s' tries to explode in the sky, but fails. (%s)", utty, pwd);
+ else
+# endif /* NETHACK */
+ Msg(0, "Illegal reattach attempt from terminal %s, \"%s\"", utty, pwd);
+ }
+ debug1("CheckPass() wrong password kill(%d, SIG_PW_FAIL)\n", pid);
+ Kill(pid, SIG_PW_FAIL);
+ return 0;
+ }
+ debug1("CheckPass() from %d happy\n", pid);
+ Kill(pid, SIG_PW_OK);
+ return 1;
+}
+#endif /* PASSWORD */
+
+
+static void
+ExecCreate(mp)
+struct msg *mp;
+{
+ struct NewWindow nwin;
+ char *args[MAXARGS];
+ register int n;
+ register char **pp = args, *p = mp->m.create.line;
+
+ nwin = nwin_undef;
+ n = mp->m.create.nargs;
+ if (n > MAXARGS - 1)
+ n = MAXARGS - 1;
+ /* ugly hack alert... should be done by the frontend! */
+ if (n)
+ {
+ int l, num;
+ char buf[20];
+
+ l = strlen(p);
+ if (IsNumColon(p, 10, buf, sizeof(buf)))
+ {
+ if (*buf)
+ nwin.aka = buf;
+ num = atoi(p);
+ if (num < 0 || num > MAXWIN - 1)
+ num = 0;
+ nwin.StartAt = num;
+ p += l + 1;
+ n--;
+ }
+ }
+ for (; n > 0; n--)
+ {
+ *pp++ = p;
+ p += strlen(p) + 1;
+ }
+ *pp = 0;
+ if (*p)
+ nwin.aka = p;
+ if (*args)
+ nwin.args = args;
+ nwin.aflag = mp->m.create.aflag;
+ nwin.flowflag = mp->m.create.flowflag;
+ if (*mp->m.create.dir)
+ nwin.dir = mp->m.create.dir;
+ nwin.lflag = mp->m.create.lflag;
+ nwin.histheight = mp->m.create.hheight;
+ if (*mp->m.create.screenterm)
+ nwin.term = mp->m.create.screenterm;
+ MakeWindow(&nwin);
+}
+
+static int
+CheckPid(pid)
+int pid;
+{
+ debug1("Checking pid %d\n", pid);
+ if (pid < 2)
+ return -1;
+ if (eff_uid == real_uid)
+ return kill(pid, 0);
+ if (UserContext() > 0)
+ UserReturn(kill(pid, 0));
+ return UserStatus();
+}
+
+#ifdef hpux
+/*
+ * From: "F. K. Bruner" <napalm@ugcs.caltech.edu>
+ * From: "Dan Egnor" <egnor@oracorp.com> Tue Aug 10 06:56:45 1993
+ * The problem is that under HPUX (and possibly other systems too) there are
+ * two equivalent device files for each pty/tty device:
+ * /dev/ttyxx == /dev/pty/ttyxx
+ * /dev/ptyxx == /dev/ptym/ptyxx
+ * I didn't look into the exact specifics, but I've run across this problem
+ * before: Even if you open /dev/ttyxx as fds 0 1 & 2 for a process, if that
+ * process calls the system to determine its tty, it'll get /dev/pty/ttyxx.
+ *
+ * Earlier versions seemed to work -- wonder what they did.
+ */
+static int
+ttycmp(s1, s2)
+char *s1, *s2;
+{
+ if (strlen(s1) > 5) s1 += strlen(s1) - 5;
+ if (strlen(s2) > 5) s2 += strlen(s2) - 5;
+ return strcmp(s1, s2);
+}
+# define TTYCMP(a, b) ttycmp(a, b)
+#else
+# define TTYCMP(a, b) strcmp(a, b)
+#endif
+
+void
+ReceiveMsg()
+{
+ int left, len, i;
+ static struct msg m;
+ char *p;
+ int ns = ServerSocket;
+ struct mode Mode;
+ struct win *wi;
+#ifdef REMOTE_DETACH
+ struct display *next;
+#endif
+
+#ifdef NAMEDPIPE
+ debug("Ha, there was someone knocking on my fifo??\n");
+ if (fcntl(ServerSocket, F_SETFL, 0) == -1)
+ Panic(errno, "BLOCK fcntl");
+#else
+ struct sockaddr_un a;
+
+ len = sizeof(a);
+ debug("Ha, there was someone knocking on my socket??\n");
+ if ((ns = accept(ns, (struct sockaddr *) &a, &len)) < 0)
+ {
+ Msg(errno, "accept");
+ return;
+ }
+#endif /* NAMEDPIPE */
+
+ p = (char *) &m;
+ left = sizeof(m);
+ while (left > 0)
+ {
+ len = read(ns, p, left);
+ if (len < 0 && errno == EINTR)
+ continue;
+ if (len <= 0)
+ break;
+ p += len;
+ left -= len;
+ }
+
+#ifdef NAMEDPIPE
+# ifndef BROKEN_PIPE
+ /* Reopen pipe to prevent EOFs at the select() call */
+ close(ServerSocket);
+ if ((ServerSocket = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
+ Panic(errno, "reopen fifo %s", SockPath);
+# endif
+#else
+ close(ns);
+#endif
+
+ if (len < 0)
+ {
+ Msg(errno, "read");
+ return;
+ }
+ if (left > 0)
+ {
+ if (left != sizeof(m))
+ Msg(0, "Message %d of %d bytes too small", left, (int)sizeof(m));
+ else
+ debug("No data on socket.\n");
+ return;
+ }
+ debug2("*** RecMsg: type %d tty %s\n", m.type, m.m_tty);
+ for (display = displays; display; display = display->d_next)
+ if (TTYCMP(D_usertty, m.m_tty) == 0)
+ break;
+ debug2("display: %s display %sfound\n", m.m_tty, display ? "" : "not ");
+ if (!display)
+ {
+ for (wi = windows; wi; wi = wi->w_next)
+ if (!TTYCMP(m.m_tty, wi->w_tty))
+ {
+ display = wi->w_display;
+ debug2("but window %s %sfound.\n", m.m_tty, display ? "" :
+ "(backfacing)");
+ break;
+ }
+ }
+
+ /* Remove the status to prevent garbage on the screen */
+ if (display && D_status)
+ RemoveStatus();
+
+ switch (m.type)
+ {
+ case MSG_WINCH:
+ if (display)
+ CheckScreenSize(1); /* Change fore */
+ break;
+ case MSG_CREATE:
+ /*
+ * the window that issued the create message need not be an active
+ * window. Then we create the window without having a display.
+ * Resulting in another inactive window.
+ *
+ * Currently we enforce that at least one display exists. But why?
+ * jw.
+ */
+ if (displays)
+ ExecCreate(&m);
+ break;
+ case MSG_CONT:
+ if (display && D_userpid != 0 && kill(D_userpid, 0) == 0)
+ break; /* Intruder Alert */
+ debug2("RecMsg: apid=%d,was %d\n", m.m.attach.apid, display ? D_userpid : 0);
+ /* FALLTHROUGH */
+ case MSG_ATTACH:
+ if (CheckPid(m.m.attach.apid))
+ {
+ Msg(0, "Attach attempt with bad pid(%d)!", m.m.attach.apid);
+ break;
+ }
+ if ((i = secopen(m.m_tty, O_RDWR | O_NONBLOCK, 0)) < 0)
+ {
+ Msg(errno, "Attach: Could not open %s!", m.m_tty);
+ Kill(m.m.attach.apid, SIG_BYE);
+ break;
+ }
+#ifdef PASSWORD
+ if (!CheckPasswd(m.m.attach.password, m.m.attach.apid, m.m_tty))
+ {
+ debug3("RcvMsg:Checkpass(%s,%d,%s) failed\n",
+ m.m.attach.password, m.m.attach.apid, m.m_tty);
+ close(i);
+ break;
+ }
+#else
+# ifdef MULTIUSER
+ Kill(m.m.attach.apid, SIGCONT);
+# endif
+#endif /* PASSWORD */
+ if (display)
+ {
+ write(i, "Attaching to a not detached screen?\n", 36);
+ close(i);
+ Kill(m.m.attach.apid, SIG_BYE);
+ Msg(0, "Attach msg ignored: We are not detached.");
+ break;
+ }
+
+#ifdef MULTIUSER
+ if (strcmp(m.m.attach.auser, LoginName))
+ if (*FindUserPtr(m.m.attach.auser) == 0)
+ {
+ write(i, "Access to session denied.\n", 26);
+ close(i);
+ Kill(m.m.attach.apid, SIG_BYE);
+ Msg(0, "Attach: access denied for user %s.", m.m.attach.auser);
+ break;
+ }
+#endif
+
+ debug2("RecMsg: apid %d is o.k. and we just opened '%s'\n", m.m.attach.apid, m.m_tty);
+ /* turn off iflag on a multi-attach... */
+ if (iflag && displays)
+ {
+ iflag = 0;
+ display = displays;
+#if defined(TERMIO) || defined(POSIX)
+ D_NewMode.tio.c_cc[VINTR] = VDISABLE;
+ D_NewMode.tio.c_lflag &= ~ISIG;
+#else /* TERMIO || POSIX */
+ D_NewMode.m_tchars.t_intrc = -1;
+#endif /* TERMIO || POSIX */
+ SetTTY(D_userfd, &D_NewMode);
+ }
+
+ /* create new display */
+ GetTTY(i, &Mode);
+ if (MakeDisplay(m.m.attach.auser, m.m_tty, m.m.attach.envterm, i, m.m.attach.apid, &Mode) == 0)
+ {
+ write(i, "Could not make display.\n", 24);
+ close(i);
+ Msg(0, "Attach: could not make display for user %s", m.m.attach.auser);
+ Kill(m.m.attach.apid, SIG_BYE);
+ break;
+ }
+#if defined(ultrix) || defined(pyr) || defined(NeXT)
+ brktty(D_userfd); /* for some strange reason this must be done */
+#endif
+#if defined(pyr) || defined(xelos) || defined(sequent)
+ /*
+ * Kludge for systems with braindamaged termcap routines,
+ * which evaluate $TERMCAP, regardless weather it describes
+ * the correct terminal type or not.
+ */
+ debug("unsetenv(TERMCAP) in case of a different terminal");
+ unsetenv("TERMCAP");
+#endif
+
+ /*
+ * We reboot our Terminal Emulator. Forget all we knew about
+ * the old terminal, reread the termcap entries in .screenrc
+ * (and nothing more from .screenrc is read. Mainly because
+ * I did not check, weather a full reinit is save. jw)
+ * and /etc/screenrc, and initialise anew.
+ */
+ if (extra_outcap)
+ free(extra_outcap);
+ if (extra_incap)
+ free(extra_incap);
+ extra_incap = extra_outcap = 0;
+ debug2("Message says size (%dx%d)\n", m.m.attach.columns, m.m.attach.lines);
+#ifdef ETCSCREENRC
+# ifdef ALLOW_SYSSCREENRC
+ if ((p = getenv("SYSSCREENRC")))
+ StartRc(p);
+ else
+# endif
+ StartRc(ETCSCREENRC);
+#endif
+ StartRc(RcFileName);
+ if (InitTermcap(m.m.attach.columns, m.m.attach.lines))
+ {
+ FreeDisplay();
+ Kill(m.m.attach.apid, SIG_BYE);
+ break;
+ }
+ InitTerm(m.m.attach.adaptflag);
+ if (displays->d_next == 0)
+ (void) chsock();
+ signal(SIGHUP, SigHup);
+#ifdef UTMPOK
+ /*
+ * we set the Utmp slots again, if we were detached normally
+ * and if we were detached by ^Z.
+ */
+ RemoveLoginSlot();
+ if (displays->d_next == 0)
+ for (wi = windows; wi; wi = wi->w_next)
+ if (wi->w_slot != (slot_t) -1)
+ SetUtmp(wi);
+#endif
+ SetMode(&D_OldMode, &D_NewMode);
+ SetTTY(D_userfd, &D_NewMode);
+
+ D_fore = NULL;
+ if (D_user->u_detachwin >= 0)
+ fore = wtab[D_user->u_detachwin];
+#ifdef MULTIUSER
+ if (!fore || fore->w_display || AclCheckPermWin(D_user, ACL_WRITE, fore))
+#else
+ if (!fore || fore->w_display)
+#endif
+ {
+ /* try to get another window */
+#ifdef MULTIUSER
+ for (wi = windows; wi; wi = wi->w_next)
+ if (!wi->w_display && !AclCheckPermWin(D_user, ACL_WRITE, fore))
+ break;
+ if (!wi)
+ for (wi = windows; wi; wi = wi->w_next)
+ if (!wi->w_display && !AclCheckPermWin(D_user, ACL_READ, fore))
+ break;
+ if (!wi)
+#endif
+ for (wi = windows; wi; wi = wi->w_next)
+ if (!wi->w_display)
+ break;
+ fore = wi;
+ }
+ if (fore)
+ SetForeWindow(fore);
+ Activate(0);
+ if (!D_fore)
+ ShowWindows();
+ if (displays->d_next == 0 && console_window)
+ {
+ if (TtyGrabConsole(console_window->w_ptyfd, 1, "reattach") == 0)
+ Msg(0, "console %s is on window %d", HostName, console_window->w_number);
+ }
+ debug("activated...\n");
+ break;
+ case MSG_ERROR:
+ Msg(0, "%s", m.m.message);
+ break;
+ case MSG_HANGUP:
+ SigHup(SIGARG);
+ break;
+#ifdef REMOTE_DETACH
+ case MSG_DETACH:
+# ifdef POW_DETACH
+ case MSG_POW_DETACH:
+# endif /* POW_DETACH */
+ for (display = displays; display; display = next)
+ {
+ next = display->d_next;
+# ifdef POW_DETACH
+ if (m.type == MSG_POW_DETACH)
+ Detach(D_REMOTE_POWER);
+ else
+# endif /* POW_DETACH */
+ if (m.type == MSG_DETACH)
+ Detach(D_REMOTE);
+ }
+ break;
+#endif
+ default:
+ Msg(0, "Invalid message (type %d).", m.type);
+ }
+}
+
+#if defined(_SEQUENT_) && !defined(NAMEDPIPE)
+#undef connect
+/*
+ * sequent_ptx socket emulation must have mode 000 on the socket!
+ */
+static int
+sconnect(s, sapp, len)
+int s, len;
+struct sockaddr *sapp;
+{
+ register struct sockaddr_un *sap;
+ struct stat st;
+ int x;
+
+ sap = (struct sockaddr_un *)sapp;
+ if (stat(sap->sun_path, &st))
+ return -1;
+ chmod(sap->sun_path, 0);
+ x = connect(s, (struct sockaddr *) sap, len);
+ chmod(sap->sun_path, st.st_mode);
+ return x;
+}
+#endif
+
+
+/*
+ * Set the mode bits of the socket to the current status
+ */
+int
+chsock()
+{
+ int r, euid = geteuid();
+ if (euid != real_uid)
+ {
+ if (UserContext() <= 0)
+ return UserStatus();
+ }
+ r = chmod(SockPath, SOCKMODE);
+ /*
+ * Sockets usually reside in the /tmp/ area, where sysadmin scripts
+ * may be happy to remove old files. We manually prevent the socket
+ * from becoming old. (chmod does not touch mtime).
+ */
+ (void)utime(SockPath, NULL);
+
+ if (euid != real_uid)
+ UserReturn(r);
+ return r;
+}
+
+
+/*
+ * Try to recreate the socket/pipe
+ */
+int
+RecoverSocket()
+{
+ close(ServerSocket);
+ if (geteuid() != real_uid)
+ {
+ if (UserContext() > 0)
+ UserReturn(unlink(SockPath));
+ (void)UserStatus();
+ }
+ else
+ (void) unlink(SockPath);
+
+ if ((ServerSocket = MakeServerSocket()) < 0)
+ return 0;
+ return 1;
+}
diff --git a/tek.patch b/tek.patch
new file mode 100644
index 0000000..10e0868
--- /dev/null
+++ b/tek.patch
@@ -0,0 +1,79 @@
+Zhang has developed a patch to the "screen" VT100 terminal emulation program
+that allows one to perform tektronics "tek40xx" style graphics in a
+screen window. I've tested it with gnuplot and it works quite well.
+
+Send flames or technical inquries to the patch author Xiaoguang
+Zhang (zhang@gmsds.ms.ornl.gov) and to screen@uni-erlangen.de
+
+=====================================================================
+
+*** ./ansi.h.orig Fri Jan 2 19:12:05 1970
+--- ./ansi.h Wed Nov 15 19:25:11 1995
+***************
+*** 56,62 ****
+ PRIN, /* Printer mode */
+ PRINESC, /* ESC seen in printer mode */
+ PRINCSI, /* CSI seen in printer mode */
+! PRIN4 /* CSI 4 seen in printer mode */
+ };
+
+ enum string_t
+--- 56,65 ----
+ PRIN, /* Printer mode */
+ PRINESC, /* ESC seen in printer mode */
+ PRINCSI, /* CSI seen in printer mode */
+! PRIN4, /* CSI 4 seen in printer mode */
+! TEK, /* Tektronix mode */
+! TEKESC, /* Tektronix escape */
+! TEKEND /* Tektronix ending sequence */
+ };
+
+ enum string_t
+*** ./ansi.c.orig Sun Oct 29 16:01:26 1995
+--- ./ansi.c Wed Nov 15 19:25:11 1995
+***************
+*** 805,810 ****
+--- 805,815 ----
+ case 'k':
+ StartString(AKA);
+ break;
++ case '\014':
++ curr->w_state = TEK;
++ RAW_PUTCHAR('\033');
++ RAW_PUTCHAR(c);
++ break;
+ default:
+ if (Special(c))
+ {
+***************
+*** 868,873 ****
+--- 873,899 ----
+ goto tryagain;
+ }
+ }
++ break;
++ case TEK:
++ switch (c)
++ {
++ case '@':
++ if ((unsigned char)*(buf - 2) == ' ') /* XXX: Yucc! */
++ curr->w_state = TEKESC;
++ /* FALLTHROUGH */
++ default:
++ RAW_PUTCHAR(c);
++ break;
++ }
++ break;
++ case TEKESC:
++ curr->w_state = (c == '\037') ? TEKEND : TEK;
++ RAW_PUTCHAR(c);
++ break;
++ case TEKEND:
++ if (c == '\030')
++ curr->w_state = LIT;
++ RAW_PUTCHAR(c);
+ break;
+ case LIT:
+ default:
+
+=====================================================================
diff --git a/term.c b/term.c
new file mode 100644
index 0000000..18cc080
--- /dev/null
+++ b/term.c
@@ -0,0 +1,257 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: term.c,v 1.4 1994/05/31 12:33:04 mlschroe Exp $ FAU")
+
+#include "term.h"
+
+#define KMAPDEF(s)
+#define KMAPADEF(s)
+#define KMAPMDEF(s)
+
+struct term term[T_N] =
+{
+/* display size */
+ { "li", T_NUM },
+ { "co", T_NUM },
+
+/* terminal types*/
+ { "hc", T_FLG },
+ { "os", T_FLG },
+ { "ns", T_FLG },
+/* cursor movement */
+ { "cm", T_STR },
+ { "ho", T_STR },
+ { "cr", T_STR },
+ { "up", T_STR },
+ { "UP", T_STR },
+ { "do", T_STR },
+ { "DO", T_STR },
+ { "bs", T_FLG },
+ { "bc", T_STR },
+ { "le", T_STR },
+ { "LE", T_STR },
+ { "nd", T_STR },
+ { "RI", T_STR },
+
+/* scroll */
+ { "cs", T_STR },
+ { "nl", T_STR },
+ { "sf", T_STR },
+ { "sr", T_STR },
+ { "al", T_STR },
+ { "AL", T_STR },
+ { "dl", T_STR },
+ { "DL", T_STR },
+
+/* insert/delete */
+ { "in", T_FLG },
+ { "im", T_STR },
+ { "ei", T_STR },
+ { "ic", T_STR },
+ { "IC", T_STR },
+ { "dc", T_STR },
+ { "DC", T_STR },
+
+/* erase */
+ { "ut", T_FLG },
+ { "cl", T_STR },
+ { "cd", T_STR },
+ { "CD", T_STR },
+ { "ce", T_STR },
+ { "cb", T_STR },
+
+/* initialise */
+ { "is", T_STR },
+ { "ti", T_STR },
+ { "te", T_STR },
+
+/* bell */
+ { "bl", T_STR },
+ { "vb", T_STR },
+
+/* resizing */
+ { "WS", T_STR },
+ { "Z0", T_STR },
+ { "Z1", T_STR },
+
+/* attributes */
+/* define T_ATTR */
+ { "mh", T_STR },
+ { "us", T_STR },
+ { "md", T_STR },
+ { "mr", T_STR },
+ { "so", T_STR },
+ { "mb", T_STR },
+ { "ue", T_STR },
+ { "se", T_STR },
+ { "me", T_STR },
+ { "ms", T_FLG },
+ { "sg", T_NUM },
+ { "ug", T_NUM },
+ { "sa", T_STR },
+
+/* color */
+ { "AF", T_STR },
+ { "AB", T_STR },
+ { "Sf", T_STR },
+ { "Sb", T_STR },
+ { "AX", T_FLG },
+
+/* keypad/cursorkeys */
+ { "ks", T_STR },
+ { "ke", T_STR },
+ { "CS", T_STR },
+ { "CE", T_STR },
+
+/* printer */
+ { "po", T_STR },
+ { "pf", T_STR },
+
+/* status line */
+ { "hs", T_FLG },
+ { "ws", T_NUM },
+ { "ts", T_STR },
+ { "fs", T_STR },
+ { "ds", T_STR },
+
+/* cursor visibility */
+ { "vi", T_STR },
+ { "vs", T_STR },
+ { "ve", T_STR },
+
+/* margin handling */
+ { "am", T_FLG },
+ { "xv", T_FLG },
+ { "xn", T_FLG },
+ { "OP", T_FLG },
+ { "LP", T_FLG },
+
+/* special settings */
+ { "NF", T_FLG },
+ { "nx", T_FLG },
+ { "AN", T_FLG },
+ { "OL", T_NUM },
+ { "KJ", T_STR },
+ { "VR", T_STR },
+ { "VN", T_STR },
+
+/* d_font setting */
+ { "G0", T_FLG },
+ { "S0", T_STR },
+ { "E0", T_STR },
+ { "C0", T_STR },
+ { "as", T_STR },
+ { "ae", T_STR },
+ { "ac", T_STR },
+ { "eA", T_STR },
+ { "XC", T_STR },
+
+/* keycaps */
+/* define T_CAPS */
+/* nolist */
+ { "k0", T_STR }, KMAPDEF("\033[10~")
+ { "k1", T_STR }, KMAPDEF("\033OP")
+ { "k2", T_STR }, KMAPDEF("\033OQ")
+ { "k3", T_STR }, KMAPDEF("\033OR")
+ { "k4", T_STR }, KMAPDEF("\033OS")
+ { "k5", T_STR }, KMAPDEF("\033[15~")
+ { "k6", T_STR }, KMAPDEF("\033[17~")
+ { "k7", T_STR }, KMAPDEF("\033[18~")
+ { "k8", T_STR }, KMAPDEF("\033[19~")
+ { "k9", T_STR }, KMAPDEF("\033[20~")
+ { "k;", T_STR }, KMAPDEF("\033[21~")
+ { "F1", T_STR }, KMAPDEF("\033[23~")
+ { "F2", T_STR }, KMAPDEF("\033[24~")
+ { "kb", T_STR }, KMAPDEF("\010")
+ { "kh", T_STR }, KMAPDEF("\033[1~") KMAPMDEF("g")
+ { "K1", T_STR },
+ { "K2", T_STR },
+ { "K3", T_STR },
+ { "K4", T_STR },
+ { "K5", T_STR },
+/* more keys for Andrew A. Chernov (ache@astral.msk.su) */
+ { "kA", T_STR },
+ { "ka", T_STR },
+ { "kB", T_STR },
+ { "kC", T_STR },
+ { "kD", T_STR }, KMAPDEF("\033[3~")
+ { "kE", T_STR },
+ { "kF", T_STR }, KMAPMDEF("\004")
+ { "kH", T_STR }, KMAPDEF("\033[4~") KMAPMDEF("G")
+ { "kI", T_STR }, KMAPDEF("\033[2~")
+ { "kL", T_STR },
+ { "kM", T_STR },
+ { "kN", T_STR }, KMAPDEF("\033[6~") KMAPMDEF("\006")
+ { "kP", T_STR }, KMAPDEF("\033[5~") KMAPMDEF("\002")
+ { "kR", T_STR }, KMAPMDEF("\025")
+ { "kS", T_STR },
+ { "kT", T_STR },
+ { "kt", T_STR },
+ { "@1", T_STR },
+ { "@7", T_STR },
+/* keys that can have two bindings */
+/* define T_CURSOR */
+ { "ku", T_STR }, KMAPDEF("\033[A") KMAPADEF("\033OA") KMAPMDEF("k")
+ { "kd", T_STR }, KMAPDEF("\033[B") KMAPADEF("\033OB") KMAPMDEF("j")
+ { "kr", T_STR }, KMAPDEF("\033[C") KMAPADEF("\033OC") KMAPMDEF("l")
+ { "kl", T_STR }, KMAPDEF("\033[D") KMAPADEF("\033OD") KMAPMDEF("h")
+/* define T_KEYPAD */
+ { "f0", T_STR }, KMAPDEF("0") KMAPADEF("\033Op")
+ { "f1", T_STR }, KMAPDEF("1") KMAPADEF("\033Oq")
+ { "f2", T_STR }, KMAPDEF("2") KMAPADEF("\033Or")
+ { "f3", T_STR }, KMAPDEF("3") KMAPADEF("\033Os")
+ { "f4", T_STR }, KMAPDEF("4") KMAPADEF("\033Ot")
+ { "f5", T_STR }, KMAPDEF("5") KMAPADEF("\033Ou")
+ { "f6", T_STR }, KMAPDEF("6") KMAPADEF("\033Ov")
+ { "f7", T_STR }, KMAPDEF("7") KMAPADEF("\033Ow")
+ { "f8", T_STR }, KMAPDEF("8") KMAPADEF("\033Ox")
+ { "f9", T_STR }, KMAPDEF("9") KMAPADEF("\033Oy")
+ { "f+", T_STR }, KMAPDEF("+") KMAPADEF("\033Ok")
+ { "f-", T_STR }, KMAPDEF("-") KMAPADEF("\033Om")
+ { "f*", T_STR }, KMAPDEF("*") KMAPADEF("\033Oj")
+ { "f/", T_STR }, KMAPDEF("/") KMAPADEF("\033Oo")
+ { "fq", T_STR }, KMAPDEF("=") KMAPADEF("\033OX")
+ { "f.", T_STR }, KMAPDEF(".") KMAPADEF("\033On")
+ { "f,", T_STR }, KMAPDEF(",") KMAPADEF("\033Ol")
+ { "fe", T_STR }, KMAPDEF("\015") KMAPADEF("\033OM")
+/* other things related to keycaps */
+/* define T_OCAPS */
+ { "km", T_FLG },
+ { "ko", T_STR },
+ { "l0", T_STR },
+ { "l1", T_STR },
+ { "l2", T_STR },
+ { "l3", T_STR },
+ { "l4", T_STR },
+ { "l5", T_STR },
+ { "l6", T_STR },
+ { "l7", T_STR },
+ { "l8", T_STR },
+ { "l9", T_STR },
+ { "la", T_STR },
+/* list */
+/* define T_ECAPS */
+/* define T_N */
+};
diff --git a/term.h.dist b/term.h.dist
new file mode 100644
index 0000000..73f021d
--- /dev/null
+++ b/term.h.dist
@@ -0,0 +1,237 @@
+/*
+ * This file is automagically created from term.c -- DO NOT EDIT
+ */
+
+#define T_FLG 0
+#define T_NUM 1
+#define T_STR 2
+
+struct term
+{
+ char *tcname;
+ int type;
+};
+
+union tcu
+{
+ int flg;
+ int num;
+ char *str;
+};
+
+#define d_LI d_tcs[0].num
+#define D_LI (D_tcs[0].num)
+#define d_CO d_tcs[1].num
+#define D_CO (D_tcs[1].num)
+#define d_HC d_tcs[2].flg
+#define D_HC (D_tcs[2].flg)
+#define d_OS d_tcs[3].flg
+#define D_OS (D_tcs[3].flg)
+#define d_NS d_tcs[4].flg
+#define D_NS (D_tcs[4].flg)
+#define d_CM d_tcs[5].str
+#define D_CM (D_tcs[5].str)
+#define d_HO d_tcs[6].str
+#define D_HO (D_tcs[6].str)
+#define d_CR d_tcs[7].str
+#define D_CR (D_tcs[7].str)
+#define d_UP d_tcs[8].str
+#define D_UP (D_tcs[8].str)
+#define d_CUP d_tcs[9].str
+#define D_CUP (D_tcs[9].str)
+#define d_DO d_tcs[10].str
+#define D_DO (D_tcs[10].str)
+#define d_CDO d_tcs[11].str
+#define D_CDO (D_tcs[11].str)
+#define d_BS d_tcs[12].flg
+#define D_BS (D_tcs[12].flg)
+#define d_BC d_tcs[13].str
+#define D_BC (D_tcs[13].str)
+#define d_LE d_tcs[14].str
+#define D_LE (D_tcs[14].str)
+#define d_CLE d_tcs[15].str
+#define D_CLE (D_tcs[15].str)
+#define d_ND d_tcs[16].str
+#define D_ND (D_tcs[16].str)
+#define d_CRI d_tcs[17].str
+#define D_CRI (D_tcs[17].str)
+#define d_CS d_tcs[18].str
+#define D_CS (D_tcs[18].str)
+#define d_NL d_tcs[19].str
+#define D_NL (D_tcs[19].str)
+#define d_SF d_tcs[20].str
+#define D_SF (D_tcs[20].str)
+#define d_SR d_tcs[21].str
+#define D_SR (D_tcs[21].str)
+#define d_AL d_tcs[22].str
+#define D_AL (D_tcs[22].str)
+#define d_CAL d_tcs[23].str
+#define D_CAL (D_tcs[23].str)
+#define d_DL d_tcs[24].str
+#define D_DL (D_tcs[24].str)
+#define d_CDL d_tcs[25].str
+#define D_CDL (D_tcs[25].str)
+#define d_IN d_tcs[26].flg
+#define D_IN (D_tcs[26].flg)
+#define d_IM d_tcs[27].str
+#define D_IM (D_tcs[27].str)
+#define d_EI d_tcs[28].str
+#define D_EI (D_tcs[28].str)
+#define d_IC d_tcs[29].str
+#define D_IC (D_tcs[29].str)
+#define d_CIC d_tcs[30].str
+#define D_CIC (D_tcs[30].str)
+#define d_DC d_tcs[31].str
+#define D_DC (D_tcs[31].str)
+#define d_CDC d_tcs[32].str
+#define D_CDC (D_tcs[32].str)
+#define d_UT d_tcs[33].flg
+#define D_UT (D_tcs[33].flg)
+#define d_CL d_tcs[34].str
+#define D_CL (D_tcs[34].str)
+#define d_CD d_tcs[35].str
+#define D_CD (D_tcs[35].str)
+#define d_CCD d_tcs[36].str
+#define D_CCD (D_tcs[36].str)
+#define d_CE d_tcs[37].str
+#define D_CE (D_tcs[37].str)
+#define d_CB d_tcs[38].str
+#define D_CB (D_tcs[38].str)
+#define d_IS d_tcs[39].str
+#define D_IS (D_tcs[39].str)
+#define d_TI d_tcs[40].str
+#define D_TI (D_tcs[40].str)
+#define d_TE d_tcs[41].str
+#define D_TE (D_tcs[41].str)
+#define d_BL d_tcs[42].str
+#define D_BL (D_tcs[42].str)
+#define d_VB d_tcs[43].str
+#define D_VB (D_tcs[43].str)
+#define d_CWS d_tcs[44].str
+#define D_CWS (D_tcs[44].str)
+#define d_CZ0 d_tcs[45].str
+#define D_CZ0 (D_tcs[45].str)
+#define d_CZ1 d_tcs[46].str
+#define D_CZ1 (D_tcs[46].str)
+#define T_ATTR 47
+#define d_MH d_tcs[47].str
+#define D_MH (D_tcs[47].str)
+#define d_US d_tcs[48].str
+#define D_US (D_tcs[48].str)
+#define d_MD d_tcs[49].str
+#define D_MD (D_tcs[49].str)
+#define d_MR d_tcs[50].str
+#define D_MR (D_tcs[50].str)
+#define d_SO d_tcs[51].str
+#define D_SO (D_tcs[51].str)
+#define d_MB d_tcs[52].str
+#define D_MB (D_tcs[52].str)
+#define d_UE d_tcs[53].str
+#define D_UE (D_tcs[53].str)
+#define d_SE d_tcs[54].str
+#define D_SE (D_tcs[54].str)
+#define d_ME d_tcs[55].str
+#define D_ME (D_tcs[55].str)
+#define d_MS d_tcs[56].flg
+#define D_MS (D_tcs[56].flg)
+#define d_SG d_tcs[57].num
+#define D_SG (D_tcs[57].num)
+#define d_UG d_tcs[58].num
+#define D_UG (D_tcs[58].num)
+#define d_SA d_tcs[59].str
+#define D_SA (D_tcs[59].str)
+#define d_CAF d_tcs[60].str
+#define D_CAF (D_tcs[60].str)
+#define d_CAB d_tcs[61].str
+#define D_CAB (D_tcs[61].str)
+#define d_CSF d_tcs[62].str
+#define D_CSF (D_tcs[62].str)
+#define d_CSB d_tcs[63].str
+#define D_CSB (D_tcs[63].str)
+#define d_CAX d_tcs[64].flg
+#define D_CAX (D_tcs[64].flg)
+#define d_KS d_tcs[65].str
+#define D_KS (D_tcs[65].str)
+#define d_KE d_tcs[66].str
+#define D_KE (D_tcs[66].str)
+#define d_CCS d_tcs[67].str
+#define D_CCS (D_tcs[67].str)
+#define d_CCE d_tcs[68].str
+#define D_CCE (D_tcs[68].str)
+#define d_PO d_tcs[69].str
+#define D_PO (D_tcs[69].str)
+#define d_PF d_tcs[70].str
+#define D_PF (D_tcs[70].str)
+#define d_HS d_tcs[71].flg
+#define D_HS (D_tcs[71].flg)
+#define d_WS d_tcs[72].num
+#define D_WS (D_tcs[72].num)
+#define d_TS d_tcs[73].str
+#define D_TS (D_tcs[73].str)
+#define d_FS d_tcs[74].str
+#define D_FS (D_tcs[74].str)
+#define d_DS d_tcs[75].str
+#define D_DS (D_tcs[75].str)
+#define d_VI d_tcs[76].str
+#define D_VI (D_tcs[76].str)
+#define d_VS d_tcs[77].str
+#define D_VS (D_tcs[77].str)
+#define d_VE d_tcs[78].str
+#define D_VE (D_tcs[78].str)
+#define d_AM d_tcs[79].flg
+#define D_AM (D_tcs[79].flg)
+#define d_XV d_tcs[80].flg
+#define D_XV (D_tcs[80].flg)
+#define d_XN d_tcs[81].flg
+#define D_XN (D_tcs[81].flg)
+#define d_COP d_tcs[82].flg
+#define D_COP (D_tcs[82].flg)
+#define d_CLP d_tcs[83].flg
+#define D_CLP (D_tcs[83].flg)
+#define d_CNF d_tcs[84].flg
+#define D_CNF (D_tcs[84].flg)
+#define d_NX d_tcs[85].flg
+#define D_NX (D_tcs[85].flg)
+#define d_CAN d_tcs[86].flg
+#define D_CAN (D_tcs[86].flg)
+#define d_COL d_tcs[87].num
+#define D_COL (D_tcs[87].num)
+#define d_CKJ d_tcs[88].str
+#define D_CKJ (D_tcs[88].str)
+#define d_CVR d_tcs[89].str
+#define D_CVR (D_tcs[89].str)
+#define d_CVN d_tcs[90].str
+#define D_CVN (D_tcs[90].str)
+#define d_CG0 d_tcs[91].flg
+#define D_CG0 (D_tcs[91].flg)
+#define d_CS0 d_tcs[92].str
+#define D_CS0 (D_tcs[92].str)
+#define d_CE0 d_tcs[93].str
+#define D_CE0 (D_tcs[93].str)
+#define d_CC0 d_tcs[94].str
+#define D_CC0 (D_tcs[94].str)
+#define d_AS d_tcs[95].str
+#define D_AS (D_tcs[95].str)
+#define d_AE d_tcs[96].str
+#define D_AE (D_tcs[96].str)
+#define d_AC d_tcs[97].str
+#define D_AC (D_tcs[97].str)
+#define d_EA d_tcs[98].str
+#define D_EA (D_tcs[98].str)
+#define d_CXC d_tcs[99].str
+#define D_CXC (D_tcs[99].str)
+#define T_CAPS 100
+#define T_CURSOR 139
+#define T_KEYPAD 143
+#define T_OCAPS 161
+#define T_ECAPS 174
+#define T_N 174
+
+#ifdef MAPKEYS
+# define KMAPDEFSTART 100
+# define NKMAPDEF 61
+# define KMAPADEFSTART 139
+# define NKMAPADEF 22
+# define KMAPMDEFSTART 114
+# define NKMAPMDEF 29
+#endif
diff --git a/term.sh b/term.sh
new file mode 100644
index 0000000..721a762
--- /dev/null
+++ b/term.sh
@@ -0,0 +1,166 @@
+#! /bin/sh
+
+if test -z "$AWK"; then
+ AWK=awk
+fi
+if test -z "$srcdir"; then
+ srcdir=.
+fi
+
+rm -f term.h
+cat << EOF > term.h
+/*
+ * This file is automagically created from term.c -- DO NOT EDIT
+ */
+
+#define T_FLG 0
+#define T_NUM 1
+#define T_STR 2
+
+struct term
+{
+ char *tcname;
+ int type;
+};
+
+union tcu
+{
+ int flg;
+ int num;
+ char *str;
+};
+
+EOF
+
+#
+# SCO-Unix sufferers may need to use the following lines:
+# perl -p < ${srcdir}/term.c \
+# -e 's/"/"C/ if /"[A-Z]."/;' \
+# -e 'y/[a-z]/[A-Z]/ if /"/;' \
+#
+sed < ${srcdir}/term.c \
+ -e '/"[A-Z]."/s/"/"C/' \
+ -e '/"/y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \
+| $AWK '
+/^ [{] ".*KMAPDEF[(].*$/{
+ if (min == 0) min = s
+ max = s;
+}
+/^ [{] ".*KMAPADEF[(].*$/{
+ if (amin == 0) amin = s
+ amax = s;
+}
+/^ [{] ".*KMAPMDEF[(].*$/{
+ if (mmin == 0) mmin = s
+ mmax = s;
+}
+/^ [{] ".*$/{
+a=substr($2,2,length($2)-3);
+b=substr($3,3,3);
+if (nolist == 0) {
+ printf "#define d_%s d_tcs[%d].%s\n",a,s,b
+ printf "#define D_%s (D_tcs[%d].%s)\n",a,s,b
+ }
+s++;
+}
+/\/* define/{
+printf "#define %s %d\n",$3,s
+}
+/\/* nolist/{
+nolist = 1;
+}
+/\/* list/{
+nolist = 0;
+}
+END {
+ printf "\n#ifdef MAPKEYS\n"
+ printf "# define KMAPDEFSTART %d\n", min
+ printf "# define NKMAPDEF %d\n", max-min+1
+ printf "# define KMAPADEFSTART %d\n", amin
+ printf "# define NKMAPADEF %d\n", amax-amin+1
+ printf "# define KMAPMDEFSTART %d\n", mmin
+ printf "# define NKMAPMDEF %d\n", mmax-mmin+1
+ printf "#endif\n"
+}
+' | sed -e s/NUM/num/ -e s/STR/str/ -e s/FLG/flg/ \
+>> term.h
+
+rm -f kmapdef.c
+cat << EOF > kmapdef.c
+/*
+ * This file is automagically created from term.c -- DO NOT EDIT
+ */
+
+#include "config.h"
+
+#ifdef MAPKEYS
+
+EOF
+
+$AWK < ${srcdir}/term.c '
+/^ [{] ".*KMAP.*$/{
+ for (i = 0; i < 3; i++) {
+ q = $(5+i)
+ if (substr(q, 1, 5) == "KMAPD") {
+ if (min == 0) min = s
+ max = s
+ arr[s] = substr(q, 9, length(q)-9)
+ }
+ if (substr(q, 1, 5) == "KMAPA") {
+ if (amin == 0) amin = s
+ amax = s
+ anarr[s] = substr(q, 10, length(q)-10)
+ }
+ if (substr(q, 1, 5) == "KMAPM") {
+ if (mmin == 0) mmin = s
+ mmax = s
+ mnarr[s] = substr(q, 10, length(q)-10)
+ }
+ }
+}
+/^ [{] ".*$/{
+ s++;
+}
+END {
+ printf "char *kmapdef[] = {\n"
+ for (s = min; s <= max; s++) {
+ if (arr[s])
+ printf "%s", arr[s]
+ else
+ printf "0"
+ if (s < max)
+ printf ",\n"
+ else
+ printf "\n"
+ }
+ printf "};\n\n"
+ printf "char *kmapadef[] = {\n"
+ for (s = amin; s <= amax; s++) {
+ if (anarr[s])
+ printf "%s", anarr[s]
+ else
+ printf "0"
+ if (s < amax)
+ printf ",\n"
+ else
+ printf "\n"
+ }
+ printf "};\n\n"
+ printf "char *kmapmdef[] = {\n"
+ for (s = mmin; s <= mmax; s++) {
+ if (mnarr[s])
+ printf "%s", mnarr[s]
+ else
+ printf "0"
+ if (s < mmax)
+ printf ",\n"
+ else
+ printf "\n"
+ }
+ printf "};\n\n#endif\n"
+}
+' >> kmapdef.c
+
+chmod a-w kmapdef.c
+chmod a-w term.h
+
diff --git a/termcap.c b/termcap.c
new file mode 100644
index 0000000..d4f748f
--- /dev/null
+++ b/termcap.c
@@ -0,0 +1,1272 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: termcap.c,v 1.8 1994/05/31 12:33:13 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+
+extern struct display *display, *displays;
+
+static void AddCap __P((char *));
+static void MakeString __P((char *, char *, int, char *));
+static char *findcap __P((char *, char **, int));
+static int copyarg __P((char **, char *));
+static char *e_tgetstr __P((char *, char **));
+static int e_tgetflag __P((char *));
+static int e_tgetnum __P((char *));
+#ifdef MAPKEYS
+static int addmapseq __P((char *, int));
+static int remmapseq __P((char *));
+#ifdef DEBUG
+static void dumpmap __P((void));
+#endif
+#endif
+
+
+extern struct term term[]; /* terminal capabilities */
+extern struct NewWindow nwin_undef, nwin_default, nwin_options;
+extern int force_vt, assume_LP;
+extern int Z0width, Z1width;
+#ifdef MAPKEYS
+extern struct action umtab[];
+extern struct action mmtab[];
+extern struct action dmtab[];
+extern char *kmap_extras[];
+extern int kmap_extras_fl[];
+extern int DefaultEsc;
+#endif
+
+char Termcap[TERMCAP_BUFSIZE + 8]; /* new termcap +8:"TERMCAP=" */
+static int Termcaplen;
+static int tcLineLen;
+char Term[MAXSTR+5]; /* +5: "TERM=" */
+char screenterm[20]; /* new $TERM, usually "screen" */
+
+char *extra_incap, *extra_outcap;
+
+static const char TermcapConst[] = "\\\n\
+\t:DO=\\E[%dB:LE=\\E[%dD:RI=\\E[%dC:UP=\\E[%dA:bs:bt=\\E[Z:\\\n\
+\t:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:ct=\\E[3g:\\\n\
+\t:do=^J:nd=\\E[C:pt:rc=\\E8:rs=\\Ec:sc=\\E7:st=\\EH:up=\\EM:\\\n\
+\t:le=^H:bl=^G:cr=^M:it#8:ho=\\E[H:nw=\\EE:ta=^I:is=\\E)0:";
+
+char *
+gettermcapstring(s)
+char *s;
+{
+ int i;
+
+ if (display == 0 || s == 0)
+ return 0;
+ for (i = 0; i < T_N; i++)
+ {
+ if (term[i].type != T_STR)
+ continue;
+ if (strcmp(term[i].tcname, s) == 0)
+ return D_tcs[i].str;
+ }
+ return 0;
+}
+
+int
+InitTermcap(wi, he)
+int wi;
+int he;
+{
+ register char *s;
+ int i;
+ char tbuf[TERMCAP_BUFSIZE], *tp;
+ int t, xue, xse, xme;
+
+ ASSERT(display);
+ bzero(tbuf, sizeof(tbuf));
+ debug1("InitTermcap: looking for tgetent('%s')\n", D_termname);
+ if (*D_termname == 0 || tgetent(tbuf, D_termname) != 1)
+ {
+#ifdef TERMINFO
+ Msg(0, "Cannot find terminfo entry for '%s'.", D_termname);
+#else
+ Msg(0, "Cannot find termcap entry for '%s'.", D_termname);
+#endif
+ return -1;
+ }
+ debug1("got it:\n%s\n",tbuf);
+#ifdef DEBUG
+ if (extra_incap)
+ debug1("Extra incap: %s\n", extra_incap);
+ if (extra_outcap)
+ debug1("Extra outcap: %s\n", extra_outcap);
+#endif
+
+ if ((D_tentry = (char *)malloc(TERMCAP_BUFSIZE + (extra_incap ? strlen(extra_incap) + 1 : 0))) == 0)
+ {
+ Msg(0, strnomem);
+ return -1;
+ }
+
+ tp = D_tentry;
+ for (i = 0; i < T_N; i++)
+ {
+ switch(term[i].type)
+ {
+ case T_FLG:
+ D_tcs[i].flg = e_tgetflag(term[i].tcname);
+ break;
+ case T_NUM:
+ D_tcs[i].num = e_tgetnum(term[i].tcname);
+ break;
+ case T_STR:
+ D_tcs[i].str = e_tgetstr(term[i].tcname, &tp);
+ /* no empty strings, please */
+ if (D_tcs[i].str && *D_tcs[i].str == 0)
+ D_tcs[i].str = 0;
+ break;
+ default:
+ Panic(0, "Illegal tc type in entry #%d", i);
+ /*NOTREACHED*/
+ }
+ }
+ if (D_HC)
+ {
+ Msg(0, "You can't run screen on a hardcopy terminal.");
+ return -1;
+ }
+ if (D_OS)
+ {
+ Msg(0, "You can't run screen on a terminal that overstrikes.");
+ return -1;
+ }
+ if (!D_CL)
+ {
+ Msg(0, "Clear screen capability required.");
+ return -1;
+ }
+ if (!D_CM)
+ {
+ Msg(0, "Addressable cursor capability required.");
+ return -1;
+ }
+ if ((s = getenv("COLUMNS")) && (i = atoi(s)) > 0)
+ D_CO = i;
+ if ((s = getenv("LINES")) && (i = atoi(s)) > 0)
+ D_LI = i;
+ if (wi)
+ D_CO = wi;
+ if (he)
+ D_LI = he;
+ if (D_CO <= 0)
+ D_CO = 80;
+ if (D_LI <= 0)
+ D_LI = 24;
+
+ if (nwin_options.flowflag == nwin_undef.flowflag)
+ nwin_default.flowflag = D_CNF ? FLOW_NOW * 0 :
+ D_NX ? FLOW_NOW * 1 :
+ FLOW_AUTOFLAG;
+ D_CLP |= (assume_LP || !D_AM || D_XV || D_XN ||
+ (!extra_incap && !strncmp(D_termname, "vt", 2)));
+ if (!D_BL)
+ D_BL = "\007";
+ if (!D_BC)
+ {
+ if (D_BS)
+ D_BC = "\b";
+ else
+ D_BC = D_LE;
+ }
+ if (!D_CR)
+ D_CR = "\r";
+ if (!D_NL)
+ D_NL = "\n";
+
+ /*
+ * Set up attribute handling.
+ * This is rather complicated because termcap has different
+ * attribute groups.
+ */
+
+ if (D_UG > 0)
+ D_US = D_UE = 0;
+ if (D_SG > 0)
+ D_SO = D_SE = 0;
+ /* Unfortunatelly there is no 'mg' capability.
+ * For now we think that mg > 0 if sg and ug > 0.
+ */
+ if (D_UG > 0 && D_SG > 0)
+ D_MH = D_MD = D_MR = D_MB = D_ME = 0;
+
+ xue = ATYP_U;
+ xse = ATYP_S;
+ xme = ATYP_M;
+
+ if (D_SO && D_SE == 0)
+ {
+ Msg(0, "Warning: 'so' but no 'se' capability.");
+ if (D_ME)
+ xse = xme;
+ else
+ D_SO = 0;
+ }
+ if (D_US && D_UE == 0)
+ {
+ Msg(0, "Warning: 'us' but no 'ue' capability.");
+ if (D_ME)
+ xue = xme;
+ else
+ D_US = 0;
+ }
+ if ((D_MH || D_MD || D_MR || D_MB) && D_ME == 0)
+ {
+ Msg(0, "Warning: 'm?' but no 'me' capability.");
+ D_MH = D_MD = D_MR = D_MB = 0;
+ }
+ /*
+ * Does ME also reverse the effect of SO and/or US? This is not
+ * clearly specified by the termcap manual. Anyway, we should at
+ * least look whether ME and SE/UE are equal:
+ */
+ if (D_UE && D_SE && strcmp(D_SE, D_UE) == 0)
+ xse = xue;
+ if (D_SE && D_ME && strcmp(D_ME, D_SE) == 0)
+ xse = xme;
+ if (D_UE && D_ME && strcmp(D_ME, D_UE) == 0)
+ xue = xme;
+
+ for (i = 0; i < NATTR; i++)
+ {
+ D_attrtab[i] = D_tcs[T_ATTR + i].str;
+ D_attrtyp[i] = i == ATTR_SO ? xse : (i == ATTR_US ? xue : xme);
+ }
+
+ /* Set up missing entries (attributes are priority ordered) */
+ s = 0;
+ t = 0;
+ for (i = 0; i < NATTR; i++)
+ if ((s = D_attrtab[i]))
+ {
+ t = D_attrtyp[i];
+ break;
+ }
+ for (i = 0; i < NATTR; i++)
+ {
+ if (D_attrtab[i] == 0)
+ {
+ D_attrtab[i] = s;
+ D_attrtyp[i] = t;
+ }
+ else
+ {
+ s = D_attrtab[i];
+ t = D_attrtyp[i];
+ }
+ }
+ if (D_CAF == 0 && D_CAB == 0)
+ {
+ /* hmm, where's the difference? */
+ D_CAF = D_CSF;
+ D_CAB = D_CSB;
+ }
+
+ if (!D_DO)
+ D_DO = D_NL;
+ if (!D_SF)
+ D_SF = D_NL;
+ if (D_IN)
+ D_IC = D_IM = 0;
+ if (D_EI == 0)
+ D_IM = 0;
+ /* some strange termcap entries have IC == IM */
+ if (D_IC && D_IM && strcmp(D_IC, D_IM) == 0)
+ D_IC = 0;
+ if (D_KE == 0)
+ D_KS = 0;
+ if (D_CVN == 0)
+ D_CVR = 0;
+ if (D_VE == 0)
+ D_VI = D_VS = 0;
+ if (D_CCE == 0)
+ D_CCS = 0;
+ if (D_CG0)
+ {
+ if (D_CS0 == 0)
+#ifdef TERMINFO
+ D_CS0 = "\033(%p1%c";
+#else
+ D_CS0 = "\033(%.";
+#endif
+ if (D_CE0 == 0)
+ D_CE0 = "\033(B";
+ D_AC = 0;
+ }
+ else if (D_AC || (D_AS && D_AE)) /* some kind of graphics */
+ {
+ D_CS0 = (D_AS && D_AE) ? D_AS : "";
+ D_CE0 = (D_AS && D_AE) ? D_AE : "";
+ D_CC0 = D_AC;
+ }
+ else
+ {
+ D_CS0 = D_CE0 = "";
+ D_CC0 = 0;
+ D_AC = ""; /* enable default string */
+ }
+
+ for (i = 0; i < 256; i++)
+ D_c0_tab[i] = i;
+ if (D_AC)
+ {
+ /* init with default string first */
+ s = "l+m+k+j+u+t+v+w+q-x|n+o~s_p\"r#`+a:f'g#~o.v-^+<,>h#I#0#y<z>";
+ for (i = strlen(s) & ~1; i >= 0; i -= 2)
+ D_c0_tab[(int)(unsigned char)s[i]] = s[i + 1];
+ }
+ if (D_CC0)
+ for (i = strlen(D_CC0) & ~1; i >= 0; i -= 2)
+ D_c0_tab[(int)(unsigned char)D_CC0[i]] = D_CC0[i + 1];
+ debug1("ISO2022 = %d\n", D_CG0);
+ if (D_PF == 0)
+ D_PO = 0;
+ debug2("terminal size is %d, %d (says TERMCAP)\n", D_CO, D_LI);
+
+ if (D_CXC)
+ if (CreateTransTable(D_CXC))
+ return -1;
+
+ /* Termcap fields Z0 & Z1 contain width-changing sequences. */
+ if (D_CZ1 == 0)
+ D_CZ0 = 0;
+ Z0width = 132;
+ Z1width = 80;
+
+ CheckScreenSize(0);
+
+ if (D_TS == 0 || D_FS == 0 || D_DS == 0)
+ D_HS = 0;
+ if (D_HS)
+ {
+ debug("oy! we have a hardware status line, says termcap\n");
+ if (D_WS <= 0)
+ D_WS = D_width;
+ }
+#ifdef KANJI
+ D_kanji = 0;
+ if (D_CKJ)
+ {
+ if (strcmp(D_CKJ, "euc") == 0)
+ D_kanji = EUC;
+ else if (strcmp(D_CKJ, "sjis") == 0)
+ D_kanji = SJIS;
+ }
+#endif
+
+ D_UPcost = CalcCost(D_UP);
+ D_DOcost = CalcCost(D_DO);
+ D_NLcost = CalcCost(D_NL);
+ D_LEcost = CalcCost(D_BC);
+ D_NDcost = CalcCost(D_ND);
+ D_CRcost = CalcCost(D_CR);
+ D_IMcost = CalcCost(D_IM);
+ D_EIcost = CalcCost(D_EI);
+
+#ifdef AUTO_NUKE
+ if (D_CAN)
+ {
+ debug("termcap has AN, setting autonuke\n");
+ D_auto_nuke = 1;
+ }
+#endif
+ if (D_COL > 0)
+ {
+ debug1("termcap has OL (%d), setting limit\n", D_COL);
+ D_obufmax = D_COL;
+ }
+#ifdef MAPKEYS
+ D_nseqs = 0;
+ for (i = 0; i < T_OCAPS - T_CAPS; i++)
+ remap(i, 1);
+ for (i = 0; i < KMAP_EXT; i++)
+ remap(i + (KMAP_KEYS+KMAP_AKEYS), 1);
+ D_seqp = D_kmaps[0].seq;
+#endif
+
+ D_tcinited = 1;
+ MakeTermcap(0);
+#ifdef MAPKEYS
+ CheckEscape();
+#endif
+ return 0;
+}
+
+#ifdef MAPKEYS
+
+int
+remap(n, map)
+int n;
+int map;
+{
+ char *s;
+ int fl = 0, domap = 0;
+ struct action *a1, *a2, *tab;
+
+ tab = umtab;
+ for (;;)
+ {
+ a1 = &tab[n];
+ a2 = 0;
+ if (n < KMAP_KEYS+KMAP_AKEYS)
+ {
+ if (n >= KMAP_KEYS)
+ n -= T_OCAPS-T_CURSOR;
+ s = D_tcs[n + T_CAPS].str;
+ if (n >= T_CURSOR-T_CAPS)
+ a2 = &tab[n + (T_OCAPS-T_CURSOR)];
+ }
+ else
+ {
+ s = kmap_extras[n - (KMAP_KEYS+KMAP_AKEYS)];
+ fl |= kmap_extras_fl[n - (KMAP_KEYS+KMAP_AKEYS)];
+ }
+ if (s == 0)
+ return 0;
+ if (a1 && a1->nr == RC_ILLEGAL)
+ a1 = 0;
+ if (a2 && a2->nr == RC_ILLEGAL)
+ a2 = 0;
+ if (a1 && a1->nr == RC_STUFF && strcmp(a1->args[0], s) == 0)
+ a1 = 0;
+ if (a2 && a2->nr == RC_STUFF && strcmp(a2->args[0], s) == 0)
+ a2 = 0;
+ domap |= (a1 || a2);
+ if (tab == umtab)
+ tab = dmtab;
+ else if (tab == dmtab)
+ tab = mmtab;
+ else
+ break;
+ }
+
+ if (map == 0 && domap)
+ return 0;
+ if (map && !domap)
+ return 0;
+ debug3("%smapping %s %#x\n", map? "" :"un",s,n);
+ if (map)
+ return addmapseq(s, n | fl);
+ else
+ return remmapseq(s);
+}
+
+void
+CheckEscape()
+{
+ struct display *odisplay;
+ int i, nr;
+
+ if (DefaultEsc >= 0)
+ return;
+
+ odisplay = display;
+ for (display = displays; display; display = display->d_next)
+ {
+ for (i = 0; i < D_nseqs; i++)
+ {
+ nr = D_kmaps[i].nr & ~KMAP_NOTIMEOUT;
+ if (umtab[nr].nr == RC_COMMAND)
+ break;
+ if (umtab[nr].nr == RC_ILLEGAL && dmtab[nr].nr == RC_COMMAND)
+ break;
+ }
+ if (i >= D_nseqs)
+ break;
+ }
+ if (display == 0)
+ {
+ display = odisplay;
+ return;
+ }
+ ParseEscape((struct user *)0, "^aa");
+ if (odisplay->d_user->u_Esc <= 0)
+ odisplay->d_user->u_Esc = DefaultEsc;
+ display = 0;
+ Msg(0, "Warning: escape char set back to ^A");
+ display = odisplay;
+}
+
+static int
+addmapseq(seq, nr)
+char *seq;
+int nr;
+{
+ int i, j = 0, k, mo, m;
+ char *p, *o;
+
+ k = strlen(seq);
+ if (k > sizeof(D_kmaps[0].seq) - 1)
+ return -1;
+ for (i = 0; i < D_nseqs; i++)
+ if ((j = strcmp(D_kmaps[i].seq, seq)) >= 0)
+ break;
+ if (i < D_nseqs && j == 0)
+ {
+ D_kmaps[i].nr = nr;
+ return 0;
+ }
+ if (D_nseqs >= sizeof(D_kmaps)/sizeof(*D_kmaps)) /* just in case... */
+ return -1;
+ for (j = D_nseqs - 1; j >= i; j--)
+ D_kmaps[j + 1] = D_kmaps[j];
+ p = D_kmaps[i].seq;
+ o = D_kmaps[i].off;
+ strcpy(p, seq);
+ bzero(o, k + 1);
+ D_kmaps[i].nr = nr;
+ D_nseqs++;
+
+ if (i + 1 < D_nseqs)
+ for (j = 0; *p; p++, o++, j++)
+ {
+ if (D_kmaps[i + 1].seq[j] != *p)
+ {
+ if (D_kmaps[i + 1].seq[j])
+ *o = 1;
+ break;
+ }
+ *o = D_kmaps[i + 1].off[j] ? D_kmaps[i + 1].off[j] + 1 : 0;
+ }
+
+ for (k = 0; k < i; k++)
+ for (m = j = 0, p = D_kmaps[k].seq, o = D_kmaps[k].off; *p; p++, o++, j++)
+ {
+ mo = m;
+ if (!m && *p != D_kmaps[i].seq[j])
+ m = 1;
+ if (*o == 0 && mo == 0 && m)
+ *o = i - k;
+ if (*o < i - k || (*o == i - k && m))
+ continue;
+ (*o)++;
+ }
+#ifdef DEBUG
+ dumpmap();
+#endif
+ return 0;
+}
+
+static int
+remmapseq(seq)
+char *seq;
+{
+ int i, j = 0, k;
+ char *p, *o;
+
+ for (i = 0; i < D_nseqs; i++)
+ if ((j = strcmp(D_kmaps[i].seq, seq)) >= 0)
+ break;
+ if (i == D_nseqs || j)
+ return -1;
+ for (k = 0; k < i; k++)
+ for (j = 0, p = D_kmaps[k].seq, o = D_kmaps[k].off; *p; p++, o++, j++)
+ {
+ if (k + *o == i)
+ *o = D_kmaps[i].off[j] ? D_kmaps[i].off[j] + *o - 1 : 0;
+ else if (k + *o > i)
+ (*o)--;
+ }
+ for (j = i + 1; j < D_nseqs; j++)
+ D_kmaps[j - 1] = D_kmaps[j];
+ D_nseqs--;
+#ifdef DEBUG
+ dumpmap();
+#endif
+ return 0;
+}
+
+#ifdef DEBUG
+static void
+dumpmap()
+{
+ char *p, *o;
+ int i,j,n;
+ debug("Mappings:\n");
+ for (i = 0; i < D_nseqs; i++)
+ {
+ for (j = 0, p = D_kmaps[i].seq, o = D_kmaps[i].off; *p; p++, o++, j++)
+ {
+ if (*p > ' ' && (unsigned char)*p < 0177)
+ {
+ debug2("%c[%d] ", *p, *o);
+ }
+ else
+ debug2("\\%03o[%d] ", (unsigned char)*p, *o);
+ }
+ n = D_kmaps[i].nr;
+ debug2(" ==> %d%s\n", n & ~KMAP_NOTIMEOUT, (n & KMAP_NOTIMEOUT) ? " (no timeout)" : "");
+ }
+}
+#endif
+
+#endif
+
+static void
+AddCap(s)
+char *s;
+{
+ register int n;
+
+ if (tcLineLen + (n = strlen(s)) > 55 && Termcaplen < TERMCAP_BUFSIZE + 8 - 4)
+ {
+ strcpy(Termcap + Termcaplen, "\\\n\t:");
+ Termcaplen += 4;
+ tcLineLen = 0;
+ }
+ if (Termcaplen + n < TERMCAP_BUFSIZE + 8)
+ {
+ strcpy(Termcap + Termcaplen, s);
+ Termcaplen += n;
+ tcLineLen += n;
+ }
+ else
+ Panic(0, "TERMCAP overflow - sorry.");
+}
+
+char *
+MakeTermcap(aflag)
+int aflag;
+{
+ char buf[TERMCAP_BUFSIZE];
+ register char *p, *cp, *s, ch, *tname;
+ int i, wi, he;
+
+ if (display)
+ {
+ wi = D_width;
+ he = D_height;
+ tname = D_termname;
+ }
+ else
+ {
+ wi = 80;
+ he = 24;
+ tname = "vt100";
+ }
+ debug1("MakeTermcap(%d)\n", aflag);
+ if ((s = getenv("SCREENCAP")) && strlen(s) < TERMCAP_BUFSIZE)
+ {
+ sprintf(Termcap, "TERMCAP=%s", s);
+ sprintf(Term, "TERM=screen");
+ debug("getenvSCREENCAP o.k.\n");
+ return Termcap;
+ }
+ Termcaplen = 0;
+ debug1("MakeTermcap screenterm='%s'\n", screenterm);
+ debug1("MakeTermcap termname='%s'\n", tname);
+ if (*screenterm == '\0')
+ {
+ debug("MakeTermcap sets screenterm=screen\n");
+ strcpy(screenterm, "screen");
+ }
+ do
+ {
+ sprintf(Term, "TERM=");
+ p = Term + 5;
+ if (!aflag && strlen(screenterm) + strlen(tname) < MAXSTR-1)
+ {
+ sprintf(p, "%s.%s", screenterm, tname);
+ if (tgetent(buf, p) == 1)
+ break;
+ }
+ if (wi >= 132)
+ {
+ sprintf(p, "%s-w", screenterm);
+ if (tgetent(buf, p) == 1)
+ break;
+ }
+ sprintf(p, "%s", screenterm);
+ if (tgetent(buf, p) == 1)
+ break;
+ sprintf(p, "vt100");
+ }
+ while (0); /* Goto free programming... */
+
+ /* check for compatibility problems, displays == 0 after fork */
+ {
+ char *tgetstr(), xbuf[TERMCAP_BUFSIZE], *xbp = xbuf;
+ if (tgetstr("im", &xbp) && tgetstr("ic", &xbp) && displays)
+ {
+#ifdef TERMINFO
+ Msg(0, "Warning: smir and ich1 set in %s terminfo entry", p);
+#else
+ Msg(0, "Warning: im and ic set in %s termcap entry", p);
+#endif
+ }
+ }
+
+ tcLineLen = 100; /* Force NL */
+ sprintf(Termcap,
+ "TERMCAP=SC|%s|VT 100/ANSI X3.64 virtual terminal", Term + 5);
+ Termcaplen = strlen(Termcap);
+ debug1("MakeTermcap decided '%s'\n", p);
+ if (extra_outcap && *extra_outcap)
+ {
+ for (cp = extra_outcap; (p = index(cp, ':')); cp = p)
+ {
+ ch = *++p;
+ *p = '\0';
+ AddCap(cp);
+ *p = ch;
+ }
+ tcLineLen = 100; /* Force NL */
+ }
+ debug1("MakeTermcap after outcap '%s'\n", (char *)TermcapConst);
+ if (Termcaplen + strlen(TermcapConst) < TERMCAP_BUFSIZE)
+ {
+ strcpy(Termcap + Termcaplen, (char *)TermcapConst);
+ Termcaplen += strlen(TermcapConst);
+ }
+ sprintf(buf, "li#%d:co#%d:", he, wi);
+ AddCap(buf);
+ AddCap("am:");
+ if (aflag || (force_vt && !D_COP) || D_CLP || !D_AM)
+ {
+ AddCap("xn:");
+ AddCap("xv:");
+ AddCap("LP:");
+ }
+ if (aflag || (D_CS && D_SR) || D_AL || D_CAL)
+ {
+ AddCap("sr=\\EM:");
+ AddCap("al=\\E[L:");
+ AddCap("AL=\\E[%dL:");
+ }
+ else if (D_SR)
+ AddCap("sr=\\EM:");
+ if (aflag || D_CS)
+ AddCap("cs=\\E[%i%d;%dr:");
+ if (aflag || D_CS || D_DL || D_CDL)
+ {
+ AddCap("dl=\\E[M:");
+ AddCap("DL=\\E[%dM:");
+ }
+ if (aflag || D_DC || D_CDC)
+ {
+ AddCap("dc=\\E[P:");
+ AddCap("DC=\\E[%dP:");
+ }
+ if (aflag || D_CIC || D_IC || D_IM)
+ {
+ AddCap("im=\\E[4h:");
+ AddCap("ei=\\E[4l:");
+ AddCap("mi:");
+ AddCap("IC=\\E[%d@:");
+ }
+#ifdef MAPKEYS
+ AddCap("ks=\\E[?1h\\E=:");
+ AddCap("ke=\\E[?1l\\E>:");
+#endif
+ AddCap("vi=\\E[?25l:");
+ AddCap("ve=\\E[34h\\E[?25h:");
+ AddCap("vs=\\E[34l:");
+ if (display)
+ {
+ if (D_US)
+ {
+ AddCap("us=\\E[4m:");
+ AddCap("ue=\\E[24m:");
+ }
+ if (D_SO)
+ {
+ AddCap("so=\\E[3m:");
+ AddCap("se=\\E[23m:");
+ }
+ if (D_MB)
+ AddCap("mb=\\E[5m:");
+ if (D_MD)
+ AddCap("md=\\E[1m:");
+ if (D_MH)
+ AddCap("mh=\\E[2m:");
+ if (D_MR)
+ AddCap("mr=\\E[7m:");
+ if (D_MB || D_MD || D_MH || D_MR)
+ AddCap("me=\\E[m:ms:");
+ if (D_CAF || D_CAB)
+ AddCap("Co#8:pa#64:AF=\\E[3%dm:AB=\\E[4%dm:op=\\E[39;49m:AX:");
+ if (D_VB)
+ AddCap("vb=\\Eg:");
+#ifndef MAPKEYS
+ if (D_KS)
+ {
+ AddCap("ks=\\E=:");
+ AddCap("ke=\\E>:");
+ }
+ if (D_CCS)
+ {
+ AddCap("CS=\\E[?1h:");
+ AddCap("CE=\\E[?1l:");
+ }
+#endif
+ if (D_CG0)
+ AddCap("G0:");
+ if (D_CC0 || (D_CS0 && *D_CS0))
+ {
+ AddCap("as=\\E(0:");
+ AddCap("ae=\\E(B:");
+ /* avoid `` because some shells dump core... */
+ AddCap("ac=\\140\\140aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~..--++,,hhII00:");
+ }
+ if (D_PO)
+ {
+ AddCap("po=\\E[5i:");
+ AddCap("pf=\\E[4i:");
+ }
+ if (D_CZ0)
+ {
+ AddCap("Z0=\\E[?3h:");
+ AddCap("Z1=\\E[?3l:");
+ }
+ if (D_CWS)
+ AddCap("WS=\\E[8;%d;%dt:");
+ }
+ for (i = T_CAPS; i < T_ECAPS; i++)
+ {
+#ifdef MAPKEYS
+ struct action *act;
+ if (i < T_OCAPS)
+ {
+ if (i >= T_KEYPAD) /* don't put keypad codes in TERMCAP */
+ continue; /* - makes it too big */
+ if (i >= T_CURSOR && i < T_OCAPS)
+ {
+ act = &umtab[i - (T_CURSOR - T_OCAPS + T_CAPS)];
+ if (act->nr == RC_ILLEGAL)
+ act = &dmtab[i - (T_CURSOR - T_OCAPS + T_CAPS)];
+ }
+ else
+ {
+ act = &umtab[i - T_CAPS];
+ if (act->nr == RC_ILLEGAL)
+ act = &dmtab[i - T_CAPS];
+ }
+ if (act->nr != RC_ILLEGAL)
+ {
+ if (act->nr == RC_STUFF)
+ {
+ MakeString(term[i].tcname, buf, sizeof(buf), act->args[0]);
+ AddCap(buf);
+ }
+ continue;
+ }
+ }
+#endif
+ if (display == 0)
+ continue;
+ switch(term[i].type)
+ {
+ case T_STR:
+ if (D_tcs[i].str == 0)
+ break;
+ MakeString(term[i].tcname, buf, sizeof(buf), D_tcs[i].str);
+ AddCap(buf);
+ break;
+ case T_FLG:
+ if (D_tcs[i].flg == 0)
+ break;
+ sprintf(buf, "%s:", term[i].tcname);
+ AddCap(buf);
+ break;
+ default:
+ break;
+ }
+ }
+ debug("MakeTermcap: end\n");
+ return Termcap;
+}
+
+static void
+MakeString(cap, buf, buflen, s)
+char *cap, *buf;
+int buflen;
+char *s;
+{
+ register char *p, *pmax;
+ register unsigned int c;
+
+ p = buf;
+ pmax = p + buflen - (3+4+2);
+ *p++ = *cap++;
+ *p++ = *cap;
+ *p++ = '=';
+ while ((c = *s++) && (p < pmax))
+ {
+ switch (c)
+ {
+ case '\033':
+ *p++ = '\\';
+ *p++ = 'E';
+ break;
+ case ':':
+ sprintf(p, "\\072");
+ p += 4;
+ break;
+ case '^':
+ case '\\':
+ *p++ = '\\';
+ *p++ = c;
+ break;
+ default:
+ if (c >= 200)
+ {
+ sprintf(p, "\\%03o", c & 0377);
+ p += 4;
+ }
+ else if (c < ' ')
+ {
+ *p++ = '^';
+ *p++ = c + '@';
+ }
+ else
+ *p++ = c;
+ }
+ }
+ *p++ = ':';
+ *p = '\0';
+}
+
+
+#undef QUOTES
+#define QUOTES(p) \
+ (*p == '\\' && (p[1] == '\\' || p[1] == ',' || p[1] == '%'))
+
+int
+CreateTransTable(s)
+char *s;
+{
+ int curchar;
+ char *templ, *arg;
+ int templlen;
+ int templnsub;
+ char *p, *sx;
+ char **ctable;
+ int l, c;
+
+ if ((D_xtable = (char ***)malloc(256 * sizeof(char **))) == 0)
+ {
+ Msg(0, strnomem);
+ return -1;
+ }
+ bzero((char *)D_xtable, 256 * sizeof(char **));
+
+ while (*s)
+ {
+ if (QUOTES(s))
+ s++;
+ curchar = (unsigned char)*s++;
+ if (curchar == 'B')
+ curchar = 0; /* ASCII */
+ templ = s;
+ templlen = 0;
+ templnsub = 0;
+ if (D_xtable[curchar] == 0)
+ {
+ if ((D_xtable[curchar] = (char **)malloc(257 * sizeof(char *))) == 0)
+ {
+ Msg(0, strnomem);
+ FreeTransTable();
+ return -1;
+ }
+ bzero((char *)D_xtable[curchar], 257 * sizeof(char *));
+ }
+ ctable = D_xtable[curchar];
+ for(; *s && *s != ','; s++)
+ {
+ if (QUOTES(s))
+ s++;
+ else if (*s == '%')
+ {
+ templnsub++;
+ continue;
+ }
+ templlen++;
+ }
+ if (*s++ == 0)
+ break;
+ while (*s && *s != ',')
+ {
+ c = (unsigned char)*s++;
+ if (QUOTES((s - 1)))
+ c = (unsigned char)*s++;
+ else if (c == '%')
+ c = 256;
+ if (ctable[c])
+ free(ctable[c]);
+ arg = s;
+ l = copyarg(&s, (char *)0);
+ if (c != 256)
+ l = l * templnsub + templlen;
+ if ((ctable[c] = (char *)malloc(l + 1)) == 0)
+ {
+ Msg(0, strnomem);
+ FreeTransTable();
+ return -1;
+ }
+ sx = ctable[c];
+ for (p = ((c == 256) ? "%" : templ); *p && *p != ','; p++)
+ {
+ if (QUOTES(p))
+ p++;
+ else if (*p == '%')
+ {
+ s = arg;
+ sx += copyarg(&s, sx);
+ continue;
+ }
+ *sx++ = *p;
+ }
+ *sx = 0;
+ ASSERT(ctable[c] + l == sx);
+ debug3("XC: %c %c->%s\n", curchar, c, ctable[c]);
+ }
+ if (*s == ',')
+ s++;
+ }
+ return 0;
+}
+
+void
+FreeTransTable()
+{
+ char ***p, **q;
+ int i, j;
+
+ if ((p = D_xtable) == 0)
+ return;
+ for (i = 0; i < 256; i++, p++)
+ {
+ if (*p == 0)
+ continue;
+ q = *p;
+ for (j = 0; j < 257; j++, q++)
+ if (*q)
+ free(*q);
+ free((char *)*p);
+ }
+ free((char *)D_xtable);
+}
+
+static int
+copyarg(pp, s)
+char **pp, *s;
+{
+ int l;
+ char *p;
+
+ for (l = 0, p = *pp; *p && *p != ','; p++)
+ {
+ if (QUOTES(p))
+ p++;
+ if (s)
+ *s++ = *p;
+ l++;
+ }
+ if (*p == ',')
+ p++;
+ *pp = p;
+ return l;
+}
+
+
+/*
+**
+** Termcap routines that use our extra_incap
+**
+*/
+
+
+/* findcap:
+ * cap = capability we are looking for
+ * tepp = pointer to bufferpointer
+ * n = size of buffer (0 = infinity)
+ */
+
+static char *
+findcap(cap, tepp, n)
+char *cap;
+char **tepp;
+int n;
+{
+ char *tep;
+ char c, *p, *cp;
+ int mode; /* mode: 0=LIT 1=^ 2=\x 3,4,5=\nnn */
+ int num = 0, capl;
+
+ if (!extra_incap)
+ return 0;
+ tep = *tepp;
+ capl = strlen(cap);
+ cp = 0;
+ mode = 0;
+ for (p = extra_incap; *p; )
+ {
+ if (strncmp(p, cap, capl) == 0)
+ {
+ p += capl;
+ c = *p;
+ if (c && c != ':' && c != '@')
+ p++;
+ if (c == 0 || c == '@' || c == '=' || c == ':' || c == '#')
+ cp = tep;
+ }
+ while ((c = *p))
+ {
+ p++;
+ if (mode == 0)
+ {
+ if (c == ':')
+ break;
+ if (c == '^')
+ mode = 1;
+ if (c == '\\')
+ mode = 2;
+ }
+ else if (mode == 1)
+ {
+ mode = 0;
+ c = c & 0x1f;
+ }
+ else if (mode == 2)
+ {
+ mode = 0;
+ switch(c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ mode = 3;
+ num = 0;
+ break;
+ case 'E':
+ c = 27;
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ }
+ }
+ if (mode > 2)
+ {
+ num = num * 8 + (c - '0');
+ if (mode++ == 5 || (*p < '0' || *p > '9'))
+ {
+ c = num;
+ mode = 0;
+ }
+ }
+ if (mode)
+ continue;
+
+ if (cp && n != 1)
+ {
+ *cp++ = c;
+ n--;
+ }
+ }
+ if (cp)
+ {
+ *cp++ = 0;
+ *tepp = cp;
+ debug2("'%s' found in extra_incap -> %s\n", cap, tep);
+ return tep;
+ }
+ }
+ return 0;
+}
+
+static char *
+e_tgetstr(cap, tepp)
+char *cap;
+char **tepp;
+{
+ char *tep, *tgetstr();
+ if ((tep = findcap(cap, tepp, 0)))
+ return (*tep == '@') ? 0 : tep;
+ return tgetstr(cap, tepp);
+}
+
+static int
+e_tgetflag(cap)
+char *cap;
+{
+ char buf[2], *bufp;
+ char *tep;
+ bufp = buf;
+ if ((tep = findcap(cap, &bufp, 2)))
+ return (*tep == '@') ? 0 : 1;
+ return tgetflag(cap);
+}
+
+static int
+e_tgetnum(cap)
+char *cap;
+{
+ char buf[20], *bufp;
+ char *tep, c;
+ int res, base = 10;
+
+ bufp = buf;
+ if ((tep = findcap(cap, &bufp, 20)))
+ {
+ c = *tep;
+ if (c == '@')
+ return -1;
+ if (c == '0')
+ base = 8;
+ res = 0;
+ while ((c = *tep++) >= '0' && c <= '9')
+ res = res * base + (c - '0');
+ return res;
+ }
+ return tgetnum(cap);
+}
+
diff --git a/terminfo/8bits b/terminfo/8bits
new file mode 100644
index 0000000..b616622
--- /dev/null
+++ b/terminfo/8bits
@@ -0,0 +1,17 @@
+
+We test some umlauts and other characters coded in
+the ISO 8859-1 (Latin 1) standard:
+
+umlaut A Ä umlaut a ä
+umlaut O Ö umlaut o ö
+umlaut U Ü umlaut u ü
+sharp s ß paragraph §
+e + / é e + \ è
+e + ^ ê a + \ à
+u + \ ù degree °
+log. not ¬ + over - ±
+<< « >> »
+fraction 1/2 ½ fraction 1/4 ¼
+power of 2 ² middle dot ·
+
+---
diff --git a/terminfo/README b/terminfo/README
new file mode 100644
index 0000000..ccbf488
--- /dev/null
+++ b/terminfo/README
@@ -0,0 +1,19 @@
+
+This directory contains various file for termcap/terminfo installation
+and testing:
+
+screencap Termcap entry for screen. Add to /etc/termcap.
+
+screeninfo.src Terminfo entry. Use 'tic screeninfo.src'
+ to install (Sun: /usr/5bin/tic).
+
+checktc.c Termcap/info test program. Checks margin
+ handling and other things.
+
+8bits Some chars from the ISO 8859-1 charset.
+
+test.txt Test file for alternate charset.
+
+tetris.c The popular game, by John Tromp. This is one of
+ the winners of the 1989 IOCCC contest.
+
diff --git a/terminfo/checktc.c b/terminfo/checktc.c
new file mode 100644
index 0000000..ccc9485
--- /dev/null
+++ b/terminfo/checktc.c
@@ -0,0 +1,204 @@
+#include <stdio.h>
+
+char *CL, *CM, *CS, *SR;
+int CO, LI, AM, XN;
+
+char *tgetstr(), *getenv();
+void PutStr(), CPutStr(), CCPutStr(), GotoPos(), RETURN();
+
+main()
+{
+ char *term, *s;
+ char tcbuf[1024];
+ char tcstr[1024], *tp;
+
+ if ((term = getenv("TERM")) == 0)
+ {
+ fprintf(stderr, "No $TERM set\n");
+ exit(1);
+ }
+ switch (tgetent(tcbuf, term))
+ {
+ case -1:
+ fprintf(stderr, "Could not open termcap file\n");
+ exit(1);
+ case 0:
+ fprintf(stderr, "I don't know what a '%s' terminal is.\n", term);
+ exit(1);
+ }
+ tp = tcstr;
+ if ((CL = tgetstr("cl", &tp)) == 0)
+ {
+ fprintf(stderr, "cl capability required\n");
+ exit(1);
+ }
+ if ((CM = tgetstr("cm", &tp)) == 0)
+ {
+ fprintf(stderr, "cm capability required\n");
+ exit(1);
+ }
+
+ if ((s = getenv("COLUMNS")))
+ CO = atoi(s);
+ if ((s = getenv("LINES")))
+ LI = atoi(s);
+ if (CO == 0)
+ CO = tgetnum("co");
+ if (LI == 0)
+ LI = tgetnum("li");
+ if (CO == 0)
+ CO = 80;
+ if (LI == 0)
+ LI = 24;
+ GotoPos(5, 1);
+ printf("******* cl capability does not work !!! *******");
+ GotoPos(5, 2);
+ PutStr(CL);
+ printf("******* cl capability does not home cursor *******");
+ GotoPos(0, 0);
+ printf(" ");
+ GotoPos(5, 4);
+ printf("******* cm capability does not work !!! *******");
+ GotoPos(5, 4);
+ printf(" ");
+ GotoPos(CO/2-12, LI/2);
+ printf("Your terminal size is");
+ GotoPos(CO/2-3, LI/2+1);
+ printf("%dx%d", CO, LI);
+ GotoPos(CO/2-2, 0);
+ printf("top");
+ GotoPos(CO/2-3, LI-1);
+ printf("bottom");
+ GotoPos(0, LI/2-2);printf("l");
+ GotoPos(0, LI/2-1);printf("e");
+ GotoPos(0, LI/2+0);printf("f");
+ GotoPos(0, LI/2+1);printf("t");
+ GotoPos(CO-1, LI/2-2);printf("r");
+ GotoPos(CO-1, LI/2-1);printf("i");
+ GotoPos(CO-1, LI/2+0);printf("g");
+ GotoPos(CO-1, LI/2+1);printf("h");
+ GotoPos(CO-1, LI/2+2);printf("t");
+ GotoPos(CO/2-15, LI/2+3);
+ RETURN();
+ AM = tgetflag("am");
+ printf("Termcap: terminal does %sauto-wrap", AM ? "" : "not ");
+ GotoPos(0, 5);
+ if (AM)
+ {
+ printf(" am capability set, but terminal does not wrap");
+ GotoPos(CO-1, 3);
+ }
+ else
+ {
+ printf(" am capability not set, but terminal does wrap");
+ GotoPos(CO-1, 4);
+ }
+ printf(" \n ");
+ GotoPos(0, 10);
+ RETURN();
+ if (AM)
+ {
+ XN = tgetflag("xn");
+ printf("Termcap: terminal has %smagic margins", XN ? "" : "no ");
+ GotoPos(0, 5);
+ if ((XN = tgetflag("xn")))
+ {
+ printf(" xn capability set, but terminal has no magic-margins");
+ GotoPos(CO-1, 4);
+ }
+ else
+ {
+ printf(" xn capability not set, but terminal has magic-margins");
+ GotoPos(CO-1, 3);
+ }
+ printf(" \n");
+ printf(" ");
+ GotoPos(0, 10);
+ RETURN();
+ if (XN)
+ {
+ GotoPos(0, 6);
+ printf(" last col in last row is not usable");
+ GotoPos(CO-1, LI-1);
+ printf(" ");
+ GotoPos(0, 6);
+ printf(" ");
+ GotoPos(0, 0);
+ printf("testing magic margins in last row");
+ GotoPos(0, 10);
+ RETURN();
+ }
+ }
+ if ((CS = tgetstr("cs", &tp)))
+ {
+ printf("Termcap: terminal has scrollregions");
+ GotoPos(0, 5);
+ printf(" cs capability set, but doesn't work");
+ CCPutStr(CS, 4, 5);
+ GotoPos(0, 5);
+ printf("\n\n");
+ CCPutStr(CS, 0, LI-1);
+ GotoPos(0, 10);
+ RETURN();
+ }
+ if ((SR = tgetstr("sr", &tp)))
+ {
+ GotoPos(0, 5);
+ printf(" sr capability set, but doesn't work");
+ GotoPos(0, 0);
+ PutStr(SR);
+ GotoPos(0, 6);
+ printf(" ");
+ GotoPos(0, 0);
+ printf("Termcap: terminal can scroll backwards");
+ GotoPos(0, 10);
+ RETURN();
+ }
+}
+
+void
+putcha(c)
+char c;
+{
+ putchar(c);
+}
+
+void
+PutStr(s)
+char *s;
+{
+ tputs(s, 1, putcha);
+ fflush(stdout);
+}
+
+void CPutStr(s, c)
+char *s;
+int c;
+{
+ tputs(tgoto(s, 0, c), 1, putcha);
+ fflush(stdout);
+}
+
+void CCPutStr(s, x, y)
+char *s;
+int x, y;
+{
+ tputs(tgoto(s, y, x), 1, putcha);
+ fflush(stdout);
+}
+
+void GotoPos(x,y)
+int x,y;
+{
+ tputs(tgoto(CM, x, y), 1, putcha);
+ fflush(stdout);
+}
+
+void
+RETURN()
+{
+ printf("Press <RETURN> to continue");
+ fflush(stdout);
+ while(getchar() != '\n');
+ PutStr(CL);
+}
diff --git a/terminfo/sco.mail b/terminfo/sco.mail
new file mode 100644
index 0000000..bd95e4f
--- /dev/null
+++ b/terminfo/sco.mail
@@ -0,0 +1,65 @@
+From root%mjbtn.UUCP@uunet.UU.NET Tue Oct 22 03:09:14 1991
+Received: from relay2.UU.NET by immd4.informatik.uni-erlangen.de with SMTP (5.64+/7.3a-FAU)
+ id AA10018; Tue, 22 Oct 91 03:09:04 +0100
+Received: from uunet.uu.net (via LOCALHOST.UU.NET) by relay2.UU.NET with SMTP
+ (5.61/UUNET-internet-primary) id AA09640; Mon, 21 Oct 91 22:09:07 -0400
+Received: from mjbtn.UUCP by uunet.uu.net with UUCP/RMAIL
+ (queueing-rmail) id 220830.17203; Mon, 21 Oct 1991 22:08:30 EDT
+Received: by mjbtn.jobsoft.com (/\==/\ Smail3.1.21.1); Mon, 21 Oct 91 20:49 CDT
+Message-Id: <m0kZBFd-0007XHC@mjbtn.jobsoft.com>
+From: root@mjbtn.jobsoft.com (Mark J. Bailey [ADMIN])
+Subject: Re: oh yes
+To: jnweiger%immd4.informatik.uni-erlangen.de%uunet.UUCP@uunet.UU.NET (Juergen Weigert)
+Date: Mon, 21 Oct 91 20:49:49 CDT
+In-Reply-To: <9110212148.AA01737@faui43.informatik.uni-erlangen.de>; from "Juergen Weigert" at Oct 21, 91 10:48 pm
+X-Mailer: ELM [version 2.3 PL11]
+Status: OR
+
+Hi,
+
+Well, more playing and finally some progress! :-)
+
+This is my .screenrc:
+
+terminfo ansi G0:hs@:am:LP@:OP
+
+Now, I am not worried about its total accurracy, but I just wanted to show
+you what I tried. I also fixed a screen-25 terminfo entry:
+
+screen-25|VT 100/ANSI X3.64 virtual terminal,
+ am, msgr, xon,
+ cols#80, it#8, lines#25,
+ bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z,
+ clear=\E[H\E[J, cr=\r, csr=\E[%i%p1%d;%p2%dr,
+ cub=\E[%p1%dD, cub1=\b, cud=\E[%p1%dB, cud1=\n,
+ cuf=\E[%p1%dC, cuf1=\E[C, cup=\E[%i%p1%d;%p2%dH,
+ cuu=\E[%p1%dA, cuu1=\EM, dl=\E[%p1%dM, dl1=\E[M,
+ ed=\E[J, el=\E[K, home=\E[H, ht=\t, hts=\EH,
+ il=\E[%p1%dL, il1=\E[L, ind=\n, is2=\E)0, kbs=\b,
+ kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA,
+ kf1=\EOP, kf2=\EOQ, kf3=\EOR, kf4=\EOS, khome=\E?,
+ ll=\E[25H, nel=\EE, rc=\E8, rev=\E[7m, ri=\EM,
+ rmkx=\E>, rmso=\E[23m, rmul=\E[24m, rs2=\Ec, sc=\E7,
+ sgr0=\E[m, smkx=\E=, smso=\E[3m, smul=\E[4m,
+ tbc=\E[3g,
+
+And notice for SCO Unix that I added 'am' to the entry for screen-25. Even
+though the external (login shell) type 'ansi' was modified with the .screenrc,
+when I added 'am' to the screen window term screen-25, it functioned flawlessly
+and I am not sure why. Anyway, vi and all the others seem to work great
+now. Next, I need to work on the G0 -> C0 graphics character mappings. I
+don't fully understand that yet. Anyway, this should be of help to others
+under SCO. BTW, that copy of the message you got from me that I sent to
+Ronald Khoo -- I applied SCO SLS patch xnx141 (for xenix) to fix the bug
+in select() when dealing with pipes, and it solved my problems on xenix.
+
+Mark.
+
+--
+Mark J. Bailey, N4XHX _______/====X11====\_______
+USMAIL: 511 Memorial Blvd., Murfreesboro, TN 37129 | JobSoft |
+VOICE: +1 615 893 0098 | Design & Development Co.|
+UUCP: ...!uunet!mjbtn!mjb, ...!raider!mjbtn!mjb | Murfreesboro, TN USA |
+DOMAIN: mjb@mjbtn.JOBSOFT.COM CIS: 76314,160 ---------------------------
+<KA9Q-UNIX-USERS Mailing List-Subscribe: ka9q-unix-requests@mjbtn.jobsoft.com>
+
diff --git a/terminfo/screencap b/terminfo/screencap
new file mode 100644
index 0000000..5738532
--- /dev/null
+++ b/terminfo/screencap
@@ -0,0 +1,21 @@
+SC|screen|VT 100/ANSI X3.64 virtual terminal:\
+ :am:xn:ms:mi:G0:km:\
+ :DO=\E[%dB:LE=\E[%dD:RI=\E[%dC:UP=\E[%dA:bs:bt=\E[Z:\
+ :cb=\E[1K:cd=\E[J:ce=\E[K:cl=\E[H\E[J:cm=\E[%i%d;%dH:ct=\E[3g:\
+ :do=^J:nd=\E[C:pt:rc=\E8:rs=\Ec:sc=\E7:st=\EH:up=\EM:\
+ :le=^H:bl=^G:cr=^M:it#8:ho=\E[H:nw=\EE:ta=^I:is=\E)0:\
+ :li#24:co#80:us=\E[4m:ue=\E[24m:so=\E[3m:se=\E[23m:\
+ :mb=\E[5m:md=\E[1m:mr=\E[7m:me=\E[m:sr=\EM:al=\E[L:\
+ :AL=\E[%dL:dl=\E[M:DL=\E[%dM:cs=\E[%i%d;%dr:dc=\E[P:\
+ :DC=\E[%dP:im=\E[4h:ei=\E[4l:IC=\E[%d@:\
+ :ks=\E[?1h\E=:ke=\E[?1l\E>:vb=\Eg:\
+ :ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:kb=^H:\
+ :k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:k5=\E[15~:k6=\E[17~:\
+ :k7=\E[18~:k8=\E[19~:k9=\E[20~:k;=\E[21~:F1=\E[23~:F2=\E[24~:\
+ :kh=\E[1~:kI=\E[2~:kD=\E[3~:kH=\E[4~:kP=\E[5~:kN=\E[6~:\
+ :eA=\E(B\E)0:as=^N:ae=^O:\
+ :vi=\E[?25l:ve=\E[34h\E[?25h:vs=\E[34l:\
+ :Co#8:pa#64:AF=\E[3%dm:AB=\E[4%dm:op=\E[39;49m:AX:\
+ :ac=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~..--++,,hhII00:
+SW|screen-w|VT 100/ANSI X3.64 virtual terminal with 132 cols:\
+ :co#132:tc=screen:
diff --git a/terminfo/screeninfo.src b/terminfo/screeninfo.src
new file mode 100644
index 0000000..ab17d2d
--- /dev/null
+++ b/terminfo/screeninfo.src
@@ -0,0 +1,48 @@
+screen|VT 100/ANSI X3.64 virtual terminal,
+ am, km, mir, msgr, xenl,
+ cols#80, it#8, lines#24, colors#8, pairs#64,
+ bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z,
+ clear=\E[H\E[J, cr=\r, csr=\E[%i%p1%d;%p2%dr,
+ cub=\E[%p1%dD, cub1=\b, cud=\E[%p1%dB, cud1=\n,
+ cuf=\E[%p1%dC, cuf1=\E[C, cup=\E[%i%p1%d;%p2%dH,
+ cuu=\E[%p1%dA, cuu1=\EM, dch=\E[%p1%dP, dch1=\E[P,
+ dl=\E[%p1%dM, dl1=\E[M, ed=\E[J, el=\E[K, el1=\E[1K,
+ enacs=\E(B\E)0, home=\E[H,
+ ht=\t, hts=\EH, ich=\E[%p1%d@, il=\E[%p1%dL, il1=\E[L,
+ ind=\n, is2=\E)0, kbs=\b, kcub1=\EOD, kcud1=\EOB,
+ kcuf1=\EOC, kcuu1=\EOA, kdch1=\E[3~, kf1=\EOP,
+ kf10=\E[21~, kf11=\E[23~, kf12=\E[24~, kf2=\EOQ,
+ kf3=\EOR, kf4=\EOS, kf5=\E[15~, kf6=\E[17~,
+ kf7=\E[18~, kf8=\E[19~, kf9=\E[20~, khome=\E[1~,
+ kich1=\E[2~, kll=\E[4~, knp=\E[6~, kpp=\E[5~, nel=\EE,
+ rc=\E8, rev=\E[7m, ri=\EM, rmir=\E[4l, rmkx=\E[?1l\E>,
+ rmso=\E[23m, rmul=\E[24m, rs2=\Ec, sc=\E7, sgr0=\E[m,
+ smir=\E[4h, smkx=\E[?1h\E=, smso=\E[3m, smul=\E[4m,
+ tbc=\E[3g, smacs=^N, rmacs=^O, flash=\Eg,
+ civis=\E[?25l, cnorm=\E[34h\E[?25h, cvvis=\E[34l,
+ op=\E[39;49m, setab=\E[4%p1%dm, setaf=\E[3%p1%dm,
+ acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~..--++\054\054hhII00,
+screen-w|VT 100/ANSI X3.64 virtual terminal with 132 cols,
+ am, km, mir, msgr, xenl,
+ cols#132, it#8, lines#24, colors#8, pairs#64,
+ bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z,
+ clear=\E[H\E[J, cr=\r, csr=\E[%i%p1%d;%p2%dr,
+ cub=\E[%p1%dD, cub1=\b, cud=\E[%p1%dB, cud1=\n,
+ cuf=\E[%p1%dC, cuf1=\E[C, cup=\E[%i%p1%d;%p2%dH,
+ cuu=\E[%p1%dA, cuu1=\EM, dch=\E[%p1%dP, dch1=\E[P,
+ dl=\E[%p1%dM, dl1=\E[M, ed=\E[J, el=\E[K, el1=\E[1K,
+ enacs=\E(B\E)0, home=\E[H,
+ ht=\t, hts=\EH, ich=\E[%p1%d@, il=\E[%p1%dL, il1=\E[L,
+ ind=\n, is2=\E)0, kbs=\b, kcub1=\EOD, kcud1=\EOB,
+ kcuf1=\EOC, kcuu1=\EOA, kdch1=\E[3~, kf1=\EOP,
+ kf10=\E[21~, kf11=\E[23~, kf12=\E[24~, kf2=\EOQ,
+ kf3=\EOR, kf4=\EOS, kf5=\E[15~, kf6=\E[17~,
+ kf7=\E[18~, kf8=\E[19~, kf9=\E[20~, khome=\E[1~,
+ kich1=\E[2~, kll=\E[4~, knp=\E[6~, kpp=\E[5~, nel=\EE,
+ rc=\E8, rev=\E[7m, ri=\EM, rmir=\E[4l, rmkx=\E[?1l\E>,
+ rmso=\E[23m, rmul=\E[24m, rs2=\Ec, sc=\E7, sgr0=\E[m,
+ smir=\E[4h, smkx=\E[?1h\E=, smso=\E[3m, smul=\E[4m,
+ tbc=\E[3g, smacs=^N, rmacs=^O, flash=\Eg,
+ civis=\E[?25l, cnorm=\E[34h\E[?25h, cvvis=\E[34l,
+ op=\E[39;49m, setab=\E[4%p1%dm, setaf=\E[3%p1%dm,
+ acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~..--++\054\054hhII00,
diff --git a/terminfo/test.txt b/terminfo/test.txt
new file mode 100644
index 0000000..2da65e5
--- /dev/null
+++ b/terminfo/test.txt
@@ -0,0 +1,603 @@
+
+ <(A)0[?4h[?5l
+
+
+
+
+
+
+
+
+
+ lqqqqqqqqqwwwqqqqqqqqqk sssssssssssssssssssssssssssss
+ xMerry Chrxxxmas * Merx \ /
+ xry Christxxx * Merry x pr rp
+ xChristmasxxxMerry Chrx oqrs srqo
+ xistmas * xxxry Christx ooppqqwqwqqppoo
+ tqqqqqqqqqjxmqqqqqqqqqu x x
+ tqqqqqqqqqq`qqqqqqqqqqu x x
+ tqqqqqqqqqkxlqqqqqqqqqu x x
+ xry Christxxx * Merry x x x
+ xChristmasxxxMerry Chrx x x
+ xistmas * xxxry Christx x x
+ xmas * MerxxxChristmasx srqqj mqqrs
+ mqqqqqqqqqvvvqqqqqqqqqj  rqpo opqr 
+lmxx
+lqmqx x
+lqwmqvx xx x
+lqwqmqvqx x x x
+lqwqmqvqx x x x
+lqwqmqvqx x x x
+lqwqmqvqx x x x
+lqwqmqvqx x x x
+lqwqmqvqx x x x
+lqwqmqvqx x x x
+//
+//
+//  / /
+//  / ///
+//  ////
+//  //// //
+/  //// / /
+ // / //
+// / // /
+//s/ // 
+sssssssssss
+/ / //  // /
+ss
+ / //  //  //
+rrrrrrrrrrr
+/ /s //  //
+qqqqqqqqq
+//  //  //
+srqqqqqqqqqrs
+  //  ///
+srrs
+//  //// //
+rrqqqqrr
+/  //// / /
+ppppppp
+ // / //
+rrqqrr
+// / // /
+rqppppqr
+//s/ // 
+
+rqpppooooooopppqr
+/ / //  // /
+qppoooooooooooppq
+ / //  //  //
+
+
+
+sssssssooo ooo. o f
+
+/ /s //  //.f
+
+ssss .f
+
+//  //  // f
+
+ssssrrrrqqqqqrrrrsssss s
+
+  //  ///. . .
+
+sssrrrrqqqqqqqqqrrrrsssf f . f
+
+//  //// / f .
+
+rrrqqqqpppppppppqqqqrss. . o f
+
+/  //// / /f .f
+
+qqqppppooooooooopppqrss .f .
+
+s// / // f f
+
+sssssssssqppoooo oopqrss.o .
+
+// / // /f f. .
+
+ssrrrrrrrrrsqpooo opqrssf f f . f
+
+//s/ // f o o f .
+
+ssssssrrrrssssss   f o o .. . o f
+
+s/ //  /  . o o ff .f
+
+srrrrrrqqqqqqqqqqqqqqrrssrqf o o .  .f .
+
+/ //  / mqvqqqqqq lqwqqqqqq x x x x . o f
+
+rqqqqqqppppppppppppppq mqvqqqqq lqwqqqqq x x x xf .o . o
+
+/s /  mqvqqqq lqwqqqq x x x x f f [14;51
+
+qppppppoooooooooooooo mqvqqq lqwqqq x x x xf  .f f . f
+
+s /  mqvqq lqwqq x x x x. o f o o f f
+
+poooooo  mqvq lqwq x x x x o o of o o .
+
+rrrrrrrrrrrrrrrrrrrrrrrrrrrrr   mqv lqw x x x xo
+ mq lq x  x  . o o of o o .  .f .
+ m l x x. o o f o . . . o ff f
+    f o o f . ff .o . o
+#3 Cheers!
+#4 Cheers! 
+
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+
+ . o o . o f  f f . . .
+#5
+#5
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ /ooooooooooooooo\
+ o o of o o .. . o f
+ / sss sss \
+o o o . o o ff .f
+ x (sOs) (sOs) x
+ . o o of o o .  .f .
+ x ` x
+. o o f o . . . o ff f
+ \ \sssssssss/ /
+f o o f . ff .o . o
+ \ /
+ . o o . o f  f f . . .
+ \sssssssssss/
+f . o . f o ff  .f f . f
+ ooppqqrrsss
+ f f f . o f o o f f .
+ ooppqqrrsss
+ o o of o o .. . o f
+ ooppqqrrsss
+o o o . o o ff .f
+ ooppqqrrsss
+ . o o of o o .  .f .
+ ooppqqrrsss
+. o o f o . . . o ff f
+ ooppqqrrsss
+f o o f . ff .o . o
+ ooppqqrrsss . o o . o f  f f . . .
+M x ` x
+f . o . f o ff  .f f . f
+M x (sOs) (sOs) x
+ f f f . o f o o f f .
+M / sss sss \
+ o o of o o .. . o f
+M /ooooooooooooooo\
+o o o . o o ff .f
+M
+ . o o of o o .  .f .
+M
+. o o f o . . . o ff f
+M
+f o o f . ff .o . o
+M
+ . o o . o f  f f . . .
+ \ /
+f . o . f o ff  .f f . f
+ \sssssssssss/
+ f f f . o f o o f f .
+ ooppqqrrsss
+ o o of o o .. . o f
+ ooppqqrrsss
+o o o . o o ff .f
+ ooppqqrrsss
+ . o o of o o .  .f .
+ ooppqqrrsss
+. o o f o . . . o ff f
+ ooppqqrrsssf o o f . ff .o . o
+M / sss sss \
+ . o o . o f  f f . . .
+M /ooooooooooooooo\
+f . o . f o ff  .f f . f
+M
+ f f f . o f o o f f .
+M
+ o o of o o .. . o f
+ ooppqqrrsss
+o o o . o o ff .f
+ ooppqqrrsss
+ . o o of o o .  .f .
+ ooppqqrrsss
+. o o f o . . . o ff f
+ ooppqqrrsssf o o f . ff .o . o
+M /ooooooooooooooo\
+ . o o . o f  f f . . .
+M
+f . o . f o ff  .f f . f
+M
+ f f f . o f o o f f .
+M
+ o o of o o .. . o f
+ \sssssssssss/
+o o o . o o ff .f
+ ooppqqrrsss
+ . o o of o o .  .f .
+ ooppqqrrsss
+. o o f o . . . o ff f
+f o o f . ff .o . o
+
+Jin
+ . o o . o f  f f . . .
+gle
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+Bells,
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+Jin
+ . o o of o o .  .f .
+gle
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+Bells,
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+Jin
+ f f f . o f o o f f .
+gle
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+all
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+the
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+way,
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+Oh!
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+What
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+fun
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+it
+ o o of o o .. . o f
+is
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+to
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+ride,
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+On
+o o o . o o ff .f
+a
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+one-
+f . o . f o ff  .f f . f
+horse
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+op
+ f f f . o f o o f f .
+en
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+sleigh.
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff f
+
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff f
+
+ o o of o o 
+. o o o  
+f o o   
+
+o o o . o o ff f
+
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff f
+
+ o o of o o 
+. o o o  
+f o o   
+
+
+Merry Christmas
+
+-
+
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff f
+
+ o o of o o 
+. o o o  
+f o o   
+
+o o o . o o ff f
+
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff .f
+ . o o of o o .  .f .
+. o o f o . . . o ff f
+f o o f . ff .o . o
+ . o o . o f  f f . . .
+f . o . f o ff  .f f . f
+ f f f . o f o o f f .
+ o o of o o .. . o f
+o o o . o o ff f
+
+ o o of o o 
+. o o o  
+f o o   
+
+[?4l
+
diff --git a/terminfo/tetris.c b/terminfo/tetris.c
new file mode 100644
index 0000000..e230373
--- /dev/null
+++ b/terminfo/tetris.c
@@ -0,0 +1,20 @@
+long h[4];t(){h[3]-=h[3]/3000;setitimer(0,h,0);}c,d,l,v[]={(int)t,0,2},w,s,I,K
+=0,i=276,j,k,q[276],Q[276],*n=q,*m,x=17,f[]={7,-13,-12,1,8,-11,-12,-1,9,-1,1,
+12,3,-13,-12,-1,12,-1,11,1,15,-1,13,1,18,-1,1,2,0,-12,-1,11,1,-12,1,13,10,-12,
+1,12,11,-12,-1,1,2,-12,-1,12,13,-12,12,13,14,-11,-1,1,4,-13,-12,12,16,-11,-12,
+12,17,-13,1,-1,5,-12,12,11,6,-12,12,24};u(){for(i=11;++i<264;)if((k=q[i])-Q[i]
+){Q[i]=k;if(i-++I||i%12<1)printf("\033[%d;%dH",(I=i)/12,i%12*2+28);printf(
+"\033[%dm "+(K-k?0:5),k);K=k;}Q[263]=c=getchar();}G(b){for(i=4;i--;)if(q[i?b+
+n[i]:b])return 0;return 1;}g(b){for(i=4;i--;q[i?x+n[i]:x]=b);}main(C,V,a)char*
+*V,*a;{h[3]=1000000/(l=C>1?atoi(V[1]):2);for(a=C>2?V[2]:"jkl pq";i;i--)*n++=i<
+25||i%12<2?7:0;srand(getpid());system("stty cbreak -echo stop u");sigvec(14,v,
+0);t();puts("\033[H\033[J");for(n=f+rand()%7*4;;g(7),u(),g(0)){if(c<0){if(G(x+
+12))x+=12;else{g(7);++w;for(j=0;j<252;j=12*(j/12+1))for(;q[++j];)if(j%12==10){
+for(;j%12;q[j--]=0);u();for(;--j;q[j+12]=q[j]);u();}n=f+rand()%7*4;G(x=17)||(c
+=a[5]);}}if(c==*a)G(--x)||++x;if(c==a[1])n=f+4**(m=n),G(x)||(n=m);if(c==a[2])G
+(++x)||--x;if(c==a[3])for(;G(x+12);++w)x+=12;if(c==a[4]||c==a[5]){s=sigblock(
+8192);printf("\033[H\033[J\033[0m%d\n",w);if(c==a[5])break;for(j=264;j--;Q[j]=
+0);while(getchar()-a[4]);puts("\033[H\033[J\033[7m");sigsetmask(s);}}d=popen(
+"stty -cbreak echo stop \023;sort -mnr -o HI - HI;cat HI","w");fprintf(d,
+"%4d from level %1d by %s\n",w,l,getlogin());pclose(d);}
+
diff --git a/tty.c.dist b/tty.c.dist
new file mode 100644
index 0000000..d9eba86
--- /dev/null
+++ b/tty.c.dist
@@ -0,0 +1,1025 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+/*
+ * NOTICE: tty.c is automatically generated from tty.sh
+ * Do not change anything here. If you then change tty.sh.
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: tty.sh,v 1.13 1994/05/31 12:33:17 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+#include <signal.h>
+#include <fcntl.h>
+#ifndef sgi
+# include <sys/file.h>
+#endif
+#if !defined(sun) || defined(SUNOS3)
+# include <sys/ioctl.h> /* collosions with termios.h */
+#else
+# ifndef TIOCEXCL
+# include <sys/ttold.h> /* needed for TIOCEXCL */
+# endif
+#endif
+
+#ifdef ISC
+# include <sys/tty.h>
+# include <sys/sioctl.h>
+# include <sys/pty.h>
+#endif
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+
+extern struct display *display, *displays;
+extern int iflag;
+
+/* Frank Schulz (fschulz@pyramid.com):
+ * I have no idea why VSTART is not defined and my fix is probably not
+ * the cleanest, but it works.
+ */
+#if !defined(VSTART) && defined(_VSTART)
+#define VSTART _VSTART
+#endif
+#if !defined(VSTOP) && defined(_VSTOP)
+#define VSTOP _VSTOP
+#endif
+
+static sigret_t
+SigAlrmDummy SIGDEFARG
+{
+ debug("SigAlrmDummy()\n");
+ SIGRETURN;
+}
+
+/*
+ * Carefully open a charcter device. Not used to open ttys.
+ */
+
+int
+OpenTTY(line)
+char *line;
+{
+ int f;
+ sigret_t (*sigalrm)__P(SIGPROTOARG);
+
+ sigalrm = signal(SIGALRM, SigAlrmDummy);
+ alarm(2);
+ /* this open only succeeds, if real uid is allowed */
+ if ((f = secopen(line, O_RDWR | O_NONBLOCK, 0)) == -1)
+ {
+ Msg(errno, "Cannot open line '%s' for R/W", line);
+ alarm(0);
+ signal(SIGALRM, sigalrm);
+ return -1;
+ }
+#ifdef I_POP
+ debug("OpenTTY I_POP\n");
+ while (ioctl(f, I_POP, (char *)0) >= 0)
+ ;
+#endif
+ /*
+ * We come here exclusively. This is to stop all kermit and cu type things
+ * accessing the same tty line.
+ * Perhaps we should better create a lock in some /usr/spool/locks directory?
+ */
+#ifdef TIOCEXCL
+ errno = 0;
+ ioctl(f, TIOCEXCL, (char *) 0);
+ debug3("%d %d %d\n", getuid(), geteuid(), getpid());
+ debug2("%s TIOCEXCL errno %d\n", line, errno);
+#endif /* TIOCEXCL */
+ /*
+ * We create a sane tty mode. We do not copy things from the display tty
+ */
+#if WE_REALLY_WANT_TO_COPY_THE_TTY_MODE
+ if (display)
+ {
+ debug1("OpenTTY: using mode of display for %s\n", line);
+ SetTTY(f, &D_NewMode);
+#ifdef DEBUG
+ DebugTTY(&D_NewMode);
+#endif
+ }
+ else
+#endif
+ {
+ struct mode Mode;
+
+ InitTTY(&Mode, TTY_FLAG_PLAIN);
+#ifdef DEBUG
+ DebugTTY(&Mode);
+#endif
+ SetTTY(f, &Mode);
+ }
+ brktty(f);
+ alarm(0);
+ signal(SIGALRM, sigalrm);
+ debug2("'%s' CONNECT fd=%d.\n", line, f);
+ return f;
+}
+
+
+/*
+ * Tty mode handling
+ */
+
+#if defined(TERMIO) || defined(POSIX)
+int intrc, origintrc = VDISABLE; /* display? */
+#else
+int intrc, origintrc = -1; /* display? */
+#endif
+static startc, stopc; /* display? */
+
+
+void
+InitTTY(m, ttyflag)
+struct mode *m;
+int ttyflag;
+{
+ bzero((char *)m, sizeof(*m));
+#ifdef POSIX
+ /* struct termios tio
+ * defaults, as seen on SunOS 4.1.3
+ */
+ debug1("InitTTY: POSIX: termios defaults a la SunOS 4.1.3 (%d)\n", ttyflag);
+#if defined(BRKINT)
+ m->tio.c_iflag |= BRKINT;
+#endif /* BRKINT */
+#if defined(IGNPAR)
+ m->tio.c_iflag |= IGNPAR;
+#endif /* IGNPAR */
+#if defined(ISTRIP)
+ m->tio.c_iflag |= ISTRIP;
+#endif /* ISTRIP */
+#if defined(IXON)
+ m->tio.c_iflag |= IXON;
+#endif /* IXON */
+#if defined(IMAXBEL)
+ m->tio.c_iflag |= IMAXBEL;
+#endif /* IMAXBEL */
+
+ if (!ttyflag) /* may not even be good for ptys.. */
+ {
+#if defined(ICRNL)
+ m->tio.c_iflag |= ICRNL;
+#endif /* ICRNL */
+#if defined(ONLCR)
+ m->tio.c_oflag |= ONLCR;
+#endif /* ONLCR */
+#if defined(TAB3)
+ m->tio.c_oflag |= TAB3;
+#endif /* TAB3 */
+#if defined(PARENB)
+ m->tio.c_cflag |= PARENB;
+#endif /* PARENB */
+ }
+
+#if defined(OPOST)
+ m->tio.c_oflag |= OPOST;
+#endif /* OPOST */
+
+#if defined(B9600)
+ m->tio.c_cflag |= B9600;
+#endif /* B9600 */
+#if defined(CS8)
+ m->tio.c_cflag |= CS8;
+#endif /* CS8 */
+#if defined(CREAD)
+ m->tio.c_cflag |= CREAD;
+#endif /* CREAD */
+#if defined(IBSHIFT) && defined(B9600)
+ m->tio.c_cflag |= B9600 << IBSHIFT;
+#endif /* IBSHIFT) && defined(B9600 */
+/* IF{CLOCAL} m->tio.c_cflag |= CLOCAL; */
+
+#if defined(ECHOCTL)
+ m->tio.c_lflag |= ECHOCTL;
+#endif /* ECHOCTL */
+#if defined(ECHOKE)
+ m->tio.c_lflag |= ECHOKE;
+#endif /* ECHOKE */
+
+ if (!ttyflag)
+ {
+#if defined(ISIG)
+ m->tio.c_lflag |= ISIG;
+#endif /* ISIG */
+#if defined(ICANON)
+ m->tio.c_lflag |= ICANON;
+#endif /* ICANON */
+#if defined(ECHO)
+ m->tio.c_lflag |= ECHO;
+#endif /* ECHO */
+ }
+#if defined(ECHOE)
+ m->tio.c_lflag |= ECHOE;
+#endif /* ECHOE */
+#if defined(ECHOK)
+ m->tio.c_lflag |= ECHOK;
+#endif /* ECHOK */
+#if defined(IEXTEN)
+ m->tio.c_lflag |= IEXTEN;
+#endif /* IEXTEN */
+
+#if defined(VINTR) && VINTR < MAXCC
+ m->tio.c_cc[VINTR] = Ctrl('C');
+#endif /* VINTR */
+#if defined(VQUIT) && VQUIT < MAXCC
+ m->tio.c_cc[VQUIT] = Ctrl('\\');
+#endif /* VQUIT */
+#if defined(VERASE) && VERASE < MAXCC
+ m->tio.c_cc[VERASE] = 0x7f; /* DEL */
+#endif /* VERASE */
+#if defined(VKILL) && VKILL < MAXCC
+ m->tio.c_cc[VKILL] = Ctrl('H');
+#endif /* VKILL */
+#if defined(VEOF) && VEOF < MAXCC
+ m->tio.c_cc[VEOF] = Ctrl('D');
+#endif /* VEOF */
+#if defined(VEOL) && VEOL < MAXCC
+ m->tio.c_cc[VEOL] = 0000;
+#endif /* VEOL */
+#if defined(VEOL2) && VEOL2 < MAXCC
+ m->tio.c_cc[VEOL2] = 0000;
+#endif /* VEOL2 */
+#if defined(VSWTCH) && VSWTCH < MAXCC
+ m->tio.c_cc[VSWTCH] = 0000;
+#endif /* VSWTCH */
+#if defined(VSTART) && VSTART < MAXCC
+ m->tio.c_cc[VSTART] = Ctrl('Q');
+#endif /* VSTART */
+#if defined(VSTOP) && VSTOP < MAXCC
+ m->tio.c_cc[VSTOP] = Ctrl('S');
+#endif /* VSTOP */
+#if defined(VSUSP) && VSUSP < MAXCC
+ m->tio.c_cc[VSUSP] = Ctrl('Z');
+#endif /* VSUSP */
+#if defined(VDSUSP) && VDSUSP < MAXCC
+ m->tio.c_cc[VDSUSP] = Ctrl('Y');
+#endif /* VDSUSP */
+#if defined(VREPRINT) && VREPRINT < MAXCC
+ m->tio.c_cc[VREPRINT] = Ctrl('R');
+#endif /* VREPRINT */
+#if defined(VDISCARD) && VDISCARD < MAXCC
+ m->tio.c_cc[VDISCARD] = Ctrl('O');
+#endif /* VDISCARD */
+#if defined(VWERASE) && VWERASE < MAXCC
+ m->tio.c_cc[VWERASE] = Ctrl('W');
+#endif /* VWERASE */
+#if defined(VLNEXT) && VLNEXT < MAXCC
+ m->tio.c_cc[VLNEXT] = Ctrl('V');
+#endif /* VLNEXT */
+#if defined(VSTATUS) && VSTATUS < MAXCC
+ m->tio.c_cc[VSTATUS] = Ctrl('T');
+#endif /* VSTATUS */
+
+ if (ttyflag)
+ {
+ m->tio.c_cc[VMIN] = 1;
+ m->tio.c_cc[VTIME] = 0;
+ }
+# ifdef hpux
+ m->m_ltchars.t_suspc = Ctrl('Z');
+ m->m_ltchars.t_dsuspc = Ctrl('Y');
+ m->m_ltchars.t_rprntc = Ctrl('R');
+ m->m_ltchars.t_flushc = Ctrl('O');
+ m->m_ltchars.t_werasc = Ctrl('W');
+ m->m_ltchars.t_lnextc = Ctrl('V');
+# endif /* hpux */
+
+#else /* POSIX */
+
+# ifdef TERMIO
+ debug1("InitTTY: nonPOSIX, struct termio a la Motorola SYSV68 (%d)\n", ttyflag);
+ /* struct termio tio
+ * defaults, as seen on Mototola SYSV68:
+ * input: 7bit, CR->NL, ^S/^Q flow control
+ * output: POSTprocessing: NL->NL-CR, Tabs to spaces
+ * control: 9600baud, 8bit CSIZE, enable input
+ * local: enable signals, erase/kill processing, echo on.
+ */
+#if defined(ISTRIP)
+ m->tio.c_iflag |= ISTRIP;
+#endif /* ISTRIP */
+#if defined(IXON)
+ m->tio.c_iflag |= IXON;
+#endif /* IXON */
+
+#if defined(OPOST)
+ m->tio.c_oflag |= OPOST;
+#endif /* OPOST */
+
+ if (!ttyflag) /* may not even be good for ptys.. */
+ {
+#if defined(ICRNL)
+ m->tio.c_iflag |= ICRNL;
+#endif /* ICRNL */
+#if defined(ONLCR)
+ m->tio.c_oflag |= ONLCR;
+#endif /* ONLCR */
+#if defined(TAB3)
+ m->tio.c_oflag |= TAB3;
+#endif /* TAB3 */
+ }
+
+#if defined(B9600)
+ m->tio.c_cflag = B9600;
+#endif /* B9600 */
+#if defined(CS8)
+ m->tio.c_cflag |= CS8;
+#endif /* CS8 */
+#if defined(CREAD)
+ m->tio.c_cflag |= CREAD;
+#endif /* CREAD */
+
+ if (!ttyflag)
+ {
+#if defined(ISIG)
+ m->tio.c_lflag |= ISIG;
+#endif /* ISIG */
+#if defined(ICANON)
+ m->tio.c_lflag |= ICANON;
+#endif /* ICANON */
+#if defined(ECHO)
+ m->tio.c_lflag |= ECHO;
+#endif /* ECHO */
+ }
+#if defined(ECHOE)
+ m->tio.c_lflag |= ECHOE;
+#endif /* ECHOE */
+#if defined(ECHOK)
+ m->tio.c_lflag |= ECHOK;
+#endif /* ECHOK */
+
+#if defined(VINTR) && VINTR < MAXCC
+ m->tio.c_cc[VINTR] = Ctrl('C');
+#endif /* VINTR */
+#if defined(VQUIT) && VQUIT < MAXCC
+ m->tio.c_cc[VQUIT] = Ctrl('\\');
+#endif /* VQUIT */
+#if defined(VERASE) && VERASE < MAXCC
+ m->tio.c_cc[VERASE] = 0177; /* DEL */
+#endif /* VERASE */
+#if defined(VKILL) && VKILL < MAXCC
+ m->tio.c_cc[VKILL] = Ctrl('H');
+#endif /* VKILL */
+#if defined(VEOF) && VEOF < MAXCC
+ m->tio.c_cc[VEOF] = Ctrl('D');
+#endif /* VEOF */
+#if defined(VEOL) && VEOL < MAXCC
+ m->tio.c_cc[VEOL] = 0377;
+#endif /* VEOL */
+#if defined(VEOL2) && VEOL2 < MAXCC
+ m->tio.c_cc[VEOL2] = 0377;
+#endif /* VEOL2 */
+#if defined(VSWTCH) && VSWTCH < MAXCC
+ m->tio.c_cc[VSWTCH] = 0000;
+#endif /* VSWTCH */
+ if (ttyflag)
+ {
+ m->tio.c_cc[VMIN] = 1;
+ m->tio.c_cc[VTIME] = 0;
+ }
+# else /* TERMIO */
+ debug1("InitTTY: BSD: defaults a la SunOS 4.1.3 (%d)\n", ttyflag);
+ m->m_ttyb.sg_ispeed = B9600;
+ m->m_ttyb.sg_ospeed = B9600;
+ m->m_ttyb.sg_erase = 0177; /*DEL */
+ m->m_ttyb.sg_kill = Ctrl('H');
+ if (!ttyflag)
+ m->m_ttyb.sg_flags = CRMOD | ECHO
+#if defined(ANYP)
+ | ANYP
+#endif /* ANYP */
+ ;
+ else
+ m->m_ttyb.sg_flags = CBREAK
+#if defined(ANYP)
+ | ANYP
+#endif /* ANYP */
+ ;
+
+ m->m_tchars.t_intrc = Ctrl('C');
+ m->m_tchars.t_quitc = Ctrl('\\');
+ m->m_tchars.t_startc = Ctrl('Q');
+ m->m_tchars.t_stopc = Ctrl('S');
+ m->m_tchars.t_eofc = Ctrl('D');
+ m->m_tchars.t_brkc = -1;
+
+ m->m_ltchars.t_suspc = Ctrl('Z');
+ m->m_ltchars.t_dsuspc = Ctrl('Y');
+ m->m_ltchars.t_rprntc = Ctrl('R');
+ m->m_ltchars.t_flushc = Ctrl('O');
+ m->m_ltchars.t_werasc = Ctrl('W');
+ m->m_ltchars.t_lnextc = Ctrl('V');
+
+#if defined(NTTYDISC)
+ m->m_ldisc = NTTYDISC;
+#endif /* NTTYDISC */
+
+ m->m_lmode = 0
+#if defined(LDECCTQ)
+ | LDECCTQ
+#endif /* LDECCTQ */
+#if defined(LCTLECH)
+ | LCTLECH
+#endif /* LCTLECH */
+#if defined(LPASS8)
+ | LPASS8
+#endif /* LPASS8 */
+#if defined(LCRTKIL)
+ | LCRTKIL
+#endif /* LCRTKIL */
+#if defined(LCRTERA)
+ | LCRTERA
+#endif /* LCRTERA */
+#if defined(LCRTBS)
+ | LCRTBS
+#endif /* LCRTBS */
+;
+# endif /* TERMIO */
+#endif /* POSIX */
+
+#if defined(KANJI) && defined(TIOCKSET) && defined(KM_ASCII) && defined(KM_SYSSJIS)
+ m->m_jtchars.t_ascii = 'J';
+ m->m_jtchars.t_kanji = 'B';
+ m->m_knjmode = KM_ASCII | KM_SYSSJIS;
+#endif
+}
+
+void
+SetTTY(fd, mp)
+int fd;
+struct mode *mp;
+{
+ errno = 0;
+#ifdef POSIX
+ tcsetattr(fd, TCSADRAIN, &mp->tio);
+# ifdef hpux
+ ioctl(fd, TIOCSLTC, (char *)&mp->m_ltchars);
+# endif
+#else
+# ifdef TERMIO
+ ioctl(fd, TCSETAW, (char *)&mp->tio);
+# ifdef CYTERMIO
+ if (mp->tio.c_line == 3)
+ {
+ ioctl(fd, LDSETMAPKEY, (char *)&mp->m_mapkey);
+ ioctl(fd, LDSETMAPSCREEN, (char *)&mp->m_mapscreen);
+ ioctl(fd, LDSETBACKSPACE, (char *)&mp->m_backspace);
+ }
+# endif
+# else
+ /* ioctl(fd, TIOCSETP, (char *)&mp->m_ttyb); */
+ ioctl(fd, TIOCSETC, (char *)&mp->m_tchars);
+ ioctl(fd, TIOCLSET, (char *)&mp->m_lmode);
+ ioctl(fd, TIOCSETD, (char *)&mp->m_ldisc);
+ ioctl(fd, TIOCSETP, (char *)&mp->m_ttyb);
+ ioctl(fd, TIOCSLTC, (char *)&mp->m_ltchars); /* moved here for apollo. jw */
+# endif
+#endif
+#if defined(KANJI) && defined(TIOCKSET) && defined(KM_ASCII) && defined(KM_SYSSJIS)
+ ioctl(fd, TIOCKSETC, &mp->m_jtchars);
+ ioctl(fd, TIOCKSET, &mp->m_knjmode);
+#endif
+ if (errno)
+ Msg(errno, "SetTTY (fd %d): ioctl failed", fd);
+}
+
+void
+GetTTY(fd, mp)
+int fd;
+struct mode *mp;
+{
+ errno = 0;
+#ifdef POSIX
+ tcgetattr(fd, &mp->tio);
+# ifdef hpux
+ ioctl(fd, TIOCGLTC, (char *)&mp->m_ltchars);
+# endif
+#else
+# ifdef TERMIO
+ ioctl(fd, TCGETA, (char *)&mp->tio);
+# ifdef CYTERMIO
+ if (mp->tio.c_line == 3)
+ {
+ ioctl(fd, LDGETMAPKEY, (char *)&mp->m_mapkey);
+ ioctl(fd, LDGETMAPSCREEN, (char *)&mp->m_mapscreen);
+ ioctl(fd, LDGETBACKSPACE, (char *)&mp->m_backspace);
+ }
+ else
+ {
+ mp->m_mapkey = NOMAPKEY;
+ mp->m_mapscreen = NOMAPSCREEN;
+ mp->m_backspace = '\b';
+ }
+# endif
+# else
+ ioctl(fd, TIOCGETP, (char *)&mp->m_ttyb);
+ ioctl(fd, TIOCGETC, (char *)&mp->m_tchars);
+ ioctl(fd, TIOCGLTC, (char *)&mp->m_ltchars);
+ ioctl(fd, TIOCLGET, (char *)&mp->m_lmode);
+ ioctl(fd, TIOCGETD, (char *)&mp->m_ldisc);
+# endif
+#endif
+#if defined(KANJI) && defined(TIOCKSET) && defined(KM_ASCII) && defined(KM_SYSSJIS)
+ ioctl(fd, TIOCKGETC, &mp->m_jtchars);
+ ioctl(fd, TIOCKGET, &mp->m_knjmode);
+#endif
+ if (errno)
+ Msg(errno, "GetTTY (fd %d): ioctl failed", fd);
+}
+
+void
+SetMode(op, np)
+struct mode *op, *np;
+{
+ *np = *op;
+
+#if defined(TERMIO) || defined(POSIX)
+# ifdef CYTERMIO
+ np->m_mapkey = NOMAPKEY;
+ np->m_mapscreen = NOMAPSCREEN;
+ np->tio.c_line = 0;
+# endif
+#if defined(ICRNL)
+ np->tio.c_iflag &= ~ICRNL;
+#endif /* ICRNL */
+#if defined(ONLCR)
+ np->tio.c_oflag &= ~ONLCR;
+#endif /* ONLCR */
+ np->tio.c_lflag &= ~(ICANON | ECHO);
+ /*
+ * From Andrew Myers (andru@tonic.lcs.mit.edu)
+ */
+#if defined(IEXTEN)
+ np->tio.c_lflag &= ~IEXTEN;
+#endif /* IEXTEN */
+
+ /*
+ * Unfortunately, the master process never will get SIGINT if the real
+ * terminal is different from the one on which it was originaly started
+ * (process group membership has not been restored or the new tty could not
+ * be made controlling again). In my solution, it is the attacher who
+ * receives SIGINT (because it is always correctly associated with the real
+ * tty) and forwards it to the master [kill(MasterPid, SIGINT)].
+ * Marc Boucher (marc@CAM.ORG)
+ */
+ if (iflag)
+ np->tio.c_lflag |= ISIG;
+ else
+ np->tio.c_lflag &= ~ISIG;
+ /*
+ * careful, careful catche monkey..
+ * never set VMIN and VTIME to zero, if you want blocking io.
+ */
+ np->tio.c_cc[VMIN] = 1;
+ np->tio.c_cc[VTIME] = 0;
+#if defined(VSTART) && VSTART < MAXCC
+ startc = op->tio.c_cc[VSTART];
+#endif /* VSTART */
+#if defined(VSTOP) && VSTOP < MAXCC
+ stopc = op->tio.c_cc[VSTOP];
+#endif /* VSTOP */
+ if (iflag)
+ origintrc = intrc = op->tio.c_cc[VINTR];
+ else
+ {
+ origintrc = op->tio.c_cc[VINTR];
+ intrc = np->tio.c_cc[VINTR] = VDISABLE;
+ }
+ np->tio.c_cc[VQUIT] = VDISABLE;
+ if (D_flow == 0)
+ {
+ np->tio.c_cc[VINTR] = VDISABLE;
+#if defined(VSTART) && VSTART < MAXCC
+ np->tio.c_cc[VSTART] = VDISABLE;
+#endif /* VSTART */
+#if defined(VSTOP) && VSTOP < MAXCC
+ np->tio.c_cc[VSTOP] = VDISABLE;
+#endif /* VSTOP */
+ np->tio.c_iflag &= ~IXON;
+ }
+#if defined(VDISCARD) && VDISCARD < MAXCC
+ np->tio.c_cc[VDISCARD] = VDISABLE;
+#endif /* VDISCARD */
+#if defined(VLNEXT) && VLNEXT < MAXCC
+ np->tio.c_cc[VLNEXT] = VDISABLE;
+#endif /* VLNEXT */
+#if defined(VSTATUS) && VSTATUS < MAXCC
+ np->tio.c_cc[VSTATUS] = VDISABLE;
+#endif /* VSTATUS */
+#if defined(VSUSP) && VSUSP < MAXCC
+ np->tio.c_cc[VSUSP] = VDISABLE;
+#endif /* VSUSP */
+#if defined(VERASE) && VERASE < MAXCC
+ np->tio.c_cc[VERASE] = VDISABLE;
+#endif /* VERASE */
+#if defined(VKILL) && VKILL < MAXCC
+ np->tio.c_cc[VKILL] = VDISABLE;
+#endif /* VKILL */
+# ifdef hpux
+ np->m_ltchars.t_suspc = VDISABLE;
+ np->m_ltchars.t_dsuspc = VDISABLE;
+ np->m_ltchars.t_rprntc = VDISABLE;
+ np->m_ltchars.t_flushc = VDISABLE;
+ np->m_ltchars.t_werasc = VDISABLE;
+ np->m_ltchars.t_lnextc = VDISABLE;
+# else /* hpux */
+#if defined(VDSUSP) && VDSUSP < MAXCC
+ np->tio.c_cc[VDSUSP] = VDISABLE;
+#endif /* VDSUSP */
+#if defined(VREPRINT) && VREPRINT < MAXCC
+ np->tio.c_cc[VREPRINT] = VDISABLE;
+#endif /* VREPRINT */
+#if defined(VWERASE) && VWERASE < MAXCC
+ np->tio.c_cc[VWERASE] = VDISABLE;
+#endif /* VWERASE */
+# endif /* hpux */
+#else /* TERMIO || POSIX */
+ startc = op->m_tchars.t_startc;
+ stopc = op->m_tchars.t_stopc;
+ if (iflag)
+ origintrc = intrc = op->m_tchars.t_intrc;
+ else
+ {
+ origintrc = op->m_tchars.t_intrc;
+ intrc = np->m_tchars.t_intrc = -1;
+ }
+ np->m_ttyb.sg_flags &= ~(CRMOD | ECHO);
+ np->m_ttyb.sg_flags |= CBREAK;
+# if defined(CYRILL) && defined(CSTYLE) && defined(CS_8BITS)
+ np->m_ttyb.sg_flags &= ~CSTYLE;
+ np->m_ttyb.sg_flags |= CS_8BITS;
+# endif
+ np->m_tchars.t_quitc = -1;
+ if (D_flow == 0)
+ {
+ np->m_tchars.t_intrc = -1;
+ np->m_tchars.t_startc = -1;
+ np->m_tchars.t_stopc = -1;
+ }
+ np->m_ltchars.t_suspc = -1;
+ np->m_ltchars.t_dsuspc = -1;
+ np->m_ltchars.t_flushc = -1;
+ np->m_ltchars.t_lnextc = -1;
+#endif /* defined(TERMIO) || defined(POSIX) */
+}
+
+void
+SetFlow(on)
+int on;
+{
+ ASSERT(display);
+ if (D_flow == on)
+ return;
+#if defined(TERMIO) || defined(POSIX)
+ if (on)
+ {
+ D_NewMode.tio.c_cc[VINTR] = intrc;
+#if defined(VSTART) && VSTART < MAXCC
+ D_NewMode.tio.c_cc[VSTART] = startc;
+#endif /* VSTART */
+#if defined(VSTOP) && VSTOP < MAXCC
+ D_NewMode.tio.c_cc[VSTOP] = stopc;
+#endif /* VSTOP */
+ D_NewMode.tio.c_iflag |= IXON;
+ }
+ else
+ {
+ D_NewMode.tio.c_cc[VINTR] = VDISABLE;
+#if defined(VSTART) && VSTART < MAXCC
+ D_NewMode.tio.c_cc[VSTART] = VDISABLE;
+#endif /* VSTART */
+#if defined(VSTOP) && VSTOP < MAXCC
+ D_NewMode.tio.c_cc[VSTOP] = VDISABLE;
+#endif /* VSTOP */
+ D_NewMode.tio.c_iflag &= ~IXON;
+ }
+# ifdef POSIX
+ if (tcsetattr(D_userfd, TCSANOW, &D_NewMode.tio))
+# else
+ if (ioctl(D_userfd, TCSETAW, (char *)&D_NewMode.tio) != 0)
+# endif
+ debug1("SetFlow: ioctl errno %d\n", errno);
+#else /* POSIX || TERMIO */
+ if (on)
+ {
+ D_NewMode.m_tchars.t_intrc = intrc;
+ D_NewMode.m_tchars.t_startc = startc;
+ D_NewMode.m_tchars.t_stopc = stopc;
+ }
+ else
+ {
+ D_NewMode.m_tchars.t_intrc = -1;
+ D_NewMode.m_tchars.t_startc = -1;
+ D_NewMode.m_tchars.t_stopc = -1;
+ }
+ if (ioctl(D_userfd, TIOCSETC, (char *)&D_NewMode.m_tchars) != 0)
+ debug1("SetFlow: ioctl errno %d\n", errno);
+#endif /* POSIX || TERMIO */
+ D_flow = on;
+}
+
+
+/*
+ * Job control handling
+ *
+ * Somehow the ultrix session handling is broken, so use
+ * the bsdish variant.
+ */
+
+/*ARGSUSED*/
+void
+brktty(fd)
+int fd;
+{
+#if defined(POSIX) && !defined(ultrix)
+ setsid(); /* will break terminal affiliation */
+# if defined(BSD) && defined(TIOCSCTTY)
+ ioctl(fd, TIOCSCTTY, (char *)0);
+# endif /* BSD && TIOCSCTTY */
+#else /* POSIX */
+# ifdef SYSV
+ setpgrp(); /* will break terminal affiliation */
+# else /* SYSV */
+# ifdef BSDJOBS
+ int devtty;
+
+ if ((devtty = open("/dev/tty", O_RDWR | O_NONBLOCK)) >= 0)
+ {
+ if (ioctl(devtty, TIOCNOTTY, (char *)0))
+ debug2("brktty: ioctl(devtty=%d, TIOCNOTTY, 0) = %d\n", devtty, errno);
+ close(devtty);
+ }
+# endif /* BSDJOBS */
+# endif /* SYSV */
+#endif /* POSIX */
+}
+
+int
+fgtty(fd)
+int fd;
+{
+#ifdef BSDJOBS
+ int mypid;
+
+ mypid = getpid();
+
+ /* The next lines should be obsolete. Can anybody check if they
+ * are really needed on the BSD platforms?
+ */
+# if defined(__osf__) || (BSD >= 199103) || defined(ISC)
+ setsid(); /* should be already done */
+# ifdef TIOCSCTTY
+ ioctl(fd, TIOCSCTTY, (char *)0);
+# endif
+# endif
+
+# ifdef POSIX
+ if (tcsetpgrp(fd, mypid))
+ {
+ debug1("fgtty: tcsetpgrp: %d\n", errno);
+ return -1;
+ }
+# else /* POSIX */
+ if (ioctl(fd, TIOCSPGRP, (char *)&mypid) != 0)
+ debug1("fgtty: TIOSETPGRP: %d\n", errno);
+# ifndef SYSV /* Already done in brktty():setpgrp() */
+ if (setpgrp(fd, mypid))
+ debug1("fgtty: setpgrp: %d\n", errno);
+# endif
+# endif /* POSIX */
+#endif /* BSDJOBS */
+ return 0;
+}
+
+
+/*
+ * Send a break for n * 0.25 seconds. Tty must be PLAIN.
+ */
+
+void SendBreak(wp, n, closeopen)
+struct win *wp;
+int n, closeopen;
+{
+ if ((wp->w_t.flags & TTY_FLAG_PLAIN) == 0)
+ return;
+
+ debug3("break(%d, %d) fd %d\n", n, closeopen, wp->w_ptyfd);
+#ifdef POSIX
+ (void) tcflush(wp->w_ptyfd, TCIOFLUSH);
+#else
+# ifdef TIOCFLUSH
+ (void) ioctl(wp->w_ptyfd, TIOCFLUSH, (char *)0);
+# endif /* TIOCFLUSH */
+#endif /* POSIX */
+ if (closeopen)
+ {
+ close(wp->w_ptyfd);
+ sleep((n + 3) / 4);
+ if ((wp->w_ptyfd = OpenTTY(wp->w_tty)) < 1)
+ {
+ Msg(0, "Ouch, cannot reopen line %s, please try harder", wp->w_tty);
+ return;
+ }
+ (void) fcntl(wp->w_ptyfd, F_SETFL, FNBLOCK);
+ }
+ else
+ {
+#ifdef POSIX
+ debug("tcsendbreak\n");
+ if (tcsendbreak(wp->w_ptyfd, n) < 0)
+ {
+ Msg(errno, "cannot send BREAK");
+ return;
+ }
+#else
+ if (!n)
+ n++;
+# ifdef TCSBRK
+ debug("TCSBRK\n");
+ {
+ int i;
+ for (i = 0; i < n; i++)
+ if (ioctl(wp->w_ptyfd, TCSBRK, (char *)0) < 0)
+ {
+ Msg(errno, "Cannot send BREAK");
+ return;
+ }
+ }
+# else /* TCSBRK */
+# if defined(TIOCSBRK) && defined(TIOCCBRK)
+ debug("TIOCSBRK TIOCCBRK\n");
+ if (ioctl(wp->w_ptyfd, TIOCSBRK, (char *)0) < 0)
+ {
+ Msg(errno, "Can't send BREAK");
+ return;
+ }
+ sleep((n + 3) / 4);
+ if (ioctl(wp->w_ptyfd, TIOCCBRK, (char *)0) < 0)
+ {
+ Msg(errno, "BREAK stuck!!! -- HELP!");
+ return;
+ }
+# else /* TIOCSBRK && TIOCCBRK */
+ Msg(0, "Break not simulated yet");
+ return;
+# endif /* TIOCSBRK && TIOCCBRK */
+# endif /* TCSBRK */
+#endif /* POSIX */
+ debug(" broken\n");
+ }
+}
+
+
+/*
+ * Console grabbing
+ */
+
+/*ARGSUSED*/
+int
+TtyGrabConsole(fd, on, rc_name)
+int fd, on;
+char *rc_name;
+{
+#ifdef TIOCCONS
+ char *slave;
+ int sfd = -1, ret = 0;
+ struct display *d;
+
+ if (!on)
+ {
+ if ((fd = OpenPTY(&slave)) < 0)
+ {
+ Msg(errno, "%s: could not open detach pty master", rc_name);
+ return -1;
+ }
+ if ((sfd = open(slave, O_RDWR)) < 0)
+ {
+ Msg(errno, "%s: could not open detach pty slave", rc_name);
+ close(fd);
+ return -1;
+ }
+ }
+ else
+ {
+ if (displays == 0)
+ {
+ Msg(0, "I need a display");
+ return -1;
+ }
+ for (d = displays; d; d = d->d_next)
+ if (strcmp(d->d_usertty, "/dev/console") == 0)
+ break;
+ if (d)
+ {
+ Msg(0, "too dangerous - screen is running on /dev/console");
+ return -1;
+ }
+ }
+ if (UserContext() == 1)
+ UserReturn(ioctl(fd, TIOCCONS, (char *)&on));
+ ret = UserStatus();
+ if (ret)
+ Msg(errno, "%s: ioctl TIOCCONS failed", rc_name);
+ if (!on)
+ {
+ close(sfd);
+ close(fd);
+ }
+ return ret;
+#else /* TIOCCONS */
+ Msg(0, "%s: no TIOCCONS on this machine", rc_name);
+ return -1;
+#endif /* TIOCCONS */
+}
+
+
+/*
+ * Write out the mode struct in a readable form
+ */
+
+#ifdef DEBUG
+void
+DebugTTY(m)
+struct mode *m;
+{
+ int i;
+
+#ifdef POSIX
+ debug("struct termios tio:\n");
+ debug1("c_iflag = %#x\n", (unsigned int)m->tio.c_iflag);
+ debug1("c_oflag = %#x\n", (unsigned int)m->tio.c_oflag);
+ debug1("c_cflag = %#x\n", (unsigned int)m->tio.c_cflag);
+ debug1("c_lflag = %#x\n", (unsigned int)m->tio.c_lflag);
+ for (i = 0; i < sizeof(m->tio.c_cc)/sizeof(*m->tio.c_cc); i++)
+ {
+ debug2("c_cc[%d] = %#x\n", i, m->tio.c_cc[i]);
+ }
+# ifdef hpux
+ debug1("suspc = %#02x\n", m->m_ltchars.t_suspc);
+ debug1("dsuspc = %#02x\n", m->m_ltchars.t_dsuspc);
+ debug1("rprntc = %#02x\n", m->m_ltchars.t_rprntc);
+ debug1("flushc = %#02x\n", m->m_ltchars.t_flushc);
+ debug1("werasc = %#02x\n", m->m_ltchars.t_werasc);
+ debug1("lnextc = %#02x\n", m->m_ltchars.t_lnextc);
+# endif /* hpux */
+#else /* POSIX */
+# ifdef TERMIO
+ debug("struct termio tio:\n");
+ debug1("c_iflag = %04o\n", m->tio.c_iflag);
+ debug1("c_oflag = %04o\n", m->tio.c_oflag);
+ debug1("c_cflag = %04o\n", m->tio.c_cflag);
+ debug1("c_lflag = %04o\n", m->tio.c_lflag);
+ for (i = 0; i < sizeof(m->tio.c_cc)/sizeof(*m->tio.c_cc); i++)
+ {
+ debug2("c_cc[%d] = %04o\n", i, m->tio.c_cc[i]);
+ }
+# else /* TERMIO */
+ debug1("sg_ispeed = %d\n", m->m_ttyb.sg_ispeed);
+ debug1("sg_ospeed = %d\n", m->m_ttyb.sg_ospeed);
+ debug1("sg_erase = %#02x\n", m->m_ttyb.sg_erase);
+ debug1("sg_kill = %#02x\n", m->m_ttyb.sg_kill);
+ debug1("sg_flags = %#04x\n", (unsigned short)m->m_ttyb.sg_flags);
+ debug1("intrc = %#02x\n", m->m_tchars.t_intrc);
+ debug1("quitc = %#02x\n", m->m_tchars.t_quitc);
+ debug1("startc = %#02x\n", m->m_tchars.t_startc);
+ debug1("stopc = %#02x\n", m->m_tchars.t_stopc);
+ debug1("eofc = %#02x\n", m->m_tchars.t_eofc);
+ debug1("brkc = %#02x\n", m->m_tchars.t_brkc);
+ debug1("suspc = %#02x\n", m->m_ltchars.t_suspc);
+ debug1("dsuspc = %#02x\n", m->m_ltchars.t_dsuspc);
+ debug1("rprntc = %#02x\n", m->m_ltchars.t_rprntc);
+ debug1("flushc = %#02x\n", m->m_ltchars.t_flushc);
+ debug1("werasc = %#02x\n", m->m_ltchars.t_werasc);
+ debug1("lnextc = %#02x\n", m->m_ltchars.t_lnextc);
+ debug1("ldisc = %d\n", m->m_ldisc);
+ debug1("lmode = %#x\n", m->m_lmode);
+# endif /* TERMIO */
+#endif /* POSIX */
+}
+#endif /* DEBUG */
diff --git a/tty.sh b/tty.sh
new file mode 100644
index 0000000..134f838
--- /dev/null
+++ b/tty.sh
@@ -0,0 +1,862 @@
+#! /bin/sh
+# sh tty.sh tty.c
+# This inserts all the needed #ifdefs for IF{} statements
+# and generates tty.c
+
+rm -f $1
+sed -e '1,17d' \
+-e 's%^IF{\(.*\)}\(.*\)%#if defined(\1)\
+ \2\
+#endif /* \1 */%' \
+-e 's%^XIF{\(.*\)}\(.*\)%#if defined(\1) \&\& \1 < MAXCC\
+ \2\
+#endif /* \1 */%' \
+ < $0 > $1
+chmod -w $1
+exit 0
+
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+/*
+ * NOTICE: tty.c is automatically generated from tty.sh
+ * Do not change anything here. If you then change tty.sh.
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: tty.sh,v 1.13 1994/05/31 12:33:17 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+#include <signal.h>
+#include <fcntl.h>
+#ifndef sgi
+# include <sys/file.h>
+#endif
+#if !defined(sun) || defined(SUNOS3)
+# include <sys/ioctl.h> /* collosions with termios.h */
+#else
+# ifndef TIOCEXCL
+# include <sys/ttold.h> /* needed for TIOCEXCL */
+# endif
+#endif
+
+#ifdef ISC
+# include <sys/tty.h>
+# include <sys/sioctl.h>
+# include <sys/pty.h>
+#endif
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+
+extern struct display *display, *displays;
+extern int iflag;
+
+/* Frank Schulz (fschulz@pyramid.com):
+ * I have no idea why VSTART is not defined and my fix is probably not
+ * the cleanest, but it works.
+ */
+#if !defined(VSTART) && defined(_VSTART)
+#define VSTART _VSTART
+#endif
+#if !defined(VSTOP) && defined(_VSTOP)
+#define VSTOP _VSTOP
+#endif
+
+static sigret_t
+SigAlrmDummy SIGDEFARG
+{
+ debug("SigAlrmDummy()\n");
+ SIGRETURN;
+}
+
+/*
+ * Carefully open a charcter device. Not used to open ttys.
+ */
+
+int
+OpenTTY(line)
+char *line;
+{
+ int f;
+ sigret_t (*sigalrm)__P(SIGPROTOARG);
+
+ sigalrm = signal(SIGALRM, SigAlrmDummy);
+ alarm(2);
+ /* this open only succeeds, if real uid is allowed */
+ if ((f = secopen(line, O_RDWR | O_NONBLOCK, 0)) == -1)
+ {
+ Msg(errno, "Cannot open line '%s' for R/W", line);
+ alarm(0);
+ signal(SIGALRM, sigalrm);
+ return -1;
+ }
+#ifdef I_POP
+ debug("OpenTTY I_POP\n");
+ while (ioctl(f, I_POP, (char *)0) >= 0)
+ ;
+#endif
+ /*
+ * We come here exclusively. This is to stop all kermit and cu type things
+ * accessing the same tty line.
+ * Perhaps we should better create a lock in some /usr/spool/locks directory?
+ */
+#ifdef TIOCEXCL
+ errno = 0;
+ ioctl(f, TIOCEXCL, (char *) 0);
+ debug3("%d %d %d\n", getuid(), geteuid(), getpid());
+ debug2("%s TIOCEXCL errno %d\n", line, errno);
+#endif /* TIOCEXCL */
+ /*
+ * We create a sane tty mode. We do not copy things from the display tty
+ */
+#if WE_REALLY_WANT_TO_COPY_THE_TTY_MODE
+ if (display)
+ {
+ debug1("OpenTTY: using mode of display for %s\n", line);
+ SetTTY(f, &D_NewMode);
+#ifdef DEBUG
+ DebugTTY(&D_NewMode);
+#endif
+ }
+ else
+#endif
+ {
+ struct mode Mode;
+
+ InitTTY(&Mode, TTY_FLAG_PLAIN);
+#ifdef DEBUG
+ DebugTTY(&Mode);
+#endif
+ SetTTY(f, &Mode);
+ }
+ brktty(f);
+ alarm(0);
+ signal(SIGALRM, sigalrm);
+ debug2("'%s' CONNECT fd=%d.\n", line, f);
+ return f;
+}
+
+
+/*
+ * Tty mode handling
+ */
+
+#if defined(TERMIO) || defined(POSIX)
+int intrc, origintrc = VDISABLE; /* display? */
+#else
+int intrc, origintrc = -1; /* display? */
+#endif
+static startc, stopc; /* display? */
+
+
+void
+InitTTY(m, ttyflag)
+struct mode *m;
+int ttyflag;
+{
+ bzero((char *)m, sizeof(*m));
+#ifdef POSIX
+ /* struct termios tio
+ * defaults, as seen on SunOS 4.1.3
+ */
+ debug1("InitTTY: POSIX: termios defaults a la SunOS 4.1.3 (%d)\n", ttyflag);
+IF{BRKINT} m->tio.c_iflag |= BRKINT;
+IF{IGNPAR} m->tio.c_iflag |= IGNPAR;
+IF{ISTRIP} m->tio.c_iflag |= ISTRIP;
+IF{IXON} m->tio.c_iflag |= IXON;
+IF{IMAXBEL} m->tio.c_iflag |= IMAXBEL;
+
+ if (!ttyflag) /* may not even be good for ptys.. */
+ {
+IF{ICRNL} m->tio.c_iflag |= ICRNL;
+IF{ONLCR} m->tio.c_oflag |= ONLCR;
+IF{TAB3} m->tio.c_oflag |= TAB3;
+IF{PARENB} m->tio.c_cflag |= PARENB;
+ }
+
+IF{OPOST} m->tio.c_oflag |= OPOST;
+
+IF{B9600} m->tio.c_cflag |= B9600;
+IF{CS8} m->tio.c_cflag |= CS8;
+IF{CREAD} m->tio.c_cflag |= CREAD;
+IF{IBSHIFT) && defined(B9600} m->tio.c_cflag |= B9600 << IBSHIFT;
+/* IF{CLOCAL} m->tio.c_cflag |= CLOCAL; */
+
+IF{ECHOCTL} m->tio.c_lflag |= ECHOCTL;
+IF{ECHOKE} m->tio.c_lflag |= ECHOKE;
+
+ if (!ttyflag)
+ {
+IF{ISIG} m->tio.c_lflag |= ISIG;
+IF{ICANON} m->tio.c_lflag |= ICANON;
+IF{ECHO} m->tio.c_lflag |= ECHO;
+ }
+IF{ECHOE} m->tio.c_lflag |= ECHOE;
+IF{ECHOK} m->tio.c_lflag |= ECHOK;
+IF{IEXTEN} m->tio.c_lflag |= IEXTEN;
+
+XIF{VINTR} m->tio.c_cc[VINTR] = Ctrl('C');
+XIF{VQUIT} m->tio.c_cc[VQUIT] = Ctrl('\\');
+XIF{VERASE} m->tio.c_cc[VERASE] = 0x7f; /* DEL */
+XIF{VKILL} m->tio.c_cc[VKILL] = Ctrl('H');
+XIF{VEOF} m->tio.c_cc[VEOF] = Ctrl('D');
+XIF{VEOL} m->tio.c_cc[VEOL] = 0000;
+XIF{VEOL2} m->tio.c_cc[VEOL2] = 0000;
+XIF{VSWTCH} m->tio.c_cc[VSWTCH] = 0000;
+XIF{VSTART} m->tio.c_cc[VSTART] = Ctrl('Q');
+XIF{VSTOP} m->tio.c_cc[VSTOP] = Ctrl('S');
+XIF{VSUSP} m->tio.c_cc[VSUSP] = Ctrl('Z');
+XIF{VDSUSP} m->tio.c_cc[VDSUSP] = Ctrl('Y');
+XIF{VREPRINT} m->tio.c_cc[VREPRINT] = Ctrl('R');
+XIF{VDISCARD} m->tio.c_cc[VDISCARD] = Ctrl('O');
+XIF{VWERASE} m->tio.c_cc[VWERASE] = Ctrl('W');
+XIF{VLNEXT} m->tio.c_cc[VLNEXT] = Ctrl('V');
+XIF{VSTATUS} m->tio.c_cc[VSTATUS] = Ctrl('T');
+
+ if (ttyflag)
+ {
+ m->tio.c_cc[VMIN] = 1;
+ m->tio.c_cc[VTIME] = 0;
+ }
+# ifdef hpux
+ m->m_ltchars.t_suspc = Ctrl('Z');
+ m->m_ltchars.t_dsuspc = Ctrl('Y');
+ m->m_ltchars.t_rprntc = Ctrl('R');
+ m->m_ltchars.t_flushc = Ctrl('O');
+ m->m_ltchars.t_werasc = Ctrl('W');
+ m->m_ltchars.t_lnextc = Ctrl('V');
+# endif /* hpux */
+
+#else /* POSIX */
+
+# ifdef TERMIO
+ debug1("InitTTY: nonPOSIX, struct termio a la Motorola SYSV68 (%d)\n", ttyflag);
+ /* struct termio tio
+ * defaults, as seen on Mototola SYSV68:
+ * input: 7bit, CR->NL, ^S/^Q flow control
+ * output: POSTprocessing: NL->NL-CR, Tabs to spaces
+ * control: 9600baud, 8bit CSIZE, enable input
+ * local: enable signals, erase/kill processing, echo on.
+ */
+IF{ISTRIP} m->tio.c_iflag |= ISTRIP;
+IF{IXON} m->tio.c_iflag |= IXON;
+
+IF{OPOST} m->tio.c_oflag |= OPOST;
+
+ if (!ttyflag) /* may not even be good for ptys.. */
+ {
+IF{ICRNL} m->tio.c_iflag |= ICRNL;
+IF{ONLCR} m->tio.c_oflag |= ONLCR;
+IF{TAB3} m->tio.c_oflag |= TAB3;
+ }
+
+IF{B9600} m->tio.c_cflag = B9600;
+IF{CS8} m->tio.c_cflag |= CS8;
+IF{CREAD} m->tio.c_cflag |= CREAD;
+
+ if (!ttyflag)
+ {
+IF{ISIG} m->tio.c_lflag |= ISIG;
+IF{ICANON} m->tio.c_lflag |= ICANON;
+IF{ECHO} m->tio.c_lflag |= ECHO;
+ }
+IF{ECHOE} m->tio.c_lflag |= ECHOE;
+IF{ECHOK} m->tio.c_lflag |= ECHOK;
+
+XIF{VINTR} m->tio.c_cc[VINTR] = Ctrl('C');
+XIF{VQUIT} m->tio.c_cc[VQUIT] = Ctrl('\\');
+XIF{VERASE} m->tio.c_cc[VERASE] = 0177; /* DEL */
+XIF{VKILL} m->tio.c_cc[VKILL] = Ctrl('H');
+XIF{VEOF} m->tio.c_cc[VEOF] = Ctrl('D');
+XIF{VEOL} m->tio.c_cc[VEOL] = 0377;
+XIF{VEOL2} m->tio.c_cc[VEOL2] = 0377;
+XIF{VSWTCH} m->tio.c_cc[VSWTCH] = 0000;
+ if (ttyflag)
+ {
+ m->tio.c_cc[VMIN] = 1;
+ m->tio.c_cc[VTIME] = 0;
+ }
+# else /* TERMIO */
+ debug1("InitTTY: BSD: defaults a la SunOS 4.1.3 (%d)\n", ttyflag);
+ m->m_ttyb.sg_ispeed = B9600;
+ m->m_ttyb.sg_ospeed = B9600;
+ m->m_ttyb.sg_erase = 0177; /*DEL */
+ m->m_ttyb.sg_kill = Ctrl('H');
+ if (!ttyflag)
+ m->m_ttyb.sg_flags = CRMOD | ECHO
+IF{ANYP} | ANYP
+ ;
+ else
+ m->m_ttyb.sg_flags = CBREAK
+IF{ANYP} | ANYP
+ ;
+
+ m->m_tchars.t_intrc = Ctrl('C');
+ m->m_tchars.t_quitc = Ctrl('\\');
+ m->m_tchars.t_startc = Ctrl('Q');
+ m->m_tchars.t_stopc = Ctrl('S');
+ m->m_tchars.t_eofc = Ctrl('D');
+ m->m_tchars.t_brkc = -1;
+
+ m->m_ltchars.t_suspc = Ctrl('Z');
+ m->m_ltchars.t_dsuspc = Ctrl('Y');
+ m->m_ltchars.t_rprntc = Ctrl('R');
+ m->m_ltchars.t_flushc = Ctrl('O');
+ m->m_ltchars.t_werasc = Ctrl('W');
+ m->m_ltchars.t_lnextc = Ctrl('V');
+
+IF{NTTYDISC} m->m_ldisc = NTTYDISC;
+
+ m->m_lmode = 0
+IF{LDECCTQ} | LDECCTQ
+IF{LCTLECH} | LCTLECH
+IF{LPASS8} | LPASS8
+IF{LCRTKIL} | LCRTKIL
+IF{LCRTERA} | LCRTERA
+IF{LCRTBS} | LCRTBS
+;
+# endif /* TERMIO */
+#endif /* POSIX */
+
+#if defined(KANJI) && defined(TIOCKSET) && defined(KM_ASCII) && defined(KM_SYSSJIS)
+ m->m_jtchars.t_ascii = 'J';
+ m->m_jtchars.t_kanji = 'B';
+ m->m_knjmode = KM_ASCII | KM_SYSSJIS;
+#endif
+}
+
+void
+SetTTY(fd, mp)
+int fd;
+struct mode *mp;
+{
+ errno = 0;
+#ifdef POSIX
+ tcsetattr(fd, TCSADRAIN, &mp->tio);
+# ifdef hpux
+ ioctl(fd, TIOCSLTC, (char *)&mp->m_ltchars);
+# endif
+#else
+# ifdef TERMIO
+ ioctl(fd, TCSETAW, (char *)&mp->tio);
+# ifdef CYTERMIO
+ if (mp->tio.c_line == 3)
+ {
+ ioctl(fd, LDSETMAPKEY, (char *)&mp->m_mapkey);
+ ioctl(fd, LDSETMAPSCREEN, (char *)&mp->m_mapscreen);
+ ioctl(fd, LDSETBACKSPACE, (char *)&mp->m_backspace);
+ }
+# endif
+# else
+ /* ioctl(fd, TIOCSETP, (char *)&mp->m_ttyb); */
+ ioctl(fd, TIOCSETC, (char *)&mp->m_tchars);
+ ioctl(fd, TIOCLSET, (char *)&mp->m_lmode);
+ ioctl(fd, TIOCSETD, (char *)&mp->m_ldisc);
+ ioctl(fd, TIOCSETP, (char *)&mp->m_ttyb);
+ ioctl(fd, TIOCSLTC, (char *)&mp->m_ltchars); /* moved here for apollo. jw */
+# endif
+#endif
+#if defined(KANJI) && defined(TIOCKSET) && defined(KM_ASCII) && defined(KM_SYSSJIS)
+ ioctl(fd, TIOCKSETC, &mp->m_jtchars);
+ ioctl(fd, TIOCKSET, &mp->m_knjmode);
+#endif
+ if (errno)
+ Msg(errno, "SetTTY (fd %d): ioctl failed", fd);
+}
+
+void
+GetTTY(fd, mp)
+int fd;
+struct mode *mp;
+{
+ errno = 0;
+#ifdef POSIX
+ tcgetattr(fd, &mp->tio);
+# ifdef hpux
+ ioctl(fd, TIOCGLTC, (char *)&mp->m_ltchars);
+# endif
+#else
+# ifdef TERMIO
+ ioctl(fd, TCGETA, (char *)&mp->tio);
+# ifdef CYTERMIO
+ if (mp->tio.c_line == 3)
+ {
+ ioctl(fd, LDGETMAPKEY, (char *)&mp->m_mapkey);
+ ioctl(fd, LDGETMAPSCREEN, (char *)&mp->m_mapscreen);
+ ioctl(fd, LDGETBACKSPACE, (char *)&mp->m_backspace);
+ }
+ else
+ {
+ mp->m_mapkey = NOMAPKEY;
+ mp->m_mapscreen = NOMAPSCREEN;
+ mp->m_backspace = '\b';
+ }
+# endif
+# else
+ ioctl(fd, TIOCGETP, (char *)&mp->m_ttyb);
+ ioctl(fd, TIOCGETC, (char *)&mp->m_tchars);
+ ioctl(fd, TIOCGLTC, (char *)&mp->m_ltchars);
+ ioctl(fd, TIOCLGET, (char *)&mp->m_lmode);
+ ioctl(fd, TIOCGETD, (char *)&mp->m_ldisc);
+# endif
+#endif
+#if defined(KANJI) && defined(TIOCKSET) && defined(KM_ASCII) && defined(KM_SYSSJIS)
+ ioctl(fd, TIOCKGETC, &mp->m_jtchars);
+ ioctl(fd, TIOCKGET, &mp->m_knjmode);
+#endif
+ if (errno)
+ Msg(errno, "GetTTY (fd %d): ioctl failed", fd);
+}
+
+void
+SetMode(op, np)
+struct mode *op, *np;
+{
+ *np = *op;
+
+#if defined(TERMIO) || defined(POSIX)
+# ifdef CYTERMIO
+ np->m_mapkey = NOMAPKEY;
+ np->m_mapscreen = NOMAPSCREEN;
+ np->tio.c_line = 0;
+# endif
+IF{ICRNL} np->tio.c_iflag &= ~ICRNL;
+IF{ONLCR} np->tio.c_oflag &= ~ONLCR;
+ np->tio.c_lflag &= ~(ICANON | ECHO);
+ /*
+ * From Andrew Myers (andru@tonic.lcs.mit.edu)
+ */
+IF{IEXTEN} np->tio.c_lflag &= ~IEXTEN;
+
+ /*
+ * Unfortunately, the master process never will get SIGINT if the real
+ * terminal is different from the one on which it was originaly started
+ * (process group membership has not been restored or the new tty could not
+ * be made controlling again). In my solution, it is the attacher who
+ * receives SIGINT (because it is always correctly associated with the real
+ * tty) and forwards it to the master [kill(MasterPid, SIGINT)].
+ * Marc Boucher (marc@CAM.ORG)
+ */
+ if (iflag)
+ np->tio.c_lflag |= ISIG;
+ else
+ np->tio.c_lflag &= ~ISIG;
+ /*
+ * careful, careful catche monkey..
+ * never set VMIN and VTIME to zero, if you want blocking io.
+ */
+ np->tio.c_cc[VMIN] = 1;
+ np->tio.c_cc[VTIME] = 0;
+XIF{VSTART} startc = op->tio.c_cc[VSTART];
+XIF{VSTOP} stopc = op->tio.c_cc[VSTOP];
+ if (iflag)
+ origintrc = intrc = op->tio.c_cc[VINTR];
+ else
+ {
+ origintrc = op->tio.c_cc[VINTR];
+ intrc = np->tio.c_cc[VINTR] = VDISABLE;
+ }
+ np->tio.c_cc[VQUIT] = VDISABLE;
+ if (D_flow == 0)
+ {
+ np->tio.c_cc[VINTR] = VDISABLE;
+XIF{VSTART} np->tio.c_cc[VSTART] = VDISABLE;
+XIF{VSTOP} np->tio.c_cc[VSTOP] = VDISABLE;
+ np->tio.c_iflag &= ~IXON;
+ }
+XIF{VDISCARD} np->tio.c_cc[VDISCARD] = VDISABLE;
+XIF{VLNEXT} np->tio.c_cc[VLNEXT] = VDISABLE;
+XIF{VSTATUS} np->tio.c_cc[VSTATUS] = VDISABLE;
+XIF{VSUSP} np->tio.c_cc[VSUSP] = VDISABLE;
+XIF{VERASE} np->tio.c_cc[VERASE] = VDISABLE;
+XIF{VKILL} np->tio.c_cc[VKILL] = VDISABLE;
+# ifdef hpux
+ np->m_ltchars.t_suspc = VDISABLE;
+ np->m_ltchars.t_dsuspc = VDISABLE;
+ np->m_ltchars.t_rprntc = VDISABLE;
+ np->m_ltchars.t_flushc = VDISABLE;
+ np->m_ltchars.t_werasc = VDISABLE;
+ np->m_ltchars.t_lnextc = VDISABLE;
+# else /* hpux */
+XIF{VDSUSP} np->tio.c_cc[VDSUSP] = VDISABLE;
+XIF{VREPRINT} np->tio.c_cc[VREPRINT] = VDISABLE;
+XIF{VWERASE} np->tio.c_cc[VWERASE] = VDISABLE;
+# endif /* hpux */
+#else /* TERMIO || POSIX */
+ startc = op->m_tchars.t_startc;
+ stopc = op->m_tchars.t_stopc;
+ if (iflag)
+ origintrc = intrc = op->m_tchars.t_intrc;
+ else
+ {
+ origintrc = op->m_tchars.t_intrc;
+ intrc = np->m_tchars.t_intrc = -1;
+ }
+ np->m_ttyb.sg_flags &= ~(CRMOD | ECHO);
+ np->m_ttyb.sg_flags |= CBREAK;
+# if defined(CYRILL) && defined(CSTYLE) && defined(CS_8BITS)
+ np->m_ttyb.sg_flags &= ~CSTYLE;
+ np->m_ttyb.sg_flags |= CS_8BITS;
+# endif
+ np->m_tchars.t_quitc = -1;
+ if (D_flow == 0)
+ {
+ np->m_tchars.t_intrc = -1;
+ np->m_tchars.t_startc = -1;
+ np->m_tchars.t_stopc = -1;
+ }
+ np->m_ltchars.t_suspc = -1;
+ np->m_ltchars.t_dsuspc = -1;
+ np->m_ltchars.t_flushc = -1;
+ np->m_ltchars.t_lnextc = -1;
+#endif /* defined(TERMIO) || defined(POSIX) */
+}
+
+void
+SetFlow(on)
+int on;
+{
+ ASSERT(display);
+ if (D_flow == on)
+ return;
+#if defined(TERMIO) || defined(POSIX)
+ if (on)
+ {
+ D_NewMode.tio.c_cc[VINTR] = intrc;
+XIF{VSTART} D_NewMode.tio.c_cc[VSTART] = startc;
+XIF{VSTOP} D_NewMode.tio.c_cc[VSTOP] = stopc;
+ D_NewMode.tio.c_iflag |= IXON;
+ }
+ else
+ {
+ D_NewMode.tio.c_cc[VINTR] = VDISABLE;
+XIF{VSTART} D_NewMode.tio.c_cc[VSTART] = VDISABLE;
+XIF{VSTOP} D_NewMode.tio.c_cc[VSTOP] = VDISABLE;
+ D_NewMode.tio.c_iflag &= ~IXON;
+ }
+# ifdef POSIX
+ if (tcsetattr(D_userfd, TCSANOW, &D_NewMode.tio))
+# else
+ if (ioctl(D_userfd, TCSETAW, (char *)&D_NewMode.tio) != 0)
+# endif
+ debug1("SetFlow: ioctl errno %d\n", errno);
+#else /* POSIX || TERMIO */
+ if (on)
+ {
+ D_NewMode.m_tchars.t_intrc = intrc;
+ D_NewMode.m_tchars.t_startc = startc;
+ D_NewMode.m_tchars.t_stopc = stopc;
+ }
+ else
+ {
+ D_NewMode.m_tchars.t_intrc = -1;
+ D_NewMode.m_tchars.t_startc = -1;
+ D_NewMode.m_tchars.t_stopc = -1;
+ }
+ if (ioctl(D_userfd, TIOCSETC, (char *)&D_NewMode.m_tchars) != 0)
+ debug1("SetFlow: ioctl errno %d\n", errno);
+#endif /* POSIX || TERMIO */
+ D_flow = on;
+}
+
+
+/*
+ * Job control handling
+ *
+ * Somehow the ultrix session handling is broken, so use
+ * the bsdish variant.
+ */
+
+/*ARGSUSED*/
+void
+brktty(fd)
+int fd;
+{
+#if defined(POSIX) && !defined(ultrix)
+ setsid(); /* will break terminal affiliation */
+# if defined(BSD) && defined(TIOCSCTTY)
+ ioctl(fd, TIOCSCTTY, (char *)0);
+# endif /* BSD && TIOCSCTTY */
+#else /* POSIX */
+# ifdef SYSV
+ setpgrp(); /* will break terminal affiliation */
+# else /* SYSV */
+# ifdef BSDJOBS
+ int devtty;
+
+ if ((devtty = open("/dev/tty", O_RDWR | O_NONBLOCK)) >= 0)
+ {
+ if (ioctl(devtty, TIOCNOTTY, (char *)0))
+ debug2("brktty: ioctl(devtty=%d, TIOCNOTTY, 0) = %d\n", devtty, errno);
+ close(devtty);
+ }
+# endif /* BSDJOBS */
+# endif /* SYSV */
+#endif /* POSIX */
+}
+
+int
+fgtty(fd)
+int fd;
+{
+#ifdef BSDJOBS
+ int mypid;
+
+ mypid = getpid();
+
+ /* The next lines should be obsolete. Can anybody check if they
+ * are really needed on the BSD platforms?
+ */
+# if defined(__osf__) || (BSD >= 199103) || defined(ISC)
+ setsid(); /* should be already done */
+# ifdef TIOCSCTTY
+ ioctl(fd, TIOCSCTTY, (char *)0);
+# endif
+# endif
+
+# ifdef POSIX
+ if (tcsetpgrp(fd, mypid))
+ {
+ debug1("fgtty: tcsetpgrp: %d\n", errno);
+ return -1;
+ }
+# else /* POSIX */
+ if (ioctl(fd, TIOCSPGRP, (char *)&mypid) != 0)
+ debug1("fgtty: TIOSETPGRP: %d\n", errno);
+# ifndef SYSV /* Already done in brktty():setpgrp() */
+ if (setpgrp(fd, mypid))
+ debug1("fgtty: setpgrp: %d\n", errno);
+# endif
+# endif /* POSIX */
+#endif /* BSDJOBS */
+ return 0;
+}
+
+
+/*
+ * Send a break for n * 0.25 seconds. Tty must be PLAIN.
+ */
+
+void SendBreak(wp, n, closeopen)
+struct win *wp;
+int n, closeopen;
+{
+ if ((wp->w_t.flags & TTY_FLAG_PLAIN) == 0)
+ return;
+
+ debug3("break(%d, %d) fd %d\n", n, closeopen, wp->w_ptyfd);
+#ifdef POSIX
+ (void) tcflush(wp->w_ptyfd, TCIOFLUSH);
+#else
+# ifdef TIOCFLUSH
+ (void) ioctl(wp->w_ptyfd, TIOCFLUSH, (char *)0);
+# endif /* TIOCFLUSH */
+#endif /* POSIX */
+ if (closeopen)
+ {
+ close(wp->w_ptyfd);
+ sleep((n + 3) / 4);
+ if ((wp->w_ptyfd = OpenTTY(wp->w_tty)) < 1)
+ {
+ Msg(0, "Ouch, cannot reopen line %s, please try harder", wp->w_tty);
+ return;
+ }
+ (void) fcntl(wp->w_ptyfd, F_SETFL, FNBLOCK);
+ }
+ else
+ {
+#ifdef POSIX
+ debug("tcsendbreak\n");
+ if (tcsendbreak(wp->w_ptyfd, n) < 0)
+ {
+ Msg(errno, "cannot send BREAK");
+ return;
+ }
+#else
+ if (!n)
+ n++;
+# ifdef TCSBRK
+ debug("TCSBRK\n");
+ {
+ int i;
+ for (i = 0; i < n; i++)
+ if (ioctl(wp->w_ptyfd, TCSBRK, (char *)0) < 0)
+ {
+ Msg(errno, "Cannot send BREAK");
+ return;
+ }
+ }
+# else /* TCSBRK */
+# if defined(TIOCSBRK) && defined(TIOCCBRK)
+ debug("TIOCSBRK TIOCCBRK\n");
+ if (ioctl(wp->w_ptyfd, TIOCSBRK, (char *)0) < 0)
+ {
+ Msg(errno, "Can't send BREAK");
+ return;
+ }
+ sleep((n + 3) / 4);
+ if (ioctl(wp->w_ptyfd, TIOCCBRK, (char *)0) < 0)
+ {
+ Msg(errno, "BREAK stuck!!! -- HELP!");
+ return;
+ }
+# else /* TIOCSBRK && TIOCCBRK */
+ Msg(0, "Break not simulated yet");
+ return;
+# endif /* TIOCSBRK && TIOCCBRK */
+# endif /* TCSBRK */
+#endif /* POSIX */
+ debug(" broken\n");
+ }
+}
+
+
+/*
+ * Console grabbing
+ */
+
+/*ARGSUSED*/
+int
+TtyGrabConsole(fd, on, rc_name)
+int fd, on;
+char *rc_name;
+{
+#ifdef TIOCCONS
+ char *slave;
+ int sfd = -1, ret = 0;
+ struct display *d;
+
+ if (!on)
+ {
+ if ((fd = OpenPTY(&slave)) < 0)
+ {
+ Msg(errno, "%s: could not open detach pty master", rc_name);
+ return -1;
+ }
+ if ((sfd = open(slave, O_RDWR)) < 0)
+ {
+ Msg(errno, "%s: could not open detach pty slave", rc_name);
+ close(fd);
+ return -1;
+ }
+ }
+ else
+ {
+ if (displays == 0)
+ {
+ Msg(0, "I need a display");
+ return -1;
+ }
+ for (d = displays; d; d = d->d_next)
+ if (strcmp(d->d_usertty, "/dev/console") == 0)
+ break;
+ if (d)
+ {
+ Msg(0, "too dangerous - screen is running on /dev/console");
+ return -1;
+ }
+ }
+ if (UserContext() == 1)
+ UserReturn(ioctl(fd, TIOCCONS, (char *)&on));
+ ret = UserStatus();
+ if (ret)
+ Msg(errno, "%s: ioctl TIOCCONS failed", rc_name);
+ if (!on)
+ {
+ close(sfd);
+ close(fd);
+ }
+ return ret;
+#else /* TIOCCONS */
+ Msg(0, "%s: no TIOCCONS on this machine", rc_name);
+ return -1;
+#endif /* TIOCCONS */
+}
+
+
+/*
+ * Write out the mode struct in a readable form
+ */
+
+#ifdef DEBUG
+void
+DebugTTY(m)
+struct mode *m;
+{
+ int i;
+
+#ifdef POSIX
+ debug("struct termios tio:\n");
+ debug1("c_iflag = %#x\n", (unsigned int)m->tio.c_iflag);
+ debug1("c_oflag = %#x\n", (unsigned int)m->tio.c_oflag);
+ debug1("c_cflag = %#x\n", (unsigned int)m->tio.c_cflag);
+ debug1("c_lflag = %#x\n", (unsigned int)m->tio.c_lflag);
+ for (i = 0; i < sizeof(m->tio.c_cc)/sizeof(*m->tio.c_cc); i++)
+ {
+ debug2("c_cc[%d] = %#x\n", i, m->tio.c_cc[i]);
+ }
+# ifdef hpux
+ debug1("suspc = %#02x\n", m->m_ltchars.t_suspc);
+ debug1("dsuspc = %#02x\n", m->m_ltchars.t_dsuspc);
+ debug1("rprntc = %#02x\n", m->m_ltchars.t_rprntc);
+ debug1("flushc = %#02x\n", m->m_ltchars.t_flushc);
+ debug1("werasc = %#02x\n", m->m_ltchars.t_werasc);
+ debug1("lnextc = %#02x\n", m->m_ltchars.t_lnextc);
+# endif /* hpux */
+#else /* POSIX */
+# ifdef TERMIO
+ debug("struct termio tio:\n");
+ debug1("c_iflag = %04o\n", m->tio.c_iflag);
+ debug1("c_oflag = %04o\n", m->tio.c_oflag);
+ debug1("c_cflag = %04o\n", m->tio.c_cflag);
+ debug1("c_lflag = %04o\n", m->tio.c_lflag);
+ for (i = 0; i < sizeof(m->tio.c_cc)/sizeof(*m->tio.c_cc); i++)
+ {
+ debug2("c_cc[%d] = %04o\n", i, m->tio.c_cc[i]);
+ }
+# else /* TERMIO */
+ debug1("sg_ispeed = %d\n", m->m_ttyb.sg_ispeed);
+ debug1("sg_ospeed = %d\n", m->m_ttyb.sg_ospeed);
+ debug1("sg_erase = %#02x\n", m->m_ttyb.sg_erase);
+ debug1("sg_kill = %#02x\n", m->m_ttyb.sg_kill);
+ debug1("sg_flags = %#04x\n", (unsigned short)m->m_ttyb.sg_flags);
+ debug1("intrc = %#02x\n", m->m_tchars.t_intrc);
+ debug1("quitc = %#02x\n", m->m_tchars.t_quitc);
+ debug1("startc = %#02x\n", m->m_tchars.t_startc);
+ debug1("stopc = %#02x\n", m->m_tchars.t_stopc);
+ debug1("eofc = %#02x\n", m->m_tchars.t_eofc);
+ debug1("brkc = %#02x\n", m->m_tchars.t_brkc);
+ debug1("suspc = %#02x\n", m->m_ltchars.t_suspc);
+ debug1("dsuspc = %#02x\n", m->m_ltchars.t_dsuspc);
+ debug1("rprntc = %#02x\n", m->m_ltchars.t_rprntc);
+ debug1("flushc = %#02x\n", m->m_ltchars.t_flushc);
+ debug1("werasc = %#02x\n", m->m_ltchars.t_werasc);
+ debug1("lnextc = %#02x\n", m->m_ltchars.t_lnextc);
+ debug1("ldisc = %d\n", m->m_ldisc);
+ debug1("lmode = %#x\n", m->m_lmode);
+# endif /* TERMIO */
+#endif /* POSIX */
+}
+#endif /* DEBUG */
diff --git a/utmp.c b/utmp.c
new file mode 100644
index 0000000..66f83f1
--- /dev/null
+++ b/utmp.c
@@ -0,0 +1,800 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: utmp.c,v 1.7 1994/05/31 12:33:21 mlschroe Exp $ FAU")
+
+
+/*
+ * An explanation of some weird things:
+ *
+ * linux should have GETUTENT, but their pututline() doesn't have
+ * a return value.
+ *
+ * UTNOKEEP: A (ugly) hack for apollo that does two things:
+ * 1) Always close and reopen the utmp file descriptor. (I don't know
+ * for what reason this is done...)
+ * 2) Implement an unsorted utmp file much like GETUTENT.
+ * (split into UT_CLOSE and UT_UNSORTED)
+ */
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+
+
+extern struct display *display;
+extern struct win *fore;
+extern char *LoginName;
+#ifdef NETHACK
+extern nethackflag;
+#endif
+
+
+#ifdef UTNOKEEP
+# define UT_CLOSE
+# define UT_UNSORTED
+#endif
+
+
+#ifdef UTMPOK
+
+static slot_t TtyNameSlot __P((char *));
+
+static int utmpok, utmpfd = -1;
+static char UtmpName[] = UTMPFILE;
+
+
+# if defined(GETUTENT) && !defined(SVR4)
+# if defined(hpux) /* cruel hpux release 8.0 */
+# define pututline _pututline
+# endif /* hpux */
+extern struct utmp *getutline(), *pututline();
+# if defined(_SEQUENT_)
+extern struct utmp *ut_add_user(), *ut_delete_user();
+extern char *ut_find_host();
+# ifndef UTHOST
+# define UTHOST /* _SEQUENT_ has got ut_find_host() */
+# endif
+# endif /* _SEQUENT_ */
+# endif /* GETUTENT && !SVR4 */
+
+# if !defined(GETUTENT) && !defined(UT_UNSORTED)
+# ifdef GETTTYENT
+# include <ttyent.h>
+# else
+struct ttyent { char *ty_name; };
+static void setttyent __P((void));
+static struct ttyent *getttyent __P((void));
+# endif
+# endif /* !GETUTENT && !UT_UNSORTED */
+
+#endif /* UTMPOK */
+
+
+
+
+/*
+ * SlotToggle - modify the utmp slot of the fore window.
+ *
+ * how > 0 do try to set a utmp slot.
+ * how = 0 try to withdraw a utmp slot.
+ *
+ * w_slot = -1 window not logged in.
+ * w_slot = 0 window not logged in, but should be logged in.
+ * (unable to write utmp, or detached).
+ */
+void
+SlotToggle(how)
+int how;
+{
+ debug1("SlotToggle %d\n", how);
+#ifdef UTMPOK
+ if (how)
+ {
+ debug(" try to log in\n");
+ if ((fore->w_slot == (slot_t) -1) || (fore->w_slot == (slot_t) 0))
+ {
+# ifdef USRLIMIT
+ if (CountUsers() >= USRLIMIT)
+ Msg(0, "User limit reached.");
+ else
+# endif
+ {
+ if (SetUtmp(fore) == 0)
+ Msg(0, "This window is now logged in.");
+ else
+ Msg(0, "This window should now be logged in.");
+ }
+ }
+ else
+ Msg(0, "This window is already logged in.");
+ }
+ else
+ {
+ debug(" try to log out\n");
+ if (fore->w_slot == (slot_t) -1)
+ Msg(0, "This window is already logged out\n");
+ else if (fore->w_slot == (slot_t) 0)
+ {
+ debug("What a relief! In fact, it was not logged in\n");
+ Msg(0, "This window is not logged in.");
+ fore->w_slot = (slot_t) -1;
+ }
+ else
+ {
+ RemoveUtmp(fore);
+ if (fore->w_slot != (slot_t) -1)
+ Msg(0, "What? Cannot remove Utmp slot?");
+ else
+ Msg(0, "This window is no longer logged in.");
+ }
+ }
+#else /* !UTMPOK */
+# ifdef UTMPFILE
+ Msg(0, "Unable to modify %s.\n", UTMPFILE);
+# else
+ Msg(0, "Unable to modify utmp-database.\n");
+# endif
+#endif
+}
+
+
+
+
+#ifdef UTMPOK
+
+
+
+void
+InitUtmp()
+{
+ debug1("InitUtmp testing '%s'...\n", UtmpName);
+ if ((utmpfd = open(UtmpName, O_RDWR)) == -1)
+ {
+ if (errno != EACCES)
+ Msg(errno, UtmpName);
+ debug("InitUtmp failed.\n");
+ utmpok = 0;
+ return;
+ }
+#ifdef GETUTENT
+ close(utmpfd); /* it was just a test */
+ utmpfd = -1;
+#endif /* GETUTENT */
+ utmpok = 1;
+}
+
+
+#ifdef USRLIMIT
+int
+CountUsers()
+{
+# ifdef GETUTENT
+ struct utmp *ut, *getutent();
+# else /* GETUTENT */
+ struct utmp utmpbuf;
+# endif /* GETUTENT */
+ int UserCount;
+
+# ifdef UT_CLOSE
+ InitUtmp();
+# endif /* UT_CLOSE */
+ debug1("CountUsers() - utmpok=%d\n", utmpok);
+ if (!utmpok)
+ return 0;
+ UserCount = 0;
+# ifdef GETUTENT
+ setutent();
+ while (ut = getutent())
+ if (ut->ut_type == USER_PROCESS)
+ UserCount++;
+# else /* GETUTENT */
+ (void) lseek(utmpfd, (off_t) 0, 0);
+ while (read(utmpfd, &utmpbuf, sizeof(utmpbuf)) == sizeof(utmpbuf))
+ if (utmpbuf.ut_name[0] != '\0')
+ UserCount++;
+# endif /* GETUTENT */
+# ifdef UT_CLOSE
+ close(utmpfd);
+# endif /* UT_CLOSE */
+ return UserCount;
+}
+#endif /* USRLIMIT */
+
+
+
+/*
+ * the utmp entry for tty is located and removed.
+ * it is stored in D_utmp_logintty.
+ */
+void
+RemoveLoginSlot()
+{
+#ifdef GETUTENT
+ struct utmp *uu;
+#endif /* GETUTENT */
+ struct utmp u; /* 'empty' slot that we write back */
+#ifdef _SEQUENT_
+ char *p;
+#endif /* _SEQUENT_ */
+
+ ASSERT(display);
+ debug("RemoveLoginSlot: removing your logintty\n");
+ D_loginslot = TtyNameSlot(D_usertty);
+ if (D_loginslot == (slot_t)0 || D_loginslot == (slot_t)-1)
+ return;
+#ifdef UT_CLOSE
+ InitUtmp();
+#endif /* UT_CLOSE */
+ if (!utmpok)
+ {
+ debug("RemoveLoginSlot: utmpok == 0\n");
+ return;
+ }
+
+#ifdef _SEQUENT_
+ if (p = ut_find_host(D_loginslot))
+ strncpy(D_loginhost, p, sizeof(D_loginhost) - 1);
+ D_loginhost[sizeof(D_loginhost) - 1] = 0;
+#endif /* _SEQUENT_ */
+
+ bzero((char *) &u, sizeof(u));
+
+#ifdef GETUTENT
+ setutent();
+ strncpy(u.ut_line, D_loginslot, sizeof(u.ut_line));
+ if ((uu = getutline(&u)) == 0)
+ {
+ Msg(0, "Utmp slot not found -> not removed");
+ return;
+ }
+ D_utmp_logintty = *uu;
+# ifdef _SEQUENT_
+ if (ut_delete_user(D_loginslot, uu->ut_pid, 0, 0) == 0)
+# else /* _SEQUENT_ */
+ u = *uu;
+ u.ut_type = DEAD_PROCESS;
+ u.ut_exit.e_termination = 0;
+ u.ut_exit.e_exit= 0;
+ if (pututline(&u) == 0)
+# endif /* _SEQUENT_ */
+
+#else /* GETUTENT */
+
+ bzero((char *)&D_utmp_logintty, sizeof(u));
+ (void) lseek(utmpfd, (off_t) (D_loginslot * sizeof(u)), 0);
+ if (read(utmpfd, (char *) &D_utmp_logintty, sizeof(u)) != sizeof(u))
+ {
+ Msg(errno, "cannot read %s ??", UtmpName);
+ sleep(1);
+ }
+# ifdef UT_UNSORTED
+ /* copy tty line */
+ bcopy((char *)&D_utmp_logintty, (char *)&u, sizeof(u));
+ bzero(u.ut_name, sizeof(u.ut_name));
+ bzero(u.ut_host, sizeof(u.ut_host));
+# ifdef linux
+ u.ut_type = DEAD_PROCESS;
+# endif
+# endif /* UT_UNSORTED */
+ (void) lseek(utmpfd, (off_t) (D_loginslot * sizeof(u)), 0);
+ if (write(utmpfd, (char *) &u, sizeof(u)) != sizeof(u))
+
+#endif /* GETUTENT */
+
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(errno, "%s is too hard to dig in", UtmpName);
+ else
+#endif /* NETHACK */
+ Msg(errno, "Could not write %s", UtmpName);
+ }
+#ifdef UT_CLOSE
+ close(utmpfd);
+#endif /* UT_CLOSE */
+ debug1(" slot %d zapped\n", (int)D_loginslot);
+}
+
+/*
+ * D_utmp_logintty is reinserted into utmp
+ */
+void
+RestoreLoginSlot()
+{
+ debug("RestoreLoginSlot()\n");
+ ASSERT(display);
+#ifdef UT_CLOSE
+ InitUtmp();
+#endif /* UT_CLOSE */
+ if (utmpok && D_loginslot != (slot_t)0 && D_loginslot != (slot_t)-1)
+ {
+#ifdef GETUTENT
+# ifdef _SEQUENT_
+ int fail;
+ debug1(" logging you in again (slot %s)\n", D_loginslot);
+/*
+ * We have problems if we add the console and use ut_add_user()
+ * because the id will be 'scon' instead of 'co'. So we
+ * restore it with pututline(). The reason why we don't use
+ * pututline all the time is that we want to set the host field.
+ * Unfortunatelly this can only be done with ut_add_user().
+ */
+ if (*D_loginhost)
+ {
+ fail = (ut_add_user(D_utmp_logintty.ut_name, D_loginslot, D_utmp_logintty.ut_pid,
+ *D_loginhost ? D_loginhost : (char *)0) == 0);
+ }
+ else
+ {
+ setutent();
+ fail = (pututline(&D_utmp_logintty) == 0);
+ }
+ if (fail)
+# else /* _SEQUENT_ */
+ debug1(" logging you in again (slot %s)\n", D_loginslot);
+ setutent();
+ if (pututline(&D_utmp_logintty) == 0)
+# endif /* _SEQUENT */
+#else /* GETUTENT */
+ debug1(" logging you in again (slot %d)\n", D_loginslot);
+# ifdef sequent
+ /*
+ * call sequent undocumented routine to count logins
+ * and add utmp entry if possible
+ */
+ if (add_utmp(D_loginslot, &D_utmp_logintty) == -1)
+# else /* sequent */
+ (void) lseek(utmpfd, (off_t) (D_loginslot * sizeof(struct utmp)), 0);
+ if (write(utmpfd, (char *) &D_utmp_logintty, sizeof(struct utmp))
+ != sizeof(struct utmp))
+# endif /* sequent */
+#endif /* GETUTENT */
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(errno, "%s is too hard to dig in", UtmpName);
+ else
+#endif /* NETHACK */
+ Msg(errno,"Could not write %s", UtmpName);
+ }
+ }
+#ifdef UT_CLOSE
+ close(utmpfd);
+#endif /* UT_CLOSE */
+ D_loginslot = (slot_t) 0;
+}
+
+
+
+/*
+ * Construct a utmp entry for window wi.
+ * the hostname field reflects what we know about the user (i.e. display)
+ * location. If d_loginhost is not set, then he is local and we write
+ * down the name of his terminal line; else he is remote and we keep
+ * the hostname here. The letter S and the window id will be appended.
+ * A saved utmp entry in wi->w_savut serves as a template, usually.
+ */
+
+int
+SetUtmp(wi)
+struct win *wi;
+{
+ register char *p;
+ register slot_t slot;
+#ifndef _SEQUENT_
+ char *line;
+#endif
+ struct utmp u;
+ int saved_ut;
+#ifdef UTHOST
+# ifdef _SEQUENT_
+ char host[100+5];
+# else /* _SEQUENT_ */
+ char host[sizeof(D_utmp_logintty.ut_host)+5];
+# endif /* _SEQUENT_ */
+#endif /* UTHOST */
+
+ wi->w_slot = (slot_t)0;
+ if (!utmpok)
+ return -1;
+ if ((slot = TtyNameSlot(wi->w_tty)) == (slot_t)0)
+ {
+ debug1("SetUtmp failed (tty %s).\n",wi->w_tty);
+ return -1;
+ }
+ debug2("SetUtmp %d will get slot %d...\n", wi->w_number, (int)slot);
+#ifdef UT_CLOSE
+ InitUtmp();
+#endif /* UT_CLOSE */
+
+ bzero((char *) &u, sizeof(u));
+ if ((saved_ut = bcmp((char *) &wi->w_savut, (char *) &u, sizeof(u))))
+ /* restore original, of which we will adopt all fields but ut_host */
+ bcopy((char *) &wi->w_savut, (char *) &u, sizeof(u));
+
+#ifdef UTHOST
+ host[sizeof(host)-5] = '\0';
+ if (display)
+ {
+# ifdef _SEQUENT_
+ strncpy(host, D_loginhost, sizeof(host) - 5);
+# else /* _SEQUENT */
+ strncpy(host, D_utmp_logintty.ut_host, sizeof(host) - 5);
+# endif /* _SEQUENT */
+ if (D_loginslot != (slot_t)0 && D_loginslot != (slot_t)-1 && host[0] != '\0')
+ {
+ /*
+ * we want to set our ut_host field to something like
+ * ":ttyhf:s.0" or
+ * "faui45:s.0" or
+ * "132.199.81.4:s.0" (even this may hurt..), but not
+ * "faui45.informati"......:s.0
+ */
+ for (p = host; *p; p++)
+ if ((*p < '0' || *p > '9') && (*p != '.'))
+ break;
+ if (*p)
+ {
+ for (p = host; *p; p++)
+ if (*p == '.')
+ {
+ *p = '\0';
+ break;
+ }
+ }
+ }
+ else
+ {
+ strncpy(host + 1, stripdev(D_usertty), sizeof(host) - 6);
+ host[0] = ':';
+ }
+ }
+ else
+ strncpy(host, "local", sizeof(host) - 5);
+ sprintf(host + strlen(host), ":S.%c", '0' + wi->w_number);
+ debug1("rlogin hostname: '%s'\n", host);
+# if !defined(_SEQUENT_) && !defined(sequent)
+ strncpy(u.ut_host, host, sizeof(u.ut_host));
+# endif
+#endif /* UTHOST */
+
+#ifdef _SEQUENT_
+ if (ut_add_user(saved_ut ? u.ut_user : LoginName, slot, saved_ut ? u.ut_pid : wi->w_pid, host) == 0)
+#else /* _SEQUENT_ */
+ if (!saved_ut)
+ { /* make new utmp from scratch */
+ line = stripdev(wi->w_tty);
+# ifdef GETUTENT
+ strncpy(u.ut_user, LoginName, sizeof(u.ut_user));
+ /* Now the tricky part... guess ut_id */
+# ifdef sgi
+ strncpy(u.ut_id, line + 3, sizeof(u.ut_id));
+# else /* sgi */
+# ifdef _IBMR2
+ strncpy(u.ut_id, line, sizeof(u.ut_id));
+# else
+ strncpy(u.ut_id, line + strlen(line) - 2, sizeof(u.ut_id));
+# endif
+# endif /* sgi */
+ strncpy(u.ut_line, line, sizeof(u.ut_line));
+ u.ut_pid = wi->w_pid;
+ u.ut_type = USER_PROCESS;
+ (void) time((time_t *)&u.ut_time);
+ } /* !saved_ut {-: */
+ setutent();
+ if (pututline(&u) == 0)
+# else /* GETUTENT */
+ strncpy(u.ut_line, line, sizeof(u.ut_line));
+ strncpy(u.ut_name, LoginName, sizeof(u.ut_name));
+# if defined(linux) /* should have GETUTENT */
+ u.ut_type = USER_PROCESS;
+ u.ut_pid = wi->w_pid;
+ strncpy(u.ut_id, line + 3, sizeof(u.ut_id));
+# endif /* linux */
+ (void) time((time_t *)&u.ut_time); /* cast needed for ultrix */
+ } /* !saved_ut */
+# ifdef sequent
+ /*
+ * call sequent undocumented routine to count logins and
+ * add utmp entry if possible
+ */
+ if (add_utmp(slot, &u) == -1)
+# else /* sequent */
+ (void) lseek(utmpfd, (off_t) (slot * sizeof(u)), 0);
+ if (write(utmpfd, (char *) &u, sizeof(u)) != sizeof(u))
+# endif /* sequent */
+# endif /* GETUTENT */
+#endif /* _SEQUENT_ */
+
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(errno, "%s is too hard to dig in", UtmpName);
+ else
+#endif /* NETHACK */
+ Msg(errno,"Could not write %s", UtmpName);
+#ifdef UT_CLOSE
+ close(utmpfd);
+#endif /* UT_CLOSE */
+ return -1;
+ }
+ debug("SetUtmp successful\n");
+ wi->w_slot = slot;
+#ifdef UT_CLOSE
+ close(utmpfd);
+#endif /* UT_CLOSE */
+ bcopy((char *) &u, (char *) &wi->w_savut, sizeof(u));
+ return 0;
+}
+
+
+
+/*
+ * if slot could be removed or was 0, wi->w_slot = -1;
+ * else not changed.
+ */
+
+int
+RemoveUtmp(wi)
+struct win *wi;
+{
+#ifdef GETUTENT
+ struct utmp *uu;
+#endif /* GETUTENT */
+ struct utmp u;
+ slot_t slot;
+
+ slot = wi->w_slot;
+#ifdef GETUTENT
+ debug1("RemoveUtmp(%s)\n", (slot == (slot_t) 0) ?
+ "no slot (0)":((slot == (slot_t) -1) ? "no slot (-1)" : slot));
+#else /* GETUTENT */
+ debug1("RemoveUtmp(wi.slot: %d)\n", slot);
+#endif /* GETUTENT */
+#ifdef UT_CLOSE
+ InitUtmp();
+#endif /* UT_CLOSE */
+ if (!utmpok)
+ return -1;
+ if (slot == (slot_t) 0 || slot == (slot_t) -1)
+ {
+ debug1("There is no utmp-slot to be removed(%d)\n", (int)slot);
+ wi->w_slot = (slot_t) -1;
+ return 0;
+ }
+ bzero((char *) &u, sizeof(u));
+#ifdef GETUTENT
+ setutent();
+# ifdef sgi
+ bcopy((char *) &wi->w_savut, (char *) &u, sizeof(u));
+ uu = &u;
+# else
+ strncpy(u.ut_line, slot, sizeof(u.ut_line));
+ if ((uu = getutline(&u)) == 0)
+ {
+ Msg(0, "Utmp slot not found -> not removed");
+ return -1;
+ }
+ bcopy((char *)uu, (char *)&wi->w_savut, sizeof(wi->w_savut));
+# endif
+# ifdef _SEQUENT_
+ if (ut_delete_user(slot, uu->ut_pid, 0, 0) == 0)
+# else /* _SEQUENT_ */
+ u = *uu;
+ u.ut_type = DEAD_PROCESS;
+ u.ut_exit.e_termination = 0;
+ u.ut_exit.e_exit= 0;
+ if (pututline(&u) == 0)
+# endif /* _SEQUENT_ */
+#else /* GETUTENT */
+ (void) lseek(utmpfd, (off_t) (slot * sizeof(u)), 0);
+ if (read(utmpfd, (char *) &wi->w_savut, sizeof(u)) != sizeof(u))
+ {
+ bzero((char *)&wi->w_savut, sizeof(wi->w_savut));
+ Msg(errno, "cannot read %s?", UtmpName);
+ sleep(1);
+ }
+# ifdef UT_UNSORTED
+ bcopy((char *)&wi->w_savut, (char *)&u, sizeof(u));
+ bzero(u.ut_name, sizeof(u.ut_name));
+ bzero(u.ut_host, sizeof(u.ut_host));
+# ifdef linux
+ u.ut_type = DEAD_PROCESS;
+# endif
+# endif /* UT_UNSORTED */
+ (void) lseek(utmpfd, (off_t) (slot * sizeof(u)), 0);
+ if (write(utmpfd, (char *) &u, sizeof(u)) != sizeof(u))
+#endif /* GETUTENT */
+ {
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(errno, "%s is too hard to dig in", UtmpName);
+ else
+#endif /* NETHACK */
+ Msg(errno,"Could not write %s", UtmpName);
+#ifdef UT_CLOSE
+ close(utmpfd);
+#endif /* UT_CLOSE */
+ return -1;
+ }
+ debug("RemoveUtmp successfull\n");
+ wi->w_slot = (slot_t) -1;
+#ifdef UT_CLOSE
+ close(utmpfd);
+#endif /* UT_CLOSE */
+ return 0;
+}
+
+
+
+/*
+ * TtyNameSlot:
+ * return an index, where the named tty is found in utmp.
+ */
+
+static slot_t
+TtyNameSlot(nam)
+char *nam;
+{
+ char *name;
+ register slot_t slot;
+#ifdef UT_UNSORTED
+ struct utmp u;
+#else
+# ifndef GETUTENT
+ register struct ttyent *tp;
+# endif /* GETUTENT */
+#endif /* UT_UNSORTED */
+
+ debug1("TtyNameSlot(%s)\n", nam);
+#ifdef UT_CLOSE
+ InitUtmp();
+#endif /* UT_CLOSE */
+ if (!utmpok || nam == 0)
+ return (slot_t)0;
+ name = stripdev(nam);
+#ifdef GETUTENT
+ slot = name;
+#else /* GETUTENT */
+# ifdef UT_UNSORTED
+ slot = 0;
+ (void) lseek(utmpfd, (off_t) 0, 0);
+ while ((read(utmpfd, (char *)&u, sizeof(u)) == sizeof(u))
+ && (strcmp(u.ut_line, name)))
+ slot++;
+# else /* UT_UNSORTED*/
+ slot = 1;
+ setttyent();
+ while ((tp = getttyent()) != 0 && strcmp(name, tp->ty_name) != 0)
+ slot++;
+# endif /* UTNOKEEP */
+#endif /* GETUTENT */
+
+#ifdef UT_CLOSE
+ close(utmpfd);
+#endif
+ return slot;
+}
+
+
+
+#if !defined(GETTTYENT) && !defined(GETUTENT) && !defined(UT_UNSORTED)
+
+/*
+ * Cheap plastic imitation of ttyent routines.
+ */
+
+static char *tt, *ttnext;
+static char ttys[] = "/etc/ttys";
+
+static void
+setttyent()
+{
+ if (ttnext == 0)
+ {
+ struct stat s;
+ register int f;
+ register char *p, *ep;
+
+ if ((f = open(ttys, O_RDONLY)) == -1 || fstat(f, &s) == -1)
+ Panic(errno, ttys);
+ if ((tt = malloc((unsigned) s.st_size + 1)) == 0)
+ Panic(0, strnomem);
+ if (read(f, tt, s.st_size) != s.st_size)
+ Panic(errno, ttys);
+ close(f);
+ for (p = tt, ep = p + s.st_size; p < ep; p++)
+ if (*p == '\n')
+ *p = '\0';
+ *p = '\0';
+ }
+ ttnext = tt;
+}
+
+static struct ttyent *
+getttyent()
+{
+ static struct ttyent t;
+
+ if (*ttnext == '\0')
+ return NULL;
+ t.ty_name = ttnext + 2;
+ ttnext += strlen(ttnext) + 1;
+ return &t;
+}
+
+#endif /* !GETTTYENT && !GETUTENT && !UT_UNSORTED*/
+
+
+
+#endif /* UTMPOK */
+
+
+
+
+/*********************************************************************
+ *
+ * getlogin() replacement (for SVR4 machines)
+ */
+
+# if defined(BUGGYGETLOGIN) && defined(UTMP_FILE)
+char *
+getlogin()
+{
+ char *tty;
+#ifdef utmp
+# undef utmp
+#endif
+ struct utmp u;
+ static char retbuf[sizeof(u.ut_user)+1];
+ int fd;
+
+ for (fd = 0; fd <= 2 && (tty = ttyname(fd)) == NULL; fd++)
+ ;
+ if ((tty == NULL) || ((fd = open(UTMP_FILE, O_RDONLY)) < 0))
+ return NULL;
+ tty = stripdev(tty);
+ retbuf[0] = '\0';
+ while (read(fd, (char *)&u, sizeof(struct utmp)) == sizeof(struct utmp))
+ {
+ if (!strncmp(tty, u.ut_line, sizeof(u.ut_line)))
+ {
+ strncpy(retbuf, u.ut_user, sizeof(u.ut_user));
+ retbuf[sizeof(u.ut_user)] = '\0';
+ if (u.ut_type == USER_PROCESS)
+ break;
+ }
+ }
+ close(fd);
+
+ return *retbuf ? retbuf : NULL;
+}
+# endif /* BUGGYGETLOGIN */
+
diff --git a/window.c b/window.c
new file mode 100644
index 0000000..021c9a0
--- /dev/null
+++ b/window.c
@@ -0,0 +1,1118 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: window.c,v 1.20 1994/05/31 12:33:24 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <fcntl.h>
+#ifndef sun
+#include <sys/ioctl.h>
+#endif
+
+#include "config.h"
+
+#ifdef SVR4
+# include <sys/stropts.h>
+#endif
+
+#include "screen.h"
+#include "extern.h"
+
+extern struct display *displays, *display;
+extern struct win *windows, *fore, *wtab[], *console_window;
+extern char *ShellArgs[];
+extern char *ShellProg;
+extern char screenterm[];
+extern char HostName[];
+extern int TtyMode;
+extern struct LayFuncs WinLf;
+extern int real_uid, real_gid, eff_uid, eff_gid;
+extern char Termcap[];
+extern char **NewEnv;
+
+#if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
+extern struct winsize glwz;
+#endif
+
+#ifdef _IBMR2
+extern int aixhack;
+#endif
+
+
+static int OpenDevice __P((char *, int, int *, char **));
+static int ForkWindow __P((char **, char *, char *, char *, struct win *));
+static void execvpe __P((char *, char **, char **));
+
+
+char DefaultShell[] = "/bin/sh";
+static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
+
+
+struct NewWindow nwin_undef =
+{
+ -1, (char *)0, (char **)0, (char *)0, (char *)0, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, (char *)0, (char *)0
+};
+
+struct NewWindow nwin_default =
+{
+ 0, (char *)0, ShellArgs, (char *)0, screenterm, 0, 1*FLOW_NOW,
+ LOGINDEFAULT, DEFAULTHISTHEIGHT, MON_OFF, WLOCK_AUTO,
+ 1, 1, 0, 0, (char *)0, (char *)0
+};
+
+struct NewWindow nwin_options;
+
+void
+nwin_compose(def, new, res)
+struct NewWindow *def, *new, *res;
+{
+ res->StartAt = new->StartAt != nwin_undef.StartAt ? new->StartAt : def->StartAt;
+ res->aka = new->aka != nwin_undef.aka ? new->aka : def->aka;
+ res->args = new->args != nwin_undef.args ? new->args : def->args;
+ res->dir = new->dir != nwin_undef.dir ? new->dir : def->dir;
+ res->term = new->term != nwin_undef.term ? new->term : def->term;
+ res->aflag = new->aflag != nwin_undef.aflag ? new->aflag : def->aflag;
+ res->flowflag = new->flowflag != nwin_undef.flowflag ? new->flowflag : def->flowflag;
+ res->lflag = new->lflag != nwin_undef.lflag ? new->lflag : def->lflag;
+ res->histheight = new->histheight != nwin_undef.histheight ? new->histheight : def->histheight;
+ res->monitor = new->monitor != nwin_undef.monitor ? new->monitor : def->monitor;
+ res->wlock = new->wlock != nwin_undef.wlock ? new->wlock : def->wlock;
+ res->wrap = new->wrap != nwin_undef.wrap ? new->wrap : def->wrap;
+ res->c1 = new->c1 != nwin_undef.c1 ? new->c1 : def->c1;
+ res->gr = new->gr != nwin_undef.gr ? new->gr : def->gr;
+#ifdef KANJI
+ res->kanji = new->kanji != nwin_undef.kanji ? new->kanji : def->kanji;
+#endif
+ res->hstatus = new->hstatus != nwin_undef.hstatus ? new->hstatus : def->hstatus;
+ res->charset = new->charset != nwin_undef.charset ? new->charset : def->charset;
+}
+
+int
+MakeWindow(newwin)
+struct NewWindow *newwin;
+{
+ register struct win **pp, *p;
+ register int n, i;
+ int f = -1;
+ struct NewWindow nwin;
+ int ttyflag;
+ char *TtyName;
+
+ debug1("NewWindow: StartAt %d\n", newwin->StartAt);
+ debug1("NewWindow: aka %s\n", newwin->aka?newwin->aka:"NULL");
+ debug1("NewWindow: dir %s\n", newwin->dir?newwin->dir:"NULL");
+ debug1("NewWindow: term %s\n", newwin->term?newwin->term:"NULL");
+ nwin_compose(&nwin_default, newwin, &nwin);
+ debug1("NWin: aka %s\n", nwin.aka ? nwin.aka : "NULL");
+ debug1("NWin: wlock %d\n", nwin.wlock);
+ pp = wtab + nwin.StartAt;
+
+ do
+ {
+ if (*pp == 0)
+ break;
+ if (++pp == wtab + MAXWIN)
+ pp = wtab;
+ }
+ while (pp != wtab + nwin.StartAt);
+ if (*pp)
+ {
+ Msg(0, "No more windows.");
+ return -1;
+ }
+
+#if defined(USRLIMIT) && defined(UTMPOK)
+ /*
+ * Count current number of users, if logging windows in.
+ */
+ if (nwin.lflag && CountUsers() >= USRLIMIT)
+ {
+ Msg(0, "User limit reached. Window will not be logged in.");
+ nwin.lflag = 0;
+ }
+#endif
+ n = pp - wtab;
+ debug1("Makewin creating %d\n", n);
+
+ if ((f = OpenDevice(nwin.args[0], nwin.lflag, &ttyflag, &TtyName)) < 0)
+ return -1;
+
+ if ((p = (struct win *) malloc(sizeof(struct win))) == 0)
+ {
+ close(f);
+ Msg(0, strnomem);
+ return -1;
+ }
+ bzero((char *) p, (int) sizeof(struct win)); /* looks like a calloc above */
+
+ /* save the command line so that zombies can be resurrected */
+ for (i = 0; nwin.args[i] && i < MAXARGS - 1; i++)
+ p->w_cmdargs[i] = SaveStr(nwin.args[i]);
+ p->w_cmdargs[i] = 0;
+
+#ifdef MULTIUSER
+ if (NewWindowAcl(p))
+ {
+ free((char *)p);
+ close(f);
+ Msg(0, strnomem);
+ return -1;
+ }
+#endif
+ p->w_winlay.l_next = 0;
+ p->w_winlay.l_layfn = &WinLf;
+ p->w_winlay.l_data = (char *)p;
+ p->w_lay = &p->w_winlay;
+ p->w_display = display;
+ p->w_pdisplay = 0;
+#ifdef MULTIUSER
+ if (display && !AclCheckPermWin(D_user, ACL_WRITE, p))
+#else
+ if (display)
+#endif
+ p->w_wlockuser = D_user;
+ p->w_number = n;
+ p->w_ptyfd = f;
+ p->w_aflag = nwin.aflag;
+ p->w_flow = nwin.flowflag | ((nwin.flowflag & FLOW_AUTOFLAG) ? (FLOW_AUTO|FLOW_NOW) : FLOW_AUTO);
+ if (!nwin.aka)
+ nwin.aka = Filename(nwin.args[0]);
+ strncpy(p->w_akabuf, nwin.aka, MAXSTR - 1);
+ if ((nwin.aka = rindex(p->w_akabuf, '|')) != NULL)
+ {
+ p->w_autoaka = 0;
+ *nwin.aka++ = 0;
+ p->w_title = nwin.aka;
+ p->w_akachange = nwin.aka + strlen(nwin.aka);
+ }
+ else
+ p->w_title = p->w_akachange = p->w_akabuf;
+ if (nwin.hstatus)
+ p->w_hstatus = SaveStr(nwin.hstatus);
+ p->w_monitor = nwin.monitor;
+ p->w_norefresh = 0;
+ strncpy(p->w_tty, TtyName, MAXSTR - 1);
+
+#ifndef COPY_PASTE
+ nwin.histheight = 0;
+#endif
+ if (ChangeWindowSize(p, display ? D_defwidth : 80, display ? D_defheight : 24, nwin.histheight))
+ {
+ FreeWindow(p);
+ return -1;
+ }
+#ifdef KANJI
+ p->w_kanji = nwin.kanji;
+#endif
+ ResetWindow(p); /* sets w_wrap, w_c1, w_gr */
+ if (nwin.charset)
+ SetCharsets(p, nwin.charset);
+
+ if (ttyflag == TTY_FLAG_PLAIN)
+ {
+ p->w_t.flags |= TTY_FLAG_PLAIN;
+ p->w_pid = 0;
+ }
+ else
+ {
+ debug("forking...\n");
+#ifdef PSEUDOS
+ p->w_pwin = NULL;
+#endif
+ p->w_pid = ForkWindow(nwin.args, nwin.dir, nwin.term, TtyName, p);
+ if (p->w_pid < 0)
+ {
+ FreeWindow(p);
+ return -1;
+ }
+ }
+ /*
+ * Place the newly created window at the head of the most-recently-used list.
+ */
+ if (display && D_fore)
+ D_other = D_fore;
+ *pp = p;
+ p->w_next = windows;
+ windows = p;
+#ifdef UTMPOK
+ p->w_slot = (slot_t) -1;
+# ifdef LOGOUTOK
+ debug1("MakeWindow will %slog in.\n", nwin.lflag?"":"not ");
+ if (nwin.lflag)
+# else /* LOGOUTOK */
+ debug1("MakeWindow will log in, LOGOUTOK undefined in config.h%s.\n",
+ nwin.lflag?"":" (although lflag=0)");
+# endif /* LOGOUTOK */
+ {
+ p->w_slot = (slot_t) 0;
+ if (display)
+ SetUtmp(p);
+ }
+#endif
+ SetForeWindow(p);
+ Activate(p->w_norefresh);
+ return n;
+}
+
+/*
+ * Resurrect a window from Zombie state.
+ * The command vector is therefore stored in the window structure.
+ * Note: The terminaltype defaults to screenterm again, the current
+ * working directory is lost.
+ */
+int
+RemakeWindow(p)
+struct win *p;
+{
+ int ttyflag;
+ char *TtyName;
+ int lflag, f;
+
+ lflag = nwin_default.lflag;
+ if ((f = OpenDevice(p->w_cmdargs[0], lflag, &ttyflag, &TtyName)) < 0)
+ return -1;
+
+ strncpy(p->w_tty, *TtyName ? TtyName : p->w_title, MAXSTR - 1);
+ p->w_ptyfd = f;
+
+ p->w_t.flags &= ~TTY_FLAG_PLAIN;
+ if (ttyflag == TTY_FLAG_PLAIN)
+ {
+ p->w_t.flags |= TTY_FLAG_PLAIN; /* Just in case... */
+ WriteString(p, p->w_cmdargs[0], strlen(p->w_cmdargs[0]));
+ WriteString(p, ": ", 2);
+ WriteString(p, p->w_title, strlen(p->w_title));
+ WriteString(p, "\r\n", 2);
+ p->w_pid = 0;
+ }
+ else
+ {
+ for (f = 0; p->w_cmdargs[f]; f++)
+ {
+ if (f)
+ WriteString(p, " ", 1);
+ WriteString(p, p->w_cmdargs[f], strlen(p->w_cmdargs[f]));
+ }
+ WriteString(p, "\r\n", 2);
+ p->w_pid = ForkWindow(p->w_cmdargs, (char *)0, nwin_default.term, TtyName, p);
+ if (p->w_pid < 0)
+ return -1;
+ }
+
+#ifdef UTMPOK
+ p->w_slot = (slot_t) -1;
+ debug1("RemakeWindow will %slog in.\n", lflag ? "" : "not ");
+# ifdef LOGOUTOK
+ if (lflag)
+# endif
+ {
+ p->w_slot = (slot_t) 0;
+ if (display)
+ SetUtmp(p);
+ }
+#endif
+ return p->w_number;
+}
+
+void
+FreeWindow(wp)
+struct win *wp;
+{
+ struct display *d;
+ int i;
+
+#ifdef PSEUDOS
+ if (wp->w_pwin)
+ FreePseudowin(wp);
+#endif
+#ifdef UTMPOK
+ RemoveUtmp(wp);
+#endif
+ if (wp->w_ptyfd >= 0)
+ {
+ (void) chmod(wp->w_tty, 0666);
+ (void) chown(wp->w_tty, 0, 0);
+ close(wp->w_ptyfd);
+ wp->w_ptyfd = -1;
+ }
+ if (wp == console_window)
+ console_window = 0;
+ if (wp->w_logfp != NULL)
+ fclose(wp->w_logfp);
+ ChangeWindowSize(wp, 0, 0, 0);
+ if (wp->w_hstatus)
+ free(wp->w_hstatus);
+ for (i = 0; wp->w_cmdargs[i]; i++)
+ free(wp->w_cmdargs[i]);
+ for (d = displays; d; d = d->d_next)
+ if (d->d_other == wp)
+ d->d_other = 0;
+#ifdef MULTIUSER
+ for (i = 0; i < ACL_BITS_PER_WIN; i++)
+ free((char *)wp->w_userbits[i]);
+#endif
+ free((char *)wp);
+}
+
+static int
+OpenDevice(arg, lflag, typep, namep)
+char *arg;
+int lflag;
+int *typep;
+char **namep;
+{
+ struct stat st;
+ int f;
+
+ if ((stat(arg, &st)) == 0 && S_ISCHR(st.st_mode))
+ {
+ if (access(arg, R_OK | W_OK) == -1)
+ {
+ Msg(errno, "Cannot access line '%s' for R/W", arg);
+ return -1;
+ }
+ debug("OpenDevice: OpenTTY\n");
+ if ((f = OpenTTY(arg)) < 0)
+ return -1;
+ *typep = TTY_FLAG_PLAIN;
+ *namep = arg;
+ }
+ else
+ {
+ *typep = 0; /* for now we hope it is a program */
+ f = OpenPTY(namep);
+ if (f == -1)
+ {
+ Msg(0, "No more PTYs.");
+ return -1;
+ }
+#ifdef TIOCPKT
+ {
+ int flag = 1;
+
+ if (ioctl(f, TIOCPKT, (char *)&flag))
+ {
+ Msg(errno, "TIOCPKT ioctl");
+ close(f);
+ return -1;
+ }
+ }
+#endif /* TIOCPKT */
+ }
+ (void) fcntl(f, F_SETFL, FNBLOCK);
+#ifdef linux
+ /*
+ * Tenebreux (zeus@ns.acadiacom.net) has Linux 1.3.70 where select gets
+ * confused in the following condition:
+ * Open a pty-master side, request a flush on it, then set packet mode.
+ * and call select(). Select will return a possible read, where the
+ * one byte response to the flush can be found. Select will thereafter
+ * return a possible read, which yields I/O error.
+ *
+ * If we request another flush *after* switching into packet mode, this
+ * I/O error does not occur. We receive a single response byte although we
+ * send two flush requests now. Maybe we should not flush at all.
+ *
+ * 10.5.96 jw.
+ */
+ tcflush(f, TCIOFLUSH);
+#endif
+#ifdef PTYGROUP
+ (void) chown(*namep, real_uid, PTYGROUP);
+#else
+ (void) chown(*namep, real_uid, real_gid);
+#endif
+#ifdef UTMPOK
+ (void) chmod(*namep, lflag ? TtyMode : (TtyMode & ~022));
+#else
+ (void) chmod(*namep, TtyMode);
+#endif
+ return f;
+}
+
+/*
+ * Fields w_width, w_height, aflag, number (and w_tty)
+ * are read from struct win *win. No fields written.
+ * If pwin is nonzero, filedescriptors are distributed
+ * between win->w_tty and open(ttyn)
+ *
+ */
+static int
+ForkWindow(args, dir, term, ttyn, win)
+char **args, *dir, *term, *ttyn;
+struct win *win;
+{
+ int pid;
+ char tebuf[25];
+ char ebuf[10];
+ char shellbuf[7 + MAXPATHLEN];
+ char *proc;
+#ifndef TIOCSWINSZ
+ char libuf[20], cobuf[20];
+#endif
+ int newfd;
+ int w = win->w_width;
+ int h = win->w_height;
+#ifdef PSEUDOS
+ int i, pat, wfdused;
+ struct pseudowin *pwin = win->w_pwin;
+#endif
+
+ proc = *args;
+ if (proc == 0)
+ {
+ args = ShellArgs;
+ proc = *args;
+ }
+ switch (pid = fork())
+ {
+ case -1:
+ Msg(errno, "fork");
+ break;
+ case 0:
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+#ifdef BSDJOBS
+ signal(SIGTTIN, SIG_DFL);
+ signal(SIGTTOU, SIG_DFL);
+#endif
+#ifdef SIGPIPE
+ signal(SIGPIPE, SIG_DFL);
+#endif
+#ifdef SIGXFSZ
+ signal(SIGXFSZ, SIG_DFL);
+#endif
+
+ displays = 0; /* beware of Panic() */
+ if (setuid(real_uid) || setgid(real_gid))
+ {
+ SendErrorMsg("Setuid/gid: %s", strerror(errno));
+ exit(1);
+ }
+ eff_uid = real_uid;
+ eff_gid = real_gid;
+ if (dir && *dir && chdir(dir) == -1)
+ {
+ SendErrorMsg("Cannot chdir to %s: %s", dir, strerror(errno));
+ exit(1);
+ }
+
+ if (display)
+ {
+ brktty(D_userfd);
+ freetty();
+ }
+ else
+ brktty(-1);
+#ifdef DEBUG
+ if (dfp && dfp != stderr)
+ fclose(dfp);
+#endif
+#ifdef _IBMR2
+ close(0);
+ dup(aixhack);
+ close(aixhack);
+#endif
+ closeallfiles(win->w_ptyfd);
+#ifdef _IBMR2
+ aixhack = dup(0);
+#endif
+#ifdef DEBUG
+ {
+ char buf[256];
+
+ sprintf(buf, "%s/screen.child", DEBUGDIR);
+ if ((dfp = fopen(buf, "a")) == 0)
+ dfp = stderr;
+ else
+ (void) chmod(buf, 0666);
+ }
+ debug1("=== ForkWindow: pid %d\n", getpid());
+#endif
+ /* Close the three /dev/null descriptors */
+ close(0);
+ close(1);
+ close(2);
+ newfd = -1;
+ /*
+ * distribute filedescriptors between the ttys
+ */
+#ifdef PSEUDOS
+ pat = pwin ? pwin->fdpat :
+ ((F_PFRONT<<(F_PSHIFT*2)) | (F_PFRONT<<F_PSHIFT) | F_PFRONT);
+ wfdused = 0;
+ for(i = 0; i < 3; i++)
+ {
+ if (pat & F_PFRONT << F_PSHIFT * i)
+ {
+ if (newfd < 0)
+ {
+ if ((newfd = open(ttyn, O_RDWR)) < 0)
+ {
+ SendErrorMsg("Cannot open %s: %s", ttyn, strerror(errno));
+ exit(1);
+ }
+ }
+ else
+ dup(newfd);
+ }
+ else
+ {
+ dup(win->w_ptyfd);
+ wfdused = 1;
+ }
+ }
+ if (wfdused)
+ {
+ /*
+ * the pseudo window process should not be surprised with a
+ * nonblocking filedescriptor. Poor Backend!
+ */
+ debug1("Clearing NBLOCK on window-fd(%d)\n", win->w_ptyfd);
+ if (fcntl(win->w_ptyfd, F_SETFL, 0))
+ SendErrorMsg("Warning: ForkWindow clear NBLOCK fcntl failed, %d", errno);
+ }
+#else /* PSEUDOS */
+ if ((newfd = open(ttyn, O_RDWR)) != 0)
+ {
+ SendErrorMsg("Cannot open %s: %s", ttyn, strerror(errno));
+ exit(1);
+ }
+ dup(0);
+ dup(0);
+#endif /* PSEUDOS */
+ close(win->w_ptyfd);
+#ifdef _IBMR2
+ close(aixhack);
+#endif
+
+ if (newfd >= 0)
+ {
+ struct mode fakemode, *modep;
+#if defined(SVR4) && !defined(sgi)
+ if (ioctl(newfd, I_PUSH, "ptem"))
+ {
+ SendErrorMsg("Cannot I_PUSH ptem %s %s", ttyn, strerror(errno));
+ exit(1);
+ }
+ if (ioctl(newfd, I_PUSH, "ldterm"))
+ {
+ SendErrorMsg("Cannot I_PUSH ldterm %s %s", ttyn, strerror(errno));
+ exit(1);
+ }
+ if (ioctl(newfd, I_PUSH, "ttcompat"))
+ {
+ SendErrorMsg("Cannot I_PUSH ttcompat %s %s", ttyn, strerror(errno));
+ exit(1);
+ }
+#endif
+ if (fgtty(newfd))
+ SendErrorMsg("fgtty: %s (%d)", strerror(errno), errno);
+ if (display)
+ {
+ debug("ForkWindow: using display tty mode for new child.\n");
+ modep = &D_OldMode;
+ }
+ else
+ {
+ debug("No display - creating tty setting\n");
+ modep = &fakemode;
+ InitTTY(modep, 0);
+#ifdef DEBUG
+ DebugTTY(modep);
+#endif
+ }
+ /* We only want echo if the users input goes to the pseudo
+ * and the pseudo's stdout is not send to the window.
+ */
+#ifdef PSEUDOS
+ if (pwin && (!(pat & F_UWP) || (pat & F_PBACK << F_PSHIFT)))
+ {
+ debug1("clearing echo on pseudywin fd (pat %x)\n", pat);
+# if defined(POSIX) || defined(TERMIO)
+ modep->tio.c_lflag &= ~ECHO;
+ modep->tio.c_iflag &= ~ICRNL;
+# else
+ modep->m_ttyb.sg_flags &= ~ECHO;
+# endif
+ }
+#endif
+ SetTTY(newfd, modep);
+#ifdef TIOCSWINSZ
+ glwz.ws_col = w;
+ glwz.ws_row = h;
+ (void) ioctl(newfd, TIOCSWINSZ, (char *)&glwz);
+#endif
+ /* Always turn off nonblocking mode */
+ (void)fcntl(newfd, F_SETFL, 0);
+ }
+#ifndef TIOCSWINSZ
+ sprintf(libuf, "LINES=%d", h);
+ sprintf(cobuf, "COLUMNS=%d", w);
+ NewEnv[5] = libuf;
+ NewEnv[6] = cobuf;
+#endif
+#ifdef MAPKEYS
+ NewEnv[2] = MakeTermcap(display == 0 || win->w_aflag);
+#else
+ if (win->w_aflag)
+ NewEnv[2] = MakeTermcap(1);
+ else
+ NewEnv[2] = Termcap;
+#endif
+ strcpy(shellbuf, "SHELL=");
+ strncpy(shellbuf + 6, ShellProg, MAXPATHLEN);
+ shellbuf[MAXPATHLEN + 6] = 0;
+ NewEnv[4] = shellbuf;
+ debug1("ForkWindow: NewEnv[4] = '%s'\n", shellbuf);
+ if (term && *term && strcmp(screenterm, term) &&
+ (strlen(term) < 20))
+ {
+ char *s1, *s2, tl;
+
+ sprintf(tebuf, "TERM=%s", term);
+ debug2("Makewindow %d with %s\n", win->w_number, tebuf);
+ tl = strlen(term);
+ NewEnv[1] = tebuf;
+ if ((s1 = index(NewEnv[2], '|')))
+ {
+ if ((s2 = index(++s1, '|')))
+ {
+ if (strlen(NewEnv[2]) - (s2 - s1) + tl < 1024)
+ {
+ bcopy(s2, s1 + tl, strlen(s2) + 1);
+ bcopy(term, s1, tl);
+ }
+ }
+ }
+ }
+ sprintf(ebuf, "WINDOW=%d", win->w_number);
+ NewEnv[3] = ebuf;
+
+ if (*proc == '-')
+ proc++;
+ if (!*proc)
+ proc = DefaultShell;
+ debug1("calling execvpe %s\n", proc);
+ execvpe(proc, args, NewEnv);
+ debug1("exec error: %d\n", errno);
+ SendErrorMsg("Cannot exec '%s': %s", proc, strerror(errno));
+ exit(1);
+ default:
+ break;
+ }
+#ifdef _IBMR2
+ close(aixhack);
+ aixhack = -1;
+#endif
+ return pid;
+}
+
+static void
+execvpe(prog, args, env)
+char *prog, **args, **env;
+{
+ register char *path = NULL, *p;
+ char buf[1024];
+ char *shargs[MAXARGS + 1];
+ register int i, eaccess = 0;
+
+ if (rindex(prog, '/'))
+ path = "";
+ if (!path && !(path = getenv("PATH")))
+ path = DefaultPath;
+ do
+ {
+ p = buf;
+ while (*path && *path != ':')
+ *p++ = *path++;
+ if (p > buf)
+ *p++ = '/';
+ strcpy(p, prog);
+ execve(buf, args, env);
+ switch (errno)
+ {
+ case ENOEXEC:
+ shargs[0] = DefaultShell;
+ shargs[1] = buf;
+ for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i)
+ ;
+ execve(DefaultShell, shargs, env);
+ return;
+ case EACCES:
+ eaccess = 1;
+ break;
+ case ENOMEM:
+ case E2BIG:
+ case ETXTBSY:
+ return;
+ }
+ } while (*path++);
+ if (eaccess)
+ errno = EACCES;
+}
+
+#ifdef PSEUDOS
+
+int
+winexec(av)
+char **av;
+{
+ char **pp;
+ char *p, *s, *t;
+ int i, r = 0, l = 0;
+ struct win *w;
+ extern struct display *display;
+ extern struct win *windows;
+ struct pseudowin *pwin;
+
+ if ((w = display ? fore : windows) == NULL)
+ return -1;
+ if (!*av || w->w_pwin)
+ {
+ Msg(0, "Filter running: %s", w->w_pwin ? w->w_pwin->p_cmd : "(none)");
+ return -1;
+ }
+ if (w->w_ptyfd < 0)
+ {
+ Msg(0, "You feel dead inside.");
+ return -1;
+ }
+ if (!(pwin = (struct pseudowin *)malloc(sizeof(struct pseudowin))))
+ {
+ Msg(0, strnomem);
+ return -1;
+ }
+ bzero((char *)pwin, (int)sizeof(*pwin));
+
+ /* allow ^a:!!./ttytest as a short form for ^a:exec !.. ./ttytest */
+ for (s = *av; *s == ' '; s++)
+ ;
+ for (p = s; *p == ':' || *p == '.' || *p == '!'; p++)
+ ;
+ if (*p != '|')
+ while (*p && p > s && p[-1] == '.')
+ p--;
+ if (*p == '|')
+ {
+ l = F_UWP;
+ p++;
+ }
+ if (*p)
+ av[0] = p;
+ else
+ av++;
+
+ t = pwin->p_cmd;
+ for (i = 0; i < 3; i++)
+ {
+ *t = (s < p) ? *s++ : '.';
+ switch (*t++)
+ {
+ case '.':
+ case '|':
+ l |= F_PFRONT << (i * F_PSHIFT);
+ break;
+ case '!':
+ l |= F_PBACK << (i * F_PSHIFT);
+ break;
+ case ':':
+ l |= F_PBOTH << (i * F_PSHIFT);
+ break;
+ }
+ }
+
+ if (l & F_UWP)
+ {
+ *t++ = '|';
+ if ((l & F_PMASK) == F_PFRONT)
+ {
+ *pwin->p_cmd = '!';
+ l ^= F_PFRONT | F_PBACK;
+ }
+ }
+ if (!(l & F_PBACK))
+ l |= F_UWP;
+ *t++ = ' ';
+ pwin->fdpat = l;
+ debug1("winexec: '%#x'\n", pwin->fdpat);
+
+ l = MAXSTR - 4;
+ for (pp = av; *pp; pp++)
+ {
+ p = *pp;
+ while (*p && l-- > 0)
+ *t++ = *p++;
+ if (l <= 0)
+ break;
+ *t++ = ' ';
+ }
+ *--t = '\0';
+ debug1("%s\n", pwin->p_cmd);
+
+ if ((pwin->p_ptyfd = OpenDevice(av[0], 0, &l, &t)) < 0)
+ {
+ free((char *)pwin);
+ return -1;
+ }
+ strncpy(pwin->p_tty, t, MAXSTR - 1);
+ w->w_pwin = pwin;
+ if (l == TTY_FLAG_PLAIN)
+ {
+ FreePseudowin(w);
+ Msg(0, "Cannot handle a TTY as a pseudo win.");
+ return -1;
+ }
+#ifdef TIOCPKT
+ {
+ int flag = 0;
+
+ if (ioctl(pwin->p_ptyfd, TIOCPKT, (char *)&flag))
+ {
+ Msg(errno, "TIOCPKT ioctl");
+ FreePseudowin(w);
+ return -1;
+ }
+ }
+#endif /* TIOCPKT */
+ pwin->p_pid = ForkWindow(av, (char *)0, (char *)0, t, w);
+ if ((r = pwin->p_pid) < 0)
+ FreePseudowin(w);
+ return r;
+}
+
+void
+FreePseudowin(w)
+struct win *w;
+{
+ struct pseudowin *pwin = w->w_pwin;
+
+ ASSERT(pwin);
+ if (fcntl(w->w_ptyfd, F_SETFL, FNBLOCK))
+ Msg(errno, "Warning: FreePseudowin: NBLOCK fcntl failed");
+ (void) chmod(pwin->p_tty, 0666);
+ (void) chown(pwin->p_tty, 0, 0);
+ if (pwin->p_ptyfd >= 0)
+ close(pwin->p_ptyfd);
+ free((char *)pwin);
+ w->w_pwin = NULL;
+}
+
+#endif /* PSEUDOS */
+
+
+#ifdef MULTI
+
+/*
+ * Clone routines. To be removed...
+ */
+
+static int CloneTermcap __P((struct display *));
+extern char **environ;
+
+
+int
+execclone(av)
+char **av;
+{
+ int f, sf;
+ char specialbuf[6];
+ struct display *old = display;
+ char **avp, *namep;
+
+ sf = OpenPTY(&namep);
+ if (sf == -1)
+ {
+ Msg(0, "No more PTYs.");
+ return -1;
+ }
+#ifdef _IBMR2
+ close(aixhack);
+ aixhack = -1;
+#endif
+ f = open(namep, O_RDWR);
+ if (f == -1)
+ {
+ close(sf);
+ Msg(errno, "Cannot open slave");
+ return -1;
+ }
+ brktty(f);
+ signal(SIGHUP, SIG_IGN); /* No hangups, please */
+ if (MakeDisplay(D_username, namep, D_termname, f, -1, &D_OldMode) == 0)
+ {
+ display = old;
+ Msg(0, "Could not make display.");
+ close(f);
+ close(sf);
+ return -1;
+ }
+ if (CloneTermcap(old))
+ {
+ FreeDisplay();
+ display = old;
+ close(sf);
+ return -1;
+ }
+
+ SetMode(&D_OldMode, &D_NewMode);
+ SetTTY(f, &D_NewMode);
+
+ switch (fork())
+ {
+ case -1:
+ FreeDisplay();
+ display = old;
+ Msg(errno, "fork");
+ close(sf);
+ return -1;
+ case 0:
+ D_usertty[0] = 0; /* for SendErrorMsg */
+ displays = 0; /* beware of Panic() */
+ if (setuid(real_uid) || setgid(real_gid))
+ {
+ SendErrorMsg("Setuid/gid: %s", strerror(errno));
+ exit(1);
+ }
+ eff_uid = real_uid;
+ eff_gid = real_gid;
+ closeallfiles(sf);
+ close(1);
+ dup(sf);
+ close(sf);
+#ifdef DEBUG
+ {
+ char buf[256];
+
+ sprintf(buf, "%s/screen.child", DEBUGDIR);
+ if ((dfp = fopen(buf, "a")) == 0)
+ dfp = stderr;
+ else
+ (void) chmod(buf, 0666);
+ }
+ debug1("=== Clone: pid %d\n", getpid());
+#endif
+ for (avp = av; *avp; avp++)
+ {
+ if (strcmp(*avp, "%p") == 0)
+ *avp = namep;
+ if (strcmp(*avp, "%X") == 0)
+ *avp = specialbuf;
+ }
+ sprintf(specialbuf, "-SXX1");
+ namep += strlen(namep);
+ specialbuf[3] = *--namep;
+ specialbuf[2] = *--namep;
+#ifdef DEBUG
+ debug("Calling:");
+ for (avp = av; *avp; avp++)
+ debug1(" %s", *avp);
+ debug("\n");
+#endif
+ execvpe(*av, av, environ);
+ SendErrorMsg("Cannot exec '%s': %s", *av, strerror(errno));
+ exit(1);
+ default:
+ break;
+ }
+ close(sf);
+ InitTerm(0);
+ Activate(0);
+ if (D_fore == 0)
+ ShowWindows();
+ return 0;
+}
+
+extern struct term term[]; /* terminal capabilities */
+
+static int
+CloneTermcap(old)
+struct display *old;
+{
+ char *tp;
+ int i, l;
+
+ l = 0;
+ for (i = 0; i < T_N; i++)
+ if (term[i].type == T_STR && old->d_tcs[i].str)
+ l += strlen(old->d_tcs[i].str) + 1;
+ if ((D_tentry = (char *)malloc(l)) == 0)
+ {
+ Msg(0, strnomem);
+ return -1;
+ }
+
+ tp = D_tentry;
+ for (i = 0; i < T_N; i++)
+ {
+ switch(term[i].type)
+ {
+ case T_FLG:
+ D_tcs[i].flg = old->d_tcs[i].flg;
+ break;
+ case T_NUM:
+ D_tcs[i].num = old->d_tcs[i].num;
+ break;
+ case T_STR:
+ D_tcs[i].str = old->d_tcs[i].str;
+ if (D_tcs[i].str)
+ {
+ strcpy(tp, D_tcs[i].str);
+ D_tcs[i].str = tp;
+ tp += strlen(tp) + 1;
+ }
+ break;
+ default:
+ Panic(0, "Illegal tc type in entry #%d", i);
+ }
+ }
+ CheckScreenSize(0);
+ for (i = 0; i < NATTR; i++)
+ D_attrtab[i] = old->d_attrtab[i];
+ for (i = 0; i < 256; i++)
+ D_c0_tab[i] = old->d_c0_tab[i];
+ D_UPcost = old->d_UPcost;
+ D_DOcost = old->d_DOcost;
+ D_NLcost = old->d_NLcost;
+ D_LEcost = old->d_LEcost;
+ D_NDcost = old->d_NDcost;
+ D_CRcost = old->d_CRcost;
+ D_IMcost = old->d_IMcost;
+ D_EIcost = old->d_EIcost;
+#ifdef AUTO_NUKE
+ D_auto_nuke = old->d_auto_nuke;
+#endif
+ if (D_CXC)
+ CreateTransTable(D_CXC);
+ D_tcinited = 1;
+ return 0;
+}
+
+#endif
+
diff --git a/window.h b/window.h
new file mode 100644
index 0000000..51a1797
--- /dev/null
+++ b/window.h
@@ -0,0 +1,233 @@
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ * $Id: window.h,v 1.11 1994/05/31 12:33:27 mlschroe Exp $ FAU
+ */
+
+#ifndef MAXWIN
+# define MAXWIN 10
+#endif
+
+
+struct NewWindow
+{
+ int StartAt; /* where to start the search for the slot */
+ char *aka; /* aka string */
+ char **args; /* argv vector */
+ char *dir; /* directory for chdir */
+ char *term; /* TERM to be set instead of "screen" */
+ int aflag;
+ int flowflag;
+ int lflag;
+ int histheight;
+ int monitor;
+ int wlock; /* default writelock setting */
+ int wrap;
+ int c1;
+ int gr;
+ int kanji;
+ char *hstatus;
+ char *charset;
+};
+
+
+#ifdef PSEUDOS
+
+struct pseudowin
+{
+ int fdpat;
+ int p_pid;
+ int p_ptyfd;
+ char p_cmd[MAXSTR];
+ char p_tty[MAXSTR];
+ char p_inbuf[IOSIZE]; /* buffered writing to p_ptyfd */
+ int p_inlen;
+};
+
+/* bits for fdpat: */
+#define F_PMASK 0x0003
+#define F_PSHIFT 2
+#define F_PFRONT 0x0001 /* . */
+#define F_PBACK 0x0002 /* ! */
+#define F_PBOTH (F_PFRONT | F_PBACK) /* : */
+
+#define F_UWP 0x1000 /* | */
+
+/* The screen process ...)
+ * ... wants to write to pseudo */
+#define W_WP(w) ((w)->w_pwin && ((w)->w_pwin->fdpat & F_PFRONT))
+
+/* ... wants to write to window: user writes to window
+ * or stdout/stderr of pseudo are duplicated to window */
+#define W_WW(w) (!((w)->w_pwin) || \
+(((w)->w_pwin->fdpat & F_PMASK) == F_PBACK) || \
+((((w)->w_pwin->fdpat >> F_PSHIFT) & F_PMASK) == F_PBOTH) || \
+((((w)->w_pwin->fdpat >> (F_PSHIFT * 2)) & F_PMASK) == F_PBOTH))
+
+/* ... wants to read from pseudowin */
+#define W_RP(w) ((w)->w_pwin && ((w)->w_pwin->fdpat & \
+((F_PFRONT << (F_PSHIFT * 2)) | (F_PFRONT << F_PSHIFT)) ))
+
+/* ... wants to read from window */
+#define W_RW(w) (!((w)->w_pwin) || ((w)->w_pwin->fdpat & F_PFRONT))
+
+/* user input is written to pseudo */
+#define W_UWP(w) ((w)->w_pwin && ((w)->w_pwin->fdpat & F_UWP))
+
+/* pseudo output has to be stuffed in window */
+#define W_PTOW(w) (\
+((w)->w_pwin->fdpat & F_PMASK << F_PSHIFT) == F_PBOTH << F_PSHIFT || \
+((w)->w_pwin->fdpat & F_PMASK << F_PSHIFT * 2) == F_PBOTH << F_PSHIFT * 2 )
+
+/* window output has to be stuffed in pseudo */
+#define W_WTOP(w) (((w)->w_pwin->fdpat & F_PMASK) == F_PBOTH)
+
+#endif /* PSEUDOS */
+
+
+
+
+struct win
+{
+ struct win *w_next; /* next window */
+#ifdef PSEUDOS
+ struct pseudowin *w_pwin; /* ptr to pseudo */
+#endif
+ struct display *w_display; /* pointer to our display */
+ struct display *w_pdisplay; /* display for printer relay */
+ int w_number; /* window number */
+ int w_active; /* is window fore and has no layer? */
+ struct layer *w_lay; /* the layer of the window */
+ struct layer w_winlay; /* the layer of the window */
+ int w_pid; /* process at the other end of ptyfd */
+ char *w_cmdargs[MAXARGS]; /* command line argument vector */
+ int w_ptyfd; /* fd of the master pty */
+ int w_aflag; /* (used for DUMP_TERMCAP) */
+ char w_inbuf[IOSIZE];
+ int w_inlen;
+ char w_outbuf[IOSIZE];
+ int w_outlen;
+ char *w_title; /* name of the window */
+ char *w_akachange; /* autoaka hack */
+ int w_autoaka; /* autoaka hack */
+ char w_akabuf[MAXSTR]; /* aka buffer */
+ char w_tty[MAXSTR];
+ struct tty_attr w_t;
+ int w_intermediate; /* char used while parsing ESC-seq */
+ int w_args[MAXARGS];
+ int w_NumArgs;
+ slot_t w_slot; /* utmp slot */
+#if defined (UTMPOK)
+ struct utmp w_savut; /* utmp entry of this window */
+#endif
+ struct mline *w_mlines;
+ int w_x, w_y; /* Cursor position */
+ int w_width, w_height; /* window size */
+ struct mchar w_rend; /* current rendition */
+ char w_FontL; /* character font GL */
+ char w_FontR; /* character font GR */
+ int w_Charset; /* charset number GL */
+ int w_CharsetR; /* charset number GR */
+ int w_charsets[4]; /* Font = charsets[Charset] */
+ int w_ss;
+ int w_saved;
+ int w_Saved_x, w_Saved_y;
+ struct mchar w_SavedRend;
+ int w_SavedCharset;
+ int w_SavedCharsetR;
+ int w_SavedCharsets[4];
+ int w_top, w_bot; /* scrollregion */
+ int w_wrap; /* autowrap */
+ int w_origin; /* origin mode */
+ int w_insert; /* window is in insert mode */
+ int w_keypad; /* keypad mode */
+ int w_cursorkeys; /* appl. cursorkeys mode */
+ int w_revvid; /* reverse video */
+ int w_curinv; /* cursor invisible */
+ int w_curvvis; /* cursor very visible */
+ int w_autolf; /* automatic linefeed */
+ char *w_hstatus; /* hardstatus line */
+#ifdef COPY_PASTE
+ char *w_pastebuf; /* this gets pasted in the window */
+ char *w_pasteptr; /* pointer in pastebuf */
+ int w_pastelen; /* bytes left to paste */
+ int w_histheight; /* all histbases are malloced with width * histheight */
+ int w_histidx; /* 0 <= histidx < histheight; where we insert lines */
+ struct mline *w_hlines; /* history buffer */
+#else
+ int w_histheight; /* always 0 */
+#endif
+ enum state_t w_state; /* parser state */
+ enum string_t w_StringType;
+ int w_gr; /* enable GR flag */
+ int w_c1; /* enable C1 flag */
+#ifdef KANJI
+ int w_kanji; /* for input and paste */
+ int w_mbcs; /* saved char for multibytes charset */
+#endif
+ char w_string[MAXSTR];
+ char *w_stringp;
+ char *w_tabs; /* line with tabs */
+ int w_bell; /* bell status of this window */
+ int w_flow; /* flow flags */
+ FILE *w_logfp; /* log to file */
+ int w_monitor; /* monitor status */
+ struct lastio_s
+ {
+ time_t lastio; /* timestamp of last filedescriptor activity */
+ int seconds; /* tell us when lastio + seconds < time() */
+ } w_tstamp;
+ char w_norefresh; /* dont redisplay when switching to that win */
+ char w_wlock; /* WLOCK_AUTO, WLOCK_OFF, WLOCK_ON */
+ struct user *w_wlockuser; /* NULL when unlocked or user who writes */
+#ifdef MULTIUSER
+ AclBits w_userbits[ACL_BITS_PER_WIN];
+#endif
+};
+
+/* definitions for wlocktype */
+#define WLOCK_OFF 0 /* all who are in w_userbits can write */
+#define WLOCK_AUTO 1 /* who selects first, can write */
+#define WLOCK_ON 2 /* w_wlockuser writes even if deselected */
+
+/*
+ * Definitions for flow
+ * 000 -(-)
+ * 001 +(-)
+ * 010 -(+)
+ * 011 +(+)
+ * 100 -(a)
+ * 111 +(a)
+ */
+#define FLOW_NOW (1<<0)
+#define FLOW_AUTO (1<<1)
+#define FLOW_AUTOFLAG (1<<2)
+
+
+/*
+ * WIN gives us a reference to line y of the *whole* image
+ * where line 0 is the oldest line in our history.
+ * y must be in whole image coordinate system, not in display.
+ */
+
+#define WIN(y) ((y < fore->w_histheight) ? \
+ &fore->w_hlines[(fore->w_histidx + y) % fore->w_histheight] \
+ : &fore->w_mlines[y - fore->w_histheight])