summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/CONTRIBUTING.md78
-rw-r--r--.github/FUNDING.yml1
-rw-r--r--.github/ISSUE_TEMPLATE.md22
-rw-r--r--.github/README.md83
-rw-r--r--.gitignore21
-rw-r--r--.mailmap37
-rw-r--r--.travis.yml16
-rw-r--r--CHANGES2813
-rw-r--r--COPYING18
-rw-r--r--Makefile136
-rw-r--r--Makefile.am208
-rw-r--r--README75
-rw-r--r--README.ja62
-rw-r--r--SYNCING173
-rw-r--r--arguments.c1
-rwxr-xr-xautogen.sh17
-rw-r--r--cfg.c1
-rw-r--r--client.c4
-rw-r--r--cmd-find.c1
-rw-r--r--cmd-join-pane.c1
-rw-r--r--cmd-list.c103
-rw-r--r--cmd-paste-buffer.c1
-rw-r--r--cmd-pipe-pane.c1
-rw-r--r--cmd-save-buffer.c1
-rw-r--r--cmd-show-buffer.c112
-rw-r--r--cmd-show-messages.c1
-rw-r--r--cmd-show-options.c1
-rw-r--r--cmd-source-file.c1
-rw-r--r--cmd-split-window.c1
-rw-r--r--cmd-unbind-key.c42
-rw-r--r--cmd.c1
-rw-r--r--compat.h385
-rw-r--r--compat/asprintf.c64
-rw-r--r--compat/base64.c315
-rw-r--r--compat/bitstring.h128
-rw-r--r--compat/cfmakeraw.c33
-rw-r--r--compat/closefrom.c109
-rw-r--r--compat/daemon-darwin.c85
-rw-r--r--compat/daemon.c75
-rw-r--r--compat/err.c93
-rw-r--r--compat/explicit_bzero.c15
-rw-r--r--compat/fdforkpty.c34
-rw-r--r--compat/fgetln.c61
-rw-r--r--compat/forkpty-aix.c119
-rw-r--r--compat/forkpty-hpux.c90
-rw-r--r--compat/forkpty-sunos.c92
-rw-r--r--compat/freezero.c31
-rw-r--r--compat/getdtablecount.c48
-rw-r--r--compat/getopt.c115
-rw-r--r--compat/getprogname.c43
-rw-r--r--compat/imsg-buffer.c309
-rw-r--r--compat/imsg.c302
-rw-r--r--compat/imsg.h111
-rw-r--r--compat/memmem.c65
-rw-r--r--compat/queue.h533
-rw-r--r--compat/reallocarray.c40
-rw-r--r--compat/recallocarray.c82
-rw-r--r--compat/setenv.c49
-rw-r--r--compat/setproctitle.c52
-rw-r--r--compat/strcasestr.c62
-rw-r--r--compat/strlcat.c57
-rw-r--r--compat/strlcpy.c53
-rw-r--r--compat/strndup.c41
-rw-r--r--compat/strnlen.c34
-rw-r--r--compat/strsep.c73
-rw-r--r--compat/strtonum.c67
-rw-r--r--compat/tree.h748
-rw-r--r--compat/unvis.c281
-rw-r--r--compat/utf8proc.c66
-rw-r--r--compat/vis.c242
-rw-r--r--compat/vis.h85
-rw-r--r--configure.ac655
-rw-r--r--example_tmux.conf71
-rw-r--r--file.c1
-rw-r--r--format.c19
-rw-r--r--input-keys.c1
-rw-r--r--job.c1
-rw-r--r--log.c1
-rw-r--r--logo/LICENSE13
-rw-r--r--logo/favicon.icobin0 -> 6518 bytes
-rw-r--r--logo/tmux-logo-1-color.eps922
-rw-r--r--logo/tmux-logo-1-color.svg18
-rw-r--r--logo/tmux-logo-huge.pngbin0 -> 47121 bytes
-rw-r--r--logo/tmux-logo-large.pngbin0 -> 12190 bytes
-rw-r--r--logo/tmux-logo-medium.pngbin0 -> 5400 bytes
-rw-r--r--logo/tmux-logo-small.pngbin0 -> 2701 bytes
-rw-r--r--logo/tmux-logo.eps925
-rw-r--r--logo/tmux-logo.svg18
-rw-r--r--logo/tmux-logomark.eps829
-rw-r--r--logo/tmux-logomark.svg15
-rw-r--r--mdoc2man.awk370
-rw-r--r--mode-key.c261
-rw-r--r--notify.c1
-rw-r--r--options-table.c1
-rw-r--r--osdep-aix.c95
-rw-r--r--osdep-cygwin.c88
-rw-r--r--osdep-darwin.c107
-rw-r--r--osdep-dragonfly.c133
-rw-r--r--osdep-freebsd.c209
-rw-r--r--osdep-hpux.c (renamed from cmd-has-session.c)37
-rw-r--r--osdep-linux.c103
-rw-r--r--osdep-netbsd.c173
-rw-r--r--osdep-openbsd.c (renamed from procname.c)27
-rw-r--r--osdep-sunos.c101
-rw-r--r--osdep-unknown.c (renamed from cmd-send-prefix.c)48
-rw-r--r--paste.c1
-rw-r--r--presentations/tmux_asiabsdcon11.odtbin0 -> 35714 bytes
-rw-r--r--presentations/tmux_asiabsdcon11.pdfbin0 -> 112246 bytes
-rw-r--r--presentations/tmux_linuxtag_2011.odpbin0 -> 15220 bytes
-rw-r--r--proc.c6
-rw-r--r--regress/Makefile10
-rw-r--r--regress/capture-pane-sgr0.sh24
-rw-r--r--regress/command-order.sh51
-rw-r--r--regress/conf-syntax.sh14
-rw-r--r--regress/conf/21867280ff7e99631046f9cc669b80d2.conf8
-rw-r--r--regress/conf/29813ff35544434e2e64dc879a8dd274.conf58
-rw-r--r--regress/conf/2eae5d47049c1f6d0bef3db4e171aed7.conf56
-rw-r--r--regress/conf/327af72ad372255817b585a74da06eda.conf30
-rw-r--r--regress/conf/58304907c117cab9898ea0b070bccde3.conf118
-rw-r--r--regress/conf/91378fd400b0444eb8cac471e30642b3.conf30
-rw-r--r--regress/conf/99749670b62bcb99a9b2e3d59708e357.conf93
-rw-r--r--regress/conf/a46e6e84cd1071105aa807256dbc158d.conf432
-rw-r--r--regress/conf/a4789a6782859c66aa8c9614ee6fabfa.conf80
-rw-r--r--regress/conf/ad0537c4e83d7a25d5dc4f3a3c571349.conf65
-rw-r--r--regress/conf/ad21dbb0893240563ddfdd954b9903a1.conf580
-rw-r--r--regress/conf/b9f0ce1976ec62ec60dc5da7dd92c160.conf84
-rw-r--r--regress/conf/d0040b2e097f1e3d31d78eed6ce8d461.conf108
-rw-r--r--regress/conf/d2e576f947e108eb9903679b65c81fbc.conf198
-rw-r--r--regress/conf/d41d8cd98f00b204e9800998ecf8427e.conf148
-rw-r--r--regress/conf/dfd579a114a8366b5a665c264e29c084.conf52
-rw-r--r--regress/conf/e2661d67d0d45a8647fb95de76ec8174.conf78
-rw-r--r--regress/conf/ed08995f38b5a3079262a88d2563abe4.conf283
-rw-r--r--regress/control-client-sanity.sh42
-rw-r--r--regress/control-client-size.sh49
-rw-r--r--regress/cursor-test.txt6
-rw-r--r--regress/cursor-test1.result33
-rw-r--r--regress/cursor-test1.sh29
-rw-r--r--regress/cursor-test2.result33
-rw-r--r--regress/cursor-test2.sh29
-rw-r--r--regress/cursor-test3.result9
-rw-r--r--regress/cursor-test3.sh29
-rw-r--r--regress/cursor-test4.result16
-rw-r--r--regress/cursor-test4.sh31
-rw-r--r--regress/format-strings.sh183
-rw-r--r--regress/has-session-return.sh19
-rw-r--r--regress/if-shell-TERM.sh30
-rw-r--r--regress/if-shell-error.sh26
-rw-r--r--regress/if-shell-nested.sh25
-rw-r--r--regress/kill-session-process-exit.sh21
-rw-r--r--regress/new-session-base-index.sh27
-rw-r--r--regress/new-session-command.sh25
-rw-r--r--regress/new-session-environment.sh66
-rw-r--r--regress/new-session-no-client.sh25
-rw-r--r--regress/new-session-size.sh27
-rw-r--r--regress/new-window-command.sh26
-rw-r--r--regress/xenl-terminal.sh29
-rw-r--r--screen.c1
-rw-r--r--server-client.c6
-rw-r--r--server-fn.c5
-rw-r--r--server.c1
-rw-r--r--session.c1
-rw-r--r--spawn.c11
-rw-r--r--tmux.115
-rw-r--r--tmux.c12
-rw-r--r--tmux.h16
-rw-r--r--tools/24-bit-color.sh127
-rw-r--r--tools/256colors.pl63
-rw-r--r--tools/UTF-8-demo.txt212
-rw-r--r--tools/ansicode.txt779
-rw-r--r--tools/cmp-cvs.sh12
-rw-r--r--tty-term.c18
-rw-r--r--utf8.c27
-rw-r--r--window-buffer.c1
-rw-r--r--window-tree.c2
-rw-r--r--window.c14
-rw-r--r--xmalloc.h4
176 files changed, 18564 insertions, 768 deletions
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 00000000..3a589484
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,78 @@
+## What should I do before opening an issue?
+
+Before opening an issue, please ensure that:
+
+- Your problem is a specific problem or question or suggestion, not a general
+ complaint.
+
+- `$TERM` inside tmux is screen, screen-256color, tmux or tmux-256color. Check
+ by running `echo $TERM` inside tmux.
+
+- You can reproduce the problem with the latest tmux release, or a build from
+ Git master.
+
+- Your question or issue is not covered [in the
+ manual](https://man.openbsd.org/tmux.1) (run `man tmux`).
+
+- Your problem is not mentioned in the [CHANGES
+ file](https://raw.githubusercontent.com/tmux/tmux/master/CHANGES) file.
+
+- Nobody else has opened the same issue recently.
+
+## What should I include in an issue?
+
+Please include the output of:
+
+~~~bash
+uname -sp && tmux -V && echo $TERM
+~~~
+
+Also include:
+
+- Your platform (Linux, OS X, or whatever).
+
+- A brief description of the problem with steps to reproduce.
+
+- A minimal tmux config, if you can't reproduce without a config.
+
+- Your terminal, and `$TERM` inside and outside of tmux.
+
+- Logs from tmux (see below).
+
+- At most one or two screenshots, if helpful.
+
+## How do I test without a .tmux.conf?
+
+Run a separate tmux server with `-f/dev/null` to skip loading `.tmux.conf`:
+
+~~~bash
+tmux -Ltest kill-server
+tmux -Ltest -f/dev/null new
+~~~
+
+## How do I get logs from tmux?
+
+Add `-vv` to tmux to create three log files in the current directory. If you can
+reproduce without a configuration file:
+
+~~~bash
+tmux -Ltest kill-server
+tmux -vv -Ltest -f/dev/null new
+~~~
+
+Or if you need your configuration:
+
+~~~base
+tmux kill-server
+tmux -vv new
+~~~
+
+The log files are:
+
+- `tmux-server*.log`: server log file.
+
+- `tmux-client*.log`: client log file.
+
+- `tmux-out*.log`: output log file.
+
+Please attach the log files to your issue.
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 00000000..c4f1ae0d
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+liberapay: tmux
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 00000000..8bf1e66a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,22 @@
+### Issue description
+
+Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
+before opening an issue.
+
+If you have upgraded, make sure your issue is not covered in the CHANGES file
+for your version: https://raw.githubusercontent.com/tmux/tmux/master/CHANGES
+
+Describe the problem and the steps to reproduce. Add a minimal tmux config if
+necessary. Screenshots can be helpful, but no more than one or two.
+
+Do not report bugs (crashes, incorrect behaviour) without reproducing on a tmux
+built from the latest code in Git.
+
+### Required information
+
+Please provide the following information:
+
+* tmux version (`tmux -V`).
+* Platform (`uname -sp`).
+* $TERM inside and outside of tmux (`echo $TERM`).
+* Logs from tmux (`tmux kill-server; tmux -vv new`).
diff --git a/.github/README.md b/.github/README.md
new file mode 100644
index 00000000..2b299cc5
--- /dev/null
+++ b/.github/README.md
@@ -0,0 +1,83 @@
+# Welcome to tmux!
+
+tmux is a terminal multiplexer: it enables a number of terminals to be created,
+accessed, and controlled from a single screen. tmux may be detached from a
+screen and continue running in the background, then later reattached.
+
+This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
+
+## Dependencies
+
+tmux depends on [libevent](https://libevent.org) 2.x, available from [this
+page](https://github.com/libevent/libevent/releases/latest).
+
+It also depends on [ncurses](https://www.gnu.org/software/ncurses/), available
+from [this page](https://invisible-mirror.net/archives/ncurses/).
+
+## Installation
+
+### From release tarball
+
+To build and install tmux from a release tarball, use:
+
+~~~bash
+./configure && make
+sudo make install
+~~~
+
+tmux can use the utempter library to update utmp(5), if it is installed - run
+configure with `--enable-utempter` to enable this.
+
+### From version control
+
+To get and build the latest from version control - note that this requires
+`autoconf`, `automake` and `pkg-config`:
+
+~~~bash
+git clone https://github.com/tmux/tmux.git
+cd tmux
+sh autogen.sh
+./configure && make
+~~~
+
+## Contributing
+
+Bug reports, feature suggestions and especially code contributions are most
+welcome. Please send by email to:
+
+tmux-users@googlegroups.com
+
+Or open a GitHub issue or pull request. **Please read [this
+document](CONTRIBUTING.md) before opening an issue.**
+
+There is [a list of suggestions for contributions](https://github.com/tmux/tmux/wiki/Contributing).
+Please feel free to ask on the mailing list if you're thinking of working on something or need
+further information.
+
+## Documentation
+
+For documentation on using tmux, see the tmux.1 manpage. View it from the
+source tree with:
+
+~~~bash
+nroff -mdoc tmux.1|less
+~~~
+
+A small example configuration is in `example_tmux.conf`.
+
+And a bash(1) completion file at:
+
+https://github.com/imomaliev/tmux-bash-completion
+
+For debugging, run tmux with `-v` or `-vv` to generate server and client log
+files in the current directory.
+
+## Support
+
+The tmux mailing list for general discussion and bug reports is:
+
+https://groups.google.com/forum/#!forum/tmux-users
+
+Subscribe by sending an email to:
+
+tmux-users+subscribe@googlegroups.com
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..d01a0166
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,21 @@
+*.o
+*~
+*.diff
+*.patch
+*.core
+core
+tags
+.deps/
+compat/.dirstamp
+aclocal.m4
+autom4te.cache/
+config.log
+config.status
+etc/
+tmux
+Makefile
+Makefile.in
+configure
+tmux.1.*
+*.dSYM
+cmd-parse.c
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 00000000..c32c8db6
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,37 @@
+Bob Beck <beck@openbsd.org> beck <beck>
+Claudio Jeker <claudio@openbsd.org> claudio <claudio>
+Igor Sobrado <sobrado@openbsd.org> sobrado <sobrado>
+Ingo Schwarze <schwarze@openbsd.org> schwarze <schwarze>
+Jacek Masiulaniec <jacekm@openbsd.org> jacekm <jacekm>
+Jason McIntyre <jmc@openbsd.org> jmc <jmc>
+Joel Sing <jsing@openbsd.org> jsing <jsing>
+Jonathan Gray <jsg@openbsd.org> jsg <jsg>
+Kenneth R Westerback <krw@openbsd.org> krw <krw>
+Marc Espie <espie@openbsd.org> espie <espie>
+Matthew Dempsky <matthew@openbsd.org> matthew <matthew>
+Matthias Kilian <kili@openbsd.org> kili <kili>
+Matthieu Herrb <matthieu@openbsd.org> matthieu <matthieu>
+Michael McConville <mmcc@openbsd.org> mmcc <mmcc>
+Miod Vallat <miod@openbsd.org> miod <miod>
+Nicholas Marriott <nicholas.marriott@gmail.com> Nicholas Marriott <nicm@openbsd.org>
+Nicholas Marriott <nicholas.marriott@gmail.com> nicm <nicm>
+Nicholas Marriott <nicholas.marriott@gmail.com> no_author <no_author@example.org>
+Okan Demirmen <okan@openbsd.org> okan <okan>
+Philip Guenther <guenther@openbsd.org> guenther <guenther>
+Pierre-Yves Ritschard <pyr@openbsd.org> pyr <pyr>
+Ray Lai <ray@openbsd.org> ray <ray>
+Ryan McBride <mcbride@openbsd.org> mcbride <mcbride>
+Sebastian Benoit <benno@openbsd.org> benno <benno>
+Sebastien Marie <semarie@openbsd.org> semarie <semarie>
+Stefan Sperling <stsp@openbsd.org> stsp <stsp>
+Stuart Henderson <sthen@openbsd.org> sthen <sthen>
+Ted Unangst <tedu@openbsd.org> tedu <tedu>
+Theo de Raadt <deraadt@openbsd.org> Theo Deraadt <deraadt@openbsd.org>
+Theo de Raadt <deraadt@openbsd.org> deraadt <deraadt>
+Thomas Adam <thomas@xteddy.org> Thomas <thomas@xteddy.org>
+Thomas Adam <thomas@xteddy.org> Thomas Adam <thomas.adam@smoothwall.net>
+Thomas Adam <thomas@xteddy.org> n6tadam <n6tadam@xteddy.org>
+Tim van der Molen <tim@openbsd.org> tim <tim>
+Tobias Stoeckmann <tobias@openbsd.org> tobias <tobias>
+Todd C Miller <millert@openbsd.org> millert <millert>
+William Yodlowsky <william@openbsd.org> william <william>
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..fd85bf61
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,16 @@
+language: c
+
+os:
+ - linux
+ - osx
+
+compiler:
+ - gcc
+ - clang
+
+before_install:
+ - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq; fi
+ - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -y install bison autotools-dev libncurses5-dev libevent-dev pkg-config libutempter-dev build-essential; fi
+
+script:
+ - ./autogen.sh && ./configure && make
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 00000000..cd3a1b8a
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,2813 @@
+CHANGES FROM 3.0 to X.X
+
+* Change file reading and writing to go through the client if necessary. This
+ fixes commands like "tmux loadb /dev/fd/X". Also modify source-file to
+ support "-" for standard input, like load-buffer and save-buffer.
+
+* Add ~/.config/tmux/tmux.conf to the default search path for configuration
+ files.
+
+* Bump the escape sequence timeout to five seconds to allow for longer
+ legitimate sequences.
+
+* Make a best effort to set xpixel and ypixel for each pane and add formats for
+ them.
+
+* Add push-default to status-left and status-right in status-format[0].
+
+* Add -F flag to send-keys to expand formats in search-backward and forward
+ copy mode commands and copy_cursor_word and copy_cursor_line formats for word
+ and line at cursor in copy mode. Use for default # and * binding with vi(1)
+ keys.
+
+* Do not clear search marks on cursor movement with vi(1) keys.
+
+* Add p format modifier for padding to width and allow multiple substitutions
+ in a single format.
+
+* Add -f for full size to join-pane (like split-window).
+
+* Handle OSC 7 (a VTE extension) and put the result in a new format (pane_path).
+
+* Change new-session -A without a session name (that is, no -s option also) to
+ attach to the best existing session like attach-session rather than creating
+ a new one.
+
+* Add an option to set the key sent by backspace for those whose system uses ^H
+ rather than ^?.
+
+* Add formats for cursor and selection position in copy mode.
+
+* Add support for percentage sizes for resize-pane ("-x 10%"). Also change
+ split-window and join-pane -l to accept similar percentages and no longer
+ document -p.
+
+* Turn automatic-rename back on if the rename escape sequence is used with an
+ empty name.
+
+* Make select-pane -P set window-active-style also to match previous behaviour.
+
+* Do not use bright when emulating 256 colours on an 8 colour terminal because
+ it is also bold on some terminals.
+
+* Add a "latest" window-size option which tries to size windows based on the
+ most recently used client. This is now the default.
+
+* Make select-pane -P set window-active-style also to match previous behaviour.
+
+* Do not truncate list-keys output.
+
+* Turn automatic-rename back on if the \033k rename escape sequence is used
+ with an empty name.
+
+* Add support for percentage sizes for resize-pane ("-x 10%"). Also change
+ split-window and join-pane -l to accept similar percentages and deprecate the
+ -p flag.
+
+* Add -F flag to send-keys to expand formats in search-backward and forward
+ copy mode commands, this makes it easier to use the cursor_word and
+ cursor_line formats.
+
+* Add formats for word and line at cursor position in copy mode.
+
+* Add formats for cursor and selection position in copy mode
+
+* Support all the forms of RGB colour strings in OSC sequences rather than
+ requiring two digits.
+
+* Limit lazy resize to panes in attached sessions only
+
+* Add an option to set the key sent by backspace for those whose system uses ^H
+ rather than ^?.
+
+* Change new-session -A without a session name (that is, no -s option also) to
+ attach to the best existing session like attach-session rather than a new
+ one.
+
+* Change window-size default from smallest to latest.
+
+* Add simple support for OSC 7 (result is available in the pane_path format).
+
+* Add push-default and pop-default for styles which change the colours and
+ attributes used for #[default]. These are used in status-format to restore
+ the behaviour of window-status-style being the default for
+ window-status-format.
+
+* Add window_marked_flag.
+
+* Add cursor-down-and-cancel in copy mode.
+
+* Default to previous search string for search-forward and search-backward.
+
+* Add -Z flag to rotate-window, select-pane, swap-pane, switch-client to
+ preserve zoomed state.
+
+* Add -N to capture-pane to preserve trailing spaces.
+
+* Add reverse sorting in tree, client and buffer modes.
+
+CHANGES FROM 3.0 to 3.0a
+
+* Do not require REG_STARTEND.
+
+* Respawn panes or windows correctly if default-command is set.
+
+* Add missing option for after-kill-pane hook.
+
+* Fix for crash with a format variable that doesn't exist.
+
+* Do not truncate list-keys output on some platforms.
+
+* Do not crash when restoring a layout with only one pane.
+
+CHANGES FROM 2.9 to 3.0
+
+* Workaround invalid layout strings generated by older tmux versions and add
+ some additional sanity checks
+
+* xterm 348 now disables margins when resized, so send DECLRMM again after
+ resize.
+
+* Add support for the SD (scroll down) escape sequence.
+
+* Expand arguments to C and s format modifiers to match the m modifier.
+
+* Add support for underscore colours (Setulc capability must be added with
+ terminal-overrides as described in tmux(1)).
+
+* Add a "fill" style attribute for the fill colour of the drawing area (where
+ appropriate).
+
+* New -H flag to send-keys to send literal keys.
+
+* Format variables for pane mouse modes (mouse_utf8_flag and mouse_sgr_flag)
+ and for origin mode (origin_flag).
+
+* Add -F to refresh-client for flags for control mode clients, only one flag
+ (no-output) supported at the moment.
+
+* Add a few vi(1) keys for menus.
+
+* Add pane options, set with set-option -p and displayed with show-options -p.
+ Pane options inherit from window options (so every pane option is also
+ a window option). The pane style is now configured by setting window-style
+ and window-active-style in the pane options; select-pane -P and -g now change
+ the option but are no longer documented.
+
+* Do not document set-window-option and show-window-options. set-option -w and
+ show-options -w should be used instead.
+
+* Add a -A flag to show-options to show parent options as well (they are marked
+ with a *).
+
+* Resize panes lazily - do not resize unless they are in an attached, active
+ window.
+
+* Add regular expression support for the format search, match and substitute
+ modifiers and make them able to ignore case. find-window now accepts -r to
+ use regular expressions.
+
+* Do not use $TMUX to find the session because for windows in multiple sessions
+ it is wrong as often as it is right, and for windows in one session it is
+ pointless. Instead use TMUX_PANE if it is present.
+
+* Do not always resize the window back to its original size after applying a
+ layout, keep it at the layout size until it must be resized (for example when
+ attached and window-size is not manual).
+
+* Add new-session -X and attach-session -x to send SIGHUP to parent when
+ detaching (like detach-client -P).
+
+* Support for octal escapes in strings (such as \007) and improve list-keys
+ output so it parses correctly if copied into a configuration file.
+
+* INCOMPATIBLE: Add a new {} syntax to the configuration file. This is a string
+ similar to single quotes but also includes newlines and allows commands that
+ take other commands as string arguments to be expressed more clearly and
+ without additional escaping.
+
+ A literal { and } or a string containing { or } must now be escaped or
+ quoted, for example '{' and '}' instead of { or }, or 'X#{foo}' instead of
+ X#{foo}.
+
+* New <, >, <= and >= comparison operators for formats.
+
+* Improve escaping of special characters in list-keys output.
+
+* INCOMPATIBLE: tmux's configuration parsing has changed to use yacc(1). There
+ is one incompatible change: a \ on its own must be escaped or quoted as
+ either \\ or '\' (the latter works on older tmux versions).
+
+ Entirely the same parser is now used for parsing the configuration file
+ and for string commands. This means that constructs previously only
+ available in .tmux.conf, such as %if, can now be used in string commands
+ (for example, those given to if-shell - not commands invoked from the
+ shell, they are still parsed by the shell itself).
+
+* Add support for the overline attribute (SGR 53). The Smol capability is
+ needed in terminal-overrides.
+
+* Add the ability to create simple menus. Introduces new command
+ display-menu. Default menus are bound to MouseDown3 on the status line;
+ MouseDown3 or M-MouseDown3 on panes; MouseDown3 in tree, client and
+ buffer modes; and C-b < and >.
+
+* Allow panes to be empty (no command). They can be created either by piping to
+ split-window -I, or by passing an empty command ('') to split-window. Output
+ can be sent to an existing empty window with display-message -I.
+
+* Add keys to jump between matching brackets (emacs C-M-f and C-M-b, vi %).
+
+* Add a -e flag to new-window, split-window, respawn-window, respawn-pane to
+ pass environment variables into the newly created process.
+
+* Hooks are now stored in the options tree as array options, allowing them to
+ have multiple separate commands. set-hook and show-hooks remain but
+ set-option and show-options can now also be used (show-options will only show
+ hooks if given the -H flag). Hooks with multiple commands are run in index
+ order.
+
+* Automatically scroll if dragging to create a selection with the mouse and the
+ cursor reaches the top or bottom line.
+
+* Add -no-clear variants of copy-selection and copy-pipe which do not clear the
+ selection after copying. Make copy-pipe clear the selection by default to be
+ consistent with copy-selection.
+
+* Add an argument to copy commands to set the prefix for the buffer name, this
+ (for example) allows buffers for different sessions to be named separately.
+
+* Update session activity on focus event.
+
+* Pass target from source-file into the config file parser so formats in %if
+ and %endif have access to more useful variables.
+
+* Add the ability to infer an option type (server, session, window) from its
+ name to show-options (it was already present in set-option).
+
+CHANGES FROM 2.9 to 2.9a
+
+* Fix bugs in select-pane and the main-horizontal and main-vertical layouts.
+
+CHANGES FROM 2.8 to 2.9
+
+* Attempt to preserve horizontal cursor position as well as vertical with
+ reflow.
+
+* Rewrite main-vertical and horizontal and change layouts to better handle the
+ case where all panes won't fit into the window size, reduce problems with
+ pane border status lines and fix other bugs mostly found by Thomas Sattler.
+
+* Add format variables for the default formats in the various modes
+ (tree_mode_format and so on) and add a -a flag to display-message to list
+ variables with values.
+
+* Add a -v flag to display-message to show verbose messages as the format is
+ parsed, this allows formats to be debugged
+
+* Add support for HPA (\033[`).
+
+* Add support for origin mode (\033[?6h).
+
+* No longer clear history on RIS.
+
+* Extend the #[] style syntax and use that together with previous format
+ changes to allow the status line to be entirely configured with a single
+ option.
+
+ Now that it is possible to configure their content, enable the existing code
+ that lets the status line be multiple lines in height. The status option can
+ now take a value of 2, 3, 4 or 5 (as well as the previous on or off) to
+ configure more than one line. The new status-format array option configures
+ the format of each line, the default just references the existing status-*
+ options, although some of the more obscure status options may be eliminated
+ in time.
+
+ Additions to the #[] syntax are: "align" to specify alignment (left, centre,
+ right), "list" for the window list and "range" to configure ranges of text
+ for the mouse bindings.
+
+ The "align" keyword can also be used to specify alignment of entries in tree
+ mode and the pane status lines.
+
+* Add E: and T: format modifiers to expand a format twice (useful to expand the
+ value of an option).
+
+* The individual -fg, -bg and -attr options have been removed; they
+ were superseded by -style options in tmux 1.9.
+
+* Allow more than one mode to be opened in a pane. Modes are kept on a stack
+ and retrieved if the same mode is entered again. Exiting the active mode goes
+ back to the previous one.
+
+* When showing command output in copy mode, call it view mode instead (affects
+ pane_mode format).
+
+* Add -b to display-panes like run-shell.
+
+* Handle UTF-8 in word-separators option.
+
+* New "terminal" colour allowing options to use the terminal default colour
+ rather than inheriting the default from a parent option.
+
+* Do not move the cursor in copy mode when the mouse wheel is used.
+
+* Use the same working directory rules for jobs as new windows rather than
+ always starting in the user's home.
+
+* Allow panes to be one line or column in size.
+
+* Go to last line when goto-line number is out of range in copy mode.
+
+* Yank previously cut text if any with C-y in the command prompt, only use the
+ buffer if no text has been cut.
+
+* Add q: format modifier to quote shell special characters.
+
+* Add StatusLeft and StatusRight mouse locations (keys such as
+ MouseDown1StatusLeft) for the status-left and status-right areas of the
+ status line.
+
+* Add -Z to find-window.
+
+* Support for windows larger than the client. This adds two new options,
+ window-size and default-size, and a new command, resize-window. The
+ force-width and force-height options and the session_width and session_height
+ formats have been removed.
+
+ The new window-size option tells tmux how to work out the size of windows:
+ largest means it picks the size of the largest session, smallest the smallest
+ session (similar to the old behaviour) and manual means that it does not
+ automatically resize windows. aggressive-resize modifies the choice of
+ session for largest and smallest as it did before.
+
+ If a window is in a session attached to a client that is too small, only part
+ of the window is shown. tmux attempts to keep the cursor visible, so the part
+ of the window displayed is changed as the cursor moves (with a small delay,
+ to try and avoid excess redrawing when applications redraw status lines or
+ similar that are not currently visible).
+
+ Drawing windows which are larger than the client is not as efficient as those
+ which fit, particularly when the cursor moves, so it is recommended to avoid
+ using this on slow machines or networks (set window-size to smallest or
+ manual).
+
+ The resize-window command can be used to resize a window manually. If it is
+ used, the window-size option is automatically set to manual for the window
+ (undo this with "setw -u window-size"). resize-window works in a similar way
+ to resize-pane (-U -D -L -R -x -y flags) but also has -a and -A flags. -a
+ sets the window to the size of the smallest client (what it would be if
+ window-size was smallest) and -A the largest.
+
+ For the same behaviour as force-width or force-height, use resize-window -x
+ or -y.
+
+ If the global window-size option is set to manual, the default-size option is
+ used for new windows. If -x or -y is used with new-session, that sets the
+ default-size option for the new session.
+
+ The maximum size of a window is 10000x10000. But expect applications to
+ complain and higher memory use if making a window that big. The minimum size
+ is the size required for the current layout including borders.
+
+ The refresh-client command can be used to pan around a window, -U -D -L -R
+ moves up, down, left or right and -c returns to automatic cursor
+ tracking. The position is reset when the current window is changed.
+
+CHANGES FROM 2.7 to 2.8
+
+* Make display-panes block the client until a pane is chosen or it
+ times out.
+
+* Clear history on RIS like most other terminals do.
+
+* Add an "Any" key to run a command if a key is pressed that is not
+ bound in the current key table.
+
+* Expand formats in load-buffer and save-buffer.
+
+* Add a rectangle_toggle format.
+
+* Add set-hook -R to run a hook immediately.
+
+* Add README.ja.
+
+* Add pane focus hooks.
+
+* Allow any punctuation as separator for s/x/y not only /.
+
+* Improve resizing with the mouse (fix resizing the wrong pane in some
+ layouts, and allow resizing multiple panes at the same time).
+
+* Allow , and } to be escaped in formats as #, and #}.
+
+* Add KRB5CCNAME to update-environment.
+
+* Change meaning of -c to display-message so the client is used if it
+ matches the session given to -t.
+
+* Fixes to : form of SGR.
+
+* Add x and X to choose-tree to kill sessions, windows or panes.
+
+CHANGES FROM 2.6 TO 2.7
+
+* Remove EVENT_* variables from environment on platforms where tmux uses them
+ so they do not pass on to panes.
+
+* Fixes for hooks at server exit.
+
+* Remove SGR 10 (was equivalent to SGR 0 but no other terminal seems to do
+ this).
+
+* Expand formats in window and session names.
+
+* Add -Z flag to choose-tree, choose-client, choose-buffer to automatically
+ zoom the pane when the mode is entered and unzoom when it exits, assuming the
+ pane is not already zoomed. This is now part of the default key bindings.
+
+* Add C-g to exit modes with emacs keys.
+
+* Add exit-empty option to exit server if no sessions (defaults to on).
+
+* Show if a filter is present in choose modes.
+
+* Add pipe-pane -I to to connect stdin of the child process.
+
+* Performance improvements for reflow.
+
+* Use RGB terminfo(5) capability to detect RGB colour terminals (the existing
+ Tc extension remains unchanged).
+
+* Support for ISO colon-separated SGR sequences.
+
+* Add select-layout -E to spread panes out evenly (bound to E key).
+
+* Support wide characters properly when reflowing.
+
+* Pass PWD to new panes as a hint to shells, as well as calling chdir().
+
+* Performance improvements for the various choose modes.
+
+* Only show first member of session groups in tree mode (-G flag to choose-tree
+ to show all).
+
+* Support %else in config files to match %if; from Brad Town in GitHub issue
+ 1071.
+
+* Fix "kind" terminfo(5) capability to be S-Down not S-Up.
+
+* Add a box around the preview label in tree mode.
+
+* Show exit status and time in the remain-on-exit pane text; from Timo
+ Boettcher in GitHub issue 1103.
+
+* Correctly use pane-base-index in tree mode.
+
+* Change the allow-rename option default to off.
+
+* Support for xterm(1) title stack escape sequences (GitHub issue 1075 from
+ Brad Town).
+
+* Correctly remove padding cells to fix a UTF-8 display problem (GitHub issue
+ 1090).
+
+CHANGES FROM 2.5 TO 2.6, 05 October 2017
+
+* Add select-pane -T to set pane title.
+
+* Fix memory leak when lines with BCE are removed from history.
+
+* Fix (again) the "prefer unattached" behaviour of attach-session.
+
+* Reorder how keys are checked to allow keys to be specified that have a
+ leading escape. GitHub issue 1048.
+
+* Support REP escape sequence (\033[b).
+
+* Run alert hooks based on options rather than always, and allow further bells
+ even if there is an existing bell.
+
+* Add -d flag to display-panes to override display-panes-time.
+
+* Add selection_present format when in copy mode (allows key bindings that do
+ something different if there is a selection).
+
+* Add pane_at_left, pane_at_right, pane_at_top and pane_at_bottom formats.
+
+* Make bell, activity and silence alerting more consistent by: removing the
+ bell-on-alert option; adding activity-action and silence-action options with
+ the same possible values as the existing bell-action; adding a "both" value
+ for the visual-bell, visual-activity and visual-silence options to trigger
+ both a bell and a message.
+
+* Add a pane_pipe format to show if pipe-pane is active.
+
+* Block signals between forking and resetting signal handlers so that the
+ libevent signal handler doesn't get called in the child and incorrectly write
+ into the signal pipe that it still shares with the parent. GitHub issue 1001.
+
+* Allow punctuation in pane_current_command.
+
+* Add -c for respawn-pane and respawn-window.
+
+* Wait for any remaining data to flush when a pane is closed while pipe-pane is
+ in use.
+
+* Fix working out current client with no target. GitHub issue 995.
+
+* Try to fallback to C.UTF-8 as well as en_US.UTF-8 when looking for a UTF-8
+ locale.
+
+* Add user-keys option for user-defined key escape sequences (mapped to User0
+ to User999 keys).
+
+* Add pane-set-clipboard hook.
+
+* FAQ file has moved out of repository to online.
+
+* Fix problem with high CPU usage when a client dies unexpectedly. GitHub issue
+ 941.
+
+* Do a dance on OS X 10.10 and above to return tmux to the user namespace,
+ allowing access to the clipboard.
+
+* Do not allow escape sequences which expect a specific terminator (APC, DSC,
+ OSC) to wait for forever - use a small timeout. This reduces the chance of
+ the pane locking up completely when sent garbage (cat /dev/random or
+ similar).
+
+* Support SIGUSR2 to toggle logging on a running server, also generate the
+ "out" log file with -vv not -vvvv.
+
+* Make set-clipboard a three state option: on (tmux both sends to outside
+ terminal and accepts from applications inside); external (tmux sends outside
+ but does not accept inside); and off.
+
+* Fix OSC 4 palette setting for bright foreground colours. GitHub issue 954.
+
+* Use setrgbf and setrgbb terminfo(5) capabilities to set RGB colours, if they
+ are available. (Tc is still supported as well.)
+
+* Fix redrawing panes when they are resized several times but end up with the
+ size unchanged (for example, splitw/resizep -Z/breakp).
+
+* Major rewrite of choose mode. Now includes preview, sorting, searching and
+ tagging; commands that can be executed directly from the mode (for example,
+ to delete one or more buffers); and filtering in tree mode.
+
+* choose-window and choose-session are now aliases of choose-tree (in the
+ command-alias option).
+
+* Support OSC 10 and OSC 11 to set foreground and background colours.
+
+* Check the U8 capability to determine whether to use UTF-8 line drawing
+ characters for ACS.
+
+* Some missing notifications for layout changes.
+
+* Control mode clients now do not affect session sizes until they issue
+ refresh-client -C. new-session -x and -y works with control clients even if
+ the session is not detached.
+
+* All new sessions that are unattached (whether with -d or started with no
+ terminal) are now created with size 80 x 24. Whether the status line is on or
+ off does not affect the size of new sessions until they are attached.
+
+* Expand formats in option names and add -F flag to expand them in option values.
+
+* Remember the search string for a pane even if copy mode is exited and entered
+ again.
+
+* Some further BCE fixes (scroll up, reverse index).
+
+* Improvements to how terminals are cleared (entirely or partially).
+
+CHANGES FROM 2.4 TO 2.5, 09 May 2017
+
+* Reset updated flag when restarting #() command so that new output is properly
+ recognised. GitHub issue 922.
+
+* Fix ECH with a background colour.
+
+* Do not rely on the terminal not moving the cursor after DL or EL.
+
+* Fix send-keys and send-prefix in copy-mode (so C-b C-b works). GitHub issue
+ 905.
+
+* Set the current pane for rotate-window so it works in command sequences.
+
+* Add pane_mode format.
+
+* Differentiate M-Up from Escape+Up when possible (that is, in terminals with
+ xterm(1) style function keys). GitHub issue 907.
+
+* Add session_stack and window_stack_index formats.
+
+* Some new control mode notifications and corresponding hooks:
+ pane-mode-changed, window-pane-changed, client-session-changed,
+ session-window-changed.
+
+* Format pane_search_string for last search term while in copy mode (useful
+ with command-prompt -I).
+
+* Fix a problem with high CPU usage and multiple clients with #(). GitHub issue
+ 889.
+
+* Fix UTF-8 combining characters in column 0.
+
+* Fix reference counting so that panes are properly destroyed and their
+ processes killed.
+
+* Clamp SU (CSI S) parameter to work around a bug in Konsole.
+
+* Tweak line wrapping in full width panes to play more nicely with terminal
+ copy and paste.
+
+* Fix when we emit SGR 0 in capture-pane -e.
+
+* Do not change TERM until after config file parsing has finished, so that
+ commands run inside the config file can use it to make decisions (typically
+ about default-terminal).
+
+* Make the initial client wait until config file parsing has finished to avoid
+ racing with commands.
+
+* Fix core when if-shell fails.
+
+* Only use ED to clear screen if the pane is at the bottom.
+
+* Fix multibyte UTF-8 output.
+
+* Code improvements around target (-t) resolution.
+
+* Change how the default target (for commands without -t) is managed across
+ command sequences: now it is set up at the start and commands are required
+ to update it if needed. Fixes binding command sequences to mouse keys.
+
+* Make if-shell from the config file work correctly.
+
+* Change to always check the root key table if no binding is found in the
+ current table (prefix table or copy-mode table or whatever). This means that
+ root key bindings will take effect even in copy mode, if not overridden by a
+ copy mode key binding.
+
+* Fix so that the history file works again.
+
+* Run config file without a client rather than using the first client, restores
+ previous behaviour.
+
+* If a #() command doesn't exit, continue to read from it and use its last full
+ line of output.
+
+* Handle slow terminals and fast output better: when the amount of data
+ outstanding gets too large, discard output until it is drained and we are
+ able to do a full redraw. Prevents tmux sitting on a huge buffer that the
+ terminal will take forever to consume.
+
+* Do not redraw a client unless we realistically think it can accept the data -
+ defer redraws until the client has nothing else waiting to write.
+
+CHANGES FROM 2.3 TO 2.4, 20 April 2017
+
+Incompatible Changes
+====================
+
+* Key tables have undergone major changes. Mode key tables are no longer
+ separate from the main key tables. All mode key tables have been removed,
+ together with the -t flag to bind-key and unbind-key.
+
+ The emacs-edit, vi-edit, emacs-choose and vi-choose tables have been replaced
+ by fixed key bindings in the command prompt and choose modes. The mode-keys
+ and status-keys options remain.
+
+ The emacs-copy and vi-copy tables have been replaced by the copy-mode and
+ copy-mode-vi tables. Commands are sent using the -X and -N flags to
+ send-keys. So the following:
+
+ bind -temacs-copy C-Up scroll-up
+ bind -temacs-copy -R5 WheelUpPane scroll-up
+
+ Becomes:
+
+ bind -Tcopy-mode C-Up send -X scroll-up
+ bind -Tcopy-mode WheelUpPane send -N5 -X scroll-up
+
+ These changes allows the full command parser (including command sequences) and
+ command set to be used - for example, the normal command prompt with editing
+ and history is now used for searching, jumping, and so on instead of a custom
+ one. The default C-r binding is now:
+
+ bind -Tcopy-mode C-r command-prompt -i -p'search up' "send -X search-backward-incremental '%%'"
+
+ There are also some new commmands available with send -X, such as
+ copy-pipe-and-cancel.
+* set-remain-on-exit has gone -- can be achieved with hooks instead.
+* Hooks: before hooks have been removed and only a selection of commands now
+ have after hooks (they are no longer automatic). Additional hooks have been
+ added.
+* The xterm-keys option now defaults to on.
+
+Normal Changes
+==============
+
+* Support for mouse double and triple clicks.
+* BCE (Background Colour Erase) is now supported.
+* All occurrences of a search string in copy mode are now highlighted;
+ additionally, the number of search results is displayed. The highlighting
+ updates interactively with the default emacs key bindings (incremental
+ search).
+* source-file now understands glob patterns.
+* Formats now have simple comparisons:
+
+ #{==:a,b}
+ #{!=:a,b}
+
+* There are the following new formats:
+
+ - #{version} -- the tmux server version;
+ - #{client_termtype} -- the terminal type of the client;
+ - #{client_name} -- the name of a client;
+ - #{client_written} -- the number of bytes written to the client.
+
+* The configuration file now accepts %if/%endif conditional blocks which are
+ processed when it is parsed; the argument is a format string (useful with the
+ new format comparison options).
+* detach-client now has -E to execute a command replacing the client instead of
+ exiting.
+* Add support for custom command aliases, this is an array option which
+ contains items of the form "alias=command". This is consulted when an
+ unknown command is parsed.
+* break-pane now has -n to specify the new window name.
+* OSC 52 support has been added for programs inside tmux to set a tmux buffer.
+* The mouse "all event" mode (1003) is now supported.
+* Palette setting is now possible (OSC 4 and 104).
+* Strikethrough support (a recent terminfo is required).
+* Grouped sessions can now be named (new -t).
+* terminal-overrides and update-environment are now array options (the previous
+ set -ag syntax should work without change).
+* There have been substantial performance improvements.
+
+CHANGES FROM 2.2 TO 2.3, 29 September 2016
+
+Incompatible Changes
+====================
+
+None.
+
+Normal Changes
+==============
+
+* New option 'pane-border-status' to add text in the pane borders.
+* Support for hooks on commands: 'after' and 'before' hooks.
+* 'source-file' understands '-q' to suppress errors for nonexistent files.
+* Lots of UTF8 improvements, especially on MacOS.
+* 'window-status-separator' understands #[] expansions.
+* 'split-window' understands '-f' for performing a full-width split.
+* Allow report count to be specified when using 'bind-key -R'.
+* 'set -a' for appending to user options (@foo) is now supported.
+* 'display-panes' can now accept a command to run, rather than always
+ selecting the pane.
+
+CHANGES FROM 2.1 TO 2.2, 10 April 2016
+
+Incompatible Changes
+====================
+
+* The format strings which referenced time have been removed. Instead:
+
+ #{t:window_activity}
+
+can be used.
+
+* Support for TMPDIR has been removed. Use TMUX_TMPDIR instead.
+* UTF8 detection now happens automatically if the client supports it, hence
+ the:
+
+ mouse-utf8
+ utf8
+
+ options has been removed.
+* The:
+
+ mouse_utf8_flag
+
+ format string has been removed.
+* The -I option to show-messages has been removed. See:
+
+ #{t:start_time}
+
+ format option instead.
+
+Normal Changes
+==============
+
+* Panes are unzoomed with selectp -LRUD
+* New formats added:
+
+ #{scroll_position}
+ #{socket_path}
+ #{=10:...} -- limit to N characters (from the start)
+ #{=-10:...} -- limit to N characters (from the end)
+ #{t:...} -- used to format time-based formats
+ #{b:...} -- used to ascertain basename from string
+ #{d:...} -- used to ascertain dirname from string
+ #{s:...} -- used to perform substitutions on a string
+
+* Job output is run via the format system, so formats work again
+* If display-time is set to 0, then the indicators wait for a key to be
+ pressed.
+* list-keys and list-commands can be run without starting the tmux server.
+* kill-session learns -C to clear all alerts in all windows of the session.
+* Support for hooks (internal for now), but hooks for the following have been
+ implemented:
+
+ alert-bell
+ alert-silence
+ alert-activity
+ client-attached
+ client-detached
+ client-resized
+ pane-died
+ pane-exited
+
+* RGB (24bit) colour support. The 'Tc' flag must be set in the external TERM
+ entry (using terminal-overrides or a custom terminfo entry).
+
+CHANGES FROM 2.0 TO 2.1, 18 October 2015
+
+Incompatible Changes
+====================
+
+* Mouse-mode has been rewritten. There's now no longer options for:
+ - mouse-resize-pane
+ - mouse-select-pane
+ - mouse-select-window
+ - mode-mouse
+
+ Instead there is just one option: 'mouse' which turns on mouse support
+ entirely.
+* 'default-terminal' is now a session option. Furthermore, if this is set
+ to 'screen-*' then emulate what screen does. If italics are wanted, this
+ can be set to 'tmux' but this is still new and not necessarily supported
+ on all platforms with older ncurses installs.
+* The c0-* options for rate-limiting have been removed. Instead, a backoff
+ approach is used.
+
+Normal Changes
+==============
+
+* New formats:
+ - session_activity
+ - window_linked
+ - window_activity_format
+ - session_alerts
+ - session_last_attached
+ - client_pid
+ - pid
+* 'copy-selection', 'append-selection', 'start-named-buffer' now understand
+ an '-x' flag to prevent it exiting copying mode.
+* 'select-pane' now understands '-P' to set window/pane background colours.
+* 'renumber-windows' now understands windows which are unlinked.
+* 'bind' now understands multiple key tables. Allows for key-chaining.
+* 'select-layout' understands '-o' to undo the last layout change.
+* The environment is updated when switching sessions as well as attaching.
+* 'select-pane' now understands '-M' for marking a pane. This marked pane
+ can then be used with commands which understand src-pane specifiers
+ automatically.
+* If a session/window target is prefixed with '=' then only an exact match
+ is considered.
+* 'move-window' understands '-a'.
+* 'update-environment' understands '-E' when attach-session is used on an
+ already attached client.
+* 'show-environment' understands '-s' to output Bourne-compatible commands.
+* New option: 'history-file' to save/restore command prompt history.
+* Copy mode is exited if the history is cleared whilst in copy-mode.
+* 'copy-mode' learned '-e' to exit copy-mode when scrolling to end.
+
+CHANGES FROM 1.9a TO 2.0, 06 March 2015
+
+Incompatible Changes
+====================
+
+* The choose-list command has been removed.
+* 'terminal-overrides' is now a server option, not a session option.
+* 'message-limit' is now a server option, not a session option.
+* 'monitor-content' option has been removed.
+* 'pane_start_path' option has been removed.
+* The "info" mechanism which used to (for some commands) provide feedback
+ has been removed, and like other commands, they now produce nothing on
+ success.
+
+Normal Changes
+==============
+
+* tmux can now write an entry to utmp if the library 'utempter' is present
+ at compile time.
+* set-buffer learned append mode (-a), and a corresponding
+ 'append-selection' command has been added to copy-mode.
+* choose-mode now has the following commands which can be bound:
+ - start-of-list
+ - end-of-list
+ - top-line
+ - bottom-line
+
+* choose-buffer now understands UTF-8.
+* Pane navigation has changed:
+ - The old way of always using the top or left if the choice is ambiguous.
+ - The new way of remembering the last used pane is annoying if the
+ layout is balanced and the leftmost is obvious to the user (because
+ clearly if we go right from the top-left in a tiled set of four we want
+ to end up in top-right, even if we were last using the bottom-right).
+
+ So instead, use a combination of both: if there is only one possible
+ pane alongside the current pane, move to it, otherwise choose the most
+ recently used of the choice.
+* 'set-buffer' can now be told to give names to buffers.
+* The 'new-session', 'new-window', 'split-window', and 'respawn-pane' commands
+ now understand multiple arguments and handle quoting problems correctly.
+* 'capture-pane' understands '-S-' to mean the start of the pane, and '-E-' to
+ mean the end of the pane.
+* Support for function keys beyond F12 has changed. The following explains:
+ - F13-F24 are S-F1 to S-F12
+ - F25-F36 are C-F1 to C-F12
+ - F37-F48 are C-S-F1 to C-S-F12
+ - F49-F60 are M-F1 to M-F12
+ - F61-F63 are M-S-F1 to M-S-F3
+
+ Therefore, F13 becomes a binding of S-F1, etc.
+* Support using pane id as part of session or window specifier (so % means
+ session-of-%1 or window-of-%1) and window id as part of session
+ (so @1 means session-of-@1).
+* 'copy-pipe' command now understands formats via -F
+* 'if-shell' command now understands formats via -F
+* 'split-window' and 'join-window' understand -b to create the pane to the left
+ or above the target pane.
+
+CHANGES FROM 1.9 TO 1.9a, 22 February 2014
+
+NOTE: This is a bug-fix release to address some important bugs which just
+missed the 1.9 deadline, but were found afterwards.
+
+Normal Changes
+==============
+
+* Fix crash due to uninitialized lastwp member of layout_cell
+* Fix -fg/-bg/-style with 256 colour terminals.
+
+CHANGES FROM 1.8 TO 1.9, 20 February 2014
+
+NOTE: This release has bumped the tmux protocol version. It is therefore
+advised that the prior tmux server is restarted when this version of tmux is
+installed, to avoid protocol mismatch errors for newer clients trying to
+talk to an older running tmux server.
+
+Incompatible Changes
+====================
+
+* 88 colour support has been removed.
+* 'default-path' has been removed. The new-window command accepts '-c' to
+ cater for this. The previous value of "." can be replaced with: 'neww -c
+ $PWD', the previous value of '' which meant current path of the pane can
+ be specified as: 'neww -c "#{pane_current_path}"'
+
+Deprecated Changes
+==================
+
+* The single format specifiers: #A -> #Z (where defined) have been
+ deprecated and replaced with longer-named equivalents, as listed in the
+ FORMATS section of the tmux manpage.
+* The various foo-{fg,bg,attr} commands have been deprecated and replaced
+ with equivalent foo-style option instead. Currently this is still
+ backwards-compatible, but will be removed over time.
+
+Normal Changes
+==============
+
+* A new environment variable TMUX_TMPDIR is now honoured, allowing the
+ socket directory to be set outside of TMPDIR (/tmp/ if not set).
+* If -s not given to swap-pane the current pane is assumed.
+* A #{pane_synchronized} format specifier has been added to be a conditional
+ format if a pane is in a synchronised mode (c.f. synchronize-panes)
+* Tmux now runs under Cygwin natively.
+* Formats can now be nested within each other and expanded accordingly.
+* Added 'automatic-rename-format' option to allow the automatic rename
+ mechanism to use something other than the default of
+ #{pane_current_command}.
+* new-session learnt '-c' to specify the starting directory for that session
+ and all subsequent windows therein.
+* The session name is now shown in the message printed to the terminal when
+ a session is detached.
+* Lots more format specifiers have been added.
+* Server race conditions have been fixed; in particular commands are not run
+ until after the configuration file is read completely.
+* Case insensitive searching in tmux's copy-mode is now possible.
+* attach-session and switch-client learnt the '-t' option to accept a window
+ and/or a pane to use.
+* Copy-mode is only exited if no selection is in progress.
+* Paste key in copy-mode is now possible to enter text from the clipboard.
+* status-interval set to '0' now works as intended.
+* tmux now supports 256 colours running under fbterm.
+* Many bug fixes!
+
+CHANGES FROM 1.7 TO 1.8, 26 March 2013
+
+Incompatible Changes
+====================
+
+* layout redo/undo has been removed.
+
+Normal Changes
+==============
+
+* Add halfpage up/down bindings to copy mode.
+* Session choosing fixed to work with unattached sessions.
+* New window options window-status-last-{attr,bg,fg} to denote the last
+ window which was active.
+* Scrolling in copy-mode now scrolls the region without moving the mouse
+ cursor.
+* run-shell learnt '-t' to specify the pane to use when displaying output.
+* Support for middle-click pasting.
+* choose-tree learns '-u' to start uncollapsed.
+* select-window learnt '-T' to toggle to the last window if it's already
+ current.
+* New session option 'assume-paste-time' for pasting text versus key-binding
+ actions.
+* choose-* commands now work outside of an attached client.
+* Aliases are now shown for list-commands command.
+* Status learns about formats.
+* Free-form options can be set with set-option if prepended with an '@'
+ sign.
+* capture-pane learnt '-p' to send to stdout, and '-e' for capturing escape
+ sequences, and '-a' to capture the alternate screen, and '-P' to dump
+ pending output.
+* Many new formats added (client_session, client_last_session, etc.)
+* Control mode, which is a way for a client to send tmux commands.
+ Currently more useful to users of iterm2.
+* resize-pane learnt '-x' and '-y' for absolute pane sizing.
+* Config file loading now reports errors from all files which are loaded via
+ the 'source-file' command.
+* 'copy-pipe' mode command to copy selection and pipe the selection to a
+ command.
+* Panes can now emit focus notifications for certain applications
+ which use those.
+* run-shell and if-shell now accept formats.
+* resize-pane learnt '-Z' for zooming a pane temporarily.
+* new-session learnt '-A' to make it behave like attach-session.
+* set-option learnt '-o' to prevent setting an option which is already set.
+* capture-pane and show-options learns '-q' to silence errors.
+* New command 'wait-for' which blocks a client until woken up again.
+* Resizing panes will now reflow the text inside them.
+* Lots and lots of bug fixes, fixing memory-leaks, etc.
+* Various manpage improvements.
+
+CHANGES FROM 1.6 TO 1.7, 13 October 2012
+
+* tmux configuration files now support line-continuation with a "\" at the
+ end of a line.
+* New option status-position to move the status line to the top or bottom of
+ the screen.
+* Enforce history-limit option when clearing the screen.
+* Give each window a unique id, like panes but prefixed with @.
+* Add pane id to each pane in layout description (while still accepting
+ the old form).
+* Provide defined ways to set the various default-path possibilities: ~
+ for home directory, . for server start directory, - for session start
+ directory and empty for the pane's working directory (the default). All
+ can also be used as part of a relative path (eg -/foo). Also provide -c
+ flags to neww and splitw to override default-path setting.
+* Add -l flag to send-keys to send input literally (without translating
+ key names).
+* Allow a single option to be specified to show-options to show just that
+ option.
+* New command "move-pane" (like join-pane but allows the same window).
+* join-pane and move-pane commands learn "-b" option to place the pane to
+ the left or above.
+* Support for bracketed-paste mode.
+* Allow send-keys command to accept hex values.
+* Add locking around "start-server" to avoid race-conditions.
+* break-pane learns -P/-F arguments for display formatting.
+* set-option learns "-q" to make it quiet, and not print out anything.
+* copy mode learns "wrap-search" option.
+* Add a simple form of output rate limiting by counting the number of
+ certain C0 sequences (linefeeds, backspaces, carriage returns) and if it
+ exceeds a threshold (current default 250/millisecond), start to redraw
+ the pane every 100 milliseconds instead of making each change as it
+ comes. Two configuration options - c0-change-trigger and
+ c0-change-interval.
+* find-window learns new flags: "-C", "-N", "-T" to match against either or
+ all of a window's content, name, or title. Defaults to all three options
+ if none specified.
+* find-window automatically selects the appropriate pane for the found
+ matches.
+* show-environment can now accept one option to show that environment value.
+* Exit mouse mode when end-of-screen reached when scrolling with the mouse
+ wheel.
+* select-layout learns -u and -U for layout history stacks.
+* kill-window, detach-client, kill-session all learn "-a" option for
+ killing all but the current thing specified.
+* move-window learns "-r" option to renumber window sequentially in a
+ session.
+* New session option "renumber-windows" to automatically renumber windows in
+ a session when a window is closed. (see "move-window -r").
+* Only enter copy-mode on scroll up.
+* choose-* and list-* commands all use "-F" for format specifiers.
+* When spawning external commands, the value from the "default-shell" option
+ is now used, rather than assuming /bin/sh.
+* New choose-tree command to render window/sessions as a tree for selection.
+* display-message learns new format options.
+* For linked-windows across sessions, all flags for that window are now
+ cleared across sessions.
+* Lots and lots of bug fixes, fixing memory-leaks, etc.
+* Various manpage improvements.
+
+CHANGES FROM 1.5 TO 1.6, 23 January 2012
+
+* Extend the mode-mouse option to add a third choice which means the mouse
+ does not enter copy mode.
+* Add a -r flag to switch-client to toggle the client read-only flag.
+* Add pane-base-index option.
+* Support \ for line continuation in the configuration file.
+* Framework for more powerful formatting of command output and use it for
+ list-{panes,windows,sessions}. This allows more descriptive replacements
+ (such as #{session_name}) and conditionals.
+* Mark dead panes with some text saying they are dead.
+* Reject $SHELL if it is not a full path.
+* Add -S option to refresh-client to redraw status line.
+* Add an else clause for if-shell.
+* Try to resolve relative paths for loadb and saveb (first, using client
+ working directory, if any, then default-path or session working directory).
+* Support for \e[3J to clear the history and send the corresponding
+ terminfo code (E3) before locking.
+* When in copy mode, make repeat count indicate buffer to replace, if used.
+* Add screen*:XT to terminal-overrides for tmux-in-tmux.
+* Status-line message attributes added.
+* Move word-separators to be a session rather than window option.
+* Change the way the working directory for new processes is discovered. If
+ default-path isn't empty, it is used. Otherwise, if a new window is created
+ from the command-line, the working directory of the client is used. If not,
+ platform specific code is used to retrieve the current working directory
+ of the process in the active pane. If that fails, the directory where the
+ session was created is used, instead.
+* Do not change the current pane if both mouse-select-{pane,window} are
+ enabled.
+* Add \033[s and \033[u to save and restore cursor position.
+* Allow $HOME to be used as default-path.
+* Add CNL and CPL escape sequences.
+* Calculate last position correctly for UTF-8 wide characters.
+* Add an option allow-rename to disable the window rename escape sequence.
+* Attributes for each type of status-line alert (ie bell, content and
+ activity) added. Therefore, remove the superfluous options
+ window-status-alert-{attr,bg,fg}.
+* Add a -R flag to send-keys to reset the terminal.
+* Add strings to allow the aixterm bright colours to be used when
+ configuring colours.
+* Drop the ability to have a list of keys in the prefix in favour of two
+ separate options, prefix and prefix2.
+* Flag -2 added to send-prefix to send the secondary prefix key.
+* Show pane size in top right of display panes mode.
+* Some memory leaks plugged.
+* More command-prompt editing improvements.
+* Various manpage improvements.
+* More Vi mode improvements.
+
+CHANGES FROM 1.4 TO 1.5, 09 July 2011
+
+* Support xterm mouse modes 1002 and 1003.
+* Change from a per-session stack of buffers to one global stack. This renders
+ copy-buffer useless and makes buffer-limit now a server option.
+* Fix most-recently-used choice by avoiding reset the activity timer for
+ unattached sessions every second.
+* Add a -P option to new-window and split-window to print the new window or
+ pane index in target form (useful to pass it into other commands).
+* Handle a # at the end of a replacement string (such as status-left)
+ correctly.
+* Support for UTF-8 mouse input (\033[1005h) which was added in xterm 262.
+ If the new mouse-utf8 option is on, UTF-8 mouse input is enabled for all
+ UTF-8 terminals. The option defaults to on if LANG etc are set in the same
+ manner as the utf8 option.
+* Support for HP-UX.
+* Accept colours of the hex form #ffffff and translate to the nearest from the
+ xterm(1) 256-colour set.
+* Clear the non-blocking IO flag (O_NONBLOCK) on the stdio file descriptors
+ before closing them (fixes things like "tmux ls && cat").
+* Use TMPDIR if set.
+* Fix next and previous session functions to actually work.
+* Support -x and -y for new-session to specify the initial size of the window
+ if created detached with -d.
+* Make bind-key accept characters with the top-bit-set and print them as octal.
+* Set $TMUX without the session when background jobs are run.
+* Simplify the way jobs work and drop the persist type, so all jobs are
+ fire-and-forget.
+* Accept tcgetattr/tcsetattr(3) failure, fixes problems with fatal() if the
+ terminal disappears while locked.
+* Add a -P option to detach to HUP the client's parent process (usually causing
+ it to exit as well).
+* Support passing through escape sequences to the underlying terminal by using
+ DCS with a "tmux;" prefix.
+* Prevent tiled producing a corrupt layout when only one column is needed.
+* Give each pane created in a tmux server a unique id (starting from 0), put it
+ in the TMUX_PANE environment variable and accept it as a target.
+* Allow a start and end line to be specified for capture-pane which may be
+ negative to capture part of the history.
+* Add -a and -s options to lsp to list all panes in the server or session
+ respectively. Likewise add -s to lsw.
+* Change -t on display-message to be target-pane for the #[A-Z] replacements
+ and add -c as target-client.
+* The attach-session command now prefers the most recently used unattached
+ session.
+* Add -s option to detach-client to detach all clients attached to a session.
+* Add -t to list-clients.
+* Change window with mouse wheel over status line if mouse-select-window is on.
+* When mode-mouse is on, automatically enter copy mode when the mouse is
+ dragged or the mouse wheel is used. Also exit copy mode when the mouse wheel
+ is scrolled off the bottom.
+* Provide #h character pair for short hostname (no domain).
+* Don't use strnvis(3) for the title as it breaks UTF-8.
+* Use the tsl and fsl terminfo(5) capabilities to update terminal title and
+ automatically fill them in on terminals with the XT capability (which means
+ their title setting is xterm-compatible).
+* Add a new option, mouse-resize-pane. When on, panes may be resized by
+ dragging their borders.
+* Fix crash by resetting last pane on {break,swap}-pane across windows.
+* Add three new copy-mode commands - select-line, copy-line, copy-end-of-line.
+* Support setting the xterm clipboard when copying from copy mode using the
+ xterm escape sequence for the purpose (if xterm is configured to allow it).
+* Support xterm(1) cursor colour change sequences through terminfo(5) Cc
+ (set) and Cr (reset) extensions.
+* Support DECSCUSR sequence to set the cursor style with two new terminfo(5)
+ extensions, Cs and Csr.
+* Make the command-prompt custom prompts recognize the status-left option
+ character pairs.
+* Add a respawn-pane command.
+* Add a couple of extra xterm-style keys that gnome terminal provides.
+* Allow the initial context on prompts to be set with the new -I option to
+ command-prompt. Include the current window and session name in the prompt
+ when renaming and add a new key binding ($) for rename session.
+* Option bell-on-alert added to trigger the terminal bell when there is an
+ alert.
+* Change the list-keys format so that it shows the keys using actual tmux
+ commands which should be able to be directly copied into the config file.
+* Show full targets for lsp/lsw -a.
+* Make confirm-before prompt customizable with -p option like command-prompt
+ and add the character pairs #W and #P to the default kill-{pane,window}
+ prompts.
+* Avoid sending data to suspended/locked clients.
+* Small memory leaks in error paths plugged.
+* Vi mode improvements.
+
+CHANGES FROM 1.3 TO 1.4, 27 December 2010
+
+* Window bell reporting fixed.
+* Show which pane is active in the list-panes output.
+* Backoff reworked.
+* Prevent the server from dying when switching into copy mode when already
+ in a different mode.
+* Reset running jobs when the status line is enabled or disabled.
+* Simplify xterm modifier detection.
+* Avoid crashing in copy mode if the screen size is too small for the
+ indicator.
+* Flags -n and -p added to switch-client.
+* Use UTF-8 line drawing characters on UTF-8 terminals, thus fixing some
+ terminals (eg putty) which disable the vt100 ACS mode switching sequences
+ in UTF-8 mode. On terminals without ACS, use ASCII equivalents.
+* New server option exit-unattached added.
+* New session option destroy-unattached added.
+* Fall back on normal session choice method if $TMUX exists but is invalid
+ rather than rejecting.
+* Mark repeating keys with "(repeat)" in the key list.
+* When removing a pane, don't change the active pane unless the active pane
+ is actually the one being removed.
+* New command last-pane added.
+* AIX fixes.
+* Flag -a added to unbind-key.
+* Add XAUTHORITY to update-environment.
+* More info regarding window and pane flags is now shown in list-*.
+* If VISUAL or EDITOR contains "vi" configure mode-keys and status-key to vi.
+* New window option monitor-silence and session option visual-silence added.
+* In the built-in layouts distribute the panes more evenly.
+* Set the default value of main-pane-width to 80 instead of 81.
+* Command-line flag -V added.
+* Instead of keeping a per-client prompt history make it global.
+* Fix rectangle copy to behave like emacs (the cursor is not part of the
+ selection on the right edge but on the left it is).
+* Flag -l added to switch-client.
+* Retrieve environment variables from the global environment rather than
+ getenv(3), thus allowing them to be updated during the configuration file.
+* New window options other-pane-{height,width} added.
+* More minor bugs fixed and manpage improvements.
+
+CHANGES FROM 1.2 TO 1.3, 18 July 2010
+
+* New input parser.
+* Flags to move through panes -UDLR added to select-pane.
+* Commands up-pane, and down-pane removed, since equivalent behaviour is now
+ available through the target flag (-t:+ and -t:-).
+* Jump-forward/backward in copy move (based on vi's F, and f commands).
+* Make paste-buffer accept a pane as a target.
+* Flag -a added to new-window to insert a window after an existing one, moving
+ windows up if necessary.
+* Merge more mode into copy mode.
+* Run job commands explicitly in the global environment (which can be modified
+ with setenv -g), rather than with the environment tmux started with.
+* Use the machine's hostname as the default title, instead of an empty string.
+* Prevent double free if the window option remain-on-exit is set.
+* Key string conversions rewritten.
+* Mark zombie windows as dead in the choose-window list.
+* Tiled layout added.
+* Signal handling reworked.
+* Reset SIGCHLD after fork to fix problems with some shells.
+* Select-prompt command removed. Therefore, bound ' to command-prompt -p index
+ "select-window -t:%%" by default.
+* Catch SIGHUP and terminate if running as a client, thus avoiding clients from
+ being left hanging around when, for instance, a SSH session is disconnected.
+* Solaris 9 fixes (such as adding compat {get,set}env(3) code).
+* Accept none instead of default for attributes.
+* Window options window-status-alert-{alert,bg,fg} added.
+* Flag -s added to the paste-buffer command to specify a custom separator.
+* Allow dragging to make a selection in copy mode if the mode-mouse option is
+ set.
+* Support the mouse scroll wheel.
+* Make pipe-pane accept special character sequences (eg #I).
+* Fix problems with window sizing when starting tmux from .xinitrc.
+* Give tmux sockets (but not the containing folder) group permissions.
+* Extend the target flags (ie -t) to accept an offset (for example -t:+2), and
+ make it wrap windows, and panes.
+* New command choose-buffer added.
+* New server option detach-on-destroy to set what happens to a client when the
+ session it is attached to is destroyed. If on (default), the client is
+ detached. Otherwise, the client is switched to the most recently active of
+ the remaining sessions.
+* The commands load-buffer, and save-buffer now accept a dash (-) as the file
+ to read from stdin, or write to stdout.
+* Custom layouts added.
+* Additional code reduction, bug fixes, and manpage enhancements.
+
+CHANGES FROM 1.1 TO 1.2, 10 March 2010
+
+* Switch to libevent.
+* Emulate the ri (reverse index) capability, ergo allowing tmux to at least
+ start on Sun consoles (TERM=sun, or sun-color).
+* Assign each entry a number, or lowercase letter in choose mode, and accept
+ that as a shortcut key.
+* Permit top-bit-set characters to be entered in the status line.
+* Mark no-prefix keys with (no prefix), rather than [] in list-keys.
+* New command show-messages (alias showmsgs), and new session option
+ message-limit, to show a per-client log of status lines messages up to the
+ number defined by message-limit.
+* Do not interpret #() for display-message to avoid leaking commands.
+* New window options window-status-format, and window-status-current-format to
+ control the format of each window in the status line.
+* Add a -p flag to display-message to print the output, instead of displaying
+ it in the status line.
+* Emulate il1, dl1, ich1 to run with vt100 feature set.
+* New command capture-pane (alias capturep) to copy the entire pane contents
+ to a paste buffer.
+* Avoid duplicating code by adding a -w flag to set-option, and show-options to
+ set, and show window options. The commands set-window-option, and
+ show-window-options are now aliases.
+* Panes can now be referred to as top, bottom, top-left, etc.
+* Add server-wide options, which can be set with set-option -s, and shown with
+ show-options -s.
+* New server option quiet (like -q from the command line).
+* New server option escape-time to set the timeout used to detect if escapes
+ are alone, part of a function key, or meta sequence.
+* New session options pane-active-border-bg, pane-active-border-fg,
+ pane-border-bg, and pane-border-fg to set pane colours.
+* Make split-window accept a pane target, instead of a window.
+* New command join-pane (alias joinp) to split, and move an existing pane into
+ the space (the opposite of break-pane), thus simplifying calls to
+ split-window, followed by move-window.
+* Permit S- prefix on keys for shift when the terminal/terminfo supports them.
+* Window targets (-t flag) can now refer to the last window (!), next (+), and
+ previous (-) window by number.
+* Mode keys to jump to the bottom/top of history, end of the next word, scroll
+ up/down, and reverse search in copy mode.
+* New session option display-panes-active-colour to display the active pane in
+ a different colour with the display-panes command.
+* Read the socket path from $TMUX if it's present, and -L, and -S are not
+ given.
+* Vi-style mode keys B, W, and E to navigate between words in copy mode.
+* Start in more mode when configuration file errors are detected.
+* Rectangle copy support added.
+* If attach-session was specified with the -r flag, make the client read-only.
+* Per-window alternate-screen option.
+* Make load-buffer work with FIFOs.
+* New window option word-separators to set the characters considered as word
+ separators in copy mode.
+* Permit keys in copy mode to be prefixed by a repeat count, entered with [1-9]
+ in vi mode, or M-[1-9] in emacs mode.
+* utf8 improvements.
+* As usual, additional code reduction, bug fixes, and manpage enhancements.
+
+CHANGES FROM 1.0 TO 1.1, 05 November 2009
+
+* New run-shell (alias run) command to run an external command without a
+ window, capture it's stdout, and send it to output mode.
+* Ability to define multiple prefix keys.
+* Internal locking mechanism removed. Instead, detach each client and run the
+ external command specified in the new session option lock-command (by default
+ lock -np), thus allowing the system password to be used.
+* set-password command, and -U command line flag removed per the above change.
+* Add support for -c command line flag to execute a shell command.
+* New lock-client (alias lockc), and lock-session (alias locks) commands to
+ lock a particular client, or all clients attached to a session.
+* Support C-n/C-p/C-v/M-v with emacs keys in choice mode.
+* Use : for goto line rather than g in vi mode.
+* Try to guess which client to use when no target client was specified. Finds
+ the current session, and if only one client is present, use it. Otherwise,
+ return the most recently used client.
+* Make C-Down/C-Up in copy mode scroll the screen down/up one line without
+ moving the cursor.
+* Scroll mode superseded by copy mode.
+* New synchronize-panes window option to send all input to all other panes in
+ the same window.
+* New lock-server session option to lock, when off (on by default), each
+ session when it has been idle for the lock-after-time setting. When on, the
+ entire server locks when all sessions have been idle for their individual
+ lock-after-time setting.
+* Add support for grouped sessions which have independent name, options,
+ current window, but where the linked windows are synchronized (ie creating,
+ killing windows are mirrored between the sessions). A grouped session may be
+ created by passing -t to new-session.
+* New mouse-select-pane session option to select the current pane with the
+ mouse.
+* Queue, and run commands in the background for if-shell, status-left,
+ status-right, and #() by starting each once every status-interval. Adds the
+ capability to call some programs which would previously cause the server to
+ hang (eg sleep/tmux). It also avoids running commands excessively (ie if used
+ multiple times, it will be run only once).
+* When a window is zombified and automatic-rename is on, append [dead] to the
+ name.
+* Split list-panes (alias lsp) off from list-windows.
+* New pipe-pane (alias pipep) to redirect a pane output to an external command.
+* Support for automatic-renames for Solaris.
+* Permit attributes to be turned off in #[] by prefixing with no (eg nobright).
+* Add H/M/L in vi mode, and M-R/M-r in emacs to move the cursor to the top,
+ middle, and bottom of the screen.
+* -a option added to kill-pane to kill all except current pane.
+* The -d command line flag is now gone (can be replaced by terminal-overrides).
+ Just use op/AX to detect default colours.
+* input/tty/utf8 improvements.
+* xterm-keys rewrite.
+* Additional code reduction, and bug fixes.
+
+CHANGES FROM 0.9 TO 1.0, 20 September 2009
+
+* Option to alter the format of the window title set by tmux.
+* Backoff for a while after multiple incorrect password attempts.
+* Quick display of pane numbers (C-b q).
+* Better choose-window, choose-session commands and a new choose-client command.
+* Option to request multiple responses when using command-prompt.
+* Improved environment handling.
+* Combine wrapped lines when pasting.
+* Option to override terminal settings (terminal-overrides).
+* Use the full range of ACS characters for drawing pane separator lines.
+* Customisable mode keys.
+* Status line colour options, with embedded colours in status-left/right, and
+ an option to centre the window list.
+* Much improved layouts, including both horizontal and vertical splitting.
+* Optional visual bell, activity and content indications.
+* Set the utf8 and status-utf8 options when the server is started with -u.
+* display-message command to show a message in the status line, by default some
+ information about the current window.
+* Improved current process detection on NetBSD.
+* unlink-window -k is now the same as kill-window.
+* attach-session now works from inside tmux.
+* A system-wide configuration file, /etc/tmux.conf.
+* A number of new commands in copy mode, including searching.
+* Panes are now specified using the target (-t) notation.
+* -t now accepts fnmatch(3) patterns and looks for prefixes.
+* Translate \r into \n when pasting.
+* Support for binding commands to keys without the prefix key
+* Support for alternate screen (terminfo smcup/rmcup).
+* Maintain data that goes off screen after reducing the window size, so it can
+ be restored when the size is increased again.
+* New if-shell command to test a shell command before running a tmux command.
+* tmux now works as the shell.
+* Man page reorganisation.
+* Many minor additions, much code tidying and several bug fixes.
+
+CHANGES FROM 0.8 TO 0.9, 01 July 2009
+
+* Major changes to build infrastructure: cleanup of makefiles and addition
+ of a configure script.
+* monitor-content window option to monitor a window for a specific fnmatch(3)
+ pattern. The find-window command also now accepts fnmatch(3) patterns.
+* previous-layout and select-layout commands, and a main-horizontal layout.
+* Recreate the server socket on SIGUSR1.
+* clear-history command.
+* Use ACS line drawing characters for pane separator lines.
+* UTF-8 improvements, and code to detect UTF-8 support by looking at
+ environment variables.
+* The resize-pane-up and resize-pane-down commands are now merged together
+ into a new resize-pane command with -U and -D flags.
+* confirm-before command to request a yes/no answer before executing dangerous
+ commands.
+* Status line bug fixes, support for UTF-8 (status-utf8 option), and a key to
+ paste from the paste buffer.
+* Support for some additional escape sequences and terminal features, including
+ better support for insert mode and tab stops.
+* Improved window resizing behaviour, modelled after xterm.
+* Some code reduction and a number of miscellaneous bug fixes.
+
+================================================================================
+
+On 01 June 2009, tmux was imported into the OpenBSD base system. From this date
+onward changes are logged as part of the normal CVS commit message to either
+OpenBSD or SourceForge CVS. This file will be updated to contain a summary of
+major changes with each release, and to mention important configuration or
+command syntax changes during development.
+
+The list of older changes is below.
+
+================================================================================
+
+21 May 2009
+
+* stat(2) files before trying to load them to avoid problems, for example
+ with "source-file /dev/zero".
+
+19 May 2009
+
+* Try to guess if the window is UTF-8 by outputting a three-byte UTF-8 wide
+ character and seeing how much the cursor moves. Currently tries to figure out
+ if this works by some stupid checks on the terminal, these need to be
+ rethought. Also might be better using a width 1 character rather than width 2.
+* If LANG contains "UTF-8", assume the terminal supports UTF-8, on the grounds
+ that anyone who configures it probably wants UTF-8. Not certain if this is
+ a perfect idea but let's see if it causes any problems.
+* New window option: monitor-content. Searches for a string in a window and if
+ it matches, highlight the status line.
+
+18 May 2009
+
+* main-horizontal layout and main-pane-height option to match vertical.
+* New window option main-pane-width to set the width of the large left pane with
+ main-vertical (was left-vertical) layout.
+* Lots of layout cleanup. manual layout is now manual-vertical.
+
+16 May 2009
+
+* select-layout command and a few default key bindings (M-0, M-1, M-2, M-9) to
+ select layouts.
+* Recreate server socket on SIGUSR1, per SF feature request 2792533.
+
+14 May 2009
+
+* Keys in status line (p in vi mode, M-y in emacs) to paste the first line
+ of the upper paste buffer. Suggested by Dan Colish.
+* clear-history command to clear a pane's history.
+* Don't force wrapping with \n when asked, let the cursor code figure it out.
+ Should fix terminals which use this to detect line breaks.
+* Major cleanup and restructuring of build infrastructure. Still separate files
+ for GNU and BSD make, but they are now hugely simplified at the expense of
+ adding a configure script which must be run before make. Now build and
+ install with:
+
+ $ ./configure && make && sudo make install
+
+04 May 2009
+
+* Use ACS line drawing characters for pane separator lines.
+
+30 April 2009
+
+* Support command sequences without a space before the semicolon, for example
+ "neww; neww" now works as well as "neww ; neww". "neww;neww" is still an
+ error.
+* previous-layout command.
+* Display the layout name in window lists.
+* Merge resize-pane-up and resize-pane-down into resize-pane with -U and -D
+ flags.
+
+29 April 2009
+
+* Get rid of compat/vis.* - only one function was used which is easily
+ replaced,and less compat code == good.
+
+27 April 2009
+
+* Avoid using the prompt history when the server is locked, and prevent any
+ input entered from being added to the client's prompt history.
+* New command, confirm-before (alias confirm), which asks for confirmation
+ before executing a command. Bound "&" and "x" by default to confirm-before
+ "kill-window" and confirm-before "kill-pane", respectively.
+
+23 April 2009
+
+* Support NEL, yet another way of making newline. Fixes the output from some
+ Gentoo packaging thing. Reported by someone on SF then logs that allowed a
+ fix sent by tcunha.
+* Use the xenl terminfo flag to detect early-wrap terminals like the FreeBSD
+ console. Many thanks for a very informative email from Christian Weisgerber.
+
+21 April 2009
+
+* tmux 0.8 released.
+
+17 April 2009
+
+* Remove the right number of characters from the buffer when escape then
+ a cursor key (or other key prefixed by \033) is pressed. Reported by
+ Stuart Henderson.
+
+03 April 2009
+
+* rotate-window command. -U flag (default) for up, -D flag for down.
+
+02 April 2009
+
+* Change scroll/pane redraws to only redraw the single pane affected rather
+ than the entire window.
+* If redrawing the region would mean redrawing > half the pane, just schedule
+ to redraw the entire window. Also add a flag to skip updating the window any
+ further if it is scheduled to be redrawn. This has the effect of batching
+ multiple redraws together.
+
+01 April 2009
+
+* Basic horizontal splitting and layout management. Still some redraw and other
+ issues - particularly, don't mix with manual pane resizing, be careful when
+ viewing from multiple clients and don't expect shell windows to redraw very
+ well after the layout is changed; generally cycling the layout a few times
+ will fix most problems. Getting this in for testing while I think about how
+ to deal with manual mode.
+
+ Split window as normal and cycle the layouts with C-b space. Some of the
+ layouts will work better when swap-pane comes along.
+
+31 March 2009
+
+* AIX port, thanks to cmihai for access to a box. Only tested on 6.1 with xlc
+ 10.1 (make sure CC is set). Needs GNU make and probably ncurses (didn't try
+ plain curses). Also won't build with DEBUG, so comment the FDEBUG=1 line in
+ GNUmakefile.
+* Draw a vertical line on the right when the window size is less than the
+ terminal size. This is partly to shake out any horizontal limit bugs on the
+ way to horizontal splitting/pane tiling. Currently a bit slow since it has to
+ do a lot of redrawing but hopefully that will improve as I get some better
+ ideas for how to do it.
+* Fix remaining problems with copy and paste and UTF-8.
+
+28 March 2009
+
+* Better UTF-8 support, including combined characters. Unicode data is now
+ stored as UTF-8 in a separate array, the code does a lookup into this every
+ time it gets to a UTF-8 cell. Zero width characters are just appended onto
+ the UTF-8 data for the previous cell. This also means that almost no bytes
+ extra are wasted non-Unicode data (yay).
+
+ Still some oddities, such as copy mode skips over wide characters in a
+ strange way, and the code could do with some tidying.
+* Key repeating is now a property of the key binding not of the command.
+ Repeat is turned on when the key is bound with the -r flag to bind-key.
+ next/previous-window no longer repeat by default as it turned out to annoy
+ me.
+
+27 March 2009
+
+* Clear using ED when redrawing the screen. I foolishly assumed using spaces
+ would be equivalent and terminals would pick up on this, but apparently not.
+ This fixes copy and paste in xterm/rxvt.
+* Sockets in /tmp are now created in a subdirectory named, tmux-UID, eg
+ tmux-1000. The default socket is thus /tmp/tmux-UID/default. To start a
+ separate server, the new -L command line option should be used: this creates
+ a socket in the same directory with a different name ("-L main" will create
+ socket called "main"). -S should only be used to place the socket outside
+ /tmp. This makes sockets a little more secure and a bit more convenient to
+ use multiple servers.
+
+21 March 2009
+
+* New session flag "set-remain-on-exit" to set remain-on-exit flag for new
+ windows created in that session (like "remain-by-default" used to do). Not
+ perfectly happy about this, but until I can think of a good way to introduce
+ it generically (maybe a set of options in the session) this will do. Fixes
+ SF request 2527847.
+
+07 March 2009
+
+* Support for 88 colour terminals.
+* break-pane command to create a new window using an existing pane.
+
+02 March 2009
+
+* Make escape key timer work properly so escape+key can be used without
+ lightning fast key presses.
+
+13 February 2009
+
+* Redo mode keys slightly more cleanly and apply them to command prompt
+ editing. vi or emacs mode is controlled by the session option status-keys.
+
+12 February 2009
+
+* Looking up argv[0] is expensive, so just use p_comm for the window name which
+ is good enough. Also increase name update time to 500 ms.
+
+11 February 2009
+
+* Only use ri when actually at the top of the screen; just move the cursor up
+ otherwise.
+* FreeBSD's console wraps lines at $COLUMNS - 1 rather than $COLUMNS (the
+ cursor can never be beyond $COLUMNS - 1) and does not appear to support
+ changing this behaviour, or any of the obvious possibilities (turning off
+ right margin wrapping, insert mode). This is irritating, most notably because
+ it impossible to write to the very bottom-right of the screen without
+ scrolling. To work around this, if built on FreeBSD and run with a "cons"
+ $TERM, the bottom-right cell on the screen is omitted.
+* Emulate scroll regions (slowly) to support the few terminals which don't have
+ it (some of which don't really have any excuse).
+
+10 February 2009
+
+* No longer redraw the status line every status-interval unless it has actually
+ changed.
+
+08 February 2009
+
+* Don't treat empty arguments ("") differently when parsing configuration
+ file/command prompt rather than command line.
+* tmux 0.7 released.
+
+03 February 2009
+
+* New command, copy-buffer (alias copyb), to copy a session paste buffer to
+ another session.
+
+01 February 2009
+
+* The character pair #(command) may now contain (escaped) right parenthesis.
+
+30 January 2009
+
+* . now bound to "command-prompt 'move-window %%'" by default, from joshe.
+
+29 January 2009
+
+* Window options to set status line fg, bg and attributes for a single
+ window. Options are: window-status-fg, window-status-bg,
+ window-status-attr. Set to "default" to use the session status colours.
+
+ This allows quite neat things like:
+
+ $ cat ~/bin/xssh
+ #!/bin/sh
+
+ if [ ! -z "$TMUX" ]; then
+ case "$1" in
+ natalya)
+ tmux setw window-status-fg red >/dev/null
+ ;;
+ natasha)
+ tmux setw window-status-fg yellow >/dev/null
+ ;;
+ esac
+ fi
+ ssh "$@"
+ [ ! -z "$TMUX" ] && tmux setw -u window-status-fg >/dev/null
+ $ alias ssh="~/bin/xssh"
+
+* Support #(command) in status-left, and status-right, which is displayed as
+ the first line of command's output (e.g. set -g status-right
+ "#(whoami)@#(hostname -s)"). Commands with )s aren't supported.
+
+28 January 2009
+
+* Support mouse in copy mode to move cursor. Can't do anything else at the
+ moment until other mouse modes are handled.
+* Better support for at least the most common variant of mouse input: parse it
+ and adjust for different panes. Also support mouse in window/session choice
+ mode.
+
+27 January 2009
+
+* Bring back the fancy window titles with session/window names: it is easy to
+ work around problems with elinks (see FAQ).
+* -u flag to scroll-mode and copy-mode to start scrolled one page
+ up. scroll-mode -u is bound to prefix,page-up (ppage) by default.
+* Allow status, mode and message attributes to be changed by three new options:
+ status-attr, mode-attr, message-attr. A comma-separated list is accepted
+ containing: bright, dim, underscore, blink, reverse, hidden, italics, for
+ example:
+
+ set -g status-attr bright,blink
+
+ From Josh Elsasser, thanks!
+
+26 January 2009
+
+* Be more clever about picking the right process to create the window name.
+* Don't balls up the terminal on UTF-8 combined characters. Don't support them
+ properly either - they are just discarded for the moment.
+
+25 January 2009
+
+* load-buffer command
+
+23 January 2009
+
+* Use reverse colours rather than swapping fg and bg for message, mode and
+ status line. This makes these usable on black and white terminals.
+* Better error messages when creating a session or window fails.
+* Oops. Return non-zero on error. Reported by Will Maier.
+
+21 January 2009
+
+* Handle SIGTERM (and kill-server which uses it), a bit more neatly - tidy
+ up properly and print a nicer message. Same effect though :-).
+* new-window now supports -k to kill target window if it exists.
+* Bring back split-window -p and -l options to specify the height a percentage
+ or as a number of lines.
+* Make window and session choice modes allow you to choose items in vi keys
+ mode (doh!). As a side-effect, this makes enter copy selection (as well
+ as C-w/M-w) when using emacs keys in copy mode. Reported by merdely.
+
+20 January 2009
+
+* Darwin support for automatic-rename from joshe; Darwin doesn't seem to have
+ a sane method of getting argv[0] and searching for the precise insane way
+ is too frustrating, so this just uses the executable name.
+* Try to change the window title to match the command running it in. This is
+ done by reading argv[0] from the process group leader of the group that owns
+ the tty (tcgetpgrp()). This can't be done portably so some OS-dependent code
+ is introduced (ugh); OpenBSD, FreeBSD and Linux are supported at the moment.
+
+ A new window flag, automatic-rename, is available: if this is set to off, the
+ window name is not changed. Specifying a name with the new-window,
+ new-session or rename-window commands will automatically set this flag to off
+ for the window in question. To disable it entirely set the option to off
+ globally (setw -g automatic-rename off).
+
+19 January 2009
+
+* Fix various stupid issues when the status line is turned off. Grr.
+* Use reverse attributes for clock and cursor, otherwise they do not
+ appear on black and white terminals.
+* An error in a command sequence now stops execution of that sequence.
+ Internally, each command code now passes a return code back rather than
+ talking to the calling client (if any) directly.
+* attach-session now tries to start the server if it isn't already started - if
+ no sessions are created in .tmux.conf this will cause an error.
+* Clean up starting server by making initial client get a special socketpair.
+
+18 January 2009
+
+* Unbreak UTF-8.
+* -a flag to next-window and previous-window to select the next or previous
+ window with activity or bell. Bound to M-n and M-p.
+* find-window command to search window names, titles and visible content (but
+ not history) for a string. If only one is found, the window is selected
+ otherwise a choice list is shown. This (as with the other choice commands)
+ only works from a key. Bound to "f" by default.
+* Cleaned up command printing code, also enclose arguments with spaces in "s.
+* Added command sequences. These are entered by separating each argument by a ;
+ argument (spaces on both sides), for example:
+
+ lsk ; lsc
+
+ To use a literal ; as the argument prefix it with \, for example:
+
+ bind x lsk \; lsc
+
+ Commands are executed from left to right. Also note that command sequences do
+ not support repeat-time repetition unless all commands making up the sequence
+ support it.
+* suspend-client command to suspend a client. Don't try to background it
+ though...
+* Mark attached sessions in sessions lists. Suggested by Simon Kuhnle.
+
+17 January 2009
+
+* tmux 0.6 released.
+
+15 January 2009
+
+* Support #H for hostname and #S for session name in status-left/right.
+* Two new commands, choose-window and choose-session which work only when bound
+ to a key and allow the window or session to be selected from a list. These
+ are now bound to "w" and "s" instead of the list commands.
+
+14 January 2009
+
+* Rework the prefix-time stuff. The option is now called repeat-time and
+ defaults to 500 ms. It only applies to a small subset of commands, currently:
+ up-pane, down-pane, next-window, previous-window, resize-pane-up,
+ resize-pane-down. These are the commands for which it is obviously useful,
+ having it for everything else was just bloody annoying.
+* The alt-up and alt-down keys now resize a pane by five lines at a time.
+* switch-pane is now select-pane and requires -p to select a pane. The
+ "o" key binding is changed to down-pane.
+* up-pane and down-pane commands, bound to arrow up and down by default.
+* Multiple vertical window splitting. Minimum pane size is four lines, an
+ (unhelpful) error will be shown if attempting to split a window with less
+ that eight lines. If the window is resized, as many panes are shown as can
+ fit without reducing them below four lines. There is (currently!) not a way
+ to show a hidden pane without making the window larger.
+
+ Note the -p and -l options to split-window are now gone, these may reappear
+ once I think them through again.
+* Server locking on inactivity (lock-after-time) is now disabled by default.
+
+13 January 2009
+
+* kill-pane command.
+
+12 January 2009
+
+* command-prompt now accepts a single argument, a template string. Any
+ occurrences of %% in this string are replaced by whatever is entered at the
+ prompt and the result is executed as a command. This allows things like (now
+ bound by default):
+
+ bind , command-prompt "rename-window %%"
+
+ Or my favourite:
+
+ bind x command-prompt "split-window 'man %%'"
+
+* Option to set prefix time, allowing multiple commands to be entered without
+ pressing the prefix key again, so long as they each typed within this time of
+ each other.
+* Yet more hacks for key handling. Think it is just about working now.
+* Two commands, resize-pane-up and resize-pane-down to resize a pane.
+* Make the window pane code handle panes of different sizes, and add a -l
+ and -p arguments to split-window to specify the new window size in lines
+ or as a percentage.
+
+11 January 2009
+
+* Vertical window splitting. Currently can only split a window into two panes.
+ New split-window command splits (bound to ") and switch-pane command (bound to
+ o) switches between panes.
+
+ close-pane, swap-pane commands are to follow. Also to come are pane resizing,
+ >2 panes, the ability to break a pane out to a full window and vice versa and
+ possibly horizontal splitting.
+
+ Panes are subelements of windows rather than being windows in their own
+ right. I tried to make them windows (so the splitting was at the session or
+ client level) but this rapidly became very complex and invasive. So in the
+ interests of having something working, I just made it so each window can have
+ two child processes instead of one (and it still took me 12 hours straight
+ coding). Now the concept is proven and much of the support code is there,
+ this may change in future if more flexibility is needed.
+* save-buffer command, from Tiago Cunha.
+
+10 January 2009
+
+* New option, lock-after-time. If there is no activity in the period specified
+ by this option (in seconds), tmux will lock the server. Default is 1800 (30
+ minutes), set to 0 to disable.
+* Server locking. Two new commands: set-password to set a password (a
+ preencrypted password may be specified with -c); and lock-server to lock the
+ server until the password is entered. Also an additional command line flag,
+ -U, to unlock from the shell. The default password is blank (any password
+ accepted). If specifying an encrypted password from encrypt(1) in .tmux.conf
+ with -c, don't forget to enclose it in single-quotes (') to prevent shell
+ variable expansion.
+* If a window is created from the command line, tmux will now use the same
+ current working directory for the new process. A new default-path option to
+ sets the working directory for processes created from keys or interactively
+ from the prompt.
+* New mode to display a large clock. Entered with clock-mode command (bound to
+ C-b t by default); two window options: clock-mode-colour and clock-mode-style
+ (12 or 24). This will probably be used as the basis for window locking.
+* New command, server-info, to show some server information and terminal
+ details.
+
+09 January 2009
+
+* Stop using ncurses variables and instead build a table of the codes we want
+ into an array for each terminal type. This makes the code a little more
+ untidy in places but gets rid of the awful global variables and calling
+ setterm all the time, and shoves all the ncurses-dependent mess into a single
+ file, tty-term.c. It also allows overriding single terminal codes, this is
+ used to fix rxvt on some platforms (where it is missing dch) and in future
+ may allow user customisation a la vim.
+* Update key handling code. Simplify, support ctrl properly and add a new
+ window option (xterm-keys) to output xterm key codes including ctrl and,
+ if available, alt and shift.
+
+08 January 2009
+
+* If built without DEBUG (the release versions), don't cause a fatal error if
+ the grid functions notice an input error, just log and ignore the
+ request. This might mean me getting shouted at less often when bugs kill
+ long-running sessions, at least in release versions.
+* Hopefully fix cursor out-of-bounds checking when writing to grid. When I
+ wrote the code I must have forgotten that the cursor can be one cell off the
+ right of the screen (yes, I know), so there were number of out-of-bounds/
+ overflow problems.
+
+07 January 2009
+
+* New flag to set and setw, -u, to unset an option (allowing it to inherit from)
+ the global options again.
+* Added more info messages for options changes.
+* A bit of tidying and reorganisation of options code.
+
+06 January 2009
+
+* Don't crash when backspacing if cursor is off the right of the screen,
+ reported by David Chisnall.
+* Complete words at any point inside command in prompt, also use option name
+ as well as command names.
+* Per-client prompt history of up to 100 items.
+* Use a splay tree for key bindings instead of an array. As a side-effect this
+ sorts them when listed.
+
+22 December 2008
+
+* Use the right keys for home and end.
+
+20 December 2008
+
+* Add vim mode for tmux configuration file to examples/, from Tiago Cunha.
+
+15 December 2008
+
+* New command, source-file (alias source), to load a configuration
+ file. Written by Tiago Cunha, many thanks.
+
+13 December 2008
+
+* Work around lack of dch. On Linux, the rxvt termcap doesn't have it (it is
+ lying, but we can't really start disbelieving termcaps...). This is a bit
+ horrible - I can see no way to do it without pretty much redrawing the whole
+ line, but it works...
+
+10 December 2008
+
+* glibc's getopt(3) is useless: it is not POSIX compliant without jumping
+ through non-portable hoops, and the method of resetting it is unclear (the
+ man page on my system says set optind to 1, but other sources say 0). So,
+ import OpenBSD's getopt_long.c into compat/ for use on Linux and use the
+ clearly documented optreset = optind = 1 method. This fixes some strange
+ issues with command parsing (getting the syntax wrong would prevent any
+ further commands being parsed).
+
+06 December 2008
+
+* Bring set/setw/show/showw into line with other commands. This means that by
+ default they now affect the current window (if any); the new -g flag must be
+ passed to set the global options. This changes the behaviour of set/show and
+ WILL BREAK CURRENT CONFIGURATIONS.
+
+ In summary, whether in the configuration file, the command prompt, or a key
+ binding, use -g to set a global option, use -t to specify a particular window
+ or session, or omit both to try and use the current window or session.
+
+ This makes set/show a bit of a pain but is the correct behaviour for
+ setw/showw and is the same as every other command, so we can put up with a
+ bit of pain for consistency.
+* Redo window options. They now work in the same way to session options with a
+ global options set. showw/setw commands now have similar syntax to show/set
+ (including the ability to use abbreviations).
+
+ PLEASE NOTE this includes the following configuration-breaking changes:
+
+ - remain-by-default is now GONE, use "setw -g remain-on-exit" to apply the
+ global window option instead;
+ - mode-keys is now a window option rather than session - use "setw [-g]
+ mode-keys" instead of set.
+
+ There are also some additions:
+
+ - message-fg and message-bg session options to control status line message
+ colours;
+ - mode-fg and mode-bg window options to set colours in window modes such as
+ copy mode.
+
+ The options code still a mess and now there is twice as much of it :-(.
+
+02 December 2008
+
+* Add support for including the window title in status-left or status-right
+ strings by including the character pair "#T". This may be prefixed with
+ a number to specify a maximum length, for example "#24T" to use at most
+ 24 characters of the title.
+* Introduce two new options, status-left-length and status-right-length,
+ control the maximum length of left and right components of the status bar.
+* elinks (and possibly others) bypass the terminal and talk directly to X to
+ restore the window title when exiting. tmux can't know about this particular
+ bit of stupidity so the title ends up strange - the prefix isn't terribly
+ important and elinks is quite useful so just get rid of it.
+
+27 November 2008
+
+* Tweaks to support Dragonfly.
+
+17 November 2008
+
+* tmux 0.5 released.
+
+16 November 2008
+
+* New window option: "utf8"; this must be on (it is off by default) for UTF-8
+ to be parsed. The global/session option "utf8-default" controls the setting
+ for new windows.
+
+ This means that by default tmux does not handle UTF-8. To use UTF-8 by
+ default it is necessary to a) "set utf8-default on" in .tmux.conf b) start
+ tmux with -u on any terminal which support UTF-8.
+
+ It seems a bit unnecessary for this to be a per-window option but that is
+ the easiest way to do it, and it can't do any harm...
+* Enable default colours if op contains \033[39;49m, based on a report from
+ fulvio ciriaco.
+
+12 November 2008
+
+* Keep stack of last windows rather than just most recent; based on a diff from
+ joshe.
+
+04 November 2008
+
+* Don't try to redraw status line when showing a prompt or message; if it does,
+ the status timer is never reset so it redraws on every loop. Spotted by
+ joshe.
+
+09 October 2008
+
+* Translate 256 colours into 16 if 256 is not available, same as screen does.
+* Better support for OSC command (only to set window title now), and also
+ support using APC for the same purpose (some Linux default shell profiles do
+ this).
+
+25 September 2008
+
+* Large internal rewrite to better support 256 colours and UTF-8. Screen data
+ is now stored as single two-way array of structures rather than as multiple
+ separate arrays. Also simplified a lot of code.
+
+ Only external changes are three new flags, -2, -d and -u, which force tmux to
+ assume the terminal supports 256 colours, default colours (useful for
+ xterm-256color which lacks the AX flag), or UTF-8 respectively.
+
+10 September 2008
+
+* Split off colour conversion code from screen code.
+
+09 September 2008
+
+* Initial UTF-8 support. A bit ugly and with a limit of 4096 UTF-8
+ characters per window.
+
+08 September 2008
+
+* 256 colour support. tmux attempts to autodetect the terminal by looking
+ both at what ncurses reports (usually wrong for xterm) and checking if
+ the TERM contains "256col". For xterm TERM=xterm-256color is needed (as
+ well as a build that support 256 colours); this seems to work for rxvt
+ as well. On non-256 colour terminals, high colours are translated to white
+ foreground and black background.
+
+28 August 2008
+
+* Support OS X/Darwin thanks to bsd-poll.c from OpenSSH. Also convert
+ from clock_gettime(2) to gettimeofday(2) as OS X doesn't support the
+ former; microsecond accuracy will have to be sufficient ;-).
+
+07 August 2008
+
+* Lose some unused/useless wrapper functions.
+
+25 July 2008
+
+* Shell variables may now be defined and used in configuration file. Define
+ variables with:
+
+ VAR=1
+
+ And use with:
+
+ renamew ${VAR}
+ renamew "x${VAR}x"
+
+ Also some other fixes to make, for example, "abc""abc" work similarly to
+ the shell.
+
+24 July 2008
+
+* Finally lose inconsistently-used SCREEN_DEF* defines.
+* If cursor mode is on, switch the arrow keys from \033[A to \033OA.
+* Support the numeric keypad in both application and numbers mode. This is
+ different from screen which always keeps it in application mode.
+
+19 July 2008
+
+* Unbreak "set status" - tmux thought it was ambiguous, reported by rivo nurges.
+
+02 July 2008
+
+* Split vi and emacs mode keys into two tables and add an option (mode-keys)
+ to select between them. Default is emacs, use,
+
+ tmux set mode-keys vi
+
+ to change to vi.
+
+ vi mode uses space to start selection, enter to copy selection and escape
+ to clear selection.
+
+01 July 2008
+
+* Protocol versioning. Clients which identify as a different version from the
+ server will be rejected.
+* tmux 0.4 released.
+
+29 June 2008
+
+* Zombie windows. These are not closed when the child process dies. May be
+ set for a window with the new "remain-on-exit" option; the default setting
+ of this flag for new windows may be set with the "remain-by-default" session
+ option.
+
+ A window may be restarted with the respawn-window command:
+
+ respawn-window [-k] [command]
+
+ If -k is given, any existing process running in the window is killed;
+ if command is omitted, the same command as when the window was first
+ created is used.
+
+27 June 2008
+
+* Handle nonexistent session or client to -t properly.
+
+25 June 2008
+
+* select-prompt command to allow a window to be selected at a prompt. Only
+ windows in the current session may be selected. Bound to ' by default.
+ Suggested by merdely.
+* move-window command. Requested by merdely.
+* Support binding alt keys (prefixed with M-). Change default to use
+ C- for ctrl keys (^ is still accepted as an alternative).
+* Slim down default key bindings: support lowercase only.
+* Handle escaped keys properly (parse eg \033b into a single key code) and
+ use this to change copy mode next/previous work to M-f and M-b to match
+ emacs.
+
+24 June 2008
+
+* Next word (C-n/w) and previous word (C-b/b) in copy mode.
+
+23 June 2008
+
+* list-commands command (alias lscm).
+* Split information about options into a table and use it to parse options
+ on input (allowing abbreviations) and to print them with show-options
+ (meaning that bell-action gets a proper string). This turned out a bit ugly
+ though :-/.
+
+22 June 2008
+
+* Do not translate black and white into default if the terminal supports
+ default colours. This was nice to force programs which didn't use default
+ colours to be properly transparent in rxvt/aterm windows with a background
+ image, but it causes trouble if someone redefines the default foreground and
+ background (to have black on white or something).
+
+21 June 2008
+
+* Naive tab completion in the command prompt. This only completes command
+ names if a) they are at the start of the text b) the cursor is at
+ the end of the text c) the text contains no spaces.
+* Only attempt to set the title where TERM looks like an xterm (contains
+ "xterm", "rxvt" or is "screen"). I hate this but I don't see a better way:
+ setting the title actually kills some other terminals pretty much dead.
+* Strip padding out of terminfo(5) strings. Currently the padding is just
+ ignored, this may need to be altered if there are any software terminals
+ out there that actually need it.
+
+20 June 2008
+
+* buffer-limit option to set maximum size of buffer stack. Default is 9.
+* Initial buffer improvements. Each session has a stack of buffers and each
+ buffer command takes a -b option to manipulate items on the stack. If -b
+ is omitted, the top entry is used. The following commands are currently
+ available:
+
+ set-buffer [-b index] [-t target-session] string
+ paste-buffer [-d] [-b index] [-t target-window]
+ delete-buffer [-b index] [-t target-session]
+ show-buffers [-t target-session]
+ show-buffer [-b index] [-t target-session]
+
+ -d to paste-buffer deletes the buffer after pasting it.
+* New option, display-time, sets the time status line messages stay on screen
+ (unless a key is pressed). Set in milliseconds, default is 750 (0.75 seconds).
+ The timer is only checked every 100 ms or so.
+
+19 June 2008
+
+* Use "status" consistently for status line option, and prefix for "prefix" key
+ option.
+* Allow commands to be entered at a prompt. This is triggered with the
+ command-prompt command, bound to : by default.
+* Show status messages properly, without blocking the server.
+
+18 June 2008
+
+* New option, set-titles. On by default, this attempts to set the window title
+ using the \e]2;...\007 xterm code.
+
+ Note that elinks requires the STY environment variable (used by screen) to be
+ set before it will set the window title. So, if you want window titles set by
+ elinks, set STY before running it (any value will do). I can't do this for all
+ windows since setting it to an invalid value breaks screen.
+* Show arrows at either end of status line when scrolled if more windows
+ exist. Highlight the arrow if a hidden window has activity or bell.
+* Scroll the status line to show the current window if necessary. Also handle
+ windows smaller than needed better (show a blank status line instead of
+ hanging or crashing).
+
+17 June 2008
+
+* tmux 0.3 released.
+
+16 June 2008
+
+* Add some information messages when window options are changed, suggested by
+ Mike Erdely. Also add a -q command-line option to suppress them.
+* show-window-options (showw) command.
+
+15 June 2008
+
+* show-options (show) command to show one or all options.
+
+14 June 2008
+
+* New window options: force-width and force-height. This will force a window
+ to an arbitrary width and height (0 for the default unlimited). This is
+ neat for emacs which doesn't have a sensible way to force hard wrapping at 80
+ columns. Also, don't try to be clever and use clr_eol when redrawing the
+ whole screen, it causes trouble since the redraw functions are used to draw
+ the blank areas too.
+* Clear the blank area below windows properly when they are smaller than client,
+ also add an indicator line to show the vertical limit.
+* Don't die on empty strings in config file, reported by Will Maier.
+
+08 June 2008
+
+* Set socket mode +x if any sessions are attached and -x if not.
+
+07 June 2008
+
+* Make status-interval actually changeable.
+
+06 June 2008
+
+* New window option: aggressive-resize. Normally, windows are resized to the
+ size of the smallest attached session to which they are linked. This means a
+ window only changes size when sessions are detached or attached, or they are
+ linked or unlinked from a session. This flag changes a window to be the size
+ of the smallest attached session for which it is the current window - it is
+ resized every time a session changes to it or away from it. This is nice for
+ things that handle SIGWINCH well (like irssi) and bad for things like shells.
+* The server now exits when no sessions remain.
+* Fix bug with inserting characters with TERM=xterm-color.
+
+05 June 2008
+
+* Completely reorganise command parsing. Much more common code in cmd-generic.c
+ and a new way of specifying windows, clients or sessions. Now, most commands
+ take a -t argument, which specifies a client, a session, or a window target.
+ Clients and sessions are given alone (sessions are fnmatch(3)d and
+ clients currently not), windows are give by (client|session):index. For
+ example, if a user is in session "1" window 0 on /dev/ttypi, these should all
+ be equivalent:
+
+ tmux renamew newname (current session and window)
+ tmux renamew -t: newname (current session and window)
+ tmux renamew -t:0 newname (current session, window 0)
+ tmux renamew -t0 newname (current session, window 0)
+ tmux renamew -t1:0 newname (session 1, window 0)
+ tmux renamew -t1: newname (session 1's current window)
+ tmux renamew -t/dev/ttypi newname (client /dev/ttypi's current
+ session and window)
+ tmux renamew -t/dev/ttypi: newname (client /dev/ttypi's current
+ session and window)
+ tmux renamew -t/dev/ttypi:0 newname (client /dev/ttypi's current
+ session, window 0)
+
+ This does have some downsides, for example, having to use -t on selectw,
+
+ tmux selectw -t7
+
+ is annoying. But then using non-flagged arguments would mean renaming the
+ current window would need to be something like:
+
+ tmux renamew : newname
+
+ It might be better not to try and be so consistent; comments to the usual
+ address ;-).
+* Infrastructure for printing arguments in list-keys output. Easy ones only for
+ now.
+
+04 June 2008
+
+* Add some vi(1) key bindings in copy mode, and support binding ^[, ^\, ^]
+ ^^ and ^_. Both from/prompted by Will Maier.
+* setw monitor-activity and set status without arguments now toggle the current
+ value; suggested by merdely.
+* New command set-window-option (alias setw) to set the single current window
+ option: monitor-activity to determine whether window activity is shown in
+ the status bar for that window (default off).
+* Change so active/bell windows are inverted in status line.
+* Activity monitoring - window with activity are marked in status line. No
+ way to disable this/filter windows yet.
+* Brought select-window command into line with everything else; it now uses
+ -i for the window index.
+* Strings to display on the left and right of the status bar may now be set
+ with the status-left and status-right options. These are passed through
+ strftime(3) before being displayed. The status bar is automatically updated
+ at an interval set by the status-interval option. The default is to display
+ nothing on the left and the date and time on the left; the default update
+ interval is 15 seconds.
+
+03 June 2008
+
+* Per session options. Setting options without specifying a session sets the
+ global options as normal (global options are inherited by all sessions);
+ passing -c or -s will set the option only for that session.
+* Because a client has a session attached, any command needing a session can
+ take a client and use its session. So, anything that used to accept -s now
+ accepts -c as well.
+* -s to specify session name now supports fnmatch(3) wildcards; if multiple
+ sessions are found, or if no -s is specified, the most newly created is used.
+* If no command is specified, assume new-session. As a byproduct, clean up
+ command default values into separate init functions.
+* kill-server command.
+
+02 June 2008
+
+* New command, start-server (alias "start"), to start the tmux server and do
+ nothing else. This is good if you have a configuration file which creates
+ windows or sessions (like me): in that case, starting the server the first
+ time tmux new is run is bad since it creates a new session and window (as
+ it is supposed to - starting the server is a side-effect).
+
+ Instead, I have a little script which does the equivalent of:
+
+ tmux has -s0 2>/dev/null || tmux start
+ tmux attach -d -s0
+
+ And I use it to start the server if necessary and attach to my primary
+ session.
+* Basic configuration file in ~/.tmux.conf or specified with -f. This is file
+ contains a set of tmux commands that are run the first time the server is
+ started. The configuration commands are executed before any others, so
+ if you have a configuration file that contains:
+
+ new -d
+ neww -s0
+
+ And you do the following without an existing server running:
+
+ tmux new
+
+ You will end up with two sessions, session 0 with two windows (created by
+ the configuration file) and your client attached to session 1 with one
+ window (created by the command-line command). I'm not completely happy with
+ this, it seems a little non-obvious, but I haven't yet decided what to do
+ about it.
+
+ There is no environment variable handling or other special stuff yet.
+
+ In the future, it might be nice to be able to have per-session configuration
+ settings, probably by having conditionals in the file (so you could, for
+ example, have commands to define a particular window layout that would only
+ be invoked if you called tmux new -smysession and mysession did not already
+ exist).
+* BIG CHANGE: -s and -c to specify session name and client name are now passed
+ after the command rather than before it. So, for example:
+
+ tmux -s0 neww
+
+ Becomes:
+
+ tmux neww -s0
+
+ This is to allow them to be used in the (forthcoming) configuration file
+ THIS WILL BREAK ANY CURRENT SCRIPTS OR ALIASES USING -s OR -c.
+
+01 June 2008
+
+* Bug fix: don't die if -k passed to link-window and the destination doesn't
+ exist.
+* New command, send-keys, will send a set of keys to a window.
+
+31 May 2008
+
+* Fix so tmux doesn't hang if the initial window fails for some reason. This
+ was highlighted by problems on Darwin, thanks to Elias Pipping for the report
+ and access to a test account. (tmux still won't work on Darwin since its
+ poll(2) is broken.)
+
+02 January 2008
+
+* Don't attempt to reset the tty on exit if it has been closed externally.
+
+06 December 2007
+
+* Restore checks for required termcap entries and add a few more obvious
+ emulations.
+* Another major reorganisation, this time of screen handling. A new set of
+ functions, screen_write_*, are now used to write to a screen and a tty
+ simultaneously. These are used by the input parser to update the base
+ window screen and also by the different modes which now interpose their own
+ screen.
+
+30 November 2007
+
+* Support \ek...\e\ to set window name.
+
+27 November 2007
+
+* Enable/disable mouse when asked, if terminal claims to support it. Mouse
+ sequences are just passed through unaltered for the moment.
+* Big internal reorganisation. Rather than leaving control of the tty solely in
+ the client and piping all data through a socket to it, change so that the
+ server opens the tty again and reads and writes to it directly. This avoids
+ a lot of buffering and copying. Also reorganise the redrawing stuff so that
+ everything goes through screen_draw_* - this makes the code simpler, but
+ still needs broken up more, and all the ways of writing to screens should be
+ more consistent.
+
+26 November 2007
+
+* Rather than shifting up one line at a time once the history is full,
+ shift by 10% of the history each time. This is faster.
+* Add ^A and ^E to copy mode to move to start-of-line/end-of-line.
+
+24 November 2007
+
+* Support for alt charset mode (VT100 graphics characters).
+
+23 November 2007
+
+* Mostly complete copy & paste. Copy mode entered with C-b [ (copy-mode
+ command). In copy mode, arrow keys/page up/page down/hjkl/C-u/C-f navigate,
+ space or C-space starts selection, and enter or C-w copies and (important!)
+ exits copy mode. C-b ] (paste-buffer) pastes into current window. No
+ extra utility keys (bol/eol/clear selection/etc), only one single buffer,
+ and no buffer manipulation commands (clear/view/etc) yet. The code is also
+ fugly :-(.
+* history-limit option to set maximum history. Does not apply retroactively to
+ existing windows! Lines take up a variable amount of space, but a reasonable
+ guess for an 80-column terminal is 250 KB per 1000 lines (of history used,
+ an empty history takes no space).
+
+21 November 2007
+
+* Create every line as zero length and only expand it as data is written,
+ rather than creating at full size immediately.
+* Make command output (eg list-keys) go to a scrollable window similar to
+ scroll mode.
+* Redo screen redrawing so it is a) readable b) split into utility functions
+ that can be used outside screen.c. Use these to make scroll mode only
+ redraw what it has to which gets rid of irritating flickering status box and
+ makes it much faster.
+* Full line width memory and horizontal scrolling in history.
+* Initial support for scroll history. = to enter scrolling mode, and then
+ vi keys or up/down/pgup/pgdown to navigate. Q to exit. No horizontal history
+ yet (need per-line sizes) and a few kinks to be worked out (resizing while in
+ history mode will probably cause trouble).
+
+20 November 2007
+
+* Fix format string error with "must specify a client" message. Also
+ sprinkle some printflike tags.
+* tmux 0.1 released.
+
+17 November 2007
+
+* (nicm) Add -k option to link-window to kill target window if it exists.
+
+16 November 2007
+
+* (nicm) Split in-client display into two columns. This is a hack but not a lot
+ more so than that bit is already and it helps with lots of keys.
+* (nicm) switch-client command to switch client between different sessions. This
+ is pretty cool:
+
+ $ tmux bind q switch 0
+ $ tmux bind w switch 1
+
+ Then you can switch between sessions 0 and 1 with a key :-).
+* (nicm) Accept "-c client-tty" on command line to allow client manipulation
+ commands, and change detach-/refresh-session to detach-/refresh-client (this
+ loses the -a behaviour, but at some point -session versions may return, and
+ -c will allow fnmatch(3)).
+* (nicm) List available commands on ambiguous command.
+
+12 November 2007
+
+* (nicm) If the terminal supports default colours (AX present), force black
+ background and white foreground to default. This is useful on transparent
+ *terms for programs which don't do it themselves (like most(1)).
+* (nicm) Fill in the rest of the man page.
+* (nicm) kill-session command.
+
+09 November 2007
+
+* (nicm) C-space is now "^ " not "^@".
+* (nicm) Support tab (\011).
+* (nicm) Initial man page outline.
+* (nicm) -V to show version.
+* (nicm) rename-session command.
+
+08 November 2007
+
+* (nicm) Check for required terminal capabilities on start.
+
+31 October 2007
+
+* (nicm) Linux port.
+
+30 October 2007
+
+* (nicm) swap-window command. Same as link-window but swaps windows.
+
+26 October 2007
+
+* (nicm) Saving scroll region on \e7 causes problems with ncmpc so I guess
+ it is not required.
+* (nicm) unlink-window command.
+* (nicm) link-window command to link an existing window into another session
+ (or another index in the same session). Syntax:
+
+ tmux -s dstname link-window [-i dstidx] srcname srcidx
+
+* (nicm) Redo window data structures. The global array remains, but each per-
+ session list is now a RB tree of winlink structures. This disassociates the
+ window index from the array size (allowing arbitrary indexes) which still
+ allowing windows to have multiple indexes.
+
+25 October 2007
+
+* (nicm) has-session command: checks if session exists.
+
+24 October 2007
+
+* (nicm) Support for \e6n to request cursor position. resize(1) now works.
+* (nicm) Support for \e7, \e8 save/restore cursor and attribute sequences.
+ Currently don't save mode (probably should). Also change some cases where
+ out-of-bound values are ignored to limit them to within range (there are
+ others than need to be checked too).
+
+23 October 2007
+
+* (nicm) Lift limit on session name passed with -s.
+* (nicm) Show size in session/window lists.
+* (nicm) Pass tty up to server when client identifies and add a list-clients
+ command to list connected clients.
+
+20 October 2007
+
+* (nicm) Add default-command option and change default to be $SHELL rather than
+ $SHELL -l. Also try to read shell from passwd db if $SHELL isn't present.
+
+19 October 2007
+
+* (nicm) -n on new-session is now -s, and -n is now the initial window name.
+ This was documented but not implemented :-/.
+* (nicm) kill-window command, bound to & by default (because it should be hard
+ to hit accidently).
+* (nicm) bell-style option with three choices: "none" completely ignore bell;
+ "any" pass through a bell in any window to current; "current" ignore bells
+ except in current window. This applies only to the bell terminal signal,
+ the status bar always reflects any bells.
+* (nicm) Refresh session command.
+
+12 October 2007
+
+* (nicm) Add a warning if $TMUX exists on new/attach.
+* (nicm) send-prefix command. Bound to C-b by default.
+* (nicm) set status, status-fg, status-bg commands. fg and bg are as a number
+ from 0 to 8 or a string ("red", "blue", etc). status may be 1/0, on/off,
+ yes/no.
+* (nicm) Make status line mark window in yellow on bell.
+
+04 October 2007
+
+* (nicm) -d option to attach to detach all other clients on the same session.
+* (nicm) Partial resizing support. Still buggy. A C-b S and back sometimes fixes
+ it when it goes wonky.
+* (mxey) Added my tmux start script as an example (examples/start-tmux.sh).
+* (mxey) New sessions can now be given a command for their first window.
+* (mxey) Fixed usage statement for new-window.
+* (nicm) attach-session (can't believe I forgot it until now!) and list-windows
+ commands.
+* (nicm) rename-window and select-window commands.
+* (nicm) set-option command (alias set): "tmux set-option prefix ^A".
+* (nicm) Key binding and unbinding is back.
+
+03 October 2007
+
+* (nicm) {new,next,last,previous}-window.
+* (nicm) Rewrite command handling so commands are much more generic and the
+ same commands are used for command line and keys (although most will probably
+ need to check how they are called). Currently incomplete (only new/detach/ls
+ implemented). Change: -s is now passed before command again!
+* (nicm) String number arguments. So you can do: tmux bind ^Q create "blah".
+* (nicm) Key binding. tmux bind key command [argument] and tmux unbind key.
+ Key names are in a table in key-string.c, plus A is A, ^A is ctrl-A.
+ Possible commands are in cmd.c (look at cmd_bind_table).
+* (nicm) Move command parsing into the client. Also rename some messages and
+ tidy up a few bits. Lots more tidying up needed :-/.
+
+02 October 2007
+
+* (nicm) Redraw client status lines on rename.
+* (nicm) Error on ambiguous command.
+
+01 October 2007
+
+* (nicm) Restore window title handling.
+* (nicm) Simple uncustomisable status line with window list.
+
+30 September 2007
+
+* (nicm) Window info command for debugging, C-b I.
+
+29 September 2007
+
+* (nicm) Deleting/inserting lines should follow scrolling region. Fix.
+* (nicm) Allow creation of detached sessions: "tmux new-session -d".
+* (nicm) Permit error messages to be passed back for transient clients like
+ rename. Also make rename -i work.
+* (nicm) Pass through bell in any window to current.
+
+28 September 2007
+
+* (nicm) Major rewrite of input parser:
+ - Lose the old weirdness in favour of a state machine.
+ - Merge in parsing from screen.c.
+ - Split key parsing off into a separate file.
+ This is step one towards hopefully allowing a status line. It requires
+ that we output data as if the terminal had one line less than it really does -
+ a serious problem when it comes to things like scrolling. This change
+ consolidates all the range checking and limiting together which should make
+ it easier.
+* (mxey) Added window renaming, like "tmux rename [-s session] [-i index] name"
+
+27 September 2007
+
+* Split "tmux list" into "tmux list-sessions" (ls) and "list-windows" (lsw).
+* New command session selection:
+ - if name is specified, look for it and use it if it exists, otherwise
+ error
+ - if no name specified, try the current session from $TMUX
+ - if $TMUX doesn't exist, and there is only one session, use it,
+ otherwise error
+
+26 September 2007
+
+* Add command aliases, so "ls" is an alias for "list".
+* Rename some commands and alter syntax to take options after a la CVS. Also
+ change some flags. So:
+
+ tmux -s/socket -nabc new
+
+ Becomes:
+
+ tmux -S/socket new -sabc
+
+* Major tidy and split of client/server code.
+
+22 September 2007
+
+* Window list command (C-b W). Started by Maximilian Gass, finished by me.
+
+20 September 2007
+
+* Specify meta via environment variable (META).
+* Record last window and ^L key to switch to it. Largely from Maximilian Gass.
+* Reset ignored signals in child after forkpty, makes ^C work.
+* Wrap on next/previous. From Maximilian Gass.
+
+19 September 2007
+
+* Don't renumber windows on close.
+
+28 August 2007
+
+* Scrolling region (\e[r) support.
+
+27 August 2007
+
+* Change screen.c to work more logically and hopefully fix heap corruption.
+
+09 July 2007
+
+* Initial import to CVS. Basic functions are working, albeit with a couple of
+ showstopper memory bugs and many missing features. Detaching, reattaching,
+ creating new sessions, listing sessions work acceptably for using with shells.
+ Simple curses programs (top, systat, tetris) and more complicated ones (mutt,
+ emacs) that don't require scrolling regions (ESC[r) mostly work fine
+ (including mutt, emacs). No status bar yet and no key remapping or other
+ customisation.
diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..fd02a999
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,18 @@
+THIS IS FOR INFORMATION ONLY, CODE IS UNDER THE LICENCE AT THE TOP OF ITS FILE.
+
+The README, CHANGES, FAQ and TODO files are licensed under the ISC license. All
+other files have a license and copyright notice at their start, typically:
+
+Copyright (c) <author>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 6e29c4fe..00000000
--- a/Makefile
+++ /dev/null
@@ -1,136 +0,0 @@
-# $OpenBSD$
-
-PROG= tmux
-SRCS= alerts.c \
- arguments.c \
- attributes.c \
- cfg.c \
- client.c \
- cmd-attach-session.c \
- cmd-bind-key.c \
- cmd-break-pane.c \
- cmd-capture-pane.c \
- cmd-choose-tree.c \
- cmd-command-prompt.c \
- cmd-confirm-before.c \
- cmd-copy-mode.c \
- cmd-detach-client.c \
- cmd-display-menu.c \
- cmd-display-message.c \
- cmd-display-panes.c \
- cmd-find-window.c \
- cmd-find.c \
- cmd-if-shell.c \
- cmd-join-pane.c \
- cmd-kill-pane.c \
- cmd-kill-server.c \
- cmd-kill-session.c \
- cmd-kill-window.c \
- cmd-list-buffers.c \
- cmd-list-clients.c \
- cmd-list-keys.c \
- cmd-list-panes.c \
- cmd-list-sessions.c \
- cmd-list-windows.c \
- cmd-load-buffer.c \
- cmd-lock-server.c \
- cmd-move-window.c \
- cmd-new-session.c \
- cmd-new-window.c \
- cmd-parse.y \
- cmd-paste-buffer.c \
- cmd-pipe-pane.c \
- cmd-queue.c \
- cmd-refresh-client.c \
- cmd-rename-session.c \
- cmd-rename-window.c \
- cmd-resize-pane.c \
- cmd-resize-window.c \
- cmd-respawn-pane.c \
- cmd-respawn-window.c \
- cmd-rotate-window.c \
- cmd-run-shell.c \
- cmd-save-buffer.c \
- cmd-select-layout.c \
- cmd-select-pane.c \
- cmd-select-window.c \
- cmd-send-keys.c \
- cmd-set-buffer.c \
- cmd-set-environment.c \
- cmd-set-option.c \
- cmd-show-environment.c \
- cmd-show-messages.c \
- cmd-show-options.c \
- cmd-source-file.c \
- cmd-split-window.c \
- cmd-swap-pane.c \
- cmd-swap-window.c \
- cmd-switch-client.c \
- cmd-unbind-key.c \
- cmd-wait-for.c \
- cmd.c \
- colour.c \
- control-notify.c \
- control.c \
- environ.c \
- file.c \
- format.c \
- format-draw.c \
- grid-view.c \
- grid.c \
- input-keys.c \
- input.c \
- job.c \
- key-bindings.c \
- key-string.c \
- layout-custom.c \
- layout-set.c \
- layout.c \
- log.c \
- menu.c \
- mode-tree.c \
- names.c \
- notify.c \
- options-table.c \
- options.c \
- paste.c \
- proc.c \
- procname.c \
- regsub.c \
- resize.c \
- screen-redraw.c \
- screen-write.c \
- screen.c \
- server-client.c \
- server-fn.c \
- server.c \
- session.c \
- spawn.c \
- status.c \
- style.c \
- tmux.c \
- tty-acs.c \
- tty-keys.c \
- tty-term.c \
- tty.c \
- utf8.c \
- window-buffer.c \
- window-client.c \
- window-clock.c \
- window-copy.c \
- window-tree.c \
- window.c \
- xmalloc.c \
- xterm-keys.c
-
-CDIAGFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
-CDIAGFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
-CDIAGFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
-CDIAGFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align
-
-CFLAGS += -I${.CURDIR}
-
-LDADD= -lutil -lcurses -levent
-DPADD= ${LIBUTIL} ${LIBCURSES} ${LIBEVENT}
-
-.include <bsd.prog.mk>
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 00000000..6902477e
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,208 @@
+# Makefile.am
+
+# Obvious program stuff.
+bin_PROGRAMS = tmux
+CLEANFILES = tmux.1.mdoc tmux.1.man cmd-parse.c
+
+# Distribution tarball options.
+EXTRA_DIST = \
+ CHANGES README README.ja COPYING example_tmux.conf \
+ osdep-*.c mdoc2man.awk tmux.1
+dist_EXTRA_tmux_SOURCES = compat/*.[ch]
+
+# Preprocessor flags.
+AM_CPPFLAGS += @XOPEN_DEFINES@
+AM_CPPFLAGS += -DTMUX_CONF="\"$(sysconfdir)/tmux.conf:~/.tmux.conf:~/.config/tmux/tmux.conf\""
+
+# Additional object files.
+LDADD = $(LIBOBJS)
+
+# Set flags for gcc.
+if IS_GCC
+AM_CFLAGS += -std=gnu99 -O2
+if IS_DEBUG
+AM_CFLAGS += -g
+AM_CFLAGS += -Wno-long-long -Wall -W -Wformat=2
+AM_CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
+AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
+AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
+AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
+AM_CFLAGS += -Wno-unused-result
+AM_CPPFLAGS += -DDEBUG
+endif
+AM_CPPFLAGS += -iquote.
+endif
+
+# Set flags for Solaris.
+if IS_SUNOS
+if IS_GCC
+AM_CPPFLAGS += -D_XPG6
+else
+AM_CPPFLAGS += -D_XPG4_2
+endif
+endif
+
+# Set flags for Sun CC.
+if IS_SUNCC
+AM_CFLAGS += -erroff=E_EMPTY_DECLARATION
+endif
+
+# Set _LINUX_SOURCE_COMPAT for AIX for malloc(0).
+if IS_AIX
+AM_CPPFLAGS += -D_LINUX_SOURCE_COMPAT=1
+endif
+
+# Set flags for NetBSD.
+if IS_NETBSD
+AM_CPPFLAGS += -D_OPENBSD_SOURCE
+endif
+
+# List of sources.
+dist_tmux_SOURCES = \
+ alerts.c \
+ arguments.c \
+ attributes.c \
+ cfg.c \
+ client.c \
+ cmd-attach-session.c \
+ cmd-bind-key.c \
+ cmd-break-pane.c \
+ cmd-capture-pane.c \
+ cmd-choose-tree.c \
+ cmd-command-prompt.c \
+ cmd-confirm-before.c \
+ cmd-copy-mode.c \
+ cmd-detach-client.c \
+ cmd-display-menu.c \
+ cmd-display-message.c \
+ cmd-display-panes.c \
+ cmd-find-window.c \
+ cmd-find.c \
+ cmd-if-shell.c \
+ cmd-join-pane.c \
+ cmd-kill-pane.c \
+ cmd-kill-server.c \
+ cmd-kill-session.c \
+ cmd-kill-window.c \
+ cmd-list-buffers.c \
+ cmd-list-clients.c \
+ cmd-list-keys.c \
+ cmd-list-panes.c \
+ cmd-list-sessions.c \
+ cmd-list-windows.c \
+ cmd-load-buffer.c \
+ cmd-lock-server.c \
+ cmd-move-window.c \
+ cmd-new-session.c \
+ cmd-new-window.c \
+ cmd-parse.y \
+ cmd-paste-buffer.c \
+ cmd-pipe-pane.c \
+ cmd-queue.c \
+ cmd-refresh-client.c \
+ cmd-rename-session.c \
+ cmd-rename-window.c \
+ cmd-resize-pane.c \
+ cmd-resize-window.c \
+ cmd-respawn-pane.c \
+ cmd-respawn-window.c \
+ cmd-rotate-window.c \
+ cmd-run-shell.c \
+ cmd-save-buffer.c \
+ cmd-select-layout.c \
+ cmd-select-pane.c \
+ cmd-select-window.c \
+ cmd-send-keys.c \
+ cmd-set-buffer.c \
+ cmd-set-environment.c \
+ cmd-set-option.c \
+ cmd-show-environment.c \
+ cmd-show-messages.c \
+ cmd-show-options.c \
+ cmd-source-file.c \
+ cmd-split-window.c \
+ cmd-swap-pane.c \
+ cmd-swap-window.c \
+ cmd-switch-client.c \
+ cmd-unbind-key.c \
+ cmd-wait-for.c \
+ cmd.c \
+ colour.c \
+ compat.h \
+ control-notify.c \
+ control.c \
+ environ.c \
+ file.c \
+ format.c \
+ format-draw.c \
+ grid-view.c \
+ grid.c \
+ input-keys.c \
+ input.c \
+ job.c \
+ key-bindings.c \
+ key-string.c \
+ layout-custom.c \
+ layout-set.c \
+ layout.c \
+ log.c \
+ menu.c \
+ mode-tree.c \
+ names.c \
+ notify.c \
+ options-table.c \
+ options.c \
+ paste.c \
+ proc.c \
+ regsub.c \
+ resize.c \
+ screen-redraw.c \
+ screen-write.c \
+ screen.c \
+ server-client.c \
+ server-fn.c \
+ server.c \
+ session.c \
+ spawn.c \
+ status.c \
+ style.c \
+ tmux.c \
+ tmux.h \
+ tty-acs.c \
+ tty-keys.c \
+ tty-term.c \
+ tty.c \
+ utf8.c \
+ window-buffer.c \
+ window-client.c \
+ window-clock.c \
+ window-copy.c \
+ window-tree.c \
+ window.c \
+ xmalloc.c \
+ xmalloc.h \
+ xterm-keys.c
+nodist_tmux_SOURCES = osdep-@PLATFORM@.c
+
+# Add compat file for forkpty.
+if NEED_FORKPTY
+nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c
+endif
+
+# Add compat file for utf8proc.
+if HAVE_UTF8PROC
+nodist_tmux_SOURCES += compat/utf8proc.c
+endif
+
+# Install tmux.1 in the right format.
+install-exec-hook:
+ if test x@MANFORMAT@ = xmdoc; then \
+ sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1 \
+ >$(srcdir)/tmux.1.mdoc; \
+ else \
+ sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1| \
+ $(AWK) -f $(srcdir)/mdoc2man.awk >$(srcdir)/tmux.1.man; \
+ fi
+ $(mkdir_p) $(DESTDIR)$(mandir)/man1
+ $(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \
+ $(DESTDIR)$(mandir)/man1/tmux.1
diff --git a/README b/README
new file mode 100644
index 00000000..4f577060
--- /dev/null
+++ b/README
@@ -0,0 +1,75 @@
+Welcome to tmux!
+
+tmux is a terminal multiplexer: it enables a number of terminals to be created,
+accessed, and controlled from a single screen. tmux may be detached from a
+screen and continue running in the background, then later reattached.
+
+This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
+
+* Dependencies
+
+tmux depends on libevent 2.x, available from:
+
+ https://github.com/libevent/libevent/releases/latest
+
+It also depends on ncurses, available from:
+
+ https://invisible-mirror.net/archives/ncurses/
+
+* Installation
+
+To build and install tmux from a release tarball, use:
+
+ $ ./configure && make
+ $ sudo make install
+
+tmux can use the utempter library to update utmp(5), if it is installed - run
+configure with --enable-utempter to enable this.
+
+To get and build the latest from version control - note that this requires
+autoconf, automake and pkg-config:
+
+ $ git clone https://github.com/tmux/tmux.git
+ $ cd tmux
+ $ sh autogen.sh
+ $ ./configure && make
+
+* Contributing
+
+Bug reports, feature suggestions and especially code contributions are most
+welcome. Please send by email to:
+
+ tmux-users@googlegroups.com
+
+Or open a GitHub issue or pull request.
+
+* Documentation
+
+For documentation on using tmux, see the tmux.1 manpage. View it from the
+source tree with:
+
+ $ nroff -mdoc tmux.1|less
+
+A small example configuration is in example_tmux.conf.
+
+A bash(1) completion file is at:
+
+ https://github.com/imomaliev/tmux-bash-completion
+
+For debugging, run tmux with -v and -vv to generate server and client log files
+in the current directory.
+
+* Support
+
+The tmux mailing list for general discussion and bug reports is:
+
+ https://groups.google.com/forum/#!forum/tmux-users
+
+Subscribe by sending an email to:
+
+ tmux-users+subscribe@googlegroups.com
+
+* License
+
+This file and the CHANGES files are licensed under the ISC license. All other
+files have a license and copyright notice at their start.
diff --git a/README.ja b/README.ja
new file mode 100644
index 00000000..1580df52
--- /dev/null
+++ b/README.ja
@@ -0,0 +1,62 @@
+tmuxへようこそ!
+
+tmuxはターミナルマルチプレクサーです。複数のターミナルを一つのスクリーン内に作成し、操作することができます。
+バックグラウンドで処理を実行中に一度スクリーンから離れて後から復帰することも可能です。
+
+OpenBSD、FreeBSD、NetBSD、Linux、OS X、Solarisで実行できます。
+
+tmuxはlibevent 2.x.に依存します。 下記からダウンロードしてください。
+
+ http://libevent.org
+
+また、ncursesも必要です。こちらからどうぞ。
+
+ http://invisible-island.net/ncurses/
+
+tarballでのtmuxのビルドとインストール方法。
+
+ $ ./configure && make
+ $ sudo make install
+
+tmuxはutmp(5)をアップデートするためにutempterを使うことができます。もしインストール済みであればオプション「--enable-utempter」をつけて実行してください。
+
+リポジトリから最新バージョンを手に入れるためには下記を実行。
+
+ $ git clone https://github.com/tmux/tmux.git
+ $ cd tmux
+ $ sh autogen.sh
+ $ ./configure && make
+
+(ビルドのためにはlibevent、ncurses libraries、headersに加えて、C compiler、make、autoconf、automake、pkg-configが必要です。)
+
+詳しい情報はhttp://git-scm.comをご覧ください。修正はメール<tmux-users@googlegroups.com>宛、もしくはhttps://github.com/tmux/tmux/issuesにて受け付けています。
+
+tmuxのドキュメントについてはtmux.1マニュアルをご覧ください。こちらのコマンドで参照可能です。
+
+ $ nroff -mdoc tmux.1|less
+
+サンプル設定は本リポジトリのexample_tmux.confに
+また、bash-completionファイルは下記にあります。
+
+ https://github.com/imomaliev/tmux-bash-completion
+
+「-v」や「-vv」を指定することでデバッグモードでの起動が可能です。カレントディレクトリにサーバーやクライアントのログファイルが生成されます。
+
+議論やバグレポート用のメーリングリストにはこちらから参加可能です。
+
+ https://groups.google.com/forum/#!forum/tmux-users
+
+gitコミットについての連絡先
+
+ https://groups.google.com/forum/#!forum/tmux-git
+
+購読は<tmux-users+subscribe@googlegroups.com>までメールをお願いします。
+
+バグレポートや機能追加(特にコードへの貢献)は大歓迎です。こちらにご連絡ください。
+
+ tmux-users@googlegroups.com
+
+本ファイル、CHANGES、 FAQ、SYNCINGそしてTODOはISC licenseで保護されています。
+その他のファイルのライセンスや著作権については、ファイルの上部に明記されています。
+
+-- Nicholas Marriott <nicholas.marriott@gmail.com>
diff --git a/SYNCING b/SYNCING
new file mode 100644
index 00000000..b8cc4b5c
--- /dev/null
+++ b/SYNCING
@@ -0,0 +1,173 @@
+Preamble
+========
+
+Tmux portable relies on repositories "tmux" and "tmux-openbsd".
+Here's a description of them:
+
+* "tmux" is the portable version, the one which contains code for other
+ operating systems, and autotools, etc., which isn't found or needed in the
+ OpenBSD base system.
+
+* "tmux-openbsd" is the version of tmux in OpenBSD base system which provides
+ the basis of the portable tmux version.
+
+Note: The "tmux-openbsd" repository is actually handled by "git cvsimport"
+running at 15 minute intervals, so a commit made to OpenBSD's tmux CVS
+repository will take at least that long to appear in this git repository.
+(It might take longer, depending on the CVS mirror used to import the
+OpenBSD code).
+
+If you've never used git before, git tracks meta-data about the committer
+and the author, as part of a commit, hence:
+
+% git config [--global] user.name "Your name"
+% git config [--global] user.email "you@yourdomain.com"
+
+Note that, if you already have this in the global ~/.gitconfig option, then
+this will be used. Setting this per-repository would involve not using the
+"--global" flag above. If you wish to use the same credentials always,
+pass the "--global" option, as shown.
+
+This is a one-off operation once the repository has been cloned, assuming
+this information has ever been set before.
+
+Cloning repositories
+====================
+
+This involves having both tmux and tmux-openbsd cloned, as in:
+
+% cd /some/where/useful
+% git clone https://github.com/tmux/tmux.git
+% git clone https://github.com/ThomasAdam/tmux-openbsd.git
+
+Note that you do not need additional checkouts to manage the sync -- an
+existing clone of either repositories will suffice. So if you already have
+these checkouts existing, skip that.
+
+Adding in git-remotes
+=====================
+
+Because the portable "tmux" git repository and the "tmux-openbsd"
+repository do not inherently share any history between each other, the
+history has been faked between them. This "faking of history" is something
+which has to be told to git for the purposes of comparing the "tmux" and
+"tmux-openbsd" repositories for syncing. To do this, we must reference the
+clone of the "tmux-openbsd" repository from the "tmux" repository, as
+shown by the following command:
+
+% cd /path/to/tmux
+% git remote add obsd-tmux file:///path/to/tmux-openbsd
+
+So that now, the remote "obsd-tmux" can be used to reference branches and
+commits from the "tmux-openbsd" repository, but from the context of the
+portable "tmux" repository, which makes sense because it's the "tmux"
+repository which will have the updates applied to them.
+
+Fetching updates
+================
+
+To ensure the latest commits from "tmux-openbsd" can be found from within
+"tmux", we have to ensure the "master" branch from "tmux-openbsd" is
+up-to-date first, and then reference that update in "tmux", as in:
+
+% cd /path/to/tmux-openbsd
+% git checkout master
+% git pull
+
+Then back in "tmux":
+
+% cd /path/to/tmux
+% git fetch obsd-tmux
+
+Creating the necessary branches
+===============================
+
+Now that "tmux" can see commits and branches from "tmux-openbsd" by way
+of the remote name "obsd-tmux", we can now create the master branch from
+"tmux-openbsd" in the "tmux" repository:
+
+% git checkout -b obsd-master obsd-tmux/master
+
+Adding in the fake history points
+=================================
+
+To tie both the "master" branch from "tmux" and the "obsd-master"
+branch from "tmux-openbsd" together, the fake history points added to the
+"tmux" repository need to be added. To do this, we must add an
+additional refspec line, as in:
+
+% cd /path/to/tmux
+% git config --add remote.origin.fetch '+refs/replace/*:refs/replace/*'
+% git fetch origin
+
+Performing the Sync
+===================
+
+Make sure the "master" branch is checked out:
+
+% git checkout master
+
+The following will show commits on OpenBSD not yet synched with "tmux":
+
+% git log master..obsd-master
+
+From there, merge the result in, fixing up any conflicts which might arise.
+
+% git merge obsd-master
+
+Then ensure things look correct by BUILDING the result of that sync:
+
+% make clean && ./autogen.sh && ./configure && make
+
+Compare the git merge result with what's on origin/master -- that is, check
+which commits you're about to push:
+
+% git log origin/master..master
+
+And if happy:
+
+% git push origin master
+
+Keeping an eye on libutil in OpenBSD
+====================================
+
+A lot of the compat/ code in tmux comes from libutil, especially imsg.
+Sometimes the API can change, etc., which might cause interesting problems
+trying to run the portable version of tmux. It's worth checking
+periodically for any changes to libutil in OpenBSD and syncing those files
+to compat/ as and when appropriate.
+
+Release tmux for next version
+=============================
+
+1. Update and commit README and CHANGES. The former should be checked for
+ anything outdated and updated with a list of things that might break
+ upgrades and the latter should mention all the major changes since
+ the last version.
+
+2. Make sure configure.ac has the new version number.
+
+3. Tag with:
+
+ % git tag -a 2.X
+
+ Where "2.X" is the next version.
+
+ Push the tag out with:
+
+ % git push --tags
+
+4. Build the tarball with 'make dist'.
+
+5. Check the tarball. If it's good, go here to select the tag just pushed:
+
+ https://github.com/tmux/tmux/tags
+
+ Click the "Add release notes", upload the tarball and add a link in the
+ description field to the CHANGES file.
+
+6. Clone the tmux.github.io repository, and change the RELEASE version in the
+ Makefile. Commit it, and run 'make' to replace %%RELEASE%%. Push the
+ result out.
+
+7. Change version back to master in configure.ac.
diff --git a/arguments.c b/arguments.c
index acdaf8aa..026272af 100644
--- a/arguments.c
+++ b/arguments.c
@@ -21,7 +21,6 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <vis.h>
#include "tmux.h"
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 00000000..b27b92ee
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+if [ "x$(uname)" = "xOpenBSD" ]; then
+ [ -z "$AUTOMAKE_VERSION" ] && export AUTOMAKE_VERSION=1.15
+ [ -z "$AUTOCONF_VERSION" ] && export AUTOCONF_VERSION=2.69
+fi
+
+die()
+{
+ echo "$@" >&2
+ exit 1
+}
+
+mkdir -p etc
+aclocal || die "aclocal failed"
+automake --add-missing --force-missing --copy --foreign || die "automake failed"
+autoreconf || die "autoreconf failed"
diff --git a/cfg.c b/cfg.c
index 92c87225..933eda4e 100644
--- a/cfg.c
+++ b/cfg.c
@@ -23,7 +23,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <util.h>
#include "tmux.h"
diff --git a/client.c b/client.c
index a36c6471..26c392b1 100644
--- a/client.c
+++ b/client.c
@@ -20,11 +20,11 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
+#include <sys/file.h>
#include <errno.h>
#include <event.h>
#include <fcntl.h>
-#include <imsg.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
@@ -334,7 +334,9 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
cfmakeraw(&tio);
tio.c_iflag = ICRNL|IXANY;
tio.c_oflag = OPOST|ONLCR;
+#ifdef NOKERNINFO
tio.c_lflag = NOKERNINFO;
+#endif
tio.c_cflag = CREAD|CS8|HUPCL;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;
diff --git a/cmd-find.c b/cmd-find.c
index e3e14f55..154842ab 100644
--- a/cmd-find.c
+++ b/cmd-find.c
@@ -22,7 +22,6 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
-#include <paths.h>
#include <unistd.h>
#include "tmux.h"
diff --git a/cmd-join-pane.c b/cmd-join-pane.c
index 5344f3ec..67207291 100644
--- a/cmd-join-pane.c
+++ b/cmd-join-pane.c
@@ -19,7 +19,6 @@
#include <sys/types.h>
-#include <paths.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
diff --git a/cmd-list.c b/cmd-list.c
deleted file mode 100644
index 82ffe55c..00000000
--- a/cmd-list.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/* $OpenBSD$ */
-
-/*
- * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "tmux.h"
-
-static u_int cmd_list_next_group = 1;
-
-struct cmd_list *
-cmd_list_new(void)
-{
- struct cmd_list *cmdlist;
-
- cmdlist = xcalloc(1, sizeof *cmdlist);
- cmdlist->references = 1;
- cmdlist->group = cmd_list_next_group++;
- TAILQ_INIT(&cmdlist->list);
- return (cmdlist);
-}
-
-void
-cmd_list_append(struct cmd_list *cmdlist, struct cmd *cmd)
-{
- cmd->group = cmdlist->group;
- TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
-}
-
-void
-cmd_list_move(struct cmd_list *cmdlist, struct cmd_list *from)
-{
- struct cmd *cmd, *cmd1;
-
- TAILQ_FOREACH_SAFE(cmd, &from->list, qentry, cmd1) {
- TAILQ_REMOVE(&from->list, cmd, qentry);
- TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
- }
- cmdlist->group = cmd_list_next_group++;
-}
-
-void
-cmd_list_free(struct cmd_list *cmdlist)
-{
- struct cmd *cmd, *cmd1;
-
- if (--cmdlist->references != 0)
- return;
-
- TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) {
- TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
- cmd_free(cmd);
- }
-
- free(cmdlist);
-}
-
-char *
-cmd_list_print(struct cmd_list *cmdlist, int escaped)
-{
- struct cmd *cmd;
- char *buf, *this;
- size_t len;
-
- len = 1;
- buf = xcalloc(1, len);
-
- TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
- this = cmd_print(cmd);
-
- len += strlen(this) + 4;
- buf = xrealloc(buf, len);
-
- strlcat(buf, this, len);
- if (TAILQ_NEXT(cmd, qentry) != NULL) {
- if (escaped)
- strlcat(buf, " \\; ", len);
- else
- strlcat(buf, " ; ", len);
- }
-
- free(this);
- }
-
- return (buf);
-}
diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c
index baad707a..2b5db825 100644
--- a/cmd-paste-buffer.c
+++ b/cmd-paste-buffer.c
@@ -20,7 +20,6 @@
#include <stdlib.h>
#include <string.h>
-#include <vis.h>
#include "tmux.h"
diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c
index 084eafe5..ce1b3d37 100644
--- a/cmd-pipe-pane.c
+++ b/cmd-pipe-pane.c
@@ -21,7 +21,6 @@
#include <errno.h>
#include <fcntl.h>
-#include <paths.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c
index 6830e5fc..84e50242 100644
--- a/cmd-save-buffer.c
+++ b/cmd-save-buffer.c
@@ -24,7 +24,6 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <vis.h>
#include "tmux.h"
diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c
deleted file mode 100644
index 0af82972..00000000
--- a/cmd-show-buffer.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/* $OpenBSD$ */
-
-/*
- * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <vis.h>
-
-#include "tmux.h"
-
-/*
- * Show a paste buffer.
- */
-
-enum cmd_retval cmd_show_buffer_exec(struct cmd *, struct cmd_ctx *);
-
-const struct cmd_entry cmd_show_buffer_entry = {
- "show-buffer", "showb",
- "b:", 0, 0,
- CMD_BUFFER_USAGE,
- 0,
- NULL,
- NULL,
- cmd_show_buffer_exec
-};
-
-enum cmd_retval
-cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
-{
- struct args *args = self->args;
- struct session *s;
- struct paste_buffer *pb;
- int buffer;
- char *in, *buf, *ptr, *cause;
- size_t size, len;
- u_int width;
-
- if ((s = cmd_find_session(ctx, NULL, 0)) == NULL)
- return (CMD_RETURN_ERROR);
-
- if (!args_has(args, 'b')) {
- if ((pb = paste_get_top(&global_buffers)) == NULL) {
- ctx->error(ctx, "no buffers");
- return (CMD_RETURN_ERROR);
- }
- } else {
- buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
- if (cause != NULL) {
- ctx->error(ctx, "buffer %s", cause);
- free(cause);
- return (CMD_RETURN_ERROR);
- }
-
- pb = paste_get_index(&global_buffers, buffer);
- if (pb == NULL) {
- ctx->error(ctx, "no buffer %d", buffer);
- return (CMD_RETURN_ERROR);
- }
- }
-
- size = pb->size;
- if (size > SIZE_MAX / 4 - 1)
- size = SIZE_MAX / 4 - 1;
- in = xmalloc(size * 4 + 1);
- strvisx(in, pb->data, size, VIS_OCTAL|VIS_TAB);
-
- width = s->sx;
- if (ctx->cmdclient != NULL)
- width = ctx->cmdclient->tty.sx;
-
- buf = xmalloc(width + 1);
- len = 0;
-
- ptr = in;
- do {
- buf[len++] = *ptr++;
-
- if (len == width || buf[len - 1] == '\n') {
- if (buf[len - 1] == '\n')
- len--;
- buf[len] = '\0';
-
- ctx->print(ctx, "%s", buf);
- len = 0;
- }
- } while (*ptr != '\0');
-
- if (len != 0) {
- buf[len] = '\0';
- ctx->print(ctx, "%s", buf);
- }
- free(buf);
-
- free(in);
-
- return (CMD_RETURN_NORMAL);
-}
diff --git a/cmd-show-messages.c b/cmd-show-messages.c
index e4b51fa8..8da12374 100644
--- a/cmd-show-messages.c
+++ b/cmd-show-messages.c
@@ -21,7 +21,6 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
-#include <vis.h>
#include "tmux.h"
diff --git a/cmd-show-options.c b/cmd-show-options.c
index 0b9eb096..da481139 100644
--- a/cmd-show-options.c
+++ b/cmd-show-options.c
@@ -20,7 +20,6 @@
#include <stdlib.h>
#include <string.h>
-#include <vis.h>
#include "tmux.h"
diff --git a/cmd-source-file.c b/cmd-source-file.c
index 46dc6d94..afe45a54 100644
--- a/cmd-source-file.c
+++ b/cmd-source-file.c
@@ -22,7 +22,6 @@
#include <glob.h>
#include <stdlib.h>
#include <string.h>
-#include <vis.h>
#include "tmux.h"
diff --git a/cmd-split-window.c b/cmd-split-window.c
index 748ae49b..eaf1f74c 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -20,7 +20,6 @@
#include <errno.h>
#include <fcntl.h>
-#include <paths.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c
index 69141346..d65ac91a 100644
--- a/cmd-unbind-key.c
+++ b/cmd-unbind-key.c
@@ -28,15 +28,12 @@
static enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmdq_item *);
-static enum cmd_retval cmd_unbind_key_mode_table(struct cmd *,
- struct cmdq_item *, key_code);
-
const struct cmd_entry cmd_unbind_key_entry = {
.name = "unbind-key",
.alias = "unbind",
- .args = { "ant:T:", 0, 1 },
- .usage = "[-an] [-t mode-table] [-T key-table] key",
+ .args = { "anT:", 0, 1 },
+ .usage = "[-an] [-T key-table] key",
.flags = CMD_AFTERHOOK,
.exec = cmd_unbind_key_exec
@@ -67,9 +64,6 @@ cmd_unbind_key_exec(struct cmd *self, struct cmdq_item *item)
key = KEYC_UNKNOWN;
}
- if (args_has(args, 't'))
- return (cmd_unbind_key_mode_table(self, item, key));
-
if (key == KEYC_UNKNOWN) {
tablename = args_get(args, 'T');
if (tablename == NULL) {
@@ -98,35 +92,3 @@ cmd_unbind_key_exec(struct cmd *self, struct cmdq_item *item)
key_bindings_remove(tablename, key);
return (CMD_RETURN_NORMAL);
}
-
-static enum cmd_retval
-cmd_unbind_key_mode_table(struct cmd *self, struct cmdq_item *item,
- key_code key)
-{
- struct args *args = self->args;
- const char *tablename;
- const struct mode_key_table *mtab;
- struct mode_key_binding *mbind, mtmp;
-
- tablename = args_get(args, 't');
- if ((mtab = mode_key_findtable(tablename)) == NULL) {
- cmdq_error(item, "unknown key table: %s", tablename);
- return (CMD_RETURN_ERROR);
- }
-
- if (key == KEYC_UNKNOWN) {
- while (!RB_EMPTY(mtab->tree)) {
- mbind = RB_ROOT(mtab->tree);
- RB_REMOVE(mode_key_tree, mtab->tree, mbind);
- free(mbind);
- }
- return (CMD_RETURN_NORMAL);
- }
-
- mtmp.key = key;
- if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) {
- RB_REMOVE(mode_key_tree, mtab->tree, mbind);
- free(mbind);
- }
- return (CMD_RETURN_NORMAL);
-}
diff --git a/cmd.c b/cmd.c
index 163db73b..f77176c9 100644
--- a/cmd.c
+++ b/cmd.c
@@ -20,7 +20,6 @@
#include <sys/time.h>
#include <fnmatch.h>
-#include <paths.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
diff --git a/compat.h b/compat.h
new file mode 100644
index 00000000..794ac67d
--- /dev/null
+++ b/compat.h
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef COMPAT_H
+#define COMPAT_H
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+
+#include <fnmatch.h>
+#include <limits.h>
+#include <stdio.h>
+#include <termios.h>
+#include <wchar.h>
+
+#ifndef __GNUC__
+#define __attribute__(a)
+#endif
+
+#ifndef __unused
+#define __unused __attribute__ ((__unused__))
+#endif
+#ifndef __dead
+#define __dead __attribute__ ((__noreturn__))
+#endif
+#ifndef __packed
+#define __packed __attribute__ ((__packed__))
+#endif
+
+#ifndef ECHOPRT
+#define ECHOPRT 0
+#endif
+
+#ifndef ACCESSPERMS
+#define ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO)
+#endif
+
+#if !defined(FIONREAD) && defined(__sun)
+#include <sys/filio.h>
+#endif
+
+#ifdef HAVE_ERR_H
+#include <err.h>
+#else
+void err(int, const char *, ...);
+void errx(int, const char *, ...);
+void warn(const char *, ...);
+void warnx(const char *, ...);
+#endif
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifndef _PATH_BSHELL
+#define _PATH_BSHELL "/bin/sh"
+#endif
+
+#ifndef _PATH_TMP
+#define _PATH_TMP "/tmp/"
+#endif
+
+#ifndef _PATH_DEVNULL
+#define _PATH_DEVNULL "/dev/null"
+#endif
+
+#ifndef _PATH_TTY
+#define _PATH_TTY "/dev/tty"
+#endif
+
+#ifndef _PATH_DEV
+#define _PATH_DEV "/dev/"
+#endif
+
+#ifndef _PATH_DEFPATH
+#define _PATH_DEFPATH "/usr/bin:/bin"
+#endif
+
+#ifndef __OpenBSD__
+#define pledge(s, p) (0)
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#else
+#include <inttypes.h>
+#endif
+
+#ifdef HAVE_QUEUE_H
+#include <sys/queue.h>
+#else
+#include "compat/queue.h"
+#endif
+
+#ifdef HAVE_TREE_H
+#include <sys/tree.h>
+#else
+#include "compat/tree.h"
+#endif
+
+#ifdef HAVE_BITSTRING_H
+#include <bitstring.h>
+#else
+#include "compat/bitstring.h"
+#endif
+
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif
+
+#ifdef HAVE_PTY_H
+#include <pty.h>
+#endif
+
+#ifdef HAVE_UTIL_H
+#include <util.h>
+#endif
+
+#ifdef HAVE_VIS
+#include <vis.h>
+#else
+#include "compat/vis.h"
+#endif
+
+#ifdef HAVE_IMSG
+#include <imsg.h>
+#else
+#include "compat/imsg.h"
+#endif
+
+#ifdef BROKEN_CMSG_FIRSTHDR
+#undef CMSG_FIRSTHDR
+#define CMSG_FIRSTHDR(mhdr) \
+ ((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \
+ (struct cmsghdr *)(mhdr)->msg_control : \
+ (struct cmsghdr *)NULL)
+#endif
+
+#ifndef CMSG_ALIGN
+#ifdef _CMSG_DATA_ALIGN
+#define CMSG_ALIGN _CMSG_DATA_ALIGN
+#else
+#define CMSG_ALIGN(len) (((len) + sizeof(long) - 1) & ~(sizeof(long) - 1))
+#endif
+#endif
+
+#ifndef CMSG_SPACE
+#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
+#endif
+
+#ifndef CMSG_LEN
+#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
+#endif
+
+#ifndef O_DIRECTORY
+#define O_DIRECTORY 0
+#endif
+
+#ifndef FNM_CASEFOLD
+#define FNM_CASEFOLD 0
+#endif
+
+#ifndef INFTIM
+#define INFTIM -1
+#endif
+
+#ifndef WAIT_ANY
+#define WAIT_ANY -1
+#endif
+
+#ifndef SUN_LEN
+#define SUN_LEN(sun) (sizeof (sun)->sun_path)
+#endif
+
+#ifndef timercmp
+#define timercmp(tvp, uvp, cmp) \
+ (((tvp)->tv_sec == (uvp)->tv_sec) ? \
+ ((tvp)->tv_usec cmp (uvp)->tv_usec) : \
+ ((tvp)->tv_sec cmp (uvp)->tv_sec))
+#endif
+
+#ifndef timeradd
+#define timeradd(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
+ if ((vvp)->tv_usec >= 1000000) { \
+ (vvp)->tv_sec++; \
+ (vvp)->tv_usec -= 1000000; \
+ } \
+ } while (0)
+#endif
+
+#ifndef timersub
+#define timersub(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif
+
+#ifndef TTY_NAME_MAX
+#define TTY_NAME_MAX 32
+#endif
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+
+#ifndef HAVE_FLOCK
+#define LOCK_SH 0
+#define LOCK_EX 0
+#define LOCK_NB 0
+#define flock(fd, op) (0)
+#endif
+
+#ifndef HAVE_EXPLICIT_BZERO
+/* explicit_bzero.c */
+void explicit_bzero(void *, size_t);
+#endif
+
+#ifndef HAVE_GETDTABLECOUNT
+/* getdtablecount.c */
+int getdtablecount(void);
+#endif
+
+#ifndef HAVE_CLOSEFROM
+/* closefrom.c */
+void closefrom(int);
+#endif
+
+#ifndef HAVE_STRCASESTR
+/* strcasestr.c */
+char *strcasestr(const char *, const char *);
+#endif
+
+#ifndef HAVE_STRSEP
+/* strsep.c */
+char *strsep(char **, const char *);
+#endif
+
+#ifndef HAVE_STRTONUM
+/* strtonum.c */
+long long strtonum(const char *, long long, long long, const char **);
+#endif
+
+#ifndef HAVE_STRLCPY
+/* strlcpy.c */
+size_t strlcpy(char *, const char *, size_t);
+#endif
+
+#ifndef HAVE_STRLCAT
+/* strlcat.c */
+size_t strlcat(char *, const char *, size_t);
+#endif
+
+#ifndef HAVE_STRNLEN
+/* strnlen.c */
+size_t strnlen(const char *, size_t);
+#endif
+
+#ifndef HAVE_STRNDUP
+/* strndup.c */
+char *strndup(const char *, size_t);
+#endif
+
+#ifndef HAVE_MEMMEM
+/* memmem.c */
+void *memmem(const void *, size_t, const void *, size_t);
+#endif
+
+#ifndef HAVE_DAEMON
+/* daemon.c */
+int daemon(int, int);
+#endif
+
+#ifndef HAVE_GETPROGNAME
+/* getprogname.c */
+const char *getprogname(void);
+#endif
+
+#ifndef HAVE_SETPROCTITLE
+/* setproctitle.c */
+void setproctitle(const char *, ...);
+#endif
+
+#ifndef HAVE_B64_NTOP
+/* base64.c */
+#undef b64_ntop
+#undef b64_pton
+int b64_ntop(const char *, size_t, char *, size_t);
+int b64_pton(const char *, u_char *, size_t);
+#endif
+
+#ifndef HAVE_FDFORKPTY
+/* fdforkpty.c */
+int getptmfd(void);
+pid_t fdforkpty(int, int *, char *, struct termios *,
+ struct winsize *);
+#endif
+
+#ifndef HAVE_FORKPTY
+/* forkpty.c */
+pid_t forkpty(int *, char *, struct termios *, struct winsize *);
+#endif
+
+#ifndef HAVE_ASPRINTF
+/* asprintf.c */
+int asprintf(char **, const char *, ...);
+int vasprintf(char **, const char *, va_list);
+#endif
+
+#ifndef HAVE_FGETLN
+/* fgetln.c */
+char *fgetln(FILE *, size_t *);
+#endif
+
+#ifndef HAVE_SETENV
+/* setenv.c */
+int setenv(const char *, const char *, int);
+int unsetenv(const char *);
+#endif
+
+#ifndef HAVE_CFMAKERAW
+/* cfmakeraw.c */
+void cfmakeraw(struct termios *);
+#endif
+
+#ifndef HAVE_FREEZERO
+/* freezero.c */
+void freezero(void *, size_t);
+#endif
+
+#ifndef HAVE_REALLOCARRAY
+/* reallocarray.c */
+void *reallocarray(void *, size_t, size_t);
+#endif
+
+#ifndef HAVE_RECALLOCARRAY
+/* recallocarray.c */
+void *recallocarray(void *, size_t, size_t, size_t);
+#endif
+
+#ifdef HAVE_UTF8PROC
+/* utf8proc.c */
+int utf8proc_wcwidth(wchar_t);
+int utf8proc_mbtowc(wchar_t *, const char *, size_t);
+int utf8proc_wctomb(char *, wchar_t);
+#endif
+
+#ifndef HAVE_GETOPT
+/* getopt.c */
+extern int BSDopterr;
+extern int BSDoptind;
+extern int BSDoptopt;
+extern int BSDoptreset;
+extern char *BSDoptarg;
+int BSDgetopt(int, char *const *, const char *);
+#define getopt(ac, av, o) BSDgetopt(ac, av, o)
+#define opterr BSDopterr
+#define optind BSDoptind
+#define optopt BSDoptopt
+#define optreset BSDoptreset
+#define optarg BSDoptarg
+#endif
+
+#endif /* COMPAT_H */
diff --git a/compat/asprintf.c b/compat/asprintf.c
new file mode 100644
index 00000000..187c19f0
--- /dev/null
+++ b/compat/asprintf.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2006 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "compat.h"
+#include "xmalloc.h"
+
+int
+asprintf(char **ret, const char *fmt, ...)
+{
+ va_list ap;
+ int n;
+
+ va_start(ap, fmt);
+ n = vasprintf(ret, fmt, ap);
+ va_end(ap);
+
+ return (n);
+}
+
+int
+vasprintf(char **ret, const char *fmt, va_list ap)
+{
+ int n;
+ va_list ap2;
+
+ va_copy(ap2, ap);
+
+ if ((n = vsnprintf(NULL, 0, fmt, ap)) < 0)
+ goto error;
+
+ *ret = xmalloc(n + 1);
+ if ((n = vsnprintf(*ret, n + 1, fmt, ap2)) < 0) {
+ free(*ret);
+ goto error;
+ }
+ va_end(ap2);
+
+ return (n);
+
+error:
+ va_end(ap2);
+ *ret = NULL;
+ return (-1);
+}
diff --git a/compat/base64.c b/compat/base64.c
new file mode 100644
index 00000000..e90696df
--- /dev/null
+++ b/compat/base64.c
@@ -0,0 +1,315 @@
+/* $OpenBSD: base64.c,v 1.8 2015/01/16 16:48:51 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <resolv.h>
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC 1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int
+b64_ntop(src, srclength, target, targsize)
+ u_char const *src;
+ size_t srclength;
+ char *target;
+ size_t targsize;
+{
+ size_t datalength = 0;
+ u_char input[3];
+ u_char output[4];
+ int i;
+
+ while (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ return (-1);
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (datalength);
+}
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+b64_pton(src, target, targsize)
+ char const *src;
+ u_char *target;
+ size_t targsize;
+{
+ int tarindex, state, ch;
+ u_char nextbyte;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = (unsigned char)*src++) != '\0') {
+ if (isspace(ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) /* A non-base64 character. */
+ return (-1);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if (tarindex >= targsize)
+ return (-1);
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if (tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ nextbyte = ((pos - Base64) & 0x0f) << 4;
+ if (tarindex + 1 < targsize)
+ target[tarindex+1] = nextbyte;
+ else if (nextbyte)
+ return (-1);
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if (tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ nextbyte = ((pos - Base64) & 0x03) << 6;
+ if (tarindex + 1 < targsize)
+ target[tarindex+1] = nextbyte;
+ else if (nextbyte)
+ return (-1);
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if (tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = (unsigned char)*src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for (; ch != '\0'; ch = (unsigned char)*src++)
+ if (!isspace(ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return (-1);
+ ch = (unsigned char)*src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for (; ch != '\0'; ch = (unsigned char)*src++)
+ if (!isspace(ch))
+ return (-1);
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && tarindex < targsize &&
+ target[tarindex] != 0)
+ return (-1);
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-1);
+ }
+
+ return (tarindex);
+}
diff --git a/compat/bitstring.h b/compat/bitstring.h
new file mode 100644
index 00000000..8fc3423e
--- /dev/null
+++ b/compat/bitstring.h
@@ -0,0 +1,128 @@
+/* $OpenBSD: bitstring.h,v 1.5 2003/06/02 19:34:12 millert Exp $ */
+/* $NetBSD: bitstring.h,v 1.5 1997/05/14 15:49:55 pk Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Vixie.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bitstring.h 8.1 (Berkeley) 7/19/93
+ */
+
+#ifndef _BITSTRING_H_
+#define _BITSTRING_H_
+
+/* modified for SV/AT and bitstring bugfix by M.R.Murphy, 11oct91
+ * bitstr_size changed gratuitously, but shorter
+ * bit_alloc spelling error fixed
+ * the following were efficient, but didn't work, they've been made to
+ * work, but are no longer as efficient :-)
+ * bit_nclear, bit_nset, bit_ffc, bit_ffs
+ */
+typedef unsigned char bitstr_t;
+
+/* internal macros */
+ /* byte of the bitstring bit is in */
+#define _bit_byte(bit) \
+ ((bit) >> 3)
+
+ /* mask for the bit within its byte */
+#define _bit_mask(bit) \
+ (1 << ((bit)&0x7))
+
+/* external macros */
+ /* bytes in a bitstring of nbits bits */
+#define bitstr_size(nbits) \
+ (((nbits) + 7) >> 3)
+
+ /* allocate a bitstring */
+#define bit_alloc(nbits) \
+ (bitstr_t *)calloc((size_t)bitstr_size(nbits), sizeof(bitstr_t))
+
+ /* allocate a bitstring on the stack */
+#define bit_decl(name, nbits) \
+ ((name)[bitstr_size(nbits)])
+
+ /* is bit N of bitstring name set? */
+#define bit_test(name, bit) \
+ ((name)[_bit_byte(bit)] & _bit_mask(bit))
+
+ /* set bit N of bitstring name */
+#define bit_set(name, bit) \
+ ((name)[_bit_byte(bit)] |= _bit_mask(bit))
+
+ /* clear bit N of bitstring name */
+#define bit_clear(name, bit) \
+ ((name)[_bit_byte(bit)] &= ~_bit_mask(bit))
+
+ /* clear bits start ... stop in bitstring */
+#define bit_nclear(name, start, stop) do { \
+ register bitstr_t *_name = name; \
+ register int _start = start, _stop = stop; \
+ while (_start <= _stop) { \
+ bit_clear(_name, _start); \
+ _start++; \
+ } \
+} while(0)
+
+ /* set bits start ... stop in bitstring */
+#define bit_nset(name, start, stop) do { \
+ register bitstr_t *_name = name; \
+ register int _start = start, _stop = stop; \
+ while (_start <= _stop) { \
+ bit_set(_name, _start); \
+ _start++; \
+ } \
+} while(0)
+
+ /* find first bit clear in name */
+#define bit_ffc(name, nbits, value) do { \
+ register bitstr_t *_name = name; \
+ register int _bit, _nbits = nbits, _value = -1; \
+ for (_bit = 0; _bit < _nbits; ++_bit) \
+ if (!bit_test(_name, _bit)) { \
+ _value = _bit; \
+ break; \
+ } \
+ *(value) = _value; \
+} while(0)
+
+ /* find first bit set in name */
+#define bit_ffs(name, nbits, value) do { \
+ register bitstr_t *_name = name; \
+ register int _bit, _nbits = nbits, _value = -1; \
+ for (_bit = 0; _bit < _nbits; ++_bit) \
+ if (bit_test(_name, _bit)) { \
+ _value = _bit; \
+ break; \
+ } \
+ *(value) = _value; \
+} while(0)
+
+#endif /* !_BITSTRING_H_ */
diff --git a/compat/cfmakeraw.c b/compat/cfmakeraw.c
new file mode 100644
index 00000000..b481a903
--- /dev/null
+++ b/compat/cfmakeraw.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Dagobert Michelsen
+ * Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <termios.h>
+
+#include "compat.h"
+
+void
+cfmakeraw(struct termios *tio)
+{
+ tio->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+ tio->c_oflag &= ~OPOST;
+ tio->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+ tio->c_cflag &= ~(CSIZE|PARENB);
+ tio->c_cflag |= CS8;
+}
diff --git a/compat/closefrom.c b/compat/closefrom.c
new file mode 100644
index 00000000..7915cde4
--- /dev/null
+++ b/compat/closefrom.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HAVE_CLOSEFROM
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <stdio.h>
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#include <limits.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#include "compat.h"
+
+#ifndef OPEN_MAX
+# define OPEN_MAX 256
+#endif
+
+#if 0
+__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $";
+#endif /* lint */
+
+/*
+ * Close all file descriptors greater than or equal to lowfd.
+ */
+#ifdef HAVE_FCNTL_CLOSEM
+void
+closefrom(int lowfd)
+{
+ (void) fcntl(lowfd, F_CLOSEM, 0);
+}
+#else
+void
+closefrom(int lowfd)
+{
+ long fd, maxfd;
+#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID)
+ char fdpath[PATH_MAX], *endp;
+ struct dirent *dent;
+ DIR *dirp;
+ int len;
+
+ /* Check for a /proc/$$/fd directory. */
+ len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid());
+ if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) {
+ while ((dent = readdir(dirp)) != NULL) {
+ fd = strtol(dent->d_name, &endp, 10);
+ if (dent->d_name != endp && *endp == '\0' &&
+ fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
+ (void) close((int) fd);
+ }
+ (void) closedir(dirp);
+ } else
+#endif
+ {
+ /*
+ * Fall back on sysconf() or getdtablesize(). We avoid checking
+ * resource limits since it is possible to open a file descriptor
+ * and then drop the rlimit such that it is below the open fd.
+ */
+#ifdef HAVE_SYSCONF
+ maxfd = sysconf(_SC_OPEN_MAX);
+#else
+ maxfd = getdtablesize();
+#endif /* HAVE_SYSCONF */
+ if (maxfd < 0)
+ maxfd = OPEN_MAX;
+
+ for (fd = lowfd; fd < maxfd; fd++)
+ (void) close((int) fd);
+ }
+}
+#endif /* !HAVE_FCNTL_CLOSEM */
+#endif /* HAVE_CLOSEFROM */
diff --git a/compat/daemon-darwin.c b/compat/daemon-darwin.c
new file mode 100644
index 00000000..64400206
--- /dev/null
+++ b/compat/daemon-darwin.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 2011-2013, Chris Johnsen <chris_johnsen@pobox.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <sys/types.h>
+
+#include <mach/mach.h>
+
+#include <Availability.h>
+#include <unistd.h>
+
+void daemon_darwin(void);
+
+#ifdef __MAC_10_10
+
+extern kern_return_t bootstrap_look_up_per_user(mach_port_t, const char *,
+ uid_t, mach_port_t *);
+extern kern_return_t bootstrap_get_root(mach_port_t, mach_port_t *);
+
+void
+daemon_darwin(void)
+{
+ mach_port_t root = MACH_PORT_NULL;
+ mach_port_t s = MACH_PORT_NULL;
+ uid_t uid;
+
+ uid = getuid();
+ if (bootstrap_get_root(bootstrap_port, &root) == KERN_SUCCESS &&
+ bootstrap_look_up_per_user(root, NULL, uid, &s) == KERN_SUCCESS &&
+ task_set_bootstrap_port(mach_task_self(), s) == KERN_SUCCESS &&
+ mach_port_deallocate(mach_task_self(), bootstrap_port) == KERN_SUCCESS)
+ bootstrap_port = s;
+}
+
+#else
+
+void
+daemon_darwin(void)
+{
+}
+
+#endif
diff --git a/compat/daemon.c b/compat/daemon.c
new file mode 100644
index 00000000..5d0c9d82
--- /dev/null
+++ b/compat/daemon.c
@@ -0,0 +1,75 @@
+/* $OpenBSD: daemon.c,v 1.6 2005/08/08 08:05:33 espie Exp $ */
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "compat.h"
+
+#ifdef __APPLE__
+extern void daemon_darwin(void);
+#endif
+
+int
+daemon(int nochdir, int noclose)
+{
+ int fd;
+
+ switch (fork()) {
+ case -1:
+ return (-1);
+ case 0:
+ break;
+ default:
+ _exit(0);
+ }
+
+ if (setsid() == -1)
+ return (-1);
+
+ if (!nochdir)
+ (void)chdir("/");
+
+ if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+ (void)dup2(fd, STDIN_FILENO);
+ (void)dup2(fd, STDOUT_FILENO);
+ (void)dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ (void)close (fd);
+ }
+
+#ifdef __APPLE__
+ daemon_darwin();
+#endif
+ return (0);
+}
diff --git a/compat/err.c b/compat/err.c
new file mode 100644
index 00000000..f470692f
--- /dev/null
+++ b/compat/err.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "compat.h"
+
+void
+err(int eval, const char *fmt, ...)
+{
+ va_list ap;
+ int saved_errno = errno;
+
+ fprintf(stderr, "%s: ", getprogname());
+
+ va_start(ap, fmt);
+ if (fmt != NULL) {
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ": ");
+ }
+ va_end(ap);
+
+ fprintf(stderr, "%s\n", strerror(saved_errno));
+ exit(eval);
+}
+
+void
+errx(int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "%s: ", getprogname());
+
+ va_start(ap, fmt);
+ if (fmt != NULL)
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ putc('\n', stderr);
+ exit(eval);
+}
+
+void
+warn(const char *fmt, ...)
+{
+ va_list ap;
+ int saved_errno = errno;
+
+ fprintf(stderr, "%s: ", getprogname());
+
+ va_start(ap, fmt);
+ if (fmt != NULL) {
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ": ");
+ }
+ va_end(ap);
+
+ fprintf(stderr, "%s\n", strerror(saved_errno));
+}
+
+void
+warnx(const char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "%s: ", getprogname());
+
+ va_start(ap, fmt);
+ if (fmt != NULL)
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ putc('\n', stderr);
+}
diff --git a/compat/explicit_bzero.c b/compat/explicit_bzero.c
new file mode 100644
index 00000000..e8bc5b36
--- /dev/null
+++ b/compat/explicit_bzero.c
@@ -0,0 +1,15 @@
+/* $OpenBSD: explicit_bzero.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */
+/*
+ * Public domain.
+ * Written by Matthew Dempsky.
+ */
+
+#include <string.h>
+
+#include "compat.h"
+
+void
+explicit_bzero(void *buf, size_t len)
+{
+ memset(buf, 0, len);
+}
diff --git a/compat/fdforkpty.c b/compat/fdforkpty.c
new file mode 100644
index 00000000..c05f0dbf
--- /dev/null
+++ b/compat/fdforkpty.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <limits.h>
+
+#include "compat.h"
+
+int
+getptmfd(void)
+{
+ return (INT_MAX);
+}
+
+pid_t
+fdforkpty(__unused int ptmfd, int *master, char *name, struct termios *tio,
+ struct winsize *ws)
+{
+ return (forkpty(master, name, tio, ws));
+}
diff --git a/compat/fgetln.c b/compat/fgetln.c
new file mode 100644
index 00000000..c71918cb
--- /dev/null
+++ b/compat/fgetln.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015 Joerg Jung <jung@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * portable fgetln() version, NOT reentrant
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "compat.h"
+
+char *
+fgetln(FILE *fp, size_t *len)
+{
+ static char *buf = NULL;
+ static size_t bufsz = 0;
+ size_t r = 0;
+ char *p;
+ int c, e;
+
+ if (!fp || !len) {
+ errno = EINVAL;
+ return NULL;
+ }
+ if (!buf) {
+ if (!(buf = calloc(1, BUFSIZ)))
+ return NULL;
+ bufsz = BUFSIZ;
+ }
+ while ((c = getc(fp)) != EOF) {
+ buf[r++] = c;
+ if (r == bufsz) {
+ if (!(p = reallocarray(buf, 2, bufsz))) {
+ e = errno;
+ free(buf);
+ errno = e;
+ buf = NULL, bufsz = 0;
+ return NULL;
+ }
+ buf = p, bufsz = 2 * bufsz;
+ }
+ if (c == '\n')
+ break;
+ }
+ return (*len = r) ? buf : NULL;
+}
diff --git a/compat/forkpty-aix.c b/compat/forkpty-aix.c
new file mode 100644
index 00000000..5eba9fd6
--- /dev/null
+++ b/compat/forkpty-aix.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stropts.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "compat.h"
+
+void fatal(const char *, ...);
+void fatalx(const char *, ...);
+
+pid_t
+forkpty(int *master, __unused char *name, struct termios *tio,
+ struct winsize *ws)
+{
+ int slave = -1, fd, pipe_fd[2];
+ char *path, dummy;
+ pid_t pid;
+
+ if (pipe(pipe_fd) == -1)
+ return (-1);
+
+ if ((*master = open("/dev/ptc", O_RDWR|O_NOCTTY)) == -1)
+ goto out;
+
+ if ((path = ttyname(*master)) == NULL)
+ goto out;
+
+ if (name != NULL)
+ strlcpy(name, path, TTY_NAME_MAX);
+
+ if ((slave = open(path, O_RDWR|O_NOCTTY)) == -1)
+ goto out;
+
+ switch (pid = fork()) {
+ case -1:
+ goto out;
+ case 0:
+ close(*master);
+
+ close(pipe_fd[1]);
+ while (read(pipe_fd[0], &dummy, 1) == -1) {
+ if (errno != EINTR)
+ break;
+ }
+ close(pipe_fd[0]);
+
+ fd = open(_PATH_TTY, O_RDWR|O_NOCTTY);
+ if (fd >= 0) {
+ ioctl(fd, TIOCNOTTY, NULL);
+ close(fd);
+ }
+
+ if (setsid() < 0)
+ fatal("setsid");
+
+ fd = open(_PATH_TTY, O_RDWR|O_NOCTTY);
+ if (fd >= 0)
+ fatalx("open succeeded (failed to disconnect)");
+
+ fd = open(path, O_RDWR);
+ if (fd < 0)
+ fatal("open failed");
+ close(fd);
+
+ fd = open("/dev/tty", O_WRONLY);
+ if (fd < 0)
+ fatal("open failed");
+ close(fd);
+
+ if (tio != NULL && tcsetattr(slave, TCSAFLUSH, tio) == -1)
+ fatal("tcsetattr failed");
+ if (ioctl(slave, TIOCSWINSZ, ws) == -1)
+ fatal("ioctl failed");
+
+ dup2(slave, 0);
+ dup2(slave, 1);
+ dup2(slave, 2);
+ if (slave > 2)
+ close(slave);
+
+ return (0);
+ }
+
+ close(slave);
+
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
+ return (pid);
+
+out:
+ if (*master != -1)
+ close(*master);
+ if (slave != -1)
+ close(slave);
+
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
+ return (-1);
+}
diff --git a/compat/forkpty-hpux.c b/compat/forkpty-hpux.c
new file mode 100644
index 00000000..64494f65
--- /dev/null
+++ b/compat/forkpty-hpux.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stropts.h>
+#include <unistd.h>
+
+#include "compat.h"
+
+void fatal(const char *, ...);
+void fatalx(const char *, ...);
+
+pid_t
+forkpty(int *master, char *name, struct termios *tio, struct winsize *ws)
+{
+ int slave = -1;
+ char *path;
+ pid_t pid;
+
+ if ((*master = open("/dev/ptmx", O_RDWR|O_NOCTTY)) == -1)
+ return (-1);
+ if (grantpt(*master) != 0)
+ goto out;
+ if (unlockpt(*master) != 0)
+ goto out;
+
+ if ((path = ptsname(*master)) == NULL)
+ goto out;
+ if (name != NULL)
+ strlcpy(name, path, TTY_NAME_MAX);
+ if ((slave = open(path, O_RDWR|O_NOCTTY)) == -1)
+ goto out;
+
+ switch (pid = fork()) {
+ case -1:
+ goto out;
+ case 0:
+ close(*master);
+
+ setsid();
+#ifdef TIOCSCTTY
+ if (ioctl(slave, TIOCSCTTY, NULL) == -1)
+ fatal("ioctl failed");
+#endif
+
+ if (ioctl(slave, I_PUSH, "ptem") == -1)
+ fatal("ioctl failed");
+ if (ioctl(slave, I_PUSH, "ldterm") == -1)
+ fatal("ioctl failed");
+
+ if (tio != NULL && tcsetattr(slave, TCSAFLUSH, tio) == -1)
+ fatal("tcsetattr failed");
+ if (ioctl(slave, TIOCSWINSZ, ws) == -1)
+ fatal("ioctl failed");
+
+ dup2(slave, 0);
+ dup2(slave, 1);
+ dup2(slave, 2);
+ if (slave > 2)
+ close(slave);
+ return (0);
+ }
+
+ close(slave);
+ return (pid);
+
+out:
+ if (*master != -1)
+ close(*master);
+ if (slave != -1)
+ close(slave);
+ return (-1);
+}
diff --git a/compat/forkpty-sunos.c b/compat/forkpty-sunos.c
new file mode 100644
index 00000000..18bba3bc
--- /dev/null
+++ b/compat/forkpty-sunos.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <stropts.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "compat.h"
+
+void fatal(const char *, ...);
+void fatalx(const char *, ...);
+
+pid_t
+forkpty(int *master, char *name, struct termios *tio, struct winsize *ws)
+{
+ int slave = -1;
+ char *path;
+ pid_t pid;
+
+ if ((*master = open("/dev/ptmx", O_RDWR|O_NOCTTY)) == -1)
+ return (-1);
+ if (grantpt(*master) != 0)
+ goto out;
+ if (unlockpt(*master) != 0)
+ goto out;
+
+ if ((path = ptsname(*master)) == NULL)
+ goto out;
+ if (name != NULL)
+ strlcpy(name, path, TTY_NAME_MAX);
+ if ((slave = open(path, O_RDWR|O_NOCTTY)) == -1)
+ goto out;
+
+ switch (pid = fork()) {
+ case -1:
+ goto out;
+ case 0:
+ close(*master);
+
+ setsid();
+#ifdef TIOCSCTTY
+ if (ioctl(slave, TIOCSCTTY, NULL) == -1)
+ fatal("ioctl failed");
+#endif
+
+ if (ioctl(slave, I_PUSH, "ptem") == -1)
+ fatal("ioctl failed");
+ if (ioctl(slave, I_PUSH, "ldterm") == -1)
+ fatal("ioctl failed");
+
+ if (tio != NULL && tcsetattr(slave, TCSAFLUSH, tio) == -1)
+ fatal("tcsetattr failed");
+ if (ioctl(slave, TIOCSWINSZ, ws) == -1)
+ fatal("ioctl failed");
+
+ dup2(slave, 0);
+ dup2(slave, 1);
+ dup2(slave, 2);
+ if (slave > 2)
+ close(slave);
+ return (0);
+ }
+
+ close(slave);
+ return (pid);
+
+out:
+ if (*master != -1)
+ close(*master);
+ if (slave != -1)
+ close(slave);
+ return (-1);
+}
diff --git a/compat/freezero.c b/compat/freezero.c
new file mode 100644
index 00000000..711a10c3
--- /dev/null
+++ b/compat/freezero.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "compat.h"
+
+void
+freezero(void *ptr, size_t size)
+{
+ if (ptr != NULL) {
+ memset(ptr, 0, size);
+ free(ptr);
+ }
+}
diff --git a/compat/getdtablecount.c b/compat/getdtablecount.c
new file mode 100644
index 00000000..1f9a0aa7
--- /dev/null
+++ b/compat/getdtablecount.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <glob.h>
+#include <unistd.h>
+
+#include "compat.h"
+
+void fatal(const char *, ...);
+void fatalx(const char *, ...);
+
+#ifdef HAVE_PROC_PID
+int
+getdtablecount(void)
+{
+ char path[PATH_MAX];
+ glob_t g;
+ int n = 0;
+
+ if (snprintf(path, sizeof path, "/proc/%ld/fd/*", (long)getpid()) < 0)
+ fatal("snprintf overflow");
+ if (glob(path, 0, NULL, &g) == 0)
+ n = g.gl_pathc;
+ globfree(&g);
+ return (n);
+}
+#else
+int
+getdtablecount(void)
+{
+ return (0);
+}
+#endif
diff --git a/compat/getopt.c b/compat/getopt.c
new file mode 100644
index 00000000..26e0e6d9
--- /dev/null
+++ b/compat/getopt.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */
+
+#include "compat.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int BSDopterr = 1, /* if error message should be printed */
+ BSDoptind = 1, /* index into parent argv vector */
+ BSDoptopt, /* character checked for validity */
+ BSDoptreset; /* reset getopt */
+char *BSDoptarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+BSDgetopt(int nargc, char *const *nargv, const char *ostr)
+{
+ static const char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ if (ostr == NULL)
+ return (-1);
+
+ if (BSDoptreset || !*place) { /* update scanning pointer */
+ BSDoptreset = 0;
+ if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') {
+ place = EMSG;
+ return (-1);
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ if (place[1])
+ return (BADCH);
+ ++BSDoptind;
+ place = EMSG;
+ return (-1);
+ }
+ } /* option letter okay? */
+ if ((BSDoptopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, BSDoptopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (BSDoptopt == (int)'-')
+ return (-1);
+ if (!*place)
+ ++BSDoptind;
+ if (BSDopterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: unknown option -- %c\n", getprogname(),
+ BSDoptopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ BSDoptarg = NULL;
+ if (!*place)
+ ++BSDoptind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ BSDoptarg = (char *)place;
+ else if (nargc <= ++BSDoptind) { /* no arg */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (BSDopterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ getprogname(), BSDoptopt);
+ return (BADCH);
+ }
+ else /* white space */
+ BSDoptarg = nargv[BSDoptind];
+ place = EMSG;
+ ++BSDoptind;
+ }
+ return (BSDoptopt); /* dump back option letter */
+}
diff --git a/compat/getprogname.c b/compat/getprogname.c
new file mode 100644
index 00000000..50afbace
--- /dev/null
+++ b/compat/getprogname.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+
+#include "compat.h"
+
+#if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
+const char *
+getprogname(void)
+{
+ return (program_invocation_short_name);
+}
+#elif defined(HAVE___PROGNAME)
+const char *
+getprogname(void)
+{
+ extern char *__progname;
+
+ return (__progname);
+}
+#else
+const char *
+getprogname(void)
+{
+ return ("tmux");
+}
+#endif
diff --git a/compat/imsg-buffer.c b/compat/imsg-buffer.c
new file mode 100644
index 00000000..814591f4
--- /dev/null
+++ b/compat/imsg-buffer.c
@@ -0,0 +1,309 @@
+/* $OpenBSD: imsg-buffer.c,v 1.11 2017/12/14 09:27:44 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "compat.h"
+#include "imsg.h"
+
+static int ibuf_realloc(struct ibuf *, size_t);
+static void ibuf_enqueue(struct msgbuf *, struct ibuf *);
+static void ibuf_dequeue(struct msgbuf *, struct ibuf *);
+
+struct ibuf *
+ibuf_open(size_t len)
+{
+ struct ibuf *buf;
+
+ if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
+ return (NULL);
+ if ((buf->buf = malloc(len)) == NULL) {
+ free(buf);
+ return (NULL);
+ }
+ buf->size = buf->max = len;
+ buf->fd = -1;
+
+ return (buf);
+}
+
+struct ibuf *
+ibuf_dynamic(size_t len, size_t max)
+{
+ struct ibuf *buf;
+
+ if (max < len)
+ return (NULL);
+
+ if ((buf = ibuf_open(len)) == NULL)
+ return (NULL);
+
+ if (max > 0)
+ buf->max = max;
+
+ return (buf);
+}
+
+static int
+ibuf_realloc(struct ibuf *buf, size_t len)
+{
+ u_char *b;
+
+ /* on static buffers max is eq size and so the following fails */
+ if (buf->wpos + len > buf->max) {
+ errno = ERANGE;
+ return (-1);
+ }
+
+ b = recallocarray(buf->buf, buf->size, buf->wpos + len, 1);
+ if (b == NULL)
+ return (-1);
+ buf->buf = b;
+ buf->size = buf->wpos + len;
+
+ return (0);
+}
+
+int
+ibuf_add(struct ibuf *buf, const void *data, size_t len)
+{
+ if (buf->wpos + len > buf->size)
+ if (ibuf_realloc(buf, len) == -1)
+ return (-1);
+
+ memcpy(buf->buf + buf->wpos, data, len);
+ buf->wpos += len;
+ return (0);
+}
+
+void *
+ibuf_reserve(struct ibuf *buf, size_t len)
+{
+ void *b;
+
+ if (buf->wpos + len > buf->size)
+ if (ibuf_realloc(buf, len) == -1)
+ return (NULL);
+
+ b = buf->buf + buf->wpos;
+ buf->wpos += len;
+ return (b);
+}
+
+void *
+ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
+{
+ /* only allowed to seek in already written parts */
+ if (pos + len > buf->wpos)
+ return (NULL);
+
+ return (buf->buf + pos);
+}
+
+size_t
+ibuf_size(struct ibuf *buf)
+{
+ return (buf->wpos);
+}
+
+size_t
+ibuf_left(struct ibuf *buf)
+{
+ return (buf->max - buf->wpos);
+}
+
+void
+ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
+{
+ ibuf_enqueue(msgbuf, buf);
+}
+
+int
+ibuf_write(struct msgbuf *msgbuf)
+{
+ struct iovec iov[IOV_MAX];
+ struct ibuf *buf;
+ unsigned int i = 0;
+ ssize_t n;
+
+ memset(&iov, 0, sizeof(iov));
+ TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
+ if (i >= IOV_MAX)
+ break;
+ iov[i].iov_base = buf->buf + buf->rpos;
+ iov[i].iov_len = buf->wpos - buf->rpos;
+ i++;
+ }
+
+again:
+ if ((n = writev(msgbuf->fd, iov, i)) == -1) {
+ if (errno == EINTR)
+ goto again;
+ if (errno == ENOBUFS)
+ errno = EAGAIN;
+ return (-1);
+ }
+
+ if (n == 0) { /* connection closed */
+ errno = 0;
+ return (0);
+ }
+
+ msgbuf_drain(msgbuf, n);
+
+ return (1);
+}
+
+void
+ibuf_free(struct ibuf *buf)
+{
+ if (buf == NULL)
+ return;
+ freezero(buf->buf, buf->size);
+ free(buf);
+}
+
+void
+msgbuf_init(struct msgbuf *msgbuf)
+{
+ msgbuf->queued = 0;
+ msgbuf->fd = -1;
+ TAILQ_INIT(&msgbuf->bufs);
+}
+
+void
+msgbuf_drain(struct msgbuf *msgbuf, size_t n)
+{
+ struct ibuf *buf, *next;
+
+ for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
+ buf = next) {
+ next = TAILQ_NEXT(buf, entry);
+ if (buf->rpos + n >= buf->wpos) {
+ n -= buf->wpos - buf->rpos;
+ ibuf_dequeue(msgbuf, buf);
+ } else {
+ buf->rpos += n;
+ n = 0;
+ }
+ }
+}
+
+void
+msgbuf_clear(struct msgbuf *msgbuf)
+{
+ struct ibuf *buf;
+
+ while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
+ ibuf_dequeue(msgbuf, buf);
+}
+
+int
+msgbuf_write(struct msgbuf *msgbuf)
+{
+ struct iovec iov[IOV_MAX];
+ struct ibuf *buf;
+ unsigned int i = 0;
+ ssize_t n;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ union {
+ struct cmsghdr hdr;
+ char buf[CMSG_SPACE(sizeof(int))];
+ } cmsgbuf;
+
+ memset(&iov, 0, sizeof(iov));
+ memset(&msg, 0, sizeof(msg));
+ memset(&cmsgbuf, 0, sizeof(cmsgbuf));
+ TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
+ if (i >= IOV_MAX)
+ break;
+ iov[i].iov_base = buf->buf + buf->rpos;
+ iov[i].iov_len = buf->wpos - buf->rpos;
+ i++;
+ if (buf->fd != -1)
+ break;
+ }
+
+ msg.msg_iov = iov;
+ msg.msg_iovlen = i;
+
+ if (buf != NULL && buf->fd != -1) {
+ msg.msg_control = (caddr_t)&cmsgbuf.buf;
+ msg.msg_controllen = sizeof(cmsgbuf.buf);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ *(int *)CMSG_DATA(cmsg) = buf->fd;
+ }
+
+again:
+ if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
+ if (errno == EINTR)
+ goto again;
+ if (errno == ENOBUFS)
+ errno = EAGAIN;
+ return (-1);
+ }
+
+ if (n == 0) { /* connection closed */
+ errno = 0;
+ return (0);
+ }
+
+ /*
+ * assumption: fd got sent if sendmsg sent anything
+ * this works because fds are passed one at a time
+ */
+ if (buf != NULL && buf->fd != -1) {
+ close(buf->fd);
+ buf->fd = -1;
+ }
+
+ msgbuf_drain(msgbuf, n);
+
+ return (1);
+}
+
+static void
+ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
+{
+ TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
+ msgbuf->queued++;
+}
+
+static void
+ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
+{
+ TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
+
+ if (buf->fd != -1)
+ close(buf->fd);
+
+ msgbuf->queued--;
+ ibuf_free(buf);
+}
diff --git a/compat/imsg.c b/compat/imsg.c
new file mode 100644
index 00000000..54ac7e56
--- /dev/null
+++ b/compat/imsg.c
@@ -0,0 +1,302 @@
+/* $OpenBSD: imsg.c,v 1.16 2017/12/14 09:27:44 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "compat.h"
+#include "imsg.h"
+
+int imsg_fd_overhead = 0;
+
+static int imsg_get_fd(struct imsgbuf *);
+
+void
+imsg_init(struct imsgbuf *ibuf, int fd)
+{
+ msgbuf_init(&ibuf->w);
+ memset(&ibuf->r, 0, sizeof(ibuf->r));
+ ibuf->fd = fd;
+ ibuf->w.fd = fd;
+ ibuf->pid = getpid();
+ TAILQ_INIT(&ibuf->fds);
+}
+
+ssize_t
+imsg_read(struct imsgbuf *ibuf)
+{
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ union {
+ struct cmsghdr hdr;
+ char buf[CMSG_SPACE(sizeof(int) * 1)];
+ } cmsgbuf;
+ struct iovec iov;
+ ssize_t n = -1;
+ int fd;
+ struct imsg_fd *ifd;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&cmsgbuf, 0, sizeof(cmsgbuf));
+
+ iov.iov_base = ibuf->r.buf + ibuf->r.wpos;
+ iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &cmsgbuf.buf;
+ msg.msg_controllen = sizeof(cmsgbuf.buf);
+
+ if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL)
+ return (-1);
+
+again:
+ if (getdtablecount() + imsg_fd_overhead +
+ (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))
+ >= getdtablesize()) {
+ errno = EAGAIN;
+ free(ifd);
+ return (-1);
+ }
+
+ if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
+ if (errno == EINTR)
+ goto again;
+ goto fail;
+ }
+
+ ibuf->r.wpos += n;
+
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS) {
+ int i;
+ int j;
+
+ /*
+ * We only accept one file descriptor. Due to C
+ * padding rules, our control buffer might contain
+ * more than one fd, and we must close them.
+ */
+ j = ((char *)cmsg + cmsg->cmsg_len -
+ (char *)CMSG_DATA(cmsg)) / sizeof(int);
+ for (i = 0; i < j; i++) {
+ fd = ((int *)CMSG_DATA(cmsg))[i];
+ if (ifd != NULL) {
+ ifd->fd = fd;
+ TAILQ_INSERT_TAIL(&ibuf->fds, ifd,
+ entry);
+ ifd = NULL;
+ } else
+ close(fd);
+ }
+ }
+ /* we do not handle other ctl data level */
+ }
+
+fail:
+ free(ifd);
+ return (n);
+}
+
+ssize_t
+imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
+{
+ size_t av, left, datalen;
+
+ av = ibuf->r.wpos;
+
+ if (IMSG_HEADER_SIZE > av)
+ return (0);
+
+ memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr));
+ if (imsg->hdr.len < IMSG_HEADER_SIZE ||
+ imsg->hdr.len > MAX_IMSGSIZE) {
+ errno = ERANGE;
+ return (-1);
+ }
+ if (imsg->hdr.len > av)
+ return (0);
+ datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
+ ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
+ if (datalen == 0)
+ imsg->data = NULL;
+ else if ((imsg->data = malloc(datalen)) == NULL)
+ return (-1);
+
+ if (imsg->hdr.flags & IMSGF_HASFD)
+ imsg->fd = imsg_get_fd(ibuf);
+ else
+ imsg->fd = -1;
+
+ memcpy(imsg->data, ibuf->r.rptr, datalen);
+
+ if (imsg->hdr.len < av) {
+ left = av - imsg->hdr.len;
+ memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left);
+ ibuf->r.wpos = left;
+ } else
+ ibuf->r.wpos = 0;
+
+ return (datalen + IMSG_HEADER_SIZE);
+}
+
+int
+imsg_compose(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
+ int fd, const void *data, uint16_t datalen)
+{
+ struct ibuf *wbuf;
+
+ if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
+ return (-1);
+
+ if (imsg_add(wbuf, data, datalen) == -1)
+ return (-1);
+
+ wbuf->fd = fd;
+
+ imsg_close(ibuf, wbuf);
+
+ return (1);
+}
+
+int
+imsg_composev(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
+ int fd, const struct iovec *iov, int iovcnt)
+{
+ struct ibuf *wbuf;
+ int i, datalen = 0;
+
+ for (i = 0; i < iovcnt; i++)
+ datalen += iov[i].iov_len;
+
+ if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
+ return (-1);
+
+ for (i = 0; i < iovcnt; i++)
+ if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
+ return (-1);
+
+ wbuf->fd = fd;
+
+ imsg_close(ibuf, wbuf);
+
+ return (1);
+}
+
+/* ARGSUSED */
+struct ibuf *
+imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
+ uint16_t datalen)
+{
+ struct ibuf *wbuf;
+ struct imsg_hdr hdr;
+
+ datalen += IMSG_HEADER_SIZE;
+ if (datalen > MAX_IMSGSIZE) {
+ errno = ERANGE;
+ return (NULL);
+ }
+
+ hdr.type = type;
+ hdr.flags = 0;
+ hdr.peerid = peerid;
+ if ((hdr.pid = pid) == 0)
+ hdr.pid = ibuf->pid;
+ if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
+ return (NULL);
+ }
+ if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
+ return (NULL);
+
+ return (wbuf);
+}
+
+int
+imsg_add(struct ibuf *msg, const void *data, uint16_t datalen)
+{
+ if (datalen)
+ if (ibuf_add(msg, data, datalen) == -1) {
+ ibuf_free(msg);
+ return (-1);
+ }
+ return (datalen);
+}
+
+void
+imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
+{
+ struct imsg_hdr *hdr;
+
+ hdr = (struct imsg_hdr *)msg->buf;
+
+ hdr->flags &= ~IMSGF_HASFD;
+ if (msg->fd != -1)
+ hdr->flags |= IMSGF_HASFD;
+
+ hdr->len = (uint16_t)msg->wpos;
+
+ ibuf_close(&ibuf->w, msg);
+}
+
+void
+imsg_free(struct imsg *imsg)
+{
+ freezero(imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE);
+}
+
+static int
+imsg_get_fd(struct imsgbuf *ibuf)
+{
+ int fd;
+ struct imsg_fd *ifd;
+
+ if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL)
+ return (-1);
+
+ fd = ifd->fd;
+ TAILQ_REMOVE(&ibuf->fds, ifd, entry);
+ free(ifd);
+
+ return (fd);
+}
+
+int
+imsg_flush(struct imsgbuf *ibuf)
+{
+ while (ibuf->w.queued)
+ if (msgbuf_write(&ibuf->w) <= 0)
+ return (-1);
+ return (0);
+}
+
+void
+imsg_clear(struct imsgbuf *ibuf)
+{
+ int fd;
+
+ msgbuf_clear(&ibuf->w);
+ while ((fd = imsg_get_fd(ibuf)) != -1)
+ close(fd);
+}
diff --git a/compat/imsg.h b/compat/imsg.h
new file mode 100644
index 00000000..8bf94147
--- /dev/null
+++ b/compat/imsg.h
@@ -0,0 +1,111 @@
+/* $OpenBSD: imsg.h,v 1.4 2017/03/24 09:34:12 nicm Exp $ */
+
+/*
+ * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
+ * Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _IMSG_H_
+#define _IMSG_H_
+
+#define IBUF_READ_SIZE 65535
+#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
+#define MAX_IMSGSIZE 16384
+
+struct ibuf {
+ TAILQ_ENTRY(ibuf) entry;
+ u_char *buf;
+ size_t size;
+ size_t max;
+ size_t wpos;
+ size_t rpos;
+ int fd;
+};
+
+struct msgbuf {
+ TAILQ_HEAD(, ibuf) bufs;
+ uint32_t queued;
+ int fd;
+};
+
+struct ibuf_read {
+ u_char buf[IBUF_READ_SIZE];
+ u_char *rptr;
+ size_t wpos;
+};
+
+struct imsg_fd {
+ TAILQ_ENTRY(imsg_fd) entry;
+ int fd;
+};
+
+struct imsgbuf {
+ TAILQ_HEAD(, imsg_fd) fds;
+ struct ibuf_read r;
+ struct msgbuf w;
+ int fd;
+ pid_t pid;
+};
+
+#define IMSGF_HASFD 1
+
+struct imsg_hdr {
+ uint32_t type;
+ uint16_t len;
+ uint16_t flags;
+ uint32_t peerid;
+ uint32_t pid;
+};
+
+struct imsg {
+ struct imsg_hdr hdr;
+ int fd;
+ void *data;
+};
+
+
+/* buffer.c */
+struct ibuf *ibuf_open(size_t);
+struct ibuf *ibuf_dynamic(size_t, size_t);
+int ibuf_add(struct ibuf *, const void *, size_t);
+void *ibuf_reserve(struct ibuf *, size_t);
+void *ibuf_seek(struct ibuf *, size_t, size_t);
+size_t ibuf_size(struct ibuf *);
+size_t ibuf_left(struct ibuf *);
+void ibuf_close(struct msgbuf *, struct ibuf *);
+int ibuf_write(struct msgbuf *);
+void ibuf_free(struct ibuf *);
+void msgbuf_init(struct msgbuf *);
+void msgbuf_clear(struct msgbuf *);
+int msgbuf_write(struct msgbuf *);
+void msgbuf_drain(struct msgbuf *, size_t);
+
+/* imsg.c */
+void imsg_init(struct imsgbuf *, int);
+ssize_t imsg_read(struct imsgbuf *);
+ssize_t imsg_get(struct imsgbuf *, struct imsg *);
+int imsg_compose(struct imsgbuf *, uint32_t, uint32_t, pid_t, int,
+ const void *, uint16_t);
+int imsg_composev(struct imsgbuf *, uint32_t, uint32_t, pid_t, int,
+ const struct iovec *, int);
+struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, uint16_t);
+int imsg_add(struct ibuf *, const void *, uint16_t);
+void imsg_close(struct imsgbuf *, struct ibuf *);
+void imsg_free(struct imsg *);
+int imsg_flush(struct imsgbuf *);
+void imsg_clear(struct imsgbuf *);
+
+#endif
diff --git a/compat/memmem.c b/compat/memmem.c
new file mode 100644
index 00000000..99e3f55d
--- /dev/null
+++ b/compat/memmem.c
@@ -0,0 +1,65 @@
+/* $OpenBSD: memmem.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */
+/*-
+ * Copyright (c) 2005 Pascal Gloor <pascal.gloor@spale.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "compat.h"
+
+/*
+ * Find the first occurrence of the byte string s in byte string l.
+ */
+
+void *
+memmem(const void *l, size_t l_len, const void *s, size_t s_len)
+{
+ const char *cur, *last;
+ const char *cl = l;
+ const char *cs = s;
+
+ /* a zero length needle should just return the haystack */
+ if (s_len == 0)
+ return (void *)cl;
+
+ /* "s" must be smaller or equal to "l" */
+ if (l_len < s_len)
+ return NULL;
+
+ /* special case where s_len == 1 */
+ if (s_len == 1)
+ return memchr(l, *cs, l_len);
+
+ /* the last position where its possible to find "s" in "l" */
+ last = cl + l_len - s_len;
+
+ for (cur = cl; cur <= last; cur++)
+ if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
+ return (void *)cur;
+
+ return NULL;
+}
diff --git a/compat/queue.h b/compat/queue.h
new file mode 100644
index 00000000..a20532cd
--- /dev/null
+++ b/compat/queue.h
@@ -0,0 +1,533 @@
+/* $OpenBSD: queue.h,v 1.44 2016/09/09 20:31:46 millert Exp $ */
+/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues and XOR simple queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * An XOR simple queue is used in the same way as a regular simple queue.
+ * The difference is that the head structure also includes a "cookie" that
+ * is XOR'd with the queue pointer (first, last or next) to generate the
+ * real pointer value.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
+#define _Q_INVALIDATE(a) (a) = ((void *)-1)
+#else
+#define _Q_INVALIDATE(a)
+#endif
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define SLIST_FIRST(head) ((head)->slh_first)
+#define SLIST_END(head) NULL
+#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_FOREACH(var, head, field) \
+ for((var) = SLIST_FIRST(head); \
+ (var) != SLIST_END(head); \
+ (var) = SLIST_NEXT(var, field))
+
+#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SLIST_FIRST(head); \
+ (var) && ((tvar) = SLIST_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_INIT(head) { \
+ SLIST_FIRST(head) = SLIST_END(head); \
+}
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
+ (slistelm)->field.sle_next = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.sle_next = (head)->slh_first; \
+ (head)->slh_first = (elm); \
+} while (0)
+
+#define SLIST_REMOVE_AFTER(elm, field) do { \
+ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ (head)->slh_first = (head)->slh_first->field.sle_next; \
+} while (0)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ if ((head)->slh_first == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->slh_first; \
+ \
+ while (curelm->field.sle_next != (elm)) \
+ curelm = curelm->field.sle_next; \
+ curelm->field.sle_next = \
+ curelm->field.sle_next->field.sle_next; \
+ } \
+ _Q_INVALIDATE((elm)->field.sle_next); \
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List access methods.
+ */
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_END(head) NULL
+#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field) \
+ for((var) = LIST_FIRST(head); \
+ (var)!= LIST_END(head); \
+ (var) = LIST_NEXT(var, field))
+
+#define LIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = LIST_FIRST(head); \
+ (var) && ((tvar) = LIST_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * List functions.
+ */
+#define LIST_INIT(head) do { \
+ LIST_FIRST(head) = LIST_END(head); \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (0)
+
+#define LIST_REMOVE(elm, field) do { \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+ _Q_INVALIDATE((elm)->field.le_prev); \
+ _Q_INVALIDATE((elm)->field.le_next); \
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do { \
+ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
+ (elm2)->field.le_next->field.le_prev = \
+ &(elm2)->field.le_next; \
+ (elm2)->field.le_prev = (elm)->field.le_prev; \
+ *(elm2)->field.le_prev = (elm2); \
+ _Q_INVALIDATE((elm)->field.le_prev); \
+ _Q_INVALIDATE((elm)->field.le_next); \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqe_next; /* next element */ \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for((var) = SIMPLEQ_FIRST(head); \
+ (var) != SIMPLEQ_END(head); \
+ (var) = SIMPLEQ_NEXT(var, field))
+
+#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SIMPLEQ_FIRST(head); \
+ (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Simple queue functions.
+ */
+#define SIMPLEQ_INIT(head) do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
+ == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+#define SIMPLEQ_CONCAT(head1, head2) do { \
+ if (!SIMPLEQ_EMPTY((head2))) { \
+ *(head1)->sqh_last = (head2)->sqh_first; \
+ (head1)->sqh_last = (head2)->sqh_last; \
+ SIMPLEQ_INIT((head2)); \
+ } \
+} while (0)
+
+/*
+ * XOR Simple queue definitions.
+ */
+#define XSIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqx_first; /* first element */ \
+ struct type **sqx_last; /* addr of last next element */ \
+ unsigned long sqx_cookie; \
+}
+
+#define XSIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqx_next; /* next element */ \
+}
+
+/*
+ * XOR Simple queue access methods.
+ */
+#define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \
+ (unsigned long)(ptr)))
+#define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first))
+#define XSIMPLEQ_END(head) NULL
+#define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
+#define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
+
+
+#define XSIMPLEQ_FOREACH(var, head, field) \
+ for ((var) = XSIMPLEQ_FIRST(head); \
+ (var) != XSIMPLEQ_END(head); \
+ (var) = XSIMPLEQ_NEXT(head, var, field))
+
+#define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = XSIMPLEQ_FIRST(head); \
+ (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * XOR Simple queue functions.
+ */
+#define XSIMPLEQ_INIT(head) do { \
+ arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
+ (head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
+} while (0)
+
+#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqx_next = (head)->sqx_first) == \
+ XSIMPLEQ_XOR(head, NULL)) \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+ (head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \
+} while (0)
+
+#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \
+ *(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+} while (0)
+
+#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \
+ XSIMPLEQ_XOR(head, NULL)) \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+ (listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \
+} while (0)
+
+#define XSIMPLEQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->sqx_first = XSIMPLEQ_XOR(head, \
+ (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
+} while (0)
+
+#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
+ if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \
+ (elm)->field.sqx_next)->field.sqx_next) \
+ == XSIMPLEQ_XOR(head, NULL)) \
+ (head)->sqx_last = \
+ XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+} while (0)
+
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+/*
+ * Tail queue access methods.
+ */
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_END(head) NULL
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define TAILQ_EMPTY(head) \
+ (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field) \
+ for((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_NEXT(var, field))
+
+#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head) && \
+ ((tvar) = TAILQ_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_PREV(var, headname, field))
+
+#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
+ for ((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head) && \
+ ((tvar) = TAILQ_PREV(var, headname, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) do { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+ _Q_INVALIDATE((elm)->field.tqe_prev); \
+ _Q_INVALIDATE((elm)->field.tqe_next); \
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
+ (elm2)->field.tqe_next->field.tqe_prev = \
+ &(elm2)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm2)->field.tqe_next; \
+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
+ *(elm2)->field.tqe_prev = (elm2); \
+ _Q_INVALIDATE((elm)->field.tqe_prev); \
+ _Q_INVALIDATE((elm)->field.tqe_next); \
+} while (0)
+
+#define TAILQ_CONCAT(head1, head2, field) do { \
+ if (!TAILQ_EMPTY(head2)) { \
+ *(head1)->tqh_last = (head2)->tqh_first; \
+ (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
+ (head1)->tqh_last = (head2)->tqh_last; \
+ TAILQ_INIT((head2)); \
+ } \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/compat/reallocarray.c b/compat/reallocarray.c
new file mode 100644
index 00000000..ba17e3f4
--- /dev/null
+++ b/compat/reallocarray.c
@@ -0,0 +1,40 @@
+/* $OpenBSD: reallocarray.c,v 1.3 2015/09/13 08:31:47 guenther Exp $ */
+/*
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "compat.h"
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+
+void *
+reallocarray(void *optr, size_t nmemb, size_t size)
+{
+ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ nmemb > 0 && SIZE_MAX / nmemb < size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return realloc(optr, size * nmemb);
+}
diff --git a/compat/recallocarray.c b/compat/recallocarray.c
new file mode 100644
index 00000000..74a919a1
--- /dev/null
+++ b/compat/recallocarray.c
@@ -0,0 +1,82 @@
+/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */
+/*
+ * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "compat.h"
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+
+void *
+recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
+{
+ size_t oldsize, newsize;
+ void *newptr;
+
+ if (ptr == NULL)
+ return calloc(newnmemb, size);
+
+ if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ newnmemb > 0 && SIZE_MAX / newnmemb < size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ newsize = newnmemb * size;
+
+ if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
+ errno = EINVAL;
+ return NULL;
+ }
+ oldsize = oldnmemb * size;
+
+ /*
+ * Don't bother too much if we're shrinking just a bit,
+ * we do not shrink for series of small steps, oh well.
+ */
+ if (newsize <= oldsize) {
+ size_t d = oldsize - newsize;
+
+ if (d < oldsize / 2 && d < (size_t)getpagesize()) {
+ memset((char *)ptr + newsize, 0, d);
+ return ptr;
+ }
+ }
+
+ newptr = malloc(newsize);
+ if (newptr == NULL)
+ return NULL;
+
+ if (newsize > oldsize) {
+ memcpy(newptr, ptr, oldsize);
+ memset((char *)newptr + oldsize, 0, newsize - oldsize);
+ } else
+ memcpy(newptr, ptr, newsize);
+
+ explicit_bzero(ptr, oldsize);
+ free(ptr);
+
+ return newptr;
+}
diff --git a/compat/setenv.c b/compat/setenv.c
new file mode 100644
index 00000000..d9235bcc
--- /dev/null
+++ b/compat/setenv.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010 Dagobert Michelsen
+ * Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "compat.h"
+
+int
+setenv(const char *name, const char *value, __unused int overwrite)
+{
+ char *newval;
+
+ xasprintf(&newval, "%s=%s", name, value);
+ return (putenv(newval));
+}
+
+int
+unsetenv(const char *name)
+{
+ char **envptr;
+ int namelen;
+
+ namelen = strlen(name);
+ for (envptr = environ; *envptr != NULL; envptr++) {
+ if (strncmp(name, *envptr, namelen) == 0 &&
+ ((*envptr)[namelen] == '=' || (*envptr)[namelen] == '\0'))
+ break;
+ }
+ for (; *envptr != NULL; envptr++)
+ *envptr = *(envptr + 1);
+ return (0);
+}
diff --git a/compat/setproctitle.c b/compat/setproctitle.c
new file mode 100644
index 00000000..e72ae274
--- /dev/null
+++ b/compat/setproctitle.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "compat.h"
+
+#if defined(HAVE_PRCTL) && defined(HAVE_PR_SET_NAME)
+
+#include <sys/prctl.h>
+
+void
+setproctitle(const char *fmt, ...)
+{
+ char title[16], name[16], *cp;
+ va_list ap;
+ int used;
+
+ va_start(ap, fmt);
+ vsnprintf(title, sizeof title, fmt, ap);
+ va_end(ap);
+
+ used = snprintf(name, sizeof name, "%s: %s", getprogname(), title);
+ if (used >= (int)sizeof name) {
+ cp = strrchr(name, ' ');
+ if (cp != NULL)
+ *cp = '\0';
+ }
+ prctl(PR_SET_NAME, name);
+}
+#else
+void
+setproctitle(__unused const char *fmt, ...)
+{
+}
+#endif
diff --git a/compat/strcasestr.c b/compat/strcasestr.c
new file mode 100644
index 00000000..8679cf88
--- /dev/null
+++ b/compat/strcasestr.c
@@ -0,0 +1,62 @@
+/* $OpenBSD: strcasestr.c,v 1.3 2006/03/31 05:34:55 deraadt Exp $ */
+/* $NetBSD: strcasestr.c,v 1.2 2005/02/09 21:35:47 kleink Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+#include <string.h>
+
+#include "compat.h"
+
+/*
+ * Find the first occurrence of find in s, ignore case.
+ */
+char *
+strcasestr(const char *s, const char *find)
+{
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != 0) {
+ c = (char)tolower((unsigned char)c);
+ len = strlen(find);
+ do {
+ do {
+ if ((sc = *s++) == 0)
+ return (NULL);
+ } while ((char)tolower((unsigned char)sc) != c);
+ } while (strncasecmp(s, find, len) != 0);
+ s--;
+ }
+ return ((char *)s);
+}
diff --git a/compat/strlcat.c b/compat/strlcat.c
new file mode 100644
index 00000000..836e3929
--- /dev/null
+++ b/compat/strlcat.c
@@ -0,0 +1,57 @@
+/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+#include "compat.h"
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
diff --git a/compat/strlcpy.c b/compat/strlcpy.c
new file mode 100644
index 00000000..46a22240
--- /dev/null
+++ b/compat/strlcpy.c
@@ -0,0 +1,53 @@
+/* $OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+#include "compat.h"
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
diff --git a/compat/strndup.c b/compat/strndup.c
new file mode 100644
index 00000000..32bec6ab
--- /dev/null
+++ b/compat/strndup.c
@@ -0,0 +1,41 @@
+/* $OpenBSD: strndup.c,v 1.2 2015/08/31 02:53:57 guenther Exp $ */
+
+/*
+ * Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "compat.h"
+
+char *
+strndup(const char *str, size_t maxlen)
+{
+ char *copy;
+ size_t len;
+
+ len = strnlen(str, maxlen);
+ copy = malloc(len + 1);
+ if (copy != NULL) {
+ (void)memcpy(copy, str, len);
+ copy[len] = '\0';
+ }
+
+ return copy;
+}
diff --git a/compat/strnlen.c b/compat/strnlen.c
new file mode 100644
index 00000000..eeeb833d
--- /dev/null
+++ b/compat/strnlen.c
@@ -0,0 +1,34 @@
+/* $OpenBSD: strnlen.c,v 1.8 2016/10/16 17:37:39 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+
+#include "compat.h"
+
+size_t
+strnlen(const char *str, size_t maxlen)
+{
+ const char *cp;
+
+ for (cp = str; maxlen != 0 && *cp != '\0'; cp++, maxlen--)
+ ;
+
+ return (size_t)(cp - str);
+}
diff --git a/compat/strsep.c b/compat/strsep.c
new file mode 100644
index 00000000..58584587
--- /dev/null
+++ b/compat/strsep.c
@@ -0,0 +1,73 @@
+/* $OpenBSD: strsep.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "compat.h"
+
+/*
+ * Get next token from string *stringp, where tokens are possibly-empty
+ * strings separated by characters from delim.
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+char *
+strsep(char **stringp, const char *delim)
+{
+ char *s;
+ const char *spanp;
+ int c, sc;
+ char *tok;
+
+ if ((s = *stringp) == NULL)
+ return (NULL);
+ for (tok = s;;) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
diff --git a/compat/strtonum.c b/compat/strtonum.c
new file mode 100644
index 00000000..25a58615
--- /dev/null
+++ b/compat/strtonum.c
@@ -0,0 +1,67 @@
+/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */
+
+/*
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "compat.h"
+
+#define INVALID 1
+#define TOOSMALL 2
+#define TOOLARGE 3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+ const char **errstrp)
+{
+ long long ll = 0;
+ char *ep;
+ int error = 0;
+ struct errval {
+ const char *errstr;
+ int err;
+ } ev[4] = {
+ { NULL, 0 },
+ { "invalid", EINVAL },
+ { "too small", ERANGE },
+ { "too large", ERANGE },
+ };
+
+ ev[0].err = errno;
+ errno = 0;
+ if (minval > maxval)
+ error = INVALID;
+ else {
+ ll = strtoll(numstr, &ep, 10);
+ if (numstr == ep || *ep != '\0')
+ error = INVALID;
+ else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+ error = TOOSMALL;
+ else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+ error = TOOLARGE;
+ }
+ if (errstrp != NULL)
+ *errstrp = ev[error].errstr;
+ errno = ev[error].err;
+ if (error)
+ ll = 0;
+
+ return (ll);
+}
diff --git a/compat/tree.h b/compat/tree.h
new file mode 100644
index 00000000..80d0f538
--- /dev/null
+++ b/compat/tree.h
@@ -0,0 +1,748 @@
+/* $OpenBSD: tree.h,v 1.13 2011/07/09 00:19:45 pirofti Exp $ */
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_TREE_H_
+#define _SYS_TREE_H_
+
+/*
+ * This file defines data structures for different types of trees:
+ * splay trees and red-black trees.
+ *
+ * A splay tree is a self-organizing data structure. Every operation
+ * on the tree causes a splay to happen. The splay moves the requested
+ * node to the root of the tree and partly rebalances it.
+ *
+ * This has the benefit that request locality causes faster lookups as
+ * the requested nodes move to the top of the tree. On the other hand,
+ * every lookup causes memory writes.
+ *
+ * The Balance Theorem bounds the total access time for m operations
+ * and n inserts on an initially empty tree as O((m + n)lg n). The
+ * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
+ *
+ * A red-black tree is a binary search tree with the node color as an
+ * extra attribute. It fulfills a set of conditions:
+ * - every search path from the root to a leaf consists of the
+ * same number of black nodes,
+ * - each red node (except for the root) has a black parent,
+ * - each leaf node is black.
+ *
+ * Every operation on a red-black tree is bounded as O(lg n).
+ * The maximum height of a red-black tree is 2lg (n+1).
+ */
+
+#define SPLAY_HEAD(name, type) \
+struct name { \
+ struct type *sph_root; /* root of the tree */ \
+}
+
+#define SPLAY_INITIALIZER(root) \
+ { NULL }
+
+#define SPLAY_INIT(root) do { \
+ (root)->sph_root = NULL; \
+} while (0)
+
+#define SPLAY_ENTRY(type) \
+struct { \
+ struct type *spe_left; /* left element */ \
+ struct type *spe_right; /* right element */ \
+}
+
+#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
+#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
+#define SPLAY_ROOT(head) (head)->sph_root
+#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
+
+/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
+#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (0)
+
+#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (0)
+
+#define SPLAY_LINKLEFT(head, tmp, field) do { \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
+} while (0)
+
+#define SPLAY_LINKRIGHT(head, tmp, field) do { \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
+} while (0)
+
+#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
+ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
+ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
+} while (0)
+
+/* Generates prototypes and inline functions */
+
+#define SPLAY_PROTOTYPE(name, type, field, cmp) \
+void name##_SPLAY(struct name *, struct type *); \
+void name##_SPLAY_MINMAX(struct name *, int); \
+struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
+struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
+ \
+/* Finds the node with the same key as elm */ \
+static __inline struct type * \
+name##_SPLAY_FIND(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) \
+ return(NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) \
+ return (head->sph_root); \
+ return (NULL); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_NEXT(struct name *head, struct type *elm) \
+{ \
+ name##_SPLAY(head, elm); \
+ if (SPLAY_RIGHT(elm, field) != NULL) { \
+ elm = SPLAY_RIGHT(elm, field); \
+ while (SPLAY_LEFT(elm, field) != NULL) { \
+ elm = SPLAY_LEFT(elm, field); \
+ } \
+ } else \
+ elm = NULL; \
+ return (elm); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_MIN_MAX(struct name *head, int val) \
+{ \
+ name##_SPLAY_MINMAX(head, val); \
+ return (SPLAY_ROOT(head)); \
+}
+
+/* Main splay operation.
+ * Moves node close to the key of elm to top
+ */
+#define SPLAY_GENERATE(name, type, field, cmp) \
+struct type * \
+name##_SPLAY_INSERT(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) { \
+ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
+ } else { \
+ int __comp; \
+ name##_SPLAY(head, elm); \
+ __comp = (cmp)(elm, (head)->sph_root); \
+ if(__comp < 0) { \
+ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
+ SPLAY_RIGHT(elm, field) = (head)->sph_root; \
+ SPLAY_LEFT((head)->sph_root, field) = NULL; \
+ } else if (__comp > 0) { \
+ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
+ SPLAY_LEFT(elm, field) = (head)->sph_root; \
+ SPLAY_RIGHT((head)->sph_root, field) = NULL; \
+ } else \
+ return ((head)->sph_root); \
+ } \
+ (head)->sph_root = (elm); \
+ return (NULL); \
+} \
+ \
+struct type * \
+name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *__tmp; \
+ if (SPLAY_EMPTY(head)) \
+ return (NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) { \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
+ } else { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
+ name##_SPLAY(head, elm); \
+ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
+ } \
+ return (elm); \
+ } \
+ return (NULL); \
+} \
+ \
+void \
+name##_SPLAY(struct name *head, struct type *elm) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+ int __comp; \
+\
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+ __left = __right = &__node; \
+\
+ while ((__comp = (cmp)(elm, (head)->sph_root))) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) > 0){ \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+} \
+ \
+/* Splay with either the minimum or the maximum element \
+ * Used to find minimum or maximum element in tree. \
+ */ \
+void name##_SPLAY_MINMAX(struct name *head, int __comp) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+\
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+ __left = __right = &__node; \
+\
+ while (1) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp > 0) { \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+}
+
+#define SPLAY_NEGINF -1
+#define SPLAY_INF 1
+
+#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
+#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
+#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
+#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
+#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
+#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
+
+#define SPLAY_FOREACH(x, name, head) \
+ for ((x) = SPLAY_MIN(name, head); \
+ (x) != NULL; \
+ (x) = SPLAY_NEXT(name, head, x))
+
+/* Macros that define a red-black tree */
+#define RB_HEAD(name, type) \
+struct name { \
+ struct type *rbh_root; /* root of the tree */ \
+}
+
+#define RB_INITIALIZER(root) \
+ { NULL }
+
+#define RB_INIT(root) do { \
+ (root)->rbh_root = NULL; \
+} while (0)
+
+#define RB_BLACK 0
+#define RB_RED 1
+#define RB_ENTRY(type) \
+struct { \
+ struct type *rbe_left; /* left element */ \
+ struct type *rbe_right; /* right element */ \
+ struct type *rbe_parent; /* parent element */ \
+ int rbe_color; /* node color */ \
+}
+
+#define RB_LEFT(elm, field) (elm)->field.rbe_left
+#define RB_RIGHT(elm, field) (elm)->field.rbe_right
+#define RB_PARENT(elm, field) (elm)->field.rbe_parent
+#define RB_COLOR(elm, field) (elm)->field.rbe_color
+#define RB_ROOT(head) (head)->rbh_root
+#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
+
+#define RB_SET(elm, parent, field) do { \
+ RB_PARENT(elm, field) = parent; \
+ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
+ RB_COLOR(elm, field) = RB_RED; \
+} while (0)
+
+#define RB_SET_BLACKRED(black, red, field) do { \
+ RB_COLOR(black, field) = RB_BLACK; \
+ RB_COLOR(red, field) = RB_RED; \
+} while (0)
+
+#ifndef RB_AUGMENT
+#define RB_AUGMENT(x) do {} while (0)
+#endif
+
+#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
+ (tmp) = RB_RIGHT(elm, field); \
+ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \
+ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_LEFT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (0)
+
+#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
+ (tmp) = RB_LEFT(elm, field); \
+ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \
+ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_RIGHT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (0)
+
+/* Generates prototypes and inline functions */
+#define RB_PROTOTYPE(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
+#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static)
+#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
+attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
+attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
+attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
+attr struct type *name##_RB_INSERT(struct name *, struct type *); \
+attr struct type *name##_RB_FIND(struct name *, struct type *); \
+attr struct type *name##_RB_NFIND(struct name *, struct type *); \
+attr struct type *name##_RB_NEXT(struct type *); \
+attr struct type *name##_RB_PREV(struct type *); \
+attr struct type *name##_RB_MINMAX(struct name *, int); \
+ \
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
+#define RB_GENERATE(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp,)
+#define RB_GENERATE_STATIC(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static)
+#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
+attr void \
+name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
+{ \
+ struct type *parent, *gparent, *tmp; \
+ while ((parent = RB_PARENT(elm, field)) && \
+ RB_COLOR(parent, field) == RB_RED) { \
+ gparent = RB_PARENT(parent, field); \
+ if (parent == RB_LEFT(gparent, field)) { \
+ tmp = RB_RIGHT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field);\
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_RIGHT(parent, field) == elm) { \
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_RIGHT(head, gparent, tmp, field); \
+ } else { \
+ tmp = RB_LEFT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field);\
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_LEFT(parent, field) == elm) { \
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_LEFT(head, gparent, tmp, field); \
+ } \
+ } \
+ RB_COLOR(head->rbh_root, field) = RB_BLACK; \
+} \
+ \
+attr void \
+name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
+{ \
+ struct type *tmp; \
+ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
+ elm != RB_ROOT(head)) { \
+ if (RB_LEFT(parent, field) == elm) { \
+ tmp = RB_RIGHT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
+ struct type *oleft; \
+ if ((oleft = RB_LEFT(tmp, field)))\
+ RB_COLOR(oleft, field) = RB_BLACK;\
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_RIGHT(head, tmp, oleft, field);\
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_RIGHT(tmp, field)) \
+ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } else { \
+ tmp = RB_LEFT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ tmp = RB_LEFT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
+ struct type *oright; \
+ if ((oright = RB_RIGHT(tmp, field)))\
+ RB_COLOR(oright, field) = RB_BLACK;\
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_LEFT(head, tmp, oright, field);\
+ tmp = RB_LEFT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_LEFT(tmp, field)) \
+ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } \
+ } \
+ if (elm) \
+ RB_COLOR(elm, field) = RB_BLACK; \
+} \
+ \
+attr struct type * \
+name##_RB_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *child, *parent, *old = elm; \
+ int color; \
+ if (RB_LEFT(elm, field) == NULL) \
+ child = RB_RIGHT(elm, field); \
+ else if (RB_RIGHT(elm, field) == NULL) \
+ child = RB_LEFT(elm, field); \
+ else { \
+ struct type *left; \
+ elm = RB_RIGHT(elm, field); \
+ while ((left = RB_LEFT(elm, field))) \
+ elm = left; \
+ child = RB_RIGHT(elm, field); \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+ if (RB_PARENT(elm, field) == old) \
+ parent = elm; \
+ (elm)->field = (old)->field; \
+ if (RB_PARENT(old, field)) { \
+ if (RB_LEFT(RB_PARENT(old, field), field) == old)\
+ RB_LEFT(RB_PARENT(old, field), field) = elm;\
+ else \
+ RB_RIGHT(RB_PARENT(old, field), field) = elm;\
+ RB_AUGMENT(RB_PARENT(old, field)); \
+ } else \
+ RB_ROOT(head) = elm; \
+ RB_PARENT(RB_LEFT(old, field), field) = elm; \
+ if (RB_RIGHT(old, field)) \
+ RB_PARENT(RB_RIGHT(old, field), field) = elm; \
+ if (parent) { \
+ left = parent; \
+ do { \
+ RB_AUGMENT(left); \
+ } while ((left = RB_PARENT(left, field))); \
+ } \
+ goto color; \
+ } \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+color: \
+ if (color == RB_BLACK) \
+ name##_RB_REMOVE_COLOR(head, parent, child); \
+ return (old); \
+} \
+ \
+/* Inserts a node into the RB tree */ \
+attr struct type * \
+name##_RB_INSERT(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp; \
+ struct type *parent = NULL; \
+ int comp = 0; \
+ tmp = RB_ROOT(head); \
+ while (tmp) { \
+ parent = tmp; \
+ comp = (cmp)(elm, parent); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ RB_SET(elm, parent, field); \
+ if (parent != NULL) { \
+ if (comp < 0) \
+ RB_LEFT(parent, field) = elm; \
+ else \
+ RB_RIGHT(parent, field) = elm; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = elm; \
+ name##_RB_INSERT_COLOR(head, elm); \
+ return (NULL); \
+} \
+ \
+/* Finds the node with the same key as elm */ \
+attr struct type * \
+name##_RB_FIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (NULL); \
+} \
+ \
+/* Finds the first node greater than or equal to the search key */ \
+attr struct type * \
+name##_RB_NFIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *res = NULL; \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) { \
+ res = tmp; \
+ tmp = RB_LEFT(tmp, field); \
+ } \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (res); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_NEXT(struct type *elm) \
+{ \
+ if (RB_RIGHT(elm, field)) { \
+ elm = RB_RIGHT(elm, field); \
+ while (RB_LEFT(elm, field)) \
+ elm = RB_LEFT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_PREV(struct type *elm) \
+{ \
+ if (RB_LEFT(elm, field)) { \
+ elm = RB_LEFT(elm, field); \
+ while (RB_RIGHT(elm, field)) \
+ elm = RB_RIGHT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field)))\
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+attr struct type * \
+name##_RB_MINMAX(struct name *head, int val) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *parent = NULL; \
+ while (tmp) { \
+ parent = tmp; \
+ if (val < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else \
+ tmp = RB_RIGHT(tmp, field); \
+ } \
+ return (parent); \
+}
+
+#define RB_NEGINF -1
+#define RB_INF 1
+
+#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
+#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
+#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
+#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
+#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
+#define RB_PREV(name, x, y) name##_RB_PREV(y)
+#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
+#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
+
+#define RB_FOREACH(x, name, head) \
+ for ((x) = RB_MIN(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_NEXT(x))
+
+#define RB_FOREACH_SAFE(x, name, head, y) \
+ for ((x) = RB_MIN(name, head); \
+ ((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \
+ (x) = (y))
+
+#define RB_FOREACH_REVERSE(x, name, head) \
+ for ((x) = RB_MAX(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_PREV(x))
+
+#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
+ for ((x) = RB_MAX(name, head); \
+ ((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \
+ (x) = (y))
+
+#endif /* _SYS_TREE_H_ */
diff --git a/compat/unvis.c b/compat/unvis.c
new file mode 100644
index 00000000..6108e772
--- /dev/null
+++ b/compat/unvis.c
@@ -0,0 +1,281 @@
+/* $OpenBSD: unvis.c,v 1.12 2005/08/08 08:05:34 espie Exp $ */
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+
+#include "compat.h"
+
+/*
+ * decode driven by state machine
+ */
+#define S_GROUND 0 /* haven't seen escape char */
+#define S_START 1 /* start decoding special sequence */
+#define S_META 2 /* metachar started (M) */
+#define S_META1 3 /* metachar more, regular char (-) */
+#define S_CTRL 4 /* control char started (^) */
+#define S_OCTAL2 5 /* octal digit 2 */
+#define S_OCTAL3 6 /* octal digit 3 */
+
+#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+
+/*
+ * unvis - decode characters previously encoded by vis
+ */
+int
+unvis(char *cp, char c, int *astate, int flag)
+{
+
+ if (flag & UNVIS_END) {
+ if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ }
+ return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
+ }
+
+ switch (*astate) {
+
+ case S_GROUND:
+ *cp = 0;
+ if (c == '\\') {
+ *astate = S_START;
+ return (0);
+ }
+ *cp = c;
+ return (UNVIS_VALID);
+
+ case S_START:
+ switch(c) {
+ case '\\':
+ *cp = c;
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ *cp = (c - '0');
+ *astate = S_OCTAL2;
+ return (0);
+ case 'M':
+ *cp = (char) 0200;
+ *astate = S_META;
+ return (0);
+ case '^':
+ *astate = S_CTRL;
+ return (0);
+ case 'n':
+ *cp = '\n';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'r':
+ *cp = '\r';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'b':
+ *cp = '\b';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'a':
+ *cp = '\007';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'v':
+ *cp = '\v';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 't':
+ *cp = '\t';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'f':
+ *cp = '\f';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 's':
+ *cp = ' ';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'E':
+ *cp = '\033';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case '\n':
+ /*
+ * hidden newline
+ */
+ *astate = S_GROUND;
+ return (UNVIS_NOCHAR);
+ case '$':
+ /*
+ * hidden marker
+ */
+ *astate = S_GROUND;
+ return (UNVIS_NOCHAR);
+ }
+ *astate = S_GROUND;
+ return (UNVIS_SYNBAD);
+
+ case S_META:
+ if (c == '-')
+ *astate = S_META1;
+ else if (c == '^')
+ *astate = S_CTRL;
+ else {
+ *astate = S_GROUND;
+ return (UNVIS_SYNBAD);
+ }
+ return (0);
+
+ case S_META1:
+ *astate = S_GROUND;
+ *cp |= c;
+ return (UNVIS_VALID);
+
+ case S_CTRL:
+ if (c == '?')
+ *cp |= 0177;
+ else
+ *cp |= c & 037;
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+
+ case S_OCTAL2: /* second possible octal digit */
+ if (isoctal(c)) {
+ /*
+ * yes - and maybe a third
+ */
+ *cp = (*cp << 3) + (c - '0');
+ *astate = S_OCTAL3;
+ return (0);
+ }
+ /*
+ * no - done with current sequence, push back passed char
+ */
+ *astate = S_GROUND;
+ return (UNVIS_VALIDPUSH);
+
+ case S_OCTAL3: /* third possible octal digit */
+ *astate = S_GROUND;
+ if (isoctal(c)) {
+ *cp = (*cp << 3) + (c - '0');
+ return (UNVIS_VALID);
+ }
+ /*
+ * we were done, push back passed char
+ */
+ return (UNVIS_VALIDPUSH);
+
+ default:
+ /*
+ * decoder in unknown state - (probably uninitialized)
+ */
+ *astate = S_GROUND;
+ return (UNVIS_SYNBAD);
+ }
+}
+
+/*
+ * strunvis - decode src into dst
+ *
+ * Number of chars decoded into dst is returned, -1 on error.
+ * Dst is null terminated.
+ */
+
+int
+strunvis(char *dst, const char *src)
+{
+ char c;
+ char *start = dst;
+ int state = 0;
+
+ while ((c = *src++)) {
+ again:
+ switch (unvis(dst, c, &state, 0)) {
+ case UNVIS_VALID:
+ dst++;
+ break;
+ case UNVIS_VALIDPUSH:
+ dst++;
+ goto again;
+ case 0:
+ case UNVIS_NOCHAR:
+ break;
+ default:
+ *dst = '\0';
+ return (-1);
+ }
+ }
+ if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
+ dst++;
+ *dst = '\0';
+ return (dst - start);
+}
+
+ssize_t
+strnunvis(char *dst, const char *src, size_t sz)
+{
+ char c, p;
+ char *start = dst, *end = dst + sz - 1;
+ int state = 0;
+
+ if (sz > 0)
+ *end = '\0';
+ while ((c = *src++)) {
+ again:
+ switch (unvis(&p, c, &state, 0)) {
+ case UNVIS_VALID:
+ if (dst < end)
+ *dst = p;
+ dst++;
+ break;
+ case UNVIS_VALIDPUSH:
+ if (dst < end)
+ *dst = p;
+ dst++;
+ goto again;
+ case 0:
+ case UNVIS_NOCHAR:
+ break;
+ default:
+ if (dst <= end)
+ *dst = '\0';
+ return (-1);
+ }
+ }
+ if (unvis(&p, c, &state, UNVIS_END) == UNVIS_VALID) {
+ if (dst < end)
+ *dst = p;
+ dst++;
+ }
+ if (dst <= end)
+ *dst = '\0';
+ return (dst - start);
+}
+
diff --git a/compat/utf8proc.c b/compat/utf8proc.c
new file mode 100644
index 00000000..dd4ab27f
--- /dev/null
+++ b/compat/utf8proc.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016 Joshua Rubin <joshua@rubixconsulting.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <utf8proc.h>
+
+#include "compat.h"
+
+int
+utf8proc_wcwidth(wchar_t wc)
+{
+ int cat;
+
+ cat = utf8proc_category(wc);
+ if (cat == UTF8PROC_CATEGORY_CO) {
+ /*
+ * The private use category is where powerline and similar
+ * codepoints are stored, they have "ambiguous" width - use 1.
+ */
+ return (1);
+ }
+ return (utf8proc_charwidth(wc));
+}
+
+int
+utf8proc_mbtowc(wchar_t *pwc, const char *s, size_t n)
+{
+ utf8proc_ssize_t slen;
+
+ if (s == NULL)
+ return (0);
+
+ /*
+ * *pwc == -1 indicates invalid codepoint
+ * slen < 0 indicates an error
+ */
+ slen = utf8proc_iterate(s, n, pwc);
+ if (*pwc == (wchar_t)-1 || slen < 0)
+ return (-1);
+ return (slen);
+}
+
+int
+utf8proc_wctomb(char *s, wchar_t wc)
+{
+ if (s == NULL)
+ return (0);
+
+ if (!utf8proc_codepoint_valid(wc))
+ return (-1);
+ return (utf8proc_encode_char(wc, s));
+}
diff --git a/compat/vis.c b/compat/vis.c
new file mode 100644
index 00000000..3d37805b
--- /dev/null
+++ b/compat/vis.c
@@ -0,0 +1,242 @@
+/* $OpenBSD: vis.c,v 1.24 2015/07/20 01:52:28 millert Exp $ */
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "compat.h"
+
+#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+#define isvisible(c,flag) \
+ (((c) == '\\' || (flag & VIS_ALL) == 0) && \
+ (((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) && \
+ (((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') || \
+ (flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) || \
+ ((flag & VIS_SP) == 0 && (c) == ' ') || \
+ ((flag & VIS_TAB) == 0 && (c) == '\t') || \
+ ((flag & VIS_NL) == 0 && (c) == '\n') || \
+ ((flag & VIS_SAFE) && ((c) == '\b' || \
+ (c) == '\007' || (c) == '\r' || \
+ isgraph((u_char)(c))))))
+
+/*
+ * vis - visually encode characters
+ */
+char *
+vis(char *dst, int c, int flag, int nextc)
+{
+ if (isvisible(c, flag)) {
+ if ((c == '"' && (flag & VIS_DQ) != 0) ||
+ (c == '\\' && (flag & VIS_NOSLASH) == 0))
+ *dst++ = '\\';
+ *dst++ = c;
+ *dst = '\0';
+ return (dst);
+ }
+
+ if (flag & VIS_CSTYLE) {
+ switch(c) {
+ case '\n':
+ *dst++ = '\\';
+ *dst++ = 'n';
+ goto done;
+ case '\r':
+ *dst++ = '\\';
+ *dst++ = 'r';
+ goto done;
+ case '\b':
+ *dst++ = '\\';
+ *dst++ = 'b';
+ goto done;
+ case '\a':
+ *dst++ = '\\';
+ *dst++ = 'a';
+ goto done;
+ case '\v':
+ *dst++ = '\\';
+ *dst++ = 'v';
+ goto done;
+ case '\t':
+ *dst++ = '\\';
+ *dst++ = 't';
+ goto done;
+ case '\f':
+ *dst++ = '\\';
+ *dst++ = 'f';
+ goto done;
+ case ' ':
+ *dst++ = '\\';
+ *dst++ = 's';
+ goto done;
+ case '\0':
+ *dst++ = '\\';
+ *dst++ = '0';
+ if (isoctal(nextc)) {
+ *dst++ = '0';
+ *dst++ = '0';
+ }
+ goto done;
+ }
+ }
+ if (((c & 0177) == ' ') || (flag & VIS_OCTAL) ||
+ ((flag & VIS_GLOB) && (c == '*' || c == '?' || c == '[' || c == '#'))) {
+ *dst++ = '\\';
+ *dst++ = ((u_char)c >> 6 & 07) + '0';
+ *dst++ = ((u_char)c >> 3 & 07) + '0';
+ *dst++ = ((u_char)c & 07) + '0';
+ goto done;
+ }
+ if ((flag & VIS_NOSLASH) == 0)
+ *dst++ = '\\';
+ if (c & 0200) {
+ c &= 0177;
+ *dst++ = 'M';
+ }
+ if (iscntrl((u_char)c)) {
+ *dst++ = '^';
+ if (c == 0177)
+ *dst++ = '?';
+ else
+ *dst++ = c + '@';
+ } else {
+ *dst++ = '-';
+ *dst++ = c;
+ }
+done:
+ *dst = '\0';
+ return (dst);
+}
+
+/*
+ * strvis, strnvis, strvisx - visually encode characters from src into dst
+ *
+ * Dst must be 4 times the size of src to account for possible
+ * expansion. The length of dst, not including the trailing NULL,
+ * is returned.
+ *
+ * Strnvis will write no more than siz-1 bytes (and will NULL terminate).
+ * The number of bytes needed to fully encode the string is returned.
+ *
+ * Strvisx encodes exactly len bytes from src into dst.
+ * This is useful for encoding a block of data.
+ */
+int
+strvis(char *dst, const char *src, int flag)
+{
+ char c;
+ char *start;
+
+ for (start = dst; (c = *src);)
+ dst = vis(dst, c, flag, *++src);
+ *dst = '\0';
+ return (dst - start);
+}
+
+int
+strnvis(char *dst, const char *src, size_t siz, int flag)
+{
+ char *start, *end;
+ char tbuf[5];
+ int c, i;
+
+ i = 0;
+ for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) {
+ if (isvisible(c, flag)) {
+ if ((c == '"' && (flag & VIS_DQ) != 0) ||
+ (c == '\\' && (flag & VIS_NOSLASH) == 0)) {
+ /* need space for the extra '\\' */
+ if (dst + 1 >= end) {
+ i = 2;
+ break;
+ }
+ *dst++ = '\\';
+ }
+ i = 1;
+ *dst++ = c;
+ src++;
+ } else {
+ i = vis(tbuf, c, flag, *++src) - tbuf;
+ if (dst + i <= end) {
+ memcpy(dst, tbuf, i);
+ dst += i;
+ } else {
+ src--;
+ break;
+ }
+ }
+ }
+ if (siz > 0)
+ *dst = '\0';
+ if (dst + i > end) {
+ /* adjust return value for truncation */
+ while ((c = *src))
+ dst += vis(tbuf, c, flag, *++src) - tbuf;
+ }
+ return (dst - start);
+}
+
+int
+stravis(char **outp, const char *src, int flag)
+{
+ char *buf;
+ int len, serrno;
+
+ buf = calloc(4, strlen(src) + 1);
+ if (buf == NULL)
+ return -1;
+ len = strvis(buf, src, flag);
+ serrno = errno;
+ *outp = realloc(buf, len + 1);
+ if (*outp == NULL) {
+ *outp = buf;
+ errno = serrno;
+ }
+ return (len);
+}
+
+int
+strvisx(char *dst, const char *src, size_t len, int flag)
+{
+ char c;
+ char *start;
+
+ for (start = dst; len > 1; len--) {
+ c = *src;
+ dst = vis(dst, c, flag, *++src);
+ }
+ if (len)
+ dst = vis(dst, *src, flag, '\0');
+ *dst = '\0';
+ return (dst - start);
+}
diff --git a/compat/vis.h b/compat/vis.h
new file mode 100644
index 00000000..9f12d236
--- /dev/null
+++ b/compat/vis.h
@@ -0,0 +1,85 @@
+/* $OpenBSD: vis.h,v 1.15 2015/07/20 01:52:27 millert Exp $ */
+/* $NetBSD: vis.h,v 1.4 1994/10/26 00:56:41 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)vis.h 5.9 (Berkeley) 4/3/91
+ */
+
+#ifndef _VIS_H_
+#define _VIS_H_
+
+/*
+ * to select alternate encoding format
+ */
+#define VIS_OCTAL 0x01 /* use octal \ddd format */
+#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */
+
+/*
+ * to alter set of characters encoded (default is to encode all
+ * non-graphic except space, tab, and newline).
+ */
+#define VIS_SP 0x04 /* also encode space */
+#define VIS_TAB 0x08 /* also encode tab */
+#define VIS_NL 0x10 /* also encode newline */
+#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL)
+#define VIS_SAFE 0x20 /* only encode "unsafe" characters */
+#define VIS_DQ 0x200 /* backslash-escape double quotes */
+#define VIS_ALL 0x400 /* encode all characters */
+
+/*
+ * other
+ */
+#define VIS_NOSLASH 0x40 /* inhibit printing '\' */
+#define VIS_GLOB 0x100 /* encode glob(3) magics and '#' */
+
+/*
+ * unvis return codes
+ */
+#define UNVIS_VALID 1 /* character valid */
+#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */
+#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */
+#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */
+#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */
+
+/*
+ * unvis flags
+ */
+#define UNVIS_END 1 /* no more characters */
+
+char *vis(char *, int, int, int);
+int strvis(char *, const char *, int);
+int stravis(char **, const char *, int);
+int strnvis(char *, const char *, size_t, int);
+int strvisx(char *, const char *, size_t, int);
+int strunvis(char *, const char *);
+int unvis(char *, char, int *, int);
+ssize_t strnunvis(char *, const char *, size_t);
+
+#endif /* !_VIS_H_ */
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 00000000..5fba1eaf
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,655 @@
+# configure.ac
+
+AC_INIT([tmux], next-3.1)
+AC_PREREQ([2.60])
+
+AC_CONFIG_AUX_DIR(etc)
+AC_CONFIG_LIBOBJ_DIR(compat)
+AM_INIT_AUTOMAKE([foreign subdir-objects])
+
+AC_CANONICAL_HOST
+
+# When CFLAGS isn't set at this stage and gcc is detected by the macro below,
+# autoconf will automatically use CFLAGS="-O2 -g". Prevent that by using an
+# empty default.
+: ${CFLAGS=""}
+
+# Save user CPPFLAGS, CFLAGS and LDFLAGS. We need to change them because
+# AC_CHECK_HEADER doesn't give us any other way to update the include
+# paths. But for Makefile.am we want to use AM_CPPFLAGS and friends.
+SAVED_CFLAGS="$CFLAGS"
+SAVED_CPPFLAGS="$CPPFLAGS"
+SAVED_LDFLAGS="$LDFLAGS"
+
+# Set up the compiler in two different ways and say yes we may want to install.
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_CC_C99
+AC_PROG_CPP
+AC_PROG_EGREP
+AC_PROG_INSTALL
+AC_PROG_YACC
+PKG_PROG_PKG_CONFIG
+AC_USE_SYSTEM_EXTENSIONS
+
+# Default tmux.conf goes in /etc not ${prefix}/etc.
+test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc
+
+# Is this --enable-debug?
+case "x$VERSION" in xnext*) enable_debug=yes;; esac
+AC_ARG_ENABLE(
+ debug,
+ AC_HELP_STRING(--enable-debug, enable debug build flags),
+)
+AM_CONDITIONAL(IS_DEBUG, test "x$enable_debug" = xyes)
+
+# Is this a static build?
+AC_ARG_ENABLE(
+ static,
+ AC_HELP_STRING(--enable-static, create a static build)
+)
+if test "x$enable_static" = xyes; then
+ test "x$PKG_CONFIG" != x && PKG_CONFIG="$PKG_CONFIG --static"
+ AM_LDFLAGS="-static $AM_LDFLAGS"
+ LDFLAGS="$AM_LDFLAGS $SAVED_LDFLAGS"
+fi
+
+# Is this gcc?
+AM_CONDITIONAL(IS_GCC, test "x$GCC" = xyes)
+
+# Is this Sun CC?
+AC_EGREP_CPP(
+ yes,
+ [
+ #ifdef __SUNPRO_C
+ yes
+ #endif
+ ],
+ found_suncc=yes,
+ found_suncc=no
+)
+AM_CONDITIONAL(IS_SUNCC, test "x$found_suncc" = xyes)
+
+# Check for various headers. Alternatives included from compat.h.
+AC_CHECK_HEADERS([ \
+ bitstring.h \
+ dirent.h \
+ fcntl.h \
+ inttypes.h \
+ libutil.h \
+ ndir.h \
+ paths.h \
+ pty.h \
+ stdint.h \
+ sys/dir.h \
+ sys/ndir.h \
+ sys/tree.h \
+ util.h \
+])
+
+# Look for library needed for flock.
+AC_SEARCH_LIBS(flock, bsd)
+
+# Check for functions that are replaced or omitted.
+AC_CHECK_FUNCS([ \
+ dirfd \
+ flock \
+ prctl \
+ sysconf \
+])
+
+# Check for functions with a compatibility implementation.
+AC_REPLACE_FUNCS([ \
+ asprintf \
+ cfmakeraw \
+ closefrom \
+ explicit_bzero \
+ fgetln \
+ freezero \
+ getdtablecount \
+ getprogname \
+ memmem \
+ recallocarray \
+ reallocarray \
+ setenv \
+ setproctitle \
+ strcasestr \
+ strlcat \
+ strlcpy \
+ strndup \
+ strsep \
+ strtonum \
+])
+AC_FUNC_STRNLEN
+
+# Look for clock_gettime. Must come before event_init.
+AC_SEARCH_LIBS(clock_gettime, rt)
+
+# Look for libevent.
+PKG_CHECK_MODULES(
+ LIBEVENT,
+ libevent,
+ [
+ AM_CFLAGS="$LIBEVENT_CFLAGS $AM_CFLAGS"
+ CFLAGS="$AM_CFLAGS $SAVED_CFLAGS"
+ LIBS="$LIBEVENT_LIBS $LIBS"
+ found_libevent=yes
+ ],
+ [
+ AC_SEARCH_LIBS(
+ event_init,
+ [event event-1.4 event2],
+ found_libevent=yes,
+ found_libevent=no
+ )
+ ]
+)
+AC_CHECK_HEADER(
+ event.h,
+ ,
+ found_libevent=no
+)
+if test "x$found_libevent" = xno; then
+ AC_MSG_ERROR("libevent not found")
+fi
+
+# Look for ncurses.
+PKG_CHECK_MODULES(
+ LIBTINFO,
+ tinfo,
+ found_ncurses=yes,
+ found_ncurses=no
+)
+if test "x$found_ncurses" = xno; then
+ PKG_CHECK_MODULES(
+ LIBNCURSES,
+ ncurses,
+ found_ncurses=yes,
+ found_ncurses=no
+ )
+fi
+if test "x$found_ncurses" = xno; then
+ PKG_CHECK_MODULES(
+ LIBNCURSES,
+ ncursesw,
+ found_ncurses=yes,
+ found_ncurses=no
+ )
+fi
+if test "x$found_ncurses" = xyes; then
+ AM_CFLAGS="$LIBNCURSES_CFLAGS $LIBTINFO_CFLAGS $AM_CFLAGS"
+ CFLAGS="$LIBNCURSES_CFLAGS $LIBTINFO_CFLAGS $CFLAGS"
+ LIBS="$LIBNCURSES_LIBS $LIBTINFO_LIBS $LIBS"
+else
+ # pkg-config didn't work, try ncurses.
+ AC_CHECK_LIB(
+ tinfo,
+ setupterm,
+ found_ncurses=yes,
+ found_ncurses=no
+ )
+ if test "x$found_ncurses" = xno; then
+ AC_CHECK_LIB(
+ ncurses,
+ setupterm,
+ found_ncurses=yes,
+ found_ncurses=no
+ )
+ fi
+ if test "x$found_ncurses" = xyes; then
+ AC_CHECK_HEADER(
+ ncurses.h,
+ LIBS="$LIBS -lncurses",
+ found_ncurses=no)
+ fi
+fi
+if test "x$found_ncurses" = xyes; then
+ AC_DEFINE(HAVE_NCURSES_H)
+else
+ # No ncurses, try curses.
+ AC_CHECK_LIB(
+ curses,
+ setupterm,
+ found_curses=yes,
+ found_curses=no
+ )
+ AC_CHECK_HEADER(
+ curses.h,
+ ,
+ found_curses=no)
+ if test "x$found_curses" = xyes; then
+ LIBS="$LIBS -lcurses"
+ AC_DEFINE(HAVE_CURSES_H)
+ else
+ AC_MSG_ERROR("curses not found")
+ fi
+fi
+
+# Look for utempter.
+AC_ARG_ENABLE(
+ utempter,
+ AC_HELP_STRING(--enable-utempter, use utempter if it is installed)
+)
+if test "x$enable_utempter" = xyes; then
+ AC_CHECK_HEADER(utempter.h, enable_utempter=yes, enable_utempter=no)
+ if test "x$enable_utempter" = xyes; then
+ AC_SEARCH_LIBS(
+ utempter_add_record,
+ utempter,
+ enable_utempter=yes,
+ enable_utempter=no
+ )
+ fi
+ if test "x$enable_utempter" = xyes; then
+ AC_DEFINE(HAVE_UTEMPTER)
+ else
+ AC_MSG_ERROR("utempter not found")
+ fi
+fi
+
+# Look for utf8proc.
+AC_ARG_ENABLE(
+ utf8proc,
+ AC_HELP_STRING(--enable-utf8proc, use utf8proc if it is installed)
+)
+if test "x$enable_utf8proc" = xyes; then
+ AC_CHECK_HEADER(utf8proc.h, enable_utf8proc=yes, enable_utf8proc=no)
+ if test "x$enable_utf8proc" = xyes; then
+ AC_SEARCH_LIBS(
+ utf8proc_charwidth,
+ utf8proc,
+ enable_utf8proc=yes,
+ enable_utf8proc=no
+ )
+ fi
+ if test "x$enable_utf8proc" = xyes; then
+ AC_DEFINE(HAVE_UTF8PROC)
+ else
+ AC_MSG_ERROR("utf8proc not found")
+ fi
+fi
+AM_CONDITIONAL(HAVE_UTF8PROC, [test "x$enable_utf8proc" = xyes])
+
+# Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well.
+AC_MSG_CHECKING(for b64_ntop)
+AC_TRY_LINK(
+ [
+ #include <sys/types.h>
+ #include <netinet/in.h>
+ #include <resolv.h>
+ ],
+ [b64_ntop(NULL, 0, NULL, 0);],
+ found_b64_ntop=yes,
+ found_b64_ntop=no
+)
+if test "x$found_b64_ntop" = xno; then
+ AC_MSG_RESULT(no)
+
+ AC_MSG_CHECKING(for b64_ntop with -lresolv)
+ OLD_LIBS="$LIBS"
+ LIBS="$LIBS -lresolv"
+ AC_TRY_LINK(
+ [
+ #include <sys/types.h>
+ #include <netinet/in.h>
+ #include <resolv.h>
+ ],
+ [b64_ntop(NULL, 0, NULL, 0);],
+ found_b64_ntop=yes,
+ found_b64_ntop=no
+ )
+ if test "x$found_b64_ntop" = xno; then
+ LIBS="$OLD_LIBS"
+ AC_MSG_RESULT(no)
+ fi
+fi
+if test "x$found_b64_ntop" = xyes; then
+ AC_DEFINE(HAVE_B64_NTOP)
+ AC_MSG_RESULT(yes)
+else
+ AC_LIBOBJ(base64)
+fi
+
+# Look for networking libraries.
+AC_SEARCH_LIBS(inet_ntoa, nsl)
+AC_SEARCH_LIBS(socket, socket)
+AC_CHECK_LIB(xnet, socket)
+
+# Check for CMSG_DATA. Some platforms require _XOPEN_SOURCE_EXTENDED (for
+# example see xopen_networking(7) on HP-UX).
+XOPEN_DEFINES=
+AC_MSG_CHECKING(for CMSG_DATA)
+AC_EGREP_CPP(
+ yes,
+ [
+ #include <sys/socket.h>
+ #ifdef CMSG_DATA
+ yes
+ #endif
+ ],
+ found_cmsg_data=yes,
+ found_cmsg_data=no
+)
+AC_MSG_RESULT($found_cmsg_data)
+if test "x$found_cmsg_data" = xno; then
+ AC_MSG_CHECKING(if CMSG_DATA needs _XOPEN_SOURCE_EXTENDED)
+ AC_EGREP_CPP(
+ yes,
+ [
+ #define _XOPEN_SOURCE 1
+ #define _XOPEN_SOURCE_EXTENDED 1
+ #include <sys/socket.h>
+ #ifdef CMSG_DATA
+ yes
+ #endif
+ ],
+ found_cmsg_data=yes,
+ found_cmsg_data=no
+ )
+ AC_MSG_RESULT($found_cmsg_data)
+ if test "x$found_cmsg_data" = xyes; then
+ XOPEN_DEFINES="-D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED"
+ else
+ AC_MSG_ERROR("CMSG_DATA not found")
+ fi
+fi
+AC_SUBST(XOPEN_DEFINES)
+
+# Look for err and friends in err.h.
+AC_CHECK_FUNC(err, found_err_h=yes, found_err_h=no)
+AC_CHECK_FUNC(errx, , found_err_h=no)
+AC_CHECK_FUNC(warn, , found_err_h=no)
+AC_CHECK_FUNC(warnx, , found_err_h=no)
+if test "x$found_err_h" = xyes; then
+ AC_CHECK_HEADER(err.h, , found_err_h=no)
+else
+ AC_LIBOBJ(err)
+fi
+
+# Look for imsg_init in libutil.
+AC_SEARCH_LIBS(imsg_init, util, found_imsg_init=yes, found_imsg_init=no)
+if test "x$found_imsg_init" = xyes; then
+ AC_DEFINE(HAVE_IMSG)
+else
+ AC_LIBOBJ(imsg)
+ AC_LIBOBJ(imsg-buffer)
+fi
+
+# Look for daemon, compat/daemon.c used if missing. Solaris 10 has it in
+# libresolv, but no declaration anywhere, so check for declaration as well as
+# function.
+AC_CHECK_FUNC(daemon, found_daemon=yes, found_daemon=no)
+AC_CHECK_DECL(
+ daemon,
+ ,
+ found_daemon=no,
+ [
+ #include <stdlib.h>
+ #include <unistd.h>
+ ]
+)
+if test "x$found_daemon" = xyes; then
+ AC_DEFINE(HAVE_DAEMON)
+else
+ AC_LIBOBJ(daemon)
+fi
+
+# Look for stravis, compat/{vis,unvis}.c used if missing.
+AC_CHECK_FUNC(stravis, found_stravis=yes, found_stravis=no)
+if test "x$found_stravis" = xyes; then
+ AC_MSG_CHECKING(if strnvis is broken)
+ AC_EGREP_HEADER([strnvis\(char \*, const char \*, size_t, int\)],
+ vis.h,
+ AC_MSG_RESULT(no),
+ [found_stravis=no])
+ if test "x$found_stravis" = xno; then
+ AC_MSG_RESULT(yes)
+ fi
+fi
+if test "x$found_stravis" = xyes; then
+ AC_CHECK_DECL(
+ VIS_DQ,
+ ,
+ found_stravis=no,
+ [
+ #include <stdlib.h>
+ #include <vis.h>
+ ]
+)
+fi
+if test "x$found_stravis" = xyes; then
+ AC_DEFINE(HAVE_VIS)
+else
+ AC_LIBOBJ(vis)
+ AC_LIBOBJ(unvis)
+fi
+
+# Look for getopt. glibc's getopt does not enforce argument order and the ways
+# of making it do so are stupid, so just use our own instead.
+AC_CHECK_FUNC(getopt, found_getopt=yes, found_getopt=no)
+if test "x$found_getopt" != xno; then
+ AC_MSG_CHECKING(if getopt is suitable)
+ AC_EGREP_CPP(
+ yes,
+ [
+ #include <features.h>
+ #ifdef __GLIBC__
+ yes
+ #endif
+ ],
+ [
+ found_getopt=no
+ AC_MSG_RESULT(no)
+ ],
+ AC_MSG_RESULT(yes))
+fi
+if test "x$found_getopt" != xno; then
+ AC_CHECK_DECLS(
+ [optarg, optind, optreset],
+ ,
+ found_getopt=no,
+ [
+ #include <unistd.h>
+ ])
+fi
+if test "x$found_getopt" != xno; then
+ AC_DEFINE(HAVE_GETOPT)
+else
+ AC_LIBOBJ(getopt)
+fi
+
+# Look for fdforkpty and forkpty in libutil.
+AC_SEARCH_LIBS(fdforkpty, util, found_fdforkpty=yes, found_fdforkpty=no)
+if test "x$found_fdforkpty" = xyes; then
+ AC_DEFINE(HAVE_FDFORKPTY)
+else
+ AC_LIBOBJ(fdforkpty)
+fi
+AC_SEARCH_LIBS(forkpty, util, found_forkpty=yes, found_forkpty=no)
+if test "x$found_forkpty" = xyes; then
+ AC_DEFINE(HAVE_FORKPTY)
+fi
+AM_CONDITIONAL(NEED_FORKPTY, test "x$found_forkpty" = xno)
+
+# Look for kinfo_getfile in libutil.
+AC_SEARCH_LIBS(kinfo_getfile, [util util-freebsd])
+
+# Look for a suitable queue.h.
+AC_CHECK_DECL(
+ TAILQ_CONCAT,
+ found_queue_h=yes,
+ found_queue_h=no,
+ [#include <sys/queue.h>]
+)
+AC_CHECK_DECL(
+ TAILQ_PREV,
+ found_queue_h=yes,
+ found_queue_h=no,
+ [#include <sys/queue.h>]
+)
+AC_CHECK_DECL(
+ TAILQ_REPLACE,
+ ,
+ found_queue_h=no,
+ [#include <sys/queue.h>]
+)
+if test "x$found_queue_h" = xyes; then
+ AC_DEFINE(HAVE_QUEUE_H)
+fi
+
+# Look for __progname.
+AC_MSG_CHECKING(for __progname)
+AC_LINK_IFELSE([AC_LANG_SOURCE(
+ [
+ #include <stdio.h>
+ #include <stdlib.h>
+ extern char *__progname;
+ int main(void) {
+ const char *cp = __progname;
+ printf("%s\n", cp);
+ exit(0);
+ }
+ ])],
+ [AC_DEFINE(HAVE___PROGNAME) AC_MSG_RESULT(yes)],
+ AC_MSG_RESULT(no)
+)
+
+# Look for program_invocation_short_name.
+AC_MSG_CHECKING(for program_invocation_short_name)
+AC_LINK_IFELSE([AC_LANG_SOURCE(
+ [
+ #include <errno.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ int main(void) {
+ const char *cp = program_invocation_short_name;
+ printf("%s\n", cp);
+ exit(0);
+ }
+ ])],
+ [AC_DEFINE(HAVE_PROGRAM_INVOCATION_SHORT_NAME) AC_MSG_RESULT(yes)],
+ AC_MSG_RESULT(no)
+)
+
+# Look for prctl(PR_SET_NAME).
+AC_CHECK_DECL(
+ PR_SET_NAME,
+ AC_DEFINE(HAVE_PR_SET_NAME),
+ ,
+ [#include <sys/prctl.h>]
+)
+
+# Look for fcntl(F_CLOSEM).
+AC_CHECK_DECL(
+ F_CLOSEM,
+ AC_DEFINE(HAVE_FCNTL_CLOSEM),
+ ,
+ [#include <fcntl.h>]
+)
+
+# Look for /proc/$$.
+AC_MSG_CHECKING(for /proc/\$\$)
+if test -d /proc/$$; then
+ AC_DEFINE(HAVE_PROC_PID)
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT(no)
+fi
+
+# Man page defaults to mdoc.
+MANFORMAT=mdoc
+AC_SUBST(MANFORMAT)
+
+# Figure out the platform.
+AC_MSG_CHECKING(platform)
+case "$host_os" in
+ *aix*)
+ AC_MSG_RESULT(aix)
+ PLATFORM=aix
+ ;;
+ *darwin*)
+ AC_MSG_RESULT(darwin)
+ PLATFORM=darwin
+ #
+ # OS X CMSG_FIRSTHDR is broken, so redefine it with a working
+ # one. daemon works but has some stupid side effects, so use
+ # our internal version which has a workaround.
+ #
+ AC_DEFINE(BROKEN_CMSG_FIRSTHDR)
+ AC_LIBOBJ(daemon)
+ AC_LIBOBJ(daemon-darwin)
+ ;;
+ *dragonfly*)
+ AC_MSG_RESULT(dragonfly)
+ PLATFORM=dragonfly
+ ;;
+ *linux*)
+ AC_MSG_RESULT(linux)
+ PLATFORM=linux
+ ;;
+ *freebsd*)
+ AC_MSG_RESULT(freebsd)
+ PLATFORM=freebsd
+ ;;
+ *netbsd*)
+ AC_MSG_RESULT(netbsd)
+ PLATFORM=netbsd
+ ;;
+ *openbsd*)
+ AC_MSG_RESULT(openbsd)
+ PLATFORM=openbsd
+ ;;
+ *sunos*)
+ AC_MSG_RESULT(sunos)
+ PLATFORM=sunos
+ ;;
+ *solaris*)
+ AC_MSG_RESULT(sunos)
+ PLATFORM=sunos
+ case `/usr/bin/nroff --version 2>&1` in
+ *GNU*)
+ # Solaris 11.4 and later use GNU groff.
+ MANFORMAT=mdoc
+ ;;
+ *)
+ # Solaris 2.0 to 11.3 use AT&T nroff.
+ MANFORMAT=man
+ ;;
+ esac
+ ;;
+ *hpux*)
+ AC_MSG_RESULT(hpux)
+ PLATFORM=hpux
+ ;;
+ *cygwin*|*msys*)
+ AC_MSG_RESULT(cygwin)
+ PLATFORM=cygwin
+ ;;
+ *)
+ AC_MSG_RESULT(unknown)
+ PLATFORM=unknown
+ ;;
+esac
+AC_SUBST(PLATFORM)
+AM_CONDITIONAL(IS_AIX, test "x$PLATFORM" = xaix)
+AM_CONDITIONAL(IS_DARWIN, test "x$PLATFORM" = xdarwin)
+AM_CONDITIONAL(IS_DRAGONFLY, test "x$PLATFORM" = xdragonfly)
+AM_CONDITIONAL(IS_LINUX, test "x$PLATFORM" = xlinux)
+AM_CONDITIONAL(IS_FREEBSD, test "x$PLATFORM" = xfreebsd)
+AM_CONDITIONAL(IS_NETBSD, test "x$PLATFORM" = xnetbsd)
+AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd)
+AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos)
+AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux)
+AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown)
+
+# Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user
+# variables.
+AC_SUBST(AM_CPPFLAGS)
+CPPFLAGS="$SAVED_CPPFLAGS"
+AC_SUBST(AM_CFLAGS)
+CFLAGS="$SAVED_CFLAGS"
+AC_SUBST(AM_LDFLAGS)
+LDFLAGS="$SAVED_LDFLAGS"
+
+# autoconf should create a Makefile.
+AC_OUTPUT(Makefile)
diff --git a/example_tmux.conf b/example_tmux.conf
new file mode 100644
index 00000000..11db9ec6
--- /dev/null
+++ b/example_tmux.conf
@@ -0,0 +1,71 @@
+#
+# Example .tmux.conf
+#
+# By Nicholas Marriott. Public domain.
+#
+
+# Some tweaks to the status line
+set -g status-right "%H:%M"
+set -g window-status-current-style "underscore"
+
+# If running inside tmux ($TMUX is set), then change the status line to red
+%if #{TMUX}
+set -g status-bg red
+%endif
+
+# Enable RGB colour if running in xterm(1)
+set-option -sa terminal-overrides ",xterm*:Tc"
+
+# Change the default $TERM to tmux-256color
+set -g default-terminal "tmux-256color"
+
+# No bells at all
+set -g bell-action none
+
+# Keep windows around after they exit
+set -g remain-on-exit on
+
+# Change the prefix key to C-a
+set -g prefix C-a
+unbind C-b
+bind C-a send-prefix
+
+# Turn the mouse on, but without copy mode dragging
+set -g mouse on
+unbind -n MouseDrag1Pane
+unbind -Tcopy-mode MouseDrag1Pane
+
+# Some extra key bindings to select higher numbered windows
+bind F1 selectw -t:10
+bind F2 selectw -t:11
+bind F3 selectw -t:12
+bind F4 selectw -t:13
+bind F5 selectw -t:14
+bind F6 selectw -t:15
+bind F7 selectw -t:16
+bind F8 selectw -t:17
+bind F9 selectw -t:18
+bind F10 selectw -t:19
+bind F11 selectw -t:20
+bind F12 selectw -t:21
+
+# A key to toggle between smallest and largest sizes if a window is visible in
+# multiple places
+bind F set -w window-size
+
+# Keys to toggle monitoring activity in a window and the synchronize-panes option
+bind m set monitor-activity
+bind y set synchronize-panes\; display 'synchronize-panes #{?synchronize-panes,on,off}'
+
+# Create a single default session - because a session is created here, tmux
+# should be started with "tmux attach" rather than "tmux new"
+new -d -s0 -nirssi 'exec irssi'
+set -t0:0 monitor-activity on
+set -t0:0 aggressive-resize on
+neww -d -ntodo 'exec emacs ~/TODO'
+setw -t0:1 aggressive-resize on
+neww -d -nmutt 'exec mutt'
+setw -t0:2 aggressive-resize on
+neww -d
+neww -d
+neww -d
diff --git a/file.c b/file.c
index 439d3464..2c06765c 100644
--- a/file.c
+++ b/file.c
@@ -21,7 +21,6 @@
#include <errno.h>
#include <fcntl.h>
-#include <imsg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/format.c b/format.c
index eaff6115..08e41271 100644
--- a/format.c
+++ b/format.c
@@ -728,7 +728,7 @@ format_cb_current_command(struct format_tree *ft, struct format_entry *fe)
if (wp == NULL || wp->shell == NULL)
return;
- cmd = get_proc_name(wp->fd, wp->tty);
+ cmd = osdep_get_name(wp->fd, wp->tty);
if (cmd == NULL || *cmd == '\0') {
free(cmd);
cmd = cmd_stringify_argv(wp->argc, wp->argv);
@@ -741,6 +741,21 @@ format_cb_current_command(struct format_tree *ft, struct format_entry *fe)
free(cmd);
}
+/* Callback for pane_current_path. */
+static void
+format_cb_current_path(struct format_tree *ft, struct format_entry *fe)
+{
+ struct window_pane *wp = ft->wp;
+ char *cwd;
+
+ if (wp == NULL)
+ return;
+
+ cwd = osdep_get_cwd(wp->fd);
+ if (cwd != NULL)
+ fe->value = xstrdup(cwd);
+}
+
/* Callback for history_bytes. */
static void
format_cb_history_bytes(struct format_tree *ft, struct format_entry *fe)
@@ -1106,6 +1121,7 @@ format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
ft->flags = flags;
ft->time = time(NULL);
+ format_add(ft, "version", "%s", VERSION);
format_add_cb(ft, "host", format_cb_host);
format_add_cb(ft, "host_short", format_cb_host_short);
format_add_cb(ft, "pid", format_cb_pid);
@@ -2554,6 +2570,7 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
format_add(ft, "pane_pid", "%ld", (long) wp->pid);
format_add_cb(ft, "pane_start_command", format_cb_start_command);
format_add_cb(ft, "pane_current_command", format_cb_current_command);
+ format_add_cb(ft, "pane_current_path", format_cb_current_path);
format_add(ft, "cursor_x", "%u", wp->base.cx);
format_add(ft, "cursor_y", "%u", wp->base.cy);
diff --git a/input-keys.c b/input-keys.c
index 01f9ad9d..b0ea5104 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -18,7 +18,6 @@
#include <sys/types.h>
-#include <stdint.h>
#include <stdlib.h>
#include <string.h>
diff --git a/job.c b/job.c
index 0c316fd8..10883e8e 100644
--- a/job.c
+++ b/job.c
@@ -20,7 +20,6 @@
#include <sys/socket.h>
#include <fcntl.h>
-#include <paths.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
diff --git a/log.c b/log.c
index 44b24c67..f87cab92 100644
--- a/log.c
+++ b/log.c
@@ -23,7 +23,6 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <vis.h>
#include "tmux.h"
diff --git a/logo/LICENSE b/logo/LICENSE
new file mode 100644
index 00000000..3f44eb59
--- /dev/null
+++ b/logo/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) 2015, Jason Long <jason@jasonlong.me>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/logo/favicon.ico b/logo/favicon.ico
new file mode 100644
index 00000000..6e5398a7
--- /dev/null
+++ b/logo/favicon.ico
Binary files differ
diff --git a/logo/tmux-logo-1-color.eps b/logo/tmux-logo-1-color.eps
new file mode 100644
index 00000000..20018e67
--- /dev/null
+++ b/logo/tmux-logo-1-color.eps
@@ -0,0 +1,922 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%APL_DSC_Encoding: UTF8
+%APLProducer: (Version 10.10.3 (Build 14D136) Quartz PS Context)
+%%Title: (Unknown)
+%%Creator: (Unknown)
+%%CreationDate: (Unknown)
+%%For: (Unknown)
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%Pages: 1
+%%BoundingBox: 0 0 608 160
+%%EndComments
+%%BeginProlog
+%%BeginFile: cg-pdf.ps
+%%Copyright: Copyright 2000-2004 Apple Computer Incorporated.
+%%Copyright: All Rights Reserved.
+currentpacking true setpacking
+/cg_md 141 dict def
+cg_md begin
+/L3? languagelevel 3 ge def
+/bd{bind def}bind def
+/ld{load def}bd
+/xs{exch store}bd
+/xd{exch def}bd
+/cmmtx matrix def
+mark
+/sc/setcolor
+/scs/setcolorspace
+/dr/defineresource
+/fr/findresource
+/T/true
+/F/false
+/d/setdash
+/w/setlinewidth
+/J/setlinecap
+/j/setlinejoin
+/M/setmiterlimit
+/i/setflat
+/rc/rectclip
+/rf/rectfill
+/rs/rectstroke
+/f/fill
+/f*/eofill
+/sf/selectfont
+/s/show
+/xS/xshow
+/yS/yshow
+/xyS/xyshow
+/S/stroke
+/m/moveto
+/l/lineto
+/c/curveto
+/h/closepath
+/n/newpath
+/q/gsave
+/Q/grestore
+counttomark 2 idiv
+{ld}repeat pop
+/SC{
+ /ColorSpace fr scs
+}bd
+/sopr /setoverprint where{pop/setoverprint}{/pop}ifelse ld
+/soprm /setoverprintmode where{pop/setoverprintmode}{/pop}ifelse ld
+/cgmtx matrix def
+/sdmtx{cgmtx currentmatrix pop}bd
+/CM {cgmtx setmatrix}bd
+/cm {cmmtx astore CM concat}bd
+/W{clip newpath}bd
+/W*{eoclip newpath}bd
+statusdict begin product end dup (HP) anchorsearch{
+ pop pop pop
+ true
+}{
+ pop
+ (hp) anchorsearch{
+ pop pop true
+ }{
+ pop false
+ }ifelse
+}ifelse
+{
+ {
+ {
+ pop pop
+ (0)dup 0 4 -1 roll put
+ F charpath
+ }cshow
+ }
+}{
+ {F charpath}
+}ifelse
+/cply exch bd
+/cps {cply stroke}bd
+/pgsave 0 def
+/bp{/pgsave save store}bd
+/ep{pgsave restore showpage}def
+/re{4 2 roll m 1 index 0 rlineto 0 exch rlineto neg 0 rlineto h}bd
+/scrdict 10 dict def
+/scrmtx matrix def
+/patarray 0 def
+/createpat{patarray 3 1 roll put}bd
+/makepat{
+scrmtx astore pop
+gsave
+initgraphics
+CM
+patarray exch get
+scrmtx
+makepattern
+grestore
+setpattern
+}bd
+/cg_BeginEPSF{
+ userdict save/cg_b4_Inc_state exch put
+ userdict/cg_endepsf/cg_EndEPSF load put
+ count userdict/cg_op_count 3 -1 roll put
+ countdictstack dup array dictstack userdict/cg_dict_array 3 -1 roll put
+ 3 sub{end}repeat
+ /showpage {} def
+ 0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin
+ 10 setmiterlimit [] 0 setdash newpath
+ false setstrokeadjust false setoverprint
+}bd
+/cg_EndEPSF{
+ countdictstack 3 sub { end } repeat
+ cg_dict_array 3 1 index length 3 sub getinterval
+ {begin}forall
+ count userdict/cg_op_count get sub{pop}repeat
+ userdict/cg_b4_Inc_state get restore
+ F setpacking
+}bd
+/cg_biproc{currentfile/RunLengthDecode filter}bd
+/cg_aiproc{currentfile/ASCII85Decode filter/RunLengthDecode filter}bd
+/ImageDataSource 0 def
+L3?{
+ /cg_mibiproc{pop pop/ImageDataSource{cg_biproc}def}bd
+ /cg_miaiproc{pop pop/ImageDataSource{cg_aiproc}def}bd
+}{
+ /ImageBandMask 0 def
+ /ImageBandData 0 def
+ /cg_mibiproc{
+ string/ImageBandMask xs
+ string/ImageBandData xs
+ /ImageDataSource{[currentfile/RunLengthDecode filter dup ImageBandMask/readstring cvx
+ /pop cvx dup ImageBandData/readstring cvx/pop cvx]cvx bind}bd
+ }bd
+ /cg_miaiproc{
+ string/ImageBandMask xs
+ string/ImageBandData xs
+ /ImageDataSource{[currentfile/ASCII85Decode filter/RunLengthDecode filter
+ dup ImageBandMask/readstring cvx
+ /pop cvx dup ImageBandData/readstring cvx/pop cvx]cvx bind}bd
+ }bd
+}ifelse
+/imsave 0 def
+/BI{save/imsave xd mark}bd
+/EI{imsave restore}bd
+/ID{
+counttomark 2 idiv
+dup 2 add
+dict begin
+{def} repeat
+pop
+/ImageType 1 def
+/ImageMatrix[Width 0 0 Height neg 0 Height]def
+currentdict dup/ImageMask known{ImageMask}{F}ifelse exch
+L3?{
+ dup/MaskedImage known
+ {
+ pop
+ <<
+ /ImageType 3
+ /InterleaveType 2
+ /DataDict currentdict
+ /MaskDict
+ << /ImageType 1
+ /Width Width
+ /Height Height
+ /ImageMatrix ImageMatrix
+ /BitsPerComponent 1
+ /Decode [0 1]
+ currentdict/Interpolate known
+ {/Interpolate Interpolate}if
+ >>
+ >>
+ }if
+}if
+exch
+{imagemask}{image}ifelse
+end
+}bd
+/cguidfix{statusdict begin mark version end
+{cvr}stopped{cleartomark 0}{exch pop}ifelse
+2012 lt{dup findfont dup length dict begin
+{1 index/FID ne 2 index/UniqueID ne and
+{def} {pop pop} ifelse}forall
+currentdict end definefont pop
+}{pop}ifelse
+}bd
+/t_array 0 def
+/t_i 0 def
+/t_c 1 string def
+/x_proc{
+ exch t_array t_i get add exch moveto
+ /t_i t_i 1 add store
+}bd
+/y_proc{
+ t_array t_i get add moveto
+ /t_i t_i 1 add store
+}bd
+/xy_proc{
+
+ t_array t_i 2 copy 1 add get 3 1 roll get
+ 4 -1 roll add 3 1 roll add moveto
+ /t_i t_i 2 add store
+}bd
+/sop 0 def
+/cp_proc/x_proc ld
+/base_charpath
+{
+ /t_array xs
+ /t_i 0 def
+ {
+ t_c 0 3 -1 roll put
+ currentpoint
+ t_c cply sop
+ cp_proc
+ }forall
+ /t_array 0 def
+}bd
+/sop/stroke ld
+/nop{}def
+/xsp/base_charpath ld
+/ysp{/cp_proc/y_proc ld base_charpath/cp_proc/x_proc ld}bd
+/xysp{/cp_proc/xy_proc ld base_charpath/cp_proc/x_proc ld}bd
+/xmp{/sop/nop ld /cp_proc/x_proc ld base_charpath/sop/stroke ld}bd
+/ymp{/sop/nop ld /cp_proc/y_proc ld base_charpath/sop/stroke ld}bd
+/xymp{/sop/nop ld /cp_proc/xy_proc ld base_charpath/sop/stroke ld}bd
+/refnt{
+findfont dup length dict copy dup
+/Encoding 4 -1 roll put
+definefont pop
+}bd
+/renmfont{
+findfont dup length dict copy definefont pop
+}bd
+L3? dup dup{save exch}if
+/Range 0 def
+/DataSource 0 def
+/val 0 def
+/nRange 0 def
+/mulRange 0 def
+/d0 0 def
+/r0 0 def
+/di 0 def
+/ri 0 def
+/a0 0 def
+/a1 0 def
+/r1 0 def
+/r2 0 def
+/dx 0 def
+/Nsteps 0 def
+/sh3tp 0 def
+/ymax 0 def
+/ymin 0 def
+/xmax 0 def
+/xmin 0 def
+/setupFunEval
+{
+ begin
+ /nRange Range length 2 idiv store
+ /mulRange
+
+ [
+ 0 1 nRange 1 sub
+ {
+ 2 mul/nDim2 xd
+ Range nDim2 get
+ Range nDim2 1 add get
+ 1 index sub
+
+ 255 div
+ exch
+ }for
+ ]store
+ end
+}bd
+/FunEval
+{
+ begin
+
+ nRange mul /val xd
+
+ 0 1 nRange 1 sub
+ {
+ dup 2 mul/nDim2 xd
+ val
+ add DataSource exch get
+ mulRange nDim2 get mul
+ mulRange nDim2 1 add get
+ add
+ }for
+ end
+}bd
+/max
+{
+ 2 copy lt
+ {exch pop}{pop}ifelse
+}bd
+/sh2
+{
+ /Coords load aload pop
+ 3 index 3 index translate
+
+ 3 -1 roll sub
+ 3 1 roll exch
+ sub
+ 2 copy
+ dup mul exch dup mul add sqrt
+ dup
+ scale
+ atan
+
+ rotate
+
+ /Function load setupFunEval
+
+
+ clippath {pathbbox}stopped {0 0 0 0}if newpath
+ /ymax xs
+ /xmax xs
+ /ymin xs
+ /xmin xs
+ currentdict/Extend known
+ {
+ /Extend load 0 get
+ {
+ 0/Function load FunEval sc
+ xmin ymin xmin abs ymax ymin sub rectfill
+ }if
+ }if
+
+ /Nsteps/Function load/Size get 0 get 1 sub store
+ /dx 1 Nsteps div store
+ gsave
+ /di ymax ymin sub store
+ /Function load
+
+ 0 1 Nsteps
+ {
+ 1 index FunEval sc
+ 0 ymin dx di rectfill
+ dx 0 translate
+ }for
+ pop
+ grestore
+ currentdict/Extend known
+ {
+ /Extend load 1 get
+ {
+ Nsteps/Function load FunEval sc
+ 1 ymin xmax 1 sub abs ymax ymin sub rectfill
+ }if
+ }if
+}bd
+/shp
+{
+ 4 copy
+
+ dup 0 gt{
+ 0 exch a1 a0 arc
+ }{
+ pop 0 moveto
+ }ifelse
+ dup 0 gt{
+ 0 exch a0 a1 arcn
+ }{
+ pop 0 lineto
+ }ifelse
+
+ fill
+
+ dup 0 gt{
+ 0 exch a0 a1 arc
+ }{
+ pop 0 moveto
+ }ifelse
+ dup 0 gt{
+ 0 exch a1 a0 arcn
+ }{
+ pop 0 lineto
+ }ifelse
+
+ fill
+}bd
+/calcmaxs
+{
+
+ xmin dup mul ymin dup mul add sqrt
+ xmax dup mul ymin dup mul add sqrt
+ xmin dup mul ymax dup mul add sqrt
+ xmax dup mul ymax dup mul add sqrt
+ max max max
+}bd
+/sh3
+{
+ /Coords load aload pop
+ 5 index 5 index translate
+ 3 -1 roll 6 -1 roll sub
+ 3 -1 roll 5 -1 roll sub
+ 2 copy dup mul exch dup mul add sqrt
+ /dx xs
+ 2 copy 0 ne exch 0 ne or
+ {
+
+ exch atan rotate
+ }{
+ pop pop
+ }ifelse
+
+ /r2 xs
+ /r1 xs
+ /Function load
+ dup/Size get 0 get 1 sub
+ /Nsteps xs
+ setupFunEval
+
+
+
+
+
+ dx r2 add r1 lt{
+
+ 0
+ }{
+ dx r1 add r2 le
+ {
+ 1
+ }{
+ r1 r2 eq
+ {
+ 2
+ }{
+ 3
+ }ifelse
+ }ifelse
+ }ifelse
+ /sh3tp xs
+ clippath {pathbbox}stopped {0 0 0 0}if
+ newpath
+ /ymax xs
+ /xmax xs
+ /ymin xs
+ /xmin xs
+
+ dx dup mul r2 r1 sub dup mul sub dup 0 gt
+ {
+ sqrt r2 r1 sub atan
+ /a0 exch 180 exch sub store
+ /a1 a0 neg store
+ }{
+ pop
+ /a0 0 store
+ /a1 360 store
+ }ifelse
+ currentdict/Extend known
+ {
+ /Extend load 0 get r1 0 gt and
+ {
+ 0/Function load FunEval sc
+
+
+
+
+ {
+ {
+ dx 0 r1 360 0 arcn
+ xmin ymin moveto
+ xmax ymin lineto
+ xmax ymax lineto
+ xmin ymax lineto
+ xmin ymin lineto
+ eofill
+ }
+ {
+ r1 0 gt{0 0 r1 0 360 arc fill}if
+ }
+ {
+
+
+
+
+ 0 r1 xmin abs r1 add neg r1 shp
+ }
+ {
+
+
+ r2 r1 gt{
+
+ 0 r1
+ r1 neg r2 r1 sub div dx mul
+ 0
+ shp
+ }{
+
+
+
+ 0 r1 calcmaxs
+ dup
+
+ r2 add dx mul dx r1 r2 sub sub div
+ neg
+ exch 1 index
+ abs exch sub
+ shp
+ }ifelse
+ }
+ }sh3tp get exec
+ }if
+ }if
+
+ /d0 0 store
+ /r0 r1 store
+ /di dx Nsteps div store
+ /ri r2 r1 sub Nsteps div store
+ /Function load
+ 0 1 Nsteps
+ {
+ 1 index FunEval sc
+ d0 di add r0 ri add d0 r0 shp
+ {
+
+ d0 0 r0 a1 a0 arc
+ d0 di add 0 r0 ri add a0 a1 arcn
+ fill
+
+
+ d0 0 r0 a0 a1 arc
+ d0 di add 0 r0 ri add a1 a0 arcn
+ fill
+ }pop
+
+
+ /d0 d0 di add store
+ /r0 r0 ri add store
+ }for
+ pop
+
+ currentdict/Extend known
+ {
+ /Extend load 1 get r2 0 gt and
+ {
+ Nsteps/Function load FunEval sc
+
+
+
+
+ {
+ {
+ dx 0 r2 0 360 arc fill
+ }
+ {
+ dx 0 r2 360 0 arcn
+ xmin ymin moveto
+ xmax ymin lineto
+ xmax ymax lineto
+ xmin ymax lineto
+ xmin ymin lineto
+ eofill
+ }
+ {
+
+
+ xmax abs r1 add r1 dx r1 shp
+ }
+ {
+
+ r2 r1 gt{
+
+
+
+ calcmaxs dup
+
+ r1 add dx mul dx r2 r1 sub sub div
+ exch 1 index
+ exch sub
+ dx r2
+ shp
+ }{
+
+ r1 neg r2 r1 sub div dx mul
+ 0
+ dx
+ r2
+ shp
+ }ifelse
+ }
+ }
+ sh3tp get exec
+ }if
+ }if
+}bd
+/sh
+{
+ begin
+ /ShadingType load dup dup 2 eq exch 3 eq or
+ {
+ gsave
+ newpath
+ /ColorSpace load scs
+ currentdict/BBox known
+ {
+ /BBox load aload pop
+ 2 index sub
+ 3 index
+ 3 -1 roll exch sub
+ exch rectclip
+ }if
+ 2 eq
+ {sh2}{sh3}ifelse
+ grestore
+ }{
+
+ pop
+ (DEBUG: shading type unimplemented\n)print flush
+ }ifelse
+ end
+}bd
+{restore}if not dup{save exch}if
+ L3?{
+ /sh/shfill ld
+ /csq/clipsave ld
+ /csQ/cliprestore ld
+ }if
+{restore}if
+end
+setpacking
+%%EndFile
+%%EndProlog
+%%BeginSetup
+%%EndSetup
+%%Page: 1 1
+%%PageBoundingBox: 0 0 608 160
+%%BeginPageSetup
+cg_md begin
+bp
+sdmtx
+[ /CIEBasedABC 4 dict dup begin
+/WhitePoint [ 0.9505 1.0000 1.0891 ] def
+/DecodeABC [
+{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse
+ 1 index 1 index ge { exch pop } { pop } ifelse <
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000001010101010101010101010101
+0101010101010101010101010101010101010101010101020202020202020202
+0202020202020202020202020202020202030303030303030303030303030303
+0303030303030304040404040404040404040404040404040404050505050505
+0505050505050505050506060606060606060606060606060607070707070707
+0707070707070708080808080808080808080808090909090909090909090909
+0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c
+0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010
+1010101010111111111111111112121212121212121313131313131313141414
+1414141414151515151515151616161616161616171717171717171818181818
+18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d
+1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223
+2323232323242424242425252525252526262626262727272727282828282829
+292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f
+2f2f303030303131313131323232323333333333343434343535353535363636
+36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e
+3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646
+4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f
+4f50505051515151525252535353535454545555555656565657575758585859
+59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263
+63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e
+6e6e6f6f6f707070717171727273737374747475757576767677777878787979
+797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585
+86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292
+9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f
+a0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae
+aeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd
+bdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc
+cdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd
+dddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee
+eeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff
+> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling
+ cvi 3 index exch get 4 -1 roll 3 -1 roll get
+ dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind
+
+{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse
+ 1 index 1 index ge { exch pop } { pop } ifelse <
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000001010101010101010101010101
+0101010101010101010101010101010101010101010101020202020202020202
+0202020202020202020202020202020202030303030303030303030303030303
+0303030303030304040404040404040404040404040404040404050505050505
+0505050505050505050506060606060606060606060606060607070707070707
+0707070707070708080808080808080808080808090909090909090909090909
+0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c
+0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010
+1010101010111111111111111112121212121212121313131313131313141414
+1414141414151515151515151616161616161616171717171717171818181818
+18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d
+1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223
+2323232323242424242425252525252526262626262727272727282828282829
+292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f
+2f2f303030303131313131323232323333333333343434343535353535363636
+36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e
+3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646
+4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f
+4f50505051515151525252535353535454545555555656565657575758585859
+59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263
+63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e
+6e6e6f6f6f707070717171727273737374747475757576767677777878787979
+797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585
+86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292
+9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f
+a0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae
+aeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd
+bdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc
+cdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd
+dddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee
+eeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff
+> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling
+ cvi 3 index exch get 4 -1 roll 3 -1 roll get
+ dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind
+
+{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse
+ 1 index 1 index ge { exch pop } { pop } ifelse <
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000001010101010101010101010101
+0101010101010101010101010101010101010101010101020202020202020202
+0202020202020202020202020202020202030303030303030303030303030303
+0303030303030304040404040404040404040404040404040404050505050505
+0505050505050505050506060606060606060606060606060607070707070707
+0707070707070708080808080808080808080808090909090909090909090909
+0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c
+0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010
+1010101010111111111111111112121212121212121313131313131313141414
+1414141414151515151515151616161616161616171717171717171818181818
+18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d
+1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223
+2323232323242424242425252525252526262626262727272727282828282829
+292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f
+2f2f303030303131313131323232323333333333343434343535353535363636
+36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e
+3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646
+4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f
+4f50505051515151525252535353535454545555555656565657575758585859
+59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263
+63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e
+6e6e6f6f6f707070717171727273737374747475757576767677777878787979
+797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585
+86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292
+9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f
+a0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae
+aeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd
+bdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc
+cdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd
+dddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee
+eeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff
+> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling
+ cvi 3 index exch get 4 -1 roll 3 -1 roll get
+ dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind
+] def
+/MatrixABC [ 0.4124 0.2126 0.0193 0.3576 0.7151 0.1192 0.1805 0.0722 0.9508 ] def
+/RangeLMN [ 0.0 0.9505 0.0 1.0000 0.0 1.0891 ] def
+end ] /Cs1 exch/ColorSpace dr pop
+%%EndPageSetup
+0.60000002 i
+/Cs1 SC
+0.23529412 0.23529412 0.23529412 sc
+q
+2 15.003872 m
+2 7.8149743 7.8157911 2 14.998466 2 c
+145.00154 2 l
+152.17584 2 158 7.8244047 158 15.003872 c
+160 15.003872 m
+160 6.7174625 153.27803 0 145.00154 0 c
+14.998466 0 l
+6.7150416 0 0 6.7065849 0 15.003872 c
+2 14 m
+0 16 l
+160 16 l
+158 14 l
+160 14 m
+0 14 l
+W
+0 0 608 160 rc
+-5 21 m
+165 21 l
+165 -5 l
+-5 -5 l
+h
+f
+Q
+q
+83 90 m
+83 160 l
+77 160 l
+77 14 l
+83 14 l
+83 84 l
+160 84 l
+160 90 l
+83 90 l
+h
+0 144.99352 m
+0 153.28137 6.7219648 160 14.998466 160 c
+145.00154 160 l
+153.28496 160 160 153.27509 160 144.99352 c
+160 14 l
+0 14 l
+0 144.99352 l
+h
+0 144.99352 m
+W*
+0 0 608 160 rc
+-5 165 m
+165 165 l
+165 9 l
+-5 9 l
+h
+f
+Q
+q
+242 12 m
+230.85426 12.165432 222.63789 15.032893 217.12346 20.7679 c
+211.60902 26.502909 208.85185 34.995007 209 46.244446 c
+209 98 l
+189 98 l
+189 113 l
+209 113 l
+209 146 l
+225 146 l
+225 113 l
+262 112.91358 l
+262 98.024689 l
+225 98 l
+225 46.079014 l
+225.39507 39.571983 226.99422 34.802074 230.1926 31.769136 c
+233.39096 28.736198 237.58186 27.219753 242.76543 27.219753 c
+245.19179 27.219753 247.89381 27.49547 250.87161 28.046913 c
+253.8494 28.598356 256.88229 29.425508 259.97037 30.528395 c
+263.27902 15.97037 l
+259.52921 14.646907 255.86215 13.681896 252.27777 13.075309 c
+248.69341 12.468721 245.19179 12.165432 241.77284 12.165432 c
+242 12 l
+h
+295 14 m
+278.15918 14 l
+278 112.91358 l
+295 112.91358 l
+295 96.370369 l
+295 96.370369 304.76617 106.29628 309.67401 109.60493 c
+314.58185 112.9136 320.34436 114.5679 326.96167 114.5679 c
+332.80695 114.5679 337.79745 112.94117 341.93326 109.68765 c
+346.06909 106.43414 349.01926 101.99509 350.78387 96.370369 c
+350.78387 96.370369 361.92294 106.29628 366.99622 109.60493 c
+372.06952 112.9136 378.08014 114.5679 385.02832 114.5679 c
+392.74854 114.5679 398.92459 111.72801 403.55673 106.04815 c
+408.18884 100.36829 410.50488 92.730911 410 83.139999 c
+410 14 l
+394 14 l
+393.96167 80.488892 l
+393.96167 87.106209 392.69336 91.820976 390.15674 94.633331 c
+387.62009 97.445694 383.98062 98.851852 379.23822 98.851852 c
+374.49579 98.851852 369.78104 97.418121 365.09375 94.550621 c
+360.40649 91.683113 356.24316 87.878212 353 83.135803 c
+353 14 l
+336.06042 14 l
+336.06042 80.488892 l
+336.06042 87.106209 334.79211 91.820976 332.25549 94.633331 c
+329.71884 97.445694 326.07938 98.851852 321.33698 98.851852 c
+316.59457 98.851852 311.87979 97.418121 307.19254 94.550621 c
+302.50525 91.683113 298.34192 87.878212 295 83.135803 c
+295 14 l
+h
+438.9505 21.264198 m
+433.10519 27.440361 430.18259 35.656738 430 46 c
+430 113 l
+447 113 l
+447 49.220001 l
+446.7258 42.16375 448.3801 36.814835 451.68875 33.175308 c
+454.99741 29.535784 459.85004 27.716049 466.2468 27.716049 c
+471.32007 27.716049 476.36569 29.177351 481.38382 32.099998 c
+486.40195 35.022648 491.39243 39.35141 496 45.086418 c
+496 112.91358 l
+513 113 l
+512.89862 14 l
+496 14 l
+496 30.197531 l
+496 30.197531 485.13364 20.271622 479.89493 16.962963 c
+474.65622 13.654305 468.78345 12 462.2764 12 c
+452.57101 12 444.79578 15.088035 438.9505 21.264198 c
+h
+588.65784 14 m
+564.50476 51.041977 l
+541.84052 14 l
+523.4776 14 l
+556.56403 63.449383 l
+524.63562 113 l
+543.164 113 l
+566.15906 77.180244 l
+589.48499 113 l
+607.84796 113 l
+574.43066 64.441978 l
+607.18622 14 l
+588.65784 14 l
+h
+588.65784 14 m
+W*
+0 0 608 160 rc
+184 151 m
+612.84796 151 l
+612.84796 7 l
+184 7 l
+h
+f
+ep
+end
+%%Trailer
+%%EOF
diff --git a/logo/tmux-logo-1-color.svg b/logo/tmux-logo-1-color.svg
new file mode 100644
index 00000000..2e6dda44
--- /dev/null
+++ b/logo/tmux-logo-1-color.svg
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="608px" height="160px" viewBox="0 0 608 160" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
+ <!-- Generator: Sketch 3.3.1 (12005) - http://www.bohemiancoding.com/sketch -->
+ <title>logomark + wordmark copy 3</title>
+ <desc>Created with Sketch.</desc>
+ <defs></defs>
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
+ <g id="logomark-+-wordmark-copy-3" sketch:type="MSLayerGroup" fill="#3C3C3C">
+ <g id="logomark" sketch:type="MSShapeGroup">
+ <g id="status-bar" transform="translate(0.000000, 144.000000)">
+ <path d="M2,0.996127635 C2,8.18502577 7.81579104,14 14.9984654,14 L145.001535,14 C152.175838,14 158,8.1755955 158,0.996127635 M160,0.996127635 C160,9.28253753 153.278035,16 145.001535,16 L14.9984654,16 C6.71504169,16 0,9.29341489 0,0.996127635 M2,2 L0,0 L160,0 L158,2 M160,2 L0,2" id="Shape"></path>
+ </g>
+ <path d="M83,70 L83,0 L77,0 L77,146 L83,146 L83,76 L160,76 L160,70 L83,70 Z M0,15.0064867 C0,6.71863293 6.72196489,0 14.9984654,0 L145.001535,0 C153.284958,0 160,6.72491953 160,15.0064867 L160,146 L0,146 L0,15.0064867 Z" id="screen"></path>
+ </g>
+ <path d="M242,148 C230.854266,147.834568 222.637888,144.967107 217.123457,139.232099 C211.609026,133.497091 208.851852,125.004995 209,113.755556 L209,62 L189,62 L189,47 L209,47 L209,14 L225,14 L225,47 L262,47.0864198 L262,61.9753086 L225,62 L225,113.920988 C225.395062,120.428016 226.994223,125.197927 230.192593,128.230864 C233.390962,131.263801 237.581867,132.780247 242.765432,132.780247 C245.191782,132.780247 247.893812,132.50453 250.871605,131.953086 C253.849398,131.401643 256.882289,130.574491 259.97037,129.471605 L263.279012,144.02963 C259.529199,145.353093 255.862158,146.318104 252.277778,146.924691 C248.693398,147.531279 245.191787,147.834568 241.77284,147.834568 L242,148 Z M295,146 L278.159194,146 L278,47.0864198 L295,47.0864198 L295,63.6296296 C295,63.6296296 304.766165,53.7037202 309.674009,50.3950617 C314.581852,47.0864032 320.344346,45.4320988 326.961663,45.4320988 C332.80696,45.4320988 337.797445,47.0588315 341.933268,50.3123457 C346.069091,53.5658599 349.019267,58.0049101 350.783885,63.6296296 C350.783885,63.6296296 361.922955,53.7037202 366.996231,50.3950617 C372.069507,47.0864032 378.080147,45.4320988 385.02833,45.4320988 C392.748533,45.4320988 398.924603,48.2719881 403.556725,53.9518519 C408.188847,59.6317156 410.504873,67.2690878 410,76.8600006 L410,146 L394,146 L393.961663,79.5111111 C393.961663,72.8937941 392.693363,68.1790264 390.156725,65.3666667 C387.620087,62.5543069 383.980617,61.1481481 379.238206,61.1481481 C374.495796,61.1481481 369.781028,62.5818787 365.093762,65.4493827 C360.406496,68.3168868 356.243163,72.121787 353,76.8641975 L353,146 L336.060428,146 L336.060428,79.5111111 C336.060428,72.8937941 334.792128,68.1790264 332.25549,65.3666667 C329.718852,62.5543069 326.079382,61.1481481 321.336972,61.1481481 C316.594561,61.1481481 311.879793,62.5818787 307.192527,65.4493827 C302.505261,68.3168868 298.341928,72.121787 295,76.8641975 L295,146 Z M438.950487,138.735802 C433.10519,132.55964 430.182585,124.343261 430,114 L430,47 L447,47 L447,110.779999 C446.725795,117.836249 448.3801,123.185167 451.688758,126.824691 C454.997417,130.464216 459.850043,132.283951 466.246783,132.283951 C471.320059,132.283951 476.365688,130.822648 481.38382,127.9 C486.401952,124.977352 491.392437,120.648588 496,114.91358 L496,47.0864198 L513,47 L512.898635,146 L496,146 L496,129.802469 C496,129.802469 485.13364,139.728379 479.894931,143.037037 C474.656222,146.345696 468.783441,148 462.276412,148 C452.571014,148 444.795783,144.911965 438.950487,138.735802 Z M588.657829,146 L564.504742,108.958025 L541.840545,146 L523.477582,146 L556.564001,96.5506173 L524.635606,47 L543.164001,47 L566.159063,82.8197531 L589.484989,47 L607.847952,47 L574.430668,95.5580247 L607.186224,146 L588.657829,146 Z" id="wordmark" sketch:type="MSShapeGroup"></path>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/logo/tmux-logo-huge.png b/logo/tmux-logo-huge.png
new file mode 100644
index 00000000..141796d4
--- /dev/null
+++ b/logo/tmux-logo-huge.png
Binary files differ
diff --git a/logo/tmux-logo-large.png b/logo/tmux-logo-large.png
new file mode 100644
index 00000000..44dce469
--- /dev/null
+++ b/logo/tmux-logo-large.png
Binary files differ
diff --git a/logo/tmux-logo-medium.png b/logo/tmux-logo-medium.png
new file mode 100644
index 00000000..be2fa5c7
--- /dev/null
+++ b/logo/tmux-logo-medium.png
Binary files differ
diff --git a/logo/tmux-logo-small.png b/logo/tmux-logo-small.png
new file mode 100644
index 00000000..a13e3d7f
--- /dev/null
+++ b/logo/tmux-logo-small.png
Binary files differ
diff --git a/logo/tmux-logo.eps b/logo/tmux-logo.eps
new file mode 100644
index 00000000..23db6a09
--- /dev/null
+++ b/logo/tmux-logo.eps
@@ -0,0 +1,925 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%APL_DSC_Encoding: UTF8
+%APLProducer: (Version 10.10.3 (Build 14D136) Quartz PS Context)
+%%Title: (Unknown)
+%%Creator: (Unknown)
+%%CreationDate: (Unknown)
+%%For: (Unknown)
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%Pages: 1
+%%BoundingBox: 0 0 608 160
+%%EndComments
+%%BeginProlog
+%%BeginFile: cg-pdf.ps
+%%Copyright: Copyright 2000-2004 Apple Computer Incorporated.
+%%Copyright: All Rights Reserved.
+currentpacking true setpacking
+/cg_md 141 dict def
+cg_md begin
+/L3? languagelevel 3 ge def
+/bd{bind def}bind def
+/ld{load def}bd
+/xs{exch store}bd
+/xd{exch def}bd
+/cmmtx matrix def
+mark
+/sc/setcolor
+/scs/setcolorspace
+/dr/defineresource
+/fr/findresource
+/T/true
+/F/false
+/d/setdash
+/w/setlinewidth
+/J/setlinecap
+/j/setlinejoin
+/M/setmiterlimit
+/i/setflat
+/rc/rectclip
+/rf/rectfill
+/rs/rectstroke
+/f/fill
+/f*/eofill
+/sf/selectfont
+/s/show
+/xS/xshow
+/yS/yshow
+/xyS/xyshow
+/S/stroke
+/m/moveto
+/l/lineto
+/c/curveto
+/h/closepath
+/n/newpath
+/q/gsave
+/Q/grestore
+counttomark 2 idiv
+{ld}repeat pop
+/SC{
+ /ColorSpace fr scs
+}bd
+/sopr /setoverprint where{pop/setoverprint}{/pop}ifelse ld
+/soprm /setoverprintmode where{pop/setoverprintmode}{/pop}ifelse ld
+/cgmtx matrix def
+/sdmtx{cgmtx currentmatrix pop}bd
+/CM {cgmtx setmatrix}bd
+/cm {cmmtx astore CM concat}bd
+/W{clip newpath}bd
+/W*{eoclip newpath}bd
+statusdict begin product end dup (HP) anchorsearch{
+ pop pop pop
+ true
+}{
+ pop
+ (hp) anchorsearch{
+ pop pop true
+ }{
+ pop false
+ }ifelse
+}ifelse
+{
+ {
+ {
+ pop pop
+ (0)dup 0 4 -1 roll put
+ F charpath
+ }cshow
+ }
+}{
+ {F charpath}
+}ifelse
+/cply exch bd
+/cps {cply stroke}bd
+/pgsave 0 def
+/bp{/pgsave save store}bd
+/ep{pgsave restore showpage}def
+/re{4 2 roll m 1 index 0 rlineto 0 exch rlineto neg 0 rlineto h}bd
+/scrdict 10 dict def
+/scrmtx matrix def
+/patarray 0 def
+/createpat{patarray 3 1 roll put}bd
+/makepat{
+scrmtx astore pop
+gsave
+initgraphics
+CM
+patarray exch get
+scrmtx
+makepattern
+grestore
+setpattern
+}bd
+/cg_BeginEPSF{
+ userdict save/cg_b4_Inc_state exch put
+ userdict/cg_endepsf/cg_EndEPSF load put
+ count userdict/cg_op_count 3 -1 roll put
+ countdictstack dup array dictstack userdict/cg_dict_array 3 -1 roll put
+ 3 sub{end}repeat
+ /showpage {} def
+ 0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin
+ 10 setmiterlimit [] 0 setdash newpath
+ false setstrokeadjust false setoverprint
+}bd
+/cg_EndEPSF{
+ countdictstack 3 sub { end } repeat
+ cg_dict_array 3 1 index length 3 sub getinterval
+ {begin}forall
+ count userdict/cg_op_count get sub{pop}repeat
+ userdict/cg_b4_Inc_state get restore
+ F setpacking
+}bd
+/cg_biproc{currentfile/RunLengthDecode filter}bd
+/cg_aiproc{currentfile/ASCII85Decode filter/RunLengthDecode filter}bd
+/ImageDataSource 0 def
+L3?{
+ /cg_mibiproc{pop pop/ImageDataSource{cg_biproc}def}bd
+ /cg_miaiproc{pop pop/ImageDataSource{cg_aiproc}def}bd
+}{
+ /ImageBandMask 0 def
+ /ImageBandData 0 def
+ /cg_mibiproc{
+ string/ImageBandMask xs
+ string/ImageBandData xs
+ /ImageDataSource{[currentfile/RunLengthDecode filter dup ImageBandMask/readstring cvx
+ /pop cvx dup ImageBandData/readstring cvx/pop cvx]cvx bind}bd
+ }bd
+ /cg_miaiproc{
+ string/ImageBandMask xs
+ string/ImageBandData xs
+ /ImageDataSource{[currentfile/ASCII85Decode filter/RunLengthDecode filter
+ dup ImageBandMask/readstring cvx
+ /pop cvx dup ImageBandData/readstring cvx/pop cvx]cvx bind}bd
+ }bd
+}ifelse
+/imsave 0 def
+/BI{save/imsave xd mark}bd
+/EI{imsave restore}bd
+/ID{
+counttomark 2 idiv
+dup 2 add
+dict begin
+{def} repeat
+pop
+/ImageType 1 def
+/ImageMatrix[Width 0 0 Height neg 0 Height]def
+currentdict dup/ImageMask known{ImageMask}{F}ifelse exch
+L3?{
+ dup/MaskedImage known
+ {
+ pop
+ <<
+ /ImageType 3
+ /InterleaveType 2
+ /DataDict currentdict
+ /MaskDict
+ << /ImageType 1
+ /Width Width
+ /Height Height
+ /ImageMatrix ImageMatrix
+ /BitsPerComponent 1
+ /Decode [0 1]
+ currentdict/Interpolate known
+ {/Interpolate Interpolate}if
+ >>
+ >>
+ }if
+}if
+exch
+{imagemask}{image}ifelse
+end
+}bd
+/cguidfix{statusdict begin mark version end
+{cvr}stopped{cleartomark 0}{exch pop}ifelse
+2012 lt{dup findfont dup length dict begin
+{1 index/FID ne 2 index/UniqueID ne and
+{def} {pop pop} ifelse}forall
+currentdict end definefont pop
+}{pop}ifelse
+}bd
+/t_array 0 def
+/t_i 0 def
+/t_c 1 string def
+/x_proc{
+ exch t_array t_i get add exch moveto
+ /t_i t_i 1 add store
+}bd
+/y_proc{
+ t_array t_i get add moveto
+ /t_i t_i 1 add store
+}bd
+/xy_proc{
+
+ t_array t_i 2 copy 1 add get 3 1 roll get
+ 4 -1 roll add 3 1 roll add moveto
+ /t_i t_i 2 add store
+}bd
+/sop 0 def
+/cp_proc/x_proc ld
+/base_charpath
+{
+ /t_array xs
+ /t_i 0 def
+ {
+ t_c 0 3 -1 roll put
+ currentpoint
+ t_c cply sop
+ cp_proc
+ }forall
+ /t_array 0 def
+}bd
+/sop/stroke ld
+/nop{}def
+/xsp/base_charpath ld
+/ysp{/cp_proc/y_proc ld base_charpath/cp_proc/x_proc ld}bd
+/xysp{/cp_proc/xy_proc ld base_charpath/cp_proc/x_proc ld}bd
+/xmp{/sop/nop ld /cp_proc/x_proc ld base_charpath/sop/stroke ld}bd
+/ymp{/sop/nop ld /cp_proc/y_proc ld base_charpath/sop/stroke ld}bd
+/xymp{/sop/nop ld /cp_proc/xy_proc ld base_charpath/sop/stroke ld}bd
+/refnt{
+findfont dup length dict copy dup
+/Encoding 4 -1 roll put
+definefont pop
+}bd
+/renmfont{
+findfont dup length dict copy definefont pop
+}bd
+L3? dup dup{save exch}if
+/Range 0 def
+/DataSource 0 def
+/val 0 def
+/nRange 0 def
+/mulRange 0 def
+/d0 0 def
+/r0 0 def
+/di 0 def
+/ri 0 def
+/a0 0 def
+/a1 0 def
+/r1 0 def
+/r2 0 def
+/dx 0 def
+/Nsteps 0 def
+/sh3tp 0 def
+/ymax 0 def
+/ymin 0 def
+/xmax 0 def
+/xmin 0 def
+/setupFunEval
+{
+ begin
+ /nRange Range length 2 idiv store
+ /mulRange
+
+ [
+ 0 1 nRange 1 sub
+ {
+ 2 mul/nDim2 xd
+ Range nDim2 get
+ Range nDim2 1 add get
+ 1 index sub
+
+ 255 div
+ exch
+ }for
+ ]store
+ end
+}bd
+/FunEval
+{
+ begin
+
+ nRange mul /val xd
+
+ 0 1 nRange 1 sub
+ {
+ dup 2 mul/nDim2 xd
+ val
+ add DataSource exch get
+ mulRange nDim2 get mul
+ mulRange nDim2 1 add get
+ add
+ }for
+ end
+}bd
+/max
+{
+ 2 copy lt
+ {exch pop}{pop}ifelse
+}bd
+/sh2
+{
+ /Coords load aload pop
+ 3 index 3 index translate
+
+ 3 -1 roll sub
+ 3 1 roll exch
+ sub
+ 2 copy
+ dup mul exch dup mul add sqrt
+ dup
+ scale
+ atan
+
+ rotate
+
+ /Function load setupFunEval
+
+
+ clippath {pathbbox}stopped {0 0 0 0}if newpath
+ /ymax xs
+ /xmax xs
+ /ymin xs
+ /xmin xs
+ currentdict/Extend known
+ {
+ /Extend load 0 get
+ {
+ 0/Function load FunEval sc
+ xmin ymin xmin abs ymax ymin sub rectfill
+ }if
+ }if
+
+ /Nsteps/Function load/Size get 0 get 1 sub store
+ /dx 1 Nsteps div store
+ gsave
+ /di ymax ymin sub store
+ /Function load
+
+ 0 1 Nsteps
+ {
+ 1 index FunEval sc
+ 0 ymin dx di rectfill
+ dx 0 translate
+ }for
+ pop
+ grestore
+ currentdict/Extend known
+ {
+ /Extend load 1 get
+ {
+ Nsteps/Function load FunEval sc
+ 1 ymin xmax 1 sub abs ymax ymin sub rectfill
+ }if
+ }if
+}bd
+/shp
+{
+ 4 copy
+
+ dup 0 gt{
+ 0 exch a1 a0 arc
+ }{
+ pop 0 moveto
+ }ifelse
+ dup 0 gt{
+ 0 exch a0 a1 arcn
+ }{
+ pop 0 lineto
+ }ifelse
+
+ fill
+
+ dup 0 gt{
+ 0 exch a0 a1 arc
+ }{
+ pop 0 moveto
+ }ifelse
+ dup 0 gt{
+ 0 exch a1 a0 arcn
+ }{
+ pop 0 lineto
+ }ifelse
+
+ fill
+}bd
+/calcmaxs
+{
+
+ xmin dup mul ymin dup mul add sqrt
+ xmax dup mul ymin dup mul add sqrt
+ xmin dup mul ymax dup mul add sqrt
+ xmax dup mul ymax dup mul add sqrt
+ max max max
+}bd
+/sh3
+{
+ /Coords load aload pop
+ 5 index 5 index translate
+ 3 -1 roll 6 -1 roll sub
+ 3 -1 roll 5 -1 roll sub
+ 2 copy dup mul exch dup mul add sqrt
+ /dx xs
+ 2 copy 0 ne exch 0 ne or
+ {
+
+ exch atan rotate
+ }{
+ pop pop
+ }ifelse
+
+ /r2 xs
+ /r1 xs
+ /Function load
+ dup/Size get 0 get 1 sub
+ /Nsteps xs
+ setupFunEval
+
+
+
+
+
+ dx r2 add r1 lt{
+
+ 0
+ }{
+ dx r1 add r2 le
+ {
+ 1
+ }{
+ r1 r2 eq
+ {
+ 2
+ }{
+ 3
+ }ifelse
+ }ifelse
+ }ifelse
+ /sh3tp xs
+ clippath {pathbbox}stopped {0 0 0 0}if
+ newpath
+ /ymax xs
+ /xmax xs
+ /ymin xs
+ /xmin xs
+
+ dx dup mul r2 r1 sub dup mul sub dup 0 gt
+ {
+ sqrt r2 r1 sub atan
+ /a0 exch 180 exch sub store
+ /a1 a0 neg store
+ }{
+ pop
+ /a0 0 store
+ /a1 360 store
+ }ifelse
+ currentdict/Extend known
+ {
+ /Extend load 0 get r1 0 gt and
+ {
+ 0/Function load FunEval sc
+
+
+
+
+ {
+ {
+ dx 0 r1 360 0 arcn
+ xmin ymin moveto
+ xmax ymin lineto
+ xmax ymax lineto
+ xmin ymax lineto
+ xmin ymin lineto
+ eofill
+ }
+ {
+ r1 0 gt{0 0 r1 0 360 arc fill}if
+ }
+ {
+
+
+
+
+ 0 r1 xmin abs r1 add neg r1 shp
+ }
+ {
+
+
+ r2 r1 gt{
+
+ 0 r1
+ r1 neg r2 r1 sub div dx mul
+ 0
+ shp
+ }{
+
+
+
+ 0 r1 calcmaxs
+ dup
+
+ r2 add dx mul dx r1 r2 sub sub div
+ neg
+ exch 1 index
+ abs exch sub
+ shp
+ }ifelse
+ }
+ }sh3tp get exec
+ }if
+ }if
+
+ /d0 0 store
+ /r0 r1 store
+ /di dx Nsteps div store
+ /ri r2 r1 sub Nsteps div store
+ /Function load
+ 0 1 Nsteps
+ {
+ 1 index FunEval sc
+ d0 di add r0 ri add d0 r0 shp
+ {
+
+ d0 0 r0 a1 a0 arc
+ d0 di add 0 r0 ri add a0 a1 arcn
+ fill
+
+
+ d0 0 r0 a0 a1 arc
+ d0 di add 0 r0 ri add a1 a0 arcn
+ fill
+ }pop
+
+
+ /d0 d0 di add store
+ /r0 r0 ri add store
+ }for
+ pop
+
+ currentdict/Extend known
+ {
+ /Extend load 1 get r2 0 gt and
+ {
+ Nsteps/Function load FunEval sc
+
+
+
+
+ {
+ {
+ dx 0 r2 0 360 arc fill
+ }
+ {
+ dx 0 r2 360 0 arcn
+ xmin ymin moveto
+ xmax ymin lineto
+ xmax ymax lineto
+ xmin ymax lineto
+ xmin ymin lineto
+ eofill
+ }
+ {
+
+
+ xmax abs r1 add r1 dx r1 shp
+ }
+ {
+
+ r2 r1 gt{
+
+
+
+ calcmaxs dup
+
+ r1 add dx mul dx r2 r1 sub sub div
+ exch 1 index
+ exch sub
+ dx r2
+ shp
+ }{
+
+ r1 neg r2 r1 sub div dx mul
+ 0
+ dx
+ r2
+ shp
+ }ifelse
+ }
+ }
+ sh3tp get exec
+ }if
+ }if
+}bd
+/sh
+{
+ begin
+ /ShadingType load dup dup 2 eq exch 3 eq or
+ {
+ gsave
+ newpath
+ /ColorSpace load scs
+ currentdict/BBox known
+ {
+ /BBox load aload pop
+ 2 index sub
+ 3 index
+ 3 -1 roll exch sub
+ exch rectclip
+ }if
+ 2 eq
+ {sh2}{sh3}ifelse
+ grestore
+ }{
+
+ pop
+ (DEBUG: shading type unimplemented\n)print flush
+ }ifelse
+ end
+}bd
+{restore}if not dup{save exch}if
+ L3?{
+ /sh/shfill ld
+ /csq/clipsave ld
+ /csQ/cliprestore ld
+ }if
+{restore}if
+end
+setpacking
+%%EndFile
+%%EndProlog
+%%BeginSetup
+%%EndSetup
+%%Page: 1 1
+%%PageBoundingBox: 0 0 608 160
+%%BeginPageSetup
+cg_md begin
+bp
+sdmtx
+[ /CIEBasedABC 4 dict dup begin
+/WhitePoint [ 0.9505 1.0000 1.0891 ] def
+/DecodeABC [
+{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse
+ 1 index 1 index ge { exch pop } { pop } ifelse <
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000001010101010101010101010101
+0101010101010101010101010101010101010101010101020202020202020202
+0202020202020202020202020202020202030303030303030303030303030303
+0303030303030304040404040404040404040404040404040404050505050505
+0505050505050505050506060606060606060606060606060607070707070707
+0707070707070708080808080808080808080808090909090909090909090909
+0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c
+0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010
+1010101010111111111111111112121212121212121313131313131313141414
+1414141414151515151515151616161616161616171717171717171818181818
+18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d
+1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223
+2323232323242424242425252525252526262626262727272727282828282829
+292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f
+2f2f303030303131313131323232323333333333343434343535353535363636
+36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e
+3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646
+4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f
+4f50505051515151525252535353535454545555555656565657575758585859
+59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263
+63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e
+6e6e6f6f6f707070717171727273737374747475757576767677777878787979
+797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585
+86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292
+9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f
+a0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae
+aeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd
+bdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc
+cdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd
+dddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee
+eeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff
+> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling
+ cvi 3 index exch get 4 -1 roll 3 -1 roll get
+ dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind
+
+{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse
+ 1 index 1 index ge { exch pop } { pop } ifelse <
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000001010101010101010101010101
+0101010101010101010101010101010101010101010101020202020202020202
+0202020202020202020202020202020202030303030303030303030303030303
+0303030303030304040404040404040404040404040404040404050505050505
+0505050505050505050506060606060606060606060606060607070707070707
+0707070707070708080808080808080808080808090909090909090909090909
+0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c
+0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010
+1010101010111111111111111112121212121212121313131313131313141414
+1414141414151515151515151616161616161616171717171717171818181818
+18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d
+1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223
+2323232323242424242425252525252526262626262727272727282828282829
+292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f
+2f2f303030303131313131323232323333333333343434343535353535363636
+36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e
+3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646
+4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f
+4f50505051515151525252535353535454545555555656565657575758585859
+59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263
+63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e
+6e6e6f6f6f707070717171727273737374747475757576767677777878787979
+797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585
+86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292
+9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f
+a0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae
+aeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd
+bdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc
+cdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd
+dddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee
+eeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff
+> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling
+ cvi 3 index exch get 4 -1 roll 3 -1 roll get
+ dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind
+
+{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse
+ 1 index 1 index ge { exch pop } { pop } ifelse <
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000001010101010101010101010101
+0101010101010101010101010101010101010101010101020202020202020202
+0202020202020202020202020202020202030303030303030303030303030303
+0303030303030304040404040404040404040404040404040404050505050505
+0505050505050505050506060606060606060606060606060607070707070707
+0707070707070708080808080808080808080808090909090909090909090909
+0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c
+0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010
+1010101010111111111111111112121212121212121313131313131313141414
+1414141414151515151515151616161616161616171717171717171818181818
+18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d
+1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223
+2323232323242424242425252525252526262626262727272727282828282829
+292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f
+2f2f303030303131313131323232323333333333343434343535353535363636
+36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e
+3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646
+4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f
+4f50505051515151525252535353535454545555555656565657575758585859
+59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263
+63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e
+6e6e6f6f6f707070717171727273737374747475757576767677777878787979
+797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585
+86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292
+9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f
+a0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae
+aeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd
+bdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc
+cdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd
+dddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee
+eeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff
+> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling
+ cvi 3 index exch get 4 -1 roll 3 -1 roll get
+ dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind
+] def
+/MatrixABC [ 0.4124 0.2126 0.0193 0.3576 0.7151 0.1192 0.1805 0.0722 0.9508 ] def
+/RangeLMN [ 0.0 0.9505 0.0 1.0000 0.0 1.0891 ] def
+end ] /Cs1 exch/ColorSpace dr pop
+%%EndPageSetup
+0.60000002 i
+/Cs1 SC
+0.10588235 0.72549021 0.12156863 sc
+q
+0 44 m
+160 44 l
+160 15.003872 l
+160 6.7174625 153.27803 0 145.00154 0 c
+14.998466 0 l
+6.7150416 0 0 6.7065849 0 15.003872 c
+0 44 l
+h
+0 44 m
+160 44 l
+160 14 l
+0 14 l
+0 44 l
+h
+0 44 m
+W*
+0 0 608 160 rc
+-5 49 m
+165 49 l
+165 -5 l
+-5 -5 l
+h
+f
+Q
+0.23529412 0.23529412 0.23529412 sc
+q
+83 90 m
+83 160 l
+77 160 l
+77 14 l
+83 14 l
+83 84 l
+160 84 l
+160 90 l
+83 90 l
+h
+0 144.99352 m
+0 153.28137 6.7219648 160 14.998466 160 c
+145.00154 160 l
+153.28496 160 160 153.27509 160 144.99352 c
+160 14 l
+0 14 l
+0 144.99352 l
+h
+0 144.99352 m
+W*
+0 0 608 160 rc
+-5 165 m
+165 165 l
+165 9 l
+-5 9 l
+h
+f
+Q
+0.10588235 0.72549021 0.12156863 sc
+q
+241.77284 12.165432 m
+230.85426 12.165432 222.63789 15.032893 217.12346 20.7679 c
+211.60902 26.502909 208.85185 34.995007 208.85185 46.244446 c
+208.85185 98.024689 l
+189 98.024689 l
+189 112.91358 l
+208.85185 112.91358 l
+208.85185 146 l
+225.39507 146 l
+225.39507 112.91358 l
+261.79013 112.91358 l
+261.79013 98.024689 l
+225.39507 98.024689 l
+225.39507 46.079014 l
+225.39507 39.571983 226.99422 34.802074 230.1926 31.769136 c
+233.39096 28.736198 237.58186 27.219753 242.76543 27.219753 c
+245.19179 27.219753 247.89381 27.49547 250.87161 28.046913 c
+253.8494 28.598356 256.88229 29.425508 259.97037 30.528395 c
+263.27902 15.97037 l
+259.52921 14.646907 255.86215 13.681896 252.27777 13.075309 c
+248.69341 12.468721 245.19179 12.165432 241.77284 12.165432 c
+241.77284 12.165432 l
+h
+294.70239 13.654321 m
+278.15918 13.654321 l
+278.15918 112.91358 l
+294.70239 112.91358 l
+294.70239 96.370369 l
+294.70239 96.370369 304.76617 106.29628 309.67401 109.60493 c
+314.58185 112.9136 320.34436 114.5679 326.96167 114.5679 c
+332.80695 114.5679 337.79745 112.94117 341.93326 109.68765 c
+346.06909 106.43414 349.01926 101.99509 350.78387 96.370369 c
+350.78387 96.370369 361.92294 106.29628 366.99622 109.60493 c
+372.06952 112.9136 378.08014 114.5679 385.02832 114.5679 c
+392.74854 114.5679 398.92459 111.72801 403.55673 106.04815 c
+408.18884 100.36829 410.50488 92.730911 410.50488 83.135803 c
+410.50488 13.654321 l
+393.96167 13.654321 l
+393.96167 80.488892 l
+393.96167 87.106209 392.69336 91.820976 390.15674 94.633331 c
+387.62009 97.445694 383.98062 98.851852 379.23822 98.851852 c
+374.49579 98.851852 369.78104 97.418121 365.09375 94.550621 c
+360.40649 91.683113 356.24316 87.878212 352.60364 83.135803 c
+352.60364 13.654321 l
+336.06042 13.654321 l
+336.06042 80.488892 l
+336.06042 87.106209 334.79211 91.820976 332.25549 94.633331 c
+329.71884 97.445694 326.07938 98.851852 321.33698 98.851852 c
+316.59457 98.851852 311.87979 97.418121 307.19254 94.550621 c
+302.50525 91.683113 298.34192 87.878212 294.70239 83.135803 c
+294.70239 13.654321 l
+h
+438.9505 21.264198 m
+433.10519 27.440361 430.18259 35.656738 430.18259 45.913582 c
+430.18259 112.91358 l
+446.7258 112.91358 l
+446.7258 49.222221 l
+446.7258 42.16375 448.3801 36.814835 451.68875 33.175308 c
+454.99741 29.535784 459.85004 27.716049 466.2468 27.716049 c
+471.32007 27.716049 476.36569 29.177351 481.38382 32.099998 c
+486.40195 35.022648 491.39243 39.35141 496.35544 45.086418 c
+496.35544 112.91358 l
+512.89862 112.91358 l
+512.89862 13.654321 l
+496.35544 13.654321 l
+496.35544 30.197531 l
+496.35544 30.197531 485.13364 20.271622 479.89493 16.962963 c
+474.65622 13.654305 468.78345 12 462.2764 12 c
+452.57101 12 444.79578 15.088035 438.9505 21.264198 c
+h
+588.65784 13.654321 m
+564.50476 51.041977 l
+541.84052 13.654321 l
+523.4776 13.654321 l
+556.56403 63.449383 l
+524.63562 112.91358 l
+543.164 112.91358 l
+566.15906 77.180244 l
+589.48499 112.91358 l
+607.84796 112.91358 l
+574.43066 64.441978 l
+607.18622 13.654321 l
+588.65784 13.654321 l
+h
+588.65784 13.654321 m
+W*
+0 0 608 160 rc
+184 151 m
+612.84796 151 l
+612.84796 7 l
+184 7 l
+h
+f
+ep
+end
+%%Trailer
+%%EOF
diff --git a/logo/tmux-logo.svg b/logo/tmux-logo.svg
new file mode 100644
index 00000000..061cddd9
--- /dev/null
+++ b/logo/tmux-logo.svg
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="608px" height="160px" viewBox="0 0 608 160" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
+ <!-- Generator: Sketch 3.3.1 (12005) - http://www.bohemiancoding.com/sketch -->
+ <title>logomark + wordmark</title>
+ <desc>Created with Sketch.</desc>
+ <defs></defs>
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
+ <g id="logomark-+-wordmark" sketch:type="MSLayerGroup">
+ <g id="logomark" sketch:type="MSShapeGroup">
+ <g id="status-bar" fill="#1BB91F">
+ <path d="M0,116 L160,116 L160,144.996128 C160,153.282538 153.278035,160 145.001535,160 L14.9984654,160 C6.71504169,160 0,153.293415 0,144.996128 L0,116 Z M0,116 L160,116 L160,146 L0,146 L0,116 Z" id="Rectangle-5"></path>
+ </g>
+ <path d="M83,70 L83,0 L77,0 L77,146 L83,146 L83,76 L160,76 L160,70 L83,70 Z M0,15.0064867 C0,6.71863293 6.72196489,0 14.9984654,0 L145.001535,0 C153.284958,0 160,6.72491953 160,15.0064867 L160,146 L0,146 L0,15.0064867 Z" id="screen" fill="#3C3C3C"></path>
+ </g>
+ <path d="M241.77284,147.834568 C230.854266,147.834568 222.637888,144.967107 217.123457,139.232099 C211.609026,133.497091 208.851852,125.004995 208.851852,113.755556 L208.851852,61.9753086 L189,61.9753086 L189,47.0864198 L208.851852,47.0864198 L208.851852,14 L225.395062,14 L225.395062,47.0864198 L261.790123,47.0864198 L261.790123,61.9753086 L225.395062,61.9753086 L225.395062,113.920988 C225.395062,120.428016 226.994223,125.197927 230.192593,128.230864 C233.390962,131.263801 237.581867,132.780247 242.765432,132.780247 C245.191782,132.780247 247.893812,132.50453 250.871605,131.953086 C253.849398,131.401643 256.882289,130.574491 259.97037,129.471605 L263.279012,144.02963 C259.529199,145.353093 255.862158,146.318104 252.277778,146.924691 C248.693398,147.531279 245.191787,147.834568 241.77284,147.834568 L241.77284,147.834568 Z M294.702404,146.345679 L278.159194,146.345679 L278.159194,47.0864198 L294.702404,47.0864198 L294.702404,63.6296296 C294.702404,63.6296296 304.766165,53.7037202 309.674009,50.3950617 C314.581852,47.0864032 320.344346,45.4320988 326.961663,45.4320988 C332.80696,45.4320988 337.797445,47.0588315 341.933268,50.3123457 C346.069091,53.5658599 349.019267,58.0049101 350.783885,63.6296296 C350.783885,63.6296296 361.922955,53.7037202 366.996231,50.3950617 C372.069507,47.0864032 378.080147,45.4320988 385.02833,45.4320988 C392.748533,45.4320988 398.924603,48.2719881 403.556725,53.9518519 C408.188847,59.6317156 410.504873,67.2690878 410.504873,76.8641975 L410.504873,146.345679 L393.961663,146.345679 L393.961663,79.5111111 C393.961663,72.8937941 392.693363,68.1790264 390.156725,65.3666667 C387.620087,62.5543069 383.980617,61.1481481 379.238206,61.1481481 C374.495796,61.1481481 369.781028,62.5818787 365.093762,65.4493827 C360.406496,68.3168868 356.243163,72.121787 352.603638,76.8641975 L352.603638,146.345679 L336.060428,146.345679 L336.060428,79.5111111 C336.060428,72.8937941 334.792128,68.1790264 332.25549,65.3666667 C329.718852,62.5543069 326.079382,61.1481481 321.336972,61.1481481 C316.594561,61.1481481 311.879793,62.5818787 307.192527,65.4493827 C302.505261,68.3168868 298.341928,72.121787 294.702404,76.8641975 L294.702404,146.345679 Z M438.950487,138.735802 C433.10519,132.55964 430.182585,124.343261 430.182585,114.08642 L430.182585,47.0864198 L446.725795,47.0864198 L446.725795,110.777778 C446.725795,117.836249 448.3801,123.185167 451.688758,126.824691 C454.997417,130.464216 459.850043,132.283951 466.246783,132.283951 C471.320059,132.283951 476.365688,130.822648 481.38382,127.9 C486.401952,124.977352 491.392437,120.648588 496.355425,114.91358 L496.355425,47.0864198 L512.898635,47.0864198 L512.898635,146.345679 L496.355425,146.345679 L496.355425,129.802469 C496.355425,129.802469 485.13364,139.728379 479.894931,143.037037 C474.656222,146.345696 468.783441,148 462.276412,148 C452.571014,148 444.795783,144.911965 438.950487,138.735802 Z M588.657829,146.345679 L564.504742,108.958025 L541.840545,146.345679 L523.477582,146.345679 L556.564001,96.5506173 L524.635606,47.0864198 L543.164001,47.0864198 L566.159063,82.8197531 L589.484989,47.0864198 L607.847952,47.0864198 L574.430668,95.5580247 L607.186224,146.345679 L588.657829,146.345679 Z" id="wordmark" fill="#1BB91F" sketch:type="MSShapeGroup"></path>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/logo/tmux-logomark.eps b/logo/tmux-logomark.eps
new file mode 100644
index 00000000..8924983b
--- /dev/null
+++ b/logo/tmux-logomark.eps
@@ -0,0 +1,829 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%APL_DSC_Encoding: UTF8
+%APLProducer: (Version 10.10.3 (Build 14D136) Quartz PS Context)
+%%Title: (Unknown)
+%%Creator: (Unknown)
+%%CreationDate: (Unknown)
+%%For: (Unknown)
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%Pages: 1
+%%BoundingBox: 0 0 160 160
+%%EndComments
+%%BeginProlog
+%%BeginFile: cg-pdf.ps
+%%Copyright: Copyright 2000-2004 Apple Computer Incorporated.
+%%Copyright: All Rights Reserved.
+currentpacking true setpacking
+/cg_md 141 dict def
+cg_md begin
+/L3? languagelevel 3 ge def
+/bd{bind def}bind def
+/ld{load def}bd
+/xs{exch store}bd
+/xd{exch def}bd
+/cmmtx matrix def
+mark
+/sc/setcolor
+/scs/setcolorspace
+/dr/defineresource
+/fr/findresource
+/T/true
+/F/false
+/d/setdash
+/w/setlinewidth
+/J/setlinecap
+/j/setlinejoin
+/M/setmiterlimit
+/i/setflat
+/rc/rectclip
+/rf/rectfill
+/rs/rectstroke
+/f/fill
+/f*/eofill
+/sf/selectfont
+/s/show
+/xS/xshow
+/yS/yshow
+/xyS/xyshow
+/S/stroke
+/m/moveto
+/l/lineto
+/c/curveto
+/h/closepath
+/n/newpath
+/q/gsave
+/Q/grestore
+counttomark 2 idiv
+{ld}repeat pop
+/SC{
+ /ColorSpace fr scs
+}bd
+/sopr /setoverprint where{pop/setoverprint}{/pop}ifelse ld
+/soprm /setoverprintmode where{pop/setoverprintmode}{/pop}ifelse ld
+/cgmtx matrix def
+/sdmtx{cgmtx currentmatrix pop}bd
+/CM {cgmtx setmatrix}bd
+/cm {cmmtx astore CM concat}bd
+/W{clip newpath}bd
+/W*{eoclip newpath}bd
+statusdict begin product end dup (HP) anchorsearch{
+ pop pop pop
+ true
+}{
+ pop
+ (hp) anchorsearch{
+ pop pop true
+ }{
+ pop false
+ }ifelse
+}ifelse
+{
+ {
+ {
+ pop pop
+ (0)dup 0 4 -1 roll put
+ F charpath
+ }cshow
+ }
+}{
+ {F charpath}
+}ifelse
+/cply exch bd
+/cps {cply stroke}bd
+/pgsave 0 def
+/bp{/pgsave save store}bd
+/ep{pgsave restore showpage}def
+/re{4 2 roll m 1 index 0 rlineto 0 exch rlineto neg 0 rlineto h}bd
+/scrdict 10 dict def
+/scrmtx matrix def
+/patarray 0 def
+/createpat{patarray 3 1 roll put}bd
+/makepat{
+scrmtx astore pop
+gsave
+initgraphics
+CM
+patarray exch get
+scrmtx
+makepattern
+grestore
+setpattern
+}bd
+/cg_BeginEPSF{
+ userdict save/cg_b4_Inc_state exch put
+ userdict/cg_endepsf/cg_EndEPSF load put
+ count userdict/cg_op_count 3 -1 roll put
+ countdictstack dup array dictstack userdict/cg_dict_array 3 -1 roll put
+ 3 sub{end}repeat
+ /showpage {} def
+ 0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin
+ 10 setmiterlimit [] 0 setdash newpath
+ false setstrokeadjust false setoverprint
+}bd
+/cg_EndEPSF{
+ countdictstack 3 sub { end } repeat
+ cg_dict_array 3 1 index length 3 sub getinterval
+ {begin}forall
+ count userdict/cg_op_count get sub{pop}repeat
+ userdict/cg_b4_Inc_state get restore
+ F setpacking
+}bd
+/cg_biproc{currentfile/RunLengthDecode filter}bd
+/cg_aiproc{currentfile/ASCII85Decode filter/RunLengthDecode filter}bd
+/ImageDataSource 0 def
+L3?{
+ /cg_mibiproc{pop pop/ImageDataSource{cg_biproc}def}bd
+ /cg_miaiproc{pop pop/ImageDataSource{cg_aiproc}def}bd
+}{
+ /ImageBandMask 0 def
+ /ImageBandData 0 def
+ /cg_mibiproc{
+ string/ImageBandMask xs
+ string/ImageBandData xs
+ /ImageDataSource{[currentfile/RunLengthDecode filter dup ImageBandMask/readstring cvx
+ /pop cvx dup ImageBandData/readstring cvx/pop cvx]cvx bind}bd
+ }bd
+ /cg_miaiproc{
+ string/ImageBandMask xs
+ string/ImageBandData xs
+ /ImageDataSource{[currentfile/ASCII85Decode filter/RunLengthDecode filter
+ dup ImageBandMask/readstring cvx
+ /pop cvx dup ImageBandData/readstring cvx/pop cvx]cvx bind}bd
+ }bd
+}ifelse
+/imsave 0 def
+/BI{save/imsave xd mark}bd
+/EI{imsave restore}bd
+/ID{
+counttomark 2 idiv
+dup 2 add
+dict begin
+{def} repeat
+pop
+/ImageType 1 def
+/ImageMatrix[Width 0 0 Height neg 0 Height]def
+currentdict dup/ImageMask known{ImageMask}{F}ifelse exch
+L3?{
+ dup/MaskedImage known
+ {
+ pop
+ <<
+ /ImageType 3
+ /InterleaveType 2
+ /DataDict currentdict
+ /MaskDict
+ << /ImageType 1
+ /Width Width
+ /Height Height
+ /ImageMatrix ImageMatrix
+ /BitsPerComponent 1
+ /Decode [0 1]
+ currentdict/Interpolate known
+ {/Interpolate Interpolate}if
+ >>
+ >>
+ }if
+}if
+exch
+{imagemask}{image}ifelse
+end
+}bd
+/cguidfix{statusdict begin mark version end
+{cvr}stopped{cleartomark 0}{exch pop}ifelse
+2012 lt{dup findfont dup length dict begin
+{1 index/FID ne 2 index/UniqueID ne and
+{def} {pop pop} ifelse}forall
+currentdict end definefont pop
+}{pop}ifelse
+}bd
+/t_array 0 def
+/t_i 0 def
+/t_c 1 string def
+/x_proc{
+ exch t_array t_i get add exch moveto
+ /t_i t_i 1 add store
+}bd
+/y_proc{
+ t_array t_i get add moveto
+ /t_i t_i 1 add store
+}bd
+/xy_proc{
+
+ t_array t_i 2 copy 1 add get 3 1 roll get
+ 4 -1 roll add 3 1 roll add moveto
+ /t_i t_i 2 add store
+}bd
+/sop 0 def
+/cp_proc/x_proc ld
+/base_charpath
+{
+ /t_array xs
+ /t_i 0 def
+ {
+ t_c 0 3 -1 roll put
+ currentpoint
+ t_c cply sop
+ cp_proc
+ }forall
+ /t_array 0 def
+}bd
+/sop/stroke ld
+/nop{}def
+/xsp/base_charpath ld
+/ysp{/cp_proc/y_proc ld base_charpath/cp_proc/x_proc ld}bd
+/xysp{/cp_proc/xy_proc ld base_charpath/cp_proc/x_proc ld}bd
+/xmp{/sop/nop ld /cp_proc/x_proc ld base_charpath/sop/stroke ld}bd
+/ymp{/sop/nop ld /cp_proc/y_proc ld base_charpath/sop/stroke ld}bd
+/xymp{/sop/nop ld /cp_proc/xy_proc ld base_charpath/sop/stroke ld}bd
+/refnt{
+findfont dup length dict copy dup
+/Encoding 4 -1 roll put
+definefont pop
+}bd
+/renmfont{
+findfont dup length dict copy definefont pop
+}bd
+L3? dup dup{save exch}if
+/Range 0 def
+/DataSource 0 def
+/val 0 def
+/nRange 0 def
+/mulRange 0 def
+/d0 0 def
+/r0 0 def
+/di 0 def
+/ri 0 def
+/a0 0 def
+/a1 0 def
+/r1 0 def
+/r2 0 def
+/dx 0 def
+/Nsteps 0 def
+/sh3tp 0 def
+/ymax 0 def
+/ymin 0 def
+/xmax 0 def
+/xmin 0 def
+/setupFunEval
+{
+ begin
+ /nRange Range length 2 idiv store
+ /mulRange
+
+ [
+ 0 1 nRange 1 sub
+ {
+ 2 mul/nDim2 xd
+ Range nDim2 get
+ Range nDim2 1 add get
+ 1 index sub
+
+ 255 div
+ exch
+ }for
+ ]store
+ end
+}bd
+/FunEval
+{
+ begin
+
+ nRange mul /val xd
+
+ 0 1 nRange 1 sub
+ {
+ dup 2 mul/nDim2 xd
+ val
+ add DataSource exch get
+ mulRange nDim2 get mul
+ mulRange nDim2 1 add get
+ add
+ }for
+ end
+}bd
+/max
+{
+ 2 copy lt
+ {exch pop}{pop}ifelse
+}bd
+/sh2
+{
+ /Coords load aload pop
+ 3 index 3 index translate
+
+ 3 -1 roll sub
+ 3 1 roll exch
+ sub
+ 2 copy
+ dup mul exch dup mul add sqrt
+ dup
+ scale
+ atan
+
+ rotate
+
+ /Function load setupFunEval
+
+
+ clippath {pathbbox}stopped {0 0 0 0}if newpath
+ /ymax xs
+ /xmax xs
+ /ymin xs
+ /xmin xs
+ currentdict/Extend known
+ {
+ /Extend load 0 get
+ {
+ 0/Function load FunEval sc
+ xmin ymin xmin abs ymax ymin sub rectfill
+ }if
+ }if
+
+ /Nsteps/Function load/Size get 0 get 1 sub store
+ /dx 1 Nsteps div store
+ gsave
+ /di ymax ymin sub store
+ /Function load
+
+ 0 1 Nsteps
+ {
+ 1 index FunEval sc
+ 0 ymin dx di rectfill
+ dx 0 translate
+ }for
+ pop
+ grestore
+ currentdict/Extend known
+ {
+ /Extend load 1 get
+ {
+ Nsteps/Function load FunEval sc
+ 1 ymin xmax 1 sub abs ymax ymin sub rectfill
+ }if
+ }if
+}bd
+/shp
+{
+ 4 copy
+
+ dup 0 gt{
+ 0 exch a1 a0 arc
+ }{
+ pop 0 moveto
+ }ifelse
+ dup 0 gt{
+ 0 exch a0 a1 arcn
+ }{
+ pop 0 lineto
+ }ifelse
+
+ fill
+
+ dup 0 gt{
+ 0 exch a0 a1 arc
+ }{
+ pop 0 moveto
+ }ifelse
+ dup 0 gt{
+ 0 exch a1 a0 arcn
+ }{
+ pop 0 lineto
+ }ifelse
+
+ fill
+}bd
+/calcmaxs
+{
+
+ xmin dup mul ymin dup mul add sqrt
+ xmax dup mul ymin dup mul add sqrt
+ xmin dup mul ymax dup mul add sqrt
+ xmax dup mul ymax dup mul add sqrt
+ max max max
+}bd
+/sh3
+{
+ /Coords load aload pop
+ 5 index 5 index translate
+ 3 -1 roll 6 -1 roll sub
+ 3 -1 roll 5 -1 roll sub
+ 2 copy dup mul exch dup mul add sqrt
+ /dx xs
+ 2 copy 0 ne exch 0 ne or
+ {
+
+ exch atan rotate
+ }{
+ pop pop
+ }ifelse
+
+ /r2 xs
+ /r1 xs
+ /Function load
+ dup/Size get 0 get 1 sub
+ /Nsteps xs
+ setupFunEval
+
+
+
+
+
+ dx r2 add r1 lt{
+
+ 0
+ }{
+ dx r1 add r2 le
+ {
+ 1
+ }{
+ r1 r2 eq
+ {
+ 2
+ }{
+ 3
+ }ifelse
+ }ifelse
+ }ifelse
+ /sh3tp xs
+ clippath {pathbbox}stopped {0 0 0 0}if
+ newpath
+ /ymax xs
+ /xmax xs
+ /ymin xs
+ /xmin xs
+
+ dx dup mul r2 r1 sub dup mul sub dup 0 gt
+ {
+ sqrt r2 r1 sub atan
+ /a0 exch 180 exch sub store
+ /a1 a0 neg store
+ }{
+ pop
+ /a0 0 store
+ /a1 360 store
+ }ifelse
+ currentdict/Extend known
+ {
+ /Extend load 0 get r1 0 gt and
+ {
+ 0/Function load FunEval sc
+
+
+
+
+ {
+ {
+ dx 0 r1 360 0 arcn
+ xmin ymin moveto
+ xmax ymin lineto
+ xmax ymax lineto
+ xmin ymax lineto
+ xmin ymin lineto
+ eofill
+ }
+ {
+ r1 0 gt{0 0 r1 0 360 arc fill}if
+ }
+ {
+
+
+
+
+ 0 r1 xmin abs r1 add neg r1 shp
+ }
+ {
+
+
+ r2 r1 gt{
+
+ 0 r1
+ r1 neg r2 r1 sub div dx mul
+ 0
+ shp
+ }{
+
+
+
+ 0 r1 calcmaxs
+ dup
+
+ r2 add dx mul dx r1 r2 sub sub div
+ neg
+ exch 1 index
+ abs exch sub
+ shp
+ }ifelse
+ }
+ }sh3tp get exec
+ }if
+ }if
+
+ /d0 0 store
+ /r0 r1 store
+ /di dx Nsteps div store
+ /ri r2 r1 sub Nsteps div store
+ /Function load
+ 0 1 Nsteps
+ {
+ 1 index FunEval sc
+ d0 di add r0 ri add d0 r0 shp
+ {
+
+ d0 0 r0 a1 a0 arc
+ d0 di add 0 r0 ri add a0 a1 arcn
+ fill
+
+
+ d0 0 r0 a0 a1 arc
+ d0 di add 0 r0 ri add a1 a0 arcn
+ fill
+ }pop
+
+
+ /d0 d0 di add store
+ /r0 r0 ri add store
+ }for
+ pop
+
+ currentdict/Extend known
+ {
+ /Extend load 1 get r2 0 gt and
+ {
+ Nsteps/Function load FunEval sc
+
+
+
+
+ {
+ {
+ dx 0 r2 0 360 arc fill
+ }
+ {
+ dx 0 r2 360 0 arcn
+ xmin ymin moveto
+ xmax ymin lineto
+ xmax ymax lineto
+ xmin ymax lineto
+ xmin ymin lineto
+ eofill
+ }
+ {
+
+
+ xmax abs r1 add r1 dx r1 shp
+ }
+ {
+
+ r2 r1 gt{
+
+
+
+ calcmaxs dup
+
+ r1 add dx mul dx r2 r1 sub sub div
+ exch 1 index
+ exch sub
+ dx r2
+ shp
+ }{
+
+ r1 neg r2 r1 sub div dx mul
+ 0
+ dx
+ r2
+ shp
+ }ifelse
+ }
+ }
+ sh3tp get exec
+ }if
+ }if
+}bd
+/sh
+{
+ begin
+ /ShadingType load dup dup 2 eq exch 3 eq or
+ {
+ gsave
+ newpath
+ /ColorSpace load scs
+ currentdict/BBox known
+ {
+ /BBox load aload pop
+ 2 index sub
+ 3 index
+ 3 -1 roll exch sub
+ exch rectclip
+ }if
+ 2 eq
+ {sh2}{sh3}ifelse
+ grestore
+ }{
+
+ pop
+ (DEBUG: shading type unimplemented\n)print flush
+ }ifelse
+ end
+}bd
+{restore}if not dup{save exch}if
+ L3?{
+ /sh/shfill ld
+ /csq/clipsave ld
+ /csQ/cliprestore ld
+ }if
+{restore}if
+end
+setpacking
+%%EndFile
+%%EndProlog
+%%BeginSetup
+%%EndSetup
+%%Page: 1 1
+%%PageBoundingBox: 0 0 160 160
+%%BeginPageSetup
+cg_md begin
+bp
+sdmtx
+[ /CIEBasedABC 4 dict dup begin
+/WhitePoint [ 0.9505 1.0000 1.0891 ] def
+/DecodeABC [
+{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse
+ 1 index 1 index ge { exch pop } { pop } ifelse <
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000001010101010101010101010101
+0101010101010101010101010101010101010101010101020202020202020202
+0202020202020202020202020202020202030303030303030303030303030303
+0303030303030304040404040404040404040404040404040404050505050505
+0505050505050505050506060606060606060606060606060607070707070707
+0707070707070708080808080808080808080808090909090909090909090909
+0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c
+0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010
+1010101010111111111111111112121212121212121313131313131313141414
+1414141414151515151515151616161616161616171717171717171818181818
+18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d
+1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223
+2323232323242424242425252525252526262626262727272727282828282829
+292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f
+2f2f303030303131313131323232323333333333343434343535353535363636
+36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e
+3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646
+4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f
+4f50505051515151525252535353535454545555555656565657575758585859
+59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263
+63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e
+6e6e6f6f6f707070717171727273737374747475757576767677777878787979
+797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585
+86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292
+9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f
+a0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae
+aeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd
+bdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc
+cdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd
+dddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee
+eeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff
+> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling
+ cvi 3 index exch get 4 -1 roll 3 -1 roll get
+ dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind
+
+{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse
+ 1 index 1 index ge { exch pop } { pop } ifelse <
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000001010101010101010101010101
+0101010101010101010101010101010101010101010101020202020202020202
+0202020202020202020202020202020202030303030303030303030303030303
+0303030303030304040404040404040404040404040404040404050505050505
+0505050505050505050506060606060606060606060606060607070707070707
+0707070707070708080808080808080808080808090909090909090909090909
+0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c
+0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010
+1010101010111111111111111112121212121212121313131313131313141414
+1414141414151515151515151616161616161616171717171717171818181818
+18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d
+1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223
+2323232323242424242425252525252526262626262727272727282828282829
+292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f
+2f2f303030303131313131323232323333333333343434343535353535363636
+36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e
+3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646
+4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f
+4f50505051515151525252535353535454545555555656565657575758585859
+59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263
+63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e
+6e6e6f6f6f707070717171727273737374747475757576767677777878787979
+797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585
+86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292
+9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f
+a0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae
+aeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd
+bdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc
+cdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd
+dddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee
+eeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff
+> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling
+ cvi 3 index exch get 4 -1 roll 3 -1 roll get
+ dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind
+
+{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse
+ 1 index 1 index ge { exch pop } { pop } ifelse <
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000001010101010101010101010101
+0101010101010101010101010101010101010101010101020202020202020202
+0202020202020202020202020202020202030303030303030303030303030303
+0303030303030304040404040404040404040404040404040404050505050505
+0505050505050505050506060606060606060606060606060607070707070707
+0707070707070708080808080808080808080808090909090909090909090909
+0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c
+0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010
+1010101010111111111111111112121212121212121313131313131313141414
+1414141414151515151515151616161616161616171717171717171818181818
+18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d
+1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223
+2323232323242424242425252525252526262626262727272727282828282829
+292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f
+2f2f303030303131313131323232323333333333343434343535353535363636
+36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e
+3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646
+4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f
+4f50505051515151525252535353535454545555555656565657575758585859
+59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263
+63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e
+6e6e6f6f6f707070717171727273737374747475757576767677777878787979
+797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585
+86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292
+9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f
+a0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae
+aeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd
+bdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc
+cdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd
+dddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee
+eeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff
+> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling
+ cvi 3 index exch get 4 -1 roll 3 -1 roll get
+ dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind
+] def
+/MatrixABC [ 0.4124 0.2126 0.0193 0.3576 0.7151 0.1192 0.1805 0.0722 0.9508 ] def
+/RangeLMN [ 0.0 0.9505 0.0 1.0000 0.0 1.0891 ] def
+end ] /Cs1 exch/ColorSpace dr pop
+%%EndPageSetup
+0.60000002 i
+/Cs1 SC
+0.10588235 0.72549021 0.12156863 sc
+q
+0 44 m
+160 44 l
+160 15.003872 l
+160 6.7174625 153.27803 0 145.00154 0 c
+14.998466 0 l
+6.7150416 0 0 6.7065849 0 15.003872 c
+0 44 l
+h
+0 44 m
+160 44 l
+160 14 l
+0 14 l
+0 44 l
+h
+0 44 m
+W*
+0 0 160 160 rc
+-5 49 m
+165 49 l
+165 -5 l
+-5 -5 l
+h
+f
+Q
+0.23529412 0.23529412 0.23529412 sc
+q
+83 90 m
+83 160 l
+77 160 l
+77 14 l
+83 14 l
+83 84 l
+160 84 l
+160 90 l
+83 90 l
+h
+0 144.99352 m
+0 153.28137 6.7219648 160 14.998466 160 c
+145.00154 160 l
+153.28496 160 160 153.27509 160 144.99352 c
+160 14 l
+0 14 l
+0 144.99352 l
+h
+0 144.99352 m
+W*
+0 0 160 160 rc
+-5 165 m
+165 165 l
+165 9 l
+-5 9 l
+h
+f
+ep
+end
+%%Trailer
+%%EOF
diff --git a/logo/tmux-logomark.svg b/logo/tmux-logomark.svg
new file mode 100644
index 00000000..c543709d
--- /dev/null
+++ b/logo/tmux-logomark.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="160px" height="160px" viewBox="0 0 160 160" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
+ <!-- Generator: Sketch 3.3.1 (12005) - http://www.bohemiancoding.com/sketch -->
+ <title>logomark copy</title>
+ <desc>Created with Sketch.</desc>
+ <defs></defs>
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
+ <g id="logomark-copy" sketch:type="MSLayerGroup">
+ <g id="status-bar" transform="translate(0.000000, 116.000000)" fill="#1BB91F" sketch:type="MSShapeGroup">
+ <path d="M0,0 L160,0 L160,28.9961276 C160,37.2825375 153.278035,44 145.001535,44 L14.9984654,44 C6.71504169,44 0,37.2934149 0,28.9961276 L0,0 Z M0,0 L160,0 L160,30 L0,30 L0,0 Z" id="Rectangle-5"></path>
+ </g>
+ <path d="M83,70 L83,0 L77,0 L77,146 L83,146 L83,76 L160,76 L160,70 L83,70 Z M0,15.0064867 C0,6.71863293 6.72196489,0 14.9984654,0 L145.001535,0 C153.284958,0 160,6.72491953 160,15.0064867 L160,146 L0,146 L0,15.0064867 Z" id="screen" fill="#3C3C3C" sketch:type="MSShapeGroup"></path>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/mdoc2man.awk b/mdoc2man.awk
new file mode 100644
index 00000000..80e8d5ff
--- /dev/null
+++ b/mdoc2man.awk
@@ -0,0 +1,370 @@
+#!/usr/bin/awk
+#
+# $Id: mdoc2man.awk,v 1.9 2009/10/24 00:52:42 dtucker Exp $
+#
+# Version history:
+# v4+ Adapted for OpenSSH Portable (see cvs Id and history)
+# v3, I put the program under a proper license
+# Dan Nelson <dnelson@allantgroup.com> added .An, .Aq and fixed a typo
+# v2, fixed to work on GNU awk --posix and MacOS X
+# v1, first attempt, didn't work on MacOS X
+#
+# Copyright (c) 2003 Peter Stuge <stuge-mdoc2man@cdy.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
+BEGIN {
+ optlist=0
+ oldoptlist=0
+ nospace=0
+ synopsis=0
+ reference=0
+ block=0
+ ext=0
+ extopt=0
+ literal=0
+ prenl=0
+ breakw=0
+ line=""
+}
+
+function wtail() {
+ retval=""
+ while(w<nwords) {
+ if(length(retval))
+ retval=retval OFS
+ retval=retval words[++w]
+ }
+ return retval
+}
+
+function add(str) {
+ for(;prenl;prenl--)
+ line=line "\n"
+ line=line str
+}
+
+! /^\./ {
+ for(;prenl;prenl--)
+ print ""
+ print
+ if(literal)
+ print ".br"
+ next
+}
+
+/^\.\\"/ { next }
+
+{
+ option=0
+ parens=0
+ angles=0
+ sub("^\\.","")
+ nwords=split($0,words)
+ for(w=1;w<=nwords;w++) {
+ skip=0
+ if(match(words[w],"^Li|Pf$")) {
+ skip=1
+ } else if(match(words[w],"^Xo$")) {
+ skip=1
+ ext=1
+ if(length(line)&&!(match(line," $")||prenl))
+ add(OFS)
+ } else if(match(words[w],"^Xc$")) {
+ skip=1
+ ext=0
+ if(!extopt)
+ prenl++
+ w=nwords
+ } else if(match(words[w],"^Bd$")) {
+ skip=1
+ if(match(words[w+1],"-literal")) {
+ literal=1
+ prenl++
+ w=nwords
+ }
+ } else if(match(words[w],"^Ed$")) {
+ skip=1
+ literal=0
+ } else if(match(words[w],"^Ns$")) {
+ skip=1
+ if(!nospace)
+ nospace=1
+ sub(" $","",line)
+ } else if(match(words[w],"^No$")) {
+ skip=1
+ sub(" $","",line)
+ add(words[++w])
+ } else if(match(words[w],"^Dq$")) {
+ skip=1
+ add("``")
+ add(words[++w])
+ while(w<nwords&&!match(words[w+1],"^[\\.,]"))
+ add(OFS words[++w])
+ add("''")
+ if(!nospace&&match(words[w+1],"^[\\.,]"))
+ nospace=1
+ } else if(match(words[w],"^Sq|Ql$")) {
+ skip=1
+ add("`" words[++w] "'")
+ if(!nospace&&match(words[w+1],"^[\\.,]"))
+ nospace=1
+ } else if(match(words[w],"^Oo$")) {
+ skip=1
+ extopt=1
+ if(!nospace)
+ nospace=1
+ add("[")
+ } else if(match(words[w],"^Oc$")) {
+ skip=1
+ extopt=0
+ add("]")
+ }
+ if(!skip) {
+ if(!nospace&&length(line)&&!(match(line," $")||prenl))
+ add(OFS)
+ if(nospace==1)
+ nospace=0
+ }
+ if(match(words[w],"^Dd$")) {
+ if(match(words[w+1],"^\\$Mdocdate:")) {
+ w++;
+ if(match(words[w+4],"^\\$$")) {
+ words[w+4] = ""
+ }
+ }
+ date=wtail()
+ next
+ } else if(match(words[w],"^Dt$")) {
+ id=wtail()
+ next
+ } else if(match(words[w],"^Ux$")) {
+ add("UNIX")
+ skip=1
+ } else if(match(words[w],"^Ox$")) {
+ add("OpenBSD")
+ skip=1
+ } else if(match(words[w],"^Os$")) {
+ add(".TH " id " \"" date "\" \"" wtail() "\"")
+ } else if(match(words[w],"^Sh$")) {
+ add(".SH")
+ synopsis=match(words[w+1],"SYNOPSIS")
+ } else if(match(words[w],"^Xr$")) {
+ add("\\fB" words[++w] "\\fP(" words[++w] ")" words[++w])
+ } else if(match(words[w],"^Rs$")) {
+ split("",refauthors)
+ nrefauthors=0
+ reftitle=""
+ refissue=""
+ refdate=""
+ refopt=""
+ refreport=""
+ reference=1
+ next
+ } else if(match(words[w],"^Re$")) {
+ prenl++
+ for(i=nrefauthors-1;i>0;i--) {
+ add(refauthors[i])
+ if(i>1)
+ add(", ")
+ }
+ if(nrefauthors>1)
+ add(" and ")
+ if(nrefauthors>0)
+ add(refauthors[0] ", ")
+ add("\\fI" reftitle "\\fP")
+ if(length(refissue))
+ add(", " refissue)
+ if(length(refreport)) {
+ add(", " refreport)
+ }
+ if(length(refdate))
+ add(", " refdate)
+ if(length(refopt))
+ add(", " refopt)
+ add(".")
+ reference=0
+ } else if(reference) {
+ if(match(words[w],"^%A$")) { refauthors[nrefauthors++]=wtail() }
+ if(match(words[w],"^%T$")) {
+ reftitle=wtail()
+ sub("^\"","",reftitle)
+ sub("\"$","",reftitle)
+ }
+ if(match(words[w],"^%N$")) { refissue=wtail() }
+ if(match(words[w],"^%D$")) { refdate=wtail() }
+ if(match(words[w],"^%O$")) { refopt=wtail() }
+ if(match(words[w],"^%R$")) { refreport=wtail() }
+ } else if(match(words[w],"^Nm$")) {
+ if(synopsis) {
+ add(".br")
+ prenl++
+ }
+ n=words[++w]
+ if(!length(name))
+ name=n
+ if(!length(n))
+ n=name
+ add("\\fB" n "\\fP")
+ if(!nospace&&match(words[w+1],"^[\\.,]"))
+ nospace=1
+ } else if(match(words[w],"^Nd$")) {
+ add("\\- " wtail())
+ } else if(match(words[w],"^Fl$")) {
+ add("\\fB\\-" words[++w] "\\fP")
+ if(!nospace&&match(words[w+1],"^[\\.,]"))
+ nospace=1
+ } else if(match(words[w],"^Ar$")) {
+ add("\\fI")
+ if(w==nwords)
+ add("file ...\\fP")
+ else {
+ add(words[++w] "\\fP")
+ while(match(words[w+1],"^\\|$"))
+ add(OFS words[++w] " \\fI" words[++w] "\\fP")
+ }
+ if(!nospace&&match(words[w+1],"^[\\.,]"))
+ nospace=1
+ } else if(match(words[w],"^Cm$")) {
+ add("\\fB" words[++w] "\\fP")
+ while(w<nwords&&match(words[w+1],"^[\\.,:;)]"))
+ add(words[++w])
+ } else if(match(words[w],"^Op$")) {
+ option=1
+ if(!nospace)
+ nospace=1
+ add("[")
+ } else if(match(words[w],"^Pp$")) {
+ prenl++
+ } else if(match(words[w],"^An$")) {
+ prenl++
+ } else if(match(words[w],"^Ss$")) {
+ add(".SS")
+ } else if(match(words[w],"^Pa$")&&!option) {
+ add("\\fI")
+ w++
+ if(match(words[w],"^\\."))
+ add("\\&")
+ add(words[w] "\\fP")
+ while(w<nwords&&match(words[w+1],"^[\\.,:;)]"))
+ add(words[++w])
+ } else if(match(words[w],"^Dv$")) {
+ add(".BR")
+ } else if(match(words[w],"^Em|Ev$")) {
+ add(".IR")
+ } else if(match(words[w],"^Pq$")) {
+ add("(")
+ nospace=1
+ parens=1
+ } else if(match(words[w],"^Aq$")) {
+ add("<")
+ nospace=1
+ angles=1
+ } else if(match(words[w],"^S[xy]$")) {
+ add(".B " wtail())
+ } else if(match(words[w],"^Ic$")) {
+ plain=1
+ add("\\fB")
+ while(w<nwords) {
+ w++
+ if(match(words[w],"^Op$")) {
+ w++
+ add("[")
+ words[nwords]=words[nwords] "]"
+ }
+ if(match(words[w],"^Ar$")) {
+ add("\\fI" words[++w] "\\fP")
+ } else if(match(words[w],"^[\\.,]")) {
+ sub(" $","",line)
+ if(plain) {
+ add("\\fP")
+ plain=0
+ }
+ add(words[w])
+ } else {
+ if(!plain) {
+ add("\\fB")
+ plain=1
+ }
+ add(words[w])
+ }
+ if(!nospace)
+ add(OFS)
+ }
+ sub(" $","",line)
+ if(plain)
+ add("\\fP")
+ } else if(match(words[w],"^Bl$")) {
+ oldoptlist=optlist
+ if(match(words[w+1],"-bullet"))
+ optlist=1
+ else if(match(words[w+1],"-enum")) {
+ optlist=2
+ enum=0
+ } else if(match(words[w+1],"-tag"))
+ optlist=3
+ else if(match(words[w+1],"-item"))
+ optlist=4
+ else if(match(words[w+1],"-bullet"))
+ optlist=1
+ w=nwords
+ } else if(match(words[w],"^El$")) {
+ optlist=oldoptlist
+ } else if(match(words[w],"^Bk$")) {
+ if(match(words[w+1],"-words")) {
+ w++
+ breakw=1
+ }
+ } else if(match(words[w],"^Ek$")) {
+ breakw=0
+ } else if(match(words[w],"^It$")&&optlist) {
+ if(optlist==1)
+ add(".IP \\(bu")
+ else if(optlist==2)
+ add(".IP " ++enum ".")
+ else if(optlist==3) {
+ add(".TP")
+ prenl++
+ if(match(words[w+1],"^Pa$|^Ev$")) {
+ add(".B")
+ w++
+ }
+ } else if(optlist==4)
+ add(".IP")
+ } else if(match(words[w],"^Sm$")) {
+ if(match(words[w+1],"off"))
+ nospace=2
+ else if(match(words[w+1],"on"))
+ nospace=0
+ w++
+ } else if(!skip) {
+ add(words[w])
+ }
+ }
+ if(match(line,"^\\.[^a-zA-Z]"))
+ sub("^\\.","",line)
+ if(parens)
+ add(")")
+ if(angles)
+ add(">")
+ if(option)
+ add("]")
+ if(ext&&!extopt&&!match(line," $"))
+ add(OFS)
+ if(!ext&&!extopt&&length(line)) {
+ print line
+ prenl=0
+ line=""
+ }
+}
diff --git a/mode-key.c b/mode-key.c
deleted file mode 100644
index 4245d173..00000000
--- a/mode-key.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/* $OpenBSD$ */
-
-/*
- * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-
-#include <string.h>
-
-#include "tmux.h"
-
-/*
- * Mode keys. These are the key bindings used when editing (status prompt), and
- * in the modes. They are split into two sets of three tables, one set of three
- * for vi and the other for emacs key bindings. The three tables are for
- * editing, for menu-like modes (choice, more), and for copy modes (copy,
- * scroll).
- *
- * The fixed tables of struct mode_key_entry below are the defaults: they are
- * built into a tree of struct mode_key_binding by mode_key_init_trees, which
- * can then be modified.
- *
- * vi command mode is handled by having a mode flag in the struct which allows
- * two sets of bindings to be swapped between. A couple of editing commands
- * (any matching MODEKEYEDIT_SWITCHMODE*) are special-cased to do this.
- */
-
-/* Command to string mapping. */
-struct mode_key_cmdstr {
- enum mode_key_cmd cmd;
- const char *name;
-};
-
-/* Entry in the default mode key tables. */
-struct mode_key_entry {
- key_code key;
- enum mode_key_cmd cmd;
-};
-
-/* Choice keys command strings. */
-static const struct mode_key_cmdstr mode_key_cmdstr_choice[] = {
- { MODEKEYCHOICE_BACKSPACE, "backspace" },
- { MODEKEYCHOICE_BOTTOMLINE, "bottom-line"},
- { MODEKEYCHOICE_CANCEL, "cancel" },
- { MODEKEYCHOICE_CHOOSE, "choose" },
- { MODEKEYCHOICE_DOWN, "down" },
- { MODEKEYCHOICE_ENDOFLIST, "end-of-list"},
- { MODEKEYCHOICE_PAGEDOWN, "page-down" },
- { MODEKEYCHOICE_PAGEUP, "page-up" },
- { MODEKEYCHOICE_SCROLLDOWN, "scroll-down" },
- { MODEKEYCHOICE_SCROLLUP, "scroll-up" },
- { MODEKEYCHOICE_STARTNUMBERPREFIX, "start-number-prefix" },
- { MODEKEYCHOICE_STARTOFLIST, "start-of-list"},
- { MODEKEYCHOICE_TOPLINE, "top-line"},
- { MODEKEYCHOICE_TREE_COLLAPSE, "tree-collapse" },
- { MODEKEYCHOICE_TREE_COLLAPSE_ALL, "tree-collapse-all" },
- { MODEKEYCHOICE_TREE_EXPAND, "tree-expand" },
- { MODEKEYCHOICE_TREE_EXPAND_ALL, "tree-expand-all" },
- { MODEKEYCHOICE_TREE_TOGGLE, "tree-toggle" },
- { MODEKEYCHOICE_UP, "up" },
-
- { 0, NULL }
-};
-
-/* vi choice selection keys. */
-static const struct mode_key_entry mode_key_vi_choice[] = {
- { '0' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '1' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '2' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '3' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '4' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '5' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '6' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '7' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '8' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '9' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '\002' /* C-b */, MODEKEYCHOICE_PAGEUP },
- { '\003' /* C-c */, MODEKEYCHOICE_CANCEL },
- { '\005' /* C-e */, MODEKEYCHOICE_SCROLLDOWN },
- { '\006' /* C-f */, MODEKEYCHOICE_PAGEDOWN },
- { '\031' /* C-y */, MODEKEYCHOICE_SCROLLUP },
- { '\n', MODEKEYCHOICE_CHOOSE },
- { '\r', MODEKEYCHOICE_CHOOSE },
- { 'j', MODEKEYCHOICE_DOWN },
- { 'k', MODEKEYCHOICE_UP },
- { 'q', MODEKEYCHOICE_CANCEL },
- { KEYC_HOME, MODEKEYCHOICE_STARTOFLIST },
- { 'g', MODEKEYCHOICE_STARTOFLIST },
- { 'H', MODEKEYCHOICE_TOPLINE },
- { 'L', MODEKEYCHOICE_BOTTOMLINE },
- { 'G', MODEKEYCHOICE_ENDOFLIST },
- { KEYC_END, MODEKEYCHOICE_ENDOFLIST },
- { KEYC_BSPACE, MODEKEYCHOICE_BACKSPACE },
- { KEYC_DOWN | KEYC_CTRL, MODEKEYCHOICE_SCROLLDOWN },
- { KEYC_DOWN, MODEKEYCHOICE_DOWN },
- { KEYC_NPAGE, MODEKEYCHOICE_PAGEDOWN },
- { KEYC_PPAGE, MODEKEYCHOICE_PAGEUP },
- { KEYC_UP | KEYC_CTRL, MODEKEYCHOICE_SCROLLUP },
- { KEYC_UP, MODEKEYCHOICE_UP },
- { ' ', MODEKEYCHOICE_TREE_TOGGLE },
- { KEYC_LEFT, MODEKEYCHOICE_TREE_COLLAPSE },
- { KEYC_RIGHT, MODEKEYCHOICE_TREE_EXPAND },
- { KEYC_LEFT | KEYC_CTRL, MODEKEYCHOICE_TREE_COLLAPSE_ALL },
- { KEYC_RIGHT | KEYC_CTRL, MODEKEYCHOICE_TREE_EXPAND_ALL },
- { KEYC_MOUSEDOWN1_PANE, MODEKEYCHOICE_CHOOSE },
- { KEYC_MOUSEDOWN3_PANE, MODEKEYCHOICE_TREE_TOGGLE },
- { KEYC_WHEELUP_PANE, MODEKEYCHOICE_UP },
- { KEYC_WHEELDOWN_PANE, MODEKEYCHOICE_DOWN },
-
- { KEYC_NONE, -1 }
-};
-struct mode_key_tree mode_key_tree_vi_choice;
-
-/* emacs choice selection keys. */
-static const struct mode_key_entry mode_key_emacs_choice[] = {
- { '0' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '1' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '2' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '3' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '4' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '5' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '6' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '7' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '8' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '9' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
- { '\003' /* C-c */, MODEKEYCHOICE_CANCEL },
- { '\016' /* C-n */, MODEKEYCHOICE_DOWN },
- { '\020' /* C-p */, MODEKEYCHOICE_UP },
- { '\026' /* C-v */, MODEKEYCHOICE_PAGEDOWN },
- { '\033' /* Escape */, MODEKEYCHOICE_CANCEL },
- { '\n', MODEKEYCHOICE_CHOOSE },
- { '\r', MODEKEYCHOICE_CHOOSE },
- { 'q', MODEKEYCHOICE_CANCEL },
- { 'v' | KEYC_ESCAPE, MODEKEYCHOICE_PAGEUP },
- { KEYC_HOME, MODEKEYCHOICE_STARTOFLIST },
- { '<' | KEYC_ESCAPE, MODEKEYCHOICE_STARTOFLIST },
- { 'R' | KEYC_ESCAPE, MODEKEYCHOICE_TOPLINE },
- { '>' | KEYC_ESCAPE, MODEKEYCHOICE_ENDOFLIST },
- { KEYC_END, MODEKEYCHOICE_ENDOFLIST },
- { KEYC_BSPACE, MODEKEYCHOICE_BACKSPACE },
- { KEYC_DOWN | KEYC_CTRL, MODEKEYCHOICE_SCROLLDOWN },
- { KEYC_DOWN, MODEKEYCHOICE_DOWN },
- { KEYC_NPAGE, MODEKEYCHOICE_PAGEDOWN },
- { KEYC_PPAGE, MODEKEYCHOICE_PAGEUP },
- { KEYC_UP | KEYC_CTRL, MODEKEYCHOICE_SCROLLUP },
- { KEYC_UP, MODEKEYCHOICE_UP },
- { ' ', MODEKEYCHOICE_TREE_TOGGLE },
- { KEYC_LEFT, MODEKEYCHOICE_TREE_COLLAPSE },
- { KEYC_RIGHT, MODEKEYCHOICE_TREE_EXPAND },
- { KEYC_LEFT | KEYC_CTRL, MODEKEYCHOICE_TREE_COLLAPSE_ALL },
- { KEYC_RIGHT | KEYC_CTRL, MODEKEYCHOICE_TREE_EXPAND_ALL },
- { KEYC_MOUSEDOWN1_PANE, MODEKEYCHOICE_CHOOSE },
- { KEYC_MOUSEDOWN3_PANE, MODEKEYCHOICE_TREE_TOGGLE },
- { KEYC_WHEELUP_PANE, MODEKEYCHOICE_UP },
- { KEYC_WHEELDOWN_PANE, MODEKEYCHOICE_DOWN },
-
- { KEYC_NONE, -1 }
-};
-struct mode_key_tree mode_key_tree_emacs_choice;
-
-/* Table mapping key table names to default settings and trees. */
-static const struct mode_key_table mode_key_tables[] = {
- { "vi-choice", mode_key_cmdstr_choice,
- &mode_key_tree_vi_choice, mode_key_vi_choice },
- { "emacs-choice", mode_key_cmdstr_choice,
- &mode_key_tree_emacs_choice, mode_key_emacs_choice },
-
- { NULL, NULL, NULL, NULL }
-};
-
-RB_GENERATE(mode_key_tree, mode_key_binding, entry, mode_key_cmp);
-
-int
-mode_key_cmp(struct mode_key_binding *mbind1, struct mode_key_binding *mbind2)
-{
- if (mbind1->key < mbind2->key)
- return (-1);
- if (mbind1->key > mbind2->key)
- return (1);
- return (0);
-}
-
-const char *
-mode_key_tostring(const struct mode_key_cmdstr *cmdstr, enum mode_key_cmd cmd)
-{
- for (; cmdstr->name != NULL; cmdstr++) {
- if (cmdstr->cmd == cmd)
- return (cmdstr->name);
- }
- return (NULL);
-}
-
-enum mode_key_cmd
-mode_key_fromstring(const struct mode_key_cmdstr *cmdstr, const char *name)
-{
- for (; cmdstr->name != NULL; cmdstr++) {
- if (strcasecmp(cmdstr->name, name) == 0)
- return (cmdstr->cmd);
- }
- return (MODEKEY_NONE);
-}
-
-const struct mode_key_table *
-mode_key_findtable(const char *name)
-{
- const struct mode_key_table *mtab;
-
- for (mtab = mode_key_tables; mtab->name != NULL; mtab++) {
- if (strcasecmp(name, mtab->name) == 0)
- return (mtab);
- }
- return (NULL);
-}
-
-void
-mode_key_init_trees(void)
-{
- const struct mode_key_table *mtab;
- const struct mode_key_entry *ment;
- struct mode_key_binding *mbind;
-
- for (mtab = mode_key_tables; mtab->name != NULL; mtab++) {
- RB_INIT(mtab->tree);
- for (ment = mtab->table; ment->key != KEYC_NONE; ment++) {
- mbind = xmalloc(sizeof *mbind);
- mbind->key = ment->key;
- mbind->cmd = ment->cmd;
- RB_INSERT(mode_key_tree, mtab->tree, mbind);
- }
- }
-}
-
-void
-mode_key_init(struct mode_key_data *mdata, struct mode_key_tree *mtree)
-{
- mdata->tree = mtree;
-}
-
-enum mode_key_cmd
-mode_key_lookup(struct mode_key_data *mdata, key_code key)
-{
- struct mode_key_binding *mbind, mtmp;
-
- mtmp.key = key;
- if ((mbind = RB_FIND(mode_key_tree, mdata->tree, &mtmp)) == NULL)
- return (MODEKEY_OTHER);
- return (mbind->cmd);
-}
diff --git a/notify.c b/notify.c
index c91a4399..200e23d6 100644
--- a/notify.c
+++ b/notify.c
@@ -17,7 +17,6 @@
*/
#include <sys/types.h>
-#include <sys/queue.h>
#include <stdlib.h>
#include <string.h>
diff --git a/options-table.c b/options-table.c
index d8612ff2..be0d220d 100644
--- a/options-table.c
+++ b/options-table.c
@@ -19,7 +19,6 @@
#include <sys/types.h>
#include <string.h>
-#include <paths.h>
#include "tmux.h"
diff --git a/osdep-aix.c b/osdep-aix.c
new file mode 100644
index 00000000..e1ce4918
--- /dev/null
+++ b/osdep-aix.c
@@ -0,0 +1,95 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/procfs.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "tmux.h"
+
+char *
+osdep_get_name(__unused int fd, char *tty)
+{
+ struct psinfo p;
+ char *path;
+ ssize_t bytes;
+ int f, ttyfd, retval;
+ pid_t pgrp;
+
+ if ((ttyfd = open(tty, O_RDONLY|O_NOCTTY)) == -1)
+ return (NULL);
+
+ retval = ioctl(ttyfd, TIOCGPGRP, &pgrp);
+ close(ttyfd);
+ if (retval == -1)
+ return (NULL);
+
+ xasprintf(&path, "/proc/%u/psinfo", (u_int) pgrp);
+ f = open(path, O_RDONLY);
+ free(path);
+ if (f < 0)
+ return (NULL);
+
+ bytes = read(f, &p, sizeof(p));
+ close(f);
+ if (bytes != sizeof(p))
+ return (NULL);
+
+ return (xstrdup(p.pr_fname));
+}
+
+char *
+osdep_get_cwd(int fd)
+{
+ static char target[MAXPATHLEN + 1];
+ char *path;
+ const char *ttypath;
+ ssize_t n;
+ pid_t pgrp;
+ int len, retval, ttyfd;
+
+ if ((ttypath = ptsname(fd)) == NULL)
+ return (NULL);
+ if ((ttyfd = open(ttypath, O_RDONLY|O_NOCTTY)) == -1)
+ return (NULL);
+
+ retval = ioctl(ttyfd, TIOCGPGRP, &pgrp);
+ close(ttyfd);
+ if (retval == -1)
+ return (NULL);
+
+ xasprintf(&path, "/proc/%u/cwd", (u_int) pgrp);
+ n = readlink(path, target, MAXPATHLEN);
+ free(path);
+ if (n > 0) {
+ target[n] = '\0';
+ if ((len = strlen(target)) > 1 && target[len - 1] == '/')
+ target[len - 1] = '\0';
+ return (target);
+ }
+ return (NULL);
+}
+
+struct event_base *
+osdep_event_init(void)
+{
+ return (event_init());
+}
diff --git a/osdep-cygwin.c b/osdep-cygwin.c
new file mode 100644
index 00000000..60630b33
--- /dev/null
+++ b/osdep-cygwin.c
@@ -0,0 +1,88 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <event.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "tmux.h"
+
+char *
+osdep_get_name(int fd, __unused char *tty)
+{
+ FILE *f;
+ char *path, *buf;
+ size_t len;
+ int ch;
+ pid_t pgrp;
+
+ if ((pgrp = tcgetpgrp(fd)) == -1)
+ return (NULL);
+
+ xasprintf(&path, "/proc/%lld/cmdline", (long long) pgrp);
+ if ((f = fopen(path, "r")) == NULL) {
+ free(path);
+ return (NULL);
+ }
+ free(path);
+
+ len = 0;
+ buf = NULL;
+ while ((ch = fgetc(f)) != EOF) {
+ if (ch == '\0')
+ break;
+ buf = xrealloc(buf, len + 2);
+ buf[len++] = ch;
+ }
+ if (buf != NULL)
+ buf[len] = '\0';
+
+ fclose(f);
+ return (buf);
+}
+
+char *
+osdep_get_cwd(int fd)
+{
+ static char target[MAXPATHLEN + 1];
+ char *path;
+ pid_t pgrp;
+ ssize_t n;
+
+ if ((pgrp = tcgetpgrp(fd)) == -1)
+ return (NULL);
+
+ xasprintf(&path, "/proc/%lld/cwd", (long long) pgrp);
+ n = readlink(path, target, MAXPATHLEN);
+ free(path);
+ if (n > 0) {
+ target[n] = '\0';
+ return (target);
+ }
+ return (NULL);
+}
+
+struct event_base *
+osdep_event_init(void)
+{
+ return (event_init());
+}
diff --git a/osdep-darwin.c b/osdep-darwin.c
new file mode 100644
index 00000000..d4a88028
--- /dev/null
+++ b/osdep-darwin.c
@@ -0,0 +1,107 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <Availability.h>
+#include <event.h>
+#include <libproc.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+char *osdep_get_name(int, char *);
+char *osdep_get_cwd(int);
+struct event_base *osdep_event_init(void);
+
+#ifndef __unused
+#define __unused __attribute__ ((__unused__))
+#endif
+
+char *
+osdep_get_name(int fd, __unused char *tty)
+{
+#ifdef __MAC_10_7
+ struct proc_bsdshortinfo bsdinfo;
+ pid_t pgrp;
+ int ret;
+
+ if ((pgrp = tcgetpgrp(fd)) == -1)
+ return (NULL);
+
+ ret = proc_pidinfo(pgrp, PROC_PIDT_SHORTBSDINFO, 0,
+ &bsdinfo, sizeof bsdinfo);
+ if (ret == sizeof bsdinfo && *bsdinfo.pbsi_comm != '\0')
+ return (strdup(bsdinfo.pbsi_comm));
+ return (NULL);
+#else
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
+ size_t size;
+ struct kinfo_proc kp;
+
+ if ((mib[3] = tcgetpgrp(fd)) == -1)
+ return (NULL);
+
+ size = sizeof kp;
+ if (sysctl(mib, 4, &kp, &size, NULL, 0) == -1)
+ return (NULL);
+ if (*kp.kp_proc.p_comm == '\0')
+ return (NULL);
+
+ return (strdup(kp.kp_proc.p_comm));
+#endif
+}
+
+char *
+osdep_get_cwd(int fd)
+{
+ static char wd[PATH_MAX];
+ struct proc_vnodepathinfo pathinfo;
+ pid_t pgrp;
+ int ret;
+
+ if ((pgrp = tcgetpgrp(fd)) == -1)
+ return (NULL);
+
+ ret = proc_pidinfo(pgrp, PROC_PIDVNODEPATHINFO, 0,
+ &pathinfo, sizeof pathinfo);
+ if (ret == sizeof pathinfo) {
+ strlcpy(wd, pathinfo.pvi_cdir.vip_path, sizeof wd);
+ return (wd);
+ }
+ return (NULL);
+}
+
+struct event_base *
+osdep_event_init(void)
+{
+ struct event_base *base;
+
+ /*
+ * On OS X, kqueue and poll are both completely broken and don't
+ * work on anything except socket file descriptors (yes, really).
+ */
+ setenv("EVENT_NOKQUEUE", "1", 1);
+ setenv("EVENT_NOPOLL", "1", 1);
+
+ base = event_init();
+ unsetenv("EVENT_NOKQUEUE");
+ unsetenv("EVENT_NOPOLL");
+ return (base);
+}
diff --git a/osdep-dragonfly.c b/osdep-dragonfly.c
new file mode 100644
index 00000000..879034e8
--- /dev/null
+++ b/osdep-dragonfly.c
@@ -0,0 +1,133 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct kinfo_proc *cmp_procs(struct kinfo_proc *, struct kinfo_proc *);
+char *osdep_get_name(int, char *);
+char *osdep_get_cwd(int);
+struct event_base *osdep_event_init(void);
+
+#ifndef nitems
+#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
+#define is_runnable(p) \
+ ((p)->kp_stat == SACTIVE || (p)->kp_stat == SIDL)
+#define is_stopped(p) \
+ ((p)->kp_stat == SSTOP || (p)->kp_stat == SZOMB)
+
+struct kinfo_proc *
+cmp_procs(struct kinfo_proc *p1, struct kinfo_proc *p2)
+{
+ if (is_runnable(p1) && !is_runnable(p2))
+ return (p1);
+ if (!is_runnable(p1) && is_runnable(p2))
+ return (p2);
+
+ if (is_stopped(p1) && !is_stopped(p2))
+ return (p1);
+ if (!is_stopped(p1) && is_stopped(p2))
+ return (p2);
+
+ if (strcmp(p1->kp_comm, p2->kp_comm) < 0)
+ return (p1);
+ if (strcmp(p1->kp_comm, p2->kp_comm) > 0)
+ return (p2);
+
+ if (p1->kp_pid > p2->kp_pid)
+ return (p1);
+ return (p2);
+}
+
+char *
+osdep_get_name(int fd, char *tty)
+{
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PGRP, 0 };
+ struct stat sb;
+ size_t len;
+ struct kinfo_proc *buf, *newbuf, *bestp;
+ u_int i;
+ char *name;
+
+ buf = NULL;
+
+ if (stat(tty, &sb) == -1)
+ return (NULL);
+ if ((mib[3] = tcgetpgrp(fd)) == -1)
+ return (NULL);
+
+retry:
+ if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) == -1)
+ return (NULL);
+ len = (len * 5) / 4;
+
+ if ((newbuf = realloc(buf, len)) == NULL)
+ goto error;
+ buf = newbuf;
+
+ if (sysctl(mib, nitems(mib), buf, &len, NULL, 0) == -1) {
+ if (errno == ENOMEM)
+ goto retry;
+ goto error;
+ }
+
+ bestp = NULL;
+ for (i = 0; i < len / sizeof (struct kinfo_proc); i++) {
+ if (buf[i].kp_tdev != sb.st_rdev)
+ continue;
+ if (bestp == NULL)
+ bestp = &buf[i];
+ else
+ bestp = cmp_procs(&buf[i], bestp);
+ }
+
+ name = NULL;
+ if (bestp != NULL)
+ name = strdup(bestp->kp_comm);
+
+ free(buf);
+ return (name);
+
+error:
+ free(buf);
+ return (NULL);
+}
+
+char *
+osdep_get_cwd(int fd)
+{
+ return (NULL);
+}
+
+struct event_base *
+osdep_event_init(void)
+{
+ return (event_init());
+}
diff --git a/osdep-freebsd.c b/osdep-freebsd.c
new file mode 100644
index 00000000..a7d02930
--- /dev/null
+++ b/osdep-freebsd.c
@@ -0,0 +1,209 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libutil.h>
+
+#include "compat.h"
+
+struct kinfo_proc *cmp_procs(struct kinfo_proc *, struct kinfo_proc *);
+char *osdep_get_name(int, char *);
+char *osdep_get_cwd(int);
+struct event_base *osdep_event_init(void);
+
+#ifndef nitems
+#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
+#define is_runnable(p) \
+ ((p)->ki_stat == SRUN || (p)->ki_stat == SIDL)
+#define is_stopped(p) \
+ ((p)->ki_stat == SSTOP || (p)->ki_stat == SZOMB)
+
+struct kinfo_proc *
+cmp_procs(struct kinfo_proc *p1, struct kinfo_proc *p2)
+{
+ if (is_runnable(p1) && !is_runnable(p2))
+ return (p1);
+ if (!is_runnable(p1) && is_runnable(p2))
+ return (p2);
+
+ if (is_stopped(p1) && !is_stopped(p2))
+ return (p1);
+ if (!is_stopped(p1) && is_stopped(p2))
+ return (p2);
+
+ if (p1->ki_estcpu > p2->ki_estcpu)
+ return (p1);
+ if (p1->ki_estcpu < p2->ki_estcpu)
+ return (p2);
+
+ if (p1->ki_slptime < p2->ki_slptime)
+ return (p1);
+ if (p1->ki_slptime > p2->ki_slptime)
+ return (p2);
+
+ if (strcmp(p1->ki_comm, p2->ki_comm) < 0)
+ return (p1);
+ if (strcmp(p1->ki_comm, p2->ki_comm) > 0)
+ return (p2);
+
+ if (p1->ki_pid > p2->ki_pid)
+ return (p1);
+ return (p2);
+}
+
+char *
+osdep_get_name(int fd, char *tty)
+{
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PGRP, 0 };
+ struct stat sb;
+ size_t len;
+ struct kinfo_proc *buf, *newbuf, *bestp;
+ u_int i;
+ char *name;
+
+ buf = NULL;
+
+ if (stat(tty, &sb) == -1)
+ return (NULL);
+ if ((mib[3] = tcgetpgrp(fd)) == -1)
+ return (NULL);
+
+retry:
+ if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) == -1)
+ return (NULL);
+ len = (len * 5) / 4;
+
+ if ((newbuf = realloc(buf, len)) == NULL)
+ goto error;
+ buf = newbuf;
+
+ if (sysctl(mib, nitems(mib), buf, &len, NULL, 0) == -1) {
+ if (errno == ENOMEM)
+ goto retry;
+ goto error;
+ }
+
+ bestp = NULL;
+ for (i = 0; i < len / sizeof (struct kinfo_proc); i++) {
+ if (buf[i].ki_tdev != sb.st_rdev)
+ continue;
+ if (bestp == NULL)
+ bestp = &buf[i];
+ else
+ bestp = cmp_procs(&buf[i], bestp);
+ }
+
+ name = NULL;
+ if (bestp != NULL)
+ name = strdup(bestp->ki_comm);
+
+ free(buf);
+ return (name);
+
+error:
+ free(buf);
+ return (NULL);
+}
+
+static char *
+osdep_get_cwd_fallback(int fd)
+{
+ static char wd[PATH_MAX];
+ struct kinfo_file *info = NULL;
+ pid_t pgrp;
+ int nrecords, i;
+
+ if ((pgrp = tcgetpgrp(fd)) == -1)
+ return (NULL);
+
+ if ((info = kinfo_getfile(pgrp, &nrecords)) == NULL)
+ return (NULL);
+
+ for (i = 0; i < nrecords; i++) {
+ if (info[i].kf_fd == KF_FD_TYPE_CWD) {
+ strlcpy(wd, info[i].kf_path, sizeof wd);
+ free(info);
+ return (wd);
+ }
+ }
+
+ free(info);
+ return (NULL);
+}
+
+#ifdef KERN_PROC_CWD
+char *
+osdep_get_cwd(int fd)
+{
+ static struct kinfo_file info;
+ static int fallback;
+ int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_CWD, 0 };
+ size_t len = sizeof info;
+
+ if (fallback)
+ return (osdep_get_cwd_fallback(fd));
+
+ if ((name[3] = tcgetpgrp(fd)) == -1)
+ return (NULL);
+
+ if (sysctl(name, 4, &info, &len, NULL, 0) == -1) {
+ if (errno == ENOENT) {
+ fallback = 1;
+ return (osdep_get_cwd_fallback(fd));
+ }
+ return (NULL);
+ }
+ return (info.kf_path);
+}
+#else /* !KERN_PROC_CWD */
+char *
+osdep_get_cwd(int fd)
+{
+ return (osdep_get_cwd_fallback(fd));
+}
+#endif /* KERN_PROC_CWD */
+
+struct event_base *
+osdep_event_init(void)
+{
+ struct event_base *base;
+
+ /*
+ * On some versions of FreeBSD, kqueue doesn't work properly on tty
+ * file descriptors. This is fixed in recent FreeBSD versions.
+ */
+ setenv("EVENT_NOKQUEUE", "1", 1);
+
+ base = event_init();
+ unsetenv("EVENT_NOKQUEUE");
+ return (base);
+}
diff --git a/cmd-has-session.c b/osdep-hpux.c
index a873b204..16993b93 100644
--- a/cmd-has-session.c
+++ b/osdep-hpux.c
@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/*
- * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
+ * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,29 +18,24 @@
#include <sys/types.h>
-#include "tmux.h"
-
-/*
- * Cause client to report an error and exit with 1 if session doesn't exist.
- */
-
-enum cmd_retval cmd_has_session_exec(struct cmd *, struct cmd_q *);
+#include <event.h>
-const struct cmd_entry cmd_has_session_entry = {
- "has-session", "has",
- "t:", 0, 0,
- CMD_TARGET_SESSION_USAGE,
- 0,
- cmd_has_session_exec
-};
+#include "tmux.h"
-enum cmd_retval
-cmd_has_session_exec(struct cmd *self, struct cmd_q *cmdq)
+char *
+osdep_get_name(__unused int fd, __unused char *tty)
{
- struct args *args = self->args;
+ return (NULL);
+}
- if (cmd_find_session(cmdq, args_get(args, 't'), 0) == NULL)
- return (CMD_RETURN_ERROR);
+char *
+osdep_get_cwd(__unused int fd)
+{
+ return (NULL);
+}
- return (CMD_RETURN_NORMAL);
+struct event_base *
+osdep_event_init(void)
+{
+ return (event_init());
}
diff --git a/osdep-linux.c b/osdep-linux.c
new file mode 100644
index 00000000..5f0d9352
--- /dev/null
+++ b/osdep-linux.c
@@ -0,0 +1,103 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <event.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "tmux.h"
+
+char *
+osdep_get_name(int fd, __unused char *tty)
+{
+ FILE *f;
+ char *path, *buf;
+ size_t len;
+ int ch;
+ pid_t pgrp;
+
+ if ((pgrp = tcgetpgrp(fd)) == -1)
+ return (NULL);
+
+ xasprintf(&path, "/proc/%lld/cmdline", (long long) pgrp);
+ if ((f = fopen(path, "r")) == NULL) {
+ free(path);
+ return (NULL);
+ }
+ free(path);
+
+ len = 0;
+ buf = NULL;
+ while ((ch = fgetc(f)) != EOF) {
+ if (ch == '\0')
+ break;
+ buf = xrealloc(buf, len + 2);
+ buf[len++] = ch;
+ }
+ if (buf != NULL)
+ buf[len] = '\0';
+
+ fclose(f);
+ return (buf);
+}
+
+char *
+osdep_get_cwd(int fd)
+{
+ static char target[MAXPATHLEN + 1];
+ char *path;
+ pid_t pgrp, sid;
+ ssize_t n;
+
+ if ((pgrp = tcgetpgrp(fd)) == -1)
+ return (NULL);
+
+ xasprintf(&path, "/proc/%lld/cwd", (long long) pgrp);
+ n = readlink(path, target, MAXPATHLEN);
+ free(path);
+
+ if (n == -1 && ioctl(fd, TIOCGSID, &sid) != -1) {
+ xasprintf(&path, "/proc/%lld/cwd", (long long) sid);
+ n = readlink(path, target, MAXPATHLEN);
+ free(path);
+ }
+
+ if (n > 0) {
+ target[n] = '\0';
+ return (target);
+ }
+ return (NULL);
+}
+
+struct event_base *
+osdep_event_init(void)
+{
+ struct event_base *base;
+
+ /* On Linux, epoll doesn't work on /dev/null (yes, really). */
+ setenv("EVENT_NOEPOLL", "1", 1);
+
+ base = event_init();
+ unsetenv("EVENT_NOEPOLL");
+ return (base);
+}
diff --git a/osdep-netbsd.c b/osdep-netbsd.c
new file mode 100644
index 00000000..67894175
--- /dev/null
+++ b/osdep-netbsd.c
@@ -0,0 +1,173 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+
+#include <errno.h>
+#include <event.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "tmux.h"
+
+#define is_runnable(p) \
+ ((p)->p_stat == LSRUN || (p)->p_stat == SIDL)
+#define is_stopped(p) \
+ ((p)->p_stat == SSTOP || (p)->p_stat == SZOMB)
+
+struct kinfo_proc2 *cmp_procs(struct kinfo_proc2 *, struct kinfo_proc2 *);
+char *osdep_get_name(int, char *);
+char *osdep_get_cwd(int);
+struct event_base *osdep_event_init(void);
+
+struct kinfo_proc2 *
+cmp_procs(struct kinfo_proc2 *p1, struct kinfo_proc2 *p2)
+{
+ if (is_runnable(p1) && !is_runnable(p2))
+ return (p1);
+ if (!is_runnable(p1) && is_runnable(p2))
+ return (p2);
+
+ if (is_stopped(p1) && !is_stopped(p2))
+ return (p1);
+ if (!is_stopped(p1) && is_stopped(p2))
+ return (p2);
+
+ if (p1->p_estcpu > p2->p_estcpu)
+ return (p1);
+ if (p1->p_estcpu < p2->p_estcpu)
+ return (p2);
+
+ if (p1->p_slptime < p2->p_slptime)
+ return (p1);
+ if (p1->p_slptime > p2->p_slptime)
+ return (p2);
+
+ if (p1->p_pid > p2->p_pid)
+ return (p1);
+ return (p2);
+}
+
+char *
+osdep_get_name(int fd, __unused char *tty)
+{
+ int mib[6];
+ struct stat sb;
+ size_t len, i;
+ struct kinfo_proc2 *buf, *newbuf, *bestp;
+ char *name;
+
+ if (stat(tty, &sb) == -1)
+ return (NULL);
+ if ((mib[3] = tcgetpgrp(fd)) == -1)
+ return (NULL);
+
+ buf = NULL;
+ len = sizeof bestp;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC2;
+ mib[2] = KERN_PROC_PGRP;
+ mib[4] = sizeof *buf;
+
+retry:
+ mib[5] = 0;
+
+ if (sysctl(mib, __arraycount(mib), NULL, &len, NULL, 0) == -1)
+ return (NULL);
+
+ if ((newbuf = realloc(buf, len)) == NULL)
+ goto error;
+ buf = newbuf;
+
+ mib[5] = len / (sizeof *buf);
+ if (sysctl(mib, __arraycount(mib), buf, &len, NULL, 0) == -1) {
+ if (errno == ENOMEM)
+ goto retry;
+ goto error;
+ }
+
+ bestp = NULL;
+ for (i = 0; i < len / (sizeof *buf); i++) {
+ if (buf[i].p_tdev != sb.st_rdev)
+ continue;
+ if (bestp == NULL)
+ bestp = &buf[i];
+ else
+ bestp = cmp_procs(&buf[i], bestp);
+ }
+
+ name = NULL;
+ if (bestp != NULL)
+ name = strdup(bestp->p_comm);
+
+ free(buf);
+ return (name);
+
+error:
+ free(buf);
+ return (NULL);
+}
+
+char *
+osdep_get_cwd(int fd)
+{
+ static char target[PATH_MAX + 1];
+ pid_t pgrp;
+#ifdef KERN_PROC_CWD
+ int mib[4];
+ size_t len;
+#else
+ char *path;
+ ssize_t n;
+#endif
+
+ if ((pgrp = tcgetpgrp(fd)) == -1)
+ return (NULL);
+
+#ifdef KERN_PROC_CWD
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC_ARGS;
+ mib[2] = pgrp;
+ mib[3] = KERN_PROC_CWD;
+ len = sizeof(target);
+ if (sysctl(mib, __arraycount(mib), target, &len, NULL, 0) == 0)
+ return (target);
+#else
+ xasprintf(&path, "/proc/%lld/cwd", (long long) pgrp);
+ n = readlink(path, target, sizeof(target) - 1);
+ free(path);
+ if (n > 0) {
+ target[n] = '\0';
+ return (target);
+ }
+#endif
+
+ return (NULL);
+}
+
+struct event_base *
+osdep_event_init(void)
+{
+ return (event_init());
+}
diff --git a/procname.c b/osdep-openbsd.c
index 07a8a56c..b21a6628 100644
--- a/procname.c
+++ b/osdep-openbsd.c
@@ -23,6 +23,7 @@
#include <sys/stat.h>
#include <errno.h>
+#include <event.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -37,7 +38,9 @@
((p)->p_stat == SSTOP || (p)->p_stat == SDEAD)
static struct kinfo_proc *cmp_procs(struct kinfo_proc *, struct kinfo_proc *);
-char *get_proc_name(int, char *);
+char *osdep_get_name(int, char *);
+char *osdep_get_cwd(int);
+struct event_base *osdep_event_init(void);
static struct kinfo_proc *
cmp_procs(struct kinfo_proc *p1, struct kinfo_proc *p2)
@@ -78,7 +81,7 @@ cmp_procs(struct kinfo_proc *p1, struct kinfo_proc *p2)
}
char *
-get_proc_name(int fd, char *tty)
+osdep_get_name(int fd, char *tty)
{
int mib[6] = { CTL_KERN, KERN_PROC, KERN_PROC_PGRP, 0,
sizeof(struct kinfo_proc), 0 };
@@ -132,3 +135,23 @@ error:
free(buf);
return (NULL);
}
+
+char *
+osdep_get_cwd(int fd)
+{
+ int name[] = { CTL_KERN, KERN_PROC_CWD, 0 };
+ static char path[MAXPATHLEN];
+ size_t pathlen = sizeof path;
+
+ if ((name[2] = tcgetpgrp(fd)) == -1)
+ return (NULL);
+ if (sysctl(name, 3, path, &pathlen, NULL, 0) != 0)
+ return (NULL);
+ return (path);
+}
+
+struct event_base *
+osdep_event_init(void)
+{
+ return (event_init());
+}
diff --git a/osdep-sunos.c b/osdep-sunos.c
new file mode 100644
index 00000000..07043a9b
--- /dev/null
+++ b/osdep-sunos.c
@@ -0,0 +1,101 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2009 Todd Carson <toc@daybefore.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <event.h>
+#include <fcntl.h>
+#include <procfs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "tmux.h"
+
+char *
+osdep_get_name(__unused int fd, char *tty)
+{
+ struct psinfo p;
+ struct stat st;
+ char *path;
+ ssize_t bytes;
+ int f;
+ pid_t pgrp;
+
+ if ((f = open(tty, O_RDONLY)) < 0)
+ return (NULL);
+
+ if (fstat(f, &st) != 0 || ioctl(f, TIOCGPGRP, &pgrp) != 0) {
+ close(f);
+ return (NULL);
+ }
+ close(f);
+
+ xasprintf(&path, "/proc/%u/psinfo", (u_int) pgrp);
+ f = open(path, O_RDONLY);
+ free(path);
+ if (f < 0)
+ return (NULL);
+
+ bytes = read(f, &p, sizeof(p));
+ close(f);
+ if (bytes != sizeof(p))
+ return (NULL);
+
+ if (p.pr_ttydev != st.st_rdev)
+ return (NULL);
+
+ return (xstrdup(p.pr_fname));
+}
+
+char *
+osdep_get_cwd(int fd)
+{
+ static char target[MAXPATHLEN + 1];
+ char *path;
+ const char *ttypath;
+ ssize_t n;
+ pid_t pgrp;
+ int retval, ttyfd;
+
+ if ((ttypath = ptsname(fd)) == NULL)
+ return (NULL);
+ if ((ttyfd = open(ttypath, O_RDONLY|O_NOCTTY)) == -1)
+ return (NULL);
+
+ retval = ioctl(ttyfd, TIOCGPGRP, &pgrp);
+ close(ttyfd);
+ if (retval == -1)
+ return (NULL);
+
+ xasprintf(&path, "/proc/%u/path/cwd", (u_int) pgrp);
+ n = readlink(path, target, MAXPATHLEN);
+ free(path);
+ if (n > 0) {
+ target[n] = '\0';
+ return (target);
+ }
+ return (NULL);
+}
+
+struct event_base *
+osdep_event_init(void)
+{
+ return (event_init());
+}
diff --git a/cmd-send-prefix.c b/osdep-unknown.c
index 04556507..bc59f569 100644
--- a/cmd-send-prefix.c
+++ b/osdep-unknown.c
@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/*
- * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
+ * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,40 +18,24 @@
#include <sys/types.h>
-#include "tmux.h"
-
-/*
- * Send prefix key as a key.
- */
-
-enum cmd_retval cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *);
+#include <event.h>
-const struct cmd_entry cmd_send_prefix_entry = {
- "send-prefix", NULL,
- "2t:", 0, 0,
- "[-2] " CMD_TARGET_PANE_USAGE,
- 0,
- NULL,
- NULL,
- cmd_send_prefix_exec
-};
+#include "tmux.h"
-enum cmd_retval
-cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx)
+char *
+osdep_get_name(__unused int fd, __unused char *tty)
{
- struct args *args = self->args;
- struct session *s;
- struct window_pane *wp;
- int key;
-
- if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
- return (CMD_RETURN_ERROR);
+ return (NULL);
+}
- if (args_has(args, '2'))
- key = options_get_number(&s->options, "prefix2");
- else
- key = options_get_number(&s->options, "prefix");
- window_pane_key(wp, s, key);
+char *
+osdep_get_cwd(int fd)
+{
+ return (NULL);
+}
- return (CMD_RETURN_NORMAL);
+struct event_base *
+osdep_event_init(void)
+{
+ return (event_init());
}
diff --git a/paste.c b/paste.c
index 0c9bc7b5..c1036ad9 100644
--- a/paste.c
+++ b/paste.c
@@ -21,7 +21,6 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include <vis.h>
#include "tmux.h"
diff --git a/presentations/tmux_asiabsdcon11.odt b/presentations/tmux_asiabsdcon11.odt
new file mode 100644
index 00000000..ac9f0934
--- /dev/null
+++ b/presentations/tmux_asiabsdcon11.odt
Binary files differ
diff --git a/presentations/tmux_asiabsdcon11.pdf b/presentations/tmux_asiabsdcon11.pdf
new file mode 100644
index 00000000..76cd9b25
--- /dev/null
+++ b/presentations/tmux_asiabsdcon11.pdf
Binary files differ
diff --git a/presentations/tmux_linuxtag_2011.odp b/presentations/tmux_linuxtag_2011.odp
new file mode 100644
index 00000000..0b6c9cf1
--- /dev/null
+++ b/presentations/tmux_linuxtag_2011.odp
Binary files differ
diff --git a/proc.c b/proc.c
index 48e0d90c..b10d4850 100644
--- a/proc.c
+++ b/proc.c
@@ -17,13 +17,11 @@
*/
#include <sys/types.h>
-#include <sys/queue.h>
#include <sys/uio.h>
#include <sys/utsname.h>
#include <errno.h>
#include <event.h>
-#include <imsg.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
@@ -182,8 +180,8 @@ proc_start(const char *name)
if (uname(&u) < 0)
memset(&u, 0, sizeof u);
- log_debug("%s started (%ld): socket %s, protocol %d", name,
- (long)getpid(), socket_path, PROTOCOL_VERSION);
+ log_debug("%s started (%ld): version %s, socket %s, protocol %d", name,
+ (long)getpid(), VERSION, socket_path, PROTOCOL_VERSION);
log_debug("on %s %s %s; libevent %s (%s)", u.sysname, u.release,
u.version, event_get_version(), event_get_method());
diff --git a/regress/Makefile b/regress/Makefile
new file mode 100644
index 00000000..e6c3619f
--- /dev/null
+++ b/regress/Makefile
@@ -0,0 +1,10 @@
+TESTS!= echo *.sh
+
+.PHONY: all $(TESTS)
+.NOTPARALLEL: all $(TESTS)
+
+all: $(TESTS)
+
+$(TESTS):
+ sh $*.sh
+ sleep 1
diff --git a/regress/capture-pane-sgr0.sh b/regress/capture-pane-sgr0.sh
new file mode 100644
index 00000000..79d96a38
--- /dev/null
+++ b/regress/capture-pane-sgr0.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# 884
+# capture-pane should send colours after SGR 0
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+$TMUX -f/dev/null new -d \
+ "printf '\033[31;42;1mabc\033[0;31mdef'; $TMUX capturep -peS0 -E0 >$TMP"
+sleep 1
+printf '\033[1m\033[31m\033[42mabc\033[0m\033[31m\033[49mdef\033[39m\n'| \
+ cmp - $TMP || exit 1
+
+$TMUX has 2>/dev/null && exit 1
+
+exit 0
diff --git a/regress/command-order.sh b/regress/command-order.sh
new file mode 100644
index 00000000..04046f0d
--- /dev/null
+++ b/regress/command-order.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+cat <<EOF >$TMP
+new -sfoo -nfoo0; neww -nfoo1; neww -nfoo2
+new -sbar -nbar0; neww -nbar1; neww -nbar2
+EOF
+$TMUX -f$TMP start </dev/null || exit 1
+sleep 1
+$TMUX lsw -aF '#{session_name},#{window_name}'|sort >$TMP || exit 1
+$TMUX kill-server 2>/dev/null
+cat <<EOF|cmp -s $TMP - || exit 1
+bar,bar0
+bar,bar1
+bar,bar2
+foo,foo0
+foo,foo1
+foo,foo2
+EOF
+
+cat <<EOF >$TMP
+new -sfoo -nfoo0
+neww -nfoo1
+neww -nfoo2
+new -sbar -nbar0
+neww -nbar1
+neww -nbar2
+EOF
+$TMUX -f$TMP start </dev/null || exit 1
+sleep 1
+$TMUX lsw -aF '#{session_name},#{window_name}'|sort >$TMP || exit 1
+$TMUX kill-server 2>/dev/null
+cat <<EOF|cmp -s $TMP - || exit 1
+bar,bar0
+bar,bar1
+bar,bar2
+foo,foo0
+foo,foo1
+foo,foo2
+EOF
+
+exit 0
diff --git a/regress/conf-syntax.sh b/regress/conf-syntax.sh
new file mode 100644
index 00000000..96d35140
--- /dev/null
+++ b/regress/conf-syntax.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+for i in conf/*.conf; do
+ $TMUX -f/dev/null start \; source -n $i || exit 1
+done
+
+exit 0
diff --git a/regress/conf/21867280ff7e99631046f9cc669b80d2.conf b/regress/conf/21867280ff7e99631046f9cc669b80d2.conf
new file mode 100644
index 00000000..43b142b4
--- /dev/null
+++ b/regress/conf/21867280ff7e99631046f9cc669b80d2.conf
@@ -0,0 +1,8 @@
+%if #{l:1}
+set -g status-style fg=cyan,bg='#001040'
+%elif #{l:1}
+set -g status-style fg=white,bg='#400040'
+%else
+set -g status-style fg=white,bg='#800000'
+%endif
+bind ^X last-window
diff --git a/regress/conf/29813ff35544434e2e64dc879a8dd274.conf b/regress/conf/29813ff35544434e2e64dc879a8dd274.conf
new file mode 100644
index 00000000..d0bda4a2
--- /dev/null
+++ b/regress/conf/29813ff35544434e2e64dc879a8dd274.conf
@@ -0,0 +1,58 @@
+set -g prefix C-g
+# needed for e.g. mutt
+bind C-g send-prefix
+
+set -g set-titles on
+set -g status-position top
+set -g status-keys vi
+set -g mode-keys vi
+set -g base-index 1
+set -g pane-base-index 1
+set -g focus-events on
+
+set history-file ~/.tmux_SSH_history
+set focus-events on
+set -g history-limit 100000
+set -s set-clipboard on
+set -g display-time 3000
+set -g display-panes-time 3000
+
+set -g pane-border-status top
+
+setw -g window-status-current-style bg=colour240,fg=colour250
+setw -g window-status-separator "|"
+set -g status-bg colour235
+set -g status-fg colour245
+
+set -g window-status-format " #I #{=+15:pane_title} #{=-2:?window_flags, #{window_flags}, }"
+set -g window-status-current-format " #I #{=+15:pane_title} #{=-2:?window_flags, #{window_flags}, }"
+set -g pane-border-format " #P: #{s/ //:pane_title} "
+
+set -g renumber-windows on
+set -g status-right-length 0
+##############################################################
+
+# I prefer not to have a status for my tabbed term
+set -g status-right ""
+set -g status-right-length 0
+set -g status-left-length 0
+set -g status-left ""
+
+# some settings for "navigation"
+bind -n C-PageUp copy-mode -u
+unbind -n C-Left
+unbind -n C-Right
+bind -n C-Left select-window -t :-
+bind -n C-Right select-window -t :+
+
+# I prefer a tiled layout and easy joining of current active pane via windows'
+# index
+bind F1 join-pane -s 1.\; select-layout tiled
+bind F2 join-pane -s 2.\; select-layout tiled
+bind F3 join-pane -s 3.\; select-layout tiled
+bind F4 join-pane -s 4.\; select-layout tiled
+bind F5 join-pane -s 5.\; select-layout tiled
+bind F6 join-pane -s 6.\; select-layout tiled
+bind F7 join-pane -s 7.\; select-layout tiled
+bind F8 join-pane -s 8.\; select-layout tiled
+bind F9 join-pane -s 9.\; select-layout tiled
diff --git a/regress/conf/2eae5d47049c1f6d0bef3db4e171aed7.conf b/regress/conf/2eae5d47049c1f6d0bef3db4e171aed7.conf
new file mode 100644
index 00000000..c09adc24
--- /dev/null
+++ b/regress/conf/2eae5d47049c1f6d0bef3db4e171aed7.conf
@@ -0,0 +1,56 @@
+# 256 colors for vim
+set -g default-terminal "screen-256color"
+
+# Set default shell to zsh
+set-option -g default-shell /bin/zsh
+
+# Start window numbering at 1
+set-option -g base-index 1
+set-window-option -g pane-base-index 1
+
+# Cycle panes with C-b C-b
+unbind ^B
+bind ^B select-pane -t :.+
+
+# Reload config wtih a key
+bind-key r source-file ~/.tmux.conf \; display "Config reloaded!"
+
+# Mouse works as expected
+# set -g mode-mouse on
+# set -g mouse-select-pane on
+# set -g mouse-resize-pane on
+# set -g mouse-select-window on
+
+# Scrolling works as expected
+set -g terminal-overrides 'xterm*:smcup@:rmcup@'
+
+# Use the system clipboard
+# set-option -g default-command "reattach-to-user-namespace -l zsh"
+
+# Clear the pane and its history
+bind -n C-k send-keys C-l \; clear-history
+
+# smart pane switching with awareness of vim splits
+bind -n C-h run "(tmux display-message -p '#{pane_current_command}' | grep -iq vim && tmux send-keys C-h) || tmux select-pane -L"
+bind -n C-j run "(tmux display-message -p '#{pane_current_command}' | grep -iq vim && tmux send-keys C-j) || tmux select-pane -D"
+bind -n C-k run "(tmux display-message -p '#{pane_current_command}' | grep -iq vim && tmux send-keys C-k) || tmux select-pane -U"
+bind -n C-l run "(tmux display-message -p '#{pane_current_command}' | grep -iq vim && tmux send-keys C-l) || tmux select-pane -R"
+bind -n C-\ run "(tmux display-message -p '#{pane_current_command}' | grep -iq vim && tmux send-keys 'C-\\') || tmux select-pane -l"
+
+# C-l is taken oer by vim style pane navigation
+bind C-l send-keys 'C-l'
+
+# Use vim keybindings in copy mode
+setw -g mode-keys vi
+
+# Setup 'v' to begin selection as in Vim
+# bind-key -t vi-copy v begin-selection
+# bind-key -t vi-copy y copy-pipe "reattach-to-user-namespace pbcopy"
+
+# Update default binding of `Enter` to also use copy-pipe
+# unbind -t vi-copy Enter
+# bind-key -t vi-copy Enter copy-pipe "reattach-to-user-namespace pbcopy"
+
+# Powerline
+run-shell "powerline-daemon -q"
+source "/Users/adamcooper/Library/Python/3.7/lib/python/site-packages/powerline/bindings/tmux/powerline.conf" \ No newline at end of file
diff --git a/regress/conf/327af72ad372255817b585a74da06eda.conf b/regress/conf/327af72ad372255817b585a74da06eda.conf
new file mode 100644
index 00000000..2a719c8b
--- /dev/null
+++ b/regress/conf/327af72ad372255817b585a74da06eda.conf
@@ -0,0 +1,30 @@
+set -sg escape-time 10
+
+set -g default-terminal tmux-256color
+set -g prefix ^X
+set -g history-limit 10000
+setw -g mode-keys vi
+setw -g xterm-keys off
+
+# black, red, green, yellow, blue, magenta, cyan, white, default.
+setw -g message-command-style fg=yellow,bg=black
+setw -g message-style fg=black,bg=yellow
+
+%if #{m:*mydomain*,#{host}}
+set -g status-style fg=cyan,bg='#001040'
+setw -g window-status-current-style fg='#f0f0f0',bg='#001040'
+%elif #{||:#{m:*somedomain*,#{host}},#{m:*otherdomain*,#{host}}}
+set -g status-style fg=white,bg='#400040'
+setw -g window-status-current-style fg=yellow,bg='#400040',bright
+%else
+set -g status-style fg=white,bg='#800000'
+setw -g window-status-current-style fg=brightwhite,bg='#800000'
+%endif
+
+unbind ^B
+bind ^X last-window
+bind x send-prefix
+bind ^C new-window
+bind ^D detach-client
+bind ^N next-window
+bind ^P previous-window
diff --git a/regress/conf/58304907c117cab9898ea0b070bccde3.conf b/regress/conf/58304907c117cab9898ea0b070bccde3.conf
new file mode 100644
index 00000000..c9ce3fa4
--- /dev/null
+++ b/regress/conf/58304907c117cab9898ea0b070bccde3.conf
@@ -0,0 +1,118 @@
+#
+# Tureba's tmux.conf
+#
+# To use it, either:
+# a) link ~/.tmux.conf to it; or
+# b) create a ~/.tmux.conf that sources it.
+#
+# who: Arthur Nascimento <tureba@gmail.com>
+# where: github.com/tureba/myconfigfiles
+#
+
+# defaults
+set -g default-shell /bin/zsh
+set -g default-command zsh
+# tmux sets screen/screen-256, but has no codes for italics
+set -g default-terminal tmux-256color
+# linux terminal doesn't need this, but xterm does
+set -g terminal-overrides 'xterm*:smcup@:rmcup@,*256col*:colors=256,xterm*:XT'
+# xterm-style function key sequences
+setw -g xterm-keys on
+
+# 1, 2 and 3 are closer together than 0, 1 and 2
+set -g base-index 1
+set -g pane-base-index 1
+
+# easier to type than C-b
+set -g prefix C-a
+set -g prefix2 C-b
+unbind C-b
+bind C-a send-prefix
+
+# for repeatable keys
+set -g repeat-time 170
+
+# status bar
+set -g status-style fg=green,bg=colour234
+set -g status-right-style bg=colour236
+set -g status-right "#[bold,fg=blue][#[fg=default]#T#[fg=blue]]#[nobold,fg=default] | #[fg=yellow]%F %R"
+set -g status-right-length 120
+set -g status-left-style bg=colour236,bright
+set -g status-left "#[fg=blue][#[fg=default]#h#[fg=cyan]:#[fg=default]#S#[fg=blue]]"
+set -g status-left-length 30
+setw -g window-status-style fg=green
+setw -g window-status-format " #I#[nobold]:#W "
+setw -g window-status-current-style fg=green,bright
+setw -g window-status-current-format "#[fg=red][#[fg=default]#I:#W#[fg=red]]"
+setw -g window-status-separator "|"
+setw -g window-status-activity-style blink
+setw -g window-status-bell-style blink
+setw -g window-status-last-style bright
+
+# enable wm window titles
+set -g set-titles on
+
+# auto window rename
+setw -g automatic-rename on
+# auto window resize
+setw -g aggressive-resize on
+
+# mouse settings
+set -g mouse on
+
+# var|bind \ cmd | vim | less | copy | zsh
+# pane_in_mode | 0 | 0 | 1 | 0
+# mouse_any_flag | 1 | 0 | 0 | 0
+# alternate_on | 1 | 1 | 0 | 0
+# WheelUpPane | send -M | send Up | * | send Up (** or copy-mode -e)
+# WheelDownPane | send -M | send Down | * | send Down
+# * panes in copy mode have scroll handled by different bindings
+
+# ** cycle over shell history
+#bind -T root WheelUpPane if -Ft= '#{mouse_any_flag}' 'send -Mt=' 'send -t= Up'
+
+# ** enter copy mode
+bind -T root WheelUpPane if -Ft= '#{mouse_any_flag}' 'send -Mt=' 'if -Ft= "#{alternate_on}" "send -t= Up" "copy-mode -et="'
+
+bind -T root WheelDownPane if -Ft= '#{mouse_any_flag}' 'send -Mt=' 'send -t= Down'
+
+# sensible v/h splits
+unbind %
+unbind '"'
+bind | split-window -h
+bind - split-window -v
+
+# hjkl pane traversal
+bind -r h select-pane -L
+bind -r j select-pane -D
+bind -r k select-pane -U
+bind -r l select-pane -R
+
+# window navigation
+unbind p
+bind -r [ previous-window
+unbind n
+bind -r ] next-window
+
+# Vi copypaste mode
+setw -g mode-keys vi
+bind C-c copy-mode
+bind p paste-buffer
+bind -T copy-mode-vi v send-keys -X begin-selection
+bind -T copy-mode-vi y send-keys -X copy-selection
+bind -T copy-mode-vi V send-keys -X rectangle-toggle
+
+# toggle window activity monitoring
+bind m setw monitor-activity
+
+# reload the configuration
+bind r source-file ~/.tmux.conf
+
+# toggle synchronize-panes
+bind S setw synchronize-panes
+
+# create a new window with exactly this command
+bind C command-prompt "new-window 'exec %%'"
+
+# (toggle) mark this pane for easier joins and swaps
+bind . select-pane -m
diff --git a/regress/conf/91378fd400b0444eb8cac471e30642b3.conf b/regress/conf/91378fd400b0444eb8cac471e30642b3.conf
new file mode 100644
index 00000000..40810076
--- /dev/null
+++ b/regress/conf/91378fd400b0444eb8cac471e30642b3.conf
@@ -0,0 +1,30 @@
+###
+
+if-shell " \
+ tmux -V \
+ | awk '{print $2}' \
+ | awk -F - '{print $1}' \
+ | awk '{ \
+ if ($1 ~ /^[[:digit:].]+$/) { \
+ exit !($1 >= 2.6) \
+ } else { \
+ exit !($1 == \"master\" || $1 == \"next\") \
+ } \
+ }'" \
+ "source-file ~/.tmux/v2rc" \
+ "source-file ~/.tmux/v1rc" \
+ ;
+
+###
+
+set-option -qg status-left \
+ "[#[fg=yellow]#{session_name}#[default]] #[fg=colour060]#{host_short}#[default]:#[fg=colour151]#{b:pane_current_path} #[fg=colour099]#(git -C #{pane_current_path} symbolic-ref --short HEAD) #[fg=green]#(git -C #{pane_current_path} status --porcelain --untracked-files=no | cut -b 1-1 | sort | uniq | awk '/^[^[:space:]]/ {printf\(\"%%s\", $0\)}')#[fg=red]#(git -C #{pane_current_path} status --porcelain --untracked-files=no | cut -b 2-2 | sort | uniq | awk '/^[^[:space:]]/ {printf\(\"%%s\", $0\)}')#[fg=colour113]#(git -C #{pane_current_path} stash list 2>/dev/null | wc -l | tr -d '\n' | sed s,^0\$,,) #[default]"
+
+set-option -qg status-right \
+ "#[default] ┊ #[fg=colour065]#(grep ^MemFree /proc/meminfo | awk '{print rshift\($2, 10\)}')#[fg=colour071]m #[default]┊ #[fg=colour101]#(echo \"\(`awk '{print \$1}' /proc/loadavg` / `grep ^processor /proc/cpuinfo | wc -l`\) \* 100\" | bc -ql | sed 's,\\..*,,' | awk '{printf\(\"%%2u\", $0\)}')#[fg=colour102]%% "
+
+set-option -qwg window-status-current-format \
+ "#[fg=colour208]»#[fg=colour190]#{window_name}#[fg=colour037]·#{?window_flags,#[fg=colour058]#{window_flags}#[default], #[default]}"
+
+set-option -qwg window-status-format \
+ "#[default]»#[fg=colour066]#{window_name}#[fg=colour037]·#{?window_flags,#[fg=colour058]#{window_flags}#[default], #[default]}"
diff --git a/regress/conf/99749670b62bcb99a9b2e3d59708e357.conf b/regress/conf/99749670b62bcb99a9b2e3d59708e357.conf
new file mode 100644
index 00000000..dd1700b0
--- /dev/null
+++ b/regress/conf/99749670b62bcb99a9b2e3d59708e357.conf
@@ -0,0 +1,93 @@
+# -----------------------------------------------------------------------------
+# This config is targeted for tmux 2.1+ and should be placed in $HOME.
+#
+# Read the "Plugin Manager" section (bottom) before trying to use this config!
+# -----------------------------------------------------------------------------
+
+# -----------------------------------------------------------------------------
+# Global options
+# -----------------------------------------------------------------------------
+
+# Set a new prefix / leader key.
+set -g prefix `
+bind ` send-prefix
+
+# Allow opening multiple terminals to view the same session at different sizes.
+setw -g aggressive-resize on
+
+# Remove delay when switching between Vim modes.
+set -s escape-time 0
+
+# Allow Vim's FocusGained to work when your terminal gains focus.
+# Requires Vim plugin: https://github.com/tmux-plugins/vim-tmux-focus-events
+set -g focus-events on
+
+# Add a bit more scroll history in the buffer.
+set -g history-limit 50000
+
+# Enable color support inside of tmux.
+set -g default-terminal "screen-256color"
+
+# Ensure window titles get renamed automatically.
+setw -g automatic-rename
+
+# Start windows and panes index at 1, not 0.
+set -g base-index 1
+setw -g pane-base-index 1
+
+# Enable full mouse support.
+set -g mouse on
+
+# Status bar optimized for Gruvbox.
+set -g status-fg colour244
+set -g status-bg default
+set -g status-left ''
+set -g status-right-length 0
+#set -g status-right-length 20
+#set -g status-right '%a %Y-%m-%d %H:%M'
+
+set -g pane-border-fg default
+set -g pane-border-bg default
+set -g pane-active-border-fg colour250
+set -g pane-active-border-bg default
+
+set-window-option -g window-status-current-attr bold
+set-window-option -g window-status-current-fg colour223
+
+# -----------------------------------------------------------------------------
+# Key bindings
+# -----------------------------------------------------------------------------
+
+# Unbind default keys
+unbind C-b
+unbind '"'
+unbind %
+
+# Reload the tmux config.
+bind-key r source-file ~/.tmux.conf
+
+# Split panes.
+bind-key h split-window -v
+bind-key v split-window -h
+
+# Move around panes with ALT + arrow keys.
+bind-key -n M-Up select-pane -U
+bind-key -n M-Left select-pane -L
+bind-key -n M-Down select-pane -D
+bind-key -n M-Right select-pane -R
+
+# -----------------------------------------------------------------------------
+# Plugin Manager - https://github.com/tmux-plugins/tpm
+# In order to use the plugins below you need to install TPM and the plugins.
+# Step 1) git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
+# Step 2) Reload tmux if it's already started with `r
+# Step 3) Launch tmux and hit `I (capital i) to fetch any plugins
+# -----------------------------------------------------------------------------
+
+# List of plugins.
+set -g @plugin 'tmux-plugins/tpm'
+set -g @plugin 'tmux-plugins/tmux-resurrect'
+set -g @plugin 'tmux-plugins/tmux-yank'
+
+# Initialize TPM (keep this line at the very bottom of your tmux.conf).
+run -b '~/.tmux/plugins/tpm/tpm'
diff --git a/regress/conf/a46e6e84cd1071105aa807256dbc158d.conf b/regress/conf/a46e6e84cd1071105aa807256dbc158d.conf
new file mode 100644
index 00000000..bfbb2d3e
--- /dev/null
+++ b/regress/conf/a46e6e84cd1071105aa807256dbc158d.conf
@@ -0,0 +1,432 @@
+# Dynamic configuration file generated by ~/Makefile from /home/sunny/.tmux.conf.erb
+#
+# DO NOT EDIT THIS FILE BY HAND --
+# YOUR CHANGES WILL BE OVERWRITTEN
+#
+
+
+
+bind-key R source ~/.tmux.conf \; display-message 'config reloaded!'
+
+#-----------------------------------------------------------------------------
+# terminal
+#-----------------------------------------------------------------------------
+
+# enable mouse support for general selection and control
+set-option -g mouse on
+
+# auto-set terminal title to current window pane's title
+set-option -g set-titles on
+
+# enable 256-color support for pretty colorschemes in Vim
+set-option -g default-terminal 'screen-256color'
+
+# allow Vim to receive focus events from terminal window
+set-option -g focus-events on
+
+# allow Vim to recieve modifier keys: Shift, Control, Alt
+set-window-option -g xterm-keys on
+
+# prevent tmux from catching modifier keys meant for Vim
+set-option -s escape-time 0
+
+# enable 24-bit true color RGB escape sequences under st
+# https://sunaku.github.io/tmux-24bit-color.html
+set-option -ga terminal-overrides ',st-256color:Tc'
+set-option -ga terminal-overrides ',xterm-256color:Tc' # hterm (ChromeOS)
+
+# allow set-titles to change the window title under XTerm
+# http://opennomad.com/content/goodbye-screen-hello-tmux
+set-option -ga terminal-overrides ',xterm*:XT'
+
+# allow set-titles to change the window title under XTerm
+# http://opennomad.com/content/goodbye-screen-hello-tmux
+# http://stackoverflow.com/questions/15195624
+set-option -ga terminal-overrides ',st-256color:smkx=\E='
+
+# yank to system clipboard rather than primary selection
+# http://invisible-island.net/xterm/terminfo-contents.html#tic-xterm_tmux
+set-option -ga terminal-overrides ',xterm*:Ms=\E]52;c;%p2%s\007'
+
+# KiTTY always appends to clipboard; must clear it first
+# https://sw.kovidgoyal.net/kitty/protocol-extensions.html#pasting-to-clipboard
+set-option -ga terminal-overrides ',xterm-kitty:Ms=\E]52;c;!\007\E]52;c;%p2%s\007'
+
+# prevent standout from appearing as italics under URxvt
+# http://comments.gmane.org/gmane.comp.terminal-emulators.tmux.user/1927
+set-option -ga terminal-overrides ',rxvt-unicode*:sitm@'
+
+#-----------------------------------------------------------------------------
+# appearance
+#-----------------------------------------------------------------------------
+
+# Colors from the "lucius" and "gruvbox" themes in the vim-airline plugin:
+# https://github.com/bling/vim-airline/blob/master/autoload/airline/themes/lucius.vim
+# https://github.com/morhetz/gruvbox/blob/master/autoload/airline/themes/gruvbox.vim
+
+set-option -g status-style fg=colour246,bg=colour237
+set-window-option -g window-status-current-style fg=colour214,bg=colour239
+set-option -g pane-border-style fg=colour239
+set-option -g pane-active-border-style fg=colour208
+set-option -g message-style fg=colour214,bg=colour239
+set-window-option -g mode-style fg=colour214,bg=colour239,bold,reverse
+
+# Common UI interaction cues from Blueprint CSS:
+# http://blueprintcss.org/tests/parts/forms.html
+set-window-option -g window-status-bell-style 'bg=#205791,fg=#d5edf8' # info (blue)
+set-window-option -g window-status-activity-style 'bg=#8a1f11,fg=#fbe3e4' # error (red)
+
+#-----------------------------------------------------------------------------
+# status bar
+#-----------------------------------------------------------------------------
+
+# toggle status bar visibility
+bind-key -n M-` set-option -g status
+
+# toggle status bar position
+bind-key -n M-~ \
+ if-shell 'tmux show-option -g status-position | grep -q top$' \
+ 'set-option -g status-position bottom' \
+ 'set-option -g status-position top'
+
+# put status bar at the top of the screen
+set-option -g status-position top
+
+# list windows on left side of status bar
+set-option -g status-left-length 0
+
+# make window list easier to scan
+set-window-option -g window-status-format ' #[bold]#I#F#[nobold]#W '
+set-window-option -g window-status-current-format ' #[bold]#I#F#[nobold]#W '
+set-window-option -g window-status-separator ''
+
+# show pane title, pane identifier, and hostname on right side of status bar
+set-option -g status-right-length 64
+set-option -g status-right '#{=32:pane_title} \
+#[fg=colour214,bg=colour239] #S:#I.#P \
+#(test -n "$SSH_TTY" && echo "#[fg=colour214,bg=colour239,bold,reverse] #H ")'
+
+#-----------------------------------------------------------------------------
+# windows
+#-----------------------------------------------------------------------------
+
+# create window
+bind-key -n M-e new-window
+
+# rename window
+bind-key -n M-E command-prompt -I '#W' 'rename-window "%%%"'
+
+set-window-option -g automatic-rename off
+
+
+# break off pane to a new window
+bind-key -n M-x \
+ command-prompt -p 'break-pane:' -I '#W' \
+ 'break-pane ; rename-window "%%%"'
+bind-key -n M-X break-pane
+
+# focus window
+bind-key -n M-, previous-window
+bind-key -n M-. next-window
+bind-key -n M-o last-window
+
+# focus by number
+set-option -g base-index 1
+set-window-option -g pane-base-index 1
+set-option -g renumber-windows on
+bind-key -n M-0 choose-window
+bind-key -n M-1 select-window -t :1
+bind-key -n M-2 select-window -t :2
+bind-key -n M-3 select-window -t :3
+bind-key -n M-4 select-window -t :4
+bind-key -n M-5 select-window -t :5
+bind-key -n M-6 select-window -t :6
+bind-key -n M-7 select-window -t :7
+bind-key -n M-8 select-window -t :8
+bind-key -n M-9 select-window -t :1 \; select-window -t :-1
+
+# swap window
+bind-key -n M-< swap-window -t :-1
+bind-key -n M-> swap-window -t :+1
+
+# monitor window
+set-option -g visual-activity on
+set-option -g visual-silence on
+
+
+bind-key -n M-k \
+ set-window-option monitor-activity \;\
+ display-message 'monitor-activity #{?monitor-activity,on,off}'
+
+bind-key -n M-K \
+ if-shell 'tmux show-window-option -g monitor-activity | grep -q off$' \
+ 'set-window-option -g monitor-activity on' \
+ 'set-window-option -g monitor-activity off' \;\
+ display-message 'monitor-activity #{?monitor-activity,on,off} (global)'
+
+bind-key -n M-j \
+ command-prompt -p 'monitor-silence (seconds):' -I '#{monitor-silence}' \
+ 'set-window-option monitor-silence %% ;\
+ display-message "monitor-silence #{?monitor-silence,on,off}"'
+
+#-----------------------------------------------------------------------------
+# panes
+#-----------------------------------------------------------------------------
+
+# send input to all panes in window (toggle)
+bind-key C-a \
+ set-option synchronize-panes \;\
+ display-message 'synchronize-panes #{?synchronize-panes,on,off}'
+
+# clear the screen in all panes in window
+bind-key C-l \
+ set-option synchronize-panes on \;\
+ send-keys C-l \;\
+ set-option synchronize-panes off
+
+# create pane (below, above, left, right)
+bind-key -n M-c split-window -c '#{pane_current_path}'
+bind-key -n M-C split-window -c '#{pane_current_path}' -b
+bind-key -n M-R split-window -c '#{pane_current_path}' -b -h
+bind-key -n M-r split-window -c '#{pane_current_path}' -h
+
+# join pane (above, left, below, right)
+bind-key -n M-g move-pane -t .-1 -s . # join pane at bottom of prev pane
+bind-key -n M-l move-pane -t .-1 -s . -h # join pane at right of prev pane
+bind-key -n M-G move-pane -d -s .+1 -t . # join next pane at bottom
+bind-key -n M-L move-pane -d -s .+1 -t . -h # join next pane at right
+
+# Intelligently navigate tmux panes and Vim splits using the same keys.
+# See https://sunaku.github.io/tmux-select-pane.html for documentation.
+#
+# +-------------+------------+-----------------------------+
+# | inside Vim? | is Zoomed? | Action taken by key binding |
+# +-------------+------------+-----------------------------+
+# | No | No | Focus directional tmux pane |
+# | No | Yes | Nothing: ignore key binding |
+# | Yes | No | Seamlessly focus Vim / tmux |
+# | Yes | Yes | Focus directional Vim split |
+# +-------------+------------+-----------------------------+
+#
+vim_navigation_timeout=0.05 # number of seconds we give Vim to navigate
+navigate=' \
+ pane_is_zoomed() { \
+ test #{window_zoomed_flag} -eq 1; \
+ }; \
+ pane_title_changed() { \
+ test "#{pane_title}" != "$(tmux display -p "##{pane_title}")"; \
+ }; \
+ command_is_vim() { \
+ case "${1%% *}" in \
+ (vi|?vi|vim*|?vim*|view|?view|vi??*) true ;; \
+ (*) false ;; \
+ esac; \
+ }; \
+ pane_contains_vim() { \
+ case "#{=3:pane_current_command}" in \
+ (git|ssh|sh) command_is_vim "#{=5:pane_title}" ;; \
+ (*) command_is_vim "#{=5:pane_current_command}" ;; \
+ esac; \
+ }; \
+ pane_contains_neovim_terminal() { \
+ test "#{=12:pane_title}" = "nvim term://"; \
+ }; \
+ navigate() { \
+ tmux_navigation_command=$1; \
+ vim_navigation_command=$2; \
+ vim_navigation_only_if=${3:-true}; \
+ if pane_contains_vim && eval "$vim_navigation_only_if"; then \
+ if pane_contains_neovim_terminal; then \
+ tmux send-keys C-\\ C-n; \
+ fi; \
+ eval "$vim_navigation_command"; \
+ if ! pane_is_zoomed; then \
+ sleep $vim_navigation_timeout; : wait for Vim to change title; \
+ if ! pane_title_changed; then \
+ eval "$tmux_navigation_command"; \
+ fi; \
+ fi; \
+ elif ! pane_is_zoomed; then \
+ eval "$tmux_navigation_command"; \
+ fi; \
+ }; \
+navigate '
+navigate_left=" $navigate 'tmux select-pane -L' 'tmux send-keys C-w h'"
+navigate_down=" $navigate 'tmux select-pane -D' 'tmux send-keys C-w j'"
+navigate_up=" $navigate 'tmux select-pane -U' 'tmux send-keys C-w k'"
+navigate_right="$navigate 'tmux select-pane -R' 'tmux send-keys C-w l'"
+navigate_back=" $navigate 'tmux select-pane -l || tmux select-pane -t1'\
+ 'tmux send-keys C-w p' \
+ 'pane_is_zoomed' "
+
+## QWERTY keys - comment these out if you don't use QWERTY layout!
+#bind-key -n M-h run-shell -b "$navigate_left"
+#bind-key -n M-j run-shell -b "$navigate_down"
+#bind-key -n M-k run-shell -b "$navigate_up"
+#bind-key -n M-l run-shell -b "$navigate_right"
+#bind-key -n M-\ run-shell -b "$navigate_back"
+
+# Dvorak keys - comment these out if you don't use Dvorak layout!
+bind-key -n M-d run-shell -b "$navigate_back"
+bind-key -n M-h run-shell -b "$navigate_left"
+bind-key -n M-t run-shell -b "$navigate_up"
+bind-key -n M-n run-shell -b "$navigate_down"
+bind-key -n M-s run-shell -b "$navigate_right"
+
+# resize pane
+bind-key -r H resize-pane -L 5
+bind-key -r T resize-pane -U 5
+bind-key -r N resize-pane -D 5
+bind-key -r S resize-pane -R 5
+
+# zoom pane
+bind-key -n M-m resize-pane -Z
+
+# swap pane
+bind-key -n M-- swap-pane -D
+bind-key -n M-_ swap-pane -U
+bind-key -n M-D run-shell 'tmux select-pane -l \; swap-pane -d -s #D'
+bind-key -n M-H run-shell 'tmux select-pane -L \; swap-pane -d -s #D'
+bind-key -n M-T run-shell 'tmux select-pane -U \; swap-pane -d -s #D'
+bind-key -n M-N run-shell 'tmux select-pane -D \; swap-pane -d -s #D'
+bind-key -n M-S run-shell 'tmux select-pane -R \; swap-pane -d -s #D'
+
+# attach by number
+bind-key -n 'M-!' join-pane -t :1
+bind-key -n 'M-@' join-pane -t :2
+bind-key -n 'M-#' join-pane -t :3
+bind-key -n 'M-$' join-pane -t :4
+bind-key -n 'M-%' join-pane -t :5
+bind-key -n 'M-^' join-pane -t :6
+bind-key -n 'M-&' join-pane -t :7
+bind-key -n 'M-*' join-pane -t :8
+bind-key -n 'M-(' run-shell 'tmux select-window -t :1 \;\
+ select-window -t :-1 \;\
+ join-pane -s "#{pane_id}"'
+bind-key -n 'M-)' choose-window 'join-pane -t "%%%"'
+
+# promote pane (toggle)
+bind-key -n M-Enter \
+ if-shell 'test #P -ne 1' \
+ 'select-pane -t 1' \
+ 'last-pane; swap-pane -s 1'
+
+# rotate panes
+bind-key -n M-a rotate-window -D
+bind-key -n M-A rotate-window -U
+
+#-----------------------------------------------------------------------------
+# layouts
+#-----------------------------------------------------------------------------
+
+bind-key M-w select-layout main-horizontal
+bind-key M-W select-layout even-vertical
+bind-key M-v select-layout main-vertical
+bind-key M-V select-layout even-horizontal
+bind-key M-z select-layout tiled
+
+# half-screen tiling layouts (horizontal, vertical)
+# https://sunaku.github.io/tmux-half-screen-tiling-layouts.html
+bind-key -n M-w select-layout main-horizontal \;\
+ run-shell 'tmux resize-pane -t 1 -y $(( #{window_height} / 2 ))'
+bind-key -n M-v select-layout main-vertical \;\
+ run-shell 'tmux resize-pane -t 1 -x $(( #{window_width} / 2 ))'
+
+# binary space partitioned layouts (dwindle, spiral)
+# https://sunaku.github.io/tmux-layout-dwindle.html
+bind-key -n M-w run-shell 'tmux-layout-dwindle brhc && tmux-redraw-vim'
+bind-key -n M-W run-shell 'tmux-layout-dwindle trhc && tmux-redraw-vim'
+bind-key -n M-v run-shell 'tmux-layout-dwindle brvc && tmux-redraw-vim'
+bind-key -n M-V run-shell 'tmux-layout-dwindle blvc && tmux-redraw-vim'
+bind-key -n M-z select-layout tiled
+
+#-----------------------------------------------------------------------------
+# scrollback buffer
+#-----------------------------------------------------------------------------
+
+# buffer length
+set-option -g history-limit 32767
+
+# search buffer using copy mode
+bind-key -n M-/ copy-mode \;\
+ command-prompt -p 'search-backward (press up):' \
+ -i 'send-keys -X search-backward-incremental "%%%"'
+
+# search buffer using Vim or less
+bind-key -n M-| \
+ capture-pane -J -S - \; \
+ new-window -n '#S:#I.#P' -a ' \
+ tmux save-buffer - \; delete-buffer | { \
+ if command -v vim; \
+ then vim -R -c "set nofen is hls ic" -; \
+ else less; \
+ fi; \
+ }; \
+ ' \; \
+ run-shell 'tmux send-keys G \?'
+
+# search colored buffer using less
+bind-key -n M-? \
+ capture-pane -e -J -S - \; \
+ new-window -n '#S:#I.#P' -a ' \
+ tmux save-buffer - \; delete-buffer | \
+ less -R \
+ ' \; \
+ run-shell 'tmux send-keys G \?'
+
+# scroll buffer
+# NOTE: set "URxvt.saveLines: 0" in ~/.Xdefaults to make Shift+PageUp bindable
+# NOTE: see http://aperiodic.net/screen/interface for doing the same in XTerm
+bind-key -n S-PPage copy-mode -u
+
+# copy text from buffer
+bind-key -n M-u copy-mode
+set-window-option -g mode-keys vi
+bind-key -T copy-mode-vi v send-keys -X begin-selection
+bind-key -T copy-mode-vi y send-keys -X copy-selection
+bind-key -T copy-mode-vi - send-keys -X jump-again
+bind-key -T copy-mode-vi _ send-keys -X jump-reverse
+bind-key -T copy-mode-vi ? command-prompt -p 'search-backward:' -I '#{pane_search_string}' -i 'send-keys -X search-backward-incremental "%%%"'
+bind-key -T copy-mode-vi / command-prompt -p 'search-forward:' -I '#{pane_search_string}' -i 'send-keys -X search-forward-incremental "%%%"'
+
+# transfer copied text to attached terminal with yank:
+# https://github.com/sunaku/home/blob/master/bin/yank
+bind-key -T copy-mode-vi Y send-keys -X copy-pipe 'yank > #{pane_tty}'
+# open the visual selection with xdg-open(1)
+bind-key -T copy-mode-vi O send-keys -X copy-pipe 'xargs -r xdg-open'
+
+# paste most-recently copied text
+bind-key -n M-i paste-buffer
+
+# paste previously copied text (chosen from a menu)
+bind-key -n M-I choose-buffer
+
+# transfer most-recently copied text to attached terminal with yank:
+# https://github.com/sunaku/home/blob/master/bin/yank
+bind-key -n M-y run-shell 'tmux save-buffer - | yank > #{pane_tty}'
+
+# transfer previously copied text (chosen from a menu) to attached terminal:
+# https://github.com/sunaku/home/blob/master/bin/yank
+bind-key -n M-Y choose-buffer 'run-shell "tmux save-buffer -b \"%%%\" - | yank > #{pane_tty}"'
+
+#-----------------------------------------------------------------------------
+# TMUX plugin manager https://github.com/tmux-plugins/tpm
+#-----------------------------------------------------------------------------
+
+set -g @plugin 'tmux-plugins/tmux-resurrect'
+set -g @resurrect-capture-pane-contents on
+
+set -g @plugin 'Morantron/tmux-fingers'
+set -g @fingers-key '-n M-U'
+set -g @fingers-compact-hints 1
+set -g @fingers-hint-format '#[fg=yellow,bold,reverse]%s'
+set -g @fingers-hint-labels ' \
+ a o e u i d h t n s \
+ p y f g c r l \
+ q j k x b m w v z \
+ A O E U I D H T N S \
+ P Y F G C R L \
+ Q J K X B M W V Z \
+'
+
+run-shell ~/.tmux/plugins/tpm/tpm
diff --git a/regress/conf/a4789a6782859c66aa8c9614ee6fabfa.conf b/regress/conf/a4789a6782859c66aa8c9614ee6fabfa.conf
new file mode 100644
index 00000000..7f4a8cd1
--- /dev/null
+++ b/regress/conf/a4789a6782859c66aa8c9614ee6fabfa.conf
@@ -0,0 +1,80 @@
+set -g default-command "if [ \"$(uname)\" = 'Darwin' ]; then exec reattach-to-user-namespace $SHELL; else exec $SHELL; fi"
+set -g history-limit 32000
+set -g update-environment "DISPLAY WINDOWID SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION SSH_CLIENT SSH_TTY KRB5CCNAME Apple_PubSub_Socket_Render Apple_Ubiquity_Message"
+
+# Reset SHLVL (otherwise it is 2 inside tmux)
+setenv -g SHLVL 0
+
+# Send esc faster so that neovim won't get so laggy
+# https://github.com/neovim/neovim/issues/2093
+set -g escape-time 100
+
+# Disable paste detection
+set -g assume-paste-time 0
+
+# Titles and window names
+set -g set-titles on
+set -g set-titles-string "#T"
+
+# Make it not so annoying/sticky to switch windows
+set -g repeat-time 170
+
+# Don't deattach me when a session ends
+set -g detach-on-destroy off
+
+# Make shift+keys work
+setw -g xterm-keys on
+
+# Prefix
+set -g prefix ^A
+unbind ^B
+bind ^A send-prefix
+bind a send-prefix
+
+# Last window
+bind ^a last
+
+# Next & prev
+bind ' ' next
+bind '^ ' next
+bind ^p prev
+
+# Status
+set -g status off
+# Need more (cow)bells!
+set -g bell-action any
+set -g bell-on-alert on
+
+# Detach
+bind ^d detach
+
+# Control the a tmux in a tmux
+bind A send-prefix \; send-prefix
+bind C send-prefix \; send-keys c
+bind n send-prefix \; send-keys ' '
+bind bspace send-prefix \; send-keys p
+bind '#' send-prefix \; send-keys '"'
+
+# Other key bindings.
+bind ^r command-prompt "find-window '%%'"
+bind '"' choose-tree -w
+bind w split-window
+bind W split-window -c "#{pane_current_path}"
+bind ^w split-window
+bind I list-windows
+bind i list-windows
+bind D neww 'if who | grep -q "$USER.* via mosh"; then tmux lsc -F "#{client_activity} #{client_tty}" | sort | head -n -1 | awk "{print \$2}" | xargs -n1 tmux detach -t; else for i in $(tmux lsc | cut -d: -f1 | grep -v "^$SSH_TTY$"); do tmux detach -t $i; done; fi'
+bind S neww -t 999 'window=`tmux display -p "#{pane_title}"`; i=0; tmux list-windows | cut -d: -f1 | while read j; do if [ $j != $i ]; then tmux move-window -s $j -t $i; fi; i=$(($i+1)); done' # ; tmux find-window -T "$window"
+bind ^s command-prompt "rename-session '%%'"
+# Make the default HOME always ~
+bind c neww -c ~
+bind ^c new -c ~
+bind escape copy-mode
+# Copy to the OS clipboard
+bind -T copy-mode-vi y send -X copy-pipe-and-cancel "if [ \"$(uname)\" = 'Darwin' ]; then reattach-to-user-namespace pbcopy; else xclip; fi"
+bind j command-prompt "join-pane -s '%%'"
+bind ! break-pane -d
+bind - command-prompt "move-pane -t '%%'"
+
+# Makes `tmux a` work even when there isn't a session going on
+new-session -A -c ~
diff --git a/regress/conf/ad0537c4e83d7a25d5dc4f3a3c571349.conf b/regress/conf/ad0537c4e83d7a25d5dc4f3a3c571349.conf
new file mode 100644
index 00000000..ce68c4ab
--- /dev/null
+++ b/regress/conf/ad0537c4e83d7a25d5dc4f3a3c571349.conf
@@ -0,0 +1,65 @@
+set-option -g allow-rename on
+set-option -g automatic-rename off
+set-option -g base-index 1
+set-option -g default-command "$SHELL"
+set-option -g default-terminal "tmux-256color"
+set-option -g history-limit 25000
+set-option -g mode-keys vi
+set-option -g prefix C-f
+set-option -g renumber-windows yes
+set-option -g set-titles on
+set-option -g set-titles-string "#T"
+set-option -g xterm-keys on
+
+set-option -g status-interval 1
+set-option -g status-left "#(tmux-status-left)"
+set-option -g status-left-length 40
+set-option -g status-right ""
+
+set-option -g window-status-current-attr bold
+set-option -g window-status-current-format "[#I#F#{?window_zoomed_flag, ,}#{=40:pane_title}]"
+set-option -g window-status-format "#I#{?window_zoomed_flag, ,}#F#{?window_flags,, }#{?window_zoomed_flag, ,}#{=20:pane_title}"
+
+set-option -g pane-active-border-fg colour247
+set-option -g pane-border-fg colour235
+set-option -g status-bg colour7
+set-option -g status-fg colour16
+set-option -g status-left-bg colour4
+set-option -g status-left-fg colour15
+set-option -g window-status-current-bg colour15
+set-option -g window-status-current-fg colour16
+
+set-option -g update-environment "DBUS_SESSION_BUS_ADDRESS DISPLAY KRB5CCNAME \
+ SESSION_MANAGER SSH_AGENT_PID SSH_ASKPASS SSH_AUTH_SOCK SSH_CONNECTION \
+ WINDOWID XAUTHORITY SSH_TTY"
+
+bind-key w break-pane -d
+bind-key l clear-history \; display "Pane history cleared."
+bind-key C-f if-shell "test #{window_panes} -eq 1" last-window last-pane
+bind-key N new-session
+bind-key t new-window
+bind-key z resize-pane -Z
+bind-key C-r rotate-window -D
+bind-key -n C-t run-shell "metamux new-shell-in-pane #{window_panes}"
+bind-key n run-shell "metamux rotate-pane next"
+bind-key p run-shell "metamux rotate-pane prev"
+bind-key q run-shell "metamux pane-buster"
+bind-key S run-shell "metamux join-hidden-pane -v"
+bind-key u run-shell "metamux open-last-url-printed"
+bind-key | run-shell "metamux join-hidden-pane -h"
+bind-key f send-prefix
+bind-key r source "$HOME/.tmux.conf" \; display "Configuration reloaded."
+
+# When the current window is split, Ctrl+Tab and Ctrl+Shift+Tab should rotate
+# between the split windows. If there is only one pane in the current window,
+# Ctrl+Tab and Ctrl+Shift+Tab will cycle between windows as though they were
+# tabs in modern desktop UIs.
+bind-key -n C-Tab if-shell "test #{window_panes} -eq 1" next-window "select-pane -t :.+"
+bind-key -n C-S-Tab if-shell "test #{window_panes} -eq 1" previous-window "select-pane -t :.-"
+
+# Binding to mark and swap panes; if no pane is marked, the shortcut will mark
+# the active pane, but if a pane is already marked, active pane will be swapped
+# with the marked pane.
+bind-key m if-shell 'test -z "$PANE_IS_MARKED"' \
+ "select-pane -m; set-env PANE_IS_MARKED 1" \
+ "swap-pane; select-pane -M; set-env -u PANE_IS_MARKED"
diff --git a/regress/conf/ad21dbb0893240563ddfdd954b9903a1.conf b/regress/conf/ad21dbb0893240563ddfdd954b9903a1.conf
new file mode 100644
index 00000000..27d8f310
--- /dev/null
+++ b/regress/conf/ad21dbb0893240563ddfdd954b9903a1.conf
@@ -0,0 +1,580 @@
+# Time-stamp: <2018-05-31 17:10:05 kmodi>
+# https://github.com/tmux/tmux
+# Hi-lock: (("\\(^\\s< \\**\\)\\(\\* *.*\\)" (1 'org-hide prepend) (2 '(:inherit org-level-1 :height 1.3 :weight bold :overline t :underline t) prepend)))
+# Hi-Lock: end
+
+# Running tmux built from master branch on tcsh in uxterm
+# tmux version 2.5-RC+ dev
+
+# Contents:
+#
+# PREFIX
+# Source config
+# Pane Management
+# Window <-join/split-> Pane
+# Select Panes
+# Resize Panes
+# Dynamic Split
+# Window Management
+# Window Navigation
+# Swap Windows
+# Split Window
+# Layout
+# Session Management
+# Mouse
+# Drag pane border to resize
+# Left click on pane
+# Middle click on pane
+# Right click on pane
+# Wheel scroll in pane
+# Wheel scroll in pane WHILE in copy-mode
+# Left click on status
+# Middle click on status
+# Other mouse settings
+# Window Title
+# Status Bar
+# Left Status
+# Right Status
+# Pane Status
+# Colors
+# Status Bar Colors
+# Message Colors
+# Window Status Colors
+# Pane Colors
+# Mode Info Colors
+# Activity
+# Command Prompt
+# Audible and Visual Bells
+# Copy & Paste
+# Synchronize commands to panes/windows/sessions
+# Terminal Setting
+# Other Options
+# Server Options
+# Session Options
+# Window Options
+# Notes
+
+# * PREFIX
+set -g prefix C-z
+unbind C-b # unbind the default binding to send prefix key to the application
+# Often you'll run a tmux inside another tmux and need a command sequence to
+# send things to the inner session. With below binding that can be accomplished
+# using "PREFIX Z <command>"
+bind Z send-prefix
+
+# * Source config
+unbind r # unbind default binding to force redraw of attached client
+bind r source-file ~/.tmux.conf \; display "Finished sourcing ~/.tmux.conf ."
+
+# * Pane Management
+
+set -g pane-base-index 1 # start pane indices at 1
+set -g main-pane-width 100 # used by selectl main-vertical
+bind z resize-pane -Z # zoom/unzoom the current pane
+# If the window has >1 panes kill them without confirming. But confirm before kill
+# the last pane (along with its window) in a window
+bind x if "tmux display -p \"#{window_panes}\" | grep ^1\$" \
+ "confirm-before -p \"Kill the only pane in window? It will kill this window too! (y/n)\" kill-pane" \
+ "kill-pane"
+bind C clear-history \; display "Cleared history of the current pane."
+unbind C-p
+bind C-p run -b "tmux display -p -F '#{pane_current_path}' | xclip -i -sel pri" \; display "Copied current path '#{pane_current_path}' to the primary selection."
+
+# Hooks need tmux 2.3+
+# set-hook -g -u after-kill-pane # Remove after hook for kill-pane
+set-hook -g after-kill-pane "selectl main-vertical"
+# If -g options is used when setting the hook, it has to be used when
+# removing (-u option) the hook too.
+
+# ** Window <-join/split-> Pane
+# Join a pane *from* a different window (of same or different session) into the CURRENT window
+# Binding mnemonic: F for (F)etch/pull (as in git) from a different window
+bind F command-prompt -p "Join pane from [sess:]win#[.pane#] (ex: kmodi:3.1) into current window:" "join-pane -s '%%'"
+# Join CURRENT pane *to* a different window
+# Binding mnemonic: P for (P)ush (as in git) to a different window
+bind P command-prompt -p "Send CURRENT pane to [sess:]win# (ex: kmodi:3):" "join-pane -t '%%'"
+# PREFIX ! : break-pane, convert the current pane to a window
+
+# ** Select Panes
+bind o select-pane -t :.+ # cycle to the next pane number
+bind O select-pane -t :.- # cycle to the previous pane number
+# PREFIX ; : last-pane or select-pane -l, switch to the last active pane
+# PREFIX ← : select-pane -L, switch to the pane on the left
+# PREFIX → : select-pane -R, switch to the pane on the right
+# PREFIX ↑ : select-pane -U, switch to the pane on the top
+# PREFIX ↓ : select-pane -D, switch to the pane on the bottom
+# PREFIX { : swap-pane -U, swap current pane with the pane above (not literally above)
+# PREFIX } : swap-pane -D, swap current pane with the pane below (not literally below)
+
+# ** Resize Panes
+bind -r h resize-pane -L 2
+bind -r C-h resize-pane -L 2
+bind -r j resize-pane -D 2
+bind -r C-j resize-pane -D 2
+bind -r k resize-pane -U 2
+bind -r C-k resize-pane -U 2
+unbind l # unbind default binding for `last-window`
+bind -r l resize-pane -R 2
+bind -r C-l resize-pane -R 2
+
+# ** Dynamic Split
+# Key-chaining example, analogous to prefix maps in emacs
+bind / switch-client -Tlauncher
+# Run below -Tlauncher commands using "PREFIX / <binding>"
+# Open calendar in a split window "PREFIX / c"
+# FIXME: Below does not work; cal pane quits as soon as it launches (before "&& sleep .."
+# was added). To make better of the situation, I now auto-close that pane after 3 seconds.
+# bind -Tlauncher c split-window -h 'cal && sleep 3'
+bind -Tlauncher c run "/home/kmodi/scripts/tcsh/tmux/dynamic_split.csh 'cal && sleep 3'"
+# Start emacsclient in terminal mode in a split window "PREFIX / e"
+# Use the emacs binding "C-x 5 0" to quit from that pane gracefully.
+bind -Tlauncher e run "/home/kmodi/scripts/tcsh/tmux/dynamic_split.csh 'emacsclient -a \"\" -t'"
+# Open man page "PREFIX / m"
+# PREFIX / m will bring up the tmux command prompt. Enter the command for which
+# you want to see the man page, example: ls. That man page will open in a split
+# pane. When you are done reviewing the man page, hit q and the split pane
+# closes by itself. Beautiful!
+bind -Tlauncher m command-prompt -p "man" "run \"/home/kmodi/scripts/tcsh/tmux/dynamic_split.csh 'man %1'\""
+# Open python interpreter in a split window for quick calculations "PREFIX / p"
+# Ctrl-D in python quits python and thus closes the split window too.
+bind -Tlauncher p run "/home/kmodi/scripts/tcsh/tmux/dynamic_split.csh 'ipython --profile=default --no-confirm-exit'"
+# PREFIX Up, Down, Right, Left : Move cursor from one pane to another
+# PREFIX Space : Cycle through different pane layouts
+# PREFIX C-o : rotate-window, rotate panes in the current window
+
+# * Window Management
+set -g base-index 1 # start window indices at 1
+# automatically renumber the windows
+# http://unix.stackexchange.com/questions/21742/renumbering-windows-in-tmux
+set -g renumber-windows on
+
+bind C-f command-prompt -p "New window:" "new-window -c '#{pane_current_path}' -n %1"
+bind C-r command-prompt -p "New name for this window:" "rename-window '%%'"
+unbind L # unbind default binding for `switch-client -l`
+bind L list-windows -F '#{window_index}:#{window_name}: #{?pane_dead, (dead), (not dead)}'
+unbind & # unbind default binding for `kill-window`
+bind C-c confirm-before -p "Kill this window? (y/n)" kill-window
+# Move the current window to another window index in the same or any other session
+bind m command-prompt -p "Move window to sess or sess:win# or win# (ex: kmodi or kmodi:3 or 2(of current session)):" "move-window -t '%%'"
+# Move or bring a window from a different session to the current one
+bind M command-prompt -p "Move the window from sess:win# (ex: kmodi:3):" "move-window -s '%%'"
+
+# ** Window Navigation
+bind C-z last-window # switch to last active window
+# Allow repeats for next/previous-window
+bind -r p previous-window
+bind -r n next-window
+# switch to another window by name
+bind W split-window "tmux lsw | peco --initial-index `tmux lsw | awk '/active.$/ {print NR-1}'` | cut -d':' -f 1 | xargs tmux select-window -t"
+# PREFIX <N> : switches to window with index=N
+
+# ** Swap Windows
+bind N move-window -r # renumber the windows
+unbind , # unbind default binding for `rename-window`
+bind -r , swap-window -t -1 # move window one position to the left
+bind -r < swap-window -t -1 # move window one position to the left
+unbind . # unbind default binding to move window to user provided index
+bind -r . swap-window -t +1 # move window one position to the right
+bind -r > swap-window -t +1 # move window one position to the right
+unbind t # unbind default binding to show time
+bind t swap-window -t 1 # swap the current window's position with window # 1, move it to the top
+
+# ** Split Window
+unbind & # unbind default binding for `split-window -h`
+bind - split-window -v -c '#{pane_current_path}' # vertical split
+bind _ split-window -v -c '#{pane_current_path}' -f # full vertical split (v2.3+)
+bind \ split-window -h -c '#{pane_current_path}' # horizontal split
+bind | split-window -h -c '#{pane_current_path}' -f # full horizontal split (v2.3+)
+# https://www.reddit.com/r/tmux/comments/3paqoi/tmux_21_has_been_released/cw5wy00
+bind w switch-client -Tsplit_wind
+bind -Tsplit_wind v split-window -v -c '#{pane_current_path}'
+bind -Tsplit_wind V split-window -v -c '#{pane_current_path}'\; swap-pane -U
+bind -Tsplit_wind h split-window -h -c '#{pane_current_path}'
+bind -Tsplit_wind H split-window -h -c '#{pane_current_path}'\; swap-pane -U
+
+# ** Layout
+bind Space next-layout
+bind C-Space select-layout -o # undo only the last layout change #v2.1
+
+# * Session Management
+bind C-t command-prompt -p "New name for this session:" "rename-session '%%'"
+bind b switch-client -l # switch to previously selected session
+# switch to another session by name
+bind S split-window "tmux ls | peco --initial-index `tmux ls | awk '/attached.$/ {print NR-1}'` | cut -d':' -f 1 | xargs tmux switch-client -t"
+# switch to ANY window in ANY session by name
+bind s split-window "tmux ls | cut -d: -f1 | xargs -I SESSION tmux lsw -F 'SESSION:#{window_name}' -t SESSION | peco --initial-index `tmux ls | cut -d: -f1 | xargs -I SESSION tmux lsw -F '___#{session_attached}#{window_active}___' -t SESSION | awk '/___11___/ {print NR-1}'` | xargs tmux switch-client -t"
+# tmux kill-session -t NAME/SESSIONNUMBER # Kill session
+
+# * Mouse
+# setw -g mode-mouse on # incompatible in tmux 2.1+
+set -g mouse on
+
+# ** Drag pane border to resize
+# set -g mouse-resize-pane off # incompatible in tmux 2.1+
+bind -T root MouseDrag1Border resize-pane -M # default
+# unbind -T root MouseDrag1Border # disable drag pane border to resize
+
+bind -T root MouseDrag1Pane if -Ft= '#{mouse_any_flag}' 'if -Ft= "#{pane_in_mode}" "copy-mode -M" "send-keys -M"' 'copy-mode -M' # default
+
+# ** Left click on pane
+# set -g mouse-select-pane on # incompatible in tmux 2.1+
+# Left click on a pane selects it
+# bind -T root MouseDown1Pane select-pane -t=\; send-keys -M # default
+bind -T root MouseDown1Pane select-pane -t=
+
+# Sun Feb 19 11:31:34 EST 2017 - kmodi
+# Below break in tmux 2.4
+# # Fri Aug 26 18:35:21 EDT 2016 - kmodi
+# # FIXME Need to remember why I unbound the below 2 bindings
+# unbind -temacs-copy MouseDown1Pane
+# unbind -temacs-copy MouseUp1Pane
+# #
+
+# https://groups.google.com/forum/#!topic/tmux-users/mHhdx7Au0Ds
+# Fri Aug 26 18:30:15 EDT 2016 - kmodi
+# Do not do the below!! That will update the primary selection with the top-most
+# tmux buffer each time you left click on a pane.
+# bind -T root MouseUp1Pane run -b "tmux show-buffer | xclip -i -sel pri"
+#
+
+# Left click in the pane *followed after a region selection* copies that to the
+# secondary selection
+bind -T root MouseUp1Pane run -b "tmux show-buffer | xclip -i -sel sec"
+# Fri Aug 26 19:03:57 EDT 2016 - kmodi
+# FIXME: As of today it needs to be figured out how to best paste the content
+# from secondary selection
+
+# ** Middle click on pane
+# Middle click in a pane to paste from the primary selection
+bind -T root MouseDown2Pane run -b "xclip -o -sel pri | tmux load-buffer - && tmux paste-buffer -s ' '"
+
+# ** Right click on pane
+# Right click on a pane selects and marks it *if not in copy-mode*; else
+# passes on the mode keys
+# bind -T root MouseDown3Pane select-pane -t= -m # default
+bind -T root MouseDown3Pane if -Ft= '#{pane_in_mode}' 'send-keys -M' 'select-pane -t= -m'
+
+# Sun Feb 19 11:32:00 EST 2017 - kmodi
+# Below breaks in tmux 2.4
+# # Right click *release* on a pane *in copy-mode* quits copy-mode
+# bind -temacs-copy MouseUp3Pane cancel
+
+# ** Wheel scroll in pane
+unbind -T root WheelUpPane
+unbind -T root WheelDownPane
+# Do mouse wheel-up to enter copy mode and do page-up
+# https://groups.google.com/d/msg/tmux-users/XTrSVUR15Zk/3iyJLMyQ7PwJ
+# Below binding did not work
+# bind -T root WheelUpPane if -Ft= '#{mouse_any_flag}' 'if -Ft= "#{pane_in_mode}" "copy-mode -u" "send-keys -M"' 'copy-mode -u'
+# Below works and allows the WheelUpPane binding in emacs-copy table to be effective
+bind -T root WheelUpPane if -Ft= '#{mouse_any_flag}' 'send-keys -M' 'if -Ft= "#{pane_in_mode}" "send-keys -M" "copy-mode -u"'
+# |---------------------+-----------------------------------------+--------------------------------|
+# | using mouse? AND .. | #{pane_in_mode} (already in copy-mode?) | action |
+# |---------------------+-----------------------------------------+--------------------------------|
+# | Yes | Don't care | Send the mode keys |
+# | No | Yes | Send the mode keys |
+# | No | No | Enable copy-mode and do PageUp |
+# |---------------------+-----------------------------------------+--------------------------------|
+
+# *** Wheel scroll in pane WHILE in copy-mode
+# Sun Feb 19 11:32:16 EST 2017 - kmodi
+# Below breaks in tmux 2.4
+# # Once in copy-mode, mouse wheel scrolls scrolls by half pages
+# bind -temacs-copy WheelUpPane halfpage-up
+# bind -temacs-copy WheelDownPane halfpage-down
+
+# ** Left click on status
+# set -g mouse-select-window on # incompatible in tmux 2.1+
+# Left click on a window name in status bar to select it
+bind -T root MouseDown1Status select-window -t= # default
+
+# ** Middle click on status
+# Middle click on a window name in status bar to kill it
+bind -T root MouseDown2Status kill-window
+
+# ** Other mouse settings
+# The special token ‘{mouse}’ or ‘=’ may be used as target-window or target-pane in
+# commands bound to mouse key bindings. Example: -t =
+
+# * Window Title
+set -g set-titles on
+set -g set-titles-string '#h :: #S:W#I(#W).P#P'
+
+# * Status Bar
+set -g status-interval 5 # default = 15 seconds
+set -g status-justify centre
+
+# ** Left Status
+set -g status-left-length 20
+# Change the left status when prefix is pressed.
+# https://www.reddit.com/r/tmux/comments/5cm2ca/post_you_favourite_tmux_tricks_here/d9ziuy9/
+set -g status-left "#{?client_prefix,#[fg=yellow]prefix pressed ..,[#S]}"
+
+# ** Right Status
+set -g status-right-length 20
+set -g status-right "%l:%M %b %d %a "
+
+# ** Pane Status
+setw -g pane-border-status "bottom"
+setw -g pane-border-format " #P #T "
+
+# # tmux-powerline
+# # https://github.com/erikw/tmux-powerline
+# set -g status-left-length 30
+# set -g status-right-length 30
+# set -g status-left "#(~/usr_local/scripts/tmux-powerline/powerline.sh left)"
+# set -g status-right "#(~/usr_local/scripts/tmux-powerline/powerline.sh right)"
+
+# * Colors
+
+# ** Status Bar Colors
+set -g status-style fg=colour246,bg=colour233 # default for whole status line
+set -g status-left-style fg=white,bold,bg=colour233
+set -g status-right-style fg=colour75,none,bg=colour233
+
+# ** Message Colors
+set -g message-style fg=colour2,bold,bg=default
+
+# ** Window Status Colors
+setw -g window-status-style default # default for all window statuses
+setw -g window-status-last-style fg=default,bg=colour235
+setw -g window-status-current-style fg=white,bold,bg=colour63
+setw -g window-status-bell-style default
+setw -g window-status-activity-style fg=white,none,bg=colour196
+# setw -g window-status-content-style fg=black,none,bg=green # incompatible with tmux 2.0+
+
+# ** Pane Colors
+setw -g pane-active-border-style fg=colour63,bg=default
+setw -g pane-border-style fg=colour235,bg=default
+setw -g window-active-style 'bg=#330000' # bg color of active pane
+setw -g window-style 'bg=black' # bg color of inactive pane(s)
+
+# ** Mode Info Colors
+# Color of display shown on top-right in copy-mode, highlighting
+setw -g mode-style fg=black,bg=colour244
+
+# * Activity
+# Notify when a window has activity
+# This quick snippet will have tmux notify you in the status area when a
+# window has activity:
+setw -g monitor-activity on
+set -g visual-activity off # Display message telling that an activity happened (on/off)
+# It lets me know that there is activity in a non-active window
+# To try this, enter `sleep 10 && echo “Hi”` in a window and switch to
+# another window.
+
+# # Notify when a window has a content alert
+# setw -g monitor-content "--[A-Za-z][A-Za-z]sim Done--" # This string appears when a sim finishes, alert then # incompatible with tmux 2.0+
+# # setw -g monitor-content "" # Disable monitor-content
+# set -g visual-content on # Display message telling that a content alert was triggered (on/off) # incompatible with tmux 2.0+
+
+# * Command Prompt
+# Move focus to command prompt. tmux commands can be entered there directly
+# without using the `tmux` prefix and it also supports auto-complete.
+bind C-x command-prompt # default command-prompt binding "PREFIX :" also works
+
+# * Audible and Visual Bells
+set -g bell-action any
+set -g bell-on-alert off
+set -g visual-bell on
+
+# * Copy & Paste
+set -g set-clipboard off # default is on
+
+# Copy tmux buffer to primary and clipboard selections
+# run -b runs a shell command in background
+# http://grota.github.io/blog/2012/05/08/tmux-clipboard-integration/
+bind C-w run -b "tmux show-buffer | xclip -i -sel pri && tmux show-buffer | xclip -i -sel cli"
+# Fri Aug 26 18:41:30 EDT 2016 - kmodi
+# Below binding was suggested by Nicholas Marriott
+# But the my older binding works fine so I am commenting out below for now.
+# bind C-w run "tmux saveb - | xclip -i -sel pri; tmux saveb - | xclip -i -sel cli"
+# Paste into tmux; also replace LF characters with
+# space as separator characters (-s) when pasting.
+# Yank from primary
+bind C-y run -b "xclip -o -sel pri | tmux load-buffer - && tmux paste-buffer -s ' '"
+# Yank from clipboard
+bind M-y run -b "xclip -o -sel cli | tmux load-buffer - && tmux paste-buffer -s ' '"
+# Open the file/dir path that was copied by selection in existing emacs client
+# Usage: Highlight a file name in ls output and press "PREFIX e"
+bind e run -b "tmux show-buffer | xclip -i -sel pri; (emacsclient -a '' `tmux display -p '#{pane_current_path}'`/`xclip -o -sel pri `&)"
+
+# * Synchronize commands to panes/windows/sessions
+# Send the same command to all panes in the same window
+bind C-a command-prompt -p "Command to all panes in this window:" \
+ "run \"tmux list-panes -F '##{pane_index}' | xargs -I PANE \
+ tmux send-keys -t PANE '%1' Enter\""
+# Alternative to using the above "C-a" binding is to enable pane synchronization,
+# type the command you want to execute in all panes in the same window and disable
+# pane synchronization
+# Also turn the pane borders red while pane synchronization is enabled.
+# - https://www.reddit.com/r/tmux/comments/5cm2ca/post_you_favourite_tmux_tricks_here/d9y6jzu/
+bind C-s if -F '#{pane_synchronized}' \
+ 'setw synchronize-panes off; \
+ setw pane-active-border-style fg=colour63,bg=default; \
+ setw pane-border-format " #P #T "' \
+ 'setw synchronize-panes on; \
+ setw pane-active-border-style fg=red; \
+ setw pane-border-format " #P - Pane Synchronization ON "'
+# So it would be: C-s <type the command RET> C-s
+
+# https://scripter.co/command-to-every-pane-window-session-in-tmux/
+# Send the same command to all panes/windows in the current session
+bind C-e command-prompt -p "Command:" \
+ "run \"tmux list-panes -s -F '##{session_name}:##{window_index}.##{pane_index}' \
+ | xargs -I PANE tmux send-keys -t PANE '%1' Enter\""
+
+# Send the same command to all panes/windows/sessions
+bind E command-prompt -p "Command:" \
+ "run \"tmux list-panes -a -F '##{session_name}:##{window_index}.##{pane_index}' \
+ | xargs -I PANE tmux send-keys -t PANE '%1' Enter\""
+
+# * Terminal Setting
+
+# From `man tmux', about `default-terminal'
+# Set the default terminal for new windows created in this session - the default
+# value of the TERM environment variable. For tmux to work correctly, this must
+# be set to ‘screen’, ‘tmux’ or a derivative of them.
+# set -g default-terminal "screen"
+set -g default-terminal "screen-256color"
+# Mon May 22 11:43:56 EDT 2017 - kmodi
+# Blinking text (useful to show broken symlinks in ls) does not work when using tmux-24bits.
+# set -g default-terminal "tmux-24bits"
+# tmux-24bits is a custom terminfo profile created using the steps explained
+# on https://github.com/ThomasAdam/tmux/blob/master/FAQ to support italics and
+# 256 colors.
+
+# Enable 24-bit color
+# https://sunaku.github.io/tmux-24bit-color.html
+set -ga terminal-overrides ",screen-256color:Tc"
+# set -ga terminal-overrides ",tmux-24bits:Tc"
+
+# Thu May 31 17:10:04 EDT 2018 - kmodi
+# TODO: Try the 24-bit emacs+tmux config for ST
+# https://www.reddit.com/r/emacs/comments/8ndm2x/gnu_emacs_261_24bit_colors_suckless_st_terminal/dzwh4vv/
+# set -g default-terminal "tmux-256color"
+# set -ga terminal-overrides ",*256col*:Tc"
+#
+
+setw -g xterm-keys on
+
+# Uncomment below when using st (by suckless.org)
+# set -g default-terminal "st-256color"
+# # https://sunaku.github.io/tmux-24bit-color.html
+# # st supports 24-bit color, so enable support for that in tmux
+# set -ga terminal-overrides ",st-256color:Tc"
+# setw -g xterm-keys off
+
+bind R refresh-client
+# bind R refresh-client \; display "Refreshed the client."
+
+# * Other Options
+
+# ** Server Options
+set -s escape-time 0 # Allows for faster key repetition
+
+# ** Session Options
+# Set the default shell to /bin/sh. If the default is tcsh, doing a split-window takes a long
+# time as my tcsh init is loaded first (which takes really long).
+set -g default-shell /bin/sh
+# If I am doing a new-window or split-window without a specified command, start the tcsh
+# shell by default.
+set -g default-command tcsh
+set -g history-limit 100000
+set -g display-time 1000 # Duration of tmux display messages in milliseconds
+
+# ** Window Options
+# When a smaller terminal connects to a tmux client, it shrinks to fit it. The
+# clients attached with bigger displays see this constrained view.
+# aggressive-resize makes it such that the window is only resized if the smaller
+# client is actively looking at it.
+setw -g aggressive-resize on
+setw -g mode-keys emacs # Use emacs keybindings in copy mode
+setw -g status-keys emacs
+
+# * Notes
+
+# |-------------------+------------|
+# | tmux command | short form |
+# |-------------------+------------|
+# | set-option | set |
+# | set-window-option | setw |
+# | bind-key | bind |
+# | unbind-key | unbind |
+# | display-message | display |
+# | run-shell | run |
+# | if-shell | if |
+# |-------------------+------------|
+
+# Colo'u'r table
+# http://guns.github.io/xterm-color-table.vim/images/xterm-color-table.png
+
+# CHARACTER PAIR REPLACED WITH
+# #(command) First line of command’s output
+# #[attributes] Colour or attribute change
+# #H Hostname of local host
+# #I Current window index
+# #P Current pane index
+# #S Session name
+# #T Current window title
+# #W Current window name
+# ## A literal ‘#’
+
+# Variables used in time format
+# Source: http://docs.splunk.com/Documentation/Splunk/5.0.2/SearchReference/Commontimeformatvariables
+# %y = year in numbers (2-digit)
+# %Y = year in numbers (4-digit)
+# %m = month in number (eg: 12)
+ # %B = full month name (eg: December)sho
+# %b = short month name (eg: Dec)
+# %d = day in numbers, with leading zeros (eg: 08)
+# %e = day in numbers, no leading zeros (eg: 8)
+# %A = full weekday name (eg: Sunday)
+# %a = short weekday name (eg: Sun)
+# %H = hours in 24-clock, with leading zeros
+# %k = hours in 24-clock, no leading zeros
+# %l = hours in 12-clock, with leading zeros
+# %p = am/pm
+# %T = time in 24-hour notation (%H:%M:%S)
+
+# PREFIX ? : list-keys, display key bindings
+
+# In command-prompt: show-options -g shows the global options
+# In command-prompt: show-window-options -g shows the global windows options
+
+# How do I know which tmux version I am running?
+# tmux -V
+
+# How to set bindings that don't need the prefix?
+# bind -n .. or
+# bind -T root ..
+
+# Changelog: https://github.com/tmux/tmux/blob/master/CHANGES
+
+# style colors: default, black, red, green, yellow, blue, magenta, cyan, white,
+# colour0-colour255, hexdecimal RGB string '#ffffff'
+# Use $SCRIPTS/bash/256-colors.sh to figure out the color number you want
+# style attributes: none, bold/bright, dim, underscore, blink, reverse, hidden,
+# or italics
+
+# https://www.reddit.com/r/tmux/comments/3paqoi/tmux_21_has_been_released/cw552qd
+
+# tmux buffers
+# PREFIX # : List all paste buffers
+# PREFIX - : Delete the most recently copied buffer of text
+# PREFIX = : Choose which buffer to paste interactively from a list
+# PREFIX ] : Paste the most recently copied buffer of text
+
+# How to start a temporary tmux server in addition to an existing running one?
+# > tmux -L temp
+
+# In a shell environment in a terminal in tmux, the env var $TMUX will be
+# defined to something like "/tmp/tmux-23273/default,31101,0". Outside tmux,
+# $TMUX will be undefined.
+
+# Notation to address a specific pane
+# SESSION_NAME:WINDOW_INDEX.PANE_NUMBER (Example: foo:2.1 i.e. Pane 1 in Window 2 of Session foo)
+
+# To print a message containing tmux variable values to stdout use '-p' option in display-message
+# tmux display-message -p '#{session_name}:#{window_name}.#{pane_index}', or
+# tmux display -p '#{session_name}:#{window_name}.#{pane_index}'
diff --git a/regress/conf/b9f0ce1976ec62ec60dc5da7dd92c160.conf b/regress/conf/b9f0ce1976ec62ec60dc5da7dd92c160.conf
new file mode 100644
index 00000000..0a878369
--- /dev/null
+++ b/regress/conf/b9f0ce1976ec62ec60dc5da7dd92c160.conf
@@ -0,0 +1,84 @@
+# none of these attempts worked, to bind keys, except sometimes during the sesssion. Oh well.
+# I thought maybe that was because F1 is handled differently in a console than in X, but
+# even just C-1 didnt work. Using just "a" or "x" as the key did, but not yet sure why not "C-".
+#bind-key -T root C-1 attach-session -t$0
+#But this one works now, only picks the wrong one? Mbe need2understand what "$1" or $0 mean, better,
+#but with the stub maybe this doesn't matter:
+bind-key "`" switch-client -t$1
+
+new-session #$0, stub, for keystroke convenience
+
+#$1 for root
+new-session #a stub I guess, where keyboard convenience is concerned
+new-window
+send-keys -l pgup
+send-keys Enter
+send-keys -l "less /root/.tmux.conf &"
+send-keys -l "echo; echo; echo Put something here for ssa or just run manly?"
+send-keys Enter
+new-window
+new-window
+new-window sul #for lcall, like man pages
+send-keys -l "man tmux&"
+send-keys Enter
+select-window -t :=1
+
+#$2 for om, so, can do C-b C-s 2 to get to the session, then C-b <#s> to get ~"tabs"
+new-session sula ; send-keys -l q #0
+send-keys Enter Escape Escape
+new-window sula ; send-keys -l q #1
+send-keys Enter Escape Escape
+new-window sula ; send-keys -l q #2
+send-keys Enter Escape Enter Enter
+new-window sula ; send-keys q #3, to start:
+send-keys Enter Escape
+# %%need a sleep here & .. ?
+send-keys Enter Enter Enter Enter
+new-window sula ; send-keys -l q #4
+send-keys Enter Escape Escape
+new-window sula
+new-window sula
+new-window sula
+new-window sula
+new-window sula
+select-window -t :=2
+select-window -t :=3
+
+#$3 for email (mutt)
+new-session sula
+new-window sula ; send-keys mutt Enter
+#nah, probly betr not?:
+#send-keys -l z
+#send-keys -l "thepassifdecide"
+#send-keys Enter
+new-window sula ; send-keys mutt Enter
+send-keys -l "c!=sent"
+send-keys Enter
+new-window sula ; send-keys -l "cd mail/config; less mailsig.txt&"
+send-keys Enter
+send-keys "less macros&"
+send-keys Enter
+select-window -t :=1
+
+#$4 for lacall-net: links etc
+new-session suln
+new-window suln
+#send-keys -l "lkslfx" #; et; links ksl.com"
+#send-keys asdafdfadfadfadfadf
+#%%does opening links break subsequent cmds? With this Enter, the switch-client etc dont work:
+#send-keys Enter
+#send-keys Space Space Space
+new-window suln
+new-window suln
+select-window -t :=1
+#send-keys Space Space Space
+
+#$5 for lacall-secnet, links?:
+#new-session sulsn
+
+# then, where to start:
+#%%need a sleep here, or ck a debug thing?
+switch-client -t"$0"
+send-keys -l "sleep 2"
+send-keys Enter
+switch-client -t$2
diff --git a/regress/conf/d0040b2e097f1e3d31d78eed6ce8d461.conf b/regress/conf/d0040b2e097f1e3d31d78eed6ce8d461.conf
new file mode 100644
index 00000000..3ae7444a
--- /dev/null
+++ b/regress/conf/d0040b2e097f1e3d31d78eed6ce8d461.conf
@@ -0,0 +1,108 @@
+# Put the status bar on top
+#set -g status-position "top"
+
+# Basic colours, safer for dumb terminals.
+#set -g status-style "bg=white,fg=black"
+#set -g status-right-style "bg=green,fg=black"
+#set -g window-status-current-style "bg=yellow,fg=black"
+#set -g message-style "bg=white,fg=black"
+#set -g window-status-activity-style "fg=blue"
+#set -g window-status-bell-style "fg=red"
+
+## Moar colours! Not recommended if attaching from dumber terminals with 8 or 16 colours.
+#set -g default-terminal "tmux-256color"
+# A more compatible XTERM var.
+set -g default-terminal "screen-256color"
+set -g message-style "bg=#485548 fg=#ffffff"
+set -g pane-border-style "fg=#424954"
+set -g pane-active-border-style "fg=#ffffff"
+set -g status-style "bg=#424954 fg=#ffffff"
+set -g status-right-style "bg=#303338 fg=colour87"
+set -g window-status-current-style "bg=#303338"
+set -g window-status-last-style "bg=#364146"
+set -g window-status-format ' #I:#W#[fg=colour201]#F '
+set -g window-status-current-format ' #[fg=colour226]#I#[fg=#ffffff]:#[fg=colour119]#W#[fg=colour202]#F '
+set -g window-status-separator ""
+
+# Uncomment and reload settings for sanity in a console with 8 colours.
+#set -g status-style "bg=white,fg=black"
+#set -g window-status-last-style "bg=white"
+
+# Might help when graphical characters used for vertical and horizontal lines are drawn as x and q.
+#set-option -ga terminal-overrides ',*:enacs@:smacs@:rmacs@:acsc@'
+
+# Count panes starting from 1.
+set -g base-index 1
+
+# With this you set the window name in the status line.
+# Beware of outrageous prompts, such as the default one in RHEL 7.
+set -g set-titles on
+# Let status right consists of only the pane title (removes date and time).
+# Usually shows current path.
+set -g status-right ' #T '
+# Increase the default length of 40.
+set -g status-right-length 80
+
+# Scroll up with the mouse.
+set -g mouse
+
+# Clipboard integration, use this in tandem with the recommended xterm settings.
+set -g set-clipboard on
+# Pass through modifier keys, xterm style. You'll want this in vim.
+set -g xterm-keys on
+# Reduce time to wait for Escape key. You'll want this for neovim.
+set-option escape-time 40
+# Leave ESC alone...
+#set-option -s escape-time 0
+
+# New-style mouse scroll (>2.1)
+bind -n WheelUpPane select-pane -t= \; copy-mode -e \; send-keys -M
+bind -n WheelDownPane select-pane -t= \; send-keys -M
+
+# This is for scrolling up with the terminal using keys, but has issues...
+#set -ga terminal-overrides ',xterm*:smcup@:rmcup@'
+
+# 10x more history.
+set -g history-limit 20000
+
+# Swap the default Control-b with Control-s which usually stops the output in a shell.
+unbind C-b
+set-option -g terminal-overrides "xterm-rightclick:krightclick=^[[29~"
+set -g prefix C-s
+bind C-s send-prefix
+
+# For renumbering windows when you get gaps in numbering.
+bind R \
+ move-window -r\; \
+ display-message "Windows reordered..."
+
+# My shortcuts.
+#bind-key -n C-S-t new-window # Doesn't work :-/
+bind-key -n C-t new-window
+bind-key -n C-PgUp prev
+bind-key -n C-PgDn next
+#bind-key -n C-S-PgUp swap-window -t -1 # Doesn't work :-/
+#bind-key -n C-S-PgDn swap-window -t +1 # Doesn't work :-/
+bind-key -n C-S-Left swap-window -t -1
+bind-key -n C-S-Right swap-window -t +1
+bind-key -n M-` select-window -t 0
+bind-key -n M-1 select-window -t 1
+bind-key -n M-2 select-window -t 2
+bind-key -n M-3 select-window -t 3
+bind-key -n M-4 select-window -t 4
+bind-key -n M-5 select-window -t 5
+bind-key -n M-6 select-window -t 6
+bind-key -n M-7 select-window -t 7
+bind-key -n M-8 select-window -t 8
+bind-key -n M-9 select-window -t 9
+bind-key -n M-0 select-window -t 10
+
+# switch panes without prefix using Alt-arrow
+bind -n M-Left select-pane -L
+bind -n M-Right select-pane -R
+bind -n M-Up select-pane -U
+bind -n M-Down select-pane -D
+
+# join pane from inputted window (horizontally or vertically)
+#bind-key @ command-prompt -p "join pane from:" "join-pane -s ':%%' -h"
+bind-key @ command-prompt -p "join pane from:" "join-pane -s ':%%' -v"
diff --git a/regress/conf/d2e576f947e108eb9903679b65c81fbc.conf b/regress/conf/d2e576f947e108eb9903679b65c81fbc.conf
new file mode 100644
index 00000000..392a69f0
--- /dev/null
+++ b/regress/conf/d2e576f947e108eb9903679b65c81fbc.conf
@@ -0,0 +1,198 @@
+### GENERAL
+
+set-option -g prefix C-a # Set prefix to <C-a>
+bind a send-prefix # Send <C-a> with <C-a>a
+
+bind R source-file ~/.tmux.conf \; display "~/.tmux.conf reloaded"
+bind -n M-R source-file ~/.tmux.conf \; display "~/.tmux.conf reloaded"
+
+set -g history-limit 10000 # lines to keep in hisoty
+set-option -g display-panes-time 3000 # Timeout for pane-numbering in ms
+bind -n M-q display-panes
+set-option -sg escape-time 0 # speed up commands
+set -g mouse on # enable mouse (tmux 2.1+)
+set -g base-index 1 # start window numbering at 1
+set -g pane-base-index 1 # start pane numbering at 1
+set -g renumber-windows on # renumber windows automatically
+setw -g automatic-rename on # rename window after process
+
+# Clear window name before renaming
+bind , rename-window "" \; command-prompt "rename-window '%%'"
+
+#### APPEARANCE
+
+set -g default-terminal "screen-256color" # use 256 colors
+setw -g aggressive-resize on # resize window to smallest client
+
+set -g pane-border-style fg=colour238 # border color for inactive panes
+set -g pane-active-border-style fg=colour247 # border color for active panes
+
+# Status bar colors and format
+setw -g window-status-format ' #[fg=#999999]#I #[fg=$666666]#W '
+setw -g window-status-current-format '#[fg=#ffffff] #I #W#[fg=#ffffff] '
+setw -g window-status-separator '#[fg=#292929]|#[fg=default]'
+set -g status-bg default # background color for status bar
+set -g status-position bottom # put status bar on top or bottom
+set -g status-interval 2 # interval in s to update status
+set -g status-justify left # horizontal alignment
+set -g message-style fg=white,bg=black # appearance of status messages
+set -g message-command-style fg=white # appearance of status message cmds
+
+# Left section of status bar
+set -g status-left ""
+
+# Status bar visibility
+set -g status off
+bind -r -n M-t set status on
+bind -r -n M-T set status off
+bind t set status on
+bind T set status off
+
+# Right section of status bar
+if-shell 'uname | grep -qi Darwin' "set -g status-right \"#[fg=#81a2be]#(/usr/local/bin/mpc | head -n 1 | sed 's/volume.*$//') #[fg=cyan]#(~/bin/battery-osx) #(~/bin/mailstatus.sh) #[fg=yellow]#(uptime|sed 's/.* //') #[fg=#666666]%F #[fg=#bababa]%R\""
+
+if-shell 'uname | grep -qi Linux' "set -g status-right \"#[fg=cyan]#(~/bin/battery-linux) #(~/bin/mailstatus.sh) #[fg=yellow]#(cat /proc/loadavg|awk '{print $1;}') #[fg=#666666]%F #[fg=#bababa]%R\""
+
+# Scaling of status-bar sections
+set -g status-right-length 40
+
+
+#### NAVIGATION
+
+# With C-a prefix
+bind h select-pane -L # navigate left with <C-a>h
+bind j select-pane -D # navigate down with <C-a>j
+bind k select-pane -U # navigate up with <C-a>k
+bind l select-pane -R # navigate right with <C-a>l
+bind -r H resize-pane -L 5 # resize pane left with <C-a>H
+bind -r J resize-pane -D 5 # resize pane down with <C-a>J
+bind -r K resize-pane -U 5 # resize pane up with <C-a>K
+bind -r L resize-pane -R 5 # resize pane right with <C-a>L
+
+# Navigate panes with Meta (alt) modifier + hjkl
+bind -r -n M-h select-pane -L # navigate left with M-h
+bind -r -n M-j select-pane -D # navigate down with M-j
+bind -r -n M-k select-pane -U # navigate up with M-k
+bind -r -n M-l select-pane -R # navigate right with M-l
+bind -r -n M-H resize-pane -L 5 # resize pane left with M-H
+bind -r -n M-J resize-pane -D 5 # resize pane down with M-J
+bind -r -n M-K resize-pane -U 5 # resize pane up with M-K
+bind -r -n M-L resize-pane -R 5 # resize pane right with M-L
+
+# Navigate windows with Meta (alt) modifier + number keys
+bind -n M-1 select-window -t :=1
+bind -n M-2 select-window -t :=2
+bind -n M-3 select-window -t :=3
+bind -n M-4 select-window -t :=4
+bind -n M-5 select-window -t :=5
+bind -n M-6 select-window -t :=6
+bind -n M-7 select-window -t :=7
+bind -n M-8 select-window -t :=8
+bind -n M-9 select-window -t :=9
+bind -n M-0 select-window -t :=10
+
+bind C-s last-window # go to last window with <C-a><C-s>
+bind C-a last-pane # go to last pane with <C-a><C-a>
+bind -n M-s last-window # go to last pane with M-s
+bind -n M-a last-pane # go to last pane with M-a
+bind -r n next-window # next window with <C-a>n
+bind -r b previous-window # next window with <C-a>p
+
+bind -n -r M-n next-window # next window with <M-n>
+bind -n -r M-b previous-window # previous window with <M-n>
+#bind -n M-, run-shell "tmux list-panes -as -F \"##I.##P ##{pane_current_command} . #{pane_current_path} (#W)#F\" | fzf-tmux | cut -d \" \" -f 1 | xargs tmux select-pane -t"
+bind -n M-, run-shell "tmux list-windows -F \"##I:##W\" | fzf-tmux | cut -d \":\" -f 1 | xargs tmux select-window -t"
+bind -n M-. run-shell "tmux list-sessions -F \"##S\" | fzf-tmux | xargs tmux switch -t"
+
+
+#### LAYOUT CHANGING BINDINGS
+
+# create panes in same directory
+bind '"' split-window -c "#{pane_current_path}"
+bind '%' split-window -h -c "#{pane_current_path}"
+
+bind -r z resize-pane -Z # toggle pane zoom with <C-a>z
+bind -r y next-layout # cycle to next pane layout with <C-a>y
+bind -r Y previous-layout # cycle to previous pane layout with <C-a>Y
+bind -r r rotate-window # rotate panes with <C-a>r
+
+bind -n M-z resize-pane -Z # toggle pane zoom with <M-z>
+bind -n -r M-y next-layout # cycle to next pane layout with <M-y>
+bind -n -r M-Y previous-layout # cycle to previous pane layout with <M-Y>
+bind -n -r M-r rotate-window # rotate panes with <M-r>
+
+bind -r Left swap-window -t -1 # Swap window left
+bind -r Right swap-window -t +1 # Swap window right
+
+bind -r B swap-window -t -1 # Swap window left
+bind -r N swap-window -t +1 # Swap window right
+bind -n -r M-B swap-window -t -1 # Swap window left
+bind -n -r M-N swap-window -t +1 # Swap window right
+
+#### CLIPBOARD
+
+# enable reattach-to-user-namespace which fixes pasteboard access and launchctl
+bind Space copy-mode # enter copy mode with <C-a><Space>
+bind -n M-u copy-mode # enter copy mode with M-u
+bind -T copy-mode-vi M-u send -X halfpage-up # scroll up with M-u
+bind -T copy-mode-vi M-d send -X halfpage-down # scroll down with M-d
+bind -T copy-mode-vi v send -X begin-selection # start "visual" with v
+
+# Copy (yank) with y
+if-shell 'uname | grep -qi Linux && which xclip > /dev/null' 'bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "DISPLAY=:0 xclip -i -sel clipboard"'
+if-shell 'uname | grep -qi Darwin' 'bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "pbcopy"'
+if-shell 'uname | grep -qi Cygwin' 'bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "cat > /dev/clipboard"'
+
+# Paste with C-a p or M-p
+if-shell 'uname | grep -qi Linux && which xclip > /dev/null' 'bind p run "DISPLAY=:0 xclip -o | tmux load-buffer - ; tmux paste-buffer"'
+if-shell 'uname | grep -qi Darwin && which reattach-to-user-namespace > /dev/null' 'bind p run "pbpaste | tmux load-buffer - ; tmux paste-buffer"'
+if-shell 'uname | grep -qi Darwin' 'bind -n M-p run "pbpaste | tmux load-buffer - ; tmux paste-buffer"'
+if-shell 'uname | grep -qi Cygwin' 'bind p run "cat /dev/clipboard | tmux load-buffer - ; tmux paste-buffer"'
+if-shell 'uname | grep -qi Cygwin' 'bind -n M-p run "cat /dev/clipboard | tmux load-buffer - ; tmux paste-buffer"'
+
+
+#### LAUNCH PROCESSES
+
+# use urlview to follow URLs in current pane
+bind u capture-pane -J \; \
+ save-buffer "/tmp/active_tmux_buffer" \; \
+ delete-buffer \; \
+ split-window -l 10 "urlview '/tmp/active_tmux_buffer' && rm /tmp/active_tmux_buffer"
+
+# Launch offlineimap in inactive splits
+bind o split-window -p 25 '$SHELL -c "offlineimap -qf INBOX"' \; select-pane -l
+bind O split-window -p 25 '$SHELL -c "offlineimap"' \; select-pane -l
+
+# Use nested bindings (<C-a>l) for grouping process launch bindings
+bind -n C-M-v new-window -n vim "/usr/local/bin/vim"
+bind -n C-M-w new-window -n weather \
+ "curl 'wttr.in/?m'; echo -e '\nPress <enter> to quit'; read -n 1 -s"
+
+# Open new window and resize status accordingly (should be a hook instead)
+bind Enter new-window -c "#{pane_current_path}" "$SHELL"
+bind -n M-Enter new-window \
+ "tmux set status-right-length `echo $(tput cols)/2|bc|tr -d '\n'`; zsh"
+
+# Use nested bindings (<C-a>m) for grouping music-control bindings
+bind m switchc -Tmpd
+bind -n M-m switchc -Tmpd
+bind -Tmpd v new-window -n vimpc "vimpc"
+bind -Tmpd p display "#(mpc toggle | tr '\n' ' ')"
+bind -Tmpd s display "#(mpc stop | tr '\n' ' ')"
+bind -Tmpd n display "#(mpc next | tr '\n' ' ')"
+bind -Tmpd b display "#(mpc prev | tr '\n' ' ')"
+bind -Tmpd r display "#(mpc clear && mpc ls | mpc add && mpc random on && mpc play | tr '\n' ' ')"
+#bind -Tmpd r new-window -n mpc "mpc clear && mpc ls | mpc add && mpc shuffle && mpc play"
+
+bind -n C-M-p display "#(mpc toggle | tr '\n' ' ')"
+bind -n C-M-s display "#(mpc stop | tr '\n' ' ')"
+bind -n C-M-n display "#(mpc next | tr '\n' ' ')"
+bind -n C-M-b display "#(mpc prev | tr '\n' ' ')"
+#bind -n C-M-r display "#(mpc clear && mpc ls | mpc add && mpc random on && mpc play | tr '\n' ' ')"
+bind -n C-M-a split-window -p 50 "source ~/code/fzf-mpd/fzf-mpd.zsh && fm"
+
+# fzf-locate from entire file system and insert result in current pane (Alt-`)
+bind -n 'M-`' run "tmux split-window -p 40 'tmux send-keys -t #{pane_id} \"$(locate / | fzf -m | paste -sd\\ -)\"'"
+
+# Change to the previous pane, repeat the last command, change back
+bind -n M-! last-pane \; send-keys C-p C-m \; last-pane
diff --git a/regress/conf/d41d8cd98f00b204e9800998ecf8427e.conf b/regress/conf/d41d8cd98f00b204e9800998ecf8427e.conf
new file mode 100644
index 00000000..79bcdb5d
--- /dev/null
+++ b/regress/conf/d41d8cd98f00b204e9800998ecf8427e.conf
@@ -0,0 +1,148 @@
+set-option -g prefix C-a
+unbind-key C-b
+bind-key C-a send-prefix
+
+set-option -s set-clipboard on
+set -sg escape-time 0
+set -g bell-action other
+set -g lock-after-time 1800
+set -g lock-command 'tput civis && read -s -n1'
+set -g history-limit 10000
+set -g default-terminal "screen-256color"
+set -g pane-border-style fg=white,bg=default
+set -g pane-active-border-style fg=red,bg=default
+set -g repeat-time 100
+set -g terminal-overrides "xterm*:kLFT5=\eOD:kRIT5=\eOC:kUP5=\eOA:kDN5=\eOB:smkx@:rmkx@:Tc"
+
+#set -g terminal-overrides '*88col*:colors=88,*256col*:colors=256,rxvt-uni*:Tc:XT:Ms=\E]52;%p1%s;%p2%s\007:Cc=\E]12;%p1%s\007:Cr=\E]12;green\007:Cs=\E]777;Cs;%p1%d\007'
+set -g mouse on
+set -g status-style bg=blue,fg=cyan
+
+set-hook -g alert-bell 'run -b "notify-send \"Bell in session #{session_name}:#{window_index}:#{window_name}\""'
+
+unbind-key /
+unbind-key c
+unbind-key d
+unbind-key f
+unbind-key i
+unbind-key l
+unbind-key n
+unbind-key o
+unbind-key p
+unbind-key r
+unbind-key s
+unbind-key t
+unbind-key w
+unbind-key x
+unbind-key |
+unbind-key -
+unbind-key A
+unbind-key S
+unbind-key .
+unbind-key "'"
+unbind-key '#'
+unbind-key ' '
+unbind-key z
+unbind-key ^z
+
+bind a send-prefix
+bind c new-window -a -c '#{pane_current_path}'
+bind d detach-client
+bind "/" command-prompt "find-window '%%'"
+bind i display-message
+bind a last-window
+bind n next-window
+bind o select-pane -D
+bind p previous-window
+bind r respawn-window
+bind s choose-tree -Z
+bind t clock-mode
+bind w choose-window
+bind k confirm-before kill-pane
+bind x set lock-command '/usr/bin/vlock' \; lock-client \; set lock-command 'tput civis && read -s -n1'
+bind "|" split-window -v -c '#{pane_current_path}'
+bind "-" split-window -h -c '#{pane_current_path}'
+bind l command-prompt "rename-window '%%'"
+bind S command-prompt "rename-session '%%'"
+bind . display-panes
+bind "'" command-prompt -p "SSH: " "new-window -n %1 'ssh %1'"
+bind ' ' choose-window
+bind z resize-pane -Z
+
+bind ^a last-window
+bind ^c new-window -a -c '#{pane_current_path}'
+bind ^d detach-client
+bind ^i display-message
+bind a last-window
+bind ^n next-window
+bind ^o select-pane -D
+bind ^p previous-window
+bind ^r respawn-window
+bind ^s choose-session
+bind ^t clock-mode
+bind ^w choose-window
+bind ^k confirm-before kill-pane
+bind ^x lock-client
+bind ^S command-prompt "rename-session '%%'"
+bind ^z resize-pane -Z
+
+bind -n C-Left previous-window
+bind -n C-Right next-window
+bind -n C-s set status
+
+bind -r C-Left swapw -t:-
+bind -r C-Right swapw -t:+
+
+# Status stuff.
+set -g status-left-style "fg=white, bg=magenta"
+set -g status-left-length 30
+set -g status-left "#S "
+set -g status-right-length 30
+set -g status-right-fg white
+set -g status-right-bg blue
+set -g status-right "#{?client_prefix,#[reverse][^a]#[noreverse],}[%a %d/%m %H:%M]"
+set -g display-panes-time 4000
+set -g window-status-bell-style reverse
+
+#setw -g window-status-current-fg white
+#setw -g window-status-current-bg colour34
+setw -g mode-keys vi
+
+setw -g window-status-separator "| "
+#setw -g window-status-format "#[bg=blue]#I:#W:#{window_flags}#[bg=default]"
+#setw -g window-status-current-format "#[fg=black,bg=green]#I:#W:#{window_flags}"
+
+setw -g window-status-format "#[bg=blue]#I:#W:#{?window_linked,+#{window_flags},#{window_flags} }#[bg=default]"
+setw -g window-status-current-format "#[fg=black,bg=green]#I:#W:#{?window_linked,+#{window_flags},#{window_flags}}"
+
+set-window-option -g clock-mode-colour green
+
+# Sessions
+new -d -sspecial
+new -d -swork -d -nmutt 'exec neomutt'
+neww -d
+neww -d
+neww -d
+neww -d
+
+# FIXME -- the entire block below is required for taskwarrior.
+#new -d -stask -ntask -x237 -y 79
+#selectl -ttask tiled
+#set -ttask status off
+#splitw -ttask:task
+#splitw -ttask:task
+#splitw -ttask:task
+#splitw -ttask:task
+#splitw -ttask:task
+#selectl -ttask:task 4ada,237x79,0,0[237x67,0,0{156x67,0,0,5,80x67,157,0[80x27,157,0,19,80x22,157,28,20,80x16,157,51,21]},237x11,0,68,22]
+#send -ttask:task.0 'cyclenext list' 'C-m'
+#send -ttask:task.1 'clear ; tasksh' 'C-m'
+#send -ttask:task.2 'cyclenext summary' 'C-m'
+#send -ttask:task.3 'cyclenext burndown.daily' 'C-m'
+#send -ttask:task.4 'cyclenext ghistory.monthly' 'C-m'
+#selectp -ttask:task.1
+#linkw -stask:task -twork
+#set -t task:task remain-on-exit on
+
+set -t work:irc remain-on-exit on
+set -t work:mutt remain-on-exit on
diff --git a/regress/conf/dfd579a114a8366b5a665c264e29c084.conf b/regress/conf/dfd579a114a8366b5a665c264e29c084.conf
new file mode 100644
index 00000000..7ad12c95
--- /dev/null
+++ b/regress/conf/dfd579a114a8366b5a665c264e29c084.conf
@@ -0,0 +1,52 @@
+set -as terminal-overrides '\e\r\n\t\u12ab\U000012ab'
+set -as terminal-overrides "\e\r\n\t\u12ab\U000012ab"
+
+# format #{abc #{def}}
+# abc
+
+set -g status-left \
+"\u007c \
+abc"
+
+%if #{TMUX}
+set -g status-bg red
+%endif
+
+X=1
+Y=2 set -g status-bg blue; Z=3 set -g status-bg magenta
+
+set -g status-left "~/abcdef"$HOME # abcdef
+
+%if #{l:1} set -g status-bg red %endif
+
+%if #{l:0}
+X=1
+%elif #{l:1}
+Y=1
+%if #{l:0}
+Y=2
+%else
+Y=3
+%endif
+%endif
+
+bind x display-message \"hello\"
+
+bind c neww -c ~
+bind ';' lsk
+
+set -g status-left "a""b"
+set -g status-left ~
+
+set -g status-left 'a $HOME b ~ c \e\e\e'
+set -g status-left "a $HOME b ~ c \e\e\e"
+
+set -s command-alias[99] "foo=lsk;neww"
+bind-key -n C-s if-shell 'true' 'display-message hello'
+
+set -g status-left-style \
+bg=red
+set -g status-left \\\
+abc
+
+set -g status-left 'xyz' ; %if #{l:1} set -g status-bg red %endif ; bind x lsk
diff --git a/regress/conf/e2661d67d0d45a8647fb95de76ec8174.conf b/regress/conf/e2661d67d0d45a8647fb95de76ec8174.conf
new file mode 100644
index 00000000..79f46df1
--- /dev/null
+++ b/regress/conf/e2661d67d0d45a8647fb95de76ec8174.conf
@@ -0,0 +1,78 @@
+# Scott Rochford's tmux configuration
+#
+# change the prefix to the GNU screen default (avoids clash with page up in vi)
+set -g prefix C-a
+unbind-key C-b
+bind-key C-a send-prefix
+# toggle sending input to all panes
+bind-key b set-window-option synchronize-panes
+# alternative to ',' which doesn't pre-fill the prompt with the existing name
+bind-key < command-prompt "rename-window '%%'"
+
+# Disabled all of these in favour of changing 'default-command' below.
+#bind-key C-p pipe-pane -o 'cat >>~/tmux_logs/output.$(echo #I-#P-#W-#T | sed "s/[^[:alnum:].-]/_/g")' \; display-message 'Toggled logging'
+# From http://unix.stackexchange.com/questions/5832/is-there-an-equivalent-of-gnu-screens-log-command-in-tmux
+# bind-key H pipe-pane -o "exec cat >>$HOME/'#W-tmux.log'" \; display-message 'Toggled logging to $HOME/#W-tmux.log'
+#bind-key H pipe-pane "exec cat >>$HOME/'#W-tmux.log'" \; display-message 'Started logging to $HOME/#W-tmux.log'
+#bind-key h pipe-pane \; display-message 'Ended logging to $HOME/#W-tmux.log'
+
+#set -g utf8 on
+
+set-option -g history-limit 32768
+
+# no longer available in 2.2
+#set-option -g mouse-select-pane on
+#set-option -g mouse-select-window on
+set-option -g mouse on
+
+# increase the amount of time status bar messages are displayed for (default 1000 I think)
+set-option -g display-time 1500
+# unfortunately this seems to have no effect in putty :-(
+set-option -g set-clipboard on
+set-option -g default-command 'tmux pipe-pane -o "cat >>~/tmux_logs/output-`date +%Y%m%d-%H%M%S-$$`" ; /bin/ksh -l'
+#
+# allow yank into system clipboard
+# from http://stackoverflow.com/questions/17255031/how-to-copy-from-tmux-running-in-putty-to-windows-clipbard
+#
+# for some reason this is wrapping at 80 cols, using save- instead of show- helps
+# -b for background is needed because xclip continues to run to service the clipboard paste reqeusts until the
+# clipboard buffer is replaced with some new contents
+#bind C-y run-shell -b "tmux save-buffer - | DISPLAY=$(<~/.xdisplay) xclip -selection clipboard -in && tmux display-message 'xclipped successfully'"
+bind C-y save-buffer ~/etc/clipboard.pipe
+#
+# this was just for testing, but interestingly for some reason tmux-show-buffer >/tmp/t never terminates, writing to a pipe works fine??
+#bind C-z run-shell "tmux show-buffer | cat >/tmp/t"
+# move x clipboard into tmux paste buffer
+#bind C-p run-shell -b "xclip -o -selection clipboard | tmux load-buffer - ; tmux paste-buffer"
+bind C-p run-shell "DISPLAY=$(<~/.xdisplay) xclip -o -selection clipboard | tmux load-buffer - ; tmux paste-buffer"
+
+# switch to last-but-one window (like prefix-l but last, last)
+# only works on tmux-2.4 + with Nicholas Marriott's patch from my feature request, unless it reached mainline....
+#bind k run-shell "tmux select-window -t $(tmux list-windows -F '#{session_stack}' | awk -F, '{print $3;exit}END{print $1}')"
+bind k run-shell "tmux select-window -t $(echo #{session_stack} | awk -F, '{w=$1}NF>=3{w=$3;exit}END{print w}')"
+
+# switch to oldest window (for clean-up), not sure why brackets are required around (NF) here...
+bind K run-shell "tmux select-window -t $(echo #{session_stack} | awk -F, '{print $(NF)}')"
+
+# prompt for hosts to connect to, open a new synchronized window with horizontally split panes for each host, supports brace expansion
+bind N command-prompt -p hosts: 'run-shell -b "bash -c \"~/lbin/nw %% >/dev/null\""'
+
+# seems to cause unexpected resizes when focussing on putty :-(
+#set-option mouse-resize-pane on
+
+#05:59 < Celti> annihilannic: I believe the #{pane_in_mode} format does what you want
+#05:59 < Celti> put it in your statusline
+#05:59 < Celti> annihilannic: No, my mistake, I should have read farther down, you want #{pane_synchronized}
+# only works in tmux 2.0?, higher than 1.6.3 anyawy
+set-option -g window-status-format ' #I:#W#F#{?pane_synchronized,S,}'
+#set-option -g window-status-current-format ' #I:#W#{?pane_synchronized,[sync],}#F'
+# to highlight in red when sync is on... not sure why I did this with set-window-option instead of set-option, perhaps
+# both work?
+set-window-option -g window-status-current-format "#{?pane_synchronized,#[bg=red],}#{?window_zoomed_flag,#[bg=yellow],} #I:#W#F#{?pane_synchronized,S,}"
+#
+# also only in 2.0? if I use this, don't need #F in window-status-*-format? - actually, nah,
+# still useful for showing [Z]oomed, or - last active, etc.
+set-option -g window-status-current-style bg=blue
+
+# Toggle input on a pane (from Thomas Sattler)
+bind-key R if -F '#{pane_input_off}' "select-pane -e; select-pane -P fg=default" "select-pane -d; select-pane -P fg=yellow" \ No newline at end of file
diff --git a/regress/conf/ed08995f38b5a3079262a88d2563abe4.conf b/regress/conf/ed08995f38b5a3079262a88d2563abe4.conf
new file mode 100644
index 00000000..a0fd1500
--- /dev/null
+++ b/regress/conf/ed08995f38b5a3079262a88d2563abe4.conf
@@ -0,0 +1,283 @@
+#---------------------------------------------------------------------------#
+# .tmux.conf
+# Helmut K. C. Tessarek, Last update 2018-10-16
+#---------------------------------------------------------------------------#
+
+#---------------------------------------------------------------------------#
+# set prefix key to ctrl+a / ctrl-b is used in vi for going back one page
+#---------------------------------------------------------------------------#
+unbind C-b
+set -g prefix C-a
+
+#---------------------------------------------------------------------------#
+# send the prefix to client inside window (nested sessions)
+#---------------------------------------------------------------------------#
+bind-key a send-prefix
+
+#---------------------------------------------------------------------------#
+# toggle last window like screen
+#---------------------------------------------------------------------------#
+bind-key C-a last-window
+
+#---------------------------------------------------------------------------#
+# start window indexing at one instead of zero
+#---------------------------------------------------------------------------#
+#set -g base-index 1
+
+#---------------------------------------------------------------------------#
+# default terminal - we want 256 colors !!!
+#---------------------------------------------------------------------------#
+set -g default-terminal "screen-256color"
+
+#---------------------------------------------------------------------------#
+# on-screen time for status messages in ms
+#---------------------------------------------------------------------------#
+set -g display-time 2000
+
+#---------------------------------------------------------------------------#
+# on-screen time for display-panes in ms
+#---------------------------------------------------------------------------#
+set -g display-panes-time 2000
+
+#---------------------------------------------------------------------------#
+# color for display pane indicator
+#---------------------------------------------------------------------------#
+set -g display-panes-colour "cyan"
+#set -g display-panes-active-colour "#0087ff"
+#set -g display-panes-active-colour "red"
+
+#---------------------------------------------------------------------------#
+# open a man page in new window
+#---------------------------------------------------------------------------#
+unbind m
+bind m command-prompt "split-window 'exec man %%'"
+
+#---------------------------------------------------------------------------#
+# quick view of processes
+#---------------------------------------------------------------------------#
+#bind '~' split-window "exec htop"
+
+#---------------------------------------------------------------------------#
+# scrollback buffer n lines
+#---------------------------------------------------------------------------#
+set -g history-limit 5000
+
+#---------------------------------------------------------------------------#
+# toggle status bar
+#---------------------------------------------------------------------------#
+unbind b
+bind-key b set-option status
+
+#---------------------------------------------------------------------------#
+# resize panes like vim
+# feel free to change the "1" to however many lines you want to resize by,
+# only one at a time can be slow
+#---------------------------------------------------------------------------#
+unbind <
+unbind >
+unbind -
+unbind +
+bind -r < resize-pane -L 1
+bind -r > resize-pane -R 1
+bind -r - resize-pane -D 1
+bind -r + resize-pane -U 1
+
+#---------------------------------------------------------------------------#
+# toggle mouse helpers
+#---------------------------------------------------------------------------#
+unbind Enter
+unbind C-m
+bind C-m set-option mouse \; display-message 'mouse -> #{?mouse,on,off}'
+
+#---------------------------------------------------------------------------#
+# Reload config file
+#---------------------------------------------------------------------------#
+unbind R
+bind-key R source-file ~/.tmux.conf \; display-message "Reloading configuration done"
+
+#---------------------------------------------------------------------------#
+# start ssh session in new window
+#---------------------------------------------------------------------------#
+unbind S
+bind-key S command-prompt "new-window -n %1 'ssh %1'"
+
+#---------------------------------------------------------------------------#
+# start new session
+#---------------------------------------------------------------------------#
+unbind C
+bind-key C command-prompt "new-session -s %1"
+
+#---------------------------------------------------------------------------#
+# Keys to switch session
+#---------------------------------------------------------------------------#
+bind Q switchc -t0
+bind W switchc -t compile
+bind E switchc -t config
+
+#---------------------------------------------------------------------------#
+# break pane in background
+#---------------------------------------------------------------------------#
+unbind '@'
+bind '@' break-pane -d
+
+#---------------------------------------------------------------------------#
+# join pane with target window
+#---------------------------------------------------------------------------#
+unbind ^
+bind ^ command-prompt "join-pane -t %1"
+
+#---------------------------------------------------------------------------#
+# move around panes with hjkl, as one would in vim after pressing ctrl-w
+#---------------------------------------------------------------------------#
+#bind h select-pane -L
+#bind j select-pane -D
+#bind k select-pane -U
+#bind l select-pane -R
+
+#---------------------------------------------------------------------------#
+# bind : to command-prompt like vim
+# this is the default in tmux already
+#---------------------------------------------------------------------------#
+bind : command-prompt
+
+#---------------------------------------------------------------------------#
+# Remain on exit
+#---------------------------------------------------------------------------#
+#setw -g remain-on-exit on
+
+#---------------------------------------------------------------------------#
+# vi-style controls for copy mode
+#---------------------------------------------------------------------------#
+setw -g mode-keys vi
+
+#---------------------------------------------------------------------------#
+# Make mouse useful in copy mode
+#---------------------------------------------------------------------------#
+#setw -g mode-mouse on
+
+#---------------------------------------------------------------------------#
+# More straight forward key bindings for splitting
+#---------------------------------------------------------------------------#
+unbind %
+unbind v
+#bind | split-window -h
+bind v split-window -h
+unbind '"'
+unbind h
+#bind - split-window -v
+bind h split-window -v
+
+#---------------------------------------------------------------------------#
+# Synchronize panes
+#---------------------------------------------------------------------------#
+unbind y
+bind y set-window-option synchronize-panes \; display-message 'synchronize-panes -> #{?synchronize-panes,on,off}'
+
+#---------------------------------------------------------------------------#
+# Other key codes: Tab, BTab, Escape
+#---------------------------------------------------------------------------#
+
+#---------------------------------------------------------------------------#
+# Clock
+#---------------------------------------------------------------------------#
+setw -g clock-mode-colour green
+setw -g clock-mode-style 24
+
+#---------------------------------------------------------------------------#
+# Terminal emulator window title
+#---------------------------------------------------------------------------#
+set -g set-titles on
+set -g set-titles-string '#S:#I.#P #W'
+
+#---------------------------------------------------------------------------#
+# Status Bar
+#---------------------------------------------------------------------------#
+set -g status-bg black
+set -g status-fg white
+set -g status-interval 1
+set -g status-left-length 30
+set -g status-left '#[fg=green]#h#[default] '
+#set -g status-right '#[fg=yellow]#(cut -d " " -f 1-4 /proc/loadavg)#[default] #[fg=cyan,bold]%Y-%m-%d %H:%M:%S#[default]'
+#set -g status-right '#[fg=yellow,bold]%Y-%m-%d %H:%M#[default]'
+set -g status-right '#[fg=yellow]%Y-%m-%d %H:%M %Z#[default]'
+#set -g status-justify center
+#set -g status-keys vi
+
+set -g allow-rename off
+setw -g automatic-rename on
+
+#---------------------------------------------------------------------------#
+# Highlighting the active window in status bar
+#---------------------------------------------------------------------------#
+#setw -g window-status-current-bg red
+set-option -g window-status-format "#I:#W#F#{?pane_synchronized,S,}"
+set-window-option -g window-status-current-format "#{?pane_synchronized,#[bg=red],}#{?window_zoomed_flag,#[bg=colour130],}#I:#W#F#{?pane_synchronized,S,}"
+set-option -g window-status-current-style bg=blue
+
+#---------------------------------------------------------------------------#
+# global update environment
+#---------------------------------------------------------------------------#
+set -g update-environment "DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY TZ"
+
+#---------------------------------------------------------------------------#
+# settings for AIX
+# terminal overrides to enable colors
+# set default terminal to vt100 or xterm (screen does not exist on AIX)
+#---------------------------------------------------------------------------#
+if-shell "uname|grep AIX" 'set -g terminal-overrides "xterm*:XT,xterm*:setab=\\E[4%p1%dm,xterm*:setaf=\\E[3%p1%dm"'
+#if-shell "uname|grep AIX" "set -g default-terminal vt100"
+if-shell "uname|grep AIX" "set -g default-terminal xterm"
+
+#---------------------------------------------------------------------------#
+# settings for macOS
+#---------------------------------------------------------------------------#
+if-shell "uname|grep Darwin" 'set -g default-command "/bin/bash -l"'
+
+#---------------------------------------------------------------------------#
+# Pane coloring
+# set inactive/active window styles
+#---------------------------------------------------------------------------#
+set -g window-style "fg=colour247,bg=colour234"
+set -g window-active-style "fg=colour250,bg=black"
+set -g @TPCS "1"
+
+#---------------------------------------------------------------------------#
+# pane border - different style / use cyan
+#---------------------------------------------------------------------------#
+#set -g pane-border-bg colour235
+#set -g pane-border-fg colour238
+#set -g pane-active-border-bg colour234
+#set -g pane-active-border-fg colour51
+
+#---------------------------------------------------------------------------#
+# toggle pane coloring on/off
+#---------------------------------------------------------------------------#
+unbind C-b
+bind C-b if -F '#{@TPCS}' \
+ 'set -g window-style "fg=default,bg=default" ; set -g window-active-style "fg=default,bg=default" ; set -g @TPCS "0"; display-message "Pane coloring -> off"' \
+ 'set -g window-style "fg=colour247,bg=colour234" ; set -g window-active-style "fg=colour250,bg=black" ; set -g @TPCS "1"; display-message "Pane coloring -> on"'
+
+#---------------------------------------------------------------------------#
+# List of plugins
+#---------------------------------------------------------------------------#
+set -g @plugin 'tmux-plugins/tpm'
+#set -g @plugin 'tmux-plugins/tmux-sensible'
+set -g @plugin 'tmux-plugins/tmux-resurrect'
+set -g @plugin 'tmux-plugins/tmux-logging'
+
+set -g @resurrect-capture-pane-contents 'on'
+set -g @resurrect-save-bash-history 'on'
+
+set -g @logging-path $HOME
+set -g @screen-capture-path $HOME
+set -g @save-complete-history-path $HOME
+
+# Other examples:
+# set -g @plugin 'github_username/plugin_name'
+# set -g @plugin 'git@github.com/user/plugin'
+# set -g @plugin 'git@bitbucket.com/user/plugin'
+
+#---------------------------------------------------------------------------#
+# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
+#---------------------------------------------------------------------------#
+run '~/.tmux/plugins/tpm/tpm'
diff --git a/regress/control-client-sanity.sh b/regress/control-client-sanity.sh
new file mode 100644
index 00000000..bf76b4d5
--- /dev/null
+++ b/regress/control-client-sanity.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+OUT=$(mktemp)
+trap "rm -f $TMP $OUT" 0 1 15
+
+$TMUX -f/dev/null new -d -x200 -y200 || exit 1
+$TMUX -f/dev/null splitw || exit 1
+sleep 1
+cat <<EOF|$TMUX -C a >$TMP
+selectp -t%0
+splitw
+neww
+splitw
+selectp -t%0
+killp -t%1
+swapp -t%2 -s%3
+neww
+splitw
+splitw
+selectl tiled
+killw
+EOF
+sleep 1
+$TMUX has || exit 1
+$TMUX lsp -aF '#{pane_id} #{window_layout}' >$TMP || exit 1
+cat <<EOF|cmp -s $TMP - || exit 1
+%0 f5ab,200x200,0,0[200x50,0,0,0,200x149,0,51,3]
+%3 f5ab,200x200,0,0[200x50,0,0,0,200x149,0,51,3]
+%2 dcbd,200x200,0,0[200x100,0,0,2,200x99,0,101,4]
+%4 dcbd,200x200,0,0[200x100,0,0,2,200x99,0,101,4]
+EOF
+$TMUX kill-server 2>/dev/null
+
+exit 0
diff --git a/regress/control-client-size.sh b/regress/control-client-size.sh
new file mode 100644
index 00000000..5847ede3
--- /dev/null
+++ b/regress/control-client-size.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+# 947
+# size in control mode should change after refresh-client -C, and -x and -y
+# should work without -d for control clients
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+OUT=$(mktemp)
+trap "rm -f $TMP $OUT" 0 1 15
+
+$TMUX -f/dev/null new -d || exit 1
+sleep 1
+cat <<EOF|$TMUX -C a >$TMP
+ls -F':#{window_width} #{window_height}'
+refresh -C 100,50
+ls -F':#{window_width} #{window_height}'
+EOF
+grep ^: $TMP >$OUT
+printf ":80 24\n:100 50\n"|cmp -s $OUT - || exit 1
+$TMUX kill-server 2>/dev/null
+
+$TMUX -f/dev/null new -d || exit 1
+sleep 1
+cat <<EOF|$TMUX -f/dev/null -C a >$TMP
+ls -F':#{window_width} #{window_height}'
+refresh -C 80,24
+ls -F':#{window_width} #{window_height}'
+EOF
+grep ^: $TMP >$OUT
+printf ":80 24\n:80 24\n"|cmp -s $OUT - || exit 1
+$TMUX kill-server 2>/dev/null
+
+cat <<EOF|$TMUX -f/dev/null -C new -x 100 -y 50 >$TMP
+ls -F':#{window_width} #{window_height}'
+refresh -C 80,24
+ls -F':#{window_width} #{window_height}'
+EOF
+grep ^: $TMP >$OUT
+printf ":100 50\n:80 24\n"|cmp -s $OUT - || exit 1
+$TMUX kill-server 2>/dev/null
+
+exit 0
diff --git a/regress/cursor-test.txt b/regress/cursor-test.txt
new file mode 100644
index 00000000..67ed52c8
--- /dev/null
+++ b/regress/cursor-test.txt
@@ -0,0 +1,6 @@
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
+incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
+commodo consequat. Duis aute
+irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat
+nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia
+deserunt mollit anim id est laborum.
diff --git a/regress/cursor-test1.result b/regress/cursor-test1.result
new file mode 100644
index 00000000..71b9a4b6
--- /dev/null
+++ b/regress/cursor-test1.result
@@ -0,0 +1,33 @@
+14 8 t
+0 ud exercitation ullamco laboris nisi ut
+1 aliquip ex ea
+2 commodo consequat. Duis aute
+3 irure dolor in reprehenderit in voluptat
+4 e velit esse cillum dolore eu fugiat
+5 nulla pariatur. Excepteur sint occaecat
+6 cupidatat non proident, sunt in culpa qu
+7 i officia
+8 deserunt mollit anim id est laborum.
+9
+4 6 t
+0 cupidatat
+1 non proide
+2 nt, sunt i
+3 n culpa qu
+4 i officia
+5 deserunt m
+6 ollit anim
+7 id est la
+8 borum.
+9
+14 8 t
+0 incididunt ut labore et dolore magna aliqua. Ut en
+1 im ad minim veniam, quis nostrud exercitation ulla
+2 mco laboris nisi ut aliquip ex ea
+3 commodo consequat. Duis aute
+4 irure dolor in reprehenderit in voluptate velit es
+5 se cillum dolore eu fugiat
+6 nulla pariatur. Excepteur sint occaecat cupidatat
+7 non proident, sunt in culpa qui officia
+8 deserunt mollit anim id est laborum.
+9
diff --git a/regress/cursor-test1.sh b/regress/cursor-test1.sh
new file mode 100644
index 00000000..2dc20539
--- /dev/null
+++ b/regress/cursor-test1.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -f/dev/null -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+$TMUX -f/dev/null new -d -x40 -y10 \
+ "cat cursor-test.txt; printf '\e[9;15H'; cat" || exit 1
+$TMUX set -g window-size manual || exit 1
+
+$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
+$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
+$TMUX resizew -x10 || exit 1
+$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
+$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
+$TMUX resizew -x50 || exit 1
+$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
+$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
+
+cmp -s $TMP cursor-test1.result || exit 1
+
+$TMUX kill-server 2>/dev/null
+exit 0
diff --git a/regress/cursor-test2.result b/regress/cursor-test2.result
new file mode 100644
index 00000000..dc005d2b
--- /dev/null
+++ b/regress/cursor-test2.result
@@ -0,0 +1,33 @@
+9 7 a
+0 cupidatat
+1 non proide
+2 nt, sunt i
+3 n culpa qu
+4 i officia
+5 deserunt m
+6 ollit anim
+7 id est la
+8 borum.
+9
+4 6 a
+0 icia
+1 deser
+2 unt m
+3 ollit
+4 anim
+5 id e
+6 st la
+7 borum
+8 .
+9
+29 8 a
+0 incididunt ut labore et dolore magna aliqua. Ut en
+1 im ad minim veniam, quis nostrud exercitation ulla
+2 mco laboris nisi ut aliquip ex ea
+3 commodo consequat. Duis aute
+4 irure dolor in reprehenderit in voluptate velit es
+5 se cillum dolore eu fugiat
+6 nulla pariatur. Excepteur sint occaecat cupidatat
+7 non proident, sunt in culpa qui officia
+8 deserunt mollit anim id est laborum.
+9
diff --git a/regress/cursor-test2.sh b/regress/cursor-test2.sh
new file mode 100644
index 00000000..9791f567
--- /dev/null
+++ b/regress/cursor-test2.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+$TMUX -f/dev/null new -d -x10 -y10 \
+ "cat cursor-test.txt; printf '\e[8;10H'; cat" || exit 1
+$TMUX set -g window-size manual || exit 1
+
+$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
+$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
+$TMUX resizew -x5 || exit 1
+$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
+$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
+$TMUX resizew -x50 || exit 1
+$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
+$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
+
+cmp -s $TMP cursor-test2.result || exit 1
+
+$TMUX kill-server 2>/dev/null
+exit 0
diff --git a/regress/cursor-test3.result b/regress/cursor-test3.result
new file mode 100644
index 00000000..e72b1a9b
--- /dev/null
+++ b/regress/cursor-test3.result
@@ -0,0 +1,9 @@
+6 1 b
+0 abcdefa
+1 bcdefab
+3 1 b
+0 fabcd
+1 efab
+6 1 b
+0 abcdefa
+1 bcdefab
diff --git a/regress/cursor-test3.sh b/regress/cursor-test3.sh
new file mode 100644
index 00000000..8bb4bd6f
--- /dev/null
+++ b/regress/cursor-test3.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+$TMUX -f/dev/null new -d -x7 -y2 \
+ "printf 'abcdefabcdefab'; printf '\e[2;7H'; cat" || exit 1
+$TMUX set -g window-size manual || exit 1
+
+$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
+$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
+$TMUX resizew -x5 || exit 1
+$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
+$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
+$TMUX resizew -x7 || exit 1
+$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
+$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
+
+cmp -s $TMP cursor-test3.result || exit 1
+
+$TMUX kill-server 2>/dev/null
+exit 0
diff --git a/regress/cursor-test4.result b/regress/cursor-test4.result
new file mode 100644
index 00000000..db26e4fa
--- /dev/null
+++ b/regress/cursor-test4.result
@@ -0,0 +1,16 @@
+0 1
+0 abcdef
+1
+2
+0 1
+0 abcdef
+1
+2
+0 1
+0 def
+1
+2
+0 1
+0 abcdef
+1
+2
diff --git a/regress/cursor-test4.sh b/regress/cursor-test4.sh
new file mode 100644
index 00000000..2bf1bb0e
--- /dev/null
+++ b/regress/cursor-test4.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+$TMUX -f/dev/null new -d -x10 -y3 "printf 'abcdef\n'; cat" || exit 1
+$TMUX set -g window-size manual || exit 1
+
+$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
+$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
+$TMUX resizew -x20 || exit 1
+$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
+$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
+$TMUX resizew -x3 || exit 1
+$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
+$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
+$TMUX resizew -x10 || exit 1
+$TMUX display -pF '#{cursor_x} #{cursor_y} #{cursor_character}' >>$TMP
+$TMUX capturep -p|awk '{print NR-1,$0}' >>$TMP
+
+cmp -s $TMP cursor-test4.result || exit 1
+
+$TMUX kill-server 2>/dev/null
+exit 0
diff --git a/regress/format-strings.sh b/regress/format-strings.sh
new file mode 100644
index 00000000..726b46bc
--- /dev/null
+++ b/regress/format-strings.sh
@@ -0,0 +1,183 @@
+#!/bin/sh
+
+# Tests of formats as described in tmux(1) FORMATS
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+
+# test_format $format $expected_result
+test_format()
+{
+ fmt="$1"
+ exp="$2"
+
+ out=$($TMUX display-message -p "$fmt")
+
+ if [ "$out" != "$exp" ]; then
+ echo "Format test failed for '$fmt'."
+ echo "Expected: '$exp'"
+ echo "But got '$out'"
+ exit 1
+ fi
+}
+
+# test_conditional_with_pane_in_mode $format $exp1 $exp2
+#
+# Tests the format string $format to yield $exp1 if #{pane_in_mode} is true and
+# $exp2 when #{pane_in_mode} is false.
+test_conditional_with_pane_in_mode()
+{
+ fmt="$1"
+ exp_true="$2"
+ exp_false="$3"
+
+ $TMUX copy-mode # enter copy mode
+ test_format "$fmt" "$exp_true"
+ $TMUX send-keys -X cancel # leave copy mode
+ test_format "$fmt" "$exp_false"
+}
+
+# test_conditional_with_session_name #format $exp_summer $exp_winter
+#
+# Tests the format string $format to yield $exp_summer if the session name is
+# 'Summer' and $exp_winter if the session name is 'Winter'.
+test_conditional_with_session_name()
+{
+ fmt="$1"
+ exp_summer="$2"
+ exp_winter="$3"
+
+ $TMUX rename-session "Summer"
+ test_format "$fmt" "$exp_summer"
+ $TMUX rename-session "Winter"
+ test_format "$fmt" "$exp_winter"
+ $TMUX rename-session "Summer" # restore default
+}
+
+
+$TMUX kill-server 2>/dev/null
+$TMUX -f/dev/null new-session -d || exit 1
+$TMUX rename-session "Summer" || exit 1 # used later in conditionals
+
+# Plain string without substitutions et al
+test_format "abc xyz" "abc xyz"
+
+# Test basic escapes for "#", "{", "#{" "}", "#}", ","
+test_format "##" "#"
+test_format "#," ","
+test_format "{" "{"
+test_format "##{" "#{"
+test_format "#}" "}"
+test_format "###}" "#}" # not a "basic" one but interesting nevertheless
+
+# Simple expansion
+test_format "#{pane_in_mode}" "0"
+
+# Simple conditionals
+test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,xyz}" "abc" "xyz"
+
+# Expansion in conditionals
+test_conditional_with_pane_in_mode "#{?pane_in_mode,#{session_name},xyz}" "Summer" "xyz"
+
+# Basic escapes in conditionals
+# First argument
+test_conditional_with_pane_in_mode "#{?pane_in_mode,##,xyz}" "#" "xyz"
+test_conditional_with_pane_in_mode "#{?pane_in_mode,#,,xyz}" "," "xyz"
+test_conditional_with_pane_in_mode "#{?pane_in_mode,{,xyz}" "{" "xyz"
+test_conditional_with_pane_in_mode "#{?pane_in_mode,##{,xyz}" "#{" "xyz"
+test_conditional_with_pane_in_mode "#{?pane_in_mode,#},xyz}" "}" "xyz"
+# not a "basic" one but interesting nevertheless
+test_conditional_with_pane_in_mode "#{?pane_in_mode,###},xyz}" "#}" "xyz"
+# Second argument
+test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,##}" "abc" "#"
+test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,#,}" "abc" ","
+test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,{}" "abc" "{"
+test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,##{}" "abc" "#{"
+test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,#}}" "abc" "}"
+# not a "basic" one but interesting nevertheless
+test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,###}}" "abc" "#}"
+# mixed
+test_conditional_with_pane_in_mode "#{?pane_in_mode,{,#}}" "{" "}"
+test_conditional_with_pane_in_mode "#{?pane_in_mode,#},{}" "}" "{"
+test_conditional_with_pane_in_mode "#{?pane_in_mode,##{,###}}" "#{" "#}"
+test_conditional_with_pane_in_mode "#{?pane_in_mode,###},##{}" "#}" "#{"
+
+# Conditionals split on the second comma (this is not documented)
+test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,xyz,bonus}" "abc" "xyz,bonus"
+
+# Curly brackets {...} do not capture a comma inside of conditionals as the
+# conditional ends on the first '}'
+test_conditional_with_pane_in_mode "#{?pane_in_mode,{abc,xyz},bonus}" "{abc,bonus}" "xyz,bonus}"
+
+# Substitutions '#{...}' capture the comma
+# invalid format: #{abc,xyz} is not a known variable name.
+#test_conditional_with_pane_in_mode "#{?pane_in_mode,#{abc,xyz},bonus}" "" "bonus"
+
+# Parenthesis (...) do not captura a comma
+test_conditional_with_pane_in_mode "#{?pane_in_mode,(abc,xyz),bonus}" "(abc" "xyz),bonus"
+test_conditional_with_pane_in_mode "#{?pane_in_mode,(abc#,xyz),bonus}" "(abc,xyz)" "bonus"
+
+# Brackets [...] do not captura a comma
+test_conditional_with_pane_in_mode "#{?pane_in_mode,[abc,xyz],bonus}" "[abc" "xyz],bonus"
+test_conditional_with_pane_in_mode "#{?pane_in_mode,[abc#,xyz],bonus}" "[abc,xyz]" "bonus"
+
+
+# Escape comma inside of #(...)
+# Note: #() commands are run asynchronous and are substituted with result of the
+# *previous* run or a placeholder (like "<'echo ,' not ready") if the command
+# has not been run before. The format is updated as soon as the command
+# finishes. As we are printing the message only once it never gets updated
+# and the displayed message is "<'echo ,' not ready>"
+test_format "#{?pane_in_mode,#(echo #,),xyz}" "xyz"
+test_conditional_with_pane_in_mode "#{?pane_in_mode,#(echo #,),xyz}" "<'echo ,' not ready>" "xyz"
+# This caching does not work :-(
+#$TMUX display-message -p "#(echo #,)" > /dev/null
+#test_conditional_with_pane_in_mode "#{?pane_in_mode,#(echo #,),xyz}" "," "xyz"
+#test_conditional_with_pane_in_mode "#{?pane_in_mode,#(echo #,),xyz}" "," "xyz"
+
+# invalid format: '#(' is not closed in the first argument of #{?,,}.
+#test_conditional_with_pane_in_mode "#{?pane_in_mode,#(echo ,),xyz}" "" "),xyz"
+
+# Escape comma inside of #[...]
+test_conditional_with_pane_in_mode "#{?pane_in_mode,#[fg=default#,bg=default]abc,xyz}" "#[fg=default,bg=default]abc" "xyz"
+# invalid format: '#[' is not closed in the first argument of #{?,,}
+#test_conditional_with_pane_in_mode "#{?pane_in_mode,#[fg=default,bg=default]abc,xyz}" "" "bg=default]abc,xyz"
+
+# Conditionals with comparison
+test_conditional_with_session_name "#{?#{==:#{session_name},Summer},abc,xyz}" "abc" "xyz"
+# Conditionals with comparison and escaped commas
+$TMUX rename-session ","
+test_format "#{?#{==:#,,#{session_name}},abc,xyz}" "abc"
+$TMUX rename-session "Summer" # reset to default
+
+# Conditional in conditional
+test_conditional_with_pane_in_mode "#{?pane_in_mode,#{?#{==:#{session_name},Summer},ABC,XYZ},xyz}" "ABC" "xyz"
+test_conditional_with_session_name "#{?pane_in_mode,#{?#{==:#{session_name},Summer},ABC,XYZ},xyz}" "xyz" "xyz"
+
+test_conditional_with_pane_in_mode "#{?pane_in_mode,abc,#{?#{==:#{session_name},Summer},ABC,XYZ}}" "abc" "ABC"
+test_conditional_with_session_name "#{?pane_in_mode,abc,#{?#{==:#{session_name},Summer},ABC,XYZ}}" "ABC" "XYZ"
+
+# Some fancy stackings
+test_conditional_with_pane_in_mode "#{?#{==:#{?pane_in_mode,#{session_name},#(echo Spring)},Summer},abc,xyz}" "abc" "xyz"
+
+
+
+# Format test for the literal option
+# Note: The behavior for #{l:...} with escapes is sometimes weird as #{l:...}
+# respects the escapes.
+test_format "#{l:#{}}" "#{}"
+test_format "#{l:#{pane_in_mode}}" "#{pane_in_mode}"
+test_format "#{l:#{?pane_in_mode,#{?#{==:#{session_name},Summer},ABC,XYZ},xyz}}" "#{?pane_in_mode,#{?#{==:#{session_name},Summer},ABC,XYZ},xyz}"
+
+# With escapes (which escape but are returned literally)
+test_format "#{l:##{}" "##{"
+test_format "#{l:#{#}}}" "#{#}}"
+
+# Invalid formats:
+#test_format "#{l:#{}" ""
+#test_format "#{l:#{#}}" ""
+
+exit 0
diff --git a/regress/has-session-return.sh b/regress/has-session-return.sh
new file mode 100644
index 00000000..5cc30f05
--- /dev/null
+++ b/regress/has-session-return.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+# 971
+# has-session should return 1 on error
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+$TMUX -f/dev/null has -tfoo </dev/null 2>/dev/null && exit 1
+$TMUX -f/dev/null start\; has -tfoo </dev/null 2>/dev/null && exit 1
+$TMUX -f/dev/null new -d\; has -tfoo </dev/null 2>/dev/null && exit 1
+$TMUX -f/dev/null new -dsfoo\; has -tfoo </dev/null 2>/dev/null || exit 1
+$TMUX kill-server 2>/dev/null
+
+exit 0
diff --git a/regress/if-shell-TERM.sh b/regress/if-shell-TERM.sh
new file mode 100644
index 00000000..5967a58f
--- /dev/null
+++ b/regress/if-shell-TERM.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+# 882
+# TERM should come from outside tmux for if-shell from the config file
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+cat <<EOF >$TMP
+if '[ "\$TERM" = "xterm" ]' \
+ 'set -g default-terminal "vt220"' \
+ 'set -g default-terminal "ansi"'
+EOF
+
+TERM=xterm $TMUX -f$TMP new -d "echo \"#\$TERM\" >>$TMP" || exit 1
+sleep 1 && [ "$(tail -1 $TMP)" = "#vt220" ] || exit 1
+
+TERM=screen $TMUX -f$TMP new -d "echo \"#\$TERM\" >>$TMP" || exit 1
+sleep 1 && [ "$(tail -1 $TMP)" = "#ansi" ] || exit 1
+
+$TMUX has 2>/dev/null && exit 1
+
+exit 0
diff --git a/regress/if-shell-error.sh b/regress/if-shell-error.sh
new file mode 100644
index 00000000..24dc578e
--- /dev/null
+++ b/regress/if-shell-error.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# 883
+# if-shell with an error should not core :-)
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+cat <<EOF >$TMP
+if 'true' 'wibble wobble'
+EOF
+
+$TMUX -f$TMP new -d || exit 1
+sleep 1
+E=$($TMUX display -p '#{pane_in_mode}')
+$TMUX kill-server 2>/dev/null
+[ "$E" = "1" ] || exit 1
+
+exit 0
diff --git a/regress/if-shell-nested.sh b/regress/if-shell-nested.sh
new file mode 100644
index 00000000..976c6738
--- /dev/null
+++ b/regress/if-shell-nested.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# 882
+# tmux inside if-shell itself should work
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+cat <<EOF >$TMP
+if '$TMUX run "true"' 'set -s @done yes'
+EOF
+
+TERM=xterm $TMUX -f$TMP new -d "$TMUX show -vs @done >>$TMP" || exit 1
+sleep 1 && [ "$(tail -1 $TMP)" = "yes" ] || exit 1
+
+$TMUX has 2>/dev/null && exit 1
+
+exit 0
diff --git a/regress/kill-session-process-exit.sh b/regress/kill-session-process-exit.sh
new file mode 100644
index 00000000..69ee27a2
--- /dev/null
+++ b/regress/kill-session-process-exit.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+# when we kill a session, processes running in it should be killed
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+$TMUX -f/dev/null new -d 'sleep 1000' || exit 1
+P=$($TMUX display -pt0:0.0 '#{pane_pid}')
+$TMUX -f/dev/null new -d || exit 1
+sleep 1
+$TMUX kill-session -t0:
+sleep 1
+kill -0 $P 2>/dev/null && exit 1
+$TMUX kill-server 2>/dev/null
+
+exit 0
diff --git a/regress/new-session-base-index.sh b/regress/new-session-base-index.sh
new file mode 100644
index 00000000..337037c3
--- /dev/null
+++ b/regress/new-session-base-index.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# new session base-index
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+cat <<EOF >$TMP
+set -g base-index 100
+new
+set base-index 200
+neww
+EOF
+
+$TMUX -f$TMP start
+echo $($TMUX lsw -F'#{window_index}') >$TMP
+(echo "100 200"|cmp -s - $TMP) || exit 1
+$TMUX kill-server 2>/dev/null
+
+exit 0
diff --git a/regress/new-session-command.sh b/regress/new-session-command.sh
new file mode 100644
index 00000000..02ba55d9
--- /dev/null
+++ b/regress/new-session-command.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# new session command
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+cat <<EOF >$TMP
+new sleep 101
+new -- sleep 102
+new "sleep 103"
+EOF
+
+$TMUX -f$TMP start
+[ $($TMUX ls|wc -l) -eq 3 ] || exit 1
+$TMUX kill-server 2>/dev/null
+
+exit 0
diff --git a/regress/new-session-environment.sh b/regress/new-session-environment.sh
new file mode 100644
index 00000000..d53f204e
--- /dev/null
+++ b/regress/new-session-environment.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+# new session environment
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+OUT=$(mktemp)
+SCRIPT=$(mktemp)
+trap "rm -f $TMP $OUT $SCRIPT" 0 1 15
+
+cat <<EOF >$SCRIPT
+(
+echo TERM=\$TERM
+echo PWD=\$(pwd)
+echo PATH=\$PATH
+echo SHELL=\$SHELL
+echo TEST=\$TEST
+) >$OUT
+EOF
+
+cat <<EOF >$TMP
+new -- /bin/sh $SCRIPT
+EOF
+
+(cd /; env -i TERM=ansi TEST=test1 PATH=1 SHELL=/bin/sh \
+ $TMUX -f$TMP start) || exit 1
+sleep 1
+(cat <<EOF|cmp -s - $OUT) || exit 1
+TERM=screen
+PWD=/
+PATH=1
+SHELL=/bin/sh
+TEST=test1
+EOF
+
+(cd /; env -i TERM=ansi TEST=test2 PATH=2 SHELL=/bin/sh \
+ $TMUX -f$TMP new -d -- /bin/sh $SCRIPT) || exit 1
+sleep 1
+(cat <<EOF|cmp -s - $OUT) || exit 1
+TERM=screen
+PWD=/
+PATH=2
+SHELL=/bin/sh
+TEST=test2
+EOF
+
+(cd /; env -i TERM=ansi TEST=test3 PATH=3 SHELL=/bin/sh \
+ $TMUX -f/dev/null new -d source $TMP) || exit 1
+sleep 1
+(cat <<EOF|cmp -s - $OUT) || exit 1
+TERM=screen
+PWD=/
+PATH=2
+SHELL=/bin/sh
+TEST=test2
+EOF
+
+$TMUX kill-server 2>/dev/null
+
+exit 0
diff --git a/regress/new-session-no-client.sh b/regress/new-session-no-client.sh
new file mode 100644
index 00000000..88c064cd
--- /dev/null
+++ b/regress/new-session-no-client.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# 869
+# new with no client (that is, from the config file) should imply -d and
+# not attach
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+cat <<EOF >$TMP
+new -stest
+EOF
+
+$TMUX -f$TMP start || exit 1
+sleep 1 && $TMUX has -t=test: || exit 1
+$TMUX kill-server 2>/dev/null
+
+exit 0
diff --git a/regress/new-session-size.sh b/regress/new-session-size.sh
new file mode 100644
index 00000000..89fc580d
--- /dev/null
+++ b/regress/new-session-size.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# new-session without clients should be the right size
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+$TMUX -f/dev/null new -d </dev/null || exit 1
+sleep 1
+$TMUX ls -F "#{window_width} #{window_height}" >$TMP
+printf "80 24\n"|cmp -s $TMP - || exit 1
+$TMUX kill-server 2>/dev/null
+
+$TMUX -f/dev/null new -d -x 100 -y 50 </dev/null || exit 1
+sleep 1
+$TMUX ls -F "#{window_width} #{window_height}" >$TMP
+printf "100 50\n"|cmp -s $TMP - || exit 1
+$TMUX kill-server 2>/dev/null
+
+exit 0
diff --git a/regress/new-window-command.sh b/regress/new-window-command.sh
new file mode 100644
index 00000000..176bffb5
--- /dev/null
+++ b/regress/new-window-command.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# new session command
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+cat <<EOF >$TMP
+new
+neww sleep 101
+neww -- sleep 102
+neww "sleep 103"
+EOF
+
+$TMUX -f$TMP start
+[ $($TMUX lsw|wc -l) -eq 4 ] || exit 1
+$TMUX kill-server 2>/dev/null
+
+exit 0
diff --git a/regress/xenl-terminal.sh b/regress/xenl-terminal.sh
new file mode 100644
index 00000000..07469ceb
--- /dev/null
+++ b/regress/xenl-terminal.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -Ltest"
+$TMUX kill-server 2>/dev/null
+TMUX2="$TEST_TMUX -Ltest2"
+$TMUX2 kill-server 2>/dev/null
+
+TMP=$(mktemp)
+trap "rm -f $TMP" 0 1 15
+
+$TMUX2 -f/dev/null new -d || exit 1
+$TMUX2 set -as terminal-overrides ',*:xenl@' || exit 1
+$TMUX2 set -g status-right 'RRR' || exit 1
+$TMUX2 set -g status-left 'LLL' || exit 1
+$TMUX2 set -g window-status-current-format 'WWW' || exit 1
+$TMUX -f/dev/null new -x20 -y2 -d "$TMUX2 attach" || exit 1
+sleep 1
+$TMUX capturep -p|tail -1 >$TMP || exit 1
+$TMUX kill-server 2>/dev/null
+$TMUX2 kill-server 2>/dev/null
+cat <<EOF|cmp -s $TMP - || exit 1
+LLLWWW RR
+EOF
+
+exit 0
diff --git a/screen.c b/screen.c
index 9db0f609..405932ef 100644
--- a/screen.c
+++ b/screen.c
@@ -21,7 +21,6 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <vis.h>
#include "tmux.h"
diff --git a/server-client.c b/server-client.c
index ee7b4c70..13d58558 100644
--- a/server-client.c
+++ b/server-client.c
@@ -23,8 +23,6 @@
#include <errno.h>
#include <event.h>
#include <fcntl.h>
-#include <imsg.h>
-#include <paths.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -1952,6 +1950,10 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
c->name = name;
log_debug("client %p name is %s", c, c->name);
+#ifdef __CYGWIN__
+ c->fd = open(c->ttyname, O_RDWR|O_NOCTTY);
+#endif
+
if (c->flags & CLIENT_CONTROL) {
close(c->fd);
c->fd = -1;
diff --git a/server-fn.c b/server-fn.c
index aa4a482b..2247f1c5 100644
--- a/server-fn.c
+++ b/server-fn.c
@@ -17,11 +17,9 @@
*/
#include <sys/types.h>
-#include <sys/queue.h>
#include <sys/wait.h>
#include <sys/uio.h>
-#include <imsg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -301,6 +299,9 @@ server_destroy_pane(struct window_pane *wp, int notify)
char tim[26];
if (wp->fd != -1) {
+#ifdef HAVE_UTEMPTER
+ utempter_remove_record(wp->fd);
+#endif
bufferevent_free(wp->event);
wp->event = NULL;
close(wp->fd);
diff --git a/server.c b/server.c
index e75b02da..a5d5e37f 100644
--- a/server.c
+++ b/server.c
@@ -26,7 +26,6 @@
#include <errno.h>
#include <event.h>
#include <fcntl.h>
-#include <paths.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/session.c b/session.c
index be9c8e07..eddafa2c 100644
--- a/session.c
+++ b/session.c
@@ -19,7 +19,6 @@
#include <sys/types.h>
#include <sys/time.h>
-#include <paths.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
diff --git a/spawn.c b/spawn.c
index 6cf7c73b..51e4ae78 100644
--- a/spawn.c
+++ b/spawn.c
@@ -19,12 +19,10 @@
#include <sys/types.h>
#include <errno.h>
-#include <paths.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <util.h>
#include "tmux.h"
@@ -435,6 +433,15 @@ spawn_pane(struct spawn_context *sc, char **cause)
_exit(1);
complete:
+#ifdef HAVE_UTEMPTER
+ if (~new_wp->flags & PANE_EMPTY) {
+ xasprintf(&cp, "tmux(%lu).%%%u", (long)getpid(), new_wp->id);
+ utempter_add_record(new_wp->fd, cp);
+ kill(getpid(), SIGCHLD);
+ free(cp);
+ }
+#endif
+
new_wp->pipe_off = 0;
new_wp->flags &= ~PANE_EXITED;
diff --git a/tmux.1 b/tmux.1
index ef288e5a..2a9aeabe 100644
--- a/tmux.1
+++ b/tmux.1
@@ -23,7 +23,7 @@
.Sh SYNOPSIS
.Nm tmux
.Bk -words
-.Op Fl 2Cluv
+.Op Fl 2CluvV
.Op Fl c Ar shell-command
.Op Fl f Ar file
.Op Fl L Ar socket-name
@@ -124,7 +124,7 @@ Specify an alternative configuration file.
By default,
.Nm
loads the system configuration file from
-.Pa /etc/tmux.conf ,
+.Pa @SYSCONFDIR@/tmux.conf ,
if present, then looks for a user configuration file at
.Pa ~/.tmux.conf .
.Pp
@@ -210,6 +210,11 @@ signal may be sent to the
server process to toggle logging between on (as if
.Fl v
was given) and off.
+.It Fl V
+Report the
+.Nm
+version.
+.Pp
.It Ar command Op Ar flags
This specifies one of a set of commands used to control
.Nm ,
@@ -4273,6 +4278,7 @@ The following variables are available, where appropriate:
.It Li "pane_at_top" Ta "" Ta "1 if pane is at the top of window"
.It Li "pane_bottom" Ta "" Ta "Bottom of pane"
.It Li "pane_current_command" Ta "" Ta "Current command if available"
+.It Li "pane_current_path" Ta "" Ta "Current path if available"
.It Li "pane_dead" Ta "" Ta "1 if pane is dead"
.It Li "pane_dead_status" Ta "" Ta "Exit status of process in dead pane"
.It Li "pane_format" Ta "" Ta "1 if format is for a pane"
@@ -4328,6 +4334,7 @@ The following variables are available, where appropriate:
.It Li "session_windows" Ta "" Ta "Number of windows in session"
.It Li "socket_path" Ta "" Ta "Server socket path"
.It Li "start_time" Ta "" Ta "Server start time"
+.It Li "version" Ta "" Ta "Server version"
.It Li "window_active" Ta "" Ta "1 if window active"
.It Li "window_active_clients" Ta "" Ta "Number of clients viewing this window"
.It Li "window_active_clients_list" Ta "" Ta "List of clients viewing this window"
@@ -5424,12 +5431,12 @@ and
options.
.El
.Sh FILES
-.Bl -tag -width "/etc/tmux.confXXX" -compact
+.Bl -tag -width "@SYSCONFDIR@/tmux.confXXX" -compact
.It Pa ~/.tmux.conf
Default
.Nm
configuration file.
-.It Pa /etc/tmux.conf
+.It Pa @SYSCONFDIR@/tmux.conf
System-wide configuration file.
.El
.Sh EXAMPLES
diff --git a/tmux.c b/tmux.c
index fe2647f5..c8a5a44e 100644
--- a/tmux.c
+++ b/tmux.c
@@ -19,19 +19,16 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <err.h>
#include <errno.h>
#include <event.h>
#include <fcntl.h>
#include <langinfo.h>
#include <locale.h>
-#include <paths.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
-#include <util.h>
#include "tmux.h"
@@ -55,7 +52,7 @@ static __dead void
usage(void)
{
fprintf(stderr,
- "usage: %s [-2Cluv] [-c shell-command] [-f file] [-L socket-name]\n"
+ "usage: %s [-2CluvV] [-c shell-command] [-f file] [-L socket-name]\n"
" [-S socket-path] [command [flags]]\n",
getprogname());
exit(1);
@@ -238,7 +235,7 @@ main(int argc, char **argv)
flags = 0;
label = path = NULL;
- while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:uUv")) != -1) {
+ while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:uUVv")) != -1) {
switch (opt) {
case '2':
flags |= CLIENT_256COLOURS;
@@ -252,6 +249,9 @@ main(int argc, char **argv)
else
flags |= CLIENT_CONTROL;
break;
+ case 'V':
+ printf("%s %s\n", getprogname(), VERSION);
+ exit(0);
case 'f':
set_cfg_file(optarg);
break;
@@ -372,5 +372,5 @@ main(int argc, char **argv)
free(label);
/* Pass control to the client. */
- exit(client_main(event_init(), argc, argv, flags));
+ exit(client_main(osdep_event_init(), argc, argv, flags));
}
diff --git a/tmux.h b/tmux.h
index 2315f643..507f5b69 100644
--- a/tmux.h
+++ b/tmux.h
@@ -20,18 +20,20 @@
#define TMUX_H
#include <sys/time.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
+#include <sys/uio.h>
-#include <bitstring.h>
#include <event.h>
#include <limits.h>
#include <stdarg.h>
-#include <stdint.h>
#include <stdio.h>
#include <termios.h>
#include <wchar.h>
+#ifdef HAVE_UTEMPTER
+#include <utempter.h>
+#endif
+
+#include "compat.h"
#include "xmalloc.h"
extern char **environ;
@@ -2712,8 +2714,10 @@ char *utf8_padcstr(const char *, u_int);
char *utf8_rpadcstr(const char *, u_int);
int utf8_cstrhas(const char *, const struct utf8_data *);
-/* procname.c */
-char *get_proc_name(int, char *);
+/* osdep-*.c */
+char *osdep_get_name(int, char *);
+char *osdep_get_cwd(int);
+struct event_base *osdep_event_init(void);
/* log.c */
void log_add_level(void);
diff --git a/tools/24-bit-color.sh b/tools/24-bit-color.sh
new file mode 100644
index 00000000..3e91da20
--- /dev/null
+++ b/tools/24-bit-color.sh
@@ -0,0 +1,127 @@
+#!/bin/bash
+#
+# This file echoes four gradients with 24-bit color codes
+# to the terminal to demonstrate their functionality.
+# The foreground escape sequence is ^[38;2;<r>;<g>;<b>m
+# The background escape sequence is ^[48;2;<r>;<g>;<b>m
+# <r> <g> <b> range from 0 to 255 inclusive.
+# The escape sequence ^[0m returns output to default
+
+#
+# From
+# https://github.com/gnachman/iTerm2/blob/master/tests/24-bit-color.sh
+# and presumably covered by
+# https://github.com/gnachman/iTerm2/blob/master/LICENSE
+#
+
+SEQ1=
+if which gseq >/dev/null 2>&1; then
+ SEQ1=gseq
+elif seq --version|grep -q GNU; then
+ SEQ1=seq
+fi
+if [ -n "$SEQ1" ]; then
+ # GNU seq requires a -ve increment if going backwards
+ seq1()
+ {
+ if [ $1 -gt $2 ]; then
+ $SEQ1 $1 -1 $2
+ else
+ $SEQ1 $1 $2
+ fi
+ }
+ SEQ=seq1
+else
+ SEQ=seq
+fi
+SEPARATOR=':'
+
+setBackgroundColor()
+{
+ echo -en "\033[48${SEPARATOR}2${SEPARATOR}$1${SEPARATOR}$2${SEPARATOR}$3""m"
+}
+
+resetOutput()
+{
+ echo -en "\033[0m\n"
+}
+
+# Gives a color $1/255 % along HSV
+# Who knows what happens when $1 is outside 0-255
+# Echoes "$red $green $blue" where
+# $red $green and $blue are integers
+# ranging between 0 and 255 inclusive
+rainbowColor()
+{
+ let h=$1/43
+ let f=$1-43*$h
+ let t=$f*255/43
+ let q=255-t
+
+ if [ $h -eq 0 ]
+ then
+ echo "255 $t 0"
+ elif [ $h -eq 1 ]
+ then
+ echo "$q 255 0"
+ elif [ $h -eq 2 ]
+ then
+ echo "0 255 $t"
+ elif [ $h -eq 3 ]
+ then
+ echo "0 $q 255"
+ elif [ $h -eq 4 ]
+ then
+ echo "$t 0 255"
+ elif [ $h -eq 5 ]
+ then
+ echo "255 0 $q"
+ else
+ # execution should never reach here
+ echo "0 0 0"
+ fi
+}
+
+for i in `$SEQ 0 127`; do
+ setBackgroundColor $i 0 0
+ echo -en " "
+done
+resetOutput
+for i in `$SEQ 255 128`; do
+ setBackgroundColor $i 0 0
+ echo -en " "
+done
+resetOutput
+
+for i in `$SEQ 0 127`; do
+ setBackgroundColor 0 $i 0
+ echo -n " "
+done
+resetOutput
+for i in `$SEQ 255 128`; do
+ setBackgroundColor 0 $i 0
+ echo -n " "
+done
+resetOutput
+
+for i in `$SEQ 0 127`; do
+ setBackgroundColor 0 0 $i
+ echo -n " "
+done
+resetOutput
+for i in `$SEQ 255 128`; do
+ setBackgroundColor 0 0 $i
+ echo -n " "
+done
+resetOutput
+
+for i in `$SEQ 0 127`; do
+ setBackgroundColor `rainbowColor $i`
+ echo -n " "
+done
+resetOutput
+for i in `$SEQ 255 128`; do
+ setBackgroundColor `rainbowColor $i`
+ echo -n " "
+done
+resetOutput
diff --git a/tools/256colors.pl b/tools/256colors.pl
new file mode 100644
index 00000000..c97c2be9
--- /dev/null
+++ b/tools/256colors.pl
@@ -0,0 +1,63 @@
+#!/usr/bin/perl
+# Author: Todd Larason <jtl@molehill.org>
+# $XFree86: xc/programs/xterm/vttests/256colors2.pl,v 1.2 2002/03/26 01:46:43 dickey Exp $
+
+# use the resources for colors 0-15 - usually more-or-less a
+# reproduction of the standard ANSI colors, but possibly more
+# pleasing shades
+
+# colors 16-231 are a 6x6x6 color cube
+for ($red = 0; $red < 6; $red++) {
+ for ($green = 0; $green < 6; $green++) {
+ for ($blue = 0; $blue < 6; $blue++) {
+ printf("\x1b]4;%d;rgb:%2.2x/%2.2x/%2.2x\x1b\\",
+ 16 + ($red * 36) + ($green * 6) + $blue,
+ ($red ? ($red * 40 + 55) : 0),
+ ($green ? ($green * 40 + 55) : 0),
+ ($blue ? ($blue * 40 + 55) : 0));
+ }
+ }
+}
+
+# colors 232-255 are a grayscale ramp, intentionally leaving out
+# black and white
+for ($gray = 0; $gray < 24; $gray++) {
+ $level = ($gray * 10) + 8;
+ printf("\x1b]4;%d;rgb:%2.2x/%2.2x/%2.2x\x1b\\",
+ 232 + $gray, $level, $level, $level);
+}
+
+
+# display the colors
+
+# first the system ones:
+print "System colors:\n";
+for ($color = 0; $color < 8; $color++) {
+ print "\x1b[48;5;${color}m ";
+}
+print "\x1b[0m\n";
+for ($color = 8; $color < 16; $color++) {
+ print "\x1b[48;5;${color}m ";
+}
+print "\x1b[0m\n\n";
+
+# now the color cube
+print "Color cube, 6x6x6:\n";
+for ($green = 0; $green < 6; $green++) {
+ for ($red = 0; $red < 6; $red++) {
+ for ($blue = 0; $blue < 6; $blue++) {
+ $color = 16 + ($red * 36) + ($green * 6) + $blue;
+ print "\x1b[48;5;${color}m ";
+ }
+ print "\x1b[0m ";
+ }
+ print "\n";
+}
+
+
+# now the grayscale ramp
+print "Grayscale ramp:\n";
+for ($color = 232; $color < 256; $color++) {
+ print "\x1b[48;5;${color}m ";
+}
+print "\x1b[0m\n";
diff --git a/tools/UTF-8-demo.txt b/tools/UTF-8-demo.txt
new file mode 100644
index 00000000..4363f27b
--- /dev/null
+++ b/tools/UTF-8-demo.txt
@@ -0,0 +1,212 @@
+
+UTF-8 encoded sample plain-text file
+‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+
+Markus Kuhn [ˈmaʳkʊs kuːn] <http://www.cl.cam.ac.uk/~mgk25/> — 2002-07-25
+
+
+The ASCII compatible UTF-8 encoding used in this plain-text file
+is defined in Unicode, ISO 10646-1, and RFC 2279.
+
+
+Using Unicode/UTF-8, you can write in emails and source code things such as
+
+Mathematics and sciences:
+
+ ∮ E⋅da = Q, n → ∞, ∑ f(i) = ∏ g(i), ⎧⎡⎛┌─────┐⎞⎤⎫
+ ⎪⎢⎜│a²+b³ ⎟⎥⎪
+ ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β), ⎪⎢⎜│───── ⎟⎥⎪
+ ⎪⎢⎜⎷ c₈ ⎟⎥⎪
+ ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ, ⎨⎢⎜ ⎟⎥⎬
+ ⎪⎢⎜ ∞ ⎟⎥⎪
+ ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (⟦A⟧ ⇔ ⟪B⟫), ⎪⎢⎜ ⎲ ⎟⎥⎪
+ ⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪
+ 2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm ⎩⎣⎝i=1 ⎠⎦⎭
+
+Linguistics and dictionaries:
+
+ ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn
+ Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ]
+
+APL:
+
+ ((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈
+
+Nicer typography in plain text files:
+
+ ╔══════════════════════════════════════════╗
+ ║ ║
+ ║ • ‘single’ and “double” quotes ║
+ ║ ║
+ ║ • Curly apostrophes: “We’ve been here” ║
+ ║ ║
+ ║ • Latin-1 apostrophe and accents: '´` ║
+ ║ ║
+ ║ • ‚deutsche‘ „Anführungszeichen“ ║
+ ║ ║
+ ║ • †, ‡, ‰, •, 3–4, —, −5/+5, ™, … ║
+ ║ ║
+ ║ • ASCII safety test: 1lI|, 0OD, 8B ║
+ ║ ╭─────────╮ ║
+ ║ • the euro symbol: │ 14.95 € │ ║
+ ║ ╰─────────╯ ║
+ ╚══════════════════════════════════════════╝
+
+Combining characters:
+
+ STARGΛ̊TE SG-1, a = v̇ = r̈, a⃑ ⊥ b⃑
+
+Greek (in Polytonic):
+
+ The Greek anthem:
+
+ Σὲ γνωρίζω ἀπὸ τὴν κόψη
+ τοῦ σπαθιοῦ τὴν τρομερή,
+ σὲ γνωρίζω ἀπὸ τὴν ὄψη
+ ποὺ μὲ βία μετράει τὴ γῆ.
+
+ ᾿Απ᾿ τὰ κόκκαλα βγαλμένη
+ τῶν ῾Ελλήνων τὰ ἱερά
+ καὶ σὰν πρῶτα ἀνδρειωμένη
+ χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά!
+
+ From a speech of Demosthenes in the 4th century BC:
+
+ Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι,
+ ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς
+ λόγους οὓς ἀκούω· τοὺς μὲν γὰρ λόγους περὶ τοῦ
+ τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿
+ εἰς τοῦτο προήκοντα, ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ
+ πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν
+ οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι,
+ οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν
+ ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον
+ τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι
+ γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν
+ προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους
+ σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ
+ τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ
+ τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς
+ τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον.
+
+ Δημοσθένους, Γ´ ᾿Ολυνθιακὸς
+
+Georgian:
+
+ From a Unicode conference invitation:
+
+ გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო
+ კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს,
+ ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს
+ ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი,
+ ინტერნაციონალიზაცია და ლოკალიზაცია, Unicode-ის გამოყენება
+ ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში,
+ ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში.
+
+Russian:
+
+ From a Unicode conference invitation:
+
+ Зарегистрируйтесь сейчас на Десятую Международную Конференцию по
+ Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии.
+ Конференция соберет широкий круг экспертов по вопросам глобального
+ Интернета и Unicode, локализации и интернационализации, воплощению и
+ применению Unicode в различных операционных системах и программных
+ приложениях, шрифтах, верстке и многоязычных компьютерных системах.
+
+Thai (UCS Level 2):
+
+ Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese
+ classic 'San Gua'):
+
+ [----------------------------|------------------------]
+ ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่
+ สิบสองกษัตริย์ก่อนหน้าแลถัดไป สององค์ไซร้โง่เขลาเบาปัญญา
+ ทรงนับถือขันทีเป็นที่พึ่ง บ้านเมืองจึงวิปริตเป็นนักหนา
+ โฮจิ๋นเรียกทัพทั่วหัวเมืองมา หมายจะฆ่ามดชั่วตัวสำคัญ
+ เหมือนขับไสไล่เสือจากเคหา รับหมาป่าเข้ามาเลยอาสัญ
+ ฝ่ายอ้องอุ้นยุแยกให้แตกกัน ใช้สาวนั้นเป็นชนวนชื่นชวนใจ
+ พลันลิฉุยกุยกีกลับก่อเหตุ ช่างอาเพศจริงหนาฟ้าร้องไห้
+ ต้องรบราฆ่าฟันจนบรรลัย ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ
+
+ (The above is a two-column text. If combining characters are handled
+ correctly, the lines of the second column should be aligned with the
+ | character above.)
+
+Ethiopian:
+
+ Proverbs in the Amharic language:
+
+ ሰማይ አይታረስ ንጉሥ አይከሰስ።
+ ብላ ካለኝ እንደአባቴ በቆመጠኝ።
+ ጌጥ ያለቤቱ ቁምጥና ነው።
+ ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው።
+ የአፍ ወለምታ በቅቤ አይታሽም።
+ አይጥ በበላ ዳዋ ተመታ።
+ ሲተረጉሙ ይደረግሙ።
+ ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል።
+ ድር ቢያብር አንበሳ ያስር።
+ ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም።
+ እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም።
+ የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ።
+ ሥራ ከመፍታት ልጄን ላፋታት።
+ ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል።
+ የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ።
+ ተንጋሎ ቢተፉ ተመልሶ ባፉ።
+ ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው።
+ እግርህን በፍራሽህ ልክ ዘርጋ።
+
+Runes:
+
+ ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ
+
+ (Old English, which transcribed into Latin reads 'He cwaeth that he
+ bude thaem lande northweardum with tha Westsae.' and means 'He said
+ that he lived in the northern land near the Western Sea.')
+
+Braille:
+
+ ⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌
+
+ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞
+ ⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎
+ ⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂
+ ⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙
+ ⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑
+ ⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲
+
+ ⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲
+
+ ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹
+ ⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞
+ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕
+ ⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹
+ ⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎
+ ⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎
+ ⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳
+ ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞
+ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲
+
+ (The first couple of paragraphs of "A Christmas Carol" by Dickens)
+
+Compact font selection example text:
+
+ ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789
+ abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ
+ –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд
+ ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა
+
+Greetings in various languages:
+
+ Hello world, Καλημέρα κόσμε, コンニチハ
+
+Box drawing alignment tests: █
+ ▉
+ ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳
+ ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳
+ ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳
+ ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳
+ ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎
+ ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏
+ ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ ▗▄▖▛▀▜ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█
+ ▝▀▘▙▄▟
diff --git a/tools/ansicode.txt b/tools/ansicode.txt
new file mode 100644
index 00000000..8767b9e7
--- /dev/null
+++ b/tools/ansicode.txt
@@ -0,0 +1,779 @@
+Summary of ANSI standards for ASCII terminals Joe Smith, 18-May-84
+
+Contents:
+ 1. Overview and Definitions
+ 2. General rules for interpreting an ESCape Sequence
+ 3. General rules for interpreting a Control Sequence
+ 4. C0 and C1 control codes in numeric order
+ 5. Two and three-character ESCape Sequences in numeric order
+ 6. Control Sequences in numeric order
+ 7. VT100 emulation requirements
+
+The VT100 USER GUIDE and ANSI standard X3.64-1979 both list the ANSI ESCape
+sequences in alphabetic order by mnemonic, but do not have a have a cross
+reference in order by ASCII code. This paper lists the combination of all
+definitions from the three ANSI standards in numeric order. For a description
+of the advantages of using these standards, see the article "Toward
+Standardized Video Terminals" in the April-1984 issue of BYTE magazine.
+
+ANSI X3.4-1977 defines the 7-bit ASCII character set (C0 and G0). It was
+written in 1968, revised in 1977, and explains the decisions made in laying out
+the ASCII code. In particular, it explains why ANSI chose to make ASCII
+incompatible with EBCDIC in order to make it self-consistant.
+
+ANSI X3.41-1974 introduces the idea of an 8-bit ASCII character set (C1 and G1
+in addition to the existing C0 and G0). It describes how to use the 8-bit
+features in a 7-bit environment. X3.41 defines the format of all ESCape
+sequences, but defines only the 3-character ones with a parameter character
+in the middle. These instruct the terminal how to interpret the C0, G0, C1,
+and G1 characters (such as by selecting different character-set ROMs).
+
+ Note: NAPLPS does videotex graphics by redefining the C1 set and
+ selecting alternate G0, G1, G2, and G3 sets.
+ See the February 1983 issue of BYTE magazine for details.
+
+ANSI X3.64-1979 defines the remaining ESCape sequences. It defines all the C1
+control characters, and specifies that certain two-character ESCape sequences
+in the 7-bit environment are to act exactly like the 8-bit C1 control set.
+X3.64 introduces the idea of a Control-Sequence, which starts with CSI
+character, has an indefinite length, and is terminated by an alphabetic
+character. The VT100 was one of the first terminals to implement this
+standard.
+
+Definitions:
+
+ Control Character - A single character with an ASCII code with the range
+ of 000 to 037 and 200 to 237 octal, 00 to 1F and 80 to 9F hex.
+
+ Escape Sequence - A two or three character string staring with ESCape.
+ (Four or more character strings are allowed but not defined.)
+
+ Control Sequence - A string starting with CSI (233 octal, 9B hex) or
+ with ESCape Left-Bracket, and terminated by an alphabetic character.
+ Any number of parameter characters (digits 0 to 9, semicolon, and
+ question mark) may appear within the Control Sequence. The terminating
+ character may be preceded by an intermediate character (such as space).
+ Character classifications:
+
+C0 Control 000-037 octal, 00-1F hex (G0 is 041-176 octal, 21-7E hex)
+SPACE 040+240 octal, 20+A0 hex Always and everywhere a blank space
+Intermediate 040-057 octal, 20-2F hex !"#$%&'()*+,-./
+Parameters 060-077 octal, 30-3F hex 0123456789:;<=>?
+Uppercase 100-137 octal, 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
+Lowercase 140-176 octal, 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~
+Alphabetic 100-176 octal, 40-7E hex (all of upper and lower case)
+Delete 177 octal, 7F hex Always and everywhere ignored
+C1 Control 200-237 octal, 80-9F hex 32 additional control characters
+G1 Displayable 241-376 octal, A1-FE hex 94 additional displayable characters
+Special 240+377 octal, A0+FF hex Same as SPACE and DELETE
+
+Note that in this paper, the terms uppercase, lowercase, and alphabetics
+include more characters than just A to Z.
+
+------------------------------------------------------------------------------
+
+General rules for interpreting an ESCape Sequence:
+
+ An ESCape Sequence starts with the ESC character (033 octal, 1B hex).
+The length of the ESCape Sequence depends on the character that immediately
+follows the ESCape.
+
+If the next character is
+ C0 control: Interpret it first, then resume processing ESCape sequence.
+ Example: CR, LF, XON, and XOFF work as normal within an ESCape sequence.
+ Intermediate: Expect zero or more intermediates, a parameter terminates
+ a private function, an alphabetic terminates a standard sequence.
+ Example: ESC ( A defines standard character set, ESC ( 0 a DEC set.
+ Parameter: End of a private 2-character escape sequence.
+ Example: ESC = sets special keypad mode, ESC > clears it.
+ Uppercase: Translate it into a C1 control character and act on it.
+ Example: ESC D does indexes down, ESC M indexes up. (CSI is special)
+ Lowercase: End of a standard 2-character escape sequence.
+ Example: ESC c resets the terminal.
+ Delete: Ignore it, and continue interpreting the ESCape sequence
+ C1 and G1: Treat the same as their 7-bit counterparts
+
+ Note that CSI is the two-character sequence ESCape left-bracket or the 8-bit
+C1 code of 233 octal, 9B hex. CSI introduces a Control Sequence, which
+continues until an alphabetic character is received.
+
+General rules for interpreting a Control Sequence:
+
+1) It starts with CSI, the Control Sequence Introducer.
+2) It contains any number of parameter characters (0123456789:;<=>?).
+3) It terminates with an alphabetic character.
+4) Intermediate characters (if any) immediately precede the terminator.
+
+If the first character after CSI is one of "<=>?" (074-077 octal, 3C-3F hex),
+then Control Sequence is to be interpreted according to private standards (such
+as setting and resetting modes not defined by ANSI). The terminal should
+expect any number of numeric parameters, separated by semicolons (073 octal,
+3B hex). Only after the terminating alphabetic character is received should
+the terminal act on the Control Sequence.
+
+=============================================================================
+ C0 set of 7-bit control characters (from ANSI X3.4-1977).
+
+Oct Hex Name * (* marks function used in DEC VT series or LA series terminals)
+--- -- - --- - --------------------------------------------------------------
+000 00 @ NUL * Null filler, terminal should ignore this character
+001 01 A SOH Start of Header
+002 02 B STX Start of Text, implied end of header
+003 03 C ETX End of Text, causes some terminal to respond with ACK or NAK
+004 04 D EOT End of Transmission
+005 05 E ENQ * Enquiry, causes terminal to send ANSWER-BACK ID
+006 06 F ACK Acknowledge, usually sent by terminal in response to ETX
+007 07 G BEL * Bell, triggers the bell, buzzer, or beeper on the terminal
+010 08 H BS * Backspace, can be used to define overstruck characters
+011 09 I HT * Horizontal Tabulation, move to next predetermined position
+012 0A J LF * Linefeed, move to same position on next line (see also NL)
+013 0B K VT * Vertical Tabulation, move to next predetermined line
+014 0C L FF * Form Feed, move to next form or page
+015 0D M CR * Carriage Return, move to first character of current line
+016 0E N SO * Shift Out, switch to G1 (other half of character set)
+017 0F O SI * Shift In, switch to G0 (normal half of character set)
+020 10 P DLE Data Link Escape, interpret next control character specially
+021 11 Q XON * (DC1) Terminal is allowed to resume transmitting
+022 12 R DC2 Device Control 2, causes ASR-33 to activate paper-tape reader
+023 13 S XOFF* (DC2) Terminal must pause and refrain from transmitting
+024 14 T DC4 Device Control 4, causes ASR-33 to deactivate paper-tape reader
+025 15 U NAK Negative Acknowledge, used sometimes with ETX and ACK
+026 16 V SYN Synchronous Idle, used to maintain timing in Sync communication
+027 17 W ETB End of Transmission block
+030 18 X CAN * Cancel (makes VT100 abort current escape sequence if any)
+031 19 Y EM End of Medium
+032 1A Z SUB * Substitute (VT100 uses this to display parity errors)
+033 1B [ ESC * Prefix to an ESCape sequence
+034 1C \ FS File Separator
+035 1D ] GS Group Separator
+036 1E ^ RS * Record Separator (sent by VT132 in block-transfer mode)
+037 1F _ US Unit Separator
+
+040 20 SP * Space (should never be defined to be otherwise)
+177 7F DEL * Delete, should be ignored by terminal
+
+==============================================================================
+ C1 set of 8-bit control characters (from ANSI X3.64-1979)
+
+Oct Hex Name * (* marks function used in DEC VT series or LA series terminals)
+--- -- - --- - --------------------------------------------------------------
+200 80 @ Reserved for future standardization
+201 81 A Reserved
+202 82 B Reserved
+203 83 C Reserved
+204 84 D IND * Index, moves down one line same column regardless of NL
+205 85 E NEL * NEw Line, moves done one line and to first column (CR+LF)
+206 86 F SSA Start of Selected Area to be sent to auxiliary output device
+207 87 G ESA End of Selected Area to be sent to auxiliary output device
+210 88 H HTS * Horizontal Tabulation Set at current position
+211 89 I HTJ Hor Tab Justify, moves string to next tab position
+212 8A J VTS Vertical Tabulation Set at current line
+213 8B K PLD Partial Line Down (subscript)
+214 8C L PLU Partial Line Up (superscript)
+215 8D M RI * Reverse Index, go up one line, reverse scroll if necessary
+216 8E N SS2 * Single Shift to G2
+217 8F O SS3 * Single Shift to G3 (VT100 uses this for sending PF keys)
+220 90 P DCS * Device Control String, terminated by ST (VT125 enters graphics)
+221 91 Q PU1 Private Use 1
+222 92 R PU2 Private Use 2
+223 93 S STS Set Transmit State
+224 94 T CCH Cancel CHaracter, ignore previous character
+225 95 U MW Message Waiting, turns on an indicator on the terminal
+226 96 V SPA Start of Protected Area
+227 97 W EPA End of Protected Area
+230 98 X Reserved for for future standard
+231 99 Y Reserved
+232 9A Z * Reserved, but causes DEC terminals to respond with DA codes
+233 9B [ CSI * Control Sequence Introducer (described in a seperate table)
+234 9C \ ST * String Terminator (VT125 exits graphics)
+235 9D ] OSC Operating System Command (reprograms intelligent terminal)
+236 9E ^ PM Privacy Message (password verification), terminated by ST
+237 9F _ APC Application Program Command (to word processor), term by ST
+
+==============================================================================
+ Character set selection sequences (from ANSI X3.41-1974)
+ All are 3 characters long (including the ESCape). Alphabetic characters
+ as 3rd character are defined by ANSI, parameter characters as 3rd character
+ may be interpreted differently by each terminal manufacturer.
+
+Oct Hex * (* marks function used in DEC VT series or LA series terminals)
+--- -- -- - ------------------------------------------------------------------
+040 20 ANNOUNCER - Determines whether to use 7-bit or 8-bit ASCII
+ A G0 only will be used. Ignore SI, SO, and G1.
+ B G0 and G1 used internally. SI and SO affect G0, G1 is ignored.
+ C G0 and G1 in an 8-bit only environment. SI and SO are ignored.
+ D G0 and G1 are used, SI and SO affect G0.
+ E
+ F * 7-bit transmission, VT240/PRO350 sends CSI as two characters ESC [
+ G * 8-bit transmission, VT240/PRO350 sends CSI as single 8-bit character
+041 21 ! Select C0 control set (choice of 63 standard, 16 private)
+042 22 " Select C1 control set (choice of 63 standard, 16 private)
+043 23 # Translate next character to a special single character
+ #3 * DECDHL1 - Double height line, top half
+ #4 * DECDHL2 - Double height line, bottom half
+ #5 * DECSWL - Single width line
+ #6 * DECDWL - Double width line
+ #7 * DECHCP - Make a hardcopy of the graphics screen (GIGI,VT125,VT241)
+ #8 * DECALN - Alignment display, fill screen with "E" to adjust focus
+044 24 $ MULTIBYTE CHARACTERS - Displayable characters require 2-bytes each
+045 25 % SPECIAL INTERPRETATION - Such as 9-bit data
+046 26 & Reserved for future standardization
+047 27 ' Reserved for future standardization
+050 28 ( * SCS - Select G0 character set (choice of 63 standard, 16 private)
+ (0 * DEC VT100 line drawing set (affects lowercase characters)
+ (1 * DEC Alternate character ROM set (RAM set on GIGI and VT220)
+ (2 * DEC Alternate character ROM set with line drawing
+ (5 * DEC Finnish on LA100
+ (6 * DEC Norwegian/Danish on LA100
+ (7 * DEC Swedish on LA100
+ (9 * DEC French Canadian
+ (< * DEC supplemental graphics (everything not in USASCII)
+ (A * UKASCII (British pound sign)
+ (B * USASCII (American pound sign)
+ (C * ISO Finnish on LA120
+ (E * ISO Norwegian/Danish on LA120
+ (H * ISO Swedish on LA120
+ (K * ISO German on LA100,LA120
+ (R * ISO French on LA100,LA120
+ (Y * ISO Italian on LA100
+ (Z * ISO Spanish on LA100
+051 29 ) * SCS - Select G1 character set (choice of 63 standard, 16 private)
+ * (same character sets as listed under G0)
+052 2A * * SCS - Select G2 character set
+ * (same character sets as listed under G0)
+053 2B + * SCS - Select G3 character set
+ * (same character sets as listed under G0)
+054 2C , SCS - Select G0 character set (additional 63+16 sets)
+055 2D - SCS - Select G1 character set (additional 63+16 sets)
+056 2E . SCS - Select G2 character set
+057 2F / SCS - Select G3 character set
+
+==============================================================================
+ Private two-character escape sequences (allowed by ANSI X3.41-1974)
+ These can be defined differently by each terminal manufacturer.
+
+Oct Hex * (* marks function used in DEC VT series or LA series terminals)
+--- -- - - ------------------------------------------------------------------
+060 30 0
+061 31 1 DECGON graphics on for VT105, DECHTS horiz tab set for LA34/LA120
+062 32 2 DECGOFF graphics off VT105, DECCAHT clear all horz tabs LA34/LA120
+063 33 3 DECVTS - set vertical tab for LA34/LA120
+064 34 4 DECCAVT - clear all vertical tabs for LA34/LA120
+065 35 5 * DECXMT - Host requests that VT132 transmit as if ENTER were pressed
+066 36 6
+067 37 7 * DECSC - Save cursor position and character attributes
+070 38 8 * DECRC - Restore cursor and attributes to previously saved position
+071 39 9
+072 3A :
+073 3B ;
+074 3C < * DECANSI - Switch from VT52 mode to VT100 mode
+075 3D = * DECKPAM - Set keypad to applications mode (ESCape instead of digits)
+076 3E > * DECKPNM - Set keypad to numeric mode (digits intead of ESCape seq)
+077 3F ?
+
+ DCS Device Control Strings used by DEC terminals (ends with ST)
+
+Pp = Start ReGIS graphics (VT125, GIGI, VT240, PRO350)
+Pq = Start SIXEL graphics (screen dump to LA34, LA100, screen load to VT125)
+Pr = SET-UP data for GIGI, $PrVC0$\ disables both visible cursors.
+Ps = Reprogram keys on the GIGI, $P0sDIR<CR>$\ makes keypad 0 send "DIR<CR>"
+ 0-9=digits on keypad, 10=ENTER, 11=minus, 12=comma, 13=period,
+ 14-17=PF1-PF4, 18-21=cursor keys. Enabled by $[?23h (PK1).
+Pt = Start VT105 graphics on a VT125
+
+==============================================================================
+
+ Standard two-character escape sequences (defined by ANSI X3.64-1979)
+
+100 40 @ See description of C1 control characters
+ An ESCape followed by one of these uppercase characters is translated
+ to an 8-bit C1 control character before being interpreted.
+220 90 P DCS - Device Control String, terminated by ST - see table above.
+133 5B [ CSI - Control Sequence Introducer - see table below.
+137 5F _ See description of C1 control characters
+
+==============================================================================
+
+ Indepenent control functions (from Appendix E of X3.64-1977).
+ These four controls have the same meaning regardless of the current
+ definition of the C0 and C1 control sets. Each control is a two-character
+ ESCape sequence, the 2nd character is lowercase.
+
+Oct Hex * (* marks function used in DEC VT series or LA series terminals)
+--- -- - - --------------------------------------------------------------------
+140 60 ` DMI - Disable Manual Input
+141 61 a INT - INTerrupt the terminal and do special action
+142 62 b EMI - Enable Manual Input
+143 63 c * RIS - Reset to Initial State (VT100 does a power-on reset)
+ ... The remaining lowercase characters are reserved by ANSI.
+153 6B k NAPLPS lock-shift G1 to GR
+154 6C l NAPLPS lock-shift G2 to GR
+155 6D m NAPLPS lock-shift G3 to GR
+156 6E n * LS2 - Shift G2 to GL (extension of SI) VT240,NAPLPS
+157 6F o * LS3 - Shift G3 to GL (extension of SO) VT240,NAPLPS
+ ... The remaining lowercase characters are reserved by ANSI.
+174 7C | * LS3R - VT240 lock-shift G3 to GR
+175 7D } * LS2R - VT240 lock-shift G2 to GR
+176 7E ~ * LS1R - VT240 lock-shift G1 to GR
+
+==============================================================================
+ Control Sequences (defined by ANSI X3.64-1979)
+
+Control Sequences are started by either ESC [ or CSI and are terminated by an
+"alphabetic" character (100 to 176 octal, 40 to 7E hex). Intermediate
+characters are space through slash (40 to 57 octal, 20 to 2F hex) and parameter
+characters are zero through question mark (60 to 77 octal, 30 to 3F hex,
+including digits and semicolon). Parameters consist of zero or more decimal
+numbers separated by semicolons. Leading zeros are optional, leading blanks
+are not allowed. If no digits precede the final character, the default
+parameter is used. Many functions treat a parameter of 0 as if it were 1.
+
+Oct Hex * (* marks function used in DEC VT series or LA series terminals)
+--- -- - - --------------------------------------------------------------------
+100 40 @ ICH - Insert CHaracter
+ [10@ = Make room for 10 characters at current position
+101 41 A * CUU - CUrsor Up
+ * [A = Move up one line, stop at top of screen, [9A = move up 9
+102 42 B * CUD - CUrsor Down
+ * [B = Move down one line, stop at bottom of screen
+103 43 C * CUF - CUrsor Forward
+ * [C = Move forward one position, stop at right edge of screen
+104 44 D * CUB - CUrsor Backward
+ * [D = Same as BackSpace, stop at left edge of screen
+105 45 E CNL - Cursor to Next Line
+ [5E = Move to first position of 5th line down
+106 46 F CPL - Cursor to Previous Line
+ [5F = Move to first position of 5th line previous
+107 47 G CHA - Cursor Horizontal position Absolute
+ [40G = Move to column 40 of current line
+110 48 H * CUP - CUrsor Position
+ * [H = Home, [24;80H = Row 24, Column 80
+111 49 I CHT - Cursor Horizontal Tabulation
+ [I = Same as HT (Control-I), [3I = Go forward 3 tabs
+112 4A J * ED - Erase in Display (cursor does not move)
+ * [J = [0J = Erase from current position to end (inclusive)
+ * [1J = Erase from beginning to current position (inclusive)
+ * [2J = Erase entire display
+ * [?0J = Selective erase in display ([?1J, [?2J similar)
+113 4B K * EL - Erase in Line (cursor does not move)
+ * [K = [0K = Erase from current position to end (inclusive)
+ * [1K = Erase from beginning to current position
+ * [2K = Erase entire current line
+ * [?0K = Selective erase to end of line ([?1K, [?2K similar)
+114 4C L * IL - Insert Line, current line moves down (VT102 series)
+ [3L = Insert 3 lines if currently in scrolling region
+115 4D M * DL - Delete Line, lines below current move up (VT102 series)
+ [2M = Delete 2 lines if currently in scrolling region
+116 4E N EF - Erase in Field (as bounded by protected fields)
+ [0N, [1N, [2N act like [L but within currend field
+117 4F O EA - Erase in qualified Area (defined by DAQ)
+ [0O, [1O, [2O act like [J but within current area
+120 50 P * DCH - Delete Character, from current position to end of field
+ [4P = Delete 4 characters, VT102 series
+121 51 Q SEM - Set Editing extent Mode (limits ICH and DCH)
+ [0Q = [Q = Insert/delete character affects rest of display
+ [1Q = ICH/DCH affect the current line only
+ [2Q = ICH/DCH affect current field (between tab stops) only
+ [3Q = ICH/DCH affect qualified area (between protected fields)
+122 52 R * CPR - Cursor Position Report (from terminal to host)
+ * [24;80R = Cursor is positioned at line 24 column 80
+123 53 S SU - Scroll up, entire display is moved up, new lines at bottom
+ [3S = Move everything up 3 lines, bring in 3 new lines
+124 54 T SD - Scroll down, new lines inserted at top of screen
+ [4T = Scroll down 4, bring previous lines back into view
+125 55 U NP - Next Page (if terminal has more than 1 page of memory)
+ [2U = Scroll forward 2 pages
+126 56 V PP - Previous Page (if terminal remembers lines scrolled off top)
+ [1V = Scroll backward 1 page
+127 57 W CTC - Cursor Tabulation Control
+ [0W = Set horizontal tab for current line at current position
+ [1W = Set vertical tab stop for current line of current page
+ [2W = Clear horiz tab stop at current position of current line
+ [3W = Clear vert tab stop at current line of current page
+ [4W = Clear all horiz tab stops on current line only
+ [5W = Clear all horiz tab stops for the entire terminal
+ [6W = Clear all vert tabs stops for the entire terminal
+130 58 X ECH - Erase CHaracter
+ [4X = Change next 4 characters to "erased" state
+131 59 Y CVT - Cursor Vertical Tab
+ [2Y = Move forward to 2nd following vertical tab stop
+132 5A Z CBT - Cursor Back Tab
+ [3Z = Move backwards to 3rd previous horizontal tab stop
+133 5B [ Reserved for future standardization left bracket
+134 5C \ Reserved reverse slant
+135 5D ] Reserved right bracket
+136 5E ^ Reserved circumflex
+137 5F _ Reserved underscore
+140 60 ` * HPA - Horizontal Position Absolute (depends on PUM)
+ [720` = Move to 720 decipoints (1 inch) from left margin
+ * [80` = Move to column 80 on LA120
+141 61 a * HPR - Horizontal Position Relative (depends on PUM)
+ [360a = Move 360 decipoints (1/2 inch) from current position
+ * [40a = Move 40 columns to right of current position on LA120
+142 62 b REP - REPeat previous displayable character
+ [80b = Repeat character 80 times
+143 63 c * DA - Device Attributes
+ * [c = Terminal will identify itself
+ * [?1;2c = Terminal is saying it is a VT100 with AVO
+ * [>0c = Secondary DA request (distinguishes VT240 from VT220)
+144 64 d * VPA - Vertical Position Absolute (depends on PUM)
+ [90d = Move to 90 decipoints (1/8 inch) from top margin
+ * [10d = Move to line 10 if before that else line 10 next page
+145 65 e * VPR - Vertical Position Relative (depends on PUM)
+ [720e = Move 720 decipoints (1 inch) down from current position
+ * [6e = Advance 6 lines forward on LA120
+146 66 f * HVP - Horizontal and Vertical Position (depends on PUM)
+ [720,1440f = Move to 1 inch down and 2 inches over (decipoints)
+ * [24;80f = Move to row 24 column 80 if PUM is set to character
+147 67 g * TBC - Tabulation Clear
+ * [0g = Clear horizontal tab stop at current position
+ * [1g = Clear vertical tab stop at current line (LA120)
+ * [2g = Clear all horizontal tab stops on current line only LA120
+ * [3g = Clear all horizontal tab stops in the terminal
+150 68 h * SM - Set Mode (. means permanently set on VT100)
+ [0h = Error, this command is ignored
+ * [1h = GATM - Guarded Area Transmit Mode, send all (VT132)
+ [2h = KAM - Keyboard Action Mode, disable keyboard input
+ [3h = CRM - Control Representation Mode, show all control chars
+ * [4h = IRM - Insertion/Replacement Mode, set insert mode (VT102)
+ [5h = SRTM - Status Report Transfer Mode, report after DCS
+ * [6h = ERM - ERasure Mode, erase protected and unprotected
+ [7h = VEM - Vertical Editing Mode, IL/DL affect previous lines
+ [8h, [9h are reserved
+ [10h = HEM - Horizontal Editing mode, ICH/DCH/IRM go backwards
+ [11h = PUM - Positioning Unit Mode, use decipoints for HVP/etc
+ . [12h = SRM - Send Receive Mode, transmit without local echo
+ [13h = FEAM - Format Effector Action Mode, FE's are stored
+ [14h = FETM - Format Effector Transfer Mode, send only if stored
+ [15h = MATM - Multiple Area Transfer Mode, send all areas
+ * [16h = TTM - Transmit Termination Mode, send scrolling region
+ [17h = SATM - Send Area Transmit Mode, send entire buffer
+ [18h = TSM - Tabulation Stop Mode, lines are independent
+ [19h = EBM - Editing Boundry Mode, all of memory affected
+ * [20h = LNM - Linefeed Newline Mode, LF interpreted as CR LF
+ * [?1h = DECCKM - Cursor Keys Mode, send ESC O A for cursor up
+ * [?2h = DECANM - ANSI Mode, use ESC < to switch VT52 to ANSI
+ * [?3h = DECCOLM - COLumn mode, 132 characters per line
+ * [?4h = DECSCLM - SCrolL Mode, smooth scrolling
+ * [?5h = DECSCNM - SCreeN Mode, black on white background
+ * [?6h = DECOM - Origin Mode, line 1 is relative to scroll region
+ * [?7h = DECAWM - AutoWrap Mode, start newline after column 80
+ * [?8h = DECARM - Auto Repeat Mode, key will autorepeat
+ * [?9h = DECINLM - INterLace Mode, interlaced for taking photos
+ * [?10h = DECEDM - EDit Mode, VT132 is in EDIT mode
+ * [?11h = DECLTM - Line Transmit Mode, ignore TTM, send line
+ [?12h = ?
+ * [?13h = DECSCFDM - Space Compression/Field Delimiting on,
+ * [?14h = DECTEM - Transmit Execution Mode, transmit on ENTER
+ [?15h = ?
+ * [?16h = DECEKEM - Edit Key Execution Mode, EDIT key is local
+ [?17h = ?
+ * [?18h = DECPFF - Print FormFeed mode, send FF after printscreen
+ * [?19h = DECPEXT - Print Extent mode, print entire screen
+ * [?20h = OV1 - Overstrike, overlay characters on GIGI
+ * [?21h = BA1 - Local BASIC, GIGI to keyboard and screen
+ * [?22h = BA2 - Host BASIC, GIGI to host computer
+ * [?23h = PK1 - GIGI numeric keypad sends reprogrammable sequences
+ * [?24h = AH1 - Autohardcopy before erasing or rolling GIGI screen
+ * [?29h = - Use only the proper pitch for the LA100 font
+ * [?38h = DECTEK - TEKtronix mode graphics
+151 69 i * MC - Media Copy (printer port on VT102)
+ * [0i = Send contents of text screen to printer
+ [1i = Fill screen from auxiliary input (printer's keyboard)
+ [2i = Send screen to secondary output device
+ [3i = Fill screen from secondary input device
+ * [4i = Turn on copying received data to primary output (VT125)
+ * [4i = Received data goes to VT102 screen, not to its printer
+ * [5i = Turn off copying received data to primary output (VT125)
+ * [5i = Received data goes to VT102's printer, not its screen
+ * [6i = Turn off copying received data to secondary output (VT125)
+ * [7i = Turn on copying received data to secondary output (VT125)
+ * [?0i = Graphics screen dump goes to graphics printer VT125,VT240
+ * [?1i = Print cursor line, terminated by CR LF
+ * [?2i = Graphics screen dump goes to host computer VT125,VT240
+ * [?4i = Disable auto print
+ * [?5i = Auto print, send a line at a time when linefeed received
+152 6A j Reserved for future standardization
+153 6B k Reserved for future standardization
+154 6C l * RM - Reset Mode (. means permanently reset on VT100)
+ * [1l = GATM - Transmit only unprotected characters (VT132)
+ . [2l = KAM - Enable input from keyboard
+ . [3l = CRM - Control characters are not displayable characters
+ * [4l = IRM - Reset to replacement mode (VT102)
+ . [5l = SRTM - Report only on command (DSR)
+ * [6l = ERM - Erase only unprotected fields
+ . [7l = VEM - IL/DL affect lines after current line
+ [8l, [9l are reserved
+ . [10l = HEM - ICH and IRM shove characters forward, DCH pulls
+ . [11l = PUM - Use character positions for HPA/HPR/VPA/VPR/HVP
+ [12l = SRM - Local echo - input from keyboard sent to screen
+ . [13l = FEAM - HPA/VPA/SGR/etc are acted upon when received
+ . [14l = FETM - Format Effectors are sent to the printer
+ [15l = MATM - Send only current area if SATM is reset
+ * [16l = TTM - Transmit partial page, up to cursor position
+ [17l = SATM - Transmit areas bounded by SSA/ESA/DAQ
+ . [18l = TSM - Setting a tab stop on one line affects all lines
+ . [19l = EBM - Insert does not overflow to next page
+ * [20l = LNM - Linefeed does not change horizontal position
+ * [?1l = DECCKM - Cursor keys send ANSI cursor position commands
+ * [?2l = DECANM - Use VT52 emulation instead of ANSI mode
+ * [?3l = DECCOLM - 80 characters per line (erases screen)
+ * [?4l = DECSCLM - Jump scrolling
+ * [?5l = DECSCNM - Normal screen (white on black background)
+ * [?6l = DECOM - Line numbers are independent of scrolling region
+ * [?7l = DECAWM - Cursor remains at end of line after column 80
+ * [?8l = DECARM - Keys do not repeat when held down
+ * [?9l = DECINLM - Display is not interlaced to avoid flicker
+ * [?10l = DECEDM - VT132 transmits all key presses
+ * [?11l = DECLTM - Send page or partial page depending on TTM
+ [?12l = ?
+ * [?13l = DECSCFDM - Don't suppress trailing spaces on transmit
+ * [?14l = DECTEM - ENTER sends ESC S (STS) a request to send
+ [?15l = ?
+ * [?16l = DECEKEM - EDIT key transmits either $[10h or $[10l
+ [?17l = ?
+ * [?18l = DECPFF - Don't send a formfeed after printing screen
+ * [?19l = DECPEXT - Print only the lines within the scroll region
+ * [?20l = OV0 - Space is destructive, replace not overstrike, GIGI
+ * [?21l = BA0 - No BASIC, GIGI is On-Line or Local
+ * [?22l = BA0 - No BASIC, GIGI is On-Line or Local
+ * [?23l = PK0 - Ignore reprogramming on GIGI keypad and cursors
+ * [?24l = AH0 - No auto-hardcopy when GIGI screen erased
+ * [?29l = Allow all character pitches on the LA100
+ * [?38l = DECTEK - Ignore TEKtronix graphics commands
+155 6D m * SGR - Set Graphics Rendition (affects character attributes)
+ * [0m = Clear all special attributes
+ * [1m = Bold or increased intensity
+ * [2m = Dim or secondary color on GIGI (superscript on XXXXXX)
+ [3m = Italic (subscript on XXXXXX)
+ * [4m = Underscore, [0;4m = Clear, then set underline only
+ * [5m = Slow blink
+ [6m = Fast blink (overscore on XXXXXX)
+ * [7m = Negative image, [0;1;7m = Bold + Inverse
+ [8m = Concealed (do not display character echoed locally)
+ [9m = Reserved for future standardization
+ * [10m = Select primary font (LA100)
+ * [11m - [19m = Selete alternate font (LA100 has 11 thru 14)
+ [20m = FRAKTUR (whatever that means)
+ * [22m = Cancel bold or dim attribute only (VT220)
+ * [24m = Cancel underline attribute only (VT220)
+ * [25m = Cancel fast or slow blink attribute only (VT220)
+ * [27m = Cancel negative image attribute only (VT220)
+ * [30m = Write with black, [40m = Set background to black (GIGI)
+ * [31m = Write with red, [41m = Set background to red
+ * [32m = Write with green, [42m = Set background to green
+ * [33m = Write with yellow, [43m = Set background to yellow
+ * [34m = Write with blue, [44m = Set background to blue
+ * [35m = Write with magenta, [45m = Set background to magenta
+ * [36m = Write with cyan, [46m = Set background to cyan
+ * [37m = Write with white, [47m = Set background to white
+ [38m, [39m, [48m, [49m are reserved
+156 6E n * DSR - Device Status Report
+ * [0n = Terminal is ready, no malfunctions detected
+ [1n = Terminal is busy, retry later
+ [2n = Terminal is busy, it will send DSR when ready
+ * [3n = Malfunction, please try again
+ [4n = Malfunction, terminal will send DSR when ready
+ * [5n = Command to terminal to report its status
+ * [6n = Command to terminal requesting cursor position (CPR)
+ * [?15n = Command to terminal requesting printer status, returns
+ [?10n = OK, [?11n = not OK, [?13n = no printer.
+ * [?25n = "Are User Defined Keys Locked?" (VT220)
+157 6F o DAQ - Define Area Qualification starting at current position
+ [0o = Accept all input, transmit on request
+ [1o = Protected and guarded, accept no input, do not transmit
+ [2o = Accept any printing character in this field
+ [3o = Numeric only field
+ [4o = Alphabetic (A-Z and a-z) only
+ [5o = Right justify in area
+ [3;6o = Zero fill in area
+ [7o = Set horizontal tab stop, this is the start of the field
+ [8o = Protected and unguarded, accept no input, do transmit
+ [9o = Space fill in area
+
+==============================================================================
+
+ Private Control Sequences (allowed by ANSI X3.41-1974).
+ These take parameter strings and terminate with the last half of lowercase.
+
+Oct Hex * (* marks function used in DEC VT series or LA series terminals)
+--- -- - - --------------------------------------------------------------------
+160 70 p * DECSTR - Soft Terminal Reset
+ [!p = Soft Terminal Reset
+161 71 q * DECLL - Load LEDs
+ [0q = Turn off all, [?1;4q turns on L1 and L4, etc
+ [154;155;157q = VT100 goes bonkers
+ [2;23!q = Partial screen dump from GIGI to graphics printer
+ [0"q = DECSCA Select Character Attributes off
+ [1"q = DECSCA - designate set as non-erasable
+ [2"q = DECSCA - designate set as erasable
+162 72 r * DECSTBM - Set top and bottom margins (scroll region on VT100)
+ [4;20r = Set top margin at line 4 and bottom at line 20
+163 73 s * DECSTRM - Set left and right margins on LA100,LA120
+ [5;130s = Set left margin at column 5 and right at column 130
+164 74 t * DECSLPP - Set physical lines per page
+ [66t = Paper has 66 lines (11 inches at 6 per inch)
+165 75 u * DECSHTS - Set many horizontal tab stops at once on LA100
+ [9;17;25;33;41;49;57;65;73;81u = Set standard tab stops
+166 76 v * DECSVTS - Set many vertical tab stops at once on LA100
+ [1;16;31;45v = Set vert tabs every 15 lines
+167 77 w * DECSHORP - Set horizontal pitch on LAxxx printers
+ [1w = 10 characters per inch, [2w = 12 characters per inch
+ [0w=10, [3w=13.2, [4w=16.5, [5w=5, [6w=6, [7w=6.6, [8w=8.25
+170 78 x * DECREQTPARM - Request terminal parameters
+ [3;5;2;64;64;1;0x = Report, 7 bit Even, 1200 baud, 1200 baud
+171 79 y * DECTST - Invoke confidence test
+ [2;1y = Power-up test on VT100 series (and VT100 part of VT125)
+ [3;1y = Power-up test on GIGI (VK100)
+ [4;1y = Power-up test on graphics portion of VT125
+172 7A z * DECVERP - Set vertical pitch on LA100
+ [1z = 6 lines per inch, [2z = 8 lines per inch
+ [0z=6, [3z=12, [4z=3, [5z=3, [6z=4
+173 7B { Private
+174 7C | * DECTTC - Transmit Termination Character
+ [0| = No extra characters, [1| = terminate with FF
+175 7D } * DECPRO - Define protected field on VT132
+ [0} = No protection, [1;4;5;7} = Any attribute is protected
+ [254} = Characters with no attributes are protected
+176 7E ~ * DECKEYS - Sent by special function keys
+ [1~=FIND, [2~=INSERT, [3~=REMOVE, [4~=SELECT, [5~=PREV, [6~=NEXT
+ [17~=F6...[34~=F20 ([23~=ESC,[24~=BS,[25~=LF,[28~=HELP,[29~=DO)
+177 7F DELETE is always ignored
+
+==============================================================================
+ Control Sequences with intermediate characters (from ANSI X3.64-1979).
+ Note that there is a SPACE character before the terminating alphabetic.
+
+Oct Hex * (* marks function used in DEC VT series or LA series terminals)
+--- -- - - --------------------------------------------------------------------
+100 40 @ SL - Scroll Left
+ [4 @ = Move everything over 4 columns, 4 new columns at right
+101 41 A SR - Scroll Right
+ [2 A = Move everything over 2 columns, 2 new columns at left
+102 42 B GSM - Graphic Size Modification
+ [110;50 B = Make 110% high, 50% wide
+103 43 C GSS - Graphic Size Selection
+ [120 C = Make characters 120 decipoints (1/6 inch) high
+104 44 D FNT - FoNT selection (used by SGR, [10m thru [19m)
+ [0;23 D = Make primary font be registered font #23
+105 45 E TSS - Thin Space Specification
+ [36 E = Define a thin space to be 36 decipoints (1/20 inch)
+106 46 F JFY - JustiFY, done by the terminal/printer
+ [0 E = No justification
+ [1 E = Fill, bringing words up from next line if necessary
+ [2 E = Interword spacing, adjust spaces between words
+ [3 E = Letter spacing, adjust width of each letter
+ [4 E = Use hyphenation
+ [5 E = Flush left margin
+ [6 E = Center following text between margins (until [0 E)
+ [7 E = Flush right margin
+ [8 E = Italian form (underscore instead of hyphen)
+107 47 G SPI - SPacing Increment (in decipoints)
+ [120;72 G = 6 per inch vertical, 10 per inch horizontal
+110 48 H QUAD- Do quadding on current line of text (typography)
+ [0 H = Flush left, [1 H = Flush left and fill with leader
+ [2 H = Center, [3 H = Center and fill with leader
+ [4 H = Flush right, [5 H = Flush right and fill with leader
+111 49 I Reserved for future standardization
+157 67 o Reserved for future standardization
+160 70 p Private use
+ ... May be defined by the printer manufacturer
+176 7E ~ Private use
+177 7F DELETE is always ignored
+
+==============================================================================
+ Minimum requirements for VT100 emulation:
+
+1) To act as a passive display, implement the 4 cursor commands, the 2 erase
+ commands, direct cursor addressing, and at least inverse characters.
+ The software should be capable of handling strings with 16 numeric parameters
+ with values in the range of 0 to 255.
+
+ [A Move cursor up one row, stop if a top of screen
+ [B Move cursor down one row, stop if at bottom of screen
+ [C Move cursor forward one column, stop if at right edge of screen
+ [D Move cursor backward one column, stop if at left edge of screen
+ [H Home to row 1 column 1 (also [1;1H)
+ [J Clear from current position to bottom of screen
+ [K Clear from current position to end of line
+ [24;80H Position to line 24 column 80 (any line 1 to 24, any column 1 to 132)
+ [0m Clear attributes to normal characters
+ [7m Add the inverse video attribute to succeeding characters
+ [0;7m Set character attributes to inverse video only
+
+2) To enter data in VT100 mode, implement the 4 cursor keys and the 4 PF keys.
+ It must be possible to enter ESC, TAB, BS, DEL, and LF from the keyboard.
+
+ [A Sent by the up-cursor key (alternately ESC O A)
+ [B Sent by the down-cursor key (alternately ESC O B)
+ [C Sent by the right-cursor key (alternately ESC O C)
+ [D Sent by the left-cursor key (alternately ESC O D)
+ OP PF1 key sends ESC O P
+ OQ PF2 key sends ESC O Q
+ OR PF3 key sends ESC O R
+ OS PF3 key sends ESC O S
+ [c Request for the terminal to identify itself
+ [?1;0c VT100 with memory for 24 by 80, inverse video character attribute
+ [?1;2c VT100 capable of 132 column mode, with bold+blink+underline+inverse
+
+3) When doing full-screen editing on a VT100, implement directed erase, the
+ numeric keypad in applications mode, and the limited scrolling region.
+ The latter is needed to do insert/delete line functions without rewriting
+ the screen.
+
+ [0J Erase from current position to bottom of screen inclusive
+ [1J Erase from top of screen to current position inclusive
+ [2J Erase entire screen (without moving the cursor)
+ [0K Erase from current position to end of line inclusive
+ [1K Erase from beginning of line to current position inclusive
+ [2K Erase entire line (without moving cursor)
+ [12;24r Set scrolling region to lines 12 thru 24. If a linefeed or an
+ INDex is received while on line 24, the former line 12 is deleted
+ and rows 13-24 move up. If a RI (reverse Index) is received while
+ on line 12, a blank line is inserted there as rows 12-13 move down.
+ All VT100 compatible terminals (except GIGI) have this feature.
+ ESC = Set numeric keypad to applications mode
+ ESC > Set numeric keypad to numbers mode
+ OA Up-cursor key sends ESC O A after ESC = ESC [ ? 1 h
+ OB Down-cursor key sends ESC O B " " "
+ OC Right-cursor key sends ESC O B " " "
+ OB Left-cursor key sends ESC O B " " "
+ OM ENTER key sends ESC O M after ESC =
+ Ol COMMA on keypad sends ESC O l " " (that's lowercase L)
+ Om MINUS on keypad sends ESC O m " "
+ Op ZERO on keypad sends ESC O p " "
+ Oq ONE on keypad sends ESC O q " "
+ Or TWO on keypad sends ESC O r " "
+ Os THREE on keypad sends ESC O s " "
+ Ot FOUR on keypad sends ESC O t " "
+ Ou FIVE on keypad sends ESC O u " "
+ Ov SIX on keypad sends ESC O v " "
+ Ow SEVEN on keypad sends ESC O w " "
+ Ox EIGHT on keypad sends ESC O x " "
+ Oy NINE on keypad sends ESC O y " "
+
+4) If the hardware is capable of double width/double height:
+
+ #3 Top half of a double-width double-height line
+ #4 Bottom half of a double-width double-height line
+ #5 Make line single-width (lines are set this way when cleared by ESC [ J)
+ #6 Make line double-width normal height (40 or 66 characters)
+
+5) If the terminal emulator is capable of insert/delete characters,
+insert/delete lines, insert/replace mode, and can do a full-screen dump to
+the printer (in text mode), then it should identify itself as a VT102
+
+ [c Request for the terminal to identify itself
+ [?6c VT102 (printer port, 132 column mode, and ins/del standard)
+ [1@ Insert a blank character position (shift line to the right)
+ [1P Delete a character position (shift line to the left)
+ [1L Insert blank line at current row (shift screen down)
+ [1M Delete the current line (shift screen up)
+ [4h Set insert mode, new characters shove existing ones to the right
+ [4l Reset insert mode, new characters replace existing ones
+ [0i Print screen (all 24 lines) to the printer
+ [4i All received data goes to the printer (nothing to the screen)
+ [5i All received data goes to the screen (nothing to the printer)
+
+
+[End of ANSICODE.TXT]
diff --git a/tools/cmp-cvs.sh b/tools/cmp-cvs.sh
new file mode 100644
index 00000000..b17d6f82
--- /dev/null
+++ b/tools/cmp-cvs.sh
@@ -0,0 +1,12 @@
+#!/bin/ksh
+
+rm diff.out
+touch diff.out
+
+for i in *.[ch]; do
+ diff -u -I'\$OpenBSD' $i ../../OpenBSD/tmux/$i >diff.tmp
+ set -- `wc -l diff.tmp`
+ [ $1 -eq 8 ] && continue
+ echo $i
+ cat diff.tmp >>diff.out
+done
diff --git a/tty-term.c b/tty-term.c
index 52468faf..3ac9bc6c 100644
--- a/tty-term.c
+++ b/tty-term.c
@@ -18,12 +18,15 @@
#include <sys/types.h>
+#if defined(HAVE_CURSES_H)
#include <curses.h>
+#elif defined(HAVE_NCURSES_H)
+#include <ncurses.h>
+#endif
#include <fnmatch.h>
#include <stdlib.h>
#include <string.h>
#include <term.h>
-#include <vis.h>
#include "tmux.h"
@@ -504,7 +507,10 @@ tty_term_find(char *name, int fd, char **cause)
}
/* Delete curses data. */
+#if !defined(NCURSES_VERSION_MAJOR) || NCURSES_VERSION_MAJOR > 5 || \
+ (NCURSES_VERSION_MAJOR == 5 && NCURSES_VERSION_MINOR > 6)
del_curterm(cur_term);
+#endif
/* These are always required. */
if (!tty_term_has(term, TTYC_CLEAR)) {
@@ -626,33 +632,33 @@ tty_term_string(struct tty_term *term, enum tty_code_code code)
const char *
tty_term_string1(struct tty_term *term, enum tty_code_code code, int a)
{
- return (tparm((char *) tty_term_string(term, code), a));
+ return (tparm((char *) tty_term_string(term, code), a, 0, 0, 0, 0, 0, 0, 0, 0));
}
const char *
tty_term_string2(struct tty_term *term, enum tty_code_code code, int a, int b)
{
- return (tparm((char *) tty_term_string(term, code), a, b));
+ return (tparm((char *) tty_term_string(term, code), a, b, 0, 0, 0, 0, 0, 0, 0));
}
const char *
tty_term_string3(struct tty_term *term, enum tty_code_code code, int a, int b,
int c)
{
- return (tparm((char *) tty_term_string(term, code), a, b, c));
+ return (tparm((char *) tty_term_string(term, code), a, b, c, 0, 0, 0, 0, 0, 0));
}
const char *
tty_term_ptr1(struct tty_term *term, enum tty_code_code code, const void *a)
{
- return (tparm((char *) tty_term_string(term, code), a));
+ return (tparm((char *) tty_term_string(term, code), (long)a, 0, 0, 0, 0, 0, 0, 0, 0));
}
const char *
tty_term_ptr2(struct tty_term *term, enum tty_code_code code, const void *a,
const void *b)
{
- return (tparm((char *) tty_term_string(term, code), a, b));
+ return (tparm((char *) tty_term_string(term, code), (long)a, (long)b, 0, 0, 0, 0, 0, 0, 0));
}
int
diff --git a/utf8.c b/utf8.c
index 3f378fb3..b4e448f7 100644
--- a/utf8.c
+++ b/utf8.c
@@ -22,7 +22,6 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
-#include <vis.h>
#include <wchar.h>
#include "tmux.h"
@@ -111,9 +110,27 @@ utf8_width(wchar_t wc)
{
int width;
+#ifdef HAVE_UTF8PROC
+ width = utf8proc_wcwidth(wc);
+#else
width = wcwidth(wc);
+#endif
if (width < 0 || width > 0xff) {
log_debug("Unicode %04lx, wcwidth() %d", (long)wc, width);
+
+#ifndef __OpenBSD__
+ /*
+ * Many platforms (particularly and inevitably OS X) have no
+ * width for relatively common characters (wcwidth() returns
+ * -1); assume width 1 in this case. This will be wrong for
+ * genuinely nonprintable characters, but they should be
+ * rare. We may pass through stuff that ideally we would block,
+ * but this is no worse than sending the same to the terminal
+ * without tmux.
+ */
+ if (width < 0)
+ return (1);
+#endif
return (-1);
}
return (width);
@@ -123,7 +140,11 @@ utf8_width(wchar_t wc)
enum utf8_state
utf8_combine(const struct utf8_data *ud, wchar_t *wc)
{
+#ifdef HAVE_UTF8PROC
+ switch (utf8proc_mbtowc(wc, ud->data, ud->size)) {
+#else
switch (mbtowc(wc, ud->data, ud->size)) {
+#endif
case -1:
log_debug("UTF-8 %.*s, mbtowc() %d", (int)ud->size, ud->data,
errno);
@@ -143,7 +164,11 @@ utf8_split(wchar_t wc, struct utf8_data *ud)
char s[MB_LEN_MAX];
int slen;
+#ifdef HAVE_UTF8PROC
+ slen = utf8proc_wctomb(s, wc);
+#else
slen = wctomb(s, wc);
+#endif
if (slen <= 0 || slen > (int)sizeof ud->data)
return (UTF8_ERROR);
diff --git a/window-buffer.c b/window-buffer.c
index e03dfa28..39d98608 100644
--- a/window-buffer.c
+++ b/window-buffer.c
@@ -21,7 +21,6 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include <vis.h>
#include "tmux.h"
diff --git a/window-tree.c b/window-tree.c
index e0aa4314..7ba14054 100644
--- a/window-tree.c
+++ b/window-tree.c
@@ -828,7 +828,7 @@ window_tree_search(__unused void *modedata, void *itemdata, const char *ss)
case WINDOW_TREE_PANE:
if (s == NULL || wl == NULL || wp == NULL)
break;
- cmd = get_proc_name(wp->fd, wp->tty);
+ cmd = osdep_get_name(wp->fd, wp->tty);
if (cmd == NULL || *cmd == '\0')
return (0);
retval = (strstr(cmd, ss) != NULL);
diff --git a/window.c b/window.c
index 64c95855..96632058 100644
--- a/window.c
+++ b/window.c
@@ -30,8 +30,6 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
-#include <util.h>
-#include <vis.h>
#include "tmux.h"
@@ -450,6 +448,15 @@ window_pane_send_resize(struct window_pane *wp, int yadjust)
ws.ws_xpixel = w->xpixel * ws.ws_col;
ws.ws_ypixel = w->ypixel * ws.ws_row;
if (ioctl(wp->fd, TIOCSWINSZ, &ws) == -1)
+#ifdef __sun
+ /*
+ * Some versions of Solaris apparently can return an error when
+ * resizing; don't know why this happens, can't reproduce on
+ * other platforms and ignoring it doesn't seem to cause any
+ * issues.
+ */
+ if (errno != EINVAL && errno != ENXIO)
+#endif
fatal("ioctl failed");
}
@@ -896,6 +903,9 @@ window_pane_destroy(struct window_pane *wp)
free(wp->searchstr);
if (wp->fd != -1) {
+#ifdef HAVE_UTEMPTER
+ utempter_remove_record(wp->fd);
+#endif
bufferevent_free(wp->event);
close(wp->fd);
}
diff --git a/xmalloc.h b/xmalloc.h
index 3fe4f1cc..d11d4bf1 100644
--- a/xmalloc.h
+++ b/xmalloc.h
@@ -19,6 +19,10 @@
#ifndef XMALLOC_H
#define XMALLOC_H
+#if !defined(__bounded__)
+#define __bounded__(x, y, z)
+#endif
+
void *xmalloc(size_t);
void *xcalloc(size_t, size_t);
void *xrealloc(void *, size_t);