diff options
author | Axel Beckert <abe@deuxchevaux.org> | 2011-09-03 14:05:19 +0200 |
---|---|---|
committer | Axel Beckert <abe@deuxchevaux.org> | 2011-09-03 14:05:19 +0200 |
commit | 0636e9ecb5a32db4d4520f50a20652faa825feaf (patch) | |
tree | b94df9221e8ae0de0dc3afac301d5b63b136a7b4 | |
download | screen-upstream/3.7.2.tar.gz |
Imported Upstream version 3.7.2upstream/3.7.2
-rw-r--r-- | COPYING | 339 | ||||
-rw-r--r-- | ChangeLog | 409 | ||||
-rw-r--r-- | FAQ | 253 | ||||
-rw-r--r-- | INSTALL | 110 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | Makefile.in | 253 | ||||
-rw-r--r-- | NEWS | 80 | ||||
-rw-r--r-- | NEWS.3.5 | 119 | ||||
-rw-r--r-- | NEWS.3.6 | 48 | ||||
-rw-r--r-- | README | 102 | ||||
-rw-r--r-- | acls.c | 545 | ||||
-rw-r--r-- | acls.h | 89 | ||||
-rw-r--r-- | ansi.c | 2511 | ||||
-rw-r--r-- | ansi.h | 116 | ||||
-rw-r--r-- | attacher.c | 815 | ||||
-rw-r--r-- | comm.c | 223 | ||||
-rw-r--r-- | comm.h.dist | 177 | ||||
-rw-r--r-- | comm.sh | 77 | ||||
-rw-r--r-- | config.h.in | 466 | ||||
-rwxr-xr-x | configure | 3257 | ||||
-rw-r--r-- | configure.in | 1033 | ||||
-rw-r--r-- | display.c | 1937 | ||||
-rw-r--r-- | display.h | 222 | ||||
-rw-r--r-- | doc/FAQ | 253 | ||||
-rw-r--r-- | doc/Makefile.in | 54 | ||||
-rw-r--r-- | doc/fdpat.ps | 6501 | ||||
-rwxr-xr-x | doc/install.sh | 119 | ||||
-rw-r--r-- | doc/screen.1 | 3349 | ||||
-rw-r--r-- | doc/screen.info | 167 | ||||
-rw-r--r-- | doc/screen.info-1 | 1514 | ||||
-rw-r--r-- | doc/screen.info-2 | 1255 | ||||
-rw-r--r-- | doc/screen.info-3 | 1381 | ||||
-rw-r--r-- | doc/screen.info-4 | 375 | ||||
-rw-r--r-- | doc/screen.texinfo | 4061 | ||||
-rw-r--r-- | etc/etcscreenrc | 95 | ||||
-rwxr-xr-x | etc/mkinstalldirs | 35 | ||||
-rwxr-xr-x | etc/newsyntax | 64 | ||||
-rw-r--r-- | etc/screenrc | 124 | ||||
-rwxr-xr-x | etc/toolcheck | 44 | ||||
-rw-r--r-- | extern.h | 315 | ||||
-rw-r--r-- | fileio.c | 760 | ||||
-rw-r--r-- | help.c | 857 | ||||
-rw-r--r-- | image.h | 106 | ||||
-rw-r--r-- | input.c | 291 | ||||
-rwxr-xr-x | install.sh | 119 | ||||
-rw-r--r-- | kmapdef.c.dist | 130 | ||||
-rw-r--r-- | loadav.c | 249 | ||||
-rw-r--r-- | mark.c | 1320 | ||||
-rw-r--r-- | mark.h | 47 | ||||
-rw-r--r-- | misc.c | 468 | ||||
-rw-r--r-- | os.h | 480 | ||||
-rw-r--r-- | osdef.h.in | 182 | ||||
-rw-r--r-- | osdef.sh | 46 | ||||
-rw-r--r-- | overlay.h | 68 | ||||
-rw-r--r-- | patchlevel.h | 237 | ||||
-rw-r--r-- | process.c | 3777 | ||||
-rw-r--r-- | pty.c | 331 | ||||
-rw-r--r-- | putenv.c | 213 | ||||
-rw-r--r-- | rcs.h | 46 | ||||
-rw-r--r-- | resize.c | 750 | ||||
-rw-r--r-- | screen.c | 2605 | ||||
-rw-r--r-- | screen.h | 251 | ||||
-rw-r--r-- | search.c | 336 | ||||
-rw-r--r-- | socket.c | 1190 | ||||
-rw-r--r-- | tek.patch | 79 | ||||
-rw-r--r-- | term.c | 257 | ||||
-rw-r--r-- | term.h.dist | 237 | ||||
-rw-r--r-- | term.sh | 166 | ||||
-rw-r--r-- | termcap.c | 1272 | ||||
-rw-r--r-- | terminfo/8bits | 17 | ||||
-rw-r--r-- | terminfo/README | 19 | ||||
-rw-r--r-- | terminfo/checktc.c | 204 | ||||
-rw-r--r-- | terminfo/sco.mail | 65 | ||||
-rw-r--r-- | terminfo/screencap | 21 | ||||
-rw-r--r-- | terminfo/screeninfo.src | 48 | ||||
-rw-r--r-- | terminfo/test.txt | 603 | ||||
-rw-r--r-- | terminfo/tetris.c | 20 | ||||
-rw-r--r-- | tty.c.dist | 1025 | ||||
-rw-r--r-- | tty.sh | 862 | ||||
-rw-r--r-- | utmp.c | 800 | ||||
-rw-r--r-- | window.c | 1118 | ||||
-rw-r--r-- | window.h | 233 |
82 files changed, 54794 insertions, 0 deletions
@@ -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. @@ -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 @@ -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 @@ -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. + @@ -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. + @@ -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 */ @@ -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; + @@ -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 + @@ -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 */ @@ -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 @@ -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) + @@ -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='[0000mk\% ' + + The escape-sequence `[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: + + 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 +} @@ -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 @@ -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) + @@ -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 */ @@ -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 */ @@ -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) + @@ -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 + @@ -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); +} @@ -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 */ + @@ -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: + +===================================================================== @@ -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 @@ -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 @@ + +<[H[J(A)0[?4h[?5l[m + + + + + + + + + + lqqqqqqqqqwwwqqqqqqqqqk sssssssssssssssssssssssssssss + x[1mMerry Chr[mx[1mx[mx[1mmas * Mer[mx \ / + xry Christx[1mx[mx * Merry x pr rp + x[1mChristmas[mx[1mx[mx[1mMerry Chr[mx oqrs srqo + xistmas * x[1mx[mxry Christx ooppqqwqwqqppoo + tqqqqqqqqqj[1mx[mmqqqqqqqqqu x x + t[1mqqqqqqqqqq`qqqqqqqqqq[mu x x + tqqqqqqqqqk[1mx[mlqqqqqqqqqu x x + xry Christx[1mx[mx * Merry x x x + x[1mChristmas[mx[1mx[mx[1mMerry Chr[mx x x + xistmas * x[1mx[mxry Christx x x + x[1mmas * Mer[mx[1mx[mx[1mChristmas[mx srqqj mqqrs + mqqqqqqqqqvvvqqqqqqqqqj [4m rqpo opqr [m[1;10r +[5;79Hl[8;79Hm[6;79Hx[7;79Hx +[5;78Hlq[8;78Hmq[6;78Hx [7;78Hx +[5;77Hlqw[8;77Hmqv[6;77Hx x[7;77Hx x +[5;76Hlqwq[8;76Hmqvq[6;76Hx x [7;76Hx x +[5;75Hlqwq[8;75Hmqvq[6;75Hx x [7;75Hx x +[5;74Hlqwq[8;74Hmqvq[6;74Hx x [7;74Hx x +[5;73Hlqwq[8;73Hmqvq[6;73Hx x [7;73Hx x +[5;72Hlqwq[8;72Hmqvq[6;72Hx x [7;72Hx x +[5;71Hlqwq[8;71Hmqvq[6;71Hx x [7;71Hx x +[5;70Hlqwq[8;70Hmqvq[6;70Hx x [7;70Hx x +[8;69H/[7;69H/ +[9;69H/[8;68H/ +[10;69H/[9;68H[1m/[m [8;68H /[7;69H [6;69H/ +[11;69H[1;4m/[m[10;68H/ [9;68H [1m/[m[8;68H /[7;68H[1m/[m/ +[12;69H[1m/[m[11;68H[1;4m/ [m[10;68H /[9;69H[1m/[m[8;68H/[7;68H[1m/[m +[13;69H/[12;68H/ [11;68H[4m /[m[10;69H[1m/[m[9;68H[1m/[m/[7;68H /[6;69H[1m/[m +[13;68H[1m/[m [12;68H [1m/[m[10;68H//[9;68H/[8;68H [7;68H[1m/[m [6;69H/ +[13;68H /[11;68H[4m/[m[9;68H [8;68H/ [7;68H//[6;69H +[13;68H/[12;68H[1m/[m[10;68H [9;68H[1m/[m [8;68H/[1m/[m[7;68H [6;69H[1m/[m +[13;68H[1m/[m[12;68H/[11;68Hs[10;68H[1m/[m [9;68H//[8;69H [6;69H +[14;53Hsssssssssss +[13;68H/[12;68H [11;68H[1;4m/ [m[10;68H//[9;69H [8;68H [1m/[m[7;68H/ [6;69H[1m/[m +[14;52Hs[14;64Hs +[13;68H [12;68H/ [11;68H[4m/[1m/[m[10;69H [9;68H /[8;68H/ [7;68H [1m/[m[6;69H/ +[14;53Hrrrrrrrrrrr +[13;68H[1m/[m [12;69H/[11;69Hs[10;68H [1m/[m[9;68H[1m/[m [8;68H /[7;69H/ +[14;54Hqqqqqqqqq +[13;68H/[1m/[m[12;69H [11;68H[4m /[m[10;68H/ [9;68H /[7;68H[1m/[m +[14;52Hsrqqqqqqqqqrs +[13;69H [12;68H [1m/[m[11;68H[4m/ [m[10;68H [1m/[m[8;68H[1m/[m[7;68H/ +[14;51Hsr[14;64Hrs +[13;69H/[12;68H/ [11;68H[4m /[m[10;69H[1m/[m[9;68H[1m/[m/[7;68H /[6;69H[1m/[m +[14;51Hrrqq[14;62Hqqrr +[13;68H[1m/[m [12;68H [1m/[m[10;68H//[9;68H/[8;68H [7;68H[1m/[m [6;69H/ +[14;55Hppppppp +[13;68H /[11;68H[4m/[m[9;68H [8;68H/ [7;68H//[6;69H +[14;51Hrrq[14;63Hqrr +[13;68H/[12;68H[1m/[m[10;68H [9;68H[1m/[m [8;68H/[1m/[m[7;68H [6;69H[1m/[m +[14;51Hrqpp[14;62Hppqr +[13;68H[1m/[m[12;68H/[11;68Hs[10;68H[1m/[m [9;68H//[8;69H [6;69H + +[14;50H[4mr[mqpppooooooopppq[4mr[m +[13;68H/[12;68H [11;68H[1;4m/ [m[10;68H//[9;69H [8;68H [1m/[m[7;68H/ [6;69H[1m/[m +[14;50H[4mq[mppooooooooooopp[4mq[m +[13;68H [12;68H/ [11;68H[4m/[1m/[m[10;69H [9;68H /[8;68H/ [7;68H [1m/[m[6;69H/ + + + +[13;55Hsssssss[14;52Hooo ooo[14;57H. o f + +[13;68H[1m/[m [12;69H/[11;69Hs[10;68H [1m/[m[9;68H[1m/[m [8;68H /[7;69H/[14;56H.f + +[13;53Hss[13;62Hss[14;53H .f + +[13;68H/[1m/[m[12;69H [11;68H[4m /[m[10;68H/ [9;68H /[7;68H[1m/[m[14;53H f + +[13;48Hssssrrrrqqqqqrrrrssss[14;50Hs s + +[13;69H [12;68H [1m/[m[11;68H[4m/ [m[10;68H [1m/[m[8;68H[1m/[m[7;68H/[14;51H. . . + +[13;47Hsssrrrrqqqqqqqqqrrrrsss[14;51Hf f . f + +[13;69H[4m/[m[12;68H/ [11;68H[4m /[m[10;69H[1m/[m[9;68H[1m/[m/[7;68H /[6;69H[14;51H f . + +[13;47Hrrrqqqqpppppppppqqqqrss[14;52H. . o f + +[13;68H[1;4m/[m [12;68H [1m/[m[10;68H//[9;68H/[8;68H [7;68H[1m/[m [6;69H/[14;52Hf .f + +[13;47Hqqqppppooooooooopppqrss[14;52H .f . + +[13;68Hs/[11;68H[4m/[m[9;68H [8;68H/ [7;68H//[6;69H [14;55Hf f + +[12;54Hsssssssss[13;47Hqppoooo oopqrss[13;54H.o .[14;55H + +[13;68H[4m/[m[12;68H[1m/[m[10;68H [9;68H[1m/[m [8;68H/[1m/[m[7;68H [6;69H[1m/[m[13;54Hf f[14;51H. . + +[12;52Hssrrrrrrrrrs[13;47Hqpooo opqrss[13;53Hf [14;51Hf f . f + +[13;68H[1;4m/[m[12;68H/[11;68Hs[10;68H[1m/[m [9;68H//[8;69H [13;53Hf o o[14;51H f . + +[12;46Hssssssrr[12;63Hrrssssss[13;47H [13;64H [6;69H [13;47Hf o o .[14;52H. . o f + +[12;68Hs[11;68H[4m/ [m[10;68H//[9;69H [8;68H [1m/[m[7;69H [13;47H . o o f[14;52Hf .f + +[12;45Hsrrrrrrqqqqqqqqqqqqqqrrssrq[13;49Hf o o . [14;52H .f . + +[12;68H[4m/ [11;68H/[1m/[m[10;69H [9;68H /[8;69H mqvqqqqqq[5;70H lqwqqqqqq[7;70H x x[6;70H x x[13;49H . o f + +[12;45Hrqqqqqqppppppppppppppq[8;71H mqvqqqqq[5;71H lqwqqqqq[7;71H x x[6;71H x x[13;50Hf .o . o[14;55H + +[12;69H[4m/[m[11;69Hs[10;68H [1m/[m[9;69H [8;72H mqvqqqq[5;72H lqwqqqq[7;72H x x[6;72H x x[13;50H f f [14;51 + +[12;45Hqppppppoooooooooooooo[8;73H mqvqqq[5;73H lqwqqq[7;73H x x[6;73H x x[13;53Hf [13;62H .[14;51Hf f . f + +[12;69Hs[11;68H[4m /[m[10;69H [8;74H mqvqq[5;74H lqwqq[7;74H x x[6;74H x x[13;47H. o f o o f[14;51H f + +[12;45Hpoooooo [8;75H mqvq[5;75H lqwq[7;75H x x[6;75H x x[12;49H o o o[13;47Hf o o . + +[11;44H[4mrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[m[12;45H [12;64H [8;76H mqv[5;76H lqw[7;76H x x[6;76H x x[12;47Ho +[8;77H mq[5;77H lq[7;77H x [6;77H x [12;47H . o o o[13;49Hf o o . [14;52H .f . +[8;78H m[5;78H l[7;78H x[6;78H x[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[8;79H [5;79H [7;79H [6;79H [12;45Hf o o f . f[13;50Hf .o . o[14;55H +[1;7m[5;25H#3 Cheers! +[6;25H#4 Cheers! [m + +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H + +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H + +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H + +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H + +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H + +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H + +[12;45H . o o . o f [13;50H f f [14;51H. . . +[5;1H[K#5 +[6;1H[K#5 +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[10;1H /ooooooooooooooo\ +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[10;1H / sss sss \ +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[10;1H x ([4msOs[m) ([4msOs[m) x +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[10;1H x ` x +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[10;1H \ \sssssssss/ / +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[10;1H \ / +[12;45H . o o . o f [13;50H f f [14;51H. . . +[10;1H \sssssssssss/ +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[10;1H ooppqqrrsss +[12;47H f f f [13;47H. o f o o f[14;51H f . +[10;1H ooppqqrrsss +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[10;1H ooppqqrrsss +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[10;1H ooppqqrrsss +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[10;1H ooppqqrrsss +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[10;1H ooppqqrrsss +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[10;1H ooppqqrrsss[12;45H . o o . o f [13;50H f f [14;51H. . . +[HM x ` x +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[HM x ([4msOs[m) ([4msOs[m) x +[12;47H f f f [13;47H. o f o o f[14;51H f . +[HM / sss sss \ +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[HM /ooooooooooooooo\ +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[HM +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[HM +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[HM +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[HM +[12;45H . o o . o f [13;50H f f [14;51H. . . +[10;1H \ / +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[10;1H \sssssssssss/ +[12;47H f f f [13;47H. o f o o f[14;51H f . +[10;1H ooppqqrrsss +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[10;1H ooppqqrrsss +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[10;1H ooppqqrrsss +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[10;1H ooppqqrrsss +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[10;1H ooppqqrrsss[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[HM / sss sss \ +[12;45H . o o . o f [13;50H f f [14;51H. . . +[HM /ooooooooooooooo\ +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[HM +[12;47H f f f [13;47H. o f o o f[14;51H f . +[HM +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[10;1H ooppqqrrsss +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[10;1H ooppqqrrsss +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[10;1H ooppqqrrsss +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[10;1H ooppqqrrsss[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[HM /ooooooooooooooo\ +[12;45H . o o . o f [13;50H f f [14;51H. . . +[HM +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[HM +[12;47H f f f [13;47H. o f o o f[14;51H f . +[HM +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[10;1H \sssssssssss/ +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[10;1H ooppqqrrsss +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[10;1H ooppqqrrsss[r +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H + +[4;45HJin +[12;45H . o o . o f [13;50H f f [14;51H. . . +[4;48Hgle +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[4;52HBells, +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[4;59HJin +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[4;62Hgle +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[4;66HBells, +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[5;45HJin +[12;47H f f f [13;47H. o f o o f[14;51H f . +[5;48Hgle +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[5;52Hall +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[5;56Hthe +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[5;60Hway, +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[6;45HOh! +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[6;50HWhat +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[6;55Hfun +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[6;59Hit +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[6;62His +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[6;65Hto +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[6;68Hride, +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[7;45HOn +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[7;48Ha +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[7;50Hone- +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[7;54Hhorse +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[7;60Hop +[12;47H f f f [13;47H. o f o o f[14;51H f . +[7;62Hen +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[7;65Hsleigh. +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf f + +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf f + +[12;47H o o o[13;49Hf o o [14;52H +[12;45H. o o o [13;49H [14;55H +[12;45Hf o o [13;50H [14;55H +[12;45H +[12;47Ho o o[13;47H . o o f[14;52Hf f + +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf f + +[12;47H o o o[13;49Hf o o [14;52H +[12;45H. o o o [13;49H [14;55H +[12;45Hf o o [13;50H [14;55H +[12;45H + +[4;45H[K[4;55HMerry Christmas +[5;45H[K +[6;45H[K[6;60H- +[7;45H[K +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf f + +[12;47H o o o[13;49Hf o o [14;52H +[12;45H. o o o [13;49H [14;55H +[12;45Hf o o [13;50H [14;55H +[12;45H +[12;47Ho o o[13;47H . o o f[14;52Hf f + +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf .f +[12;47H . o o o[13;49Hf o o . [14;52H .f . +[12;45H. o o f o . .[13;49H . o f[14;55Hf f +[12;45Hf o o f . f[13;50Hf .o . o[14;55H +[12;45H . o o . o f [13;50H f f [14;51H. . . +[12;47Hf . o . f o f[13;53Hf [13;62H .[14;51Hf f . f +[12;47H f f f [13;47H. o f o o f[14;51H f . +[12;49H o o o[13;47Hf o o .[14;52H. . o f +[12;47Ho o o[13;47H . o o f[14;52Hf f + +[12;47H o o o[13;49Hf o o [14;52H +[12;45H. o o o [13;49H [14;55H +[12;45Hf o o [13;50H [14;55H +[12;45H +[22;1H[?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 */ @@ -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 */ @@ -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]) |