summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:28:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:28:28 +0000
commit5a5e2352c9a01f9076994915188c26c6b9036202 (patch)
tree1e1474b8b914d161946c01ba26a56db68b1fd5d3
parentInitial commit. (diff)
downloadscreen-upstream.tar.xz
screen-upstream.zip
Adding upstream version 4.9.0.upstream/4.9.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--.gitignore21
-rw-r--r--.iscreenrc169
-rw-r--r--COPYING674
-rw-r--r--ChangeLog619
l---------FAQ1
-rw-r--r--HACKING39
-rw-r--r--INSTALL114
-rw-r--r--Makefile.in356
-rw-r--r--NEWS28
-rw-r--r--NEWS.3.5119
-rw-r--r--NEWS.3.648
-rw-r--r--NEWS.3.739
-rw-r--r--NEWS.3.9205
-rw-r--r--README102
-rw-r--r--TODO7
-rw-r--r--acconfig.h579
-rw-r--r--acls.c1147
-rw-r--r--acls.h98
-rw-r--r--ansi.c3207
-rw-r--r--ansi.h175
-rw-r--r--attacher.c1117
-rwxr-xr-xautogen.sh2
-rw-r--r--braille.c945
-rw-r--r--braille.h83
-rw-r--r--braille_tsi.c314
-rw-r--r--canvas.c918
-rw-r--r--canvas.h101
-rw-r--r--comm.c348
-rw-r--r--comm.sh96
-rw-r--r--configure.ac1315
-rw-r--r--display.c4082
-rw-r--r--display.h338
-rw-r--r--doc/.gitignore2
-rw-r--r--doc/FAQ253
-rw-r--r--doc/Makefile.in62
-rw-r--r--doc/README.DOTSCREEN151
-rw-r--r--doc/fdpat.ps6501
l---------doc/install.sh1
-rw-r--r--doc/make.help51
-rw-r--r--doc/screen.15402
-rw-r--r--doc/screen.texinfo6102
-rw-r--r--doc/window_to_display.ps2959
-rw-r--r--encoding.c2144
-rwxr-xr-xetc/ccdefs46
-rw-r--r--etc/completer.zsh53
-rwxr-xr-xetc/countmail67
-rw-r--r--etc/etcscreenrc94
-rw-r--r--etc/gr-braille.tbl260
-rw-r--r--etc/gs-braille.tbl261
-rwxr-xr-xetc/mkinstalldirs35
-rwxr-xr-xetc/newsyntax64
-rwxr-xr-xetc/newsyntax3871
-rw-r--r--etc/screenrc153
-rwxr-xr-xetc/toolcheck44
-rw-r--r--etc/us-braille.tbl260
-rw-r--r--extern.h514
-rw-r--r--fileio.c788
-rw-r--r--help.c936
-rw-r--r--image.h189
-rw-r--r--input.c528
-rwxr-xr-xinstall.sh119
-rw-r--r--layer.c1247
-rw-r--r--layer.h163
-rw-r--r--layout.c350
-rw-r--r--layout.h63
-rw-r--r--list_display.c245
-rw-r--r--list_generic.c486
-rw-r--r--list_generic.h73
-rw-r--r--list_window.c708
-rw-r--r--loadav.c396
-rw-r--r--logfile.c251
-rw-r--r--logfile.h87
-rw-r--r--mark.c1449
-rw-r--r--mark.h58
-rw-r--r--misc.c798
-rw-r--r--nethack.c138
-rw-r--r--os.h529
-rw-r--r--osdef.h.in202
-rw-r--r--osdef.sh69
-rw-r--r--patchlevel.h538
-rw-r--r--process.c7414
-rw-r--r--pty.c425
-rw-r--r--putenv.c216
-rw-r--r--resize.c1133
-rw-r--r--sched.c272
-rw-r--r--sched.h48
-rw-r--r--screen.c3448
-rw-r--r--screen.h316
-rw-r--r--search.c383
-rw-r--r--socket.c1939
-rw-r--r--teln.c578
-rw-r--r--term.c298
-rw-r--r--term.sh169
-rw-r--r--termcap.c1545
-rw-r--r--terminfo/8bits17
-rw-r--r--terminfo/README20
-rw-r--r--terminfo/checktc.c204
-rw-r--r--terminfo/screencap23
-rw-r--r--terminfo/screeninfo.src80
-rw-r--r--terminfo/test.txt603
-rw-r--r--terminfo/tetris.c20
-rw-r--r--tty.sh1569
-rw-r--r--utf8encodings/01bin0 -> 29808 bytes
-rw-r--r--utf8encodings/02bin0 -> 27550 bytes
-rw-r--r--utf8encodings/03bin0 -> 32926 bytes
-rw-r--r--utf8encodings/04bin0 -> 24302 bytes
-rw-r--r--utf8encodings/18bin0 -> 54862 bytes
-rw-r--r--utf8encodings/19bin0 -> 95776 bytes
-rw-r--r--utf8encodings/a1bin0 -> 536 bytes
-rw-r--r--utf8encodings/bfbin0 -> 232 bytes
-rw-r--r--utf8encodings/c2bin0 -> 256 bytes
-rw-r--r--utf8encodings/c3bin0 -> 140 bytes
-rw-r--r--utf8encodings/c4bin0 -> 228 bytes
-rw-r--r--utf8encodings/c6bin0 -> 68 bytes
-rw-r--r--utf8encodings/c7bin0 -> 52 bytes
-rw-r--r--utf8encodings/c8bin0 -> 40 bytes
-rw-r--r--utf8encodings/ccbin0 -> 68 bytes
-rw-r--r--utf8encodings/cdbin0 -> 52 bytes
-rw-r--r--utf8encodings/d6bin0 -> 212 bytes
-rw-r--r--utmp.c893
-rw-r--r--viewport.c129
-rw-r--r--viewport.h51
-rw-r--r--window.c2359
-rw-r--r--window.h357
124 files changed, 77875 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..529960c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,21 @@
+*.o
+.*.swp
+\#*\#
+*~
+Makefile
+autom4te.cache
+cscope.out
+TAGS
+tags
+comm.h
+config.h
+config.h.in
+config.log
+config.status
+configure
+kmapdef.c
+osdef.h
+term.h
+screen
+stamp-h.in
+tty.c
diff --git a/.iscreenrc b/.iscreenrc
new file mode 100644
index 0000000..7a937f9
--- /dev/null
+++ b/.iscreenrc
@@ -0,0 +1,169 @@
+#
+# A sample .screenrc which I use for everyday work.
+#
+# some of the commands commented out here, have been moved to
+# /local/etc/screenrc
+#
+# we want no password, right?
+#password # This will ask us for a password.
+password none # Same as not even mentioning it.
+#password 12Bz/9hNlPLZk # "1234"
+#password YahtrWblnJw # ypmatch jnweiger passwd. Well, ... :-)
+
+scrollback 200 # we have a 200 lines history buffer
+markkeys "@=\177:@=^C" # our mad facit-twist terminal buffer overflow...
+markkeys "h=^B:l=^F:\$=^E" # some missing emacs style bindings in copymode
+
+echo -n "booting screen"
+
+# let it flash, not horn!
+#vbell on # "vbell" doesn't work any longer, sorry.
+#vbell_msg " Wuff, Wuff!! " # this is the default message
+#bell "Bimmmel No. %" # sounds the bell and shows a message
+
+# we want to login all windows we create.
+#login on # "login", "nologin" don't work any longer, sorry 2.
+
+echo -n "."
+# we have no termcap entry for screen on the target machine? Well then
+# we tell a lie.
+term screen # would be the obvious default here.
+#term vt100 # screen will understand vt100 for 99%.
+
+# we want to survive hangups
+# note that the default setting is off now!
+autodetach on
+
+# when we open a window, where shall its CWD be?
+chdir # without argument it's my $HOME
+
+echo -n "."
+# I hate nonexisting status lines! Force screen to believe me.
+#hardstatus off
+
+# now some Terminal setup:
+# Printing in the leftmost column is not save. We express that fact as :LP@:
+#
+# Emacs tends to smear it's highlighted status bar across the screen, producing
+# ugly areas of bright background, if termcap isn't perfectly sober.
+# Give a little :ms@: in the termcap, this may help.
+#
+# And who invented the initialisation for facit terminals? We tell him that
+# we don't like smooth scroll, by specifying :ti=\E[?l:.
+# \E[?3l 80 Zeichen
+# \E[?3h 132 Zeichen
+# LP Last column Printable
+# \E[A cursor up
+# \E[B cursor down
+# \E[?4h smooth scroll
+# \E[?4l jump scroll
+# \E[%dL insert %d lines
+# \E[K clear to end of line
+# cs \E[%i%d;%dr for twist and xterm
+# ms@ Move in Standout mode is NOT save.
+# WS our private variable, it declares that the terminal can
+# be resized by an escape-sequence
+# The termcap statement takes 2 or three parameters. First parameter lists
+# which TERMCAPs are affected by this statement. Second we specify changes
+# in screen's view of that terminals. Third we may specify some capabilities
+# that user-programs want to see in the $TERMCAP environment variable or in
+# screen's termcap entry.
+termcap vt* cl=\E[H\E[J\E[?1h:vi=\E[?35h:ve=\E[35l:ti=\E[?4l[vt100]
+termcap facit ti=\E[?4l[facit]
+termcap xterm* is=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;4;6l:Z0=\E[?3h:Z1=\E[?3l
+
+echo -n "."
+# "\E(B", "\E(0", "\E(1", "\E(2", ... to switch between charsets.
+# screen internally emulates G1: "\E)..", G2: "\E*..", G3: "\E+.."
+# you can switch between them, with:
+#
+# code | switch to
+# ------+------
+# ^O | G0
+# ^N | G1
+# \En | G2
+# \Eo | G3
+#termcap facit|vt100|xterm* G0
+
+# how do we resize windows? under sunview, this is standard, but xterm
+# needs to be a specially hacked xterm, to make this work.
+termcap xterm* WS=\E[8;%d;%dt
+
+# ICL 6402 testing:
+termcap icl* G0:S0=\E$[start]:E0=\E%[end]:C0=j9k<l6m3n?q\:t7u=v;w>x5 GS=\E(0^O:GE=\E(B^O:G1=k:G2=l:G3=m:G4=j:GV=x:GH=q:GR=u:GL=t:GU=w:GD=v:GC=n
+
+# Flow control produces trouble. ^S und ^Q will never reach screen, as our
+# terminals catch them locally. Who can explain that to me?:
+#flow on|off|auto [interrupt]
+
+# Long lines get wrapped around (the back of your terminal). This is the
+# default for vt100. But now programs make different asumptions about your
+# terminal. You may find two linefeeds where you'd expect one, or you may
+# be confronted with a truncated line. Currently there is no fix, but pressing
+# C-A r and doing a redraw.
+#wrap on
+
+# the autoaka allows you to see the currently executing shell command in the
+# window name field. To use that, your shell prompt must contain ^[k^[\ or
+# you will see the string "(init)" as a name.
+# in my .cshrc I may use this for a wonderful tcsh-prompt:
+# set prompt="%{^[k^[\\%}%h %c2(%m)%# "
+#
+# defining a shellaka that contains a pipe-symbol (|) activates the
+# autoaka feature. To the left of that | you specify a constant part of
+# your prompt as a trigger, to the right you may place a default string
+# as in
+shellaka '> |tc'
+# but beware! specifying a window name with the -t option has priority over
+# the autoaka mechanism. Although specifying -t "> |foo" will work.
+# shellaka tc
+
+# ... now a little bit of key bindings
+# In case we don't have write permission for /etc/utmp (no s-bit)
+# we create even local windows via rlogin. -> Et voila: a utmp-slot
+# utmp-slots are strongly recommended to keep sccs and talk happy.
+# (thus we have ^A# or. ^Ac for window creation with or without utmp-slot.)
+# but if we run suid-root, we produce all the rlogins with -ln,
+# as nobody shall refer to these pty's.
+bind '!' screen -ln -k faui41 rlogin faui41
+bind '@' screen -ln -k vme2 rlogin faui4_vme2
+#bind '#' screen -k faui43
+bind '#' screen -ln -k faui43 rlogin faui43
+bind '$' screen -ln -k faui44 rlogin faui44
+bind '%' screen -ln -k faui45 rlogin faui45
+bind '\^' screen -ln -k sup1 rlogin fausup1
+bind '&' screen -ln -k sup2 rlogin fausup2
+bind '*' screen -ln -k faui48 rlogin faui48
+bind '(' screen -ln -k faui09 rlogin faui09
+bind ')' screen -ln -k faui10 rlogin faui10
+bind 'J' screen -ln -k 4j rlogin faui4j
+bind 'P' screen -ln -k 4p rlogin faui4p
+bind '^C' screen -ln -k 45c rlogin faui45c
+bind '^D' screen -ln -k 45d rlogin faui45d
+bind '^E' screen -ln -k 45e rlogin faui45e
+bind '^I' screen -ln -k 45i rlogin faui45i
+
+# these two are logIn and logOut. As a toggle is too stupid.
+#bind 'I' set login on
+#bind 'O' set login off
+bind 'L'
+
+# What happens, when you 'think emacs' and want to erase a whole
+# line? You type ^A^K right? Under screen it should be ^Aa^K. But...
+# killing the window would be a real punishment for a little mistyping.
+bind k #wow! I even mange to type ^Ak by accident.
+#bind ^k
+#bind K kill
+
+echo -n "."
+#screen 1:faui43 # My good old <nr>:<alias> syntax
+#screen -k faui43 # The way Wayne Davison thinks about it.
+#screen -ln -k faui43 # this one not logged in.
+#screen -ln 2:faui09 rlogin faui09 -l jnweiger
+
+# Finally another bonus feature for people using strange terminal settings like
+# different baud rate, etc. The next user will get standard settings
+# as ^[c is a reset sequence.
+#pow_detach_msg "" # is the default
+pow_detach_msg "c"
+echo "done."
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. 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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. 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.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ 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.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ 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
+state 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) <year> <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 3 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, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU 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 Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..cf08d53
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,619 @@
+Version 4.9.0 (30/01/2022):
+ * Hardstatus option for used encoding (escape string '%e')
+ * OpenBSD uses native openpty() from its utils.h
+ * Fixes:
+ - fix combining char handling that could lead to a segfault
+ - CVE-2021-26937: possible denial of service via a crafted UTF-8 character sequence (bug #60030)
+ - make screen exit code be 0 when checking --help
+ - session names limit is 80 symbols (bug #61534)
+ - option -X ignores specified user in multiuser env (bug #37437)
+ - a lot of reformations/fixes/cleanups (man page and source code)
+
+Version 4.8.0 (05/02/2020):
+ * Improve startup time by only polling for files to close
+ * Fixes:
+ - Fix for segfault if termcap doesn't have Km entry
+ - Make screen exit code be 0 when checking --version
+ - Fix potential memory corruption when using OSC 49
+
+Version 4.7.0 (02/10/2019):
+ * Add support for SGR (1006) mouse mode
+ * Add support for OSC 11
+ * Update Unicode ambiguous and wide tables to 12.1.0
+ * Fixes:
+ - cross-compilation support (bug #43223)
+ - a lot of manpage fixes and cleanups
+
+Version 4.6.2 (23/10/2017):
+ * Fixes:
+ - revert changes to cursor position restore behavour (bug #51832)
+ - set freed pointer to NULL (bug #52133)
+ - documentation fixes
+ - fix windowlist crashes (bug #43054 & #51500)
+
+Version 4.6.1 (10/07/2017):
+ * Fixes:
+ - problems with starting session in some cases
+ - parallel make install
+ - segfault when querying info on nonUTF locale (bug #51402)
+
+Version 4.6.0 (28/06/2017):
+ * Update Unicode wide tables to 9.0 (bug #50044)
+ * Support more serial speeds
+ * Improved namespaces support
+ * Migrate from fifos to sockets
+ * Start viewing scrollback at first line of output (bug #49377)
+
+Version 4.5.1 (25/02/2017):
+ * Fixes:
+ - logfile permissions problem (CVE-2017-5618)
+ - SunOS build problem (bug #50089)
+ - FreeBSD core dumps (bug #50143)
+
+Version 4.5.0 (10/12/2016):
+ * Allow specifying logfile's name via command line parameter '-L'
+ * Fixes:
+ - broken handling of "bind u digraph U+" (bug #48691)
+ - crash with long $TERM (bug #48983)
+ - crash when bumping blank window
+ - build for AIX (bug #49149)
+ - %x improperly separating arguments
+ - install with custom DESTDIR (bug #48370)
+
+Version 4.4.0 (19/06/2016):
+ * Support up to 24 function keys
+ * Fix runtime issues
+ * 'logfile' command, starts logging into new file upon changing
+
+Version 4.3.1 (28/06/2015):
+ * Fix resize bug
+
+Version 4.3.0 (13/06/2015):
+ * Introduce Xx string escape showing the executed command of a window
+ * Implement dead/zombie window polling, allowing for auto reconnecting
+ * Allow setting hardstatus on first line
+ * New Commands:
+ - 'sort' command sorting windows by title
+ - 'bumpleft', 'bumpright' - manually move windows on window list
+ - 'collapse' removing numbering 'gaps' between windows, by renumbering
+ - 'windows' command now accepts arguments for use with querying
+
+Version 4.2.1 (28/04/2014):
+ * allow for terminal with long $TERM (up to 32 characters)
+ * allow to use long logins
+ * documentation fixes
+ * runtime fixes
+
+Version 4.2.0 (17/04/2014):
+ New Commands:
+ * 'unbindall' to unbind all commands
+ * 'up', 'down', 'left', 'right' sub-commands for 'focus'
+ * 'rendition' to specify rendition to use in caption/hardstatus for window-names that have bell/monitor/silence/so turned on.
+ * 'layout', with the following sub-commands
+ - 'title'
+ - 'number'
+ - 'autosave' ('autosave on' or 'autosave off')
+ - 'new'
+ - 'save' ('save <name>')
+ - 'select'
+ - 'next'
+ - 'prev'
+ - 'attach'
+ - 'show'
+ - 'remove'
+ - 'dump'
+ * 'group' for moving window(s) into a group.
+ * 'defmousetrack' and 'mousetrack', to turn on/off mouse-tracking for
+ displays. It's turned off by default. With mouse-tracking turned on, it's
+ possible to switch to a region ('focus') using mouse clicks. It's also
+ possible to select a text region in copy-mode using a mouse click to place
+ a mark and the scroll wheel to scroll through the buffer. Additional
+ features might be to allow clicking on window-titles in the caption to
+ switch to that window.
+ * All commands prefixed '@' are treated as 'quiet', i.e. '@'-prefixed commands
+ do not trigger any display messages.
+
+ Changed Commands:
+ * '-v' parameter to 'split' command for vertical splits.
+ * 'sorendition' deprecated in favour of 'rendition so'.
+ * 'digraph' can take a second parameter to specify custom digraphs. For
+ example,
+ 'digraph >= ≥' or 'digraph >= U+2265'
+ Using '0' as the second parameter will remove the digraph.
+ * 'stuff' will prompt for input if there's nothing to stuff.
+ * The argument to ":number" can be prefixed with '+' or '-' to use it as a
+ relative argument.
+ * '-g' parameter to 'windowlist' to show nested list of windows.
+ * '//group' parameter to 'screen' to create a grouped window.
+ * 'blankerprg' shows the currently set command on no argument.
+ * 'maxwin' can now be used to increase the number of maximum windows.
+
+ .screenrc:
+ * $PID expands to the PID of the screen session.
+ * $PWD expands to the current working directory of the session.
+ * $STY expands to the session name.
+ * Tilde-expansion in pathnames (e.g. for the 'source' command)
+ * C-style escapes can be used (e.g. "\n" to get a newline with 'stuff')
+ * '%p' in caption/hardstatus string expands to the PID of the backend, and
+ '%+p' expands to the PID of the frontend (display).
+ * '%S' in caption/hardstatus string expands to the session name.
+ * '%P' in the caption string evaluates to true if the region is in copy mode.
+ * '%E' in the caption string evaluates to true if the escape character has
+ currently been pressed.
+
+ Window List:
+ * Nested views when there are window groups (with 'windowlist -g').
+ * Press 'm' to toggle the most-recent view.
+ * Press 'g' to toggle nestedness.
+ * Press 'a' to view all windows in the list.
+ * Press '/' to search in the list.
+ * Press ',' and '.' to re-order windows in the list.
+ * Press 'K' to kill a window (requires confirmation).
+
+ Display List:
+ * Press 'd' to detach a display, 'D' to power-detach.
+
+ Others:
+ * Start using 'ChangeLog' for logging changes again.
+ * Terminfo update for 256-color support.
+ * Multiple input history (partially from Romain Francoise).
+ * vi-like fFtT;, searching in copy mode.
+ * In copy mode, search in reverse direction when 'N' is pressed.
+ * Tab-completion for command input.
+ * Some more readline-like bindings in input mode (e.g. ^W, ^D, ^P, ^N etc.)
+ * Fix displaying unicode characters in the caption/hardstatus on UTF8 locale.
+ * A revamped displays list (for 'displays' command)
+ * Increased default maximum number of windows from 40 to 100.
+ * Increased number color/attribute changes in caption/hardstatus string from 16 to 256.
+ * Some commands can be remotely queried using the -Q command-line flag.
+
+ In-Progress:
+ * Scripting support (thanks to Google Summer of Code 2009 project by Rui Guo)
+
+ Developers:
+ * Alexander Naumov <alexander_naumov@opensuse.org>
+ * Amadeusz Sławiński <amade@asmblr.net>
+ * Juergen Weigert <jw@suse.de>
+ * Michael Schroeder <mls@suse.de>
+ * Micah Cowan <micah@cowan.name>
+ * Sadrul Habib Chowdhury <sadrul@users.sourceforge.net>
+
+ Contributors:
+ * Clavelito <maromomo@hotmail.com>
+ * Dick <dick@mrns.nl>
+ * Gabriel <g2p.code@gmail.com>
+ * Benjamin Andresen <bandresen@gmail.com>
+ * Takeshi Banse <takebi@laafc.net>
+ * Maarten Billemont <lhunath@gmail.com>
+ * Curtis Brown <mrbrown8@juno.com>
+ * Cyril Brulebois <kibi@debian.org>
+ * Trent W Buck <trentbuck@gmail.com>
+ * Stephane Chazelas <stephane_chazelas@yahoo.fr>
+ * Kees Cook <kees@ubuntu.com>
+ * Thomas Dickey <tom@invisible-island.net>
+ * Christian Ebert <blacktrash@gmx.net>
+ * Geraint Edwards <gedge-lists-screen@yadn.org>
+ * Romain Francoise <romain@orebokech.com>
+ * Alexander Gattin <xrgtn@yandex.ru>
+ * Emanuele Giaquinta <e.giaquinta@glauco.it>
+ * Yi-Hsuan Hsin <mhsin@mhsin.org>
+ * Kipling Inscore <kinscore@synaptics.com>
+ * Chris Jones <cjns1989@gmail.com>
+ * Max Kalashnikov <mmt@maxkalashnikov.com>
+ * Steve Kemp <steve@steve.org.uk>
+ * Ryan Niebur <ryan@debian.org>
+ * Jan Christoph Nordholz <hesso@pool.math.tu-berlin.de>
+ * William Pursell <bill.pursell@gmail.com>
+ * Michael Scherer <misc@mandriva.org>
+ * Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+ * Peter Teichman <peter@teichman.org>
+
+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 key 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 resizable, 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, although 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 environment 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 don't open every file the attacher tells us.
+
+we have now our wonderful "Wuff, Wuff" visual_bell
+
+we have now the interprocess-communication-buffer. secure version.
+
+'^A =' removes the interprocess-communication-buffer.
+
+markroutine as in 2.1
+
+markroutine: 'a' toggles append mode,
+ '>' like ' ', but immediately WriteFile(DUMP_EXCHANGE) then.
+ 'A' like ' ', but first switch to append mode.
+
+.screenrc understands "screen 2:faui09 rlogin faui09 -l jnweiger"
+ and "password none"
+ and "vbell [on|off]"
+
+'^A :' allows .screenrc commands "online".
+
+screen now receives new $TERM from attacher, when it is reattached
+
+MakeClientSocket() fifo version does now test for access.
+
+.screenrc learns "hardstatus {on|off}"
+
+termcap's VB is used for vbell if available.
+
+Attach() code rewritten:
+ screen now lists socket directory, if it does not find a suitable socket
+ screen -d [host.tty] detaches a running screen.
+
+screen -[ls|list]
+ list all sockets that we find in our sockdir
+
+when the socket has been removed, send a SIGCHLD to the poor SCREEN
+process and it will try to recover. then try a 'screen -r' again.
+all the socket stuff lives now in an extra file.
+
+Major changes in version 2.4:
+=============================
+
+* Test version that presents the erlangen extensions from 2.0 in a 2.3
+ screen.
+
+* window resize support
+
+* screen locking C-a x
+
+* support for SYSV
+
+* password protection
+
+* copy & paste across screens
+
+* remote detach and power detach
+
+Major changes in version 2.3:
+
+* Terminal emulation has been significantly enhanced and bugfixed.
+
+* We now fully update the last character on the screen for true auto-
+ margin terminals, though there may be some delay before the character
+ can be safely added to the screen. If your terminal has character
+ insert it will be used to shorten the delay.
+
+* Added the "termcap" .screenrc command to tweak your terminal's termcap
+ entry AND to customize the termcap generated for the virtual terminals.
+ See also the -L and -O command-line options, and the SCREENCAP environ-
+ ment variable.
+
+* Fixed screen's character handling when detached or suspended to NOT block
+ the child processes in their windows -- output continues to be processed
+ in the background.
+
+* Added a.k.a.s (window-name aliases) that allow you to customize the
+ window-information line, including being able to change the name on-
+ the-fly to reflect what's currently running in the window (see the
+ -k option, shellaka command, and ALSO KNOWN AS discussion in the doc).
+
+* Added the ability to log the output of a window to a file (see the
+ "C-a H" (log) command).
+
+* Flow-control can now be set for each window and switched interactively
+ (see the "flow" command, -f option, and FLOW CONTROL discussion).
+
+* Individual windows can be included or excluded from mention in the
+ /etc/utmp file (see the "login" command and -l option).
+
+* Added an activity monitor, which allows you to have a window watched for
+ the start of any output and alert you when it occurs (see the "C-a M"
+ (monitor) command).
+
+* Enhanced the information in the window-information line to keep track of
+ windows that have: logging turned on '(L)'; beeped in the background '!';
+ became active while being monitored '@' (see the "C-a w" (windows) command).
+
+* Added an on-line help display that lists all the commands and their
+ key bindings (see the "C-a ?" (help) command).
+
+* Extended handling of the beep message (and also the new activity message)
+ to allow '~' to specify a literal beep (see the "beep" and "activity"
+ .screenrc commands).
+
+* You can now set the default action on receipt of a hangup signal: detach
+ or terminate (see the "autodetach" .screenrc command).
+
+* Routing of characters to their virtual terminals has been enhanced to
+ not drop characters nor (in rare circumstances) hang up screen.
+
+* The NFS compatibility has been enhanced.
+
+Major changes in version 2.0a:
+
+* Screen allows you to `detach' the "screen" session from the physical
+ terminal and resume it at a later point in time (possibly on a
+ different terminal or in a different login session).
+
+ To get an impression of this functionality do the following:
+
+ - call "screen" and create a couple of windows
+ - type Control-A Control-D (screen terminates; you are back
+ in the shell)
+ - call "screen -r" to resume the detached screen
+
+* Screen supports multiple character sets and the ISO 2022 control
+ functions to designate and switch between character sets.
+ This allows you, for instance, to make use of the VT100 graphics
+ character set or national character sets.
diff --git a/FAQ b/FAQ
new file mode 120000
index 0000000..1ad45dd
--- /dev/null
+++ b/FAQ
@@ -0,0 +1 @@
+doc/FAQ \ No newline at end of file
diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000..9cd0d1a
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,39 @@
+WIP notes on hacking the Screen source.
+
+* Screen commands are handled by the DoAction function in process.c.
+ The local variable nr is set to an integer value representing the
+ command to be evaluated; for every command `foo', there is an
+ integer value RC_FOO for use as nr's value to represent it. Find
+ the matching case label to follow processing of the command.
+
+ The RC_FOO values are defined in comm.h, which is automatically
+ generated by comm.sh, based on the names of the commands
+ themselves (found in comm.c).
+
+* The current display is held in the global variable "display".
+ Variable names like D_foo are shorthands for display->d_foo (where d_foo
+ is a member of "struct display").
+
+* Names like D_IS, D_TI, D_SG usually refer to the values of various
+ termcap features of the current display. These are found in term.h,
+ which is automatically generated from term.c by term.sh.
+
+* The main input-reading function for handling user input from a display,
+ is disp_readev_fn in display.c. This also handles automatic transformation
+ of mouse-tracking codes from display coordinates to screen-window
+ coordinates, and decodes characters from the display's encoding, passing
+ it on to the foreground input processor.
+
+ Input is passed through ProcessInput in process.c to handle
+ keybindings (specified by bindkey and such), and then processed by
+ layer-specific input-processing functions, which you'll find in
+ instances of struct LayFuncs. For instance, keystrokes are processed
+ by:
+
+ normal windows: WinPrGocess
+ window in copy-mode: MarkProcess
+ window list: WListProcess
+ command input line: InpProcess
+
+* Handling string escapes (in hardstatus and the like), such as %w or
+ %{= bw}, is done in screen.c, MakeWinMsgEv().
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..dd48ee0
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,114 @@
+Installation of GNU screen.
+
+
+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
+https://www.gnu.org/prep/standards/, especially the `Makefile
+Conventions', `Configuration', and `User Interfaces' sections.
+
+0.) autogen.sh
+--------------
+First, run ./autogen.sh. This will create configure file that you can use.
+This should be already done, so you can skip this step.
+
+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.
+And then please report a bug (https://savannah.gnu.org/bugs/?group=screen
+or mail screen-devel@gnu.org).
+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 uncertain about your NFS implementation, use a UFS directory for
+SOCKDIR. Personally, I favour a user's 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-devel@gnu.org 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 user's 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 privileges are required to open pty's.
+- Pty's should be owned by the user, so that she can do chmod to prevent
+ intruder 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 writable 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, ...
+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. :-)
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..08b44d3
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,356 @@
+#
+# Makefile template for screen
+#
+# See machine dependant config.h for more configuration options.
+#
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+DESTDIR =
+
+# Where to install screen.
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+datarootdir = @datarootdir@
+datadir = @datadir@
+
+# don't forget to change mandir and infodir in doc/Makefile.
+bindir = $(exec_prefix)/bin
+
+VERSION = @VERSION@
+SCREEN = screen-$(VERSION)
+
+GIT_REV =
+DEFS = @DEFS@ -DGIT_REV=\"$(GIT_REV)\"
+
+ETCSCREENRC = @ETCSCREENRC@
+ifeq (${ETCSCREENRC}, )
+ETCSCREENRC=$(prefix)/etc/screenrc
+endif
+SCREENENCODINGS = $(datadir)/screen/utf8encodings
+
+CC = @CC@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@ -DETCSCREENRC='"$(ETCSCREENRC)"' \
+ -DSCREENENCODINGS='"$(SCREENENCODINGS)"'
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+CPP=@CPP@
+CPP_DEPEND=$(CC) -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,screen}.<pid>. Look at these files and quote
+# questionable sections when sending bug-reports to the author.
+# -DDUMPSHADOW
+# With shadow-pw screen would never dump core. Use this option if
+# you still want to have a core. Use only for debugging.
+OPTIONS=
+#OPTIONS= -DDEBUG
+
+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 braille.c braille_tsi.c logfile.c layer.c \
+ sched.c teln.c nethack.c encoding.c canvas.c layout.c viewport.c \
+ list_display.c list_generic.c list_window.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 braille.o braille_tsi.o logfile.o layer.o \
+ list_generic.o list_display.o list_window.o \
+ sched.o teln.o nethack.o encoding.o canvas.o layout.o viewport.o
+
+all: screen
+
+screen: $(OFILES)
+ $(CC) $(LDFLAGS) -o $@ $(OFILES) $(LIBS)
+
+.c.o:
+ $(CC) -c -I. -I$(srcdir) $(M_CFLAGS) $(CPPFLAGS) $(DEFS) \
+ $(OPTIONS) $(CFLAGS) $<
+
+install_bin: .version screen installdirs
+ -if [ -f $(DESTDIR)$(bindir)/$(SCREEN) ] && [ ! -f $(DESTDIR)$(bindir)/$(SCREEN).old ]; \
+ then mv $(DESTDIR)$(bindir)/$(SCREEN) $(DESTDIR)$(bindir)/$(SCREEN).old; fi
+ $(INSTALL_PROGRAM) screen $(DESTDIR)$(bindir)/$(SCREEN)
+ -chown root $(DESTDIR)$(bindir)/$(SCREEN) && chmod 4755 $(DESTDIR)$(bindir)/$(SCREEN)
+# This doesn't work if $(bindir)/screen is a symlink
+ -if [ -f $(DESTDIR)$(bindir)/screen ] && [ ! -f $(DESTDIR)$(bindir)/screen.old ]; then mv $(DESTDIR)$(bindir)/screen $(DESTDIR)$(bindir)/screen.old; fi
+ rm -f $(DESTDIR)$(bindir)/screen
+ (cd $(DESTDIR)$(bindir) && ln -f -s $(SCREEN) screen)
+ cp $(srcdir)/utf8encodings/?? $(DESTDIR)$(SCREENENCODINGS)
+
+###############################################################################
+install: installdirs install_bin
+ cd doc ; $(MAKE) install
+ -if [ -d $(DESTDIR)/usr/lib/terminfo ]; then \
+ PATH="$$PATH:/usr/5bin" tic ${srcdir}/terminfo/screeninfo.src; \
+ chmod 644 $(DESTDIR)/usr/lib/terminfo/s/screen*; \
+ fi
+# 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 $(DESTDIR)$(bindir) $(DESTDIR)$(SCREENENCODINGS)
+ cd doc ; $(MAKE) installdirs
+
+uninstall: .version
+ rm -f $(DESTDIR)$(bindir)/$(SCREEN)
+ rm -f $(DESTDIR)$(bindir)/screen
+ -mv $(DESTDIR)$(bindir)/screen.old $(DESTDIR)$(bindir)/screen
+ rm -f $(DESTDIR)$(ETCSCREENRC)
+ cd doc; $(MAKE) uninstall
+
+shadow:
+ mkdir shadow;
+ cd shadow; ln -s ../*.[ch] ../*.in ../*.sh ../configure ../doc ../terminfo ../etc .
+ rm -f shadow/term.h shadow/tty.c shadow/comm.h shadow/osdef.h
+ echo "install all Makefiles and config:" > shadow/Makefile
+ echo " rm -f config.cache" >> shadow/Makefile
+ echo " sh ./configure" >> shadow/Makefile
+
+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
+ CPP="$(CPP) $(CPPFLAGS)" 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 config.cache osdef0.c osdef1.sed osdef2.sed
+
+clean celan: mostlyclean
+ rm -f tty.c term.h comm.h osdef.h kmapdef.c core
+
+# 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).tar $(SCREEN).tar.gz
+# rm -f config.status Makefile
+# rm -f osdef.h doc/Makefile
+
+maintainer-clean:
+ @echo "This command is not even intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+
+# Delete everything from the current directory that can be
+# reconstructed with this Makefile.
+realclean: .version mostlyclean
+ rm -f $(SCREEN).tar $(SCREEN).tar.gz
+ rm -f config.status Makefile doc/Makefile
+ rm -f tty.c term.h comm.h osdef.h kmapdef.c
+ rm -f config.h
+ echo "install all Makefiles and config:" > Makefile
+ echo " sh ./configure" >> Makefile
+
+tags TAGS: $(CFILES)
+ -ctags *.sh $(CFILES) *.h
+ -etags *.sh $(CFILES) *.h
+
+dist: .version $(SCREEN).tar.gz
+
+$(SCREEN).tar: .version term.h comm.h tty.c kmapdef.c
+ -rm -rf dist
+ mkdir dist
+ mkdir dist/$(SCREEN)
+ ln acls.h ansi.h display.h extern.h logfile.h mark.h os.h \
+ layer.h patchlevel.h screen.h window.h image.h \
+ osdef.h.in term.sh tty.sh comm.sh osdef.sh braille.h \
+ sched.h \
+ $(CFILES) \
+ ChangeLog COPYING INSTALL NEWS* TODO install.sh \
+ dist/$(SCREEN)
+ cd dist/$(SCREEN); mv tty.c tty.c.dist
+ cd dist/$(SCREEN); mv kmapdef.c kmapdef.c.dist
+ ln configure.in configure dist/$(SCREEN)
+ sed -e 's@"/local/screens@"/tmp/screens@' -e 's@"/local@"/usr/local@g' < config.h.in > dist/$(SCREEN)/config.h.in
+ sed -e 's@[ ]/local@ /usr/local@g' -e 's/^CFLAGS = -g/CFLAGS = -O/' < Makefile.in > dist/$(SCREEN)/Makefile.in
+ ln term.h dist/$(SCREEN)/term.h.dist
+ ln comm.h dist/$(SCREEN)/comm.h.dist
+ ln README dist/$(SCREEN)/README
+ mkdir dist/$(SCREEN)/terminfo
+ cd terminfo; ln 8bits README checktc.c screencap \
+ screeninfo.src test.txt tetris.c \
+ ../dist/$(SCREEN)/terminfo
+ mkdir dist/$(SCREEN)/etc
+ cd etc; ln * ../dist/$(SCREEN)/etc
+ mkdir dist/$(SCREEN)/utf8encodings
+ cd utf8encodings; ln * ../dist/$(SCREEN)/utf8encodings
+ # sed -e 's/^startup/#startup/' -e 's/^autodetach/#autodetach/' < $(ETCSCREENRC) > dist/$(SCREEN)/etc/etcscreenrc
+ cp $(HOME)/.screenrc dist/$(SCREEN)/etc/screenrc
+ mkdir dist/$(SCREEN)/doc
+ sed -e 's@/local/emacs@/usr/local@g' < doc/Makefile.in > dist/$(SCREEN)/doc/Makefile.in
+ cd doc; ln FAQ README.DOTSCREEN screen.1 screen.texinfo fdpat.ps make.help window_to_display.ps \
+ ../dist/$(SCREEN)/doc
+ cd doc; if test -f screen.info; then ln screen.info* \
+ ../dist/$(SCREEN)/doc; fi
+ cd dist/$(SCREEN)/doc; ln -s ../install.sh .
+ cd dist/$(SCREEN); ln -s doc/FAQ .
+ echo "install all Makefiles and config:" > dist/$(SCREEN)/Makefile
+ echo " rm -f config.cache" >> dist/$(SCREEN)/Makefile
+ echo " sh ./configure" >> dist/$(SCREEN)/Makefile
+ cd dist; tar cf ../$(SCREEN).tar $(SCREEN)
+ rm -rf dist
+
+$(SCREEN).tar.gz: $(SCREEN).tar
+ gzip -nf $(SCREEN).tar || gzip -f $(SCREEN).tar
+
+# Perform self-tests (if any).
+check:
+
+lint:
+ lint -I. $(CFILES)
+
+saber:
+ #load $(CFLAGS) screen.c ansi.c $(LIBS)
+
+config:
+ rm -f config.cache
+ sh ./configure
+
+
+###############################################################################
+
+.version:
+ @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'`; \
+ if [ "$${rev}.$${vers}.$${pat}" != "$(VERSION)" ]; then \
+ echo "This distribution is screen-$${rev}.$${vers}.$${pat}, but"; \
+ echo "the Makefile is from $(VERSION). Please update!"; exit 1; fi
+
+###############################################################################
+
+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 -k 2,2 2>/dev/null || sort -t'"' -u +1 -2) |\
+ sed -e 's/.*"\.\/\(.*\)".*/\1/'\
+ ` >> DEPEND ; \
+ done
+
+
+depend: depend.in
+ ./config.status || ./configure
+
+depend.in: $(CFILES) term.h
+ cp Makefile.in Makefile.in~
+ sed -e '/\#\#\# Dependencies/q' < Makefile.in > tmp_make
+ for i in $(CFILES); do echo $$i; $(CPP_DEPEND) $$i >> tmp_make; done
+ mv tmp_make Makefile.in
+
+###############################################################################
+
+### Dependencies:
+screen.o: layout.h viewport.h canvas.h screen.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h braille.h \
+ patchlevel.h logfile.h extern.h
+ansi.o: layout.h viewport.h canvas.h ansi.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h braille.h extern.h \
+ logfile.h
+fileio.o: layout.h viewport.h canvas.h fileio.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h
+mark.o: layout.h viewport.h canvas.h mark.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h mark.h extern.h
+misc.o: layout.h viewport.h canvas.h misc.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h
+resize.o: layout.h viewport.h canvas.h resize.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h
+socket.o: layout.h viewport.h canvas.h socket.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h
+search.o: layout.h viewport.h canvas.h search.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h mark.h extern.h
+tty.o: layout.h viewport.h canvas.h tty.c config.h screen.h os.h osdef.h ansi.h acls.h comm.h \
+ layer.h term.h image.h display.h window.h extern.h
+term.o: layout.h viewport.h canvas.h term.c term.h
+window.o: layout.h viewport.h canvas.h window.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h logfile.h
+utmp.o: layout.h viewport.h canvas.h utmp.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h
+loadav.o: layout.h viewport.h canvas.h loadav.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h
+putenv.o: layout.h viewport.h canvas.h putenv.c config.h
+help.o: layout.h viewport.h canvas.h help.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h list_generic.h
+termcap.o: layout.h viewport.h canvas.h termcap.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h
+input.o: layout.h viewport.h canvas.h input.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h
+attacher.o: layout.h viewport.h canvas.h attacher.c config.h screen.h os.h osdef.h ansi.h \
+ acls.h comm.h layer.h term.h image.h display.h window.h extern.h
+pty.o: layout.h viewport.h canvas.h pty.c config.h screen.h os.h osdef.h ansi.h acls.h comm.h \
+ layer.h term.h image.h display.h window.h extern.h
+process.o: layout.h viewport.h canvas.h process.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h logfile.h
+display.o: layout.h viewport.h canvas.h display.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h braille.h
+canvas.o: layout.h viewport.h canvas.h canvas.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h \
+ braille.h
+comm.o: layout.h viewport.h canvas.h comm.c config.h acls.h comm.h
+kmapdef.o: layout.h viewport.h canvas.h kmapdef.c config.h
+acls.o: layout.h viewport.h canvas.h acls.c config.h screen.h os.h osdef.h ansi.h acls.h comm.h \
+ layer.h term.h image.h display.h window.h extern.h
+braille.o: layout.h viewport.h canvas.h braille.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h braille.h
+braille_tsi.o: layout.h viewport.h canvas.h braille_tsi.c config.h screen.h os.h osdef.h ansi.h \
+ acls.h comm.h layer.h term.h image.h display.h window.h extern.h \
+ braille.h
+logfile.o: layout.h viewport.h canvas.h logfile.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h logfile.h
+layer.o: layout.h viewport.h canvas.h layer.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h
+sched.o: layout.h viewport.h canvas.h sched.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h logfile.h
+teln.o: layout.h viewport.h canvas.h teln.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h
+nethack.o: layout.h viewport.h canvas.h nethack.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h
+encoding.o: layout.h viewport.h canvas.h encoding.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h
+layout.o: layout.h viewport.h canvas.h layout.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h \
+ braille.h
+viewport.o: layout.h viewport.h canvas.h viewport.c config.h screen.h os.h osdef.h ansi.h acls.h \
+ comm.h layer.h term.h image.h display.h window.h extern.h \
+ braille.h
+list_generic.o: list_generic.h list_generic.c layer.h screen.h osdef.h
+list_display.o: list_generic.h list_display.c layer.h screen.h osdef.h
+list_window.o: list_generic.h list_window.c window.h layer.h screen.h osdef.h comm.h
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..ad502ef
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,28 @@
+ ------------------------------
+ What's new in screen-4.0.3 ?
+ ------------------------------
+
+* zombie command has new option 'onerror'
+
+* buffer overflow in resize.c fixed
+
+* minor docu update
+
+* more robust startup
+
+* use setresuid; SendAttachMsg() for fd-passing added; DoCSI enhanced.
+
+ ------------------------------
+ What's new in screen-4.0.0 ?
+ ------------------------------
+
+* new screenrc parser, not 100% compatible.
+
+* screenblanker support: new 'idle', 'blanker', 'blankerprg'
+ commands.
+
+* zmodem support via the 'zmodem' command.
+
+* nonblock code rewritten, nonblock now understands a timeout.
+ new command 'defnonblock'.
+
diff --git a/NEWS.3.5 b/NEWS.3.5
new file mode 100644
index 0000000..26e49ba
--- /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 occurrences 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 useful if you want to start screen in your /etc/rc file
+ (e.g. as a console multiplexer)
+
+* Console grabbing added ('console on' command).
+
+* Windows can now be selected by akas, too. (Per default bound to the
+ >'< key.)
+
+* New terminal capabiliteise CS/CE for cursorkey control.
+
+* setenv/unsetenv commands added.
+
+* Expansion of environment variables ($VAR) and terminal capabilities
+ ($:TC:) in the screenrc files and detach messages.
+ Example: pow_detach_msg "Session of \$LOGNAME \$:cr:\$:nl:ended."
+
+* New commands:
+ 'hardcopydir' and 'logdir' to change the output directories,
+ 'partial' and 'allpartial' to make screen only refresh the line
+ containing the cursor if a window is selected (useful for slow
+ modem connections).
+
+* Cleanup of the provided termcap/terminfo file. Please install
+ the new one!
+
+* The program 'terminfo/checktc.c' does a visual check of a
+ termcap/terminfo entry. Please try it before calling screen and
+ in a screen session.
+
+* LOTS of bugfixes and code cleanup.
+
+Thanks to all the beta testers who helped porting screen to at least
+the following platforms: Ultrix, SunOS, Solaris, BSD43, linux, NEWSOS,
+Irix, OSF/1, Harris CX/UX, hpux, dynix/ptx, AIX.
+And even more thanks to the brave who attempted to use the 'exec'
+command features.
+
+ Donnate patches, bugreports, suggestions, money, beer & pizza to
+ screen@uni-erlangen.de
+
diff --git a/NEWS.3.6 b/NEWS.3.6
new file mode 100644
index 0000000..6d4360f
--- /dev/null
+++ b/NEWS.3.6
@@ -0,0 +1,48 @@
+
+ ----------------------------
+ What's new in screen-3.6 ?
+ ----------------------------
+
+* Input translation! This makes the vt100 emulation complete.
+ As an addition it is now possible to bind any command to any
+ (function-) key. See the man page for more details (bindkey
+ command).
+
+* Status line support. Each window can have a different status line.
+ Use the ANSI APC string to set the status line, i.e.:
+ <ESC>_<status string><ESC>\
+ (For convenience the xterm sequence is also accepted.)
+ You may want to add
+ termcap * '' ':hs:ts=\E_:fs=\E\\:ds=\E_\E\\:'
+ terminfo * '' ':hs:ts=\E_:fs=\E\\:ds=\E_\E\\:'
+ to your ~/.screenrc to make screen advertise the hardstatus
+ support.
+
+* Zombie feature added. Windows now may generate a message (with a
+ timestamp) if they die and stay around until the user presses
+ a key.
+
+* New paste syntax: Paste can now concatenate registers and paste
+ either on screen or in anouther register.
+ This makes the old "ins_reg", "copy_reg" commands obsolete.
+
+* More architecures supported. Screen now runs on AIX3.2.5,
+ Solaris, NeXT and some other exotic platforms.
+
+* Kanji support added. Screen understands JIS, EUC and SJIS coding.
+ This is an experimental feature.
+
+* GR charset switching (ISO 2022) implemented. Can be enabled with
+ the "gr" command.
+
+* C1 sequences implemented (see the "c1" command).
+
+* Tek support from Xiaoguang Zhang. Apply tek.patch if you want to
+ make screen pass tek sequences.
+
+* List of new commands:
+ bindkey, c1, command, defc1, defgr, defkanji, gr, kanji, mapdefault,
+ mapnotnext, maptimeout, pastefont, printcmd, readreg, stuff, zombie
+
+* Lots of other bugs fixed.
+
diff --git a/NEWS.3.7 b/NEWS.3.7
new file mode 100644
index 0000000..e398f95
--- /dev/null
+++ b/NEWS.3.7
@@ -0,0 +1,39 @@
+
+
+ ----------------------------
+ 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'
+
+* New 'digraph' command (bound to ^A^V)
+ ^A^Va" or ^A^V0344 input an a-umlaut
+
+* activity/bell message strings can now include the window title:
+ %t - title
+ %n - number (a single % still works)
+
+* 'defhstatus' command to give everey window a default
+ hardstatus line. ^E is used as a string escape instead of %
+ (see above). Try 'defhstatus "Screen: window ^E (^Et)"'
+
+* Input parser changed to understand '^' (see ^E above).
+
+Note that the linux color xterm has a stupid bug: the characters
+get the color of the cursor, therefore if you change color and move
+the cursor around all the characters will get the new color...
+Here is a patch:
+ pub/utilities/screen/color_xterm_patch
+Btw.: rxvt works fine.
+
+* Optional Braille support. If you can read Braille and have one of
+ the devices listed in README.DOTSCREEN, please compile with
+ -DHAVE_BRAILLE and let us know if this feature is useful.
+
diff --git a/NEWS.3.9 b/NEWS.3.9
new file mode 100644
index 0000000..4dc7891
--- /dev/null
+++ b/NEWS.3.9
@@ -0,0 +1,205 @@
+ -------------------------------
+ What's new in screen-3.9.15 ?
+ -------------------------------
+
+* unicode combining character support
+
+* new encoding: chinese GBK
+
+* new 'backtick' command and string escape to embed command
+ output into e.g. the hardstatus line
+
+
+ -------------------------------
+ What's new in screen-3.9.13 ?
+ -------------------------------
+
+* altscreen support from Gurusamy Sarathy
+
+* new command "maxwin" to set a limit on the number of windows
+
+* new keys in copy&paste mode: 'B' and 'E'
+
+
+ -------------------------------
+ What's new in screen-3.9.11 ?
+ -------------------------------
+
+* windowlist, bound to ^A"
+
+* support for other encodings, e.g. big5, koi8r, cp1251
+ new commands 'encoding', 'defencoding'
+ 'register', 'readreg', 'readbuf', 'writebuf' now understand
+ an extra encoding parameter
+
+* support for double utf-8 characters
+
+* lots of new string escapes and extensions to existsing ones:
+ %LD, %LM, %Lw, %W, %-w, %+w, %H, %f, %F, %l, %=, %<, %>
+
+* new commands: 'source', 'eval', 'deflog', 'ignorecase', 'setsid'
+
+* command key classes: 'bind', 'command' and 'help' understand
+ a '-c <class>' parameter. See the man page for examples
+
+* new login state: always - don't remove slot even if screen gets
+ detached
+
+* 256 color support (experimental)
+
+* configurable time format string (for ^At)
+
+* config option to use localized month/week names
+
+* new option '-h' for hardcopy: also dump the scrollback buffer
+
+
+ ------------------------------
+ What's new in screen-3.9.9 ?
+ ------------------------------
+
+* new '-X' option to send commands to screen sessions.
+
+ screen -X echo Hi...
+
+* added a possibility to change the attributes/color in caption or
+ hardstatus strings:
+
+ caption always "%3n %{r}%t%{-}%? @%u%?%? %{g}[%h]%{-}%?"
+
+* new 'dinfo' command to show what screen thinks about your terminal.
+
+* new 'attrcolor' command to map attributes to color codes:
+ attrcolor u "-u b"
+ attrcolor b "r"
+
+* support for UTF-8: new commands 'utf8', 'defutf8' to change the
+ encoding of a window, plus a '-U' option to tell screen that
+ your terminal sends/receives UTF-8 codes.
+
+* support for 16 colors.
+
+
+ ------------------------------
+ What's new in screen-3.9.8 ?
+ ------------------------------
+
+* new command 'resize' to resize regions (aka split windows), try:
+ bind = resize =
+ bind + resize +1
+ bind - resize -1
+ bind _ resize max
+
+* new argument for 'focus': up, down, top, bottom
+
+* X11 mouse tracking support
+
+* Support for the "new color model", aka "background color erase":
+ the bce/defbce commands change the color model of the current
+ window/new windows.
+
+* experimental rxvt OSC sequence support (used to set a background
+ picture or to change the default colors), disabled by default.
+
+
+ ----------------------------
+ What's new in screen-3.9 ?
+ ----------------------------
+
+* real multiuser support
+ A window can now be displayed on more than one attached displays.
+ Screen does all the necessary clipping if the window size doesn't
+ fit the display.
+ New command:
+ ^AF - fit the window size into the display size.
+
+* split screen support
+ A display may now host multiple windows.
+ New commands:
+ ^AS - split horizontally. This add another region to the display
+ ^A<Tab> - move the focus to the next region
+ ^AX - kill the current region
+ ^AQ - kill all other regions
+
+* hardstatus emulation support
+ The last line of the display may now be used as a hardstatus
+ line if the terminal doesn't have the 'hs' capability.
+ New commands:
+ hardstatus [always]lastline
+ hardstatus [always]message
+ hardstatus [always]ignore
+
+* configurable window seperator and hardstatus strings
+ The window (region) seperator and the hardstatus can be set to an
+ arbitrary string containing screen's % escape sequences.
+ The window's hardstatus is just another escape sequence, '%h'.
+ New commands:
+ hardstatus string [string]
+ caption string [string]
+ The default strings are "%h" (hardstatus) and "%3n %t" (caption).
+
+* permanent window seperator
+ The window seperator can be set to stay on screen even if
+ the display contains only one region
+ New commands:
+ caption always
+ caption splitonly
+
+* many new escapes
+ %c - current time HH:MM (*CHANGE*: this was %w in screen-3.7)
+ %C - current time HH:MM in 24h format
+ %l - the load of the system
+ %h - hardstatus of the window
+ %w - all window names
+ %W - all window names except the current window
+ %u - all other users on this window
+ %? - the part to the next %? is displayed only if an escape
+ expands to an nonempty string.
+ %: - "else" part of %?
+ Some escapes like %c may be qualified with a '0' (like %0c)
+ to make screen use '0' instead of space as a filler.
+ Others understand a length qualifier, like %3n.
+ If escapes like the current time are used as hardstatus/caption
+ string screen will update them so that you can always have
+ the current time onscreen.
+ *CHANGE* ~ is no longer used as bell character, use ^G instead!
+
+* logfile timestamps and flush timeout
+ New commands:
+ logfile flush <secs>
+ logtstamp [on|off]
+ logtstamp string [string]
+ logtstamp after [secs]
+
+* configurable breaktype
+ You can now choose one of TIOCSBRK, TCSBRK, tcsendbreak.
+ New commands:
+ breaktype
+ defbreaktype
+
+* other new commands:
+ hstatus - set the window's hardstatus
+ defslowpaste
+ defsilence
+
+* optional builtin telnet.
+ This is useful if screen is used as frontend to a terminal
+ multiplexor. Use //telnet to access the builtin telnet program,
+ as in: 'screen //telnet host [port]'
+
+* remote detach and reattach change:
+ '-d' is now ignored if the screen is already detached and you
+ want to reattach. You can also use '-RR' to make screen use
+ the first session found if more than one session is available.
+ Thus '-d -RR' or '-x -RR' always gets you a screen.
+
+* support for history compaction
+ You can tell screen to suppress trailing blank lines when
+ scolling up text into the history buffer. (Wayne Davison)
+ New command:
+ compacthist
+
+* optional Braille support. If you can read Braille and have one of
+ the devices listed in README.DOTSCREEN, please compile with
+ -DHAVE_BRAILLE and let us know if this feature is useful.
+
diff --git a/README b/README
new file mode 100644
index 0000000..00b6908
--- /dev/null
+++ b/README
@@ -0,0 +1,102 @@
+
+ [If you just got the screen package, it pays to read the file INSTALL]
+ [This intro only describes the most common features to get you started]
+ [A full description of all features is contained in the source package]
+
+
+
+Short introduction to GNU screen.
+
+Send bugreports, fixes, enhancements, t-shirts, money, beer & pizza to
+ screen-devel@gnu.org
+
+Screen provides you with an ANSI/vt100 terminal emulator, which can multiplex
+up to 10 pseudo-terminals. On startup, it executes $SHELL in window 0.
+Then it reads $HOME/.screenrc to learn configuration, keybindings, and
+possibly open more windows.
+
+ C-a ? (help) Show all keybindings.
+
+ C-a c (screen) Create new windows.
+
+ C-a SPACE (next) Advance to next window (with wraparound).
+
+ C-a C-a (other) Toggle between the current and previously
+ displayed windows.
+
+ C-a 0 (select n) Switch to window n=0 ... 9.
+ ...
+ C-a 9
+
+ C-a w (windows) Show a list of window names in the status line.
+
+ C-a a (meta) Send a literal C-a/C-s/C-q to the
+ C-a s (xoff) process in the window.
+ C-a q (xon) For instance, emacs uses C-a and C-s.
+
+ C-a l (redisplay) Redraw this window.
+
+ C-a W (width) Toggle between 80 & 132 columns mode.
+
+ C-a L (login) Try to toggle the window's utmp-slot.
+
+ C-a z (suspend) Suspend the whole screen session.
+
+ C-a x (lockscreen) Execute /usr/bin/lock, $LOCKCMD or a
+ built-in terminal lock.
+
+ C-a H (log) Log stdout of window n to screenlog.n.
+
+ C-a C-[ (copy) Start copy mode. Move cursor with h,j,k,l.
+ Set 2 marks with SPACE or y. Abort with ESC.
+ (C-[ is ESC.) Preceeding second mark with
+ an a appends the text to the copy buffer.
+
+ C-a C-] (paste) Output copy buffer to current window's stdin.
+
+ C-a < (readbuf) Read the copy buffer from /tmp/screen-exchange.
+ C-a > (writebuf) Write the copy buffer to /tmp/screen-exchange.
+
+ C-a d (detach) Detach screen. All processes continue and may
+ spool output to their pty's, but screen
+ disconnects from your terminal.
+
+ C-a D D (pow_detach) Power detach. Disconnect like C-a d but also
+ kill the parent shell.
+
+ C-a K (kill) Kill a window and send SIGHUP to its process
+ group. Per default this would be C-a C-k,
+ but it is redefined in the demo .screenrc
+ (think of killing a whole line in emacs).
+
+ C-a : (colon) Online configuration change.
+
+See the man page or TeXinfo manual for many more keybindings and commands.
+
+screen -r [pid.tty.host|tty.host]
+ Reattach to a specific detached session. The terminal emulator
+ reconfigures according to your $TERMCAP or $TERM settings.
+ When you have multiple screens detached, you must supply the session
+ name.
+
+screen -R reattaches to a detached session or (if none) creates a new
+ session.
+
+screen -d [pid.tty.host|tty.host]
+ Detach a screen session remotely. Has the same effect as typing 'C-a d'
+ on the controlling terminal. 'screen -D' will power-detach.
+
+screen -list
+screen -ls
+screen -wipe
+ Show all available sessions and their status. Use -wipe to remove
+ DEAD sessions.
+
+ If sockets are missing, you may send a SIGCHLD to its 'SCREEN'
+ process and the process will re-establish the socket (think of
+ someone cleaning /tmp thoroughly).
+
+screen -h 200
+ Starts a new screen session and sets the number of lines in the scrollback
+ buffer to 200. The default is 100 lines.
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..54b2b9f
--- /dev/null
+++ b/TODO
@@ -0,0 +1,7 @@
+- display size adaption (Activate)
+- process.c cleanup via comm splitting
+- writelocks?
+- partial?
+- type into several windows at once (for cluster admins)
+- configurable digraph table
+- command line options should overwrite config files.
diff --git a/acconfig.h b/acconfig.h
new file mode 100644
index 0000000..46d62b0
--- /dev/null
+++ b/acconfig.h
@@ -0,0 +1,579 @@
+/* Copyright (c) 1993-2000
+ * 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 3, 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, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ * $Id$ GNU
+ */
+
+
+
+
+
+/**********************************************************************
+ *
+ * User Configuration Section
+ */
+
+/*
+ * Maximum of simultaneously allowed windows per screen session.
+ */
+#ifndef MAXWIN
+# define MAXWIN 100
+#endif
+
+/*
+ * 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 AFS- or NFS-mounted. Especially
+ * AFS is unlikely to support named sockets.
+ *
+ * Screen will name the subdirectories "S-$USER" (e.g /tmp/S-davison).
+ */
+#undef SOCKDIR
+
+/*
+ * Define this if the SOCKDIR is not shared between hosts.
+ */
+#define SOCKDIR_IS_LOCAL_TO_HOST
+
+/*
+ * 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 CHECKLOGIN to force Screen users to enter their Unix password
+ * in addition to the screen password.
+ *
+ * Define NOSYSLOG if yo do not have logging facilities. Currently
+ * syslog() will be used to trace ``su'' commands only.
+ */
+#define CHECKLOGIN 1
+#undef NOSYSLOG
+
+
+/*
+ * 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)
+ * define PTYROFS if the /dev/pty devices are mounted on a read-only
+ * filesystem so screen should not even attempt to set mode or group
+ * even if running as root (e.g. on TiVo).
+ */
+#undef PTYMODE
+#undef PTYGROUP
+#undef PTYROFS
+
+/*
+ * 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
+
+/*
+ * define DETACH can detach a session. An absolute 'must'.
+ */
+#define DETACH
+
+/*
+ * 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 (requires DETACH).
+ * 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)
+ * define MAPKEYS to include input keyboard translation.
+ * define FONT to support ISO2022/alternet charset support
+ * define COLOR to include ansi color support. This may expose
+ * a bug in x11r6-color-xterm.
+ * define DW_CHARS to include support for double-width character
+ * sets.
+ * define ENCODINGS to include support for encodings like euc or big5.
+ * Needs FONT to work.
+ * define UTF8 if you want support for UTF-8 encoding.
+ * Needs FONT and ENCODINGS to work.
+ * define COLORS16 if you want 16 colors.
+ * Needs COLOR to work.
+ * define BUILTIN_TELNET to add telnet support to screen.
+ * Syntax: screen //telnet host [port]
+ * define RXVT_OSC if you want support for rxvts special
+ * change fgcolor/bgcolor/bgpicture sequences
+ */
+#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
+# define FONT
+# define DW_CHARS
+# define ENCODINGS
+# define UTF8
+# define COLORS16
+# define ZMODEM
+# define BLANKER_PRG
+#endif /* SIMPLESCREEN */
+
+#undef BUILTIN_TELNET
+#undef RXVT_OSC
+#undef COLORS256
+
+
+/*
+ * If you have a braille display you should define HAVE_BRAILLE.
+ * The code inside #ifdef HAVE_BRAILLE was contributed by Hadi Bargi
+ * Rangin (bargi@dots.physics.orst.edu).
+ * WARNING: this is more or less unsupported code, it may be full of
+ * bugs leading to security holes, enable at your own risk!
+ */
+#undef HAVE_BRAILLE
+
+
+/*
+ * 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 will run perfectly without s-bit.
+ *
+ * If LOGOUTOK is undefined and UTMPOK is defined, all windows are
+ * initially and permanently logged in.
+ *
+ * Set CAREFULUTMP to one (1) if you want that users have at least one
+ * window per screen session logged in.
+ */
+#define LOGOUTOK 1
+#undef CAREFULUTMP
+
+
+/*
+ * 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
+
+/*
+ * both must be defined if you want to favor tcsendbreak over
+ * other calls to generate a break condition on serial lines.
+ * (Do not bother, if you are not using plain tty windows.)
+ */
+#define POSIX_HAS_A_GOOD_TCSENDBREAK
+#define SUNOS4_AND_WE_TRUST_TCSENDBREAK
+
+/*
+ * to lower the interrupt load on the host machine, you may want to
+ * adjust the VMIN and VTIME settings used for plain tty windows.
+ * See the termio(4) manual page (Non-Canonical Mode Input Processing)
+ * for details.
+ * if undefined, VMIN=1, VTIME=0 is used as a default - this gives you
+ * best user responsiveness, but highest interrupt frequency.
+ * (Do not bother, if you are not using plain tty windows.)
+ */
+#define TTYVMIN 100
+#define TTYVTIME 2
+
+/*
+ * looks like the above values are ignored by setting FNDELAY.
+ * This is default for all pty/ttys, you may disable it for
+ * ttys here. After playing with it for a while, one may find out
+ * that this feature may cause screen to lock up.
+ */
+#ifdef bsdi
+# define TTY_DISABLE_FNBLOCK /* select barfs without it ... */
+#endif
+
+
+/*
+ * 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
+
+
+/*
+ * Define USE_LOCALE if you want screen to use the locale names
+ * for the name of the month and day of the week.
+ */
+#undef USE_LOCALE
+
+/*
+ * Define USE_PAM if your system supports PAM (Pluggable Authentication
+ * Modules) and you want screen to use it instead of calling crypt().
+ * (You may also need to add -lpam to LIBS in the Makefile.)
+ */
+#undef USE_PAM
+
+/*
+ * Define CHECK_SCREEN_W if you want screen to set TERM to screen-w
+ * if the terminal width is greater than 131 columns. No longer needed
+ * on modern systems which use $COLUMNS or the tty settings instead.
+ */
+#undef CHECK_SCREEN_W
+
+/**********************************************************************
+ *
+ * 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
+
+/*
+ * 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
+
+/*
+ * Define if you have the utempter utmp helper program
+ */
+#undef HAVE_UTEMPTER
+
+/*
+ * 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.
+ */
+#undef HAVE_SETRESUID
+#undef HAVE_SETREUID
+
+/*
+ * If your system supports BSD4.4's seteuid() and setegid(), define
+ * HAVE_SETEUID.
+ */
+#undef HAVE_SETEUID
+
+/*
+ * execvpe is now defined in some systems.
+ */
+#undef HAVE_EXECVPE
+
+/*
+ * 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 LOADAV_USE_NLIST64
+
+#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.
+ * "But then, memmove() should work, if at all available" he thought...
+ * Boing, never say "works everywhere" unless you checked SCO UNIX.
+ * Their memove fails the test in the configure script. Sigh. (Juergen)
+ */
+#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 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 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 setenv() takes 3 arguments define HAVE_SETENV_3
+ */
+#undef HAVE_SETENV_3
+
+/*
+ * If setenv() takes 2 arguments define HAVE_SETENV_2
+ */
+#undef HAVE_SETENV_2
+
+/*
+ * 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
+
+/*
+ * define HAVE_NL_LANGINFO if your system has the nl_langinfo() call
+ * and <langinfo.h> defines CODESET.
+ */
+#undef HAVE_NL_LANGINFO
+
+/*
+ * Newer versions of Solaris include fdwalk, which can greatly improve
+ * the startup time of screen; otherwise screen spends a lot of time
+ * closing file descriptors.
+ */
+#undef HAVE_FDWALK
+
+/*
+ * define HAVE_DEV_PTC if you have a /dev/ptc character special
+ * device.
+ */
+#undef HAVE_DEV_PTC
+
+/*
+ * define HAVE_SVR4_PTYS if you have a /dev/ptmx character special
+ * device and support the ptsname(), grantpt(), unlockpt() functions.
+ */
+#undef HAVE_SVR4_PTYS
+
+/*
+ * 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/acls.c b/acls.c
new file mode 100644
index 0000000..1de8e89
--- /dev/null
+++ b/acls.c
@@ -0,0 +1,1147 @@
+/* Copyright (c) 2008, 2009
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Micah Cowan (micah@cowan.name)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
+ * 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 3, 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, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+
+/* XXX: WHY IS THIS HERE?? :XXX */
+
+#ifdef CHECKLOGIN
+# ifdef _SEQUENT_
+# include <stdio.h> /* needed by <pwd.h> */
+# endif /* _SEQUENT_ */
+# include <pwd.h>
+# ifdef SHADOWPW
+# include <shadow.h>
+# endif /* SHADOWPW */
+#endif /* CHECKLOGIN */
+
+#ifndef NOSYSLOG
+# include <syslog.h>
+#endif
+
+#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 char NullStr[];
+extern char SockPath[];
+extern struct display *display, *displays;
+struct acluser *users;
+
+#ifdef MULTIUSER
+int maxusercount = 0; /* used in process.c: RC_MONITOR, RC_SILENCE */
+
+/* record given user ids here */
+static AclBits userbits;
+
+/*
+ * rights a new unknown user will have on windows and cmds.
+ * These are changed by a "umask ?-..." command:
+ */
+static char default_w_bit[ACL_BITS_PER_WIN] =
+{
+ 1, /* EXEC */
+ 1, /* WRITE */
+ 1 /* READ */
+};
+
+static char default_c_bit[ACL_BITS_PER_CMD] =
+{
+ 0 /* EXEC */
+};
+
+/* rights of all users per newly created window */
+/*
+ * are now stored per user (umask)
+ * static AclBits default_w_userbits[ACL_BITS_PER_WIN];
+ * static AclBits default_c_userbits[ACL_BITS_PER_CMD];
+ */
+
+static int GrowBitfield __P((AclBits *, int, int, int));
+static struct aclusergroup **FindGroupPtr __P((struct aclusergroup **, struct acluser *, int));
+static int AclSetPermCmd __P((struct acluser *, char *, struct comm *));
+static int AclSetPermWin __P((struct acluser *, struct acluser *, char *, struct win *));
+static int UserAcl __P((struct acluser *, struct acluser **, int, char **));
+static int UserAclCopy __P((struct acluser **, struct acluser **));
+
+
+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 acluser **
+FindUserPtr(name)
+char *name;
+{
+ struct acluser **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)->u_id:-1);
+#else /* MULTIUSER */
+ debug2("FindUserPtr %s %sfound\n", name, (*u)?"":"not ");
+#endif /* MULTIUSER */
+ return u;
+}
+
+int DefaultEsc = -1; /* initialised by screen.c:main() */
+int DefaultMetaEsc = -1;
+
+/*
+ * Add a new user. His password may be NULL or "" if none. His name must not
+ * be "none", as this represents the NULL-pointer when dealing with groups.
+ * He has default rights, determined by umask.
+ */
+int
+UserAdd(name, pass, up)
+char *name, *pass;
+struct acluser **up;
+{
+#ifdef MULTIUSER
+ int j;
+#endif
+
+ if (!up)
+ up = FindUserPtr(name);
+ if (*up)
+ {
+ if (pass)
+ (*up)->u_password = SaveStr(pass);
+ return 1; /* he is already there */
+ }
+ if (strcmp("none", name)) /* "none" is a reserved word */
+ *up = (struct acluser *)calloc(1, sizeof(struct acluser));
+ if (!*up)
+ return -1; /* he still does not exist */
+#ifdef COPY_PASTE
+ (*up)->u_plop.buf = NULL;
+ (*up)->u_plop.len = 0;
+# ifdef ENCODINGS
+ (*up)->u_plop.enc = 0;
+# endif
+#endif
+ (*up)->u_Esc = DefaultEsc;
+ (*up)->u_MetaEsc = DefaultMetaEsc;
+ strncpy((*up)->u_name, name, MAXLOGINLEN);
+ (*up)->u_password = NULL;
+ if (pass)
+ (*up)->u_password = SaveStr(pass);
+ if (!(*up)->u_password)
+ (*up)->u_password = NullStr;
+ (*up)->u_detachwin = -1;
+ (*up)->u_detachotherwin = -1;
+
+#ifdef MULTIUSER
+ (*up)->u_group = NULL;
+ /* now find an unused index */
+ for ((*up)->u_id = 0; (*up)->u_id < maxusercount; (*up)->u_id++)
+ if (!(ACLBIT((*up)->u_id) & ACLBYTE(userbits, (*up)->u_id)))
+ break;
+ debug2("UserAdd %s id %d\n", name, (*up)->u_id);
+ if ((*up)->u_id == maxusercount)
+ {
+ int j;
+ struct win *w;
+ struct acluser *u;
+
+ 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 (j = 0; j <= RC_LAST; j++)
+ {
+ int i;
+
+ for (i = 0; i < ACL_BITS_PER_CMD; i++)
+ if (GrowBitfield(&comms[j].userbits[i], maxusercount, USER_CHUNK,
+ default_c_bit[i]))
+ {
+ free((char *)*up); *up = NULL; return -1;
+ }
+ }
+ /* fourth, default window creation bits per user */
+ for (u = users; u != *up; u = u->u_next)
+ {
+ for (j = 0; j < ACL_BITS_PER_WIN; j++)
+ {
+ if (GrowBitfield(&u->u_umask_w_bits[j], maxusercount, USER_CHUNK,
+ default_w_bit[j]))
+ {
+ free((char *)*up); *up = NULL; return -1;
+ }
+ }
+ }
+
+ /* fifth, the bits for each window */
+ /* keep these in sync with NewWindowAcl() */
+ for (w = windows; w; w = w->w_next)
+ {
+ /* five a: the access control list */
+ 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;
+ }
+ /* five b: the activity notify list */
+ /* five c: the silence notify list */
+ if (GrowBitfield(&w->w_mon_notify, maxusercount, USER_CHUNK, 0) ||
+ GrowBitfield(&w->w_lio_notify, maxusercount, USER_CHUNK, 0))
+ {
+ free((char *)*up); *up = NULL; return -1;
+ }
+ }
+ maxusercount += USER_CHUNK;
+ }
+
+ /* mark the user-entry as "in-use" */
+ ACLBYTE(userbits, (*up)->u_id) |= ACLBIT((*up)->u_id);
+
+ /* user id 0 is the session creator, he has all rights */
+ if ((*up)->u_id == 0)
+ AclSetPerm(NULL, *up, "+a", "#?");
+
+ /* user nobody has a fixed set of rights: */
+ if (!strcmp((*up)->u_name, "nobody"))
+ {
+ AclSetPerm(NULL, *up, "-rwx", "#?");
+ AclSetPerm(NULL, *up, "+x", "su");
+ AclSetPerm(NULL, *up, "+x", "detach");
+ AclSetPerm(NULL, *up, "+x", "displays");
+ AclSetPerm(NULL, *up, "+x", "version");
+ }
+
+ /*
+ * Create his umask:
+ * Give default_w_bit's for all users,
+ * but allow himself everything on "his" windows.
+ */
+ for (j = 0; j < ACL_BITS_PER_WIN; j++)
+ {
+ if (GrowBitfield(&(*up)->u_umask_w_bits[j], 0, maxusercount,
+ default_w_bit[j]))
+ {
+ free((char *)*up); *up = NULL; return -1;
+ }
+ ACLBYTE((*up)->u_umask_w_bits[j], (*up)->u_id) |= ACLBIT((*up)->u_id);
+ }
+#else /* MULTIUSER */
+ debug1("UserAdd %s\n", name);
+#endif /* MULTIUSER */
+ return 0;
+}
+
+#if 0
+/* change user's password */
+int
+UserSetPass(name, pass, up)
+char *name, *pass;
+struct acluser **up;
+{
+ if (!up)
+ up = FindUserPtr(name);
+ if (!*up)
+ return UserAdd(name, pass, up);
+ if (!strcmp(name, "nobody")) /* he remains without password */
+ return -1;
+ strncpy((*up)->u_password, pass ? pass : "", 20);
+ (*up)->u_password[20] = '\0';
+ return 0;
+}
+#endif
+
+/*
+ * Remove a user from the list.
+ * Destroy all his permissions and completely detach him from the session.
+ */
+int
+UserDel(name, up)
+char *name;
+struct acluser **up;
+{
+ struct acluser *u;
+#ifdef MULTIUSER
+ int i;
+#endif
+ struct display *old, *next;
+
+ if (!up)
+ up = FindUserPtr(name);
+ if (!(u = *up))
+ return -1; /* he who does not exist cannot be removed */
+ old = display;
+ for (display = displays; display; display = next)
+ {
+ next = display->d_next; /* read the next ptr now, Detach may zap it. */
+ if (D_user != u)
+ continue;
+ if (display == old)
+ old = NULL;
+ Detach(D_REMOTE);
+ }
+ display = old;
+ *up = u->u_next;
+
+#ifdef MULTIUSER
+ for (up = &users; *up; up = &(*up)->u_next)
+ {
+ /* unlink all group references to this user */
+ struct aclusergroup **g = &(*up)->u_group;
+
+ while (*g)
+ {
+ if ((*g)->u == u)
+ {
+ struct aclusergroup *next = (*g)->next;
+
+ free((char *)(*g));
+ *g = next;
+ }
+ else
+ g = &(*g)->next;
+ }
+ }
+ ACLBYTE(userbits, u->u_id) &= ~ACLBIT(u->u_id);
+ /* restore the bits in his slot to default: */
+ AclSetPerm(NULL, u, default_w_bit[ACL_READ] ? "+r" : "-r", "#");
+ AclSetPerm(NULL, u, default_w_bit[ACL_WRITE]? "+w" : "-w", "#");
+ AclSetPerm(NULL, u, default_w_bit[ACL_EXEC] ? "+x" : "-x", "#");
+ AclSetPerm(NULL, u, default_c_bit[ACL_EXEC] ? "+x" : "-x", "?");
+ for (i = 0; i < ACL_BITS_PER_WIN; i++)
+ free((char *)u->u_umask_w_bits[i]);
+#endif /* MULTIUSER */
+ debug1("FREEING user structure for %s\n", u->u_name);
+#ifdef COPY_PASTE
+ UserFreeCopyBuffer(u);
+#endif
+ free((char *)u);
+ if (!users)
+ {
+ debug("Last user deleted. Feierabend.\n");
+ Finit(0); /* Destroying whole session. Noone could ever attach again. */
+ }
+ 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 acluser *u;
+{
+ struct win *w;
+ struct paster *pa;
+
+ if (!u->u_plop.buf)
+ return 1;
+ for (w = windows; w; w = w->w_next)
+ {
+ pa = &w->w_paster;
+ if (pa->pa_pasteptr >= u->u_plop.buf &&
+ pa->pa_pasteptr - u->u_plop.buf < u->u_plop.len)
+ FreePaster(pa);
+ }
+ free((char *)u->u_plop.buf);
+ u->u_plop.len = 0;
+ u->u_plop.buf = 0;
+ return 0;
+}
+#endif /* COPY_PASTE */
+
+#ifdef MULTIUSER
+/*
+ * Traverses group nodes. It searches for a node that references user u.
+ * If recursive is true, nodes found in the users are also searched using
+ * depth first method. If none of the nodes references u, the address of
+ * the last next pointer is returned. This address will contain NULL.
+ */
+static struct aclusergroup **
+FindGroupPtr(gp, u, recursive)
+struct aclusergroup **gp;
+struct acluser *u;
+int recursive;
+{
+ struct aclusergroup **g;
+
+ ASSERT(recursive < 1000); /* Ouch, cycle detection failed */
+ while (*gp)
+ {
+ if ((*gp)->u == u)
+ return gp; /* found him here. */
+ if (recursive &&
+ *(g = FindGroupPtr(&(*gp)->u->u_group, u, recursive + 1)))
+ return g; /* found him there. */
+ gp = &(*gp)->next;
+ }
+ return gp; /* *gp is NULL */
+}
+
+static int
+PasswordMatches(pw, password)
+const char *pw, *password;
+{
+ if (!*password)
+ return 0;
+ char *buf = crypt((char *)pw, (char *)password);
+ return (buf && !strcmp(buf, password));
+}
+
+/*
+ * Returns nonzero if failed or already linked.
+ * Both users are created on demand.
+ * Cyclic links are prevented.
+ */
+int
+AclLinkUser(from, to)
+char *from, *to;
+{
+ struct acluser **u1, **u2;
+ struct aclusergroup **g;
+
+ if (!*(u1 = FindUserPtr(from)) && UserAdd(from, NULL, u1))
+ return -1;
+ if (!*(u2 = FindUserPtr(to)) && UserAdd(to, NULL, u2))
+ return -1; /* hmm, could not find both users. */
+
+ if (*FindGroupPtr(&(*u2)->u_group, *u1, 1))
+ return 1; /* cyclic link detected! */
+ if (*(g = FindGroupPtr(&(*u1)->u_group, *u2, 0)))
+ return 2; /* aha, we are already linked! */
+
+ if (!(*g = (struct aclusergroup *)malloc(sizeof(struct aclusergroup))))
+ return -1; /* Could not alloc link. Poor screen */
+ (*g)->u = (*u2);
+ (*g)->next = NULL;
+ return 0;
+}
+
+/*
+ * The user pointer stored at *up will be substituted by a pointer
+ * to the named user's structure, if passwords match.
+ * returns NULL if successfull, an static error string otherwise
+ */
+char *
+DoSu(up, name, pw1, pw2)
+struct acluser **up;
+char *name, *pw1, *pw2;
+{
+ struct acluser *u;
+ int sorry = 0;
+
+ if (!(u = *FindUserPtr(name)))
+ sorry++;
+ else
+ {
+#ifdef CHECKLOGIN
+ struct passwd *pp;
+#ifdef SHADOWPW
+ struct spwd *ss;
+ int t, c;
+#endif
+ char *pass = "";
+
+ if (!(pp = getpwnam(name)))
+ {
+ debug1("getpwnam(\"%s\") failed\n", name);
+ if (!(pw1 && *pw1 && *pw1 != '\377'))
+ {
+ debug("no unix account, no screen passwd\n");
+ sorry++;
+ }
+ }
+ else
+ pass = pp->pw_passwd;
+#ifdef SHADOWPW
+ for (t = 0; t < 13; t++)
+ {
+ c = pass[t];
+ if (!(c == '.' || c == '/' ||
+ (c >= '0' && c <= '9') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z')))
+ break;
+ }
+ if (t < 13)
+ {
+ if (!(ss = getspnam(name)))
+ {
+ debug1("getspnam(\"%s\") failed\n", name);
+ sorry++;
+ }
+ else
+ pass = ss->sp_pwdp;
+ }
+#endif /* SHADOWPW */
+
+ if (pw2 && *pw2 && *pw2 != '\377') /* provided a system password */
+ {
+ if (!PasswordMatches(pw2, pass))
+ {
+ debug("System password mismatch\n");
+ sorry++;
+ }
+ }
+ else /* no pasword provided */
+ if (*pass) /* but need one */
+ sorry++;
+#endif /* CHECKLOGIN */
+ if (pw1 && *pw1 && *pw1 != '\377') /* provided a screen password */
+ {
+ if (!PasswordMatches(pw1, u->u_password))
+ {
+ debug("screen password mismatch\n");
+ sorry++;
+ }
+ }
+ else /* no pasword provided */
+ if (*u->u_password) /* but need one */
+ sorry++;
+ }
+
+ debug2("syslog(LOG_NOTICE, \"screen %s: \"su %s\" ", SockPath, name);
+ debug2("%s for \"%s\"\n", sorry ? "failed" : "succeeded", (*up)->u_name);
+#ifndef NOSYSLOG
+# ifdef BSD_42
+ openlog("screen", LOG_PID);
+# else
+ openlog("screen", LOG_PID, LOG_AUTH);
+# endif /* BSD_42 */
+ syslog(LOG_NOTICE, "%s: \"su %s\" %s for \"%s\"", SockPath, name,
+ sorry ? "failed" : "succeeded", (*up)->u_name);
+ closelog();
+#else
+ debug("NOT LOGGED.\n");
+#endif /* NOSYSLOG */
+
+ if (sorry)
+ return "Sorry.";
+ else
+ *up = u; /* substitute user now */
+ return NULL;
+}
+#endif /* MULTIUSER */
+
+/************************************************************************
+ * end of user managing code *
+ ************************************************************************/
+
+
+#ifdef MULTIUSER
+
+/* This gives the users default rights to the new window w created by u */
+int
+NewWindowAcl(w, u)
+struct win *w;
+struct acluser *u;
+{
+ int i, j;
+
+ debug2("NewWindowAcl %s's umask_w_bits for window %d\n",
+ u ? u->u_name : "everybody", w->w_number);
+
+ /* keep these in sync with UserAdd part five. */
+ if (GrowBitfield(&w->w_mon_notify, 0, maxusercount, 0) ||
+ GrowBitfield(&w->w_lio_notify, 0, maxusercount, 0))
+ return -1;
+ 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]);
+ free((char *)w->w_mon_notify);
+ free((char *)w->w_lio_notify);
+ return -1;
+ }
+ for (i = 0; i < maxusercount; i++)
+ if (u ? (ACLBIT(i) & ACLBYTE(u->u_umask_w_bits[j], i)) :
+ default_w_bit[j])
+ ACLBYTE(w->w_userbits[j], i) |= ACLBIT(i);
+ }
+ return 0;
+}
+
+void
+FreeWindowAcl(w)
+struct win *w;
+{
+ int i;
+
+ for (i = 0; i < ACL_BITS_PER_WIN; i++)
+ free((char *)w->w_userbits[i]);
+ free((char *)w->w_mon_notify);
+ free((char *)w->w_lio_notify);
+}
+
+
+/* if mode starts with '-' we remove the users exec bit for cmd */
+/*
+ * NOTE: before you make this function look the same as
+ * AclSetPermWin, try to merge both functions.
+ */
+static int
+AclSetPermCmd(u, mode, cmd)
+struct acluser *u;
+char *mode;
+struct comm *cmd;
+{
+ int neg = 0;
+ char *m = mode;
+
+ while (*m)
+ {
+ switch (*m++)
+ {
+ case '-':
+ neg = 1;
+ continue;
+ case '+':
+ neg = 0;
+ continue;
+ case 'a':
+ case 'e':
+ case 'x':
+/* debug3("AclSetPermCmd %s %s %s\n", u->u_name, mode, cmd->name); */
+ if (neg)
+ ACLBYTE(cmd->userbits[ACL_EXEC], u->u_id) &= ~ACLBIT(u->u_id);
+ else
+ ACLBYTE(cmd->userbits[ACL_EXEC], u->u_id) |= ACLBIT(u->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.
+ * Letter n allows network access on a window.
+ * uu should be NULL, except if you want to change his umask.
+ */
+static int
+AclSetPermWin(uu, u, mode, win)
+struct acluser *u, *uu;
+char *mode;
+struct win *win;
+{
+ int neg = 0;
+ int bit, bits;
+ AclBits *bitarray;
+ char *m = mode;
+
+ if (uu)
+ {
+ debug3("AclSetPermWin %s UMASK %s %s\n", uu->u_name, u->u_name, mode);
+ bitarray = uu->u_umask_w_bits;
+ }
+ else
+ {
+ ASSERT(win);
+ bitarray = win->w_userbits;
+ debug3("AclSetPermWin %s %s %d\n", u->u_name, mode, win->w_number);
+ }
+
+ while (*m)
+ {
+ switch (*m++)
+ {
+ case '-':
+ neg = 1;
+ continue;
+ case '+':
+ neg = 0;
+ continue;
+ case 'r':
+ bits = (1 << ACL_READ);
+ break;
+ case 'w':
+ bits = (1 << ACL_WRITE);
+ break;
+ case 'x':
+ bits = (1 << ACL_EXEC);
+ break;
+ case 'a':
+ bits = (1 << ACL_BITS_PER_WIN) - 1;
+ break;
+ default:
+ return -1;
+ }
+ for (bit = 0; bit < ACL_BITS_PER_WIN; bit++)
+ {
+ if (!(bits & (1 << bit)))
+ continue;
+ if (neg)
+ ACLBYTE(bitarray[bit], u->u_id) &= ~ACLBIT(u->u_id);
+ else
+ ACLBYTE(bitarray[bit], u->u_id) |= ACLBIT(u->u_id);
+ if (!uu && (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;
+ }
+ }
+ }
+ if (uu && u->u_name[0] == '?' && u->u_name[1] == '\0')
+ {
+ /*
+ * It is Mr. '?', the unknown user. He deserves special treatment as
+ * he defines the defaults. Sorry, this is global, not per user.
+ */
+ if (win)
+ {
+ debug1("AclSetPermWin: default_w_bits '%s'.\n", mode);
+ for (bit = 0; bit < ACL_BITS_PER_WIN; bit++)
+ default_w_bit[bit] =
+ (ACLBYTE(bitarray[bit], u->u_id) & ACLBIT(u->u_id)) ? 1 : 0;
+ }
+ else
+ {
+ /*
+ * Hack. I do not want to duplicate all the above code for
+ * AclSetPermCmd. This asumes that there are not more bits
+ * per cmd than per win.
+ */
+ debug1("AclSetPermWin: default_c_bits '%s'.\n", mode);
+ for (bit = 0; bit < ACL_BITS_PER_CMD; bit++)
+ default_c_bit[bit] =
+ (ACLBYTE(bitarray[bit], u->u_id) & ACLBIT(u->u_id)) ? 1 : 0;
+ }
+ UserDel(u->u_name, NULL);
+ }
+ return 0;
+}
+
+/*
+ * String is broken down into comand and window names, mode applies
+ * A command name matches first, so do not use these as window names.
+ * uu should be NULL, except if you want to change his umask.
+ */
+int
+AclSetPerm(uu, u, mode, s)
+struct acluser *uu, *u;
+char *mode, *s;
+{
+ struct win *w;
+ int i;
+ char *p, ch;
+
+ debug3("AclSetPerm(uu, user '%s', mode '%s', object '%s')\n",
+ u->u_name, mode, s);
+ while (*s)
+ {
+ switch (*s)
+ {
+ case '*': /* all windows and all commands */
+ return AclSetPerm(uu, u, mode, "#?");
+ case '#':
+ if (uu) /* window umask or .. */
+ AclSetPermWin(uu, u, mode, (struct win *)1);
+ else /* .. or all windows */
+ for (w = windows; w; w = w->w_next)
+ AclSetPermWin((struct acluser *)0, u, mode, w);
+ s++;
+ break;
+ case '?':
+ if (uu) /* command umask or .. */
+ AclSetPermWin(uu, u, mode, (struct win *)0);
+ else /* .. or 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))
+ *p++ = '\0';
+ if ((i = FindCommnr(s)) != RC_ILLEGAL)
+ AclSetPermCmd(u, mode, &comms[i]);
+ else if (((i = WindowByNoN(s)) >= 0) && wtab[i])
+ AclSetPermWin((struct acluser *)0, u, mode, wtab[i]);
+ else
+ /* checking group name */
+ return -1;
+ if (ch)
+ p[-1] = ch;
+ s = p;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Generic ACL Manager:
+ *
+ * This handles acladd and aclchg identical.
+ * With 2 or 4 parameters, the second parameter is a password.
+ * With 3 or 4 parameters the last two parameters specify the permissions
+ * else user is added with full permissions.
+ * With 1 parameter the users permissions are copied from user *argv.
+ * Unlike the other cases, u->u_name should not match *argv here.
+ * uu should be NULL, except if you want to change his umask.
+ */
+static int
+UserAcl(uu, u, argc, argv)
+struct acluser *uu, **u;
+int argc;
+char **argv;
+{
+ if ((*u && !strcmp((*u)->u_name, "nobody")) ||
+ (argc > 1 && !strcmp(argv[0], "nobody")))
+ return -1; /* do not change nobody! */
+
+ switch (argc)
+ {
+ case 1+1+2:
+ debug2("UserAcl: user '%s', password '%s':", argv[0], argv[1]);
+ return (UserAdd(argv[0], argv[1], u) < 0) ||
+ AclSetPerm(uu, *u, argv[2], argv[3]);
+ case 1+2:
+ debug1("UserAcl: user '%s', no password:", argv[0]);
+ return (UserAdd(argv[0], NULL, u) < 0) ||
+ AclSetPerm(uu, *u, argv[1], argv[2]);
+ case 1+1:
+ debug2("UserAcl: user '%s', password '%s'\n", argv[0], argv[1]);
+ return UserAdd(argv[0], argv[1], u) < 0;
+ case 1:
+ debug1("UserAcl: user '%s', no password:", argv[0]);
+ return (UserAdd(argv[0], NULL, u) < 0) ||
+ AclSetPerm(uu, *u, "+a", "#?");
+ default:
+ return -1;
+ }
+}
+
+static int
+UserAclCopy(to_up, from_up)
+struct acluser **to_up, **from_up;
+{
+ struct win *w;
+ int i, j, to_id, from_id;
+
+ if (!*to_up || !*from_up)
+ return -1;
+ debug2("UserAclCopy: from user '%s' to user '%s'\n",
+ (*from_up)->u_name, (*to_up)->u_name);
+ if ((to_id = (*to_up)->u_id) == (from_id = (*from_up)->u_id))
+ return -1;
+ for (w = windows; w; w = w->w_next)
+ {
+ for (i = 0; i < ACL_BITS_PER_WIN; i++)
+ {
+ if (ACLBYTE(w->w_userbits[i], from_id) & ACLBIT(from_id))
+ ACLBYTE(w->w_userbits[i], to_id) |= ACLBIT(to_id);
+ else
+ {
+ ACLBYTE(w->w_userbits[i], to_id) &= ~ACLBIT(to_id);
+ if ((w->w_wlockuser == *to_up) && (i == ACL_WRITE))
+ {
+ debug2("%s lost wlock on win %d\n",
+ (*to_up)->u_name, w->w_number);
+ w->w_wlockuser = NULL;
+ if (w->w_wlock == WLOCK_ON)
+ w->w_wlock = WLOCK_AUTO;
+ }
+ }
+ }
+ }
+ for (j = 0; j <= RC_LAST; j++)
+ {
+ for (i = 0; i < ACL_BITS_PER_CMD; i++)
+ {
+ if (ACLBYTE(comms[j].userbits[i], from_id) & ACLBIT(from_id))
+ ACLBYTE(comms[j].userbits[i], to_id) |= ACLBIT(to_id);
+ else
+ ACLBYTE(comms[j].userbits[i], to_id) &= ~ACLBIT(to_id);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Syntax:
+ * user [password] [+rwx #?]
+ * * [password] [+rwx #?]
+ * user1,user2,user3 [password] [+rwx #?]
+ * user1,user2,user3=user
+ * uu should be NULL, except if you want to change his umask.
+ */
+int
+UsersAcl(uu, argc, argv)
+struct acluser *uu;
+int argc;
+char **argv;
+{
+ char *s;
+ int r;
+ struct acluser **cf_u = NULL;
+
+ if (argc == 1)
+ {
+ char *p = NULL;
+
+ s = argv[0];
+ while (*s)
+ if (*s++ == '=') p = s;
+ if (p)
+ {
+ p[-1] = '\0';
+ cf_u = FindUserPtr(p);
+ }
+ }
+
+ if (argv[0][0] == '*' && argv[0][1] == '\0')
+ {
+ struct acluser **u;
+
+ debug("all users acls.\n");
+ for (u = &users; *u; u = &(*u)->u_next)
+ if (strcmp("nobody", (*u)->u_name) &&
+ ((cf_u) ?
+ ((r = UserAclCopy(u, cf_u)) < 0) :
+ ((r = UserAcl(uu, u, argc, argv)) < 0)))
+ return -1;
+ return 0;
+ }
+
+ do
+ {
+ for (s = argv[0]; *s && *s!=' ' && *s!='\t' && *s!=',' && *s!='='; s++)
+ ;
+ *s ? (*s++ = '\0') : (*s = '\0');
+ debug2("UsersAcl(uu, \"%s\", argc=%d)\n", argv[0], argc);
+ if ((cf_u) ?
+ ((r = UserAclCopy(FindUserPtr(argv[0]), cf_u)) < 0) :
+ ((r = UserAcl(uu, FindUserPtr(argv[0]), argc, argv)) < 0))
+ return -1;
+ } while (*(argv[0] = s));
+ return 0;
+}
+
+/*
+ * Preprocess argments, so that umask can be set with UsersAcl
+ *
+ * all current users umask ±rwxn
+ * one specific user umask user1±rwxn
+ * several users umask user1,user2,...±rwxn
+ * default_w_bits umask ?±rwxn
+ * default_c_bits umask ??±rwxn
+ */
+int
+AclUmask(u, str, errp)
+struct acluser *u;
+char *str;
+char **errp;
+{
+ char mode[16];
+ char *av[3];
+ char *p, c = '\0';
+
+ /* split str into user and bits section. */
+ for (p = str; *p; p++)
+ if ((c = *p) == '+' || c == '-')
+ break;
+ if (!*p)
+ {
+ *errp = "Bad argument. Should be ``[user[,user...]{+|-}rwxn''.";
+ return -1;
+ }
+ strncpy(mode, p, 15);
+ mode[15] = '\0';
+ *p = '\0';
+
+ /* construct argument vector */
+ if (!strcmp("??", str))
+ {
+ str++;
+ av[2] = "?";
+ }
+ else
+ av[2] = "#";
+ av[1] = mode;
+ av[0] = *str ? str : "*";
+ /* call UsersAcl */
+ if (UsersAcl(u, 3, av))
+ {
+ *errp = "UsersAcl failed. Hmmm.";
+ *p = c;
+ return -1;
+ }
+ *p = c;
+ return 0;
+}
+
+void
+AclWinSwap(a, b)
+int a, b;
+{
+ debug2("AclWinSwap(%d, %d) NOP.\n", a, b);
+}
+
+struct acluser *EffectiveAclUser = NULL; /* hook for AT command permission */
+
+int
+AclCheckPermWin(u, mode, w)
+struct acluser *u;
+int mode;
+struct win *w;
+{
+ int ok;
+
+ if (mode < 0 || mode >= ACL_BITS_PER_WIN)
+ return -1;
+ if (EffectiveAclUser)
+ {
+ debug1("AclCheckPermWin: WARNING user %s overridden!\n", u->u_name);
+ u = EffectiveAclUser;
+ }
+ ok = ACLBYTE(w->w_userbits[mode], u->u_id) & ACLBIT(u->u_id);
+ debug3("AclCheckPermWin(%s, %d, %d) = ", u->u_name, mode, w->w_number);
+
+ if (!ok)
+ {
+ struct aclusergroup **g = &u->u_group;
+ struct acluser *saved_eff = EffectiveAclUser;
+
+ EffectiveAclUser = NULL;
+ while (*g)
+ {
+ if (!AclCheckPermWin((*g)->u, mode, w))
+ break;
+ g = &(*g)->next;
+ }
+ EffectiveAclUser = saved_eff;
+ if (*g)
+ ok = 1;
+ }
+ debug1("%d\n", !ok);
+ return !ok;
+}
+
+int
+AclCheckPermCmd(u, mode, c)
+struct acluser *u;
+int mode;
+struct comm *c;
+{
+ int ok;
+
+ if (mode < 0 || mode >= ACL_BITS_PER_CMD)
+ return -1;
+ if (EffectiveAclUser)
+ {
+ debug1("AclCheckPermCmd: WARNING user %s overridden!\n", u->u_name);
+ u = EffectiveAclUser;
+ }
+ ok = ACLBYTE(c->userbits[mode], u->u_id) & ACLBIT(u->u_id);
+ debug3("AclCheckPermCmd(%s %d %s) = ", u->u_name, mode, c->name);
+ if (!ok)
+ {
+ struct aclusergroup **g = &u->u_group;
+ struct acluser *saved_eff = EffectiveAclUser;
+
+ EffectiveAclUser = NULL;
+ while (*g)
+ {
+ if (!AclCheckPermCmd((*g)->u, mode, c))
+ break;
+ g = &(*g)->next;
+ }
+ EffectiveAclUser = saved_eff;
+ if (*g)
+ ok = 1;
+ }
+ debug1("%d\n", !ok);
+ return !ok;
+}
+
+#endif /* MULTIUSER */
diff --git a/acls.h b/acls.h
new file mode 100644
index 0000000..4e6c8a8
--- /dev/null
+++ b/acls.h
@@ -0,0 +1,98 @@
+/* Copyright (c) 2008, 2009
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Micah Cowan (micah@cowan.name)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
+ * 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 3, 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, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ */
+
+#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;
+
+/*
+ * How a user joins a group.
+ * Here is the node to construct one list per user.
+ */
+struct aclusergroup
+{
+ struct acluser *u; /* the user who borrows us his rights */
+ struct aclusergroup *next;
+};
+#endif /* MULTIUSER */
+
+/***************
+ * ==> user.h
+ */
+
+/*
+ * a copy buffer
+ */
+struct plop
+{
+ char *buf;
+ int len;
+#ifdef ENCODINGS
+ int enc;
+#endif
+};
+
+/*
+ * 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 acluser
+{
+ struct acluser *u_next; /* continue the main user list */
+ char u_name[MAXLOGINLEN + 1]; /* login name how he showed up */
+ char *u_password; /* his password (may be NullStr). */
+ int u_checkpassword; /* nonzero if this u_password is valid */
+ int u_detachwin; /* the window where he last detached */
+ int u_detachotherwin; /* window that was "other" when he detached */
+ int u_Esc, u_MetaEsc; /* the users screen escape character */
+#ifdef COPY_PASTE
+ struct plop u_plop;
+#endif
+#ifdef MULTIUSER
+ int u_id; /* a uniq index in the bitfields. */
+ AclBits u_umask_w_bits[ACL_BITS_PER_WIN]; /* his window create umask */
+ struct aclusergroup *u_group; /* linked list of pointers to other users */
+#endif
+} User;
+
+extern int DefaultEsc, DefaultMetaEsc;
+
diff --git a/ansi.c b/ansi.c
new file mode 100644
index 0000000..27983bb
--- /dev/null
+++ b/ansi.c
@@ -0,0 +1,3207 @@
+/* Copyright (c) 2008, 2009
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Micah Cowan (micah@cowan.name)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
+ * 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 3, 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, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#ifndef sun /* we want to know about TIOCPKT. */
+# include <sys/ioctl.h>
+#endif
+
+#include "config.h"
+#include "screen.h"
+#include "braille.h"
+#include "extern.h"
+#include "logfile.h"
+
+extern struct display *display, *displays;
+extern struct win *fore; /* for 83 escape */
+extern struct layer *flayer; /* for 83 escape */
+
+extern struct NewWindow nwin_default; /* for ResetWindow() */
+extern int nversion; /* numerical version of screen */
+extern int log_flush, logtstamp_on, logtstamp_after;
+extern char *logtstamp_string;
+extern char *captionstring;
+extern char *hstatusstring;
+extern char *wliststr;
+#ifdef COPY_PASTE
+extern int compacthist;
+#endif
+#ifdef MULTIUSER
+extern struct acluser *EffectiveAclUser;
+#endif
+
+/* widths for Z0/Z1 switching */
+const int Z0width = 132;
+const int Z1width = 80;
+
+/* globals set in WriteString */
+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; /* display status line in hs */
+char *printcmd = 0;
+int use_altscreen = 0; /* enable alternate screen support? */
+
+unsigned char *blank; /* line filled with spaces */
+unsigned 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, ... */};
+
+int renditions[NUM_RENDS] = {65529 /* =ub */, 65531 /* =b */, 65533 /* =u */ };
+
+/* keep string_t and string_t_string in sync! */
+static char *string_t_string[] =
+{
+ "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 */
+};
+
+/* keep state_t and state_t_string in sync! */
+static char *state_t_string[] =
+{
+ "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 */
+};
+
+static int Special __P((int));
+static void DoESC __P((int, int));
+static void DoCSI __P((int, int));
+static void StringStart __P((enum string_t));
+static void StringChar __P((int));
+static int StringEnd __P((void));
+static void PrintStart __P((void));
+static void PrintChar __P((int));
+static void PrintFlush __P((void));
+#ifdef FONT
+static void DesignateCharset __P((int, int));
+static void MapCharset __P((int));
+static void MapCharsetR __P((int));
+#endif
+static void SaveCursor __P((struct cursor *));
+static void RestoreCursor __P((struct cursor *));
+static void BackSpace __P((void));
+static void Return __P((void));
+static void LineFeed __P((int));
+static void ReverseLineFeed __P((void));
+static void InsertChar __P((int));
+static void DeleteChar __P((int));
+static void DeleteLine __P((int));
+static void InsertLine __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 ClearLineRegion __P((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 FindAKA __P((void));
+static void Report __P((char *, int, int));
+static void ScrollRegion __P((int));
+#ifdef COPY_PASTE
+static void WAddLineToHist __P((struct win *, struct mline *));
+#endif
+static void WLogString __P((struct win *, char *, int));
+static void WReverseVideo __P((struct win *, int));
+static int WindowChangedCheck __P((char *, int, int *));
+static void MFixLine __P((struct win *, int, struct mchar *));
+static void MScrollH __P((struct win *, int, int, int, int, int));
+static void MScrollV __P((struct win *, int, int, int, int));
+static void MClearArea __P((struct win *, int, int, int, int, int));
+static void MInsChar __P((struct win *, struct mchar *, int, int));
+static void MPutChar __P((struct win *, struct mchar *, int, int));
+static void MPutStr __P((struct win *, char *, int, struct mchar *, int, int));
+static void MWrapChar __P((struct win *, struct mchar *, int, int, int, int));
+#ifdef COLOR
+static void MBceLine __P((struct win *, int, int, int, int));
+#endif
+
+#ifdef COLOR
+# define CURR_BCE (curr->w_bce ? rend_getbg(&curr->w_rend) : 0)
+#else
+# define CURR_BCE 0
+#endif
+
+void
+ResetAnsiState(p)
+struct win *p;
+{
+ p->w_state = LIT;
+ p->w_StringType = NONE;
+}
+
+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_mouse = 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.on = 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;
+#ifdef FONT
+ ResetCharsets(p);
+#endif
+#ifdef COLOR
+ p->w_bce = nwin_default.bce;
+#endif
+}
+
+/* adds max 22 bytes */
+int
+GetAnsiStatus(w, buf)
+struct win *w;
+char *buf;
+{
+ char *p = buf;
+
+ if (w->w_state == LIT)
+ return 0;
+
+ strcpy(p, state_t_string[w->w_state]);
+ p += strlen(p);
+ if (w->w_intermediate)
+ {
+ *p++ = '-';
+ if (w->w_intermediate > 0xff)
+ p += AddXChar(p, w->w_intermediate >> 8);
+ p += AddXChar(p, w->w_intermediate & 0xff);
+ *p = 0;
+ }
+ if (w->w_state == ASTR || w->w_state == STRESC)
+ sprintf(p, "-%s", string_t_string[w->w_StringType]);
+ p += strlen(p);
+ return p - buf;
+}
+
+
+#ifdef FONT
+
+void
+ResetCharsets(p)
+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 ENCODINGS
+ ResetEncoding(p);
+#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];
+}
+#endif /* FONT */
+
+/*****************************************************************/
+
+
+/*
+ * Here comes the vt100 emulator
+ * - writes logfiles,
+ * - sets timestamp and flags activity in window.
+ * - record program output in window scrollback
+ * - translate program output for the display and put it into the obuf.
+ *
+ */
+void
+WriteString(wp, buf, len)
+struct win *wp;
+register char *buf;
+register int len;
+{
+ register int c;
+#ifdef FONT
+ register int font;
+#endif
+ struct canvas *cv;
+
+ if (!len)
+ return;
+ if (wp->w_log)
+ WLogString(wp, buf, len);
+
+ /* set global variables (yuck!) */
+ curr = wp;
+ cols = curr->w_width;
+ rows = curr->w_height;
+
+ if (curr->w_silence)
+ SetTimeout(&curr->w_silenceev, curr->w_silencewait * 1000);
+
+ if (curr->w_monitor == MON_ON)
+ {
+ debug2("ACTIVITY %d %d\n", curr->w_monitor, curr->w_bell);
+ curr->w_monitor = MON_FOUND;
+ }
+
+ if (cols > 0 && rows > 0)
+ {
+ do
+ {
+ c = (unsigned char)*buf++;
+#ifdef FONT
+# ifdef DW_CHARS
+ if (!curr->w_mbcs)
+# endif
+ curr->w_rend.font = curr->w_FontL; /* Default: GL */
+#endif
+
+ /* The next part is only for speedup */
+ if (curr->w_state == LIT &&
+#ifdef UTF8
+ curr->w_encoding != UTF8 &&
+#endif
+#ifdef DW_CHARS
+ !is_dw_font(curr->w_rend.font) &&
+# ifdef ENCODINGS
+ curr->w_rend.font != KANA && !curr->w_mbcs &&
+# endif
+#endif
+#ifdef FONT
+ curr->w_rend.font != '<' &&
+#endif
+ c >= ' ' && c != 0x7f &&
+ ((c & 0x80) == 0 || ((c >= 0xa0 || !curr->w_c1) && !curr->w_gr)) && !curr->w_ss &&
+ !curr->w_insert && curr->w_x < cols - 1)
+ {
+ register int currx = curr->w_x;
+ char *imp = buf - 1;
+
+ while (currx < cols - 1)
+ {
+ currx++;
+ if (--len == 0)
+ break;
+ c = (unsigned char)*buf++;
+ if (c < ' ' || c == 0x7f || ((c & 0x80) && ((c < 0xa0 && curr->w_c1) || curr->w_gr)))
+ break;
+ }
+ currx -= curr->w_x;
+ if (currx > 0)
+ {
+ MPutStr(curr, imp, currx, &curr->w_rend, curr->w_x, curr->w_y);
+ LPutStr(&curr->w_layer, imp, currx, &curr->w_rend, curr->w_x, curr->w_y);
+ curr->w_x += currx;
+ }
+ if (len == 0)
+ break;
+ }
+ /* end of speedup code */
+
+#ifdef UTF8
+ if (curr->w_encoding == UTF8)
+ {
+ c = FromUtf8(c, &curr->w_decodestate);
+ if (c == -1)
+ continue;
+ if (c == -2)
+ {
+ c = UCS_REPL;
+ /* try char again */
+ buf--;
+ len++;
+ }
+ if (c > 0xff)
+ debug1("read UNICODE %04x\n", c);
+ }
+#endif
+
+ 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! */
+ /* allow ^E for title escapes */
+ if (!(curr->w_StringType == OSC && c < ' ' && c != '\005'))
+ if (!curr->w_c1 || c != ('\\' ^ 0xc0))
+ {
+ StringChar(c);
+ break;
+ }
+ c = '\\';
+ /* FALLTHROUGH */
+ case STRESC:
+ switch (c)
+ {
+ case '\\':
+ if (StringEnd() == 0 || len <= 1)
+ break;
+ /* check if somewhere a status is displayed */
+ for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
+ {
+ display = cv->c_display;
+ if (D_status == STATUS_ON_WIN)
+ break;
+ }
+ if (cv)
+ {
+ if (len > IOSIZE + 1)
+ len = IOSIZE + 1;
+ curr->w_outlen = len - 1;
+ bcopy(buf, curr->w_outbuf, len - 1);
+ return; /* wait till status is gone */
+ }
+ break;
+ case '\033':
+ StringChar('\033');
+ break;
+ default:
+ curr->w_state = ASTR;
+ StringChar('\033');
+ StringChar(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 ']':
+ StringStart(OSC);
+ break;
+ case '_':
+ StringStart(APC);
+ break;
+ case 'P':
+ StringStart(DCS);
+ break;
+ case '^':
+ StringStart(PM);
+ break;
+ case '!':
+ StringStart(GM);
+ break;
+ case '"':
+ case 'k':
+ StringStart(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 DW_CHARS
+ 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 >= 0 && curr->w_NumArgs < MAXARGS)
+ {
+ if (curr->w_args[curr->w_NumArgs] < 100000000)
+ curr->w_args[curr->w_NumArgs] =
+ 10 * curr->w_args[curr->w_NumArgs] + (c - '0');
+ }
+ break;
+ case ';':
+ case ':':
+ if (curr->w_NumArgs < MAXARGS)
+ curr->w_NumArgs++;
+ break;
+ default:
+ if (Special(c))
+ break;
+ if (c >= '@' && c <= '~')
+ {
+ if (curr->w_NumArgs < MAXARGS)
+ 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:
+#ifdef DW_CHARS
+ if (curr->w_mbcs)
+ if (c <= ' ' || c == 0x7f || (c >= 0x80 && c < 0xa0 && curr->w_c1))
+ curr->w_mbcs = 0;
+#endif
+ if (c < ' ')
+ {
+ if (c == '\033')
+ {
+ curr->w_intermediate = 0;
+ curr->w_state = ESC;
+ if (curr->w_autoaka < 0)
+ curr->w_autoaka = 0;
+ }
+ else
+ Special(c);
+ break;
+ }
+ if (c >= 0x80 && c < 0xa0 && curr->w_c1)
+#ifdef FONT
+ if ((curr->w_FontR & 0xf0) != 0x20
+# ifdef UTF8
+ || curr->w_encoding == UTF8
+# endif
+ )
+#endif
+ {
+ switch (c)
+ {
+ case 0xc0 ^ 'D':
+ case 0xc0 ^ 'E':
+ case 0xc0 ^ 'H':
+ case 0xc0 ^ 'M':
+ case 0xc0 ^ 'N': /* SS2 */
+ case 0xc0 ^ 'O': /* SS3 */
+ DoESC(c ^ 0xc0, 0);
+ break;
+ case 0xc0 ^ '[':
+ 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':
+ StringStart(DCS);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+#ifdef FONT
+# ifdef DW_CHARS
+ if (!curr->w_mbcs)
+ {
+# endif
+ if (c < 0x80 || curr->w_gr == 0)
+ curr->w_rend.font = curr->w_FontL;
+# ifdef ENCODINGS
+ else if (curr->w_gr == 2 && !curr->w_ss)
+ curr->w_rend.font = curr->w_FontE;
+# endif
+ else
+ curr->w_rend.font = curr->w_FontR;
+# ifdef DW_CHARS
+ }
+# endif
+# ifdef UTF8
+ if (curr->w_encoding == UTF8)
+ {
+ if (curr->w_rend.font == '0')
+ {
+ struct mchar mc, *mcp;
+
+ debug1("SPECIAL %x\n", c);
+ mc.image = c;
+ mc.mbcs = 0;
+ mc.font = '0';
+ mc.fontx = 0;
+ mcp = recode_mchar(&mc, 0, UTF8);
+ debug2("%02x %02x\n", mcp->image, mcp->font);
+ c = mcp->image | mcp->font << 8;
+ }
+ curr->w_rend.font = 0;
+ }
+ if (curr->w_encoding == UTF8 && c >= 0x0300 && utf8_iscomb(c))
+ {
+ int ox, oy;
+ struct mchar omc;
+
+ ox = curr->w_x - 1;
+ oy = curr->w_y;
+ if (ox < 0)
+ {
+ ox = curr->w_width - 1;
+ oy--;
+ }
+ if (oy < 0)
+ oy = 0;
+ copy_mline2mchar(&omc, &curr->w_mlines[oy], ox);
+ if (omc.image == 0xff && omc.font == 0xff && omc.fontx == 0)
+ {
+ ox--;
+ if (ox >= 0)
+ {
+ copy_mline2mchar(&omc, &curr->w_mlines[oy], ox);
+ omc.mbcs = 0xff;
+ }
+ }
+ if (ox >= 0)
+ {
+ utf8_handle_comb(c, &omc);
+ MFixLine(curr, oy, &omc);
+ copy_mchar2mline(&omc, &curr->w_mlines[oy], ox);
+ LPutChar(&curr->w_layer, &omc, ox, oy);
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+ }
+ break;
+ }
+# ifdef DW_CHARS
+ if (curr->w_encoding == UTF8 && utf8_isdouble(c))
+ curr->w_mbcs = 0xff;
+# endif
+ font = curr->w_rend.font;
+# endif
+# ifdef DW_CHARS
+# ifdef ENCODINGS
+ if (font == KANA && curr->w_encoding == 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;
+ }
+ }
+# endif
+ if (font == 031 && c == 0x80 && !curr->w_mbcs)
+ font = curr->w_rend.font = 0;
+ if (is_dw_font(font) && c == ' ')
+ font = curr->w_rend.font = 0;
+ if (is_dw_font(font) || 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);
+ }
+# ifdef UTF8
+ if (curr->w_encoding != UTF8)
+# endif
+ {
+ c = curr->w_mbcs;
+# ifdef ENCODINGS
+ if (font == KANA && curr->w_encoding == SJIS)
+ {
+ debug2("SJIS !! %x %x\n", c, t);
+ /*
+ * SJIS -> EUC mapping:
+ * First byte:
+ * 81,82...9f -> 21,23...5d
+ * e0,e1...ef -> 5f,61...7d
+ * Second byte:
+ * 40-7e -> 21-5f
+ * 80-9e -> 60-7e
+ * 9f-fc -> 21-7e (increment first byte!)
+ */
+ 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);
+ }
+# endif
+ if (t && curr->w_gr && font != 030 && font != 031)
+ {
+ t &= 0x7f;
+ if (t < ' ')
+ goto tryagain;
+ }
+ if (t == '\177')
+ break;
+ curr->w_mbcs = t;
+ }
+ }
+# endif /* DW_CHARS */
+ if (font == '<' && c >= ' ')
+ {
+ font = curr->w_rend.font = 0;
+ c |= 0x80;
+ }
+# ifdef UTF8
+ else if (curr->w_gr && curr->w_encoding != UTF8)
+# else
+ else if (curr->w_gr)
+# endif
+ {
+#ifdef ENCODINGS
+ if (c == 0x80 && font == 0 && curr->w_encoding == GBK)
+ c = 0xa4;
+ else
+ c &= 0x7f;
+ if (c < ' ' && font != 031)
+ goto tryagain;
+#else
+ c &= 0x7f;
+ if (c < ' ') /* this is ugly but kanji support */
+ goto tryagain; /* prevents nicer programming */
+#endif
+ }
+#endif /* FONT */
+ if (c == '\177')
+ break;
+ curr->w_rend.image = c;
+#ifdef UTF8
+ if (curr->w_encoding == UTF8)
+ {
+ curr->w_rend.font = c >> 8;
+ curr->w_rend.fontx = c >> 16;
+ }
+#endif
+#ifdef DW_CHARS
+ curr->w_rend.mbcs = curr->w_mbcs;
+#endif
+ if (curr->w_x < cols - 1)
+ {
+ if (curr->w_insert)
+ {
+ save_mline(&curr->w_mlines[curr->w_y], cols);
+ MInsChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
+ LInsChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y, &mline_old);
+ curr->w_x++;
+ }
+ else
+ {
+ MPutChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
+ LPutChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y);
+ curr->w_x++;
+ }
+ }
+ else if (curr->w_x == cols - 1)
+ {
+ MPutChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
+ LPutChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y);
+ if (curr->w_wrap)
+ curr->w_x++;
+ }
+ else
+ {
+ MWrapChar(curr, &curr->w_rend, curr->w_y, curr->w_top, curr->w_bot, curr->w_insert);
+ LWrapChar(&curr->w_layer, &curr->w_rend, curr->w_y, curr->w_top, curr->w_bot, curr->w_insert);
+ if (curr->w_y != curr->w_bot && curr->w_y != curr->w_height - 1)
+ curr->w_y++;
+ curr->w_x = 1;
+ }
+#ifdef FONT
+# ifdef DW_CHARS
+ if (curr->w_mbcs)
+ {
+ curr->w_rend.mbcs = curr->w_mbcs = 0;
+ curr->w_x++;
+ }
+# endif
+ if (curr->w_ss)
+ {
+ curr->w_FontL = curr->w_charsets[curr->w_Charset];
+ curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
+ curr->w_rend.font = curr->w_FontL;
+ LSetRendition(&curr->w_layer, &curr->w_rend);
+ curr->w_ss = 0;
+ }
+#endif /* FONT */
+ break;
+ }
+ }
+ while (--len);
+ }
+ if (!printcmd && curr->w_state == PRIN)
+ PrintFlush();
+}
+
+static void
+WLogString(p, buf, len)
+struct win *p;
+char *buf;
+int len;
+{
+ if (!p->w_log)
+ return;
+ if (logtstamp_on && p->w_logsilence >= logtstamp_after * 2)
+ {
+ char *t = MakeWinMsg(logtstamp_string, p, '%');
+ logfwrite(p->w_log, t, strlen(t)); /* long time no write */
+ }
+ p->w_logsilence = 0;
+ if (logfwrite(p->w_log, buf, len) < 1)
+ {
+ WMsg(p, errno, "Error writing logfile");
+ logfclose(p->w_log);
+ p->w_log = 0;
+ }
+ if (!log_flush)
+ logfflush(p->w_log);
+}
+
+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();
+ case '\013': /* Vertical tab is the same as Line Feed */
+ LineFeed(0);
+ return 1;
+ case '\007':
+ WBell(curr, visual_bell);
+ return 1;
+ case '\t':
+ ForwardTab();
+ return 1;
+#ifdef FONT
+ case '\017': /* SI */
+ MapCharset(G0);
+ return 1;
+ case '\016': /* SO */
+ MapCharset(G1);
+ return 1;
+#endif
+ }
+ 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(1);
+ break;
+ case 'D':
+ LineFeed(0);
+ 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(&curr->w_saved);
+ break;
+ case '8':
+ RestoreCursor(&curr->w_saved);
+ break;
+ case 'c':
+ ClearScreen();
+ ResetWindow(curr);
+ LKeypadMode(&curr->w_layer, 0);
+ LCursorkeysMode(&curr->w_layer, 0);
+#ifndef TIOCPKT
+ WNewAutoFlow(curr, 1);
+#endif
+ /* XXX
+ SetRendition(&mchar_null);
+ InsertMode(0);
+ ChangeScrollRegion(0, rows - 1);
+ */
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+ break;
+ case '=':
+ LKeypadMode(&curr->w_layer, curr->w_keypad = 1);
+#ifndef TIOCPKT
+ WNewAutoFlow(curr, 0);
+#endif /* !TIOCPKT */
+ break;
+ case '>':
+ LKeypadMode(&curr->w_layer, curr->w_keypad = 0);
+#ifndef TIOCPKT
+ WNewAutoFlow(curr, 1);
+#endif /* !TIOCPKT */
+ break;
+#ifdef FONT
+ 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;
+#endif /* FONT */
+ case 'g': /* VBELL, private screen sequence */
+ WBell(curr, 1);
+ break;
+ }
+ break;
+ case '#':
+ switch (c)
+ {
+ case '8':
+ FillWithEs();
+ break;
+ }
+ break;
+#ifdef FONT
+ case '(':
+ DesignateCharset(c, G0);
+ break;
+ case ')':
+ DesignateCharset(c, G1);
+ break;
+ case '*':
+ DesignateCharset(c, G2);
+ break;
+ case '+':
+ DesignateCharset(c, G3);
+ break;
+# ifdef DW_CHARS
+/*
+ * 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
+#endif /* FONT */
+ }
+}
+
+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;
+ LGotoPos(&curr->w_layer, --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();
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+ break;
+ }
+ break;
+ case 'K':
+ if (a1 < 0 || a1 > 2)
+ a1 %= 3;
+ switch (a1)
+ {
+ case 0:
+ ClearLineRegion(curr->w_x, cols - 1);
+ break;
+ case 1:
+ ClearLineRegion(0, curr->w_x);
+ break;
+ case 2:
+ ClearLineRegion(0, cols - 1);
+ break;
+ }
+ break;
+ case 'X':
+ a1 = curr->w_x + (a1 ? a1 - 1 : 0);
+ ClearLineRegion(curr->w_x, a1 < cols ? a1 : cols - 1);
+ 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 'E':
+ curr->w_x = 0;
+ CursorDown(a1 ? a1 : 1); /* positions cursor */
+ break;
+ case 'F':
+ curr->w_x = 0;
+ CursorUp(a1 ? a1 : 1); /* positions cursor */
+ break;
+ case 'G':
+ case '`': /* HPA */
+ curr->w_x = a1 ? a1 - 1 : 0;
+ if (curr->w_x >= cols)
+ curr->w_x = cols - 1;
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+ break;
+ case 'd': /* VPA */
+ curr->w_y = a1 ? a1 - 1 : 0;
+ if (curr->w_y >= rows)
+ curr->w_y = rows - 1;
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+ 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)
+ {
+ curr->w_y = curr->w_top;
+ curr->w_x = 0;
+ }
+ else
+ curr->w_y = curr->w_x = 0;
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+ break;
+ case 's':
+ SaveCursor(&curr->w_saved);
+ break;
+ case 't':
+ switch(a1)
+ {
+ case 11:
+ if (curr->w_layer.l_cvlist)
+ Report("\033[1t", 0, 0);
+ else
+ Report("\033[2t", 0, 0);
+ break;
+ case 7:
+ LRefreshAll(&curr->w_layer, 0);
+ break;
+ case 21:
+ a1 = strlen(curr->w_title);
+ if ((unsigned)(curr->w_inlen + 5 + a1) <= sizeof(curr->w_inbuf))
+ {
+ bcopy("\033]l", curr->w_inbuf + curr->w_inlen, 3);
+ bcopy(curr->w_title, curr->w_inbuf + curr->w_inlen + 3, a1);
+ bcopy("\033\\", curr->w_inbuf + curr->w_inlen + 3 + a1, 2);
+ curr->w_inlen += 5 + a1;
+ }
+ break;
+ case 8:
+ a1 = curr->w_args[2];
+ if (a1 < 1)
+ a1 = curr->w_width;
+ if (a2 < 1)
+ a2 = curr->w_height;
+ if (a1 > 10000 || a2 > 10000)
+ break;
+ WChangeSize(curr, a1, a2);
+ cols = curr->w_width;
+ rows = curr->w_height;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 'u':
+ RestoreCursor(&curr->w_saved);
+ 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': /* MC Media Control */
+ if (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;
+ LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
+ }
+ break;
+ case 'S': /* code from a 97801 term / DEC vt400 */
+ ScrollRegion(a1 ? a1 : 1);
+ break;
+ case 'T': /* code from a 97801 term / DEC vt400 */
+ case '^': /* SD as per ISO 6429 */
+ 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 */
+ LCursorkeysMode(&curr->w_layer, curr->w_cursorkeys = i);
+#ifndef TIOCPKT
+ WNewAutoFlow(curr, !i);
+#endif /* !TIOCPKT */
+ break;
+ case 2: /* ANM: ansi/vt52 mode */
+ if (i)
+ {
+#ifdef FONT
+# ifdef ENCODINGS
+ if (curr->w_encoding)
+ break;
+# endif
+ curr->w_charsets[0] = curr->w_charsets[1] =
+ curr->w_charsets[2] = curr->w_charsets[3] =
+ curr->w_FontL = curr->w_FontR = ASCII;
+ curr->w_Charset = 0;
+ curr->w_CharsetR = 2;
+ curr->w_ss = 0;
+#endif
+ }
+ break;
+ case 3: /* COLM: column mode */
+ i = (i ? Z0width : Z1width);
+ ClearScreen();
+ curr->w_x = 0;
+ curr->w_y = 0;
+ WChangeSize(curr, i, curr->w_height);
+ cols = curr->w_width;
+ rows = curr->w_height;
+ break;
+ /* case 4: SCLM: scrolling mode */
+ case 5: /* SCNM: screen mode */
+ if (i != curr->w_revvid)
+ WReverseVideo(curr, i);
+ 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;
+ LGotoPos(&curr->w_layer, 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 9: /* X10 mouse tracking */
+ curr->w_mouse = i ? 9 : 0;
+ LMouseMode(&curr->w_layer, curr->w_mouse);
+ break;
+ /* 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 18: PFF: Printer term form feed */
+ /* case 19: PEX: Printer extend screen / scroll. reg */
+ case 25: /* TCEM: text cursor enable mode */
+ curr->w_curinv = !i;
+ LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
+ break;
+ /* case 34: RLM: Right to left mode */
+ /* case 35: HEBM: hebrew keyboard map */
+ /* case 36: HEM: hebrew encoding */
+ /* case 38: TeK Mode */
+ /* case 40: 132 col enable */
+ /* case 42: NRCM: 7bit NRC character mode */
+ /* case 44: margin bell enable */
+ case 47: /* xterm-like alternate screen */
+ case 1047: /* xterm-like alternate screen */
+ case 1049: /* xterm-like alternate screen */
+ if (use_altscreen)
+ {
+ if (i)
+ {
+ if (!curr->w_alt.on) {
+ SaveCursor(&curr->w_alt.cursor);
+ EnterAltScreen(curr);
+ }
+ }
+ else
+ {
+ if (curr->w_alt.on) {
+ RestoreCursor(&curr->w_alt.cursor);
+ LeaveAltScreen(curr);
+ }
+ }
+ if (a1 == 47 && !i)
+ curr->w_saved.on = 0;
+ LRefreshAll(&curr->w_layer, 0);
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+ }
+ break;
+ case 1048:
+ if (i)
+ SaveCursor(&curr->w_saved);
+ else
+ RestoreCursor(&curr->w_saved);
+ break;
+ /* case 66: NKM: Numeric keypad appl mode */
+ /* case 68: KBUM: Keyboard usage mode (data process) */
+ case 1000: /* VT200 mouse tracking */
+ case 1001: /* VT200 highlight mouse */
+ case 1002: /* button event mouse*/
+ case 1003: /* any event mouse*/
+ curr->w_mouse = i ? a1 : 0;
+ LMouseMode(&curr->w_layer, curr->w_mouse);
+ break;
+ /* case 1005: UTF-8 mouse mode rejected */
+ case 1006: /* SGR mouse mode */
+ curr->w_extmouse = i ? a1 : 0;
+ LExtMouseMode(&curr->w_layer, curr->w_extmouse);
+ break;
+ /* case 1015: UXRVT mouse mode rejected */
+ }
+ }
+ break;
+ case '>':
+ switch (c)
+ {
+ case 'c': /* secondary DA */
+ if (a1 == 0)
+ Report("\033[>%d;%d;0c", 83, nversion); /* 83 == 'S' */
+ break;
+ }
+ break;
+ }
+}
+
+
+static void
+StringStart(type)
+enum string_t type;
+{
+ curr->w_StringType = type;
+ curr->w_stringp = curr->w_string;
+ curr->w_state = ASTR;
+}
+
+static void
+StringChar(c)
+int c;
+{
+ if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
+ curr->w_state = LIT;
+ else
+ *(curr->w_stringp)++ = c;
+}
+
+/*
+ * Do string processing. Returns -1 if output should be suspended
+ * until status is gone.
+ */
+static int
+StringEnd()
+{
+ struct canvas *cv;
+ char *p;
+ int typ;
+ char *t;
+
+ /* There's two ways to terminate an OSC. If we've seen an ESC
+ * then it's been ST otherwise it's BEL. */
+ t = curr->w_state == STRESC ? "\033\\" : "\a";
+
+ curr->w_state = LIT;
+ *curr->w_stringp = '\0';
+ switch (curr->w_StringType)
+ {
+ case OSC: /* special xterm compatibility hack */
+ if (curr->w_string[0] == ';' || (p = index(curr->w_string, ';')) == 0)
+ break;
+ typ = atoi(curr->w_string);
+ p++;
+#ifdef MULTIUSER
+ if (typ == 83) /* 83 = 'S' */
+ {
+ /* special execute commands sequence */
+ char *args[MAXARGS];
+ int argl[MAXARGS];
+ struct acluser *windowuser;
+
+ windowuser = *FindUserPtr(":window:");
+ if (windowuser && Parse(p, sizeof(curr->w_string) - (p - curr->w_string), args, argl))
+ {
+ for (display = displays; display; display = display->d_next)
+ if (D_forecv->c_layer->l_bottom == &curr->w_layer)
+ break; /* found it */
+ if (display == 0 && curr->w_layer.l_cvlist)
+ display = curr->w_layer.l_cvlist->c_display;
+ if (display == 0)
+ display = displays;
+ EffectiveAclUser = windowuser;
+ fore = curr;
+ flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer;
+ DoCommand(args, argl);
+ EffectiveAclUser = 0;
+ fore = 0;
+ flayer = 0;
+ }
+ break;
+ }
+#endif
+#ifdef RXVT_OSC
+ if (typ == 0 || typ == 1 || typ == 2 || typ == 11 || typ == 20 || typ == 39 || typ == 49)
+ {
+ int typ2;
+ typ2 = typ / 10;
+ if (strcmp(curr->w_xtermosc[typ2], p))
+ {
+ if (typ != 11 || strcmp("?", p))
+ {
+ strncpy(curr->w_xtermosc[typ2], p, sizeof(curr->w_xtermosc[typ2]) - 1);
+ curr->w_xtermosc[typ2][sizeof(curr->w_xtermosc[typ2]) - 1] = 0;
+ }
+
+ for (display = displays; display; display = display->d_next)
+ {
+ if (!D_CXT)
+ continue;
+ if (D_forecv->c_layer->l_bottom == &curr->w_layer)
+ SetXtermOSC(typ2, p, t);
+ if ((typ2 == 3 || typ2 == 4) && D_xtermosc[typ2])
+ Redisplay(0);
+ if (typ == 11 && !strcmp("?", p))
+ break;
+ }
+ }
+ }
+ if (typ != 0 && typ != 2)
+ break;
+#else
+ if (typ < 0 || typ > 2)
+ break;
+#endif
+
+ curr->w_stringp -= p - curr->w_string;
+ if (curr->w_stringp > curr->w_string)
+ bcopy(p, 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);
+ WindowChanged(curr, 'h');
+ break;
+ case PM:
+ case GM:
+ for (display = displays; display; display = display->d_next)
+ {
+ for (cv = D_cvlist; cv; cv = cv->c_next)
+ if (cv->c_layer->l_bottom == &curr->w_layer)
+ break;
+ if (cv || curr->w_StringType == GM)
+ MakeStatus(curr->w_string);
+ }
+ return -1;
+ case DCS:
+ LAY_DISPLAYS(&curr->w_layer, AddStr(curr->w_string));
+ break;
+ case AKA:
+ if (curr->w_title == curr->w_akabuf && !*curr->w_string)
+ break;
+ if (curr->w_dynamicaka)
+ ChangeAKA(curr, curr->w_string, strlen(curr->w_string));
+ if (!*curr->w_string)
+ curr->w_autoaka = curr->w_y + 1;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static void
+PrintStart()
+{
+ curr->w_pdisplay = 0;
+
+ /* find us a nice display to print on, fore prefered */
+ display = curr->w_lastdisp;
+ if (!(display && curr == D_fore && (printcmd || D_PO)))
+ for (display = displays; display; display = display->d_next)
+ if (curr == D_fore && (printcmd || D_PO))
+ break;
+ if (!display)
+ {
+ struct canvas *cv;
+ for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
+ {
+ display = cv->c_display;
+ if (printcmd || D_PO)
+ break;
+ }
+ if (!cv)
+ {
+ display = displays;
+ if (!display || display->d_next || !(printcmd || D_PO))
+ return;
+ }
+ }
+ curr->w_pdisplay = display;
+ curr->w_stringp = curr->w_string;
+ curr->w_state = PRIN;
+ if (printcmd && curr->w_pdisplay->d_printfd < 0)
+ curr->w_pdisplay->d_printfd = printpipe(curr, printcmd);
+}
+
+static void
+PrintChar(c)
+int c;
+{
+ if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
+ PrintFlush();
+ *(curr->w_stringp)++ = c;
+}
+
+static void
+PrintFlush()
+{
+ 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)
+ {
+ WMsg(curr, 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)
+ {
+ AddCStr(D_PO);
+ AddStrn(curr->w_string, curr->w_stringp - curr->w_string);
+ AddCStr(D_PF);
+ Flush(3);
+ }
+ curr->w_stringp = curr->w_string;
+}
+
+
+void
+WNewAutoFlow(win, on)
+struct win *win;
+int on;
+{
+ debug1("WNewAutoFlow: %d\n", on);
+ 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;
+ LSetFlow(&win->w_layer, win->w_flow & FLOW_NOW);
+}
+
+
+#ifdef FONT
+
+static void
+DesignateCharset(c, n)
+int c, n;
+{
+ curr->w_ss = 0;
+# ifdef ENCODINGS
+ if (c == ('@' & 037)) /* map JIS 6226 to 0208 */
+ c = KANJI;
+# endif
+ if (c == 'B')
+ c = ASCII;
+ if (curr->w_charsets[n] != c)
+ {
+ curr->w_charsets[n] = c;
+ if (curr->w_Charset == n)
+ {
+ curr->w_FontL = c;
+ curr->w_rend.font = curr->w_FontL;
+ LSetRendition(&curr->w_layer, &curr->w_rend);
+ }
+ 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;
+ curr->w_FontL = curr->w_charsets[n];
+ curr->w_rend.font = curr->w_FontL;
+ LSetRendition(&curr->w_layer, &curr->w_rend);
+ }
+}
+
+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;
+}
+
+#endif /* FONT */
+
+static void
+SaveCursor(cursor)
+struct cursor *cursor;
+{
+ cursor->on = 1;
+ cursor->x = curr->w_x;
+ cursor->y = curr->w_y;
+ cursor->Rend = curr->w_rend;
+#ifdef FONT
+ cursor->Charset = curr->w_Charset;
+ cursor->CharsetR = curr->w_CharsetR;
+ bcopy((char *) curr->w_charsets, (char *) cursor->Charsets,
+ 4 * sizeof(int));
+#endif
+}
+
+static void
+RestoreCursor(cursor)
+struct cursor *cursor;
+{
+ if (!cursor->on)
+ return;
+ LGotoPos(&curr->w_layer, cursor->x, cursor->y);
+ curr->w_x = cursor->x;
+ curr->w_y = cursor->y;
+ curr->w_rend = cursor->Rend;
+#ifdef FONT
+ bcopy((char *) cursor->Charsets, (char *) curr->w_charsets,
+ 4 * sizeof(int));
+ curr->w_Charset = cursor->Charset;
+ curr->w_CharsetR = cursor->CharsetR;
+ curr->w_ss = 0;
+ curr->w_FontL = curr->w_charsets[curr->w_Charset];
+ curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
+#endif
+ LSetRendition(&curr->w_layer, &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--;
+ }
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+}
+
+static void
+Return()
+{
+ if (curr->w_x == 0)
+ return;
+ curr->w_x = 0;
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+}
+
+static void
+LineFeed(out_mode)
+int out_mode;
+{
+ /* out_mode: 0=lf, 1=cr+lf */
+ if (out_mode)
+ curr->w_x = 0;
+ if (curr->w_y != curr->w_bot) /* Don't scroll */
+ {
+ if (curr->w_y < rows-1)
+ curr->w_y++;
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+ return;
+ }
+ if (curr->w_autoaka > 1)
+ curr->w_autoaka--;
+ MScrollV(curr, 1, curr->w_top, curr->w_bot, CURR_BCE);
+ LScrollV(&curr->w_layer, 1, curr->w_top, curr->w_bot, CURR_BCE);
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+}
+
+static void
+ReverseLineFeed()
+{
+ if (curr->w_y == curr->w_top)
+ {
+ MScrollV(curr, -1, curr->w_top, curr->w_bot, CURR_BCE);
+ LScrollV(&curr->w_layer, -1, curr->w_top, curr->w_bot, CURR_BCE);
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+ }
+ else if (curr->w_y > 0)
+ CursorUp(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);
+ MScrollH(curr, -n, y, x, curr->w_width - 1, CURR_BCE);
+ LScrollH(&curr->w_layer, -n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
+ LGotoPos(&curr->w_layer, 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);
+ MScrollH(curr, n, y, x, curr->w_width - 1, CURR_BCE);
+ LScrollH(&curr->w_layer, n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
+ LGotoPos(&curr->w_layer, x, y);
+}
+
+static void
+DeleteLine(n)
+int n;
+{
+ 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;
+ MScrollV(curr, n, curr->w_y, curr->w_bot, CURR_BCE);
+ LScrollV(&curr->w_layer, n, curr->w_y, curr->w_bot, CURR_BCE);
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+}
+
+static void
+InsertLine(n)
+int n;
+{
+ 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;
+ MScrollV(curr, -n, curr->w_y, curr->w_bot, CURR_BCE);
+ LScrollV(&curr->w_layer, -n, curr->w_y, curr->w_bot, CURR_BCE);
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+}
+
+static void
+ScrollRegion(n)
+int n;
+{
+ MScrollV(curr, n, curr->w_top, curr->w_bot, CURR_BCE);
+ LScrollV(&curr->w_layer, n, curr->w_top, curr->w_bot, CURR_BCE);
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+}
+
+
+static void
+ForwardTab()
+{
+ register int x = curr->w_x;
+
+ if (x == cols)
+ {
+ LineFeed(1);
+ x = 0;
+ }
+ if (curr->w_tabs[x] && x < cols - 1)
+ x++;
+ while (x < cols - 1 && !curr->w_tabs[x])
+ x++;
+ curr->w_x = x;
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+}
+
+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--;
+ curr->w_x = x;
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+}
+
+static void
+ClearScreen()
+{
+ LClearArea(&curr->w_layer, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE, 1);
+#ifdef COPY_PASTE
+ MScrollV(curr, curr->w_height, 0, curr->w_height - 1, CURR_BCE);
+#else
+ MClearArea(curr, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE);
+#endif
+}
+
+static void
+ClearFromBOS()
+{
+ register int y = curr->w_y, x = curr->w_x;
+
+ LClearArea(&curr->w_layer, 0, 0, x, y, CURR_BCE, 1);
+ MClearArea(curr, 0, 0, x, y, CURR_BCE);
+ RestorePosRendition();
+}
+
+static void
+ClearToEOS()
+{
+ register int y = curr->w_y, x = curr->w_x;
+
+ if (x == 0 && y == 0)
+ {
+ ClearScreen();
+ RestorePosRendition();
+ return;
+ }
+ LClearArea(&curr->w_layer, x, y, cols - 1, rows - 1, CURR_BCE, 1);
+ MClearArea(curr, x, y, cols - 1, rows - 1, CURR_BCE);
+ RestorePosRendition();
+}
+
+static void
+ClearLineRegion(from, to)
+int from, to;
+{
+ register int y = curr->w_y;
+ LClearArea(&curr->w_layer, from, y, to, y, CURR_BCE, 1);
+ MClearArea(curr, from, y, to, y, CURR_BCE);
+ RestorePosRendition();
+}
+
+static void
+CursorRight(n)
+register int n;
+{
+ register int x = curr->w_x;
+
+ if (x == cols)
+ {
+ LineFeed(1);
+ x = 0;
+ }
+ if ((curr->w_x += n) >= cols)
+ curr->w_x = cols - 1;
+ LGotoPos(&curr->w_layer, 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;
+ LGotoPos(&curr->w_layer, 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;
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+}
+
+static void
+CursorLeft(n)
+register int n;
+{
+ if ((curr->w_x -= n) < 0)
+ curr->w_x = 0;
+ LGotoPos(&curr->w_layer, 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 2: KAM: Lock keyboard */
+ case 4: /* IRM: Insert mode */
+ curr->w_insert = on;
+ LAY_DISPLAYS(&curr->w_layer, InsertMode(on));
+ break;
+ /* case 12: SRM: Echo mode on */
+ case 20: /* LNM: Linefeed mode */
+ curr->w_autolf = on;
+ break;
+ case 34:
+ curr->w_curvvis = !on;
+ LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static char rendlist[] =
+{
+ ~((1 << NATTR) - 1), 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()
+{
+#ifdef COLOR
+ register int j, i = 0, a = curr->w_rend.attr, c = curr->w_rend.color;
+# ifdef COLORS256
+ int cx = curr->w_rend.colorx;
+# endif
+#else
+ register int j, i = 0, a = curr->w_rend.attr;
+#endif
+
+ do
+ {
+ j = curr->w_args[i];
+#ifdef COLOR
+ if ((j == 38 || j == 48) && i + 2 < curr->w_NumArgs && curr->w_args[i + 1] == 5)
+ {
+ int jj;
+
+ i += 2;
+ jj = curr->w_args[i];
+ if (jj < 0 || jj > 255)
+ continue;
+# ifdef COLORS256
+ if (j == 38)
+ {
+ c = (c & 0xf0) | ((jj & 0x0f) ^ 9);
+ a |= A_BFG;
+ if (jj >= 8 && jj < 16)
+ c |= 0x08;
+ else
+ a ^= A_BFG;
+ a = (a & 0xbf) | (jj & 8 ? 0x40 : 0);
+ cx = (cx & 0xf0) | (jj >> 4 & 0x0f);
+ }
+ else
+ {
+ c = (c & 0x0f) | ((jj & 0x0f) ^ 9) << 4;
+ a |= A_BBG;
+ if (jj >= 8 && jj < 16)
+ c |= 0x80;
+ else
+ a ^= A_BBG;
+ cx = (cx & 0x0f) | (jj & 0xf0);
+ }
+ continue;
+# else
+ jj = color256to16(jj) + 30;
+ if (jj >= 38)
+ jj += 60 - 8;
+ j = j == 38 ? jj : jj + 10;
+# endif
+ }
+# ifdef COLORS16
+ if (j == 0 || (j >= 30 && j <= 39 && j != 38))
+ a &= 0xbf;
+ if (j == 0 || (j >= 40 && j <= 49 && j != 48))
+ a &= 0x7f;
+ if (j >= 90 && j <= 97)
+ a |= 0x40;
+ if (j >= 100 && j <= 107)
+ a |= 0x80;
+# endif
+ if (j >= 90 && j <= 97)
+ j -= 60;
+ if (j >= 100 && j <= 107)
+ j -= 60;
+ if (j >= 30 && j <= 39 && j != 38)
+ c = (c & 0xf0) | ((j - 30) ^ 9);
+ else if (j >= 40 && j <= 49 && j != 48)
+ c = (c & 0x0f) | (((j - 40) ^ 9) << 4);
+ if (j == 0)
+ c = 0;
+# ifdef COLORS256
+ if (j == 0 || (j >= 30 && j <= 39 && j != 38))
+ cx &= 0xf0;
+ if (j == 0 || (j >= 40 && j <= 49 && j != 48))
+ cx &= 0x0f;
+# endif
+#endif
+ if (j < 0 || j >= (int)(sizeof(rendlist)/sizeof(*rendlist)))
+ continue;
+ j = rendlist[j];
+ if (j & (1 << NATTR))
+ a &= j;
+ else
+ a |= j;
+ }
+ while (++i < curr->w_NumArgs);
+ curr->w_rend.attr = a;
+#ifdef COLOR
+ curr->w_rend.color = c;
+# ifdef COLORS256
+ curr->w_rend.colorx = cx;
+# endif
+#endif
+ LSetRendition(&curr->w_layer, &curr->w_rend);
+}
+
+static void
+FillWithEs()
+{
+ register int i;
+ register unsigned char *p, *ep;
+
+ LClearAll(&curr->w_layer, 1);
+ 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';
+ }
+ LRefreshAll(&curr->w_layer, 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;
+{
+ int i, c;
+
+ for (i = 0; l > 0; l--)
+ {
+ if (p->w_akachange + i == p->w_akabuf + sizeof(p->w_akabuf) - 1)
+ break;
+ c = (unsigned char)*s++;
+ if (c == 0)
+ break;
+ if (c < 32 || c == 127 || (c >= 128 && c < 160 && p->w_c1))
+ continue;
+ p->w_akachange[i++] = c;
+ }
+ p->w_akachange[i] = 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;
+ WindowChanged(p, 't');
+ WindowChanged((struct win *)0, 'w');
+ WindowChanged((struct win *)0, 'W');
+}
+
+static void
+FindAKA()
+{
+ register unsigned 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((char *)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, (char *)line, cp - line);
+ }
+ else
+ wp->w_autoaka = 0;
+}
+
+static void
+RestorePosRendition()
+{
+ LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
+ LSetRendition(&curr->w_layer, &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]; /* enough room for all replys */
+
+ sprintf(rbuf, fmt, n1, n2);
+ len = strlen(rbuf);
+
+#ifdef PSEUDOS
+ if (W_UWP(curr))
+ {
+ if ((unsigned)(curr->w_pwin->p_inlen + len) <= sizeof(curr->w_pwin->p_inbuf))
+ {
+ bcopy(rbuf, curr->w_pwin->p_inbuf + curr->w_pwin->p_inlen, len);
+ curr->w_pwin->p_inlen += len;
+ }
+ }
+ else
+#endif
+ {
+ if ((unsigned)(curr->w_inlen + len) <= sizeof(curr->w_inbuf))
+ {
+ bcopy(rbuf, curr->w_inbuf + curr->w_inlen, len);
+ curr->w_inlen += len;
+ }
+ }
+}
+
+
+
+/*
+ *====================================================================*
+ *====================================================================*
+ */
+
+/**********************************************************************
+ *
+ * Memory subsystem.
+ *
+ */
+
+static void
+MFixLine(p, y, mc)
+struct win *p;
+int y;
+struct mchar *mc;
+{
+ struct mline *ml = &p->w_mlines[y];
+ if (mc->attr && ml->attr == null)
+ {
+ if ((ml->attr = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
+ {
+ ml->attr = null;
+ mc->attr = p->w_rend.attr = 0;
+ WMsg(p, 0, "Warning: no space for attr - turned off");
+ }
+ }
+#ifdef FONT
+ if (mc->font && ml->font == null)
+ {
+ if ((ml->font = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
+ {
+ ml->font = null;
+ p->w_FontL = p->w_charsets[p->w_ss ? p->w_ss : p->w_Charset] = 0;
+ p->w_FontR = p->w_charsets[p->w_ss ? p->w_ss : p->w_CharsetR] = 0;
+ mc->font = mc->fontx = p->w_rend.font = 0;
+ WMsg(p, 0, "Warning: no space for font - turned off");
+ }
+ }
+ if (mc->fontx && ml->fontx == null)
+ {
+ if ((ml->fontx = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
+ {
+ ml->fontx = null;
+ mc->fontx = 0;
+ }
+ }
+#endif
+#ifdef COLOR
+ if (mc->color && ml->color == null)
+ {
+ if ((ml->color = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
+ {
+ ml->color = null;
+ mc->color = p->w_rend.color = 0;
+ WMsg(p, 0, "Warning: no space for color - turned off");
+ }
+ }
+# ifdef COLORS256
+ if (mc->colorx && ml->colorx == null)
+ {
+ if ((ml->colorx = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
+ {
+ ml->colorx = null;
+ mc->colorx = p->w_rend.colorx = 0;
+ WMsg(p, 0, "Warning: no space for extended colors - turned off");
+ }
+ }
+# endif
+#endif
+}
+
+/*****************************************************************/
+
+#ifdef DW_CHARS
+# define MKillDwRight(p, ml, x) \
+ if (dw_right(ml, x, p->w_encoding)) \
+ { \
+ if (x > 0) \
+ copy_mchar2mline(&mchar_blank, ml, x - 1); \
+ copy_mchar2mline(&mchar_blank, ml, x); \
+ }
+
+# define MKillDwLeft(p, ml, x) \
+ if (dw_left(ml, x, p->w_encoding)) \
+ { \
+ copy_mchar2mline(&mchar_blank, ml, x); \
+ copy_mchar2mline(&mchar_blank, ml, x + 1); \
+ }
+#else
+# define MKillDwRight(p, ml, x) ;
+# define MKillDwLeft(p, ml, x) ;
+#endif
+
+static void
+MScrollH(p, n, y, xs, xe, bce)
+struct win *p;
+int n, y, xs, xe, bce;
+{
+ struct mline *ml;
+
+ if (n == 0)
+ return;
+ ml = &p->w_mlines[y];
+ MKillDwRight(p, ml, xs);
+ MKillDwLeft(p, ml, xe);
+ if (n > 0)
+ {
+ if (xe - xs + 1 > n)
+ {
+ MKillDwRight(p, ml, xs + n);
+ bcopy_mline(ml, xs + n, xs, xe + 1 - xs - n);
+ }
+ else
+ n = xe - xs + 1;
+ clear_mline(ml, xe + 1 - n, n);
+#ifdef COLOR
+ if (bce)
+ MBceLine(p, y, xe + 1 - n, n, bce);
+#endif
+ }
+ else
+ {
+ n = -n;
+ if (xe - xs + 1 > n)
+ {
+ MKillDwLeft(p, ml, xe - n);
+ bcopy_mline(ml, xs, xs + n, xe + 1 - xs - n);
+ }
+ else
+ n = xe - xs + 1;
+ clear_mline(ml, xs, n);
+#ifdef COLOR
+ if (bce)
+ MBceLine(p, y, xs, n, bce);
+#endif
+ }
+}
+
+static void
+MScrollV(p, n, ys, ye, bce)
+struct win *p;
+int n, ys, ye, bce;
+{
+ int i, cnt1, cnt2;
+ struct mline tmp[256];
+ struct mline *ml;
+
+ if (n == 0)
+ return;
+ if (n > 0)
+ {
+ if (ye - ys + 1 < n)
+ n = ye - ys + 1;
+ if (n > 256)
+ {
+ MScrollV(p, n - 256, ys, ye, bce);
+ n = 256;
+ }
+#ifdef COPY_PASTE
+ if (compacthist)
+ {
+ ye = MFindUsedLine(p, ye, ys);
+ if (ye - ys + 1 < n)
+ n = ye - ys + 1;
+ if (n <= 0)
+ return;
+ }
+#endif
+ /* Clear lines */
+ ml = p->w_mlines + ys;
+ for (i = ys; i < ys + n; i++, ml++)
+ {
+#ifdef COPY_PASTE
+ if (ys == p->w_top)
+ WAddLineToHist(p, ml);
+#endif
+ if (ml->attr != null)
+ free(ml->attr);
+ ml->attr = null;
+#ifdef FONT
+ if (ml->font != null)
+ free(ml->font);
+ ml->font = null;
+ if (ml->fontx != null)
+ free(ml->fontx);
+ ml->fontx = null;
+#endif
+#ifdef COLOR
+ if (ml->color != null)
+ free(ml->color);
+ ml->color = null;
+# ifdef COLORS256
+ if (ml->colorx != null)
+ free(ml->colorx);
+ ml->colorx = null;
+# endif
+#endif
+ bclear((char *)ml->image, p->w_width + 1);
+#ifdef COLOR
+ if (bce)
+ MBceLine(p, i, 0, p->w_width, bce);
+#endif
+ }
+ /* switch 'em over */
+ cnt1 = n * sizeof(struct mline);
+ cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
+ if (cnt1 && cnt2)
+ Scroll((char *)(p->w_mlines + ys), cnt1, cnt2, (char *)tmp);
+ }
+ else
+ {
+ n = -n;
+ if (ye - ys + 1 < n)
+ n = ye - ys + 1;
+ if (n > 256)
+ {
+ MScrollV(p, - (n - 256), ys, ye, bce);
+ n = 256;
+ }
+
+ ml = p->w_mlines + ye;
+ /* Clear lines */
+ for (i = ye; i > ye - n; i--, ml--)
+ {
+ if (ml->attr != null)
+ free(ml->attr);
+ ml->attr = null;
+#ifdef FONT
+ if (ml->font != null)
+ free(ml->font);
+ ml->font = null;
+ if (ml->fontx != null)
+ free(ml->fontx);
+ ml->fontx = null;
+#endif
+#ifdef COLOR
+ if (ml->color != null)
+ free(ml->color);
+ ml->color = null;
+# ifdef COLORS256
+ if (ml->colorx != null)
+ free(ml->colorx);
+ ml->colorx = null;
+# endif
+#endif
+ bclear((char *)ml->image, p->w_width + 1);
+#ifdef COLOR
+ if (bce)
+ MBceLine(p, i, 0, p->w_width, bce);
+#endif
+ }
+ cnt1 = n * sizeof(struct mline);
+ cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
+ if (cnt1 && cnt2)
+ Scroll((char *)(p->w_mlines + ys), cnt2, cnt1, (char *)tmp);
+ }
+}
+
+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
+MClearArea(p, xs, ys, xe, ye, bce)
+struct win *p;
+int xs, ys, xe, ye, bce;
+{
+ int n, y;
+ int xxe;
+ struct mline *ml;
+
+ /* Check for zero-height window */
+ if (ys < 0 || ye < ys)
+ return;
+
+ /* check for magic margin condition */
+ if (xs >= p->w_width)
+ xs = p->w_width - 1;
+ if (xe >= p->w_width)
+ xe = p->w_width - 1;
+
+ MKillDwRight(p, p->w_mlines + ys, xs);
+ MKillDwLeft(p, p->w_mlines + ye, xe);
+
+ ml = p->w_mlines + ys;
+ for (y = ys; y <= ye; y++, ml++)
+ {
+ xxe = (y == ye) ? xe : p->w_width - 1;
+ n = xxe - xs + 1;
+ if (n > 0)
+ clear_mline(ml, xs, n);
+#ifdef COLOR
+ if (n > 0 && bce)
+ MBceLine(p, y, xs, xs + n - 1, bce);
+#endif
+ xs = 0;
+ }
+}
+
+static void
+MInsChar(p, c, x, y)
+struct win *p;
+struct mchar *c;
+int x, y;
+{
+ int n;
+ struct mline *ml;
+
+ ASSERT(x >= 0 && x < p->w_width);
+ MFixLine(p, y, c);
+ ml = p->w_mlines + y;
+ n = p->w_width - x - 1;
+ MKillDwRight(p, ml, x);
+ if (n > 0)
+ {
+ MKillDwRight(p, ml, p->w_width - 1);
+ bcopy_mline(ml, x, x + 1, n);
+ }
+ copy_mchar2mline(c, ml, x);
+#ifdef DW_CHARS
+ if (c->mbcs)
+ {
+ if (--n > 0)
+ {
+ MKillDwRight(p, ml, p->w_width - 1);
+ bcopy_mline(ml, x + 1, x + 2, n);
+ }
+ copy_mchar2mline(c, ml, x + 1);
+ ml->image[x + 1] = c->mbcs;
+# ifdef UTF8
+ if (p->w_encoding != UTF8)
+ ml->font[x + 1] |= 0x80;
+ else if (p->w_encoding == UTF8 && c->mbcs)
+ {
+ ml->font[x + 1] = c->mbcs;
+ ml->fontx[x + 1] = 0;
+ }
+# else
+ ml->font[x + 1] |= 0x80;
+# endif
+ }
+#endif
+}
+
+static void
+MPutChar(p, c, x, y)
+struct win *p;
+struct mchar *c;
+int x, y;
+{
+ struct mline *ml;
+
+ MFixLine(p, y, c);
+ ml = &p->w_mlines[y];
+ MKillDwRight(p, ml, x);
+ MKillDwLeft(p, ml, x);
+ copy_mchar2mline(c, ml, x);
+#ifdef DW_CHARS
+ if (c->mbcs)
+ {
+ MKillDwLeft(p, ml, x + 1);
+ copy_mchar2mline(c, ml, x + 1);
+ ml->image[x + 1] = c->mbcs;
+# ifdef UTF8
+ if (p->w_encoding != UTF8)
+ ml->font[x + 1] |= 0x80;
+ else if (p->w_encoding == UTF8 && c->mbcs)
+ {
+ ml->font[x + 1] = c->mbcs;
+ ml->fontx[x + 1] = 0;
+ }
+# else
+ ml->font[x + 1] |= 0x80;
+# endif
+ }
+#endif
+}
+
+
+static void
+MWrapChar(p, c, y, top, bot, ins)
+struct win *p;
+struct mchar *c;
+int y, top, bot;
+int ins;
+{
+ struct mline *ml;
+ int bce;
+
+#ifdef COLOR
+ bce = rend_getbg(c);
+#else
+ bce = 0;
+#endif
+ MFixLine(p, y, c);
+ ml = &p->w_mlines[y];
+ copy_mchar2mline(&mchar_null, ml, p->w_width);
+ if (y == bot)
+ MScrollV(p, 1, top, bot, bce);
+ else if (y < p->w_height - 1)
+ y++;
+ if (ins)
+ MInsChar(p, c, 0, y);
+ else
+ MPutChar(p, c, 0, y);
+}
+
+static void
+MPutStr(p, s, n, r, x, y)
+struct win *p;
+char *s;
+int n;
+struct mchar *r;
+int x, y;
+{
+ struct mline *ml;
+ int i;
+ unsigned char *b;
+
+ if (n <= 0)
+ return;
+ MFixLine(p, y, r);
+ ml = &p->w_mlines[y];
+ MKillDwRight(p, ml, x);
+ MKillDwLeft(p, ml, x + n - 1);
+ bcopy(s, (char *)ml->image + x, n);
+ if (ml->attr != null)
+ {
+ b = ml->attr + x;
+ for (i = n; i-- > 0;)
+ *b++ = r->attr;
+ }
+#ifdef FONT
+ if (ml->font != null)
+ {
+ b = ml->font + x;
+ for (i = n; i-- > 0;)
+ *b++ = r->font;
+ }
+ if (ml->fontx != null)
+ {
+ b = ml->fontx + x;
+ for (i = n; i-- > 0;)
+ *b++ = r->fontx;
+ }
+#endif
+#ifdef COLOR
+ if (ml->color != null)
+ {
+ b = ml->color + x;
+ for (i = n; i-- > 0;)
+ *b++ = r->color;
+ }
+# ifdef COLORS256
+ if (ml->colorx != null)
+ {
+ b = ml->colorx + x;
+ for (i = n; i-- > 0;)
+ *b++ = r->colorx;
+ }
+# endif
+#endif
+}
+
+#ifdef COLOR
+static void
+MBceLine(p, y, xs, xe, bce)
+struct win *p;
+int y, xs, xe, bce;
+{
+ struct mchar mc;
+ struct mline *ml;
+ int x;
+
+ mc = mchar_null;
+ rend_setbg(&mc, bce);
+ MFixLine(p, y, &mc);
+ ml = p->w_mlines + y;
+# ifdef COLORS16
+ if (mc.attr)
+ for (x = xs; x <= xe; x++)
+ ml->attr[x] = mc.attr;
+# endif
+ if (mc.color)
+ for (x = xs; x <= xe; x++)
+ ml->color[x] = mc.color;
+# ifdef COLORS256
+ if (mc.colorx)
+ for (x = xs; x <= xe; x++)
+ ml->colorx[x] = mc.colorx;
+# endif
+}
+#endif
+
+
+#ifdef COPY_PASTE
+static void
+WAddLineToHist(wp, ml)
+struct win *wp;
+struct mline *ml;
+{
+ register unsigned 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);
+
+#ifdef FONT
+ q = ml->font; o = hml->font; hml->font = q; ml->font = null;
+ if (o != null)
+ free(o);
+ q = ml->fontx; o = hml->fontx; hml->fontx = q; ml->fontx = null;
+ if (o != null)
+ free(o);
+#endif
+
+#ifdef COLOR
+ q = ml->color; o = hml->color; hml->color = q; ml->color = null;
+ if (o != null)
+ free(o);
+# ifdef COLORS256
+ q = ml->colorx; o = hml->colorx; hml->colorx = q; ml->colorx = null;
+ if (o != null)
+ free(o);
+# endif
+#endif
+
+ if (++wp->w_histidx >= wp->w_histheight)
+ wp->w_histidx = 0;
+ if (wp->w_scrollback_height < wp->w_histheight)
+ ++wp->w_scrollback_height;
+}
+#endif
+
+int
+MFindUsedLine(p, ye, ys)
+struct win *p;
+int ys, ye;
+{
+ int y;
+ struct mline *ml = p->w_mlines + ye;
+
+ debug2("MFindUsedLine: %d %d\n", ye, ys);
+ for (y = ye; y >= ys; y--, ml--)
+ {
+ if (bcmp((char*)ml->image, blank, p->w_width))
+ break;
+ if (ml->attr != null && bcmp((char*)ml->attr, null, p->w_width))
+ break;
+#ifdef COLOR
+ if (ml->color != null && bcmp((char*)ml->color, null, p->w_width))
+ break;
+# ifdef COLORS256
+ if (ml->colorx != null && bcmp((char*)ml->colorx, null, p->w_width))
+ break;
+# endif
+#endif
+#ifdef UTF8
+ if (p->w_encoding == UTF8)
+ {
+ if (ml->font != null && bcmp((char*)ml->font, null, p->w_width))
+ break;
+ if (ml->fontx != null && bcmp((char*)ml->fontx, null, p->w_width))
+ break;
+ }
+#endif
+ }
+ debug1("MFindUsedLine returning %d\n", y);
+ return y;
+}
+
+
+/*
+ *====================================================================*
+ *====================================================================*
+ */
+
+/*
+ * Tricky: send only one bell even if the window is displayed
+ * more than once.
+ */
+void
+WBell(p, visual)
+struct win *p;
+int visual;
+{
+ struct canvas *cv;
+ if (displays == NULL)
+ p->w_bell = BELL_DONE;
+ for (display = displays; display; display = display->d_next)
+ {
+ for (cv = D_cvlist; cv; cv = cv->c_next)
+ if (cv->c_layer->l_bottom == &p->w_layer)
+ break;
+ if (cv && !visual)
+ AddCStr(D_BL);
+ else if (cv && D_VB)
+ AddCStr(D_VB);
+ else
+ p->w_bell = visual ? BELL_VISUAL : BELL_FOUND;
+ }
+}
+
+/*
+ * This should be reverse video.
+ * Only change video if window is fore.
+ * Because it is used in some termcaps to emulate
+ * a visual bell we do this hack here.
+ * (screen uses \Eg as special vbell sequence)
+ */
+static void
+WReverseVideo(p, on)
+struct win *p;
+int on;
+{
+ struct canvas *cv;
+ for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
+ {
+ display = cv->c_display;
+ if (cv != D_forecv)
+ continue;
+ ReverseVideo(on);
+ if (!on && p->w_revvid && !D_CVR)
+ {
+ if (D_VB)
+ AddCStr(D_VB);
+ else
+ p->w_bell = BELL_VISUAL;
+ }
+ }
+}
+
+void
+WMsg(p, err, str)
+struct win *p;
+int err;
+char *str;
+{
+ extern struct layer *flayer;
+ struct layer *oldflayer = flayer;
+ flayer = &p->w_layer;
+ LMsg(err, "%s", str);
+ flayer = oldflayer;
+}
+
+void
+WChangeSize(p, w, h)
+struct win *p;
+int w, h;
+{
+ int wok = 0;
+ struct canvas *cv;
+
+ if (p->w_layer.l_cvlist == 0)
+ {
+ /* window not displayed -> works always */
+ ChangeWindowSize(p, w, h, p->w_histheight);
+ return;
+ }
+ for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
+ {
+ display = cv->c_display;
+ if (p != D_fore)
+ continue; /* change only fore */
+ if (D_CWS)
+ break;
+ if (D_CZ0 && (w == Z0width || w == Z1width))
+ wok = 1;
+ }
+ if (cv == 0 && wok == 0) /* can't change any display */
+ return;
+ if (!D_CWS)
+ h = p->w_height;
+ ChangeWindowSize(p, w, h, p->w_histheight);
+ for (display = displays; display; display = display->d_next)
+ {
+ if (p == D_fore)
+ {
+ if (D_cvlist && D_cvlist->c_next == 0)
+ ResizeDisplay(w, h);
+ else
+ ResizeDisplay(w, D_height);
+ ResizeLayersToCanvases(); /* XXX Hmm ? */
+ continue;
+ }
+ for (cv = D_cvlist; cv; cv = cv->c_next)
+ if (cv->c_layer->l_bottom == &p->w_layer)
+ break;
+ if (cv)
+ Redisplay(0);
+ }
+}
+
+static int
+WindowChangedCheck(s, what, hp)
+char *s;
+int what;
+int *hp;
+{
+ int h = 0;
+ int l;
+ while(*s)
+ {
+ if (*s++ != (hp ? '%' : '\005'))
+ continue;
+ l = 0;
+ s += (*s == '+');
+ s += (*s == '-');
+ while (*s >= '0' && *s <= '9')
+ s++;
+ if (*s == 'L')
+ {
+ s++;
+ l = 0x100;
+ }
+ if (*s == 'h')
+ h = 1;
+ if (*s == what || ((*s | l) == what) || what == 'd')
+ break;
+ if (*s)
+ s++;
+ }
+ if (hp)
+ *hp = h;
+ return *s ? 1 : 0;
+}
+
+void
+WindowChanged(p, what)
+struct win *p;
+int what;
+{
+ int inwstr, inhstr, inlstr;
+ int inwstrh = 0, inhstrh = 0, inlstrh = 0;
+ int got, ox, oy;
+ struct display *olddisplay = display;
+ struct canvas *cv;
+
+ inwstr = inhstr = 0;
+
+ if (what == 'f')
+ {
+ WindowChanged((struct win *)0, 'w'|0x100);
+ WindowChanged((struct win *)0, 'W'|0x100);
+ }
+
+ if (what)
+ {
+ inwstr = WindowChangedCheck(captionstring, what, &inwstrh);
+ inhstr = WindowChangedCheck(hstatusstring, what, &inhstrh);
+ inlstr = WindowChangedCheck(wliststr, what, &inlstrh);
+ }
+ else
+ {
+ inwstr = inhstr = 0;
+ inlstr = 1;
+ }
+
+ if (p == 0)
+ {
+ for (display = displays; display; display = display->d_next)
+ {
+ ox = D_x;
+ oy = D_y;
+ for (cv = D_cvlist; cv; cv = cv->c_next)
+ {
+ if (inlstr || (inlstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
+ WListUpdatecv(cv, (struct win *)0);
+ p = Layer2Window(cv->c_layer);
+ if (inwstr || (inwstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
+ if (cv->c_ye + 1 < D_height)
+ RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
+ }
+ p = D_fore;
+ if (inhstr || (inhstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
+ RefreshHStatus();
+ if (ox != -1 && oy != -1)
+ GotoPos(ox, oy);
+ }
+ display = olddisplay;
+ return;
+ }
+
+ if (p->w_hstatus && *p->w_hstatus && (inwstrh || inhstrh || inlstrh) && WindowChangedCheck(p->w_hstatus, what, (int *)0))
+ {
+ inwstr |= inwstrh;
+ inhstr |= inhstrh;
+ inlstr |= inlstrh;
+ }
+ if (!inwstr && !inhstr && !inlstr)
+ return;
+ for (display = displays; display; display = display->d_next)
+ {
+ got = 0;
+ ox = D_x;
+ oy = D_y;
+ for (cv = D_cvlist; cv; cv = cv->c_next)
+ {
+ if (inlstr)
+ WListUpdatecv(cv, p);
+ if (Layer2Window(cv->c_layer) != p)
+ continue;
+ got = 1;
+ if (inwstr && cv->c_ye + 1 < D_height)
+ RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
+ }
+ if (got && inhstr && p == D_fore)
+ RefreshHStatus();
+ if (ox != -1 && oy != -1)
+ GotoPos(ox, oy);
+ }
+ display = olddisplay;
+}
+
diff --git a/ansi.h b/ansi.h
new file mode 100644
index 0000000..e816beb
--- /dev/null
+++ b/ansi.h
@@ -0,0 +1,175 @@
+/* Copyright (c) 2008, 2009
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Micah Cowan (micah@cowan.name)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
+ * 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 3, 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, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ * $Id$ GNU
+ */
+
+#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)
+
+#ifdef COLORS16
+/* pseudo attributes */
+# define ATTR_BFG 6 /* bright foreground */
+# define ATTR_BBG 7 /* bright background */
+# define A_BFG (1<<ATTR_BFG)
+# define A_BBG (1<<ATTR_BBG)
+#endif
+
+/*
+ * Parser state
+ */
+/* keep state_t and state_t_string in sync! */
+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 */
+};
+
+/* keep string_t and string_t_string in sync! */
+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 ENCODINGS
+
+#define KANJI ('B' & 037)
+#define KANJI0212 ('D' & 037)
+#define KANA 'I'
+
+#define EUC_JP 1
+#define SJIS 2
+#define EUC_KR 3
+#define EUC_CN 4
+#define BIG5 5
+#define KOI8R 6
+#define CP1251 7
+#define GBK 20
+
+#define EUC EUC_JP
+
+#endif
+
+#ifdef UTF8
+#undef UTF8
+#define UTF8 8
+#endif
+
+#ifdef UTF8
+# define UCS_REPL 0xfffd /* character for illegal codes */
+# define UCS_REPL_DW 0xff1f /* character for illegal codes */
+# define UCS_HIDDEN 0xffff
+#endif
+
+#ifdef DW_CHARS
+# define is_dw_font(f) ((f) && ((f) & 0x60) == 0)
+
+# ifdef UTF8
+# define dw_left(ml, x, enc) ((enc == UTF8) ? \
+ (unsigned char)(ml)->font[(x) + 1] == 0xff && (unsigned char)(ml)->image[(x) + 1] == 0xff : \
+ ((unsigned char)(ml)->font[x] & 0x1f) != 0 && ((unsigned char)(ml)->font[x] & 0xe0) == 0 \
+ )
+# define dw_right(ml, x, enc) ((enc == UTF8) ? \
+ (unsigned char)(ml)->font[x] == 0xff && (unsigned char)(ml)->image[x] == 0xff : \
+ ((unsigned char)(ml)->font[x] & 0xe0) == 0x80 \
+ )
+# else
+# define dw_left(ml, x, enc) ( \
+ ((unsigned char)(ml)->font[x] & 0x1f) != 0 && ((unsigned char)(ml)->font[x] & 0xe0) == 0 \
+ )
+# define dw_right(ml, x, enc) ( \
+ ((unsigned char)(ml)->font[x] & 0xe0) == 0x80 \
+ )
+# endif /* UTF8 */
+#else
+# define dw_left(ml, x, enc) 0
+# define dw_right(ml, x, enc) 0
+#endif
diff --git a/attacher.c b/attacher.c
new file mode 100644
index 0000000..18ba43c
--- /dev/null
+++ b/attacher.c
@@ -0,0 +1,1117 @@
+/* Copyright (c) 2008, 2009
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Micah Cowan (micah@cowan.name)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
+ * 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 3, 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, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ */
+
+#include "config.h"
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <signal.h>
+#include "screen.h"
+#include "extern.h"
+
+#include <pwd.h>
+
+static int WriteMessage __P((int, struct msg *));
+static sigret_t AttacherSigInt __P(SIGPROTOARG);
+#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
+static sigret_t AttachSigCont __P(SIGPROTOARG);
+
+extern int real_uid, real_gid, eff_uid, eff_gid;
+extern int ServerSocket;
+extern struct display *displays;
+extern char *SockName, *SockMatch, SockPath[];
+extern char HostName[];
+extern struct passwd *ppp;
+extern char *attach_tty, *attach_term, *LoginName, *preselect;
+/* Indicator whether the current tty exists in another namespace. */
+extern bool attach_tty_is_in_new_ns;
+/* Content of the tty symlink when attach_tty_is_in_new_ns == true. */
+extern char attach_tty_name_in_ns[];
+extern int xflag, dflag, rflag, quietflag, adaptflag;
+extern struct mode attach_Mode;
+extern struct NewWindow nwin_options;
+extern int MasterPid, attach_fd;
+
+#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
+
+
+static int ContinuePlease;
+
+static sigret_t
+AttachSigCont SIGDEFARG
+{
+ debug("SigCont()\n");
+ ContinuePlease = 1;
+ SIGRETURN;
+}
+
+static int QueryResult;
+
+static sigret_t
+QueryResultSuccess SIGDEFARG
+{
+ QueryResult = 1;
+ SIGRETURN;
+}
+
+static sigret_t
+QueryResultFail SIGDEFARG
+{
+ QueryResult = 2;
+ SIGRETURN;
+}
+
+/*
+ * 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!
+ *
+ * if type == MSG_ATTACH and sockets are used, attaches
+ * tty filedescriptor.
+ */
+
+static int
+WriteMessage(s, m)
+int s;
+struct msg *m;
+{
+ int r, l = sizeof(*m);
+ bool is_socket;
+
+ is_socket = IsSocket(SockPath);
+ if (is_socket && m->type == MSG_ATTACH)
+ return SendAttachMsg(s, m, attach_fd);
+
+ while(l > 0)
+ {
+ r = write(s, (char *)m + (sizeof(*m) - l), l);
+ if (r == -1 && errno == EINTR)
+ continue;
+ if (r == -1 || r == 0)
+ return -1;
+ l -= r;
+ }
+ return 0;
+}
+
+
+int
+Attach(how)
+int how;
+{
+ int n, lasts;
+ struct msg m;
+ struct stat st;
+ char *s;
+ bool is_socket;
+
+ 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;
+ if (setgid(real_gid) || setuid(real_uid))
+ Panic(errno, "setuid/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;
+#ifdef HAVE_SETRESUID
+ if (setresuid(multi_uid, own_uid, multi_uid))
+ Panic(errno, "setresuid");
+#else
+ xseteuid(multi_uid);
+ xseteuid(own_uid);
+#endif
+ 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;
+ m.protocol_revision = MSG_REVISION;
+ strncpy(m.m_tty, attach_tty_is_in_new_ns ? attach_tty_name_in_ns : attach_tty, sizeof(m.m_tty) - 1);
+ m.m_tty[sizeof(m.m_tty) - 1] = 0;
+
+ is_socket = IsSocket(SockPath);
+ if (how == MSG_WINCH)
+ {
+ if ((lasts = MakeClientSocket(0, is_socket)) >= 0)
+ {
+ WriteMessage(lasts, &m);
+ close(lasts);
+ }
+ return 0;
+ }
+
+ if (how == MSG_CONT)
+ {
+ if ((lasts = MakeClientSocket(0, is_socket)) < 0)
+ {
+ Panic(0, "Sorry, cannot contact session \"%s\" again.\r\n",
+ SockName);
+ }
+ }
+ else
+ {
+ n = FindSocket(&lasts, (int *)0, (int *)0, SockMatch, &is_socket);
+ switch (n)
+ {
+ case 0:
+ if (rflag && (rflag & 1) == 0)
+ return 0;
+ if (quietflag)
+ eexit(10);
+ if (SockMatch && *SockMatch) {
+ Panic(0, "There is no screen to be %sed matching %s.",
+ xflag ? "attach" :
+ dflag ? "detach" :
+ "resum", SockMatch);
+ } else {
+ Panic(0, "There is no screen to be %sed.",
+ xflag ? "attach" :
+ dflag ? "detach" :
+ "resum");
+ }
+ /* NOTREACHED */
+ case 1:
+ break;
+ default:
+ if (rflag < 3)
+ {
+ 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
+ {
+ if (setuid(real_uid))
+ Panic(errno, "setuid");
+ }
+#if defined(MULTIUSER) && defined(USE_SETEUID)
+ else
+ {
+ /* This call to xsetuid should also set the saved uid */
+ xseteuid(real_uid); /* multi_uid, allow backend to send signals */
+ }
+#endif
+ eff_uid = real_uid;
+ if (setgid(real_gid))
+ Panic(errno, "setgid");
+ eff_gid = real_gid;
+
+ debug2("Attach: uid %d euid %d\n", (int)getuid(), (int)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)", (int)st.st_mode);
+
+ /*
+ * Change: if -x or -r ignore failing -d
+ */
+ if ((xflag || rflag) && dflag && (st.st_mode & 0700) == 0600)
+ dflag = 0;
+
+ /*
+ * Without -x, the mode must match.
+ * With -x the mode is irrelevant unless -d.
+ */
+ 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_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 there is no password for the session, or the user enters the correct
+ * password, then we get a SIGCONT. Otherwise we get a SIG_BYE */
+ signal(SIGCONT, AttachSigCont);
+ if (WriteMessage(lasts, &m))
+ Panic(errno, "WriteMessage");
+ close(lasts);
+ while (!ContinuePlease)
+ pause(); /* wait for SIGCONT */
+ signal(SIGCONT, SIG_DFL);
+ ContinuePlease = 0;
+ 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, is_socket)) == -1)
+ Panic(0, "Cannot contact screen again. Sigh.");
+ m.type = how;
+ }
+#endif
+ ASSERT(how == MSG_ATTACH || how == MSG_CONT);
+ strncpy(m.m.attach.envterm, attach_term, MAXTERMLEN);
+ m.m.attach.envterm[MAXTERMLEN] = 0;
+ 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.esc = DefaultEsc;
+ m.m.attach.meta_esc = DefaultMetaEsc;
+ strncpy(m.m.attach.preselect, preselect ? preselect : "", sizeof(m.m.attach.preselect) - 1);
+ m.m.attach.preselect[sizeof(m.m.attach.preselect) - 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);
+ m.m.attach.encoding = nwin_options.encoding > 0 ? nwin_options.encoding + 1 : 0;
+
+#ifdef REMOTE_DETACH
+#ifdef POW_DETACH
+ if (dflag == 2)
+ m.m.attach.detachfirst = MSG_POW_DETACH;
+ else
+#endif
+ if (dflag)
+ m.m.attach.detachfirst = MSG_DETACH;
+ else
+#endif
+ m.m.attach.detachfirst = MSG_ATTACH;
+
+#ifdef MULTIUSER
+ /* setup CONT signal handler to repair the terminal mode */
+ if (multi && (how == MSG_ATTACH || how == MSG_CONT))
+ signal(SIGCONT, AttachSigCont);
+#endif
+
+ if (WriteMessage(lasts, &m))
+ Panic(errno, "WriteMessage");
+ close(lasts);
+ debug1("Attach(%d): sent\n", m.type);
+#ifdef MULTIUSER
+ if (multi && (how == MSG_ATTACH || how == MSG_CONT))
+ {
+ while (!ContinuePlease)
+ pause(); /* wait for SIGCONT */
+ signal(SIGCONT, SIG_DFL);
+ ContinuePlease = 0;
+# 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;
+}
+
+
+static int AttacherPanic = 0;
+
+#ifdef DEBUG
+static sigret_t
+AttacherChld SIGDEFARG
+{
+ AttacherPanic = 1;
+ SIGRETURN;
+}
+#endif
+
+static sigret_t
+AttacherSigAlarm SIGDEFARG
+{
+#ifdef DEBUG
+ static int tick_cnt = 0;
+ if ((tick_cnt = (tick_cnt + 1) % 4) == 0)
+ debug("tick\n");
+#endif
+ SIGRETURN;
+}
+
+/*
+ * the frontend's Interrupt handler
+ * we forward SIGINT to the poor backend
+ */
+static sigret_t
+AttacherSigInt SIGDEFARG
+{
+ signal(SIGINT, AttacherSigInt);
+ Kill(MasterPid, SIGINT);
+ SIGRETURN;
+}
+
+/*
+ * Unfortunately 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;
+ bool is_socket;
+
+ 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));
+ strncpy(m.m_tty, attach_tty_is_in_new_ns ? attach_tty_name_in_ns : attach_tty, sizeof(m.m_tty) - 1);
+ m.m_tty[sizeof(m.m_tty) - 1] = 0;
+ debug1("attach_tty is %s\n", attach_tty);
+ m.m.detach.dpid = getpid();
+ m.type = MSG_HANGUP;
+ m.protocol_revision = MSG_REVISION;
+ is_socket = IsSocket(SockPath);
+ if ((s = MakeClientSocket(0, is_socket)) >= 0)
+ {
+ WriteMessage(s, &m);
+ close(s);
+ }
+ }
+#ifdef MULTIUSER
+ if (tty_oldmode >= 0)
+ {
+ if (setuid(own_uid))
+ Panic(errno, "setuid");
+ 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
+ if (setgid(real_gid))
+ Panic(errno, "setgid");
+#ifdef MULTIUSER
+ if (setuid(own_uid))
+ Panic(errno, "setuid");
+#else
+ if (setuid(real_uid))
+ Panic(errno, "setuid");
+#endif
+ /* 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
+
+#if defined(DEBUG) && defined(SIG_NODEBUG)
+static sigret_t
+AttacherNoDebug SIGDEFARG
+{
+ debug("AttacherNoDebug()\n");
+ signal(SIG_NODEBUG, AttacherNoDebug);
+ if (dfp)
+ {
+ debug("debug: closing debug file.\n");
+ fflush(dfp);
+ fclose(dfp);
+ dfp = NULL;
+ }
+ SIGRETURN;
+}
+#endif /* SIG_NODEBUG */
+
+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
+#if defined(DEBUG) && defined(SIG_NODEBUG)
+ signal(SIG_NODEBUG, AttacherNoDebug);
+#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 (;;)
+ {
+ signal(SIGALRM, AttacherSigAlarm);
+ alarm(15);
+ pause();
+ alarm(0);
+ if (kill(MasterPid, 0) < 0 && errno != EPERM)
+ {
+ debug1("attacher: Panic! MasterPid %d does not exist.\n", MasterPid);
+ AttacherPanic++;
+ }
+ if (AttacherPanic)
+ {
+ fcntl(0, F_SETFL, 0);
+ SetTTY(0, &attach_Mode);
+ printf("\nError: Cannot find master process to attach to!\n");
+ eexit(1);
+ }
+#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();
+ if (setgid(real_gid))
+ Panic(errno, "setgid");
+#ifdef MULTIUSER
+ if (setuid(own_uid))
+ Panic(errno, "setuid");
+#else
+ if (setuid(real_uid))
+ Panic(errno, "setuid");
+#endif
+ 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 == SIGCHLD ? SIG_DFL : 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 */
+ displays = 0; /* beware of Panic() */
+ ServerSocket = -1;
+ if (setgid(real_gid))
+ Panic(errno, "setgid");
+#ifdef MULTIUSER
+ if (setuid(own_uid))
+ Panic(errno, "setuid");
+#else
+ if (setuid(real_uid)) /* this should be done already */
+ Panic(errno, "setuid");
+#endif
+ closeallfiles(0); /* important: /etc/shadow may be open */
+ execl(prg, "SCREEN-LOCK", NULL);
+ exit(errno);
+ }
+ if (pid == -1)
+ 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("%s", 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 */
+
+#ifdef USE_PAM
+
+/*
+ * PAM support by Pablo Averbuj <pablo@averbuj.com>
+ */
+
+#include <security/pam_appl.h>
+
+static int PAM_conv __P((int, const struct pam_message **, struct pam_response **, void *));
+
+static int
+PAM_conv(num_msg, msg, resp, appdata_ptr)
+int num_msg;
+const struct pam_message **msg;
+struct pam_response **resp;
+void *appdata_ptr;
+{
+ int replies = 0;
+ struct pam_response *reply = NULL;
+
+ reply = malloc(sizeof(struct pam_response)*num_msg);
+ if (!reply)
+ return PAM_CONV_ERR;
+ #define COPY_STRING(s) (s) ? strdup(s) : NULL
+
+ for (replies = 0; replies < num_msg; replies++)
+ {
+ switch (msg[replies]->msg_style)
+ {
+ case PAM_PROMPT_ECHO_OFF:
+ /* wants password */
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = appdata_ptr ? strdup((char *)appdata_ptr) : 0;
+ break;
+ case PAM_TEXT_INFO:
+ /* ignore the informational mesage */
+ /* but first clear out any drek left by malloc */
+ reply[replies].resp = NULL;
+ break;
+ case PAM_PROMPT_ECHO_ON:
+ /* user name given to PAM already */
+ /* fall through */
+ default:
+ /* unknown or PAM_ERROR_MSG */
+ free(reply);
+ return PAM_CONV_ERR;
+ }
+ }
+ *resp = reply;
+ return PAM_SUCCESS;
+}
+
+static struct pam_conv PAM_conversation = {
+ &PAM_conv,
+ NULL
+};
+
+
+#endif
+
+/* -- original copyright by Luigi Cannelloni 1985 (luigi@faui70.UUCP) -- */
+static void
+screen_builtin_lck()
+{
+ char fullname[100], *cp1, message[100 + 100];
+#ifdef USE_PAM
+ pam_handle_t *pamh = 0;
+ int pam_error;
+ char *tty_name;
+#endif
+ char *pass = 0, mypass[16 + 1], salt[3];
+ int using_pam = 1;
+
+#ifdef USE_PAM
+ if (!ppp->pw_uid)
+ {
+#endif
+ using_pam = 0;
+ pass = ppp->pw_passwd;
+ if (pass == 0 || *pass == 0)
+ {
+ if ((pass = getpass("Key: ")))
+ {
+ strncpy(mypass, pass, sizeof(mypass) - 1);
+ mypass[sizeof(mypass) - 1] = 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;
+ }
+
+ salt[0] = 'A' + (int)(time(0) % 26);
+ salt[1] = 'A' + (int)((time(0) >> 6) % 26);
+ salt[2] = 0;
+ pass = crypt(mypass, salt);
+ if (!pass)
+ {
+ fprintf(stderr, "crypt() error.\007\n");
+ sleep(2);
+ return;
+ }
+ pass = ppp->pw_passwd = SaveStr(pass);
+ }
+#ifdef USE_PAM
+ }
+#endif
+
+ debug("screen_builtin_lck looking in gcos field\n");
+ strncpy(fullname, ppp->pw_gecos, sizeof(fullname) - 9);
+ fullname[sizeof(fullname) - 9] = 0;
+
+ if ((cp1 = index(fullname, ',')) != NULL)
+ *cp1 = '\0';
+ if ((cp1 = index(fullname, '&')) != NULL)
+ {
+ strncpy(cp1, ppp->pw_name, 8);
+ cp1[8] = 0;
+ if (*cp1 >= 'a' && *cp1 <= 'z')
+ *cp1 -= 'a' - 'A';
+ }
+
+ sprintf(message, "Screen used by %s%s<%s> on %s.\nPassword:\007",
+ fullname, fullname[0] ? " " : "", ppp->pw_name, HostName);
+
+ /* 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 */
+ }
+ if (using_pam)
+ {
+#ifdef USE_PAM
+ PAM_conversation.appdata_ptr = cp1;
+ pam_error = pam_start("screen", ppp->pw_name, &PAM_conversation, &pamh);
+ if (pam_error != PAM_SUCCESS)
+ AttacherFinit(SIGARG); /* goodbye */
+
+ if (strncmp(attach_tty, "/dev/", 5) == 0)
+ tty_name = attach_tty + 5;
+ else
+ tty_name = attach_tty;
+ pam_error = pam_set_item(pamh, PAM_TTY, tty_name);
+ if (pam_error != PAM_SUCCESS)
+ AttacherFinit(SIGARG); /* goodbye */
+
+ pam_error = pam_authenticate(pamh, 0);
+ pam_end(pamh, pam_error);
+ PAM_conversation.appdata_ptr = 0;
+ if (pam_error == PAM_SUCCESS)
+ break;
+#endif
+ }
+ else
+ {
+ char *buf = crypt(cp1, pass);
+ if (buf && !strncmp(buf, pass, strlen(pass)))
+ break;
+ }
+ debug("screen_builtin_lck: NO!!!!!\n");
+ bzero(cp1, strlen(cp1));
+ }
+ bzero(cp1, strlen(cp1));
+ debug("password ok.\n");
+}
+
+#endif /* LOCK */
+
+
+void
+SendCmdMessage(sty, match, av, query)
+char *sty;
+char *match;
+char **av;
+int query;
+{
+ int i, s;
+ struct msg m;
+ char *p;
+ int len, n;
+ bool is_socket;
+
+ if (sty == 0)
+ {
+ i = FindSocket(&s, (int *)0, (int *)0, match, &is_socket);
+ if (i == 0)
+ Panic(0, "No screen session found.");
+ if (i != 1)
+ Panic(0, "Use -S to specify a session.");
+ }
+ else
+ {
+#ifdef NAME_MAX
+ if (strlen(sty) > NAME_MAX)
+ sty[NAME_MAX] = 0;
+#endif
+ if (strlen(sty) > 2 * MAXSTR - 1)
+ sty[2 * MAXSTR - 1] = 0;
+ sprintf(SockPath + strlen(SockPath), "/%s", sty);
+ is_socket = IsSocket(SockPath);
+ if ((s = MakeClientSocket(1, is_socket)) == -1)
+ exit(1);
+ }
+ bzero((char *)&m, sizeof(m));
+ m.type = query ? MSG_QUERY : MSG_COMMAND;
+ if (attach_tty)
+ {
+ strncpy(m.m_tty, attach_tty_is_in_new_ns ? attach_tty_name_in_ns : attach_tty, sizeof(m.m_tty) - 1);
+ m.m_tty[sizeof(m.m_tty) - 1] = 0;
+ }
+ p = m.m.command.cmd;
+ n = 0;
+ for (; *av && n < MAXARGS - 1; ++av, ++n)
+ {
+ len = strlen(*av) + 1;
+ if (p + len >= m.m.command.cmd + sizeof(m.m.command.cmd) - 1)
+ break;
+ strcpy(p, *av);
+ p += len;
+ }
+ *p = 0;
+ m.m.command.nargs = n;
+ strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1);
+ m.m.command.auser[sizeof(m.m.command.auser) - 1] = 0;
+ m.protocol_revision = MSG_REVISION;
+ strncpy(m.m.command.preselect, preselect ? preselect : "", sizeof(m.m.command.preselect) - 1);
+ m.m.command.preselect[sizeof(m.m.command.preselect) - 1] = 0;
+ m.m.command.apid = getpid();
+ debug1("SendCommandMsg writing '%s'\n", m.m.command.cmd);
+ if (query)
+ {
+ /* Create a server socket so we can get back the result */
+ char *sp = SockPath + strlen(SockPath);
+ char query[] = "-queryX";
+ char c;
+ int r = -1;
+ for (c = 'A'; c <= 'Z'; c++)
+ {
+ query[6] = c;
+ strcpy(sp, query); /* XXX: strncpy? */
+ if ((r = MakeServerSocket(is_socket)) >= 0)
+ break;
+ }
+ if (r < 0)
+ {
+ for (c = '0'; c <= '9'; c++)
+ {
+ query[6] = c;
+ strcpy(sp, query);
+ if ((r = MakeServerSocket(is_socket)) >= 0)
+ break;
+ }
+ }
+
+ if (r < 0)
+ Panic(0, "Could not create a listening socket to read the results.");
+
+ strncpy(m.m.command.writeback, SockPath, sizeof(m.m.command.writeback) - 1);
+ m.m.command.writeback[sizeof(m.m.command.writeback) - 1] = '\0';
+
+ /* Send the message, then wait for a response */
+ signal(SIGCONT, QueryResultSuccess);
+ signal(SIG_BYE, QueryResultFail);
+ if (WriteMessage(s, &m))
+ Msg(errno, "write");
+ close(s);
+ while (!QueryResult)
+ pause();
+ signal(SIGCONT, SIG_DFL);
+ signal(SIG_BYE, SIG_DFL);
+
+ /* Read the result and spit it out to stdout */
+ ReceiveRaw(r);
+ unlink(SockPath);
+ if (QueryResult == 2) /* An error happened */
+ exit(1);
+ }
+ else
+ {
+ if (WriteMessage(s, &m))
+ Msg(errno, "write");
+ close(s);
+ }
+}
+
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..68f4a17
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+autoreconf -i
diff --git a/braille.c b/braille.c
new file mode 100644
index 0000000..93a3ee1
--- /dev/null
+++ b/braille.c
@@ -0,0 +1,945 @@
+/*
+ * A braille interface to unix tty terminals
+ *
+ * Authors: Hadi Bargi Rangin bargi@dots.physics.orst.edu
+ * Bill Barry barryb@dots.physics.orst.edu
+ *
+ * Copyright (c) 1995 by Science Access Project, Oregon State University.
+ *
+ *
+ * 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 3, 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, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+#include "braille.h"
+
+#ifdef HAVE_BRAILLE
+
+
+extern int bd_init_powerbraille_40 __P((void));
+extern int bd_init_powerbraille_80 __P((void));
+extern int bd_init_navigator_40 __P((void));
+
+extern struct layer *flayer;
+extern struct display *displays, *display;
+extern char *rc_name;
+
+
+
+
+/* global variables */
+
+struct braille_display bd;
+
+struct bd_type {
+ char *name;
+ int (*init) __P((void));
+};
+
+static struct bd_type bd_typelist[] =
+{
+ {"powerbraille_40", bd_init_powerbraille_40},
+ {"powerbraille_80", bd_init_powerbraille_80},
+ {"navigator_40" , bd_init_navigator_40}
+};
+
+static void position_braille_cursor __P((void));
+static int initialize_braille_display_type __P((char *));
+static int open_braille_device __P(());
+static int load_braille_table __P((char *));
+static void bd_signal __P((void));
+static void bd_bc_left __P((void));
+static void bd_bc_right __P((void));
+static void bd_bc_up __P((void));
+static void bd_bc_down __P((void));
+static void bd_upper_left __P((void));
+static void bd_upper_right __P((void));
+static void bd_lower_left __P((void));
+static void bd_lower_right __P((void));
+static int bd_do_search __P((int, int, int));
+static void bd_normalize __P((int, int));
+static void bd_readev_fn __P((struct event *, char *));
+static void bd_writeev_fn __P((struct event *, char *));
+static void bd_selectev_fn __P((struct event *, char *));
+
+static unsigned char btable_local [] =
+{
+ 0xC8,0xC1,0xC3,0xC9,0xD9,0xD1,0xCB,0xDB,
+ 0xD3,0xCA,0xDA,0xC5,0xC7,0xCD,0xDD,0xD5,
+ 0xCF,0xDF,0xD7,0xCE,0xDE,0xE5,0xE7,0xFA,
+ 0xED,0xFD,0xF5,0xEA,0xF3,0xFB,0xD8,0xF8,
+ 0x00,0x2E,0x10,0x3C,0x2B,0x29,0x2F,0x04,
+ 0x37,0x3E,0x21,0x2C,0x20,0x24,0x28,0x0C,
+ 0x34,0x02,0x06,0x12,0x32,0x22,0x16,0x36,
+ 0x26,0x14,0x31,0x30,0x23,0x3F,0x1C,0x39,
+ 0x48,0x41,0x43,0x49,0x59,0x51,0x4B,0x5B,
+ 0x53,0x4A,0x5A,0x45,0x47,0x4D,0x5D,0x55,
+ 0x4F,0x5F,0x57,0x4E,0x5E,0x65,0x67,0x7A,
+ 0x6D,0x7D,0x75,0x6A,0x73,0x7B,0x58,0x38,
+ 0x08,0x01,0x03,0x09,0x19,0x11,0x0B,0x1B,
+ 0x13,0x0A,0x1A,0x05,0x07,0x0D,0x1D,0x15,
+ 0x0F,0x1F,0x17,0x0E,0x1E,0x25,0x27,0x3A,
+ 0x2D,0x3D,0x35,0x2A,0x33,0x3B,0x18,0x78,
+ 0x88,0x81,0x83,0x89,0x99,0x91,0x8B,0x9B,
+ 0x93,0x8A,0x9A,0x85,0x87,0x8D,0x9D,0x95,
+ 0x8F,0x9F,0x97,0x8E,0x9E,0xA5,0xA7,0xBA,
+ 0xAD,0xBD,0xB5,0xAA,0xB3,0xBB,0x98,0xB8,
+ 0x40,0x6E,0x50,0x7C,0x6B,0x69,0x6F,0x44,
+ 0x77,0x7E,0x61,0x6C,0x60,0x64,0x68,0x4C,
+ 0x74,0x42,0x46,0x52,0x72,0x62,0x56,0x76,
+ 0x66,0x54,0x71,0x70,0x63,0x7F,0x5C,0x79,
+ 0xC0,0xEE,0xD0,0xFC,0xEB,0xE9,0xEF,0xC4,
+ 0xF7,0xFE,0xE1,0xEC,0xE0,0xE4,0xE8,0xCC,
+ 0xF4,0xC2,0xC6,0xD2,0xF2,0xE2,0xD6,0xF6,
+ 0xE6,0xD4,0xF1,0xF0,0xE3,0xFF,0xDC,0xF9,
+ 0x80,0xAE,0x90,0xBC,0xAB,0xA9,0xAF,0x84,
+ 0xB7,0xBE,0xA1,0xAC,0xA0,0xA4,0xA8,0x8C,
+ 0xB4,0x82,0x86,0x92,0xB2,0xA2,0x96,0xB6,
+ 0xA6,0x94,0xB1,0xB0,0xA3,0xBF,0x9C,0xB9
+};
+
+void
+InitBraille()
+{
+ bd.bd_start_braille=0;
+ bd.bd_port = 0;
+ bd.bd_braille_table = SaveStr("internal us-braille.tbl");
+ bd.bd_type = 0;
+ bd.bd_baud = 9600;
+ bd.bd_bell = 1;
+ bd.bd_eightdot = 1;
+ bd.bd_info = 0;
+ bd.bd_link = 1;
+ bd.bd_ncells = 0;
+ bd.bd_width = 0;
+ bd.bd_ncrc = 1;
+ bd.bd_scroll = 1;
+ bd.bd_skip = 0;
+ bd.bd_using_braille = 0;
+ bd.bd_obuflen = 0;
+ bd.bd_fd = -1;
+ bcopy((char *)btable_local, bd.bd_btable, 256);
+}
+
+static int
+initialize_braille_display_type(s)
+char *s;
+{
+ int i;
+
+ for (i = 0; i < sizeof(bd_typelist)/sizeof(*bd_typelist); i++)
+ if (!strcmp(s, bd_typelist[i].name))
+ break;
+ if (i == sizeof(bd_typelist)/sizeof(*bd_typelist))
+ {
+ Msg(0, "No entry for bd_type: %s ", s);
+ return -1;
+ }
+ bd.bd_type = bd_typelist[i].name;
+ if ((*bd_typelist[i].init)())
+ return -1;
+
+ if (!bd.bd_width)
+ bd.bd_width = bd.bd_ncells;
+
+ return 0;
+}
+
+void
+StartBraille()
+{
+ bd.bd_dpy = displays;
+
+ debug("StartBraille called\n");
+ evdeq(&bd.bd_readev);
+ evdeq(&bd.bd_writeev);
+ evdeq(&bd.bd_selectev);
+ bd.bd_using_braille = 0;
+
+ if (!bd.bd_start_braille)
+ return;
+
+ if (bd.bd_type == 0 || bd.bd_port == 0)
+ return;
+
+ if (bd.bd_fd < 0 && open_braille_device())
+ {
+ Msg(0, "bd_port turned off");
+ free(bd.bd_port);
+ bd.bd_port = 0;
+ return;
+ }
+
+ /* check if braille display is connected and turned on */
+ if (bd.bd_response_test())
+ {
+ Msg(0, "Make sure that braille display is connected and turned on. ");
+ Msg(0, "start_braille turned off");
+ bd.bd_start_braille = 0;
+ }
+ else
+ {
+ bd.bd_using_braille = 1;
+ bd.bd_readev.fd = bd.bd_writeev.fd = bd.bd_fd;
+ bd.bd_readev.type = EV_READ;
+ bd.bd_writeev.type = EV_WRITE;
+ bd.bd_selectev.type = EV_ALWAYS;
+ bd.bd_readev.data = bd.bd_writeev.data = bd.bd_selectev.data = (char *)&bd;
+ bd.bd_readev.handler = bd_readev_fn;
+ bd.bd_writeev.handler = bd_writeev_fn;
+ bd.bd_selectev.handler = bd_selectev_fn;
+ evenq(&bd.bd_readev);
+ bd.bd_writeev.condpos = &bd.bd_obuflen;
+ bd.bd_writeev.condneg = 0;
+ evenq(&bd.bd_writeev);
+ bd.bd_selectev.pri = -20;
+ evenq(&bd.bd_selectev);
+ }
+}
+
+
+static int
+load_braille_table(tablename)
+char *tablename;
+{
+ int i, j, c, p;
+ FILE *fp;
+ char buffer[80], a[10];
+
+ if ((fp = secfopen(tablename, "r")) == 0)
+ {
+ Msg(errno, "Braille table not found: %s ", tablename);
+ return -1;
+ }
+ bzero(bd.bd_btable, 256);
+ /* format:
+ * Dec Hex Braille Description
+ * 7 07 (12-45--8) BEL
+ */
+ while (fgets(buffer, sizeof(buffer), fp))
+ {
+ if (buffer[0] == '#')
+ continue;
+ sscanf(buffer,"%d %x %8s", &i, &j, a);
+ if (i < 0 || i > 255)
+ continue;
+ for (j=1, p=1, c=0; j<9; j++, p*=2)
+ if (a[j] == '0' + j)
+ c += p;
+ bd.bd_btable[i] = c;
+ }
+ fclose(fp);
+ return 0;
+}
+
+
+static int
+open_braille_device(s)
+char *s;
+{
+ char str[256];
+
+ sprintf(str, "%d cs8 -istrip ixon ixoff", bd.bd_baud);
+ bd.bd_fd = OpenTTY(bd.bd_port, str);
+ if (bd.bd_fd == -1)
+ {
+ Msg(errno, "open comm port failed: %s ", bd.bd_port);
+ return -1;
+ }
+ fcntl(bd.bd_fd, F_SETFL, FNBLOCK);
+ return 0;
+}
+
+
+static void
+position_braille_cursor()
+{
+ int sx = bd.bd_sx;
+ int bx = BD_FORE->w_bd_x;
+ int eol = BD_FORE->w_width;
+ int w = bd.bd_width;
+
+ if (bd.bd_scroll)
+ bx = sx - w + bd.bd_ncrc; /* keep rc centered in window */
+ else
+ bx = w * (int)(sx / w); /* increase bc in integral steps */
+
+ if (bx > eol - w)
+ bx = eol - w;
+ if (bx < 0)
+ bx = 0;
+ BD_FORE->w_bd_x = bx;
+ BD_FORE->w_bd_y = bd.bd_sy;
+}
+
+
+void
+RefreshBraille()
+{
+ int i, y, xs, xe;
+ int cursor_pos;
+
+ if (!bd.bd_using_braille)
+ return;
+ if (!BD_FORE)
+ return;
+ bcopy(bd.bd_line, bd.bd_oline, bd.bd_ncells);
+ bd.bd_refreshing = 1;
+ flayer = bd.bd_dpy->d_forecv->c_layer;
+ bd.bd_sx = flayer->l_x;
+ bd.bd_sy = flayer->l_y;
+ display = bd.bd_dpy;
+ if ((D_obufp != D_obuf) && bd.bd_link)
+ {
+ /* jump to real cursor */
+ debug("calling position_braille_cursor\n");
+ position_braille_cursor();
+ }
+ bclear(bd.bd_line, bd.bd_ncells);
+
+ y = BD_FORE->w_bd_y;
+ xs = BD_FORE->w_bd_x;
+
+ if (bd.bd_info & 1)
+ {
+ sprintf(bd.bd_line, "%02d%02d", (BD_FORE->w_bd_x + 1) % 100, (BD_FORE->w_bd_y + 1) % 100);
+ bd.bd_line[4] = ' ';
+ }
+ if (bd.bd_info & 2)
+ {
+ sprintf(bd.bd_line + bd.bd_ncells - 4, "%02d%02d",(bd.bd_sx +1) % 100, (bd.bd_sy +1) % 100);
+ }
+
+ xe = xs + bd.bd_width - 1;
+
+ if (xs > flayer->l_width - 1)
+ xs = flayer->l_width - 1;
+ if (xe > flayer->l_width - 1)
+ xe = flayer->l_width - 1;
+
+ if (D_status)
+ {
+ sprintf(bd.bd_line, "**%-*.*s", bd.bd_ncells - 2, bd.bd_ncells - 2, D_status_lastmsg ? D_status_lastmsg : "unknown msg");
+ xs = xe = -1;
+ }
+ else if (xs <= xe)
+ {
+ LayRedisplayLine(-1, xs, xe, 1);
+ LayRedisplayLine(y, xs, xe, 1);
+ }
+
+ debug1("Braille: got >%s<\n", bd.bd_line);
+
+ bd.bd_refreshing = 0;
+
+ if (y == bd.bd_sy && xs <= bd.bd_sx && bd.bd_sx <= xe)
+ cursor_pos = bd.bd_sx - xs + (bd.bd_info & 1 ? 4 : 0);
+ else
+ cursor_pos = bd.bd_ncells;
+ for (i = 0; i < bd.bd_ncells; i++)
+ if (bd.bd_line[i] != bd.bd_oline[i])
+ break;
+ if (bd.bd_cursorpos != cursor_pos || i < bd.bd_ncells)
+ bd.write_line_braille(bd.bd_line, bd.bd_ncells, cursor_pos);
+ bd.bd_cursorpos = cursor_pos;
+}
+
+
+/**********************************************************************
+ *
+ */
+
+/*
+ * So, why is there a Flush() down below? The reason is simple: the
+ * cursor warp (if bd_link is on) checks the obuf to see if something
+ * happened. If there would be no Flush, screen would warp the
+ * bd cursor if a bd movement command tries to ring the bell.
+ * (In other words: this is a gross hack!)
+ */
+static void
+bd_signal()
+{
+ if (!bd.bd_bell)
+ return;
+ display = bd.bd_dpy;
+ if (D_obufp != D_obuf)
+ AddCStr(D_BL);
+ else
+ {
+ AddCStr(D_BL);
+ Flush(0);
+ }
+}
+
+static int
+bd_do_search(y, xs, xe)
+int y, xs, xe;
+{
+ int oy = BD_FORE->w_bd_y;
+
+ if (!bd.bd_skip) /* no skip mode, found it */
+ {
+ if (xs > xe)
+ return 0;
+ bd.bd_searchmin = xs;
+ bd.bd_searchmax = xe;
+ return 1;
+ }
+ flayer = bd.bd_dpy->d_forecv->c_layer;
+ bd.bd_searchmax = -1;
+ bd.bd_searchmin = flayer->l_width;
+ if (xs <= xe)
+ {
+ BD_FORE->w_bd_y = y; /* stupid hack */
+ bd.bd_refreshing = bd.bd_searching = 1;
+ bd.bd_searchstart = xs;
+ bd.bd_searchend = xe;
+ LayRedisplayLine(-1, xs, xe, 1);
+ LayRedisplayLine(y, xs, xe, 1);
+ bd.bd_refreshing = bd.bd_searching = 0;
+ BD_FORE->w_bd_y = oy;
+ }
+ return bd.bd_searchmax >= 0;
+}
+
+static void
+bd_normalize(x, y)
+int x, y;
+{
+ if (x > BD_FORE->w_width - bd.bd_width)
+ x = BD_FORE->w_width - bd.bd_width;
+ if (x < 0)
+ x = 0;
+ if (y < 0)
+ {
+ bd_signal();
+ y = 0;
+ }
+ if (y >= BD_FORE->w_height)
+ {
+ bd_signal();
+ y = BD_FORE->w_height - 1;
+ }
+ if (x != BD_FORE->w_bd_x || y != BD_FORE->w_bd_y)
+ bd.bd_moved = 1;
+ BD_FORE->w_bd_x = x;
+ BD_FORE->w_bd_y = y;
+}
+
+static void
+bd_bc_left()
+{
+ int bx = BD_FORE->w_bd_x, by = BD_FORE->w_bd_y;
+ int ex;
+
+ ex = bx - 1;
+ bx = 0;
+ for (; by >= 0; by--)
+ {
+ if (bd_do_search(by, 0, ex))
+ {
+ if (!bd.bd_skip && by != BD_FORE->w_bd_y)
+ bd_signal();
+ bx = bd.bd_searchmax + 1 - bd.bd_width;
+ break;
+ }
+ ex = BD_FORE->w_width - 1;
+ }
+ bd_normalize(bx, by);
+}
+
+static void
+bd_bc_right()
+{
+ int bx = BD_FORE->w_bd_x, by = BD_FORE->w_bd_y;
+ int sx;
+
+ sx = bx + bd.bd_width;
+ bx = BD_FORE->w_width - bd.bd_width;
+ for (; by < BD_FORE->w_height; by++)
+ {
+ if (bd_do_search(by, sx, BD_FORE->w_width - 1))
+ {
+ if (!bd.bd_skip && by != BD_FORE->w_bd_y)
+ bd_signal();
+ bx = bd.bd_searchmin;
+ break;
+ }
+ sx = 0;
+ }
+ bd_normalize(bx, by);
+}
+
+static void
+bd_bc_up()
+{
+ int bx = BD_FORE->w_bd_x, by = BD_FORE->w_bd_y;
+
+ for (by--; by >= 0; by--)
+ if (bd_do_search(by, bx, bx + bd.bd_width - 1))
+ break;
+ bd_normalize(bx, by);
+}
+
+static void
+bd_bc_down()
+{
+ int bx = BD_FORE->w_bd_x, by = BD_FORE->w_bd_y;
+
+ for (by++; by < BD_FORE->w_height; by++)
+ if (bd_do_search(by, bx, bx + bd.bd_width - 1))
+ break;
+ bd_normalize(bx, by);
+}
+
+
+static void
+bd_upper_left()
+{
+ bd_normalize(0, 0);
+}
+
+
+static void
+bd_upper_right()
+{
+ bd_normalize(BD_FORE->w_width - bd.bd_width, 0);
+}
+
+
+static void
+bd_lower_left()
+{
+ bd_normalize(0, BD_FORE->w_height - 1);
+}
+
+
+static void
+bd_lower_right()
+{
+ bd_normalize(BD_FORE->w_width - bd.bd_width, BD_FORE->w_height -1);
+}
+
+/**********************************************************************
+ *
+ */
+
+
+static void
+bd_check(x, c)
+int x, c;
+{
+ if (c == ' ')
+ return;
+ if (x < bd.bd_searchstart || x > bd.bd_searchend)
+ return;
+ if (x > bd.bd_searchmax)
+ bd.bd_searchmax = x;
+ if (x < bd.bd_searchmin)
+ bd.bd_searchmin = x;
+}
+
+
+
+/*ARGSUSED*/
+void
+BGotoPos(la, x, y)
+struct layer *la;
+int x, y;
+{
+}
+
+/*ARGSUSED*/
+void
+BCDisplayLine(la, ml, y, xs, xe, isblank)
+struct layer *la;
+struct mline *ml;
+int y, xs, xe;
+int isblank;
+{
+ int x;
+ int sx, ex;
+ char *l;
+
+ if (y != BD_FORE->w_bd_y)
+ return;
+ if (bd.bd_searching)
+ {
+ for (x = xs; x <= xe; x++)
+ bd_check(x, ml->image[x]);
+ return;
+ }
+ l = bd.bd_line;
+ sx = BD_FORE->w_bd_x;
+ ex = sx + bd.bd_width - 1;
+ if (bd.bd_info & 1)
+ l += 4;
+ for (x = xs; x <= xe; x++)
+ if (x >= sx && x <= ex)
+ l[x - sx] = ml->image[x];
+}
+
+/*ARGSUSED*/
+void
+BPutChar(la, c, x, y)
+struct layer *la;
+struct mchar *c;
+int x, y;
+{
+ int sx, ex;
+ char *l;
+
+ if (y != BD_FORE->w_bd_y)
+ return;
+ if (bd.bd_searching)
+ {
+ bd_check(x, c->image);
+ return;
+ }
+ l = bd.bd_line;
+ sx = BD_FORE->w_bd_x;
+ ex = sx + bd.bd_width - 1;
+ if (bd.bd_info & 1)
+ l += 4;
+ if (x >= sx && x <= ex)
+ l[x - sx] = c->image;
+}
+
+/*ARGSUSED*/
+void
+BPutStr(la, s, n, r, x, y)
+struct layer *la;
+char *s;
+int n;
+struct mchar *r;
+int x, y;
+{
+ int sx, ex;
+ char *l;
+
+ if (y != BD_FORE->w_bd_y)
+ return;
+ if (bd.bd_searching)
+ {
+ for (; n > 0; n--, s++, x++)
+ bd_check(x, *s);
+ return;
+ }
+ l = bd.bd_line;
+ sx = BD_FORE->w_bd_x;
+ ex = sx + bd.bd_width - 1;
+ if (bd.bd_info & 1)
+ l += 4;
+ for (; n > 0; n--, s++, x++)
+ if (x >= sx && x <= ex)
+ l[x - sx] = *s;
+}
+
+
+
+/**********************************************************************
+ *
+ */
+
+static char *infonames[] = {"none", "bc", "sc", "bc+sc"};
+
+void
+DoBrailleAction(act, msgok)
+struct action *act;
+int msgok;
+{
+ int nr, dosig;
+ int n, l, o;
+ char *s, **args;
+ struct stat st;
+
+ nr = act->nr;
+ args = act->args;
+ dosig = display && !*rc_name;
+
+ switch(nr)
+ {
+ case RC_BD_BELL:
+ if (ParseSwitch(act, &bd.bd_bell) || !msgok)
+ {
+ bd_signal();
+ break;
+ }
+ Msg(0, bd.bd_bell ? "bd_bell is on." : "bd_bell is off.");
+ break;
+
+ case RC_BD_EIGHTDOT:
+ if (ParseSwitch(act, &bd.bd_eightdot) || !msgok)
+ break;
+ Msg(0, "switched to %d-dots system.", bd.bd_eightdot ? 8 : 6);
+ break;
+
+ case RC_BD_INFO:
+ n = bd.bd_info;
+ if (*args)
+ {
+ if (strlen(*args) == 4)
+ n = args[0][n] - '0';
+ else if (ParseNum(act, &n))
+ break;
+ }
+ if (n < 0 || n > 3)
+ {
+ Msg(0, "Out of range; 0 <= bd_info >= 3 ");
+ break;
+ }
+ /* bd_width at the beginning is unknown */
+ if (bd.bd_width == 0)
+ break;
+
+ o = (bd.bd_info * 2 + 2) & 12;
+ l = (n * 2 + 2) & 12;
+ if (l >= bd.bd_ncells)
+ {
+ Msg(0, "bd_info is too large for braille display.");
+ break;
+ }
+ if (l >= bd.bd_width + o)
+ {
+ Msg(0, "bd_info is too large for bd_width.");
+ break;
+ }
+ bd.bd_width += o - l;
+ bd.bd_info = n;
+
+ if (msgok)
+ Msg(0, "bd_info is %s.", infonames[n]);
+ position_braille_cursor();
+ break;
+
+ case RC_BD_LINK:
+ if (*args == 0 && bd.bd_moved)
+ bd.bd_link = 0;
+ if (ParseSwitch(act, &bd.bd_link))
+ break;
+ if (bd.bd_link)
+ {
+ bd.bd_moved = 0;
+ if (dosig)
+ bd_signal();
+ position_braille_cursor();
+ }
+ if (msgok)
+ Msg(0, bd.bd_link ? "bd_link is on." : "bd_link is off.");
+ break;
+
+ case RC_BD_SKIP:
+ if (ParseSwitch(act, &bd.bd_skip))
+ break;
+ if (bd.bd_skip && dosig)
+ bd_signal();
+ if (msgok)
+ Msg(0, bd.bd_skip ? "bd_skip is on." : "bd_skip is off.");
+ break;
+
+ case RC_BD_SCROLL:
+ if (ParseSwitch(act, &bd.bd_scroll) || !msgok)
+ {
+ position_braille_cursor();
+ break;
+ }
+ Msg(0, bd.bd_scroll ? "bd_scroll is on." : "bd_scroll is off.");
+ break;
+
+ case RC_BD_NCRC:
+ n = bd.bd_ncrc;
+ if (*args)
+ {
+ if (args[0][0] == '+')
+ n = (n + atoi(*args + 1)) % bd.bd_width + 1;
+ else if (args[0][0] == '-')
+ n = (n - atoi(*args + 1)) % bd.bd_width + 1;
+ else if (ParseNum(act, &n))
+ break;
+ }
+ if (n < 1 || n > bd.bd_width)
+ {
+ Msg(0, "Out of range; 1 <= bd_ncrc >= %d", bd.bd_width);
+ break;
+ }
+ bd.bd_ncrc = n;
+ if (msgok)
+ Msg(0, "bd_ncrc status is: %d ", bd.bd_ncrc);
+ position_braille_cursor();
+ break;
+
+ case RC_BD_BRAILLE_TABLE:
+ s = 0;
+ if (*args)
+ {
+ if (ParseSaveStr(act, &s))
+ break;
+ if (load_braille_table(s))
+ {
+ free(s);
+ break;
+ }
+ if (bd.bd_braille_table)
+ free(bd.bd_braille_table);
+ bd.bd_braille_table = s;
+ }
+ if (msgok)
+ Msg(0, "bd_braille_table is: %s ", bd.bd_braille_table);
+ break;
+
+ case RC_BD_PORT:
+ s = 0;
+ if (*args)
+ {
+ if (ParseSaveStr(act, &s))
+ break;
+
+ if (stat(s, &st) || !S_ISCHR(st.st_mode) || access(s, R_OK|W_OK))
+ {
+ Msg(0, "Cannot access braille device port %s", s);
+ free(s);
+ break;
+ }
+ if (bd.bd_fd >= 0)
+ close(bd.bd_fd);
+ bd.bd_fd = -1;
+ if (bd.bd_port)
+ free(bd.bd_port);
+ bd.bd_port = s;
+ }
+ if (msgok)
+ Msg(0, "bd_port is: %s ", bd.bd_port ? bd.bd_port : "not set");
+ StartBraille();
+ break;
+
+ case RC_BD_TYPE:
+ s = 0;
+ if (*args)
+ if (ParseSaveStr(act, &s) || initialize_braille_display_type(s))
+ break;
+ if (msgok)
+ Msg(0, "bd_type is: %s ", bd.bd_type ? bd.bd_type : "not set");
+ StartBraille();
+ break;
+
+ case RC_BD_START_BRAILLE:
+ if (ParseSwitch(act, &bd.bd_start_braille))
+ break;
+ if (msgok)
+ Msg(0, bd.bd_start_braille ? "bd_start_braille is on." : "bd_start_braille is off.");
+ StartBraille();
+ break;
+
+ case RC_BD_WIDTH:
+ n = bd.bd_width;
+ if (*args)
+ {
+ if (ParseNum(act, &n))
+ break;
+ }
+ if (n <= 0)
+ {
+ Msg(0, "Invalid value for bd_width: %d ", n);
+ break;
+ }
+ l = (bd.bd_info * 2 + 2) & 12;
+ if (n > bd.bd_ncells - l || n < l)
+ {
+ Msg(0, "bd_info is too large for bd_width.");
+ break;
+ }
+ bd.bd_width = n;
+ if (msgok)
+ Msg(0, "bd_width is: %d ", bd.bd_width);
+ break;
+
+ case RC_BD_BC_LEFT:
+ bd_bc_left();
+ break;
+
+ case RC_BD_BC_RIGHT:
+ bd_bc_right();
+ break;
+
+ case RC_BD_BC_UP:
+ bd_bc_up();
+ break;
+
+ case RC_BD_BC_DOWN:
+ bd_bc_down();
+ break;
+
+ case RC_BD_UPPER_LEFT:
+ bd_upper_left();
+ break;
+
+ case RC_BD_UPPER_RIGHT:
+ bd_upper_right();
+ break;
+
+ case RC_BD_LOWER_LEFT:
+ bd_lower_left();
+ break;
+
+ case RC_BD_LOWER_RIGHT:
+ bd_lower_right();
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+bd_readev_fn(ev, data)
+struct event *ev;
+char *data;
+{
+ bd.buttonpress();
+}
+
+static void
+bd_writeev_fn(ev, data)
+struct event *ev;
+char *data;
+{
+ int len;
+
+ if (bd.bd_obuflen == 0)
+ return;
+ if ((len = write(bd.bd_fd, bd.bd_obuf, bd.bd_obuflen)) < 0)
+ len = bd.bd_obuflen; /* dead braille display */
+ if ((bd.bd_obuflen -= len))
+ bcopy(bd.bd_obuf + len, bd.bd_obuf, bd.bd_obuflen);
+}
+
+static void
+bd_selectev_fn(ev, data)
+struct event *ev;
+char *data;
+{
+ RefreshBraille();
+}
+
+#endif /* HAVE_BRAILLE */
diff --git a/braille.h b/braille.h
new file mode 100644
index 0000000..266ad41
--- /dev/null
+++ b/braille.h
@@ -0,0 +1,83 @@
+/*
+ * Authors: Hadi Bargi Rangin bargi@dots.physics.orst.edu
+ * Bill Barry barryb@dots.physics.orst.edu
+ * Randy Lundquist randyl@dots.physics.orst.edu
+ *
+ * Modifications Copyright (c) 1995 by
+ * Science Access Project, Oregon State University.
+ *
+ * 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 3, 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, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ * $Id$ GNU
+ */
+
+#ifdef HAVE_BRAILLE
+
+extern void StartBraille __P((void));
+
+struct braille_display
+{
+ struct display *bd_dpy; /* display we are connected to */
+ int bd_start_braille; /* screenrc var to request to turn braille on */
+ int bd_using_braille; /* all is fine, use braille */
+ struct event bd_readev;
+ struct event bd_writeev;
+ struct event bd_selectev;
+ int bd_fd; /* file descriptor */
+ int bd_obuflen; /* current number of charactors in output buffer */
+ char bd_obuf[IOSIZE];
+ int bd_info; /* default, no info, 0,1,2,3 */
+ int bd_ncrc; /* default 1, numbers of cells on the right side of real cursor, 1...bd_width */
+ int bd_skip; /* default off, on/off */
+ int bd_link; /* default, linked, on/off */
+ int bd_width; /* length of braille display to use, <=bd_ncells */
+ int bd_scroll; /* default on, scroll on/off */
+ char *bd_braille_table; /* braille code */
+
+ int bd_bell; /* bell used for navigation on/off */
+ int bd_ncells; /* real number of cells on braille display */
+ int bd_eightdot; /* eightdot on/off */
+ int bd_baud; /* communication baudrate between port and braille display */
+ char *bd_port; /* serial port to use */
+ char *bd_type; /* kind of braille display */
+ double bd_version; /* rom version of braille display */
+ char bd_btable[256]; /* braille translation table */
+
+ /* functions which communicate with braille displays */
+ int (*write_line_braille) __P((char [],int, int));
+ void (*buttonpress) __P((void));
+ int (*bd_response_test) __P((void));
+
+ int bd_refreshing; /* are we doing a refresh? */
+ char bd_line[40+1]; /* bd_ncells chars displayed on braille */
+ int bd_cursorpos; /* cursor position on braille */
+ char bd_oline[40+1]; /* bd_ncells chars displayed on braille */
+ int bd_sx, bd_sy; /* screen cursor pos */
+ int bd_moved; /* used braille move keys */
+
+ int bd_searching; /* are we seaching (bd_skip is on) */
+ int bd_searchmax; /* search: max x */
+ int bd_searchmin; /* search: min x */
+ int bd_searchstart;
+ int bd_searchend;
+};
+
+extern struct braille_display bd;
+
+#define BD_FORE bd.bd_dpy->d_fore
+
+#endif
diff --git a/braille_tsi.c b/braille_tsi.c
new file mode 100644
index 0000000..8e05d75
--- /dev/null
+++ b/braille_tsi.c
@@ -0,0 +1,314 @@
+/* bd-tsi.c, TSI specific key bindings and display commands
+ *
+ * dotscreen
+ * A braille interface to unix tty terminals
+ * Authors: Hadi Bargi Rangin bargi@dots.physics.orst.edu
+ * Bill Barry barryb@dots.physics.orst.edu
+ *
+ * Copyright (c) 1995 by Science Access Project, Oregon State University.
+ *
+ *
+ * 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 3, 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, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ */
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+#include "braille.h"
+
+#ifdef HAVE_BRAILLE
+
+extern struct display *display;
+
+struct key2rc {
+ int key;
+ int nr;
+ char *arg1;
+ char *arg2;
+};
+
+static int tsi_ctype = 1; /* cursor type, 0,1,2 */
+
+static int tsi_line_type; /* indicates number of cells on powerbraille
+ display 01=20 cells 02=40 cells 03=80 cells */
+
+static int display_status_tsi __P((void));
+static int write_line_tsi __P((char*, int, int));
+static void buttonpress_tsi __P((structkey2rc*));
+static void buttonpress_navigator_40 __P((void));
+static void buttonpress_powerbraille_40 __P((void));
+static void buttonpress_powerbraille_80 __P((void));
+
+int
+bd_init_powerbraille_40()
+{
+ bd.write_line_braille = write_line_tsi;
+ bd.buttonpress = buttonpress_powerbraille_40;
+ bd.bd_response_test = display_status_tsi;
+ bd.bd_ncells = 40;
+ tsi_line_type = 2;
+ return 0;
+}
+
+int
+bd_init_powerbraille_80()
+{
+ bd.write_line_braille = write_line_tsi;
+ bd.buttonpress = buttonpress_powerbraille_80;
+ bd.bd_response_test = display_status_tsi;
+ bd.bd_ncells = 80;
+ tsi_line_type = 3;
+ return 0;
+}
+
+int
+bd_init_navigator_40()
+{
+ bd.write_line_braille = write_line_tsi;
+ bd.buttonpress = buttonpress_navigator_40;
+ bd.bd_response_test = display_status_tsi;
+ bd.bd_ncells = 40;
+ tsi_line_type = 2;
+ return 0;
+}
+
+static int
+display_status_tsi()
+{
+ char obuf[3], ibuf[20];
+ int r;
+
+ obuf[0] = 0xff;
+ obuf[1] = 0xff;
+ obuf[2] = 0x0a;
+ r = read(bd.bd_fd, ibuf, 20); /* flush the input port */
+ r = write(bd.bd_fd, obuf, 3);
+ if (r != 3)
+ return -1;
+
+ /* we have written to the display asking for a response
+ we wait 1 second for the response, read it and if no
+ response we wait 2 seconds, if still no response,
+ return -1 to indicate no braille display available */
+
+ sleep(1);
+ r = read(bd.bd_fd, ibuf, 2);
+ if (r == -1) {
+ sleep(2);
+ r = read(bd.bd_fd, ibuf, 2);
+ }
+
+ debug2("first chars from braille display %d %d\n", ibuf[0], ibuf[1]);
+ if (r != 2 || ibuf[0] != 0 || ibuf[1] != 5)
+ return -1;
+
+ r = read(bd.bd_fd, ibuf, 2);
+ if (r != 2)
+ return -1;
+
+ debug2("braille display size:%d dots:%d\n", ibuf[0], ibuf[1]);
+ bd.bd_ncells = (unsigned char)ibuf[0];
+ if (bd.bd_ncells <= 1)
+ return -1;
+
+ r = read(bd.bd_fd, ibuf, 1);
+ if (r != 1)
+ return -1;
+
+ if (ibuf[0] == 'V')
+ r = read(bd.bd_fd, ibuf, 3);
+ else
+ r = read(bd.bd_fd, ibuf + 1, 2) + 1;
+
+ if (r != 3)
+ return -1;
+
+ ibuf[3] = 0;
+ debug1("braille display version %s\n", ibuf);
+ bd.bd_version = atof(ibuf);
+ return 0;
+}
+
+static int
+write_line_tsi(char *bstr, int line_length, int cursor_pos)
+{
+ int obp, i;
+ bd.bd_obuf[0] = 0xff;
+ bd.bd_obuf[1] = 0xff;
+ bd.bd_obuf[2] = tsi_line_type;
+ bd.bd_obuf[3] = 0x07;
+ bd.bd_obuf[4] = cursor_pos;
+ bd.bd_obuf[5] = tsi_ctype;
+ obp = 6;
+
+ for (i = 0; i < line_length; i++) {
+ bd.bd_obuf[2*i + obp] = 0;
+ bd.bd_obuf[2*i + 1 + obp] = bd.bd_btable[(int)(unsigned char)bstr[i]];
+ }
+ for (i = line_length; i < bd.bd_ncells; i++) {
+ bd.bd_obuf[2*i + obp] = 0;
+ bd.bd_obuf[2*i + 1 + obp] = bd.bd_btable[(int)' '];
+ }
+
+ bd.bd_obuflen = 2*bd.bd_ncells + obp;
+ return 0;
+}
+
+static struct key2rc keys_navigator_40[] = {
+ {0x4000000, RC_STUFF, "-k", "kl"}, /* 1 */
+ {0x10000000, RC_STUFF, "-k", "kr"}, /* 3 */
+ {0x8000000, RC_STUFF, "-k", "ku"}, /* 2 */
+ {0x20000000, RC_STUFF, "-k", "kd"}, /* 4 */
+ {0x2000, RC_BD_BC_LEFT, 0, 0}, /* 6 */
+ {0x8000, RC_BD_BC_RIGHT, 0, 0}, /* 8 */
+ {0x4000, RC_BD_BC_UP, 0, 0}, /* 7 */
+ {0x10000, RC_BD_BC_DOWN, 0, 0}, /* 9 */
+ {0x6000, RC_BD_UPPER_LEFT, 0, 0}, /* 6, 7 */
+ {0xc000, RC_BD_UPPER_RIGHT, 0, 0}, /* 7, 8 */
+ {0x12000, RC_BD_LOWER_LEFT, 0, 0}, /* 6, 9 */
+ {0x18000, RC_BD_LOWER_RIGHT, 0, 0}, /* 8, 9 */
+ {0xa000, RC_BD_INFO, "1032", 0}, /* bc 6, 8 */
+ {0x14000000, RC_BD_INFO, "2301", 0}, /* sc 1, 3 */
+ {0x4008000, RC_BD_INFO, "3330", 0}, /* bc+sc 1, 8 */
+ {0x8010000, RC_BD_BELL, 0, 0}, /* 2, 9 */
+ {0x8004000, RC_BD_EIGHTDOT, 0, 0}, /* 2, 7 */
+ {0x40000000, RC_STUFF, "\015", 0}, /* 5 */
+ {0x20000, RC_BD_LINK, 0, 0}, /* 10 */
+ {0x10002000, RC_BD_SCROLL, 0, 0}, /* 3, 6 */
+ {0x20010000, RC_BD_NCRC, "+", 0}, /* 4, 9 */
+ {0x14000, RC_BD_SKIP, 0, 0}, /* 7, 9*/
+ {-1, RC_ILLEGAL, 0, 0}
+};
+
+static struct key2rc keys_powerbraille_40[] = {
+ {0x4000000, RC_STUFF, "-k", "kl"}, /* 1 */
+ {0x10000000, RC_STUFF, "-k", "kr"}, /* 3 */
+ {0x8000000, RC_STUFF, "-k", "ku"}, /* 2 */
+ {0x20000000, RC_STUFF, "-k", "kd"}, /* 4 */
+ {0x2000, RC_BD_BC_LEFT, 0, 0}, /* 6 */
+ {0x8000, RC_BD_BC_RIGHT, 0, 0}, /* 8 */
+ {0x4000, RC_BD_BC_UP, 0, 0}, /* 7 */
+ {0x10000, RC_BD_BC_DOWN, 0, 0}, /* 9 */
+ {0x8002000, RC_BD_UPPER_LEFT, 0, 0}, /* 2, 6 */
+ {0xc000, RC_BD_UPPER_RIGHT, 0, 0}, /* 7, 8 */
+ {0x20002000, RC_BD_LOWER_LEFT, 0, 0}, /* 3, 6 */
+ {0x18000, RC_BD_LOWER_RIGHT, 0, 0}, /* 8, 9 */
+ {0x8008000, RC_BD_INFO, "1032", 0}, /* bc 2, 8 */
+ {0x6000, RC_BD_INFO, "2301", 0}, /* 6, 7 */
+ {0x8004000, RC_BD_INFO, "3330", 0}, /* bc+sc 2, 7 */
+ {0x8010000, RC_BD_BELL, 0, 0}, /* 2, 9 */
+ {0x20008000, RC_BD_EIGHTDOT, 0, 0}, /* 4, 6 */
+ {0x40000000, RC_STUFF, "\015", 0}, /* 5 */
+ {0x20000, RC_BD_LINK, 0, 0}, /* 10 */
+ {0xa000, RC_BD_SCROLL, 0, 0}, /* 6, 8 */
+ {0x20010000, RC_BD_NCRC, "+", 0}, /* 4, 9 */
+ {0x20004000, RC_BD_SKIP, 0, 0}, /* 4, 7 */
+ {-1, RC_ILLEGAL, 0, 0}
+};
+
+static struct key2rc keys_powerbraille_80[] = {
+ {0x4000000, RC_STUFF, "-k", "kl"}, /* 1 */
+ {0x10000000, RC_STUFF, "-k", "kr"}, /* 3 */
+ {0x8000000, RC_STUFF, "-k", "ku"}, /* 2 */
+ {0x20000000, RC_STUFF, "-k", "kd"}, /* 4 */
+ {0x40000, RC_BD_BC_LEFT, 0, 0}, /* 6 */
+ {0x100000, RC_BD_BC_RIGHT, 0, 0}, /* 8 */
+ {0x4000, RC_BD_BC_UP, 0, 0}, /* 7 */
+ {0x10000, RC_BD_BC_DOWN, 0, 0}, /* 9 */
+ {0x44000, RC_BD_UPPER_LEFT, 0, 0}, /* 6, 7 */
+ {0x104000, RC_BD_UPPER_RIGHT, 0, 0}, /* 7, 8 */
+ {0x50000, RC_BD_LOWER_LEFT, 0, 0}, /* 6, 9 */
+ {0x110000, RC_BD_LOWER_RIGHT, 0, 0}, /* 8, 9 */
+ {0x8100000, RC_BD_INFO, "1032", 0}, /* 2, 8 */
+ {0x8040000, RC_BD_INFO, "2301", 0}, /* 2, 6 */
+ {0x140000, RC_BD_INFO, "3330", 0}, /* 6, 8 */
+ {0x8010000, RC_BD_BELL, 0, 0}, /* 2, 9 */
+ {0x8004000, RC_BD_EIGHTDOT, 0, 0}, /* 2, 7 */
+ {0x40000000, RC_STUFF, "\015", 0}, /* 5 */
+ {0x20000, RC_BD_LINK, 0, 0}, /* 10 */
+ {0x20004000, RC_BD_SCROLL, 0, 0}, /* 4, 7 */
+ {0x20010000, RC_BD_NCRC, "+", 0}, /* 4, 9 */
+ {0x40010000, RC_BD_SKIP, 0, 0}, /* 5, 9 */
+ {-1, RC_ILLEGAL, 0, 0}
+};
+
+static void
+buttonpress_tsi(struct key2rc *tab)
+{
+ int i, nb;
+ int bkeys;
+ unsigned char buf[10];
+ nb = read(bd.bd_fd, buf, 10);
+ debug1("buttonpress_tsi: read %d bytes\n", nb);
+ for (i = 0, bkeys = 0; i < nb; i++) {
+ switch (buf[i] & 0xE0) {
+ case 0x00: bkeys += ((int)(buf[i] & 0x1f)); break;
+ case 0x20: bkeys += ((int)(buf[i] & 0x1f) << 5); break;
+ case 0x40: bkeys += ((int)(buf[i] & 0x1f) << 9); break;
+ case 0x60: bkeys += ((int)(buf[i] & 0x1f) << 13); break;
+ case 0xA0: bkeys += ((int)(buf[i] & 0x1f) << 18); break;
+ case 0xC0: bkeys += ((int)(buf[i] & 0x1f) << 22); break;
+ case 0xE0: bkeys += ((int)(buf[i] & 0x1f) << 26); break;
+ default: break;
+ }
+ }
+ debug1("bkeys %x\n", bkeys);
+
+ for (i = 0; tab[i].key != -1; i++)
+ if (bkeys == tab[i].key)
+ break;
+
+ debug1("bkey index %d\n", i);
+
+ if (tab[i].key != -1 && tab[i].nr != RC_ILLEGAL) {
+ char *args[3];
+ int argl[2];
+
+ struct action act;
+ args[0] = tab[i].arg1;
+ args[1] = tab[i].arg2;
+ args[2] = 0;
+ argl[0] = args[0] ? strlen(args[0]) : 0;
+ argl[1] = args[1] ? strlen(args[1]) : 0;
+ act.nr = tab[i].nr;
+ act.args = args;
+ act.argl = argl;
+ display = bd.bd_dpy;
+ DoAction(&act, -2);
+ }
+}
+
+static void
+buttonpress_navigator_40()
+{
+ buttonpress_tsi(keys_navigator_40);
+}
+
+static void
+buttonpress_powerbraille_40()
+{
+ buttonpress_tsi(keys_powerbraille_40);
+}
+
+static void
+buttonpress_powerbraille_80()
+{
+ buttonpress_tsi(keys_powerbraille_80);
+}
+
+#endif /* HAVE_BRAILLE */
diff --git a/canvas.c b/canvas.c
new file mode 100644
index 0000000..919e94d
--- /dev/null
+++ b/canvas.c
@@ -0,0 +1,918 @@
+/* Copyright (c) 2008, 2009
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Micah Cowan (micah@cowan.name)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
+ * 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 3, 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, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ */
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+#include "canvas.h"
+#include "list_generic.h"
+
+extern struct display *display;
+extern struct win *fore, *windows;
+extern struct layer *flayer;
+extern int captionalways;
+extern struct LayFuncs BlankLf;
+extern int focusminwidth, focusminheight;
+
+static void
+CanvasInitBlank(cv)
+struct canvas *cv;
+{
+ cv->c_blank.l_cvlist = cv;
+ cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
+ cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
+ cv->c_blank.l_x = cv->c_blank.l_y = 0;
+ cv->c_blank.l_layfn = &BlankLf;
+ cv->c_blank.l_data = 0;
+ cv->c_blank.l_next = 0;
+ cv->c_blank.l_bottom = &cv->c_blank;
+ cv->c_blank.l_blocking = 0;
+ cv->c_layer = &cv->c_blank;
+}
+
+static void
+FreePerp(pcv)
+struct canvas *pcv;
+{
+ struct canvas *cv;
+
+ if (!pcv->c_slperp)
+ return;
+ cv = pcv->c_slperp;
+ cv->c_slprev = pcv->c_slprev;
+ if (cv->c_slprev)
+ cv->c_slprev->c_slnext = cv;
+ cv->c_slback = pcv->c_slback;
+ if (cv->c_slback && cv->c_slback->c_slperp == pcv)
+ cv->c_slback->c_slperp = cv;
+ cv->c_slorient = pcv->c_slorient;
+ cv->c_slweight = pcv->c_slweight;
+ while (cv->c_slnext)
+ {
+ cv = cv->c_slnext;
+ cv->c_slorient = pcv->c_slorient;
+ cv->c_slback = pcv->c_slback;
+ cv->c_slweight = pcv->c_slweight;
+ }
+ cv->c_slnext = pcv->c_slnext;
+ if (cv->c_slnext)
+ cv->c_slnext->c_slprev = cv;
+ LayerCleanupMemory(&pcv->c_blank);
+ free(pcv);
+}
+
+void
+FreeCanvas(cv)
+struct canvas *cv;
+{
+ struct viewport *vp, *nvp;
+ struct canvas **cvp;
+ struct win *p;
+
+ if (cv->c_slprev)
+ cv->c_slprev->c_slnext = cv->c_slnext;
+ if (cv->c_slnext)
+ cv->c_slnext->c_slprev = cv->c_slprev;
+ if (cv->c_slback && cv->c_slback->c_slperp == cv)
+ cv->c_slback->c_slperp = cv->c_slnext ? cv->c_slnext : cv->c_slprev;
+ if (cv->c_slperp)
+ {
+ while (cv->c_slperp)
+ FreeCanvas(cv->c_slperp);
+ LayerCleanupMemory(&cv->c_blank);
+ free(cv);
+ return;
+ }
+
+ if (display)
+ {
+ if (D_forecv == cv)
+ D_forecv = 0;
+ /* remove from canvas chain as SetCanvasWindow might call
+ * some layer function */
+ for (cvp = &D_cvlist; *cvp ; cvp = &(*cvp)->c_next)
+ if (*cvp == cv)
+ {
+ *cvp = cv->c_next;
+ break;
+ }
+ }
+ p = cv->c_layer ? Layer2Window(cv->c_layer) : 0;
+ SetCanvasWindow(cv, 0);
+ if (p)
+ WindowChanged(p, 'u');
+ if (flayer == cv->c_layer)
+ flayer = 0;
+ for (vp = cv->c_vplist; vp; vp = nvp)
+ {
+ vp->v_canvas = 0;
+ nvp = vp->v_next;
+ vp->v_next = 0;
+ free(vp);
+ }
+ evdeq(&cv->c_captev);
+ LayerCleanupMemory(&cv->c_blank);
+ free(cv);
+}
+
+int
+CountCanvas(cv)
+struct canvas *cv;
+{
+ int num = 0;
+ for (; cv; cv = cv->c_slnext)
+ {
+ if (cv->c_slperp)
+ {
+ struct canvas *cvp;
+ int nump = 1, n;
+ for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
+ if (cvp->c_slperp)
+ {
+ n = CountCanvas(cvp->c_slperp);
+ if (n > nump)
+ nump = n;
+ }
+ num += nump;
+ }
+ else
+ num++;
+ }
+ return num;
+}
+
+int
+CountCanvasPerp(cv)
+struct canvas *cv;
+{
+ struct canvas *cvp;
+ int num = 1, n;
+ for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
+ if (cvp->c_slperp)
+ {
+ n = CountCanvas(cvp->c_slperp);
+ if (n > num)
+ num = n;
+ }
+ return num;
+}
+
+struct canvas *
+FindCanvas(x, y)
+int x, y;
+{
+ struct canvas *cv, *mcv = 0;
+ int m, mm = 0;
+
+ for (cv = D_cvlist; cv; cv = cv->c_next)
+ {
+ /* ye + 1 because of caption line */
+ if (x >= cv->c_xs && x <= cv->c_xe && y >= cv->c_ys && y <= cv->c_ye + 1)
+ return cv;
+ if (cv == D_forecv)
+ continue;
+ m = 0;
+ if (x >= D_forecv->c_xs && x <= D_forecv->c_xe)
+ {
+ if (x < cv->c_xs || x > cv->c_xe)
+ continue;
+ if (y < D_forecv->c_ys && y < cv->c_ys)
+ continue;
+ if (y > D_forecv->c_ye + 1 && y > cv->c_ye + 1)
+ continue;
+ if (y < cv->c_ys)
+ m = cv->c_ys - y;
+ if (y > cv->c_ye + 1)
+ m = y - (cv->c_ye + 1);
+ }
+ if (y >= D_forecv->c_ys && y <= D_forecv->c_ye + 1)
+ {
+ if (y < cv->c_ys || y > cv->c_ye + 1)
+ continue;
+ if (x < D_forecv->c_xs && x < cv->c_xs)
+ continue;
+ if (x > D_forecv->c_xe && x > cv->c_xe)
+ continue;
+ if (x < cv->c_xs)
+ m = cv->c_xs - x;
+ if (x > cv->c_xe)
+ m = x - cv->c_xe;
+ }
+ if (m && (!mm || m < mm))
+ {
+ mcv = cv;
+ mm = m;
+ }
+ }
+ return mcv ? mcv : D_forecv;
+}
+
+void
+SetCanvasWindow(cv, wi)
+struct canvas *cv;
+struct win *wi;
+{
+ struct win *p = 0, **pp;
+ struct layer *l;
+ struct canvas *cvp, **cvpp;
+
+ l = cv->c_layer;
+ display = cv->c_display;
+
+ if (l)
+ {
+ /* remove old layer */
+ for (cvpp = &l->l_cvlist; (cvp = *cvpp); cvpp = &cvp->c_lnext)
+ if (cvp == cv)
+ break;
+ ASSERT(cvp);
+ *cvpp = cvp->c_lnext;
+
+ p = Layer2Window(l);
+ l = cv->c_layer;
+ cv->c_layer = 0;
+
+ if (p && cv == D_forecv)
+ {
+#ifdef MULTIUSER
+ ReleaseAutoWritelock(display, p);
+#endif
+ if (p->w_silence)
+ {
+ SetTimeout(&p->w_silenceev, p->w_silencewait * 1000);
+ evenq(&p->w_silenceev);
+ }
+ D_other = fore;
+ D_fore = 0;
+ }
+ if (l->l_cvlist == 0 && (p == 0 || l != p->w_savelayer))
+ KillLayerChain(l);
+ }
+
+ /* find right layer to display on canvas */
+ if (wi && wi->w_type != W_TYPE_GROUP)
+ {
+ l = &wi->w_layer;
+ if (wi->w_savelayer && (wi->w_blocked || wi->w_savelayer->l_cvlist == 0))
+ l = wi->w_savelayer;
+ }
+ else
+ {
+ l = &cv->c_blank;
+ if (wi)
+ l->l_data = (char *)wi;
+ else
+ l->l_data = 0;
+ }
+
+ /* add our canvas to the layer's canvaslist */
+ ASSERT(l->l_cvlist != cv);
+ cv->c_lnext = l->l_cvlist;
+ l->l_cvlist = cv;
+ cv->c_layer = l;
+ cv->c_xoff = cv->c_xs;
+ cv->c_yoff = cv->c_ys;
+ RethinkViewportOffsets(cv);
+
+ if (flayer == 0)
+ flayer = l;
+
+ if (wi && wi->w_type == W_TYPE_GROUP)
+ {
+ /* auto-start windowlist on groups */
+ struct display *d = display;
+ struct layer *oldflayer = flayer;
+ flayer = l;
+ display_windows(0, 0, wi);
+ flayer = oldflayer;
+ display = d;
+ }
+
+ if (wi && D_other == wi)
+ D_other = wi->w_next; /* Might be 0, but that's OK. */
+ if (cv == D_forecv)
+ {
+ D_fore = wi;
+ fore = D_fore; /* XXX ? */
+ if (wi)
+ {
+#ifdef MULTIUSER
+ ObtainAutoWritelock(display, wi);
+#endif
+ /*
+ * Place the window at the head of the most-recently-used list
+ */
+ if (windows != wi)
+ {
+ 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;
+ WListLinkChanged();
+ }
+ }
+ }
+}
+
+static void
+cv_winid_fn(ev, data)
+struct event *ev;
+char *data;
+{
+ int ox, oy;
+ struct canvas *cv = (struct canvas *)data;
+
+ display = cv->c_display;
+ if (D_status == STATUS_ON_WIN)
+ {
+ SetTimeout(ev, 1);
+ evenq(ev);
+ return;
+ }
+ ox = D_x;
+ oy = D_y;
+ if (cv->c_ye + 1 < D_height)
+ RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
+ if (ox != -1 && oy != -1)
+ GotoPos(ox, oy);
+}
+
+int
+MakeDefaultCanvas()
+{
+ struct canvas *cv;
+
+ ASSERT(display);
+ if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
+ return -1;
+ cv->c_xs = 0;
+ cv->c_xe = D_width - 1;
+ cv->c_ys = (D_has_hstatus == HSTATUS_FIRSTLINE);
+ cv->c_ye = D_height - 1 - (D_has_hstatus == HSTATUS_LASTLINE) - captionalways;
+ debug2("MakeDefaultCanvas 0,0 %d,%d\n", cv->c_xe, cv->c_ye);
+ cv->c_xoff = 0;
+ cv->c_yoff = 0;
+ cv->c_next = 0;
+ cv->c_display = display;
+ cv->c_vplist = 0;
+ cv->c_slnext = 0;
+ cv->c_slprev = 0;
+ cv->c_slperp = 0;
+ cv->c_slweight = 1;
+ cv->c_slback = &D_canvas;
+ D_canvas.c_slperp = cv;
+ D_canvas.c_xs = cv->c_xs;
+ D_canvas.c_xe = cv->c_xe;
+ D_canvas.c_ys = cv->c_ys;
+ D_canvas.c_ye = cv->c_ye;
+ cv->c_slorient = SLICE_UNKN;
+ cv->c_captev.type = EV_TIMEOUT;
+ cv->c_captev.data = (char *)cv;
+ cv->c_captev.handler = cv_winid_fn;
+
+ CanvasInitBlank(cv);
+ cv->c_lnext = 0;
+
+ D_cvlist = cv;
+ RethinkDisplayViewports();
+ D_forecv = cv; /* default input focus */
+ return 0;
+}
+
+static struct canvas **
+CreateCanvasChainRec(cv, cvp)
+struct canvas *cv;
+struct canvas **cvp;
+{
+ for (; cv; cv = cv->c_slnext)
+ {
+ if (cv->c_slperp)
+ cvp = CreateCanvasChainRec(cv->c_slperp, cvp);
+ else
+ {
+ *cvp = cv;
+ cvp = &cv->c_next;
+ }
+ }
+ return cvp;
+}
+
+void
+RecreateCanvasChain()
+{
+ struct canvas **cvp;
+ cvp = CreateCanvasChainRec(D_canvas.c_slperp, &D_cvlist);
+ *cvp = 0;
+}
+
+void
+EqualizeCanvas(cv, gflag)
+struct canvas *cv;
+int gflag;
+{
+ struct canvas *cv2;
+ for (; cv; cv = cv->c_slnext)
+ {
+ if (cv->c_slperp && gflag)
+ {
+ cv->c_slweight = CountCanvasPerp(cv);
+ for (cv2 = cv->c_slperp; cv2; cv2 = cv2->c_slnext)
+ if (cv2->c_slperp)
+ EqualizeCanvas(cv2->c_slperp, gflag);
+ }
+ else
+ cv->c_slweight = 1;
+ }
+}
+
+void
+ResizeCanvas(cv)
+struct canvas *cv;
+{
+ struct canvas *cv2, *cvn, *fcv;
+ int nh, i, maxi, hh, m, w, wsum;
+ int need, got;
+ int xs, ys, xe, ye;
+ int focusmin = 0;
+
+ xs = cv->c_xs;
+ ys = cv->c_ys;
+ xe = cv->c_xe;
+ ye = cv->c_ye;
+ cv = cv->c_slperp;
+ debug2("ResizeCanvas: %d,%d", xs, ys);
+ debug2(" %d,%d\n", xe, ye);
+ if (cv == 0)
+ return;
+ if (cv->c_slorient == SLICE_UNKN)
+ {
+ ASSERT(!cv->c_slnext && !cv->c_slperp);
+ cv->c_xs = xs;
+ cv->c_xe = xe;
+ cv->c_ys = ys;
+ cv->c_ye = ye;
+ cv->c_xoff = cv->c_xs;
+ cv->c_yoff = cv->c_ys;
+ cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
+ cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
+ return;
+ }
+
+ fcv = 0;
+ if (focusminwidth || focusminheight)
+ {
+ debug("searching for focus canvas\n");
+ cv2 = D_forecv;
+ while (cv2->c_slback)
+ {
+ if (cv2->c_slback == cv->c_slback)
+ {
+ fcv = cv2;
+ focusmin = cv->c_slorient == SLICE_VERT ? focusminheight : focusminwidth;
+ if (focusmin > 0)
+ focusmin--;
+ else if (focusmin < 0)
+ focusmin = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
+ debug1("found, focusmin=%d\n", focusmin);
+ }
+ cv2 = cv2->c_slback;
+ }
+ }
+ if (focusmin)
+ {
+ m = CountCanvas(cv) * 2;
+ nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
+ nh -= m;
+ if (nh < 0)
+ nh = 0;
+ if (focusmin > nh)
+ focusmin = nh;
+ debug1("corrected to %d\n", focusmin);
+ }
+
+ /* pass 1: calculate weight sum */
+ for (cv2 = cv, wsum = 0; cv2; cv2 = cv2->c_slnext)
+ {
+ debug1(" weight %d\n", cv2->c_slweight);
+ wsum += cv2->c_slweight;
+ }
+ debug1("wsum = %d\n", wsum);
+ if (wsum == 0)
+ wsum = 1;
+ w = wsum;
+
+ /* pass 2: calculate need/excess space */
+ nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
+ for (cv2 = cv, need = got = 0; cv2; cv2 = cv2->c_slnext)
+ {
+ m = cv2->c_slperp ? CountCanvasPerp(cv2) * 2 - 1 : 1;
+ if (cv2 == fcv)
+ m += focusmin;
+ hh = cv2->c_slweight ? nh * cv2->c_slweight / w : 0;
+ w -= cv2->c_slweight;
+ nh -= hh;
+ debug2(" should %d min %d\n", hh, m);
+ if (hh <= m + 1)
+ need += m + 1 - hh;
+ else
+ got += hh - m - 1;
+ }
+ debug2("need: %d, got %d\n", need, got);
+ if (need > got)
+ need = got;
+
+ /* pass 3: distribute space */
+ nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
+ i = cv->c_slorient == SLICE_VERT ? ys : xs;
+ maxi = cv->c_slorient == SLICE_VERT ? ye : xe;
+ w = wsum;
+ for (; cv; cv = cvn)
+ {
+ cvn = cv->c_slnext;
+ if (i > maxi)
+ {
+ if (cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slprev->c_slperp && !cv->c_slprev->c_slprev)
+ {
+ cv->c_slprev->c_slorient = SLICE_UNKN;
+ if (!captionalways)
+ {
+ cv->c_slback->c_ye++;
+ cv->c_slprev->c_ye++;
+ }
+ }
+ SetCanvasWindow(cv, 0);
+ FreeCanvas(cv);
+ continue;
+ }
+ m = cv->c_slperp ? CountCanvasPerp(cv) * 2 - 1 : 1;
+ if (cv == fcv)
+ m += focusmin;
+ hh = cv->c_slweight ? nh * cv->c_slweight / w : 0;
+ w -= cv->c_slweight;
+ nh -= hh;
+ debug2(" should %d min %d\n", hh, m);
+ if (hh <= m + 1)
+ {
+ hh = m + 1;
+ debug1(" -> %d\n", hh);
+ }
+ else
+ {
+ int hx = 1; //FIXME Division by zero (got) is posible. "hx = 1" is random number here!!!
+ if (got != 0)
+ hx = need * (hh - m - 1) / got;
+ else
+ debug(" got = 0\n");
+
+ debug3(" -> %d - %d = %d\n", hh, hx, hh - hx);
+ got -= (hh - m - 1);
+ hh -= hx;
+ need -= hx;
+ debug2(" now need=%d got=%d\n", need, got);
+ }
+ ASSERT(hh >= m + 1);
+ /* hh is window size plus pation line */
+ if (i + hh > maxi + 2)
+ {
+ hh = maxi + 2 - i;
+ debug1(" not enough space, reducing to %d\n", hh);
+ }
+ if (i + hh == maxi + 1)
+ {
+ hh++;
+ debug(" incrementing as no other canvas will fit\n");
+ }
+ if (cv->c_slorient == SLICE_VERT)
+ {
+ cv->c_xs = xs;
+ cv->c_xe = xe;
+ cv->c_ys = i;
+ cv->c_ye = i + hh - 2;
+ cv->c_xoff = xs;
+ cv->c_yoff = i;
+ }
+ else
+ {
+ cv->c_xs = i;
+ cv->c_xe = i + hh - 2;
+ cv->c_ys = ys;
+ cv->c_ye = ye;
+ cv->c_xoff = i;
+ cv->c_yoff = ys;
+ }
+ cv->c_xoff = cv->c_xs;
+ cv->c_yoff = cv->c_ys;
+ cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
+ cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
+ if (cv->c_slperp)
+ {
+ ResizeCanvas(cv);
+ if (!cv->c_slperp->c_slnext)
+ {
+ debug("deleting perp node\n");
+ FreePerp(cv->c_slperp);
+ FreePerp(cv);
+ }
+ }
+ i += hh;
+ }
+}
+
+static struct canvas *
+AddPerp(cv)
+struct canvas *cv;
+{
+ struct canvas *pcv;
+ debug("Creating new perp node\n");
+
+ if ((pcv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
+ return 0;
+ pcv->c_next = 0;
+ pcv->c_display = cv->c_display;
+ pcv->c_slnext = cv->c_slnext;
+ pcv->c_slprev = cv->c_slprev;
+ pcv->c_slperp = cv;
+ pcv->c_slback = cv->c_slback;
+ if (cv->c_slback && cv->c_slback->c_slperp == cv)
+ cv->c_slback->c_slperp = pcv;
+ pcv->c_slorient = cv->c_slorient;
+ pcv->c_xoff = 0;
+ pcv->c_yoff = 0;
+ pcv->c_xs = cv->c_xs;
+ pcv->c_xe = cv->c_xe;
+ pcv->c_ys = cv->c_ys;
+ pcv->c_ye = cv->c_ye;
+ if (pcv->c_slnext)
+ pcv->c_slnext->c_slprev = pcv;
+ if (pcv->c_slprev)
+ pcv->c_slprev->c_slnext = pcv;
+ pcv->c_slweight = cv->c_slweight;
+ CanvasInitBlank(pcv);
+ cv->c_slweight = 1;
+ cv->c_slnext = 0;
+ cv->c_slprev = 0;
+ cv->c_slperp = 0;
+ cv->c_slback = pcv;
+ cv->c_slorient = SLICE_UNKN;
+ return pcv;
+}
+
+int
+AddCanvas(orient)
+int orient;
+{
+ struct canvas *cv;
+ int xs, xe, ys, ye;
+ int h, num;
+
+ cv = D_forecv;
+ debug2("AddCanvas orient %d, forecv is %d\n", orient, cv->c_slorient);
+
+ if (cv->c_slorient != SLICE_UNKN && cv->c_slorient != orient)
+ if (!AddPerp(cv))
+ return -1;
+
+ cv = D_forecv;
+ xs = cv->c_slback->c_xs;
+ xe = cv->c_slback->c_xe;
+ ys = cv->c_slback->c_ys;
+ ye = cv->c_slback->c_ye;
+ if (!captionalways && cv == D_canvas.c_slperp && !cv->c_slnext)
+ ye--; /* need space for caption */
+ debug2("Adding Canvas to slice %d,%d ", xs, ys);
+ debug2("%d,%d\n", xe, ye);
+
+ num = CountCanvas(cv->c_slback->c_slperp) + 1;
+ debug1("Num = %d\n", num);
+ if (orient == SLICE_VERT)
+ h = ye - ys + 1;
+ else
+ h = xe - xs + 1;
+
+ h -= 2 * num - 1;
+ if (h < 0)
+ return -1; /* can't fit in */
+
+ if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
+ return -1;
+
+ D_forecv->c_slback->c_ye = ye; /* in case we modified it above */
+ D_forecv->c_slorient = orient; /* in case it was UNKN */
+ cv->c_slnext = D_forecv->c_slnext;
+ cv->c_slprev = D_forecv;
+ D_forecv->c_slnext = cv;
+ if (cv->c_slnext)
+ cv->c_slnext->c_slprev = cv;
+ cv->c_slorient = orient;
+ cv->c_slback = D_forecv->c_slback;
+
+ cv->c_xs = xs;
+ cv->c_xe = xe;
+ cv->c_ys = ys;
+ cv->c_ye = ye;
+ cv->c_xoff = 0;
+ cv->c_yoff = 0;
+ cv->c_display = display;
+ cv->c_vplist = 0;
+ cv->c_captev.type = EV_TIMEOUT;
+ cv->c_captev.data = (char *)cv;
+ cv->c_captev.handler = cv_winid_fn;
+
+ CanvasInitBlank(cv);
+ cv->c_lnext = 0;
+
+ cv->c_next = 0;
+
+ cv = cv->c_slback;
+ EqualizeCanvas(cv->c_slperp, 0);
+ ResizeCanvas(cv);
+ RecreateCanvasChain();
+ RethinkDisplayViewports();
+ ResizeLayersToCanvases();
+ return 0;
+}
+
+void
+RemCanvas()
+{
+ int ye;
+ struct canvas *cv;
+
+ debug("RemCanvas\n");
+ cv = D_forecv;
+ ye = cv->c_slback->c_ye;
+ if (cv->c_slorient == SLICE_UNKN)
+ return;
+ while (cv->c_slprev)
+ cv = cv->c_slprev;
+ if (!cv->c_slnext)
+ return;
+ if (!cv->c_slnext->c_slnext && cv->c_slback->c_slback)
+ {
+ /* two canvases in slice, kill perp node */
+ cv = D_forecv;
+ debug("deleting perp node\n");
+ FreePerp(cv->c_slprev ? cv->c_slprev : cv->c_slnext);
+ FreePerp(cv->c_slback);
+ }
+ /* free canvas */
+ cv = D_forecv;
+ D_forecv = cv->c_slprev;
+ if (!D_forecv)
+ D_forecv = cv->c_slnext;
+ FreeCanvas(cv);
+
+ cv = D_forecv;
+ while (D_forecv->c_slperp)
+ D_forecv = D_forecv->c_slperp;
+
+ /* if only one canvas left, set orient back to unknown */
+ if (!cv->c_slnext && !cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slperp)
+ {
+ cv->c_slorient = SLICE_UNKN;
+ if (!captionalways)
+ cv->c_slback->c_ye = ++ye; /* caption line no longer needed */
+ }
+ cv = cv->c_slback;
+ EqualizeCanvas(cv->c_slperp, 0);
+ ResizeCanvas(cv);
+
+ D_fore = Layer2Window(D_forecv->c_layer);
+ flayer = D_forecv->c_layer;
+
+ RecreateCanvasChain();
+ RethinkDisplayViewports();
+ ResizeLayersToCanvases();
+}
+
+void
+OneCanvas()
+{
+ struct canvas *cv = D_forecv, *ocv = 0;
+
+ if (cv->c_slprev)
+ {
+ ocv = cv->c_slprev;
+ cv->c_slprev->c_slnext = cv->c_slnext;
+ }
+ if (cv->c_slnext)
+ {
+ ocv = cv->c_slnext;
+ cv->c_slnext->c_slprev = cv->c_slprev;
+ }
+ if (!ocv)
+ return;
+ if (cv->c_slback && cv->c_slback->c_slperp == cv)
+ cv->c_slback->c_slperp = ocv;
+ cv->c_slorient = SLICE_UNKN;
+ while (D_canvas.c_slperp)
+ FreeCanvas(D_canvas.c_slperp);
+ cv = D_forecv;
+ D_canvas.c_slperp = cv;
+ cv->c_slback = &D_canvas;
+ cv->c_slnext = 0;
+ cv->c_slprev = 0;
+ ASSERT(!cv->c_slperp);
+ if (!captionalways)
+ D_canvas.c_ye++; /* caption line no longer needed */
+ ResizeCanvas(&D_canvas);
+ RecreateCanvasChain();
+ RethinkDisplayViewports();
+ ResizeLayersToCanvases();
+}
+
+void
+DupLayoutCv(cvf, cvt, save)
+struct canvas *cvf, *cvt;
+int save;
+{
+ while(cvf)
+ {
+ cvt->c_slorient = cvf->c_slorient;
+ cvt->c_slweight = cvf->c_slweight;
+ if (cvf == D_forecv)
+ D_forecv = cvt;
+ if (!save)
+ {
+ cvt->c_display = display;
+ if (!cvf->c_slperp)
+ {
+ cvt->c_captev.type = EV_TIMEOUT;
+ cvt->c_captev.data = (char *)cvt;
+ cvt->c_captev.handler = cv_winid_fn;
+ cvt->c_blank.l_cvlist = 0;
+ cvt->c_blank.l_layfn = &BlankLf;
+ cvt->c_blank.l_bottom = &cvt->c_blank;
+ }
+ cvt->c_layer = cvf->c_layer;
+ }
+ else
+ {
+ struct win *p = cvf->c_layer ? Layer2Window(cvf->c_layer) : 0;
+ cvt->c_layer = p ? &p->w_layer : 0;
+ }
+ if (cvf->c_slperp)
+ {
+ cvt->c_slperp = (struct canvas *)calloc(1, sizeof(struct canvas));
+ cvt->c_slperp->c_slback = cvt;
+ CanvasInitBlank(cvt->c_slperp);
+ DupLayoutCv(cvf->c_slperp, cvt->c_slperp, save);
+ }
+ if (cvf->c_slnext)
+ {
+ cvt->c_slnext = (struct canvas *)calloc(1, sizeof(struct canvas));
+ cvt->c_slnext->c_slprev = cvt;
+ cvt->c_slnext->c_slback = cvt->c_slback;
+ CanvasInitBlank(cvt->c_slnext);
+ }
+ cvf = cvf->c_slnext;
+ cvt = cvt->c_slnext;
+ }
+}
+
+void
+PutWindowCv(cv)
+struct canvas *cv;
+{
+ struct win *p;
+ for (; cv; cv = cv->c_slnext)
+ {
+ if (cv->c_slperp)
+ {
+ PutWindowCv(cv->c_slperp);
+ continue;
+ }
+ p = cv->c_layer ? (struct win *)cv->c_layer->l_data : 0;
+ cv->c_layer = 0;
+ SetCanvasWindow(cv, p);
+ }
+}
+
diff --git a/canvas.h b/canvas.h
new file mode 100644
index 0000000..d918013
--- /dev/null
+++ b/canvas.h
@@ -0,0 +1,101 @@
+/* Copyright (c) 2008, 2009
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Micah Cowan (micah@cowan.name)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
+ * 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 3, 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, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ * $Id$ GNU
+ */
+
+#ifndef SCREEN_CANVAS_H
+#define SCREEN_CANVAS_H
+
+#define SLICE_UNKN 0
+#define SLICE_VERT (1 << 0)
+#define SLICE_HORI (1 << 1)
+
+#define SLICE_THIS (1 << 2) /* used in equal test */
+#define SLICE_GLOBAL (1 << 3)
+
+struct canvas
+{
+ struct canvas *c_next; /* next canvas on display */
+ struct display *c_display; /* back pointer to display */
+
+ struct canvas *c_slnext; /* next canvas in display slice */
+ struct canvas *c_slprev; /* prev canvas in display slice */
+ struct canvas *c_slperp; /* perpendicular slice */
+ struct canvas *c_slback; /* perpendicular slice back pointer */
+ int c_slorient; /* our slice orientation */
+ int c_slweight; /* size ratio */
+
+ struct viewport *c_vplist;
+ struct layer *c_layer; /* layer on this canvas */
+ struct canvas *c_lnext; /* next canvas that displays layer */
+ struct layer c_blank; /* bottom layer, always blank */
+ int c_xoff; /* canvas x offset on display */
+ int c_yoff; /* canvas y offset on display */
+ int c_xs;
+ int c_xe;
+ int c_ys;
+ int c_ye;
+ struct event c_captev; /* caption changed event */
+};
+
+struct win; /* forward declaration */
+
+extern void SetCanvasWindow __P((struct canvas *, struct win *));
+extern void SetForeCanvas __P((struct display *, struct canvas *));
+extern struct canvas *FindCanvas __P((int, int));
+extern int MakeDefaultCanvas __P((void));
+extern int AddCanvas __P((int));
+extern void RemCanvas __P((void));
+extern void OneCanvas __P((void));
+extern void FreeCanvas __P((struct canvas *));
+extern void ResizeCanvas __P((struct canvas *));
+extern void RecreateCanvasChain __P((void));
+extern void RethinkViewportOffsets __P((struct canvas *));
+extern int CountCanvasPerp __P((struct canvas *));
+extern void EqualizeCanvas __P((struct canvas *, int));
+extern void DupLayoutCv __P((struct canvas *, struct canvas *, int));
+extern void PutWindowCv __P((struct canvas *));
+
+#define CV_CALL(cv, cmd) \
+{ \
+ struct display *olddisplay = display; \
+ struct layer *oldflayer = flayer; \
+ struct layer *l = cv->c_layer; \
+ struct canvas *cvlist = l->l_cvlist; \
+ struct canvas *cvlnext = cv->c_lnext; \
+ flayer = l; \
+ l->l_cvlist = cv; \
+ cv->c_lnext = 0; \
+ cmd; \
+ flayer = oldflayer; \
+ l->l_cvlist = cvlist; \
+ cv->c_lnext = cvlnext; \
+ display = olddisplay; \
+}
+
+#endif /* SCREEN_CANVAS_H */
+
diff --git a/comm.c b/comm.c
new file mode 100644
index 0000000..90eaa7e
--- /dev/null
+++ b/comm.c
@@ -0,0 +1,348 @@
+/* Copyright (c) 2008, 2009
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Micah Cowan (micah@cowan.name)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+#ifdef HAVE_BRAILLE
+ * Modified by:
+ * Authors: Hadi Bargi Rangin bargi@dots.physics.orst.edu
+ * Bill Barry barryb@dots.physics.orst.edu
+ *
+ * Modifications Copyright (c) 1995 by
+ * Science Access Project, Oregon State University.
+#endif
+ *
+ * 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 3, 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, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ */
+
+#include "config.h"
+#include "os.h"
+#include "acls.h"
+#include "comm.h"
+
+#define bcopy :-( /* or include screen.h here */
+
+/* Must be in alpha order ! */
+
+struct comm comms[RC_LAST + 1] =
+{
+#ifdef MULTIUSER
+ { "acladd", ARGS_1234 },
+ { "aclchg", ARGS_23 },
+ { "acldel", ARGS_1 },
+ { "aclgrp", ARGS_12 },
+ { "aclumask", ARGS_1|ARGS_ORMORE },
+#endif
+ { "activity", ARGS_1 },
+#ifdef MULTIUSER
+ { "addacl", ARGS_1234 },
+#endif
+ { "allpartial", NEED_DISPLAY|ARGS_1 },
+ { "altscreen", ARGS_01 },
+ { "at", ARGS_2|ARGS_ORMORE },
+#ifdef COLOR
+ { "attrcolor", ARGS_12 },
+#endif
+ { "autodetach", ARGS_1 },
+#ifdef AUTO_NUKE
+ { "autonuke", NEED_DISPLAY|ARGS_1 },
+#endif
+ { "backtick", ARGS_1|ARGS_ORMORE },
+#ifdef COLOR
+ { "bce", NEED_FORE|ARGS_01 },
+#endif
+
+#ifdef HAVE_BRAILLE
+/* keywords for braille display (bd) */
+ { "bd_bc_down", ARGS_0 },
+ { "bd_bc_left", ARGS_0 },
+ { "bd_bc_right", ARGS_0 },
+ { "bd_bc_up", ARGS_0 },
+ { "bd_bell", ARGS_01 },
+ { "bd_braille_table", ARGS_01 },
+ { "bd_eightdot", ARGS_01 },
+ { "bd_info", ARGS_01 },
+ { "bd_link", ARGS_01 },
+ { "bd_lower_left", ARGS_0 },
+ { "bd_lower_right", ARGS_0 },
+ { "bd_ncrc", ARGS_01 },
+ { "bd_port", ARGS_01 },
+ { "bd_scroll", ARGS_01 },
+ { "bd_skip", ARGS_01 },
+ { "bd_start_braille", ARGS_01 },
+ { "bd_type", ARGS_01 },
+ { "bd_upper_left", ARGS_0 },
+ { "bd_upper_right", ARGS_0 },
+ { "bd_width", ARGS_01 },
+#endif
+
+ { "bell", ARGS_01 },
+ { "bell_msg", ARGS_01 },
+ { "bind", ARGS_1|ARGS_ORMORE },
+#ifdef MAPKEYS
+ { "bindkey", ARGS_0|ARGS_ORMORE },
+#endif
+ { "blanker", NEED_DISPLAY|ARGS_0},
+#ifdef BLANKER_PRG
+ { "blankerprg", ARGS_0|ARGS_ORMORE },
+#endif
+ { "break", NEED_FORE|ARGS_01 },
+ { "breaktype", NEED_FORE|ARGS_01 },
+#ifdef COPY_PASTE
+ { "bufferfile", ARGS_01 },
+#endif
+ { "bumpleft", NEED_FORE|ARGS_0 },
+ { "bumpright", NEED_FORE|ARGS_0 },
+ { "c1", NEED_FORE|ARGS_01 },
+ { "caption", ARGS_12 },
+#ifdef MULTIUSER
+ { "chacl", ARGS_23 },
+#endif
+ { "charset", NEED_FORE|ARGS_1 },
+ { "chdir", ARGS_01 },
+#ifdef DW_CHARS
+ { "cjkwidth", ARGS_01 },
+#endif
+ { "clear", NEED_FORE|ARGS_0 },
+ { "collapse", ARGS_0 },
+ { "colon", NEED_LAYER|ARGS_01 },
+ { "command", NEED_DISPLAY|ARGS_02 },
+#ifdef COPY_PASTE
+ { "compacthist", ARGS_01 },
+#endif
+ { "console", NEED_FORE|ARGS_01 },
+#ifdef COPY_PASTE
+ { "copy", NEED_FORE|NEED_DISPLAY|ARGS_0 },
+ { "crlf", ARGS_01 },
+#endif
+ { "debug", ARGS_01 },
+#ifdef AUTO_NUKE
+ { "defautonuke", ARGS_1 },
+#endif
+#ifdef COLOR
+ { "defbce", ARGS_1 },
+#endif
+ { "defbreaktype", ARGS_01 },
+ { "defc1", ARGS_1 },
+ { "defcharset", ARGS_01 },
+ { "defdynamictitle", ARGS_1 },
+#ifdef ENCODINGS
+ { "defencoding", ARGS_1 },
+#endif
+ { "defescape", ARGS_1 },
+ { "defflow", ARGS_12 },
+ { "defgr", ARGS_1 },
+ { "defhstatus", ARGS_01 },
+#ifdef ENCODINGS
+ { "defkanji", ARGS_1 },
+#endif
+ { "deflog", ARGS_1 },
+#if defined(UTMPOK) && defined(LOGOUTOK)
+ { "deflogin", ARGS_1 },
+#endif
+ { "defmode", ARGS_1 },
+ { "defmonitor", ARGS_1 },
+ { "defmousetrack", ARGS_1 },
+#ifdef MULTI
+ { "defnonblock", ARGS_1 },
+#endif
+ { "defobuflimit", ARGS_1 },
+#ifdef COPY_PASTE
+ { "defscrollback", ARGS_1 },
+#endif
+ { "defshell", ARGS_1 },
+ { "defsilence", ARGS_1 },
+ { "defslowpaste", ARGS_1 },
+#ifdef UTF8
+ { "defutf8", ARGS_1 },
+#endif
+ { "defwrap", ARGS_1 },
+ { "defwritelock", ARGS_1 },
+#ifdef DETACH
+ { "detach", NEED_DISPLAY|ARGS_01 },
+#endif
+ { "digraph", NEED_LAYER|ARGS_012 },
+ { "dinfo", NEED_DISPLAY|ARGS_0 },
+ { "displays", NEED_LAYER|ARGS_0 },
+ { "dumptermcap", NEED_FORE|ARGS_0 },
+ { "dynamictitle", ARGS_1 },
+ { "echo", CAN_QUERY|ARGS_12 },
+#ifdef ENCODINGS
+ { "encoding", ARGS_12 },
+#endif
+ { "escape", ARGS_1 },
+ { "eval", ARGS_1|ARGS_ORMORE },
+#ifdef PSEUDOS
+ { "exec", ARGS_0|ARGS_ORMORE },
+#endif
+ { "fit", NEED_DISPLAY|ARGS_0 },
+ { "flow", NEED_FORE|ARGS_01 },
+ { "focus", NEED_DISPLAY|ARGS_01 },
+ { "focusminsize", ARGS_02 },
+ { "gr", NEED_FORE|ARGS_01 },
+ { "group", NEED_FORE|ARGS_01 },
+ { "hardcopy", NEED_FORE|ARGS_012 },
+ { "hardcopy_append", ARGS_1 },
+ { "hardcopydir", ARGS_01 },
+ { "hardstatus", ARGS_012 },
+ { "height", ARGS_0123 },
+ { "help", NEED_LAYER|ARGS_02 },
+#ifdef COPY_PASTE
+ { "history", NEED_DISPLAY|NEED_FORE|ARGS_0 },
+#endif
+ { "hstatus", NEED_FORE|ARGS_1 },
+ { "idle", ARGS_0|ARGS_ORMORE },
+ { "ignorecase", ARGS_01 },
+ { "info", CAN_QUERY|NEED_LAYER|ARGS_0 },
+#ifdef ENCODINGS
+ { "kanji", NEED_FORE|ARGS_12 },
+#endif
+ { "kill", NEED_FORE|ARGS_0 },
+ { "lastmsg", CAN_QUERY|NEED_DISPLAY|ARGS_0 },
+ { "layout", ARGS_1|ARGS_ORMORE},
+ { "license", NEED_LAYER|ARGS_0 },
+#ifdef LOCK
+ { "lockscreen", NEED_DISPLAY|ARGS_0 },
+#endif
+ { "log", NEED_FORE|ARGS_01 },
+ { "logfile", ARGS_012 },
+#if defined(UTMPOK) && defined(LOGOUTOK)
+ { "login", NEED_FORE|ARGS_01 },
+#endif
+ { "logtstamp", ARGS_012 },
+#ifdef MAPKEYS
+ { "mapdefault", NEED_DISPLAY|ARGS_0 },
+ { "mapnotnext", NEED_DISPLAY|ARGS_0 },
+ { "maptimeout", ARGS_01 },
+#endif
+#ifdef COPY_PASTE
+ { "markkeys", ARGS_1 },
+#endif
+ { "maxwin", ARGS_01 },
+ { "meta", NEED_LAYER|ARGS_0 },
+ { "monitor", NEED_FORE|ARGS_01 },
+ { "mousetrack", NEED_DISPLAY | ARGS_01 },
+ { "msgminwait", ARGS_1 },
+ { "msgwait", ARGS_1 },
+#ifdef MULTIUSER
+ { "multiuser", ARGS_1 },
+#endif
+ { "nethack", ARGS_1 },
+ { "next", ARGS_0 },
+#ifdef MULTI
+ { "nonblock", NEED_DISPLAY|ARGS_01 },
+#endif
+ { "number", CAN_QUERY|NEED_FORE|ARGS_01 },
+ { "obuflimit", NEED_DISPLAY|ARGS_01 },
+ { "only", NEED_DISPLAY|ARGS_0 },
+ { "other", ARGS_0 },
+ { "partial", NEED_FORE|ARGS_01 },
+#ifdef PASSWORD
+ { "password", ARGS_01 },
+#endif
+#ifdef COPY_PASTE
+ { "paste", NEED_LAYER|ARGS_012 },
+ { "pastefont", ARGS_01 },
+#endif
+ { "pow_break", NEED_FORE|ARGS_01 },
+#if defined(DETACH) && defined(POW_DETACH)
+ { "pow_detach", NEED_DISPLAY|ARGS_0 },
+ { "pow_detach_msg", ARGS_01 },
+#endif
+ { "prev", ARGS_0 },
+ { "printcmd", ARGS_01 },
+ { "process", NEED_DISPLAY|ARGS_01 },
+ { "quit", ARGS_0 },
+#ifdef COPY_PASTE
+ { "readbuf", ARGS_0123 },
+#endif
+ { "readreg", ARGS_0|ARGS_ORMORE },
+ { "redisplay", NEED_DISPLAY|ARGS_0 },
+ { "register", ARGS_24 },
+ { "remove", NEED_DISPLAY|ARGS_0 },
+#ifdef COPY_PASTE
+ { "removebuf", ARGS_0 },
+#endif
+ { "rendition", ARGS_23 },
+ { "reset", NEED_FORE|ARGS_0 },
+ { "resize", NEED_DISPLAY|ARGS_0|ARGS_ORMORE },
+ { "screen", ARGS_0|ARGS_ORMORE },
+#ifdef COPY_PASTE
+ { "scrollback", NEED_FORE|ARGS_1 },
+#endif
+ { "select", CAN_QUERY|ARGS_01 },
+ { "sessionname", ARGS_01 },
+ { "setenv", ARGS_012 },
+ { "setsid", ARGS_1 },
+ { "shell", ARGS_1 },
+ { "shelltitle", ARGS_1 },
+ { "silence", NEED_FORE|ARGS_01 },
+ { "silencewait", ARGS_1 },
+ { "sleep", ARGS_1 },
+ { "slowpaste", NEED_FORE|ARGS_01 },
+ { "sorendition", ARGS_012 },
+ { "sort", ARGS_0},
+ { "source", ARGS_1 },
+ { "split", NEED_DISPLAY|ARGS_01 },
+ { "startup_message", ARGS_1 },
+ { "stuff", NEED_LAYER|ARGS_012 },
+#ifdef MULTIUSER
+ { "su", NEED_DISPLAY|ARGS_012 },
+#endif
+#ifdef BSDJOBS
+ { "suspend", NEED_DISPLAY|ARGS_0 },
+#endif
+ { "term", ARGS_1 },
+ { "termcap", ARGS_23 },
+ { "termcapinfo", ARGS_23 },
+ { "terminfo", ARGS_23 },
+ { "time", CAN_QUERY|ARGS_01 },
+ { "title", CAN_QUERY|NEED_FORE|ARGS_01 },
+ { "umask", ARGS_1|ARGS_ORMORE },
+ { "unbindall", ARGS_0 },
+ { "unsetenv", ARGS_1 },
+#ifdef UTF8
+ { "utf8", NEED_FORE|ARGS_012 },
+#endif
+ { "vbell", ARGS_01 },
+ { "vbell_msg", ARGS_01 },
+ { "vbellwait", ARGS_1 },
+ { "verbose", ARGS_01 },
+ { "version", ARGS_0 },
+ { "wall", NEED_DISPLAY|ARGS_1},
+ { "width", ARGS_0123 },
+ { "windowlist", ARGS_012 },
+ { "windows", CAN_QUERY|ARGS_01 },
+ { "wrap", NEED_FORE|ARGS_01 },
+#ifdef COPY_PASTE
+ { "writebuf", ARGS_0123 },
+#endif
+ { "writelock", NEED_FORE|ARGS_01 },
+ { "xoff", NEED_LAYER|ARGS_0 },
+ { "xon", NEED_LAYER|ARGS_0 },
+#ifdef ZMODEM
+ { "zmodem", ARGS_012 },
+#endif
+ { "zombie", ARGS_012 },
+ { "zombie_timeout", ARGS_1 }
+};
diff --git a/comm.sh b/comm.sh
new file mode 100644
index 0000000..ad2210c
--- /dev/null
+++ b/comm.sh
@@ -0,0 +1,96 @@
+#! /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
+
+LC_ALL=C
+export LC_ALL
+
+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_0 (0)
+#define ARGS_1 (1)
+#define ARGS_2 (2)
+#define ARGS_3 (3)
+
+#define ARGS_PLUS1 (1<<2)
+#define ARGS_PLUS2 (1<<3)
+#define ARGS_PLUS3 (1<<4)
+#define ARGS_ORMORE (1<<5)
+
+#define NEED_FORE (1<<6) /* this command needs a fore window */
+#define NEED_DISPLAY (1<<7) /* this command needs a display */
+#define NEED_LAYER (1<<8) /* this command needs a layer */
+#define CAN_QUERY (1<<9) /* this command can be queried, i.e. used with -Q to
+ get back a result to stdout */
+
+#define ARGS_01 (ARGS_0 | ARGS_PLUS1)
+#define ARGS_02 (ARGS_0 | ARGS_PLUS2)
+#define ARGS_12 (ARGS_1 | ARGS_PLUS1)
+#define ARGS_23 (ARGS_2 | ARGS_PLUS1)
+#define ARGS_24 (ARGS_2 | ARGS_PLUS2)
+#define ARGS_34 (ARGS_3 | ARGS_PLUS1)
+#define ARGS_012 (ARGS_0 | ARGS_PLUS1 | ARGS_PLUS2)
+#define ARGS_0123 (ARGS_0 | ARGS_PLUS1 | ARGS_PLUS2 | ARGS_PLUS3)
+#define ARGS_123 (ARGS_1 | ARGS_PLUS1 | ARGS_PLUS2)
+#define ARGS_124 (ARGS_1 | ARGS_PLUS1 | ARGS_PLUS3)
+#define ARGS_1234 (ARGS_1 | ARGS_PLUS1 | ARGS_PLUS2 | ARGS_PLUS3)
+
+struct action
+{
+ int nr;
+ char **args;
+ int *argl;
+ int quiet; /* Suppress (currently unused)
+ 0x01 - Error message
+ 0x02 - Normal message
+ */
+};
+
+#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/configure.ac b/configure.ac
new file mode 100644
index 0000000..c0f02df
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,1315 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl $Id$ GNU
+dnl
+dnl Many thanks to David MacKenzie for writing autoconf and
+dnl providing a sample configure.in file for screen.
+dnl
+AC_REVISION($Revision$)dnl
+AC_INIT(screen.c)
+AC_CONFIG_HEADER(config.h)
+AC_PREREQ(2.60)
+
+dnl
+dnl Define some useful macros
+dnl
+AC_DEFUN([AC_PROGRAM_SOURCE],
+[AC_REQUIRE([AC_PROG_CPP])AC_PROVIDE([$0])cat > conftest.c <<EOF
+#include "confdefs.h"
+[$1]
+_CUT_HERE_
+[$2]
+EOF
+eval "$ac_cpp conftest.c 2>&5 | sed -e '1,/_CUT_HERE_/d' -e 's/ //g' > conftest.out"
+. ./conftest.out
+rm -f conftest*
+])dnl
+dnl
+define(AC_NOTE,
+[echo "$1" 1>&AC_FD_MSG
+])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_PROGRAM(screen)
+AC_PREFIX_PROGRAM(gzip)
+
+old_CFLAGS="$CFLAGS"
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_GCC_TRADITIONAL
+AC_ISC_POSIX
+AC_USE_SYSTEM_EXTENSIONS
+
+AC_PROG_AWK
+
+AC_PROG_INSTALL
+
+if test -f etc/toolcheck; then
+AC_CHECKING(for buggy tools)
+sh etc/toolcheck 1>&AC_FD_MSG
+fi
+
+
+
+dnl SOCKDIR
+AC_MSG_CHECKING(if a system-wide socket dir should be used)
+AC_ARG_ENABLE(socket-dir,
+ [ --disable-socket-dir disable system wide socket-dir and use ~/.screen instead],
+ [
+ AC_MSG_RESULT(no. ~/.screen will be used instead.)
+ ],
+ [
+ AC_MSG_RESULT(yes)
+ AC_MSG_CHECKING(for the socket dir)
+ SOCKDIR="(eff_uid ? \"/tmp/uscreens\" : \"/tmp/screens\")"
+ AC_ARG_WITH(socket-dir, [ --with-socket-dir=path where to put the per-user sockets], [
+ case "${withval}" in
+ *\"*) SOCKDIR="${withval}" ;;
+ *) SOCKDIR="\"${withval}\"" ;;
+ esac
+ ])
+ AC_MSG_RESULT(${SOCKDIR})
+ AC_DEFINE_UNQUOTED(SOCKDIR, $SOCKDIR)
+ ]
+)
+
+
+dnl
+dnl **** special unix variants ****
+dnl
+if test "$cross_compiling" = no && 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 "$cross_compiling" = no && test -f /sysV68 ; then
+AC_DEFINE(sysV68)
+fi
+
+if test "$cross_compiling" = no ; then
+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
+oldlibs="$LIBS"
+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"
+AC_CHECKING(mld library)
+AC_TRY_LINK(,,,LIBS="$oldlibs")
+dnl
+dnl
+if test -r /dev/ptc; then
+AC_DEFINE(MIPS)
+AC_CHECKING(wait3)
+AC_TRY_LINK(,[wait3();], ,
+AC_CHECKING(wait2)
+AC_TRY_LINK(,[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
+fi
+
+
+AC_CHECKING(for Ultrix)
+AC_EGREP_CPP(YES_IS_DEFINED,
+[#if defined(ultrix) || defined(__ultrix)
+ YES_IS_DEFINED;
+#endif
+], ULTRIX=1)
+
+if test "$cross_compiling" = no && test -f /usr/lib/libpyr.a ; then
+oldlibs="$LIBS"
+LIBS="$LIBS -lpyr"
+AC_CHECKING(Pyramid OSX)
+AC_TRY_LINK(,[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_EGREP_CPP(YES_IS_DEFINED,
+[#if defined(butterfly)
+ YES_IS_DEFINED;
+#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_EGREP_CPP(YES_IS_DEFINED,
+[#include <sys/types.h>
+#include <unistd.h>
+main () {
+#ifdef _POSIX_VERSION
+ YES_IS_DEFINED;
+#endif
+], AC_NOTE(- you have a POSIX system) AC_DEFINE(POSIX) posix=1)
+fi
+
+AC_CHECKING(for System V)
+AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <signal.h>
+#include <fcntl.h>], [int x = SIGCHLD | FNDELAY;], , AC_DEFINE(SYSV))
+
+AC_CHECKING(for sequent/ptx)
+AC_EGREP_CPP(YES_IS_DEFINED,
+[#ifdef _SEQUENT_
+ YES_IS_DEFINED;
+#endif
+], LIBS="$LIBS -lsocket -linet";seqptx=1)
+
+AC_CHECKING(SVR4)
+AC_EGREP_CPP(yes,
+[main () {
+#if defined(SVR4) || defined(__SVR4)
+ yes;
+#endif
+], AC_NOTE(- you have a SVR4 system) AC_DEFINE(SVR4) svr4=1)
+if test -n "$svr4" ; then
+oldlibs="$LIBS"
+LIBS="$LIBS -lelf"
+AC_CHECKING(SVR4)
+AC_TRY_LINK([#include <utmpx.h>
+],,
+[AC_CHECK_HEADER(dwarf.h, AC_DEFINE(BUGGYGETLOGIN),
+[AC_CHECK_HEADER(elf.h, AC_DEFINE(BUGGYGETLOGIN))])]
+,LIBS="$oldlibs")
+fi
+
+AC_CHECK_HEADERS([stropts.h string.h strings.h])
+
+AC_CHECKING(for Solaris 2.x)
+AC_EGREP_CPP(YES_IS_DEFINED,
+[#if defined(SVR4) && defined(sun)
+ YES_IS_DEFINED;
+#endif
+], LIBS="$LIBS -lsocket -lnsl -lkstat")
+
+dnl
+dnl **** typedefs ****
+dnl
+dnl (currently not used)
+dnl
+dnl AC_CHECKING(for pid_t)
+dnl AC_EGREP_CPP(pid_t,[#include <sys/types.h>
+dnl ],AC_DEFINE(PID_T_DEFINED))
+dnl
+dnl AC_CHECKING(for sig_t)
+dnl AC_EGREP_CPP(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_EGREP_CPP(uid_t,[#include <sys/types.h>
+dnl ],AC_DEFINE(UID_T_DEFINED))
+dnl
+
+dnl
+dnl **** Job control ****
+dnl
+
+AC_CHECKING(BSD job jontrol)
+AC_TRY_LINK(
+[#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 **** setresuid(), setreuid(), seteuid() ****
+dnl
+AC_CHECKING(setresuid)
+AC_TRY_LINK(,[
+setresuid(0, 0, 0);
+], AC_DEFINE(HAVE_SETRESUID))
+AC_CHECKING(setreuid)
+AC_TRY_LINK(,[
+setreuid(0, 0);
+], 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_CHECKING(seteuid)
+AC_TRY_LINK(,[
+#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 execvpe
+AC_CHECKING(execvpe)
+AC_TRY_LINK(,[
+ execvpe(0, 0, 0);
+], AC_DEFINE(HAVE_EXECVPE)
+CFLAGS="$CFLAGS -D_GNU_SOURCE")
+
+dnl
+dnl **** select() ****
+dnl
+
+AC_CHECKING(select)
+AC_TRY_LINK(,[select(0, 0, 0, 0, 0);],,
+LIBS="$LIBS -lnet -lnsl"
+AC_CHECKING(select with $LIBS)
+AC_TRY_LINK(,[select(0, 0, 0, 0, 0);],,
+AC_MSG_ERROR(!!! no select - no screen))
+)
+dnl
+dnl **** FIFO tests ****
+dnl
+
+AC_CHECKING(fifos)
+AC_TRY_RUN([
+/* For select - According to POSIX 1003.1-2001 */
+#include <sys/select.h>
+
+/* For select - According to earlier standards */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.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;
+ fd_set f;
+
+ (void)alarm(5);
+ unlink(fin);
+#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);
+ }
+ FD_SET(0, &f);
+ 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),
+AC_NOTE(- skipping check because we are cross compiling; assuming fifos are usable) fifo=1)
+rm -f /tmp/conftest*
+
+if test -n "$fifo"; then
+AC_CHECKING(for broken fifo implementation)
+AC_TRY_RUN([
+/* For select - According to POSIX 1003.1-2001 */
+#include <sys/select.h>
+
+/* For select - According to earlier standards */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.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 timeval tv;
+ fd_set f;
+
+#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);
+ FD_SET(0, &f);
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ if (select(1, &f, 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,
+AC_NOTE(- skipping check because we are cross compiling; assuming fifo implementation is ok))
+rm -f /tmp/conftest*
+fi
+
+dnl
+dnl **** SOCKET tests ****
+dnl
+dnl may need LIBS="$LIBS -lsocket" here
+dnl
+
+AC_CHECKING(sockets)
+AC_TRY_RUN([
+/* For select - According to POSIX 1003.1-2001 */
+#include <sys/select.h>
+
+/* For select - According to earlier standards */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+char *son = "/tmp/conftest$$";
+
+main()
+{
+ int s1, s2, l;
+ struct sockaddr_un a;
+ fd_set f;
+
+ (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);
+ FD_SET(0, &f);
+ if (select(1, &f, 0, 0, 0) == -1)
+ exit(1);
+ exit(0);
+}
+], AC_NOTE(- your sockets are usable) sock=1,
+AC_NOTE(- your sockets are not usable),
+AC_NOTE(- skipping check because we are cross compiling; assuming sockets are usable) sock=1)
+rm -f /tmp/conftest*
+
+if test -n "$sock"; then
+AC_CHECKING(socket implementation)
+AC_TRY_RUN([
+/* For select - According to POSIX 1003.1-2001 */
+#include <sys/select.h>
+
+/* For select - According to earlier standards */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.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,
+AC_NOTE(- skipping check because we are cross compiling; assuming sockets are normal))
+rm -f /tmp/conftest*
+fi
+
+
+dnl
+dnl **** choose sockets or fifos ****
+dnl
+dnl **** check the select implementation ****
+dnl
+
+AC_TRY_RUN([
+/* For select - According to POSIX 1003.1-2001 */
+#include <sys/select.h>
+
+/* For select - According to earlier standards */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.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()
+{
+ fd_set f;
+
+#ifdef __FreeBSD__
+/* From Andrew A. Chernov (ache@astral.msk.su):
+ * opening RDWR fifo fails in BSD 4.4, but select return values are
+ * 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, l;
+ struct sockaddr_un a;
+ fd_set f;
+
+ (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
+
+
+ FD_SET(0, &f);
+ if (select(1, &f, 0, 0, 0) == -1)
+ exit(1);
+ if (select(1, &f, &f, 0, 0) != 2)
+ exit(1);
+ exit(0);
+}
+],AC_NOTE(- select is ok),
+AC_NOTE(- select can't count) AC_DEFINE(SELECT_BROKEN),
+AC_NOTE(- skipping check because we are cross compiling; assuming select is ok))
+
+dnl
+dnl **** termcap or terminfo ****
+dnl
+AC_CHECKING(for tgetent)
+AC_TRY_LINK(,tgetent((char *)0, (char *)0);,,
+olibs="$LIBS"
+LIBS="-lcurses $olibs"
+AC_CHECKING(libcurses)
+AC_TRY_LINK(,[
+#ifdef __hpux
+__sorry_hpux_libcurses_is_totally_broken_in_10_10();
+#else
+tgetent((char *)0, (char *)0);
+#endif
+],,
+LIBS="-ltermcap $olibs"
+AC_CHECKING(libtermcap)
+AC_TRY_LINK(,tgetent((char *)0, (char *)0);,,
+LIBS="-ltermlib $olibs"
+AC_CHECKING(libtermlib)
+AC_TRY_LINK(,tgetent((char *)0, (char *)0);,,
+LIBS="-lncursesw $olibs"
+AC_CHECKING(libncursesw)
+AC_TRY_LINK(,tgetent((char *)0, (char *)0);,,
+LIBS="-ltinfow $olibs"
+AC_CHECKING(libtinfow)
+AC_TRY_LINK(,tgetent((char *)0, (char *)0);,,
+LIBS="-lncurses $olibs"
+AC_CHECKING(libncurses)
+AC_TRY_LINK(,tgetent((char *)0, (char *)0);,,
+LIBS="-ltinfo $olibs"
+AC_CHECKING(libtinfo)
+AC_TRY_LINK(,tgetent((char *)0, (char *)0);,,
+AC_MSG_ERROR(!!! no tgetent - no screen)))))))))
+
+AC_TRY_RUN([
+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_NOTE(- skipping check because we are cross compiling; assuming terminfo database is used) AC_DEFINE(TERMINFO))
+AC_CHECKING(ospeed)
+AC_TRY_LINK(extern short ospeed;,ospeed=5;,,AC_DEFINE(NEED_OSPEED))
+
+dnl
+dnl **** PTY specific things ****
+dnl
+if test "$cross_compiling" = no ; then
+AC_CHECKING(for /dev/ptc)
+if test -r /dev/ptc; then
+AC_DEFINE(HAVE_DEV_PTC)
+fi
+fi
+
+if test "$cross_compiling" = no ; then
+AC_CHECKING(for SVR4 ptys)
+sysvr4ptys=
+if test -c /dev/ptmx ; then
+AC_TRY_LINK([],[ptsname(0);grantpt(0);unlockpt(0);],[AC_DEFINE(HAVE_SVR4_PTYS)
+sysvr4ptys=1])
+fi
+fi
+
+AC_CHECK_FUNCS(getpt)
+
+dnl check for openpty()
+if test -z "$sysvr4ptys"; then
+AC_CHECK_FUNCS(openpty,,
+[AC_CHECK_LIB(util,openpty, [AC_DEFINE(HAVE_OPENPTY)] [LIBS="$LIBS -lutil"])])
+fi
+
+if test "$cross_compiling" = no ; then
+AC_CHECKING(for ptyranges)
+if test -d /dev/ptym ; then
+pdir='/dev/ptym'
+else
+pdir='/dev'
+fi
+dnl SCO uses ptyp%d
+AC_EGREP_CPP(YES_IS_DEFINED,
+[#ifdef M_UNIX
+ YES_IS_DEFINED;
+#endif
+], ptys=`echo /dev/ptyp??`, ptys=`echo $pdir/pty??`)
+dnl if test -c /dev/ptyp19; then
+dnl ptys=`echo /dev/ptyp??`
+dnl else
+dnl ptys=`echo $pdir/pty??`
+dnl fi
+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
+fi
+
+dnl **** pty mode/group handling ****
+dnl
+dnl support provided by Luke Mewburn <lm@rmit.edu.au>, 931222
+AC_ARG_WITH(pty-mode, [ --with-pty-mode=mode default mode for ptys], [ ptymode="${withval}" ])
+AC_ARG_WITH(pty-group, [ --with-pty-group=group default group for ptys], [ ptygrp="${withval}" ])
+test -n "$ptymode" || ptymode=0620
+if test -n "$ptygrp" ; then
+AC_DEFINE_UNQUOTED(PTYMODE, $ptymode)
+AC_DEFINE_UNQUOTED(PTYGROUP,$ptygrp)
+else
+
+AC_CHECKING(default tty permissions/group)
+rm -f conftest_grp
+AC_TRY_RUN([
+#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: $ptymode, group: $ptygrp])
+ AC_DEFINE_UNQUOTED(PTYMODE, $ptymode)
+ AC_DEFINE_UNQUOTED(PTYGROUP,$ptygrp)
+ else
+ AC_NOTE(- ptys are world accessable)
+ fi
+],[
+ WRITEPATH=''
+ XTERMPATH=''
+ AC_PATH_PROG(WRITEPATH, write)
+ AC_PATH_PROG(XTERMPATH, xterm)
+ found=
+ if test -n "$WRITEPATH$XTERMPATH"; then
+ findfollow=
+ lsfollow=
+ found=`find $WRITEPATH $XTERMPATH -follow -print 2>/dev/null`
+ if test -n "$found"; then
+ findfollow=-follow
+ lsfollow=L
+ fi
+ if test -n "$XTERMPATH"; then
+ ptygrpn=`ls -l$lsfollow $XTERMPATH | sed -n -e 1p | $AWK '{print $4}'`
+ if test tty != "$ptygrpn"; then
+ XTERMPATH=
+ fi
+ fi
+ fi
+ if test -n "$WRITEPATH$XTERMPATH"; then
+ found=`find $WRITEPATH $XTERMPATH $findfollow -perm -2000 -print`
+ if test -n "$found"; then
+ ptygrp=`ls -ln$lsfollow $found | sed -n -e 1p | $AWK '{print $4}'`
+ AC_NOTE([- pty mode: $ptymode, group: $ptygrp])
+ AC_DEFINE_UNQUOTED(PTYMODE, $ptymode)
+ AC_DEFINE_UNQUOTED(PTYGROUP,$ptygrp)
+ else
+ AC_NOTE(- ptys are world accessable)
+ fi
+ else
+ AC_NOTE(- can't determine - assume ptys are world accessable)
+ fi
+ ],
+ AC_NOTE(- skipping check because we are cross compiling; assuming ptys are world accessable)
+)
+rm -f conftest_grp
+fi
+
+dnl
+dnl **** utmp handling ****
+dnl
+AC_CHECKING(getutent)
+AC_TRY_LINK([
+#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; pututline((struct utmp *)0); getutent();], AC_DEFINE(GETUTENT),
+olibs="$LIBS"
+LIBS="$LIBS -lgen"
+AC_CHECKING(getutent with -lgen)
+AC_TRY_LINK([
+#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; pututline((struct utmp *)0); getutent();], AC_DEFINE(GETUTENT), LIBS="$olibs")
+)
+AC_CHECKING(ut_host)
+AC_TRY_COMPILE([
+#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))
+AC_CHECK_HEADER(utempter.h, have_utempter=yes, have_utempter=no)
+if test "$have_utempter" = yes; then
+ AC_DEFINE(HAVE_UTEMPTER)
+ LIBS="$LIBS -lutempter"
+fi
+
+dnl
+dnl **** loadav ****
+dnl
+if test "$cross_compiling" = no ; then
+AC_CHECKING(for libutil(s))
+test -f /usr/lib/libutils.a && LIBS="$LIBS -lutils"
+test -f /usr/lib/libutil.a && LIBS="$LIBS -lutil"
+fi
+
+AC_CHECKING(getloadavg)
+AC_TRY_LINK(,[getloadavg((double *)0, 0);],
+AC_DEFINE(LOADAV_GETLOADAVG) load=1,
+if test "$cross_compiling" = no && test -f /usr/lib/libkvm.a ; then
+olibs="$LIBS"
+LIBS="$LIBS -lkvm"
+AC_CHECKING(getloadavg with -lkvm)
+AC_TRY_LINK(,[getloadavg((double *)0, 0);],
+AC_DEFINE(LOADAV_GETLOADAVG) load=1, LIBS="$olibs")
+fi
+)
+
+if test -z "$load" ; then
+AC_EGREP_CPP(YES_IS_DEFINED,
+[#if defined(NeXT) || defined(apollo) || defined(linux)
+ YES_IS_DEFINED;
+#endif
+], load=1)
+fi
+if test -z "$load" && test "$cross_compiling" = no ; 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')
+ if test -r $core ; then
+ AC_DEFINE_UNQUOTED(LOADAV_UNIX,"$core")
+ AC_CHECK_HEADER(nlist.h,
+ [AC_DEFINE(NLIST_STRUCT)
+ AC_CHECKING(n_un in struct nlist)
+ AC_TRY_COMPILE([#include <nlist.h>],
+ [struct nlist n; n.n_un.n_name = 0;],
+ AC_DEFINE(NLIST_NAME_UNION))])
+
+ AC_CHECKING(for nlist declaration)
+ AC_EGREP_CPP([nlist(( | )( | )*.*\(|\()],[
+#ifdef NLIST_STRUCT
+# include <nlist.h>
+#else
+# include <a.out.h>
+#endif
+],AC_DEFINE(NLIST_DECLARED))
+
+ AC_CHECKING(for avenrun symbol)
+ nlist64=
+ for av in avenrun _avenrun _Loadavg avenrun _avenrun _Loadavg; do
+ AC_TRY_RUN([
+#include <sys/types.h>
+#ifdef NLIST_STRUCT
+#include <nlist.h>
+#else
+#include <a.out.h>
+#endif
+
+$nlist64
+
+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)
+ if test "$av" = _Loadavg; then
+ nlist64='#define nlist nlist64'
+ fi
+ 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")
+ if test -n "$nlist64"; then
+ AC_NOTE(- used nlist64 to find it)
+ AC_DEFINE(LOADAV_USE_NLIST64)
+ fi
+ load=1
+ fi
+ else
+ AC_NOTE( Can't configure the load average display feature)
+ AC_NOTE( because $core is not readable by you.)
+ AC_NOTE( To configure the load average display feature,)
+ AC_NOTE( re-run configure as root if possible.)
+ AC_NOTE( If you are not the system administrator then disregard)
+ AC_NOTE( this warning. You can still use screen without)
+ AC_NOTE( the load average display feature.)
+ fi
+fi
+fi
+
+AC_PROGRAM_SOURCE([
+#include <sys/types.h>
+#include <sys/param.h>
+],[
+#if !defined(LOADAV_GETLOADAVG) && ((defined(hp300) && !defined(__hpux)) || defined(sun) || (defined(ultrix) && defined(mips)) || defined(_SEQUENT_) || defined(sgi) || (defined(SVR4) && !defined(__hpux)) || defined(sony_news) || (!defined(__osf__) && 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
+loadtype=int
+loadscale=1024
+# 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_CHECKING(return type of signal handlers)
+AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+extern void (*signal ()) ();], [int i;], AC_DEFINE(SIGVOID))
+AC_CHECKING(sigset)
+AC_TRY_LINK([
+#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_TRY_RUN([
+#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)
+if test "$cross_compiling" = no ; then
+test -f /lib/libcrypt_d.a || test -f /usr/lib/libcrypt_d.a && LIBS="$LIBS -lcrypt_d"
+fi
+oldlibs="$LIBS"
+LIBS="$LIBS -lcrypt"
+AC_CHECKING(crypt)
+AC_TRY_LINK(,,,LIBS="$oldlibs")
+if test "$cross_compiling" = no ; then
+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"
+fi
+
+oldlibs="$LIBS"
+LIBS="$LIBS -lsun"
+AC_CHECKING(IRIX sun library)
+AC_TRY_LINK(,,,LIBS="$oldlibs")
+
+AC_CHECKING(syslog)
+AC_TRY_LINK(,[closelog();], , [oldlibs="$LIBS"
+LIBS="$LIBS -lbsd"
+AC_CHECKING(syslog in libbsd.a)
+AC_TRY_LINK(, [closelog();], AC_NOTE(- found.), [LIBS="$oldlibs"
+AC_NOTE(- bad news: syslog missing.) AC_DEFINE(NOSYSLOG)])])
+
+AC_EGREP_CPP(YES_IS_DEFINED,
+[#ifdef M_UNIX
+ YES_IS_DEFINED;
+#endif
+], LIBS="$LIBS -lsocket -lcrypt_i")
+
+dnl
+dnl **** misc things ****
+dnl
+AC_CHECKING(wait union)
+AC_TRY_COMPILE([#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_TRY_CPP([#include <termio.h>], AC_DEFINE(TERMIO),
+if test -n "$posix"; then
+AC_TRY_CPP([#include <termios.h>], AC_DEFINE(TERMIO))
+fi
+)
+fi
+
+dnl AC_CHECK_HEADER(shadow.h, AC_DEFINE(SHADOWPW))
+AC_CHECKING(getspnam)
+AC_TRY_LINK([#include <shadow.h>], [getspnam("x");],AC_DEFINE(SHADOWPW))
+
+AC_CHECKING(getttyent)
+AC_TRY_LINK(,[getttyent();], AC_DEFINE(GETTTYENT))
+
+AC_CHECKING(fdwalk)
+AC_TRY_LINK([#include <stdlib.h>], [fdwalk(NULL, NULL);],AC_DEFINE(HAVE_FDWALK))
+
+AC_CHECKING(whether memcpy/memmove/bcopy handles overlapping arguments)
+AC_TRY_RUN([
+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_TRY_RUN([
+#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_NOTE(- skipping check because we are cross compiling; use memmove) AC_DEFINE(USEMEMMOVE))
+
+
+AC_TRY_RUN([
+#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_SYS_LONG_FILE_NAMES
+
+AC_MSG_CHECKING(for vsprintf)
+AC_TRY_LINK([#include <stdarg.h>],[va_list valist; vsprintf(0,0,valist);], AC_MSG_RESULT(yes);AC_DEFINE(USEVARARGS), AC_MSG_RESULT(no))
+
+AC_HEADER_DIRENT
+
+AC_MSG_CHECKING(for setenv)
+if test -z "$ac_setenv_args"; then
+ AC_TRY_LINK(
+ [#include <stdlib.h>],
+ [
+ setenv((char *) 0, (char *) 0, 0);
+ ], ac_setenv_args=3)
+fi
+if test -z "$ac_setenv_args"; then
+ AC_TRY_LINK(
+ [#include <stdlib.h>],
+ [
+ setenv((char *) 0, (char *) 0);
+ ], ac_setenv_args=2)
+fi
+if test -n "$ac_setenv_args"; then
+ AC_DEFINE(USESETENV)
+ if test "$ac_setenv_args" = 3; then
+ AC_DEFINE(HAVE_SETENV_3)
+ elif test "$ac_setenv_args" = 2; then
+ AC_DEFINE(HAVE_SETENV_2)
+ fi
+else
+ AC_MSG_RESULT(no)
+ AC_MSG_CHECKING(for putenv)
+ AC_TRY_LINK(,[putenv((char *)0);unsetenv((char *)0);], AC_MSG_RESULT(yes) , AC_MSG_RESULT(no);AC_DEFINE(NEEDPUTENV))
+fi
+AC_MSG_CHECKING([for nl_langinfo(CODESET)])
+AC_TRY_LINK([
+#include <langinfo.h>
+],[nl_langinfo(CODESET);], AC_MSG_RESULT(yes);AC_DEFINE(HAVE_NL_LANGINFO), AC_MSG_RESULT(no))
+
+AC_SEARCH_LIBS(gethostname, nsl)
+
+AC_CHECK_FUNCS(rename fchmod fchown strerror lstat _exit utimes vsnprintf getcwd setlocale strftime)
+
+AC_ARG_ENABLE(pam, [ --enable-pam enable PAM support])
+if test "$enable_pam" = "yes"; then
+ AC_MSG_CHECKING(for PAM support)
+ oldlibs="$LIBS"
+ LIBS="$LIBS -lpam"
+ AC_TRY_LINK([#include <security/pam_appl.h>], [
+ pam_start(0, 0, 0, 0);
+ pam_authenticate(0, 0);
+ pam_end(0,0);
+ ], AC_MSG_RESULT(yes);AC_DEFINE(USE_PAM),
+ AC_MSG_RESULT(no);LIBS="$oldlibs")
+fi
+
+AC_ARG_ENABLE(use-locale,
+ [ --enable-use-locale use localized month/day names (default: yes)],
+ [],
+ [enable_use_locale=yes]
+)
+if test "$enable_use_locale" = "yes"; then
+ AC_DEFINE(USE_LOCALE)
+fi
+AC_ARG_ENABLE(telnet, [ --enable-telnet enable builtin telnet])
+if test "$enable_telnet" = "yes"; then
+ AC_DEFINE(BUILTIN_TELNET)
+fi
+AC_ARG_ENABLE(colors256, [ --enable-colors256 enable support for 256 colors])
+if test "$enable_colors256" = "yes"; then
+ AC_DEFINE(COLORS256)
+fi
+AC_ARG_ENABLE(rxvt_osc, [ --enable-rxvt_osc enable support for rxvt OSC codes])
+if test "$enable_rxvt_osc" = "yes"; then
+ AC_DEFINE(RXVT_OSC)
+fi
+
+dnl
+dnl **** the end ****
+dnl
+if test -z "$old_CFLAGS"; then
+ if test "x$CFLAGS" = "x-g"; then
+ CFLAGS="-O"
+ fi
+fi
+dnl Ptx bug workaround -- insert -lc after -ltermcap
+test -n "$seqptx" && LIBS="-ltermcap -lc -lsocket -linet -lnsl -lsec -lseq"
+
+ETCSCREENRC=
+AC_MSG_CHECKING(for the global screenrc file)
+AC_ARG_WITH(sys-screenrc, [ --with-sys-screenrc=path to the global screenrc file], [ ETCSCREENRC="${withval}" ])
+AC_SUBST(ETCSCREENRC)
+
+AC_OUTPUT(Makefile doc/Makefile, [[
+# a hook for preserving undef directive in config.h
+mv config.h conftest
+sed -e 's@^\(.*\)defin.\( .*\) .*/\*\(.*KEEP_UNDEF_HERE\)@\1undef\2 /\*\3@' < conftest > config.h
+rm -f conftest
+]])
+
+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 in 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..978b0a8
--- /dev/null
+++ b/display.c
@@ -0,0 +1,4082 @@
+/* Copyright (c) 2008, 2009
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Micah Cowan (micah@cowan.name)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
+ * 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 3, 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, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ */
+
+#include <sys/types.h>
+#include <signal.h>
+#include <fcntl.h>
+#ifndef sun
+# include <sys/ioctl.h>
+#endif
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+#include "braille.h"
+#include "canvas.h"
+
+/* CSI parsing status */
+enum
+ {
+ CSI_PB=0, CSI_PX=1, CSI_PY=2, CSI_DONE=3,
+ CSI_ESC_SEEN, CSI_BEGIN, CSI_INACTIVE, CSI_INVALID
+ };
+
+static int CountChars __P((int));
+static int DoAddChar __P((int));
+static int BlankResize __P((int, int));
+static int CallRewrite __P((int, int, int, int));
+static void disp_readev_fn __P((struct event *, char *));
+static void disp_processinput __P((struct display *, unsigned char *, int));
+static void disp_writeev_fn __P((struct event *, char *));
+#ifdef linux
+static void disp_writeev_eagain __P((struct event *, char *));
+#endif
+static void disp_status_fn __P((struct event *, char *));
+static void disp_hstatus_fn __P((struct event *, char *));
+static void disp_blocked_fn __P((struct event *, char *));
+#ifdef MAPKEYS
+static void disp_map_fn __P((struct event *, char *));
+#endif
+static void disp_idle_fn __P((struct event *, char *));
+#ifdef BLANKER_PRG
+static void disp_blanker_fn __P((struct event *, char *));
+#endif
+static void WriteLP __P((int, int));
+static void INSERTCHAR __P((int));
+static void RAW_PUTCHAR __P((int));
+#ifdef COLOR
+static void SetBackColor __P((int));
+#endif
+static void RemoveStatusMinWait __P((void));
+
+
+extern struct layer *flayer;
+extern struct win *windows, *fore;
+extern struct LayFuncs WinLf;
+
+extern int use_hardstatus;
+extern int MsgWait, MsgMinWait;
+extern const int Z0width, Z1width;
+extern unsigned char *blank, *null;
+extern struct mline mline_blank, mline_null, mline_old;
+extern struct mchar mchar_null, mchar_blank, mchar_so;
+extern struct NewWindow nwin_default;
+extern struct action idleaction;
+
+/* XXX shouldn't be here */
+extern char *hstatusstring;
+extern char *captionstring;
+
+extern int pastefont;
+extern int idletimo;
+
+#ifdef BLANKER_PRG
+extern int pty_preopen;
+#if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
+extern struct winsize glwz;
+#endif
+extern char **NewEnv;
+extern int real_uid, real_gid;
+extern int ServerSocket, eff_uid, eff_gid;
+#endif
+
+/*
+ * tputs needs this to calculate the padding
+ */
+#ifndef NEED_OSPEED
+extern
+#endif /* NEED_OSPEED */
+short ospeed;
+
+
+struct display *display, *displays;
+#ifdef COLOR
+int attr2color[8][4];
+int nattr2color;
+#endif
+
+#ifndef MULTI
+struct display TheDisplay;
+#endif
+
+/*
+ * The default values
+ */
+int defobuflimit = OBUF_MAX;
+int defnonblock = -1;
+int defmousetrack = 0;
+#ifdef AUTO_NUKE
+int defautonuke = 0;
+#endif
+int captionalways;
+int hardstatusemu = HSTATUS_IGNORE;
+
+int focusminwidth, focusminheight;
+
+/*
+ * 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, 0);
+}
+
+void
+DefClearLine(y, xs, xe, bce)
+int y, xs, xe, bce;
+{
+ LClearLine(flayer, y, xs, xe, bce, (struct mline *)0);
+}
+
+/*ARGSUSED*/
+int
+DefRewrite(y, xs, xe, rend, doit)
+int y, xs, xe, doit;
+struct mchar *rend;
+{
+ return EXPENSIVE;
+}
+
+/*ARGSUSED*/
+int
+DefResize(wi, he)
+int wi, he;
+{
+ return -1;
+}
+
+void
+DefRestore()
+{
+ LAY_DISPLAYS(flayer, InsertMode(0));
+ /* ChangeScrollRegion(0, D_height - 1); */
+ LKeypadMode(flayer, 0);
+ LCursorkeysMode(flayer, 0);
+ LCursorVisibility(flayer, 0);
+ LMouseMode(flayer, 0);
+ LSetRendition(flayer, &mchar_null);
+ LSetFlow(flayer, nwin_default.flowflag & FLOW_NOW);
+}
+
+/*
+ * Blank layer management
+ */
+
+struct LayFuncs BlankLf =
+{
+ DefProcess,
+ 0,
+ DefRedisplayLine,
+ DefClearLine,
+ DefRewrite,
+ BlankResize,
+ DefRestore,
+ 0
+};
+
+/*ARGSUSED*/
+static int
+BlankResize(wi, he)
+int wi, he;
+{
+ flayer->l_width = wi;
+ flayer->l_height = he;
+ return 0;
+}
+
+
+/*
+ * Generate new display, start with a blank layer.
+ * The termcap arrays are not initialised here.
+ * The new display is placed in the displays list.
+ */
+
+struct display *
+MakeDisplay(uname, utty, term, fd, pid, Mode)
+char *uname, *utty, *term;
+int fd, pid;
+struct mode *Mode;
+{
+ struct acluser **u;
+ struct baud_values *b;
+
+ if (!*(u = FindUserPtr(uname)) && UserAdd(uname, (char *)0, u))
+ return 0; /* could not find or add user */
+
+#ifdef MULTI
+ if ((display = (struct display *)calloc(1, sizeof(*display))) == 0)
+ return 0;
+#else
+ if (displays)
+ return 0;
+ bzero((char *)&TheDisplay, sizeof(TheDisplay));
+ display = &TheDisplay;
+#endif
+ display->d_next = displays;
+ displays = display;
+ D_flow = 1;
+ D_nonblock = defnonblock;
+ D_userfd = fd;
+ D_readev.fd = D_writeev.fd = fd;
+ D_readev.type = EV_READ;
+ D_writeev.type = EV_WRITE;
+ D_readev.data = D_writeev.data = (char *)display;
+ D_readev.handler = disp_readev_fn;
+ D_writeev.handler = disp_writeev_fn;
+ evenq(&D_readev);
+ D_writeev.condpos = &D_obuflen;
+ D_writeev.condneg = &D_obuffree;
+ evenq(&D_writeev);
+ D_statusev.type = EV_TIMEOUT;
+ D_statusev.data = (char *)display;
+ D_statusev.handler = disp_status_fn;
+ D_hstatusev.type = EV_TIMEOUT;
+ D_hstatusev.data = (char *)display;
+ D_hstatusev.handler = disp_hstatus_fn;
+ D_blockedev.type = EV_TIMEOUT;
+ D_blockedev.data = (char *)display;
+ D_blockedev.handler = disp_blocked_fn;
+ D_blockedev.condpos = &D_obuffree;
+ D_blockedev.condneg = &D_obuflenmax;
+ D_hstatusev.handler = disp_hstatus_fn;
+#ifdef MAPKEYS
+ D_mapev.type = EV_TIMEOUT;
+ D_mapev.data = (char *)display;
+ D_mapev.handler = disp_map_fn;
+#endif
+ D_idleev.type = EV_TIMEOUT;
+ D_idleev.data = (char *)display;
+ D_idleev.handler = disp_idle_fn;
+#ifdef BLANKER_PRG
+ D_blankerev.type = EV_READ;
+ D_blankerev.data = (char *)display;
+ D_blankerev.handler = disp_blanker_fn;
+ D_blankerev.fd = -1;
+#endif
+ D_OldMode = *Mode;
+ D_status_obuffree = -1;
+ Resize_obuf(); /* Allocate memory for buffer */
+ D_obufmax = defobuflimit;
+ D_obuflenmax = D_obuflen - D_obufmax;
+#ifdef AUTO_NUKE
+ D_auto_nuke = defautonuke;
+#endif
+ D_obufp = D_obuf;
+ D_printfd = -1;
+ D_userpid = pid;
+
+#ifdef POSIX
+ if ((b = lookup_baud((int)cfgetospeed(&D_OldMode.tio))))
+ D_dospeed = b->idx;
+#else
+# ifdef TERMIO
+ if ((b = lookup_baud(D_OldMode.tio.c_cflag & CBAUD)))
+ D_dospeed = b->idx;
+# else
+ D_dospeed = (short)D_OldMode.m_ttyb.sg_ospeed;
+# endif
+#endif
+ debug1("New displays ospeed = %d\n", D_dospeed);
+
+ strncpy(D_usertty, utty, sizeof(D_usertty) - 1);
+ D_usertty[sizeof(D_usertty) - 1] = 0;
+ strncpy(D_termname, term, MAXTERMLEN);
+ D_termname[MAXTERMLEN] = 0;
+ D_user = *u;
+ D_processinput = ProcessInput;
+ D_mousetrack = defmousetrack;
+ return display;
+}
+
+
+void
+FreeDisplay()
+{
+ struct win *p;
+#ifdef MULTI
+ struct display *d, **dp;
+#endif
+
+#ifdef FONT
+ FreeTransTable();
+#endif
+#ifdef BLANKER_PRG
+ KillBlanker();
+#endif
+ if (D_userfd >= 0)
+ {
+ Flush(3);
+ if (!display)
+ return;
+ SetTTY(D_userfd, &D_OldMode);
+ fcntl(D_userfd, F_SETFL, 0);
+ }
+ freetty();
+ if (D_tentry)
+ free(D_tentry);
+ D_tentry = 0;
+ if (D_processinputdata)
+ free(D_processinputdata);
+ D_processinputdata = 0;
+ D_tcinited = 0;
+ evdeq(&D_hstatusev);
+ evdeq(&D_statusev);
+ evdeq(&D_readev);
+ evdeq(&D_writeev);
+ evdeq(&D_blockedev);
+#ifdef MAPKEYS
+ evdeq(&D_mapev);
+ if (D_kmaps)
+ {
+ free(D_kmaps);
+ D_kmaps = 0;
+ D_aseqs = 0;
+ D_nseqs = 0;
+ D_seqp = 0;
+ D_seql = 0;
+ D_seqh = 0;
+ }
+#endif
+ evdeq(&D_idleev);
+#ifdef BLANKER_PRG
+ evdeq(&D_blankerev);
+#endif
+#ifdef HAVE_BRAILLE
+ if (bd.bd_dpy == display)
+ {
+ bd.bd_start_braille = 0;
+ StartBraille();
+ }
+#endif
+
+#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;
+#else /* MULTI */
+ ASSERT(display == displays);
+ ASSERT(display == &TheDisplay);
+ displays = 0;
+#endif /* MULTI */
+
+ while (D_canvas.c_slperp)
+ FreeCanvas(D_canvas.c_slperp);
+ D_cvlist = 0;
+
+ for (p = windows; p; p = p->w_next)
+ {
+ if (p->w_pdisplay == display)
+ p->w_pdisplay = 0;
+ if (p->w_lastdisp == display)
+ p->w_lastdisp = 0;
+ if (p->w_readev.condneg == &D_status || p->w_readev.condneg == &D_obuflenmax)
+ p->w_readev.condpos = p->w_readev.condneg = 0;
+ }
+#ifdef ZMODEM
+ for (p = windows; p; p = p->w_next)
+ if (p->w_zdisplay == display)
+ zmodem_abort(p, 0);
+#endif
+ if (D_mousetrack)
+ {
+ D_mousetrack = 0;
+ MouseMode(0);
+ }
+#ifdef MULTI
+ free((char *)display);
+#endif
+ 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;
+ AddCStr(D_IS);
+ AddCStr(D_TI);
+ /* Check for toggle */
+ if (D_IM && strcmp(D_IM, D_EI))
+ AddCStr(D_EI);
+ D_insert = 0;
+#ifdef MAPKEYS
+ AddCStr(D_KS);
+ AddCStr(D_CCS);
+#else
+ /* Check for toggle */
+ if (D_KS && strcmp(D_KS, D_KE))
+ AddCStr(D_KE);
+ if (D_CCS && strcmp(D_CCS, D_CCE))
+ AddCStr(D_CCE);
+#endif
+ D_keypad = 0;
+ D_cursorkeys = 0;
+ AddCStr(D_ME);
+ AddCStr(D_EA);
+ AddCStr(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(3);
+ ClearAll();
+ 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);
+#ifdef BLANKER_PRG
+ KillBlanker();
+#endif
+ if (D_tcinited)
+ {
+ ResizeDisplay(D_defwidth, D_defheight);
+ InsertMode(0);
+ ChangeScrollRegion(0, D_height - 1);
+ KeypadMode(0);
+ CursorkeysMode(0);
+ CursorVisibility(0);
+ if (D_mousetrack)
+ D_mousetrack = 0;
+ MouseMode(0);
+ ExtMouseMode(0);
+ SetRendition(&mchar_null);
+ SetFlow(FLOW_NOW);
+#ifdef MAPKEYS
+ AddCStr(D_KE);
+ AddCStr(D_CCE);
+#endif
+ if (D_hstatus)
+ ShowHStatus((char *)0);
+#ifdef RXVT_OSC
+ ClearAllXtermOSC();
+#endif
+ D_x = D_y = -1;
+ GotoPos(0, D_height - 1);
+ AddChar('\r');
+ AddChar('\n');
+ AddCStr(D_TE);
+ }
+ Flush(3);
+}
+
+
+static void
+INSERTCHAR(c)
+int c;
+{
+ ASSERT(display);
+ if (!D_insert && D_x < D_width - 1)
+ {
+ if (D_IC || D_CIC)
+ {
+ if (D_IC)
+ AddCStr(D_IC);
+ else
+ AddCStr2(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)
+ {
+ int y = D_y;
+ RAW_PUTCHAR(c);
+ if (D_AM && !D_CLP)
+ GotoPos(D_width - 1, y);
+ return;
+ }
+ debug("PUTCHARLP: lp_missing!\n");
+ D_lp_missing = 1;
+ D_rend.image = c;
+ D_lpchar = D_rend;
+#ifdef DW_CHARS
+ /* XXX -> PutChar ? */
+ if (D_mbcs)
+ {
+ D_lpchar.mbcs = c;
+ D_lpchar.image = D_mbcs;
+ D_mbcs = 0;
+ D_x--;
+ }
+#endif
+}
+
+/*
+ * RAW_PUTCHAR() is for all text that will be displayed.
+ * NOTE: charset Nr. 0 has a conversion table, but c1, c2, ... don't.
+ */
+
+STATIC void
+RAW_PUTCHAR(c)
+int c;
+{
+ ASSERT(display);
+
+#ifdef FONT
+# ifdef UTF8
+ if (D_encoding == UTF8)
+ {
+ c = (c & 255) | (unsigned char)D_rend.font << 8 | (unsigned char)D_rend.fontx << 16;
+# ifdef DW_CHARS
+ if (D_mbcs)
+ {
+ c = D_mbcs;
+ if (D_x == D_width)
+ D_x += D_AM ? 1 : -1;
+ D_mbcs = 0;
+ }
+ else if (utf8_isdouble(c))
+ {
+ D_mbcs = c;
+ D_x++;
+ return;
+ }
+# endif
+ if (c < 32)
+ {
+ AddCStr2(D_CS0, '0');
+ AddChar(c + 0x5f);
+ AddCStr(D_CE0);
+ goto addedutf8;
+ }
+ if (c < 0x80)
+ {
+ 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(c);
+ }
+ else
+ AddUtf8(c);
+ goto addedutf8;
+ }
+# endif
+# ifdef DW_CHARS
+ if (is_dw_font(D_rend.font))
+ {
+ int t = c;
+ if (D_mbcs == 0)
+ {
+ D_mbcs = c;
+ D_x++;
+ return;
+ }
+ D_x--;
+ if (D_x == D_width - 1)
+ D_x += D_AM ? 1 : -1;
+ c = D_mbcs;
+ D_mbcs = t;
+ }
+# endif
+# if defined(ENCODINGS) && defined(DW_CHARS)
+ if (D_encoding)
+ c = PrepareEncodedChar(c);
+# endif
+# ifdef DW_CHARS
+ 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]);
+#else /* FONT */
+ AddChar(c);
+#endif /* FONT */
+
+#ifdef UTF8
+addedutf8:
+#endif
+ 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 DW_CHARS
+ if (D_mbcs)
+ {
+ c = D_mbcs;
+ D_mbcs = 0;
+ goto kanjiloop;
+ }
+#endif
+}
+
+static int
+DoAddChar(c)
+int c;
+{
+ /* this is for ESC-sequences only (AddChar is a macro) */
+ AddChar(c);
+ return c;
+}
+
+void
+AddCStr(s)
+char *s;
+{
+ if (display && s && *s)
+ {
+ ospeed = D_dospeed;
+ tputs(s, 1, DoAddChar);
+ }
+}
+
+void
+AddCStr2(s, c)
+char *s;
+int c;
+{
+ if (display && s && *s)
+ {
+ ospeed = D_dospeed;
+ tputs(tgoto(s, 0, c), 1, DoAddChar);
+ }
+}
+
+
+/* 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 (on)
+ AddCStr(D_IM);
+ else
+ AddCStr(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 (on)
+ AddCStr(D_KS);
+ else
+ AddCStr(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 (on)
+ AddCStr(D_CCS);
+ else
+ AddCStr(D_CCE);
+ }
+#endif
+}
+
+void
+ReverseVideo(on)
+int on;
+{
+ if (display && D_revvid != on && D_CVR)
+ {
+ D_revvid = on;
+ if (D_revvid)
+ AddCStr(D_CVR);
+ else
+ AddCStr(D_CVN);
+ }
+}
+
+void
+CursorVisibility(v)
+int v;
+{
+ if (display && D_curvis != v)
+ {
+ if (D_curvis)
+ AddCStr(D_VE); /* do this always, just to be safe */
+ D_curvis = 0;
+ if (v == -1 && D_VI)
+ AddCStr(D_VI);
+ else if (v == 1 && D_VS)
+ AddCStr(D_VS);
+ else
+ return;
+ D_curvis = v;
+ }
+}
+
+void
+MouseMode(mode)
+int mode;
+{
+ if (!display)
+ return;
+
+ if (mode < D_mousetrack)
+ mode = D_mousetrack;
+
+ if (D_mouse != mode)
+ {
+ char mousebuf[20];
+ if (!D_CXT)
+ return;
+ if (D_mouse)
+ {
+ sprintf(mousebuf, "\033[?%dl", D_mouse);
+ AddStr(mousebuf);
+ }
+ if (mode)
+ {
+ sprintf(mousebuf, "\033[?%dh", mode);
+ AddStr(mousebuf);
+ }
+ D_mouse = mode;
+ D_mouse_parse.state = CSI_INACTIVE;
+ }
+}
+
+void
+ExtMouseMode(mode)
+ int mode;
+{
+ if (display && D_extmouse != mode)
+ {
+ char mousebuf[20];
+ if (!D_CXT)
+ return;
+ if (D_extmouse)
+ {
+ sprintf(mousebuf, "\033[?%dl", D_extmouse);
+ AddStr(mousebuf);
+ }
+ if (mode)
+ {
+ sprintf(mousebuf, "\033[?%dh", mode);
+ AddStr(mousebuf);
+ }
+ D_extmouse = mode;
+ D_mouse_parse.state = CSI_INACTIVE;
+ }
+}
+
+static int StrCost;
+
+/* ARGSUSED */
+static int
+CountChars(c)
+int c;
+{
+ StrCost++;
+ return c;
+}
+
+int
+CalcCost(s)
+register char *s;
+{
+ ASSERT(display);
+ if (s)
+ {
+ StrCost = 0;
+ ospeed = D_dospeed;
+ tputs(s, 1, CountChars);
+ return StrCost;
+ }
+ else
+ return EXPENSIVE;
+}
+
+static int
+CallRewrite(y, xs, xe, doit)
+int y, xs, xe, doit;
+{
+ struct canvas *cv, *cvlist, *cvlnext;
+ struct viewport *vp;
+ struct layer *oldflayer;
+ int cost;
+
+ debug3("CallRewrite %d %d %d\n", y, xs, xe);
+ ASSERT(display);
+ ASSERT(xe >= xs);
+
+ vp = 0;
+ for (cv = D_cvlist; cv; cv = cv->c_next)
+ {
+ if (y < cv->c_ys || y > cv->c_ye || xe < cv->c_xs || xs > cv->c_xe)
+ continue;
+ for (vp = cv->c_vplist; vp; vp = vp->v_next)
+ if (y >= vp->v_ys && y <= vp->v_ye && xe >= vp->v_xs && xs <= vp->v_xe)
+ break;
+ if (vp)
+ break;
+ }
+ if (doit)
+ {
+ oldflayer = flayer;
+ flayer = cv->c_layer;
+ cvlist = flayer->l_cvlist;
+ cvlnext = cv->c_lnext;
+ flayer->l_cvlist = cv;
+ cv->c_lnext = 0;
+ LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 1);
+ flayer->l_cvlist = cvlist;
+ cv->c_lnext = cvlnext;
+ flayer = oldflayer;
+ return 0;
+ }
+ if (cv == 0 || cv->c_layer == 0)
+ return EXPENSIVE; /* not found or nothing on it */
+ if (xs < vp->v_xs || xe > vp->v_xe)
+ return EXPENSIVE; /* crosses viewport boundaries */
+ if (y - vp->v_yoff < 0 || y - vp->v_yoff >= cv->c_layer->l_height)
+ return EXPENSIVE; /* line not on layer */
+ if (xs - vp->v_xoff < 0 || xe - vp->v_xoff >= cv->c_layer->l_width)
+ return EXPENSIVE; /* line not on layer */
+#ifdef UTF8
+ if (D_encoding == UTF8)
+ D_rend.font = 0;
+#endif
+ oldflayer = flayer;
+ flayer = cv->c_layer;
+ debug3("Calling Rewrite %d %d %d\n", y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff);
+ cost = LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 0);
+ flayer = oldflayer;
+ if (D_insert)
+ cost += D_EIcost + D_IMcost;
+ return cost;
+}
+
+
+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;
+ debug2("GotoPos (%d,%d)", x1, y1);
+ debug2(" -> (%d,%d)\n", x2, y2);
+ 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)
+ AddCStr(D_HO);
+ else
+ AddCStr(tgoto(D_CM, x2, y2));
+ D_x = x2;
+ D_y = y2;
+ return;
+ }
+
+ /* some scrollregion implementations don't allow movements
+ * away from the region. sigh.
+ */
+ if ((y1 > D_bot && y2 > y1) || (y1 < D_top && y2 < y1))
+ goto DoCM;
+
+ /* 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 <= LayRewrite() */
+ if (dx < costx && (m = CallRewrite(y1, x1, x2 - 1, 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: LayRewrite() >= x2 */
+ if (x2 + D_CRcost < costx && (m = (x2 ? CallRewrite(y1, 0, x2 - 1, 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)
+ AddCStr(D_BC);
+ break;
+ case M_CLE:
+ AddCStr2(D_CLE, -dx);
+ break;
+ case M_RI:
+ while (dx-- > 0)
+ AddCStr(D_ND);
+ break;
+ case M_CRI:
+ AddCStr2(D_CRI, dx);
+ break;
+ case M_CR:
+ AddCStr(D_CR);
+ D_x = 0;
+ x1 = 0;
+ /* FALLTHROUGH */
+ case M_RW:
+ if (x1 < x2)
+ (void) CallRewrite(y1, x1, x2 - 1, 1);
+ break;
+ default:
+ break;
+ }
+
+ switch (ym)
+ {
+ case M_UP:
+ while (dy++ < 0)
+ AddCStr(D_UP);
+ break;
+ case M_CUP:
+ AddCStr2(D_CUP, -dy);
+ break;
+ case M_DO:
+ s = (x2 == 0) ? D_NL : D_DO;
+ while (dy-- > 0)
+ AddCStr(s);
+ break;
+ case M_CDO:
+ AddCStr2(D_CDO, dy);
+ break;
+ default:
+ break;
+ }
+ D_x = x2;
+ D_y = y2;
+}
+
+void
+ClearAll()
+{
+ ASSERT(display);
+ ClearArea(0, 0, 0, D_width - 1, D_width - 1, D_height - 1, 0, 0);
+}
+
+void
+ClearArea(x1, y1, xs, xe, x2, y2, bce, uselayfn)
+int x1, y1, xs, xe, x2, y2, bce, uselayfn;
+{
+ int y, xxe;
+ struct canvas *cv;
+ struct viewport *vp;
+
+ debug2("Clear %d,%d", x1, y1);
+ debug2(" %d-%d", xs, xe);
+ debug2(" %d,%d", x2, y2);
+ debug2(" uselayfn=%d bce=%d\n", uselayfn, bce);
+ ASSERT(display);
+ if (x1 == D_width)
+ x1--;
+ if (x2 == D_width)
+ x2--;
+ if (xs == -1)
+ xs = x1;
+ if (xe == -1)
+ xe = x2;
+ if (D_UT) /* Safe to erase ? */
+ SetRendition(&mchar_null);
+#ifdef COLOR
+ if (D_BE)
+ SetBackColor(bce);
+#endif
+ 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 && (!bce || D_BE))
+ {
+#ifdef AUTO_NUKE
+ if (x1 == 0 && y1 == 0 && D_auto_nuke)
+ NukePending();
+#endif
+ if (x1 == 0 && y1 == 0 && D_CL)
+ {
+ AddCStr(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);
+ AddCStr(D_CD);
+ return;
+ }
+ }
+ if (x1 == 0 && xs == 0 && (xe == D_width - 1 || y1 == y2) && y1 == 0 && D_CCD && (!bce || D_BE))
+ {
+ GotoPos(x1, y1);
+ AddCStr(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)) && (!bce || D_BE))
+ {
+ GotoPos(xxe, y);
+ AddCStr(D_CB);
+ continue;
+ }
+ if (xxe == D_width - 1 && D_CE && (!bce || D_BE))
+ {
+ GotoPos(x1, y);
+ AddCStr(D_CE);
+ continue;
+ }
+ if (uselayfn)
+ {
+ vp = 0;
+ for (cv = D_cvlist; cv; cv = cv->c_next)
+ {
+ if (y < cv->c_ys || y > cv->c_ye || xxe < cv->c_xs || x1 > cv->c_xe)
+ continue;
+ for (vp = cv->c_vplist; vp; vp = vp->v_next)
+ if (y >= vp->v_ys && y <= vp->v_ye && xxe >= vp->v_xs && x1 <= vp->v_xe)
+ break;
+ if (vp)
+ break;
+ }
+ if (cv && cv->c_layer && x1 >= vp->v_xs && xxe <= vp->v_xe &&
+ y - vp->v_yoff >= 0 && y - vp->v_yoff < cv->c_layer->l_height &&
+ xxe - vp->v_xoff >= 0 && x1 - vp->v_xoff < cv->c_layer->l_width)
+ {
+ struct layer *oldflayer = flayer;
+ struct canvas *cvlist, *cvlnext;
+ flayer = cv->c_layer;
+ cvlist = flayer->l_cvlist;
+ cvlnext = cv->c_lnext;
+ flayer->l_cvlist = cv;
+ cv->c_lnext = 0;
+ LayClearLine(y - vp->v_yoff, x1 - vp->v_xoff, xxe - vp->v_xoff, bce);
+ flayer->l_cvlist = cvlist;
+ cv->c_lnext = cvlnext;
+ flayer = oldflayer;
+ continue;
+ }
+ }
+ ClearLine((struct mline *)0, y, x1, xxe, bce);
+ }
+}
+
+
+/*
+ * 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;
+{
+ ASSERT(display);
+
+ /* XXX do em all? */
+ InsertMode(0);
+ ChangeScrollRegion(0, D_height - 1);
+ KeypadMode(0);
+ CursorkeysMode(0);
+ CursorVisibility(0);
+ MouseMode(0);
+ ExtMouseMode(0);
+ SetRendition(&mchar_null);
+ SetFlow(FLOW_NOW);
+
+ ClearAll();
+#ifdef RXVT_OSC
+ RefreshXtermOSC();
+#endif
+ if (cur_only > 0 && D_fore)
+ RefreshArea(0, D_fore->w_y, D_width - 1, D_fore->w_y, 1);
+ else
+ RefreshAll(1);
+ RefreshHStatus();
+ CV_CALL(D_forecv, LayRestore();LaySetCursor());
+}
+
+void
+RedisplayDisplays(cur_only)
+int cur_only;
+{
+ struct display *olddisplay = display;
+ for (display = displays; display; display = display->d_next)
+ Redisplay(cur_only);
+ display = olddisplay;
+}
+
+
+/* XXX: use oml! */
+void
+ScrollH(y, xs, xe, n, bce, oml)
+int y, xs, xe, n, bce;
+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);
+#ifdef COLOR
+ if (D_BE)
+ SetBackColor(bce);
+#endif
+ if (n > 0)
+ {
+ if (n >= xe - xs + 1)
+ n = xe - xs + 1;
+ if (D_CDC && !(n == 1 && D_DC))
+ AddCStr2(D_CDC, n);
+ else if (D_DC)
+ {
+ for (i = n; i--; )
+ AddCStr(D_DC);
+ }
+ else
+ {
+ RefreshLine(y, xs, xe, 0);
+ /* UpdateLine(oml, y, xs, xe); */
+ return;
+ }
+ }
+ else
+ {
+ if (-n >= xe - xs + 1)
+ n = -(xe - xs + 1);
+ if (!D_insert)
+ {
+ if (D_CIC && !(n == -1 && D_IC))
+ AddCStr2(D_CIC, -n);
+ else if (D_IC)
+ {
+ for (i = -n; i--; )
+ AddCStr(D_IC);
+ }
+ else if (D_IM)
+ {
+ InsertMode(1);
+ SetRendition(&mchar_null);
+#ifdef COLOR
+ SetBackColor(bce);
+#endif
+ for (i = -n; i--; )
+ INSERTCHAR(' ');
+ bce = 0; /* all done */
+ }
+ else
+ {
+ /* UpdateLine(oml, y, xs, xe); */
+ RefreshLine(y, xs, xe, 0);
+ return;
+ }
+ }
+ else
+ {
+ SetRendition(&mchar_null);
+#ifdef COLOR
+ SetBackColor(bce);
+#endif
+ for (i = -n; i--; )
+ INSERTCHAR(' ');
+ bce = 0; /* all done */
+ }
+ }
+ if (bce && !D_BE)
+ {
+ if (n > 0)
+ ClearLine((struct mline *)0, y, xe - n + 1, xe, bce);
+ else
+ ClearLine((struct mline *)0, y, xs, xs - n - 1, bce);
+ }
+ if (D_lp_missing && y == D_bot)
+ {
+ if (n > 0)
+ WriteLP(D_width - 1 - n, y);
+ D_lp_missing = 0;
+ }
+}
+
+void
+ScrollV(xs, ys, xe, ye, n, bce)
+int xs, ys, xe, ye, n, bce;
+{
+ int i;
+ int up;
+ int oldbot;
+ int alok, dlok, aldlfaster;
+ int missy = 0;
+
+ ASSERT(display);
+ if (n == 0)
+ return;
+ if (n >= ye - ys + 1 || -n >= ye - ys + 1)
+ {
+ ClearArea(xs, ys, xs, xe, xe, ye, bce, 0);
+ return;
+ }
+ if (xs > D_vpxmin || xe < D_vpxmax)
+ {
+ RefreshArea(xs, ys, xe, ye, 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;
+
+ oldbot = D_bot;
+ if (ys < D_top || D_bot != ye)
+ ChangeScrollRegion(ys, ye);
+ alok = (D_AL || D_CAL || (ys >= D_top && ye == D_bot && up));
+ dlok = (D_DL || D_CDL || (ys >= D_top && 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)))
+ {
+ WriteLP(D_width - 1, oldbot);
+ if (oldbot == D_bot) /* have scrolled */
+ {
+ if (--n == 0)
+ {
+/* XXX
+ ChangeScrollRegion(oldtop, oldbot);
+*/
+ if (bce && !D_BE)
+ ClearLine((struct mline *)0, ye, xs, xe, bce);
+ return;
+ }
+ }
+ }
+
+ if (D_UT)
+ SetRendition(&mchar_null);
+#ifdef COLOR
+ if (D_BE)
+ SetBackColor(bce);
+#endif
+
+ aldlfaster = (n > 1 && ys >= D_top && ye == D_bot && ((up && D_CDL) || (!up && D_CAL)));
+
+ if ((up || D_SR) && D_top == ys && D_bot == ye && !aldlfaster)
+ {
+ if (up)
+ {
+ GotoPos(0, ye);
+ for(i = n; i-- > 0; )
+ AddCStr(D_NL); /* was SF, I think NL is faster */
+ }
+ else
+ {
+ GotoPos(0, ys);
+ for(i = n; i-- > 0; )
+ AddCStr(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))
+ AddCStr2(D_CDL, n);
+ else
+ for(i = n; i--; )
+ AddCStr(D_DL);
+ }
+ if (!up || ye != D_bot)
+ {
+ GotoPos(0, up ? ye+1-n : ys);
+ if (D_CAL && !(n == 1 && D_AL))
+ AddCStr2(D_CAL, n);
+ else
+ for(i = n; i--; )
+ AddCStr(D_AL);
+ }
+ }
+ else
+ {
+ RefreshArea(xs, ys, xe, ye, 0);
+ return;
+ }
+ if (bce && !D_BE)
+ {
+ if (up)
+ ClearArea(xs, ye - n + 1, xs, xe, xe, ye, bce, 0);
+ else
+ ClearArea(xs, ys, xs, xe, xe, ys + n - 1, bce, 0);
+ }
+ if (D_lp_missing && missy != D_bot)
+ WriteLP(D_width - 1, missy);
+/* XXX
+ ChangeScrollRegion(oldtop, oldbot);
+ if (D_lp_missing && missy != D_bot)
+ WriteLP(D_width - 1, missy);
+*/
+}
+
+void
+SetAttr(new)
+register int new;
+{
+ register int i, j, old, typ;
+
+ if (!display || (old = D_rend.attr) == new)
+ return;
+#ifdef COLORS16
+ D_col16change = (old ^ new) & (A_BFG | A_BBG);
+ new ^= D_col16change;
+ if (old == new)
+ return;
+#endif
+#if defined(TERMINFO) && defined(USE_SGR)
+ if (D_SA)
+ {
+ char *tparm();
+ SetFont(ASCII);
+ ospeed = D_dospeed;
+ 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, DoAddChar);
+ D_rend.attr = new;
+ D_atyp = 0;
+# ifdef COLOR
+ if (D_hascolor)
+ rend_setdefault(&D_rend);
+# endif
+ return;
+ }
+#endif
+ D_rend.attr = new;
+ typ = D_atyp;
+ if ((new & old) != old)
+ {
+ if ((typ & ATYP_U))
+ AddCStr(D_UE);
+ if ((typ & ATYP_S))
+ AddCStr(D_SE);
+ if ((typ & ATYP_M))
+ {
+ AddCStr(D_ME);
+#ifdef COLOR
+ /* ansi attrib handling: \E[m resets color, too */
+ if (D_hascolor)
+ rend_setdefault(&D_rend);
+#endif
+#ifdef FONT
+ if (!D_CG0)
+ {
+ /* D_ME may also reset the alternate charset */
+ D_rend.font = 0;
+# ifdef ENCODINGS
+ D_realfont = 0;
+# endif
+ }
+#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])
+ {
+ AddCStr(D_attrtab[i]);
+ typ |= D_attrtyp[i];
+ }
+ }
+ D_atyp = typ;
+}
+
+#ifdef FONT
+void
+SetFont(new)
+int new;
+{
+ int old = D_rend.font;
+ if (!display || old == new)
+ return;
+ D_rend.font = new;
+#ifdef ENCODINGS
+ if (D_encoding && CanEncodeFont(D_encoding, new))
+ return;
+ if (new == D_realfont)
+ return;
+ D_realfont = new;
+#endif
+ if (D_xtable && D_xtable[(int)(unsigned char)new] &&
+ D_xtable[(int)(unsigned char)new][256])
+ {
+ AddCStr(D_xtable[(int)(unsigned char)new][256]);
+ return;
+ }
+
+ if (!D_CG0 && new != '0')
+ {
+ new = ASCII;
+ if (old == new)
+ return;
+ }
+
+ if (new == ASCII)
+ AddCStr(D_CE0);
+#ifdef DW_CHARS
+ else if (new < ' ')
+ {
+ AddStr("\033$");
+ if (new > 2)
+ AddChar('(');
+ AddChar(new + '@');
+ }
+#endif
+ else
+ AddCStr2(D_CS0, new);
+}
+#endif
+
+#ifdef COLOR
+
+int
+color256to16(jj)
+int jj;
+{
+ int min, max;
+ int r, g, b;
+
+ if (jj >= 232)
+ {
+ jj = (jj - 232) / 6;
+ jj = (jj & 1) << 3 | (jj & 2 ? 7 : 0);
+ }
+ else if (jj >= 16)
+ {
+ jj -= 16;
+ r = jj / 36;
+ g = (jj / 6) % 6;
+ b = jj % 6;
+ min = r < g ? (r < b ? r : b) : (g < b ? g : b);
+ max = r > g ? (r > b ? r : b) : (g > b ? g : b);
+ if (min == max)
+ jj = ((max + 1) & 2) << 2 | ((max + 1) & 4 ? 7 : 0);
+ else
+ jj = (b - min) / (max - min) << 2 | (g - min) / (max - min) << 1 | (r -
+min) / (max - min) | (max > 3 ? 8 : 0);
+ }
+ return jj;
+}
+
+#ifdef COLORS256
+int
+color256to88(jj)
+int jj;
+{
+ int r, g, b;
+
+ if (jj >= 232)
+ return (jj - 232) / 3 + 80;
+ if (jj >= 16)
+ {
+ jj -= 16;
+ r = jj / 36;
+ g = (jj / 6) % 6;
+ b = jj % 6;
+ return ((r + 1) / 2) * 16 + ((g + 1) / 2) * 4 + ((b + 1) / 2) + 16;
+ }
+ return jj;
+}
+#endif
+
+void
+SetColor(f, b)
+int f, b;
+{
+ int of, ob;
+ static unsigned char sftrans[8] = {0,4,2,6,1,5,3,7};
+
+ if (!display)
+ return;
+
+ of = rend_getfg(&D_rend);
+ ob = rend_getbg(&D_rend);
+
+#ifdef COLORS16
+ /* intense default not invented yet */
+ if (f == 0x100)
+ f = 0;
+ if (b == 0x100)
+ b = 0;
+#endif
+ debug2("SetColor %d %d", coli2e(of), coli2e(ob));
+ debug2(" -> %d %d\n", coli2e(f), coli2e(b));
+ debug2("(%d %d", of, ob);
+ debug2(" -> %d %d)\n", f, b);
+
+ if (!D_CAX && D_hascolor && ((f == 0 && f != of) || (b == 0 && b != ob)))
+ {
+ if (D_OP)
+ AddCStr(D_OP);
+ else
+ {
+ int oattr;
+ oattr = D_rend.attr;
+ AddCStr(D_ME ? D_ME : "\033[m");
+#ifdef FONT
+ if (D_ME && !D_CG0)
+ {
+ /* D_ME may also reset the alternate charset */
+ D_rend.font = 0;
+# ifdef ENCODINGS
+ D_realfont = 0;
+# endif
+ }
+#endif
+ D_atyp = 0;
+ D_rend.attr = 0;
+ SetAttr(oattr);
+ }
+ of = ob = 0;
+ }
+ rend_setfg(&D_rend, f);
+ rend_setbg(&D_rend, b);
+#ifdef COLORS16
+ D_col16change = 0;
+#endif
+ if (!D_hascolor)
+ return;
+ f = f ? coli2e(f) : -1;
+ b = b ? coli2e(b) : -1;
+ of = of ? coli2e(of) : -1;
+ ob = ob ? coli2e(ob) : -1;
+#ifdef COLORS256
+ if (f != of && f > 15 && D_CCO != 256)
+ f = D_CCO == 88 && D_CAF ? color256to88(f) : color256to16(f);
+ if (f != of && f > 15 && D_CAF)
+ {
+ AddCStr2(D_CAF, f);
+ of = f;
+ }
+ if (b != ob && b > 15 && D_CCO != 256)
+ b = D_CCO == 88 && D_CAB ? color256to88(b) : color256to16(b);
+ if (b != ob && b > 15 && D_CAB)
+ {
+ AddCStr2(D_CAB, b);
+ ob = b;
+ }
+#endif
+ if (f != of && f != (of | 8))
+ {
+ if (f == -1)
+ AddCStr("\033[39m"); /* works because AX is set */
+ else if (D_CAF)
+ AddCStr2(D_CAF, f & 7);
+ else if (D_CSF)
+ AddCStr2(D_CSF, sftrans[f & 7]);
+ }
+ if (b != ob && b != (ob | 8))
+ {
+ if (b == -1)
+ AddCStr("\033[49m"); /* works because AX is set */
+ else if (D_CAB)
+ AddCStr2(D_CAB, b & 7);
+ else if (D_CSB)
+ AddCStr2(D_CSB, sftrans[b & 7]);
+ }
+#ifdef COLORS16
+ if (f != of && D_CXT && (f & 8) != 0 && f != -1)
+ {
+# ifdef TERMINFO
+ AddCStr2("\033[9%p1%dm", f & 7);
+# else
+ AddCStr2("\033[9%dm", f & 7);
+# endif
+ }
+ if (b != ob && D_CXT && (b & 8) != 0 && b != -1)
+ {
+# ifdef TERMINFO
+ AddCStr2("\033[10%p1%dm", b & 7);
+# else
+ AddCStr2("\033[10%dm", b & 7);
+# endif
+ }
+#endif
+}
+
+static void
+SetBackColor(new)
+int new;
+{
+ if (!display)
+ return;
+ SetColor(rend_getfg(&D_rend), new);
+}
+#endif /* COLOR */
+
+void
+SetRendition(mc)
+struct mchar *mc;
+{
+ if (!display)
+ return;
+#ifdef COLOR
+ if (nattr2color && D_hascolor && (mc->attr & nattr2color) != 0)
+ {
+ static struct mchar mmc;
+ int i;
+ mmc = *mc;
+ for (i = 0; i < 8; i++)
+ if (attr2color[i] && (mc->attr & (1 << i)) != 0)
+ {
+ if (mc->color == 0 && attr2color[i][3])
+ ApplyAttrColor(attr2color[i][3], &mmc);
+ else if ((mc->color & 0x0f) == 0 && attr2color[i][2])
+ ApplyAttrColor(attr2color[i][2], &mmc);
+ else if ((mc->color & 0xf0) == 0 && attr2color[i][1])
+ ApplyAttrColor(attr2color[i][1], &mmc);
+ else
+ ApplyAttrColor(attr2color[i][0], &mmc);
+ }
+ mc = &mmc;
+ debug2("SetRendition: mapped to %02x %02x\n", (unsigned char)mc->attr, 0x99 - (unsigned char)mc->color);
+ }
+# ifdef COLORS16
+ if (D_hascolor && D_CC8 && (mc->attr & (A_BFG|A_BBG)))
+ {
+ int a = mc->attr;
+ if ((mc->attr & A_BFG) && D_MD)
+ a |= A_BD;
+ if ((mc->attr & A_BBG) && D_MB)
+ a |= A_BL;
+ if (D_rend.attr != a)
+ SetAttr(a);
+ }
+ else
+# endif /* COLORS16 */
+#endif /* COLOR */
+ if (D_rend.attr != mc->attr)
+ SetAttr(mc->attr);
+
+#ifdef COLOR
+ if (D_rend.color != mc->color
+# ifdef COLORS256
+ || D_rend.colorx != mc->colorx
+# endif
+# ifdef COLORS16
+ || D_col16change
+# endif
+ )
+ SetColor(rend_getfg(mc), rend_getbg(mc));
+#endif
+#ifdef FONT
+ if (D_rend.font != mc->font)
+ SetFont(mc->font);
+#ifdef UTF8
+ if (D_encoding == UTF8)
+ D_rend.fontx = mc->fontx;
+#endif
+#endif
+}
+
+void
+SetRenditionMline(ml, x)
+struct mline *ml;
+int x;
+{
+ if (!display)
+ return;
+#ifdef COLOR
+ if (nattr2color && D_hascolor && (ml->attr[x] & nattr2color) != 0)
+ {
+ struct mchar mc;
+ copy_mline2mchar(&mc, ml, x);
+ SetRendition(&mc);
+ return;
+ }
+# ifdef COLORS16
+ if (D_hascolor && D_CC8 && (ml->attr[x] & (A_BFG|A_BBG)))
+ {
+ int a = ml->attr[x];
+ if ((ml->attr[x] & A_BFG) && D_MD)
+ a |= A_BD;
+ if ((ml->attr[x] & A_BBG) && D_MB)
+ a |= A_BL;
+ if (D_rend.attr != a)
+ SetAttr(a);
+ }
+ else
+# endif /* COLORS16 */
+#endif /* COLOR */
+ if (D_rend.attr != ml->attr[x])
+ SetAttr(ml->attr[x]);
+#ifdef COLOR
+ if (D_rend.color != ml->color[x]
+# ifdef COLORS256
+ || D_rend.colorx != ml->colorx[x]
+# endif
+# ifdef COLORS16
+ || D_col16change
+# endif
+ )
+ {
+ struct mchar mc;
+ copy_mline2mchar(&mc, ml, x);
+ SetColor(rend_getfg(&mc), rend_getbg(&mc));
+ }
+#endif
+#ifdef FONT
+ if (D_rend.font != ml->font[x])
+ SetFont(ml->font[x]);
+#ifdef UTF8
+ if (D_encoding == UTF8)
+ D_rend.fontx = ml->fontx[x];
+#endif
+#endif
+}
+
+void
+MakeStatus(msg)
+char *msg;
+{
+ register char *s, *t;
+ register int max;
+
+ if (!display)
+ return;
+
+ if (D_blocked)
+ return;
+ if (!D_tcinited)
+ {
+ debug("tc not inited, just writing msg\n");
+ if (D_processinputdata)
+ return; /* XXX: better */
+ AddStr(msg);
+ AddStr("\r\n");
+ Flush(0);
+ return;
+ }
+ if (!use_hardstatus || !D_HS)
+ {
+ max = D_width;
+ if (D_CLP == 0)
+ max--;
+ }
+ else
+ max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
+ if (D_status)
+ {
+ /* same message? */
+ if (strcmp(msg, D_status_lastmsg) == 0)
+ {
+ debug("same message - increase timeout");
+ if (!D_status_obufpos)
+ SetTimeout(&D_statusev, MsgWait);
+ return;
+ }
+ RemoveStatusMinWait();
+ }
+ for (s = t = msg; *s && t - msg < max; ++s)
+ if (*s == BELL)
+ AddCStr(D_BL);
+ else if ((unsigned char)*s >= ' ' && *s != 0177)
+ *t++ = *s;
+ *t = '\0';
+ if (t == msg)
+ return;
+ 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_len = t - msg;
+ D_status_lastx = D_x;
+ D_status_lasty = D_y;
+ if (!use_hardstatus || D_has_hstatus == HSTATUS_IGNORE || D_has_hstatus == HSTATUS_MESSAGE)
+ {
+ D_status = STATUS_ON_WIN;
+ debug1("using STATLINE %d\n", STATLINE);
+ GotoPos(0, STATLINE);
+ SetRendition(&mchar_so);
+ InsertMode(0);
+ AddStr(msg);
+ if (D_status_len < max)
+ {
+ /* Wayne Davison: add extra space for readability */
+ D_status_len++;
+ SetRendition(&mchar_null);
+ AddChar(' ');
+ if (D_status_len < max)
+ {
+ D_status_len++;
+ AddChar(' ');
+ AddChar('\b');
+ }
+ AddChar('\b');
+ }
+ D_x = -1;
+ }
+ else
+ {
+ D_status = STATUS_ON_HS;
+ ShowHStatus(msg);
+ }
+
+ D_status_obufpos = D_obufp - D_obuf;
+ ASSERT(D_status_obufpos > 0);
+
+ if (D_status == STATUS_ON_WIN)
+ {
+ struct display *olddisplay = display;
+ struct layer *oldflayer = flayer;
+
+ /* this is copied over from RemoveStatus() */
+ D_status = 0;
+ GotoPos(0, STATLINE);
+ RefreshLine(STATLINE, 0, D_status_len - 1, 0);
+ GotoPos(D_status_lastx, D_status_lasty);
+ flayer = D_forecv ? D_forecv->c_layer : 0;
+ if (flayer)
+ LaySetCursor();
+ display = olddisplay;
+ flayer = oldflayer;
+ D_status = STATUS_ON_WIN;
+ }
+}
+
+void
+RemoveStatus()
+{
+ struct display *olddisplay;
+ struct layer *oldflayer;
+ int where;
+
+ if (!display)
+ return;
+ if (!(where = D_status))
+ return;
+
+ debug("RemoveStatus\n");
+ if (D_status_obuffree >= 0)
+ {
+ D_obuflen = D_status_obuflen;
+ D_obuffree = D_status_obuffree;
+ D_status_obuffree = -1;
+ }
+ D_status = 0;
+ D_status_obufpos = 0;
+ D_status_bell = 0;
+ evdeq(&D_statusev);
+ olddisplay = display;
+ oldflayer = flayer;
+ if (where == STATUS_ON_WIN)
+ {
+ if (captionalways || (D_canvas.c_slperp && D_canvas.c_slperp->c_slnext))
+ {
+ GotoPos(0, STATLINE);
+ RefreshLine(STATLINE, 0, D_status_len - 1, 0);
+ GotoPos(D_status_lastx, D_status_lasty);
+ }
+ }
+ else
+ RefreshHStatus();
+ flayer = D_forecv ? D_forecv->c_layer : 0;
+ if (flayer)
+ LaySetCursor();
+ display = olddisplay;
+ flayer = oldflayer;
+}
+
+/* Remove the status but make sure that it is seen for MsgMinWait ms */
+static void
+RemoveStatusMinWait()
+{
+ /* XXX: should flush output first if D_status_obufpos is set */
+ if (!D_status_bell && !D_status_obufpos)
+ {
+ struct timeval now;
+ int ti;
+ gettimeofday(&now, NULL);
+ ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
+ if (ti < MsgMinWait)
+ DisplaySleep1000(MsgMinWait - ti, 0);
+ }
+ RemoveStatus();
+}
+
+#ifdef UTF8
+static int
+strlen_onscreen(unsigned char *c, unsigned char *end)
+{
+ int len = 0;
+ while (*c && (!end || c < end))
+ {
+ int v, dec = 0;
+ do
+ {
+ v = FromUtf8(*c++, &dec);
+ if (v == -2)
+ c--;
+ }
+ while (v < 0 && (!end || c < end));
+ if (!utf8_iscomb(v))
+ {
+ if (utf8_isdouble(v))
+ len++;
+ len++;
+ }
+ }
+
+ return len;
+}
+
+static int
+PrePutWinMsg(s, start, max)
+char *s;
+int start, max;
+{
+ /* Avoid double-encoding problem for a UTF-8 message on a UTF-8 locale.
+ Ideally, this would not be necessary. But fixing it the Right Way will
+ probably take way more time. So this will have to do for now. */
+ if (D_encoding == UTF8)
+ {
+ int chars = strlen_onscreen((unsigned char *)(s + start), (unsigned char *)(s + max));
+ D_encoding = 0;
+ PutWinMsg(s, start, max + ((max - start) - chars)); /* Multibyte count */
+ D_encoding = UTF8;
+ D_x -= (max - chars); /* Yak! But this is necessary to count for
+ the fact that not every byte represents a
+ character. */
+ return start + chars;
+ }
+ else
+ {
+ PutWinMsg(s, start, max);
+ return max;
+ }
+}
+#else
+static int
+PrePutWinMsg(s, start, max)
+char *s;
+int start, max;
+{
+ PutWinMsg(s, start, max);
+ return max;
+}
+#endif
+
+/* refresh the display's hstatus line */
+void
+ShowHStatus(str)
+char *str;
+{
+ int l, ox, oy, max;
+
+ if (D_status == STATUS_ON_WIN && D_has_hstatus == HSTATUS_LASTLINE && STATLINE == D_height-1)
+ return; /* sorry, in use */
+ if (D_blocked)
+ return;
+
+ if (D_HS && D_has_hstatus == HSTATUS_HS)
+ {
+ if (!D_hstatus && (str == 0 || *str == 0))
+ return;
+ debug("ShowHStatus: using HS\n");
+ SetRendition(&mchar_null);
+ InsertMode(0);
+ if (D_hstatus)
+ AddCStr(D_DS);
+ D_hstatus = 0;
+ if (str == 0 || *str == 0)
+ return;
+ AddCStr2(D_TS, 0);
+ max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
+ if ((int)strlen(str) > max)
+ AddStrn(str, max);
+ else
+ AddStr(str);
+ AddCStr(D_FS);
+ D_hstatus = 1;
+ }
+ else if (D_has_hstatus == HSTATUS_LASTLINE)
+ {
+ debug("ShowHStatus: using last line\n");
+ ox = D_x;
+ oy = D_y;
+ str = str ? str : "";
+ l = strlen(str);
+ if (l > D_width)
+ l = D_width;
+ GotoPos(0, D_height - 1);
+ SetRendition(captionalways || D_cvlist == 0 || D_cvlist->c_next ? &mchar_null: &mchar_so);
+ l = PrePutWinMsg(str, 0, l);
+ if (!captionalways && D_cvlist && !D_cvlist->c_next)
+ while (l++ < D_width)
+ PUTCHARLP(' ');
+ if (l < D_width)
+ ClearArea(l, D_height - 1, l, D_width - 1, D_width - 1, D_height - 1, 0, 0);
+ if (ox != -1 && oy != -1)
+ GotoPos(ox, oy);
+ D_hstatus = *str ? 1 : 0;
+ SetRendition(&mchar_null);
+ }
+ else if (D_has_hstatus == HSTATUS_FIRSTLINE)
+ {
+ debug("ShowHStatus: using first line\n");
+ ox = D_x;
+ oy = D_y;
+ str = str ? str : "";
+ l = strlen(str);
+ if (l > D_width)
+ l = D_width;
+ GotoPos(0, 0);
+ SetRendition(captionalways || D_cvlist == 0 || D_cvlist->c_next ? &mchar_null: &mchar_so);
+ l = PrePutWinMsg(str, 0, l);
+ if (!captionalways || (D_cvlist && !D_cvlist->c_next))
+ while (l++ < D_width)
+ PUTCHARLP(' ');
+ if (l < D_width)
+ ClearArea(l, 0, l, D_width - 1, D_width - 1, 0, 0, 0);
+ if (ox != -1 && oy != -1)
+ GotoPos(ox, oy);
+ D_hstatus = *str ? 1 : 0;
+ SetRendition(&mchar_null);
+ }
+ else if (str && *str && D_has_hstatus == HSTATUS_MESSAGE)
+ {
+ debug("ShowHStatus: using message\n");
+ Msg(0, "%s", str);
+ }
+}
+
+
+/*
+ * Refreshes the harstatus of the fore window. Shouldn't be here...
+ */
+void
+RefreshHStatus()
+{
+ char *buf;
+#ifdef UTF8
+ int extrabytes = strlen(hstatusstring) - strlen_onscreen((unsigned char *)hstatusstring, NULL);
+#else
+ int extrabytes = 0;
+#endif
+ evdeq(&D_hstatusev);
+ if (D_status == STATUS_ON_HS)
+ return;
+ buf = MakeWinMsgEv(hstatusstring, D_fore, '%', (D_HS && D_has_hstatus == HSTATUS_HS && D_WS > 0) ? D_WS : D_width - !D_CLP + extrabytes, &D_hstatusev, 0);
+ if (buf && *buf)
+ {
+ ShowHStatus(buf);
+ if (D_has_hstatus != HSTATUS_IGNORE && D_hstatusev.timeout.tv_sec)
+ evenq(&D_hstatusev);
+ }
+ else
+ ShowHStatus((char *)0);
+}
+
+/*********************************************************************/
+/*
+ * Here come the routines that refresh an arbitrary part of the screen.
+ */
+
+void
+RefreshAll(isblank)
+int isblank;
+{
+ struct canvas *cv;
+
+ ASSERT(display);
+ debug("Signalling full refresh!\n");
+ for (cv = D_cvlist; cv; cv = cv->c_next)
+ {
+ CV_CALL(cv, LayRedisplayLine(-1, -1, -1, isblank));
+ display = cv->c_display; /* just in case! */
+ }
+ RefreshArea(0, 0, D_width - 1, D_height - 1, isblank);
+}
+
+void
+RefreshArea(xs, ys, xe, ye, isblank)
+int xs, ys, xe, ye, isblank;
+{
+ int y;
+ ASSERT(display);
+ debug2("Refresh Area: %d,%d", xs, ys);
+ debug3(" - %d,%d (isblank=%d)\n", xe, ye, isblank);
+ if (!isblank && xs == 0 && xe == D_width - 1 && ye == D_height - 1 && (ys == 0 || D_CD))
+ {
+ ClearArea(xs, ys, xs, xe, xe, ye, 0, 0);
+ isblank = 1;
+ }
+ for (y = ys; y <= ye; y++)
+ RefreshLine(y, xs, xe, isblank);
+}
+
+void
+RefreshLine(y, from, to, isblank)
+int y, from, to, isblank;
+{
+ struct viewport *vp, *lvp;
+ struct canvas *cv, *lcv, *cvlist, *cvlnext;
+ struct layer *oldflayer;
+ int xx, yy, l;
+ char *buf;
+ struct win *p;
+
+ ASSERT(display);
+
+ debug2("RefreshLine %d %d", y, from);
+ debug2(" %d %d\n", to, isblank);
+
+ if (D_status == STATUS_ON_WIN && y == STATLINE)
+ {
+ if (to >= D_status_len)
+ D_status_len = to + 1;
+ return; /* can't refresh status */
+ }
+
+ if (isblank == 0 && D_CE && to == D_width - 1 && from < to && D_status != STATUS_ON_HS)
+ {
+ GotoPos(from, y);
+ if (D_UT || D_BE)
+ SetRendition(&mchar_null);
+ AddCStr(D_CE);
+ isblank = 1;
+ }
+
+ if ((y == D_height - 1 && D_has_hstatus == HSTATUS_LASTLINE) || (y == 0 && D_has_hstatus == HSTATUS_FIRSTLINE) )
+ {
+ RefreshHStatus();
+ return;
+ }
+
+ while (from <= to)
+ {
+ lcv = 0;
+ lvp = 0;
+ for (cv = display->d_cvlist; cv; cv = cv->c_next)
+ {
+ if (y == cv->c_ye + 1 && from >= cv->c_xs && from <= cv->c_xe)
+ {
+#ifdef UTF8
+ int extrabytes = strlen(captionstring) - strlen_onscreen((unsigned char *)captionstring, NULL);
+#else
+ int extrabytes = 0;
+#endif
+ p = Layer2Window(cv->c_layer);
+ buf = MakeWinMsgEv(captionstring, p, '%', cv->c_xe - cv->c_xs + (cv->c_xe + 1 < D_width || D_CLP) + extrabytes, &cv->c_captev, 0);
+ if (cv->c_captev.timeout.tv_sec)
+ evenq(&cv->c_captev);
+ xx = to > cv->c_xe ? cv->c_xe : to;
+ l = strlen(buf);
+ GotoPos(from, y);
+ SetRendition(&mchar_so);
+ if (l > xx - cv->c_xs + 1)
+ l = xx - cv->c_xs + 1;
+ l = PrePutWinMsg(buf, from - cv->c_xs, l + extrabytes);
+ from = cv->c_xs + l;
+ for (; from <= xx; from++)
+ PUTCHARLP(' ');
+ break;
+ }
+ if (from == cv->c_xe + 1 && y >= cv->c_ys && y <= cv->c_ye + 1)
+ {
+ GotoPos(from, y);
+ SetRendition(&mchar_so);
+ PUTCHARLP(' ');
+ from++;
+ break;
+ }
+ if (y < cv->c_ys || y > cv->c_ye || to < cv->c_xs || from > cv->c_xe)
+ continue;
+ debug2("- canvas hit: %d %d", cv->c_xs, cv->c_ys);
+ debug2(" %d %d\n", cv->c_xe, cv->c_ye);
+ for (vp = cv->c_vplist; vp; vp = vp->v_next)
+ {
+ debug2(" - vp: %d %d", vp->v_xs, vp->v_ys);
+ debug2(" %d %d\n", vp->v_xe, vp->v_ye);
+ /* find leftmost overlapping vp */
+ if (y >= vp->v_ys && y <= vp->v_ye && from <= vp->v_xe && to >= vp->v_xs && (lvp == 0 || lvp->v_xs > vp->v_xs))
+ {
+ lcv = cv;
+ lvp = vp;
+ }
+ }
+ }
+ if (cv)
+ continue; /* we advanced from */
+ if (lvp == 0)
+ break;
+ if (from < lvp->v_xs)
+ {
+ if (!isblank)
+ DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xs - 1);
+ from = lvp->v_xs;
+ }
+
+ /* call LayRedisplayLine on canvas lcv viewport lvp */
+ yy = y - lvp->v_yoff;
+ xx = to < lvp->v_xe ? to : lvp->v_xe;
+
+ if (lcv->c_layer && lcv->c_xoff + lcv->c_layer->l_width == from)
+ {
+ GotoPos(from, y);
+ SetRendition(&mchar_blank);
+ PUTCHARLP('|');
+ from++;
+ }
+ if (lcv->c_layer && yy == lcv->c_layer->l_height)
+ {
+ GotoPos(from, y);
+ SetRendition(&mchar_blank);
+ while (from <= lvp->v_xe && from - lvp->v_xoff < lcv->c_layer->l_width)
+ {
+ PUTCHARLP('-');
+ from++;
+ }
+ if (from >= lvp->v_xe + 1)
+ continue;
+ }
+ if (lcv->c_layer == 0 || yy >= lcv->c_layer->l_height || from - lvp->v_xoff >= lcv->c_layer->l_width)
+ {
+ if (!isblank)
+ DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xe);
+ from = lvp->v_xe + 1;
+ continue;
+ }
+
+ if (xx - lvp->v_xoff >= lcv->c_layer->l_width)
+ xx = lcv->c_layer->l_width + lvp->v_xoff - 1;
+ oldflayer = flayer;
+ flayer = lcv->c_layer;
+ cvlist = flayer->l_cvlist;
+ cvlnext = lcv->c_lnext;
+ flayer->l_cvlist = lcv;
+ lcv->c_lnext = 0;
+ LayRedisplayLine(yy, from - lvp->v_xoff, xx - lvp->v_xoff, isblank);
+ flayer->l_cvlist = cvlist;
+ lcv->c_lnext = cvlnext;
+ flayer = oldflayer;
+
+ from = xx + 1;
+ }
+ if (!isblank && from <= to)
+ DisplayLine(&mline_null, &mline_blank, y, from, to);
+}
+
+/*********************************************************************/
+
+/* clear lp_missing by writing the char on the screen. The
+ * position must be safe.
+ */
+static void
+WriteLP(x2, y2)
+int x2, y2;
+{
+ struct mchar oldrend;
+
+ ASSERT(display);
+ ASSERT(D_lp_missing);
+ oldrend = D_rend;
+ debug2("WriteLP(%d,%d)\n", x2, y2);
+#ifdef DW_CHARS
+ if (D_lpchar.mbcs)
+ {
+ if (x2 > 0)
+ x2--;
+ else
+ D_lpchar = mchar_blank;
+ }
+#endif
+ /* Can't use PutChar */
+ GotoPos(x2, y2);
+ SetRendition(&D_lpchar);
+ PUTCHAR(D_lpchar.image);
+#ifdef DW_CHARS
+ if (D_lpchar.mbcs)
+ PUTCHAR(D_lpchar.mbcs);
+#endif
+ D_lp_missing = 0;
+ SetRendition(&oldrend);
+}
+
+void
+ClearLine(oml, y, from, to, bce)
+struct mline *oml;
+int from, to, y, bce;
+{
+ int x;
+#ifdef COLOR
+ struct mchar bcechar;
+#endif
+
+ debug3("ClearLine %d,%d-%d\n", y, from, to);
+ if (D_UT) /* Safe to erase ? */
+ SetRendition(&mchar_null);
+#ifdef COLOR
+ if (D_BE)
+ SetBackColor(bce);
+#endif
+ if (from == 0 && D_CB && (to != D_width - 1 || (D_x == to && D_y == y)) && (!bce || D_BE))
+ {
+ GotoPos(to, y);
+ AddCStr(D_CB);
+ return;
+ }
+ if (to == D_width - 1 && D_CE && (!bce || D_BE))
+ {
+ GotoPos(from, y);
+ AddCStr(D_CE);
+ return;
+ }
+ if (oml == 0)
+ oml = &mline_null;
+#ifdef COLOR
+ if (!bce)
+ {
+ DisplayLine(oml, &mline_blank, y, from, to);
+ return;
+ }
+ bcechar = mchar_null;
+ rend_setbg(&bcechar, bce);
+ for (x = from; x <= to; x++)
+ copy_mchar2mline(&bcechar, &mline_old, x);
+ DisplayLine(oml, &mline_old, y, from, to);
+#else
+ DisplayLine(oml, &mline_blank, y, from, to);
+#endif
+}
+
+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))
+ {
+#ifdef DW_CHARS
+ if ((D_IC || D_IM) && from < to && !dw_left(ml, to, D_encoding))
+#else
+ if ((D_IC || D_IM) && from < to)
+#endif
+ {
+ last2flag = 1;
+ D_lp_missing = 0;
+ to--;
+ }
+ else
+ {
+ delete_lp = !cmp_mchar_mline(&mchar_blank, oml, to) && (D_CE || D_DC || D_CDC);
+ D_lp_missing = !cmp_mchar_mline(&mchar_blank, ml, to);
+ copy_mline2mchar(&D_lpchar, ml, to);
+ }
+ }
+ to--;
+ }
+#ifdef DW_CHARS
+ if (D_mbcs)
+ {
+ /* finish dw-char (can happen after a wrap) */
+ debug("DisplayLine finishing kanji\n");
+ SetRenditionMline(ml, from);
+ PUTCHAR(ml->image[from]);
+ from++;
+ }
+#endif
+ for (x = from; x <= to; x++)
+ {
+#if 0 /* no longer needed */
+ if (x || D_x != D_width || D_y != y - 1)
+#endif
+ {
+ if (ml != NULL && (x < to || x != D_width - 1 || ml->image[x + 1]))
+ if (cmp_mline(oml, ml, x))
+ continue;
+ GotoPos(x, y);
+ }
+#ifdef DW_CHARS
+ if (dw_right(ml, x, D_encoding))
+ {
+ x--;
+ debug1("DisplayLine on right side of dw char- x now %d\n", x);
+ GotoPos(x, y);
+ }
+ if (x == to && dw_left(ml, x, D_encoding))
+ break; /* don't start new kanji */
+#endif
+ SetRenditionMline(ml, x);
+ PUTCHAR(ml->image[x]);
+#ifdef DW_CHARS
+ if (dw_left(ml, x, D_encoding))
+ PUTCHAR(ml->image[++x]);
+#endif
+ }
+#if 0 /* not needed any longer */
+ /* compare != 0 because ' ' can happen when clipping occures */
+ if (to == D_width - 1 && y < D_height - 1 && D_x == D_width && ml->image[to + 1])
+ GotoPos(0, y + 1);
+#endif
+ 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)
+ AddCStr(D_DC);
+ else if (D_CDC)
+ AddCStr2(D_CDC, 1);
+ else if (D_CE)
+ AddCStr(D_CE);
+ }
+}
+
+void
+PutChar(c, x, y)
+struct mchar *c;
+int x, y;
+{
+ GotoPos(x, y);
+ SetRendition(c);
+ PUTCHARLP(c->image);
+#ifdef DW_CHARS
+ if (c->mbcs)
+ {
+# ifdef UTF8
+ if (D_encoding == UTF8)
+ D_rend.font = 0;
+# endif
+ PUTCHARLP(c->mbcs);
+ }
+#endif
+}
+
+void
+InsChar(c, x, xe, y, oml)
+struct mchar *c;
+int x, xe, y;
+struct mline *oml;
+{
+ GotoPos(x, y);
+ if (y == D_bot && !D_CLP)
+ {
+ if (x == D_width - 1)
+ {
+ D_lp_missing = 1;
+ D_lpchar = *c;
+ return;
+ }
+ if (xe == D_width - 1)
+ D_lp_missing = 0;
+ }
+ if (x == xe)
+ {
+ SetRendition(c);
+ PUTCHARLP(c->image);
+ return;
+ }
+ if (!(D_IC || D_CIC || D_IM) || xe != D_width - 1)
+ {
+ RefreshLine(y, x, xe, 0);
+ GotoPos(x + 1, y);
+ /* UpdateLine(oml, y, x, xe); */
+ return;
+ }
+ InsertMode(1);
+ if (!D_insert)
+ {
+#ifdef DW_CHARS
+ if (c->mbcs && D_IC)
+ AddCStr(D_IC);
+ if (D_IC)
+ AddCStr(D_IC);
+ else
+ AddCStr2(D_CIC, c->mbcs ? 2 : 1);
+#else
+ if (D_IC)
+ AddCStr(D_IC);
+ else
+ AddCStr2(D_CIC, 1);
+#endif
+ }
+ SetRendition(c);
+ RAW_PUTCHAR(c->image);
+#ifdef DW_CHARS
+ if (c->mbcs)
+ {
+# ifdef UTF8
+ if (D_encoding == UTF8)
+ D_rend.font = 0;
+# endif
+ if (D_x == D_width - 1)
+ PUTCHARLP(c->mbcs);
+ else
+ RAW_PUTCHAR(c->mbcs);
+ }
+#endif
+}
+
+void
+WrapChar(c, x, y, xs, ys, xe, ye, ins)
+struct mchar *c;
+int x, y;
+int xs, ys, xe, ye;
+int ins;
+{
+ int bce;
+
+#ifdef COLOR
+ bce = rend_getbg(c);
+#else
+ bce = 0;
+#endif
+ debug("WrapChar:");
+ debug2(" x %d y %d", x, y);
+ debug2(" Dx %d Dy %d", D_x, D_y);
+ debug2(" xs %d ys %d", xs, ys);
+ debug3(" xe %d ye %d ins %d\n", xe, ye, ins);
+ if (xs != 0 || x != D_width || !D_AM)
+ {
+ if (y == ye)
+ ScrollV(xs, ys, xe, ye, 1, bce);
+ else if (y < D_height - 1)
+ y++;
+ if (ins)
+ InsChar(c, xs, xe, y, 0);
+ else
+ PutChar(c, xs, y);
+ return;
+ }
+ if (y == ye) /* we have to scroll */
+ {
+ debug("- scrolling\n");
+ ChangeScrollRegion(ys, ye);
+ if (D_bot != y || D_x != D_width || (!bce && !D_BE))
+ {
+ debug("- have to call ScrollV\n");
+ ScrollV(xs, ys, xe, ye, 1, bce);
+ y--;
+ }
+ }
+ else if (y == D_bot) /* remove unusable region? */
+ ChangeScrollRegion(0, D_height - 1);
+ if (D_x != D_width || D_y != y)
+ {
+ if (D_CLP && y >= 0) /* don't even try if !LP */
+ RefreshLine(y, D_width - 1, D_width - 1, 0);
+ debug2("- refresh last char -> x,y now %d,%d\n", D_x, D_y);
+ if (D_x != D_width || D_y != y) /* sorry, no bonus */
+ {
+ if (y == ye)
+ ScrollV(xs, ys, xe, ye, 1, bce);
+ GotoPos(xs, y == ye || y == D_height - 1 ? y : y + 1);
+ }
+ }
+ debug("- writeing new char");
+ if (y != ye && y < D_height - 1)
+ y++;
+ if (ins != D_insert)
+ InsertMode(ins);
+ if (ins && !D_insert)
+ {
+ InsChar(c, 0, xe, y, 0);
+ debug2(" -> done with insert (%d,%d)\n", D_x, D_y);
+ return;
+ }
+ D_y = y;
+ D_x = 0;
+ SetRendition(c);
+ RAW_PUTCHAR(c->image);
+#ifdef DW_CHARS
+ if (c->mbcs)
+ {
+# ifdef UTF8
+ if (D_encoding == UTF8)
+ D_rend.font = 0;
+# endif
+ RAW_PUTCHAR(c->mbcs);
+ }
+#endif
+ debug2(" -> done (%d,%d)\n", D_x, D_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_width != wi && (D_height == he || !D_CWS) && D_CZ0 && (wi == Z0width || wi == Z1width))
+ {
+ debug("ResizeDisplay: using Z0/Z1\n");
+ AddCStr(wi == Z0width ? D_CZ0 : D_CZ1);
+ ChangeScreenSize(wi, D_height, 0);
+ return (he == D_height) ? 0 : -1;
+ }
+ if (D_CWS)
+ {
+ debug("ResizeDisplay: using WS\n");
+ AddCStr(tgoto(D_CWS, wi, he));
+ ChangeScreenSize(wi, he, 0);
+ return 0;
+ }
+ return -1;
+}
+
+void
+ChangeScrollRegion(newtop, newbot)
+int newtop, newbot;
+{
+ if (display == 0)
+ return;
+ if (newtop == newbot)
+ return; /* xterm etc can't do it */
+ if (newtop == -1)
+ newtop = 0;
+ if (newbot == -1)
+ newbot = D_height - 1;
+ 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);
+ AddCStr(tgoto(D_CS, newbot, newtop));
+ D_top = newtop;
+ D_bot = newbot;
+ D_y = D_x = -1; /* Just in case... */
+}
+
+#ifdef RXVT_OSC
+#define WT_FLAG "2" /* change to "0" to set both title and icon */
+
+void
+SetXtermOSC(i, s, t)
+int i;
+char *s;
+char *t;
+{
+ static char *oscs[][2] = {
+ { WT_FLAG ";", "screen" }, /* set window title */
+ { "11;", ""}, /* background RGB */
+ { "20;", "" }, /* background */
+ { "39;", "black" }, /* default foreground (black?) */
+ { "49;", "white" } /* default background (white?) */
+ };
+
+ ASSERT(display);
+ if (!D_CXT)
+ return;
+ if (!s)
+ s = "";
+ if (!D_xtermosc[i] && !*s)
+ return;
+ if (i == 0 && !D_xtermosc[0])
+ AddStr("\033[22;" WT_FLAG "t"); /* stack titles (xterm patch #251) */
+ if (!*s)
+ s = oscs[i][1];
+ D_xtermosc[i] = 1;
+ AddStr("\033]");
+ AddStr(oscs[i][0]);
+ AddStr(s);
+ AddStr(t);
+}
+
+void
+ClearAllXtermOSC()
+{
+ int i;
+ for (i = 4; i >= 0; i--)
+ SetXtermOSC(i, 0, "\a");
+ if (D_xtermosc[0])
+ AddStr("\033[23;" WT_FLAG "t"); /* unstack titles (xterm patch #251) */
+}
+#undef WT_FLAG
+#endif
+
+/*
+ * Output buffering routines
+ */
+
+void
+AddStr(str)
+char *str;
+{
+ register char c;
+
+ ASSERT(display);
+
+#ifdef UTF8
+ if (D_encoding == UTF8)
+ {
+ while ((c = *str++))
+ AddUtf8((unsigned char)c);
+ return;
+ }
+#endif
+ while ((c = *str++))
+ AddChar(c);
+}
+
+void
+AddStrn(str, n)
+char *str;
+int n;
+{
+ register char c;
+
+ ASSERT(display);
+#ifdef UTF8
+ if (D_encoding == UTF8)
+ {
+ while ((c = *str++) && n-- > 0)
+ AddUtf8((unsigned char)c);
+ }
+ else
+#endif
+ while ((c = *str++) && n-- > 0)
+ AddChar(c);
+ while (n-- > 0)
+ AddChar(' ');
+}
+
+void
+Flush(progress)
+int progress;
+{
+ register int l;
+ int wr;
+ register char *p;
+
+ ASSERT(display);
+ l = D_obufp - D_obuf;
+ debug1("Flush(): %d\n", l);
+ if (l == 0)
+ return;
+ ASSERT(l + D_obuffree == D_obuflen);
+ if (D_userfd < 0)
+ {
+ D_obuffree += l;
+ D_obufp = D_obuf;
+ return;
+ }
+ p = D_obuf;
+ if (!progress)
+ {
+ if (fcntl(D_userfd, F_SETFL, 0))
+ debug1("Warning: BLOCK fcntl failed: %d\n", errno);
+ }
+ while (l)
+ {
+ if (progress)
+ {
+ fd_set w;
+ FD_ZERO(&w);
+ FD_SET(D_userfd, &w);
+ struct timeval t;
+ t.tv_sec = progress;
+ t.tv_usec = 0;
+ wr = select(FD_SETSIZE, (fd_set *)0, &w, (fd_set *)0, &t);
+ if (wr == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ debug1("Warning: select failed: %d\n", errno);
+ break;
+ }
+ if (wr == 0)
+ {
+ /* no progress after 3 seconds. sorry. */
+ debug1("Warning: no progress after %d seconds\n", progress);
+ break;
+ }
+ }
+ wr = write(D_userfd, p, l);
+ if (wr <= 0)
+ {
+ if (errno == EINTR)
+ continue;
+ debug1("Writing to display: %d\n", errno);
+ break;
+ }
+ D_obuffree += wr;
+ p += wr;
+ l -= wr;
+ }
+ if (l)
+ debug1("Warning: Flush could not write %d bytes\n", l);
+ D_obuffree += l;
+ D_obufp = D_obuf;
+ if (!progress)
+ {
+ if (fcntl(D_userfd, F_SETFL, FNBLOCK))
+ debug1("Warning: NBLOCK fcntl failed: %d\n", errno);
+ }
+ if (D_blocked == 1)
+ D_blocked = 0;
+ D_blocked_fuzz = 0;
+}
+
+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;
+ D_obuflenmax = -D_obufmax;
+ D_blocked = 0;
+ D_blocked_fuzz = 0;
+}
+
+/*
+ * Asynchronous output routines by
+ * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
+ */
+
+void
+Resize_obuf()
+{
+ register int ind;
+
+ ASSERT(display);
+ if (D_status_obuffree >= 0)
+ {
+ ASSERT(D_obuffree == -1);
+ RemoveStatusMinWait();
+ if (--D_obuffree > 0) /* redo AddChar decrement */
+ return;
+ }
+ 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;
+ D_obuflenmax = D_obuflen - D_obufmax;
+ debug1("ResizeObuf: resized to %d\n", D_obuflen);
+}
+
+void
+DisplaySleep1000(n, eat)
+int n;
+int eat;
+{
+ char buf;
+ fd_set r;
+ struct timeval t;
+
+ if (n <= 0)
+ return;
+ if (!display)
+ {
+ debug("DisplaySleep has no display sigh\n");
+ sleep1000(n);
+ return;
+ }
+ t.tv_usec = (n % 1000) * 1000;
+ t.tv_sec = n / 1000;
+ 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");
+ if (eat)
+ read(D_userfd, &buf, 1);
+ }
+ debug2("DisplaySleep(%d) ending, eat was %d\n", n, eat);
+}
+
+#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;
+ int oldmouse = D_mouse;
+ int oldextmouse = D_extmouse;
+
+ 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;
+ AddCStr(D_IS);
+ AddCStr(D_TI);
+ /* Turn off all attributes. (Tim MacKenzie) */
+ if (D_ME)
+ AddCStr(D_ME);
+ else
+ {
+#ifdef COLOR
+ if (D_hascolor)
+ AddStr("\033[m"); /* why is D_ME not set? */
+#endif
+ AddCStr(D_SE);
+ AddCStr(D_UE);
+ }
+ /* Check for toggle */
+ if (D_IM && strcmp(D_IM, D_EI))
+ AddCStr(D_EI);
+ D_insert = 0;
+ /* Check for toggle */
+#ifdef MAPKEYS
+ if (D_KS && strcmp(D_KS, D_KE))
+ AddCStr(D_KS);
+ if (D_CCS && strcmp(D_CCS, D_CCE))
+ AddCStr(D_CCS);
+#else
+ if (D_KS && strcmp(D_KS, D_KE))
+ AddCStr(D_KE);
+ D_keypad = 0;
+ if (D_CCS && strcmp(D_CCS, D_CCE))
+ AddCStr(D_CCE);
+ D_cursorkeys = 0;
+#endif
+ AddCStr(D_CE0);
+ D_rend = mchar_null;
+ D_atyp = 0;
+ AddCStr(D_DS);
+ D_hstatus = 0;
+ AddCStr(D_VE);
+ D_curvis = 0;
+ ChangeScrollRegion(oldtop, oldbot);
+ SetRendition(&oldrend);
+ KeypadMode(oldkeypad);
+ CursorkeysMode(oldcursorkeys);
+ CursorVisibility(oldcurvis);
+ MouseMode(oldmouse);
+ ExtMouseMode(oldextmouse);
+ if (D_CWS)
+ {
+ debug("ResizeDisplay: using WS\n");
+ AddCStr(tgoto(D_CWS, D_width, D_height));
+ }
+ else if (D_CZ0 && (D_width == Z0width || D_width == Z1width))
+ {
+ debug("ResizeDisplay: using Z0/Z1\n");
+ AddCStr(D_width == Z0width ? D_CZ0 : D_CZ1);
+ }
+}
+#endif /* AUTO_NUKE */
+
+#ifdef linux
+/* linux' select can't handle flow control, so wait 100ms if
+ * we get EAGAIN
+ */
+static void
+disp_writeev_eagain(ev, data)
+struct event *ev;
+char *data;
+{
+ display = (struct display *)data;
+ evdeq(&D_writeev);
+ D_writeev.type = EV_WRITE;
+ D_writeev.handler = disp_writeev_fn;
+ evenq(&D_writeev);
+}
+#endif
+
+static void
+disp_writeev_fn(ev, data)
+struct event *ev;
+char *data;
+{
+ int len, size = OUTPUT_BLOCK_SIZE;
+
+ display = (struct display *)data;
+ len = D_obufp - D_obuf;
+ if (len < size)
+ size = len;
+ if (D_status_obufpos && size > D_status_obufpos)
+ size = D_status_obufpos;
+ 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;
+ if (D_status_obufpos)
+ {
+ D_status_obufpos -= size;
+ if (!D_status_obufpos)
+ {
+ debug("finished writing the status message\n");
+ /* we're finished displaying the message! */
+ if (D_status == STATUS_ON_WIN)
+ {
+ /* setup continue trigger */
+ D_status_obuflen = D_obuflen;
+ D_status_obuffree = D_obuffree;
+ /* setting obbuffree to 0 will make AddChar call
+ * ResizeObuf */
+ D_obuffree = D_obuflen = 0;
+ }
+ gettimeofday(&D_status_time, NULL);
+ SetTimeout(&D_statusev, MsgWait);
+ evenq(&D_statusev);
+#ifdef HAVE_BRAILLE
+ RefreshBraille(); /* let user see multiple Msg()s */
+#endif
+ }
+ }
+ if (D_blocked_fuzz)
+ {
+ D_blocked_fuzz -= size;
+ if (D_blocked_fuzz < 0)
+ D_blocked_fuzz = 0;
+ }
+ if (D_blockedev.queued)
+ {
+ if (D_obufp - D_obuf > D_obufmax / 2)
+ {
+ debug2("%s: resetting timeout to %g secs\n", D_usertty, D_nonblock/1000.);
+ SetTimeout(&D_blockedev, D_nonblock);
+ }
+ else
+ {
+ debug1("%s: deleting blocked timeout\n", D_usertty);
+ evdeq(&D_blockedev);
+ }
+ }
+ if (D_blocked == 1 && D_obuf == D_obufp)
+ {
+ /* empty again, restart output */
+ debug1("%s: buffer empty, unblocking\n", D_usertty);
+ D_blocked = 0;
+ Activate(D_fore ? D_fore->w_norefresh : 0);
+ D_blocked_fuzz = D_obufp - D_obuf;
+ }
+ }
+ else
+ {
+#ifdef linux
+ /* linux flow control is badly broken */
+ if (errno == EAGAIN)
+ {
+ evdeq(&D_writeev);
+ D_writeev.type = EV_TIMEOUT;
+ D_writeev.handler = disp_writeev_eagain;
+ SetTimeout(&D_writeev, 100);
+ evenq(&D_writeev);
+ }
+#endif
+ if (errno != EINTR && errno != EAGAIN)
+#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
+ if (errno != EWOULDBLOCK)
+#endif
+ Msg(errno, "Error writing output to display");
+ }
+}
+
+/* maximum mouse sequence length is SGR: ESC [ < b ; x ; y M */
+#define MAX_MOUSE_SEQUENCE (3+10+1+10+1+10+1)
+
+static void
+disp_readev_fn(ev, data)
+struct event *ev;
+char *data;
+{
+ /* We have to intercept mouse sequences in order to translate them
+ * properly, and an incoming sequence could be spread over multiple
+ * I/O reads. When this occurs, we buffer intermediate state in
+ * D_mouse_params, and then use the reservation at the front of
+ * bufspace to prepend the completed and translated mouse sequence.
+ */
+ int size;
+ char bufspace[MAX_MOUSE_SEQUENCE + IOSIZE];
+ unsigned char *buf = (unsigned char*)bufspace + MAX_MOUSE_SEQUENCE;
+
+ struct canvas *cv;
+
+ display = (struct display *)data;
+
+ /* Hmmmm... a bit ugly... */
+ if (D_forecv)
+ for (cv = D_forecv->c_layer->l_cvlist; cv; cv = cv->c_lnext)
+ {
+ display = cv->c_display;
+ if (D_status == STATUS_ON_WIN)
+ RemoveStatus();
+ }
+
+ display = (struct display *)data;
+ if (D_fore == 0)
+ size = IOSIZE;
+ else
+ {
+#ifdef PSEUDOS
+ if (W_UWP(D_fore))
+ size = sizeof(D_fore->w_pwin->p_inbuf) - D_fore->w_pwin->p_inlen;
+ else
+#endif
+ size = sizeof(D_fore->w_inbuf) - D_fore->w_inlen;
+ }
+
+ if (size > IOSIZE)
+ size = IOSIZE;
+ if (size <= 0)
+ size = 1; /* Always allow one char for command keys */
+
+ size = read(D_userfd, buf, size);
+ if (size < 0)
+ {
+ if (errno == EINTR || errno == EAGAIN)
+ return;
+#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
+ if (errno == EWOULDBLOCK)
+ return;
+#endif
+ debug1("Read error: %d - hangup!\n", errno);
+ Hangup();
+ sleep(1);
+ return;
+ }
+ else if (size == 0)
+ {
+ debug("Found EOF - hangup!\n");
+ Hangup();
+ sleep(1);
+ return;
+ }
+ if (D_blocked == 4)
+ {
+ D_blocked = 0;
+#ifdef BLANKER_PRG
+ KillBlanker();
+#endif
+ Activate(D_fore ? D_fore->w_norefresh : 0);
+ ResetIdle();
+ return;
+ }
+#ifdef ZMODEM
+ if (D_blocked > 1) /* 2, 3 */
+ {
+ char *bufp;
+ struct win *p;
+
+ flayer = 0;
+ for (p = windows; p ; p = p->w_next)
+ if (p->w_zdisplay == display)
+ {
+ flayer = &p->w_layer;
+ bufp = (char *)buf;
+ while (size > 0)
+ LayProcess(&bufp, &size);
+ return;
+ }
+ debug("zmodem window gone, deblocking display");
+ zmodem_abort(0, display);
+ }
+#endif
+ if (idletimo > 0)
+ ResetIdle();
+ if (D_fore)
+ D_fore->w_lastdisp = display;
+
+ if (D_mouse && D_forecv)
+ {
+ unsigned char *bp = (unsigned char *)buf;
+ unsigned char *end = bp + size;
+ unsigned char *mark = NULL;
+
+ /* When mouse mode is enabled, buffer up incoming CSI until we
+ * know whether it is a mouse sequence. If not a mouse event,
+ * emit the CSI unchanged; if an invalid mouse event, swallow
+ * it; otherwise, translate the sequence and emit it.
+ *
+ * Supported mouse events take two flavors.
+ *
+ * VT200: CSI M Cb Cx Cy
+ * SGR: CSI < Ps ; Ps ; Ps M|m
+ *
+ * UTF-8 and UXRVT modes are explicitly rejected because they
+ * introduce incompatibilities with other control sequences.
+ *
+ * NOTE: applications wishing to use SGR mode will normally
+ * enable VT200 mode first as a fallback in case the terminal
+ * does not support SGR mode. Thus, we must expect to receive
+ * either mode's sequences when mouse mode is enabled. We will
+ * dutifully translate whatever arrives, without attempting to
+ * convert between modes on behalf of the application.
+ */
+ switch (D_mouse_parse.state)
+ {
+ case CSI_PY:
+ case CSI_PX:
+ case CSI_PB:
+ /* Partial mouse sequence; do not restore suppressed
+ * characters. We will emit a translated version (if valid)
+ * or swallow them (otherwise).
+ */
+ break;
+
+ case CSI_BEGIN:
+ /* Partial CSI; restore suppressed characters in case it
+ * turns out not to be a mouse sequence after all.
+ */
+ *(--buf) = '[';
+ ++size;
+ /* fall through */
+
+ case CSI_ESC_SEEN:
+ /* Escape character; restore it in case this turns out not
+ * to be the start of a mouse sequence after all.
+ */
+ *(--buf) = '\033';
+ ++size;
+ break;
+
+ default:
+ break;
+ };
+
+ while (bp != end)
+ {
+ unsigned char c = *(bp++);
+
+ switch (D_mouse_parse.state)
+ {
+ case CSI_INACTIVE:
+ if (c == '\033')
+ {
+ /* potential escape sequence */
+ mark = bp-1;
+ D_mouse_parse.state = CSI_ESC_SEEN;
+ }
+ break;
+
+ case CSI_ESC_SEEN:
+ if (c == '[')
+ {
+ /* continue buffering an escape sequence */
+ D_mouse_parse.state = CSI_BEGIN;
+ }
+ else
+ D_mouse_parse.state = CSI_INACTIVE;
+ break;
+
+ case CSI_BEGIN:
+ if (c == 'M')
+ {
+ /* VT200 mouse sequence */
+ D_mouse_parse.state = CSI_PB;
+ D_mouse_parse.sgrmode = 0;
+ }
+ else if (c == '<')
+ {
+ /* SGR mouse sequence */
+ D_mouse_parse.state = CSI_PB;
+ D_mouse_parse.params[D_mouse_parse.state] = 0;
+ D_mouse_parse.sgrmode = 1;
+ }
+ else
+ D_mouse_parse.state = CSI_INACTIVE;
+ break;
+
+ case CSI_PB:
+ case CSI_PX:
+ case CSI_PY:
+ if (D_mouse_parse.sgrmode)
+ {
+ /* SGR mode: parse decimal numbers */
+ if ('0' <= c && c <= '9')
+ {
+ D_mouse_parse.params[D_mouse_parse.state] *= 10;
+ D_mouse_parse.params[D_mouse_parse.state] += c - '0';
+ }
+ else if (D_mouse_parse.state == CSI_PY)
+ {
+ if (c == 'M' || c == 'm')
+ D_mouse_parse.state = CSI_DONE;
+ else
+ D_mouse_parse.state = CSI_INVALID;
+ }
+ else if (c == ';')
+ {
+ D_mouse_parse.state++;
+ D_mouse_parse.params[D_mouse_parse.state] = 0;
+ }
+ else
+ D_mouse_parse.state = CSI_INVALID;
+ }
+ else
+ {
+ /* VT200 mode: read raw binary values */
+ D_mouse_parse.params[D_mouse_parse.state++] = c;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (D_mouse_parse.state == CSI_INVALID)
+ {
+ /* swallow invalid sequence, but emit whatever came before */
+ if (buf < mark)
+ disp_processinput(display, buf, mark-buf);
+
+ buf = bp;
+ size = end - bp;
+ D_mouse_parse.state = CSI_INACTIVE;
+ }
+ else if (D_mouse_parse.state == CSI_DONE)
+ {
+ /* emit whatever came before this sequence */
+ if (buf < mark)
+ disp_processinput(display, buf, mark-buf);
+
+ buf = bp;
+ size = end - bp;
+
+ int x = D_mouse_parse.params[CSI_PX];
+ int y = D_mouse_parse.params[CSI_PY];
+ int bias = D_mouse_parse.sgrmode? 1 : 33;
+
+ x -= bias;
+ y -= bias;
+
+ if (x >= D_forecv->c_xs && x <= D_forecv->c_xe && y >= D_forecv->c_ys && y <= D_forecv->c_ye)
+ {
+ if ((D_fore && D_fore->w_mouse) || (D_mousetrack && D_forecv->c_layer->l_mode == 1))
+ {
+ /* Send clicks only if the window is expecting clicks */
+ x -= D_forecv->c_xoff;
+ y -= D_forecv->c_yoff;
+
+ if (x >= 0 && x < D_forecv->c_layer->l_width && y >= 0 && y < D_forecv->c_layer->l_height)
+ {
+ char tmp[MAX_MOUSE_SEQUENCE+1];
+ int n;
+
+ x += bias;
+ y += bias;
+
+ if (D_mouse_parse.sgrmode)
+ {
+ n = snprintf(
+ tmp, MAX_MOUSE_SEQUENCE, "\033[<%d;%d;%d%c",
+ D_mouse_parse.params[CSI_PB], x, y, c);
+ }
+ else
+ {
+ n = snprintf(
+ tmp, MAX_MOUSE_SEQUENCE, "\033[M%c%c%c",
+ D_mouse_parse.params[CSI_PB], x, y);
+ }
+
+ if (n > MAX_MOUSE_SEQUENCE)
+ n = MAX_MOUSE_SEQUENCE;
+
+ /* emit sequence */
+ buf -= n;
+ size += n;
+ memcpy(buf, tmp, n);
+ }
+ }
+ }
+ else if (D_mousetrack)
+ {
+ /* 'focus' to the clicked region, only on mouse up */
+ int focus = 0;
+ if (D_mouse_parse.sgrmode)
+ focus = (c == 'm');
+ else
+ focus = (D_mouse_parse.params[CSI_PB] == '#');
+
+ struct canvas *cv = FindCanvas(x, y);
+ if (focus && cv)
+ {
+ SetForeCanvas(display, cv);
+ /* XXX: Do we want to reset the input buffer? */
+ }
+ }
+
+ D_mouse_parse.state = CSI_INACTIVE;
+ }
+ }
+
+ if (D_mouse_parse.state != CSI_INACTIVE)
+ {
+ /* suppress partial sequence at end */
+ size = mark? mark - buf : 0;
+ }
+ }
+
+ if (size > 0)
+ disp_processinput(display, buf, size);
+}
+
+static void
+disp_processinput(display, buf, size)
+ struct display* display;
+ unsigned char* buf;
+ int size;
+{
+#ifdef ENCODINGS
+ if (D_encoding != (D_forecv ? D_forecv->c_layer->l_encoding : 0))
+ {
+ int i, j, c, enc;
+ char buf2[IOSIZE * 2 + 10];
+ enc = D_forecv ? D_forecv->c_layer->l_encoding : 0;
+ for (i = j = 0; i < size; i++)
+ {
+ c = ((unsigned char *)buf)[i];
+ c = DecodeChar(c, D_encoding, &D_decodestate);
+ if (c == -2)
+ i--; /* try char again */
+ if (c < 0)
+ continue;
+ if (pastefont)
+ {
+ int font = 0;
+ j += EncodeChar(buf2 + j, c, enc, &font);
+ j += EncodeChar(buf2 + j, -1, enc, &font);
+ }
+ else
+ j += EncodeChar(buf2 + j, c, enc, 0);
+ if (j > (int)sizeof(buf2) - 10) /* just in case... */
+ break;
+ }
+ (*D_processinput)(buf2, j);
+ return;
+ }
+#endif
+ (*D_processinput)((char *)buf, size);
+}
+
+static void
+disp_status_fn(ev, data)
+struct event *ev;
+char *data;
+{
+ display = (struct display *)data;
+ debug1("disp_status_fn for display %x\n", (int)display);
+ if (D_status)
+ RemoveStatus();
+}
+
+static void
+disp_hstatus_fn(ev, data)
+struct event *ev;
+char *data;
+{
+ display = (struct display *)data;
+ if (D_status == STATUS_ON_HS)
+ {
+ SetTimeout(ev, 1);
+ evenq(ev);
+ return;
+ }
+ RefreshHStatus();
+}
+
+static void
+disp_blocked_fn(ev, data)
+struct event *ev;
+char *data;
+{
+ struct win *p;
+
+ display = (struct display *)data;
+ debug1("blocked timeout %s\n", D_usertty);
+ if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
+ {
+ debug("stopping output to display\n");
+ D_blocked = 1;
+ /* re-enable all windows */
+ for (p = windows; p; p = p->w_next)
+ if (p->w_readev.condneg == &D_obuflenmax)
+ {
+ debug1("freeing window #%d\n", p->w_number);
+ p->w_readev.condpos = p->w_readev.condneg = 0;
+ }
+ }
+}
+
+#ifdef MAPKEYS
+static void
+disp_map_fn(ev, data)
+struct event *ev;
+char *data;
+{
+ char *p;
+ int l, i;
+ unsigned char *q;
+ display = (struct display *)data;
+ debug("Flushing map sequence\n");
+ if (!(l = D_seql))
+ return;
+ p = (char *)D_seqp - l;
+ D_seqp = D_kmaps + 3;
+ D_seql = 0;
+ if ((q = D_seqh) != 0)
+ {
+ D_seqh = 0;
+ i = q[0] << 8 | q[1];
+ i &= ~KMAP_NOTIMEOUT;
+ debug1("Mapping former hit #%d - ", i);
+ debug2("%d(%s) - ", q[2], q + 3);
+ if (StuffKey(i))
+ ProcessInput2((char *)q + 3, q[2]);
+ if (display == 0)
+ return;
+ l -= q[2];
+ p += q[2];
+ }
+ else
+ D_dontmap = 1;
+ ProcessInput(p, l);
+}
+#endif
+
+static void
+disp_idle_fn(ev, data)
+struct event *ev;
+char *data;
+{
+ struct display *olddisplay;
+ display = (struct display *)data;
+ debug("idle timeout\n");
+ if (idletimo <= 0 || idleaction.nr == RC_ILLEGAL)
+ return;
+ olddisplay = display;
+ flayer = D_forecv->c_layer;
+ fore = D_fore;
+ DoAction(&idleaction, -1);
+ if (idleaction.nr == RC_BLANKER)
+ return;
+ for (display = displays; display; display = display->d_next)
+ if (olddisplay == display)
+ break;
+ if (display)
+ ResetIdle();
+}
+
+void
+ResetIdle()
+{
+ if (idletimo > 0)
+ {
+ SetTimeout(&D_idleev, idletimo);
+ if (!D_idleev.queued)
+ evenq(&D_idleev);
+ }
+ else
+ evdeq(&D_idleev);
+}
+
+
+#ifdef BLANKER_PRG
+
+static void
+disp_blanker_fn(ev, data)
+struct event *ev;
+char *data;
+{
+ char buf[IOSIZE], *b;
+ int size;
+
+ display = (struct display *)data;
+ size = read(D_blankerev.fd, buf, IOSIZE);
+ if (size <= 0)
+ {
+ evdeq(&D_blankerev);
+ close(D_blankerev.fd);
+ D_blankerev.fd = -1;
+ return;
+ }
+ for (b = buf; size; size--)
+ AddChar(*b++);
+}
+
+void
+KillBlanker()
+{
+ int oldtop = D_top, oldbot = D_bot;
+ struct mchar oldrend;
+
+ if (D_blankerev.fd == -1)
+ return;
+ if (D_blocked == 4)
+ D_blocked = 0;
+ evdeq(&D_blankerev);
+ close(D_blankerev.fd);
+ D_blankerev.fd = -1;
+ Kill(D_blankerpid, SIGHUP);
+ D_top = D_bot = -1;
+ oldrend = D_rend;
+ if (D_ME)
+ {
+ AddCStr(D_ME);
+ AddCStr(D_ME);
+ }
+ else
+ {
+#ifdef COLOR
+ if (D_hascolor)
+ AddStr("\033[m\033[m"); /* why is D_ME not set? */
+#endif
+ AddCStr(D_SE);
+ AddCStr(D_UE);
+ }
+ AddCStr(D_VE);
+ AddCStr(D_CE0);
+ D_rend = mchar_null;
+ D_atyp = 0;
+ D_curvis = 0;
+ D_x = D_y = -1;
+ ChangeScrollRegion(oldtop, oldbot);
+ SetRendition(&oldrend);
+ ClearAll();
+}
+
+void
+RunBlanker(cmdv)
+char **cmdv;
+{
+ char *m;
+ int pid;
+ int slave = -1;
+ int ptype = 0;
+ char termname[MAXTERMLEN + 6];
+#ifndef TIOCSWINSZ
+ char libuf[20], cobuf[20];
+#endif
+ char **np;
+
+ strcpy(termname, "TERM=");
+ strncpy(termname + 5, D_termname, MAXTERMLEN - 6);
+ termname[sizeof(termname) - 1] = 0;
+ KillBlanker();
+ D_blankerpid = -1;
+ if ((D_blankerev.fd = OpenDevice(cmdv, 0, &ptype, &m)) == -1)
+ {
+ Msg(0, "OpenDevice failed");
+ return;
+ }
+#ifdef O_NOCTTY
+ if (pty_preopen)
+ {
+ if ((slave = open(m, O_RDWR|O_NOCTTY)) == -1)
+ {
+ Msg(errno, "%s", m);
+ close(D_blankerev.fd);
+ D_blankerev.fd = -1;
+ return;
+ }
+ }
+#endif
+ switch (pid = (int)fork())
+ {
+ case -1:
+ Msg(errno, "fork");
+ close(D_blankerev.fd);
+ D_blankerev.fd = -1;
+ close(slave);
+ return;
+ case 0:
+ displays = 0;
+ ServerSocket = -1;
+#ifdef SIGPIPE
+ signal(SIGPIPE, SIG_DFL);
+#endif
+ if (setgid(real_gid) || setuid(real_uid))
+ Panic(errno, "setuid/setgid");
+ eff_uid = real_uid;
+ eff_gid = real_gid;
+ brktty(D_userfd);
+ freetty();
+#ifdef DEBUG
+ if (dfp && dfp != stderr)
+ fclose(dfp);
+#endif
+ if (slave != -1)
+ {
+ close(0);
+ dup(slave);
+ close(slave);
+ closeallfiles(D_blankerev.fd);
+ slave = dup(0);
+ }
+ else
+ closeallfiles(D_blankerev.fd);
+#ifdef DEBUG
+ if (dfp)
+ {
+ char buf[256];
+
+ sprintf(buf, "%s/screen.blanker", DEBUGDIR);
+ if ((dfp = fopen(buf, "a")) == 0)
+ dfp = stderr;
+ else
+ (void) chmod(buf, 0666);
+ }
+ debug1("=== RunBlanker: pid %d\n", (int)getpid());
+#endif
+ close(0);
+ close(1);
+ close(2);
+ if (open(m, O_RDWR))
+ Panic(errno, "Cannot open %s", m);
+ dup(0);
+ dup(0);
+ close(D_blankerev.fd);
+ if (slave != -1)
+ close(slave);
+ InitPTY(0);
+ fgtty(0);
+ SetTTY(0, &D_OldMode);
+ np = NewEnv + 3;
+ *np++ = NewEnv[0];
+ *np++ = termname;
+#ifdef TIOCSWINSZ
+ glwz.ws_col = D_width;
+ glwz.ws_row = D_height;
+ (void)ioctl(0, TIOCSWINSZ, (char *)&glwz);
+#else
+ /* Always turn off nonblocking mode */
+ (void)fcntl(0, F_SETFL, 0);
+ sprintf(libuf, "LINES=%d", D_height);
+ sprintf(cobuf, "COLUMNS=%d", D_width);
+ *np++ = libuf;
+ *np++ = cobuf;
+#endif
+ debug1("calling execvpe %s\n", *cmdv);
+ execvpe(*cmdv, cmdv, NewEnv + 3);
+ debug1("exec error: %d\n", errno);
+ Panic(errno, "Cannot exec '%s'", *cmdv);
+ default:
+ break;
+ }
+ D_blankerpid = pid;
+ evenq(&D_blankerev);
+ D_blocked = 4;
+ ClearAll();
+ close(slave);
+}
+
+#endif /* BLANKER_PRG */
+
+
diff --git a/display.h b/display.h
new file mode 100644
index 0000000..b094619
--- /dev/null
+++ b/display.h
@@ -0,0 +1,338 @@
+/* Copyright (c) 2008, 2009
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Micah Cowan (micah@cowan.name)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
+ * 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 3, 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, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ * $Id$ GNU
+ */
+
+#ifndef SCREEN_DISPLAY_H
+#define SCREEN_DISPLAY_H
+
+#include "layout.h"
+#include "canvas.h"
+#include "viewport.h"
+
+#ifdef MAPKEYS
+
+#define KMAP_KEYS (T_OCAPS-T_CAPS)
+#define KMAP_AKEYS (T_OCAPS-T_CURSOR)
+
+#define KMAP_NOTIMEOUT 0x4000
+
+struct kmap_ext
+{
+ char *str;
+ int fl;
+ struct action um;
+ struct action dm;
+ struct action mm;
+};
+
+#else
+
+#define KMAP_KEYS 0
+
+#endif
+
+struct win; /* forward declaration */
+
+struct mouse_parse
+{
+ char sgrmode; /* non-zero if parsing an SGR sequence */
+ int state; /* current state of parsing */
+ int params[3]; /* parsed params: button, x, y */
+};
+
+struct display
+{
+ struct display *d_next; /* linked list */
+ struct acluser *d_user; /* user who owns that display */
+ struct canvas d_canvas; /* our canvas slice */
+ struct canvas *d_cvlist; /* the canvases of this display */
+ struct canvas *d_forecv; /* current input focus */
+ struct layout *d_layout; /* layout we're using */
+ void (*d_processinput) __P((char *, int));
+ char *d_processinputdata; /* data for processinput */
+ int d_vpxmin, d_vpxmax; /* min/max used position on display */
+ struct win *d_fore; /* pointer to fore window */
+ struct win *d_other; /* pointer to other window */
+ int d_nonblock; /* -1 don't block if obufmax reached */
+ /* >0: block after nonblock secs */
+ char d_termname[MAXTERMLEN + 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 */
+ int d_col16change; /* the 16col bits changed in attr */
+ char d_atyp; /* current attribute types */
+#ifdef DW_CHARS
+ int d_mbcs; /* saved char for multibytes charset */
+#endif
+#ifdef ENCODINGS
+ int d_encoding; /* what encoding type the display is */
+ int d_decodestate; /* state of our decoder */
+ int d_realfont; /* real font of terminal */
+#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_has_hstatus; /* display has hardstatus line */
+ int d_hstatus; /* hardstatus used */
+ int d_lp_missing; /* last character on bot line missing */
+ int d_mouse; /* mouse mode */
+ int d_extmouse; /* extended mouse mode */
+ struct mouse_parse d_mouse_parse; /* state of mouse code parsing */
+ int d_mousetrack; /* set when user wants to use mouse even when the window
+ does not */
+#ifdef RXVT_OSC
+ int d_xtermosc[5]; /* osc used */
+#endif
+ struct mchar d_lpchar; /* missing char */
+ struct timeval d_status_time; /* time of status display */
+ int 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_status_obuflen; /* saved obuflen */
+ int d_status_obuffree; /* saved obuffree */
+ int d_status_obufpos; /* end of status position in obuf */
+ struct event d_statusev; /* timeout event */
+ struct event d_hstatusev; /* hstatus changed event */
+ int d_kaablamm; /* display kaablamm msg */
+ struct action *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 event d_readev; /* userfd read event */
+ struct event d_writeev; /* userfd write event */
+ struct event d_blockedev; /* blocked timeout */
+ 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*/
+ int d_intrc; /* current intr when flow is on */
+ char *d_obuf; /* output buffer */
+ int d_obuflen; /* len of buffer */
+ int d_obufmax; /* len where we are blocking the pty */
+ int d_obuflenmax; /* len - max */
+ 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 */
+ int d_aseqs; /* number of allocated mappings */
+ unsigned char *d_kmaps; /* keymaps */
+ unsigned char *d_seqp; /* pointer into keymap array */
+ int d_seql; /* number of parsed chars */
+ unsigned char *d_seqh; /* last hit */
+ struct event d_mapev; /* timeout event */
+ int d_dontmap; /* do not map next */
+ int d_mapdefault; /* do map next to default */
+#endif
+ union tcu d_tcs[T_N]; /* terminal capabilities */
+ char *d_attrtab[NATTR]; /* attrib emulation table */
+ char d_attrtyp[NATTR]; /* attrib group table */
+ int d_hascolor; /* do we support color */
+ short d_dospeed; /* baudrate of tty */
+#ifdef FONT
+ char d_c0_tab[256]; /* conversion for C0 */
+ char ***d_xtable; /* char translation table */
+#endif
+ 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 */
+ int d_loginttymode;
+# ifdef _SEQUENT_
+ char d_loginhost[100+1];
+# endif /* _SEQUENT_ */
+#endif
+ int d_blocked;
+ int d_blocked_fuzz;
+ struct event d_idleev; /* screen blanker */
+#ifdef BLANKER_PRG
+ int d_blankerpid;
+ struct event d_blankerev;
+#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_canvas DISPLAY(d_canvas)
+#define D_cvlist DISPLAY(d_cvlist)
+#define D_layout DISPLAY(d_layout)
+#define D_forecv DISPLAY(d_forecv)
+#define D_processinput DISPLAY(d_processinput)
+#define D_processinputdata DISPLAY(d_processinputdata)
+#define D_vpxmin DISPLAY(d_vpxmin)
+#define D_vpxmax DISPLAY(d_vpxmax)
+#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_col16change DISPLAY(d_col16change)
+#define D_atyp DISPLAY(d_atyp)
+#define D_mbcs DISPLAY(d_mbcs)
+#define D_encoding DISPLAY(d_encoding)
+#define D_decodestate DISPLAY(d_decodestate)
+#define D_realfont DISPLAY(d_realfont)
+#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_has_hstatus DISPLAY(d_has_hstatus)
+#define D_hstatus DISPLAY(d_hstatus)
+#define D_lp_missing DISPLAY(d_lp_missing)
+#define D_mouse DISPLAY(d_mouse)
+#define D_mouse_parse DISPLAY(d_mouse_parse)
+#define D_extmouse DISPLAY(d_extmouse)
+#define D_mousetrack DISPLAY(d_mousetrack)
+#define D_xtermosc DISPLAY(d_xtermosc)
+#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_status_obuflen DISPLAY(d_status_obuflen)
+#define D_status_obuffree DISPLAY(d_status_obuffree)
+#define D_status_obufpos DISPLAY(d_status_obufpos)
+#define D_statusev DISPLAY(d_statusev)
+#define D_hstatusev DISPLAY(d_hstatusev)
+#define D_kaablamm DISPLAY(d_kaablamm)
+#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_intr DISPLAY(d_intr)
+#define D_obuf DISPLAY(d_obuf)
+#define D_obuflen DISPLAY(d_obuflen)
+#define D_obufmax DISPLAY(d_obufmax)
+#define D_obuflenmax DISPLAY(d_obuflenmax)
+#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_aseqs DISPLAY(d_aseqs)
+#define D_seqp DISPLAY(d_seqp)
+#define D_seql DISPLAY(d_seql)
+#define D_seqh DISPLAY(d_seqh)
+#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_hascolor DISPLAY(d_hascolor)
+#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_loginttymode DISPLAY(d_loginttymode)
+#define D_loginhost DISPLAY(d_loginhost)
+#define D_readev DISPLAY(d_readev)
+#define D_writeev DISPLAY(d_writeev)
+#define D_blockedev DISPLAY(d_blockedev)
+#define D_mapev DISPLAY(d_mapev)
+#define D_blocked DISPLAY(d_blocked)
+#define D_blocked_fuzz DISPLAY(d_blocked_fuzz)
+#define D_idleev DISPLAY(d_idleev)
+#define D_blankerev DISPLAY(d_blankerev)
+#define D_blankerpid DISPLAY(d_blankerpid)
+
+
+#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)
+
+#define STATUS_OFF 0
+#define STATUS_ON_WIN 1
+#define STATUS_ON_HS 2
+
+#define HSTATUS_IGNORE 0
+#define HSTATUS_LASTLINE 1
+#define HSTATUS_MESSAGE 2
+#define HSTATUS_HS 3
+#define HSTATUS_FIRSTLINE 4
+#define HSTATUS_ALWAYS (1<<3)
+
+#endif /* SCREEN_DISPLAY_H */
+
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 0000000..2681820
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1,2 @@
+Makefile
+screen.info*
diff --git a/doc/FAQ b/doc/FAQ
new file mode 100644
index 0000000..6c9c8af
--- /dev/null
+++ b/doc/FAQ
@@ -0,0 +1,253 @@
+ jw 21.10.93
+ 05.05.94
+
+ screen: frequently asked questions -- known problems -- unimplemented bugs
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+
+Q: Why is it impossible to download a file with Kermit/sz/rz when
+ screen is running? Do I need to set some special variables?
+
+A: Screen always interprets control-sequences sent by the
+ applications and translates/optimizes them for the current
+ terminal type. Screen always parses the user input for its
+ escape character (CTRL-A). Both are basic screen features and
+ cannot be switched off. Even if it were possible to switch
+ screen into a completely transparent mode, you could never switch
+ between windows, while kermit/sz/rz is downloading a file. You
+ must wait til the end as kermit/sz/rz will not transmit your
+ input during a file transfer and as kermit/sz/rz would be very
+ confused if screen switched away the window containing the
+ other kermit/sz/rz. Simply detach your screen session for each
+ file transfer and start the transfer program only from the shell
+ where you started screen.
+
+Q: I am using screen with a YYY terminal, which supports the XXX
+ graphic language. I am very happy with it, except one thing: I
+ cannot render graphics into screen windows.
+
+A: You are out of luck there. Screen provides a fixed set of escape
+ sequences in order to make it possible to switch terminal types.
+ Screen has to know exactly what the escape sequences do to the
+ terminal because it must hold an image in memory. Otherwise
+ screen could not restore the image if you switch to another
+ window. Because of this you have to change screens escape
+ sequence parser (ansi.c) to pass the XXX graphics sequences to
+ the terminal. Of course the graphics will be lost if you switch
+ to another window. Screen will only honour graphics sequences
+ that are demanded by an overwhelming majority.
+
+Q: For some unknown reason, the fifo in /tmp/screens/S-myname is
+ gone, and i can't resume my screen session. Is there a way to
+ recreate the fifo?
+
+A: Screen checks the fifo/socket whenever it receives a SIGCHLD
+ signal. If missing, the fifo/socket is recreated then. If screen
+ is running non set-uid the user can issue a 'kill -CHLD
+ screenpid' directly (it is -CHILD on some systems). Screenpid is
+ the process-id of the screen process found in a 'ps -x' listing.
+ But usually this won't work, as screen should be installed set-
+ uid root. In this case you will not be able to send it a signal,
+ but the kernel will. It does so, whenever a child of screen
+ changes its state. Find the process-id (shellpid below) of the
+ "least important" shell running inside screen. The try 'kill
+ -STOP shellpid'. If the fifo/socket does not reappear, destroy
+ the shell process. You sacrify one shell to save the rest. If
+ nothing works, please do not forget to remove all processes
+ running in the lost screen session.
+
+Q: When you start "screen" a page of text comes up to start you
+ off. Is there a way to get rid of this text as a command line
+ argument or by using a switch of some sort.
+
+A: Just put the following line in your ~/.screenrc:
+ startup_message off
+ Many peole ask this, although it is in the man page, too :-)
+
+Q: Start "screen emacs" and run emacs function suspend-emacs
+ (ctrl-z). The window containing emacs vanishes.
+
+A: This is a known bug. Unfortunatly there is no easy fix
+ because this is specified in the POSIX standard. When a new
+ window is created Screen opens up a new session because the
+ window has to get the pty as a controlling terminal (a
+ session can only have one controlling terminal). With the
+ setsid() call the process also creates a new process
+ group. This process group is orphaned, because there is no
+ process in the session which is not in the process
+ group. Now if the process group leader (i.e. your program)
+ gets a TTIN/TTOU/TSTP, POSIX states that the kernel must
+ send a KILL signal to the process group because there is no
+ one left to continue the process. Even if screen would
+ try to restart the program, that would be after it received the
+ KILL signal which cannot be caught or ignored.
+
+ tromey@klab.caltech.edu (Tom Tromey): I've noticed this exact
+ same problem. I put this in my .emacs file. It seems to work:
+
+ ;; If running under screen, disable C-z.
+ (if (and (getenv "STY") (not window-system))
+ (global-unset-key "\C-z"))
+
+Q: Screen gets the terminal size wrong and messes up.
+
+A: Before you start screen: Check with 'stty -a' what the terminal
+ driver thinks about rows and columns. Check the environment
+ variables LINES and COLUMNS. Then from within screen check with
+ the info command (CTRL-A i) what size screen thinks your terminal
+ is. If correcting tty driver setting and environment variables
+ does not help, look up the terminal capability definition. First
+ the TERMCAP environment variable. If this is not set, look up the
+ terminals name as defined in the environment variable TERM in
+ /etc/termcap or in the terminfo database with untic or infocmp.
+ There may be :li=...: and :co=...: or even :ll=...: entries
+ (cols#... and lines#... when it's terminfo) defined incorrectly.
+ Either construct your own TERMCAP environment variables with
+ correct settings, use screens terminfo/termcap command in your
+ .screenrc file or have the database corrected by the system
+ administrator.
+
+Q: Screen messes up the terminal output when I use my favourite ap-
+ plication. Setting the terminal size does not help.
+
+A: Probably you got the termcap/terminfo entries wrong. Fixing this
+ is a three stage procedure. First, find out if terminfo or
+ termcap is used. If your system only has /etc/termcap,
+ but not /usr/lib/terminfo/... then you are using termcap.
+ Easy. But if your system has both, then it depends how the appli-
+ cation and how screen were linked. Beware, if your applica-
+ tion runs on another host via rlogin, telnet or the like, you
+ should check the terminfo/termcap databases there. If you cannot
+ tell if terminfo or termcap is used (or you just want to be
+ save), the do all steps in stage 3 in parallel for both
+ systems (on all envolved hosts). Second: Understand the basic
+ rules how screen does its terminal emulation. When screen is
+ started or reattached, it relies on the TERM environment variable
+ to correctly reflect the terminal type you have physically
+ in front of you. And the entry should either exist in the system
+ terminfo/termcap database or be specified via the TERMCAP en-
+ vironment variable (if screen is using the termcap system). On
+ the other end, screen understands one set of control codes. It
+ relies on the application using these codes. This means applica-
+ tions that run under screen must be able to adapt their con-
+ trol codes to screen. The application should use the TERM vari-
+ able and termcap or terminfo library to find out how to drive
+ its terminal. When running under screen, the terminal is virtual
+ and is only defined by the set of control codes that screen
+ understands. The TERM variable is automatically set to
+ "screen" and the "screen"-entries should exist in the data-
+ bases. If your application uses hardcoded control codes rather
+ than a database, you are on your own. Hint: The codes under-
+ stood by screen are a superset of the very common definition
+ named "vt100". Look at the documentation of screen. The
+ codes are listed there. Third: Have the entry "screen" in-
+ stalled on all hosts or make sure you can live with "vt100".
+ Check the codes sent by your application, when the TERM variable
+ is set to "screen". Do not try to set the TERM variable inside
+ screen to anything other than "screen" or "vt100" or compati-
+ ble. Thus your application can drive screen correctly. Also take
+ care that a good entry is installed for your physical terminal
+ that screen has to drive. Even if the entry was good enough
+ for your application to drive the terminal directly, screen may
+ find flaws, as it tries to use other capabilities while op-
+ timizing the screen output. The screenrc commands
+ "termcap" and/or "terminfo" may help to fine-tune capabilities
+ without calling the supervisor to change the database.
+
+Q: I cannot configure screen. Sed does not work.
+
+A: The regular expressions used in our configure scrip are too
+ complicated for GNU sed version 2.03. In this regard it is bug
+ compatible with Ultrix 3.1 "sed": GNU sed version 2.03 dumps
+ core with our configure script. Try an older release. E.g. from
+ ftp.uni-erlangen.de:/pub/utilities/screen/sed-2.02b.tar.gz
+
+Q: When reattaching a session from a different Workstation, the
+ DISPLAY environment variable should be updated. Even ``CTLR-A
+ : setenv DISPLAY newhost:0'' does not work as expected.
+
+A: Under unix every process has its own environment. The environ-
+ ment of the SCREEN process can be changed with the `setenv' com-
+ mand. This however cannot affect the environment of the
+ shells or applications already running under screen. Subsequently
+ spawned processes will reflect the changes. One should be aware
+ of this problem when running applications from very old shells.
+ Screen is a means for keeping processes alive.
+
+Q: About once every 5 times I ran the program, rather than getting
+ a "screen," I got someone elses IRC output/input.
+
+A: What probably happened is that an IRC process was left running on
+ a pseudo tty in such a way that the kernel thought the tty was
+ available for reallocation. You can fix this behaviour by
+ applying the SunOS 4.1.x tty jumbo patch (100513-04).
+
+Q: Screen compiled on SunOS 5.3 cannot reattach a detached session.
+
+A: You are using /usr/ucb/cc, this compiler is wrong. Actually it
+ links with a C-library that mis-interprets dirent. Try again
+ with /opt/SUNWspro/bin/cc!
+
+Q: The "talk" command does not work when Screen is active.
+
+A: Talk and several other programs rely on entries in the Utmp-
+ Database (/etc/utmp). On some systems this Database is world
+ writable, on others it is not. If it is not, screen must be
+ installed with the appropriate permissions (user or group s-bit)
+ just like any program that uses PTYs (rlogin, xterm, ...). When
+ screen cannot write to utmp, you will see messages on you display
+ which do not belong to any screen window.
+ When screen can update utmp, it is not guaranteed that it does as
+ you expect. First this depends on the config.h file defining
+ UTMPOK, LOGINDEFAULT, and perhaps CAREFULUTMP. Second it depends
+ on the screenrc files (system wide and per user), if utmp entries
+ are done. Third, you can control whether windows are logged in
+ with screens ``login'' command.
+
+Q: Seteuid() does not work as expected in AIX. Attempting a multi-
+ user-attach results in a screen-panic: "seteuid: not owner".
+
+A: This is not a screen problem. According to Kay Nettle
+ (pkn@cs.utexas.edu) you need the AIX patch PTF 423674.
+
+Q: When I type cd directory (any directory or just blank) from
+ within one of the windows in screen, the whole thing just freezes
+ up.
+
+A: You display the current working directory in xterm's title bar,
+ This may be caused by hardcoded ESC-sequences in the shell prompt
+ or in an cd alias. In Xterm the coding is
+ ESC ] n ; string_to_display ^G
+ where n = 1, 2, 3 selects the location of the displayed string.
+ Screen misinterprets this as the ansi operating system comment
+ sequence:
+ ESC ] osc_string
+ and waits (according to ansi) for the string terminator
+ ESC \
+ Screen versions after 3.5.12 may provide a workaround.
+
+Q: Mesg or biff cannot be turned on or off while running screen.
+
+A: Screen failed to change the owner of the pty it uses. You need to
+ install screen setuid-root. See the file INSTALL for details.
+
+Q: The cursor left key deletes the characters instead of just moving the
+ cursor. A redisplay (^Al) brings everything back.
+
+A: Your terminal emulator treats the backspace as "destructive". You
+ can probably change this somewhere in the setup. We can't think
+ of a reason why anybody would want a destructive backspace, but
+ if you really must have it, add the lines
+ termcap <TERM> 'bc@:bs@'
+ terminfo <TERM> 'bc@:bs@'
+ to your ~/.screenrc (replace <TERM> with the terminal type your
+ emulator uses).
+
+Q: I have an old SysV OS (like Motorola SysV68) and sometimes screen
+ doesn't reset the attributes correctly. A redisplay (^Al) doesn't
+ make things better.
+
+A: The libcurses library has a bug if attributes are cleared with
+ the special ue/se capabilities. As a workaround (other than upgrading
+ your system) modify 'rmul' (and 'rmso'?) in screen's terminfo entry:
+ rmul=\E[m, rmso=\E[m
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644
index 0000000..f7c7db7
--- /dev/null
+++ b/doc/Makefile.in
@@ -0,0 +1,62 @@
+# Makefile for Screen documentation
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+DESTDIR =
+
+prefix = @prefix@
+datarootdir = @datarootdir@
+mandir = @mandir@
+infodir = @infodir@
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+MAKEINFO = makeinfo
+TEXI2DVI = texi2dvi
+TEXI2PDF = texi2pdf
+
+SHELL = /bin/sh
+
+all: screen.info
+
+dvi screen.dvi: screen.texinfo mostlyclean
+ $(TEXI2DVI) $(srcdir)/screen.texinfo
+
+pdf screen.pdf: screen.texinfo mostlyclean
+ $(TEXI2PDF) $(srcdir)/screen.texinfo
+
+info screen.info: screen.texinfo
+ @rm -f screen.info*
+ $(MAKEINFO) $(srcdir)/screen.texinfo -o screen.info
+
+install: installdirs
+ $(INSTALL_DATA) $(srcdir)/screen.1 $(DESTDIR)$(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 $(DESTDIR)$(infodir);done; \
+ if $(SHELL) -c 'install-info --version' >/dev/null 2>&1; then \
+ install-info --info-dir=$(DESTDIR)$(infodir) $$d/screen.info; \
+ else true; fi; \
+ fi
+
+uninstall:
+ rm -f $(DESTDIR)$(mandir)/man1/screen.1
+ rm -f $(DESTDIR)$(infodir)/screen.info*
+
+installdirs:
+ $(srcdir)/../etc/mkinstalldirs $(DESTDIR)$(mandir)/man1 $(DESTDIR)$(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/README.DOTSCREEN b/doc/README.DOTSCREEN
new file mode 100644
index 0000000..f17fa37
--- /dev/null
+++ b/doc/README.DOTSCREEN
@@ -0,0 +1,151 @@
+From bargi@dots.physics.orst.edu Thu Aug 31 23:42 MET 1995
+Received: from faui45.informatik.uni-erlangen.de (root@faui45.informatik.uni-erlangen.de [131.188.34.45]) by immd4.informatik.uni-erlangen.de with ESMTP
+ id XAA14775 (8.6.12/7.4f-FAU);; Thu, 31 Aug 1995 23:42:15 +0200
+Received: from dots.physics.orst.edu (bargi@dots.PHYSICS.ORST.EDU [128.193.96.106]) by uni-erlangen.de with ESMTP
+ id XAA03048 (8.6.12/7.4f-FAU); for <screen@uni-erlangen.de>; Thu, 31 Aug 1995 23:42:03 +0200
+Received: (from bargi@localhost) by dots.physics.orst.edu (8.6.11/8.6.9) id OAA15627; Thu, 31 Aug 1995 14:41:47 -0700
+From: Hadi Bargi Rangin <bargi@dots.physics.orst.edu>
+Message-Id: <199508312141.OAA15627@dots.physics.orst.edu>
+Subject: README.DOTSCREEN
+To: screen@uni-erlangen.de
+Date: Thu, 31 Aug 1995 14:41:47 -0700 (PDT)
+Cc: bargi@dots.physics.orst.edu (Hadi Bargi Rangin)
+X-Mailer: ELM [version 2.4 PL24]
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Content-Type: text/plain; charset=US-ASCII
+Content-Length: 5423
+Status: RO
+
+Hallo,
+
+ leider war readme file fuer dotscreen nicht in unserem dotscreen-Packet,
+deshalb schicke ich es Euch nachtraeglich. Nachdem Ihr unseren packet
+getestet habt, koennen wir Euch anrufen und vielleicht mehr ueber die
+Einzelnheiten sprechen, ob wir unsere Weiterentwicklung koordinieren
+wollen.
+
+Danke,
+
+Gruss,
+Hadi
+
+===============================================================================
+Quick introduction to dotscreen
+-------------------------------
+
+1. Introduction
+2. Is dotscreen different as screen?
+3. Installation instructions
+4. Functions description
+5. Further development
+
+
+1. Introduction
+===============
+
+Dotscreen, is a system which allow a person direct access to unix via
+a braille display. The emphasis is on direct, because the braille
+display is connected directly to the serial port on the unix
+machine. You no longer must use a dos machine running a terminal
+emulation logged into a unix machine. Dotscreen is built on top of
+screen, a powerful full-screen window manager for unix tty terminals.
+Screen keeps track of what is being displayed in each window that it
+is managing so that it can easily switch back and forth between these
+windows. Dotscreen makes this stored window information available via
+a braille display. Dotscreen only allows access to tty terminal
+sessions, it does not allow access to X-Windows, however, it will run
+in an xterm window. Currently, it works with the TSI Navigator 40 and
+the TSI PowerBraille 40 braille displays. We plan to support other
+displays as demand and information about other displays is made
+available to us
+
+2. Is dotscreen different than screen?
+======================================
+
+All of screens functions still work in dotscreen. A few of the
+functions are not accessible via braille, but we expect to remedy that
+in future releases.
+
+3. Installation instructions
+============================
+
+Please read the INSTALL file for full installation instructions.
+In addition to those instructions, note that you must create
+a .screenrc file and that file must contain the type of braille
+display that you are using and the serial device that the display
+is connected to. A minimal .screenrc file should contain something
+like the following four lines, (these are only examples, please
+customize them for your configuration)
+
+
+# example of .screenrc when using braille display
+bd_start_braille on
+bd_type powerbraille_40
+bd_port /dev/ttyS0
+bd_braille_table /home/gardner/us-braille.tbl
+# end of example
+
+
+4. Functions description
+========================
+
+The basic operation of screen is described in README. The braille
+navigation commands are similar to commands usually found on dos
+braille screenreaders. Also, because dotscreen is built on top of
+screen, the user can switch back and forth easily between many running
+applications. The braille commands can be changed any time after
+starting screen using the internal screen "C-a :" command line. All
+braille commands begin with "bd_"; following is the list of braille
+commands:
+
+bd_start_braille on/off # Starts/stops using braille features on screen
+bd_link on/off # links/unlinks braille cursor to/from screen cursor
+bd_bell on/off # turn on/off sending bell-signal to terminal
+bd_scroll on/off # enables/disables scrolling
+bd_skip on/off # skip/don't skip balnk lines
+bd_width <integer-value> # number of braille cells that user want to use,
+ # this value is always <= total number of cells
+bd_ncrc <interger-value> # number of cells displayed on the right side
+ # of physical cursor (default = 1)
+bd_info <integer-value> # displays braille/screen cursor position
+ # depending on its value, (no info: 0, only
+ # bc-info: 1, only sc-info: 2, bc- and sc-info: 3
+bd_port <serial-device> # serial port which braille display is connected to
+bd_braille_table <bl-table> # braille table to be used. German, US and GS
+ # braille tables are provided
+bd_type <braille-display-type>
+ # braille display type being used
+
+Note: currently valid value for some parameters:
+bd_type:
+ 1. navigator_40
+ 2. powerbraille_40.
+
+bd_braille_table:
+ 1. gr-braille.tbl German braille code
+ 2. us-braille.tbl US computer braille code
+ 3. gs-braille.tbl GS braille code
+
+Since the braille tables are in files, you should give the full
+pathnames of the files either in .screenrc or using the
+internal screen "C-a :" command line.
+
+5. Further development
+======================
+
+As mentioned above, currently Dotscreen works with Telesensory braille
+displays the PowerBraille and the Navigator because Telesensory has
+given us the information needed to program their braille display. We
+plan to add support for other braille displays when and if we get the
+requisite information from the braille display manufacturer.
+Also some things such as cursor navigation from the braille display
+have not been implemented. If you find a feature missing that
+you wish to have, please contact us.
+
+This software has been developed within the Science Access Project at
+Oregon State University under the direction of John Gardner.
+
+Authors: Hadi Bargi Rangin (bargi@dots.physics.orst.edu)
+ Bill Barry (barryb@dots.physics.orst.edu)
+
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